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