xref: /openbmc/linux/drivers/soc/rockchip/io-domain.c (revision f05643a0)
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 
58 struct rockchip_iodomain;
59 
60 struct rockchip_iodomain_supply {
61 	struct rockchip_iodomain *iod;
62 	struct regulator *reg;
63 	struct notifier_block nb;
64 	int idx;
65 };
66 
67 struct 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 
74 struct 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 
82 static 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 
123 static 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 
144 static 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 
194 static 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 
213 static 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 
232 static 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 
251 static 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 
270 static 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 
289 static 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 
304 static 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  */
330 static 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 
352 static 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 
362 static 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 
379 static 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 
393 static 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 
409 static 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 
421 static 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 
431 static 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 
448 static 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 
464 static 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 
487 static const struct rockchip_iodomain_soc_data soc_data_rv1108_pmu = {
488 	.grf_offset = 0x104,
489 	.supply_names = {
490 		"pmu",
491 	},
492 };
493 
494 static 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 };
549 MODULE_DEVICE_TABLE(of, rockchip_iodomain_match);
550 
551 static 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 
658 unreg_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 
670 static 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 
686 static 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 
695 module_platform_driver(rockchip_iodomain_driver);
696 
697 MODULE_DESCRIPTION("Rockchip IO-domain driver");
698 MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
699 MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>");
700 MODULE_LICENSE("GPL v2");
701