Re: [PATCH v3] leds: implement OpenFirmare GPIO LED driver

Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
From: Trent Piepho
Date: Wednesday, July 16, 2008 - 10:13 pm

on Wed, 16 Jul 2008, Grant Likely wrote:

Ok, how about adding code the existing leds-gpio driver so that it can creates
LEDs from of_platform devices too?

I've made a patch to do this and it works ok.  The code added to leds-gpio is
about half what was involved in Anton's new driver.  What I did was re-factor
the existing platform device probe function to use a new function that creates
a single led.  Then a new of_platform probe function can use it too.  That way
most of the probe code is shared.  remove, suspend and resume aren't shared,
but they're short.  And the existing code to actually drive the led gets
reused as is.

There is still one of_platform device per led because of how the bindings work
(but that could be changed with new bindings), but there are zero extra
platform devices created.

Here's an example patch.  It won't apply to the git kernel as is, but should
make it clear how this works.

diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index a4a2838..12e681e 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -71,11 +71,45 @@ static int gpio_blink_set(struct led_classdev *led_cdev,
  	return led_dat->platform_gpio_blink_set(led_dat->gpio, delay_on, delay_off);
  }

+static int create_gpio_led(struct gpio_led *cur_led,
+	struct gpio_led_data *led_dat, struct device *parent,
+	int (*blink_set)(unsigned, unsigned long *, unsigned long *))
+
+{
+	int ret;
+
+	ret = gpio_request(cur_led->gpio, cur_led->name);
+	if (ret < 0)
+		return ret;
+
+	led_dat->cdev.name = cur_led->name;
+	led_dat->cdev.default_trigger = cur_led->default_trigger;
+	led_dat->gpio = cur_led->gpio;
+	led_dat->can_sleep = gpio_cansleep(cur_led->gpio);
+	led_dat->active_low = cur_led->active_low;
+	if (blink_set) {
+		led_dat->platform_gpio_blink_set = blink_set;
+		led_dat->cdev.blink_set = gpio_blink_set;
+	}
+	led_dat->cdev.brightness_set = gpio_led_set;
+	led_dat->cdev.brightness = cur_led->start_on ? LED_FULL : LED_OFF;
+
+	gpio_direction_output(led_dat->gpio,
+			      led_dat->active_low ^ cur_led->start_on);
+
+	INIT_WORK(&led_dat->work, gpio_led_work);
+
+	ret = led_classdev_register(parent, &led_dat->cdev);
+	if (ret < 0)
+		gpio_free(led_dat->gpio);
+
+	return ret;
+}
+
  static int gpio_led_probe(struct platform_device *pdev)
  {
  	struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
-	struct gpio_led *cur_led;
-	struct gpio_led_data *leds_data, *led_dat;
+	struct gpio_led_data *leds_data;
  	int i, ret = 0;

  	if (!pdata)
@@ -87,36 +121,10 @@ static int gpio_led_probe(struct platform_device *pdev)
  		return -ENOMEM;

  	for (i = 0; i < pdata->num_leds; i++) {
-		cur_led = &pdata->leds[i];
-		led_dat = &leds_data[i];
-
-		ret = gpio_request(cur_led->gpio, cur_led->name);
+		ret = create_gpio_led(&pdata->leds[i], &leds_data[i],
+				      &pdev->dev, pdata->gpio_blink_set);
  		if (ret < 0)
  			goto err;
-
-		led_dat->cdev.name = cur_led->name;
-		led_dat->cdev.default_trigger = cur_led->default_trigger;
-		led_dat->gpio = cur_led->gpio;
-		led_dat->can_sleep = gpio_cansleep(cur_led->gpio);
-		led_dat->active_low = cur_led->active_low;
-		if (pdata->gpio_blink_set) {
-			led_dat->platform_gpio_blink_set = pdata->gpio_blink_set;
-			led_dat->cdev.blink_set = gpio_blink_set;
-		}
-		led_dat->cdev.brightness_set = gpio_led_set;
-		led_dat->cdev.brightness =
-			cur_led->start_on ? LED_FULL : LED_OFF;
-
-		gpio_direction_output(led_dat->gpio,
-				      led_dat->active_low ^ cur_led->start_on);
-
-		INIT_WORK(&led_dat->work, gpio_led_work);
-
-		ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
-		if (ret < 0) {
-			gpio_free(led_dat->gpio);
-			goto err;
-		}
  	}

  	platform_set_drvdata(pdev, leds_data);
@@ -217,3 +225,105 @@ MODULE_AUTHOR("Raphael Assenat <raph@8d.com>");
  MODULE_DESCRIPTION("GPIO LED driver");
  MODULE_LICENSE("GPL");
  MODULE_ALIAS("platform:leds-gpio");
+
+
+/* #ifdef CONFIG_LEDS_GPIO_OF */
+/* OpenFirmware bindings */
+#include <linux/of_platform.h>
+
+/* crap for old kernel, ignore */
+static inline const char *dev_name(struct device *dev)
+{ return dev->bus_id; }
+int of_get_gpio(struct device_node *np, int index)
+{ const u32 *pp = of_get_property(np, "gpio", NULL); return pp ? *pp : -1; }
+
+static int __devinit of_gpio_leds_probe(struct of_device *ofdev,
+					const struct of_device_id *match)
+{
+	struct device_node *np = ofdev->node;
+	struct gpio_led led;
+	struct gpio_led_data *led_dat;
+	int ret;
+
+	led_dat = kzalloc(sizeof(*led_dat), GFP_KERNEL);
+	if (!led_dat)
+		return -ENOMEM;
+
+	memset(&led, 0, sizeof(led));
+	led.gpio = of_get_gpio(np, 0);
+	led.name = of_get_property(np, "label", NULL);
+	if (!led.name)
+		led.name = dev_name(&ofdev->dev);
+
+	ret = create_gpio_led(&led, led_dat, &ofdev->dev, NULL);
+	if (ret < 0) {
+		kfree(led_dat);
+		return ret;
+	}
+
+	dev_set_drvdata(&ofdev->dev, led_dat);
+
+	return 0;
+}
+
+static int __devexit of_gpio_leds_remove(struct of_device *ofdev)
+{
+	struct gpio_led_data *led = dev_get_drvdata(&ofdev->dev);
+
+	led_classdev_unregister(&led->cdev);
+	cancel_work_sync(&led->work);
+	gpio_free(led->gpio);
+	kfree(led);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int of_gpio_led_suspend(struct of_device *ofdev, pm_message_t state)
+{
+	struct gpio_led_data *led = dev_get_drvdata(&ofdev->dev);
+
+	led_classdev_suspend(&led->cdev);
+	return 0;
+}
+
+static int of_gpio_led_resume(struct of_device *ofdev)
+{
+	struct gpio_led_data *led = dev_get_drvdata(&ofdev->dev);
+
+	led_classdev_resume(&led->cdev);
+	return 0;
+}
+#else
+#define of_gpio_led_suspend NULL
+#define of_gpio_led_resume NULL
+#endif /* CONFIG_PM */
+
+static const struct of_device_id of_gpio_leds_match[] = {
+	{ .compatible = "gpio-led", },
+	{},
+};
+
+static struct of_platform_driver of_gpio_leds_driver = {
+	.driver = {
+		.name = "of_gpio_leds",
+		.owner = THIS_MODULE,
+	},
+	.match_table = of_gpio_leds_match,
+	.probe = of_gpio_leds_probe,
+	.remove = __devexit_p(of_gpio_leds_remove),
+	.suspend = of_gpio_led_suspend,
+	.resume = of_gpio_led_resume,
+};
+
+static int __init of_gpio_leds_init(void)
+{
+	return of_register_platform_driver(&of_gpio_leds_driver);
+}
+module_init(of_gpio_leds_init);
+
+static void __exit of_gpio_leds_exit(void)
+{
+	of_unregister_platform_driver(&of_gpio_leds_driver);
+}
+module_exit(of_gpio_leds_exit);
--
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
[PATCH] leds: implement OpenFirmare GPIO LED driver, Anton Vorontsov, (Mon Jul 14, 9:41 am)
Re: [PATCH] leds: implement OpenFirmare GPIO LED driver, Stephen Rothwell, (Mon Jul 14, 8:10 pm)
Re: [PATCH] leds: implement OpenFirmare GPIO LED driver, Anton Vorontsov, (Tue Jul 15, 5:38 am)
[PATCH v2] leds: implement OpenFirmare GPIO LED driver, Anton Vorontsov, (Tue Jul 15, 5:40 am)
Re: [PATCH v2] leds: implement OpenFirmare GPIO LED driver, Richard Purdie, (Tue Jul 15, 5:54 am)
Re: [PATCH v2] leds: implement OpenFirmare GPIO LED driver, Anton Vorontsov, (Tue Jul 15, 6:24 am)
Re: [PATCH v2] leds: implement OpenFirmare GPIO LED driver, Richard Purdie, (Tue Jul 15, 6:31 am)
Re: [PATCH v2] leds: implement OpenFirmare GPIO LED driver, Anton Vorontsov, (Tue Jul 15, 7:23 am)
Re: [PATCH v2] leds: implement OpenFirmare GPIO LED driver, Richard Purdie, (Tue Jul 15, 7:43 am)
[PATCH v3] leds: implement OpenFirmare GPIO LED driver, Anton Vorontsov, (Tue Jul 15, 8:19 am)
Re: [PATCH v3] leds: implement OpenFirmare GPIO LED driver, Trent Piepho, (Wed Jul 16, 10:13 pm)
Re: [PATCH] leds: implement OpenFirmare GPIO LED driver, Segher Boessenkool, (Wed Jul 16, 10:59 pm)
Re: [PATCH] leds: implement OpenFirmare GPIO LED driver, Anton Vorontsov, (Thu Jul 17, 4:07 am)
Re: [PATCH v3] leds: implement OpenFirmare GPIO LED driver, Anton Vorontsov, (Thu Jul 17, 6:55 am)
Re: [PATCH v3] leds: implement OpenFirmare GPIO LED driver, Anton Vorontsov, (Thu Jul 17, 7:05 am)
Re: [PATCH v3] leds: implement OpenFirmare GPIO LED driver, Anton Vorontsov, (Thu Jul 17, 7:13 am)
Re: [PATCH] leds: implement OpenFirmare GPIO LED driver, Sean MacLennan, (Thu Jul 17, 7:58 am)
Re: [PATCH] leds: implement OpenFirmare GPIO LED driver, Grant Likely, (Thu Jul 17, 8:07 am)
Re: [PATCH v3] leds: implement OpenFirmare GPIO LED driver, Anton Vorontsov, (Thu Jul 17, 8:20 am)
Re: [PATCH v3] leds: implement OpenFirmare GPIO LED driver, Anton Vorontsov, (Thu Jul 17, 4:42 pm)
Re: [PATCH] leds: implement OpenFirmare GPIO LED driver, David Gibson, (Thu Jul 17, 8:35 pm)
Re: [PATCH] leds: implement OpenFirmare GPIO LED driver, Grant Likely, (Thu Jul 17, 9:44 pm)
Re: [PATCH v3] leds: implement OpenFirmare GPIO LED driver, Anton Vorontsov, (Fri Jul 18, 3:05 am)
Re: PIXIS gpio controller and gpio flags, Trent Piepho, (Sat Jul 19, 2:08 pm)
Re: PIXIS gpio controller and gpio flags, Anton Vorontsov, (Mon Jul 21, 10:53 am)
Re: PIXIS gpio controller and gpio flags, Trent Piepho, (Mon Jul 21, 2:12 pm)
Re: PIXIS gpio controller and gpio flags, Anton Vorontsov, (Wed Jul 23, 7:56 am)
Re: PIXIS gpio controller and gpio flags, Trent Piepho, (Wed Jul 23, 4:42 pm)
[RFC PATCH] of_gpio: implement of_get_gpio_flags(), Anton Vorontsov, (Fri Jul 25, 9:48 am)
[PATCH 1/2] leds: make the default trigger name const, Trent Piepho, (Fri Jul 25, 2:01 pm)
[PATCH 2/2] leds: Support OpenFirmware led bindings, Trent Piepho, (Fri Jul 25, 2:01 pm)
Re: [RFC PATCH] of_gpio: implement of_get_gpio_flags(), Trent Piepho, (Sat Jul 26, 1:26 am)
Re: [PATCH 2/2] leds: Support OpenFirmware led bindings, Grant Likely, (Sat Jul 26, 7:21 pm)
Re: [PATCH 1/2] leds: make the default trigger name const, Stephen Rothwell, (Sun Jul 27, 6:11 am)
[PATCH v2] leds: make the default trigger name const, Trent Piepho, (Sun Jul 27, 7:02 pm)
Re: [PATCH 2/2] leds: Support OpenFirmware led bindings, Trent Piepho, (Mon Jul 28, 1:31 am)
Re: [PATCH 1/2] leds: make the default trigger name const, Anton Vorontsov, (Mon Jul 28, 2:53 am)
Re: [PATCH 2/2] leds: Support OpenFirmware led bindings, Grant Likely, (Mon Jul 28, 10:09 am)
Re: [PATCH 2/2] leds: Support OpenFirmware led bindings, Anton Vorontsov, (Mon Jul 28, 11:02 am)
Re: [PATCH 2/2] leds: Support OpenFirmware led bindings, Grant Likely, (Mon Jul 28, 11:06 am)
Re: [PATCH 2/2] leds: Support OpenFirmware led bindings, Trent Piepho, (Mon Jul 28, 11:26 am)
Re: [PATCH 2/2] leds: Support OpenFirmware led bindings, Grant Likely, (Mon Jul 28, 11:49 am)
Re: [PATCH 2/2] leds: Support OpenFirmware led bindings, Anton Vorontsov, (Mon Jul 28, 11:51 am)
Re: [PATCH 2/2] leds: Support OpenFirmware led bindings, Trent Piepho, (Mon Jul 28, 12:11 pm)