lm3646.c (10772B)
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 49enum 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 */ 66struct 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 */ 81static 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 */ 99static 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, ®_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 133static 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, ®_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, ®_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 198static const struct v4l2_ctrl_ops lm3646_led_ctrl_ops = { 199 .g_volatile_ctrl = lm3646_get_ctrl, 200 .s_ctrl = lm3646_set_ctrl, 201}; 202 203static 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 */ 261static const struct v4l2_subdev_ops lm3646_ops = { 262 .core = NULL, 263}; 264 265static const struct regmap_config lm3646_regmap = { 266 .reg_bits = 8, 267 .val_bits = 8, 268 .max_register = 0xFF, 269}; 270 271static 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 289err_out: 290 v4l2_ctrl_handler_free(&flash->ctrls_led); 291 return rval; 292} 293 294static 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, ®_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, ®_val); 335} 336 337static int lm3646_probe(struct i2c_client *client, 338 const struct i2c_device_id *devid) 339{ 340 struct lm3646_flash *flash; 341 struct lm3646_platform_data *pdata = dev_get_platdata(&client->dev); 342 int rval; 343 344 flash = devm_kzalloc(&client->dev, sizeof(*flash), GFP_KERNEL); 345 if (flash == NULL) 346 return -ENOMEM; 347 348 flash->regmap = devm_regmap_init_i2c(client, &lm3646_regmap); 349 if (IS_ERR(flash->regmap)) 350 return PTR_ERR(flash->regmap); 351 352 /* check device tree if there is no platform data */ 353 if (pdata == NULL) { 354 pdata = devm_kzalloc(&client->dev, 355 sizeof(struct lm3646_platform_data), 356 GFP_KERNEL); 357 if (pdata == NULL) 358 return -ENOMEM; 359 /* use default data in case of no platform data */ 360 pdata->flash_timeout = LM3646_FLASH_TOUT_MAX; 361 pdata->led1_torch_brt = LM3646_LED1_TORCH_BRT_MAX; 362 pdata->led1_flash_brt = LM3646_LED1_FLASH_BRT_MAX; 363 } 364 flash->pdata = pdata; 365 flash->dev = &client->dev; 366 367 rval = lm3646_subdev_init(flash); 368 if (rval < 0) 369 return rval; 370 371 rval = lm3646_init_device(flash); 372 if (rval < 0) 373 return rval; 374 375 i2c_set_clientdata(client, flash); 376 377 return 0; 378} 379 380static int lm3646_remove(struct i2c_client *client) 381{ 382 struct lm3646_flash *flash = i2c_get_clientdata(client); 383 384 v4l2_device_unregister_subdev(&flash->subdev_led); 385 v4l2_ctrl_handler_free(&flash->ctrls_led); 386 media_entity_cleanup(&flash->subdev_led.entity); 387 388 return 0; 389} 390 391static const struct i2c_device_id lm3646_id_table[] = { 392 {LM3646_NAME, 0}, 393 {} 394}; 395 396MODULE_DEVICE_TABLE(i2c, lm3646_id_table); 397 398static struct i2c_driver lm3646_i2c_driver = { 399 .driver = { 400 .name = LM3646_NAME, 401 }, 402 .probe = lm3646_probe, 403 .remove = lm3646_remove, 404 .id_table = lm3646_id_table, 405}; 406 407module_i2c_driver(lm3646_i2c_driver); 408 409MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>"); 410MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>"); 411MODULE_DESCRIPTION("Texas Instruments LM3646 Dual Flash LED driver"); 412MODULE_LICENSE("GPL");