cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

lp855x_bl.c (13607B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * TI LP855x Backlight Driver
      4 *
      5 *			Copyright (C) 2011 Texas Instruments
      6 */
      7
      8#include <linux/acpi.h>
      9#include <linux/module.h>
     10#include <linux/slab.h>
     11#include <linux/i2c.h>
     12#include <linux/backlight.h>
     13#include <linux/delay.h>
     14#include <linux/err.h>
     15#include <linux/of.h>
     16#include <linux/platform_data/lp855x.h>
     17#include <linux/pwm.h>
     18#include <linux/regulator/consumer.h>
     19
     20/* LP8550/1/2/3/6 Registers */
     21#define LP855X_BRIGHTNESS_CTRL		0x00
     22#define LP855X_DEVICE_CTRL		0x01
     23#define LP855X_EEPROM_START		0xA0
     24#define LP855X_EEPROM_END		0xA7
     25#define LP8556_EPROM_START		0xA0
     26#define LP8556_EPROM_END		0xAF
     27
     28/* LP8555/7 Registers */
     29#define LP8557_BL_CMD			0x00
     30#define LP8557_BL_MASK			0x01
     31#define LP8557_BL_ON			0x01
     32#define LP8557_BL_OFF			0x00
     33#define LP8557_BRIGHTNESS_CTRL		0x04
     34#define LP8557_CONFIG			0x10
     35#define LP8555_EPROM_START		0x10
     36#define LP8555_EPROM_END		0x7A
     37#define LP8557_EPROM_START		0x10
     38#define LP8557_EPROM_END		0x1E
     39
     40#define DEFAULT_BL_NAME		"lcd-backlight"
     41#define MAX_BRIGHTNESS		255
     42
     43enum lp855x_brightness_ctrl_mode {
     44	PWM_BASED = 1,
     45	REGISTER_BASED,
     46};
     47
     48struct lp855x;
     49
     50/*
     51 * struct lp855x_device_config
     52 * @pre_init_device: init device function call before updating the brightness
     53 * @reg_brightness: register address for brigthenss control
     54 * @reg_devicectrl: register address for device control
     55 * @post_init_device: late init device function call
     56 */
     57struct lp855x_device_config {
     58	int (*pre_init_device)(struct lp855x *);
     59	u8 reg_brightness;
     60	u8 reg_devicectrl;
     61	int (*post_init_device)(struct lp855x *);
     62};
     63
     64struct lp855x {
     65	const char *chipname;
     66	enum lp855x_chip_id chip_id;
     67	enum lp855x_brightness_ctrl_mode mode;
     68	struct lp855x_device_config *cfg;
     69	struct i2c_client *client;
     70	struct backlight_device *bl;
     71	struct device *dev;
     72	struct lp855x_platform_data *pdata;
     73	struct pwm_device *pwm;
     74	struct regulator *supply;	/* regulator for VDD input */
     75	struct regulator *enable;	/* regulator for EN/VDDIO input */
     76};
     77
     78static int lp855x_write_byte(struct lp855x *lp, u8 reg, u8 data)
     79{
     80	return i2c_smbus_write_byte_data(lp->client, reg, data);
     81}
     82
     83static int lp855x_update_bit(struct lp855x *lp, u8 reg, u8 mask, u8 data)
     84{
     85	int ret;
     86	u8 tmp;
     87
     88	ret = i2c_smbus_read_byte_data(lp->client, reg);
     89	if (ret < 0) {
     90		dev_err(lp->dev, "failed to read 0x%.2x\n", reg);
     91		return ret;
     92	}
     93
     94	tmp = (u8)ret;
     95	tmp &= ~mask;
     96	tmp |= data & mask;
     97
     98	return lp855x_write_byte(lp, reg, tmp);
     99}
    100
    101static bool lp855x_is_valid_rom_area(struct lp855x *lp, u8 addr)
    102{
    103	u8 start, end;
    104
    105	switch (lp->chip_id) {
    106	case LP8550:
    107	case LP8551:
    108	case LP8552:
    109	case LP8553:
    110		start = LP855X_EEPROM_START;
    111		end = LP855X_EEPROM_END;
    112		break;
    113	case LP8556:
    114		start = LP8556_EPROM_START;
    115		end = LP8556_EPROM_END;
    116		break;
    117	case LP8555:
    118		start = LP8555_EPROM_START;
    119		end = LP8555_EPROM_END;
    120		break;
    121	case LP8557:
    122		start = LP8557_EPROM_START;
    123		end = LP8557_EPROM_END;
    124		break;
    125	default:
    126		return false;
    127	}
    128
    129	return addr >= start && addr <= end;
    130}
    131
    132static int lp8557_bl_off(struct lp855x *lp)
    133{
    134	/* BL_ON = 0 before updating EPROM settings */
    135	return lp855x_update_bit(lp, LP8557_BL_CMD, LP8557_BL_MASK,
    136				LP8557_BL_OFF);
    137}
    138
    139static int lp8557_bl_on(struct lp855x *lp)
    140{
    141	/* BL_ON = 1 after updating EPROM settings */
    142	return lp855x_update_bit(lp, LP8557_BL_CMD, LP8557_BL_MASK,
    143				LP8557_BL_ON);
    144}
    145
    146static struct lp855x_device_config lp855x_dev_cfg = {
    147	.reg_brightness = LP855X_BRIGHTNESS_CTRL,
    148	.reg_devicectrl = LP855X_DEVICE_CTRL,
    149};
    150
    151static struct lp855x_device_config lp8557_dev_cfg = {
    152	.reg_brightness = LP8557_BRIGHTNESS_CTRL,
    153	.reg_devicectrl = LP8557_CONFIG,
    154	.pre_init_device = lp8557_bl_off,
    155	.post_init_device = lp8557_bl_on,
    156};
    157
    158/*
    159 * Device specific configuration flow
    160 *
    161 *    a) pre_init_device(optional)
    162 *    b) update the brightness register
    163 *    c) update device control register
    164 *    d) update ROM area(optional)
    165 *    e) post_init_device(optional)
    166 *
    167 */
    168static int lp855x_configure(struct lp855x *lp)
    169{
    170	u8 val, addr;
    171	int i, ret;
    172	struct lp855x_platform_data *pd = lp->pdata;
    173
    174	if (lp->cfg->pre_init_device) {
    175		ret = lp->cfg->pre_init_device(lp);
    176		if (ret) {
    177			dev_err(lp->dev, "pre init device err: %d\n", ret);
    178			goto err;
    179		}
    180	}
    181
    182	val = pd->initial_brightness;
    183	ret = lp855x_write_byte(lp, lp->cfg->reg_brightness, val);
    184	if (ret)
    185		goto err;
    186
    187	val = pd->device_control;
    188	ret = lp855x_write_byte(lp, lp->cfg->reg_devicectrl, val);
    189	if (ret)
    190		goto err;
    191
    192	if (pd->size_program > 0) {
    193		for (i = 0; i < pd->size_program; i++) {
    194			addr = pd->rom_data[i].addr;
    195			val = pd->rom_data[i].val;
    196			if (!lp855x_is_valid_rom_area(lp, addr))
    197				continue;
    198
    199			ret = lp855x_write_byte(lp, addr, val);
    200			if (ret)
    201				goto err;
    202		}
    203	}
    204
    205	if (lp->cfg->post_init_device) {
    206		ret = lp->cfg->post_init_device(lp);
    207		if (ret) {
    208			dev_err(lp->dev, "post init device err: %d\n", ret);
    209			goto err;
    210		}
    211	}
    212
    213	return 0;
    214
    215err:
    216	return ret;
    217}
    218
    219static void lp855x_pwm_ctrl(struct lp855x *lp, int br, int max_br)
    220{
    221	unsigned int period = lp->pdata->period_ns;
    222	unsigned int duty = br * period / max_br;
    223	struct pwm_device *pwm;
    224
    225	/* request pwm device with the consumer name */
    226	if (!lp->pwm) {
    227		pwm = devm_pwm_get(lp->dev, lp->chipname);
    228		if (IS_ERR(pwm))
    229			return;
    230
    231		lp->pwm = pwm;
    232
    233		/*
    234		 * FIXME: pwm_apply_args() should be removed when switching to
    235		 * the atomic PWM API.
    236		 */
    237		pwm_apply_args(pwm);
    238	}
    239
    240	pwm_config(lp->pwm, duty, period);
    241	if (duty)
    242		pwm_enable(lp->pwm);
    243	else
    244		pwm_disable(lp->pwm);
    245}
    246
    247static int lp855x_bl_update_status(struct backlight_device *bl)
    248{
    249	struct lp855x *lp = bl_get_data(bl);
    250	int brightness = bl->props.brightness;
    251
    252	if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
    253		brightness = 0;
    254
    255	if (lp->mode == PWM_BASED)
    256		lp855x_pwm_ctrl(lp, brightness, bl->props.max_brightness);
    257	else if (lp->mode == REGISTER_BASED)
    258		lp855x_write_byte(lp, lp->cfg->reg_brightness, (u8)brightness);
    259
    260	return 0;
    261}
    262
    263static const struct backlight_ops lp855x_bl_ops = {
    264	.options = BL_CORE_SUSPENDRESUME,
    265	.update_status = lp855x_bl_update_status,
    266};
    267
    268static int lp855x_backlight_register(struct lp855x *lp)
    269{
    270	struct backlight_device *bl;
    271	struct backlight_properties props;
    272	struct lp855x_platform_data *pdata = lp->pdata;
    273	const char *name = pdata->name ? : DEFAULT_BL_NAME;
    274
    275	memset(&props, 0, sizeof(props));
    276	props.type = BACKLIGHT_PLATFORM;
    277	props.max_brightness = MAX_BRIGHTNESS;
    278
    279	if (pdata->initial_brightness > props.max_brightness)
    280		pdata->initial_brightness = props.max_brightness;
    281
    282	props.brightness = pdata->initial_brightness;
    283
    284	bl = devm_backlight_device_register(lp->dev, name, lp->dev, lp,
    285				       &lp855x_bl_ops, &props);
    286	if (IS_ERR(bl))
    287		return PTR_ERR(bl);
    288
    289	lp->bl = bl;
    290
    291	return 0;
    292}
    293
    294static ssize_t lp855x_get_chip_id(struct device *dev,
    295				struct device_attribute *attr, char *buf)
    296{
    297	struct lp855x *lp = dev_get_drvdata(dev);
    298
    299	return scnprintf(buf, PAGE_SIZE, "%s\n", lp->chipname);
    300}
    301
    302static ssize_t lp855x_get_bl_ctl_mode(struct device *dev,
    303				     struct device_attribute *attr, char *buf)
    304{
    305	struct lp855x *lp = dev_get_drvdata(dev);
    306	char *strmode = NULL;
    307
    308	if (lp->mode == PWM_BASED)
    309		strmode = "pwm based";
    310	else if (lp->mode == REGISTER_BASED)
    311		strmode = "register based";
    312
    313	return scnprintf(buf, PAGE_SIZE, "%s\n", strmode);
    314}
    315
    316static DEVICE_ATTR(chip_id, S_IRUGO, lp855x_get_chip_id, NULL);
    317static DEVICE_ATTR(bl_ctl_mode, S_IRUGO, lp855x_get_bl_ctl_mode, NULL);
    318
    319static struct attribute *lp855x_attributes[] = {
    320	&dev_attr_chip_id.attr,
    321	&dev_attr_bl_ctl_mode.attr,
    322	NULL,
    323};
    324
    325static const struct attribute_group lp855x_attr_group = {
    326	.attrs = lp855x_attributes,
    327};
    328
    329#ifdef CONFIG_OF
    330static int lp855x_parse_dt(struct lp855x *lp)
    331{
    332	struct device *dev = lp->dev;
    333	struct device_node *node = dev->of_node;
    334	struct lp855x_platform_data *pdata = lp->pdata;
    335	int rom_length;
    336
    337	if (!node) {
    338		dev_err(dev, "no platform data\n");
    339		return -EINVAL;
    340	}
    341
    342	of_property_read_string(node, "bl-name", &pdata->name);
    343	of_property_read_u8(node, "dev-ctrl", &pdata->device_control);
    344	of_property_read_u8(node, "init-brt", &pdata->initial_brightness);
    345	of_property_read_u32(node, "pwm-period", &pdata->period_ns);
    346
    347	/* Fill ROM platform data if defined */
    348	rom_length = of_get_child_count(node);
    349	if (rom_length > 0) {
    350		struct lp855x_rom_data *rom;
    351		struct device_node *child;
    352		int i = 0;
    353
    354		rom = devm_kcalloc(dev, rom_length, sizeof(*rom), GFP_KERNEL);
    355		if (!rom)
    356			return -ENOMEM;
    357
    358		for_each_child_of_node(node, child) {
    359			of_property_read_u8(child, "rom-addr", &rom[i].addr);
    360			of_property_read_u8(child, "rom-val", &rom[i].val);
    361			i++;
    362		}
    363
    364		pdata->size_program = rom_length;
    365		pdata->rom_data = &rom[0];
    366	}
    367
    368	return 0;
    369}
    370#else
    371static int lp855x_parse_dt(struct lp855x *lp)
    372{
    373	return -EINVAL;
    374}
    375#endif
    376
    377static int lp855x_parse_acpi(struct lp855x *lp)
    378{
    379	int ret;
    380
    381	/*
    382	 * On ACPI the device has already been initialized by the firmware
    383	 * and is in register mode, so we can read back the settings from
    384	 * the registers.
    385	 */
    386	ret = i2c_smbus_read_byte_data(lp->client, lp->cfg->reg_brightness);
    387	if (ret < 0)
    388		return ret;
    389
    390	lp->pdata->initial_brightness = ret;
    391
    392	ret = i2c_smbus_read_byte_data(lp->client, lp->cfg->reg_devicectrl);
    393	if (ret < 0)
    394		return ret;
    395
    396	lp->pdata->device_control = ret;
    397	return 0;
    398}
    399
    400static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
    401{
    402	const struct acpi_device_id *acpi_id = NULL;
    403	struct device *dev = &cl->dev;
    404	struct lp855x *lp;
    405	int ret;
    406
    407	if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
    408		return -EIO;
    409
    410	lp = devm_kzalloc(dev, sizeof(struct lp855x), GFP_KERNEL);
    411	if (!lp)
    412		return -ENOMEM;
    413
    414	lp->client = cl;
    415	lp->dev = dev;
    416	lp->pdata = dev_get_platdata(dev);
    417
    418	if (id) {
    419		lp->chipname = id->name;
    420		lp->chip_id = id->driver_data;
    421	} else {
    422		acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
    423		if (!acpi_id)
    424			return -ENODEV;
    425
    426		lp->chipname = acpi_id->id;
    427		lp->chip_id = acpi_id->driver_data;
    428	}
    429
    430	switch (lp->chip_id) {
    431	case LP8550:
    432	case LP8551:
    433	case LP8552:
    434	case LP8553:
    435	case LP8556:
    436		lp->cfg = &lp855x_dev_cfg;
    437		break;
    438	case LP8555:
    439	case LP8557:
    440		lp->cfg = &lp8557_dev_cfg;
    441		break;
    442	default:
    443		return -EINVAL;
    444	}
    445
    446	if (!lp->pdata) {
    447		lp->pdata = devm_kzalloc(dev, sizeof(*lp->pdata), GFP_KERNEL);
    448		if (!lp->pdata)
    449			return -ENOMEM;
    450
    451		if (id) {
    452			ret = lp855x_parse_dt(lp);
    453			if (ret < 0)
    454				return ret;
    455		} else {
    456			ret = lp855x_parse_acpi(lp);
    457			if (ret < 0)
    458				return ret;
    459		}
    460	}
    461
    462	if (lp->pdata->period_ns > 0)
    463		lp->mode = PWM_BASED;
    464	else
    465		lp->mode = REGISTER_BASED;
    466
    467	lp->supply = devm_regulator_get(dev, "power");
    468	if (IS_ERR(lp->supply)) {
    469		if (PTR_ERR(lp->supply) == -EPROBE_DEFER)
    470			return -EPROBE_DEFER;
    471		lp->supply = NULL;
    472	}
    473
    474	lp->enable = devm_regulator_get_optional(dev, "enable");
    475	if (IS_ERR(lp->enable)) {
    476		ret = PTR_ERR(lp->enable);
    477		if (ret == -ENODEV) {
    478			lp->enable = NULL;
    479		} else {
    480			return dev_err_probe(dev, ret, "getting enable regulator\n");
    481		}
    482	}
    483
    484	if (lp->supply) {
    485		ret = regulator_enable(lp->supply);
    486		if (ret < 0) {
    487			dev_err(dev, "failed to enable supply: %d\n", ret);
    488			return ret;
    489		}
    490	}
    491
    492	if (lp->enable) {
    493		ret = regulator_enable(lp->enable);
    494		if (ret < 0) {
    495			dev_err(dev, "failed to enable vddio: %d\n", ret);
    496			goto disable_supply;
    497		}
    498
    499		/*
    500		 * LP8555 datasheet says t_RESPONSE (time between VDDIO and
    501		 * I2C) is 1ms.
    502		 */
    503		usleep_range(1000, 2000);
    504	}
    505
    506	i2c_set_clientdata(cl, lp);
    507
    508	ret = lp855x_configure(lp);
    509	if (ret) {
    510		dev_err(dev, "device config err: %d", ret);
    511		goto disable_vddio;
    512	}
    513
    514	ret = lp855x_backlight_register(lp);
    515	if (ret) {
    516		dev_err(dev, "failed to register backlight. err: %d\n", ret);
    517		goto disable_vddio;
    518	}
    519
    520	ret = sysfs_create_group(&dev->kobj, &lp855x_attr_group);
    521	if (ret) {
    522		dev_err(dev, "failed to register sysfs. err: %d\n", ret);
    523		goto disable_vddio;
    524	}
    525
    526	backlight_update_status(lp->bl);
    527
    528	return 0;
    529
    530disable_vddio:
    531	if (lp->enable)
    532		regulator_disable(lp->enable);
    533disable_supply:
    534	if (lp->supply)
    535		regulator_disable(lp->supply);
    536
    537	return ret;
    538}
    539
    540static int lp855x_remove(struct i2c_client *cl)
    541{
    542	struct lp855x *lp = i2c_get_clientdata(cl);
    543
    544	lp->bl->props.brightness = 0;
    545	backlight_update_status(lp->bl);
    546	if (lp->enable)
    547		regulator_disable(lp->enable);
    548	if (lp->supply)
    549		regulator_disable(lp->supply);
    550	sysfs_remove_group(&lp->dev->kobj, &lp855x_attr_group);
    551
    552	return 0;
    553}
    554
    555static const struct of_device_id lp855x_dt_ids[] = {
    556	{ .compatible = "ti,lp8550", },
    557	{ .compatible = "ti,lp8551", },
    558	{ .compatible = "ti,lp8552", },
    559	{ .compatible = "ti,lp8553", },
    560	{ .compatible = "ti,lp8555", },
    561	{ .compatible = "ti,lp8556", },
    562	{ .compatible = "ti,lp8557", },
    563	{ }
    564};
    565MODULE_DEVICE_TABLE(of, lp855x_dt_ids);
    566
    567static const struct i2c_device_id lp855x_ids[] = {
    568	{"lp8550", LP8550},
    569	{"lp8551", LP8551},
    570	{"lp8552", LP8552},
    571	{"lp8553", LP8553},
    572	{"lp8555", LP8555},
    573	{"lp8556", LP8556},
    574	{"lp8557", LP8557},
    575	{ }
    576};
    577MODULE_DEVICE_TABLE(i2c, lp855x_ids);
    578
    579#ifdef CONFIG_ACPI
    580static const struct acpi_device_id lp855x_acpi_match[] = {
    581	/* Xiaomi specific HID used for the LP8556 on the Mi Pad 2 */
    582	{ "XMCC0001", LP8556 },
    583	{ }
    584};
    585MODULE_DEVICE_TABLE(acpi, lp855x_acpi_match);
    586#endif
    587
    588static struct i2c_driver lp855x_driver = {
    589	.driver = {
    590		   .name = "lp855x",
    591		   .of_match_table = of_match_ptr(lp855x_dt_ids),
    592		   .acpi_match_table = ACPI_PTR(lp855x_acpi_match),
    593		   },
    594	.probe = lp855x_probe,
    595	.remove = lp855x_remove,
    596	.id_table = lp855x_ids,
    597};
    598
    599module_i2c_driver(lp855x_driver);
    600
    601MODULE_DESCRIPTION("Texas Instruments LP855x Backlight driver");
    602MODULE_AUTHOR("Milo Kim <milo.kim@ti.com>");
    603MODULE_LICENSE("GPL");