Skip to content

Commit

Permalink
gpio: exar: switch to using regmap
Browse files Browse the repository at this point in the history
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>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
  • Loading branch information
Bartosz Golaszewski committed Nov 25, 2020
1 parent 696868d commit 36fb721
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 54 deletions.
1 change: 1 addition & 0 deletions drivers/gpio/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
91 changes: 37 additions & 54 deletions drivers/gpio/gpio-exar.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -26,9 +27,8 @@ static DEFINE_IDA(ida_index);

struct exar_gpio_chip {
struct gpio_chip gpio_chip;
struct mutex lock;
struct regmap *regmap;
int index;
void __iomem *regs;
char name[20];
unsigned int first_pin;
};
Expand All @@ -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->regmap, addr, BIT(bit)))
return GPIO_LINE_DIRECTION_IN;

return GPIO_LINE_DIRECTION_OUT;
Expand All @@ -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->regmap, addr, BIT(bit)));
}

static void exar_set_value(struct gpio_chip *chip, unsigned int offset,
Expand All @@ -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->regmap, addr, BIT(bit));
else
regmap_clear_bits(exar_gpio->regmap, 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->regmap, 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->regmap, addr, BIT(bit));

return 0;
}

static const struct regmap_config exar_regmap_config = {
.name = "exar-gpio",
.reg_bits = 16,
.val_bits = 8,
};

static int gpio_exar_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
Expand Down Expand Up @@ -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->regmap = devm_regmap_init_mmio(dev, p, &exar_regmap_config);
if (IS_ERR(exar_gpio->regmap))
return PTR_ERR(exar_gpio->regmap);

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;
Expand All @@ -181,7 +168,6 @@ static int gpio_exar_probe(struct platform_device *pdev)
exar_gpio->gpio_chip.set = exar_set_value;
exar_gpio->gpio_chip.base = -1;
exar_gpio->gpio_chip.ngpio = ngpios;
exar_gpio->regs = p;
exar_gpio->index = index;
exar_gpio->first_pin = first_pin;

Expand All @@ -195,8 +181,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;
}

Expand All @@ -205,7 +189,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;
}
Expand Down

0 comments on commit 36fb721

Please sign in to comment.