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 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 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 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 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 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 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 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 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 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 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 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_new = 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