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