tmio_mmc.c revision 8e7bfdb37ac001c95d2c768932b57de1019409cd
1/* 2 * linux/drivers/mmc/host/tmio_mmc.c 3 * 4 * Copyright (C) 2007 Ian Molton 5 * Copyright (C) 2004 Ian Molton 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 * 11 * Driver for the MMC / SD / SDIO cell found in: 12 * 13 * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3 14 */ 15 16#include <linux/device.h> 17#include <linux/mfd/core.h> 18#include <linux/mfd/tmio.h> 19#include <linux/mmc/host.h> 20#include <linux/module.h> 21#include <linux/pagemap.h> 22#include <linux/scatterlist.h> 23 24#include "tmio_mmc.h" 25 26#ifdef CONFIG_PM 27static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state) 28{ 29 const struct mfd_cell *cell = mfd_get_cell(dev); 30 struct mmc_host *mmc = platform_get_drvdata(dev); 31 int ret; 32 33 ret = tmio_mmc_host_suspend(&dev->dev); 34 35 /* Tell MFD core it can disable us now.*/ 36 if (!ret && cell->disable) 37 cell->disable(dev); 38 39 return ret; 40} 41 42static int tmio_mmc_resume(struct platform_device *dev) 43{ 44 const struct mfd_cell *cell = mfd_get_cell(dev); 45 struct mmc_host *mmc = platform_get_drvdata(dev); 46 int ret = 0; 47 48 /* Tell the MFD core we are ready to be enabled */ 49 if (cell->resume) 50 ret = cell->resume(dev); 51 52 if (!ret) 53 ret = tmio_mmc_host_resume(&dev->dev); 54 55 return ret; 56} 57#else 58#define tmio_mmc_suspend NULL 59#define tmio_mmc_resume NULL 60#endif 61 62static int __devinit tmio_mmc_probe(struct platform_device *pdev) 63{ 64 const struct mfd_cell *cell = mfd_get_cell(pdev); 65 struct tmio_mmc_data *pdata; 66 struct tmio_mmc_host *host; 67 int ret = -EINVAL, irq; 68 69 if (pdev->num_resources != 2) 70 goto out; 71 72 pdata = mfd_get_data(pdev); 73 if (!pdata || !pdata->hclk) 74 goto out; 75 76 irq = platform_get_irq(pdev, 0); 77 if (irq < 0) { 78 ret = irq; 79 goto out; 80 } 81 82 /* Tell the MFD core we are ready to be enabled */ 83 if (cell->enable) { 84 ret = cell->enable(pdev); 85 if (ret) 86 goto out; 87 } 88 89 ret = tmio_mmc_host_probe(&host, pdev, pdata); 90 if (ret) 91 goto cell_disable; 92 93 ret = request_irq(irq, tmio_mmc_irq, IRQF_DISABLED | 94 IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), host); 95 if (ret) 96 goto host_remove; 97 98 pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc), 99 (unsigned long)host->ctl, irq); 100 101 return 0; 102 103host_remove: 104 tmio_mmc_host_remove(host); 105cell_disable: 106 if (cell->disable) 107 cell->disable(pdev); 108out: 109 return ret; 110} 111 112static int __devexit tmio_mmc_remove(struct platform_device *pdev) 113{ 114 const struct mfd_cell *cell = mfd_get_cell(pdev); 115 struct mmc_host *mmc = platform_get_drvdata(pdev); 116 117 platform_set_drvdata(pdev, NULL); 118 119 if (mmc) { 120 struct tmio_mmc_host *host = mmc_priv(mmc); 121 free_irq(platform_get_irq(pdev, 0), host); 122 tmio_mmc_host_remove(host); 123 if (cell->disable) 124 cell->disable(pdev); 125 } 126 127 return 0; 128} 129 130/* ------------------- device registration ----------------------- */ 131 132static struct platform_driver tmio_mmc_driver = { 133 .driver = { 134 .name = "tmio-mmc", 135 .owner = THIS_MODULE, 136 }, 137 .probe = tmio_mmc_probe, 138 .remove = __devexit_p(tmio_mmc_remove), 139 .suspend = tmio_mmc_suspend, 140 .resume = tmio_mmc_resume, 141}; 142 143 144static int __init tmio_mmc_init(void) 145{ 146 return platform_driver_register(&tmio_mmc_driver); 147} 148 149static void __exit tmio_mmc_exit(void) 150{ 151 platform_driver_unregister(&tmio_mmc_driver); 152} 153 154module_init(tmio_mmc_init); 155module_exit(tmio_mmc_exit); 156 157MODULE_DESCRIPTION("Toshiba TMIO SD/MMC driver"); 158MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); 159MODULE_LICENSE("GPL v2"); 160MODULE_ALIAS("platform:tmio-mmc"); 161