Lines Matching +full:int +full:- +full:fwd +full:- +full:mask
1 // SPDX-License-Identifier: GPL-2.0-only
5 // Copyright (C) 2019-2020 Glider bv
7 #define DRV_NAME "gpio-aggregator"
45 static int aggr_add_gpio(struct gpio_aggregator *aggr, const char *key, in aggr_add_gpio()
46 int hwnum, unsigned int *n) in aggr_add_gpio()
50 lookups = krealloc(aggr->lookups, struct_size(lookups, table, *n + 2), in aggr_add_gpio()
53 return -ENOMEM; in aggr_add_gpio()
55 lookups->table[*n] = GPIO_LOOKUP_IDX(key, hwnum, NULL, *n, 0); in aggr_add_gpio()
58 memset(&lookups->table[*n], 0, sizeof(lookups->table[*n])); in aggr_add_gpio()
60 aggr->lookups = lookups; in aggr_add_gpio()
64 static int aggr_parse(struct gpio_aggregator *aggr) in aggr_parse()
66 char *args = skip_spaces(aggr->args); in aggr_parse()
69 unsigned int i, n = 0; in aggr_parse()
70 int error = 0; in aggr_parse()
74 return -ENOMEM; in aggr_parse()
109 error = -EINVAL; in aggr_parse()
122 int res, id; in new_device_store()
127 return -ENOMEM; in new_device_store()
129 memcpy(aggr->args, buf, count + 1); in new_device_store()
131 aggr->lookups = kzalloc(struct_size(aggr->lookups, table, 1), in new_device_store()
133 if (!aggr->lookups) { in new_device_store()
134 res = -ENOMEM; in new_device_store()
147 aggr->lookups->dev_id = kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, id); in new_device_store()
148 if (!aggr->lookups->dev_id) { in new_device_store()
149 res = -ENOMEM; in new_device_store()
157 gpiod_add_lookup_table(aggr->lookups); in new_device_store()
165 aggr->pdev = pdev; in new_device_store()
169 gpiod_remove_lookup_table(aggr->lookups); in new_device_store()
171 kfree(aggr->lookups->dev_id); in new_device_store()
177 kfree(aggr->lookups); in new_device_store()
187 platform_device_unregister(aggr->pdev); in gpio_aggregator_free()
188 gpiod_remove_lookup_table(aggr->lookups); in gpio_aggregator_free()
189 kfree(aggr->lookups->dev_id); in gpio_aggregator_free()
190 kfree(aggr->lookups); in gpio_aggregator_free()
198 unsigned int id; in delete_device_store()
199 int error; in delete_device_store()
202 return -EINVAL; in delete_device_store()
212 return -ENOENT; in delete_device_store()
226 static int __exit gpio_aggregator_idr_remove(int id, void *p, void *data) in gpio_aggregator_idr_remove()
261 #define fwd_tmp_values(fwd) &(fwd)->tmp[0] argument
262 #define fwd_tmp_descs(fwd) (void *)&(fwd)->tmp[BITS_TO_LONGS((fwd)->chip.ngpio)] argument
266 static int gpio_fwd_get_direction(struct gpio_chip *chip, unsigned int offset) in gpio_fwd_get_direction()
268 struct gpiochip_fwd *fwd = gpiochip_get_data(chip); in gpio_fwd_get_direction() local
270 return gpiod_get_direction(fwd->descs[offset]); in gpio_fwd_get_direction()
273 static int gpio_fwd_direction_input(struct gpio_chip *chip, unsigned int offset) in gpio_fwd_direction_input()
275 struct gpiochip_fwd *fwd = gpiochip_get_data(chip); in gpio_fwd_direction_input() local
277 return gpiod_direction_input(fwd->descs[offset]); in gpio_fwd_direction_input()
280 static int gpio_fwd_direction_output(struct gpio_chip *chip, in gpio_fwd_direction_output()
281 unsigned int offset, int value) in gpio_fwd_direction_output()
283 struct gpiochip_fwd *fwd = gpiochip_get_data(chip); in gpio_fwd_direction_output() local
285 return gpiod_direction_output(fwd->descs[offset], value); in gpio_fwd_direction_output()
288 static int gpio_fwd_get(struct gpio_chip *chip, unsigned int offset) in gpio_fwd_get()
290 struct gpiochip_fwd *fwd = gpiochip_get_data(chip); in gpio_fwd_get() local
292 return chip->can_sleep ? gpiod_get_value_cansleep(fwd->descs[offset]) in gpio_fwd_get()
293 : gpiod_get_value(fwd->descs[offset]); in gpio_fwd_get()
296 static int gpio_fwd_get_multiple(struct gpiochip_fwd *fwd, unsigned long *mask, in gpio_fwd_get_multiple() argument
299 struct gpio_desc **descs = fwd_tmp_descs(fwd); in gpio_fwd_get_multiple()
300 unsigned long *values = fwd_tmp_values(fwd); in gpio_fwd_get_multiple()
301 unsigned int i, j = 0; in gpio_fwd_get_multiple()
302 int error; in gpio_fwd_get_multiple()
304 bitmap_clear(values, 0, fwd->chip.ngpio); in gpio_fwd_get_multiple()
305 for_each_set_bit(i, mask, fwd->chip.ngpio) in gpio_fwd_get_multiple()
306 descs[j++] = fwd->descs[i]; in gpio_fwd_get_multiple()
308 if (fwd->chip.can_sleep) in gpio_fwd_get_multiple()
316 for_each_set_bit(i, mask, fwd->chip.ngpio) in gpio_fwd_get_multiple()
322 static int gpio_fwd_get_multiple_locked(struct gpio_chip *chip, in gpio_fwd_get_multiple_locked()
323 unsigned long *mask, unsigned long *bits) in gpio_fwd_get_multiple_locked() argument
325 struct gpiochip_fwd *fwd = gpiochip_get_data(chip); in gpio_fwd_get_multiple_locked() local
327 int error; in gpio_fwd_get_multiple_locked()
329 if (chip->can_sleep) { in gpio_fwd_get_multiple_locked()
330 mutex_lock(&fwd->mlock); in gpio_fwd_get_multiple_locked()
331 error = gpio_fwd_get_multiple(fwd, mask, bits); in gpio_fwd_get_multiple_locked()
332 mutex_unlock(&fwd->mlock); in gpio_fwd_get_multiple_locked()
334 spin_lock_irqsave(&fwd->slock, flags); in gpio_fwd_get_multiple_locked()
335 error = gpio_fwd_get_multiple(fwd, mask, bits); in gpio_fwd_get_multiple_locked()
336 spin_unlock_irqrestore(&fwd->slock, flags); in gpio_fwd_get_multiple_locked()
342 static void gpio_fwd_delay(struct gpio_chip *chip, unsigned int offset, int value) in gpio_fwd_delay()
344 struct gpiochip_fwd *fwd = gpiochip_get_data(chip); in gpio_fwd_delay() local
346 bool is_active_low = gpiod_is_active_low(fwd->descs[offset]); in gpio_fwd_delay()
349 delay_timings = &fwd->delay_timings[offset]; in gpio_fwd_delay()
351 delay_us = delay_timings->ramp_up_us; in gpio_fwd_delay()
353 delay_us = delay_timings->ramp_down_us; in gpio_fwd_delay()
357 if (chip->can_sleep) in gpio_fwd_delay()
363 static void gpio_fwd_set(struct gpio_chip *chip, unsigned int offset, int value) in gpio_fwd_set()
365 struct gpiochip_fwd *fwd = gpiochip_get_data(chip); in gpio_fwd_set() local
367 if (chip->can_sleep) in gpio_fwd_set()
368 gpiod_set_value_cansleep(fwd->descs[offset], value); in gpio_fwd_set()
370 gpiod_set_value(fwd->descs[offset], value); in gpio_fwd_set()
372 if (fwd->delay_timings) in gpio_fwd_set()
376 static void gpio_fwd_set_multiple(struct gpiochip_fwd *fwd, unsigned long *mask, in gpio_fwd_set_multiple() argument
379 struct gpio_desc **descs = fwd_tmp_descs(fwd); in gpio_fwd_set_multiple()
380 unsigned long *values = fwd_tmp_values(fwd); in gpio_fwd_set_multiple()
381 unsigned int i, j = 0; in gpio_fwd_set_multiple()
383 for_each_set_bit(i, mask, fwd->chip.ngpio) { in gpio_fwd_set_multiple()
385 descs[j++] = fwd->descs[i]; in gpio_fwd_set_multiple()
388 if (fwd->chip.can_sleep) in gpio_fwd_set_multiple()
395 unsigned long *mask, unsigned long *bits) in gpio_fwd_set_multiple_locked() argument
397 struct gpiochip_fwd *fwd = gpiochip_get_data(chip); in gpio_fwd_set_multiple_locked() local
400 if (chip->can_sleep) { in gpio_fwd_set_multiple_locked()
401 mutex_lock(&fwd->mlock); in gpio_fwd_set_multiple_locked()
402 gpio_fwd_set_multiple(fwd, mask, bits); in gpio_fwd_set_multiple_locked()
403 mutex_unlock(&fwd->mlock); in gpio_fwd_set_multiple_locked()
405 spin_lock_irqsave(&fwd->slock, flags); in gpio_fwd_set_multiple_locked()
406 gpio_fwd_set_multiple(fwd, mask, bits); in gpio_fwd_set_multiple_locked()
407 spin_unlock_irqrestore(&fwd->slock, flags); in gpio_fwd_set_multiple_locked()
411 static int gpio_fwd_set_config(struct gpio_chip *chip, unsigned int offset, in gpio_fwd_set_config()
414 struct gpiochip_fwd *fwd = gpiochip_get_data(chip); in gpio_fwd_set_config() local
416 return gpiod_set_config(fwd->descs[offset], config); in gpio_fwd_set_config()
419 static int gpio_fwd_to_irq(struct gpio_chip *chip, unsigned int offset) in gpio_fwd_to_irq()
421 struct gpiochip_fwd *fwd = gpiochip_get_data(chip); in gpio_fwd_to_irq() local
423 return gpiod_to_irq(fwd->descs[offset]); in gpio_fwd_to_irq()
428 * for the GPIO ramp-up or ramp-down delays. This can serve the following
430 * - Open-drain output using an RC filter
435 static int gpiochip_fwd_delay_of_xlate(struct gpio_chip *chip, in gpiochip_fwd_delay_of_xlate()
439 struct gpiochip_fwd *fwd = gpiochip_get_data(chip); in gpiochip_fwd_delay_of_xlate() local
443 if (gpiospec->args_count != chip->of_gpio_n_cells) in gpiochip_fwd_delay_of_xlate()
444 return -EINVAL; in gpiochip_fwd_delay_of_xlate()
446 line = gpiospec->args[0]; in gpiochip_fwd_delay_of_xlate()
447 if (line >= chip->ngpio) in gpiochip_fwd_delay_of_xlate()
448 return -EINVAL; in gpiochip_fwd_delay_of_xlate()
450 timings = &fwd->delay_timings[line]; in gpiochip_fwd_delay_of_xlate()
451 timings->ramp_up_us = gpiospec->args[1]; in gpiochip_fwd_delay_of_xlate()
452 timings->ramp_down_us = gpiospec->args[2]; in gpiochip_fwd_delay_of_xlate()
457 static int gpiochip_fwd_setup_delay_line(struct device *dev, struct gpio_chip *chip, in gpiochip_fwd_setup_delay_line()
458 struct gpiochip_fwd *fwd) in gpiochip_fwd_setup_delay_line() argument
460 fwd->delay_timings = devm_kcalloc(dev, chip->ngpio, in gpiochip_fwd_setup_delay_line()
461 sizeof(*fwd->delay_timings), in gpiochip_fwd_setup_delay_line()
463 if (!fwd->delay_timings) in gpiochip_fwd_setup_delay_line()
464 return -ENOMEM; in gpiochip_fwd_setup_delay_line()
466 chip->of_xlate = gpiochip_fwd_delay_of_xlate; in gpiochip_fwd_setup_delay_line()
467 chip->of_gpio_n_cells = 3; in gpiochip_fwd_setup_delay_line()
472 static int gpiochip_fwd_setup_delay_line(struct device *dev, struct gpio_chip *chip, in gpiochip_fwd_setup_delay_line()
473 struct gpiochip_fwd *fwd) in gpiochip_fwd_setup_delay_line() argument
480 * gpiochip_fwd_create() - Create a new GPIO forwarder
491 * Return: An opaque object pointer, or an ERR_PTR()-encoded negative error
495 unsigned int ngpios, in gpiochip_fwd_create()
500 struct gpiochip_fwd *fwd; in gpiochip_fwd_create() local
502 unsigned int i; in gpiochip_fwd_create()
503 int error; in gpiochip_fwd_create()
505 fwd = devm_kzalloc(dev, struct_size(fwd, tmp, fwd_tmp_size(ngpios)), in gpiochip_fwd_create()
507 if (!fwd) in gpiochip_fwd_create()
508 return ERR_PTR(-ENOMEM); in gpiochip_fwd_create()
510 chip = &fwd->chip; in gpiochip_fwd_create()
525 chip->can_sleep = true; in gpiochip_fwd_create()
526 if (parent && parent->set_config) in gpiochip_fwd_create()
527 chip->set_config = gpio_fwd_set_config; in gpiochip_fwd_create()
530 chip->label = label; in gpiochip_fwd_create()
531 chip->parent = dev; in gpiochip_fwd_create()
532 chip->owner = THIS_MODULE; in gpiochip_fwd_create()
533 chip->get_direction = gpio_fwd_get_direction; in gpiochip_fwd_create()
534 chip->direction_input = gpio_fwd_direction_input; in gpiochip_fwd_create()
535 chip->direction_output = gpio_fwd_direction_output; in gpiochip_fwd_create()
536 chip->get = gpio_fwd_get; in gpiochip_fwd_create()
537 chip->get_multiple = gpio_fwd_get_multiple_locked; in gpiochip_fwd_create()
538 chip->set = gpio_fwd_set; in gpiochip_fwd_create()
539 chip->set_multiple = gpio_fwd_set_multiple_locked; in gpiochip_fwd_create()
540 chip->to_irq = gpio_fwd_to_irq; in gpiochip_fwd_create()
541 chip->base = -1; in gpiochip_fwd_create()
542 chip->ngpio = ngpios; in gpiochip_fwd_create()
543 fwd->descs = descs; in gpiochip_fwd_create()
545 if (chip->can_sleep) in gpiochip_fwd_create()
546 mutex_init(&fwd->mlock); in gpiochip_fwd_create()
548 spin_lock_init(&fwd->slock); in gpiochip_fwd_create()
551 error = gpiochip_fwd_setup_delay_line(dev, chip, fwd); in gpiochip_fwd_create()
556 error = devm_gpiochip_add_data(dev, chip, fwd); in gpiochip_fwd_create()
560 return fwd; in gpiochip_fwd_create()
568 static int gpio_aggregator_probe(struct platform_device *pdev) in gpio_aggregator_probe()
570 struct device *dev = &pdev->dev; in gpio_aggregator_probe()
572 struct gpiochip_fwd *fwd; in gpio_aggregator_probe() local
574 int i, n; in gpio_aggregator_probe()
582 return -ENOMEM; in gpio_aggregator_probe()
591 fwd = gpiochip_fwd_create(dev, n, descs, features); in gpio_aggregator_probe()
592 if (IS_ERR(fwd)) in gpio_aggregator_probe()
593 return PTR_ERR(fwd); in gpio_aggregator_probe()
595 platform_set_drvdata(pdev, fwd); in gpio_aggregator_probe()
601 .compatible = "gpio-delay",
605 * Add GPIO-operated devices controlled from userspace below,
621 static int __init gpio_aggregator_init(void) in gpio_aggregator_init()