Commit 15add068 authored by Thomas Petazzoni's avatar Thomas Petazzoni Committed by Linus Walleij

gpio: pca953x: add ->set_config implementation

This commit adds a minimal implementation of the ->set_config() hook,
with support for the PIN_CONFIG_BIAS_PULL_UP and
PIN_CONFIG_BIAS_PULL_DOWN configurations.
Signed-off-by: default avatarThomas Petazzoni <thomas.petazzoni@bootlin.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent d449991c
...@@ -178,6 +178,8 @@ static int pca953x_bank_shift(struct pca953x_chip *chip) ...@@ -178,6 +178,8 @@ static int pca953x_bank_shift(struct pca953x_chip *chip)
#define PCA957x_BANK_OUTPUT BIT(5) #define PCA957x_BANK_OUTPUT BIT(5)
#define PCAL9xxx_BANK_IN_LATCH BIT(8 + 2) #define PCAL9xxx_BANK_IN_LATCH BIT(8 + 2)
#define PCAL9xxx_BANK_PULL_EN BIT(8 + 3)
#define PCAL9xxx_BANK_PULL_SEL BIT(8 + 4)
#define PCAL9xxx_BANK_IRQ_MASK BIT(8 + 5) #define PCAL9xxx_BANK_IRQ_MASK BIT(8 + 5)
#define PCAL9xxx_BANK_IRQ_STAT BIT(8 + 6) #define PCAL9xxx_BANK_IRQ_STAT BIT(8 + 6)
...@@ -199,6 +201,8 @@ static int pca953x_bank_shift(struct pca953x_chip *chip) ...@@ -199,6 +201,8 @@ static int pca953x_bank_shift(struct pca953x_chip *chip)
* - Extended set, above 0x40, often chip specific. * - Extended set, above 0x40, often chip specific.
* - PCAL6524/PCAL9555A with custom PCAL IRQ handling: * - PCAL6524/PCAL9555A with custom PCAL IRQ handling:
* Input latch register 0x40 + 2 * bank_size RW * Input latch register 0x40 + 2 * bank_size RW
* Pull-up/pull-down enable reg 0x40 + 3 * bank_size RW
* Pull-up/pull-down select reg 0x40 + 4 * bank_size RW
* Interrupt mask register 0x40 + 5 * bank_size RW * Interrupt mask register 0x40 + 5 * bank_size RW
* Interrupt status register 0x40 + 6 * bank_size R * Interrupt status register 0x40 + 6 * bank_size R
* *
...@@ -247,7 +251,8 @@ static bool pca953x_readable_register(struct device *dev, unsigned int reg) ...@@ -247,7 +251,8 @@ static bool pca953x_readable_register(struct device *dev, unsigned int reg)
} }
if (chip->driver_data & PCA_PCAL) { if (chip->driver_data & PCA_PCAL) {
bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_IRQ_MASK | bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_PULL_EN |
PCAL9xxx_BANK_PULL_SEL | PCAL9xxx_BANK_IRQ_MASK |
PCAL9xxx_BANK_IRQ_STAT; PCAL9xxx_BANK_IRQ_STAT;
} }
...@@ -268,7 +273,8 @@ static bool pca953x_writeable_register(struct device *dev, unsigned int reg) ...@@ -268,7 +273,8 @@ static bool pca953x_writeable_register(struct device *dev, unsigned int reg)
} }
if (chip->driver_data & PCA_PCAL) if (chip->driver_data & PCA_PCAL)
bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_IRQ_MASK; bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_PULL_EN |
PCAL9xxx_BANK_PULL_SEL | PCAL9xxx_BANK_IRQ_MASK;
return pca953x_check_register(chip, reg, bank); return pca953x_check_register(chip, reg, bank);
} }
...@@ -473,6 +479,61 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc, ...@@ -473,6 +479,61 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
mutex_unlock(&chip->i2c_lock); mutex_unlock(&chip->i2c_lock);
} }
static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip,
unsigned int offset,
unsigned long config)
{
u8 pull_en_reg = pca953x_recalc_addr(chip, PCAL953X_PULL_EN, offset,
true, false);
u8 pull_sel_reg = pca953x_recalc_addr(chip, PCAL953X_PULL_SEL, offset,
true, false);
u8 bit = BIT(offset % BANK_SZ);
int ret;
/*
* pull-up/pull-down configuration requires PCAL extended
* registers
*/
if (!(chip->driver_data & PCA_PCAL))
return -ENOTSUPP;
mutex_lock(&chip->i2c_lock);
/* Disable pull-up/pull-down */
ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, 0);
if (ret)
goto exit;
/* Configure pull-up/pull-down */
if (config == PIN_CONFIG_BIAS_PULL_UP)
ret = regmap_write_bits(chip->regmap, pull_sel_reg, bit, bit);
else if (config == PIN_CONFIG_BIAS_PULL_DOWN)
ret = regmap_write_bits(chip->regmap, pull_sel_reg, bit, 0);
if (ret)
goto exit;
/* Enable pull-up/pull-down */
ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, bit);
exit:
mutex_unlock(&chip->i2c_lock);
return ret;
}
static int pca953x_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
unsigned long config)
{
struct pca953x_chip *chip = gpiochip_get_data(gc);
switch (config) {
case PIN_CONFIG_BIAS_PULL_UP:
case PIN_CONFIG_BIAS_PULL_DOWN:
return pca953x_gpio_set_pull_up_down(chip, offset, config);
default:
return -ENOTSUPP;
}
}
static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
{ {
struct gpio_chip *gc; struct gpio_chip *gc;
...@@ -485,6 +546,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) ...@@ -485,6 +546,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
gc->set = pca953x_gpio_set_value; gc->set = pca953x_gpio_set_value;
gc->get_direction = pca953x_gpio_get_direction; gc->get_direction = pca953x_gpio_get_direction;
gc->set_multiple = pca953x_gpio_set_multiple; gc->set_multiple = pca953x_gpio_set_multiple;
gc->set_config = pca953x_gpio_set_config;
gc->can_sleep = true; gc->can_sleep = true;
gc->base = chip->gpio_start; gc->base = chip->gpio_start;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment