summaryrefslogtreecommitdiffstats
path: root/drivers/mci/atmel-sdhci-common.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mci/atmel-sdhci-common.c')
-rw-r--r--drivers/mci/atmel-sdhci-common.c168
1 files changed, 53 insertions, 115 deletions
diff --git a/drivers/mci/atmel-sdhci-common.c b/drivers/mci/atmel-sdhci-common.c
index 680b1980c0..082ce842f7 100644
--- a/drivers/mci/atmel-sdhci-common.c
+++ b/drivers/mci/atmel-sdhci-common.c
@@ -11,10 +11,19 @@
#include <common.h>
#include <mci.h>
+#include <linux/bitfield.h>
-#include "atmel-sdhci.h"
+#include <mach/at91/early_udelay.h>
+
+#ifdef __PBL__
+#define udelay early_udelay
+#undef dev_err
+#define dev_err(d, ...) pr_err(__VA_ARGS__)
+#undef dev_warn
+#define dev_warn(d, ...) pr_warn(__VA_ARGS__)
+#endif
-#define AT91_SDHCI_CA1R 0x44 /* Capabilities 1 Register */
+#include "atmel-sdhci.h"
#define AT91_SDHCI_MC1R 0x204
#define AT91_SDHCI_MC1_FCD BIT(7)
@@ -30,15 +39,15 @@ static inline struct at91_sdhci *to_priv(struct sdhci *sdhci)
void at91_sdhci_host_capability(struct at91_sdhci *host,
unsigned *voltages)
{
- u16 caps;
+ u32 caps;
- caps = sdhci_read16(&host->sdhci, SDHCI_CAPABILITIES_1);
+ caps = sdhci_read32(&host->sdhci, SDHCI_CAPABILITIES);
- if (caps & SDHCI_HOSTCAP_VOLTAGE_330)
+ if (caps & SDHCI_CAN_VDD_330)
*voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
- if (caps & SDHCI_HOSTCAP_VOLTAGE_300)
+ if (caps & SDHCI_CAN_VDD_300)
*voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
- if (caps & SDHCI_HOSTCAP_VOLTAGE_180)
+ if (caps & SDHCI_CAN_VDD_180)
*voltages |= MMC_VDD_165_195;
}
@@ -80,49 +89,18 @@ exit:
return is_inserted;
}
-static int at91_sdhci_wait_for_done(struct at91_sdhci *host, u32 mask)
-{
- struct sdhci *sdhci = &host->sdhci;
- u16 status;
- int ret;
-
- ret = sdhci_read16_poll_timeout(sdhci, SDHCI_INT_NORMAL_STATUS, status,
- (status & mask) == mask || (status & SDHCI_INT_ERROR),
- USEC_PER_SEC);
-
- if (ret < 0) {
- pr_err("SDHCI timeout while waiting for done\n");
- return ret;
- }
-
- if (status & SDHCI_INT_ERROR) {
- pr_err("SDHCI_INT_ERROR: 0x%08x\n",
- sdhci_read16(sdhci, SDHCI_INT_ERROR_STATUS));
- return -EPERM;
- }
-
- return status;
-}
-
int at91_sdhci_send_command(struct at91_sdhci *host, struct mci_cmd *cmd,
struct mci_data *data)
{
unsigned command, xfer;
struct sdhci *sdhci = &host->sdhci;
- u32 mask, status, state;
+ u32 mask;
+ int status;
int ret;
- /* Wait for idle before next command */
- mask = SDHCI_CMD_INHIBIT_CMD;
- if (cmd->cmdidx != MMC_CMD_STOP_TRANSMISSION)
- mask |= SDHCI_CMD_INHIBIT_DATA;
-
- ret = sdhci_read32_poll_timeout(sdhci, SDHCI_PRESENT_STATE, state,
- !(state & mask), 100 * USEC_PER_MSEC);
- if (ret) {
- pr_err("timeout while waiting for idle\n");
+ ret = sdhci_wait_idle_data(&host->sdhci, cmd);
+ if (ret)
return ret;
- }
sdhci_write32(sdhci, SDHCI_INT_STATUS, ~0U);
@@ -146,29 +124,30 @@ int at91_sdhci_send_command(struct at91_sdhci *host, struct mci_cmd *cmd,
sdhci_write32(sdhci, SDHCI_ARGUMENT, cmd->cmdarg);
sdhci_write16(sdhci, SDHCI_COMMAND, command);
- status = at91_sdhci_wait_for_done(host, mask);
- if (status >= 0 && (status & (SDHCI_INT_ERROR | mask)) == mask) {
- sdhci_read_response(sdhci, cmd);
- sdhci_write32(sdhci, SDHCI_INT_STATUS, mask);
-
- if (data)
- sdhci_transfer_data(sdhci, data);
+ status = sdhci_wait_for_done(&host->sdhci, mask);
+ if (status < 0)
+ goto error;
- udelay(1000);
+ sdhci_read_response(sdhci, cmd);
+ sdhci_write32(sdhci, SDHCI_INT_STATUS, mask);
- status = sdhci_read32(sdhci, SDHCI_INT_STATUS);
- sdhci_write32(sdhci, SDHCI_INT_STATUS, ~0U);
+ if (data)
+ sdhci_transfer_data_pio(sdhci, data);
- return 0;
- }
+ udelay(1000);
status = sdhci_read32(sdhci, SDHCI_INT_STATUS);
sdhci_write32(sdhci, SDHCI_INT_STATUS, ~0U);
+ return 0;
+
+error:
+ sdhci_write32(sdhci, SDHCI_INT_STATUS, ~0U);
+
sdhci_reset(sdhci, SDHCI_RESET_CMD);
sdhci_reset(sdhci, SDHCI_RESET_DATA);
- return status & SDHCI_INT_TIMEOUT ? -ETIMEDOUT : -ECOMM;
+ return status;
}
static void at91_sdhci_set_power(struct at91_sdhci *host, unsigned vdd)
@@ -206,26 +185,21 @@ static int at91_sdhci_set_clock(struct at91_sdhci *host, unsigned clock)
struct sdhci *sdhci = &host->sdhci;
unsigned clk = 0, clk_div;
unsigned reg;
- u32 present_mask, caps, caps_clk_mult;
+ u32 caps, caps_clk_mult;
int ret;
- present_mask = SDHCI_CMD_INHIBIT_CMD | SDHCI_CMD_INHIBIT_DATA;
- ret = sdhci_read32_poll_timeout(sdhci, SDHCI_PRESENT_STATE, reg,
- !(reg & present_mask),
- 100 * USEC_PER_MSEC);
- if (ret) {
- pr_warn("Timeout waiting for CMD and DAT Inhibit bits\n");
+ ret = sdhci_wait_idle_data(&host->sdhci, NULL);
+ if (ret)
return ret;
- }
sdhci_write16(sdhci, SDHCI_CLOCK_CONTROL, 0);
if (clock == 0)
return 0;
- caps = sdhci_read32(sdhci, AT91_SDHCI_CA1R);
+ caps = sdhci_read32(sdhci, SDHCI_CAPABILITIES_1);
- caps_clk_mult = (caps & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT;
+ caps_clk_mult = FIELD_GET(SDHCI_CLOCK_MUL_MASK, caps);
if (caps_clk_mult) {
for (clk_div = 1; clk_div <= 1024; clk_div++) {
@@ -250,26 +224,26 @@ static int at91_sdhci_set_clock(struct at91_sdhci *host, unsigned clock)
clk |= SDHCI_FREQ_SEL(clk_div);
clk |= ((clk_div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
<< SDHCI_DIVIDER_HI_SHIFT;
- clk |= SDHCI_INTCLOCK_EN;
+ clk |= SDHCI_CLOCK_INT_EN;
sdhci_write16(sdhci, SDHCI_CLOCK_CONTROL, clk);
ret = sdhci_read32_poll_timeout(sdhci, SDHCI_CLOCK_CONTROL, clk,
- clk & SDHCI_INTCLOCK_STABLE,
+ clk & SDHCI_CLOCK_INT_STABLE,
20 * USEC_PER_MSEC);
if (ret) {
- pr_warn("Timeout waiting for clock stable\n");
+ dev_warn(host->dev, "Timeout waiting for clock stable\n");
return ret;
}
- clk |= SDHCI_SDCLOCK_EN;
+ clk |= SDHCI_CLOCK_CARD_EN;
sdhci_write16(sdhci, SDHCI_CLOCK_CONTROL, clk);
reg = sdhci_read8(sdhci, SDHCI_HOST_CONTROL);
if (clock > 26000000)
- reg |= SDHCI_HIGHSPEED_EN;
+ reg |= SDHCI_CTRL_HISPD;
else
- reg &= ~SDHCI_HIGHSPEED_EN;
+ reg &= ~SDHCI_CTRL_HISPD;
sdhci_write8(sdhci, SDHCI_HOST_CONTROL, reg);
@@ -285,15 +259,15 @@ static int at91_sdhci_set_bus_width(struct at91_sdhci *host, unsigned bus_width)
switch(bus_width) {
case MMC_BUS_WIDTH_8:
- reg |= SDHCI_DATA_WIDTH_8BIT;
+ reg |= SDHCI_CTRL_8BITBUS;
break;
case MMC_BUS_WIDTH_4:
- reg &= ~SDHCI_DATA_WIDTH_8BIT;
- reg |= SDHCI_DATA_WIDTH_4BIT;
+ reg &= ~SDHCI_CTRL_8BITBUS;
+ reg |= SDHCI_CTRL_4BITBUS;
break;
default:
- reg &= ~SDHCI_DATA_WIDTH_8BIT;
- reg &= ~SDHCI_DATA_WIDTH_4BIT;
+ reg &= ~SDHCI_CTRL_8BITBUS;
+ reg &= ~SDHCI_CTRL_4BITBUS;
}
sdhci_write8(sdhci, SDHCI_HOST_CONTROL, reg);
@@ -358,50 +332,14 @@ int at91_sdhci_init(struct at91_sdhci *host, u32 maxclk,
}
if (cal_always_on) {
- sdhci_write32(sdhci, AT91_SDHCI_CALCR_ALWYSON | AT91_SDHCI_CALCR_EN,
- AT91_SDHCI_CALCR);
+ sdhci_write32(sdhci, AT91_SDHCI_CALCR,
+ AT91_SDHCI_CALCR_ALWYSON | AT91_SDHCI_CALCR_EN);
}
return 0;
}
-static u32 at91_sdhci_read32(struct sdhci *sdhci, int reg)
-{
- return readl(to_priv(sdhci)->base + reg);
-}
-
-static void at91_sdhci_write32(struct sdhci *sdhci, int reg, u32 value)
-{
- writel(value, to_priv(sdhci)->base + reg);
-}
-
-static u16 at91_sdhci_read16(struct sdhci *sdhci, int reg)
-{
- return readw(to_priv(sdhci)->base + reg);
-}
-
-static void at91_sdhci_write16(struct sdhci *sdhci, int reg, u16 value)
-{
- writew(value, to_priv(sdhci)->base + reg);
-}
-
-static u8 at91_sdhci_read8(struct sdhci *sdhci, int reg)
-{
- return readb(to_priv(sdhci)->base + reg);
-}
-
-static void at91_sdhci_write8(struct sdhci *sdhci, int reg, u8 value)
-{
- writeb(value, to_priv(sdhci)->base + reg);
-}
-
void at91_sdhci_mmio_init(struct at91_sdhci *host, void __iomem *base)
{
- host->base = base;
- host->sdhci.read8 = at91_sdhci_read8;
- host->sdhci.read16 = at91_sdhci_read16;
- host->sdhci.read32 = at91_sdhci_read32;
- host->sdhci.write8 = at91_sdhci_write8;
- host->sdhci.write16 = at91_sdhci_write16;
- host->sdhci.write32 = at91_sdhci_write32;
+ host->sdhci.base = base;
}