162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// Device driver for regulators in Hi6421 IC
462306a36Sopenharmony_ci//
562306a36Sopenharmony_ci// Copyright (c) <2011-2014> HiSilicon Technologies Co., Ltd.
662306a36Sopenharmony_ci//              http://www.hisilicon.com
762306a36Sopenharmony_ci// Copyright (c) <2013-2014> Linaro Ltd.
862306a36Sopenharmony_ci//              https://www.linaro.org
962306a36Sopenharmony_ci//
1062306a36Sopenharmony_ci// Author: Guodong Xu <guodong.xu@linaro.org>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci#include <linux/device.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/err.h>
1662306a36Sopenharmony_ci#include <linux/platform_device.h>
1762306a36Sopenharmony_ci#include <linux/of.h>
1862306a36Sopenharmony_ci#include <linux/regmap.h>
1962306a36Sopenharmony_ci#include <linux/regulator/driver.h>
2062306a36Sopenharmony_ci#include <linux/regulator/machine.h>
2162306a36Sopenharmony_ci#include <linux/regulator/of_regulator.h>
2262306a36Sopenharmony_ci#include <linux/mfd/hi6421-pmic.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/*
2562306a36Sopenharmony_ci * struct hi6421_regulator_pdata - Hi6421 regulator data of platform device
2662306a36Sopenharmony_ci * @lock: mutex to serialize regulator enable
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_cistruct hi6421_regulator_pdata {
2962306a36Sopenharmony_ci	struct mutex lock;
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/*
3362306a36Sopenharmony_ci * struct hi6421_regulator_info - hi6421 regulator information
3462306a36Sopenharmony_ci * @desc: regulator description
3562306a36Sopenharmony_ci * @mode_mask: ECO mode bitmask of LDOs; for BUCKs, this masks sleep
3662306a36Sopenharmony_ci * @eco_microamp: eco mode load upper limit (in uA), valid for LDOs only
3762306a36Sopenharmony_ci */
3862306a36Sopenharmony_cistruct hi6421_regulator_info {
3962306a36Sopenharmony_ci	struct regulator_desc	desc;
4062306a36Sopenharmony_ci	u8		mode_mask;
4162306a36Sopenharmony_ci	u32		eco_microamp;
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/* HI6421 regulators */
4562306a36Sopenharmony_cienum hi6421_regulator_id {
4662306a36Sopenharmony_ci	HI6421_LDO0,
4762306a36Sopenharmony_ci	HI6421_LDO1,
4862306a36Sopenharmony_ci	HI6421_LDO2,
4962306a36Sopenharmony_ci	HI6421_LDO3,
5062306a36Sopenharmony_ci	HI6421_LDO4,
5162306a36Sopenharmony_ci	HI6421_LDO5,
5262306a36Sopenharmony_ci	HI6421_LDO6,
5362306a36Sopenharmony_ci	HI6421_LDO7,
5462306a36Sopenharmony_ci	HI6421_LDO8,
5562306a36Sopenharmony_ci	HI6421_LDO9,
5662306a36Sopenharmony_ci	HI6421_LDO10,
5762306a36Sopenharmony_ci	HI6421_LDO11,
5862306a36Sopenharmony_ci	HI6421_LDO12,
5962306a36Sopenharmony_ci	HI6421_LDO13,
6062306a36Sopenharmony_ci	HI6421_LDO14,
6162306a36Sopenharmony_ci	HI6421_LDO15,
6262306a36Sopenharmony_ci	HI6421_LDO16,
6362306a36Sopenharmony_ci	HI6421_LDO17,
6462306a36Sopenharmony_ci	HI6421_LDO18,
6562306a36Sopenharmony_ci	HI6421_LDO19,
6662306a36Sopenharmony_ci	HI6421_LDO20,
6762306a36Sopenharmony_ci	HI6421_LDOAUDIO,
6862306a36Sopenharmony_ci	HI6421_BUCK0,
6962306a36Sopenharmony_ci	HI6421_BUCK1,
7062306a36Sopenharmony_ci	HI6421_BUCK2,
7162306a36Sopenharmony_ci	HI6421_BUCK3,
7262306a36Sopenharmony_ci	HI6421_BUCK4,
7362306a36Sopenharmony_ci	HI6421_BUCK5,
7462306a36Sopenharmony_ci	HI6421_NUM_REGULATORS,
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/* LDO 0, 4~7, 9~14, 16~20 have same voltage table. */
7862306a36Sopenharmony_cistatic const unsigned int ldo_0_voltages[] = {
7962306a36Sopenharmony_ci	1500000, 1800000, 2400000, 2500000,
8062306a36Sopenharmony_ci	2600000, 2700000, 2850000, 3000000,
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci/* LDO 8, 15 have same voltage table. */
8462306a36Sopenharmony_cistatic const unsigned int ldo_8_voltages[] = {
8562306a36Sopenharmony_ci	1500000, 1800000, 2400000, 2600000,
8662306a36Sopenharmony_ci	2700000, 2850000, 3000000, 3300000,
8762306a36Sopenharmony_ci};
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/* Ranges are sorted in ascending order. */
9062306a36Sopenharmony_cistatic const struct linear_range ldo_audio_volt_range[] = {
9162306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(2800000, 0, 3, 50000),
9262306a36Sopenharmony_ci	REGULATOR_LINEAR_RANGE(3000000, 4, 7, 100000),
9362306a36Sopenharmony_ci};
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic const unsigned int buck_3_voltages[] = {
9662306a36Sopenharmony_ci	 950000, 1050000, 1100000, 1117000,
9762306a36Sopenharmony_ci	1134000, 1150000, 1167000, 1200000,
9862306a36Sopenharmony_ci};
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic const unsigned int buck_4_voltages[] = {
10162306a36Sopenharmony_ci	1150000, 1200000, 1250000, 1350000,
10262306a36Sopenharmony_ci	1700000, 1800000, 1900000, 2000000,
10362306a36Sopenharmony_ci};
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic const unsigned int buck_5_voltages[] = {
10662306a36Sopenharmony_ci	1150000, 1200000, 1250000, 1350000,
10762306a36Sopenharmony_ci	1600000, 1700000, 1800000, 1900000,
10862306a36Sopenharmony_ci};
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic const struct regulator_ops hi6421_ldo_ops;
11162306a36Sopenharmony_cistatic const struct regulator_ops hi6421_ldo_linear_ops;
11262306a36Sopenharmony_cistatic const struct regulator_ops hi6421_ldo_linear_range_ops;
11362306a36Sopenharmony_cistatic const struct regulator_ops hi6421_buck012_ops;
11462306a36Sopenharmony_cistatic const struct regulator_ops hi6421_buck345_ops;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci#define HI6421_LDO_ENABLE_TIME (350)
11762306a36Sopenharmony_ci/*
11862306a36Sopenharmony_ci * _id - LDO id name string
11962306a36Sopenharmony_ci * _match - of match name string
12062306a36Sopenharmony_ci * v_table - voltage table
12162306a36Sopenharmony_ci * vreg - voltage select register
12262306a36Sopenharmony_ci * vmask - voltage select mask
12362306a36Sopenharmony_ci * ereg - enable register
12462306a36Sopenharmony_ci * emask - enable mask
12562306a36Sopenharmony_ci * odelay - off/on delay time in uS
12662306a36Sopenharmony_ci * ecomask - eco mode mask
12762306a36Sopenharmony_ci * ecoamp - eco mode load uppler limit in uA
12862306a36Sopenharmony_ci */
12962306a36Sopenharmony_ci#define HI6421_LDO(_id, _match, v_table, vreg, vmask, ereg, emask,	\
13062306a36Sopenharmony_ci		   odelay, ecomask, ecoamp)				\
13162306a36Sopenharmony_ci	[HI6421_##_id] = {						\
13262306a36Sopenharmony_ci		.desc = {						\
13362306a36Sopenharmony_ci			.name		= #_id,				\
13462306a36Sopenharmony_ci			.of_match        = #_match,			\
13562306a36Sopenharmony_ci			.regulators_node = "regulators",		\
13662306a36Sopenharmony_ci			.ops		= &hi6421_ldo_ops,		\
13762306a36Sopenharmony_ci			.type		= REGULATOR_VOLTAGE,		\
13862306a36Sopenharmony_ci			.id		= HI6421_##_id,			\
13962306a36Sopenharmony_ci			.owner		= THIS_MODULE,			\
14062306a36Sopenharmony_ci			.n_voltages	= ARRAY_SIZE(v_table),		\
14162306a36Sopenharmony_ci			.volt_table	= v_table,			\
14262306a36Sopenharmony_ci			.vsel_reg	= HI6421_REG_TO_BUS_ADDR(vreg),	\
14362306a36Sopenharmony_ci			.vsel_mask	= vmask,			\
14462306a36Sopenharmony_ci			.enable_reg	= HI6421_REG_TO_BUS_ADDR(ereg),	\
14562306a36Sopenharmony_ci			.enable_mask	= emask,			\
14662306a36Sopenharmony_ci			.enable_time	= HI6421_LDO_ENABLE_TIME,	\
14762306a36Sopenharmony_ci			.off_on_delay	= odelay,			\
14862306a36Sopenharmony_ci		},							\
14962306a36Sopenharmony_ci		.mode_mask		= ecomask,			\
15062306a36Sopenharmony_ci		.eco_microamp		= ecoamp,			\
15162306a36Sopenharmony_ci	}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci/* HI6421 LDO1~3 are linear voltage regulators at fixed uV_step
15462306a36Sopenharmony_ci *
15562306a36Sopenharmony_ci * _id - LDO id name string
15662306a36Sopenharmony_ci * _match - of match name string
15762306a36Sopenharmony_ci * _min_uV - minimum voltage supported in uV
15862306a36Sopenharmony_ci * n_volt - number of votages available
15962306a36Sopenharmony_ci * vstep - voltage increase in each linear step in uV
16062306a36Sopenharmony_ci * vreg - voltage select register
16162306a36Sopenharmony_ci * vmask - voltage select mask
16262306a36Sopenharmony_ci * ereg - enable register
16362306a36Sopenharmony_ci * emask - enable mask
16462306a36Sopenharmony_ci * odelay - off/on delay time in uS
16562306a36Sopenharmony_ci * ecomask - eco mode mask
16662306a36Sopenharmony_ci * ecoamp - eco mode load uppler limit in uA
16762306a36Sopenharmony_ci */
16862306a36Sopenharmony_ci#define HI6421_LDO_LINEAR(_id, _match, _min_uV, n_volt, vstep, vreg, vmask,\
16962306a36Sopenharmony_ci			  ereg, emask, odelay, ecomask, ecoamp)		\
17062306a36Sopenharmony_ci	[HI6421_##_id] = {						\
17162306a36Sopenharmony_ci		.desc = {						\
17262306a36Sopenharmony_ci			.name		= #_id,				\
17362306a36Sopenharmony_ci			.of_match        = #_match,			\
17462306a36Sopenharmony_ci			.regulators_node = "regulators",		\
17562306a36Sopenharmony_ci			.ops		= &hi6421_ldo_linear_ops,	\
17662306a36Sopenharmony_ci			.type		= REGULATOR_VOLTAGE,		\
17762306a36Sopenharmony_ci			.id		= HI6421_##_id,			\
17862306a36Sopenharmony_ci			.owner		= THIS_MODULE,			\
17962306a36Sopenharmony_ci			.min_uV		= _min_uV,			\
18062306a36Sopenharmony_ci			.n_voltages	= n_volt,			\
18162306a36Sopenharmony_ci			.uV_step	= vstep,			\
18262306a36Sopenharmony_ci			.vsel_reg	= HI6421_REG_TO_BUS_ADDR(vreg),	\
18362306a36Sopenharmony_ci			.vsel_mask	= vmask,			\
18462306a36Sopenharmony_ci			.enable_reg	= HI6421_REG_TO_BUS_ADDR(ereg),	\
18562306a36Sopenharmony_ci			.enable_mask	= emask,			\
18662306a36Sopenharmony_ci			.enable_time	= HI6421_LDO_ENABLE_TIME,	\
18762306a36Sopenharmony_ci			.off_on_delay	= odelay,			\
18862306a36Sopenharmony_ci		},							\
18962306a36Sopenharmony_ci		.mode_mask		= ecomask,			\
19062306a36Sopenharmony_ci		.eco_microamp		= ecoamp,			\
19162306a36Sopenharmony_ci	}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci/* HI6421 LDOAUDIO is a linear voltage regulator with two 4-step ranges
19462306a36Sopenharmony_ci *
19562306a36Sopenharmony_ci * _id - LDO id name string
19662306a36Sopenharmony_ci * _match - of match name string
19762306a36Sopenharmony_ci * n_volt - number of votages available
19862306a36Sopenharmony_ci * volt_ranges - array of linear_range
19962306a36Sopenharmony_ci * vstep - voltage increase in each linear step in uV
20062306a36Sopenharmony_ci * vreg - voltage select register
20162306a36Sopenharmony_ci * vmask - voltage select mask
20262306a36Sopenharmony_ci * ereg - enable register
20362306a36Sopenharmony_ci * emask - enable mask
20462306a36Sopenharmony_ci * odelay - off/on delay time in uS
20562306a36Sopenharmony_ci * ecomask - eco mode mask
20662306a36Sopenharmony_ci * ecoamp - eco mode load uppler limit in uA
20762306a36Sopenharmony_ci */
20862306a36Sopenharmony_ci#define HI6421_LDO_LINEAR_RANGE(_id, _match, n_volt, volt_ranges, vreg, vmask,\
20962306a36Sopenharmony_ci				ereg, emask, odelay, ecomask, ecoamp)	\
21062306a36Sopenharmony_ci	[HI6421_##_id] = {						\
21162306a36Sopenharmony_ci		.desc = {						\
21262306a36Sopenharmony_ci			.name		= #_id,				\
21362306a36Sopenharmony_ci			.of_match        = #_match,			\
21462306a36Sopenharmony_ci			.regulators_node = "regulators",		\
21562306a36Sopenharmony_ci			.ops		= &hi6421_ldo_linear_range_ops,	\
21662306a36Sopenharmony_ci			.type		= REGULATOR_VOLTAGE,		\
21762306a36Sopenharmony_ci			.id		= HI6421_##_id,			\
21862306a36Sopenharmony_ci			.owner		= THIS_MODULE,			\
21962306a36Sopenharmony_ci			.n_voltages	= n_volt,			\
22062306a36Sopenharmony_ci			.linear_ranges	= volt_ranges,			\
22162306a36Sopenharmony_ci			.n_linear_ranges = ARRAY_SIZE(volt_ranges),	\
22262306a36Sopenharmony_ci			.vsel_reg	= HI6421_REG_TO_BUS_ADDR(vreg),	\
22362306a36Sopenharmony_ci			.vsel_mask	= vmask,			\
22462306a36Sopenharmony_ci			.enable_reg	= HI6421_REG_TO_BUS_ADDR(ereg),	\
22562306a36Sopenharmony_ci			.enable_mask	= emask,			\
22662306a36Sopenharmony_ci			.enable_time	= HI6421_LDO_ENABLE_TIME,	\
22762306a36Sopenharmony_ci			.off_on_delay	= odelay,			\
22862306a36Sopenharmony_ci		},							\
22962306a36Sopenharmony_ci		.mode_mask		= ecomask,			\
23062306a36Sopenharmony_ci		.eco_microamp		= ecoamp,			\
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci/* HI6421 BUCK0/1/2 are linear voltage regulators at fixed uV_step
23462306a36Sopenharmony_ci *
23562306a36Sopenharmony_ci * _id - BUCK0/1/2 id name string
23662306a36Sopenharmony_ci * _match - of match name string
23762306a36Sopenharmony_ci * vreg - voltage select register
23862306a36Sopenharmony_ci * vmask - voltage select mask
23962306a36Sopenharmony_ci * ereg - enable register
24062306a36Sopenharmony_ci * emask - enable mask
24162306a36Sopenharmony_ci * sleepmask - mask of sleep mode
24262306a36Sopenharmony_ci * etime - enable time
24362306a36Sopenharmony_ci * odelay - off/on delay time in uS
24462306a36Sopenharmony_ci */
24562306a36Sopenharmony_ci#define HI6421_BUCK012(_id, _match, vreg, vmask, ereg, emask, sleepmask,\
24662306a36Sopenharmony_ci			etime, odelay)					\
24762306a36Sopenharmony_ci	[HI6421_##_id] = {						\
24862306a36Sopenharmony_ci		.desc = {						\
24962306a36Sopenharmony_ci			.name		= #_id,				\
25062306a36Sopenharmony_ci			.of_match        = #_match,			\
25162306a36Sopenharmony_ci			.regulators_node = "regulators",		\
25262306a36Sopenharmony_ci			.ops		= &hi6421_buck012_ops,		\
25362306a36Sopenharmony_ci			.type		= REGULATOR_VOLTAGE,		\
25462306a36Sopenharmony_ci			.id		= HI6421_##_id,			\
25562306a36Sopenharmony_ci			.owner		= THIS_MODULE,			\
25662306a36Sopenharmony_ci			.min_uV		= 700000,			\
25762306a36Sopenharmony_ci			.n_voltages	= 128,				\
25862306a36Sopenharmony_ci			.uV_step	= 7086,				\
25962306a36Sopenharmony_ci			.vsel_reg	= HI6421_REG_TO_BUS_ADDR(vreg),	\
26062306a36Sopenharmony_ci			.vsel_mask	= vmask,			\
26162306a36Sopenharmony_ci			.enable_reg	= HI6421_REG_TO_BUS_ADDR(ereg),	\
26262306a36Sopenharmony_ci			.enable_mask	= emask,			\
26362306a36Sopenharmony_ci			.enable_time	= etime,			\
26462306a36Sopenharmony_ci			.off_on_delay	= odelay,			\
26562306a36Sopenharmony_ci		},							\
26662306a36Sopenharmony_ci		.mode_mask		= sleepmask,			\
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci/* HI6421 BUCK3/4/5 share similar configurations as LDOs, with exception
27062306a36Sopenharmony_ci *  that it supports SLEEP mode, so has different .ops.
27162306a36Sopenharmony_ci *
27262306a36Sopenharmony_ci * _id - LDO id name string
27362306a36Sopenharmony_ci * _match - of match name string
27462306a36Sopenharmony_ci * v_table - voltage table
27562306a36Sopenharmony_ci * vreg - voltage select register
27662306a36Sopenharmony_ci * vmask - voltage select mask
27762306a36Sopenharmony_ci * ereg - enable register
27862306a36Sopenharmony_ci * emask - enable mask
27962306a36Sopenharmony_ci * odelay - off/on delay time in uS
28062306a36Sopenharmony_ci * sleepmask - mask of sleep mode
28162306a36Sopenharmony_ci */
28262306a36Sopenharmony_ci#define HI6421_BUCK345(_id, _match, v_table, vreg, vmask, ereg, emask,	\
28362306a36Sopenharmony_ci			odelay, sleepmask)				\
28462306a36Sopenharmony_ci	[HI6421_##_id] = {						\
28562306a36Sopenharmony_ci		.desc = {						\
28662306a36Sopenharmony_ci			.name		= #_id,				\
28762306a36Sopenharmony_ci			.of_match        = #_match,			\
28862306a36Sopenharmony_ci			.regulators_node = "regulators",		\
28962306a36Sopenharmony_ci			.ops		= &hi6421_buck345_ops,		\
29062306a36Sopenharmony_ci			.type		= REGULATOR_VOLTAGE,		\
29162306a36Sopenharmony_ci			.id		= HI6421_##_id,			\
29262306a36Sopenharmony_ci			.owner		= THIS_MODULE,			\
29362306a36Sopenharmony_ci			.n_voltages	= ARRAY_SIZE(v_table),		\
29462306a36Sopenharmony_ci			.volt_table	= v_table,			\
29562306a36Sopenharmony_ci			.vsel_reg	= HI6421_REG_TO_BUS_ADDR(vreg),	\
29662306a36Sopenharmony_ci			.vsel_mask	= vmask,			\
29762306a36Sopenharmony_ci			.enable_reg	= HI6421_REG_TO_BUS_ADDR(ereg),	\
29862306a36Sopenharmony_ci			.enable_mask	= emask,			\
29962306a36Sopenharmony_ci			.enable_time	= HI6421_LDO_ENABLE_TIME,	\
30062306a36Sopenharmony_ci			.off_on_delay	= odelay,			\
30162306a36Sopenharmony_ci		},							\
30262306a36Sopenharmony_ci		.mode_mask		= sleepmask,			\
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci/* HI6421 regulator information */
30662306a36Sopenharmony_cistatic struct hi6421_regulator_info
30762306a36Sopenharmony_ci		hi6421_regulator_info[HI6421_NUM_REGULATORS] = {
30862306a36Sopenharmony_ci	HI6421_LDO(LDO0, hi6421_vout0, ldo_0_voltages, 0x20, 0x07, 0x20, 0x10,
30962306a36Sopenharmony_ci		   10000, 0x20, 8000),
31062306a36Sopenharmony_ci	HI6421_LDO_LINEAR(LDO1, hi6421_vout1, 1700000, 4, 100000, 0x21, 0x03,
31162306a36Sopenharmony_ci			  0x21, 0x10, 10000, 0x20, 5000),
31262306a36Sopenharmony_ci	HI6421_LDO_LINEAR(LDO2, hi6421_vout2, 1050000, 8, 50000, 0x22, 0x07,
31362306a36Sopenharmony_ci			  0x22, 0x10, 20000, 0x20, 8000),
31462306a36Sopenharmony_ci	HI6421_LDO_LINEAR(LDO3, hi6421_vout3, 1050000, 8, 50000, 0x23, 0x07,
31562306a36Sopenharmony_ci			  0x23, 0x10, 20000, 0x20, 8000),
31662306a36Sopenharmony_ci	HI6421_LDO(LDO4, hi6421_vout4, ldo_0_voltages, 0x24, 0x07, 0x24, 0x10,
31762306a36Sopenharmony_ci		   20000, 0x20, 8000),
31862306a36Sopenharmony_ci	HI6421_LDO(LDO5, hi6421_vout5, ldo_0_voltages, 0x25, 0x07, 0x25, 0x10,
31962306a36Sopenharmony_ci		   20000, 0x20, 8000),
32062306a36Sopenharmony_ci	HI6421_LDO(LDO6, hi6421_vout6, ldo_0_voltages, 0x26, 0x07, 0x26, 0x10,
32162306a36Sopenharmony_ci		   20000, 0x20, 8000),
32262306a36Sopenharmony_ci	HI6421_LDO(LDO7, hi6421_vout7, ldo_0_voltages, 0x27, 0x07, 0x27, 0x10,
32362306a36Sopenharmony_ci		   20000, 0x20, 5000),
32462306a36Sopenharmony_ci	HI6421_LDO(LDO8, hi6421_vout8, ldo_8_voltages, 0x28, 0x07, 0x28, 0x10,
32562306a36Sopenharmony_ci		   20000, 0x20, 8000),
32662306a36Sopenharmony_ci	HI6421_LDO(LDO9, hi6421_vout9, ldo_0_voltages, 0x29, 0x07, 0x29, 0x10,
32762306a36Sopenharmony_ci		   40000, 0x20, 8000),
32862306a36Sopenharmony_ci	HI6421_LDO(LDO10, hi6421_vout10, ldo_0_voltages, 0x2a, 0x07, 0x2a, 0x10,
32962306a36Sopenharmony_ci		   40000, 0x20, 8000),
33062306a36Sopenharmony_ci	HI6421_LDO(LDO11, hi6421_vout11, ldo_0_voltages, 0x2b, 0x07, 0x2b, 0x10,
33162306a36Sopenharmony_ci		   40000, 0x20, 8000),
33262306a36Sopenharmony_ci	HI6421_LDO(LDO12, hi6421_vout12, ldo_0_voltages, 0x2c, 0x07, 0x2c, 0x10,
33362306a36Sopenharmony_ci		   40000, 0x20, 8000),
33462306a36Sopenharmony_ci	HI6421_LDO(LDO13, hi6421_vout13, ldo_0_voltages, 0x2d, 0x07, 0x2d, 0x10,
33562306a36Sopenharmony_ci		   40000, 0x20, 8000),
33662306a36Sopenharmony_ci	HI6421_LDO(LDO14, hi6421_vout14, ldo_0_voltages, 0x2e, 0x07, 0x2e, 0x10,
33762306a36Sopenharmony_ci		   40000, 0x20, 8000),
33862306a36Sopenharmony_ci	HI6421_LDO(LDO15, hi6421_vout15, ldo_8_voltages, 0x2f, 0x07, 0x2f, 0x10,
33962306a36Sopenharmony_ci		   40000, 0x20, 8000),
34062306a36Sopenharmony_ci	HI6421_LDO(LDO16, hi6421_vout16, ldo_0_voltages, 0x30, 0x07, 0x30, 0x10,
34162306a36Sopenharmony_ci		   40000, 0x20, 8000),
34262306a36Sopenharmony_ci	HI6421_LDO(LDO17, hi6421_vout17, ldo_0_voltages, 0x31, 0x07, 0x31, 0x10,
34362306a36Sopenharmony_ci		   40000, 0x20, 8000),
34462306a36Sopenharmony_ci	HI6421_LDO(LDO18, hi6421_vout18, ldo_0_voltages, 0x32, 0x07, 0x32, 0x10,
34562306a36Sopenharmony_ci		   40000, 0x20, 8000),
34662306a36Sopenharmony_ci	HI6421_LDO(LDO19, hi6421_vout19, ldo_0_voltages, 0x33, 0x07, 0x33, 0x10,
34762306a36Sopenharmony_ci		   40000, 0x20, 8000),
34862306a36Sopenharmony_ci	HI6421_LDO(LDO20, hi6421_vout20, ldo_0_voltages, 0x34, 0x07, 0x34, 0x10,
34962306a36Sopenharmony_ci		   40000, 0x20, 8000),
35062306a36Sopenharmony_ci	HI6421_LDO_LINEAR_RANGE(LDOAUDIO, hi6421_vout_audio, 8,
35162306a36Sopenharmony_ci				ldo_audio_volt_range, 0x36, 0x70, 0x36, 0x01,
35262306a36Sopenharmony_ci				40000, 0x02, 5000),
35362306a36Sopenharmony_ci	HI6421_BUCK012(BUCK0, hi6421_buck0, 0x0d, 0x7f, 0x0c, 0x01, 0x10, 400,
35462306a36Sopenharmony_ci		       20000),
35562306a36Sopenharmony_ci	HI6421_BUCK012(BUCK1, hi6421_buck1, 0x0f, 0x7f, 0x0e, 0x01, 0x10, 400,
35662306a36Sopenharmony_ci		       20000),
35762306a36Sopenharmony_ci	HI6421_BUCK012(BUCK2, hi6421_buck2, 0x11, 0x7f, 0x10, 0x01, 0x10, 350,
35862306a36Sopenharmony_ci		       100),
35962306a36Sopenharmony_ci	HI6421_BUCK345(BUCK3, hi6421_buck3, buck_3_voltages, 0x13, 0x07, 0x12,
36062306a36Sopenharmony_ci		       0x01, 20000, 0x10),
36162306a36Sopenharmony_ci	HI6421_BUCK345(BUCK4, hi6421_buck4, buck_4_voltages, 0x15, 0x07, 0x14,
36262306a36Sopenharmony_ci		       0x01, 20000, 0x10),
36362306a36Sopenharmony_ci	HI6421_BUCK345(BUCK5, hi6421_buck5, buck_5_voltages, 0x17, 0x07, 0x16,
36462306a36Sopenharmony_ci		       0x01, 20000, 0x10),
36562306a36Sopenharmony_ci};
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic int hi6421_regulator_enable(struct regulator_dev *rdev)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	struct hi6421_regulator_pdata *pdata = rdev_get_drvdata(rdev);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	/* hi6421 spec requires regulator enablement must be serialized:
37262306a36Sopenharmony_ci	 *  - Because when BUCK, LDO switching from off to on, it will have
37362306a36Sopenharmony_ci	 *    a huge instantaneous current; so you can not turn on two or
37462306a36Sopenharmony_ci	 *    more LDO or BUCKs simultaneously, or it may burn the chip.
37562306a36Sopenharmony_ci	 */
37662306a36Sopenharmony_ci	mutex_lock(&pdata->lock);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	/* call regulator regmap helper */
37962306a36Sopenharmony_ci	regulator_enable_regmap(rdev);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	mutex_unlock(&pdata->lock);
38262306a36Sopenharmony_ci	return 0;
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_cistatic unsigned int hi6421_regulator_ldo_get_mode(struct regulator_dev *rdev)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	struct hi6421_regulator_info *info;
38862306a36Sopenharmony_ci	unsigned int reg_val;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	info = container_of(rdev->desc, struct hi6421_regulator_info, desc);
39162306a36Sopenharmony_ci	regmap_read(rdev->regmap, rdev->desc->enable_reg, &reg_val);
39262306a36Sopenharmony_ci	if (reg_val & info->mode_mask)
39362306a36Sopenharmony_ci		return REGULATOR_MODE_IDLE;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	return REGULATOR_MODE_NORMAL;
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic unsigned int hi6421_regulator_buck_get_mode(struct regulator_dev *rdev)
39962306a36Sopenharmony_ci{
40062306a36Sopenharmony_ci	struct hi6421_regulator_info *info;
40162306a36Sopenharmony_ci	unsigned int reg_val;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	info = container_of(rdev->desc, struct hi6421_regulator_info, desc);
40462306a36Sopenharmony_ci	regmap_read(rdev->regmap, rdev->desc->enable_reg, &reg_val);
40562306a36Sopenharmony_ci	if (reg_val & info->mode_mask)
40662306a36Sopenharmony_ci		return REGULATOR_MODE_STANDBY;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	return REGULATOR_MODE_NORMAL;
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_cistatic int hi6421_regulator_ldo_set_mode(struct regulator_dev *rdev,
41262306a36Sopenharmony_ci						unsigned int mode)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	struct hi6421_regulator_info *info;
41562306a36Sopenharmony_ci	unsigned int new_mode;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	info = container_of(rdev->desc, struct hi6421_regulator_info, desc);
41862306a36Sopenharmony_ci	switch (mode) {
41962306a36Sopenharmony_ci	case REGULATOR_MODE_NORMAL:
42062306a36Sopenharmony_ci		new_mode = 0;
42162306a36Sopenharmony_ci		break;
42262306a36Sopenharmony_ci	case REGULATOR_MODE_IDLE:
42362306a36Sopenharmony_ci		new_mode = info->mode_mask;
42462306a36Sopenharmony_ci		break;
42562306a36Sopenharmony_ci	default:
42662306a36Sopenharmony_ci		return -EINVAL;
42762306a36Sopenharmony_ci	}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	/* set mode */
43062306a36Sopenharmony_ci	regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
43162306a36Sopenharmony_ci			   info->mode_mask, new_mode);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	return 0;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic int hi6421_regulator_buck_set_mode(struct regulator_dev *rdev,
43762306a36Sopenharmony_ci						unsigned int mode)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	struct hi6421_regulator_info *info;
44062306a36Sopenharmony_ci	unsigned int new_mode;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	info = container_of(rdev->desc, struct hi6421_regulator_info, desc);
44362306a36Sopenharmony_ci	switch (mode) {
44462306a36Sopenharmony_ci	case REGULATOR_MODE_NORMAL:
44562306a36Sopenharmony_ci		new_mode = 0;
44662306a36Sopenharmony_ci		break;
44762306a36Sopenharmony_ci	case REGULATOR_MODE_STANDBY:
44862306a36Sopenharmony_ci		new_mode = info->mode_mask;
44962306a36Sopenharmony_ci		break;
45062306a36Sopenharmony_ci	default:
45162306a36Sopenharmony_ci		return -EINVAL;
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	/* set mode */
45562306a36Sopenharmony_ci	regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
45662306a36Sopenharmony_ci			   info->mode_mask, new_mode);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	return 0;
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic unsigned int
46262306a36Sopenharmony_cihi6421_regulator_ldo_get_optimum_mode(struct regulator_dev *rdev,
46362306a36Sopenharmony_ci			int input_uV, int output_uV, int load_uA)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	struct hi6421_regulator_info *info;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	info = container_of(rdev->desc, struct hi6421_regulator_info, desc);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	if (load_uA > info->eco_microamp)
47062306a36Sopenharmony_ci		return REGULATOR_MODE_NORMAL;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	return REGULATOR_MODE_IDLE;
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic const struct regulator_ops hi6421_ldo_ops = {
47662306a36Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
47762306a36Sopenharmony_ci	.enable = hi6421_regulator_enable,
47862306a36Sopenharmony_ci	.disable = regulator_disable_regmap,
47962306a36Sopenharmony_ci	.list_voltage = regulator_list_voltage_table,
48062306a36Sopenharmony_ci	.map_voltage = regulator_map_voltage_ascend,
48162306a36Sopenharmony_ci	.get_voltage_sel = regulator_get_voltage_sel_regmap,
48262306a36Sopenharmony_ci	.set_voltage_sel = regulator_set_voltage_sel_regmap,
48362306a36Sopenharmony_ci	.get_mode = hi6421_regulator_ldo_get_mode,
48462306a36Sopenharmony_ci	.set_mode = hi6421_regulator_ldo_set_mode,
48562306a36Sopenharmony_ci	.get_optimum_mode = hi6421_regulator_ldo_get_optimum_mode,
48662306a36Sopenharmony_ci};
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_cistatic const struct regulator_ops hi6421_ldo_linear_ops = {
48962306a36Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
49062306a36Sopenharmony_ci	.enable = hi6421_regulator_enable,
49162306a36Sopenharmony_ci	.disable = regulator_disable_regmap,
49262306a36Sopenharmony_ci	.list_voltage = regulator_list_voltage_linear,
49362306a36Sopenharmony_ci	.map_voltage = regulator_map_voltage_linear,
49462306a36Sopenharmony_ci	.get_voltage_sel = regulator_get_voltage_sel_regmap,
49562306a36Sopenharmony_ci	.set_voltage_sel = regulator_set_voltage_sel_regmap,
49662306a36Sopenharmony_ci	.get_mode = hi6421_regulator_ldo_get_mode,
49762306a36Sopenharmony_ci	.set_mode = hi6421_regulator_ldo_set_mode,
49862306a36Sopenharmony_ci	.get_optimum_mode = hi6421_regulator_ldo_get_optimum_mode,
49962306a36Sopenharmony_ci};
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic const struct regulator_ops hi6421_ldo_linear_range_ops = {
50262306a36Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
50362306a36Sopenharmony_ci	.enable = hi6421_regulator_enable,
50462306a36Sopenharmony_ci	.disable = regulator_disable_regmap,
50562306a36Sopenharmony_ci	.list_voltage = regulator_list_voltage_linear_range,
50662306a36Sopenharmony_ci	.map_voltage = regulator_map_voltage_linear_range,
50762306a36Sopenharmony_ci	.get_voltage_sel = regulator_get_voltage_sel_regmap,
50862306a36Sopenharmony_ci	.set_voltage_sel = regulator_set_voltage_sel_regmap,
50962306a36Sopenharmony_ci	.get_mode = hi6421_regulator_ldo_get_mode,
51062306a36Sopenharmony_ci	.set_mode = hi6421_regulator_ldo_set_mode,
51162306a36Sopenharmony_ci	.get_optimum_mode = hi6421_regulator_ldo_get_optimum_mode,
51262306a36Sopenharmony_ci};
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_cistatic const struct regulator_ops hi6421_buck012_ops = {
51562306a36Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
51662306a36Sopenharmony_ci	.enable = hi6421_regulator_enable,
51762306a36Sopenharmony_ci	.disable = regulator_disable_regmap,
51862306a36Sopenharmony_ci	.list_voltage = regulator_list_voltage_linear,
51962306a36Sopenharmony_ci	.map_voltage = regulator_map_voltage_linear,
52062306a36Sopenharmony_ci	.get_voltage_sel = regulator_get_voltage_sel_regmap,
52162306a36Sopenharmony_ci	.set_voltage_sel = regulator_set_voltage_sel_regmap,
52262306a36Sopenharmony_ci	.get_mode = hi6421_regulator_buck_get_mode,
52362306a36Sopenharmony_ci	.set_mode = hi6421_regulator_buck_set_mode,
52462306a36Sopenharmony_ci};
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic const struct regulator_ops hi6421_buck345_ops = {
52762306a36Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
52862306a36Sopenharmony_ci	.enable = hi6421_regulator_enable,
52962306a36Sopenharmony_ci	.disable = regulator_disable_regmap,
53062306a36Sopenharmony_ci	.list_voltage = regulator_list_voltage_table,
53162306a36Sopenharmony_ci	.map_voltage = regulator_map_voltage_ascend,
53262306a36Sopenharmony_ci	.get_voltage_sel = regulator_get_voltage_sel_regmap,
53362306a36Sopenharmony_ci	.set_voltage_sel = regulator_set_voltage_sel_regmap,
53462306a36Sopenharmony_ci	.get_mode = hi6421_regulator_buck_get_mode,
53562306a36Sopenharmony_ci	.set_mode = hi6421_regulator_buck_set_mode,
53662306a36Sopenharmony_ci};
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_cistatic int hi6421_regulator_probe(struct platform_device *pdev)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	struct hi6421_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
54162306a36Sopenharmony_ci	struct hi6421_regulator_pdata *pdata;
54262306a36Sopenharmony_ci	struct hi6421_regulator_info *info;
54362306a36Sopenharmony_ci	struct regulator_config config = { };
54462306a36Sopenharmony_ci	struct regulator_dev *rdev;
54562306a36Sopenharmony_ci	int i;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
54862306a36Sopenharmony_ci	if (!pdata)
54962306a36Sopenharmony_ci		return -ENOMEM;
55062306a36Sopenharmony_ci	mutex_init(&pdata->lock);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(hi6421_regulator_info); i++) {
55362306a36Sopenharmony_ci		/* assign per-regulator data */
55462306a36Sopenharmony_ci		info = &hi6421_regulator_info[i];
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci		config.dev = pdev->dev.parent;
55762306a36Sopenharmony_ci		config.driver_data = pdata;
55862306a36Sopenharmony_ci		config.regmap = pmic->regmap;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci		rdev = devm_regulator_register(&pdev->dev, &info->desc,
56162306a36Sopenharmony_ci					       &config);
56262306a36Sopenharmony_ci		if (IS_ERR(rdev)) {
56362306a36Sopenharmony_ci			dev_err(&pdev->dev, "failed to register regulator %s\n",
56462306a36Sopenharmony_ci				info->desc.name);
56562306a36Sopenharmony_ci			return PTR_ERR(rdev);
56662306a36Sopenharmony_ci		}
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	return 0;
57062306a36Sopenharmony_ci}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_cistatic const struct platform_device_id hi6421_regulator_table[] = {
57362306a36Sopenharmony_ci	{ .name = "hi6421-regulator" },
57462306a36Sopenharmony_ci	{},
57562306a36Sopenharmony_ci};
57662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, hi6421_regulator_table);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_cistatic struct platform_driver hi6421_regulator_driver = {
57962306a36Sopenharmony_ci	.id_table = hi6421_regulator_table,
58062306a36Sopenharmony_ci	.driver = {
58162306a36Sopenharmony_ci		.name	= "hi6421-regulator",
58262306a36Sopenharmony_ci		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
58362306a36Sopenharmony_ci	},
58462306a36Sopenharmony_ci	.probe	= hi6421_regulator_probe,
58562306a36Sopenharmony_ci};
58662306a36Sopenharmony_cimodule_platform_driver(hi6421_regulator_driver);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ciMODULE_AUTHOR("Guodong Xu <guodong.xu@linaro.org>");
58962306a36Sopenharmony_ciMODULE_DESCRIPTION("Hi6421 regulator driver");
59062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
591