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

Configure Feed

Select the types of activity you want to include in your feed.

at v4.14-rc5 489 lines 13 kB view raw
1/* 2* Simple driver for Texas Instruments LM3630A Backlight 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/backlight.h> 14#include <linux/err.h> 15#include <linux/delay.h> 16#include <linux/uaccess.h> 17#include <linux/interrupt.h> 18#include <linux/regmap.h> 19#include <linux/pwm.h> 20#include <linux/platform_data/lm3630a_bl.h> 21 22#define REG_CTRL 0x00 23#define REG_BOOST 0x02 24#define REG_CONFIG 0x01 25#define REG_BRT_A 0x03 26#define REG_BRT_B 0x04 27#define REG_I_A 0x05 28#define REG_I_B 0x06 29#define REG_INT_STATUS 0x09 30#define REG_INT_EN 0x0A 31#define REG_FAULT 0x0B 32#define REG_PWM_OUTLOW 0x12 33#define REG_PWM_OUTHIGH 0x13 34#define REG_FILTER_STRENGTH 0x50 35#define REG_MAX 0x50 36 37#define INT_DEBOUNCE_MSEC 10 38struct lm3630a_chip { 39 struct device *dev; 40 struct delayed_work work; 41 42 int irq; 43 struct workqueue_struct *irqthread; 44 struct lm3630a_platform_data *pdata; 45 struct backlight_device *bleda; 46 struct backlight_device *bledb; 47 struct regmap *regmap; 48 struct pwm_device *pwmd; 49}; 50 51/* i2c access */ 52static int lm3630a_read(struct lm3630a_chip *pchip, unsigned int reg) 53{ 54 int rval; 55 unsigned int reg_val; 56 57 rval = regmap_read(pchip->regmap, reg, &reg_val); 58 if (rval < 0) 59 return rval; 60 return reg_val & 0xFF; 61} 62 63static int lm3630a_write(struct lm3630a_chip *pchip, 64 unsigned int reg, unsigned int data) 65{ 66 return regmap_write(pchip->regmap, reg, data); 67} 68 69static int lm3630a_update(struct lm3630a_chip *pchip, 70 unsigned int reg, unsigned int mask, 71 unsigned int data) 72{ 73 return regmap_update_bits(pchip->regmap, reg, mask, data); 74} 75 76/* initialize chip */ 77static int lm3630a_chip_init(struct lm3630a_chip *pchip) 78{ 79 int rval; 80 struct lm3630a_platform_data *pdata = pchip->pdata; 81 82 usleep_range(1000, 2000); 83 /* set Filter Strength Register */ 84 rval = lm3630a_write(pchip, REG_FILTER_STRENGTH, 0x03); 85 /* set Cofig. register */ 86 rval |= lm3630a_update(pchip, REG_CONFIG, 0x07, pdata->pwm_ctrl); 87 /* set boost control */ 88 rval |= lm3630a_write(pchip, REG_BOOST, 0x38); 89 /* set current A */ 90 rval |= lm3630a_update(pchip, REG_I_A, 0x1F, 0x1F); 91 /* set current B */ 92 rval |= lm3630a_write(pchip, REG_I_B, 0x1F); 93 /* set control */ 94 rval |= lm3630a_update(pchip, REG_CTRL, 0x14, pdata->leda_ctrl); 95 rval |= lm3630a_update(pchip, REG_CTRL, 0x0B, pdata->ledb_ctrl); 96 usleep_range(1000, 2000); 97 /* set brightness A and B */ 98 rval |= lm3630a_write(pchip, REG_BRT_A, pdata->leda_init_brt); 99 rval |= lm3630a_write(pchip, REG_BRT_B, pdata->ledb_init_brt); 100 101 if (rval < 0) 102 dev_err(pchip->dev, "i2c failed to access register\n"); 103 return rval; 104} 105 106/* interrupt handling */ 107static void lm3630a_delayed_func(struct work_struct *work) 108{ 109 int rval; 110 struct lm3630a_chip *pchip; 111 112 pchip = container_of(work, struct lm3630a_chip, work.work); 113 114 rval = lm3630a_read(pchip, REG_INT_STATUS); 115 if (rval < 0) { 116 dev_err(pchip->dev, 117 "i2c failed to access REG_INT_STATUS Register\n"); 118 return; 119 } 120 121 dev_info(pchip->dev, "REG_INT_STATUS Register is 0x%x\n", rval); 122} 123 124static irqreturn_t lm3630a_isr_func(int irq, void *chip) 125{ 126 int rval; 127 struct lm3630a_chip *pchip = chip; 128 unsigned long delay = msecs_to_jiffies(INT_DEBOUNCE_MSEC); 129 130 queue_delayed_work(pchip->irqthread, &pchip->work, delay); 131 132 rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); 133 if (rval < 0) { 134 dev_err(pchip->dev, "i2c failed to access register\n"); 135 return IRQ_NONE; 136 } 137 return IRQ_HANDLED; 138} 139 140static int lm3630a_intr_config(struct lm3630a_chip *pchip) 141{ 142 int rval; 143 144 rval = lm3630a_write(pchip, REG_INT_EN, 0x87); 145 if (rval < 0) 146 return rval; 147 148 INIT_DELAYED_WORK(&pchip->work, lm3630a_delayed_func); 149 pchip->irqthread = create_singlethread_workqueue("lm3630a-irqthd"); 150 if (!pchip->irqthread) { 151 dev_err(pchip->dev, "create irq thread fail\n"); 152 return -ENOMEM; 153 } 154 if (request_threaded_irq 155 (pchip->irq, NULL, lm3630a_isr_func, 156 IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lm3630a_irq", pchip)) { 157 dev_err(pchip->dev, "request threaded irq fail\n"); 158 destroy_workqueue(pchip->irqthread); 159 return -ENOMEM; 160 } 161 return rval; 162} 163 164static void lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max) 165{ 166 unsigned int period = pchip->pdata->pwm_period; 167 unsigned int duty = br * period / br_max; 168 169 pwm_config(pchip->pwmd, duty, period); 170 if (duty) 171 pwm_enable(pchip->pwmd); 172 else 173 pwm_disable(pchip->pwmd); 174} 175 176/* update and get brightness */ 177static int lm3630a_bank_a_update_status(struct backlight_device *bl) 178{ 179 int ret; 180 struct lm3630a_chip *pchip = bl_get_data(bl); 181 enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; 182 183 /* pwm control */ 184 if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) { 185 lm3630a_pwm_ctrl(pchip, bl->props.brightness, 186 bl->props.max_brightness); 187 return bl->props.brightness; 188 } 189 190 /* disable sleep */ 191 ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); 192 if (ret < 0) 193 goto out_i2c_err; 194 usleep_range(1000, 2000); 195 /* minimum brightness is 0x04 */ 196 ret = lm3630a_write(pchip, REG_BRT_A, bl->props.brightness); 197 if (bl->props.brightness < 0x4) 198 ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDA_ENABLE, 0); 199 else 200 ret |= lm3630a_update(pchip, REG_CTRL, 201 LM3630A_LEDA_ENABLE, LM3630A_LEDA_ENABLE); 202 if (ret < 0) 203 goto out_i2c_err; 204 return bl->props.brightness; 205 206out_i2c_err: 207 dev_err(pchip->dev, "i2c failed to access\n"); 208 return bl->props.brightness; 209} 210 211static int lm3630a_bank_a_get_brightness(struct backlight_device *bl) 212{ 213 int brightness, rval; 214 struct lm3630a_chip *pchip = bl_get_data(bl); 215 enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; 216 217 if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) { 218 rval = lm3630a_read(pchip, REG_PWM_OUTHIGH); 219 if (rval < 0) 220 goto out_i2c_err; 221 brightness = (rval & 0x01) << 8; 222 rval = lm3630a_read(pchip, REG_PWM_OUTLOW); 223 if (rval < 0) 224 goto out_i2c_err; 225 brightness |= rval; 226 goto out; 227 } 228 229 /* disable sleep */ 230 rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); 231 if (rval < 0) 232 goto out_i2c_err; 233 usleep_range(1000, 2000); 234 rval = lm3630a_read(pchip, REG_BRT_A); 235 if (rval < 0) 236 goto out_i2c_err; 237 brightness = rval; 238 239out: 240 bl->props.brightness = brightness; 241 return bl->props.brightness; 242out_i2c_err: 243 dev_err(pchip->dev, "i2c failed to access register\n"); 244 return 0; 245} 246 247static const struct backlight_ops lm3630a_bank_a_ops = { 248 .options = BL_CORE_SUSPENDRESUME, 249 .update_status = lm3630a_bank_a_update_status, 250 .get_brightness = lm3630a_bank_a_get_brightness, 251}; 252 253/* update and get brightness */ 254static int lm3630a_bank_b_update_status(struct backlight_device *bl) 255{ 256 int ret; 257 struct lm3630a_chip *pchip = bl_get_data(bl); 258 enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; 259 260 /* pwm control */ 261 if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) { 262 lm3630a_pwm_ctrl(pchip, bl->props.brightness, 263 bl->props.max_brightness); 264 return bl->props.brightness; 265 } 266 267 /* disable sleep */ 268 ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); 269 if (ret < 0) 270 goto out_i2c_err; 271 usleep_range(1000, 2000); 272 /* minimum brightness is 0x04 */ 273 ret = lm3630a_write(pchip, REG_BRT_B, bl->props.brightness); 274 if (bl->props.brightness < 0x4) 275 ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDB_ENABLE, 0); 276 else 277 ret |= lm3630a_update(pchip, REG_CTRL, 278 LM3630A_LEDB_ENABLE, LM3630A_LEDB_ENABLE); 279 if (ret < 0) 280 goto out_i2c_err; 281 return bl->props.brightness; 282 283out_i2c_err: 284 dev_err(pchip->dev, "i2c failed to access REG_CTRL\n"); 285 return bl->props.brightness; 286} 287 288static int lm3630a_bank_b_get_brightness(struct backlight_device *bl) 289{ 290 int brightness, rval; 291 struct lm3630a_chip *pchip = bl_get_data(bl); 292 enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; 293 294 if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) { 295 rval = lm3630a_read(pchip, REG_PWM_OUTHIGH); 296 if (rval < 0) 297 goto out_i2c_err; 298 brightness = (rval & 0x01) << 8; 299 rval = lm3630a_read(pchip, REG_PWM_OUTLOW); 300 if (rval < 0) 301 goto out_i2c_err; 302 brightness |= rval; 303 goto out; 304 } 305 306 /* disable sleep */ 307 rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); 308 if (rval < 0) 309 goto out_i2c_err; 310 usleep_range(1000, 2000); 311 rval = lm3630a_read(pchip, REG_BRT_B); 312 if (rval < 0) 313 goto out_i2c_err; 314 brightness = rval; 315 316out: 317 bl->props.brightness = brightness; 318 return bl->props.brightness; 319out_i2c_err: 320 dev_err(pchip->dev, "i2c failed to access register\n"); 321 return 0; 322} 323 324static const struct backlight_ops lm3630a_bank_b_ops = { 325 .options = BL_CORE_SUSPENDRESUME, 326 .update_status = lm3630a_bank_b_update_status, 327 .get_brightness = lm3630a_bank_b_get_brightness, 328}; 329 330static int lm3630a_backlight_register(struct lm3630a_chip *pchip) 331{ 332 struct backlight_properties props; 333 struct lm3630a_platform_data *pdata = pchip->pdata; 334 335 props.type = BACKLIGHT_RAW; 336 if (pdata->leda_ctrl != LM3630A_LEDA_DISABLE) { 337 props.brightness = pdata->leda_init_brt; 338 props.max_brightness = pdata->leda_max_brt; 339 pchip->bleda = 340 devm_backlight_device_register(pchip->dev, "lm3630a_leda", 341 pchip->dev, pchip, 342 &lm3630a_bank_a_ops, &props); 343 if (IS_ERR(pchip->bleda)) 344 return PTR_ERR(pchip->bleda); 345 } 346 347 if ((pdata->ledb_ctrl != LM3630A_LEDB_DISABLE) && 348 (pdata->ledb_ctrl != LM3630A_LEDB_ON_A)) { 349 props.brightness = pdata->ledb_init_brt; 350 props.max_brightness = pdata->ledb_max_brt; 351 pchip->bledb = 352 devm_backlight_device_register(pchip->dev, "lm3630a_ledb", 353 pchip->dev, pchip, 354 &lm3630a_bank_b_ops, &props); 355 if (IS_ERR(pchip->bledb)) 356 return PTR_ERR(pchip->bledb); 357 } 358 return 0; 359} 360 361static const struct regmap_config lm3630a_regmap = { 362 .reg_bits = 8, 363 .val_bits = 8, 364 .max_register = REG_MAX, 365}; 366 367static int lm3630a_probe(struct i2c_client *client, 368 const struct i2c_device_id *id) 369{ 370 struct lm3630a_platform_data *pdata = dev_get_platdata(&client->dev); 371 struct lm3630a_chip *pchip; 372 int rval; 373 374 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 375 dev_err(&client->dev, "fail : i2c functionality check\n"); 376 return -EOPNOTSUPP; 377 } 378 379 pchip = devm_kzalloc(&client->dev, sizeof(struct lm3630a_chip), 380 GFP_KERNEL); 381 if (!pchip) 382 return -ENOMEM; 383 pchip->dev = &client->dev; 384 385 pchip->regmap = devm_regmap_init_i2c(client, &lm3630a_regmap); 386 if (IS_ERR(pchip->regmap)) { 387 rval = PTR_ERR(pchip->regmap); 388 dev_err(&client->dev, "fail : allocate reg. map: %d\n", rval); 389 return rval; 390 } 391 392 i2c_set_clientdata(client, pchip); 393 if (pdata == NULL) { 394 pdata = devm_kzalloc(pchip->dev, 395 sizeof(struct lm3630a_platform_data), 396 GFP_KERNEL); 397 if (pdata == NULL) 398 return -ENOMEM; 399 /* default values */ 400 pdata->leda_ctrl = LM3630A_LEDA_ENABLE; 401 pdata->ledb_ctrl = LM3630A_LEDB_ENABLE; 402 pdata->leda_max_brt = LM3630A_MAX_BRIGHTNESS; 403 pdata->ledb_max_brt = LM3630A_MAX_BRIGHTNESS; 404 pdata->leda_init_brt = LM3630A_MAX_BRIGHTNESS; 405 pdata->ledb_init_brt = LM3630A_MAX_BRIGHTNESS; 406 } 407 pchip->pdata = pdata; 408 409 /* chip initialize */ 410 rval = lm3630a_chip_init(pchip); 411 if (rval < 0) { 412 dev_err(&client->dev, "fail : init chip\n"); 413 return rval; 414 } 415 /* backlight register */ 416 rval = lm3630a_backlight_register(pchip); 417 if (rval < 0) { 418 dev_err(&client->dev, "fail : backlight register.\n"); 419 return rval; 420 } 421 /* pwm */ 422 if (pdata->pwm_ctrl != LM3630A_PWM_DISABLE) { 423 pchip->pwmd = devm_pwm_get(pchip->dev, "lm3630a-pwm"); 424 if (IS_ERR(pchip->pwmd)) { 425 dev_err(&client->dev, "fail : get pwm device\n"); 426 return PTR_ERR(pchip->pwmd); 427 } 428 429 /* 430 * FIXME: pwm_apply_args() should be removed when switching to 431 * the atomic PWM API. 432 */ 433 pwm_apply_args(pchip->pwmd); 434 } 435 436 /* interrupt enable : irq 0 is not allowed */ 437 pchip->irq = client->irq; 438 if (pchip->irq) { 439 rval = lm3630a_intr_config(pchip); 440 if (rval < 0) 441 return rval; 442 } 443 dev_info(&client->dev, "LM3630A backlight register OK.\n"); 444 return 0; 445} 446 447static int lm3630a_remove(struct i2c_client *client) 448{ 449 int rval; 450 struct lm3630a_chip *pchip = i2c_get_clientdata(client); 451 452 rval = lm3630a_write(pchip, REG_BRT_A, 0); 453 if (rval < 0) 454 dev_err(pchip->dev, "i2c failed to access register\n"); 455 456 rval = lm3630a_write(pchip, REG_BRT_B, 0); 457 if (rval < 0) 458 dev_err(pchip->dev, "i2c failed to access register\n"); 459 460 if (pchip->irq) { 461 free_irq(pchip->irq, pchip); 462 flush_workqueue(pchip->irqthread); 463 destroy_workqueue(pchip->irqthread); 464 } 465 return 0; 466} 467 468static const struct i2c_device_id lm3630a_id[] = { 469 {LM3630A_NAME, 0}, 470 {} 471}; 472 473MODULE_DEVICE_TABLE(i2c, lm3630a_id); 474 475static struct i2c_driver lm3630a_i2c_driver = { 476 .driver = { 477 .name = LM3630A_NAME, 478 }, 479 .probe = lm3630a_probe, 480 .remove = lm3630a_remove, 481 .id_table = lm3630a_id, 482}; 483 484module_i2c_driver(lm3630a_i2c_driver); 485 486MODULE_DESCRIPTION("Texas Instruments Backlight driver for LM3630A"); 487MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>"); 488MODULE_AUTHOR("LDD MLP <ldd-mlp@list.ti.com>"); 489MODULE_LICENSE("GPL v2");