xref: /openbmc/linux/drivers/regulator/fan53555.c (revision d2501661)
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 
114fb9a506SCristian Ciocaltea #include <linux/bits.h>
1249d8c599SYunfan Zhang #include <linux/err.h>
134fb9a506SCristian Ciocaltea #include <linux/i2c.h>
144fb9a506SCristian Ciocaltea #include <linux/module.h>
154fb9a506SCristian Ciocaltea #include <linux/of_device.h>
164fb9a506SCristian Ciocaltea #include <linux/param.h>
1749d8c599SYunfan Zhang #include <linux/platform_device.h>
184fb9a506SCristian Ciocaltea #include <linux/regmap.h>
1949d8c599SYunfan Zhang #include <linux/regulator/driver.h>
204fb9a506SCristian Ciocaltea #include <linux/regulator/fan53555.h>
2149d8c599SYunfan Zhang #include <linux/regulator/machine.h>
2291f23d8fSHeiko Stuebner #include <linux/regulator/of_regulator.h>
2349d8c599SYunfan Zhang #include <linux/slab.h>
2449d8c599SYunfan Zhang 
2549d8c599SYunfan Zhang /* Voltage setting */
2649d8c599SYunfan Zhang #define FAN53555_VSEL0		0x00
2749d8c599SYunfan Zhang #define FAN53555_VSEL1		0x01
28914df8faSJoseph Chen 
29914df8faSJoseph Chen #define TCS4525_VSEL0		0x11
30914df8faSJoseph Chen #define TCS4525_VSEL1		0x10
31914df8faSJoseph Chen #define TCS4525_TIME		0x13
32914df8faSJoseph Chen #define TCS4525_COMMAND		0x14
33914df8faSJoseph Chen 
3449d8c599SYunfan Zhang /* Control register */
3549d8c599SYunfan Zhang #define FAN53555_CONTROL	0x02
3649d8c599SYunfan Zhang /* IC Type */
3749d8c599SYunfan Zhang #define FAN53555_ID1		0x03
3849d8c599SYunfan Zhang /* IC mask version */
3949d8c599SYunfan Zhang #define FAN53555_ID2		0x04
4049d8c599SYunfan Zhang /* Monitor register */
4149d8c599SYunfan Zhang #define FAN53555_MONITOR	0x05
4249d8c599SYunfan Zhang 
4349d8c599SYunfan Zhang /* VSEL bit definitions */
44*d2501661SCristian Ciocaltea #define VSEL_BUCK_EN		BIT(7)
45*d2501661SCristian Ciocaltea #define VSEL_MODE		BIT(6)
4649d8c599SYunfan Zhang /* Chip ID and Verison */
4749d8c599SYunfan Zhang #define DIE_ID			0x0F	/* ID1 */
4849d8c599SYunfan Zhang #define DIE_REV			0x0F	/* ID2 */
4949d8c599SYunfan Zhang /* Control bit definitions */
50*d2501661SCristian Ciocaltea #define CTL_OUTPUT_DISCHG	BIT(7)
51*d2501661SCristian Ciocaltea #define CTL_SLEW_MASK		GENMASK(6, 4)
52*d2501661SCristian Ciocaltea #define CTL_RESET		BIT(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 
59*d2501661SCristian Ciocaltea #define TCS_VSEL0_MODE		BIT(7)
60*d2501661SCristian Ciocaltea #define TCS_VSEL1_MODE		BIT(6)
61914df8faSJoseph Chen 
62c5d5b55bSCristian Ciocaltea #define TCS_SLEW_MASK		GENMASK(4, 3)
6349d8c599SYunfan Zhang 
64ee30928aSHeiko Stuebner enum fan53555_vendor {
65f2a9eb97SBjorn Andersson 	FAN53526_VENDOR_FAIRCHILD = 0,
66f2a9eb97SBjorn Andersson 	FAN53555_VENDOR_FAIRCHILD,
67ee30928aSHeiko Stuebner 	FAN53555_VENDOR_SILERGY,
68b3cc8ec0SPeter Geis 	FAN53526_VENDOR_TCS,
69ee30928aSHeiko Stuebner };
70ee30928aSHeiko Stuebner 
71f2a9eb97SBjorn Andersson enum {
72f2a9eb97SBjorn Andersson 	FAN53526_CHIP_ID_01 = 1,
73f2a9eb97SBjorn Andersson };
74f2a9eb97SBjorn Andersson 
75f2a9eb97SBjorn Andersson enum {
76f2a9eb97SBjorn Andersson 	FAN53526_CHIP_REV_08 = 8,
77f2a9eb97SBjorn Andersson };
78f2a9eb97SBjorn Andersson 
7949d8c599SYunfan Zhang /* IC Type */
8049d8c599SYunfan Zhang enum {
8149d8c599SYunfan Zhang 	FAN53555_CHIP_ID_00 = 0,
8249d8c599SYunfan Zhang 	FAN53555_CHIP_ID_01,
8349d8c599SYunfan Zhang 	FAN53555_CHIP_ID_02,
8449d8c599SYunfan Zhang 	FAN53555_CHIP_ID_03,
8549d8c599SYunfan Zhang 	FAN53555_CHIP_ID_04,
8649d8c599SYunfan Zhang 	FAN53555_CHIP_ID_05,
875e39cf49SWadim Egorov 	FAN53555_CHIP_ID_08 = 8,
8849d8c599SYunfan Zhang };
8949d8c599SYunfan Zhang 
90f9028dcdSPeter Geis enum {
91f9028dcdSPeter Geis 	TCS4525_CHIP_ID_12 = 12,
92f9028dcdSPeter Geis };
93f9028dcdSPeter Geis 
945eee5eceSRudi Heitbaum enum {
955eee5eceSRudi Heitbaum 	TCS4526_CHIP_ID_00 = 0,
965eee5eceSRudi Heitbaum };
975eee5eceSRudi Heitbaum 
98e57cbb70SWadim Egorov /* IC mask revision */
99e57cbb70SWadim Egorov enum {
100e57cbb70SWadim Egorov 	FAN53555_CHIP_REV_00 = 0x3,
101e57cbb70SWadim Egorov 	FAN53555_CHIP_REV_13 = 0xf,
102e57cbb70SWadim Egorov };
103e57cbb70SWadim Egorov 
104ee30928aSHeiko Stuebner enum {
105ee30928aSHeiko Stuebner 	SILERGY_SYR82X = 8,
1065365e3dfSVasily Khoruzhick 	SILERGY_SYR83X = 9,
107ee30928aSHeiko Stuebner };
108ee30928aSHeiko Stuebner 
10949d8c599SYunfan Zhang struct fan53555_device_info {
110ee30928aSHeiko Stuebner 	enum fan53555_vendor vendor;
11149d8c599SYunfan Zhang 	struct device *dev;
11249d8c599SYunfan Zhang 	struct regulator_desc desc;
11349d8c599SYunfan Zhang 	struct regulator_init_data *regulator;
11449d8c599SYunfan Zhang 	/* IC Type and Rev */
11549d8c599SYunfan Zhang 	int chip_id;
11649d8c599SYunfan Zhang 	int chip_rev;
11749d8c599SYunfan Zhang 	/* Voltage setting register */
11849d8c599SYunfan Zhang 	unsigned int vol_reg;
11949d8c599SYunfan Zhang 	unsigned int sleep_reg;
12049d8c599SYunfan Zhang 	/* Voltage range and step(linear) */
12149d8c599SYunfan Zhang 	unsigned int vsel_min;
12249d8c599SYunfan Zhang 	unsigned int vsel_step;
123f2a9eb97SBjorn Andersson 	unsigned int vsel_count;
124f2a9eb97SBjorn Andersson 	/* Mode */
125f2a9eb97SBjorn Andersson 	unsigned int mode_reg;
126f2a9eb97SBjorn Andersson 	unsigned int mode_mask;
12749d8c599SYunfan Zhang 	/* Sleep voltage cache */
12849d8c599SYunfan Zhang 	unsigned int sleep_vol_cache;
129914df8faSJoseph Chen 	/* Slew rate */
130914df8faSJoseph Chen 	unsigned int slew_reg;
131914df8faSJoseph Chen 	unsigned int slew_mask;
132b61ac767SAxel Lin 	const unsigned int *ramp_delay_table;
133b61ac767SAxel Lin 	unsigned int n_ramp_values;
134914df8faSJoseph Chen 	unsigned int slew_rate;
13549d8c599SYunfan Zhang };
13649d8c599SYunfan Zhang 
13749d8c599SYunfan Zhang static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV)
13849d8c599SYunfan Zhang {
13949d8c599SYunfan Zhang 	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
14049d8c599SYunfan Zhang 	int ret;
14149d8c599SYunfan Zhang 
14249d8c599SYunfan Zhang 	if (di->sleep_vol_cache == uV)
14349d8c599SYunfan Zhang 		return 0;
14449d8c599SYunfan Zhang 	ret = regulator_map_voltage_linear(rdev, uV, uV);
14549d8c599SYunfan Zhang 	if (ret < 0)
146145fe1e1SSachin Kamat 		return ret;
147a69929c7SAxel Lin 	ret = regmap_update_bits(rdev->regmap, di->sleep_reg,
148f2a9eb97SBjorn Andersson 				 di->desc.vsel_mask, ret);
14949d8c599SYunfan Zhang 	if (ret < 0)
150145fe1e1SSachin Kamat 		return ret;
15149d8c599SYunfan Zhang 	/* Cache the sleep voltage setting.
15249d8c599SYunfan Zhang 	 * Might not be the real voltage which is rounded */
15349d8c599SYunfan Zhang 	di->sleep_vol_cache = uV;
15449d8c599SYunfan Zhang 
15549d8c599SYunfan Zhang 	return 0;
15649d8c599SYunfan Zhang }
15749d8c599SYunfan Zhang 
158ab7cad33Szhangqing static int fan53555_set_suspend_enable(struct regulator_dev *rdev)
159ab7cad33Szhangqing {
160ab7cad33Szhangqing 	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
161ab7cad33Szhangqing 
162a69929c7SAxel Lin 	return regmap_update_bits(rdev->regmap, di->sleep_reg,
163ab7cad33Szhangqing 				  VSEL_BUCK_EN, VSEL_BUCK_EN);
164ab7cad33Szhangqing }
165ab7cad33Szhangqing 
166ab7cad33Szhangqing static int fan53555_set_suspend_disable(struct regulator_dev *rdev)
167ab7cad33Szhangqing {
168ab7cad33Szhangqing 	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
169ab7cad33Szhangqing 
170a69929c7SAxel Lin 	return regmap_update_bits(rdev->regmap, di->sleep_reg,
171ab7cad33Szhangqing 				  VSEL_BUCK_EN, 0);
172ab7cad33Szhangqing }
173ab7cad33Szhangqing 
17449d8c599SYunfan Zhang static int fan53555_set_mode(struct regulator_dev *rdev, unsigned int mode)
17549d8c599SYunfan Zhang {
17649d8c599SYunfan Zhang 	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
17749d8c599SYunfan Zhang 
17849d8c599SYunfan Zhang 	switch (mode) {
17949d8c599SYunfan Zhang 	case REGULATOR_MODE_FAST:
180a69929c7SAxel Lin 		regmap_update_bits(rdev->regmap, di->mode_reg,
181f2a9eb97SBjorn Andersson 				   di->mode_mask, di->mode_mask);
18249d8c599SYunfan Zhang 		break;
18349d8c599SYunfan Zhang 	case REGULATOR_MODE_NORMAL:
184a69929c7SAxel Lin 		regmap_update_bits(rdev->regmap, di->vol_reg, di->mode_mask, 0);
18549d8c599SYunfan Zhang 		break;
18649d8c599SYunfan Zhang 	default:
18749d8c599SYunfan Zhang 		return -EINVAL;
18849d8c599SYunfan Zhang 	}
18949d8c599SYunfan Zhang 	return 0;
19049d8c599SYunfan Zhang }
19149d8c599SYunfan Zhang 
19249d8c599SYunfan Zhang static unsigned int fan53555_get_mode(struct regulator_dev *rdev)
19349d8c599SYunfan Zhang {
19449d8c599SYunfan Zhang 	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
19549d8c599SYunfan Zhang 	unsigned int val;
19649d8c599SYunfan Zhang 	int ret = 0;
19749d8c599SYunfan Zhang 
198a69929c7SAxel Lin 	ret = regmap_read(rdev->regmap, di->mode_reg, &val);
19949d8c599SYunfan Zhang 	if (ret < 0)
20049d8c599SYunfan Zhang 		return ret;
201f2a9eb97SBjorn Andersson 	if (val & di->mode_mask)
20249d8c599SYunfan Zhang 		return REGULATOR_MODE_FAST;
20349d8c599SYunfan Zhang 	else
20449d8c599SYunfan Zhang 		return REGULATOR_MODE_NORMAL;
20549d8c599SYunfan Zhang }
20649d8c599SYunfan Zhang 
207b61ac767SAxel Lin static const unsigned int slew_rates[] = {
208dd7e71fbSHeiko Stuebner 	64000,
209dd7e71fbSHeiko Stuebner 	32000,
210dd7e71fbSHeiko Stuebner 	16000,
211dd7e71fbSHeiko Stuebner 	 8000,
212dd7e71fbSHeiko Stuebner 	 4000,
213dd7e71fbSHeiko Stuebner 	 2000,
214dd7e71fbSHeiko Stuebner 	 1000,
215dd7e71fbSHeiko Stuebner 	  500,
216dd7e71fbSHeiko Stuebner };
217dd7e71fbSHeiko Stuebner 
218b61ac767SAxel Lin static const unsigned int tcs_slew_rates[] = {
219914df8faSJoseph Chen 	18700,
220914df8faSJoseph Chen 	 9300,
221914df8faSJoseph Chen 	 4600,
222914df8faSJoseph Chen 	 2300,
223914df8faSJoseph Chen };
224914df8faSJoseph Chen 
22571880ab2SBhumika Goyal static const struct regulator_ops fan53555_regulator_ops = {
22649d8c599SYunfan Zhang 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
22749d8c599SYunfan Zhang 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
228fda87a42SHeiko Stuebner 	.set_voltage_time_sel = regulator_set_voltage_time_sel,
22949d8c599SYunfan Zhang 	.map_voltage = regulator_map_voltage_linear,
23049d8c599SYunfan Zhang 	.list_voltage = regulator_list_voltage_linear,
23149d8c599SYunfan Zhang 	.set_suspend_voltage = fan53555_set_suspend_voltage,
23249d8c599SYunfan Zhang 	.enable = regulator_enable_regmap,
23349d8c599SYunfan Zhang 	.disable = regulator_disable_regmap,
23449d8c599SYunfan Zhang 	.is_enabled = regulator_is_enabled_regmap,
23549d8c599SYunfan Zhang 	.set_mode = fan53555_set_mode,
23649d8c599SYunfan Zhang 	.get_mode = fan53555_get_mode,
237b61ac767SAxel Lin 	.set_ramp_delay = regulator_set_ramp_delay_regmap,
238ab7cad33Szhangqing 	.set_suspend_enable = fan53555_set_suspend_enable,
239ab7cad33Szhangqing 	.set_suspend_disable = fan53555_set_suspend_disable,
24049d8c599SYunfan Zhang };
24149d8c599SYunfan Zhang 
242f2a9eb97SBjorn Andersson static int fan53526_voltages_setup_fairchild(struct fan53555_device_info *di)
243f2a9eb97SBjorn Andersson {
244f2a9eb97SBjorn Andersson 	/* Init voltage range and step */
245f2a9eb97SBjorn Andersson 	switch (di->chip_id) {
246f2a9eb97SBjorn Andersson 	case FAN53526_CHIP_ID_01:
247f2a9eb97SBjorn Andersson 		switch (di->chip_rev) {
248f2a9eb97SBjorn Andersson 		case FAN53526_CHIP_REV_08:
249f2a9eb97SBjorn Andersson 			di->vsel_min = 600000;
250f2a9eb97SBjorn Andersson 			di->vsel_step = 6250;
251f2a9eb97SBjorn Andersson 			break;
252f2a9eb97SBjorn Andersson 		default:
253f2a9eb97SBjorn Andersson 			dev_err(di->dev,
254f2a9eb97SBjorn Andersson 				"Chip ID %d with rev %d not supported!\n",
255f2a9eb97SBjorn Andersson 				di->chip_id, di->chip_rev);
256f2a9eb97SBjorn Andersson 			return -EINVAL;
257f2a9eb97SBjorn Andersson 		}
258f2a9eb97SBjorn Andersson 		break;
259f2a9eb97SBjorn Andersson 	default:
260f2a9eb97SBjorn Andersson 		dev_err(di->dev,
261f2a9eb97SBjorn Andersson 			"Chip ID %d not supported!\n", di->chip_id);
262f2a9eb97SBjorn Andersson 		return -EINVAL;
263f2a9eb97SBjorn Andersson 	}
264f2a9eb97SBjorn Andersson 
26530b38b80SAxel Lin 	di->slew_reg = FAN53555_CONTROL;
26630b38b80SAxel Lin 	di->slew_mask = CTL_SLEW_MASK;
267b61ac767SAxel Lin 	di->ramp_delay_table = slew_rates;
268b61ac767SAxel Lin 	di->n_ramp_values = ARRAY_SIZE(slew_rates);
269f2a9eb97SBjorn Andersson 	di->vsel_count = FAN53526_NVOLTAGES;
270f2a9eb97SBjorn Andersson 
271f2a9eb97SBjorn Andersson 	return 0;
272f2a9eb97SBjorn Andersson }
273f2a9eb97SBjorn Andersson 
274ee30928aSHeiko Stuebner static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di)
27549d8c599SYunfan Zhang {
27649d8c599SYunfan Zhang 	/* Init voltage range and step */
27749d8c599SYunfan Zhang 	switch (di->chip_id) {
27849d8c599SYunfan Zhang 	case FAN53555_CHIP_ID_00:
279e57cbb70SWadim Egorov 		switch (di->chip_rev) {
280e57cbb70SWadim Egorov 		case FAN53555_CHIP_REV_00:
281e57cbb70SWadim Egorov 			di->vsel_min = 600000;
282e57cbb70SWadim Egorov 			di->vsel_step = 10000;
283e57cbb70SWadim Egorov 			break;
284e57cbb70SWadim Egorov 		case FAN53555_CHIP_REV_13:
285e57cbb70SWadim Egorov 			di->vsel_min = 800000;
286e57cbb70SWadim Egorov 			di->vsel_step = 10000;
287e57cbb70SWadim Egorov 			break;
288e57cbb70SWadim Egorov 		default:
289e57cbb70SWadim Egorov 			dev_err(di->dev,
290e57cbb70SWadim Egorov 				"Chip ID %d with rev %d not supported!\n",
291e57cbb70SWadim Egorov 				di->chip_id, di->chip_rev);
292e57cbb70SWadim Egorov 			return -EINVAL;
293e57cbb70SWadim Egorov 		}
294e57cbb70SWadim Egorov 		break;
29549d8c599SYunfan Zhang 	case FAN53555_CHIP_ID_01:
29649d8c599SYunfan Zhang 	case FAN53555_CHIP_ID_03:
29749d8c599SYunfan Zhang 	case FAN53555_CHIP_ID_05:
2985e39cf49SWadim Egorov 	case FAN53555_CHIP_ID_08:
29949d8c599SYunfan Zhang 		di->vsel_min = 600000;
30049d8c599SYunfan Zhang 		di->vsel_step = 10000;
30149d8c599SYunfan Zhang 		break;
30249d8c599SYunfan Zhang 	case FAN53555_CHIP_ID_04:
30349d8c599SYunfan Zhang 		di->vsel_min = 603000;
30449d8c599SYunfan Zhang 		di->vsel_step = 12826;
30549d8c599SYunfan Zhang 		break;
30649d8c599SYunfan Zhang 	default:
30749d8c599SYunfan Zhang 		dev_err(di->dev,
308ee30928aSHeiko Stuebner 			"Chip ID %d not supported!\n", di->chip_id);
30949d8c599SYunfan Zhang 		return -EINVAL;
31049d8c599SYunfan Zhang 	}
311914df8faSJoseph Chen 	di->slew_reg = FAN53555_CONTROL;
312914df8faSJoseph Chen 	di->slew_mask = CTL_SLEW_MASK;
313b61ac767SAxel Lin 	di->ramp_delay_table = slew_rates;
314b61ac767SAxel Lin 	di->n_ramp_values = ARRAY_SIZE(slew_rates);
315f2a9eb97SBjorn Andersson 	di->vsel_count = FAN53555_NVOLTAGES;
316f2a9eb97SBjorn Andersson 
317dd7e71fbSHeiko Stuebner 	return 0;
31849d8c599SYunfan Zhang }
31949d8c599SYunfan Zhang 
320ee30928aSHeiko Stuebner static int fan53555_voltages_setup_silergy(struct fan53555_device_info *di)
321ee30928aSHeiko Stuebner {
322ee30928aSHeiko Stuebner 	/* Init voltage range and step */
323ee30928aSHeiko Stuebner 	switch (di->chip_id) {
324ee30928aSHeiko Stuebner 	case SILERGY_SYR82X:
3255365e3dfSVasily Khoruzhick 	case SILERGY_SYR83X:
326ee30928aSHeiko Stuebner 		di->vsel_min = 712500;
327ee30928aSHeiko Stuebner 		di->vsel_step = 12500;
328ee30928aSHeiko Stuebner 		break;
329ee30928aSHeiko Stuebner 	default:
330ee30928aSHeiko Stuebner 		dev_err(di->dev,
331ee30928aSHeiko Stuebner 			"Chip ID %d not supported!\n", di->chip_id);
332ee30928aSHeiko Stuebner 		return -EINVAL;
333ee30928aSHeiko Stuebner 	}
334914df8faSJoseph Chen 	di->slew_reg = FAN53555_CONTROL;
335914df8faSJoseph Chen 	di->slew_mask = CTL_SLEW_MASK;
336b61ac767SAxel Lin 	di->ramp_delay_table = slew_rates;
337b61ac767SAxel Lin 	di->n_ramp_values = ARRAY_SIZE(slew_rates);
338f2a9eb97SBjorn Andersson 	di->vsel_count = FAN53555_NVOLTAGES;
339f2a9eb97SBjorn Andersson 
340ee30928aSHeiko Stuebner 	return 0;
341ee30928aSHeiko Stuebner }
342ee30928aSHeiko Stuebner 
343b3cc8ec0SPeter Geis static int fan53526_voltages_setup_tcs(struct fan53555_device_info *di)
344914df8faSJoseph Chen {
345f9028dcdSPeter Geis 	switch (di->chip_id) {
346f9028dcdSPeter Geis 	case TCS4525_CHIP_ID_12:
3475eee5eceSRudi Heitbaum 	case TCS4526_CHIP_ID_00:
348914df8faSJoseph Chen 		di->slew_reg = TCS4525_TIME;
349914df8faSJoseph Chen 		di->slew_mask = TCS_SLEW_MASK;
350b61ac767SAxel Lin 		di->ramp_delay_table = tcs_slew_rates;
351b61ac767SAxel Lin 		di->n_ramp_values = ARRAY_SIZE(tcs_slew_rates);
352914df8faSJoseph Chen 
353914df8faSJoseph Chen 		/* Init voltage range and step */
354914df8faSJoseph Chen 		di->vsel_min = 600000;
355914df8faSJoseph Chen 		di->vsel_step = 6250;
356d4db69ebSPeter Geis 		di->vsel_count = FAN53526_NVOLTAGES;
357f9028dcdSPeter Geis 		break;
358f9028dcdSPeter Geis 	default:
359f9028dcdSPeter Geis 		dev_err(di->dev, "Chip ID %d not supported!\n", di->chip_id);
360f9028dcdSPeter Geis 		return -EINVAL;
361f9028dcdSPeter Geis 	}
362914df8faSJoseph Chen 
363914df8faSJoseph Chen 	return 0;
364914df8faSJoseph Chen }
365914df8faSJoseph Chen 
366ee30928aSHeiko Stuebner /* For 00,01,03,05 options:
367ee30928aSHeiko Stuebner  * VOUT = 0.60V + NSELx * 10mV, from 0.60 to 1.23V.
368ee30928aSHeiko Stuebner  * For 04 option:
369ee30928aSHeiko Stuebner  * VOUT = 0.603V + NSELx * 12.826mV, from 0.603 to 1.411V.
370ee30928aSHeiko Stuebner  * */
371ee30928aSHeiko Stuebner static int fan53555_device_setup(struct fan53555_device_info *di,
372ee30928aSHeiko Stuebner 				struct fan53555_platform_data *pdata)
373ee30928aSHeiko Stuebner {
374ee30928aSHeiko Stuebner 	int ret = 0;
375ee30928aSHeiko Stuebner 
376ee30928aSHeiko Stuebner 	/* Setup voltage control register */
377914df8faSJoseph Chen 	switch (di->vendor) {
378914df8faSJoseph Chen 	case FAN53526_VENDOR_FAIRCHILD:
379914df8faSJoseph Chen 	case FAN53555_VENDOR_FAIRCHILD:
380914df8faSJoseph Chen 	case FAN53555_VENDOR_SILERGY:
381ee30928aSHeiko Stuebner 		switch (pdata->sleep_vsel_id) {
382ee30928aSHeiko Stuebner 		case FAN53555_VSEL_ID_0:
383ee30928aSHeiko Stuebner 			di->sleep_reg = FAN53555_VSEL0;
384ee30928aSHeiko Stuebner 			di->vol_reg = FAN53555_VSEL1;
385ee30928aSHeiko Stuebner 			break;
386ee30928aSHeiko Stuebner 		case FAN53555_VSEL_ID_1:
387ee30928aSHeiko Stuebner 			di->sleep_reg = FAN53555_VSEL1;
388ee30928aSHeiko Stuebner 			di->vol_reg = FAN53555_VSEL0;
389ee30928aSHeiko Stuebner 			break;
390ee30928aSHeiko Stuebner 		default:
391ee30928aSHeiko Stuebner 			dev_err(di->dev, "Invalid VSEL ID!\n");
392ee30928aSHeiko Stuebner 			return -EINVAL;
393ee30928aSHeiko Stuebner 		}
394914df8faSJoseph Chen 		break;
395b3cc8ec0SPeter Geis 	case FAN53526_VENDOR_TCS:
396914df8faSJoseph Chen 		switch (pdata->sleep_vsel_id) {
397914df8faSJoseph Chen 		case FAN53555_VSEL_ID_0:
398914df8faSJoseph Chen 			di->sleep_reg = TCS4525_VSEL0;
399914df8faSJoseph Chen 			di->vol_reg = TCS4525_VSEL1;
400914df8faSJoseph Chen 			break;
401914df8faSJoseph Chen 		case FAN53555_VSEL_ID_1:
402914df8faSJoseph Chen 			di->sleep_reg = TCS4525_VSEL1;
403914df8faSJoseph Chen 			di->vol_reg = TCS4525_VSEL0;
404914df8faSJoseph Chen 			break;
405914df8faSJoseph Chen 		default:
406914df8faSJoseph Chen 			dev_err(di->dev, "Invalid VSEL ID!\n");
407914df8faSJoseph Chen 			return -EINVAL;
408914df8faSJoseph Chen 		}
409914df8faSJoseph Chen 		break;
410914df8faSJoseph Chen 	default:
411914df8faSJoseph Chen 		dev_err(di->dev, "vendor %d not supported!\n", di->vendor);
412914df8faSJoseph Chen 		return -EINVAL;
413914df8faSJoseph Chen 	}
414ee30928aSHeiko Stuebner 
415f2a9eb97SBjorn Andersson 	/* Setup mode control register */
416ee30928aSHeiko Stuebner 	switch (di->vendor) {
417f2a9eb97SBjorn Andersson 	case FAN53526_VENDOR_FAIRCHILD:
418f2a9eb97SBjorn Andersson 		di->mode_reg = FAN53555_CONTROL;
419f2a9eb97SBjorn Andersson 
420f2a9eb97SBjorn Andersson 		switch (pdata->sleep_vsel_id) {
421f2a9eb97SBjorn Andersson 		case FAN53555_VSEL_ID_0:
422f2a9eb97SBjorn Andersson 			di->mode_mask = CTL_MODE_VSEL1_MODE;
423f2a9eb97SBjorn Andersson 			break;
424f2a9eb97SBjorn Andersson 		case FAN53555_VSEL_ID_1:
425f2a9eb97SBjorn Andersson 			di->mode_mask = CTL_MODE_VSEL0_MODE;
426f2a9eb97SBjorn Andersson 			break;
427f2a9eb97SBjorn Andersson 		}
428f2a9eb97SBjorn Andersson 		break;
429f2a9eb97SBjorn Andersson 	case FAN53555_VENDOR_FAIRCHILD:
430f2a9eb97SBjorn Andersson 	case FAN53555_VENDOR_SILERGY:
431f2a9eb97SBjorn Andersson 		di->mode_reg = di->vol_reg;
432f2a9eb97SBjorn Andersson 		di->mode_mask = VSEL_MODE;
433f2a9eb97SBjorn Andersson 		break;
434b3cc8ec0SPeter Geis 	case FAN53526_VENDOR_TCS:
435914df8faSJoseph Chen 		di->mode_reg = TCS4525_COMMAND;
436914df8faSJoseph Chen 
437914df8faSJoseph Chen 		switch (pdata->sleep_vsel_id) {
438914df8faSJoseph Chen 		case FAN53555_VSEL_ID_0:
439914df8faSJoseph Chen 			di->mode_mask = TCS_VSEL1_MODE;
440914df8faSJoseph Chen 			break;
441914df8faSJoseph Chen 		case FAN53555_VSEL_ID_1:
442914df8faSJoseph Chen 			di->mode_mask = TCS_VSEL0_MODE;
443914df8faSJoseph Chen 			break;
444914df8faSJoseph Chen 		}
445914df8faSJoseph Chen 		break;
446f2a9eb97SBjorn Andersson 	default:
447f2a9eb97SBjorn Andersson 		dev_err(di->dev, "vendor %d not supported!\n", di->vendor);
448f2a9eb97SBjorn Andersson 		return -EINVAL;
449f2a9eb97SBjorn Andersson 	}
450f2a9eb97SBjorn Andersson 
451f2a9eb97SBjorn Andersson 	/* Setup voltage range */
452f2a9eb97SBjorn Andersson 	switch (di->vendor) {
453f2a9eb97SBjorn Andersson 	case FAN53526_VENDOR_FAIRCHILD:
454f2a9eb97SBjorn Andersson 		ret = fan53526_voltages_setup_fairchild(di);
455f2a9eb97SBjorn Andersson 		break;
456ee30928aSHeiko Stuebner 	case FAN53555_VENDOR_FAIRCHILD:
457ee30928aSHeiko Stuebner 		ret = fan53555_voltages_setup_fairchild(di);
458ee30928aSHeiko Stuebner 		break;
459ee30928aSHeiko Stuebner 	case FAN53555_VENDOR_SILERGY:
460ee30928aSHeiko Stuebner 		ret = fan53555_voltages_setup_silergy(di);
461ee30928aSHeiko Stuebner 		break;
462b3cc8ec0SPeter Geis 	case FAN53526_VENDOR_TCS:
463b3cc8ec0SPeter Geis 		ret = fan53526_voltages_setup_tcs(di);
464914df8faSJoseph Chen 		break;
465ee30928aSHeiko Stuebner 	default:
466fe230531SAxel Lin 		dev_err(di->dev, "vendor %d not supported!\n", di->vendor);
467ee30928aSHeiko Stuebner 		return -EINVAL;
468ee30928aSHeiko Stuebner 	}
469ee30928aSHeiko Stuebner 
470ee30928aSHeiko Stuebner 	return ret;
471ee30928aSHeiko Stuebner }
472ee30928aSHeiko Stuebner 
47349d8c599SYunfan Zhang static int fan53555_regulator_register(struct fan53555_device_info *di,
47449d8c599SYunfan Zhang 			struct regulator_config *config)
47549d8c599SYunfan Zhang {
47649d8c599SYunfan Zhang 	struct regulator_desc *rdesc = &di->desc;
477a69929c7SAxel Lin 	struct regulator_dev *rdev;
47849d8c599SYunfan Zhang 
47949d8c599SYunfan Zhang 	rdesc->name = "fan53555-reg";
4803415d601SHeiko Stuebner 	rdesc->supply_name = "vin";
48149d8c599SYunfan Zhang 	rdesc->ops = &fan53555_regulator_ops;
48249d8c599SYunfan Zhang 	rdesc->type = REGULATOR_VOLTAGE;
483f2a9eb97SBjorn Andersson 	rdesc->n_voltages = di->vsel_count;
48449d8c599SYunfan Zhang 	rdesc->enable_reg = di->vol_reg;
48549d8c599SYunfan Zhang 	rdesc->enable_mask = VSEL_BUCK_EN;
48649d8c599SYunfan Zhang 	rdesc->min_uV = di->vsel_min;
48749d8c599SYunfan Zhang 	rdesc->uV_step = di->vsel_step;
48849d8c599SYunfan Zhang 	rdesc->vsel_reg = di->vol_reg;
489f2a9eb97SBjorn Andersson 	rdesc->vsel_mask = di->vsel_count - 1;
490b61ac767SAxel Lin 	rdesc->ramp_reg = di->slew_reg;
491b61ac767SAxel Lin 	rdesc->ramp_mask = di->slew_mask;
492b61ac767SAxel Lin 	rdesc->ramp_delay_table = di->ramp_delay_table;
493b61ac767SAxel Lin 	rdesc->n_ramp_values = di->n_ramp_values;
49449d8c599SYunfan Zhang 	rdesc->owner = THIS_MODULE;
49549d8c599SYunfan Zhang 
496a69929c7SAxel Lin 	rdev = devm_regulator_register(di->dev, &di->desc, config);
497a69929c7SAxel Lin 	return PTR_ERR_OR_ZERO(rdev);
49849d8c599SYunfan Zhang }
49949d8c599SYunfan Zhang 
500121b567dSKrzysztof Kozlowski static const struct regmap_config fan53555_regmap_config = {
50149d8c599SYunfan Zhang 	.reg_bits = 8,
50249d8c599SYunfan Zhang 	.val_bits = 8,
50349d8c599SYunfan Zhang };
50449d8c599SYunfan Zhang 
50591f23d8fSHeiko Stuebner static struct fan53555_platform_data *fan53555_parse_dt(struct device *dev,
506072e78b1SJavier Martinez Canillas 					      struct device_node *np,
507072e78b1SJavier Martinez Canillas 					      const struct regulator_desc *desc)
50891f23d8fSHeiko Stuebner {
50991f23d8fSHeiko Stuebner 	struct fan53555_platform_data *pdata;
51091f23d8fSHeiko Stuebner 	int ret;
51191f23d8fSHeiko Stuebner 	u32 tmp;
51291f23d8fSHeiko Stuebner 
51391f23d8fSHeiko Stuebner 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
51491f23d8fSHeiko Stuebner 	if (!pdata)
51591f23d8fSHeiko Stuebner 		return NULL;
51691f23d8fSHeiko Stuebner 
517072e78b1SJavier Martinez Canillas 	pdata->regulator = of_get_regulator_init_data(dev, np, desc);
51891f23d8fSHeiko Stuebner 
51991f23d8fSHeiko Stuebner 	ret = of_property_read_u32(np, "fcs,suspend-voltage-selector",
52091f23d8fSHeiko Stuebner 				   &tmp);
52191f23d8fSHeiko Stuebner 	if (!ret)
52291f23d8fSHeiko Stuebner 		pdata->sleep_vsel_id = tmp;
52391f23d8fSHeiko Stuebner 
52491f23d8fSHeiko Stuebner 	return pdata;
52591f23d8fSHeiko Stuebner }
52691f23d8fSHeiko Stuebner 
5275e97d7e8SJisheng Zhang static const struct of_device_id __maybe_unused fan53555_dt_ids[] = {
52891f23d8fSHeiko Stuebner 	{
529f2a9eb97SBjorn Andersson 		.compatible = "fcs,fan53526",
530f2a9eb97SBjorn Andersson 		.data = (void *)FAN53526_VENDOR_FAIRCHILD,
531f2a9eb97SBjorn Andersson 	}, {
53291f23d8fSHeiko Stuebner 		.compatible = "fcs,fan53555",
533ee30928aSHeiko Stuebner 		.data = (void *)FAN53555_VENDOR_FAIRCHILD
534ee30928aSHeiko Stuebner 	}, {
535ee30928aSHeiko Stuebner 		.compatible = "silergy,syr827",
536ee30928aSHeiko Stuebner 		.data = (void *)FAN53555_VENDOR_SILERGY,
537ee30928aSHeiko Stuebner 	}, {
538ee30928aSHeiko Stuebner 		.compatible = "silergy,syr828",
539ee30928aSHeiko Stuebner 		.data = (void *)FAN53555_VENDOR_SILERGY,
540914df8faSJoseph Chen 	}, {
541914df8faSJoseph Chen 		.compatible = "tcs,tcs4525",
542b3cc8ec0SPeter Geis 		.data = (void *)FAN53526_VENDOR_TCS
5435eee5eceSRudi Heitbaum 	}, {
5445eee5eceSRudi Heitbaum 		.compatible = "tcs,tcs4526",
5455eee5eceSRudi Heitbaum 		.data = (void *)FAN53526_VENDOR_TCS
54691f23d8fSHeiko Stuebner 	},
54791f23d8fSHeiko Stuebner 	{ }
54891f23d8fSHeiko Stuebner };
54991f23d8fSHeiko Stuebner MODULE_DEVICE_TABLE(of, fan53555_dt_ids);
55091f23d8fSHeiko Stuebner 
55165542565SUwe Kleine-König static int fan53555_regulator_probe(struct i2c_client *client)
55249d8c599SYunfan Zhang {
55365542565SUwe Kleine-König 	const struct i2c_device_id *id = i2c_client_get_device_id(client);
55491f23d8fSHeiko Stuebner 	struct device_node *np = client->dev.of_node;
55549d8c599SYunfan Zhang 	struct fan53555_device_info *di;
55649d8c599SYunfan Zhang 	struct fan53555_platform_data *pdata;
55749d8c599SYunfan Zhang 	struct regulator_config config = { };
558a69929c7SAxel Lin 	struct regmap *regmap;
55949d8c599SYunfan Zhang 	unsigned int val;
56049d8c599SYunfan Zhang 	int ret;
56149d8c599SYunfan Zhang 
562072e78b1SJavier Martinez Canillas 	di = devm_kzalloc(&client->dev, sizeof(struct fan53555_device_info),
563072e78b1SJavier Martinez Canillas 					GFP_KERNEL);
564072e78b1SJavier Martinez Canillas 	if (!di)
565072e78b1SJavier Martinez Canillas 		return -ENOMEM;
566072e78b1SJavier Martinez Canillas 
567dff91d0bSJingoo Han 	pdata = dev_get_platdata(&client->dev);
56891f23d8fSHeiko Stuebner 	if (!pdata)
569072e78b1SJavier Martinez Canillas 		pdata = fan53555_parse_dt(&client->dev, np, &di->desc);
57091f23d8fSHeiko Stuebner 
57149d8c599SYunfan Zhang 	if (!pdata || !pdata->regulator) {
57249d8c599SYunfan Zhang 		dev_err(&client->dev, "Platform data not found!\n");
57349d8c599SYunfan Zhang 		return -ENODEV;
57449d8c599SYunfan Zhang 	}
57549d8c599SYunfan Zhang 
576e13426bfSAxel Lin 	di->regulator = pdata->regulator;
577ee30928aSHeiko Stuebner 	if (client->dev.of_node) {
578d110e3e9SJisheng Zhang 		di->vendor =
579d110e3e9SJisheng Zhang 			(unsigned long)of_device_get_match_data(&client->dev);
580ee30928aSHeiko Stuebner 	} else {
581dd7e71fbSHeiko Stuebner 		/* if no ramp constraint set, get the pdata ramp_delay */
582dd7e71fbSHeiko Stuebner 		if (!di->regulator->constraints.ramp_delay) {
58387919e0cSAxel Lin 			if (pdata->slew_rate >= ARRAY_SIZE(slew_rates)) {
58487919e0cSAxel Lin 				dev_err(&client->dev, "Invalid slew_rate\n");
58587919e0cSAxel Lin 				return -EINVAL;
58687919e0cSAxel Lin 			}
587dd7e71fbSHeiko Stuebner 
58891f23d8fSHeiko Stuebner 			di->regulator->constraints.ramp_delay
58987919e0cSAxel Lin 					= slew_rates[pdata->slew_rate];
59091f23d8fSHeiko Stuebner 		}
591ee30928aSHeiko Stuebner 
592ee30928aSHeiko Stuebner 		di->vendor = id->driver_data;
593dd7e71fbSHeiko Stuebner 	}
594dd7e71fbSHeiko Stuebner 
595a69929c7SAxel Lin 	regmap = devm_regmap_init_i2c(client, &fan53555_regmap_config);
596a69929c7SAxel Lin 	if (IS_ERR(regmap)) {
59749d8c599SYunfan Zhang 		dev_err(&client->dev, "Failed to allocate regmap!\n");
598a69929c7SAxel Lin 		return PTR_ERR(regmap);
59949d8c599SYunfan Zhang 	}
60049d8c599SYunfan Zhang 	di->dev = &client->dev;
60149d8c599SYunfan Zhang 	i2c_set_clientdata(client, di);
60249d8c599SYunfan Zhang 	/* Get chip ID */
603a69929c7SAxel Lin 	ret = regmap_read(regmap, FAN53555_ID1, &val);
60449d8c599SYunfan Zhang 	if (ret < 0) {
60549d8c599SYunfan Zhang 		dev_err(&client->dev, "Failed to get chip ID!\n");
606145fe1e1SSachin Kamat 		return ret;
60749d8c599SYunfan Zhang 	}
60849d8c599SYunfan Zhang 	di->chip_id = val & DIE_ID;
60949d8c599SYunfan Zhang 	/* Get chip revision */
610a69929c7SAxel Lin 	ret = regmap_read(regmap, FAN53555_ID2, &val);
61149d8c599SYunfan Zhang 	if (ret < 0) {
61249d8c599SYunfan Zhang 		dev_err(&client->dev, "Failed to get chip Rev!\n");
613145fe1e1SSachin Kamat 		return ret;
61449d8c599SYunfan Zhang 	}
61549d8c599SYunfan Zhang 	di->chip_rev = val & DIE_REV;
61649d8c599SYunfan Zhang 	dev_info(&client->dev, "FAN53555 Option[%d] Rev[%d] Detected!\n",
61749d8c599SYunfan Zhang 				di->chip_id, di->chip_rev);
61849d8c599SYunfan Zhang 	/* Device init */
61949d8c599SYunfan Zhang 	ret = fan53555_device_setup(di, pdata);
62049d8c599SYunfan Zhang 	if (ret < 0) {
62149d8c599SYunfan Zhang 		dev_err(&client->dev, "Failed to setup device!\n");
62249d8c599SYunfan Zhang 		return ret;
62349d8c599SYunfan Zhang 	}
62449d8c599SYunfan Zhang 	/* Register regulator */
62549d8c599SYunfan Zhang 	config.dev = di->dev;
62649d8c599SYunfan Zhang 	config.init_data = di->regulator;
627a69929c7SAxel Lin 	config.regmap = regmap;
62849d8c599SYunfan Zhang 	config.driver_data = di;
62991f23d8fSHeiko Stuebner 	config.of_node = np;
63091f23d8fSHeiko Stuebner 
63149d8c599SYunfan Zhang 	ret = fan53555_regulator_register(di, &config);
63249d8c599SYunfan Zhang 	if (ret < 0)
63349d8c599SYunfan Zhang 		dev_err(&client->dev, "Failed to register regulator!\n");
63449d8c599SYunfan Zhang 	return ret;
63549d8c599SYunfan Zhang 
63649d8c599SYunfan Zhang }
63749d8c599SYunfan Zhang 
63849d8c599SYunfan Zhang static const struct i2c_device_id fan53555_id[] = {
639ee30928aSHeiko Stuebner 	{
640f2a9eb97SBjorn Andersson 		.name = "fan53526",
641f2a9eb97SBjorn Andersson 		.driver_data = FAN53526_VENDOR_FAIRCHILD
642f2a9eb97SBjorn Andersson 	}, {
643ee30928aSHeiko Stuebner 		.name = "fan53555",
644ee30928aSHeiko Stuebner 		.driver_data = FAN53555_VENDOR_FAIRCHILD
645ee30928aSHeiko Stuebner 	}, {
646fc1111b8SGuillaume Tucker 		.name = "syr827",
647fc1111b8SGuillaume Tucker 		.driver_data = FAN53555_VENDOR_SILERGY
648fc1111b8SGuillaume Tucker 	}, {
649fc1111b8SGuillaume Tucker 		.name = "syr828",
650ee30928aSHeiko Stuebner 		.driver_data = FAN53555_VENDOR_SILERGY
651914df8faSJoseph Chen 	}, {
652914df8faSJoseph Chen 		.name = "tcs4525",
653b3cc8ec0SPeter Geis 		.driver_data = FAN53526_VENDOR_TCS
6545eee5eceSRudi Heitbaum 	}, {
6555eee5eceSRudi Heitbaum 		.name = "tcs4526",
6565eee5eceSRudi Heitbaum 		.driver_data = FAN53526_VENDOR_TCS
657ee30928aSHeiko Stuebner 	},
65849d8c599SYunfan Zhang 	{ },
65949d8c599SYunfan Zhang };
660e80c47bdSJavier Martinez Canillas MODULE_DEVICE_TABLE(i2c, fan53555_id);
66149d8c599SYunfan Zhang 
66249d8c599SYunfan Zhang static struct i2c_driver fan53555_regulator_driver = {
66349d8c599SYunfan Zhang 	.driver = {
66449d8c599SYunfan Zhang 		.name = "fan53555-regulator",
66591f23d8fSHeiko Stuebner 		.of_match_table = of_match_ptr(fan53555_dt_ids),
66649d8c599SYunfan Zhang 	},
66765542565SUwe Kleine-König 	.probe_new = fan53555_regulator_probe,
66849d8c599SYunfan Zhang 	.id_table = fan53555_id,
66949d8c599SYunfan Zhang };
67049d8c599SYunfan Zhang 
67149d8c599SYunfan Zhang module_i2c_driver(fan53555_regulator_driver);
67249d8c599SYunfan Zhang 
67349d8c599SYunfan Zhang MODULE_AUTHOR("Yunfan Zhang <yfzhang@marvell.com>");
67449d8c599SYunfan Zhang MODULE_DESCRIPTION("FAN53555 regulator driver");
67549d8c599SYunfan Zhang MODULE_LICENSE("GPL v2");
676