1 /* 2 * sdhci-pltfm.c Support for SDHCI platform devices 3 * Copyright (c) 2009 Intel Corporation 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 */ 18 19 /* Supports: 20 * SDHCI platform devices 21 * 22 * Inspired by sdhci-pci.c, by Pierre Ossman 23 */ 24 25 #include <linux/delay.h> 26 #include <linux/highmem.h> 27 #include <linux/platform_device.h> 28 29 #include <linux/mmc/host.h> 30 31 #include <linux/io.h> 32 33 #include "sdhci.h" 34 35 /*****************************************************************************\ 36 * * 37 * SDHCI core callbacks * 38 * * 39 \*****************************************************************************/ 40 41 static struct sdhci_ops sdhci_pltfm_ops = { 42 }; 43 44 /*****************************************************************************\ 45 * * 46 * Device probing/removal * 47 * * 48 \*****************************************************************************/ 49 50 static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) 51 { 52 struct sdhci_host *host; 53 struct resource *iomem; 54 int ret; 55 56 BUG_ON(pdev == NULL); 57 58 iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 59 if (!iomem) { 60 ret = -ENOMEM; 61 goto err; 62 } 63 64 if (resource_size(iomem) != 0x100) 65 dev_err(&pdev->dev, "Invalid iomem size. You may " 66 "experience problems.\n"); 67 68 if (pdev->dev.parent) 69 host = sdhci_alloc_host(pdev->dev.parent, 0); 70 else 71 host = sdhci_alloc_host(&pdev->dev, 0); 72 73 if (IS_ERR(host)) { 74 ret = PTR_ERR(host); 75 goto err; 76 } 77 78 host->hw_name = "platform"; 79 host->ops = &sdhci_pltfm_ops; 80 host->irq = platform_get_irq(pdev, 0); 81 82 if (!request_mem_region(iomem->start, resource_size(iomem), 83 mmc_hostname(host->mmc))) { 84 dev_err(&pdev->dev, "cannot request region\n"); 85 ret = -EBUSY; 86 goto err_request; 87 } 88 89 host->ioaddr = ioremap(iomem->start, resource_size(iomem)); 90 if (!host->ioaddr) { 91 dev_err(&pdev->dev, "failed to remap registers\n"); 92 ret = -ENOMEM; 93 goto err_remap; 94 } 95 96 ret = sdhci_add_host(host); 97 if (ret) 98 goto err_add_host; 99 100 platform_set_drvdata(pdev, host); 101 102 return 0; 103 104 err_add_host: 105 iounmap(host->ioaddr); 106 err_remap: 107 release_mem_region(iomem->start, resource_size(iomem)); 108 err_request: 109 sdhci_free_host(host); 110 err: 111 printk(KERN_ERR"Probing of sdhci-pltfm failed: %d\n", ret); 112 return ret; 113 } 114 115 static int __devexit sdhci_pltfm_remove(struct platform_device *pdev) 116 { 117 struct sdhci_host *host = platform_get_drvdata(pdev); 118 struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 119 int dead; 120 u32 scratch; 121 122 dead = 0; 123 scratch = readl(host->ioaddr + SDHCI_INT_STATUS); 124 if (scratch == (u32)-1) 125 dead = 1; 126 127 sdhci_remove_host(host, dead); 128 iounmap(host->ioaddr); 129 release_mem_region(iomem->start, resource_size(iomem)); 130 sdhci_free_host(host); 131 platform_set_drvdata(pdev, NULL); 132 133 return 0; 134 } 135 136 static struct platform_driver sdhci_pltfm_driver = { 137 .driver = { 138 .name = "sdhci", 139 .owner = THIS_MODULE, 140 }, 141 .probe = sdhci_pltfm_probe, 142 .remove = __devexit_p(sdhci_pltfm_remove), 143 }; 144 145 /*****************************************************************************\ 146 * * 147 * Driver init/exit * 148 * * 149 \*****************************************************************************/ 150 151 static int __init sdhci_drv_init(void) 152 { 153 return platform_driver_register(&sdhci_pltfm_driver); 154 } 155 156 static void __exit sdhci_drv_exit(void) 157 { 158 platform_driver_unregister(&sdhci_pltfm_driver); 159 } 160 161 module_init(sdhci_drv_init); 162 module_exit(sdhci_drv_exit); 163 164 MODULE_DESCRIPTION("Secure Digital Host Controller Interface platform driver"); 165 MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>"); 166 MODULE_LICENSE("GPL v2"); 167 MODULE_ALIAS("platform:sdhci"); 168 169