summaryrefslogtreecommitdiff
path: root/drivers/mmc/sdhci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/sdhci.c')
-rw-r--r--drivers/mmc/sdhci.c165
1 files changed, 107 insertions, 58 deletions
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 604f18dcc9..7ddb549e03 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -9,6 +9,7 @@
*/
#include <common.h>
+#include <errno.h>
#include <malloc.h>
#include <mmc.h>
#include <sdhci.h>
@@ -129,9 +130,17 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,
#define CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT 100
#define SDHCI_READ_STATUS_TIMEOUT 1000
+#ifdef CONFIG_DM_MMC_OPS
+static int sdhci_send_command(struct udevice *dev, struct mmc_cmd *cmd,
+ struct mmc_data *data)
+{
+ struct mmc *mmc = mmc_get_mmc_dev(dev);
+
+#else
static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
- struct mmc_data *data)
+ struct mmc_data *data)
{
+#endif
struct sdhci_host *host = mmc->priv;
unsigned int stat = 0;
int ret = 0;
@@ -161,7 +170,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
cmd_timeout);
} else {
puts("timeout.\n");
- return COMM_ERR;
+ return -ECOMM;
}
}
time++;
@@ -175,7 +184,8 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
flags = SDHCI_CMD_RESP_LONG;
else if (cmd->resp_type & MMC_RSP_BUSY) {
flags = SDHCI_CMD_RESP_SHORT_BUSY;
- mask |= SDHCI_INT_DATA_END;
+ if (data)
+ mask |= SDHCI_INT_DATA_END;
} else
flags = SDHCI_CMD_RESP_SHORT;
@@ -243,17 +253,17 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
stat = sdhci_readl(host, SDHCI_INT_STATUS);
if (stat & SDHCI_INT_ERROR)
break;
- } while (((stat & mask) != mask) &&
- (get_timer(start) < SDHCI_READ_STATUS_TIMEOUT));
- if (get_timer(start) >= SDHCI_READ_STATUS_TIMEOUT) {
- if (host->quirks & SDHCI_QUIRK_BROKEN_R1B)
- return 0;
- else {
- printf("%s: Timeout for status update!\n", __func__);
- return TIMEOUT;
+ if (get_timer(start) >= SDHCI_READ_STATUS_TIMEOUT) {
+ if (host->quirks & SDHCI_QUIRK_BROKEN_R1B) {
+ return 0;
+ } else {
+ printf("%s: Timeout for status update!\n",
+ __func__);
+ return -ETIMEDOUT;
+ }
}
- }
+ } while ((stat & mask) != mask);
if ((stat & (SDHCI_INT_ERROR | mask)) == mask) {
sdhci_cmd_done(host, cmd);
@@ -279,9 +289,9 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
sdhci_reset(host, SDHCI_RESET_CMD);
sdhci_reset(host, SDHCI_RESET_DATA);
if (stat & SDHCI_INT_TIMEOUT)
- return TIMEOUT;
+ return -ETIMEDOUT;
else
- return COMM_ERR;
+ return -ECOMM;
}
static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
@@ -304,7 +314,7 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
}
reg = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
- reg &= ~SDHCI_CLOCK_CARD_EN;
+ reg &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN);
sdhci_writew(host, reg, SDHCI_CLOCK_CONTROL);
if (clock == 0)
@@ -389,8 +399,14 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
}
+#ifdef CONFIG_DM_MMC_OPS
+static int sdhci_set_ios(struct udevice *dev)
+{
+ struct mmc *mmc = mmc_get_mmc_dev(dev);
+#else
static void sdhci_set_ios(struct mmc *mmc)
{
+#endif
u32 ctrl;
struct sdhci_host *host = mmc->priv;
@@ -426,6 +442,9 @@ static void sdhci_set_ios(struct mmc *mmc)
ctrl &= ~SDHCI_CTRL_HISPD;
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+#ifdef CONFIG_DM_MMC_OPS
+ return 0;
+#endif
}
static int sdhci_init(struct mmc *mmc)
@@ -472,80 +491,109 @@ static int sdhci_init(struct mmc *mmc)
return 0;
}
+#ifdef CONFIG_DM_MMC_OPS
+int sdhci_probe(struct udevice *dev)
+{
+ struct mmc *mmc = mmc_get_mmc_dev(dev);
+ return sdhci_init(mmc);
+}
+
+const struct dm_mmc_ops sdhci_ops = {
+ .send_cmd = sdhci_send_command,
+ .set_ios = sdhci_set_ios,
+};
+#else
static const struct mmc_ops sdhci_ops = {
.send_cmd = sdhci_send_command,
.set_ios = sdhci_set_ios,
.init = sdhci_init,
};
+#endif
-int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
+int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
+ u32 max_clk, u32 min_clk)
{
- unsigned int caps;
-
- host->cfg.name = host->name;
- host->cfg.ops = &sdhci_ops;
+ u32 caps;
caps = sdhci_readl(host, SDHCI_CAPABILITIES);
-#ifdef CONFIG_MMC_SDMA
- if (!(caps & SDHCI_CAN_DO_SDMA)) {
- printf("%s: Your controller doesn't support SDMA!!\n",
- __func__);
- return -1;
- }
-#endif
+ host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
+ cfg->name = host->name;
+#ifndef CONFIG_DM_MMC_OPS
+ cfg->ops = &sdhci_ops;
+#endif
if (max_clk)
- host->cfg.f_max = max_clk;
+ cfg->f_max = max_clk;
else {
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
- host->cfg.f_max = (caps & SDHCI_CLOCK_V3_BASE_MASK)
- >> SDHCI_CLOCK_BASE_SHIFT;
+ cfg->f_max = (caps & SDHCI_CLOCK_V3_BASE_MASK) >>
+ SDHCI_CLOCK_BASE_SHIFT;
else
- host->cfg.f_max = (caps & SDHCI_CLOCK_BASE_MASK)
- >> SDHCI_CLOCK_BASE_SHIFT;
- host->cfg.f_max *= 1000000;
- }
- if (host->cfg.f_max == 0) {
- printf("%s: Hardware doesn't specify base clock frequency\n",
- __func__);
- return -1;
+ cfg->f_max = (caps & SDHCI_CLOCK_BASE_MASK) >>
+ SDHCI_CLOCK_BASE_SHIFT;
+ cfg->f_max *= 1000000;
}
+ if (cfg->f_max == 0)
+ return -EINVAL;
if (min_clk)
- host->cfg.f_min = min_clk;
+ cfg->f_min = min_clk;
else {
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
- host->cfg.f_min = host->cfg.f_max /
- SDHCI_MAX_DIV_SPEC_300;
+ cfg->f_min = cfg->f_max / SDHCI_MAX_DIV_SPEC_300;
else
- host->cfg.f_min = host->cfg.f_max /
- SDHCI_MAX_DIV_SPEC_200;
+ cfg->f_min = cfg->f_max / SDHCI_MAX_DIV_SPEC_200;
}
-
- host->cfg.voltages = 0;
+ cfg->voltages = 0;
if (caps & SDHCI_CAN_VDD_330)
- host->cfg.voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
+ cfg->voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
if (caps & SDHCI_CAN_VDD_300)
- host->cfg.voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
+ cfg->voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
if (caps & SDHCI_CAN_VDD_180)
- host->cfg.voltages |= MMC_VDD_165_195;
-
- if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE)
- host->cfg.voltages |= host->voltages;
+ cfg->voltages |= MMC_VDD_165_195;
- host->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT;
+ cfg->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT;
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
if (caps & SDHCI_CAN_DO_8BIT)
- host->cfg.host_caps |= MMC_MODE_8BIT;
+ cfg->host_caps |= MMC_MODE_8BIT;
}
- if (host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)
- host->cfg.host_caps &= ~(MMC_MODE_HS | MMC_MODE_HS_52MHz);
-
if (host->host_caps)
- host->cfg.host_caps |= host->host_caps;
+ cfg->host_caps |= host->host_caps;
+
+
+ cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
- host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
+ return 0;
+}
+
+#ifdef CONFIG_BLK
+int sdhci_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg)
+{
+ return mmc_bind(dev, mmc, cfg);
+}
+#else
+int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
+{
+#ifdef CONFIG_MMC_SDMA
+ unsigned int caps;
+
+ caps = sdhci_readl(host, SDHCI_CAPABILITIES);
+ if (!(caps & SDHCI_CAN_DO_SDMA)) {
+ printf("%s: Your controller doesn't support SDMA!!\n",
+ __func__);
+ return -1;
+ }
+#endif
+
+ if (sdhci_setup_cfg(&host->cfg, host, max_clk, min_clk)) {
+ printf("%s: Hardware doesn't specify base clock frequency\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE)
+ host->cfg.voltages |= host->voltages;
sdhci_reset(host, SDHCI_RESET_ALL);
@@ -557,3 +605,4 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
return 0;
}
+#endif