mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 08:14:15 +08:00
Merge branches 'misc', 'sa1100-for-next' and 'spectre' into for-linus
This commit is contained in:
commit
97b6f89f72
@ -1282,65 +1282,6 @@ int sa1111_get_audio_rate(struct sa1111_dev *sadev)
|
||||
}
|
||||
EXPORT_SYMBOL(sa1111_get_audio_rate);
|
||||
|
||||
void sa1111_set_io_dir(struct sa1111_dev *sadev,
|
||||
unsigned int bits, unsigned int dir,
|
||||
unsigned int sleep_dir)
|
||||
{
|
||||
struct sa1111 *sachip = sa1111_chip_driver(sadev);
|
||||
unsigned long flags;
|
||||
unsigned int val;
|
||||
void __iomem *gpio = sachip->base + SA1111_GPIO;
|
||||
|
||||
#define MODIFY_BITS(port, mask, dir) \
|
||||
if (mask) { \
|
||||
val = readl_relaxed(port); \
|
||||
val &= ~(mask); \
|
||||
val |= (dir) & (mask); \
|
||||
writel_relaxed(val, port); \
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sachip->lock, flags);
|
||||
MODIFY_BITS(gpio + SA1111_GPIO_PADDR, bits & 15, dir);
|
||||
MODIFY_BITS(gpio + SA1111_GPIO_PBDDR, (bits >> 8) & 255, dir >> 8);
|
||||
MODIFY_BITS(gpio + SA1111_GPIO_PCDDR, (bits >> 16) & 255, dir >> 16);
|
||||
|
||||
MODIFY_BITS(gpio + SA1111_GPIO_PASDR, bits & 15, sleep_dir);
|
||||
MODIFY_BITS(gpio + SA1111_GPIO_PBSDR, (bits >> 8) & 255, sleep_dir >> 8);
|
||||
MODIFY_BITS(gpio + SA1111_GPIO_PCSDR, (bits >> 16) & 255, sleep_dir >> 16);
|
||||
spin_unlock_irqrestore(&sachip->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(sa1111_set_io_dir);
|
||||
|
||||
void sa1111_set_io(struct sa1111_dev *sadev, unsigned int bits, unsigned int v)
|
||||
{
|
||||
struct sa1111 *sachip = sa1111_chip_driver(sadev);
|
||||
unsigned long flags;
|
||||
unsigned int val;
|
||||
void __iomem *gpio = sachip->base + SA1111_GPIO;
|
||||
|
||||
spin_lock_irqsave(&sachip->lock, flags);
|
||||
MODIFY_BITS(gpio + SA1111_GPIO_PADWR, bits & 15, v);
|
||||
MODIFY_BITS(gpio + SA1111_GPIO_PBDWR, (bits >> 8) & 255, v >> 8);
|
||||
MODIFY_BITS(gpio + SA1111_GPIO_PCDWR, (bits >> 16) & 255, v >> 16);
|
||||
spin_unlock_irqrestore(&sachip->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(sa1111_set_io);
|
||||
|
||||
void sa1111_set_sleep_io(struct sa1111_dev *sadev, unsigned int bits, unsigned int v)
|
||||
{
|
||||
struct sa1111 *sachip = sa1111_chip_driver(sadev);
|
||||
unsigned long flags;
|
||||
unsigned int val;
|
||||
void __iomem *gpio = sachip->base + SA1111_GPIO;
|
||||
|
||||
spin_lock_irqsave(&sachip->lock, flags);
|
||||
MODIFY_BITS(gpio + SA1111_GPIO_PASSR, bits & 15, v);
|
||||
MODIFY_BITS(gpio + SA1111_GPIO_PBSSR, (bits >> 8) & 255, v >> 8);
|
||||
MODIFY_BITS(gpio + SA1111_GPIO_PCSSR, (bits >> 16) & 255, v >> 16);
|
||||
spin_unlock_irqrestore(&sachip->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(sa1111_set_sleep_io);
|
||||
|
||||
/*
|
||||
* Individual device operations.
|
||||
*/
|
||||
|
@ -111,6 +111,7 @@
|
||||
#include <linux/kernel.h>
|
||||
|
||||
extern unsigned int processor_id;
|
||||
struct proc_info_list *lookup_processor(u32 midr);
|
||||
|
||||
#ifdef CONFIG_CPU_CP15
|
||||
#define read_cpuid(reg) \
|
||||
|
@ -433,10 +433,6 @@ int sa1111_check_dma_bug(dma_addr_t addr);
|
||||
int sa1111_driver_register(struct sa1111_driver *);
|
||||
void sa1111_driver_unregister(struct sa1111_driver *);
|
||||
|
||||
void sa1111_set_io_dir(struct sa1111_dev *sadev, unsigned int bits, unsigned int dir, unsigned int sleep_dir);
|
||||
void sa1111_set_io(struct sa1111_dev *sadev, unsigned int bits, unsigned int v);
|
||||
void sa1111_set_sleep_io(struct sa1111_dev *sadev, unsigned int bits, unsigned int v);
|
||||
|
||||
struct sa1111_platform_data {
|
||||
int irq_base; /* base for cascaded on-chip IRQs */
|
||||
unsigned disable_devs;
|
||||
|
@ -23,7 +23,7 @@ struct mm_struct;
|
||||
/*
|
||||
* Don't change this structure - ASM code relies on it.
|
||||
*/
|
||||
extern struct processor {
|
||||
struct processor {
|
||||
/* MISC
|
||||
* get data abort address/flags
|
||||
*/
|
||||
@ -79,9 +79,13 @@ extern struct processor {
|
||||
unsigned int suspend_size;
|
||||
void (*do_suspend)(void *);
|
||||
void (*do_resume)(void *);
|
||||
} processor;
|
||||
};
|
||||
|
||||
#ifndef MULTI_CPU
|
||||
static inline void init_proc_vtable(const struct processor *p)
|
||||
{
|
||||
}
|
||||
|
||||
extern void cpu_proc_init(void);
|
||||
extern void cpu_proc_fin(void);
|
||||
extern int cpu_do_idle(void);
|
||||
@ -98,17 +102,50 @@ extern void cpu_reset(unsigned long addr, bool hvc) __attribute__((noreturn));
|
||||
extern void cpu_do_suspend(void *);
|
||||
extern void cpu_do_resume(void *);
|
||||
#else
|
||||
#define cpu_proc_init processor._proc_init
|
||||
#define cpu_proc_fin processor._proc_fin
|
||||
#define cpu_reset processor.reset
|
||||
#define cpu_do_idle processor._do_idle
|
||||
#define cpu_dcache_clean_area processor.dcache_clean_area
|
||||
#define cpu_set_pte_ext processor.set_pte_ext
|
||||
#define cpu_do_switch_mm processor.switch_mm
|
||||
|
||||
/* These three are private to arch/arm/kernel/suspend.c */
|
||||
#define cpu_do_suspend processor.do_suspend
|
||||
#define cpu_do_resume processor.do_resume
|
||||
extern struct processor processor;
|
||||
#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
|
||||
#include <linux/smp.h>
|
||||
/*
|
||||
* This can't be a per-cpu variable because we need to access it before
|
||||
* per-cpu has been initialised. We have a couple of functions that are
|
||||
* called in a pre-emptible context, and so can't use smp_processor_id()
|
||||
* there, hence PROC_TABLE(). We insist in init_proc_vtable() that the
|
||||
* function pointers for these are identical across all CPUs.
|
||||
*/
|
||||
extern struct processor *cpu_vtable[];
|
||||
#define PROC_VTABLE(f) cpu_vtable[smp_processor_id()]->f
|
||||
#define PROC_TABLE(f) cpu_vtable[0]->f
|
||||
static inline void init_proc_vtable(const struct processor *p)
|
||||
{
|
||||
unsigned int cpu = smp_processor_id();
|
||||
*cpu_vtable[cpu] = *p;
|
||||
WARN_ON_ONCE(cpu_vtable[cpu]->dcache_clean_area !=
|
||||
cpu_vtable[0]->dcache_clean_area);
|
||||
WARN_ON_ONCE(cpu_vtable[cpu]->set_pte_ext !=
|
||||
cpu_vtable[0]->set_pte_ext);
|
||||
}
|
||||
#else
|
||||
#define PROC_VTABLE(f) processor.f
|
||||
#define PROC_TABLE(f) processor.f
|
||||
static inline void init_proc_vtable(const struct processor *p)
|
||||
{
|
||||
processor = *p;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define cpu_proc_init PROC_VTABLE(_proc_init)
|
||||
#define cpu_check_bugs PROC_VTABLE(check_bugs)
|
||||
#define cpu_proc_fin PROC_VTABLE(_proc_fin)
|
||||
#define cpu_reset PROC_VTABLE(reset)
|
||||
#define cpu_do_idle PROC_VTABLE(_do_idle)
|
||||
#define cpu_dcache_clean_area PROC_TABLE(dcache_clean_area)
|
||||
#define cpu_set_pte_ext PROC_TABLE(set_pte_ext)
|
||||
#define cpu_do_switch_mm PROC_VTABLE(switch_mm)
|
||||
|
||||
/* These two are private to arch/arm/kernel/suspend.c */
|
||||
#define cpu_do_suspend PROC_VTABLE(do_suspend)
|
||||
#define cpu_do_resume PROC_VTABLE(do_resume)
|
||||
#endif
|
||||
|
||||
extern void cpu_resume(void);
|
||||
|
@ -6,8 +6,8 @@
|
||||
void check_other_bugs(void)
|
||||
{
|
||||
#ifdef MULTI_CPU
|
||||
if (processor.check_bugs)
|
||||
processor.check_bugs();
|
||||
if (cpu_check_bugs)
|
||||
cpu_check_bugs();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -145,6 +145,9 @@ __mmap_switched_data:
|
||||
#endif
|
||||
.size __mmap_switched_data, . - __mmap_switched_data
|
||||
|
||||
__FINIT
|
||||
.text
|
||||
|
||||
/*
|
||||
* This provides a C-API version of __lookup_processor_type
|
||||
*/
|
||||
@ -156,9 +159,6 @@ ENTRY(lookup_processor_type)
|
||||
ldmfd sp!, {r4 - r6, r9, pc}
|
||||
ENDPROC(lookup_processor_type)
|
||||
|
||||
__FINIT
|
||||
.text
|
||||
|
||||
/*
|
||||
* Read processor ID register (CP#15, CR0), and look up in the linker-built
|
||||
* supported processor list. Note that we can't use the absolute addresses
|
||||
|
@ -114,6 +114,11 @@ EXPORT_SYMBOL(elf_hwcap2);
|
||||
|
||||
#ifdef MULTI_CPU
|
||||
struct processor processor __ro_after_init;
|
||||
#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
|
||||
struct processor *cpu_vtable[NR_CPUS] = {
|
||||
[0] = &processor,
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
#ifdef MULTI_TLB
|
||||
struct cpu_tlb_fns cpu_tlb __ro_after_init;
|
||||
@ -666,28 +671,33 @@ static void __init smp_build_mpidr_hash(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* locate processor in the list of supported processor types. The linker
|
||||
* builds this table for us from the entries in arch/arm/mm/proc-*.S
|
||||
*/
|
||||
struct proc_info_list *lookup_processor(u32 midr)
|
||||
{
|
||||
struct proc_info_list *list = lookup_processor_type(midr);
|
||||
|
||||
if (!list) {
|
||||
pr_err("CPU%u: configuration botched (ID %08x), CPU halted\n",
|
||||
smp_processor_id(), midr);
|
||||
while (1)
|
||||
/* can't use cpu_relax() here as it may require MMU setup */;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static void __init setup_processor(void)
|
||||
{
|
||||
struct proc_info_list *list;
|
||||
|
||||
/*
|
||||
* locate processor in the list of supported processor
|
||||
* types. The linker builds this table for us from the
|
||||
* entries in arch/arm/mm/proc-*.S
|
||||
*/
|
||||
list = lookup_processor_type(read_cpuid_id());
|
||||
if (!list) {
|
||||
pr_err("CPU configuration botched (ID %08x), unable to continue.\n",
|
||||
read_cpuid_id());
|
||||
while (1);
|
||||
}
|
||||
unsigned int midr = read_cpuid_id();
|
||||
struct proc_info_list *list = lookup_processor(midr);
|
||||
|
||||
cpu_name = list->cpu_name;
|
||||
__cpu_architecture = __get_cpu_architecture();
|
||||
|
||||
#ifdef MULTI_CPU
|
||||
processor = *list->proc;
|
||||
#endif
|
||||
init_proc_vtable(list->proc);
|
||||
#ifdef MULTI_TLB
|
||||
cpu_tlb = *list->tlb;
|
||||
#endif
|
||||
@ -699,7 +709,7 @@ static void __init setup_processor(void)
|
||||
#endif
|
||||
|
||||
pr_info("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
|
||||
cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
|
||||
list->cpu_name, midr, midr & 15,
|
||||
proc_arch[cpu_architecture()], get_cr());
|
||||
|
||||
snprintf(init_utsname()->machine, __NEW_UTS_LEN + 1, "%s%c",
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/procinfo.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/tlbflush.h>
|
||||
@ -102,6 +103,30 @@ static unsigned long get_arch_pgd(pgd_t *pgd)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
|
||||
static int secondary_biglittle_prepare(unsigned int cpu)
|
||||
{
|
||||
if (!cpu_vtable[cpu])
|
||||
cpu_vtable[cpu] = kzalloc(sizeof(*cpu_vtable[cpu]), GFP_KERNEL);
|
||||
|
||||
return cpu_vtable[cpu] ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
static void secondary_biglittle_init(void)
|
||||
{
|
||||
init_proc_vtable(lookup_processor(read_cpuid_id())->proc);
|
||||
}
|
||||
#else
|
||||
static int secondary_biglittle_prepare(unsigned int cpu)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void secondary_biglittle_init(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
int __cpu_up(unsigned int cpu, struct task_struct *idle)
|
||||
{
|
||||
int ret;
|
||||
@ -109,6 +134,10 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
|
||||
if (!smp_ops.smp_boot_secondary)
|
||||
return -ENOSYS;
|
||||
|
||||
ret = secondary_biglittle_prepare(cpu);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* We need to tell the secondary core where to find
|
||||
* its stack and the page tables.
|
||||
@ -359,6 +388,8 @@ asmlinkage void secondary_start_kernel(void)
|
||||
struct mm_struct *mm = &init_mm;
|
||||
unsigned int cpu;
|
||||
|
||||
secondary_biglittle_init();
|
||||
|
||||
/*
|
||||
* The identity mapping is uncached (strongly ordered), so
|
||||
* switch away from it before attempting any exclusive accesses.
|
||||
|
@ -46,6 +46,7 @@ config ARCH_LUBBOCK
|
||||
|
||||
config MACH_MAINSTONE
|
||||
bool "Intel HCDDBBVA0 Development Platform (aka Mainstone)"
|
||||
select GPIO_REG
|
||||
select PXA27x
|
||||
|
||||
config MACH_ZYLONITE
|
||||
|
@ -119,6 +119,10 @@
|
||||
#define MST_PCMCIA_PWR_VCC_33 0x8 /* voltage VCC = 3.3V */
|
||||
#define MST_PCMCIA_PWR_VCC_50 0x4 /* voltage VCC = 5.0V */
|
||||
|
||||
#define MST_PCMCIA_INPUTS \
|
||||
(MST_PCMCIA_nIRQ | MST_PCMCIA_nSPKR_BVD2 | MST_PCMCIA_nSTSCHG_BVD1 | \
|
||||
MST_PCMCIA_nVS2 | MST_PCMCIA_nVS1 | MST_PCMCIA_nCD)
|
||||
|
||||
/* board specific IRQs */
|
||||
#define MAINSTONE_NR_IRQS IRQ_BOARD_START
|
||||
|
||||
|
@ -136,10 +136,26 @@ static struct pxa2xx_udc_mach_info udc_info __initdata = {
|
||||
// no D+ pullup; lubbock can't connect/disconnect in software
|
||||
};
|
||||
|
||||
/* GPIOs for SA1111 PCMCIA */
|
||||
static struct gpiod_lookup_table sa1111_pcmcia_gpio_table = {
|
||||
.dev_id = "1800",
|
||||
.table = {
|
||||
{ "sa1111", 0, "a0vpp", GPIO_ACTIVE_HIGH },
|
||||
{ "sa1111", 1, "a1vpp", GPIO_ACTIVE_HIGH },
|
||||
{ "sa1111", 2, "a0vcc", GPIO_ACTIVE_HIGH },
|
||||
{ "sa1111", 3, "a1vcc", GPIO_ACTIVE_HIGH },
|
||||
{ "lubbock", 14, "b0vcc", GPIO_ACTIVE_HIGH },
|
||||
{ "lubbock", 15, "b1vcc", GPIO_ACTIVE_HIGH },
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static void lubbock_init_pcmcia(void)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
gpiod_add_lookup_table(&sa1111_pcmcia_gpio_table);
|
||||
|
||||
/* Add an alias for the SA1111 PCMCIA clock */
|
||||
clk = clk_get_sys("pxa2xx-pcmcia", NULL);
|
||||
if (!IS_ERR(clk)) {
|
||||
|
@ -13,6 +13,7 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/gpio-reg.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
@ -507,12 +508,64 @@ static void __init mainstone_init_keypad(void)
|
||||
static inline void mainstone_init_keypad(void) {}
|
||||
#endif
|
||||
|
||||
static int mst_pcmcia0_irqs[11] = {
|
||||
[0 ... 10] = -1,
|
||||
[5] = MAINSTONE_S0_CD_IRQ,
|
||||
[8] = MAINSTONE_S0_STSCHG_IRQ,
|
||||
[10] = MAINSTONE_S0_IRQ,
|
||||
};
|
||||
|
||||
static int mst_pcmcia1_irqs[11] = {
|
||||
[0 ... 10] = -1,
|
||||
[5] = MAINSTONE_S1_CD_IRQ,
|
||||
[8] = MAINSTONE_S1_STSCHG_IRQ,
|
||||
[10] = MAINSTONE_S1_IRQ,
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table mainstone_pcmcia_gpio_table = {
|
||||
.dev_id = "pxa2xx-pcmcia",
|
||||
.table = {
|
||||
GPIO_LOOKUP("mst-pcmcia0", 0, "a0vpp", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("mst-pcmcia0", 1, "a1vpp", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("mst-pcmcia0", 2, "a0vcc", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("mst-pcmcia0", 3, "a1vcc", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("mst-pcmcia0", 4, "areset", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("mst-pcmcia0", 5, "adetect", GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP("mst-pcmcia0", 6, "avs1", GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP("mst-pcmcia0", 7, "avs2", GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP("mst-pcmcia0", 8, "abvd1", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("mst-pcmcia0", 9, "abvd2", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("mst-pcmcia0", 10, "aready", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("mst-pcmcia1", 0, "b0vpp", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("mst-pcmcia1", 1, "b1vpp", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("mst-pcmcia1", 2, "b0vcc", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("mst-pcmcia1", 3, "b1vcc", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("mst-pcmcia1", 4, "breset", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("mst-pcmcia1", 5, "bdetect", GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP("mst-pcmcia1", 6, "bvs1", GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP("mst-pcmcia1", 7, "bvs2", GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP("mst-pcmcia1", 8, "bbvd1", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("mst-pcmcia1", 9, "bbvd2", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("mst-pcmcia1", 10, "bready", GPIO_ACTIVE_HIGH),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static void __init mainstone_init(void)
|
||||
{
|
||||
int SW7 = 0; /* FIXME: get from SCR (Mst doc section 3.2.1.1) */
|
||||
|
||||
pxa2xx_mfp_config(ARRAY_AND_SIZE(mainstone_pin_config));
|
||||
|
||||
/* Register board control register(s) as GPIOs */
|
||||
gpio_reg_init(NULL, (void __iomem *)&MST_PCMCIA0, -1, 11,
|
||||
"mst-pcmcia0", MST_PCMCIA_INPUTS, 0, NULL,
|
||||
NULL, mst_pcmcia0_irqs);
|
||||
gpio_reg_init(NULL, (void __iomem *)&MST_PCMCIA1, -1, 11,
|
||||
"mst-pcmcia1", MST_PCMCIA_INPUTS, 0, NULL,
|
||||
NULL, mst_pcmcia1_irqs);
|
||||
gpiod_add_lookup_table(&mainstone_pcmcia_gpio_table);
|
||||
|
||||
pxa_set_ffuart_info(NULL);
|
||||
pxa_set_btuart_info(NULL);
|
||||
pxa_set_stuart_info(NULL);
|
||||
|
@ -6,6 +6,7 @@ config SA1100_ASSABET
|
||||
bool "Assabet"
|
||||
select ARM_SA1110_CPUFREQ
|
||||
select GPIO_REG
|
||||
select LEDS_GPIO_REGISTER
|
||||
select REGULATOR
|
||||
select REGULATOR_FIXED_VOLTAGE
|
||||
help
|
||||
@ -24,6 +25,7 @@ config ASSABET_NEPONSET
|
||||
config SA1100_CERF
|
||||
bool "CerfBoard"
|
||||
select ARM_SA1110_CPUFREQ
|
||||
select LEDS_GPIO_REGISTER
|
||||
help
|
||||
The Intrinsyc CerfBoard is based on the StrongARM 1110 (Discontinued).
|
||||
More information is available at:
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio/gpio-reg.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/platform_data/sa11x0-serial.h>
|
||||
#include <linux/regulator/fixed.h>
|
||||
@ -101,7 +102,7 @@ static int __init assabet_init_gpio(void __iomem *reg, u32 def_val)
|
||||
|
||||
assabet_bcr_gc = gc;
|
||||
|
||||
return 0;
|
||||
return gc->base;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -479,6 +480,49 @@ static struct gpiod_lookup_table assabet_cf_vcc_gpio_table = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct gpio_led assabet_leds[] __initdata = {
|
||||
{
|
||||
.name = "assabet:red",
|
||||
.default_trigger = "cpu0",
|
||||
.active_low = 1,
|
||||
.default_state = LEDS_GPIO_DEFSTATE_KEEP,
|
||||
}, {
|
||||
.name = "assabet:green",
|
||||
.default_trigger = "heartbeat",
|
||||
.active_low = 1,
|
||||
.default_state = LEDS_GPIO_DEFSTATE_KEEP,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct gpio_led_platform_data assabet_leds_pdata __initconst = {
|
||||
.num_leds = ARRAY_SIZE(assabet_leds),
|
||||
.leds = assabet_leds,
|
||||
};
|
||||
|
||||
static struct gpio_keys_button assabet_keys_buttons[] = {
|
||||
{
|
||||
.gpio = 0,
|
||||
.irq = IRQ_GPIO0,
|
||||
.desc = "gpio0",
|
||||
.wakeup = 1,
|
||||
.can_disable = 1,
|
||||
.debounce_interval = 5,
|
||||
}, {
|
||||
.gpio = 1,
|
||||
.irq = IRQ_GPIO1,
|
||||
.desc = "gpio1",
|
||||
.wakeup = 1,
|
||||
.can_disable = 1,
|
||||
.debounce_interval = 5,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct gpio_keys_platform_data assabet_keys_pdata = {
|
||||
.buttons = assabet_keys_buttons,
|
||||
.nbuttons = ARRAY_SIZE(assabet_keys_buttons),
|
||||
.rep = 0,
|
||||
};
|
||||
|
||||
static void __init assabet_init(void)
|
||||
{
|
||||
/*
|
||||
@ -533,6 +577,13 @@ static void __init assabet_init(void)
|
||||
|
||||
}
|
||||
|
||||
platform_device_register_resndata(NULL, "gpio-keys", 0,
|
||||
NULL, 0,
|
||||
&assabet_keys_pdata,
|
||||
sizeof(assabet_keys_pdata));
|
||||
|
||||
gpio_led_register_device(-1, &assabet_leds_pdata);
|
||||
|
||||
#ifndef ASSABET_PAL_VIDEO
|
||||
sa11x0_register_lcd(&lq039q2ds54_info);
|
||||
#else
|
||||
@ -726,92 +777,9 @@ static void __init assabet_map_io(void)
|
||||
sa1100_register_uart(2, 3);
|
||||
}
|
||||
|
||||
/* LEDs */
|
||||
#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
|
||||
struct assabet_led {
|
||||
struct led_classdev cdev;
|
||||
u32 mask;
|
||||
};
|
||||
|
||||
/*
|
||||
* The triggers lines up below will only be used if the
|
||||
* LED triggers are compiled in.
|
||||
*/
|
||||
static const struct {
|
||||
const char *name;
|
||||
const char *trigger;
|
||||
} assabet_leds[] = {
|
||||
{ "assabet:red", "cpu0",},
|
||||
{ "assabet:green", "heartbeat", },
|
||||
};
|
||||
|
||||
/*
|
||||
* The LED control in Assabet is reversed:
|
||||
* - setting bit means turn off LED
|
||||
* - clearing bit means turn on LED
|
||||
*/
|
||||
static void assabet_led_set(struct led_classdev *cdev,
|
||||
enum led_brightness b)
|
||||
{
|
||||
struct assabet_led *led = container_of(cdev,
|
||||
struct assabet_led, cdev);
|
||||
|
||||
if (b != LED_OFF)
|
||||
ASSABET_BCR_clear(led->mask);
|
||||
else
|
||||
ASSABET_BCR_set(led->mask);
|
||||
}
|
||||
|
||||
static enum led_brightness assabet_led_get(struct led_classdev *cdev)
|
||||
{
|
||||
struct assabet_led *led = container_of(cdev,
|
||||
struct assabet_led, cdev);
|
||||
|
||||
return (ASSABET_BCR & led->mask) ? LED_OFF : LED_FULL;
|
||||
}
|
||||
|
||||
static int __init assabet_leds_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!machine_is_assabet())
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(assabet_leds); i++) {
|
||||
struct assabet_led *led;
|
||||
|
||||
led = kzalloc(sizeof(*led), GFP_KERNEL);
|
||||
if (!led)
|
||||
break;
|
||||
|
||||
led->cdev.name = assabet_leds[i].name;
|
||||
led->cdev.brightness_set = assabet_led_set;
|
||||
led->cdev.brightness_get = assabet_led_get;
|
||||
led->cdev.default_trigger = assabet_leds[i].trigger;
|
||||
|
||||
if (!i)
|
||||
led->mask = ASSABET_BCR_LED_RED;
|
||||
else
|
||||
led->mask = ASSABET_BCR_LED_GREEN;
|
||||
|
||||
if (led_classdev_register(NULL, &led->cdev) < 0) {
|
||||
kfree(led);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since we may have triggers on any subsystem, defer registration
|
||||
* until after subsystem_init.
|
||||
*/
|
||||
fs_initcall(assabet_leds_init);
|
||||
#endif
|
||||
|
||||
void __init assabet_init_irq(void)
|
||||
{
|
||||
unsigned int assabet_gpio_base;
|
||||
u32 def_val;
|
||||
|
||||
sa1100_init_irq();
|
||||
@ -826,7 +794,10 @@ void __init assabet_init_irq(void)
|
||||
*
|
||||
* This must precede any driver calls to BCR_set() or BCR_clear().
|
||||
*/
|
||||
assabet_init_gpio((void *)&ASSABET_BCR, def_val);
|
||||
assabet_gpio_base = assabet_init_gpio((void *)&ASSABET_BCR, def_val);
|
||||
|
||||
assabet_leds[0].gpio = assabet_gpio_base + 13;
|
||||
assabet_leds[1].gpio = assabet_gpio_base + 14;
|
||||
}
|
||||
|
||||
MACHINE_START(ASSABET, "Intel-Assabet")
|
||||
|
@ -89,18 +89,8 @@ static struct gpio_led_platform_data cerf_gpio_led_info = {
|
||||
.num_leds = ARRAY_SIZE(cerf_gpio_leds),
|
||||
};
|
||||
|
||||
static struct platform_device cerf_leds = {
|
||||
.name = "leds-gpio",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = &cerf_gpio_led_info,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static struct platform_device *cerf_devices[] __initdata = {
|
||||
&cerfuart2_device,
|
||||
&cerf_leds,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SA1100_CERF_FLASH_32MB
|
||||
@ -176,6 +166,7 @@ static void __init cerf_init(void)
|
||||
{
|
||||
sa11x0_ppc_configure_mcp();
|
||||
platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices));
|
||||
gpio_led_register_device(-1, &cerf_gpio_led_info);
|
||||
sa11x0_register_mtd(&cerf_flash_data, &cerf_flash_resource, 1);
|
||||
sa11x0_register_mcp(&cerf_mcp_data);
|
||||
sa11x0_register_pcmcia(1, &cerf_cf_gpio_table);
|
||||
|
@ -235,18 +235,11 @@ void sa11x0_register_lcd(struct sa1100fb_mach_info *inf)
|
||||
sa11x0_register_device(&sa11x0fb_device, inf);
|
||||
}
|
||||
|
||||
static bool sa11x0pcmcia_legacy = true;
|
||||
static struct platform_device sa11x0pcmcia_device = {
|
||||
.name = "sa11x0-pcmcia",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
void sa11x0_register_pcmcia(int socket, struct gpiod_lookup_table *table)
|
||||
{
|
||||
if (table)
|
||||
gpiod_add_lookup_table(table);
|
||||
platform_device_register_simple("sa11x0-pcmcia", socket, NULL, 0);
|
||||
sa11x0pcmcia_legacy = false;
|
||||
}
|
||||
|
||||
static struct platform_device sa11x0mtd_device = {
|
||||
@ -331,9 +324,6 @@ static int __init sa1100_init(void)
|
||||
{
|
||||
pm_power_off = sa1100_power_off;
|
||||
|
||||
if (sa11x0pcmcia_legacy)
|
||||
platform_device_register(&sa11x0pcmcia_device);
|
||||
|
||||
regulator_has_full_constraints();
|
||||
|
||||
return platform_add_devices(sa11x0_devices, ARRAY_SIZE(sa11x0_devices));
|
||||
|
@ -126,6 +126,7 @@ static void __init h3100_mach_init(void)
|
||||
{
|
||||
h3xxx_mach_init();
|
||||
|
||||
sa11x0_register_pcmcia(-1, NULL);
|
||||
sa11x0_register_lcd(&h3100_lcd_info);
|
||||
sa11x0_register_irda(&h3100_irda_data);
|
||||
}
|
||||
|
@ -190,6 +190,17 @@ static struct platform_device s1d13xxxfb_device = {
|
||||
.resource = s1d13xxxfb_resources,
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table jornada_pcmcia_gpiod_table = {
|
||||
.dev_id = "1800",
|
||||
.table = {
|
||||
GPIO_LOOKUP("sa1111", 0, "s0-power", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("sa1111", 1, "s1-power", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("sa1111", 2, "s0-3v", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("sa1111", 3, "s1-3v", GPIO_ACTIVE_HIGH),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource sa1111_resources[] = {
|
||||
[0] = DEFINE_RES_MEM(SA1111REGSTART, SA1111REGLEN),
|
||||
[1] = DEFINE_RES_IRQ(IRQ_GPIO1),
|
||||
@ -265,6 +276,7 @@ static int __init jornada720_init(void)
|
||||
udelay(20); /* give it some time to restart */
|
||||
|
||||
gpiod_add_lookup_table(&jornada_ts_gpiod_table);
|
||||
gpiod_add_lookup_table(&jornada_pcmcia_gpiod_table);
|
||||
|
||||
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/gpio-reg.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/irq.h>
|
||||
@ -96,6 +97,19 @@ struct neponset_drvdata {
|
||||
struct gpio_chip *gpio[4];
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table neponset_pcmcia_table = {
|
||||
.dev_id = "1800",
|
||||
.table = {
|
||||
GPIO_LOOKUP("sa1111", 1, "a0vcc", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("sa1111", 0, "a1vcc", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("neponset-ncr", 5, "a0vpp", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("neponset-ncr", 6, "a1vpp", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("sa1111", 2, "b0vcc", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("sa1111", 3, "b1vcc", GPIO_ACTIVE_HIGH),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static struct neponset_drvdata *nep;
|
||||
|
||||
void neponset_ncr_frob(unsigned int mask, unsigned int val)
|
||||
@ -374,6 +388,8 @@ static int neponset_probe(struct platform_device *dev)
|
||||
d->base + AUD_CTL, AUD_NGPIO, false,
|
||||
neponset_aud_names);
|
||||
|
||||
gpiod_add_lookup_table(&neponset_pcmcia_table);
|
||||
|
||||
/*
|
||||
* We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately
|
||||
* something on the Neponset activates this IRQ on sleep (eth?)
|
||||
@ -424,6 +440,9 @@ static int neponset_remove(struct platform_device *dev)
|
||||
platform_device_unregister(d->sa1111);
|
||||
if (!IS_ERR(d->smc91x))
|
||||
platform_device_unregister(d->smc91x);
|
||||
|
||||
gpiod_remove_lookup_table(&neponset_pcmcia_table);
|
||||
|
||||
irq_set_chained_handler(irq, NULL);
|
||||
irq_free_descs(d->irq_base, NEP_IRQ_NR);
|
||||
nep = NULL;
|
||||
|
@ -274,6 +274,13 @@
|
||||
.endm
|
||||
|
||||
.macro define_processor_functions name:req, dabort:req, pabort:req, nommu=0, suspend=0, bugs=0
|
||||
/*
|
||||
* If we are building for big.Little with branch predictor hardening,
|
||||
* we need the processor function tables to remain available after boot.
|
||||
*/
|
||||
#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
|
||||
.section ".rodata"
|
||||
#endif
|
||||
.type \name\()_processor_functions, #object
|
||||
.align 2
|
||||
ENTRY(\name\()_processor_functions)
|
||||
@ -309,6 +316,9 @@ ENTRY(\name\()_processor_functions)
|
||||
.endif
|
||||
|
||||
.size \name\()_processor_functions, . - \name\()_processor_functions
|
||||
#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
|
||||
.previous
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro define_cache_functions name:req
|
||||
|
@ -52,8 +52,6 @@ static void cpu_v7_spectre_init(void)
|
||||
case ARM_CPU_PART_CORTEX_A17:
|
||||
case ARM_CPU_PART_CORTEX_A73:
|
||||
case ARM_CPU_PART_CORTEX_A75:
|
||||
if (processor.switch_mm != cpu_v7_bpiall_switch_mm)
|
||||
goto bl_error;
|
||||
per_cpu(harden_branch_predictor_fn, cpu) =
|
||||
harden_branch_predictor_bpiall;
|
||||
spectre_v2_method = "BPIALL";
|
||||
@ -61,8 +59,6 @@ static void cpu_v7_spectre_init(void)
|
||||
|
||||
case ARM_CPU_PART_CORTEX_A15:
|
||||
case ARM_CPU_PART_BRAHMA_B15:
|
||||
if (processor.switch_mm != cpu_v7_iciallu_switch_mm)
|
||||
goto bl_error;
|
||||
per_cpu(harden_branch_predictor_fn, cpu) =
|
||||
harden_branch_predictor_iciallu;
|
||||
spectre_v2_method = "ICIALLU";
|
||||
@ -88,11 +84,9 @@ static void cpu_v7_spectre_init(void)
|
||||
ARM_SMCCC_ARCH_WORKAROUND_1, &res);
|
||||
if ((int)res.a0 != 0)
|
||||
break;
|
||||
if (processor.switch_mm != cpu_v7_hvc_switch_mm && cpu)
|
||||
goto bl_error;
|
||||
per_cpu(harden_branch_predictor_fn, cpu) =
|
||||
call_hvc_arch_workaround_1;
|
||||
processor.switch_mm = cpu_v7_hvc_switch_mm;
|
||||
cpu_do_switch_mm = cpu_v7_hvc_switch_mm;
|
||||
spectre_v2_method = "hypervisor";
|
||||
break;
|
||||
|
||||
@ -101,11 +95,9 @@ static void cpu_v7_spectre_init(void)
|
||||
ARM_SMCCC_ARCH_WORKAROUND_1, &res);
|
||||
if ((int)res.a0 != 0)
|
||||
break;
|
||||
if (processor.switch_mm != cpu_v7_smc_switch_mm && cpu)
|
||||
goto bl_error;
|
||||
per_cpu(harden_branch_predictor_fn, cpu) =
|
||||
call_smc_arch_workaround_1;
|
||||
processor.switch_mm = cpu_v7_smc_switch_mm;
|
||||
cpu_do_switch_mm = cpu_v7_smc_switch_mm;
|
||||
spectre_v2_method = "firmware";
|
||||
break;
|
||||
|
||||
@ -119,11 +111,6 @@ static void cpu_v7_spectre_init(void)
|
||||
if (spectre_v2_method)
|
||||
pr_info("CPU%u: Spectre v2: using %s workaround\n",
|
||||
smp_processor_id(), spectre_v2_method);
|
||||
return;
|
||||
|
||||
bl_error:
|
||||
pr_err("CPU%u: Spectre v2: incorrect context switching function, system vulnerable\n",
|
||||
cpu);
|
||||
}
|
||||
#else
|
||||
static void cpu_v7_spectre_init(void)
|
||||
|
@ -112,7 +112,7 @@ ENTRY(cpu_v7_hvc_switch_mm)
|
||||
hvc #0
|
||||
ldmfd sp!, {r0 - r3}
|
||||
b cpu_v7_switch_mm
|
||||
ENDPROC(cpu_v7_smc_switch_mm)
|
||||
ENDPROC(cpu_v7_hvc_switch_mm)
|
||||
#endif
|
||||
ENTRY(cpu_v7_iciallu_switch_mm)
|
||||
mov r3, #0
|
||||
|
@ -573,7 +573,7 @@ int vfp_preserve_user_clear_hwstate(struct user_vfp *ufp,
|
||||
*/
|
||||
ufp_exc->fpexc = hwstate->fpexc;
|
||||
ufp_exc->fpinst = hwstate->fpinst;
|
||||
ufp_exc->fpinst2 = ufp_exc->fpinst2;
|
||||
ufp_exc->fpinst2 = hwstate->fpinst2;
|
||||
|
||||
/* Ensure that VFP is disabled. */
|
||||
vfp_flush_hwstate(thread);
|
||||
|
@ -63,6 +63,9 @@ config CARDBUS
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config PCMCIA_MAX1600
|
||||
tristate
|
||||
|
||||
comment "PC-card bridges"
|
||||
|
||||
config YENTA
|
||||
@ -191,6 +194,8 @@ config PCMCIA_SA1111
|
||||
select PCMCIA_SOC_COMMON
|
||||
select PCMCIA_SA11XX_BASE if ARCH_SA1100
|
||||
select PCMCIA_PXA2XX if ARCH_LUBBOCK && SA1111
|
||||
select PCMCIA_MAX1600 if ASSABET_NEPONSET
|
||||
select PCMCIA_MAX1600 if ARCH_LUBBOCK && SA1111
|
||||
help
|
||||
Say Y here to include support for SA1111-based PCMCIA or CF
|
||||
sockets, found on the Jornada 720, Graphicsmaster and other
|
||||
@ -207,6 +212,7 @@ config PCMCIA_PXA2XX
|
||||
|| MACH_VPAC270 || MACH_BALLOON3 || MACH_COLIBRI \
|
||||
|| MACH_COLIBRI320 || MACH_H4700)
|
||||
select PCMCIA_SOC_COMMON
|
||||
select PCMCIA_MAX1600 if MACH_MAINSTONE
|
||||
help
|
||||
Say Y here to include support for the PXA2xx PCMCIA controller
|
||||
|
||||
|
@ -35,6 +35,7 @@ obj-$(CONFIG_OMAP_CF) += omap_cf.o
|
||||
obj-$(CONFIG_AT91_CF) += at91_cf.o
|
||||
obj-$(CONFIG_ELECTRA_CF) += electra_cf.o
|
||||
obj-$(CONFIG_PCMCIA_ALCHEMY_DEVBOARD) += db1xxx_ss.o
|
||||
obj-$(CONFIG_PCMCIA_MAX1600) += max1600.o
|
||||
|
||||
sa1111_cs-y += sa1111_generic.o
|
||||
sa1111_cs-$(CONFIG_ASSABET_NEPONSET) += sa1111_neponset.o
|
||||
|
122
drivers/pcmcia/max1600.c
Normal file
122
drivers/pcmcia/max1600.c
Normal file
@ -0,0 +1,122 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* MAX1600 PCMCIA power switch library
|
||||
*
|
||||
* Copyright (C) 2016 Russell King
|
||||
*/
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
#include "max1600.h"
|
||||
|
||||
static const char *max1600_gpio_name[2][MAX1600_GPIO_MAX] = {
|
||||
{ "a0vcc", "a1vcc", "a0vpp", "a1vpp" },
|
||||
{ "b0vcc", "b1vcc", "b0vpp", "b1vpp" },
|
||||
};
|
||||
|
||||
int max1600_init(struct device *dev, struct max1600 **ptr,
|
||||
unsigned int channel, unsigned int code)
|
||||
{
|
||||
struct max1600 *m;
|
||||
int chan;
|
||||
int i;
|
||||
|
||||
switch (channel) {
|
||||
case MAX1600_CHAN_A:
|
||||
chan = 0;
|
||||
break;
|
||||
case MAX1600_CHAN_B:
|
||||
chan = 1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (code != MAX1600_CODE_LOW && code != MAX1600_CODE_HIGH)
|
||||
return -EINVAL;
|
||||
|
||||
m = devm_kzalloc(dev, sizeof(*m), GFP_KERNEL);
|
||||
if (!m)
|
||||
return -ENOMEM;
|
||||
|
||||
m->dev = dev;
|
||||
m->code = code;
|
||||
|
||||
for (i = 0; i < MAX1600_GPIO_MAX; i++) {
|
||||
const char *name;
|
||||
|
||||
name = max1600_gpio_name[chan][i];
|
||||
if (i != MAX1600_GPIO_0VPP) {
|
||||
m->gpio[i] = devm_gpiod_get(dev, name, GPIOD_OUT_LOW);
|
||||
} else {
|
||||
m->gpio[i] = devm_gpiod_get_optional(dev, name,
|
||||
GPIOD_OUT_LOW);
|
||||
if (!m->gpio[i])
|
||||
break;
|
||||
}
|
||||
if (IS_ERR(m->gpio[i]))
|
||||
return PTR_ERR(m->gpio[i]);
|
||||
}
|
||||
|
||||
*ptr = m;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(max1600_init);
|
||||
|
||||
int max1600_configure(struct max1600 *m, unsigned int vcc, unsigned int vpp)
|
||||
{
|
||||
DECLARE_BITMAP(values, MAX1600_GPIO_MAX) = { 0, };
|
||||
int n = MAX1600_GPIO_0VPP;
|
||||
|
||||
if (m->gpio[MAX1600_GPIO_0VPP]) {
|
||||
if (vpp == 0) {
|
||||
__assign_bit(MAX1600_GPIO_0VPP, values, 0);
|
||||
__assign_bit(MAX1600_GPIO_1VPP, values, 0);
|
||||
} else if (vpp == 120) {
|
||||
__assign_bit(MAX1600_GPIO_0VPP, values, 0);
|
||||
__assign_bit(MAX1600_GPIO_1VPP, values, 1);
|
||||
} else if (vpp == vcc) {
|
||||
__assign_bit(MAX1600_GPIO_0VPP, values, 1);
|
||||
__assign_bit(MAX1600_GPIO_1VPP, values, 0);
|
||||
} else {
|
||||
dev_err(m->dev, "unrecognised Vpp %u.%uV\n",
|
||||
vpp / 10, vpp % 10);
|
||||
return -EINVAL;
|
||||
}
|
||||
n = MAX1600_GPIO_MAX;
|
||||
} else if (vpp != vcc && vpp != 0) {
|
||||
dev_err(m->dev, "no VPP control\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (vcc == 0) {
|
||||
__assign_bit(MAX1600_GPIO_0VCC, values, 0);
|
||||
__assign_bit(MAX1600_GPIO_1VCC, values, 0);
|
||||
} else if (vcc == 33) { /* VY */
|
||||
__assign_bit(MAX1600_GPIO_0VCC, values, 1);
|
||||
__assign_bit(MAX1600_GPIO_1VCC, values, 0);
|
||||
} else if (vcc == 50) { /* VX */
|
||||
__assign_bit(MAX1600_GPIO_0VCC, values, 0);
|
||||
__assign_bit(MAX1600_GPIO_1VCC, values, 1);
|
||||
} else {
|
||||
dev_err(m->dev, "unrecognised Vcc %u.%uV\n",
|
||||
vcc / 10, vcc % 10);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (m->code == MAX1600_CODE_HIGH) {
|
||||
/*
|
||||
* Cirrus mode appears to be the same as Intel mode,
|
||||
* except the VCC pins are inverted.
|
||||
*/
|
||||
__change_bit(MAX1600_GPIO_0VCC, values);
|
||||
__change_bit(MAX1600_GPIO_1VCC, values);
|
||||
}
|
||||
|
||||
return gpiod_set_array_value_cansleep(n, m->gpio, NULL, values);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(max1600_configure);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
32
drivers/pcmcia/max1600.h
Normal file
32
drivers/pcmcia/max1600.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef MAX1600_H
|
||||
#define MAX1600_H
|
||||
|
||||
struct gpio_desc;
|
||||
|
||||
enum {
|
||||
MAX1600_GPIO_0VCC = 0,
|
||||
MAX1600_GPIO_1VCC,
|
||||
MAX1600_GPIO_0VPP,
|
||||
MAX1600_GPIO_1VPP,
|
||||
MAX1600_GPIO_MAX,
|
||||
|
||||
MAX1600_CHAN_A,
|
||||
MAX1600_CHAN_B,
|
||||
|
||||
MAX1600_CODE_LOW,
|
||||
MAX1600_CODE_HIGH,
|
||||
};
|
||||
|
||||
struct max1600 {
|
||||
struct gpio_desc *gpio[MAX1600_GPIO_MAX];
|
||||
struct device *dev;
|
||||
unsigned int code;
|
||||
};
|
||||
|
||||
int max1600_init(struct device *dev, struct max1600 **ptr,
|
||||
unsigned int channel, unsigned int code);
|
||||
|
||||
int max1600_configure(struct max1600 *, unsigned int vcc, unsigned int vpp);
|
||||
|
||||
#endif
|
@ -11,56 +11,55 @@
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <pcmcia/ss.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include <mach/pxa2xx-regs.h>
|
||||
#include <mach/mainstone.h>
|
||||
|
||||
#include "soc_common.h"
|
||||
|
||||
#include "max1600.h"
|
||||
|
||||
static int mst_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
|
||||
{
|
||||
/*
|
||||
* Setup default state of GPIO outputs
|
||||
* before we enable them as outputs.
|
||||
*/
|
||||
if (skt->nr == 0) {
|
||||
skt->socket.pci_irq = MAINSTONE_S0_IRQ;
|
||||
skt->stat[SOC_STAT_CD].irq = MAINSTONE_S0_CD_IRQ;
|
||||
skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD";
|
||||
skt->stat[SOC_STAT_BVD1].irq = MAINSTONE_S0_STSCHG_IRQ;
|
||||
skt->stat[SOC_STAT_BVD1].name = "PCMCIA0 STSCHG";
|
||||
} else {
|
||||
skt->socket.pci_irq = MAINSTONE_S1_IRQ;
|
||||
skt->stat[SOC_STAT_CD].irq = MAINSTONE_S1_CD_IRQ;
|
||||
skt->stat[SOC_STAT_CD].name = "PCMCIA1 CD";
|
||||
skt->stat[SOC_STAT_BVD1].irq = MAINSTONE_S1_STSCHG_IRQ;
|
||||
skt->stat[SOC_STAT_BVD1].name = "PCMCIA1 STSCHG";
|
||||
}
|
||||
return 0;
|
||||
struct device *dev = skt->socket.dev.parent;
|
||||
struct max1600 *m;
|
||||
int ret;
|
||||
|
||||
skt->stat[SOC_STAT_CD].name = skt->nr ? "bdetect" : "adetect";
|
||||
skt->stat[SOC_STAT_BVD1].name = skt->nr ? "bbvd1" : "abvd1";
|
||||
skt->stat[SOC_STAT_BVD2].name = skt->nr ? "bbvd2" : "abvd2";
|
||||
skt->stat[SOC_STAT_RDY].name = skt->nr ? "bready" : "aready";
|
||||
skt->stat[SOC_STAT_VS1].name = skt->nr ? "bvs1" : "avs1";
|
||||
skt->stat[SOC_STAT_VS2].name = skt->nr ? "bvs2" : "avs2";
|
||||
|
||||
skt->gpio_reset = devm_gpiod_get(dev, skt->nr ? "breset" : "areset",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(skt->gpio_reset))
|
||||
return PTR_ERR(skt->gpio_reset);
|
||||
|
||||
ret = max1600_init(dev, &m, skt->nr ? MAX1600_CHAN_B : MAX1600_CHAN_A,
|
||||
MAX1600_CODE_HIGH);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
skt->driver_data = m;
|
||||
|
||||
return soc_pcmcia_request_gpiods(skt);
|
||||
}
|
||||
|
||||
static unsigned long mst_pcmcia_status[2];
|
||||
static unsigned int mst_pcmcia_bvd1_status[2];
|
||||
|
||||
static void mst_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
|
||||
struct pcmcia_state *state)
|
||||
{
|
||||
unsigned long status, flip;
|
||||
|
||||
status = (skt->nr == 0) ? MST_PCMCIA0 : MST_PCMCIA1;
|
||||
flip = (status ^ mst_pcmcia_status[skt->nr]) & MST_PCMCIA_nSTSCHG_BVD1;
|
||||
unsigned int flip = mst_pcmcia_bvd1_status[skt->nr] ^ state->bvd1;
|
||||
|
||||
/*
|
||||
* Workaround for STSCHG which can't be deasserted:
|
||||
@ -68,62 +67,18 @@ static void mst_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
|
||||
* as needed to avoid IRQ locks.
|
||||
*/
|
||||
if (flip) {
|
||||
mst_pcmcia_status[skt->nr] = status;
|
||||
if (status & MST_PCMCIA_nSTSCHG_BVD1)
|
||||
enable_irq( (skt->nr == 0) ? MAINSTONE_S0_STSCHG_IRQ
|
||||
: MAINSTONE_S1_STSCHG_IRQ );
|
||||
mst_pcmcia_bvd1_status[skt->nr] = state->bvd1;
|
||||
if (state->bvd1)
|
||||
enable_irq(skt->stat[SOC_STAT_BVD1].irq);
|
||||
else
|
||||
disable_irq( (skt->nr == 0) ? MAINSTONE_S0_STSCHG_IRQ
|
||||
: MAINSTONE_S1_STSCHG_IRQ );
|
||||
disable_irq(skt->stat[SOC_STAT_BVD2].irq);
|
||||
}
|
||||
|
||||
state->detect = (status & MST_PCMCIA_nCD) ? 0 : 1;
|
||||
state->ready = (status & MST_PCMCIA_nIRQ) ? 1 : 0;
|
||||
state->bvd1 = (status & MST_PCMCIA_nSTSCHG_BVD1) ? 1 : 0;
|
||||
state->bvd2 = (status & MST_PCMCIA_nSPKR_BVD2) ? 1 : 0;
|
||||
state->vs_3v = (status & MST_PCMCIA_nVS1) ? 0 : 1;
|
||||
state->vs_Xv = (status & MST_PCMCIA_nVS2) ? 0 : 1;
|
||||
}
|
||||
|
||||
static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
|
||||
const socket_state_t *state)
|
||||
{
|
||||
unsigned long power = 0;
|
||||
int ret = 0;
|
||||
|
||||
switch (state->Vcc) {
|
||||
case 0: power |= MST_PCMCIA_PWR_VCC_0; break;
|
||||
case 33: power |= MST_PCMCIA_PWR_VCC_33; break;
|
||||
case 50: power |= MST_PCMCIA_PWR_VCC_50; break;
|
||||
default:
|
||||
printk(KERN_ERR "%s(): bad Vcc %u\n",
|
||||
__func__, state->Vcc);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
switch (state->Vpp) {
|
||||
case 0: power |= MST_PCMCIA_PWR_VPP_0; break;
|
||||
case 120: power |= MST_PCMCIA_PWR_VPP_120; break;
|
||||
default:
|
||||
if(state->Vpp == state->Vcc) {
|
||||
power |= MST_PCMCIA_PWR_VPP_VCC;
|
||||
} else {
|
||||
printk(KERN_ERR "%s(): bad Vpp %u\n",
|
||||
__func__, state->Vpp);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (state->flags & SS_RESET)
|
||||
power |= MST_PCMCIA_RESET;
|
||||
|
||||
switch (skt->nr) {
|
||||
case 0: MST_PCMCIA0 = power; break;
|
||||
case 1: MST_PCMCIA1 = power; break;
|
||||
default: ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return max1600_configure(skt->driver_data, state->Vcc, state->Vpp);
|
||||
}
|
||||
|
||||
static struct pcmcia_low_level mst_pcmcia_ops __initdata = {
|
||||
|
@ -39,8 +39,8 @@ simpad_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
|
||||
{
|
||||
long cs3reg = simpad_get_cs3_ro();
|
||||
|
||||
state->bvd1 = 1; /* Might be cs3reg & PCMCIA_BVD1 */
|
||||
state->bvd2 = 1; /* Might be cs3reg & PCMCIA_BVD2 */
|
||||
/* bvd1 might be cs3reg & PCMCIA_BVD1 */
|
||||
/* bvd2 might be cs3reg & PCMCIA_BVD2 */
|
||||
|
||||
if ((cs3reg & (PCMCIA_VS1|PCMCIA_VS2)) ==
|
||||
(PCMCIA_VS1|PCMCIA_VS2)) {
|
||||
|
@ -6,29 +6,62 @@
|
||||
*
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/hardware/sa1111.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include "sa1111_generic.h"
|
||||
|
||||
/* Does SOCKET1_3V actually do anything? */
|
||||
#define SOCKET0_POWER GPIO_GPIO0
|
||||
#define SOCKET0_3V GPIO_GPIO2
|
||||
#define SOCKET1_POWER (GPIO_GPIO1 | GPIO_GPIO3)
|
||||
#define SOCKET1_3V GPIO_GPIO3
|
||||
/*
|
||||
* Socket 0 power: GPIO A0
|
||||
* Socket 0 3V: GPIO A2
|
||||
* Socket 1 power: GPIO A1 & GPIO A3
|
||||
* Socket 1 3V: GPIO A3
|
||||
* Does Socket 1 3V actually do anything?
|
||||
*/
|
||||
enum {
|
||||
J720_GPIO_PWR,
|
||||
J720_GPIO_3V,
|
||||
J720_GPIO_MAX,
|
||||
};
|
||||
struct jornada720_data {
|
||||
struct gpio_desc *gpio[J720_GPIO_MAX];
|
||||
};
|
||||
|
||||
static int jornada720_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
|
||||
{
|
||||
struct device *dev = skt->socket.dev.parent;
|
||||
struct jornada720_data *j;
|
||||
|
||||
j = devm_kzalloc(dev, sizeof(*j), GFP_KERNEL);
|
||||
if (!j)
|
||||
return -ENOMEM;
|
||||
|
||||
j->gpio[J720_GPIO_PWR] = devm_gpiod_get(dev, skt->nr ? "s1-power" :
|
||||
"s0-power", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(j->gpio[J720_GPIO_PWR]))
|
||||
return PTR_ERR(j->gpio[J720_GPIO_PWR]);
|
||||
|
||||
j->gpio[J720_GPIO_3V] = devm_gpiod_get(dev, skt->nr ? "s1-3v" :
|
||||
"s0-3v", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(j->gpio[J720_GPIO_3V]))
|
||||
return PTR_ERR(j->gpio[J720_GPIO_3V]);
|
||||
|
||||
skt->driver_data = j;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
|
||||
{
|
||||
struct sa1111_pcmcia_socket *s = to_skt(skt);
|
||||
unsigned int pa_dwr_mask, pa_dwr_set;
|
||||
struct jornada720_data *j = skt->driver_data;
|
||||
DECLARE_BITMAP(values, J720_GPIO_MAX) = { 0, };
|
||||
int ret;
|
||||
|
||||
printk(KERN_INFO "%s(): config socket %d vcc %d vpp %d\n", __func__,
|
||||
@ -36,35 +69,34 @@ jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s
|
||||
|
||||
switch (skt->nr) {
|
||||
case 0:
|
||||
pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V;
|
||||
|
||||
switch (state->Vcc) {
|
||||
default:
|
||||
case 0:
|
||||
pa_dwr_set = 0;
|
||||
__assign_bit(J720_GPIO_PWR, values, 0);
|
||||
__assign_bit(J720_GPIO_3V, values, 0);
|
||||
break;
|
||||
case 33:
|
||||
pa_dwr_set = SOCKET0_POWER | SOCKET0_3V;
|
||||
__assign_bit(J720_GPIO_PWR, values, 1);
|
||||
__assign_bit(J720_GPIO_3V, values, 1);
|
||||
break;
|
||||
case 50:
|
||||
pa_dwr_set = SOCKET0_POWER;
|
||||
__assign_bit(J720_GPIO_PWR, values, 1);
|
||||
__assign_bit(J720_GPIO_3V, values, 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
pa_dwr_mask = SOCKET1_POWER;
|
||||
|
||||
switch (state->Vcc) {
|
||||
default:
|
||||
case 0:
|
||||
pa_dwr_set = 0;
|
||||
__assign_bit(J720_GPIO_PWR, values, 0);
|
||||
__assign_bit(J720_GPIO_3V, values, 0);
|
||||
break;
|
||||
case 33:
|
||||
pa_dwr_set = SOCKET1_POWER;
|
||||
break;
|
||||
case 50:
|
||||
pa_dwr_set = SOCKET1_POWER;
|
||||
__assign_bit(J720_GPIO_PWR, values, 1);
|
||||
__assign_bit(J720_GPIO_3V, values, 1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -81,13 +113,15 @@ jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s
|
||||
|
||||
ret = sa1111_pcmcia_configure_socket(skt, state);
|
||||
if (ret == 0)
|
||||
sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
|
||||
ret = gpiod_set_array_value_cansleep(J720_GPIO_MAX, j->gpio,
|
||||
NULL, values);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct pcmcia_low_level jornada720_pcmcia_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.hw_init = jornada720_pcmcia_hw_init,
|
||||
.configure_socket = jornada720_pcmcia_configure_socket,
|
||||
.first = 0,
|
||||
.nr = 2,
|
||||
@ -95,16 +129,9 @@ static struct pcmcia_low_level jornada720_pcmcia_ops = {
|
||||
|
||||
int pcmcia_jornada720_init(struct sa1111_dev *sadev)
|
||||
{
|
||||
unsigned int pin = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3;
|
||||
|
||||
/* Fixme: why messing around with SA11x0's GPIO1? */
|
||||
GRER |= 0x00000002;
|
||||
|
||||
/* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */
|
||||
sa1111_set_io_dir(sadev, pin, 0, 0);
|
||||
sa1111_set_io(sadev, pin, 0);
|
||||
sa1111_set_sleep_io(sadev, pin, 0);
|
||||
|
||||
sa11xx_drv_pcmcia_ops(&jornada720_pcmcia_ops);
|
||||
return sa1111_pcmcia_add(sadev, &jornada720_pcmcia_ops,
|
||||
sa11xx_drv_pcmcia_add_one);
|
||||
|
@ -24,20 +24,31 @@
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/hardware/sa1111.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <mach/lubbock.h>
|
||||
|
||||
#include "sa1111_generic.h"
|
||||
#include "max1600.h"
|
||||
|
||||
static int lubbock_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
|
||||
{
|
||||
struct max1600 *m;
|
||||
int ret;
|
||||
|
||||
ret = max1600_init(skt->socket.dev.parent, &m,
|
||||
skt->nr ? MAX1600_CHAN_B : MAX1600_CHAN_A,
|
||||
MAX1600_CODE_HIGH);
|
||||
if (ret == 0)
|
||||
skt->driver_data = m;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
|
||||
const socket_state_t *state)
|
||||
{
|
||||
struct sa1111_pcmcia_socket *s = to_skt(skt);
|
||||
unsigned int pa_dwr_mask, pa_dwr_set, misc_mask, misc_set;
|
||||
struct max1600 *m = skt->driver_data;
|
||||
int ret = 0;
|
||||
|
||||
pa_dwr_mask = pa_dwr_set = misc_mask = misc_set = 0;
|
||||
|
||||
/* Lubbock uses the Maxim MAX1602, with the following connections:
|
||||
*
|
||||
* Socket 0 (PCMCIA):
|
||||
@ -71,74 +82,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
|
||||
again:
|
||||
switch (skt->nr) {
|
||||
case 0:
|
||||
pa_dwr_mask = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3;
|
||||
|
||||
switch (state->Vcc) {
|
||||
case 0: /* Hi-Z */
|
||||
break;
|
||||
|
||||
case 33: /* VY */
|
||||
pa_dwr_set |= GPIO_A3;
|
||||
break;
|
||||
|
||||
case 50: /* VX */
|
||||
pa_dwr_set |= GPIO_A2;
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
|
||||
__func__, state->Vcc);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
switch (state->Vpp) {
|
||||
case 0: /* Hi-Z */
|
||||
break;
|
||||
|
||||
case 120: /* 12IN */
|
||||
pa_dwr_set |= GPIO_A1;
|
||||
break;
|
||||
|
||||
default: /* VCC */
|
||||
if (state->Vpp == state->Vcc)
|
||||
pa_dwr_set |= GPIO_A0;
|
||||
else {
|
||||
printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
|
||||
__func__, state->Vpp);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
misc_mask = (1 << 15) | (1 << 14);
|
||||
|
||||
switch (state->Vcc) {
|
||||
case 0: /* Hi-Z */
|
||||
break;
|
||||
|
||||
case 33: /* VY */
|
||||
misc_set |= 1 << 15;
|
||||
break;
|
||||
|
||||
case 50: /* VX */
|
||||
misc_set |= 1 << 14;
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
|
||||
__func__, state->Vcc);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (state->Vpp != state->Vcc && state->Vpp != 0) {
|
||||
printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n",
|
||||
__func__, state->Vpp);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -147,11 +91,8 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
|
||||
|
||||
if (ret == 0)
|
||||
ret = sa1111_pcmcia_configure_socket(skt, state);
|
||||
|
||||
if (ret == 0) {
|
||||
lubbock_set_misc_wr(misc_mask, misc_set);
|
||||
sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
|
||||
}
|
||||
if (ret == 0)
|
||||
ret = max1600_configure(m, state->Vcc, state->Vpp);
|
||||
|
||||
#if 1
|
||||
if (ret == 0 && state->Vcc == 33) {
|
||||
@ -175,8 +116,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
|
||||
/*
|
||||
* Switch to 5V, Configure socket with 5V voltage
|
||||
*/
|
||||
lubbock_set_misc_wr(misc_mask, 0);
|
||||
sa1111_set_io(s->dev, pa_dwr_mask, 0);
|
||||
max1600_configure(m, 0, 0);
|
||||
|
||||
/*
|
||||
* It takes about 100ms to turn off Vcc.
|
||||
@ -201,6 +141,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
|
||||
|
||||
static struct pcmcia_low_level lubbock_pcmcia_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.hw_init = lubbock_pcmcia_hw_init,
|
||||
.configure_socket = lubbock_pcmcia_configure_socket,
|
||||
.first = 0,
|
||||
.nr = 2,
|
||||
@ -210,17 +151,6 @@ static struct pcmcia_low_level lubbock_pcmcia_ops = {
|
||||
|
||||
int pcmcia_lubbock_init(struct sa1111_dev *sadev)
|
||||
{
|
||||
/*
|
||||
* Set GPIO_A<3:0> to be outputs for the MAX1600,
|
||||
* and switch to standby mode.
|
||||
*/
|
||||
sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0);
|
||||
sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
|
||||
sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
|
||||
|
||||
/* Set CF Socket 1 power to standby mode. */
|
||||
lubbock_set_misc_wr((1 << 15) | (1 << 14), 0);
|
||||
|
||||
pxa2xx_drv_pcmcia_ops(&lubbock_pcmcia_ops);
|
||||
pxa2xx_configure_sockets(&sadev->dev, &lubbock_pcmcia_ops);
|
||||
return sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops,
|
||||
|
@ -10,12 +10,10 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <mach/neponset.h>
|
||||
#include <asm/hardware/sa1111.h>
|
||||
|
||||
#include "sa1111_generic.h"
|
||||
#include "max1600.h"
|
||||
|
||||
/*
|
||||
* Neponset uses the Maxim MAX1600, with the following connections:
|
||||
@ -40,70 +38,36 @@
|
||||
* "Standard Intel code" mode. Refer to the Maxim data sheet for
|
||||
* the corresponding truth table.
|
||||
*/
|
||||
static int neponset_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
|
||||
{
|
||||
struct max1600 *m;
|
||||
int ret;
|
||||
|
||||
ret = max1600_init(skt->socket.dev.parent, &m,
|
||||
skt->nr ? MAX1600_CHAN_B : MAX1600_CHAN_A,
|
||||
MAX1600_CODE_LOW);
|
||||
if (ret == 0)
|
||||
skt->driver_data = m;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
|
||||
{
|
||||
struct sa1111_pcmcia_socket *s = to_skt(skt);
|
||||
unsigned int ncr_mask, ncr_set, pa_dwr_mask, pa_dwr_set;
|
||||
struct max1600 *m = skt->driver_data;
|
||||
int ret;
|
||||
|
||||
switch (skt->nr) {
|
||||
case 0:
|
||||
pa_dwr_mask = GPIO_A0 | GPIO_A1;
|
||||
ncr_mask = NCR_A0VPP | NCR_A1VPP;
|
||||
|
||||
if (state->Vpp == 0)
|
||||
ncr_set = 0;
|
||||
else if (state->Vpp == 120)
|
||||
ncr_set = NCR_A1VPP;
|
||||
else if (state->Vpp == state->Vcc)
|
||||
ncr_set = NCR_A0VPP;
|
||||
else {
|
||||
printk(KERN_ERR "%s(): unrecognized VPP %u\n",
|
||||
__func__, state->Vpp);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
pa_dwr_mask = GPIO_A2 | GPIO_A3;
|
||||
ncr_mask = 0;
|
||||
ncr_set = 0;
|
||||
|
||||
if (state->Vpp != state->Vcc && state->Vpp != 0) {
|
||||
printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
|
||||
__func__, state->Vpp);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* pa_dwr_set is the mask for selecting Vcc on both sockets.
|
||||
* pa_dwr_mask selects which bits (and therefore socket) we change.
|
||||
*/
|
||||
switch (state->Vcc) {
|
||||
default:
|
||||
case 0: pa_dwr_set = 0; break;
|
||||
case 33: pa_dwr_set = GPIO_A1|GPIO_A2; break;
|
||||
case 50: pa_dwr_set = GPIO_A0|GPIO_A3; break;
|
||||
}
|
||||
|
||||
ret = sa1111_pcmcia_configure_socket(skt, state);
|
||||
if (ret == 0) {
|
||||
neponset_ncr_frob(ncr_mask, ncr_set);
|
||||
sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
|
||||
}
|
||||
if (ret == 0)
|
||||
ret = max1600_configure(m, state->Vcc, state->Vpp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct pcmcia_low_level neponset_pcmcia_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.hw_init = neponset_pcmcia_hw_init,
|
||||
.configure_socket = neponset_pcmcia_configure_socket,
|
||||
.first = 0,
|
||||
.nr = 2,
|
||||
@ -111,13 +75,6 @@ static struct pcmcia_low_level neponset_pcmcia_ops = {
|
||||
|
||||
int pcmcia_neponset_init(struct sa1111_dev *sadev)
|
||||
{
|
||||
/*
|
||||
* Set GPIO_A<3:0> to be outputs for the MAX1600,
|
||||
* and switch to standby mode.
|
||||
*/
|
||||
sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0);
|
||||
sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
|
||||
sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
|
||||
sa11xx_drv_pcmcia_ops(&neponset_pcmcia_ops);
|
||||
return sa1111_pcmcia_add(sadev, &neponset_pcmcia_ops,
|
||||
sa11xx_drv_pcmcia_add_one);
|
||||
|
Loading…
Reference in New Issue
Block a user