xref: /openbmc/linux/drivers/mfd/lm3533-core.c (revision 9816d859)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
216c5c023SJohan Hovold /*
316c5c023SJohan Hovold  * lm3533-core.c -- LM3533 Core
416c5c023SJohan Hovold  *
516c5c023SJohan Hovold  * Copyright (C) 2011-2012 Texas Instruments
616c5c023SJohan Hovold  *
716c5c023SJohan Hovold  * Author: Johan Hovold <jhovold@gmail.com>
816c5c023SJohan Hovold  */
916c5c023SJohan Hovold 
1016c5c023SJohan Hovold #include <linux/module.h>
1116c5c023SJohan Hovold #include <linux/init.h>
1216c5c023SJohan Hovold #include <linux/kernel.h>
1316c5c023SJohan Hovold #include <linux/err.h>
1416c5c023SJohan Hovold #include <linux/gpio.h>
1516c5c023SJohan Hovold #include <linux/i2c.h>
1616c5c023SJohan Hovold #include <linux/mfd/core.h>
1716c5c023SJohan Hovold #include <linux/regmap.h>
1816c5c023SJohan Hovold #include <linux/seq_file.h>
1916c5c023SJohan Hovold #include <linux/slab.h>
2016c5c023SJohan Hovold #include <linux/uaccess.h>
2116c5c023SJohan Hovold 
2216c5c023SJohan Hovold #include <linux/mfd/lm3533.h>
2316c5c023SJohan Hovold 
2416c5c023SJohan Hovold 
2516c5c023SJohan Hovold #define LM3533_BOOST_OVP_MASK		0x06
2616c5c023SJohan Hovold #define LM3533_BOOST_OVP_SHIFT		1
2716c5c023SJohan Hovold 
2816c5c023SJohan Hovold #define LM3533_BOOST_FREQ_MASK		0x01
2916c5c023SJohan Hovold #define LM3533_BOOST_FREQ_SHIFT		0
3016c5c023SJohan Hovold 
3116c5c023SJohan Hovold #define LM3533_BL_ID_MASK		1
3216c5c023SJohan Hovold #define LM3533_LED_ID_MASK		3
3316c5c023SJohan Hovold #define LM3533_BL_ID_MAX		1
3416c5c023SJohan Hovold #define LM3533_LED_ID_MAX		3
3516c5c023SJohan Hovold 
3616c5c023SJohan Hovold #define LM3533_HVLED_ID_MAX		2
3716c5c023SJohan Hovold #define LM3533_LVLED_ID_MAX		5
3816c5c023SJohan Hovold 
3916c5c023SJohan Hovold #define LM3533_REG_OUTPUT_CONF1		0x10
4016c5c023SJohan Hovold #define LM3533_REG_OUTPUT_CONF2		0x11
4116c5c023SJohan Hovold #define LM3533_REG_BOOST_PWM		0x2c
4216c5c023SJohan Hovold 
4316c5c023SJohan Hovold #define LM3533_REG_MAX			0xb2
4416c5c023SJohan Hovold 
4516c5c023SJohan Hovold 
4616c5c023SJohan Hovold static struct mfd_cell lm3533_als_devs[] = {
4716c5c023SJohan Hovold 	{
4816c5c023SJohan Hovold 		.name	= "lm3533-als",
4916c5c023SJohan Hovold 		.id	= -1,
5016c5c023SJohan Hovold 	},
5116c5c023SJohan Hovold };
5216c5c023SJohan Hovold 
5316c5c023SJohan Hovold static struct mfd_cell lm3533_bl_devs[] = {
5416c5c023SJohan Hovold 	{
5516c5c023SJohan Hovold 		.name	= "lm3533-backlight",
5616c5c023SJohan Hovold 		.id	= 0,
5716c5c023SJohan Hovold 	},
5816c5c023SJohan Hovold 	{
5916c5c023SJohan Hovold 		.name	= "lm3533-backlight",
6016c5c023SJohan Hovold 		.id	= 1,
6116c5c023SJohan Hovold 	},
6216c5c023SJohan Hovold };
6316c5c023SJohan Hovold 
6416c5c023SJohan Hovold static struct mfd_cell lm3533_led_devs[] = {
6516c5c023SJohan Hovold 	{
6616c5c023SJohan Hovold 		.name	= "lm3533-leds",
6716c5c023SJohan Hovold 		.id	= 0,
6816c5c023SJohan Hovold 	},
6916c5c023SJohan Hovold 	{
7016c5c023SJohan Hovold 		.name	= "lm3533-leds",
7116c5c023SJohan Hovold 		.id	= 1,
7216c5c023SJohan Hovold 	},
7316c5c023SJohan Hovold 	{
7416c5c023SJohan Hovold 		.name	= "lm3533-leds",
7516c5c023SJohan Hovold 		.id	= 2,
7616c5c023SJohan Hovold 	},
7716c5c023SJohan Hovold 	{
7816c5c023SJohan Hovold 		.name	= "lm3533-leds",
7916c5c023SJohan Hovold 		.id	= 3,
8016c5c023SJohan Hovold 	},
8116c5c023SJohan Hovold };
8216c5c023SJohan Hovold 
lm3533_read(struct lm3533 * lm3533,u8 reg,u8 * val)8316c5c023SJohan Hovold int lm3533_read(struct lm3533 *lm3533, u8 reg, u8 *val)
8416c5c023SJohan Hovold {
8516c5c023SJohan Hovold 	int tmp;
8616c5c023SJohan Hovold 	int ret;
8716c5c023SJohan Hovold 
8816c5c023SJohan Hovold 	ret = regmap_read(lm3533->regmap, reg, &tmp);
8916c5c023SJohan Hovold 	if (ret < 0) {
9016c5c023SJohan Hovold 		dev_err(lm3533->dev, "failed to read register %02x: %d\n",
9116c5c023SJohan Hovold 								reg, ret);
9216c5c023SJohan Hovold 		return ret;
9316c5c023SJohan Hovold 	}
9416c5c023SJohan Hovold 
9516c5c023SJohan Hovold 	*val = tmp;
9616c5c023SJohan Hovold 
9716c5c023SJohan Hovold 	dev_dbg(lm3533->dev, "read [%02x]: %02x\n", reg, *val);
9816c5c023SJohan Hovold 
9916c5c023SJohan Hovold 	return ret;
10016c5c023SJohan Hovold }
10116c5c023SJohan Hovold EXPORT_SYMBOL_GPL(lm3533_read);
10216c5c023SJohan Hovold 
lm3533_write(struct lm3533 * lm3533,u8 reg,u8 val)10316c5c023SJohan Hovold int lm3533_write(struct lm3533 *lm3533, u8 reg, u8 val)
10416c5c023SJohan Hovold {
10516c5c023SJohan Hovold 	int ret;
10616c5c023SJohan Hovold 
10716c5c023SJohan Hovold 	dev_dbg(lm3533->dev, "write [%02x]: %02x\n", reg, val);
10816c5c023SJohan Hovold 
10916c5c023SJohan Hovold 	ret = regmap_write(lm3533->regmap, reg, val);
11016c5c023SJohan Hovold 	if (ret < 0) {
11116c5c023SJohan Hovold 		dev_err(lm3533->dev, "failed to write register %02x: %d\n",
11216c5c023SJohan Hovold 								reg, ret);
11316c5c023SJohan Hovold 	}
11416c5c023SJohan Hovold 
11516c5c023SJohan Hovold 	return ret;
11616c5c023SJohan Hovold }
11716c5c023SJohan Hovold EXPORT_SYMBOL_GPL(lm3533_write);
11816c5c023SJohan Hovold 
lm3533_update(struct lm3533 * lm3533,u8 reg,u8 val,u8 mask)11916c5c023SJohan Hovold int lm3533_update(struct lm3533 *lm3533, u8 reg, u8 val, u8 mask)
12016c5c023SJohan Hovold {
12116c5c023SJohan Hovold 	int ret;
12216c5c023SJohan Hovold 
12316c5c023SJohan Hovold 	dev_dbg(lm3533->dev, "update [%02x]: %02x/%02x\n", reg, val, mask);
12416c5c023SJohan Hovold 
125664dd066SAxel Lin 	ret = regmap_update_bits(lm3533->regmap, reg, mask, val);
12616c5c023SJohan Hovold 	if (ret < 0) {
12716c5c023SJohan Hovold 		dev_err(lm3533->dev, "failed to update register %02x: %d\n",
12816c5c023SJohan Hovold 								reg, ret);
12916c5c023SJohan Hovold 	}
13016c5c023SJohan Hovold 
13116c5c023SJohan Hovold 	return ret;
13216c5c023SJohan Hovold }
13316c5c023SJohan Hovold EXPORT_SYMBOL_GPL(lm3533_update);
13416c5c023SJohan Hovold 
lm3533_set_boost_freq(struct lm3533 * lm3533,enum lm3533_boost_freq freq)135d9055dc5SJohan Hovold static int lm3533_set_boost_freq(struct lm3533 *lm3533,
136d9055dc5SJohan Hovold 						enum lm3533_boost_freq freq)
137d9055dc5SJohan Hovold {
138d9055dc5SJohan Hovold 	int ret;
139d9055dc5SJohan Hovold 
140d9055dc5SJohan Hovold 	ret = lm3533_update(lm3533, LM3533_REG_BOOST_PWM,
141d9055dc5SJohan Hovold 					freq << LM3533_BOOST_FREQ_SHIFT,
142d9055dc5SJohan Hovold 					LM3533_BOOST_FREQ_MASK);
143d9055dc5SJohan Hovold 	if (ret)
144d9055dc5SJohan Hovold 		dev_err(lm3533->dev, "failed to set boost frequency\n");
145d9055dc5SJohan Hovold 
146d9055dc5SJohan Hovold 	return ret;
147d9055dc5SJohan Hovold }
148d9055dc5SJohan Hovold 
149d9055dc5SJohan Hovold 
lm3533_set_boost_ovp(struct lm3533 * lm3533,enum lm3533_boost_ovp ovp)150d9055dc5SJohan Hovold static int lm3533_set_boost_ovp(struct lm3533 *lm3533,
151d9055dc5SJohan Hovold 						enum lm3533_boost_ovp ovp)
152d9055dc5SJohan Hovold {
153d9055dc5SJohan Hovold 	int ret;
154d9055dc5SJohan Hovold 
155d9055dc5SJohan Hovold 	ret = lm3533_update(lm3533, LM3533_REG_BOOST_PWM,
156d9055dc5SJohan Hovold 					ovp << LM3533_BOOST_OVP_SHIFT,
157d9055dc5SJohan Hovold 					LM3533_BOOST_OVP_MASK);
158d9055dc5SJohan Hovold 	if (ret)
159d9055dc5SJohan Hovold 		dev_err(lm3533->dev, "failed to set boost ovp\n");
160d9055dc5SJohan Hovold 
161d9055dc5SJohan Hovold 	return ret;
162d9055dc5SJohan Hovold }
163d9055dc5SJohan Hovold 
16416c5c023SJohan Hovold /*
16516c5c023SJohan Hovold  * HVLED output config -- output hvled controlled by backlight bl
16616c5c023SJohan Hovold  */
lm3533_set_hvled_config(struct lm3533 * lm3533,u8 hvled,u8 bl)16716c5c023SJohan Hovold static int lm3533_set_hvled_config(struct lm3533 *lm3533, u8 hvled, u8 bl)
16816c5c023SJohan Hovold {
16916c5c023SJohan Hovold 	u8 val;
17016c5c023SJohan Hovold 	u8 mask;
17116c5c023SJohan Hovold 	int shift;
17216c5c023SJohan Hovold 	int ret;
17316c5c023SJohan Hovold 
17416c5c023SJohan Hovold 	if (hvled == 0 || hvled > LM3533_HVLED_ID_MAX)
17516c5c023SJohan Hovold 		return -EINVAL;
17616c5c023SJohan Hovold 
17716c5c023SJohan Hovold 	if (bl > LM3533_BL_ID_MAX)
17816c5c023SJohan Hovold 		return -EINVAL;
17916c5c023SJohan Hovold 
18016c5c023SJohan Hovold 	shift = hvled - 1;
18116c5c023SJohan Hovold 	mask = LM3533_BL_ID_MASK << shift;
18216c5c023SJohan Hovold 	val = bl << shift;
18316c5c023SJohan Hovold 
18416c5c023SJohan Hovold 	ret = lm3533_update(lm3533, LM3533_REG_OUTPUT_CONF1, val, mask);
18516c5c023SJohan Hovold 	if (ret)
18616c5c023SJohan Hovold 		dev_err(lm3533->dev, "failed to set hvled config\n");
18716c5c023SJohan Hovold 
18816c5c023SJohan Hovold 	return ret;
18916c5c023SJohan Hovold }
19016c5c023SJohan Hovold 
19116c5c023SJohan Hovold /*
19216c5c023SJohan Hovold  * LVLED output config -- output lvled controlled by LED led
19316c5c023SJohan Hovold  */
lm3533_set_lvled_config(struct lm3533 * lm3533,u8 lvled,u8 led)19416c5c023SJohan Hovold static int lm3533_set_lvled_config(struct lm3533 *lm3533, u8 lvled, u8 led)
19516c5c023SJohan Hovold {
19616c5c023SJohan Hovold 	u8 reg;
19716c5c023SJohan Hovold 	u8 val;
19816c5c023SJohan Hovold 	u8 mask;
19916c5c023SJohan Hovold 	int shift;
20016c5c023SJohan Hovold 	int ret;
20116c5c023SJohan Hovold 
20216c5c023SJohan Hovold 	if (lvled == 0 || lvled > LM3533_LVLED_ID_MAX)
20316c5c023SJohan Hovold 		return -EINVAL;
20416c5c023SJohan Hovold 
20516c5c023SJohan Hovold 	if (led > LM3533_LED_ID_MAX)
20616c5c023SJohan Hovold 		return -EINVAL;
20716c5c023SJohan Hovold 
20816c5c023SJohan Hovold 	if (lvled < 4) {
20916c5c023SJohan Hovold 		reg = LM3533_REG_OUTPUT_CONF1;
21016c5c023SJohan Hovold 		shift = 2 * lvled;
21116c5c023SJohan Hovold 	} else {
21216c5c023SJohan Hovold 		reg = LM3533_REG_OUTPUT_CONF2;
21316c5c023SJohan Hovold 		shift = 2 * (lvled - 4);
21416c5c023SJohan Hovold 	}
21516c5c023SJohan Hovold 
21616c5c023SJohan Hovold 	mask = LM3533_LED_ID_MASK << shift;
21716c5c023SJohan Hovold 	val = led << shift;
21816c5c023SJohan Hovold 
21916c5c023SJohan Hovold 	ret = lm3533_update(lm3533, reg, val, mask);
22016c5c023SJohan Hovold 	if (ret)
22116c5c023SJohan Hovold 		dev_err(lm3533->dev, "failed to set lvled config\n");
22216c5c023SJohan Hovold 
22316c5c023SJohan Hovold 	return ret;
22416c5c023SJohan Hovold }
22516c5c023SJohan Hovold 
lm3533_enable(struct lm3533 * lm3533)22616c5c023SJohan Hovold static void lm3533_enable(struct lm3533 *lm3533)
22716c5c023SJohan Hovold {
22816c5c023SJohan Hovold 	if (gpio_is_valid(lm3533->gpio_hwen))
22916c5c023SJohan Hovold 		gpio_set_value(lm3533->gpio_hwen, 1);
23016c5c023SJohan Hovold }
23116c5c023SJohan Hovold 
lm3533_disable(struct lm3533 * lm3533)23216c5c023SJohan Hovold static void lm3533_disable(struct lm3533 *lm3533)
23316c5c023SJohan Hovold {
23416c5c023SJohan Hovold 	if (gpio_is_valid(lm3533->gpio_hwen))
23516c5c023SJohan Hovold 		gpio_set_value(lm3533->gpio_hwen, 0);
23616c5c023SJohan Hovold }
23716c5c023SJohan Hovold 
23816c5c023SJohan Hovold enum lm3533_attribute_type {
23916c5c023SJohan Hovold 	LM3533_ATTR_TYPE_BACKLIGHT,
24016c5c023SJohan Hovold 	LM3533_ATTR_TYPE_LED,
24116c5c023SJohan Hovold };
24216c5c023SJohan Hovold 
24316c5c023SJohan Hovold struct lm3533_device_attribute {
24416c5c023SJohan Hovold 	struct device_attribute dev_attr;
24516c5c023SJohan Hovold 	enum lm3533_attribute_type type;
24616c5c023SJohan Hovold 	union {
24716c5c023SJohan Hovold 		struct {
24816c5c023SJohan Hovold 			u8 id;
24916c5c023SJohan Hovold 		} output;
25016c5c023SJohan Hovold 	} u;
25116c5c023SJohan Hovold };
25216c5c023SJohan Hovold 
25316c5c023SJohan Hovold #define to_lm3533_dev_attr(_attr) \
25416c5c023SJohan Hovold 	container_of(_attr, struct lm3533_device_attribute, dev_attr)
25516c5c023SJohan Hovold 
show_output(struct device * dev,struct device_attribute * attr,char * buf)25616c5c023SJohan Hovold static ssize_t show_output(struct device *dev,
25716c5c023SJohan Hovold 				struct device_attribute *attr, char *buf)
25816c5c023SJohan Hovold {
25916c5c023SJohan Hovold 	struct lm3533 *lm3533 = dev_get_drvdata(dev);
26016c5c023SJohan Hovold 	struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr);
26116c5c023SJohan Hovold 	int id = lattr->u.output.id;
26216c5c023SJohan Hovold 	u8 reg;
26316c5c023SJohan Hovold 	u8 val;
26416c5c023SJohan Hovold 	u8 mask;
26516c5c023SJohan Hovold 	int shift;
26616c5c023SJohan Hovold 	int ret;
26716c5c023SJohan Hovold 
26816c5c023SJohan Hovold 	if (lattr->type == LM3533_ATTR_TYPE_BACKLIGHT) {
26916c5c023SJohan Hovold 		reg = LM3533_REG_OUTPUT_CONF1;
27016c5c023SJohan Hovold 		shift = id - 1;
27116c5c023SJohan Hovold 		mask = LM3533_BL_ID_MASK << shift;
27216c5c023SJohan Hovold 	} else {
27316c5c023SJohan Hovold 		if (id < 4) {
27416c5c023SJohan Hovold 			reg = LM3533_REG_OUTPUT_CONF1;
27516c5c023SJohan Hovold 			shift = 2 * id;
27616c5c023SJohan Hovold 		} else {
27716c5c023SJohan Hovold 			reg = LM3533_REG_OUTPUT_CONF2;
27816c5c023SJohan Hovold 			shift = 2 * (id - 4);
27916c5c023SJohan Hovold 		}
28016c5c023SJohan Hovold 		mask = LM3533_LED_ID_MASK << shift;
28116c5c023SJohan Hovold 	}
28216c5c023SJohan Hovold 
28316c5c023SJohan Hovold 	ret = lm3533_read(lm3533, reg, &val);
28416c5c023SJohan Hovold 	if (ret)
28516c5c023SJohan Hovold 		return ret;
28616c5c023SJohan Hovold 
28716c5c023SJohan Hovold 	val = (val & mask) >> shift;
28816c5c023SJohan Hovold 
2898cc5e62bSye xingchen 	return sysfs_emit(buf, "%u\n", val);
29016c5c023SJohan Hovold }
29116c5c023SJohan Hovold 
store_output(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)29216c5c023SJohan Hovold static ssize_t store_output(struct device *dev,
29316c5c023SJohan Hovold 					struct device_attribute *attr,
29416c5c023SJohan Hovold 					const char *buf, size_t len)
29516c5c023SJohan Hovold {
29616c5c023SJohan Hovold 	struct lm3533 *lm3533 = dev_get_drvdata(dev);
29716c5c023SJohan Hovold 	struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr);
29816c5c023SJohan Hovold 	int id = lattr->u.output.id;
29916c5c023SJohan Hovold 	u8 val;
30016c5c023SJohan Hovold 	int ret;
30116c5c023SJohan Hovold 
30216c5c023SJohan Hovold 	if (kstrtou8(buf, 0, &val))
30316c5c023SJohan Hovold 		return -EINVAL;
30416c5c023SJohan Hovold 
30516c5c023SJohan Hovold 	if (lattr->type == LM3533_ATTR_TYPE_BACKLIGHT)
30616c5c023SJohan Hovold 		ret = lm3533_set_hvled_config(lm3533, id, val);
30716c5c023SJohan Hovold 	else
30816c5c023SJohan Hovold 		ret = lm3533_set_lvled_config(lm3533, id, val);
30916c5c023SJohan Hovold 
31016c5c023SJohan Hovold 	if (ret)
31116c5c023SJohan Hovold 		return ret;
31216c5c023SJohan Hovold 
31316c5c023SJohan Hovold 	return len;
31416c5c023SJohan Hovold }
31516c5c023SJohan Hovold 
31616c5c023SJohan Hovold #define LM3533_OUTPUT_ATTR(_name, _mode, _show, _store, _type, _id) \
31716c5c023SJohan Hovold 	struct lm3533_device_attribute lm3533_dev_attr_##_name = \
31816c5c023SJohan Hovold 		{ .dev_attr	= __ATTR(_name, _mode, _show, _store), \
31916c5c023SJohan Hovold 		  .type		= _type, \
32016c5c023SJohan Hovold 		  .u.output	= { .id = _id }, }
32116c5c023SJohan Hovold 
32216c5c023SJohan Hovold #define LM3533_OUTPUT_ATTR_RW(_name, _type, _id) \
32316c5c023SJohan Hovold 	LM3533_OUTPUT_ATTR(output_##_name, S_IRUGO | S_IWUSR, \
32416c5c023SJohan Hovold 					show_output, store_output, _type, _id)
32516c5c023SJohan Hovold 
32616c5c023SJohan Hovold #define LM3533_OUTPUT_HVLED_ATTR_RW(_nr) \
32716c5c023SJohan Hovold 	LM3533_OUTPUT_ATTR_RW(hvled##_nr, LM3533_ATTR_TYPE_BACKLIGHT, _nr)
32816c5c023SJohan Hovold #define LM3533_OUTPUT_LVLED_ATTR_RW(_nr) \
32916c5c023SJohan Hovold 	LM3533_OUTPUT_ATTR_RW(lvled##_nr, LM3533_ATTR_TYPE_LED, _nr)
33016c5c023SJohan Hovold /*
33116c5c023SJohan Hovold  * Output config:
33216c5c023SJohan Hovold  *
33316c5c023SJohan Hovold  * output_hvled<nr>	0-1
33416c5c023SJohan Hovold  * output_lvled<nr>	0-3
33516c5c023SJohan Hovold  */
33616c5c023SJohan Hovold static LM3533_OUTPUT_HVLED_ATTR_RW(1);
33716c5c023SJohan Hovold static LM3533_OUTPUT_HVLED_ATTR_RW(2);
33816c5c023SJohan Hovold static LM3533_OUTPUT_LVLED_ATTR_RW(1);
33916c5c023SJohan Hovold static LM3533_OUTPUT_LVLED_ATTR_RW(2);
34016c5c023SJohan Hovold static LM3533_OUTPUT_LVLED_ATTR_RW(3);
34116c5c023SJohan Hovold static LM3533_OUTPUT_LVLED_ATTR_RW(4);
34216c5c023SJohan Hovold static LM3533_OUTPUT_LVLED_ATTR_RW(5);
34316c5c023SJohan Hovold 
34416c5c023SJohan Hovold static struct attribute *lm3533_attributes[] = {
34516c5c023SJohan Hovold 	&lm3533_dev_attr_output_hvled1.dev_attr.attr,
34616c5c023SJohan Hovold 	&lm3533_dev_attr_output_hvled2.dev_attr.attr,
34716c5c023SJohan Hovold 	&lm3533_dev_attr_output_lvled1.dev_attr.attr,
34816c5c023SJohan Hovold 	&lm3533_dev_attr_output_lvled2.dev_attr.attr,
34916c5c023SJohan Hovold 	&lm3533_dev_attr_output_lvled3.dev_attr.attr,
35016c5c023SJohan Hovold 	&lm3533_dev_attr_output_lvled4.dev_attr.attr,
35116c5c023SJohan Hovold 	&lm3533_dev_attr_output_lvled5.dev_attr.attr,
35216c5c023SJohan Hovold 	NULL,
35316c5c023SJohan Hovold };
35416c5c023SJohan Hovold 
35516c5c023SJohan Hovold #define to_dev_attr(_attr) \
35616c5c023SJohan Hovold 	container_of(_attr, struct device_attribute, attr)
35716c5c023SJohan Hovold 
lm3533_attr_is_visible(struct kobject * kobj,struct attribute * attr,int n)358168755ebSDan Carpenter static umode_t lm3533_attr_is_visible(struct kobject *kobj,
35916c5c023SJohan Hovold 					     struct attribute *attr, int n)
36016c5c023SJohan Hovold {
36123144a32SYang Li 	struct device *dev = kobj_to_dev(kobj);
36216c5c023SJohan Hovold 	struct lm3533 *lm3533 = dev_get_drvdata(dev);
36316c5c023SJohan Hovold 	struct device_attribute *dattr = to_dev_attr(attr);
36416c5c023SJohan Hovold 	struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(dattr);
36516c5c023SJohan Hovold 	enum lm3533_attribute_type type = lattr->type;
36660908855SJohan Hovold 	umode_t mode = attr->mode;
36716c5c023SJohan Hovold 
36816c5c023SJohan Hovold 	if (!lm3533->have_backlights && type == LM3533_ATTR_TYPE_BACKLIGHT)
36916c5c023SJohan Hovold 		mode = 0;
37016c5c023SJohan Hovold 	else if (!lm3533->have_leds && type == LM3533_ATTR_TYPE_LED)
37116c5c023SJohan Hovold 		mode = 0;
37216c5c023SJohan Hovold 
37316c5c023SJohan Hovold 	return mode;
37416c5c023SJohan Hovold };
37516c5c023SJohan Hovold 
37616c5c023SJohan Hovold static struct attribute_group lm3533_attribute_group = {
37716c5c023SJohan Hovold 	.is_visible	= lm3533_attr_is_visible,
37816c5c023SJohan Hovold 	.attrs		= lm3533_attributes
37916c5c023SJohan Hovold };
38016c5c023SJohan Hovold 
lm3533_device_als_init(struct lm3533 * lm3533)381f791be49SBill Pemberton static int lm3533_device_als_init(struct lm3533 *lm3533)
38216c5c023SJohan Hovold {
383334a41ceSJingoo Han 	struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
38416c5c023SJohan Hovold 	int ret;
38516c5c023SJohan Hovold 
38616c5c023SJohan Hovold 	if (!pdata->als)
38716c5c023SJohan Hovold 		return 0;
38816c5c023SJohan Hovold 
38916c5c023SJohan Hovold 	lm3533_als_devs[0].platform_data = pdata->als;
39016c5c023SJohan Hovold 	lm3533_als_devs[0].pdata_size = sizeof(*pdata->als);
39116c5c023SJohan Hovold 
3920848c94fSMark Brown 	ret = mfd_add_devices(lm3533->dev, 0, lm3533_als_devs, 1, NULL,
3930848c94fSMark Brown 			      0, NULL);
39416c5c023SJohan Hovold 	if (ret) {
39516c5c023SJohan Hovold 		dev_err(lm3533->dev, "failed to add ALS device\n");
39616c5c023SJohan Hovold 		return ret;
39716c5c023SJohan Hovold 	}
39816c5c023SJohan Hovold 
39916c5c023SJohan Hovold 	lm3533->have_als = 1;
40016c5c023SJohan Hovold 
40116c5c023SJohan Hovold 	return 0;
40216c5c023SJohan Hovold }
40316c5c023SJohan Hovold 
lm3533_device_bl_init(struct lm3533 * lm3533)404f791be49SBill Pemberton static int lm3533_device_bl_init(struct lm3533 *lm3533)
40516c5c023SJohan Hovold {
406334a41ceSJingoo Han 	struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
40716c5c023SJohan Hovold 	int i;
40816c5c023SJohan Hovold 	int ret;
40916c5c023SJohan Hovold 
41016c5c023SJohan Hovold 	if (!pdata->backlights || pdata->num_backlights == 0)
41116c5c023SJohan Hovold 		return 0;
41216c5c023SJohan Hovold 
41316c5c023SJohan Hovold 	if (pdata->num_backlights > ARRAY_SIZE(lm3533_bl_devs))
41416c5c023SJohan Hovold 		pdata->num_backlights = ARRAY_SIZE(lm3533_bl_devs);
41516c5c023SJohan Hovold 
41616c5c023SJohan Hovold 	for (i = 0; i < pdata->num_backlights; ++i) {
41716c5c023SJohan Hovold 		lm3533_bl_devs[i].platform_data = &pdata->backlights[i];
41816c5c023SJohan Hovold 		lm3533_bl_devs[i].pdata_size = sizeof(pdata->backlights[i]);
41916c5c023SJohan Hovold 	}
42016c5c023SJohan Hovold 
42116c5c023SJohan Hovold 	ret = mfd_add_devices(lm3533->dev, 0, lm3533_bl_devs,
4220848c94fSMark Brown 			      pdata->num_backlights, NULL, 0, NULL);
42316c5c023SJohan Hovold 	if (ret) {
42416c5c023SJohan Hovold 		dev_err(lm3533->dev, "failed to add backlight devices\n");
42516c5c023SJohan Hovold 		return ret;
42616c5c023SJohan Hovold 	}
42716c5c023SJohan Hovold 
42816c5c023SJohan Hovold 	lm3533->have_backlights = 1;
42916c5c023SJohan Hovold 
43016c5c023SJohan Hovold 	return 0;
43116c5c023SJohan Hovold }
43216c5c023SJohan Hovold 
lm3533_device_led_init(struct lm3533 * lm3533)433f791be49SBill Pemberton static int lm3533_device_led_init(struct lm3533 *lm3533)
43416c5c023SJohan Hovold {
435334a41ceSJingoo Han 	struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
43616c5c023SJohan Hovold 	int i;
43716c5c023SJohan Hovold 	int ret;
43816c5c023SJohan Hovold 
43916c5c023SJohan Hovold 	if (!pdata->leds || pdata->num_leds == 0)
44016c5c023SJohan Hovold 		return 0;
44116c5c023SJohan Hovold 
44216c5c023SJohan Hovold 	if (pdata->num_leds > ARRAY_SIZE(lm3533_led_devs))
44316c5c023SJohan Hovold 		pdata->num_leds = ARRAY_SIZE(lm3533_led_devs);
44416c5c023SJohan Hovold 
44516c5c023SJohan Hovold 	for (i = 0; i < pdata->num_leds; ++i) {
44616c5c023SJohan Hovold 		lm3533_led_devs[i].platform_data = &pdata->leds[i];
44716c5c023SJohan Hovold 		lm3533_led_devs[i].pdata_size = sizeof(pdata->leds[i]);
44816c5c023SJohan Hovold 	}
44916c5c023SJohan Hovold 
45016c5c023SJohan Hovold 	ret = mfd_add_devices(lm3533->dev, 0, lm3533_led_devs,
4510848c94fSMark Brown 			      pdata->num_leds, NULL, 0, NULL);
45216c5c023SJohan Hovold 	if (ret) {
45316c5c023SJohan Hovold 		dev_err(lm3533->dev, "failed to add LED devices\n");
45416c5c023SJohan Hovold 		return ret;
45516c5c023SJohan Hovold 	}
45616c5c023SJohan Hovold 
45716c5c023SJohan Hovold 	lm3533->have_leds = 1;
45816c5c023SJohan Hovold 
45916c5c023SJohan Hovold 	return 0;
46016c5c023SJohan Hovold }
46116c5c023SJohan Hovold 
lm3533_device_setup(struct lm3533 * lm3533,struct lm3533_platform_data * pdata)462f791be49SBill Pemberton static int lm3533_device_setup(struct lm3533 *lm3533,
463d9055dc5SJohan Hovold 					struct lm3533_platform_data *pdata)
464d9055dc5SJohan Hovold {
465d9055dc5SJohan Hovold 	int ret;
466d9055dc5SJohan Hovold 
467d9055dc5SJohan Hovold 	ret = lm3533_set_boost_freq(lm3533, pdata->boost_freq);
468d9055dc5SJohan Hovold 	if (ret)
469d9055dc5SJohan Hovold 		return ret;
470d9055dc5SJohan Hovold 
471a1c16d71SJavier Martinez Canillas 	return lm3533_set_boost_ovp(lm3533, pdata->boost_ovp);
472d9055dc5SJohan Hovold }
473d9055dc5SJohan Hovold 
lm3533_device_init(struct lm3533 * lm3533)474f791be49SBill Pemberton static int lm3533_device_init(struct lm3533 *lm3533)
47516c5c023SJohan Hovold {
476334a41ceSJingoo Han 	struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
47716c5c023SJohan Hovold 	int ret;
47816c5c023SJohan Hovold 
47916c5c023SJohan Hovold 	dev_dbg(lm3533->dev, "%s\n", __func__);
48016c5c023SJohan Hovold 
48116c5c023SJohan Hovold 	if (!pdata) {
48216c5c023SJohan Hovold 		dev_err(lm3533->dev, "no platform data\n");
48316c5c023SJohan Hovold 		return -EINVAL;
48416c5c023SJohan Hovold 	}
48516c5c023SJohan Hovold 
48616c5c023SJohan Hovold 	lm3533->gpio_hwen = pdata->gpio_hwen;
48716c5c023SJohan Hovold 
48816c5c023SJohan Hovold 	if (gpio_is_valid(lm3533->gpio_hwen)) {
489bf5ea28aSJingoo Han 		ret = devm_gpio_request_one(lm3533->dev, lm3533->gpio_hwen,
490bf5ea28aSJingoo Han 					GPIOF_OUT_INIT_LOW, "lm3533-hwen");
49116c5c023SJohan Hovold 		if (ret < 0) {
49216c5c023SJohan Hovold 			dev_err(lm3533->dev,
49316c5c023SJohan Hovold 				"failed to request HWEN GPIO %d\n",
49416c5c023SJohan Hovold 				lm3533->gpio_hwen);
49516c5c023SJohan Hovold 			return ret;
49616c5c023SJohan Hovold 		}
49716c5c023SJohan Hovold 	}
49816c5c023SJohan Hovold 
49916c5c023SJohan Hovold 	lm3533_enable(lm3533);
50016c5c023SJohan Hovold 
501d9055dc5SJohan Hovold 	ret = lm3533_device_setup(lm3533, pdata);
502d9055dc5SJohan Hovold 	if (ret)
503d9055dc5SJohan Hovold 		goto err_disable;
504d9055dc5SJohan Hovold 
50516c5c023SJohan Hovold 	lm3533_device_als_init(lm3533);
50616c5c023SJohan Hovold 	lm3533_device_bl_init(lm3533);
50716c5c023SJohan Hovold 	lm3533_device_led_init(lm3533);
50816c5c023SJohan Hovold 
50916c5c023SJohan Hovold 	ret = sysfs_create_group(&lm3533->dev->kobj, &lm3533_attribute_group);
51016c5c023SJohan Hovold 	if (ret < 0) {
51116c5c023SJohan Hovold 		dev_err(lm3533->dev, "failed to create sysfs attributes\n");
51216c5c023SJohan Hovold 		goto err_unregister;
51316c5c023SJohan Hovold 	}
51416c5c023SJohan Hovold 
51516c5c023SJohan Hovold 	return 0;
51616c5c023SJohan Hovold 
51716c5c023SJohan Hovold err_unregister:
51816c5c023SJohan Hovold 	mfd_remove_devices(lm3533->dev);
519d9055dc5SJohan Hovold err_disable:
52016c5c023SJohan Hovold 	lm3533_disable(lm3533);
52116c5c023SJohan Hovold 
52216c5c023SJohan Hovold 	return ret;
52316c5c023SJohan Hovold }
52416c5c023SJohan Hovold 
lm3533_device_exit(struct lm3533 * lm3533)5254740f73fSBill Pemberton static void lm3533_device_exit(struct lm3533 *lm3533)
52616c5c023SJohan Hovold {
52716c5c023SJohan Hovold 	dev_dbg(lm3533->dev, "%s\n", __func__);
52816c5c023SJohan Hovold 
52916c5c023SJohan Hovold 	sysfs_remove_group(&lm3533->dev->kobj, &lm3533_attribute_group);
53016c5c023SJohan Hovold 
53116c5c023SJohan Hovold 	mfd_remove_devices(lm3533->dev);
53216c5c023SJohan Hovold 	lm3533_disable(lm3533);
53316c5c023SJohan Hovold }
53416c5c023SJohan Hovold 
lm3533_readable_register(struct device * dev,unsigned int reg)53516c5c023SJohan Hovold static bool lm3533_readable_register(struct device *dev, unsigned int reg)
53616c5c023SJohan Hovold {
53716c5c023SJohan Hovold 	switch (reg) {
53816c5c023SJohan Hovold 	case 0x10 ... 0x2c:
53916c5c023SJohan Hovold 	case 0x30 ... 0x38:
54016c5c023SJohan Hovold 	case 0x40 ... 0x45:
54116c5c023SJohan Hovold 	case 0x50 ... 0x57:
54216c5c023SJohan Hovold 	case 0x60 ... 0x6e:
54316c5c023SJohan Hovold 	case 0x70 ... 0x75:
54416c5c023SJohan Hovold 	case 0x80 ... 0x85:
54516c5c023SJohan Hovold 	case 0x90 ... 0x95:
54616c5c023SJohan Hovold 	case 0xa0 ... 0xa5:
54716c5c023SJohan Hovold 	case 0xb0 ... 0xb2:
54816c5c023SJohan Hovold 		return true;
54916c5c023SJohan Hovold 	default:
55016c5c023SJohan Hovold 		return false;
55116c5c023SJohan Hovold 	}
55216c5c023SJohan Hovold }
55316c5c023SJohan Hovold 
lm3533_volatile_register(struct device * dev,unsigned int reg)55416c5c023SJohan Hovold static bool lm3533_volatile_register(struct device *dev, unsigned int reg)
55516c5c023SJohan Hovold {
55616c5c023SJohan Hovold 	switch (reg) {
557c48bf153SJohan Hovold 	case 0x34 ... 0x36:	/* zone */
55816c5c023SJohan Hovold 	case 0x37 ... 0x38:	/* adc */
55916c5c023SJohan Hovold 	case 0xb0 ... 0xb1:	/* fault */
56016c5c023SJohan Hovold 		return true;
56116c5c023SJohan Hovold 	default:
56216c5c023SJohan Hovold 		return false;
56316c5c023SJohan Hovold 	}
56416c5c023SJohan Hovold }
56516c5c023SJohan Hovold 
lm3533_precious_register(struct device * dev,unsigned int reg)56616c5c023SJohan Hovold static bool lm3533_precious_register(struct device *dev, unsigned int reg)
56716c5c023SJohan Hovold {
56816c5c023SJohan Hovold 	switch (reg) {
56916c5c023SJohan Hovold 	case 0x34:		/* zone */
57016c5c023SJohan Hovold 		return true;
57116c5c023SJohan Hovold 	default:
57216c5c023SJohan Hovold 		return false;
57316c5c023SJohan Hovold 	}
57416c5c023SJohan Hovold }
57516c5c023SJohan Hovold 
576dd635161SKrzysztof Kozlowski static const struct regmap_config regmap_config = {
57716c5c023SJohan Hovold 	.reg_bits	= 8,
57816c5c023SJohan Hovold 	.val_bits	= 8,
57916c5c023SJohan Hovold 	.max_register	= LM3533_REG_MAX,
58016c5c023SJohan Hovold 	.readable_reg	= lm3533_readable_register,
58116c5c023SJohan Hovold 	.volatile_reg	= lm3533_volatile_register,
58216c5c023SJohan Hovold 	.precious_reg	= lm3533_precious_register,
58316c5c023SJohan Hovold };
58416c5c023SJohan Hovold 
lm3533_i2c_probe(struct i2c_client * i2c)585daf811fcSUwe Kleine-König static int lm3533_i2c_probe(struct i2c_client *i2c)
58616c5c023SJohan Hovold {
58716c5c023SJohan Hovold 	struct lm3533 *lm3533;
58816c5c023SJohan Hovold 
58916c5c023SJohan Hovold 	dev_dbg(&i2c->dev, "%s\n", __func__);
59016c5c023SJohan Hovold 
591fa648e51SJohan Hovold 	lm3533 = devm_kzalloc(&i2c->dev, sizeof(*lm3533), GFP_KERNEL);
59216c5c023SJohan Hovold 	if (!lm3533)
59316c5c023SJohan Hovold 		return -ENOMEM;
59416c5c023SJohan Hovold 
59516c5c023SJohan Hovold 	i2c_set_clientdata(i2c, lm3533);
59616c5c023SJohan Hovold 
597fa648e51SJohan Hovold 	lm3533->regmap = devm_regmap_init_i2c(i2c, &regmap_config);
598fa648e51SJohan Hovold 	if (IS_ERR(lm3533->regmap))
599fa648e51SJohan Hovold 		return PTR_ERR(lm3533->regmap);
60016c5c023SJohan Hovold 
60116c5c023SJohan Hovold 	lm3533->dev = &i2c->dev;
60216c5c023SJohan Hovold 	lm3533->irq = i2c->irq;
60316c5c023SJohan Hovold 
604a1c16d71SJavier Martinez Canillas 	return lm3533_device_init(lm3533);
60516c5c023SJohan Hovold }
60616c5c023SJohan Hovold 
lm3533_i2c_remove(struct i2c_client * i2c)607ed5c2f5fSUwe Kleine-König static void lm3533_i2c_remove(struct i2c_client *i2c)
60816c5c023SJohan Hovold {
60916c5c023SJohan Hovold 	struct lm3533 *lm3533 = i2c_get_clientdata(i2c);
61016c5c023SJohan Hovold 
61116c5c023SJohan Hovold 	dev_dbg(&i2c->dev, "%s\n", __func__);
61216c5c023SJohan Hovold 
61316c5c023SJohan Hovold 	lm3533_device_exit(lm3533);
61416c5c023SJohan Hovold }
61516c5c023SJohan Hovold 
61616c5c023SJohan Hovold static const struct i2c_device_id lm3533_i2c_ids[] = {
61716c5c023SJohan Hovold 	{ "lm3533", 0 },
61816c5c023SJohan Hovold 	{ },
61916c5c023SJohan Hovold };
62016c5c023SJohan Hovold MODULE_DEVICE_TABLE(i2c, lm3533_i2c_ids);
62116c5c023SJohan Hovold 
62216c5c023SJohan Hovold static struct i2c_driver lm3533_i2c_driver = {
62316c5c023SJohan Hovold 	.driver = {
62416c5c023SJohan Hovold 		   .name = "lm3533",
62516c5c023SJohan Hovold 	},
62616c5c023SJohan Hovold 	.id_table	= lm3533_i2c_ids,
627*9816d859SUwe Kleine-König 	.probe		= lm3533_i2c_probe,
62884449216SBill Pemberton 	.remove		= lm3533_i2c_remove,
62916c5c023SJohan Hovold };
63016c5c023SJohan Hovold 
lm3533_i2c_init(void)63116c5c023SJohan Hovold static int __init lm3533_i2c_init(void)
63216c5c023SJohan Hovold {
63316c5c023SJohan Hovold 	return i2c_add_driver(&lm3533_i2c_driver);
63416c5c023SJohan Hovold }
63516c5c023SJohan Hovold subsys_initcall(lm3533_i2c_init);
63616c5c023SJohan Hovold 
lm3533_i2c_exit(void)63716c5c023SJohan Hovold static void __exit lm3533_i2c_exit(void)
63816c5c023SJohan Hovold {
63916c5c023SJohan Hovold 	i2c_del_driver(&lm3533_i2c_driver);
64016c5c023SJohan Hovold }
64116c5c023SJohan Hovold module_exit(lm3533_i2c_exit);
64216c5c023SJohan Hovold 
64316c5c023SJohan Hovold MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>");
64416c5c023SJohan Hovold MODULE_DESCRIPTION("LM3533 Core");
64516c5c023SJohan Hovold MODULE_LICENSE("GPL");
646