1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * drivers/media/i2c/lm3560.c |
4 | * General device driver for TI lm3559, lm3560, FLASH LED Driver |
5 | * |
6 | * Copyright (C) 2013 Texas Instruments |
7 | * |
8 | * Contact: Daniel Jeong <gshark.jeong@gmail.com> |
9 | * Ldd-Mlp <ldd-mlp@list.ti.com> |
10 | */ |
11 | |
12 | #include <linux/delay.h> |
13 | #include <linux/module.h> |
14 | #include <linux/i2c.h> |
15 | #include <linux/slab.h> |
16 | #include <linux/mutex.h> |
17 | #include <linux/regmap.h> |
18 | #include <linux/videodev2.h> |
19 | #include <media/i2c/lm3560.h> |
20 | #include <media/v4l2-ctrls.h> |
21 | #include <media/v4l2-device.h> |
22 | |
23 | /* registers definitions */ |
24 | #define REG_ENABLE 0x10 |
25 | #define REG_TORCH_BR 0xa0 |
26 | #define REG_FLASH_BR 0xb0 |
27 | #define REG_FLASH_TOUT 0xc0 |
28 | #define REG_FLAG 0xd0 |
29 | #define REG_CONFIG1 0xe0 |
30 | |
31 | /* fault mask */ |
32 | #define FAULT_TIMEOUT (1<<0) |
33 | #define FAULT_OVERTEMP (1<<1) |
34 | #define FAULT_SHORT_CIRCUIT (1<<2) |
35 | |
36 | enum led_enable { |
37 | MODE_SHDN = 0x0, |
38 | MODE_TORCH = 0x2, |
39 | MODE_FLASH = 0x3, |
40 | }; |
41 | |
42 | /** |
43 | * struct lm3560_flash |
44 | * |
45 | * @dev: pointer to &struct device |
46 | * @pdata: platform data |
47 | * @regmap: reg. map for i2c |
48 | * @lock: muxtex for serial access. |
49 | * @led_mode: V4L2 LED mode |
50 | * @ctrls_led: V4L2 controls |
51 | * @subdev_led: V4L2 subdev |
52 | */ |
53 | struct lm3560_flash { |
54 | struct device *dev; |
55 | struct lm3560_platform_data *pdata; |
56 | struct regmap *regmap; |
57 | struct mutex lock; |
58 | |
59 | enum v4l2_flash_led_mode led_mode; |
60 | struct v4l2_ctrl_handler ctrls_led[LM3560_LED_MAX]; |
61 | struct v4l2_subdev subdev_led[LM3560_LED_MAX]; |
62 | }; |
63 | |
64 | #define to_lm3560_flash(_ctrl, _no) \ |
65 | container_of(_ctrl->handler, struct lm3560_flash, ctrls_led[_no]) |
66 | |
67 | /* enable mode control */ |
68 | static int lm3560_mode_ctrl(struct lm3560_flash *flash) |
69 | { |
70 | int rval = -EINVAL; |
71 | |
72 | switch (flash->led_mode) { |
73 | case V4L2_FLASH_LED_MODE_NONE: |
74 | rval = regmap_update_bits(map: flash->regmap, |
75 | REG_ENABLE, mask: 0x03, val: MODE_SHDN); |
76 | break; |
77 | case V4L2_FLASH_LED_MODE_TORCH: |
78 | rval = regmap_update_bits(map: flash->regmap, |
79 | REG_ENABLE, mask: 0x03, val: MODE_TORCH); |
80 | break; |
81 | case V4L2_FLASH_LED_MODE_FLASH: |
82 | rval = regmap_update_bits(map: flash->regmap, |
83 | REG_ENABLE, mask: 0x03, val: MODE_FLASH); |
84 | break; |
85 | } |
86 | return rval; |
87 | } |
88 | |
89 | /* led1/2 enable/disable */ |
90 | static int lm3560_enable_ctrl(struct lm3560_flash *flash, |
91 | enum lm3560_led_id led_no, bool on) |
92 | { |
93 | int rval; |
94 | |
95 | if (led_no == LM3560_LED0) { |
96 | if (on) |
97 | rval = regmap_update_bits(map: flash->regmap, |
98 | REG_ENABLE, mask: 0x08, val: 0x08); |
99 | else |
100 | rval = regmap_update_bits(map: flash->regmap, |
101 | REG_ENABLE, mask: 0x08, val: 0x00); |
102 | } else { |
103 | if (on) |
104 | rval = regmap_update_bits(map: flash->regmap, |
105 | REG_ENABLE, mask: 0x10, val: 0x10); |
106 | else |
107 | rval = regmap_update_bits(map: flash->regmap, |
108 | REG_ENABLE, mask: 0x10, val: 0x00); |
109 | } |
110 | return rval; |
111 | } |
112 | |
113 | /* torch1/2 brightness control */ |
114 | static int lm3560_torch_brt_ctrl(struct lm3560_flash *flash, |
115 | enum lm3560_led_id led_no, unsigned int brt) |
116 | { |
117 | int rval; |
118 | u8 br_bits; |
119 | |
120 | if (brt < LM3560_TORCH_BRT_MIN) |
121 | return lm3560_enable_ctrl(flash, led_no, on: false); |
122 | else |
123 | rval = lm3560_enable_ctrl(flash, led_no, on: true); |
124 | |
125 | br_bits = LM3560_TORCH_BRT_uA_TO_REG(brt); |
126 | if (led_no == LM3560_LED0) |
127 | rval = regmap_update_bits(map: flash->regmap, |
128 | REG_TORCH_BR, mask: 0x07, val: br_bits); |
129 | else |
130 | rval = regmap_update_bits(map: flash->regmap, |
131 | REG_TORCH_BR, mask: 0x38, val: br_bits << 3); |
132 | |
133 | return rval; |
134 | } |
135 | |
136 | /* flash1/2 brightness control */ |
137 | static int lm3560_flash_brt_ctrl(struct lm3560_flash *flash, |
138 | enum lm3560_led_id led_no, unsigned int brt) |
139 | { |
140 | int rval; |
141 | u8 br_bits; |
142 | |
143 | if (brt < LM3560_FLASH_BRT_MIN) |
144 | return lm3560_enable_ctrl(flash, led_no, on: false); |
145 | else |
146 | rval = lm3560_enable_ctrl(flash, led_no, on: true); |
147 | |
148 | br_bits = LM3560_FLASH_BRT_uA_TO_REG(brt); |
149 | if (led_no == LM3560_LED0) |
150 | rval = regmap_update_bits(map: flash->regmap, |
151 | REG_FLASH_BR, mask: 0x0f, val: br_bits); |
152 | else |
153 | rval = regmap_update_bits(map: flash->regmap, |
154 | REG_FLASH_BR, mask: 0xf0, val: br_bits << 4); |
155 | |
156 | return rval; |
157 | } |
158 | |
159 | /* v4l2 controls */ |
160 | static int lm3560_get_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no) |
161 | { |
162 | struct lm3560_flash *flash = to_lm3560_flash(ctrl, led_no); |
163 | int rval = -EINVAL; |
164 | |
165 | mutex_lock(&flash->lock); |
166 | |
167 | if (ctrl->id == V4L2_CID_FLASH_FAULT) { |
168 | s32 fault = 0; |
169 | unsigned int reg_val; |
170 | rval = regmap_read(map: flash->regmap, REG_FLAG, val: ®_val); |
171 | if (rval < 0) |
172 | goto out; |
173 | if (reg_val & FAULT_SHORT_CIRCUIT) |
174 | fault |= V4L2_FLASH_FAULT_SHORT_CIRCUIT; |
175 | if (reg_val & FAULT_OVERTEMP) |
176 | fault |= V4L2_FLASH_FAULT_OVER_TEMPERATURE; |
177 | if (reg_val & FAULT_TIMEOUT) |
178 | fault |= V4L2_FLASH_FAULT_TIMEOUT; |
179 | ctrl->cur.val = fault; |
180 | } |
181 | |
182 | out: |
183 | mutex_unlock(lock: &flash->lock); |
184 | return rval; |
185 | } |
186 | |
187 | static int lm3560_set_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no) |
188 | { |
189 | struct lm3560_flash *flash = to_lm3560_flash(ctrl, led_no); |
190 | u8 tout_bits; |
191 | int rval = -EINVAL; |
192 | |
193 | mutex_lock(&flash->lock); |
194 | |
195 | switch (ctrl->id) { |
196 | case V4L2_CID_FLASH_LED_MODE: |
197 | flash->led_mode = ctrl->val; |
198 | if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) |
199 | rval = lm3560_mode_ctrl(flash); |
200 | break; |
201 | |
202 | case V4L2_CID_FLASH_STROBE_SOURCE: |
203 | rval = regmap_update_bits(map: flash->regmap, |
204 | REG_CONFIG1, mask: 0x04, val: (ctrl->val) << 2); |
205 | if (rval < 0) |
206 | goto err_out; |
207 | break; |
208 | |
209 | case V4L2_CID_FLASH_STROBE: |
210 | if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) { |
211 | rval = -EBUSY; |
212 | goto err_out; |
213 | } |
214 | flash->led_mode = V4L2_FLASH_LED_MODE_FLASH; |
215 | rval = lm3560_mode_ctrl(flash); |
216 | break; |
217 | |
218 | case V4L2_CID_FLASH_STROBE_STOP: |
219 | if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) { |
220 | rval = -EBUSY; |
221 | goto err_out; |
222 | } |
223 | flash->led_mode = V4L2_FLASH_LED_MODE_NONE; |
224 | rval = lm3560_mode_ctrl(flash); |
225 | break; |
226 | |
227 | case V4L2_CID_FLASH_TIMEOUT: |
228 | tout_bits = LM3560_FLASH_TOUT_ms_TO_REG(ctrl->val); |
229 | rval = regmap_update_bits(map: flash->regmap, |
230 | REG_FLASH_TOUT, mask: 0x1f, val: tout_bits); |
231 | break; |
232 | |
233 | case V4L2_CID_FLASH_INTENSITY: |
234 | rval = lm3560_flash_brt_ctrl(flash, led_no, brt: ctrl->val); |
235 | break; |
236 | |
237 | case V4L2_CID_FLASH_TORCH_INTENSITY: |
238 | rval = lm3560_torch_brt_ctrl(flash, led_no, brt: ctrl->val); |
239 | break; |
240 | } |
241 | |
242 | err_out: |
243 | mutex_unlock(lock: &flash->lock); |
244 | return rval; |
245 | } |
246 | |
247 | static int lm3560_led1_get_ctrl(struct v4l2_ctrl *ctrl) |
248 | { |
249 | return lm3560_get_ctrl(ctrl, led_no: LM3560_LED1); |
250 | } |
251 | |
252 | static int lm3560_led1_set_ctrl(struct v4l2_ctrl *ctrl) |
253 | { |
254 | return lm3560_set_ctrl(ctrl, led_no: LM3560_LED1); |
255 | } |
256 | |
257 | static int lm3560_led0_get_ctrl(struct v4l2_ctrl *ctrl) |
258 | { |
259 | return lm3560_get_ctrl(ctrl, led_no: LM3560_LED0); |
260 | } |
261 | |
262 | static int lm3560_led0_set_ctrl(struct v4l2_ctrl *ctrl) |
263 | { |
264 | return lm3560_set_ctrl(ctrl, led_no: LM3560_LED0); |
265 | } |
266 | |
267 | static const struct v4l2_ctrl_ops lm3560_led_ctrl_ops[LM3560_LED_MAX] = { |
268 | [LM3560_LED0] = { |
269 | .g_volatile_ctrl = lm3560_led0_get_ctrl, |
270 | .s_ctrl = lm3560_led0_set_ctrl, |
271 | }, |
272 | [LM3560_LED1] = { |
273 | .g_volatile_ctrl = lm3560_led1_get_ctrl, |
274 | .s_ctrl = lm3560_led1_set_ctrl, |
275 | } |
276 | }; |
277 | |
278 | static int lm3560_init_controls(struct lm3560_flash *flash, |
279 | enum lm3560_led_id led_no) |
280 | { |
281 | struct v4l2_ctrl *fault; |
282 | u32 max_flash_brt = flash->pdata->max_flash_brt[led_no]; |
283 | u32 max_torch_brt = flash->pdata->max_torch_brt[led_no]; |
284 | struct v4l2_ctrl_handler *hdl = &flash->ctrls_led[led_no]; |
285 | const struct v4l2_ctrl_ops *ops = &lm3560_led_ctrl_ops[led_no]; |
286 | |
287 | v4l2_ctrl_handler_init(hdl, 8); |
288 | |
289 | /* flash mode */ |
290 | v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_FLASH_LED_MODE, |
291 | max: V4L2_FLASH_LED_MODE_TORCH, mask: ~0x7, |
292 | def: V4L2_FLASH_LED_MODE_NONE); |
293 | flash->led_mode = V4L2_FLASH_LED_MODE_NONE; |
294 | |
295 | /* flash source */ |
296 | v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_FLASH_STROBE_SOURCE, |
297 | max: 0x1, mask: ~0x3, def: V4L2_FLASH_STROBE_SOURCE_SOFTWARE); |
298 | |
299 | /* flash strobe */ |
300 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE, min: 0, max: 0, step: 0, def: 0); |
301 | |
302 | /* flash strobe stop */ |
303 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE_STOP, min: 0, max: 0, step: 0, def: 0); |
304 | |
305 | /* flash strobe timeout */ |
306 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_TIMEOUT, |
307 | LM3560_FLASH_TOUT_MIN, |
308 | max: flash->pdata->max_flash_timeout, |
309 | LM3560_FLASH_TOUT_STEP, |
310 | def: flash->pdata->max_flash_timeout); |
311 | |
312 | /* flash brt */ |
313 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_INTENSITY, |
314 | LM3560_FLASH_BRT_MIN, max: max_flash_brt, |
315 | LM3560_FLASH_BRT_STEP, def: max_flash_brt); |
316 | |
317 | /* torch brt */ |
318 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_TORCH_INTENSITY, |
319 | LM3560_TORCH_BRT_MIN, max: max_torch_brt, |
320 | LM3560_TORCH_BRT_STEP, def: max_torch_brt); |
321 | |
322 | /* fault */ |
323 | fault = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_FAULT, min: 0, |
324 | V4L2_FLASH_FAULT_OVER_VOLTAGE |
325 | | V4L2_FLASH_FAULT_OVER_TEMPERATURE |
326 | | V4L2_FLASH_FAULT_SHORT_CIRCUIT |
327 | | V4L2_FLASH_FAULT_TIMEOUT, step: 0, def: 0); |
328 | if (fault != NULL) |
329 | fault->flags |= V4L2_CTRL_FLAG_VOLATILE; |
330 | |
331 | if (hdl->error) |
332 | return hdl->error; |
333 | |
334 | flash->subdev_led[led_no].ctrl_handler = hdl; |
335 | return 0; |
336 | } |
337 | |
338 | /* initialize device */ |
339 | static const struct v4l2_subdev_ops lm3560_ops = { |
340 | .core = NULL, |
341 | }; |
342 | |
343 | static const struct regmap_config lm3560_regmap = { |
344 | .reg_bits = 8, |
345 | .val_bits = 8, |
346 | .max_register = 0xFF, |
347 | }; |
348 | |
349 | static int lm3560_subdev_init(struct lm3560_flash *flash, |
350 | enum lm3560_led_id led_no, char *led_name) |
351 | { |
352 | struct i2c_client *client = to_i2c_client(flash->dev); |
353 | int rval; |
354 | |
355 | v4l2_i2c_subdev_init(sd: &flash->subdev_led[led_no], client, ops: &lm3560_ops); |
356 | flash->subdev_led[led_no].flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
357 | strscpy(flash->subdev_led[led_no].name, led_name, |
358 | sizeof(flash->subdev_led[led_no].name)); |
359 | rval = lm3560_init_controls(flash, led_no); |
360 | if (rval) |
361 | goto err_out; |
362 | rval = media_entity_pads_init(entity: &flash->subdev_led[led_no].entity, num_pads: 0, NULL); |
363 | if (rval < 0) |
364 | goto err_out; |
365 | flash->subdev_led[led_no].entity.function = MEDIA_ENT_F_FLASH; |
366 | |
367 | return rval; |
368 | |
369 | err_out: |
370 | v4l2_ctrl_handler_free(hdl: &flash->ctrls_led[led_no]); |
371 | return rval; |
372 | } |
373 | |
374 | static int lm3560_init_device(struct lm3560_flash *flash) |
375 | { |
376 | int rval; |
377 | unsigned int reg_val; |
378 | |
379 | /* set peak current */ |
380 | rval = regmap_update_bits(map: flash->regmap, |
381 | REG_FLASH_TOUT, mask: 0x60, val: flash->pdata->peak); |
382 | if (rval < 0) |
383 | return rval; |
384 | /* output disable */ |
385 | flash->led_mode = V4L2_FLASH_LED_MODE_NONE; |
386 | rval = lm3560_mode_ctrl(flash); |
387 | if (rval < 0) |
388 | return rval; |
389 | /* reset faults */ |
390 | rval = regmap_read(map: flash->regmap, REG_FLAG, val: ®_val); |
391 | return rval; |
392 | } |
393 | |
394 | static int lm3560_probe(struct i2c_client *client) |
395 | { |
396 | struct lm3560_flash *flash; |
397 | struct lm3560_platform_data *pdata = dev_get_platdata(dev: &client->dev); |
398 | int rval; |
399 | |
400 | flash = devm_kzalloc(dev: &client->dev, size: sizeof(*flash), GFP_KERNEL); |
401 | if (flash == NULL) |
402 | return -ENOMEM; |
403 | |
404 | flash->regmap = devm_regmap_init_i2c(client, &lm3560_regmap); |
405 | if (IS_ERR(ptr: flash->regmap)) { |
406 | rval = PTR_ERR(ptr: flash->regmap); |
407 | return rval; |
408 | } |
409 | |
410 | /* if there is no platform data, use chip default value */ |
411 | if (pdata == NULL) { |
412 | pdata = devm_kzalloc(dev: &client->dev, size: sizeof(*pdata), GFP_KERNEL); |
413 | if (pdata == NULL) |
414 | return -ENODEV; |
415 | pdata->peak = LM3560_PEAK_3600mA; |
416 | pdata->max_flash_timeout = LM3560_FLASH_TOUT_MAX; |
417 | /* led 1 */ |
418 | pdata->max_flash_brt[LM3560_LED0] = LM3560_FLASH_BRT_MAX; |
419 | pdata->max_torch_brt[LM3560_LED0] = LM3560_TORCH_BRT_MAX; |
420 | /* led 2 */ |
421 | pdata->max_flash_brt[LM3560_LED1] = LM3560_FLASH_BRT_MAX; |
422 | pdata->max_torch_brt[LM3560_LED1] = LM3560_TORCH_BRT_MAX; |
423 | } |
424 | flash->pdata = pdata; |
425 | flash->dev = &client->dev; |
426 | mutex_init(&flash->lock); |
427 | |
428 | rval = lm3560_subdev_init(flash, led_no: LM3560_LED0, led_name: "lm3560-led0" ); |
429 | if (rval < 0) |
430 | return rval; |
431 | |
432 | rval = lm3560_subdev_init(flash, led_no: LM3560_LED1, led_name: "lm3560-led1" ); |
433 | if (rval < 0) |
434 | return rval; |
435 | |
436 | rval = lm3560_init_device(flash); |
437 | if (rval < 0) |
438 | return rval; |
439 | |
440 | i2c_set_clientdata(client, data: flash); |
441 | |
442 | return 0; |
443 | } |
444 | |
445 | static void lm3560_remove(struct i2c_client *client) |
446 | { |
447 | struct lm3560_flash *flash = i2c_get_clientdata(client); |
448 | unsigned int i; |
449 | |
450 | for (i = LM3560_LED0; i < LM3560_LED_MAX; i++) { |
451 | v4l2_device_unregister_subdev(sd: &flash->subdev_led[i]); |
452 | v4l2_ctrl_handler_free(hdl: &flash->ctrls_led[i]); |
453 | media_entity_cleanup(entity: &flash->subdev_led[i].entity); |
454 | } |
455 | } |
456 | |
457 | static const struct i2c_device_id lm3560_id_table[] = { |
458 | {LM3559_NAME, 0}, |
459 | {LM3560_NAME, 0}, |
460 | {} |
461 | }; |
462 | |
463 | MODULE_DEVICE_TABLE(i2c, lm3560_id_table); |
464 | |
465 | static struct i2c_driver lm3560_i2c_driver = { |
466 | .driver = { |
467 | .name = LM3560_NAME, |
468 | .pm = NULL, |
469 | }, |
470 | .probe = lm3560_probe, |
471 | .remove = lm3560_remove, |
472 | .id_table = lm3560_id_table, |
473 | }; |
474 | |
475 | module_i2c_driver(lm3560_i2c_driver); |
476 | |
477 | MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>" ); |
478 | MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>" ); |
479 | MODULE_DESCRIPTION("Texas Instruments LM3560 LED flash driver" ); |
480 | MODULE_LICENSE("GPL" ); |
481 | |