leds-lm355x.c (12715B)
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/leds.h> 11#include <linux/slab.h> 12#include <linux/platform_device.h> 13#include <linux/fs.h> 14#include <linux/regmap.h> 15#include <linux/platform_data/leds-lm355x.h> 16 17enum lm355x_type { 18 CHIP_LM3554 = 0, 19 CHIP_LM3556, 20}; 21 22enum lm355x_regs { 23 REG_FLAG = 0, 24 REG_TORCH_CFG, 25 REG_TORCH_CTRL, 26 REG_STROBE_CFG, 27 REG_FLASH_CTRL, 28 REG_INDI_CFG, 29 REG_INDI_CTRL, 30 REG_OPMODE, 31 REG_MAX, 32}; 33 34/* operation mode */ 35enum lm355x_mode { 36 MODE_SHDN = 0, 37 MODE_INDIC, 38 MODE_TORCH, 39 MODE_FLASH 40}; 41 42/* register map info. */ 43struct lm355x_reg_data { 44 u8 regno; 45 u8 mask; 46 u8 shift; 47}; 48 49struct lm355x_chip_data { 50 struct device *dev; 51 enum lm355x_type type; 52 53 struct led_classdev cdev_flash; 54 struct led_classdev cdev_torch; 55 struct led_classdev cdev_indicator; 56 57 struct lm355x_platform_data *pdata; 58 struct regmap *regmap; 59 struct mutex lock; 60 61 unsigned int last_flag; 62 struct lm355x_reg_data *regs; 63}; 64 65/* specific indicator function for lm3556 */ 66enum lm3556_indic_pulse_time { 67 PULSE_TIME_0_MS = 0, 68 PULSE_TIME_32_MS, 69 PULSE_TIME_64_MS, 70 PULSE_TIME_92_MS, 71 PULSE_TIME_128_MS, 72 PULSE_TIME_160_MS, 73 PULSE_TIME_196_MS, 74 PULSE_TIME_224_MS, 75 PULSE_TIME_256_MS, 76 PULSE_TIME_288_MS, 77 PULSE_TIME_320_MS, 78 PULSE_TIME_352_MS, 79 PULSE_TIME_384_MS, 80 PULSE_TIME_416_MS, 81 PULSE_TIME_448_MS, 82 PULSE_TIME_480_MS, 83}; 84 85enum lm3556_indic_n_blank { 86 INDIC_N_BLANK_0 = 0, 87 INDIC_N_BLANK_1, 88 INDIC_N_BLANK_2, 89 INDIC_N_BLANK_3, 90 INDIC_N_BLANK_4, 91 INDIC_N_BLANK_5, 92 INDIC_N_BLANK_6, 93 INDIC_N_BLANK_7, 94 INDIC_N_BLANK_8, 95 INDIC_N_BLANK_9, 96 INDIC_N_BLANK_10, 97 INDIC_N_BLANK_11, 98 INDIC_N_BLANK_12, 99 INDIC_N_BLANK_13, 100 INDIC_N_BLANK_14, 101 INDIC_N_BLANK_15, 102}; 103 104enum lm3556_indic_period { 105 INDIC_PERIOD_0 = 0, 106 INDIC_PERIOD_1, 107 INDIC_PERIOD_2, 108 INDIC_PERIOD_3, 109 INDIC_PERIOD_4, 110 INDIC_PERIOD_5, 111 INDIC_PERIOD_6, 112 INDIC_PERIOD_7, 113}; 114 115#define INDIC_PATTERN_SIZE 4 116 117struct indicator { 118 u8 blinking; 119 u8 period_cnt; 120}; 121 122/* indicator pattern data only for lm3556 */ 123static struct indicator indicator_pattern[INDIC_PATTERN_SIZE] = { 124 [0] = {(INDIC_N_BLANK_1 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_1}, 125 [1] = {(INDIC_N_BLANK_15 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_2}, 126 [2] = {(INDIC_N_BLANK_10 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_4}, 127 [3] = {(INDIC_N_BLANK_5 << 4) | PULSE_TIME_32_MS, INDIC_PERIOD_7}, 128}; 129 130static struct lm355x_reg_data lm3554_regs[REG_MAX] = { 131 [REG_FLAG] = {0xD0, 0xBF, 0}, 132 [REG_TORCH_CFG] = {0xE0, 0x80, 7}, 133 [REG_TORCH_CTRL] = {0xA0, 0x38, 3}, 134 [REG_STROBE_CFG] = {0xE0, 0x04, 2}, 135 [REG_FLASH_CTRL] = {0xB0, 0x78, 3}, 136 [REG_INDI_CFG] = {0xE0, 0x08, 3}, 137 [REG_INDI_CTRL] = {0xA0, 0xC0, 6}, 138 [REG_OPMODE] = {0xA0, 0x03, 0}, 139}; 140 141static struct lm355x_reg_data lm3556_regs[REG_MAX] = { 142 [REG_FLAG] = {0x0B, 0xFF, 0}, 143 [REG_TORCH_CFG] = {0x0A, 0x10, 4}, 144 [REG_TORCH_CTRL] = {0x09, 0x70, 4}, 145 [REG_STROBE_CFG] = {0x0A, 0x20, 5}, 146 [REG_FLASH_CTRL] = {0x09, 0x0F, 0}, 147 [REG_INDI_CFG] = {0xFF, 0xFF, 0}, 148 [REG_INDI_CTRL] = {0x09, 0x70, 4}, 149 [REG_OPMODE] = {0x0A, 0x03, 0}, 150}; 151 152static char lm355x_name[][I2C_NAME_SIZE] = { 153 [CHIP_LM3554] = LM3554_NAME, 154 [CHIP_LM3556] = LM3556_NAME, 155}; 156 157/* chip initialize */ 158static int lm355x_chip_init(struct lm355x_chip_data *chip) 159{ 160 int ret; 161 unsigned int reg_val; 162 struct lm355x_platform_data *pdata = chip->pdata; 163 164 /* input and output pins configuration */ 165 switch (chip->type) { 166 case CHIP_LM3554: 167 reg_val = (u32)pdata->pin_tx2 | (u32)pdata->ntc_pin; 168 ret = regmap_update_bits(chip->regmap, 0xE0, 0x28, reg_val); 169 if (ret < 0) 170 goto out; 171 reg_val = (u32)pdata->pass_mode; 172 ret = regmap_update_bits(chip->regmap, 0xA0, 0x04, reg_val); 173 if (ret < 0) 174 goto out; 175 break; 176 177 case CHIP_LM3556: 178 reg_val = (u32)pdata->pin_tx2 | (u32)pdata->ntc_pin | 179 (u32)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 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_WO(pattern); 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(&client->dev, &chip->cdev_flash); 457 if (err < 0) 458 goto err_out; 459 /* torch */ 460 chip->cdev_torch.name = "torch"; 461 chip->cdev_torch.max_brightness = 8; 462 chip->cdev_torch.brightness_set_blocking = lm355x_torch_brightness_set; 463 chip->cdev_torch.default_trigger = "torch"; 464 err = led_classdev_register(&client->dev, &chip->cdev_torch); 465 if (err < 0) 466 goto err_create_torch_file; 467 /* indicator */ 468 chip->cdev_indicator.name = "indicator"; 469 if (id->driver_data == CHIP_LM3554) 470 chip->cdev_indicator.max_brightness = 4; 471 else 472 chip->cdev_indicator.max_brightness = 8; 473 chip->cdev_indicator.brightness_set_blocking = 474 lm355x_indicator_brightness_set; 475 /* indicator pattern control only for LM3556 */ 476 if (id->driver_data == CHIP_LM3556) 477 chip->cdev_indicator.groups = lm355x_indicator_groups; 478 err = led_classdev_register(&client->dev, &chip->cdev_indicator); 479 if (err < 0) 480 goto err_create_indicator_file; 481 482 dev_info(&client->dev, "%s is initialized\n", 483 lm355x_name[id->driver_data]); 484 return 0; 485 486err_create_indicator_file: 487 led_classdev_unregister(&chip->cdev_torch); 488err_create_torch_file: 489 led_classdev_unregister(&chip->cdev_flash); 490err_out: 491 return err; 492} 493 494static int lm355x_remove(struct i2c_client *client) 495{ 496 struct lm355x_chip_data *chip = i2c_get_clientdata(client); 497 struct lm355x_reg_data *preg = chip->regs; 498 499 regmap_write(chip->regmap, preg[REG_OPMODE].regno, 0); 500 led_classdev_unregister(&chip->cdev_indicator); 501 led_classdev_unregister(&chip->cdev_torch); 502 led_classdev_unregister(&chip->cdev_flash); 503 dev_info(&client->dev, "%s is removed\n", lm355x_name[chip->type]); 504 505 return 0; 506} 507 508static const struct i2c_device_id lm355x_id[] = { 509 {LM3554_NAME, CHIP_LM3554}, 510 {LM3556_NAME, CHIP_LM3556}, 511 {} 512}; 513 514MODULE_DEVICE_TABLE(i2c, lm355x_id); 515 516static struct i2c_driver lm355x_i2c_driver = { 517 .driver = { 518 .name = LM355x_NAME, 519 .pm = NULL, 520 }, 521 .probe = lm355x_probe, 522 .remove = lm355x_remove, 523 .id_table = lm355x_id, 524}; 525 526module_i2c_driver(lm355x_i2c_driver); 527 528MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM355x"); 529MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>"); 530MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>"); 531MODULE_LICENSE("GPL v2");