[ARM] pxa: add support for additional GPIOs on PXA26x
authorEric Miao <eric.miao@marvell.com>
Wed, 26 Nov 2008 10:12:04 +0000 (18:12 +0800)
committerEric Miao <eric.miao@marvell.com>
Tue, 2 Dec 2008 06:42:37 +0000 (14:42 +0800)
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>
arch/arm/mach-pxa/Kconfig
arch/arm/mach-pxa/gpio.c
arch/arm/mach-pxa/include/mach/mfp-pxa25x.h
arch/arm/mach-pxa/mfp-pxa2xx.c
arch/arm/mach-pxa/pxa25x.c

index a062235e83a8b4c3b272c3d7af016d85dcd8b2ba..6c59f989a61a7c6e651b802db08bfa1165ca7fb2 100644 (file)
@@ -394,6 +394,12 @@ config PXA27x
        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
index 14930cf8be7b58d27d523310c02a7e6fe65f3ed4..843144ff1f61446cc3a168124419b2853d9199fb 100644 (file)
@@ -33,6 +33,18 @@ struct pxa_gpio_chip {
 
 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 @@ static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
        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 @@ static int pxa_gpio_direction_output(struct gpio_chip *chip,
        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 unsigned long GPIO_IRQ_mask[4];
  */
 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 @@ static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
                /* 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 @@ static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
                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);
index 617cab2cc8d0fcd7edb682134d3c10b6b1ca6389..a72869b73ee3a44d638cdd1fe5031d32913787cd 100644 (file)
 #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 */
index 1f2298759077955b35328a2deb70ed2042eca2f8..33626de8cbf65be9ce0b91780708f522941025e1 100644 (file)
@@ -38,6 +38,7 @@ struct gpio_desc {
        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 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c)
        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 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c)
        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 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c)
        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 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c)
                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 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c)
                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 @@ static void __init pxa25x_mfp_init(void)
                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) {}
index 6543321a2df422294982e9acdb9c41e28108a344..0f672998b2eb76e72269b1ca0af3f2722bc0f559 100644 (file)
@@ -298,6 +298,14 @@ void __init pxa25x_init_irq(void)
        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,