Commit db6eaf8388a413a5ee1b4547ce78506b9c6456b0
Committed by
Bryan Wu
1 parent
9ce7cb170f
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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>
Showing 1 changed file with 157 additions and 346 deletions Side-by-side Diff
drivers/leds/leds-lp5523.c
... | ... | @@ -35,6 +35,7 @@ |
35 | 35 | #include <linux/workqueue.h> |
36 | 36 | #include <linux/slab.h> |
37 | 37 | #include <linux/platform_data/leds-lp55xx.h> |
38 | +#include <linux/firmware.h> | |
38 | 39 | |
39 | 40 | #include "leds-lp55xx-common.h" |
40 | 41 | |
41 | 42 | |
... | ... | @@ -108,20 +109,39 @@ |
108 | 109 | #define LED_ACTIVE(mux, led) (!!(mux & (0x0001 << led))) |
109 | 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 | 140 | enum lp5523_chip_id { |
112 | 141 | LP5523, |
113 | 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 | 145 | struct lp5523_led { |
126 | 146 | int id; |
127 | 147 | u8 chan_nr; |
128 | 148 | |
... | ... | @@ -135,13 +155,17 @@ |
135 | 155 | struct lp5523_chip { |
136 | 156 | struct mutex lock; /* Serialize control */ |
137 | 157 | struct i2c_client *client; |
138 | - struct lp5523_engine engines[LP5523_ENGINES]; | |
139 | 158 | struct lp5523_led leds[LP5523_MAX_LEDS]; |
140 | 159 | struct lp5523_platform_data *pdata; |
141 | 160 | u8 num_channels; |
142 | 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 | 169 | static void lp5523_set_led_current(struct lp55xx_led *led, u8 led_current) |
146 | 170 | { |
147 | 171 | led->led_current = led_current; |
... | ... | @@ -149,27 +173,6 @@ |
149 | 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 | 176 | static int lp5523_write(struct i2c_client *client, u8 reg, u8 value) |
174 | 177 | { |
175 | 178 | return i2c_smbus_write_byte_data(client, reg, value); |
176 | 179 | |
177 | 180 | |
178 | 181 | |
179 | 182 | |
180 | 183 | |
181 | 184 | |
182 | 185 | |
183 | 186 | |
184 | 187 | |
185 | 188 | |
186 | 189 | |
187 | 190 | |
188 | 191 | |
189 | 192 | |
190 | 193 | |
191 | 194 | |
192 | 195 | |
193 | 196 | |
194 | 197 | |
195 | 198 | |
196 | 199 | |
197 | 200 | |
198 | 201 | |
199 | 202 | |
200 | 203 | |
201 | 204 | |
202 | 205 | |
203 | 206 | |
204 | 207 | |
205 | 208 | |
206 | 209 | |
207 | 210 | |
208 | 211 | |
209 | 212 | |
210 | 213 | |
211 | 214 | |
... | ... | @@ -212,178 +215,163 @@ |
212 | 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); | |
218 | - struct i2c_client *client = chip->client; | |
219 | - int ret; | |
220 | - u8 engine_state; | |
220 | + enum lp55xx_engine_index idx = chip->engine_idx; | |
221 | + u8 mask[] = { | |
222 | + [LP55XX_ENGINE_1] = LP5523_MODE_ENG1_M, | |
223 | + [LP55XX_ENGINE_2] = LP5523_MODE_ENG2_M, | |
224 | + [LP55XX_ENGINE_3] = LP5523_MODE_ENG3_M, | |
225 | + }; | |
221 | 226 | |
222 | - ret = lp5523_read(client, LP5523_REG_OP_MODE, &engine_state); | |
223 | - if (ret) | |
224 | - goto fail; | |
227 | + u8 val[] = { | |
228 | + [LP55XX_ENGINE_1] = LP5523_LOAD_ENG1, | |
229 | + [LP55XX_ENGINE_2] = LP5523_LOAD_ENG2, | |
230 | + [LP55XX_ENGINE_3] = LP5523_LOAD_ENG3, | |
231 | + }; | |
225 | 232 | |
226 | - engine_state &= ~(engine->engine_mask); | |
233 | + u8 page_sel[] = { | |
234 | + [LP55XX_ENGINE_1] = LP5523_PAGE_ENG1, | |
235 | + [LP55XX_ENGINE_2] = LP5523_PAGE_ENG2, | |
236 | + [LP55XX_ENGINE_3] = LP5523_PAGE_ENG3, | |
237 | + }; | |
227 | 238 | |
228 | - /* set mode only for this engine */ | |
229 | - mode &= engine->engine_mask; | |
239 | + lp55xx_update_bits(chip, LP5523_REG_OP_MODE, mask[idx], val[idx]); | |
230 | 240 | |
231 | - engine_state |= mode; | |
241 | + lp5523_wait_opmode_done(); | |
232 | 242 | |
233 | - ret |= lp5523_write(client, LP5523_REG_OP_MODE, engine_state); | |
234 | -fail: | |
235 | - return ret; | |
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); | |
241 | - struct i2c_client *client = chip->client; | |
242 | - int ret = 0; | |
248 | + lp55xx_write(chip, LP5523_REG_OP_MODE, 0); | |
249 | + lp5523_wait_opmode_done(); | |
250 | +} | |
243 | 251 | |
244 | - ret |= lp5523_set_engine_mode(engine, LP5523_CMD_LOAD); | |
252 | +static void lp5523_turn_off_channels(struct lp55xx_chip *chip) | |
253 | +{ | |
254 | + int i; | |
245 | 255 | |
246 | - ret |= lp5523_write(client, LP5523_REG_PROG_PAGE_SEL, engine->mux_page); | |
247 | - ret |= lp5523_write(client, LP5523_REG_PROG_MEM, | |
248 | - (u8)(mux >> 8)); | |
249 | - ret |= lp5523_write(client, LP5523_REG_PROG_MEM + 1, (u8)(mux)); | |
250 | - engine->led_mux = mux; | |
251 | - | |
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); | |
258 | - struct i2c_client *client = chip->client; | |
262 | + int ret; | |
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, | |
265 | - engine->prog_page); | |
266 | - ret |= i2c_smbus_write_i2c_block_data(client, LP5523_REG_PROG_MEM, | |
267 | - LP5523_PROGRAM_LENGTH, pattern); | |
278 | + ret = lp55xx_read(chip, LP5523_REG_OP_MODE, &mode); | |
279 | + if (ret) | |
280 | + return; | |
268 | 281 | |
269 | - return ret; | |
270 | -} | |
282 | + ret = lp55xx_read(chip, LP5523_REG_ENABLE, &exec); | |
283 | + if (ret) | |
284 | + return; | |
271 | 285 | |
272 | -static int lp5523_run_program(struct lp5523_engine *engine) | |
273 | -{ | |
274 | - struct lp5523_chip *chip = engine_to_lp5523(engine); | |
275 | - struct i2c_client *client = chip->client; | |
276 | - int ret; | |
286 | + /* change operation mode to RUN only when each engine is loading */ | |
287 | + if (LP5523_ENG1_IS_LOADING(mode)) { | |
288 | + mode = (mode & ~LP5523_MODE_ENG1_M) | LP5523_RUN_ENG1; | |
289 | + exec = (exec & ~LP5523_EXEC_ENG1_M) | LP5523_RUN_ENG1; | |
290 | + } | |
277 | 291 | |
278 | - ret = lp5523_write(client, LP5523_REG_ENABLE, | |
279 | - LP5523_CMD_RUN | LP5523_ENABLE); | |
280 | - if (ret) | |
281 | - goto fail; | |
292 | + if (LP5523_ENG2_IS_LOADING(mode)) { | |
293 | + mode = (mode & ~LP5523_MODE_ENG2_M) | LP5523_RUN_ENG2; | |
294 | + exec = (exec & ~LP5523_EXEC_ENG2_M) | LP5523_RUN_ENG2; | |
295 | + } | |
282 | 296 | |
283 | - ret = lp5523_set_engine_mode(engine, LP5523_CMD_RUN); | |
284 | -fail: | |
285 | - return ret; | |
297 | + if (LP5523_ENG3_IS_LOADING(mode)) { | |
298 | + mode = (mode & ~LP5523_MODE_ENG3_M) | LP5523_RUN_ENG3; | |
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 | 318 | int i; |
291 | - u16 tmp_mux = 0; | |
292 | 319 | |
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; | |
320 | + /* clear program memory before updating */ | |
321 | + for (i = 0; i < LP5523_PROGRAM_LENGTH; i++) | |
322 | + lp55xx_write(chip, LP5523_REG_PROG_MEM + i, 0); | |
309 | 323 | |
310 | - return 0; | |
311 | -} | |
324 | + i = 0; | |
325 | + while ((offset < size - 1) && (i < LP5523_PROGRAM_LENGTH)) { | |
326 | + /* separate sscanfs because length is working only for %s */ | |
327 | + ret = sscanf(data + offset, "%2s%n ", c, &nrchars); | |
328 | + if (ret != 1) | |
329 | + goto err; | |
312 | 330 | |
313 | -static void lp5523_mux_to_array(u16 led_mux, char *array) | |
314 | -{ | |
315 | - int i, pos = 0; | |
316 | - for (i = 0; i < LP5523_MAX_LEDS; i++) | |
317 | - pos += sprintf(array + pos, "%x", LED_ACTIVE(led_mux, i)); | |
331 | + ret = sscanf(c, "%2x", &cmd); | |
332 | + if (ret != 1) | |
333 | + goto err; | |
318 | 334 | |
319 | - array[pos] = '\0'; | |
320 | -} | |
335 | + pattern[i] = (u8)cmd; | |
336 | + offset += nrchars; | |
337 | + i++; | |
338 | + } | |
321 | 339 | |
322 | -/*--------------------------------------------------------------*/ | |
323 | -/* Sysfs interface */ | |
324 | -/*--------------------------------------------------------------*/ | |
340 | + /* Each instruction is 16bit long. Check that length is even */ | |
341 | + if (i % 2) | |
342 | + goto err; | |
325 | 343 | |
326 | -static ssize_t show_engine_leds(struct device *dev, | |
327 | - struct device_attribute *attr, | |
328 | - char *buf, int nr) | |
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]; | |
344 | + update_size = i; | |
345 | + for (i = 0; i < update_size; i++) | |
346 | + lp55xx_write(chip, LP5523_REG_PROG_MEM + i, pattern[i]); | |
333 | 347 | |
334 | - lp5523_mux_to_array(chip->engines[nr - 1].led_mux, mux); | |
348 | + return 0; | |
335 | 349 | |
336 | - return sprintf(buf, "%s\n", mux); | |
350 | +err: | |
351 | + dev_err(&chip->cl->dev, "wrong pattern format\n"); | |
352 | + return -EINVAL; | |
337 | 353 | } |
338 | 354 | |
339 | -#define show_leds(nr) \ | |
340 | -static ssize_t show_engine##nr##_leds(struct device *dev, \ | |
341 | - struct device_attribute *attr, \ | |
342 | - char *buf) \ | |
343 | -{ \ | |
344 | - return show_engine_leds(dev, attr, buf, nr); \ | |
345 | -} | |
346 | -show_leds(1) | |
347 | -show_leds(2) | |
348 | -show_leds(3) | |
349 | - | |
350 | -static ssize_t store_engine_leds(struct device *dev, | |
351 | - struct device_attribute *attr, | |
352 | - const char *buf, size_t len, int nr) | |
355 | +static void lp5523_firmware_loaded(struct lp55xx_chip *chip) | |
353 | 356 | { |
354 | - struct i2c_client *client = to_i2c_client(dev); | |
355 | - struct lp5523_chip *chip = i2c_get_clientdata(client); | |
356 | - u16 mux = 0; | |
357 | - ssize_t ret; | |
357 | + const struct firmware *fw = chip->fw; | |
358 | 358 | |
359 | - if (lp5523_mux_parse(buf, &mux, len)) | |
360 | - return -EINVAL; | |
359 | + if (fw->size > LP5523_PROGRAM_LENGTH) { | |
360 | + dev_err(&chip->cl->dev, "firmware data size overflow: %zu\n", | |
361 | + fw->size); | |
362 | + return; | |
363 | + } | |
361 | 364 | |
362 | - mutex_lock(&chip->lock); | |
363 | - ret = -EINVAL; | |
364 | - if (chip->engines[nr - 1].mode != LP5523_CMD_LOAD) | |
365 | - goto leave; | |
365 | + /* | |
366 | + * Program momery sequence | |
367 | + * 1) set engine mode to "LOAD" | |
368 | + * 2) write firmware data into program memory | |
369 | + */ | |
366 | 370 | |
367 | - if (lp5523_load_mux(&chip->engines[nr - 1], mux)) | |
368 | - goto leave; | |
369 | - | |
370 | - ret = len; | |
371 | -leave: | |
372 | - mutex_unlock(&chip->lock); | |
373 | - return ret; | |
371 | + lp5523_load_engine(chip); | |
372 | + lp5523_update_program_memory(chip, fw->data, fw->size); | |
374 | 373 | } |
375 | 374 | |
376 | -#define store_leds(nr) \ | |
377 | -static ssize_t store_engine##nr##_leds(struct device *dev, \ | |
378 | - struct device_attribute *attr, \ | |
379 | - const char *buf, size_t len) \ | |
380 | -{ \ | |
381 | - return store_engine_leds(dev, attr, buf, len, nr); \ | |
382 | -} | |
383 | -store_leds(1) | |
384 | -store_leds(2) | |
385 | -store_leds(3) | |
386 | - | |
387 | 375 | static ssize_t lp5523_selftest(struct device *dev, |
388 | 376 | struct device_attribute *attr, |
389 | 377 | char *buf) |
390 | 378 | |
391 | 379 | |
... | ... | @@ -485,159 +473,10 @@ |
485 | 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 | 476 | static DEVICE_ATTR(selftest, S_IRUGO, lp5523_selftest, NULL); |
629 | 477 | |
630 | 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 | 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 | 480 | NULL, |
642 | 481 | }; |
643 | 482 | |
... | ... | @@ -664,36 +503,6 @@ |
664 | 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 | 506 | /* Chip specific configurations */ |
698 | 507 | static struct lp55xx_device_config lp5523_cfg = { |
699 | 508 | .reset = { |
... | ... | @@ -708,6 +517,8 @@ |
708 | 517 | .post_init_device = lp5523_post_init_device, |
709 | 518 | .brightness_work_fn = lp5523_led_brightness_work, |
710 | 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 | 524 | static int lp5523_probe(struct i2c_client *client, |