summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXinwei Kong <kong.kongxinwei@hisilicon.com>2015-11-08 15:16:17 +0800
committerXinwei Kong <kong.kongxinwei@hisilicon.com>2015-11-08 17:28:23 +0800
commit8150568cbbe28dd2fad4f986110eda54fd851017 (patch)
tree0f218982ef1926fc7734c82efecc429eb2a8b6d1
parente0f235c47943bcab7edd82ab05d3aef28f501c06 (diff)
mmc: HiKey: configure the dw_mmc-k3 driver for estuary kernel
Signed-off-by: Fei Wang <w.f@huawei.com> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
-rw-r--r--arch/arm64/configs/defconfig12
-rw-r--r--drivers/mmc/host/dw_mmc-k3.c100
-rw-r--r--drivers/mmc/host/dw_mmc.h2
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 <linux/module.h>
-#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
#include <linux/mmc/host.h>
#include <linux/mmc/dw_mmc.h>
+#include <linux/module.h>
#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
#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_ */