Message ID | 20201104193051.32236-8-brgl@bgdev.pl |
---|---|
State | New |
Headers | show |
Series | [v2,1/8] regmap: provide regmap_assign_bits() | expand |
On Wed, Nov 4, 2020 at 9:34 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote: ... > +static const struct regmap_config exar_regmap_config = { > + .name = "exar-gpio", > + .reg_bits = 8, > + .val_bits = 8, > +}; Looking at gpio-pca953xx regmap conversion I'm wondering shouldn't you provide a callback to define volatile registers (such as GPIO input bits)? -- With Best Regards, Andy Shevchenko
On Wed, Nov 4, 2020 at 9:35 PM Andy Shevchenko <andy.shevchenko@gmail.com> wrote: > > On Wed, Nov 4, 2020 at 9:34 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote: > > ... > > > +static const struct regmap_config exar_regmap_config = { > > + .name = "exar-gpio", > > + .reg_bits = 8, > > + .val_bits = 8, > > +}; > > Looking at gpio-pca953xx regmap conversion I'm wondering shouldn't you > provide a callback to define volatile registers (such as GPIO input > bits)? > > -- > With Best Regards, > Andy Shevchenko I think this was done in pca953x due to weird calculations of banks and registers. For a rather simple driver like this one I don't think this is needed. Bartosz
On Wed, Nov 04, 2020 at 08:30:50PM +0100, Bartosz Golaszewski wrote: > @@ -119,21 +81,39 @@ 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); > + regmap_assign_bits(exar_gpio->regs, addr, BIT(bit), value); > } This appears to be the use of _assign_bits() and TBH I'm still both having a hard time understanding the motivation for it and liking the name, especially since AFAICT it's only setting a single bit here. The above is just regmap_update_bits(exar_gpio->regs, addr, 1 << bit, value << bit); AFAICT (and indeed now I dig around assign_bit() only works on a single bit and does both shifts which makes the correspondance with that interface super unclear, we're not mirroring that interface here). If you're trying to clone the bitops function it should probably be an actual clone of the bitops function not something different, that would be clearer and it'd be easier to understand why someone would want the API in the first place. But perhaps I'm missing something here?
On Thu, Nov 5, 2020 at 6:41 PM Mark Brown <broonie@kernel.org> wrote: > > On Wed, Nov 04, 2020 at 08:30:50PM +0100, Bartosz Golaszewski wrote: > > > @@ -119,21 +81,39 @@ 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); > > + regmap_assign_bits(exar_gpio->regs, addr, BIT(bit), value); > > } > > This appears to be the use of _assign_bits() and TBH I'm still both > having a hard time understanding the motivation for it and liking the > name, especially since AFAICT it's only setting a single bit here. The > above is just > > regmap_update_bits(exar_gpio->regs, addr, 1 << bit, value << bit); > > AFAICT (and indeed now I dig around assign_bit() only works on a single > bit and does both shifts which makes the correspondance with that > interface super unclear, we're not mirroring that interface here). If > you're trying to clone the bitops function it should probably be an > actual clone of the bitops function not something different, that would > be clearer and it'd be easier to understand why someone would want the > API in the first place. But perhaps I'm missing something here? It's true that bitops set/clear/assign bit macros work on single bits and take their offsets as arguments. However all regmap helpers operate on masks. Two release cycles back we added two helpers regmap_set_bits() and regmap_clear_bits() which are just wrappers around regmap_update_bits(). The naming was inspired by bitops (because how would one name these operations differently anyway?) but it was supposed to be able to clear/set multiple bits at once - at least this was my use-case in mtk-star-emac driver I was writing at the time and for which I wrote these helpers. Now the regmap_assign_bits() helper is just an extension to these two which allows users to use one line instead of four. I'm not trying to clone bitops - it's just that I don't have a better idea for the naming. Bartosz
On Fri, Nov 06, 2020 at 12:13:55PM +0100, Bartosz Golaszewski wrote: > On Thu, Nov 5, 2020 at 6:41 PM Mark Brown <broonie@kernel.org> wrote: > > AFAICT (and indeed now I dig around assign_bit() only works on a single > > bit and does both shifts which makes the correspondance with that > > interface super unclear, we're not mirroring that interface here). If > > you're trying to clone the bitops function it should probably be an > > actual clone of the bitops function not something different, that would > > be clearer and it'd be easier to understand why someone would want the > > API in the first place. But perhaps I'm missing something here? > It's true that bitops set/clear/assign bit macros work on single bits > and take their offsets as arguments. However all regmap helpers > operate on masks. Two release cycles back we added two helpers > regmap_set_bits() and regmap_clear_bits() which are just wrappers > around regmap_update_bits(). The naming was inspired by bitops > (because how would one name these operations differently anyway?) but > it was supposed to be able to clear/set multiple bits at once - at > least this was my use-case in mtk-star-emac driver I was writing at > the time and for which I wrote these helpers. Which is fine and not at all unclear since there's no separate value argument, the value comes along with the name. > Now the regmap_assign_bits() helper is just an extension to these two > which allows users to use one line instead of four. I'm not trying to > clone bitops - it's just that I don't have a better idea for the > naming. I really don't see the benefit to the helper, it makes sense in the context of bitops where the operation does all the shifting and it's only a single bit but for regmap where it's dealing with bitmasks as well and the naming doesn't make it crystal clear I can only see this being confusing to people. Had the set and clear helpers for regmap been done as single bits it'd be a lot easier but that's not the case and it'd also be odd to have just this one helper that took a shift rather than a bitmask.
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..94ef500567ef 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,39 @@ 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); + regmap_assign_bits(exar_gpio->regs, addr, BIT(bit), value); } 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 +143,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 +179,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 +187,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; }