From 9af512e81964a1b9a6ac7ae9b24507f99e557c36 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 15 Apr 2020 16:51:39 +0200 Subject: leds: netxbig: Convert to use GPIO descriptors This converts the NetXbig LED driver to use GPIO descriptors instead of using the legacy interfaces in and to iteratively parse the device tree for global GPIO numbers. Signed-off-by: Linus Walleij Signed-off-by: Pavel Machek Tested-by: Simon Guinot --- drivers/leds/leds-netxbig.c | 148 ++++++++++++++++++++++++-------------------- 1 file changed, 81 insertions(+), 67 deletions(-) (limited to 'drivers/leds') diff --git a/drivers/leds/leds-netxbig.c b/drivers/leds/leds-netxbig.c index 14ef4ccdda3a..ceceeb6a0e96 100644 --- a/drivers/leds/leds-netxbig.c +++ b/drivers/leds/leds-netxbig.c @@ -12,16 +12,17 @@ #include #include #include -#include -#include +#include #include +#include +#include struct netxbig_gpio_ext { - unsigned int *addr; + struct gpio_desc **addr; int num_addr; - unsigned int *data; + struct gpio_desc **data; int num_data; - unsigned int enable; + struct gpio_desc *enable; }; enum netxbig_led_mode { @@ -69,7 +70,7 @@ static void gpio_ext_set_addr(struct netxbig_gpio_ext *gpio_ext, int addr) int pin; for (pin = 0; pin < gpio_ext->num_addr; pin++) - gpio_set_value(gpio_ext->addr[pin], (addr >> pin) & 1); + gpiod_set_value(gpio_ext->addr[pin], (addr >> pin) & 1); } static void gpio_ext_set_data(struct netxbig_gpio_ext *gpio_ext, int data) @@ -77,14 +78,14 @@ static void gpio_ext_set_data(struct netxbig_gpio_ext *gpio_ext, int data) int pin; for (pin = 0; pin < gpio_ext->num_data; pin++) - gpio_set_value(gpio_ext->data[pin], (data >> pin) & 1); + gpiod_set_value(gpio_ext->data[pin], (data >> pin) & 1); } static void gpio_ext_enable_select(struct netxbig_gpio_ext *gpio_ext) { /* Enable select is done on the raising edge. */ - gpio_set_value(gpio_ext->enable, 0); - gpio_set_value(gpio_ext->enable, 1); + gpiod_set_value(gpio_ext->enable, 0); + gpiod_set_value(gpio_ext->enable, 1); } static void gpio_ext_set_value(struct netxbig_gpio_ext *gpio_ext, @@ -99,41 +100,6 @@ static void gpio_ext_set_value(struct netxbig_gpio_ext *gpio_ext, spin_unlock_irqrestore(&gpio_ext_lock, flags); } -static int gpio_ext_init(struct platform_device *pdev, - struct netxbig_gpio_ext *gpio_ext) -{ - int err; - int i; - - if (unlikely(!gpio_ext)) - return -EINVAL; - - /* Configure address GPIOs. */ - for (i = 0; i < gpio_ext->num_addr; i++) { - err = devm_gpio_request_one(&pdev->dev, gpio_ext->addr[i], - GPIOF_OUT_INIT_LOW, - "GPIO extension addr"); - if (err) - return err; - } - /* Configure data GPIOs. */ - for (i = 0; i < gpio_ext->num_data; i++) { - err = devm_gpio_request_one(&pdev->dev, gpio_ext->data[i], - GPIOF_OUT_INIT_LOW, - "GPIO extension data"); - if (err) - return err; - } - /* Configure "enable select" GPIO. */ - err = devm_gpio_request_one(&pdev->dev, gpio_ext->enable, - GPIOF_OUT_INIT_LOW, - "GPIO extension enable"); - if (err) - return err; - - return 0; -} - /* * Class LED driver. */ @@ -347,15 +313,47 @@ static int create_netxbig_led(struct platform_device *pdev, return devm_led_classdev_register(&pdev->dev, &led_dat->cdev); } -static int gpio_ext_get_of_pdata(struct device *dev, struct device_node *np, - struct netxbig_gpio_ext *gpio_ext) +/** + * netxbig_gpio_ext_remove() - Clean up GPIO extension data + * @data: managed resource data to clean up + * + * Since we pick GPIO descriptors from another device than the device our + * driver is probing to, we need to register a specific callback to free + * these up using managed resources. + */ +static void netxbig_gpio_ext_remove(void *data) +{ + struct netxbig_gpio_ext *gpio_ext = data; + int i; + + for (i = 0; i < gpio_ext->num_addr; i++) + gpiod_put(gpio_ext->addr[i]); + for (i = 0; i < gpio_ext->num_data; i++) + gpiod_put(gpio_ext->data[i]); + gpiod_put(gpio_ext->enable); +} + +/** + * netxbig_gpio_ext_get() - Obtain GPIO extension device data + * @dev: main LED device + * @gpio_ext_dev: the GPIO extension device + * @gpio_ext: the data structure holding the GPIO extension data + * + * This function walks the subdevice that only contain GPIO line + * handles in the device tree and obtains the GPIO descriptors from that + * device. + */ +static int netxbig_gpio_ext_get(struct device *dev, + struct device *gpio_ext_dev, + struct netxbig_gpio_ext *gpio_ext) { - int *addr, *data; + struct gpio_desc **addr, **data; int num_addr, num_data; + struct gpio_desc *gpiod; int ret; int i; - ret = of_gpio_named_count(np, "addr-gpios"); + ret = gpiod_count(gpio_ext_dev, "addr"); if (ret < 0) { dev_err(dev, "Failed to count GPIOs in DT property addr-gpios\n"); @@ -366,16 +364,25 @@ static int gpio_ext_get_of_pdata(struct device *dev, struct device_node *np, if (!addr) return -ENOMEM; + /* + * We cannot use devm_ managed resources with these GPIO descriptors + * since they are associated with the "GPIO extension device" which + * does not probe any driver. The device tree parser will however + * populate a platform device for it so we can anyway obtain the + * GPIO descriptors from the device. + */ for (i = 0; i < num_addr; i++) { - ret = of_get_named_gpio(np, "addr-gpios", i); - if (ret < 0) - return ret; - addr[i] = ret; + gpiod = gpiod_get_index(gpio_ext_dev, "addr", i, + GPIOD_OUT_LOW); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + gpiod_set_consumer_name(gpiod, "GPIO extension addr"); + addr[i] = gpiod; } gpio_ext->addr = addr; gpio_ext->num_addr = num_addr; - ret = of_gpio_named_count(np, "data-gpios"); + ret = gpiod_count(gpio_ext_dev, "data"); if (ret < 0) { dev_err(dev, "Failed to count GPIOs in DT property data-gpios\n"); @@ -387,23 +394,26 @@ static int gpio_ext_get_of_pdata(struct device *dev, struct device_node *np, return -ENOMEM; for (i = 0; i < num_data; i++) { - ret = of_get_named_gpio(np, "data-gpios", i); - if (ret < 0) - return ret; - data[i] = ret; + gpiod = gpiod_get_index(gpio_ext_dev, "data", i, + GPIOD_OUT_LOW); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + gpiod_set_consumer_name(gpiod, "GPIO extension data"); + data[i] = gpiod; } gpio_ext->data = data; gpio_ext->num_data = num_data; - ret = of_get_named_gpio(np, "enable-gpio", 0); - if (ret < 0) { + gpiod = gpiod_get(gpio_ext_dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(gpiod)) { dev_err(dev, "Failed to get GPIO from DT property enable-gpio\n"); - return ret; + return PTR_ERR(gpiod); } - gpio_ext->enable = ret; + gpiod_set_consumer_name(gpiod, "GPIO extension enable"); + gpio_ext->enable = gpiod; - return 0; + return devm_add_action_or_reset(dev, netxbig_gpio_ext_remove, gpio_ext); } static int netxbig_leds_get_of_pdata(struct device *dev, @@ -411,6 +421,8 @@ static int netxbig_leds_get_of_pdata(struct device *dev, { struct device_node *np = dev->of_node; struct device_node *gpio_ext_np; + struct platform_device *gpio_ext_pdev; + struct device *gpio_ext_dev; struct device_node *child; struct netxbig_gpio_ext *gpio_ext; struct netxbig_led_timer *timers; @@ -426,13 +438,19 @@ static int netxbig_leds_get_of_pdata(struct device *dev, dev_err(dev, "Failed to get DT handle gpio-ext\n"); return -EINVAL; } + gpio_ext_pdev = of_find_device_by_node(gpio_ext_np); + if (!gpio_ext_pdev) { + dev_err(dev, "Failed to find platform device for gpio-ext\n"); + return -ENODEV; + } + gpio_ext_dev = &gpio_ext_pdev->dev; gpio_ext = devm_kzalloc(dev, sizeof(*gpio_ext), GFP_KERNEL); if (!gpio_ext) { of_node_put(gpio_ext_np); return -ENOMEM; } - ret = gpio_ext_get_of_pdata(dev, gpio_ext_np, gpio_ext); + ret = netxbig_gpio_ext_get(dev, gpio_ext_dev, gpio_ext); of_node_put(gpio_ext_np); if (ret) return ret; @@ -585,10 +603,6 @@ static int netxbig_led_probe(struct platform_device *pdev) if (!leds_data) return -ENOMEM; - ret = gpio_ext_init(pdev, pdata->gpio_ext); - if (ret < 0) - return ret; - for (i = 0; i < pdata->num_leds; i++) { ret = create_netxbig_led(pdev, pdata, &leds_data[i], &pdata->leds[i]); -- cgit