aboutsummaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-11-30 08:11:18 -0800
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-11-30 08:11:18 -0800
commitb62c855938be50c13f3f2aa81fafe4a9ca2b6650 (patch)
treec133f2b64893561347415d1861f8926c24f12daf /arch/arm
parent80cbd911ca25535f6bb66bbcbb98950ec328eb40 (diff)
parente252d4c362ad89c5b533833d9e7493c732215925 (diff)
Merge branch 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm: [ARM] 4680/1: parentheses around NR_IRQS definition [ARM] 4679/1: AT91: Change maintainer email address [ARM] 4675/1: pxa: fix mfp address definition error for pxa320 [ARM] 4674/1: pxa: increase LCD PCLK drive strength to fast 2mA for PXA300/PXA310 [ARM] 4673/1: pxa: add missing IRQ_SSP4 definitions for PXA3xx [ARM] 4672/1: pxa: fix DRCMR(n) to support PXA27x and later processors [ARM] 4665/1: fix __und_usr wrt accessing the undefined insn in user space [ARM] 4659/1: remove possibilities for spurious false negative with __kuser_cmpxchg [ARM] 4661/1: fix do_undefinstr wrt the enabling of IRQs [ARM] uengine: fix memset size error [ARM] 4648/1: i.MX/MX1 ensure more complete AITC initialization [ARM] 4611/2: AT91: Fix GPIO buttons pins on SAM9261-EK. [ARM] 4650/1: AT91: New-style init of I2C, support for i2c-gpio [ARM] 4604/2: AT91: Master clock divistor on SAM9 [ARM] 4662/1: Fix PXA serial driver compilation if SERIAL_PXA_CONSOLE is disabled [ARM] PXA ssp: unlock when ssp tries to close an invalid port [ARM] 4654/1: pxa: update default MFP register value [ARM] 4653/1: pxa: fix a gpio typo in mfp-pxa320.h [ARM] 4652/1: pxa: fix a typo of pxa27x usb host clk definition [ARM] 4651/1: pxa: add PXA3xx specific IRQ definitions
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/common/uengine.c6
-rw-r--r--arch/arm/kernel/entry-armv.S96
-rw-r--r--arch/arm/kernel/traps.c5
-rw-r--r--arch/arm/mach-at91/at91rm9200_devices.c41
-rw-r--r--arch/arm/mach-at91/at91sam9260_devices.c42
-rw-r--r--arch/arm/mach-at91/at91sam9261_devices.c42
-rw-r--r--arch/arm/mach-at91/at91sam9263_devices.c42
-rw-r--r--arch/arm/mach-at91/at91sam9rl_devices.c43
-rw-r--r--arch/arm/mach-at91/board-carmeva.c2
-rw-r--r--arch/arm/mach-at91/board-csb337.c11
-rw-r--r--arch/arm/mach-at91/board-csb637.c2
-rw-r--r--arch/arm/mach-at91/board-dk.c15
-rw-r--r--arch/arm/mach-at91/board-eb9200.c10
-rw-r--r--arch/arm/mach-at91/board-ek.c2
-rw-r--r--arch/arm/mach-at91/board-kafa.c2
-rw-r--r--arch/arm/mach-at91/board-kb9202.c2
-rw-r--r--arch/arm/mach-at91/board-picotux200.c2
-rw-r--r--arch/arm/mach-at91/board-sam9260ek.c2
-rw-r--r--arch/arm/mach-at91/board-sam9261ek.c18
-rw-r--r--arch/arm/mach-at91/board-sam9263ek.c2
-rw-r--r--arch/arm/mach-at91/board-sam9rlek.c2
-rw-r--r--arch/arm/mach-at91/clock.c9
-rw-r--r--arch/arm/mach-imx/irq.c51
-rw-r--r--arch/arm/mach-pxa/pxa27x.c2
-rw-r--r--arch/arm/mach-pxa/pxa320.c7
-rw-r--r--arch/arm/mach-pxa/ssp.c1
26 files changed, 359 insertions, 100 deletions
diff --git a/arch/arm/common/uengine.c b/arch/arm/common/uengine.c
index 95c8508c29b..117cab30bd3 100644
--- a/arch/arm/common/uengine.c
+++ b/arch/arm/common/uengine.c
@@ -374,8 +374,8 @@ static int set_initial_registers(int uengine, struct ixp2000_uengine_code *c)
u8 *ucode;
int i;
- gpr_a = kmalloc(128 * sizeof(u32), GFP_KERNEL);
- gpr_b = kmalloc(128 * sizeof(u32), GFP_KERNEL);
+ gpr_a = kzalloc(128 * sizeof(u32), GFP_KERNEL);
+ gpr_b = kzalloc(128 * sizeof(u32), GFP_KERNEL);
ucode = kmalloc(513 * 5, GFP_KERNEL);
if (gpr_a == NULL || gpr_b == NULL || ucode == NULL) {
kfree(ucode);
@@ -388,8 +388,6 @@ static int set_initial_registers(int uengine, struct ixp2000_uengine_code *c)
if (c->uengine_parameters & IXP2000_UENGINE_4_CONTEXTS)
per_ctx_regs = 32;
- memset(gpr_a, 0, sizeof(gpr_a));
- memset(gpr_b, 0, sizeof(gpr_b));
for (i = 0; i < 256; i++) {
struct ixp2000_reg_value *r = c->initial_reg_values + i;
u32 *bank;
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index d645897652c..29dec080a60 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -339,16 +339,6 @@ __pabt_svc:
str r1, [sp] @ save the "real" r0 copied
@ from the exception stack
-#if __LINUX_ARM_ARCH__ < 6 && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
-#ifndef CONFIG_MMU
-#warning "NPTL on non MMU needs fixing"
-#else
- @ make sure our user space atomic helper is aborted
- cmp r2, #TASK_SIZE
- bichs r3, r3, #PSR_Z_BIT
-#endif
-#endif
-
@
@ We are now ready to fill in the remaining blanks on the stack:
@
@@ -372,9 +362,25 @@ __pabt_svc:
zero_fp
.endm
+ .macro kuser_cmpxchg_check
+#if __LINUX_ARM_ARCH__ < 6 && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#ifndef CONFIG_MMU
+#warning "NPTL on non MMU needs fixing"
+#else
+ @ Make sure our user space atomic helper is restarted
+ @ if it was interrupted in a critical region. Here we
+ @ perform a quick test inline since it should be false
+ @ 99.9999% of the time. The rest is done out of line.
+ cmp r2, #TASK_SIZE
+ blhs kuser_cmpxchg_fixup
+#endif
+#endif
+ .endm
+
.align 5
__dabt_usr:
usr_entry
+ kuser_cmpxchg_check
@
@ Call the processor-specific abort handler:
@@ -404,6 +410,7 @@ __dabt_usr:
.align 5
__irq_usr:
usr_entry
+ kuser_cmpxchg_check
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_off
@@ -446,9 +453,9 @@ __und_usr:
@
@ r0 - instruction
@
-1: ldrt r0, [r4]
adr r9, ret_from_exception
adr lr, __und_usr_unknown
+1: ldrt r0, [r4]
@
@ fallthrough to call_fpe
@
@@ -669,7 +676,7 @@ __kuser_helper_start:
*
* Clobbered:
*
- * the Z flag might be lost
+ * none
*
* Definition and user space usage example:
*
@@ -730,9 +737,6 @@ __kuser_memory_barrier: @ 0xffff0fa0
*
* - This routine already includes memory barriers as needed.
*
- * - A failure might be transient, i.e. it is possible, although unlikely,
- * that "failure" be returned even if *ptr == oldval.
- *
* For example, a user space atomic_add implementation could look like this:
*
* #define atomic_add(ptr, val) \
@@ -769,46 +773,62 @@ __kuser_cmpxchg: @ 0xffff0fc0
#elif __LINUX_ARM_ARCH__ < 6
+#ifdef CONFIG_MMU
+
/*
- * Theory of operation:
- *
- * We set the Z flag before loading oldval. If ever an exception
- * occurs we can not be sure the loaded value will still be the same
- * when the exception returns, therefore the user exception handler
- * will clear the Z flag whenever the interrupted user code was
- * actually from the kernel address space (see the usr_entry macro).
- *
- * The post-increment on the str is used to prevent a race with an
- * exception happening just after the str instruction which would
- * clear the Z flag although the exchange was done.
+ * The only thing that can break atomicity in this cmpxchg
+ * implementation is either an IRQ or a data abort exception
+ * causing another process/thread to be scheduled in the middle
+ * of the critical sequence. To prevent this, code is added to
+ * the IRQ and data abort exception handlers to set the pc back
+ * to the beginning of the critical section if it is found to be
+ * within that critical section (see kuser_cmpxchg_fixup).
*/
-#ifdef CONFIG_MMU
- teq ip, ip @ set Z flag
- ldr ip, [r2] @ load current val
- add r3, r2, #1 @ prepare store ptr
- teqeq ip, r0 @ compare with oldval if still allowed
- streq r1, [r3, #-1]! @ store newval if still allowed
- subs r0, r2, r3 @ if r2 == r3 the str occured
+1: ldr r3, [r2] @ load current val
+ subs r3, r3, r0 @ compare with oldval
+2: streq r1, [r2] @ store newval if eq
+ rsbs r0, r3, #0 @ set return val and C flag
+ usr_ret lr
+
+ .text
+kuser_cmpxchg_fixup:
+ @ Called from kuser_cmpxchg_check macro.
+ @ r2 = address of interrupted insn (must be preserved).
+ @ sp = saved regs. r7 and r8 are clobbered.
+ @ 1b = first critical insn, 2b = last critical insn.
+ @ If r2 >= 1b and r2 <= 2b then saved pc_usr is set to 1b.
+ mov r7, #0xffff0fff
+ sub r7, r7, #(0xffff0fff - (0xffff0fc0 + (1b - __kuser_cmpxchg)))
+ subs r8, r2, r7
+ rsbcss r8, r8, #(2b - 1b)
+ strcs r7, [sp, #S_PC]
+ mov pc, lr
+ .previous
+
#else
#warning "NPTL on non MMU needs fixing"
mov r0, #-1
adds r0, r0, #0
-#endif
usr_ret lr
+#endif
#else
#ifdef CONFIG_SMP
mcr p15, 0, r0, c7, c10, 5 @ dmb
#endif
- ldrex r3, [r2]
+1: ldrex r3, [r2]
subs r3, r3, r0
strexeq r3, r1, [r2]
+ teqeq r3, #1
+ beq 1b
rsbs r0, r3, #0
+ /* beware -- each __kuser slot must be 8 instructions max */
#ifdef CONFIG_SMP
- mcr p15, 0, r0, c7, c10, 5 @ dmb
-#endif
+ b __kuser_memory_barrier
+#else
usr_ret lr
+#endif
#endif
@@ -829,7 +849,7 @@ __kuser_cmpxchg: @ 0xffff0fc0
*
* Clobbered:
*
- * the Z flag might be lost
+ * none
*
* Definition and user space usage example:
*
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 4764bd9ccee..c34db4e868f 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -327,7 +327,7 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
if ((instr & hook->instr_mask) == hook->instr_val &&
(regs->ARM_cpsr & hook->cpsr_mask) == hook->cpsr_val) {
if (hook->fn(regs, instr) == 0) {
- spin_unlock_irq(&undef_lock);
+ spin_unlock_irqrestore(&undef_lock, flags);
return;
}
}
@@ -509,7 +509,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
* existence. Don't ever use this from user code.
*/
case 0xfff0:
- {
+ for (;;) {
extern void do_DataAbort(unsigned long addr, unsigned int fsr,
struct pt_regs *regs);
unsigned long val;
@@ -545,7 +545,6 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
up_read(&mm->mmap_sem);
/* simulate a write access fault */
do_DataAbort(addr, 15 + (1 << 11), regs);
- return -1;
}
#endif
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index 0417c165d50..9296833f91c 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -14,6 +14,7 @@
#include <asm/mach/map.h>
#include <linux/platform_device.h>
+#include <linux/i2c-gpio.h>
#include <asm/arch/board.h>
#include <asm/arch/gpio.h>
@@ -435,7 +436,40 @@ void __init at91_add_device_nand(struct at91_nand_data *data) {}
* TWI (i2c)
* -------------------------------------------------------------------- */
-#if defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
+/*
+ * Prefer the GPIO code since the TWI controller isn't robust
+ * (gets overruns and underruns under load) and can only issue
+ * repeated STARTs in one scenario (the driver doesn't yet handle them).
+ */
+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
+
+static struct i2c_gpio_platform_data pdata = {
+ .sda_pin = AT91_PIN_PA25,
+ .sda_is_open_drain = 1,
+ .scl_pin = AT91_PIN_PA26,
+ .scl_is_open_drain = 1,
+ .udelay = 2, /* ~100 kHz */
+};
+
+static struct platform_device at91rm9200_twi_device = {
+ .name = "i2c-gpio",
+ .id = -1,
+ .dev.platform_data = &pdata,
+};
+
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+{
+ at91_set_GPIO_periph(AT91_PIN_PA25, 1); /* TWD (SDA) */
+ at91_set_multi_drive(AT91_PIN_PA25, 1);
+
+ at91_set_GPIO_periph(AT91_PIN_PA26, 1); /* TWCK (SCL) */
+ at91_set_multi_drive(AT91_PIN_PA26, 1);
+
+ i2c_register_board_info(0, devices, nr_devices);
+ platform_device_register(&at91rm9200_twi_device);
+}
+
+#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
static struct resource twi_resources[] = {
[0] = {
@@ -457,7 +491,7 @@ static struct platform_device at91rm9200_twi_device = {
.num_resources = ARRAY_SIZE(twi_resources),
};
-void __init at91_add_device_i2c(void)
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
{
/* pins used for TWI interface */
at91_set_A_periph(AT91_PIN_PA25, 0); /* TWD */
@@ -466,10 +500,11 @@ void __init at91_add_device_i2c(void)
at91_set_A_periph(AT91_PIN_PA26, 0); /* TWCK */
at91_set_multi_drive(AT91_PIN_PA26, 1);
+ i2c_register_board_info(0, devices, nr_devices);
platform_device_register(&at91rm9200_twi_device);
}
#else
-void __init at91_add_device_i2c(void) {}
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
#endif
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index ffd3154c1e5..3091bf47d8c 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -13,6 +13,7 @@
#include <asm/mach/map.h>
#include <linux/platform_device.h>
+#include <linux/i2c-gpio.h>
#include <asm/arch/board.h>
#include <asm/arch/gpio.h>
@@ -352,7 +353,41 @@ void __init at91_add_device_nand(struct at91_nand_data *data) {}
* TWI (i2c)
* -------------------------------------------------------------------- */
-#if defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
+/*
+ * Prefer the GPIO code since the TWI controller isn't robust
+ * (gets overruns and underruns under load) and can only issue
+ * repeated STARTs in one scenario (the driver doesn't yet handle them).
+ */
+
+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
+
+static struct i2c_gpio_platform_data pdata = {
+ .sda_pin = AT91_PIN_PA23,
+ .sda_is_open_drain = 1,
+ .scl_pin = AT91_PIN_PA24,
+ .scl_is_open_drain = 1,
+ .udelay = 2, /* ~100 kHz */
+};
+
+static struct platform_device at91sam9260_twi_device = {
+ .name = "i2c-gpio",
+ .id = -1,
+ .dev.platform_data = &pdata,
+};
+
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+{
+ at91_set_GPIO_periph(AT91_PIN_PA23, 1); /* TWD (SDA) */
+ at91_set_multi_drive(AT91_PIN_PA23, 1);
+
+ at91_set_GPIO_periph(AT91_PIN_PA24, 1); /* TWCK (SCL) */
+ at91_set_multi_drive(AT91_PIN_PA24, 1);
+
+ i2c_register_board_info(0, devices, nr_devices);
+ platform_device_register(&at91sam9260_twi_device);
+}
+
+#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
static struct resource twi_resources[] = {
[0] = {
@@ -374,7 +409,7 @@ static struct platform_device at91sam9260_twi_device = {
.num_resources = ARRAY_SIZE(twi_resources),
};
-void __init at91_add_device_i2c(void)
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
{
/* pins used for TWI interface */
at91_set_A_periph(AT91_PIN_PA23, 0); /* TWD */
@@ -383,10 +418,11 @@ void __init at91_add_device_i2c(void)
at91_set_A_periph(AT91_PIN_PA24, 0); /* TWCK */
at91_set_multi_drive(AT91_PIN_PA24, 1);
+ i2c_register_board_info(0, devices, nr_devices);
platform_device_register(&at91sam9260_twi_device);
}
#else
-void __init at91_add_device_i2c(void) {}
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
#endif
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 3576595b494..64979a9023c 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -14,7 +14,9 @@
#include <asm/mach/map.h>
#include <linux/platform_device.h>
+#include <linux/i2c-gpio.h>
+#include <linux/fb.h>
#include <video/atmel_lcdc.h>
#include <asm/arch/board.h>
@@ -275,7 +277,40 @@ void __init at91_add_device_nand(struct at91_nand_data *data) {}
* TWI (i2c)
* -------------------------------------------------------------------- */
-#if defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
+/*
+ * Prefer the GPIO code since the TWI controller isn't robust
+ * (gets overruns and underruns under load) and can only issue
+ * repeated STARTs in one scenario (the driver doesn't yet handle them).
+ */
+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
+
+static struct i2c_gpio_platform_data pdata = {
+ .sda_pin = AT91_PIN_PA7,
+ .sda_is_open_drain = 1,
+ .scl_pin = AT91_PIN_PA8,
+ .scl_is_open_drain = 1,
+ .udelay = 2, /* ~100 kHz */
+};
+
+static struct platform_device at91sam9261_twi_device = {
+ .name = "i2c-gpio",
+ .id = -1,
+ .dev.platform_data = &pdata,
+};
+
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+{
+ at91_set_GPIO_periph(AT91_PIN_PA7, 1); /* TWD (SDA) */
+ at91_set_multi_drive(AT91_PIN_PA7, 1);
+
+ at91_set_GPIO_periph(AT91_PIN_PA8, 1); /* TWCK (SCL) */
+ at91_set_multi_drive(AT91_PIN_PA8, 1);
+
+ i2c_register_board_info(0, devices, nr_devices);
+ platform_device_register(&at91sam9261_twi_device);
+}
+
+#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
static struct resource twi_resources[] = {
[0] = {
@@ -297,7 +332,7 @@ static struct platform_device at91sam9261_twi_device = {
.num_resources = ARRAY_SIZE(twi_resources),
};
-void __init at91_add_device_i2c(void)
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
{
/* pins used for TWI interface */
at91_set_A_periph(AT91_PIN_PA7, 0); /* TWD */
@@ -306,10 +341,11 @@ void __init at91_add_device_i2c(void)
at91_set_A_periph(AT91_PIN_PA8, 0); /* TWCK */
at91_set_multi_drive(AT91_PIN_PA8, 1);
+ i2c_register_board_info(0, devices, nr_devices);
platform_device_register(&at91sam9261_twi_device);
}
#else
-void __init at91_add_device_i2c(void) {}
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
#endif
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index f924bd5017d..ac329a98e95 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -13,7 +13,9 @@
#include <asm/mach/map.h>
#include <linux/platform_device.h>
+#include <linux/i2c-gpio.h>
+#include <linux/fb.h>
#include <video/atmel_lcdc.h>
#include <asm/arch/board.h>
@@ -421,7 +423,40 @@ void __init at91_add_device_nand(struct at91_nand_data *data) {}
* TWI (i2c)
* -------------------------------------------------------------------- */
-#if defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
+/*
+ * Prefer the GPIO code since the TWI controller isn't robust
+ * (gets overruns and underruns under load) and can only issue
+ * repeated STARTs in one scenario (the driver doesn't yet handle them).
+ */
+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
+
+static struct i2c_gpio_platform_data pdata = {
+ .sda_pin = AT91_PIN_PB4,
+ .sda_is_open_drain = 1,
+ .scl_pin = AT91_PIN_PB5,
+ .scl_is_open_drain = 1,
+ .udelay = 2, /* ~100 kHz */
+};
+
+static struct platform_device at91sam9263_twi_device = {
+ .name = "i2c-gpio",
+ .id = -1,
+ .dev.platform_data = &pdata,
+};
+
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+{
+ at91_set_GPIO_periph(AT91_PIN_PB4, 1); /* TWD (SDA) */
+ at91_set_multi_drive(AT91_PIN_PB4, 1);
+
+ at91_set_GPIO_periph(AT91_PIN_PB5, 1); /* TWCK (SCL) */
+ at91_set_multi_drive(AT91_PIN_PB5, 1);
+
+ i2c_register_board_info(0, devices, nr_devices);
+ platform_device_register(&at91sam9263_twi_device);
+}
+
+#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
static struct resource twi_resources[] = {
[0] = {
@@ -443,7 +478,7 @@ static struct platform_device at91sam9263_twi_device = {
.num_resources = ARRAY_SIZE(twi_resources),
};
-void __init at91_add_device_i2c(void)
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
{
/* pins used for TWI interface */
at91_set_A_periph(AT91_PIN_PB4, 0); /* TWD */
@@ -452,10 +487,11 @@ void __init at91_add_device_i2c(void)
at91_set_A_periph(AT91_PIN_PB5, 0); /* TWCK */
at91_set_multi_drive(AT91_PIN_PB5, 1);
+ i2c_register_board_info(0, devices, nr_devices);
platform_device_register(&at91sam9263_twi_device);
}
#else
-void __init at91_add_device_i2c(void) {}
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
#endif
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index cd7532bcd4e..2bd60a3dc62 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -10,8 +10,9 @@
#include <asm/mach/map.h>
#include <linux/platform_device.h>
-#include <linux/fb.h>
+#include <linux/i2c-gpio.h>
+#include <linux/fb.h>
#include <video/atmel_lcdc.h>
#include <asm/arch/board.h>
@@ -169,7 +170,40 @@ void __init at91_add_device_nand(struct at91_nand_data *data) {}
* TWI (i2c)
* -------------------------------------------------------------------- */
-#if defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
+/*
+ * Prefer the GPIO code since the TWI controller isn't robust
+ * (gets overruns and underruns under load) and can only issue
+ * repeated STARTs in one scenario (the driver doesn't yet handle them).
+ */
+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
+
+static struct i2c_gpio_platform_data pdata = {
+ .sda_pin = AT91_PIN_PA23,
+ .sda_is_open_drain = 1,
+ .scl_pin = AT91_PIN_PA24,
+ .scl_is_open_drain = 1,
+ .udelay = 2, /* ~100 kHz */
+};
+
+static struct platform_device at91sam9rl_twi_device = {
+ .name = "i2c-gpio",
+ .id = -1,
+ .dev.platform_data = &pdata,
+};
+
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+{
+ at91_set_GPIO_periph(AT91_PIN_PA23, 1); /* TWD (SDA) */
+ at91_set_multi_drive(AT91_PIN_PA23, 1);
+
+ at91_set_GPIO_periph(AT91_PIN_PA24, 1); /* TWCK (SCL) */
+ at91_set_multi_drive(AT91_PIN_PA24, 1);
+
+ i2c_register_board_info(0, devices, nr_devices);
+ platform_device_register(&at91sam9rl_twi_device);
+}
+
+#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
static struct resource twi_resources[] = {
[0] = {
@@ -191,7 +225,7 @@ static struct platform_device at91sam9rl_twi_device = {
.num_resources = ARRAY_SIZE(twi_resources),
};
-void __init at91_add_device_i2c(void)
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
{
/* pins used for TWI interface */
at91_set_A_periph(AT91_PIN_PA23, 0); /* TWD */
@@ -200,10 +234,11 @@ void __init at91_add_device_i2c(void)
at91_set_A_periph(AT91_PIN_PA24, 0); /* TWCK */
at91_set_multi_drive(AT91_PIN_PA24, 1);
+ i2c_register_board_info(0, devices, nr_devices);
platform_device_register(&at91sam9rl_twi_device);
}
#else
-void __init at91_add_device_i2c(void) {}
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
#endif
diff --git a/arch/arm/mach-at91/board-carmeva.c b/arch/arm/mach-at91/board-carmeva.c
index 76ec856cd4f..0f0878294a6 100644
--- a/arch/arm/mach-at91/board-carmeva.c
+++ b/arch/arm/mach-at91/board-carmeva.c
@@ -128,7 +128,7 @@ static void __init carmeva_board_init(void)
/* USB Device */
at91_add_device_udc(&carmeva_udc_data);
/* I2C */
- at91_add_device_i2c();
+ at91_add_device_i2c(NULL, 0);
/* SPI */
at91_add_device_spi(carmeva_spi_devices, ARRAY_SIZE(carmeva_spi_devices));
/* Compact Flash */
diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
index dde089922e3..d0aa20c9383 100644
--- a/arch/arm/mach-at91/board-csb337.c
+++ b/arch/arm/mach-at91/board-csb337.c
@@ -23,7 +23,6 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/mtd/physmap.h>
@@ -85,12 +84,12 @@ static struct at91_udc_data __initdata csb337_udc_data = {
};
static struct i2c_board_info __initdata csb337_i2c_devices[] = {
- { I2C_BOARD_INFO("rtc-ds1307", 0x68),
- .type = "ds1307",
+ {
+ I2C_BOARD_INFO("rtc-ds1307", 0x68),
+ .type = "ds1307",
},
};
-
static struct at91_cf_data __initdata csb337_cf_data = {
/*
* connector P4 on the CSB 337 mates to
@@ -168,9 +167,7 @@ static void __init csb337_board_init(void)
/* USB Device */
at91_add_device_udc(&csb337_udc_data);
/* I2C */
- at91_add_device_i2c();
- i2c_register_board_info(0, csb337_i2c_devices,
- ARRAY_SIZE(csb337_i2c_devices));
+ at91_add_device_i2c(csb337_i2c_devices, ARRAY_SIZE(csb337_i2c_devices));
/* Compact Flash */
at91_set_gpio_input(AT91_PIN_PB22, 1); /* IOIS16 */
at91_add_device_cf(&csb337_cf_data);
diff --git a/arch/arm/mach-at91/board-csb637.c b/arch/arm/mach-at91/board-csb637.c
index 77f04b935b3..c5c721d27f4 100644
--- a/arch/arm/mach-at91/board-csb637.c
+++ b/arch/arm/mach-at91/board-csb637.c
@@ -129,7 +129,7 @@ static void __init csb637_board_init(void)
/* USB Device */
at91_add_device_udc(&csb637_udc_data);
/* I2C */
- at91_add_device_i2c();
+ at91_add_device_i2c(NULL, 0);
/* SPI */
at91_add_device_spi(NULL, 0);
/* NOR flash */
diff --git a/arch/arm/mach-at91/board-dk.c b/arch/arm/mach-at91/board-dk.c
index af497896a96..40c9e433170 100644
--- a/arch/arm/mach-at91/board-dk.c
+++ b/arch/arm/mach-at91/board-dk.c
@@ -124,6 +124,19 @@ static struct spi_board_info dk_spi_devices[] = {
#endif
};
+static struct i2c_board_info __initdata dk_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("ics1523", 0x26),
+ },
+ {
+ I2C_BOARD_INFO("x9429", 0x28),
+ },
+ {
+ I2C_BOARD_INFO("at24c", 0x50),
+ .type = "24c1024",
+ }
+};
+
static struct mtd_partition __initdata dk_nand_partition[] = {
{
.name = "NAND Partition 1",
@@ -185,7 +198,7 @@ static void __init dk_board_init(void)
/* Compact Flash */
at91_add_device_cf(&dk_cf_data);
/* I2C */
- at91_add_device_i2c();
+ at91_add_device_i2c(dk_i2c_devices, ARRAY_SIZE(dk_i2c_devices));
/* SPI */
at91_add_device_spi(dk_spi_devices, ARRAY_SIZE(dk_spi_devices));
#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
diff --git a/arch/arm/mach-at91/board-eb9200.c b/arch/arm/mach-at91/board-eb9200.c
index 20458b5548f..b7b79bb9d6c 100644
--- a/arch/arm/mach-at91/board-eb9200.c
+++ b/arch/arm/mach-at91/board-eb9200.c
@@ -91,6 +91,14 @@ static struct at91_mmc_data __initdata eb9200_mmc_data = {
.wire4 = 1,
};
+static struct i2c_board_info __initdata eb9200_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("at24c", 0x50),
+ .type = "24c512",
+ },
+};
+
+
static void __init eb9200_board_init(void)
{
/* Serial */
@@ -102,7 +110,7 @@ static void __init eb9200_board_init(void)
/* USB Device */
at91_add_device_udc(&eb9200_udc_data);
/* I2C */
- at91_add_device_i2c();
+ at91_add_device_i2c(eb9200_i2c_devices, ARRAY_SIZE(eb9200_i2c_devices));
/* Compact Flash */
at91_add_device_cf(&eb9200_cf_data);
/* SPI */
diff --git a/arch/arm/mach-at91/board-ek.c b/arch/arm/mach-at91/board-ek.c
index 322fdd75a1e..d05b1b2be9f 100644
--- a/arch/arm/mach-at91/board-ek.c
+++ b/arch/arm/mach-at91/board-ek.c
@@ -145,7 +145,7 @@ static void __init ek_board_init(void)
at91_add_device_udc(&ek_udc_data);
at91_set_multi_drive(ek_udc_data.pullup_pin, 1); /* pullup_pin is connected to reset */
/* I2C */
- at91_add_device_i2c();
+ at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
/* SPI */
at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
diff --git a/arch/arm/mach-at91/board-kafa.c b/arch/arm/mach-at91/board-kafa.c
index c77d84ce9ca..cf1b7b2f76f 100644
--- a/arch/arm/mach-at91/board-kafa.c
+++ b/arch/arm/mach-at91/board-kafa.c
@@ -92,7 +92,7 @@ static void __init kafa_board_init(void)
/* USB Device */
at91_add_device_udc(&kafa_udc_data);
/* I2C */
- at91_add_device_i2c();
+ at91_add_device_i2c(NULL, 0);
/* SPI */
at91_add_device_spi(NULL, 0);
}
diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c
index 7d9b1a278fd..4b39b9cda75 100644
--- a/arch/arm/mach-at91/board-kb9202.c
+++ b/arch/arm/mach-at91/board-kb9202.c
@@ -124,7 +124,7 @@ static void __init kb9202_board_init(void)
/* MMC */
at91_add_device_mmc(0, &kb9202_mmc_data);
/* I2C */
- at91_add_device_i2c();
+ at91_add_device_i2c(NULL, 0);
/* SPI */
at91_add_device_spi(NULL, 0);
/* NAND */
diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c
index 49cfe7ab4a8..6acb55c09ae 100644
--- a/arch/arm/mach-at91/board-picotux200.c
+++ b/arch/arm/mach-at91/board-picotux200.c
@@ -139,7 +139,7 @@ static void __init picotux200_board_init(void)
// at91_add_device_udc(&picotux200_udc_data);
// at91_set_multi_drive(picotux200_udc_data.pullup_pin, 1); /* pullup_pin is connected to reset */
/* I2C */
- at91_add_device_i2c();
+ at91_add_device_i2c(NULL, 0);
/* SPI */
// at91_add_device_spi(picotux200_spi_devices, ARRAY_SIZE(picotux200_spi_devices));
#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
index 65fa532bb4a..b343a6c2812 100644
--- a/arch/arm/mach-at91/board-sam9260ek.c
+++ b/arch/arm/mach-at91/board-sam9260ek.c
@@ -189,7 +189,7 @@ static void __init ek_board_init(void)
/* MMC */
at91_add_device_mmc(0, &ek_mmc_data);
/* I2C */
- at91_add_device_i2c();
+ at91_add_device_i2c(NULL, 0);
}
MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK")
diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
index 42e172cb0f4..550ae59a3ac 100644
--- a/arch/arm/mach-at91/board-sam9261ek.c
+++ b/arch/arm/mach-at91/board-sam9261ek.c
@@ -382,14 +382,14 @@ static struct platform_device ek_button_device = {
static void __init ek_add_device_buttons(void)
{
- at91_set_gpio_input(AT91_PIN_PB27, 0); /* btn0 */
- at91_set_deglitch(AT91_PIN_PB27, 1);
- at91_set_gpio_input(AT91_PIN_PB26, 0); /* btn1 */
- at91_set_deglitch(AT91_PIN_PB26, 1);
- at91_set_gpio_input(AT91_PIN_PB25, 0); /* btn2 */
- at91_set_deglitch(AT91_PIN_PB25, 1);
- at91_set_gpio_input(AT91_PIN_PB24, 0); /* btn3 */
- at91_set_deglitch(AT91_PIN_PB24, 1);
+ at91_set_gpio_input(AT91_PIN_PA27, 0); /* btn0 */
+ at91_set_deglitch(AT91_PIN_PA27, 1);
+ at91_set_gpio_input(AT91_PIN_PA26, 0); /* btn1 */
+ at91_set_deglitch(AT91_PIN_PA26, 1);
+ at91_set_gpio_input(AT91_PIN_PA25, 0); /* btn2 */
+ at91_set_deglitch(AT91_PIN_PA25, 1);
+ at91_set_gpio_input(AT91_PIN_PA24, 0); /* btn3 */
+ at91_set_deglitch(AT91_PIN_PA24, 1);
platform_device_register(&ek_button_device);
}
@@ -406,7 +406,7 @@ static void __init ek_board_init(void)
/* USB Device */
at91_add_device_udc(&ek_udc_data);
/* I2C */
- at91_add_device_i2c();
+ at91_add_device_i2c(NULL, 0);
/* NAND */
at91_add_device_nand(&ek_nand_data);
/* DM9000 ethernet */
diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
index 2a1cc73390b..ab9dcc07545 100644
--- a/arch/arm/mach-at91/board-sam9263ek.c
+++ b/arch/arm/mach-at91/board-sam9263ek.c
@@ -291,7 +291,7 @@ static void __init ek_board_init(void)
/* NAND */
at91_add_device_nand(&ek_nand_data);
/* I2C */
- at91_add_device_i2c();
+ at91_add_device_i2c(NULL, 0);
/* LCD Controller */
at91_add_device_lcdc(&ek_lcdc_data);
/* AC97 */
diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
index 9b61320f295..bc0546d7245 100644
--- a/arch/arm/mach-at91/board-sam9rlek.c
+++ b/arch/arm/mach-at91/board-sam9rlek.c
@@ -181,7 +181,7 @@ static void __init ek_board_init(void)
/* Serial */
at91_add_device_serial();
/* I2C */
- at91_add_device_i2c();
+ at91_add_device_i2c(NULL, 0);
/* NAND */
at91_add_device_nand(&ek_nand_data);
/* SPI */
diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
index 848efb2a4eb..57c3b647ce8 100644
--- a/arch/arm/mach-at91/clock.c
+++ b/arch/arm/mach-at91/clock.c
@@ -351,7 +351,7 @@ static void init_programmable_clock(struct clk *clk)
pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
parent = at91_css_to_clk(pckr & AT91_PMC_CSS);
clk->parent = parent;
- clk->rate_hz = parent->rate_hz / (1 << ((pckr >> 2) & 3));
+ clk->rate_hz = parent->rate_hz / (1 << ((pckr & AT91_PMC_PRES) >> 2));
}
#endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */
@@ -587,8 +587,11 @@ int __init at91_clock_init(unsigned long main_clock)
mckr = at91_sys_read(AT91_PMC_MCKR);
mck.parent = at91_css_to_clk(mckr & AT91_PMC_CSS);
freq = mck.parent->rate_hz;
- freq /= (1 << ((mckr >> 2) & 3)); /* prescale */
- mck.rate_hz = freq / (1 + ((mckr >> 8) & 3)); /* mdiv */
+ freq /= (1 << ((mckr & AT91_PMC_PRES) >> 2)); /* prescale */
+ if (cpu_is_at91rm9200())
+ mck.rate_hz = freq / (1 + ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */
+ else
+ mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */
/* Register the PMC's standard clocks */
for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++)
diff --git a/arch/arm/mach-imx/irq.c b/arch/arm/mach-imx/irq.c
index 0791b56caec..a7465db8489 100644
--- a/arch/arm/mach-imx/irq.c
+++ b/arch/arm/mach-imx/irq.c
@@ -43,12 +43,46 @@
*
*/
-#define INTENNUM_OFF 0x8
-#define INTDISNUM_OFF 0xC
+#define INTCNTL_OFF 0x00
+#define NIMASK_OFF 0x04
+#define INTENNUM_OFF 0x08
+#define INTDISNUM_OFF 0x0C
+#define INTENABLEH_OFF 0x10
+#define INTENABLEL_OFF 0x14
+#define INTTYPEH_OFF 0x18
+#define INTTYPEL_OFF 0x1C
+#define NIPRIORITY_OFF(x) (0x20+4*(7-(x)))
+#define NIVECSR_OFF 0x40
+#define FIVECSR_OFF 0x44
+#define INTSRCH_OFF 0x48
+#define INTSRCL_OFF 0x4C
+#define INTFRCH_OFF 0x50
+#define INTFRCL_OFF 0x54
+#define NIPNDH_OFF 0x58
+#define NIPNDL_OFF 0x5C
+#define FIPNDH_OFF 0x60
+#define FIPNDL_OFF 0x64
#define VA_AITC_BASE IO_ADDRESS(IMX_AITC_BASE)
-#define IMX_AITC_INTDISNUM (VA_AITC_BASE + INTDISNUM_OFF)
+#define IMX_AITC_INTCNTL (VA_AITC_BASE + INTCNTL_OFF)
+#define IMX_AITC_NIMASK (VA_AITC_BASE + NIMASK_OFF)
#define IMX_AITC_INTENNUM (VA_AITC_BASE + INTENNUM_OFF)
+#define IMX_AITC_INTDISNUM (VA_AITC_BASE + INTDISNUM_OFF)
+#define IMX_AITC_INTENABLEH (VA_AITC_BASE + INTENABLEH_OFF)
+#define IMX_AITC_INTENABLEL (VA_AITC_BASE + INTENABLEL_OFF)
+#define IMX_AITC_INTTYPEH (VA_AITC_BASE + INTTYPEH_OFF)
+#define IMX_AITC_INTTYPEL (VA_AITC_BASE + INTTYPEL_OFF)
+#define IMX_AITC_NIPRIORITY(x) (VA_AITC_BASE + NIPRIORITY_OFF(x))
+#define IMX_AITC_NIVECSR (VA_AITC_BASE + NIVECSR_OFF)
+#define IMX_AITC_FIVECSR (VA_AITC_BASE + FIVECSR_OFF)
+#define IMX_AITC_INTSRCH (VA_AITC_BASE + INTSRCH_OFF)
+#define IMX_AITC_INTSRCL (VA_AITC_BASE + INTSRCL_OFF)
+#define IMX_AITC_INTFRCH (VA_AITC_BASE + INTFRCH_OFF)
+#define IMX_AITC_INTFRCL (VA_AITC_BASE + INTFRCL_OFF)
+#define IMX_AITC_NIPNDH (VA_AITC_BASE + NIPNDH_OFF)
+#define IMX_AITC_NIPNDL (VA_AITC_BASE + NIPNDL_OFF)
+#define IMX_AITC_FIPNDH (VA_AITC_BASE + FIPNDH_OFF)
+#define IMX_AITC_FIPNDL (VA_AITC_BASE + FIPNDL_OFF)
#if 0
#define DEBUG_IRQ(fmt...) printk(fmt)
@@ -222,7 +256,12 @@ imx_init_irq(void)
DEBUG_IRQ("Initializing imx interrupts\n");
- /* Mask all interrupts initially */
+ /* Disable all interrupts initially. */
+ /* Do not rely on the bootloader. */
+ __raw_writel(0, IMX_AITC_INTENABLEH);
+ __raw_writel(0, IMX_AITC_INTENABLEL);
+
+ /* Mask all GPIO interrupts as well */
IMR(0) = 0;
IMR(1) = 0;
IMR(2) = 0;
@@ -245,6 +284,6 @@ imx_init_irq(void)
set_irq_chained_handler(GPIO_INT_PORTC, imx_gpioc_demux_handler);
set_irq_chained_handler(GPIO_INT_PORTD, imx_gpiod_demux_handler);
- /* Disable all interrupts initially. */
- /* In IMX this is done in the bootloader. */
+ /* Release masking of interrupts according to priority */
+ __raw_writel(-1, IMX_AITC_NIMASK);
}
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index d0f2b597db1..8e126e6b74c 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -146,7 +146,7 @@ static struct clk pxa27x_clks[] = {
INIT_CKEN("MMCCLK", MMC, 19500000, 0, &pxa_device_mci.dev),
INIT_CKEN("FICPCLK", FICP, 48000000, 0, &pxa_device_ficp.dev),
- INIT_CKEN("USBCLK", USB, 48000000, 0, &pxa27x_device_ohci.dev),
+ INIT_CKEN("USBCLK", USBHOST, 48000000, 0, &pxa27x_device_ohci.dev),
INIT_CKEN("I2CCLK", PWRI2C, 13000000, 0, &pxa27x_device_i2c_power.dev),
INIT_CKEN("KBDCLK", KEYPAD, 32768, 0, NULL),
diff --git a/arch/arm/mach-pxa/pxa320.c b/arch/arm/mach-pxa/pxa320.c
index 1010f77d977..74128eb8f8d 100644
--- a/arch/arm/mach-pxa/pxa320.c
+++ b/arch/arm/mach-pxa/pxa320.c
@@ -23,8 +23,11 @@
static struct pxa3xx_mfp_addr_map pxa320_mfp_addr_map[] __initdata = {
MFP_ADDR_X(GPIO0, GPIO4, 0x0124),
- MFP_ADDR_X(GPIO5, GPIO26, 0x028C),
- MFP_ADDR_X(GPIO27, GPIO62, 0x0400),
+ MFP_ADDR_X(GPIO5, GPIO9, 0x028C),
+ MFP_ADDR(GPIO10, 0x0458),
+ MFP_ADDR_X(GPIO11, GPIO26, 0x02A0),
+ MFP_ADDR_X(GPIO27, GPIO48, 0x0400),
+ MFP_ADDR_X(GPIO49, GPIO62, 0x045C),
MFP_ADDR_X(GPIO63, GPIO73, 0x04B4),
MFP_ADDR_X(GPIO74, GPIO98, 0x04F0),
MFP_ADDR_X(GPIO99, GPIO127, 0x0600),
diff --git a/arch/arm/mach-pxa/ssp.c b/arch/arm/mach-pxa/ssp.c
index 71766ac0328..422afee8816 100644
--- a/arch/arm/mach-pxa/ssp.c
+++ b/arch/arm/mach-pxa/ssp.c
@@ -309,6 +309,7 @@ void ssp_exit(struct ssp_dev *dev)
if (dev->port > PXA_SSP_PORTS || dev->port == 0) {
printk(KERN_WARNING "SSP: tried to close invalid port\n");
+ mutex_unlock(&mutex);
return;
}