blob: 85812521b6baddf00f47bb2b1a9cfa095ff661a4 [file] [log] [blame]
Heiko Stübner662a9582014-09-11 15:48:55 -07001/*
2 * Rockchip IO Voltage Domain driver
3 *
4 * Copyright 2014 MundoReader S.L.
5 * Copyright 2014 Google, Inc.
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
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 * The max voltage for 1.8V and 3.3V come from the Rockchip datasheet under
30 * "Recommended Operating Conditions" for "Digital GPIO". When the typical
31 * is 3.3V the max is 3.6V. When the typical is 1.8V the max is 1.98V.
32 *
33 * They are used like this:
34 * - If the voltage on a rail is above the "1.8" voltage (1.98V) we'll tell the
35 * SoC we're at 3.3.
36 * - If the voltage on a rail is above the "3.3" voltage (3.6V) we'll consider
37 * that to be an error.
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
David Wu7db36b12017-02-23 20:33:11 +080046#define RK3328_SOC_CON4 0x410
47#define RK3328_SOC_CON4_VCCIO2 BIT(7)
48#define RK3328_SOC_VCCIO2_SUPPLY_NUM 1
49
Heiko Stuebner3fc147e2015-08-04 21:37:01 +020050#define RK3368_SOC_CON15 0x43c
51#define RK3368_SOC_CON15_FLASH0 BIT(14)
52#define RK3368_SOC_FLASH_SUPPLY_NUM 2
53
David Wuf4476712016-03-16 02:45:26 +080054#define RK3399_PMUGRF_CON0 0x180
55#define RK3399_PMUGRF_CON0_VSEL BIT(8)
56#define RK3399_PMUGRF_VSEL_SUPPLY_NUM 9
57
Heiko Stübner662a9582014-09-11 15:48:55 -070058struct rockchip_iodomain;
59
60/**
61 * @supplies: voltage settings matching the register bits.
62 */
63struct rockchip_iodomain_soc_data {
64 int grf_offset;
65 const char *supply_names[MAX_SUPPLIES];
66 void (*init)(struct rockchip_iodomain *iod);
67};
68
69struct rockchip_iodomain_supply {
70 struct rockchip_iodomain *iod;
71 struct regulator *reg;
72 struct notifier_block nb;
73 int idx;
74};
75
76struct rockchip_iodomain {
77 struct device *dev;
78 struct regmap *grf;
79 struct rockchip_iodomain_soc_data *soc_data;
80 struct rockchip_iodomain_supply supplies[MAX_SUPPLIES];
81};
82
83static int rockchip_iodomain_write(struct rockchip_iodomain_supply *supply,
84 int uV)
85{
86 struct rockchip_iodomain *iod = supply->iod;
87 u32 val;
88 int ret;
89
90 /* set value bit */
91 val = (uV > MAX_VOLTAGE_1_8) ? 0 : 1;
92 val <<= supply->idx;
93
94 /* apply hiword-mask */
95 val |= (BIT(supply->idx) << 16);
96
97 ret = regmap_write(iod->grf, iod->soc_data->grf_offset, val);
98 if (ret)
99 dev_err(iod->dev, "Couldn't write to GRF\n");
100
101 return ret;
102}
103
104static int rockchip_iodomain_notify(struct notifier_block *nb,
105 unsigned long event,
106 void *data)
107{
108 struct rockchip_iodomain_supply *supply =
109 container_of(nb, struct rockchip_iodomain_supply, nb);
110 int uV;
111 int ret;
112
113 /*
114 * According to Rockchip it's important to keep the SoC IO domain
115 * higher than (or equal to) the external voltage. That means we need
116 * to change it before external voltage changes happen in the case
117 * of an increase.
118 *
119 * Note that in the "pre" change we pick the max possible voltage that
120 * the regulator might end up at (the client requests a range and we
121 * don't know for certain the exact voltage). Right now we rely on the
122 * slop in MAX_VOLTAGE_1_8 and MAX_VOLTAGE_3_3 to save us if clients
123 * request something like a max of 3.6V when they really want 3.3V.
124 * We could attempt to come up with better rules if this fails.
125 */
126 if (event & REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) {
127 struct pre_voltage_change_data *pvc_data = data;
128
129 uV = max_t(unsigned long, pvc_data->old_uV, pvc_data->max_uV);
130 } else if (event & (REGULATOR_EVENT_VOLTAGE_CHANGE |
131 REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE)) {
132 uV = (unsigned long)data;
133 } else {
134 return NOTIFY_OK;
135 }
136
137 dev_dbg(supply->iod->dev, "Setting to %d\n", uV);
138
139 if (uV > MAX_VOLTAGE_3_3) {
140 dev_err(supply->iod->dev, "Voltage too high: %d\n", uV);
141
142 if (event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE)
143 return NOTIFY_BAD;
144 }
145
146 ret = rockchip_iodomain_write(supply, uV);
147 if (ret && event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE)
148 return NOTIFY_BAD;
149
Shawn Linf5261402016-10-10 20:44:22 +0800150 dev_dbg(supply->iod->dev, "Setting to %d done\n", uV);
Heiko Stübner662a9582014-09-11 15:48:55 -0700151 return NOTIFY_OK;
152}
153
154static void rk3288_iodomain_init(struct rockchip_iodomain *iod)
155{
156 int ret;
157 u32 val;
158
159 /* if no flash supply we should leave things alone */
160 if (!iod->supplies[RK3288_SOC_FLASH_SUPPLY_NUM].reg)
161 return;
162
163 /*
164 * set flash0 iodomain to also use this framework
165 * instead of a special gpio.
166 */
167 val = RK3288_SOC_CON2_FLASH0 | (RK3288_SOC_CON2_FLASH0 << 16);
168 ret = regmap_write(iod->grf, RK3288_SOC_CON2, val);
169 if (ret < 0)
170 dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
171}
172
David Wu7db36b12017-02-23 20:33:11 +0800173static void rk3328_iodomain_init(struct rockchip_iodomain *iod)
174{
175 int ret;
176 u32 val;
177
178 /* if no vccio2 supply we should leave things alone */
179 if (!iod->supplies[RK3328_SOC_VCCIO2_SUPPLY_NUM].reg)
180 return;
181
182 /*
183 * set vccio2 iodomain to also use this framework
184 * instead of a special gpio.
185 */
186 val = RK3328_SOC_CON4_VCCIO2 | (RK3328_SOC_CON4_VCCIO2 << 16);
187 ret = regmap_write(iod->grf, RK3328_SOC_CON4, val);
188 if (ret < 0)
189 dev_warn(iod->dev, "couldn't update vccio2 vsel ctrl\n");
190}
191
Heiko Stuebner3fc147e2015-08-04 21:37:01 +0200192static void rk3368_iodomain_init(struct rockchip_iodomain *iod)
193{
194 int ret;
195 u32 val;
196
197 /* if no flash supply we should leave things alone */
198 if (!iod->supplies[RK3368_SOC_FLASH_SUPPLY_NUM].reg)
199 return;
200
201 /*
202 * set flash0 iodomain to also use this framework
203 * instead of a special gpio.
204 */
205 val = RK3368_SOC_CON15_FLASH0 | (RK3368_SOC_CON15_FLASH0 << 16);
206 ret = regmap_write(iod->grf, RK3368_SOC_CON15, val);
207 if (ret < 0)
208 dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
209}
210
David Wuf4476712016-03-16 02:45:26 +0800211static void rk3399_pmu_iodomain_init(struct rockchip_iodomain *iod)
212{
213 int ret;
214 u32 val;
215
216 /* if no pmu io supply we should leave things alone */
217 if (!iod->supplies[RK3399_PMUGRF_VSEL_SUPPLY_NUM].reg)
218 return;
219
220 /*
221 * set pmu io iodomain to also use this framework
222 * instead of a special gpio.
223 */
224 val = RK3399_PMUGRF_CON0_VSEL | (RK3399_PMUGRF_CON0_VSEL << 16);
225 ret = regmap_write(iod->grf, RK3399_PMUGRF_CON0, val);
226 if (ret < 0)
227 dev_warn(iod->dev, "couldn't update pmu io iodomain ctrl\n");
228}
229
Heiko Stübner662a9582014-09-11 15:48:55 -0700230/*
231 * On the rk3188 the io-domains are handled by a shared register with the
232 * lower 8 bits being still being continuing drive-strength settings.
233 */
234static const struct rockchip_iodomain_soc_data soc_data_rk3188 = {
235 .grf_offset = 0x104,
236 .supply_names = {
237 NULL,
238 NULL,
239 NULL,
240 NULL,
241 NULL,
242 NULL,
243 NULL,
244 NULL,
245 "ap0",
246 "ap1",
247 "cif",
248 "flash",
249 "vccio0",
250 "vccio1",
251 "lcdc0",
252 "lcdc1",
253 },
254};
255
256static const struct rockchip_iodomain_soc_data soc_data_rk3288 = {
257 .grf_offset = 0x380,
258 .supply_names = {
259 "lcdc", /* LCDC_VDD */
260 "dvp", /* DVPIO_VDD */
261 "flash0", /* FLASH0_VDD (emmc) */
262 "flash1", /* FLASH1_VDD (sdio1) */
263 "wifi", /* APIO3_VDD (sdio0) */
264 "bb", /* APIO5_VDD */
265 "audio", /* APIO4_VDD */
266 "sdcard", /* SDMMC0_VDD (sdmmc) */
267 "gpio30", /* APIO1_VDD */
268 "gpio1830", /* APIO2_VDD */
269 },
270 .init = rk3288_iodomain_init,
271};
272
David Wu7db36b12017-02-23 20:33:11 +0800273static const struct rockchip_iodomain_soc_data soc_data_rk3328 = {
274 .grf_offset = 0x410,
275 .supply_names = {
276 "vccio1",
277 "vccio2",
278 "vccio3",
279 "vccio4",
280 "vccio5",
281 "vccio6",
282 "pmuio",
283 },
284 .init = rk3328_iodomain_init,
285};
286
Heiko Stuebner3fc147e2015-08-04 21:37:01 +0200287static const struct rockchip_iodomain_soc_data soc_data_rk3368 = {
288 .grf_offset = 0x900,
289 .supply_names = {
290 NULL, /* reserved */
291 "dvp", /* DVPIO_VDD */
292 "flash0", /* FLASH0_VDD (emmc) */
293 "wifi", /* APIO2_VDD (sdio0) */
294 NULL,
295 "audio", /* APIO3_VDD */
296 "sdcard", /* SDMMC0_VDD (sdmmc) */
297 "gpio30", /* APIO1_VDD */
298 "gpio1830", /* APIO4_VDD (gpujtag) */
299 },
300 .init = rk3368_iodomain_init,
301};
302
303static const struct rockchip_iodomain_soc_data soc_data_rk3368_pmu = {
304 .grf_offset = 0x100,
305 .supply_names = {
306 NULL,
307 NULL,
308 NULL,
309 NULL,
310 "pmu", /*PMU IO domain*/
311 "vop", /*LCDC IO domain*/
312 },
313};
314
David Wuf4476712016-03-16 02:45:26 +0800315static const struct rockchip_iodomain_soc_data soc_data_rk3399 = {
316 .grf_offset = 0xe640,
317 .supply_names = {
318 "bt656", /* APIO2_VDD */
319 "audio", /* APIO5_VDD */
320 "sdmmc", /* SDMMC0_VDD */
321 "gpio1830", /* APIO4_VDD */
322 },
323};
324
325static const struct rockchip_iodomain_soc_data soc_data_rk3399_pmu = {
326 .grf_offset = 0x180,
327 .supply_names = {
328 NULL,
329 NULL,
330 NULL,
331 NULL,
332 NULL,
333 NULL,
334 NULL,
335 NULL,
336 NULL,
337 "pmu1830", /* PMUIO2_VDD */
338 },
339 .init = rk3399_pmu_iodomain_init,
340};
341
Heiko Stübner662a9582014-09-11 15:48:55 -0700342static const struct of_device_id rockchip_iodomain_match[] = {
343 {
344 .compatible = "rockchip,rk3188-io-voltage-domain",
345 .data = (void *)&soc_data_rk3188
346 },
347 {
348 .compatible = "rockchip,rk3288-io-voltage-domain",
349 .data = (void *)&soc_data_rk3288
350 },
Heiko Stuebner3fc147e2015-08-04 21:37:01 +0200351 {
David Wu7db36b12017-02-23 20:33:11 +0800352 .compatible = "rockchip,rk3328-io-voltage-domain",
353 .data = (void *)&soc_data_rk3328
354 },
355 {
Heiko Stuebner3fc147e2015-08-04 21:37:01 +0200356 .compatible = "rockchip,rk3368-io-voltage-domain",
357 .data = (void *)&soc_data_rk3368
358 },
359 {
360 .compatible = "rockchip,rk3368-pmu-io-voltage-domain",
361 .data = (void *)&soc_data_rk3368_pmu
362 },
David Wuf4476712016-03-16 02:45:26 +0800363 {
364 .compatible = "rockchip,rk3399-io-voltage-domain",
365 .data = (void *)&soc_data_rk3399
366 },
367 {
368 .compatible = "rockchip,rk3399-pmu-io-voltage-domain",
369 .data = (void *)&soc_data_rk3399_pmu
370 },
Heiko Stübner662a9582014-09-11 15:48:55 -0700371 { /* sentinel */ },
372};
Luis de Bethencourtfa743d92015-10-02 15:27:57 +0100373MODULE_DEVICE_TABLE(of, rockchip_iodomain_match);
Heiko Stübner662a9582014-09-11 15:48:55 -0700374
375static int rockchip_iodomain_probe(struct platform_device *pdev)
376{
377 struct device_node *np = pdev->dev.of_node;
378 const struct of_device_id *match;
379 struct rockchip_iodomain *iod;
Heiko Stuebnerbc19b9a2016-03-31 15:48:42 +0200380 struct device *parent;
Heiko Stübner662a9582014-09-11 15:48:55 -0700381 int i, ret = 0;
382
383 if (!np)
384 return -ENODEV;
385
386 iod = devm_kzalloc(&pdev->dev, sizeof(*iod), GFP_KERNEL);
387 if (!iod)
388 return -ENOMEM;
389
390 iod->dev = &pdev->dev;
391 platform_set_drvdata(pdev, iod);
392
393 match = of_match_node(rockchip_iodomain_match, np);
394 iod->soc_data = (struct rockchip_iodomain_soc_data *)match->data;
395
Heiko Stuebnerbc19b9a2016-03-31 15:48:42 +0200396 parent = pdev->dev.parent;
397 if (parent && parent->of_node) {
398 iod->grf = syscon_node_to_regmap(parent->of_node);
399 } else {
400 dev_dbg(&pdev->dev, "falling back to old binding\n");
401 iod->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
402 }
403
Heiko Stübner662a9582014-09-11 15:48:55 -0700404 if (IS_ERR(iod->grf)) {
405 dev_err(&pdev->dev, "couldn't find grf regmap\n");
406 return PTR_ERR(iod->grf);
407 }
408
409 for (i = 0; i < MAX_SUPPLIES; i++) {
410 const char *supply_name = iod->soc_data->supply_names[i];
411 struct rockchip_iodomain_supply *supply = &iod->supplies[i];
412 struct regulator *reg;
413 int uV;
414
415 if (!supply_name)
416 continue;
417
418 reg = devm_regulator_get_optional(iod->dev, supply_name);
419 if (IS_ERR(reg)) {
420 ret = PTR_ERR(reg);
421
422 /* If a supply wasn't specified, that's OK */
423 if (ret == -ENODEV)
424 continue;
425 else if (ret != -EPROBE_DEFER)
426 dev_err(iod->dev, "couldn't get regulator %s\n",
427 supply_name);
428 goto unreg_notify;
429 }
430
431 /* set initial correct value */
432 uV = regulator_get_voltage(reg);
433
434 /* must be a regulator we can get the voltage of */
435 if (uV < 0) {
436 dev_err(iod->dev, "Can't determine voltage: %s\n",
437 supply_name);
438 goto unreg_notify;
439 }
440
441 if (uV > MAX_VOLTAGE_3_3) {
442 dev_crit(iod->dev,
443 "%d uV is too high. May damage SoC!\n",
444 uV);
445 ret = -EINVAL;
446 goto unreg_notify;
447 }
448
449 /* setup our supply */
450 supply->idx = i;
451 supply->iod = iod;
452 supply->reg = reg;
453 supply->nb.notifier_call = rockchip_iodomain_notify;
454
455 ret = rockchip_iodomain_write(supply, uV);
456 if (ret) {
457 supply->reg = NULL;
458 goto unreg_notify;
459 }
460
461 /* register regulator notifier */
462 ret = regulator_register_notifier(reg, &supply->nb);
463 if (ret) {
464 dev_err(&pdev->dev,
465 "regulator notifier request failed\n");
466 supply->reg = NULL;
467 goto unreg_notify;
468 }
469 }
470
471 if (iod->soc_data->init)
472 iod->soc_data->init(iod);
473
474 return 0;
475
476unreg_notify:
477 for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
478 struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
479
480 if (io_supply->reg)
481 regulator_unregister_notifier(io_supply->reg,
482 &io_supply->nb);
483 }
484
485 return ret;
486}
487
488static int rockchip_iodomain_remove(struct platform_device *pdev)
489{
490 struct rockchip_iodomain *iod = platform_get_drvdata(pdev);
491 int i;
492
493 for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
494 struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
495
496 if (io_supply->reg)
497 regulator_unregister_notifier(io_supply->reg,
498 &io_supply->nb);
499 }
500
501 return 0;
502}
503
504static struct platform_driver rockchip_iodomain_driver = {
505 .probe = rockchip_iodomain_probe,
506 .remove = rockchip_iodomain_remove,
507 .driver = {
508 .name = "rockchip-iodomain",
509 .of_match_table = rockchip_iodomain_match,
510 },
511};
512
513module_platform_driver(rockchip_iodomain_driver);
514
515MODULE_DESCRIPTION("Rockchip IO-domain driver");
516MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
517MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>");
518MODULE_LICENSE("GPL v2");