diff options
Diffstat (limited to 'drivers/mmc/host/renesas_sdhi_core.c')
| -rw-r--r-- | drivers/mmc/host/renesas_sdhi_core.c | 280 |
1 files changed, 239 insertions, 41 deletions
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 345934e4f59e..2a310a145785 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -22,16 +22,19 @@ #include <linux/delay.h> #include <linux/iopoll.h> #include <linux/kernel.h> -#include <linux/mfd/tmio.h> #include <linux/mmc/host.h> #include <linux/mmc/mmc.h> #include <linux/mmc/slot-gpio.h> #include <linux/module.h> #include <linux/pinctrl/consumer.h> #include <linux/pinctrl/pinctrl-state.h> +#include <linux/platform_data/tmio.h> #include <linux/platform_device.h> #include <linux/pm_domain.h> +#include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/of_regulator.h> #include <linux/reset.h> #include <linux/sh_dma.h> #include <linux/slab.h> @@ -220,7 +223,11 @@ static void renesas_sdhi_set_clock(struct tmio_mmc_host *host, clk &= ~0xff; } - sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK); + clock = clk & CLK_CTL_DIV_MASK; + if (clock != CLK_CTL_DIV_MASK) + host->mmc->actual_clock /= (1 << (ffs(clock) + 1)); + + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clock); if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) usleep_range(10000, 11000); @@ -581,14 +588,29 @@ static void renesas_sdhi_reset(struct tmio_mmc_host *host, bool preserve) if (!preserve) { if (priv->rstc) { + u32 sd_status; + /* + * HW reset might have toggled the regulator state in + * HW which regulator core might be unaware of so save + * and restore the regulator state during HW reset. + */ + if (priv->rdev) + sd_status = sd_ctrl_read32(host, CTL_SD_STATUS); + reset_control_reset(priv->rstc); /* Unknown why but without polling reset status, it will hang */ read_poll_timeout(reset_control_status, ret, ret == 0, 1, 100, false, priv->rstc); /* At least SDHI_VER_GEN2_SDR50 needs manual release of reset */ sd_ctrl_write16(host, CTL_RESET_SD, 0x0001); + if (priv->rdev) + sd_ctrl_write32(host, CTL_SD_STATUS, sd_status); + priv->needs_adjust_hs400 = false; renesas_sdhi_set_clock(host, host->clk_cache); + + /* Ensure default value for this driver. */ + renesas_sdhi_sdbuf_width(host, 16); } else if (priv->scc_ctl) { renesas_sdhi_scc_reset(host, priv); } @@ -669,9 +691,8 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) /* Set SCC */ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, priv->tap_set); - /* Enable auto re-tuning */ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, - SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN | + (priv->card_is_sdio ? 0 : SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN) | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); return 0; @@ -761,6 +782,14 @@ static bool renesas_sdhi_manual_correction(struct tmio_mmc_host *host, bool use_ if (bad_taps & BIT(new_tap % priv->tap_num)) return test_bit(error_tap % priv->tap_num, priv->smpcmp); } else { + if (!priv->card_is_sdio && + !(val & SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR)) { + u32 smpcmp = sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_SMPCMP); + + /* DAT1 is unmatched because of an SDIO irq */ + if (smpcmp & (BIT(17) | BIT(1))) + return false; + } if (val & SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR) return true; /* need retune */ else if (val & SH_MOBILE_SDHI_SCC_RVSREQ_REQTAPUP) @@ -811,11 +840,14 @@ static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host, if (mmc_doing_tune(host->mmc)) return false; - if (((mrq->cmd->error == -ETIMEDOUT) || - (mrq->data && mrq->data->error == -ETIMEDOUT)) && - ((host->mmc->caps & MMC_CAP_NONREMOVABLE) || - (host->ops.get_cd && host->ops.get_cd(host->mmc)))) - ret |= true; + /* mrq can be NULL to check SCC error on SDIO irq without any request */ + if (mrq) { + if (((mrq->cmd->error == -ETIMEDOUT) || + (mrq->data && mrq->data->error == -ETIMEDOUT)) && + ((host->mmc->caps & MMC_CAP_NONREMOVABLE) || + (host->ops.get_cd && host->ops.get_cd(host->mmc)))) + ret |= true; + } if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) & SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN) @@ -826,6 +858,28 @@ static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host, return ret; } +static void renesas_sdhi_init_card(struct mmc_host *mmc, struct mmc_card *card) +{ + struct tmio_mmc_host *host = mmc_priv(mmc); + struct renesas_sdhi *priv = host_to_priv(host); + + /* + * This controller cannot do auto-retune with SDIO irqs, so we + * then need to enforce manual correction. However, when tuning, + * mmc->card is not populated yet, so we don't know if the card + * is SDIO. init_card provides this information earlier, so we + * keep a copy of it. + */ + priv->card_is_sdio = mmc_card_sdio(card); +} + +static void renesas_sdhi_sdio_irq(struct tmio_mmc_host *host) +{ + /* This controller requires retune when an SDIO irq occurs */ + if (renesas_sdhi_check_scc_error(host, NULL)) + mmc_retune_needed(host->mmc); +} + static int renesas_sdhi_wait_idle(struct tmio_mmc_host *host, u32 bit) { int timeout = 1000; @@ -901,6 +955,102 @@ static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable) renesas_sdhi_sdbuf_width(host, enable ? width : 16); } +static const unsigned int renesas_sdhi_vqmmc_voltages[] = { + 3300000, 1800000 +}; + +static int renesas_sdhi_regulator_disable(struct regulator_dev *rdev) +{ + struct tmio_mmc_host *host = rdev_get_drvdata(rdev); + u32 sd_status; + + sd_status = sd_ctrl_read32(host, CTL_SD_STATUS); + sd_status &= ~SD_STATUS_PWEN; + sd_ctrl_write32(host, CTL_SD_STATUS, sd_status); + + return 0; +} + +static int renesas_sdhi_regulator_enable(struct regulator_dev *rdev) +{ + struct tmio_mmc_host *host = rdev_get_drvdata(rdev); + u32 sd_status; + + sd_status = sd_ctrl_read32(host, CTL_SD_STATUS); + sd_status |= SD_STATUS_PWEN; + sd_ctrl_write32(host, CTL_SD_STATUS, sd_status); + + return 0; +} + +static int renesas_sdhi_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct tmio_mmc_host *host = rdev_get_drvdata(rdev); + u32 sd_status; + + sd_status = sd_ctrl_read32(host, CTL_SD_STATUS); + + return (sd_status & SD_STATUS_PWEN) ? 1 : 0; +} + +static int renesas_sdhi_regulator_get_voltage(struct regulator_dev *rdev) +{ + struct tmio_mmc_host *host = rdev_get_drvdata(rdev); + u32 sd_status; + + sd_status = sd_ctrl_read32(host, CTL_SD_STATUS); + + return (sd_status & SD_STATUS_IOVS) ? 1800000 : 3300000; +} + +static int renesas_sdhi_regulator_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, + unsigned int *selector) +{ + struct tmio_mmc_host *host = rdev_get_drvdata(rdev); + u32 sd_status; + + sd_status = sd_ctrl_read32(host, CTL_SD_STATUS); + if (min_uV >= 1700000 && max_uV <= 1950000) { + sd_status |= SD_STATUS_IOVS; + *selector = 1; + } else { + sd_status &= ~SD_STATUS_IOVS; + *selector = 0; + } + sd_ctrl_write32(host, CTL_SD_STATUS, sd_status); + + return 0; +} + +static int renesas_sdhi_regulator_list_voltage(struct regulator_dev *rdev, + unsigned int selector) +{ + if (selector >= ARRAY_SIZE(renesas_sdhi_vqmmc_voltages)) + return -EINVAL; + + return renesas_sdhi_vqmmc_voltages[selector]; +} + +static const struct regulator_ops renesas_sdhi_regulator_voltage_ops = { + .enable = renesas_sdhi_regulator_enable, + .disable = renesas_sdhi_regulator_disable, + .is_enabled = renesas_sdhi_regulator_is_enabled, + .list_voltage = renesas_sdhi_regulator_list_voltage, + .get_voltage = renesas_sdhi_regulator_get_voltage, + .set_voltage = renesas_sdhi_regulator_set_voltage, +}; + +static const struct regulator_desc renesas_sdhi_vqmmc_regulator = { + .name = "sdhi-vqmmc-regulator", + .of_match = of_match_ptr("vqmmc-regulator"), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .ops = &renesas_sdhi_regulator_voltage_ops, + .volt_table = renesas_sdhi_vqmmc_voltages, + .n_voltages = ARRAY_SIZE(renesas_sdhi_vqmmc_voltages), +}; + int renesas_sdhi_probe(struct platform_device *pdev, const struct tmio_mmc_dma_ops *dma_ops, const struct renesas_sdhi_of_data *of_data, @@ -908,7 +1058,10 @@ int renesas_sdhi_probe(struct platform_device *pdev, { struct tmio_mmc_data *mmd = pdev->dev.platform_data; struct tmio_mmc_data *mmc_data; + struct regulator_config rcfg = { .dev = &pdev->dev, }; + struct regulator_dev *rdev; struct renesas_sdhi_dma *dma_priv; + struct device *dev = &pdev->dev; struct tmio_mmc_host *host; struct renesas_sdhi *priv; int num_irqs, irq, ret, i; @@ -951,7 +1104,7 @@ int renesas_sdhi_probe(struct platform_device *pdev, if (IS_ERR(priv->clk_cd)) return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk_cd), "cannot get cd clock"); - priv->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); + priv->rstc = devm_reset_control_get_optional_exclusive_deasserted(&pdev->dev, NULL); if (IS_ERR(priv->rstc)) return PTR_ERR(priv->rstc); @@ -967,6 +1120,8 @@ int renesas_sdhi_probe(struct platform_device *pdev, if (IS_ERR(host)) return PTR_ERR(host); + priv->host = host; + if (of_data) { mmc_data->flags |= of_data->tmio_flags; mmc_data->ocr_mask = of_data->tmio_ocr_mask; @@ -983,18 +1138,18 @@ int renesas_sdhi_probe(struct platform_device *pdev, } - host->write16_hook = renesas_sdhi_write16_hook; - host->clk_enable = renesas_sdhi_clk_enable; - host->clk_disable = renesas_sdhi_clk_disable; - host->set_clock = renesas_sdhi_set_clock; - host->multi_io_quirk = renesas_sdhi_multi_io_quirk; - host->dma_ops = dma_ops; + host->write16_hook = renesas_sdhi_write16_hook; + host->clk_enable = renesas_sdhi_clk_enable; + host->clk_disable = renesas_sdhi_clk_disable; + host->set_clock = renesas_sdhi_set_clock; + host->multi_io_quirk = renesas_sdhi_multi_io_quirk; + host->dma_ops = dma_ops; if (sdhi_has_quirk(priv, hs400_disabled)) host->mmc->caps2 &= ~(MMC_CAP2_HS400 | MMC_CAP2_HS400_ES); /* For some SoC, we disable internal WP. GPIO may override this */ - if (mmc_can_gpio_ro(host->mmc)) + if (mmc_host_can_gpio_ro(host->mmc)) mmc_data->capabilities2 &= ~MMC_CAP2_NO_WRITE_PROTECT; /* SDR speeds are only available on Gen2+ */ @@ -1006,6 +1161,8 @@ int renesas_sdhi_probe(struct platform_device *pdev, host->sdcard_irq_setbit_mask = TMIO_STAT_ALWAYS_SET_27; host->sdcard_irq_mask_all = TMIO_MASK_ALL_RCAR2; host->reset = renesas_sdhi_reset; + } else { + host->sdcard_irq_mask_all = TMIO_MASK_ALL; } /* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */ @@ -1044,7 +1201,20 @@ int renesas_sdhi_probe(struct platform_device *pdev, ret = renesas_sdhi_clk_enable(host); if (ret) - goto efree; + return ret; + + rcfg.of_node = of_get_available_child_by_name(dev->of_node, "vqmmc-regulator"); + if (rcfg.of_node) { + rcfg.driver_data = priv->host; + rdev = devm_regulator_register(dev, &renesas_sdhi_vqmmc_regulator, &rcfg); + of_node_put(rcfg.of_node); + if (IS_ERR(rdev)) { + dev_err(dev, "regulator register failed err=%ld", PTR_ERR(rdev)); + ret = PTR_ERR(rdev); + goto edisclk; + } + priv->rdev = rdev; + } ver = sd_ctrl_read16(host, CTL_VERSION); /* GEN2_SDR104 is first known SDHI to use 32bit block count */ @@ -1094,67 +1264,95 @@ int renesas_sdhi_probe(struct platform_device *pdev, dev_warn(&host->pdev->dev, "Unknown clock rate for tuning\n"); host->check_retune = renesas_sdhi_check_scc_error; + host->sdio_irq = renesas_sdhi_sdio_irq; + host->ops.init_card = renesas_sdhi_init_card; host->ops.execute_tuning = renesas_sdhi_execute_tuning; host->ops.prepare_hs400_tuning = renesas_sdhi_prepare_hs400_tuning; host->ops.hs400_downgrade = renesas_sdhi_disable_scc; host->ops.hs400_complete = renesas_sdhi_hs400_complete; } - ret = tmio_mmc_host_probe(host); - if (ret < 0) - goto edisclk; - - num_irqs = platform_irq_count(pdev); - if (num_irqs < 0) { - ret = num_irqs; - goto eirq; - } + sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, host->sdcard_irq_mask_all); /* There must be at least one IRQ source */ - if (!num_irqs) { - ret = -ENXIO; - goto eirq; + num_irqs = platform_irq_count(pdev); + if (num_irqs <= 0) { + ret = num_irqs ?: -ENOENT; + goto edisclk; } for (i = 0; i < num_irqs; i++) { irq = platform_get_irq(pdev, i); if (irq < 0) { ret = irq; - goto eirq; + goto edisclk; } ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq, 0, dev_name(&pdev->dev), host); if (ret) - goto eirq; + goto edisclk; } + ret = tmio_mmc_host_probe(host); + if (ret < 0) + goto edisclk; + dev_info(&pdev->dev, "%s base at %pa, max clock rate %u MHz\n", mmc_hostname(host->mmc), &res->start, host->mmc->f_max / 1000000); return ret; -eirq: - tmio_mmc_host_remove(host); edisclk: renesas_sdhi_clk_disable(host); -efree: - tmio_mmc_host_free(host); - return ret; } EXPORT_SYMBOL_GPL(renesas_sdhi_probe); -int renesas_sdhi_remove(struct platform_device *pdev) +void renesas_sdhi_remove(struct platform_device *pdev) { struct tmio_mmc_host *host = platform_get_drvdata(pdev); tmio_mmc_host_remove(host); renesas_sdhi_clk_disable(host); - tmio_mmc_host_free(host); - - return 0; } EXPORT_SYMBOL_GPL(renesas_sdhi_remove); +int renesas_sdhi_suspend(struct device *dev) +{ + struct tmio_mmc_host *host = dev_get_drvdata(dev); + struct renesas_sdhi *priv = host_to_priv(host); + int ret; + + ret = pm_runtime_force_suspend(dev); + if (ret) + return ret; + + ret = reset_control_assert(priv->rstc); + if (ret) + pm_runtime_force_resume(dev); + + return ret; +} +EXPORT_SYMBOL_GPL(renesas_sdhi_suspend); + +int renesas_sdhi_resume(struct device *dev) +{ + struct tmio_mmc_host *host = dev_get_drvdata(dev); + struct renesas_sdhi *priv = host_to_priv(host); + int ret; + + ret = reset_control_deassert(priv->rstc); + if (ret) + return ret; + + ret = pm_runtime_force_resume(dev); + if (ret) + reset_control_assert(priv->rstc); + + return ret; +} +EXPORT_SYMBOL_GPL(renesas_sdhi_resume); + +MODULE_DESCRIPTION("Renesas SDHI core driver"); MODULE_LICENSE("GPL v2"); |
