1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. |
5 | * |
6 | *******************************************************************************/ |
7 | |
8 | #include <drv_types.h> |
9 | #include <rtw_debug.h> |
10 | |
11 | static bool rtw_sdio_claim_host_needed(struct sdio_func *func) |
12 | { |
13 | struct dvobj_priv *dvobj = sdio_get_drvdata(func); |
14 | struct sdio_data *sdio_data = &dvobj->intf_data; |
15 | |
16 | if (sdio_data->sys_sdio_irq_thd && sdio_data->sys_sdio_irq_thd == current) |
17 | return false; |
18 | return true; |
19 | } |
20 | |
21 | inline void rtw_sdio_set_irq_thd(struct dvobj_priv *dvobj, void *thd_hdl) |
22 | { |
23 | struct sdio_data *sdio_data = &dvobj->intf_data; |
24 | |
25 | sdio_data->sys_sdio_irq_thd = thd_hdl; |
26 | } |
27 | |
28 | /* |
29 | * Return: |
30 | *0 Success |
31 | *others Fail |
32 | */ |
33 | s32 _sd_cmd52_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata) |
34 | { |
35 | struct adapter *padapter; |
36 | struct dvobj_priv *psdiodev; |
37 | struct sdio_data *psdio; |
38 | |
39 | int err = 0, i; |
40 | struct sdio_func *func; |
41 | |
42 | padapter = pintfhdl->padapter; |
43 | psdiodev = pintfhdl->pintf_dev; |
44 | psdio = &psdiodev->intf_data; |
45 | |
46 | if (padapter->bSurpriseRemoved) |
47 | return err; |
48 | |
49 | func = psdio->func; |
50 | |
51 | for (i = 0; i < cnt; i++) { |
52 | pdata[i] = sdio_readb(func, addr: addr + i, err_ret: &err); |
53 | if (err) |
54 | break; |
55 | } |
56 | return err; |
57 | } |
58 | |
59 | /* |
60 | * Return: |
61 | *0 Success |
62 | *others Fail |
63 | */ |
64 | s32 sd_cmd52_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata) |
65 | { |
66 | struct adapter *padapter; |
67 | struct dvobj_priv *psdiodev; |
68 | struct sdio_data *psdio; |
69 | |
70 | int err = 0; |
71 | struct sdio_func *func; |
72 | bool claim_needed; |
73 | |
74 | padapter = pintfhdl->padapter; |
75 | psdiodev = pintfhdl->pintf_dev; |
76 | psdio = &psdiodev->intf_data; |
77 | |
78 | if (padapter->bSurpriseRemoved) |
79 | return err; |
80 | |
81 | func = psdio->func; |
82 | claim_needed = rtw_sdio_claim_host_needed(func); |
83 | |
84 | if (claim_needed) |
85 | sdio_claim_host(func); |
86 | err = _sd_cmd52_read(pintfhdl, addr, cnt, pdata); |
87 | if (claim_needed) |
88 | sdio_release_host(func); |
89 | return err; |
90 | } |
91 | |
92 | /* |
93 | * Return: |
94 | *0 Success |
95 | *others Fail |
96 | */ |
97 | s32 _sd_cmd52_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata) |
98 | { |
99 | struct adapter *padapter; |
100 | struct dvobj_priv *psdiodev; |
101 | struct sdio_data *psdio; |
102 | |
103 | int err = 0, i; |
104 | struct sdio_func *func; |
105 | |
106 | padapter = pintfhdl->padapter; |
107 | psdiodev = pintfhdl->pintf_dev; |
108 | psdio = &psdiodev->intf_data; |
109 | |
110 | if (padapter->bSurpriseRemoved) |
111 | return err; |
112 | |
113 | func = psdio->func; |
114 | |
115 | for (i = 0; i < cnt; i++) { |
116 | sdio_writeb(func, b: pdata[i], addr: addr + i, err_ret: &err); |
117 | if (err) |
118 | break; |
119 | } |
120 | return err; |
121 | } |
122 | |
123 | /* |
124 | * Return: |
125 | *0 Success |
126 | *others Fail |
127 | */ |
128 | s32 sd_cmd52_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata) |
129 | { |
130 | struct adapter *padapter; |
131 | struct dvobj_priv *psdiodev; |
132 | struct sdio_data *psdio; |
133 | |
134 | int err = 0; |
135 | struct sdio_func *func; |
136 | bool claim_needed; |
137 | |
138 | padapter = pintfhdl->padapter; |
139 | psdiodev = pintfhdl->pintf_dev; |
140 | psdio = &psdiodev->intf_data; |
141 | |
142 | if (padapter->bSurpriseRemoved) |
143 | return err; |
144 | |
145 | func = psdio->func; |
146 | claim_needed = rtw_sdio_claim_host_needed(func); |
147 | |
148 | if (claim_needed) |
149 | sdio_claim_host(func); |
150 | err = _sd_cmd52_write(pintfhdl, addr, cnt, pdata); |
151 | if (claim_needed) |
152 | sdio_release_host(func); |
153 | return err; |
154 | } |
155 | |
156 | u8 sd_read8(struct intf_hdl *pintfhdl, u32 addr, s32 *err) |
157 | { |
158 | struct adapter *padapter; |
159 | struct dvobj_priv *psdiodev; |
160 | struct sdio_data *psdio; |
161 | |
162 | u8 v = 0; |
163 | struct sdio_func *func; |
164 | bool claim_needed; |
165 | |
166 | padapter = pintfhdl->padapter; |
167 | psdiodev = pintfhdl->pintf_dev; |
168 | psdio = &psdiodev->intf_data; |
169 | |
170 | if (padapter->bSurpriseRemoved) |
171 | return v; |
172 | |
173 | func = psdio->func; |
174 | claim_needed = rtw_sdio_claim_host_needed(func); |
175 | |
176 | if (claim_needed) |
177 | sdio_claim_host(func); |
178 | v = sdio_readb(func, addr, err_ret: err); |
179 | if (claim_needed) |
180 | sdio_release_host(func); |
181 | return v; |
182 | } |
183 | |
184 | u32 sd_read32(struct intf_hdl *pintfhdl, u32 addr, s32 *err) |
185 | { |
186 | struct adapter *padapter; |
187 | struct dvobj_priv *psdiodev; |
188 | struct sdio_data *psdio; |
189 | u32 v = 0; |
190 | struct sdio_func *func; |
191 | bool claim_needed; |
192 | |
193 | padapter = pintfhdl->padapter; |
194 | psdiodev = pintfhdl->pintf_dev; |
195 | psdio = &psdiodev->intf_data; |
196 | |
197 | if (padapter->bSurpriseRemoved) |
198 | return v; |
199 | |
200 | func = psdio->func; |
201 | claim_needed = rtw_sdio_claim_host_needed(func); |
202 | |
203 | if (claim_needed) |
204 | sdio_claim_host(func); |
205 | v = sdio_readl(func, addr, err_ret: err); |
206 | if (claim_needed) |
207 | sdio_release_host(func); |
208 | |
209 | if (err && *err) { |
210 | int i; |
211 | |
212 | *err = 0; |
213 | for (i = 0; i < SD_IO_TRY_CNT; i++) { |
214 | if (claim_needed) |
215 | sdio_claim_host(func); |
216 | v = sdio_readl(func, addr, err_ret: err); |
217 | if (claim_needed) |
218 | sdio_release_host(func); |
219 | |
220 | if (*err == 0) { |
221 | rtw_reset_continual_io_error(dvobj: psdiodev); |
222 | break; |
223 | } else { |
224 | if ((-ESHUTDOWN == *err) || (-ENODEV == *err)) |
225 | padapter->bSurpriseRemoved = true; |
226 | |
227 | if (rtw_inc_and_chk_continual_io_error(dvobj: psdiodev) == true) { |
228 | padapter->bSurpriseRemoved = true; |
229 | break; |
230 | } |
231 | } |
232 | } |
233 | } |
234 | return v; |
235 | } |
236 | |
237 | void sd_write8(struct intf_hdl *pintfhdl, u32 addr, u8 v, s32 *err) |
238 | { |
239 | struct adapter *padapter; |
240 | struct dvobj_priv *psdiodev; |
241 | struct sdio_data *psdio; |
242 | struct sdio_func *func; |
243 | bool claim_needed; |
244 | |
245 | padapter = pintfhdl->padapter; |
246 | psdiodev = pintfhdl->pintf_dev; |
247 | psdio = &psdiodev->intf_data; |
248 | |
249 | if (padapter->bSurpriseRemoved) |
250 | return; |
251 | |
252 | func = psdio->func; |
253 | claim_needed = rtw_sdio_claim_host_needed(func); |
254 | |
255 | if (claim_needed) |
256 | sdio_claim_host(func); |
257 | sdio_writeb(func, b: v, addr, err_ret: err); |
258 | if (claim_needed) |
259 | sdio_release_host(func); |
260 | } |
261 | |
262 | void sd_write32(struct intf_hdl *pintfhdl, u32 addr, u32 v, s32 *err) |
263 | { |
264 | struct adapter *padapter; |
265 | struct dvobj_priv *psdiodev; |
266 | struct sdio_data *psdio; |
267 | struct sdio_func *func; |
268 | bool claim_needed; |
269 | |
270 | padapter = pintfhdl->padapter; |
271 | psdiodev = pintfhdl->pintf_dev; |
272 | psdio = &psdiodev->intf_data; |
273 | |
274 | if (padapter->bSurpriseRemoved) |
275 | return; |
276 | |
277 | func = psdio->func; |
278 | claim_needed = rtw_sdio_claim_host_needed(func); |
279 | |
280 | if (claim_needed) |
281 | sdio_claim_host(func); |
282 | sdio_writel(func, b: v, addr, err_ret: err); |
283 | if (claim_needed) |
284 | sdio_release_host(func); |
285 | |
286 | if (err && *err) { |
287 | int i; |
288 | |
289 | *err = 0; |
290 | for (i = 0; i < SD_IO_TRY_CNT; i++) { |
291 | if (claim_needed) |
292 | sdio_claim_host(func); |
293 | sdio_writel(func, b: v, addr, err_ret: err); |
294 | if (claim_needed) |
295 | sdio_release_host(func); |
296 | if (*err == 0) { |
297 | rtw_reset_continual_io_error(dvobj: psdiodev); |
298 | break; |
299 | } else { |
300 | if ((-ESHUTDOWN == *err) || (-ENODEV == *err)) |
301 | padapter->bSurpriseRemoved = true; |
302 | |
303 | if (rtw_inc_and_chk_continual_io_error(dvobj: psdiodev) == true) { |
304 | padapter->bSurpriseRemoved = true; |
305 | break; |
306 | } |
307 | } |
308 | } |
309 | |
310 | } |
311 | } |
312 | |
313 | /* |
314 | * Use CMD53 to read data from SDIO device. |
315 | * This function MUST be called after sdio_claim_host() or |
316 | * in SDIO ISR(host had been claimed). |
317 | * |
318 | * Parameters: |
319 | *psdio pointer of SDIO_DATA |
320 | *addr address to read |
321 | *cnt amount to read |
322 | *pdata pointer to put data, this should be a "DMA:able scratch buffer"! |
323 | * |
324 | * Return: |
325 | *0 Success |
326 | *others Fail |
327 | */ |
328 | s32 _sd_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata) |
329 | { |
330 | struct adapter *padapter; |
331 | struct dvobj_priv *psdiodev; |
332 | struct sdio_data *psdio; |
333 | |
334 | int err = -EPERM; |
335 | struct sdio_func *func; |
336 | |
337 | padapter = pintfhdl->padapter; |
338 | psdiodev = pintfhdl->pintf_dev; |
339 | psdio = &psdiodev->intf_data; |
340 | |
341 | if (padapter->bSurpriseRemoved) |
342 | return err; |
343 | |
344 | func = psdio->func; |
345 | |
346 | if (unlikely((cnt == 1) || (cnt == 2))) { |
347 | int i; |
348 | u8 *pbuf = pdata; |
349 | |
350 | for (i = 0; i < cnt; i++) { |
351 | *(pbuf + i) = sdio_readb(func, addr: addr + i, err_ret: &err); |
352 | |
353 | if (err) |
354 | break; |
355 | } |
356 | return err; |
357 | } |
358 | |
359 | err = sdio_memcpy_fromio(func, dst: pdata, addr, count: cnt); |
360 | |
361 | return err; |
362 | } |
363 | |
364 | /* |
365 | * Use CMD53 to read data from SDIO device. |
366 | * |
367 | * Parameters: |
368 | *psdio pointer of SDIO_DATA |
369 | *addr address to read |
370 | *cnt amount to read |
371 | *pdata pointer to put data, this should be a "DMA:able scratch buffer"! |
372 | * |
373 | * Return: |
374 | *0 Success |
375 | *others Fail |
376 | */ |
377 | s32 sd_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata) |
378 | { |
379 | struct adapter *padapter; |
380 | struct dvobj_priv *psdiodev; |
381 | struct sdio_data *psdio; |
382 | |
383 | struct sdio_func *func; |
384 | bool claim_needed; |
385 | s32 err = -EPERM; |
386 | |
387 | padapter = pintfhdl->padapter; |
388 | psdiodev = pintfhdl->pintf_dev; |
389 | psdio = &psdiodev->intf_data; |
390 | |
391 | if (padapter->bSurpriseRemoved) |
392 | return err; |
393 | |
394 | func = psdio->func; |
395 | claim_needed = rtw_sdio_claim_host_needed(func); |
396 | |
397 | if (claim_needed) |
398 | sdio_claim_host(func); |
399 | err = _sd_read(pintfhdl, addr, cnt, pdata); |
400 | if (claim_needed) |
401 | sdio_release_host(func); |
402 | return err; |
403 | } |
404 | |
405 | /* |
406 | * Use CMD53 to write data to SDIO device. |
407 | * This function MUST be called after sdio_claim_host() or |
408 | * in SDIO ISR(host had been claimed). |
409 | * |
410 | * Parameters: |
411 | *psdio pointer of SDIO_DATA |
412 | *addr address to write |
413 | *cnt amount to write |
414 | *pdata data pointer, this should be a "DMA:able scratch buffer"! |
415 | * |
416 | * Return: |
417 | *0 Success |
418 | *others Fail |
419 | */ |
420 | s32 _sd_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata) |
421 | { |
422 | struct adapter *padapter; |
423 | struct dvobj_priv *psdiodev; |
424 | struct sdio_data *psdio; |
425 | |
426 | struct sdio_func *func; |
427 | u32 size; |
428 | s32 err = -EPERM; |
429 | |
430 | padapter = pintfhdl->padapter; |
431 | psdiodev = pintfhdl->pintf_dev; |
432 | psdio = &psdiodev->intf_data; |
433 | |
434 | if (padapter->bSurpriseRemoved) |
435 | return err; |
436 | |
437 | func = psdio->func; |
438 | /* size = sdio_align_size(func, cnt); */ |
439 | |
440 | if (unlikely((cnt == 1) || (cnt == 2))) { |
441 | int i; |
442 | u8 *pbuf = pdata; |
443 | |
444 | for (i = 0; i < cnt; i++) { |
445 | sdio_writeb(func, b: *(pbuf + i), addr: addr + i, err_ret: &err); |
446 | if (err) |
447 | break; |
448 | } |
449 | |
450 | return err; |
451 | } |
452 | |
453 | size = cnt; |
454 | err = sdio_memcpy_toio(func, addr, src: pdata, count: size); |
455 | |
456 | return err; |
457 | } |
458 | |
459 | /* |
460 | * Use CMD53 to write data to SDIO device. |
461 | * |
462 | * Parameters: |
463 | * psdio pointer of SDIO_DATA |
464 | * addr address to write |
465 | * cnt amount to write |
466 | * pdata data pointer, this should be a "DMA:able scratch buffer"! |
467 | * |
468 | * Return: |
469 | * 0 Success |
470 | * others Fail |
471 | */ |
472 | s32 sd_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata) |
473 | { |
474 | struct adapter *padapter; |
475 | struct dvobj_priv *psdiodev; |
476 | struct sdio_data *psdio; |
477 | struct sdio_func *func; |
478 | bool claim_needed; |
479 | s32 err = -EPERM; |
480 | |
481 | padapter = pintfhdl->padapter; |
482 | psdiodev = pintfhdl->pintf_dev; |
483 | psdio = &psdiodev->intf_data; |
484 | |
485 | if (padapter->bSurpriseRemoved) |
486 | return err; |
487 | |
488 | func = psdio->func; |
489 | claim_needed = rtw_sdio_claim_host_needed(func); |
490 | |
491 | if (claim_needed) |
492 | sdio_claim_host(func); |
493 | err = _sd_write(pintfhdl, addr, cnt, pdata); |
494 | if (claim_needed) |
495 | sdio_release_host(func); |
496 | return err; |
497 | } |
498 | |