linux/drivers/media/i2c/lm3646.c
<<
>>
Prefs
   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, &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
 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, &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
 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, &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
 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");
 413