xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/sdio/native_sdio/src/dev_quirks.c (revision 7cbbd39379b4c6f3666de26d3fab0db60241c14b)
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  */
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  */
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  */
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  */
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  */
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  */
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
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
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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