diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index a3f436ba554d68b8becca9c86105914be4c98078..c1227757817ba713b5d5d83b8becfdfba8b122fd 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -28,14 +28,14 @@ config ARM select ARCH_WANT_IPC_PARSE_VERSION select BUILDTIME_EXTABLE_SORT if MMU select CLONE_BACKWARDS - select CPU_PM if (SUSPEND || CPU_IDLE) + select CPU_PM if SUSPEND || CPU_IDLE select DCACHE_WORD_ACCESS if HAVE_EFFICIENT_UNALIGNED_ACCESS select DMA_REMAP if MMU select EDAC_SUPPORT select EDAC_ATOMIC_SCRUB select GENERIC_ALLOCATOR select GENERIC_ARCH_TOPOLOGY if ARM_CPU_TOPOLOGY - select GENERIC_ATOMIC64 if (CPU_V7M || CPU_V6 || !CPU_32v6K || !AEABI) + select GENERIC_ATOMIC64 if CPU_V7M || CPU_V6 || !CPU_32v6K || !AEABI select GENERIC_CLOCKEVENTS_BROADCAST if SMP select GENERIC_CPU_AUTOPROBE select GENERIC_EARLY_IOREMAP @@ -50,12 +50,12 @@ config ARM select GENERIC_STRNLEN_USER select HANDLE_DOMAIN_IRQ select HARDIRQS_SW_RESEND - select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT) + select HAVE_ARCH_AUDITSYSCALL if AEABI && !OABI_COMPAT select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6 select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32 && MMU select HAVE_ARCH_MMAP_RND_BITS if MMU - select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT) + select HAVE_ARCH_SECCOMP_FILTER if AEABI && !OABI_COMPAT select HAVE_ARCH_THREAD_STRUCT_WHITELIST select HAVE_ARCH_TRACEHOOK select HAVE_ARM_SMCCC if CPU_V7 @@ -64,16 +64,16 @@ config ARM select HAVE_C_RECORDMCOUNT select HAVE_DEBUG_KMEMLEAK select HAVE_DMA_CONTIGUOUS if MMU - select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL) && !CPU_ENDIAN_BE32 && MMU + select HAVE_DYNAMIC_FTRACE if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU select HAVE_DYNAMIC_FTRACE_WITH_REGS if HAVE_DYNAMIC_FTRACE select HAVE_EFFICIENT_UNALIGNED_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && MMU select HAVE_EXIT_THREAD - select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL) - select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL) - select HAVE_FUNCTION_TRACER if (!XIP_KERNEL) + select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL + select HAVE_FUNCTION_GRAPH_TRACER if !THUMB2_KERNEL + select HAVE_FUNCTION_TRACER if !XIP_KERNEL select HAVE_GCC_PLUGINS select HAVE_GENERIC_DMA_COHERENT - select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7)) + select HAVE_HW_BREAKPOINT if PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7) select HAVE_IDE if PCI || ISA || PCMCIA select HAVE_IRQ_TIME_ACCOUNTING select HAVE_KERNEL_GZIP @@ -82,15 +82,15 @@ config ARM select HAVE_KERNEL_LZO select HAVE_KERNEL_XZ select HAVE_KPROBES if !XIP_KERNEL && !CPU_ENDIAN_BE32 && !CPU_V7M - select HAVE_KRETPROBES if (HAVE_KPROBES) + select HAVE_KRETPROBES if HAVE_KPROBES select HAVE_MOD_ARCH_SPECIFIC select HAVE_NMI - select HAVE_OPROFILE if (HAVE_PERF_EVENTS) + select HAVE_OPROFILE if HAVE_PERF_EVENTS select HAVE_OPTPROBES if !THUMB2_KERNEL select HAVE_PERF_EVENTS select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP - select HAVE_RCU_TABLE_FREE if (SMP && ARM_LPAE) + select HAVE_RCU_TABLE_FREE if SMP && ARM_LPAE select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_RSEQ select HAVE_STACKPROTECTOR @@ -1738,7 +1738,6 @@ config PARAVIRT config PARAVIRT_TIME_ACCOUNTING bool "Paravirtual steal time accounting" select PARAVIRT - default n help Select this option to enable fine granularity task steal time accounting. Time spent executing other tasks in parallel with diff --git a/arch/arm/boot/compressed/atags_to_fdt.c b/arch/arm/boot/compressed/atags_to_fdt.c index 41fa7316c52b9014b63bae76896a4288b5ff4e30..330cd3c2eae55b1f83c3a92c1a1089414594eb8a 100644 --- a/arch/arm/boot/compressed/atags_to_fdt.c +++ b/arch/arm/boot/compressed/atags_to_fdt.c @@ -98,6 +98,24 @@ static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline) setprop_string(fdt, "/chosen", "bootargs", cmdline); } +static void hex_str(char *out, uint32_t value) +{ + uint32_t digit; + int idx; + + for (idx = 7; idx >= 0; idx--) { + digit = value >> 28; + value <<= 4; + digit &= 0xf; + if (digit < 10) + digit += '0'; + else + digit += 'A'-10; + *out++ = digit; + } + *out = '\0'; +} + /* * Convert and fold provided ATAGs into the provided FDT. * @@ -180,6 +198,11 @@ int atags_to_fdt(void *atag_list, void *fdt, int total_space) initrd_start); setprop_cell(fdt, "/chosen", "linux,initrd-end", initrd_start + initrd_size); + } else if (atag->hdr.tag == ATAG_SERIAL) { + char serno[16+2]; + hex_str(serno, atag->u.serialnr.high); + hex_str(serno+8, atag->u.serialnr.low); + setprop_string(fdt, "/", "serial-number", serno); } } diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index a2c878769eaf5a2c616117ff732b1df540778ac8..45412d21aa6b7da2241cb6377a747977a1f80748 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -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. */ diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 88286dd483ff901bd1d215fb5450db32add47bd2..28a48e0d4cca04f65b8bc90179c8daf5a3632397 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -243,13 +243,15 @@ .endm #endif -#define USER(x...) \ +#define USERL(l, x...) \ 9999: x; \ .pushsection __ex_table,"a"; \ .align 3; \ - .long 9999b,9001f; \ + .long 9999b,l; \ .popsection +#define USER(x...) USERL(9001f, x) + #ifdef CONFIG_SMP #define ALT_SMP(instr...) \ 9998: instr diff --git a/arch/arm/include/asm/hardware/sa1111.h b/arch/arm/include/asm/hardware/sa1111.h index 798e520e8a495a3d12f45cf2985d2bebf5e3792c..d134b9a5ff94794b6f1b251cf97f66b28d531dd2 100644 --- a/arch/arm/include/asm/hardware/sa1111.h +++ b/arch/arm/include/asm/hardware/sa1111.h @@ -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; diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 27ed17ec45fe2a5728f8cec106baf3a8596afb2f..42aa4a22803c2760d7799bdd17b4434d9cc387bd 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -349,6 +349,13 @@ do { \ #define __get_user_asm_byte(x, addr, err) \ __get_user_asm(x, addr, err, ldrb) +#if __LINUX_ARM_ARCH__ >= 6 + +#define __get_user_asm_half(x, addr, err) \ + __get_user_asm(x, addr, err, ldrh) + +#else + #ifndef __ARMEB__ #define __get_user_asm_half(x, __gu_addr, err) \ ({ \ @@ -367,6 +374,8 @@ do { \ }) #endif +#endif /* __LINUX_ARM_ARCH__ >= 6 */ + #define __get_user_asm_word(x, addr, err) \ __get_user_asm(x, addr, err, ldr) #endif @@ -442,6 +451,13 @@ do { \ #define __put_user_asm_byte(x, __pu_addr, err) \ __put_user_asm(x, __pu_addr, err, strb) +#if __LINUX_ARM_ARCH__ >= 6 + +#define __put_user_asm_half(x, __pu_addr, err) \ + __put_user_asm(x, __pu_addr, err, strh) + +#else + #ifndef __ARMEB__ #define __put_user_asm_half(x, __pu_addr, err) \ ({ \ @@ -458,6 +474,8 @@ do { \ }) #endif +#endif /* __LINUX_ARM_ARCH__ >= 6 */ + #define __put_user_asm_word(x, __pu_addr, err) \ __put_user_asm(x, __pu_addr, err, str) diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 6b1148cafffdbe09070f996343287a4db9bb1baa..4485d0404514cda1b18e5bbd11594f5378a5366f 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -398,7 +398,7 @@ ENTRY(secondary_startup) ldmia r4, {r5, r7, r12} @ address to jump to after sub lr, r4, r5 @ mmu has been enabled add r3, r7, lr - ldrd r4, [r3, #0] @ get secondary_data.pgdir + ldrd r4, r5, [r3, #0] @ get secondary_data.pgdir ARM_BE8(eor r4, r4, r5) @ Swap r5 and r4 in BE: ARM_BE8(eor r5, r4, r5) @ it can be done in 3 steps ARM_BE8(eor r4, r4, r5) @ without using a temp reg. diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 12a6172263c0b057a94f2041accf581088374fb0..3bf82232b1bed4bce829749ce6af885bbc43c191 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -724,6 +724,21 @@ void smp_send_stop(void) pr_warn("SMP: failed to stop secondary CPUs\n"); } +/* In case panic() and panic() called at the same time on CPU1 and CPU2, + * and CPU 1 calls panic_smp_self_stop() before crash_smp_send_stop() + * CPU1 can't receive the ipi irqs from CPU2, CPU1 will be always online, + * kdump fails. So split out the panic_smp_self_stop() and add + * set_cpu_online(smp_processor_id(), false). + */ +void panic_smp_self_stop(void) +{ + pr_debug("CPU %u will stop doing anything useful since another CPU has paniced\n", + smp_processor_id()); + set_cpu_online(smp_processor_id(), false); + while (1) + cpu_relax(); +} + /* * not supported here */ diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S index 6709a8d33963b679b0a0f6ec683e3291a7f07a71..0d4c189c7f4f00ca4795ae7aa78917838697580b 100644 --- a/arch/arm/lib/copy_from_user.S +++ b/arch/arm/lib/copy_from_user.S @@ -34,12 +34,13 @@ * Number of bytes NOT copied. */ +#ifdef CONFIG_CPU_USE_DOMAINS + #ifndef CONFIG_THUMB2_KERNEL #define LDR1W_SHIFT 0 #else #define LDR1W_SHIFT 1 #endif -#define STR1W_SHIFT 0 .macro ldr1w ptr reg abort ldrusr \reg, \ptr, 4, abort=\abort @@ -57,10 +58,30 @@ ldr4w \ptr, \reg5, \reg6, \reg7, \reg8, \abort .endm +#else + +#define LDR1W_SHIFT 0 + + .macro ldr1w ptr reg abort + USERL(\abort, W(ldr) \reg, [\ptr], #4) + .endm + + .macro ldr4w ptr reg1 reg2 reg3 reg4 abort + USERL(\abort, ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4}) + .endm + + .macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort + USERL(\abort, ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}) + .endm + +#endif /* CONFIG_CPU_USE_DOMAINS */ + .macro ldr1b ptr reg cond=al abort ldrusr \reg, \ptr, 1, \cond, abort=\abort .endm +#define STR1W_SHIFT 0 + .macro str1w ptr reg abort W(str) \reg, [\ptr], #4 .endm diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S index 970abe521197fa1881473c2f7b1423bcea77227c..97a6ff4b7e3cab0bd4501498bf8a7433dc9ca08a 100644 --- a/arch/arm/lib/copy_to_user.S +++ b/arch/arm/lib/copy_to_user.S @@ -35,11 +35,6 @@ */ #define LDR1W_SHIFT 0 -#ifndef CONFIG_THUMB2_KERNEL -#define STR1W_SHIFT 0 -#else -#define STR1W_SHIFT 1 -#endif .macro ldr1w ptr reg abort W(ldr) \reg, [\ptr], #4 @@ -57,6 +52,14 @@ ldr\cond\()b \reg, [\ptr], #1 .endm +#ifdef CONFIG_CPU_USE_DOMAINS + +#ifndef CONFIG_THUMB2_KERNEL +#define STR1W_SHIFT 0 +#else +#define STR1W_SHIFT 1 +#endif + .macro str1w ptr reg abort strusr \reg, \ptr, 4, abort=\abort .endm @@ -72,6 +75,20 @@ str1w \ptr, \reg8, \abort .endm +#else + +#define STR1W_SHIFT 0 + + .macro str1w ptr reg abort + USERL(\abort, W(str) \reg, [\ptr], #4) + .endm + + .macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort + USERL(\abort, stmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}) + .endm + +#endif /* CONFIG_CPU_USE_DOMAINS */ + .macro str1b ptr reg cond=al abort strusr \reg, \ptr, 1, \cond, abort=\abort .endm diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S index 746e7801dcdf70fed9e339c2d6800b3f275c49b7..b2e4bc3a635e22002fd90eaf4d802b528f6dab32 100644 --- a/arch/arm/lib/getuser.S +++ b/arch/arm/lib/getuser.S @@ -42,6 +42,12 @@ _ASM_NOKPROBE(__get_user_1) ENTRY(__get_user_2) check_uaccess r0, 2, r1, r2, __get_user_bad +#if __LINUX_ARM_ARCH__ >= 6 + +2: TUSER(ldrh) r2, [r0] + +#else + #ifdef CONFIG_CPU_USE_DOMAINS rb .req ip 2: ldrbt r2, [r0], #1 @@ -56,6 +62,9 @@ rb .req r0 #else orr r2, rb, r2, lsl #8 #endif + +#endif /* __LINUX_ARM_ARCH__ >= 6 */ + mov r0, #0 ret lr ENDPROC(__get_user_2) @@ -145,7 +154,9 @@ _ASM_NOKPROBE(__get_user_bad8) .pushsection __ex_table, "a" .long 1b, __get_user_bad .long 2b, __get_user_bad +#if __LINUX_ARM_ARCH__ < 6 .long 3b, __get_user_bad +#endif .long 4b, __get_user_bad .long 5b, __get_user_bad8 .long 6b, __get_user_bad8 diff --git a/arch/arm/lib/putuser.S b/arch/arm/lib/putuser.S index 38d660d3705f4f259c5299d2cc8c1126f0a1dbb4..515eeaa9975c6cbf75b8aba01d85df7deb063b25 100644 --- a/arch/arm/lib/putuser.S +++ b/arch/arm/lib/putuser.S @@ -41,16 +41,13 @@ ENDPROC(__put_user_1) ENTRY(__put_user_2) check_uaccess r0, 2, r1, ip, __put_user_bad - mov ip, r2, lsr #8 -#ifdef CONFIG_THUMB2_KERNEL -#ifndef __ARMEB__ -2: TUSER(strb) r2, [r0] -3: TUSER(strb) ip, [r0, #1] +#if __LINUX_ARM_ARCH__ >= 6 + +2: TUSER(strh) r2, [r0] + #else -2: TUSER(strb) ip, [r0] -3: TUSER(strb) r2, [r0, #1] -#endif -#else /* !CONFIG_THUMB2_KERNEL */ + + mov ip, r2, lsr #8 #ifndef __ARMEB__ 2: TUSER(strb) r2, [r0], #1 3: TUSER(strb) ip, [r0] @@ -58,7 +55,8 @@ ENTRY(__put_user_2) 2: TUSER(strb) ip, [r0], #1 3: TUSER(strb) r2, [r0] #endif -#endif /* CONFIG_THUMB2_KERNEL */ + +#endif /* __LINUX_ARM_ARCH__ >= 6 */ mov r0, #0 ret lr ENDPROC(__put_user_2) @@ -91,7 +89,9 @@ ENDPROC(__put_user_bad) .pushsection __ex_table, "a" .long 1b, __put_user_bad .long 2b, __put_user_bad +#if __LINUX_ARM_ARCH__ < 6 .long 3b, __put_user_bad +#endif .long 4b, __put_user_bad .long 5b, __put_user_bad .long 6b, __put_user_bad diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 9f27b486a5362fca0bbd3819d3498e6e55755201..5e33d1a9066473fe6aa9cd871b15c1f80cc486c7 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -223,7 +223,6 @@ config MACH_NOKIA_N8X0 config OMAP3_SDRC_AC_TIMING bool "Enable SDRC AC timing register changes" depends on ARCH_OMAP3 - default n help If you know that none of your system initiators will attempt to access SDRAM during CORE DVFS, select Y here. This should boost diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index 1c73694c871ad8289b572056d5c3727f3ee22eb2..10e070368f64f6997b8f5b9ad933bfe708e7a507 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -69,8 +69,6 @@ static const struct omap_smp_config omap5_cfg __initconst = { .startup_addr = omap5_secondary_startup, }; -static DEFINE_SPINLOCK(boot_lock); - void __iomem *omap4_get_scu_base(void) { return cfg.scu_base; @@ -173,12 +171,6 @@ static void omap4_secondary_init(unsigned int cpu) /* Enable ACR to allow for ICUALLU workaround */ omap5_secondary_harden_predictor(); } - - /* - * Synchronise with the boot thread. - */ - spin_lock(&boot_lock); - spin_unlock(&boot_lock); } static int omap4_boot_secondary(unsigned int cpu, struct task_struct *idle) @@ -187,12 +179,6 @@ static int omap4_boot_secondary(unsigned int cpu, struct task_struct *idle) static bool booted; static struct powerdomain *cpu1_pwrdm; - /* - * Set synchronisation state between this boot processor - * and the secondary one - */ - spin_lock(&boot_lock); - /* * Update the AuxCoreBoot0 with boot state for secondary core. * omap4_secondary_startup() routine will hold the secondary core till @@ -266,12 +252,6 @@ static int omap4_boot_secondary(unsigned int cpu, struct task_struct *idle) arch_send_wakeup_ipi_mask(cpumask_of(cpu)); - /* - * Now the secondary core is starting up let it run its - * calibrations, then wait for it to finish - */ - spin_unlock(&boot_lock); - return 0; } diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index b185794549be464c9db36b86f36d766858f5895e..dc8e4f4b7adeef460cc58767f5dabe155c327498 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -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 @@ -551,7 +552,6 @@ config TOSA_BT config TOSA_USE_EXT_KEYCODES bool "Tosa keyboard: use extended keycodes" depends on MACH_TOSA - default n help Say Y here to enable the tosa keyboard driver to generate extended (>= 127) keycodes. Be aware, that they can't be correctly interpreted diff --git a/arch/arm/mach-pxa/include/mach/mainstone.h b/arch/arm/mach-pxa/include/mach/mainstone.h index e82a7d31104e02f5c21987d198fe229bad8afff5..474041a83d80b09de20840468bd2218e2114a78f 100644 --- a/arch/arm/mach-pxa/include/mach/mainstone.h +++ b/arch/arm/mach-pxa/include/mach/mainstone.h @@ -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 diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index c576e8462043c998009095b6e169b0a3f30641a7..a1391e113ef464638ef649eb157a85c08b3144a3 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -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)) { diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index 9e39fc2ad2d97c6188aeda052067fdfda1329d49..d6e17d407ac0c555912379441a946e15d2649b27 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -13,6 +13,7 @@ * published by the Free Software Foundation. */ #include +#include #include #include #include @@ -504,12 +505,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); diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile index adf39ad71cc310d91a55a88a2b466ff09427fb81..6ca6400fa51e142469293b878d68daad4c8a5930 100644 --- a/arch/arm/mach-realview/Makefile +++ b/arch/arm/mach-realview/Makefile @@ -5,4 +5,3 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/arch/arm/plat-versatile/inc obj-y += realview-dt.o obj-$(CONFIG_SMP) += platsmp-dt.o -obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o diff --git a/arch/arm/mach-realview/hotplug.c b/arch/arm/mach-realview/hotplug.c deleted file mode 100644 index 968e2d1964f672536264d7bb6029907a03631e28..0000000000000000000000000000000000000000 --- a/arch/arm/mach-realview/hotplug.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * linux/arch/arm/mach-realview/hotplug.c - * - * Copyright (C) 2002 ARM Ltd. - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include -#include -#include - -#include -#include - -static inline void cpu_enter_lowpower(void) -{ - unsigned int v; - - asm volatile( - " mcr p15, 0, %1, c7, c5, 0\n" - " mcr p15, 0, %1, c7, c10, 4\n" - /* - * Turn off coherency - */ - " mrc p15, 0, %0, c1, c0, 1\n" - " bic %0, %0, #0x20\n" - " mcr p15, 0, %0, c1, c0, 1\n" - " mrc p15, 0, %0, c1, c0, 0\n" - " bic %0, %0, %2\n" - " mcr p15, 0, %0, c1, c0, 0\n" - : "=&r" (v) - : "r" (0), "Ir" (CR_C) - : "cc"); -} - -static inline void cpu_leave_lowpower(void) -{ - unsigned int v; - - asm volatile( "mrc p15, 0, %0, c1, c0, 0\n" - " orr %0, %0, %1\n" - " mcr p15, 0, %0, c1, c0, 0\n" - " mrc p15, 0, %0, c1, c0, 1\n" - " orr %0, %0, #0x20\n" - " mcr p15, 0, %0, c1, c0, 1\n" - : "=&r" (v) - : "Ir" (CR_C) - : "cc"); -} - -static inline void platform_do_lowpower(unsigned int cpu, int *spurious) -{ - /* - * there is no power-control hardware on this platform, so all - * we can do is put the core into WFI; this is safe as the calling - * code will have already disabled interrupts - */ - for (;;) { - /* - * here's the WFI - */ - asm(".word 0xe320f003\n" - : - : - : "memory", "cc"); - - if (pen_release == cpu_logical_map(cpu)) { - /* - * OK, proper wakeup, we're done - */ - break; - } - - /* - * Getting here, means that we have come out of WFI without - * having been woken up - this shouldn't happen - * - * Just note it happening - when we're woken, we can report - * its occurrence. - */ - (*spurious)++; - } -} - -/* - * platform-specific code to shutdown a CPU - * - * Called with IRQs disabled - */ -void realview_cpu_die(unsigned int cpu) -{ - int spurious = 0; - - /* - * we're ready for shutdown now, so do it - */ - cpu_enter_lowpower(); - platform_do_lowpower(cpu, &spurious); - - /* - * bring this CPU back into the world of cache - * coherency, and then restore interrupts - */ - cpu_leave_lowpower(); - - if (spurious) - pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); -} diff --git a/arch/arm/mach-realview/hotplug.h b/arch/arm/mach-realview/hotplug.h deleted file mode 100644 index eacd7a4dad2f96c0a912fb5b07c6198de9f232eb..0000000000000000000000000000000000000000 --- a/arch/arm/mach-realview/hotplug.h +++ /dev/null @@ -1 +0,0 @@ -void realview_cpu_die(unsigned int cpu); diff --git a/arch/arm/mach-realview/platsmp-dt.c b/arch/arm/mach-realview/platsmp-dt.c index c242423bf8db5a5e64d9818f01c42e0b23b699fd..ce331b3dbf54d46ae75a58ba92f6f1b90b5401e9 100644 --- a/arch/arm/mach-realview/platsmp-dt.c +++ b/arch/arm/mach-realview/platsmp-dt.c @@ -17,7 +17,6 @@ #include #include -#include "hotplug.h" #define REALVIEW_SYS_FLAGSSET_OFFSET 0x30 @@ -79,6 +78,13 @@ static void __init realview_smp_prepare_cpus(unsigned int max_cpus) __pa_symbol(versatile_secondary_startup)); } +#ifdef CONFIG_HOTPLUG_CPU +static void realview_cpu_die(unsigned int cpu) +{ + return versatile_immitation_cpu_die(cpu, 0x20); +} +#endif + static const struct smp_operations realview_dt_smp_ops __initconst = { .smp_prepare_cpus = realview_smp_prepare_cpus, .smp_secondary_init = versatile_secondary_init, diff --git a/arch/arm/mach-sa1100/Kconfig b/arch/arm/mach-sa1100/Kconfig index acb2c520ae8b55a0ec420924d186091bbf9ce11b..ce41c6708a8309337601e72423921b07e48d9bc4 100644 --- a/arch/arm/mach-sa1100/Kconfig +++ b/arch/arm/mach-sa1100/Kconfig @@ -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: diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index 3e8c0948abcc3ef52e557429211936268e4cf034..dfa42496ec27957f8a1cddff3b640626d430c374 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -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") diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c index b2a4b41626efbb3f920efd6ea99fa35205b6e7a3..88e526561a2440f2ea1b66411bb1ba238a038169 100644 --- a/arch/arm/mach-sa1100/cerf.c +++ b/arch/arm/mach-sa1100/cerf.c @@ -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); diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 800321c6cbd8cf5edb209904b52634292f35c735..755290bf658b49f825d0dc57e5e6cdb58e925c4d 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c @@ -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)); diff --git a/arch/arm/mach-sa1100/h3100.c b/arch/arm/mach-sa1100/h3100.c index c6b412054a3c9057a3840acacbca0fd49bc70947..9dc5bcb7326bbcbcad649db51f93c5d2dbd783a8 100644 --- a/arch/arm/mach-sa1100/h3100.c +++ b/arch/arm/mach-sa1100/h3100.c @@ -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); } diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c index 0a2ca9be00e6dff68a8dcbd60e66468c4cf66680..6298bad09ef35ee1abeb658309dbc00d11ac8cc1 100644 --- a/arch/arm/mach-sa1100/jornada720.c +++ b/arch/arm/mach-sa1100/jornada720.c @@ -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)); } diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c index b1823f445358cf99ffba59704a77d6917d181378..eb60a71cf125a4b78c57e51bcbe5d55f53eb49c6 100644 --- a/arch/arm/mach-sa1100/neponset.c +++ b/arch/arm/mach-sa1100/neponset.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -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; diff --git a/arch/arm/mach-vexpress/Makefile b/arch/arm/mach-vexpress/Makefile index 51c35e2b737aa6eb6123b384ab36880d0f5fa633..3651a1ed0f2b197f875470782bc60f745ed4b5dd 100644 --- a/arch/arm/mach-vexpress/Makefile +++ b/arch/arm/mach-vexpress/Makefile @@ -15,6 +15,5 @@ obj-$(CONFIG_ARCH_VEXPRESS_TC2_PM) += tc2_pm.o CFLAGS_tc2_pm.o += -march=armv7-a CFLAGS_REMOVE_tc2_pm.o = -pg obj-$(CONFIG_SMP) += platsmp.o -obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_ARCH_MPS2) += v2m-mps2.o diff --git a/arch/arm/mach-vexpress/core.h b/arch/arm/mach-vexpress/core.h index a162ab46ee0253d4493873676b0f1758e3130c1f..f4a7519084f170fb949139e7ccfe3ac37ccef57b 100644 --- a/arch/arm/mach-vexpress/core.h +++ b/arch/arm/mach-vexpress/core.h @@ -1,5 +1,3 @@ bool vexpress_smp_init_ops(void); extern const struct smp_operations vexpress_smp_dt_ops; - -extern void vexpress_cpu_die(unsigned int cpu); diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c index 742499bac6d09f27eaed8580e2df4b06e63a3252..af0113be597035d7f666847b948a48f83ce7bec3 100644 --- a/arch/arm/mach-vexpress/platsmp.c +++ b/arch/arm/mach-vexpress/platsmp.c @@ -82,6 +82,13 @@ static void __init vexpress_smp_dt_prepare_cpus(unsigned int max_cpus) vexpress_flags_set(__pa_symbol(versatile_secondary_startup)); } +#ifdef CONFIG_HOTPLUG_CPU +static void vexpress_cpu_die(unsigned int cpu) +{ + versatile_immitation_cpu_die(cpu, 0x40); +} +#endif + const struct smp_operations vexpress_smp_dt_ops __initconst = { .smp_prepare_cpus = vexpress_smp_dt_prepare_cpus, .smp_secondary_init = versatile_secondary_init, diff --git a/arch/arm/mm/copypage-fa.c b/arch/arm/mm/copypage-fa.c index d130a5ece5d55658b1c6cdd11f2721e7ea3f53f6..bf24690ec83aff157e2042e5d4a2a4f2a078d6b4 100644 --- a/arch/arm/mm/copypage-fa.c +++ b/arch/arm/mm/copypage-fa.c @@ -17,26 +17,25 @@ /* * Faraday optimised copy_user_page */ -static void __naked -fa_copy_user_page(void *kto, const void *kfrom) +static void fa_copy_user_page(void *kto, const void *kfrom) { - asm("\ - stmfd sp!, {r4, lr} @ 2\n\ - mov r2, %0 @ 1\n\ -1: ldmia r1!, {r3, r4, ip, lr} @ 4\n\ - stmia r0, {r3, r4, ip, lr} @ 4\n\ - mcr p15, 0, r0, c7, c14, 1 @ 1 clean and invalidate D line\n\ - add r0, r0, #16 @ 1\n\ - ldmia r1!, {r3, r4, ip, lr} @ 4\n\ - stmia r0, {r3, r4, ip, lr} @ 4\n\ - mcr p15, 0, r0, c7, c14, 1 @ 1 clean and invalidate D line\n\ - add r0, r0, #16 @ 1\n\ - subs r2, r2, #1 @ 1\n\ + int tmp; + + asm volatile ("\ +1: ldmia %1!, {r3, r4, ip, lr} @ 4\n\ + stmia %0, {r3, r4, ip, lr} @ 4\n\ + mcr p15, 0, %0, c7, c14, 1 @ 1 clean and invalidate D line\n\ + add %0, %0, #16 @ 1\n\ + ldmia %1!, {r3, r4, ip, lr} @ 4\n\ + stmia %0, {r3, r4, ip, lr} @ 4\n\ + mcr p15, 0, %0, c7, c14, 1 @ 1 clean and invalidate D line\n\ + add %0, %0, #16 @ 1\n\ + subs %2, %2, #1 @ 1\n\ bne 1b @ 1\n\ - mcr p15, 0, r2, c7, c10, 4 @ 1 drain WB\n\ - ldmfd sp!, {r4, pc} @ 3" - : - : "I" (PAGE_SIZE / 32)); + mcr p15, 0, %2, c7, c10, 4 @ 1 drain WB" + : "+&r" (kto), "+&r" (kfrom), "=&r" (tmp) + : "2" (PAGE_SIZE / 32) + : "r3", "r4", "ip", "lr"); } void fa_copy_user_highpage(struct page *to, struct page *from, diff --git a/arch/arm/mm/copypage-feroceon.c b/arch/arm/mm/copypage-feroceon.c index 49ee0c1a720972bc93d0a7335c8b365b01fdf93e..cc819732d9b820e393567ab7a01b4e2d0b5d6cbd 100644 --- a/arch/arm/mm/copypage-feroceon.c +++ b/arch/arm/mm/copypage-feroceon.c @@ -13,58 +13,56 @@ #include #include -static void __naked -feroceon_copy_user_page(void *kto, const void *kfrom) +static void feroceon_copy_user_page(void *kto, const void *kfrom) { - asm("\ - stmfd sp!, {r4-r9, lr} \n\ - mov ip, %2 \n\ -1: mov lr, r1 \n\ - ldmia r1!, {r2 - r9} \n\ - pld [lr, #32] \n\ - pld [lr, #64] \n\ - pld [lr, #96] \n\ - pld [lr, #128] \n\ - pld [lr, #160] \n\ - pld [lr, #192] \n\ - pld [lr, #224] \n\ - stmia r0, {r2 - r9} \n\ - ldmia r1!, {r2 - r9} \n\ - mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\ - add r0, r0, #32 \n\ - stmia r0, {r2 - r9} \n\ - ldmia r1!, {r2 - r9} \n\ - mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\ - add r0, r0, #32 \n\ - stmia r0, {r2 - r9} \n\ - ldmia r1!, {r2 - r9} \n\ - mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\ - add r0, r0, #32 \n\ - stmia r0, {r2 - r9} \n\ - ldmia r1!, {r2 - r9} \n\ - mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\ - add r0, r0, #32 \n\ - stmia r0, {r2 - r9} \n\ - ldmia r1!, {r2 - r9} \n\ - mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\ - add r0, r0, #32 \n\ - stmia r0, {r2 - r9} \n\ - ldmia r1!, {r2 - r9} \n\ - mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\ - add r0, r0, #32 \n\ - stmia r0, {r2 - r9} \n\ - ldmia r1!, {r2 - r9} \n\ - mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\ - add r0, r0, #32 \n\ - stmia r0, {r2 - r9} \n\ - subs ip, ip, #(32 * 8) \n\ - mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\ - add r0, r0, #32 \n\ + int tmp; + + asm volatile ("\ +1: ldmia %1!, {r2 - r7, ip, lr} \n\ + pld [%1, #0] \n\ + pld [%1, #32] \n\ + pld [%1, #64] \n\ + pld [%1, #96] \n\ + pld [%1, #128] \n\ + pld [%1, #160] \n\ + pld [%1, #192] \n\ + stmia %0, {r2 - r7, ip, lr} \n\ + ldmia %1!, {r2 - r7, ip, lr} \n\ + mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\ + add %0, %0, #32 \n\ + stmia %0, {r2 - r7, ip, lr} \n\ + ldmia %1!, {r2 - r7, ip, lr} \n\ + mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\ + add %0, %0, #32 \n\ + stmia %0, {r2 - r7, ip, lr} \n\ + ldmia %1!, {r2 - r7, ip, lr} \n\ + mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\ + add %0, %0, #32 \n\ + stmia %0, {r2 - r7, ip, lr} \n\ + ldmia %1!, {r2 - r7, ip, lr} \n\ + mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\ + add %0, %0, #32 \n\ + stmia %0, {r2 - r7, ip, lr} \n\ + ldmia %1!, {r2 - r7, ip, lr} \n\ + mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\ + add %0, %0, #32 \n\ + stmia %0, {r2 - r7, ip, lr} \n\ + ldmia %1!, {r2 - r7, ip, lr} \n\ + mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\ + add %0, %0, #32 \n\ + stmia %0, {r2 - r7, ip, lr} \n\ + ldmia %1!, {r2 - r7, ip, lr} \n\ + mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\ + add %0, %0, #32 \n\ + stmia %0, {r2 - r7, ip, lr} \n\ + subs %2, %2, #(32 * 8) \n\ + mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\ + add %0, %0, #32 \n\ bne 1b \n\ - mcr p15, 0, ip, c7, c10, 4 @ drain WB\n\ - ldmfd sp!, {r4-r9, pc}" - : - : "r" (kto), "r" (kfrom), "I" (PAGE_SIZE)); + mcr p15, 0, %2, c7, c10, 4 @ drain WB" + : "+&r" (kto), "+&r" (kfrom), "=&r" (tmp) + : "2" (PAGE_SIZE) + : "r2", "r3", "r4", "r5", "r6", "r7", "ip", "lr"); } void feroceon_copy_user_highpage(struct page *to, struct page *from, diff --git a/arch/arm/mm/copypage-v4mc.c b/arch/arm/mm/copypage-v4mc.c index 0224416cba3c8f323f04cf284fd2cd629e81c6ef..b03202cddddb2d07bf2fcfe3ee2d9d118066f846 100644 --- a/arch/arm/mm/copypage-v4mc.c +++ b/arch/arm/mm/copypage-v4mc.c @@ -40,12 +40,11 @@ static DEFINE_RAW_SPINLOCK(minicache_lock); * instruction. If your processor does not supply this, you have to write your * own copy_user_highpage that does the right thing. */ -static void __naked -mc_copy_user_page(void *from, void *to) +static void mc_copy_user_page(void *from, void *to) { - asm volatile( - "stmfd sp!, {r4, lr} @ 2\n\ - mov r4, %2 @ 1\n\ + int tmp; + + asm volatile ("\ ldmia %0!, {r2, r3, ip, lr} @ 4\n\ 1: mcr p15, 0, %1, c7, c6, 1 @ 1 invalidate D line\n\ stmia %1!, {r2, r3, ip, lr} @ 4\n\ @@ -55,13 +54,13 @@ mc_copy_user_page(void *from, void *to) mcr p15, 0, %1, c7, c6, 1 @ 1 invalidate D line\n\ stmia %1!, {r2, r3, ip, lr} @ 4\n\ ldmia %0!, {r2, r3, ip, lr} @ 4\n\ - subs r4, r4, #1 @ 1\n\ + subs %2, %2, #1 @ 1\n\ stmia %1!, {r2, r3, ip, lr} @ 4\n\ ldmneia %0!, {r2, r3, ip, lr} @ 4\n\ - bne 1b @ 1\n\ - ldmfd sp!, {r4, pc} @ 3" - : - : "r" (from), "r" (to), "I" (PAGE_SIZE / 64)); + bne 1b @ " + : "+&r" (from), "+&r" (to), "=&r" (tmp) + : "2" (PAGE_SIZE / 64) + : "r2", "r3", "ip", "lr"); } void v4_mc_copy_user_highpage(struct page *to, struct page *from, diff --git a/arch/arm/mm/copypage-v4wb.c b/arch/arm/mm/copypage-v4wb.c index 067d0fdd630c1082a0f895fee16bddfb4b002fa4..cd3e165afeedeb400c19b1dbb1b578e10b0d2400 100644 --- a/arch/arm/mm/copypage-v4wb.c +++ b/arch/arm/mm/copypage-v4wb.c @@ -22,29 +22,28 @@ * instruction. If your processor does not supply this, you have to write your * own copy_user_highpage that does the right thing. */ -static void __naked -v4wb_copy_user_page(void *kto, const void *kfrom) +static void v4wb_copy_user_page(void *kto, const void *kfrom) { - asm("\ - stmfd sp!, {r4, lr} @ 2\n\ - mov r2, %2 @ 1\n\ - ldmia r1!, {r3, r4, ip, lr} @ 4\n\ -1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line\n\ - stmia r0!, {r3, r4, ip, lr} @ 4\n\ - ldmia r1!, {r3, r4, ip, lr} @ 4+1\n\ - stmia r0!, {r3, r4, ip, lr} @ 4\n\ - ldmia r1!, {r3, r4, ip, lr} @ 4\n\ - mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line\n\ - stmia r0!, {r3, r4, ip, lr} @ 4\n\ - ldmia r1!, {r3, r4, ip, lr} @ 4\n\ - subs r2, r2, #1 @ 1\n\ - stmia r0!, {r3, r4, ip, lr} @ 4\n\ - ldmneia r1!, {r3, r4, ip, lr} @ 4\n\ + int tmp; + + asm volatile ("\ + ldmia %1!, {r3, r4, ip, lr} @ 4\n\ +1: mcr p15, 0, %0, c7, c6, 1 @ 1 invalidate D line\n\ + stmia %0!, {r3, r4, ip, lr} @ 4\n\ + ldmia %1!, {r3, r4, ip, lr} @ 4+1\n\ + stmia %0!, {r3, r4, ip, lr} @ 4\n\ + ldmia %1!, {r3, r4, ip, lr} @ 4\n\ + mcr p15, 0, %0, c7, c6, 1 @ 1 invalidate D line\n\ + stmia %0!, {r3, r4, ip, lr} @ 4\n\ + ldmia %1!, {r3, r4, ip, lr} @ 4\n\ + subs %2, %2, #1 @ 1\n\ + stmia %0!, {r3, r4, ip, lr} @ 4\n\ + ldmneia %1!, {r3, r4, ip, lr} @ 4\n\ bne 1b @ 1\n\ - mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB\n\ - ldmfd sp!, {r4, pc} @ 3" - : - : "r" (kto), "r" (kfrom), "I" (PAGE_SIZE / 64)); + mcr p15, 0, %1, c7, c10, 4 @ 1 drain WB" + : "+&r" (kto), "+&r" (kfrom), "=&r" (tmp) + : "2" (PAGE_SIZE / 64) + : "r3", "r4", "ip", "lr"); } void v4wb_copy_user_highpage(struct page *to, struct page *from, diff --git a/arch/arm/mm/copypage-v4wt.c b/arch/arm/mm/copypage-v4wt.c index b85c5da2e510ea8a3cfe337eb797ef7a26d17dba..8614572e1296ba904a018fd07b2dfe66843a5272 100644 --- a/arch/arm/mm/copypage-v4wt.c +++ b/arch/arm/mm/copypage-v4wt.c @@ -20,27 +20,26 @@ * dirty data in the cache. However, we do have to ensure that * subsequent reads are up to date. */ -static void __naked -v4wt_copy_user_page(void *kto, const void *kfrom) +static void v4wt_copy_user_page(void *kto, const void *kfrom) { - asm("\ - stmfd sp!, {r4, lr} @ 2\n\ - mov r2, %2 @ 1\n\ - ldmia r1!, {r3, r4, ip, lr} @ 4\n\ -1: stmia r0!, {r3, r4, ip, lr} @ 4\n\ - ldmia r1!, {r3, r4, ip, lr} @ 4+1\n\ - stmia r0!, {r3, r4, ip, lr} @ 4\n\ - ldmia r1!, {r3, r4, ip, lr} @ 4\n\ - stmia r0!, {r3, r4, ip, lr} @ 4\n\ - ldmia r1!, {r3, r4, ip, lr} @ 4\n\ - subs r2, r2, #1 @ 1\n\ - stmia r0!, {r3, r4, ip, lr} @ 4\n\ - ldmneia r1!, {r3, r4, ip, lr} @ 4\n\ + int tmp; + + asm volatile ("\ + ldmia %1!, {r3, r4, ip, lr} @ 4\n\ +1: stmia %0!, {r3, r4, ip, lr} @ 4\n\ + ldmia %1!, {r3, r4, ip, lr} @ 4+1\n\ + stmia %0!, {r3, r4, ip, lr} @ 4\n\ + ldmia %1!, {r3, r4, ip, lr} @ 4\n\ + stmia %0!, {r3, r4, ip, lr} @ 4\n\ + ldmia %1!, {r3, r4, ip, lr} @ 4\n\ + subs %2, %2, #1 @ 1\n\ + stmia %0!, {r3, r4, ip, lr} @ 4\n\ + ldmneia %1!, {r3, r4, ip, lr} @ 4\n\ bne 1b @ 1\n\ - mcr p15, 0, r2, c7, c7, 0 @ flush ID cache\n\ - ldmfd sp!, {r4, pc} @ 3" - : - : "r" (kto), "r" (kfrom), "I" (PAGE_SIZE / 64)); + mcr p15, 0, %2, c7, c7, 0 @ flush ID cache" + : "+&r" (kto), "+&r" (kfrom), "=&r" (tmp) + : "2" (PAGE_SIZE / 64) + : "r3", "r4", "ip", "lr"); } void v4wt_copy_user_highpage(struct page *to, struct page *from, diff --git a/arch/arm/mm/copypage-xsc3.c b/arch/arm/mm/copypage-xsc3.c index 03a2042aced5f88b54e224396720c95d5fc3acce..a08158241ad16d4fd2d52808526bc4e10e19f30b 100644 --- a/arch/arm/mm/copypage-xsc3.c +++ b/arch/arm/mm/copypage-xsc3.c @@ -21,53 +21,46 @@ /* * XSC3 optimised copy_user_highpage - * r0 = destination - * r1 = source * * The source page may have some clean entries in the cache already, but we * can safely ignore them - break_cow() will flush them out of the cache * if we eventually end up using our copied page. * */ -static void __naked -xsc3_mc_copy_user_page(void *kto, const void *kfrom) +static void xsc3_mc_copy_user_page(void *kto, const void *kfrom) { - asm("\ - stmfd sp!, {r4, r5, lr} \n\ - mov lr, %2 \n\ - \n\ - pld [r1, #0] \n\ - pld [r1, #32] \n\ -1: pld [r1, #64] \n\ - pld [r1, #96] \n\ + int tmp; + + asm volatile ("\ + pld [%1, #0] \n\ + pld [%1, #32] \n\ +1: pld [%1, #64] \n\ + pld [%1, #96] \n\ \n\ -2: ldrd r2, [r1], #8 \n\ - mov ip, r0 \n\ - ldrd r4, [r1], #8 \n\ - mcr p15, 0, ip, c7, c6, 1 @ invalidate\n\ - strd r2, [r0], #8 \n\ - ldrd r2, [r1], #8 \n\ - strd r4, [r0], #8 \n\ - ldrd r4, [r1], #8 \n\ - strd r2, [r0], #8 \n\ - strd r4, [r0], #8 \n\ - ldrd r2, [r1], #8 \n\ - mov ip, r0 \n\ - ldrd r4, [r1], #8 \n\ - mcr p15, 0, ip, c7, c6, 1 @ invalidate\n\ - strd r2, [r0], #8 \n\ - ldrd r2, [r1], #8 \n\ - subs lr, lr, #1 \n\ - strd r4, [r0], #8 \n\ - ldrd r4, [r1], #8 \n\ - strd r2, [r0], #8 \n\ - strd r4, [r0], #8 \n\ +2: ldrd r2, r3, [%1], #8 \n\ + ldrd r4, r5, [%1], #8 \n\ + mcr p15, 0, %0, c7, c6, 1 @ invalidate\n\ + strd r2, r3, [%0], #8 \n\ + ldrd r2, r3, [%1], #8 \n\ + strd r4, r5, [%0], #8 \n\ + ldrd r4, r5, [%1], #8 \n\ + strd r2, r3, [%0], #8 \n\ + strd r4, r5, [%0], #8 \n\ + ldrd r2, r3, [%1], #8 \n\ + ldrd r4, r5, [%1], #8 \n\ + mcr p15, 0, %0, c7, c6, 1 @ invalidate\n\ + strd r2, r3, [%0], #8 \n\ + ldrd r2, r3, [%1], #8 \n\ + subs %2, %2, #1 \n\ + strd r4, r5, [%0], #8 \n\ + ldrd r4, r5, [%1], #8 \n\ + strd r2, r3, [%0], #8 \n\ + strd r4, r5, [%0], #8 \n\ bgt 1b \n\ - beq 2b \n\ - \n\ - ldmfd sp!, {r4, r5, pc}" - : - : "r" (kto), "r" (kfrom), "I" (PAGE_SIZE / 64 - 1)); + beq 2b " + : "+&r" (kto), "+&r" (kfrom), "=&r" (tmp) + : "2" (PAGE_SIZE / 64 - 1) + : "r2", "r3", "r4", "r5"); } void xsc3_mc_copy_user_highpage(struct page *to, struct page *from, @@ -85,8 +78,6 @@ void xsc3_mc_copy_user_highpage(struct page *to, struct page *from, /* * XScale optimised clear_user_page - * r0 = destination - * r1 = virtual user address of ultimate destination page */ void xsc3_mc_clear_user_highpage(struct page *page, unsigned long vaddr) { @@ -96,10 +87,10 @@ void xsc3_mc_clear_user_highpage(struct page *page, unsigned long vaddr) mov r2, #0 \n\ mov r3, #0 \n\ 1: mcr p15, 0, %0, c7, c6, 1 @ invalidate line\n\ - strd r2, [%0], #8 \n\ - strd r2, [%0], #8 \n\ - strd r2, [%0], #8 \n\ - strd r2, [%0], #8 \n\ + strd r2, r3, [%0], #8 \n\ + strd r2, r3, [%0], #8 \n\ + strd r2, r3, [%0], #8 \n\ + strd r2, r3, [%0], #8 \n\ subs r1, r1, #1 \n\ bne 1b" : "=r" (ptr) diff --git a/arch/arm/mm/copypage-xscale.c b/arch/arm/mm/copypage-xscale.c index 97972379f4d6ad24ff28d1bef2ffbdbc5d295afb..63b92193675458747467cb329d41e8edd69d1c45 100644 --- a/arch/arm/mm/copypage-xscale.c +++ b/arch/arm/mm/copypage-xscale.c @@ -36,52 +36,51 @@ static DEFINE_RAW_SPINLOCK(minicache_lock); * Dcache aliasing issue. The writes will be forwarded to the write buffer, * and merged as appropriate. */ -static void __naked -mc_copy_user_page(void *from, void *to) +static void mc_copy_user_page(void *from, void *to) { + int tmp; + /* * Strangely enough, best performance is achieved * when prefetching destination as well. (NP) */ - asm volatile( - "stmfd sp!, {r4, r5, lr} \n\ - mov lr, %2 \n\ - pld [r0, #0] \n\ - pld [r0, #32] \n\ - pld [r1, #0] \n\ - pld [r1, #32] \n\ -1: pld [r0, #64] \n\ - pld [r0, #96] \n\ - pld [r1, #64] \n\ - pld [r1, #96] \n\ -2: ldrd r2, [r0], #8 \n\ - ldrd r4, [r0], #8 \n\ - mov ip, r1 \n\ - strd r2, [r1], #8 \n\ - ldrd r2, [r0], #8 \n\ - strd r4, [r1], #8 \n\ - ldrd r4, [r0], #8 \n\ - strd r2, [r1], #8 \n\ - strd r4, [r1], #8 \n\ + asm volatile ("\ + pld [%0, #0] \n\ + pld [%0, #32] \n\ + pld [%1, #0] \n\ + pld [%1, #32] \n\ +1: pld [%0, #64] \n\ + pld [%0, #96] \n\ + pld [%1, #64] \n\ + pld [%1, #96] \n\ +2: ldrd r2, r3, [%0], #8 \n\ + ldrd r4, r5, [%0], #8 \n\ + mov ip, %1 \n\ + strd r2, r3, [%1], #8 \n\ + ldrd r2, r3, [%0], #8 \n\ + strd r4, r5, [%1], #8 \n\ + ldrd r4, r5, [%0], #8 \n\ + strd r2, r3, [%1], #8 \n\ + strd r4, r5, [%1], #8 \n\ mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\ - ldrd r2, [r0], #8 \n\ + ldrd r2, r3, [%0], #8 \n\ mcr p15, 0, ip, c7, c6, 1 @ invalidate D line\n\ - ldrd r4, [r0], #8 \n\ - mov ip, r1 \n\ - strd r2, [r1], #8 \n\ - ldrd r2, [r0], #8 \n\ - strd r4, [r1], #8 \n\ - ldrd r4, [r0], #8 \n\ - strd r2, [r1], #8 \n\ - strd r4, [r1], #8 \n\ + ldrd r4, r5, [%0], #8 \n\ + mov ip, %1 \n\ + strd r2, r3, [%1], #8 \n\ + ldrd r2, r3, [%0], #8 \n\ + strd r4, r5, [%1], #8 \n\ + ldrd r4, r5, [%0], #8 \n\ + strd r2, r3, [%1], #8 \n\ + strd r4, r5, [%1], #8 \n\ mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\ - subs lr, lr, #1 \n\ + subs %2, %2, #1 \n\ mcr p15, 0, ip, c7, c6, 1 @ invalidate D line\n\ bgt 1b \n\ - beq 2b \n\ - ldmfd sp!, {r4, r5, pc} " - : - : "r" (from), "r" (to), "I" (PAGE_SIZE / 64 - 1)); + beq 2b " + : "+&r" (from), "+&r" (to), "=&r" (tmp) + : "2" (PAGE_SIZE / 64 - 1) + : "r2", "r3", "r4", "r5", "ip"); } void xscale_mc_copy_user_highpage(struct page *to, struct page *from, @@ -115,10 +114,10 @@ xscale_mc_clear_user_highpage(struct page *page, unsigned long vaddr) mov r2, #0 \n\ mov r3, #0 \n\ 1: mov ip, %0 \n\ - strd r2, [%0], #8 \n\ - strd r2, [%0], #8 \n\ - strd r2, [%0], #8 \n\ - strd r2, [%0], #8 \n\ + strd r2, r3, [%0], #8 \n\ + strd r2, r3, [%0], #8 \n\ + strd r2, r3, [%0], #8 \n\ + strd r2, r3, [%0], #8 \n\ mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\ subs r1, r1, #1 \n\ mcr p15, 0, ip, c7, c6, 1 @ invalidate D line\n\ diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index f4ea4c62c613ccbea22eca928984ac72a9057e8d..58f69fa07df95640151ec2576b3a0419a0991da5 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -173,6 +173,12 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr, show_regs(regs); } #endif +#ifndef CONFIG_KUSER_HELPERS + if ((sig == SIGSEGV) && ((addr & PAGE_MASK) == 0xffff0000)) + printk_ratelimited(KERN_DEBUG + "%s: CONFIG_KUSER_HELPERS disabled at 0x%08lx\n", + tsk->comm, addr); +#endif tsk->thread.address = addr; tsk->thread.error_code = fsr; diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S index 19516fbc2c55a65c761094bf3a67c8cd69568183..5461d589a1e25e7b63207f83968f63429860263b 100644 --- a/arch/arm/mm/proc-macros.S +++ b/arch/arm/mm/proc-macros.S @@ -278,7 +278,7 @@ * If we are building for big.Little with branch predictor hardening, * we need the processor function tables to remain available after boot. */ -#if 1 // defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR) +#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR) .section ".rodata" #endif .type \name\()_processor_functions, #object @@ -316,7 +316,7 @@ ENTRY(\name\()_processor_functions) .endif .size \name\()_processor_functions, . - \name\()_processor_functions -#if 1 // defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR) +#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR) .previous #endif .endm diff --git a/arch/arm/mm/pv-fixup-asm.S b/arch/arm/mm/pv-fixup-asm.S index 1867f3e430161ff6cf530302aa77eb9cea314054..fd2ff9034d177ff1088cf515bb40eed7eb792d72 100644 --- a/arch/arm/mm/pv-fixup-asm.S +++ b/arch/arm/mm/pv-fixup-asm.S @@ -33,10 +33,10 @@ ENTRY(lpae_pgtables_remap_asm) add r7, r2, #0x1000 add r6, r7, r6, lsr #SECTION_SHIFT - L2_ORDER add r7, r7, #PAGE_OFFSET >> (SECTION_SHIFT - L2_ORDER) -1: ldrd r4, [r7] +1: ldrd r4, r5, [r7] adds r4, r4, r0 adc r5, r5, r1 - strd r4, [r7], #1 << L2_ORDER + strd r4, r5, [r7], #1 << L2_ORDER cmp r7, r6 bls 1b @@ -44,22 +44,22 @@ ENTRY(lpae_pgtables_remap_asm) add r7, r2, #0x1000 add r7, r7, r3, lsr #SECTION_SHIFT - L2_ORDER bic r7, r7, #(1 << L2_ORDER) - 1 - ldrd r4, [r7] + ldrd r4, r5, [r7] adds r4, r4, r0 adc r5, r5, r1 - strd r4, [r7], #1 << L2_ORDER - ldrd r4, [r7] + strd r4, r5, [r7], #1 << L2_ORDER + ldrd r4, r5, [r7] adds r4, r4, r0 adc r5, r5, r1 - strd r4, [r7] + strd r4, r5, [r7] /* Update level 1 entries */ mov r6, #4 mov r7, r2 -2: ldrd r4, [r7] +2: ldrd r4, r5, [r7] adds r4, r4, r0 adc r5, r5, r1 - strd r4, [r7], #1 << L1_ORDER + strd r4, r5, [r7], #1 << L1_ORDER subs r6, r6, #1 bne 2b diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index c0a242cae79afd3df963a292ae73d7e5914530b7..93fd7fc537cf4259622e6bef6753ed6404b1866d 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -92,7 +92,6 @@ config OMAP_32K_TIMER config OMAP3_L2_AUX_SECURE_SAVE_RESTORE bool "OMAP3 HS/EMU save and restore for L2 AUX control register" depends on ARCH_OMAP3 && PM - default n help Without this option, L2 Auxiliary control register contents are lost during off-mode entry on HS/EMU devices. This feature diff --git a/arch/arm/plat-versatile/Makefile b/arch/arm/plat-versatile/Makefile index bff3ba889882e7debd1587ed0be2f5c7563ed9a4..b2f0ddfdc4ccb460b6c1bb818784f1b5b5839137 100644 --- a/arch/arm/plat-versatile/Makefile +++ b/arch/arm/plat-versatile/Makefile @@ -2,3 +2,4 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include obj-$(CONFIG_PLAT_VERSATILE_SCHED_CLOCK) += sched-clock.o obj-$(CONFIG_SMP) += headsmp.o platsmp.o +obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o diff --git a/arch/arm/plat-versatile/headsmp.S b/arch/arm/plat-versatile/headsmp.S index 40f27e52de759aed3ab7d3f7e912bf4feab3a358..e99396dfa6f3393e3290669c9e63bf6324801e83 100644 --- a/arch/arm/plat-versatile/headsmp.S +++ b/arch/arm/plat-versatile/headsmp.S @@ -37,5 +37,5 @@ pen: ldr r7, [r6] .align 1: .long . - .long pen_release + .long versatile_cpu_release ENDPROC(versatile_secondary_startup) diff --git a/arch/arm/mach-vexpress/hotplug.c b/arch/arm/plat-versatile/hotplug.c similarity index 56% rename from arch/arm/mach-vexpress/hotplug.c rename to arch/arm/plat-versatile/hotplug.c index d8f1a05f5e8777f5749ac24820034de24f5dc408..c974958417fe7ccf76bdb1f1d2f051abbece6f3e 100644 --- a/arch/arm/mach-vexpress/hotplug.c +++ b/arch/arm/plat-versatile/hotplug.c @@ -1,12 +1,15 @@ /* - * linux/arch/arm/mach-realview/hotplug.c - * * Copyright (C) 2002 ARM Ltd. * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. + * + * This hotplug implementation is _specific_ to the situation found on + * ARM development platforms where there is _no_ possibility of actually + * taking a CPU offline, resetting it, or otherwise. Real platforms must + * NOT copy this code. */ #include #include @@ -15,9 +18,9 @@ #include #include -#include "core.h" +#include -static inline void cpu_enter_lowpower(void) +static inline void versatile_immitation_enter_lowpower(unsigned int actrl_mask) { unsigned int v; @@ -34,11 +37,11 @@ static inline void cpu_enter_lowpower(void) " bic %0, %0, %2\n" " mcr p15, 0, %0, c1, c0, 0\n" : "=&r" (v) - : "r" (0), "Ir" (CR_C), "Ir" (0x40) + : "r" (0), "Ir" (CR_C), "Ir" (actrl_mask) : "cc"); } -static inline void cpu_leave_lowpower(void) +static inline void versatile_immitation_leave_lowpower(unsigned int actrl_mask) { unsigned int v; @@ -50,21 +53,23 @@ static inline void cpu_leave_lowpower(void) " orr %0, %0, %2\n" " mcr p15, 0, %0, c1, c0, 1\n" : "=&r" (v) - : "Ir" (CR_C), "Ir" (0x40) + : "Ir" (CR_C), "Ir" (actrl_mask) : "cc"); } -static inline void platform_do_lowpower(unsigned int cpu, int *spurious) +static inline void versatile_immitation_do_lowpower(unsigned int cpu, int *spurious) { /* * there is no power-control hardware on this platform, so all * we can do is put the core into WFI; this is safe as the calling - * code will have already disabled interrupts + * code will have already disabled interrupts. + * + * This code should not be used outside Versatile platforms. */ for (;;) { wfi(); - if (pen_release == cpu_logical_map(cpu)) { + if (versatile_cpu_release == cpu_logical_map(cpu)) { /* * OK, proper wakeup, we're done */ @@ -83,25 +88,17 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious) } /* - * platform-specific code to shutdown a CPU - * - * Called with IRQs disabled + * platform-specific code to shutdown a CPU. + * This code supports immitation-style CPU hotplug for Versatile/Realview/ + * Versatile Express platforms that are unable to do real CPU hotplug. */ -void vexpress_cpu_die(unsigned int cpu) +void versatile_immitation_cpu_die(unsigned int cpu, unsigned int actrl_mask) { int spurious = 0; - /* - * we're ready for shutdown now, so do it - */ - cpu_enter_lowpower(); - platform_do_lowpower(cpu, &spurious); - - /* - * bring this CPU back into the world of cache - * coherency, and then restore interrupts - */ - cpu_leave_lowpower(); + versatile_immitation_enter_lowpower(actrl_mask); + versatile_immitation_do_lowpower(cpu, &spurious); + versatile_immitation_leave_lowpower(actrl_mask); if (spurious) pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); diff --git a/arch/arm/plat-versatile/include/plat/platsmp.h b/arch/arm/plat-versatile/include/plat/platsmp.h index 50fb830192e0367d9cb9ea7cc0c13547fab7bfeb..1b087fbbc700ec4c92dcd73027743528ba283a5b 100644 --- a/arch/arm/plat-versatile/include/plat/platsmp.h +++ b/arch/arm/plat-versatile/include/plat/platsmp.h @@ -8,7 +8,9 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +extern volatile int versatile_cpu_release; extern void versatile_secondary_startup(void); extern void versatile_secondary_init(unsigned int cpu); extern int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle); +void versatile_immitation_cpu_die(unsigned int cpu, unsigned int actrl_mask); diff --git a/arch/arm/plat-versatile/platsmp.c b/arch/arm/plat-versatile/platsmp.c index c2366510187a8fb54eb27b994b3d7b998f3cad72..6e2836243187c678229a61ec6ea53d23fd16ff6a 100644 --- a/arch/arm/plat-versatile/platsmp.c +++ b/arch/arm/plat-versatile/platsmp.c @@ -7,6 +7,11 @@ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. + * + * This code is specific to the hardware found on ARM Realview and + * Versatile Express platforms where the CPUs are unable to be individually + * woken, and where there is no way to hot-unplug CPUs. Real platforms + * should not copy this code. */ #include #include @@ -21,18 +26,32 @@ #include /* - * Write pen_release in a way that is guaranteed to be visible to all - * observers, irrespective of whether they're taking part in coherency + * versatile_cpu_release controls the release of CPUs from the holding + * pen in headsmp.S, which exists because we are not always able to + * control the release of individual CPUs from the board firmware. + * Production platforms do not need this. + */ +volatile int versatile_cpu_release = -1; + +/* + * Write versatile_cpu_release in a way that is guaranteed to be visible to + * all observers, irrespective of whether they're taking part in coherency * or not. This is necessary for the hotplug code to work reliably. */ -static void write_pen_release(int val) +static void versatile_write_cpu_release(int val) { - pen_release = val; + versatile_cpu_release = val; smp_wmb(); - sync_cache_w(&pen_release); + sync_cache_w(&versatile_cpu_release); } -static DEFINE_SPINLOCK(boot_lock); +/* + * versatile_lock exists to avoid running the loops_per_jiffy delay loop + * calibrations on the secondary CPU while the requesting CPU is using + * the limited-bandwidth bus - which affects the calibration value. + * Production platforms do not need this. + */ +static DEFINE_RAW_SPINLOCK(versatile_lock); void versatile_secondary_init(unsigned int cpu) { @@ -40,13 +59,13 @@ void versatile_secondary_init(unsigned int cpu) * let the primary processor know we're out of the * pen, then head off into the C entry point */ - write_pen_release(-1); + versatile_write_cpu_release(-1); /* * Synchronise with the boot thread. */ - spin_lock(&boot_lock); - spin_unlock(&boot_lock); + raw_spin_lock(&versatile_lock); + raw_spin_unlock(&versatile_lock); } int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle) @@ -57,7 +76,7 @@ int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle) * Set synchronisation state between this boot processor * and the secondary one */ - spin_lock(&boot_lock); + raw_spin_lock(&versatile_lock); /* * This is really belt and braces; we hold unintended secondary @@ -65,7 +84,7 @@ int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle) * since we haven't sent them a soft interrupt, they shouldn't * be there. */ - write_pen_release(cpu_logical_map(cpu)); + versatile_write_cpu_release(cpu_logical_map(cpu)); /* * Send the secondary CPU a soft interrupt, thereby causing @@ -77,7 +96,7 @@ int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle) timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { smp_rmb(); - if (pen_release == -1) + if (versatile_cpu_release == -1) break; udelay(10); @@ -87,7 +106,7 @@ int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle) * now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ - spin_unlock(&boot_lock); + raw_spin_unlock(&versatile_lock); - return pen_release != -1 ? -ENOSYS : 0; + return versatile_cpu_release != -1 ? -ENOSYS : 0; } diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index c9bdbb463a7ee36b8115820a7e5b2db83f82c98d..fab92ba8e56622360bb718cdd48f18831475856f 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -64,6 +64,9 @@ config CARDBUS If unsure, say Y. +config PCMCIA_MAX1600 + tristate + comment "PC-card bridges" config YENTA @@ -192,6 +195,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 @@ -208,6 +213,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 diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index 28502bd159e07bca8ea8f215008808ab2a709753..01779c5c45f35dfd056e872d9101d13f4c3e9561 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -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 diff --git a/drivers/pcmcia/max1600.c b/drivers/pcmcia/max1600.c new file mode 100644 index 0000000000000000000000000000000000000000..379875a5e7cd4368585d854c947afdf664bdf10f --- /dev/null +++ b/drivers/pcmcia/max1600.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MAX1600 PCMCIA power switch library + * + * Copyright (C) 2016 Russell King + */ +#include +#include +#include +#include +#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"); diff --git a/drivers/pcmcia/max1600.h b/drivers/pcmcia/max1600.h new file mode 100644 index 0000000000000000000000000000000000000000..00bf1a09464f9e045de01b0ded17a1d27b62372f --- /dev/null +++ b/drivers/pcmcia/max1600.h @@ -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 diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c index 7e32e25cdcb29d20965d2e7843bf0a8d3b8bf8a2..770c7bf0171dfd0fea504f3b3f2203b58af7b7c9 100644 --- a/drivers/pcmcia/pxa2xx_mainstone.c +++ b/drivers/pcmcia/pxa2xx_mainstone.c @@ -11,56 +11,55 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - +#include #include #include +#include #include #include -#include #include #include #include -#include - -#include -#include #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 = { diff --git a/drivers/pcmcia/sa1100_simpad.c b/drivers/pcmcia/sa1100_simpad.c index e235ee14eaa6e2565630305da21de55e9fca8e69..e2e8729afd9dc9b9e5ff822af974f26ff1926783 100644 --- a/drivers/pcmcia/sa1100_simpad.c +++ b/drivers/pcmcia/sa1100_simpad.c @@ -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)) { diff --git a/drivers/pcmcia/sa1111_jornada720.c b/drivers/pcmcia/sa1111_jornada720.c index 3d4ca87ca76cd58871f4aa33ab72134843baa143..1083e1b4f25dbbaa85ccea6d02fc008e4b84a57c 100644 --- a/drivers/pcmcia/sa1111_jornada720.c +++ b/drivers/pcmcia/sa1111_jornada720.c @@ -6,29 +6,62 @@ * */ #include -#include #include #include +#include #include #include #include -#include #include #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); diff --git a/drivers/pcmcia/sa1111_lubbock.c b/drivers/pcmcia/sa1111_lubbock.c index e741f499c875314d40855190186ee939f0dba2e7..e3fc14cfb42b33ff51ad3c88f60d4d91801894a9 100644 --- a/drivers/pcmcia/sa1111_lubbock.c +++ b/drivers/pcmcia/sa1111_lubbock.c @@ -24,20 +24,31 @@ #include #include #include -#include #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, diff --git a/drivers/pcmcia/sa1111_neponset.c b/drivers/pcmcia/sa1111_neponset.c index 0ccf05a28a4b96686d76e908b54b949c298715cb..de0ce13355b449855d7789accca7e72be8242d1e 100644 --- a/drivers/pcmcia/sa1111_neponset.c +++ b/drivers/pcmcia/sa1111_neponset.c @@ -10,12 +10,10 @@ #include #include -#include #include -#include -#include #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_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) +static int neponset_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { - struct sa1111_pcmcia_socket *s = to_skt(skt); - unsigned int ncr_mask, ncr_set, pa_dwr_mask, pa_dwr_set; + struct max1600 *m; 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; + 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; - default: - return -1; - } + return ret; +} - /* - * 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; - } +static int +neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) +{ + struct max1600 *m = skt->driver_data; + int ret; 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);