brintos

brintos / linux-shallow public Read only

0
0
Text · 13.5 KiB · 0a2409d Raw
636 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * lm3533-core.c -- LM3533 Core4 *5 * Copyright (C) 2011-2012 Texas Instruments6 *7 * Author: Johan Hovold <jhovold@gmail.com>8 */9 10#include <linux/module.h>11#include <linux/init.h>12#include <linux/kernel.h>13#include <linux/err.h>14#include <linux/gpio/consumer.h>15#include <linux/i2c.h>16#include <linux/mfd/core.h>17#include <linux/regmap.h>18#include <linux/seq_file.h>19#include <linux/slab.h>20#include <linux/uaccess.h>21 22#include <linux/mfd/lm3533.h>23 24 25#define LM3533_BOOST_OVP_MASK		0x0626#define LM3533_BOOST_OVP_SHIFT		127 28#define LM3533_BOOST_FREQ_MASK		0x0129#define LM3533_BOOST_FREQ_SHIFT		030 31#define LM3533_BL_ID_MASK		132#define LM3533_LED_ID_MASK		333#define LM3533_BL_ID_MAX		134#define LM3533_LED_ID_MAX		335 36#define LM3533_HVLED_ID_MAX		237#define LM3533_LVLED_ID_MAX		538 39#define LM3533_REG_OUTPUT_CONF1		0x1040#define LM3533_REG_OUTPUT_CONF2		0x1141#define LM3533_REG_BOOST_PWM		0x2c42 43#define LM3533_REG_MAX			0xb244 45 46static struct mfd_cell lm3533_als_devs[] = {47	{48		.name	= "lm3533-als",49		.id	= -1,50	},51};52 53static struct mfd_cell lm3533_bl_devs[] = {54	{55		.name	= "lm3533-backlight",56		.id	= 0,57	},58	{59		.name	= "lm3533-backlight",60		.id	= 1,61	},62};63 64static struct mfd_cell lm3533_led_devs[] = {65	{66		.name	= "lm3533-leds",67		.id	= 0,68	},69	{70		.name	= "lm3533-leds",71		.id	= 1,72	},73	{74		.name	= "lm3533-leds",75		.id	= 2,76	},77	{78		.name	= "lm3533-leds",79		.id	= 3,80	},81};82 83int lm3533_read(struct lm3533 *lm3533, u8 reg, u8 *val)84{85	int tmp;86	int ret;87 88	ret = regmap_read(lm3533->regmap, reg, &tmp);89	if (ret < 0) {90		dev_err(lm3533->dev, "failed to read register %02x: %d\n",91								reg, ret);92		return ret;93	}94 95	*val = tmp;96 97	dev_dbg(lm3533->dev, "read [%02x]: %02x\n", reg, *val);98 99	return ret;100}101EXPORT_SYMBOL_GPL(lm3533_read);102 103int lm3533_write(struct lm3533 *lm3533, u8 reg, u8 val)104{105	int ret;106 107	dev_dbg(lm3533->dev, "write [%02x]: %02x\n", reg, val);108 109	ret = regmap_write(lm3533->regmap, reg, val);110	if (ret < 0) {111		dev_err(lm3533->dev, "failed to write register %02x: %d\n",112								reg, ret);113	}114 115	return ret;116}117EXPORT_SYMBOL_GPL(lm3533_write);118 119int lm3533_update(struct lm3533 *lm3533, u8 reg, u8 val, u8 mask)120{121	int ret;122 123	dev_dbg(lm3533->dev, "update [%02x]: %02x/%02x\n", reg, val, mask);124 125	ret = regmap_update_bits(lm3533->regmap, reg, mask, val);126	if (ret < 0) {127		dev_err(lm3533->dev, "failed to update register %02x: %d\n",128								reg, ret);129	}130 131	return ret;132}133EXPORT_SYMBOL_GPL(lm3533_update);134 135static int lm3533_set_boost_freq(struct lm3533 *lm3533,136						enum lm3533_boost_freq freq)137{138	int ret;139 140	ret = lm3533_update(lm3533, LM3533_REG_BOOST_PWM,141					freq << LM3533_BOOST_FREQ_SHIFT,142					LM3533_BOOST_FREQ_MASK);143	if (ret)144		dev_err(lm3533->dev, "failed to set boost frequency\n");145 146	return ret;147}148 149 150static int lm3533_set_boost_ovp(struct lm3533 *lm3533,151						enum lm3533_boost_ovp ovp)152{153	int ret;154 155	ret = lm3533_update(lm3533, LM3533_REG_BOOST_PWM,156					ovp << LM3533_BOOST_OVP_SHIFT,157					LM3533_BOOST_OVP_MASK);158	if (ret)159		dev_err(lm3533->dev, "failed to set boost ovp\n");160 161	return ret;162}163 164/*165 * HVLED output config -- output hvled controlled by backlight bl166 */167static int lm3533_set_hvled_config(struct lm3533 *lm3533, u8 hvled, u8 bl)168{169	u8 val;170	u8 mask;171	int shift;172	int ret;173 174	if (hvled == 0 || hvled > LM3533_HVLED_ID_MAX)175		return -EINVAL;176 177	if (bl > LM3533_BL_ID_MAX)178		return -EINVAL;179 180	shift = hvled - 1;181	mask = LM3533_BL_ID_MASK << shift;182	val = bl << shift;183 184	ret = lm3533_update(lm3533, LM3533_REG_OUTPUT_CONF1, val, mask);185	if (ret)186		dev_err(lm3533->dev, "failed to set hvled config\n");187 188	return ret;189}190 191/*192 * LVLED output config -- output lvled controlled by LED led193 */194static int lm3533_set_lvled_config(struct lm3533 *lm3533, u8 lvled, u8 led)195{196	u8 reg;197	u8 val;198	u8 mask;199	int shift;200	int ret;201 202	if (lvled == 0 || lvled > LM3533_LVLED_ID_MAX)203		return -EINVAL;204 205	if (led > LM3533_LED_ID_MAX)206		return -EINVAL;207 208	if (lvled < 4) {209		reg = LM3533_REG_OUTPUT_CONF1;210		shift = 2 * lvled;211	} else {212		reg = LM3533_REG_OUTPUT_CONF2;213		shift = 2 * (lvled - 4);214	}215 216	mask = LM3533_LED_ID_MASK << shift;217	val = led << shift;218 219	ret = lm3533_update(lm3533, reg, val, mask);220	if (ret)221		dev_err(lm3533->dev, "failed to set lvled config\n");222 223	return ret;224}225 226static void lm3533_enable(struct lm3533 *lm3533)227{228	gpiod_set_value(lm3533->hwen, 1);229}230 231static void lm3533_disable(struct lm3533 *lm3533)232{233	gpiod_set_value(lm3533->hwen, 0);234}235 236enum lm3533_attribute_type {237	LM3533_ATTR_TYPE_BACKLIGHT,238	LM3533_ATTR_TYPE_LED,239};240 241struct lm3533_device_attribute {242	struct device_attribute dev_attr;243	enum lm3533_attribute_type type;244	union {245		struct {246			u8 id;247		} output;248	} u;249};250 251#define to_lm3533_dev_attr(_attr) \252	container_of(_attr, struct lm3533_device_attribute, dev_attr)253 254static ssize_t show_output(struct device *dev,255				struct device_attribute *attr, char *buf)256{257	struct lm3533 *lm3533 = dev_get_drvdata(dev);258	struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr);259	int id = lattr->u.output.id;260	u8 reg;261	u8 val;262	u8 mask;263	int shift;264	int ret;265 266	if (lattr->type == LM3533_ATTR_TYPE_BACKLIGHT) {267		reg = LM3533_REG_OUTPUT_CONF1;268		shift = id - 1;269		mask = LM3533_BL_ID_MASK << shift;270	} else {271		if (id < 4) {272			reg = LM3533_REG_OUTPUT_CONF1;273			shift = 2 * id;274		} else {275			reg = LM3533_REG_OUTPUT_CONF2;276			shift = 2 * (id - 4);277		}278		mask = LM3533_LED_ID_MASK << shift;279	}280 281	ret = lm3533_read(lm3533, reg, &val);282	if (ret)283		return ret;284 285	val = (val & mask) >> shift;286 287	return sysfs_emit(buf, "%u\n", val);288}289 290static ssize_t store_output(struct device *dev,291					struct device_attribute *attr,292					const char *buf, size_t len)293{294	struct lm3533 *lm3533 = dev_get_drvdata(dev);295	struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr);296	int id = lattr->u.output.id;297	u8 val;298	int ret;299 300	if (kstrtou8(buf, 0, &val))301		return -EINVAL;302 303	if (lattr->type == LM3533_ATTR_TYPE_BACKLIGHT)304		ret = lm3533_set_hvled_config(lm3533, id, val);305	else306		ret = lm3533_set_lvled_config(lm3533, id, val);307 308	if (ret)309		return ret;310 311	return len;312}313 314#define LM3533_OUTPUT_ATTR(_name, _mode, _show, _store, _type, _id) \315	struct lm3533_device_attribute lm3533_dev_attr_##_name = \316		{ .dev_attr	= __ATTR(_name, _mode, _show, _store), \317		  .type		= _type, \318		  .u.output	= { .id = _id }, }319 320#define LM3533_OUTPUT_ATTR_RW(_name, _type, _id) \321	LM3533_OUTPUT_ATTR(output_##_name, S_IRUGO | S_IWUSR, \322					show_output, store_output, _type, _id)323 324#define LM3533_OUTPUT_HVLED_ATTR_RW(_nr) \325	LM3533_OUTPUT_ATTR_RW(hvled##_nr, LM3533_ATTR_TYPE_BACKLIGHT, _nr)326#define LM3533_OUTPUT_LVLED_ATTR_RW(_nr) \327	LM3533_OUTPUT_ATTR_RW(lvled##_nr, LM3533_ATTR_TYPE_LED, _nr)328/*329 * Output config:330 *331 * output_hvled<nr>	0-1332 * output_lvled<nr>	0-3333 */334static LM3533_OUTPUT_HVLED_ATTR_RW(1);335static LM3533_OUTPUT_HVLED_ATTR_RW(2);336static LM3533_OUTPUT_LVLED_ATTR_RW(1);337static LM3533_OUTPUT_LVLED_ATTR_RW(2);338static LM3533_OUTPUT_LVLED_ATTR_RW(3);339static LM3533_OUTPUT_LVLED_ATTR_RW(4);340static LM3533_OUTPUT_LVLED_ATTR_RW(5);341 342static struct attribute *lm3533_attributes[] = {343	&lm3533_dev_attr_output_hvled1.dev_attr.attr,344	&lm3533_dev_attr_output_hvled2.dev_attr.attr,345	&lm3533_dev_attr_output_lvled1.dev_attr.attr,346	&lm3533_dev_attr_output_lvled2.dev_attr.attr,347	&lm3533_dev_attr_output_lvled3.dev_attr.attr,348	&lm3533_dev_attr_output_lvled4.dev_attr.attr,349	&lm3533_dev_attr_output_lvled5.dev_attr.attr,350	NULL,351};352 353#define to_dev_attr(_attr) \354	container_of(_attr, struct device_attribute, attr)355 356static umode_t lm3533_attr_is_visible(struct kobject *kobj,357					     struct attribute *attr, int n)358{359	struct device *dev = kobj_to_dev(kobj);360	struct lm3533 *lm3533 = dev_get_drvdata(dev);361	struct device_attribute *dattr = to_dev_attr(attr);362	struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(dattr);363	enum lm3533_attribute_type type = lattr->type;364	umode_t mode = attr->mode;365 366	if (!lm3533->have_backlights && type == LM3533_ATTR_TYPE_BACKLIGHT)367		mode = 0;368	else if (!lm3533->have_leds && type == LM3533_ATTR_TYPE_LED)369		mode = 0;370 371	return mode;372};373 374static struct attribute_group lm3533_attribute_group = {375	.is_visible	= lm3533_attr_is_visible,376	.attrs		= lm3533_attributes377};378 379static int lm3533_device_als_init(struct lm3533 *lm3533)380{381	struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);382	int ret;383 384	if (!pdata->als)385		return 0;386 387	lm3533_als_devs[0].platform_data = pdata->als;388	lm3533_als_devs[0].pdata_size = sizeof(*pdata->als);389 390	ret = mfd_add_devices(lm3533->dev, 0, lm3533_als_devs, 1, NULL,391			      0, NULL);392	if (ret) {393		dev_err(lm3533->dev, "failed to add ALS device\n");394		return ret;395	}396 397	lm3533->have_als = 1;398 399	return 0;400}401 402static int lm3533_device_bl_init(struct lm3533 *lm3533)403{404	struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);405	int i;406	int ret;407 408	if (!pdata->backlights || pdata->num_backlights == 0)409		return 0;410 411	if (pdata->num_backlights > ARRAY_SIZE(lm3533_bl_devs))412		pdata->num_backlights = ARRAY_SIZE(lm3533_bl_devs);413 414	for (i = 0; i < pdata->num_backlights; ++i) {415		lm3533_bl_devs[i].platform_data = &pdata->backlights[i];416		lm3533_bl_devs[i].pdata_size = sizeof(pdata->backlights[i]);417	}418 419	ret = mfd_add_devices(lm3533->dev, 0, lm3533_bl_devs,420			      pdata->num_backlights, NULL, 0, NULL);421	if (ret) {422		dev_err(lm3533->dev, "failed to add backlight devices\n");423		return ret;424	}425 426	lm3533->have_backlights = 1;427 428	return 0;429}430 431static int lm3533_device_led_init(struct lm3533 *lm3533)432{433	struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);434	int i;435	int ret;436 437	if (!pdata->leds || pdata->num_leds == 0)438		return 0;439 440	if (pdata->num_leds > ARRAY_SIZE(lm3533_led_devs))441		pdata->num_leds = ARRAY_SIZE(lm3533_led_devs);442 443	for (i = 0; i < pdata->num_leds; ++i) {444		lm3533_led_devs[i].platform_data = &pdata->leds[i];445		lm3533_led_devs[i].pdata_size = sizeof(pdata->leds[i]);446	}447 448	ret = mfd_add_devices(lm3533->dev, 0, lm3533_led_devs,449			      pdata->num_leds, NULL, 0, NULL);450	if (ret) {451		dev_err(lm3533->dev, "failed to add LED devices\n");452		return ret;453	}454 455	lm3533->have_leds = 1;456 457	return 0;458}459 460static int lm3533_device_setup(struct lm3533 *lm3533,461					struct lm3533_platform_data *pdata)462{463	int ret;464 465	ret = lm3533_set_boost_freq(lm3533, pdata->boost_freq);466	if (ret)467		return ret;468 469	return lm3533_set_boost_ovp(lm3533, pdata->boost_ovp);470}471 472static int lm3533_device_init(struct lm3533 *lm3533)473{474	struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);475	int ret;476 477	dev_dbg(lm3533->dev, "%s\n", __func__);478 479	if (!pdata) {480		dev_err(lm3533->dev, "no platform data\n");481		return -EINVAL;482	}483 484	lm3533->hwen = devm_gpiod_get(lm3533->dev, NULL, GPIOD_OUT_LOW);485	if (IS_ERR(lm3533->hwen))486		return dev_err_probe(lm3533->dev, PTR_ERR(lm3533->hwen), "failed to request HWEN GPIO\n");487	gpiod_set_consumer_name(lm3533->hwen, "lm3533-hwen");488 489	lm3533_enable(lm3533);490 491	ret = lm3533_device_setup(lm3533, pdata);492	if (ret)493		goto err_disable;494 495	lm3533_device_als_init(lm3533);496	lm3533_device_bl_init(lm3533);497	lm3533_device_led_init(lm3533);498 499	ret = sysfs_create_group(&lm3533->dev->kobj, &lm3533_attribute_group);500	if (ret < 0) {501		dev_err(lm3533->dev, "failed to create sysfs attributes\n");502		goto err_unregister;503	}504 505	return 0;506 507err_unregister:508	mfd_remove_devices(lm3533->dev);509err_disable:510	lm3533_disable(lm3533);511 512	return ret;513}514 515static void lm3533_device_exit(struct lm3533 *lm3533)516{517	dev_dbg(lm3533->dev, "%s\n", __func__);518 519	sysfs_remove_group(&lm3533->dev->kobj, &lm3533_attribute_group);520 521	mfd_remove_devices(lm3533->dev);522	lm3533_disable(lm3533);523}524 525static bool lm3533_readable_register(struct device *dev, unsigned int reg)526{527	switch (reg) {528	case 0x10 ... 0x2c:529	case 0x30 ... 0x38:530	case 0x40 ... 0x45:531	case 0x50 ... 0x57:532	case 0x60 ... 0x6e:533	case 0x70 ... 0x75:534	case 0x80 ... 0x85:535	case 0x90 ... 0x95:536	case 0xa0 ... 0xa5:537	case 0xb0 ... 0xb2:538		return true;539	default:540		return false;541	}542}543 544static bool lm3533_volatile_register(struct device *dev, unsigned int reg)545{546	switch (reg) {547	case 0x34 ... 0x36:	/* zone */548	case 0x37 ... 0x38:	/* adc */549	case 0xb0 ... 0xb1:	/* fault */550		return true;551	default:552		return false;553	}554}555 556static bool lm3533_precious_register(struct device *dev, unsigned int reg)557{558	switch (reg) {559	case 0x34:		/* zone */560		return true;561	default:562		return false;563	}564}565 566static const struct regmap_config regmap_config = {567	.reg_bits	= 8,568	.val_bits	= 8,569	.max_register	= LM3533_REG_MAX,570	.readable_reg	= lm3533_readable_register,571	.volatile_reg	= lm3533_volatile_register,572	.precious_reg	= lm3533_precious_register,573};574 575static int lm3533_i2c_probe(struct i2c_client *i2c)576{577	struct lm3533 *lm3533;578 579	dev_dbg(&i2c->dev, "%s\n", __func__);580 581	lm3533 = devm_kzalloc(&i2c->dev, sizeof(*lm3533), GFP_KERNEL);582	if (!lm3533)583		return -ENOMEM;584 585	i2c_set_clientdata(i2c, lm3533);586 587	lm3533->regmap = devm_regmap_init_i2c(i2c, &regmap_config);588	if (IS_ERR(lm3533->regmap))589		return PTR_ERR(lm3533->regmap);590 591	lm3533->dev = &i2c->dev;592	lm3533->irq = i2c->irq;593 594	return lm3533_device_init(lm3533);595}596 597static void lm3533_i2c_remove(struct i2c_client *i2c)598{599	struct lm3533 *lm3533 = i2c_get_clientdata(i2c);600 601	dev_dbg(&i2c->dev, "%s\n", __func__);602 603	lm3533_device_exit(lm3533);604}605 606static const struct i2c_device_id lm3533_i2c_ids[] = {607	{ "lm3533" },608	{ }609};610MODULE_DEVICE_TABLE(i2c, lm3533_i2c_ids);611 612static struct i2c_driver lm3533_i2c_driver = {613	.driver = {614		   .name = "lm3533",615	},616	.id_table	= lm3533_i2c_ids,617	.probe		= lm3533_i2c_probe,618	.remove		= lm3533_i2c_remove,619};620 621static int __init lm3533_i2c_init(void)622{623	return i2c_add_driver(&lm3533_i2c_driver);624}625subsys_initcall(lm3533_i2c_init);626 627static void __exit lm3533_i2c_exit(void)628{629	i2c_del_driver(&lm3533_i2c_driver);630}631module_exit(lm3533_i2c_exit);632 633MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>");634MODULE_DESCRIPTION("LM3533 Core");635MODULE_LICENSE("GPL");636