495 lines · c
1// SPDX-License-Identifier: GPL-2.02// Flash and torch driver for Texas Instruments LM3601X LED3// Flash driver chip family4// 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 0x015#define LM3601X_LED_TORCH 0x116 17/* Registers */18#define LM3601X_ENABLE_REG 0x0119#define LM3601X_CFG_REG 0x0220#define LM3601X_LED_FLASH_REG 0x0321#define LM3601X_LED_TORCH_REG 0x0422#define LM3601X_FLAGS_REG 0x0523#define LM3601X_DEV_ID_REG 0x0624 25#define LM3601X_SW_RESET BIT(7)26 27/* Enable Mode bits */28#define LM3601X_MODE_STANDBY 0x0029#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 37600051#define LM3601X_MIN_TORCH_I_UA 240052#define LM3601X_TORCH_REG_DIV 296553 54#define LM3601X_MAX_STROBE_I_UA 150000055#define LM3601X_MIN_STROBE_I_UA 1100056#define LM3601X_STROBE_REG_DIV 1180057 58#define LM3601X_TIMEOUT_MASK 0x1e59#define LM3601X_ENABLE_MASK (LM3601X_MODE_IR_DRV | LM3601X_MODE_TORCH)60 61#define LM3601X_LOWER_STEP_US 4000062#define LM3601X_UPPER_STEP_US 20000063#define LM3601X_MIN_TIMEOUT_US 4000064#define LM3601X_MAX_TIMEOUT_US 160000065#define LM3601X_TIMEOUT_XOVER_US 40000066 67enum lm3601x_type {68 CHIP_LM36010 = 0,69 CHIP_LM36011,70};71 72/**73 * struct lm3601x_led - private lm3601x LED data74 * @fled_cdev: flash LED class device pointer75 * @client: Pointer to the I2C client76 * @regmap: Devices register map77 * @lock: Lock for reading/writing the device78 * @flash_timeout: the timeout for the flash79 * @last_flag: last known flags register value80 * @torch_current_max: maximum current for the torch81 * @flash_current_max: maximum current for the flash82 * @max_flash_timeout: maximum timeout for the flash83 * @led_mode: The mode to enable either IR or Torch84 */85struct lm3601x_led {86 struct led_classdev_flash fled_cdev;87 struct i2c_client *client;88 struct regmap *regmap;89 struct mutex lock;90 91 unsigned int flash_timeout;92 unsigned int last_flag;93 94 u32 torch_current_max;95 u32 flash_current_max;96 u32 max_flash_timeout;97 98 u32 led_mode;99};100 101static const struct reg_default lm3601x_regmap_defs[] = {102 { LM3601X_ENABLE_REG, 0x20 },103 { LM3601X_CFG_REG, 0x15 },104 { LM3601X_LED_FLASH_REG, 0x00 },105 { LM3601X_LED_TORCH_REG, 0x00 },106};107 108static bool lm3601x_volatile_reg(struct device *dev, unsigned int reg)109{110 switch (reg) {111 case LM3601X_FLAGS_REG:112 return true;113 default:114 return false;115 }116}117 118static const struct regmap_config lm3601x_regmap = {119 .reg_bits = 8,120 .val_bits = 8,121 122 .max_register = LM3601X_DEV_ID_REG,123 .reg_defaults = lm3601x_regmap_defs,124 .num_reg_defaults = ARRAY_SIZE(lm3601x_regmap_defs),125 .cache_type = REGCACHE_MAPLE,126 .volatile_reg = lm3601x_volatile_reg,127};128 129static struct lm3601x_led *fled_cdev_to_led(struct led_classdev_flash *fled_cdev)130{131 return container_of(fled_cdev, struct lm3601x_led, fled_cdev);132}133 134static int lm3601x_read_faults(struct lm3601x_led *led)135{136 int flags_val;137 int ret;138 139 ret = regmap_read(led->regmap, LM3601X_FLAGS_REG, &flags_val);140 if (ret < 0)141 return -EIO;142 143 led->last_flag = 0;144 145 if (flags_val & LM36010_OVP_FAULT)146 led->last_flag |= LED_FAULT_OVER_VOLTAGE;147 148 if (flags_val & (LM3601X_THERM_SHUTDOWN | LM3601X_THERM_CURR))149 led->last_flag |= LED_FAULT_OVER_TEMPERATURE;150 151 if (flags_val & LM3601X_SHORT_FAULT)152 led->last_flag |= LED_FAULT_SHORT_CIRCUIT;153 154 if (flags_val & LM36010_CURR_LIMIT)155 led->last_flag |= LED_FAULT_OVER_CURRENT;156 157 if (flags_val & LM3601X_UVLO_FAULT)158 led->last_flag |= LED_FAULT_UNDER_VOLTAGE;159 160 if (flags_val & LM3601X_IVFM_TRIP)161 led->last_flag |= LED_FAULT_INPUT_VOLTAGE;162 163 if (flags_val & LM3601X_THERM_SHUTDOWN)164 led->last_flag |= LED_FAULT_LED_OVER_TEMPERATURE;165 166 return led->last_flag;167}168 169static int lm3601x_brightness_set(struct led_classdev *cdev,170 enum led_brightness brightness)171{172 struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(cdev);173 struct lm3601x_led *led = fled_cdev_to_led(fled_cdev);174 int ret, led_mode_val;175 176 mutex_lock(&led->lock);177 178 ret = lm3601x_read_faults(led);179 if (ret < 0)180 goto out;181 182 if (led->led_mode == LM3601X_LED_TORCH)183 led_mode_val = LM3601X_MODE_TORCH;184 else185 led_mode_val = LM3601X_MODE_IR_DRV;186 187 if (brightness == LED_OFF) {188 ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG,189 led_mode_val, LED_OFF);190 goto out;191 }192 193 ret = regmap_write(led->regmap, LM3601X_LED_TORCH_REG, brightness - 1);194 if (ret < 0)195 goto out;196 197 ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG,198 LM3601X_MODE_TORCH | LM3601X_MODE_IR_DRV,199 led_mode_val);200out:201 mutex_unlock(&led->lock);202 return ret;203}204 205static int lm3601x_strobe_set(struct led_classdev_flash *fled_cdev,206 bool state)207{208 struct lm3601x_led *led = fled_cdev_to_led(fled_cdev);209 int timeout_reg_val;210 int current_timeout;211 int ret;212 213 mutex_lock(&led->lock);214 215 ret = regmap_read(led->regmap, LM3601X_CFG_REG, ¤t_timeout);216 if (ret < 0)217 goto out;218 219 if (led->flash_timeout >= LM3601X_TIMEOUT_XOVER_US)220 timeout_reg_val = led->flash_timeout / LM3601X_UPPER_STEP_US + 0x07;221 else222 timeout_reg_val = led->flash_timeout / LM3601X_LOWER_STEP_US - 0x01;223 224 if (led->flash_timeout != current_timeout)225 ret = regmap_update_bits(led->regmap, LM3601X_CFG_REG,226 LM3601X_TIMEOUT_MASK, timeout_reg_val);227 228 if (state)229 ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG,230 LM3601X_MODE_TORCH | LM3601X_MODE_IR_DRV,231 LM3601X_MODE_STROBE);232 else233 ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG,234 LM3601X_MODE_STROBE, LED_OFF);235 236 ret = lm3601x_read_faults(led);237out:238 mutex_unlock(&led->lock);239 return ret;240}241 242static int lm3601x_flash_brightness_set(struct led_classdev_flash *fled_cdev,243 u32 brightness)244{245 struct lm3601x_led *led = fled_cdev_to_led(fled_cdev);246 u8 brightness_val;247 int ret;248 249 mutex_lock(&led->lock);250 ret = lm3601x_read_faults(led);251 if (ret < 0)252 goto out;253 254 if (brightness == LED_OFF) {255 ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG,256 LM3601X_MODE_STROBE, LED_OFF);257 goto out;258 }259 260 brightness_val = brightness / LM3601X_STROBE_REG_DIV;261 262 ret = regmap_write(led->regmap, LM3601X_LED_FLASH_REG, brightness_val);263out:264 mutex_unlock(&led->lock);265 return ret;266}267 268static int lm3601x_flash_timeout_set(struct led_classdev_flash *fled_cdev,269 u32 timeout)270{271 struct lm3601x_led *led = fled_cdev_to_led(fled_cdev);272 273 mutex_lock(&led->lock);274 275 led->flash_timeout = timeout;276 277 mutex_unlock(&led->lock);278 279 return 0;280}281 282static int lm3601x_strobe_get(struct led_classdev_flash *fled_cdev, bool *state)283{284 struct lm3601x_led *led = fled_cdev_to_led(fled_cdev);285 int strobe_state;286 int ret;287 288 mutex_lock(&led->lock);289 290 ret = regmap_read(led->regmap, LM3601X_ENABLE_REG, &strobe_state);291 if (ret < 0)292 goto out;293 294 *state = strobe_state & LM3601X_MODE_STROBE;295 296out:297 mutex_unlock(&led->lock);298 return ret;299}300 301static int lm3601x_flash_fault_get(struct led_classdev_flash *fled_cdev,302 u32 *fault)303{304 struct lm3601x_led *led = fled_cdev_to_led(fled_cdev);305 306 lm3601x_read_faults(led);307 308 *fault = led->last_flag;309 310 return 0;311}312 313static const struct led_flash_ops flash_ops = {314 .flash_brightness_set = lm3601x_flash_brightness_set,315 .strobe_set = lm3601x_strobe_set,316 .strobe_get = lm3601x_strobe_get,317 .timeout_set = lm3601x_flash_timeout_set,318 .fault_get = lm3601x_flash_fault_get,319};320 321static int lm3601x_register_leds(struct lm3601x_led *led,322 struct fwnode_handle *fwnode)323{324 struct led_classdev *led_cdev;325 struct led_flash_setting *setting;326 struct led_init_data init_data = {};327 328 led->fled_cdev.ops = &flash_ops;329 330 setting = &led->fled_cdev.timeout;331 setting->min = LM3601X_MIN_TIMEOUT_US;332 setting->max = led->max_flash_timeout;333 setting->step = LM3601X_LOWER_STEP_US;334 setting->val = led->max_flash_timeout;335 336 setting = &led->fled_cdev.brightness;337 setting->min = LM3601X_MIN_STROBE_I_UA;338 setting->max = led->flash_current_max;339 setting->step = LM3601X_TORCH_REG_DIV;340 setting->val = led->flash_current_max;341 342 led_cdev = &led->fled_cdev.led_cdev;343 led_cdev->brightness_set_blocking = lm3601x_brightness_set;344 led_cdev->max_brightness =345 DIV_ROUND_UP(led->torch_current_max - LM3601X_MIN_TORCH_I_UA + 1,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 if (led->torch_current_max > LM3601X_MAX_TORCH_I_UA) {391 dev_warn(&led->client->dev,392 "Max torch current set too high (%d vs %d)\n",393 led->torch_current_max,394 LM3601X_MAX_TORCH_I_UA);395 led->torch_current_max = LM3601X_MAX_TORCH_I_UA;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 414 *fwnode = child;415 416out_err:417 fwnode_handle_put(child);418 return ret;419}420 421static int lm3601x_probe(struct i2c_client *client)422{423 struct lm3601x_led *led;424 struct fwnode_handle *fwnode;425 int ret;426 427 led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL);428 if (!led)429 return -ENOMEM;430 431 led->client = client;432 i2c_set_clientdata(client, led);433 434 ret = lm3601x_parse_node(led, &fwnode);435 if (ret)436 return -ENODEV;437 438 led->regmap = devm_regmap_init_i2c(client, &lm3601x_regmap);439 if (IS_ERR(led->regmap)) {440 ret = PTR_ERR(led->regmap);441 dev_err(&client->dev,442 "Failed to allocate register map: %d\n", ret);443 return ret;444 }445 446 ret = regmap_write(led->regmap, LM3601X_DEV_ID_REG, LM3601X_SW_RESET);447 if (ret)448 dev_warn(&client->dev, "Failed to reset the LED controller\n");449 450 mutex_init(&led->lock);451 452 return lm3601x_register_leds(led, fwnode);453}454 455static void lm3601x_remove(struct i2c_client *client)456{457 struct lm3601x_led *led = i2c_get_clientdata(client);458 int ret;459 460 ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG,461 LM3601X_ENABLE_MASK, LM3601X_MODE_STANDBY);462 if (ret)463 dev_warn(&client->dev,464 "Failed to put into standby (%pe)\n", ERR_PTR(ret));465}466 467static const struct i2c_device_id lm3601x_id[] = {468 { "LM36010", CHIP_LM36010 },469 { "LM36011", CHIP_LM36011 },470 { }471};472MODULE_DEVICE_TABLE(i2c, lm3601x_id);473 474static const struct of_device_id of_lm3601x_leds_match[] = {475 { .compatible = "ti,lm36010", },476 { .compatible = "ti,lm36011", },477 { }478};479MODULE_DEVICE_TABLE(of, of_lm3601x_leds_match);480 481static struct i2c_driver lm3601x_i2c_driver = {482 .driver = {483 .name = "lm3601x",484 .of_match_table = of_lm3601x_leds_match,485 },486 .probe = lm3601x_probe,487 .remove = lm3601x_remove,488 .id_table = lm3601x_id,489};490module_i2c_driver(lm3601x_i2c_driver);491 492MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3601X");493MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");494MODULE_LICENSE("GPL v2");495