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