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