Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003 * Simple driver for Texas Instruments LM355x LED Flash driver chip
0004 * Copyright (C) 2012 Texas Instruments
0005 */
0006 
0007 #include <linux/module.h>
0008 #include <linux/delay.h>
0009 #include <linux/i2c.h>
0010 #include <linux/leds.h>
0011 #include <linux/slab.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/fs.h>
0014 #include <linux/regmap.h>
0015 #include <linux/platform_data/leds-lm355x.h>
0016 
0017 enum lm355x_type {
0018     CHIP_LM3554 = 0,
0019     CHIP_LM3556,
0020 };
0021 
0022 enum lm355x_regs {
0023     REG_FLAG = 0,
0024     REG_TORCH_CFG,
0025     REG_TORCH_CTRL,
0026     REG_STROBE_CFG,
0027     REG_FLASH_CTRL,
0028     REG_INDI_CFG,
0029     REG_INDI_CTRL,
0030     REG_OPMODE,
0031     REG_MAX,
0032 };
0033 
0034 /* operation mode */
0035 enum lm355x_mode {
0036     MODE_SHDN = 0,
0037     MODE_INDIC,
0038     MODE_TORCH,
0039     MODE_FLASH
0040 };
0041 
0042 /* register map info. */
0043 struct lm355x_reg_data {
0044     u8 regno;
0045     u8 mask;
0046     u8 shift;
0047 };
0048 
0049 struct lm355x_chip_data {
0050     struct device *dev;
0051     enum lm355x_type type;
0052 
0053     struct led_classdev cdev_flash;
0054     struct led_classdev cdev_torch;
0055     struct led_classdev cdev_indicator;
0056 
0057     struct lm355x_platform_data *pdata;
0058     struct regmap *regmap;
0059     struct mutex lock;
0060 
0061     unsigned int last_flag;
0062     struct lm355x_reg_data *regs;
0063 };
0064 
0065 /* specific indicator function for lm3556 */
0066 enum lm3556_indic_pulse_time {
0067     PULSE_TIME_0_MS = 0,
0068     PULSE_TIME_32_MS,
0069     PULSE_TIME_64_MS,
0070     PULSE_TIME_92_MS,
0071     PULSE_TIME_128_MS,
0072     PULSE_TIME_160_MS,
0073     PULSE_TIME_196_MS,
0074     PULSE_TIME_224_MS,
0075     PULSE_TIME_256_MS,
0076     PULSE_TIME_288_MS,
0077     PULSE_TIME_320_MS,
0078     PULSE_TIME_352_MS,
0079     PULSE_TIME_384_MS,
0080     PULSE_TIME_416_MS,
0081     PULSE_TIME_448_MS,
0082     PULSE_TIME_480_MS,
0083 };
0084 
0085 enum lm3556_indic_n_blank {
0086     INDIC_N_BLANK_0 = 0,
0087     INDIC_N_BLANK_1,
0088     INDIC_N_BLANK_2,
0089     INDIC_N_BLANK_3,
0090     INDIC_N_BLANK_4,
0091     INDIC_N_BLANK_5,
0092     INDIC_N_BLANK_6,
0093     INDIC_N_BLANK_7,
0094     INDIC_N_BLANK_8,
0095     INDIC_N_BLANK_9,
0096     INDIC_N_BLANK_10,
0097     INDIC_N_BLANK_11,
0098     INDIC_N_BLANK_12,
0099     INDIC_N_BLANK_13,
0100     INDIC_N_BLANK_14,
0101     INDIC_N_BLANK_15,
0102 };
0103 
0104 enum lm3556_indic_period {
0105     INDIC_PERIOD_0 = 0,
0106     INDIC_PERIOD_1,
0107     INDIC_PERIOD_2,
0108     INDIC_PERIOD_3,
0109     INDIC_PERIOD_4,
0110     INDIC_PERIOD_5,
0111     INDIC_PERIOD_6,
0112     INDIC_PERIOD_7,
0113 };
0114 
0115 #define INDIC_PATTERN_SIZE 4
0116 
0117 struct indicator {
0118     u8 blinking;
0119     u8 period_cnt;
0120 };
0121 
0122 /* indicator pattern data only for lm3556 */
0123 static struct indicator indicator_pattern[INDIC_PATTERN_SIZE] = {
0124     [0] = {(INDIC_N_BLANK_1 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_1},
0125     [1] = {(INDIC_N_BLANK_15 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_2},
0126     [2] = {(INDIC_N_BLANK_10 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_4},
0127     [3] = {(INDIC_N_BLANK_5 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_7},
0128 };
0129 
0130 static struct lm355x_reg_data lm3554_regs[REG_MAX] = {
0131     [REG_FLAG] = {0xD0, 0xBF, 0},
0132     [REG_TORCH_CFG] = {0xE0, 0x80, 7},
0133     [REG_TORCH_CTRL] = {0xA0, 0x38, 3},
0134     [REG_STROBE_CFG] = {0xE0, 0x04, 2},
0135     [REG_FLASH_CTRL] = {0xB0, 0x78, 3},
0136     [REG_INDI_CFG] = {0xE0, 0x08, 3},
0137     [REG_INDI_CTRL] = {0xA0, 0xC0, 6},
0138     [REG_OPMODE] = {0xA0, 0x03, 0},
0139 };
0140 
0141 static struct lm355x_reg_data lm3556_regs[REG_MAX] = {
0142     [REG_FLAG] = {0x0B, 0xFF, 0},
0143     [REG_TORCH_CFG] = {0x0A, 0x10, 4},
0144     [REG_TORCH_CTRL] = {0x09, 0x70, 4},
0145     [REG_STROBE_CFG] = {0x0A, 0x20, 5},
0146     [REG_FLASH_CTRL] = {0x09, 0x0F, 0},
0147     [REG_INDI_CFG] = {0xFF, 0xFF, 0},
0148     [REG_INDI_CTRL] = {0x09, 0x70, 4},
0149     [REG_OPMODE] = {0x0A, 0x03, 0},
0150 };
0151 
0152 static char lm355x_name[][I2C_NAME_SIZE] = {
0153     [CHIP_LM3554] = LM3554_NAME,
0154     [CHIP_LM3556] = LM3556_NAME,
0155 };
0156 
0157 /* chip initialize */
0158 static int lm355x_chip_init(struct lm355x_chip_data *chip)
0159 {
0160     int ret;
0161     unsigned int reg_val;
0162     struct lm355x_platform_data *pdata = chip->pdata;
0163 
0164     /* input and output pins configuration */
0165     switch (chip->type) {
0166     case CHIP_LM3554:
0167         reg_val = (u32)pdata->pin_tx2 | (u32)pdata->ntc_pin;
0168         ret = regmap_update_bits(chip->regmap, 0xE0, 0x28, reg_val);
0169         if (ret < 0)
0170             goto out;
0171         reg_val = (u32)pdata->pass_mode;
0172         ret = regmap_update_bits(chip->regmap, 0xA0, 0x04, reg_val);
0173         if (ret < 0)
0174             goto out;
0175         break;
0176 
0177     case CHIP_LM3556:
0178         reg_val = (u32)pdata->pin_tx2 | (u32)pdata->ntc_pin |
0179                   (u32)pdata->pass_mode;
0180         ret = regmap_update_bits(chip->regmap, 0x0A, 0xC4, reg_val);
0181         if (ret < 0)
0182             goto out;
0183         break;
0184     default:
0185         return -ENODATA;
0186     }
0187 
0188     return ret;
0189 out:
0190     dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
0191     return ret;
0192 }
0193 
0194 /* chip control */
0195 static int lm355x_control(struct lm355x_chip_data *chip,
0196                u8 brightness, enum lm355x_mode opmode)
0197 {
0198     int ret;
0199     unsigned int reg_val;
0200     struct lm355x_platform_data *pdata = chip->pdata;
0201     struct lm355x_reg_data *preg = chip->regs;
0202 
0203     ret = regmap_read(chip->regmap, preg[REG_FLAG].regno, &chip->last_flag);
0204     if (ret < 0)
0205         goto out;
0206     if (chip->last_flag & preg[REG_FLAG].mask)
0207         dev_info(chip->dev, "%s Last FLAG is 0x%x\n",
0208              lm355x_name[chip->type],
0209              chip->last_flag & preg[REG_FLAG].mask);
0210     /* brightness 0 means shutdown */
0211     if (!brightness)
0212         opmode = MODE_SHDN;
0213 
0214     switch (opmode) {
0215     case MODE_TORCH:
0216         ret =
0217             regmap_update_bits(chip->regmap, preg[REG_TORCH_CTRL].regno,
0218                        preg[REG_TORCH_CTRL].mask,
0219                        (brightness - 1)
0220                        << preg[REG_TORCH_CTRL].shift);
0221         if (ret < 0)
0222             goto out;
0223 
0224         if (pdata->pin_tx1 != LM355x_PIN_TORCH_DISABLE) {
0225             ret =
0226                 regmap_update_bits(chip->regmap,
0227                            preg[REG_TORCH_CFG].regno,
0228                            preg[REG_TORCH_CFG].mask,
0229                            0x01 <<
0230                            preg[REG_TORCH_CFG].shift);
0231             if (ret < 0)
0232                 goto out;
0233             opmode = MODE_SHDN;
0234             dev_info(chip->dev,
0235                  "torch brt is set - ext. torch pin mode\n");
0236         }
0237         break;
0238 
0239     case MODE_FLASH:
0240 
0241         ret =
0242             regmap_update_bits(chip->regmap, preg[REG_FLASH_CTRL].regno,
0243                        preg[REG_FLASH_CTRL].mask,
0244                        (brightness - 1)
0245                        << preg[REG_FLASH_CTRL].shift);
0246         if (ret < 0)
0247             goto out;
0248 
0249         if (pdata->pin_strobe != LM355x_PIN_STROBE_DISABLE) {
0250             if (chip->type == CHIP_LM3554)
0251                 reg_val = 0x00;
0252             else
0253                 reg_val = 0x01;
0254             ret =
0255                 regmap_update_bits(chip->regmap,
0256                            preg[REG_STROBE_CFG].regno,
0257                            preg[REG_STROBE_CFG].mask,
0258                            reg_val <<
0259                            preg[REG_STROBE_CFG].shift);
0260             if (ret < 0)
0261                 goto out;
0262             opmode = MODE_SHDN;
0263             dev_info(chip->dev,
0264                  "flash brt is set - ext. strobe pin mode\n");
0265         }
0266         break;
0267 
0268     case MODE_INDIC:
0269         ret =
0270             regmap_update_bits(chip->regmap, preg[REG_INDI_CTRL].regno,
0271                        preg[REG_INDI_CTRL].mask,
0272                        (brightness - 1)
0273                        << preg[REG_INDI_CTRL].shift);
0274         if (ret < 0)
0275             goto out;
0276 
0277         if (pdata->pin_tx2 != LM355x_PIN_TX_DISABLE) {
0278             ret =
0279                 regmap_update_bits(chip->regmap,
0280                            preg[REG_INDI_CFG].regno,
0281                            preg[REG_INDI_CFG].mask,
0282                            0x01 <<
0283                            preg[REG_INDI_CFG].shift);
0284             if (ret < 0)
0285                 goto out;
0286             opmode = MODE_SHDN;
0287         }
0288         break;
0289     case MODE_SHDN:
0290         break;
0291     default:
0292         return -EINVAL;
0293     }
0294     /* operation mode control */
0295     ret = regmap_update_bits(chip->regmap, preg[REG_OPMODE].regno,
0296                  preg[REG_OPMODE].mask,
0297                  opmode << preg[REG_OPMODE].shift);
0298     if (ret < 0)
0299         goto out;
0300     return ret;
0301 out:
0302     dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
0303     return ret;
0304 }
0305 
0306 /* torch */
0307 
0308 static int lm355x_torch_brightness_set(struct led_classdev *cdev,
0309                     enum led_brightness brightness)
0310 {
0311     struct lm355x_chip_data *chip =
0312         container_of(cdev, struct lm355x_chip_data, cdev_torch);
0313     int ret;
0314 
0315     mutex_lock(&chip->lock);
0316     ret = lm355x_control(chip, brightness, MODE_TORCH);
0317     mutex_unlock(&chip->lock);
0318     return ret;
0319 }
0320 
0321 /* flash */
0322 
0323 static int lm355x_strobe_brightness_set(struct led_classdev *cdev,
0324                      enum led_brightness brightness)
0325 {
0326     struct lm355x_chip_data *chip =
0327         container_of(cdev, struct lm355x_chip_data, cdev_flash);
0328     int ret;
0329 
0330     mutex_lock(&chip->lock);
0331     ret = lm355x_control(chip, brightness, MODE_FLASH);
0332     mutex_unlock(&chip->lock);
0333     return ret;
0334 }
0335 
0336 /* indicator */
0337 
0338 static int lm355x_indicator_brightness_set(struct led_classdev *cdev,
0339                         enum led_brightness brightness)
0340 {
0341     struct lm355x_chip_data *chip =
0342         container_of(cdev, struct lm355x_chip_data, cdev_indicator);
0343     int ret;
0344 
0345     mutex_lock(&chip->lock);
0346     ret = lm355x_control(chip, brightness, MODE_INDIC);
0347     mutex_unlock(&chip->lock);
0348     return ret;
0349 }
0350 
0351 /* indicator pattern only for lm3556*/
0352 static ssize_t pattern_store(struct device *dev,
0353                  struct device_attribute *attr,
0354                  const char *buf, size_t size)
0355 {
0356     ssize_t ret;
0357     struct led_classdev *led_cdev = dev_get_drvdata(dev);
0358     struct lm355x_chip_data *chip =
0359         container_of(led_cdev, struct lm355x_chip_data, cdev_indicator);
0360     unsigned int state;
0361 
0362     ret = kstrtouint(buf, 10, &state);
0363     if (ret)
0364         goto out;
0365     if (state > INDIC_PATTERN_SIZE - 1)
0366         state = INDIC_PATTERN_SIZE - 1;
0367 
0368     ret = regmap_write(chip->regmap, 0x04,
0369                indicator_pattern[state].blinking);
0370     if (ret < 0)
0371         goto out;
0372 
0373     ret = regmap_write(chip->regmap, 0x05,
0374                indicator_pattern[state].period_cnt);
0375     if (ret < 0)
0376         goto out;
0377 
0378     return size;
0379 out:
0380     dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
0381     return ret;
0382 }
0383 
0384 static DEVICE_ATTR_WO(pattern);
0385 
0386 static struct attribute *lm355x_indicator_attrs[] = {
0387     &dev_attr_pattern.attr,
0388     NULL
0389 };
0390 ATTRIBUTE_GROUPS(lm355x_indicator);
0391 
0392 static const struct regmap_config lm355x_regmap = {
0393     .reg_bits = 8,
0394     .val_bits = 8,
0395     .max_register = 0xFF,
0396 };
0397 
0398 /* module initialize */
0399 static int lm355x_probe(struct i2c_client *client,
0400                   const struct i2c_device_id *id)
0401 {
0402     struct lm355x_platform_data *pdata = dev_get_platdata(&client->dev);
0403     struct lm355x_chip_data *chip;
0404 
0405     int err;
0406 
0407     if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
0408         dev_err(&client->dev, "i2c functionality check fail.\n");
0409         return -EOPNOTSUPP;
0410     }
0411 
0412     if (pdata == NULL) {
0413         dev_err(&client->dev, "needs Platform Data.\n");
0414         return -ENODATA;
0415     }
0416 
0417     chip = devm_kzalloc(&client->dev,
0418                 sizeof(struct lm355x_chip_data), GFP_KERNEL);
0419     if (!chip)
0420         return -ENOMEM;
0421 
0422     chip->dev = &client->dev;
0423     chip->type = id->driver_data;
0424     switch (id->driver_data) {
0425     case CHIP_LM3554:
0426         chip->regs = lm3554_regs;
0427         break;
0428     case CHIP_LM3556:
0429         chip->regs = lm3556_regs;
0430         break;
0431     default:
0432         return -ENOSYS;
0433     }
0434     chip->pdata = pdata;
0435 
0436     chip->regmap = devm_regmap_init_i2c(client, &lm355x_regmap);
0437     if (IS_ERR(chip->regmap)) {
0438         err = PTR_ERR(chip->regmap);
0439         dev_err(&client->dev,
0440             "Failed to allocate register map: %d\n", err);
0441         return err;
0442     }
0443 
0444     mutex_init(&chip->lock);
0445     i2c_set_clientdata(client, chip);
0446 
0447     err = lm355x_chip_init(chip);
0448     if (err < 0)
0449         goto err_out;
0450 
0451     /* flash */
0452     chip->cdev_flash.name = "flash";
0453     chip->cdev_flash.max_brightness = 16;
0454     chip->cdev_flash.brightness_set_blocking = lm355x_strobe_brightness_set;
0455     chip->cdev_flash.default_trigger = "flash";
0456     err = led_classdev_register(&client->dev, &chip->cdev_flash);
0457     if (err < 0)
0458         goto err_out;
0459     /* torch */
0460     chip->cdev_torch.name = "torch";
0461     chip->cdev_torch.max_brightness = 8;
0462     chip->cdev_torch.brightness_set_blocking = lm355x_torch_brightness_set;
0463     chip->cdev_torch.default_trigger = "torch";
0464     err = led_classdev_register(&client->dev, &chip->cdev_torch);
0465     if (err < 0)
0466         goto err_create_torch_file;
0467     /* indicator */
0468     chip->cdev_indicator.name = "indicator";
0469     if (id->driver_data == CHIP_LM3554)
0470         chip->cdev_indicator.max_brightness = 4;
0471     else
0472         chip->cdev_indicator.max_brightness = 8;
0473     chip->cdev_indicator.brightness_set_blocking =
0474                     lm355x_indicator_brightness_set;
0475     /* indicator pattern control only for LM3556 */
0476     if (id->driver_data == CHIP_LM3556)
0477         chip->cdev_indicator.groups = lm355x_indicator_groups;
0478     err = led_classdev_register(&client->dev, &chip->cdev_indicator);
0479     if (err < 0)
0480         goto err_create_indicator_file;
0481 
0482     dev_info(&client->dev, "%s is initialized\n",
0483          lm355x_name[id->driver_data]);
0484     return 0;
0485 
0486 err_create_indicator_file:
0487     led_classdev_unregister(&chip->cdev_torch);
0488 err_create_torch_file:
0489     led_classdev_unregister(&chip->cdev_flash);
0490 err_out:
0491     return err;
0492 }
0493 
0494 static int lm355x_remove(struct i2c_client *client)
0495 {
0496     struct lm355x_chip_data *chip = i2c_get_clientdata(client);
0497     struct lm355x_reg_data *preg = chip->regs;
0498 
0499     regmap_write(chip->regmap, preg[REG_OPMODE].regno, 0);
0500     led_classdev_unregister(&chip->cdev_indicator);
0501     led_classdev_unregister(&chip->cdev_torch);
0502     led_classdev_unregister(&chip->cdev_flash);
0503     dev_info(&client->dev, "%s is removed\n", lm355x_name[chip->type]);
0504 
0505     return 0;
0506 }
0507 
0508 static const struct i2c_device_id lm355x_id[] = {
0509     {LM3554_NAME, CHIP_LM3554},
0510     {LM3556_NAME, CHIP_LM3556},
0511     {}
0512 };
0513 
0514 MODULE_DEVICE_TABLE(i2c, lm355x_id);
0515 
0516 static struct i2c_driver lm355x_i2c_driver = {
0517     .driver = {
0518            .name = LM355x_NAME,
0519            .pm = NULL,
0520            },
0521     .probe = lm355x_probe,
0522     .remove = lm355x_remove,
0523     .id_table = lm355x_id,
0524 };
0525 
0526 module_i2c_driver(lm355x_i2c_driver);
0527 
0528 MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM355x");
0529 MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
0530 MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
0531 MODULE_LICENSE("GPL v2");