10d1bb41aSBen Dooks /* linux/drivers/mmc/host/sdhci-s3c.c 20d1bb41aSBen Dooks * 30d1bb41aSBen Dooks * Copyright 2008 Openmoko Inc. 40d1bb41aSBen Dooks * Copyright 2008 Simtec Electronics 50d1bb41aSBen Dooks * Ben Dooks <ben@simtec.co.uk> 60d1bb41aSBen Dooks * http://armlinux.simtec.co.uk/ 70d1bb41aSBen Dooks * 80d1bb41aSBen Dooks * SDHCI (HSMMC) support for Samsung SoC 90d1bb41aSBen Dooks * 100d1bb41aSBen Dooks * This program is free software; you can redistribute it and/or modify 110d1bb41aSBen Dooks * it under the terms of the GNU General Public License version 2 as 120d1bb41aSBen Dooks * published by the Free Software Foundation. 130d1bb41aSBen Dooks */ 140d1bb41aSBen Dooks 150d1bb41aSBen Dooks #include <linux/delay.h> 160d1bb41aSBen Dooks #include <linux/dma-mapping.h> 170d1bb41aSBen Dooks #include <linux/platform_device.h> 185a0e3ad6STejun Heo #include <linux/slab.h> 190d1bb41aSBen Dooks #include <linux/clk.h> 200d1bb41aSBen Dooks #include <linux/io.h> 210d1bb41aSBen Dooks 220d1bb41aSBen Dooks #include <linux/mmc/host.h> 230d1bb41aSBen Dooks 240d1bb41aSBen Dooks #include <plat/sdhci.h> 250d1bb41aSBen Dooks #include <plat/regs-sdhci.h> 260d1bb41aSBen Dooks 270d1bb41aSBen Dooks #include "sdhci.h" 280d1bb41aSBen Dooks 290d1bb41aSBen Dooks #define MAX_BUS_CLK (4) 300d1bb41aSBen Dooks 310d1bb41aSBen Dooks /** 320d1bb41aSBen Dooks * struct sdhci_s3c - S3C SDHCI instance 330d1bb41aSBen Dooks * @host: The SDHCI host created 340d1bb41aSBen Dooks * @pdev: The platform device we where created from. 350d1bb41aSBen Dooks * @ioarea: The resource created when we claimed the IO area. 360d1bb41aSBen Dooks * @pdata: The platform data for this controller. 370d1bb41aSBen Dooks * @cur_clk: The index of the current bus clock. 380d1bb41aSBen Dooks * @clk_io: The clock for the internal bus interface. 390d1bb41aSBen Dooks * @clk_bus: The clocks that are available for the SD/MMC bus clock. 400d1bb41aSBen Dooks */ 410d1bb41aSBen Dooks struct sdhci_s3c { 420d1bb41aSBen Dooks struct sdhci_host *host; 430d1bb41aSBen Dooks struct platform_device *pdev; 440d1bb41aSBen Dooks struct resource *ioarea; 450d1bb41aSBen Dooks struct s3c_sdhci_platdata *pdata; 460d1bb41aSBen Dooks unsigned int cur_clk; 470d1bb41aSBen Dooks 480d1bb41aSBen Dooks struct clk *clk_io; 490d1bb41aSBen Dooks struct clk *clk_bus[MAX_BUS_CLK]; 500d1bb41aSBen Dooks }; 510d1bb41aSBen Dooks 520d1bb41aSBen Dooks static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host) 530d1bb41aSBen Dooks { 540d1bb41aSBen Dooks return sdhci_priv(host); 550d1bb41aSBen Dooks } 560d1bb41aSBen Dooks 570d1bb41aSBen Dooks /** 580d1bb41aSBen Dooks * get_curclk - convert ctrl2 register to clock source number 590d1bb41aSBen Dooks * @ctrl2: Control2 register value. 600d1bb41aSBen Dooks */ 610d1bb41aSBen Dooks static u32 get_curclk(u32 ctrl2) 620d1bb41aSBen Dooks { 630d1bb41aSBen Dooks ctrl2 &= S3C_SDHCI_CTRL2_SELBASECLK_MASK; 640d1bb41aSBen Dooks ctrl2 >>= S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; 650d1bb41aSBen Dooks 660d1bb41aSBen Dooks return ctrl2; 670d1bb41aSBen Dooks } 680d1bb41aSBen Dooks 690d1bb41aSBen Dooks static void sdhci_s3c_check_sclk(struct sdhci_host *host) 700d1bb41aSBen Dooks { 710d1bb41aSBen Dooks struct sdhci_s3c *ourhost = to_s3c(host); 720d1bb41aSBen Dooks u32 tmp = readl(host->ioaddr + S3C_SDHCI_CONTROL2); 730d1bb41aSBen Dooks 740d1bb41aSBen Dooks if (get_curclk(tmp) != ourhost->cur_clk) { 750d1bb41aSBen Dooks dev_dbg(&ourhost->pdev->dev, "restored ctrl2 clock setting\n"); 760d1bb41aSBen Dooks 770d1bb41aSBen Dooks tmp &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; 780d1bb41aSBen Dooks tmp |= ourhost->cur_clk << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; 790d1bb41aSBen Dooks writel(tmp, host->ioaddr + 0x80); 800d1bb41aSBen Dooks } 810d1bb41aSBen Dooks } 820d1bb41aSBen Dooks 830d1bb41aSBen Dooks /** 840d1bb41aSBen Dooks * sdhci_s3c_get_max_clk - callback to get maximum clock frequency. 850d1bb41aSBen Dooks * @host: The SDHCI host instance. 860d1bb41aSBen Dooks * 870d1bb41aSBen Dooks * Callback to return the maximum clock rate acheivable by the controller. 880d1bb41aSBen Dooks */ 890d1bb41aSBen Dooks static unsigned int sdhci_s3c_get_max_clk(struct sdhci_host *host) 900d1bb41aSBen Dooks { 910d1bb41aSBen Dooks struct sdhci_s3c *ourhost = to_s3c(host); 920d1bb41aSBen Dooks struct clk *busclk; 930d1bb41aSBen Dooks unsigned int rate, max; 940d1bb41aSBen Dooks int clk; 950d1bb41aSBen Dooks 960d1bb41aSBen Dooks /* note, a reset will reset the clock source */ 970d1bb41aSBen Dooks 980d1bb41aSBen Dooks sdhci_s3c_check_sclk(host); 990d1bb41aSBen Dooks 1000d1bb41aSBen Dooks for (max = 0, clk = 0; clk < MAX_BUS_CLK; clk++) { 1010d1bb41aSBen Dooks busclk = ourhost->clk_bus[clk]; 1020d1bb41aSBen Dooks if (!busclk) 1030d1bb41aSBen Dooks continue; 1040d1bb41aSBen Dooks 1050d1bb41aSBen Dooks rate = clk_get_rate(busclk); 1060d1bb41aSBen Dooks if (rate > max) 1070d1bb41aSBen Dooks max = rate; 1080d1bb41aSBen Dooks } 1090d1bb41aSBen Dooks 1100d1bb41aSBen Dooks return max; 1110d1bb41aSBen Dooks } 1120d1bb41aSBen Dooks 1130d1bb41aSBen Dooks /** 1140d1bb41aSBen Dooks * sdhci_s3c_consider_clock - consider one the bus clocks for current setting 1150d1bb41aSBen Dooks * @ourhost: Our SDHCI instance. 1160d1bb41aSBen Dooks * @src: The source clock index. 1170d1bb41aSBen Dooks * @wanted: The clock frequency wanted. 1180d1bb41aSBen Dooks */ 1190d1bb41aSBen Dooks static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost, 1200d1bb41aSBen Dooks unsigned int src, 1210d1bb41aSBen Dooks unsigned int wanted) 1220d1bb41aSBen Dooks { 1230d1bb41aSBen Dooks unsigned long rate; 1240d1bb41aSBen Dooks struct clk *clksrc = ourhost->clk_bus[src]; 1250d1bb41aSBen Dooks int div; 1260d1bb41aSBen Dooks 1270d1bb41aSBen Dooks if (!clksrc) 1280d1bb41aSBen Dooks return UINT_MAX; 1290d1bb41aSBen Dooks 1300d1bb41aSBen Dooks rate = clk_get_rate(clksrc); 1310d1bb41aSBen Dooks 1320d1bb41aSBen Dooks for (div = 1; div < 256; div *= 2) { 1330d1bb41aSBen Dooks if ((rate / div) <= wanted) 1340d1bb41aSBen Dooks break; 1350d1bb41aSBen Dooks } 1360d1bb41aSBen Dooks 1370d1bb41aSBen Dooks dev_dbg(&ourhost->pdev->dev, "clk %d: rate %ld, want %d, got %ld\n", 1380d1bb41aSBen Dooks src, rate, wanted, rate / div); 1390d1bb41aSBen Dooks 1400d1bb41aSBen Dooks return (wanted - (rate / div)); 1410d1bb41aSBen Dooks } 1420d1bb41aSBen Dooks 1430d1bb41aSBen Dooks /** 1440d1bb41aSBen Dooks * sdhci_s3c_set_clock - callback on clock change 1450d1bb41aSBen Dooks * @host: The SDHCI host being changed 1460d1bb41aSBen Dooks * @clock: The clock rate being requested. 1470d1bb41aSBen Dooks * 1480d1bb41aSBen Dooks * When the card's clock is going to be changed, look at the new frequency 1490d1bb41aSBen Dooks * and find the best clock source to go with it. 1500d1bb41aSBen Dooks */ 1510d1bb41aSBen Dooks static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock) 1520d1bb41aSBen Dooks { 1530d1bb41aSBen Dooks struct sdhci_s3c *ourhost = to_s3c(host); 1540d1bb41aSBen Dooks unsigned int best = UINT_MAX; 1550d1bb41aSBen Dooks unsigned int delta; 1560d1bb41aSBen Dooks int best_src = 0; 1570d1bb41aSBen Dooks int src; 1580d1bb41aSBen Dooks u32 ctrl; 1590d1bb41aSBen Dooks 1600d1bb41aSBen Dooks /* don't bother if the clock is going off. */ 1610d1bb41aSBen Dooks if (clock == 0) 1620d1bb41aSBen Dooks return; 1630d1bb41aSBen Dooks 1640d1bb41aSBen Dooks for (src = 0; src < MAX_BUS_CLK; src++) { 1650d1bb41aSBen Dooks delta = sdhci_s3c_consider_clock(ourhost, src, clock); 1660d1bb41aSBen Dooks if (delta < best) { 1670d1bb41aSBen Dooks best = delta; 1680d1bb41aSBen Dooks best_src = src; 1690d1bb41aSBen Dooks } 1700d1bb41aSBen Dooks } 1710d1bb41aSBen Dooks 1720d1bb41aSBen Dooks dev_dbg(&ourhost->pdev->dev, 1730d1bb41aSBen Dooks "selected source %d, clock %d, delta %d\n", 1740d1bb41aSBen Dooks best_src, clock, best); 1750d1bb41aSBen Dooks 1760d1bb41aSBen Dooks /* select the new clock source */ 1770d1bb41aSBen Dooks 1780d1bb41aSBen Dooks if (ourhost->cur_clk != best_src) { 1790d1bb41aSBen Dooks struct clk *clk = ourhost->clk_bus[best_src]; 1800d1bb41aSBen Dooks 1810d1bb41aSBen Dooks /* turn clock off to card before changing clock source */ 1820d1bb41aSBen Dooks writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); 1830d1bb41aSBen Dooks 1840d1bb41aSBen Dooks ourhost->cur_clk = best_src; 1850d1bb41aSBen Dooks host->max_clk = clk_get_rate(clk); 1860d1bb41aSBen Dooks 1870d1bb41aSBen Dooks ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2); 1880d1bb41aSBen Dooks ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; 1890d1bb41aSBen Dooks ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; 1900d1bb41aSBen Dooks writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); 1910d1bb41aSBen Dooks } 1920d1bb41aSBen Dooks 1930d1bb41aSBen Dooks /* reconfigure the hardware for new clock rate */ 1940d1bb41aSBen Dooks 1950d1bb41aSBen Dooks { 1960d1bb41aSBen Dooks struct mmc_ios ios; 1970d1bb41aSBen Dooks 1980d1bb41aSBen Dooks ios.clock = clock; 1990d1bb41aSBen Dooks 2000d1bb41aSBen Dooks if (ourhost->pdata->cfg_card) 2010d1bb41aSBen Dooks (ourhost->pdata->cfg_card)(ourhost->pdev, host->ioaddr, 2020d1bb41aSBen Dooks &ios, NULL); 2030d1bb41aSBen Dooks } 2040d1bb41aSBen Dooks } 2050d1bb41aSBen Dooks 206ce5f036bSMarek Szyprowski /** 207ce5f036bSMarek Szyprowski * sdhci_s3c_get_min_clock - callback to get minimal supported clock value 208ce5f036bSMarek Szyprowski * @host: The SDHCI host being queried 209ce5f036bSMarek Szyprowski * 210ce5f036bSMarek Szyprowski * To init mmc host properly a minimal clock value is needed. For high system 211ce5f036bSMarek Szyprowski * bus clock's values the standard formula gives values out of allowed range. 212ce5f036bSMarek Szyprowski * The clock still can be set to lower values, if clock source other then 213ce5f036bSMarek Szyprowski * system bus is selected. 214ce5f036bSMarek Szyprowski */ 215ce5f036bSMarek Szyprowski static unsigned int sdhci_s3c_get_min_clock(struct sdhci_host *host) 216ce5f036bSMarek Szyprowski { 217ce5f036bSMarek Szyprowski struct sdhci_s3c *ourhost = to_s3c(host); 218ce5f036bSMarek Szyprowski unsigned int delta, min = UINT_MAX; 219ce5f036bSMarek Szyprowski int src; 220ce5f036bSMarek Szyprowski 221ce5f036bSMarek Szyprowski for (src = 0; src < MAX_BUS_CLK; src++) { 222ce5f036bSMarek Szyprowski delta = sdhci_s3c_consider_clock(ourhost, src, 0); 223ce5f036bSMarek Szyprowski if (delta == UINT_MAX) 224ce5f036bSMarek Szyprowski continue; 225ce5f036bSMarek Szyprowski /* delta is a negative value in this case */ 226ce5f036bSMarek Szyprowski if (-delta < min) 227ce5f036bSMarek Szyprowski min = -delta; 228ce5f036bSMarek Szyprowski } 229ce5f036bSMarek Szyprowski return min; 230ce5f036bSMarek Szyprowski } 231ce5f036bSMarek Szyprowski 2320d1bb41aSBen Dooks static struct sdhci_ops sdhci_s3c_ops = { 2330d1bb41aSBen Dooks .get_max_clock = sdhci_s3c_get_max_clk, 2340d1bb41aSBen Dooks .set_clock = sdhci_s3c_set_clock, 235ce5f036bSMarek Szyprowski .get_min_clock = sdhci_s3c_get_min_clock, 2360d1bb41aSBen Dooks }; 2370d1bb41aSBen Dooks 2380d1bb41aSBen Dooks static int __devinit sdhci_s3c_probe(struct platform_device *pdev) 2390d1bb41aSBen Dooks { 2400d1bb41aSBen Dooks struct s3c_sdhci_platdata *pdata = pdev->dev.platform_data; 2410d1bb41aSBen Dooks struct device *dev = &pdev->dev; 2420d1bb41aSBen Dooks struct sdhci_host *host; 2430d1bb41aSBen Dooks struct sdhci_s3c *sc; 2440d1bb41aSBen Dooks struct resource *res; 2450d1bb41aSBen Dooks int ret, irq, ptr, clks; 2460d1bb41aSBen Dooks 2470d1bb41aSBen Dooks if (!pdata) { 2480d1bb41aSBen Dooks dev_err(dev, "no device data specified\n"); 2490d1bb41aSBen Dooks return -ENOENT; 2500d1bb41aSBen Dooks } 2510d1bb41aSBen Dooks 2520d1bb41aSBen Dooks irq = platform_get_irq(pdev, 0); 2530d1bb41aSBen Dooks if (irq < 0) { 2540d1bb41aSBen Dooks dev_err(dev, "no irq specified\n"); 2550d1bb41aSBen Dooks return irq; 2560d1bb41aSBen Dooks } 2570d1bb41aSBen Dooks 2580d1bb41aSBen Dooks res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2590d1bb41aSBen Dooks if (!res) { 2600d1bb41aSBen Dooks dev_err(dev, "no memory specified\n"); 2610d1bb41aSBen Dooks return -ENOENT; 2620d1bb41aSBen Dooks } 2630d1bb41aSBen Dooks 2640d1bb41aSBen Dooks host = sdhci_alloc_host(dev, sizeof(struct sdhci_s3c)); 2650d1bb41aSBen Dooks if (IS_ERR(host)) { 2660d1bb41aSBen Dooks dev_err(dev, "sdhci_alloc_host() failed\n"); 2670d1bb41aSBen Dooks return PTR_ERR(host); 2680d1bb41aSBen Dooks } 2690d1bb41aSBen Dooks 2700d1bb41aSBen Dooks sc = sdhci_priv(host); 2710d1bb41aSBen Dooks 2720d1bb41aSBen Dooks sc->host = host; 2730d1bb41aSBen Dooks sc->pdev = pdev; 2740d1bb41aSBen Dooks sc->pdata = pdata; 2750d1bb41aSBen Dooks 2760d1bb41aSBen Dooks platform_set_drvdata(pdev, host); 2770d1bb41aSBen Dooks 2780d1bb41aSBen Dooks sc->clk_io = clk_get(dev, "hsmmc"); 2790d1bb41aSBen Dooks if (IS_ERR(sc->clk_io)) { 2800d1bb41aSBen Dooks dev_err(dev, "failed to get io clock\n"); 2810d1bb41aSBen Dooks ret = PTR_ERR(sc->clk_io); 2820d1bb41aSBen Dooks goto err_io_clk; 2830d1bb41aSBen Dooks } 2840d1bb41aSBen Dooks 2850d1bb41aSBen Dooks /* enable the local io clock and keep it running for the moment. */ 2860d1bb41aSBen Dooks clk_enable(sc->clk_io); 2870d1bb41aSBen Dooks 2880d1bb41aSBen Dooks for (clks = 0, ptr = 0; ptr < MAX_BUS_CLK; ptr++) { 2890d1bb41aSBen Dooks struct clk *clk; 2900d1bb41aSBen Dooks char *name = pdata->clocks[ptr]; 2910d1bb41aSBen Dooks 2920d1bb41aSBen Dooks if (name == NULL) 2930d1bb41aSBen Dooks continue; 2940d1bb41aSBen Dooks 2950d1bb41aSBen Dooks clk = clk_get(dev, name); 2960d1bb41aSBen Dooks if (IS_ERR(clk)) { 2970d1bb41aSBen Dooks dev_err(dev, "failed to get clock %s\n", name); 2980d1bb41aSBen Dooks continue; 2990d1bb41aSBen Dooks } 3000d1bb41aSBen Dooks 3010d1bb41aSBen Dooks clks++; 3020d1bb41aSBen Dooks sc->clk_bus[ptr] = clk; 3030d1bb41aSBen Dooks clk_enable(clk); 3040d1bb41aSBen Dooks 3050d1bb41aSBen Dooks dev_info(dev, "clock source %d: %s (%ld Hz)\n", 3060d1bb41aSBen Dooks ptr, name, clk_get_rate(clk)); 3070d1bb41aSBen Dooks } 3080d1bb41aSBen Dooks 3090d1bb41aSBen Dooks if (clks == 0) { 3100d1bb41aSBen Dooks dev_err(dev, "failed to find any bus clocks\n"); 3110d1bb41aSBen Dooks ret = -ENOENT; 3120d1bb41aSBen Dooks goto err_no_busclks; 3130d1bb41aSBen Dooks } 3140d1bb41aSBen Dooks 3150d1bb41aSBen Dooks sc->ioarea = request_mem_region(res->start, resource_size(res), 3160d1bb41aSBen Dooks mmc_hostname(host->mmc)); 3170d1bb41aSBen Dooks if (!sc->ioarea) { 3180d1bb41aSBen Dooks dev_err(dev, "failed to reserve register area\n"); 3190d1bb41aSBen Dooks ret = -ENXIO; 3200d1bb41aSBen Dooks goto err_req_regs; 3210d1bb41aSBen Dooks } 3220d1bb41aSBen Dooks 3230d1bb41aSBen Dooks host->ioaddr = ioremap_nocache(res->start, resource_size(res)); 3240d1bb41aSBen Dooks if (!host->ioaddr) { 3250d1bb41aSBen Dooks dev_err(dev, "failed to map registers\n"); 3260d1bb41aSBen Dooks ret = -ENXIO; 3270d1bb41aSBen Dooks goto err_req_regs; 3280d1bb41aSBen Dooks } 3290d1bb41aSBen Dooks 3300d1bb41aSBen Dooks /* Ensure we have minimal gpio selected CMD/CLK/Detect */ 3310d1bb41aSBen Dooks if (pdata->cfg_gpio) 3320d1bb41aSBen Dooks pdata->cfg_gpio(pdev, pdata->max_width); 3330d1bb41aSBen Dooks 3340d1bb41aSBen Dooks host->hw_name = "samsung-hsmmc"; 3350d1bb41aSBen Dooks host->ops = &sdhci_s3c_ops; 3360d1bb41aSBen Dooks host->quirks = 0; 3370d1bb41aSBen Dooks host->irq = irq; 3380d1bb41aSBen Dooks 3390d1bb41aSBen Dooks /* Setup quirks for the controller */ 340b2e75effSThomas Abraham host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC; 3410d1bb41aSBen Dooks 3420d1bb41aSBen Dooks #ifndef CONFIG_MMC_SDHCI_S3C_DMA 3430d1bb41aSBen Dooks 3440d1bb41aSBen Dooks /* we currently see overruns on errors, so disable the SDMA 3450d1bb41aSBen Dooks * support as well. */ 3460d1bb41aSBen Dooks host->quirks |= SDHCI_QUIRK_BROKEN_DMA; 3470d1bb41aSBen Dooks 3480d1bb41aSBen Dooks #endif /* CONFIG_MMC_SDHCI_S3C_DMA */ 3490d1bb41aSBen Dooks 3500d1bb41aSBen Dooks /* It seems we do not get an DATA transfer complete on non-busy 3510d1bb41aSBen Dooks * transfers, not sure if this is a problem with this specific 3520d1bb41aSBen Dooks * SDHCI block, or a missing configuration that needs to be set. */ 3530d1bb41aSBen Dooks host->quirks |= SDHCI_QUIRK_NO_BUSY_IRQ; 3540d1bb41aSBen Dooks 3550d1bb41aSBen Dooks host->quirks |= (SDHCI_QUIRK_32BIT_DMA_ADDR | 3560d1bb41aSBen Dooks SDHCI_QUIRK_32BIT_DMA_SIZE); 3570d1bb41aSBen Dooks 3583fe42e07SHyuk Lee /* HSMMC on Samsung SoCs uses SDCLK as timeout clock */ 3593fe42e07SHyuk Lee host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK; 3603fe42e07SHyuk Lee 3610d1bb41aSBen Dooks ret = sdhci_add_host(host); 3620d1bb41aSBen Dooks if (ret) { 3630d1bb41aSBen Dooks dev_err(dev, "sdhci_add_host() failed\n"); 3640d1bb41aSBen Dooks goto err_add_host; 3650d1bb41aSBen Dooks } 3660d1bb41aSBen Dooks 3670d1bb41aSBen Dooks return 0; 3680d1bb41aSBen Dooks 3690d1bb41aSBen Dooks err_add_host: 3700d1bb41aSBen Dooks release_resource(sc->ioarea); 3710d1bb41aSBen Dooks kfree(sc->ioarea); 3720d1bb41aSBen Dooks 3730d1bb41aSBen Dooks err_req_regs: 3740d1bb41aSBen Dooks for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) { 3750d1bb41aSBen Dooks clk_disable(sc->clk_bus[ptr]); 3760d1bb41aSBen Dooks clk_put(sc->clk_bus[ptr]); 3770d1bb41aSBen Dooks } 3780d1bb41aSBen Dooks 3790d1bb41aSBen Dooks err_no_busclks: 3800d1bb41aSBen Dooks clk_disable(sc->clk_io); 3810d1bb41aSBen Dooks clk_put(sc->clk_io); 3820d1bb41aSBen Dooks 3830d1bb41aSBen Dooks err_io_clk: 3840d1bb41aSBen Dooks sdhci_free_host(host); 3850d1bb41aSBen Dooks 3860d1bb41aSBen Dooks return ret; 3870d1bb41aSBen Dooks } 3880d1bb41aSBen Dooks 3890d1bb41aSBen Dooks static int __devexit sdhci_s3c_remove(struct platform_device *pdev) 3900d1bb41aSBen Dooks { 3919d51a6b2SMarek Szyprowski struct sdhci_host *host = platform_get_drvdata(pdev); 3929d51a6b2SMarek Szyprowski struct sdhci_s3c *sc = sdhci_priv(host); 3939d51a6b2SMarek Szyprowski int ptr; 3949d51a6b2SMarek Szyprowski 3959d51a6b2SMarek Szyprowski sdhci_remove_host(host, 1); 3969d51a6b2SMarek Szyprowski 3979d51a6b2SMarek Szyprowski for (ptr = 0; ptr < 3; ptr++) { 3989d51a6b2SMarek Szyprowski clk_disable(sc->clk_bus[ptr]); 3999d51a6b2SMarek Szyprowski clk_put(sc->clk_bus[ptr]); 4009d51a6b2SMarek Szyprowski } 4019d51a6b2SMarek Szyprowski clk_disable(sc->clk_io); 4029d51a6b2SMarek Szyprowski clk_put(sc->clk_io); 4039d51a6b2SMarek Szyprowski 4049d51a6b2SMarek Szyprowski iounmap(host->ioaddr); 4059d51a6b2SMarek Szyprowski release_resource(sc->ioarea); 4069d51a6b2SMarek Szyprowski kfree(sc->ioarea); 4079d51a6b2SMarek Szyprowski 4089d51a6b2SMarek Szyprowski sdhci_free_host(host); 4099d51a6b2SMarek Szyprowski platform_set_drvdata(pdev, NULL); 4109d51a6b2SMarek Szyprowski 4110d1bb41aSBen Dooks return 0; 4120d1bb41aSBen Dooks } 4130d1bb41aSBen Dooks 4140d1bb41aSBen Dooks #ifdef CONFIG_PM 4150d1bb41aSBen Dooks 4160d1bb41aSBen Dooks static int sdhci_s3c_suspend(struct platform_device *dev, pm_message_t pm) 4170d1bb41aSBen Dooks { 4180d1bb41aSBen Dooks struct sdhci_host *host = platform_get_drvdata(dev); 4190d1bb41aSBen Dooks 4200d1bb41aSBen Dooks sdhci_suspend_host(host, pm); 4210d1bb41aSBen Dooks return 0; 4220d1bb41aSBen Dooks } 4230d1bb41aSBen Dooks 4240d1bb41aSBen Dooks static int sdhci_s3c_resume(struct platform_device *dev) 4250d1bb41aSBen Dooks { 4260d1bb41aSBen Dooks struct sdhci_host *host = platform_get_drvdata(dev); 4270d1bb41aSBen Dooks 4280d1bb41aSBen Dooks sdhci_resume_host(host); 4290d1bb41aSBen Dooks return 0; 4300d1bb41aSBen Dooks } 4310d1bb41aSBen Dooks 4320d1bb41aSBen Dooks #else 4330d1bb41aSBen Dooks #define sdhci_s3c_suspend NULL 4340d1bb41aSBen Dooks #define sdhci_s3c_resume NULL 4350d1bb41aSBen Dooks #endif 4360d1bb41aSBen Dooks 4370d1bb41aSBen Dooks static struct platform_driver sdhci_s3c_driver = { 4380d1bb41aSBen Dooks .probe = sdhci_s3c_probe, 4390d1bb41aSBen Dooks .remove = __devexit_p(sdhci_s3c_remove), 4400d1bb41aSBen Dooks .suspend = sdhci_s3c_suspend, 4410d1bb41aSBen Dooks .resume = sdhci_s3c_resume, 4420d1bb41aSBen Dooks .driver = { 4430d1bb41aSBen Dooks .owner = THIS_MODULE, 4440d1bb41aSBen Dooks .name = "s3c-sdhci", 4450d1bb41aSBen Dooks }, 4460d1bb41aSBen Dooks }; 4470d1bb41aSBen Dooks 4480d1bb41aSBen Dooks static int __init sdhci_s3c_init(void) 4490d1bb41aSBen Dooks { 4500d1bb41aSBen Dooks return platform_driver_register(&sdhci_s3c_driver); 4510d1bb41aSBen Dooks } 4520d1bb41aSBen Dooks 4530d1bb41aSBen Dooks static void __exit sdhci_s3c_exit(void) 4540d1bb41aSBen Dooks { 4550d1bb41aSBen Dooks platform_driver_unregister(&sdhci_s3c_driver); 4560d1bb41aSBen Dooks } 4570d1bb41aSBen Dooks 4580d1bb41aSBen Dooks module_init(sdhci_s3c_init); 4590d1bb41aSBen Dooks module_exit(sdhci_s3c_exit); 4600d1bb41aSBen Dooks 4610d1bb41aSBen Dooks MODULE_DESCRIPTION("Samsung SDHCI (HSMMC) glue"); 4620d1bb41aSBen Dooks MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); 4630d1bb41aSBen Dooks MODULE_LICENSE("GPL v2"); 4640d1bb41aSBen Dooks MODULE_ALIAS("platform:s3c-sdhci"); 465