diff mbox series

[v3,6/7] gpio: exar: switch to using regmap

Message ID 20201110123406.3261-7-brgl@bgdev.pl
State Superseded
Headers show
Series [v3,1/7] gpio: exar: add a newline after the copyright notice | expand

Commit Message

Bartosz Golaszewski Nov. 10, 2020, 12:34 p.m. UTC
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

We can simplify the code in gpio-exar by using regmap. This allows us to
drop the mutex (regmap provides its own locking) and we can also reuse
regmap's bit operations instead of implementing our own update function.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/gpio/Kconfig     |  1 +
 drivers/gpio/gpio-exar.c | 90 +++++++++++++++++-----------------------
 2 files changed, 38 insertions(+), 53 deletions(-)

Comments

Bartosz Golaszewski Nov. 10, 2020, 1:29 p.m. UTC | #1
On Tue, Nov 10, 2020 at 2:23 PM Jan Kiszka <jan.kiszka@siemens.com> wrote:
>
>
> Unfortunately, this one still crashes:
>

Just to confirm: does patch 5/7 alone work?

Bartosz
Andy Shevchenko Nov. 10, 2020, 2:11 p.m. UTC | #2
On Tue, Nov 10, 2020 at 2:35 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

...

>  struct exar_gpio_chip {

>         struct gpio_chip gpio_chip;

> -       struct mutex lock;


> +       struct regmap *regs;


Leaving the same name is a call for potential troubles.

>         int index;

> -       void __iomem *regs;

>         char name[20];

>         unsigned int first_pin;

>  };


...

> +static const struct regmap_config exar_regmap_config = {

> +       .name           = "exar-gpio",

> +       .reg_bits       = 8,

> +       .val_bits       = 8,

> +};


Looking at the crash, are you sure this is a comprehensive description?
Maybe it requires something like stride or so?

-- 
With Best Regards,
Andy Shevchenko
Bartosz Golaszewski Nov. 10, 2020, 2:24 p.m. UTC | #3
On Tue, Nov 10, 2020 at 3:11 PM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
>

> On Tue, Nov 10, 2020 at 2:35 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

>

> ...

>

> >  struct exar_gpio_chip {

> >         struct gpio_chip gpio_chip;

> > -       struct mutex lock;

>

> > +       struct regmap *regs;

>

> Leaving the same name is a call for potential troubles.

>

> >         int index;

> > -       void __iomem *regs;

> >         char name[20];

> >         unsigned int first_pin;

> >  };

>

> ...

>

> > +static const struct regmap_config exar_regmap_config = {

> > +       .name           = "exar-gpio",

> > +       .reg_bits       = 8,

> > +       .val_bits       = 8,

> > +};

>

> Looking at the crash, are you sure this is a comprehensive description?

> Maybe it requires something like stride or so?

>


This is what I'm looking at ATM. Looking at the datasheet[1], there
are no breaks in the registers so the default stride of 1 should be
fine as is the value bits width of 8. I think that I got the address
width wrong though. Should be 16 bits probably.

Jan: could you change reg_bits to 16 and try again?

Bartosz

[1] https://www.maxlinear.com/ds/xr17v352.pdf
Andy Shevchenko Nov. 10, 2020, 2:26 p.m. UTC | #4
On Tue, Nov 10, 2020 at 01:34:05PM +0100, Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

> 

> We can simplify the code in gpio-exar by using regmap. This allows us to

> drop the mutex (regmap provides its own locking) and we can also reuse

> regmap's bit operations instead of implementing our own update function.


...

> +	/*

> +	 * We don't need to check the return values of mmio regmap operations (unless

> +	 * the regmap has a clock attached which is not the case here).

> +	 */

> +	exar_gpio->regs = devm_regmap_init_mmio(dev, p, &exar_regmap_config);

> +	if (IS_ERR(exar_gpio->regs))

> +		return PTR_ERR(exar_gpio->regs);

>  

>  	index = ida_alloc(&ida_index, GFP_KERNEL);

> -	if (index < 0) {

> -		ret = index;

> -		goto err_mutex_destroy;

> -	}

> +	if (index < 0)

> +		return index;


And below you effectively use p as regmap!
That's what renaming of variable regs -> regmap or map can easily reveal.

	exar_gpio->regs = p;


-- 
With Best Regards,
Andy Shevchenko
Andy Shevchenko Nov. 10, 2020, 2:27 p.m. UTC | #5
On Tue, Nov 10, 2020 at 04:26:24PM +0200, Andy Shevchenko wrote:
> On Tue, Nov 10, 2020 at 01:34:05PM +0100, Bartosz Golaszewski wrote:

> > From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

> > 

> > We can simplify the code in gpio-exar by using regmap. This allows us to

> > drop the mutex (regmap provides its own locking) and we can also reuse

> > regmap's bit operations instead of implementing our own update function.

> 

> ...

> 

> > +	/*

> > +	 * We don't need to check the return values of mmio regmap operations (unless

> > +	 * the regmap has a clock attached which is not the case here).

> > +	 */

> > +	exar_gpio->regs = devm_regmap_init_mmio(dev, p, &exar_regmap_config);

> > +	if (IS_ERR(exar_gpio->regs))

> > +		return PTR_ERR(exar_gpio->regs);

> >  

> >  	index = ida_alloc(&ida_index, GFP_KERNEL);

> > -	if (index < 0) {

> > -		ret = index;

> > -		goto err_mutex_destroy;

> > -	}

> > +	if (index < 0)

> > +		return index;

> 

> And below you effectively use p as regmap!

> That's what renaming of variable regs -> regmap or map can easily reveal.

> 

> 	exar_gpio->regs = p;


Jan, if you remove this line, does it help?

-- 
With Best Regards,
Andy Shevchenko
Bartosz Golaszewski Nov. 10, 2020, 2:30 p.m. UTC | #6
On Tue, Nov 10, 2020 at 3:26 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>

> On Tue, Nov 10, 2020 at 04:26:24PM +0200, Andy Shevchenko wrote:

> > On Tue, Nov 10, 2020 at 01:34:05PM +0100, Bartosz Golaszewski wrote:

> > > From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

> > >

> > > We can simplify the code in gpio-exar by using regmap. This allows us to

> > > drop the mutex (regmap provides its own locking) and we can also reuse

> > > regmap's bit operations instead of implementing our own update function.

> >

> > ...

> >

> > > +   /*

> > > +    * We don't need to check the return values of mmio regmap operations (unless

> > > +    * the regmap has a clock attached which is not the case here).

> > > +    */

> > > +   exar_gpio->regs = devm_regmap_init_mmio(dev, p, &exar_regmap_config);

> > > +   if (IS_ERR(exar_gpio->regs))

> > > +           return PTR_ERR(exar_gpio->regs);

> > >

> > >     index = ida_alloc(&ida_index, GFP_KERNEL);

> > > -   if (index < 0) {

> > > -           ret = index;

> > > -           goto err_mutex_destroy;

> > > -   }

> > > +   if (index < 0)

> > > +           return index;

> >

> > And below you effectively use p as regmap!

> > That's what renaming of variable regs -> regmap or map can easily reveal.

> >

> >       exar_gpio->regs = p;

>

> Jan, if you remove this line, does it help?

>


Ha! I guess you were right saying that keeping the name is asking for
trouble then. :)

I think that may be it but address width should still be changed to 16.

Bartosz
Jan Kiszka Nov. 10, 2020, 2:50 p.m. UTC | #7
On 10.11.20 15:30, Bartosz Golaszewski wrote:
> On Tue, Nov 10, 2020 at 3:26 PM Andy Shevchenko

> <andriy.shevchenko@linux.intel.com> wrote:

>>

>> On Tue, Nov 10, 2020 at 04:26:24PM +0200, Andy Shevchenko wrote:

>>> On Tue, Nov 10, 2020 at 01:34:05PM +0100, Bartosz Golaszewski wrote:

>>>> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

>>>>

>>>> We can simplify the code in gpio-exar by using regmap. This allows us to

>>>> drop the mutex (regmap provides its own locking) and we can also reuse

>>>> regmap's bit operations instead of implementing our own update function.

>>>

>>> ...

>>>

>>>> +   /*

>>>> +    * We don't need to check the return values of mmio regmap operations (unless

>>>> +    * the regmap has a clock attached which is not the case here).

>>>> +    */

>>>> +   exar_gpio->regs = devm_regmap_init_mmio(dev, p, &exar_regmap_config);

>>>> +   if (IS_ERR(exar_gpio->regs))

>>>> +           return PTR_ERR(exar_gpio->regs);

>>>>

>>>>     index = ida_alloc(&ida_index, GFP_KERNEL);

>>>> -   if (index < 0) {

>>>> -           ret = index;

>>>> -           goto err_mutex_destroy;

>>>> -   }

>>>> +   if (index < 0)

>>>> +           return index;

>>>

>>> And below you effectively use p as regmap!

>>> That's what renaming of variable regs -> regmap or map can easily reveal.

>>>

>>>       exar_gpio->regs = p;

>>

>> Jan, if you remove this line, does it help?

>>

> 

> Ha! I guess you were right saying that keeping the name is asking for

> trouble then. :)

> 

> I think that may be it but address width should still be changed to 16.

> 


Removing the line that Andy found made things work here. And switching
to 16 for reg_bits didn't make things worse again.

Jan

-- 
Siemens AG, T RDA IOT
Corporate Competence Center Embedded Linux
Bartosz Golaszewski Nov. 10, 2020, 2:52 p.m. UTC | #8
On Tue, Nov 10, 2020 at 3:50 PM Jan Kiszka <jan.kiszka@siemens.com> wrote:
>

>

> On 10.11.20 15:30, Bartosz Golaszewski wrote:

> > On Tue, Nov 10, 2020 at 3:26 PM Andy Shevchenko

> > <andriy.shevchenko@linux.intel.com> wrote:

> >>

> >> On Tue, Nov 10, 2020 at 04:26:24PM +0200, Andy Shevchenko wrote:

> >>> On Tue, Nov 10, 2020 at 01:34:05PM +0100, Bartosz Golaszewski wrote:

> >>>> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

> >>>>

> >>>> We can simplify the code in gpio-exar by using regmap. This allows us to

> >>>> drop the mutex (regmap provides its own locking) and we can also reuse

> >>>> regmap's bit operations instead of implementing our own update function.

> >>>

> >>> ...

> >>>

> >>>> +   /*

> >>>> +    * We don't need to check the return values of mmio regmap operations (unless

> >>>> +    * the regmap has a clock attached which is not the case here).

> >>>> +    */

> >>>> +   exar_gpio->regs = devm_regmap_init_mmio(dev, p, &exar_regmap_config);

> >>>> +   if (IS_ERR(exar_gpio->regs))

> >>>> +           return PTR_ERR(exar_gpio->regs);

> >>>>

> >>>>     index = ida_alloc(&ida_index, GFP_KERNEL);

> >>>> -   if (index < 0) {

> >>>> -           ret = index;

> >>>> -           goto err_mutex_destroy;

> >>>> -   }

> >>>> +   if (index < 0)

> >>>> +           return index;

> >>>

> >>> And below you effectively use p as regmap!

> >>> That's what renaming of variable regs -> regmap or map can easily reveal.

> >>>

> >>>       exar_gpio->regs = p;

> >>

> >> Jan, if you remove this line, does it help?

> >>

> >

> > Ha! I guess you were right saying that keeping the name is asking for

> > trouble then. :)

> >

> > I think that may be it but address width should still be changed to 16.

> >

>

> Removing the line that Andy found made things work here. And switching

> to 16 for reg_bits didn't make things worse again.

>

> Jan


Alright! I'll send a v4 with these things fixed then.

Bartosz
Andy Shevchenko Nov. 10, 2020, 3:01 p.m. UTC | #9
On Tue, Nov 10, 2020 at 03:52:00PM +0100, Bartosz Golaszewski wrote:
> On Tue, Nov 10, 2020 at 3:50 PM Jan Kiszka <jan.kiszka@siemens.com> wrote:

> > On 10.11.20 15:30, Bartosz Golaszewski wrote:


...

> > Removing the line that Andy found made things work here. And switching

> > to 16 for reg_bits didn't make things worse again.

> >

> > Jan

> 

> Alright! I'll send a v4 with these things fixed then.


Hold on, the registers are 16-bit wide, but their halves are sparsed!
So, I guess 8 and 8 with helpers to get hi and lo parts are essential.


-- 
With Best Regards,
Andy Shevchenko
diff mbox series

Patch

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 5d4de5cd6759..253a61ec9645 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -255,6 +255,7 @@  config GPIO_EP93XX
 config GPIO_EXAR
 	tristate "Support for GPIO pins on XR17V352/354/358"
 	depends on SERIAL_8250_EXAR
+	select REGMAP_MMIO
 	help
 	  Selecting this option will enable handling of GPIO pins present
 	  on Exar XR17V352/354/358 chips.
diff --git a/drivers/gpio/gpio-exar.c b/drivers/gpio/gpio-exar.c
index 28b0b4b5fa35..a2d324c513f8 100644
--- a/drivers/gpio/gpio-exar.c
+++ b/drivers/gpio/gpio-exar.c
@@ -14,6 +14,7 @@ 
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 
 #define EXAR_OFFSET_MPIOLVL_LO 0x90
 #define EXAR_OFFSET_MPIOSEL_LO 0x93
@@ -26,9 +27,8 @@  static DEFINE_IDA(ida_index);
 
 struct exar_gpio_chip {
 	struct gpio_chip gpio_chip;
-	struct mutex lock;
+	struct regmap *regs;
 	int index;
-	void __iomem *regs;
 	char name[20];
 	unsigned int first_pin;
 };
@@ -53,51 +53,13 @@  exar_offset_to_bit(struct exar_gpio_chip *exar_gpio, unsigned int offset)
 	return (offset + exar_gpio->first_pin) % 8;
 }
 
-static void exar_update(struct gpio_chip *chip, unsigned int reg, int val,
-			unsigned int offset)
-{
-	struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
-	int temp;
-
-	mutex_lock(&exar_gpio->lock);
-	temp = readb(exar_gpio->regs + reg);
-	temp &= ~BIT(offset);
-	if (val)
-		temp |= BIT(offset);
-	writeb(temp, exar_gpio->regs + reg);
-	mutex_unlock(&exar_gpio->lock);
-}
-
-static int exar_set_direction(struct gpio_chip *chip, int direction,
-			      unsigned int offset)
-{
-	struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
-	unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset);
-	unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
-
-	exar_update(chip, addr, direction, bit);
-	return 0;
-}
-
-static int exar_get(struct gpio_chip *chip, unsigned int reg)
-{
-	struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
-	int value;
-
-	mutex_lock(&exar_gpio->lock);
-	value = readb(exar_gpio->regs + reg);
-	mutex_unlock(&exar_gpio->lock);
-
-	return value;
-}
-
 static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
 {
 	struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
 	unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset);
 	unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
 
-	if (exar_get(chip, addr) & BIT(bit))
+	if (regmap_test_bits(exar_gpio->regs, addr, BIT(bit)))
 		return GPIO_LINE_DIRECTION_IN;
 
 	return GPIO_LINE_DIRECTION_OUT;
@@ -109,7 +71,7 @@  static int exar_get_value(struct gpio_chip *chip, unsigned int offset)
 	unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset);
 	unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
 
-	return !!(exar_get(chip, addr) & BIT(bit));
+	return !!(regmap_test_bits(exar_gpio->regs, addr, BIT(bit)));
 }
 
 static void exar_set_value(struct gpio_chip *chip, unsigned int offset,
@@ -119,21 +81,42 @@  static void exar_set_value(struct gpio_chip *chip, unsigned int offset,
 	unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset);
 	unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
 
-	exar_update(chip, addr, value, bit);
+	if (value)
+		regmap_set_bits(exar_gpio->regs, addr, BIT(bit));
+	else
+		regmap_clear_bits(exar_gpio->regs, addr, BIT(bit));
 }
 
 static int exar_direction_output(struct gpio_chip *chip, unsigned int offset,
 				 int value)
 {
+	struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
+	unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset);
+	unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
+
 	exar_set_value(chip, offset, value);
-	return exar_set_direction(chip, 0, offset);
+	regmap_clear_bits(exar_gpio->regs, addr, BIT(bit));
+
+	return 0;
 }
 
 static int exar_direction_input(struct gpio_chip *chip, unsigned int offset)
 {
-	return exar_set_direction(chip, 1, offset);
+	struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
+	unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset);
+	unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
+
+	regmap_set_bits(exar_gpio->regs, addr, BIT(bit));
+
+	return 0;
 }
 
+static const struct regmap_config exar_regmap_config = {
+	.name		= "exar-gpio",
+	.reg_bits	= 8,
+	.val_bits	= 8,
+};
+
 static int gpio_exar_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -163,13 +146,17 @@  static int gpio_exar_probe(struct platform_device *pdev)
 	if (!exar_gpio)
 		return -ENOMEM;
 
-	mutex_init(&exar_gpio->lock);
+	/*
+	 * We don't need to check the return values of mmio regmap operations (unless
+	 * the regmap has a clock attached which is not the case here).
+	 */
+	exar_gpio->regs = devm_regmap_init_mmio(dev, p, &exar_regmap_config);
+	if (IS_ERR(exar_gpio->regs))
+		return PTR_ERR(exar_gpio->regs);
 
 	index = ida_alloc(&ida_index, GFP_KERNEL);
-	if (index < 0) {
-		ret = index;
-		goto err_mutex_destroy;
-	}
+	if (index < 0)
+		return index;
 
 	sprintf(exar_gpio->name, "exar_gpio%d", index);
 	exar_gpio->gpio_chip.label = exar_gpio->name;
@@ -195,8 +182,6 @@  static int gpio_exar_probe(struct platform_device *pdev)
 
 err_destroy:
 	ida_free(&ida_index, index);
-err_mutex_destroy:
-	mutex_destroy(&exar_gpio->lock);
 	return ret;
 }
 
@@ -205,7 +190,6 @@  static int gpio_exar_remove(struct platform_device *pdev)
 	struct exar_gpio_chip *exar_gpio = platform_get_drvdata(pdev);
 
 	ida_free(&ida_index, exar_gpio->index);
-	mutex_destroy(&exar_gpio->lock);
 
 	return 0;
 }