aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/leds/Kconfig1
-rw-r--r--drivers/leds/leds-lp55xx-common.c117
-rw-r--r--drivers/leds/leds-lp55xx-common.h19
3 files changed, 137 insertions, 0 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 3d7822b3498f..fc680a9ed841 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -196,6 +196,7 @@ config LEDS_LP3944
196config LEDS_LP55XX_COMMON 196config LEDS_LP55XX_COMMON
197 tristate "Common Driver for TI/National LP5521 and LP5523/55231" 197 tristate "Common Driver for TI/National LP5521 and LP5523/55231"
198 depends on LEDS_LP5521 || LEDS_LP5523 198 depends on LEDS_LP5521 || LEDS_LP5523
199 select FW_LOADER
199 help 200 help
200 This option supports common operations for LP5521 and LP5523/55231 201 This option supports common operations for LP5521 and LP5523/55231
201 devices. 202 devices.
diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c
index 98407ca45e4f..578902ab604f 100644
--- a/drivers/leds/leds-lp55xx-common.c
+++ b/drivers/leds/leds-lp55xx-common.c
@@ -13,6 +13,7 @@
13 */ 13 */
14 14
15#include <linux/delay.h> 15#include <linux/delay.h>
16#include <linux/firmware.h>
16#include <linux/i2c.h> 17#include <linux/i2c.h>
17#include <linux/leds.h> 18#include <linux/leds.h>
18#include <linux/module.h> 19#include <linux/module.h>
@@ -197,7 +198,123 @@ static int lp55xx_init_led(struct lp55xx_led *led,
197 return 0; 198 return 0;
198} 199}
199 200
201static void lp55xx_firmware_loaded(const struct firmware *fw, void *context)
202{
203 struct lp55xx_chip *chip = context;
204 struct device *dev = &chip->cl->dev;
205
206 if (!fw) {
207 dev_err(dev, "firmware request failed\n");
208 goto out;
209 }
210
211 /* handling firmware data is chip dependent */
212 mutex_lock(&chip->lock);
213
214 chip->fw = fw;
215 if (chip->cfg->firmware_cb)
216 chip->cfg->firmware_cb(chip);
217
218 mutex_unlock(&chip->lock);
219
220out:
221 /* firmware should be released for other channel use */
222 release_firmware(chip->fw);
223}
224
225static int lp55xx_request_firmware(struct lp55xx_chip *chip)
226{
227 const char *name = chip->cl->name;
228 struct device *dev = &chip->cl->dev;
229
230 return request_firmware_nowait(THIS_MODULE, true, name, dev,
231 GFP_KERNEL, chip, lp55xx_firmware_loaded);
232}
233
234static ssize_t lp55xx_show_engine_select(struct device *dev,
235 struct device_attribute *attr,
236 char *buf)
237{
238 struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
239 struct lp55xx_chip *chip = led->chip;
240
241 return sprintf(buf, "%d\n", chip->engine_idx);
242}
243
244static ssize_t lp55xx_store_engine_select(struct device *dev,
245 struct device_attribute *attr,
246 const char *buf, size_t len)
247{
248 struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
249 struct lp55xx_chip *chip = led->chip;
250 unsigned long val;
251 int ret;
252
253 if (kstrtoul(buf, 0, &val))
254 return -EINVAL;
255
256 /* select the engine to be run */
257
258 switch (val) {
259 case LP55XX_ENGINE_1:
260 case LP55XX_ENGINE_2:
261 case LP55XX_ENGINE_3:
262 mutex_lock(&chip->lock);
263 chip->engine_idx = val;
264 ret = lp55xx_request_firmware(chip);
265 mutex_unlock(&chip->lock);
266 break;
267 default:
268 dev_err(dev, "%lu: invalid engine index. (1, 2, 3)\n", val);
269 return -EINVAL;
270 }
271
272 if (ret) {
273 dev_err(dev, "request firmware err: %d\n", ret);
274 return ret;
275 }
276
277 return len;
278}
279
280static inline void lp55xx_run_engine(struct lp55xx_chip *chip, bool start)
281{
282 if (chip->cfg->run_engine)
283 chip->cfg->run_engine(chip, start);
284}
285
286static ssize_t lp55xx_store_engine_run(struct device *dev,
287 struct device_attribute *attr,
288 const char *buf, size_t len)
289{
290 struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
291 struct lp55xx_chip *chip = led->chip;
292 unsigned long val;
293
294 if (kstrtoul(buf, 0, &val))
295 return -EINVAL;
296
297 /* run or stop the selected engine */
298
299 if (val <= 0) {
300 lp55xx_run_engine(chip, false);
301 return len;
302 }
303
304 mutex_lock(&chip->lock);
305 lp55xx_run_engine(chip, true);
306 mutex_unlock(&chip->lock);
307
308 return len;
309}
310
311static DEVICE_ATTR(select_engine, S_IRUGO | S_IWUSR,
312 lp55xx_show_engine_select, lp55xx_store_engine_select);
313static DEVICE_ATTR(run_engine, S_IWUSR, NULL, lp55xx_store_engine_run);
314
200static struct attribute *lp55xx_engine_attributes[] = { 315static struct attribute *lp55xx_engine_attributes[] = {
316 &dev_attr_select_engine.attr,
317 &dev_attr_run_engine.attr,
201 NULL, 318 NULL,
202}; 319};
203 320
diff --git a/drivers/leds/leds-lp55xx-common.h b/drivers/leds/leds-lp55xx-common.h
index d0be837643f0..8473abf9830c 100644
--- a/drivers/leds/leds-lp55xx-common.h
+++ b/drivers/leds/leds-lp55xx-common.h
@@ -15,6 +15,13 @@
15#ifndef _LEDS_LP55XX_COMMON_H 15#ifndef _LEDS_LP55XX_COMMON_H
16#define _LEDS_LP55XX_COMMON_H 16#define _LEDS_LP55XX_COMMON_H
17 17
18enum lp55xx_engine_index {
19 LP55XX_ENGINE_INVALID,
20 LP55XX_ENGINE_1,
21 LP55XX_ENGINE_2,
22 LP55XX_ENGINE_3,
23};
24
18struct lp55xx_led; 25struct lp55xx_led;
19struct lp55xx_chip; 26struct lp55xx_chip;
20 27
@@ -36,6 +43,8 @@ struct lp55xx_reg {
36 * @post_init_device : Chip specific initialization code 43 * @post_init_device : Chip specific initialization code
37 * @brightness_work_fn : Brightness work function 44 * @brightness_work_fn : Brightness work function
38 * @set_led_current : LED current set function 45 * @set_led_current : LED current set function
46 * @firmware_cb : Call function when the firmware is loaded
47 * @run_engine : Run internal engine for pattern
39 */ 48 */
40struct lp55xx_device_config { 49struct lp55xx_device_config {
41 const struct lp55xx_reg reset; 50 const struct lp55xx_reg reset;
@@ -50,6 +59,12 @@ struct lp55xx_device_config {
50 59
51 /* current setting function */ 60 /* current setting function */
52 void (*set_led_current) (struct lp55xx_led *led, u8 led_current); 61 void (*set_led_current) (struct lp55xx_led *led, u8 led_current);
62
63 /* access program memory when the firmware is loaded */
64 void (*firmware_cb)(struct lp55xx_chip *chip);
65
66 /* used for running firmware LED patterns */
67 void (*run_engine) (struct lp55xx_chip *chip, bool start);
53}; 68};
54 69
55/* 70/*
@@ -59,6 +74,8 @@ struct lp55xx_device_config {
59 * @lock : Lock for user-space interface 74 * @lock : Lock for user-space interface
60 * @num_leds : Number of registered LEDs 75 * @num_leds : Number of registered LEDs
61 * @cfg : Device specific configuration data 76 * @cfg : Device specific configuration data
77 * @engine_idx : Selected engine number
78 * @fw : Firmware data for running a LED pattern
62 */ 79 */
63struct lp55xx_chip { 80struct lp55xx_chip {
64 struct i2c_client *cl; 81 struct i2c_client *cl;
@@ -66,6 +83,8 @@ struct lp55xx_chip {
66 struct mutex lock; /* lock for user-space interface */ 83 struct mutex lock; /* lock for user-space interface */
67 int num_leds; 84 int num_leds;
68 struct lp55xx_device_config *cfg; 85 struct lp55xx_device_config *cfg;
86 enum lp55xx_engine_index engine_idx;
87 const struct firmware *fw;
69}; 88};
70 89
71/* 90/*