The aggregator mode can also handle properties of the platform, that do not belong to the GPIO controller itself. One of such a property is a signal delay line. Set up a parser to support it. Signed-off-by: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx> --- drivers/gpio/gpio-aggregator.c | 70 +++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index a74a8d86caf3..ed11aa56bc51 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -18,6 +18,7 @@ #include <linux/mutex.h> #include <linux/overflow.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/string.h> @@ -423,6 +424,51 @@ static int gpio_fwd_to_irq(struct gpio_chip *chip, unsigned int offset) return gpiod_to_irq(fwd->descs[offset]); } +#ifdef CONFIG_OF_GPIO +static int gpiochip_fwd_delay_of_xlate(struct gpio_chip *chip, + const struct of_phandle_args *gpiospec, + u32 *flags) +{ + struct gpiochip_fwd *fwd = gpiochip_get_data(chip); + struct gpiochip_fwd_timing *timings; + u32 line; + + if (gpiospec->args_count != chip->of_gpio_n_cells) + return -EINVAL; + + line = gpiospec->args[0]; + if (line >= chip->ngpio) + return -EINVAL; + + timings = &fwd->delay_timings[line]; + timings->ramp_up_us = gpiospec->args[1]; + timings->ramp_down_us = gpiospec->args[2]; + + return line; +} + +static int gpiochip_fwd_setup_delay_line(struct device *dev, struct gpio_chip *chip, + struct gpiochip_fwd *fwd) +{ + fwd->delay_timings = devm_kcalloc(dev, chip->ngpio, + sizeof(*fwd->delay_timings), + GFP_KERNEL); + if (!fwd->delay_timings) + return -ENOMEM; + + chip->of_xlate = gpiochip_fwd_delay_of_xlate; + chip->of_gpio_n_cells = 3; + + return 0; +} +#else +static int gpiochip_fwd_setup_delay_line(struct device *dev, struct gpio_chip *chip, + struct gpiochip_fwd *fwd) +{ + return 0; +} +#endif /* !CONFIG_OF_GPIO */ + /** * gpiochip_fwd_create() - Create a new GPIO forwarder * @dev: Parent device pointer @@ -430,6 +476,7 @@ static int gpio_fwd_to_irq(struct gpio_chip *chip, unsigned int offset) * @descs: Array containing the GPIO descriptors to forward to. * This array must contain @ngpios entries, and must not be deallocated * before the forwarder has been destroyed again. + * @delay_line: True if the pins have an external delay line. * * This function creates a new gpiochip, which forwards all GPIO operations to * the passed GPIO descriptors. @@ -439,7 +486,8 @@ static int gpio_fwd_to_irq(struct gpio_chip *chip, unsigned int offset) */ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, unsigned int ngpios, - struct gpio_desc *descs[]) + struct gpio_desc *descs[], + bool delay_line) { const char *label = dev_name(dev); struct gpiochip_fwd *fwd; @@ -492,6 +540,12 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, else spin_lock_init(&fwd->slock); + if (delay_line) { + error = gpiochip_fwd_setup_delay_line(dev, chip, fwd); + if (error) + return ERR_PTR(error); + } + error = devm_gpiochip_add_data(dev, chip, fwd); if (error) return ERR_PTR(error); @@ -509,6 +563,7 @@ static int gpio_aggregator_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct gpio_desc **descs; struct gpiochip_fwd *fwd; + bool delay_line; int i, n; n = gpiod_count(dev, NULL); @@ -525,7 +580,9 @@ static int gpio_aggregator_probe(struct platform_device *pdev) return PTR_ERR(descs[i]); } - fwd = gpiochip_fwd_create(dev, n, descs); + delay_line = fwnode_device_is_compatible(dev_fwnode(dev), "gpio-delay"); + + fwd = gpiochip_fwd_create(dev, n, descs, delay_line); if (IS_ERR(fwd)) return PTR_ERR(fwd); @@ -534,6 +591,15 @@ static int gpio_aggregator_probe(struct platform_device *pdev) } static const struct of_device_id gpio_aggregator_dt_ids[] = { + /* + * The GPIO delay provides a way to configure platform specific delays + * for GPIO ramp-up or ramp-down delays. This can serve the following + * purposes: + * - Open-drain output using an RC filter + */ + { + .compatible = "gpio-delay", + }, /* * Add GPIO-operated devices controlled from userspace below, * or use "driver_override" in sysfs. -- 2.40.0.1.gaa8946217a0b