arm-sdk

os build toolkit for various embedded devices
git clone https://git.parazyd.org/arm-sdk
Log | Files | Refs | Submodules | README | LICENSE

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