18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// da9052-regulator.c: Regulator driver for DA9052
48c2ecf20Sopenharmony_ci//
58c2ecf20Sopenharmony_ci// Copyright(c) 2011 Dialog Semiconductor Ltd.
68c2ecf20Sopenharmony_ci//
78c2ecf20Sopenharmony_ci// Author: David Dajun Chen <dchen@diasemi.com>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
118c2ecf20Sopenharmony_ci#include <linux/init.h>
128c2ecf20Sopenharmony_ci#include <linux/err.h>
138c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
148c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h>
158c2ecf20Sopenharmony_ci#include <linux/regulator/machine.h>
168c2ecf20Sopenharmony_ci#include <linux/of.h>
178c2ecf20Sopenharmony_ci#include <linux/regulator/of_regulator.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <linux/mfd/da9052/da9052.h>
208c2ecf20Sopenharmony_ci#include <linux/mfd/da9052/reg.h>
218c2ecf20Sopenharmony_ci#include <linux/mfd/da9052/pdata.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/* Buck step size */
248c2ecf20Sopenharmony_ci#define DA9052_BUCK_PERI_3uV_STEP		100000
258c2ecf20Sopenharmony_ci#define DA9052_BUCK_PERI_REG_MAP_UPTO_3uV	24
268c2ecf20Sopenharmony_ci#define DA9052_CONST_3uV			3000000
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define DA9052_MIN_UA		0
298c2ecf20Sopenharmony_ci#define DA9052_MAX_UA		3
308c2ecf20Sopenharmony_ci#define DA9052_CURRENT_RANGE	4
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/* Bit masks */
338c2ecf20Sopenharmony_ci#define DA9052_BUCK_ILIM_MASK_EVEN	0x0c
348c2ecf20Sopenharmony_ci#define DA9052_BUCK_ILIM_MASK_ODD	0xc0
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/* DA9052 REGULATOR IDs */
378c2ecf20Sopenharmony_ci#define DA9052_ID_BUCK1		0
388c2ecf20Sopenharmony_ci#define DA9052_ID_BUCK2		1
398c2ecf20Sopenharmony_ci#define DA9052_ID_BUCK3		2
408c2ecf20Sopenharmony_ci#define DA9052_ID_BUCK4		3
418c2ecf20Sopenharmony_ci#define DA9052_ID_LDO1		4
428c2ecf20Sopenharmony_ci#define DA9052_ID_LDO2		5
438c2ecf20Sopenharmony_ci#define DA9052_ID_LDO3		6
448c2ecf20Sopenharmony_ci#define DA9052_ID_LDO4		7
458c2ecf20Sopenharmony_ci#define DA9052_ID_LDO5		8
468c2ecf20Sopenharmony_ci#define DA9052_ID_LDO6		9
478c2ecf20Sopenharmony_ci#define DA9052_ID_LDO7		10
488c2ecf20Sopenharmony_ci#define DA9052_ID_LDO8		11
498c2ecf20Sopenharmony_ci#define DA9052_ID_LDO9		12
508c2ecf20Sopenharmony_ci#define DA9052_ID_LDO10		13
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic const u32 da9052_current_limits[3][4] = {
538c2ecf20Sopenharmony_ci	{700000, 800000, 1000000, 1200000},	/* DA9052-BC BUCKs */
548c2ecf20Sopenharmony_ci	{1600000, 2000000, 2400000, 3000000},	/* DA9053-AA/Bx BUCK-CORE */
558c2ecf20Sopenharmony_ci	{800000, 1000000, 1200000, 1500000},	/* DA9053-AA/Bx BUCK-PRO,
568c2ecf20Sopenharmony_ci						 * BUCK-MEM and BUCK-PERI
578c2ecf20Sopenharmony_ci						*/
588c2ecf20Sopenharmony_ci};
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistruct da9052_regulator_info {
618c2ecf20Sopenharmony_ci	struct regulator_desc reg_desc;
628c2ecf20Sopenharmony_ci	int step_uV;
638c2ecf20Sopenharmony_ci	int min_uV;
648c2ecf20Sopenharmony_ci	int max_uV;
658c2ecf20Sopenharmony_ci	unsigned char activate_bit;
668c2ecf20Sopenharmony_ci};
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistruct da9052_regulator {
698c2ecf20Sopenharmony_ci	struct da9052 *da9052;
708c2ecf20Sopenharmony_ci	struct da9052_regulator_info *info;
718c2ecf20Sopenharmony_ci	struct regulator_dev *rdev;
728c2ecf20Sopenharmony_ci};
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic int verify_range(struct da9052_regulator_info *info,
758c2ecf20Sopenharmony_ci			 int min_uV, int max_uV)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	if (min_uV > info->max_uV || max_uV < info->min_uV)
788c2ecf20Sopenharmony_ci		return -EINVAL;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	return 0;
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic int da9052_dcdc_get_current_limit(struct regulator_dev *rdev)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
868c2ecf20Sopenharmony_ci	int offset = rdev_get_id(rdev);
878c2ecf20Sopenharmony_ci	int ret, row = 2;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	ret = da9052_reg_read(regulator->da9052, DA9052_BUCKA_REG + offset/2);
908c2ecf20Sopenharmony_ci	if (ret < 0)
918c2ecf20Sopenharmony_ci		return ret;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	/* Determine the even or odd position of the buck current limit
948c2ecf20Sopenharmony_ci	 * register field
958c2ecf20Sopenharmony_ci	*/
968c2ecf20Sopenharmony_ci	if (offset % 2 == 0)
978c2ecf20Sopenharmony_ci		ret = (ret & DA9052_BUCK_ILIM_MASK_EVEN) >> 2;
988c2ecf20Sopenharmony_ci	else
998c2ecf20Sopenharmony_ci		ret = (ret & DA9052_BUCK_ILIM_MASK_ODD) >> 6;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	/* Select the appropriate current limit range */
1028c2ecf20Sopenharmony_ci	if (regulator->da9052->chip_id == DA9052)
1038c2ecf20Sopenharmony_ci		row = 0;
1048c2ecf20Sopenharmony_ci	else if (offset == 0)
1058c2ecf20Sopenharmony_ci		row = 1;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	return da9052_current_limits[row][ret];
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic int da9052_dcdc_set_current_limit(struct regulator_dev *rdev, int min_uA,
1118c2ecf20Sopenharmony_ci					  int max_uA)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
1148c2ecf20Sopenharmony_ci	int offset = rdev_get_id(rdev);
1158c2ecf20Sopenharmony_ci	int reg_val = 0;
1168c2ecf20Sopenharmony_ci	int i, row = 2;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	/* Select the appropriate current limit range */
1198c2ecf20Sopenharmony_ci	if (regulator->da9052->chip_id == DA9052)
1208c2ecf20Sopenharmony_ci		row = 0;
1218c2ecf20Sopenharmony_ci	else if (offset == 0)
1228c2ecf20Sopenharmony_ci		row = 1;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	for (i = DA9052_CURRENT_RANGE - 1; i >= 0; i--) {
1258c2ecf20Sopenharmony_ci		if ((min_uA <= da9052_current_limits[row][i]) &&
1268c2ecf20Sopenharmony_ci		    (da9052_current_limits[row][i] <= max_uA)) {
1278c2ecf20Sopenharmony_ci			reg_val = i;
1288c2ecf20Sopenharmony_ci			break;
1298c2ecf20Sopenharmony_ci		}
1308c2ecf20Sopenharmony_ci	}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	if (i < 0)
1338c2ecf20Sopenharmony_ci		return -EINVAL;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	/* Determine the even or odd position of the buck current limit
1368c2ecf20Sopenharmony_ci	 * register field
1378c2ecf20Sopenharmony_ci	*/
1388c2ecf20Sopenharmony_ci	if (offset % 2 == 0)
1398c2ecf20Sopenharmony_ci		return da9052_reg_update(regulator->da9052,
1408c2ecf20Sopenharmony_ci					 DA9052_BUCKA_REG + offset/2,
1418c2ecf20Sopenharmony_ci					 DA9052_BUCK_ILIM_MASK_EVEN,
1428c2ecf20Sopenharmony_ci					 reg_val << 2);
1438c2ecf20Sopenharmony_ci	else
1448c2ecf20Sopenharmony_ci		return da9052_reg_update(regulator->da9052,
1458c2ecf20Sopenharmony_ci					 DA9052_BUCKA_REG + offset/2,
1468c2ecf20Sopenharmony_ci					 DA9052_BUCK_ILIM_MASK_ODD,
1478c2ecf20Sopenharmony_ci					 reg_val << 6);
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic int da9052_list_voltage(struct regulator_dev *rdev,
1518c2ecf20Sopenharmony_ci				unsigned int selector)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
1548c2ecf20Sopenharmony_ci	struct da9052_regulator_info *info = regulator->info;
1558c2ecf20Sopenharmony_ci	int id = rdev_get_id(rdev);
1568c2ecf20Sopenharmony_ci	int volt_uV;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	if ((id == DA9052_ID_BUCK4) && (regulator->da9052->chip_id == DA9052)
1598c2ecf20Sopenharmony_ci		&& (selector >= DA9052_BUCK_PERI_REG_MAP_UPTO_3uV)) {
1608c2ecf20Sopenharmony_ci		volt_uV = ((DA9052_BUCK_PERI_REG_MAP_UPTO_3uV * info->step_uV)
1618c2ecf20Sopenharmony_ci			  + info->min_uV);
1628c2ecf20Sopenharmony_ci		volt_uV += (selector - DA9052_BUCK_PERI_REG_MAP_UPTO_3uV)
1638c2ecf20Sopenharmony_ci				    * (DA9052_BUCK_PERI_3uV_STEP);
1648c2ecf20Sopenharmony_ci	} else {
1658c2ecf20Sopenharmony_ci		volt_uV = (selector * info->step_uV) + info->min_uV;
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	if (volt_uV > info->max_uV)
1698c2ecf20Sopenharmony_ci		return -EINVAL;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	return volt_uV;
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic int da9052_map_voltage(struct regulator_dev *rdev,
1758c2ecf20Sopenharmony_ci			      int min_uV, int max_uV)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
1788c2ecf20Sopenharmony_ci	struct da9052_regulator_info *info = regulator->info;
1798c2ecf20Sopenharmony_ci	int id = rdev_get_id(rdev);
1808c2ecf20Sopenharmony_ci	int ret, sel;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	ret = verify_range(info, min_uV, max_uV);
1838c2ecf20Sopenharmony_ci	if (ret < 0)
1848c2ecf20Sopenharmony_ci		return ret;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	if (min_uV < info->min_uV)
1878c2ecf20Sopenharmony_ci		min_uV = info->min_uV;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if ((id == DA9052_ID_BUCK4) && (regulator->da9052->chip_id == DA9052)
1908c2ecf20Sopenharmony_ci		&& (min_uV >= DA9052_CONST_3uV)) {
1918c2ecf20Sopenharmony_ci			sel = DA9052_BUCK_PERI_REG_MAP_UPTO_3uV +
1928c2ecf20Sopenharmony_ci			      DIV_ROUND_UP(min_uV - DA9052_CONST_3uV,
1938c2ecf20Sopenharmony_ci					   DA9052_BUCK_PERI_3uV_STEP);
1948c2ecf20Sopenharmony_ci	} else {
1958c2ecf20Sopenharmony_ci		sel = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
1968c2ecf20Sopenharmony_ci	}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	ret = da9052_list_voltage(rdev, sel);
1998c2ecf20Sopenharmony_ci	if (ret < 0)
2008c2ecf20Sopenharmony_ci		return ret;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	return sel;
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev,
2068c2ecf20Sopenharmony_ci					    unsigned int selector)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
2098c2ecf20Sopenharmony_ci	struct da9052_regulator_info *info = regulator->info;
2108c2ecf20Sopenharmony_ci	int id = rdev_get_id(rdev);
2118c2ecf20Sopenharmony_ci	int ret;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	ret = da9052_reg_update(regulator->da9052, rdev->desc->vsel_reg,
2148c2ecf20Sopenharmony_ci				rdev->desc->vsel_mask, selector);
2158c2ecf20Sopenharmony_ci	if (ret < 0)
2168c2ecf20Sopenharmony_ci		return ret;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	/* Some LDOs and DCDCs are DVC controlled which requires enabling of
2198c2ecf20Sopenharmony_ci	 * the activate bit to implment the changes on the output.
2208c2ecf20Sopenharmony_ci	 */
2218c2ecf20Sopenharmony_ci	switch (id) {
2228c2ecf20Sopenharmony_ci	case DA9052_ID_BUCK1:
2238c2ecf20Sopenharmony_ci	case DA9052_ID_BUCK2:
2248c2ecf20Sopenharmony_ci	case DA9052_ID_BUCK3:
2258c2ecf20Sopenharmony_ci	case DA9052_ID_LDO2:
2268c2ecf20Sopenharmony_ci	case DA9052_ID_LDO3:
2278c2ecf20Sopenharmony_ci		ret = da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG,
2288c2ecf20Sopenharmony_ci					info->activate_bit, info->activate_bit);
2298c2ecf20Sopenharmony_ci		break;
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	return ret;
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic int da9052_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
2368c2ecf20Sopenharmony_ci						 unsigned int old_sel,
2378c2ecf20Sopenharmony_ci						 unsigned int new_sel)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
2408c2ecf20Sopenharmony_ci	struct da9052_regulator_info *info = regulator->info;
2418c2ecf20Sopenharmony_ci	int id = rdev_get_id(rdev);
2428c2ecf20Sopenharmony_ci	int ret = 0;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	/* The DVC controlled LDOs and DCDCs ramp with 6.25mV/µs after enabling
2458c2ecf20Sopenharmony_ci	 * the activate bit.
2468c2ecf20Sopenharmony_ci	 */
2478c2ecf20Sopenharmony_ci	switch (id) {
2488c2ecf20Sopenharmony_ci	case DA9052_ID_BUCK1:
2498c2ecf20Sopenharmony_ci	case DA9052_ID_BUCK2:
2508c2ecf20Sopenharmony_ci	case DA9052_ID_BUCK3:
2518c2ecf20Sopenharmony_ci	case DA9052_ID_LDO2:
2528c2ecf20Sopenharmony_ci	case DA9052_ID_LDO3:
2538c2ecf20Sopenharmony_ci		ret = DIV_ROUND_UP(abs(new_sel - old_sel) * info->step_uV,
2548c2ecf20Sopenharmony_ci				   6250);
2558c2ecf20Sopenharmony_ci		break;
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	return ret;
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic const struct regulator_ops da9052_dcdc_ops = {
2628c2ecf20Sopenharmony_ci	.get_current_limit = da9052_dcdc_get_current_limit,
2638c2ecf20Sopenharmony_ci	.set_current_limit = da9052_dcdc_set_current_limit,
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	.list_voltage = da9052_list_voltage,
2668c2ecf20Sopenharmony_ci	.map_voltage = da9052_map_voltage,
2678c2ecf20Sopenharmony_ci	.get_voltage_sel = regulator_get_voltage_sel_regmap,
2688c2ecf20Sopenharmony_ci	.set_voltage_sel = da9052_regulator_set_voltage_sel,
2698c2ecf20Sopenharmony_ci	.set_voltage_time_sel = da9052_regulator_set_voltage_time_sel,
2708c2ecf20Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
2718c2ecf20Sopenharmony_ci	.enable = regulator_enable_regmap,
2728c2ecf20Sopenharmony_ci	.disable = regulator_disable_regmap,
2738c2ecf20Sopenharmony_ci};
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_cistatic const struct regulator_ops da9052_ldo_ops = {
2768c2ecf20Sopenharmony_ci	.list_voltage = da9052_list_voltage,
2778c2ecf20Sopenharmony_ci	.map_voltage = da9052_map_voltage,
2788c2ecf20Sopenharmony_ci	.get_voltage_sel = regulator_get_voltage_sel_regmap,
2798c2ecf20Sopenharmony_ci	.set_voltage_sel = da9052_regulator_set_voltage_sel,
2808c2ecf20Sopenharmony_ci	.set_voltage_time_sel = da9052_regulator_set_voltage_time_sel,
2818c2ecf20Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
2828c2ecf20Sopenharmony_ci	.enable = regulator_enable_regmap,
2838c2ecf20Sopenharmony_ci	.disable = regulator_disable_regmap,
2848c2ecf20Sopenharmony_ci};
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci#define DA9052_LDO(_id, _name, step, min, max, sbits, ebits, abits) \
2878c2ecf20Sopenharmony_ci{\
2888c2ecf20Sopenharmony_ci	.reg_desc = {\
2898c2ecf20Sopenharmony_ci		.name = #_name,\
2908c2ecf20Sopenharmony_ci		.of_match = of_match_ptr(#_name),\
2918c2ecf20Sopenharmony_ci		.regulators_node = of_match_ptr("regulators"),\
2928c2ecf20Sopenharmony_ci		.ops = &da9052_ldo_ops,\
2938c2ecf20Sopenharmony_ci		.type = REGULATOR_VOLTAGE,\
2948c2ecf20Sopenharmony_ci		.id = DA9052_ID_##_id,\
2958c2ecf20Sopenharmony_ci		.n_voltages = (max - min) / step + 1, \
2968c2ecf20Sopenharmony_ci		.owner = THIS_MODULE,\
2978c2ecf20Sopenharmony_ci		.vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
2988c2ecf20Sopenharmony_ci		.vsel_mask = (1 << (sbits)) - 1,\
2998c2ecf20Sopenharmony_ci		.enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
3008c2ecf20Sopenharmony_ci		.enable_mask = 1 << (ebits),\
3018c2ecf20Sopenharmony_ci	},\
3028c2ecf20Sopenharmony_ci	.min_uV = (min) * 1000,\
3038c2ecf20Sopenharmony_ci	.max_uV = (max) * 1000,\
3048c2ecf20Sopenharmony_ci	.step_uV = (step) * 1000,\
3058c2ecf20Sopenharmony_ci	.activate_bit = (abits),\
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci#define DA9052_DCDC(_id, _name, step, min, max, sbits, ebits, abits) \
3098c2ecf20Sopenharmony_ci{\
3108c2ecf20Sopenharmony_ci	.reg_desc = {\
3118c2ecf20Sopenharmony_ci		.name = #_name,\
3128c2ecf20Sopenharmony_ci		.of_match = of_match_ptr(#_name),\
3138c2ecf20Sopenharmony_ci		.regulators_node = of_match_ptr("regulators"),\
3148c2ecf20Sopenharmony_ci		.ops = &da9052_dcdc_ops,\
3158c2ecf20Sopenharmony_ci		.type = REGULATOR_VOLTAGE,\
3168c2ecf20Sopenharmony_ci		.id = DA9052_ID_##_id,\
3178c2ecf20Sopenharmony_ci		.n_voltages = (max - min) / step + 1, \
3188c2ecf20Sopenharmony_ci		.owner = THIS_MODULE,\
3198c2ecf20Sopenharmony_ci		.vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
3208c2ecf20Sopenharmony_ci		.vsel_mask = (1 << (sbits)) - 1,\
3218c2ecf20Sopenharmony_ci		.enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
3228c2ecf20Sopenharmony_ci		.enable_mask = 1 << (ebits),\
3238c2ecf20Sopenharmony_ci	},\
3248c2ecf20Sopenharmony_ci	.min_uV = (min) * 1000,\
3258c2ecf20Sopenharmony_ci	.max_uV = (max) * 1000,\
3268c2ecf20Sopenharmony_ci	.step_uV = (step) * 1000,\
3278c2ecf20Sopenharmony_ci	.activate_bit = (abits),\
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cistatic struct da9052_regulator_info da9052_regulator_info[] = {
3318c2ecf20Sopenharmony_ci	DA9052_DCDC(BUCK1, buck1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO),
3328c2ecf20Sopenharmony_ci	DA9052_DCDC(BUCK2, buck2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO),
3338c2ecf20Sopenharmony_ci	DA9052_DCDC(BUCK3, buck3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO),
3348c2ecf20Sopenharmony_ci	DA9052_DCDC(BUCK4, buck4, 50, 1800, 3600, 5, 6, 0),
3358c2ecf20Sopenharmony_ci	DA9052_LDO(LDO1, ldo1, 50, 600, 1800, 5, 6, 0),
3368c2ecf20Sopenharmony_ci	DA9052_LDO(LDO2, ldo2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO),
3378c2ecf20Sopenharmony_ci	DA9052_LDO(LDO3, ldo3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO),
3388c2ecf20Sopenharmony_ci	DA9052_LDO(LDO4, ldo4, 25, 1725, 3300, 6, 6, 0),
3398c2ecf20Sopenharmony_ci	DA9052_LDO(LDO5, ldo5, 50, 1200, 3600, 6, 6, 0),
3408c2ecf20Sopenharmony_ci	DA9052_LDO(LDO6, ldo6, 50, 1200, 3600, 6, 6, 0),
3418c2ecf20Sopenharmony_ci	DA9052_LDO(LDO7, ldo7, 50, 1200, 3600, 6, 6, 0),
3428c2ecf20Sopenharmony_ci	DA9052_LDO(LDO8, ldo8, 50, 1200, 3600, 6, 6, 0),
3438c2ecf20Sopenharmony_ci	DA9052_LDO(LDO9, ldo9, 50, 1250, 3650, 6, 6, 0),
3448c2ecf20Sopenharmony_ci	DA9052_LDO(LDO10, ldo10, 50, 1200, 3600, 6, 6, 0),
3458c2ecf20Sopenharmony_ci};
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_cistatic struct da9052_regulator_info da9053_regulator_info[] = {
3488c2ecf20Sopenharmony_ci	DA9052_DCDC(BUCK1, buck1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO),
3498c2ecf20Sopenharmony_ci	DA9052_DCDC(BUCK2, buck2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO),
3508c2ecf20Sopenharmony_ci	DA9052_DCDC(BUCK3, buck3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO),
3518c2ecf20Sopenharmony_ci	DA9052_DCDC(BUCK4, buck4, 25, 950, 2525, 6, 6, 0),
3528c2ecf20Sopenharmony_ci	DA9052_LDO(LDO1, ldo1, 50, 600, 1800, 5, 6, 0),
3538c2ecf20Sopenharmony_ci	DA9052_LDO(LDO2, ldo2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO),
3548c2ecf20Sopenharmony_ci	DA9052_LDO(LDO3, ldo3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO),
3558c2ecf20Sopenharmony_ci	DA9052_LDO(LDO4, ldo4, 25, 1725, 3300, 6, 6, 0),
3568c2ecf20Sopenharmony_ci	DA9052_LDO(LDO5, ldo5, 50, 1200, 3600, 6, 6, 0),
3578c2ecf20Sopenharmony_ci	DA9052_LDO(LDO6, ldo6, 50, 1200, 3600, 6, 6, 0),
3588c2ecf20Sopenharmony_ci	DA9052_LDO(LDO7, ldo7, 50, 1200, 3600, 6, 6, 0),
3598c2ecf20Sopenharmony_ci	DA9052_LDO(LDO8, ldo8, 50, 1200, 3600, 6, 6, 0),
3608c2ecf20Sopenharmony_ci	DA9052_LDO(LDO9, ldo9, 50, 1250, 3650, 6, 6, 0),
3618c2ecf20Sopenharmony_ci	DA9052_LDO(LDO10, ldo10, 50, 1200, 3600, 6, 6, 0),
3628c2ecf20Sopenharmony_ci};
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_cistatic inline struct da9052_regulator_info *find_regulator_info(u8 chip_id,
3658c2ecf20Sopenharmony_ci								 int id)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	struct da9052_regulator_info *info;
3688c2ecf20Sopenharmony_ci	int i;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	switch (chip_id) {
3718c2ecf20Sopenharmony_ci	case DA9052:
3728c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(da9052_regulator_info); i++) {
3738c2ecf20Sopenharmony_ci			info = &da9052_regulator_info[i];
3748c2ecf20Sopenharmony_ci			if (info->reg_desc.id == id)
3758c2ecf20Sopenharmony_ci				return info;
3768c2ecf20Sopenharmony_ci		}
3778c2ecf20Sopenharmony_ci		break;
3788c2ecf20Sopenharmony_ci	case DA9053_AA:
3798c2ecf20Sopenharmony_ci	case DA9053_BA:
3808c2ecf20Sopenharmony_ci	case DA9053_BB:
3818c2ecf20Sopenharmony_ci	case DA9053_BC:
3828c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(da9053_regulator_info); i++) {
3838c2ecf20Sopenharmony_ci			info = &da9053_regulator_info[i];
3848c2ecf20Sopenharmony_ci			if (info->reg_desc.id == id)
3858c2ecf20Sopenharmony_ci				return info;
3868c2ecf20Sopenharmony_ci		}
3878c2ecf20Sopenharmony_ci		break;
3888c2ecf20Sopenharmony_ci	}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	return NULL;
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_cistatic int da9052_regulator_probe(struct platform_device *pdev)
3948c2ecf20Sopenharmony_ci{
3958c2ecf20Sopenharmony_ci	const struct mfd_cell *cell = mfd_get_cell(pdev);
3968c2ecf20Sopenharmony_ci	struct regulator_config config = { };
3978c2ecf20Sopenharmony_ci	struct da9052_regulator *regulator;
3988c2ecf20Sopenharmony_ci	struct da9052 *da9052;
3998c2ecf20Sopenharmony_ci	struct da9052_pdata *pdata;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	regulator = devm_kzalloc(&pdev->dev, sizeof(struct da9052_regulator),
4028c2ecf20Sopenharmony_ci				 GFP_KERNEL);
4038c2ecf20Sopenharmony_ci	if (!regulator)
4048c2ecf20Sopenharmony_ci		return -ENOMEM;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	da9052 = dev_get_drvdata(pdev->dev.parent);
4078c2ecf20Sopenharmony_ci	pdata = dev_get_platdata(da9052->dev);
4088c2ecf20Sopenharmony_ci	regulator->da9052 = da9052;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	regulator->info = find_regulator_info(regulator->da9052->chip_id,
4118c2ecf20Sopenharmony_ci					      cell->id);
4128c2ecf20Sopenharmony_ci	if (regulator->info == NULL) {
4138c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "invalid regulator ID specified\n");
4148c2ecf20Sopenharmony_ci		return -EINVAL;
4158c2ecf20Sopenharmony_ci	}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	config.dev = da9052->dev;
4188c2ecf20Sopenharmony_ci	config.driver_data = regulator;
4198c2ecf20Sopenharmony_ci	config.regmap = da9052->regmap;
4208c2ecf20Sopenharmony_ci	if (pdata)
4218c2ecf20Sopenharmony_ci		config.init_data = pdata->regulators[cell->id];
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	regulator->rdev = devm_regulator_register(&pdev->dev,
4248c2ecf20Sopenharmony_ci						  &regulator->info->reg_desc,
4258c2ecf20Sopenharmony_ci						  &config);
4268c2ecf20Sopenharmony_ci	if (IS_ERR(regulator->rdev)) {
4278c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to register regulator %s\n",
4288c2ecf20Sopenharmony_ci			regulator->info->reg_desc.name);
4298c2ecf20Sopenharmony_ci		return PTR_ERR(regulator->rdev);
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, regulator);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	return 0;
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cistatic struct platform_driver da9052_regulator_driver = {
4388c2ecf20Sopenharmony_ci	.probe = da9052_regulator_probe,
4398c2ecf20Sopenharmony_ci	.driver = {
4408c2ecf20Sopenharmony_ci		.name = "da9052-regulator",
4418c2ecf20Sopenharmony_ci	},
4428c2ecf20Sopenharmony_ci};
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_cistatic int __init da9052_regulator_init(void)
4458c2ecf20Sopenharmony_ci{
4468c2ecf20Sopenharmony_ci	return platform_driver_register(&da9052_regulator_driver);
4478c2ecf20Sopenharmony_ci}
4488c2ecf20Sopenharmony_cisubsys_initcall(da9052_regulator_init);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistatic void __exit da9052_regulator_exit(void)
4518c2ecf20Sopenharmony_ci{
4528c2ecf20Sopenharmony_ci	platform_driver_unregister(&da9052_regulator_driver);
4538c2ecf20Sopenharmony_ci}
4548c2ecf20Sopenharmony_cimodule_exit(da9052_regulator_exit);
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ciMODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
4578c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Power Regulator driver for Dialog DA9052 PMIC");
4588c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
4598c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:da9052-regulator");
460