xref: /openbmc/linux/drivers/mmc/host/sdhci-s3c.c (revision ce5f036b)
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