Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: dw_mmc: k3: support hi6220

Support hi6220, tested on hikey board
emmc: support hs
sd: support hs, sdr12, sdr25

Signed-off-by: Jorge A. Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
Signed-off-by: Dan Yuan <yuandan@hisilicon.com>
Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Zhangfei Gao and committed by
Ulf Hansson
0293efdd 8f7849c4

+101 -2
+101 -2
drivers/mmc/host/dw_mmc-k3.c
··· 8 8 * (at your option) any later version. 9 9 */ 10 10 11 - #include <linux/module.h> 12 - #include <linux/platform_device.h> 13 11 #include <linux/clk.h> 12 + #include <linux/mfd/syscon.h> 14 13 #include <linux/mmc/host.h> 15 14 #include <linux/mmc/dw_mmc.h> 15 + #include <linux/module.h> 16 16 #include <linux/of_address.h> 17 + #include <linux/platform_device.h> 18 + #include <linux/regmap.h> 19 + #include <linux/regulator/consumer.h> 17 20 18 21 #include "dw_mmc.h" 19 22 #include "dw_mmc-pltfm.h" 23 + 24 + /* 25 + * hi6220 sd only support io voltage 1.8v and 3v 26 + * Also need config AO_SCTRL_SEL18 accordingly 27 + */ 28 + #define AO_SCTRL_SEL18 BIT(10) 29 + #define AO_SCTRL_CTRL3 0x40C 30 + 31 + struct k3_priv { 32 + struct regmap *reg; 33 + }; 20 34 21 35 static void dw_mci_k3_set_ios(struct dw_mci *host, struct mmc_ios *ios) 22 36 { ··· 47 33 .set_ios = dw_mci_k3_set_ios, 48 34 }; 49 35 36 + static int dw_mci_hi6220_parse_dt(struct dw_mci *host) 37 + { 38 + struct k3_priv *priv; 39 + 40 + priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL); 41 + if (!priv) 42 + return -ENOMEM; 43 + 44 + priv->reg = syscon_regmap_lookup_by_phandle(host->dev->of_node, 45 + "hisilicon,peripheral-syscon"); 46 + if (IS_ERR(priv->reg)) 47 + priv->reg = NULL; 48 + 49 + host->priv = priv; 50 + return 0; 51 + } 52 + 53 + static int dw_mci_hi6220_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) 54 + { 55 + struct dw_mci_slot *slot = mmc_priv(mmc); 56 + struct k3_priv *priv; 57 + struct dw_mci *host; 58 + int min_uv, max_uv; 59 + int ret; 60 + 61 + host = slot->host; 62 + priv = host->priv; 63 + 64 + if (!priv || !priv->reg) 65 + return 0; 66 + 67 + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { 68 + ret = regmap_update_bits(priv->reg, AO_SCTRL_CTRL3, 69 + AO_SCTRL_SEL18, 0); 70 + min_uv = 3000000; 71 + max_uv = 3000000; 72 + } else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { 73 + ret = regmap_update_bits(priv->reg, AO_SCTRL_CTRL3, 74 + AO_SCTRL_SEL18, AO_SCTRL_SEL18); 75 + min_uv = 1800000; 76 + max_uv = 1800000; 77 + } else { 78 + dev_dbg(host->dev, "voltage not supported\n"); 79 + return -EINVAL; 80 + } 81 + 82 + if (ret) { 83 + dev_dbg(host->dev, "switch voltage failed\n"); 84 + return ret; 85 + } 86 + 87 + if (IS_ERR_OR_NULL(mmc->supply.vqmmc)) 88 + return 0; 89 + 90 + ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv); 91 + if (ret) { 92 + dev_dbg(host->dev, "Regulator set error %d: %d - %d\n", 93 + ret, min_uv, max_uv); 94 + return ret; 95 + } 96 + 97 + return 0; 98 + } 99 + 100 + static void dw_mci_hi6220_set_ios(struct dw_mci *host, struct mmc_ios *ios) 101 + { 102 + int ret; 103 + unsigned int clock; 104 + 105 + clock = (ios->clock <= 25000000) ? 25000000 : ios->clock; 106 + 107 + ret = clk_set_rate(host->biu_clk, clock); 108 + if (ret) 109 + dev_warn(host->dev, "failed to set rate %uHz\n", clock); 110 + 111 + host->bus_hz = clk_get_rate(host->biu_clk); 112 + } 113 + 114 + static const struct dw_mci_drv_data hi6220_data = { 115 + .switch_voltage = dw_mci_hi6220_switch_voltage, 116 + .set_ios = dw_mci_hi6220_set_ios, 117 + .parse_dt = dw_mci_hi6220_parse_dt, 118 + }; 119 + 50 120 static const struct of_device_id dw_mci_k3_match[] = { 51 121 { .compatible = "hisilicon,hi4511-dw-mshc", .data = &k3_drv_data, }, 122 + { .compatible = "hisilicon,hi6220-dw-mshc", .data = &hi6220_data, }, 52 123 {}, 53 124 }; 54 125 MODULE_DEVICE_TABLE(of, dw_mci_k3_match);