1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * lp5523.c - LP5523, LP55231 LED Driver |
4 | * |
5 | * Copyright (C) 2010 Nokia Corporation |
6 | * Copyright (C) 2012 Texas Instruments |
7 | * |
8 | * Contact: Samu Onkalo <samu.p.onkalo@nokia.com> |
9 | * Milo(Woogyom) Kim <milo.kim@ti.com> |
10 | */ |
11 | |
12 | #include <linux/delay.h> |
13 | #include <linux/firmware.h> |
14 | #include <linux/i2c.h> |
15 | #include <linux/leds.h> |
16 | #include <linux/module.h> |
17 | #include <linux/mutex.h> |
18 | #include <linux/of.h> |
19 | #include <linux/platform_data/leds-lp55xx.h> |
20 | #include <linux/slab.h> |
21 | |
22 | #include "leds-lp55xx-common.h" |
23 | |
24 | #define LP5523_PROGRAM_LENGTH 32 /* bytes */ |
25 | /* Memory is used like this: |
26 | * 0x00 engine 1 program |
27 | * 0x10 engine 2 program |
28 | * 0x20 engine 3 program |
29 | * 0x30 engine 1 muxing info |
30 | * 0x40 engine 2 muxing info |
31 | * 0x50 engine 3 muxing info |
32 | */ |
33 | #define LP5523_MAX_LEDS 9 |
34 | |
35 | /* Registers */ |
36 | #define LP5523_REG_ENABLE 0x00 |
37 | #define LP5523_REG_OP_MODE 0x01 |
38 | #define LP5523_REG_ENABLE_LEDS_MSB 0x04 |
39 | #define LP5523_REG_ENABLE_LEDS_LSB 0x05 |
40 | #define LP5523_REG_LED_CTRL_BASE 0x06 |
41 | #define LP5523_REG_LED_PWM_BASE 0x16 |
42 | #define LP5523_REG_LED_CURRENT_BASE 0x26 |
43 | #define LP5523_REG_CONFIG 0x36 |
44 | #define LP5523_REG_STATUS 0x3A |
45 | #define LP5523_REG_RESET 0x3D |
46 | #define LP5523_REG_LED_TEST_CTRL 0x41 |
47 | #define LP5523_REG_LED_TEST_ADC 0x42 |
48 | #define LP5523_REG_MASTER_FADER_BASE 0x48 |
49 | #define LP5523_REG_CH1_PROG_START 0x4C |
50 | #define LP5523_REG_CH2_PROG_START 0x4D |
51 | #define LP5523_REG_CH3_PROG_START 0x4E |
52 | #define LP5523_REG_PROG_PAGE_SEL 0x4F |
53 | #define LP5523_REG_PROG_MEM 0x50 |
54 | |
55 | /* Bit description in registers */ |
56 | #define LP5523_ENABLE 0x40 |
57 | #define LP5523_AUTO_INC 0x40 |
58 | #define LP5523_PWR_SAVE 0x20 |
59 | #define LP5523_PWM_PWR_SAVE 0x04 |
60 | #define LP5523_CP_MODE_MASK 0x18 |
61 | #define LP5523_CP_MODE_SHIFT 3 |
62 | #define LP5523_AUTO_CLK 0x02 |
63 | #define LP5523_DEFAULT_CONFIG \ |
64 | (LP5523_AUTO_INC | LP5523_PWR_SAVE | LP5523_AUTO_CLK | LP5523_PWM_PWR_SAVE) |
65 | |
66 | #define LP5523_EN_LEDTEST 0x80 |
67 | #define LP5523_LEDTEST_DONE 0x80 |
68 | #define LP5523_RESET 0xFF |
69 | #define LP5523_ADC_SHORTCIRC_LIM 80 |
70 | #define LP5523_EXT_CLK_USED 0x08 |
71 | #define LP5523_ENG_STATUS_MASK 0x07 |
72 | |
73 | #define LP5523_FADER_MAPPING_MASK 0xC0 |
74 | #define LP5523_FADER_MAPPING_SHIFT 6 |
75 | |
76 | /* Memory Page Selection */ |
77 | #define LP5523_PAGE_ENG1 0 |
78 | #define LP5523_PAGE_ENG2 1 |
79 | #define LP5523_PAGE_ENG3 2 |
80 | #define LP5523_PAGE_MUX1 3 |
81 | #define LP5523_PAGE_MUX2 4 |
82 | #define LP5523_PAGE_MUX3 5 |
83 | |
84 | /* Program Memory Operations */ |
85 | #define LP5523_MODE_ENG1_M 0x30 /* Operation Mode Register */ |
86 | #define LP5523_MODE_ENG2_M 0x0C |
87 | #define LP5523_MODE_ENG3_M 0x03 |
88 | #define LP5523_LOAD_ENG1 0x10 |
89 | #define LP5523_LOAD_ENG2 0x04 |
90 | #define LP5523_LOAD_ENG3 0x01 |
91 | |
92 | #define LP5523_ENG1_IS_LOADING(mode) \ |
93 | ((mode & LP5523_MODE_ENG1_M) == LP5523_LOAD_ENG1) |
94 | #define LP5523_ENG2_IS_LOADING(mode) \ |
95 | ((mode & LP5523_MODE_ENG2_M) == LP5523_LOAD_ENG2) |
96 | #define LP5523_ENG3_IS_LOADING(mode) \ |
97 | ((mode & LP5523_MODE_ENG3_M) == LP5523_LOAD_ENG3) |
98 | |
99 | #define LP5523_EXEC_ENG1_M 0x30 /* Enable Register */ |
100 | #define LP5523_EXEC_ENG2_M 0x0C |
101 | #define LP5523_EXEC_ENG3_M 0x03 |
102 | #define LP5523_EXEC_M 0x3F |
103 | #define LP5523_RUN_ENG1 0x20 |
104 | #define LP5523_RUN_ENG2 0x08 |
105 | #define LP5523_RUN_ENG3 0x02 |
106 | |
107 | #define LED_ACTIVE(mux, led) (!!(mux & (0x0001 << led))) |
108 | |
109 | enum lp5523_chip_id { |
110 | LP5523, |
111 | LP55231, |
112 | }; |
113 | |
114 | static int lp5523_init_program_engine(struct lp55xx_chip *chip); |
115 | |
116 | static inline void lp5523_wait_opmode_done(void) |
117 | { |
118 | usleep_range(min: 1000, max: 2000); |
119 | } |
120 | |
121 | static void lp5523_set_led_current(struct lp55xx_led *led, u8 led_current) |
122 | { |
123 | led->led_current = led_current; |
124 | lp55xx_write(chip: led->chip, LP5523_REG_LED_CURRENT_BASE + led->chan_nr, |
125 | val: led_current); |
126 | } |
127 | |
128 | static int lp5523_post_init_device(struct lp55xx_chip *chip) |
129 | { |
130 | int ret; |
131 | int val; |
132 | |
133 | ret = lp55xx_write(chip, LP5523_REG_ENABLE, LP5523_ENABLE); |
134 | if (ret) |
135 | return ret; |
136 | |
137 | /* Chip startup time is 500 us, 1 - 2 ms gives some margin */ |
138 | usleep_range(min: 1000, max: 2000); |
139 | |
140 | val = LP5523_DEFAULT_CONFIG; |
141 | val |= (chip->pdata->charge_pump_mode << LP5523_CP_MODE_SHIFT) & LP5523_CP_MODE_MASK; |
142 | |
143 | ret = lp55xx_write(chip, LP5523_REG_CONFIG, val); |
144 | if (ret) |
145 | return ret; |
146 | |
147 | /* turn on all leds */ |
148 | ret = lp55xx_write(chip, LP5523_REG_ENABLE_LEDS_MSB, val: 0x01); |
149 | if (ret) |
150 | return ret; |
151 | |
152 | ret = lp55xx_write(chip, LP5523_REG_ENABLE_LEDS_LSB, val: 0xff); |
153 | if (ret) |
154 | return ret; |
155 | |
156 | return lp5523_init_program_engine(chip); |
157 | } |
158 | |
159 | static void lp5523_load_engine(struct lp55xx_chip *chip) |
160 | { |
161 | enum lp55xx_engine_index idx = chip->engine_idx; |
162 | static const u8 mask[] = { |
163 | [LP55XX_ENGINE_1] = LP5523_MODE_ENG1_M, |
164 | [LP55XX_ENGINE_2] = LP5523_MODE_ENG2_M, |
165 | [LP55XX_ENGINE_3] = LP5523_MODE_ENG3_M, |
166 | }; |
167 | |
168 | static const u8 val[] = { |
169 | [LP55XX_ENGINE_1] = LP5523_LOAD_ENG1, |
170 | [LP55XX_ENGINE_2] = LP5523_LOAD_ENG2, |
171 | [LP55XX_ENGINE_3] = LP5523_LOAD_ENG3, |
172 | }; |
173 | |
174 | lp55xx_update_bits(chip, LP5523_REG_OP_MODE, mask: mask[idx], val: val[idx]); |
175 | |
176 | lp5523_wait_opmode_done(); |
177 | } |
178 | |
179 | static void lp5523_load_engine_and_select_page(struct lp55xx_chip *chip) |
180 | { |
181 | enum lp55xx_engine_index idx = chip->engine_idx; |
182 | static const u8 page_sel[] = { |
183 | [LP55XX_ENGINE_1] = LP5523_PAGE_ENG1, |
184 | [LP55XX_ENGINE_2] = LP5523_PAGE_ENG2, |
185 | [LP55XX_ENGINE_3] = LP5523_PAGE_ENG3, |
186 | }; |
187 | |
188 | lp5523_load_engine(chip); |
189 | |
190 | lp55xx_write(chip, LP5523_REG_PROG_PAGE_SEL, val: page_sel[idx]); |
191 | } |
192 | |
193 | static void lp5523_stop_all_engines(struct lp55xx_chip *chip) |
194 | { |
195 | lp55xx_write(chip, LP5523_REG_OP_MODE, val: 0); |
196 | lp5523_wait_opmode_done(); |
197 | } |
198 | |
199 | static void lp5523_stop_engine(struct lp55xx_chip *chip) |
200 | { |
201 | enum lp55xx_engine_index idx = chip->engine_idx; |
202 | static const u8 mask[] = { |
203 | [LP55XX_ENGINE_1] = LP5523_MODE_ENG1_M, |
204 | [LP55XX_ENGINE_2] = LP5523_MODE_ENG2_M, |
205 | [LP55XX_ENGINE_3] = LP5523_MODE_ENG3_M, |
206 | }; |
207 | |
208 | lp55xx_update_bits(chip, LP5523_REG_OP_MODE, mask: mask[idx], val: 0); |
209 | |
210 | lp5523_wait_opmode_done(); |
211 | } |
212 | |
213 | static void lp5523_turn_off_channels(struct lp55xx_chip *chip) |
214 | { |
215 | int i; |
216 | |
217 | for (i = 0; i < LP5523_MAX_LEDS; i++) |
218 | lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + i, val: 0); |
219 | } |
220 | |
221 | static void lp5523_run_engine(struct lp55xx_chip *chip, bool start) |
222 | { |
223 | int ret; |
224 | u8 mode; |
225 | u8 exec; |
226 | |
227 | /* stop engine */ |
228 | if (!start) { |
229 | lp5523_stop_engine(chip); |
230 | lp5523_turn_off_channels(chip); |
231 | return; |
232 | } |
233 | |
234 | /* |
235 | * To run the engine, |
236 | * operation mode and enable register should updated at the same time |
237 | */ |
238 | |
239 | ret = lp55xx_read(chip, LP5523_REG_OP_MODE, val: &mode); |
240 | if (ret) |
241 | return; |
242 | |
243 | ret = lp55xx_read(chip, LP5523_REG_ENABLE, val: &exec); |
244 | if (ret) |
245 | return; |
246 | |
247 | /* change operation mode to RUN only when each engine is loading */ |
248 | if (LP5523_ENG1_IS_LOADING(mode)) { |
249 | mode = (mode & ~LP5523_MODE_ENG1_M) | LP5523_RUN_ENG1; |
250 | exec = (exec & ~LP5523_EXEC_ENG1_M) | LP5523_RUN_ENG1; |
251 | } |
252 | |
253 | if (LP5523_ENG2_IS_LOADING(mode)) { |
254 | mode = (mode & ~LP5523_MODE_ENG2_M) | LP5523_RUN_ENG2; |
255 | exec = (exec & ~LP5523_EXEC_ENG2_M) | LP5523_RUN_ENG2; |
256 | } |
257 | |
258 | if (LP5523_ENG3_IS_LOADING(mode)) { |
259 | mode = (mode & ~LP5523_MODE_ENG3_M) | LP5523_RUN_ENG3; |
260 | exec = (exec & ~LP5523_EXEC_ENG3_M) | LP5523_RUN_ENG3; |
261 | } |
262 | |
263 | lp55xx_write(chip, LP5523_REG_OP_MODE, val: mode); |
264 | lp5523_wait_opmode_done(); |
265 | |
266 | lp55xx_update_bits(chip, LP5523_REG_ENABLE, LP5523_EXEC_M, val: exec); |
267 | } |
268 | |
269 | static int lp5523_init_program_engine(struct lp55xx_chip *chip) |
270 | { |
271 | int i; |
272 | int j; |
273 | int ret; |
274 | u8 status; |
275 | /* one pattern per engine setting LED MUX start and stop addresses */ |
276 | static const u8 pattern[][LP5523_PROGRAM_LENGTH] = { |
277 | { 0x9c, 0x30, 0x9c, 0xb0, 0x9d, 0x80, 0xd8, 0x00, 0}, |
278 | { 0x9c, 0x40, 0x9c, 0xc0, 0x9d, 0x80, 0xd8, 0x00, 0}, |
279 | { 0x9c, 0x50, 0x9c, 0xd0, 0x9d, 0x80, 0xd8, 0x00, 0}, |
280 | }; |
281 | |
282 | /* hardcode 32 bytes of memory for each engine from program memory */ |
283 | ret = lp55xx_write(chip, LP5523_REG_CH1_PROG_START, val: 0x00); |
284 | if (ret) |
285 | return ret; |
286 | |
287 | ret = lp55xx_write(chip, LP5523_REG_CH2_PROG_START, val: 0x10); |
288 | if (ret) |
289 | return ret; |
290 | |
291 | ret = lp55xx_write(chip, LP5523_REG_CH3_PROG_START, val: 0x20); |
292 | if (ret) |
293 | return ret; |
294 | |
295 | /* write LED MUX address space for each engine */ |
296 | for (i = LP55XX_ENGINE_1; i <= LP55XX_ENGINE_3; i++) { |
297 | chip->engine_idx = i; |
298 | lp5523_load_engine_and_select_page(chip); |
299 | |
300 | for (j = 0; j < LP5523_PROGRAM_LENGTH; j++) { |
301 | ret = lp55xx_write(chip, LP5523_REG_PROG_MEM + j, |
302 | val: pattern[i - 1][j]); |
303 | if (ret) |
304 | goto out; |
305 | } |
306 | } |
307 | |
308 | lp5523_run_engine(chip, start: true); |
309 | |
310 | /* Let the programs run for couple of ms and check the engine status */ |
311 | usleep_range(min: 3000, max: 6000); |
312 | ret = lp55xx_read(chip, LP5523_REG_STATUS, val: &status); |
313 | if (ret) |
314 | goto out; |
315 | status &= LP5523_ENG_STATUS_MASK; |
316 | |
317 | if (status != LP5523_ENG_STATUS_MASK) { |
318 | dev_err(&chip->cl->dev, |
319 | "could not configure LED engine, status = 0x%.2x\n" , |
320 | status); |
321 | ret = -1; |
322 | } |
323 | |
324 | out: |
325 | lp5523_stop_all_engines(chip); |
326 | return ret; |
327 | } |
328 | |
329 | static int lp5523_update_program_memory(struct lp55xx_chip *chip, |
330 | const u8 *data, size_t size) |
331 | { |
332 | u8 pattern[LP5523_PROGRAM_LENGTH] = {0}; |
333 | unsigned int cmd; |
334 | char c[3]; |
335 | int nrchars; |
336 | int ret; |
337 | int offset = 0; |
338 | int i = 0; |
339 | |
340 | while ((offset < size - 1) && (i < LP5523_PROGRAM_LENGTH)) { |
341 | /* separate sscanfs because length is working only for %s */ |
342 | ret = sscanf(data + offset, "%2s%n " , c, &nrchars); |
343 | if (ret != 1) |
344 | goto err; |
345 | |
346 | ret = sscanf(c, "%2x" , &cmd); |
347 | if (ret != 1) |
348 | goto err; |
349 | |
350 | pattern[i] = (u8)cmd; |
351 | offset += nrchars; |
352 | i++; |
353 | } |
354 | |
355 | /* Each instruction is 16bit long. Check that length is even */ |
356 | if (i % 2) |
357 | goto err; |
358 | |
359 | for (i = 0; i < LP5523_PROGRAM_LENGTH; i++) { |
360 | ret = lp55xx_write(chip, LP5523_REG_PROG_MEM + i, val: pattern[i]); |
361 | if (ret) |
362 | return -EINVAL; |
363 | } |
364 | |
365 | return size; |
366 | |
367 | err: |
368 | dev_err(&chip->cl->dev, "wrong pattern format\n" ); |
369 | return -EINVAL; |
370 | } |
371 | |
372 | static void lp5523_firmware_loaded(struct lp55xx_chip *chip) |
373 | { |
374 | const struct firmware *fw = chip->fw; |
375 | |
376 | if (fw->size > LP5523_PROGRAM_LENGTH) { |
377 | dev_err(&chip->cl->dev, "firmware data size overflow: %zu\n" , |
378 | fw->size); |
379 | return; |
380 | } |
381 | |
382 | /* |
383 | * Program memory sequence |
384 | * 1) set engine mode to "LOAD" |
385 | * 2) write firmware data into program memory |
386 | */ |
387 | |
388 | lp5523_load_engine_and_select_page(chip); |
389 | lp5523_update_program_memory(chip, data: fw->data, size: fw->size); |
390 | } |
391 | |
392 | static ssize_t show_engine_mode(struct device *dev, |
393 | struct device_attribute *attr, |
394 | char *buf, int nr) |
395 | { |
396 | struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev)); |
397 | struct lp55xx_chip *chip = led->chip; |
398 | enum lp55xx_engine_mode mode = chip->engines[nr - 1].mode; |
399 | |
400 | switch (mode) { |
401 | case LP55XX_ENGINE_RUN: |
402 | return sprintf(buf, fmt: "run\n" ); |
403 | case LP55XX_ENGINE_LOAD: |
404 | return sprintf(buf, fmt: "load\n" ); |
405 | case LP55XX_ENGINE_DISABLED: |
406 | default: |
407 | return sprintf(buf, fmt: "disabled\n" ); |
408 | } |
409 | } |
410 | show_mode(1) |
411 | show_mode(2) |
412 | show_mode(3) |
413 | |
414 | static ssize_t store_engine_mode(struct device *dev, |
415 | struct device_attribute *attr, |
416 | const char *buf, size_t len, int nr) |
417 | { |
418 | struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev)); |
419 | struct lp55xx_chip *chip = led->chip; |
420 | struct lp55xx_engine *engine = &chip->engines[nr - 1]; |
421 | |
422 | mutex_lock(&chip->lock); |
423 | |
424 | chip->engine_idx = nr; |
425 | |
426 | if (!strncmp(buf, "run" , 3)) { |
427 | lp5523_run_engine(chip, start: true); |
428 | engine->mode = LP55XX_ENGINE_RUN; |
429 | } else if (!strncmp(buf, "load" , 4)) { |
430 | lp5523_stop_engine(chip); |
431 | lp5523_load_engine(chip); |
432 | engine->mode = LP55XX_ENGINE_LOAD; |
433 | } else if (!strncmp(buf, "disabled" , 8)) { |
434 | lp5523_stop_engine(chip); |
435 | engine->mode = LP55XX_ENGINE_DISABLED; |
436 | } |
437 | |
438 | mutex_unlock(lock: &chip->lock); |
439 | |
440 | return len; |
441 | } |
442 | store_mode(1) |
443 | store_mode(2) |
444 | store_mode(3) |
445 | |
446 | static int lp5523_mux_parse(const char *buf, u16 *mux, size_t len) |
447 | { |
448 | u16 tmp_mux = 0; |
449 | int i; |
450 | |
451 | len = min_t(int, len, LP5523_MAX_LEDS); |
452 | |
453 | for (i = 0; i < len; i++) { |
454 | switch (buf[i]) { |
455 | case '1': |
456 | tmp_mux |= (1 << i); |
457 | break; |
458 | case '0': |
459 | break; |
460 | case '\n': |
461 | i = len; |
462 | break; |
463 | default: |
464 | return -1; |
465 | } |
466 | } |
467 | *mux = tmp_mux; |
468 | |
469 | return 0; |
470 | } |
471 | |
472 | static void lp5523_mux_to_array(u16 led_mux, char *array) |
473 | { |
474 | int i, pos = 0; |
475 | |
476 | for (i = 0; i < LP5523_MAX_LEDS; i++) |
477 | pos += sprintf(buf: array + pos, fmt: "%x" , LED_ACTIVE(led_mux, i)); |
478 | |
479 | array[pos] = '\0'; |
480 | } |
481 | |
482 | static ssize_t show_engine_leds(struct device *dev, |
483 | struct device_attribute *attr, |
484 | char *buf, int nr) |
485 | { |
486 | struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev)); |
487 | struct lp55xx_chip *chip = led->chip; |
488 | char mux[LP5523_MAX_LEDS + 1]; |
489 | |
490 | lp5523_mux_to_array(led_mux: chip->engines[nr - 1].led_mux, array: mux); |
491 | |
492 | return sprintf(buf, fmt: "%s\n" , mux); |
493 | } |
494 | show_leds(1) |
495 | show_leds(2) |
496 | show_leds(3) |
497 | |
498 | static int lp5523_load_mux(struct lp55xx_chip *chip, u16 mux, int nr) |
499 | { |
500 | struct lp55xx_engine *engine = &chip->engines[nr - 1]; |
501 | int ret; |
502 | static const u8 mux_page[] = { |
503 | [LP55XX_ENGINE_1] = LP5523_PAGE_MUX1, |
504 | [LP55XX_ENGINE_2] = LP5523_PAGE_MUX2, |
505 | [LP55XX_ENGINE_3] = LP5523_PAGE_MUX3, |
506 | }; |
507 | |
508 | lp5523_load_engine(chip); |
509 | |
510 | ret = lp55xx_write(chip, LP5523_REG_PROG_PAGE_SEL, val: mux_page[nr]); |
511 | if (ret) |
512 | return ret; |
513 | |
514 | ret = lp55xx_write(chip, LP5523_REG_PROG_MEM, val: (u8)(mux >> 8)); |
515 | if (ret) |
516 | return ret; |
517 | |
518 | ret = lp55xx_write(chip, LP5523_REG_PROG_MEM + 1, val: (u8)(mux)); |
519 | if (ret) |
520 | return ret; |
521 | |
522 | engine->led_mux = mux; |
523 | return 0; |
524 | } |
525 | |
526 | static ssize_t store_engine_leds(struct device *dev, |
527 | struct device_attribute *attr, |
528 | const char *buf, size_t len, int nr) |
529 | { |
530 | struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev)); |
531 | struct lp55xx_chip *chip = led->chip; |
532 | struct lp55xx_engine *engine = &chip->engines[nr - 1]; |
533 | u16 mux = 0; |
534 | ssize_t ret; |
535 | |
536 | if (lp5523_mux_parse(buf, mux: &mux, len)) |
537 | return -EINVAL; |
538 | |
539 | mutex_lock(&chip->lock); |
540 | |
541 | chip->engine_idx = nr; |
542 | ret = -EINVAL; |
543 | |
544 | if (engine->mode != LP55XX_ENGINE_LOAD) |
545 | goto leave; |
546 | |
547 | if (lp5523_load_mux(chip, mux, nr)) |
548 | goto leave; |
549 | |
550 | ret = len; |
551 | leave: |
552 | mutex_unlock(lock: &chip->lock); |
553 | return ret; |
554 | } |
555 | store_leds(1) |
556 | store_leds(2) |
557 | store_leds(3) |
558 | |
559 | static ssize_t store_engine_load(struct device *dev, |
560 | struct device_attribute *attr, |
561 | const char *buf, size_t len, int nr) |
562 | { |
563 | struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev)); |
564 | struct lp55xx_chip *chip = led->chip; |
565 | int ret; |
566 | |
567 | mutex_lock(&chip->lock); |
568 | |
569 | chip->engine_idx = nr; |
570 | lp5523_load_engine_and_select_page(chip); |
571 | ret = lp5523_update_program_memory(chip, data: buf, size: len); |
572 | |
573 | mutex_unlock(lock: &chip->lock); |
574 | |
575 | return ret; |
576 | } |
577 | store_load(1) |
578 | store_load(2) |
579 | store_load(3) |
580 | |
581 | static ssize_t lp5523_selftest(struct device *dev, |
582 | struct device_attribute *attr, |
583 | char *buf) |
584 | { |
585 | struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev)); |
586 | struct lp55xx_chip *chip = led->chip; |
587 | struct lp55xx_platform_data *pdata = chip->pdata; |
588 | int ret, pos = 0; |
589 | u8 status, adc, vdd, i; |
590 | |
591 | mutex_lock(&chip->lock); |
592 | |
593 | ret = lp55xx_read(chip, LP5523_REG_STATUS, val: &status); |
594 | if (ret < 0) |
595 | goto fail; |
596 | |
597 | /* Check that ext clock is really in use if requested */ |
598 | if (pdata->clock_mode == LP55XX_CLOCK_EXT) { |
599 | if ((status & LP5523_EXT_CLK_USED) == 0) |
600 | goto fail; |
601 | } |
602 | |
603 | /* Measure VDD (i.e. VBAT) first (channel 16 corresponds to VDD) */ |
604 | lp55xx_write(chip, LP5523_REG_LED_TEST_CTRL, LP5523_EN_LEDTEST | 16); |
605 | usleep_range(min: 3000, max: 6000); /* ADC conversion time is typically 2.7 ms */ |
606 | ret = lp55xx_read(chip, LP5523_REG_STATUS, val: &status); |
607 | if (ret < 0) |
608 | goto fail; |
609 | |
610 | if (!(status & LP5523_LEDTEST_DONE)) |
611 | usleep_range(min: 3000, max: 6000); /* Was not ready. Wait little bit */ |
612 | |
613 | ret = lp55xx_read(chip, LP5523_REG_LED_TEST_ADC, val: &vdd); |
614 | if (ret < 0) |
615 | goto fail; |
616 | |
617 | vdd--; /* There may be some fluctuation in measurement */ |
618 | |
619 | for (i = 0; i < pdata->num_channels; i++) { |
620 | /* Skip disabled channels */ |
621 | if (pdata->led_config[i].led_current == 0) |
622 | continue; |
623 | |
624 | /* Set default current */ |
625 | lp55xx_write(chip, LP5523_REG_LED_CURRENT_BASE + led->chan_nr, |
626 | val: pdata->led_config[i].led_current); |
627 | |
628 | lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + led->chan_nr, |
629 | val: 0xff); |
630 | /* let current stabilize 2 - 4ms before measurements start */ |
631 | usleep_range(min: 2000, max: 4000); |
632 | lp55xx_write(chip, LP5523_REG_LED_TEST_CTRL, |
633 | LP5523_EN_LEDTEST | led->chan_nr); |
634 | /* ADC conversion time is 2.7 ms typically */ |
635 | usleep_range(min: 3000, max: 6000); |
636 | ret = lp55xx_read(chip, LP5523_REG_STATUS, val: &status); |
637 | if (ret < 0) |
638 | goto fail; |
639 | |
640 | if (!(status & LP5523_LEDTEST_DONE)) |
641 | usleep_range(min: 3000, max: 6000); /* Was not ready. Wait. */ |
642 | |
643 | ret = lp55xx_read(chip, LP5523_REG_LED_TEST_ADC, val: &adc); |
644 | if (ret < 0) |
645 | goto fail; |
646 | |
647 | if (adc >= vdd || adc < LP5523_ADC_SHORTCIRC_LIM) |
648 | pos += sprintf(buf: buf + pos, fmt: "LED %d FAIL\n" , |
649 | led->chan_nr); |
650 | |
651 | lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + led->chan_nr, |
652 | val: 0x00); |
653 | |
654 | /* Restore current */ |
655 | lp55xx_write(chip, LP5523_REG_LED_CURRENT_BASE + led->chan_nr, |
656 | val: led->led_current); |
657 | led++; |
658 | } |
659 | if (pos == 0) |
660 | pos = sprintf(buf, fmt: "OK\n" ); |
661 | goto release_lock; |
662 | fail: |
663 | pos = sprintf(buf, fmt: "FAIL\n" ); |
664 | |
665 | release_lock: |
666 | mutex_unlock(lock: &chip->lock); |
667 | |
668 | return pos; |
669 | } |
670 | |
671 | #define show_fader(nr) \ |
672 | static ssize_t show_master_fader##nr(struct device *dev, \ |
673 | struct device_attribute *attr, \ |
674 | char *buf) \ |
675 | { \ |
676 | return show_master_fader(dev, attr, buf, nr); \ |
677 | } |
678 | |
679 | #define store_fader(nr) \ |
680 | static ssize_t store_master_fader##nr(struct device *dev, \ |
681 | struct device_attribute *attr, \ |
682 | const char *buf, size_t len) \ |
683 | { \ |
684 | return store_master_fader(dev, attr, buf, len, nr); \ |
685 | } |
686 | |
687 | static ssize_t show_master_fader(struct device *dev, |
688 | struct device_attribute *attr, |
689 | char *buf, int nr) |
690 | { |
691 | struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev)); |
692 | struct lp55xx_chip *chip = led->chip; |
693 | int ret; |
694 | u8 val; |
695 | |
696 | mutex_lock(&chip->lock); |
697 | ret = lp55xx_read(chip, LP5523_REG_MASTER_FADER_BASE + nr - 1, val: &val); |
698 | mutex_unlock(lock: &chip->lock); |
699 | |
700 | if (ret == 0) |
701 | ret = sprintf(buf, fmt: "%u\n" , val); |
702 | |
703 | return ret; |
704 | } |
705 | show_fader(1) |
706 | show_fader(2) |
707 | show_fader(3) |
708 | |
709 | static ssize_t store_master_fader(struct device *dev, |
710 | struct device_attribute *attr, |
711 | const char *buf, size_t len, int nr) |
712 | { |
713 | struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev)); |
714 | struct lp55xx_chip *chip = led->chip; |
715 | int ret; |
716 | unsigned long val; |
717 | |
718 | if (kstrtoul(s: buf, base: 0, res: &val)) |
719 | return -EINVAL; |
720 | |
721 | if (val > 0xff) |
722 | return -EINVAL; |
723 | |
724 | mutex_lock(&chip->lock); |
725 | ret = lp55xx_write(chip, LP5523_REG_MASTER_FADER_BASE + nr - 1, |
726 | val: (u8)val); |
727 | mutex_unlock(lock: &chip->lock); |
728 | |
729 | if (ret == 0) |
730 | ret = len; |
731 | |
732 | return ret; |
733 | } |
734 | store_fader(1) |
735 | store_fader(2) |
736 | store_fader(3) |
737 | |
738 | static ssize_t show_master_fader_leds(struct device *dev, |
739 | struct device_attribute *attr, |
740 | char *buf) |
741 | { |
742 | struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev)); |
743 | struct lp55xx_chip *chip = led->chip; |
744 | int i, ret, pos = 0; |
745 | u8 val; |
746 | |
747 | mutex_lock(&chip->lock); |
748 | |
749 | for (i = 0; i < LP5523_MAX_LEDS; i++) { |
750 | ret = lp55xx_read(chip, LP5523_REG_LED_CTRL_BASE + i, val: &val); |
751 | if (ret) |
752 | goto leave; |
753 | |
754 | val = (val & LP5523_FADER_MAPPING_MASK) |
755 | >> LP5523_FADER_MAPPING_SHIFT; |
756 | if (val > 3) { |
757 | ret = -EINVAL; |
758 | goto leave; |
759 | } |
760 | buf[pos++] = val + '0'; |
761 | } |
762 | buf[pos++] = '\n'; |
763 | ret = pos; |
764 | leave: |
765 | mutex_unlock(lock: &chip->lock); |
766 | return ret; |
767 | } |
768 | |
769 | static ssize_t store_master_fader_leds(struct device *dev, |
770 | struct device_attribute *attr, |
771 | const char *buf, size_t len) |
772 | { |
773 | struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev)); |
774 | struct lp55xx_chip *chip = led->chip; |
775 | int i, n, ret; |
776 | u8 val; |
777 | |
778 | n = min_t(int, len, LP5523_MAX_LEDS); |
779 | |
780 | mutex_lock(&chip->lock); |
781 | |
782 | for (i = 0; i < n; i++) { |
783 | if (buf[i] >= '0' && buf[i] <= '3') { |
784 | val = (buf[i] - '0') << LP5523_FADER_MAPPING_SHIFT; |
785 | ret = lp55xx_update_bits(chip, |
786 | LP5523_REG_LED_CTRL_BASE + i, |
787 | LP5523_FADER_MAPPING_MASK, |
788 | val); |
789 | if (ret) |
790 | goto leave; |
791 | } else { |
792 | ret = -EINVAL; |
793 | goto leave; |
794 | } |
795 | } |
796 | ret = len; |
797 | leave: |
798 | mutex_unlock(lock: &chip->lock); |
799 | return ret; |
800 | } |
801 | |
802 | static int lp5523_multicolor_brightness(struct lp55xx_led *led) |
803 | { |
804 | struct lp55xx_chip *chip = led->chip; |
805 | int ret; |
806 | int i; |
807 | |
808 | mutex_lock(&chip->lock); |
809 | for (i = 0; i < led->mc_cdev.num_colors; i++) { |
810 | ret = lp55xx_write(chip, |
811 | LP5523_REG_LED_PWM_BASE + |
812 | led->mc_cdev.subled_info[i].channel, |
813 | val: led->mc_cdev.subled_info[i].brightness); |
814 | if (ret) |
815 | break; |
816 | } |
817 | mutex_unlock(lock: &chip->lock); |
818 | return ret; |
819 | } |
820 | |
821 | static int lp5523_led_brightness(struct lp55xx_led *led) |
822 | { |
823 | struct lp55xx_chip *chip = led->chip; |
824 | int ret; |
825 | |
826 | mutex_lock(&chip->lock); |
827 | ret = lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + led->chan_nr, |
828 | val: led->brightness); |
829 | mutex_unlock(lock: &chip->lock); |
830 | return ret; |
831 | } |
832 | |
833 | static LP55XX_DEV_ATTR_RW(engine1_mode, show_engine1_mode, store_engine1_mode); |
834 | static LP55XX_DEV_ATTR_RW(engine2_mode, show_engine2_mode, store_engine2_mode); |
835 | static LP55XX_DEV_ATTR_RW(engine3_mode, show_engine3_mode, store_engine3_mode); |
836 | static LP55XX_DEV_ATTR_RW(engine1_leds, show_engine1_leds, store_engine1_leds); |
837 | static LP55XX_DEV_ATTR_RW(engine2_leds, show_engine2_leds, store_engine2_leds); |
838 | static LP55XX_DEV_ATTR_RW(engine3_leds, show_engine3_leds, store_engine3_leds); |
839 | static LP55XX_DEV_ATTR_WO(engine1_load, store_engine1_load); |
840 | static LP55XX_DEV_ATTR_WO(engine2_load, store_engine2_load); |
841 | static LP55XX_DEV_ATTR_WO(engine3_load, store_engine3_load); |
842 | static LP55XX_DEV_ATTR_RO(selftest, lp5523_selftest); |
843 | static LP55XX_DEV_ATTR_RW(master_fader1, show_master_fader1, |
844 | store_master_fader1); |
845 | static LP55XX_DEV_ATTR_RW(master_fader2, show_master_fader2, |
846 | store_master_fader2); |
847 | static LP55XX_DEV_ATTR_RW(master_fader3, show_master_fader3, |
848 | store_master_fader3); |
849 | static LP55XX_DEV_ATTR_RW(master_fader_leds, show_master_fader_leds, |
850 | store_master_fader_leds); |
851 | |
852 | static struct attribute *lp5523_attributes[] = { |
853 | &dev_attr_engine1_mode.attr, |
854 | &dev_attr_engine2_mode.attr, |
855 | &dev_attr_engine3_mode.attr, |
856 | &dev_attr_engine1_load.attr, |
857 | &dev_attr_engine2_load.attr, |
858 | &dev_attr_engine3_load.attr, |
859 | &dev_attr_engine1_leds.attr, |
860 | &dev_attr_engine2_leds.attr, |
861 | &dev_attr_engine3_leds.attr, |
862 | &dev_attr_selftest.attr, |
863 | &dev_attr_master_fader1.attr, |
864 | &dev_attr_master_fader2.attr, |
865 | &dev_attr_master_fader3.attr, |
866 | &dev_attr_master_fader_leds.attr, |
867 | NULL, |
868 | }; |
869 | |
870 | static const struct attribute_group lp5523_group = { |
871 | .attrs = lp5523_attributes, |
872 | }; |
873 | |
874 | /* Chip specific configurations */ |
875 | static struct lp55xx_device_config lp5523_cfg = { |
876 | .reset = { |
877 | .addr = LP5523_REG_RESET, |
878 | .val = LP5523_RESET, |
879 | }, |
880 | .enable = { |
881 | .addr = LP5523_REG_ENABLE, |
882 | .val = LP5523_ENABLE, |
883 | }, |
884 | .max_channel = LP5523_MAX_LEDS, |
885 | .post_init_device = lp5523_post_init_device, |
886 | .brightness_fn = lp5523_led_brightness, |
887 | .multicolor_brightness_fn = lp5523_multicolor_brightness, |
888 | .set_led_current = lp5523_set_led_current, |
889 | .firmware_cb = lp5523_firmware_loaded, |
890 | .run_engine = lp5523_run_engine, |
891 | .dev_attr_group = &lp5523_group, |
892 | }; |
893 | |
894 | static int lp5523_probe(struct i2c_client *client) |
895 | { |
896 | const struct i2c_device_id *id = i2c_client_get_device_id(client); |
897 | int ret; |
898 | struct lp55xx_chip *chip; |
899 | struct lp55xx_led *led; |
900 | struct lp55xx_platform_data *pdata = dev_get_platdata(dev: &client->dev); |
901 | struct device_node *np = dev_of_node(dev: &client->dev); |
902 | |
903 | chip = devm_kzalloc(dev: &client->dev, size: sizeof(*chip), GFP_KERNEL); |
904 | if (!chip) |
905 | return -ENOMEM; |
906 | |
907 | chip->cfg = &lp5523_cfg; |
908 | |
909 | if (!pdata) { |
910 | if (np) { |
911 | pdata = lp55xx_of_populate_pdata(dev: &client->dev, np, |
912 | chip); |
913 | if (IS_ERR(ptr: pdata)) |
914 | return PTR_ERR(ptr: pdata); |
915 | } else { |
916 | dev_err(&client->dev, "no platform data\n" ); |
917 | return -EINVAL; |
918 | } |
919 | } |
920 | |
921 | led = devm_kcalloc(dev: &client->dev, |
922 | n: pdata->num_channels, size: sizeof(*led), GFP_KERNEL); |
923 | if (!led) |
924 | return -ENOMEM; |
925 | |
926 | chip->cl = client; |
927 | chip->pdata = pdata; |
928 | |
929 | mutex_init(&chip->lock); |
930 | |
931 | i2c_set_clientdata(client, data: led); |
932 | |
933 | ret = lp55xx_init_device(chip); |
934 | if (ret) |
935 | goto err_init; |
936 | |
937 | dev_info(&client->dev, "%s Programmable led chip found\n" , id->name); |
938 | |
939 | ret = lp55xx_register_leds(led, chip); |
940 | if (ret) |
941 | goto err_out; |
942 | |
943 | ret = lp55xx_register_sysfs(chip); |
944 | if (ret) { |
945 | dev_err(&client->dev, "registering sysfs failed\n" ); |
946 | goto err_out; |
947 | } |
948 | |
949 | return 0; |
950 | |
951 | err_out: |
952 | lp55xx_deinit_device(chip); |
953 | err_init: |
954 | return ret; |
955 | } |
956 | |
957 | static void lp5523_remove(struct i2c_client *client) |
958 | { |
959 | struct lp55xx_led *led = i2c_get_clientdata(client); |
960 | struct lp55xx_chip *chip = led->chip; |
961 | |
962 | lp5523_stop_all_engines(chip); |
963 | lp55xx_unregister_sysfs(chip); |
964 | lp55xx_deinit_device(chip); |
965 | } |
966 | |
967 | static const struct i2c_device_id lp5523_id[] = { |
968 | { "lp5523" , LP5523 }, |
969 | { "lp55231" , LP55231 }, |
970 | { } |
971 | }; |
972 | |
973 | MODULE_DEVICE_TABLE(i2c, lp5523_id); |
974 | |
975 | static const struct of_device_id of_lp5523_leds_match[] = { |
976 | { .compatible = "national,lp5523" , }, |
977 | { .compatible = "ti,lp55231" , }, |
978 | {}, |
979 | }; |
980 | |
981 | MODULE_DEVICE_TABLE(of, of_lp5523_leds_match); |
982 | |
983 | static struct i2c_driver lp5523_driver = { |
984 | .driver = { |
985 | .name = "lp5523x" , |
986 | .of_match_table = of_lp5523_leds_match, |
987 | }, |
988 | .probe = lp5523_probe, |
989 | .remove = lp5523_remove, |
990 | .id_table = lp5523_id, |
991 | }; |
992 | |
993 | module_i2c_driver(lp5523_driver); |
994 | |
995 | MODULE_AUTHOR("Mathias Nyman <mathias.nyman@nokia.com>" ); |
996 | MODULE_AUTHOR("Milo Kim <milo.kim@ti.com>" ); |
997 | MODULE_DESCRIPTION("LP5523 LED engine" ); |
998 | MODULE_LICENSE("GPL" ); |
999 | |