]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/pinctrl/pinctrl-axp209.c
pinctrl: axp209: add programmable ADC muxing value
[mirror_ubuntu-jammy-kernel.git] / drivers / pinctrl / pinctrl-axp209.c
CommitLineData
f72f4b44 1/*
23f75d7d 2 * AXP20x pinctrl and GPIO driver
f72f4b44
MR
3 *
4 * Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com>
23f75d7d 5 * Copyright (C) 2017 Quentin Schulz <quentin.schulz@free-electrons.com>
f72f4b44
MR
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12
13#include <linux/bitops.h>
14#include <linux/device.h>
15#include <linux/gpio/driver.h>
16#include <linux/init.h>
17#include <linux/interrupt.h>
18#include <linux/kernel.h>
19#include <linux/mfd/axp20x.h>
20#include <linux/module.h>
21#include <linux/of.h>
23f75d7d
QS
22#include <linux/pinctrl/pinconf-generic.h>
23#include <linux/pinctrl/pinctrl.h>
24#include <linux/pinctrl/pinmux.h>
f72f4b44
MR
25#include <linux/platform_device.h>
26#include <linux/regmap.h>
27#include <linux/slab.h>
28
29#define AXP20X_GPIO_FUNCTIONS 0x7
30#define AXP20X_GPIO_FUNCTION_OUT_LOW 0
31#define AXP20X_GPIO_FUNCTION_OUT_HIGH 1
32#define AXP20X_GPIO_FUNCTION_INPUT 2
33
23f75d7d
QS
34#define AXP20X_FUNC_GPIO_OUT 0
35#define AXP20X_FUNC_GPIO_IN 1
36#define AXP20X_FUNC_LDO 2
37#define AXP20X_FUNC_ADC 3
38#define AXP20X_FUNCS_NB 4
39
40#define AXP20X_MUX_GPIO_OUT 0
41#define AXP20X_MUX_GPIO_IN BIT(1)
42#define AXP20X_MUX_ADC BIT(2)
43
44struct axp20x_pctrl_desc {
45 const struct pinctrl_pin_desc *pins;
46 unsigned int npins;
47 /* Stores the pins supporting LDO function. Bit offset is pin number. */
48 u8 ldo_mask;
49 /* Stores the pins supporting ADC function. Bit offset is pin number. */
50 u8 adc_mask;
48e706fb 51 u8 gpio_status_offset;
a0a4b4c2 52 u8 adc_mux;
23f75d7d
QS
53};
54
55struct axp20x_pinctrl_function {
56 const char *name;
57 unsigned int muxval;
58 const char **groups;
59 unsigned int ngroups;
60};
61
d242e60c 62struct axp20x_pctl {
f72f4b44
MR
63 struct gpio_chip chip;
64 struct regmap *regmap;
23f75d7d
QS
65 struct pinctrl_dev *pctl_dev;
66 struct device *dev;
67 const struct axp20x_pctrl_desc *desc;
68 struct axp20x_pinctrl_function funcs[AXP20X_FUNCS_NB];
69};
70
71static const struct pinctrl_pin_desc axp209_pins[] = {
72 PINCTRL_PIN(0, "GPIO0"),
73 PINCTRL_PIN(1, "GPIO1"),
74 PINCTRL_PIN(2, "GPIO2"),
75};
76
77static const struct axp20x_pctrl_desc axp20x_data = {
78 .pins = axp209_pins,
79 .npins = ARRAY_SIZE(axp209_pins),
80 .ldo_mask = BIT(0) | BIT(1),
81 .adc_mask = BIT(0) | BIT(1),
48e706fb 82 .gpio_status_offset = 4,
a0a4b4c2 83 .adc_mux = AXP20X_MUX_ADC,
f72f4b44
MR
84};
85
3cac991e 86static int axp20x_gpio_get_reg(unsigned int offset)
f72f4b44
MR
87{
88 switch (offset) {
89 case 0:
90 return AXP20X_GPIO0_CTRL;
91 case 1:
92 return AXP20X_GPIO1_CTRL;
93 case 2:
94 return AXP20X_GPIO2_CTRL;
95 }
96
97 return -EINVAL;
98}
99
3cac991e 100static int axp20x_gpio_input(struct gpio_chip *chip, unsigned int offset)
f72f4b44 101{
23f75d7d 102 return pinctrl_gpio_direction_input(chip->base + offset);
f72f4b44
MR
103}
104
3cac991e 105static int axp20x_gpio_get(struct gpio_chip *chip, unsigned int offset)
f72f4b44 106{
d242e60c 107 struct axp20x_pctl *pctl = gpiochip_get_data(chip);
f72f4b44 108 unsigned int val;
1d2b2ac0 109 int ret;
f72f4b44 110
d242e60c 111 ret = regmap_read(pctl->regmap, AXP20X_GPIO20_SS, &val);
f72f4b44
MR
112 if (ret)
113 return ret;
114
48e706fb 115 return !!(val & BIT(offset + pctl->desc->gpio_status_offset));
f72f4b44
MR
116}
117
3cac991e
QS
118static int axp20x_gpio_get_direction(struct gpio_chip *chip,
119 unsigned int offset)
81d3753d 120{
d242e60c 121 struct axp20x_pctl *pctl = gpiochip_get_data(chip);
81d3753d
MR
122 unsigned int val;
123 int reg, ret;
124
125 reg = axp20x_gpio_get_reg(offset);
126 if (reg < 0)
127 return reg;
128
d242e60c 129 ret = regmap_read(pctl->regmap, reg, &val);
81d3753d
MR
130 if (ret)
131 return ret;
132
133 /*
134 * This shouldn't really happen if the pin is in use already,
135 * or if it's not in use yet, it doesn't matter since we're
136 * going to change the value soon anyway. Default to output.
137 */
138 if ((val & AXP20X_GPIO_FUNCTIONS) > 2)
139 return 0;
140
141 /*
142 * The GPIO directions are the three lowest values.
143 * 2 is input, 0 and 1 are output
144 */
145 return val & 2;
146}
147
3cac991e 148static int axp20x_gpio_output(struct gpio_chip *chip, unsigned int offset,
f72f4b44 149 int value)
23f75d7d
QS
150{
151 chip->set(chip, offset, value);
152
153 return 0;
154}
155
156static void axp20x_gpio_set(struct gpio_chip *chip, unsigned int offset,
157 int value)
f72f4b44 158{
d242e60c 159 struct axp20x_pctl *pctl = gpiochip_get_data(chip);
f72f4b44
MR
160 int reg;
161
23f75d7d
QS
162 reg = axp20x_gpio_get_reg(offset);
163 if (reg < 0)
164 return;
165
d242e60c 166 regmap_update_bits(pctl->regmap, reg,
23f75d7d
QS
167 AXP20X_GPIO_FUNCTIONS,
168 value ? AXP20X_GPIO_FUNCTION_OUT_HIGH :
169 AXP20X_GPIO_FUNCTION_OUT_LOW);
170}
171
172static int axp20x_pmx_set(struct pinctrl_dev *pctldev, unsigned int offset,
173 u8 config)
174{
d242e60c 175 struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
23f75d7d
QS
176 int reg;
177
f72f4b44
MR
178 reg = axp20x_gpio_get_reg(offset);
179 if (reg < 0)
180 return reg;
181
d242e60c 182 return regmap_update_bits(pctl->regmap, reg, AXP20X_GPIO_FUNCTIONS,
23f75d7d 183 config);
f72f4b44
MR
184}
185
23f75d7d
QS
186static int axp20x_pmx_func_cnt(struct pinctrl_dev *pctldev)
187{
d242e60c 188 struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
23f75d7d 189
d242e60c 190 return ARRAY_SIZE(pctl->funcs);
23f75d7d
QS
191}
192
193static const char *axp20x_pmx_func_name(struct pinctrl_dev *pctldev,
194 unsigned int selector)
195{
d242e60c 196 struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
23f75d7d 197
d242e60c 198 return pctl->funcs[selector].name;
23f75d7d
QS
199}
200
201static int axp20x_pmx_func_groups(struct pinctrl_dev *pctldev,
202 unsigned int selector,
203 const char * const **groups,
204 unsigned int *num_groups)
205{
d242e60c 206 struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
23f75d7d 207
d242e60c
QS
208 *groups = pctl->funcs[selector].groups;
209 *num_groups = pctl->funcs[selector].ngroups;
23f75d7d
QS
210
211 return 0;
212}
213
214static int axp20x_pmx_set_mux(struct pinctrl_dev *pctldev,
215 unsigned int function, unsigned int group)
216{
d242e60c 217 struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
23f75d7d
QS
218 unsigned int mask;
219
220 /* Every pin supports GPIO_OUT and GPIO_IN functions */
221 if (function <= AXP20X_FUNC_GPIO_IN)
222 return axp20x_pmx_set(pctldev, group,
d242e60c 223 pctl->funcs[function].muxval);
23f75d7d
QS
224
225 if (function == AXP20X_FUNC_LDO)
d242e60c 226 mask = pctl->desc->ldo_mask;
23f75d7d 227 else
d242e60c 228 mask = pctl->desc->adc_mask;
23f75d7d
QS
229
230 if (!(BIT(group) & mask))
231 return -EINVAL;
232
233 /*
234 * We let the regulator framework handle the LDO muxing as muxing bits
235 * are basically also regulators on/off bits. It's better not to enforce
236 * any state of the regulator when selecting LDO mux so that we don't
237 * interfere with the regulator driver.
238 */
239 if (function == AXP20X_FUNC_LDO)
240 return 0;
241
d242e60c 242 return axp20x_pmx_set(pctldev, group, pctl->funcs[function].muxval);
23f75d7d
QS
243}
244
245static int axp20x_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
246 struct pinctrl_gpio_range *range,
247 unsigned int offset, bool input)
248{
d242e60c 249 struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
23f75d7d
QS
250
251 if (input)
252 return axp20x_pmx_set(pctldev, offset,
d242e60c 253 pctl->funcs[AXP20X_FUNC_GPIO_IN].muxval);
23f75d7d
QS
254
255 return axp20x_pmx_set(pctldev, offset,
d242e60c 256 pctl->funcs[AXP20X_FUNC_GPIO_OUT].muxval);
23f75d7d
QS
257}
258
259static const struct pinmux_ops axp20x_pmx_ops = {
260 .get_functions_count = axp20x_pmx_func_cnt,
261 .get_function_name = axp20x_pmx_func_name,
262 .get_function_groups = axp20x_pmx_func_groups,
263 .set_mux = axp20x_pmx_set_mux,
264 .gpio_set_direction = axp20x_pmx_gpio_set_direction,
265 .strict = true,
266};
267
268static int axp20x_groups_cnt(struct pinctrl_dev *pctldev)
269{
d242e60c 270 struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
23f75d7d 271
d242e60c 272 return pctl->desc->npins;
23f75d7d
QS
273}
274
275static int axp20x_group_pins(struct pinctrl_dev *pctldev, unsigned int selector,
276 const unsigned int **pins, unsigned int *num_pins)
277{
d242e60c 278 struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
23f75d7d 279
d242e60c 280 *pins = (unsigned int *)&pctl->desc->pins[selector];
23f75d7d
QS
281 *num_pins = 1;
282
283 return 0;
284}
285
286static const char *axp20x_group_name(struct pinctrl_dev *pctldev,
287 unsigned int selector)
f72f4b44 288{
d242e60c 289 struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
23f75d7d 290
d242e60c 291 return pctl->desc->pins[selector].name;
23f75d7d
QS
292}
293
294static const struct pinctrl_ops axp20x_pctrl_ops = {
295 .dt_node_to_map = pinconf_generic_dt_node_to_map_group,
296 .dt_free_map = pinconf_generic_dt_free_map,
297 .get_groups_count = axp20x_groups_cnt,
298 .get_group_name = axp20x_group_name,
299 .get_group_pins = axp20x_group_pins,
300};
301
302static void axp20x_funcs_groups_from_mask(struct device *dev, unsigned int mask,
303 unsigned int mask_len,
304 struct axp20x_pinctrl_function *func,
305 const struct pinctrl_pin_desc *pins)
306{
307 unsigned long int mask_cpy = mask;
308 const char **group;
309 unsigned int ngroups = hweight8(mask);
310 int bit;
311
312 func->ngroups = ngroups;
313 if (func->ngroups > 0) {
314 func->groups = devm_kzalloc(dev, ngroups * sizeof(const char *),
315 GFP_KERNEL);
316 group = func->groups;
317 for_each_set_bit(bit, &mask_cpy, mask_len) {
318 *group = pins[bit].name;
319 group++;
320 }
321 }
322}
323
324static void axp20x_build_funcs_groups(struct platform_device *pdev)
325{
d242e60c
QS
326 struct axp20x_pctl *pctl = platform_get_drvdata(pdev);
327 int i, pin, npins = pctl->desc->npins;
328
329 pctl->funcs[AXP20X_FUNC_GPIO_OUT].name = "gpio_out";
330 pctl->funcs[AXP20X_FUNC_GPIO_OUT].muxval = AXP20X_MUX_GPIO_OUT;
331 pctl->funcs[AXP20X_FUNC_GPIO_IN].name = "gpio_in";
332 pctl->funcs[AXP20X_FUNC_GPIO_IN].muxval = AXP20X_MUX_GPIO_IN;
333 pctl->funcs[AXP20X_FUNC_LDO].name = "ldo";
23f75d7d
QS
334 /*
335 * Muxval for LDO is useless as we won't use it.
336 * See comment in axp20x_pmx_set_mux.
337 */
d242e60c 338 pctl->funcs[AXP20X_FUNC_ADC].name = "adc";
a0a4b4c2 339 pctl->funcs[AXP20X_FUNC_ADC].muxval = pctl->desc->adc_mux;
23f75d7d
QS
340
341 /* Every pin supports GPIO_OUT and GPIO_IN functions */
342 for (i = 0; i <= AXP20X_FUNC_GPIO_IN; i++) {
d242e60c
QS
343 pctl->funcs[i].ngroups = npins;
344 pctl->funcs[i].groups = devm_kzalloc(&pdev->dev,
23f75d7d
QS
345 npins * sizeof(char *),
346 GFP_KERNEL);
347 for (pin = 0; pin < npins; pin++)
d242e60c 348 pctl->funcs[i].groups[pin] = pctl->desc->pins[pin].name;
23f75d7d
QS
349 }
350
d242e60c
QS
351 axp20x_funcs_groups_from_mask(&pdev->dev, pctl->desc->ldo_mask,
352 npins, &pctl->funcs[AXP20X_FUNC_LDO],
353 pctl->desc->pins);
23f75d7d 354
d242e60c
QS
355 axp20x_funcs_groups_from_mask(&pdev->dev, pctl->desc->adc_mask,
356 npins, &pctl->funcs[AXP20X_FUNC_ADC],
357 pctl->desc->pins);
f72f4b44
MR
358}
359
d242e60c 360static int axp20x_pctl_probe(struct platform_device *pdev)
f72f4b44
MR
361{
362 struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
d242e60c 363 struct axp20x_pctl *pctl;
23f75d7d 364 struct pinctrl_desc *pctrl_desc;
f72f4b44
MR
365 int ret;
366
367 if (!of_device_is_available(pdev->dev.of_node))
368 return -ENODEV;
369
370 if (!axp20x) {
371 dev_err(&pdev->dev, "Parent drvdata not set\n");
372 return -EINVAL;
373 }
374
d242e60c
QS
375 pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
376 if (!pctl)
f72f4b44
MR
377 return -ENOMEM;
378
d242e60c
QS
379 pctl->chip.base = -1;
380 pctl->chip.can_sleep = true;
381 pctl->chip.request = gpiochip_generic_request;
382 pctl->chip.free = gpiochip_generic_free;
383 pctl->chip.parent = &pdev->dev;
384 pctl->chip.label = dev_name(&pdev->dev);
385 pctl->chip.owner = THIS_MODULE;
386 pctl->chip.get = axp20x_gpio_get;
387 pctl->chip.get_direction = axp20x_gpio_get_direction;
388 pctl->chip.set = axp20x_gpio_set;
389 pctl->chip.direction_input = axp20x_gpio_input;
390 pctl->chip.direction_output = axp20x_gpio_output;
391 pctl->chip.ngpio = 3;
392
393 pctl->desc = &axp20x_data;
394 pctl->regmap = axp20x->regmap;
395 pctl->dev = &pdev->dev;
396
397 platform_set_drvdata(pdev, pctl);
23f75d7d
QS
398
399 axp20x_build_funcs_groups(pdev);
400
401 pctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctrl_desc), GFP_KERNEL);
402 if (!pctrl_desc)
403 return -ENOMEM;
404
405 pctrl_desc->name = dev_name(&pdev->dev);
406 pctrl_desc->owner = THIS_MODULE;
d242e60c
QS
407 pctrl_desc->pins = pctl->desc->pins;
408 pctrl_desc->npins = pctl->desc->npins;
23f75d7d
QS
409 pctrl_desc->pctlops = &axp20x_pctrl_ops;
410 pctrl_desc->pmxops = &axp20x_pmx_ops;
411
d242e60c
QS
412 pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, pctrl_desc, pctl);
413 if (IS_ERR(pctl->pctl_dev)) {
23f75d7d 414 dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
d242e60c 415 return PTR_ERR(pctl->pctl_dev);
23f75d7d 416 }
f72f4b44 417
d242e60c 418 ret = devm_gpiochip_add_data(&pdev->dev, &pctl->chip, pctl);
f72f4b44
MR
419 if (ret) {
420 dev_err(&pdev->dev, "Failed to register GPIO chip\n");
421 return ret;
422 }
423
d242e60c
QS
424 ret = gpiochip_add_pin_range(&pctl->chip, dev_name(&pdev->dev),
425 pctl->desc->pins->number,
426 pctl->desc->pins->number,
427 pctl->desc->npins);
23f75d7d
QS
428 if (ret) {
429 dev_err(&pdev->dev, "failed to add pin range\n");
430 return ret;
431 }
432
433 dev_info(&pdev->dev, "AXP209 pinctrl and GPIO driver loaded\n");
f72f4b44
MR
434
435 return 0;
436}
437
d242e60c 438static const struct of_device_id axp20x_pctl_match[] = {
f72f4b44
MR
439 { .compatible = "x-powers,axp209-gpio" },
440 { }
441};
d242e60c 442MODULE_DEVICE_TABLE(of, axp20x_pctl_match);
f72f4b44 443
d242e60c
QS
444static struct platform_driver axp20x_pctl_driver = {
445 .probe = axp20x_pctl_probe,
f72f4b44
MR
446 .driver = {
447 .name = "axp20x-gpio",
d242e60c 448 .of_match_table = axp20x_pctl_match,
f72f4b44
MR
449 },
450};
451
d242e60c 452module_platform_driver(axp20x_pctl_driver);
f72f4b44
MR
453
454MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
23f75d7d
QS
455MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
456MODULE_DESCRIPTION("AXP20x PMIC pinctrl and GPIO driver");
f72f4b44 457MODULE_LICENSE("GPL");