1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // Copyright (C) 2013 Broadcom Corporation |
3 | |
4 | #include <linux/kernel.h> |
5 | #include <linux/module.h> |
6 | #include <linux/delay.h> |
7 | #include <linux/highmem.h> |
8 | #include <linux/platform_device.h> |
9 | #include <linux/mmc/host.h> |
10 | #include <linux/io.h> |
11 | #include <linux/clk.h> |
12 | #include <linux/regulator/consumer.h> |
13 | #include <linux/of.h> |
14 | #include <linux/mmc/slot-gpio.h> |
15 | |
16 | #include "sdhci-pltfm.h" |
17 | #include "sdhci.h" |
18 | |
19 | #define SDHCI_SOFT_RESET 0x01000000 |
20 | #define KONA_SDHOST_CORECTRL 0x8000 |
21 | #define KONA_SDHOST_CD_PINCTRL 0x00000008 |
22 | #define KONA_SDHOST_STOP_HCLK 0x00000004 |
23 | #define KONA_SDHOST_RESET 0x00000002 |
24 | #define KONA_SDHOST_EN 0x00000001 |
25 | |
26 | #define KONA_SDHOST_CORESTAT 0x8004 |
27 | #define KONA_SDHOST_WP 0x00000002 |
28 | #define KONA_SDHOST_CD_SW 0x00000001 |
29 | |
30 | #define KONA_SDHOST_COREIMR 0x8008 |
31 | #define KONA_SDHOST_IP 0x00000001 |
32 | |
33 | #define KONA_SDHOST_COREISR 0x800C |
34 | #define KONA_SDHOST_COREIMSR 0x8010 |
35 | #define KONA_SDHOST_COREDBG1 0x8014 |
36 | #define KONA_SDHOST_COREGPO_MASK 0x8018 |
37 | |
38 | #define SD_DETECT_GPIO_DEBOUNCE_128MS 128 |
39 | |
40 | #define KONA_MMC_AUTOSUSPEND_DELAY (50) |
41 | |
42 | struct sdhci_bcm_kona_dev { |
43 | struct mutex write_lock; /* protect back to back writes */ |
44 | }; |
45 | |
46 | |
47 | static int sdhci_bcm_kona_sd_reset(struct sdhci_host *host) |
48 | { |
49 | unsigned int val; |
50 | unsigned long timeout; |
51 | |
52 | /* This timeout should be sufficent for core to reset */ |
53 | timeout = jiffies + msecs_to_jiffies(m: 100); |
54 | |
55 | /* reset the host using the top level reset */ |
56 | val = sdhci_readl(host, KONA_SDHOST_CORECTRL); |
57 | val |= KONA_SDHOST_RESET; |
58 | sdhci_writel(host, val, KONA_SDHOST_CORECTRL); |
59 | |
60 | while (!(sdhci_readl(host, KONA_SDHOST_CORECTRL) & KONA_SDHOST_RESET)) { |
61 | if (time_is_before_jiffies(timeout)) { |
62 | pr_err("Error: sd host is stuck in reset!!!\n" ); |
63 | return -EFAULT; |
64 | } |
65 | } |
66 | |
67 | /* bring the host out of reset */ |
68 | val = sdhci_readl(host, KONA_SDHOST_CORECTRL); |
69 | val &= ~KONA_SDHOST_RESET; |
70 | |
71 | /* |
72 | * Back-to-Back register write needs a delay of 1ms at bootup (min 10uS) |
73 | * Back-to-Back writes to same register needs delay when SD bus clock |
74 | * is very low w.r.t AHB clock, mainly during boot-time and during card |
75 | * insert-removal. |
76 | */ |
77 | usleep_range(min: 1000, max: 5000); |
78 | sdhci_writel(host, val, KONA_SDHOST_CORECTRL); |
79 | |
80 | return 0; |
81 | } |
82 | |
83 | static void sdhci_bcm_kona_sd_init(struct sdhci_host *host) |
84 | { |
85 | unsigned int val; |
86 | |
87 | /* enable the interrupt from the IP core */ |
88 | val = sdhci_readl(host, KONA_SDHOST_COREIMR); |
89 | val |= KONA_SDHOST_IP; |
90 | sdhci_writel(host, val, KONA_SDHOST_COREIMR); |
91 | |
92 | /* Enable the AHB clock gating module to the host */ |
93 | val = sdhci_readl(host, KONA_SDHOST_CORECTRL); |
94 | val |= KONA_SDHOST_EN; |
95 | |
96 | /* |
97 | * Back-to-Back register write needs a delay of 1ms at bootup (min 10uS) |
98 | * Back-to-Back writes to same register needs delay when SD bus clock |
99 | * is very low w.r.t AHB clock, mainly during boot-time and during card |
100 | * insert-removal. |
101 | */ |
102 | usleep_range(min: 1000, max: 5000); |
103 | sdhci_writel(host, val, KONA_SDHOST_CORECTRL); |
104 | } |
105 | |
106 | /* |
107 | * Software emulation of the SD card insertion/removal. Set insert=1 for insert |
108 | * and insert=0 for removal. The card detection is done by GPIO. For Broadcom |
109 | * IP to function properly the bit 0 of CORESTAT register needs to be set/reset |
110 | * to generate the CD IRQ handled in sdhci.c which schedules card_tasklet. |
111 | */ |
112 | static int sdhci_bcm_kona_sd_card_emulate(struct sdhci_host *host, int insert) |
113 | { |
114 | struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host); |
115 | struct sdhci_bcm_kona_dev *kona_dev = sdhci_pltfm_priv(host: pltfm_priv); |
116 | u32 val; |
117 | |
118 | /* |
119 | * Back-to-Back register write needs a delay of min 10uS. |
120 | * Back-to-Back writes to same register needs delay when SD bus clock |
121 | * is very low w.r.t AHB clock, mainly during boot-time and during card |
122 | * insert-removal. |
123 | * We keep 20uS |
124 | */ |
125 | mutex_lock(&kona_dev->write_lock); |
126 | udelay(20); |
127 | val = sdhci_readl(host, KONA_SDHOST_CORESTAT); |
128 | |
129 | if (insert) { |
130 | int ret; |
131 | |
132 | ret = mmc_gpio_get_ro(host: host->mmc); |
133 | if (ret >= 0) |
134 | val = (val & ~KONA_SDHOST_WP) | |
135 | ((ret) ? KONA_SDHOST_WP : 0); |
136 | |
137 | val |= KONA_SDHOST_CD_SW; |
138 | sdhci_writel(host, val, KONA_SDHOST_CORESTAT); |
139 | } else { |
140 | val &= ~KONA_SDHOST_CD_SW; |
141 | sdhci_writel(host, val, KONA_SDHOST_CORESTAT); |
142 | } |
143 | mutex_unlock(lock: &kona_dev->write_lock); |
144 | |
145 | return 0; |
146 | } |
147 | |
148 | /* |
149 | * SD card interrupt event callback |
150 | */ |
151 | static void sdhci_bcm_kona_card_event(struct sdhci_host *host) |
152 | { |
153 | if (mmc_gpio_get_cd(host: host->mmc) > 0) { |
154 | dev_dbg(mmc_dev(host->mmc), |
155 | "card inserted\n" ); |
156 | sdhci_bcm_kona_sd_card_emulate(host, insert: 1); |
157 | } else { |
158 | dev_dbg(mmc_dev(host->mmc), |
159 | "card removed\n" ); |
160 | sdhci_bcm_kona_sd_card_emulate(host, insert: 0); |
161 | } |
162 | } |
163 | |
164 | static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host, |
165 | u8 power_mode) |
166 | { |
167 | /* |
168 | * JEDEC and SD spec specify supplying 74 continuous clocks to |
169 | * device after power up. With minimum bus (100KHz) that |
170 | * translates to 740us |
171 | */ |
172 | if (power_mode != MMC_POWER_OFF) |
173 | udelay(740); |
174 | } |
175 | |
176 | static const struct sdhci_ops sdhci_bcm_kona_ops = { |
177 | .set_clock = sdhci_set_clock, |
178 | .get_max_clock = sdhci_pltfm_clk_get_max_clock, |
179 | .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, |
180 | .platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks, |
181 | .set_bus_width = sdhci_set_bus_width, |
182 | .reset = sdhci_reset, |
183 | .set_uhs_signaling = sdhci_set_uhs_signaling, |
184 | .card_event = sdhci_bcm_kona_card_event, |
185 | }; |
186 | |
187 | static const struct sdhci_pltfm_data sdhci_pltfm_data_kona = { |
188 | .ops = &sdhci_bcm_kona_ops, |
189 | .quirks = SDHCI_QUIRK_NO_CARD_NO_RESET | |
190 | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_32BIT_DMA_ADDR | |
191 | SDHCI_QUIRK_32BIT_DMA_SIZE | SDHCI_QUIRK_32BIT_ADMA_SIZE | |
192 | SDHCI_QUIRK_FORCE_BLK_SZ_2048 | |
193 | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, |
194 | }; |
195 | |
196 | static const struct of_device_id sdhci_bcm_kona_of_match[] = { |
197 | { .compatible = "brcm,kona-sdhci" }, |
198 | { .compatible = "bcm,kona-sdhci" }, /* deprecated name */ |
199 | {} |
200 | }; |
201 | MODULE_DEVICE_TABLE(of, sdhci_bcm_kona_of_match); |
202 | |
203 | static int sdhci_bcm_kona_probe(struct platform_device *pdev) |
204 | { |
205 | struct sdhci_bcm_kona_dev *kona_dev = NULL; |
206 | struct sdhci_pltfm_host *pltfm_priv; |
207 | struct device *dev = &pdev->dev; |
208 | struct sdhci_host *host; |
209 | int ret; |
210 | |
211 | ret = 0; |
212 | |
213 | host = sdhci_pltfm_init(pdev, pdata: &sdhci_pltfm_data_kona, |
214 | priv_size: sizeof(*kona_dev)); |
215 | if (IS_ERR(ptr: host)) |
216 | return PTR_ERR(ptr: host); |
217 | |
218 | dev_dbg(dev, "%s: inited. IOADDR=%p\n" , __func__, host->ioaddr); |
219 | |
220 | pltfm_priv = sdhci_priv(host); |
221 | |
222 | kona_dev = sdhci_pltfm_priv(host: pltfm_priv); |
223 | mutex_init(&kona_dev->write_lock); |
224 | |
225 | ret = mmc_of_parse(host: host->mmc); |
226 | if (ret) |
227 | goto err_pltfm_free; |
228 | |
229 | if (!host->mmc->f_max) { |
230 | dev_err(&pdev->dev, "Missing max-freq for SDHCI cfg\n" ); |
231 | ret = -ENXIO; |
232 | goto err_pltfm_free; |
233 | } |
234 | |
235 | /* Get and enable the core clock */ |
236 | pltfm_priv->clk = devm_clk_get(dev, NULL); |
237 | if (IS_ERR(ptr: pltfm_priv->clk)) { |
238 | dev_err(dev, "Failed to get core clock\n" ); |
239 | ret = PTR_ERR(ptr: pltfm_priv->clk); |
240 | goto err_pltfm_free; |
241 | } |
242 | |
243 | ret = clk_set_rate(clk: pltfm_priv->clk, rate: host->mmc->f_max); |
244 | if (ret) { |
245 | dev_err(dev, "Failed to set rate core clock\n" ); |
246 | goto err_pltfm_free; |
247 | } |
248 | |
249 | ret = clk_prepare_enable(clk: pltfm_priv->clk); |
250 | if (ret) { |
251 | dev_err(dev, "Failed to enable core clock\n" ); |
252 | goto err_pltfm_free; |
253 | } |
254 | |
255 | dev_dbg(dev, "non-removable=%c\n" , |
256 | mmc_card_is_removable(host->mmc) ? 'N' : 'Y'); |
257 | dev_dbg(dev, "cd_gpio %c, wp_gpio %c\n" , |
258 | (mmc_gpio_get_cd(host->mmc) != -ENOSYS) ? 'Y' : 'N', |
259 | (mmc_gpio_get_ro(host->mmc) != -ENOSYS) ? 'Y' : 'N'); |
260 | |
261 | if (!mmc_card_is_removable(host: host->mmc)) |
262 | host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; |
263 | |
264 | dev_dbg(dev, "is_8bit=%c\n" , |
265 | (host->mmc->caps & MMC_CAP_8_BIT_DATA) ? 'Y' : 'N'); |
266 | |
267 | ret = sdhci_bcm_kona_sd_reset(host); |
268 | if (ret) |
269 | goto err_clk_disable; |
270 | |
271 | sdhci_bcm_kona_sd_init(host); |
272 | |
273 | ret = sdhci_add_host(host); |
274 | if (ret) |
275 | goto err_reset; |
276 | |
277 | /* if device is eMMC, emulate card insert right here */ |
278 | if (!mmc_card_is_removable(host: host->mmc)) { |
279 | ret = sdhci_bcm_kona_sd_card_emulate(host, insert: 1); |
280 | if (ret) { |
281 | dev_err(dev, |
282 | "unable to emulate card insertion\n" ); |
283 | goto err_remove_host; |
284 | } |
285 | } |
286 | /* |
287 | * Since the card detection GPIO interrupt is configured to be |
288 | * edge sensitive, check the initial GPIO value here, emulate |
289 | * only if the card is present |
290 | */ |
291 | if (mmc_gpio_get_cd(host: host->mmc) > 0) |
292 | sdhci_bcm_kona_sd_card_emulate(host, insert: 1); |
293 | |
294 | dev_dbg(dev, "initialized properly\n" ); |
295 | return 0; |
296 | |
297 | err_remove_host: |
298 | sdhci_remove_host(host, dead: 0); |
299 | |
300 | err_reset: |
301 | sdhci_bcm_kona_sd_reset(host); |
302 | |
303 | err_clk_disable: |
304 | clk_disable_unprepare(clk: pltfm_priv->clk); |
305 | |
306 | err_pltfm_free: |
307 | sdhci_pltfm_free(pdev); |
308 | |
309 | dev_err(dev, "Probing of sdhci-pltfm failed: %d\n" , ret); |
310 | return ret; |
311 | } |
312 | |
313 | static void sdhci_bcm_kona_remove(struct platform_device *pdev) |
314 | { |
315 | struct sdhci_host *host = platform_get_drvdata(pdev); |
316 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
317 | struct clk *clk = pltfm_host->clk; |
318 | |
319 | sdhci_pltfm_remove(pdev); |
320 | clk_disable_unprepare(clk); |
321 | } |
322 | |
323 | static struct platform_driver sdhci_bcm_kona_driver = { |
324 | .driver = { |
325 | .name = "sdhci-kona" , |
326 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
327 | .pm = &sdhci_pltfm_pmops, |
328 | .of_match_table = sdhci_bcm_kona_of_match, |
329 | }, |
330 | .probe = sdhci_bcm_kona_probe, |
331 | .remove_new = sdhci_bcm_kona_remove, |
332 | }; |
333 | module_platform_driver(sdhci_bcm_kona_driver); |
334 | |
335 | MODULE_DESCRIPTION("SDHCI driver for Broadcom Kona platform" ); |
336 | MODULE_AUTHOR("Broadcom" ); |
337 | MODULE_LICENSE("GPL v2" ); |
338 | |