1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/err.h>
20#include <linux/mfd/syscon.h>
21#include <linux/of.h>
22#include <linux/platform_device.h>
23#include <linux/regmap.h>
24#include <linux/regulator/consumer.h>
25
26#define MAX_SUPPLIES 16
27
28
29
30
31
32
33
34
35
36
37
38
39#define MAX_VOLTAGE_1_8 1980000
40#define MAX_VOLTAGE_3_3 3600000
41
42#define RK3288_SOC_CON2 0x24c
43#define RK3288_SOC_CON2_FLASH0 BIT(7)
44#define RK3288_SOC_FLASH_SUPPLY_NUM 2
45
46#define RK3368_SOC_CON15 0x43c
47#define RK3368_SOC_CON15_FLASH0 BIT(14)
48#define RK3368_SOC_FLASH_SUPPLY_NUM 2
49
50#define RK3399_PMUGRF_CON0 0x180
51#define RK3399_PMUGRF_CON0_VSEL BIT(8)
52#define RK3399_PMUGRF_VSEL_SUPPLY_NUM 9
53
54struct rockchip_iodomain;
55
56
57
58
59struct rockchip_iodomain_soc_data {
60 int grf_offset;
61 const char *supply_names[MAX_SUPPLIES];
62 void (*init)(struct rockchip_iodomain *iod);
63};
64
65struct rockchip_iodomain_supply {
66 struct rockchip_iodomain *iod;
67 struct regulator *reg;
68 struct notifier_block nb;
69 int idx;
70};
71
72struct rockchip_iodomain {
73 struct device *dev;
74 struct regmap *grf;
75 struct rockchip_iodomain_soc_data *soc_data;
76 struct rockchip_iodomain_supply supplies[MAX_SUPPLIES];
77};
78
79static int rockchip_iodomain_write(struct rockchip_iodomain_supply *supply,
80 int uV)
81{
82 struct rockchip_iodomain *iod = supply->iod;
83 u32 val;
84 int ret;
85
86
87 val = (uV > MAX_VOLTAGE_1_8) ? 0 : 1;
88 val <<= supply->idx;
89
90
91 val |= (BIT(supply->idx) << 16);
92
93 ret = regmap_write(iod->grf, iod->soc_data->grf_offset, val);
94 if (ret)
95 dev_err(iod->dev, "Couldn't write to GRF\n");
96
97 return ret;
98}
99
100static int rockchip_iodomain_notify(struct notifier_block *nb,
101 unsigned long event,
102 void *data)
103{
104 struct rockchip_iodomain_supply *supply =
105 container_of(nb, struct rockchip_iodomain_supply, nb);
106 int uV;
107 int ret;
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122 if (event & REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) {
123 struct pre_voltage_change_data *pvc_data = data;
124
125 uV = max_t(unsigned long, pvc_data->old_uV, pvc_data->max_uV);
126 } else if (event & (REGULATOR_EVENT_VOLTAGE_CHANGE |
127 REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE)) {
128 uV = (unsigned long)data;
129 } else {
130 return NOTIFY_OK;
131 }
132
133 dev_dbg(supply->iod->dev, "Setting to %d\n", uV);
134
135 if (uV > MAX_VOLTAGE_3_3) {
136 dev_err(supply->iod->dev, "Voltage too high: %d\n", uV);
137
138 if (event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE)
139 return NOTIFY_BAD;
140 }
141
142 ret = rockchip_iodomain_write(supply, uV);
143 if (ret && event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE)
144 return NOTIFY_BAD;
145
146 dev_info(supply->iod->dev, "Setting to %d done\n", uV);
147 return NOTIFY_OK;
148}
149
150static void rk3288_iodomain_init(struct rockchip_iodomain *iod)
151{
152 int ret;
153 u32 val;
154
155
156 if (!iod->supplies[RK3288_SOC_FLASH_SUPPLY_NUM].reg)
157 return;
158
159
160
161
162
163 val = RK3288_SOC_CON2_FLASH0 | (RK3288_SOC_CON2_FLASH0 << 16);
164 ret = regmap_write(iod->grf, RK3288_SOC_CON2, val);
165 if (ret < 0)
166 dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
167}
168
169static void rk3368_iodomain_init(struct rockchip_iodomain *iod)
170{
171 int ret;
172 u32 val;
173
174
175 if (!iod->supplies[RK3368_SOC_FLASH_SUPPLY_NUM].reg)
176 return;
177
178
179
180
181
182 val = RK3368_SOC_CON15_FLASH0 | (RK3368_SOC_CON15_FLASH0 << 16);
183 ret = regmap_write(iod->grf, RK3368_SOC_CON15, val);
184 if (ret < 0)
185 dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
186}
187
188static void rk3399_pmu_iodomain_init(struct rockchip_iodomain *iod)
189{
190 int ret;
191 u32 val;
192
193
194 if (!iod->supplies[RK3399_PMUGRF_VSEL_SUPPLY_NUM].reg)
195 return;
196
197
198
199
200
201 val = RK3399_PMUGRF_CON0_VSEL | (RK3399_PMUGRF_CON0_VSEL << 16);
202 ret = regmap_write(iod->grf, RK3399_PMUGRF_CON0, val);
203 if (ret < 0)
204 dev_warn(iod->dev, "couldn't update pmu io iodomain ctrl\n");
205}
206
207
208
209
210
211static const struct rockchip_iodomain_soc_data soc_data_rk3188 = {
212 .grf_offset = 0x104,
213 .supply_names = {
214 NULL,
215 NULL,
216 NULL,
217 NULL,
218 NULL,
219 NULL,
220 NULL,
221 NULL,
222 "ap0",
223 "ap1",
224 "cif",
225 "flash",
226 "vccio0",
227 "vccio1",
228 "lcdc0",
229 "lcdc1",
230 },
231};
232
233static const struct rockchip_iodomain_soc_data soc_data_rk3288 = {
234 .grf_offset = 0x380,
235 .supply_names = {
236 "lcdc",
237 "dvp",
238 "flash0",
239 "flash1",
240 "wifi",
241 "bb",
242 "audio",
243 "sdcard",
244 "gpio30",
245 "gpio1830",
246 },
247 .init = rk3288_iodomain_init,
248};
249
250static const struct rockchip_iodomain_soc_data soc_data_rk3368 = {
251 .grf_offset = 0x900,
252 .supply_names = {
253 NULL,
254 "dvp",
255 "flash0",
256 "wifi",
257 NULL,
258 "audio",
259 "sdcard",
260 "gpio30",
261 "gpio1830",
262 },
263 .init = rk3368_iodomain_init,
264};
265
266static const struct rockchip_iodomain_soc_data soc_data_rk3368_pmu = {
267 .grf_offset = 0x100,
268 .supply_names = {
269 NULL,
270 NULL,
271 NULL,
272 NULL,
273 "pmu",
274 "vop",
275 },
276};
277
278static const struct rockchip_iodomain_soc_data soc_data_rk3399 = {
279 .grf_offset = 0xe640,
280 .supply_names = {
281 "bt656",
282 "audio",
283 "sdmmc",
284 "gpio1830",
285 },
286};
287
288static const struct rockchip_iodomain_soc_data soc_data_rk3399_pmu = {
289 .grf_offset = 0x180,
290 .supply_names = {
291 NULL,
292 NULL,
293 NULL,
294 NULL,
295 NULL,
296 NULL,
297 NULL,
298 NULL,
299 NULL,
300 "pmu1830",
301 },
302 .init = rk3399_pmu_iodomain_init,
303};
304
305static const struct of_device_id rockchip_iodomain_match[] = {
306 {
307 .compatible = "rockchip,rk3188-io-voltage-domain",
308 .data = (void *)&soc_data_rk3188
309 },
310 {
311 .compatible = "rockchip,rk3288-io-voltage-domain",
312 .data = (void *)&soc_data_rk3288
313 },
314 {
315 .compatible = "rockchip,rk3368-io-voltage-domain",
316 .data = (void *)&soc_data_rk3368
317 },
318 {
319 .compatible = "rockchip,rk3368-pmu-io-voltage-domain",
320 .data = (void *)&soc_data_rk3368_pmu
321 },
322 {
323 .compatible = "rockchip,rk3399-io-voltage-domain",
324 .data = (void *)&soc_data_rk3399
325 },
326 {
327 .compatible = "rockchip,rk3399-pmu-io-voltage-domain",
328 .data = (void *)&soc_data_rk3399_pmu
329 },
330 { },
331};
332MODULE_DEVICE_TABLE(of, rockchip_iodomain_match);
333
334static int rockchip_iodomain_probe(struct platform_device *pdev)
335{
336 struct device_node *np = pdev->dev.of_node;
337 const struct of_device_id *match;
338 struct rockchip_iodomain *iod;
339 struct device *parent;
340 int i, ret = 0;
341
342 if (!np)
343 return -ENODEV;
344
345 iod = devm_kzalloc(&pdev->dev, sizeof(*iod), GFP_KERNEL);
346 if (!iod)
347 return -ENOMEM;
348
349 iod->dev = &pdev->dev;
350 platform_set_drvdata(pdev, iod);
351
352 match = of_match_node(rockchip_iodomain_match, np);
353 iod->soc_data = (struct rockchip_iodomain_soc_data *)match->data;
354
355 parent = pdev->dev.parent;
356 if (parent && parent->of_node) {
357 iod->grf = syscon_node_to_regmap(parent->of_node);
358 } else {
359 dev_dbg(&pdev->dev, "falling back to old binding\n");
360 iod->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
361 }
362
363 if (IS_ERR(iod->grf)) {
364 dev_err(&pdev->dev, "couldn't find grf regmap\n");
365 return PTR_ERR(iod->grf);
366 }
367
368 for (i = 0; i < MAX_SUPPLIES; i++) {
369 const char *supply_name = iod->soc_data->supply_names[i];
370 struct rockchip_iodomain_supply *supply = &iod->supplies[i];
371 struct regulator *reg;
372 int uV;
373
374 if (!supply_name)
375 continue;
376
377 reg = devm_regulator_get_optional(iod->dev, supply_name);
378 if (IS_ERR(reg)) {
379 ret = PTR_ERR(reg);
380
381
382 if (ret == -ENODEV)
383 continue;
384 else if (ret != -EPROBE_DEFER)
385 dev_err(iod->dev, "couldn't get regulator %s\n",
386 supply_name);
387 goto unreg_notify;
388 }
389
390
391 uV = regulator_get_voltage(reg);
392
393
394 if (uV < 0) {
395 dev_err(iod->dev, "Can't determine voltage: %s\n",
396 supply_name);
397 goto unreg_notify;
398 }
399
400 if (uV > MAX_VOLTAGE_3_3) {
401 dev_crit(iod->dev,
402 "%d uV is too high. May damage SoC!\n",
403 uV);
404 ret = -EINVAL;
405 goto unreg_notify;
406 }
407
408
409 supply->idx = i;
410 supply->iod = iod;
411 supply->reg = reg;
412 supply->nb.notifier_call = rockchip_iodomain_notify;
413
414 ret = rockchip_iodomain_write(supply, uV);
415 if (ret) {
416 supply->reg = NULL;
417 goto unreg_notify;
418 }
419
420
421 ret = regulator_register_notifier(reg, &supply->nb);
422 if (ret) {
423 dev_err(&pdev->dev,
424 "regulator notifier request failed\n");
425 supply->reg = NULL;
426 goto unreg_notify;
427 }
428 }
429
430 if (iod->soc_data->init)
431 iod->soc_data->init(iod);
432
433 return 0;
434
435unreg_notify:
436 for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
437 struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
438
439 if (io_supply->reg)
440 regulator_unregister_notifier(io_supply->reg,
441 &io_supply->nb);
442 }
443
444 return ret;
445}
446
447static int rockchip_iodomain_remove(struct platform_device *pdev)
448{
449 struct rockchip_iodomain *iod = platform_get_drvdata(pdev);
450 int i;
451
452 for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
453 struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
454
455 if (io_supply->reg)
456 regulator_unregister_notifier(io_supply->reg,
457 &io_supply->nb);
458 }
459
460 return 0;
461}
462
463static struct platform_driver rockchip_iodomain_driver = {
464 .probe = rockchip_iodomain_probe,
465 .remove = rockchip_iodomain_remove,
466 .driver = {
467 .name = "rockchip-iodomain",
468 .of_match_table = rockchip_iodomain_match,
469 },
470};
471
472module_platform_driver(rockchip_iodomain_driver);
473
474MODULE_DESCRIPTION("Rockchip IO-domain driver");
475MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
476MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>");
477MODULE_LICENSE("GPL v2");
478