linux/drivers/leds/leds-lm355x.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3* Simple driver for Texas Instruments LM355x LED Flash driver chip
   4* Copyright (C) 2012 Texas Instruments
   5*/
   6
   7#include <linux/module.h>
   8#include <linux/delay.h>
   9#include <linux/i2c.h>
  10#include <linux/gpio.h>
  11#include <linux/leds.h>
  12#include <linux/slab.h>
  13#include <linux/platform_device.h>
  14#include <linux/fs.h>
  15#include <linux/regmap.h>
  16#include <linux/platform_data/leds-lm355x.h>
  17
  18enum lm355x_type {
  19        CHIP_LM3554 = 0,
  20        CHIP_LM3556,
  21};
  22
  23enum lm355x_regs {
  24        REG_FLAG = 0,
  25        REG_TORCH_CFG,
  26        REG_TORCH_CTRL,
  27        REG_STROBE_CFG,
  28        REG_FLASH_CTRL,
  29        REG_INDI_CFG,
  30        REG_INDI_CTRL,
  31        REG_OPMODE,
  32        REG_MAX,
  33};
  34
  35/* operation mode */
  36enum lm355x_mode {
  37        MODE_SHDN = 0,
  38        MODE_INDIC,
  39        MODE_TORCH,
  40        MODE_FLASH
  41};
  42
  43/* register map info. */
  44struct lm355x_reg_data {
  45        u8 regno;
  46        u8 mask;
  47        u8 shift;
  48};
  49
  50struct lm355x_chip_data {
  51        struct device *dev;
  52        enum lm355x_type type;
  53
  54        struct led_classdev cdev_flash;
  55        struct led_classdev cdev_torch;
  56        struct led_classdev cdev_indicator;
  57
  58        struct lm355x_platform_data *pdata;
  59        struct regmap *regmap;
  60        struct mutex lock;
  61
  62        unsigned int last_flag;
  63        struct lm355x_reg_data *regs;
  64};
  65
  66/* specific indicator function for lm3556 */
  67enum lm3556_indic_pulse_time {
  68        PULSE_TIME_0_MS = 0,
  69        PULSE_TIME_32_MS,
  70        PULSE_TIME_64_MS,
  71        PULSE_TIME_92_MS,
  72        PULSE_TIME_128_MS,
  73        PULSE_TIME_160_MS,
  74        PULSE_TIME_196_MS,
  75        PULSE_TIME_224_MS,
  76        PULSE_TIME_256_MS,
  77        PULSE_TIME_288_MS,
  78        PULSE_TIME_320_MS,
  79        PULSE_TIME_352_MS,
  80        PULSE_TIME_384_MS,
  81        PULSE_TIME_416_MS,
  82        PULSE_TIME_448_MS,
  83        PULSE_TIME_480_MS,
  84};
  85
  86enum lm3556_indic_n_blank {
  87        INDIC_N_BLANK_0 = 0,
  88        INDIC_N_BLANK_1,
  89        INDIC_N_BLANK_2,
  90        INDIC_N_BLANK_3,
  91        INDIC_N_BLANK_4,
  92        INDIC_N_BLANK_5,
  93        INDIC_N_BLANK_6,
  94        INDIC_N_BLANK_7,
  95        INDIC_N_BLANK_8,
  96        INDIC_N_BLANK_9,
  97        INDIC_N_BLANK_10,
  98        INDIC_N_BLANK_11,
  99        INDIC_N_BLANK_12,
 100        INDIC_N_BLANK_13,
 101        INDIC_N_BLANK_14,
 102        INDIC_N_BLANK_15,
 103};
 104
 105enum lm3556_indic_period {
 106        INDIC_PERIOD_0 = 0,
 107        INDIC_PERIOD_1,
 108        INDIC_PERIOD_2,
 109        INDIC_PERIOD_3,
 110        INDIC_PERIOD_4,
 111        INDIC_PERIOD_5,
 112        INDIC_PERIOD_6,
 113        INDIC_PERIOD_7,
 114};
 115
 116#define INDIC_PATTERN_SIZE 4
 117
 118struct indicator {
 119        u8 blinking;
 120        u8 period_cnt;
 121};
 122
 123/* indicator pattern data only for lm3556 */
 124static struct indicator indicator_pattern[INDIC_PATTERN_SIZE] = {
 125        [0] = {(INDIC_N_BLANK_1 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_1},
 126        [1] = {(INDIC_N_BLANK_15 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_2},
 127        [2] = {(INDIC_N_BLANK_10 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_4},
 128        [3] = {(INDIC_N_BLANK_5 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_7},
 129};
 130
 131static struct lm355x_reg_data lm3554_regs[REG_MAX] = {
 132        [REG_FLAG] = {0xD0, 0xBF, 0},
 133        [REG_TORCH_CFG] = {0xE0, 0x80, 7},
 134        [REG_TORCH_CTRL] = {0xA0, 0x38, 3},
 135        [REG_STROBE_CFG] = {0xE0, 0x04, 2},
 136        [REG_FLASH_CTRL] = {0xB0, 0x78, 3},
 137        [REG_INDI_CFG] = {0xE0, 0x08, 3},
 138        [REG_INDI_CTRL] = {0xA0, 0xC0, 6},
 139        [REG_OPMODE] = {0xA0, 0x03, 0},
 140};
 141
 142static struct lm355x_reg_data lm3556_regs[REG_MAX] = {
 143        [REG_FLAG] = {0x0B, 0xFF, 0},
 144        [REG_TORCH_CFG] = {0x0A, 0x10, 4},
 145        [REG_TORCH_CTRL] = {0x09, 0x70, 4},
 146        [REG_STROBE_CFG] = {0x0A, 0x20, 5},
 147        [REG_FLASH_CTRL] = {0x09, 0x0F, 0},
 148        [REG_INDI_CFG] = {0xFF, 0xFF, 0},
 149        [REG_INDI_CTRL] = {0x09, 0x70, 4},
 150        [REG_OPMODE] = {0x0A, 0x03, 0},
 151};
 152
 153static char lm355x_name[][I2C_NAME_SIZE] = {
 154        [CHIP_LM3554] = LM3554_NAME,
 155        [CHIP_LM3556] = LM3556_NAME,
 156};
 157
 158/* chip initialize */
 159static int lm355x_chip_init(struct lm355x_chip_data *chip)
 160{
 161        int ret;
 162        unsigned int reg_val;
 163        struct lm355x_platform_data *pdata = chip->pdata;
 164
 165        /* input and output pins configuration */
 166        switch (chip->type) {
 167        case CHIP_LM3554:
 168                reg_val = pdata->pin_tx2 | pdata->ntc_pin;
 169                ret = regmap_update_bits(chip->regmap, 0xE0, 0x28, reg_val);
 170                if (ret < 0)
 171                        goto out;
 172                reg_val = pdata->pass_mode;
 173                ret = regmap_update_bits(chip->regmap, 0xA0, 0x04, reg_val);
 174                if (ret < 0)
 175                        goto out;
 176                break;
 177
 178        case CHIP_LM3556:
 179                reg_val = pdata->pin_tx2 | pdata->ntc_pin | pdata->pass_mode;
 180                ret = regmap_update_bits(chip->regmap, 0x0A, 0xC4, reg_val);
 181                if (ret < 0)
 182                        goto out;
 183                break;
 184        default:
 185                return -ENODATA;
 186        }
 187
 188        return ret;
 189out:
 190        dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
 191        return ret;
 192}
 193
 194/* chip control */
 195static int lm355x_control(struct lm355x_chip_data *chip,
 196                           u8 brightness, enum lm355x_mode opmode)
 197{
 198        int ret;
 199        unsigned int reg_val;
 200        struct lm355x_platform_data *pdata = chip->pdata;
 201        struct lm355x_reg_data *preg = chip->regs;
 202
 203        ret = regmap_read(chip->regmap, preg[REG_FLAG].regno, &chip->last_flag);
 204        if (ret < 0)
 205                goto out;
 206        if (chip->last_flag & preg[REG_FLAG].mask)
 207                dev_info(chip->dev, "%s Last FLAG is 0x%x\n",
 208                         lm355x_name[chip->type],
 209                         chip->last_flag & preg[REG_FLAG].mask);
 210        /* brightness 0 means shutdown */
 211        if (!brightness)
 212                opmode = MODE_SHDN;
 213
 214        switch (opmode) {
 215        case MODE_TORCH:
 216                ret =
 217                    regmap_update_bits(chip->regmap, preg[REG_TORCH_CTRL].regno,
 218                                       preg[REG_TORCH_CTRL].mask,
 219                                       (brightness - 1)
 220                                       << preg[REG_TORCH_CTRL].shift);
 221                if (ret < 0)
 222                        goto out;
 223
 224                if (pdata->pin_tx1 != LM355x_PIN_TORCH_DISABLE) {
 225                        ret =
 226                            regmap_update_bits(chip->regmap,
 227                                               preg[REG_TORCH_CFG].regno,
 228                                               preg[REG_TORCH_CFG].mask,
 229                                               0x01 <<
 230                                               preg[REG_TORCH_CFG].shift);
 231                        if (ret < 0)
 232                                goto out;
 233                        opmode = MODE_SHDN;
 234                        dev_info(chip->dev,
 235                                 "torch brt is set - ext. torch pin mode\n");
 236                }
 237                break;
 238
 239        case MODE_FLASH:
 240
 241                ret =
 242                    regmap_update_bits(chip->regmap, preg[REG_FLASH_CTRL].regno,
 243                                       preg[REG_FLASH_CTRL].mask,
 244                                       (brightness - 1)
 245                                       << preg[REG_FLASH_CTRL].shift);
 246                if (ret < 0)
 247                        goto out;
 248
 249                if (pdata->pin_strobe != LM355x_PIN_STROBE_DISABLE) {
 250                        if (chip->type == CHIP_LM3554)
 251                                reg_val = 0x00;
 252                        else
 253                                reg_val = 0x01;
 254                        ret =
 255                            regmap_update_bits(chip->regmap,
 256                                               preg[REG_STROBE_CFG].regno,
 257                                               preg[REG_STROBE_CFG].mask,
 258                                               reg_val <<
 259                                               preg[REG_STROBE_CFG].shift);
 260                        if (ret < 0)
 261                                goto out;
 262                        opmode = MODE_SHDN;
 263                        dev_info(chip->dev,
 264                                 "flash brt is set - ext. strobe pin mode\n");
 265                }
 266                break;
 267
 268        case MODE_INDIC:
 269                ret =
 270                    regmap_update_bits(chip->regmap, preg[REG_INDI_CTRL].regno,
 271                                       preg[REG_INDI_CTRL].mask,
 272                                       (brightness - 1)
 273                                       << preg[REG_INDI_CTRL].shift);
 274                if (ret < 0)
 275                        goto out;
 276
 277                if (pdata->pin_tx2 != LM355x_PIN_TX_DISABLE) {
 278                        ret =
 279                            regmap_update_bits(chip->regmap,
 280                                               preg[REG_INDI_CFG].regno,
 281                                               preg[REG_INDI_CFG].mask,
 282                                               0x01 <<
 283                                               preg[REG_INDI_CFG].shift);
 284                        if (ret < 0)
 285                                goto out;
 286                        opmode = MODE_SHDN;
 287                }
 288                break;
 289        case MODE_SHDN:
 290                break;
 291        default:
 292                return -EINVAL;
 293        }
 294        /* operation mode control */
 295        ret = regmap_update_bits(chip->regmap, preg[REG_OPMODE].regno,
 296                                 preg[REG_OPMODE].mask,
 297                                 opmode << preg[REG_OPMODE].shift);
 298        if (ret < 0)
 299                goto out;
 300        return ret;
 301out:
 302        dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
 303        return ret;
 304}
 305
 306/* torch */
 307
 308static int lm355x_torch_brightness_set(struct led_classdev *cdev,
 309                                        enum led_brightness brightness)
 310{
 311        struct lm355x_chip_data *chip =
 312            container_of(cdev, struct lm355x_chip_data, cdev_torch);
 313        int ret;
 314
 315        mutex_lock(&chip->lock);
 316        ret = lm355x_control(chip, brightness, MODE_TORCH);
 317        mutex_unlock(&chip->lock);
 318        return ret;
 319}
 320
 321/* flash */
 322
 323static int lm355x_strobe_brightness_set(struct led_classdev *cdev,
 324                                         enum led_brightness brightness)
 325{
 326        struct lm355x_chip_data *chip =
 327            container_of(cdev, struct lm355x_chip_data, cdev_flash);
 328        int ret;
 329
 330        mutex_lock(&chip->lock);
 331        ret = lm355x_control(chip, brightness, MODE_FLASH);
 332        mutex_unlock(&chip->lock);
 333        return ret;
 334}
 335
 336/* indicator */
 337
 338static int lm355x_indicator_brightness_set(struct led_classdev *cdev,
 339                                            enum led_brightness brightness)
 340{
 341        struct lm355x_chip_data *chip =
 342            container_of(cdev, struct lm355x_chip_data, cdev_indicator);
 343        int ret;
 344
 345        mutex_lock(&chip->lock);
 346        ret = lm355x_control(chip, brightness, MODE_INDIC);
 347        mutex_unlock(&chip->lock);
 348        return ret;
 349}
 350
 351/* indicator pattern only for lm3556*/
 352static ssize_t lm3556_indicator_pattern_store(struct device *dev,
 353                                              struct device_attribute *attr,
 354                                              const char *buf, size_t size)
 355{
 356        ssize_t ret;
 357        struct led_classdev *led_cdev = dev_get_drvdata(dev);
 358        struct lm355x_chip_data *chip =
 359            container_of(led_cdev, struct lm355x_chip_data, cdev_indicator);
 360        unsigned int state;
 361
 362        ret = kstrtouint(buf, 10, &state);
 363        if (ret)
 364                goto out;
 365        if (state > INDIC_PATTERN_SIZE - 1)
 366                state = INDIC_PATTERN_SIZE - 1;
 367
 368        ret = regmap_write(chip->regmap, 0x04,
 369                           indicator_pattern[state].blinking);
 370        if (ret < 0)
 371                goto out;
 372
 373        ret = regmap_write(chip->regmap, 0x05,
 374                           indicator_pattern[state].period_cnt);
 375        if (ret < 0)
 376                goto out;
 377
 378        return size;
 379out:
 380        dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
 381        return ret;
 382}
 383
 384static DEVICE_ATTR(pattern, S_IWUSR, NULL, lm3556_indicator_pattern_store);
 385
 386static struct attribute *lm355x_indicator_attrs[] = {
 387        &dev_attr_pattern.attr,
 388        NULL
 389};
 390ATTRIBUTE_GROUPS(lm355x_indicator);
 391
 392static const struct regmap_config lm355x_regmap = {
 393        .reg_bits = 8,
 394        .val_bits = 8,
 395        .max_register = 0xFF,
 396};
 397
 398/* module initialize */
 399static int lm355x_probe(struct i2c_client *client,
 400                                  const struct i2c_device_id *id)
 401{
 402        struct lm355x_platform_data *pdata = dev_get_platdata(&client->dev);
 403        struct lm355x_chip_data *chip;
 404
 405        int err;
 406
 407        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 408                dev_err(&client->dev, "i2c functionality check fail.\n");
 409                return -EOPNOTSUPP;
 410        }
 411
 412        if (pdata == NULL) {
 413                dev_err(&client->dev, "needs Platform Data.\n");
 414                return -ENODATA;
 415        }
 416
 417        chip = devm_kzalloc(&client->dev,
 418                            sizeof(struct lm355x_chip_data), GFP_KERNEL);
 419        if (!chip)
 420                return -ENOMEM;
 421
 422        chip->dev = &client->dev;
 423        chip->type = id->driver_data;
 424        switch (id->driver_data) {
 425        case CHIP_LM3554:
 426                chip->regs = lm3554_regs;
 427                break;
 428        case CHIP_LM3556:
 429                chip->regs = lm3556_regs;
 430                break;
 431        default:
 432                return -ENOSYS;
 433        }
 434        chip->pdata = pdata;
 435
 436        chip->regmap = devm_regmap_init_i2c(client, &lm355x_regmap);
 437        if (IS_ERR(chip->regmap)) {
 438                err = PTR_ERR(chip->regmap);
 439                dev_err(&client->dev,
 440                        "Failed to allocate register map: %d\n", err);
 441                return err;
 442        }
 443
 444        mutex_init(&chip->lock);
 445        i2c_set_clientdata(client, chip);
 446
 447        err = lm355x_chip_init(chip);
 448        if (err < 0)
 449                goto err_out;
 450
 451        /* flash */
 452        chip->cdev_flash.name = "flash";
 453        chip->cdev_flash.max_brightness = 16;
 454        chip->cdev_flash.brightness_set_blocking = lm355x_strobe_brightness_set;
 455        chip->cdev_flash.default_trigger = "flash";
 456        err = led_classdev_register((struct device *)
 457                                    &client->dev, &chip->cdev_flash);
 458        if (err < 0)
 459                goto err_out;
 460        /* torch */
 461        chip->cdev_torch.name = "torch";
 462        chip->cdev_torch.max_brightness = 8;
 463        chip->cdev_torch.brightness_set_blocking = lm355x_torch_brightness_set;
 464        chip->cdev_torch.default_trigger = "torch";
 465        err = led_classdev_register((struct device *)
 466                                    &client->dev, &chip->cdev_torch);
 467        if (err < 0)
 468                goto err_create_torch_file;
 469        /* indicator */
 470        chip->cdev_indicator.name = "indicator";
 471        if (id->driver_data == CHIP_LM3554)
 472                chip->cdev_indicator.max_brightness = 4;
 473        else
 474                chip->cdev_indicator.max_brightness = 8;
 475        chip->cdev_indicator.brightness_set_blocking =
 476                                        lm355x_indicator_brightness_set;
 477        /* indicator pattern control only for LM3556 */
 478        if (id->driver_data == CHIP_LM3556)
 479                chip->cdev_indicator.groups = lm355x_indicator_groups;
 480        err = led_classdev_register((struct device *)
 481                                    &client->dev, &chip->cdev_indicator);
 482        if (err < 0)
 483                goto err_create_indicator_file;
 484
 485        dev_info(&client->dev, "%s is initialized\n",
 486                 lm355x_name[id->driver_data]);
 487        return 0;
 488
 489err_create_indicator_file:
 490        led_classdev_unregister(&chip->cdev_torch);
 491err_create_torch_file:
 492        led_classdev_unregister(&chip->cdev_flash);
 493err_out:
 494        return err;
 495}
 496
 497static int lm355x_remove(struct i2c_client *client)
 498{
 499        struct lm355x_chip_data *chip = i2c_get_clientdata(client);
 500        struct lm355x_reg_data *preg = chip->regs;
 501
 502        regmap_write(chip->regmap, preg[REG_OPMODE].regno, 0);
 503        led_classdev_unregister(&chip->cdev_indicator);
 504        led_classdev_unregister(&chip->cdev_torch);
 505        led_classdev_unregister(&chip->cdev_flash);
 506        dev_info(&client->dev, "%s is removed\n", lm355x_name[chip->type]);
 507
 508        return 0;
 509}
 510
 511static const struct i2c_device_id lm355x_id[] = {
 512        {LM3554_NAME, CHIP_LM3554},
 513        {LM3556_NAME, CHIP_LM3556},
 514        {}
 515};
 516
 517MODULE_DEVICE_TABLE(i2c, lm355x_id);
 518
 519static struct i2c_driver lm355x_i2c_driver = {
 520        .driver = {
 521                   .name = LM355x_NAME,
 522                   .pm = NULL,
 523                   },
 524        .probe = lm355x_probe,
 525        .remove = lm355x_remove,
 526        .id_table = lm355x_id,
 527};
 528
 529module_i2c_driver(lm355x_i2c_driver);
 530
 531MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM355x");
 532MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
 533MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
 534MODULE_LICENSE("GPL v2");
 535