xref: /openbmc/linux/drivers/regulator/rt5190a-regulator.c (revision 760423dfad53877b468490758fe7ea968ded9402)
1*760423dfSChiYuan Huang // SPDX-License-Identifier: GPL-2.0+
2*760423dfSChiYuan Huang 
3*760423dfSChiYuan Huang #include <dt-bindings/regulator/richtek,rt5190a-regulator.h>
4*760423dfSChiYuan Huang #include <linux/bits.h>
5*760423dfSChiYuan Huang #include <linux/i2c.h>
6*760423dfSChiYuan Huang #include <linux/interrupt.h>
7*760423dfSChiYuan Huang #include <linux/kernel.h>
8*760423dfSChiYuan Huang #include <linux/module.h>
9*760423dfSChiYuan Huang #include <linux/of.h>
10*760423dfSChiYuan Huang #include <linux/property.h>
11*760423dfSChiYuan Huang #include <linux/regmap.h>
12*760423dfSChiYuan Huang #include <linux/regulator/driver.h>
13*760423dfSChiYuan Huang #include <linux/regulator/machine.h>
14*760423dfSChiYuan Huang #include <linux/regulator/of_regulator.h>
15*760423dfSChiYuan Huang 
16*760423dfSChiYuan Huang #define RT5190A_REG_MANUFACTURE		0x00
17*760423dfSChiYuan Huang #define RT5190A_REG_BUCK2VSEL		0x04
18*760423dfSChiYuan Huang #define RT5190A_REG_BUCK3VSEL		0x05
19*760423dfSChiYuan Huang #define RT5190A_REG_DCDCCNTL		0x06
20*760423dfSChiYuan Huang #define RT5190A_REG_ENABLE		0x07
21*760423dfSChiYuan Huang #define RT5190A_REG_DISCHARGE		0x09
22*760423dfSChiYuan Huang #define RT5190A_REG_PROTMODE		0x0A
23*760423dfSChiYuan Huang #define RT5190A_REG_MUTECNTL		0x0B
24*760423dfSChiYuan Huang #define RT5190A_REG_PGSTAT		0x0F
25*760423dfSChiYuan Huang #define RT5190A_REG_OVINT		0x10
26*760423dfSChiYuan Huang #define RT5190A_REG_HOTDIEMASK		0x17
27*760423dfSChiYuan Huang 
28*760423dfSChiYuan Huang #define RT5190A_VSEL_MASK		GENMASK(6, 0)
29*760423dfSChiYuan Huang #define RT5190A_RID_BITMASK(rid)	BIT(rid + 1)
30*760423dfSChiYuan Huang #define RT5190A_BUCK1_DISCHG_MASK	GENMASK(1, 0)
31*760423dfSChiYuan Huang #define RT5190A_BUCK1_DISCHG_ONVAL	0x01
32*760423dfSChiYuan Huang #define RT5190A_OVERVOLT_MASK		GENMASK(7, 0)
33*760423dfSChiYuan Huang #define RT5190A_UNDERVOLT_MASK		GENMASK(15, 8)
34*760423dfSChiYuan Huang #define RT5190A_CH234OT_MASK		BIT(29)
35*760423dfSChiYuan Huang #define RT5190A_CHIPOT_MASK		BIT(28)
36*760423dfSChiYuan Huang 
37*760423dfSChiYuan Huang #define RT5190A_BUCK23_MINUV		600000
38*760423dfSChiYuan Huang #define RT5190A_BUCK23_MAXUV		1400000
39*760423dfSChiYuan Huang #define RT5190A_BUCK23_STEPUV		10000
40*760423dfSChiYuan Huang #define RT5190A_BUCK23_STEPNUM		((1400000 - 600000) / 10000 + 1)
41*760423dfSChiYuan Huang 
42*760423dfSChiYuan Huang enum {
43*760423dfSChiYuan Huang 	RT5190A_IDX_BUCK1 = 0,
44*760423dfSChiYuan Huang 	RT5190A_IDX_BUCK2,
45*760423dfSChiYuan Huang 	RT5190A_IDX_BUCK3,
46*760423dfSChiYuan Huang 	RT5190A_IDX_BUCK4,
47*760423dfSChiYuan Huang 	RT5190A_IDX_LDO,
48*760423dfSChiYuan Huang 	RT5190A_MAX_IDX
49*760423dfSChiYuan Huang };
50*760423dfSChiYuan Huang 
51*760423dfSChiYuan Huang struct rt5190a_priv {
52*760423dfSChiYuan Huang 	struct device *dev;
53*760423dfSChiYuan Huang 	struct regmap *regmap;
54*760423dfSChiYuan Huang 	struct regulator_desc rdesc[RT5190A_MAX_IDX];
55*760423dfSChiYuan Huang 	struct regulator_dev *rdev[RT5190A_MAX_IDX];
56*760423dfSChiYuan Huang };
57*760423dfSChiYuan Huang 
58*760423dfSChiYuan Huang static int rt5190a_get_error_flags(struct regulator_dev *rdev,
59*760423dfSChiYuan Huang 				   unsigned int *flags)
60*760423dfSChiYuan Huang {
61*760423dfSChiYuan Huang 	struct regmap *regmap = rdev_get_regmap(rdev);
62*760423dfSChiYuan Huang 	int rid = rdev_get_id(rdev);
63*760423dfSChiYuan Huang 	unsigned int pgood_stat;
64*760423dfSChiYuan Huang 	int ret;
65*760423dfSChiYuan Huang 
66*760423dfSChiYuan Huang 	ret = regmap_read(regmap, RT5190A_REG_PGSTAT, &pgood_stat);
67*760423dfSChiYuan Huang 	if (ret)
68*760423dfSChiYuan Huang 		return ret;
69*760423dfSChiYuan Huang 
70*760423dfSChiYuan Huang 	if (!(pgood_stat & RT5190A_RID_BITMASK(rid)))
71*760423dfSChiYuan Huang 		*flags = REGULATOR_ERROR_FAIL;
72*760423dfSChiYuan Huang 	else
73*760423dfSChiYuan Huang 		*flags = 0;
74*760423dfSChiYuan Huang 
75*760423dfSChiYuan Huang 	return 0;
76*760423dfSChiYuan Huang }
77*760423dfSChiYuan Huang 
78*760423dfSChiYuan Huang static int rt5190a_fixed_buck_set_mode(struct regulator_dev *rdev,
79*760423dfSChiYuan Huang 				       unsigned int mode)
80*760423dfSChiYuan Huang {
81*760423dfSChiYuan Huang 	struct regmap *regmap = rdev_get_regmap(rdev);
82*760423dfSChiYuan Huang 	int rid = rdev_get_id(rdev);
83*760423dfSChiYuan Huang 	unsigned int mask = RT5190A_RID_BITMASK(rid), val;
84*760423dfSChiYuan Huang 
85*760423dfSChiYuan Huang 	switch (mode) {
86*760423dfSChiYuan Huang 	case REGULATOR_MODE_FAST:
87*760423dfSChiYuan Huang 		val = mask;
88*760423dfSChiYuan Huang 		break;
89*760423dfSChiYuan Huang 	case REGULATOR_MODE_NORMAL:
90*760423dfSChiYuan Huang 		val = 0;
91*760423dfSChiYuan Huang 		break;
92*760423dfSChiYuan Huang 	default:
93*760423dfSChiYuan Huang 		return -EINVAL;
94*760423dfSChiYuan Huang 	}
95*760423dfSChiYuan Huang 
96*760423dfSChiYuan Huang 	return regmap_update_bits(regmap, RT5190A_REG_DCDCCNTL, mask, val);
97*760423dfSChiYuan Huang }
98*760423dfSChiYuan Huang 
99*760423dfSChiYuan Huang static unsigned int rt5190a_fixed_buck_get_mode(struct regulator_dev *rdev)
100*760423dfSChiYuan Huang {
101*760423dfSChiYuan Huang 	struct regmap *regmap = rdev_get_regmap(rdev);
102*760423dfSChiYuan Huang 	int rid = rdev_get_id(rdev);
103*760423dfSChiYuan Huang 	unsigned int val;
104*760423dfSChiYuan Huang 	int ret;
105*760423dfSChiYuan Huang 
106*760423dfSChiYuan Huang 	ret = regmap_read(regmap, RT5190A_REG_DCDCCNTL, &val);
107*760423dfSChiYuan Huang 	if (ret) {
108*760423dfSChiYuan Huang 		dev_err(&rdev->dev, "Failed to get mode [%d]\n", ret);
109*760423dfSChiYuan Huang 		return ret;
110*760423dfSChiYuan Huang 	}
111*760423dfSChiYuan Huang 
112*760423dfSChiYuan Huang 	if (val & RT5190A_RID_BITMASK(rid))
113*760423dfSChiYuan Huang 		return REGULATOR_MODE_FAST;
114*760423dfSChiYuan Huang 
115*760423dfSChiYuan Huang 	return REGULATOR_MODE_NORMAL;
116*760423dfSChiYuan Huang }
117*760423dfSChiYuan Huang 
118*760423dfSChiYuan Huang static const struct regulator_ops rt5190a_ranged_buck_ops = {
119*760423dfSChiYuan Huang 	.enable	= regulator_enable_regmap,
120*760423dfSChiYuan Huang 	.disable = regulator_disable_regmap,
121*760423dfSChiYuan Huang 	.is_enabled = regulator_is_enabled_regmap,
122*760423dfSChiYuan Huang 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
123*760423dfSChiYuan Huang 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
124*760423dfSChiYuan Huang 	.list_voltage = regulator_list_voltage_linear,
125*760423dfSChiYuan Huang 	.set_active_discharge = regulator_set_active_discharge_regmap,
126*760423dfSChiYuan Huang 	.get_error_flags = rt5190a_get_error_flags,
127*760423dfSChiYuan Huang };
128*760423dfSChiYuan Huang 
129*760423dfSChiYuan Huang static const struct regulator_ops rt5190a_fixed_buck_ops = {
130*760423dfSChiYuan Huang 	.enable	= regulator_enable_regmap,
131*760423dfSChiYuan Huang 	.disable = regulator_disable_regmap,
132*760423dfSChiYuan Huang 	.is_enabled = regulator_is_enabled_regmap,
133*760423dfSChiYuan Huang 	.set_active_discharge = regulator_set_active_discharge_regmap,
134*760423dfSChiYuan Huang 	.set_mode = rt5190a_fixed_buck_set_mode,
135*760423dfSChiYuan Huang 	.get_mode = rt5190a_fixed_buck_get_mode,
136*760423dfSChiYuan Huang 	.get_error_flags = rt5190a_get_error_flags,
137*760423dfSChiYuan Huang };
138*760423dfSChiYuan Huang 
139*760423dfSChiYuan Huang static const struct regulator_ops rt5190a_fixed_ldo_ops = {
140*760423dfSChiYuan Huang 	.enable	= regulator_enable_regmap,
141*760423dfSChiYuan Huang 	.disable = regulator_disable_regmap,
142*760423dfSChiYuan Huang 	.is_enabled = regulator_is_enabled_regmap,
143*760423dfSChiYuan Huang 	.set_active_discharge = regulator_set_active_discharge_regmap,
144*760423dfSChiYuan Huang 	.get_error_flags = rt5190a_get_error_flags,
145*760423dfSChiYuan Huang };
146*760423dfSChiYuan Huang 
147*760423dfSChiYuan Huang static irqreturn_t rt5190a_irq_handler(int irq, void *data)
148*760423dfSChiYuan Huang {
149*760423dfSChiYuan Huang 	struct rt5190a_priv *priv = data;
150*760423dfSChiYuan Huang 	__le32 raws;
151*760423dfSChiYuan Huang 	unsigned int events, fields;
152*760423dfSChiYuan Huang 	static const struct {
153*760423dfSChiYuan Huang 		unsigned int bitmask;
154*760423dfSChiYuan Huang 		unsigned int report;
155*760423dfSChiYuan Huang 	} event_tbl[] = {
156*760423dfSChiYuan Huang 		{ RT5190A_OVERVOLT_MASK, REGULATOR_ERROR_REGULATION_OUT },
157*760423dfSChiYuan Huang 		{ RT5190A_UNDERVOLT_MASK, REGULATOR_ERROR_UNDER_VOLTAGE }
158*760423dfSChiYuan Huang 	};
159*760423dfSChiYuan Huang 	int i, j, ret;
160*760423dfSChiYuan Huang 
161*760423dfSChiYuan Huang 	ret = regmap_raw_read(priv->regmap, RT5190A_REG_OVINT, &raws,
162*760423dfSChiYuan Huang 			      sizeof(raws));
163*760423dfSChiYuan Huang 	if (ret) {
164*760423dfSChiYuan Huang 		dev_err(priv->dev, "Failed to read events\n");
165*760423dfSChiYuan Huang 		return IRQ_NONE;
166*760423dfSChiYuan Huang 	}
167*760423dfSChiYuan Huang 
168*760423dfSChiYuan Huang 	events = le32_to_cpu(raws);
169*760423dfSChiYuan Huang 
170*760423dfSChiYuan Huang 	ret = regmap_raw_write(priv->regmap, RT5190A_REG_OVINT, &raws,
171*760423dfSChiYuan Huang 			       sizeof(raws));
172*760423dfSChiYuan Huang 	if (ret)
173*760423dfSChiYuan Huang 		dev_err(priv->dev, "Failed to write-clear events\n");
174*760423dfSChiYuan Huang 
175*760423dfSChiYuan Huang 	/* Handle OV,UV events */
176*760423dfSChiYuan Huang 	for (i = 0; i < ARRAY_SIZE(event_tbl); i++) {
177*760423dfSChiYuan Huang 		fields = events & event_tbl[i].bitmask;
178*760423dfSChiYuan Huang 		fields >>= ffs(event_tbl[i].bitmask) - 1;
179*760423dfSChiYuan Huang 
180*760423dfSChiYuan Huang 		for (j = 0; j < RT5190A_MAX_IDX; j++) {
181*760423dfSChiYuan Huang 			if (!(fields & RT5190A_RID_BITMASK(j)))
182*760423dfSChiYuan Huang 				continue;
183*760423dfSChiYuan Huang 
184*760423dfSChiYuan Huang 			regulator_notifier_call_chain(priv->rdev[j],
185*760423dfSChiYuan Huang 						      event_tbl[i].report,
186*760423dfSChiYuan Huang 						      NULL);
187*760423dfSChiYuan Huang 		}
188*760423dfSChiYuan Huang 	}
189*760423dfSChiYuan Huang 
190*760423dfSChiYuan Huang 	/* Handle CH234 OT event */
191*760423dfSChiYuan Huang 	if (events & RT5190A_CH234OT_MASK) {
192*760423dfSChiYuan Huang 		for (j = RT5190A_IDX_BUCK2; j < RT5190A_IDX_LDO; j++) {
193*760423dfSChiYuan Huang 			regulator_notifier_call_chain(priv->rdev[j],
194*760423dfSChiYuan Huang 						      REGULATOR_ERROR_OVER_TEMP,
195*760423dfSChiYuan Huang 						      NULL);
196*760423dfSChiYuan Huang 		}
197*760423dfSChiYuan Huang 	}
198*760423dfSChiYuan Huang 
199*760423dfSChiYuan Huang 	/* Warning if CHIP OT occur */
200*760423dfSChiYuan Huang 	if (events & RT5190A_CHIPOT_MASK)
201*760423dfSChiYuan Huang 		dev_warn(priv->dev, "CHIP overheat\n");
202*760423dfSChiYuan Huang 
203*760423dfSChiYuan Huang 	return IRQ_HANDLED;
204*760423dfSChiYuan Huang }
205*760423dfSChiYuan Huang 
206*760423dfSChiYuan Huang static unsigned int rt5190a_of_map_mode(unsigned int mode)
207*760423dfSChiYuan Huang {
208*760423dfSChiYuan Huang 	switch (mode) {
209*760423dfSChiYuan Huang 	case RT5190A_OPMODE_AUTO:
210*760423dfSChiYuan Huang 		return REGULATOR_MODE_NORMAL;
211*760423dfSChiYuan Huang 	case RT5190A_OPMODE_FPWM:
212*760423dfSChiYuan Huang 		return REGULATOR_MODE_FAST;
213*760423dfSChiYuan Huang 	default:
214*760423dfSChiYuan Huang 		return REGULATOR_MODE_INVALID;
215*760423dfSChiYuan Huang 	}
216*760423dfSChiYuan Huang }
217*760423dfSChiYuan Huang 
218*760423dfSChiYuan Huang static int rt5190a_of_parse_cb(struct rt5190a_priv *priv, int rid,
219*760423dfSChiYuan Huang 			       struct of_regulator_match *match)
220*760423dfSChiYuan Huang {
221*760423dfSChiYuan Huang 	struct regulator_desc *desc = priv->rdesc + rid;
222*760423dfSChiYuan Huang 	struct regulator_init_data *init_data = match->init_data;
223*760423dfSChiYuan Huang 	struct device_node *np = match->of_node;
224*760423dfSChiYuan Huang 	bool latchup_enable;
225*760423dfSChiYuan Huang 	unsigned int mask = RT5190A_RID_BITMASK(rid), val;
226*760423dfSChiYuan Huang 
227*760423dfSChiYuan Huang 	switch (rid) {
228*760423dfSChiYuan Huang 	case RT5190A_IDX_BUCK1:
229*760423dfSChiYuan Huang 	case RT5190A_IDX_BUCK4:
230*760423dfSChiYuan Huang 	case RT5190A_IDX_LDO:
231*760423dfSChiYuan Huang 		init_data->constraints.apply_uV = 0;
232*760423dfSChiYuan Huang 
233*760423dfSChiYuan Huang 		if (init_data->constraints.min_uV ==
234*760423dfSChiYuan Huang 				init_data->constraints.max_uV)
235*760423dfSChiYuan Huang 			desc->fixed_uV = init_data->constraints.min_uV;
236*760423dfSChiYuan Huang 		else {
237*760423dfSChiYuan Huang 			dev_err(priv->dev,
238*760423dfSChiYuan Huang 				"Variable voltage for fixed regulator\n");
239*760423dfSChiYuan Huang 			return -EINVAL;
240*760423dfSChiYuan Huang 		}
241*760423dfSChiYuan Huang 		break;
242*760423dfSChiYuan Huang 	default:
243*760423dfSChiYuan Huang 		break;
244*760423dfSChiYuan Huang 	}
245*760423dfSChiYuan Huang 
246*760423dfSChiYuan Huang 	latchup_enable = of_property_read_bool(np, "richtek,latchup-enable");
247*760423dfSChiYuan Huang 
248*760423dfSChiYuan Huang 	/* latchup: 0, default hiccup: 1 */
249*760423dfSChiYuan Huang 	val = !latchup_enable ? mask : 0;
250*760423dfSChiYuan Huang 
251*760423dfSChiYuan Huang 	return regmap_update_bits(priv->regmap, RT5190A_REG_PROTMODE, mask, val);
252*760423dfSChiYuan Huang }
253*760423dfSChiYuan Huang 
254*760423dfSChiYuan Huang static void rt5190a_fillin_regulator_desc(struct regulator_desc *desc, int rid)
255*760423dfSChiYuan Huang {
256*760423dfSChiYuan Huang 	static const char * const regu_name[] = { "buck1", "buck2",
257*760423dfSChiYuan Huang 						  "buck3", "buck4",
258*760423dfSChiYuan Huang 						  "ldo" };
259*760423dfSChiYuan Huang 	static const char * const supply[] = { NULL, "vin2", "vin3", "vin4",
260*760423dfSChiYuan Huang 					       "vinldo" };
261*760423dfSChiYuan Huang 
262*760423dfSChiYuan Huang 	desc->name = regu_name[rid];
263*760423dfSChiYuan Huang 	desc->supply_name = supply[rid];
264*760423dfSChiYuan Huang 	desc->owner = THIS_MODULE;
265*760423dfSChiYuan Huang 	desc->type = REGULATOR_VOLTAGE;
266*760423dfSChiYuan Huang 	desc->id = rid;
267*760423dfSChiYuan Huang 	desc->enable_reg = RT5190A_REG_ENABLE;
268*760423dfSChiYuan Huang 	desc->enable_mask = RT5190A_RID_BITMASK(rid);
269*760423dfSChiYuan Huang 	desc->active_discharge_reg = RT5190A_REG_DISCHARGE;
270*760423dfSChiYuan Huang 	desc->active_discharge_mask = RT5190A_RID_BITMASK(rid);
271*760423dfSChiYuan Huang 	desc->active_discharge_on = RT5190A_RID_BITMASK(rid);
272*760423dfSChiYuan Huang 
273*760423dfSChiYuan Huang 	switch (rid) {
274*760423dfSChiYuan Huang 	case RT5190A_IDX_BUCK1:
275*760423dfSChiYuan Huang 		desc->active_discharge_mask = RT5190A_BUCK1_DISCHG_MASK;
276*760423dfSChiYuan Huang 		desc->active_discharge_on = RT5190A_BUCK1_DISCHG_ONVAL;
277*760423dfSChiYuan Huang 		desc->n_voltages = 1;
278*760423dfSChiYuan Huang 		desc->ops = &rt5190a_fixed_buck_ops;
279*760423dfSChiYuan Huang 		desc->of_map_mode = rt5190a_of_map_mode;
280*760423dfSChiYuan Huang 		break;
281*760423dfSChiYuan Huang 	case RT5190A_IDX_BUCK2:
282*760423dfSChiYuan Huang 		desc->vsel_reg = RT5190A_REG_BUCK2VSEL;
283*760423dfSChiYuan Huang 		desc->vsel_mask = RT5190A_VSEL_MASK;
284*760423dfSChiYuan Huang 		desc->min_uV = RT5190A_BUCK23_MINUV;
285*760423dfSChiYuan Huang 		desc->uV_step = RT5190A_BUCK23_STEPUV;
286*760423dfSChiYuan Huang 		desc->n_voltages = RT5190A_BUCK23_STEPNUM;
287*760423dfSChiYuan Huang 		desc->ops = &rt5190a_ranged_buck_ops;
288*760423dfSChiYuan Huang 		break;
289*760423dfSChiYuan Huang 	case RT5190A_IDX_BUCK3:
290*760423dfSChiYuan Huang 		desc->vsel_reg = RT5190A_REG_BUCK3VSEL;
291*760423dfSChiYuan Huang 		desc->vsel_mask = RT5190A_VSEL_MASK;
292*760423dfSChiYuan Huang 		desc->min_uV = RT5190A_BUCK23_MINUV;
293*760423dfSChiYuan Huang 		desc->uV_step = RT5190A_BUCK23_STEPUV;
294*760423dfSChiYuan Huang 		desc->n_voltages = RT5190A_BUCK23_STEPNUM;
295*760423dfSChiYuan Huang 		desc->ops = &rt5190a_ranged_buck_ops;
296*760423dfSChiYuan Huang 		break;
297*760423dfSChiYuan Huang 	case RT5190A_IDX_BUCK4:
298*760423dfSChiYuan Huang 		desc->n_voltages = 1;
299*760423dfSChiYuan Huang 		desc->ops = &rt5190a_fixed_buck_ops;
300*760423dfSChiYuan Huang 		desc->of_map_mode = rt5190a_of_map_mode;
301*760423dfSChiYuan Huang 		break;
302*760423dfSChiYuan Huang 	case RT5190A_IDX_LDO:
303*760423dfSChiYuan Huang 		desc->n_voltages = 1;
304*760423dfSChiYuan Huang 		desc->ops = &rt5190a_fixed_ldo_ops;
305*760423dfSChiYuan Huang 		break;
306*760423dfSChiYuan Huang 	}
307*760423dfSChiYuan Huang }
308*760423dfSChiYuan Huang 
309*760423dfSChiYuan Huang static struct of_regulator_match rt5190a_regulator_match[] = {
310*760423dfSChiYuan Huang 	{ .name = "buck1", },
311*760423dfSChiYuan Huang 	{ .name = "buck2", },
312*760423dfSChiYuan Huang 	{ .name = "buck3", },
313*760423dfSChiYuan Huang 	{ .name = "buck4", },
314*760423dfSChiYuan Huang 	{ .name = "ldo", }
315*760423dfSChiYuan Huang };
316*760423dfSChiYuan Huang 
317*760423dfSChiYuan Huang static int rt5190a_parse_regulator_dt_data(struct rt5190a_priv *priv)
318*760423dfSChiYuan Huang {
319*760423dfSChiYuan Huang 	struct device_node *regulator_np;
320*760423dfSChiYuan Huang 	struct regulator_desc *reg_desc;
321*760423dfSChiYuan Huang 	struct of_regulator_match *match;
322*760423dfSChiYuan Huang 	int i, ret;
323*760423dfSChiYuan Huang 
324*760423dfSChiYuan Huang 	for (i = 0; i < RT5190A_MAX_IDX; i++) {
325*760423dfSChiYuan Huang 		reg_desc = priv->rdesc + i;
326*760423dfSChiYuan Huang 		match = rt5190a_regulator_match + i;
327*760423dfSChiYuan Huang 
328*760423dfSChiYuan Huang 		rt5190a_fillin_regulator_desc(reg_desc, i);
329*760423dfSChiYuan Huang 
330*760423dfSChiYuan Huang 		match->desc = reg_desc;
331*760423dfSChiYuan Huang 	}
332*760423dfSChiYuan Huang 
333*760423dfSChiYuan Huang 	regulator_np = of_get_child_by_name(priv->dev->of_node, "regulators");
334*760423dfSChiYuan Huang 	if (!regulator_np) {
335*760423dfSChiYuan Huang 		dev_err(priv->dev, "Could not find 'regulators' node\n");
336*760423dfSChiYuan Huang 		return -ENODEV;
337*760423dfSChiYuan Huang 	}
338*760423dfSChiYuan Huang 
339*760423dfSChiYuan Huang 	ret = of_regulator_match(priv->dev, regulator_np,
340*760423dfSChiYuan Huang 				 rt5190a_regulator_match,
341*760423dfSChiYuan Huang 				 ARRAY_SIZE(rt5190a_regulator_match));
342*760423dfSChiYuan Huang 
343*760423dfSChiYuan Huang 	of_node_put(regulator_np);
344*760423dfSChiYuan Huang 
345*760423dfSChiYuan Huang 	if (ret < 0) {
346*760423dfSChiYuan Huang 		dev_err(priv->dev,
347*760423dfSChiYuan Huang 			"Error parsing regulator init data: %d\n", ret);
348*760423dfSChiYuan Huang 		return ret;
349*760423dfSChiYuan Huang 	}
350*760423dfSChiYuan Huang 
351*760423dfSChiYuan Huang 	for (i = 0; i < RT5190A_MAX_IDX; i++) {
352*760423dfSChiYuan Huang 		match = rt5190a_regulator_match + i;
353*760423dfSChiYuan Huang 
354*760423dfSChiYuan Huang 		ret = rt5190a_of_parse_cb(priv, i, match);
355*760423dfSChiYuan Huang 		if (ret) {
356*760423dfSChiYuan Huang 			dev_err(priv->dev, "Failed in [%d] of_parse_cb\n", i);
357*760423dfSChiYuan Huang 			return ret;
358*760423dfSChiYuan Huang 		}
359*760423dfSChiYuan Huang 	}
360*760423dfSChiYuan Huang 
361*760423dfSChiYuan Huang 	return 0;
362*760423dfSChiYuan Huang }
363*760423dfSChiYuan Huang 
364*760423dfSChiYuan Huang static const struct reg_sequence rt5190a_init_patch[] = {
365*760423dfSChiYuan Huang 	{ 0x09, 0x3d, },
366*760423dfSChiYuan Huang 	{ 0x0a, 0x3e, },
367*760423dfSChiYuan Huang 	{ 0x0b, 0x01, },
368*760423dfSChiYuan Huang 	{ 0x10, 0xff, },
369*760423dfSChiYuan Huang 	{ 0x11, 0xff, },
370*760423dfSChiYuan Huang 	{ 0x12, 0xff, },
371*760423dfSChiYuan Huang 	{ 0x13, 0xff, },
372*760423dfSChiYuan Huang 	{ 0x14, 0, },
373*760423dfSChiYuan Huang 	{ 0x15, 0, },
374*760423dfSChiYuan Huang 	{ 0x16, 0x3e, },
375*760423dfSChiYuan Huang 	{ 0x17, 0, }
376*760423dfSChiYuan Huang };
377*760423dfSChiYuan Huang 
378*760423dfSChiYuan Huang static int rt5190a_device_initialize(struct rt5190a_priv *priv)
379*760423dfSChiYuan Huang {
380*760423dfSChiYuan Huang 	bool mute_enable;
381*760423dfSChiYuan Huang 	int ret;
382*760423dfSChiYuan Huang 
383*760423dfSChiYuan Huang 	ret = regmap_register_patch(priv->regmap, rt5190a_init_patch,
384*760423dfSChiYuan Huang 				    ARRAY_SIZE(rt5190a_init_patch));
385*760423dfSChiYuan Huang 	if (ret) {
386*760423dfSChiYuan Huang 		dev_err(priv->dev, "Failed to do register patch\n");
387*760423dfSChiYuan Huang 		return ret;
388*760423dfSChiYuan Huang 	}
389*760423dfSChiYuan Huang 
390*760423dfSChiYuan Huang 	mute_enable = device_property_read_bool(priv->dev,
391*760423dfSChiYuan Huang 						"richtek,mute-enable");
392*760423dfSChiYuan Huang 
393*760423dfSChiYuan Huang 	if (mute_enable) {
394*760423dfSChiYuan Huang 		ret = regmap_write(priv->regmap, RT5190A_REG_MUTECNTL, 0x00);
395*760423dfSChiYuan Huang 		if (ret) {
396*760423dfSChiYuan Huang 			dev_err(priv->dev, "Failed to enable mute function\n");
397*760423dfSChiYuan Huang 			return ret;
398*760423dfSChiYuan Huang 		}
399*760423dfSChiYuan Huang 	}
400*760423dfSChiYuan Huang 
401*760423dfSChiYuan Huang 	return 0;
402*760423dfSChiYuan Huang }
403*760423dfSChiYuan Huang 
404*760423dfSChiYuan Huang static int rt5190a_device_check(struct rt5190a_priv *priv)
405*760423dfSChiYuan Huang {
406*760423dfSChiYuan Huang 	u16 devid;
407*760423dfSChiYuan Huang 	int ret;
408*760423dfSChiYuan Huang 
409*760423dfSChiYuan Huang 	ret = regmap_raw_read(priv->regmap, RT5190A_REG_MANUFACTURE, &devid,
410*760423dfSChiYuan Huang 			      sizeof(devid));
411*760423dfSChiYuan Huang 	if (ret)
412*760423dfSChiYuan Huang 		return ret;
413*760423dfSChiYuan Huang 
414*760423dfSChiYuan Huang 	if (devid) {
415*760423dfSChiYuan Huang 		dev_err(priv->dev, "Incorrect device id 0x%04x\n", devid);
416*760423dfSChiYuan Huang 		return -ENODEV;
417*760423dfSChiYuan Huang 	}
418*760423dfSChiYuan Huang 
419*760423dfSChiYuan Huang 	return 0;
420*760423dfSChiYuan Huang }
421*760423dfSChiYuan Huang 
422*760423dfSChiYuan Huang static const struct regmap_config rt5190a_regmap_config = {
423*760423dfSChiYuan Huang 	.reg_bits = 8,
424*760423dfSChiYuan Huang 	.val_bits = 8,
425*760423dfSChiYuan Huang 	.max_register = RT5190A_REG_HOTDIEMASK,
426*760423dfSChiYuan Huang };
427*760423dfSChiYuan Huang 
428*760423dfSChiYuan Huang static int rt5190a_probe(struct i2c_client *i2c)
429*760423dfSChiYuan Huang {
430*760423dfSChiYuan Huang 	struct rt5190a_priv *priv;
431*760423dfSChiYuan Huang 	struct regulator_config cfg = {};
432*760423dfSChiYuan Huang 	int i, ret;
433*760423dfSChiYuan Huang 
434*760423dfSChiYuan Huang 	priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
435*760423dfSChiYuan Huang 	if (!priv)
436*760423dfSChiYuan Huang 		return -ENOMEM;
437*760423dfSChiYuan Huang 
438*760423dfSChiYuan Huang 	priv->dev = &i2c->dev;
439*760423dfSChiYuan Huang 
440*760423dfSChiYuan Huang 	priv->regmap = devm_regmap_init_i2c(i2c, &rt5190a_regmap_config);
441*760423dfSChiYuan Huang 	if (IS_ERR(priv->regmap)) {
442*760423dfSChiYuan Huang 		dev_err(&i2c->dev, "Failed to allocate regmap\n");
443*760423dfSChiYuan Huang 		return PTR_ERR(priv->regmap);
444*760423dfSChiYuan Huang 	}
445*760423dfSChiYuan Huang 
446*760423dfSChiYuan Huang 	ret = rt5190a_device_check(priv);
447*760423dfSChiYuan Huang 	if (ret) {
448*760423dfSChiYuan Huang 		dev_err(&i2c->dev, "Failed to check device %d\n", ret);
449*760423dfSChiYuan Huang 		return ret;
450*760423dfSChiYuan Huang 	}
451*760423dfSChiYuan Huang 
452*760423dfSChiYuan Huang 	ret = rt5190a_device_initialize(priv);
453*760423dfSChiYuan Huang 	if (ret) {
454*760423dfSChiYuan Huang 		dev_err(&i2c->dev, "Failed to initialize the device\n");
455*760423dfSChiYuan Huang 		return ret;
456*760423dfSChiYuan Huang 	}
457*760423dfSChiYuan Huang 
458*760423dfSChiYuan Huang 	ret = rt5190a_parse_regulator_dt_data(priv);
459*760423dfSChiYuan Huang 	if (ret) {
460*760423dfSChiYuan Huang 		dev_err(&i2c->dev, "Failed to parse regulator dt\n");
461*760423dfSChiYuan Huang 		return ret;
462*760423dfSChiYuan Huang 	}
463*760423dfSChiYuan Huang 
464*760423dfSChiYuan Huang 	cfg.dev = &i2c->dev;
465*760423dfSChiYuan Huang 	cfg.regmap = priv->regmap;
466*760423dfSChiYuan Huang 
467*760423dfSChiYuan Huang 	for (i = 0; i < RT5190A_MAX_IDX; i++) {
468*760423dfSChiYuan Huang 		struct regulator_desc *desc = priv->rdesc + i;
469*760423dfSChiYuan Huang 		struct of_regulator_match *match = rt5190a_regulator_match + i;
470*760423dfSChiYuan Huang 
471*760423dfSChiYuan Huang 		cfg.init_data = match->init_data;
472*760423dfSChiYuan Huang 		cfg.of_node = match->of_node;
473*760423dfSChiYuan Huang 
474*760423dfSChiYuan Huang 		priv->rdev[i] = devm_regulator_register(&i2c->dev, desc, &cfg);
475*760423dfSChiYuan Huang 		if (IS_ERR(priv->rdev[i])) {
476*760423dfSChiYuan Huang 			dev_err(&i2c->dev, "Failed to register regulator %s\n",
477*760423dfSChiYuan Huang 				desc->name);
478*760423dfSChiYuan Huang 			return PTR_ERR(priv->rdev[i]);
479*760423dfSChiYuan Huang 		}
480*760423dfSChiYuan Huang 	}
481*760423dfSChiYuan Huang 
482*760423dfSChiYuan Huang 	if (i2c->irq) {
483*760423dfSChiYuan Huang 		ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
484*760423dfSChiYuan Huang 						rt5190a_irq_handler,
485*760423dfSChiYuan Huang 						IRQF_ONESHOT,
486*760423dfSChiYuan Huang 						dev_name(&i2c->dev), priv);
487*760423dfSChiYuan Huang 		if (ret) {
488*760423dfSChiYuan Huang 			dev_err(&i2c->dev, "Failed to register interrupt\n");
489*760423dfSChiYuan Huang 			return ret;
490*760423dfSChiYuan Huang 		}
491*760423dfSChiYuan Huang 	}
492*760423dfSChiYuan Huang 
493*760423dfSChiYuan Huang 	return 0;
494*760423dfSChiYuan Huang }
495*760423dfSChiYuan Huang 
496*760423dfSChiYuan Huang static const struct of_device_id __maybe_unused rt5190a_device_table[] = {
497*760423dfSChiYuan Huang 	{ .compatible = "richtek,rt5190a", },
498*760423dfSChiYuan Huang 	{}
499*760423dfSChiYuan Huang };
500*760423dfSChiYuan Huang MODULE_DEVICE_TABLE(of, rt5190a_device_table);
501*760423dfSChiYuan Huang 
502*760423dfSChiYuan Huang static struct i2c_driver rt5190a_driver = {
503*760423dfSChiYuan Huang 	.driver = {
504*760423dfSChiYuan Huang 		.name = "rt5190a",
505*760423dfSChiYuan Huang 		.of_match_table = rt5190a_device_table,
506*760423dfSChiYuan Huang 	},
507*760423dfSChiYuan Huang 	.probe_new = rt5190a_probe,
508*760423dfSChiYuan Huang };
509*760423dfSChiYuan Huang module_i2c_driver(rt5190a_driver);
510*760423dfSChiYuan Huang 
511*760423dfSChiYuan Huang MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
512*760423dfSChiYuan Huang MODULE_DESCRIPTION("Richtek RT5190A Regulator Driver");
513*760423dfSChiYuan Huang MODULE_LICENSE("GPL v2");
514