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 26c8964481d0273ef77a37ed2c627482fde3a1222cUlf Hansson#ifdef CONFIG_PM_SLEEP 27c8964481d0273ef77a37ed2c627482fde3a1222cUlf Hanssonstatic int tmio_mmc_suspend(struct device *dev) 284a48998fa16121d0fe3436cce43afd6f47424103Ian Molton{ 29c8964481d0273ef77a37ed2c627482fde3a1222cUlf Hansson struct platform_device *pdev = to_platform_device(dev); 30c8964481d0273ef77a37ed2c627482fde3a1222cUlf Hansson const struct mfd_cell *cell = mfd_get_cell(pdev); 314a48998fa16121d0fe3436cce43afd6f47424103Ian Molton int ret; 324a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 3370a15e1a3c58ee841415c84170b80a3859027686Ulf Hansson ret = pm_runtime_force_suspend(dev); 344a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 354a48998fa16121d0fe3436cce43afd6f47424103Ian Molton /* Tell MFD core it can disable us now.*/ 364a48998fa16121d0fe3436cce43afd6f47424103Ian Molton if (!ret && cell->disable) 37c8964481d0273ef77a37ed2c627482fde3a1222cUlf Hansson cell->disable(pdev); 384a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 394a48998fa16121d0fe3436cce43afd6f47424103Ian Molton return ret; 404a48998fa16121d0fe3436cce43afd6f47424103Ian Molton} 414a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 42c8964481d0273ef77a37ed2c627482fde3a1222cUlf Hanssonstatic int tmio_mmc_resume(struct device *dev) 434a48998fa16121d0fe3436cce43afd6f47424103Ian Molton{ 44c8964481d0273ef77a37ed2c627482fde3a1222cUlf Hansson struct platform_device *pdev = to_platform_device(dev); 45c8964481d0273ef77a37ed2c627482fde3a1222cUlf Hansson const struct mfd_cell *cell = mfd_get_cell(pdev); 464a48998fa16121d0fe3436cce43afd6f47424103Ian Molton int ret = 0; 474a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 484a48998fa16121d0fe3436cce43afd6f47424103Ian Molton /* Tell the MFD core we are ready to be enabled */ 49e6ee7182c3b22afe0b983eac89dc020a93a13179Guennadi Liakhovetski if (cell->resume) 50c8964481d0273ef77a37ed2c627482fde3a1222cUlf Hansson ret = cell->resume(pdev); 514a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 52e6ee7182c3b22afe0b983eac89dc020a93a13179Guennadi Liakhovetski if (!ret) 5370a15e1a3c58ee841415c84170b80a3859027686Ulf Hansson ret = pm_runtime_force_resume(dev); 544a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 554a48998fa16121d0fe3436cce43afd6f47424103Ian Molton return ret; 564a48998fa16121d0fe3436cce43afd6f47424103Ian Molton} 574a48998fa16121d0fe3436cce43afd6f47424103Ian Molton#endif 584a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 59c3be1efd41a97f93be390240387d356a07b664c7Bill Pembertonstatic int tmio_mmc_probe(struct platform_device *pdev) 604a48998fa16121d0fe3436cce43afd6f47424103Ian Molton{ 61b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski const struct mfd_cell *cell = mfd_get_cell(pdev); 62f0e46cc4971f6be96010d9248e0fc076b229d989Philipp Zabel struct tmio_mmc_data *pdata; 634a48998fa16121d0fe3436cce43afd6f47424103Ian Molton struct tmio_mmc_host *host; 643b159a6e955c8d468f4ffa212c8b5d68d8323a8dKuninori Morimoto struct resource *res; 658e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm int ret = -EINVAL, irq; 664a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 67b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski if (pdev->num_resources != 2) 684a48998fa16121d0fe3436cce43afd6f47424103Ian Molton goto out; 694a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 70ec71974f2a3ae052cdbb57a92ce3c3b34ebd7b5dSamuel Ortiz pdata = pdev->dev.platform_data; 71d6c9b5ed37c26503795d241474a17db1d306e7eaPhilipp Zabel if (!pdata || !pdata->hclk) 72f0e46cc4971f6be96010d9248e0fc076b229d989Philipp Zabel goto out; 73d6c9b5ed37c26503795d241474a17db1d306e7eaPhilipp Zabel 748e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm irq = platform_get_irq(pdev, 0); 758e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm if (irq < 0) { 768e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm ret = irq; 778e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm goto out; 788e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm } 798e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm 804a48998fa16121d0fe3436cce43afd6f47424103Ian Molton /* Tell the MFD core we are ready to be enabled */ 814a48998fa16121d0fe3436cce43afd6f47424103Ian Molton if (cell->enable) { 82b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski ret = cell->enable(pdev); 834a48998fa16121d0fe3436cce43afd6f47424103Ian Molton if (ret) 84b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski goto out; 854a48998fa16121d0fe3436cce43afd6f47424103Ian Molton } 864a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 873b159a6e955c8d468f4ffa212c8b5d68d8323a8dKuninori Morimoto res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 883b159a6e955c8d468f4ffa212c8b5d68d8323a8dKuninori Morimoto if (!res) 893b159a6e955c8d468f4ffa212c8b5d68d8323a8dKuninori Morimoto return -EINVAL; 903b159a6e955c8d468f4ffa212c8b5d68d8323a8dKuninori Morimoto 913b159a6e955c8d468f4ffa212c8b5d68d8323a8dKuninori Morimoto /* SD control register space size is 0x200, 0x400 for bus_shift=1 */ 921e0bf16cae6d50f9a10738c89957468c977c6f89Kuninori Morimoto pdata->bus_shift = resource_size(res) >> 10; 935d60e500541ed154112809627f12d86056ac5f09Kuninori Morimoto pdata->flags |= TMIO_MMC_HAVE_HIGH_REG; 943b159a6e955c8d468f4ffa212c8b5d68d8323a8dKuninori Morimoto 95b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski ret = tmio_mmc_host_probe(&host, pdev, pdata); 964a48998fa16121d0fe3436cce43afd6f47424103Ian Molton if (ret) 977ee422dc6e947fcdc153246d47f26ae0b7cf083dMagnus Damm goto cell_disable; 984a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 99d9618e9f1a057efdfc52514d6cd7af56e9bddc17Yong Zhang ret = request_irq(irq, tmio_mmc_irq, IRQF_TRIGGER_FALLING, 100d9618e9f1a057efdfc52514d6cd7af56e9bddc17Yong Zhang dev_name(&pdev->dev), host); 1018e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm if (ret) 1028e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm goto host_remove; 1038e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm 104311f3ac76826bfd8ed6213ded91ec947df164defGuennadi Liakhovetski pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc), 1058e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm (unsigned long)host->ctl, irq); 1064a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 1074a48998fa16121d0fe3436cce43afd6f47424103Ian Molton return 0; 1084a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 1098e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Dammhost_remove: 1108e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm tmio_mmc_host_remove(host); 1117ee422dc6e947fcdc153246d47f26ae0b7cf083dMagnus Dammcell_disable: 1127ee422dc6e947fcdc153246d47f26ae0b7cf083dMagnus Damm if (cell->disable) 113b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski cell->disable(pdev); 1144a48998fa16121d0fe3436cce43afd6f47424103Ian Moltonout: 1154a48998fa16121d0fe3436cce43afd6f47424103Ian Molton return ret; 1164a48998fa16121d0fe3436cce43afd6f47424103Ian Molton} 1174a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 1186e0ee714fdab0568c3487455951dea2673e9557fBill Pembertonstatic int tmio_mmc_remove(struct platform_device *pdev) 1194a48998fa16121d0fe3436cce43afd6f47424103Ian Molton{ 120b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski const struct mfd_cell *cell = mfd_get_cell(pdev); 121b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski struct mmc_host *mmc = platform_get_drvdata(pdev); 1224a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 1234a48998fa16121d0fe3436cce43afd6f47424103Ian Molton if (mmc) { 1248e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm struct tmio_mmc_host *host = mmc_priv(mmc); 1258e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm free_irq(platform_get_irq(pdev, 0), host); 1268e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm tmio_mmc_host_remove(host); 1277ee422dc6e947fcdc153246d47f26ae0b7cf083dMagnus Damm if (cell->disable) 128b6147490e6aac82fa2f4b9d7fce925d9891ebe8fGuennadi Liakhovetski cell->disable(pdev); 1294a48998fa16121d0fe3436cce43afd6f47424103Ian Molton } 1304a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 1314a48998fa16121d0fe3436cce43afd6f47424103Ian Molton return 0; 1324a48998fa16121d0fe3436cce43afd6f47424103Ian Molton} 1334a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 1344a48998fa16121d0fe3436cce43afd6f47424103Ian Molton/* ------------------- device registration ----------------------- */ 1354a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 136c8964481d0273ef77a37ed2c627482fde3a1222cUlf Hanssonstatic const struct dev_pm_ops tmio_mmc_dev_pm_ops = { 137c8964481d0273ef77a37ed2c627482fde3a1222cUlf Hansson SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_suspend, tmio_mmc_resume) 13878f76df60926f7853df9ee2b707ea9254129775cUlf Hansson SET_PM_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend, 13978f76df60926f7853df9ee2b707ea9254129775cUlf Hansson tmio_mmc_host_runtime_resume, 14078f76df60926f7853df9ee2b707ea9254129775cUlf Hansson NULL) 141c8964481d0273ef77a37ed2c627482fde3a1222cUlf Hansson}; 142c8964481d0273ef77a37ed2c627482fde3a1222cUlf Hansson 1434a48998fa16121d0fe3436cce43afd6f47424103Ian Moltonstatic struct platform_driver tmio_mmc_driver = { 1444a48998fa16121d0fe3436cce43afd6f47424103Ian Molton .driver = { 1454a48998fa16121d0fe3436cce43afd6f47424103Ian Molton .name = "tmio-mmc", 1464a48998fa16121d0fe3436cce43afd6f47424103Ian Molton .owner = THIS_MODULE, 147c8964481d0273ef77a37ed2c627482fde3a1222cUlf Hansson .pm = &tmio_mmc_dev_pm_ops, 1484a48998fa16121d0fe3436cce43afd6f47424103Ian Molton }, 1494a48998fa16121d0fe3436cce43afd6f47424103Ian Molton .probe = tmio_mmc_probe, 1500433c14356702e296f474f77ebd42f0a9d9a5487Bill Pemberton .remove = tmio_mmc_remove, 1514a48998fa16121d0fe3436cce43afd6f47424103Ian Molton}; 1524a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 153d1f81a64a4250bdd776978be06ae2b8e13ec7471Axel Linmodule_platform_driver(tmio_mmc_driver); 1544a48998fa16121d0fe3436cce43afd6f47424103Ian Molton 1554a48998fa16121d0fe3436cce43afd6f47424103Ian MoltonMODULE_DESCRIPTION("Toshiba TMIO SD/MMC driver"); 1564a48998fa16121d0fe3436cce43afd6f47424103Ian MoltonMODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); 1574a48998fa16121d0fe3436cce43afd6f47424103Ian MoltonMODULE_LICENSE("GPL v2"); 1584a48998fa16121d0fe3436cce43afd6f47424103Ian MoltonMODULE_ALIAS("platform:tmio-mmc"); 159