0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/bits.h>
0011 #include <linux/clk.h>
0012 #include <linux/delay.h>
0013 #include <linux/err.h>
0014 #include <linux/gpio/consumer.h>
0015 #include <linux/module.h>
0016 #include <linux/of.h>
0017 #include <linux/property.h>
0018
0019 #include "sdhci-pltfm.h"
0020 #include "sdhci_f_sdh30.h"
0021
0022
0023 #define MLB_SOFT_RESET 0x0200
0024 #define MLB_SOFT_RESET_RSTX BIT(0)
0025
0026 #define MLB_WP_CD_LED_SET 0x0210
0027 #define MLB_WP_CD_LED_SET_LED_INV BIT(2)
0028
0029 #define MLB_CR_SET 0x0220
0030 #define MLB_CR_SET_CR_TOCLKUNIT BIT(24)
0031 #define MLB_CR_SET_CR_TOCLKFREQ_SFT (16)
0032 #define MLB_CR_SET_CR_TOCLKFREQ_MASK (0x3F << MLB_CR_SET_CR_TOCLKFREQ_SFT)
0033 #define MLB_CR_SET_CR_BCLKFREQ_SFT (8)
0034 #define MLB_CR_SET_CR_BCLKFREQ_MASK (0xFF << MLB_CR_SET_CR_BCLKFREQ_SFT)
0035 #define MLB_CR_SET_CR_RTUNTIMER_SFT (4)
0036 #define MLB_CR_SET_CR_RTUNTIMER_MASK (0xF << MLB_CR_SET_CR_RTUNTIMER_SFT)
0037
0038 #define MLB_SD_TOCLK_I_DIV 16
0039 #define MLB_TOCLKFREQ_UNIT_THRES 16000000
0040 #define MLB_CAL_TOCLKFREQ_MHZ(rate) (rate / MLB_SD_TOCLK_I_DIV / 1000000)
0041 #define MLB_CAL_TOCLKFREQ_KHZ(rate) (rate / MLB_SD_TOCLK_I_DIV / 1000)
0042 #define MLB_TOCLKFREQ_MAX 63
0043 #define MLB_TOCLKFREQ_MIN 1
0044
0045 #define MLB_SD_BCLK_I_DIV 4
0046 #define MLB_CAL_BCLKFREQ(rate) (rate / MLB_SD_BCLK_I_DIV / 1000000)
0047 #define MLB_BCLKFREQ_MAX 255
0048 #define MLB_BCLKFREQ_MIN 1
0049
0050 #define MLB_CDR_SET 0x0230
0051 #define MLB_CDR_SET_CLK2POW16 3
0052
0053 struct f_sdhost_priv {
0054 struct clk *clk_iface;
0055 struct clk *clk;
0056 struct device *dev;
0057 bool enable_cmd_dat_delay;
0058 };
0059
0060 static void sdhci_milbeaut_soft_voltage_switch(struct sdhci_host *host)
0061 {
0062 u32 ctrl = 0;
0063
0064 usleep_range(2500, 3000);
0065 ctrl = sdhci_readl(host, F_SDH30_IO_CONTROL2);
0066 ctrl |= F_SDH30_CRES_O_DN;
0067 sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
0068 ctrl |= F_SDH30_MSEL_O_1_8;
0069 sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
0070
0071 ctrl &= ~F_SDH30_CRES_O_DN;
0072 sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
0073 usleep_range(2500, 3000);
0074
0075 ctrl = sdhci_readl(host, F_SDH30_TUNING_SETTING);
0076 ctrl |= F_SDH30_CMD_CHK_DIS;
0077 sdhci_writel(host, ctrl, F_SDH30_TUNING_SETTING);
0078 }
0079
0080 static unsigned int sdhci_milbeaut_get_min_clock(struct sdhci_host *host)
0081 {
0082 return F_SDH30_MIN_CLOCK;
0083 }
0084
0085 static void sdhci_milbeaut_reset(struct sdhci_host *host, u8 mask)
0086 {
0087 struct f_sdhost_priv *priv = sdhci_priv(host);
0088 u16 clk;
0089 u32 ctl;
0090 ktime_t timeout;
0091
0092 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
0093 clk = (clk & ~SDHCI_CLOCK_CARD_EN) | SDHCI_CLOCK_INT_EN;
0094 sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
0095
0096 sdhci_reset(host, mask);
0097
0098 clk |= SDHCI_CLOCK_CARD_EN;
0099 sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
0100
0101 timeout = ktime_add_ms(ktime_get(), 10);
0102 while (1) {
0103 bool timedout = ktime_after(ktime_get(), timeout);
0104
0105 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
0106 if (clk & SDHCI_CLOCK_INT_STABLE)
0107 break;
0108 if (timedout) {
0109 pr_err("%s: Internal clock never stabilised.\n",
0110 mmc_hostname(host->mmc));
0111 sdhci_dumpregs(host);
0112 return;
0113 }
0114 udelay(10);
0115 }
0116
0117 if (priv->enable_cmd_dat_delay) {
0118 ctl = sdhci_readl(host, F_SDH30_ESD_CONTROL);
0119 ctl |= F_SDH30_CMD_DAT_DELAY;
0120 sdhci_writel(host, ctl, F_SDH30_ESD_CONTROL);
0121 }
0122 }
0123
0124 static const struct sdhci_ops sdhci_milbeaut_ops = {
0125 .voltage_switch = sdhci_milbeaut_soft_voltage_switch,
0126 .get_min_clock = sdhci_milbeaut_get_min_clock,
0127 .reset = sdhci_milbeaut_reset,
0128 .set_clock = sdhci_set_clock,
0129 .set_bus_width = sdhci_set_bus_width,
0130 .set_uhs_signaling = sdhci_set_uhs_signaling,
0131 .set_power = sdhci_set_power_and_bus_voltage,
0132 };
0133
0134 static void sdhci_milbeaut_bridge_reset(struct sdhci_host *host,
0135 int reset_flag)
0136 {
0137 if (reset_flag)
0138 sdhci_writel(host, 0, MLB_SOFT_RESET);
0139 else
0140 sdhci_writel(host, MLB_SOFT_RESET_RSTX, MLB_SOFT_RESET);
0141 }
0142
0143 static void sdhci_milbeaut_bridge_init(struct sdhci_host *host,
0144 int rate)
0145 {
0146 u32 val, clk;
0147
0148
0149 val = sdhci_readl(host, MLB_CR_SET);
0150 val &= ~(MLB_CR_SET_CR_TOCLKFREQ_MASK | MLB_CR_SET_CR_TOCLKUNIT |
0151 MLB_CR_SET_CR_BCLKFREQ_MASK);
0152 if (rate >= MLB_TOCLKFREQ_UNIT_THRES) {
0153 clk = MLB_CAL_TOCLKFREQ_MHZ(rate);
0154 clk = min_t(u32, MLB_TOCLKFREQ_MAX, clk);
0155 val |= MLB_CR_SET_CR_TOCLKUNIT |
0156 (clk << MLB_CR_SET_CR_TOCLKFREQ_SFT);
0157 } else {
0158 clk = MLB_CAL_TOCLKFREQ_KHZ(rate);
0159 clk = min_t(u32, MLB_TOCLKFREQ_MAX, clk);
0160 clk = max_t(u32, MLB_TOCLKFREQ_MIN, clk);
0161 val |= clk << MLB_CR_SET_CR_TOCLKFREQ_SFT;
0162 }
0163
0164 clk = MLB_CAL_BCLKFREQ(rate);
0165 clk = min_t(u32, MLB_BCLKFREQ_MAX, clk);
0166 clk = max_t(u32, MLB_BCLKFREQ_MIN, clk);
0167 val |= clk << MLB_CR_SET_CR_BCLKFREQ_SFT;
0168 val &= ~MLB_CR_SET_CR_RTUNTIMER_MASK;
0169 sdhci_writel(host, val, MLB_CR_SET);
0170
0171 sdhci_writel(host, MLB_CDR_SET_CLK2POW16, MLB_CDR_SET);
0172
0173 sdhci_writel(host, MLB_WP_CD_LED_SET_LED_INV, MLB_WP_CD_LED_SET);
0174 }
0175
0176 static void sdhci_milbeaut_vendor_init(struct sdhci_host *host)
0177 {
0178 struct f_sdhost_priv *priv = sdhci_priv(host);
0179 u32 ctl;
0180
0181 ctl = sdhci_readl(host, F_SDH30_IO_CONTROL2);
0182 ctl |= F_SDH30_CRES_O_DN;
0183 sdhci_writel(host, ctl, F_SDH30_IO_CONTROL2);
0184 ctl &= ~F_SDH30_MSEL_O_1_8;
0185 sdhci_writel(host, ctl, F_SDH30_IO_CONTROL2);
0186 ctl &= ~F_SDH30_CRES_O_DN;
0187 sdhci_writel(host, ctl, F_SDH30_IO_CONTROL2);
0188
0189 ctl = sdhci_readw(host, F_SDH30_AHB_CONFIG);
0190 ctl |= F_SDH30_SIN | F_SDH30_AHB_INCR_16 | F_SDH30_AHB_INCR_8 |
0191 F_SDH30_AHB_INCR_4;
0192 ctl &= ~(F_SDH30_AHB_BIGED | F_SDH30_BUSLOCK_EN);
0193 sdhci_writew(host, ctl, F_SDH30_AHB_CONFIG);
0194
0195 if (priv->enable_cmd_dat_delay) {
0196 ctl = sdhci_readl(host, F_SDH30_ESD_CONTROL);
0197 ctl |= F_SDH30_CMD_DAT_DELAY;
0198 sdhci_writel(host, ctl, F_SDH30_ESD_CONTROL);
0199 }
0200 }
0201
0202 static const struct of_device_id mlb_dt_ids[] = {
0203 {
0204 .compatible = "socionext,milbeaut-m10v-sdhci-3.0",
0205 },
0206 { }
0207 };
0208 MODULE_DEVICE_TABLE(of, mlb_dt_ids);
0209
0210 static void sdhci_milbeaut_init(struct sdhci_host *host)
0211 {
0212 struct f_sdhost_priv *priv = sdhci_priv(host);
0213 int rate = clk_get_rate(priv->clk);
0214 u16 ctl;
0215
0216 sdhci_milbeaut_bridge_reset(host, 0);
0217
0218 ctl = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
0219 ctl &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN);
0220 sdhci_writew(host, ctl, SDHCI_CLOCK_CONTROL);
0221
0222 sdhci_milbeaut_bridge_reset(host, 1);
0223
0224 sdhci_milbeaut_bridge_init(host, rate);
0225 sdhci_milbeaut_bridge_reset(host, 0);
0226
0227 sdhci_milbeaut_vendor_init(host);
0228 }
0229
0230 static int sdhci_milbeaut_probe(struct platform_device *pdev)
0231 {
0232 struct sdhci_host *host;
0233 struct device *dev = &pdev->dev;
0234 int irq, ret = 0;
0235 struct f_sdhost_priv *priv;
0236
0237 irq = platform_get_irq(pdev, 0);
0238 if (irq < 0)
0239 return irq;
0240
0241 host = sdhci_alloc_host(dev, sizeof(struct f_sdhost_priv));
0242 if (IS_ERR(host))
0243 return PTR_ERR(host);
0244
0245 priv = sdhci_priv(host);
0246 priv->dev = dev;
0247
0248 host->quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
0249 SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
0250 SDHCI_QUIRK_CLOCK_BEFORE_RESET |
0251 SDHCI_QUIRK_DELAY_AFTER_POWER;
0252 host->quirks2 = SDHCI_QUIRK2_SUPPORT_SINGLE |
0253 SDHCI_QUIRK2_TUNING_WORK_AROUND |
0254 SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
0255
0256 priv->enable_cmd_dat_delay = device_property_read_bool(dev,
0257 "fujitsu,cmd-dat-delay-select");
0258
0259 ret = mmc_of_parse(host->mmc);
0260 if (ret)
0261 goto err;
0262
0263 platform_set_drvdata(pdev, host);
0264
0265 host->hw_name = "f_sdh30";
0266 host->ops = &sdhci_milbeaut_ops;
0267 host->irq = irq;
0268
0269 host->ioaddr = devm_platform_ioremap_resource(pdev, 0);
0270 if (IS_ERR(host->ioaddr)) {
0271 ret = PTR_ERR(host->ioaddr);
0272 goto err;
0273 }
0274
0275 if (dev_of_node(dev)) {
0276 sdhci_get_of_property(pdev);
0277
0278 priv->clk_iface = devm_clk_get(&pdev->dev, "iface");
0279 if (IS_ERR(priv->clk_iface)) {
0280 ret = PTR_ERR(priv->clk_iface);
0281 goto err;
0282 }
0283
0284 ret = clk_prepare_enable(priv->clk_iface);
0285 if (ret)
0286 goto err;
0287
0288 priv->clk = devm_clk_get(&pdev->dev, "core");
0289 if (IS_ERR(priv->clk)) {
0290 ret = PTR_ERR(priv->clk);
0291 goto err_clk;
0292 }
0293
0294 ret = clk_prepare_enable(priv->clk);
0295 if (ret)
0296 goto err_clk;
0297 }
0298
0299 sdhci_milbeaut_init(host);
0300
0301 ret = sdhci_add_host(host);
0302 if (ret)
0303 goto err_add_host;
0304
0305 return 0;
0306
0307 err_add_host:
0308 clk_disable_unprepare(priv->clk);
0309 err_clk:
0310 clk_disable_unprepare(priv->clk_iface);
0311 err:
0312 sdhci_free_host(host);
0313 return ret;
0314 }
0315
0316 static int sdhci_milbeaut_remove(struct platform_device *pdev)
0317 {
0318 struct sdhci_host *host = platform_get_drvdata(pdev);
0319 struct f_sdhost_priv *priv = sdhci_priv(host);
0320
0321 sdhci_remove_host(host, readl(host->ioaddr + SDHCI_INT_STATUS) ==
0322 0xffffffff);
0323
0324 clk_disable_unprepare(priv->clk_iface);
0325 clk_disable_unprepare(priv->clk);
0326
0327 sdhci_free_host(host);
0328 platform_set_drvdata(pdev, NULL);
0329
0330 return 0;
0331 }
0332
0333 static struct platform_driver sdhci_milbeaut_driver = {
0334 .driver = {
0335 .name = "sdhci-milbeaut",
0336 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
0337 .of_match_table = of_match_ptr(mlb_dt_ids),
0338 },
0339 .probe = sdhci_milbeaut_probe,
0340 .remove = sdhci_milbeaut_remove,
0341 };
0342
0343 module_platform_driver(sdhci_milbeaut_driver);
0344
0345 MODULE_DESCRIPTION("MILBEAUT SD Card Controller driver");
0346 MODULE_AUTHOR("Takao Orito <orito.takao@socionext.com>");
0347 MODULE_LICENSE("GPL v2");
0348 MODULE_ALIAS("platform:sdhci-milbeaut");