Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Rockchip IO Voltage Domain driver
0004  *
0005  * Copyright 2014 MundoReader S.L.
0006  * Copyright 2014 Google, Inc.
0007  */
0008 
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/err.h>
0012 #include <linux/mfd/syscon.h>
0013 #include <linux/of.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/regmap.h>
0016 #include <linux/regulator/consumer.h>
0017 
0018 #define MAX_SUPPLIES        16
0019 
0020 /*
0021  * The max voltage for 1.8V and 3.3V come from the Rockchip datasheet under
0022  * "Recommended Operating Conditions" for "Digital GPIO".   When the typical
0023  * is 3.3V the max is 3.6V.  When the typical is 1.8V the max is 1.98V.
0024  *
0025  * They are used like this:
0026  * - If the voltage on a rail is above the "1.8" voltage (1.98V) we'll tell the
0027  *   SoC we're at 3.3.
0028  * - If the voltage on a rail is above the "3.3" voltage (3.6V) we'll consider
0029  *   that to be an error.
0030  */
0031 #define MAX_VOLTAGE_1_8     1980000
0032 #define MAX_VOLTAGE_3_3     3600000
0033 
0034 #define PX30_IO_VSEL            0x180
0035 #define PX30_IO_VSEL_VCCIO6_SRC     BIT(0)
0036 #define PX30_IO_VSEL_VCCIO6_SUPPLY_NUM  1
0037 
0038 #define RK3288_SOC_CON2         0x24c
0039 #define RK3288_SOC_CON2_FLASH0      BIT(7)
0040 #define RK3288_SOC_FLASH_SUPPLY_NUM 2
0041 
0042 #define RK3328_SOC_CON4         0x410
0043 #define RK3328_SOC_CON4_VCCIO2      BIT(7)
0044 #define RK3328_SOC_VCCIO2_SUPPLY_NUM    1
0045 
0046 #define RK3368_SOC_CON15        0x43c
0047 #define RK3368_SOC_CON15_FLASH0     BIT(14)
0048 #define RK3368_SOC_FLASH_SUPPLY_NUM 2
0049 
0050 #define RK3399_PMUGRF_CON0      0x180
0051 #define RK3399_PMUGRF_CON0_VSEL     BIT(8)
0052 #define RK3399_PMUGRF_VSEL_SUPPLY_NUM   9
0053 
0054 #define RK3568_PMU_GRF_IO_VSEL0     (0x0140)
0055 #define RK3568_PMU_GRF_IO_VSEL1     (0x0144)
0056 #define RK3568_PMU_GRF_IO_VSEL2     (0x0148)
0057 
0058 struct rockchip_iodomain;
0059 
0060 struct rockchip_iodomain_supply {
0061     struct rockchip_iodomain *iod;
0062     struct regulator *reg;
0063     struct notifier_block nb;
0064     int idx;
0065 };
0066 
0067 struct rockchip_iodomain_soc_data {
0068     int grf_offset;
0069     const char *supply_names[MAX_SUPPLIES];
0070     void (*init)(struct rockchip_iodomain *iod);
0071     int (*write)(struct rockchip_iodomain_supply *supply, int uV);
0072 };
0073 
0074 struct rockchip_iodomain {
0075     struct device *dev;
0076     struct regmap *grf;
0077     const struct rockchip_iodomain_soc_data *soc_data;
0078     struct rockchip_iodomain_supply supplies[MAX_SUPPLIES];
0079     int (*write)(struct rockchip_iodomain_supply *supply, int uV);
0080 };
0081 
0082 static int rk3568_iodomain_write(struct rockchip_iodomain_supply *supply, int uV)
0083 {
0084     struct rockchip_iodomain *iod = supply->iod;
0085     u32 is_3v3 = uV > MAX_VOLTAGE_1_8;
0086     u32 val0, val1;
0087     int b;
0088 
0089     switch (supply->idx) {
0090     case 0: /* pmuio1 */
0091         break;
0092     case 1: /* pmuio2 */
0093         b = supply->idx;
0094         val0 = BIT(16 + b) | (is_3v3 ? 0 : BIT(b));
0095         b = supply->idx + 4;
0096         val1 = BIT(16 + b) | (is_3v3 ? BIT(b) : 0);
0097 
0098         regmap_write(iod->grf, RK3568_PMU_GRF_IO_VSEL2, val0);
0099         regmap_write(iod->grf, RK3568_PMU_GRF_IO_VSEL2, val1);
0100         break;
0101     case 3: /* vccio2 */
0102         break;
0103     case 2: /* vccio1 */
0104     case 4: /* vccio3 */
0105     case 5: /* vccio4 */
0106     case 6: /* vccio5 */
0107     case 7: /* vccio6 */
0108     case 8: /* vccio7 */
0109         b = supply->idx - 1;
0110         val0 = BIT(16 + b) | (is_3v3 ? 0 : BIT(b));
0111         val1 = BIT(16 + b) | (is_3v3 ? BIT(b) : 0);
0112 
0113         regmap_write(iod->grf, RK3568_PMU_GRF_IO_VSEL0, val0);
0114         regmap_write(iod->grf, RK3568_PMU_GRF_IO_VSEL1, val1);
0115         break;
0116     default:
0117         return -EINVAL;
0118     }
0119 
0120     return 0;
0121 }
0122 
0123 static int rockchip_iodomain_write(struct rockchip_iodomain_supply *supply,
0124                    int uV)
0125 {
0126     struct rockchip_iodomain *iod = supply->iod;
0127     u32 val;
0128     int ret;
0129 
0130     /* set value bit */
0131     val = (uV > MAX_VOLTAGE_1_8) ? 0 : 1;
0132     val <<= supply->idx;
0133 
0134     /* apply hiword-mask */
0135     val |= (BIT(supply->idx) << 16);
0136 
0137     ret = regmap_write(iod->grf, iod->soc_data->grf_offset, val);
0138     if (ret)
0139         dev_err(iod->dev, "Couldn't write to GRF\n");
0140 
0141     return ret;
0142 }
0143 
0144 static int rockchip_iodomain_notify(struct notifier_block *nb,
0145                     unsigned long event,
0146                     void *data)
0147 {
0148     struct rockchip_iodomain_supply *supply =
0149             container_of(nb, struct rockchip_iodomain_supply, nb);
0150     int uV;
0151     int ret;
0152 
0153     /*
0154      * According to Rockchip it's important to keep the SoC IO domain
0155      * higher than (or equal to) the external voltage.  That means we need
0156      * to change it before external voltage changes happen in the case
0157      * of an increase.
0158      *
0159      * Note that in the "pre" change we pick the max possible voltage that
0160      * the regulator might end up at (the client requests a range and we
0161      * don't know for certain the exact voltage).  Right now we rely on the
0162      * slop in MAX_VOLTAGE_1_8 and MAX_VOLTAGE_3_3 to save us if clients
0163      * request something like a max of 3.6V when they really want 3.3V.
0164      * We could attempt to come up with better rules if this fails.
0165      */
0166     if (event & REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) {
0167         struct pre_voltage_change_data *pvc_data = data;
0168 
0169         uV = max_t(unsigned long, pvc_data->old_uV, pvc_data->max_uV);
0170     } else if (event & (REGULATOR_EVENT_VOLTAGE_CHANGE |
0171                 REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE)) {
0172         uV = (unsigned long)data;
0173     } else {
0174         return NOTIFY_OK;
0175     }
0176 
0177     dev_dbg(supply->iod->dev, "Setting to %d\n", uV);
0178 
0179     if (uV > MAX_VOLTAGE_3_3) {
0180         dev_err(supply->iod->dev, "Voltage too high: %d\n", uV);
0181 
0182         if (event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE)
0183             return NOTIFY_BAD;
0184     }
0185 
0186     ret = supply->iod->write(supply, uV);
0187     if (ret && event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE)
0188         return NOTIFY_BAD;
0189 
0190     dev_dbg(supply->iod->dev, "Setting to %d done\n", uV);
0191     return NOTIFY_OK;
0192 }
0193 
0194 static void px30_iodomain_init(struct rockchip_iodomain *iod)
0195 {
0196     int ret;
0197     u32 val;
0198 
0199     /* if no VCCIO6 supply we should leave things alone */
0200     if (!iod->supplies[PX30_IO_VSEL_VCCIO6_SUPPLY_NUM].reg)
0201         return;
0202 
0203     /*
0204      * set vccio6 iodomain to also use this framework
0205      * instead of a special gpio.
0206      */
0207     val = PX30_IO_VSEL_VCCIO6_SRC | (PX30_IO_VSEL_VCCIO6_SRC << 16);
0208     ret = regmap_write(iod->grf, PX30_IO_VSEL, val);
0209     if (ret < 0)
0210         dev_warn(iod->dev, "couldn't update vccio6 ctrl\n");
0211 }
0212 
0213 static void rk3288_iodomain_init(struct rockchip_iodomain *iod)
0214 {
0215     int ret;
0216     u32 val;
0217 
0218     /* if no flash supply we should leave things alone */
0219     if (!iod->supplies[RK3288_SOC_FLASH_SUPPLY_NUM].reg)
0220         return;
0221 
0222     /*
0223      * set flash0 iodomain to also use this framework
0224      * instead of a special gpio.
0225      */
0226     val = RK3288_SOC_CON2_FLASH0 | (RK3288_SOC_CON2_FLASH0 << 16);
0227     ret = regmap_write(iod->grf, RK3288_SOC_CON2, val);
0228     if (ret < 0)
0229         dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
0230 }
0231 
0232 static void rk3328_iodomain_init(struct rockchip_iodomain *iod)
0233 {
0234     int ret;
0235     u32 val;
0236 
0237     /* if no vccio2 supply we should leave things alone */
0238     if (!iod->supplies[RK3328_SOC_VCCIO2_SUPPLY_NUM].reg)
0239         return;
0240 
0241     /*
0242      * set vccio2 iodomain to also use this framework
0243      * instead of a special gpio.
0244      */
0245     val = RK3328_SOC_CON4_VCCIO2 | (RK3328_SOC_CON4_VCCIO2 << 16);
0246     ret = regmap_write(iod->grf, RK3328_SOC_CON4, val);
0247     if (ret < 0)
0248         dev_warn(iod->dev, "couldn't update vccio2 vsel ctrl\n");
0249 }
0250 
0251 static void rk3368_iodomain_init(struct rockchip_iodomain *iod)
0252 {
0253     int ret;
0254     u32 val;
0255 
0256     /* if no flash supply we should leave things alone */
0257     if (!iod->supplies[RK3368_SOC_FLASH_SUPPLY_NUM].reg)
0258         return;
0259 
0260     /*
0261      * set flash0 iodomain to also use this framework
0262      * instead of a special gpio.
0263      */
0264     val = RK3368_SOC_CON15_FLASH0 | (RK3368_SOC_CON15_FLASH0 << 16);
0265     ret = regmap_write(iod->grf, RK3368_SOC_CON15, val);
0266     if (ret < 0)
0267         dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
0268 }
0269 
0270 static void rk3399_pmu_iodomain_init(struct rockchip_iodomain *iod)
0271 {
0272     int ret;
0273     u32 val;
0274 
0275     /* if no pmu io supply we should leave things alone */
0276     if (!iod->supplies[RK3399_PMUGRF_VSEL_SUPPLY_NUM].reg)
0277         return;
0278 
0279     /*
0280      * set pmu io iodomain to also use this framework
0281      * instead of a special gpio.
0282      */
0283     val = RK3399_PMUGRF_CON0_VSEL | (RK3399_PMUGRF_CON0_VSEL << 16);
0284     ret = regmap_write(iod->grf, RK3399_PMUGRF_CON0, val);
0285     if (ret < 0)
0286         dev_warn(iod->dev, "couldn't update pmu io iodomain ctrl\n");
0287 }
0288 
0289 static const struct rockchip_iodomain_soc_data soc_data_px30 = {
0290     .grf_offset = 0x180,
0291     .supply_names = {
0292         NULL,
0293         "vccio6",
0294         "vccio1",
0295         "vccio2",
0296         "vccio3",
0297         "vccio4",
0298         "vccio5",
0299         "vccio-oscgpi",
0300     },
0301     .init = px30_iodomain_init,
0302 };
0303 
0304 static const struct rockchip_iodomain_soc_data soc_data_px30_pmu = {
0305     .grf_offset = 0x100,
0306     .supply_names = {
0307         NULL,
0308         NULL,
0309         NULL,
0310         NULL,
0311         NULL,
0312         NULL,
0313         NULL,
0314         NULL,
0315         NULL,
0316         NULL,
0317         NULL,
0318         NULL,
0319         NULL,
0320         NULL,
0321         "pmuio1",
0322         "pmuio2",
0323     },
0324 };
0325 
0326 /*
0327  * On the rk3188 the io-domains are handled by a shared register with the
0328  * lower 8 bits being still being continuing drive-strength settings.
0329  */
0330 static const struct rockchip_iodomain_soc_data soc_data_rk3188 = {
0331     .grf_offset = 0x104,
0332     .supply_names = {
0333         NULL,
0334         NULL,
0335         NULL,
0336         NULL,
0337         NULL,
0338         NULL,
0339         NULL,
0340         NULL,
0341         "ap0",
0342         "ap1",
0343         "cif",
0344         "flash",
0345         "vccio0",
0346         "vccio1",
0347         "lcdc0",
0348         "lcdc1",
0349     },
0350 };
0351 
0352 static const struct rockchip_iodomain_soc_data soc_data_rk3228 = {
0353     .grf_offset = 0x418,
0354     .supply_names = {
0355         "vccio1",
0356         "vccio2",
0357         "vccio3",
0358         "vccio4",
0359     },
0360 };
0361 
0362 static const struct rockchip_iodomain_soc_data soc_data_rk3288 = {
0363     .grf_offset = 0x380,
0364     .supply_names = {
0365         "lcdc",     /* LCDC_VDD */
0366         "dvp",      /* DVPIO_VDD */
0367         "flash0",   /* FLASH0_VDD (emmc) */
0368         "flash1",   /* FLASH1_VDD (sdio1) */
0369         "wifi",     /* APIO3_VDD  (sdio0) */
0370         "bb",       /* APIO5_VDD */
0371         "audio",    /* APIO4_VDD */
0372         "sdcard",   /* SDMMC0_VDD (sdmmc) */
0373         "gpio30",   /* APIO1_VDD */
0374         "gpio1830", /* APIO2_VDD */
0375     },
0376     .init = rk3288_iodomain_init,
0377 };
0378 
0379 static const struct rockchip_iodomain_soc_data soc_data_rk3328 = {
0380     .grf_offset = 0x410,
0381     .supply_names = {
0382         "vccio1",
0383         "vccio2",
0384         "vccio3",
0385         "vccio4",
0386         "vccio5",
0387         "vccio6",
0388         "pmuio",
0389     },
0390     .init = rk3328_iodomain_init,
0391 };
0392 
0393 static const struct rockchip_iodomain_soc_data soc_data_rk3368 = {
0394     .grf_offset = 0x900,
0395     .supply_names = {
0396         NULL,       /* reserved */
0397         "dvp",      /* DVPIO_VDD */
0398         "flash0",   /* FLASH0_VDD (emmc) */
0399         "wifi",     /* APIO2_VDD (sdio0) */
0400         NULL,
0401         "audio",    /* APIO3_VDD */
0402         "sdcard",   /* SDMMC0_VDD (sdmmc) */
0403         "gpio30",   /* APIO1_VDD */
0404         "gpio1830", /* APIO4_VDD (gpujtag) */
0405     },
0406     .init = rk3368_iodomain_init,
0407 };
0408 
0409 static const struct rockchip_iodomain_soc_data soc_data_rk3368_pmu = {
0410     .grf_offset = 0x100,
0411     .supply_names = {
0412         NULL,
0413         NULL,
0414         NULL,
0415         NULL,
0416         "pmu",          /*PMU IO domain*/
0417         "vop",          /*LCDC IO domain*/
0418     },
0419 };
0420 
0421 static const struct rockchip_iodomain_soc_data soc_data_rk3399 = {
0422     .grf_offset = 0xe640,
0423     .supply_names = {
0424         "bt656",        /* APIO2_VDD */
0425         "audio",        /* APIO5_VDD */
0426         "sdmmc",        /* SDMMC0_VDD */
0427         "gpio1830",     /* APIO4_VDD */
0428     },
0429 };
0430 
0431 static const struct rockchip_iodomain_soc_data soc_data_rk3399_pmu = {
0432     .grf_offset = 0x180,
0433     .supply_names = {
0434         NULL,
0435         NULL,
0436         NULL,
0437         NULL,
0438         NULL,
0439         NULL,
0440         NULL,
0441         NULL,
0442         NULL,
0443         "pmu1830",      /* PMUIO2_VDD */
0444     },
0445     .init = rk3399_pmu_iodomain_init,
0446 };
0447 
0448 static const struct rockchip_iodomain_soc_data soc_data_rk3568_pmu = {
0449     .grf_offset = 0x140,
0450     .supply_names = {
0451         "pmuio1",
0452         "pmuio2",
0453         "vccio1",
0454         "vccio2",
0455         "vccio3",
0456         "vccio4",
0457         "vccio5",
0458         "vccio6",
0459         "vccio7",
0460     },
0461     .write = rk3568_iodomain_write,
0462 };
0463 
0464 static const struct rockchip_iodomain_soc_data soc_data_rv1108 = {
0465     .grf_offset = 0x404,
0466     .supply_names = {
0467         NULL,
0468         NULL,
0469         NULL,
0470         NULL,
0471         NULL,
0472         NULL,
0473         NULL,
0474         NULL,
0475         NULL,
0476         NULL,
0477         NULL,
0478         "vccio1",
0479         "vccio2",
0480         "vccio3",
0481         "vccio5",
0482         "vccio6",
0483     },
0484 
0485 };
0486 
0487 static const struct rockchip_iodomain_soc_data soc_data_rv1108_pmu = {
0488     .grf_offset = 0x104,
0489     .supply_names = {
0490         "pmu",
0491     },
0492 };
0493 
0494 static const struct of_device_id rockchip_iodomain_match[] = {
0495     {
0496         .compatible = "rockchip,px30-io-voltage-domain",
0497         .data = (void *)&soc_data_px30
0498     },
0499     {
0500         .compatible = "rockchip,px30-pmu-io-voltage-domain",
0501         .data = (void *)&soc_data_px30_pmu
0502     },
0503     {
0504         .compatible = "rockchip,rk3188-io-voltage-domain",
0505         .data = &soc_data_rk3188
0506     },
0507     {
0508         .compatible = "rockchip,rk3228-io-voltage-domain",
0509         .data = &soc_data_rk3228
0510     },
0511     {
0512         .compatible = "rockchip,rk3288-io-voltage-domain",
0513         .data = &soc_data_rk3288
0514     },
0515     {
0516         .compatible = "rockchip,rk3328-io-voltage-domain",
0517         .data = &soc_data_rk3328
0518     },
0519     {
0520         .compatible = "rockchip,rk3368-io-voltage-domain",
0521         .data = &soc_data_rk3368
0522     },
0523     {
0524         .compatible = "rockchip,rk3368-pmu-io-voltage-domain",
0525         .data = &soc_data_rk3368_pmu
0526     },
0527     {
0528         .compatible = "rockchip,rk3399-io-voltage-domain",
0529         .data = &soc_data_rk3399
0530     },
0531     {
0532         .compatible = "rockchip,rk3399-pmu-io-voltage-domain",
0533         .data = &soc_data_rk3399_pmu
0534     },
0535     {
0536         .compatible = "rockchip,rk3568-pmu-io-voltage-domain",
0537         .data = &soc_data_rk3568_pmu
0538     },
0539     {
0540         .compatible = "rockchip,rv1108-io-voltage-domain",
0541         .data = &soc_data_rv1108
0542     },
0543     {
0544         .compatible = "rockchip,rv1108-pmu-io-voltage-domain",
0545         .data = &soc_data_rv1108_pmu
0546     },
0547     { /* sentinel */ },
0548 };
0549 MODULE_DEVICE_TABLE(of, rockchip_iodomain_match);
0550 
0551 static int rockchip_iodomain_probe(struct platform_device *pdev)
0552 {
0553     struct device_node *np = pdev->dev.of_node;
0554     const struct of_device_id *match;
0555     struct rockchip_iodomain *iod;
0556     struct device *parent;
0557     int i, ret = 0;
0558 
0559     if (!np)
0560         return -ENODEV;
0561 
0562     iod = devm_kzalloc(&pdev->dev, sizeof(*iod), GFP_KERNEL);
0563     if (!iod)
0564         return -ENOMEM;
0565 
0566     iod->dev = &pdev->dev;
0567     platform_set_drvdata(pdev, iod);
0568 
0569     match = of_match_node(rockchip_iodomain_match, np);
0570     iod->soc_data = match->data;
0571 
0572     if (iod->soc_data->write)
0573         iod->write = iod->soc_data->write;
0574     else
0575         iod->write = rockchip_iodomain_write;
0576 
0577     parent = pdev->dev.parent;
0578     if (parent && parent->of_node) {
0579         iod->grf = syscon_node_to_regmap(parent->of_node);
0580     } else {
0581         dev_dbg(&pdev->dev, "falling back to old binding\n");
0582         iod->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
0583     }
0584 
0585     if (IS_ERR(iod->grf)) {
0586         dev_err(&pdev->dev, "couldn't find grf regmap\n");
0587         return PTR_ERR(iod->grf);
0588     }
0589 
0590     for (i = 0; i < MAX_SUPPLIES; i++) {
0591         const char *supply_name = iod->soc_data->supply_names[i];
0592         struct rockchip_iodomain_supply *supply = &iod->supplies[i];
0593         struct regulator *reg;
0594         int uV;
0595 
0596         if (!supply_name)
0597             continue;
0598 
0599         reg = devm_regulator_get_optional(iod->dev, supply_name);
0600         if (IS_ERR(reg)) {
0601             ret = PTR_ERR(reg);
0602 
0603             /* If a supply wasn't specified, that's OK */
0604             if (ret == -ENODEV)
0605                 continue;
0606             else if (ret != -EPROBE_DEFER)
0607                 dev_err(iod->dev, "couldn't get regulator %s\n",
0608                     supply_name);
0609             goto unreg_notify;
0610         }
0611 
0612         /* set initial correct value */
0613         uV = regulator_get_voltage(reg);
0614 
0615         /* must be a regulator we can get the voltage of */
0616         if (uV < 0) {
0617             dev_err(iod->dev, "Can't determine voltage: %s\n",
0618                 supply_name);
0619             ret = uV;
0620             goto unreg_notify;
0621         }
0622 
0623         if (uV > MAX_VOLTAGE_3_3) {
0624             dev_crit(iod->dev,
0625                  "%d uV is too high. May damage SoC!\n",
0626                  uV);
0627             ret = -EINVAL;
0628             goto unreg_notify;
0629         }
0630 
0631         /* setup our supply */
0632         supply->idx = i;
0633         supply->iod = iod;
0634         supply->reg = reg;
0635         supply->nb.notifier_call = rockchip_iodomain_notify;
0636 
0637         ret = iod->write(supply, uV);
0638         if (ret) {
0639             supply->reg = NULL;
0640             goto unreg_notify;
0641         }
0642 
0643         /* register regulator notifier */
0644         ret = regulator_register_notifier(reg, &supply->nb);
0645         if (ret) {
0646             dev_err(&pdev->dev,
0647                 "regulator notifier request failed\n");
0648             supply->reg = NULL;
0649             goto unreg_notify;
0650         }
0651     }
0652 
0653     if (iod->soc_data->init)
0654         iod->soc_data->init(iod);
0655 
0656     return 0;
0657 
0658 unreg_notify:
0659     for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
0660         struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
0661 
0662         if (io_supply->reg)
0663             regulator_unregister_notifier(io_supply->reg,
0664                               &io_supply->nb);
0665     }
0666 
0667     return ret;
0668 }
0669 
0670 static int rockchip_iodomain_remove(struct platform_device *pdev)
0671 {
0672     struct rockchip_iodomain *iod = platform_get_drvdata(pdev);
0673     int i;
0674 
0675     for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
0676         struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
0677 
0678         if (io_supply->reg)
0679             regulator_unregister_notifier(io_supply->reg,
0680                               &io_supply->nb);
0681     }
0682 
0683     return 0;
0684 }
0685 
0686 static struct platform_driver rockchip_iodomain_driver = {
0687     .probe   = rockchip_iodomain_probe,
0688     .remove  = rockchip_iodomain_remove,
0689     .driver  = {
0690         .name  = "rockchip-iodomain",
0691         .of_match_table = rockchip_iodomain_match,
0692     },
0693 };
0694 
0695 module_platform_driver(rockchip_iodomain_driver);
0696 
0697 MODULE_DESCRIPTION("Rockchip IO-domain driver");
0698 MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
0699 MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>");
0700 MODULE_LICENSE("GPL v2");