Skip to content

Commit 82039d2

Browse files
srelinusw
authored andcommitted
pinctrl: mcp23s08: add pinconf support
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@collabora.co.uk> Tested-by: Enric Balletbo i Serra <enric.balletbo@collabora.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
1 parent 64ac43e commit 82039d2

File tree

2 files changed

+176
-24
lines changed

2 files changed

+176
-24
lines changed

drivers/pinctrl/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ config PINCTRL_MCP23S08
153153
select GPIOLIB_IRQCHIP
154154
select REGMAP_I2C if I2C
155155
select REGMAP_SPI if SPI_MASTER
156+
select GENERIC_PINCONF
156157
help
157158
SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017
158159
I/O expanders.

drivers/pinctrl/pinctrl-mcp23s08.c

Lines changed: 175 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
#include <linux/of_irq.h>
2525
#include <linux/of_device.h>
2626
#include <linux/regmap.h>
27+
#include <linux/pinctrl/pinctrl.h>
28+
#include <linux/pinctrl/pinconf.h>
29+
#include <linux/pinctrl/pinconf-generic.h>
2730

2831
/**
2932
* MCP types supported by driver
@@ -77,6 +80,9 @@ struct mcp23s08 {
7780

7881
struct regmap *regmap;
7982
struct device *dev;
83+
84+
struct pinctrl_dev *pctldev;
85+
struct pinctrl_desc pinctrl_desc;
8086
};
8187

8288
static const struct regmap_config mcp23x08_regmap = {
@@ -96,6 +102,158 @@ static const struct regmap_config mcp23x17_regmap = {
96102
.val_format_endian = REGMAP_ENDIAN_LITTLE,
97103
};
98104

105+
static int mcp_read(struct mcp23s08 *mcp, unsigned int reg, unsigned int *val)
106+
{
107+
return regmap_read(mcp->regmap, reg << mcp->reg_shift, val);
108+
}
109+
110+
static int mcp_write(struct mcp23s08 *mcp, unsigned int reg, unsigned int val)
111+
{
112+
return regmap_write(mcp->regmap, reg << mcp->reg_shift, val);
113+
}
114+
115+
static int mcp_set_bit(struct mcp23s08 *mcp, unsigned int reg,
116+
unsigned int pin, bool enabled)
117+
{
118+
u16 val = enabled ? 0xffff : 0x0000;
119+
u16 mask = BIT(pin);
120+
return regmap_update_bits(mcp->regmap, reg << mcp->reg_shift,
121+
mask, val);
122+
}
123+
124+
static int mcp_update_cache(struct mcp23s08 *mcp)
125+
{
126+
int ret, reg, i;
127+
128+
for (i = 0; i < ARRAY_SIZE(mcp->cache); i++) {
129+
ret = mcp_read(mcp, i, &reg);
130+
if (ret < 0)
131+
return ret;
132+
mcp->cache[i] = reg;
133+
}
134+
135+
return 0;
136+
}
137+
138+
static const struct pinctrl_pin_desc mcp23x08_pins[] = {
139+
PINCTRL_PIN(0, "gpio0"),
140+
PINCTRL_PIN(1, "gpio1"),
141+
PINCTRL_PIN(2, "gpio2"),
142+
PINCTRL_PIN(3, "gpio3"),
143+
PINCTRL_PIN(4, "gpio4"),
144+
PINCTRL_PIN(5, "gpio5"),
145+
PINCTRL_PIN(6, "gpio6"),
146+
PINCTRL_PIN(7, "gpio7"),
147+
};
148+
149+
static const struct pinctrl_pin_desc mcp23x17_pins[] = {
150+
PINCTRL_PIN(0, "gpio0"),
151+
PINCTRL_PIN(1, "gpio1"),
152+
PINCTRL_PIN(2, "gpio2"),
153+
PINCTRL_PIN(3, "gpio3"),
154+
PINCTRL_PIN(4, "gpio4"),
155+
PINCTRL_PIN(5, "gpio5"),
156+
PINCTRL_PIN(6, "gpio6"),
157+
PINCTRL_PIN(7, "gpio7"),
158+
PINCTRL_PIN(8, "gpio8"),
159+
PINCTRL_PIN(9, "gpio9"),
160+
PINCTRL_PIN(10, "gpio10"),
161+
PINCTRL_PIN(11, "gpio11"),
162+
PINCTRL_PIN(12, "gpio12"),
163+
PINCTRL_PIN(13, "gpio13"),
164+
PINCTRL_PIN(14, "gpio14"),
165+
PINCTRL_PIN(15, "gpio15"),
166+
};
167+
168+
static int mcp_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
169+
{
170+
return 0;
171+
}
172+
173+
static const char *mcp_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
174+
unsigned int group)
175+
{
176+
return NULL;
177+
}
178+
179+
static int mcp_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
180+
unsigned int group,
181+
const unsigned int **pins,
182+
unsigned int *num_pins)
183+
{
184+
return -ENOTSUPP;
185+
}
186+
187+
static const struct pinctrl_ops mcp_pinctrl_ops = {
188+
.get_groups_count = mcp_pinctrl_get_groups_count,
189+
.get_group_name = mcp_pinctrl_get_group_name,
190+
.get_group_pins = mcp_pinctrl_get_group_pins,
191+
#ifdef CONFIG_OF
192+
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
193+
.dt_free_map = pinconf_generic_dt_free_map,
194+
#endif
195+
};
196+
197+
static int mcp_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
198+
unsigned long *config)
199+
{
200+
struct mcp23s08 *mcp = pinctrl_dev_get_drvdata(pctldev);
201+
enum pin_config_param param = pinconf_to_config_param(*config);
202+
unsigned int data, status;
203+
int ret;
204+
205+
switch (param) {
206+
case PIN_CONFIG_BIAS_PULL_UP:
207+
ret = mcp_read(mcp, MCP_GPPU, &data);
208+
if (ret < 0)
209+
return ret;
210+
status = (data & BIT(pin)) ? 1 : 0;
211+
break;
212+
default:
213+
dev_err(mcp->dev, "Invalid config param %04x\n", param);
214+
return -ENOTSUPP;
215+
}
216+
217+
*config = 0;
218+
219+
return status ? 0 : -EINVAL;
220+
}
221+
222+
static int mcp_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
223+
unsigned long *configs, unsigned int num_configs)
224+
{
225+
struct mcp23s08 *mcp = pinctrl_dev_get_drvdata(pctldev);
226+
enum pin_config_param param;
227+
u32 arg, mask;
228+
u16 val;
229+
int ret = 0;
230+
int i;
231+
232+
for (i = 0; i < num_configs; i++) {
233+
param = pinconf_to_config_param(configs[i]);
234+
arg = pinconf_to_config_argument(configs[i]);
235+
236+
switch (param) {
237+
case PIN_CONFIG_BIAS_PULL_UP:
238+
val = arg ? 0xFFFF : 0x0000;
239+
mask = BIT(pin);
240+
ret = mcp_set_bit(mcp, MCP_GPPU, pin, arg);
241+
break;
242+
default:
243+
dev_err(mcp->dev, "Invalid config param %04x\n", param);
244+
return -ENOTSUPP;
245+
}
246+
}
247+
248+
return ret;
249+
}
250+
251+
static const struct pinconf_ops mcp_pinconf_ops = {
252+
.pin_config_get = mcp_pinconf_get,
253+
.pin_config_set = mcp_pinconf_set,
254+
.is_generic = true,
255+
};
256+
99257
/*----------------------------------------------------------------------*/
100258

101259
#ifdef CONFIG_SPI_MASTER
@@ -158,30 +316,6 @@ static const struct regmap_bus mcp23sxx_spi_regmap = {
158316

159317
#endif /* CONFIG_SPI_MASTER */
160318

161-
static int mcp_read(struct mcp23s08 *mcp, unsigned int reg, unsigned int *val)
162-
{
163-
return regmap_read(mcp->regmap, reg << mcp->reg_shift, val);
164-
}
165-
166-
static int mcp_write(struct mcp23s08 *mcp, unsigned int reg, unsigned int val)
167-
{
168-
return regmap_write(mcp->regmap, reg << mcp->reg_shift, val);
169-
}
170-
171-
static int mcp_update_cache(struct mcp23s08 *mcp)
172-
{
173-
int ret, reg, i;
174-
175-
for (i = 0; i < ARRAY_SIZE(mcp->cache); i++) {
176-
ret = mcp_read(mcp, i, &reg);
177-
if (ret < 0)
178-
return ret;
179-
mcp->cache[i] = reg;
180-
}
181-
182-
return 0;
183-
}
184-
185319
/*----------------------------------------------------------------------*/
186320

187321
/* 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,
682816
if (ret)
683817
goto fail;
684818
}
819+
820+
mcp->pinctrl_desc.name = "mcp23xxx-pinctrl";
821+
mcp->pinctrl_desc.pctlops = &mcp_pinctrl_ops;
822+
mcp->pinctrl_desc.confops = &mcp_pinconf_ops;
823+
mcp->pinctrl_desc.npins = mcp->chip.ngpio;
824+
if (mcp->pinctrl_desc.npins == 8)
825+
mcp->pinctrl_desc.pins = mcp23x08_pins;
826+
else if (mcp->pinctrl_desc.npins == 16)
827+
mcp->pinctrl_desc.pins = mcp23x17_pins;
828+
mcp->pinctrl_desc.owner = THIS_MODULE;
829+
830+
mcp->pctldev = devm_pinctrl_register(dev, &mcp->pinctrl_desc, mcp);
831+
if (IS_ERR(mcp->pctldev)) {
832+
ret = PTR_ERR(mcp->pctldev);
833+
goto fail;
834+
}
835+
685836
fail:
686837
if (ret < 0)
687838
dev_dbg(dev, "can't setup chip %d, --> %d\n", addr, ret);

0 commit comments

Comments
 (0)