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

leds: Add new LED driver for lm3642 chips

This driver is a general version for LM642 led chip of TI.

LM3642 :
The LM3642 is a 4MHz fixed-frequency synchronous boost
converter plus 1.5A constant current driver for a high-current
white LED.
The LM3642 is controlled via an I2C-compatible interface.

Signed-off-by: G.Shark Jeong <gshark.jeong@gmail.com>
Signed-off-by: Bryan Wu <bryan.wu@canonical.com>

authored by

G.Shark Jeong and committed by
Bryan Wu
8b7cfbec f1625842

+521
+11
drivers/leds/Kconfig
··· 63 63 hardware-accelerated blinking with maximum on and off periods of 9.8 64 64 and 77 seconds respectively. 65 65 66 + config LEDS_LM3642 67 + tristate "LED support for LM3642 Chip" 68 + depends on LEDS_CLASS && I2C 69 + select REGMAP_I2C 70 + help 71 + This option enables support for LEDs connected to LM3642. 72 + The LM3642 is a 4MHz fixed-frequency synchronous boost 73 + converter plus 1.5A constant current driver for a high-current 74 + white LED. 75 + 76 + 66 77 config LEDS_LOCOMO 67 78 tristate "LED Support for Locomo device" 68 79 depends on LEDS_CLASS
+1
drivers/leds/Makefile
··· 11 11 obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o 12 12 obj-$(CONFIG_LEDS_LM3530) += leds-lm3530.o 13 13 obj-$(CONFIG_LEDS_LM3533) += leds-lm3533.o 14 + obj-$(CONFIG_LEDS_LM3642) += leds-lm3642.o 14 15 obj-$(CONFIG_LEDS_MIKROTIK_RB532) += leds-rb532.o 15 16 obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o 16 17 obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
+471
drivers/leds/leds-lm3642.c
··· 1 + /* 2 + * Simple driver for Texas Instruments LM3642 LED Flash driver chip 3 + * Copyright (C) 2012 Texas Instruments 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + */ 10 + #include <linux/module.h> 11 + #include <linux/delay.h> 12 + #include <linux/i2c.h> 13 + #include <linux/leds.h> 14 + #include <linux/slab.h> 15 + #include <linux/platform_device.h> 16 + #include <linux/fs.h> 17 + #include <linux/regmap.h> 18 + #include <linux/workqueue.h> 19 + #include <linux/platform_data/leds-lm3642.h> 20 + 21 + #define REG_FILT_TIME (0x0) 22 + #define REG_IVFM_MODE (0x1) 23 + #define REG_TORCH_TIME (0x6) 24 + #define REG_FLASH (0x8) 25 + #define REG_I_CTRL (0x9) 26 + #define REG_ENABLE (0xA) 27 + #define REG_FLAG (0xB) 28 + #define REG_MAX (0xB) 29 + 30 + #define UVLO_EN_SHIFT (7) 31 + #define IVM_D_TH_SHIFT (2) 32 + #define TORCH_RAMP_UP_TIME_SHIFT (3) 33 + #define TORCH_RAMP_DN_TIME_SHIFT (0) 34 + #define INDUCTOR_I_LIMIT_SHIFT (6) 35 + #define FLASH_RAMP_TIME_SHIFT (3) 36 + #define FLASH_TOUT_TIME_SHIFT (0) 37 + #define TORCH_I_SHIFT (4) 38 + #define FLASH_I_SHIFT (0) 39 + #define IVFM_SHIFT (7) 40 + #define TX_PIN_EN_SHIFT (6) 41 + #define STROBE_PIN_EN_SHIFT (5) 42 + #define TORCH_PIN_EN_SHIFT (4) 43 + #define MODE_BITS_SHIFT (0) 44 + 45 + #define UVLO_EN_MASK (0x1) 46 + #define IVM_D_TH_MASK (0x7) 47 + #define TORCH_RAMP_UP_TIME_MASK (0x7) 48 + #define TORCH_RAMP_DN_TIME_MASK (0x7) 49 + #define INDUCTOR_I_LIMIT_MASK (0x1) 50 + #define FLASH_RAMP_TIME_MASK (0x7) 51 + #define FLASH_TOUT_TIME_MASK (0x7) 52 + #define TORCH_I_MASK (0x7) 53 + #define FLASH_I_MASK (0xF) 54 + #define IVFM_MASK (0x1) 55 + #define TX_PIN_EN_MASK (0x1) 56 + #define STROBE_PIN_EN_MASK (0x1) 57 + #define TORCH_PIN_EN_MASK (0x1) 58 + #define MODE_BITS_MASK (0x73) 59 + #define EX_PIN_CONTROL_MASK (0x71) 60 + #define EX_PIN_ENABLE_MASK (0x70) 61 + 62 + enum lm3642_mode { 63 + MODES_STASNDBY = 0, 64 + MODES_INDIC, 65 + MODES_TORCH, 66 + MODES_FLASH 67 + }; 68 + 69 + struct lm3642_chip_data { 70 + struct device *dev; 71 + 72 + struct led_classdev cdev_flash; 73 + struct led_classdev cdev_torch; 74 + struct led_classdev cdev_indicator; 75 + 76 + struct work_struct work_flash; 77 + struct work_struct work_torch; 78 + struct work_struct work_indicator; 79 + 80 + u8 br_flash; 81 + u8 br_torch; 82 + u8 br_indicator; 83 + 84 + enum lm3642_torch_pin_enable torch_pin; 85 + enum lm3642_strobe_pin_enable strobe_pin; 86 + enum lm3642_tx_pin_enable tx_pin; 87 + 88 + struct lm3642_platform_data *pdata; 89 + struct regmap *regmap; 90 + struct mutex lock; 91 + 92 + unsigned int last_flag; 93 + }; 94 + 95 + /* chip initialize */ 96 + static int __devinit lm3642_chip_init(struct lm3642_chip_data *chip) 97 + { 98 + unsigned int reg_val; 99 + int ret; 100 + struct lm3642_platform_data *pdata = chip->pdata; 101 + 102 + /* set enable register */ 103 + ret = regmap_read(chip->regmap, REG_ENABLE, &reg_val); 104 + if (ret < 0) 105 + goto out; 106 + 107 + reg_val &= (~EX_PIN_ENABLE_MASK); 108 + reg_val |= pdata->tx_pin; 109 + ret = regmap_write(chip->regmap, REG_ENABLE, reg_val); 110 + if (ret < 0) 111 + goto out; 112 + 113 + out: 114 + dev_err(chip->dev, "Failed to read REG_ENABLE Register\n"); 115 + return ret; 116 + } 117 + 118 + /* chip control */ 119 + static int lm3642_control(struct lm3642_chip_data *chip, 120 + u8 brightness, enum lm3642_mode opmode) 121 + { 122 + int ret; 123 + 124 + ret = regmap_read(chip->regmap, REG_FLAG, &chip->last_flag); 125 + if (ret < 0) { 126 + dev_err(chip->dev, "Failed to read REG_FLAG Register\n"); 127 + goto out; 128 + } 129 + 130 + if (chip->last_flag) 131 + dev_info(chip->dev, "Last FLAG is 0x%x\n", chip->last_flag); 132 + 133 + /* brightness 0 means off-state */ 134 + if (!brightness) 135 + opmode = MODES_STASNDBY; 136 + 137 + switch (opmode) { 138 + case MODES_TORCH: 139 + ret = regmap_update_bits(chip->regmap, REG_I_CTRL, 140 + TORCH_I_MASK << TORCH_I_SHIFT, 141 + (brightness - 1) << TORCH_I_SHIFT); 142 + 143 + if (chip->torch_pin) 144 + opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT); 145 + break; 146 + 147 + case MODES_FLASH: 148 + ret = regmap_update_bits(chip->regmap, REG_I_CTRL, 149 + FLASH_I_MASK << FLASH_I_SHIFT, 150 + (brightness - 1) << FLASH_I_SHIFT); 151 + 152 + if (chip->strobe_pin) 153 + opmode |= (STROBE_PIN_EN_MASK << STROBE_PIN_EN_SHIFT); 154 + break; 155 + 156 + case MODES_INDIC: 157 + ret = regmap_update_bits(chip->regmap, REG_I_CTRL, 158 + TORCH_I_MASK << TORCH_I_SHIFT, 159 + (brightness - 1) << TORCH_I_SHIFT); 160 + break; 161 + 162 + case MODES_STASNDBY: 163 + 164 + break; 165 + 166 + default: 167 + return ret; 168 + } 169 + if (ret < 0) { 170 + dev_err(chip->dev, "Failed to write REG_I_CTRL Register\n"); 171 + goto out; 172 + } 173 + 174 + if (chip->tx_pin) 175 + opmode |= (TX_PIN_EN_MASK << TX_PIN_EN_SHIFT); 176 + 177 + ret = regmap_update_bits(chip->regmap, REG_ENABLE, 178 + MODE_BITS_MASK << MODE_BITS_SHIFT, 179 + opmode << MODE_BITS_SHIFT); 180 + out: 181 + return ret; 182 + } 183 + 184 + /* torch */ 185 + 186 + /* torch pin config for lm3642*/ 187 + static ssize_t lm3642_torch_pin_store(struct device *dev, 188 + struct device_attribute *devAttr, 189 + const char *buf, size_t size) 190 + { 191 + ssize_t ret; 192 + struct led_classdev *led_cdev = dev_get_drvdata(dev); 193 + struct lm3642_chip_data *chip = 194 + container_of(led_cdev, struct lm3642_chip_data, cdev_indicator); 195 + unsigned int state; 196 + 197 + ret = kstrtouint(buf, 10, &state); 198 + if (ret) 199 + goto out_strtoint; 200 + if (state != 0) 201 + state = 0x01 << TORCH_PIN_EN_SHIFT; 202 + 203 + chip->torch_pin = state; 204 + ret = regmap_update_bits(chip->regmap, REG_ENABLE, 205 + TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT, 206 + state); 207 + if (ret < 0) 208 + goto out; 209 + 210 + return size; 211 + out: 212 + dev_err(chip->dev, "%s:i2c access fail to register\n", __func__); 213 + return size; 214 + out_strtoint: 215 + dev_err(chip->dev, "%s: fail to change str to int\n", __func__); 216 + return size; 217 + } 218 + 219 + static DEVICE_ATTR(torch_pin, 0666, NULL, lm3642_torch_pin_store); 220 + 221 + static void lm3642_deferred_torch_brightness_set(struct work_struct *work) 222 + { 223 + struct lm3642_chip_data *chip = 224 + container_of(work, struct lm3642_chip_data, work_torch); 225 + 226 + mutex_lock(&chip->lock); 227 + lm3642_control(chip, chip->br_torch, MODES_TORCH); 228 + mutex_unlock(&chip->lock); 229 + } 230 + 231 + static void lm3642_torch_brightness_set(struct led_classdev *cdev, 232 + enum led_brightness brightness) 233 + { 234 + struct lm3642_chip_data *chip = 235 + container_of(cdev, struct lm3642_chip_data, cdev_torch); 236 + 237 + chip->br_torch = brightness; 238 + schedule_work(&chip->work_torch); 239 + } 240 + 241 + /* flash */ 242 + 243 + /* strobe pin config for lm3642*/ 244 + static ssize_t lm3642_strobe_pin_store(struct device *dev, 245 + struct device_attribute *devAttr, 246 + const char *buf, size_t size) 247 + { 248 + ssize_t ret; 249 + struct led_classdev *led_cdev = dev_get_drvdata(dev); 250 + struct lm3642_chip_data *chip = 251 + container_of(led_cdev, struct lm3642_chip_data, cdev_indicator); 252 + unsigned int state; 253 + 254 + ret = kstrtouint(buf, 10, &state); 255 + if (ret) 256 + goto out_strtoint; 257 + if (state != 0) 258 + state = 0x01 << STROBE_PIN_EN_SHIFT; 259 + 260 + chip->strobe_pin = state; 261 + ret = regmap_update_bits(chip->regmap, REG_ENABLE, 262 + STROBE_PIN_EN_MASK << STROBE_PIN_EN_SHIFT, 263 + state); 264 + if (ret < 0) 265 + goto out; 266 + 267 + return size; 268 + out: 269 + dev_err(chip->dev, "%s:i2c access fail to register\n", __func__); 270 + return size; 271 + out_strtoint: 272 + dev_err(chip->dev, "%s: fail to change str to int\n", __func__); 273 + return size; 274 + } 275 + 276 + static DEVICE_ATTR(strobe_pin, 0666, NULL, lm3642_strobe_pin_store); 277 + 278 + static void lm3642_deferred_strobe_brightness_set(struct work_struct *work) 279 + { 280 + struct lm3642_chip_data *chip = 281 + container_of(work, struct lm3642_chip_data, work_flash); 282 + 283 + mutex_lock(&chip->lock); 284 + lm3642_control(chip, chip->br_flash, MODES_FLASH); 285 + mutex_unlock(&chip->lock); 286 + } 287 + 288 + static void lm3642_strobe_brightness_set(struct led_classdev *cdev, 289 + enum led_brightness brightness) 290 + { 291 + struct lm3642_chip_data *chip = 292 + container_of(cdev, struct lm3642_chip_data, cdev_flash); 293 + 294 + chip->br_flash = brightness; 295 + schedule_work(&chip->work_flash); 296 + } 297 + 298 + /* indicator */ 299 + static void lm3642_deferred_indicator_brightness_set(struct work_struct *work) 300 + { 301 + struct lm3642_chip_data *chip = 302 + container_of(work, struct lm3642_chip_data, work_indicator); 303 + 304 + mutex_lock(&chip->lock); 305 + lm3642_control(chip, chip->br_indicator, MODES_INDIC); 306 + mutex_unlock(&chip->lock); 307 + } 308 + 309 + static void lm3642_indicator_brightness_set(struct led_classdev *cdev, 310 + enum led_brightness brightness) 311 + { 312 + struct lm3642_chip_data *chip = 313 + container_of(cdev, struct lm3642_chip_data, cdev_indicator); 314 + 315 + chip->br_indicator = brightness; 316 + schedule_work(&chip->work_indicator); 317 + } 318 + 319 + static const struct regmap_config lm3642_regmap = { 320 + .reg_bits = 8, 321 + .val_bits = 8, 322 + .max_register = REG_MAX, 323 + }; 324 + 325 + static int __devinit lm3642_probe(struct i2c_client *client, 326 + const struct i2c_device_id *id) 327 + { 328 + struct lm3642_platform_data *pdata = client->dev.platform_data; 329 + struct lm3642_chip_data *chip; 330 + 331 + int err; 332 + 333 + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 334 + dev_err(&client->dev, "i2c functionality check fail.\n"); 335 + return -EOPNOTSUPP; 336 + } 337 + 338 + if (pdata == NULL) { 339 + dev_err(&client->dev, "needs Platform Data.\n"); 340 + return -ENODATA; 341 + } 342 + 343 + chip = devm_kzalloc(&client->dev, 344 + sizeof(struct lm3642_chip_data), GFP_KERNEL); 345 + if (!chip) 346 + return -ENOMEM; 347 + 348 + chip->dev = &client->dev; 349 + chip->pdata = pdata; 350 + 351 + chip->tx_pin = pdata->tx_pin; 352 + chip->torch_pin = pdata->torch_pin; 353 + chip->strobe_pin = pdata->strobe_pin; 354 + 355 + chip->regmap = devm_regmap_init_i2c(client, &lm3642_regmap); 356 + if (IS_ERR(chip->regmap)) { 357 + err = PTR_ERR(chip->regmap); 358 + dev_err(&client->dev, "Failed to allocate register map: %d\n", 359 + err); 360 + return err; 361 + } 362 + 363 + mutex_init(&chip->lock); 364 + i2c_set_clientdata(client, chip); 365 + 366 + err = lm3642_chip_init(chip); 367 + if (err < 0) 368 + goto err_out; 369 + 370 + /* flash */ 371 + INIT_WORK(&chip->work_flash, lm3642_deferred_strobe_brightness_set); 372 + chip->cdev_flash.name = "flash"; 373 + chip->cdev_flash.max_brightness = 16; 374 + chip->cdev_flash.brightness_set = lm3642_strobe_brightness_set; 375 + err = led_classdev_register((struct device *) 376 + &client->dev, &chip->cdev_flash); 377 + if (err < 0) { 378 + dev_err(chip->dev, "failed to register flash\n"); 379 + goto err_out; 380 + } 381 + err = device_create_file(chip->cdev_flash.dev, &dev_attr_strobe_pin); 382 + if (err < 0) { 383 + dev_err(chip->dev, "failed to create strobe-pin file\n"); 384 + goto err_create_flash_pin_file; 385 + } 386 + 387 + /* torch */ 388 + INIT_WORK(&chip->work_torch, lm3642_deferred_torch_brightness_set); 389 + chip->cdev_torch.name = "torch"; 390 + chip->cdev_torch.max_brightness = 8; 391 + chip->cdev_torch.brightness_set = lm3642_torch_brightness_set; 392 + err = led_classdev_register((struct device *) 393 + &client->dev, &chip->cdev_torch); 394 + if (err < 0) { 395 + dev_err(chip->dev, "failed to register torch\n"); 396 + goto err_create_torch_file; 397 + } 398 + err = device_create_file(chip->cdev_torch.dev, &dev_attr_torch_pin); 399 + if (err < 0) { 400 + dev_err(chip->dev, "failed to create torch-pin file\n"); 401 + goto err_create_torch_pin_file; 402 + } 403 + 404 + /* indicator */ 405 + INIT_WORK(&chip->work_indicator, 406 + lm3642_deferred_indicator_brightness_set); 407 + chip->cdev_indicator.name = "indicator"; 408 + chip->cdev_indicator.max_brightness = 8; 409 + chip->cdev_indicator.brightness_set = lm3642_indicator_brightness_set; 410 + err = led_classdev_register((struct device *) 411 + &client->dev, &chip->cdev_indicator); 412 + if (err < 0) { 413 + dev_err(chip->dev, "failed to register indicator\n"); 414 + goto err_create_indicator_file; 415 + } 416 + 417 + dev_info(&client->dev, "LM3642 is initialized\n"); 418 + return 0; 419 + 420 + err_create_indicator_file: 421 + device_remove_file(chip->cdev_torch.dev, &dev_attr_torch_pin); 422 + err_create_torch_pin_file: 423 + led_classdev_unregister(&chip->cdev_torch); 424 + err_create_torch_file: 425 + device_remove_file(chip->cdev_flash.dev, &dev_attr_strobe_pin); 426 + err_create_flash_pin_file: 427 + led_classdev_unregister(&chip->cdev_flash); 428 + err_out: 429 + return err; 430 + } 431 + 432 + static int __devexit lm3642_remove(struct i2c_client *client) 433 + { 434 + struct lm3642_chip_data *chip = i2c_get_clientdata(client); 435 + 436 + led_classdev_unregister(&chip->cdev_indicator); 437 + flush_work(&chip->work_indicator); 438 + device_remove_file(chip->cdev_torch.dev, &dev_attr_torch_pin); 439 + led_classdev_unregister(&chip->cdev_torch); 440 + flush_work(&chip->work_torch); 441 + device_remove_file(chip->cdev_flash.dev, &dev_attr_strobe_pin); 442 + led_classdev_unregister(&chip->cdev_flash); 443 + flush_work(&chip->work_flash); 444 + regmap_write(chip->regmap, REG_ENABLE, 0); 445 + return 0; 446 + } 447 + 448 + static const struct i2c_device_id lm3642_id[] = { 449 + {LM3642_NAME, 0}, 450 + {} 451 + }; 452 + 453 + MODULE_DEVICE_TABLE(i2c, lm3642_id); 454 + 455 + static struct i2c_driver lm3642_i2c_driver = { 456 + .driver = { 457 + .name = LM3642_NAME, 458 + .owner = THIS_MODULE, 459 + .pm = NULL, 460 + }, 461 + .probe = lm3642_probe, 462 + .remove = __devexit_p(lm3642_remove), 463 + .id_table = lm3642_id, 464 + }; 465 + 466 + module_i2c_driver(lm3642_i2c_driver); 467 + 468 + MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3642"); 469 + MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>"); 470 + MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>"); 471 + MODULE_LICENSE("GPL v2");
+38
include/linux/platform_data/leds-lm3642.h
··· 1 + /* 2 + * Copyright (C) 2012 Texas Instruments 3 + * 4 + * License Terms: GNU General Public License v2 5 + * 6 + * Simple driver for Texas Instruments LM3642 LED driver chip 7 + * 8 + * Author: G.Shark Jeong <gshark.jeong@gmail.com> 9 + * Daniel Jeong <daniel.jeong@ti.com> 10 + */ 11 + 12 + #ifndef __LINUX_LM3642_H 13 + #define __LINUX_LM3642_H 14 + 15 + #define LM3642_NAME "leds-lm3642" 16 + 17 + enum lm3642_torch_pin_enable { 18 + LM3642_TORCH_PIN_DISABLE = 0x00, 19 + LM3642_TORCH_PIN_ENABLE = 0x10, 20 + }; 21 + 22 + enum lm3642_strobe_pin_enable { 23 + LM3642_STROBE_PIN_DISABLE = 0x00, 24 + LM3642_STROBE_PIN_ENABLE = 0x20, 25 + }; 26 + 27 + enum lm3642_tx_pin_enable { 28 + LM3642_TX_PIN_DISABLE = 0x00, 29 + LM3642_TX_PIN_ENABLE = 0x40, 30 + }; 31 + 32 + struct lm3642_platform_data { 33 + enum lm3642_torch_pin_enable torch_pin; 34 + enum lm3642_strobe_pin_enable strobe_pin; 35 + enum lm3642_tx_pin_enable tx_pin; 36 + }; 37 + 38 + #endif /* __LINUX_LM3642_H */