Version:  2.0.40 2.2.26 2.4.37 2.6.39 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15

Linux/drivers/leds/leds-regulator.c

  1 /*
  2  * leds-regulator.c - LED class driver for regulator driven LEDs.
  3  *
  4  * Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it>
  5  *
  6  * Inspired by leds-wm8350 driver.
  7  *
  8  * This program is free software; you can redistribute it and/or modify
  9  * it under the terms of the GNU General Public License version 2 as
 10  * published by the Free Software Foundation.
 11  *
 12  */
 13 
 14 #include <linux/module.h>
 15 #include <linux/err.h>
 16 #include <linux/slab.h>
 17 #include <linux/workqueue.h>
 18 #include <linux/leds.h>
 19 #include <linux/leds-regulator.h>
 20 #include <linux/platform_device.h>
 21 #include <linux/regulator/consumer.h>
 22 
 23 #define to_regulator_led(led_cdev) \
 24         container_of(led_cdev, struct regulator_led, cdev)
 25 
 26 struct regulator_led {
 27         struct led_classdev cdev;
 28         enum led_brightness value;
 29         int enabled;
 30         struct mutex mutex;
 31         struct work_struct work;
 32 
 33         struct regulator *vcc;
 34 };
 35 
 36 static inline int led_regulator_get_max_brightness(struct regulator *supply)
 37 {
 38         int ret;
 39         int voltage = regulator_list_voltage(supply, 0);
 40 
 41         if (voltage <= 0)
 42                 return 1;
 43 
 44         /* even if regulator can't change voltages,
 45          * we still assume it can change status
 46          * and the LED can be turned on and off.
 47          */
 48         ret = regulator_set_voltage(supply, voltage, voltage);
 49         if (ret < 0)
 50                 return 1;
 51 
 52         return regulator_count_voltages(supply);
 53 }
 54 
 55 static int led_regulator_get_voltage(struct regulator *supply,
 56                 enum led_brightness brightness)
 57 {
 58         if (brightness == 0)
 59                 return -EINVAL;
 60 
 61         return regulator_list_voltage(supply, brightness - 1);
 62 }
 63 
 64 
 65 static void regulator_led_enable(struct regulator_led *led)
 66 {
 67         int ret;
 68 
 69         if (led->enabled)
 70                 return;
 71 
 72         ret = regulator_enable(led->vcc);
 73         if (ret != 0) {
 74                 dev_err(led->cdev.dev, "Failed to enable vcc: %d\n", ret);
 75                 return;
 76         }
 77 
 78         led->enabled = 1;
 79 }
 80 
 81 static void regulator_led_disable(struct regulator_led *led)
 82 {
 83         int ret;
 84 
 85         if (!led->enabled)
 86                 return;
 87 
 88         ret = regulator_disable(led->vcc);
 89         if (ret != 0) {
 90                 dev_err(led->cdev.dev, "Failed to disable vcc: %d\n", ret);
 91                 return;
 92         }
 93 
 94         led->enabled = 0;
 95 }
 96 
 97 static void regulator_led_set_value(struct regulator_led *led)
 98 {
 99         int voltage;
100         int ret;
101 
102         mutex_lock(&led->mutex);
103 
104         if (led->value == LED_OFF) {
105                 regulator_led_disable(led);
106                 goto out;
107         }
108 
109         if (led->cdev.max_brightness > 1) {
110                 voltage = led_regulator_get_voltage(led->vcc, led->value);
111                 dev_dbg(led->cdev.dev, "brightness: %d voltage: %d\n",
112                                 led->value, voltage);
113 
114                 ret = regulator_set_voltage(led->vcc, voltage, voltage);
115                 if (ret != 0)
116                         dev_err(led->cdev.dev, "Failed to set voltage %d: %d\n",
117                                 voltage, ret);
118         }
119 
120         regulator_led_enable(led);
121 
122 out:
123         mutex_unlock(&led->mutex);
124 }
125 
126 static void led_work(struct work_struct *work)
127 {
128         struct regulator_led *led;
129 
130         led = container_of(work, struct regulator_led, work);
131         regulator_led_set_value(led);
132 }
133 
134 static void regulator_led_brightness_set(struct led_classdev *led_cdev,
135                            enum led_brightness value)
136 {
137         struct regulator_led *led = to_regulator_led(led_cdev);
138 
139         led->value = value;
140         schedule_work(&led->work);
141 }
142 
143 static int regulator_led_probe(struct platform_device *pdev)
144 {
145         struct led_regulator_platform_data *pdata =
146                         dev_get_platdata(&pdev->dev);
147         struct regulator_led *led;
148         struct regulator *vcc;
149         int ret = 0;
150 
151         if (pdata == NULL) {
152                 dev_err(&pdev->dev, "no platform data\n");
153                 return -ENODEV;
154         }
155 
156         vcc = regulator_get_exclusive(&pdev->dev, "vled");
157         if (IS_ERR(vcc)) {
158                 dev_err(&pdev->dev, "Cannot get vcc for %s\n", pdata->name);
159                 return PTR_ERR(vcc);
160         }
161 
162         led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
163         if (led == NULL) {
164                 ret = -ENOMEM;
165                 goto err_vcc;
166         }
167 
168         led->cdev.max_brightness = led_regulator_get_max_brightness(vcc);
169         if (pdata->brightness > led->cdev.max_brightness) {
170                 dev_err(&pdev->dev, "Invalid default brightness %d\n",
171                                 pdata->brightness);
172                 ret = -EINVAL;
173                 goto err_vcc;
174         }
175         led->value = pdata->brightness;
176 
177         led->cdev.brightness_set = regulator_led_brightness_set;
178         led->cdev.name = pdata->name;
179         led->cdev.flags |= LED_CORE_SUSPENDRESUME;
180         led->vcc = vcc;
181 
182         /* to handle correctly an already enabled regulator */
183         if (regulator_is_enabled(led->vcc))
184                 led->enabled = 1;
185 
186         mutex_init(&led->mutex);
187         INIT_WORK(&led->work, led_work);
188 
189         platform_set_drvdata(pdev, led);
190 
191         ret = led_classdev_register(&pdev->dev, &led->cdev);
192         if (ret < 0) {
193                 cancel_work_sync(&led->work);
194                 goto err_vcc;
195         }
196 
197         /* to expose the default value to userspace */
198         led->cdev.brightness = led->value;
199 
200         /* Set the default led status */
201         regulator_led_set_value(led);
202 
203         return 0;
204 
205 err_vcc:
206         regulator_put(vcc);
207         return ret;
208 }
209 
210 static int regulator_led_remove(struct platform_device *pdev)
211 {
212         struct regulator_led *led = platform_get_drvdata(pdev);
213 
214         led_classdev_unregister(&led->cdev);
215         cancel_work_sync(&led->work);
216         regulator_led_disable(led);
217         regulator_put(led->vcc);
218         return 0;
219 }
220 
221 static struct platform_driver regulator_led_driver = {
222         .driver = {
223                    .name  = "leds-regulator",
224                    .owner = THIS_MODULE,
225                    },
226         .probe  = regulator_led_probe,
227         .remove = regulator_led_remove,
228 };
229 
230 module_platform_driver(regulator_led_driver);
231 
232 MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
233 MODULE_DESCRIPTION("Regulator driven LED driver");
234 MODULE_LICENSE("GPL");
235 MODULE_ALIAS("platform:leds-regulator");
236 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us