blob: cf8182fc3642dcbc3fdfd8cf71701a8153f03ed9 [file] [log] [blame]
Thomas Gleixner9c92ab62019-05-29 07:17:56 -07001// SPDX-License-Identifier: GPL-2.0-only
Heiko Stübner662a9582014-09-11 15:48:55 -07002/*
3 * Rockchip IO Voltage Domain driver
4 *
5 * Copyright 2014 MundoReader S.L.
6 * Copyright 2014 Google, Inc.
Heiko Stübner662a9582014-09-11 15:48:55 -07007 */
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
David Wub8281fa2018-05-15 19:48:19 +080034#define PX30_IO_VSEL 0x180
35#define PX30_IO_VSEL_VCCIO6_SRC BIT(0)
36#define PX30_IO_VSEL_VCCIO6_SUPPLY_NUM 1
37
Heiko Stübner662a9582014-09-11 15:48:55 -070038#define RK3288_SOC_CON2 0x24c
39#define RK3288_SOC_CON2_FLASH0 BIT(7)
40#define RK3288_SOC_FLASH_SUPPLY_NUM 2
41
David Wu7db36b12017-02-23 20:33:11 +080042#define RK3328_SOC_CON4 0x410
43#define RK3328_SOC_CON4_VCCIO2 BIT(7)
44#define RK3328_SOC_VCCIO2_SUPPLY_NUM 1
45
Heiko Stuebner3fc147e2015-08-04 21:37:01 +020046#define RK3368_SOC_CON15 0x43c
47#define RK3368_SOC_CON15_FLASH0 BIT(14)
48#define RK3368_SOC_FLASH_SUPPLY_NUM 2
49
David Wuf4476712016-03-16 02:45:26 +080050#define RK3399_PMUGRF_CON0 0x180
51#define RK3399_PMUGRF_CON0_VSEL BIT(8)
52#define RK3399_PMUGRF_VSEL_SUPPLY_NUM 9
53
Heiko Stübner662a9582014-09-11 15:48:55 -070054struct rockchip_iodomain;
55
Heiko Stübner662a9582014-09-11 15:48:55 -070056struct rockchip_iodomain_soc_data {
57 int grf_offset;
58 const char *supply_names[MAX_SUPPLIES];
59 void (*init)(struct rockchip_iodomain *iod);
60};
61
62struct rockchip_iodomain_supply {
63 struct rockchip_iodomain *iod;
64 struct regulator *reg;
65 struct notifier_block nb;
66 int idx;
67};
68
69struct rockchip_iodomain {
70 struct device *dev;
71 struct regmap *grf;
Julia Lawall5a2772a2018-01-02 14:27:57 +010072 const struct rockchip_iodomain_soc_data *soc_data;
Heiko Stübner662a9582014-09-11 15:48:55 -070073 struct rockchip_iodomain_supply supplies[MAX_SUPPLIES];
74};
75
76static int rockchip_iodomain_write(struct rockchip_iodomain_supply *supply,
77 int uV)
78{
79 struct rockchip_iodomain *iod = supply->iod;
80 u32 val;
81 int ret;
82
83 /* set value bit */
84 val = (uV > MAX_VOLTAGE_1_8) ? 0 : 1;
85 val <<= supply->idx;
86
87 /* apply hiword-mask */
88 val |= (BIT(supply->idx) << 16);
89
90 ret = regmap_write(iod->grf, iod->soc_data->grf_offset, val);
91 if (ret)
92 dev_err(iod->dev, "Couldn't write to GRF\n");
93
94 return ret;
95}
96
97static int rockchip_iodomain_notify(struct notifier_block *nb,
98 unsigned long event,
99 void *data)
100{
101 struct rockchip_iodomain_supply *supply =
102 container_of(nb, struct rockchip_iodomain_supply, nb);
103 int uV;
104 int ret;
105
106 /*
107 * According to Rockchip it's important to keep the SoC IO domain
108 * higher than (or equal to) the external voltage. That means we need
109 * to change it before external voltage changes happen in the case
110 * of an increase.
111 *
112 * Note that in the "pre" change we pick the max possible voltage that
113 * the regulator might end up at (the client requests a range and we
114 * don't know for certain the exact voltage). Right now we rely on the
115 * slop in MAX_VOLTAGE_1_8 and MAX_VOLTAGE_3_3 to save us if clients
116 * request something like a max of 3.6V when they really want 3.3V.
117 * We could attempt to come up with better rules if this fails.
118 */
119 if (event & REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) {
120 struct pre_voltage_change_data *pvc_data = data;
121
122 uV = max_t(unsigned long, pvc_data->old_uV, pvc_data->max_uV);
123 } else if (event & (REGULATOR_EVENT_VOLTAGE_CHANGE |
124 REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE)) {
125 uV = (unsigned long)data;
126 } else {
127 return NOTIFY_OK;
128 }
129
130 dev_dbg(supply->iod->dev, "Setting to %d\n", uV);
131
132 if (uV > MAX_VOLTAGE_3_3) {
133 dev_err(supply->iod->dev, "Voltage too high: %d\n", uV);
134
135 if (event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE)
136 return NOTIFY_BAD;
137 }
138
139 ret = rockchip_iodomain_write(supply, uV);
140 if (ret && event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE)
141 return NOTIFY_BAD;
142
Shawn Linf5261402016-10-10 20:44:22 +0800143 dev_dbg(supply->iod->dev, "Setting to %d done\n", uV);
Heiko Stübner662a9582014-09-11 15:48:55 -0700144 return NOTIFY_OK;
145}
146
David Wub8281fa2018-05-15 19:48:19 +0800147static void px30_iodomain_init(struct rockchip_iodomain *iod)
148{
149 int ret;
150 u32 val;
151
Heiko Stuebneradef0ce2020-01-21 23:28:59 +0100152 /* if no VCCIO6 supply we should leave things alone */
David Wub8281fa2018-05-15 19:48:19 +0800153 if (!iod->supplies[PX30_IO_VSEL_VCCIO6_SUPPLY_NUM].reg)
154 return;
155
156 /*
Heiko Stuebneradef0ce2020-01-21 23:28:59 +0100157 * set vccio6 iodomain to also use this framework
David Wub8281fa2018-05-15 19:48:19 +0800158 * instead of a special gpio.
159 */
160 val = PX30_IO_VSEL_VCCIO6_SRC | (PX30_IO_VSEL_VCCIO6_SRC << 16);
161 ret = regmap_write(iod->grf, PX30_IO_VSEL, val);
162 if (ret < 0)
Heiko Stuebneradef0ce2020-01-21 23:28:59 +0100163 dev_warn(iod->dev, "couldn't update vccio6 ctrl\n");
David Wub8281fa2018-05-15 19:48:19 +0800164}
165
Heiko Stübner662a9582014-09-11 15:48:55 -0700166static void rk3288_iodomain_init(struct rockchip_iodomain *iod)
167{
168 int ret;
169 u32 val;
170
171 /* if no flash supply we should leave things alone */
172 if (!iod->supplies[RK3288_SOC_FLASH_SUPPLY_NUM].reg)
173 return;
174
175 /*
176 * set flash0 iodomain to also use this framework
177 * instead of a special gpio.
178 */
179 val = RK3288_SOC_CON2_FLASH0 | (RK3288_SOC_CON2_FLASH0 << 16);
180 ret = regmap_write(iod->grf, RK3288_SOC_CON2, val);
181 if (ret < 0)
182 dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
183}
184
David Wu7db36b12017-02-23 20:33:11 +0800185static void rk3328_iodomain_init(struct rockchip_iodomain *iod)
186{
187 int ret;
188 u32 val;
189
190 /* if no vccio2 supply we should leave things alone */
191 if (!iod->supplies[RK3328_SOC_VCCIO2_SUPPLY_NUM].reg)
192 return;
193
194 /*
195 * set vccio2 iodomain to also use this framework
196 * instead of a special gpio.
197 */
198 val = RK3328_SOC_CON4_VCCIO2 | (RK3328_SOC_CON4_VCCIO2 << 16);
199 ret = regmap_write(iod->grf, RK3328_SOC_CON4, val);
200 if (ret < 0)
201 dev_warn(iod->dev, "couldn't update vccio2 vsel ctrl\n");
202}
203
Heiko Stuebner3fc147e2015-08-04 21:37:01 +0200204static void rk3368_iodomain_init(struct rockchip_iodomain *iod)
205{
206 int ret;
207 u32 val;
208
209 /* if no flash supply we should leave things alone */
210 if (!iod->supplies[RK3368_SOC_FLASH_SUPPLY_NUM].reg)
211 return;
212
213 /*
214 * set flash0 iodomain to also use this framework
215 * instead of a special gpio.
216 */
217 val = RK3368_SOC_CON15_FLASH0 | (RK3368_SOC_CON15_FLASH0 << 16);
218 ret = regmap_write(iod->grf, RK3368_SOC_CON15, val);
219 if (ret < 0)
220 dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
221}
222
David Wuf4476712016-03-16 02:45:26 +0800223static void rk3399_pmu_iodomain_init(struct rockchip_iodomain *iod)
224{
225 int ret;
226 u32 val;
227
228 /* if no pmu io supply we should leave things alone */
229 if (!iod->supplies[RK3399_PMUGRF_VSEL_SUPPLY_NUM].reg)
230 return;
231
232 /*
233 * set pmu io iodomain to also use this framework
234 * instead of a special gpio.
235 */
236 val = RK3399_PMUGRF_CON0_VSEL | (RK3399_PMUGRF_CON0_VSEL << 16);
237 ret = regmap_write(iod->grf, RK3399_PMUGRF_CON0, val);
238 if (ret < 0)
239 dev_warn(iod->dev, "couldn't update pmu io iodomain ctrl\n");
240}
241
David Wub8281fa2018-05-15 19:48:19 +0800242static const struct rockchip_iodomain_soc_data soc_data_px30 = {
243 .grf_offset = 0x180,
244 .supply_names = {
245 NULL,
246 "vccio6",
247 "vccio1",
248 "vccio2",
249 "vccio3",
250 "vccio4",
251 "vccio5",
252 "vccio-oscgpi",
253 },
254 .init = px30_iodomain_init,
255};
256
257static const struct rockchip_iodomain_soc_data soc_data_px30_pmu = {
258 .grf_offset = 0x100,
259 .supply_names = {
260 NULL,
261 NULL,
262 NULL,
263 NULL,
264 NULL,
265 NULL,
266 NULL,
267 NULL,
268 NULL,
269 NULL,
270 NULL,
271 NULL,
272 NULL,
273 NULL,
274 "pmuio1",
275 "pmuio2",
276 },
277};
278
Heiko Stübner662a9582014-09-11 15:48:55 -0700279/*
280 * On the rk3188 the io-domains are handled by a shared register with the
281 * lower 8 bits being still being continuing drive-strength settings.
282 */
283static const struct rockchip_iodomain_soc_data soc_data_rk3188 = {
284 .grf_offset = 0x104,
285 .supply_names = {
286 NULL,
287 NULL,
288 NULL,
289 NULL,
290 NULL,
291 NULL,
292 NULL,
293 NULL,
294 "ap0",
295 "ap1",
296 "cif",
297 "flash",
298 "vccio0",
299 "vccio1",
300 "lcdc0",
301 "lcdc1",
302 },
303};
304
David Wu1a99d0c2017-06-09 17:36:14 +0800305static const struct rockchip_iodomain_soc_data soc_data_rk3228 = {
306 .grf_offset = 0x418,
307 .supply_names = {
308 "vccio1",
309 "vccio2",
310 "vccio3",
311 "vccio4",
312 },
313};
314
Heiko Stübner662a9582014-09-11 15:48:55 -0700315static const struct rockchip_iodomain_soc_data soc_data_rk3288 = {
316 .grf_offset = 0x380,
317 .supply_names = {
318 "lcdc", /* LCDC_VDD */
319 "dvp", /* DVPIO_VDD */
320 "flash0", /* FLASH0_VDD (emmc) */
321 "flash1", /* FLASH1_VDD (sdio1) */
322 "wifi", /* APIO3_VDD (sdio0) */
323 "bb", /* APIO5_VDD */
324 "audio", /* APIO4_VDD */
325 "sdcard", /* SDMMC0_VDD (sdmmc) */
326 "gpio30", /* APIO1_VDD */
327 "gpio1830", /* APIO2_VDD */
328 },
329 .init = rk3288_iodomain_init,
330};
331
David Wu7db36b12017-02-23 20:33:11 +0800332static const struct rockchip_iodomain_soc_data soc_data_rk3328 = {
333 .grf_offset = 0x410,
334 .supply_names = {
335 "vccio1",
336 "vccio2",
337 "vccio3",
338 "vccio4",
339 "vccio5",
340 "vccio6",
341 "pmuio",
342 },
343 .init = rk3328_iodomain_init,
344};
345
Heiko Stuebner3fc147e2015-08-04 21:37:01 +0200346static const struct rockchip_iodomain_soc_data soc_data_rk3368 = {
347 .grf_offset = 0x900,
348 .supply_names = {
349 NULL, /* reserved */
350 "dvp", /* DVPIO_VDD */
351 "flash0", /* FLASH0_VDD (emmc) */
352 "wifi", /* APIO2_VDD (sdio0) */
353 NULL,
354 "audio", /* APIO3_VDD */
355 "sdcard", /* SDMMC0_VDD (sdmmc) */
356 "gpio30", /* APIO1_VDD */
357 "gpio1830", /* APIO4_VDD (gpujtag) */
358 },
359 .init = rk3368_iodomain_init,
360};
361
362static const struct rockchip_iodomain_soc_data soc_data_rk3368_pmu = {
363 .grf_offset = 0x100,
364 .supply_names = {
365 NULL,
366 NULL,
367 NULL,
368 NULL,
369 "pmu", /*PMU IO domain*/
370 "vop", /*LCDC IO domain*/
371 },
372};
373
David Wuf4476712016-03-16 02:45:26 +0800374static const struct rockchip_iodomain_soc_data soc_data_rk3399 = {
375 .grf_offset = 0xe640,
376 .supply_names = {
377 "bt656", /* APIO2_VDD */
378 "audio", /* APIO5_VDD */
379 "sdmmc", /* SDMMC0_VDD */
380 "gpio1830", /* APIO4_VDD */
381 },
382};
383
384static const struct rockchip_iodomain_soc_data soc_data_rk3399_pmu = {
385 .grf_offset = 0x180,
386 .supply_names = {
387 NULL,
388 NULL,
389 NULL,
390 NULL,
391 NULL,
392 NULL,
393 NULL,
394 NULL,
395 NULL,
396 "pmu1830", /* PMUIO2_VDD */
397 },
398 .init = rk3399_pmu_iodomain_init,
399};
400
David Wu9d913e42017-08-21 18:58:33 +0800401static const struct rockchip_iodomain_soc_data soc_data_rv1108 = {
402 .grf_offset = 0x404,
403 .supply_names = {
404 NULL,
405 NULL,
406 NULL,
407 NULL,
408 NULL,
409 NULL,
410 NULL,
411 NULL,
412 NULL,
413 NULL,
414 NULL,
415 "vccio1",
416 "vccio2",
417 "vccio3",
418 "vccio5",
419 "vccio6",
420 },
421
422};
423
424static const struct rockchip_iodomain_soc_data soc_data_rv1108_pmu = {
425 .grf_offset = 0x104,
426 .supply_names = {
427 "pmu",
428 },
429};
430
Heiko Stübner662a9582014-09-11 15:48:55 -0700431static const struct of_device_id rockchip_iodomain_match[] = {
432 {
David Wub8281fa2018-05-15 19:48:19 +0800433 .compatible = "rockchip,px30-io-voltage-domain",
434 .data = (void *)&soc_data_px30
435 },
436 {
437 .compatible = "rockchip,px30-pmu-io-voltage-domain",
438 .data = (void *)&soc_data_px30_pmu
439 },
440 {
Heiko Stübner662a9582014-09-11 15:48:55 -0700441 .compatible = "rockchip,rk3188-io-voltage-domain",
Julia Lawall5a2772a2018-01-02 14:27:57 +0100442 .data = &soc_data_rk3188
Heiko Stübner662a9582014-09-11 15:48:55 -0700443 },
444 {
David Wu1a99d0c2017-06-09 17:36:14 +0800445 .compatible = "rockchip,rk3228-io-voltage-domain",
Julia Lawall5a2772a2018-01-02 14:27:57 +0100446 .data = &soc_data_rk3228
David Wu1a99d0c2017-06-09 17:36:14 +0800447 },
448 {
Heiko Stübner662a9582014-09-11 15:48:55 -0700449 .compatible = "rockchip,rk3288-io-voltage-domain",
Julia Lawall5a2772a2018-01-02 14:27:57 +0100450 .data = &soc_data_rk3288
Heiko Stübner662a9582014-09-11 15:48:55 -0700451 },
Heiko Stuebner3fc147e2015-08-04 21:37:01 +0200452 {
David Wu7db36b12017-02-23 20:33:11 +0800453 .compatible = "rockchip,rk3328-io-voltage-domain",
Julia Lawall5a2772a2018-01-02 14:27:57 +0100454 .data = &soc_data_rk3328
David Wu7db36b12017-02-23 20:33:11 +0800455 },
456 {
Heiko Stuebner3fc147e2015-08-04 21:37:01 +0200457 .compatible = "rockchip,rk3368-io-voltage-domain",
Julia Lawall5a2772a2018-01-02 14:27:57 +0100458 .data = &soc_data_rk3368
Heiko Stuebner3fc147e2015-08-04 21:37:01 +0200459 },
460 {
461 .compatible = "rockchip,rk3368-pmu-io-voltage-domain",
Julia Lawall5a2772a2018-01-02 14:27:57 +0100462 .data = &soc_data_rk3368_pmu
Heiko Stuebner3fc147e2015-08-04 21:37:01 +0200463 },
David Wuf4476712016-03-16 02:45:26 +0800464 {
465 .compatible = "rockchip,rk3399-io-voltage-domain",
Julia Lawall5a2772a2018-01-02 14:27:57 +0100466 .data = &soc_data_rk3399
David Wuf4476712016-03-16 02:45:26 +0800467 },
468 {
469 .compatible = "rockchip,rk3399-pmu-io-voltage-domain",
Julia Lawall5a2772a2018-01-02 14:27:57 +0100470 .data = &soc_data_rk3399_pmu
David Wuf4476712016-03-16 02:45:26 +0800471 },
David Wu9d913e42017-08-21 18:58:33 +0800472 {
473 .compatible = "rockchip,rv1108-io-voltage-domain",
Julia Lawall5a2772a2018-01-02 14:27:57 +0100474 .data = &soc_data_rv1108
David Wu9d913e42017-08-21 18:58:33 +0800475 },
476 {
477 .compatible = "rockchip,rv1108-pmu-io-voltage-domain",
Julia Lawall5a2772a2018-01-02 14:27:57 +0100478 .data = &soc_data_rv1108_pmu
David Wu9d913e42017-08-21 18:58:33 +0800479 },
Heiko Stübner662a9582014-09-11 15:48:55 -0700480 { /* sentinel */ },
481};
Luis de Bethencourtfa743d92015-10-02 15:27:57 +0100482MODULE_DEVICE_TABLE(of, rockchip_iodomain_match);
Heiko Stübner662a9582014-09-11 15:48:55 -0700483
484static int rockchip_iodomain_probe(struct platform_device *pdev)
485{
486 struct device_node *np = pdev->dev.of_node;
487 const struct of_device_id *match;
488 struct rockchip_iodomain *iod;
Heiko Stuebnerbc19b9a2016-03-31 15:48:42 +0200489 struct device *parent;
Heiko Stübner662a9582014-09-11 15:48:55 -0700490 int i, ret = 0;
491
492 if (!np)
493 return -ENODEV;
494
495 iod = devm_kzalloc(&pdev->dev, sizeof(*iod), GFP_KERNEL);
496 if (!iod)
497 return -ENOMEM;
498
499 iod->dev = &pdev->dev;
500 platform_set_drvdata(pdev, iod);
501
502 match = of_match_node(rockchip_iodomain_match, np);
Julia Lawall5a2772a2018-01-02 14:27:57 +0100503 iod->soc_data = match->data;
Heiko Stübner662a9582014-09-11 15:48:55 -0700504
Heiko Stuebnerbc19b9a2016-03-31 15:48:42 +0200505 parent = pdev->dev.parent;
506 if (parent && parent->of_node) {
507 iod->grf = syscon_node_to_regmap(parent->of_node);
508 } else {
509 dev_dbg(&pdev->dev, "falling back to old binding\n");
510 iod->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
511 }
512
Heiko Stübner662a9582014-09-11 15:48:55 -0700513 if (IS_ERR(iod->grf)) {
514 dev_err(&pdev->dev, "couldn't find grf regmap\n");
515 return PTR_ERR(iod->grf);
516 }
517
518 for (i = 0; i < MAX_SUPPLIES; i++) {
519 const char *supply_name = iod->soc_data->supply_names[i];
520 struct rockchip_iodomain_supply *supply = &iod->supplies[i];
521 struct regulator *reg;
522 int uV;
523
524 if (!supply_name)
525 continue;
526
527 reg = devm_regulator_get_optional(iod->dev, supply_name);
528 if (IS_ERR(reg)) {
529 ret = PTR_ERR(reg);
530
531 /* If a supply wasn't specified, that's OK */
532 if (ret == -ENODEV)
533 continue;
534 else if (ret != -EPROBE_DEFER)
535 dev_err(iod->dev, "couldn't get regulator %s\n",
536 supply_name);
537 goto unreg_notify;
538 }
539
540 /* set initial correct value */
541 uV = regulator_get_voltage(reg);
542
543 /* must be a regulator we can get the voltage of */
544 if (uV < 0) {
545 dev_err(iod->dev, "Can't determine voltage: %s\n",
546 supply_name);
Zhang Changzhongc2867b22020-12-04 16:33:25 +0800547 ret = uV;
Heiko Stübner662a9582014-09-11 15:48:55 -0700548 goto unreg_notify;
549 }
550
551 if (uV > MAX_VOLTAGE_3_3) {
552 dev_crit(iod->dev,
553 "%d uV is too high. May damage SoC!\n",
554 uV);
555 ret = -EINVAL;
556 goto unreg_notify;
557 }
558
559 /* setup our supply */
560 supply->idx = i;
561 supply->iod = iod;
562 supply->reg = reg;
563 supply->nb.notifier_call = rockchip_iodomain_notify;
564
565 ret = rockchip_iodomain_write(supply, uV);
566 if (ret) {
567 supply->reg = NULL;
568 goto unreg_notify;
569 }
570
571 /* register regulator notifier */
572 ret = regulator_register_notifier(reg, &supply->nb);
573 if (ret) {
574 dev_err(&pdev->dev,
575 "regulator notifier request failed\n");
576 supply->reg = NULL;
577 goto unreg_notify;
578 }
579 }
580
581 if (iod->soc_data->init)
582 iod->soc_data->init(iod);
583
584 return 0;
585
586unreg_notify:
587 for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
588 struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
589
590 if (io_supply->reg)
591 regulator_unregister_notifier(io_supply->reg,
592 &io_supply->nb);
593 }
594
595 return ret;
596}
597
598static int rockchip_iodomain_remove(struct platform_device *pdev)
599{
600 struct rockchip_iodomain *iod = platform_get_drvdata(pdev);
601 int i;
602
603 for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
604 struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
605
606 if (io_supply->reg)
607 regulator_unregister_notifier(io_supply->reg,
608 &io_supply->nb);
609 }
610
611 return 0;
612}
613
614static struct platform_driver rockchip_iodomain_driver = {
615 .probe = rockchip_iodomain_probe,
616 .remove = rockchip_iodomain_remove,
617 .driver = {
618 .name = "rockchip-iodomain",
619 .of_match_table = rockchip_iodomain_match,
620 },
621};
622
623module_platform_driver(rockchip_iodomain_driver);
624
625MODULE_DESCRIPTION("Rockchip IO-domain driver");
626MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
627MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>");
628MODULE_LICENSE("GPL v2");