From 82dfe46f68342b3139b4df33cf3f782ab6d52dd9 Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen <lars@metafoo.de>
Date: Thu, 13 May 2010 23:20:53 +0200
Subject: [PATCH 34/69] LEDS: leds-pwm: Add init, notfiy and exit callbacks

This patch adds init, notify and exit callbacks to the leds-pwm driver similar
to those seen for the pwm-backlight driver;

On certain platforms with pin muxing the output of a pwm pin is bogus until the
pwm is been properly configured. On these platforms it is usefull to have the
added callbacks, so that the gpio pin can be configured after the pwm device has
been successfully configured.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/leds/leds-pwm.c  |   29 ++++++++++++++++++++++++-----
 include/linux/leds_pwm.h |   20 ++++++++++++++++++++
 2 files changed, 44 insertions(+), 5 deletions(-)

diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index 666daf7..46fac25 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -26,8 +26,8 @@
 struct led_pwm_data {
 	struct led_classdev	cdev;
 	struct pwm_device	*pwm;
-	unsigned int 		active_low;
-	unsigned int		period;
+	struct led_pwm		*led;
+	struct device		*parent;
 };
 
 static void led_pwm_set(struct led_classdev *led_cdev,
@@ -35,8 +35,13 @@ static void led_pwm_set(struct led_classdev *led_cdev,
 {
 	struct led_pwm_data *led_dat =
 		container_of(led_cdev, struct led_pwm_data, cdev);
+	struct device *parent = led_dat->parent;
+	struct led_pwm_platform_data *pdata = parent->platform_data;
 	unsigned int max = led_dat->cdev.max_brightness;
-	unsigned int period =  led_dat->period;
+	unsigned int period =  led_dat->led->pwm_period_ns;
+
+	if (pdata->notify)
+	    brightness = pdata->notify(parent, led_dat->led, brightness);
 
 	if (brightness == 0) {
 		pwm_config(led_dat->pwm, 0, period);
@@ -77,18 +82,28 @@ static int led_pwm_probe(struct platform_device *pdev)
 
 		led_dat->cdev.name = cur_led->name;
 		led_dat->cdev.default_trigger = cur_led->default_trigger;
-		led_dat->active_low = cur_led->active_low;
-		led_dat->period = cur_led->pwm_period_ns;
 		led_dat->cdev.brightness_set = led_pwm_set;
 		led_dat->cdev.brightness = LED_OFF;
 		led_dat->cdev.max_brightness = cur_led->max_brightness;
 		led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
 
+		led_dat->led = cur_led;
+		led_dat->parent = &pdev->dev;
+
 		ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
 		if (ret < 0) {
 			pwm_free(led_dat->pwm);
 			goto err;
 		}
+
+		if (pdata->init) {
+			ret = pdata->init(&pdev->dev, cur_led);
+			if (ret < 0) {
+				led_classdev_unregister(&led_dat->cdev);
+				pwm_free(led_dat->pwm);
+				goto err;
+			}
+		}
 	}
 
 	platform_set_drvdata(pdev, leds_data);
@@ -98,6 +113,8 @@ static int led_pwm_probe(struct platform_device *pdev)
 err:
 	if (i > 0) {
 		for (i = i - 1; i >= 0; i--) {
+			if (pdata->exit)
+				pdata->exit(&pdev->dev, &pdata->leds[i]);
 			led_classdev_unregister(&leds_data[i].cdev);
 			pwm_free(leds_data[i].pwm);
 		}
@@ -117,6 +134,8 @@ static int __devexit led_pwm_remove(struct platform_device *pdev)
 	leds_data = platform_get_drvdata(pdev);
 
 	for (i = 0; i < pdata->num_leds; i++) {
+		if (pdata->exit)
+			pdata->exit(&pdev->dev, &pdata->leds[i]);
 		led_classdev_unregister(&leds_data[i].cdev);
 		pwm_free(leds_data[i].pwm);
 	}
diff --git a/include/linux/leds_pwm.h b/include/linux/leds_pwm.h
index 33a0711..42d4969 100644
--- a/include/linux/leds_pwm.h
+++ b/include/linux/leds_pwm.h
@@ -16,6 +16,26 @@ struct led_pwm {
 struct led_pwm_platform_data {
 	int			num_leds;
 	struct led_pwm	*leds;
+
+	/* @init: The init callback is called after the pwm device for a led has
+	 * been successfully configured. If the return value is negative it will be
+	 * seen as an error and initzalisation of the leds-pwm device will fail.
+	 */
+	int (*init)(struct device *dev, struct led_pwm *led);
+
+	/* @notify: The notify callback is called whenever the brightness of a led
+	 * is changed.
+	 * The return value of the callback will be the brightness which is used to
+	 * configure the pwm device.
+	 */
+	enum led_brightness (*notify)(struct device *dev, struct led_pwm *led,
+	    enum led_brightness brightness);
+
+	/* @exit: The exit callback is called, whenever a led device registered by
+	 * the leds-pwm device is unregistered. It will be called prior to freeing
+	 * the pwm device.
+	 */
+	void (*exit)(struct device *dev, struct led_pwm *led);
 };
 
 #endif
-- 
1.7.2.5

