summaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/au1xmmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/au1xmmc.c')
-rw-r--r--drivers/mmc/host/au1xmmc.c198
1 files changed, 107 insertions, 91 deletions
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
index f5443a6c4915..9c9f6af29251 100644
--- a/drivers/mmc/host/au1xmmc.c
+++ b/drivers/mmc/host/au1xmmc.c
@@ -32,6 +32,7 @@
* (the low to high transition will not occur).
*/
+#include <linux/clk.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
@@ -90,7 +91,7 @@ struct au1xmmc_host {
struct mmc_request *mrq;
u32 flags;
- u32 iobase;
+ void __iomem *iobase;
u32 clock;
u32 bus_width;
u32 power_mode;
@@ -118,6 +119,7 @@ struct au1xmmc_host {
struct au1xmmc_platform_data *platdata;
struct platform_device *pdev;
struct resource *ioarea;
+ struct clk *clk;
};
/* Status flags used by the host structure */
@@ -162,32 +164,33 @@ static inline int has_dbdma(void)
static inline void IRQ_ON(struct au1xmmc_host *host, u32 mask)
{
- u32 val = au_readl(HOST_CONFIG(host));
+ u32 val = __raw_readl(HOST_CONFIG(host));
val |= mask;
- au_writel(val, HOST_CONFIG(host));
- au_sync();
+ __raw_writel(val, HOST_CONFIG(host));
+ wmb(); /* drain writebuffer */
}
static inline void FLUSH_FIFO(struct au1xmmc_host *host)
{
- u32 val = au_readl(HOST_CONFIG2(host));
+ u32 val = __raw_readl(HOST_CONFIG2(host));
- au_writel(val | SD_CONFIG2_FF, HOST_CONFIG2(host));
- au_sync_delay(1);
+ __raw_writel(val | SD_CONFIG2_FF, HOST_CONFIG2(host));
+ wmb(); /* drain writebuffer */
+ mdelay(1);
/* SEND_STOP will turn off clock control - this re-enables it */
val &= ~SD_CONFIG2_DF;
- au_writel(val, HOST_CONFIG2(host));
- au_sync();
+ __raw_writel(val, HOST_CONFIG2(host));
+ wmb(); /* drain writebuffer */
}
static inline void IRQ_OFF(struct au1xmmc_host *host, u32 mask)
{
- u32 val = au_readl(HOST_CONFIG(host));
+ u32 val = __raw_readl(HOST_CONFIG(host));
val &= ~mask;
- au_writel(val, HOST_CONFIG(host));
- au_sync();
+ __raw_writel(val, HOST_CONFIG(host));
+ wmb(); /* drain writebuffer */
}
static inline void SEND_STOP(struct au1xmmc_host *host)
@@ -197,12 +200,13 @@ static inline void SEND_STOP(struct au1xmmc_host *host)
WARN_ON(host->status != HOST_S_DATA);
host->status = HOST_S_STOP;
- config2 = au_readl(HOST_CONFIG2(host));
- au_writel(config2 | SD_CONFIG2_DF, HOST_CONFIG2(host));
- au_sync();
+ config2 = __raw_readl(HOST_CONFIG2(host));
+ __raw_writel(config2 | SD_CONFIG2_DF, HOST_CONFIG2(host));
+ wmb(); /* drain writebuffer */
/* Send the stop command */
- au_writel(STOP_CMD, HOST_CMD(host));
+ __raw_writel(STOP_CMD, HOST_CMD(host));
+ wmb(); /* drain writebuffer */
}
static void au1xmmc_set_power(struct au1xmmc_host *host, int state)
@@ -296,28 +300,28 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
}
}
- au_writel(cmd->arg, HOST_CMDARG(host));
- au_sync();
+ __raw_writel(cmd->arg, HOST_CMDARG(host));
+ wmb(); /* drain writebuffer */
if (wait)
IRQ_OFF(host, SD_CONFIG_CR);
- au_writel((mmccmd | SD_CMD_GO), HOST_CMD(host));
- au_sync();
+ __raw_writel((mmccmd | SD_CMD_GO), HOST_CMD(host));
+ wmb(); /* drain writebuffer */
/* Wait for the command to go on the line */
- while (au_readl(HOST_CMD(host)) & SD_CMD_GO)
+ while (__raw_readl(HOST_CMD(host)) & SD_CMD_GO)
/* nop */;
/* Wait for the command to come back */
if (wait) {
- u32 status = au_readl(HOST_STATUS(host));
+ u32 status = __raw_readl(HOST_STATUS(host));
while (!(status & SD_STATUS_CR))
- status = au_readl(HOST_STATUS(host));
+ status = __raw_readl(HOST_STATUS(host));
/* Clear the CR status */
- au_writel(SD_STATUS_CR, HOST_STATUS(host));
+ __raw_writel(SD_STATUS_CR, HOST_STATUS(host));
IRQ_ON(host, SD_CONFIG_CR);
}
@@ -339,11 +343,11 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
data = mrq->cmd->data;
if (status == 0)
- status = au_readl(HOST_STATUS(host));
+ status = __raw_readl(HOST_STATUS(host));
/* The transaction is really over when the SD_STATUS_DB bit is clear */
while ((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB))
- status = au_readl(HOST_STATUS(host));
+ status = __raw_readl(HOST_STATUS(host));
data->error = 0;
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma.dir);
@@ -357,7 +361,7 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
data->error = -EILSEQ;
/* Clear the CRC bits */
- au_writel(SD_STATUS_WC | SD_STATUS_RC, HOST_STATUS(host));
+ __raw_writel(SD_STATUS_WC | SD_STATUS_RC, HOST_STATUS(host));
data->bytes_xfered = 0;
@@ -380,7 +384,7 @@ static void au1xmmc_tasklet_data(unsigned long param)
{
struct au1xmmc_host *host = (struct au1xmmc_host *)param;
- u32 status = au_readl(HOST_STATUS(host));
+ u32 status = __raw_readl(HOST_STATUS(host));
au1xmmc_data_complete(host, status);
}
@@ -412,15 +416,15 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host)
max = AU1XMMC_MAX_TRANSFER;
for (count = 0; count < max; count++) {
- status = au_readl(HOST_STATUS(host));
+ status = __raw_readl(HOST_STATUS(host));
if (!(status & SD_STATUS_TH))
break;
val = *sg_ptr++;
- au_writel((unsigned long)val, HOST_TXPORT(host));
- au_sync();
+ __raw_writel((unsigned long)val, HOST_TXPORT(host));
+ wmb(); /* drain writebuffer */
}
host->pio.len -= count;
@@ -472,7 +476,7 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host)
max = AU1XMMC_MAX_TRANSFER;
for (count = 0; count < max; count++) {
- status = au_readl(HOST_STATUS(host));
+ status = __raw_readl(HOST_STATUS(host));
if (!(status & SD_STATUS_NE))
break;
@@ -494,7 +498,7 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host)
break;
}
- val = au_readl(HOST_RXPORT(host));
+ val = __raw_readl(HOST_RXPORT(host));
if (sg_ptr)
*sg_ptr++ = (unsigned char)(val & 0xFF);
@@ -537,10 +541,10 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
if (cmd->flags & MMC_RSP_PRESENT) {
if (cmd->flags & MMC_RSP_136) {
- r[0] = au_readl(host->iobase + SD_RESP3);
- r[1] = au_readl(host->iobase + SD_RESP2);
- r[2] = au_readl(host->iobase + SD_RESP1);
- r[3] = au_readl(host->iobase + SD_RESP0);
+ r[0] = __raw_readl(host->iobase + SD_RESP3);
+ r[1] = __raw_readl(host->iobase + SD_RESP2);
+ r[2] = __raw_readl(host->iobase + SD_RESP1);
+ r[3] = __raw_readl(host->iobase + SD_RESP0);
/* The CRC is omitted from the response, so really
* we only got 120 bytes, but the engine expects
@@ -559,7 +563,7 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
* that means that the OSR data starts at bit 31,
* so we can just read RESP0 and return that.
*/
- cmd->resp[0] = au_readl(host->iobase + SD_RESP0);
+ cmd->resp[0] = __raw_readl(host->iobase + SD_RESP0);
}
}
@@ -586,7 +590,7 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
u32 mask = SD_STATUS_DB | SD_STATUS_NE;
while((status & mask) != mask)
- status = au_readl(HOST_STATUS(host));
+ status = __raw_readl(HOST_STATUS(host));
}
au1xxx_dbdma_start(channel);
@@ -595,24 +599,17 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
static void au1xmmc_set_clock(struct au1xmmc_host *host, int rate)
{
- unsigned int pbus = get_au1x00_speed();
- unsigned int divisor;
+ unsigned int pbus = clk_get_rate(host->clk);
+ unsigned int divisor = ((pbus / rate) / 2) - 1;
u32 config;
- /* From databook:
- * divisor = ((((cpuclock / sbus_divisor) / 2) / mmcclock) / 2) - 1
- */
- pbus /= ((au_readl(SYS_POWERCTRL) & 0x3) + 2);
- pbus /= 2;
- divisor = ((pbus / rate) / 2) - 1;
-
- config = au_readl(HOST_CONFIG(host));
+ config = __raw_readl(HOST_CONFIG(host));
config &= ~(SD_CONFIG_DIV);
config |= (divisor & SD_CONFIG_DIV) | SD_CONFIG_DE;
- au_writel(config, HOST_CONFIG(host));
- au_sync();
+ __raw_writel(config, HOST_CONFIG(host));
+ wmb(); /* drain writebuffer */
}
static int au1xmmc_prepare_data(struct au1xmmc_host *host,
@@ -636,7 +633,7 @@ static int au1xmmc_prepare_data(struct au1xmmc_host *host,
if (host->dma.len == 0)
return -ETIMEDOUT;
- au_writel(data->blksz - 1, HOST_BLKSIZE(host));
+ __raw_writel(data->blksz - 1, HOST_BLKSIZE(host));
if (host->flags & (HOST_F_DMA | HOST_F_DBDMA)) {
int i;
@@ -723,31 +720,34 @@ static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq)
static void au1xmmc_reset_controller(struct au1xmmc_host *host)
{
/* Apply the clock */
- au_writel(SD_ENABLE_CE, HOST_ENABLE(host));
- au_sync_delay(1);
+ __raw_writel(SD_ENABLE_CE, HOST_ENABLE(host));
+ wmb(); /* drain writebuffer */
+ mdelay(1);
- au_writel(SD_ENABLE_R | SD_ENABLE_CE, HOST_ENABLE(host));
- au_sync_delay(5);
+ __raw_writel(SD_ENABLE_R | SD_ENABLE_CE, HOST_ENABLE(host));
+ wmb(); /* drain writebuffer */
+ mdelay(5);
- au_writel(~0, HOST_STATUS(host));
- au_sync();
+ __raw_writel(~0, HOST_STATUS(host));
+ wmb(); /* drain writebuffer */
- au_writel(0, HOST_BLKSIZE(host));
- au_writel(0x001fffff, HOST_TIMEOUT(host));
- au_sync();
+ __raw_writel(0, HOST_BLKSIZE(host));
+ __raw_writel(0x001fffff, HOST_TIMEOUT(host));
+ wmb(); /* drain writebuffer */
- au_writel(SD_CONFIG2_EN, HOST_CONFIG2(host));
- au_sync();
+ __raw_writel(SD_CONFIG2_EN, HOST_CONFIG2(host));
+ wmb(); /* drain writebuffer */
- au_writel(SD_CONFIG2_EN | SD_CONFIG2_FF, HOST_CONFIG2(host));
- au_sync_delay(1);
+ __raw_writel(SD_CONFIG2_EN | SD_CONFIG2_FF, HOST_CONFIG2(host));
+ wmb(); /* drain writebuffer */
+ mdelay(1);
- au_writel(SD_CONFIG2_EN, HOST_CONFIG2(host));
- au_sync();
+ __raw_writel(SD_CONFIG2_EN, HOST_CONFIG2(host));
+ wmb(); /* drain writebuffer */
/* Configure interrupts */
- au_writel(AU1XMMC_INTERRUPTS, HOST_CONFIG(host));
- au_sync();
+ __raw_writel(AU1XMMC_INTERRUPTS, HOST_CONFIG(host));
+ wmb(); /* drain writebuffer */
}
@@ -767,7 +767,7 @@ static void au1xmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
host->clock = ios->clock;
}
- config2 = au_readl(HOST_CONFIG2(host));
+ config2 = __raw_readl(HOST_CONFIG2(host));
switch (ios->bus_width) {
case MMC_BUS_WIDTH_8:
config2 |= SD_CONFIG2_BB;
@@ -780,8 +780,8 @@ static void au1xmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
config2 &= ~(SD_CONFIG2_WB | SD_CONFIG2_BB);
break;
}
- au_writel(config2, HOST_CONFIG2(host));
- au_sync();
+ __raw_writel(config2, HOST_CONFIG2(host));
+ wmb(); /* drain writebuffer */
}
#define STATUS_TIMEOUT (SD_STATUS_RAT | SD_STATUS_DT)
@@ -793,7 +793,7 @@ static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
struct au1xmmc_host *host = dev_id;
u32 status;
- status = au_readl(HOST_STATUS(host));
+ status = __raw_readl(HOST_STATUS(host));
if (!(status & SD_STATUS_I))
return IRQ_NONE; /* not ours */
@@ -839,8 +839,8 @@ static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
status);
}
- au_writel(status, HOST_STATUS(host));
- au_sync();
+ __raw_writel(status, HOST_STATUS(host));
+ wmb(); /* drain writebuffer */
return IRQ_HANDLED;
}
@@ -976,7 +976,7 @@ static int au1xmmc_probe(struct platform_device *pdev)
goto out1;
}
- host->iobase = (unsigned long)ioremap(r->start, 0x3c);
+ host->iobase = ioremap(r->start, 0x3c);
if (!host->iobase) {
dev_err(&pdev->dev, "cannot remap mmio\n");
goto out2;
@@ -1025,6 +1025,16 @@ static int au1xmmc_probe(struct platform_device *pdev)
goto out3;
}
+ host->clk = clk_get(&pdev->dev, ALCHEMY_PERIPH_CLK);
+ if (IS_ERR(host->clk)) {
+ dev_err(&pdev->dev, "cannot find clock\n");
+ goto out_irq;
+ }
+ if (clk_prepare_enable(host->clk)) {
+ dev_err(&pdev->dev, "cannot enable clock\n");
+ goto out_clk;
+ }
+
host->status = HOST_S_IDLE;
/* board-specific carddetect setup, if any */
@@ -1075,7 +1085,7 @@ static int au1xmmc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, host);
- pr_info(DRIVER_NAME ": MMC Controller %d set up at %8.8X"
+ pr_info(DRIVER_NAME ": MMC Controller %d set up at %p"
" (mode=%s)\n", pdev->id, host->iobase,
host->flags & HOST_F_DMA ? "dma" : "pio");
@@ -1087,10 +1097,10 @@ out6:
led_classdev_unregister(host->platdata->led);
out5:
#endif
- au_writel(0, HOST_ENABLE(host));
- au_writel(0, HOST_CONFIG(host));
- au_writel(0, HOST_CONFIG2(host));
- au_sync();
+ __raw_writel(0, HOST_ENABLE(host));
+ __raw_writel(0, HOST_CONFIG(host));
+ __raw_writel(0, HOST_CONFIG2(host));
+ wmb(); /* drain writebuffer */
if (host->flags & HOST_F_DBDMA)
au1xmmc_dbdma_shutdown(host);
@@ -1101,7 +1111,10 @@ out5:
if (host->platdata && host->platdata->cd_setup &&
!(mmc->caps & MMC_CAP_NEEDS_POLL))
host->platdata->cd_setup(mmc, 0);
-
+out_clk:
+ clk_disable_unprepare(host->clk);
+ clk_put(host->clk);
+out_irq:
free_irq(host->irq, host);
out3:
iounmap((void *)host->iobase);
@@ -1130,10 +1143,10 @@ static int au1xmmc_remove(struct platform_device *pdev)
!(host->mmc->caps & MMC_CAP_NEEDS_POLL))
host->platdata->cd_setup(host->mmc, 0);
- au_writel(0, HOST_ENABLE(host));
- au_writel(0, HOST_CONFIG(host));
- au_writel(0, HOST_CONFIG2(host));
- au_sync();
+ __raw_writel(0, HOST_ENABLE(host));
+ __raw_writel(0, HOST_CONFIG(host));
+ __raw_writel(0, HOST_CONFIG2(host));
+ wmb(); /* drain writebuffer */
tasklet_kill(&host->data_task);
tasklet_kill(&host->finish_task);
@@ -1143,6 +1156,9 @@ static int au1xmmc_remove(struct platform_device *pdev)
au1xmmc_set_power(host, 0);
+ clk_disable_unprepare(host->clk);
+ clk_put(host->clk);
+
free_irq(host->irq, host);
iounmap((void *)host->iobase);
release_resource(host->ioarea);
@@ -1158,11 +1174,11 @@ static int au1xmmc_suspend(struct platform_device *pdev, pm_message_t state)
{
struct au1xmmc_host *host = platform_get_drvdata(pdev);
- au_writel(0, HOST_CONFIG2(host));
- au_writel(0, HOST_CONFIG(host));
- au_writel(0xffffffff, HOST_STATUS(host));
- au_writel(0, HOST_ENABLE(host));
- au_sync();
+ __raw_writel(0, HOST_CONFIG2(host));
+ __raw_writel(0, HOST_CONFIG(host));
+ __raw_writel(0xffffffff, HOST_STATUS(host));
+ __raw_writel(0, HOST_ENABLE(host));
+ wmb(); /* drain writebuffer */
return 0;
}