leds-lm3601x.c (12061B)
1// SPDX-License-Identifier: GPL-2.0 2// Flash and torch driver for Texas Instruments LM3601X LED 3// Flash driver chip family 4// Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ 5 6#include <linux/delay.h> 7#include <linux/i2c.h> 8#include <linux/leds.h> 9#include <linux/led-class-flash.h> 10#include <linux/module.h> 11#include <linux/regmap.h> 12#include <linux/slab.h> 13 14#define LM3601X_LED_IR 0x0 15#define LM3601X_LED_TORCH 0x1 16 17/* Registers */ 18#define LM3601X_ENABLE_REG 0x01 19#define LM3601X_CFG_REG 0x02 20#define LM3601X_LED_FLASH_REG 0x03 21#define LM3601X_LED_TORCH_REG 0x04 22#define LM3601X_FLAGS_REG 0x05 23#define LM3601X_DEV_ID_REG 0x06 24 25#define LM3601X_SW_RESET BIT(7) 26 27/* Enable Mode bits */ 28#define LM3601X_MODE_STANDBY 0x00 29#define LM3601X_MODE_IR_DRV BIT(0) 30#define LM3601X_MODE_TORCH BIT(1) 31#define LM3601X_MODE_STROBE (BIT(0) | BIT(1)) 32#define LM3601X_STRB_EN BIT(2) 33#define LM3601X_STRB_EDGE_TRIG BIT(3) 34#define LM3601X_IVFM_EN BIT(4) 35 36#define LM36010_BOOST_LIMIT_28 BIT(5) 37#define LM36010_BOOST_FREQ_4MHZ BIT(6) 38#define LM36010_BOOST_MODE_PASS BIT(7) 39 40/* Flag Mask */ 41#define LM3601X_FLASH_TIME_OUT BIT(0) 42#define LM3601X_UVLO_FAULT BIT(1) 43#define LM3601X_THERM_SHUTDOWN BIT(2) 44#define LM3601X_THERM_CURR BIT(3) 45#define LM36010_CURR_LIMIT BIT(4) 46#define LM3601X_SHORT_FAULT BIT(5) 47#define LM3601X_IVFM_TRIP BIT(6) 48#define LM36010_OVP_FAULT BIT(7) 49 50#define LM3601X_MAX_TORCH_I_UA 376000 51#define LM3601X_MIN_TORCH_I_UA 2400 52#define LM3601X_TORCH_REG_DIV 2965 53 54#define LM3601X_MAX_STROBE_I_UA 1500000 55#define LM3601X_MIN_STROBE_I_UA 11000 56#define LM3601X_STROBE_REG_DIV 11800 57 58#define LM3601X_TIMEOUT_MASK 0x1e 59#define LM3601X_ENABLE_MASK (LM3601X_MODE_IR_DRV | LM3601X_MODE_TORCH) 60 61#define LM3601X_LOWER_STEP_US 40000 62#define LM3601X_UPPER_STEP_US 200000 63#define LM3601X_MIN_TIMEOUT_US 40000 64#define LM3601X_MAX_TIMEOUT_US 1600000 65#define LM3601X_TIMEOUT_XOVER_US 400000 66 67enum lm3601x_type { 68 CHIP_LM36010 = 0, 69 CHIP_LM36011, 70}; 71 72/** 73 * struct lm3601x_led - 74 * @fled_cdev: flash LED class device pointer 75 * @client: Pointer to the I2C client 76 * @regmap: Devices register map 77 * @lock: Lock for reading/writing the device 78 * @led_name: LED label for the Torch or IR LED 79 * @flash_timeout: the timeout for the flash 80 * @last_flag: last known flags register value 81 * @torch_current_max: maximum current for the torch 82 * @flash_current_max: maximum current for the flash 83 * @max_flash_timeout: maximum timeout for the flash 84 * @led_mode: The mode to enable either IR or Torch 85 */ 86struct lm3601x_led { 87 struct led_classdev_flash fled_cdev; 88 struct i2c_client *client; 89 struct regmap *regmap; 90 struct mutex lock; 91 92 unsigned int flash_timeout; 93 unsigned int last_flag; 94 95 u32 torch_current_max; 96 u32 flash_current_max; 97 u32 max_flash_timeout; 98 99 u32 led_mode; 100}; 101 102static const struct reg_default lm3601x_regmap_defs[] = { 103 { LM3601X_ENABLE_REG, 0x20 }, 104 { LM3601X_CFG_REG, 0x15 }, 105 { LM3601X_LED_FLASH_REG, 0x00 }, 106 { LM3601X_LED_TORCH_REG, 0x00 }, 107}; 108 109static bool lm3601x_volatile_reg(struct device *dev, unsigned int reg) 110{ 111 switch (reg) { 112 case LM3601X_FLAGS_REG: 113 return true; 114 default: 115 return false; 116 } 117} 118 119static const struct regmap_config lm3601x_regmap = { 120 .reg_bits = 8, 121 .val_bits = 8, 122 123 .max_register = LM3601X_DEV_ID_REG, 124 .reg_defaults = lm3601x_regmap_defs, 125 .num_reg_defaults = ARRAY_SIZE(lm3601x_regmap_defs), 126 .cache_type = REGCACHE_RBTREE, 127 .volatile_reg = lm3601x_volatile_reg, 128}; 129 130static struct lm3601x_led *fled_cdev_to_led(struct led_classdev_flash *fled_cdev) 131{ 132 return container_of(fled_cdev, struct lm3601x_led, fled_cdev); 133} 134 135static int lm3601x_read_faults(struct lm3601x_led *led) 136{ 137 int flags_val; 138 int ret; 139 140 ret = regmap_read(led->regmap, LM3601X_FLAGS_REG, &flags_val); 141 if (ret < 0) 142 return -EIO; 143 144 led->last_flag = 0; 145 146 if (flags_val & LM36010_OVP_FAULT) 147 led->last_flag |= LED_FAULT_OVER_VOLTAGE; 148 149 if (flags_val & (LM3601X_THERM_SHUTDOWN | LM3601X_THERM_CURR)) 150 led->last_flag |= LED_FAULT_OVER_TEMPERATURE; 151 152 if (flags_val & LM3601X_SHORT_FAULT) 153 led->last_flag |= LED_FAULT_SHORT_CIRCUIT; 154 155 if (flags_val & LM36010_CURR_LIMIT) 156 led->last_flag |= LED_FAULT_OVER_CURRENT; 157 158 if (flags_val & LM3601X_UVLO_FAULT) 159 led->last_flag |= LED_FAULT_UNDER_VOLTAGE; 160 161 if (flags_val & LM3601X_IVFM_TRIP) 162 led->last_flag |= LED_FAULT_INPUT_VOLTAGE; 163 164 if (flags_val & LM3601X_THERM_SHUTDOWN) 165 led->last_flag |= LED_FAULT_LED_OVER_TEMPERATURE; 166 167 return led->last_flag; 168} 169 170static int lm3601x_brightness_set(struct led_classdev *cdev, 171 enum led_brightness brightness) 172{ 173 struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(cdev); 174 struct lm3601x_led *led = fled_cdev_to_led(fled_cdev); 175 int ret, led_mode_val; 176 177 mutex_lock(&led->lock); 178 179 ret = lm3601x_read_faults(led); 180 if (ret < 0) 181 goto out; 182 183 if (led->led_mode == LM3601X_LED_TORCH) 184 led_mode_val = LM3601X_MODE_TORCH; 185 else 186 led_mode_val = LM3601X_MODE_IR_DRV; 187 188 if (brightness == LED_OFF) { 189 ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG, 190 led_mode_val, LED_OFF); 191 goto out; 192 } 193 194 ret = regmap_write(led->regmap, LM3601X_LED_TORCH_REG, brightness); 195 if (ret < 0) 196 goto out; 197 198 ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG, 199 LM3601X_MODE_TORCH | LM3601X_MODE_IR_DRV, 200 led_mode_val); 201out: 202 mutex_unlock(&led->lock); 203 return ret; 204} 205 206static int lm3601x_strobe_set(struct led_classdev_flash *fled_cdev, 207 bool state) 208{ 209 struct lm3601x_led *led = fled_cdev_to_led(fled_cdev); 210 int timeout_reg_val; 211 int current_timeout; 212 int ret; 213 214 mutex_lock(&led->lock); 215 216 ret = regmap_read(led->regmap, LM3601X_CFG_REG, ¤t_timeout); 217 if (ret < 0) 218 goto out; 219 220 if (led->flash_timeout >= LM3601X_TIMEOUT_XOVER_US) 221 timeout_reg_val = led->flash_timeout / LM3601X_UPPER_STEP_US + 0x07; 222 else 223 timeout_reg_val = led->flash_timeout / LM3601X_LOWER_STEP_US - 0x01; 224 225 if (led->flash_timeout != current_timeout) 226 ret = regmap_update_bits(led->regmap, LM3601X_CFG_REG, 227 LM3601X_TIMEOUT_MASK, timeout_reg_val); 228 229 if (state) 230 ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG, 231 LM3601X_MODE_TORCH | LM3601X_MODE_IR_DRV, 232 LM3601X_MODE_STROBE); 233 else 234 ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG, 235 LM3601X_MODE_STROBE, LED_OFF); 236 237 ret = lm3601x_read_faults(led); 238out: 239 mutex_unlock(&led->lock); 240 return ret; 241} 242 243static int lm3601x_flash_brightness_set(struct led_classdev_flash *fled_cdev, 244 u32 brightness) 245{ 246 struct lm3601x_led *led = fled_cdev_to_led(fled_cdev); 247 u8 brightness_val; 248 int ret; 249 250 mutex_lock(&led->lock); 251 ret = lm3601x_read_faults(led); 252 if (ret < 0) 253 goto out; 254 255 if (brightness == LED_OFF) { 256 ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG, 257 LM3601X_MODE_STROBE, LED_OFF); 258 goto out; 259 } 260 261 brightness_val = brightness / LM3601X_STROBE_REG_DIV; 262 263 ret = regmap_write(led->regmap, LM3601X_LED_FLASH_REG, brightness_val); 264out: 265 mutex_unlock(&led->lock); 266 return ret; 267} 268 269static int lm3601x_flash_timeout_set(struct led_classdev_flash *fled_cdev, 270 u32 timeout) 271{ 272 struct lm3601x_led *led = fled_cdev_to_led(fled_cdev); 273 274 mutex_lock(&led->lock); 275 276 led->flash_timeout = timeout; 277 278 mutex_unlock(&led->lock); 279 280 return 0; 281} 282 283static int lm3601x_strobe_get(struct led_classdev_flash *fled_cdev, bool *state) 284{ 285 struct lm3601x_led *led = fled_cdev_to_led(fled_cdev); 286 int strobe_state; 287 int ret; 288 289 mutex_lock(&led->lock); 290 291 ret = regmap_read(led->regmap, LM3601X_ENABLE_REG, &strobe_state); 292 if (ret < 0) 293 goto out; 294 295 *state = strobe_state & LM3601X_MODE_STROBE; 296 297out: 298 mutex_unlock(&led->lock); 299 return ret; 300} 301 302static int lm3601x_flash_fault_get(struct led_classdev_flash *fled_cdev, 303 u32 *fault) 304{ 305 struct lm3601x_led *led = fled_cdev_to_led(fled_cdev); 306 307 lm3601x_read_faults(led); 308 309 *fault = led->last_flag; 310 311 return 0; 312} 313 314static const struct led_flash_ops flash_ops = { 315 .flash_brightness_set = lm3601x_flash_brightness_set, 316 .strobe_set = lm3601x_strobe_set, 317 .strobe_get = lm3601x_strobe_get, 318 .timeout_set = lm3601x_flash_timeout_set, 319 .fault_get = lm3601x_flash_fault_get, 320}; 321 322static int lm3601x_register_leds(struct lm3601x_led *led, 323 struct fwnode_handle *fwnode) 324{ 325 struct led_classdev *led_cdev; 326 struct led_flash_setting *setting; 327 struct led_init_data init_data = {}; 328 329 led->fled_cdev.ops = &flash_ops; 330 331 setting = &led->fled_cdev.timeout; 332 setting->min = LM3601X_MIN_TIMEOUT_US; 333 setting->max = led->max_flash_timeout; 334 setting->step = LM3601X_LOWER_STEP_US; 335 setting->val = led->max_flash_timeout; 336 337 setting = &led->fled_cdev.brightness; 338 setting->min = LM3601X_MIN_STROBE_I_UA; 339 setting->max = led->flash_current_max; 340 setting->step = LM3601X_TORCH_REG_DIV; 341 setting->val = led->flash_current_max; 342 343 led_cdev = &led->fled_cdev.led_cdev; 344 led_cdev->brightness_set_blocking = lm3601x_brightness_set; 345 led_cdev->max_brightness = DIV_ROUND_UP(led->torch_current_max, 346 LM3601X_TORCH_REG_DIV); 347 led_cdev->flags |= LED_DEV_CAP_FLASH; 348 349 init_data.fwnode = fwnode; 350 init_data.devicename = led->client->name; 351 init_data.default_label = (led->led_mode == LM3601X_LED_TORCH) ? 352 "torch" : "infrared"; 353 return devm_led_classdev_flash_register_ext(&led->client->dev, 354 &led->fled_cdev, &init_data); 355} 356 357static int lm3601x_parse_node(struct lm3601x_led *led, 358 struct fwnode_handle **fwnode) 359{ 360 struct fwnode_handle *child = NULL; 361 int ret = -ENODEV; 362 363 child = device_get_next_child_node(&led->client->dev, child); 364 if (!child) { 365 dev_err(&led->client->dev, "No LED Child node\n"); 366 return ret; 367 } 368 369 ret = fwnode_property_read_u32(child, "reg", &led->led_mode); 370 if (ret) { 371 dev_err(&led->client->dev, "reg DT property missing\n"); 372 goto out_err; 373 } 374 375 if (led->led_mode > LM3601X_LED_TORCH || 376 led->led_mode < LM3601X_LED_IR) { 377 dev_warn(&led->client->dev, "Invalid led mode requested\n"); 378 ret = -EINVAL; 379 goto out_err; 380 } 381 382 ret = fwnode_property_read_u32(child, "led-max-microamp", 383 &led->torch_current_max); 384 if (ret) { 385 dev_warn(&led->client->dev, 386 "led-max-microamp DT property missing\n"); 387 goto out_err; 388 } 389 390 ret = fwnode_property_read_u32(child, "flash-max-microamp", 391 &led->flash_current_max); 392 if (ret) { 393 dev_warn(&led->client->dev, 394 "flash-max-microamp DT property missing\n"); 395 goto out_err; 396 } 397 398 ret = fwnode_property_read_u32(child, "flash-max-timeout-us", 399 &led->max_flash_timeout); 400 if (ret) { 401 dev_warn(&led->client->dev, 402 "flash-max-timeout-us DT property missing\n"); 403 goto out_err; 404 } 405 406 *fwnode = child; 407 408out_err: 409 fwnode_handle_put(child); 410 return ret; 411} 412 413static int lm3601x_probe(struct i2c_client *client) 414{ 415 struct lm3601x_led *led; 416 struct fwnode_handle *fwnode; 417 int ret; 418 419 led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL); 420 if (!led) 421 return -ENOMEM; 422 423 led->client = client; 424 i2c_set_clientdata(client, led); 425 426 ret = lm3601x_parse_node(led, &fwnode); 427 if (ret) 428 return -ENODEV; 429 430 led->regmap = devm_regmap_init_i2c(client, &lm3601x_regmap); 431 if (IS_ERR(led->regmap)) { 432 ret = PTR_ERR(led->regmap); 433 dev_err(&client->dev, 434 "Failed to allocate register map: %d\n", ret); 435 return ret; 436 } 437 438 mutex_init(&led->lock); 439 440 return lm3601x_register_leds(led, fwnode); 441} 442 443static int lm3601x_remove(struct i2c_client *client) 444{ 445 struct lm3601x_led *led = i2c_get_clientdata(client); 446 447 mutex_destroy(&led->lock); 448 449 return regmap_update_bits(led->regmap, LM3601X_ENABLE_REG, 450 LM3601X_ENABLE_MASK, 451 LM3601X_MODE_STANDBY); 452} 453 454static const struct i2c_device_id lm3601x_id[] = { 455 { "LM36010", CHIP_LM36010 }, 456 { "LM36011", CHIP_LM36011 }, 457 { } 458}; 459MODULE_DEVICE_TABLE(i2c, lm3601x_id); 460 461static const struct of_device_id of_lm3601x_leds_match[] = { 462 { .compatible = "ti,lm36010", }, 463 { .compatible = "ti,lm36011", }, 464 { } 465}; 466MODULE_DEVICE_TABLE(of, of_lm3601x_leds_match); 467 468static struct i2c_driver lm3601x_i2c_driver = { 469 .driver = { 470 .name = "lm3601x", 471 .of_match_table = of_lm3601x_leds_match, 472 }, 473 .probe_new = lm3601x_probe, 474 .remove = lm3601x_remove, 475 .id_table = lm3601x_id, 476}; 477module_i2c_driver(lm3601x_i2c_driver); 478 479MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3601X"); 480MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); 481MODULE_LICENSE("GPL v2");