tmio_mmc.c revision ec71974f2a3ae052cdbb57a92ce3c3b34ebd7b5d
14a48998fa16121d0fe3436cce43afd6f47424103Ian Molton/*
2b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski * linux/drivers/mmc/host/tmio_mmc.c
34a48998fa16121d0fe3436cce43afd6f47424103Ian Molton *
4b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski * Copyright (C) 2007 Ian Molton
5b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski * Copyright (C) 2004 Ian Molton
64a48998fa16121d0fe3436cce43afd6f47424103Ian Molton *
74a48998fa16121d0fe3436cce43afd6f47424103Ian Molton * This program is free software; you can redistribute it and/or modify
84a48998fa16121d0fe3436cce43afd6f47424103Ian Molton * it under the terms of the GNU General Public License version 2 as
94a48998fa16121d0fe3436cce43afd6f47424103Ian Molton * published by the Free Software Foundation.
104a48998fa16121d0fe3436cce43afd6f47424103Ian Molton *
114a48998fa16121d0fe3436cce43afd6f47424103Ian Molton * Driver for the MMC / SD / SDIO cell found in:
124a48998fa16121d0fe3436cce43afd6f47424103Ian Molton *
13e6f2c7adc1318e233d31d113e6896607c54073a4Philipp Zabel * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3
144a48998fa16121d0fe3436cce43afd6f47424103Ian Molton */
15e0bc6ff8b8d5c066d978d23e690d5599db4cb2b3Guennadi Liakhovetski
16e0bc6ff8b8d5c066d978d23e690d5599db4cb2b3Guennadi Liakhovetski#include <linux/device.h>
174a48998fa16121d0fe3436cce43afd6f47424103Ian Molton#include <linux/mfd/core.h>
184a48998fa16121d0fe3436cce43afd6f47424103Ian Molton#include <linux/mfd/tmio.h>
19e0bc6ff8b8d5c066d978d23e690d5599db4cb2b3Guennadi Liakhovetski#include <linux/mmc/host.h>
20e0bc6ff8b8d5c066d978d23e690d5599db4cb2b3Guennadi Liakhovetski#include <linux/module.h>
21e0bc6ff8b8d5c066d978d23e690d5599db4cb2b3Guennadi Liakhovetski#include <linux/pagemap.h>
22e0bc6ff8b8d5c066d978d23e690d5599db4cb2b3Guennadi Liakhovetski#include <linux/scatterlist.h>
236ff56e0d8e02df023440ea65774cf1d15e669eceArnd Hannemann
24b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski#include "tmio_mmc.h"
254a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
264a48998fa16121d0fe3436cce43afd6f47424103Ian Molton#ifdef CONFIG_PM
274a48998fa16121d0fe3436cce43afd6f47424103Ian Moltonstatic int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
284a48998fa16121d0fe3436cce43afd6f47424103Ian Molton{
29944dc03551f6e812c00e586edba84b28c52ffe8cAndres Salomon	const struct mfd_cell *cell = mfd_get_cell(dev);
304a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	struct mmc_host *mmc = platform_get_drvdata(dev);
314a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	int ret;
324a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
33e6ee7182c3b22afe0b983eac89dc020a93a13179Guennadi Liakhovetski	ret = tmio_mmc_host_suspend(&dev->dev);
344a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
354a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	/* Tell MFD core it can disable us now.*/
364a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	if (!ret && cell->disable)
374a48998fa16121d0fe3436cce43afd6f47424103Ian Molton		cell->disable(dev);
384a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
394a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	return ret;
404a48998fa16121d0fe3436cce43afd6f47424103Ian Molton}
414a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
424a48998fa16121d0fe3436cce43afd6f47424103Ian Moltonstatic int tmio_mmc_resume(struct platform_device *dev)
434a48998fa16121d0fe3436cce43afd6f47424103Ian Molton{
44944dc03551f6e812c00e586edba84b28c52ffe8cAndres Salomon	const struct mfd_cell *cell = mfd_get_cell(dev);
454a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	struct mmc_host *mmc = platform_get_drvdata(dev);
464a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	int ret = 0;
474a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
484a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	/* Tell the MFD core we are ready to be enabled */
49e6ee7182c3b22afe0b983eac89dc020a93a13179Guennadi Liakhovetski	if (cell->resume)
5064e8867ba8098b69889c1af94997a5ba2348fb26Ian Molton		ret = cell->resume(dev);
514a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
52e6ee7182c3b22afe0b983eac89dc020a93a13179Guennadi Liakhovetski	if (!ret)
53e6ee7182c3b22afe0b983eac89dc020a93a13179Guennadi Liakhovetski		ret = tmio_mmc_host_resume(&dev->dev);
544a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
554a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	return ret;
564a48998fa16121d0fe3436cce43afd6f47424103Ian Molton}
574a48998fa16121d0fe3436cce43afd6f47424103Ian Molton#else
584a48998fa16121d0fe3436cce43afd6f47424103Ian Molton#define tmio_mmc_suspend NULL
594a48998fa16121d0fe3436cce43afd6f47424103Ian Molton#define tmio_mmc_resume NULL
604a48998fa16121d0fe3436cce43afd6f47424103Ian Molton#endif
614a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
62b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetskistatic int __devinit tmio_mmc_probe(struct platform_device *pdev)
634a48998fa16121d0fe3436cce43afd6f47424103Ian Molton{
64b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski	const struct mfd_cell *cell = mfd_get_cell(pdev);
65f0e46cc4971f6be96010d9248e0fc076b229d989Philipp Zabel	struct tmio_mmc_data *pdata;
664a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	struct tmio_mmc_host *host;
678e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm	int ret = -EINVAL, irq;
684a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
69b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski	if (pdev->num_resources != 2)
704a48998fa16121d0fe3436cce43afd6f47424103Ian Molton		goto out;
714a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
72ec71974f2a3ae052cdbb57a92ce3c3b34ebd7b5dSamuel Ortiz	pdata = pdev->dev.platform_data;
73d6c9b5ed37c26503795d241474a17db1d306e7eaPhilipp Zabel	if (!pdata || !pdata->hclk)
74f0e46cc4971f6be96010d9248e0fc076b229d989Philipp Zabel		goto out;
75d6c9b5ed37c26503795d241474a17db1d306e7eaPhilipp Zabel
768e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm	irq = platform_get_irq(pdev, 0);
778e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm	if (irq < 0) {
788e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm		ret = irq;
798e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm		goto out;
808e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm	}
818e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm
824a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	/* Tell the MFD core we are ready to be enabled */
834a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	if (cell->enable) {
84b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski		ret = cell->enable(pdev);
854a48998fa16121d0fe3436cce43afd6f47424103Ian Molton		if (ret)
86b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski			goto out;
874a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	}
884a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
89b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski	ret = tmio_mmc_host_probe(&host, pdev, pdata);
904a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	if (ret)
917ee422dc6e947fcdc153246d47f26ae0b7cf083dMagnus Damm		goto cell_disable;
924a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
938e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm	ret = request_irq(irq, tmio_mmc_irq, IRQF_DISABLED |
948e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm			  IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), host);
958e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm	if (ret)
968e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm		goto host_remove;
978e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm
98311f3ac76826bfd8ed6213ded91ec947df164defGuennadi Liakhovetski	pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc),
998e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm		(unsigned long)host->ctl, irq);
1004a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
1014a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	return 0;
1024a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
1038e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Dammhost_remove:
1048e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm	tmio_mmc_host_remove(host);
1057ee422dc6e947fcdc153246d47f26ae0b7cf083dMagnus Dammcell_disable:
1067ee422dc6e947fcdc153246d47f26ae0b7cf083dMagnus Damm	if (cell->disable)
107b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski		cell->disable(pdev);
1084a48998fa16121d0fe3436cce43afd6f47424103Ian Moltonout:
1094a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	return ret;
1104a48998fa16121d0fe3436cce43afd6f47424103Ian Molton}
1114a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
112b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetskistatic int __devexit tmio_mmc_remove(struct platform_device *pdev)
1134a48998fa16121d0fe3436cce43afd6f47424103Ian Molton{
114b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski	const struct mfd_cell *cell = mfd_get_cell(pdev);
115b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski	struct mmc_host *mmc = platform_get_drvdata(pdev);
1164a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
117b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski	platform_set_drvdata(pdev, NULL);
1184a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
1194a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	if (mmc) {
1208e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm		struct tmio_mmc_host *host = mmc_priv(mmc);
1218e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm		free_irq(platform_get_irq(pdev, 0), host);
1228e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm		tmio_mmc_host_remove(host);
1237ee422dc6e947fcdc153246d47f26ae0b7cf083dMagnus Damm		if (cell->disable)
124b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski			cell->disable(pdev);
1254a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	}
1264a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
1274a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	return 0;
1284a48998fa16121d0fe3436cce43afd6f47424103Ian Molton}
1294a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
1304a48998fa16121d0fe3436cce43afd6f47424103Ian Molton/* ------------------- device registration ----------------------- */
1314a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
1324a48998fa16121d0fe3436cce43afd6f47424103Ian Moltonstatic struct platform_driver tmio_mmc_driver = {
1334a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	.driver = {
1344a48998fa16121d0fe3436cce43afd6f47424103Ian Molton		.name = "tmio-mmc",
1354a48998fa16121d0fe3436cce43afd6f47424103Ian Molton		.owner = THIS_MODULE,
1364a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	},
1374a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	.probe = tmio_mmc_probe,
1384a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	.remove = __devexit_p(tmio_mmc_remove),
1394a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	.suspend = tmio_mmc_suspend,
1404a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	.resume = tmio_mmc_resume,
1414a48998fa16121d0fe3436cce43afd6f47424103Ian Molton};
1424a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
1434a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
1444a48998fa16121d0fe3436cce43afd6f47424103Ian Moltonstatic int __init tmio_mmc_init(void)
1454a48998fa16121d0fe3436cce43afd6f47424103Ian Molton{
1464a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	return platform_driver_register(&tmio_mmc_driver);
1474a48998fa16121d0fe3436cce43afd6f47424103Ian Molton}
1484a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
1494a48998fa16121d0fe3436cce43afd6f47424103Ian Moltonstatic void __exit tmio_mmc_exit(void)
1504a48998fa16121d0fe3436cce43afd6f47424103Ian Molton{
1514a48998fa16121d0fe3436cce43afd6f47424103Ian Molton	platform_driver_unregister(&tmio_mmc_driver);
1524a48998fa16121d0fe3436cce43afd6f47424103Ian Molton}
1534a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
1544a48998fa16121d0fe3436cce43afd6f47424103Ian Moltonmodule_init(tmio_mmc_init);
1554a48998fa16121d0fe3436cce43afd6f47424103Ian Moltonmodule_exit(tmio_mmc_exit);
1564a48998fa16121d0fe3436cce43afd6f47424103Ian Molton
1574a48998fa16121d0fe3436cce43afd6f47424103Ian MoltonMODULE_DESCRIPTION("Toshiba TMIO SD/MMC driver");
1584a48998fa16121d0fe3436cce43afd6f47424103Ian MoltonMODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
1594a48998fa16121d0fe3436cce43afd6f47424103Ian MoltonMODULE_LICENSE("GPL v2");
1604a48998fa16121d0fe3436cce43afd6f47424103Ian MoltonMODULE_ALIAS("platform:tmio-mmc");
161