diff options
author | Milo(Woogyom) Kim <milo.kim@ti.com> | 2013-02-05 05:18:51 -0500 |
---|---|---|
committer | Bryan Wu <cooloney@gmail.com> | 2013-02-06 18:59:29 -0500 |
commit | db6eaf8388a413a5ee1b4547ce78506b9c6456b0 (patch) | |
tree | 238aae833d0a52e4723c8cc71fccfa5ea68a2af5 /drivers/leds/leds-lp5523.c | |
parent | 9ce7cb170f97f83a78dc948bf7d25690f15e1328 (diff) |
leds-lp5523: 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
engine1_leds
engine2_leds
engine3_leds
All device attributes and functions are replaced with two callback functions,
'firmware_cb' and 'run_engine'.
New engine functions:
lp5523_load/stop/run_engine(), lp5523_update_program_memory() and
lp5523_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/leds/leds-lp5523.c')
-rw-r--r-- | drivers/leds/leds-lp5523.c | 503 |
1 files changed, 157 insertions, 346 deletions
diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index 70630156eff9..4b1ad9013a51 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.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 | ||
@@ -108,20 +109,39 @@ | |||
108 | #define LED_ACTIVE(mux, led) (!!(mux & (0x0001 << led))) | 109 | #define LED_ACTIVE(mux, led) (!!(mux & (0x0001 << led))) |
109 | #define SHIFT_MASK(id) (((id) - 1) * 2) | 110 | #define SHIFT_MASK(id) (((id) - 1) * 2) |
110 | 111 | ||
112 | /* Memory Page Selection */ | ||
113 | #define LP5523_PAGE_ENG1 0 | ||
114 | #define LP5523_PAGE_ENG2 1 | ||
115 | #define LP5523_PAGE_ENG3 2 | ||
116 | |||
117 | /* Program Memory Operations */ | ||
118 | #define LP5523_MODE_ENG1_M 0x30 /* Operation Mode Register */ | ||
119 | #define LP5523_MODE_ENG2_M 0x0C | ||
120 | #define LP5523_MODE_ENG3_M 0x03 | ||
121 | #define LP5523_LOAD_ENG1 0x10 | ||
122 | #define LP5523_LOAD_ENG2 0x04 | ||
123 | #define LP5523_LOAD_ENG3 0x01 | ||
124 | |||
125 | #define LP5523_ENG1_IS_LOADING(mode) \ | ||
126 | ((mode & LP5523_MODE_ENG1_M) == LP5523_LOAD_ENG1) | ||
127 | #define LP5523_ENG2_IS_LOADING(mode) \ | ||
128 | ((mode & LP5523_MODE_ENG2_M) == LP5523_LOAD_ENG2) | ||
129 | #define LP5523_ENG3_IS_LOADING(mode) \ | ||
130 | ((mode & LP5523_MODE_ENG3_M) == LP5523_LOAD_ENG3) | ||
131 | |||
132 | #define LP5523_EXEC_ENG1_M 0x30 /* Enable Register */ | ||
133 | #define LP5523_EXEC_ENG2_M 0x0C | ||
134 | #define LP5523_EXEC_ENG3_M 0x03 | ||
135 | #define LP5523_EXEC_M 0x3F | ||
136 | #define LP5523_RUN_ENG1 0x20 | ||
137 | #define LP5523_RUN_ENG2 0x08 | ||
138 | #define LP5523_RUN_ENG3 0x02 | ||
139 | |||
111 | enum lp5523_chip_id { | 140 | enum lp5523_chip_id { |
112 | LP5523, | 141 | LP5523, |
113 | LP55231, | 142 | LP55231, |
114 | }; | 143 | }; |
115 | 144 | ||
116 | struct lp5523_engine { | ||
117 | int id; | ||
118 | u8 mode; | ||
119 | u8 prog_page; | ||
120 | u8 mux_page; | ||
121 | u16 led_mux; | ||
122 | u8 engine_mask; | ||
123 | }; | ||
124 | |||
125 | struct lp5523_led { | 145 | struct lp5523_led { |
126 | int id; | 146 | int id; |
127 | u8 chan_nr; | 147 | u8 chan_nr; |
@@ -135,13 +155,17 @@ struct lp5523_led { | |||
135 | struct lp5523_chip { | 155 | struct lp5523_chip { |
136 | struct mutex lock; /* Serialize control */ | 156 | struct mutex lock; /* Serialize control */ |
137 | struct i2c_client *client; | 157 | struct i2c_client *client; |
138 | struct lp5523_engine engines[LP5523_ENGINES]; | ||
139 | struct lp5523_led leds[LP5523_MAX_LEDS]; | 158 | struct lp5523_led leds[LP5523_MAX_LEDS]; |
140 | struct lp5523_platform_data *pdata; | 159 | struct lp5523_platform_data *pdata; |
141 | u8 num_channels; | 160 | u8 num_channels; |
142 | u8 num_leds; | 161 | u8 num_leds; |
143 | }; | 162 | }; |
144 | 163 | ||
164 | static inline void lp5523_wait_opmode_done(void) | ||
165 | { | ||
166 | usleep_range(1000, 2000); | ||
167 | } | ||
168 | |||
145 | static void lp5523_set_led_current(struct lp55xx_led *led, u8 led_current) | 169 | static void lp5523_set_led_current(struct lp55xx_led *led, u8 led_current) |
146 | { | 170 | { |
147 | led->led_current = led_current; | 171 | led->led_current = led_current; |
@@ -149,27 +173,6 @@ static void lp5523_set_led_current(struct lp55xx_led *led, u8 led_current) | |||
149 | led_current); | 173 | led_current); |
150 | } | 174 | } |
151 | 175 | ||
152 | static inline struct lp5523_led *cdev_to_led(struct led_classdev *cdev) | ||
153 | { | ||
154 | return container_of(cdev, struct lp5523_led, cdev); | ||
155 | } | ||
156 | |||
157 | static inline struct lp5523_chip *engine_to_lp5523(struct lp5523_engine *engine) | ||
158 | { | ||
159 | return container_of(engine, struct lp5523_chip, | ||
160 | engines[engine->id - 1]); | ||
161 | } | ||
162 | |||
163 | static inline struct lp5523_chip *led_to_lp5523(struct lp5523_led *led) | ||
164 | { | ||
165 | return container_of(led, struct lp5523_chip, | ||
166 | leds[led->id]); | ||
167 | } | ||
168 | |||
169 | static void lp5523_set_mode(struct lp5523_engine *engine, u8 mode); | ||
170 | static int lp5523_set_engine_mode(struct lp5523_engine *engine, u8 mode); | ||
171 | static int lp5523_load_program(struct lp5523_engine *engine, const u8 *pattern); | ||
172 | |||
173 | static int lp5523_write(struct i2c_client *client, u8 reg, u8 value) | 176 | static int lp5523_write(struct i2c_client *client, u8 reg, u8 value) |
174 | { | 177 | { |
175 | return i2c_smbus_write_byte_data(client, reg, value); | 178 | return i2c_smbus_write_byte_data(client, reg, value); |
@@ -212,177 +215,162 @@ static int lp5523_post_init_device(struct lp55xx_chip *chip) | |||
212 | return lp55xx_write(chip, LP5523_REG_ENABLE_LEDS_LSB, 0xff); | 215 | return lp55xx_write(chip, LP5523_REG_ENABLE_LEDS_LSB, 0xff); |
213 | } | 216 | } |
214 | 217 | ||
215 | static int lp5523_set_engine_mode(struct lp5523_engine *engine, u8 mode) | 218 | static void lp5523_load_engine(struct lp55xx_chip *chip) |
216 | { | 219 | { |
217 | struct lp5523_chip *chip = engine_to_lp5523(engine); | 220 | enum lp55xx_engine_index idx = chip->engine_idx; |
218 | struct i2c_client *client = chip->client; | 221 | u8 mask[] = { |
219 | int ret; | 222 | [LP55XX_ENGINE_1] = LP5523_MODE_ENG1_M, |
220 | u8 engine_state; | 223 | [LP55XX_ENGINE_2] = LP5523_MODE_ENG2_M, |
221 | 224 | [LP55XX_ENGINE_3] = LP5523_MODE_ENG3_M, | |
222 | ret = lp5523_read(client, LP5523_REG_OP_MODE, &engine_state); | 225 | }; |
223 | if (ret) | 226 | |
224 | goto fail; | 227 | u8 val[] = { |
225 | 228 | [LP55XX_ENGINE_1] = LP5523_LOAD_ENG1, | |
226 | engine_state &= ~(engine->engine_mask); | 229 | [LP55XX_ENGINE_2] = LP5523_LOAD_ENG2, |
227 | 230 | [LP55XX_ENGINE_3] = LP5523_LOAD_ENG3, | |
228 | /* set mode only for this engine */ | 231 | }; |
229 | mode &= engine->engine_mask; | 232 | |
230 | 233 | u8 page_sel[] = { | |
231 | engine_state |= mode; | 234 | [LP55XX_ENGINE_1] = LP5523_PAGE_ENG1, |
232 | 235 | [LP55XX_ENGINE_2] = LP5523_PAGE_ENG2, | |
233 | ret |= lp5523_write(client, LP5523_REG_OP_MODE, engine_state); | 236 | [LP55XX_ENGINE_3] = LP5523_PAGE_ENG3, |
234 | fail: | 237 | }; |
235 | return ret; | 238 | |
239 | lp55xx_update_bits(chip, LP5523_REG_OP_MODE, mask[idx], val[idx]); | ||
240 | |||
241 | lp5523_wait_opmode_done(); | ||
242 | |||
243 | lp55xx_write(chip, LP5523_REG_PROG_PAGE_SEL, page_sel[idx]); | ||
236 | } | 244 | } |
237 | 245 | ||
238 | static int lp5523_load_mux(struct lp5523_engine *engine, u16 mux) | 246 | static void lp5523_stop_engine(struct lp55xx_chip *chip) |
239 | { | 247 | { |
240 | struct lp5523_chip *chip = engine_to_lp5523(engine); | 248 | lp55xx_write(chip, LP5523_REG_OP_MODE, 0); |
241 | struct i2c_client *client = chip->client; | 249 | lp5523_wait_opmode_done(); |
242 | int ret = 0; | 250 | } |
243 | |||
244 | ret |= lp5523_set_engine_mode(engine, LP5523_CMD_LOAD); | ||
245 | 251 | ||
246 | ret |= lp5523_write(client, LP5523_REG_PROG_PAGE_SEL, engine->mux_page); | 252 | static void lp5523_turn_off_channels(struct lp55xx_chip *chip) |
247 | ret |= lp5523_write(client, LP5523_REG_PROG_MEM, | 253 | { |
248 | (u8)(mux >> 8)); | 254 | int i; |
249 | ret |= lp5523_write(client, LP5523_REG_PROG_MEM + 1, (u8)(mux)); | ||
250 | engine->led_mux = mux; | ||
251 | 255 | ||
252 | return ret; | 256 | for (i = 0; i < LP5523_MAX_LEDS; i++) |
257 | lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + i, 0); | ||
253 | } | 258 | } |
254 | 259 | ||
255 | static int lp5523_load_program(struct lp5523_engine *engine, const u8 *pattern) | 260 | static void lp5523_run_engine(struct lp55xx_chip *chip, bool start) |
256 | { | 261 | { |
257 | struct lp5523_chip *chip = engine_to_lp5523(engine); | 262 | int ret; |
258 | struct i2c_client *client = chip->client; | 263 | u8 mode; |
264 | u8 exec; | ||
259 | 265 | ||
260 | int ret = 0; | 266 | /* stop engine */ |
267 | if (!start) { | ||
268 | lp5523_stop_engine(chip); | ||
269 | lp5523_turn_off_channels(chip); | ||
270 | return; | ||
271 | } | ||
261 | 272 | ||
262 | ret |= lp5523_set_engine_mode(engine, LP5523_CMD_LOAD); | 273 | /* |
274 | * To run the engine, | ||
275 | * operation mode and enable register should updated at the same time | ||
276 | */ | ||
263 | 277 | ||
264 | ret |= lp5523_write(client, LP5523_REG_PROG_PAGE_SEL, | 278 | ret = lp55xx_read(chip, LP5523_REG_OP_MODE, &mode); |
265 | engine->prog_page); | 279 | if (ret) |
266 | ret |= i2c_smbus_write_i2c_block_data(client, LP5523_REG_PROG_MEM, | 280 | return; |
267 | LP5523_PROGRAM_LENGTH, pattern); | ||
268 | 281 | ||
269 | return ret; | 282 | ret = lp55xx_read(chip, LP5523_REG_ENABLE, &exec); |
270 | } | 283 | if (ret) |
284 | return; | ||
271 | 285 | ||
272 | static int lp5523_run_program(struct lp5523_engine *engine) | 286 | /* change operation mode to RUN only when each engine is loading */ |
273 | { | 287 | if (LP5523_ENG1_IS_LOADING(mode)) { |
274 | struct lp5523_chip *chip = engine_to_lp5523(engine); | 288 | mode = (mode & ~LP5523_MODE_ENG1_M) | LP5523_RUN_ENG1; |
275 | struct i2c_client *client = chip->client; | 289 | exec = (exec & ~LP5523_EXEC_ENG1_M) | LP5523_RUN_ENG1; |
276 | int ret; | 290 | } |
277 | 291 | ||
278 | ret = lp5523_write(client, LP5523_REG_ENABLE, | 292 | if (LP5523_ENG2_IS_LOADING(mode)) { |
279 | LP5523_CMD_RUN | LP5523_ENABLE); | 293 | mode = (mode & ~LP5523_MODE_ENG2_M) | LP5523_RUN_ENG2; |
280 | if (ret) | 294 | exec = (exec & ~LP5523_EXEC_ENG2_M) | LP5523_RUN_ENG2; |
281 | goto fail; | 295 | } |
282 | 296 | ||
283 | ret = lp5523_set_engine_mode(engine, LP5523_CMD_RUN); | 297 | if (LP5523_ENG3_IS_LOADING(mode)) { |
284 | fail: | 298 | mode = (mode & ~LP5523_MODE_ENG3_M) | LP5523_RUN_ENG3; |
285 | return ret; | 299 | exec = (exec & ~LP5523_EXEC_ENG3_M) | LP5523_RUN_ENG3; |
300 | } | ||
301 | |||
302 | lp55xx_write(chip, LP5523_REG_OP_MODE, mode); | ||
303 | lp5523_wait_opmode_done(); | ||
304 | |||
305 | lp55xx_update_bits(chip, LP5523_REG_ENABLE, LP5523_EXEC_M, exec); | ||
286 | } | 306 | } |
287 | 307 | ||
288 | static int lp5523_mux_parse(const char *buf, u16 *mux, size_t len) | 308 | static int lp5523_update_program_memory(struct lp55xx_chip *chip, |
309 | const u8 *data, size_t size) | ||
289 | { | 310 | { |
311 | u8 pattern[LP5523_PROGRAM_LENGTH] = {0}; | ||
312 | unsigned cmd; | ||
313 | char c[3]; | ||
314 | int update_size; | ||
315 | int nrchars; | ||
316 | int offset = 0; | ||
317 | int ret; | ||
290 | int i; | 318 | int i; |
291 | u16 tmp_mux = 0; | ||
292 | |||
293 | len = min_t(int, len, LP5523_MAX_LEDS); | ||
294 | for (i = 0; i < len; i++) { | ||
295 | switch (buf[i]) { | ||
296 | case '1': | ||
297 | tmp_mux |= (1 << i); | ||
298 | break; | ||
299 | case '0': | ||
300 | break; | ||
301 | case '\n': | ||
302 | i = len; | ||
303 | break; | ||
304 | default: | ||
305 | return -1; | ||
306 | } | ||
307 | } | ||
308 | *mux = tmp_mux; | ||
309 | 319 | ||
310 | return 0; | 320 | /* clear program memory before updating */ |
311 | } | 321 | for (i = 0; i < LP5523_PROGRAM_LENGTH; i++) |
322 | lp55xx_write(chip, LP5523_REG_PROG_MEM + i, 0); | ||
312 | 323 | ||
313 | static void lp5523_mux_to_array(u16 led_mux, char *array) | 324 | i = 0; |
314 | { | 325 | while ((offset < size - 1) && (i < LP5523_PROGRAM_LENGTH)) { |
315 | int i, pos = 0; | 326 | /* separate sscanfs because length is working only for %s */ |
316 | for (i = 0; i < LP5523_MAX_LEDS; i++) | 327 | ret = sscanf(data + offset, "%2s%n ", c, &nrchars); |
317 | pos += sprintf(array + pos, "%x", LED_ACTIVE(led_mux, i)); | 328 | if (ret != 1) |
329 | goto err; | ||
318 | 330 | ||
319 | array[pos] = '\0'; | 331 | ret = sscanf(c, "%2x", &cmd); |
320 | } | 332 | if (ret != 1) |
333 | goto err; | ||
321 | 334 | ||
322 | /*--------------------------------------------------------------*/ | 335 | pattern[i] = (u8)cmd; |
323 | /* Sysfs interface */ | 336 | offset += nrchars; |
324 | /*--------------------------------------------------------------*/ | 337 | i++; |
338 | } | ||
325 | 339 | ||
326 | static ssize_t show_engine_leds(struct device *dev, | 340 | /* Each instruction is 16bit long. Check that length is even */ |
327 | struct device_attribute *attr, | 341 | if (i % 2) |
328 | char *buf, int nr) | 342 | goto err; |
329 | { | ||
330 | struct i2c_client *client = to_i2c_client(dev); | ||
331 | struct lp5523_chip *chip = i2c_get_clientdata(client); | ||
332 | char mux[LP5523_MAX_LEDS + 1]; | ||
333 | 343 | ||
334 | lp5523_mux_to_array(chip->engines[nr - 1].led_mux, mux); | 344 | update_size = i; |
345 | for (i = 0; i < update_size; i++) | ||
346 | lp55xx_write(chip, LP5523_REG_PROG_MEM + i, pattern[i]); | ||
335 | 347 | ||
336 | return sprintf(buf, "%s\n", mux); | 348 | return 0; |
337 | } | ||
338 | 349 | ||
339 | #define show_leds(nr) \ | 350 | err: |
340 | static ssize_t show_engine##nr##_leds(struct device *dev, \ | 351 | dev_err(&chip->cl->dev, "wrong pattern format\n"); |
341 | struct device_attribute *attr, \ | 352 | return -EINVAL; |
342 | char *buf) \ | ||
343 | { \ | ||
344 | return show_engine_leds(dev, attr, buf, nr); \ | ||
345 | } | 353 | } |
346 | show_leds(1) | ||
347 | show_leds(2) | ||
348 | show_leds(3) | ||
349 | 354 | ||
350 | static ssize_t store_engine_leds(struct device *dev, | 355 | static void lp5523_firmware_loaded(struct lp55xx_chip *chip) |
351 | struct device_attribute *attr, | ||
352 | const char *buf, size_t len, int nr) | ||
353 | { | 356 | { |
354 | struct i2c_client *client = to_i2c_client(dev); | 357 | const struct firmware *fw = chip->fw; |
355 | struct lp5523_chip *chip = i2c_get_clientdata(client); | ||
356 | u16 mux = 0; | ||
357 | ssize_t ret; | ||
358 | |||
359 | if (lp5523_mux_parse(buf, &mux, len)) | ||
360 | return -EINVAL; | ||
361 | 358 | ||
362 | mutex_lock(&chip->lock); | 359 | if (fw->size > LP5523_PROGRAM_LENGTH) { |
363 | ret = -EINVAL; | 360 | dev_err(&chip->cl->dev, "firmware data size overflow: %zu\n", |
364 | if (chip->engines[nr - 1].mode != LP5523_CMD_LOAD) | 361 | fw->size); |
365 | goto leave; | 362 | return; |
366 | 363 | } | |
367 | if (lp5523_load_mux(&chip->engines[nr - 1], mux)) | ||
368 | goto leave; | ||
369 | 364 | ||
370 | ret = len; | 365 | /* |
371 | leave: | 366 | * Program momery sequence |
372 | mutex_unlock(&chip->lock); | 367 | * 1) set engine mode to "LOAD" |
373 | return ret; | 368 | * 2) write firmware data into program memory |
374 | } | 369 | */ |
375 | 370 | ||
376 | #define store_leds(nr) \ | 371 | lp5523_load_engine(chip); |
377 | static ssize_t store_engine##nr##_leds(struct device *dev, \ | 372 | lp5523_update_program_memory(chip, fw->data, fw->size); |
378 | struct device_attribute *attr, \ | ||
379 | const char *buf, size_t len) \ | ||
380 | { \ | ||
381 | return store_engine_leds(dev, attr, buf, len, nr); \ | ||
382 | } | 373 | } |
383 | store_leds(1) | ||
384 | store_leds(2) | ||
385 | store_leds(3) | ||
386 | 374 | ||
387 | static ssize_t lp5523_selftest(struct device *dev, | 375 | static ssize_t lp5523_selftest(struct device *dev, |
388 | struct device_attribute *attr, | 376 | struct device_attribute *attr, |
@@ -485,159 +473,10 @@ static void lp5523_led_brightness_work(struct work_struct *work) | |||
485 | mutex_unlock(&chip->lock); | 473 | mutex_unlock(&chip->lock); |
486 | } | 474 | } |
487 | 475 | ||
488 | static int lp5523_do_store_load(struct lp5523_engine *engine, | ||
489 | const char *buf, size_t len) | ||
490 | { | ||
491 | struct lp5523_chip *chip = engine_to_lp5523(engine); | ||
492 | struct i2c_client *client = chip->client; | ||
493 | int ret, nrchars, offset = 0, i = 0; | ||
494 | char c[3]; | ||
495 | unsigned cmd; | ||
496 | u8 pattern[LP5523_PROGRAM_LENGTH] = {0}; | ||
497 | |||
498 | if (engine->mode != LP5523_CMD_LOAD) | ||
499 | return -EINVAL; | ||
500 | |||
501 | while ((offset < len - 1) && (i < LP5523_PROGRAM_LENGTH)) { | ||
502 | /* separate sscanfs because length is working only for %s */ | ||
503 | ret = sscanf(buf + offset, "%2s%n ", c, &nrchars); | ||
504 | ret = sscanf(c, "%2x", &cmd); | ||
505 | if (ret != 1) | ||
506 | goto fail; | ||
507 | pattern[i] = (u8)cmd; | ||
508 | |||
509 | offset += nrchars; | ||
510 | i++; | ||
511 | } | ||
512 | |||
513 | /* Each instruction is 16bit long. Check that length is even */ | ||
514 | if (i % 2) | ||
515 | goto fail; | ||
516 | |||
517 | mutex_lock(&chip->lock); | ||
518 | ret = lp5523_load_program(engine, pattern); | ||
519 | mutex_unlock(&chip->lock); | ||
520 | |||
521 | if (ret) { | ||
522 | dev_err(&client->dev, "failed loading pattern\n"); | ||
523 | return ret; | ||
524 | } | ||
525 | |||
526 | return len; | ||
527 | fail: | ||
528 | dev_err(&client->dev, "wrong pattern format\n"); | ||
529 | return -EINVAL; | ||
530 | } | ||
531 | |||
532 | static ssize_t store_engine_load(struct device *dev, | ||
533 | struct device_attribute *attr, | ||
534 | const char *buf, size_t len, int nr) | ||
535 | { | ||
536 | struct i2c_client *client = to_i2c_client(dev); | ||
537 | struct lp5523_chip *chip = i2c_get_clientdata(client); | ||
538 | return lp5523_do_store_load(&chip->engines[nr - 1], buf, len); | ||
539 | } | ||
540 | |||
541 | #define store_load(nr) \ | ||
542 | static ssize_t store_engine##nr##_load(struct device *dev, \ | ||
543 | struct device_attribute *attr, \ | ||
544 | const char *buf, size_t len) \ | ||
545 | { \ | ||
546 | return store_engine_load(dev, attr, buf, len, nr); \ | ||
547 | } | ||
548 | store_load(1) | ||
549 | store_load(2) | ||
550 | store_load(3) | ||
551 | |||
552 | static ssize_t show_engine_mode(struct device *dev, | ||
553 | struct device_attribute *attr, | ||
554 | char *buf, int nr) | ||
555 | { | ||
556 | struct i2c_client *client = to_i2c_client(dev); | ||
557 | struct lp5523_chip *chip = i2c_get_clientdata(client); | ||
558 | switch (chip->engines[nr - 1].mode) { | ||
559 | case LP5523_CMD_RUN: | ||
560 | return sprintf(buf, "run\n"); | ||
561 | case LP5523_CMD_LOAD: | ||
562 | return sprintf(buf, "load\n"); | ||
563 | case LP5523_CMD_DISABLED: | ||
564 | return sprintf(buf, "disabled\n"); | ||
565 | default: | ||
566 | return sprintf(buf, "disabled\n"); | ||
567 | } | ||
568 | } | ||
569 | |||
570 | #define show_mode(nr) \ | ||
571 | static ssize_t show_engine##nr##_mode(struct device *dev, \ | ||
572 | struct device_attribute *attr, \ | ||
573 | char *buf) \ | ||
574 | { \ | ||
575 | return show_engine_mode(dev, attr, buf, nr); \ | ||
576 | } | ||
577 | show_mode(1) | ||
578 | show_mode(2) | ||
579 | show_mode(3) | ||
580 | |||
581 | static ssize_t store_engine_mode(struct device *dev, | ||
582 | struct device_attribute *attr, | ||
583 | const char *buf, size_t len, int nr) | ||
584 | { | ||
585 | struct i2c_client *client = to_i2c_client(dev); | ||
586 | struct lp5523_chip *chip = i2c_get_clientdata(client); | ||
587 | struct lp5523_engine *engine = &chip->engines[nr - 1]; | ||
588 | mutex_lock(&chip->lock); | ||
589 | |||
590 | if (!strncmp(buf, "run", 3)) | ||
591 | lp5523_set_mode(engine, LP5523_CMD_RUN); | ||
592 | else if (!strncmp(buf, "load", 4)) | ||
593 | lp5523_set_mode(engine, LP5523_CMD_LOAD); | ||
594 | else if (!strncmp(buf, "disabled", 8)) | ||
595 | lp5523_set_mode(engine, LP5523_CMD_DISABLED); | ||
596 | |||
597 | mutex_unlock(&chip->lock); | ||
598 | return len; | ||
599 | } | ||
600 | |||
601 | #define store_mode(nr) \ | ||
602 | static ssize_t store_engine##nr##_mode(struct device *dev, \ | ||
603 | struct device_attribute *attr, \ | ||
604 | const char *buf, size_t len) \ | ||
605 | { \ | ||
606 | return store_engine_mode(dev, attr, buf, len, nr); \ | ||
607 | } | ||
608 | store_mode(1) | ||
609 | store_mode(2) | ||
610 | store_mode(3) | ||
611 | |||
612 | /* device attributes */ | ||
613 | static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUSR, | ||
614 | show_engine1_mode, store_engine1_mode); | ||
615 | static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUSR, | ||
616 | show_engine2_mode, store_engine2_mode); | ||
617 | static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUSR, | ||
618 | show_engine3_mode, store_engine3_mode); | ||
619 | static DEVICE_ATTR(engine1_leds, S_IRUGO | S_IWUSR, | ||
620 | show_engine1_leds, store_engine1_leds); | ||
621 | static DEVICE_ATTR(engine2_leds, S_IRUGO | S_IWUSR, | ||
622 | show_engine2_leds, store_engine2_leds); | ||
623 | static DEVICE_ATTR(engine3_leds, S_IRUGO | S_IWUSR, | ||
624 | show_engine3_leds, store_engine3_leds); | ||
625 | static DEVICE_ATTR(engine1_load, S_IWUSR, NULL, store_engine1_load); | ||
626 | static DEVICE_ATTR(engine2_load, S_IWUSR, NULL, store_engine2_load); | ||
627 | static DEVICE_ATTR(engine3_load, S_IWUSR, NULL, store_engine3_load); | ||
628 | static DEVICE_ATTR(selftest, S_IRUGO, lp5523_selftest, NULL); | 476 | static DEVICE_ATTR(selftest, S_IRUGO, lp5523_selftest, NULL); |
629 | 477 | ||
630 | static struct attribute *lp5523_attributes[] = { | 478 | static struct attribute *lp5523_attributes[] = { |
631 | &dev_attr_engine1_mode.attr, | ||
632 | &dev_attr_engine2_mode.attr, | ||
633 | &dev_attr_engine3_mode.attr, | ||
634 | &dev_attr_selftest.attr, | 479 | &dev_attr_selftest.attr, |
635 | &dev_attr_engine1_load.attr, | ||
636 | &dev_attr_engine1_leds.attr, | ||
637 | &dev_attr_engine2_load.attr, | ||
638 | &dev_attr_engine2_leds.attr, | ||
639 | &dev_attr_engine3_load.attr, | ||
640 | &dev_attr_engine3_leds.attr, | ||
641 | NULL, | 480 | NULL, |
642 | }; | 481 | }; |
643 | 482 | ||
@@ -664,36 +503,6 @@ static void lp5523_unregister_sysfs(struct i2c_client *client) | |||
664 | sysfs_remove_group(&dev->kobj, &lp5523_group); | 503 | sysfs_remove_group(&dev->kobj, &lp5523_group); |
665 | } | 504 | } |
666 | 505 | ||
667 | /*--------------------------------------------------------------*/ | ||
668 | /* Set chip operating mode */ | ||
669 | /*--------------------------------------------------------------*/ | ||
670 | static void lp5523_set_mode(struct lp5523_engine *engine, u8 mode) | ||
671 | { | ||
672 | /* if in that mode already do nothing, except for run */ | ||
673 | if (mode == engine->mode && mode != LP5523_CMD_RUN) | ||
674 | return; | ||
675 | |||
676 | switch (mode) { | ||
677 | case LP5523_CMD_RUN: | ||
678 | lp5523_run_program(engine); | ||
679 | break; | ||
680 | case LP5523_CMD_LOAD: | ||
681 | lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED); | ||
682 | lp5523_set_engine_mode(engine, LP5523_CMD_LOAD); | ||
683 | break; | ||
684 | case LP5523_CMD_DISABLED: | ||
685 | lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED); | ||
686 | break; | ||
687 | default: | ||
688 | return; | ||
689 | } | ||
690 | |||
691 | engine->mode = mode; | ||
692 | } | ||
693 | |||
694 | /*--------------------------------------------------------------*/ | ||
695 | /* Probe, Attach, Remove */ | ||
696 | /*--------------------------------------------------------------*/ | ||
697 | /* Chip specific configurations */ | 506 | /* Chip specific configurations */ |
698 | static struct lp55xx_device_config lp5523_cfg = { | 507 | static struct lp55xx_device_config lp5523_cfg = { |
699 | .reset = { | 508 | .reset = { |
@@ -708,6 +517,8 @@ static struct lp55xx_device_config lp5523_cfg = { | |||
708 | .post_init_device = lp5523_post_init_device, | 517 | .post_init_device = lp5523_post_init_device, |
709 | .brightness_work_fn = lp5523_led_brightness_work, | 518 | .brightness_work_fn = lp5523_led_brightness_work, |
710 | .set_led_current = lp5523_set_led_current, | 519 | .set_led_current = lp5523_set_led_current, |
520 | .firmware_cb = lp5523_firmware_loaded, | ||
521 | .run_engine = lp5523_run_engine, | ||
711 | }; | 522 | }; |
712 | 523 | ||
713 | static int lp5523_probe(struct i2c_client *client, | 524 | static int lp5523_probe(struct i2c_client *client, |