1 /*
2  * Freescale eSDHC i.MX controller driver for the platform bus.
3  *
4  * derived from the OF-version.
5  *
6  * Copyright (c) 2010 Pengutronix e.K.
7  *   Author: Wolfram Sang <w.sang@pengutronix.de>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License.
12  */
13 
14 #include <linux/io.h>
15 #include <linux/delay.h>
16 #include <linux/err.h>
17 #include <linux/clk.h>
18 #include <linux/gpio.h>
19 #include <linux/module.h>
20 #include <linux/slab.h>
21 #include <linux/mmc/host.h>
22 #include <linux/mmc/mmc.h>
23 #include <linux/mmc/sdio.h>
24 #include <linux/mmc/slot-gpio.h>
25 #include <linux/of.h>
26 #include <linux/of_device.h>
27 #include <linux/of_gpio.h>
28 #include <linux/pinctrl/consumer.h>
29 #include <linux/platform_data/mmc-esdhc-imx.h>
30 #include "sdhci-pltfm.h"
31 #include "sdhci-esdhc.h"
32 
33 #define	ESDHC_CTRL_D3CD			0x08
34 /* VENDOR SPEC register */
35 #define ESDHC_VENDOR_SPEC		0xc0
36 #define  ESDHC_VENDOR_SPEC_SDIO_QUIRK	(1 << 1)
37 #define ESDHC_WTMK_LVL			0x44
38 #define ESDHC_MIX_CTRL			0x48
39 
40 /*
41  * There is an INT DMA ERR mis-match between eSDHC and STD SDHC SPEC:
42  * Bit25 is used in STD SPEC, and is reserved in fsl eSDHC design,
43  * but bit28 is used as the INT DMA ERR in fsl eSDHC design.
44  * Define this macro DMA error INT for fsl eSDHC
45  */
46 #define ESDHC_INT_VENDOR_SPEC_DMA_ERR	(1 << 28)
47 
48 /*
49  * The CMDTYPE of the CMD register (offset 0xE) should be set to
50  * "11" when the STOP CMD12 is issued on imx53 to abort one
51  * open ended multi-blk IO. Otherwise the TC INT wouldn't
52  * be generated.
53  * In exact block transfer, the controller doesn't complete the
54  * operations automatically as required at the end of the
55  * transfer and remains on hold if the abort command is not sent.
56  * As a result, the TC flag is not asserted and SW  received timeout
57  * exeception. Bit1 of Vendor Spec registor is used to fix it.
58  */
59 #define ESDHC_FLAG_MULTIBLK_NO_INT	(1 << 1)
60 
61 enum imx_esdhc_type {
62 	IMX25_ESDHC,
63 	IMX35_ESDHC,
64 	IMX51_ESDHC,
65 	IMX53_ESDHC,
66 	IMX6Q_USDHC,
67 };
68 
69 struct pltfm_imx_data {
70 	int flags;
71 	u32 scratchpad;
72 	enum imx_esdhc_type devtype;
73 	struct pinctrl *pinctrl;
74 	struct esdhc_platform_data boarddata;
75 	struct clk *clk_ipg;
76 	struct clk *clk_ahb;
77 	struct clk *clk_per;
78 };
79 
80 static struct platform_device_id imx_esdhc_devtype[] = {
81 	{
82 		.name = "sdhci-esdhc-imx25",
83 		.driver_data = IMX25_ESDHC,
84 	}, {
85 		.name = "sdhci-esdhc-imx35",
86 		.driver_data = IMX35_ESDHC,
87 	}, {
88 		.name = "sdhci-esdhc-imx51",
89 		.driver_data = IMX51_ESDHC,
90 	}, {
91 		.name = "sdhci-esdhc-imx53",
92 		.driver_data = IMX53_ESDHC,
93 	}, {
94 		.name = "sdhci-usdhc-imx6q",
95 		.driver_data = IMX6Q_USDHC,
96 	}, {
97 		/* sentinel */
98 	}
99 };
100 MODULE_DEVICE_TABLE(platform, imx_esdhc_devtype);
101 
102 static const struct of_device_id imx_esdhc_dt_ids[] = {
103 	{ .compatible = "fsl,imx25-esdhc", .data = &imx_esdhc_devtype[IMX25_ESDHC], },
104 	{ .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], },
105 	{ .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], },
106 	{ .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], },
107 	{ .compatible = "fsl,imx6q-usdhc", .data = &imx_esdhc_devtype[IMX6Q_USDHC], },
108 	{ /* sentinel */ }
109 };
110 MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
111 
112 static inline int is_imx25_esdhc(struct pltfm_imx_data *data)
113 {
114 	return data->devtype == IMX25_ESDHC;
115 }
116 
117 static inline int is_imx35_esdhc(struct pltfm_imx_data *data)
118 {
119 	return data->devtype == IMX35_ESDHC;
120 }
121 
122 static inline int is_imx51_esdhc(struct pltfm_imx_data *data)
123 {
124 	return data->devtype == IMX51_ESDHC;
125 }
126 
127 static inline int is_imx53_esdhc(struct pltfm_imx_data *data)
128 {
129 	return data->devtype == IMX53_ESDHC;
130 }
131 
132 static inline int is_imx6q_usdhc(struct pltfm_imx_data *data)
133 {
134 	return data->devtype == IMX6Q_USDHC;
135 }
136 
137 static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
138 {
139 	void __iomem *base = host->ioaddr + (reg & ~0x3);
140 	u32 shift = (reg & 0x3) * 8;
141 
142 	writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
143 }
144 
145 static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
146 {
147 	u32 val = readl(host->ioaddr + reg);
148 
149 	if (unlikely(reg == SDHCI_CAPABILITIES)) {
150 		/* In FSL esdhc IC module, only bit20 is used to indicate the
151 		 * ADMA2 capability of esdhc, but this bit is messed up on
152 		 * some SOCs (e.g. on MX25, MX35 this bit is set, but they
153 		 * don't actually support ADMA2). So set the BROKEN_ADMA
154 		 * uirk on MX25/35 platforms.
155 		 */
156 
157 		if (val & SDHCI_CAN_DO_ADMA1) {
158 			val &= ~SDHCI_CAN_DO_ADMA1;
159 			val |= SDHCI_CAN_DO_ADMA2;
160 		}
161 	}
162 
163 	if (unlikely(reg == SDHCI_INT_STATUS)) {
164 		if (val & ESDHC_INT_VENDOR_SPEC_DMA_ERR) {
165 			val &= ~ESDHC_INT_VENDOR_SPEC_DMA_ERR;
166 			val |= SDHCI_INT_ADMA_ERROR;
167 		}
168 	}
169 
170 	return val;
171 }
172 
173 static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
174 {
175 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
176 	struct pltfm_imx_data *imx_data = pltfm_host->priv;
177 	u32 data;
178 
179 	if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) {
180 		if (val & SDHCI_INT_CARD_INT) {
181 			/*
182 			 * Clear and then set D3CD bit to avoid missing the
183 			 * card interrupt.  This is a eSDHC controller problem
184 			 * so we need to apply the following workaround: clear
185 			 * and set D3CD bit will make eSDHC re-sample the card
186 			 * interrupt. In case a card interrupt was lost,
187 			 * re-sample it by the following steps.
188 			 */
189 			data = readl(host->ioaddr + SDHCI_HOST_CONTROL);
190 			data &= ~ESDHC_CTRL_D3CD;
191 			writel(data, host->ioaddr + SDHCI_HOST_CONTROL);
192 			data |= ESDHC_CTRL_D3CD;
193 			writel(data, host->ioaddr + SDHCI_HOST_CONTROL);
194 		}
195 	}
196 
197 	if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
198 				&& (reg == SDHCI_INT_STATUS)
199 				&& (val & SDHCI_INT_DATA_END))) {
200 			u32 v;
201 			v = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
202 			v &= ~ESDHC_VENDOR_SPEC_SDIO_QUIRK;
203 			writel(v, host->ioaddr + ESDHC_VENDOR_SPEC);
204 	}
205 
206 	if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) {
207 		if (val & SDHCI_INT_ADMA_ERROR) {
208 			val &= ~SDHCI_INT_ADMA_ERROR;
209 			val |= ESDHC_INT_VENDOR_SPEC_DMA_ERR;
210 		}
211 	}
212 
213 	writel(val, host->ioaddr + reg);
214 }
215 
216 static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
217 {
218 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
219 	struct pltfm_imx_data *imx_data = pltfm_host->priv;
220 
221 	if (unlikely(reg == SDHCI_HOST_VERSION)) {
222 		reg ^= 2;
223 		if (is_imx6q_usdhc(imx_data)) {
224 			/*
225 			 * The usdhc register returns a wrong host version.
226 			 * Correct it here.
227 			 */
228 			return SDHCI_SPEC_300;
229 		}
230 	}
231 
232 	return readw(host->ioaddr + reg);
233 }
234 
235 static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
236 {
237 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
238 	struct pltfm_imx_data *imx_data = pltfm_host->priv;
239 
240 	switch (reg) {
241 	case SDHCI_TRANSFER_MODE:
242 		if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
243 				&& (host->cmd->opcode == SD_IO_RW_EXTENDED)
244 				&& (host->cmd->data->blocks > 1)
245 				&& (host->cmd->data->flags & MMC_DATA_READ)) {
246 			u32 v;
247 			v = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
248 			v |= ESDHC_VENDOR_SPEC_SDIO_QUIRK;
249 			writel(v, host->ioaddr + ESDHC_VENDOR_SPEC);
250 		}
251 
252 		if (is_imx6q_usdhc(imx_data)) {
253 			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
254 			m = val | (m & 0xffff0000);
255 			writel(m, host->ioaddr + ESDHC_MIX_CTRL);
256 		} else {
257 			/*
258 			 * Postpone this write, we must do it together with a
259 			 * command write that is down below.
260 			 */
261 			imx_data->scratchpad = val;
262 		}
263 		return;
264 	case SDHCI_COMMAND:
265 		if ((host->cmd->opcode == MMC_STOP_TRANSMISSION ||
266 		     host->cmd->opcode == MMC_SET_BLOCK_COUNT) &&
267 	            (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
268 			val |= SDHCI_CMD_ABORTCMD;
269 
270 		if (is_imx6q_usdhc(imx_data))
271 			writel(val << 16,
272 			       host->ioaddr + SDHCI_TRANSFER_MODE);
273 		else
274 			writel(val << 16 | imx_data->scratchpad,
275 			       host->ioaddr + SDHCI_TRANSFER_MODE);
276 		return;
277 	case SDHCI_BLOCK_SIZE:
278 		val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
279 		break;
280 	}
281 	esdhc_clrset_le(host, 0xffff, val, reg);
282 }
283 
284 static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
285 {
286 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
287 	struct pltfm_imx_data *imx_data = pltfm_host->priv;
288 	u32 new_val;
289 
290 	switch (reg) {
291 	case SDHCI_POWER_CONTROL:
292 		/*
293 		 * FSL put some DMA bits here
294 		 * If your board has a regulator, code should be here
295 		 */
296 		return;
297 	case SDHCI_HOST_CONTROL:
298 		/* FSL messed up here, so we need to manually compose it. */
299 		new_val = val & (SDHCI_CTRL_LED | SDHCI_CTRL_4BITBUS);
300 		/* ensure the endianness */
301 		new_val |= ESDHC_HOST_CONTROL_LE;
302 		/* bits 8&9 are reserved on mx25 */
303 		if (!is_imx25_esdhc(imx_data)) {
304 			/* DMA mode bits are shifted */
305 			new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5;
306 		}
307 
308 		esdhc_clrset_le(host, 0xffff, new_val, reg);
309 		return;
310 	}
311 	esdhc_clrset_le(host, 0xff, val, reg);
312 
313 	/*
314 	 * The esdhc has a design violation to SDHC spec which tells
315 	 * that software reset should not affect card detection circuit.
316 	 * But esdhc clears its SYSCTL register bits [0..2] during the
317 	 * software reset.  This will stop those clocks that card detection
318 	 * circuit relies on.  To work around it, we turn the clocks on back
319 	 * to keep card detection circuit functional.
320 	 */
321 	if ((reg == SDHCI_SOFTWARE_RESET) && (val & 1))
322 		esdhc_clrset_le(host, 0x7, 0x7, ESDHC_SYSTEM_CONTROL);
323 }
324 
325 static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host)
326 {
327 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
328 
329 	return clk_get_rate(pltfm_host->clk);
330 }
331 
332 static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
333 {
334 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
335 
336 	return clk_get_rate(pltfm_host->clk) / 256 / 16;
337 }
338 
339 static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
340 {
341 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
342 	struct pltfm_imx_data *imx_data = pltfm_host->priv;
343 	struct esdhc_platform_data *boarddata = &imx_data->boarddata;
344 
345 	switch (boarddata->wp_type) {
346 	case ESDHC_WP_GPIO:
347 		return mmc_gpio_get_ro(host->mmc);
348 	case ESDHC_WP_CONTROLLER:
349 		return !(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
350 			       SDHCI_WRITE_PROTECT);
351 	case ESDHC_WP_NONE:
352 		break;
353 	}
354 
355 	return -ENOSYS;
356 }
357 
358 static struct sdhci_ops sdhci_esdhc_ops = {
359 	.read_l = esdhc_readl_le,
360 	.read_w = esdhc_readw_le,
361 	.write_l = esdhc_writel_le,
362 	.write_w = esdhc_writew_le,
363 	.write_b = esdhc_writeb_le,
364 	.set_clock = esdhc_set_clock,
365 	.get_max_clock = esdhc_pltfm_get_max_clock,
366 	.get_min_clock = esdhc_pltfm_get_min_clock,
367 	.get_ro = esdhc_pltfm_get_ro,
368 };
369 
370 static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
371 	.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_HISPD_BIT
372 			| SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
373 			| SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC
374 			| SDHCI_QUIRK_BROKEN_CARD_DETECTION,
375 	.ops = &sdhci_esdhc_ops,
376 };
377 
378 #ifdef CONFIG_OF
379 static int
380 sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
381 			 struct esdhc_platform_data *boarddata)
382 {
383 	struct device_node *np = pdev->dev.of_node;
384 
385 	if (!np)
386 		return -ENODEV;
387 
388 	if (of_get_property(np, "non-removable", NULL))
389 		boarddata->cd_type = ESDHC_CD_PERMANENT;
390 
391 	if (of_get_property(np, "fsl,cd-controller", NULL))
392 		boarddata->cd_type = ESDHC_CD_CONTROLLER;
393 
394 	if (of_get_property(np, "fsl,wp-controller", NULL))
395 		boarddata->wp_type = ESDHC_WP_CONTROLLER;
396 
397 	boarddata->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
398 	if (gpio_is_valid(boarddata->cd_gpio))
399 		boarddata->cd_type = ESDHC_CD_GPIO;
400 
401 	boarddata->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
402 	if (gpio_is_valid(boarddata->wp_gpio))
403 		boarddata->wp_type = ESDHC_WP_GPIO;
404 
405 	return 0;
406 }
407 #else
408 static inline int
409 sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
410 			 struct esdhc_platform_data *boarddata)
411 {
412 	return -ENODEV;
413 }
414 #endif
415 
416 static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
417 {
418 	const struct of_device_id *of_id =
419 			of_match_device(imx_esdhc_dt_ids, &pdev->dev);
420 	struct sdhci_pltfm_host *pltfm_host;
421 	struct sdhci_host *host;
422 	struct esdhc_platform_data *boarddata;
423 	int err;
424 	struct pltfm_imx_data *imx_data;
425 
426 	host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata);
427 	if (IS_ERR(host))
428 		return PTR_ERR(host);
429 
430 	pltfm_host = sdhci_priv(host);
431 
432 	imx_data = devm_kzalloc(&pdev->dev, sizeof(*imx_data), GFP_KERNEL);
433 	if (!imx_data) {
434 		err = -ENOMEM;
435 		goto free_sdhci;
436 	}
437 
438 	if (of_id)
439 		pdev->id_entry = of_id->data;
440 	imx_data->devtype = pdev->id_entry->driver_data;
441 	pltfm_host->priv = imx_data;
442 
443 	imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
444 	if (IS_ERR(imx_data->clk_ipg)) {
445 		err = PTR_ERR(imx_data->clk_ipg);
446 		goto free_sdhci;
447 	}
448 
449 	imx_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
450 	if (IS_ERR(imx_data->clk_ahb)) {
451 		err = PTR_ERR(imx_data->clk_ahb);
452 		goto free_sdhci;
453 	}
454 
455 	imx_data->clk_per = devm_clk_get(&pdev->dev, "per");
456 	if (IS_ERR(imx_data->clk_per)) {
457 		err = PTR_ERR(imx_data->clk_per);
458 		goto free_sdhci;
459 	}
460 
461 	pltfm_host->clk = imx_data->clk_per;
462 
463 	clk_prepare_enable(imx_data->clk_per);
464 	clk_prepare_enable(imx_data->clk_ipg);
465 	clk_prepare_enable(imx_data->clk_ahb);
466 
467 	imx_data->pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
468 	if (IS_ERR(imx_data->pinctrl)) {
469 		err = PTR_ERR(imx_data->pinctrl);
470 		goto disable_clk;
471 	}
472 
473 	host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
474 
475 	if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data))
476 		/* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
477 		host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK
478 			| SDHCI_QUIRK_BROKEN_ADMA;
479 
480 	if (is_imx53_esdhc(imx_data))
481 		imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT;
482 
483 	/*
484 	 * The imx6q ROM code will change the default watermark level setting
485 	 * to something insane.  Change it back here.
486 	 */
487 	if (is_imx6q_usdhc(imx_data))
488 		writel(0x08100810, host->ioaddr + ESDHC_WTMK_LVL);
489 
490 	boarddata = &imx_data->boarddata;
491 	if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) {
492 		if (!host->mmc->parent->platform_data) {
493 			dev_err(mmc_dev(host->mmc), "no board data!\n");
494 			err = -EINVAL;
495 			goto disable_clk;
496 		}
497 		imx_data->boarddata = *((struct esdhc_platform_data *)
498 					host->mmc->parent->platform_data);
499 	}
500 
501 	/* write_protect */
502 	if (boarddata->wp_type == ESDHC_WP_GPIO) {
503 		err = mmc_gpio_request_ro(host->mmc, boarddata->wp_gpio);
504 		if (err) {
505 			dev_err(mmc_dev(host->mmc),
506 				"failed to request write-protect gpio!\n");
507 			goto disable_clk;
508 		}
509 		host->mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
510 	}
511 
512 	/* card_detect */
513 	switch (boarddata->cd_type) {
514 	case ESDHC_CD_GPIO:
515 		err = mmc_gpio_request_cd(host->mmc, boarddata->cd_gpio);
516 		if (err) {
517 			dev_err(mmc_dev(host->mmc),
518 				"failed to request card-detect gpio!\n");
519 			goto disable_clk;
520 		}
521 		/* fall through */
522 
523 	case ESDHC_CD_CONTROLLER:
524 		/* we have a working card_detect back */
525 		host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
526 		break;
527 
528 	case ESDHC_CD_PERMANENT:
529 		host->mmc->caps = MMC_CAP_NONREMOVABLE;
530 		break;
531 
532 	case ESDHC_CD_NONE:
533 		break;
534 	}
535 
536 	err = sdhci_add_host(host);
537 	if (err)
538 		goto disable_clk;
539 
540 	return 0;
541 
542 disable_clk:
543 	clk_disable_unprepare(imx_data->clk_per);
544 	clk_disable_unprepare(imx_data->clk_ipg);
545 	clk_disable_unprepare(imx_data->clk_ahb);
546 free_sdhci:
547 	sdhci_pltfm_free(pdev);
548 	return err;
549 }
550 
551 static int sdhci_esdhc_imx_remove(struct platform_device *pdev)
552 {
553 	struct sdhci_host *host = platform_get_drvdata(pdev);
554 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
555 	struct pltfm_imx_data *imx_data = pltfm_host->priv;
556 	int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
557 
558 	sdhci_remove_host(host, dead);
559 
560 	clk_disable_unprepare(imx_data->clk_per);
561 	clk_disable_unprepare(imx_data->clk_ipg);
562 	clk_disable_unprepare(imx_data->clk_ahb);
563 
564 	sdhci_pltfm_free(pdev);
565 
566 	return 0;
567 }
568 
569 static struct platform_driver sdhci_esdhc_imx_driver = {
570 	.driver		= {
571 		.name	= "sdhci-esdhc-imx",
572 		.owner	= THIS_MODULE,
573 		.of_match_table = imx_esdhc_dt_ids,
574 		.pm	= SDHCI_PLTFM_PMOPS,
575 	},
576 	.id_table	= imx_esdhc_devtype,
577 	.probe		= sdhci_esdhc_imx_probe,
578 	.remove		= sdhci_esdhc_imx_remove,
579 };
580 
581 module_platform_driver(sdhci_esdhc_imx_driver);
582 
583 MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC");
584 MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
585 MODULE_LICENSE("GPL v2");
586