628 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3* Simple driver for Texas Instruments LM3630A Backlight driver chip4* Copyright (C) 2012 Texas Instruments5*/6#include <linux/module.h>7#include <linux/slab.h>8#include <linux/i2c.h>9#include <linux/backlight.h>10#include <linux/err.h>11#include <linux/delay.h>12#include <linux/uaccess.h>13#include <linux/interrupt.h>14#include <linux/regmap.h>15#include <linux/gpio/consumer.h>16#include <linux/pwm.h>17#include <linux/platform_data/lm3630a_bl.h>18 19#define REG_CTRL 0x0020#define REG_BOOST 0x0221#define REG_CONFIG 0x0122#define REG_BRT_A 0x0323#define REG_BRT_B 0x0424#define REG_I_A 0x0525#define REG_I_B 0x0626#define REG_INT_STATUS 0x0927#define REG_INT_EN 0x0A28#define REG_FAULT 0x0B29#define REG_PWM_OUTLOW 0x1230#define REG_PWM_OUTHIGH 0x1331#define REG_FILTER_STRENGTH 0x5032#define REG_MAX 0x5033 34#define INT_DEBOUNCE_MSEC 1035 36#define LM3630A_BANK_0 037#define LM3630A_BANK_1 138 39#define LM3630A_NUM_SINKS 240#define LM3630A_SINK_0 041#define LM3630A_SINK_1 142 43struct lm3630a_chip {44 struct device *dev;45 struct delayed_work work;46 47 int irq;48 struct workqueue_struct *irqthread;49 struct lm3630a_platform_data *pdata;50 struct backlight_device *bleda;51 struct backlight_device *bledb;52 struct gpio_desc *enable_gpio;53 struct regmap *regmap;54 struct pwm_device *pwmd;55 struct pwm_state pwmd_state;56};57 58/* i2c access */59static int lm3630a_read(struct lm3630a_chip *pchip, unsigned int reg)60{61 int rval;62 unsigned int reg_val;63 64 rval = regmap_read(pchip->regmap, reg, ®_val);65 if (rval < 0)66 return rval;67 return reg_val & 0xFF;68}69 70static int lm3630a_write(struct lm3630a_chip *pchip,71 unsigned int reg, unsigned int data)72{73 return regmap_write(pchip->regmap, reg, data);74}75 76static int lm3630a_update(struct lm3630a_chip *pchip,77 unsigned int reg, unsigned int mask,78 unsigned int data)79{80 return regmap_update_bits(pchip->regmap, reg, mask, data);81}82 83/* initialize chip */84static int lm3630a_chip_init(struct lm3630a_chip *pchip)85{86 int rval;87 struct lm3630a_platform_data *pdata = pchip->pdata;88 89 usleep_range(1000, 2000);90 /* set Filter Strength Register */91 rval = lm3630a_write(pchip, REG_FILTER_STRENGTH, 0x03);92 /* set Cofig. register */93 rval |= lm3630a_update(pchip, REG_CONFIG, 0x07, pdata->pwm_ctrl);94 /* set boost control */95 rval |= lm3630a_write(pchip, REG_BOOST, 0x38);96 /* set current A */97 rval |= lm3630a_update(pchip, REG_I_A, 0x1F, 0x1F);98 /* set current B */99 rval |= lm3630a_write(pchip, REG_I_B, 0x1F);100 /* set control */101 rval |= lm3630a_update(pchip, REG_CTRL, 0x14, pdata->leda_ctrl);102 rval |= lm3630a_update(pchip, REG_CTRL, 0x0B, pdata->ledb_ctrl);103 usleep_range(1000, 2000);104 /* set brightness A and B */105 rval |= lm3630a_write(pchip, REG_BRT_A, pdata->leda_init_brt);106 rval |= lm3630a_write(pchip, REG_BRT_B, pdata->ledb_init_brt);107 108 if (rval < 0)109 dev_err(pchip->dev, "i2c failed to access register\n");110 return rval;111}112 113/* interrupt handling */114static void lm3630a_delayed_func(struct work_struct *work)115{116 int rval;117 struct lm3630a_chip *pchip;118 119 pchip = container_of(work, struct lm3630a_chip, work.work);120 121 rval = lm3630a_read(pchip, REG_INT_STATUS);122 if (rval < 0) {123 dev_err(pchip->dev,124 "i2c failed to access REG_INT_STATUS Register\n");125 return;126 }127 128 dev_info(pchip->dev, "REG_INT_STATUS Register is 0x%x\n", rval);129}130 131static irqreturn_t lm3630a_isr_func(int irq, void *chip)132{133 int rval;134 struct lm3630a_chip *pchip = chip;135 unsigned long delay = msecs_to_jiffies(INT_DEBOUNCE_MSEC);136 137 queue_delayed_work(pchip->irqthread, &pchip->work, delay);138 139 rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);140 if (rval < 0) {141 dev_err(pchip->dev, "i2c failed to access register\n");142 return IRQ_NONE;143 }144 return IRQ_HANDLED;145}146 147static int lm3630a_intr_config(struct lm3630a_chip *pchip)148{149 int rval;150 151 rval = lm3630a_write(pchip, REG_INT_EN, 0x87);152 if (rval < 0)153 return rval;154 155 INIT_DELAYED_WORK(&pchip->work, lm3630a_delayed_func);156 pchip->irqthread = create_singlethread_workqueue("lm3630a-irqthd");157 if (!pchip->irqthread) {158 dev_err(pchip->dev, "create irq thread fail\n");159 return -ENOMEM;160 }161 if (request_threaded_irq162 (pchip->irq, NULL, lm3630a_isr_func,163 IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lm3630a_irq", pchip)) {164 dev_err(pchip->dev, "request threaded irq fail\n");165 destroy_workqueue(pchip->irqthread);166 return -ENOMEM;167 }168 return rval;169}170 171static int lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max)172{173 int err;174 175 pchip->pwmd_state.period = pchip->pdata->pwm_period;176 177 err = pwm_set_relative_duty_cycle(&pchip->pwmd_state, br, br_max);178 if (err)179 return err;180 181 pchip->pwmd_state.enabled = pchip->pwmd_state.duty_cycle ? true : false;182 183 return pwm_apply_might_sleep(pchip->pwmd, &pchip->pwmd_state);184}185 186/* update and get brightness */187static int lm3630a_bank_a_update_status(struct backlight_device *bl)188{189 int ret;190 struct lm3630a_chip *pchip = bl_get_data(bl);191 enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;192 int brightness = backlight_get_brightness(bl);193 194 /* pwm control */195 if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0)196 return lm3630a_pwm_ctrl(pchip, brightness,197 bl->props.max_brightness);198 199 /* disable sleep */200 ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);201 if (ret < 0)202 goto out_i2c_err;203 usleep_range(1000, 2000);204 /* minimum brightness is 0x04 */205 ret = lm3630a_write(pchip, REG_BRT_A, brightness);206 207 if (brightness < 0x4)208 /* turn the string off */209 ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDA_ENABLE, 0);210 else211 ret |= lm3630a_update(pchip, REG_CTRL,212 LM3630A_LEDA_ENABLE, LM3630A_LEDA_ENABLE);213 if (ret < 0)214 goto out_i2c_err;215 return 0;216 217out_i2c_err:218 dev_err(pchip->dev, "i2c failed to access (%pe)\n", ERR_PTR(ret));219 return ret;220}221 222static int lm3630a_bank_a_get_brightness(struct backlight_device *bl)223{224 int brightness, rval;225 struct lm3630a_chip *pchip = bl_get_data(bl);226 enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;227 228 if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) {229 rval = lm3630a_read(pchip, REG_PWM_OUTHIGH);230 if (rval < 0)231 goto out_i2c_err;232 brightness = (rval & 0x01) << 8;233 rval = lm3630a_read(pchip, REG_PWM_OUTLOW);234 if (rval < 0)235 goto out_i2c_err;236 brightness |= rval;237 return brightness;238 }239 240 /* disable sleep */241 rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);242 if (rval < 0)243 goto out_i2c_err;244 usleep_range(1000, 2000);245 rval = lm3630a_read(pchip, REG_BRT_A);246 if (rval < 0)247 goto out_i2c_err;248 return rval;249 250out_i2c_err:251 dev_err(pchip->dev, "i2c failed to access register\n");252 return 0;253}254 255static const struct backlight_ops lm3630a_bank_a_ops = {256 .options = BL_CORE_SUSPENDRESUME,257 .update_status = lm3630a_bank_a_update_status,258 .get_brightness = lm3630a_bank_a_get_brightness,259};260 261/* update and get brightness */262static int lm3630a_bank_b_update_status(struct backlight_device *bl)263{264 int ret;265 struct lm3630a_chip *pchip = bl_get_data(bl);266 enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;267 int brightness = backlight_get_brightness(bl);268 269 /* pwm control */270 if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0)271 return lm3630a_pwm_ctrl(pchip, brightness,272 bl->props.max_brightness);273 274 /* disable sleep */275 ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);276 if (ret < 0)277 goto out_i2c_err;278 usleep_range(1000, 2000);279 /* minimum brightness is 0x04 */280 ret = lm3630a_write(pchip, REG_BRT_B, brightness);281 282 if (brightness < 0x4)283 /* turn the string off */284 ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDB_ENABLE, 0);285 else286 ret |= lm3630a_update(pchip, REG_CTRL,287 LM3630A_LEDB_ENABLE, LM3630A_LEDB_ENABLE);288 if (ret < 0)289 goto out_i2c_err;290 return 0;291 292out_i2c_err:293 dev_err(pchip->dev, "i2c failed to access (%pe)\n", ERR_PTR(ret));294 return ret;295}296 297static int lm3630a_bank_b_get_brightness(struct backlight_device *bl)298{299 int brightness, rval;300 struct lm3630a_chip *pchip = bl_get_data(bl);301 enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;302 303 if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) {304 rval = lm3630a_read(pchip, REG_PWM_OUTHIGH);305 if (rval < 0)306 goto out_i2c_err;307 brightness = (rval & 0x01) << 8;308 rval = lm3630a_read(pchip, REG_PWM_OUTLOW);309 if (rval < 0)310 goto out_i2c_err;311 brightness |= rval;312 return brightness;313 }314 315 /* disable sleep */316 rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);317 if (rval < 0)318 goto out_i2c_err;319 usleep_range(1000, 2000);320 rval = lm3630a_read(pchip, REG_BRT_B);321 if (rval < 0)322 goto out_i2c_err;323 return rval;324 325out_i2c_err:326 dev_err(pchip->dev, "i2c failed to access register\n");327 return 0;328}329 330static const struct backlight_ops lm3630a_bank_b_ops = {331 .options = BL_CORE_SUSPENDRESUME,332 .update_status = lm3630a_bank_b_update_status,333 .get_brightness = lm3630a_bank_b_get_brightness,334};335 336static int lm3630a_backlight_register(struct lm3630a_chip *pchip)337{338 struct lm3630a_platform_data *pdata = pchip->pdata;339 struct backlight_properties props;340 const char *label;341 342 memset(&props, 0, sizeof(struct backlight_properties));343 props.type = BACKLIGHT_RAW;344 if (pdata->leda_ctrl != LM3630A_LEDA_DISABLE) {345 props.brightness = pdata->leda_init_brt;346 props.max_brightness = pdata->leda_max_brt;347 label = pdata->leda_label ? pdata->leda_label : "lm3630a_leda";348 pchip->bleda =349 devm_backlight_device_register(pchip->dev, label,350 pchip->dev, pchip,351 &lm3630a_bank_a_ops, &props);352 if (IS_ERR(pchip->bleda))353 return PTR_ERR(pchip->bleda);354 }355 356 if ((pdata->ledb_ctrl != LM3630A_LEDB_DISABLE) &&357 (pdata->ledb_ctrl != LM3630A_LEDB_ON_A)) {358 props.brightness = pdata->ledb_init_brt;359 props.max_brightness = pdata->ledb_max_brt;360 label = pdata->ledb_label ? pdata->ledb_label : "lm3630a_ledb";361 pchip->bledb =362 devm_backlight_device_register(pchip->dev, label,363 pchip->dev, pchip,364 &lm3630a_bank_b_ops, &props);365 if (IS_ERR(pchip->bledb))366 return PTR_ERR(pchip->bledb);367 }368 return 0;369}370 371static const struct regmap_config lm3630a_regmap = {372 .reg_bits = 8,373 .val_bits = 8,374 .max_register = REG_MAX,375};376 377static int lm3630a_parse_led_sources(struct fwnode_handle *node,378 int default_led_sources)379{380 u32 sources[LM3630A_NUM_SINKS];381 int ret, num_sources, i;382 383 num_sources = fwnode_property_count_u32(node, "led-sources");384 if (num_sources < 0)385 return default_led_sources;386 else if (num_sources > ARRAY_SIZE(sources))387 return -EINVAL;388 389 ret = fwnode_property_read_u32_array(node, "led-sources", sources,390 num_sources);391 if (ret)392 return ret;393 394 for (i = 0; i < num_sources; i++) {395 if (sources[i] != LM3630A_SINK_0 && sources[i] != LM3630A_SINK_1)396 return -EINVAL;397 398 ret |= BIT(sources[i]);399 }400 401 return ret;402}403 404static int lm3630a_parse_bank(struct lm3630a_platform_data *pdata,405 struct fwnode_handle *node, int *seen_led_sources)406{407 int led_sources, ret;408 const char *label;409 u32 bank, val;410 bool linear;411 412 ret = fwnode_property_read_u32(node, "reg", &bank);413 if (ret)414 return ret;415 416 if (bank != LM3630A_BANK_0 && bank != LM3630A_BANK_1)417 return -EINVAL;418 419 led_sources = lm3630a_parse_led_sources(node, BIT(bank));420 if (led_sources < 0)421 return led_sources;422 423 if (*seen_led_sources & led_sources)424 return -EINVAL;425 426 *seen_led_sources |= led_sources;427 428 linear = fwnode_property_read_bool(node,429 "ti,linear-mapping-mode");430 if (bank) {431 if (led_sources & BIT(LM3630A_SINK_0) ||432 !(led_sources & BIT(LM3630A_SINK_1)))433 return -EINVAL;434 435 pdata->ledb_ctrl = linear ?436 LM3630A_LEDB_ENABLE_LINEAR :437 LM3630A_LEDB_ENABLE;438 } else {439 if (!(led_sources & BIT(LM3630A_SINK_0)))440 return -EINVAL;441 442 pdata->leda_ctrl = linear ?443 LM3630A_LEDA_ENABLE_LINEAR :444 LM3630A_LEDA_ENABLE;445 446 if (led_sources & BIT(LM3630A_SINK_1))447 pdata->ledb_ctrl = LM3630A_LEDB_ON_A;448 }449 450 ret = fwnode_property_read_string(node, "label", &label);451 if (!ret) {452 if (bank)453 pdata->ledb_label = label;454 else455 pdata->leda_label = label;456 }457 458 ret = fwnode_property_read_u32(node, "default-brightness",459 &val);460 if (!ret) {461 if (bank)462 pdata->ledb_init_brt = val;463 else464 pdata->leda_init_brt = val;465 }466 467 ret = fwnode_property_read_u32(node, "max-brightness", &val);468 if (!ret) {469 if (bank)470 pdata->ledb_max_brt = val;471 else472 pdata->leda_max_brt = val;473 }474 475 return 0;476}477 478static int lm3630a_parse_node(struct lm3630a_chip *pchip,479 struct lm3630a_platform_data *pdata)480{481 int ret = -ENODEV, seen_led_sources = 0;482 struct fwnode_handle *node;483 484 device_for_each_child_node(pchip->dev, node) {485 ret = lm3630a_parse_bank(pdata, node, &seen_led_sources);486 if (ret) {487 fwnode_handle_put(node);488 return ret;489 }490 }491 492 return ret;493}494 495static int lm3630a_probe(struct i2c_client *client)496{497 struct lm3630a_platform_data *pdata = dev_get_platdata(&client->dev);498 struct lm3630a_chip *pchip;499 int rval;500 501 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {502 dev_err(&client->dev, "fail : i2c functionality check\n");503 return -EOPNOTSUPP;504 }505 506 pchip = devm_kzalloc(&client->dev, sizeof(struct lm3630a_chip),507 GFP_KERNEL);508 if (!pchip)509 return -ENOMEM;510 pchip->dev = &client->dev;511 512 pchip->regmap = devm_regmap_init_i2c(client, &lm3630a_regmap);513 if (IS_ERR(pchip->regmap)) {514 rval = PTR_ERR(pchip->regmap);515 dev_err(&client->dev, "fail : allocate reg. map: %d\n", rval);516 return rval;517 }518 519 i2c_set_clientdata(client, pchip);520 if (pdata == NULL) {521 pdata = devm_kzalloc(pchip->dev,522 sizeof(struct lm3630a_platform_data),523 GFP_KERNEL);524 if (pdata == NULL)525 return -ENOMEM;526 527 /* default values */528 pdata->leda_max_brt = LM3630A_MAX_BRIGHTNESS;529 pdata->ledb_max_brt = LM3630A_MAX_BRIGHTNESS;530 pdata->leda_init_brt = LM3630A_MAX_BRIGHTNESS;531 pdata->ledb_init_brt = LM3630A_MAX_BRIGHTNESS;532 533 rval = lm3630a_parse_node(pchip, pdata);534 if (rval) {535 dev_err(&client->dev, "fail : parse node\n");536 return rval;537 }538 }539 pchip->pdata = pdata;540 541 pchip->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable",542 GPIOD_OUT_HIGH);543 if (IS_ERR(pchip->enable_gpio))544 return PTR_ERR(pchip->enable_gpio);545 546 /* chip initialize */547 rval = lm3630a_chip_init(pchip);548 if (rval < 0) {549 dev_err(&client->dev, "fail : init chip\n");550 return rval;551 }552 /* backlight register */553 rval = lm3630a_backlight_register(pchip);554 if (rval < 0) {555 dev_err(&client->dev, "fail : backlight register.\n");556 return rval;557 }558 /* pwm */559 if (pdata->pwm_ctrl != LM3630A_PWM_DISABLE) {560 pchip->pwmd = devm_pwm_get(pchip->dev, "lm3630a-pwm");561 if (IS_ERR(pchip->pwmd))562 return dev_err_probe(&client->dev, PTR_ERR(pchip->pwmd),563 "fail : get pwm device\n");564 565 pwm_init_state(pchip->pwmd, &pchip->pwmd_state);566 }567 568 /* interrupt enable : irq 0 is not allowed */569 pchip->irq = client->irq;570 if (pchip->irq) {571 rval = lm3630a_intr_config(pchip);572 if (rval < 0)573 return rval;574 }575 dev_info(&client->dev, "LM3630A backlight register OK.\n");576 return 0;577}578 579static void lm3630a_remove(struct i2c_client *client)580{581 int rval;582 struct lm3630a_chip *pchip = i2c_get_clientdata(client);583 584 rval = lm3630a_write(pchip, REG_BRT_A, 0);585 if (rval < 0)586 dev_err(pchip->dev, "i2c failed to access register\n");587 588 rval = lm3630a_write(pchip, REG_BRT_B, 0);589 if (rval < 0)590 dev_err(pchip->dev, "i2c failed to access register\n");591 592 if (pchip->irq) {593 free_irq(pchip->irq, pchip);594 destroy_workqueue(pchip->irqthread);595 }596}597 598static const struct i2c_device_id lm3630a_id[] = {599 { LM3630A_NAME },600 {}601};602 603MODULE_DEVICE_TABLE(i2c, lm3630a_id);604 605static const struct of_device_id lm3630a_match_table[] = {606 { .compatible = "ti,lm3630a", },607 { },608};609 610MODULE_DEVICE_TABLE(of, lm3630a_match_table);611 612static struct i2c_driver lm3630a_i2c_driver = {613 .driver = {614 .name = LM3630A_NAME,615 .of_match_table = lm3630a_match_table,616 },617 .probe = lm3630a_probe,618 .remove = lm3630a_remove,619 .id_table = lm3630a_id,620};621 622module_i2c_driver(lm3630a_i2c_driver);623 624MODULE_DESCRIPTION("Texas Instruments Backlight driver for LM3630A");625MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");626MODULE_AUTHOR("LDD MLP <ldd-mlp@list.ti.com>");627MODULE_LICENSE("GPL v2");628