xref: /linux/drivers/regulator/da9052-regulator.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
1fd2f02f9SAxel Lin // SPDX-License-Identifier: GPL-2.0+
2fd2f02f9SAxel Lin //
3fd2f02f9SAxel Lin // da9052-regulator.c: Regulator driver for DA9052
4fd2f02f9SAxel Lin //
5fd2f02f9SAxel Lin // Copyright(c) 2011 Dialog Semiconductor Ltd.
6fd2f02f9SAxel Lin //
7fd2f02f9SAxel Lin // Author: David Dajun Chen <dchen@diasemi.com>
808bf1c0aSAshish Jangam 
908bf1c0aSAshish Jangam #include <linux/module.h>
1008bf1c0aSAshish Jangam #include <linux/moduleparam.h>
1108bf1c0aSAshish Jangam #include <linux/init.h>
1208bf1c0aSAshish Jangam #include <linux/err.h>
1308bf1c0aSAshish Jangam #include <linux/platform_device.h>
1408bf1c0aSAshish Jangam #include <linux/regulator/driver.h>
1508bf1c0aSAshish Jangam #include <linux/regulator/machine.h>
16cd22a965SMark Brown #include <linux/of.h>
1788c84c14SYing-Chun Liu (PaulLiu) #include <linux/regulator/of_regulator.h>
1808bf1c0aSAshish Jangam 
1908bf1c0aSAshish Jangam #include <linux/mfd/da9052/da9052.h>
2008bf1c0aSAshish Jangam #include <linux/mfd/da9052/reg.h>
2108bf1c0aSAshish Jangam #include <linux/mfd/da9052/pdata.h>
2208bf1c0aSAshish Jangam 
2308bf1c0aSAshish Jangam /* Buck step size */
2408bf1c0aSAshish Jangam #define DA9052_BUCK_PERI_3uV_STEP		100000
2508bf1c0aSAshish Jangam #define DA9052_BUCK_PERI_REG_MAP_UPTO_3uV	24
2608bf1c0aSAshish Jangam #define DA9052_CONST_3uV			3000000
2708bf1c0aSAshish Jangam 
2808bf1c0aSAshish Jangam #define DA9052_MIN_UA		0
2908bf1c0aSAshish Jangam #define DA9052_MAX_UA		3
3008bf1c0aSAshish Jangam #define DA9052_CURRENT_RANGE	4
3108bf1c0aSAshish Jangam 
3208bf1c0aSAshish Jangam /* Bit masks */
3308bf1c0aSAshish Jangam #define DA9052_BUCK_ILIM_MASK_EVEN	0x0c
3408bf1c0aSAshish Jangam #define DA9052_BUCK_ILIM_MASK_ODD	0xc0
3508bf1c0aSAshish Jangam 
369210f05bSAxel Lin /* DA9052 REGULATOR IDs */
379210f05bSAxel Lin #define DA9052_ID_BUCK1		0
389210f05bSAxel Lin #define DA9052_ID_BUCK2		1
399210f05bSAxel Lin #define DA9052_ID_BUCK3		2
409210f05bSAxel Lin #define DA9052_ID_BUCK4		3
419210f05bSAxel Lin #define DA9052_ID_LDO1		4
429210f05bSAxel Lin #define DA9052_ID_LDO2		5
439210f05bSAxel Lin #define DA9052_ID_LDO3		6
449210f05bSAxel Lin #define DA9052_ID_LDO4		7
459210f05bSAxel Lin #define DA9052_ID_LDO5		8
469210f05bSAxel Lin #define DA9052_ID_LDO6		9
479210f05bSAxel Lin #define DA9052_ID_LDO7		10
489210f05bSAxel Lin #define DA9052_ID_LDO8		11
499210f05bSAxel Lin #define DA9052_ID_LDO9		12
509210f05bSAxel Lin #define DA9052_ID_LDO10		13
519210f05bSAxel Lin 
5208bf1c0aSAshish Jangam static const u32 da9052_current_limits[3][4] = {
5308bf1c0aSAshish Jangam 	{700000, 800000, 1000000, 1200000},	/* DA9052-BC BUCKs */
5408bf1c0aSAshish Jangam 	{1600000, 2000000, 2400000, 3000000},	/* DA9053-AA/Bx BUCK-CORE */
5508bf1c0aSAshish Jangam 	{800000, 1000000, 1200000, 1500000},	/* DA9053-AA/Bx BUCK-PRO,
5608bf1c0aSAshish Jangam 						 * BUCK-MEM and BUCK-PERI
5708bf1c0aSAshish Jangam 						*/
5808bf1c0aSAshish Jangam };
5908bf1c0aSAshish Jangam 
6008bf1c0aSAshish Jangam struct da9052_regulator_info {
6108bf1c0aSAshish Jangam 	struct regulator_desc reg_desc;
6208bf1c0aSAshish Jangam 	int step_uV;
6308bf1c0aSAshish Jangam 	int min_uV;
6408bf1c0aSAshish Jangam 	int max_uV;
65d706b1e4SAxel Lin 	unsigned char activate_bit;
6608bf1c0aSAshish Jangam };
6708bf1c0aSAshish Jangam 
6808bf1c0aSAshish Jangam struct da9052_regulator {
6908bf1c0aSAshish Jangam 	struct da9052 *da9052;
70*9653007eSKrzysztof Kozlowski 	const struct da9052_regulator_info *info;
7108bf1c0aSAshish Jangam 	struct regulator_dev *rdev;
7208bf1c0aSAshish Jangam };
7308bf1c0aSAshish Jangam 
verify_range(const struct da9052_regulator_info * info,int min_uV,int max_uV)74*9653007eSKrzysztof Kozlowski static int verify_range(const struct da9052_regulator_info *info,
7508bf1c0aSAshish Jangam 			 int min_uV, int max_uV)
7608bf1c0aSAshish Jangam {
7708bf1c0aSAshish Jangam 	if (min_uV > info->max_uV || max_uV < info->min_uV)
7808bf1c0aSAshish Jangam 		return -EINVAL;
7908bf1c0aSAshish Jangam 
8008bf1c0aSAshish Jangam 	return 0;
8108bf1c0aSAshish Jangam }
8208bf1c0aSAshish Jangam 
da9052_dcdc_get_current_limit(struct regulator_dev * rdev)8308bf1c0aSAshish Jangam static int da9052_dcdc_get_current_limit(struct regulator_dev *rdev)
8408bf1c0aSAshish Jangam {
8508bf1c0aSAshish Jangam 	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
8608bf1c0aSAshish Jangam 	int offset = rdev_get_id(rdev);
8708bf1c0aSAshish Jangam 	int ret, row = 2;
8808bf1c0aSAshish Jangam 
8908bf1c0aSAshish Jangam 	ret = da9052_reg_read(regulator->da9052, DA9052_BUCKA_REG + offset/2);
9008bf1c0aSAshish Jangam 	if (ret < 0)
9108bf1c0aSAshish Jangam 		return ret;
9208bf1c0aSAshish Jangam 
9308bf1c0aSAshish Jangam 	/* Determine the even or odd position of the buck current limit
9408bf1c0aSAshish Jangam 	 * register field
9508bf1c0aSAshish Jangam 	*/
9608bf1c0aSAshish Jangam 	if (offset % 2 == 0)
9708bf1c0aSAshish Jangam 		ret = (ret & DA9052_BUCK_ILIM_MASK_EVEN) >> 2;
9808bf1c0aSAshish Jangam 	else
9908bf1c0aSAshish Jangam 		ret = (ret & DA9052_BUCK_ILIM_MASK_ODD) >> 6;
10008bf1c0aSAshish Jangam 
10108bf1c0aSAshish Jangam 	/* Select the appropriate current limit range */
10208bf1c0aSAshish Jangam 	if (regulator->da9052->chip_id == DA9052)
10308bf1c0aSAshish Jangam 		row = 0;
10408bf1c0aSAshish Jangam 	else if (offset == 0)
10508bf1c0aSAshish Jangam 		row = 1;
10608bf1c0aSAshish Jangam 
10708bf1c0aSAshish Jangam 	return da9052_current_limits[row][ret];
10808bf1c0aSAshish Jangam }
10908bf1c0aSAshish Jangam 
da9052_dcdc_set_current_limit(struct regulator_dev * rdev,int min_uA,int max_uA)11008bf1c0aSAshish Jangam static int da9052_dcdc_set_current_limit(struct regulator_dev *rdev, int min_uA,
11108bf1c0aSAshish Jangam 					  int max_uA)
11208bf1c0aSAshish Jangam {
11308bf1c0aSAshish Jangam 	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
11408bf1c0aSAshish Jangam 	int offset = rdev_get_id(rdev);
11508bf1c0aSAshish Jangam 	int reg_val = 0;
11608bf1c0aSAshish Jangam 	int i, row = 2;
11708bf1c0aSAshish Jangam 
11808bf1c0aSAshish Jangam 	/* Select the appropriate current limit range */
11908bf1c0aSAshish Jangam 	if (regulator->da9052->chip_id == DA9052)
12008bf1c0aSAshish Jangam 		row = 0;
12108bf1c0aSAshish Jangam 	else if (offset == 0)
12208bf1c0aSAshish Jangam 		row = 1;
12308bf1c0aSAshish Jangam 
12419d23c21SAxel Lin 	for (i = DA9052_CURRENT_RANGE - 1; i >= 0; i--) {
1251e369bcdSAxel Lin 		if ((min_uA <= da9052_current_limits[row][i]) &&
1261e369bcdSAxel Lin 		    (da9052_current_limits[row][i] <= max_uA)) {
12708bf1c0aSAshish Jangam 			reg_val = i;
12808bf1c0aSAshish Jangam 			break;
12908bf1c0aSAshish Jangam 		}
13008bf1c0aSAshish Jangam 	}
13108bf1c0aSAshish Jangam 
1321e369bcdSAxel Lin 	if (i < 0)
1331e369bcdSAxel Lin 		return -EINVAL;
1341e369bcdSAxel Lin 
13508bf1c0aSAshish Jangam 	/* Determine the even or odd position of the buck current limit
13608bf1c0aSAshish Jangam 	 * register field
13708bf1c0aSAshish Jangam 	*/
13808bf1c0aSAshish Jangam 	if (offset % 2 == 0)
13908bf1c0aSAshish Jangam 		return da9052_reg_update(regulator->da9052,
14008bf1c0aSAshish Jangam 					 DA9052_BUCKA_REG + offset/2,
14108bf1c0aSAshish Jangam 					 DA9052_BUCK_ILIM_MASK_EVEN,
14208bf1c0aSAshish Jangam 					 reg_val << 2);
14308bf1c0aSAshish Jangam 	else
14408bf1c0aSAshish Jangam 		return da9052_reg_update(regulator->da9052,
14508bf1c0aSAshish Jangam 					 DA9052_BUCKA_REG + offset/2,
14608bf1c0aSAshish Jangam 					 DA9052_BUCK_ILIM_MASK_ODD,
14708bf1c0aSAshish Jangam 					 reg_val << 6);
14808bf1c0aSAshish Jangam }
14908bf1c0aSAshish Jangam 
da9052_list_voltage(struct regulator_dev * rdev,unsigned int selector)15008bf1c0aSAshish Jangam static int da9052_list_voltage(struct regulator_dev *rdev,
15108bf1c0aSAshish Jangam 				unsigned int selector)
15208bf1c0aSAshish Jangam {
15308bf1c0aSAshish Jangam 	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
154*9653007eSKrzysztof Kozlowski 	const struct da9052_regulator_info *info = regulator->info;
1550ec446eaSAxel Lin 	int id = rdev_get_id(rdev);
15608bf1c0aSAshish Jangam 	int volt_uV;
15708bf1c0aSAshish Jangam 
1580ec446eaSAxel Lin 	if ((id == DA9052_ID_BUCK4) && (regulator->da9052->chip_id == DA9052)
1590ec446eaSAxel Lin 		&& (selector >= DA9052_BUCK_PERI_REG_MAP_UPTO_3uV)) {
1600ec446eaSAxel Lin 		volt_uV = ((DA9052_BUCK_PERI_REG_MAP_UPTO_3uV * info->step_uV)
1610ec446eaSAxel Lin 			  + info->min_uV);
1620ec446eaSAxel Lin 		volt_uV += (selector - DA9052_BUCK_PERI_REG_MAP_UPTO_3uV)
1630ec446eaSAxel Lin 				    * (DA9052_BUCK_PERI_3uV_STEP);
1640ec446eaSAxel Lin 	} else {
1650ec446eaSAxel Lin 		volt_uV = (selector * info->step_uV) + info->min_uV;
1660ec446eaSAxel Lin 	}
16708bf1c0aSAshish Jangam 
16808bf1c0aSAshish Jangam 	if (volt_uV > info->max_uV)
16908bf1c0aSAshish Jangam 		return -EINVAL;
17008bf1c0aSAshish Jangam 
17108bf1c0aSAshish Jangam 	return volt_uV;
17208bf1c0aSAshish Jangam }
17308bf1c0aSAshish Jangam 
da9052_map_voltage(struct regulator_dev * rdev,int min_uV,int max_uV)1744923b48bSAxel Lin static int da9052_map_voltage(struct regulator_dev *rdev,
1754923b48bSAxel Lin 			      int min_uV, int max_uV)
17608bf1c0aSAshish Jangam {
17708bf1c0aSAshish Jangam 	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
178*9653007eSKrzysztof Kozlowski 	const struct da9052_regulator_info *info = regulator->info;
1790ec446eaSAxel Lin 	int id = rdev_get_id(rdev);
1804923b48bSAxel Lin 	int ret, sel;
18108bf1c0aSAshish Jangam 
18208bf1c0aSAshish Jangam 	ret = verify_range(info, min_uV, max_uV);
18308bf1c0aSAshish Jangam 	if (ret < 0)
18408bf1c0aSAshish Jangam 		return ret;
18508bf1c0aSAshish Jangam 
18608bf1c0aSAshish Jangam 	if (min_uV < info->min_uV)
18708bf1c0aSAshish Jangam 		min_uV = info->min_uV;
18808bf1c0aSAshish Jangam 
1890ec446eaSAxel Lin 	if ((id == DA9052_ID_BUCK4) && (regulator->da9052->chip_id == DA9052)
1900ec446eaSAxel Lin 		&& (min_uV >= DA9052_CONST_3uV)) {
1914923b48bSAxel Lin 			sel = DA9052_BUCK_PERI_REG_MAP_UPTO_3uV +
1920ec446eaSAxel Lin 			      DIV_ROUND_UP(min_uV - DA9052_CONST_3uV,
1930ec446eaSAxel Lin 					   DA9052_BUCK_PERI_3uV_STEP);
1940ec446eaSAxel Lin 	} else {
1954923b48bSAxel Lin 		sel = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
1960ec446eaSAxel Lin 	}
19708bf1c0aSAshish Jangam 
1984923b48bSAxel Lin 	ret = da9052_list_voltage(rdev, sel);
19908bf1c0aSAshish Jangam 	if (ret < 0)
20008bf1c0aSAshish Jangam 		return ret;
20108bf1c0aSAshish Jangam 
2024923b48bSAxel Lin 	return sel;
2034923b48bSAxel Lin }
2044923b48bSAxel Lin 
da9052_regulator_set_voltage_sel(struct regulator_dev * rdev,unsigned int selector)205d706b1e4SAxel Lin static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev,
206d706b1e4SAxel Lin 					    unsigned int selector)
207d706b1e4SAxel Lin {
208d706b1e4SAxel Lin 	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
209*9653007eSKrzysztof Kozlowski 	const struct da9052_regulator_info *info = regulator->info;
210d706b1e4SAxel Lin 	int id = rdev_get_id(rdev);
211d706b1e4SAxel Lin 	int ret;
212d706b1e4SAxel Lin 
213d706b1e4SAxel Lin 	ret = da9052_reg_update(regulator->da9052, rdev->desc->vsel_reg,
214d706b1e4SAxel Lin 				rdev->desc->vsel_mask, selector);
215d706b1e4SAxel Lin 	if (ret < 0)
216d706b1e4SAxel Lin 		return ret;
217d706b1e4SAxel Lin 
218d706b1e4SAxel Lin 	/* Some LDOs and DCDCs are DVC controlled which requires enabling of
219d706b1e4SAxel Lin 	 * the activate bit to implment the changes on the output.
220d706b1e4SAxel Lin 	 */
221d706b1e4SAxel Lin 	switch (id) {
222d706b1e4SAxel Lin 	case DA9052_ID_BUCK1:
223d706b1e4SAxel Lin 	case DA9052_ID_BUCK2:
224d706b1e4SAxel Lin 	case DA9052_ID_BUCK3:
225d706b1e4SAxel Lin 	case DA9052_ID_LDO2:
226d706b1e4SAxel Lin 	case DA9052_ID_LDO3:
227d706b1e4SAxel Lin 		ret = da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG,
228d706b1e4SAxel Lin 					info->activate_bit, info->activate_bit);
229d706b1e4SAxel Lin 		break;
230d706b1e4SAxel Lin 	}
231d706b1e4SAxel Lin 
232d706b1e4SAxel Lin 	return ret;
233d706b1e4SAxel Lin }
234d706b1e4SAxel Lin 
da9052_regulator_set_voltage_time_sel(struct regulator_dev * rdev,unsigned int old_sel,unsigned int new_sel)2355c99a7b1SPhilipp Zabel static int da9052_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
2365c99a7b1SPhilipp Zabel 						 unsigned int old_sel,
2375c99a7b1SPhilipp Zabel 						 unsigned int new_sel)
2385c99a7b1SPhilipp Zabel {
2395c99a7b1SPhilipp Zabel 	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
240*9653007eSKrzysztof Kozlowski 	const struct da9052_regulator_info *info = regulator->info;
2415c99a7b1SPhilipp Zabel 	int id = rdev_get_id(rdev);
2425c99a7b1SPhilipp Zabel 	int ret = 0;
2435c99a7b1SPhilipp Zabel 
2445c99a7b1SPhilipp Zabel 	/* The DVC controlled LDOs and DCDCs ramp with 6.25mV/µs after enabling
2455c99a7b1SPhilipp Zabel 	 * the activate bit.
2465c99a7b1SPhilipp Zabel 	 */
2475c99a7b1SPhilipp Zabel 	switch (id) {
2485c99a7b1SPhilipp Zabel 	case DA9052_ID_BUCK1:
2495c99a7b1SPhilipp Zabel 	case DA9052_ID_BUCK2:
2505c99a7b1SPhilipp Zabel 	case DA9052_ID_BUCK3:
2515c99a7b1SPhilipp Zabel 	case DA9052_ID_LDO2:
2525c99a7b1SPhilipp Zabel 	case DA9052_ID_LDO3:
253a336dc8fSAxel Lin 		ret = DIV_ROUND_UP(abs(new_sel - old_sel) * info->step_uV,
254a336dc8fSAxel Lin 				   6250);
2555c99a7b1SPhilipp Zabel 		break;
2565c99a7b1SPhilipp Zabel 	}
2575c99a7b1SPhilipp Zabel 
2585c99a7b1SPhilipp Zabel 	return ret;
2595c99a7b1SPhilipp Zabel }
2605c99a7b1SPhilipp Zabel 
26171242b49SJulia Lawall static const struct regulator_ops da9052_dcdc_ops = {
26208bf1c0aSAshish Jangam 	.get_current_limit = da9052_dcdc_get_current_limit,
26308bf1c0aSAshish Jangam 	.set_current_limit = da9052_dcdc_set_current_limit,
26408bf1c0aSAshish Jangam 
26508bf1c0aSAshish Jangam 	.list_voltage = da9052_list_voltage,
2664923b48bSAxel Lin 	.map_voltage = da9052_map_voltage,
26709812bc4SAxel Lin 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
268d706b1e4SAxel Lin 	.set_voltage_sel = da9052_regulator_set_voltage_sel,
2695c99a7b1SPhilipp Zabel 	.set_voltage_time_sel = da9052_regulator_set_voltage_time_sel,
2700d481f74SAxel Lin 	.is_enabled = regulator_is_enabled_regmap,
2710d481f74SAxel Lin 	.enable = regulator_enable_regmap,
2720d481f74SAxel Lin 	.disable = regulator_disable_regmap,
27308bf1c0aSAshish Jangam };
27408bf1c0aSAshish Jangam 
27571242b49SJulia Lawall static const struct regulator_ops da9052_ldo_ops = {
27608bf1c0aSAshish Jangam 	.list_voltage = da9052_list_voltage,
2774923b48bSAxel Lin 	.map_voltage = da9052_map_voltage,
27809812bc4SAxel Lin 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
279d706b1e4SAxel Lin 	.set_voltage_sel = da9052_regulator_set_voltage_sel,
2805c99a7b1SPhilipp Zabel 	.set_voltage_time_sel = da9052_regulator_set_voltage_time_sel,
2810d481f74SAxel Lin 	.is_enabled = regulator_is_enabled_regmap,
2820d481f74SAxel Lin 	.enable = regulator_enable_regmap,
2830d481f74SAxel Lin 	.disable = regulator_disable_regmap,
28408bf1c0aSAshish Jangam };
28508bf1c0aSAshish Jangam 
28645460fe9SRob Herring #define DA9052_LDO(_id, _name, step, min, max, sbits, ebits, abits) \
28708bf1c0aSAshish Jangam {\
28808bf1c0aSAshish Jangam 	.reg_desc = {\
28945460fe9SRob Herring 		.name = #_name,\
29067ddc68aSAxel Lin 		.of_match = of_match_ptr(#_name),\
29167ddc68aSAxel Lin 		.regulators_node = of_match_ptr("regulators"),\
29208bf1c0aSAshish Jangam 		.ops = &da9052_ldo_ops,\
29308bf1c0aSAshish Jangam 		.type = REGULATOR_VOLTAGE,\
2949210f05bSAxel Lin 		.id = DA9052_ID_##_id,\
2957b957654SAxel Lin 		.n_voltages = (max - min) / step + 1, \
29608bf1c0aSAshish Jangam 		.owner = THIS_MODULE,\
29709812bc4SAxel Lin 		.vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
29809812bc4SAxel Lin 		.vsel_mask = (1 << (sbits)) - 1,\
2990d481f74SAxel Lin 		.enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
3000d481f74SAxel Lin 		.enable_mask = 1 << (ebits),\
30108bf1c0aSAshish Jangam 	},\
30208bf1c0aSAshish Jangam 	.min_uV = (min) * 1000,\
30308bf1c0aSAshish Jangam 	.max_uV = (max) * 1000,\
30408bf1c0aSAshish Jangam 	.step_uV = (step) * 1000,\
305d706b1e4SAxel Lin 	.activate_bit = (abits),\
30608bf1c0aSAshish Jangam }
30708bf1c0aSAshish Jangam 
30845460fe9SRob Herring #define DA9052_DCDC(_id, _name, step, min, max, sbits, ebits, abits) \
30908bf1c0aSAshish Jangam {\
31008bf1c0aSAshish Jangam 	.reg_desc = {\
31145460fe9SRob Herring 		.name = #_name,\
31267ddc68aSAxel Lin 		.of_match = of_match_ptr(#_name),\
31367ddc68aSAxel Lin 		.regulators_node = of_match_ptr("regulators"),\
31408bf1c0aSAshish Jangam 		.ops = &da9052_dcdc_ops,\
31508bf1c0aSAshish Jangam 		.type = REGULATOR_VOLTAGE,\
3169210f05bSAxel Lin 		.id = DA9052_ID_##_id,\
3177b957654SAxel Lin 		.n_voltages = (max - min) / step + 1, \
31808bf1c0aSAshish Jangam 		.owner = THIS_MODULE,\
31909812bc4SAxel Lin 		.vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
32009812bc4SAxel Lin 		.vsel_mask = (1 << (sbits)) - 1,\
3210d481f74SAxel Lin 		.enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
3220d481f74SAxel Lin 		.enable_mask = 1 << (ebits),\
32308bf1c0aSAshish Jangam 	},\
32408bf1c0aSAshish Jangam 	.min_uV = (min) * 1000,\
32508bf1c0aSAshish Jangam 	.max_uV = (max) * 1000,\
32608bf1c0aSAshish Jangam 	.step_uV = (step) * 1000,\
327d706b1e4SAxel Lin 	.activate_bit = (abits),\
32808bf1c0aSAshish Jangam }
32908bf1c0aSAshish Jangam 
330*9653007eSKrzysztof Kozlowski static const struct da9052_regulator_info da9052_regulator_info[] = {
33145460fe9SRob Herring 	DA9052_DCDC(BUCK1, buck1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO),
33245460fe9SRob Herring 	DA9052_DCDC(BUCK2, buck2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO),
33345460fe9SRob Herring 	DA9052_DCDC(BUCK3, buck3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO),
33445460fe9SRob Herring 	DA9052_DCDC(BUCK4, buck4, 50, 1800, 3600, 5, 6, 0),
33545460fe9SRob Herring 	DA9052_LDO(LDO1, ldo1, 50, 600, 1800, 5, 6, 0),
33645460fe9SRob Herring 	DA9052_LDO(LDO2, ldo2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO),
33745460fe9SRob Herring 	DA9052_LDO(LDO3, ldo3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO),
33845460fe9SRob Herring 	DA9052_LDO(LDO4, ldo4, 25, 1725, 3300, 6, 6, 0),
33945460fe9SRob Herring 	DA9052_LDO(LDO5, ldo5, 50, 1200, 3600, 6, 6, 0),
34045460fe9SRob Herring 	DA9052_LDO(LDO6, ldo6, 50, 1200, 3600, 6, 6, 0),
34145460fe9SRob Herring 	DA9052_LDO(LDO7, ldo7, 50, 1200, 3600, 6, 6, 0),
34245460fe9SRob Herring 	DA9052_LDO(LDO8, ldo8, 50, 1200, 3600, 6, 6, 0),
34345460fe9SRob Herring 	DA9052_LDO(LDO9, ldo9, 50, 1250, 3650, 6, 6, 0),
34445460fe9SRob Herring 	DA9052_LDO(LDO10, ldo10, 50, 1200, 3600, 6, 6, 0),
34508bf1c0aSAshish Jangam };
34608bf1c0aSAshish Jangam 
347*9653007eSKrzysztof Kozlowski static const struct da9052_regulator_info da9053_regulator_info[] = {
34845460fe9SRob Herring 	DA9052_DCDC(BUCK1, buck1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO),
34945460fe9SRob Herring 	DA9052_DCDC(BUCK2, buck2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO),
35045460fe9SRob Herring 	DA9052_DCDC(BUCK3, buck3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO),
35145460fe9SRob Herring 	DA9052_DCDC(BUCK4, buck4, 25, 950, 2525, 6, 6, 0),
35245460fe9SRob Herring 	DA9052_LDO(LDO1, ldo1, 50, 600, 1800, 5, 6, 0),
35345460fe9SRob Herring 	DA9052_LDO(LDO2, ldo2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO),
35445460fe9SRob Herring 	DA9052_LDO(LDO3, ldo3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO),
35545460fe9SRob Herring 	DA9052_LDO(LDO4, ldo4, 25, 1725, 3300, 6, 6, 0),
35645460fe9SRob Herring 	DA9052_LDO(LDO5, ldo5, 50, 1200, 3600, 6, 6, 0),
35745460fe9SRob Herring 	DA9052_LDO(LDO6, ldo6, 50, 1200, 3600, 6, 6, 0),
35845460fe9SRob Herring 	DA9052_LDO(LDO7, ldo7, 50, 1200, 3600, 6, 6, 0),
35945460fe9SRob Herring 	DA9052_LDO(LDO8, ldo8, 50, 1200, 3600, 6, 6, 0),
36045460fe9SRob Herring 	DA9052_LDO(LDO9, ldo9, 50, 1250, 3650, 6, 6, 0),
36145460fe9SRob Herring 	DA9052_LDO(LDO10, ldo10, 50, 1200, 3600, 6, 6, 0),
36208bf1c0aSAshish Jangam };
36308bf1c0aSAshish Jangam 
find_regulator_info(u8 chip_id,int id)364*9653007eSKrzysztof Kozlowski static inline const struct da9052_regulator_info *find_regulator_info(u8 chip_id,
36508bf1c0aSAshish Jangam 								      int id)
36608bf1c0aSAshish Jangam {
367*9653007eSKrzysztof Kozlowski 	const struct da9052_regulator_info *info;
36808bf1c0aSAshish Jangam 	int i;
36908bf1c0aSAshish Jangam 
370984b5a6bSAshish Jangam 	switch (chip_id) {
371984b5a6bSAshish Jangam 	case DA9052:
37208bf1c0aSAshish Jangam 		for (i = 0; i < ARRAY_SIZE(da9052_regulator_info); i++) {
37308bf1c0aSAshish Jangam 			info = &da9052_regulator_info[i];
37408bf1c0aSAshish Jangam 			if (info->reg_desc.id == id)
37508bf1c0aSAshish Jangam 				return info;
37608bf1c0aSAshish Jangam 		}
377984b5a6bSAshish Jangam 		break;
378984b5a6bSAshish Jangam 	case DA9053_AA:
379984b5a6bSAshish Jangam 	case DA9053_BA:
380984b5a6bSAshish Jangam 	case DA9053_BB:
3818b708144SSteve Twiss 	case DA9053_BC:
38208bf1c0aSAshish Jangam 		for (i = 0; i < ARRAY_SIZE(da9053_regulator_info); i++) {
38308bf1c0aSAshish Jangam 			info = &da9053_regulator_info[i];
38408bf1c0aSAshish Jangam 			if (info->reg_desc.id == id)
38508bf1c0aSAshish Jangam 				return info;
38608bf1c0aSAshish Jangam 		}
387984b5a6bSAshish Jangam 		break;
38808bf1c0aSAshish Jangam 	}
38908bf1c0aSAshish Jangam 
39008bf1c0aSAshish Jangam 	return NULL;
39108bf1c0aSAshish Jangam }
39208bf1c0aSAshish Jangam 
da9052_regulator_probe(struct platform_device * pdev)393a5023574SBill Pemberton static int da9052_regulator_probe(struct platform_device *pdev)
39408bf1c0aSAshish Jangam {
395e0c21530SJohan Hovold 	const struct mfd_cell *cell = mfd_get_cell(pdev);
396c172708dSMark Brown 	struct regulator_config config = { };
39708bf1c0aSAshish Jangam 	struct da9052_regulator *regulator;
39808bf1c0aSAshish Jangam 	struct da9052 *da9052;
39908bf1c0aSAshish Jangam 	struct da9052_pdata *pdata;
40008bf1c0aSAshish Jangam 
401984b5a6bSAshish Jangam 	regulator = devm_kzalloc(&pdev->dev, sizeof(struct da9052_regulator),
402984b5a6bSAshish Jangam 				 GFP_KERNEL);
40308bf1c0aSAshish Jangam 	if (!regulator)
40408bf1c0aSAshish Jangam 		return -ENOMEM;
40508bf1c0aSAshish Jangam 
40608bf1c0aSAshish Jangam 	da9052 = dev_get_drvdata(pdev->dev.parent);
407dff91d0bSJingoo Han 	pdata = dev_get_platdata(da9052->dev);
40808bf1c0aSAshish Jangam 	regulator->da9052 = da9052;
40908bf1c0aSAshish Jangam 
41008bf1c0aSAshish Jangam 	regulator->info = find_regulator_info(regulator->da9052->chip_id,
411e0c21530SJohan Hovold 					      cell->id);
41208bf1c0aSAshish Jangam 	if (regulator->info == NULL) {
41308bf1c0aSAshish Jangam 		dev_err(&pdev->dev, "invalid regulator ID specified\n");
4147eb6444fSAxel Lin 		return -EINVAL;
41508bf1c0aSAshish Jangam 	}
416c172708dSMark Brown 
41767ddc68aSAxel Lin 	config.dev = da9052->dev;
418c172708dSMark Brown 	config.driver_data = regulator;
4190d481f74SAxel Lin 	config.regmap = da9052->regmap;
42067ddc68aSAxel Lin 	if (pdata)
421e0c21530SJohan Hovold 		config.init_data = pdata->regulators[cell->id];
422c172708dSMark Brown 
423ea49a5ebSAxel Lin 	regulator->rdev = devm_regulator_register(&pdev->dev,
424ea49a5ebSAxel Lin 						  &regulator->info->reg_desc,
425c172708dSMark Brown 						  &config);
42608bf1c0aSAshish Jangam 	if (IS_ERR(regulator->rdev)) {
42708bf1c0aSAshish Jangam 		dev_err(&pdev->dev, "failed to register regulator %s\n",
42808bf1c0aSAshish Jangam 			regulator->info->reg_desc.name);
4297eb6444fSAxel Lin 		return PTR_ERR(regulator->rdev);
43008bf1c0aSAshish Jangam 	}
43108bf1c0aSAshish Jangam 
43208bf1c0aSAshish Jangam 	platform_set_drvdata(pdev, regulator);
43308bf1c0aSAshish Jangam 
43408bf1c0aSAshish Jangam 	return 0;
43508bf1c0aSAshish Jangam }
43608bf1c0aSAshish Jangam 
43708bf1c0aSAshish Jangam static struct platform_driver da9052_regulator_driver = {
43808bf1c0aSAshish Jangam 	.probe = da9052_regulator_probe,
43908bf1c0aSAshish Jangam 	.driver = {
44008bf1c0aSAshish Jangam 		.name = "da9052-regulator",
441259b93b2SDouglas Anderson 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
44208bf1c0aSAshish Jangam 	},
44308bf1c0aSAshish Jangam };
44408bf1c0aSAshish Jangam 
da9052_regulator_init(void)44508bf1c0aSAshish Jangam static int __init da9052_regulator_init(void)
44608bf1c0aSAshish Jangam {
44708bf1c0aSAshish Jangam 	return platform_driver_register(&da9052_regulator_driver);
44808bf1c0aSAshish Jangam }
44908bf1c0aSAshish Jangam subsys_initcall(da9052_regulator_init);
45008bf1c0aSAshish Jangam 
da9052_regulator_exit(void)45108bf1c0aSAshish Jangam static void __exit da9052_regulator_exit(void)
45208bf1c0aSAshish Jangam {
45308bf1c0aSAshish Jangam 	platform_driver_unregister(&da9052_regulator_driver);
45408bf1c0aSAshish Jangam }
45508bf1c0aSAshish Jangam module_exit(da9052_regulator_exit);
45608bf1c0aSAshish Jangam 
45708bf1c0aSAshish Jangam MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
45808bf1c0aSAshish Jangam MODULE_DESCRIPTION("Power Regulator driver for Dialog DA9052 PMIC");
45908bf1c0aSAshish Jangam MODULE_LICENSE("GPL");
46008bf1c0aSAshish Jangam MODULE_ALIAS("platform:da9052-regulator");
461