1760423dfSChiYuan Huang // SPDX-License-Identifier: GPL-2.0+
2760423dfSChiYuan Huang 
3760423dfSChiYuan Huang #include <dt-bindings/regulator/richtek,rt5190a-regulator.h>
4760423dfSChiYuan Huang #include <linux/bits.h>
5760423dfSChiYuan Huang #include <linux/i2c.h>
6760423dfSChiYuan Huang #include <linux/interrupt.h>
7760423dfSChiYuan Huang #include <linux/kernel.h>
8760423dfSChiYuan Huang #include <linux/module.h>
9760423dfSChiYuan Huang #include <linux/of.h>
10760423dfSChiYuan Huang #include <linux/property.h>
11760423dfSChiYuan Huang #include <linux/regmap.h>
12760423dfSChiYuan Huang #include <linux/regulator/driver.h>
13760423dfSChiYuan Huang #include <linux/regulator/machine.h>
14760423dfSChiYuan Huang #include <linux/regulator/of_regulator.h>
15760423dfSChiYuan Huang 
16760423dfSChiYuan Huang #define RT5190A_REG_MANUFACTURE		0x00
17760423dfSChiYuan Huang #define RT5190A_REG_BUCK2VSEL		0x04
18760423dfSChiYuan Huang #define RT5190A_REG_BUCK3VSEL		0x05
19760423dfSChiYuan Huang #define RT5190A_REG_DCDCCNTL		0x06
20760423dfSChiYuan Huang #define RT5190A_REG_ENABLE		0x07
21760423dfSChiYuan Huang #define RT5190A_REG_DISCHARGE		0x09
22760423dfSChiYuan Huang #define RT5190A_REG_PROTMODE		0x0A
23760423dfSChiYuan Huang #define RT5190A_REG_MUTECNTL		0x0B
24760423dfSChiYuan Huang #define RT5190A_REG_PGSTAT		0x0F
25760423dfSChiYuan Huang #define RT5190A_REG_OVINT		0x10
26760423dfSChiYuan Huang #define RT5190A_REG_HOTDIEMASK		0x17
27760423dfSChiYuan Huang 
28760423dfSChiYuan Huang #define RT5190A_VSEL_MASK		GENMASK(6, 0)
29760423dfSChiYuan Huang #define RT5190A_RID_BITMASK(rid)	BIT(rid + 1)
30760423dfSChiYuan Huang #define RT5190A_BUCK1_DISCHG_MASK	GENMASK(1, 0)
31760423dfSChiYuan Huang #define RT5190A_BUCK1_DISCHG_ONVAL	0x01
32760423dfSChiYuan Huang #define RT5190A_OVERVOLT_MASK		GENMASK(7, 0)
33760423dfSChiYuan Huang #define RT5190A_UNDERVOLT_MASK		GENMASK(15, 8)
34760423dfSChiYuan Huang #define RT5190A_CH234OT_MASK		BIT(29)
35760423dfSChiYuan Huang #define RT5190A_CHIPOT_MASK		BIT(28)
36760423dfSChiYuan Huang 
37760423dfSChiYuan Huang #define RT5190A_BUCK23_MINUV		600000
38760423dfSChiYuan Huang #define RT5190A_BUCK23_MAXUV		1400000
39760423dfSChiYuan Huang #define RT5190A_BUCK23_STEPUV		10000
40760423dfSChiYuan Huang #define RT5190A_BUCK23_STEPNUM		((1400000 - 600000) / 10000 + 1)
41760423dfSChiYuan Huang 
42760423dfSChiYuan Huang enum {
43760423dfSChiYuan Huang 	RT5190A_IDX_BUCK1 = 0,
44760423dfSChiYuan Huang 	RT5190A_IDX_BUCK2,
45760423dfSChiYuan Huang 	RT5190A_IDX_BUCK3,
46760423dfSChiYuan Huang 	RT5190A_IDX_BUCK4,
47760423dfSChiYuan Huang 	RT5190A_IDX_LDO,
48760423dfSChiYuan Huang 	RT5190A_MAX_IDX
49760423dfSChiYuan Huang };
50760423dfSChiYuan Huang 
51760423dfSChiYuan Huang struct rt5190a_priv {
52760423dfSChiYuan Huang 	struct device *dev;
53760423dfSChiYuan Huang 	struct regmap *regmap;
54760423dfSChiYuan Huang 	struct regulator_desc rdesc[RT5190A_MAX_IDX];
55760423dfSChiYuan Huang 	struct regulator_dev *rdev[RT5190A_MAX_IDX];
56760423dfSChiYuan Huang };
57760423dfSChiYuan Huang 
rt5190a_get_error_flags(struct regulator_dev * rdev,unsigned int * flags)58760423dfSChiYuan Huang static int rt5190a_get_error_flags(struct regulator_dev *rdev,
59760423dfSChiYuan Huang 				   unsigned int *flags)
60760423dfSChiYuan Huang {
61760423dfSChiYuan Huang 	struct regmap *regmap = rdev_get_regmap(rdev);
62760423dfSChiYuan Huang 	int rid = rdev_get_id(rdev);
63760423dfSChiYuan Huang 	unsigned int pgood_stat;
64760423dfSChiYuan Huang 	int ret;
65760423dfSChiYuan Huang 
66760423dfSChiYuan Huang 	ret = regmap_read(regmap, RT5190A_REG_PGSTAT, &pgood_stat);
67760423dfSChiYuan Huang 	if (ret)
68760423dfSChiYuan Huang 		return ret;
69760423dfSChiYuan Huang 
70760423dfSChiYuan Huang 	if (!(pgood_stat & RT5190A_RID_BITMASK(rid)))
71760423dfSChiYuan Huang 		*flags = REGULATOR_ERROR_FAIL;
72760423dfSChiYuan Huang 	else
73760423dfSChiYuan Huang 		*flags = 0;
74760423dfSChiYuan Huang 
75760423dfSChiYuan Huang 	return 0;
76760423dfSChiYuan Huang }
77760423dfSChiYuan Huang 
rt5190a_fixed_buck_set_mode(struct regulator_dev * rdev,unsigned int mode)78760423dfSChiYuan Huang static int rt5190a_fixed_buck_set_mode(struct regulator_dev *rdev,
79760423dfSChiYuan Huang 				       unsigned int mode)
80760423dfSChiYuan Huang {
81760423dfSChiYuan Huang 	struct regmap *regmap = rdev_get_regmap(rdev);
82760423dfSChiYuan Huang 	int rid = rdev_get_id(rdev);
83760423dfSChiYuan Huang 	unsigned int mask = RT5190A_RID_BITMASK(rid), val;
84760423dfSChiYuan Huang 
85760423dfSChiYuan Huang 	switch (mode) {
86760423dfSChiYuan Huang 	case REGULATOR_MODE_FAST:
87760423dfSChiYuan Huang 		val = mask;
88760423dfSChiYuan Huang 		break;
89760423dfSChiYuan Huang 	case REGULATOR_MODE_NORMAL:
90760423dfSChiYuan Huang 		val = 0;
91760423dfSChiYuan Huang 		break;
92760423dfSChiYuan Huang 	default:
93760423dfSChiYuan Huang 		return -EINVAL;
94760423dfSChiYuan Huang 	}
95760423dfSChiYuan Huang 
96760423dfSChiYuan Huang 	return regmap_update_bits(regmap, RT5190A_REG_DCDCCNTL, mask, val);
97760423dfSChiYuan Huang }
98760423dfSChiYuan Huang 
rt5190a_fixed_buck_get_mode(struct regulator_dev * rdev)99760423dfSChiYuan Huang static unsigned int rt5190a_fixed_buck_get_mode(struct regulator_dev *rdev)
100760423dfSChiYuan Huang {
101760423dfSChiYuan Huang 	struct regmap *regmap = rdev_get_regmap(rdev);
102760423dfSChiYuan Huang 	int rid = rdev_get_id(rdev);
103760423dfSChiYuan Huang 	unsigned int val;
104760423dfSChiYuan Huang 	int ret;
105760423dfSChiYuan Huang 
106760423dfSChiYuan Huang 	ret = regmap_read(regmap, RT5190A_REG_DCDCCNTL, &val);
107760423dfSChiYuan Huang 	if (ret) {
108760423dfSChiYuan Huang 		dev_err(&rdev->dev, "Failed to get mode [%d]\n", ret);
109760423dfSChiYuan Huang 		return ret;
110760423dfSChiYuan Huang 	}
111760423dfSChiYuan Huang 
112760423dfSChiYuan Huang 	if (val & RT5190A_RID_BITMASK(rid))
113760423dfSChiYuan Huang 		return REGULATOR_MODE_FAST;
114760423dfSChiYuan Huang 
115760423dfSChiYuan Huang 	return REGULATOR_MODE_NORMAL;
116760423dfSChiYuan Huang }
117760423dfSChiYuan Huang 
118760423dfSChiYuan Huang static const struct regulator_ops rt5190a_ranged_buck_ops = {
119760423dfSChiYuan Huang 	.enable	= regulator_enable_regmap,
120760423dfSChiYuan Huang 	.disable = regulator_disable_regmap,
121760423dfSChiYuan Huang 	.is_enabled = regulator_is_enabled_regmap,
122760423dfSChiYuan Huang 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
123760423dfSChiYuan Huang 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
124760423dfSChiYuan Huang 	.list_voltage = regulator_list_voltage_linear,
125760423dfSChiYuan Huang 	.set_active_discharge = regulator_set_active_discharge_regmap,
126760423dfSChiYuan Huang 	.get_error_flags = rt5190a_get_error_flags,
127760423dfSChiYuan Huang };
128760423dfSChiYuan Huang 
129760423dfSChiYuan Huang static const struct regulator_ops rt5190a_fixed_buck_ops = {
130760423dfSChiYuan Huang 	.enable	= regulator_enable_regmap,
131760423dfSChiYuan Huang 	.disable = regulator_disable_regmap,
132760423dfSChiYuan Huang 	.is_enabled = regulator_is_enabled_regmap,
133760423dfSChiYuan Huang 	.set_active_discharge = regulator_set_active_discharge_regmap,
134760423dfSChiYuan Huang 	.set_mode = rt5190a_fixed_buck_set_mode,
135760423dfSChiYuan Huang 	.get_mode = rt5190a_fixed_buck_get_mode,
136760423dfSChiYuan Huang 	.get_error_flags = rt5190a_get_error_flags,
137760423dfSChiYuan Huang };
138760423dfSChiYuan Huang 
139760423dfSChiYuan Huang static const struct regulator_ops rt5190a_fixed_ldo_ops = {
140760423dfSChiYuan Huang 	.enable	= regulator_enable_regmap,
141760423dfSChiYuan Huang 	.disable = regulator_disable_regmap,
142760423dfSChiYuan Huang 	.is_enabled = regulator_is_enabled_regmap,
143760423dfSChiYuan Huang 	.set_active_discharge = regulator_set_active_discharge_regmap,
144760423dfSChiYuan Huang 	.get_error_flags = rt5190a_get_error_flags,
145760423dfSChiYuan Huang };
146760423dfSChiYuan Huang 
rt5190a_irq_handler(int irq,void * data)147760423dfSChiYuan Huang static irqreturn_t rt5190a_irq_handler(int irq, void *data)
148760423dfSChiYuan Huang {
149760423dfSChiYuan Huang 	struct rt5190a_priv *priv = data;
150760423dfSChiYuan Huang 	__le32 raws;
151760423dfSChiYuan Huang 	unsigned int events, fields;
152760423dfSChiYuan Huang 	static const struct {
153760423dfSChiYuan Huang 		unsigned int bitmask;
154760423dfSChiYuan Huang 		unsigned int report;
155760423dfSChiYuan Huang 	} event_tbl[] = {
156760423dfSChiYuan Huang 		{ RT5190A_OVERVOLT_MASK, REGULATOR_ERROR_REGULATION_OUT },
157760423dfSChiYuan Huang 		{ RT5190A_UNDERVOLT_MASK, REGULATOR_ERROR_UNDER_VOLTAGE }
158760423dfSChiYuan Huang 	};
159760423dfSChiYuan Huang 	int i, j, ret;
160760423dfSChiYuan Huang 
161760423dfSChiYuan Huang 	ret = regmap_raw_read(priv->regmap, RT5190A_REG_OVINT, &raws,
162760423dfSChiYuan Huang 			      sizeof(raws));
163760423dfSChiYuan Huang 	if (ret) {
164760423dfSChiYuan Huang 		dev_err(priv->dev, "Failed to read events\n");
165760423dfSChiYuan Huang 		return IRQ_NONE;
166760423dfSChiYuan Huang 	}
167760423dfSChiYuan Huang 
168760423dfSChiYuan Huang 	events = le32_to_cpu(raws);
169760423dfSChiYuan Huang 
170760423dfSChiYuan Huang 	ret = regmap_raw_write(priv->regmap, RT5190A_REG_OVINT, &raws,
171760423dfSChiYuan Huang 			       sizeof(raws));
172760423dfSChiYuan Huang 	if (ret)
173760423dfSChiYuan Huang 		dev_err(priv->dev, "Failed to write-clear events\n");
174760423dfSChiYuan Huang 
175760423dfSChiYuan Huang 	/* Handle OV,UV events */
176760423dfSChiYuan Huang 	for (i = 0; i < ARRAY_SIZE(event_tbl); i++) {
177760423dfSChiYuan Huang 		fields = events & event_tbl[i].bitmask;
178760423dfSChiYuan Huang 		fields >>= ffs(event_tbl[i].bitmask) - 1;
179760423dfSChiYuan Huang 
180760423dfSChiYuan Huang 		for (j = 0; j < RT5190A_MAX_IDX; j++) {
181760423dfSChiYuan Huang 			if (!(fields & RT5190A_RID_BITMASK(j)))
182760423dfSChiYuan Huang 				continue;
183760423dfSChiYuan Huang 
184760423dfSChiYuan Huang 			regulator_notifier_call_chain(priv->rdev[j],
185760423dfSChiYuan Huang 						      event_tbl[i].report,
186760423dfSChiYuan Huang 						      NULL);
187760423dfSChiYuan Huang 		}
188760423dfSChiYuan Huang 	}
189760423dfSChiYuan Huang 
190760423dfSChiYuan Huang 	/* Handle CH234 OT event */
191760423dfSChiYuan Huang 	if (events & RT5190A_CH234OT_MASK) {
192760423dfSChiYuan Huang 		for (j = RT5190A_IDX_BUCK2; j < RT5190A_IDX_LDO; j++) {
193760423dfSChiYuan Huang 			regulator_notifier_call_chain(priv->rdev[j],
194760423dfSChiYuan Huang 						      REGULATOR_ERROR_OVER_TEMP,
195760423dfSChiYuan Huang 						      NULL);
196760423dfSChiYuan Huang 		}
197760423dfSChiYuan Huang 	}
198760423dfSChiYuan Huang 
199760423dfSChiYuan Huang 	/* Warning if CHIP OT occur */
200760423dfSChiYuan Huang 	if (events & RT5190A_CHIPOT_MASK)
201760423dfSChiYuan Huang 		dev_warn(priv->dev, "CHIP overheat\n");
202760423dfSChiYuan Huang 
203760423dfSChiYuan Huang 	return IRQ_HANDLED;
204760423dfSChiYuan Huang }
205760423dfSChiYuan Huang 
rt5190a_of_map_mode(unsigned int mode)206760423dfSChiYuan Huang static unsigned int rt5190a_of_map_mode(unsigned int mode)
207760423dfSChiYuan Huang {
208760423dfSChiYuan Huang 	switch (mode) {
209760423dfSChiYuan Huang 	case RT5190A_OPMODE_AUTO:
210760423dfSChiYuan Huang 		return REGULATOR_MODE_NORMAL;
211760423dfSChiYuan Huang 	case RT5190A_OPMODE_FPWM:
212760423dfSChiYuan Huang 		return REGULATOR_MODE_FAST;
213760423dfSChiYuan Huang 	default:
214760423dfSChiYuan Huang 		return REGULATOR_MODE_INVALID;
215760423dfSChiYuan Huang 	}
216760423dfSChiYuan Huang }
217760423dfSChiYuan Huang 
rt5190a_of_parse_cb(struct rt5190a_priv * priv,int rid,struct of_regulator_match * match)218760423dfSChiYuan Huang static int rt5190a_of_parse_cb(struct rt5190a_priv *priv, int rid,
219760423dfSChiYuan Huang 			       struct of_regulator_match *match)
220760423dfSChiYuan Huang {
221760423dfSChiYuan Huang 	struct regulator_desc *desc = priv->rdesc + rid;
222760423dfSChiYuan Huang 	struct regulator_init_data *init_data = match->init_data;
223760423dfSChiYuan Huang 	struct device_node *np = match->of_node;
224760423dfSChiYuan Huang 	bool latchup_enable;
225760423dfSChiYuan Huang 	unsigned int mask = RT5190A_RID_BITMASK(rid), val;
226760423dfSChiYuan Huang 
2275f7202d8SChiYuan Huang 	if (!init_data)
2285f7202d8SChiYuan Huang 		return 0;
2295f7202d8SChiYuan Huang 
230760423dfSChiYuan Huang 	switch (rid) {
231760423dfSChiYuan Huang 	case RT5190A_IDX_BUCK1:
232760423dfSChiYuan Huang 	case RT5190A_IDX_BUCK4:
233760423dfSChiYuan Huang 	case RT5190A_IDX_LDO:
234760423dfSChiYuan Huang 		init_data->constraints.apply_uV = 0;
235760423dfSChiYuan Huang 
236760423dfSChiYuan Huang 		if (init_data->constraints.min_uV ==
237760423dfSChiYuan Huang 				init_data->constraints.max_uV)
238760423dfSChiYuan Huang 			desc->fixed_uV = init_data->constraints.min_uV;
239760423dfSChiYuan Huang 		else {
240760423dfSChiYuan Huang 			dev_err(priv->dev,
241760423dfSChiYuan Huang 				"Variable voltage for fixed regulator\n");
242760423dfSChiYuan Huang 			return -EINVAL;
243760423dfSChiYuan Huang 		}
244760423dfSChiYuan Huang 		break;
245760423dfSChiYuan Huang 	default:
246760423dfSChiYuan Huang 		break;
247760423dfSChiYuan Huang 	}
248760423dfSChiYuan Huang 
249760423dfSChiYuan Huang 	latchup_enable = of_property_read_bool(np, "richtek,latchup-enable");
250760423dfSChiYuan Huang 
251760423dfSChiYuan Huang 	/* latchup: 0, default hiccup: 1 */
252760423dfSChiYuan Huang 	val = !latchup_enable ? mask : 0;
253760423dfSChiYuan Huang 
254760423dfSChiYuan Huang 	return regmap_update_bits(priv->regmap, RT5190A_REG_PROTMODE, mask, val);
255760423dfSChiYuan Huang }
256760423dfSChiYuan Huang 
rt5190a_fillin_regulator_desc(struct regulator_desc * desc,int rid)257760423dfSChiYuan Huang static void rt5190a_fillin_regulator_desc(struct regulator_desc *desc, int rid)
258760423dfSChiYuan Huang {
259760423dfSChiYuan Huang 	static const char * const regu_name[] = { "buck1", "buck2",
260760423dfSChiYuan Huang 						  "buck3", "buck4",
261760423dfSChiYuan Huang 						  "ldo" };
262760423dfSChiYuan Huang 	static const char * const supply[] = { NULL, "vin2", "vin3", "vin4",
263760423dfSChiYuan Huang 					       "vinldo" };
264760423dfSChiYuan Huang 
265760423dfSChiYuan Huang 	desc->name = regu_name[rid];
266760423dfSChiYuan Huang 	desc->supply_name = supply[rid];
267760423dfSChiYuan Huang 	desc->owner = THIS_MODULE;
268760423dfSChiYuan Huang 	desc->type = REGULATOR_VOLTAGE;
269760423dfSChiYuan Huang 	desc->id = rid;
270760423dfSChiYuan Huang 	desc->enable_reg = RT5190A_REG_ENABLE;
271760423dfSChiYuan Huang 	desc->enable_mask = RT5190A_RID_BITMASK(rid);
272760423dfSChiYuan Huang 	desc->active_discharge_reg = RT5190A_REG_DISCHARGE;
273760423dfSChiYuan Huang 	desc->active_discharge_mask = RT5190A_RID_BITMASK(rid);
274760423dfSChiYuan Huang 	desc->active_discharge_on = RT5190A_RID_BITMASK(rid);
275760423dfSChiYuan Huang 
276760423dfSChiYuan Huang 	switch (rid) {
277760423dfSChiYuan Huang 	case RT5190A_IDX_BUCK1:
278760423dfSChiYuan Huang 		desc->active_discharge_mask = RT5190A_BUCK1_DISCHG_MASK;
279760423dfSChiYuan Huang 		desc->active_discharge_on = RT5190A_BUCK1_DISCHG_ONVAL;
280760423dfSChiYuan Huang 		desc->n_voltages = 1;
281760423dfSChiYuan Huang 		desc->ops = &rt5190a_fixed_buck_ops;
282760423dfSChiYuan Huang 		desc->of_map_mode = rt5190a_of_map_mode;
283760423dfSChiYuan Huang 		break;
284760423dfSChiYuan Huang 	case RT5190A_IDX_BUCK2:
285760423dfSChiYuan Huang 		desc->vsel_reg = RT5190A_REG_BUCK2VSEL;
286760423dfSChiYuan Huang 		desc->vsel_mask = RT5190A_VSEL_MASK;
287760423dfSChiYuan Huang 		desc->min_uV = RT5190A_BUCK23_MINUV;
288760423dfSChiYuan Huang 		desc->uV_step = RT5190A_BUCK23_STEPUV;
289760423dfSChiYuan Huang 		desc->n_voltages = RT5190A_BUCK23_STEPNUM;
290760423dfSChiYuan Huang 		desc->ops = &rt5190a_ranged_buck_ops;
291760423dfSChiYuan Huang 		break;
292760423dfSChiYuan Huang 	case RT5190A_IDX_BUCK3:
293760423dfSChiYuan Huang 		desc->vsel_reg = RT5190A_REG_BUCK3VSEL;
294760423dfSChiYuan Huang 		desc->vsel_mask = RT5190A_VSEL_MASK;
295760423dfSChiYuan Huang 		desc->min_uV = RT5190A_BUCK23_MINUV;
296760423dfSChiYuan Huang 		desc->uV_step = RT5190A_BUCK23_STEPUV;
297760423dfSChiYuan Huang 		desc->n_voltages = RT5190A_BUCK23_STEPNUM;
298760423dfSChiYuan Huang 		desc->ops = &rt5190a_ranged_buck_ops;
299760423dfSChiYuan Huang 		break;
300760423dfSChiYuan Huang 	case RT5190A_IDX_BUCK4:
301760423dfSChiYuan Huang 		desc->n_voltages = 1;
302760423dfSChiYuan Huang 		desc->ops = &rt5190a_fixed_buck_ops;
303760423dfSChiYuan Huang 		desc->of_map_mode = rt5190a_of_map_mode;
304760423dfSChiYuan Huang 		break;
305760423dfSChiYuan Huang 	case RT5190A_IDX_LDO:
306760423dfSChiYuan Huang 		desc->n_voltages = 1;
307760423dfSChiYuan Huang 		desc->ops = &rt5190a_fixed_ldo_ops;
308760423dfSChiYuan Huang 		break;
309760423dfSChiYuan Huang 	}
310760423dfSChiYuan Huang }
311760423dfSChiYuan Huang 
312760423dfSChiYuan Huang static struct of_regulator_match rt5190a_regulator_match[] = {
313760423dfSChiYuan Huang 	{ .name = "buck1", },
314760423dfSChiYuan Huang 	{ .name = "buck2", },
315760423dfSChiYuan Huang 	{ .name = "buck3", },
316760423dfSChiYuan Huang 	{ .name = "buck4", },
317760423dfSChiYuan Huang 	{ .name = "ldo", }
318760423dfSChiYuan Huang };
319760423dfSChiYuan Huang 
rt5190a_parse_regulator_dt_data(struct rt5190a_priv * priv)320760423dfSChiYuan Huang static int rt5190a_parse_regulator_dt_data(struct rt5190a_priv *priv)
321760423dfSChiYuan Huang {
322760423dfSChiYuan Huang 	struct device_node *regulator_np;
323760423dfSChiYuan Huang 	struct regulator_desc *reg_desc;
324760423dfSChiYuan Huang 	struct of_regulator_match *match;
325760423dfSChiYuan Huang 	int i, ret;
326760423dfSChiYuan Huang 
327760423dfSChiYuan Huang 	for (i = 0; i < RT5190A_MAX_IDX; i++) {
328760423dfSChiYuan Huang 		reg_desc = priv->rdesc + i;
329760423dfSChiYuan Huang 		match = rt5190a_regulator_match + i;
330760423dfSChiYuan Huang 
331760423dfSChiYuan Huang 		rt5190a_fillin_regulator_desc(reg_desc, i);
332760423dfSChiYuan Huang 
333760423dfSChiYuan Huang 		match->desc = reg_desc;
334760423dfSChiYuan Huang 	}
335760423dfSChiYuan Huang 
336760423dfSChiYuan Huang 	regulator_np = of_get_child_by_name(priv->dev->of_node, "regulators");
337760423dfSChiYuan Huang 	if (!regulator_np) {
338760423dfSChiYuan Huang 		dev_err(priv->dev, "Could not find 'regulators' node\n");
339760423dfSChiYuan Huang 		return -ENODEV;
340760423dfSChiYuan Huang 	}
341760423dfSChiYuan Huang 
342760423dfSChiYuan Huang 	ret = of_regulator_match(priv->dev, regulator_np,
343760423dfSChiYuan Huang 				 rt5190a_regulator_match,
344760423dfSChiYuan Huang 				 ARRAY_SIZE(rt5190a_regulator_match));
345760423dfSChiYuan Huang 
346760423dfSChiYuan Huang 	of_node_put(regulator_np);
347760423dfSChiYuan Huang 
348760423dfSChiYuan Huang 	if (ret < 0) {
349760423dfSChiYuan Huang 		dev_err(priv->dev,
350760423dfSChiYuan Huang 			"Error parsing regulator init data: %d\n", ret);
351760423dfSChiYuan Huang 		return ret;
352760423dfSChiYuan Huang 	}
353760423dfSChiYuan Huang 
354760423dfSChiYuan Huang 	for (i = 0; i < RT5190A_MAX_IDX; i++) {
355760423dfSChiYuan Huang 		match = rt5190a_regulator_match + i;
356760423dfSChiYuan Huang 
357760423dfSChiYuan Huang 		ret = rt5190a_of_parse_cb(priv, i, match);
358760423dfSChiYuan Huang 		if (ret) {
359760423dfSChiYuan Huang 			dev_err(priv->dev, "Failed in [%d] of_parse_cb\n", i);
360760423dfSChiYuan Huang 			return ret;
361760423dfSChiYuan Huang 		}
362760423dfSChiYuan Huang 	}
363760423dfSChiYuan Huang 
364760423dfSChiYuan Huang 	return 0;
365760423dfSChiYuan Huang }
366760423dfSChiYuan Huang 
367760423dfSChiYuan Huang static const struct reg_sequence rt5190a_init_patch[] = {
368760423dfSChiYuan Huang 	{ 0x09, 0x3d, },
369760423dfSChiYuan Huang 	{ 0x0a, 0x3e, },
370760423dfSChiYuan Huang 	{ 0x0b, 0x01, },
371760423dfSChiYuan Huang 	{ 0x10, 0xff, },
372760423dfSChiYuan Huang 	{ 0x11, 0xff, },
373760423dfSChiYuan Huang 	{ 0x12, 0xff, },
374760423dfSChiYuan Huang 	{ 0x13, 0xff, },
375760423dfSChiYuan Huang 	{ 0x14, 0, },
376760423dfSChiYuan Huang 	{ 0x15, 0, },
377760423dfSChiYuan Huang 	{ 0x16, 0x3e, },
378760423dfSChiYuan Huang 	{ 0x17, 0, }
379760423dfSChiYuan Huang };
380760423dfSChiYuan Huang 
rt5190a_device_initialize(struct rt5190a_priv * priv)381760423dfSChiYuan Huang static int rt5190a_device_initialize(struct rt5190a_priv *priv)
382760423dfSChiYuan Huang {
383760423dfSChiYuan Huang 	bool mute_enable;
384760423dfSChiYuan Huang 	int ret;
385760423dfSChiYuan Huang 
386760423dfSChiYuan Huang 	ret = regmap_register_patch(priv->regmap, rt5190a_init_patch,
387760423dfSChiYuan Huang 				    ARRAY_SIZE(rt5190a_init_patch));
388760423dfSChiYuan Huang 	if (ret) {
389760423dfSChiYuan Huang 		dev_err(priv->dev, "Failed to do register patch\n");
390760423dfSChiYuan Huang 		return ret;
391760423dfSChiYuan Huang 	}
392760423dfSChiYuan Huang 
393760423dfSChiYuan Huang 	mute_enable = device_property_read_bool(priv->dev,
394760423dfSChiYuan Huang 						"richtek,mute-enable");
395760423dfSChiYuan Huang 
396760423dfSChiYuan Huang 	if (mute_enable) {
397760423dfSChiYuan Huang 		ret = regmap_write(priv->regmap, RT5190A_REG_MUTECNTL, 0x00);
398760423dfSChiYuan Huang 		if (ret) {
399760423dfSChiYuan Huang 			dev_err(priv->dev, "Failed to enable mute function\n");
400760423dfSChiYuan Huang 			return ret;
401760423dfSChiYuan Huang 		}
402760423dfSChiYuan Huang 	}
403760423dfSChiYuan Huang 
404760423dfSChiYuan Huang 	return 0;
405760423dfSChiYuan Huang }
406760423dfSChiYuan Huang 
rt5190a_device_check(struct rt5190a_priv * priv)407760423dfSChiYuan Huang static int rt5190a_device_check(struct rt5190a_priv *priv)
408760423dfSChiYuan Huang {
409760423dfSChiYuan Huang 	u16 devid;
410760423dfSChiYuan Huang 	int ret;
411760423dfSChiYuan Huang 
412760423dfSChiYuan Huang 	ret = regmap_raw_read(priv->regmap, RT5190A_REG_MANUFACTURE, &devid,
413760423dfSChiYuan Huang 			      sizeof(devid));
414760423dfSChiYuan Huang 	if (ret)
415760423dfSChiYuan Huang 		return ret;
416760423dfSChiYuan Huang 
417760423dfSChiYuan Huang 	if (devid) {
418760423dfSChiYuan Huang 		dev_err(priv->dev, "Incorrect device id 0x%04x\n", devid);
419760423dfSChiYuan Huang 		return -ENODEV;
420760423dfSChiYuan Huang 	}
421760423dfSChiYuan Huang 
422760423dfSChiYuan Huang 	return 0;
423760423dfSChiYuan Huang }
424760423dfSChiYuan Huang 
425760423dfSChiYuan Huang static const struct regmap_config rt5190a_regmap_config = {
426760423dfSChiYuan Huang 	.reg_bits = 8,
427760423dfSChiYuan Huang 	.val_bits = 8,
428760423dfSChiYuan Huang 	.max_register = RT5190A_REG_HOTDIEMASK,
429760423dfSChiYuan Huang };
430760423dfSChiYuan Huang 
rt5190a_probe(struct i2c_client * i2c)431760423dfSChiYuan Huang static int rt5190a_probe(struct i2c_client *i2c)
432760423dfSChiYuan Huang {
433760423dfSChiYuan Huang 	struct rt5190a_priv *priv;
434760423dfSChiYuan Huang 	struct regulator_config cfg = {};
435760423dfSChiYuan Huang 	int i, ret;
436760423dfSChiYuan Huang 
437760423dfSChiYuan Huang 	priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
438760423dfSChiYuan Huang 	if (!priv)
439760423dfSChiYuan Huang 		return -ENOMEM;
440760423dfSChiYuan Huang 
441760423dfSChiYuan Huang 	priv->dev = &i2c->dev;
442760423dfSChiYuan Huang 
443760423dfSChiYuan Huang 	priv->regmap = devm_regmap_init_i2c(i2c, &rt5190a_regmap_config);
444760423dfSChiYuan Huang 	if (IS_ERR(priv->regmap)) {
445760423dfSChiYuan Huang 		dev_err(&i2c->dev, "Failed to allocate regmap\n");
446760423dfSChiYuan Huang 		return PTR_ERR(priv->regmap);
447760423dfSChiYuan Huang 	}
448760423dfSChiYuan Huang 
449760423dfSChiYuan Huang 	ret = rt5190a_device_check(priv);
450760423dfSChiYuan Huang 	if (ret) {
451760423dfSChiYuan Huang 		dev_err(&i2c->dev, "Failed to check device %d\n", ret);
452760423dfSChiYuan Huang 		return ret;
453760423dfSChiYuan Huang 	}
454760423dfSChiYuan Huang 
455760423dfSChiYuan Huang 	ret = rt5190a_device_initialize(priv);
456760423dfSChiYuan Huang 	if (ret) {
457760423dfSChiYuan Huang 		dev_err(&i2c->dev, "Failed to initialize the device\n");
458760423dfSChiYuan Huang 		return ret;
459760423dfSChiYuan Huang 	}
460760423dfSChiYuan Huang 
461760423dfSChiYuan Huang 	ret = rt5190a_parse_regulator_dt_data(priv);
462760423dfSChiYuan Huang 	if (ret) {
463760423dfSChiYuan Huang 		dev_err(&i2c->dev, "Failed to parse regulator dt\n");
464760423dfSChiYuan Huang 		return ret;
465760423dfSChiYuan Huang 	}
466760423dfSChiYuan Huang 
467760423dfSChiYuan Huang 	cfg.dev = &i2c->dev;
468760423dfSChiYuan Huang 	cfg.regmap = priv->regmap;
469760423dfSChiYuan Huang 
470760423dfSChiYuan Huang 	for (i = 0; i < RT5190A_MAX_IDX; i++) {
471760423dfSChiYuan Huang 		struct regulator_desc *desc = priv->rdesc + i;
472760423dfSChiYuan Huang 		struct of_regulator_match *match = rt5190a_regulator_match + i;
473760423dfSChiYuan Huang 
474760423dfSChiYuan Huang 		cfg.init_data = match->init_data;
475760423dfSChiYuan Huang 		cfg.of_node = match->of_node;
476760423dfSChiYuan Huang 
477760423dfSChiYuan Huang 		priv->rdev[i] = devm_regulator_register(&i2c->dev, desc, &cfg);
478760423dfSChiYuan Huang 		if (IS_ERR(priv->rdev[i])) {
479760423dfSChiYuan Huang 			dev_err(&i2c->dev, "Failed to register regulator %s\n",
480760423dfSChiYuan Huang 				desc->name);
481760423dfSChiYuan Huang 			return PTR_ERR(priv->rdev[i]);
482760423dfSChiYuan Huang 		}
483760423dfSChiYuan Huang 	}
484760423dfSChiYuan Huang 
485760423dfSChiYuan Huang 	if (i2c->irq) {
486760423dfSChiYuan Huang 		ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
487760423dfSChiYuan Huang 						rt5190a_irq_handler,
488760423dfSChiYuan Huang 						IRQF_ONESHOT,
489760423dfSChiYuan Huang 						dev_name(&i2c->dev), priv);
490760423dfSChiYuan Huang 		if (ret) {
491760423dfSChiYuan Huang 			dev_err(&i2c->dev, "Failed to register interrupt\n");
492760423dfSChiYuan Huang 			return ret;
493760423dfSChiYuan Huang 		}
494760423dfSChiYuan Huang 	}
495760423dfSChiYuan Huang 
496760423dfSChiYuan Huang 	return 0;
497760423dfSChiYuan Huang }
498760423dfSChiYuan Huang 
499760423dfSChiYuan Huang static const struct of_device_id __maybe_unused rt5190a_device_table[] = {
500760423dfSChiYuan Huang 	{ .compatible = "richtek,rt5190a", },
501760423dfSChiYuan Huang 	{}
502760423dfSChiYuan Huang };
503760423dfSChiYuan Huang MODULE_DEVICE_TABLE(of, rt5190a_device_table);
504760423dfSChiYuan Huang 
505760423dfSChiYuan Huang static struct i2c_driver rt5190a_driver = {
506760423dfSChiYuan Huang 	.driver = {
507760423dfSChiYuan Huang 		.name = "rt5190a",
50841cff178SDouglas Anderson 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
509760423dfSChiYuan Huang 		.of_match_table = rt5190a_device_table,
510760423dfSChiYuan Huang 	},
511*964e1865SUwe Kleine-König 	.probe = rt5190a_probe,
512760423dfSChiYuan Huang };
513760423dfSChiYuan Huang module_i2c_driver(rt5190a_driver);
514760423dfSChiYuan Huang 
515760423dfSChiYuan Huang MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
516760423dfSChiYuan Huang MODULE_DESCRIPTION("Richtek RT5190A Regulator Driver");
517760423dfSChiYuan Huang MODULE_LICENSE("GPL v2");
518