1 /*
2 * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include <linux/mmc/card.h>
21 #include <linux/mmc/mmc.h>
22 #include <linux/mmc/host.h>
23 #include <linux/mmc/sdio_func.h>
24 #include <linux/mmc/sdio_ids.h>
25 #include <linux/mmc/sdio.h>
26 #include <linux/mmc/sd.h>
27 #include <linux/kthread.h>
28 #include <linux/version.h>
29 #include <linux/module.h>
30 #include <qdf_atomic.h>
31 #include <cds_utils.h>
32 #include <qdf_timer.h>
33 #include <cds_api.h>
34 #include <qdf_time.h>
35 #include "hif_sdio_dev.h"
36 #include "if_sdio.h"
37 #include "regtable_sdio.h"
38 #include "wma_api.h"
39 #include "hif_internal.h"
40 #include <transfer/transfer.h>
41
42 /* QUIRK PARAMETERS */
43 unsigned int writecccr1;
44 module_param(writecccr1, uint, 0644);
45 unsigned int writecccr1value;
46 module_param(writecccr1value, uint, 0644);
47
48 unsigned int writecccr2;
49 module_param(writecccr2, uint, 0644);
50 unsigned int writecccr2value;
51 module_param(writecccr2value, uint, 0644);
52
53 unsigned int writecccr3;
54 module_param(writecccr3, uint, 0644);
55 unsigned int writecccr3value;
56 module_param(writecccr3value, uint, 0644);
57
58 unsigned int writecccr4;
59 module_param(writecccr4, uint, 0644);
60 unsigned int writecccr4value;
61 module_param(writecccr4value, uint, 0644);
62
63 unsigned int modstrength;
64 module_param(modstrength, uint, 0644);
65 MODULE_PARM_DESC(modstrength, "Adjust internal driver strength");
66
67 unsigned int mmcbuswidth;
68 /* PERM:S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH */
69 module_param(mmcbuswidth, uint, 0644);
70 MODULE_PARM_DESC(mmcbuswidth,
71 "Set MMC driver Bus Width: 1-1Bit, 4-4Bit, 8-8Bit");
72
73 unsigned int mmcclock;
74 module_param(mmcclock, uint, 0644);
75 MODULE_PARM_DESC(mmcclock, "Set MMC driver Clock value");
76
77 #ifdef CONFIG_X86
78 unsigned int asyncintdelay = 2;
79 module_param(asyncintdelay, uint, 0644);
80 MODULE_PARM_DESC(asyncintdelay, "Delay clock count for async interrupt, 2 is default, valid values are 1 and 2");
81 #else
82 unsigned int asyncintdelay;
83 module_param(asyncintdelay, uint, 0644);
84 MODULE_PARM_DESC(asyncintdelay, "Delay clock count for async interrupt, 0 is default, valid values are 1 and 2");
85 #endif
86
87 unsigned int brokenirq;
88 module_param(brokenirq, uint, 0644);
89 MODULE_PARM_DESC(brokenirq,
90 "Set as 1 to use polling method instead of interrupt mode");
91
92 #ifdef CONFIG_SDIO_TRANSFER_MAILBOX
93 /**
94 * hif_sdio_quirk_force_drive_strength() - Set SDIO drive strength
95 * @ol_sc: softc instance
96 * @func: pointer to sdio_func
97 *
98 * This function forces the driver strength of the SDIO
99 * Call this with the sdhci host claimed
100 *
101 * Return: none.
102 */
hif_sdio_quirk_force_drive_strength(struct hif_softc * ol_sc,struct sdio_func * func)103 void hif_sdio_quirk_force_drive_strength(struct hif_softc *ol_sc,
104 struct sdio_func *func)
105 {
106 int err = 0;
107 unsigned char value = 0;
108 uint32_t mask = 0, addr = SDIO_CCCR_DRIVE_STRENGTH;
109
110 err = func0_cmd52_read_byte(func->card, addr, &value);
111 if (err) {
112 hif_err("read driver strength 0x%02X fail %d", addr, err);
113 return;
114 }
115
116 mask = (SDIO_DRIVE_DTSx_MASK << SDIO_DRIVE_DTSx_SHIFT);
117 value = (value & ~mask) | SDIO_DTSx_SET_TYPE_D;
118 err = func0_cmd52_write_byte(func->card, addr, value);
119 if (err) {
120 hif_err("Write driver strength 0x%02X to 0x%02X failed: %d",
121 (uint32_t)value, addr, err);
122 return;
123 }
124
125 value = 0;
126 addr = CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR;
127 err = func0_cmd52_read_byte(func->card, addr, &value);
128 if (err) {
129 hif_err("Read CCCR 0x%02X failed: %d", addr, err);
130 return;
131 }
132
133 mask = CCCR_SDIO_DRIVER_STRENGTH_ENABLE_MASK;
134 value = (value & ~mask) | CCCR_SDIO_DRIVER_STRENGTH_ENABLE_A |
135 CCCR_SDIO_DRIVER_STRENGTH_ENABLE_C |
136 CCCR_SDIO_DRIVER_STRENGTH_ENABLE_D;
137 err = func0_cmd52_write_byte(func->card, addr, value);
138 if (err)
139 hif_err("Write CCCR 0x%02X to 0x%02X failed: %d",
140 addr, value, err);
141 }
142
143 /**
144 * hif_sdio_quirk_async_intr() - Set asynchronous interrupt settings
145 * @ol_sc: softc instance
146 * @func: pointer to sdio_func
147 *
148 * The values are taken from the module parameter asyncintdelay
149 * Call this with the sdhci host claimed
150 *
151 * Return: none.
152 */
hif_sdio_quirk_async_intr(struct hif_softc * ol_sc,struct sdio_func * func)153 int hif_sdio_quirk_async_intr(struct hif_softc *ol_sc, struct sdio_func *func)
154 {
155 uint8_t data;
156 uint16_t manfid;
157 int set_async_irq = 0, ret = 0;
158 struct hif_sdio_dev *device = get_hif_device(ol_sc, func);
159
160 manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
161
162 switch (manfid) {
163 case MANUFACTURER_ID_AR6003_BASE:
164 set_async_irq = 1;
165 ret =
166 func0_cmd52_write_byte(func->card,
167 CCCR_SDIO_IRQ_MODE_REG_AR6003,
168 SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_AR6003);
169 if (ret)
170 return ret;
171 break;
172 case MANUFACTURER_ID_AR6320_BASE:
173 case MANUFACTURER_ID_QCA9377_BASE:
174 case MANUFACTURER_ID_QCA9379_BASE:
175 set_async_irq = 1;
176 ret = func0_cmd52_read_byte(func->card,
177 CCCR_SDIO_IRQ_MODE_REG_AR6320,
178 &data);
179 if (ret)
180 return ret;
181
182 data |= SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_AR6320;
183 ret = func0_cmd52_write_byte(func->card,
184 CCCR_SDIO_IRQ_MODE_REG_AR6320,
185 data);
186 if (ret)
187 return ret;
188 break;
189 }
190
191 if (asyncintdelay) {
192 /* Set CCCR 0xF0[7:6] to increase async interrupt delay clock
193 * to fix interrupt missing issue on dell 8460p
194 */
195
196 ret = func0_cmd52_read_byte(func->card,
197 CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS,
198 &data);
199 if (ret)
200 return ret;
201
202 data = (data & ~CCCR_SDIO_ASYNC_INT_DELAY_MASK) |
203 ((asyncintdelay << CCCR_SDIO_ASYNC_INT_DELAY_LSB) &
204 CCCR_SDIO_ASYNC_INT_DELAY_MASK);
205
206 ret = func0_cmd52_write_byte(func->card,
207 CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS,
208 data);
209 if (ret)
210 return ret;
211 }
212
213 return ret;
214 }
215 #else
216 /**
217 * hif_sdio_quirk_force_drive_strength() - Set SDIO drive strength
218 * @ol_sc: softc instance
219 * @func: pointer to sdio_func
220 *
221 * This function forces the driver strength of the SDIO
222 * Call this with the sdhci host claimed
223 *
224 * Return: none.
225 */
hif_sdio_quirk_force_drive_strength(struct hif_softc * ol_sc,struct sdio_func * func)226 void hif_sdio_quirk_force_drive_strength(struct hif_softc *ol_sc,
227 struct sdio_func *func)
228 {
229 }
230
231 /**
232 * hif_sdio_quirk_async_intr() - Set asynchronous interrupt settings
233 * @ol_sc: softc instance
234 * @func: pointer to sdio_func
235 *
236 * The values are taken from the module parameter asyncintdelay
237 * Call this with the sdhci host claimed
238 *
239 * Return: none.
240 */
hif_sdio_quirk_async_intr(struct hif_softc * ol_sc,struct sdio_func * func)241 int hif_sdio_quirk_async_intr(struct hif_softc *ol_sc, struct sdio_func *func)
242 {
243 return 0;
244 }
245 #endif
246
247 /**
248 * hif_sdio_quirk_write_cccr() - write a desired CCCR register
249 * @ol_sc: softc instance
250 * @func: pointer to sdio_func
251 *
252 * The values are taken from the module parameter writecccr
253 * Call this with the sdhci host claimed
254 *
255 * Return: none.
256 */
hif_sdio_quirk_write_cccr(struct hif_softc * ol_sc,struct sdio_func * func)257 void hif_sdio_quirk_write_cccr(struct hif_softc *ol_sc, struct sdio_func *func)
258 {
259 int32_t err;
260
261 if (writecccr1) {
262 err = func0_cmd52_write_byte(func->card, writecccr1,
263 writecccr1value);
264 if (err)
265 hif_err("Write CCCR 0x%02X to 0x%02X failed: %d",
266 (unsigned int)writecccr1,
267 (unsigned int)writecccr1value,
268 err);
269 else
270 hif_info("%s Write CCCR 0x%02X to 0x%02X OK",
271 (unsigned int)writecccr1,
272 writecccr1value);
273 }
274
275 if (writecccr2) {
276 err = func0_cmd52_write_byte(func->card, writecccr2,
277 writecccr2value);
278 if (err)
279 hif_err("Write CCCR 0x%02X to 0x%02X failed: %d",
280 (unsigned int)writecccr2,
281 (unsigned int)writecccr2value,
282 err);
283 else
284 hif_info("%s Write CCCR 0x%02X to 0x%02X OK",
285 (unsigned int)writecccr2,
286 (unsigned int)writecccr2value);
287 }
288 if (writecccr3) {
289 err = func0_cmd52_write_byte(func->card, writecccr3,
290 writecccr3value);
291 if (err)
292 hif_err("Write CCCR 0x%02X to 0x%02X failed: %d",
293 (unsigned int)writecccr3,
294 (unsigned int)writecccr3value,
295 err);
296 else
297 hif_info("%s Write CCCR 0x%02X to 0x%02X OK",
298 (unsigned int)writecccr3,
299 (unsigned int)writecccr3value);
300 }
301 if (writecccr4) {
302 err = func0_cmd52_write_byte(func->card, writecccr4,
303 writecccr4value);
304 if (err)
305 hif_err("Write CCCR 0x%02X to 0x%02X failed: %d",
306 (unsigned int)writecccr4,
307 (unsigned int)writecccr4value,
308 err);
309 else
310 hif_info("%s Write CCCR 0x%02X to 0x%02X OK",
311 (unsigned int)writecccr4,
312 (unsigned int)writecccr4value);
313 }
314 }
315
316 /**
317 * hif_sdio_quirk_mod_strength() - write a desired CCCR register
318 * @ol_sc: softc instance
319 * @func: pointer to sdio_func
320 *
321 * The values are taken from the module parameter writecccr
322 * Call this with the sdhci host claimed
323 *
324 * Return: none.
325 */
hif_sdio_quirk_mod_strength(struct hif_softc * ol_sc,struct sdio_func * func)326 int hif_sdio_quirk_mod_strength(struct hif_softc *ol_sc, struct sdio_func *func)
327 {
328 int ret = 0;
329 uint32_t addr, value;
330 struct hif_sdio_dev *device = get_hif_device(ol_sc, func);
331 uint16_t manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
332
333 if (!modstrength) /* TODO: Dont set this : scn is not populated yet */
334 return 0;
335
336 if (!scn) {
337 hif_err("scn is null");
338 return -1;
339 }
340
341 if (!scn->hostdef) {
342 hif_err("scn->hostdef is null");
343 return -1;
344 }
345
346 switch (manfid) {
347 case MANUFACTURER_ID_QCN7605_BASE:
348 break;
349 default:
350 addr = WINDOW_DATA_ADDRESS;
351 value = 0x0FFF;
352 ret = sdio_memcpy_toio(func, addr, &value, 4);
353 if (ret) {
354 hif_err("write 0x%x 0x%x error:%d", addr, value, ret);
355 break;
356 }
357 hif_info("addr 0x%x val 0x%x", addr, value);
358
359 addr = WINDOW_WRITE_ADDR_ADDRESS;
360 value = 0x50F8;
361 ret = sdio_memcpy_toio(func, addr, &value, 4);
362 if (ret) {
363 hif_err("write 0x%x 0x%x error:%d", addr, value, ret);
364 break;
365 }
366 hif_info("addr 0x%x val 0x%x", addr, value);
367 break;
368 }
369
370 return ret;
371 }
372
373 #if KERNEL_VERSION(3, 4, 0) <= LINUX_VERSION_CODE
374 #ifdef SDIO_BUS_WIDTH_8BIT
hif_cmd52_write_byte_8bit(struct sdio_func * func)375 static int hif_cmd52_write_byte_8bit(struct sdio_func *func)
376 {
377 return func0_cmd52_write_byte(func->card, SDIO_CCCR_IF,
378 SDIO_BUS_CD_DISABLE | SDIO_BUS_WIDTH_8BIT);
379 }
380 #else
hif_cmd52_write_byte_8bit(struct sdio_func * func)381 static int hif_cmd52_write_byte_8bit(struct sdio_func *func)
382 {
383 hif_err("8BIT Bus Width not supported");
384 return QDF_STATUS_E_FAILURE;
385 }
386 #endif
387 #endif
388
389 /**
390 * hif_sdio_set_bus_speed() - Set the sdio bus speed
391 * @ol_sc: softc instance
392 * @func: pointer to sdio_func
393 *
394 * Return: QDF_STATUS
395 */
hif_sdio_set_bus_speed(struct hif_softc * ol_sc,struct sdio_func * func)396 QDF_STATUS hif_sdio_set_bus_speed(struct hif_softc *ol_sc,
397 struct sdio_func *func)
398 {
399 uint32_t clock, clock_set = 12500000;
400 struct hif_sdio_dev *device = get_hif_device(ol_sc, func);
401 uint16_t manfid;
402
403 manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
404
405 if (manfid == MANUFACTURER_ID_QCN7605_BASE)
406 return QDF_STATUS_SUCCESS;
407
408 if (mmcclock > 0)
409 clock_set = mmcclock;
410 #if (KERNEL_VERSION(3, 16, 0) > LINUX_VERSION_CODE)
411 if (sdio_card_highspeed(func->card))
412 #else
413 if (mmc_card_hs(func->card))
414 #endif
415 clock = 50000000;
416 else
417 clock = func->card->cis.max_dtr;
418
419 if (clock > device->host->f_max)
420 clock = device->host->f_max;
421
422 hif_info("Clock setting: (%d,%d)",
423 func->card->cis.max_dtr, device->host->f_max);
424
425 /* Limit clock if specified */
426 if (mmcclock > 0) {
427 hif_info("Limit clock from %d to %d", clock, clock_set);
428 device->host->ios.clock = clock_set;
429 device->host->ops->set_ios(device->host,
430 &device->host->ios);
431 }
432
433 return QDF_STATUS_SUCCESS;
434 }
435
436 /**
437 * hif_sdio_set_bus_width() - Set the sdio bus width
438 * @ol_sc: softc instance
439 * @func: pointer to sdio_func
440 *
441 * Return: QDF_STATUS
442 */
hif_sdio_set_bus_width(struct hif_softc * ol_sc,struct sdio_func * func)443 QDF_STATUS hif_sdio_set_bus_width(struct hif_softc *ol_sc,
444 struct sdio_func *func)
445 {
446 int ret = 0;
447 uint16_t manfid;
448 uint8_t data = 0;
449 struct hif_sdio_dev *device = get_hif_device(ol_sc, func);
450 QDF_STATUS status = QDF_STATUS_SUCCESS;
451
452 manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
453
454 if (manfid == MANUFACTURER_ID_QCN7605_BASE)
455 return status;
456
457 #if KERNEL_VERSION(3, 4, 0) <= LINUX_VERSION_CODE
458 if (mmcbuswidth == 0)
459 return status;
460
461 /* Set MMC Bus Width: 1-1Bit, 4-4Bit, 8-8Bit */
462 if (mmcbuswidth == 1) {
463 data = SDIO_BUS_CD_DISABLE | SDIO_BUS_WIDTH_1BIT;
464 ret = func0_cmd52_write_byte(func->card,
465 SDIO_CCCR_IF,
466 data);
467 if (ret)
468 hif_err("Bus Width 0x%x failed %d", data, ret);
469 device->host->ios.bus_width = MMC_BUS_WIDTH_1;
470 device->host->ops->set_ios(device->host,
471 &device->host->ios);
472 } else if (mmcbuswidth == 4 &&
473 (device->host->caps & MMC_CAP_4_BIT_DATA)) {
474 data = SDIO_BUS_CD_DISABLE | SDIO_BUS_WIDTH_4BIT;
475 ret = func0_cmd52_write_byte(func->card,
476 SDIO_CCCR_IF,
477 data);
478 if (ret)
479 hif_err("Bus Width 0x%x failed: %d", data, ret);
480 device->host->ios.bus_width = MMC_BUS_WIDTH_4;
481 device->host->ops->set_ios(device->host,
482 &device->host->ios);
483 } else if (mmcbuswidth == 8 &&
484 (device->host->caps & MMC_CAP_8_BIT_DATA)) {
485 ret = hif_cmd52_write_byte_8bit(func);
486 if (ret)
487 hif_err("Bus Width 8 failed: %d", ret);
488 device->host->ios.bus_width = MMC_BUS_WIDTH_8;
489 device->host->ops->set_ios(device->host,
490 &device->host->ios);
491 } else {
492 hif_err("Unsupported bus width %d", mmcbuswidth);
493 status = QDF_STATUS_E_FAILURE;
494 goto out;
495 }
496
497 status = qdf_status_from_os_return(ret);
498
499 out:
500 hif_debug("Bus width: %d", mmcbuswidth);
501 #endif
502 return status;
503 }
504
505
506 /**
507 * hif_mask_interrupt() - Disable hif device irq
508 * @device: pointer to struct hif_sdio_dev
509 *
510 *
511 * Return: None.
512 */
hif_mask_interrupt(struct hif_sdio_dev * device)513 void hif_mask_interrupt(struct hif_sdio_dev *device)
514 {
515 int ret;
516 uint16_t manfid;
517
518 manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
519
520 if (manfid == MANUFACTURER_ID_QCN7605_BASE)
521 return;
522
523 HIF_ENTER();
524
525 /* Mask our function IRQ */
526 sdio_claim_host(device->func);
527 while (atomic_read(&device->irq_handling)) {
528 sdio_release_host(device->func);
529 schedule_timeout_interruptible(HZ / 10);
530 sdio_claim_host(device->func);
531 }
532 ret = sdio_release_irq(device->func);
533 sdio_release_host(device->func);
534 if (ret)
535 hif_err("Failed %d", ret);
536
537 HIF_EXIT();
538 }
539
540 /**
541 * hif_irq_handler() - hif-sdio interrupt handler
542 * @func: pointer to sdio_func
543 *
544 * Return: None.
545 */
hif_irq_handler(struct sdio_func * func)546 static void hif_irq_handler(struct sdio_func *func)
547 {
548 struct hif_sdio_dev *device = get_hif_device(NULL, func);
549 atomic_set(&device->irq_handling, 1);
550 /* release the host during intr so we can use
551 * it when we process cmds
552 */
553 sdio_release_host(device->func);
554 device->htc_callbacks.dsr_handler(device->htc_callbacks.context);
555 sdio_claim_host(device->func);
556 atomic_set(&device->irq_handling, 0);
557 }
558
559 /**
560 * hif_un_mask_interrupt() - Re-enable hif device irq
561 * @device: pointer to struct hif_sdio_dev
562 *
563 *
564 * Return: None.
565 */
hif_un_mask_interrupt(struct hif_sdio_dev * device)566 void hif_un_mask_interrupt(struct hif_sdio_dev *device)
567 {
568 int ret;
569 uint16_t manfid;
570
571 manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
572
573 if (manfid == MANUFACTURER_ID_QCN7605_BASE)
574 return;
575
576 HIF_ENTER();
577 /*
578 * On HP Elitebook 8460P, interrupt mode is not stable
579 * in high throughput, so polling method should be used
580 * instead of interrupt mode.
581 */
582 if (brokenirq) {
583 hif_info("Using broken IRQ mode");
584 device->func->card->host->caps &= ~MMC_CAP_SDIO_IRQ;
585 }
586 /* Register the IRQ Handler */
587 sdio_claim_host(device->func);
588 ret = sdio_claim_irq(device->func, hif_irq_handler);
589 sdio_release_host(device->func);
590
591 HIF_EXIT();
592 }
593
594 /**
595 * hif_sdio_func_disable() - Handle device enabling as per device
596 * @device: HIF device object
597 * @func: function pointer
598 * @reset:
599 *
600 * Return success or failure
601 */
hif_sdio_func_disable(struct hif_sdio_dev * device,struct sdio_func * func,bool reset)602 QDF_STATUS hif_sdio_func_disable(struct hif_sdio_dev *device,
603 struct sdio_func *func,
604 bool reset)
605 {
606 int ret = 0;
607 uint16_t manfid;
608 QDF_STATUS status = QDF_STATUS_SUCCESS;
609
610 manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
611
612 if (manfid == MANUFACTURER_ID_QCN7605_BASE)
613 return 0;
614
615 /* Disable the card */
616 sdio_claim_host(device->func);
617
618 ret = sdio_disable_func(device->func);
619 if (ret)
620 status = QDF_STATUS_E_FAILURE;
621
622 if (reset && status == QDF_STATUS_SUCCESS)
623 ret = func0_cmd52_write_byte(device->func->card,
624 SDIO_CCCR_ABORT,
625 (1 << 3));
626
627 if (ret) {
628 status = QDF_STATUS_E_FAILURE;
629 hif_err("reset failed: %d", ret);
630 }
631
632 sdio_release_host(device->func);
633
634 return status;
635 }
636
637 /**
638 * reinit_sdio() - re-initialize sdio bus
639 * @device: pointer to hif device
640 *
641 * Return: 0 on success, error number otherwise.
642 */
reinit_sdio(struct hif_sdio_dev * device)643 QDF_STATUS reinit_sdio(struct hif_sdio_dev *device)
644 {
645 int32_t err = 0;
646 struct mmc_host *host;
647 struct mmc_card *card;
648 struct sdio_func *func;
649 uint8_t cmd52_resp;
650 uint32_t clock;
651 uint16_t manfid;
652
653 func = device->func;
654 card = func->card;
655 host = card->host;
656
657 manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
658
659 if (manfid == MANUFACTURER_ID_QCN7605_BASE)
660 return QDF_STATUS_SUCCESS;
661
662 sdio_claim_host(func);
663
664 do {
665 /* Enable high speed */
666 if (card->host->caps & MMC_CAP_SD_HIGHSPEED) {
667 hif_debug("Set high speed mode");
668 err = func0_cmd52_read_byte(card, SDIO_CCCR_SPEED,
669 &cmd52_resp);
670 if (err) {
671 hif_err("CCCR speed set failed: %d", err);
672 sdio_card_state(card);
673 /* no need to break */
674 } else {
675 err = func0_cmd52_write_byte(card,
676 SDIO_CCCR_SPEED,
677 (cmd52_resp |
678 SDIO_SPEED_EHS));
679 if (err) {
680 hif_err("CCCR speed set failed: %d", err);
681 break;
682 }
683 sdio_card_set_highspeed(card);
684 host->ios.timing = MMC_TIMING_SD_HS;
685 host->ops->set_ios(host, &host->ios);
686 }
687 }
688
689 /* Set clock */
690 if (sdio_card_highspeed(card))
691 clock = 50000000;
692 else
693 clock = card->cis.max_dtr;
694
695 if (clock > host->f_max)
696 clock = host->f_max;
697 /*
698 * In fpga mode the clk should be set to 12500000,
699 * or will result in scan channel setting timeout error.
700 * So in fpga mode, please set module parameter mmcclock
701 * to 12500000.
702 */
703 if (mmcclock > 0)
704 clock = mmcclock;
705 host->ios.clock = clock;
706 host->ops->set_ios(host, &host->ios);
707
708 if (card->host->caps & MMC_CAP_4_BIT_DATA) {
709 /* Set bus width & disable card detect resistor */
710 err = func0_cmd52_write_byte(card, SDIO_CCCR_IF,
711 SDIO_BUS_CD_DISABLE |
712 SDIO_BUS_WIDTH_4BIT);
713 if (err) {
714 hif_err("Set bus mode failed: %d", err);
715 break;
716 }
717 host->ios.bus_width = MMC_BUS_WIDTH_4;
718 host->ops->set_ios(host, &host->ios);
719 }
720 } while (0);
721
722 sdio_release_host(func);
723
724 return (err) ? QDF_STATUS_E_FAILURE : QDF_STATUS_SUCCESS;
725 }
726