xref: /openbmc/linux/drivers/mmc/host/sdhci_f_sdh30.c (revision bd724b27)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * linux/drivers/mmc/host/sdhci_f_sdh30.c
4  *
5  * Copyright (C) 2013 - 2015 Fujitsu Semiconductor, Ltd
6  *              Vincent Yang <vincent.yang@tw.fujitsu.com>
7  * Copyright (C) 2015 Linaro Ltd  Andy Green <andy.green@linaro.org>
8  */
9 
10 #include <linux/acpi.h>
11 #include <linux/err.h>
12 #include <linux/delay.h>
13 #include <linux/module.h>
14 #include <linux/of.h>
15 #include <linux/property.h>
16 #include <linux/clk.h>
17 #include <linux/reset.h>
18 
19 #include "sdhci-pltfm.h"
20 #include "sdhci_f_sdh30.h"
21 
22 struct f_sdhost_priv {
23 	struct clk *clk_iface;
24 	struct clk *clk;
25 	struct reset_control *rst;
26 	u32 vendor_hs200;
27 	struct device *dev;
28 	bool enable_cmd_dat_delay;
29 };
30 
31 static void sdhci_f_sdh30_soft_voltage_switch(struct sdhci_host *host)
32 {
33 	struct f_sdhost_priv *priv = sdhci_priv(host);
34 	u32 ctrl = 0;
35 
36 	usleep_range(2500, 3000);
37 	ctrl = sdhci_readl(host, F_SDH30_IO_CONTROL2);
38 	ctrl |= F_SDH30_CRES_O_DN;
39 	sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
40 	ctrl |= F_SDH30_MSEL_O_1_8;
41 	sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
42 
43 	ctrl &= ~F_SDH30_CRES_O_DN;
44 	sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
45 	usleep_range(2500, 3000);
46 
47 	if (priv->vendor_hs200) {
48 		dev_info(priv->dev, "%s: setting hs200\n", __func__);
49 		ctrl = sdhci_readl(host, F_SDH30_ESD_CONTROL);
50 		ctrl |= priv->vendor_hs200;
51 		sdhci_writel(host, ctrl, F_SDH30_ESD_CONTROL);
52 	}
53 
54 	ctrl = sdhci_readl(host, F_SDH30_TUNING_SETTING);
55 	ctrl |= F_SDH30_CMD_CHK_DIS;
56 	sdhci_writel(host, ctrl, F_SDH30_TUNING_SETTING);
57 }
58 
59 static unsigned int sdhci_f_sdh30_get_min_clock(struct sdhci_host *host)
60 {
61 	return F_SDH30_MIN_CLOCK;
62 }
63 
64 static void sdhci_f_sdh30_reset(struct sdhci_host *host, u8 mask)
65 {
66 	struct f_sdhost_priv *priv = sdhci_priv(host);
67 	u32 ctl;
68 
69 	if (sdhci_readw(host, SDHCI_CLOCK_CONTROL) == 0)
70 		sdhci_writew(host, 0xBC01, SDHCI_CLOCK_CONTROL);
71 
72 	sdhci_reset(host, mask);
73 
74 	if (priv->enable_cmd_dat_delay) {
75 		ctl = sdhci_readl(host, F_SDH30_ESD_CONTROL);
76 		ctl |= F_SDH30_CMD_DAT_DELAY;
77 		sdhci_writel(host, ctl, F_SDH30_ESD_CONTROL);
78 	}
79 }
80 
81 static const struct sdhci_ops sdhci_f_sdh30_ops = {
82 	.voltage_switch = sdhci_f_sdh30_soft_voltage_switch,
83 	.get_min_clock = sdhci_f_sdh30_get_min_clock,
84 	.reset = sdhci_f_sdh30_reset,
85 	.set_clock = sdhci_set_clock,
86 	.set_bus_width = sdhci_set_bus_width,
87 	.set_uhs_signaling = sdhci_set_uhs_signaling,
88 };
89 
90 static int sdhci_f_sdh30_probe(struct platform_device *pdev)
91 {
92 	struct sdhci_host *host;
93 	struct device *dev = &pdev->dev;
94 	int irq, ctrl = 0, ret = 0;
95 	struct f_sdhost_priv *priv;
96 	u32 reg = 0;
97 
98 	irq = platform_get_irq(pdev, 0);
99 	if (irq < 0)
100 		return irq;
101 
102 	host = sdhci_alloc_host(dev, sizeof(struct f_sdhost_priv));
103 	if (IS_ERR(host))
104 		return PTR_ERR(host);
105 
106 	priv = sdhci_priv(host);
107 	priv->dev = dev;
108 
109 	host->quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
110 		       SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
111 	host->quirks2 = SDHCI_QUIRK2_SUPPORT_SINGLE |
112 			SDHCI_QUIRK2_TUNING_WORK_AROUND;
113 
114 	priv->enable_cmd_dat_delay = device_property_read_bool(dev,
115 						"fujitsu,cmd-dat-delay-select");
116 
117 	ret = mmc_of_parse(host->mmc);
118 	if (ret)
119 		goto err;
120 
121 	platform_set_drvdata(pdev, host);
122 
123 	host->hw_name = "f_sdh30";
124 	host->ops = &sdhci_f_sdh30_ops;
125 	host->irq = irq;
126 
127 	host->ioaddr = devm_platform_ioremap_resource(pdev, 0);
128 	if (IS_ERR(host->ioaddr)) {
129 		ret = PTR_ERR(host->ioaddr);
130 		goto err;
131 	}
132 
133 	if (dev_of_node(dev)) {
134 		sdhci_get_of_property(pdev);
135 
136 		priv->clk_iface = devm_clk_get(&pdev->dev, "iface");
137 		if (IS_ERR(priv->clk_iface)) {
138 			ret = PTR_ERR(priv->clk_iface);
139 			goto err;
140 		}
141 
142 		ret = clk_prepare_enable(priv->clk_iface);
143 		if (ret)
144 			goto err;
145 
146 		priv->clk = devm_clk_get(&pdev->dev, "core");
147 		if (IS_ERR(priv->clk)) {
148 			ret = PTR_ERR(priv->clk);
149 			goto err_clk;
150 		}
151 
152 		ret = clk_prepare_enable(priv->clk);
153 		if (ret)
154 			goto err_clk;
155 
156 		priv->rst = devm_reset_control_get_optional_shared(dev, NULL);
157 		if (IS_ERR(priv->rst)) {
158 			ret = PTR_ERR(priv->rst);
159 			goto err_rst;
160 		}
161 
162 		ret = reset_control_deassert(priv->rst);
163 		if (ret)
164 			goto err_rst;
165 	}
166 
167 	/* init vendor specific regs */
168 	ctrl = sdhci_readw(host, F_SDH30_AHB_CONFIG);
169 	ctrl |= F_SDH30_SIN | F_SDH30_AHB_INCR_16 | F_SDH30_AHB_INCR_8 |
170 		F_SDH30_AHB_INCR_4;
171 	ctrl &= ~(F_SDH30_AHB_BIGED | F_SDH30_BUSLOCK_EN);
172 	sdhci_writew(host, ctrl, F_SDH30_AHB_CONFIG);
173 
174 	reg = sdhci_readl(host, F_SDH30_ESD_CONTROL);
175 	sdhci_writel(host, reg & ~F_SDH30_EMMC_RST, F_SDH30_ESD_CONTROL);
176 	msleep(20);
177 	sdhci_writel(host, reg | F_SDH30_EMMC_RST, F_SDH30_ESD_CONTROL);
178 
179 	reg = sdhci_readl(host, SDHCI_CAPABILITIES);
180 	if (reg & SDHCI_CAN_DO_8BIT)
181 		priv->vendor_hs200 = F_SDH30_EMMC_HS200;
182 
183 	ret = sdhci_add_host(host);
184 	if (ret)
185 		goto err_add_host;
186 
187 	return 0;
188 
189 err_add_host:
190 	reset_control_assert(priv->rst);
191 err_rst:
192 	clk_disable_unprepare(priv->clk);
193 err_clk:
194 	clk_disable_unprepare(priv->clk_iface);
195 err:
196 	sdhci_free_host(host);
197 	return ret;
198 }
199 
200 static int sdhci_f_sdh30_remove(struct platform_device *pdev)
201 {
202 	struct sdhci_host *host = platform_get_drvdata(pdev);
203 	struct f_sdhost_priv *priv = sdhci_priv(host);
204 
205 	sdhci_remove_host(host, readl(host->ioaddr + SDHCI_INT_STATUS) ==
206 			  0xffffffff);
207 
208 	reset_control_assert(priv->rst);
209 	clk_disable_unprepare(priv->clk);
210 	clk_disable_unprepare(priv->clk_iface);
211 
212 	sdhci_free_host(host);
213 	platform_set_drvdata(pdev, NULL);
214 
215 	return 0;
216 }
217 
218 #ifdef CONFIG_OF
219 static const struct of_device_id f_sdh30_dt_ids[] = {
220 	{ .compatible = "fujitsu,mb86s70-sdhci-3.0" },
221 	{ /* sentinel */ }
222 };
223 MODULE_DEVICE_TABLE(of, f_sdh30_dt_ids);
224 #endif
225 
226 #ifdef CONFIG_ACPI
227 static const struct acpi_device_id f_sdh30_acpi_ids[] = {
228 	{ "SCX0002" },
229 	{ /* sentinel */ }
230 };
231 MODULE_DEVICE_TABLE(acpi, f_sdh30_acpi_ids);
232 #endif
233 
234 static struct platform_driver sdhci_f_sdh30_driver = {
235 	.driver = {
236 		.name = "f_sdh30",
237 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
238 		.of_match_table = of_match_ptr(f_sdh30_dt_ids),
239 		.acpi_match_table = ACPI_PTR(f_sdh30_acpi_ids),
240 		.pm	= &sdhci_pltfm_pmops,
241 	},
242 	.probe	= sdhci_f_sdh30_probe,
243 	.remove	= sdhci_f_sdh30_remove,
244 };
245 
246 module_platform_driver(sdhci_f_sdh30_driver);
247 
248 MODULE_DESCRIPTION("F_SDH30 SD Card Controller driver");
249 MODULE_LICENSE("GPL v2");
250 MODULE_AUTHOR("FUJITSU SEMICONDUCTOR LTD.");
251 MODULE_ALIAS("platform:f_sdh30");
252