1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * drivers/media/i2c/adp1653.c |
4 | * |
5 | * Copyright (C) 2008--2011 Nokia Corporation |
6 | * |
7 | * Contact: Sakari Ailus <sakari.ailus@iki.fi> |
8 | * |
9 | * Contributors: |
10 | * Sakari Ailus <sakari.ailus@iki.fi> |
11 | * Tuukka Toivonen <tuukkat76@gmail.com> |
12 | * Pavel Machek <pavel@ucw.cz> |
13 | * |
14 | * TODO: |
15 | * - fault interrupt handling |
16 | * - hardware strobe |
17 | * - power doesn't need to be ON if all lights are off |
18 | */ |
19 | |
20 | #include <linux/delay.h> |
21 | #include <linux/module.h> |
22 | #include <linux/i2c.h> |
23 | #include <linux/slab.h> |
24 | #include <linux/of.h> |
25 | #include <linux/gpio/consumer.h> |
26 | #include <media/i2c/adp1653.h> |
27 | #include <media/v4l2-device.h> |
28 | |
29 | #define TIMEOUT_MAX 820000 |
30 | #define TIMEOUT_STEP 54600 |
31 | #define TIMEOUT_MIN (TIMEOUT_MAX - ADP1653_REG_CONFIG_TMR_SET_MAX \ |
32 | * TIMEOUT_STEP) |
33 | #define TIMEOUT_US_TO_CODE(t) ((TIMEOUT_MAX + (TIMEOUT_STEP / 2) - (t)) \ |
34 | / TIMEOUT_STEP) |
35 | #define TIMEOUT_CODE_TO_US(c) (TIMEOUT_MAX - (c) * TIMEOUT_STEP) |
36 | |
37 | /* Write values into ADP1653 registers. */ |
38 | static int adp1653_update_hw(struct adp1653_flash *flash) |
39 | { |
40 | struct i2c_client *client = v4l2_get_subdevdata(sd: &flash->subdev); |
41 | u8 out_sel; |
42 | u8 config = 0; |
43 | int rval; |
44 | |
45 | out_sel = ADP1653_INDICATOR_INTENSITY_uA_TO_REG( |
46 | flash->indicator_intensity->val) |
47 | << ADP1653_REG_OUT_SEL_ILED_SHIFT; |
48 | |
49 | switch (flash->led_mode->val) { |
50 | case V4L2_FLASH_LED_MODE_NONE: |
51 | break; |
52 | case V4L2_FLASH_LED_MODE_FLASH: |
53 | /* Flash mode, light on with strobe, duration from timer */ |
54 | config = ADP1653_REG_CONFIG_TMR_CFG; |
55 | config |= TIMEOUT_US_TO_CODE(flash->flash_timeout->val) |
56 | << ADP1653_REG_CONFIG_TMR_SET_SHIFT; |
57 | break; |
58 | case V4L2_FLASH_LED_MODE_TORCH: |
59 | /* Torch mode, light immediately on, duration indefinite */ |
60 | out_sel |= ADP1653_FLASH_INTENSITY_mA_TO_REG( |
61 | flash->torch_intensity->val) |
62 | << ADP1653_REG_OUT_SEL_HPLED_SHIFT; |
63 | break; |
64 | } |
65 | |
66 | rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, value: out_sel); |
67 | if (rval < 0) |
68 | return rval; |
69 | |
70 | rval = i2c_smbus_write_byte_data(client, ADP1653_REG_CONFIG, value: config); |
71 | if (rval < 0) |
72 | return rval; |
73 | |
74 | return 0; |
75 | } |
76 | |
77 | static int adp1653_get_fault(struct adp1653_flash *flash) |
78 | { |
79 | struct i2c_client *client = v4l2_get_subdevdata(sd: &flash->subdev); |
80 | int fault; |
81 | int rval; |
82 | |
83 | fault = i2c_smbus_read_byte_data(client, ADP1653_REG_FAULT); |
84 | if (fault < 0) |
85 | return fault; |
86 | |
87 | flash->fault |= fault; |
88 | |
89 | if (!flash->fault) |
90 | return 0; |
91 | |
92 | /* Clear faults. */ |
93 | rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, value: 0); |
94 | if (rval < 0) |
95 | return rval; |
96 | |
97 | flash->led_mode->val = V4L2_FLASH_LED_MODE_NONE; |
98 | |
99 | rval = adp1653_update_hw(flash); |
100 | if (rval) |
101 | return rval; |
102 | |
103 | return flash->fault; |
104 | } |
105 | |
106 | static int adp1653_strobe(struct adp1653_flash *flash, int enable) |
107 | { |
108 | struct i2c_client *client = v4l2_get_subdevdata(sd: &flash->subdev); |
109 | u8 out_sel = ADP1653_INDICATOR_INTENSITY_uA_TO_REG( |
110 | flash->indicator_intensity->val) |
111 | << ADP1653_REG_OUT_SEL_ILED_SHIFT; |
112 | int rval; |
113 | |
114 | if (flash->led_mode->val != V4L2_FLASH_LED_MODE_FLASH) |
115 | return -EBUSY; |
116 | |
117 | if (!enable) |
118 | return i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, |
119 | value: out_sel); |
120 | |
121 | out_sel |= ADP1653_FLASH_INTENSITY_mA_TO_REG( |
122 | flash->flash_intensity->val) |
123 | << ADP1653_REG_OUT_SEL_HPLED_SHIFT; |
124 | rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, value: out_sel); |
125 | if (rval) |
126 | return rval; |
127 | |
128 | /* Software strobe using i2c */ |
129 | rval = i2c_smbus_write_byte_data(client, ADP1653_REG_SW_STROBE, |
130 | ADP1653_REG_SW_STROBE_SW_STROBE); |
131 | if (rval) |
132 | return rval; |
133 | return i2c_smbus_write_byte_data(client, ADP1653_REG_SW_STROBE, value: 0); |
134 | } |
135 | |
136 | /* -------------------------------------------------------------------------- |
137 | * V4L2 controls |
138 | */ |
139 | |
140 | static int adp1653_get_ctrl(struct v4l2_ctrl *ctrl) |
141 | { |
142 | struct adp1653_flash *flash = |
143 | container_of(ctrl->handler, struct adp1653_flash, ctrls); |
144 | int rval; |
145 | |
146 | rval = adp1653_get_fault(flash); |
147 | if (rval) |
148 | return rval; |
149 | |
150 | ctrl->cur.val = 0; |
151 | |
152 | if (flash->fault & ADP1653_REG_FAULT_FLT_SCP) |
153 | ctrl->cur.val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT; |
154 | if (flash->fault & ADP1653_REG_FAULT_FLT_OT) |
155 | ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE; |
156 | if (flash->fault & ADP1653_REG_FAULT_FLT_TMR) |
157 | ctrl->cur.val |= V4L2_FLASH_FAULT_TIMEOUT; |
158 | if (flash->fault & ADP1653_REG_FAULT_FLT_OV) |
159 | ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_VOLTAGE; |
160 | |
161 | flash->fault = 0; |
162 | |
163 | return 0; |
164 | } |
165 | |
166 | static int adp1653_set_ctrl(struct v4l2_ctrl *ctrl) |
167 | { |
168 | struct adp1653_flash *flash = |
169 | container_of(ctrl->handler, struct adp1653_flash, ctrls); |
170 | int rval; |
171 | |
172 | rval = adp1653_get_fault(flash); |
173 | if (rval) |
174 | return rval; |
175 | if ((rval & (ADP1653_REG_FAULT_FLT_SCP | |
176 | ADP1653_REG_FAULT_FLT_OT | |
177 | ADP1653_REG_FAULT_FLT_OV)) && |
178 | (ctrl->id == V4L2_CID_FLASH_STROBE || |
179 | ctrl->id == V4L2_CID_FLASH_TORCH_INTENSITY || |
180 | ctrl->id == V4L2_CID_FLASH_LED_MODE)) |
181 | return -EBUSY; |
182 | |
183 | switch (ctrl->id) { |
184 | case V4L2_CID_FLASH_STROBE: |
185 | return adp1653_strobe(flash, enable: 1); |
186 | case V4L2_CID_FLASH_STROBE_STOP: |
187 | return adp1653_strobe(flash, enable: 0); |
188 | } |
189 | |
190 | return adp1653_update_hw(flash); |
191 | } |
192 | |
193 | static const struct v4l2_ctrl_ops adp1653_ctrl_ops = { |
194 | .g_volatile_ctrl = adp1653_get_ctrl, |
195 | .s_ctrl = adp1653_set_ctrl, |
196 | }; |
197 | |
198 | static int adp1653_init_controls(struct adp1653_flash *flash) |
199 | { |
200 | struct v4l2_ctrl *fault; |
201 | |
202 | v4l2_ctrl_handler_init(&flash->ctrls, 9); |
203 | |
204 | flash->led_mode = |
205 | v4l2_ctrl_new_std_menu(hdl: &flash->ctrls, ops: &adp1653_ctrl_ops, |
206 | V4L2_CID_FLASH_LED_MODE, |
207 | max: V4L2_FLASH_LED_MODE_TORCH, mask: ~0x7, def: 0); |
208 | v4l2_ctrl_new_std_menu(hdl: &flash->ctrls, ops: &adp1653_ctrl_ops, |
209 | V4L2_CID_FLASH_STROBE_SOURCE, |
210 | max: V4L2_FLASH_STROBE_SOURCE_SOFTWARE, mask: ~0x1, def: 0); |
211 | v4l2_ctrl_new_std(hdl: &flash->ctrls, ops: &adp1653_ctrl_ops, |
212 | V4L2_CID_FLASH_STROBE, min: 0, max: 0, step: 0, def: 0); |
213 | v4l2_ctrl_new_std(hdl: &flash->ctrls, ops: &adp1653_ctrl_ops, |
214 | V4L2_CID_FLASH_STROBE_STOP, min: 0, max: 0, step: 0, def: 0); |
215 | flash->flash_timeout = |
216 | v4l2_ctrl_new_std(hdl: &flash->ctrls, ops: &adp1653_ctrl_ops, |
217 | V4L2_CID_FLASH_TIMEOUT, TIMEOUT_MIN, |
218 | max: flash->platform_data->max_flash_timeout, |
219 | TIMEOUT_STEP, |
220 | def: flash->platform_data->max_flash_timeout); |
221 | flash->flash_intensity = |
222 | v4l2_ctrl_new_std(hdl: &flash->ctrls, ops: &adp1653_ctrl_ops, |
223 | V4L2_CID_FLASH_INTENSITY, |
224 | ADP1653_FLASH_INTENSITY_MIN, |
225 | max: flash->platform_data->max_flash_intensity, |
226 | step: 1, def: flash->platform_data->max_flash_intensity); |
227 | flash->torch_intensity = |
228 | v4l2_ctrl_new_std(hdl: &flash->ctrls, ops: &adp1653_ctrl_ops, |
229 | V4L2_CID_FLASH_TORCH_INTENSITY, |
230 | ADP1653_TORCH_INTENSITY_MIN, |
231 | max: flash->platform_data->max_torch_intensity, |
232 | ADP1653_FLASH_INTENSITY_STEP, |
233 | def: flash->platform_data->max_torch_intensity); |
234 | flash->indicator_intensity = |
235 | v4l2_ctrl_new_std(hdl: &flash->ctrls, ops: &adp1653_ctrl_ops, |
236 | V4L2_CID_FLASH_INDICATOR_INTENSITY, |
237 | ADP1653_INDICATOR_INTENSITY_MIN, |
238 | max: flash->platform_data->max_indicator_intensity, |
239 | ADP1653_INDICATOR_INTENSITY_STEP, |
240 | ADP1653_INDICATOR_INTENSITY_MIN); |
241 | fault = v4l2_ctrl_new_std(hdl: &flash->ctrls, ops: &adp1653_ctrl_ops, |
242 | V4L2_CID_FLASH_FAULT, min: 0, |
243 | V4L2_FLASH_FAULT_OVER_VOLTAGE |
244 | | V4L2_FLASH_FAULT_OVER_TEMPERATURE |
245 | | V4L2_FLASH_FAULT_SHORT_CIRCUIT, step: 0, def: 0); |
246 | |
247 | if (flash->ctrls.error) |
248 | return flash->ctrls.error; |
249 | |
250 | fault->flags |= V4L2_CTRL_FLAG_VOLATILE; |
251 | |
252 | flash->subdev.ctrl_handler = &flash->ctrls; |
253 | return 0; |
254 | } |
255 | |
256 | /* -------------------------------------------------------------------------- |
257 | * V4L2 subdev operations |
258 | */ |
259 | |
260 | static int |
261 | adp1653_init_device(struct adp1653_flash *flash) |
262 | { |
263 | struct i2c_client *client = v4l2_get_subdevdata(sd: &flash->subdev); |
264 | int rval; |
265 | |
266 | /* Clear FAULT register by writing zero to OUT_SEL */ |
267 | rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, value: 0); |
268 | if (rval < 0) { |
269 | dev_err(&client->dev, "failed writing fault register\n" ); |
270 | return -EIO; |
271 | } |
272 | |
273 | mutex_lock(flash->ctrls.lock); |
274 | /* Reset faults before reading new ones. */ |
275 | flash->fault = 0; |
276 | rval = adp1653_get_fault(flash); |
277 | mutex_unlock(lock: flash->ctrls.lock); |
278 | if (rval > 0) { |
279 | dev_err(&client->dev, "faults detected: 0x%1.1x\n" , rval); |
280 | return -EIO; |
281 | } |
282 | |
283 | mutex_lock(flash->ctrls.lock); |
284 | rval = adp1653_update_hw(flash); |
285 | mutex_unlock(lock: flash->ctrls.lock); |
286 | if (rval) { |
287 | dev_err(&client->dev, |
288 | "adp1653_update_hw failed at %s\n" , __func__); |
289 | return -EIO; |
290 | } |
291 | |
292 | return 0; |
293 | } |
294 | |
295 | static int |
296 | __adp1653_set_power(struct adp1653_flash *flash, int on) |
297 | { |
298 | int ret; |
299 | |
300 | if (flash->platform_data->power) { |
301 | ret = flash->platform_data->power(&flash->subdev, on); |
302 | if (ret < 0) |
303 | return ret; |
304 | } else { |
305 | gpiod_set_value(desc: flash->platform_data->enable_gpio, value: on); |
306 | if (on) |
307 | /* Some delay is apparently required. */ |
308 | udelay(20); |
309 | } |
310 | |
311 | if (!on) |
312 | return 0; |
313 | |
314 | ret = adp1653_init_device(flash); |
315 | if (ret >= 0) |
316 | return ret; |
317 | |
318 | if (flash->platform_data->power) |
319 | flash->platform_data->power(&flash->subdev, 0); |
320 | else |
321 | gpiod_set_value(desc: flash->platform_data->enable_gpio, value: 0); |
322 | |
323 | return ret; |
324 | } |
325 | |
326 | static int |
327 | adp1653_set_power(struct v4l2_subdev *subdev, int on) |
328 | { |
329 | struct adp1653_flash *flash = to_adp1653_flash(subdev); |
330 | int ret = 0; |
331 | |
332 | mutex_lock(&flash->power_lock); |
333 | |
334 | /* If the power count is modified from 0 to != 0 or from != 0 to 0, |
335 | * update the power state. |
336 | */ |
337 | if (flash->power_count == !on) { |
338 | ret = __adp1653_set_power(flash, on: !!on); |
339 | if (ret < 0) |
340 | goto done; |
341 | } |
342 | |
343 | /* Update the power count. */ |
344 | flash->power_count += on ? 1 : -1; |
345 | WARN_ON(flash->power_count < 0); |
346 | |
347 | done: |
348 | mutex_unlock(lock: &flash->power_lock); |
349 | return ret; |
350 | } |
351 | |
352 | static int adp1653_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) |
353 | { |
354 | return adp1653_set_power(subdev: sd, on: 1); |
355 | } |
356 | |
357 | static int adp1653_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) |
358 | { |
359 | return adp1653_set_power(subdev: sd, on: 0); |
360 | } |
361 | |
362 | static const struct v4l2_subdev_core_ops adp1653_core_ops = { |
363 | .s_power = adp1653_set_power, |
364 | }; |
365 | |
366 | static const struct v4l2_subdev_ops adp1653_ops = { |
367 | .core = &adp1653_core_ops, |
368 | }; |
369 | |
370 | static const struct v4l2_subdev_internal_ops adp1653_internal_ops = { |
371 | .open = adp1653_open, |
372 | .close = adp1653_close, |
373 | }; |
374 | |
375 | /* -------------------------------------------------------------------------- |
376 | * I2C driver |
377 | */ |
378 | #ifdef CONFIG_PM |
379 | |
380 | static int adp1653_suspend(struct device *dev) |
381 | { |
382 | struct v4l2_subdev *subdev = dev_get_drvdata(dev); |
383 | struct adp1653_flash *flash = to_adp1653_flash(subdev); |
384 | |
385 | if (!flash->power_count) |
386 | return 0; |
387 | |
388 | return __adp1653_set_power(flash, on: 0); |
389 | } |
390 | |
391 | static int adp1653_resume(struct device *dev) |
392 | { |
393 | struct v4l2_subdev *subdev = dev_get_drvdata(dev); |
394 | struct adp1653_flash *flash = to_adp1653_flash(subdev); |
395 | |
396 | if (!flash->power_count) |
397 | return 0; |
398 | |
399 | return __adp1653_set_power(flash, on: 1); |
400 | } |
401 | |
402 | #else |
403 | |
404 | #define adp1653_suspend NULL |
405 | #define adp1653_resume NULL |
406 | |
407 | #endif /* CONFIG_PM */ |
408 | |
409 | static int adp1653_of_init(struct i2c_client *client, |
410 | struct adp1653_flash *flash, |
411 | struct device_node *node) |
412 | { |
413 | struct adp1653_platform_data *pd; |
414 | struct device_node *node_indicator = NULL; |
415 | struct device_node *node_flash; |
416 | |
417 | pd = devm_kzalloc(dev: &client->dev, size: sizeof(*pd), GFP_KERNEL); |
418 | if (!pd) |
419 | return -ENOMEM; |
420 | flash->platform_data = pd; |
421 | |
422 | node_flash = of_get_child_by_name(node, name: "flash" ); |
423 | if (!node_flash) |
424 | return -EINVAL; |
425 | |
426 | if (of_property_read_u32(np: node_flash, propname: "flash-timeout-us" , |
427 | out_value: &pd->max_flash_timeout)) |
428 | goto err; |
429 | |
430 | if (of_property_read_u32(np: node_flash, propname: "flash-max-microamp" , |
431 | out_value: &pd->max_flash_intensity)) |
432 | goto err; |
433 | |
434 | pd->max_flash_intensity /= 1000; |
435 | |
436 | if (of_property_read_u32(np: node_flash, propname: "led-max-microamp" , |
437 | out_value: &pd->max_torch_intensity)) |
438 | goto err; |
439 | |
440 | pd->max_torch_intensity /= 1000; |
441 | |
442 | node_indicator = of_get_child_by_name(node, name: "indicator" ); |
443 | if (!node_indicator) |
444 | goto err; |
445 | |
446 | if (of_property_read_u32(np: node_indicator, propname: "led-max-microamp" , |
447 | out_value: &pd->max_indicator_intensity)) |
448 | goto err; |
449 | |
450 | of_node_put(node: node_flash); |
451 | of_node_put(node: node_indicator); |
452 | |
453 | pd->enable_gpio = devm_gpiod_get(dev: &client->dev, con_id: "enable" , flags: GPIOD_OUT_LOW); |
454 | if (IS_ERR(ptr: pd->enable_gpio)) { |
455 | dev_err(&client->dev, "Error getting GPIO\n" ); |
456 | return PTR_ERR(ptr: pd->enable_gpio); |
457 | } |
458 | |
459 | return 0; |
460 | err: |
461 | dev_err(&client->dev, "Required property not found\n" ); |
462 | of_node_put(node: node_flash); |
463 | of_node_put(node: node_indicator); |
464 | return -EINVAL; |
465 | } |
466 | |
467 | |
468 | static int adp1653_probe(struct i2c_client *client) |
469 | { |
470 | struct adp1653_flash *flash; |
471 | int ret; |
472 | |
473 | flash = devm_kzalloc(dev: &client->dev, size: sizeof(*flash), GFP_KERNEL); |
474 | if (flash == NULL) |
475 | return -ENOMEM; |
476 | |
477 | if (client->dev.of_node) { |
478 | ret = adp1653_of_init(client, flash, node: client->dev.of_node); |
479 | if (ret) |
480 | return ret; |
481 | } else { |
482 | if (!client->dev.platform_data) { |
483 | dev_err(&client->dev, |
484 | "Neither DT not platform data provided\n" ); |
485 | return -EINVAL; |
486 | } |
487 | flash->platform_data = client->dev.platform_data; |
488 | } |
489 | |
490 | mutex_init(&flash->power_lock); |
491 | |
492 | v4l2_i2c_subdev_init(sd: &flash->subdev, client, ops: &adp1653_ops); |
493 | flash->subdev.internal_ops = &adp1653_internal_ops; |
494 | flash->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
495 | |
496 | ret = adp1653_init_controls(flash); |
497 | if (ret) |
498 | goto free_and_quit; |
499 | |
500 | ret = media_entity_pads_init(entity: &flash->subdev.entity, num_pads: 0, NULL); |
501 | if (ret < 0) |
502 | goto free_and_quit; |
503 | |
504 | flash->subdev.entity.function = MEDIA_ENT_F_FLASH; |
505 | |
506 | return 0; |
507 | |
508 | free_and_quit: |
509 | dev_err(&client->dev, "adp1653: failed to register device\n" ); |
510 | v4l2_ctrl_handler_free(hdl: &flash->ctrls); |
511 | return ret; |
512 | } |
513 | |
514 | static void adp1653_remove(struct i2c_client *client) |
515 | { |
516 | struct v4l2_subdev *subdev = i2c_get_clientdata(client); |
517 | struct adp1653_flash *flash = to_adp1653_flash(subdev); |
518 | |
519 | v4l2_device_unregister_subdev(sd: &flash->subdev); |
520 | v4l2_ctrl_handler_free(hdl: &flash->ctrls); |
521 | media_entity_cleanup(entity: &flash->subdev.entity); |
522 | } |
523 | |
524 | static const struct i2c_device_id adp1653_id_table[] = { |
525 | { ADP1653_NAME, 0 }, |
526 | { } |
527 | }; |
528 | MODULE_DEVICE_TABLE(i2c, adp1653_id_table); |
529 | |
530 | static const struct dev_pm_ops adp1653_pm_ops = { |
531 | .suspend = adp1653_suspend, |
532 | .resume = adp1653_resume, |
533 | }; |
534 | |
535 | static struct i2c_driver adp1653_i2c_driver = { |
536 | .driver = { |
537 | .name = ADP1653_NAME, |
538 | .pm = &adp1653_pm_ops, |
539 | }, |
540 | .probe = adp1653_probe, |
541 | .remove = adp1653_remove, |
542 | .id_table = adp1653_id_table, |
543 | }; |
544 | |
545 | module_i2c_driver(adp1653_i2c_driver); |
546 | |
547 | MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>" ); |
548 | MODULE_DESCRIPTION("Analog Devices ADP1653 LED flash driver" ); |
549 | MODULE_LICENSE("GPL" ); |
550 | |