Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Flash and torch driver for Texas Instruments LM3601X LED
0003 // Flash driver chip family
0004 // Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
0005 
0006 #include <linux/delay.h>
0007 #include <linux/i2c.h>
0008 #include <linux/leds.h>
0009 #include <linux/led-class-flash.h>
0010 #include <linux/module.h>
0011 #include <linux/regmap.h>
0012 #include <linux/slab.h>
0013 
0014 #define LM3601X_LED_IR      0x0
0015 #define LM3601X_LED_TORCH   0x1
0016 
0017 /* Registers */
0018 #define LM3601X_ENABLE_REG  0x01
0019 #define LM3601X_CFG_REG     0x02
0020 #define LM3601X_LED_FLASH_REG   0x03
0021 #define LM3601X_LED_TORCH_REG   0x04
0022 #define LM3601X_FLAGS_REG   0x05
0023 #define LM3601X_DEV_ID_REG  0x06
0024 
0025 #define LM3601X_SW_RESET    BIT(7)
0026 
0027 /* Enable Mode bits */
0028 #define LM3601X_MODE_STANDBY    0x00
0029 #define LM3601X_MODE_IR_DRV BIT(0)
0030 #define LM3601X_MODE_TORCH  BIT(1)
0031 #define LM3601X_MODE_STROBE (BIT(0) | BIT(1))
0032 #define LM3601X_STRB_EN     BIT(2)
0033 #define LM3601X_STRB_EDGE_TRIG  BIT(3)
0034 #define LM3601X_IVFM_EN     BIT(4)
0035 
0036 #define LM36010_BOOST_LIMIT_28  BIT(5)
0037 #define LM36010_BOOST_FREQ_4MHZ BIT(6)
0038 #define LM36010_BOOST_MODE_PASS BIT(7)
0039 
0040 /* Flag Mask */
0041 #define LM3601X_FLASH_TIME_OUT  BIT(0)
0042 #define LM3601X_UVLO_FAULT  BIT(1)
0043 #define LM3601X_THERM_SHUTDOWN  BIT(2)
0044 #define LM3601X_THERM_CURR  BIT(3)
0045 #define LM36010_CURR_LIMIT  BIT(4)
0046 #define LM3601X_SHORT_FAULT BIT(5)
0047 #define LM3601X_IVFM_TRIP   BIT(6)
0048 #define LM36010_OVP_FAULT   BIT(7)
0049 
0050 #define LM3601X_MAX_TORCH_I_UA  376000
0051 #define LM3601X_MIN_TORCH_I_UA  2400
0052 #define LM3601X_TORCH_REG_DIV   2965
0053 
0054 #define LM3601X_MAX_STROBE_I_UA 1500000
0055 #define LM3601X_MIN_STROBE_I_UA 11000
0056 #define LM3601X_STROBE_REG_DIV  11800
0057 
0058 #define LM3601X_TIMEOUT_MASK    0x1e
0059 #define LM3601X_ENABLE_MASK (LM3601X_MODE_IR_DRV | LM3601X_MODE_TORCH)
0060 
0061 #define LM3601X_LOWER_STEP_US   40000
0062 #define LM3601X_UPPER_STEP_US   200000
0063 #define LM3601X_MIN_TIMEOUT_US  40000
0064 #define LM3601X_MAX_TIMEOUT_US  1600000
0065 #define LM3601X_TIMEOUT_XOVER_US 400000
0066 
0067 enum lm3601x_type {
0068     CHIP_LM36010 = 0,
0069     CHIP_LM36011,
0070 };
0071 
0072 /**
0073  * struct lm3601x_led -
0074  * @fled_cdev: flash LED class device pointer
0075  * @client: Pointer to the I2C client
0076  * @regmap: Devices register map
0077  * @lock: Lock for reading/writing the device
0078  * @led_name: LED label for the Torch or IR LED
0079  * @flash_timeout: the timeout for the flash
0080  * @last_flag: last known flags register value
0081  * @torch_current_max: maximum current for the torch
0082  * @flash_current_max: maximum current for the flash
0083  * @max_flash_timeout: maximum timeout for the flash
0084  * @led_mode: The mode to enable either IR or Torch
0085  */
0086 struct lm3601x_led {
0087     struct led_classdev_flash fled_cdev;
0088     struct i2c_client *client;
0089     struct regmap *regmap;
0090     struct mutex lock;
0091 
0092     unsigned int flash_timeout;
0093     unsigned int last_flag;
0094 
0095     u32 torch_current_max;
0096     u32 flash_current_max;
0097     u32 max_flash_timeout;
0098 
0099     u32 led_mode;
0100 };
0101 
0102 static const struct reg_default lm3601x_regmap_defs[] = {
0103     { LM3601X_ENABLE_REG, 0x20 },
0104     { LM3601X_CFG_REG, 0x15 },
0105     { LM3601X_LED_FLASH_REG, 0x00 },
0106     { LM3601X_LED_TORCH_REG, 0x00 },
0107 };
0108 
0109 static bool lm3601x_volatile_reg(struct device *dev, unsigned int reg)
0110 {
0111     switch (reg) {
0112     case LM3601X_FLAGS_REG:
0113         return true;
0114     default:
0115         return false;
0116     }
0117 }
0118 
0119 static const struct regmap_config lm3601x_regmap = {
0120     .reg_bits = 8,
0121     .val_bits = 8,
0122 
0123     .max_register = LM3601X_DEV_ID_REG,
0124     .reg_defaults = lm3601x_regmap_defs,
0125     .num_reg_defaults = ARRAY_SIZE(lm3601x_regmap_defs),
0126     .cache_type = REGCACHE_RBTREE,
0127     .volatile_reg = lm3601x_volatile_reg,
0128 };
0129 
0130 static struct lm3601x_led *fled_cdev_to_led(struct led_classdev_flash *fled_cdev)
0131 {
0132     return container_of(fled_cdev, struct lm3601x_led, fled_cdev);
0133 }
0134 
0135 static int lm3601x_read_faults(struct lm3601x_led *led)
0136 {
0137     int flags_val;
0138     int ret;
0139 
0140     ret = regmap_read(led->regmap, LM3601X_FLAGS_REG, &flags_val);
0141     if (ret < 0)
0142         return -EIO;
0143 
0144     led->last_flag = 0;
0145 
0146     if (flags_val & LM36010_OVP_FAULT)
0147         led->last_flag |= LED_FAULT_OVER_VOLTAGE;
0148 
0149     if (flags_val & (LM3601X_THERM_SHUTDOWN | LM3601X_THERM_CURR))
0150         led->last_flag |= LED_FAULT_OVER_TEMPERATURE;
0151 
0152     if (flags_val & LM3601X_SHORT_FAULT)
0153         led->last_flag |= LED_FAULT_SHORT_CIRCUIT;
0154 
0155     if (flags_val & LM36010_CURR_LIMIT)
0156         led->last_flag |= LED_FAULT_OVER_CURRENT;
0157 
0158     if (flags_val & LM3601X_UVLO_FAULT)
0159         led->last_flag |= LED_FAULT_UNDER_VOLTAGE;
0160 
0161     if (flags_val & LM3601X_IVFM_TRIP)
0162         led->last_flag |= LED_FAULT_INPUT_VOLTAGE;
0163 
0164     if (flags_val & LM3601X_THERM_SHUTDOWN)
0165         led->last_flag |= LED_FAULT_LED_OVER_TEMPERATURE;
0166 
0167     return led->last_flag;
0168 }
0169 
0170 static int lm3601x_brightness_set(struct led_classdev *cdev,
0171                     enum led_brightness brightness)
0172 {
0173     struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(cdev);
0174     struct lm3601x_led *led = fled_cdev_to_led(fled_cdev);
0175     int ret, led_mode_val;
0176 
0177     mutex_lock(&led->lock);
0178 
0179     ret = lm3601x_read_faults(led);
0180     if (ret < 0)
0181         goto out;
0182 
0183     if (led->led_mode == LM3601X_LED_TORCH)
0184         led_mode_val = LM3601X_MODE_TORCH;
0185     else
0186         led_mode_val = LM3601X_MODE_IR_DRV;
0187 
0188     if (brightness == LED_OFF) {
0189         ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG,
0190                     led_mode_val, LED_OFF);
0191         goto out;
0192     }
0193 
0194     ret = regmap_write(led->regmap, LM3601X_LED_TORCH_REG, brightness);
0195     if (ret < 0)
0196         goto out;
0197 
0198     ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG,
0199                 LM3601X_MODE_TORCH | LM3601X_MODE_IR_DRV,
0200                 led_mode_val);
0201 out:
0202     mutex_unlock(&led->lock);
0203     return ret;
0204 }
0205 
0206 static int lm3601x_strobe_set(struct led_classdev_flash *fled_cdev,
0207                 bool state)
0208 {
0209     struct lm3601x_led *led = fled_cdev_to_led(fled_cdev);
0210     int timeout_reg_val;
0211     int current_timeout;
0212     int ret;
0213 
0214     mutex_lock(&led->lock);
0215 
0216     ret = regmap_read(led->regmap, LM3601X_CFG_REG, &current_timeout);
0217     if (ret < 0)
0218         goto out;
0219 
0220     if (led->flash_timeout >= LM3601X_TIMEOUT_XOVER_US)
0221         timeout_reg_val = led->flash_timeout / LM3601X_UPPER_STEP_US + 0x07;
0222     else
0223         timeout_reg_val = led->flash_timeout / LM3601X_LOWER_STEP_US - 0x01;
0224 
0225     if (led->flash_timeout != current_timeout)
0226         ret = regmap_update_bits(led->regmap, LM3601X_CFG_REG,
0227                     LM3601X_TIMEOUT_MASK, timeout_reg_val);
0228 
0229     if (state)
0230         ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG,
0231                     LM3601X_MODE_TORCH | LM3601X_MODE_IR_DRV,
0232                     LM3601X_MODE_STROBE);
0233     else
0234         ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG,
0235                     LM3601X_MODE_STROBE, LED_OFF);
0236 
0237     ret = lm3601x_read_faults(led);
0238 out:
0239     mutex_unlock(&led->lock);
0240     return ret;
0241 }
0242 
0243 static int lm3601x_flash_brightness_set(struct led_classdev_flash *fled_cdev,
0244                     u32 brightness)
0245 {
0246     struct lm3601x_led *led = fled_cdev_to_led(fled_cdev);
0247     u8 brightness_val;
0248     int ret;
0249 
0250     mutex_lock(&led->lock);
0251     ret = lm3601x_read_faults(led);
0252     if (ret < 0)
0253         goto out;
0254 
0255     if (brightness == LED_OFF) {
0256         ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG,
0257                     LM3601X_MODE_STROBE, LED_OFF);
0258         goto out;
0259     }
0260 
0261     brightness_val = brightness / LM3601X_STROBE_REG_DIV;
0262 
0263     ret = regmap_write(led->regmap, LM3601X_LED_FLASH_REG, brightness_val);
0264 out:
0265     mutex_unlock(&led->lock);
0266     return ret;
0267 }
0268 
0269 static int lm3601x_flash_timeout_set(struct led_classdev_flash *fled_cdev,
0270                 u32 timeout)
0271 {
0272     struct lm3601x_led *led = fled_cdev_to_led(fled_cdev);
0273 
0274     mutex_lock(&led->lock);
0275 
0276     led->flash_timeout = timeout;
0277 
0278     mutex_unlock(&led->lock);
0279 
0280     return 0;
0281 }
0282 
0283 static int lm3601x_strobe_get(struct led_classdev_flash *fled_cdev, bool *state)
0284 {
0285     struct lm3601x_led *led = fled_cdev_to_led(fled_cdev);
0286     int strobe_state;
0287     int ret;
0288 
0289     mutex_lock(&led->lock);
0290 
0291     ret = regmap_read(led->regmap, LM3601X_ENABLE_REG, &strobe_state);
0292     if (ret < 0)
0293         goto out;
0294 
0295     *state = strobe_state & LM3601X_MODE_STROBE;
0296 
0297 out:
0298     mutex_unlock(&led->lock);
0299     return ret;
0300 }
0301 
0302 static int lm3601x_flash_fault_get(struct led_classdev_flash *fled_cdev,
0303                 u32 *fault)
0304 {
0305     struct lm3601x_led *led = fled_cdev_to_led(fled_cdev);
0306 
0307     lm3601x_read_faults(led);
0308 
0309     *fault = led->last_flag;
0310 
0311     return 0;
0312 }
0313 
0314 static const struct led_flash_ops flash_ops = {
0315     .flash_brightness_set   = lm3601x_flash_brightness_set,
0316     .strobe_set     = lm3601x_strobe_set,
0317     .strobe_get     = lm3601x_strobe_get,
0318     .timeout_set        = lm3601x_flash_timeout_set,
0319     .fault_get      = lm3601x_flash_fault_get,
0320 };
0321 
0322 static int lm3601x_register_leds(struct lm3601x_led *led,
0323                  struct fwnode_handle *fwnode)
0324 {
0325     struct led_classdev *led_cdev;
0326     struct led_flash_setting *setting;
0327     struct led_init_data init_data = {};
0328 
0329     led->fled_cdev.ops = &flash_ops;
0330 
0331     setting = &led->fled_cdev.timeout;
0332     setting->min = LM3601X_MIN_TIMEOUT_US;
0333     setting->max = led->max_flash_timeout;
0334     setting->step = LM3601X_LOWER_STEP_US;
0335     setting->val = led->max_flash_timeout;
0336 
0337     setting = &led->fled_cdev.brightness;
0338     setting->min = LM3601X_MIN_STROBE_I_UA;
0339     setting->max = led->flash_current_max;
0340     setting->step = LM3601X_TORCH_REG_DIV;
0341     setting->val = led->flash_current_max;
0342 
0343     led_cdev = &led->fled_cdev.led_cdev;
0344     led_cdev->brightness_set_blocking = lm3601x_brightness_set;
0345     led_cdev->max_brightness = DIV_ROUND_UP(led->torch_current_max,
0346                         LM3601X_TORCH_REG_DIV);
0347     led_cdev->flags |= LED_DEV_CAP_FLASH;
0348 
0349     init_data.fwnode = fwnode;
0350     init_data.devicename = led->client->name;
0351     init_data.default_label = (led->led_mode == LM3601X_LED_TORCH) ?
0352                     "torch" : "infrared";
0353     return devm_led_classdev_flash_register_ext(&led->client->dev,
0354                         &led->fled_cdev, &init_data);
0355 }
0356 
0357 static int lm3601x_parse_node(struct lm3601x_led *led,
0358                   struct fwnode_handle **fwnode)
0359 {
0360     struct fwnode_handle *child = NULL;
0361     int ret = -ENODEV;
0362 
0363     child = device_get_next_child_node(&led->client->dev, child);
0364     if (!child) {
0365         dev_err(&led->client->dev, "No LED Child node\n");
0366         return ret;
0367     }
0368 
0369     ret = fwnode_property_read_u32(child, "reg", &led->led_mode);
0370     if (ret) {
0371         dev_err(&led->client->dev, "reg DT property missing\n");
0372         goto out_err;
0373     }
0374 
0375     if (led->led_mode > LM3601X_LED_TORCH ||
0376         led->led_mode < LM3601X_LED_IR) {
0377         dev_warn(&led->client->dev, "Invalid led mode requested\n");
0378         ret = -EINVAL;
0379         goto out_err;
0380     }
0381 
0382     ret = fwnode_property_read_u32(child, "led-max-microamp",
0383                     &led->torch_current_max);
0384     if (ret) {
0385         dev_warn(&led->client->dev,
0386             "led-max-microamp DT property missing\n");
0387         goto out_err;
0388     }
0389 
0390     ret = fwnode_property_read_u32(child, "flash-max-microamp",
0391                 &led->flash_current_max);
0392     if (ret) {
0393         dev_warn(&led->client->dev,
0394              "flash-max-microamp DT property missing\n");
0395         goto out_err;
0396     }
0397 
0398     ret = fwnode_property_read_u32(child, "flash-max-timeout-us",
0399                 &led->max_flash_timeout);
0400     if (ret) {
0401         dev_warn(&led->client->dev,
0402              "flash-max-timeout-us DT property missing\n");
0403         goto out_err;
0404     }
0405 
0406     *fwnode = child;
0407 
0408 out_err:
0409     fwnode_handle_put(child);
0410     return ret;
0411 }
0412 
0413 static int lm3601x_probe(struct i2c_client *client)
0414 {
0415     struct lm3601x_led *led;
0416     struct fwnode_handle *fwnode;
0417     int ret;
0418 
0419     led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL);
0420     if (!led)
0421         return -ENOMEM;
0422 
0423     led->client = client;
0424     i2c_set_clientdata(client, led);
0425 
0426     ret = lm3601x_parse_node(led, &fwnode);
0427     if (ret)
0428         return -ENODEV;
0429 
0430     led->regmap = devm_regmap_init_i2c(client, &lm3601x_regmap);
0431     if (IS_ERR(led->regmap)) {
0432         ret = PTR_ERR(led->regmap);
0433         dev_err(&client->dev,
0434             "Failed to allocate register map: %d\n", ret);
0435         return ret;
0436     }
0437 
0438     mutex_init(&led->lock);
0439 
0440     return lm3601x_register_leds(led, fwnode);
0441 }
0442 
0443 static int lm3601x_remove(struct i2c_client *client)
0444 {
0445     struct lm3601x_led *led = i2c_get_clientdata(client);
0446 
0447     mutex_destroy(&led->lock);
0448 
0449     return regmap_update_bits(led->regmap, LM3601X_ENABLE_REG,
0450                LM3601X_ENABLE_MASK,
0451                LM3601X_MODE_STANDBY);
0452 }
0453 
0454 static const struct i2c_device_id lm3601x_id[] = {
0455     { "LM36010", CHIP_LM36010 },
0456     { "LM36011", CHIP_LM36011 },
0457     { }
0458 };
0459 MODULE_DEVICE_TABLE(i2c, lm3601x_id);
0460 
0461 static const struct of_device_id of_lm3601x_leds_match[] = {
0462     { .compatible = "ti,lm36010", },
0463     { .compatible = "ti,lm36011", },
0464     { }
0465 };
0466 MODULE_DEVICE_TABLE(of, of_lm3601x_leds_match);
0467 
0468 static struct i2c_driver lm3601x_i2c_driver = {
0469     .driver = {
0470         .name = "lm3601x",
0471         .of_match_table = of_lm3601x_leds_match,
0472     },
0473     .probe_new = lm3601x_probe,
0474     .remove = lm3601x_remove,
0475     .id_table = lm3601x_id,
0476 };
0477 module_i2c_driver(lm3601x_i2c_driver);
0478 
0479 MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3601X");
0480 MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
0481 MODULE_LICENSE("GPL v2");