Merge tag 'char-misc-6.5-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[linux-block.git] / drivers / regulator / rt5739.c
CommitLineData
4536f3b9
CH
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_ACTD_MASK BIT(7)
35#define RT5739_ENVSEL1_MASK BIT(1)
36#define RT5739_ENVSEL0_MASK BIT(0)
37
38#define RT5739_VOLT_MINUV 300000
39#define RT5739_VOLT_MAXUV 1300000
40#define RT5739_VOLT_STPUV 5000
41#define RT5739_N_VOLTS 201
42#define RT5739_I2CRDY_TIMEUS 1000
43
44static int rt5739_set_mode(struct regulator_dev *rdev, unsigned int mode)
45{
46 const struct regulator_desc *desc = rdev->desc;
47 struct regmap *regmap = rdev_get_regmap(rdev);
48 unsigned int mask, val;
49
50 if (desc->vsel_reg == RT5739_REG_NSEL0)
51 mask = RT5739_MODEVSEL0_MASK;
52 else
53 mask = RT5739_MODEVSEL1_MASK;
54
55 switch (mode) {
56 case REGULATOR_MODE_FAST:
57 val = mask;
58 break;
59 case REGULATOR_MODE_NORMAL:
60 val = 0;
61 break;
62 default:
63 return -EINVAL;
64 }
65
66 return regmap_update_bits(regmap, RT5739_REG_CNTL1, mask, val);
67}
68
69static unsigned int rt5739_get_mode(struct regulator_dev *rdev)
70{
71 const struct regulator_desc *desc = rdev->desc;
72 struct regmap *regmap = rdev_get_regmap(rdev);
73 unsigned int mask, val;
74 int ret;
75
76 if (desc->vsel_reg == RT5739_REG_NSEL0)
77 mask = RT5739_MODEVSEL0_MASK;
78 else
79 mask = RT5739_MODEVSEL1_MASK;
80
81 ret = regmap_read(regmap, RT5739_REG_CNTL1, &val);
82 if (ret)
83 return REGULATOR_MODE_INVALID;
84
85 if (val & mask)
86 return REGULATOR_MODE_FAST;
87
88 return REGULATOR_MODE_NORMAL;
89}
90
91static int rt5739_set_suspend_voltage(struct regulator_dev *rdev, int uV)
92{
93 const struct regulator_desc *desc = rdev->desc;
94 struct regmap *regmap = rdev_get_regmap(rdev);
95 unsigned int reg, vsel;
96
97 if (uV < RT5739_VOLT_MINUV || uV > RT5739_VOLT_MAXUV)
98 return -EINVAL;
99
100 if (desc->vsel_reg == RT5739_REG_NSEL0)
101 reg = RT5739_REG_NSEL1;
102 else
103 reg = RT5739_REG_NSEL0;
104
105 vsel = (uV - RT5739_VOLT_MINUV) / RT5739_VOLT_STPUV;
106 return regmap_write(regmap, reg, vsel);
107}
108
109static int rt5739_set_suspend_enable(struct regulator_dev *rdev)
110{
111 const struct regulator_desc *desc = rdev->desc;
112 struct regmap *regmap = rdev_get_regmap(rdev);
113 unsigned int mask;
114
115 if (desc->vsel_reg == RT5739_REG_NSEL0)
116 mask = RT5739_ENVSEL1_MASK;
117 else
118 mask = RT5739_ENVSEL0_MASK;
119
120 return regmap_update_bits(regmap, desc->enable_reg, mask, mask);
121}
122
123static int rt5739_set_suspend_disable(struct regulator_dev *rdev)
124{
125 const struct regulator_desc *desc = rdev->desc;
126 struct regmap *regmap = rdev_get_regmap(rdev);
127 unsigned int mask;
128
129 if (desc->vsel_reg == RT5739_REG_NSEL0)
130 mask = RT5739_ENVSEL1_MASK;
131 else
132 mask = RT5739_ENVSEL0_MASK;
133
134 return regmap_update_bits(regmap, desc->enable_reg, mask, 0);
135}
136
137static int rt5739_set_suspend_mode(struct regulator_dev *rdev,
138 unsigned int mode)
139{
140 const struct regulator_desc *desc = rdev->desc;
141 struct regmap *regmap = rdev_get_regmap(rdev);
142 unsigned int mask, val;
143
144 if (desc->vsel_reg == RT5739_REG_NSEL0)
145 mask = RT5739_MODEVSEL1_MASK;
146 else
147 mask = RT5739_MODEVSEL0_MASK;
148
149 switch (mode) {
150 case REGULATOR_MODE_FAST:
151 val = mask;
152 break;
153 case REGULATOR_MODE_NORMAL:
154 val = 0;
155 break;
156 default:
157 return -EINVAL;
158 }
159
160 return regmap_update_bits(regmap, RT5739_REG_CNTL1, mask, val);
161}
162
163static const struct regulator_ops rt5739_regulator_ops = {
164 .list_voltage = regulator_list_voltage_linear,
165 .get_voltage_sel = regulator_get_voltage_sel_regmap,
166 .set_voltage_sel = regulator_set_voltage_sel_regmap,
167 .enable = regulator_enable_regmap,
168 .disable = regulator_disable_regmap,
169 .is_enabled = regulator_is_enabled_regmap,
170 .set_active_discharge = regulator_set_active_discharge_regmap,
171 .set_mode = rt5739_set_mode,
172 .get_mode = rt5739_get_mode,
173 .set_suspend_voltage = rt5739_set_suspend_voltage,
174 .set_suspend_enable = rt5739_set_suspend_enable,
175 .set_suspend_disable = rt5739_set_suspend_disable,
176 .set_suspend_mode = rt5739_set_suspend_mode,
177};
178
179static unsigned int rt5739_of_map_mode(unsigned int mode)
180{
181 switch (mode) {
182 case RT5739_AUTO_MODE:
183 return REGULATOR_MODE_NORMAL;
184 case RT5739_FPWM_MODE:
185 return REGULATOR_MODE_FAST;
186 default:
187 return REGULATOR_MODE_INVALID;
188 }
189}
190
191static void rt5739_init_regulator_desc(struct regulator_desc *desc,
192 bool vsel_active_high)
193{
194 /* Fixed */
195 desc->name = "rt5739-regulator";
196 desc->owner = THIS_MODULE;
197 desc->ops = &rt5739_regulator_ops;
198 desc->n_voltages = RT5739_N_VOLTS;
199 desc->min_uV = RT5739_VOLT_MINUV;
200 desc->uV_step = RT5739_VOLT_STPUV;
201 desc->vsel_mask = RT5739_VSEL_MASK;
202 desc->enable_reg = RT5739_REG_CNTL2;
203 desc->active_discharge_reg = RT5739_REG_CNTL1;
204 desc->active_discharge_mask = RT5739_ACTD_MASK;
205 desc->active_discharge_on = RT5739_ACTD_MASK;
206 desc->of_map_mode = rt5739_of_map_mode;
207
208 /* Assigned by vsel level */
209 if (vsel_active_high) {
210 desc->vsel_reg = RT5739_REG_NSEL1;
211 desc->enable_mask = RT5739_ENVSEL1_MASK;
212 } else {
213 desc->vsel_reg = RT5739_REG_NSEL0;
214 desc->enable_mask = RT5739_ENVSEL0_MASK;
215 }
216}
217
218static const struct regmap_config rt5739_regmap_config = {
219 .name = "rt5739",
220 .reg_bits = 8,
221 .val_bits = 8,
222 .max_register = RT5739_REG_CNTL4,
223};
224
225static int rt5739_probe(struct i2c_client *i2c)
226{
227 struct device *dev = &i2c->dev;
228 struct regulator_desc *desc;
229 struct regmap *regmap;
230 struct gpio_desc *enable_gpio;
231 struct regulator_config cfg = {};
232 struct regulator_dev *rdev;
233 bool vsel_acth;
234 unsigned int vid;
235 int ret;
236
237 desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
238 if (!desc)
239 return -ENOMEM;
240
241 enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
242 if (IS_ERR(enable_gpio))
243 return dev_err_probe(dev, PTR_ERR(enable_gpio), "Failed to get 'enable' gpio\n");
244 else if (enable_gpio)
245 usleep_range(RT5739_I2CRDY_TIMEUS, RT5739_I2CRDY_TIMEUS + 1000);
246
247 regmap = devm_regmap_init_i2c(i2c, &rt5739_regmap_config);
248 if (IS_ERR(regmap))
249 return dev_err_probe(dev, PTR_ERR(regmap), "Failed to init regmap\n");
250
251 ret = regmap_read(regmap, RT5739_REG_ID1, &vid);
252 if (ret)
253 return dev_err_probe(dev, ret, "Failed to read VID\n");
254
255 /* RT5739: (VID & MASK) must be 0 */
256 if (vid & RT5739_VID_MASK)
257 return dev_err_probe(dev, -ENODEV, "Incorrect VID (0x%02x)\n", vid);
258
259 vsel_acth = device_property_read_bool(dev, "richtek,vsel-active-high");
260
261 rt5739_init_regulator_desc(desc, vsel_acth);
262
263 cfg.dev = dev;
264 cfg.of_node = dev_of_node(dev);
265 cfg.init_data = of_get_regulator_init_data(dev, dev_of_node(dev), desc);
266 rdev = devm_regulator_register(dev, desc, &cfg);
267 if (IS_ERR(rdev))
268 return dev_err_probe(dev, PTR_ERR(rdev), "Failed to register regulator\n");
269
270 return 0;
271}
272
273static const struct of_device_id rt5739_device_table[] = {
274 { .compatible = "richtek,rt5739" },
275 { /* sentinel */ }
276};
277MODULE_DEVICE_TABLE(of, rt5739_device_table);
278
279static struct i2c_driver rt5739_driver = {
280 .driver = {
281 .name = "rt5739",
bdce47bb 282 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
4536f3b9
CH
283 .of_match_table = rt5739_device_table,
284 },
d692cc61 285 .probe = rt5739_probe,
4536f3b9
CH
286};
287module_i2c_driver(rt5739_driver);
288
289MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
290MODULE_DESCRIPTION("Richtek RT5739 regulator driver");
291MODULE_LICENSE("GPL");