Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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