0016-backlight-add-TI-LMU-backlight-driver.patch (34674B)
1 From 102ad25228f75277c9f023a121c073c906034d13 Mon Sep 17 00:00:00 2001 2 From: Milo Kim <Milo.Kim@ti.com> 3 Date: Mon, 17 Jul 2017 15:39:56 +0200 4 Subject: [PATCH 16/17] backlight: add TI LMU backlight driver 5 6 This is consolidated driver which supports the following 7 backlight devices: LM3532, LM3631, LM3632, LM3633, LM3695 8 and LM3697. 9 10 Structure 11 --------- 12 It consists of two parts - core and data. 13 14 Core part supports features below. 15 - Backlight subsystem control 16 - Channel configuration from DT properties 17 - Light dimming effect control: ramp up and down. 18 - LMU fault monitor notifier handling 19 - PWM brightness control 20 21 Data part describes device specific data. 22 - Register value configuration for each LMU device 23 : initialization, channel configuration, control mode, enable and 24 brightness. 25 - PWM action configuration 26 - Light dimming effect table 27 - Option for LMU fault monitor support 28 29 Signed-off-by: Milo Kim <milo.kim@ti.com> 30 Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> 31 --- 32 drivers/video/backlight/Kconfig | 7 + 33 drivers/video/backlight/Makefile | 3 + 34 drivers/video/backlight/ti-lmu-backlight-core.c | 729 ++++++++++++++++++++++++ 35 drivers/video/backlight/ti-lmu-backlight-data.c | 304 ++++++++++ 36 drivers/video/backlight/ti-lmu-backlight-data.h | 95 +++ 37 5 files changed, 1138 insertions(+) 38 create mode 100644 drivers/video/backlight/ti-lmu-backlight-core.c 39 create mode 100644 drivers/video/backlight/ti-lmu-backlight-data.c 40 create mode 100644 drivers/video/backlight/ti-lmu-backlight-data.h 41 42 diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig 43 index 4e1d2ad..c3cc833 100644 44 --- a/drivers/video/backlight/Kconfig 45 +++ b/drivers/video/backlight/Kconfig 46 @@ -427,6 +427,13 @@ config BACKLIGHT_SKY81452 47 To compile this driver as a module, choose M here: the module will 48 be called sky81452-backlight 49 50 +config BACKLIGHT_TI_LMU 51 + tristate "Backlight driver for TI LMU" 52 + depends on BACKLIGHT_CLASS_DEVICE && MFD_TI_LMU 53 + help 54 + Say Y to enable the backlight driver for TI LMU devices. 55 + This supports LM3532, LM3631, LM3632, LM3633, LM3695 and LM3697. 56 + 57 config BACKLIGHT_TPS65217 58 tristate "TPS65217 Backlight" 59 depends on BACKLIGHT_CLASS_DEVICE && MFD_TPS65217 60 diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile 61 index 8905129..c532e43 100644 62 --- a/drivers/video/backlight/Makefile 63 +++ b/drivers/video/backlight/Makefile 64 @@ -52,6 +52,9 @@ obj-$(CONFIG_BACKLIGHT_PM8941_WLED) += pm8941-wled.o 65 obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o 66 obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o 67 obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o 68 +ti-lmu-backlight-objs := ti-lmu-backlight-core.o \ 69 + ti-lmu-backlight-data.o 70 +obj-$(CONFIG_BACKLIGHT_TI_LMU) += ti-lmu-backlight.o 71 obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o 72 obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o 73 obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o 74 diff --git a/drivers/video/backlight/ti-lmu-backlight-core.c b/drivers/video/backlight/ti-lmu-backlight-core.c 75 new file mode 100644 76 index 0000000..fca9508 77 --- /dev/null 78 +++ b/drivers/video/backlight/ti-lmu-backlight-core.c 79 @@ -0,0 +1,729 @@ 80 +/* 81 + * TI LMU (Lighting Management Unit) Backlight Driver 82 + * 83 + * Copyright 2015 Texas Instruments 84 + * 85 + * Author: Milo Kim <milo.kim@ti.com> 86 + * 87 + * This program is free software; you can redistribute it and/or modify 88 + * it under the terms of the GNU General Public License version 2 as 89 + * published by the Free Software Foundation. 90 + */ 91 + 92 +#include <linux/backlight.h> 93 +#include <linux/bitops.h> 94 +#include <linux/device.h> 95 +#include <linux/delay.h> 96 +#include <linux/err.h> 97 +#include <linux/kernel.h> 98 +#include <linux/mfd/ti-lmu.h> 99 +#include <linux/mfd/ti-lmu-register.h> 100 +#include <linux/module.h> 101 +#include <linux/notifier.h> 102 +#include <linux/of.h> 103 +#include <linux/of_device.h> 104 +#include <linux/platform_device.h> 105 +#include <linux/pwm.h> 106 +#include <linux/slab.h> 107 + 108 +#include "ti-lmu-backlight-data.h" 109 + 110 +enum ti_lmu_bl_ctrl_mode { 111 + BL_REGISTER_BASED, 112 + BL_PWM_BASED, 113 +}; 114 + 115 +enum ti_lmu_bl_ramp_mode { 116 + BL_RAMP_UP, 117 + BL_RAMP_DOWN, 118 +}; 119 + 120 +struct ti_lmu_bl; 121 + 122 +/** 123 + * struct ti_lmu_bl_chip 124 + * 125 + * @dev: Parent device pointer 126 + * @lmu: LMU structure. 127 + * Used for register R/W access and notification. 128 + * @cfg: Device configuration data 129 + * @lmu_bl: Multiple backlight channels 130 + * @num_backlights: Number of backlight channels 131 + * @nb: Notifier block for handling LMU fault monitor event 132 + * 133 + * One backlight chip can have multiple backlight channels, 'ti_lmu_bl'. 134 + */ 135 +struct ti_lmu_bl_chip { 136 + struct device *dev; 137 + struct ti_lmu *lmu; 138 + const struct ti_lmu_bl_cfg *cfg; 139 + struct ti_lmu_bl *lmu_bl; 140 + int num_backlights; 141 + struct notifier_block nb; 142 +}; 143 + 144 +/** 145 + * struct ti_lmu_bl 146 + * 147 + * @chip: Pointer to parent backlight device 148 + * @bl_dev: Backlight subsystem device structure 149 + * @bank_id: Backlight bank ID 150 + * @name: Backlight channel name 151 + * @mode: Backlight control mode 152 + * @led_sources: Backlight output channel configuration. 153 + * Bit mask is set on parsing DT. 154 + * @default_brightness: [Optional] Initial brightness value 155 + * @ramp_up_msec: [Optional] Ramp up time 156 + * @ramp_down_msec: [Optional] Ramp down time 157 + * @pwm_period: [Optional] PWM period 158 + * @pwm: [Optional] PWM subsystem structure 159 + * 160 + * Each backlight device has its own channel configuration. 161 + * For chip control, parent chip data structure is used. 162 + */ 163 +struct ti_lmu_bl { 164 + struct ti_lmu_bl_chip *chip; 165 + struct backlight_device *bl_dev; 166 + 167 + int bank_id; 168 + const char *name; 169 + enum ti_lmu_bl_ctrl_mode mode; 170 + unsigned long led_sources; 171 + 172 + unsigned int default_brightness; 173 + 174 + /* Used for lighting effect */ 175 + unsigned int ramp_up_msec; 176 + unsigned int ramp_down_msec; 177 + 178 + /* Only valid in PWM mode */ 179 + unsigned int pwm_period; 180 + struct pwm_device *pwm; 181 +}; 182 + 183 +#define NUM_DUAL_CHANNEL 2 184 +#define LMU_BACKLIGHT_DUAL_CHANNEL_USED (BIT(0) | BIT(1)) 185 +#define LMU_BACKLIGHT_11BIT_LSB_MASK (BIT(0) | BIT(1) | BIT(2)) 186 +#define LMU_BACKLIGHT_11BIT_MSB_SHIFT 3 187 +#define DEFAULT_PWM_NAME "lmu-backlight" 188 + 189 +static int ti_lmu_backlight_enable(struct ti_lmu_bl *lmu_bl, bool enable) 190 +{ 191 + struct ti_lmu_bl_chip *chip = lmu_bl->chip; 192 + struct regmap *regmap = chip->lmu->regmap; 193 + unsigned long enable_time = chip->cfg->reginfo->enable_usec; 194 + u8 *reg = chip->cfg->reginfo->enable; 195 + u8 mask = BIT(lmu_bl->bank_id); 196 + u8 val = (enable == true) ? mask : 0; 197 + int ret; 198 + 199 + if (!reg) 200 + return -EINVAL; 201 + 202 + ret = regmap_update_bits(regmap, *reg, mask, val); 203 + if (ret) 204 + return ret; 205 + 206 + if (enable_time > 0) 207 + usleep_range(enable_time, enable_time + 100); 208 + 209 + return 0; 210 +} 211 + 212 +static int ti_lmu_backlight_pwm_ctrl(struct ti_lmu_bl *lmu_bl, int brightness, 213 + int max_brightness) 214 +{ 215 + struct pwm_state state = { }; 216 + int ret; 217 + 218 + if (!lmu_bl->pwm) { 219 + lmu_bl->pwm = devm_pwm_get(lmu_bl->chip->dev, DEFAULT_PWM_NAME); 220 + if (IS_ERR(lmu_bl->pwm)) { 221 + ret = PTR_ERR(lmu_bl->pwm); 222 + lmu_bl->pwm = NULL; 223 + dev_err(lmu_bl->chip->dev, 224 + "Can not get PWM device, err: %d\n", ret); 225 + return ret; 226 + } 227 + } 228 + 229 + pwm_init_state(lmu_bl->pwm, &state); 230 + state.period = lmu_bl->pwm_period; 231 + state.duty_cycle = brightness * state.period / max_brightness; 232 + 233 + if (state.duty_cycle) 234 + state.enabled = true; 235 + else 236 + state.enabled = false; 237 + 238 + ret = pwm_apply_state(lmu_bl->pwm, &state); 239 + if (ret) 240 + dev_err(lmu_bl->chip->dev, "Failed to configure PWM: %d", ret); 241 + 242 + return ret; 243 +} 244 + 245 +static int ti_lmu_backlight_update_brightness_register(struct ti_lmu_bl *lmu_bl, 246 + int brightness) 247 +{ 248 + const struct ti_lmu_bl_cfg *cfg = lmu_bl->chip->cfg; 249 + const struct ti_lmu_bl_reg *reginfo = cfg->reginfo; 250 + struct regmap *regmap = lmu_bl->chip->lmu->regmap; 251 + u8 reg, val; 252 + int ret; 253 + 254 + /* 255 + * Brightness register update 256 + * 257 + * 11 bit dimming: update LSB bits and write MSB byte. 258 + * MSB brightness should be shifted. 259 + * 8 bit dimming: write MSB byte. 260 + */ 261 + if (cfg->max_brightness == MAX_BRIGHTNESS_11BIT) { 262 + reg = reginfo->brightness_lsb[lmu_bl->bank_id]; 263 + ret = regmap_update_bits(regmap, reg, 264 + LMU_BACKLIGHT_11BIT_LSB_MASK, 265 + brightness); 266 + if (ret) 267 + return ret; 268 + 269 + val = brightness >> LMU_BACKLIGHT_11BIT_MSB_SHIFT; 270 + } else { 271 + val = brightness; 272 + } 273 + 274 + reg = reginfo->brightness_msb[lmu_bl->bank_id]; 275 + return regmap_write(regmap, reg, val); 276 +} 277 + 278 +static int ti_lmu_backlight_update_status(struct backlight_device *bl_dev) 279 +{ 280 + struct ti_lmu_bl *lmu_bl = bl_get_data(bl_dev); 281 + const struct ti_lmu_bl_cfg *cfg = lmu_bl->chip->cfg; 282 + int brightness = bl_dev->props.brightness; 283 + bool enable = brightness > 0; 284 + int ret; 285 + 286 + if (bl_dev->props.state & BL_CORE_SUSPENDED) 287 + brightness = 0; 288 + 289 + ret = ti_lmu_backlight_enable(lmu_bl, enable); 290 + if (ret) 291 + return ret; 292 + 293 + if (lmu_bl->mode == BL_PWM_BASED) { 294 + ti_lmu_backlight_pwm_ctrl(lmu_bl, brightness, 295 + bl_dev->props.max_brightness); 296 + 297 + switch (cfg->pwm_action) { 298 + case UPDATE_PWM_ONLY: 299 + /* No register update is required */ 300 + return 0; 301 + case UPDATE_MAX_BRT: 302 + /* 303 + * PWM can start from any non-zero code and dim down 304 + * to zero. So, brightness register should be updated 305 + * even in PWM mode. 306 + */ 307 + if (brightness > 0) 308 + brightness = MAX_BRIGHTNESS_11BIT; 309 + else 310 + brightness = 0; 311 + break; 312 + default: 313 + break; 314 + } 315 + } 316 + 317 + return ti_lmu_backlight_update_brightness_register(lmu_bl, brightness); 318 +} 319 + 320 +static const struct backlight_ops lmu_backlight_ops = { 321 + .options = BL_CORE_SUSPENDRESUME, 322 + .update_status = ti_lmu_backlight_update_status, 323 +}; 324 + 325 +static int ti_lmu_backlight_of_get_ctrl_bank(struct device_node *np, 326 + struct ti_lmu_bl *lmu_bl) 327 +{ 328 + const char *name; 329 + u32 *sources; 330 + int num_channels = lmu_bl->chip->cfg->num_channels; 331 + int ret, num_sources; 332 + 333 + sources = devm_kzalloc(lmu_bl->chip->dev, num_channels, GFP_KERNEL); 334 + if (!sources) 335 + return -ENOMEM; 336 + 337 + if (!of_property_read_string(np, "label", &name)) 338 + lmu_bl->name = name; 339 + else 340 + lmu_bl->name = np->name; 341 + 342 + ret = of_property_count_u32_elems(np, "led-sources"); 343 + if (ret < 0 || ret > num_channels) 344 + return -EINVAL; 345 + 346 + num_sources = ret; 347 + ret = of_property_read_u32_array(np, "led-sources", sources, 348 + num_sources); 349 + if (ret) 350 + return ret; 351 + 352 + lmu_bl->led_sources = 0; 353 + while (num_sources--) 354 + set_bit(sources[num_sources], &lmu_bl->led_sources); 355 + 356 + return 0; 357 +} 358 + 359 +static void ti_lmu_backlight_of_get_light_properties(struct device_node *np, 360 + struct ti_lmu_bl *lmu_bl) 361 +{ 362 + of_property_read_u32(np, "default-brightness-level", 363 + &lmu_bl->default_brightness); 364 + 365 + of_property_read_u32(np, "ramp-up-msec", &lmu_bl->ramp_up_msec); 366 + of_property_read_u32(np, "ramp-down-msec", &lmu_bl->ramp_down_msec); 367 +} 368 + 369 +static void ti_lmu_backlight_of_get_brightness_mode(struct device_node *np, 370 + struct ti_lmu_bl *lmu_bl) 371 +{ 372 + of_property_read_u32(np, "pwm-period", &lmu_bl->pwm_period); 373 + 374 + if (lmu_bl->pwm_period > 0) 375 + lmu_bl->mode = BL_PWM_BASED; 376 + else 377 + lmu_bl->mode = BL_REGISTER_BASED; 378 +} 379 + 380 +static int ti_lmu_backlight_of_create(struct ti_lmu_bl_chip *chip, 381 + struct device_node *np) 382 +{ 383 + struct device_node *child; 384 + struct ti_lmu_bl *lmu_bl, *each; 385 + int ret, num_backlights; 386 + int i = 0; 387 + 388 + num_backlights = of_get_child_count(np); 389 + if (num_backlights == 0) { 390 + dev_err(chip->dev, "No backlight strings\n"); 391 + return -ENODEV; 392 + } 393 + 394 + /* One chip can have mulitple backlight strings */ 395 + lmu_bl = devm_kzalloc(chip->dev, sizeof(*lmu_bl) * num_backlights, 396 + GFP_KERNEL); 397 + if (!lmu_bl) 398 + return -ENOMEM; 399 + 400 + /* Child is mapped to LMU backlight control bank */ 401 + for_each_child_of_node(np, child) { 402 + each = lmu_bl + i; 403 + each->bank_id = i; 404 + each->chip = chip; 405 + 406 + ret = ti_lmu_backlight_of_get_ctrl_bank(child, each); 407 + if (ret) { 408 + of_node_put(np); 409 + return ret; 410 + } 411 + 412 + ti_lmu_backlight_of_get_light_properties(child, each); 413 + ti_lmu_backlight_of_get_brightness_mode(child, each); 414 + 415 + i++; 416 + } 417 + 418 + chip->lmu_bl = lmu_bl; 419 + chip->num_backlights = num_backlights; 420 + 421 + return 0; 422 +} 423 + 424 +static int ti_lmu_backlight_check_channel(struct ti_lmu_bl *lmu_bl) 425 +{ 426 + const struct ti_lmu_bl_cfg *cfg = lmu_bl->chip->cfg; 427 + const struct ti_lmu_bl_reg *reginfo = lmu_bl->chip->cfg->reginfo; 428 + 429 + if (!reginfo->brightness_msb) 430 + return -EINVAL; 431 + 432 + if (cfg->max_brightness > MAX_BRIGHTNESS_8BIT) { 433 + if (!reginfo->brightness_lsb) 434 + return -EINVAL; 435 + } 436 + 437 + return 0; 438 +} 439 + 440 +static int ti_lmu_backlight_create_channel(struct ti_lmu_bl *lmu_bl) 441 +{ 442 + struct regmap *regmap = lmu_bl->chip->lmu->regmap; 443 + const struct lmu_bl_reg_data *regdata = 444 + lmu_bl->chip->cfg->reginfo->channel; 445 + int num_channels = lmu_bl->chip->cfg->num_channels; 446 + int i, ret; 447 + u8 shift; 448 + 449 + /* 450 + * How to create backlight output channels: 451 + * Check 'led_sources' bit and update registers. 452 + * 453 + * 1) Dual channel configuration 454 + * The 1st register data is used for single channel. 455 + * The 2nd register data is used for dual channel. 456 + * 457 + * 2) Multiple channel configuration 458 + * Each register data is mapped to bank ID. 459 + * Bit shift operation is defined in channel registers. 460 + * 461 + * Channel register data consists of address, mask, value. 462 + */ 463 + 464 + if (num_channels == NUM_DUAL_CHANNEL) { 465 + if (lmu_bl->led_sources == LMU_BACKLIGHT_DUAL_CHANNEL_USED) 466 + regdata++; 467 + 468 + return regmap_update_bits(regmap, regdata->reg, regdata->mask, 469 + regdata->val); 470 + } 471 + 472 + for (i = 0; regdata && i < num_channels; i++) { 473 + /* 474 + * Note that the result of regdata->val is shift bit. 475 + * The bank_id should be shifted for the channel configuration. 476 + */ 477 + if (test_bit(i, &lmu_bl->led_sources)) { 478 + shift = regdata->val; 479 + ret = regmap_update_bits(regmap, regdata->reg, 480 + regdata->mask, 481 + lmu_bl->bank_id << shift); 482 + if (ret) 483 + return ret; 484 + } 485 + 486 + regdata++; 487 + } 488 + 489 + return 0; 490 +} 491 + 492 +static int ti_lmu_backlight_update_ctrl_mode(struct ti_lmu_bl *lmu_bl) 493 +{ 494 + struct regmap *regmap = lmu_bl->chip->lmu->regmap; 495 + const struct lmu_bl_reg_data *regdata = 496 + lmu_bl->chip->cfg->reginfo->mode + lmu_bl->bank_id; 497 + u8 val = regdata->val; 498 + 499 + if (!regdata) 500 + return 0; 501 + 502 + /* 503 + * Update PWM configuration register. 504 + * If the mode is register based, then clear the bit. 505 + */ 506 + if (lmu_bl->mode != BL_PWM_BASED) 507 + val = 0; 508 + 509 + return regmap_update_bits(regmap, regdata->reg, regdata->mask, val); 510 +} 511 + 512 +static int ti_lmu_backlight_convert_ramp_to_index(struct ti_lmu_bl *lmu_bl, 513 + enum ti_lmu_bl_ramp_mode mode) 514 +{ 515 + const int *ramp_table = lmu_bl->chip->cfg->ramp_table; 516 + const int size = lmu_bl->chip->cfg->size_ramp; 517 + unsigned int msec; 518 + int i; 519 + 520 + if (!ramp_table) 521 + return -EINVAL; 522 + 523 + switch (mode) { 524 + case BL_RAMP_UP: 525 + msec = lmu_bl->ramp_up_msec; 526 + break; 527 + case BL_RAMP_DOWN: 528 + msec = lmu_bl->ramp_down_msec; 529 + break; 530 + default: 531 + return -EINVAL; 532 + } 533 + 534 + if (msec <= ramp_table[0]) 535 + return 0; 536 + 537 + if (msec > ramp_table[size - 1]) 538 + return size - 1; 539 + 540 + for (i = 1; i < size; i++) { 541 + if (msec == ramp_table[i]) 542 + return i; 543 + 544 + /* Find an approximate index by looking up the table */ 545 + if (msec > ramp_table[i - 1] && msec < ramp_table[i]) { 546 + if (msec - ramp_table[i - 1] < ramp_table[i] - msec) 547 + return i - 1; 548 + else 549 + return i; 550 + } 551 + } 552 + 553 + return -EINVAL; 554 +} 555 + 556 +static int ti_lmu_backlight_set_ramp(struct ti_lmu_bl *lmu_bl) 557 +{ 558 + struct regmap *regmap = lmu_bl->chip->lmu->regmap; 559 + const struct ti_lmu_bl_reg *reginfo = lmu_bl->chip->cfg->reginfo; 560 + int offset = reginfo->ramp_reg_offset; 561 + int i, ret, index; 562 + struct lmu_bl_reg_data regdata; 563 + 564 + for (i = BL_RAMP_UP; i <= BL_RAMP_DOWN; i++) { 565 + index = ti_lmu_backlight_convert_ramp_to_index(lmu_bl, i); 566 + if (index > 0) { 567 + if (!reginfo->ramp) 568 + break; 569 + 570 + regdata = reginfo->ramp[i]; 571 + if (lmu_bl->bank_id != 0) 572 + regdata.val += offset; 573 + 574 + /* regdata.val is shift bit */ 575 + ret = regmap_update_bits(regmap, regdata.reg, 576 + regdata.mask, 577 + index << regdata.val); 578 + if (ret) 579 + return ret; 580 + } 581 + } 582 + 583 + return 0; 584 +} 585 + 586 +static int ti_lmu_backlight_configure(struct ti_lmu_bl *lmu_bl) 587 +{ 588 + int ret; 589 + 590 + ret = ti_lmu_backlight_check_channel(lmu_bl); 591 + if (ret) 592 + return ret; 593 + 594 + ret = ti_lmu_backlight_create_channel(lmu_bl); 595 + if (ret) 596 + return ret; 597 + 598 + ret = ti_lmu_backlight_update_ctrl_mode(lmu_bl); 599 + if (ret) 600 + return ret; 601 + 602 + return ti_lmu_backlight_set_ramp(lmu_bl); 603 +} 604 + 605 +static int ti_lmu_backlight_init(struct ti_lmu_bl_chip *chip) 606 +{ 607 + struct regmap *regmap = chip->lmu->regmap; 608 + const struct lmu_bl_reg_data *regdata = 609 + chip->cfg->reginfo->init; 610 + int num_init = chip->cfg->reginfo->num_init; 611 + int i, ret; 612 + 613 + for (i = 0; regdata && i < num_init; i++) { 614 + ret = regmap_update_bits(regmap, regdata->reg, regdata->mask, 615 + regdata->val); 616 + if (ret) 617 + return ret; 618 + 619 + regdata++; 620 + } 621 + 622 + return 0; 623 +} 624 + 625 +static int ti_lmu_backlight_reload(struct ti_lmu_bl_chip *chip) 626 +{ 627 + struct ti_lmu_bl *each; 628 + int i, ret; 629 + 630 + ret = ti_lmu_backlight_init(chip); 631 + if (ret) 632 + return ret; 633 + 634 + for (i = 0; i < chip->num_backlights; i++) { 635 + each = chip->lmu_bl + i; 636 + ret = ti_lmu_backlight_configure(each); 637 + if (ret) 638 + return ret; 639 + 640 + ret = backlight_update_status(each->bl_dev); 641 + if (ret) 642 + return ret; 643 + } 644 + 645 + return 0; 646 +} 647 + 648 +static int ti_lmu_backlight_add_device(struct device *dev, 649 + struct ti_lmu_bl *lmu_bl) 650 +{ 651 + struct backlight_device *bl_dev; 652 + struct backlight_properties props; 653 + 654 + memset(&props, 0, sizeof(struct backlight_properties)); 655 + props.type = BACKLIGHT_PLATFORM; 656 + props.brightness = lmu_bl->default_brightness; 657 + props.max_brightness = lmu_bl->chip->cfg->max_brightness; 658 + 659 + bl_dev = devm_backlight_device_register(dev, lmu_bl->name, 660 + lmu_bl->chip->dev, lmu_bl, 661 + &lmu_backlight_ops, &props); 662 + if (IS_ERR(bl_dev)) 663 + return PTR_ERR(bl_dev); 664 + 665 + lmu_bl->bl_dev = bl_dev; 666 + 667 + return 0; 668 +} 669 + 670 +static struct ti_lmu_bl_chip * 671 +ti_lmu_backlight_register(struct device *dev, struct ti_lmu *lmu, 672 + const struct ti_lmu_bl_cfg *cfg) 673 +{ 674 + struct ti_lmu_bl_chip *chip; 675 + struct ti_lmu_bl *each; 676 + int i, ret; 677 + 678 + if (!cfg) { 679 + dev_err(dev, "Operation is not configured\n"); 680 + return ERR_PTR(-EINVAL); 681 + } 682 + 683 + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 684 + if (!chip) 685 + return ERR_PTR(-ENOMEM); 686 + 687 + chip->dev = dev; 688 + chip->lmu = lmu; 689 + chip->cfg = cfg; 690 + 691 + ret = ti_lmu_backlight_of_create(chip, dev->of_node); 692 + if (ret) 693 + return ERR_PTR(ret); 694 + 695 + ret = ti_lmu_backlight_init(chip); 696 + if (ret) { 697 + dev_err(dev, "Backlight init err: %d\n", ret); 698 + return ERR_PTR(ret); 699 + } 700 + 701 + for (i = 0; i < chip->num_backlights; i++) { 702 + each = chip->lmu_bl + i; 703 + 704 + ret = ti_lmu_backlight_configure(each); 705 + if (ret) { 706 + dev_err(dev, "Backlight config err: %d\n", ret); 707 + return ERR_PTR(ret); 708 + } 709 + 710 + ret = ti_lmu_backlight_add_device(dev, each); 711 + if (ret) { 712 + dev_err(dev, "Backlight device err: %d\n", ret); 713 + return ERR_PTR(ret); 714 + } 715 + 716 + ret = backlight_update_status(each->bl_dev); 717 + if (ret) { 718 + dev_err(dev, "Backlight update err: %d\n", ret); 719 + return ERR_PTR(ret); 720 + } 721 + } 722 + 723 + return chip; 724 +} 725 + 726 +static void ti_lmu_backlight_unregister(struct ti_lmu_bl_chip *chip) 727 +{ 728 + struct ti_lmu_bl *each; 729 + int i; 730 + 731 + /* Turn off the brightness */ 732 + for (i = 0; i < chip->num_backlights; i++) { 733 + each = chip->lmu_bl + i; 734 + each->bl_dev->props.brightness = 0; 735 + backlight_update_status(each->bl_dev); 736 + } 737 +} 738 + 739 +static int ti_lmu_backlight_monitor_notifier(struct notifier_block *nb, 740 + unsigned long action, void *unused) 741 +{ 742 + struct ti_lmu_bl_chip *chip = container_of(nb, struct ti_lmu_bl_chip, 743 + nb); 744 + 745 + if (action == LMU_EVENT_MONITOR_DONE) { 746 + if (ti_lmu_backlight_reload(chip)) 747 + return NOTIFY_STOP; 748 + } 749 + 750 + return NOTIFY_OK; 751 +} 752 + 753 +static int ti_lmu_backlight_probe(struct platform_device *pdev) 754 +{ 755 + struct device *dev = &pdev->dev; 756 + struct ti_lmu *lmu = dev_get_drvdata(dev->parent); 757 + struct ti_lmu_bl_chip *chip; 758 + int ret; 759 + 760 + chip = ti_lmu_backlight_register(dev, lmu, &lmu_bl_cfg[pdev->id]); 761 + if (IS_ERR(chip)) 762 + return PTR_ERR(chip); 763 + 764 + /* 765 + * Notifier callback is required because backlight device needs 766 + * reconfiguration after fault detection procedure is done by 767 + * ti-lmu-fault-monitor driver. 768 + */ 769 + if (chip->cfg->fault_monitor_used) { 770 + chip->nb.notifier_call = ti_lmu_backlight_monitor_notifier; 771 + ret = blocking_notifier_chain_register(&chip->lmu->notifier, 772 + &chip->nb); 773 + if (ret) 774 + return ret; 775 + } 776 + 777 + platform_set_drvdata(pdev, chip); 778 + 779 + return 0; 780 +} 781 + 782 +static int ti_lmu_backlight_remove(struct platform_device *pdev) 783 +{ 784 + struct ti_lmu_bl_chip *chip = platform_get_drvdata(pdev); 785 + 786 + if (chip->cfg->fault_monitor_used) 787 + blocking_notifier_chain_unregister(&chip->lmu->notifier, 788 + &chip->nb); 789 + 790 + ti_lmu_backlight_unregister(chip); 791 + 792 + return 0; 793 +} 794 + 795 +static struct platform_driver ti_lmu_backlight_driver = { 796 + .probe = ti_lmu_backlight_probe, 797 + .remove = ti_lmu_backlight_remove, 798 + .driver = { 799 + .name = "ti-lmu-backlight", 800 + }, 801 +}; 802 + 803 +module_platform_driver(ti_lmu_backlight_driver) 804 + 805 +MODULE_DESCRIPTION("TI LMU Backlight Driver"); 806 +MODULE_AUTHOR("Milo Kim"); 807 +MODULE_LICENSE("GPL v2"); 808 +MODULE_ALIAS("platform:ti-lmu-backlight"); 809 diff --git a/drivers/video/backlight/ti-lmu-backlight-data.c b/drivers/video/backlight/ti-lmu-backlight-data.c 810 new file mode 100644 811 index 0000000..583136c 812 --- /dev/null 813 +++ b/drivers/video/backlight/ti-lmu-backlight-data.c 814 @@ -0,0 +1,304 @@ 815 +/* 816 + * TI LMU (Lighting Management Unit) Backlight Device Data 817 + * 818 + * Copyright 2015 Texas Instruments 819 + * 820 + * Author: Milo Kim <milo.kim@ti.com> 821 + * 822 + * This program is free software; you can redistribute it and/or modify 823 + * it under the terms of the GNU General Public License version 2 as 824 + * published by the Free Software Foundation. 825 + */ 826 + 827 +#include "ti-lmu-backlight-data.h" 828 + 829 +/* LM3532 */ 830 +static const struct lmu_bl_reg_data lm3532_init_data[] = { 831 + { LM3532_REG_ZONE_CFG_A, LM3532_ZONE_MASK, LM3532_ZONE_0 }, 832 + { LM3532_REG_ZONE_CFG_B, LM3532_ZONE_MASK, LM3532_ZONE_1 }, 833 + { LM3532_REG_ZONE_CFG_C, LM3532_ZONE_MASK, LM3532_ZONE_2 }, 834 +}; 835 + 836 +static const struct lmu_bl_reg_data lm3532_channel_data[] = { 837 + { LM3532_REG_OUTPUT_CFG, LM3532_ILED1_CFG_MASK, 838 + LM3532_ILED1_CFG_SHIFT }, 839 + { LM3532_REG_OUTPUT_CFG, LM3532_ILED2_CFG_MASK, 840 + LM3532_ILED2_CFG_SHIFT }, 841 + { LM3532_REG_OUTPUT_CFG, LM3532_ILED3_CFG_MASK, 842 + LM3532_ILED3_CFG_SHIFT }, 843 +}; 844 + 845 +static const struct lmu_bl_reg_data lm3532_mode_data[] = { 846 + { LM3532_REG_PWM_A_CFG, LM3532_PWM_A_MASK, LM3532_PWM_ZONE_0 }, 847 + { LM3532_REG_PWM_B_CFG, LM3532_PWM_B_MASK, LM3532_PWM_ZONE_1 }, 848 + { LM3532_REG_PWM_C_CFG, LM3532_PWM_C_MASK, LM3532_PWM_ZONE_2 }, 849 +}; 850 + 851 +static const struct lmu_bl_reg_data lm3532_ramp_data[] = { 852 + { LM3532_REG_RAMPUP, LM3532_RAMPUP_MASK, LM3532_RAMPUP_SHIFT }, 853 + { LM3532_REG_RAMPDN, LM3532_RAMPDN_MASK, LM3532_RAMPDN_SHIFT }, 854 +}; 855 + 856 +static u8 lm3532_enable_reg = LM3532_REG_ENABLE; 857 + 858 +static u8 lm3532_brightness_regs[] = { 859 + LM3532_REG_BRT_A, 860 + LM3532_REG_BRT_B, 861 + LM3532_REG_BRT_C, 862 +}; 863 + 864 +static const struct ti_lmu_bl_reg lm3532_reg_info = { 865 + .init = lm3532_init_data, 866 + .num_init = ARRAY_SIZE(lm3532_init_data), 867 + .channel = lm3532_channel_data, 868 + .mode = lm3532_mode_data, 869 + .ramp = lm3532_ramp_data, 870 + .enable = &lm3532_enable_reg, 871 + .brightness_msb = lm3532_brightness_regs, 872 +}; 873 + 874 +/* LM3631 */ 875 +static const struct lmu_bl_reg_data lm3631_init_data[] = { 876 + { LM3631_REG_BRT_MODE, LM3631_MODE_MASK, LM3631_DEFAULT_MODE }, 877 + { LM3631_REG_BL_CFG, LM3631_MAP_MASK, LM3631_EXPONENTIAL_MAP }, 878 +}; 879 + 880 +static const struct lmu_bl_reg_data lm3631_channel_data[] = { 881 + { LM3631_REG_BL_CFG, LM3631_BL_CHANNEL_MASK, LM3631_BL_SINGLE_CHANNEL }, 882 + { LM3631_REG_BL_CFG, LM3631_BL_CHANNEL_MASK, LM3631_BL_DUAL_CHANNEL }, 883 +}; 884 + 885 +static const struct lmu_bl_reg_data lm3631_ramp_data[] = { 886 + { LM3631_REG_SLOPE, LM3631_SLOPE_MASK, LM3631_SLOPE_SHIFT }, 887 +}; 888 + 889 +static u8 lm3631_enable_reg = LM3631_REG_DEVCTRL; 890 +static u8 lm3631_brightness_msb_reg = LM3631_REG_BRT_MSB; 891 +static u8 lm3631_brightness_lsb_reg = LM3631_REG_BRT_LSB; 892 + 893 +static const struct ti_lmu_bl_reg lm3631_reg_info = { 894 + .init = lm3631_init_data, 895 + .num_init = ARRAY_SIZE(lm3631_init_data), 896 + .channel = lm3631_channel_data, 897 + .ramp = lm3631_ramp_data, 898 + .enable = &lm3631_enable_reg, 899 + .brightness_msb = &lm3631_brightness_msb_reg, 900 + .brightness_lsb = &lm3631_brightness_lsb_reg, 901 +}; 902 + 903 +/* LM3632 */ 904 +static const struct lmu_bl_reg_data lm3632_init_data[] = { 905 + { LM3632_REG_CONFIG1, LM3632_OVP_MASK, LM3632_OVP_25V }, 906 + { LM3632_REG_CONFIG2, LM3632_SWFREQ_MASK, LM3632_SWFREQ_1MHZ }, 907 +}; 908 + 909 +static const struct lmu_bl_reg_data lm3632_channel_data[] = { 910 + { LM3632_REG_ENABLE, LM3632_BL_CHANNEL_MASK, LM3632_BL_SINGLE_CHANNEL }, 911 + { LM3632_REG_ENABLE, LM3632_BL_CHANNEL_MASK, LM3632_BL_DUAL_CHANNEL }, 912 +}; 913 + 914 +static const struct lmu_bl_reg_data lm3632_mode_data[] = { 915 + { LM3632_REG_IO_CTRL, LM3632_PWM_MASK, LM3632_PWM_MODE }, 916 +}; 917 + 918 +static u8 lm3632_enable_reg = LM3632_REG_ENABLE; 919 +static u8 lm3632_brightness_msb_reg = LM3632_REG_BRT_MSB; 920 +static u8 lm3632_brightness_lsb_reg = LM3632_REG_BRT_LSB; 921 + 922 +static const struct ti_lmu_bl_reg lm3632_reg_info = { 923 + .init = lm3632_init_data, 924 + .num_init = ARRAY_SIZE(lm3632_init_data), 925 + .channel = lm3632_channel_data, 926 + .mode = lm3632_mode_data, 927 + .enable = &lm3632_enable_reg, 928 + .brightness_msb = &lm3632_brightness_msb_reg, 929 + .brightness_lsb = &lm3632_brightness_lsb_reg, 930 +}; 931 + 932 +/* LM3633 */ 933 +static const struct lmu_bl_reg_data lm3633_init_data[] = { 934 + { LM3633_REG_BOOST_CFG, LM3633_OVP_MASK, LM3633_OVP_40V }, 935 + { LM3633_REG_BL_RAMP_CONF, LM3633_BL_RAMP_MASK, LM3633_BL_RAMP_EACH }, 936 +}; 937 + 938 +static const struct lmu_bl_reg_data lm3633_channel_data[] = { 939 + { LM3633_REG_HVLED_OUTPUT_CFG, LM3633_HVLED1_CFG_MASK, 940 + LM3633_HVLED1_CFG_SHIFT }, 941 + { LM3633_REG_HVLED_OUTPUT_CFG, LM3633_HVLED2_CFG_MASK, 942 + LM3633_HVLED2_CFG_SHIFT }, 943 + { LM3633_REG_HVLED_OUTPUT_CFG, LM3633_HVLED3_CFG_MASK, 944 + LM3633_HVLED3_CFG_SHIFT }, 945 +}; 946 + 947 +static const struct lmu_bl_reg_data lm3633_mode_data[] = { 948 + { LM3633_REG_PWM_CFG, LM3633_PWM_A_MASK, LM3633_PWM_A_MASK }, 949 + { LM3633_REG_PWM_CFG, LM3633_PWM_B_MASK, LM3633_PWM_B_MASK }, 950 +}; 951 + 952 +static const struct lmu_bl_reg_data lm3633_ramp_data[] = { 953 + { LM3633_REG_BL0_RAMP, LM3633_BL_RAMPUP_MASK, LM3633_BL_RAMPUP_SHIFT }, 954 + { LM3633_REG_BL0_RAMP, LM3633_BL_RAMPDN_MASK, LM3633_BL_RAMPDN_SHIFT }, 955 +}; 956 + 957 +static u8 lm3633_enable_reg = LM3633_REG_ENABLE; 958 + 959 +static u8 lm3633_brightness_msb_regs[] = { 960 + LM3633_REG_BRT_HVLED_A_MSB, 961 + LM3633_REG_BRT_HVLED_B_MSB, 962 +}; 963 + 964 +static u8 lm3633_brightness_lsb_regs[] = { 965 + LM3633_REG_BRT_HVLED_A_LSB, 966 + LM3633_REG_BRT_HVLED_B_LSB, 967 +}; 968 + 969 +static const struct ti_lmu_bl_reg lm3633_reg_info = { 970 + .init = lm3633_init_data, 971 + .num_init = ARRAY_SIZE(lm3633_init_data), 972 + .channel = lm3633_channel_data, 973 + .mode = lm3633_mode_data, 974 + .ramp = lm3633_ramp_data, 975 + .ramp_reg_offset = 1, /* For LM3633_REG_BL1_RAMPUP/DN */ 976 + .enable = &lm3633_enable_reg, 977 + .brightness_msb = lm3633_brightness_msb_regs, 978 + .brightness_lsb = lm3633_brightness_lsb_regs, 979 +}; 980 + 981 +/* LM3695 */ 982 +static const struct lmu_bl_reg_data lm3695_init_data[] = { 983 + { LM3695_REG_GP, LM3695_BRT_RW_MASK, LM3695_BRT_RW_MASK }, 984 +}; 985 + 986 +static const struct lmu_bl_reg_data lm3695_channel_data[] = { 987 + { LM3695_REG_GP, LM3695_BL_CHANNEL_MASK, LM3695_BL_SINGLE_CHANNEL }, 988 + { LM3695_REG_GP, LM3695_BL_CHANNEL_MASK, LM3695_BL_DUAL_CHANNEL }, 989 +}; 990 + 991 +static u8 lm3695_enable_reg = LM3695_REG_GP; 992 +static u8 lm3695_brightness_msb_reg = LM3695_REG_BRT_MSB; 993 +static u8 lm3695_brightness_lsb_reg = LM3695_REG_BRT_LSB; 994 + 995 +static const struct ti_lmu_bl_reg lm3695_reg_info = { 996 + .init = lm3695_init_data, 997 + .num_init = ARRAY_SIZE(lm3695_init_data), 998 + .channel = lm3695_channel_data, 999 + .enable = &lm3695_enable_reg, 1000 + .enable_usec = 600, 1001 + .brightness_msb = &lm3695_brightness_msb_reg, 1002 + .brightness_lsb = &lm3695_brightness_lsb_reg, 1003 +}; 1004 + 1005 +/* LM3697 */ 1006 +static const struct lmu_bl_reg_data lm3697_init_data[] = { 1007 + { LM3697_REG_RAMP_CONF, LM3697_RAMP_MASK, LM3697_RAMP_EACH }, 1008 +}; 1009 + 1010 +static const struct lmu_bl_reg_data lm3697_channel_data[] = { 1011 + { LM3697_REG_HVLED_OUTPUT_CFG, LM3697_HVLED1_CFG_MASK, 1012 + LM3697_HVLED1_CFG_SHIFT }, 1013 + { LM3697_REG_HVLED_OUTPUT_CFG, LM3697_HVLED2_CFG_MASK, 1014 + LM3697_HVLED2_CFG_SHIFT }, 1015 + { LM3697_REG_HVLED_OUTPUT_CFG, LM3697_HVLED3_CFG_MASK, 1016 + LM3697_HVLED3_CFG_SHIFT }, 1017 +}; 1018 + 1019 +static const struct lmu_bl_reg_data lm3697_mode_data[] = { 1020 + { LM3697_REG_PWM_CFG, LM3697_PWM_A_MASK, LM3697_PWM_A_MASK }, 1021 + { LM3697_REG_PWM_CFG, LM3697_PWM_B_MASK, LM3697_PWM_B_MASK }, 1022 +}; 1023 + 1024 +static const struct lmu_bl_reg_data lm3697_ramp_data[] = { 1025 + { LM3697_REG_BL0_RAMP, LM3697_RAMPUP_MASK, LM3697_RAMPUP_SHIFT }, 1026 + { LM3697_REG_BL0_RAMP, LM3697_RAMPDN_MASK, LM3697_RAMPDN_SHIFT }, 1027 +}; 1028 + 1029 +static u8 lm3697_enable_reg = LM3697_REG_ENABLE; 1030 + 1031 +static u8 lm3697_brightness_msb_regs[] = { 1032 + LM3697_REG_BRT_A_MSB, 1033 + LM3697_REG_BRT_B_MSB, 1034 +}; 1035 + 1036 +static u8 lm3697_brightness_lsb_regs[] = { 1037 + LM3697_REG_BRT_A_LSB, 1038 + LM3697_REG_BRT_B_LSB, 1039 +}; 1040 + 1041 +static const struct ti_lmu_bl_reg lm3697_reg_info = { 1042 + .init = lm3697_init_data, 1043 + .num_init = ARRAY_SIZE(lm3697_init_data), 1044 + .channel = lm3697_channel_data, 1045 + .mode = lm3697_mode_data, 1046 + .ramp = lm3697_ramp_data, 1047 + .ramp_reg_offset = 1, /* For LM3697_REG_BL1_RAMPUP/DN */ 1048 + .enable = &lm3697_enable_reg, 1049 + .brightness_msb = lm3697_brightness_msb_regs, 1050 + .brightness_lsb = lm3697_brightness_lsb_regs, 1051 +}; 1052 + 1053 +static int lm3532_ramp_table[] = { 0, 1, 2, 4, 8, 16, 32, 65 }; 1054 + 1055 +static int lm3631_ramp_table[] = { 1056 + 0, 1, 2, 5, 10, 20, 50, 100, 1057 + 250, 500, 750, 1000, 1500, 2000, 3000, 4000, 1058 +}; 1059 + 1060 +static int common_ramp_table[] = { 1061 + 2, 250, 500, 1000, 2000, 4000, 8000, 16000, 1062 +}; 1063 + 1064 +#define LM3532_MAX_CHANNELS 3 1065 +#define LM3631_MAX_CHANNELS 2 1066 +#define LM3632_MAX_CHANNELS 2 1067 +#define LM3633_MAX_CHANNELS 3 1068 +#define LM3695_MAX_CHANNELS 2 1069 +#define LM3697_MAX_CHANNELS 3 1070 + 1071 +const struct ti_lmu_bl_cfg lmu_bl_cfg[LMU_MAX_ID] = { 1072 + { 1073 + .reginfo = &lm3532_reg_info, 1074 + .num_channels = LM3532_MAX_CHANNELS, 1075 + .max_brightness = MAX_BRIGHTNESS_8BIT, 1076 + .pwm_action = UPDATE_PWM_AND_BRT_REGISTER, 1077 + .ramp_table = lm3532_ramp_table, 1078 + .size_ramp = ARRAY_SIZE(lm3532_ramp_table), 1079 + }, 1080 + { 1081 + .reginfo = &lm3631_reg_info, 1082 + .num_channels = LM3631_MAX_CHANNELS, 1083 + .max_brightness = MAX_BRIGHTNESS_11BIT, 1084 + .pwm_action = UPDATE_PWM_ONLY, 1085 + .ramp_table = lm3631_ramp_table, 1086 + .size_ramp = ARRAY_SIZE(lm3631_ramp_table), 1087 + }, 1088 + { 1089 + .reginfo = &lm3632_reg_info, 1090 + .num_channels = LM3632_MAX_CHANNELS, 1091 + .max_brightness = MAX_BRIGHTNESS_11BIT, 1092 + .pwm_action = UPDATE_PWM_ONLY, 1093 + }, 1094 + { 1095 + .reginfo = &lm3633_reg_info, 1096 + .num_channels = LM3633_MAX_CHANNELS, 1097 + .max_brightness = MAX_BRIGHTNESS_11BIT, 1098 + .pwm_action = UPDATE_MAX_BRT, 1099 + .ramp_table = common_ramp_table, 1100 + .size_ramp = ARRAY_SIZE(common_ramp_table), 1101 + .fault_monitor_used = true, 1102 + }, 1103 + { 1104 + .reginfo = &lm3695_reg_info, 1105 + .num_channels = LM3695_MAX_CHANNELS, 1106 + .max_brightness = MAX_BRIGHTNESS_11BIT, 1107 + .pwm_action = UPDATE_PWM_AND_BRT_REGISTER, 1108 + }, 1109 + { 1110 + .reginfo = &lm3697_reg_info, 1111 + .num_channels = LM3697_MAX_CHANNELS, 1112 + .max_brightness = MAX_BRIGHTNESS_11BIT, 1113 + .pwm_action = UPDATE_PWM_AND_BRT_REGISTER, 1114 + .ramp_table = common_ramp_table, 1115 + .size_ramp = ARRAY_SIZE(common_ramp_table), 1116 + .fault_monitor_used = true, 1117 + }, 1118 +}; 1119 diff --git a/drivers/video/backlight/ti-lmu-backlight-data.h b/drivers/video/backlight/ti-lmu-backlight-data.h 1120 new file mode 100644 1121 index 0000000..c64e8e6 1122 --- /dev/null 1123 +++ b/drivers/video/backlight/ti-lmu-backlight-data.h 1124 @@ -0,0 +1,95 @@ 1125 +/* 1126 + * TI LMU (Lighting Management Unit) Backlight Device Data Definitions 1127 + * 1128 + * Copyright 2015 Texas Instruments 1129 + * 1130 + * Author: Milo Kim <milo.kim@ti.com> 1131 + * 1132 + * This program is free software; you can redistribute it and/or modify 1133 + * it under the terms of the GNU General Public License version 2 as 1134 + * published by the Free Software Foundation. 1135 + */ 1136 + 1137 +#ifndef __TI_LMU_BACKLIGHT_H__ 1138 +#define __TI_LMU_BACKLIGHT_H__ 1139 + 1140 +#include <linux/mfd/ti-lmu.h> 1141 +#include <linux/mfd/ti-lmu-register.h> 1142 + 1143 +#define MAX_BRIGHTNESS_8BIT 255 1144 +#define MAX_BRIGHTNESS_11BIT 2047 1145 + 1146 +enum ti_lmu_bl_pwm_action { 1147 + /* Update PWM duty, no brightness register update is required */ 1148 + UPDATE_PWM_ONLY, 1149 + /* Update not only duty but also brightness register */ 1150 + UPDATE_PWM_AND_BRT_REGISTER, 1151 + /* Update max value in brightness registers */ 1152 + UPDATE_MAX_BRT, 1153 +}; 1154 + 1155 +struct lmu_bl_reg_data { 1156 + u8 reg; 1157 + u8 mask; 1158 + u8 val; 1159 +}; 1160 + 1161 +/** 1162 + * struct ti_lmu_bl_reg 1163 + * 1164 + * @init: Device initialization registers 1165 + * @num_init: Numbers of initialization registers 1166 + * @channel: Backlight channel configuration registers 1167 + * @mode: Brightness control mode registers 1168 + * @ramp: Ramp registers for lighting effect 1169 + * @ramp_reg_offset: Ramp register offset. 1170 + * Only used for multiple ramp registers. 1171 + * @enable: Enable control register address 1172 + * @enable_usec: Delay time for updating enable register. 1173 + * Unit is microsecond. 1174 + * @brightness_msb: Brightness MSB(Upper 8 bits) registers. 1175 + * Concatenated with LSB in 11 bit dimming mode. 1176 + * In 8 bit dimming, only MSB is used. 1177 + * @brightness_lsb: Brightness LSB(Lower 3 bits) registers. 1178 + * Only valid in 11 bit dimming mode. 1179 + */ 1180 +struct ti_lmu_bl_reg { 1181 + const struct lmu_bl_reg_data *init; 1182 + int num_init; 1183 + const struct lmu_bl_reg_data *channel; 1184 + const struct lmu_bl_reg_data *mode; 1185 + const struct lmu_bl_reg_data *ramp; 1186 + int ramp_reg_offset; 1187 + u8 *enable; 1188 + unsigned long enable_usec; 1189 + u8 *brightness_msb; 1190 + u8 *brightness_lsb; 1191 +}; 1192 + 1193 +/** 1194 + * struct ti_lmu_bl_cfg 1195 + * 1196 + * @reginfo: Device register configuration 1197 + * @num_channels: Number of backlight channels 1198 + * @max_brightness: Max brightness value of backlight device 1199 + * @pwm_action: How to control brightness registers in PWM mode 1200 + * @ramp_table: [Optional] Ramp time table for lighting effect. 1201 + * It's used for searching approximate register index. 1202 + * @size_ramp: [Optional] Size of ramp table 1203 + * @fault_monitor_used: [Optional] Set true if the device needs to handle 1204 + * LMU fault monitor event. 1205 + * 1206 + * This structure is used for device specific data configuration. 1207 + */ 1208 +struct ti_lmu_bl_cfg { 1209 + const struct ti_lmu_bl_reg *reginfo; 1210 + int num_channels; 1211 + int max_brightness; 1212 + enum ti_lmu_bl_pwm_action pwm_action; 1213 + int *ramp_table; 1214 + int size_ramp; 1215 + bool fault_monitor_used; 1216 +}; 1217 + 1218 +extern const struct ti_lmu_bl_cfg lmu_bl_cfg[LMU_MAX_ID]; 1219 +#endif 1220 -- 1221 2.1.4 1222