xref: /linux/drivers/regulator/pfuze100-regulator.c (revision 36ec807b627b4c0a0a382f0ae48eac7187d14b2b)
1809858cdSFabio Estevam // SPDX-License-Identifier: GPL-2.0+
2809858cdSFabio Estevam //
3809858cdSFabio Estevam // Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
4809858cdSFabio Estevam 
53784b6d6SRobin Gong #include <linux/kernel.h>
63784b6d6SRobin Gong #include <linux/module.h>
73784b6d6SRobin Gong #include <linux/init.h>
83784b6d6SRobin Gong #include <linux/err.h>
93784b6d6SRobin Gong #include <linux/of.h>
103784b6d6SRobin Gong #include <linux/of_device.h>
113784b6d6SRobin Gong #include <linux/regulator/of_regulator.h>
123784b6d6SRobin Gong #include <linux/platform_device.h>
1302a1124dSDmitry Osipenko #include <linux/reboot.h>
143784b6d6SRobin Gong #include <linux/regulator/driver.h>
153784b6d6SRobin Gong #include <linux/regulator/machine.h>
163784b6d6SRobin Gong #include <linux/regulator/pfuze100.h>
173784b6d6SRobin Gong #include <linux/i2c.h>
183784b6d6SRobin Gong #include <linux/slab.h>
193784b6d6SRobin Gong #include <linux/regmap.h>
203784b6d6SRobin Gong 
219d2fd4f0SMarco Felsch #define PFUZE_FLAG_DISABLE_SW	BIT(1)
229d2fd4f0SMarco Felsch 
233784b6d6SRobin Gong #define PFUZE_NUMREGS		128
243784b6d6SRobin Gong #define PFUZE100_VOL_OFFSET	0
253784b6d6SRobin Gong #define PFUZE100_STANDBY_OFFSET	1
263784b6d6SRobin Gong #define PFUZE100_MODE_OFFSET	3
273784b6d6SRobin Gong #define PFUZE100_CONF_OFFSET	4
283784b6d6SRobin Gong 
293784b6d6SRobin Gong #define PFUZE100_DEVICEID	0x0
303784b6d6SRobin Gong #define PFUZE100_REVID		0x3
31a1b6fa85SAxel Lin #define PFUZE100_FABID		0x4
323784b6d6SRobin Gong 
33c6182ac9SGeorge McCollister #define PFUZE100_COINVOL	0x1a
343784b6d6SRobin Gong #define PFUZE100_SW1ABVOL	0x20
35c29daffaSOleksij Rempel #define PFUZE100_SW1ABMODE	0x23
363784b6d6SRobin Gong #define PFUZE100_SW1CVOL	0x2e
37c29daffaSOleksij Rempel #define PFUZE100_SW1CMODE	0x31
383784b6d6SRobin Gong #define PFUZE100_SW2VOL		0x35
39c29daffaSOleksij Rempel #define PFUZE100_SW2MODE	0x38
403784b6d6SRobin Gong #define PFUZE100_SW3AVOL	0x3c
41c29daffaSOleksij Rempel #define PFUZE100_SW3AMODE	0x3f
423784b6d6SRobin Gong #define PFUZE100_SW3BVOL	0x43
43c29daffaSOleksij Rempel #define PFUZE100_SW3BMODE	0x46
443784b6d6SRobin Gong #define PFUZE100_SW4VOL		0x4a
45c29daffaSOleksij Rempel #define PFUZE100_SW4MODE	0x4d
463784b6d6SRobin Gong #define PFUZE100_SWBSTCON1	0x66
473784b6d6SRobin Gong #define PFUZE100_VREFDDRCON	0x6a
483784b6d6SRobin Gong #define PFUZE100_VSNVSVOL	0x6b
493784b6d6SRobin Gong #define PFUZE100_VGEN1VOL	0x6c
503784b6d6SRobin Gong #define PFUZE100_VGEN2VOL	0x6d
513784b6d6SRobin Gong #define PFUZE100_VGEN3VOL	0x6e
523784b6d6SRobin Gong #define PFUZE100_VGEN4VOL	0x6f
533784b6d6SRobin Gong #define PFUZE100_VGEN5VOL	0x70
543784b6d6SRobin Gong #define PFUZE100_VGEN6VOL	0x71
553784b6d6SRobin Gong 
56c29daffaSOleksij Rempel #define PFUZE100_SWxMODE_MASK	0xf
57c29daffaSOleksij Rempel #define PFUZE100_SWxMODE_APS_APS	0x8
58c29daffaSOleksij Rempel #define PFUZE100_SWxMODE_APS_OFF	0x4
59c29daffaSOleksij Rempel 
60c29daffaSOleksij Rempel #define PFUZE100_VGENxLPWR	BIT(6)
61c29daffaSOleksij Rempel #define PFUZE100_VGENxSTBY	BIT(5)
62c29daffaSOleksij Rempel 
63297101abSStefan Wahren enum chips { PFUZE100, PFUZE200, PFUZE3000 = 3, PFUZE3001 = 0x31, };
64f2518480SRobin Gong 
653784b6d6SRobin Gong struct pfuze_regulator {
663784b6d6SRobin Gong 	struct regulator_desc desc;
673784b6d6SRobin Gong 	unsigned char stby_reg;
683784b6d6SRobin Gong 	unsigned char stby_mask;
699d2fd4f0SMarco Felsch 	bool sw_reg;
703784b6d6SRobin Gong };
713784b6d6SRobin Gong 
723784b6d6SRobin Gong struct pfuze_chip {
73f2518480SRobin Gong 	int	chip_id;
749d2fd4f0SMarco Felsch 	int     flags;
753784b6d6SRobin Gong 	struct regmap *regmap;
763784b6d6SRobin Gong 	struct device *dev;
773784b6d6SRobin Gong 	struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR];
783784b6d6SRobin Gong 	struct regulator_dev *regulators[PFUZE100_MAX_REGULATOR];
7912425654SFabio Estevam 	struct pfuze_regulator *pfuze_regulators;
803784b6d6SRobin Gong };
813784b6d6SRobin Gong 
823784b6d6SRobin Gong static const int pfuze100_swbst[] = {
833784b6d6SRobin Gong 	5000000, 5050000, 5100000, 5150000,
843784b6d6SRobin Gong };
853784b6d6SRobin Gong 
863784b6d6SRobin Gong static const int pfuze100_vsnvs[] = {
873784b6d6SRobin Gong 	1000000, 1100000, 1200000, 1300000, 1500000, 1800000, 3000000,
883784b6d6SRobin Gong };
893784b6d6SRobin Gong 
90c6182ac9SGeorge McCollister static const int pfuze100_coin[] = {
91c6182ac9SGeorge McCollister 	2500000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
92c6182ac9SGeorge McCollister };
93c6182ac9SGeorge McCollister 
941dced996SAnson Huang static const int pfuze3000_sw1a[] = {
951dced996SAnson Huang 	700000, 725000, 750000, 775000, 800000, 825000, 850000, 875000,
961dced996SAnson Huang 	900000, 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000,
971dced996SAnson Huang 	1100000, 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000,
981dced996SAnson Huang 	1300000, 1325000, 1350000, 1375000, 1400000, 1425000, 1800000, 3300000,
991dced996SAnson Huang };
1001dced996SAnson Huang 
101e5a7a72cSRobin Gong static const int pfuze3000_sw2lo[] = {
102e5a7a72cSRobin Gong 	1500000, 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000,
103e5a7a72cSRobin Gong };
104e5a7a72cSRobin Gong 
105e5a7a72cSRobin Gong static const int pfuze3000_sw2hi[] = {
106e5a7a72cSRobin Gong 	2500000, 2800000, 2850000, 3000000, 3100000, 3150000, 3200000, 3300000,
107e5a7a72cSRobin Gong };
108e5a7a72cSRobin Gong 
1093784b6d6SRobin Gong static const struct of_device_id pfuze_dt_ids[] = {
110f2518480SRobin Gong 	{ .compatible = "fsl,pfuze100", .data = (void *)PFUZE100},
111f2518480SRobin Gong 	{ .compatible = "fsl,pfuze200", .data = (void *)PFUZE200},
112e5a7a72cSRobin Gong 	{ .compatible = "fsl,pfuze3000", .data = (void *)PFUZE3000},
113297101abSStefan Wahren 	{ .compatible = "fsl,pfuze3001", .data = (void *)PFUZE3001},
114e6c4c337SAxel Lin 	{ }
1153784b6d6SRobin Gong };
1163784b6d6SRobin Gong MODULE_DEVICE_TABLE(of, pfuze_dt_ids);
1173784b6d6SRobin Gong 
1183784b6d6SRobin Gong static int pfuze100_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
1193784b6d6SRobin Gong {
1203784b6d6SRobin Gong 	struct pfuze_chip *pfuze100 = rdev_get_drvdata(rdev);
121d55efa4dSThiago Farina 	int id = rdev_get_id(rdev);
122297101abSStefan Wahren 	bool reg_has_ramp_delay;
123a7503a9dSRobin Gong 	unsigned int ramp_bits = 0;
1243784b6d6SRobin Gong 	int ret;
1253784b6d6SRobin Gong 
126297101abSStefan Wahren 	switch (pfuze100->chip_id) {
127297101abSStefan Wahren 	case PFUZE3001:
128297101abSStefan Wahren 		/* no dynamic voltage scaling for PF3001 */
129297101abSStefan Wahren 		reg_has_ramp_delay = false;
130297101abSStefan Wahren 		break;
131297101abSStefan Wahren 	case PFUZE3000:
132297101abSStefan Wahren 		reg_has_ramp_delay = (id < PFUZE3000_SWBST);
133297101abSStefan Wahren 		break;
134297101abSStefan Wahren 	case PFUZE200:
135297101abSStefan Wahren 		reg_has_ramp_delay = (id < PFUZE200_SWBST);
136297101abSStefan Wahren 		break;
137297101abSStefan Wahren 	case PFUZE100:
138297101abSStefan Wahren 	default:
139297101abSStefan Wahren 		reg_has_ramp_delay = (id < PFUZE100_SWBST);
140297101abSStefan Wahren 		break;
141297101abSStefan Wahren 	}
142297101abSStefan Wahren 
143297101abSStefan Wahren 	if (reg_has_ramp_delay) {
144a7503a9dSRobin Gong 		if (ramp_delay > 0) {
145e5656669SAxel Lin 			ramp_delay = 12500 / ramp_delay;
1463784b6d6SRobin Gong 			ramp_bits = (ramp_delay >> 1) - (ramp_delay >> 3);
147a7503a9dSRobin Gong 		}
148a7503a9dSRobin Gong 
149e5656669SAxel Lin 		ret = regmap_update_bits(pfuze100->regmap,
150e5656669SAxel Lin 					 rdev->desc->vsel_reg + 4,
151e5656669SAxel Lin 					 0xc0, ramp_bits << 6);
1523784b6d6SRobin Gong 		if (ret < 0)
1533784b6d6SRobin Gong 			dev_err(pfuze100->dev, "ramp failed, err %d\n", ret);
154297101abSStefan Wahren 	} else {
1553784b6d6SRobin Gong 		ret = -EACCES;
156297101abSStefan Wahren 	}
1573784b6d6SRobin Gong 
1583784b6d6SRobin Gong 	return ret;
1593784b6d6SRobin Gong }
1603784b6d6SRobin Gong 
161e5053853SBhumika Goyal static const struct regulator_ops pfuze100_ldo_regulator_ops = {
1623784b6d6SRobin Gong 	.enable = regulator_enable_regmap,
1633784b6d6SRobin Gong 	.disable = regulator_disable_regmap,
1643784b6d6SRobin Gong 	.is_enabled = regulator_is_enabled_regmap,
1653784b6d6SRobin Gong 	.list_voltage = regulator_list_voltage_linear,
1663784b6d6SRobin Gong 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
1673784b6d6SRobin Gong 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
1683784b6d6SRobin Gong };
1693784b6d6SRobin Gong 
170e5053853SBhumika Goyal static const struct regulator_ops pfuze100_fixed_regulator_ops = {
171ab3ca774SAxel Lin 	.enable = regulator_enable_regmap,
172ab3ca774SAxel Lin 	.disable = regulator_disable_regmap,
173ab3ca774SAxel Lin 	.is_enabled = regulator_is_enabled_regmap,
1743784b6d6SRobin Gong 	.list_voltage = regulator_list_voltage_linear,
1753784b6d6SRobin Gong };
1763784b6d6SRobin Gong 
177e5053853SBhumika Goyal static const struct regulator_ops pfuze100_sw_regulator_ops = {
1783784b6d6SRobin Gong 	.list_voltage = regulator_list_voltage_linear,
1793784b6d6SRobin Gong 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
1803784b6d6SRobin Gong 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
1813784b6d6SRobin Gong 	.set_voltage_time_sel = regulator_set_voltage_time_sel,
1823784b6d6SRobin Gong 	.set_ramp_delay = pfuze100_set_ramp_delay,
1833784b6d6SRobin Gong };
1843784b6d6SRobin Gong 
1859d2fd4f0SMarco Felsch static const struct regulator_ops pfuze100_sw_disable_regulator_ops = {
1869d2fd4f0SMarco Felsch 	.enable = regulator_enable_regmap,
1879d2fd4f0SMarco Felsch 	.disable = regulator_disable_regmap,
1889d2fd4f0SMarco Felsch 	.is_enabled = regulator_is_enabled_regmap,
1899d2fd4f0SMarco Felsch 	.list_voltage = regulator_list_voltage_linear,
1909d2fd4f0SMarco Felsch 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
1919d2fd4f0SMarco Felsch 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
1929d2fd4f0SMarco Felsch 	.set_voltage_time_sel = regulator_set_voltage_time_sel,
1939d2fd4f0SMarco Felsch 	.set_ramp_delay = pfuze100_set_ramp_delay,
1949d2fd4f0SMarco Felsch };
1959d2fd4f0SMarco Felsch 
196e5053853SBhumika Goyal static const struct regulator_ops pfuze100_swb_regulator_ops = {
197a6dcf978SSean Cross 	.enable = regulator_enable_regmap,
198a6dcf978SSean Cross 	.disable = regulator_disable_regmap,
1990b01fd3dSAnson Huang 	.is_enabled = regulator_is_enabled_regmap,
2003784b6d6SRobin Gong 	.list_voltage = regulator_list_voltage_table,
2012e04cc41SAxel Lin 	.map_voltage = regulator_map_voltage_ascend,
2023784b6d6SRobin Gong 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
2033784b6d6SRobin Gong 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
2043784b6d6SRobin Gong 
2053784b6d6SRobin Gong };
2063784b6d6SRobin Gong 
2076f1cf525SRobin Gong static const struct regulator_ops pfuze3000_sw_regulator_ops = {
2086f1cf525SRobin Gong 	.enable = regulator_enable_regmap,
2096f1cf525SRobin Gong 	.disable = regulator_disable_regmap,
2106f1cf525SRobin Gong 	.is_enabled = regulator_is_enabled_regmap,
2116f1cf525SRobin Gong 	.list_voltage = regulator_list_voltage_table,
2126f1cf525SRobin Gong 	.map_voltage = regulator_map_voltage_ascend,
2136f1cf525SRobin Gong 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
2146f1cf525SRobin Gong 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
2156f1cf525SRobin Gong 	.set_voltage_time_sel = regulator_set_voltage_time_sel,
2166f1cf525SRobin Gong 	.set_ramp_delay = pfuze100_set_ramp_delay,
2176f1cf525SRobin Gong 
2186f1cf525SRobin Gong };
2196f1cf525SRobin Gong 
220f2518480SRobin Gong #define PFUZE100_FIXED_REG(_chip, _name, base, voltage)	\
221f2518480SRobin Gong 	[_chip ## _ ## _name] = {	\
2223784b6d6SRobin Gong 		.desc = {	\
2233784b6d6SRobin Gong 			.name = #_name,	\
2243784b6d6SRobin Gong 			.n_voltages = 1,	\
2253784b6d6SRobin Gong 			.ops = &pfuze100_fixed_regulator_ops,	\
2263784b6d6SRobin Gong 			.type = REGULATOR_VOLTAGE,	\
227f2518480SRobin Gong 			.id = _chip ## _ ## _name,	\
2283784b6d6SRobin Gong 			.owner = THIS_MODULE,	\
2293784b6d6SRobin Gong 			.min_uV = (voltage),	\
2303784b6d6SRobin Gong 			.enable_reg = (base),	\
2313784b6d6SRobin Gong 			.enable_mask = 0x10,	\
2323784b6d6SRobin Gong 		},	\
2333784b6d6SRobin Gong 	}
2343784b6d6SRobin Gong 
235f2518480SRobin Gong #define PFUZE100_SW_REG(_chip, _name, base, min, max, step)	\
236f2518480SRobin Gong 	[_chip ## _ ## _name] = {	\
2373784b6d6SRobin Gong 		.desc = {	\
2383784b6d6SRobin Gong 			.name = #_name,\
2393784b6d6SRobin Gong 			.n_voltages = ((max) - (min)) / (step) + 1,	\
2403784b6d6SRobin Gong 			.ops = &pfuze100_sw_regulator_ops,	\
2413784b6d6SRobin Gong 			.type = REGULATOR_VOLTAGE,	\
242f2518480SRobin Gong 			.id = _chip ## _ ## _name,	\
2433784b6d6SRobin Gong 			.owner = THIS_MODULE,	\
2443784b6d6SRobin Gong 			.min_uV = (min),	\
2453784b6d6SRobin Gong 			.uV_step = (step),	\
2463784b6d6SRobin Gong 			.vsel_reg = (base) + PFUZE100_VOL_OFFSET,	\
2473784b6d6SRobin Gong 			.vsel_mask = 0x3f,	\
2489d2fd4f0SMarco Felsch 			.enable_reg = (base) + PFUZE100_MODE_OFFSET,	\
2499d2fd4f0SMarco Felsch 			.enable_mask = 0xf,	\
2503784b6d6SRobin Gong 		},	\
2513784b6d6SRobin Gong 		.stby_reg = (base) + PFUZE100_STANDBY_OFFSET,	\
2523784b6d6SRobin Gong 		.stby_mask = 0x3f,	\
2539d2fd4f0SMarco Felsch 		.sw_reg = true,		\
2543784b6d6SRobin Gong 	}
2553784b6d6SRobin Gong 
256f2518480SRobin Gong #define PFUZE100_SWB_REG(_chip, _name, base, mask, voltages)	\
257f2518480SRobin Gong 	[_chip ## _ ##  _name] = {	\
2583784b6d6SRobin Gong 		.desc = {	\
2593784b6d6SRobin Gong 			.name = #_name,	\
2603784b6d6SRobin Gong 			.n_voltages = ARRAY_SIZE(voltages),	\
2613784b6d6SRobin Gong 			.ops = &pfuze100_swb_regulator_ops,	\
2623784b6d6SRobin Gong 			.type = REGULATOR_VOLTAGE,	\
263f2518480SRobin Gong 			.id = _chip ## _ ## _name,	\
2643784b6d6SRobin Gong 			.owner = THIS_MODULE,	\
2653784b6d6SRobin Gong 			.volt_table = voltages,	\
2663784b6d6SRobin Gong 			.vsel_reg = (base),	\
2673784b6d6SRobin Gong 			.vsel_mask = (mask),	\
268a6dcf978SSean Cross 			.enable_reg = (base),	\
269a6dcf978SSean Cross 			.enable_mask = 0x48,	\
2703784b6d6SRobin Gong 		},	\
2713784b6d6SRobin Gong 	}
2723784b6d6SRobin Gong 
273f2518480SRobin Gong #define PFUZE100_VGEN_REG(_chip, _name, base, min, max, step)	\
274f2518480SRobin Gong 	[_chip ## _ ## _name] = {	\
2753784b6d6SRobin Gong 		.desc = {	\
2763784b6d6SRobin Gong 			.name = #_name,	\
2773784b6d6SRobin Gong 			.n_voltages = ((max) - (min)) / (step) + 1,	\
2783784b6d6SRobin Gong 			.ops = &pfuze100_ldo_regulator_ops,	\
2793784b6d6SRobin Gong 			.type = REGULATOR_VOLTAGE,	\
280f2518480SRobin Gong 			.id = _chip ## _ ## _name,	\
2813784b6d6SRobin Gong 			.owner = THIS_MODULE,	\
2823784b6d6SRobin Gong 			.min_uV = (min),	\
2833784b6d6SRobin Gong 			.uV_step = (step),	\
2843784b6d6SRobin Gong 			.vsel_reg = (base),	\
2853784b6d6SRobin Gong 			.vsel_mask = 0xf,	\
2863784b6d6SRobin Gong 			.enable_reg = (base),	\
2873784b6d6SRobin Gong 			.enable_mask = 0x10,	\
2883784b6d6SRobin Gong 		},	\
2893784b6d6SRobin Gong 		.stby_reg = (base),	\
2903784b6d6SRobin Gong 		.stby_mask = 0x20,	\
2913784b6d6SRobin Gong 	}
2923784b6d6SRobin Gong 
293c6182ac9SGeorge McCollister #define PFUZE100_COIN_REG(_chip, _name, base, mask, voltages)	\
294c6182ac9SGeorge McCollister 	[_chip ## _ ##  _name] = {	\
295c6182ac9SGeorge McCollister 		.desc = {	\
296c6182ac9SGeorge McCollister 			.name = #_name,	\
297c6182ac9SGeorge McCollister 			.n_voltages = ARRAY_SIZE(voltages),	\
298c6182ac9SGeorge McCollister 			.ops = &pfuze100_swb_regulator_ops,	\
299c6182ac9SGeorge McCollister 			.type = REGULATOR_VOLTAGE,	\
300c6182ac9SGeorge McCollister 			.id = _chip ## _ ## _name,	\
301c6182ac9SGeorge McCollister 			.owner = THIS_MODULE,	\
302c6182ac9SGeorge McCollister 			.volt_table = voltages,	\
303c6182ac9SGeorge McCollister 			.vsel_reg = (base),	\
304c6182ac9SGeorge McCollister 			.vsel_mask = (mask),	\
305c6182ac9SGeorge McCollister 			.enable_reg = (base),	\
306c6182ac9SGeorge McCollister 			.enable_mask = 0x8,	\
307c6182ac9SGeorge McCollister 		},	\
308c6182ac9SGeorge McCollister 	}
309c6182ac9SGeorge McCollister 
310e5a7a72cSRobin Gong #define PFUZE3000_VCC_REG(_chip, _name, base, min, max, step)	{	\
311e5a7a72cSRobin Gong 	.desc = {	\
312e5a7a72cSRobin Gong 		.name = #_name,	\
313e5a7a72cSRobin Gong 		.n_voltages = ((max) - (min)) / (step) + 1,	\
314e5a7a72cSRobin Gong 		.ops = &pfuze100_ldo_regulator_ops,	\
315e5a7a72cSRobin Gong 		.type = REGULATOR_VOLTAGE,	\
316e5a7a72cSRobin Gong 		.id = _chip ## _ ## _name,	\
317e5a7a72cSRobin Gong 		.owner = THIS_MODULE,	\
318e5a7a72cSRobin Gong 		.min_uV = (min),	\
319e5a7a72cSRobin Gong 		.uV_step = (step),	\
320e5a7a72cSRobin Gong 		.vsel_reg = (base),	\
321e5a7a72cSRobin Gong 		.vsel_mask = 0x3,	\
322e5a7a72cSRobin Gong 		.enable_reg = (base),	\
323e5a7a72cSRobin Gong 		.enable_mask = 0x10,	\
324e5a7a72cSRobin Gong 	},	\
325e5a7a72cSRobin Gong 	.stby_reg = (base),	\
326e5a7a72cSRobin Gong 	.stby_mask = 0x20,	\
327e5a7a72cSRobin Gong }
328e5a7a72cSRobin Gong 
3296f1cf525SRobin Gong /* No linar case for the some switches of PFUZE3000 */
3306f1cf525SRobin Gong #define PFUZE3000_SW_REG(_chip, _name, base, mask, voltages)	\
3316f1cf525SRobin Gong 	[_chip ## _ ##  _name] = {	\
332e5a7a72cSRobin Gong 		.desc = {	\
333e5a7a72cSRobin Gong 			.name = #_name,	\
3346f1cf525SRobin Gong 			.n_voltages = ARRAY_SIZE(voltages),	\
3356f1cf525SRobin Gong 			.ops = &pfuze3000_sw_regulator_ops,	\
336e5a7a72cSRobin Gong 			.type = REGULATOR_VOLTAGE,	\
337e5a7a72cSRobin Gong 			.id = _chip ## _ ## _name,	\
338e5a7a72cSRobin Gong 			.owner = THIS_MODULE,	\
3396f1cf525SRobin Gong 			.volt_table = voltages,	\
340e5a7a72cSRobin Gong 			.vsel_reg = (base) + PFUZE100_VOL_OFFSET,	\
3416f1cf525SRobin Gong 			.vsel_mask = (mask),	\
3426f1cf525SRobin Gong 			.enable_reg = (base) + PFUZE100_MODE_OFFSET,	\
3436f1cf525SRobin Gong 			.enable_mask = 0xf,	\
3446f1cf525SRobin Gong 			.enable_val = 0x8,	\
3456f1cf525SRobin Gong 			.enable_time = 500,	\
346e5a7a72cSRobin Gong 		},	\
347e5a7a72cSRobin Gong 		.stby_reg = (base) + PFUZE100_STANDBY_OFFSET,	\
3486f1cf525SRobin Gong 		.stby_mask = (mask),	\
3496f1cf525SRobin Gong 		.sw_reg = true,		\
350e5a7a72cSRobin Gong 	}
351e5a7a72cSRobin Gong 
352e5a7a72cSRobin Gong #define PFUZE3000_SW3_REG(_chip, _name, base, min, max, step)	{	\
353e5a7a72cSRobin Gong 	.desc = {	\
354e5a7a72cSRobin Gong 		.name = #_name,\
355e5a7a72cSRobin Gong 		.n_voltages = ((max) - (min)) / (step) + 1,	\
356e5a7a72cSRobin Gong 		.ops = &pfuze100_sw_regulator_ops,	\
357e5a7a72cSRobin Gong 		.type = REGULATOR_VOLTAGE,	\
358e5a7a72cSRobin Gong 		.id = _chip ## _ ## _name,	\
359e5a7a72cSRobin Gong 		.owner = THIS_MODULE,	\
360e5a7a72cSRobin Gong 		.min_uV = (min),	\
361e5a7a72cSRobin Gong 		.uV_step = (step),	\
362e5a7a72cSRobin Gong 		.vsel_reg = (base) + PFUZE100_VOL_OFFSET,	\
363e5a7a72cSRobin Gong 		.vsel_mask = 0xf,	\
364e5a7a72cSRobin Gong 	},	\
365e5a7a72cSRobin Gong 	.stby_reg = (base) + PFUZE100_STANDBY_OFFSET,	\
366e5a7a72cSRobin Gong 	.stby_mask = 0xf,	\
367e5a7a72cSRobin Gong }
368e5a7a72cSRobin Gong 
369f2518480SRobin Gong /* PFUZE100 */
3703784b6d6SRobin Gong static struct pfuze_regulator pfuze100_regulators[] = {
371f2518480SRobin Gong 	PFUZE100_SW_REG(PFUZE100, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000),
372f2518480SRobin Gong 	PFUZE100_SW_REG(PFUZE100, SW1C, PFUZE100_SW1CVOL, 300000, 1875000, 25000),
373f2518480SRobin Gong 	PFUZE100_SW_REG(PFUZE100, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000),
374f2518480SRobin Gong 	PFUZE100_SW_REG(PFUZE100, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000),
375f2518480SRobin Gong 	PFUZE100_SW_REG(PFUZE100, SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000),
376f2518480SRobin Gong 	PFUZE100_SW_REG(PFUZE100, SW4, PFUZE100_SW4VOL, 400000, 1975000, 25000),
377f2518480SRobin Gong 	PFUZE100_SWB_REG(PFUZE100, SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst),
378f2518480SRobin Gong 	PFUZE100_SWB_REG(PFUZE100, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
379f2518480SRobin Gong 	PFUZE100_FIXED_REG(PFUZE100, VREFDDR, PFUZE100_VREFDDRCON, 750000),
380f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE100, VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000),
381f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE100, VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
382f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE100, VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000),
383f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE100, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000),
384f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE100, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
385f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE100, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
38661d0de05SAdam Ford 	PFUZE100_COIN_REG(PFUZE100, COIN, PFUZE100_COINVOL, 0x7, pfuze100_coin),
3873784b6d6SRobin Gong };
3883784b6d6SRobin Gong 
389f2518480SRobin Gong static struct pfuze_regulator pfuze200_regulators[] = {
390f2518480SRobin Gong 	PFUZE100_SW_REG(PFUZE200, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000),
391f2518480SRobin Gong 	PFUZE100_SW_REG(PFUZE200, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000),
392f2518480SRobin Gong 	PFUZE100_SW_REG(PFUZE200, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000),
393f2518480SRobin Gong 	PFUZE100_SW_REG(PFUZE200, SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000),
394f2518480SRobin Gong 	PFUZE100_SWB_REG(PFUZE200, SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst),
395f2518480SRobin Gong 	PFUZE100_SWB_REG(PFUZE200, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
396f2518480SRobin Gong 	PFUZE100_FIXED_REG(PFUZE200, VREFDDR, PFUZE100_VREFDDRCON, 750000),
397f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE200, VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000),
398f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE200, VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
399f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE200, VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000),
400f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE200, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000),
401f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE200, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
402f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE200, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
403c6182ac9SGeorge McCollister 	PFUZE100_COIN_REG(PFUZE200, COIN, PFUZE100_COINVOL, 0x7, pfuze100_coin),
404f2518480SRobin Gong };
405f2518480SRobin Gong 
406e5a7a72cSRobin Gong static struct pfuze_regulator pfuze3000_regulators[] = {
4076f1cf525SRobin Gong 	PFUZE3000_SW_REG(PFUZE3000, SW1A, PFUZE100_SW1ABVOL, 0x1f, pfuze3000_sw1a),
408e5a7a72cSRobin Gong 	PFUZE100_SW_REG(PFUZE3000, SW1B, PFUZE100_SW1CVOL, 700000, 1475000, 25000),
4096f1cf525SRobin Gong 	PFUZE3000_SW_REG(PFUZE3000, SW2, PFUZE100_SW2VOL, 0x7, pfuze3000_sw2lo),
410e5a7a72cSRobin Gong 	PFUZE3000_SW3_REG(PFUZE3000, SW3, PFUZE100_SW3AVOL, 900000, 1650000, 50000),
411e5a7a72cSRobin Gong 	PFUZE100_SWB_REG(PFUZE3000, SWBST, PFUZE100_SWBSTCON1, 0x3, pfuze100_swbst),
412e5a7a72cSRobin Gong 	PFUZE100_SWB_REG(PFUZE3000, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
413e5a7a72cSRobin Gong 	PFUZE100_FIXED_REG(PFUZE3000, VREFDDR, PFUZE100_VREFDDRCON, 750000),
414e5a7a72cSRobin Gong 	PFUZE100_VGEN_REG(PFUZE3000, VLDO1, PFUZE100_VGEN1VOL, 1800000, 3300000, 100000),
415e5a7a72cSRobin Gong 	PFUZE100_VGEN_REG(PFUZE3000, VLDO2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
416e5a7a72cSRobin Gong 	PFUZE3000_VCC_REG(PFUZE3000, VCCSD, PFUZE100_VGEN3VOL, 2850000, 3300000, 150000),
417e5a7a72cSRobin Gong 	PFUZE3000_VCC_REG(PFUZE3000, V33, PFUZE100_VGEN4VOL, 2850000, 3300000, 150000),
418e5a7a72cSRobin Gong 	PFUZE100_VGEN_REG(PFUZE3000, VLDO3, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
419e5a7a72cSRobin Gong 	PFUZE100_VGEN_REG(PFUZE3000, VLDO4, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
420e5a7a72cSRobin Gong };
421e5a7a72cSRobin Gong 
422297101abSStefan Wahren static struct pfuze_regulator pfuze3001_regulators[] = {
4236f1cf525SRobin Gong 	PFUZE3000_SW_REG(PFUZE3001, SW1, PFUZE100_SW1ABVOL, 0x1f, pfuze3000_sw1a),
4246f1cf525SRobin Gong 	PFUZE3000_SW_REG(PFUZE3001, SW2, PFUZE100_SW2VOL, 0x7, pfuze3000_sw2lo),
425297101abSStefan Wahren 	PFUZE3000_SW3_REG(PFUZE3001, SW3, PFUZE100_SW3AVOL, 900000, 1650000, 50000),
426297101abSStefan Wahren 	PFUZE100_SWB_REG(PFUZE3001, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
427297101abSStefan Wahren 	PFUZE100_VGEN_REG(PFUZE3001, VLDO1, PFUZE100_VGEN1VOL, 1800000, 3300000, 100000),
428297101abSStefan Wahren 	PFUZE100_VGEN_REG(PFUZE3001, VLDO2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
429297101abSStefan Wahren 	PFUZE3000_VCC_REG(PFUZE3001, VCCSD, PFUZE100_VGEN3VOL, 2850000, 3300000, 150000),
430297101abSStefan Wahren 	PFUZE3000_VCC_REG(PFUZE3001, V33, PFUZE100_VGEN4VOL, 2850000, 3300000, 150000),
431297101abSStefan Wahren 	PFUZE100_VGEN_REG(PFUZE3001, VLDO3, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
432297101abSStefan Wahren 	PFUZE100_VGEN_REG(PFUZE3001, VLDO4, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
433297101abSStefan Wahren };
434297101abSStefan Wahren 
435f2518480SRobin Gong /* PFUZE100 */
4363784b6d6SRobin Gong static struct of_regulator_match pfuze100_matches[] = {
4373784b6d6SRobin Gong 	{ .name = "sw1ab",	},
4383784b6d6SRobin Gong 	{ .name = "sw1c",	},
4393784b6d6SRobin Gong 	{ .name = "sw2",	},
4403784b6d6SRobin Gong 	{ .name = "sw3a",	},
4413784b6d6SRobin Gong 	{ .name = "sw3b",	},
4423784b6d6SRobin Gong 	{ .name = "sw4",	},
4433784b6d6SRobin Gong 	{ .name = "swbst",	},
4443784b6d6SRobin Gong 	{ .name = "vsnvs",	},
4453784b6d6SRobin Gong 	{ .name = "vrefddr",	},
4463784b6d6SRobin Gong 	{ .name = "vgen1",	},
4473784b6d6SRobin Gong 	{ .name = "vgen2",	},
4483784b6d6SRobin Gong 	{ .name = "vgen3",	},
4493784b6d6SRobin Gong 	{ .name = "vgen4",	},
4503784b6d6SRobin Gong 	{ .name = "vgen5",	},
4513784b6d6SRobin Gong 	{ .name = "vgen6",	},
45261d0de05SAdam Ford 	{ .name = "coin",	},
4533784b6d6SRobin Gong };
4543784b6d6SRobin Gong 
455f2518480SRobin Gong /* PFUZE200 */
456f2518480SRobin Gong static struct of_regulator_match pfuze200_matches[] = {
457f2518480SRobin Gong 
458f2518480SRobin Gong 	{ .name = "sw1ab",	},
459f2518480SRobin Gong 	{ .name = "sw2",	},
460f2518480SRobin Gong 	{ .name = "sw3a",	},
461f2518480SRobin Gong 	{ .name = "sw3b",	},
462f2518480SRobin Gong 	{ .name = "swbst",	},
463f2518480SRobin Gong 	{ .name = "vsnvs",	},
464f2518480SRobin Gong 	{ .name = "vrefddr",	},
465f2518480SRobin Gong 	{ .name = "vgen1",	},
466f2518480SRobin Gong 	{ .name = "vgen2",	},
467f2518480SRobin Gong 	{ .name = "vgen3",	},
468f2518480SRobin Gong 	{ .name = "vgen4",	},
469f2518480SRobin Gong 	{ .name = "vgen5",	},
470f2518480SRobin Gong 	{ .name = "vgen6",	},
471c6182ac9SGeorge McCollister 	{ .name = "coin",	},
472f2518480SRobin Gong };
473f2518480SRobin Gong 
474e5a7a72cSRobin Gong /* PFUZE3000 */
475e5a7a72cSRobin Gong static struct of_regulator_match pfuze3000_matches[] = {
476e5a7a72cSRobin Gong 
477e5a7a72cSRobin Gong 	{ .name = "sw1a",	},
478e5a7a72cSRobin Gong 	{ .name = "sw1b",	},
479e5a7a72cSRobin Gong 	{ .name = "sw2",	},
480e5a7a72cSRobin Gong 	{ .name = "sw3",	},
481e5a7a72cSRobin Gong 	{ .name = "swbst",	},
482e5a7a72cSRobin Gong 	{ .name = "vsnvs",	},
483e5a7a72cSRobin Gong 	{ .name = "vrefddr",	},
484e5a7a72cSRobin Gong 	{ .name = "vldo1",	},
485e5a7a72cSRobin Gong 	{ .name = "vldo2",	},
486e5a7a72cSRobin Gong 	{ .name = "vccsd",	},
487e5a7a72cSRobin Gong 	{ .name = "v33",	},
488e5a7a72cSRobin Gong 	{ .name = "vldo3",	},
489e5a7a72cSRobin Gong 	{ .name = "vldo4",	},
490e5a7a72cSRobin Gong };
491e5a7a72cSRobin Gong 
492297101abSStefan Wahren /* PFUZE3001 */
493297101abSStefan Wahren static struct of_regulator_match pfuze3001_matches[] = {
494297101abSStefan Wahren 
495297101abSStefan Wahren 	{ .name = "sw1",	},
496297101abSStefan Wahren 	{ .name = "sw2",	},
497297101abSStefan Wahren 	{ .name = "sw3",	},
498297101abSStefan Wahren 	{ .name = "vsnvs",	},
499297101abSStefan Wahren 	{ .name = "vldo1",	},
500297101abSStefan Wahren 	{ .name = "vldo2",	},
501297101abSStefan Wahren 	{ .name = "vccsd",	},
502297101abSStefan Wahren 	{ .name = "v33",	},
503297101abSStefan Wahren 	{ .name = "vldo3",	},
504297101abSStefan Wahren 	{ .name = "vldo4",	},
505297101abSStefan Wahren };
506297101abSStefan Wahren 
507f2518480SRobin Gong static struct of_regulator_match *pfuze_matches;
508f2518480SRobin Gong 
5093784b6d6SRobin Gong static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
5103784b6d6SRobin Gong {
5113784b6d6SRobin Gong 	struct device *dev = chip->dev;
5123784b6d6SRobin Gong 	struct device_node *np, *parent;
5133784b6d6SRobin Gong 	int ret;
5143784b6d6SRobin Gong 
5153e01c75aSFabio Estevam 	np = of_node_get(dev->of_node);
5163784b6d6SRobin Gong 	if (!np)
5176428789eSFabio Estevam 		return -EINVAL;
5183784b6d6SRobin Gong 
5199d2fd4f0SMarco Felsch 	if (of_property_read_bool(np, "fsl,pfuze-support-disable-sw"))
5209d2fd4f0SMarco Felsch 		chip->flags |= PFUZE_FLAG_DISABLE_SW;
5219d2fd4f0SMarco Felsch 
522d7857c42SSachin Kamat 	parent = of_get_child_by_name(np, "regulators");
5233784b6d6SRobin Gong 	if (!parent) {
5243784b6d6SRobin Gong 		dev_err(dev, "regulators node not found\n");
525afaa7b93SMiaoqian Lin 		of_node_put(np);
5263784b6d6SRobin Gong 		return -EINVAL;
5273784b6d6SRobin Gong 	}
5283784b6d6SRobin Gong 
529f2518480SRobin Gong 	switch (chip->chip_id) {
530297101abSStefan Wahren 	case PFUZE3001:
531297101abSStefan Wahren 		pfuze_matches = pfuze3001_matches;
532297101abSStefan Wahren 		ret = of_regulator_match(dev, parent, pfuze3001_matches,
533297101abSStefan Wahren 					 ARRAY_SIZE(pfuze3001_matches));
534297101abSStefan Wahren 		break;
535e5a7a72cSRobin Gong 	case PFUZE3000:
536e5a7a72cSRobin Gong 		pfuze_matches = pfuze3000_matches;
537e5a7a72cSRobin Gong 		ret = of_regulator_match(dev, parent, pfuze3000_matches,
538e5a7a72cSRobin Gong 					 ARRAY_SIZE(pfuze3000_matches));
539e5a7a72cSRobin Gong 		break;
540f2518480SRobin Gong 	case PFUZE200:
541f2518480SRobin Gong 		pfuze_matches = pfuze200_matches;
542f2518480SRobin Gong 		ret = of_regulator_match(dev, parent, pfuze200_matches,
543f2518480SRobin Gong 					 ARRAY_SIZE(pfuze200_matches));
544f2518480SRobin Gong 		break;
545f2518480SRobin Gong 
546f2518480SRobin Gong 	case PFUZE100:
547f2518480SRobin Gong 	default:
548f2518480SRobin Gong 		pfuze_matches = pfuze100_matches;
5493784b6d6SRobin Gong 		ret = of_regulator_match(dev, parent, pfuze100_matches,
5503784b6d6SRobin Gong 					 ARRAY_SIZE(pfuze100_matches));
551f2518480SRobin Gong 		break;
552f2518480SRobin Gong 	}
5533784b6d6SRobin Gong 
5543784b6d6SRobin Gong 	of_node_put(parent);
555afaa7b93SMiaoqian Lin 	of_node_put(np);
5563784b6d6SRobin Gong 	if (ret < 0) {
5573784b6d6SRobin Gong 		dev_err(dev, "Error parsing regulator init data: %d\n",
5583784b6d6SRobin Gong 			ret);
5593784b6d6SRobin Gong 		return ret;
5603784b6d6SRobin Gong 	}
5613784b6d6SRobin Gong 
5623784b6d6SRobin Gong 	return 0;
5633784b6d6SRobin Gong }
5643784b6d6SRobin Gong 
5653784b6d6SRobin Gong static inline struct regulator_init_data *match_init_data(int index)
5663784b6d6SRobin Gong {
567f2518480SRobin Gong 	return pfuze_matches[index].init_data;
5683784b6d6SRobin Gong }
5693784b6d6SRobin Gong 
5703784b6d6SRobin Gong static inline struct device_node *match_of_node(int index)
5713784b6d6SRobin Gong {
572f2518480SRobin Gong 	return pfuze_matches[index].of_node;
5733784b6d6SRobin Gong }
5743784b6d6SRobin Gong 
57502a1124dSDmitry Osipenko static int pfuze_power_off_prepare(struct sys_off_data *data)
576c29daffaSOleksij Rempel {
57702a1124dSDmitry Osipenko 	struct pfuze_chip *syspm_pfuze_chip = data->cb_data;
57802a1124dSDmitry Osipenko 
579db6565afSColin Ian King 	dev_info(syspm_pfuze_chip->dev, "Configure standby mode for power off");
580c29daffaSOleksij Rempel 
581c29daffaSOleksij Rempel 	/* Switch from default mode: APS/APS to APS/Off */
582c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW1ABMODE,
583c29daffaSOleksij Rempel 			   PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
584c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW1CMODE,
585c29daffaSOleksij Rempel 			   PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
586c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW2MODE,
587c29daffaSOleksij Rempel 			   PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
588c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW3AMODE,
589c29daffaSOleksij Rempel 			   PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
590c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW3BMODE,
591c29daffaSOleksij Rempel 			   PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
592c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW4MODE,
593c29daffaSOleksij Rempel 			   PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
594c29daffaSOleksij Rempel 
595c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN1VOL,
596c29daffaSOleksij Rempel 			   PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
597c29daffaSOleksij Rempel 			   PFUZE100_VGENxSTBY);
598c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN2VOL,
599c29daffaSOleksij Rempel 			   PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
600c29daffaSOleksij Rempel 			   PFUZE100_VGENxSTBY);
601c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN3VOL,
602c29daffaSOleksij Rempel 			   PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
603c29daffaSOleksij Rempel 			   PFUZE100_VGENxSTBY);
604c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN4VOL,
605c29daffaSOleksij Rempel 			   PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
606c29daffaSOleksij Rempel 			   PFUZE100_VGENxSTBY);
607c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN5VOL,
608c29daffaSOleksij Rempel 			   PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
609c29daffaSOleksij Rempel 			   PFUZE100_VGENxSTBY);
610c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN6VOL,
611c29daffaSOleksij Rempel 			   PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
612c29daffaSOleksij Rempel 			   PFUZE100_VGENxSTBY);
61302a1124dSDmitry Osipenko 
61402a1124dSDmitry Osipenko 	return NOTIFY_DONE;
615c29daffaSOleksij Rempel }
616c29daffaSOleksij Rempel 
617c29daffaSOleksij Rempel static int pfuze_power_off_prepare_init(struct pfuze_chip *pfuze_chip)
618c29daffaSOleksij Rempel {
61902a1124dSDmitry Osipenko 	int err;
62002a1124dSDmitry Osipenko 
621c29daffaSOleksij Rempel 	if (pfuze_chip->chip_id != PFUZE100) {
622c29daffaSOleksij Rempel 		dev_warn(pfuze_chip->dev, "Requested pm_power_off_prepare handler for not supported chip\n");
623c29daffaSOleksij Rempel 		return -ENODEV;
624c29daffaSOleksij Rempel 	}
625c29daffaSOleksij Rempel 
62602a1124dSDmitry Osipenko 	err = devm_register_sys_off_handler(pfuze_chip->dev,
62702a1124dSDmitry Osipenko 					    SYS_OFF_MODE_POWER_OFF_PREPARE,
62802a1124dSDmitry Osipenko 					    SYS_OFF_PRIO_DEFAULT,
62902a1124dSDmitry Osipenko 					    pfuze_power_off_prepare,
63002a1124dSDmitry Osipenko 					    pfuze_chip);
63102a1124dSDmitry Osipenko 	if (err) {
63202a1124dSDmitry Osipenko 		dev_err(pfuze_chip->dev, "failed to register sys-off handler: %d\n",
63302a1124dSDmitry Osipenko 			err);
63402a1124dSDmitry Osipenko 		return err;
635c29daffaSOleksij Rempel 	}
636c29daffaSOleksij Rempel 
637c29daffaSOleksij Rempel 	return 0;
638c29daffaSOleksij Rempel }
639c29daffaSOleksij Rempel 
6403784b6d6SRobin Gong static int pfuze_identify(struct pfuze_chip *pfuze_chip)
6413784b6d6SRobin Gong {
6423784b6d6SRobin Gong 	unsigned int value;
6433784b6d6SRobin Gong 	int ret;
6443784b6d6SRobin Gong 
6453784b6d6SRobin Gong 	ret = regmap_read(pfuze_chip->regmap, PFUZE100_DEVICEID, &value);
6463784b6d6SRobin Gong 	if (ret)
6473784b6d6SRobin Gong 		return ret;
6483784b6d6SRobin Gong 
649f2518480SRobin Gong 	if (((value & 0x0f) == 0x8) && (pfuze_chip->chip_id == PFUZE100)) {
65062b38916SFabio Estevam 		/*
65162b38916SFabio Estevam 		 * Freescale misprogrammed 1-3% of parts prior to week 8 of 2013
652f2518480SRobin Gong 		 * as ID=8 in PFUZE100
65362b38916SFabio Estevam 		 */
654236c427cSTim Harvey 		dev_info(pfuze_chip->dev, "Assuming misprogrammed ID=0x8");
655e5a7a72cSRobin Gong 	} else if ((value & 0x0f) != pfuze_chip->chip_id &&
656297101abSStefan Wahren 		   (value & 0xf0) >> 4 != pfuze_chip->chip_id &&
657297101abSStefan Wahren 		   (value != pfuze_chip->chip_id)) {
658f2518480SRobin Gong 		/* device id NOT match with your setting */
6593784b6d6SRobin Gong 		dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value);
6603784b6d6SRobin Gong 		return -ENODEV;
6613784b6d6SRobin Gong 	}
6623784b6d6SRobin Gong 
6633784b6d6SRobin Gong 	ret = regmap_read(pfuze_chip->regmap, PFUZE100_REVID, &value);
6643784b6d6SRobin Gong 	if (ret)
6653784b6d6SRobin Gong 		return ret;
6663784b6d6SRobin Gong 	dev_info(pfuze_chip->dev,
667f2694383SFabio Estevam 		 "Full layer: %x, Metal layer: %x\n",
6683784b6d6SRobin Gong 		 (value & 0xf0) >> 4, value & 0x0f);
6693784b6d6SRobin Gong 
6703784b6d6SRobin Gong 	ret = regmap_read(pfuze_chip->regmap, PFUZE100_FABID, &value);
6713784b6d6SRobin Gong 	if (ret)
6723784b6d6SRobin Gong 		return ret;
6733784b6d6SRobin Gong 	dev_info(pfuze_chip->dev, "FAB: %x, FIN: %x\n",
6743784b6d6SRobin Gong 		 (value & 0xc) >> 2, value & 0x3);
6753784b6d6SRobin Gong 
6763784b6d6SRobin Gong 	return 0;
6773784b6d6SRobin Gong }
6783784b6d6SRobin Gong 
6793784b6d6SRobin Gong static const struct regmap_config pfuze_regmap_config = {
6803784b6d6SRobin Gong 	.reg_bits = 8,
6813784b6d6SRobin Gong 	.val_bits = 8,
6826b8430c3SAxel Lin 	.max_register = PFUZE_NUMREGS - 1,
683*0332f074SBo Liu 	.cache_type = REGCACHE_MAPLE,
6843784b6d6SRobin Gong };
6853784b6d6SRobin Gong 
6868348c710SUwe Kleine-König static int pfuze100_regulator_probe(struct i2c_client *client)
6873784b6d6SRobin Gong {
6888348c710SUwe Kleine-König 	const struct i2c_device_id *id = i2c_client_get_device_id(client);
6893784b6d6SRobin Gong 	struct pfuze_chip *pfuze_chip;
6903784b6d6SRobin Gong 	struct regulator_config config = { };
6913784b6d6SRobin Gong 	int i, ret;
692f2518480SRobin Gong 	const struct of_device_id *match;
693f2518480SRobin Gong 	u32 regulator_num;
694e5a7a72cSRobin Gong 	u32 sw_check_start, sw_check_end, sw_hi = 0x40;
6953784b6d6SRobin Gong 
6963784b6d6SRobin Gong 	pfuze_chip = devm_kzalloc(&client->dev, sizeof(*pfuze_chip),
6973784b6d6SRobin Gong 			GFP_KERNEL);
6983784b6d6SRobin Gong 	if (!pfuze_chip)
6993784b6d6SRobin Gong 		return -ENOMEM;
7003784b6d6SRobin Gong 
701f2518480SRobin Gong 	if (client->dev.of_node) {
7029e8925ebSChen Jiahao 		match = of_match_device(pfuze_dt_ids, &client->dev);
703f2518480SRobin Gong 		if (!match) {
704f2518480SRobin Gong 			dev_err(&client->dev, "Error: No device match found\n");
705f2518480SRobin Gong 			return -ENODEV;
706f2518480SRobin Gong 		}
707f2518480SRobin Gong 		pfuze_chip->chip_id = (int)(long)match->data;
708f2518480SRobin Gong 	} else if (id) {
709f2518480SRobin Gong 		pfuze_chip->chip_id = id->driver_data;
710f2518480SRobin Gong 	} else {
711f2518480SRobin Gong 		dev_err(&client->dev, "No dts match or id table match found\n");
712f2518480SRobin Gong 		return -ENODEV;
713f2518480SRobin Gong 	}
714f2518480SRobin Gong 
7158c86ab25SAxel Lin 	i2c_set_clientdata(client, pfuze_chip);
7163784b6d6SRobin Gong 	pfuze_chip->dev = &client->dev;
7173784b6d6SRobin Gong 
7183784b6d6SRobin Gong 	pfuze_chip->regmap = devm_regmap_init_i2c(client, &pfuze_regmap_config);
7193784b6d6SRobin Gong 	if (IS_ERR(pfuze_chip->regmap)) {
7203784b6d6SRobin Gong 		ret = PTR_ERR(pfuze_chip->regmap);
7213784b6d6SRobin Gong 		dev_err(&client->dev,
7223784b6d6SRobin Gong 			"regmap allocation failed with err %d\n", ret);
7233784b6d6SRobin Gong 		return ret;
7243784b6d6SRobin Gong 	}
7253784b6d6SRobin Gong 
7263784b6d6SRobin Gong 	ret = pfuze_identify(pfuze_chip);
7273784b6d6SRobin Gong 	if (ret) {
7283784b6d6SRobin Gong 		dev_err(&client->dev, "unrecognized pfuze chip ID!\n");
7293784b6d6SRobin Gong 		return ret;
7303784b6d6SRobin Gong 	}
7313784b6d6SRobin Gong 
732f2518480SRobin Gong 	/* use the right regulators after identify the right device */
733f2518480SRobin Gong 	switch (pfuze_chip->chip_id) {
734297101abSStefan Wahren 	case PFUZE3001:
735297101abSStefan Wahren 		pfuze_chip->pfuze_regulators = pfuze3001_regulators;
736297101abSStefan Wahren 		regulator_num = ARRAY_SIZE(pfuze3001_regulators);
737297101abSStefan Wahren 		sw_check_start = PFUZE3001_SW2;
738297101abSStefan Wahren 		sw_check_end = PFUZE3001_SW2;
739297101abSStefan Wahren 		sw_hi = 1 << 3;
740297101abSStefan Wahren 		break;
741e5a7a72cSRobin Gong 	case PFUZE3000:
74212425654SFabio Estevam 		pfuze_chip->pfuze_regulators = pfuze3000_regulators;
743e5a7a72cSRobin Gong 		regulator_num = ARRAY_SIZE(pfuze3000_regulators);
744e5a7a72cSRobin Gong 		sw_check_start = PFUZE3000_SW2;
745e5a7a72cSRobin Gong 		sw_check_end = PFUZE3000_SW2;
746e5a7a72cSRobin Gong 		sw_hi = 1 << 3;
747e5a7a72cSRobin Gong 		break;
748f2518480SRobin Gong 	case PFUZE200:
74912425654SFabio Estevam 		pfuze_chip->pfuze_regulators = pfuze200_regulators;
750f2518480SRobin Gong 		regulator_num = ARRAY_SIZE(pfuze200_regulators);
751f2518480SRobin Gong 		sw_check_start = PFUZE200_SW2;
752f2518480SRobin Gong 		sw_check_end = PFUZE200_SW3B;
753f2518480SRobin Gong 		break;
754f2518480SRobin Gong 	case PFUZE100:
755f2518480SRobin Gong 	default:
75612425654SFabio Estevam 		pfuze_chip->pfuze_regulators = pfuze100_regulators;
757f2518480SRobin Gong 		regulator_num = ARRAY_SIZE(pfuze100_regulators);
758f2518480SRobin Gong 		sw_check_start = PFUZE100_SW2;
759f2518480SRobin Gong 		sw_check_end = PFUZE100_SW4;
760f2518480SRobin Gong 		break;
761f2518480SRobin Gong 	}
762f2518480SRobin Gong 	dev_info(&client->dev, "pfuze%s found.\n",
763e5a7a72cSRobin Gong 		(pfuze_chip->chip_id == PFUZE100) ? "100" :
764297101abSStefan Wahren 		(((pfuze_chip->chip_id == PFUZE200) ? "200" :
765297101abSStefan Wahren 		((pfuze_chip->chip_id == PFUZE3000) ? "3000" : "3001"))));
766f2518480SRobin Gong 
76712425654SFabio Estevam 	memcpy(pfuze_chip->regulator_descs, pfuze_chip->pfuze_regulators,
76878e1e867SXiaolei Wang 		regulator_num * sizeof(struct pfuze_regulator));
769f2518480SRobin Gong 
7703784b6d6SRobin Gong 	ret = pfuze_parse_regulators_dt(pfuze_chip);
7713784b6d6SRobin Gong 	if (ret)
7723784b6d6SRobin Gong 		return ret;
7733784b6d6SRobin Gong 
774f2518480SRobin Gong 	for (i = 0; i < regulator_num; i++) {
7753784b6d6SRobin Gong 		struct regulator_init_data *init_data;
776d9493234SAxel Lin 		struct regulator_desc *desc;
7773784b6d6SRobin Gong 		int val;
7783784b6d6SRobin Gong 
779d9493234SAxel Lin 		desc = &pfuze_chip->regulator_descs[i].desc;
780d9493234SAxel Lin 
7813784b6d6SRobin Gong 		init_data = match_init_data(i);
7823784b6d6SRobin Gong 
7833784b6d6SRobin Gong 		/* SW2~SW4 high bit check and modify the voltage value table */
784f2518480SRobin Gong 		if (i >= sw_check_start && i <= sw_check_end) {
7851252b283SYizhuo 			ret = regmap_read(pfuze_chip->regmap,
7861252b283SYizhuo 						desc->vsel_reg, &val);
7871252b283SYizhuo 			if (ret) {
7881252b283SYizhuo 				dev_err(&client->dev, "Fails to read from the register.\n");
7891252b283SYizhuo 				return ret;
7901252b283SYizhuo 			}
7911252b283SYizhuo 
792e5a7a72cSRobin Gong 			if (val & sw_hi) {
793297101abSStefan Wahren 				if (pfuze_chip->chip_id == PFUZE3000 ||
794297101abSStefan Wahren 					pfuze_chip->chip_id == PFUZE3001) {
795e5a7a72cSRobin Gong 					desc->volt_table = pfuze3000_sw2hi;
796e5a7a72cSRobin Gong 					desc->n_voltages = ARRAY_SIZE(pfuze3000_sw2hi);
797e5a7a72cSRobin Gong 				} else {
798d9493234SAxel Lin 					desc->min_uV = 800000;
799d9493234SAxel Lin 					desc->uV_step = 50000;
800d9493234SAxel Lin 					desc->n_voltages = 51;
8013784b6d6SRobin Gong 				}
8023784b6d6SRobin Gong 			}
803e5a7a72cSRobin Gong 		}
8043784b6d6SRobin Gong 
8059d2fd4f0SMarco Felsch 		/*
8069d2fd4f0SMarco Felsch 		 * Allow SW regulators to turn off. Checking it trough a flag is
8079d2fd4f0SMarco Felsch 		 * a workaround to keep the backward compatibility with existing
8089d2fd4f0SMarco Felsch 		 * old dtb's which may relay on the fact that we didn't disable
8099d2fd4f0SMarco Felsch 		 * the switched regulator till yet.
8109d2fd4f0SMarco Felsch 		 */
8119d2fd4f0SMarco Felsch 		if (pfuze_chip->flags & PFUZE_FLAG_DISABLE_SW) {
812365ec8b6SSean Nyekjaer 			if (pfuze_chip->chip_id == PFUZE100 ||
813365ec8b6SSean Nyekjaer 				pfuze_chip->chip_id == PFUZE200) {
8149d2fd4f0SMarco Felsch 				if (pfuze_chip->regulator_descs[i].sw_reg) {
8159d2fd4f0SMarco Felsch 					desc->ops = &pfuze100_sw_disable_regulator_ops;
8169d2fd4f0SMarco Felsch 					desc->enable_val = 0x8;
8179d2fd4f0SMarco Felsch 					desc->disable_val = 0x0;
8189d2fd4f0SMarco Felsch 					desc->enable_time = 500;
8199d2fd4f0SMarco Felsch 				}
8209d2fd4f0SMarco Felsch 			}
821365ec8b6SSean Nyekjaer 		}
8229d2fd4f0SMarco Felsch 
8233784b6d6SRobin Gong 		config.dev = &client->dev;
8243784b6d6SRobin Gong 		config.init_data = init_data;
8253784b6d6SRobin Gong 		config.driver_data = pfuze_chip;
8263784b6d6SRobin Gong 		config.of_node = match_of_node(i);
8273784b6d6SRobin Gong 
828f5247b40SJingoo Han 		pfuze_chip->regulators[i] =
829f5247b40SJingoo Han 			devm_regulator_register(&client->dev, desc, &config);
8303784b6d6SRobin Gong 		if (IS_ERR(pfuze_chip->regulators[i])) {
8313784b6d6SRobin Gong 			dev_err(&client->dev, "register regulator%s failed\n",
83212425654SFabio Estevam 				pfuze_chip->pfuze_regulators[i].desc.name);
833f5247b40SJingoo Han 			return PTR_ERR(pfuze_chip->regulators[i]);
8343784b6d6SRobin Gong 		}
8353784b6d6SRobin Gong 	}
8363784b6d6SRobin Gong 
837c29daffaSOleksij Rempel 	if (of_property_read_bool(client->dev.of_node,
838c29daffaSOleksij Rempel 				  "fsl,pmic-stby-poweroff"))
839c29daffaSOleksij Rempel 		return pfuze_power_off_prepare_init(pfuze_chip);
840c29daffaSOleksij Rempel 
841c29daffaSOleksij Rempel 	return 0;
842c29daffaSOleksij Rempel }
843c29daffaSOleksij Rempel 
8443784b6d6SRobin Gong static struct i2c_driver pfuze_driver = {
8453784b6d6SRobin Gong 	.driver = {
8463784b6d6SRobin Gong 		.name = "pfuze100-regulator",
847259b93b2SDouglas Anderson 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
8483784b6d6SRobin Gong 		.of_match_table = pfuze_dt_ids,
8493784b6d6SRobin Gong 	},
850964e1865SUwe Kleine-König 	.probe = pfuze100_regulator_probe,
8513784b6d6SRobin Gong };
8523784b6d6SRobin Gong module_i2c_driver(pfuze_driver);
8533784b6d6SRobin Gong 
8543784b6d6SRobin Gong MODULE_AUTHOR("Robin Gong <b38343@freescale.com>");
855297101abSStefan Wahren MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/200/3000/3001 PMIC");
85612d20fc2SRobin Gong MODULE_LICENSE("GPL v2");
857