481 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * drivers/media/i2c/lm3560.c4 * General device driver for TI lm3559, lm3560, FLASH LED Driver5 *6 * Copyright (C) 2013 Texas Instruments7 *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 0x1025#define REG_TORCH_BR 0xa026#define REG_FLASH_BR 0xb027#define REG_FLASH_TOUT 0xc028#define REG_FLAG 0xd029#define REG_CONFIG1 0xe030 31/* fault mask */32#define FAULT_TIMEOUT (1<<0)33#define FAULT_OVERTEMP (1<<1)34#define FAULT_SHORT_CIRCUIT (1<<2)35 36enum led_enable {37 MODE_SHDN = 0x0,38 MODE_TORCH = 0x2,39 MODE_FLASH = 0x3,40};41 42/**43 * struct lm3560_flash44 *45 * @dev: pointer to &struct device46 * @pdata: platform data47 * @regmap: reg. map for i2c48 * @lock: muxtex for serial access.49 * @led_mode: V4L2 LED mode50 * @ctrls_led: V4L2 controls51 * @subdev_led: V4L2 subdev52 */53struct 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 */68static 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(flash->regmap,75 REG_ENABLE, 0x03, MODE_SHDN);76 break;77 case V4L2_FLASH_LED_MODE_TORCH:78 rval = regmap_update_bits(flash->regmap,79 REG_ENABLE, 0x03, MODE_TORCH);80 break;81 case V4L2_FLASH_LED_MODE_FLASH:82 rval = regmap_update_bits(flash->regmap,83 REG_ENABLE, 0x03, MODE_FLASH);84 break;85 }86 return rval;87}88 89/* led1/2 enable/disable */90static 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(flash->regmap,98 REG_ENABLE, 0x08, 0x08);99 else100 rval = regmap_update_bits(flash->regmap,101 REG_ENABLE, 0x08, 0x00);102 } else {103 if (on)104 rval = regmap_update_bits(flash->regmap,105 REG_ENABLE, 0x10, 0x10);106 else107 rval = regmap_update_bits(flash->regmap,108 REG_ENABLE, 0x10, 0x00);109 }110 return rval;111}112 113/* torch1/2 brightness control */114static 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, false);122 else123 rval = lm3560_enable_ctrl(flash, led_no, true);124 125 br_bits = LM3560_TORCH_BRT_uA_TO_REG(brt);126 if (led_no == LM3560_LED0)127 rval = regmap_update_bits(flash->regmap,128 REG_TORCH_BR, 0x07, br_bits);129 else130 rval = regmap_update_bits(flash->regmap,131 REG_TORCH_BR, 0x38, br_bits << 3);132 133 return rval;134}135 136/* flash1/2 brightness control */137static 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, false);145 else146 rval = lm3560_enable_ctrl(flash, led_no, true);147 148 br_bits = LM3560_FLASH_BRT_uA_TO_REG(brt);149 if (led_no == LM3560_LED0)150 rval = regmap_update_bits(flash->regmap,151 REG_FLASH_BR, 0x0f, br_bits);152 else153 rval = regmap_update_bits(flash->regmap,154 REG_FLASH_BR, 0xf0, br_bits << 4);155 156 return rval;157}158 159/* v4l2 controls */160static 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(flash->regmap, REG_FLAG, ®_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 182out:183 mutex_unlock(&flash->lock);184 return rval;185}186 187static 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(flash->regmap,204 REG_CONFIG1, 0x04, (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(flash->regmap,230 REG_FLASH_TOUT, 0x1f, tout_bits);231 break;232 233 case V4L2_CID_FLASH_INTENSITY:234 rval = lm3560_flash_brt_ctrl(flash, led_no, ctrl->val);235 break;236 237 case V4L2_CID_FLASH_TORCH_INTENSITY:238 rval = lm3560_torch_brt_ctrl(flash, led_no, ctrl->val);239 break;240 }241 242err_out:243 mutex_unlock(&flash->lock);244 return rval;245}246 247static int lm3560_led1_get_ctrl(struct v4l2_ctrl *ctrl)248{249 return lm3560_get_ctrl(ctrl, LM3560_LED1);250}251 252static int lm3560_led1_set_ctrl(struct v4l2_ctrl *ctrl)253{254 return lm3560_set_ctrl(ctrl, LM3560_LED1);255}256 257static int lm3560_led0_get_ctrl(struct v4l2_ctrl *ctrl)258{259 return lm3560_get_ctrl(ctrl, LM3560_LED0);260}261 262static int lm3560_led0_set_ctrl(struct v4l2_ctrl *ctrl)263{264 return lm3560_set_ctrl(ctrl, LM3560_LED0);265}266 267static 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 278static 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 V4L2_FLASH_LED_MODE_TORCH, ~0x7,292 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 0x1, ~0x3, V4L2_FLASH_STROBE_SOURCE_SOFTWARE);298 299 /* flash strobe */300 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE, 0, 0, 0, 0);301 302 /* flash strobe stop */303 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0);304 305 /* flash strobe timeout */306 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_TIMEOUT,307 LM3560_FLASH_TOUT_MIN,308 flash->pdata->max_flash_timeout,309 LM3560_FLASH_TOUT_STEP,310 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_flash_brt,315 LM3560_FLASH_BRT_STEP, 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_torch_brt,320 LM3560_TORCH_BRT_STEP, max_torch_brt);321 322 /* fault */323 fault = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_FAULT, 0,324 V4L2_FLASH_FAULT_OVER_VOLTAGE325 | V4L2_FLASH_FAULT_OVER_TEMPERATURE326 | V4L2_FLASH_FAULT_SHORT_CIRCUIT327 | V4L2_FLASH_FAULT_TIMEOUT, 0, 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 */339static const struct v4l2_subdev_ops lm3560_ops = {340 .core = NULL,341};342 343static const struct regmap_config lm3560_regmap = {344 .reg_bits = 8,345 .val_bits = 8,346 .max_register = 0xFF,347};348 349static 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(&flash->subdev_led[led_no], client, &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(&flash->subdev_led[led_no].entity, 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 369err_out:370 v4l2_ctrl_handler_free(&flash->ctrls_led[led_no]);371 return rval;372}373 374static 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(flash->regmap,381 REG_FLASH_TOUT, 0x60, 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(flash->regmap, REG_FLAG, ®_val);391 return rval;392}393 394static int lm3560_probe(struct i2c_client *client)395{396 struct lm3560_flash *flash;397 struct lm3560_platform_data *pdata = dev_get_platdata(&client->dev);398 int rval;399 400 flash = devm_kzalloc(&client->dev, 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(flash->regmap)) {406 rval = PTR_ERR(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(&client->dev, 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, LM3560_LED0, "lm3560-led0");429 if (rval < 0)430 return rval;431 432 rval = lm3560_subdev_init(flash, LM3560_LED1, "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, flash);441 442 return 0;443}444 445static 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(&flash->subdev_led[i]);452 v4l2_ctrl_handler_free(&flash->ctrls_led[i]);453 media_entity_cleanup(&flash->subdev_led[i].entity);454 }455}456 457static const struct i2c_device_id lm3560_id_table[] = {458 { LM3559_NAME },459 { LM3560_NAME },460 {}461};462 463MODULE_DEVICE_TABLE(i2c, lm3560_id_table);464 465static 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 475module_i2c_driver(lm3560_i2c_driver);476 477MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");478MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>");479MODULE_DESCRIPTION("Texas Instruments LM3560 LED flash driver");480MODULE_LICENSE("GPL");481