[U-Boot] [UBOOT PATCH 1/1] gpio: lpc32xx: fix issues with port3 gpio

slemieux.tyco at gmail.com slemieux.tyco at gmail.com
Wed Sep 9 13:40:25 CEST 2015


From: Sylvain Lemieux <slemieux at tycoint.com>

The current simplify lpc32xx gpio driver implementation assume a
maximum of 32 GPIO per port; there are a total of 22 GPI, 24 GPO
and 6 GPIO to managed on port 3.

Update the driver to fix the following:
1) When requesting GPI_xx and GPO_xx on port 3 (xx is the same number)
   the second call to "gpio_request" will return -EBUSY.

2) The status of GPO_xx pin report the status of the
   corresponding GPI_xx pin when using the "gpio status" command.

3) The gpio driver may setup the direction register for the wrong
   gpio when calling "gpio_direction_input" (GPI_xx) or
   "gpio_direction_output" (GPO_xx) on port 3; the call to the
   direction is require to use the "gpio status" command.

The following change were done in the driver:
1) port3 GPI are cache in a separate 32 bits in the array.
2) port3 direction register written only for GPIO pins.
3) port3 GPO & GPIO (as output) are read using "p3_outp_state".
4) LPC32XX_GPI_P3_GRP updated to match the change.

Signed-off-by: Sylvain Lemieux <slemieux at tycoint.com>
---
To reproduce the issues, the following test can be execute:
1) Add to source code:
   int ret1 = gpio_request(LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 19), "GPO_19");
   int ret2 = gpio_request(LPC32XX_GPIO(LPC32XX_GPI_P3_GRP, 19), "GPI_19");

   The second call return "-EBUSY".

2) Setup a logical 0 on GPI_19 pin
   --> gpio set 115
   gpio: pin 115 (gpio 115) value is 1

   --> gpio status
   115: output: 0 [x] GPO_19

   Setup a logic 1 on GPI_19 pin
   --> gpio clear115
   gpio: pin 115 (gpio 115) value is 0

   --> gpio status
   115: output: 1 [x] GPO_19

3) Add to source code: 
   (void)gpio_request(LPC32XX_GPIO(LPC32XX_GPI_P3_GRP, 25), "GPI_25");

   --> gpio status
   121: unknown

   Add to source code:
   (void)gpio_request(LPC32XX_GPIO(LPC32XX_GPI_P3_GRP, 25), "GPI_25");
   (void)gpio_direction_input(LPC32XX_GPIO(LPC32XX_GPI_P3_GRP, 25));

   --> gpio status
   121: input: 0 [x] GPI_25

   The direction register is written and GPIO_0 is configured as input.

Note:
I am sending the patch using <slemieux.tyco at gmail.com>,
until I can submit patch using my regular e-mail <slemieux at tycoint.com>.

 arch/arm/include/asm/arch-lpc32xx/gpio_grp.h |  4 +--
 drivers/gpio/lpc32xx_gpio.c                  | 41 ++++++++++++++++++++++++----
 2 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/arch/arm/include/asm/arch-lpc32xx/gpio_grp.h b/arch/arm/include/asm/arch-lpc32xx/gpio_grp.h
index aa85337..3cc8a37 100644
--- a/arch/arm/include/asm/arch-lpc32xx/gpio_grp.h
+++ b/arch/arm/include/asm/arch-lpc32xx/gpio_grp.h
@@ -12,7 +12,7 @@
 
 /* 
  * Macro to map the pin for the lpc32xx_gpio driver.
- * Note: - GPIOS are considered here as homogeneous and linear, from 0 to 127;
+ * Note: - GPIOS are considered here as homogeneous and linear from 0 to 159;
  *         mapping is done per register, as group of 32.
  *         (see drivers/gpio/lpc32xx_gpio.c for details).
  *       - macros can be use with the following pins:
@@ -26,9 +26,9 @@
 #define LPC32XX_GPIO_P0_GRP 0
 #define LPC32XX_GPIO_P1_GRP 32
 #define LPC32XX_GPIO_P2_GRP 64
-#define LPC32XX_GPI_P3_GRP  96
 #define LPC32XX_GPO_P3_GRP  96
 #define LPC32XX_GPIO_P3_GRP (LPC32XX_GPO_P3_GRP + 25)
+#define LPC32XX_GPI_P3_GRP  128
 
 /*
  * A specific GPIO can be selected with this macro
diff --git a/drivers/gpio/lpc32xx_gpio.c b/drivers/gpio/lpc32xx_gpio.c
index 8a9826e..9674ee7 100644
--- a/drivers/gpio/lpc32xx_gpio.c
+++ b/drivers/gpio/lpc32xx_gpio.c
@@ -22,7 +22,7 @@
  *   read on another one.
 *
  * In order to keep this code simple, GPIOS are considered here as
- * homogeneous and linear, from 0 to 127.
+ * homogeneous and linear, from 0 to 159.
  *
  *	** WARNING #1 **
  *
@@ -35,7 +35,7 @@
  * Please read NOTE in description of lpc32xx_gpio_get_function().
  */
 
-#define LPC32XX_GPIOS 128
+#define LPC32XX_GPIOS 160
 
 struct lpc32xx_gpio_priv {
 	struct gpio_regs *regs;
@@ -45,11 +45,18 @@ struct lpc32xx_gpio_priv {
 
 /**
  * We have 4 GPIO ports of 32 bits each
+ *
+ * Port mapping offset (32 bits each):
+ * - Port 0: 0
+ * - Port 1: 32
+ * - Port 2: 64
+ * - Port 3: GPO / GPIO (output): 96
+ * - Port 3: GPI: 128
  */
 
-#define MAX_GPIO 128
+#define MAX_GPIO 160
 
-#define GPIO_TO_PORT(gpio) ((gpio / 32) & 3)
+#define GPIO_TO_PORT(gpio) ((gpio / 32) & 7)
 #define GPIO_TO_RANK(gpio) (gpio % 32)
 #define GPIO_TO_MASK(gpio) (1 << (gpio % 32))
 
@@ -75,9 +82,16 @@ static int lpc32xx_gpio_direction_input(struct udevice *dev, unsigned offset)
 		break;
 	case 2:
 		/* ports 2 and 3 share a common direction */
-	case 3:
 		writel(mask, &regs->p2_p3_dir_clr);
 		break;
+	case 3:
+		/* Setup direction only for GPIO_xx. */
+		if ((mask >= 25) && (mask <= 30))
+			writel(mask, &regs->p2_p3_dir_clr);
+		break;
+	case 4:
+		/* GPI_xx; nothing to do. */
+		break;
 	default:
 		return -1;
 	}
@@ -111,6 +125,11 @@ static int lpc32xx_gpio_get_value(struct udevice *dev, unsigned offset)
 		value = readl(&regs->p2_inp_state);
 		break;
 	case 3:
+		/* Read GPO_xx and GPIO_xx (as output) using p3_outp_state. */
+		value = readl(&regs->p3_outp_state);
+		break;
+	case 4:
+		/* Read GPI_xx and GPIO_xx (as input) using p3_inp_state. */
 		value = readl(&regs->p3_inp_state);
 		break;
 	default:
@@ -149,6 +168,8 @@ static int gpio_set(struct udevice *dev, unsigned gpio)
 	case 3:
 		writel(mask, &regs->p3_outp_set);
 		break;
+	case 4:
+		/* GPI_xx; invalid. */
 	default:
 		return -1;
 	}
@@ -181,6 +202,8 @@ static int gpio_clr(struct udevice *dev, unsigned gpio)
 	case 3:
 		writel(mask, &regs->p3_outp_clr);
 		break;
+	case 4:
+		/* GPI_xx; invalid. */
 	default:
 		return -1;
 	}
@@ -223,9 +246,15 @@ static int lpc32xx_gpio_direction_output(struct udevice *dev, unsigned offset,
 		break;
 	case 2:
 		/* ports 2 and 3 share a common direction */
-	case 3:
 		writel(mask, &regs->p2_p3_dir_set);
 		break;
+	case 3:
+		/* Setup direction only for GPIO_xx. */
+		if ((mask >= 25) && (mask <= 30))
+			writel(mask, &regs->p2_p3_dir_set);
+		break;
+	case 4:
+		/* GPI_xx; invalid. */
 	default:
 		return -1;
 	}
-- 
1.8.3.1



More information about the U-Boot mailing list