Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Rockchip IO Voltage Domain driver
4 *
5 * Copyright 2014 MundoReader S.L.
6 * Copyright 2014 Google, Inc.
7 */
8
9#include <linux/kernel.h>
10#include <linux/module.h>
11#include <linux/err.h>
12#include <linux/mfd/syscon.h>
13#include <linux/of.h>
14#include <linux/platform_device.h>
15#include <linux/regmap.h>
16#include <linux/regulator/consumer.h>
17
18#define MAX_SUPPLIES 16
19
20/*
21 * The max voltage for 1.8V and 3.3V come from the Rockchip datasheet under
22 * "Recommended Operating Conditions" for "Digital GPIO". When the typical
23 * is 3.3V the max is 3.6V. When the typical is 1.8V the max is 1.98V.
24 *
25 * They are used like this:
26 * - If the voltage on a rail is above the "1.8" voltage (1.98V) we'll tell the
27 * SoC we're at 3.3.
28 * - If the voltage on a rail is above the "3.3" voltage (3.6V) we'll consider
29 * that to be an error.
30 */
31#define MAX_VOLTAGE_1_8 1980000
32#define MAX_VOLTAGE_3_3 3600000
33
34#define PX30_IO_VSEL 0x180
35#define PX30_IO_VSEL_VCCIO6_SRC BIT(0)
36#define PX30_IO_VSEL_VCCIO6_SUPPLY_NUM 1
37
38#define RK3288_SOC_CON2 0x24c
39#define RK3288_SOC_CON2_FLASH0 BIT(7)
40#define RK3288_SOC_FLASH_SUPPLY_NUM 2
41
42#define RK3328_SOC_CON4 0x410
43#define RK3328_SOC_CON4_VCCIO2 BIT(7)
44#define RK3328_SOC_VCCIO2_SUPPLY_NUM 1
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
56struct rockchip_iodomain_soc_data {
57 int grf_offset;
58 const char *supply_names[MAX_SUPPLIES];
59 void (*init)(struct rockchip_iodomain *iod);
60};
61
62struct rockchip_iodomain_supply {
63 struct rockchip_iodomain *iod;
64 struct regulator *reg;
65 struct notifier_block nb;
66 int idx;
67};
68
69struct rockchip_iodomain {
70 struct device *dev;
71 struct regmap *grf;
72 const struct rockchip_iodomain_soc_data *soc_data;
73 struct rockchip_iodomain_supply supplies[MAX_SUPPLIES];
74};
75
76static int rockchip_iodomain_write(struct rockchip_iodomain_supply *supply,
77 int uV)
78{
79 struct rockchip_iodomain *iod = supply->iod;
80 u32 val;
81 int ret;
82
83 /* set value bit */
84 val = (uV > MAX_VOLTAGE_1_8) ? 0 : 1;
85 val <<= supply->idx;
86
87 /* apply hiword-mask */
88 val |= (BIT(supply->idx) << 16);
89
90 ret = regmap_write(iod->grf, iod->soc_data->grf_offset, val);
91 if (ret)
92 dev_err(iod->dev, "Couldn't write to GRF\n");
93
94 return ret;
95}
96
97static int rockchip_iodomain_notify(struct notifier_block *nb,
98 unsigned long event,
99 void *data)
100{
101 struct rockchip_iodomain_supply *supply =
102 container_of(nb, struct rockchip_iodomain_supply, nb);
103 int uV;
104 int ret;
105
106 /*
107 * According to Rockchip it's important to keep the SoC IO domain
108 * higher than (or equal to) the external voltage. That means we need
109 * to change it before external voltage changes happen in the case
110 * of an increase.
111 *
112 * Note that in the "pre" change we pick the max possible voltage that
113 * the regulator might end up at (the client requests a range and we
114 * don't know for certain the exact voltage). Right now we rely on the
115 * slop in MAX_VOLTAGE_1_8 and MAX_VOLTAGE_3_3 to save us if clients
116 * request something like a max of 3.6V when they really want 3.3V.
117 * We could attempt to come up with better rules if this fails.
118 */
119 if (event & REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) {
120 struct pre_voltage_change_data *pvc_data = data;
121
122 uV = max_t(unsigned long, pvc_data->old_uV, pvc_data->max_uV);
123 } else if (event & (REGULATOR_EVENT_VOLTAGE_CHANGE |
124 REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE)) {
125 uV = (unsigned long)data;
126 } else {
127 return NOTIFY_OK;
128 }
129
130 dev_dbg(supply->iod->dev, "Setting to %d\n", uV);
131
132 if (uV > MAX_VOLTAGE_3_3) {
133 dev_err(supply->iod->dev, "Voltage too high: %d\n", uV);
134
135 if (event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE)
136 return NOTIFY_BAD;
137 }
138
139 ret = rockchip_iodomain_write(supply, uV);
140 if (ret && event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE)
141 return NOTIFY_BAD;
142
143 dev_dbg(supply->iod->dev, "Setting to %d done\n", uV);
144 return NOTIFY_OK;
145}
146
147static void px30_iodomain_init(struct rockchip_iodomain *iod)
148{
149 int ret;
150 u32 val;
151
152 /* if no VCCIO6 supply we should leave things alone */
153 if (!iod->supplies[PX30_IO_VSEL_VCCIO6_SUPPLY_NUM].reg)
154 return;
155
156 /*
157 * set vccio6 iodomain to also use this framework
158 * instead of a special gpio.
159 */
160 val = PX30_IO_VSEL_VCCIO6_SRC | (PX30_IO_VSEL_VCCIO6_SRC << 16);
161 ret = regmap_write(iod->grf, PX30_IO_VSEL, val);
162 if (ret < 0)
163 dev_warn(iod->dev, "couldn't update vccio6 ctrl\n");
164}
165
166static void rk3288_iodomain_init(struct rockchip_iodomain *iod)
167{
168 int ret;
169 u32 val;
170
171 /* if no flash supply we should leave things alone */
172 if (!iod->supplies[RK3288_SOC_FLASH_SUPPLY_NUM].reg)
173 return;
174
175 /*
176 * set flash0 iodomain to also use this framework
177 * instead of a special gpio.
178 */
179 val = RK3288_SOC_CON2_FLASH0 | (RK3288_SOC_CON2_FLASH0 << 16);
180 ret = regmap_write(iod->grf, RK3288_SOC_CON2, val);
181 if (ret < 0)
182 dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
183}
184
185static void rk3328_iodomain_init(struct rockchip_iodomain *iod)
186{
187 int ret;
188 u32 val;
189
190 /* if no vccio2 supply we should leave things alone */
191 if (!iod->supplies[RK3328_SOC_VCCIO2_SUPPLY_NUM].reg)
192 return;
193
194 /*
195 * set vccio2 iodomain to also use this framework
196 * instead of a special gpio.
197 */
198 val = RK3328_SOC_CON4_VCCIO2 | (RK3328_SOC_CON4_VCCIO2 << 16);
199 ret = regmap_write(iod->grf, RK3328_SOC_CON4, val);
200 if (ret < 0)
201 dev_warn(iod->dev, "couldn't update vccio2 vsel ctrl\n");
202}
203
204static void rk3368_iodomain_init(struct rockchip_iodomain *iod)
205{
206 int ret;
207 u32 val;
208
209 /* if no flash supply we should leave things alone */
210 if (!iod->supplies[RK3368_SOC_FLASH_SUPPLY_NUM].reg)
211 return;
212
213 /*
214 * set flash0 iodomain to also use this framework
215 * instead of a special gpio.
216 */
217 val = RK3368_SOC_CON15_FLASH0 | (RK3368_SOC_CON15_FLASH0 << 16);
218 ret = regmap_write(iod->grf, RK3368_SOC_CON15, val);
219 if (ret < 0)
220 dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
221}
222
223static void rk3399_pmu_iodomain_init(struct rockchip_iodomain *iod)
224{
225 int ret;
226 u32 val;
227
228 /* if no pmu io supply we should leave things alone */
229 if (!iod->supplies[RK3399_PMUGRF_VSEL_SUPPLY_NUM].reg)
230 return;
231
232 /*
233 * set pmu io iodomain to also use this framework
234 * instead of a special gpio.
235 */
236 val = RK3399_PMUGRF_CON0_VSEL | (RK3399_PMUGRF_CON0_VSEL << 16);
237 ret = regmap_write(iod->grf, RK3399_PMUGRF_CON0, val);
238 if (ret < 0)
239 dev_warn(iod->dev, "couldn't update pmu io iodomain ctrl\n");
240}
241
242static const struct rockchip_iodomain_soc_data soc_data_px30 = {
243 .grf_offset = 0x180,
244 .supply_names = {
245 NULL,
246 "vccio6",
247 "vccio1",
248 "vccio2",
249 "vccio3",
250 "vccio4",
251 "vccio5",
252 "vccio-oscgpi",
253 },
254 .init = px30_iodomain_init,
255};
256
257static const struct rockchip_iodomain_soc_data soc_data_px30_pmu = {
258 .grf_offset = 0x100,
259 .supply_names = {
260 NULL,
261 NULL,
262 NULL,
263 NULL,
264 NULL,
265 NULL,
266 NULL,
267 NULL,
268 NULL,
269 NULL,
270 NULL,
271 NULL,
272 NULL,
273 NULL,
274 "pmuio1",
275 "pmuio2",
276 },
277};
278
279/*
280 * On the rk3188 the io-domains are handled by a shared register with the
281 * lower 8 bits being still being continuing drive-strength settings.
282 */
283static const struct rockchip_iodomain_soc_data soc_data_rk3188 = {
284 .grf_offset = 0x104,
285 .supply_names = {
286 NULL,
287 NULL,
288 NULL,
289 NULL,
290 NULL,
291 NULL,
292 NULL,
293 NULL,
294 "ap0",
295 "ap1",
296 "cif",
297 "flash",
298 "vccio0",
299 "vccio1",
300 "lcdc0",
301 "lcdc1",
302 },
303};
304
305static const struct rockchip_iodomain_soc_data soc_data_rk3228 = {
306 .grf_offset = 0x418,
307 .supply_names = {
308 "vccio1",
309 "vccio2",
310 "vccio3",
311 "vccio4",
312 },
313};
314
315static const struct rockchip_iodomain_soc_data soc_data_rk3288 = {
316 .grf_offset = 0x380,
317 .supply_names = {
318 "lcdc", /* LCDC_VDD */
319 "dvp", /* DVPIO_VDD */
320 "flash0", /* FLASH0_VDD (emmc) */
321 "flash1", /* FLASH1_VDD (sdio1) */
322 "wifi", /* APIO3_VDD (sdio0) */
323 "bb", /* APIO5_VDD */
324 "audio", /* APIO4_VDD */
325 "sdcard", /* SDMMC0_VDD (sdmmc) */
326 "gpio30", /* APIO1_VDD */
327 "gpio1830", /* APIO2_VDD */
328 },
329 .init = rk3288_iodomain_init,
330};
331
332static const struct rockchip_iodomain_soc_data soc_data_rk3328 = {
333 .grf_offset = 0x410,
334 .supply_names = {
335 "vccio1",
336 "vccio2",
337 "vccio3",
338 "vccio4",
339 "vccio5",
340 "vccio6",
341 "pmuio",
342 },
343 .init = rk3328_iodomain_init,
344};
345
346static const struct rockchip_iodomain_soc_data soc_data_rk3368 = {
347 .grf_offset = 0x900,
348 .supply_names = {
349 NULL, /* reserved */
350 "dvp", /* DVPIO_VDD */
351 "flash0", /* FLASH0_VDD (emmc) */
352 "wifi", /* APIO2_VDD (sdio0) */
353 NULL,
354 "audio", /* APIO3_VDD */
355 "sdcard", /* SDMMC0_VDD (sdmmc) */
356 "gpio30", /* APIO1_VDD */
357 "gpio1830", /* APIO4_VDD (gpujtag) */
358 },
359 .init = rk3368_iodomain_init,
360};
361
362static const struct rockchip_iodomain_soc_data soc_data_rk3368_pmu = {
363 .grf_offset = 0x100,
364 .supply_names = {
365 NULL,
366 NULL,
367 NULL,
368 NULL,
369 "pmu", /*PMU IO domain*/
370 "vop", /*LCDC IO domain*/
371 },
372};
373
374static const struct rockchip_iodomain_soc_data soc_data_rk3399 = {
375 .grf_offset = 0xe640,
376 .supply_names = {
377 "bt656", /* APIO2_VDD */
378 "audio", /* APIO5_VDD */
379 "sdmmc", /* SDMMC0_VDD */
380 "gpio1830", /* APIO4_VDD */
381 },
382};
383
384static const struct rockchip_iodomain_soc_data soc_data_rk3399_pmu = {
385 .grf_offset = 0x180,
386 .supply_names = {
387 NULL,
388 NULL,
389 NULL,
390 NULL,
391 NULL,
392 NULL,
393 NULL,
394 NULL,
395 NULL,
396 "pmu1830", /* PMUIO2_VDD */
397 },
398 .init = rk3399_pmu_iodomain_init,
399};
400
401static const struct rockchip_iodomain_soc_data soc_data_rv1108 = {
402 .grf_offset = 0x404,
403 .supply_names = {
404 NULL,
405 NULL,
406 NULL,
407 NULL,
408 NULL,
409 NULL,
410 NULL,
411 NULL,
412 NULL,
413 NULL,
414 NULL,
415 "vccio1",
416 "vccio2",
417 "vccio3",
418 "vccio5",
419 "vccio6",
420 },
421
422};
423
424static const struct rockchip_iodomain_soc_data soc_data_rv1108_pmu = {
425 .grf_offset = 0x104,
426 .supply_names = {
427 "pmu",
428 },
429};
430
431static const struct of_device_id rockchip_iodomain_match[] = {
432 {
433 .compatible = "rockchip,px30-io-voltage-domain",
434 .data = (void *)&soc_data_px30
435 },
436 {
437 .compatible = "rockchip,px30-pmu-io-voltage-domain",
438 .data = (void *)&soc_data_px30_pmu
439 },
440 {
441 .compatible = "rockchip,rk3188-io-voltage-domain",
442 .data = &soc_data_rk3188
443 },
444 {
445 .compatible = "rockchip,rk3228-io-voltage-domain",
446 .data = &soc_data_rk3228
447 },
448 {
449 .compatible = "rockchip,rk3288-io-voltage-domain",
450 .data = &soc_data_rk3288
451 },
452 {
453 .compatible = "rockchip,rk3328-io-voltage-domain",
454 .data = &soc_data_rk3328
455 },
456 {
457 .compatible = "rockchip,rk3368-io-voltage-domain",
458 .data = &soc_data_rk3368
459 },
460 {
461 .compatible = "rockchip,rk3368-pmu-io-voltage-domain",
462 .data = &soc_data_rk3368_pmu
463 },
464 {
465 .compatible = "rockchip,rk3399-io-voltage-domain",
466 .data = &soc_data_rk3399
467 },
468 {
469 .compatible = "rockchip,rk3399-pmu-io-voltage-domain",
470 .data = &soc_data_rk3399_pmu
471 },
472 {
473 .compatible = "rockchip,rv1108-io-voltage-domain",
474 .data = &soc_data_rv1108
475 },
476 {
477 .compatible = "rockchip,rv1108-pmu-io-voltage-domain",
478 .data = &soc_data_rv1108_pmu
479 },
480 { /* sentinel */ },
481};
482MODULE_DEVICE_TABLE(of, rockchip_iodomain_match);
483
484static int rockchip_iodomain_probe(struct platform_device *pdev)
485{
486 struct device_node *np = pdev->dev.of_node;
487 const struct of_device_id *match;
488 struct rockchip_iodomain *iod;
489 struct device *parent;
490 int i, ret = 0;
491
492 if (!np)
493 return -ENODEV;
494
495 iod = devm_kzalloc(&pdev->dev, sizeof(*iod), GFP_KERNEL);
496 if (!iod)
497 return -ENOMEM;
498
499 iod->dev = &pdev->dev;
500 platform_set_drvdata(pdev, iod);
501
502 match = of_match_node(rockchip_iodomain_match, np);
503 iod->soc_data = match->data;
504
505 parent = pdev->dev.parent;
506 if (parent && parent->of_node) {
507 iod->grf = syscon_node_to_regmap(parent->of_node);
508 } else {
509 dev_dbg(&pdev->dev, "falling back to old binding\n");
510 iod->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
511 }
512
513 if (IS_ERR(iod->grf)) {
514 dev_err(&pdev->dev, "couldn't find grf regmap\n");
515 return PTR_ERR(iod->grf);
516 }
517
518 for (i = 0; i < MAX_SUPPLIES; i++) {
519 const char *supply_name = iod->soc_data->supply_names[i];
520 struct rockchip_iodomain_supply *supply = &iod->supplies[i];
521 struct regulator *reg;
522 int uV;
523
524 if (!supply_name)
525 continue;
526
527 reg = devm_regulator_get_optional(iod->dev, supply_name);
528 if (IS_ERR(reg)) {
529 ret = PTR_ERR(reg);
530
531 /* If a supply wasn't specified, that's OK */
532 if (ret == -ENODEV)
533 continue;
534 else if (ret != -EPROBE_DEFER)
535 dev_err(iod->dev, "couldn't get regulator %s\n",
536 supply_name);
537 goto unreg_notify;
538 }
539
540 /* set initial correct value */
541 uV = regulator_get_voltage(reg);
542
543 /* must be a regulator we can get the voltage of */
544 if (uV < 0) {
545 dev_err(iod->dev, "Can't determine voltage: %s\n",
546 supply_name);
547 ret = uV;
548 goto unreg_notify;
549 }
550
551 if (uV > MAX_VOLTAGE_3_3) {
552 dev_crit(iod->dev,
553 "%d uV is too high. May damage SoC!\n",
554 uV);
555 ret = -EINVAL;
556 goto unreg_notify;
557 }
558
559 /* setup our supply */
560 supply->idx = i;
561 supply->iod = iod;
562 supply->reg = reg;
563 supply->nb.notifier_call = rockchip_iodomain_notify;
564
565 ret = rockchip_iodomain_write(supply, uV);
566 if (ret) {
567 supply->reg = NULL;
568 goto unreg_notify;
569 }
570
571 /* register regulator notifier */
572 ret = regulator_register_notifier(reg, &supply->nb);
573 if (ret) {
574 dev_err(&pdev->dev,
575 "regulator notifier request failed\n");
576 supply->reg = NULL;
577 goto unreg_notify;
578 }
579 }
580
581 if (iod->soc_data->init)
582 iod->soc_data->init(iod);
583
584 return 0;
585
586unreg_notify:
587 for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
588 struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
589
590 if (io_supply->reg)
591 regulator_unregister_notifier(io_supply->reg,
592 &io_supply->nb);
593 }
594
595 return ret;
596}
597
598static int rockchip_iodomain_remove(struct platform_device *pdev)
599{
600 struct rockchip_iodomain *iod = platform_get_drvdata(pdev);
601 int i;
602
603 for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
604 struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
605
606 if (io_supply->reg)
607 regulator_unregister_notifier(io_supply->reg,
608 &io_supply->nb);
609 }
610
611 return 0;
612}
613
614static struct platform_driver rockchip_iodomain_driver = {
615 .probe = rockchip_iodomain_probe,
616 .remove = rockchip_iodomain_remove,
617 .driver = {
618 .name = "rockchip-iodomain",
619 .of_match_table = rockchip_iodomain_match,
620 },
621};
622
623module_platform_driver(rockchip_iodomain_driver);
624
625MODULE_DESCRIPTION("Rockchip IO-domain driver");
626MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
627MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>");
628MODULE_LICENSE("GPL v2");