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