162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#include <linux/bits.h>
462306a36Sopenharmony_ci#include <linux/kernel.h>
562306a36Sopenharmony_ci#include <linux/module.h>
662306a36Sopenharmony_ci#include <linux/of.h>
762306a36Sopenharmony_ci#include <linux/platform_device.h>
862306a36Sopenharmony_ci#include <linux/regmap.h>
962306a36Sopenharmony_ci#include <linux/regulator/driver.h>
1062306a36Sopenharmony_ci#include <linux/regulator/machine.h>
1162306a36Sopenharmony_ci#include <linux/regulator/of_regulator.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define RT5120_REG_PGSTAT	0x03
1462306a36Sopenharmony_ci#define RT5120_REG_CH1VID	0x06
1562306a36Sopenharmony_ci#define RT5120_REG_CH1SLPVID	0x07
1662306a36Sopenharmony_ci#define RT5120_REG_ENABLE	0x08
1762306a36Sopenharmony_ci#define RT5120_REG_MODECTL	0x09
1862306a36Sopenharmony_ci#define RT5120_REG_UVOVPROT	0x0A
1962306a36Sopenharmony_ci#define RT5120_REG_SLPCTL	0x0C
2062306a36Sopenharmony_ci#define RT5120_REG_INTSTAT	0x1E
2162306a36Sopenharmony_ci#define RT5120_REG_DISCHG	0x1F
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define RT5120_OUTPG_MASK(rid)	BIT(rid + 1)
2462306a36Sopenharmony_ci#define RT5120_OUTUV_MASK(rid)	BIT(rid + 9)
2562306a36Sopenharmony_ci#define RT5120_OUTOV_MASK(rid)	BIT(rid + 16)
2662306a36Sopenharmony_ci#define RT5120_CH1VID_MASK	GENMASK(6, 0)
2762306a36Sopenharmony_ci#define RT5120_RIDEN_MASK(rid)	BIT(rid + 1)
2862306a36Sopenharmony_ci#define RT5120_RADEN_MASK(rid)	BIT(rid)
2962306a36Sopenharmony_ci#define RT5120_FPWM_MASK(rid)	BIT(rid + 1)
3062306a36Sopenharmony_ci#define RT5120_UVHICCUP_MASK	BIT(1)
3162306a36Sopenharmony_ci#define RT5120_OVHICCUP_MASK	BIT(0)
3262306a36Sopenharmony_ci#define RT5120_HOTDIE_MASK	BIT(1)
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define RT5120_BUCK1_MINUV	600000
3562306a36Sopenharmony_ci#define RT5120_BUCK1_MAXUV	1393750
3662306a36Sopenharmony_ci#define RT5120_BUCK1_STEPUV	6250
3762306a36Sopenharmony_ci#define RT5120_BUCK1_NUM_VOLT	0x80
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define RT5120_AUTO_MODE	0
4062306a36Sopenharmony_ci#define RT5120_FPWM_MODE	1
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cienum {
4362306a36Sopenharmony_ci	RT5120_REGULATOR_BUCK1 = 0,
4462306a36Sopenharmony_ci	RT5120_REGULATOR_BUCK2,
4562306a36Sopenharmony_ci	RT5120_REGULATOR_BUCK3,
4662306a36Sopenharmony_ci	RT5120_REGULATOR_BUCK4,
4762306a36Sopenharmony_ci	RT5120_REGULATOR_LDO,
4862306a36Sopenharmony_ci	RT5120_REGULATOR_EXTEN,
4962306a36Sopenharmony_ci	RT5120_MAX_REGULATOR
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistruct rt5120_priv {
5362306a36Sopenharmony_ci	struct device *dev;
5462306a36Sopenharmony_ci	struct regmap *regmap;
5562306a36Sopenharmony_ci	struct regulator_desc rdesc[RT5120_MAX_REGULATOR];
5662306a36Sopenharmony_ci};
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic int rt5120_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	struct regmap *regmap = rdev_get_regmap(rdev);
6162306a36Sopenharmony_ci	int rid = rdev_get_id(rdev);
6262306a36Sopenharmony_ci	unsigned int mask = RT5120_FPWM_MASK(rid), val;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	switch (mode) {
6562306a36Sopenharmony_ci	case REGULATOR_MODE_NORMAL:
6662306a36Sopenharmony_ci		val = 0;
6762306a36Sopenharmony_ci		break;
6862306a36Sopenharmony_ci	case REGULATOR_MODE_FAST:
6962306a36Sopenharmony_ci		val = RT5120_FPWM_MASK(rid);
7062306a36Sopenharmony_ci		break;
7162306a36Sopenharmony_ci	default:
7262306a36Sopenharmony_ci		return -EINVAL;
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	return regmap_update_bits(regmap, RT5120_REG_MODECTL, mask, val);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic unsigned int rt5120_buck_get_mode(struct regulator_dev *rdev)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	struct regmap *regmap = rdev_get_regmap(rdev);
8162306a36Sopenharmony_ci	int ret, rid = rdev_get_id(rdev);
8262306a36Sopenharmony_ci	unsigned int val;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	ret = regmap_read(regmap, RT5120_REG_MODECTL, &val);
8562306a36Sopenharmony_ci	if (ret)
8662306a36Sopenharmony_ci		return REGULATOR_MODE_INVALID;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	if (val & RT5120_FPWM_MASK(rid))
8962306a36Sopenharmony_ci		return REGULATOR_MODE_FAST;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	return REGULATOR_MODE_NORMAL;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic int rt5120_regulator_get_error_flags(struct regulator_dev *rdev,
9562306a36Sopenharmony_ci					    unsigned int *flags)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	struct regmap *regmap = rdev_get_regmap(rdev);
9862306a36Sopenharmony_ci	unsigned int stat, hd_stat, cur_flags = 0;
9962306a36Sopenharmony_ci	int rid = rdev_get_id(rdev), ret;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	/*
10262306a36Sopenharmony_ci	 * reg 0x03/0x04/0x05 to indicate PG/UV/OV
10362306a36Sopenharmony_ci	 * use block read to descrease I/O xfer time
10462306a36Sopenharmony_ci	 */
10562306a36Sopenharmony_ci	ret = regmap_raw_read(regmap, RT5120_REG_PGSTAT, &stat, 3);
10662306a36Sopenharmony_ci	if (ret)
10762306a36Sopenharmony_ci		return ret;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	ret = regmap_read(regmap, RT5120_REG_INTSTAT, &hd_stat);
11062306a36Sopenharmony_ci	if (ret)
11162306a36Sopenharmony_ci		return ret;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	if (!(stat & RT5120_OUTPG_MASK(rid))) {
11462306a36Sopenharmony_ci		if (stat & RT5120_OUTUV_MASK(rid))
11562306a36Sopenharmony_ci			cur_flags |= REGULATOR_ERROR_UNDER_VOLTAGE;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci		if (stat & RT5120_OUTOV_MASK(rid))
11862306a36Sopenharmony_ci			cur_flags |= REGULATOR_ERROR_REGULATION_OUT;
11962306a36Sopenharmony_ci	}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (hd_stat & RT5120_HOTDIE_MASK)
12262306a36Sopenharmony_ci		cur_flags |= REGULATOR_ERROR_OVER_TEMP;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	*flags = cur_flags;
12562306a36Sopenharmony_ci	return 0;
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic int rt5120_buck1_set_suspend_voltage(struct regulator_dev *rdev, int uV)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	struct regmap *regmap = rdev_get_regmap(rdev);
13162306a36Sopenharmony_ci	int sel;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	if (uV < RT5120_BUCK1_MINUV || uV > RT5120_BUCK1_MAXUV)
13462306a36Sopenharmony_ci		return -EINVAL;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	sel = (uV - RT5120_BUCK1_MINUV) / RT5120_BUCK1_STEPUV;
13762306a36Sopenharmony_ci	return regmap_write(regmap, RT5120_REG_CH1SLPVID, sel);
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic int rt5120_regulator_set_suspend_enable(struct regulator_dev *rdev)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	struct regmap *regmap = rdev_get_regmap(rdev);
14362306a36Sopenharmony_ci	int rid = rdev_get_id(rdev);
14462306a36Sopenharmony_ci	unsigned int mask = RT5120_RIDEN_MASK(rid);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	return regmap_update_bits(regmap, RT5120_REG_SLPCTL, mask, mask);
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic int rt5120_regulator_set_suspend_disable(struct regulator_dev *rdev)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	struct regmap *regmap = rdev_get_regmap(rdev);
15262306a36Sopenharmony_ci	int rid = rdev_get_id(rdev);
15362306a36Sopenharmony_ci	unsigned int mask = RT5120_RIDEN_MASK(rid);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	return regmap_update_bits(regmap, RT5120_REG_SLPCTL, mask, 0);
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic const struct regulator_ops rt5120_buck1_ops = {
15962306a36Sopenharmony_ci	.enable = regulator_enable_regmap,
16062306a36Sopenharmony_ci	.disable = regulator_disable_regmap,
16162306a36Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
16262306a36Sopenharmony_ci	.list_voltage = regulator_list_voltage_linear,
16362306a36Sopenharmony_ci	.set_voltage_sel = regulator_set_voltage_sel_regmap,
16462306a36Sopenharmony_ci	.get_voltage_sel = regulator_get_voltage_sel_regmap,
16562306a36Sopenharmony_ci	.set_active_discharge = regulator_set_active_discharge_regmap,
16662306a36Sopenharmony_ci	.set_mode = rt5120_buck_set_mode,
16762306a36Sopenharmony_ci	.get_mode = rt5120_buck_get_mode,
16862306a36Sopenharmony_ci	.get_error_flags = rt5120_regulator_get_error_flags,
16962306a36Sopenharmony_ci	.set_suspend_voltage = rt5120_buck1_set_suspend_voltage,
17062306a36Sopenharmony_ci	.set_suspend_enable = rt5120_regulator_set_suspend_enable,
17162306a36Sopenharmony_ci	.set_suspend_disable = rt5120_regulator_set_suspend_disable,
17262306a36Sopenharmony_ci};
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic const struct regulator_ops rt5120_buck234_ops = {
17562306a36Sopenharmony_ci	.enable = regulator_enable_regmap,
17662306a36Sopenharmony_ci	.disable = regulator_disable_regmap,
17762306a36Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
17862306a36Sopenharmony_ci	.set_active_discharge = regulator_set_active_discharge_regmap,
17962306a36Sopenharmony_ci	.set_mode = rt5120_buck_set_mode,
18062306a36Sopenharmony_ci	.get_mode = rt5120_buck_get_mode,
18162306a36Sopenharmony_ci	.get_error_flags = rt5120_regulator_get_error_flags,
18262306a36Sopenharmony_ci	.set_suspend_enable = rt5120_regulator_set_suspend_enable,
18362306a36Sopenharmony_ci	.set_suspend_disable = rt5120_regulator_set_suspend_disable,
18462306a36Sopenharmony_ci};
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic const struct regulator_ops rt5120_ldo_ops = {
18762306a36Sopenharmony_ci	.enable = regulator_enable_regmap,
18862306a36Sopenharmony_ci	.disable = regulator_disable_regmap,
18962306a36Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
19062306a36Sopenharmony_ci	.set_active_discharge = regulator_set_active_discharge_regmap,
19162306a36Sopenharmony_ci	.get_error_flags = rt5120_regulator_get_error_flags,
19262306a36Sopenharmony_ci	.set_suspend_enable = rt5120_regulator_set_suspend_enable,
19362306a36Sopenharmony_ci	.set_suspend_disable = rt5120_regulator_set_suspend_disable,
19462306a36Sopenharmony_ci};
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistatic const struct regulator_ops rt5120_exten_ops = {
19762306a36Sopenharmony_ci	.enable = regulator_enable_regmap,
19862306a36Sopenharmony_ci	.disable = regulator_disable_regmap,
19962306a36Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
20062306a36Sopenharmony_ci	.set_suspend_enable = rt5120_regulator_set_suspend_enable,
20162306a36Sopenharmony_ci	.set_suspend_disable = rt5120_regulator_set_suspend_disable,
20262306a36Sopenharmony_ci};
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic unsigned int rt5120_buck_of_map_mode(unsigned int mode)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	switch (mode) {
20762306a36Sopenharmony_ci	case RT5120_AUTO_MODE:
20862306a36Sopenharmony_ci		return REGULATOR_MODE_NORMAL;
20962306a36Sopenharmony_ci	case RT5120_FPWM_MODE:
21062306a36Sopenharmony_ci		return REGULATOR_MODE_FAST;
21162306a36Sopenharmony_ci	default:
21262306a36Sopenharmony_ci		return REGULATOR_MODE_INVALID;
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic void rt5120_fillin_regulator_desc(struct regulator_desc *desc, int rid)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	static const char * const name[] = {
21962306a36Sopenharmony_ci		"buck1", "buck2", "buck3", "buck4", "ldo", "exten" };
22062306a36Sopenharmony_ci	static const char * const sname[] = {
22162306a36Sopenharmony_ci		"vin1", "vin2", "vin3", "vin4", "vinldo", NULL };
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	/* Common regulator property */
22462306a36Sopenharmony_ci	desc->name = name[rid];
22562306a36Sopenharmony_ci	desc->supply_name = sname[rid];
22662306a36Sopenharmony_ci	desc->owner = THIS_MODULE;
22762306a36Sopenharmony_ci	desc->type = REGULATOR_VOLTAGE;
22862306a36Sopenharmony_ci	desc->id = rid;
22962306a36Sopenharmony_ci	desc->enable_reg = RT5120_REG_ENABLE;
23062306a36Sopenharmony_ci	desc->enable_mask = RT5120_RIDEN_MASK(rid);
23162306a36Sopenharmony_ci	desc->active_discharge_reg = RT5120_REG_DISCHG;
23262306a36Sopenharmony_ci	desc->active_discharge_mask = RT5120_RADEN_MASK(rid);
23362306a36Sopenharmony_ci	desc->active_discharge_on = RT5120_RADEN_MASK(rid);
23462306a36Sopenharmony_ci	/* Config n_voltages to 1 for all*/
23562306a36Sopenharmony_ci	desc->n_voltages = 1;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	/* Only buck support mode change */
23862306a36Sopenharmony_ci	if (rid >= RT5120_REGULATOR_BUCK1 && rid <= RT5120_REGULATOR_BUCK4)
23962306a36Sopenharmony_ci		desc->of_map_mode = rt5120_buck_of_map_mode;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	/* RID specific property init */
24262306a36Sopenharmony_ci	switch (rid) {
24362306a36Sopenharmony_ci	case RT5120_REGULATOR_BUCK1:
24462306a36Sopenharmony_ci		/* Only buck1 support voltage change by I2C */
24562306a36Sopenharmony_ci		desc->n_voltages = RT5120_BUCK1_NUM_VOLT;
24662306a36Sopenharmony_ci		desc->min_uV = RT5120_BUCK1_MINUV;
24762306a36Sopenharmony_ci		desc->uV_step = RT5120_BUCK1_STEPUV;
24862306a36Sopenharmony_ci		desc->vsel_reg = RT5120_REG_CH1VID,
24962306a36Sopenharmony_ci		desc->vsel_mask = RT5120_CH1VID_MASK,
25062306a36Sopenharmony_ci		desc->ops = &rt5120_buck1_ops;
25162306a36Sopenharmony_ci		break;
25262306a36Sopenharmony_ci	case RT5120_REGULATOR_BUCK2 ... RT5120_REGULATOR_BUCK4:
25362306a36Sopenharmony_ci		desc->ops = &rt5120_buck234_ops;
25462306a36Sopenharmony_ci		break;
25562306a36Sopenharmony_ci	case RT5120_REGULATOR_LDO:
25662306a36Sopenharmony_ci		desc->ops = &rt5120_ldo_ops;
25762306a36Sopenharmony_ci		break;
25862306a36Sopenharmony_ci	default:
25962306a36Sopenharmony_ci		desc->ops = &rt5120_exten_ops;
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic int rt5120_of_parse_cb(struct rt5120_priv *priv, int rid,
26462306a36Sopenharmony_ci			      struct of_regulator_match *match)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	struct regulator_desc *desc = priv->rdesc + rid;
26762306a36Sopenharmony_ci	struct regulator_init_data *init_data = match->init_data;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	if (!init_data || rid == RT5120_REGULATOR_BUCK1)
27062306a36Sopenharmony_ci		return 0;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	if (init_data->constraints.min_uV != init_data->constraints.max_uV) {
27362306a36Sopenharmony_ci		dev_err(priv->dev, "Variable voltage for fixed regulator\n");
27462306a36Sopenharmony_ci		return -EINVAL;
27562306a36Sopenharmony_ci	}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	desc->fixed_uV = init_data->constraints.min_uV;
27862306a36Sopenharmony_ci	return 0;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic struct of_regulator_match rt5120_regu_match[RT5120_MAX_REGULATOR] = {
28262306a36Sopenharmony_ci	[RT5120_REGULATOR_BUCK1] = { .name = "buck1", },
28362306a36Sopenharmony_ci	[RT5120_REGULATOR_BUCK2] = { .name = "buck2", },
28462306a36Sopenharmony_ci	[RT5120_REGULATOR_BUCK3] = { .name = "buck3", },
28562306a36Sopenharmony_ci	[RT5120_REGULATOR_BUCK4] = { .name = "buck4", },
28662306a36Sopenharmony_ci	[RT5120_REGULATOR_LDO] = { .name = "ldo", },
28762306a36Sopenharmony_ci	[RT5120_REGULATOR_EXTEN] = { .name = "exten", }
28862306a36Sopenharmony_ci};
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic int rt5120_parse_regulator_dt_data(struct rt5120_priv *priv)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	struct device *dev = priv->dev->parent;
29362306a36Sopenharmony_ci	struct device_node *reg_node;
29462306a36Sopenharmony_ci	int i, ret;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	for (i = 0; i < RT5120_MAX_REGULATOR; i++) {
29762306a36Sopenharmony_ci		rt5120_fillin_regulator_desc(priv->rdesc + i, i);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci		rt5120_regu_match[i].desc = priv->rdesc + i;
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	reg_node = of_get_child_by_name(dev->of_node, "regulators");
30362306a36Sopenharmony_ci	if (!reg_node) {
30462306a36Sopenharmony_ci		dev_err(priv->dev, "Couldn't find 'regulators' node\n");
30562306a36Sopenharmony_ci		return -ENODEV;
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	ret = of_regulator_match(priv->dev, reg_node, rt5120_regu_match,
30962306a36Sopenharmony_ci				 ARRAY_SIZE(rt5120_regu_match));
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	of_node_put(reg_node);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	if (ret < 0) {
31462306a36Sopenharmony_ci		dev_err(priv->dev,
31562306a36Sopenharmony_ci			"Error parsing regulator init data (%d)\n", ret);
31662306a36Sopenharmony_ci		return ret;
31762306a36Sopenharmony_ci	}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	for (i = 0; i < RT5120_MAX_REGULATOR; i++) {
32062306a36Sopenharmony_ci		ret = rt5120_of_parse_cb(priv, i, rt5120_regu_match + i);
32162306a36Sopenharmony_ci		if (ret) {
32262306a36Sopenharmony_ci			dev_err(priv->dev, "Failed in [%d] of_passe_cb\n", i);
32362306a36Sopenharmony_ci			return ret;
32462306a36Sopenharmony_ci		}
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	return 0;
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic int rt5120_device_property_init(struct rt5120_priv *priv)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	struct device *dev = priv->dev->parent;
33362306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
33462306a36Sopenharmony_ci	bool prot_enable;
33562306a36Sopenharmony_ci	unsigned int prot_enable_val = 0;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	/* Assign UV/OV HW protection behavior */
33862306a36Sopenharmony_ci	prot_enable = of_property_read_bool(np,
33962306a36Sopenharmony_ci					    "richtek,enable-undervolt-hiccup");
34062306a36Sopenharmony_ci	if (prot_enable)
34162306a36Sopenharmony_ci		prot_enable_val |= RT5120_UVHICCUP_MASK;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	prot_enable = of_property_read_bool(np,
34462306a36Sopenharmony_ci					    "richtek,enable-overvolt-hiccup");
34562306a36Sopenharmony_ci	if (prot_enable)
34662306a36Sopenharmony_ci		prot_enable_val |= RT5120_OVHICCUP_MASK;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	return regmap_update_bits(priv->regmap, RT5120_REG_UVOVPROT,
34962306a36Sopenharmony_ci				  RT5120_UVHICCUP_MASK | RT5120_OVHICCUP_MASK,
35062306a36Sopenharmony_ci				  prot_enable_val);
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cistatic int rt5120_regulator_probe(struct platform_device *pdev)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	struct rt5120_priv *priv;
35662306a36Sopenharmony_ci	struct regulator_dev *rdev;
35762306a36Sopenharmony_ci	struct regulator_config config = {};
35862306a36Sopenharmony_ci	int i, ret;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
36162306a36Sopenharmony_ci	if (!priv)
36262306a36Sopenharmony_ci		return -ENOMEM;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	priv->dev = &pdev->dev;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	priv->regmap = dev_get_regmap(pdev->dev.parent, NULL);
36762306a36Sopenharmony_ci	if (!priv->regmap) {
36862306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to init regmap\n");
36962306a36Sopenharmony_ci		return -ENODEV;
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	ret = rt5120_device_property_init(priv);
37362306a36Sopenharmony_ci	if (ret) {
37462306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to do property init\n");
37562306a36Sopenharmony_ci		return ret;
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	ret = rt5120_parse_regulator_dt_data(priv);
37962306a36Sopenharmony_ci	if (ret) {
38062306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to parse dt data\n");
38162306a36Sopenharmony_ci		return ret;
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	config.dev = &pdev->dev;
38562306a36Sopenharmony_ci	config.regmap = priv->regmap;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	for (i = 0; i < RT5120_MAX_REGULATOR; i++) {
38862306a36Sopenharmony_ci		config.of_node = rt5120_regu_match[i].of_node;
38962306a36Sopenharmony_ci		config.init_data = rt5120_regu_match[i].init_data;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci		rdev = devm_regulator_register(&pdev->dev, priv->rdesc + i,
39262306a36Sopenharmony_ci					       &config);
39362306a36Sopenharmony_ci		if (IS_ERR(rdev)) {
39462306a36Sopenharmony_ci			dev_err(&pdev->dev,
39562306a36Sopenharmony_ci				"Failed to register regulator [%d]\n", i);
39662306a36Sopenharmony_ci			return PTR_ERR(rdev);
39762306a36Sopenharmony_ci		}
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	return 0;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic const struct platform_device_id rt5120_regulator_dev_table[] = {
40462306a36Sopenharmony_ci	{ "rt5120-regulator", 0 },
40562306a36Sopenharmony_ci	{}
40662306a36Sopenharmony_ci};
40762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, rt5120_regulator_dev_table);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cistatic struct platform_driver rt5120_regulator_driver = {
41062306a36Sopenharmony_ci	.driver = {
41162306a36Sopenharmony_ci		.name = "rt5120-regulator",
41262306a36Sopenharmony_ci		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
41362306a36Sopenharmony_ci	},
41462306a36Sopenharmony_ci	.id_table = rt5120_regulator_dev_table,
41562306a36Sopenharmony_ci	.probe = rt5120_regulator_probe,
41662306a36Sopenharmony_ci};
41762306a36Sopenharmony_cimodule_platform_driver(rt5120_regulator_driver);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ciMODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
42062306a36Sopenharmony_ciMODULE_DESCRIPTION("Richtek RT5120 regulator driver");
42162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
422