1 /* 2 * Simple driver for Texas Instruments LM3639 Backlight + Flash LED 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/slab.h> 12 #include <linux/i2c.h> 13 #include <linux/leds.h> 14 #include <linux/backlight.h> 15 #include <linux/err.h> 16 #include <linux/delay.h> 17 #include <linux/uaccess.h> 18 #include <linux/interrupt.h> 19 #include <linux/regmap.h> 20 #include <linux/platform_data/lm3639_bl.h> 21 22 #define REG_DEV_ID 0x00 23 #define REG_CHECKSUM 0x01 24 #define REG_BL_CONF_1 0x02 25 #define REG_BL_CONF_2 0x03 26 #define REG_BL_CONF_3 0x04 27 #define REG_BL_CONF_4 0x05 28 #define REG_FL_CONF_1 0x06 29 #define REG_FL_CONF_2 0x07 30 #define REG_FL_CONF_3 0x08 31 #define REG_IO_CTRL 0x09 32 #define REG_ENABLE 0x0A 33 #define REG_FLAG 0x0B 34 #define REG_MAX REG_FLAG 35 36 struct lm3639_chip_data { 37 struct device *dev; 38 struct lm3639_platform_data *pdata; 39 40 struct backlight_device *bled; 41 struct led_classdev cdev_flash; 42 struct led_classdev cdev_torch; 43 struct regmap *regmap; 44 45 unsigned int bled_mode; 46 unsigned int bled_map; 47 unsigned int last_flag; 48 }; 49 50 /* initialize chip */ 51 static int lm3639_chip_init(struct lm3639_chip_data *pchip) 52 { 53 int ret; 54 unsigned int reg_val; 55 struct lm3639_platform_data *pdata = pchip->pdata; 56 57 /* input pins config. */ 58 ret = 59 regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x08, 60 pdata->pin_pwm); 61 if (ret < 0) 62 goto out; 63 64 reg_val = (pdata->pin_pwm & 0x40) | pdata->pin_strobe | pdata->pin_tx; 65 ret = regmap_update_bits(pchip->regmap, REG_IO_CTRL, 0x7C, reg_val); 66 if (ret < 0) 67 goto out; 68 69 /* init brightness */ 70 ret = regmap_write(pchip->regmap, REG_BL_CONF_4, pdata->init_brt_led); 71 if (ret < 0) 72 goto out; 73 74 ret = regmap_write(pchip->regmap, REG_BL_CONF_3, pdata->init_brt_led); 75 if (ret < 0) 76 goto out; 77 78 /* output pins config. */ 79 if (!pdata->init_brt_led) 80 reg_val = pdata->fled_pins | pdata->bled_pins; 81 else 82 reg_val = pdata->fled_pins | pdata->bled_pins | 0x01; 83 84 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x79, reg_val); 85 if (ret < 0) 86 goto out; 87 88 return ret; 89 out: 90 dev_err(pchip->dev, "i2c failed to access register\n"); 91 return ret; 92 } 93 94 /* update and get brightness */ 95 static int lm3639_bled_update_status(struct backlight_device *bl) 96 { 97 int ret; 98 unsigned int reg_val; 99 struct lm3639_chip_data *pchip = bl_get_data(bl); 100 struct lm3639_platform_data *pdata = pchip->pdata; 101 102 ret = regmap_read(pchip->regmap, REG_FLAG, ®_val); 103 if (ret < 0) 104 goto out; 105 106 if (reg_val != 0) 107 dev_info(pchip->dev, "last flag is 0x%x\n", reg_val); 108 109 /* pwm control */ 110 if (pdata->pin_pwm) { 111 if (pdata->pwm_set_intensity) 112 pdata->pwm_set_intensity(bl->props.brightness, 113 pdata->max_brt_led); 114 else 115 dev_err(pchip->dev, 116 "No pwm control func. in plat-data\n"); 117 return bl->props.brightness; 118 } 119 120 /* i2c control and set brigtness */ 121 ret = regmap_write(pchip->regmap, REG_BL_CONF_4, bl->props.brightness); 122 if (ret < 0) 123 goto out; 124 ret = regmap_write(pchip->regmap, REG_BL_CONF_3, bl->props.brightness); 125 if (ret < 0) 126 goto out; 127 128 if (!bl->props.brightness) 129 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x01, 0x00); 130 else 131 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x01, 0x01); 132 if (ret < 0) 133 goto out; 134 135 return bl->props.brightness; 136 out: 137 dev_err(pchip->dev, "i2c failed to access registers\n"); 138 return bl->props.brightness; 139 } 140 141 static int lm3639_bled_get_brightness(struct backlight_device *bl) 142 { 143 int ret; 144 unsigned int reg_val; 145 struct lm3639_chip_data *pchip = bl_get_data(bl); 146 struct lm3639_platform_data *pdata = pchip->pdata; 147 148 if (pdata->pin_pwm) { 149 if (pdata->pwm_get_intensity) 150 bl->props.brightness = pdata->pwm_get_intensity(); 151 else 152 dev_err(pchip->dev, 153 "No pwm control func. in plat-data\n"); 154 return bl->props.brightness; 155 } 156 157 ret = regmap_read(pchip->regmap, REG_BL_CONF_1, ®_val); 158 if (ret < 0) 159 goto out; 160 if (reg_val & 0x10) 161 ret = regmap_read(pchip->regmap, REG_BL_CONF_4, ®_val); 162 else 163 ret = regmap_read(pchip->regmap, REG_BL_CONF_3, ®_val); 164 if (ret < 0) 165 goto out; 166 bl->props.brightness = reg_val; 167 168 return bl->props.brightness; 169 out: 170 dev_err(pchip->dev, "i2c failed to access register\n"); 171 return bl->props.brightness; 172 } 173 174 static const struct backlight_ops lm3639_bled_ops = { 175 .options = BL_CORE_SUSPENDRESUME, 176 .update_status = lm3639_bled_update_status, 177 .get_brightness = lm3639_bled_get_brightness, 178 }; 179 180 /* backlight mapping mode */ 181 static ssize_t lm3639_bled_mode_store(struct device *dev, 182 struct device_attribute *devAttr, 183 const char *buf, size_t size) 184 { 185 ssize_t ret; 186 struct lm3639_chip_data *pchip = dev_get_drvdata(dev); 187 unsigned int state; 188 189 ret = kstrtouint(buf, 10, &state); 190 if (ret) 191 goto out_input; 192 193 if (!state) 194 ret = 195 regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x10, 196 0x00); 197 else 198 ret = 199 regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x10, 200 0x10); 201 202 if (ret < 0) 203 goto out; 204 205 return size; 206 207 out: 208 dev_err(pchip->dev, "%s:i2c access fail to register\n", __func__); 209 return ret; 210 211 out_input: 212 dev_err(pchip->dev, "%s:input conversion fail\n", __func__); 213 return ret; 214 215 } 216 217 static DEVICE_ATTR(bled_mode, S_IWUSR, NULL, lm3639_bled_mode_store); 218 219 /* torch */ 220 static void lm3639_torch_brightness_set(struct led_classdev *cdev, 221 enum led_brightness brightness) 222 { 223 int ret; 224 unsigned int reg_val; 225 struct lm3639_chip_data *pchip; 226 227 pchip = container_of(cdev, struct lm3639_chip_data, cdev_torch); 228 229 ret = regmap_read(pchip->regmap, REG_FLAG, ®_val); 230 if (ret < 0) 231 goto out; 232 if (reg_val != 0) 233 dev_info(pchip->dev, "last flag is 0x%x\n", reg_val); 234 235 /* brightness 0 means off state */ 236 if (!brightness) { 237 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x00); 238 if (ret < 0) 239 goto out; 240 return; 241 } 242 243 ret = regmap_update_bits(pchip->regmap, 244 REG_FL_CONF_1, 0x70, (brightness - 1) << 4); 245 if (ret < 0) 246 goto out; 247 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x02); 248 if (ret < 0) 249 goto out; 250 251 return; 252 out: 253 dev_err(pchip->dev, "i2c failed to access register\n"); 254 return; 255 } 256 257 /* flash */ 258 static void lm3639_flash_brightness_set(struct led_classdev *cdev, 259 enum led_brightness brightness) 260 { 261 int ret; 262 unsigned int reg_val; 263 struct lm3639_chip_data *pchip; 264 265 pchip = container_of(cdev, struct lm3639_chip_data, cdev_flash); 266 267 ret = regmap_read(pchip->regmap, REG_FLAG, ®_val); 268 if (ret < 0) 269 goto out; 270 if (reg_val != 0) 271 dev_info(pchip->dev, "last flag is 0x%x\n", reg_val); 272 273 /* torch off before flash control */ 274 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x00); 275 if (ret < 0) 276 goto out; 277 278 /* brightness 0 means off state */ 279 if (!brightness) 280 return; 281 282 ret = regmap_update_bits(pchip->regmap, 283 REG_FL_CONF_1, 0x0F, brightness - 1); 284 if (ret < 0) 285 goto out; 286 ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x06); 287 if (ret < 0) 288 goto out; 289 290 return; 291 out: 292 dev_err(pchip->dev, "i2c failed to access register\n"); 293 return; 294 } 295 296 static const struct regmap_config lm3639_regmap = { 297 .reg_bits = 8, 298 .val_bits = 8, 299 .max_register = REG_MAX, 300 }; 301 302 static int lm3639_probe(struct i2c_client *client, 303 const struct i2c_device_id *id) 304 { 305 int ret; 306 struct lm3639_chip_data *pchip; 307 struct lm3639_platform_data *pdata = client->dev.platform_data; 308 struct backlight_properties props; 309 310 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 311 dev_err(&client->dev, "i2c functionality check fail.\n"); 312 return -EOPNOTSUPP; 313 } 314 315 if (pdata == NULL) { 316 dev_err(&client->dev, "Needs Platform Data.\n"); 317 return -ENODATA; 318 } 319 320 pchip = devm_kzalloc(&client->dev, 321 sizeof(struct lm3639_chip_data), GFP_KERNEL); 322 if (!pchip) 323 return -ENOMEM; 324 325 pchip->pdata = pdata; 326 pchip->dev = &client->dev; 327 328 pchip->regmap = devm_regmap_init_i2c(client, &lm3639_regmap); 329 if (IS_ERR(pchip->regmap)) { 330 ret = PTR_ERR(pchip->regmap); 331 dev_err(&client->dev, "fail : allocate register map: %d\n", 332 ret); 333 return ret; 334 } 335 i2c_set_clientdata(client, pchip); 336 337 /* chip initialize */ 338 ret = lm3639_chip_init(pchip); 339 if (ret < 0) { 340 dev_err(&client->dev, "fail : chip init\n"); 341 goto err_out; 342 } 343 344 /* backlight */ 345 props.type = BACKLIGHT_RAW; 346 props.brightness = pdata->init_brt_led; 347 props.max_brightness = pdata->max_brt_led; 348 pchip->bled = 349 backlight_device_register("lm3639_bled", pchip->dev, pchip, 350 &lm3639_bled_ops, &props); 351 if (IS_ERR(pchip->bled)) { 352 dev_err(&client->dev, "fail : backlight register\n"); 353 ret = -EIO; 354 goto err_out; 355 } 356 357 ret = device_create_file(&(pchip->bled->dev), &dev_attr_bled_mode); 358 if (ret < 0) { 359 dev_err(&client->dev, "failed : add sysfs entries\n"); 360 ret = -EIO; 361 goto err_bled_mode; 362 } 363 364 /* flash */ 365 pchip->cdev_flash.name = "lm3639_flash"; 366 pchip->cdev_flash.max_brightness = 16; 367 pchip->cdev_flash.brightness_set = lm3639_flash_brightness_set; 368 ret = led_classdev_register((struct device *) 369 &client->dev, &pchip->cdev_flash); 370 if (ret < 0) { 371 dev_err(&client->dev, "fail : flash register\n"); 372 ret = -EIO; 373 goto err_flash; 374 } 375 376 /* torch */ 377 pchip->cdev_torch.name = "lm3639_torch"; 378 pchip->cdev_torch.max_brightness = 8; 379 pchip->cdev_torch.brightness_set = lm3639_torch_brightness_set; 380 ret = led_classdev_register((struct device *) 381 &client->dev, &pchip->cdev_torch); 382 if (ret < 0) { 383 dev_err(&client->dev, "fail : torch register\n"); 384 ret = -EIO; 385 goto err_torch; 386 } 387 388 return 0; 389 390 err_torch: 391 led_classdev_unregister(&pchip->cdev_flash); 392 err_flash: 393 device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode); 394 err_bled_mode: 395 backlight_device_unregister(pchip->bled); 396 err_out: 397 return ret; 398 } 399 400 static int lm3639_remove(struct i2c_client *client) 401 { 402 struct lm3639_chip_data *pchip = i2c_get_clientdata(client); 403 404 regmap_write(pchip->regmap, REG_ENABLE, 0x00); 405 406 if (&pchip->cdev_torch) 407 led_classdev_unregister(&pchip->cdev_torch); 408 if (&pchip->cdev_flash) 409 led_classdev_unregister(&pchip->cdev_flash); 410 if (pchip->bled) { 411 device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode); 412 backlight_device_unregister(pchip->bled); 413 } 414 return 0; 415 } 416 417 static const struct i2c_device_id lm3639_id[] = { 418 {LM3639_NAME, 0}, 419 {} 420 }; 421 422 MODULE_DEVICE_TABLE(i2c, lm3639_id); 423 static struct i2c_driver lm3639_i2c_driver = { 424 .driver = { 425 .name = LM3639_NAME, 426 }, 427 .probe = lm3639_probe, 428 .remove = lm3639_remove, 429 .id_table = lm3639_id, 430 }; 431 432 module_i2c_driver(lm3639_i2c_driver); 433 434 MODULE_DESCRIPTION("Texas Instruments Backlight+Flash LED driver for LM3639"); 435 MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>"); 436 MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>"); 437 MODULE_LICENSE("GPL v2"); 438