Adds support for setting mcp23s08 pins to output-high or output-low via pinmux in the device tree. Signed-off-by: Tomaz Solc <tomaz.solc@xxxxxxxxxx> --- .../bindings/pinctrl/pinctrl-mcp23s08.txt | 12 ++-- drivers/pinctrl/pinctrl-mcp23s08.c | 58 ++++++++++++++----- 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-mcp23s08.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-mcp23s08.txt index 2fa5edac7a35..483ac9f719a1 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-mcp23s08.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-mcp23s08.txt @@ -88,11 +88,11 @@ gpiom1: gpio@0 { spi-max-frequency = <1000000>; }; -Pull-up configuration -===================== +Pin configuration +================= -If pins are used as output, they can also be configured with pull-ups. This is -done with pinctrl. +If pins are used as inputs, they can also be configured with pull-ups. Pins +used as outputs can have their default states set. This is done with pinctrl. Please refer file <devicetree/bindings/pinctrl/pinctrl-bindings.txt> for details of the common pinctrl bindings used by client devices, @@ -121,8 +121,10 @@ The following optional property is defined in the pinmux DT binding document <pinctrl-bindings.txt>. Absence of this property will leave the configuration in its default state. bias-pull-up + output-high + output-low -Example with pinctrl to pull-up output pins: +Example with pinctrl to pull-up input pins: gpio21: gpio@21 { compatible = "microchip,mcp23017"; gpio-controller; diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c index 764c93dfd277..81fc7fcef8ec 100644 --- a/drivers/pinctrl/pinctrl-mcp23s08.c +++ b/drivers/pinctrl/pinctrl-mcp23s08.c @@ -159,6 +159,26 @@ static int mcp_set_bit(struct mcp23s08 *mcp, unsigned int reg, return mcp_set_mask(mcp, reg, mask, enabled); } +static int __mcp23s08_set(struct mcp23s08 *mcp, unsigned mask, bool value) +{ + return mcp_set_mask(mcp, MCP_OLAT, mask, value); +} + +static int mcp_direction_output(struct mcp23s08 *mcp, unsigned offset, + int value) +{ + unsigned mask = BIT(offset); + int status; + + mutex_lock(&mcp->lock); + status = __mcp23s08_set(mcp, mask, value); + if (status == 0) { + status = mcp_set_mask(mcp, MCP_IODIR, mask, false); + } + mutex_unlock(&mcp->lock); + return status; +} + static const struct pinctrl_pin_desc mcp23x08_pins[] = { PINCTRL_PIN(0, "gpio0"), PINCTRL_PIN(1, "gpio1"), @@ -225,6 +245,7 @@ static int mcp_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, enum pin_config_param param = pinconf_to_config_param(*config); unsigned int data, status; int ret; + u16 arg; switch (param) { case PIN_CONFIG_BIAS_PULL_UP: @@ -232,12 +253,28 @@ static int mcp_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, if (ret < 0) return ret; status = (data & BIT(pin)) ? 1 : 0; + arg = 1; + break; + case PIN_CONFIG_OUTPUT: + ret = mcp_read(mcp, MCP_IODIR, &data); + if (ret < 0) { + return ret; + } + + status = (data & BIT(pin)) ? 0 : 1; + + ret = mcp_read(mcp, MCP_OLAT, &data); + if (ret < 0) { + return ret; + } + + arg = (data & BIT(pin)) ? 1 : 0; break; default: return -ENOTSUPP; } - *config = 0; + *config = pinconf_to_config_packed(param, arg); return status ? 0 : -EINVAL; } @@ -259,6 +296,9 @@ static int mcp_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, case PIN_CONFIG_BIAS_PULL_UP: ret = mcp_set_bit(mcp, MCP_GPPU, pin, arg); break; + case PIN_CONFIG_OUTPUT: + ret = mcp_direction_output(mcp, pin, arg); + break; default: dev_dbg(mcp->dev, "Invalid config param %04x\n", param); return -ENOTSUPP; @@ -308,11 +348,6 @@ static int mcp23s08_get(struct gpio_chip *chip, unsigned offset) return status; } -static int __mcp23s08_set(struct mcp23s08 *mcp, unsigned mask, bool value) -{ - return mcp_set_mask(mcp, MCP_OLAT, mask, value); -} - static void mcp23s08_set(struct gpio_chip *chip, unsigned offset, int value) { struct mcp23s08 *mcp = gpiochip_get_data(chip); @@ -327,16 +362,7 @@ static int mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value) { struct mcp23s08 *mcp = gpiochip_get_data(chip); - unsigned mask = BIT(offset); - int status; - - mutex_lock(&mcp->lock); - status = __mcp23s08_set(mcp, mask, value); - if (status == 0) { - status = mcp_set_mask(mcp, MCP_IODIR, mask, false); - } - mutex_unlock(&mcp->lock); - return status; + return mcp_direction_output(mcp, offset, value); } static int -- 2.20.1