1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * SDIO interface.
4 *
5 * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
6 * Copyright (c) 2010, ST-Ericsson
7 */
8 #include <linux/module.h>
9 #include <linux/mmc/sdio.h>
10 #include <linux/mmc/sdio_func.h>
11 #include <linux/mmc/card.h>
12 #include <linux/interrupt.h>
13 #include <linux/of.h>
14 #include <linux/of_irq.h>
15 #include <linux/irq.h>
16 #include <linux/align.h>
17 #include <linux/pm.h>
18
19 #include "bus.h"
20 #include "wfx.h"
21 #include "hwio.h"
22 #include "main.h"
23 #include "bh.h"
24
25 static const struct wfx_platform_data pdata_wf200 = {
26 .file_fw = "wfx/wfm_wf200",
27 .file_pds = "wfx/wf200.pds",
28 };
29
30 static const struct wfx_platform_data pdata_brd4001a = {
31 .file_fw = "wfx/wfm_wf200",
32 .file_pds = "wfx/brd4001a.pds",
33 };
34
35 static const struct wfx_platform_data pdata_brd8022a = {
36 .file_fw = "wfx/wfm_wf200",
37 .file_pds = "wfx/brd8022a.pds",
38 };
39
40 static const struct wfx_platform_data pdata_brd8023a = {
41 .file_fw = "wfx/wfm_wf200",
42 .file_pds = "wfx/brd8023a.pds",
43 };
44
45 struct wfx_sdio_priv {
46 struct sdio_func *func;
47 struct wfx_dev *core;
48 u8 buf_id_tx;
49 u8 buf_id_rx;
50 int of_irq;
51 };
52
wfx_sdio_copy_from_io(void * priv,unsigned int reg_id,void * dst,size_t count)53 static int wfx_sdio_copy_from_io(void *priv, unsigned int reg_id, void *dst, size_t count)
54 {
55 struct wfx_sdio_priv *bus = priv;
56 unsigned int sdio_addr = reg_id << 2;
57 int ret;
58
59 WARN(reg_id > 7, "chip only has 7 registers");
60 WARN(!IS_ALIGNED((uintptr_t)dst, 4), "unaligned buffer address");
61 WARN(!IS_ALIGNED(count, 4), "unaligned buffer size");
62
63 /* Use queue mode buffers */
64 if (reg_id == WFX_REG_IN_OUT_QUEUE)
65 sdio_addr |= (bus->buf_id_rx + 1) << 7;
66 ret = sdio_memcpy_fromio(bus->func, dst, sdio_addr, count);
67 if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE)
68 bus->buf_id_rx = (bus->buf_id_rx + 1) % 4;
69
70 return ret;
71 }
72
wfx_sdio_copy_to_io(void * priv,unsigned int reg_id,const void * src,size_t count)73 static int wfx_sdio_copy_to_io(void *priv, unsigned int reg_id, const void *src, size_t count)
74 {
75 struct wfx_sdio_priv *bus = priv;
76 unsigned int sdio_addr = reg_id << 2;
77 int ret;
78
79 WARN(reg_id > 7, "chip only has 7 registers");
80 WARN(!IS_ALIGNED((uintptr_t)src, 4), "unaligned buffer address");
81 WARN(!IS_ALIGNED(count, 4), "unaligned buffer size");
82
83 /* Use queue mode buffers */
84 if (reg_id == WFX_REG_IN_OUT_QUEUE)
85 sdio_addr |= bus->buf_id_tx << 7;
86 /* FIXME: discards 'const' qualifier for src */
87 ret = sdio_memcpy_toio(bus->func, sdio_addr, (void *)src, count);
88 if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE)
89 bus->buf_id_tx = (bus->buf_id_tx + 1) % 32;
90
91 return ret;
92 }
93
wfx_sdio_lock(void * priv)94 static void wfx_sdio_lock(void *priv)
95 {
96 struct wfx_sdio_priv *bus = priv;
97
98 sdio_claim_host(bus->func);
99 }
100
wfx_sdio_unlock(void * priv)101 static void wfx_sdio_unlock(void *priv)
102 {
103 struct wfx_sdio_priv *bus = priv;
104
105 sdio_release_host(bus->func);
106 }
107
wfx_sdio_irq_handler(struct sdio_func * func)108 static void wfx_sdio_irq_handler(struct sdio_func *func)
109 {
110 struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
111
112 wfx_bh_request_rx(bus->core);
113 }
114
wfx_sdio_irq_handler_ext(int irq,void * priv)115 static irqreturn_t wfx_sdio_irq_handler_ext(int irq, void *priv)
116 {
117 struct wfx_sdio_priv *bus = priv;
118
119 sdio_claim_host(bus->func);
120 wfx_bh_request_rx(bus->core);
121 sdio_release_host(bus->func);
122 return IRQ_HANDLED;
123 }
124
wfx_sdio_irq_subscribe(void * priv)125 static int wfx_sdio_irq_subscribe(void *priv)
126 {
127 struct wfx_sdio_priv *bus = priv;
128 u32 flags;
129 int ret;
130 u8 cccr;
131
132 if (!bus->of_irq) {
133 sdio_claim_host(bus->func);
134 ret = sdio_claim_irq(bus->func, wfx_sdio_irq_handler);
135 sdio_release_host(bus->func);
136 return ret;
137 }
138
139 flags = irq_get_trigger_type(bus->of_irq);
140 if (!flags)
141 flags = IRQF_TRIGGER_HIGH;
142 flags |= IRQF_ONESHOT;
143 ret = devm_request_threaded_irq(&bus->func->dev, bus->of_irq, NULL,
144 wfx_sdio_irq_handler_ext, flags, "wfx", bus);
145 if (ret)
146 return ret;
147 sdio_claim_host(bus->func);
148 cccr = sdio_f0_readb(bus->func, SDIO_CCCR_IENx, NULL);
149 cccr |= BIT(0);
150 cccr |= BIT(bus->func->num);
151 sdio_f0_writeb(bus->func, cccr, SDIO_CCCR_IENx, NULL);
152 sdio_release_host(bus->func);
153 return 0;
154 }
155
wfx_sdio_irq_unsubscribe(void * priv)156 static int wfx_sdio_irq_unsubscribe(void *priv)
157 {
158 struct wfx_sdio_priv *bus = priv;
159 int ret;
160
161 if (bus->of_irq)
162 devm_free_irq(&bus->func->dev, bus->of_irq, bus);
163 sdio_claim_host(bus->func);
164 ret = sdio_release_irq(bus->func);
165 sdio_release_host(bus->func);
166 return ret;
167 }
168
wfx_sdio_align_size(void * priv,size_t size)169 static size_t wfx_sdio_align_size(void *priv, size_t size)
170 {
171 struct wfx_sdio_priv *bus = priv;
172
173 return sdio_align_size(bus->func, size);
174 }
175
wfx_sdio_set_wakeup(void * priv,bool enabled)176 static void wfx_sdio_set_wakeup(void *priv, bool enabled)
177 {
178 struct wfx_sdio_priv *bus = priv;
179
180 device_set_wakeup_enable(&bus->func->dev, enabled);
181 }
182
183 static const struct wfx_hwbus_ops wfx_sdio_hwbus_ops = {
184 .copy_from_io = wfx_sdio_copy_from_io,
185 .copy_to_io = wfx_sdio_copy_to_io,
186 .irq_subscribe = wfx_sdio_irq_subscribe,
187 .irq_unsubscribe = wfx_sdio_irq_unsubscribe,
188 .lock = wfx_sdio_lock,
189 .unlock = wfx_sdio_unlock,
190 .align_size = wfx_sdio_align_size,
191 .set_wakeup = wfx_sdio_set_wakeup,
192 };
193
194 static const struct of_device_id wfx_sdio_of_match[] = {
195 { .compatible = "silabs,wf200", .data = &pdata_wf200 },
196 { .compatible = "silabs,brd4001a", .data = &pdata_brd4001a },
197 { .compatible = "silabs,brd8022a", .data = &pdata_brd8022a },
198 { .compatible = "silabs,brd8023a", .data = &pdata_brd8023a },
199 { },
200 };
201 MODULE_DEVICE_TABLE(of, wfx_sdio_of_match);
202
wfx_sdio_suspend(struct device * dev)203 static int wfx_sdio_suspend(struct device *dev)
204 {
205 struct sdio_func *func = dev_to_sdio_func(dev);
206 struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
207 int ret;
208
209 if (!device_may_wakeup(dev))
210 return 0;
211
212 flush_work(&bus->core->hif.bh);
213 /* Either "wakeup-source" attribute or out-of-band IRQ is required for
214 * WoWLAN
215 */
216 if (bus->of_irq) {
217 ret = enable_irq_wake(bus->of_irq);
218 if (ret)
219 return ret;
220 } else {
221 ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
222 if (ret)
223 return ret;
224 }
225 return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
226 }
227
wfx_sdio_resume(struct device * dev)228 static int wfx_sdio_resume(struct device *dev)
229 {
230 struct sdio_func *func = dev_to_sdio_func(dev);
231 struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
232
233 if (!device_may_wakeup(dev))
234 return 0;
235 if (bus->of_irq)
236 return disable_irq_wake(bus->of_irq);
237 else
238 return 0;
239 }
240
wfx_sdio_probe(struct sdio_func * func,const struct sdio_device_id * id)241 static int wfx_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
242 {
243 const struct wfx_platform_data *pdata = of_device_get_match_data(&func->dev);
244 mmc_pm_flag_t pm_flag = sdio_get_host_pm_caps(func);
245 struct device_node *np = func->dev.of_node;
246 struct wfx_sdio_priv *bus;
247 int ret;
248
249 if (func->num != 1) {
250 dev_err(&func->dev, "SDIO function number is %d while it should always be 1 (unsupported chip?)\n",
251 func->num);
252 return -ENODEV;
253 }
254
255 if (!pdata) {
256 dev_warn(&func->dev, "no compatible device found in DT\n");
257 return -ENODEV;
258 }
259
260 bus = devm_kzalloc(&func->dev, sizeof(*bus), GFP_KERNEL);
261 if (!bus)
262 return -ENOMEM;
263
264 bus->func = func;
265 bus->of_irq = irq_of_parse_and_map(np, 0);
266 sdio_set_drvdata(func, bus);
267
268 sdio_claim_host(func);
269 ret = sdio_enable_func(func);
270 /* Block of 64 bytes is more efficient than 512B for frame sizes < 4k */
271 sdio_set_block_size(func, 64);
272 sdio_release_host(func);
273 if (ret)
274 return ret;
275
276 bus->core = wfx_init_common(&func->dev, pdata, &wfx_sdio_hwbus_ops, bus);
277 if (!bus->core) {
278 ret = -EIO;
279 goto sdio_release;
280 }
281
282 ret = wfx_probe(bus->core);
283 if (ret)
284 goto sdio_release;
285
286 if (pm_flag & MMC_PM_KEEP_POWER)
287 device_set_wakeup_capable(&func->dev, true);
288
289 return 0;
290
291 sdio_release:
292 sdio_claim_host(func);
293 sdio_disable_func(func);
294 sdio_release_host(func);
295 return ret;
296 }
297
wfx_sdio_remove(struct sdio_func * func)298 static void wfx_sdio_remove(struct sdio_func *func)
299 {
300 struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
301
302 wfx_release(bus->core);
303 sdio_claim_host(func);
304 sdio_disable_func(func);
305 sdio_release_host(func);
306 }
307
308 static const struct sdio_device_id wfx_sdio_ids[] = {
309 /* WF200 does not have official VID/PID */
310 { SDIO_DEVICE(0x0000, 0x1000) },
311 { },
312 };
313 MODULE_DEVICE_TABLE(sdio, wfx_sdio_ids);
314
315 static DEFINE_SIMPLE_DEV_PM_OPS(wfx_sdio_pm_ops, wfx_sdio_suspend, wfx_sdio_resume);
316
317 struct sdio_driver wfx_sdio_driver = {
318 .name = "wfx-sdio",
319 .id_table = wfx_sdio_ids,
320 .probe = wfx_sdio_probe,
321 .remove = wfx_sdio_remove,
322 .drv = {
323 .of_match_table = wfx_sdio_of_match,
324 .pm = &wfx_sdio_pm_ops,
325 }
326 };
327