1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Device driver for RT5739 regulator |
4 | * |
5 | * Copyright (C) 2023 Richtek Technology Corp. |
6 | * |
7 | * Author: ChiYuan Huang <cy_huang@richtek.com> |
8 | */ |
9 | |
10 | #include <linux/bits.h> |
11 | #include <linux/gpio/consumer.h> |
12 | #include <linux/i2c.h> |
13 | #include <linux/kernel.h> |
14 | #include <linux/mod_devicetable.h> |
15 | #include <linux/property.h> |
16 | #include <linux/regmap.h> |
17 | #include <linux/regulator/driver.h> |
18 | #include <linux/regulator/of_regulator.h> |
19 | |
20 | #define RT5739_AUTO_MODE 0 |
21 | #define RT5739_FPWM_MODE 1 |
22 | |
23 | #define RT5739_REG_NSEL0 0x00 |
24 | #define RT5739_REG_NSEL1 0x01 |
25 | #define RT5739_REG_CNTL1 0x02 |
26 | #define RT5739_REG_ID1 0x03 |
27 | #define RT5739_REG_CNTL2 0x06 |
28 | #define RT5739_REG_CNTL4 0x08 |
29 | |
30 | #define RT5739_VSEL_MASK GENMASK(7, 0) |
31 | #define RT5739_MODEVSEL1_MASK BIT(1) |
32 | #define RT5739_MODEVSEL0_MASK BIT(0) |
33 | #define RT5739_VID_MASK GENMASK(7, 5) |
34 | #define RT5739_DID_MASK GENMASK(3, 0) |
35 | #define RT5739_ACTD_MASK BIT(7) |
36 | #define RT5739_ENVSEL1_MASK BIT(1) |
37 | #define RT5739_ENVSEL0_MASK BIT(0) |
38 | |
39 | #define RT5733_CHIPDIE_ID 0x1 |
40 | #define RT5733_VOLT_MINUV 270000 |
41 | #define RT5733_VOLT_MAXUV 1401250 |
42 | #define RT5733_VOLT_STPUV 6250 |
43 | #define RT5733_N_VOLTS 182 |
44 | |
45 | #define RT5739_VOLT_MINUV 300000 |
46 | #define RT5739_VOLT_MAXUV 1300000 |
47 | #define RT5739_VOLT_STPUV 5000 |
48 | #define RT5739_N_VOLTS 201 |
49 | #define RT5739_I2CRDY_TIMEUS 1000 |
50 | |
51 | static int rt5739_set_mode(struct regulator_dev *rdev, unsigned int mode) |
52 | { |
53 | const struct regulator_desc *desc = rdev->desc; |
54 | struct regmap *regmap = rdev_get_regmap(rdev); |
55 | unsigned int mask, val; |
56 | |
57 | if (desc->vsel_reg == RT5739_REG_NSEL0) |
58 | mask = RT5739_MODEVSEL0_MASK; |
59 | else |
60 | mask = RT5739_MODEVSEL1_MASK; |
61 | |
62 | switch (mode) { |
63 | case REGULATOR_MODE_FAST: |
64 | val = mask; |
65 | break; |
66 | case REGULATOR_MODE_NORMAL: |
67 | val = 0; |
68 | break; |
69 | default: |
70 | return -EINVAL; |
71 | } |
72 | |
73 | return regmap_update_bits(map: regmap, RT5739_REG_CNTL1, mask, val); |
74 | } |
75 | |
76 | static unsigned int rt5739_get_mode(struct regulator_dev *rdev) |
77 | { |
78 | const struct regulator_desc *desc = rdev->desc; |
79 | struct regmap *regmap = rdev_get_regmap(rdev); |
80 | unsigned int mask, val; |
81 | int ret; |
82 | |
83 | if (desc->vsel_reg == RT5739_REG_NSEL0) |
84 | mask = RT5739_MODEVSEL0_MASK; |
85 | else |
86 | mask = RT5739_MODEVSEL1_MASK; |
87 | |
88 | ret = regmap_read(map: regmap, RT5739_REG_CNTL1, val: &val); |
89 | if (ret) |
90 | return REGULATOR_MODE_INVALID; |
91 | |
92 | if (val & mask) |
93 | return REGULATOR_MODE_FAST; |
94 | |
95 | return REGULATOR_MODE_NORMAL; |
96 | } |
97 | |
98 | static int rt5739_set_suspend_voltage(struct regulator_dev *rdev, int uV) |
99 | { |
100 | const struct regulator_desc *desc = rdev->desc; |
101 | struct regmap *regmap = rdev_get_regmap(rdev); |
102 | unsigned int reg, vsel; |
103 | int max_uV; |
104 | |
105 | max_uV = desc->min_uV + desc->uV_step * (desc->n_voltages - 1); |
106 | |
107 | if (uV < desc->min_uV || uV > max_uV) |
108 | return -EINVAL; |
109 | |
110 | if (desc->vsel_reg == RT5739_REG_NSEL0) |
111 | reg = RT5739_REG_NSEL1; |
112 | else |
113 | reg = RT5739_REG_NSEL0; |
114 | |
115 | vsel = (uV - desc->min_uV) / desc->uV_step; |
116 | return regmap_write(map: regmap, reg, val: vsel); |
117 | } |
118 | |
119 | static int rt5739_set_suspend_enable(struct regulator_dev *rdev) |
120 | { |
121 | const struct regulator_desc *desc = rdev->desc; |
122 | struct regmap *regmap = rdev_get_regmap(rdev); |
123 | unsigned int mask; |
124 | |
125 | if (desc->vsel_reg == RT5739_REG_NSEL0) |
126 | mask = RT5739_ENVSEL1_MASK; |
127 | else |
128 | mask = RT5739_ENVSEL0_MASK; |
129 | |
130 | return regmap_update_bits(map: regmap, reg: desc->enable_reg, mask, val: mask); |
131 | } |
132 | |
133 | static int rt5739_set_suspend_disable(struct regulator_dev *rdev) |
134 | { |
135 | const struct regulator_desc *desc = rdev->desc; |
136 | struct regmap *regmap = rdev_get_regmap(rdev); |
137 | unsigned int mask; |
138 | |
139 | if (desc->vsel_reg == RT5739_REG_NSEL0) |
140 | mask = RT5739_ENVSEL1_MASK; |
141 | else |
142 | mask = RT5739_ENVSEL0_MASK; |
143 | |
144 | return regmap_update_bits(map: regmap, reg: desc->enable_reg, mask, val: 0); |
145 | } |
146 | |
147 | static int rt5739_set_suspend_mode(struct regulator_dev *rdev, |
148 | unsigned int mode) |
149 | { |
150 | const struct regulator_desc *desc = rdev->desc; |
151 | struct regmap *regmap = rdev_get_regmap(rdev); |
152 | unsigned int mask, val; |
153 | |
154 | if (desc->vsel_reg == RT5739_REG_NSEL0) |
155 | mask = RT5739_MODEVSEL1_MASK; |
156 | else |
157 | mask = RT5739_MODEVSEL0_MASK; |
158 | |
159 | switch (mode) { |
160 | case REGULATOR_MODE_FAST: |
161 | val = mask; |
162 | break; |
163 | case REGULATOR_MODE_NORMAL: |
164 | val = 0; |
165 | break; |
166 | default: |
167 | return -EINVAL; |
168 | } |
169 | |
170 | return regmap_update_bits(map: regmap, RT5739_REG_CNTL1, mask, val); |
171 | } |
172 | |
173 | static const struct regulator_ops rt5739_regulator_ops = { |
174 | .list_voltage = regulator_list_voltage_linear, |
175 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
176 | .set_voltage_sel = regulator_set_voltage_sel_regmap, |
177 | .enable = regulator_enable_regmap, |
178 | .disable = regulator_disable_regmap, |
179 | .is_enabled = regulator_is_enabled_regmap, |
180 | .set_active_discharge = regulator_set_active_discharge_regmap, |
181 | .set_mode = rt5739_set_mode, |
182 | .get_mode = rt5739_get_mode, |
183 | .set_suspend_voltage = rt5739_set_suspend_voltage, |
184 | .set_suspend_enable = rt5739_set_suspend_enable, |
185 | .set_suspend_disable = rt5739_set_suspend_disable, |
186 | .set_suspend_mode = rt5739_set_suspend_mode, |
187 | }; |
188 | |
189 | static unsigned int rt5739_of_map_mode(unsigned int mode) |
190 | { |
191 | switch (mode) { |
192 | case RT5739_AUTO_MODE: |
193 | return REGULATOR_MODE_NORMAL; |
194 | case RT5739_FPWM_MODE: |
195 | return REGULATOR_MODE_FAST; |
196 | default: |
197 | return REGULATOR_MODE_INVALID; |
198 | } |
199 | } |
200 | |
201 | static void rt5739_init_regulator_desc(struct regulator_desc *desc, |
202 | bool vsel_active_high, u8 did) |
203 | { |
204 | /* Fixed */ |
205 | desc->name = "rt5739-regulator" ; |
206 | desc->owner = THIS_MODULE; |
207 | desc->ops = &rt5739_regulator_ops; |
208 | desc->vsel_mask = RT5739_VSEL_MASK; |
209 | desc->enable_reg = RT5739_REG_CNTL2; |
210 | desc->active_discharge_reg = RT5739_REG_CNTL1; |
211 | desc->active_discharge_mask = RT5739_ACTD_MASK; |
212 | desc->active_discharge_on = RT5739_ACTD_MASK; |
213 | desc->of_map_mode = rt5739_of_map_mode; |
214 | |
215 | /* Assigned by vsel level */ |
216 | if (vsel_active_high) { |
217 | desc->vsel_reg = RT5739_REG_NSEL1; |
218 | desc->enable_mask = RT5739_ENVSEL1_MASK; |
219 | } else { |
220 | desc->vsel_reg = RT5739_REG_NSEL0; |
221 | desc->enable_mask = RT5739_ENVSEL0_MASK; |
222 | } |
223 | |
224 | /* Assigned by CHIPDIE ID */ |
225 | switch (did) { |
226 | case RT5733_CHIPDIE_ID: |
227 | desc->n_voltages = RT5733_N_VOLTS; |
228 | desc->min_uV = RT5733_VOLT_MINUV; |
229 | desc->uV_step = RT5733_VOLT_STPUV; |
230 | break; |
231 | default: |
232 | desc->n_voltages = RT5739_N_VOLTS; |
233 | desc->min_uV = RT5739_VOLT_MINUV; |
234 | desc->uV_step = RT5739_VOLT_STPUV; |
235 | break; |
236 | } |
237 | } |
238 | |
239 | static const struct regmap_config rt5739_regmap_config = { |
240 | .name = "rt5739" , |
241 | .reg_bits = 8, |
242 | .val_bits = 8, |
243 | .max_register = RT5739_REG_CNTL4, |
244 | }; |
245 | |
246 | static int rt5739_probe(struct i2c_client *i2c) |
247 | { |
248 | struct device *dev = &i2c->dev; |
249 | struct regulator_desc *desc; |
250 | struct regmap *regmap; |
251 | struct gpio_desc *enable_gpio; |
252 | struct regulator_config cfg = {}; |
253 | struct regulator_dev *rdev; |
254 | bool vsel_acth; |
255 | unsigned int vid; |
256 | int ret; |
257 | |
258 | desc = devm_kzalloc(dev, size: sizeof(*desc), GFP_KERNEL); |
259 | if (!desc) |
260 | return -ENOMEM; |
261 | |
262 | enable_gpio = devm_gpiod_get_optional(dev, con_id: "enable" , flags: GPIOD_OUT_HIGH); |
263 | if (IS_ERR(ptr: enable_gpio)) |
264 | return dev_err_probe(dev, err: PTR_ERR(ptr: enable_gpio), fmt: "Failed to get 'enable' gpio\n" ); |
265 | else if (enable_gpio) |
266 | usleep_range(RT5739_I2CRDY_TIMEUS, RT5739_I2CRDY_TIMEUS + 1000); |
267 | |
268 | regmap = devm_regmap_init_i2c(i2c, &rt5739_regmap_config); |
269 | if (IS_ERR(ptr: regmap)) |
270 | return dev_err_probe(dev, err: PTR_ERR(ptr: regmap), fmt: "Failed to init regmap\n" ); |
271 | |
272 | ret = regmap_read(map: regmap, RT5739_REG_ID1, val: &vid); |
273 | if (ret) |
274 | return dev_err_probe(dev, err: ret, fmt: "Failed to read VID\n" ); |
275 | |
276 | /* RT5739: (VID & MASK) must be 0 */ |
277 | if (vid & RT5739_VID_MASK) |
278 | return dev_err_probe(dev, err: -ENODEV, fmt: "Incorrect VID (0x%02x)\n" , vid); |
279 | |
280 | vsel_acth = device_property_read_bool(dev, propname: "richtek,vsel-active-high" ); |
281 | |
282 | rt5739_init_regulator_desc(desc, vsel_active_high: vsel_acth, did: vid & RT5739_DID_MASK); |
283 | |
284 | cfg.dev = dev; |
285 | cfg.of_node = dev_of_node(dev); |
286 | cfg.init_data = of_get_regulator_init_data(dev, node: dev_of_node(dev), desc); |
287 | rdev = devm_regulator_register(dev, regulator_desc: desc, config: &cfg); |
288 | if (IS_ERR(ptr: rdev)) |
289 | return dev_err_probe(dev, err: PTR_ERR(ptr: rdev), fmt: "Failed to register regulator\n" ); |
290 | |
291 | return 0; |
292 | } |
293 | |
294 | static const struct of_device_id rt5739_device_table[] = { |
295 | { .compatible = "richtek,rt5733" }, |
296 | { .compatible = "richtek,rt5739" }, |
297 | { /* sentinel */ } |
298 | }; |
299 | MODULE_DEVICE_TABLE(of, rt5739_device_table); |
300 | |
301 | static struct i2c_driver rt5739_driver = { |
302 | .driver = { |
303 | .name = "rt5739" , |
304 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
305 | .of_match_table = rt5739_device_table, |
306 | }, |
307 | .probe = rt5739_probe, |
308 | }; |
309 | module_i2c_driver(rt5739_driver); |
310 | |
311 | MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>" ); |
312 | MODULE_DESCRIPTION("Richtek RT5739 regulator driver" ); |
313 | MODULE_LICENSE("GPL" ); |
314 | |