xref: /linux/drivers/regulator/fan53555.c (revision 259b93b21a9ffe5117af4dfb5505437e463c6a5a)
16a1beee2SAxel Lin // SPDX-License-Identifier: GPL-2.0
26a1beee2SAxel Lin //
36a1beee2SAxel Lin // FAN53555 Fairchild Digitally Programmable TinyBuck Regulator Driver.
46a1beee2SAxel Lin //
56a1beee2SAxel Lin // Supported Part Numbers:
66a1beee2SAxel Lin // FAN53555UC00X/01X/03X/04X/05X
76a1beee2SAxel Lin //
86a1beee2SAxel Lin // Copyright (c) 2012 Marvell Technology Ltd.
96a1beee2SAxel Lin // Yunfan Zhang <yfzhang@marvell.com>
106a1beee2SAxel Lin 
1149d8c599SYunfan Zhang #include <linux/module.h>
1249d8c599SYunfan Zhang #include <linux/param.h>
1349d8c599SYunfan Zhang #include <linux/err.h>
1449d8c599SYunfan Zhang #include <linux/platform_device.h>
1549d8c599SYunfan Zhang #include <linux/regulator/driver.h>
1649d8c599SYunfan Zhang #include <linux/regulator/machine.h>
1791f23d8fSHeiko Stuebner #include <linux/regulator/of_regulator.h>
1891f23d8fSHeiko Stuebner #include <linux/of_device.h>
1949d8c599SYunfan Zhang #include <linux/i2c.h>
2049d8c599SYunfan Zhang #include <linux/slab.h>
2149d8c599SYunfan Zhang #include <linux/regmap.h>
2249d8c599SYunfan Zhang #include <linux/regulator/fan53555.h>
2349d8c599SYunfan Zhang 
2449d8c599SYunfan Zhang /* Voltage setting */
2549d8c599SYunfan Zhang #define FAN53555_VSEL0		0x00
2649d8c599SYunfan Zhang #define FAN53555_VSEL1		0x01
27914df8faSJoseph Chen 
28914df8faSJoseph Chen #define TCS4525_VSEL0		0x11
29914df8faSJoseph Chen #define TCS4525_VSEL1		0x10
30914df8faSJoseph Chen #define TCS4525_TIME		0x13
31914df8faSJoseph Chen #define TCS4525_COMMAND		0x14
32914df8faSJoseph Chen 
3349d8c599SYunfan Zhang /* Control register */
3449d8c599SYunfan Zhang #define FAN53555_CONTROL	0x02
3549d8c599SYunfan Zhang /* IC Type */
3649d8c599SYunfan Zhang #define FAN53555_ID1		0x03
3749d8c599SYunfan Zhang /* IC mask version */
3849d8c599SYunfan Zhang #define FAN53555_ID2		0x04
3949d8c599SYunfan Zhang /* Monitor register */
4049d8c599SYunfan Zhang #define FAN53555_MONITOR	0x05
4149d8c599SYunfan Zhang 
4249d8c599SYunfan Zhang /* VSEL bit definitions */
4349d8c599SYunfan Zhang #define VSEL_BUCK_EN	(1 << 7)
4449d8c599SYunfan Zhang #define VSEL_MODE		(1 << 6)
4549d8c599SYunfan Zhang /* Chip ID and Verison */
4649d8c599SYunfan Zhang #define DIE_ID		0x0F	/* ID1 */
4749d8c599SYunfan Zhang #define DIE_REV		0x0F	/* ID2 */
4849d8c599SYunfan Zhang /* Control bit definitions */
4949d8c599SYunfan Zhang #define CTL_OUTPUT_DISCHG	(1 << 7)
5049d8c599SYunfan Zhang #define CTL_SLEW_MASK		(0x7 << 4)
5149d8c599SYunfan Zhang #define CTL_SLEW_SHIFT		4
5249d8c599SYunfan Zhang #define CTL_RESET			(1 << 2)
53f2a9eb97SBjorn Andersson #define CTL_MODE_VSEL0_MODE	BIT(0)
54f2a9eb97SBjorn Andersson #define CTL_MODE_VSEL1_MODE	BIT(1)
5549d8c599SYunfan Zhang 
5649d8c599SYunfan Zhang #define FAN53555_NVOLTAGES	64	/* Numbers of voltages */
57f2a9eb97SBjorn Andersson #define FAN53526_NVOLTAGES	128
58914df8faSJoseph Chen 
59914df8faSJoseph Chen #define TCS_VSEL0_MODE		(1 << 7)
60914df8faSJoseph Chen #define TCS_VSEL1_MODE		(1 << 6)
61914df8faSJoseph Chen 
62914df8faSJoseph Chen #define TCS_SLEW_SHIFT		3
63914df8faSJoseph Chen #define TCS_SLEW_MASK		(0x3 < 3)
6449d8c599SYunfan Zhang 
65ee30928aSHeiko Stuebner enum fan53555_vendor {
66f2a9eb97SBjorn Andersson 	FAN53526_VENDOR_FAIRCHILD = 0,
67f2a9eb97SBjorn Andersson 	FAN53555_VENDOR_FAIRCHILD,
68ee30928aSHeiko Stuebner 	FAN53555_VENDOR_SILERGY,
69b3cc8ec0SPeter Geis 	FAN53526_VENDOR_TCS,
70ee30928aSHeiko Stuebner };
71ee30928aSHeiko Stuebner 
72f2a9eb97SBjorn Andersson enum {
73f2a9eb97SBjorn Andersson 	FAN53526_CHIP_ID_01 = 1,
74f2a9eb97SBjorn Andersson };
75f2a9eb97SBjorn Andersson 
76f2a9eb97SBjorn Andersson enum {
77f2a9eb97SBjorn Andersson 	FAN53526_CHIP_REV_08 = 8,
78f2a9eb97SBjorn Andersson };
79f2a9eb97SBjorn Andersson 
8049d8c599SYunfan Zhang /* IC Type */
8149d8c599SYunfan Zhang enum {
8249d8c599SYunfan Zhang 	FAN53555_CHIP_ID_00 = 0,
8349d8c599SYunfan Zhang 	FAN53555_CHIP_ID_01,
8449d8c599SYunfan Zhang 	FAN53555_CHIP_ID_02,
8549d8c599SYunfan Zhang 	FAN53555_CHIP_ID_03,
8649d8c599SYunfan Zhang 	FAN53555_CHIP_ID_04,
8749d8c599SYunfan Zhang 	FAN53555_CHIP_ID_05,
885e39cf49SWadim Egorov 	FAN53555_CHIP_ID_08 = 8,
8949d8c599SYunfan Zhang };
9049d8c599SYunfan Zhang 
91f9028dcdSPeter Geis enum {
92f9028dcdSPeter Geis 	TCS4525_CHIP_ID_12 = 12,
93f9028dcdSPeter Geis };
94f9028dcdSPeter Geis 
955eee5eceSRudi Heitbaum enum {
965eee5eceSRudi Heitbaum 	TCS4526_CHIP_ID_00 = 0,
975eee5eceSRudi Heitbaum };
985eee5eceSRudi Heitbaum 
99e57cbb70SWadim Egorov /* IC mask revision */
100e57cbb70SWadim Egorov enum {
101e57cbb70SWadim Egorov 	FAN53555_CHIP_REV_00 = 0x3,
102e57cbb70SWadim Egorov 	FAN53555_CHIP_REV_13 = 0xf,
103e57cbb70SWadim Egorov };
104e57cbb70SWadim Egorov 
105ee30928aSHeiko Stuebner enum {
106ee30928aSHeiko Stuebner 	SILERGY_SYR82X = 8,
1075365e3dfSVasily Khoruzhick 	SILERGY_SYR83X = 9,
108ee30928aSHeiko Stuebner };
109ee30928aSHeiko Stuebner 
11049d8c599SYunfan Zhang struct fan53555_device_info {
111ee30928aSHeiko Stuebner 	enum fan53555_vendor vendor;
11249d8c599SYunfan Zhang 	struct device *dev;
11349d8c599SYunfan Zhang 	struct regulator_desc desc;
11449d8c599SYunfan Zhang 	struct regulator_init_data *regulator;
11549d8c599SYunfan Zhang 	/* IC Type and Rev */
11649d8c599SYunfan Zhang 	int chip_id;
11749d8c599SYunfan Zhang 	int chip_rev;
11849d8c599SYunfan Zhang 	/* Voltage setting register */
11949d8c599SYunfan Zhang 	unsigned int vol_reg;
12049d8c599SYunfan Zhang 	unsigned int sleep_reg;
12149d8c599SYunfan Zhang 	/* Voltage range and step(linear) */
12249d8c599SYunfan Zhang 	unsigned int vsel_min;
12349d8c599SYunfan Zhang 	unsigned int vsel_step;
124f2a9eb97SBjorn Andersson 	unsigned int vsel_count;
125f2a9eb97SBjorn Andersson 	/* Mode */
126f2a9eb97SBjorn Andersson 	unsigned int mode_reg;
127f2a9eb97SBjorn Andersson 	unsigned int mode_mask;
12849d8c599SYunfan Zhang 	/* Sleep voltage cache */
12949d8c599SYunfan Zhang 	unsigned int sleep_vol_cache;
130914df8faSJoseph Chen 	/* Slew rate */
131914df8faSJoseph Chen 	unsigned int slew_reg;
132914df8faSJoseph Chen 	unsigned int slew_mask;
133b61ac767SAxel Lin 	const unsigned int *ramp_delay_table;
134b61ac767SAxel Lin 	unsigned int n_ramp_values;
135914df8faSJoseph Chen 	unsigned int slew_rate;
13649d8c599SYunfan Zhang };
13749d8c599SYunfan Zhang 
13849d8c599SYunfan Zhang static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV)
13949d8c599SYunfan Zhang {
14049d8c599SYunfan Zhang 	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
14149d8c599SYunfan Zhang 	int ret;
14249d8c599SYunfan Zhang 
14349d8c599SYunfan Zhang 	if (di->sleep_vol_cache == uV)
14449d8c599SYunfan Zhang 		return 0;
14549d8c599SYunfan Zhang 	ret = regulator_map_voltage_linear(rdev, uV, uV);
14649d8c599SYunfan Zhang 	if (ret < 0)
147145fe1e1SSachin Kamat 		return ret;
148a69929c7SAxel Lin 	ret = regmap_update_bits(rdev->regmap, di->sleep_reg,
149f2a9eb97SBjorn Andersson 				 di->desc.vsel_mask, ret);
15049d8c599SYunfan Zhang 	if (ret < 0)
151145fe1e1SSachin Kamat 		return ret;
15249d8c599SYunfan Zhang 	/* Cache the sleep voltage setting.
15349d8c599SYunfan Zhang 	 * Might not be the real voltage which is rounded */
15449d8c599SYunfan Zhang 	di->sleep_vol_cache = uV;
15549d8c599SYunfan Zhang 
15649d8c599SYunfan Zhang 	return 0;
15749d8c599SYunfan Zhang }
15849d8c599SYunfan Zhang 
159ab7cad33Szhangqing static int fan53555_set_suspend_enable(struct regulator_dev *rdev)
160ab7cad33Szhangqing {
161ab7cad33Szhangqing 	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
162ab7cad33Szhangqing 
163a69929c7SAxel Lin 	return regmap_update_bits(rdev->regmap, di->sleep_reg,
164ab7cad33Szhangqing 				  VSEL_BUCK_EN, VSEL_BUCK_EN);
165ab7cad33Szhangqing }
166ab7cad33Szhangqing 
167ab7cad33Szhangqing static int fan53555_set_suspend_disable(struct regulator_dev *rdev)
168ab7cad33Szhangqing {
169ab7cad33Szhangqing 	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
170ab7cad33Szhangqing 
171a69929c7SAxel Lin 	return regmap_update_bits(rdev->regmap, di->sleep_reg,
172ab7cad33Szhangqing 				  VSEL_BUCK_EN, 0);
173ab7cad33Szhangqing }
174ab7cad33Szhangqing 
17549d8c599SYunfan Zhang static int fan53555_set_mode(struct regulator_dev *rdev, unsigned int mode)
17649d8c599SYunfan Zhang {
17749d8c599SYunfan Zhang 	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
17849d8c599SYunfan Zhang 
17949d8c599SYunfan Zhang 	switch (mode) {
18049d8c599SYunfan Zhang 	case REGULATOR_MODE_FAST:
181a69929c7SAxel Lin 		regmap_update_bits(rdev->regmap, di->mode_reg,
182f2a9eb97SBjorn Andersson 				   di->mode_mask, di->mode_mask);
18349d8c599SYunfan Zhang 		break;
18449d8c599SYunfan Zhang 	case REGULATOR_MODE_NORMAL:
185a69929c7SAxel Lin 		regmap_update_bits(rdev->regmap, di->vol_reg, di->mode_mask, 0);
18649d8c599SYunfan Zhang 		break;
18749d8c599SYunfan Zhang 	default:
18849d8c599SYunfan Zhang 		return -EINVAL;
18949d8c599SYunfan Zhang 	}
19049d8c599SYunfan Zhang 	return 0;
19149d8c599SYunfan Zhang }
19249d8c599SYunfan Zhang 
19349d8c599SYunfan Zhang static unsigned int fan53555_get_mode(struct regulator_dev *rdev)
19449d8c599SYunfan Zhang {
19549d8c599SYunfan Zhang 	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
19649d8c599SYunfan Zhang 	unsigned int val;
19749d8c599SYunfan Zhang 	int ret = 0;
19849d8c599SYunfan Zhang 
199a69929c7SAxel Lin 	ret = regmap_read(rdev->regmap, di->mode_reg, &val);
20049d8c599SYunfan Zhang 	if (ret < 0)
20149d8c599SYunfan Zhang 		return ret;
202f2a9eb97SBjorn Andersson 	if (val & di->mode_mask)
20349d8c599SYunfan Zhang 		return REGULATOR_MODE_FAST;
20449d8c599SYunfan Zhang 	else
20549d8c599SYunfan Zhang 		return REGULATOR_MODE_NORMAL;
20649d8c599SYunfan Zhang }
20749d8c599SYunfan Zhang 
208b61ac767SAxel Lin static const unsigned int slew_rates[] = {
209dd7e71fbSHeiko Stuebner 	64000,
210dd7e71fbSHeiko Stuebner 	32000,
211dd7e71fbSHeiko Stuebner 	16000,
212dd7e71fbSHeiko Stuebner 	 8000,
213dd7e71fbSHeiko Stuebner 	 4000,
214dd7e71fbSHeiko Stuebner 	 2000,
215dd7e71fbSHeiko Stuebner 	 1000,
216dd7e71fbSHeiko Stuebner 	  500,
217dd7e71fbSHeiko Stuebner };
218dd7e71fbSHeiko Stuebner 
219b61ac767SAxel Lin static const unsigned int tcs_slew_rates[] = {
220914df8faSJoseph Chen 	18700,
221914df8faSJoseph Chen 	 9300,
222914df8faSJoseph Chen 	 4600,
223914df8faSJoseph Chen 	 2300,
224914df8faSJoseph Chen };
225914df8faSJoseph Chen 
22671880ab2SBhumika Goyal static const struct regulator_ops fan53555_regulator_ops = {
22749d8c599SYunfan Zhang 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
22849d8c599SYunfan Zhang 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
229fda87a42SHeiko Stuebner 	.set_voltage_time_sel = regulator_set_voltage_time_sel,
23049d8c599SYunfan Zhang 	.map_voltage = regulator_map_voltage_linear,
23149d8c599SYunfan Zhang 	.list_voltage = regulator_list_voltage_linear,
23249d8c599SYunfan Zhang 	.set_suspend_voltage = fan53555_set_suspend_voltage,
23349d8c599SYunfan Zhang 	.enable = regulator_enable_regmap,
23449d8c599SYunfan Zhang 	.disable = regulator_disable_regmap,
23549d8c599SYunfan Zhang 	.is_enabled = regulator_is_enabled_regmap,
23649d8c599SYunfan Zhang 	.set_mode = fan53555_set_mode,
23749d8c599SYunfan Zhang 	.get_mode = fan53555_get_mode,
238b61ac767SAxel Lin 	.set_ramp_delay = regulator_set_ramp_delay_regmap,
239ab7cad33Szhangqing 	.set_suspend_enable = fan53555_set_suspend_enable,
240ab7cad33Szhangqing 	.set_suspend_disable = fan53555_set_suspend_disable,
24149d8c599SYunfan Zhang };
24249d8c599SYunfan Zhang 
243f2a9eb97SBjorn Andersson static int fan53526_voltages_setup_fairchild(struct fan53555_device_info *di)
244f2a9eb97SBjorn Andersson {
245f2a9eb97SBjorn Andersson 	/* Init voltage range and step */
246f2a9eb97SBjorn Andersson 	switch (di->chip_id) {
247f2a9eb97SBjorn Andersson 	case FAN53526_CHIP_ID_01:
248f2a9eb97SBjorn Andersson 		switch (di->chip_rev) {
249f2a9eb97SBjorn Andersson 		case FAN53526_CHIP_REV_08:
250f2a9eb97SBjorn Andersson 			di->vsel_min = 600000;
251f2a9eb97SBjorn Andersson 			di->vsel_step = 6250;
252f2a9eb97SBjorn Andersson 			break;
253f2a9eb97SBjorn Andersson 		default:
254f2a9eb97SBjorn Andersson 			dev_err(di->dev,
255f2a9eb97SBjorn Andersson 				"Chip ID %d with rev %d not supported!\n",
256f2a9eb97SBjorn Andersson 				di->chip_id, di->chip_rev);
257f2a9eb97SBjorn Andersson 			return -EINVAL;
258f2a9eb97SBjorn Andersson 		}
259f2a9eb97SBjorn Andersson 		break;
260f2a9eb97SBjorn Andersson 	default:
261f2a9eb97SBjorn Andersson 		dev_err(di->dev,
262f2a9eb97SBjorn Andersson 			"Chip ID %d not supported!\n", di->chip_id);
263f2a9eb97SBjorn Andersson 		return -EINVAL;
264f2a9eb97SBjorn Andersson 	}
265f2a9eb97SBjorn Andersson 
26630b38b80SAxel Lin 	di->slew_reg = FAN53555_CONTROL;
26730b38b80SAxel Lin 	di->slew_mask = CTL_SLEW_MASK;
268b61ac767SAxel Lin 	di->ramp_delay_table = slew_rates;
269b61ac767SAxel Lin 	di->n_ramp_values = ARRAY_SIZE(slew_rates);
270f2a9eb97SBjorn Andersson 	di->vsel_count = FAN53526_NVOLTAGES;
271f2a9eb97SBjorn Andersson 
272f2a9eb97SBjorn Andersson 	return 0;
273f2a9eb97SBjorn Andersson }
274f2a9eb97SBjorn Andersson 
275ee30928aSHeiko Stuebner static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di)
27649d8c599SYunfan Zhang {
27749d8c599SYunfan Zhang 	/* Init voltage range and step */
27849d8c599SYunfan Zhang 	switch (di->chip_id) {
27949d8c599SYunfan Zhang 	case FAN53555_CHIP_ID_00:
280e57cbb70SWadim Egorov 		switch (di->chip_rev) {
281e57cbb70SWadim Egorov 		case FAN53555_CHIP_REV_00:
282e57cbb70SWadim Egorov 			di->vsel_min = 600000;
283e57cbb70SWadim Egorov 			di->vsel_step = 10000;
284e57cbb70SWadim Egorov 			break;
285e57cbb70SWadim Egorov 		case FAN53555_CHIP_REV_13:
286e57cbb70SWadim Egorov 			di->vsel_min = 800000;
287e57cbb70SWadim Egorov 			di->vsel_step = 10000;
288e57cbb70SWadim Egorov 			break;
289e57cbb70SWadim Egorov 		default:
290e57cbb70SWadim Egorov 			dev_err(di->dev,
291e57cbb70SWadim Egorov 				"Chip ID %d with rev %d not supported!\n",
292e57cbb70SWadim Egorov 				di->chip_id, di->chip_rev);
293e57cbb70SWadim Egorov 			return -EINVAL;
294e57cbb70SWadim Egorov 		}
295e57cbb70SWadim Egorov 		break;
29649d8c599SYunfan Zhang 	case FAN53555_CHIP_ID_01:
29749d8c599SYunfan Zhang 	case FAN53555_CHIP_ID_03:
29849d8c599SYunfan Zhang 	case FAN53555_CHIP_ID_05:
2995e39cf49SWadim Egorov 	case FAN53555_CHIP_ID_08:
30049d8c599SYunfan Zhang 		di->vsel_min = 600000;
30149d8c599SYunfan Zhang 		di->vsel_step = 10000;
30249d8c599SYunfan Zhang 		break;
30349d8c599SYunfan Zhang 	case FAN53555_CHIP_ID_04:
30449d8c599SYunfan Zhang 		di->vsel_min = 603000;
30549d8c599SYunfan Zhang 		di->vsel_step = 12826;
30649d8c599SYunfan Zhang 		break;
30749d8c599SYunfan Zhang 	default:
30849d8c599SYunfan Zhang 		dev_err(di->dev,
309ee30928aSHeiko Stuebner 			"Chip ID %d not supported!\n", di->chip_id);
31049d8c599SYunfan Zhang 		return -EINVAL;
31149d8c599SYunfan Zhang 	}
312914df8faSJoseph Chen 	di->slew_reg = FAN53555_CONTROL;
313914df8faSJoseph Chen 	di->slew_mask = CTL_SLEW_MASK;
314b61ac767SAxel Lin 	di->ramp_delay_table = slew_rates;
315b61ac767SAxel Lin 	di->n_ramp_values = ARRAY_SIZE(slew_rates);
316f2a9eb97SBjorn Andersson 	di->vsel_count = FAN53555_NVOLTAGES;
317f2a9eb97SBjorn Andersson 
318dd7e71fbSHeiko Stuebner 	return 0;
31949d8c599SYunfan Zhang }
32049d8c599SYunfan Zhang 
321ee30928aSHeiko Stuebner static int fan53555_voltages_setup_silergy(struct fan53555_device_info *di)
322ee30928aSHeiko Stuebner {
323ee30928aSHeiko Stuebner 	/* Init voltage range and step */
324ee30928aSHeiko Stuebner 	switch (di->chip_id) {
325ee30928aSHeiko Stuebner 	case SILERGY_SYR82X:
3265365e3dfSVasily Khoruzhick 	case SILERGY_SYR83X:
327ee30928aSHeiko Stuebner 		di->vsel_min = 712500;
328ee30928aSHeiko Stuebner 		di->vsel_step = 12500;
329ee30928aSHeiko Stuebner 		break;
330ee30928aSHeiko Stuebner 	default:
331ee30928aSHeiko Stuebner 		dev_err(di->dev,
332ee30928aSHeiko Stuebner 			"Chip ID %d not supported!\n", di->chip_id);
333ee30928aSHeiko Stuebner 		return -EINVAL;
334ee30928aSHeiko Stuebner 	}
335914df8faSJoseph Chen 	di->slew_reg = FAN53555_CONTROL;
336914df8faSJoseph Chen 	di->slew_mask = CTL_SLEW_MASK;
337b61ac767SAxel Lin 	di->ramp_delay_table = slew_rates;
338b61ac767SAxel Lin 	di->n_ramp_values = ARRAY_SIZE(slew_rates);
339f2a9eb97SBjorn Andersson 	di->vsel_count = FAN53555_NVOLTAGES;
340f2a9eb97SBjorn Andersson 
341ee30928aSHeiko Stuebner 	return 0;
342ee30928aSHeiko Stuebner }
343ee30928aSHeiko Stuebner 
344b3cc8ec0SPeter Geis static int fan53526_voltages_setup_tcs(struct fan53555_device_info *di)
345914df8faSJoseph Chen {
346f9028dcdSPeter Geis 	switch (di->chip_id) {
347f9028dcdSPeter Geis 	case TCS4525_CHIP_ID_12:
3485eee5eceSRudi Heitbaum 	case TCS4526_CHIP_ID_00:
349914df8faSJoseph Chen 		di->slew_reg = TCS4525_TIME;
350914df8faSJoseph Chen 		di->slew_mask = TCS_SLEW_MASK;
351b61ac767SAxel Lin 		di->ramp_delay_table = tcs_slew_rates;
352b61ac767SAxel Lin 		di->n_ramp_values = ARRAY_SIZE(tcs_slew_rates);
353914df8faSJoseph Chen 
354914df8faSJoseph Chen 		/* Init voltage range and step */
355914df8faSJoseph Chen 		di->vsel_min = 600000;
356914df8faSJoseph Chen 		di->vsel_step = 6250;
357d4db69ebSPeter Geis 		di->vsel_count = FAN53526_NVOLTAGES;
358f9028dcdSPeter Geis 		break;
359f9028dcdSPeter Geis 	default:
360f9028dcdSPeter Geis 		dev_err(di->dev, "Chip ID %d not supported!\n", di->chip_id);
361f9028dcdSPeter Geis 		return -EINVAL;
362f9028dcdSPeter Geis 	}
363914df8faSJoseph Chen 
364914df8faSJoseph Chen 	return 0;
365914df8faSJoseph Chen }
366914df8faSJoseph Chen 
367ee30928aSHeiko Stuebner /* For 00,01,03,05 options:
368ee30928aSHeiko Stuebner  * VOUT = 0.60V + NSELx * 10mV, from 0.60 to 1.23V.
369ee30928aSHeiko Stuebner  * For 04 option:
370ee30928aSHeiko Stuebner  * VOUT = 0.603V + NSELx * 12.826mV, from 0.603 to 1.411V.
371ee30928aSHeiko Stuebner  * */
372ee30928aSHeiko Stuebner static int fan53555_device_setup(struct fan53555_device_info *di,
373ee30928aSHeiko Stuebner 				struct fan53555_platform_data *pdata)
374ee30928aSHeiko Stuebner {
375ee30928aSHeiko Stuebner 	int ret = 0;
376ee30928aSHeiko Stuebner 
377ee30928aSHeiko Stuebner 	/* Setup voltage control register */
378914df8faSJoseph Chen 	switch (di->vendor) {
379914df8faSJoseph Chen 	case FAN53526_VENDOR_FAIRCHILD:
380914df8faSJoseph Chen 	case FAN53555_VENDOR_FAIRCHILD:
381914df8faSJoseph Chen 	case FAN53555_VENDOR_SILERGY:
382ee30928aSHeiko Stuebner 		switch (pdata->sleep_vsel_id) {
383ee30928aSHeiko Stuebner 		case FAN53555_VSEL_ID_0:
384ee30928aSHeiko Stuebner 			di->sleep_reg = FAN53555_VSEL0;
385ee30928aSHeiko Stuebner 			di->vol_reg = FAN53555_VSEL1;
386ee30928aSHeiko Stuebner 			break;
387ee30928aSHeiko Stuebner 		case FAN53555_VSEL_ID_1:
388ee30928aSHeiko Stuebner 			di->sleep_reg = FAN53555_VSEL1;
389ee30928aSHeiko Stuebner 			di->vol_reg = FAN53555_VSEL0;
390ee30928aSHeiko Stuebner 			break;
391ee30928aSHeiko Stuebner 		default:
392ee30928aSHeiko Stuebner 			dev_err(di->dev, "Invalid VSEL ID!\n");
393ee30928aSHeiko Stuebner 			return -EINVAL;
394ee30928aSHeiko Stuebner 		}
395914df8faSJoseph Chen 		break;
396b3cc8ec0SPeter Geis 	case FAN53526_VENDOR_TCS:
397914df8faSJoseph Chen 		switch (pdata->sleep_vsel_id) {
398914df8faSJoseph Chen 		case FAN53555_VSEL_ID_0:
399914df8faSJoseph Chen 			di->sleep_reg = TCS4525_VSEL0;
400914df8faSJoseph Chen 			di->vol_reg = TCS4525_VSEL1;
401914df8faSJoseph Chen 			break;
402914df8faSJoseph Chen 		case FAN53555_VSEL_ID_1:
403914df8faSJoseph Chen 			di->sleep_reg = TCS4525_VSEL1;
404914df8faSJoseph Chen 			di->vol_reg = TCS4525_VSEL0;
405914df8faSJoseph Chen 			break;
406914df8faSJoseph Chen 		default:
407914df8faSJoseph Chen 			dev_err(di->dev, "Invalid VSEL ID!\n");
408914df8faSJoseph Chen 			return -EINVAL;
409914df8faSJoseph Chen 		}
410914df8faSJoseph Chen 		break;
411914df8faSJoseph Chen 	default:
412914df8faSJoseph Chen 		dev_err(di->dev, "vendor %d not supported!\n", di->vendor);
413914df8faSJoseph Chen 		return -EINVAL;
414914df8faSJoseph Chen 	}
415ee30928aSHeiko Stuebner 
416f2a9eb97SBjorn Andersson 	/* Setup mode control register */
417ee30928aSHeiko Stuebner 	switch (di->vendor) {
418f2a9eb97SBjorn Andersson 	case FAN53526_VENDOR_FAIRCHILD:
419f2a9eb97SBjorn Andersson 		di->mode_reg = FAN53555_CONTROL;
420f2a9eb97SBjorn Andersson 
421f2a9eb97SBjorn Andersson 		switch (pdata->sleep_vsel_id) {
422f2a9eb97SBjorn Andersson 		case FAN53555_VSEL_ID_0:
423f2a9eb97SBjorn Andersson 			di->mode_mask = CTL_MODE_VSEL1_MODE;
424f2a9eb97SBjorn Andersson 			break;
425f2a9eb97SBjorn Andersson 		case FAN53555_VSEL_ID_1:
426f2a9eb97SBjorn Andersson 			di->mode_mask = CTL_MODE_VSEL0_MODE;
427f2a9eb97SBjorn Andersson 			break;
428f2a9eb97SBjorn Andersson 		}
429f2a9eb97SBjorn Andersson 		break;
430f2a9eb97SBjorn Andersson 	case FAN53555_VENDOR_FAIRCHILD:
431f2a9eb97SBjorn Andersson 	case FAN53555_VENDOR_SILERGY:
432f2a9eb97SBjorn Andersson 		di->mode_reg = di->vol_reg;
433f2a9eb97SBjorn Andersson 		di->mode_mask = VSEL_MODE;
434f2a9eb97SBjorn Andersson 		break;
435b3cc8ec0SPeter Geis 	case FAN53526_VENDOR_TCS:
436914df8faSJoseph Chen 		di->mode_reg = TCS4525_COMMAND;
437914df8faSJoseph Chen 
438914df8faSJoseph Chen 		switch (pdata->sleep_vsel_id) {
439914df8faSJoseph Chen 		case FAN53555_VSEL_ID_0:
440914df8faSJoseph Chen 			di->mode_mask = TCS_VSEL1_MODE;
441914df8faSJoseph Chen 			break;
442914df8faSJoseph Chen 		case FAN53555_VSEL_ID_1:
443914df8faSJoseph Chen 			di->mode_mask = TCS_VSEL0_MODE;
444914df8faSJoseph Chen 			break;
445914df8faSJoseph Chen 		}
446914df8faSJoseph Chen 		break;
447f2a9eb97SBjorn Andersson 	default:
448f2a9eb97SBjorn Andersson 		dev_err(di->dev, "vendor %d not supported!\n", di->vendor);
449f2a9eb97SBjorn Andersson 		return -EINVAL;
450f2a9eb97SBjorn Andersson 	}
451f2a9eb97SBjorn Andersson 
452f2a9eb97SBjorn Andersson 	/* Setup voltage range */
453f2a9eb97SBjorn Andersson 	switch (di->vendor) {
454f2a9eb97SBjorn Andersson 	case FAN53526_VENDOR_FAIRCHILD:
455f2a9eb97SBjorn Andersson 		ret = fan53526_voltages_setup_fairchild(di);
456f2a9eb97SBjorn Andersson 		break;
457ee30928aSHeiko Stuebner 	case FAN53555_VENDOR_FAIRCHILD:
458ee30928aSHeiko Stuebner 		ret = fan53555_voltages_setup_fairchild(di);
459ee30928aSHeiko Stuebner 		break;
460ee30928aSHeiko Stuebner 	case FAN53555_VENDOR_SILERGY:
461ee30928aSHeiko Stuebner 		ret = fan53555_voltages_setup_silergy(di);
462ee30928aSHeiko Stuebner 		break;
463b3cc8ec0SPeter Geis 	case FAN53526_VENDOR_TCS:
464b3cc8ec0SPeter Geis 		ret = fan53526_voltages_setup_tcs(di);
465914df8faSJoseph Chen 		break;
466ee30928aSHeiko Stuebner 	default:
467fe230531SAxel Lin 		dev_err(di->dev, "vendor %d not supported!\n", di->vendor);
468ee30928aSHeiko Stuebner 		return -EINVAL;
469ee30928aSHeiko Stuebner 	}
470ee30928aSHeiko Stuebner 
471ee30928aSHeiko Stuebner 	return ret;
472ee30928aSHeiko Stuebner }
473ee30928aSHeiko Stuebner 
47449d8c599SYunfan Zhang static int fan53555_regulator_register(struct fan53555_device_info *di,
47549d8c599SYunfan Zhang 			struct regulator_config *config)
47649d8c599SYunfan Zhang {
47749d8c599SYunfan Zhang 	struct regulator_desc *rdesc = &di->desc;
478a69929c7SAxel Lin 	struct regulator_dev *rdev;
47949d8c599SYunfan Zhang 
48049d8c599SYunfan Zhang 	rdesc->name = "fan53555-reg";
4813415d601SHeiko Stuebner 	rdesc->supply_name = "vin";
48249d8c599SYunfan Zhang 	rdesc->ops = &fan53555_regulator_ops;
48349d8c599SYunfan Zhang 	rdesc->type = REGULATOR_VOLTAGE;
484f2a9eb97SBjorn Andersson 	rdesc->n_voltages = di->vsel_count;
48549d8c599SYunfan Zhang 	rdesc->enable_reg = di->vol_reg;
48649d8c599SYunfan Zhang 	rdesc->enable_mask = VSEL_BUCK_EN;
48749d8c599SYunfan Zhang 	rdesc->min_uV = di->vsel_min;
48849d8c599SYunfan Zhang 	rdesc->uV_step = di->vsel_step;
48949d8c599SYunfan Zhang 	rdesc->vsel_reg = di->vol_reg;
490f2a9eb97SBjorn Andersson 	rdesc->vsel_mask = di->vsel_count - 1;
491b61ac767SAxel Lin 	rdesc->ramp_reg = di->slew_reg;
492b61ac767SAxel Lin 	rdesc->ramp_mask = di->slew_mask;
493b61ac767SAxel Lin 	rdesc->ramp_delay_table = di->ramp_delay_table;
494b61ac767SAxel Lin 	rdesc->n_ramp_values = di->n_ramp_values;
49549d8c599SYunfan Zhang 	rdesc->owner = THIS_MODULE;
49649d8c599SYunfan Zhang 
497a69929c7SAxel Lin 	rdev = devm_regulator_register(di->dev, &di->desc, config);
498a69929c7SAxel Lin 	return PTR_ERR_OR_ZERO(rdev);
49949d8c599SYunfan Zhang }
50049d8c599SYunfan Zhang 
501121b567dSKrzysztof Kozlowski static const struct regmap_config fan53555_regmap_config = {
50249d8c599SYunfan Zhang 	.reg_bits = 8,
50349d8c599SYunfan Zhang 	.val_bits = 8,
50449d8c599SYunfan Zhang };
50549d8c599SYunfan Zhang 
50691f23d8fSHeiko Stuebner static struct fan53555_platform_data *fan53555_parse_dt(struct device *dev,
507072e78b1SJavier Martinez Canillas 					      struct device_node *np,
508072e78b1SJavier Martinez Canillas 					      const struct regulator_desc *desc)
50991f23d8fSHeiko Stuebner {
51091f23d8fSHeiko Stuebner 	struct fan53555_platform_data *pdata;
51191f23d8fSHeiko Stuebner 	int ret;
51291f23d8fSHeiko Stuebner 	u32 tmp;
51391f23d8fSHeiko Stuebner 
51491f23d8fSHeiko Stuebner 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
51591f23d8fSHeiko Stuebner 	if (!pdata)
51691f23d8fSHeiko Stuebner 		return NULL;
51791f23d8fSHeiko Stuebner 
518072e78b1SJavier Martinez Canillas 	pdata->regulator = of_get_regulator_init_data(dev, np, desc);
51991f23d8fSHeiko Stuebner 
52091f23d8fSHeiko Stuebner 	ret = of_property_read_u32(np, "fcs,suspend-voltage-selector",
52191f23d8fSHeiko Stuebner 				   &tmp);
52291f23d8fSHeiko Stuebner 	if (!ret)
52391f23d8fSHeiko Stuebner 		pdata->sleep_vsel_id = tmp;
52491f23d8fSHeiko Stuebner 
52591f23d8fSHeiko Stuebner 	return pdata;
52691f23d8fSHeiko Stuebner }
52791f23d8fSHeiko Stuebner 
5285e97d7e8SJisheng Zhang static const struct of_device_id __maybe_unused fan53555_dt_ids[] = {
52991f23d8fSHeiko Stuebner 	{
530f2a9eb97SBjorn Andersson 		.compatible = "fcs,fan53526",
531f2a9eb97SBjorn Andersson 		.data = (void *)FAN53526_VENDOR_FAIRCHILD,
532f2a9eb97SBjorn Andersson 	}, {
53391f23d8fSHeiko Stuebner 		.compatible = "fcs,fan53555",
534ee30928aSHeiko Stuebner 		.data = (void *)FAN53555_VENDOR_FAIRCHILD
535ee30928aSHeiko Stuebner 	}, {
536ee30928aSHeiko Stuebner 		.compatible = "silergy,syr827",
537ee30928aSHeiko Stuebner 		.data = (void *)FAN53555_VENDOR_SILERGY,
538ee30928aSHeiko Stuebner 	}, {
539ee30928aSHeiko Stuebner 		.compatible = "silergy,syr828",
540ee30928aSHeiko Stuebner 		.data = (void *)FAN53555_VENDOR_SILERGY,
541914df8faSJoseph Chen 	}, {
542914df8faSJoseph Chen 		.compatible = "tcs,tcs4525",
543b3cc8ec0SPeter Geis 		.data = (void *)FAN53526_VENDOR_TCS
5445eee5eceSRudi Heitbaum 	}, {
5455eee5eceSRudi Heitbaum 		.compatible = "tcs,tcs4526",
5465eee5eceSRudi Heitbaum 		.data = (void *)FAN53526_VENDOR_TCS
54791f23d8fSHeiko Stuebner 	},
54891f23d8fSHeiko Stuebner 	{ }
54991f23d8fSHeiko Stuebner };
55091f23d8fSHeiko Stuebner MODULE_DEVICE_TABLE(of, fan53555_dt_ids);
55191f23d8fSHeiko Stuebner 
55265542565SUwe Kleine-König static int fan53555_regulator_probe(struct i2c_client *client)
55349d8c599SYunfan Zhang {
55465542565SUwe Kleine-König 	const struct i2c_device_id *id = i2c_client_get_device_id(client);
55591f23d8fSHeiko Stuebner 	struct device_node *np = client->dev.of_node;
55649d8c599SYunfan Zhang 	struct fan53555_device_info *di;
55749d8c599SYunfan Zhang 	struct fan53555_platform_data *pdata;
55849d8c599SYunfan Zhang 	struct regulator_config config = { };
559a69929c7SAxel Lin 	struct regmap *regmap;
56049d8c599SYunfan Zhang 	unsigned int val;
56149d8c599SYunfan Zhang 	int ret;
56249d8c599SYunfan Zhang 
563072e78b1SJavier Martinez Canillas 	di = devm_kzalloc(&client->dev, sizeof(struct fan53555_device_info),
564072e78b1SJavier Martinez Canillas 					GFP_KERNEL);
565072e78b1SJavier Martinez Canillas 	if (!di)
566072e78b1SJavier Martinez Canillas 		return -ENOMEM;
567072e78b1SJavier Martinez Canillas 
568dff91d0bSJingoo Han 	pdata = dev_get_platdata(&client->dev);
56991f23d8fSHeiko Stuebner 	if (!pdata)
570072e78b1SJavier Martinez Canillas 		pdata = fan53555_parse_dt(&client->dev, np, &di->desc);
57191f23d8fSHeiko Stuebner 
57249d8c599SYunfan Zhang 	if (!pdata || !pdata->regulator) {
57349d8c599SYunfan Zhang 		dev_err(&client->dev, "Platform data not found!\n");
57449d8c599SYunfan Zhang 		return -ENODEV;
57549d8c599SYunfan Zhang 	}
57649d8c599SYunfan Zhang 
577e13426bfSAxel Lin 	di->regulator = pdata->regulator;
578ee30928aSHeiko Stuebner 	if (client->dev.of_node) {
579d110e3e9SJisheng Zhang 		di->vendor =
580d110e3e9SJisheng Zhang 			(unsigned long)of_device_get_match_data(&client->dev);
581ee30928aSHeiko Stuebner 	} else {
582dd7e71fbSHeiko Stuebner 		/* if no ramp constraint set, get the pdata ramp_delay */
583dd7e71fbSHeiko Stuebner 		if (!di->regulator->constraints.ramp_delay) {
58487919e0cSAxel Lin 			if (pdata->slew_rate >= ARRAY_SIZE(slew_rates)) {
58587919e0cSAxel Lin 				dev_err(&client->dev, "Invalid slew_rate\n");
58687919e0cSAxel Lin 				return -EINVAL;
58787919e0cSAxel Lin 			}
588dd7e71fbSHeiko Stuebner 
58991f23d8fSHeiko Stuebner 			di->regulator->constraints.ramp_delay
59087919e0cSAxel Lin 					= slew_rates[pdata->slew_rate];
59191f23d8fSHeiko Stuebner 		}
592ee30928aSHeiko Stuebner 
593ee30928aSHeiko Stuebner 		di->vendor = id->driver_data;
594dd7e71fbSHeiko Stuebner 	}
595dd7e71fbSHeiko Stuebner 
596a69929c7SAxel Lin 	regmap = devm_regmap_init_i2c(client, &fan53555_regmap_config);
597a69929c7SAxel Lin 	if (IS_ERR(regmap)) {
59849d8c599SYunfan Zhang 		dev_err(&client->dev, "Failed to allocate regmap!\n");
599a69929c7SAxel Lin 		return PTR_ERR(regmap);
60049d8c599SYunfan Zhang 	}
60149d8c599SYunfan Zhang 	di->dev = &client->dev;
60249d8c599SYunfan Zhang 	i2c_set_clientdata(client, di);
60349d8c599SYunfan Zhang 	/* Get chip ID */
604a69929c7SAxel Lin 	ret = regmap_read(regmap, FAN53555_ID1, &val);
60549d8c599SYunfan Zhang 	if (ret < 0) {
60649d8c599SYunfan Zhang 		dev_err(&client->dev, "Failed to get chip ID!\n");
607145fe1e1SSachin Kamat 		return ret;
60849d8c599SYunfan Zhang 	}
60949d8c599SYunfan Zhang 	di->chip_id = val & DIE_ID;
61049d8c599SYunfan Zhang 	/* Get chip revision */
611a69929c7SAxel Lin 	ret = regmap_read(regmap, FAN53555_ID2, &val);
61249d8c599SYunfan Zhang 	if (ret < 0) {
61349d8c599SYunfan Zhang 		dev_err(&client->dev, "Failed to get chip Rev!\n");
614145fe1e1SSachin Kamat 		return ret;
61549d8c599SYunfan Zhang 	}
61649d8c599SYunfan Zhang 	di->chip_rev = val & DIE_REV;
61749d8c599SYunfan Zhang 	dev_info(&client->dev, "FAN53555 Option[%d] Rev[%d] Detected!\n",
61849d8c599SYunfan Zhang 				di->chip_id, di->chip_rev);
61949d8c599SYunfan Zhang 	/* Device init */
62049d8c599SYunfan Zhang 	ret = fan53555_device_setup(di, pdata);
62149d8c599SYunfan Zhang 	if (ret < 0) {
62249d8c599SYunfan Zhang 		dev_err(&client->dev, "Failed to setup device!\n");
62349d8c599SYunfan Zhang 		return ret;
62449d8c599SYunfan Zhang 	}
62549d8c599SYunfan Zhang 	/* Register regulator */
62649d8c599SYunfan Zhang 	config.dev = di->dev;
62749d8c599SYunfan Zhang 	config.init_data = di->regulator;
628a69929c7SAxel Lin 	config.regmap = regmap;
62949d8c599SYunfan Zhang 	config.driver_data = di;
63091f23d8fSHeiko Stuebner 	config.of_node = np;
63191f23d8fSHeiko Stuebner 
63249d8c599SYunfan Zhang 	ret = fan53555_regulator_register(di, &config);
63349d8c599SYunfan Zhang 	if (ret < 0)
63449d8c599SYunfan Zhang 		dev_err(&client->dev, "Failed to register regulator!\n");
63549d8c599SYunfan Zhang 	return ret;
63649d8c599SYunfan Zhang 
63749d8c599SYunfan Zhang }
63849d8c599SYunfan Zhang 
63949d8c599SYunfan Zhang static const struct i2c_device_id fan53555_id[] = {
640ee30928aSHeiko Stuebner 	{
641f2a9eb97SBjorn Andersson 		.name = "fan53526",
642f2a9eb97SBjorn Andersson 		.driver_data = FAN53526_VENDOR_FAIRCHILD
643f2a9eb97SBjorn Andersson 	}, {
644ee30928aSHeiko Stuebner 		.name = "fan53555",
645ee30928aSHeiko Stuebner 		.driver_data = FAN53555_VENDOR_FAIRCHILD
646ee30928aSHeiko Stuebner 	}, {
647fc1111b8SGuillaume Tucker 		.name = "syr827",
648fc1111b8SGuillaume Tucker 		.driver_data = FAN53555_VENDOR_SILERGY
649fc1111b8SGuillaume Tucker 	}, {
650fc1111b8SGuillaume Tucker 		.name = "syr828",
651ee30928aSHeiko Stuebner 		.driver_data = FAN53555_VENDOR_SILERGY
652914df8faSJoseph Chen 	}, {
653914df8faSJoseph Chen 		.name = "tcs4525",
654b3cc8ec0SPeter Geis 		.driver_data = FAN53526_VENDOR_TCS
6555eee5eceSRudi Heitbaum 	}, {
6565eee5eceSRudi Heitbaum 		.name = "tcs4526",
6575eee5eceSRudi Heitbaum 		.driver_data = FAN53526_VENDOR_TCS
658ee30928aSHeiko Stuebner 	},
65949d8c599SYunfan Zhang 	{ },
66049d8c599SYunfan Zhang };
661e80c47bdSJavier Martinez Canillas MODULE_DEVICE_TABLE(i2c, fan53555_id);
66249d8c599SYunfan Zhang 
66349d8c599SYunfan Zhang static struct i2c_driver fan53555_regulator_driver = {
66449d8c599SYunfan Zhang 	.driver = {
66549d8c599SYunfan Zhang 		.name = "fan53555-regulator",
666*259b93b2SDouglas Anderson 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
66791f23d8fSHeiko Stuebner 		.of_match_table = of_match_ptr(fan53555_dt_ids),
66849d8c599SYunfan Zhang 	},
66965542565SUwe Kleine-König 	.probe_new = fan53555_regulator_probe,
67049d8c599SYunfan Zhang 	.id_table = fan53555_id,
67149d8c599SYunfan Zhang };
67249d8c599SYunfan Zhang 
67349d8c599SYunfan Zhang module_i2c_driver(fan53555_regulator_driver);
67449d8c599SYunfan Zhang 
67549d8c599SYunfan Zhang MODULE_AUTHOR("Yunfan Zhang <yfzhang@marvell.com>");
67649d8c599SYunfan Zhang MODULE_DESCRIPTION("FAN53555 regulator driver");
67749d8c599SYunfan Zhang MODULE_LICENSE("GPL v2");
678