xref: /linux/drivers/regulator/pfuze100-regulator.c (revision a7503a9d8fcfac3fefdb63fc61efedef41635e94)
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>
133784b6d6SRobin Gong #include <linux/regulator/driver.h>
143784b6d6SRobin Gong #include <linux/regulator/machine.h>
153784b6d6SRobin Gong #include <linux/regulator/pfuze100.h>
163784b6d6SRobin Gong #include <linux/i2c.h>
173784b6d6SRobin Gong #include <linux/slab.h>
183784b6d6SRobin Gong #include <linux/regmap.h>
193784b6d6SRobin Gong 
209d2fd4f0SMarco Felsch #define PFUZE_FLAG_DISABLE_SW	BIT(1)
219d2fd4f0SMarco Felsch 
223784b6d6SRobin Gong #define PFUZE_NUMREGS		128
233784b6d6SRobin Gong #define PFUZE100_VOL_OFFSET	0
243784b6d6SRobin Gong #define PFUZE100_STANDBY_OFFSET	1
253784b6d6SRobin Gong #define PFUZE100_MODE_OFFSET	3
263784b6d6SRobin Gong #define PFUZE100_CONF_OFFSET	4
273784b6d6SRobin Gong 
283784b6d6SRobin Gong #define PFUZE100_DEVICEID	0x0
293784b6d6SRobin Gong #define PFUZE100_REVID		0x3
30a1b6fa85SAxel Lin #define PFUZE100_FABID		0x4
313784b6d6SRobin Gong 
32c6182ac9SGeorge McCollister #define PFUZE100_COINVOL	0x1a
333784b6d6SRobin Gong #define PFUZE100_SW1ABVOL	0x20
34c29daffaSOleksij Rempel #define PFUZE100_SW1ABMODE	0x23
353784b6d6SRobin Gong #define PFUZE100_SW1CVOL	0x2e
36c29daffaSOleksij Rempel #define PFUZE100_SW1CMODE	0x31
373784b6d6SRobin Gong #define PFUZE100_SW2VOL		0x35
38c29daffaSOleksij Rempel #define PFUZE100_SW2MODE	0x38
393784b6d6SRobin Gong #define PFUZE100_SW3AVOL	0x3c
40c29daffaSOleksij Rempel #define PFUZE100_SW3AMODE	0x3f
413784b6d6SRobin Gong #define PFUZE100_SW3BVOL	0x43
42c29daffaSOleksij Rempel #define PFUZE100_SW3BMODE	0x46
433784b6d6SRobin Gong #define PFUZE100_SW4VOL		0x4a
44c29daffaSOleksij Rempel #define PFUZE100_SW4MODE	0x4d
453784b6d6SRobin Gong #define PFUZE100_SWBSTCON1	0x66
463784b6d6SRobin Gong #define PFUZE100_VREFDDRCON	0x6a
473784b6d6SRobin Gong #define PFUZE100_VSNVSVOL	0x6b
483784b6d6SRobin Gong #define PFUZE100_VGEN1VOL	0x6c
493784b6d6SRobin Gong #define PFUZE100_VGEN2VOL	0x6d
503784b6d6SRobin Gong #define PFUZE100_VGEN3VOL	0x6e
513784b6d6SRobin Gong #define PFUZE100_VGEN4VOL	0x6f
523784b6d6SRobin Gong #define PFUZE100_VGEN5VOL	0x70
533784b6d6SRobin Gong #define PFUZE100_VGEN6VOL	0x71
543784b6d6SRobin Gong 
55c29daffaSOleksij Rempel #define PFUZE100_SWxMODE_MASK	0xf
56c29daffaSOleksij Rempel #define PFUZE100_SWxMODE_APS_APS	0x8
57c29daffaSOleksij Rempel #define PFUZE100_SWxMODE_APS_OFF	0x4
58c29daffaSOleksij Rempel 
59c29daffaSOleksij Rempel #define PFUZE100_VGENxLPWR	BIT(6)
60c29daffaSOleksij Rempel #define PFUZE100_VGENxSTBY	BIT(5)
61c29daffaSOleksij Rempel 
62297101abSStefan Wahren enum chips { PFUZE100, PFUZE200, PFUZE3000 = 3, PFUZE3001 = 0x31, };
63f2518480SRobin Gong 
643784b6d6SRobin Gong struct pfuze_regulator {
653784b6d6SRobin Gong 	struct regulator_desc desc;
663784b6d6SRobin Gong 	unsigned char stby_reg;
673784b6d6SRobin Gong 	unsigned char stby_mask;
689d2fd4f0SMarco Felsch 	bool sw_reg;
693784b6d6SRobin Gong };
703784b6d6SRobin Gong 
713784b6d6SRobin Gong struct pfuze_chip {
72f2518480SRobin Gong 	int	chip_id;
739d2fd4f0SMarco Felsch 	int     flags;
743784b6d6SRobin Gong 	struct regmap *regmap;
753784b6d6SRobin Gong 	struct device *dev;
763784b6d6SRobin Gong 	struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR];
773784b6d6SRobin Gong 	struct regulator_dev *regulators[PFUZE100_MAX_REGULATOR];
7812425654SFabio Estevam 	struct pfuze_regulator *pfuze_regulators;
793784b6d6SRobin Gong };
803784b6d6SRobin Gong 
813784b6d6SRobin Gong static const int pfuze100_swbst[] = {
823784b6d6SRobin Gong 	5000000, 5050000, 5100000, 5150000,
833784b6d6SRobin Gong };
843784b6d6SRobin Gong 
853784b6d6SRobin Gong static const int pfuze100_vsnvs[] = {
863784b6d6SRobin Gong 	1000000, 1100000, 1200000, 1300000, 1500000, 1800000, 3000000,
873784b6d6SRobin Gong };
883784b6d6SRobin Gong 
89c6182ac9SGeorge McCollister static const int pfuze100_coin[] = {
90c6182ac9SGeorge McCollister 	2500000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
91c6182ac9SGeorge McCollister };
92c6182ac9SGeorge McCollister 
931dced996SAnson Huang static const int pfuze3000_sw1a[] = {
941dced996SAnson Huang 	700000, 725000, 750000, 775000, 800000, 825000, 850000, 875000,
951dced996SAnson Huang 	900000, 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000,
961dced996SAnson Huang 	1100000, 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000,
971dced996SAnson Huang 	1300000, 1325000, 1350000, 1375000, 1400000, 1425000, 1800000, 3300000,
981dced996SAnson Huang };
991dced996SAnson Huang 
100e5a7a72cSRobin Gong static const int pfuze3000_sw2lo[] = {
101e5a7a72cSRobin Gong 	1500000, 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000,
102e5a7a72cSRobin Gong };
103e5a7a72cSRobin Gong 
104e5a7a72cSRobin Gong static const int pfuze3000_sw2hi[] = {
105e5a7a72cSRobin Gong 	2500000, 2800000, 2850000, 3000000, 3100000, 3150000, 3200000, 3300000,
106e5a7a72cSRobin Gong };
107e5a7a72cSRobin Gong 
1083784b6d6SRobin Gong static const struct i2c_device_id pfuze_device_id[] = {
109f2518480SRobin Gong 	{.name = "pfuze100", .driver_data = PFUZE100},
110f2518480SRobin Gong 	{.name = "pfuze200", .driver_data = PFUZE200},
111e5a7a72cSRobin Gong 	{.name = "pfuze3000", .driver_data = PFUZE3000},
112297101abSStefan Wahren 	{.name = "pfuze3001", .driver_data = PFUZE3001},
113e6c4c337SAxel Lin 	{ }
1143784b6d6SRobin Gong };
1153784b6d6SRobin Gong MODULE_DEVICE_TABLE(i2c, pfuze_device_id);
1163784b6d6SRobin Gong 
1173784b6d6SRobin Gong static const struct of_device_id pfuze_dt_ids[] = {
118f2518480SRobin Gong 	{ .compatible = "fsl,pfuze100", .data = (void *)PFUZE100},
119f2518480SRobin Gong 	{ .compatible = "fsl,pfuze200", .data = (void *)PFUZE200},
120e5a7a72cSRobin Gong 	{ .compatible = "fsl,pfuze3000", .data = (void *)PFUZE3000},
121297101abSStefan Wahren 	{ .compatible = "fsl,pfuze3001", .data = (void *)PFUZE3001},
122e6c4c337SAxel Lin 	{ }
1233784b6d6SRobin Gong };
1243784b6d6SRobin Gong MODULE_DEVICE_TABLE(of, pfuze_dt_ids);
1253784b6d6SRobin Gong 
1263784b6d6SRobin Gong static int pfuze100_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
1273784b6d6SRobin Gong {
1283784b6d6SRobin Gong 	struct pfuze_chip *pfuze100 = rdev_get_drvdata(rdev);
129d55efa4dSThiago Farina 	int id = rdev_get_id(rdev);
130297101abSStefan Wahren 	bool reg_has_ramp_delay;
131*a7503a9dSRobin Gong 	unsigned int ramp_bits = 0;
1323784b6d6SRobin Gong 	int ret;
1333784b6d6SRobin Gong 
134297101abSStefan Wahren 	switch (pfuze100->chip_id) {
135297101abSStefan Wahren 	case PFUZE3001:
136297101abSStefan Wahren 		/* no dynamic voltage scaling for PF3001 */
137297101abSStefan Wahren 		reg_has_ramp_delay = false;
138297101abSStefan Wahren 		break;
139297101abSStefan Wahren 	case PFUZE3000:
140297101abSStefan Wahren 		reg_has_ramp_delay = (id < PFUZE3000_SWBST);
141297101abSStefan Wahren 		break;
142297101abSStefan Wahren 	case PFUZE200:
143297101abSStefan Wahren 		reg_has_ramp_delay = (id < PFUZE200_SWBST);
144297101abSStefan Wahren 		break;
145297101abSStefan Wahren 	case PFUZE100:
146297101abSStefan Wahren 	default:
147297101abSStefan Wahren 		reg_has_ramp_delay = (id < PFUZE100_SWBST);
148297101abSStefan Wahren 		break;
149297101abSStefan Wahren 	}
150297101abSStefan Wahren 
151297101abSStefan Wahren 	if (reg_has_ramp_delay) {
152*a7503a9dSRobin Gong 		if (ramp_delay > 0) {
153e5656669SAxel Lin 			ramp_delay = 12500 / ramp_delay;
1543784b6d6SRobin Gong 			ramp_bits = (ramp_delay >> 1) - (ramp_delay >> 3);
155*a7503a9dSRobin Gong 		}
156*a7503a9dSRobin Gong 
157e5656669SAxel Lin 		ret = regmap_update_bits(pfuze100->regmap,
158e5656669SAxel Lin 					 rdev->desc->vsel_reg + 4,
159e5656669SAxel Lin 					 0xc0, ramp_bits << 6);
1603784b6d6SRobin Gong 		if (ret < 0)
1613784b6d6SRobin Gong 			dev_err(pfuze100->dev, "ramp failed, err %d\n", ret);
162297101abSStefan Wahren 	} else {
1633784b6d6SRobin Gong 		ret = -EACCES;
164297101abSStefan Wahren 	}
1653784b6d6SRobin Gong 
1663784b6d6SRobin Gong 	return ret;
1673784b6d6SRobin Gong }
1683784b6d6SRobin Gong 
169e5053853SBhumika Goyal static const struct regulator_ops pfuze100_ldo_regulator_ops = {
1703784b6d6SRobin Gong 	.enable = regulator_enable_regmap,
1713784b6d6SRobin Gong 	.disable = regulator_disable_regmap,
1723784b6d6SRobin Gong 	.is_enabled = regulator_is_enabled_regmap,
1733784b6d6SRobin Gong 	.list_voltage = regulator_list_voltage_linear,
1743784b6d6SRobin Gong 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
1753784b6d6SRobin Gong 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
1763784b6d6SRobin Gong };
1773784b6d6SRobin Gong 
178e5053853SBhumika Goyal static const struct regulator_ops pfuze100_fixed_regulator_ops = {
179ab3ca774SAxel Lin 	.enable = regulator_enable_regmap,
180ab3ca774SAxel Lin 	.disable = regulator_disable_regmap,
181ab3ca774SAxel Lin 	.is_enabled = regulator_is_enabled_regmap,
1823784b6d6SRobin Gong 	.list_voltage = regulator_list_voltage_linear,
1833784b6d6SRobin Gong };
1843784b6d6SRobin Gong 
185e5053853SBhumika Goyal static const struct regulator_ops pfuze100_sw_regulator_ops = {
1863784b6d6SRobin Gong 	.list_voltage = regulator_list_voltage_linear,
1873784b6d6SRobin Gong 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
1883784b6d6SRobin Gong 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
1893784b6d6SRobin Gong 	.set_voltage_time_sel = regulator_set_voltage_time_sel,
1903784b6d6SRobin Gong 	.set_ramp_delay = pfuze100_set_ramp_delay,
1913784b6d6SRobin Gong };
1923784b6d6SRobin Gong 
1939d2fd4f0SMarco Felsch static const struct regulator_ops pfuze100_sw_disable_regulator_ops = {
1949d2fd4f0SMarco Felsch 	.enable = regulator_enable_regmap,
1959d2fd4f0SMarco Felsch 	.disable = regulator_disable_regmap,
1969d2fd4f0SMarco Felsch 	.is_enabled = regulator_is_enabled_regmap,
1979d2fd4f0SMarco Felsch 	.list_voltage = regulator_list_voltage_linear,
1989d2fd4f0SMarco Felsch 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
1999d2fd4f0SMarco Felsch 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
2009d2fd4f0SMarco Felsch 	.set_voltage_time_sel = regulator_set_voltage_time_sel,
2019d2fd4f0SMarco Felsch 	.set_ramp_delay = pfuze100_set_ramp_delay,
2029d2fd4f0SMarco Felsch };
2039d2fd4f0SMarco Felsch 
204e5053853SBhumika Goyal static const struct regulator_ops pfuze100_swb_regulator_ops = {
205a6dcf978SSean Cross 	.enable = regulator_enable_regmap,
206a6dcf978SSean Cross 	.disable = regulator_disable_regmap,
2070b01fd3dSAnson Huang 	.is_enabled = regulator_is_enabled_regmap,
2083784b6d6SRobin Gong 	.list_voltage = regulator_list_voltage_table,
2092e04cc41SAxel Lin 	.map_voltage = regulator_map_voltage_ascend,
2103784b6d6SRobin Gong 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
2113784b6d6SRobin Gong 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
2123784b6d6SRobin Gong 
2133784b6d6SRobin Gong };
2143784b6d6SRobin Gong 
2156f1cf525SRobin Gong static const struct regulator_ops pfuze3000_sw_regulator_ops = {
2166f1cf525SRobin Gong 	.enable = regulator_enable_regmap,
2176f1cf525SRobin Gong 	.disable = regulator_disable_regmap,
2186f1cf525SRobin Gong 	.is_enabled = regulator_is_enabled_regmap,
2196f1cf525SRobin Gong 	.list_voltage = regulator_list_voltage_table,
2206f1cf525SRobin Gong 	.map_voltage = regulator_map_voltage_ascend,
2216f1cf525SRobin Gong 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
2226f1cf525SRobin Gong 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
2236f1cf525SRobin Gong 	.set_voltage_time_sel = regulator_set_voltage_time_sel,
2246f1cf525SRobin Gong 	.set_ramp_delay = pfuze100_set_ramp_delay,
2256f1cf525SRobin Gong 
2266f1cf525SRobin Gong };
2276f1cf525SRobin Gong 
228f2518480SRobin Gong #define PFUZE100_FIXED_REG(_chip, _name, base, voltage)	\
229f2518480SRobin Gong 	[_chip ## _ ## _name] = {	\
2303784b6d6SRobin Gong 		.desc = {	\
2313784b6d6SRobin Gong 			.name = #_name,	\
2323784b6d6SRobin Gong 			.n_voltages = 1,	\
2333784b6d6SRobin Gong 			.ops = &pfuze100_fixed_regulator_ops,	\
2343784b6d6SRobin Gong 			.type = REGULATOR_VOLTAGE,	\
235f2518480SRobin Gong 			.id = _chip ## _ ## _name,	\
2363784b6d6SRobin Gong 			.owner = THIS_MODULE,	\
2373784b6d6SRobin Gong 			.min_uV = (voltage),	\
2383784b6d6SRobin Gong 			.enable_reg = (base),	\
2393784b6d6SRobin Gong 			.enable_mask = 0x10,	\
2403784b6d6SRobin Gong 		},	\
2413784b6d6SRobin Gong 	}
2423784b6d6SRobin Gong 
243f2518480SRobin Gong #define PFUZE100_SW_REG(_chip, _name, base, min, max, step)	\
244f2518480SRobin Gong 	[_chip ## _ ## _name] = {	\
2453784b6d6SRobin Gong 		.desc = {	\
2463784b6d6SRobin Gong 			.name = #_name,\
2473784b6d6SRobin Gong 			.n_voltages = ((max) - (min)) / (step) + 1,	\
2483784b6d6SRobin Gong 			.ops = &pfuze100_sw_regulator_ops,	\
2493784b6d6SRobin Gong 			.type = REGULATOR_VOLTAGE,	\
250f2518480SRobin Gong 			.id = _chip ## _ ## _name,	\
2513784b6d6SRobin Gong 			.owner = THIS_MODULE,	\
2523784b6d6SRobin Gong 			.min_uV = (min),	\
2533784b6d6SRobin Gong 			.uV_step = (step),	\
2543784b6d6SRobin Gong 			.vsel_reg = (base) + PFUZE100_VOL_OFFSET,	\
2553784b6d6SRobin Gong 			.vsel_mask = 0x3f,	\
2569d2fd4f0SMarco Felsch 			.enable_reg = (base) + PFUZE100_MODE_OFFSET,	\
2579d2fd4f0SMarco Felsch 			.enable_mask = 0xf,	\
2583784b6d6SRobin Gong 		},	\
2593784b6d6SRobin Gong 		.stby_reg = (base) + PFUZE100_STANDBY_OFFSET,	\
2603784b6d6SRobin Gong 		.stby_mask = 0x3f,	\
2619d2fd4f0SMarco Felsch 		.sw_reg = true,		\
2623784b6d6SRobin Gong 	}
2633784b6d6SRobin Gong 
264f2518480SRobin Gong #define PFUZE100_SWB_REG(_chip, _name, base, mask, voltages)	\
265f2518480SRobin Gong 	[_chip ## _ ##  _name] = {	\
2663784b6d6SRobin Gong 		.desc = {	\
2673784b6d6SRobin Gong 			.name = #_name,	\
2683784b6d6SRobin Gong 			.n_voltages = ARRAY_SIZE(voltages),	\
2693784b6d6SRobin Gong 			.ops = &pfuze100_swb_regulator_ops,	\
2703784b6d6SRobin Gong 			.type = REGULATOR_VOLTAGE,	\
271f2518480SRobin Gong 			.id = _chip ## _ ## _name,	\
2723784b6d6SRobin Gong 			.owner = THIS_MODULE,	\
2733784b6d6SRobin Gong 			.volt_table = voltages,	\
2743784b6d6SRobin Gong 			.vsel_reg = (base),	\
2753784b6d6SRobin Gong 			.vsel_mask = (mask),	\
276a6dcf978SSean Cross 			.enable_reg = (base),	\
277a6dcf978SSean Cross 			.enable_mask = 0x48,	\
2783784b6d6SRobin Gong 		},	\
2793784b6d6SRobin Gong 	}
2803784b6d6SRobin Gong 
281f2518480SRobin Gong #define PFUZE100_VGEN_REG(_chip, _name, base, min, max, step)	\
282f2518480SRobin Gong 	[_chip ## _ ## _name] = {	\
2833784b6d6SRobin Gong 		.desc = {	\
2843784b6d6SRobin Gong 			.name = #_name,	\
2853784b6d6SRobin Gong 			.n_voltages = ((max) - (min)) / (step) + 1,	\
2863784b6d6SRobin Gong 			.ops = &pfuze100_ldo_regulator_ops,	\
2873784b6d6SRobin Gong 			.type = REGULATOR_VOLTAGE,	\
288f2518480SRobin Gong 			.id = _chip ## _ ## _name,	\
2893784b6d6SRobin Gong 			.owner = THIS_MODULE,	\
2903784b6d6SRobin Gong 			.min_uV = (min),	\
2913784b6d6SRobin Gong 			.uV_step = (step),	\
2923784b6d6SRobin Gong 			.vsel_reg = (base),	\
2933784b6d6SRobin Gong 			.vsel_mask = 0xf,	\
2943784b6d6SRobin Gong 			.enable_reg = (base),	\
2953784b6d6SRobin Gong 			.enable_mask = 0x10,	\
2963784b6d6SRobin Gong 		},	\
2973784b6d6SRobin Gong 		.stby_reg = (base),	\
2983784b6d6SRobin Gong 		.stby_mask = 0x20,	\
2993784b6d6SRobin Gong 	}
3003784b6d6SRobin Gong 
301c6182ac9SGeorge McCollister #define PFUZE100_COIN_REG(_chip, _name, base, mask, voltages)	\
302c6182ac9SGeorge McCollister 	[_chip ## _ ##  _name] = {	\
303c6182ac9SGeorge McCollister 		.desc = {	\
304c6182ac9SGeorge McCollister 			.name = #_name,	\
305c6182ac9SGeorge McCollister 			.n_voltages = ARRAY_SIZE(voltages),	\
306c6182ac9SGeorge McCollister 			.ops = &pfuze100_swb_regulator_ops,	\
307c6182ac9SGeorge McCollister 			.type = REGULATOR_VOLTAGE,	\
308c6182ac9SGeorge McCollister 			.id = _chip ## _ ## _name,	\
309c6182ac9SGeorge McCollister 			.owner = THIS_MODULE,	\
310c6182ac9SGeorge McCollister 			.volt_table = voltages,	\
311c6182ac9SGeorge McCollister 			.vsel_reg = (base),	\
312c6182ac9SGeorge McCollister 			.vsel_mask = (mask),	\
313c6182ac9SGeorge McCollister 			.enable_reg = (base),	\
314c6182ac9SGeorge McCollister 			.enable_mask = 0x8,	\
315c6182ac9SGeorge McCollister 		},	\
316c6182ac9SGeorge McCollister 	}
317c6182ac9SGeorge McCollister 
318e5a7a72cSRobin Gong #define PFUZE3000_VCC_REG(_chip, _name, base, min, max, step)	{	\
319e5a7a72cSRobin Gong 	.desc = {	\
320e5a7a72cSRobin Gong 		.name = #_name,	\
321e5a7a72cSRobin Gong 		.n_voltages = ((max) - (min)) / (step) + 1,	\
322e5a7a72cSRobin Gong 		.ops = &pfuze100_ldo_regulator_ops,	\
323e5a7a72cSRobin Gong 		.type = REGULATOR_VOLTAGE,	\
324e5a7a72cSRobin Gong 		.id = _chip ## _ ## _name,	\
325e5a7a72cSRobin Gong 		.owner = THIS_MODULE,	\
326e5a7a72cSRobin Gong 		.min_uV = (min),	\
327e5a7a72cSRobin Gong 		.uV_step = (step),	\
328e5a7a72cSRobin Gong 		.vsel_reg = (base),	\
329e5a7a72cSRobin Gong 		.vsel_mask = 0x3,	\
330e5a7a72cSRobin Gong 		.enable_reg = (base),	\
331e5a7a72cSRobin Gong 		.enable_mask = 0x10,	\
332e5a7a72cSRobin Gong 	},	\
333e5a7a72cSRobin Gong 	.stby_reg = (base),	\
334e5a7a72cSRobin Gong 	.stby_mask = 0x20,	\
335e5a7a72cSRobin Gong }
336e5a7a72cSRobin Gong 
3376f1cf525SRobin Gong /* No linar case for the some switches of PFUZE3000 */
3386f1cf525SRobin Gong #define PFUZE3000_SW_REG(_chip, _name, base, mask, voltages)	\
3396f1cf525SRobin Gong 	[_chip ## _ ##  _name] = {	\
340e5a7a72cSRobin Gong 		.desc = {	\
341e5a7a72cSRobin Gong 			.name = #_name,	\
3426f1cf525SRobin Gong 			.n_voltages = ARRAY_SIZE(voltages),	\
3436f1cf525SRobin Gong 			.ops = &pfuze3000_sw_regulator_ops,	\
344e5a7a72cSRobin Gong 			.type = REGULATOR_VOLTAGE,	\
345e5a7a72cSRobin Gong 			.id = _chip ## _ ## _name,	\
346e5a7a72cSRobin Gong 			.owner = THIS_MODULE,	\
3476f1cf525SRobin Gong 			.volt_table = voltages,	\
348e5a7a72cSRobin Gong 			.vsel_reg = (base) + PFUZE100_VOL_OFFSET,	\
3496f1cf525SRobin Gong 			.vsel_mask = (mask),	\
3506f1cf525SRobin Gong 			.enable_reg = (base) + PFUZE100_MODE_OFFSET,	\
3516f1cf525SRobin Gong 			.enable_mask = 0xf,	\
3526f1cf525SRobin Gong 			.enable_val = 0x8,	\
3536f1cf525SRobin Gong 			.enable_time = 500,	\
354e5a7a72cSRobin Gong 		},	\
355e5a7a72cSRobin Gong 		.stby_reg = (base) + PFUZE100_STANDBY_OFFSET,	\
3566f1cf525SRobin Gong 		.stby_mask = (mask),	\
3576f1cf525SRobin Gong 		.sw_reg = true,		\
358e5a7a72cSRobin Gong 	}
359e5a7a72cSRobin Gong 
360e5a7a72cSRobin Gong #define PFUZE3000_SW3_REG(_chip, _name, base, min, max, step)	{	\
361e5a7a72cSRobin Gong 	.desc = {	\
362e5a7a72cSRobin Gong 		.name = #_name,\
363e5a7a72cSRobin Gong 		.n_voltages = ((max) - (min)) / (step) + 1,	\
364e5a7a72cSRobin Gong 		.ops = &pfuze100_sw_regulator_ops,	\
365e5a7a72cSRobin Gong 		.type = REGULATOR_VOLTAGE,	\
366e5a7a72cSRobin Gong 		.id = _chip ## _ ## _name,	\
367e5a7a72cSRobin Gong 		.owner = THIS_MODULE,	\
368e5a7a72cSRobin Gong 		.min_uV = (min),	\
369e5a7a72cSRobin Gong 		.uV_step = (step),	\
370e5a7a72cSRobin Gong 		.vsel_reg = (base) + PFUZE100_VOL_OFFSET,	\
371e5a7a72cSRobin Gong 		.vsel_mask = 0xf,	\
372e5a7a72cSRobin Gong 	},	\
373e5a7a72cSRobin Gong 	.stby_reg = (base) + PFUZE100_STANDBY_OFFSET,	\
374e5a7a72cSRobin Gong 	.stby_mask = 0xf,	\
375e5a7a72cSRobin Gong }
376e5a7a72cSRobin Gong 
377f2518480SRobin Gong /* PFUZE100 */
3783784b6d6SRobin Gong static struct pfuze_regulator pfuze100_regulators[] = {
379f2518480SRobin Gong 	PFUZE100_SW_REG(PFUZE100, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000),
380f2518480SRobin Gong 	PFUZE100_SW_REG(PFUZE100, SW1C, PFUZE100_SW1CVOL, 300000, 1875000, 25000),
381f2518480SRobin Gong 	PFUZE100_SW_REG(PFUZE100, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000),
382f2518480SRobin Gong 	PFUZE100_SW_REG(PFUZE100, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000),
383f2518480SRobin Gong 	PFUZE100_SW_REG(PFUZE100, SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000),
384f2518480SRobin Gong 	PFUZE100_SW_REG(PFUZE100, SW4, PFUZE100_SW4VOL, 400000, 1975000, 25000),
385f2518480SRobin Gong 	PFUZE100_SWB_REG(PFUZE100, SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst),
386f2518480SRobin Gong 	PFUZE100_SWB_REG(PFUZE100, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
387f2518480SRobin Gong 	PFUZE100_FIXED_REG(PFUZE100, VREFDDR, PFUZE100_VREFDDRCON, 750000),
388f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE100, VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000),
389f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE100, VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
390f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE100, VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000),
391f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE100, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000),
392f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE100, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
393f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE100, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
39461d0de05SAdam Ford 	PFUZE100_COIN_REG(PFUZE100, COIN, PFUZE100_COINVOL, 0x7, pfuze100_coin),
3953784b6d6SRobin Gong };
3963784b6d6SRobin Gong 
397f2518480SRobin Gong static struct pfuze_regulator pfuze200_regulators[] = {
398f2518480SRobin Gong 	PFUZE100_SW_REG(PFUZE200, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000),
399f2518480SRobin Gong 	PFUZE100_SW_REG(PFUZE200, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000),
400f2518480SRobin Gong 	PFUZE100_SW_REG(PFUZE200, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000),
401f2518480SRobin Gong 	PFUZE100_SW_REG(PFUZE200, SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000),
402f2518480SRobin Gong 	PFUZE100_SWB_REG(PFUZE200, SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst),
403f2518480SRobin Gong 	PFUZE100_SWB_REG(PFUZE200, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
404f2518480SRobin Gong 	PFUZE100_FIXED_REG(PFUZE200, VREFDDR, PFUZE100_VREFDDRCON, 750000),
405f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE200, VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000),
406f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE200, VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
407f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE200, VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000),
408f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE200, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000),
409f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE200, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
410f2518480SRobin Gong 	PFUZE100_VGEN_REG(PFUZE200, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
411c6182ac9SGeorge McCollister 	PFUZE100_COIN_REG(PFUZE200, COIN, PFUZE100_COINVOL, 0x7, pfuze100_coin),
412f2518480SRobin Gong };
413f2518480SRobin Gong 
414e5a7a72cSRobin Gong static struct pfuze_regulator pfuze3000_regulators[] = {
4156f1cf525SRobin Gong 	PFUZE3000_SW_REG(PFUZE3000, SW1A, PFUZE100_SW1ABVOL, 0x1f, pfuze3000_sw1a),
416e5a7a72cSRobin Gong 	PFUZE100_SW_REG(PFUZE3000, SW1B, PFUZE100_SW1CVOL, 700000, 1475000, 25000),
4176f1cf525SRobin Gong 	PFUZE3000_SW_REG(PFUZE3000, SW2, PFUZE100_SW2VOL, 0x7, pfuze3000_sw2lo),
418e5a7a72cSRobin Gong 	PFUZE3000_SW3_REG(PFUZE3000, SW3, PFUZE100_SW3AVOL, 900000, 1650000, 50000),
419e5a7a72cSRobin Gong 	PFUZE100_SWB_REG(PFUZE3000, SWBST, PFUZE100_SWBSTCON1, 0x3, pfuze100_swbst),
420e5a7a72cSRobin Gong 	PFUZE100_SWB_REG(PFUZE3000, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
421e5a7a72cSRobin Gong 	PFUZE100_FIXED_REG(PFUZE3000, VREFDDR, PFUZE100_VREFDDRCON, 750000),
422e5a7a72cSRobin Gong 	PFUZE100_VGEN_REG(PFUZE3000, VLDO1, PFUZE100_VGEN1VOL, 1800000, 3300000, 100000),
423e5a7a72cSRobin Gong 	PFUZE100_VGEN_REG(PFUZE3000, VLDO2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
424e5a7a72cSRobin Gong 	PFUZE3000_VCC_REG(PFUZE3000, VCCSD, PFUZE100_VGEN3VOL, 2850000, 3300000, 150000),
425e5a7a72cSRobin Gong 	PFUZE3000_VCC_REG(PFUZE3000, V33, PFUZE100_VGEN4VOL, 2850000, 3300000, 150000),
426e5a7a72cSRobin Gong 	PFUZE100_VGEN_REG(PFUZE3000, VLDO3, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
427e5a7a72cSRobin Gong 	PFUZE100_VGEN_REG(PFUZE3000, VLDO4, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
428e5a7a72cSRobin Gong };
429e5a7a72cSRobin Gong 
430297101abSStefan Wahren static struct pfuze_regulator pfuze3001_regulators[] = {
4316f1cf525SRobin Gong 	PFUZE3000_SW_REG(PFUZE3001, SW1, PFUZE100_SW1ABVOL, 0x1f, pfuze3000_sw1a),
4326f1cf525SRobin Gong 	PFUZE3000_SW_REG(PFUZE3001, SW2, PFUZE100_SW2VOL, 0x7, pfuze3000_sw2lo),
433297101abSStefan Wahren 	PFUZE3000_SW3_REG(PFUZE3001, SW3, PFUZE100_SW3AVOL, 900000, 1650000, 50000),
434297101abSStefan Wahren 	PFUZE100_SWB_REG(PFUZE3001, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
435297101abSStefan Wahren 	PFUZE100_VGEN_REG(PFUZE3001, VLDO1, PFUZE100_VGEN1VOL, 1800000, 3300000, 100000),
436297101abSStefan Wahren 	PFUZE100_VGEN_REG(PFUZE3001, VLDO2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
437297101abSStefan Wahren 	PFUZE3000_VCC_REG(PFUZE3001, VCCSD, PFUZE100_VGEN3VOL, 2850000, 3300000, 150000),
438297101abSStefan Wahren 	PFUZE3000_VCC_REG(PFUZE3001, V33, PFUZE100_VGEN4VOL, 2850000, 3300000, 150000),
439297101abSStefan Wahren 	PFUZE100_VGEN_REG(PFUZE3001, VLDO3, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
440297101abSStefan Wahren 	PFUZE100_VGEN_REG(PFUZE3001, VLDO4, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
441297101abSStefan Wahren };
442297101abSStefan Wahren 
4433784b6d6SRobin Gong #ifdef CONFIG_OF
444f2518480SRobin Gong /* PFUZE100 */
4453784b6d6SRobin Gong static struct of_regulator_match pfuze100_matches[] = {
4463784b6d6SRobin Gong 	{ .name = "sw1ab",	},
4473784b6d6SRobin Gong 	{ .name = "sw1c",	},
4483784b6d6SRobin Gong 	{ .name = "sw2",	},
4493784b6d6SRobin Gong 	{ .name = "sw3a",	},
4503784b6d6SRobin Gong 	{ .name = "sw3b",	},
4513784b6d6SRobin Gong 	{ .name = "sw4",	},
4523784b6d6SRobin Gong 	{ .name = "swbst",	},
4533784b6d6SRobin Gong 	{ .name = "vsnvs",	},
4543784b6d6SRobin Gong 	{ .name = "vrefddr",	},
4553784b6d6SRobin Gong 	{ .name = "vgen1",	},
4563784b6d6SRobin Gong 	{ .name = "vgen2",	},
4573784b6d6SRobin Gong 	{ .name = "vgen3",	},
4583784b6d6SRobin Gong 	{ .name = "vgen4",	},
4593784b6d6SRobin Gong 	{ .name = "vgen5",	},
4603784b6d6SRobin Gong 	{ .name = "vgen6",	},
46161d0de05SAdam Ford 	{ .name = "coin",	},
4623784b6d6SRobin Gong };
4633784b6d6SRobin Gong 
464f2518480SRobin Gong /* PFUZE200 */
465f2518480SRobin Gong static struct of_regulator_match pfuze200_matches[] = {
466f2518480SRobin Gong 
467f2518480SRobin Gong 	{ .name = "sw1ab",	},
468f2518480SRobin Gong 	{ .name = "sw2",	},
469f2518480SRobin Gong 	{ .name = "sw3a",	},
470f2518480SRobin Gong 	{ .name = "sw3b",	},
471f2518480SRobin Gong 	{ .name = "swbst",	},
472f2518480SRobin Gong 	{ .name = "vsnvs",	},
473f2518480SRobin Gong 	{ .name = "vrefddr",	},
474f2518480SRobin Gong 	{ .name = "vgen1",	},
475f2518480SRobin Gong 	{ .name = "vgen2",	},
476f2518480SRobin Gong 	{ .name = "vgen3",	},
477f2518480SRobin Gong 	{ .name = "vgen4",	},
478f2518480SRobin Gong 	{ .name = "vgen5",	},
479f2518480SRobin Gong 	{ .name = "vgen6",	},
480c6182ac9SGeorge McCollister 	{ .name = "coin",	},
481f2518480SRobin Gong };
482f2518480SRobin Gong 
483e5a7a72cSRobin Gong /* PFUZE3000 */
484e5a7a72cSRobin Gong static struct of_regulator_match pfuze3000_matches[] = {
485e5a7a72cSRobin Gong 
486e5a7a72cSRobin Gong 	{ .name = "sw1a",	},
487e5a7a72cSRobin Gong 	{ .name = "sw1b",	},
488e5a7a72cSRobin Gong 	{ .name = "sw2",	},
489e5a7a72cSRobin Gong 	{ .name = "sw3",	},
490e5a7a72cSRobin Gong 	{ .name = "swbst",	},
491e5a7a72cSRobin Gong 	{ .name = "vsnvs",	},
492e5a7a72cSRobin Gong 	{ .name = "vrefddr",	},
493e5a7a72cSRobin Gong 	{ .name = "vldo1",	},
494e5a7a72cSRobin Gong 	{ .name = "vldo2",	},
495e5a7a72cSRobin Gong 	{ .name = "vccsd",	},
496e5a7a72cSRobin Gong 	{ .name = "v33",	},
497e5a7a72cSRobin Gong 	{ .name = "vldo3",	},
498e5a7a72cSRobin Gong 	{ .name = "vldo4",	},
499e5a7a72cSRobin Gong };
500e5a7a72cSRobin Gong 
501297101abSStefan Wahren /* PFUZE3001 */
502297101abSStefan Wahren static struct of_regulator_match pfuze3001_matches[] = {
503297101abSStefan Wahren 
504297101abSStefan Wahren 	{ .name = "sw1",	},
505297101abSStefan Wahren 	{ .name = "sw2",	},
506297101abSStefan Wahren 	{ .name = "sw3",	},
507297101abSStefan Wahren 	{ .name = "vsnvs",	},
508297101abSStefan Wahren 	{ .name = "vldo1",	},
509297101abSStefan Wahren 	{ .name = "vldo2",	},
510297101abSStefan Wahren 	{ .name = "vccsd",	},
511297101abSStefan Wahren 	{ .name = "v33",	},
512297101abSStefan Wahren 	{ .name = "vldo3",	},
513297101abSStefan Wahren 	{ .name = "vldo4",	},
514297101abSStefan Wahren };
515297101abSStefan Wahren 
516f2518480SRobin Gong static struct of_regulator_match *pfuze_matches;
517f2518480SRobin Gong 
5183784b6d6SRobin Gong static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
5193784b6d6SRobin Gong {
5203784b6d6SRobin Gong 	struct device *dev = chip->dev;
5213784b6d6SRobin Gong 	struct device_node *np, *parent;
5223784b6d6SRobin Gong 	int ret;
5233784b6d6SRobin Gong 
5243e01c75aSFabio Estevam 	np = of_node_get(dev->of_node);
5253784b6d6SRobin Gong 	if (!np)
5266428789eSFabio Estevam 		return -EINVAL;
5273784b6d6SRobin Gong 
5289d2fd4f0SMarco Felsch 	if (of_property_read_bool(np, "fsl,pfuze-support-disable-sw"))
5299d2fd4f0SMarco Felsch 		chip->flags |= PFUZE_FLAG_DISABLE_SW;
5309d2fd4f0SMarco Felsch 
531d7857c42SSachin Kamat 	parent = of_get_child_by_name(np, "regulators");
5323784b6d6SRobin Gong 	if (!parent) {
5333784b6d6SRobin Gong 		dev_err(dev, "regulators node not found\n");
5343784b6d6SRobin Gong 		return -EINVAL;
5353784b6d6SRobin Gong 	}
5363784b6d6SRobin Gong 
537f2518480SRobin Gong 	switch (chip->chip_id) {
538297101abSStefan Wahren 	case PFUZE3001:
539297101abSStefan Wahren 		pfuze_matches = pfuze3001_matches;
540297101abSStefan Wahren 		ret = of_regulator_match(dev, parent, pfuze3001_matches,
541297101abSStefan Wahren 					 ARRAY_SIZE(pfuze3001_matches));
542297101abSStefan Wahren 		break;
543e5a7a72cSRobin Gong 	case PFUZE3000:
544e5a7a72cSRobin Gong 		pfuze_matches = pfuze3000_matches;
545e5a7a72cSRobin Gong 		ret = of_regulator_match(dev, parent, pfuze3000_matches,
546e5a7a72cSRobin Gong 					 ARRAY_SIZE(pfuze3000_matches));
547e5a7a72cSRobin Gong 		break;
548f2518480SRobin Gong 	case PFUZE200:
549f2518480SRobin Gong 		pfuze_matches = pfuze200_matches;
550f2518480SRobin Gong 		ret = of_regulator_match(dev, parent, pfuze200_matches,
551f2518480SRobin Gong 					 ARRAY_SIZE(pfuze200_matches));
552f2518480SRobin Gong 		break;
553f2518480SRobin Gong 
554f2518480SRobin Gong 	case PFUZE100:
555f2518480SRobin Gong 	default:
556f2518480SRobin Gong 		pfuze_matches = pfuze100_matches;
5573784b6d6SRobin Gong 		ret = of_regulator_match(dev, parent, pfuze100_matches,
5583784b6d6SRobin Gong 					 ARRAY_SIZE(pfuze100_matches));
559f2518480SRobin Gong 		break;
560f2518480SRobin Gong 	}
5613784b6d6SRobin Gong 
5623784b6d6SRobin Gong 	of_node_put(parent);
5633784b6d6SRobin Gong 	if (ret < 0) {
5643784b6d6SRobin Gong 		dev_err(dev, "Error parsing regulator init data: %d\n",
5653784b6d6SRobin Gong 			ret);
5663784b6d6SRobin Gong 		return ret;
5673784b6d6SRobin Gong 	}
5683784b6d6SRobin Gong 
5693784b6d6SRobin Gong 	return 0;
5703784b6d6SRobin Gong }
5713784b6d6SRobin Gong 
5723784b6d6SRobin Gong static inline struct regulator_init_data *match_init_data(int index)
5733784b6d6SRobin Gong {
574f2518480SRobin Gong 	return pfuze_matches[index].init_data;
5753784b6d6SRobin Gong }
5763784b6d6SRobin Gong 
5773784b6d6SRobin Gong static inline struct device_node *match_of_node(int index)
5783784b6d6SRobin Gong {
579f2518480SRobin Gong 	return pfuze_matches[index].of_node;
5803784b6d6SRobin Gong }
5813784b6d6SRobin Gong #else
5823784b6d6SRobin Gong static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
5833784b6d6SRobin Gong {
584205c97bcSRobin Gong 	return 0;
5853784b6d6SRobin Gong }
5863784b6d6SRobin Gong 
5873784b6d6SRobin Gong static inline struct regulator_init_data *match_init_data(int index)
5883784b6d6SRobin Gong {
5893784b6d6SRobin Gong 	return NULL;
5903784b6d6SRobin Gong }
5913784b6d6SRobin Gong 
5923784b6d6SRobin Gong static inline struct device_node *match_of_node(int index)
5933784b6d6SRobin Gong {
5943784b6d6SRobin Gong 	return NULL;
5953784b6d6SRobin Gong }
5963784b6d6SRobin Gong #endif
5973784b6d6SRobin Gong 
598c29daffaSOleksij Rempel static struct pfuze_chip *syspm_pfuze_chip;
599c29daffaSOleksij Rempel 
600c29daffaSOleksij Rempel static void pfuze_power_off_prepare(void)
601c29daffaSOleksij Rempel {
602db6565afSColin Ian King 	dev_info(syspm_pfuze_chip->dev, "Configure standby mode for power off");
603c29daffaSOleksij Rempel 
604c29daffaSOleksij Rempel 	/* Switch from default mode: APS/APS to APS/Off */
605c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW1ABMODE,
606c29daffaSOleksij Rempel 			   PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
607c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW1CMODE,
608c29daffaSOleksij Rempel 			   PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
609c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW2MODE,
610c29daffaSOleksij Rempel 			   PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
611c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW3AMODE,
612c29daffaSOleksij Rempel 			   PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
613c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW3BMODE,
614c29daffaSOleksij Rempel 			   PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
615c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW4MODE,
616c29daffaSOleksij Rempel 			   PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
617c29daffaSOleksij Rempel 
618c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN1VOL,
619c29daffaSOleksij Rempel 			   PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
620c29daffaSOleksij Rempel 			   PFUZE100_VGENxSTBY);
621c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN2VOL,
622c29daffaSOleksij Rempel 			   PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
623c29daffaSOleksij Rempel 			   PFUZE100_VGENxSTBY);
624c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN3VOL,
625c29daffaSOleksij Rempel 			   PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
626c29daffaSOleksij Rempel 			   PFUZE100_VGENxSTBY);
627c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN4VOL,
628c29daffaSOleksij Rempel 			   PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
629c29daffaSOleksij Rempel 			   PFUZE100_VGENxSTBY);
630c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN5VOL,
631c29daffaSOleksij Rempel 			   PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
632c29daffaSOleksij Rempel 			   PFUZE100_VGENxSTBY);
633c29daffaSOleksij Rempel 	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN6VOL,
634c29daffaSOleksij Rempel 			   PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
635c29daffaSOleksij Rempel 			   PFUZE100_VGENxSTBY);
636c29daffaSOleksij Rempel }
637c29daffaSOleksij Rempel 
638c29daffaSOleksij Rempel static int pfuze_power_off_prepare_init(struct pfuze_chip *pfuze_chip)
639c29daffaSOleksij Rempel {
640c29daffaSOleksij Rempel 	if (pfuze_chip->chip_id != PFUZE100) {
641c29daffaSOleksij Rempel 		dev_warn(pfuze_chip->dev, "Requested pm_power_off_prepare handler for not supported chip\n");
642c29daffaSOleksij Rempel 		return -ENODEV;
643c29daffaSOleksij Rempel 	}
644c29daffaSOleksij Rempel 
645c29daffaSOleksij Rempel 	if (pm_power_off_prepare) {
646c29daffaSOleksij Rempel 		dev_warn(pfuze_chip->dev, "pm_power_off_prepare is already registered.\n");
647c29daffaSOleksij Rempel 		return -EBUSY;
648c29daffaSOleksij Rempel 	}
649c29daffaSOleksij Rempel 
650c29daffaSOleksij Rempel 	if (syspm_pfuze_chip) {
651c29daffaSOleksij Rempel 		dev_warn(pfuze_chip->dev, "syspm_pfuze_chip is already set.\n");
652c29daffaSOleksij Rempel 		return -EBUSY;
653c29daffaSOleksij Rempel 	}
654c29daffaSOleksij Rempel 
655c29daffaSOleksij Rempel 	syspm_pfuze_chip = pfuze_chip;
656c29daffaSOleksij Rempel 	pm_power_off_prepare = pfuze_power_off_prepare;
657c29daffaSOleksij Rempel 
658c29daffaSOleksij Rempel 	return 0;
659c29daffaSOleksij Rempel }
660c29daffaSOleksij Rempel 
6613784b6d6SRobin Gong static int pfuze_identify(struct pfuze_chip *pfuze_chip)
6623784b6d6SRobin Gong {
6633784b6d6SRobin Gong 	unsigned int value;
6643784b6d6SRobin Gong 	int ret;
6653784b6d6SRobin Gong 
6663784b6d6SRobin Gong 	ret = regmap_read(pfuze_chip->regmap, PFUZE100_DEVICEID, &value);
6673784b6d6SRobin Gong 	if (ret)
6683784b6d6SRobin Gong 		return ret;
6693784b6d6SRobin Gong 
670f2518480SRobin Gong 	if (((value & 0x0f) == 0x8) && (pfuze_chip->chip_id == PFUZE100)) {
67162b38916SFabio Estevam 		/*
67262b38916SFabio Estevam 		 * Freescale misprogrammed 1-3% of parts prior to week 8 of 2013
673f2518480SRobin Gong 		 * as ID=8 in PFUZE100
67462b38916SFabio Estevam 		 */
675236c427cSTim Harvey 		dev_info(pfuze_chip->dev, "Assuming misprogrammed ID=0x8");
676e5a7a72cSRobin Gong 	} else if ((value & 0x0f) != pfuze_chip->chip_id &&
677297101abSStefan Wahren 		   (value & 0xf0) >> 4 != pfuze_chip->chip_id &&
678297101abSStefan Wahren 		   (value != pfuze_chip->chip_id)) {
679f2518480SRobin Gong 		/* device id NOT match with your setting */
6803784b6d6SRobin Gong 		dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value);
6813784b6d6SRobin Gong 		return -ENODEV;
6823784b6d6SRobin Gong 	}
6833784b6d6SRobin Gong 
6843784b6d6SRobin Gong 	ret = regmap_read(pfuze_chip->regmap, PFUZE100_REVID, &value);
6853784b6d6SRobin Gong 	if (ret)
6863784b6d6SRobin Gong 		return ret;
6873784b6d6SRobin Gong 	dev_info(pfuze_chip->dev,
688f2694383SFabio Estevam 		 "Full layer: %x, Metal layer: %x\n",
6893784b6d6SRobin Gong 		 (value & 0xf0) >> 4, value & 0x0f);
6903784b6d6SRobin Gong 
6913784b6d6SRobin Gong 	ret = regmap_read(pfuze_chip->regmap, PFUZE100_FABID, &value);
6923784b6d6SRobin Gong 	if (ret)
6933784b6d6SRobin Gong 		return ret;
6943784b6d6SRobin Gong 	dev_info(pfuze_chip->dev, "FAB: %x, FIN: %x\n",
6953784b6d6SRobin Gong 		 (value & 0xc) >> 2, value & 0x3);
6963784b6d6SRobin Gong 
6973784b6d6SRobin Gong 	return 0;
6983784b6d6SRobin Gong }
6993784b6d6SRobin Gong 
7003784b6d6SRobin Gong static const struct regmap_config pfuze_regmap_config = {
7013784b6d6SRobin Gong 	.reg_bits = 8,
7023784b6d6SRobin Gong 	.val_bits = 8,
7036b8430c3SAxel Lin 	.max_register = PFUZE_NUMREGS - 1,
7043784b6d6SRobin Gong 	.cache_type = REGCACHE_RBTREE,
7053784b6d6SRobin Gong };
7063784b6d6SRobin Gong 
7073784b6d6SRobin Gong static int pfuze100_regulator_probe(struct i2c_client *client,
7083784b6d6SRobin Gong 				    const struct i2c_device_id *id)
7093784b6d6SRobin Gong {
7103784b6d6SRobin Gong 	struct pfuze_chip *pfuze_chip;
7113784b6d6SRobin Gong 	struct pfuze_regulator_platform_data *pdata =
7123784b6d6SRobin Gong 	    dev_get_platdata(&client->dev);
7133784b6d6SRobin Gong 	struct regulator_config config = { };
7143784b6d6SRobin Gong 	int i, ret;
715f2518480SRobin Gong 	const struct of_device_id *match;
716f2518480SRobin Gong 	u32 regulator_num;
717e5a7a72cSRobin Gong 	u32 sw_check_start, sw_check_end, sw_hi = 0x40;
7183784b6d6SRobin Gong 
7193784b6d6SRobin Gong 	pfuze_chip = devm_kzalloc(&client->dev, sizeof(*pfuze_chip),
7203784b6d6SRobin Gong 			GFP_KERNEL);
7213784b6d6SRobin Gong 	if (!pfuze_chip)
7223784b6d6SRobin Gong 		return -ENOMEM;
7233784b6d6SRobin Gong 
724f2518480SRobin Gong 	if (client->dev.of_node) {
725f2518480SRobin Gong 		match = of_match_device(of_match_ptr(pfuze_dt_ids),
726f2518480SRobin Gong 				&client->dev);
727f2518480SRobin Gong 		if (!match) {
728f2518480SRobin Gong 			dev_err(&client->dev, "Error: No device match found\n");
729f2518480SRobin Gong 			return -ENODEV;
730f2518480SRobin Gong 		}
731f2518480SRobin Gong 		pfuze_chip->chip_id = (int)(long)match->data;
732f2518480SRobin Gong 	} else if (id) {
733f2518480SRobin Gong 		pfuze_chip->chip_id = id->driver_data;
734f2518480SRobin Gong 	} else {
735f2518480SRobin Gong 		dev_err(&client->dev, "No dts match or id table match found\n");
736f2518480SRobin Gong 		return -ENODEV;
737f2518480SRobin Gong 	}
738f2518480SRobin Gong 
7398c86ab25SAxel Lin 	i2c_set_clientdata(client, pfuze_chip);
7403784b6d6SRobin Gong 	pfuze_chip->dev = &client->dev;
7413784b6d6SRobin Gong 
7423784b6d6SRobin Gong 	pfuze_chip->regmap = devm_regmap_init_i2c(client, &pfuze_regmap_config);
7433784b6d6SRobin Gong 	if (IS_ERR(pfuze_chip->regmap)) {
7443784b6d6SRobin Gong 		ret = PTR_ERR(pfuze_chip->regmap);
7453784b6d6SRobin Gong 		dev_err(&client->dev,
7463784b6d6SRobin Gong 			"regmap allocation failed with err %d\n", ret);
7473784b6d6SRobin Gong 		return ret;
7483784b6d6SRobin Gong 	}
7493784b6d6SRobin Gong 
7503784b6d6SRobin Gong 	ret = pfuze_identify(pfuze_chip);
7513784b6d6SRobin Gong 	if (ret) {
7523784b6d6SRobin Gong 		dev_err(&client->dev, "unrecognized pfuze chip ID!\n");
7533784b6d6SRobin Gong 		return ret;
7543784b6d6SRobin Gong 	}
7553784b6d6SRobin Gong 
756f2518480SRobin Gong 	/* use the right regulators after identify the right device */
757f2518480SRobin Gong 	switch (pfuze_chip->chip_id) {
758297101abSStefan Wahren 	case PFUZE3001:
759297101abSStefan Wahren 		pfuze_chip->pfuze_regulators = pfuze3001_regulators;
760297101abSStefan Wahren 		regulator_num = ARRAY_SIZE(pfuze3001_regulators);
761297101abSStefan Wahren 		sw_check_start = PFUZE3001_SW2;
762297101abSStefan Wahren 		sw_check_end = PFUZE3001_SW2;
763297101abSStefan Wahren 		sw_hi = 1 << 3;
764297101abSStefan Wahren 		break;
765e5a7a72cSRobin Gong 	case PFUZE3000:
76612425654SFabio Estevam 		pfuze_chip->pfuze_regulators = pfuze3000_regulators;
767e5a7a72cSRobin Gong 		regulator_num = ARRAY_SIZE(pfuze3000_regulators);
768e5a7a72cSRobin Gong 		sw_check_start = PFUZE3000_SW2;
769e5a7a72cSRobin Gong 		sw_check_end = PFUZE3000_SW2;
770e5a7a72cSRobin Gong 		sw_hi = 1 << 3;
771e5a7a72cSRobin Gong 		break;
772f2518480SRobin Gong 	case PFUZE200:
77312425654SFabio Estevam 		pfuze_chip->pfuze_regulators = pfuze200_regulators;
774f2518480SRobin Gong 		regulator_num = ARRAY_SIZE(pfuze200_regulators);
775f2518480SRobin Gong 		sw_check_start = PFUZE200_SW2;
776f2518480SRobin Gong 		sw_check_end = PFUZE200_SW3B;
777f2518480SRobin Gong 		break;
778f2518480SRobin Gong 	case PFUZE100:
779f2518480SRobin Gong 	default:
78012425654SFabio Estevam 		pfuze_chip->pfuze_regulators = pfuze100_regulators;
781f2518480SRobin Gong 		regulator_num = ARRAY_SIZE(pfuze100_regulators);
782f2518480SRobin Gong 		sw_check_start = PFUZE100_SW2;
783f2518480SRobin Gong 		sw_check_end = PFUZE100_SW4;
784f2518480SRobin Gong 		break;
785f2518480SRobin Gong 	}
786f2518480SRobin Gong 	dev_info(&client->dev, "pfuze%s found.\n",
787e5a7a72cSRobin Gong 		(pfuze_chip->chip_id == PFUZE100) ? "100" :
788297101abSStefan Wahren 		(((pfuze_chip->chip_id == PFUZE200) ? "200" :
789297101abSStefan Wahren 		((pfuze_chip->chip_id == PFUZE3000) ? "3000" : "3001"))));
790f2518480SRobin Gong 
79112425654SFabio Estevam 	memcpy(pfuze_chip->regulator_descs, pfuze_chip->pfuze_regulators,
792f2518480SRobin Gong 		sizeof(pfuze_chip->regulator_descs));
793f2518480SRobin Gong 
7943784b6d6SRobin Gong 	ret = pfuze_parse_regulators_dt(pfuze_chip);
7953784b6d6SRobin Gong 	if (ret)
7963784b6d6SRobin Gong 		return ret;
7973784b6d6SRobin Gong 
798f2518480SRobin Gong 	for (i = 0; i < regulator_num; i++) {
7993784b6d6SRobin Gong 		struct regulator_init_data *init_data;
800d9493234SAxel Lin 		struct regulator_desc *desc;
8013784b6d6SRobin Gong 		int val;
8023784b6d6SRobin Gong 
803d9493234SAxel Lin 		desc = &pfuze_chip->regulator_descs[i].desc;
804d9493234SAxel Lin 
8053784b6d6SRobin Gong 		if (pdata)
8063784b6d6SRobin Gong 			init_data = pdata->init_data[i];
8073784b6d6SRobin Gong 		else
8083784b6d6SRobin Gong 			init_data = match_init_data(i);
8093784b6d6SRobin Gong 
8103784b6d6SRobin Gong 		/* SW2~SW4 high bit check and modify the voltage value table */
811f2518480SRobin Gong 		if (i >= sw_check_start && i <= sw_check_end) {
8121252b283SYizhuo 			ret = regmap_read(pfuze_chip->regmap,
8131252b283SYizhuo 						desc->vsel_reg, &val);
8141252b283SYizhuo 			if (ret) {
8151252b283SYizhuo 				dev_err(&client->dev, "Fails to read from the register.\n");
8161252b283SYizhuo 				return ret;
8171252b283SYizhuo 			}
8181252b283SYizhuo 
819e5a7a72cSRobin Gong 			if (val & sw_hi) {
820297101abSStefan Wahren 				if (pfuze_chip->chip_id == PFUZE3000 ||
821297101abSStefan Wahren 					pfuze_chip->chip_id == PFUZE3001) {
822e5a7a72cSRobin Gong 					desc->volt_table = pfuze3000_sw2hi;
823e5a7a72cSRobin Gong 					desc->n_voltages = ARRAY_SIZE(pfuze3000_sw2hi);
824e5a7a72cSRobin Gong 				} else {
825d9493234SAxel Lin 					desc->min_uV = 800000;
826d9493234SAxel Lin 					desc->uV_step = 50000;
827d9493234SAxel Lin 					desc->n_voltages = 51;
8283784b6d6SRobin Gong 				}
8293784b6d6SRobin Gong 			}
830e5a7a72cSRobin Gong 		}
8313784b6d6SRobin Gong 
8329d2fd4f0SMarco Felsch 		/*
8339d2fd4f0SMarco Felsch 		 * Allow SW regulators to turn off. Checking it trough a flag is
8349d2fd4f0SMarco Felsch 		 * a workaround to keep the backward compatibility with existing
8359d2fd4f0SMarco Felsch 		 * old dtb's which may relay on the fact that we didn't disable
8369d2fd4f0SMarco Felsch 		 * the switched regulator till yet.
8379d2fd4f0SMarco Felsch 		 */
8389d2fd4f0SMarco Felsch 		if (pfuze_chip->flags & PFUZE_FLAG_DISABLE_SW) {
8399d2fd4f0SMarco Felsch 			if (pfuze_chip->regulator_descs[i].sw_reg) {
8409d2fd4f0SMarco Felsch 				desc->ops = &pfuze100_sw_disable_regulator_ops;
8419d2fd4f0SMarco Felsch 				desc->enable_val = 0x8;
8429d2fd4f0SMarco Felsch 				desc->disable_val = 0x0;
8439d2fd4f0SMarco Felsch 				desc->enable_time = 500;
8449d2fd4f0SMarco Felsch 			}
8459d2fd4f0SMarco Felsch 		}
8469d2fd4f0SMarco Felsch 
8473784b6d6SRobin Gong 		config.dev = &client->dev;
8483784b6d6SRobin Gong 		config.init_data = init_data;
8493784b6d6SRobin Gong 		config.driver_data = pfuze_chip;
8503784b6d6SRobin Gong 		config.of_node = match_of_node(i);
8513784b6d6SRobin Gong 
852f5247b40SJingoo Han 		pfuze_chip->regulators[i] =
853f5247b40SJingoo Han 			devm_regulator_register(&client->dev, desc, &config);
8543784b6d6SRobin Gong 		if (IS_ERR(pfuze_chip->regulators[i])) {
8553784b6d6SRobin Gong 			dev_err(&client->dev, "register regulator%s failed\n",
85612425654SFabio Estevam 				pfuze_chip->pfuze_regulators[i].desc.name);
857f5247b40SJingoo Han 			return PTR_ERR(pfuze_chip->regulators[i]);
8583784b6d6SRobin Gong 		}
8593784b6d6SRobin Gong 	}
8603784b6d6SRobin Gong 
861c29daffaSOleksij Rempel 	if (of_property_read_bool(client->dev.of_node,
862c29daffaSOleksij Rempel 				  "fsl,pmic-stby-poweroff"))
863c29daffaSOleksij Rempel 		return pfuze_power_off_prepare_init(pfuze_chip);
864c29daffaSOleksij Rempel 
865c29daffaSOleksij Rempel 	return 0;
866c29daffaSOleksij Rempel }
867c29daffaSOleksij Rempel 
868c29daffaSOleksij Rempel static int pfuze100_regulator_remove(struct i2c_client *client)
869c29daffaSOleksij Rempel {
870c29daffaSOleksij Rempel 	if (syspm_pfuze_chip) {
871c29daffaSOleksij Rempel 		syspm_pfuze_chip = NULL;
872c29daffaSOleksij Rempel 		pm_power_off_prepare = NULL;
873c29daffaSOleksij Rempel 	}
874c29daffaSOleksij Rempel 
8753784b6d6SRobin Gong 	return 0;
8763784b6d6SRobin Gong }
8773784b6d6SRobin Gong 
8783784b6d6SRobin Gong static struct i2c_driver pfuze_driver = {
8793784b6d6SRobin Gong 	.id_table = pfuze_device_id,
8803784b6d6SRobin Gong 	.driver = {
8813784b6d6SRobin Gong 		.name = "pfuze100-regulator",
8823784b6d6SRobin Gong 		.of_match_table = pfuze_dt_ids,
8833784b6d6SRobin Gong 	},
8843784b6d6SRobin Gong 	.probe = pfuze100_regulator_probe,
885c29daffaSOleksij Rempel 	.remove = pfuze100_regulator_remove,
8863784b6d6SRobin Gong };
8873784b6d6SRobin Gong module_i2c_driver(pfuze_driver);
8883784b6d6SRobin Gong 
8893784b6d6SRobin Gong MODULE_AUTHOR("Robin Gong <b38343@freescale.com>");
890297101abSStefan Wahren MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/200/3000/3001 PMIC");
89112d20fc2SRobin Gong MODULE_LICENSE("GPL v2");
892