[ARM] pxa: add support for additional GPIOs on PXA26x
Original patch from Marek Vasut, the problems with PXA26x are:
1. there are additional 4 GPIOs 86,87,88,89 have their direction bits
inverted in GPDR2, as well as their alternate function bits being
'1' for their GPIO functionality in GAFRx
2. there is no easy way to decide if the processor is a pxa26x or a
pxa250/pxa255 at run-time, so the assumption here is the pxa26x
will be treated as one of the pxa25x variants, and board code
should have a better knowledge of the processor it is featured
Introduce pxa26x_init_irq() for the second purpose, and treat the
additional GPIOs > 85 on PXA25x specially.
Kconfig option CONFIG_CPU_PXA26x is introduced to optimize the code
a bit when PXA26x support isn't needed. Board config options have
to select this to enable the support for PXA26x.
__gpio_is_inverted() will be optimized way when CONFIG_CPU_PXA26x
isn't selected.
Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
Signed-off-by: Eric Miao <eric.miao@marvell.com>
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index a062235..6c59f98 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -394,6 +394,12 @@
help
Select code specific to PXA27x variants
+config CPU_PXA26x
+ bool
+ select PXA25x
+ help
+ Select code specific to PXA26x (codename Dalhart)
+
config PXA3xx
bool
help
diff --git a/arch/arm/mach-pxa/gpio.c b/arch/arm/mach-pxa/gpio.c
index 14930cf..843144f 100644
--- a/arch/arm/mach-pxa/gpio.c
+++ b/arch/arm/mach-pxa/gpio.c
@@ -33,6 +33,18 @@
int pxa_last_gpio;
+#ifdef CONFIG_CPU_PXA26x
+/* GPIO86/87/88/89 on PXA26x have their direction bits in GPDR2 inverted,
+ * as well as their Alternate Function value being '1' for GPIO in GAFRx.
+ */
+static int __gpio_is_inverted(unsigned gpio)
+{
+ return cpu_is_pxa25x() && gpio > 85;
+}
+#else
+#define __gpio_is_inverted(gpio) (0)
+#endif
+
/*
* Configure pins for GPIO or other functions
*/
@@ -75,7 +87,10 @@
gpdr = pxa->regbase + GPDR_OFFSET;
local_irq_save(flags);
value = __raw_readl(gpdr);
- value &= ~mask;
+ if (__gpio_is_inverted(chip->base + offset))
+ value |= mask;
+ else
+ value &= ~mask;
__raw_writel(value, gpdr);
local_irq_restore(flags);
@@ -97,7 +112,10 @@
gpdr = pxa->regbase + GPDR_OFFSET;
local_irq_save(flags);
tmp = __raw_readl(gpdr);
- tmp |= mask;
+ if (__gpio_is_inverted(chip->base + offset))
+ tmp &= ~mask;
+ else
+ tmp |= mask;
__raw_writel(tmp, gpdr);
local_irq_restore(flags);
@@ -173,10 +191,17 @@
*/
static int __gpio_is_occupied(unsigned gpio)
{
- if (cpu_is_pxa25x() || cpu_is_pxa27x())
- return GAFR(gpio) & (0x3 << (((gpio) & 0xf) * 2));
- else
- return 0;
+ if (cpu_is_pxa27x() || cpu_is_pxa25x()) {
+ int af = (GAFR(gpio) >> ((gpio & 0xf) * 2)) & 0x3;
+ int dir = GPDR(gpio) & GPIO_bit(gpio);
+
+ if (__gpio_is_inverted(gpio))
+ return af != 1 || dir == 0;
+ else
+ return af != 0 || dir != 0;
+ }
+
+ return 0;
}
static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
@@ -190,9 +215,8 @@
/* Don't mess with enabled GPIOs using preconfigured edges or
* GPIOs set to alternate function or to output during probe
*/
- if ((GPIO_IRQ_rising_edge[idx] |
- GPIO_IRQ_falling_edge[idx] |
- GPDR(gpio)) & GPIO_bit(gpio))
+ if ((GPIO_IRQ_rising_edge[idx] & GPIO_bit(gpio)) ||
+ (GPIO_IRQ_falling_edge[idx] & GPIO_bit(gpio)))
return 0;
if (__gpio_is_occupied(gpio))
@@ -201,7 +225,10 @@
type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
}
- GPDR(gpio) &= ~GPIO_bit(gpio);
+ if (__gpio_is_inverted(gpio))
+ GPDR(gpio) |= GPIO_bit(gpio);
+ else
+ GPDR(gpio) &= ~GPIO_bit(gpio);
if (type & IRQ_TYPE_EDGE_RISING)
__set_bit(gpio, GPIO_IRQ_rising_edge);
diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa25x.h b/arch/arm/mach-pxa/include/mach/mfp-pxa25x.h
index 617cab2..a72869b 100644
--- a/arch/arm/mach-pxa/include/mach/mfp-pxa25x.h
+++ b/arch/arm/mach-pxa/include/mach/mfp-pxa25x.h
@@ -158,4 +158,35 @@
#define GPIO76_LCD_PCLK MFP_CFG_OUT(GPIO76, AF2, DRIVE_LOW)
#define GPIO77_LCD_BIAS MFP_CFG_OUT(GPIO77, AF2, DRIVE_LOW)
+#ifdef CONFIG_CPU_PXA26x
+/* GPIO */
+#define GPIO85_GPIO MFP_CFG_IN(GPIO85, AF0)
+#define GPIO86_GPIO MFP_CFG_IN(GPIO86, AF1)
+#define GPIO87_GPIO MFP_CFG_IN(GPIO87, AF1)
+#define GPIO88_GPIO MFP_CFG_IN(GPIO88, AF1)
+#define GPIO89_GPIO MFP_CFG_IN(GPIO89, AF1)
+
+/* SDRAM */
+#define GPIO86_nSDCS2 MFP_CFG_OUT(GPIO86, AF0, DRIVE_HIGH)
+#define GPIO87_nSDCS3 MFP_CFG_OUT(GPIO87, AF0, DRIVE_HIGH)
+#define GPIO88_RDnWR MFP_CFG_OUT(GPIO88, AF0, DRIVE_HIGH)
+#define GPIO89_nACRESET MFP_CFG_OUT(GPIO89, AF0, DRIVE_HIGH)
+
+/* USB */
+#define GPIO9_USB_RCV MFP_CFG_IN(GPIO9, AF1)
+#define GPIO32_USB_VP MFP_CFG_IN(GPIO32, AF2)
+#define GPIO34_USB_VM MFP_CFG_IN(GPIO34, AF2)
+#define GPIO39_USB_VPO MFP_CFG_OUT(GPIO39, AF3, DRIVE_LOW)
+#define GPIO56_USB_VMO MFP_CFG_OUT(GPIO56, AF1, DRIVE_LOW)
+#define GPIO57_USB_nOE MFP_CFG_OUT(GPIO57, AF1, DRIVE_HIGH)
+
+/* ASSP */
+#define GPIO28_ASSP_BITCLK_IN MFP_CFG_IN(GPIO28, AF3)
+#define GPIO28_ASSP_BITCLK_OUT MFP_CFG_OUT(GPIO28, AF3, DRIVE_LOW)
+#define GPIO29_ASSP_RXD MFP_CFG_IN(GPIO29, AF3)
+#define GPIO30_ASSP_TXD MFP_CFG_OUT(GPIO30, AF3, DRIVE_LOW)
+#define GPIO31_ASSP_SFRM_IN MFP_CFG_IN(GPIO31, AF1)
+#define GPIO31_ASSP_SFRM_OUT MFP_CFG_OUT(GPIO31, AF3, DRIVE_LOW)
+#endif
+
#endif /* __ASM_ARCH_MFP_PXA25X_H */
diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c
index 1f22987..33626de 100644
--- a/arch/arm/mach-pxa/mfp-pxa2xx.c
+++ b/arch/arm/mach-pxa/mfp-pxa2xx.c
@@ -38,6 +38,7 @@
unsigned valid : 1;
unsigned can_wakeup : 1;
unsigned keypad_gpio : 1;
+ unsigned dir_inverted : 1;
unsigned int mask; /* bit mask in PWER or PKWR */
unsigned int mux_mask; /* bit mask of muxed gpio bits, 0 if no mux */
unsigned long config;
@@ -54,7 +55,7 @@
int uorl = !!(gpio & 0x10); /* GAFRx_U or GAFRx_L ? */
int shft = (gpio & 0xf) << 1;
int fn = MFP_AF(c);
- int dir = c & MFP_DIR_OUT;
+ int is_out = (c & MFP_DIR_OUT) ? 1 : 0;
if (fn > 3)
return -EINVAL;
@@ -68,7 +69,7 @@
else
GAFR_U(bank) = gafr;
- if (dir == MFP_DIR_OUT)
+ if (is_out ^ gpio_desc[gpio].dir_inverted)
GPDR(gpio) |= mask;
else
GPDR(gpio) &= ~mask;
@@ -77,11 +78,11 @@
switch (c & MFP_LPM_STATE_MASK) {
case MFP_LPM_DRIVE_HIGH:
PGSR(bank) |= mask;
- dir = MFP_DIR_OUT;
+ is_out = 1;
break;
case MFP_LPM_DRIVE_LOW:
PGSR(bank) &= ~mask;
- dir = MFP_DIR_OUT;
+ is_out = 1;
break;
case MFP_LPM_DEFAULT:
break;
@@ -92,7 +93,7 @@
break;
}
- if (dir == MFP_DIR_OUT)
+ if (is_out ^ gpio_desc[gpio].dir_inverted)
gpdr_lpm[bank] |= mask;
else
gpdr_lpm[bank] &= ~mask;
@@ -106,7 +107,7 @@
return -EINVAL;
}
- if ((c & MFP_LPM_CAN_WAKEUP) && (dir == MFP_DIR_OUT)) {
+ if ((c & MFP_LPM_CAN_WAKEUP) && is_out) {
pr_warning("%s: output GPIO%d unable to wakeup\n",
__func__, gpio);
return -EINVAL;
@@ -221,6 +222,12 @@
gpio_desc[i].can_wakeup = 1;
gpio_desc[i].mask = GPIO_bit(i);
}
+
+ /* PXA26x has additional 4 GPIOs (86/87/88/89) which has the
+ * direction bit inverted in GPDR2. See PXA26x DM 4.1.1.
+ */
+ for (i = 86; i <= pxa_last_gpio; i++)
+ gpio_desc[i].dir_inverted = 1;
}
#else
static inline void pxa25x_mfp_init(void) {}
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
index 6543321..0f67299 100644
--- a/arch/arm/mach-pxa/pxa25x.c
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -298,6 +298,14 @@
pxa_init_gpio(85, pxa25x_set_wake);
}
+#ifdef CONFIG_CPU_PXA26x
+void __init pxa26x_init_irq(void)
+{
+ pxa_init_irq(32, pxa25x_set_wake);
+ pxa_init_gpio(90, pxa25x_set_wake);
+}
+#endif
+
static struct platform_device *pxa25x_devices[] __initdata = {
&pxa25x_device_udc,
&pxa_device_ffuart,