xref: /openbmc/linux/drivers/media/i2c/lm3646.c (revision 461ba3e7)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * drivers/media/i2c/lm3646.c
4  * General device driver for TI lm3646, Dual FLASH LED Driver
5  *
6  * Copyright (C) 2014 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/i2c.h>
14 #include <linux/module.h>
15 #include <linux/slab.h>
16 #include <linux/regmap.h>
17 #include <linux/videodev2.h>
18 #include <media/i2c/lm3646.h>
19 #include <media/v4l2-ctrls.h>
20 #include <media/v4l2-device.h>
21 
22 /* registers definitions */
23 #define REG_ENABLE		0x01
24 #define REG_TORCH_BR	0x05
25 #define REG_FLASH_BR	0x05
26 #define REG_FLASH_TOUT	0x04
27 #define REG_FLAG		0x08
28 #define REG_STROBE_SRC	0x06
29 #define REG_LED1_FLASH_BR 0x06
30 #define REG_LED1_TORCH_BR 0x07
31 
32 #define MASK_ENABLE		0x03
33 #define MASK_TORCH_BR	0x70
34 #define MASK_FLASH_BR	0x0F
35 #define MASK_FLASH_TOUT	0x07
36 #define MASK_FLAG		0xFF
37 #define MASK_STROBE_SRC	0x80
38 
39 /* Fault Mask */
40 #define FAULT_TIMEOUT	(1<<0)
41 #define FAULT_SHORT_CIRCUIT	(1<<1)
42 #define FAULT_UVLO		(1<<2)
43 #define FAULT_IVFM		(1<<3)
44 #define FAULT_OCP		(1<<4)
45 #define FAULT_OVERTEMP	(1<<5)
46 #define FAULT_NTC_TRIP	(1<<6)
47 #define FAULT_OVP		(1<<7)
48 
49 enum led_mode {
50 	MODE_SHDN = 0x0,
51 	MODE_TORCH = 0x2,
52 	MODE_FLASH = 0x3,
53 };
54 
55 /*
56  * struct lm3646_flash
57  *
58  * @pdata: platform data
59  * @regmap: reg. map for i2c
60  * @lock: muxtex for serial access.
61  * @led_mode: V4L2 LED mode
62  * @ctrls_led: V4L2 controls
63  * @subdev_led: V4L2 subdev
64  * @mode_reg : mode register value
65  */
66 struct lm3646_flash {
67 	struct device *dev;
68 	struct lm3646_platform_data *pdata;
69 	struct regmap *regmap;
70 
71 	struct v4l2_ctrl_handler ctrls_led;
72 	struct v4l2_subdev subdev_led;
73 
74 	u8 mode_reg;
75 };
76 
77 #define to_lm3646_flash(_ctrl)	\
78 	container_of(_ctrl->handler, struct lm3646_flash, ctrls_led)
79 
80 /* enable mode control */
81 static int lm3646_mode_ctrl(struct lm3646_flash *flash,
82 			    enum v4l2_flash_led_mode led_mode)
83 {
84 	switch (led_mode) {
85 	case V4L2_FLASH_LED_MODE_NONE:
86 		return regmap_write(flash->regmap,
87 				    REG_ENABLE, flash->mode_reg | MODE_SHDN);
88 	case V4L2_FLASH_LED_MODE_TORCH:
89 		return regmap_write(flash->regmap,
90 				    REG_ENABLE, flash->mode_reg | MODE_TORCH);
91 	case V4L2_FLASH_LED_MODE_FLASH:
92 		return regmap_write(flash->regmap,
93 				    REG_ENABLE, flash->mode_reg | MODE_FLASH);
94 	}
95 	return -EINVAL;
96 }
97 
98 /* V4L2 controls  */
99 static int lm3646_get_ctrl(struct v4l2_ctrl *ctrl)
100 {
101 	struct lm3646_flash *flash = to_lm3646_flash(ctrl);
102 	unsigned int reg_val;
103 	int rval;
104 
105 	if (ctrl->id != V4L2_CID_FLASH_FAULT)
106 		return -EINVAL;
107 
108 	rval = regmap_read(flash->regmap, REG_FLAG, &reg_val);
109 	if (rval < 0)
110 		return rval;
111 
112 	ctrl->val = 0;
113 	if (reg_val & FAULT_TIMEOUT)
114 		ctrl->val |= V4L2_FLASH_FAULT_TIMEOUT;
115 	if (reg_val & FAULT_SHORT_CIRCUIT)
116 		ctrl->val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
117 	if (reg_val & FAULT_UVLO)
118 		ctrl->val |= V4L2_FLASH_FAULT_UNDER_VOLTAGE;
119 	if (reg_val & FAULT_IVFM)
120 		ctrl->val |= V4L2_FLASH_FAULT_INPUT_VOLTAGE;
121 	if (reg_val & FAULT_OCP)
122 		ctrl->val |= V4L2_FLASH_FAULT_OVER_CURRENT;
123 	if (reg_val & FAULT_OVERTEMP)
124 		ctrl->val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
125 	if (reg_val & FAULT_NTC_TRIP)
126 		ctrl->val |= V4L2_FLASH_FAULT_LED_OVER_TEMPERATURE;
127 	if (reg_val & FAULT_OVP)
128 		ctrl->val |= V4L2_FLASH_FAULT_OVER_VOLTAGE;
129 
130 	return 0;
131 }
132 
133 static int lm3646_set_ctrl(struct v4l2_ctrl *ctrl)
134 {
135 	struct lm3646_flash *flash = to_lm3646_flash(ctrl);
136 	unsigned int reg_val;
137 	int rval;
138 
139 	switch (ctrl->id) {
140 	case V4L2_CID_FLASH_LED_MODE:
141 
142 		if (ctrl->val != V4L2_FLASH_LED_MODE_FLASH)
143 			return lm3646_mode_ctrl(flash, ctrl->val);
144 		/* switch to SHDN mode before flash strobe on */
145 		return lm3646_mode_ctrl(flash, V4L2_FLASH_LED_MODE_NONE);
146 
147 	case V4L2_CID_FLASH_STROBE_SOURCE:
148 		return regmap_update_bits(flash->regmap,
149 					  REG_STROBE_SRC, MASK_STROBE_SRC,
150 					  (ctrl->val) << 7);
151 
152 	case V4L2_CID_FLASH_STROBE:
153 
154 		/* read and check current mode of chip to start flash */
155 		rval = regmap_read(flash->regmap, REG_ENABLE, &reg_val);
156 		if (rval < 0 || ((reg_val & MASK_ENABLE) != MODE_SHDN))
157 			return rval;
158 		/* flash on */
159 		return lm3646_mode_ctrl(flash, V4L2_FLASH_LED_MODE_FLASH);
160 
161 	case V4L2_CID_FLASH_STROBE_STOP:
162 
163 		/*
164 		 * flash mode will be turned automatically
165 		 * from FLASH mode to SHDN mode after flash duration timeout
166 		 * read and check current mode of chip to stop flash
167 		 */
168 		rval = regmap_read(flash->regmap, REG_ENABLE, &reg_val);
169 		if (rval < 0)
170 			return rval;
171 		if ((reg_val & MASK_ENABLE) == MODE_FLASH)
172 			return lm3646_mode_ctrl(flash,
173 						V4L2_FLASH_LED_MODE_NONE);
174 		return rval;
175 
176 	case V4L2_CID_FLASH_TIMEOUT:
177 		return regmap_update_bits(flash->regmap,
178 					  REG_FLASH_TOUT, MASK_FLASH_TOUT,
179 					  LM3646_FLASH_TOUT_ms_TO_REG
180 					  (ctrl->val));
181 
182 	case V4L2_CID_FLASH_INTENSITY:
183 		return regmap_update_bits(flash->regmap,
184 					  REG_FLASH_BR, MASK_FLASH_BR,
185 					  LM3646_TOTAL_FLASH_BRT_uA_TO_REG
186 					  (ctrl->val));
187 
188 	case V4L2_CID_FLASH_TORCH_INTENSITY:
189 		return regmap_update_bits(flash->regmap,
190 					  REG_TORCH_BR, MASK_TORCH_BR,
191 					  LM3646_TOTAL_TORCH_BRT_uA_TO_REG
192 					  (ctrl->val) << 4);
193 	}
194 
195 	return -EINVAL;
196 }
197 
198 static const struct v4l2_ctrl_ops lm3646_led_ctrl_ops = {
199 	.g_volatile_ctrl = lm3646_get_ctrl,
200 	.s_ctrl = lm3646_set_ctrl,
201 };
202 
203 static int lm3646_init_controls(struct lm3646_flash *flash)
204 {
205 	struct v4l2_ctrl *fault;
206 	struct v4l2_ctrl_handler *hdl = &flash->ctrls_led;
207 	const struct v4l2_ctrl_ops *ops = &lm3646_led_ctrl_ops;
208 
209 	v4l2_ctrl_handler_init(hdl, 8);
210 	/* flash mode */
211 	v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_FLASH_LED_MODE,
212 			       V4L2_FLASH_LED_MODE_TORCH, ~0x7,
213 			       V4L2_FLASH_LED_MODE_NONE);
214 
215 	/* flash source */
216 	v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_FLASH_STROBE_SOURCE,
217 			       0x1, ~0x3, V4L2_FLASH_STROBE_SOURCE_SOFTWARE);
218 
219 	/* flash strobe */
220 	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE, 0, 0, 0, 0);
221 	/* flash strobe stop */
222 	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0);
223 
224 	/* flash strobe timeout */
225 	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_TIMEOUT,
226 			  LM3646_FLASH_TOUT_MIN,
227 			  LM3646_FLASH_TOUT_MAX,
228 			  LM3646_FLASH_TOUT_STEP, flash->pdata->flash_timeout);
229 
230 	/* max flash current */
231 	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_INTENSITY,
232 			  LM3646_TOTAL_FLASH_BRT_MIN,
233 			  LM3646_TOTAL_FLASH_BRT_MAX,
234 			  LM3646_TOTAL_FLASH_BRT_STEP,
235 			  LM3646_TOTAL_FLASH_BRT_MAX);
236 
237 	/* max torch current */
238 	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_TORCH_INTENSITY,
239 			  LM3646_TOTAL_TORCH_BRT_MIN,
240 			  LM3646_TOTAL_TORCH_BRT_MAX,
241 			  LM3646_TOTAL_TORCH_BRT_STEP,
242 			  LM3646_TOTAL_TORCH_BRT_MAX);
243 
244 	/* fault */
245 	fault = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_FAULT, 0,
246 				  V4L2_FLASH_FAULT_OVER_VOLTAGE
247 				  | V4L2_FLASH_FAULT_OVER_TEMPERATURE
248 				  | V4L2_FLASH_FAULT_SHORT_CIRCUIT
249 				  | V4L2_FLASH_FAULT_TIMEOUT, 0, 0);
250 	if (fault != NULL)
251 		fault->flags |= V4L2_CTRL_FLAG_VOLATILE;
252 
253 	if (hdl->error)
254 		return hdl->error;
255 
256 	flash->subdev_led.ctrl_handler = hdl;
257 	return 0;
258 }
259 
260 /* initialize device */
261 static const struct v4l2_subdev_ops lm3646_ops = {
262 	.core = NULL,
263 };
264 
265 static const struct regmap_config lm3646_regmap = {
266 	.reg_bits = 8,
267 	.val_bits = 8,
268 	.max_register = 0xFF,
269 };
270 
271 static int lm3646_subdev_init(struct lm3646_flash *flash)
272 {
273 	struct i2c_client *client = to_i2c_client(flash->dev);
274 	int rval;
275 
276 	v4l2_i2c_subdev_init(&flash->subdev_led, client, &lm3646_ops);
277 	flash->subdev_led.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
278 	strscpy(flash->subdev_led.name, LM3646_NAME,
279 		sizeof(flash->subdev_led.name));
280 	rval = lm3646_init_controls(flash);
281 	if (rval)
282 		goto err_out;
283 	rval = media_entity_pads_init(&flash->subdev_led.entity, 0, NULL);
284 	if (rval < 0)
285 		goto err_out;
286 	flash->subdev_led.entity.function = MEDIA_ENT_F_FLASH;
287 	return rval;
288 
289 err_out:
290 	v4l2_ctrl_handler_free(&flash->ctrls_led);
291 	return rval;
292 }
293 
294 static int lm3646_init_device(struct lm3646_flash *flash)
295 {
296 	unsigned int reg_val;
297 	int rval;
298 
299 	/* read the value of mode register to reduce redundant i2c accesses */
300 	rval = regmap_read(flash->regmap, REG_ENABLE, &reg_val);
301 	if (rval < 0)
302 		return rval;
303 	flash->mode_reg = reg_val & 0xfc;
304 
305 	/* output disable */
306 	rval = lm3646_mode_ctrl(flash, V4L2_FLASH_LED_MODE_NONE);
307 	if (rval < 0)
308 		return rval;
309 
310 	/*
311 	 * LED1 flash current setting
312 	 * LED2 flash current = Total(Max) flash current - LED1 flash current
313 	 */
314 	rval = regmap_update_bits(flash->regmap,
315 				  REG_LED1_FLASH_BR, 0x7F,
316 				  LM3646_LED1_FLASH_BRT_uA_TO_REG
317 				  (flash->pdata->led1_flash_brt));
318 
319 	if (rval < 0)
320 		return rval;
321 
322 	/*
323 	 * LED1 torch current setting
324 	 * LED2 torch current = Total(Max) torch current - LED1 torch current
325 	 */
326 	rval = regmap_update_bits(flash->regmap,
327 				  REG_LED1_TORCH_BR, 0x7F,
328 				  LM3646_LED1_TORCH_BRT_uA_TO_REG
329 				  (flash->pdata->led1_torch_brt));
330 	if (rval < 0)
331 		return rval;
332 
333 	/* Reset flag register */
334 	return regmap_read(flash->regmap, REG_FLAG, &reg_val);
335 }
336 
337 static int lm3646_probe(struct i2c_client *client)
338 {
339 	struct lm3646_flash *flash;
340 	struct lm3646_platform_data *pdata = dev_get_platdata(&client->dev);
341 	int rval;
342 
343 	flash = devm_kzalloc(&client->dev, sizeof(*flash), GFP_KERNEL);
344 	if (flash == NULL)
345 		return -ENOMEM;
346 
347 	flash->regmap = devm_regmap_init_i2c(client, &lm3646_regmap);
348 	if (IS_ERR(flash->regmap))
349 		return PTR_ERR(flash->regmap);
350 
351 	/* check device tree if there is no platform data */
352 	if (pdata == NULL) {
353 		pdata = devm_kzalloc(&client->dev,
354 				     sizeof(struct lm3646_platform_data),
355 				     GFP_KERNEL);
356 		if (pdata == NULL)
357 			return -ENOMEM;
358 		/* use default data in case of no platform data */
359 		pdata->flash_timeout = LM3646_FLASH_TOUT_MAX;
360 		pdata->led1_torch_brt = LM3646_LED1_TORCH_BRT_MAX;
361 		pdata->led1_flash_brt = LM3646_LED1_FLASH_BRT_MAX;
362 	}
363 	flash->pdata = pdata;
364 	flash->dev = &client->dev;
365 
366 	rval = lm3646_subdev_init(flash);
367 	if (rval < 0)
368 		return rval;
369 
370 	rval = lm3646_init_device(flash);
371 	if (rval < 0)
372 		return rval;
373 
374 	i2c_set_clientdata(client, flash);
375 
376 	return 0;
377 }
378 
379 static void lm3646_remove(struct i2c_client *client)
380 {
381 	struct lm3646_flash *flash = i2c_get_clientdata(client);
382 
383 	v4l2_device_unregister_subdev(&flash->subdev_led);
384 	v4l2_ctrl_handler_free(&flash->ctrls_led);
385 	media_entity_cleanup(&flash->subdev_led.entity);
386 }
387 
388 static const struct i2c_device_id lm3646_id_table[] = {
389 	{LM3646_NAME, 0},
390 	{}
391 };
392 
393 MODULE_DEVICE_TABLE(i2c, lm3646_id_table);
394 
395 static struct i2c_driver lm3646_i2c_driver = {
396 	.driver = {
397 		   .name = LM3646_NAME,
398 		   },
399 	.probe_new = lm3646_probe,
400 	.remove = lm3646_remove,
401 	.id_table = lm3646_id_table,
402 };
403 
404 module_i2c_driver(lm3646_i2c_driver);
405 
406 MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
407 MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>");
408 MODULE_DESCRIPTION("Texas Instruments LM3646 Dual Flash LED driver");
409 MODULE_LICENSE("GPL");
410