• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
46 #define RK3328_SOC_CON4			0x410
47 #define RK3328_SOC_CON4_VCCIO2		BIT(7)
48 #define RK3328_SOC_VCCIO2_SUPPLY_NUM	1
49 
50 #define RK3368_SOC_CON15		0x43c
51 #define RK3368_SOC_CON15_FLASH0		BIT(14)
52 #define RK3368_SOC_FLASH_SUPPLY_NUM	2
53 
54 #define RK3399_PMUGRF_CON0		0x180
55 #define RK3399_PMUGRF_CON0_VSEL		BIT(8)
56 #define RK3399_PMUGRF_VSEL_SUPPLY_NUM	9
57 
58 struct rockchip_iodomain;
59 
60 /**
61  * @supplies: voltage settings matching the register bits.
62  */
63 struct rockchip_iodomain_soc_data {
64 	int grf_offset;
65 	const char *supply_names[MAX_SUPPLIES];
66 	void (*init)(struct rockchip_iodomain *iod);
67 };
68 
69 struct rockchip_iodomain_supply {
70 	struct rockchip_iodomain *iod;
71 	struct regulator *reg;
72 	struct notifier_block nb;
73 	int idx;
74 };
75 
76 struct 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 
rockchip_iodomain_write(struct rockchip_iodomain_supply * supply,int uV)83 static 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 
rockchip_iodomain_notify(struct notifier_block * nb,unsigned long event,void * data)104 static 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 
150 	dev_dbg(supply->iod->dev, "Setting to %d done\n", uV);
151 	return NOTIFY_OK;
152 }
153 
rk3288_iodomain_init(struct rockchip_iodomain * iod)154 static 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 
rk3328_iodomain_init(struct rockchip_iodomain * iod)173 static 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 
rk3368_iodomain_init(struct rockchip_iodomain * iod)192 static 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 
rk3399_pmu_iodomain_init(struct rockchip_iodomain * iod)211 static 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 
230 /*
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  */
234 static 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 
256 static const struct rockchip_iodomain_soc_data soc_data_rk3228 = {
257 	.grf_offset = 0x418,
258 	.supply_names = {
259 		"vccio1",
260 		"vccio2",
261 		"vccio3",
262 		"vccio4",
263 	},
264 };
265 
266 static const struct rockchip_iodomain_soc_data soc_data_rk3288 = {
267 	.grf_offset = 0x380,
268 	.supply_names = {
269 		"lcdc",		/* LCDC_VDD */
270 		"dvp",		/* DVPIO_VDD */
271 		"flash0",	/* FLASH0_VDD (emmc) */
272 		"flash1",	/* FLASH1_VDD (sdio1) */
273 		"wifi",		/* APIO3_VDD  (sdio0) */
274 		"bb",		/* APIO5_VDD */
275 		"audio",	/* APIO4_VDD */
276 		"sdcard",	/* SDMMC0_VDD (sdmmc) */
277 		"gpio30",	/* APIO1_VDD */
278 		"gpio1830",	/* APIO2_VDD */
279 	},
280 	.init = rk3288_iodomain_init,
281 };
282 
283 static const struct rockchip_iodomain_soc_data soc_data_rk3328 = {
284 	.grf_offset = 0x410,
285 	.supply_names = {
286 		"vccio1",
287 		"vccio2",
288 		"vccio3",
289 		"vccio4",
290 		"vccio5",
291 		"vccio6",
292 		"pmuio",
293 	},
294 	.init = rk3328_iodomain_init,
295 };
296 
297 static const struct rockchip_iodomain_soc_data soc_data_rk3368 = {
298 	.grf_offset = 0x900,
299 	.supply_names = {
300 		NULL,		/* reserved */
301 		"dvp",		/* DVPIO_VDD */
302 		"flash0",	/* FLASH0_VDD (emmc) */
303 		"wifi",		/* APIO2_VDD (sdio0) */
304 		NULL,
305 		"audio",	/* APIO3_VDD */
306 		"sdcard",	/* SDMMC0_VDD (sdmmc) */
307 		"gpio30",	/* APIO1_VDD */
308 		"gpio1830",	/* APIO4_VDD (gpujtag) */
309 	},
310 	.init = rk3368_iodomain_init,
311 };
312 
313 static const struct rockchip_iodomain_soc_data soc_data_rk3368_pmu = {
314 	.grf_offset = 0x100,
315 	.supply_names = {
316 		NULL,
317 		NULL,
318 		NULL,
319 		NULL,
320 		"pmu",	        /*PMU IO domain*/
321 		"vop",	        /*LCDC IO domain*/
322 	},
323 };
324 
325 static const struct rockchip_iodomain_soc_data soc_data_rk3399 = {
326 	.grf_offset = 0xe640,
327 	.supply_names = {
328 		"bt656",		/* APIO2_VDD */
329 		"audio",		/* APIO5_VDD */
330 		"sdmmc",		/* SDMMC0_VDD */
331 		"gpio1830",		/* APIO4_VDD */
332 	},
333 };
334 
335 static const struct rockchip_iodomain_soc_data soc_data_rk3399_pmu = {
336 	.grf_offset = 0x180,
337 	.supply_names = {
338 		NULL,
339 		NULL,
340 		NULL,
341 		NULL,
342 		NULL,
343 		NULL,
344 		NULL,
345 		NULL,
346 		NULL,
347 		"pmu1830",		/* PMUIO2_VDD */
348 	},
349 	.init = rk3399_pmu_iodomain_init,
350 };
351 
352 static const struct rockchip_iodomain_soc_data soc_data_rv1108 = {
353 	.grf_offset = 0x404,
354 	.supply_names = {
355 		NULL,
356 		NULL,
357 		NULL,
358 		NULL,
359 		NULL,
360 		NULL,
361 		NULL,
362 		NULL,
363 		NULL,
364 		NULL,
365 		NULL,
366 		"vccio1",
367 		"vccio2",
368 		"vccio3",
369 		"vccio5",
370 		"vccio6",
371 	},
372 
373 };
374 
375 static const struct rockchip_iodomain_soc_data soc_data_rv1108_pmu = {
376 	.grf_offset = 0x104,
377 	.supply_names = {
378 		"pmu",
379 	},
380 };
381 
382 static const struct of_device_id rockchip_iodomain_match[] = {
383 	{
384 		.compatible = "rockchip,rk3188-io-voltage-domain",
385 		.data = (void *)&soc_data_rk3188
386 	},
387 	{
388 		.compatible = "rockchip,rk3228-io-voltage-domain",
389 		.data = (void *)&soc_data_rk3228
390 	},
391 	{
392 		.compatible = "rockchip,rk3288-io-voltage-domain",
393 		.data = (void *)&soc_data_rk3288
394 	},
395 	{
396 		.compatible = "rockchip,rk3328-io-voltage-domain",
397 		.data = (void *)&soc_data_rk3328
398 	},
399 	{
400 		.compatible = "rockchip,rk3368-io-voltage-domain",
401 		.data = (void *)&soc_data_rk3368
402 	},
403 	{
404 		.compatible = "rockchip,rk3368-pmu-io-voltage-domain",
405 		.data = (void *)&soc_data_rk3368_pmu
406 	},
407 	{
408 		.compatible = "rockchip,rk3399-io-voltage-domain",
409 		.data = (void *)&soc_data_rk3399
410 	},
411 	{
412 		.compatible = "rockchip,rk3399-pmu-io-voltage-domain",
413 		.data = (void *)&soc_data_rk3399_pmu
414 	},
415 	{
416 		.compatible = "rockchip,rv1108-io-voltage-domain",
417 		.data = (void *)&soc_data_rv1108
418 	},
419 	{
420 		.compatible = "rockchip,rv1108-pmu-io-voltage-domain",
421 		.data = (void *)&soc_data_rv1108_pmu
422 	},
423 	{ /* sentinel */ },
424 };
425 MODULE_DEVICE_TABLE(of, rockchip_iodomain_match);
426 
rockchip_iodomain_probe(struct platform_device * pdev)427 static int rockchip_iodomain_probe(struct platform_device *pdev)
428 {
429 	struct device_node *np = pdev->dev.of_node;
430 	const struct of_device_id *match;
431 	struct rockchip_iodomain *iod;
432 	struct device *parent;
433 	int i, ret = 0;
434 
435 	if (!np)
436 		return -ENODEV;
437 
438 	iod = devm_kzalloc(&pdev->dev, sizeof(*iod), GFP_KERNEL);
439 	if (!iod)
440 		return -ENOMEM;
441 
442 	iod->dev = &pdev->dev;
443 	platform_set_drvdata(pdev, iod);
444 
445 	match = of_match_node(rockchip_iodomain_match, np);
446 	iod->soc_data = (struct rockchip_iodomain_soc_data *)match->data;
447 
448 	parent = pdev->dev.parent;
449 	if (parent && parent->of_node) {
450 		iod->grf = syscon_node_to_regmap(parent->of_node);
451 	} else {
452 		dev_dbg(&pdev->dev, "falling back to old binding\n");
453 		iod->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
454 	}
455 
456 	if (IS_ERR(iod->grf)) {
457 		dev_err(&pdev->dev, "couldn't find grf regmap\n");
458 		return PTR_ERR(iod->grf);
459 	}
460 
461 	for (i = 0; i < MAX_SUPPLIES; i++) {
462 		const char *supply_name = iod->soc_data->supply_names[i];
463 		struct rockchip_iodomain_supply *supply = &iod->supplies[i];
464 		struct regulator *reg;
465 		int uV;
466 
467 		if (!supply_name)
468 			continue;
469 
470 		reg = devm_regulator_get_optional(iod->dev, supply_name);
471 		if (IS_ERR(reg)) {
472 			ret = PTR_ERR(reg);
473 
474 			/* If a supply wasn't specified, that's OK */
475 			if (ret == -ENODEV)
476 				continue;
477 			else if (ret != -EPROBE_DEFER)
478 				dev_err(iod->dev, "couldn't get regulator %s\n",
479 					supply_name);
480 			goto unreg_notify;
481 		}
482 
483 		/* set initial correct value */
484 		uV = regulator_get_voltage(reg);
485 
486 		/* must be a regulator we can get the voltage of */
487 		if (uV < 0) {
488 			dev_err(iod->dev, "Can't determine voltage: %s\n",
489 				supply_name);
490 			goto unreg_notify;
491 		}
492 
493 		if (uV > MAX_VOLTAGE_3_3) {
494 			dev_crit(iod->dev,
495 				 "%d uV is too high. May damage SoC!\n",
496 				 uV);
497 			ret = -EINVAL;
498 			goto unreg_notify;
499 		}
500 
501 		/* setup our supply */
502 		supply->idx = i;
503 		supply->iod = iod;
504 		supply->reg = reg;
505 		supply->nb.notifier_call = rockchip_iodomain_notify;
506 
507 		ret = rockchip_iodomain_write(supply, uV);
508 		if (ret) {
509 			supply->reg = NULL;
510 			goto unreg_notify;
511 		}
512 
513 		/* register regulator notifier */
514 		ret = regulator_register_notifier(reg, &supply->nb);
515 		if (ret) {
516 			dev_err(&pdev->dev,
517 				"regulator notifier request failed\n");
518 			supply->reg = NULL;
519 			goto unreg_notify;
520 		}
521 	}
522 
523 	if (iod->soc_data->init)
524 		iod->soc_data->init(iod);
525 
526 	return 0;
527 
528 unreg_notify:
529 	for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
530 		struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
531 
532 		if (io_supply->reg)
533 			regulator_unregister_notifier(io_supply->reg,
534 						      &io_supply->nb);
535 	}
536 
537 	return ret;
538 }
539 
rockchip_iodomain_remove(struct platform_device * pdev)540 static int rockchip_iodomain_remove(struct platform_device *pdev)
541 {
542 	struct rockchip_iodomain *iod = platform_get_drvdata(pdev);
543 	int i;
544 
545 	for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
546 		struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
547 
548 		if (io_supply->reg)
549 			regulator_unregister_notifier(io_supply->reg,
550 						      &io_supply->nb);
551 	}
552 
553 	return 0;
554 }
555 
556 static struct platform_driver rockchip_iodomain_driver = {
557 	.probe   = rockchip_iodomain_probe,
558 	.remove  = rockchip_iodomain_remove,
559 	.driver  = {
560 		.name  = "rockchip-iodomain",
561 		.of_match_table = rockchip_iodomain_match,
562 	},
563 };
564 
565 module_platform_driver(rockchip_iodomain_driver);
566 
567 MODULE_DESCRIPTION("Rockchip IO-domain driver");
568 MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
569 MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>");
570 MODULE_LICENSE("GPL v2");
571