Hi, On Mon, May 15, 2017 at 11:24:26AM +0200, Sebastian Reichel wrote: > mcp23xxx device have configurable 100k pullup resistors. This adds > support for enabling them using pinctrl's pinconf interface. > > Signed-off-by: Sebastian Reichel <sebastian.reichel@xxxxxxxxxxxxxxx> I just noticed, that I forgot to add: Tested-by: Enric Balletbo i Serra <enric.balletbo@xxxxxxxxxxxxx> -- Sebastian > --- > drivers/pinctrl/Kconfig | 1 + > drivers/pinctrl/pinctrl-mcp23s08.c | 199 ++++++++++++++++++++++++++++++++----- > 2 files changed, 176 insertions(+), 24 deletions(-) > > diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig > index b5aa50c51633..1dabd1d79c1d 100644 > --- a/drivers/pinctrl/Kconfig > +++ b/drivers/pinctrl/Kconfig > @@ -153,6 +153,7 @@ config PINCTRL_MCP23S08 > select GPIOLIB_IRQCHIP > select REGMAP_I2C if I2C > select REGMAP_SPI if SPI_MASTER > + select GENERIC_PINCONF > help > SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017 > I/O expanders. > diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c > index 2a57d024481d..d957c4bbc8c1 100644 > --- a/drivers/pinctrl/pinctrl-mcp23s08.c > +++ b/drivers/pinctrl/pinctrl-mcp23s08.c > @@ -24,6 +24,9 @@ > #include <linux/of_irq.h> > #include <linux/of_device.h> > #include <linux/regmap.h> > +#include <linux/pinctrl/pinctrl.h> > +#include <linux/pinctrl/pinconf.h> > +#include <linux/pinctrl/pinconf-generic.h> > > /** > * MCP types supported by driver > @@ -77,6 +80,9 @@ struct mcp23s08 { > > struct regmap *regmap; > struct device *dev; > + > + struct pinctrl_dev *pctldev; > + struct pinctrl_desc pinctrl_desc; > }; > > static const struct regmap_config mcp23x08_regmap = { > @@ -96,6 +102,158 @@ static const struct regmap_config mcp23x17_regmap = { > .val_format_endian = REGMAP_ENDIAN_LITTLE, > }; > > +static int mcp_read(struct mcp23s08 *mcp, unsigned int reg, unsigned int *val) > +{ > + return regmap_read(mcp->regmap, reg << mcp->reg_shift, val); > +} > + > +static int mcp_write(struct mcp23s08 *mcp, unsigned int reg, unsigned int val) > +{ > + return regmap_write(mcp->regmap, reg << mcp->reg_shift, val); > +} > + > +static int mcp_set_bit(struct mcp23s08 *mcp, unsigned int reg, > + unsigned int pin, bool enabled) > +{ > + u16 val = enabled ? 0xffff : 0x0000; > + u16 mask = BIT(pin); > + return regmap_update_bits(mcp->regmap, reg << mcp->reg_shift, > + mask, val); > +} > + > +static int mcp_update_cache(struct mcp23s08 *mcp) > +{ > + int ret, reg, i; > + > + for (i = 0; i < ARRAY_SIZE(mcp->cache); i++) { > + ret = mcp_read(mcp, i, ®); > + if (ret < 0) > + return ret; > + mcp->cache[i] = reg; > + } > + > + return 0; > +} > + > +static const struct pinctrl_pin_desc mcp23x08_pins[] = { > + PINCTRL_PIN(0, "gpio0"), > + PINCTRL_PIN(1, "gpio1"), > + PINCTRL_PIN(2, "gpio2"), > + PINCTRL_PIN(3, "gpio3"), > + PINCTRL_PIN(4, "gpio4"), > + PINCTRL_PIN(5, "gpio5"), > + PINCTRL_PIN(6, "gpio6"), > + PINCTRL_PIN(7, "gpio7"), > +}; > + > +static const struct pinctrl_pin_desc mcp23x17_pins[] = { > + PINCTRL_PIN(0, "gpio0"), > + PINCTRL_PIN(1, "gpio1"), > + PINCTRL_PIN(2, "gpio2"), > + PINCTRL_PIN(3, "gpio3"), > + PINCTRL_PIN(4, "gpio4"), > + PINCTRL_PIN(5, "gpio5"), > + PINCTRL_PIN(6, "gpio6"), > + PINCTRL_PIN(7, "gpio7"), > + PINCTRL_PIN(8, "gpio8"), > + PINCTRL_PIN(9, "gpio9"), > + PINCTRL_PIN(10, "gpio10"), > + PINCTRL_PIN(11, "gpio11"), > + PINCTRL_PIN(12, "gpio12"), > + PINCTRL_PIN(13, "gpio13"), > + PINCTRL_PIN(14, "gpio14"), > + PINCTRL_PIN(15, "gpio15"), > +}; > + > +static int mcp_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) > +{ > + return 0; > +} > + > +static const char *mcp_pinctrl_get_group_name(struct pinctrl_dev *pctldev, > + unsigned int group) > +{ > + return NULL; > +} > + > +static int mcp_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, > + unsigned int group, > + const unsigned int **pins, > + unsigned int *num_pins) > +{ > + return -ENOTSUPP; > +} > + > +static const struct pinctrl_ops mcp_pinctrl_ops = { > + .get_groups_count = mcp_pinctrl_get_groups_count, > + .get_group_name = mcp_pinctrl_get_group_name, > + .get_group_pins = mcp_pinctrl_get_group_pins, > +#ifdef CONFIG_OF > + .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, > + .dt_free_map = pinconf_generic_dt_free_map, > +#endif > +}; > + > +static int mcp_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, > + unsigned long *config) > +{ > + struct mcp23s08 *mcp = pinctrl_dev_get_drvdata(pctldev); > + enum pin_config_param param = pinconf_to_config_param(*config); > + unsigned int data, status; > + int ret; > + > + switch (param) { > + case PIN_CONFIG_BIAS_PULL_UP: > + ret = mcp_read(mcp, MCP_GPPU, &data); > + if (ret < 0) > + return ret; > + status = (data & BIT(pin)) ? 1 : 0; > + break; > + default: > + dev_err(mcp->dev, "Invalid config param %04x\n", param); > + return -ENOTSUPP; > + } > + > + *config = 0; > + > + return status ? 0 : -EINVAL; > +} > + > +static int mcp_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, > + unsigned long *configs, unsigned int num_configs) > +{ > + struct mcp23s08 *mcp = pinctrl_dev_get_drvdata(pctldev); > + enum pin_config_param param; > + u32 arg, mask; > + u16 val; > + int ret = 0; > + int i; > + > + for (i = 0; i < num_configs; i++) { > + param = pinconf_to_config_param(configs[i]); > + arg = pinconf_to_config_argument(configs[i]); > + > + switch (param) { > + case PIN_CONFIG_BIAS_PULL_UP: > + val = arg ? 0xFFFF : 0x0000; > + mask = BIT(pin); > + ret = mcp_set_bit(mcp, MCP_GPPU, pin, arg); > + break; > + default: > + dev_err(mcp->dev, "Invalid config param %04x\n", param); > + return -ENOTSUPP; > + } > + } > + > + return ret; > +} > + > +static const struct pinconf_ops mcp_pinconf_ops = { > + .pin_config_get = mcp_pinconf_get, > + .pin_config_set = mcp_pinconf_set, > + .is_generic = true, > +}; > + > /*----------------------------------------------------------------------*/ > > #ifdef CONFIG_SPI_MASTER > @@ -158,30 +316,6 @@ static const struct regmap_bus mcp23sxx_spi_regmap = { > > #endif /* CONFIG_SPI_MASTER */ > > -static int mcp_read(struct mcp23s08 *mcp, unsigned int reg, unsigned int *val) > -{ > - return regmap_read(mcp->regmap, reg << mcp->reg_shift, val); > -} > - > -static int mcp_write(struct mcp23s08 *mcp, unsigned int reg, unsigned int val) > -{ > - return regmap_write(mcp->regmap, reg << mcp->reg_shift, val); > -} > - > -static int mcp_update_cache(struct mcp23s08 *mcp) > -{ > - int ret, reg, i; > - > - for (i = 0; i < ARRAY_SIZE(mcp->cache); i++) { > - ret = mcp_read(mcp, i, ®); > - if (ret < 0) > - return ret; > - mcp->cache[i] = reg; > - } > - > - return 0; > -} > - > /*----------------------------------------------------------------------*/ > > /* A given spi_device can represent up to eight mcp23sxx chips > @@ -682,6 +816,23 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, > if (ret) > goto fail; > } > + > + mcp->pinctrl_desc.name = "mcp23xxx-pinctrl"; > + mcp->pinctrl_desc.pctlops = &mcp_pinctrl_ops; > + mcp->pinctrl_desc.confops = &mcp_pinconf_ops; > + mcp->pinctrl_desc.npins = mcp->chip.ngpio; > + if (mcp->pinctrl_desc.npins == 8) > + mcp->pinctrl_desc.pins = mcp23x08_pins; > + else if (mcp->pinctrl_desc.npins == 16) > + mcp->pinctrl_desc.pins = mcp23x17_pins; > + mcp->pinctrl_desc.owner = THIS_MODULE; > + > + mcp->pctldev = devm_pinctrl_register(dev, &mcp->pinctrl_desc, mcp); > + if (IS_ERR(mcp->pctldev)) { > + ret = PTR_ERR(mcp->pctldev); > + goto fail; > + } > + > fail: > if (ret < 0) > dev_dbg(dev, "can't setup chip %d, --> %d\n", addr, ret); > -- > 2.11.0 >
Attachment:
signature.asc
Description: PGP signature