/drivers/mmc/host/sdhci-pxa.c
C | 303 lines | 215 code | 48 blank | 40 comment | 27 complexity | 5ccabfd82efd24221aac201bad0c1d45 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
1/* linux/drivers/mmc/host/sdhci-pxa.c 2 * 3 * Copyright (C) 2010 Marvell International Ltd. 4 * Zhangfei Gao <zhangfei.gao@marvell.com> 5 * Kevin Wang <dwang4@marvell.com> 6 * Mingwei Wang <mwwang@marvell.com> 7 * Philip Rakity <prakity@marvell.com> 8 * Mark Brown <markb@marvell.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 */ 14 15/* Supports: 16 * SDHCI support for MMP2/PXA910/PXA168 17 * 18 * Refer to sdhci-s3c.c. 19 */ 20 21#include <linux/delay.h> 22#include <linux/platform_device.h> 23#include <linux/mmc/host.h> 24#include <linux/clk.h> 25#include <linux/io.h> 26#include <linux/err.h> 27#include <plat/sdhci.h> 28#include "sdhci.h" 29 30#define DRIVER_NAME "sdhci-pxa" 31 32#define SD_FIFO_PARAM 0x104 33#define DIS_PAD_SD_CLK_GATE 0x400 34 35struct sdhci_pxa { 36 struct sdhci_host *host; 37 struct sdhci_pxa_platdata *pdata; 38 struct clk *clk; 39 struct resource *res; 40 41 u8 clk_enable; 42}; 43 44/*****************************************************************************\ 45 * * 46 * SDHCI core callbacks * 47 * * 48\*****************************************************************************/ 49static void set_clock(struct sdhci_host *host, unsigned int clock) 50{ 51 struct sdhci_pxa *pxa = sdhci_priv(host); 52 u32 tmp = 0; 53 54 if (clock == 0) { 55 if (pxa->clk_enable) { 56 clk_disable(pxa->clk); 57 pxa->clk_enable = 0; 58 } 59 } else { 60 if (0 == pxa->clk_enable) { 61 if (pxa->pdata->flags & PXA_FLAG_DISABLE_CLOCK_GATING) { 62 tmp = readl(host->ioaddr + SD_FIFO_PARAM); 63 tmp |= DIS_PAD_SD_CLK_GATE; 64 writel(tmp, host->ioaddr + SD_FIFO_PARAM); 65 } 66 clk_enable(pxa->clk); 67 pxa->clk_enable = 1; 68 } 69 } 70} 71 72static int set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) 73{ 74 u16 ctrl_2; 75 76 /* 77 * Set V18_EN -- UHS modes do not work without this. 78 * does not change signaling voltage 79 */ 80 ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); 81 82 /* Select Bus Speed Mode for host */ 83 ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; 84 switch (uhs) { 85 case MMC_TIMING_UHS_SDR12: 86 ctrl_2 |= SDHCI_CTRL_UHS_SDR12; 87 break; 88 case MMC_TIMING_UHS_SDR25: 89 ctrl_2 |= SDHCI_CTRL_UHS_SDR25; 90 break; 91 case MMC_TIMING_UHS_SDR50: 92 ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180; 93 break; 94 case MMC_TIMING_UHS_SDR104: 95 ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180; 96 break; 97 case MMC_TIMING_UHS_DDR50: 98 ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180; 99 break; 100 } 101 102 sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); 103 pr_debug("%s:%s uhs = %d, ctrl_2 = %04X\n", 104 __func__, mmc_hostname(host->mmc), uhs, ctrl_2); 105 106 return 0; 107} 108 109static struct sdhci_ops sdhci_pxa_ops = { 110 .set_uhs_signaling = set_uhs_signaling, 111 .set_clock = set_clock, 112}; 113 114/*****************************************************************************\ 115 * * 116 * Device probing/removal * 117 * * 118\*****************************************************************************/ 119 120static int __devinit sdhci_pxa_probe(struct platform_device *pdev) 121{ 122 struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; 123 struct device *dev = &pdev->dev; 124 struct sdhci_host *host = NULL; 125 struct resource *iomem = NULL; 126 struct sdhci_pxa *pxa = NULL; 127 int ret, irq; 128 129 irq = platform_get_irq(pdev, 0); 130 if (irq < 0) { 131 dev_err(dev, "no irq specified\n"); 132 return irq; 133 } 134 135 iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 136 if (!iomem) { 137 dev_err(dev, "no memory specified\n"); 138 return -ENOENT; 139 } 140 141 host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pxa)); 142 if (IS_ERR(host)) { 143 dev_err(dev, "failed to alloc host\n"); 144 return PTR_ERR(host); 145 } 146 147 pxa = sdhci_priv(host); 148 pxa->host = host; 149 pxa->pdata = pdata; 150 pxa->clk_enable = 0; 151 152 pxa->clk = clk_get(dev, "PXA-SDHCLK"); 153 if (IS_ERR(pxa->clk)) { 154 dev_err(dev, "failed to get io clock\n"); 155 ret = PTR_ERR(pxa->clk); 156 goto out; 157 } 158 159 pxa->res = request_mem_region(iomem->start, resource_size(iomem), 160 mmc_hostname(host->mmc)); 161 if (!pxa->res) { 162 dev_err(&pdev->dev, "cannot request region\n"); 163 ret = -EBUSY; 164 goto out; 165 } 166 167 host->ioaddr = ioremap(iomem->start, resource_size(iomem)); 168 if (!host->ioaddr) { 169 dev_err(&pdev->dev, "failed to remap registers\n"); 170 ret = -ENOMEM; 171 goto out; 172 } 173 174 host->hw_name = "MMC"; 175 host->ops = &sdhci_pxa_ops; 176 host->irq = irq; 177 host->quirks = SDHCI_QUIRK_BROKEN_ADMA 178 | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL 179 | SDHCI_QUIRK_32BIT_DMA_ADDR 180 | SDHCI_QUIRK_32BIT_DMA_SIZE 181 | SDHCI_QUIRK_32BIT_ADMA_SIZE 182 | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC; 183 184 if (pdata->quirks) 185 host->quirks |= pdata->quirks; 186 187 /* enable 1/8V DDR capable */ 188 host->mmc->caps |= MMC_CAP_1_8V_DDR; 189 190 /* If slot design supports 8 bit data, indicate this to MMC. */ 191 if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT) 192 host->mmc->caps |= MMC_CAP_8_BIT_DATA; 193 194 ret = sdhci_add_host(host); 195 if (ret) { 196 dev_err(&pdev->dev, "failed to add host\n"); 197 goto out; 198 } 199 200 if (pxa->pdata->max_speed) 201 host->mmc->f_max = pxa->pdata->max_speed; 202 203 platform_set_drvdata(pdev, host); 204 205 return 0; 206out: 207 if (host) { 208 clk_put(pxa->clk); 209 if (host->ioaddr) 210 iounmap(host->ioaddr); 211 if (pxa->res) 212 release_mem_region(pxa->res->start, 213 resource_size(pxa->res)); 214 sdhci_free_host(host); 215 } 216 217 return ret; 218} 219 220static int __devexit sdhci_pxa_remove(struct platform_device *pdev) 221{ 222 struct sdhci_host *host = platform_get_drvdata(pdev); 223 struct sdhci_pxa *pxa = sdhci_priv(host); 224 int dead = 0; 225 u32 scratch; 226 227 if (host) { 228 scratch = readl(host->ioaddr + SDHCI_INT_STATUS); 229 if (scratch == (u32)-1) 230 dead = 1; 231 232 sdhci_remove_host(host, dead); 233 234 if (host->ioaddr) 235 iounmap(host->ioaddr); 236 if (pxa->res) 237 release_mem_region(pxa->res->start, 238 resource_size(pxa->res)); 239 if (pxa->clk_enable) { 240 clk_disable(pxa->clk); 241 pxa->clk_enable = 0; 242 } 243 clk_put(pxa->clk); 244 245 sdhci_free_host(host); 246 platform_set_drvdata(pdev, NULL); 247 } 248 249 return 0; 250} 251 252#ifdef CONFIG_PM 253static int sdhci_pxa_suspend(struct platform_device *dev, pm_message_t state) 254{ 255 struct sdhci_host *host = platform_get_drvdata(dev); 256 257 return sdhci_suspend_host(host, state); 258} 259 260static int sdhci_pxa_resume(struct platform_device *dev) 261{ 262 struct sdhci_host *host = platform_get_drvdata(dev); 263 264 return sdhci_resume_host(host); 265} 266#else 267#define sdhci_pxa_suspend NULL 268#define sdhci_pxa_resume NULL 269#endif 270 271static struct platform_driver sdhci_pxa_driver = { 272 .probe = sdhci_pxa_probe, 273 .remove = __devexit_p(sdhci_pxa_remove), 274 .suspend = sdhci_pxa_suspend, 275 .resume = sdhci_pxa_resume, 276 .driver = { 277 .name = DRIVER_NAME, 278 .owner = THIS_MODULE, 279 }, 280}; 281 282/*****************************************************************************\ 283 * * 284 * Driver init/exit * 285 * * 286\*****************************************************************************/ 287 288static int __init sdhci_pxa_init(void) 289{ 290 return platform_driver_register(&sdhci_pxa_driver); 291} 292 293static void __exit sdhci_pxa_exit(void) 294{ 295 platform_driver_unregister(&sdhci_pxa_driver); 296} 297 298module_init(sdhci_pxa_init); 299module_exit(sdhci_pxa_exit); 300 301MODULE_DESCRIPTION("SDH controller driver for PXA168/PXA910/MMP2"); 302MODULE_AUTHOR("Zhangfei Gao <zhangfei.gao@marvell.com>"); 303MODULE_LICENSE("GPL v2");