Commit 97b6f89f authored by Russell King's avatar Russell King

Merge branches 'misc', 'sa1100-for-next' and 'spectre' into for-linus

...@@ -1282,65 +1282,6 @@ int sa1111_get_audio_rate(struct sa1111_dev *sadev) ...@@ -1282,65 +1282,6 @@ int sa1111_get_audio_rate(struct sa1111_dev *sadev)
} }
EXPORT_SYMBOL(sa1111_get_audio_rate); 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. * Individual device operations.
*/ */
......
...@@ -111,6 +111,7 @@ ...@@ -111,6 +111,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
extern unsigned int processor_id; extern unsigned int processor_id;
struct proc_info_list *lookup_processor(u32 midr);
#ifdef CONFIG_CPU_CP15 #ifdef CONFIG_CPU_CP15
#define read_cpuid(reg) \ #define read_cpuid(reg) \
......
...@@ -433,10 +433,6 @@ int sa1111_check_dma_bug(dma_addr_t addr); ...@@ -433,10 +433,6 @@ int sa1111_check_dma_bug(dma_addr_t addr);
int sa1111_driver_register(struct sa1111_driver *); int sa1111_driver_register(struct sa1111_driver *);
void sa1111_driver_unregister(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 { struct sa1111_platform_data {
int irq_base; /* base for cascaded on-chip IRQs */ int irq_base; /* base for cascaded on-chip IRQs */
unsigned disable_devs; unsigned disable_devs;
......
...@@ -23,7 +23,7 @@ struct mm_struct; ...@@ -23,7 +23,7 @@ struct mm_struct;
/* /*
* Don't change this structure - ASM code relies on it. * Don't change this structure - ASM code relies on it.
*/ */
extern struct processor { struct processor {
/* MISC /* MISC
* get data abort address/flags * get data abort address/flags
*/ */
...@@ -79,9 +79,13 @@ extern struct processor { ...@@ -79,9 +79,13 @@ extern struct processor {
unsigned int suspend_size; unsigned int suspend_size;
void (*do_suspend)(void *); void (*do_suspend)(void *);
void (*do_resume)(void *); void (*do_resume)(void *);
} processor; };
#ifndef MULTI_CPU #ifndef MULTI_CPU
static inline void init_proc_vtable(const struct processor *p)
{
}
extern void cpu_proc_init(void); extern void cpu_proc_init(void);
extern void cpu_proc_fin(void); extern void cpu_proc_fin(void);
extern int cpu_do_idle(void); extern int cpu_do_idle(void);
...@@ -98,17 +102,50 @@ extern void cpu_reset(unsigned long addr, bool hvc) __attribute__((noreturn)); ...@@ -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_suspend(void *);
extern void cpu_do_resume(void *); extern void cpu_do_resume(void *);
#else #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 */ extern struct processor processor;
#define cpu_do_suspend processor.do_suspend #if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
#define cpu_do_resume processor.do_resume #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 #endif
extern void cpu_resume(void); extern void cpu_resume(void);
......
...@@ -6,8 +6,8 @@ ...@@ -6,8 +6,8 @@
void check_other_bugs(void) void check_other_bugs(void)
{ {
#ifdef MULTI_CPU #ifdef MULTI_CPU
if (processor.check_bugs) if (cpu_check_bugs)
processor.check_bugs(); cpu_check_bugs();
#endif #endif
} }
......
...@@ -145,6 +145,9 @@ __mmap_switched_data: ...@@ -145,6 +145,9 @@ __mmap_switched_data:
#endif #endif
.size __mmap_switched_data, . - __mmap_switched_data .size __mmap_switched_data, . - __mmap_switched_data
__FINIT
.text
/* /*
* This provides a C-API version of __lookup_processor_type * This provides a C-API version of __lookup_processor_type
*/ */
...@@ -156,9 +159,6 @@ ENTRY(lookup_processor_type) ...@@ -156,9 +159,6 @@ ENTRY(lookup_processor_type)
ldmfd sp!, {r4 - r6, r9, pc} ldmfd sp!, {r4 - r6, r9, pc}
ENDPROC(lookup_processor_type) ENDPROC(lookup_processor_type)
__FINIT
.text
/* /*
* Read processor ID register (CP#15, CR0), and look up in the linker-built * 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 * supported processor list. Note that we can't use the absolute addresses
......
...@@ -114,6 +114,11 @@ EXPORT_SYMBOL(elf_hwcap2); ...@@ -114,6 +114,11 @@ EXPORT_SYMBOL(elf_hwcap2);
#ifdef MULTI_CPU #ifdef MULTI_CPU
struct processor processor __ro_after_init; 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 #endif
#ifdef MULTI_TLB #ifdef MULTI_TLB
struct cpu_tlb_fns cpu_tlb __ro_after_init; struct cpu_tlb_fns cpu_tlb __ro_after_init;
...@@ -666,28 +671,33 @@ static void __init smp_build_mpidr_hash(void) ...@@ -666,28 +671,33 @@ static void __init smp_build_mpidr_hash(void)
} }
#endif #endif
static void __init setup_processor(void) /*
* 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; struct proc_info_list *list = lookup_processor_type(midr);
/*
* 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) { if (!list) {
pr_err("CPU configuration botched (ID %08x), unable to continue.\n", pr_err("CPU%u: configuration botched (ID %08x), CPU halted\n",
read_cpuid_id()); smp_processor_id(), midr);
while (1); while (1)
/* can't use cpu_relax() here as it may require MMU setup */;
} }
return list;
}
static void __init setup_processor(void)
{
unsigned int midr = read_cpuid_id();
struct proc_info_list *list = lookup_processor(midr);
cpu_name = list->cpu_name; cpu_name = list->cpu_name;
__cpu_architecture = __get_cpu_architecture(); __cpu_architecture = __get_cpu_architecture();
#ifdef MULTI_CPU init_proc_vtable(list->proc);
processor = *list->proc;
#endif
#ifdef MULTI_TLB #ifdef MULTI_TLB
cpu_tlb = *list->tlb; cpu_tlb = *list->tlb;
#endif #endif
...@@ -699,7 +709,7 @@ static void __init setup_processor(void) ...@@ -699,7 +709,7 @@ static void __init setup_processor(void)
#endif #endif
pr_info("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n", 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()); proc_arch[cpu_architecture()], get_cr());
snprintf(init_utsname()->machine, __NEW_UTS_LEN + 1, "%s%c", snprintf(init_utsname()->machine, __NEW_UTS_LEN + 1, "%s%c",
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/procinfo.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
...@@ -102,6 +103,30 @@ static unsigned long get_arch_pgd(pgd_t *pgd) ...@@ -102,6 +103,30 @@ static unsigned long get_arch_pgd(pgd_t *pgd)
#endif #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 __cpu_up(unsigned int cpu, struct task_struct *idle)
{ {
int ret; int ret;
...@@ -109,6 +134,10 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) ...@@ -109,6 +134,10 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
if (!smp_ops.smp_boot_secondary) if (!smp_ops.smp_boot_secondary)
return -ENOSYS; return -ENOSYS;
ret = secondary_biglittle_prepare(cpu);
if (ret)
return ret;
/* /*
* We need to tell the secondary core where to find * We need to tell the secondary core where to find
* its stack and the page tables. * its stack and the page tables.
...@@ -359,6 +388,8 @@ asmlinkage void secondary_start_kernel(void) ...@@ -359,6 +388,8 @@ asmlinkage void secondary_start_kernel(void)
struct mm_struct *mm = &init_mm; struct mm_struct *mm = &init_mm;
unsigned int cpu; unsigned int cpu;
secondary_biglittle_init();
/* /*
* The identity mapping is uncached (strongly ordered), so * The identity mapping is uncached (strongly ordered), so
* switch away from it before attempting any exclusive accesses. * switch away from it before attempting any exclusive accesses.
......
...@@ -46,6 +46,7 @@ config ARCH_LUBBOCK ...@@ -46,6 +46,7 @@ config ARCH_LUBBOCK
config MACH_MAINSTONE config MACH_MAINSTONE
bool "Intel HCDDBBVA0 Development Platform (aka Mainstone)" bool "Intel HCDDBBVA0 Development Platform (aka Mainstone)"
select GPIO_REG
select PXA27x select PXA27x
config MACH_ZYLONITE config MACH_ZYLONITE
......
...@@ -119,6 +119,10 @@ ...@@ -119,6 +119,10 @@
#define MST_PCMCIA_PWR_VCC_33 0x8 /* voltage VCC = 3.3V */ #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_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 */ /* board specific IRQs */
#define MAINSTONE_NR_IRQS IRQ_BOARD_START #define MAINSTONE_NR_IRQS IRQ_BOARD_START
......
...@@ -136,10 +136,26 @@ static struct pxa2xx_udc_mach_info udc_info __initdata = { ...@@ -136,10 +136,26 @@ static struct pxa2xx_udc_mach_info udc_info __initdata = {
// no D+ pullup; lubbock can't connect/disconnect in software // 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) static void lubbock_init_pcmcia(void)
{ {
struct clk *clk; struct clk *clk;
gpiod_add_lookup_table(&sa1111_pcmcia_gpio_table);
/* Add an alias for the SA1111 PCMCIA clock */ /* Add an alias for the SA1111 PCMCIA clock */
clk = clk_get_sys("pxa2xx-pcmcia", NULL); clk = clk_get_sys("pxa2xx-pcmcia", NULL);
if (!IS_ERR(clk)) { if (!IS_ERR(clk)) {
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/gpio/gpio-reg.h>
#include <linux/gpio/machine.h> #include <linux/gpio/machine.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -507,12 +508,64 @@ static void __init mainstone_init_keypad(void) ...@@ -507,12 +508,64 @@ static void __init mainstone_init_keypad(void)
static inline void mainstone_init_keypad(void) {} static inline void mainstone_init_keypad(void) {}
#endif #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) static void __init mainstone_init(void)
{ {
int SW7 = 0; /* FIXME: get from SCR (Mst doc section 3.2.1.1) */ int SW7 = 0; /* FIXME: get from SCR (Mst doc section 3.2.1.1) */
pxa2xx_mfp_config(ARRAY_AND_SIZE(mainstone_pin_config)); 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_ffuart_info(NULL);
pxa_set_btuart_info(NULL); pxa_set_btuart_info(NULL);
pxa_set_stuart_info(NULL); pxa_set_stuart_info(NULL);
......
...@@ -6,6 +6,7 @@ config SA1100_ASSABET ...@@ -6,6 +6,7 @@ config SA1100_ASSABET
bool "Assabet" bool "Assabet"
select ARM_SA1110_CPUFREQ select ARM_SA1110_CPUFREQ
select GPIO_REG select GPIO_REG
select LEDS_GPIO_REGISTER
select REGULATOR select REGULATOR
select REGULATOR_FIXED_VOLTAGE select REGULATOR_FIXED_VOLTAGE
help help
...@@ -24,6 +25,7 @@ config ASSABET_NEPONSET ...@@ -24,6 +25,7 @@ config ASSABET_NEPONSET
config SA1100_CERF config SA1100_CERF
bool "CerfBoard" bool "CerfBoard"
select ARM_SA1110_CPUFREQ select ARM_SA1110_CPUFREQ
select LEDS_GPIO_REGISTER
help help
The Intrinsyc CerfBoard is based on the StrongARM 1110 (Discontinued). The Intrinsyc CerfBoard is based on the StrongARM 1110 (Discontinued).
More information is available at: More information is available at:
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/gpio/gpio-reg.h> #include <linux/gpio/gpio-reg.h>
#include <linux/gpio/machine.h> #include <linux/gpio/machine.h>
#include <linux/gpio_keys.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/platform_data/sa11x0-serial.h> #include <linux/platform_data/sa11x0-serial.h>
#include <linux/regulator/fixed.h> #include <linux/regulator/fixed.h>
...@@ -101,7 +102,7 @@ static int __init assabet_init_gpio(void __iomem *reg, u32 def_val) ...@@ -101,7 +102,7 @@ static int __init assabet_init_gpio(void __iomem *reg, u32 def_val)
assabet_bcr_gc = gc; assabet_bcr_gc = gc;
return 0; return gc->base;
} }
/* /*
...@@ -479,6 +480,49 @@ static struct gpiod_lookup_table assabet_cf_vcc_gpio_table = { ...@@ -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) static void __init assabet_init(void)
{ {
/* /*
...@@ -533,6 +577,13 @@ 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 #ifndef ASSABET_PAL_VIDEO
sa11x0_register_lcd(&lq039q2ds54_info); sa11x0_register_lcd(&lq039q2ds54_info);
#else #else
...@@ -726,92 +777,9 @@ static void __init assabet_map_io(void) ...@@ -726,92 +777,9 @@ static void __init assabet_map_io(void)
sa1100_register_uart(2, 3); 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) void __init assabet_init_irq(void)
{ {
unsigned int assabet_gpio_base;
u32 def_val; u32 def_val;
sa1100_init_irq(); sa1100_init_irq();
...@@ -826,7 +794,10 @@ void __init assabet_init_irq(void) ...@@ -826,7 +794,10 @@ void __init assabet_init_irq(void)
* *
* This must precede any driver calls to BCR_set() or BCR_clear(). * 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") MACHINE_START(ASSABET, "Intel-Assabet")
......
...@@ -89,18 +89,8 @@ static struct gpio_led_platform_data cerf_gpio_led_info = { ...@@ -89,18 +89,8 @@ static struct gpio_led_platform_data cerf_gpio_led_info = {
.num_leds = ARRAY_SIZE(cerf_gpio_leds), .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 = { static struct platform_device *cerf_devices[] __initdata = {
&cerfuart2_device, &cerfuart2_device,
&cerf_leds,
}; };
#ifdef CONFIG_SA1100_CERF_FLASH_32MB #ifdef CONFIG_SA1100_CERF_FLASH_32MB
...@@ -176,6 +166,7 @@ static void __init cerf_init(void) ...@@ -176,6 +166,7 @@ static void __init cerf_init(void)
{ {
sa11x0_ppc_configure_mcp(); sa11x0_ppc_configure_mcp();
platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices)); 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_mtd(&cerf_flash_data, &cerf_flash_resource, 1);
sa11x0_register_mcp(&cerf_mcp_data); sa11x0_register_mcp(&cerf_mcp_data);
sa11x0_register_pcmcia(1, &cerf_cf_gpio_table); sa11x0_register_pcmcia(1, &cerf_cf_gpio_table);
......
...@@ -235,18 +235,11 @@ void sa11x0_register_lcd(struct sa1100fb_mach_info *inf) ...@@ -235,18 +235,11 @@ void sa11x0_register_lcd(struct sa1100fb_mach_info *inf)
sa11x0_register_device(&sa11x0fb_device, 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) void sa11x0_register_pcmcia(int socket, struct gpiod_lookup_table *table)
{ {
if (table) if (table)
gpiod_add_lookup_table(table); gpiod_add_lookup_table(table);
platform_device_register_simple("sa11x0-pcmcia", socket, NULL, 0); platform_device_register_simple("sa11x0-pcmcia", socket, NULL, 0);
sa11x0pcmcia_legacy = false;
} }
static struct platform_device sa11x0mtd_device = { static struct platform_device sa11x0mtd_device = {
...@@ -331,9 +324,6 @@ static int __init sa1100_init(void) ...@@ -331,9 +324,6 @@ static int __init sa1100_init(void)
{ {
pm_power_off = sa1100_power_off; pm_power_off = sa1100_power_off;
if (sa11x0pcmcia_legacy)
platform_device_register(&sa11x0pcmcia_device);
regulator_has_full_constraints(); regulator_has_full_constraints();
return platform_add_devices(sa11x0_devices, ARRAY_SIZE(sa11x0_devices)); return platform_add_devices(sa11x0_devices, ARRAY_SIZE(sa11x0_devices));
......
...@@ -126,6 +126,7 @@ static void __init h3100_mach_init(void) ...@@ -126,6 +126,7 @@ static void __init h3100_mach_init(void)
{ {
h3xxx_mach_init(); h3xxx_mach_init();
sa11x0_register_pcmcia(-1, NULL);
sa11x0_register_lcd(&h3100_lcd_info); sa11x0_register_lcd(&h3100_lcd_info);
sa11x0_register_irda(&h3100_irda_data); sa11x0_register_irda(&h3100_irda_data);
} }
......
...@@ -190,6 +190,17 @@ static struct platform_device s1d13xxxfb_device = { ...@@ -190,6 +190,17 @@ static struct platform_device s1d13xxxfb_device = {
.resource = s1d13xxxfb_resources, .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[] = { static struct resource sa1111_resources[] = {
[0] = DEFINE_RES_MEM(SA1111REGSTART, SA1111REGLEN), [0] = DEFINE_RES_MEM(SA1111REGSTART, SA1111REGLEN),
[1] = DEFINE_RES_IRQ(IRQ_GPIO1), [1] = DEFINE_RES_IRQ(IRQ_GPIO1),
...@@ -265,6 +276,7 @@ static int __init jornada720_init(void) ...@@ -265,6 +276,7 @@ static int __init jornada720_init(void)
udelay(20); /* give it some time to restart */ udelay(20); /* give it some time to restart */
gpiod_add_lookup_table(&jornada_ts_gpiod_table); gpiod_add_lookup_table(&jornada_ts_gpiod_table);
gpiod_add_lookup_table(&jornada_pcmcia_gpiod_table);
ret = platform_add_devices(devices, ARRAY_SIZE(devices)); ret = platform_add_devices(devices, ARRAY_SIZE(devices));
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/gpio/gpio-reg.h> #include <linux/gpio/gpio-reg.h>
#include <linux/gpio/machine.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/irq.h> #include <linux/irq.h>
...@@ -96,6 +97,19 @@ struct neponset_drvdata { ...@@ -96,6 +97,19 @@ struct neponset_drvdata {
struct gpio_chip *gpio[4]; 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; static struct neponset_drvdata *nep;
void neponset_ncr_frob(unsigned int mask, unsigned int val) void neponset_ncr_frob(unsigned int mask, unsigned int val)
...@@ -374,6 +388,8 @@ static int neponset_probe(struct platform_device *dev) ...@@ -374,6 +388,8 @@ static int neponset_probe(struct platform_device *dev)
d->base + AUD_CTL, AUD_NGPIO, false, d->base + AUD_CTL, AUD_NGPIO, false,
neponset_aud_names); neponset_aud_names);
gpiod_add_lookup_table(&neponset_pcmcia_table);
/* /*
* We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately * We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately
* something on the Neponset activates this IRQ on sleep (eth?) * something on the Neponset activates this IRQ on sleep (eth?)
...@@ -424,6 +440,9 @@ static int neponset_remove(struct platform_device *dev) ...@@ -424,6 +440,9 @@ static int neponset_remove(struct platform_device *dev)
platform_device_unregister(d->sa1111); platform_device_unregister(d->sa1111);
if (!IS_ERR(d->smc91x)) if (!IS_ERR(d->smc91x))
platform_device_unregister(d->smc91x); platform_device_unregister(d->smc91x);
gpiod_remove_lookup_table(&neponset_pcmcia_table);
irq_set_chained_handler(irq, NULL); irq_set_chained_handler(irq, NULL);
irq_free_descs(d->irq_base, NEP_IRQ_NR); irq_free_descs(d->irq_base, NEP_IRQ_NR);
nep = NULL; nep = NULL;
......
...@@ -274,6 +274,13 @@ ...@@ -274,6 +274,13 @@
.endm .endm
.macro define_processor_functions name:req, dabort:req, pabort:req, nommu=0, suspend=0, bugs=0 .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 .type \name\()_processor_functions, #object
.align 2 .align 2
ENTRY(\name\()_processor_functions) ENTRY(\name\()_processor_functions)
...@@ -309,6 +316,9 @@ ENTRY(\name\()_processor_functions) ...@@ -309,6 +316,9 @@ ENTRY(\name\()_processor_functions)
.endif .endif
.size \name\()_processor_functions, . - \name\()_processor_functions .size \name\()_processor_functions, . - \name\()_processor_functions
#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
.previous
#endif
.endm .endm
.macro define_cache_functions name:req .macro define_cache_functions name:req
......
...@@ -52,8 +52,6 @@ static void cpu_v7_spectre_init(void) ...@@ -52,8 +52,6 @@ static void cpu_v7_spectre_init(void)
case ARM_CPU_PART_CORTEX_A17: case ARM_CPU_PART_CORTEX_A17:
case ARM_CPU_PART_CORTEX_A73: case ARM_CPU_PART_CORTEX_A73:
case ARM_CPU_PART_CORTEX_A75: 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) = per_cpu(harden_branch_predictor_fn, cpu) =
harden_branch_predictor_bpiall; harden_branch_predictor_bpiall;
spectre_v2_method = "BPIALL"; spectre_v2_method = "BPIALL";
...@@ -61,8 +59,6 @@ static void cpu_v7_spectre_init(void) ...@@ -61,8 +59,6 @@ static void cpu_v7_spectre_init(void)
case ARM_CPU_PART_CORTEX_A15: case ARM_CPU_PART_CORTEX_A15:
case ARM_CPU_PART_BRAHMA_B15: 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) = per_cpu(harden_branch_predictor_fn, cpu) =
harden_branch_predictor_iciallu; harden_branch_predictor_iciallu;
spectre_v2_method = "ICIALLU"; spectre_v2_method = "ICIALLU";
...@@ -88,11 +84,9 @@ static void cpu_v7_spectre_init(void) ...@@ -88,11 +84,9 @@ static void cpu_v7_spectre_init(void)
ARM_SMCCC_ARCH_WORKAROUND_1, &res); ARM_SMCCC_ARCH_WORKAROUND_1, &res);
if ((int)res.a0 != 0) if ((int)res.a0 != 0)
break; break;
if (processor.switch_mm != cpu_v7_hvc_switch_mm && cpu)
goto bl_error;
per_cpu(harden_branch_predictor_fn, cpu) = per_cpu(harden_branch_predictor_fn, cpu) =
call_hvc_arch_workaround_1; 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"; spectre_v2_method = "hypervisor";
break; break;
...@@ -101,11 +95,9 @@ static void cpu_v7_spectre_init(void) ...@@ -101,11 +95,9 @@ static void cpu_v7_spectre_init(void)
ARM_SMCCC_ARCH_WORKAROUND_1, &res); ARM_SMCCC_ARCH_WORKAROUND_1, &res);
if ((int)res.a0 != 0) if ((int)res.a0 != 0)
break; break;
if (processor.switch_mm != cpu_v7_smc_switch_mm && cpu)
goto bl_error;
per_cpu(harden_branch_predictor_fn, cpu) = per_cpu(harden_branch_predictor_fn, cpu) =
call_smc_arch_workaround_1; 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"; spectre_v2_method = "firmware";
break; break;
...@@ -119,11 +111,6 @@ static void cpu_v7_spectre_init(void) ...@@ -119,11 +111,6 @@ static void cpu_v7_spectre_init(void)
if (spectre_v2_method) if (spectre_v2_method)
pr_info("CPU%u: Spectre v2: using %s workaround\n", pr_info("CPU%u: Spectre v2: using %s workaround\n",
smp_processor_id(), spectre_v2_method); smp_processor_id(), spectre_v2_method);
return;
bl_error:
pr_err("CPU%u: Spectre v2: incorrect context switching function, system vulnerable\n",
cpu);
} }
#else #else
static void cpu_v7_spectre_init(void) static void cpu_v7_spectre_init(void)
......
...@@ -112,7 +112,7 @@ ENTRY(cpu_v7_hvc_switch_mm) ...@@ -112,7 +112,7 @@ ENTRY(cpu_v7_hvc_switch_mm)
hvc #0 hvc #0
ldmfd sp!, {r0 - r3} ldmfd sp!, {r0 - r3}
b cpu_v7_switch_mm b cpu_v7_switch_mm
ENDPROC(cpu_v7_smc_switch_mm) ENDPROC(cpu_v7_hvc_switch_mm)
#endif #endif
ENTRY(cpu_v7_iciallu_switch_mm) ENTRY(cpu_v7_iciallu_switch_mm)
mov r3, #0 mov r3, #0
......
...@@ -573,7 +573,7 @@ int vfp_preserve_user_clear_hwstate(struct user_vfp *ufp, ...@@ -573,7 +573,7 @@ int vfp_preserve_user_clear_hwstate(struct user_vfp *ufp,
*/ */
ufp_exc->fpexc = hwstate->fpexc; ufp_exc->fpexc = hwstate->fpexc;
ufp_exc->fpinst = hwstate->fpinst; ufp_exc->fpinst = hwstate->fpinst;
ufp_exc->fpinst2 = ufp_exc->fpinst2; ufp_exc->fpinst2 = hwstate->fpinst2;
/* Ensure that VFP is disabled. */ /* Ensure that VFP is disabled. */
vfp_flush_hwstate(thread); vfp_flush_hwstate(thread);
......
...@@ -63,6 +63,9 @@ config CARDBUS ...@@ -63,6 +63,9 @@ config CARDBUS
If unsure, say Y. If unsure, say Y.
config PCMCIA_MAX1600
tristate
comment "PC-card bridges" comment "PC-card bridges"
config YENTA config YENTA
...@@ -191,6 +194,8 @@ config PCMCIA_SA1111 ...@@ -191,6 +194,8 @@ config PCMCIA_SA1111
select PCMCIA_SOC_COMMON select PCMCIA_SOC_COMMON
select PCMCIA_SA11XX_BASE if ARCH_SA1100 select PCMCIA_SA11XX_BASE if ARCH_SA1100
select PCMCIA_PXA2XX if ARCH_LUBBOCK && SA1111 select PCMCIA_PXA2XX if ARCH_LUBBOCK && SA1111
select PCMCIA_MAX1600 if ASSABET_NEPONSET
select PCMCIA_MAX1600 if ARCH_LUBBOCK && SA1111
help help
Say Y here to include support for SA1111-based PCMCIA or CF Say Y here to include support for SA1111-based PCMCIA or CF
sockets, found on the Jornada 720, Graphicsmaster and other sockets, found on the Jornada 720, Graphicsmaster and other
...@@ -207,6 +212,7 @@ config PCMCIA_PXA2XX ...@@ -207,6 +212,7 @@ config PCMCIA_PXA2XX
|| MACH_VPAC270 || MACH_BALLOON3 || MACH_COLIBRI \ || MACH_VPAC270 || MACH_BALLOON3 || MACH_COLIBRI \
|| MACH_COLIBRI320 || MACH_H4700) || MACH_COLIBRI320 || MACH_H4700)
select PCMCIA_SOC_COMMON select PCMCIA_SOC_COMMON
select PCMCIA_MAX1600 if MACH_MAINSTONE
help help
Say Y here to include support for the PXA2xx PCMCIA controller Say Y here to include support for the PXA2xx PCMCIA controller
......
...@@ -35,6 +35,7 @@ obj-$(CONFIG_OMAP_CF) += omap_cf.o ...@@ -35,6 +35,7 @@ obj-$(CONFIG_OMAP_CF) += omap_cf.o
obj-$(CONFIG_AT91_CF) += at91_cf.o obj-$(CONFIG_AT91_CF) += at91_cf.o
obj-$(CONFIG_ELECTRA_CF) += electra_cf.o obj-$(CONFIG_ELECTRA_CF) += electra_cf.o
obj-$(CONFIG_PCMCIA_ALCHEMY_DEVBOARD) += db1xxx_ss.o obj-$(CONFIG_PCMCIA_ALCHEMY_DEVBOARD) += db1xxx_ss.o
obj-$(CONFIG_PCMCIA_MAX1600) += max1600.o
sa1111_cs-y += sa1111_generic.o sa1111_cs-y += sa1111_generic.o
sa1111_cs-$(CONFIG_ASSABET_NEPONSET) += sa1111_neponset.o sa1111_cs-$(CONFIG_ASSABET_NEPONSET) += sa1111_neponset.o
......
// 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");
/* 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 @@ ...@@ -11,56 +11,55 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/gpio/consumer.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <pcmcia/ss.h> #include <pcmcia/ss.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/irq.h>
#include <mach/pxa2xx-regs.h>
#include <mach/mainstone.h>
#include "soc_common.h" #include "soc_common.h"
#include "max1600.h"
static int mst_pcmcia_hw_init(struct soc_pcmcia_socket *skt) static int mst_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
{ {
/* struct device *dev = skt->socket.dev.parent;
* Setup default state of GPIO outputs struct max1600 *m;
* before we enable them as outputs. int ret;
*/
if (skt->nr == 0) { skt->stat[SOC_STAT_CD].name = skt->nr ? "bdetect" : "adetect";
skt->socket.pci_irq = MAINSTONE_S0_IRQ; skt->stat[SOC_STAT_BVD1].name = skt->nr ? "bbvd1" : "abvd1";
skt->stat[SOC_STAT_CD].irq = MAINSTONE_S0_CD_IRQ; skt->stat[SOC_STAT_BVD2].name = skt->nr ? "bbvd2" : "abvd2";
skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD"; skt->stat[SOC_STAT_RDY].name = skt->nr ? "bready" : "aready";
skt->stat[SOC_STAT_BVD1].irq = MAINSTONE_S0_STSCHG_IRQ; skt->stat[SOC_STAT_VS1].name = skt->nr ? "bvs1" : "avs1";
skt->stat[SOC_STAT_BVD1].name = "PCMCIA0 STSCHG"; skt->stat[SOC_STAT_VS2].name = skt->nr ? "bvs2" : "avs2";
} else {
skt->socket.pci_irq = MAINSTONE_S1_IRQ; skt->gpio_reset = devm_gpiod_get(dev, skt->nr ? "breset" : "areset",
skt->stat[SOC_STAT_CD].irq = MAINSTONE_S1_CD_IRQ; GPIOD_OUT_HIGH);
skt->stat[SOC_STAT_CD].name = "PCMCIA1 CD"; if (IS_ERR(skt->gpio_reset))
skt->stat[SOC_STAT_BVD1].irq = MAINSTONE_S1_STSCHG_IRQ; return PTR_ERR(skt->gpio_reset);
skt->stat[SOC_STAT_BVD1].name = "PCMCIA1 STSCHG";
} ret = max1600_init(dev, &m, skt->nr ? MAX1600_CHAN_B : MAX1600_CHAN_A,
return 0; 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, static void mst_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
struct pcmcia_state *state) struct pcmcia_state *state)
{ {
unsigned long status, flip; unsigned int flip = mst_pcmcia_bvd1_status[skt->nr] ^ state->bvd1;
status = (skt->nr == 0) ? MST_PCMCIA0 : MST_PCMCIA1;
flip = (status ^ mst_pcmcia_status[skt->nr]) & MST_PCMCIA_nSTSCHG_BVD1;
/* /*
* Workaround for STSCHG which can't be deasserted: * Workaround for STSCHG which can't be deasserted:
...@@ -68,62 +67,18 @@ static void mst_pcmcia_socket_state(struct soc_pcmcia_socket *skt, ...@@ -68,62 +67,18 @@ static void mst_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
* as needed to avoid IRQ locks. * as needed to avoid IRQ locks.
*/ */
if (flip) { if (flip) {
mst_pcmcia_status[skt->nr] = status; mst_pcmcia_bvd1_status[skt->nr] = state->bvd1;
if (status & MST_PCMCIA_nSTSCHG_BVD1) if (state->bvd1)
enable_irq( (skt->nr == 0) ? MAINSTONE_S0_STSCHG_IRQ enable_irq(skt->stat[SOC_STAT_BVD1].irq);
: MAINSTONE_S1_STSCHG_IRQ );
else else
disable_irq( (skt->nr == 0) ? MAINSTONE_S0_STSCHG_IRQ disable_irq(skt->stat[SOC_STAT_BVD2].irq);
: MAINSTONE_S1_STSCHG_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, static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
const socket_state_t *state) const socket_state_t *state)
{ {
unsigned long power = 0; return max1600_configure(skt->driver_data, state->Vcc, state->Vpp);
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;
} }
static struct pcmcia_low_level mst_pcmcia_ops __initdata = { static struct pcmcia_low_level mst_pcmcia_ops __initdata = {
......
...@@ -39,8 +39,8 @@ simpad_pcmcia_socket_state(struct soc_pcmcia_socket *skt, ...@@ -39,8 +39,8 @@ simpad_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
{ {
long cs3reg = simpad_get_cs3_ro(); long cs3reg = simpad_get_cs3_ro();
state->bvd1 = 1; /* Might be cs3reg & PCMCIA_BVD1 */ /* bvd1 might be cs3reg & PCMCIA_BVD1 */
state->bvd2 = 1; /* Might be cs3reg & PCMCIA_BVD2 */ /* bvd2 might be cs3reg & PCMCIA_BVD2 */
if ((cs3reg & (PCMCIA_VS1|PCMCIA_VS2)) == if ((cs3reg & (PCMCIA_VS1|PCMCIA_VS2)) ==
(PCMCIA_VS1|PCMCIA_VS2)) { (PCMCIA_VS1|PCMCIA_VS2)) {
......
...@@ -6,29 +6,62 @@ ...@@ -6,29 +6,62 @@
* *
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h> #include <linux/io.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <asm/hardware/sa1111.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include "sa1111_generic.h" #include "sa1111_generic.h"
/* Does SOCKET1_3V actually do anything? */ /*
#define SOCKET0_POWER GPIO_GPIO0 * Socket 0 power: GPIO A0
#define SOCKET0_3V GPIO_GPIO2 * Socket 0 3V: GPIO A2
#define SOCKET1_POWER (GPIO_GPIO1 | GPIO_GPIO3) * Socket 1 power: GPIO A1 & GPIO A3
#define SOCKET1_3V GPIO_GPIO3 * 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 static int
jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
{ {
struct sa1111_pcmcia_socket *s = to_skt(skt); struct jornada720_data *j = skt->driver_data;
unsigned int pa_dwr_mask, pa_dwr_set; DECLARE_BITMAP(values, J720_GPIO_MAX) = { 0, };
int ret; int ret;
printk(KERN_INFO "%s(): config socket %d vcc %d vpp %d\n", __func__, 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 ...@@ -36,35 +69,34 @@ jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s
switch (skt->nr) { switch (skt->nr) {
case 0: case 0:
pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V;
switch (state->Vcc) { switch (state->Vcc) {
default: default:
case 0: case 0:
pa_dwr_set = 0; __assign_bit(J720_GPIO_PWR, values, 0);
__assign_bit(J720_GPIO_3V, values, 0);
break; break;
case 33: case 33:
pa_dwr_set = SOCKET0_POWER | SOCKET0_3V; __assign_bit(J720_GPIO_PWR, values, 1);
__assign_bit(J720_GPIO_3V, values, 1);
break; break;
case 50: case 50:
pa_dwr_set = SOCKET0_POWER; __assign_bit(J720_GPIO_PWR, values, 1);
__assign_bit(J720_GPIO_3V, values, 0);
break; break;
} }
break; break;
case 1: case 1:
pa_dwr_mask = SOCKET1_POWER;
switch (state->Vcc) { switch (state->Vcc) {
default: default:
case 0: case 0:
pa_dwr_set = 0; __assign_bit(J720_GPIO_PWR, values, 0);
__assign_bit(J720_GPIO_3V, values, 0);
break; break;
case 33: case 33:
pa_dwr_set = SOCKET1_POWER;
break;
case 50: case 50:
pa_dwr_set = SOCKET1_POWER; __assign_bit(J720_GPIO_PWR, values, 1);
__assign_bit(J720_GPIO_3V, values, 1);
break; break;
} }
break; break;
...@@ -81,13 +113,15 @@ jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s ...@@ -81,13 +113,15 @@ jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s
ret = sa1111_pcmcia_configure_socket(skt, state); ret = sa1111_pcmcia_configure_socket(skt, state);
if (ret == 0) 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; return ret;
} }
static struct pcmcia_low_level jornada720_pcmcia_ops = { static struct pcmcia_low_level jornada720_pcmcia_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.hw_init = jornada720_pcmcia_hw_init,
.configure_socket = jornada720_pcmcia_configure_socket, .configure_socket = jornada720_pcmcia_configure_socket,
.first = 0, .first = 0,
.nr = 2, .nr = 2,
...@@ -95,16 +129,9 @@ static struct pcmcia_low_level jornada720_pcmcia_ops = { ...@@ -95,16 +129,9 @@ static struct pcmcia_low_level jornada720_pcmcia_ops = {
int pcmcia_jornada720_init(struct sa1111_dev *sadev) 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? */ /* Fixme: why messing around with SA11x0's GPIO1? */
GRER |= 0x00000002; 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); sa11xx_drv_pcmcia_ops(&jornada720_pcmcia_ops);
return sa1111_pcmcia_add(sadev, &jornada720_pcmcia_ops, return sa1111_pcmcia_add(sadev, &jornada720_pcmcia_ops,
sa11xx_drv_pcmcia_add_one); sa11xx_drv_pcmcia_add_one);
......
...@@ -24,20 +24,31 @@ ...@@ -24,20 +24,31 @@
#include <mach/hardware.h> #include <mach/hardware.h>
#include <asm/hardware/sa1111.h> #include <asm/hardware/sa1111.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <mach/lubbock.h>
#include "sa1111_generic.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 static int
lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
const socket_state_t *state) const socket_state_t *state)
{ {
struct sa1111_pcmcia_socket *s = to_skt(skt); struct max1600 *m = skt->driver_data;
unsigned int pa_dwr_mask, pa_dwr_set, misc_mask, misc_set;
int ret = 0; int ret = 0;
pa_dwr_mask = pa_dwr_set = misc_mask = misc_set = 0;
/* Lubbock uses the Maxim MAX1602, with the following connections: /* Lubbock uses the Maxim MAX1602, with the following connections:
* *
* Socket 0 (PCMCIA): * Socket 0 (PCMCIA):
...@@ -71,74 +82,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, ...@@ -71,74 +82,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
again: again:
switch (skt->nr) { switch (skt->nr) {
case 0: 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: 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; break;
default: default:
...@@ -147,11 +91,8 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, ...@@ -147,11 +91,8 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
if (ret == 0) if (ret == 0)
ret = sa1111_pcmcia_configure_socket(skt, state); ret = sa1111_pcmcia_configure_socket(skt, state);
if (ret == 0)
if (ret == 0) { ret = max1600_configure(m, state->Vcc, state->Vpp);
lubbock_set_misc_wr(misc_mask, misc_set);
sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
}
#if 1 #if 1
if (ret == 0 && state->Vcc == 33) { if (ret == 0 && state->Vcc == 33) {
...@@ -175,8 +116,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, ...@@ -175,8 +116,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
/* /*
* Switch to 5V, Configure socket with 5V voltage * Switch to 5V, Configure socket with 5V voltage
*/ */
lubbock_set_misc_wr(misc_mask, 0); max1600_configure(m, 0, 0);
sa1111_set_io(s->dev, pa_dwr_mask, 0);
/* /*
* It takes about 100ms to turn off Vcc. * It takes about 100ms to turn off Vcc.
...@@ -201,6 +141,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, ...@@ -201,6 +141,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
static struct pcmcia_low_level lubbock_pcmcia_ops = { static struct pcmcia_low_level lubbock_pcmcia_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.hw_init = lubbock_pcmcia_hw_init,
.configure_socket = lubbock_pcmcia_configure_socket, .configure_socket = lubbock_pcmcia_configure_socket,
.first = 0, .first = 0,
.nr = 2, .nr = 2,
...@@ -210,17 +151,6 @@ static struct pcmcia_low_level lubbock_pcmcia_ops = { ...@@ -210,17 +151,6 @@ static struct pcmcia_low_level lubbock_pcmcia_ops = {
int pcmcia_lubbock_init(struct sa1111_dev *sadev) 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_drv_pcmcia_ops(&lubbock_pcmcia_ops);
pxa2xx_configure_sockets(&sadev->dev, &lubbock_pcmcia_ops); pxa2xx_configure_sockets(&sadev->dev, &lubbock_pcmcia_ops);
return sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops, return sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops,
......
...@@ -10,12 +10,10 @@ ...@@ -10,12 +10,10 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/init.h> #include <linux/init.h>
#include <mach/hardware.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <mach/neponset.h>
#include <asm/hardware/sa1111.h>
#include "sa1111_generic.h" #include "sa1111_generic.h"
#include "max1600.h"
/* /*
* Neponset uses the Maxim MAX1600, with the following connections: * Neponset uses the Maxim MAX1600, with the following connections:
...@@ -40,70 +38,36 @@ ...@@ -40,70 +38,36 @@
* "Standard Intel code" mode. Refer to the Maxim data sheet for * "Standard Intel code" mode. Refer to the Maxim data sheet for
* the corresponding truth table. * the corresponding truth table.
*/ */
static int neponset_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
static int
neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
{ {
struct sa1111_pcmcia_socket *s = to_skt(skt); struct max1600 *m;
unsigned int ncr_mask, ncr_set, pa_dwr_mask, pa_dwr_set;
int ret; int ret;
switch (skt->nr) { ret = max1600_init(skt->socket.dev.parent, &m,
case 0: skt->nr ? MAX1600_CHAN_B : MAX1600_CHAN_A,
pa_dwr_mask = GPIO_A0 | GPIO_A1; MAX1600_CODE_LOW);
ncr_mask = NCR_A0VPP | NCR_A1VPP; if (ret == 0)
skt->driver_data = m;
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 ret;
return -1; }
}
/* static int
* pa_dwr_set is the mask for selecting Vcc on both sockets. neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
* pa_dwr_mask selects which bits (and therefore socket) we change. {
*/ struct max1600 *m = skt->driver_data;
switch (state->Vcc) { int ret;
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); ret = sa1111_pcmcia_configure_socket(skt, state);
if (ret == 0) { if (ret == 0)
neponset_ncr_frob(ncr_mask, ncr_set); ret = max1600_configure(m, state->Vcc, state->Vpp);
sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
}
return ret; return ret;
} }
static struct pcmcia_low_level neponset_pcmcia_ops = { static struct pcmcia_low_level neponset_pcmcia_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.hw_init = neponset_pcmcia_hw_init,
.configure_socket = neponset_pcmcia_configure_socket, .configure_socket = neponset_pcmcia_configure_socket,
.first = 0, .first = 0,
.nr = 2, .nr = 2,
...@@ -111,13 +75,6 @@ static struct pcmcia_low_level neponset_pcmcia_ops = { ...@@ -111,13 +75,6 @@ static struct pcmcia_low_level neponset_pcmcia_ops = {
int pcmcia_neponset_init(struct sa1111_dev *sadev) 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); sa11xx_drv_pcmcia_ops(&neponset_pcmcia_ops);
return sa1111_pcmcia_add(sadev, &neponset_pcmcia_ops, return sa1111_pcmcia_add(sadev, &neponset_pcmcia_ops,
sa11xx_drv_pcmcia_add_one); sa11xx_drv_pcmcia_add_one);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment