xref: /openbmc/linux/drivers/soc/rockchip/io-domain.c (revision 0352f880)
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 
58 struct rockchip_iodomain;
59 
60 struct rockchip_iodomain_supply {
61 	struct rockchip_iodomain *iod;
62 	struct regulator *reg;
63 	struct notifier_block nb;
64 	int idx;
65 };
66 
67 struct 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 
74 struct 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 
82 static 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 
123 static 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 
144 static 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 
194 static 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 
213 static 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 
232 static 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 
251 static 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 
270 static 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 
289 static 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 
304 static 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  */
330 static 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 
352 static 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 
362 static 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 
379 static 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 
393 static 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 
409 static 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 
421 static 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 
431 static 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 
448 static 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 
464 static 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 
487 static const struct rockchip_iodomain_soc_data soc_data_rv1108_pmu = {
488 	.grf_offset = 0x104,
489 	.supply_names = {
490 		"pmu",
491 	},
492 };
493 
494 static 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 
510 static 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 };
569 MODULE_DEVICE_TABLE(of, rockchip_iodomain_match);
570 
571 static 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 
678 unreg_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 
690 static 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 
706 static 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 
715 module_platform_driver(rockchip_iodomain_driver);
716 
717 MODULE_DESCRIPTION("Rockchip IO-domain driver");
718 MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
719 MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>");
720 MODULE_LICENSE("GPL v2");
721