diff options
author | Milo(Woogyom) Kim <milo.kim@ti.com> | 2013-02-05 05:18:10 -0500 |
---|---|---|
committer | Bryan Wu <cooloney@gmail.com> | 2013-02-06 18:59:29 -0500 |
commit | 9ce7cb170f97f83a78dc948bf7d25690f15e1328 (patch) | |
tree | 3c575cd93f9d09c7f7b6fc93a5336e3f59cba2c2 /drivers | |
parent | 10c06d178df11b0b2b746321a80ea14241997127 (diff) |
leds-lp5521: use generic firmware interface
LP55xx common driver provides generic firmware interface
for running a LED pattern.
LP5521 and LP5523 have many device attributes for running patterns.
This patch cleans up those complex code.
Removed device attributes:
engine1_mode
engine2_mode
engine3_mode
engine1_load
engine2_load
engine3_load
led_pattern
All device attributes and functions are replaced with two callback functions,
'firmware_cb' and 'run_engine'.
New engine functions:
lp5521_load/stop/run_engine(), lp5521_update_program_memory() and
lp5521_wait_opmode_done()
Signed-off-by: Milo(Woogyom) Kim <milo.kim@ti.com>
Signed-off-by: Bryan Wu <cooloney@gmail.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/leds/leds-lp5521.c | 414 |
1 files changed, 163 insertions, 251 deletions
diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index cec252eae716..89371e065c13 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/workqueue.h> | 35 | #include <linux/workqueue.h> |
36 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
37 | #include <linux/platform_data/leds-lp55xx.h> | 37 | #include <linux/platform_data/leds-lp55xx.h> |
38 | #include <linux/firmware.h> | ||
38 | 39 | ||
39 | #include "leds-lp55xx-common.h" | 40 | #include "leds-lp55xx-common.h" |
40 | 41 | ||
@@ -101,12 +102,28 @@ | |||
101 | /* Reset register value */ | 102 | /* Reset register value */ |
102 | #define LP5521_RESET 0xFF | 103 | #define LP5521_RESET 0xFF |
103 | 104 | ||
104 | struct lp5521_engine { | 105 | /* Program Memory Operations */ |
105 | int id; | 106 | #define LP5521_MODE_R_M 0x30 /* Operation Mode Register */ |
106 | u8 mode; | 107 | #define LP5521_MODE_G_M 0x0C |
107 | u8 prog_page; | 108 | #define LP5521_MODE_B_M 0x03 |
108 | u8 engine_mask; | 109 | #define LP5521_LOAD_R 0x10 |
109 | }; | 110 | #define LP5521_LOAD_G 0x04 |
111 | #define LP5521_LOAD_B 0x01 | ||
112 | |||
113 | #define LP5521_R_IS_LOADING(mode) \ | ||
114 | ((mode & LP5521_MODE_R_M) == LP5521_LOAD_R) | ||
115 | #define LP5521_G_IS_LOADING(mode) \ | ||
116 | ((mode & LP5521_MODE_G_M) == LP5521_LOAD_G) | ||
117 | #define LP5521_B_IS_LOADING(mode) \ | ||
118 | ((mode & LP5521_MODE_B_M) == LP5521_LOAD_B) | ||
119 | |||
120 | #define LP5521_EXEC_R_M 0x30 /* Enable Register */ | ||
121 | #define LP5521_EXEC_G_M 0x0C | ||
122 | #define LP5521_EXEC_B_M 0x03 | ||
123 | #define LP5521_EXEC_M 0x3F | ||
124 | #define LP5521_RUN_R 0x20 | ||
125 | #define LP5521_RUN_G 0x08 | ||
126 | #define LP5521_RUN_B 0x02 | ||
110 | 127 | ||
111 | struct lp5521_led { | 128 | struct lp5521_led { |
112 | int id; | 129 | int id; |
@@ -122,12 +139,17 @@ struct lp5521_chip { | |||
122 | struct lp5521_platform_data *pdata; | 139 | struct lp5521_platform_data *pdata; |
123 | struct mutex lock; /* Serialize control */ | 140 | struct mutex lock; /* Serialize control */ |
124 | struct i2c_client *client; | 141 | struct i2c_client *client; |
125 | struct lp5521_engine engines[LP5521_MAX_ENGINES]; | ||
126 | struct lp5521_led leds[LP5521_MAX_LEDS]; | 142 | struct lp5521_led leds[LP5521_MAX_LEDS]; |
127 | u8 num_channels; | 143 | u8 num_channels; |
128 | u8 num_leds; | 144 | u8 num_leds; |
129 | }; | 145 | }; |
130 | 146 | ||
147 | static inline void lp5521_wait_opmode_done(void) | ||
148 | { | ||
149 | /* operation mode change needs to be longer than 153 us */ | ||
150 | usleep_range(200, 300); | ||
151 | } | ||
152 | |||
131 | static inline void lp5521_wait_enable_done(void) | 153 | static inline void lp5521_wait_enable_done(void) |
132 | { | 154 | { |
133 | /* it takes more 488 us to update ENABLE register */ | 155 | /* it takes more 488 us to update ENABLE register */ |
@@ -141,23 +163,6 @@ static void lp5521_set_led_current(struct lp55xx_led *led, u8 led_current) | |||
141 | led_current); | 163 | led_current); |
142 | } | 164 | } |
143 | 165 | ||
144 | static inline struct lp5521_led *cdev_to_led(struct led_classdev *cdev) | ||
145 | { | ||
146 | return container_of(cdev, struct lp5521_led, cdev); | ||
147 | } | ||
148 | |||
149 | static inline struct lp5521_chip *engine_to_lp5521(struct lp5521_engine *engine) | ||
150 | { | ||
151 | return container_of(engine, struct lp5521_chip, | ||
152 | engines[engine->id - 1]); | ||
153 | } | ||
154 | |||
155 | static inline struct lp5521_chip *led_to_lp5521(struct lp5521_led *led) | ||
156 | { | ||
157 | return container_of(led, struct lp5521_chip, | ||
158 | leds[led->id]); | ||
159 | } | ||
160 | |||
161 | static inline int lp5521_write(struct i2c_client *client, u8 reg, u8 value) | 166 | static inline int lp5521_write(struct i2c_client *client, u8 reg, u8 value) |
162 | { | 167 | { |
163 | return i2c_smbus_write_byte_data(client, reg, value); | 168 | return i2c_smbus_write_byte_data(client, reg, value); |
@@ -175,65 +180,153 @@ static int lp5521_read(struct i2c_client *client, u8 reg, u8 *buf) | |||
175 | return 0; | 180 | return 0; |
176 | } | 181 | } |
177 | 182 | ||
178 | static int lp5521_set_engine_mode(struct lp5521_engine *engine, u8 mode) | 183 | static void lp5521_load_engine(struct lp55xx_chip *chip) |
179 | { | 184 | { |
180 | struct lp5521_chip *chip = engine_to_lp5521(engine); | 185 | enum lp55xx_engine_index idx = chip->engine_idx; |
181 | struct i2c_client *client = chip->client; | 186 | u8 mask[] = { |
182 | int ret; | 187 | [LP55XX_ENGINE_1] = LP5521_MODE_R_M, |
183 | u8 engine_state; | 188 | [LP55XX_ENGINE_2] = LP5521_MODE_G_M, |
189 | [LP55XX_ENGINE_3] = LP5521_MODE_B_M, | ||
190 | }; | ||
184 | 191 | ||
185 | /* Only transition between RUN and DIRECT mode are handled here */ | 192 | u8 val[] = { |
186 | if (mode == LP5521_CMD_LOAD) | 193 | [LP55XX_ENGINE_1] = LP5521_LOAD_R, |
187 | return 0; | 194 | [LP55XX_ENGINE_2] = LP5521_LOAD_G, |
195 | [LP55XX_ENGINE_3] = LP5521_LOAD_B, | ||
196 | }; | ||
188 | 197 | ||
189 | if (mode == LP5521_CMD_DISABLED) | 198 | lp55xx_update_bits(chip, LP5521_REG_OP_MODE, mask[idx], val[idx]); |
190 | mode = LP5521_CMD_DIRECT; | ||
191 | 199 | ||
192 | ret = lp5521_read(client, LP5521_REG_OP_MODE, &engine_state); | 200 | lp5521_wait_opmode_done(); |
193 | if (ret < 0) | 201 | } |
194 | return ret; | ||
195 | 202 | ||
196 | /* set mode only for this engine */ | 203 | static void lp5521_stop_engine(struct lp55xx_chip *chip) |
197 | engine_state &= ~(engine->engine_mask); | 204 | { |
198 | mode &= engine->engine_mask; | 205 | lp55xx_write(chip, LP5521_REG_OP_MODE, 0); |
199 | engine_state |= mode; | 206 | lp5521_wait_opmode_done(); |
200 | return lp5521_write(client, LP5521_REG_OP_MODE, engine_state); | ||
201 | } | 207 | } |
202 | 208 | ||
203 | static int lp5521_load_program(struct lp5521_engine *eng, const u8 *pattern) | 209 | static void lp5521_run_engine(struct lp55xx_chip *chip, bool start) |
204 | { | 210 | { |
205 | struct lp5521_chip *chip = engine_to_lp5521(eng); | ||
206 | struct i2c_client *client = chip->client; | ||
207 | int ret; | 211 | int ret; |
208 | int addr; | ||
209 | u8 mode; | 212 | u8 mode; |
213 | u8 exec; | ||
210 | 214 | ||
211 | /* move current engine to direct mode and remember the state */ | 215 | /* stop engine */ |
212 | ret = lp5521_set_engine_mode(eng, LP5521_CMD_DIRECT); | 216 | if (!start) { |
217 | lp5521_stop_engine(chip); | ||
218 | lp55xx_write(chip, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT); | ||
219 | lp5521_wait_opmode_done(); | ||
220 | return; | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * To run the engine, | ||
225 | * operation mode and enable register should updated at the same time | ||
226 | */ | ||
227 | |||
228 | ret = lp55xx_read(chip, LP5521_REG_OP_MODE, &mode); | ||
213 | if (ret) | 229 | if (ret) |
214 | return ret; | 230 | return; |
215 | 231 | ||
216 | /* Mode change requires min 500 us delay. 1 - 2 ms with margin */ | 232 | ret = lp55xx_read(chip, LP5521_REG_ENABLE, &exec); |
217 | usleep_range(1000, 2000); | ||
218 | ret = lp5521_read(client, LP5521_REG_OP_MODE, &mode); | ||
219 | if (ret) | 233 | if (ret) |
220 | return ret; | 234 | return; |
235 | |||
236 | /* change operation mode to RUN only when each engine is loading */ | ||
237 | if (LP5521_R_IS_LOADING(mode)) { | ||
238 | mode = (mode & ~LP5521_MODE_R_M) | LP5521_RUN_R; | ||
239 | exec = (exec & ~LP5521_EXEC_R_M) | LP5521_RUN_R; | ||
240 | } | ||
241 | |||
242 | if (LP5521_G_IS_LOADING(mode)) { | ||
243 | mode = (mode & ~LP5521_MODE_G_M) | LP5521_RUN_G; | ||
244 | exec = (exec & ~LP5521_EXEC_G_M) | LP5521_RUN_G; | ||
245 | } | ||
246 | |||
247 | if (LP5521_B_IS_LOADING(mode)) { | ||
248 | mode = (mode & ~LP5521_MODE_B_M) | LP5521_RUN_B; | ||
249 | exec = (exec & ~LP5521_EXEC_B_M) | LP5521_RUN_B; | ||
250 | } | ||
251 | |||
252 | lp55xx_write(chip, LP5521_REG_OP_MODE, mode); | ||
253 | lp5521_wait_opmode_done(); | ||
221 | 254 | ||
222 | /* For loading, all the engines to load mode */ | 255 | lp55xx_update_bits(chip, LP5521_REG_ENABLE, LP5521_EXEC_M, exec); |
223 | lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT); | 256 | lp5521_wait_enable_done(); |
224 | /* Mode change requires min 500 us delay. 1 - 2 ms with margin */ | 257 | } |
225 | usleep_range(1000, 2000); | 258 | |
226 | lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_LOAD); | 259 | static int lp5521_update_program_memory(struct lp55xx_chip *chip, |
227 | /* Mode change requires min 500 us delay. 1 - 2 ms with margin */ | 260 | const u8 *data, size_t size) |
228 | usleep_range(1000, 2000); | 261 | { |
229 | 262 | enum lp55xx_engine_index idx = chip->engine_idx; | |
230 | addr = LP5521_PROG_MEM_BASE + eng->prog_page * LP5521_PROG_MEM_SIZE; | 263 | u8 pattern[LP5521_PROGRAM_LENGTH] = {0}; |
231 | i2c_smbus_write_i2c_block_data(client, | 264 | u8 addr[] = { |
232 | addr, | 265 | [LP55XX_ENGINE_1] = LP5521_REG_R_PROG_MEM, |
233 | LP5521_PROG_MEM_SIZE, | 266 | [LP55XX_ENGINE_2] = LP5521_REG_G_PROG_MEM, |
234 | pattern); | 267 | [LP55XX_ENGINE_3] = LP5521_REG_B_PROG_MEM, |
235 | 268 | }; | |
236 | return lp5521_write(client, LP5521_REG_OP_MODE, mode); | 269 | unsigned cmd; |
270 | char c[3]; | ||
271 | int program_size; | ||
272 | int nrchars; | ||
273 | int offset = 0; | ||
274 | int ret; | ||
275 | int i; | ||
276 | |||
277 | /* clear program memory before updating */ | ||
278 | for (i = 0; i < LP5521_PROGRAM_LENGTH; i++) | ||
279 | lp55xx_write(chip, addr[idx] + i, 0); | ||
280 | |||
281 | i = 0; | ||
282 | while ((offset < size - 1) && (i < LP5521_PROGRAM_LENGTH)) { | ||
283 | /* separate sscanfs because length is working only for %s */ | ||
284 | ret = sscanf(data + offset, "%2s%n ", c, &nrchars); | ||
285 | if (ret != 1) | ||
286 | goto err; | ||
287 | |||
288 | ret = sscanf(c, "%2x", &cmd); | ||
289 | if (ret != 1) | ||
290 | goto err; | ||
291 | |||
292 | pattern[i] = (u8)cmd; | ||
293 | offset += nrchars; | ||
294 | i++; | ||
295 | } | ||
296 | |||
297 | /* Each instruction is 16bit long. Check that length is even */ | ||
298 | if (i % 2) | ||
299 | goto err; | ||
300 | |||
301 | program_size = i; | ||
302 | for (i = 0; i < program_size; i++) | ||
303 | lp55xx_write(chip, addr[idx] + i, pattern[i]); | ||
304 | |||
305 | return 0; | ||
306 | |||
307 | err: | ||
308 | dev_err(&chip->cl->dev, "wrong pattern format\n"); | ||
309 | return -EINVAL; | ||
310 | } | ||
311 | |||
312 | static void lp5521_firmware_loaded(struct lp55xx_chip *chip) | ||
313 | { | ||
314 | const struct firmware *fw = chip->fw; | ||
315 | |||
316 | if (fw->size > LP5521_PROGRAM_LENGTH) { | ||
317 | dev_err(&chip->cl->dev, "firmware data size overflow: %zu\n", | ||
318 | fw->size); | ||
319 | return; | ||
320 | } | ||
321 | |||
322 | /* | ||
323 | * Program momery sequence | ||
324 | * 1) set engine mode to "LOAD" | ||
325 | * 2) write firmware data into program memory | ||
326 | */ | ||
327 | |||
328 | lp5521_load_engine(chip); | ||
329 | lp5521_update_program_memory(chip, fw->data, fw->size); | ||
237 | } | 330 | } |
238 | 331 | ||
239 | static int lp5521_post_init_device(struct lp55xx_chip *chip) | 332 | static int lp5521_post_init_device(struct lp55xx_chip *chip) |
@@ -313,155 +406,6 @@ static void lp5521_led_brightness_work(struct work_struct *work) | |||
313 | mutex_unlock(&chip->lock); | 406 | mutex_unlock(&chip->lock); |
314 | } | 407 | } |
315 | 408 | ||
316 | /* Set engine mode and create appropriate sysfs attributes, if required. */ | ||
317 | static int lp5521_set_mode(struct lp5521_engine *engine, u8 mode) | ||
318 | { | ||
319 | int ret = 0; | ||
320 | |||
321 | /* if in that mode already do nothing, except for run */ | ||
322 | if (mode == engine->mode && mode != LP5521_CMD_RUN) | ||
323 | return 0; | ||
324 | |||
325 | if (mode == LP5521_CMD_RUN) { | ||
326 | ret = lp5521_set_engine_mode(engine, LP5521_CMD_RUN); | ||
327 | } else if (mode == LP5521_CMD_LOAD) { | ||
328 | lp5521_set_engine_mode(engine, LP5521_CMD_DISABLED); | ||
329 | lp5521_set_engine_mode(engine, LP5521_CMD_LOAD); | ||
330 | } else if (mode == LP5521_CMD_DISABLED) { | ||
331 | lp5521_set_engine_mode(engine, LP5521_CMD_DISABLED); | ||
332 | } | ||
333 | |||
334 | engine->mode = mode; | ||
335 | |||
336 | return ret; | ||
337 | } | ||
338 | |||
339 | static int lp5521_do_store_load(struct lp5521_engine *engine, | ||
340 | const char *buf, size_t len) | ||
341 | { | ||
342 | struct lp5521_chip *chip = engine_to_lp5521(engine); | ||
343 | struct i2c_client *client = chip->client; | ||
344 | int ret, nrchars, offset = 0, i = 0; | ||
345 | char c[3]; | ||
346 | unsigned cmd; | ||
347 | u8 pattern[LP5521_PROGRAM_LENGTH] = {0}; | ||
348 | |||
349 | while ((offset < len - 1) && (i < LP5521_PROGRAM_LENGTH)) { | ||
350 | /* separate sscanfs because length is working only for %s */ | ||
351 | ret = sscanf(buf + offset, "%2s%n ", c, &nrchars); | ||
352 | if (ret != 2) | ||
353 | goto fail; | ||
354 | ret = sscanf(c, "%2x", &cmd); | ||
355 | if (ret != 1) | ||
356 | goto fail; | ||
357 | pattern[i] = (u8)cmd; | ||
358 | |||
359 | offset += nrchars; | ||
360 | i++; | ||
361 | } | ||
362 | |||
363 | /* Each instruction is 16bit long. Check that length is even */ | ||
364 | if (i % 2) | ||
365 | goto fail; | ||
366 | |||
367 | mutex_lock(&chip->lock); | ||
368 | if (engine->mode == LP5521_CMD_LOAD) | ||
369 | ret = lp5521_load_program(engine, pattern); | ||
370 | else | ||
371 | ret = -EINVAL; | ||
372 | mutex_unlock(&chip->lock); | ||
373 | |||
374 | if (ret) { | ||
375 | dev_err(&client->dev, "failed loading pattern\n"); | ||
376 | return ret; | ||
377 | } | ||
378 | |||
379 | return len; | ||
380 | fail: | ||
381 | dev_err(&client->dev, "wrong pattern format\n"); | ||
382 | return -EINVAL; | ||
383 | } | ||
384 | |||
385 | static ssize_t store_engine_load(struct device *dev, | ||
386 | struct device_attribute *attr, | ||
387 | const char *buf, size_t len, int nr) | ||
388 | { | ||
389 | struct i2c_client *client = to_i2c_client(dev); | ||
390 | struct lp5521_chip *chip = i2c_get_clientdata(client); | ||
391 | return lp5521_do_store_load(&chip->engines[nr - 1], buf, len); | ||
392 | } | ||
393 | |||
394 | #define store_load(nr) \ | ||
395 | static ssize_t store_engine##nr##_load(struct device *dev, \ | ||
396 | struct device_attribute *attr, \ | ||
397 | const char *buf, size_t len) \ | ||
398 | { \ | ||
399 | return store_engine_load(dev, attr, buf, len, nr); \ | ||
400 | } | ||
401 | store_load(1) | ||
402 | store_load(2) | ||
403 | store_load(3) | ||
404 | |||
405 | static ssize_t show_engine_mode(struct device *dev, | ||
406 | struct device_attribute *attr, | ||
407 | char *buf, int nr) | ||
408 | { | ||
409 | struct i2c_client *client = to_i2c_client(dev); | ||
410 | struct lp5521_chip *chip = i2c_get_clientdata(client); | ||
411 | switch (chip->engines[nr - 1].mode) { | ||
412 | case LP5521_CMD_RUN: | ||
413 | return sprintf(buf, "run\n"); | ||
414 | case LP5521_CMD_LOAD: | ||
415 | return sprintf(buf, "load\n"); | ||
416 | case LP5521_CMD_DISABLED: | ||
417 | return sprintf(buf, "disabled\n"); | ||
418 | default: | ||
419 | return sprintf(buf, "disabled\n"); | ||
420 | } | ||
421 | } | ||
422 | |||
423 | #define show_mode(nr) \ | ||
424 | static ssize_t show_engine##nr##_mode(struct device *dev, \ | ||
425 | struct device_attribute *attr, \ | ||
426 | char *buf) \ | ||
427 | { \ | ||
428 | return show_engine_mode(dev, attr, buf, nr); \ | ||
429 | } | ||
430 | show_mode(1) | ||
431 | show_mode(2) | ||
432 | show_mode(3) | ||
433 | |||
434 | static ssize_t store_engine_mode(struct device *dev, | ||
435 | struct device_attribute *attr, | ||
436 | const char *buf, size_t len, int nr) | ||
437 | { | ||
438 | struct i2c_client *client = to_i2c_client(dev); | ||
439 | struct lp5521_chip *chip = i2c_get_clientdata(client); | ||
440 | struct lp5521_engine *engine = &chip->engines[nr - 1]; | ||
441 | mutex_lock(&chip->lock); | ||
442 | |||
443 | if (!strncmp(buf, "run", 3)) | ||
444 | lp5521_set_mode(engine, LP5521_CMD_RUN); | ||
445 | else if (!strncmp(buf, "load", 4)) | ||
446 | lp5521_set_mode(engine, LP5521_CMD_LOAD); | ||
447 | else if (!strncmp(buf, "disabled", 8)) | ||
448 | lp5521_set_mode(engine, LP5521_CMD_DISABLED); | ||
449 | |||
450 | mutex_unlock(&chip->lock); | ||
451 | return len; | ||
452 | } | ||
453 | |||
454 | #define store_mode(nr) \ | ||
455 | static ssize_t store_engine##nr##_mode(struct device *dev, \ | ||
456 | struct device_attribute *attr, \ | ||
457 | const char *buf, size_t len) \ | ||
458 | { \ | ||
459 | return store_engine_mode(dev, attr, buf, len, nr); \ | ||
460 | } | ||
461 | store_mode(1) | ||
462 | store_mode(2) | ||
463 | store_mode(3) | ||
464 | |||
465 | static ssize_t lp5521_selftest(struct device *dev, | 409 | static ssize_t lp5521_selftest(struct device *dev, |
466 | struct device_attribute *attr, | 410 | struct device_attribute *attr, |
467 | char *buf) | 411 | char *buf) |
@@ -550,45 +494,11 @@ static void lp5521_run_led_pattern(int mode, struct lp5521_chip *chip) | |||
550 | } | 494 | } |
551 | } | 495 | } |
552 | 496 | ||
553 | static ssize_t store_led_pattern(struct device *dev, | ||
554 | struct device_attribute *attr, | ||
555 | const char *buf, size_t len) | ||
556 | { | ||
557 | struct lp5521_chip *chip = i2c_get_clientdata(to_i2c_client(dev)); | ||
558 | unsigned long val; | ||
559 | int ret; | ||
560 | |||
561 | ret = kstrtoul(buf, 16, &val); | ||
562 | if (ret) | ||
563 | return ret; | ||
564 | |||
565 | lp5521_run_led_pattern(val, chip); | ||
566 | |||
567 | return len; | ||
568 | } | ||
569 | |||
570 | /* device attributes */ | 497 | /* device attributes */ |
571 | static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUSR, | ||
572 | show_engine1_mode, store_engine1_mode); | ||
573 | static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUSR, | ||
574 | show_engine2_mode, store_engine2_mode); | ||
575 | static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUSR, | ||
576 | show_engine3_mode, store_engine3_mode); | ||
577 | static DEVICE_ATTR(engine1_load, S_IWUSR, NULL, store_engine1_load); | ||
578 | static DEVICE_ATTR(engine2_load, S_IWUSR, NULL, store_engine2_load); | ||
579 | static DEVICE_ATTR(engine3_load, S_IWUSR, NULL, store_engine3_load); | ||
580 | static DEVICE_ATTR(selftest, S_IRUGO, lp5521_selftest, NULL); | 498 | static DEVICE_ATTR(selftest, S_IRUGO, lp5521_selftest, NULL); |
581 | static DEVICE_ATTR(led_pattern, S_IWUSR, NULL, store_led_pattern); | ||
582 | 499 | ||
583 | static struct attribute *lp5521_attributes[] = { | 500 | static struct attribute *lp5521_attributes[] = { |
584 | &dev_attr_engine1_mode.attr, | ||
585 | &dev_attr_engine2_mode.attr, | ||
586 | &dev_attr_engine3_mode.attr, | ||
587 | &dev_attr_selftest.attr, | 501 | &dev_attr_selftest.attr, |
588 | &dev_attr_engine1_load.attr, | ||
589 | &dev_attr_engine2_load.attr, | ||
590 | &dev_attr_engine3_load.attr, | ||
591 | &dev_attr_led_pattern.attr, | ||
592 | NULL | 502 | NULL |
593 | }; | 503 | }; |
594 | 504 | ||
@@ -623,6 +533,8 @@ static struct lp55xx_device_config lp5521_cfg = { | |||
623 | .post_init_device = lp5521_post_init_device, | 533 | .post_init_device = lp5521_post_init_device, |
624 | .brightness_work_fn = lp5521_led_brightness_work, | 534 | .brightness_work_fn = lp5521_led_brightness_work, |
625 | .set_led_current = lp5521_set_led_current, | 535 | .set_led_current = lp5521_set_led_current, |
536 | .firmware_cb = lp5521_firmware_loaded, | ||
537 | .run_engine = lp5521_run_engine, | ||
626 | }; | 538 | }; |
627 | 539 | ||
628 | static int lp5521_probe(struct i2c_client *client, | 540 | static int lp5521_probe(struct i2c_client *client, |