cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

io-domain.c (16137B)


      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
     58struct rockchip_iodomain;
     59
     60struct rockchip_iodomain_supply {
     61	struct rockchip_iodomain *iod;
     62	struct regulator *reg;
     63	struct notifier_block nb;
     64	int idx;
     65};
     66
     67struct 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
     74struct 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
     82static 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
    123static 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
    144static 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
    194static 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
    213static 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
    232static 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
    251static 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
    270static 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
    289static 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
    304static 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 */
    330static 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
    352static 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
    362static 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
    379static 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
    393static 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
    409static 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
    421static 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
    431static 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
    448static 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
    464static 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
    487static const struct rockchip_iodomain_soc_data soc_data_rv1108_pmu = {
    488	.grf_offset = 0x104,
    489	.supply_names = {
    490		"pmu",
    491	},
    492};
    493
    494static const struct of_device_id rockchip_iodomain_match[] = {
    495	{
    496		.compatible = "rockchip,px30-io-voltage-domain",
    497		.data = (void *)&soc_data_px30
    498	},
    499	{
    500		.compatible = "rockchip,px30-pmu-io-voltage-domain",
    501		.data = (void *)&soc_data_px30_pmu
    502	},
    503	{
    504		.compatible = "rockchip,rk3188-io-voltage-domain",
    505		.data = &soc_data_rk3188
    506	},
    507	{
    508		.compatible = "rockchip,rk3228-io-voltage-domain",
    509		.data = &soc_data_rk3228
    510	},
    511	{
    512		.compatible = "rockchip,rk3288-io-voltage-domain",
    513		.data = &soc_data_rk3288
    514	},
    515	{
    516		.compatible = "rockchip,rk3328-io-voltage-domain",
    517		.data = &soc_data_rk3328
    518	},
    519	{
    520		.compatible = "rockchip,rk3368-io-voltage-domain",
    521		.data = &soc_data_rk3368
    522	},
    523	{
    524		.compatible = "rockchip,rk3368-pmu-io-voltage-domain",
    525		.data = &soc_data_rk3368_pmu
    526	},
    527	{
    528		.compatible = "rockchip,rk3399-io-voltage-domain",
    529		.data = &soc_data_rk3399
    530	},
    531	{
    532		.compatible = "rockchip,rk3399-pmu-io-voltage-domain",
    533		.data = &soc_data_rk3399_pmu
    534	},
    535	{
    536		.compatible = "rockchip,rk3568-pmu-io-voltage-domain",
    537		.data = &soc_data_rk3568_pmu
    538	},
    539	{
    540		.compatible = "rockchip,rv1108-io-voltage-domain",
    541		.data = &soc_data_rv1108
    542	},
    543	{
    544		.compatible = "rockchip,rv1108-pmu-io-voltage-domain",
    545		.data = &soc_data_rv1108_pmu
    546	},
    547	{ /* sentinel */ },
    548};
    549MODULE_DEVICE_TABLE(of, rockchip_iodomain_match);
    550
    551static int rockchip_iodomain_probe(struct platform_device *pdev)
    552{
    553	struct device_node *np = pdev->dev.of_node;
    554	const struct of_device_id *match;
    555	struct rockchip_iodomain *iod;
    556	struct device *parent;
    557	int i, ret = 0;
    558
    559	if (!np)
    560		return -ENODEV;
    561
    562	iod = devm_kzalloc(&pdev->dev, sizeof(*iod), GFP_KERNEL);
    563	if (!iod)
    564		return -ENOMEM;
    565
    566	iod->dev = &pdev->dev;
    567	platform_set_drvdata(pdev, iod);
    568
    569	match = of_match_node(rockchip_iodomain_match, np);
    570	iod->soc_data = match->data;
    571
    572	if (iod->soc_data->write)
    573		iod->write = iod->soc_data->write;
    574	else
    575		iod->write = rockchip_iodomain_write;
    576
    577	parent = pdev->dev.parent;
    578	if (parent && parent->of_node) {
    579		iod->grf = syscon_node_to_regmap(parent->of_node);
    580	} else {
    581		dev_dbg(&pdev->dev, "falling back to old binding\n");
    582		iod->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
    583	}
    584
    585	if (IS_ERR(iod->grf)) {
    586		dev_err(&pdev->dev, "couldn't find grf regmap\n");
    587		return PTR_ERR(iod->grf);
    588	}
    589
    590	for (i = 0; i < MAX_SUPPLIES; i++) {
    591		const char *supply_name = iod->soc_data->supply_names[i];
    592		struct rockchip_iodomain_supply *supply = &iod->supplies[i];
    593		struct regulator *reg;
    594		int uV;
    595
    596		if (!supply_name)
    597			continue;
    598
    599		reg = devm_regulator_get_optional(iod->dev, supply_name);
    600		if (IS_ERR(reg)) {
    601			ret = PTR_ERR(reg);
    602
    603			/* If a supply wasn't specified, that's OK */
    604			if (ret == -ENODEV)
    605				continue;
    606			else if (ret != -EPROBE_DEFER)
    607				dev_err(iod->dev, "couldn't get regulator %s\n",
    608					supply_name);
    609			goto unreg_notify;
    610		}
    611
    612		/* set initial correct value */
    613		uV = regulator_get_voltage(reg);
    614
    615		/* must be a regulator we can get the voltage of */
    616		if (uV < 0) {
    617			dev_err(iod->dev, "Can't determine voltage: %s\n",
    618				supply_name);
    619			ret = uV;
    620			goto unreg_notify;
    621		}
    622
    623		if (uV > MAX_VOLTAGE_3_3) {
    624			dev_crit(iod->dev,
    625				 "%d uV is too high. May damage SoC!\n",
    626				 uV);
    627			ret = -EINVAL;
    628			goto unreg_notify;
    629		}
    630
    631		/* setup our supply */
    632		supply->idx = i;
    633		supply->iod = iod;
    634		supply->reg = reg;
    635		supply->nb.notifier_call = rockchip_iodomain_notify;
    636
    637		ret = iod->write(supply, uV);
    638		if (ret) {
    639			supply->reg = NULL;
    640			goto unreg_notify;
    641		}
    642
    643		/* register regulator notifier */
    644		ret = regulator_register_notifier(reg, &supply->nb);
    645		if (ret) {
    646			dev_err(&pdev->dev,
    647				"regulator notifier request failed\n");
    648			supply->reg = NULL;
    649			goto unreg_notify;
    650		}
    651	}
    652
    653	if (iod->soc_data->init)
    654		iod->soc_data->init(iod);
    655
    656	return 0;
    657
    658unreg_notify:
    659	for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
    660		struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
    661
    662		if (io_supply->reg)
    663			regulator_unregister_notifier(io_supply->reg,
    664						      &io_supply->nb);
    665	}
    666
    667	return ret;
    668}
    669
    670static int rockchip_iodomain_remove(struct platform_device *pdev)
    671{
    672	struct rockchip_iodomain *iod = platform_get_drvdata(pdev);
    673	int i;
    674
    675	for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
    676		struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
    677
    678		if (io_supply->reg)
    679			regulator_unregister_notifier(io_supply->reg,
    680						      &io_supply->nb);
    681	}
    682
    683	return 0;
    684}
    685
    686static struct platform_driver rockchip_iodomain_driver = {
    687	.probe   = rockchip_iodomain_probe,
    688	.remove  = rockchip_iodomain_remove,
    689	.driver  = {
    690		.name  = "rockchip-iodomain",
    691		.of_match_table = rockchip_iodomain_match,
    692	},
    693};
    694
    695module_platform_driver(rockchip_iodomain_driver);
    696
    697MODULE_DESCRIPTION("Rockchip IO-domain driver");
    698MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
    699MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>");
    700MODULE_LICENSE("GPL v2");