xref: /linux/drivers/soc/rockchip/io-domain.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
1e943c43bSUlf Hansson // SPDX-License-Identifier: GPL-2.0-only
2e943c43bSUlf Hansson /*
3e943c43bSUlf Hansson  * Rockchip IO Voltage Domain driver
4e943c43bSUlf Hansson  *
5e943c43bSUlf Hansson  * Copyright 2014 MundoReader S.L.
6e943c43bSUlf Hansson  * Copyright 2014 Google, Inc.
7e943c43bSUlf Hansson  */
8e943c43bSUlf Hansson 
9e943c43bSUlf Hansson #include <linux/kernel.h>
10e943c43bSUlf Hansson #include <linux/module.h>
11e943c43bSUlf Hansson #include <linux/err.h>
12e943c43bSUlf Hansson #include <linux/mfd/syscon.h>
13e943c43bSUlf Hansson #include <linux/of.h>
14e943c43bSUlf Hansson #include <linux/platform_device.h>
15e943c43bSUlf Hansson #include <linux/regmap.h>
16e943c43bSUlf Hansson #include <linux/regulator/consumer.h>
17e943c43bSUlf Hansson 
18e943c43bSUlf Hansson #define MAX_SUPPLIES		16
19e943c43bSUlf Hansson 
20e943c43bSUlf Hansson /*
21e943c43bSUlf Hansson  * The max voltage for 1.8V and 3.3V come from the Rockchip datasheet under
22e943c43bSUlf Hansson  * "Recommended Operating Conditions" for "Digital GPIO".   When the typical
23e943c43bSUlf Hansson  * is 3.3V the max is 3.6V.  When the typical is 1.8V the max is 1.98V.
24e943c43bSUlf Hansson  *
25e943c43bSUlf Hansson  * They are used like this:
26e943c43bSUlf Hansson  * - If the voltage on a rail is above the "1.8" voltage (1.98V) we'll tell the
27e943c43bSUlf Hansson  *   SoC we're at 3.3.
28e943c43bSUlf Hansson  * - If the voltage on a rail is above the "3.3" voltage (3.6V) we'll consider
29e943c43bSUlf Hansson  *   that to be an error.
30e943c43bSUlf Hansson  */
31e943c43bSUlf Hansson #define MAX_VOLTAGE_1_8		1980000
32e943c43bSUlf Hansson #define MAX_VOLTAGE_3_3		3600000
33e943c43bSUlf Hansson 
34e943c43bSUlf Hansson #define PX30_IO_VSEL			0x180
35e943c43bSUlf Hansson #define PX30_IO_VSEL_VCCIO6_SRC		BIT(0)
36e943c43bSUlf Hansson #define PX30_IO_VSEL_VCCIO6_SUPPLY_NUM	1
37e943c43bSUlf Hansson 
38e943c43bSUlf Hansson #define RK3288_SOC_CON2			0x24c
39e943c43bSUlf Hansson #define RK3288_SOC_CON2_FLASH0		BIT(7)
40e943c43bSUlf Hansson #define RK3288_SOC_FLASH_SUPPLY_NUM	2
41e943c43bSUlf Hansson 
42*f0d70478SDavid Wu #define RK3308_SOC_CON0			0x300
43*f0d70478SDavid Wu #define RK3308_SOC_CON0_VCCIO3		BIT(8)
44*f0d70478SDavid Wu #define RK3308_SOC_VCCIO3_SUPPLY_NUM	3
45*f0d70478SDavid Wu 
46e943c43bSUlf Hansson #define RK3328_SOC_CON4			0x410
47e943c43bSUlf Hansson #define RK3328_SOC_CON4_VCCIO2		BIT(7)
48e943c43bSUlf Hansson #define RK3328_SOC_VCCIO2_SUPPLY_NUM	1
49e943c43bSUlf Hansson 
50e943c43bSUlf Hansson #define RK3368_SOC_CON15		0x43c
51e943c43bSUlf Hansson #define RK3368_SOC_CON15_FLASH0		BIT(14)
52e943c43bSUlf Hansson #define RK3368_SOC_FLASH_SUPPLY_NUM	2
53e943c43bSUlf Hansson 
54e943c43bSUlf Hansson #define RK3399_PMUGRF_CON0		0x180
55e943c43bSUlf Hansson #define RK3399_PMUGRF_CON0_VSEL		BIT(8)
56e943c43bSUlf Hansson #define RK3399_PMUGRF_VSEL_SUPPLY_NUM	9
57e943c43bSUlf Hansson 
5828b05a64SJianqun Xu #define RK3568_PMU_GRF_IO_VSEL0		(0x0140)
5928b05a64SJianqun Xu #define RK3568_PMU_GRF_IO_VSEL1		(0x0144)
6028b05a64SJianqun Xu #define RK3568_PMU_GRF_IO_VSEL2		(0x0148)
61e943c43bSUlf Hansson 
6228b05a64SJianqun Xu struct rockchip_iodomain;
63e943c43bSUlf Hansson 
64e943c43bSUlf Hansson struct rockchip_iodomain_supply {
65e943c43bSUlf Hansson 	struct rockchip_iodomain *iod;
66e943c43bSUlf Hansson 	struct regulator *reg;
67e943c43bSUlf Hansson 	struct notifier_block nb;
68e943c43bSUlf Hansson 	int idx;
69e943c43bSUlf Hansson };
70e943c43bSUlf Hansson 
7128b05a64SJianqun Xu struct rockchip_iodomain_soc_data {
7228b05a64SJianqun Xu 	int grf_offset;
7328b05a64SJianqun Xu 	const char *supply_names[MAX_SUPPLIES];
7428b05a64SJianqun Xu 	void (*init)(struct rockchip_iodomain *iod);
7528b05a64SJianqun Xu 	int (*write)(struct rockchip_iodomain_supply *supply, int uV);
7628b05a64SJianqun Xu };
7728b05a64SJianqun Xu 
78e943c43bSUlf Hansson struct rockchip_iodomain {
79e943c43bSUlf Hansson 	struct device *dev;
80e943c43bSUlf Hansson 	struct regmap *grf;
81e943c43bSUlf Hansson 	const struct rockchip_iodomain_soc_data *soc_data;
82e943c43bSUlf Hansson 	struct rockchip_iodomain_supply supplies[MAX_SUPPLIES];
8328b05a64SJianqun Xu 	int (*write)(struct rockchip_iodomain_supply *supply, int uV);
84e943c43bSUlf Hansson };
85e943c43bSUlf Hansson 
rk3568_iodomain_write(struct rockchip_iodomain_supply * supply,int uV)8628b05a64SJianqun Xu static int rk3568_iodomain_write(struct rockchip_iodomain_supply *supply, int uV)
8728b05a64SJianqun Xu {
8828b05a64SJianqun Xu 	struct rockchip_iodomain *iod = supply->iod;
8928b05a64SJianqun Xu 	u32 is_3v3 = uV > MAX_VOLTAGE_1_8;
9028b05a64SJianqun Xu 	u32 val0, val1;
9128b05a64SJianqun Xu 	int b;
9228b05a64SJianqun Xu 
9328b05a64SJianqun Xu 	switch (supply->idx) {
9428b05a64SJianqun Xu 	case 0: /* pmuio1 */
9528b05a64SJianqun Xu 		break;
9628b05a64SJianqun Xu 	case 1: /* pmuio2 */
9728b05a64SJianqun Xu 		b = supply->idx;
9828b05a64SJianqun Xu 		val0 = BIT(16 + b) | (is_3v3 ? 0 : BIT(b));
9928b05a64SJianqun Xu 		b = supply->idx + 4;
10028b05a64SJianqun Xu 		val1 = BIT(16 + b) | (is_3v3 ? BIT(b) : 0);
10128b05a64SJianqun Xu 
10228b05a64SJianqun Xu 		regmap_write(iod->grf, RK3568_PMU_GRF_IO_VSEL2, val0);
10328b05a64SJianqun Xu 		regmap_write(iod->grf, RK3568_PMU_GRF_IO_VSEL2, val1);
10428b05a64SJianqun Xu 		break;
10528b05a64SJianqun Xu 	case 3: /* vccio2 */
10628b05a64SJianqun Xu 		break;
10728b05a64SJianqun Xu 	case 2: /* vccio1 */
10828b05a64SJianqun Xu 	case 4: /* vccio3 */
10928b05a64SJianqun Xu 	case 5: /* vccio4 */
11028b05a64SJianqun Xu 	case 6: /* vccio5 */
11128b05a64SJianqun Xu 	case 7: /* vccio6 */
11228b05a64SJianqun Xu 	case 8: /* vccio7 */
11328b05a64SJianqun Xu 		b = supply->idx - 1;
11428b05a64SJianqun Xu 		val0 = BIT(16 + b) | (is_3v3 ? 0 : BIT(b));
11528b05a64SJianqun Xu 		val1 = BIT(16 + b) | (is_3v3 ? BIT(b) : 0);
11628b05a64SJianqun Xu 
11728b05a64SJianqun Xu 		regmap_write(iod->grf, RK3568_PMU_GRF_IO_VSEL0, val0);
11828b05a64SJianqun Xu 		regmap_write(iod->grf, RK3568_PMU_GRF_IO_VSEL1, val1);
11928b05a64SJianqun Xu 		break;
12028b05a64SJianqun Xu 	default:
12128b05a64SJianqun Xu 		return -EINVAL;
1229e5747c5SJiapeng Chong 	}
12328b05a64SJianqun Xu 
12428b05a64SJianqun Xu 	return 0;
12528b05a64SJianqun Xu }
12628b05a64SJianqun Xu 
rockchip_iodomain_write(struct rockchip_iodomain_supply * supply,int uV)127e943c43bSUlf Hansson static int rockchip_iodomain_write(struct rockchip_iodomain_supply *supply,
128e943c43bSUlf Hansson 				   int uV)
129e943c43bSUlf Hansson {
130e943c43bSUlf Hansson 	struct rockchip_iodomain *iod = supply->iod;
131e943c43bSUlf Hansson 	u32 val;
132e943c43bSUlf Hansson 	int ret;
133e943c43bSUlf Hansson 
134e943c43bSUlf Hansson 	/* set value bit */
135e943c43bSUlf Hansson 	val = (uV > MAX_VOLTAGE_1_8) ? 0 : 1;
136e943c43bSUlf Hansson 	val <<= supply->idx;
137e943c43bSUlf Hansson 
138e943c43bSUlf Hansson 	/* apply hiword-mask */
139e943c43bSUlf Hansson 	val |= (BIT(supply->idx) << 16);
140e943c43bSUlf Hansson 
141e943c43bSUlf Hansson 	ret = regmap_write(iod->grf, iod->soc_data->grf_offset, val);
142e943c43bSUlf Hansson 	if (ret)
143e943c43bSUlf Hansson 		dev_err(iod->dev, "Couldn't write to GRF\n");
144e943c43bSUlf Hansson 
145e943c43bSUlf Hansson 	return ret;
146e943c43bSUlf Hansson }
147e943c43bSUlf Hansson 
rockchip_iodomain_notify(struct notifier_block * nb,unsigned long event,void * data)148e943c43bSUlf Hansson static int rockchip_iodomain_notify(struct notifier_block *nb,
149e943c43bSUlf Hansson 				    unsigned long event,
150e943c43bSUlf Hansson 				    void *data)
151e943c43bSUlf Hansson {
152e943c43bSUlf Hansson 	struct rockchip_iodomain_supply *supply =
153e943c43bSUlf Hansson 			container_of(nb, struct rockchip_iodomain_supply, nb);
154e943c43bSUlf Hansson 	int uV;
155e943c43bSUlf Hansson 	int ret;
156e943c43bSUlf Hansson 
157e943c43bSUlf Hansson 	/*
158e943c43bSUlf Hansson 	 * According to Rockchip it's important to keep the SoC IO domain
159e943c43bSUlf Hansson 	 * higher than (or equal to) the external voltage.  That means we need
160e943c43bSUlf Hansson 	 * to change it before external voltage changes happen in the case
161e943c43bSUlf Hansson 	 * of an increase.
162e943c43bSUlf Hansson 	 *
163e943c43bSUlf Hansson 	 * Note that in the "pre" change we pick the max possible voltage that
164e943c43bSUlf Hansson 	 * the regulator might end up at (the client requests a range and we
165e943c43bSUlf Hansson 	 * don't know for certain the exact voltage).  Right now we rely on the
166e943c43bSUlf Hansson 	 * slop in MAX_VOLTAGE_1_8 and MAX_VOLTAGE_3_3 to save us if clients
167e943c43bSUlf Hansson 	 * request something like a max of 3.6V when they really want 3.3V.
168e943c43bSUlf Hansson 	 * We could attempt to come up with better rules if this fails.
169e943c43bSUlf Hansson 	 */
170e943c43bSUlf Hansson 	if (event & REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) {
171e943c43bSUlf Hansson 		struct pre_voltage_change_data *pvc_data = data;
172e943c43bSUlf Hansson 
173e943c43bSUlf Hansson 		uV = max_t(unsigned long, pvc_data->old_uV, pvc_data->max_uV);
174e943c43bSUlf Hansson 	} else if (event & (REGULATOR_EVENT_VOLTAGE_CHANGE |
175e943c43bSUlf Hansson 			    REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE)) {
176e943c43bSUlf Hansson 		uV = (unsigned long)data;
177e943c43bSUlf Hansson 	} else {
178e943c43bSUlf Hansson 		return NOTIFY_OK;
179e943c43bSUlf Hansson 	}
180e943c43bSUlf Hansson 
181e943c43bSUlf Hansson 	dev_dbg(supply->iod->dev, "Setting to %d\n", uV);
182e943c43bSUlf Hansson 
183e943c43bSUlf Hansson 	if (uV > MAX_VOLTAGE_3_3) {
184e943c43bSUlf Hansson 		dev_err(supply->iod->dev, "Voltage too high: %d\n", uV);
185e943c43bSUlf Hansson 
186e943c43bSUlf Hansson 		if (event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE)
187e943c43bSUlf Hansson 			return NOTIFY_BAD;
188e943c43bSUlf Hansson 	}
189e943c43bSUlf Hansson 
19028b05a64SJianqun Xu 	ret = supply->iod->write(supply, uV);
191e943c43bSUlf Hansson 	if (ret && event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE)
192e943c43bSUlf Hansson 		return NOTIFY_BAD;
193e943c43bSUlf Hansson 
194e943c43bSUlf Hansson 	dev_dbg(supply->iod->dev, "Setting to %d done\n", uV);
195e943c43bSUlf Hansson 	return NOTIFY_OK;
196e943c43bSUlf Hansson }
197e943c43bSUlf Hansson 
px30_iodomain_init(struct rockchip_iodomain * iod)198e943c43bSUlf Hansson static void px30_iodomain_init(struct rockchip_iodomain *iod)
199e943c43bSUlf Hansson {
200e943c43bSUlf Hansson 	int ret;
201e943c43bSUlf Hansson 	u32 val;
202e943c43bSUlf Hansson 
203e943c43bSUlf Hansson 	/* if no VCCIO6 supply we should leave things alone */
204e943c43bSUlf Hansson 	if (!iod->supplies[PX30_IO_VSEL_VCCIO6_SUPPLY_NUM].reg)
205e943c43bSUlf Hansson 		return;
206e943c43bSUlf Hansson 
207e943c43bSUlf Hansson 	/*
208e943c43bSUlf Hansson 	 * set vccio6 iodomain to also use this framework
209e943c43bSUlf Hansson 	 * instead of a special gpio.
210e943c43bSUlf Hansson 	 */
211e943c43bSUlf Hansson 	val = PX30_IO_VSEL_VCCIO6_SRC | (PX30_IO_VSEL_VCCIO6_SRC << 16);
212e943c43bSUlf Hansson 	ret = regmap_write(iod->grf, PX30_IO_VSEL, val);
213e943c43bSUlf Hansson 	if (ret < 0)
214e943c43bSUlf Hansson 		dev_warn(iod->dev, "couldn't update vccio6 ctrl\n");
215e943c43bSUlf Hansson }
216e943c43bSUlf Hansson 
rk3288_iodomain_init(struct rockchip_iodomain * iod)217e943c43bSUlf Hansson static void rk3288_iodomain_init(struct rockchip_iodomain *iod)
218e943c43bSUlf Hansson {
219e943c43bSUlf Hansson 	int ret;
220e943c43bSUlf Hansson 	u32 val;
221e943c43bSUlf Hansson 
222e943c43bSUlf Hansson 	/* if no flash supply we should leave things alone */
223e943c43bSUlf Hansson 	if (!iod->supplies[RK3288_SOC_FLASH_SUPPLY_NUM].reg)
224e943c43bSUlf Hansson 		return;
225e943c43bSUlf Hansson 
226e943c43bSUlf Hansson 	/*
227e943c43bSUlf Hansson 	 * set flash0 iodomain to also use this framework
228e943c43bSUlf Hansson 	 * instead of a special gpio.
229e943c43bSUlf Hansson 	 */
230e943c43bSUlf Hansson 	val = RK3288_SOC_CON2_FLASH0 | (RK3288_SOC_CON2_FLASH0 << 16);
231e943c43bSUlf Hansson 	ret = regmap_write(iod->grf, RK3288_SOC_CON2, val);
232e943c43bSUlf Hansson 	if (ret < 0)
233e943c43bSUlf Hansson 		dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
234e943c43bSUlf Hansson }
235e943c43bSUlf Hansson 
rk3308_iodomain_init(struct rockchip_iodomain * iod)236*f0d70478SDavid Wu static void rk3308_iodomain_init(struct rockchip_iodomain *iod)
237*f0d70478SDavid Wu {
238*f0d70478SDavid Wu 	int ret;
239*f0d70478SDavid Wu 	u32 val;
240*f0d70478SDavid Wu 
241*f0d70478SDavid Wu 	/* if no vccio3 supply we should leave things alone */
242*f0d70478SDavid Wu 	if (!iod->supplies[RK3308_SOC_VCCIO3_SUPPLY_NUM].reg)
243*f0d70478SDavid Wu 		return;
244*f0d70478SDavid Wu 
245*f0d70478SDavid Wu 	/*
246*f0d70478SDavid Wu 	 * set vccio3 iodomain to also use this framework
247*f0d70478SDavid Wu 	 * instead of a special gpio.
248*f0d70478SDavid Wu 	 */
249*f0d70478SDavid Wu 	val = RK3308_SOC_CON0_VCCIO3 | (RK3308_SOC_CON0_VCCIO3 << 16);
250*f0d70478SDavid Wu 	ret = regmap_write(iod->grf, RK3308_SOC_CON0, val);
251*f0d70478SDavid Wu 	if (ret < 0)
252*f0d70478SDavid Wu 		dev_warn(iod->dev, "couldn't update vccio3 vsel ctrl\n");
253*f0d70478SDavid Wu }
254*f0d70478SDavid Wu 
rk3328_iodomain_init(struct rockchip_iodomain * iod)255e943c43bSUlf Hansson static void rk3328_iodomain_init(struct rockchip_iodomain *iod)
256e943c43bSUlf Hansson {
257e943c43bSUlf Hansson 	int ret;
258e943c43bSUlf Hansson 	u32 val;
259e943c43bSUlf Hansson 
260e943c43bSUlf Hansson 	/* if no vccio2 supply we should leave things alone */
261e943c43bSUlf Hansson 	if (!iod->supplies[RK3328_SOC_VCCIO2_SUPPLY_NUM].reg)
262e943c43bSUlf Hansson 		return;
263e943c43bSUlf Hansson 
264e943c43bSUlf Hansson 	/*
265e943c43bSUlf Hansson 	 * set vccio2 iodomain to also use this framework
266e943c43bSUlf Hansson 	 * instead of a special gpio.
267e943c43bSUlf Hansson 	 */
268e943c43bSUlf Hansson 	val = RK3328_SOC_CON4_VCCIO2 | (RK3328_SOC_CON4_VCCIO2 << 16);
269e943c43bSUlf Hansson 	ret = regmap_write(iod->grf, RK3328_SOC_CON4, val);
270e943c43bSUlf Hansson 	if (ret < 0)
271e943c43bSUlf Hansson 		dev_warn(iod->dev, "couldn't update vccio2 vsel ctrl\n");
272e943c43bSUlf Hansson }
273e943c43bSUlf Hansson 
rk3368_iodomain_init(struct rockchip_iodomain * iod)274e943c43bSUlf Hansson static void rk3368_iodomain_init(struct rockchip_iodomain *iod)
275e943c43bSUlf Hansson {
276e943c43bSUlf Hansson 	int ret;
277e943c43bSUlf Hansson 	u32 val;
278e943c43bSUlf Hansson 
279e943c43bSUlf Hansson 	/* if no flash supply we should leave things alone */
280e943c43bSUlf Hansson 	if (!iod->supplies[RK3368_SOC_FLASH_SUPPLY_NUM].reg)
281e943c43bSUlf Hansson 		return;
282e943c43bSUlf Hansson 
283e943c43bSUlf Hansson 	/*
284e943c43bSUlf Hansson 	 * set flash0 iodomain to also use this framework
285e943c43bSUlf Hansson 	 * instead of a special gpio.
286e943c43bSUlf Hansson 	 */
287e943c43bSUlf Hansson 	val = RK3368_SOC_CON15_FLASH0 | (RK3368_SOC_CON15_FLASH0 << 16);
288e943c43bSUlf Hansson 	ret = regmap_write(iod->grf, RK3368_SOC_CON15, val);
289e943c43bSUlf Hansson 	if (ret < 0)
290e943c43bSUlf Hansson 		dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
291e943c43bSUlf Hansson }
292e943c43bSUlf Hansson 
rk3399_pmu_iodomain_init(struct rockchip_iodomain * iod)293e943c43bSUlf Hansson static void rk3399_pmu_iodomain_init(struct rockchip_iodomain *iod)
294e943c43bSUlf Hansson {
295e943c43bSUlf Hansson 	int ret;
296e943c43bSUlf Hansson 	u32 val;
297e943c43bSUlf Hansson 
298e943c43bSUlf Hansson 	/* if no pmu io supply we should leave things alone */
299e943c43bSUlf Hansson 	if (!iod->supplies[RK3399_PMUGRF_VSEL_SUPPLY_NUM].reg)
300e943c43bSUlf Hansson 		return;
301e943c43bSUlf Hansson 
302e943c43bSUlf Hansson 	/*
303e943c43bSUlf Hansson 	 * set pmu io iodomain to also use this framework
304e943c43bSUlf Hansson 	 * instead of a special gpio.
305e943c43bSUlf Hansson 	 */
306e943c43bSUlf Hansson 	val = RK3399_PMUGRF_CON0_VSEL | (RK3399_PMUGRF_CON0_VSEL << 16);
307e943c43bSUlf Hansson 	ret = regmap_write(iod->grf, RK3399_PMUGRF_CON0, val);
308e943c43bSUlf Hansson 	if (ret < 0)
309e943c43bSUlf Hansson 		dev_warn(iod->dev, "couldn't update pmu io iodomain ctrl\n");
310e943c43bSUlf Hansson }
311e943c43bSUlf Hansson 
312e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_px30 = {
313e943c43bSUlf Hansson 	.grf_offset = 0x180,
314e943c43bSUlf Hansson 	.supply_names = {
315e943c43bSUlf Hansson 		NULL,
316e943c43bSUlf Hansson 		"vccio6",
317e943c43bSUlf Hansson 		"vccio1",
318e943c43bSUlf Hansson 		"vccio2",
319e943c43bSUlf Hansson 		"vccio3",
320e943c43bSUlf Hansson 		"vccio4",
321e943c43bSUlf Hansson 		"vccio5",
322e943c43bSUlf Hansson 		"vccio-oscgpi",
323e943c43bSUlf Hansson 	},
324e943c43bSUlf Hansson 	.init = px30_iodomain_init,
325e943c43bSUlf Hansson };
326e943c43bSUlf Hansson 
327e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_px30_pmu = {
328e943c43bSUlf Hansson 	.grf_offset = 0x100,
329e943c43bSUlf Hansson 	.supply_names = {
330e943c43bSUlf Hansson 		NULL,
331e943c43bSUlf Hansson 		NULL,
332e943c43bSUlf Hansson 		NULL,
333e943c43bSUlf Hansson 		NULL,
334e943c43bSUlf Hansson 		NULL,
335e943c43bSUlf Hansson 		NULL,
336e943c43bSUlf Hansson 		NULL,
337e943c43bSUlf Hansson 		NULL,
338e943c43bSUlf Hansson 		NULL,
339e943c43bSUlf Hansson 		NULL,
340e943c43bSUlf Hansson 		NULL,
341e943c43bSUlf Hansson 		NULL,
342e943c43bSUlf Hansson 		NULL,
343e943c43bSUlf Hansson 		NULL,
344e943c43bSUlf Hansson 		"pmuio1",
345e943c43bSUlf Hansson 		"pmuio2",
346e943c43bSUlf Hansson 	},
347e943c43bSUlf Hansson };
348e943c43bSUlf Hansson 
349e943c43bSUlf Hansson /*
350e943c43bSUlf Hansson  * On the rk3188 the io-domains are handled by a shared register with the
351e943c43bSUlf Hansson  * lower 8 bits being still being continuing drive-strength settings.
352e943c43bSUlf Hansson  */
353e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_rk3188 = {
354e943c43bSUlf Hansson 	.grf_offset = 0x104,
355e943c43bSUlf Hansson 	.supply_names = {
356e943c43bSUlf Hansson 		NULL,
357e943c43bSUlf Hansson 		NULL,
358e943c43bSUlf Hansson 		NULL,
359e943c43bSUlf Hansson 		NULL,
360e943c43bSUlf Hansson 		NULL,
361e943c43bSUlf Hansson 		NULL,
362e943c43bSUlf Hansson 		NULL,
363e943c43bSUlf Hansson 		NULL,
364e943c43bSUlf Hansson 		"ap0",
365e943c43bSUlf Hansson 		"ap1",
366e943c43bSUlf Hansson 		"cif",
367e943c43bSUlf Hansson 		"flash",
368e943c43bSUlf Hansson 		"vccio0",
369e943c43bSUlf Hansson 		"vccio1",
370e943c43bSUlf Hansson 		"lcdc0",
371e943c43bSUlf Hansson 		"lcdc1",
372e943c43bSUlf Hansson 	},
373e943c43bSUlf Hansson };
374e943c43bSUlf Hansson 
375e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_rk3228 = {
376e943c43bSUlf Hansson 	.grf_offset = 0x418,
377e943c43bSUlf Hansson 	.supply_names = {
378e943c43bSUlf Hansson 		"vccio1",
379e943c43bSUlf Hansson 		"vccio2",
380e943c43bSUlf Hansson 		"vccio3",
381e943c43bSUlf Hansson 		"vccio4",
382e943c43bSUlf Hansson 	},
383e943c43bSUlf Hansson };
384e943c43bSUlf Hansson 
385e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_rk3288 = {
386e943c43bSUlf Hansson 	.grf_offset = 0x380,
387e943c43bSUlf Hansson 	.supply_names = {
388e943c43bSUlf Hansson 		"lcdc",		/* LCDC_VDD */
389e943c43bSUlf Hansson 		"dvp",		/* DVPIO_VDD */
390e943c43bSUlf Hansson 		"flash0",	/* FLASH0_VDD (emmc) */
391e943c43bSUlf Hansson 		"flash1",	/* FLASH1_VDD (sdio1) */
392e943c43bSUlf Hansson 		"wifi",		/* APIO3_VDD  (sdio0) */
393e943c43bSUlf Hansson 		"bb",		/* APIO5_VDD */
394e943c43bSUlf Hansson 		"audio",	/* APIO4_VDD */
395e943c43bSUlf Hansson 		"sdcard",	/* SDMMC0_VDD (sdmmc) */
396e943c43bSUlf Hansson 		"gpio30",	/* APIO1_VDD */
397e943c43bSUlf Hansson 		"gpio1830",	/* APIO2_VDD */
398e943c43bSUlf Hansson 	},
399e943c43bSUlf Hansson 	.init = rk3288_iodomain_init,
400e943c43bSUlf Hansson };
401e943c43bSUlf Hansson 
402*f0d70478SDavid Wu static const struct rockchip_iodomain_soc_data soc_data_rk3308 = {
403*f0d70478SDavid Wu 	.grf_offset = 0x300,
404*f0d70478SDavid Wu 	.supply_names = {
405*f0d70478SDavid Wu 		"vccio0",
406*f0d70478SDavid Wu 		"vccio1",
407*f0d70478SDavid Wu 		"vccio2",
408*f0d70478SDavid Wu 		"vccio3",
409*f0d70478SDavid Wu 		"vccio4",
410*f0d70478SDavid Wu 		"vccio5",
411*f0d70478SDavid Wu 	},
412*f0d70478SDavid Wu 	.init = rk3308_iodomain_init,
413*f0d70478SDavid Wu };
414*f0d70478SDavid Wu 
415e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_rk3328 = {
416e943c43bSUlf Hansson 	.grf_offset = 0x410,
417e943c43bSUlf Hansson 	.supply_names = {
418e943c43bSUlf Hansson 		"vccio1",
419e943c43bSUlf Hansson 		"vccio2",
420e943c43bSUlf Hansson 		"vccio3",
421e943c43bSUlf Hansson 		"vccio4",
422e943c43bSUlf Hansson 		"vccio5",
423e943c43bSUlf Hansson 		"vccio6",
424e943c43bSUlf Hansson 		"pmuio",
425e943c43bSUlf Hansson 	},
426e943c43bSUlf Hansson 	.init = rk3328_iodomain_init,
427e943c43bSUlf Hansson };
428e943c43bSUlf Hansson 
429e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_rk3368 = {
430e943c43bSUlf Hansson 	.grf_offset = 0x900,
431e943c43bSUlf Hansson 	.supply_names = {
432e943c43bSUlf Hansson 		NULL,		/* reserved */
433e943c43bSUlf Hansson 		"dvp",		/* DVPIO_VDD */
434e943c43bSUlf Hansson 		"flash0",	/* FLASH0_VDD (emmc) */
435e943c43bSUlf Hansson 		"wifi",		/* APIO2_VDD (sdio0) */
436e943c43bSUlf Hansson 		NULL,
437e943c43bSUlf Hansson 		"audio",	/* APIO3_VDD */
438e943c43bSUlf Hansson 		"sdcard",	/* SDMMC0_VDD (sdmmc) */
439e943c43bSUlf Hansson 		"gpio30",	/* APIO1_VDD */
440e943c43bSUlf Hansson 		"gpio1830",	/* APIO4_VDD (gpujtag) */
441e943c43bSUlf Hansson 	},
442e943c43bSUlf Hansson 	.init = rk3368_iodomain_init,
443e943c43bSUlf Hansson };
444e943c43bSUlf Hansson 
445e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_rk3368_pmu = {
446e943c43bSUlf Hansson 	.grf_offset = 0x100,
447e943c43bSUlf Hansson 	.supply_names = {
448e943c43bSUlf Hansson 		NULL,
449e943c43bSUlf Hansson 		NULL,
450e943c43bSUlf Hansson 		NULL,
451e943c43bSUlf Hansson 		NULL,
452e943c43bSUlf Hansson 		"pmu",	        /*PMU IO domain*/
453e943c43bSUlf Hansson 		"vop",	        /*LCDC IO domain*/
454e943c43bSUlf Hansson 	},
455e943c43bSUlf Hansson };
456e943c43bSUlf Hansson 
457e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_rk3399 = {
458e943c43bSUlf Hansson 	.grf_offset = 0xe640,
459e943c43bSUlf Hansson 	.supply_names = {
460e943c43bSUlf Hansson 		"bt656",		/* APIO2_VDD */
461e943c43bSUlf Hansson 		"audio",		/* APIO5_VDD */
462e943c43bSUlf Hansson 		"sdmmc",		/* SDMMC0_VDD */
463e943c43bSUlf Hansson 		"gpio1830",		/* APIO4_VDD */
464e943c43bSUlf Hansson 	},
465e943c43bSUlf Hansson };
466e943c43bSUlf Hansson 
467e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_rk3399_pmu = {
468e943c43bSUlf Hansson 	.grf_offset = 0x180,
469e943c43bSUlf Hansson 	.supply_names = {
470e943c43bSUlf Hansson 		NULL,
471e943c43bSUlf Hansson 		NULL,
472e943c43bSUlf Hansson 		NULL,
473e943c43bSUlf Hansson 		NULL,
474e943c43bSUlf Hansson 		NULL,
475e943c43bSUlf Hansson 		NULL,
476e943c43bSUlf Hansson 		NULL,
477e943c43bSUlf Hansson 		NULL,
478e943c43bSUlf Hansson 		NULL,
479e943c43bSUlf Hansson 		"pmu1830",		/* PMUIO2_VDD */
480e943c43bSUlf Hansson 	},
481e943c43bSUlf Hansson 	.init = rk3399_pmu_iodomain_init,
482e943c43bSUlf Hansson };
483e943c43bSUlf Hansson 
48428b05a64SJianqun Xu static const struct rockchip_iodomain_soc_data soc_data_rk3568_pmu = {
48528b05a64SJianqun Xu 	.grf_offset = 0x140,
48628b05a64SJianqun Xu 	.supply_names = {
48728b05a64SJianqun Xu 		"pmuio1",
48828b05a64SJianqun Xu 		"pmuio2",
48928b05a64SJianqun Xu 		"vccio1",
49028b05a64SJianqun Xu 		"vccio2",
49128b05a64SJianqun Xu 		"vccio3",
49228b05a64SJianqun Xu 		"vccio4",
49328b05a64SJianqun Xu 		"vccio5",
49428b05a64SJianqun Xu 		"vccio6",
49528b05a64SJianqun Xu 		"vccio7",
49628b05a64SJianqun Xu 	},
49728b05a64SJianqun Xu 	.write = rk3568_iodomain_write,
49828b05a64SJianqun Xu };
49928b05a64SJianqun Xu 
500e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_rv1108 = {
501e943c43bSUlf Hansson 	.grf_offset = 0x404,
502e943c43bSUlf Hansson 	.supply_names = {
503e943c43bSUlf Hansson 		NULL,
504e943c43bSUlf Hansson 		NULL,
505e943c43bSUlf Hansson 		NULL,
506e943c43bSUlf Hansson 		NULL,
507e943c43bSUlf Hansson 		NULL,
508e943c43bSUlf Hansson 		NULL,
509e943c43bSUlf Hansson 		NULL,
510e943c43bSUlf Hansson 		NULL,
511e943c43bSUlf Hansson 		NULL,
512e943c43bSUlf Hansson 		NULL,
513e943c43bSUlf Hansson 		NULL,
514e943c43bSUlf Hansson 		"vccio1",
515e943c43bSUlf Hansson 		"vccio2",
516e943c43bSUlf Hansson 		"vccio3",
517e943c43bSUlf Hansson 		"vccio5",
518e943c43bSUlf Hansson 		"vccio6",
519e943c43bSUlf Hansson 	},
520e943c43bSUlf Hansson 
521e943c43bSUlf Hansson };
522e943c43bSUlf Hansson 
523e943c43bSUlf Hansson static const struct rockchip_iodomain_soc_data soc_data_rv1108_pmu = {
524e943c43bSUlf Hansson 	.grf_offset = 0x104,
525e943c43bSUlf Hansson 	.supply_names = {
526e943c43bSUlf Hansson 		"pmu",
527e943c43bSUlf Hansson 	},
528e943c43bSUlf Hansson };
529e943c43bSUlf Hansson 
530570ed4e5SJianqun Xu static const struct rockchip_iodomain_soc_data soc_data_rv1126_pmu = {
531570ed4e5SJianqun Xu 	.grf_offset = 0x140,
532570ed4e5SJianqun Xu 	.supply_names = {
533570ed4e5SJianqun Xu 		NULL,
534570ed4e5SJianqun Xu 		"vccio1",
535570ed4e5SJianqun Xu 		"vccio2",
536570ed4e5SJianqun Xu 		"vccio3",
537570ed4e5SJianqun Xu 		"vccio4",
538570ed4e5SJianqun Xu 		"vccio5",
539570ed4e5SJianqun Xu 		"vccio6",
540570ed4e5SJianqun Xu 		"vccio7",
541570ed4e5SJianqun Xu 		"pmuio0",
542570ed4e5SJianqun Xu 		"pmuio1",
543570ed4e5SJianqun Xu 	},
544570ed4e5SJianqun Xu };
545570ed4e5SJianqun Xu 
546e943c43bSUlf Hansson static const struct of_device_id rockchip_iodomain_match[] = {
547e943c43bSUlf Hansson 	{
548e943c43bSUlf Hansson 		.compatible = "rockchip,px30-io-voltage-domain",
549e943c43bSUlf Hansson 		.data = (void *)&soc_data_px30
550e943c43bSUlf Hansson 	},
551e943c43bSUlf Hansson 	{
552e943c43bSUlf Hansson 		.compatible = "rockchip,px30-pmu-io-voltage-domain",
553e943c43bSUlf Hansson 		.data = (void *)&soc_data_px30_pmu
554e943c43bSUlf Hansson 	},
555e943c43bSUlf Hansson 	{
556e943c43bSUlf Hansson 		.compatible = "rockchip,rk3188-io-voltage-domain",
557e943c43bSUlf Hansson 		.data = &soc_data_rk3188
558e943c43bSUlf Hansson 	},
559e943c43bSUlf Hansson 	{
560e943c43bSUlf Hansson 		.compatible = "rockchip,rk3228-io-voltage-domain",
561e943c43bSUlf Hansson 		.data = &soc_data_rk3228
562e943c43bSUlf Hansson 	},
563e943c43bSUlf Hansson 	{
564e943c43bSUlf Hansson 		.compatible = "rockchip,rk3288-io-voltage-domain",
565e943c43bSUlf Hansson 		.data = &soc_data_rk3288
566e943c43bSUlf Hansson 	},
567e943c43bSUlf Hansson 	{
568*f0d70478SDavid Wu 		.compatible = "rockchip,rk3308-io-voltage-domain",
569*f0d70478SDavid Wu 		.data = &soc_data_rk3308
570*f0d70478SDavid Wu 	},
571*f0d70478SDavid Wu 	{
572e943c43bSUlf Hansson 		.compatible = "rockchip,rk3328-io-voltage-domain",
573e943c43bSUlf Hansson 		.data = &soc_data_rk3328
574e943c43bSUlf Hansson 	},
575e943c43bSUlf Hansson 	{
576e943c43bSUlf Hansson 		.compatible = "rockchip,rk3368-io-voltage-domain",
577e943c43bSUlf Hansson 		.data = &soc_data_rk3368
578e943c43bSUlf Hansson 	},
579e943c43bSUlf Hansson 	{
580e943c43bSUlf Hansson 		.compatible = "rockchip,rk3368-pmu-io-voltage-domain",
581e943c43bSUlf Hansson 		.data = &soc_data_rk3368_pmu
582e943c43bSUlf Hansson 	},
583e943c43bSUlf Hansson 	{
584e943c43bSUlf Hansson 		.compatible = "rockchip,rk3399-io-voltage-domain",
585e943c43bSUlf Hansson 		.data = &soc_data_rk3399
586e943c43bSUlf Hansson 	},
587e943c43bSUlf Hansson 	{
588e943c43bSUlf Hansson 		.compatible = "rockchip,rk3399-pmu-io-voltage-domain",
589e943c43bSUlf Hansson 		.data = &soc_data_rk3399_pmu
590e943c43bSUlf Hansson 	},
591e943c43bSUlf Hansson 	{
59228b05a64SJianqun Xu 		.compatible = "rockchip,rk3568-pmu-io-voltage-domain",
59328b05a64SJianqun Xu 		.data = &soc_data_rk3568_pmu
59428b05a64SJianqun Xu 	},
59528b05a64SJianqun Xu 	{
596e943c43bSUlf Hansson 		.compatible = "rockchip,rv1108-io-voltage-domain",
597e943c43bSUlf Hansson 		.data = &soc_data_rv1108
598e943c43bSUlf Hansson 	},
599e943c43bSUlf Hansson 	{
600e943c43bSUlf Hansson 		.compatible = "rockchip,rv1108-pmu-io-voltage-domain",
601e943c43bSUlf Hansson 		.data = &soc_data_rv1108_pmu
602e943c43bSUlf Hansson 	},
603570ed4e5SJianqun Xu 	{
604570ed4e5SJianqun Xu 		.compatible = "rockchip,rv1126-pmu-io-voltage-domain",
605570ed4e5SJianqun Xu 		.data = &soc_data_rv1126_pmu
606570ed4e5SJianqun Xu 	},
607e943c43bSUlf Hansson 	{ /* sentinel */ },
608e943c43bSUlf Hansson };
609e943c43bSUlf Hansson MODULE_DEVICE_TABLE(of, rockchip_iodomain_match);
610e943c43bSUlf Hansson 
rockchip_iodomain_probe(struct platform_device * pdev)611e943c43bSUlf Hansson static int rockchip_iodomain_probe(struct platform_device *pdev)
612e943c43bSUlf Hansson {
613e943c43bSUlf Hansson 	struct device_node *np = pdev->dev.of_node;
614e943c43bSUlf Hansson 	const struct of_device_id *match;
615e943c43bSUlf Hansson 	struct rockchip_iodomain *iod;
616e943c43bSUlf Hansson 	struct device *parent;
617e943c43bSUlf Hansson 	int i, ret = 0;
618e943c43bSUlf Hansson 
619e943c43bSUlf Hansson 	if (!np)
620e943c43bSUlf Hansson 		return -ENODEV;
621e943c43bSUlf Hansson 
622e943c43bSUlf Hansson 	iod = devm_kzalloc(&pdev->dev, sizeof(*iod), GFP_KERNEL);
623e943c43bSUlf Hansson 	if (!iod)
624e943c43bSUlf Hansson 		return -ENOMEM;
625e943c43bSUlf Hansson 
626e943c43bSUlf Hansson 	iod->dev = &pdev->dev;
627e943c43bSUlf Hansson 	platform_set_drvdata(pdev, iod);
628e943c43bSUlf Hansson 
629e943c43bSUlf Hansson 	match = of_match_node(rockchip_iodomain_match, np);
630e943c43bSUlf Hansson 	iod->soc_data = match->data;
631e943c43bSUlf Hansson 
63228b05a64SJianqun Xu 	if (iod->soc_data->write)
63328b05a64SJianqun Xu 		iod->write = iod->soc_data->write;
63428b05a64SJianqun Xu 	else
63528b05a64SJianqun Xu 		iod->write = rockchip_iodomain_write;
63628b05a64SJianqun Xu 
637e943c43bSUlf Hansson 	parent = pdev->dev.parent;
638e943c43bSUlf Hansson 	if (parent && parent->of_node) {
639e943c43bSUlf Hansson 		iod->grf = syscon_node_to_regmap(parent->of_node);
640e943c43bSUlf Hansson 	} else {
641e943c43bSUlf Hansson 		dev_dbg(&pdev->dev, "falling back to old binding\n");
642e943c43bSUlf Hansson 		iod->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
643e943c43bSUlf Hansson 	}
644e943c43bSUlf Hansson 
645e943c43bSUlf Hansson 	if (IS_ERR(iod->grf)) {
646e943c43bSUlf Hansson 		dev_err(&pdev->dev, "couldn't find grf regmap\n");
647e943c43bSUlf Hansson 		return PTR_ERR(iod->grf);
648e943c43bSUlf Hansson 	}
649e943c43bSUlf Hansson 
650e943c43bSUlf Hansson 	for (i = 0; i < MAX_SUPPLIES; i++) {
651e943c43bSUlf Hansson 		const char *supply_name = iod->soc_data->supply_names[i];
652e943c43bSUlf Hansson 		struct rockchip_iodomain_supply *supply = &iod->supplies[i];
653e943c43bSUlf Hansson 		struct regulator *reg;
654e943c43bSUlf Hansson 		int uV;
655e943c43bSUlf Hansson 
656e943c43bSUlf Hansson 		if (!supply_name)
657e943c43bSUlf Hansson 			continue;
658e943c43bSUlf Hansson 
659e943c43bSUlf Hansson 		reg = devm_regulator_get_optional(iod->dev, supply_name);
660e943c43bSUlf Hansson 		if (IS_ERR(reg)) {
661e943c43bSUlf Hansson 			ret = PTR_ERR(reg);
662e943c43bSUlf Hansson 
663e943c43bSUlf Hansson 			/* If a supply wasn't specified, that's OK */
664e943c43bSUlf Hansson 			if (ret == -ENODEV)
665e943c43bSUlf Hansson 				continue;
666e943c43bSUlf Hansson 			else if (ret != -EPROBE_DEFER)
667e943c43bSUlf Hansson 				dev_err(iod->dev, "couldn't get regulator %s\n",
668e943c43bSUlf Hansson 					supply_name);
669e943c43bSUlf Hansson 			goto unreg_notify;
670e943c43bSUlf Hansson 		}
671e943c43bSUlf Hansson 
672e943c43bSUlf Hansson 		/* set initial correct value */
673e943c43bSUlf Hansson 		uV = regulator_get_voltage(reg);
674e943c43bSUlf Hansson 
675e943c43bSUlf Hansson 		/* must be a regulator we can get the voltage of */
676e943c43bSUlf Hansson 		if (uV < 0) {
677e943c43bSUlf Hansson 			dev_err(iod->dev, "Can't determine voltage: %s\n",
678e943c43bSUlf Hansson 				supply_name);
679c2867b2eSZhang Changzhong 			ret = uV;
680e943c43bSUlf Hansson 			goto unreg_notify;
681e943c43bSUlf Hansson 		}
682e943c43bSUlf Hansson 
683e943c43bSUlf Hansson 		if (uV > MAX_VOLTAGE_3_3) {
684e943c43bSUlf Hansson 			dev_crit(iod->dev,
685e943c43bSUlf Hansson 				 "%d uV is too high. May damage SoC!\n",
686e943c43bSUlf Hansson 				 uV);
687e943c43bSUlf Hansson 			ret = -EINVAL;
688e943c43bSUlf Hansson 			goto unreg_notify;
689e943c43bSUlf Hansson 		}
690e943c43bSUlf Hansson 
691e943c43bSUlf Hansson 		/* setup our supply */
692e943c43bSUlf Hansson 		supply->idx = i;
693e943c43bSUlf Hansson 		supply->iod = iod;
694e943c43bSUlf Hansson 		supply->reg = reg;
695e943c43bSUlf Hansson 		supply->nb.notifier_call = rockchip_iodomain_notify;
696e943c43bSUlf Hansson 
69728b05a64SJianqun Xu 		ret = iod->write(supply, uV);
698e943c43bSUlf Hansson 		if (ret) {
699e943c43bSUlf Hansson 			supply->reg = NULL;
700e943c43bSUlf Hansson 			goto unreg_notify;
701e943c43bSUlf Hansson 		}
702e943c43bSUlf Hansson 
703e943c43bSUlf Hansson 		/* register regulator notifier */
704e943c43bSUlf Hansson 		ret = regulator_register_notifier(reg, &supply->nb);
705e943c43bSUlf Hansson 		if (ret) {
706e943c43bSUlf Hansson 			dev_err(&pdev->dev,
707e943c43bSUlf Hansson 				"regulator notifier request failed\n");
708e943c43bSUlf Hansson 			supply->reg = NULL;
709e943c43bSUlf Hansson 			goto unreg_notify;
710e943c43bSUlf Hansson 		}
711e943c43bSUlf Hansson 	}
712e943c43bSUlf Hansson 
713e943c43bSUlf Hansson 	if (iod->soc_data->init)
714e943c43bSUlf Hansson 		iod->soc_data->init(iod);
715e943c43bSUlf Hansson 
716e943c43bSUlf Hansson 	return 0;
717e943c43bSUlf Hansson 
718e943c43bSUlf Hansson unreg_notify:
719e943c43bSUlf Hansson 	for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
720e943c43bSUlf Hansson 		struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
721e943c43bSUlf Hansson 
722e943c43bSUlf Hansson 		if (io_supply->reg)
723e943c43bSUlf Hansson 			regulator_unregister_notifier(io_supply->reg,
724e943c43bSUlf Hansson 						      &io_supply->nb);
725e943c43bSUlf Hansson 	}
726e943c43bSUlf Hansson 
727e943c43bSUlf Hansson 	return ret;
728e943c43bSUlf Hansson }
729e943c43bSUlf Hansson 
rockchip_iodomain_remove(struct platform_device * pdev)73020bd1191SUwe Kleine-König static void rockchip_iodomain_remove(struct platform_device *pdev)
731e943c43bSUlf Hansson {
732e943c43bSUlf Hansson 	struct rockchip_iodomain *iod = platform_get_drvdata(pdev);
733e943c43bSUlf Hansson 	int i;
734e943c43bSUlf Hansson 
735e943c43bSUlf Hansson 	for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
736e943c43bSUlf Hansson 		struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
737e943c43bSUlf Hansson 
738e943c43bSUlf Hansson 		if (io_supply->reg)
739e943c43bSUlf Hansson 			regulator_unregister_notifier(io_supply->reg,
740e943c43bSUlf Hansson 						      &io_supply->nb);
741e943c43bSUlf Hansson 	}
742e943c43bSUlf Hansson }
743e943c43bSUlf Hansson 
744e943c43bSUlf Hansson static struct platform_driver rockchip_iodomain_driver = {
745e943c43bSUlf Hansson 	.probe   = rockchip_iodomain_probe,
74620bd1191SUwe Kleine-König 	.remove_new = rockchip_iodomain_remove,
747e943c43bSUlf Hansson 	.driver  = {
748e943c43bSUlf Hansson 		.name  = "rockchip-iodomain",
749e943c43bSUlf Hansson 		.of_match_table = rockchip_iodomain_match,
750e943c43bSUlf Hansson 	},
751e943c43bSUlf Hansson };
752e943c43bSUlf Hansson 
753e943c43bSUlf Hansson module_platform_driver(rockchip_iodomain_driver);
754e943c43bSUlf Hansson 
755e943c43bSUlf Hansson MODULE_DESCRIPTION("Rockchip IO-domain driver");
756e943c43bSUlf Hansson MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
757e943c43bSUlf Hansson MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>");
758e943c43bSUlf Hansson MODULE_LICENSE("GPL v2");
759