提交 48f54a2d 编写于 作者: M Marek Vasut

mmc: sh_mmcif: Add DM and DT probing support

Add MMC DM and DT probing support into the SH MMCIF driver.
This patch abstracts out the common bits of the send command
and set ios functions, so they can be used both by DM and non
DM setups and adds the DM probe support.
Signed-off-by: NMarek Vasut <marek.vasut+renesas@gmail.com>
Cc: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
Cc: Jaehoon Chung <jh80.chung@samsung.com>
上级 010bbe73
......@@ -11,9 +11,13 @@
#include <watchdog.h>
#include <command.h>
#include <mmc.h>
#include <clk.h>
#include <dm.h>
#include <malloc.h>
#include <linux/errno.h>
#include <asm/io.h>
#include <linux/compat.h>
#include <linux/io.h>
#include <linux/sizes.h>
#include "sh_mmcif.h"
#define DRIVER_NAME "sh_mmcif"
......@@ -510,10 +514,9 @@ static int sh_mmcif_start_cmd(struct sh_mmcif_host *host,
return ret;
}
static int sh_mmcif_request(struct mmc *mmc, struct mmc_cmd *cmd,
struct mmc_data *data)
static int sh_mmcif_send_cmd_common(struct sh_mmcif_host *host,
struct mmc_cmd *cmd, struct mmc_data *data)
{
struct sh_mmcif_host *host = mmc->priv;
int ret;
WATCHDOG_RESET();
......@@ -539,10 +542,8 @@ static int sh_mmcif_request(struct mmc *mmc, struct mmc_cmd *cmd,
return ret;
}
static int sh_mmcif_set_ios(struct mmc *mmc)
static int sh_mmcif_set_ios_common(struct sh_mmcif_host *host, struct mmc *mmc)
{
struct sh_mmcif_host *host = mmc->priv;
if (mmc->clock)
sh_mmcif_clock_control(host, mmc->clock);
......@@ -558,19 +559,45 @@ static int sh_mmcif_set_ios(struct mmc *mmc)
return 0;
}
static int sh_mmcif_init(struct mmc *mmc)
static int sh_mmcif_initialize_common(struct sh_mmcif_host *host)
{
struct sh_mmcif_host *host = mmc->priv;
sh_mmcif_sync_reset(host);
sh_mmcif_write(MASK_ALL, &host->regs->ce_int_mask);
return 0;
}
#ifndef CONFIG_DM_MMC
static void *mmc_priv(struct mmc *mmc)
{
return (void *)mmc->priv;
}
static int sh_mmcif_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
struct mmc_data *data)
{
struct sh_mmcif_host *host = mmc_priv(mmc);
return sh_mmcif_send_cmd_common(host, cmd, data);
}
static int sh_mmcif_set_ios(struct mmc *mmc)
{
struct sh_mmcif_host *host = mmc_priv(mmc);
return sh_mmcif_set_ios_common(host, mmc);
}
static int sh_mmcif_initialize(struct mmc *mmc)
{
struct sh_mmcif_host *host = mmc_priv(mmc);
return sh_mmcif_initialize_common(host);
}
static const struct mmc_ops sh_mmcif_ops = {
.send_cmd = sh_mmcif_request,
.send_cmd = sh_mmcif_send_cmd,
.set_ios = sh_mmcif_set_ios,
.init = sh_mmcif_init,
.init = sh_mmcif_initialize,
};
static struct mmc_config sh_mmcif_cfg = {
......@@ -606,3 +633,115 @@ int mmcif_mmc_init(void)
return 0;
}
#else
struct sh_mmcif_plat {
struct mmc_config cfg;
struct mmc mmc;
};
int sh_mmcif_dm_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
struct mmc_data *data)
{
struct sh_mmcif_host *host = dev_get_priv(dev);
return sh_mmcif_send_cmd_common(host, cmd, data);
}
int sh_mmcif_dm_set_ios(struct udevice *dev)
{
struct sh_mmcif_host *host = dev_get_priv(dev);
struct mmc *mmc = mmc_get_mmc_dev(dev);
return sh_mmcif_set_ios_common(host, mmc);
}
static const struct dm_mmc_ops sh_mmcif_dm_ops = {
.send_cmd = sh_mmcif_dm_send_cmd,
.set_ios = sh_mmcif_dm_set_ios,
};
static int sh_mmcif_dm_bind(struct udevice *dev)
{
struct sh_mmcif_plat *plat = dev_get_platdata(dev);
return mmc_bind(dev, &plat->mmc, &plat->cfg);
}
static int sh_mmcif_dm_probe(struct udevice *dev)
{
struct sh_mmcif_plat *plat = dev_get_platdata(dev);
struct sh_mmcif_host *host = dev_get_priv(dev);
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
struct clk sh_mmcif_clk;
fdt_addr_t base;
int ret;
base = devfdt_get_addr(dev);
if (base == FDT_ADDR_T_NONE)
return -EINVAL;
host->regs = (struct sh_mmcif_regs *)devm_ioremap(dev, base, SZ_2K);
if (!host->regs)
return -ENOMEM;
ret = clk_get_by_index(dev, 0, &sh_mmcif_clk);
if (ret) {
debug("failed to get clock, ret=%d\n", ret);
return ret;
}
ret = clk_enable(&sh_mmcif_clk);
if (ret) {
debug("failed to enable clock, ret=%d\n", ret);
return ret;
}
host->clk = clk_get_rate(&sh_mmcif_clk);
plat->cfg.name = dev->name;
plat->cfg.host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS;
switch (fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width",
1)) {
case 8:
plat->cfg.host_caps |= MMC_MODE_8BIT;
break;
case 4:
plat->cfg.host_caps |= MMC_MODE_4BIT;
break;
case 1:
break;
default:
dev_err(dev, "Invalid \"bus-width\" value\n");
return -EINVAL;
}
sh_mmcif_initialize_common(host);
plat->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34;
plat->cfg.f_min = MMC_CLK_DIV_MIN(host->clk);
plat->cfg.f_max = MMC_CLK_DIV_MAX(host->clk);
plat->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
upriv->mmc = &plat->mmc;
return 0;
}
static const struct udevice_id sh_mmcif_sd_match[] = {
{ .compatible = "renesas,sh-mmcif" },
{ /* sentinel */ }
};
U_BOOT_DRIVER(sh_mmcif_mmc) = {
.name = "sh-mmcif",
.id = UCLASS_MMC,
.of_match = sh_mmcif_sd_match,
.bind = sh_mmcif_dm_bind,
.probe = sh_mmcif_dm_probe,
.priv_auto_alloc_size = sizeof(struct sh_mmcif_host),
.platdata_auto_alloc_size = sizeof(struct sh_mmcif_plat),
.ops = &sh_mmcif_dm_ops,
};
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册