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