sdhci-esdhc-imx.c 14.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Freescale eSDHC i.MX controller driver for the platform bus.
 *
 * derived from the OF-version.
 *
 * Copyright (c) 2010 Pengutronix e.K.
 *   Author: Wolfram Sang <w.sang@pengutronix.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License.
 */

#include <linux/io.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/clk.h>
18
#include <linux/gpio.h>
19
#include <linux/slab.h>
20
#include <linux/mmc/host.h>
21 22
#include <linux/mmc/mmc.h>
#include <linux/mmc/sdio.h>
23 24 25
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
26
#include <mach/esdhc.h>
27 28 29
#include "sdhci-pltfm.h"
#include "sdhci-esdhc.h"

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
/* VENDOR SPEC register */
#define SDHCI_VENDOR_SPEC		0xC0
#define  SDHCI_VENDOR_SPEC_SDIO_QUIRK	0x00000002

/*
 * The CMDTYPE of the CMD register (offset 0xE) should be set to
 * "11" when the STOP CMD12 is issued on imx53 to abort one
 * open ended multi-blk IO. Otherwise the TC INT wouldn't
 * be generated.
 * In exact block transfer, the controller doesn't complete the
 * operations automatically as required at the end of the
 * transfer and remains on hold if the abort command is not sent.
 * As a result, the TC flag is not asserted and SW  received timeout
 * exeception. Bit1 of Vendor Spec registor is used to fix it.
 */
#define ESDHC_FLAG_MULTIBLK_NO_INT	(1 << 1)
46

47 48 49 50 51 52 53
enum imx_esdhc_type {
	IMX25_ESDHC,
	IMX35_ESDHC,
	IMX51_ESDHC,
	IMX53_ESDHC,
};

54 55 56
struct pltfm_imx_data {
	int flags;
	u32 scratchpad;
57
	enum imx_esdhc_type devtype;
58
	struct esdhc_platform_data boarddata;
59 60
};

61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
static struct platform_device_id imx_esdhc_devtype[] = {
	{
		.name = "sdhci-esdhc-imx25",
		.driver_data = IMX25_ESDHC,
	}, {
		.name = "sdhci-esdhc-imx35",
		.driver_data = IMX35_ESDHC,
	}, {
		.name = "sdhci-esdhc-imx51",
		.driver_data = IMX51_ESDHC,
	}, {
		.name = "sdhci-esdhc-imx53",
		.driver_data = IMX53_ESDHC,
	}, {
		/* sentinel */
	}
};
MODULE_DEVICE_TABLE(platform, imx_esdhc_devtype);

80 81 82 83 84 85 86 87 88
static const struct of_device_id imx_esdhc_dt_ids[] = {
	{ .compatible = "fsl,imx25-esdhc", .data = &imx_esdhc_devtype[IMX25_ESDHC], },
	{ .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], },
	{ .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], },
	{ .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
static inline int is_imx25_esdhc(struct pltfm_imx_data *data)
{
	return data->devtype == IMX25_ESDHC;
}

static inline int is_imx35_esdhc(struct pltfm_imx_data *data)
{
	return data->devtype == IMX35_ESDHC;
}

static inline int is_imx51_esdhc(struct pltfm_imx_data *data)
{
	return data->devtype == IMX51_ESDHC;
}

static inline int is_imx53_esdhc(struct pltfm_imx_data *data)
{
	return data->devtype == IMX53_ESDHC;
}

109 110 111 112 113 114 115 116
static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
{
	void __iomem *base = host->ioaddr + (reg & ~0x3);
	u32 shift = (reg & 0x3) * 8;

	writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
}

117 118
static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
{
119 120 121
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct pltfm_imx_data *imx_data = pltfm_host->priv;
	struct esdhc_platform_data *boarddata = &imx_data->boarddata;
122

123
	/* fake CARD_PRESENT flag */
124 125
	u32 val = readl(host->ioaddr + reg);

126
	if (unlikely((reg == SDHCI_PRESENT_STATE)
127 128
			&& gpio_is_valid(boarddata->cd_gpio))) {
		if (gpio_get_value(boarddata->cd_gpio))
129
			/* no card, if a valid gpio says so... */
130
			val &= ~SDHCI_CARD_PRESENT;
131 132 133 134 135 136 137 138 139 140
		else
			/* ... in all other cases assume card is present */
			val |= SDHCI_CARD_PRESENT;
	}

	return val;
}

static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
{
141 142
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct pltfm_imx_data *imx_data = pltfm_host->priv;
143
	struct esdhc_platform_data *boarddata = &imx_data->boarddata;
144 145

	if (unlikely((reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)
146
			&& (boarddata->cd_type == ESDHC_CD_GPIO)))
147 148 149 150 151
		/*
		 * these interrupts won't work with a custom card_detect gpio
		 */
		val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);

152 153 154 155 156 157 158 159 160
	if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
				&& (reg == SDHCI_INT_STATUS)
				&& (val & SDHCI_INT_DATA_END))) {
			u32 v;
			v = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
			v &= ~SDHCI_VENDOR_SPEC_SDIO_QUIRK;
			writel(v, host->ioaddr + SDHCI_VENDOR_SPEC);
	}

161 162 163
	writel(val, host->ioaddr + reg);
}

164 165 166 167 168 169 170 171 172 173 174
static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
{
	if (unlikely(reg == SDHCI_HOST_VERSION))
		reg ^= 2;

	return readw(host->ioaddr + reg);
}

static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
{
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
175
	struct pltfm_imx_data *imx_data = pltfm_host->priv;
176 177 178 179 180 181 182

	switch (reg) {
	case SDHCI_TRANSFER_MODE:
		/*
		 * Postpone this write, we must do it together with a
		 * command write that is down below.
		 */
183 184 185 186 187 188 189 190 191
		if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
				&& (host->cmd->opcode == SD_IO_RW_EXTENDED)
				&& (host->cmd->data->blocks > 1)
				&& (host->cmd->data->flags & MMC_DATA_READ)) {
			u32 v;
			v = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
			v |= SDHCI_VENDOR_SPEC_SDIO_QUIRK;
			writel(v, host->ioaddr + SDHCI_VENDOR_SPEC);
		}
192
		imx_data->scratchpad = val;
193 194
		return;
	case SDHCI_COMMAND:
195 196 197
		if ((host->cmd->opcode == MMC_STOP_TRANSMISSION)
			&& (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
			val |= SDHCI_CMD_ABORTCMD;
198
		writel(val << 16 | imx_data->scratchpad,
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
			host->ioaddr + SDHCI_TRANSFER_MODE);
		return;
	case SDHCI_BLOCK_SIZE:
		val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
		break;
	}
	esdhc_clrset_le(host, 0xffff, val, reg);
}

static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
{
	u32 new_val;

	switch (reg) {
	case SDHCI_POWER_CONTROL:
		/*
		 * FSL put some DMA bits here
		 * If your board has a regulator, code should be here
		 */
		return;
	case SDHCI_HOST_CONTROL:
		/* FSL messed up here, so we can just keep those two */
		new_val = val & (SDHCI_CTRL_LED | SDHCI_CTRL_4BITBUS);
		/* ensure the endianess */
		new_val |= ESDHC_HOST_CONTROL_LE;
		/* DMA mode bits are shifted */
		new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5;

		esdhc_clrset_le(host, 0xffff, new_val, reg);
		return;
	}
	esdhc_clrset_le(host, 0xff, val, reg);
231 232 233 234 235 236 237 238 239 240 241

	/*
	 * The esdhc has a design violation to SDHC spec which tells
	 * that software reset should not affect card detection circuit.
	 * But esdhc clears its SYSCTL register bits [0..2] during the
	 * software reset.  This will stop those clocks that card detection
	 * circuit relies on.  To work around it, we turn the clocks on back
	 * to keep card detection circuit functional.
	 */
	if ((reg == SDHCI_SOFTWARE_RESET) && (val & 1))
		esdhc_clrset_le(host, 0x7, 0x7, ESDHC_SYSTEM_CONTROL);
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
}

static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host)
{
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);

	return clk_get_rate(pltfm_host->clk);
}

static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
{
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);

	return clk_get_rate(pltfm_host->clk) / 256 / 16;
}

258 259
static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
{
260 261 262
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct pltfm_imx_data *imx_data = pltfm_host->priv;
	struct esdhc_platform_data *boarddata = &imx_data->boarddata;
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277

	switch (boarddata->wp_type) {
	case ESDHC_WP_GPIO:
		if (gpio_is_valid(boarddata->wp_gpio))
			return gpio_get_value(boarddata->wp_gpio);
	case ESDHC_WP_CONTROLLER:
		return !(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
			       SDHCI_WRITE_PROTECT);
	case ESDHC_WP_NONE:
		break;
	}

	return -ENOSYS;
}

278
static struct sdhci_ops sdhci_esdhc_ops = {
279
	.read_l = esdhc_readl_le,
280
	.read_w = esdhc_readw_le,
281
	.write_l = esdhc_writel_le,
282 283 284 285 286
	.write_w = esdhc_writew_le,
	.write_b = esdhc_writeb_le,
	.set_clock = esdhc_set_clock,
	.get_max_clock = esdhc_pltfm_get_max_clock,
	.get_min_clock = esdhc_pltfm_get_min_clock,
287
	.get_ro = esdhc_pltfm_get_ro,
288 289
};

290 291 292 293 294 295 296
static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
	.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA
			| SDHCI_QUIRK_BROKEN_CARD_DETECTION,
	/* ADMA has issues. Might be fixable */
	.ops = &sdhci_esdhc_ops,
};

297 298 299 300 301 302 303 304
static irqreturn_t cd_irq(int irq, void *data)
{
	struct sdhci_host *sdhost = (struct sdhci_host *)data;

	tasklet_schedule(&sdhost->card_tasklet);
	return IRQ_HANDLED;
};

305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
#ifdef CONFIG_OF
static int __devinit
sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
			 struct esdhc_platform_data *boarddata)
{
	struct device_node *np = pdev->dev.of_node;

	if (!np)
		return -ENODEV;

	if (of_get_property(np, "fsl,card-wired", NULL))
		boarddata->cd_type = ESDHC_CD_PERMANENT;

	if (of_get_property(np, "fsl,cd-controller", NULL))
		boarddata->cd_type = ESDHC_CD_CONTROLLER;

	if (of_get_property(np, "fsl,wp-controller", NULL))
		boarddata->wp_type = ESDHC_WP_CONTROLLER;

	boarddata->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
	if (gpio_is_valid(boarddata->cd_gpio))
		boarddata->cd_type = ESDHC_CD_GPIO;

	boarddata->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
	if (gpio_is_valid(boarddata->wp_gpio))
		boarddata->wp_type = ESDHC_WP_GPIO;

	return 0;
}
#else
static inline int
sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
			 struct esdhc_platform_data *boarddata)
{
	return -ENODEV;
}
#endif

343
static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
344
{
345 346
	const struct of_device_id *of_id =
			of_match_device(imx_esdhc_dt_ids, &pdev->dev);
347 348 349
	struct sdhci_pltfm_host *pltfm_host;
	struct sdhci_host *host;
	struct esdhc_platform_data *boarddata;
350
	struct clk *clk;
351
	int err;
352
	struct pltfm_imx_data *imx_data;
353

354 355 356 357 358 359 360
	host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata);
	if (IS_ERR(host))
		return PTR_ERR(host);

	pltfm_host = sdhci_priv(host);

	imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL);
361 362 363 364
	if (!imx_data) {
		err = -ENOMEM;
		goto err_imx_data;
	}
365

366 367
	if (of_id)
		pdev->id_entry = of_id->data;
368
	imx_data->devtype = pdev->id_entry->driver_data;
369 370
	pltfm_host->priv = imx_data;

371 372 373
	clk = clk_get(mmc_dev(host->mmc), NULL);
	if (IS_ERR(clk)) {
		dev_err(mmc_dev(host->mmc), "clk err\n");
374 375
		err = PTR_ERR(clk);
		goto err_clk_get;
376 377 378 379
	}
	clk_enable(clk);
	pltfm_host->clk = clk;

380
	if (!is_imx25_esdhc(imx_data))
381 382
		host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;

383
	if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data))
384
		/* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
385
		host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK;
386

387
	if (is_imx53_esdhc(imx_data))
388 389
		imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT;

390
	boarddata = &imx_data->boarddata;
391 392 393 394 395 396 397 398 399
	if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) {
		if (!host->mmc->parent->platform_data) {
			dev_err(mmc_dev(host->mmc), "no board data!\n");
			err = -EINVAL;
			goto no_board_data;
		}
		imx_data->boarddata = *((struct esdhc_platform_data *)
					host->mmc->parent->platform_data);
	}
400 401 402

	/* write_protect */
	if (boarddata->wp_type == ESDHC_WP_GPIO) {
403 404 405
		err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP");
		if (err) {
			dev_warn(mmc_dev(host->mmc),
406 407
				 "no write-protect pin available!\n");
			boarddata->wp_gpio = -EINVAL;
408
		}
409 410 411 412 413 414 415
	} else {
		boarddata->wp_gpio = -EINVAL;
	}

	/* card_detect */
	if (boarddata->cd_type != ESDHC_CD_GPIO)
		boarddata->cd_gpio = -EINVAL;
416

417 418
	switch (boarddata->cd_type) {
	case ESDHC_CD_GPIO:
419 420
		err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD");
		if (err) {
421
			dev_err(mmc_dev(host->mmc),
422 423 424 425 426 427 428 429
				"no card-detect pin available!\n");
			goto no_card_detect_pin;
		}

		err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq,
				 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
				 mmc_hostname(host->mmc), host);
		if (err) {
430
			dev_err(mmc_dev(host->mmc), "request irq error\n");
431 432
			goto no_card_detect_irq;
		}
433
		/* fall through */
434

435 436
	case ESDHC_CD_CONTROLLER:
		/* we have a working card_detect back */
437
		host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
438 439 440 441 442 443 444 445
		break;

	case ESDHC_CD_PERMANENT:
		host->mmc->caps = MMC_CAP_NONREMOVABLE;
		break;

	case ESDHC_CD_NONE:
		break;
446
	}
447

448 449 450 451
	err = sdhci_add_host(host);
	if (err)
		goto err_add_host;

452
	return 0;
453

454 455 456 457 458 459 460 461 462 463
err_add_host:
	if (gpio_is_valid(boarddata->cd_gpio))
		free_irq(gpio_to_irq(boarddata->cd_gpio), host);
no_card_detect_irq:
	if (gpio_is_valid(boarddata->cd_gpio))
		gpio_free(boarddata->cd_gpio);
	if (gpio_is_valid(boarddata->wp_gpio))
		gpio_free(boarddata->wp_gpio);
no_card_detect_pin:
no_board_data:
464 465
	clk_disable(pltfm_host->clk);
	clk_put(pltfm_host->clk);
466 467
err_clk_get:
	kfree(imx_data);
468
err_imx_data:
469 470
	sdhci_pltfm_free(pdev);
	return err;
471 472
}

473
static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)
474
{
475
	struct sdhci_host *host = platform_get_drvdata(pdev);
476
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
477
	struct pltfm_imx_data *imx_data = pltfm_host->priv;
478
	struct esdhc_platform_data *boarddata = &imx_data->boarddata;
479 480 481
	int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);

	sdhci_remove_host(host, dead);
482

483
	if (gpio_is_valid(boarddata->wp_gpio))
484
		gpio_free(boarddata->wp_gpio);
485

486 487
	if (gpio_is_valid(boarddata->cd_gpio)) {
		free_irq(gpio_to_irq(boarddata->cd_gpio), host);
488 489 490
		gpio_free(boarddata->cd_gpio);
	}

491 492
	clk_disable(pltfm_host->clk);
	clk_put(pltfm_host->clk);
493
	kfree(imx_data);
494 495 496 497

	sdhci_pltfm_free(pdev);

	return 0;
498 499
}

500 501 502 503
static struct platform_driver sdhci_esdhc_imx_driver = {
	.driver		= {
		.name	= "sdhci-esdhc-imx",
		.owner	= THIS_MODULE,
504
		.of_match_table = imx_esdhc_dt_ids,
505
	},
506
	.id_table	= imx_esdhc_devtype,
507 508 509 510 511 512
	.probe		= sdhci_esdhc_imx_probe,
	.remove		= __devexit_p(sdhci_esdhc_imx_remove),
#ifdef CONFIG_PM
	.suspend	= sdhci_pltfm_suspend,
	.resume		= sdhci_pltfm_resume,
#endif
513
};
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529

static int __init sdhci_esdhc_imx_init(void)
{
	return platform_driver_register(&sdhci_esdhc_imx_driver);
}
module_init(sdhci_esdhc_imx_init);

static void __exit sdhci_esdhc_imx_exit(void)
{
	platform_driver_unregister(&sdhci_esdhc_imx_driver);
}
module_exit(sdhci_esdhc_imx_exit);

MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC");
MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
MODULE_LICENSE("GPL v2");