xref: /linux/drivers/regulator/rt8092.c (revision c17ee635fd3a482b2ad2bf5e269755c2eae5f25e)
1*32a708baSChiYuan Huang // SPDX-License-Identifier: GPL-2.0+
2*32a708baSChiYuan Huang //
3*32a708baSChiYuan Huang // Copyright (c) 2025 Richtek Technology Corp.
4*32a708baSChiYuan Huang //
5*32a708baSChiYuan Huang // Author: ChiYuan Huang <cy_huang@richtek.com>
6*32a708baSChiYuan Huang 
7*32a708baSChiYuan Huang #include <linux/bitfield.h>
8*32a708baSChiYuan Huang #include <linux/bits.h>
9*32a708baSChiYuan Huang #include <linux/gpio/consumer.h>
10*32a708baSChiYuan Huang #include <linux/i2c.h>
11*32a708baSChiYuan Huang #include <linux/mod_devicetable.h>
12*32a708baSChiYuan Huang #include <linux/module.h>
13*32a708baSChiYuan Huang #include <linux/property.h>
14*32a708baSChiYuan Huang #include <linux/regmap.h>
15*32a708baSChiYuan Huang #include <linux/regulator/consumer.h>
16*32a708baSChiYuan Huang #include <linux/regulator/driver.h>
17*32a708baSChiYuan Huang #include <linux/regulator/of_regulator.h>
18*32a708baSChiYuan Huang 
19*32a708baSChiYuan Huang #define RT8092_REG_MNTRPT	0x00
20*32a708baSChiYuan Huang #define RT8092_REG_VOUTH	0x10
21*32a708baSChiYuan Huang #define RT8092_REG_VOUTL	0x11
22*32a708baSChiYuan Huang #define RT8092_REG_PWMMODE	0x14
23*32a708baSChiYuan Huang #define RT8092_REG_EVENT	0x18
24*32a708baSChiYuan Huang #define RT8092_REG_VBANKH	0x1C
25*32a708baSChiYuan Huang #define RT8092_REG_VBANKL	0x1D
26*32a708baSChiYuan Huang #define RT8092_REG_VBOUND	0x1E
27*32a708baSChiYuan Huang 
28*32a708baSChiYuan Huang #define RT8092_TSDEVT_MASK	BIT(7)
29*32a708baSChiYuan Huang #define RT8092_PGEVT_MASK	BIT(0)
30*32a708baSChiYuan Huang #define RT8092_VSEL_MASK	GENMASK(6, 0)
31*32a708baSChiYuan Huang #define RT8092_VOUTEN_MASK	BIT(7)
32*32a708baSChiYuan Huang #define RT8092_FPWML_MASK	BIT(7)
33*32a708baSChiYuan Huang #define RT8092_FPWMH_MASK	BIT(6)
34*32a708baSChiYuan Huang #define RT8092_OCPEVT_MASK	BIT(7)
35*32a708baSChiYuan Huang #define RT8092_SCPEVT_MASK	BIT(4)
36*32a708baSChiYuan Huang #define RT8092_VINUVEVT_MASK	BIT(1)
37*32a708baSChiYuan Huang #define RT8092_VBANK_MASK	GENMASK(1, 0)
38*32a708baSChiYuan Huang 
39*32a708baSChiYuan Huang #define RT8092_MODE_AUTO	0
40*32a708baSChiYuan Huang #define RT8092_MODE_FPWM	1
41*32a708baSChiYuan Huang #define RT8092_VOUT_BASEUV	303125
42*32a708baSChiYuan Huang #define RT8092_VOUT_STEPUV	3125
43*32a708baSChiYuan Huang #define RT8092_VOUT_MINSEL	15
44*32a708baSChiYuan Huang #define RT8092_NUM_VOLTS	128
45*32a708baSChiYuan Huang #define RT8092_INITSS_US	400
46*32a708baSChiYuan Huang 
47*32a708baSChiYuan Huang static int rt8092_get_vbank_index(struct regmap *regmap, bool vsel_high, unsigned int *vbank_idx)
48*32a708baSChiYuan Huang {
49*32a708baSChiYuan Huang 	unsigned int vbank_reg = vsel_high ? RT8092_REG_VBANKH : RT8092_REG_VBANKL;
50*32a708baSChiYuan Huang 	unsigned int index;
51*32a708baSChiYuan Huang 	int ret;
52*32a708baSChiYuan Huang 
53*32a708baSChiYuan Huang 	ret = regmap_read(regmap, vbank_reg, &index);
54*32a708baSChiYuan Huang 	if (ret)
55*32a708baSChiYuan Huang 		return ret;
56*32a708baSChiYuan Huang 
57*32a708baSChiYuan Huang 	*vbank_idx = FIELD_GET(RT8092_VBANK_MASK, index);
58*32a708baSChiYuan Huang 	return 0;
59*32a708baSChiYuan Huang }
60*32a708baSChiYuan Huang 
61*32a708baSChiYuan Huang static int rt8092_set_operating_mode(struct regulator_dev *rdev, unsigned int mode)
62*32a708baSChiYuan Huang {
63*32a708baSChiYuan Huang 	const struct regulator_desc *desc = rdev->desc;
64*32a708baSChiYuan Huang 	struct regmap *regmap = rdev_get_regmap(rdev);
65*32a708baSChiYuan Huang 	unsigned int mode_mask, mode_val;
66*32a708baSChiYuan Huang 
67*32a708baSChiYuan Huang 	mode_mask = desc->vsel_reg == RT8092_REG_VOUTH ? RT8092_FPWMH_MASK : RT8092_FPWML_MASK;
68*32a708baSChiYuan Huang 
69*32a708baSChiYuan Huang 	switch (mode) {
70*32a708baSChiYuan Huang 	case REGULATOR_MODE_FAST:
71*32a708baSChiYuan Huang 		mode_val = mode_mask;
72*32a708baSChiYuan Huang 		break;
73*32a708baSChiYuan Huang 	case REGULATOR_MODE_NORMAL:
74*32a708baSChiYuan Huang 		mode_val = 0;
75*32a708baSChiYuan Huang 		break;
76*32a708baSChiYuan Huang 	default:
77*32a708baSChiYuan Huang 		return -EINVAL;
78*32a708baSChiYuan Huang 	}
79*32a708baSChiYuan Huang 
80*32a708baSChiYuan Huang 	return regmap_update_bits(regmap, RT8092_REG_PWMMODE, mode_mask, mode_val);
81*32a708baSChiYuan Huang }
82*32a708baSChiYuan Huang 
83*32a708baSChiYuan Huang static unsigned int rt8092_get_operating_mode(struct regulator_dev *rdev)
84*32a708baSChiYuan Huang {
85*32a708baSChiYuan Huang 	const struct regulator_desc *desc = rdev->desc;
86*32a708baSChiYuan Huang 	struct regmap *regmap = rdev_get_regmap(rdev);
87*32a708baSChiYuan Huang 	unsigned int mode_mask, mode_val;
88*32a708baSChiYuan Huang 	int ret;
89*32a708baSChiYuan Huang 
90*32a708baSChiYuan Huang 	mode_mask = desc->vsel_reg == RT8092_REG_VOUTH ? RT8092_FPWMH_MASK : RT8092_FPWML_MASK;
91*32a708baSChiYuan Huang 
92*32a708baSChiYuan Huang 	ret = regmap_read(regmap, RT8092_REG_PWMMODE, &mode_val);
93*32a708baSChiYuan Huang 	if (ret)
94*32a708baSChiYuan Huang 		return REGULATOR_MODE_INVALID;
95*32a708baSChiYuan Huang 
96*32a708baSChiYuan Huang 	return mode_val & mode_mask ? REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
97*32a708baSChiYuan Huang }
98*32a708baSChiYuan Huang 
99*32a708baSChiYuan Huang static int rt8092_get_error_flags(struct regulator_dev *rdev, unsigned int *flags)
100*32a708baSChiYuan Huang {
101*32a708baSChiYuan Huang 	struct regmap *regmap = rdev_get_regmap(rdev);
102*32a708baSChiYuan Huang 	unsigned int mntrpt, evtrpt, events = 0;
103*32a708baSChiYuan Huang 	int ret;
104*32a708baSChiYuan Huang 
105*32a708baSChiYuan Huang 	ret = regmap_read(regmap, RT8092_REG_MNTRPT, &mntrpt);
106*32a708baSChiYuan Huang 	if (ret)
107*32a708baSChiYuan Huang 		return ret;
108*32a708baSChiYuan Huang 
109*32a708baSChiYuan Huang 	ret = regmap_read(regmap, RT8092_REG_EVENT, &evtrpt);
110*32a708baSChiYuan Huang 	if (ret)
111*32a708baSChiYuan Huang 		return ret;
112*32a708baSChiYuan Huang 
113*32a708baSChiYuan Huang 	if (!(mntrpt & RT8092_PGEVT_MASK) || evtrpt & RT8092_VINUVEVT_MASK)
114*32a708baSChiYuan Huang 		events |= REGULATOR_ERROR_UNDER_VOLTAGE;
115*32a708baSChiYuan Huang 
116*32a708baSChiYuan Huang 	if (mntrpt & RT8092_TSDEVT_MASK)
117*32a708baSChiYuan Huang 		events |= REGULATOR_ERROR_OVER_TEMP;
118*32a708baSChiYuan Huang 
119*32a708baSChiYuan Huang 	if (evtrpt & RT8092_OCPEVT_MASK)
120*32a708baSChiYuan Huang 		events |= REGULATOR_ERROR_OVER_CURRENT;
121*32a708baSChiYuan Huang 
122*32a708baSChiYuan Huang 	if (evtrpt & RT8092_SCPEVT_MASK)
123*32a708baSChiYuan Huang 		events |= REGULATOR_ERROR_FAIL;
124*32a708baSChiYuan Huang 
125*32a708baSChiYuan Huang 	*flags = events;
126*32a708baSChiYuan Huang 	return 0;
127*32a708baSChiYuan Huang }
128*32a708baSChiYuan Huang 
129*32a708baSChiYuan Huang 
130*32a708baSChiYuan Huang static int rt8092_set_suspend_voltage(struct regulator_dev *rdev, int uV)
131*32a708baSChiYuan Huang {
132*32a708baSChiYuan Huang 	const struct regulator_desc *desc = rdev->desc;
133*32a708baSChiYuan Huang 	struct regmap *regmap = rdev_get_regmap(rdev);
134*32a708baSChiYuan Huang 	unsigned int vsel_reg, vsel_val, vbank_idx;
135*32a708baSChiYuan Huang 	bool vsel_high;
136*32a708baSChiYuan Huang 	int ret;
137*32a708baSChiYuan Huang 
138*32a708baSChiYuan Huang 	vsel_reg = desc->vsel_reg == RT8092_REG_VOUTH ? RT8092_REG_VOUTL : RT8092_REG_VOUTH;
139*32a708baSChiYuan Huang 	vsel_high = desc->vsel_reg == RT8092_REG_VOUTH;
140*32a708baSChiYuan Huang 
141*32a708baSChiYuan Huang 	ret = rt8092_get_vbank_index(regmap, vsel_high, &vbank_idx);
142*32a708baSChiYuan Huang 	if (ret)
143*32a708baSChiYuan Huang 		return ret;
144*32a708baSChiYuan Huang 
145*32a708baSChiYuan Huang 	/* VOUT  = (BASEUV + STEPUV * VSEL) * 2^vbank_idx */
146*32a708baSChiYuan Huang 	uV >>= vbank_idx;
147*32a708baSChiYuan Huang 	if (uV < RT8092_VOUT_BASEUV)
148*32a708baSChiYuan Huang 		return -EINVAL;
149*32a708baSChiYuan Huang 
150*32a708baSChiYuan Huang 	vsel_val = (uV - RT8092_VOUT_BASEUV) / RT8092_VOUT_STEPUV;
151*32a708baSChiYuan Huang 	if (vsel_val < RT8092_VOUT_MINSEL || vsel_val >= RT8092_NUM_VOLTS)
152*32a708baSChiYuan Huang 		return -EINVAL;
153*32a708baSChiYuan Huang 
154*32a708baSChiYuan Huang 	return regmap_update_bits(regmap, vsel_reg, RT8092_VSEL_MASK, vsel_val);
155*32a708baSChiYuan Huang }
156*32a708baSChiYuan Huang 
157*32a708baSChiYuan Huang static int rt8092_set_suspend_enable(struct regulator_dev *rdev)
158*32a708baSChiYuan Huang {
159*32a708baSChiYuan Huang 	const struct regulator_desc *desc = rdev->desc;
160*32a708baSChiYuan Huang 	struct regmap *regmap = rdev_get_regmap(rdev);
161*32a708baSChiYuan Huang 	unsigned int enable_reg;
162*32a708baSChiYuan Huang 
163*32a708baSChiYuan Huang 	enable_reg = desc->vsel_reg == RT8092_REG_VOUTH ? RT8092_REG_VOUTL : RT8092_REG_VOUTH;
164*32a708baSChiYuan Huang 	return regmap_set_bits(regmap, enable_reg, RT8092_VOUTEN_MASK);
165*32a708baSChiYuan Huang }
166*32a708baSChiYuan Huang 
167*32a708baSChiYuan Huang static int rt8092_set_suspend_disable(struct regulator_dev *rdev)
168*32a708baSChiYuan Huang {
169*32a708baSChiYuan Huang 	const struct regulator_desc *desc = rdev->desc;
170*32a708baSChiYuan Huang 	struct regmap *regmap = rdev_get_regmap(rdev);
171*32a708baSChiYuan Huang 	unsigned int enable_reg;
172*32a708baSChiYuan Huang 
173*32a708baSChiYuan Huang 	enable_reg = desc->vsel_reg == RT8092_REG_VOUTH ? RT8092_REG_VOUTL : RT8092_REG_VOUTH;
174*32a708baSChiYuan Huang 	return regmap_clear_bits(regmap, enable_reg, RT8092_VOUTEN_MASK);
175*32a708baSChiYuan Huang }
176*32a708baSChiYuan Huang 
177*32a708baSChiYuan Huang static int rt8092_set_suspend_mode(struct regulator_dev *rdev, unsigned int mode)
178*32a708baSChiYuan Huang {
179*32a708baSChiYuan Huang 	const struct regulator_desc *desc = rdev->desc;
180*32a708baSChiYuan Huang 	struct regmap *regmap = rdev_get_regmap(rdev);
181*32a708baSChiYuan Huang 	unsigned int mode_mask, mode_val;
182*32a708baSChiYuan Huang 
183*32a708baSChiYuan Huang 	mode_mask = desc->vsel_reg == RT8092_REG_VOUTH ? RT8092_FPWML_MASK : RT8092_FPWMH_MASK;
184*32a708baSChiYuan Huang 
185*32a708baSChiYuan Huang 	switch (mode) {
186*32a708baSChiYuan Huang 	case REGULATOR_MODE_FAST:
187*32a708baSChiYuan Huang 		mode_val = mode_mask;
188*32a708baSChiYuan Huang 		break;
189*32a708baSChiYuan Huang 	case REGULATOR_MODE_NORMAL:
190*32a708baSChiYuan Huang 		mode_val = 0;
191*32a708baSChiYuan Huang 		break;
192*32a708baSChiYuan Huang 	default:
193*32a708baSChiYuan Huang 		return -EINVAL;
194*32a708baSChiYuan Huang 	}
195*32a708baSChiYuan Huang 
196*32a708baSChiYuan Huang 	return regmap_update_bits(regmap, RT8092_REG_PWMMODE, mode_mask, mode_val);
197*32a708baSChiYuan Huang }
198*32a708baSChiYuan Huang 
199*32a708baSChiYuan Huang static const struct regulator_ops rt8092_regulator_ops = {
200*32a708baSChiYuan Huang 	.list_voltage = regulator_list_voltage_linear,
201*32a708baSChiYuan Huang 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
202*32a708baSChiYuan Huang 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
203*32a708baSChiYuan Huang 	.enable = regulator_enable_regmap,
204*32a708baSChiYuan Huang 	.disable = regulator_disable_regmap,
205*32a708baSChiYuan Huang 	.is_enabled = regulator_is_enabled_regmap,
206*32a708baSChiYuan Huang 	.set_mode = rt8092_set_operating_mode,
207*32a708baSChiYuan Huang 	.get_mode = rt8092_get_operating_mode,
208*32a708baSChiYuan Huang 	.get_error_flags = rt8092_get_error_flags,
209*32a708baSChiYuan Huang 	.set_suspend_voltage = rt8092_set_suspend_voltage,
210*32a708baSChiYuan Huang 	.set_suspend_enable = rt8092_set_suspend_enable,
211*32a708baSChiYuan Huang 	.set_suspend_disable = rt8092_set_suspend_disable,
212*32a708baSChiYuan Huang 	.set_suspend_mode = rt8092_set_suspend_mode,
213*32a708baSChiYuan Huang };
214*32a708baSChiYuan Huang 
215*32a708baSChiYuan Huang static unsigned int rt8092_of_map_mode(unsigned int mode)
216*32a708baSChiYuan Huang {
217*32a708baSChiYuan Huang 	switch (mode) {
218*32a708baSChiYuan Huang 	case RT8092_MODE_AUTO:
219*32a708baSChiYuan Huang 		return REGULATOR_MODE_NORMAL;
220*32a708baSChiYuan Huang 	case RT8092_MODE_FPWM:
221*32a708baSChiYuan Huang 		return REGULATOR_MODE_FAST;
222*32a708baSChiYuan Huang 	default:
223*32a708baSChiYuan Huang 		return REGULATOR_MODE_INVALID;
224*32a708baSChiYuan Huang 	}
225*32a708baSChiYuan Huang }
226*32a708baSChiYuan Huang 
227*32a708baSChiYuan Huang static const struct regmap_config rt8092_regmap_cfg = {
228*32a708baSChiYuan Huang 	.name =	"rt8092",
229*32a708baSChiYuan Huang 	.reg_bits = 8,
230*32a708baSChiYuan Huang 	.val_bits = 8,
231*32a708baSChiYuan Huang 	.max_register = RT8092_REG_VBOUND,
232*32a708baSChiYuan Huang };
233*32a708baSChiYuan Huang 
234*32a708baSChiYuan Huang static int rt8092_probe(struct i2c_client *i2c)
235*32a708baSChiYuan Huang {
236*32a708baSChiYuan Huang 	unsigned int vbank_idx, min_uV, step_uV;
237*32a708baSChiYuan Huang 	struct regulator_config cfg = {};
238*32a708baSChiYuan Huang 	struct device *dev = &i2c->dev;
239*32a708baSChiYuan Huang 	struct regulator_desc *desc;
240*32a708baSChiYuan Huang 	struct regulator_dev *rdev;
241*32a708baSChiYuan Huang 	struct gpio_desc *enable;
242*32a708baSChiYuan Huang 	struct regmap *regmap;
243*32a708baSChiYuan Huang 	bool vsel_high;
244*32a708baSChiYuan Huang 	int ret;
245*32a708baSChiYuan Huang 
246*32a708baSChiYuan Huang 	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
247*32a708baSChiYuan Huang 	if (!desc)
248*32a708baSChiYuan Huang 		return -ENOMEM;
249*32a708baSChiYuan Huang 
250*32a708baSChiYuan Huang 	enable = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
251*32a708baSChiYuan Huang 	if (IS_ERR(enable))
252*32a708baSChiYuan Huang 		return dev_err_probe(dev, PTR_ERR(enable), "Failed get 'enable' gpio\n");
253*32a708baSChiYuan Huang 
254*32a708baSChiYuan Huang 	regmap = devm_regmap_init_i2c(i2c, &rt8092_regmap_cfg);
255*32a708baSChiYuan Huang 	if (IS_ERR(regmap))
256*32a708baSChiYuan Huang 		return dev_err_probe(dev, PTR_ERR(regmap), "Failed to init regmap\n");
257*32a708baSChiYuan Huang 
258*32a708baSChiYuan Huang 	vsel_high = device_property_read_bool(dev, "richtek,vsel-active-high");
259*32a708baSChiYuan Huang 
260*32a708baSChiYuan Huang 	ret = rt8092_get_vbank_index(regmap, vsel_high, &vbank_idx);
261*32a708baSChiYuan Huang 	if (ret)
262*32a708baSChiYuan Huang 		return dev_err_probe(dev, ret, "Failed to get VOUT bank index\n");
263*32a708baSChiYuan Huang 
264*32a708baSChiYuan Huang 	/*
265*32a708baSChiYuan Huang 	 * step VOUT = STEP_UV * 2^vbank_idx
266*32a708baSChiYuan Huang 	 * min VOUT  = (BASEUV + STEPUV * VMIN_SEL) * 2^vbank_idx
267*32a708baSChiYuan Huang 	 */
268*32a708baSChiYuan Huang 	step_uV = RT8092_VOUT_STEPUV << vbank_idx;
269*32a708baSChiYuan Huang 	min_uV = (RT8092_VOUT_BASEUV + RT8092_VOUT_STEPUV * RT8092_VOUT_MINSEL) << vbank_idx;
270*32a708baSChiYuan Huang 
271*32a708baSChiYuan Huang 	desc->name = "rt8092";
272*32a708baSChiYuan Huang 	desc->owner = THIS_MODULE;
273*32a708baSChiYuan Huang 	desc->type = REGULATOR_VOLTAGE;
274*32a708baSChiYuan Huang 	desc->ops = &rt8092_regulator_ops;
275*32a708baSChiYuan Huang 	desc->n_voltages = RT8092_NUM_VOLTS;
276*32a708baSChiYuan Huang 	desc->min_uV = min_uV;
277*32a708baSChiYuan Huang 	desc->uV_step = step_uV;
278*32a708baSChiYuan Huang 	desc->linear_min_sel = RT8092_VOUT_MINSEL;
279*32a708baSChiYuan Huang 	desc->enable_reg = desc->vsel_reg = vsel_high ? RT8092_REG_VOUTH : RT8092_REG_VOUTL;
280*32a708baSChiYuan Huang 	desc->vsel_mask = RT8092_VSEL_MASK;
281*32a708baSChiYuan Huang 	desc->enable_mask = RT8092_VOUTEN_MASK;
282*32a708baSChiYuan Huang 	desc->enable_time = RT8092_INITSS_US;
283*32a708baSChiYuan Huang 	desc->of_map_mode = rt8092_of_map_mode;
284*32a708baSChiYuan Huang 
285*32a708baSChiYuan Huang 	cfg.dev = dev;
286*32a708baSChiYuan Huang 	cfg.of_node = dev_of_node(dev);
287*32a708baSChiYuan Huang 	cfg.init_data = of_get_regulator_init_data(dev, dev_of_node(dev), desc);
288*32a708baSChiYuan Huang 
289*32a708baSChiYuan Huang 	rdev = devm_regulator_register(dev, desc, &cfg);
290*32a708baSChiYuan Huang 	if (IS_ERR(rdev))
291*32a708baSChiYuan Huang 		return dev_err_probe(dev, PTR_ERR(rdev), "Failed to register regulator\n");
292*32a708baSChiYuan Huang 
293*32a708baSChiYuan Huang 	return 0;
294*32a708baSChiYuan Huang }
295*32a708baSChiYuan Huang 
296*32a708baSChiYuan Huang static const struct of_device_id rt8092_device_tables[] = {
297*32a708baSChiYuan Huang 	{ .compatible = "richtek,rt8092" },
298*32a708baSChiYuan Huang 	{}
299*32a708baSChiYuan Huang };
300*32a708baSChiYuan Huang MODULE_DEVICE_TABLE(of, rt8092_device_tables);
301*32a708baSChiYuan Huang 
302*32a708baSChiYuan Huang static struct i2c_driver rt8092_driver = {
303*32a708baSChiYuan Huang 	.driver = {
304*32a708baSChiYuan Huang 		.name = "rt8092",
305*32a708baSChiYuan Huang 		.of_match_table = rt8092_device_tables,
306*32a708baSChiYuan Huang 	},
307*32a708baSChiYuan Huang 	.probe = rt8092_probe,
308*32a708baSChiYuan Huang };
309*32a708baSChiYuan Huang module_i2c_driver(rt8092_driver);
310*32a708baSChiYuan Huang 
311*32a708baSChiYuan Huang MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
312*32a708baSChiYuan Huang MODULE_DESCRIPTION("Richtek RT8092 Regulator Driver");
313*32a708baSChiYuan Huang MODULE_LICENSE("GPL");
314