Skip to contentSkip to conversation

gpio-mpc8xxx: add mpc8xxx_gpio_set_multiple function

PATCH Superseded Rojhalat Ibrahim 2 participants 3 messages Jun 2, 2014 – Jun 7, 2014 GPIO

v4 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

PATCH v4 2/2 gpio-mpc8xxx: add mpc8xxx_gpio_set_multiple function

Add a set_multiple function to the MPC8xxx GPIO chip driver and thereby allow for actual performance improvements when setting multiple outputs simultaneously. In my case the time needed to configure an FPGA goes down from 48 s to 20 s.

---
This patch depends on my previous patch "gpiolib: allow simultaneous setting of multiple GPIO outputs".

Change log:
v4: - change interface of the set_multiple driver function to use
unsigned long as type for the bit fields
- use generic bitops (which also use unsigned long for bit fields)
v3: - change commit message
v2: - add this patch (v1 included only changes to gpiolib)

 drivers/gpio/gpio-mpc8xxx.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
drivers/gpio/gpio-mpc8xxx.c +27 -0
index d7d6d72..d1ff879 100644
@@ -105,6 +105,32 @@ static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
 	spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
 }
 
+static void mpc8xxx_gpio_set_multiple(struct gpio_chip *gc,
+				      unsigned long *mask, unsigned long *bits)
+{
+	struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
+	struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+
+	for (i = 0; i < gc->ngpio; i++) {
+		if (*mask == 0)
+			break;
+		if (__test_and_clear_bit(i, mask)) {
+			if (test_bit(i, bits))
+				mpc8xxx_gc->data |= mpc8xxx_gpio2mask(i);
+			else
+				mpc8xxx_gc->data &= ~mpc8xxx_gpio2mask(i);
+		}
+	}
+
+	out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data);
+
+	spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+}
+
 static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
 {
 	struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
@@ -344,6 +370,7 @@ static void __init mpc8xxx_add_controller(struct device_node *np)
 	gc->get = of_device_is_compatible(np, "fsl,mpc8572-gpio") ?
 		mpc8572_gpio_get : mpc8xxx_gpio_get;
 	gc->set = mpc8xxx_gpio_set;
+	gc->set_multiple = mpc8xxx_gpio_set_multiple;
 	gc->to_irq = mpc8xxx_gpio_to_irq;
 
 	ret = of_mm_gpiochip_add(np, mm_gc);

--
1.8.5.5

#1 lore raw
Quoted 31 lines · Rojhalat Ibrahim

Add a set_multiple function to the MPC8xxx GPIO chip driver and thereby allow for actual performance improvements when setting multiple outputs simultaneously. In my case the time needed to configure an FPGA goes down from 48 s to 20 s.

---
This patch depends on my previous patch "gpiolib: allow simultaneous setting of multiple GPIO outputs".

Change log:
v4: - change interface of the set_multiple driver function to use
unsigned long as type for the bit fields
- use generic bitops (which also use unsigned long for bit fields)
v3: - change commit message
v2: - add this patch (v1 included only changes to gpiolib)

 drivers/gpio/gpio-mpc8xxx.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
drivers/gpio/gpio-mpc8xxx.c +3 -0
index d7d6d72..d1ff879 100644
@@ -105,6 +105,32 @@ static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
        spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
 }
 
+static void mpc8xxx_gpio_set_multiple(struct gpio_chip *gc,
+                                     unsigned long *mask, unsigned long *bits)
+{

drivers/gpio/gpio-mpc8xxx.c static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) · line 120

Quoted 10 lines
drivers/gpio/gpio-mpc8xxx.c +10 -0
+       struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+
+       for (i = 0; i < gc->ngpio; i++) {
+               if (*mask == 0)
+                       break;

Ok, so this works because presentely you can only have 32 GPIOs max on this chip. But you cannot be sure that future revisions won't extend that number ; and if this happens this function won't work as-is anymore. I won't take much more code to make it more generic, so please do it now to avoid hours of horrendous debugging to your future self.

Quoted 27 lines
drivers/gpio/gpio-mpc8xxx.c +14 -1
+               if (__test_and_clear_bit(i, mask)) {
+                       if (test_bit(i, bits))
+                               mpc8xxx_gc->data |= mpc8xxx_gpio2mask(i);
+                       else
+                               mpc8xxx_gc->data &= ~mpc8xxx_gpio2mask(i);
+               }
+       }
+
+       out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data);
+
+       spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+}
+
 static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
 {
        struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
@@ -344,6 +370,7 @@ static void __init mpc8xxx_add_controller(struct device_node *np)
        gc->get = of_device_is_compatible(np, "fsl,mpc8572-gpio") ?
                mpc8572_gpio_get : mpc8xxx_gpio_get;
        gc->set = mpc8xxx_gpio_set;
+       gc->set_multiple = mpc8xxx_gpio_set_multiple;
        gc->to_irq = mpc8xxx_gpio_to_irq;
 
        ret = of_mm_gpiochip_add(np, mm_gc);
 
--

1.8.5.5

Reviewed-by
#2 lore raw
Quoted 41 lines · Alexandre Courbot
Quoted 40 lines · Rojhalat Ibrahim

Add a set_multiple function to the MPC8xxx GPIO chip driver and thereby allow for actual performance improvements when setting multiple outputs simultaneously. In my case the time needed to configure an FPGA goes down from 48 s to 20 s.

---
This patch depends on my previous patch "gpiolib: allow simultaneous setting of multiple GPIO outputs".

Change log:
v4: - change interface of the set_multiple driver function to use
unsigned long as type for the bit fields
- use generic bitops (which also use unsigned long for bit fields)
v3: - change commit message
v2: - add this patch (v1 included only changes to gpiolib)

 drivers/gpio/gpio-mpc8xxx.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
drivers/gpio/gpio-mpc8xxx.c +12 -0
index d7d6d72..d1ff879 100644
@@ -105,6 +105,32 @@ static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
        spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
 }
 
+static void mpc8xxx_gpio_set_multiple(struct gpio_chip *gc,
+                                     unsigned long *mask, unsigned long *bits)
+{
+       struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+
+       for (i = 0; i < gc->ngpio; i++) {
+               if (*mask == 0)
Quoted 8 lines

drivers/gpio/gpio-mpc8xxx.c static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) · line 120

Quoted 1 line
drivers/gpio/gpio-mpc8xxx.c +1 -0
+                       break;

Ok, so this works because presentely you can only have 32 GPIOs max on this chip. But you cannot be sure that future revisions won't extend that number ; and if this happens this function won't work as-is anymore. I won't take much more code to make it more generic, so please do it now to avoid hours of horrendous debugging to your future self.

Looking at it twice you only have one data register, so there is probably not much you can do for the moment - please ignore my previous comment.