From 48f54a2d749517db1c57749c28832df8ea9f8b72 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 21 Apr 2018 17:27:11 +0200 Subject: [PATCH] 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: Marek Vasut Cc: Nobuhiro Iwamatsu Cc: Jaehoon Chung --- drivers/mmc/sh_mmcif.c | 165 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 152 insertions(+), 13 deletions(-) diff --git a/drivers/mmc/sh_mmcif.c b/drivers/mmc/sh_mmcif.c index 1ff59f06d5..26fe125cea 100644 --- a/drivers/mmc/sh_mmcif.c +++ b/drivers/mmc/sh_mmcif.c @@ -11,9 +11,13 @@ #include #include #include +#include +#include #include #include -#include +#include +#include +#include #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, - .set_ios = sh_mmcif_set_ios, - .init = sh_mmcif_init, + .send_cmd = sh_mmcif_send_cmd, + .set_ios = sh_mmcif_set_ios, + .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 -- 2.39.5