Commit | Line | Data |
---|---|---|
6928a3c0 CH |
1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* | |
3 | * Copyright (C) 2023 Richtek Technology Corp. | |
4 | * | |
5 | * Author: ChiYuan Huang <cy_huang@richtek.com> | |
6 | */ | |
7 | ||
8 | #include <linux/i2c.h> | |
9 | #include <linux/kernel.h> | |
10 | #include <linux/mod_devicetable.h> | |
11 | #include <linux/module.h> | |
12 | #include <linux/property.h> | |
13 | #include <linux/regmap.h> | |
14 | #include <linux/regulator/driver.h> | |
15 | #include <linux/regulator/of_regulator.h> | |
16 | ||
17 | #define RT4803_AUTO_MODE 1 | |
18 | #define RT4803_FPWM_MODE 2 | |
19 | ||
20 | #define RT4803_REG_CONFIG 0x01 | |
21 | #define RT4803_REG_VSELL 0x02 | |
22 | #define RT4803_REG_VSELH 0x03 | |
23 | #define RT4803_REG_ILIM 0x04 | |
24 | #define RT4803_REG_STAT 0x05 | |
25 | ||
26 | #define RT4803_MODE_MASK GENMASK(1, 0) | |
27 | #define RT4803_VSEL_MASK GENMASK(4, 0) | |
28 | #define RT4803_ILIM_MASK GENMASK(3, 0) | |
29 | #define RT4803_TSD_MASK BIT(7) | |
30 | #define RT4803_HOTDIE_MASK BIT(6) | |
31 | #define RT4803_FAULT_MASK BIT(1) | |
32 | #define RT4803_PGOOD_MASK BIT(0) | |
33 | ||
34 | #define RT4803_VOUT_MINUV 2850000 | |
35 | #define RT4803_VOUT_STEPUV 50000 | |
36 | #define RT4803_VOUT_NUM 32 | |
37 | ||
38 | static int rt4803_set_mode(struct regulator_dev *rdev, unsigned int mode) | |
39 | { | |
40 | struct regmap *regmap = rdev_get_regmap(rdev); | |
41 | unsigned int modeval; | |
42 | ||
43 | switch (mode) { | |
44 | case REGULATOR_MODE_NORMAL: | |
45 | modeval = RT4803_AUTO_MODE; | |
46 | break; | |
47 | case REGULATOR_MODE_FAST: | |
48 | modeval = RT4803_FPWM_MODE; | |
49 | break; | |
50 | default: | |
51 | return -EINVAL; | |
52 | } | |
53 | ||
54 | modeval <<= ffs(RT4803_MODE_MASK) - 1; | |
55 | ||
56 | return regmap_update_bits(regmap, RT4803_REG_CONFIG, RT4803_MODE_MASK, modeval); | |
57 | } | |
58 | ||
59 | static unsigned int rt4803_get_mode(struct regulator_dev *rdev) | |
60 | { | |
61 | struct regmap *regmap = rdev_get_regmap(rdev); | |
62 | unsigned int modeval; | |
63 | int ret; | |
64 | ||
65 | ret = regmap_read(regmap, RT4803_REG_CONFIG, &modeval); | |
66 | if (ret) | |
67 | return REGULATOR_MODE_INVALID; | |
68 | ||
69 | modeval >>= ffs(RT4803_MODE_MASK) - 1; | |
70 | ||
71 | switch (modeval) { | |
72 | case RT4803_AUTO_MODE: | |
73 | return REGULATOR_MODE_NORMAL; | |
74 | case RT4803_FPWM_MODE: | |
75 | return REGULATOR_MODE_FAST; | |
76 | default: | |
77 | return REGULATOR_MODE_INVALID; | |
78 | } | |
79 | } | |
80 | ||
81 | static int rt4803_get_error_flags(struct regulator_dev *rdev, unsigned int *flags) | |
82 | { | |
83 | struct regmap *regmap = rdev_get_regmap(rdev); | |
84 | unsigned int state, events = 0; | |
85 | int ret; | |
86 | ||
87 | ret = regmap_read(regmap, RT4803_REG_STAT, &state); | |
88 | if (ret) | |
89 | return ret; | |
90 | ||
91 | if (state & RT4803_PGOOD_MASK) | |
92 | goto out_error_flag; | |
93 | ||
94 | if (state & RT4803_FAULT_MASK) | |
95 | events |= REGULATOR_ERROR_FAIL; | |
96 | ||
97 | if (state & RT4803_HOTDIE_MASK) | |
98 | events |= REGULATOR_ERROR_OVER_TEMP_WARN; | |
99 | ||
100 | if (state & RT4803_TSD_MASK) | |
101 | events |= REGULATOR_ERROR_OVER_TEMP; | |
102 | ||
103 | out_error_flag: | |
104 | *flags = events; | |
105 | return 0; | |
106 | } | |
107 | ||
108 | static int rt4803_set_suspend_voltage(struct regulator_dev *rdev, int uV) | |
109 | { | |
110 | struct regmap *regmap = rdev_get_regmap(rdev); | |
111 | unsigned int reg, vsel; | |
112 | ||
113 | if (rdev->desc->vsel_reg == RT4803_REG_VSELL) | |
114 | reg = RT4803_REG_VSELH; | |
115 | else | |
116 | reg = RT4803_REG_VSELL; | |
117 | ||
118 | vsel = (uV - rdev->desc->min_uV) / rdev->desc->uV_step; | |
119 | vsel <<= ffs(RT4803_VSEL_MASK) - 1; | |
120 | ||
121 | return regmap_update_bits(regmap, reg, RT4803_VSEL_MASK, vsel); | |
122 | } | |
123 | ||
124 | static const struct regulator_ops rt4803_regulator_ops = { | |
125 | .list_voltage = regulator_list_voltage_linear, | |
126 | .set_voltage_sel = regulator_set_voltage_sel_regmap, | |
127 | .get_voltage_sel = regulator_get_voltage_sel_regmap, | |
128 | .set_mode = rt4803_set_mode, | |
129 | .get_mode = rt4803_get_mode, | |
130 | .get_error_flags = rt4803_get_error_flags, | |
131 | .set_suspend_voltage = rt4803_set_suspend_voltage, | |
132 | }; | |
133 | ||
134 | static unsigned int rt4803_of_map_mode(unsigned int mode) | |
135 | { | |
136 | switch (mode) { | |
137 | case RT4803_AUTO_MODE: | |
138 | return REGULATOR_MODE_NORMAL; | |
139 | case RT4803_FPWM_MODE: | |
140 | return REGULATOR_MODE_FAST; | |
141 | default: | |
142 | return REGULATOR_MODE_INVALID; | |
143 | } | |
144 | } | |
145 | ||
146 | static const struct regmap_config rt4803_regmap_config = { | |
147 | .reg_bits = 8, | |
148 | .val_bits = 8, | |
149 | .max_register = RT4803_REG_STAT, | |
150 | }; | |
151 | ||
152 | static int rt4803_probe(struct i2c_client *i2c) | |
153 | { | |
154 | struct device *dev = &i2c->dev; | |
155 | struct regmap *regmap; | |
156 | struct regulator_desc *desc; | |
157 | struct regulator_config cfg = {}; | |
158 | struct regulator_dev *rdev; | |
159 | bool vsel_act_high; | |
160 | int ret; | |
161 | ||
162 | desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); | |
163 | if (!desc) | |
164 | return -ENOMEM; | |
165 | ||
166 | regmap = devm_regmap_init_i2c(i2c, &rt4803_regmap_config); | |
167 | if (IS_ERR(regmap)) | |
168 | return dev_err_probe(dev, PTR_ERR(regmap), "Failed to init regmap\n"); | |
169 | ||
170 | /* Always configure the input current limit to max 5A at initial */ | |
171 | ret = regmap_update_bits(regmap, RT4803_REG_ILIM, RT4803_ILIM_MASK, 0xff); | |
172 | if (ret) | |
173 | return dev_err_probe(dev, ret, "Failed to config ILIM to max\n"); | |
174 | ||
175 | vsel_act_high = device_property_read_bool(dev, "richtek,vsel-active-high"); | |
176 | ||
177 | desc->name = "rt4803-regulator"; | |
178 | desc->type = REGULATOR_VOLTAGE; | |
179 | desc->owner = THIS_MODULE; | |
180 | desc->ops = &rt4803_regulator_ops; | |
181 | desc->min_uV = RT4803_VOUT_MINUV; | |
182 | desc->uV_step = RT4803_VOUT_STEPUV; | |
183 | desc->n_voltages = RT4803_VOUT_NUM; | |
184 | desc->vsel_mask = RT4803_VSEL_MASK; | |
185 | desc->of_map_mode = rt4803_of_map_mode; | |
186 | if (vsel_act_high) | |
187 | desc->vsel_reg = RT4803_REG_VSELH; | |
188 | else | |
189 | desc->vsel_reg = RT4803_REG_VSELL; | |
190 | ||
191 | cfg.dev = dev; | |
192 | cfg.of_node = dev_of_node(dev); | |
193 | cfg.init_data = of_get_regulator_init_data(dev, dev_of_node(dev), desc); | |
194 | ||
195 | rdev = devm_regulator_register(dev, desc, &cfg); | |
196 | return PTR_ERR_OR_ZERO(rdev); | |
197 | } | |
198 | ||
199 | static const struct of_device_id rt4803_device_match_table[] = { | |
200 | { .compatible = "richtek,rt4803" }, | |
201 | {} | |
202 | }; | |
203 | MODULE_DEVICE_TABLE(of, rt4803_device_match_table); | |
204 | ||
205 | static struct i2c_driver rt4803_driver = { | |
206 | .driver = { | |
207 | .name = "rt4803", | |
208 | .of_match_table = rt4803_device_match_table, | |
209 | }, | |
210 | .probe = rt4803_probe, | |
211 | }; | |
212 | module_i2c_driver(rt4803_driver); | |
213 | ||
214 | MODULE_DESCRIPTION("Richtek RT4803 voltage regulator driver"); | |
215 | MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); | |
216 | MODULE_LICENSE("GPL"); |