1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // GPIO Aggregator
4*4882a593Smuzhiyun //
5*4882a593Smuzhiyun // Copyright (C) 2019-2020 Glider bv
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #define DRV_NAME "gpio-aggregator"
8*4882a593Smuzhiyun #define pr_fmt(fmt) DRV_NAME ": " fmt
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/bitmap.h>
11*4882a593Smuzhiyun #include <linux/bitops.h>
12*4882a593Smuzhiyun #include <linux/ctype.h>
13*4882a593Smuzhiyun #include <linux/gpio.h>
14*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
15*4882a593Smuzhiyun #include <linux/gpio/driver.h>
16*4882a593Smuzhiyun #include <linux/gpio/machine.h>
17*4882a593Smuzhiyun #include <linux/idr.h>
18*4882a593Smuzhiyun #include <linux/kernel.h>
19*4882a593Smuzhiyun #include <linux/module.h>
20*4882a593Smuzhiyun #include <linux/mutex.h>
21*4882a593Smuzhiyun #include <linux/overflow.h>
22*4882a593Smuzhiyun #include <linux/platform_device.h>
23*4882a593Smuzhiyun #include <linux/spinlock.h>
24*4882a593Smuzhiyun #include <linux/string.h>
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun /*
28*4882a593Smuzhiyun * GPIO Aggregator sysfs interface
29*4882a593Smuzhiyun */
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun struct gpio_aggregator {
32*4882a593Smuzhiyun struct gpiod_lookup_table *lookups;
33*4882a593Smuzhiyun struct platform_device *pdev;
34*4882a593Smuzhiyun char args[];
35*4882a593Smuzhiyun };
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun static DEFINE_MUTEX(gpio_aggregator_lock); /* protects idr */
38*4882a593Smuzhiyun static DEFINE_IDR(gpio_aggregator_idr);
39*4882a593Smuzhiyun
get_arg(char ** args)40*4882a593Smuzhiyun static char *get_arg(char **args)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun char *start, *end;
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun start = skip_spaces(*args);
45*4882a593Smuzhiyun if (!*start)
46*4882a593Smuzhiyun return NULL;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun if (*start == '"') {
49*4882a593Smuzhiyun /* Quoted arg */
50*4882a593Smuzhiyun end = strchr(++start, '"');
51*4882a593Smuzhiyun if (!end)
52*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
53*4882a593Smuzhiyun } else {
54*4882a593Smuzhiyun /* Unquoted arg */
55*4882a593Smuzhiyun for (end = start; *end && !isspace(*end); end++) ;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun if (*end)
59*4882a593Smuzhiyun *end++ = '\0';
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun *args = end;
62*4882a593Smuzhiyun return start;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun
isrange(const char * s)65*4882a593Smuzhiyun static bool isrange(const char *s)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun size_t n;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun if (IS_ERR_OR_NULL(s))
70*4882a593Smuzhiyun return false;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun while (1) {
73*4882a593Smuzhiyun n = strspn(s, "0123456789");
74*4882a593Smuzhiyun if (!n)
75*4882a593Smuzhiyun return false;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun s += n;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun switch (*s++) {
80*4882a593Smuzhiyun case '\0':
81*4882a593Smuzhiyun return true;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun case '-':
84*4882a593Smuzhiyun case ',':
85*4882a593Smuzhiyun break;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun default:
88*4882a593Smuzhiyun return false;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
aggr_add_gpio(struct gpio_aggregator * aggr,const char * key,int hwnum,unsigned int * n)93*4882a593Smuzhiyun static int aggr_add_gpio(struct gpio_aggregator *aggr, const char *key,
94*4882a593Smuzhiyun int hwnum, unsigned int *n)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun struct gpiod_lookup_table *lookups;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun lookups = krealloc(aggr->lookups, struct_size(lookups, table, *n + 2),
99*4882a593Smuzhiyun GFP_KERNEL);
100*4882a593Smuzhiyun if (!lookups)
101*4882a593Smuzhiyun return -ENOMEM;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun lookups->table[*n] =
104*4882a593Smuzhiyun (struct gpiod_lookup)GPIO_LOOKUP_IDX(key, hwnum, NULL, *n, 0);
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun (*n)++;
107*4882a593Smuzhiyun memset(&lookups->table[*n], 0, sizeof(lookups->table[*n]));
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun aggr->lookups = lookups;
110*4882a593Smuzhiyun return 0;
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun
aggr_parse(struct gpio_aggregator * aggr)113*4882a593Smuzhiyun static int aggr_parse(struct gpio_aggregator *aggr)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun char *args = aggr->args;
116*4882a593Smuzhiyun unsigned long *bitmap;
117*4882a593Smuzhiyun unsigned int i, n = 0;
118*4882a593Smuzhiyun char *name, *offsets;
119*4882a593Smuzhiyun int error = 0;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun bitmap = bitmap_alloc(ARCH_NR_GPIOS, GFP_KERNEL);
122*4882a593Smuzhiyun if (!bitmap)
123*4882a593Smuzhiyun return -ENOMEM;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun for (name = get_arg(&args), offsets = get_arg(&args); name;
126*4882a593Smuzhiyun offsets = get_arg(&args)) {
127*4882a593Smuzhiyun if (IS_ERR(name)) {
128*4882a593Smuzhiyun pr_err("Cannot get GPIO specifier: %pe\n", name);
129*4882a593Smuzhiyun error = PTR_ERR(name);
130*4882a593Smuzhiyun goto free_bitmap;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun if (!isrange(offsets)) {
134*4882a593Smuzhiyun /* Named GPIO line */
135*4882a593Smuzhiyun error = aggr_add_gpio(aggr, name, U16_MAX, &n);
136*4882a593Smuzhiyun if (error)
137*4882a593Smuzhiyun goto free_bitmap;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun name = offsets;
140*4882a593Smuzhiyun continue;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun /* GPIO chip + offset(s) */
144*4882a593Smuzhiyun error = bitmap_parselist(offsets, bitmap, ARCH_NR_GPIOS);
145*4882a593Smuzhiyun if (error) {
146*4882a593Smuzhiyun pr_err("Cannot parse %s: %d\n", offsets, error);
147*4882a593Smuzhiyun goto free_bitmap;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun for_each_set_bit(i, bitmap, ARCH_NR_GPIOS) {
151*4882a593Smuzhiyun error = aggr_add_gpio(aggr, name, i, &n);
152*4882a593Smuzhiyun if (error)
153*4882a593Smuzhiyun goto free_bitmap;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun name = get_arg(&args);
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun if (!n) {
160*4882a593Smuzhiyun pr_err("No GPIOs specified\n");
161*4882a593Smuzhiyun error = -EINVAL;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun free_bitmap:
165*4882a593Smuzhiyun bitmap_free(bitmap);
166*4882a593Smuzhiyun return error;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun
new_device_store(struct device_driver * driver,const char * buf,size_t count)169*4882a593Smuzhiyun static ssize_t new_device_store(struct device_driver *driver, const char *buf,
170*4882a593Smuzhiyun size_t count)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun struct gpio_aggregator *aggr;
173*4882a593Smuzhiyun struct platform_device *pdev;
174*4882a593Smuzhiyun int res, id;
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun /* kernfs guarantees string termination, so count + 1 is safe */
177*4882a593Smuzhiyun aggr = kzalloc(sizeof(*aggr) + count + 1, GFP_KERNEL);
178*4882a593Smuzhiyun if (!aggr)
179*4882a593Smuzhiyun return -ENOMEM;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun memcpy(aggr->args, buf, count + 1);
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun aggr->lookups = kzalloc(struct_size(aggr->lookups, table, 1),
184*4882a593Smuzhiyun GFP_KERNEL);
185*4882a593Smuzhiyun if (!aggr->lookups) {
186*4882a593Smuzhiyun res = -ENOMEM;
187*4882a593Smuzhiyun goto free_ga;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun mutex_lock(&gpio_aggregator_lock);
191*4882a593Smuzhiyun id = idr_alloc(&gpio_aggregator_idr, aggr, 0, 0, GFP_KERNEL);
192*4882a593Smuzhiyun mutex_unlock(&gpio_aggregator_lock);
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun if (id < 0) {
195*4882a593Smuzhiyun res = id;
196*4882a593Smuzhiyun goto free_table;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun aggr->lookups->dev_id = kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, id);
200*4882a593Smuzhiyun if (!aggr->lookups->dev_id) {
201*4882a593Smuzhiyun res = -ENOMEM;
202*4882a593Smuzhiyun goto remove_idr;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun res = aggr_parse(aggr);
206*4882a593Smuzhiyun if (res)
207*4882a593Smuzhiyun goto free_dev_id;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun gpiod_add_lookup_table(aggr->lookups);
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun pdev = platform_device_register_simple(DRV_NAME, id, NULL, 0);
212*4882a593Smuzhiyun if (IS_ERR(pdev)) {
213*4882a593Smuzhiyun res = PTR_ERR(pdev);
214*4882a593Smuzhiyun goto remove_table;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun aggr->pdev = pdev;
218*4882a593Smuzhiyun return count;
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun remove_table:
221*4882a593Smuzhiyun gpiod_remove_lookup_table(aggr->lookups);
222*4882a593Smuzhiyun free_dev_id:
223*4882a593Smuzhiyun kfree(aggr->lookups->dev_id);
224*4882a593Smuzhiyun remove_idr:
225*4882a593Smuzhiyun mutex_lock(&gpio_aggregator_lock);
226*4882a593Smuzhiyun idr_remove(&gpio_aggregator_idr, id);
227*4882a593Smuzhiyun mutex_unlock(&gpio_aggregator_lock);
228*4882a593Smuzhiyun free_table:
229*4882a593Smuzhiyun kfree(aggr->lookups);
230*4882a593Smuzhiyun free_ga:
231*4882a593Smuzhiyun kfree(aggr);
232*4882a593Smuzhiyun return res;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun static DRIVER_ATTR_WO(new_device);
236*4882a593Smuzhiyun
gpio_aggregator_free(struct gpio_aggregator * aggr)237*4882a593Smuzhiyun static void gpio_aggregator_free(struct gpio_aggregator *aggr)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun platform_device_unregister(aggr->pdev);
240*4882a593Smuzhiyun gpiod_remove_lookup_table(aggr->lookups);
241*4882a593Smuzhiyun kfree(aggr->lookups->dev_id);
242*4882a593Smuzhiyun kfree(aggr->lookups);
243*4882a593Smuzhiyun kfree(aggr);
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun
delete_device_store(struct device_driver * driver,const char * buf,size_t count)246*4882a593Smuzhiyun static ssize_t delete_device_store(struct device_driver *driver,
247*4882a593Smuzhiyun const char *buf, size_t count)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun struct gpio_aggregator *aggr;
250*4882a593Smuzhiyun unsigned int id;
251*4882a593Smuzhiyun int error;
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun if (!str_has_prefix(buf, DRV_NAME "."))
254*4882a593Smuzhiyun return -EINVAL;
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun error = kstrtouint(buf + strlen(DRV_NAME "."), 10, &id);
257*4882a593Smuzhiyun if (error)
258*4882a593Smuzhiyun return error;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun mutex_lock(&gpio_aggregator_lock);
261*4882a593Smuzhiyun aggr = idr_remove(&gpio_aggregator_idr, id);
262*4882a593Smuzhiyun mutex_unlock(&gpio_aggregator_lock);
263*4882a593Smuzhiyun if (!aggr)
264*4882a593Smuzhiyun return -ENOENT;
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun gpio_aggregator_free(aggr);
267*4882a593Smuzhiyun return count;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun static DRIVER_ATTR_WO(delete_device);
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun static struct attribute *gpio_aggregator_attrs[] = {
272*4882a593Smuzhiyun &driver_attr_new_device.attr,
273*4882a593Smuzhiyun &driver_attr_delete_device.attr,
274*4882a593Smuzhiyun NULL,
275*4882a593Smuzhiyun };
276*4882a593Smuzhiyun ATTRIBUTE_GROUPS(gpio_aggregator);
277*4882a593Smuzhiyun
gpio_aggregator_idr_remove(int id,void * p,void * data)278*4882a593Smuzhiyun static int __exit gpio_aggregator_idr_remove(int id, void *p, void *data)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun gpio_aggregator_free(p);
281*4882a593Smuzhiyun return 0;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
gpio_aggregator_remove_all(void)284*4882a593Smuzhiyun static void __exit gpio_aggregator_remove_all(void)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun mutex_lock(&gpio_aggregator_lock);
287*4882a593Smuzhiyun idr_for_each(&gpio_aggregator_idr, gpio_aggregator_idr_remove, NULL);
288*4882a593Smuzhiyun idr_destroy(&gpio_aggregator_idr);
289*4882a593Smuzhiyun mutex_unlock(&gpio_aggregator_lock);
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun /*
294*4882a593Smuzhiyun * GPIO Forwarder
295*4882a593Smuzhiyun */
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun struct gpiochip_fwd {
298*4882a593Smuzhiyun struct gpio_chip chip;
299*4882a593Smuzhiyun struct gpio_desc **descs;
300*4882a593Smuzhiyun union {
301*4882a593Smuzhiyun struct mutex mlock; /* protects tmp[] if can_sleep */
302*4882a593Smuzhiyun spinlock_t slock; /* protects tmp[] if !can_sleep */
303*4882a593Smuzhiyun };
304*4882a593Smuzhiyun unsigned long tmp[]; /* values and descs for multiple ops */
305*4882a593Smuzhiyun };
306*4882a593Smuzhiyun
gpio_fwd_get_direction(struct gpio_chip * chip,unsigned int offset)307*4882a593Smuzhiyun static int gpio_fwd_get_direction(struct gpio_chip *chip, unsigned int offset)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun struct gpiochip_fwd *fwd = gpiochip_get_data(chip);
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun return gpiod_get_direction(fwd->descs[offset]);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
gpio_fwd_direction_input(struct gpio_chip * chip,unsigned int offset)314*4882a593Smuzhiyun static int gpio_fwd_direction_input(struct gpio_chip *chip, unsigned int offset)
315*4882a593Smuzhiyun {
316*4882a593Smuzhiyun struct gpiochip_fwd *fwd = gpiochip_get_data(chip);
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun return gpiod_direction_input(fwd->descs[offset]);
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
gpio_fwd_direction_output(struct gpio_chip * chip,unsigned int offset,int value)321*4882a593Smuzhiyun static int gpio_fwd_direction_output(struct gpio_chip *chip,
322*4882a593Smuzhiyun unsigned int offset, int value)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun struct gpiochip_fwd *fwd = gpiochip_get_data(chip);
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun return gpiod_direction_output(fwd->descs[offset], value);
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun
gpio_fwd_get(struct gpio_chip * chip,unsigned int offset)329*4882a593Smuzhiyun static int gpio_fwd_get(struct gpio_chip *chip, unsigned int offset)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun struct gpiochip_fwd *fwd = gpiochip_get_data(chip);
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun return chip->can_sleep ? gpiod_get_value_cansleep(fwd->descs[offset])
334*4882a593Smuzhiyun : gpiod_get_value(fwd->descs[offset]);
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
gpio_fwd_get_multiple(struct gpiochip_fwd * fwd,unsigned long * mask,unsigned long * bits)337*4882a593Smuzhiyun static int gpio_fwd_get_multiple(struct gpiochip_fwd *fwd, unsigned long *mask,
338*4882a593Smuzhiyun unsigned long *bits)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun struct gpio_desc **descs;
341*4882a593Smuzhiyun unsigned long *values;
342*4882a593Smuzhiyun unsigned int i, j = 0;
343*4882a593Smuzhiyun int error;
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun /* Both values bitmap and desc pointers are stored in tmp[] */
346*4882a593Smuzhiyun values = &fwd->tmp[0];
347*4882a593Smuzhiyun descs = (void *)&fwd->tmp[BITS_TO_LONGS(fwd->chip.ngpio)];
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun bitmap_clear(values, 0, fwd->chip.ngpio);
350*4882a593Smuzhiyun for_each_set_bit(i, mask, fwd->chip.ngpio)
351*4882a593Smuzhiyun descs[j++] = fwd->descs[i];
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun if (fwd->chip.can_sleep)
354*4882a593Smuzhiyun error = gpiod_get_array_value_cansleep(j, descs, NULL, values);
355*4882a593Smuzhiyun else
356*4882a593Smuzhiyun error = gpiod_get_array_value(j, descs, NULL, values);
357*4882a593Smuzhiyun if (error)
358*4882a593Smuzhiyun return error;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun j = 0;
361*4882a593Smuzhiyun for_each_set_bit(i, mask, fwd->chip.ngpio)
362*4882a593Smuzhiyun __assign_bit(i, bits, test_bit(j++, values));
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun return 0;
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun
gpio_fwd_get_multiple_locked(struct gpio_chip * chip,unsigned long * mask,unsigned long * bits)367*4882a593Smuzhiyun static int gpio_fwd_get_multiple_locked(struct gpio_chip *chip,
368*4882a593Smuzhiyun unsigned long *mask, unsigned long *bits)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun struct gpiochip_fwd *fwd = gpiochip_get_data(chip);
371*4882a593Smuzhiyun unsigned long flags;
372*4882a593Smuzhiyun int error;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun if (chip->can_sleep) {
375*4882a593Smuzhiyun mutex_lock(&fwd->mlock);
376*4882a593Smuzhiyun error = gpio_fwd_get_multiple(fwd, mask, bits);
377*4882a593Smuzhiyun mutex_unlock(&fwd->mlock);
378*4882a593Smuzhiyun } else {
379*4882a593Smuzhiyun spin_lock_irqsave(&fwd->slock, flags);
380*4882a593Smuzhiyun error = gpio_fwd_get_multiple(fwd, mask, bits);
381*4882a593Smuzhiyun spin_unlock_irqrestore(&fwd->slock, flags);
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun return error;
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun
gpio_fwd_set(struct gpio_chip * chip,unsigned int offset,int value)387*4882a593Smuzhiyun static void gpio_fwd_set(struct gpio_chip *chip, unsigned int offset, int value)
388*4882a593Smuzhiyun {
389*4882a593Smuzhiyun struct gpiochip_fwd *fwd = gpiochip_get_data(chip);
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun if (chip->can_sleep)
392*4882a593Smuzhiyun gpiod_set_value_cansleep(fwd->descs[offset], value);
393*4882a593Smuzhiyun else
394*4882a593Smuzhiyun gpiod_set_value(fwd->descs[offset], value);
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun
gpio_fwd_set_multiple(struct gpiochip_fwd * fwd,unsigned long * mask,unsigned long * bits)397*4882a593Smuzhiyun static void gpio_fwd_set_multiple(struct gpiochip_fwd *fwd, unsigned long *mask,
398*4882a593Smuzhiyun unsigned long *bits)
399*4882a593Smuzhiyun {
400*4882a593Smuzhiyun struct gpio_desc **descs;
401*4882a593Smuzhiyun unsigned long *values;
402*4882a593Smuzhiyun unsigned int i, j = 0;
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun /* Both values bitmap and desc pointers are stored in tmp[] */
405*4882a593Smuzhiyun values = &fwd->tmp[0];
406*4882a593Smuzhiyun descs = (void *)&fwd->tmp[BITS_TO_LONGS(fwd->chip.ngpio)];
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun for_each_set_bit(i, mask, fwd->chip.ngpio) {
409*4882a593Smuzhiyun __assign_bit(j, values, test_bit(i, bits));
410*4882a593Smuzhiyun descs[j++] = fwd->descs[i];
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun if (fwd->chip.can_sleep)
414*4882a593Smuzhiyun gpiod_set_array_value_cansleep(j, descs, NULL, values);
415*4882a593Smuzhiyun else
416*4882a593Smuzhiyun gpiod_set_array_value(j, descs, NULL, values);
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun
gpio_fwd_set_multiple_locked(struct gpio_chip * chip,unsigned long * mask,unsigned long * bits)419*4882a593Smuzhiyun static void gpio_fwd_set_multiple_locked(struct gpio_chip *chip,
420*4882a593Smuzhiyun unsigned long *mask, unsigned long *bits)
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun struct gpiochip_fwd *fwd = gpiochip_get_data(chip);
423*4882a593Smuzhiyun unsigned long flags;
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun if (chip->can_sleep) {
426*4882a593Smuzhiyun mutex_lock(&fwd->mlock);
427*4882a593Smuzhiyun gpio_fwd_set_multiple(fwd, mask, bits);
428*4882a593Smuzhiyun mutex_unlock(&fwd->mlock);
429*4882a593Smuzhiyun } else {
430*4882a593Smuzhiyun spin_lock_irqsave(&fwd->slock, flags);
431*4882a593Smuzhiyun gpio_fwd_set_multiple(fwd, mask, bits);
432*4882a593Smuzhiyun spin_unlock_irqrestore(&fwd->slock, flags);
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun
gpio_fwd_set_config(struct gpio_chip * chip,unsigned int offset,unsigned long config)436*4882a593Smuzhiyun static int gpio_fwd_set_config(struct gpio_chip *chip, unsigned int offset,
437*4882a593Smuzhiyun unsigned long config)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun struct gpiochip_fwd *fwd = gpiochip_get_data(chip);
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun return gpiod_set_config(fwd->descs[offset], config);
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun /**
445*4882a593Smuzhiyun * gpiochip_fwd_create() - Create a new GPIO forwarder
446*4882a593Smuzhiyun * @dev: Parent device pointer
447*4882a593Smuzhiyun * @ngpios: Number of GPIOs in the forwarder.
448*4882a593Smuzhiyun * @descs: Array containing the GPIO descriptors to forward to.
449*4882a593Smuzhiyun * This array must contain @ngpios entries, and must not be deallocated
450*4882a593Smuzhiyun * before the forwarder has been destroyed again.
451*4882a593Smuzhiyun *
452*4882a593Smuzhiyun * This function creates a new gpiochip, which forwards all GPIO operations to
453*4882a593Smuzhiyun * the passed GPIO descriptors.
454*4882a593Smuzhiyun *
455*4882a593Smuzhiyun * Return: An opaque object pointer, or an ERR_PTR()-encoded negative error
456*4882a593Smuzhiyun * code on failure.
457*4882a593Smuzhiyun */
gpiochip_fwd_create(struct device * dev,unsigned int ngpios,struct gpio_desc * descs[])458*4882a593Smuzhiyun static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev,
459*4882a593Smuzhiyun unsigned int ngpios,
460*4882a593Smuzhiyun struct gpio_desc *descs[])
461*4882a593Smuzhiyun {
462*4882a593Smuzhiyun const char *label = dev_name(dev);
463*4882a593Smuzhiyun struct gpiochip_fwd *fwd;
464*4882a593Smuzhiyun struct gpio_chip *chip;
465*4882a593Smuzhiyun unsigned int i;
466*4882a593Smuzhiyun int error;
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun fwd = devm_kzalloc(dev, struct_size(fwd, tmp,
469*4882a593Smuzhiyun BITS_TO_LONGS(ngpios) + ngpios), GFP_KERNEL);
470*4882a593Smuzhiyun if (!fwd)
471*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun chip = &fwd->chip;
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun /*
476*4882a593Smuzhiyun * If any of the GPIO lines are sleeping, then the entire forwarder
477*4882a593Smuzhiyun * will be sleeping.
478*4882a593Smuzhiyun * If any of the chips support .set_config(), then the forwarder will
479*4882a593Smuzhiyun * support setting configs.
480*4882a593Smuzhiyun */
481*4882a593Smuzhiyun for (i = 0; i < ngpios; i++) {
482*4882a593Smuzhiyun struct gpio_chip *parent = gpiod_to_chip(descs[i]);
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun dev_dbg(dev, "%u => gpio-%d\n", i, desc_to_gpio(descs[i]));
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun if (gpiod_cansleep(descs[i]))
487*4882a593Smuzhiyun chip->can_sleep = true;
488*4882a593Smuzhiyun if (parent && parent->set_config)
489*4882a593Smuzhiyun chip->set_config = gpio_fwd_set_config;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun chip->label = label;
493*4882a593Smuzhiyun chip->parent = dev;
494*4882a593Smuzhiyun chip->owner = THIS_MODULE;
495*4882a593Smuzhiyun chip->get_direction = gpio_fwd_get_direction;
496*4882a593Smuzhiyun chip->direction_input = gpio_fwd_direction_input;
497*4882a593Smuzhiyun chip->direction_output = gpio_fwd_direction_output;
498*4882a593Smuzhiyun chip->get = gpio_fwd_get;
499*4882a593Smuzhiyun chip->get_multiple = gpio_fwd_get_multiple_locked;
500*4882a593Smuzhiyun chip->set = gpio_fwd_set;
501*4882a593Smuzhiyun chip->set_multiple = gpio_fwd_set_multiple_locked;
502*4882a593Smuzhiyun chip->base = -1;
503*4882a593Smuzhiyun chip->ngpio = ngpios;
504*4882a593Smuzhiyun fwd->descs = descs;
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun if (chip->can_sleep)
507*4882a593Smuzhiyun mutex_init(&fwd->mlock);
508*4882a593Smuzhiyun else
509*4882a593Smuzhiyun spin_lock_init(&fwd->slock);
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun error = devm_gpiochip_add_data(dev, chip, fwd);
512*4882a593Smuzhiyun if (error)
513*4882a593Smuzhiyun return ERR_PTR(error);
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun return fwd;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun /*
520*4882a593Smuzhiyun * GPIO Aggregator platform device
521*4882a593Smuzhiyun */
522*4882a593Smuzhiyun
gpio_aggregator_probe(struct platform_device * pdev)523*4882a593Smuzhiyun static int gpio_aggregator_probe(struct platform_device *pdev)
524*4882a593Smuzhiyun {
525*4882a593Smuzhiyun struct device *dev = &pdev->dev;
526*4882a593Smuzhiyun struct gpio_desc **descs;
527*4882a593Smuzhiyun struct gpiochip_fwd *fwd;
528*4882a593Smuzhiyun int i, n;
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun n = gpiod_count(dev, NULL);
531*4882a593Smuzhiyun if (n < 0)
532*4882a593Smuzhiyun return n;
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun descs = devm_kmalloc_array(dev, n, sizeof(*descs), GFP_KERNEL);
535*4882a593Smuzhiyun if (!descs)
536*4882a593Smuzhiyun return -ENOMEM;
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun for (i = 0; i < n; i++) {
539*4882a593Smuzhiyun descs[i] = devm_gpiod_get_index(dev, NULL, i, GPIOD_ASIS);
540*4882a593Smuzhiyun if (IS_ERR(descs[i]))
541*4882a593Smuzhiyun return PTR_ERR(descs[i]);
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun fwd = gpiochip_fwd_create(dev, n, descs);
545*4882a593Smuzhiyun if (IS_ERR(fwd))
546*4882a593Smuzhiyun return PTR_ERR(fwd);
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun platform_set_drvdata(pdev, fwd);
549*4882a593Smuzhiyun return 0;
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun #ifdef CONFIG_OF
553*4882a593Smuzhiyun static const struct of_device_id gpio_aggregator_dt_ids[] = {
554*4882a593Smuzhiyun /*
555*4882a593Smuzhiyun * Add GPIO-operated devices controlled from userspace below,
556*4882a593Smuzhiyun * or use "driver_override" in sysfs
557*4882a593Smuzhiyun */
558*4882a593Smuzhiyun {},
559*4882a593Smuzhiyun };
560*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, gpio_aggregator_dt_ids);
561*4882a593Smuzhiyun #endif
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun static struct platform_driver gpio_aggregator_driver = {
564*4882a593Smuzhiyun .probe = gpio_aggregator_probe,
565*4882a593Smuzhiyun .driver = {
566*4882a593Smuzhiyun .name = DRV_NAME,
567*4882a593Smuzhiyun .groups = gpio_aggregator_groups,
568*4882a593Smuzhiyun .of_match_table = of_match_ptr(gpio_aggregator_dt_ids),
569*4882a593Smuzhiyun },
570*4882a593Smuzhiyun };
571*4882a593Smuzhiyun
gpio_aggregator_init(void)572*4882a593Smuzhiyun static int __init gpio_aggregator_init(void)
573*4882a593Smuzhiyun {
574*4882a593Smuzhiyun return platform_driver_register(&gpio_aggregator_driver);
575*4882a593Smuzhiyun }
576*4882a593Smuzhiyun module_init(gpio_aggregator_init);
577*4882a593Smuzhiyun
gpio_aggregator_exit(void)578*4882a593Smuzhiyun static void __exit gpio_aggregator_exit(void)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun gpio_aggregator_remove_all();
581*4882a593Smuzhiyun platform_driver_unregister(&gpio_aggregator_driver);
582*4882a593Smuzhiyun }
583*4882a593Smuzhiyun module_exit(gpio_aggregator_exit);
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>");
586*4882a593Smuzhiyun MODULE_DESCRIPTION("GPIO Aggregator");
587*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
588