From 8150568cbbe28dd2fad4f986110eda54fd851017 Mon Sep 17 00:00:00 2001 From: Xinwei Kong Date: Sun, 8 Nov 2015 15:16:17 +0800 Subject: mmc: HiKey: configure the dw_mmc-k3 driver for estuary kernel Signed-off-by: Fei Wang Signed-off-by: Xinwei Kong --- arch/arm64/configs/defconfig | 12 +++--- drivers/mmc/host/dw_mmc-k3.c | 100 ++++++++++++++++++++++++++++++++++++++++++- drivers/mmc/host/dw_mmc.h | 2 + 3 files changed, 106 insertions(+), 8 deletions(-) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 32fb2beaa614..7f90c6d9aabe 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -5642,15 +5642,15 @@ CONFIG_UWB=m CONFIG_UWB_HWA=m CONFIG_UWB_WHCI=m CONFIG_UWB_I1480U=m -CONFIG_MMC=m +CONFIG_MMC=y # CONFIG_MMC_DEBUG is not set # CONFIG_MMC_CLKGATE is not set # # MMC/SD/SDIO Card Drivers # -CONFIG_MMC_BLOCK=m -CONFIG_MMC_BLOCK_MINORS=8 +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=64 CONFIG_MMC_BLOCK_BOUNCE=y CONFIG_SDIO_UART=m # CONFIG_MMC_TEST is not set @@ -5672,11 +5672,11 @@ CONFIG_MMC_TIFM_SD=m CONFIG_MMC_SPI=m CONFIG_MMC_CB710=m CONFIG_MMC_VIA_SDMMC=m -CONFIG_MMC_DW=m +CONFIG_MMC_DW=y CONFIG_MMC_DW_IDMAC=y -CONFIG_MMC_DW_PLTFM=m +CONFIG_MMC_DW_PLTFM=y CONFIG_MMC_DW_EXYNOS=m -CONFIG_MMC_DW_K3=m +CONFIG_MMC_DW_K3=y CONFIG_MMC_DW_PCI=m CONFIG_MMC_VUB300=m CONFIG_MMC_USHC=m diff --git a/drivers/mmc/host/dw_mmc-k3.c b/drivers/mmc/host/dw_mmc-k3.c index 650f9cc3f7a6..5ba0b0f09f81 100644 --- a/drivers/mmc/host/dw_mmc-k3.c +++ b/drivers/mmc/host/dw_mmc-k3.c @@ -8,16 +8,28 @@ * (at your option) any later version. */ -#include -#include #include +#include #include #include +#include #include +#include +#include +#include #include "dw_mmc.h" #include "dw_mmc-pltfm.h" +#define AO_SCTRL_SEL18 BIT(10) +#define AO_SCTRL_CTRL3 0x40C + +#define SDMMC_CMD_DISABLE_BOOT BIT(26) + +struct k3_priv { + struct regmap *reg; +}; + static void dw_mci_k3_set_ios(struct dw_mci *host, struct mmc_ios *ios) { int ret; @@ -33,8 +45,92 @@ static const struct dw_mci_drv_data k3_drv_data = { .set_ios = dw_mci_k3_set_ios, }; +static int dw_mci_hi6220_parse_dt(struct dw_mci *host) +{ + struct k3_priv *priv; + + priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->reg = syscon_regmap_lookup_by_phandle(host->dev->of_node, + "hisilicon,peripheral-syscon"); + if (IS_ERR(priv->reg)) + priv->reg = NULL; + + host->priv = priv; + return 0; +} + +static int dw_mci_hi6220_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct dw_mci_slot *slot = mmc_priv(mmc); + struct k3_priv *priv; + struct dw_mci *host; + int min_uv, max_uv; + int ret; + + host = slot->host; + priv = host->priv; + + if (!priv || !priv->reg) + return 0; + + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { + ret = regmap_update_bits(priv->reg, AO_SCTRL_CTRL3, + AO_SCTRL_SEL18, 0); + min_uv = 3000000; + max_uv = 3000000; + } else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { + ret = regmap_update_bits(priv->reg, AO_SCTRL_CTRL3, + AO_SCTRL_SEL18, AO_SCTRL_SEL18); + min_uv = 1800000; + max_uv = 1800000; + } else { + dev_dbg(host->dev, "voltage not supported\n"); + return -EINVAL; + } + + if (ret) { + dev_dbg(host->dev, "switch voltage failed\n"); + return ret; + } + + if (IS_ERR_OR_NULL(mmc->supply.vqmmc)) + return 0; + + ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv); + if (ret) { + dev_dbg(host->dev, "Regulator set error %d: %d - %d\n", + ret, min_uv, max_uv); + return ret; + } + return 0; +} + +static void dw_mci_hi6220_set_ios(struct dw_mci *host, struct mmc_ios *ios) +{ + int ret; + unsigned int clock; + + clock = (ios->clock <= 25000000) ? 25000000 : ios->clock; + + ret = clk_set_rate(host->biu_clk, clock); + if (ret) + dev_warn(host->dev, "failed to set rate %uHz\n", clock); + + host->bus_hz = clk_get_rate(host->biu_clk); +} + +static const struct dw_mci_drv_data hi6220_data = { + .switch_voltage = dw_mci_hi6220_switch_voltage, + .set_ios = dw_mci_hi6220_set_ios, + .parse_dt = dw_mci_hi6220_parse_dt, +}; + static const struct of_device_id dw_mci_k3_match[] = { { .compatible = "hisilicon,hi4511-dw-mshc", .data = &k3_drv_data, }, + { .compatible = "hisilicon,hi6220-dw-mshc", .data = &hi6220_data, }, {}, }; MODULE_DEVICE_TABLE(of, dw_mci_k3_match); diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index f45ab91de339..c7236170bf98 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -287,5 +287,7 @@ struct dw_mci_drv_data { int (*execute_tuning)(struct dw_mci_slot *slot); int (*prepare_hs400_tuning)(struct dw_mci *host, struct mmc_ios *ios); + int (*switch_voltage)(struct mmc_host *mmc, + struct mmc_ios *ios); }; #endif /* _DW_MMC_H_ */ -- cgit v1.2.3