1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * regmap based generic GPIO driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright 2020 Michael Walle <michael@walle.cc>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/gpio/driver.h>
9*4882a593Smuzhiyun #include <linux/gpio/regmap.h>
10*4882a593Smuzhiyun #include <linux/kernel.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/regmap.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun struct gpio_regmap {
15*4882a593Smuzhiyun struct device *parent;
16*4882a593Smuzhiyun struct regmap *regmap;
17*4882a593Smuzhiyun struct gpio_chip gpio_chip;
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun int reg_stride;
20*4882a593Smuzhiyun int ngpio_per_reg;
21*4882a593Smuzhiyun unsigned int reg_dat_base;
22*4882a593Smuzhiyun unsigned int reg_set_base;
23*4882a593Smuzhiyun unsigned int reg_clr_base;
24*4882a593Smuzhiyun unsigned int reg_dir_in_base;
25*4882a593Smuzhiyun unsigned int reg_dir_out_base;
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun int (*reg_mask_xlate)(struct gpio_regmap *gpio, unsigned int base,
28*4882a593Smuzhiyun unsigned int offset, unsigned int *reg,
29*4882a593Smuzhiyun unsigned int *mask);
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun void *driver_data;
32*4882a593Smuzhiyun };
33*4882a593Smuzhiyun
gpio_regmap_addr(unsigned int addr)34*4882a593Smuzhiyun static unsigned int gpio_regmap_addr(unsigned int addr)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun if (addr == GPIO_REGMAP_ADDR_ZERO)
37*4882a593Smuzhiyun return 0;
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun return addr;
40*4882a593Smuzhiyun }
41*4882a593Smuzhiyun
gpio_regmap_simple_xlate(struct gpio_regmap * gpio,unsigned int base,unsigned int offset,unsigned int * reg,unsigned int * mask)42*4882a593Smuzhiyun static int gpio_regmap_simple_xlate(struct gpio_regmap *gpio,
43*4882a593Smuzhiyun unsigned int base, unsigned int offset,
44*4882a593Smuzhiyun unsigned int *reg, unsigned int *mask)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun unsigned int line = offset % gpio->ngpio_per_reg;
47*4882a593Smuzhiyun unsigned int stride = offset / gpio->ngpio_per_reg;
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun *reg = base + stride * gpio->reg_stride;
50*4882a593Smuzhiyun *mask = BIT(line);
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun return 0;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun
gpio_regmap_get(struct gpio_chip * chip,unsigned int offset)55*4882a593Smuzhiyun static int gpio_regmap_get(struct gpio_chip *chip, unsigned int offset)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun struct gpio_regmap *gpio = gpiochip_get_data(chip);
58*4882a593Smuzhiyun unsigned int base, val, reg, mask;
59*4882a593Smuzhiyun int ret;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /* we might not have an output register if we are input only */
62*4882a593Smuzhiyun if (gpio->reg_dat_base)
63*4882a593Smuzhiyun base = gpio_regmap_addr(gpio->reg_dat_base);
64*4882a593Smuzhiyun else
65*4882a593Smuzhiyun base = gpio_regmap_addr(gpio->reg_set_base);
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun ret = gpio->reg_mask_xlate(gpio, base, offset, ®, &mask);
68*4882a593Smuzhiyun if (ret)
69*4882a593Smuzhiyun return ret;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun ret = regmap_read(gpio->regmap, reg, &val);
72*4882a593Smuzhiyun if (ret)
73*4882a593Smuzhiyun return ret;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun return !!(val & mask);
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun
gpio_regmap_set(struct gpio_chip * chip,unsigned int offset,int val)78*4882a593Smuzhiyun static void gpio_regmap_set(struct gpio_chip *chip, unsigned int offset,
79*4882a593Smuzhiyun int val)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun struct gpio_regmap *gpio = gpiochip_get_data(chip);
82*4882a593Smuzhiyun unsigned int base = gpio_regmap_addr(gpio->reg_set_base);
83*4882a593Smuzhiyun unsigned int reg, mask;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun gpio->reg_mask_xlate(gpio, base, offset, ®, &mask);
86*4882a593Smuzhiyun if (val)
87*4882a593Smuzhiyun regmap_update_bits(gpio->regmap, reg, mask, mask);
88*4882a593Smuzhiyun else
89*4882a593Smuzhiyun regmap_update_bits(gpio->regmap, reg, mask, 0);
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
gpio_regmap_set_with_clear(struct gpio_chip * chip,unsigned int offset,int val)92*4882a593Smuzhiyun static void gpio_regmap_set_with_clear(struct gpio_chip *chip,
93*4882a593Smuzhiyun unsigned int offset, int val)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun struct gpio_regmap *gpio = gpiochip_get_data(chip);
96*4882a593Smuzhiyun unsigned int base, reg, mask;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun if (val)
99*4882a593Smuzhiyun base = gpio_regmap_addr(gpio->reg_set_base);
100*4882a593Smuzhiyun else
101*4882a593Smuzhiyun base = gpio_regmap_addr(gpio->reg_clr_base);
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun gpio->reg_mask_xlate(gpio, base, offset, ®, &mask);
104*4882a593Smuzhiyun regmap_write(gpio->regmap, reg, mask);
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
gpio_regmap_get_direction(struct gpio_chip * chip,unsigned int offset)107*4882a593Smuzhiyun static int gpio_regmap_get_direction(struct gpio_chip *chip,
108*4882a593Smuzhiyun unsigned int offset)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun struct gpio_regmap *gpio = gpiochip_get_data(chip);
111*4882a593Smuzhiyun unsigned int base, val, reg, mask;
112*4882a593Smuzhiyun int invert, ret;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun if (gpio->reg_dir_out_base) {
115*4882a593Smuzhiyun base = gpio_regmap_addr(gpio->reg_dir_out_base);
116*4882a593Smuzhiyun invert = 0;
117*4882a593Smuzhiyun } else if (gpio->reg_dir_in_base) {
118*4882a593Smuzhiyun base = gpio_regmap_addr(gpio->reg_dir_in_base);
119*4882a593Smuzhiyun invert = 1;
120*4882a593Smuzhiyun } else {
121*4882a593Smuzhiyun return -EOPNOTSUPP;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun ret = gpio->reg_mask_xlate(gpio, base, offset, ®, &mask);
125*4882a593Smuzhiyun if (ret)
126*4882a593Smuzhiyun return ret;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun ret = regmap_read(gpio->regmap, reg, &val);
129*4882a593Smuzhiyun if (ret)
130*4882a593Smuzhiyun return ret;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun if (!!(val & mask) ^ invert)
133*4882a593Smuzhiyun return GPIO_LINE_DIRECTION_OUT;
134*4882a593Smuzhiyun else
135*4882a593Smuzhiyun return GPIO_LINE_DIRECTION_IN;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
gpio_regmap_set_direction(struct gpio_chip * chip,unsigned int offset,bool output)138*4882a593Smuzhiyun static int gpio_regmap_set_direction(struct gpio_chip *chip,
139*4882a593Smuzhiyun unsigned int offset, bool output)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun struct gpio_regmap *gpio = gpiochip_get_data(chip);
142*4882a593Smuzhiyun unsigned int base, val, reg, mask;
143*4882a593Smuzhiyun int invert, ret;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun if (gpio->reg_dir_out_base) {
146*4882a593Smuzhiyun base = gpio_regmap_addr(gpio->reg_dir_out_base);
147*4882a593Smuzhiyun invert = 0;
148*4882a593Smuzhiyun } else if (gpio->reg_dir_in_base) {
149*4882a593Smuzhiyun base = gpio_regmap_addr(gpio->reg_dir_in_base);
150*4882a593Smuzhiyun invert = 1;
151*4882a593Smuzhiyun } else {
152*4882a593Smuzhiyun return -EOPNOTSUPP;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun ret = gpio->reg_mask_xlate(gpio, base, offset, ®, &mask);
156*4882a593Smuzhiyun if (ret)
157*4882a593Smuzhiyun return ret;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun if (invert)
160*4882a593Smuzhiyun val = output ? 0 : mask;
161*4882a593Smuzhiyun else
162*4882a593Smuzhiyun val = output ? mask : 0;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun return regmap_update_bits(gpio->regmap, reg, mask, val);
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun
gpio_regmap_direction_input(struct gpio_chip * chip,unsigned int offset)167*4882a593Smuzhiyun static int gpio_regmap_direction_input(struct gpio_chip *chip,
168*4882a593Smuzhiyun unsigned int offset)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun return gpio_regmap_set_direction(chip, offset, false);
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
gpio_regmap_direction_output(struct gpio_chip * chip,unsigned int offset,int value)173*4882a593Smuzhiyun static int gpio_regmap_direction_output(struct gpio_chip *chip,
174*4882a593Smuzhiyun unsigned int offset, int value)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun gpio_regmap_set(chip, offset, value);
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun return gpio_regmap_set_direction(chip, offset, true);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
gpio_regmap_set_drvdata(struct gpio_regmap * gpio,void * data)181*4882a593Smuzhiyun void gpio_regmap_set_drvdata(struct gpio_regmap *gpio, void *data)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun gpio->driver_data = data;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gpio_regmap_set_drvdata);
186*4882a593Smuzhiyun
gpio_regmap_get_drvdata(struct gpio_regmap * gpio)187*4882a593Smuzhiyun void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun return gpio->driver_data;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gpio_regmap_get_drvdata);
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun /**
194*4882a593Smuzhiyun * gpio_regmap_register() - Register a generic regmap GPIO controller
195*4882a593Smuzhiyun * @config: configuration for gpio_regmap
196*4882a593Smuzhiyun *
197*4882a593Smuzhiyun * Return: A pointer to the registered gpio_regmap or ERR_PTR error value.
198*4882a593Smuzhiyun */
gpio_regmap_register(const struct gpio_regmap_config * config)199*4882a593Smuzhiyun struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun struct gpio_regmap *gpio;
202*4882a593Smuzhiyun struct gpio_chip *chip;
203*4882a593Smuzhiyun int ret;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun if (!config->parent)
206*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun if (!config->ngpio)
209*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun /* we need at least one */
212*4882a593Smuzhiyun if (!config->reg_dat_base && !config->reg_set_base)
213*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun /* if we have a direction register we need both input and output */
216*4882a593Smuzhiyun if ((config->reg_dir_out_base || config->reg_dir_in_base) &&
217*4882a593Smuzhiyun (!config->reg_dat_base || !config->reg_set_base))
218*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun /* we don't support having both registers simultaneously for now */
221*4882a593Smuzhiyun if (config->reg_dir_out_base && config->reg_dir_in_base)
222*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun gpio = kzalloc(sizeof(*gpio), GFP_KERNEL);
225*4882a593Smuzhiyun if (!gpio)
226*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun gpio->parent = config->parent;
229*4882a593Smuzhiyun gpio->regmap = config->regmap;
230*4882a593Smuzhiyun gpio->ngpio_per_reg = config->ngpio_per_reg;
231*4882a593Smuzhiyun gpio->reg_stride = config->reg_stride;
232*4882a593Smuzhiyun gpio->reg_mask_xlate = config->reg_mask_xlate;
233*4882a593Smuzhiyun gpio->reg_dat_base = config->reg_dat_base;
234*4882a593Smuzhiyun gpio->reg_set_base = config->reg_set_base;
235*4882a593Smuzhiyun gpio->reg_clr_base = config->reg_clr_base;
236*4882a593Smuzhiyun gpio->reg_dir_in_base = config->reg_dir_in_base;
237*4882a593Smuzhiyun gpio->reg_dir_out_base = config->reg_dir_out_base;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun /* if not set, assume there is only one register */
240*4882a593Smuzhiyun if (!gpio->ngpio_per_reg)
241*4882a593Smuzhiyun gpio->ngpio_per_reg = config->ngpio;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun /* if not set, assume they are consecutive */
244*4882a593Smuzhiyun if (!gpio->reg_stride)
245*4882a593Smuzhiyun gpio->reg_stride = 1;
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun if (!gpio->reg_mask_xlate)
248*4882a593Smuzhiyun gpio->reg_mask_xlate = gpio_regmap_simple_xlate;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun chip = &gpio->gpio_chip;
251*4882a593Smuzhiyun chip->parent = config->parent;
252*4882a593Smuzhiyun chip->base = -1;
253*4882a593Smuzhiyun chip->ngpio = config->ngpio;
254*4882a593Smuzhiyun chip->names = config->names;
255*4882a593Smuzhiyun chip->label = config->label ?: dev_name(config->parent);
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun /*
258*4882a593Smuzhiyun * If our regmap is fast_io we should probably set can_sleep to false.
259*4882a593Smuzhiyun * Right now, the regmap doesn't save this property, nor is there any
260*4882a593Smuzhiyun * access function for it.
261*4882a593Smuzhiyun * The only regmap type which uses fast_io is regmap-mmio. For now,
262*4882a593Smuzhiyun * assume a safe default of true here.
263*4882a593Smuzhiyun */
264*4882a593Smuzhiyun chip->can_sleep = true;
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun chip->get = gpio_regmap_get;
267*4882a593Smuzhiyun if (gpio->reg_set_base && gpio->reg_clr_base)
268*4882a593Smuzhiyun chip->set = gpio_regmap_set_with_clear;
269*4882a593Smuzhiyun else if (gpio->reg_set_base)
270*4882a593Smuzhiyun chip->set = gpio_regmap_set;
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun if (gpio->reg_dir_in_base || gpio->reg_dir_out_base) {
273*4882a593Smuzhiyun chip->get_direction = gpio_regmap_get_direction;
274*4882a593Smuzhiyun chip->direction_input = gpio_regmap_direction_input;
275*4882a593Smuzhiyun chip->direction_output = gpio_regmap_direction_output;
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun ret = gpiochip_add_data(chip, gpio);
279*4882a593Smuzhiyun if (ret < 0)
280*4882a593Smuzhiyun goto err_free_gpio;
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun if (config->irq_domain) {
283*4882a593Smuzhiyun ret = gpiochip_irqchip_add_domain(chip, config->irq_domain);
284*4882a593Smuzhiyun if (ret)
285*4882a593Smuzhiyun goto err_remove_gpiochip;
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun return gpio;
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun err_remove_gpiochip:
291*4882a593Smuzhiyun gpiochip_remove(chip);
292*4882a593Smuzhiyun err_free_gpio:
293*4882a593Smuzhiyun kfree(gpio);
294*4882a593Smuzhiyun return ERR_PTR(ret);
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gpio_regmap_register);
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun /**
299*4882a593Smuzhiyun * gpio_regmap_unregister() - Unregister a generic regmap GPIO controller
300*4882a593Smuzhiyun * @gpio: gpio_regmap device to unregister
301*4882a593Smuzhiyun */
gpio_regmap_unregister(struct gpio_regmap * gpio)302*4882a593Smuzhiyun void gpio_regmap_unregister(struct gpio_regmap *gpio)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun gpiochip_remove(&gpio->gpio_chip);
305*4882a593Smuzhiyun kfree(gpio);
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gpio_regmap_unregister);
308*4882a593Smuzhiyun
devm_gpio_regmap_unregister(struct device * dev,void * res)309*4882a593Smuzhiyun static void devm_gpio_regmap_unregister(struct device *dev, void *res)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun gpio_regmap_unregister(*(struct gpio_regmap **)res);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun /**
315*4882a593Smuzhiyun * devm_gpio_regmap_register() - resource managed gpio_regmap_register()
316*4882a593Smuzhiyun * @dev: device that is registering this GPIO device
317*4882a593Smuzhiyun * @config: configuration for gpio_regmap
318*4882a593Smuzhiyun *
319*4882a593Smuzhiyun * Managed gpio_regmap_register(). For generic regmap GPIO device registered by
320*4882a593Smuzhiyun * this function, gpio_regmap_unregister() is automatically called on driver
321*4882a593Smuzhiyun * detach. See gpio_regmap_register() for more information.
322*4882a593Smuzhiyun *
323*4882a593Smuzhiyun * Return: A pointer to the registered gpio_regmap or ERR_PTR error value.
324*4882a593Smuzhiyun */
devm_gpio_regmap_register(struct device * dev,const struct gpio_regmap_config * config)325*4882a593Smuzhiyun struct gpio_regmap *devm_gpio_regmap_register(struct device *dev,
326*4882a593Smuzhiyun const struct gpio_regmap_config *config)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun struct gpio_regmap **ptr, *gpio;
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun ptr = devres_alloc(devm_gpio_regmap_unregister, sizeof(*ptr),
331*4882a593Smuzhiyun GFP_KERNEL);
332*4882a593Smuzhiyun if (!ptr)
333*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun gpio = gpio_regmap_register(config);
336*4882a593Smuzhiyun if (!IS_ERR(gpio)) {
337*4882a593Smuzhiyun *ptr = gpio;
338*4882a593Smuzhiyun devres_add(dev, ptr);
339*4882a593Smuzhiyun } else {
340*4882a593Smuzhiyun devres_free(ptr);
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun return gpio;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(devm_gpio_regmap_register);
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
348*4882a593Smuzhiyun MODULE_DESCRIPTION("GPIO generic regmap driver core");
349*4882a593Smuzhiyun MODULE_LICENSE("GPL");
350