Patchwork mpc52xx_gpio: support MPC52xx simple interrupt GPIO

login
register
mail settings
Submitter Roman Fietze
Date July 7, 2010, 11:32 a.m.
Message ID <201007071332.38754.roman.fietze@telemotive.de>
Download mbox | patch
Permalink /patch/58103/
State Not Applicable
Delegated to: Anatolij Gustschin
Headers show

Comments

Roman Fietze - July 7, 2010, 11:32 a.m.
Hello Sascha, hello List Members,

I could not find a way to access the MPC5200(B) simple interrupt pins
using the 52xx platform GPIO driver. So I added the simple interrupt
pins when the mpc5200-gpio is probed. Is there something I overlooked?
If not, here's the patch.


From 749b58686384275d253eeca8f3f0bd7a12daebe2 Mon Sep 17 00:00:00 2001
From: Roman Fietze <roman.fietze@telemotive.de>
Date: Wed, 7 Jul 2010 13:21:12 +0200
Subject: [PATCH] mpc52xx_gpio: support MPC52xx simple interrupt GPIO

Add two OF GPIO chips when probing fsl,mpc5200-gpio, one for the 32
simple GPIO pins and one for the 8 simple interrupt GPIO pins.

The current order of driver registrations will cause the simple
interrupt GPIO pin numbers be below the ones of the simple GPIO pins,
so current code will not have to be changed, except if there are more
GPIO pins with dynamic pin numbers registered after the platform
driver.

Signed-off-by: Roman Fietze <roman.fietze@telemotive.de>
---
 arch/powerpc/platforms/52xx/mpc52xx_gpio.c |  128 
+++++++++++++++++++++++++++-
 1 files changed, 126 insertions(+), 2 deletions(-)

+static int __devinit mpc52xx_simple_sint_gpiochip_probe(struct of_device 
*ofdev,
 					const struct of_device_id *match)
 {
 	struct mpc52xx_gpiochip *chip;
@@ -316,6 +416,7 @@ static int __devinit mpc52xx_simple_gpiochip_probe(struct 
of_device *ofdev,
 	struct mpc52xx_gpio __iomem *regs;
 	int ret;
 
+	/* simple GPIO */
 	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
 	if (!chip)
 		return -ENOMEM;
@@ -338,6 +439,29 @@ static int __devinit mpc52xx_simple_gpiochip_probe(struct 
of_device *ofdev,
 	chip->shadow_ddr = in_be32(&regs->simple_ddr);
 	chip->shadow_dvo = in_be32(&regs->simple_dvo);
 
+	/* simple interrupt GPIO */
+	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	ofchip = &chip->mmchip.of_gc;
+
+	ofchip->gpio_cells          = 2;
+	ofchip->gc.ngpio            = 8;
+	ofchip->gc.direction_input  = mpc52xx_sint_gpio_dir_in;
+	ofchip->gc.direction_output = mpc52xx_sint_gpio_dir_out;
+	ofchip->gc.get              = mpc52xx_sint_gpio_get;
+	ofchip->gc.set              = mpc52xx_sint_gpio_set;
+
+	ret = of_mm_gpiochip_add(ofdev->node, &chip->mmchip);
+	if (ret)
+		return ret;
+
+	regs = chip->mmchip.regs;
+	chip->shadow_gpioe = in_8(&regs->sint_gpioe);
+	chip->shadow_ddr = in_8(&regs->sint_ddr);
+	chip->shadow_dvo = in_8(&regs->sint_dvo);
+
 	return 0;
 }
 
@@ -351,7 +475,7 @@ static const struct of_device_id 
mpc52xx_simple_gpiochip_match[] = {
 static struct of_platform_driver mpc52xx_simple_gpiochip_driver = {
 	.name = "gpio",
 	.match_table = mpc52xx_simple_gpiochip_match,
-	.probe = mpc52xx_simple_gpiochip_probe,
+	.probe = mpc52xx_simple_sint_gpiochip_probe,
 	.remove = mpc52xx_gpiochip_remove,
 };

Patch

diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpio.c 
b/arch/powerpc/platforms/52xx/mpc52xx_gpio.c
index fda7c2a..d0a9fce 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_gpio.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_gpio.c
@@ -308,7 +308,107 @@  mpc52xx_simple_gpio_dir_out(struct gpio_chip *gc, 
unsigned int gpio, int val)
 	return 0;
 }
 
-static int __devinit mpc52xx_simple_gpiochip_probe(struct of_device *ofdev,
+/*
+ * GPIO LIB API implementation for simple interrupt GPIOs
+ *
+ * There's a maximum of 8 simple interrupt GPIOs. Which of these are
+ * available for use depends on your board setup.  The numbering
+ * reflects the bit numbering in the port registers:
+ *
+ *  0.. 3 > ETH_16..ETH_13
+ *  4     > USB1_9
+ *  5     > PSC3_8
+ *  6.. 7 > PSC3_5..PSC3_4
+ */
+static int mpc52xx_sint_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+	struct mpc52xx_gpio __iomem *regs = mm_gc->regs;
+	unsigned int ret;
+
+	ret = (in_8(&regs->sint_ival) >> (7 - gpio)) & 1;
+
+	return ret;
+}
+
+static inline void
+__mpc52xx_sint_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+	struct mpc52xx_gpiochip *chip = container_of(mm_gc,
+						     struct mpc52xx_gpiochip, 
mmchip);
+	struct mpc52xx_gpio __iomem *regs = mm_gc->regs;
+
+	if (val)
+		chip->shadow_dvo |= 1 << (7 - gpio);
+	else
+		chip->shadow_dvo &= ~(1 << (7 - gpio));
+	out_8(&regs->sint_dvo, chip->shadow_dvo);
+}
+
+static void
+mpc52xx_sint_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&gpio_lock, flags);
+
+	__mpc52xx_sint_gpio_set(gc, gpio, val);
+
+	spin_unlock_irqrestore(&gpio_lock, flags);
+}
+
+static int mpc52xx_sint_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+	struct mpc52xx_gpiochip *chip = container_of(mm_gc,
+						     struct mpc52xx_gpiochip, 
mmchip);
+	struct mpc52xx_gpio __iomem *regs = mm_gc->regs;
+	unsigned long flags;
+
+	spin_lock_irqsave(&gpio_lock, flags);
+
+	/* set the direction */
+	chip->shadow_ddr &= ~(1 << (7 - gpio));
+	out_8(&regs->sint_ddr, chip->shadow_ddr);
+
+	/* and enable the pin */
+	chip->shadow_gpioe |= 1 << (7 - gpio);
+	out_8(&regs->sint_gpioe, chip->shadow_gpioe);
+
+	spin_unlock_irqrestore(&gpio_lock, flags);
+
+	return 0;
+}
+
+static int
+mpc52xx_sint_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+	struct mpc52xx_gpiochip *chip = container_of(mm_gc,
+						     struct mpc52xx_gpiochip, 
mmchip);
+	struct mpc52xx_gpio __iomem *regs = mm_gc->regs;
+	unsigned long flags;
+
+	spin_lock_irqsave(&gpio_lock, flags);
+
+	/* First set initial value */
+	__mpc52xx_sint_gpio_set(gc, gpio, val);
+
+	/* Then set direction */
+	chip->shadow_ddr |= 1 << (7 - gpio);
+	out_8(&regs->sint_ddr, chip->shadow_ddr);
+
+	/* Finally enable the pin */
+	chip->shadow_gpioe |= 1 << (7 - gpio);
+	out_8(&regs->sint_gpioe, chip->shadow_gpioe);
+
+	spin_unlock_irqrestore(&gpio_lock, flags);
+
+	return 0;
+}
+