MT6620: add the new driver JB2 V1.0
[firefly-linux-kernel-4.4.55.git] / drivers / mtk_wcn_combo / common / linux / hif_sdio.c
1 /*
2 ** $Id: $
3 */
4
5 /*! \file   "hif_sdio.c"
6  * \brief
7  *
8  * detailed description
9 */
10
11 /*
12 ** $Log: $
13  *
14  * 07 25 2010 george.kuo
15  *
16  * Move hif_sdio driver to linux directory.
17  *
18  * 07 23 2010 george.kuo
19  *
20  * Add MT6620 driver source tree
21  * , including char device driver (wmt, bt, gps), stp driver, interface driver (tty ldisc and hif_sdio), and bt hci driver.
22 **
23 **
24 */
25
26
27 /*******************************************************************************
28 *                         C O M P I L E R   F L A G S
29 ********************************************************************************
30 */
31 #define HIF_SDIO_UPDATE (1)
32 #if (WMT_PLAT_APEX==1)
33 #define HIF_SDIO_SUPPORT_SUSPEND (1)
34 #else
35 #define HIF_SDIO_SUPPORT_SUSPEND (0)
36 #endif
37
38 /*******************************************************************************
39 *                    E X T E R N A L   R E F E R E N C E S
40 ********************************************************************************
41 */
42
43
44
45 #include "hif_sdio.h"
46 #include "hif_sdio_chrdev.h"
47
48 #if 0
49 extern void mmc_power_up_ext(struct mmc_host *host);
50 extern void mmc_power_off_ext(struct mmc_host *host);
51 #else
52 #define mmc_power_up_ext(x)
53 #define mmc_power_off_ext(x)
54
55 #endif
56 /*******************************************************************************
57 *                              C O N S T A N T S
58 ********************************************************************************
59 */
60 //#define DRV_NAME "[hif_sdio]"
61
62 /*******************************************************************************
63 *                             D A T A   T Y P E S
64 ********************************************************************************
65 */
66
67 /*******************************************************************************
68 *                                 M A C R O S
69 ********************************************************************************
70 */
71 /*!
72  * \brief A macro used to generate hif_sdio client's context
73  *
74  * Generate a context for hif_sdio client based on the following input parameters
75  * |<-card id (16bits)->|<-block size in unit of 256 bytes(8 bits)->|<-function number(4bits)->|<-index(4bits)->|
76  *
77  * \param manf      the 16 bit manufacturer id
78  * \param card      the 16 bit card id
79  * \param func      the 16 bit function number
80  * \param b_sz    the 16 bit function block size
81  */
82 #define CLTCTX(cid, func, blk_sz, idx) \
83     (MTK_WCN_HIF_SDIO_CLTCTX)( (((UINT32)(cid) & 0xFFFFUL) << 16) | \
84         (((UINT32)(func) & 0xFUL) << 4) | \
85         (((UINT32)(blk_sz) & 0xFF00UL) << 0) | \
86         (((UINT32)idx & 0xFUL) << 0) )
87
88 /*!
89  * \brief A set of macros used to get information out of an hif_sdio client context
90  *
91  * Generate a context for hif_sdio client based on the following input parameters
92  */
93 #define CLTCTX_CID(ctx) (((ctx) >> 16) & 0xFFFF)
94 #define CLTCTX_FUNC(ctx) (((ctx) >> 4) & 0xF)
95 #define CLTCTX_BLK_SZ(ctx) (((ctx) >> 0) & 0xFF00)
96 #define CLTCTX_IDX(ctx) ((ctx) & 0xF)
97 #define CLTCTX_IDX_VALID(idx) ((idx >= 0) && (idx < CFG_CLIENT_COUNT))
98
99 /*******************************************************************************
100 *                   F U N C T I O N   D E C L A R A T I O N S
101 ********************************************************************************
102 */
103 #if HIF_SDIO_SUPPORT_SUSPEND
104 static int hif_sdio_suspend (
105     struct device *dev
106     );
107
108 static int hif_sdio_resume (
109     struct device *dev
110     );
111 #endif
112 static int hif_sdio_probe (
113     struct sdio_func *func,
114     const struct sdio_device_id *id
115     );
116
117 static void hif_sdio_remove (
118     struct sdio_func *func
119     );
120
121 static void hif_sdio_irq (
122     struct sdio_func *func
123     );
124
125 static int hif_sdio_clt_probe_func (
126     MTK_WCN_HIF_SDIO_REGISTINFO *registinfo_p,
127     INT8 probe_idx
128     );
129
130 static void hif_sdio_clt_probe_worker(
131     struct work_struct *work
132     );
133
134 static int hif_sdio_find_probed_list_index_by_func(
135     struct sdio_func *func
136     );
137
138 #if 0 // TODO:[ChangeFeature][George] remove obsolete function?
139 static int hif_sdio_find_probed_list_index_by_clt_index(
140     INT32 clt_index
141     );
142 #endif
143
144 static int hif_sdio_find_probed_list_index_by_id_func(
145     UINT16 vendor,
146     UINT16 device,
147     UINT16 func_num
148     );
149
150 static void hif_sdio_init_clt_list(
151     INT32 index
152     );
153
154 static int hif_sdio_find_clt_list_index (
155     UINT16 vendor,
156     UINT16 device,
157     UINT16 func_num
158     );
159
160 static int hif_sdio_check_supported_sdio_id(
161     UINT16 vendor,
162     UINT16 device
163     );
164
165 static int hif_sdio_check_duplicate_sdio_id(
166     UINT16 vendor,
167     UINT16 device,
168     UINT16 func_num
169     );
170
171 static int hif_sdio_add_clt_list(
172     INT32*  clt_index_p,
173     const MTK_WCN_HIF_SDIO_CLTINFO *pinfo,
174     UINT32 tbl_index
175     );
176
177 static INT32 hif_sdio_stp_on(
178     void
179     );
180
181 static INT32 hif_sdio_stp_off(
182     void
183     );
184
185 static INT32 hif_sdio_wifi_on(
186     void
187     );
188
189 static INT32 hif_sdio_wifi_off(
190     void
191     );
192
193 /*******************************************************************************
194 *                           P R I V A T E   D A T A
195 ********************************************************************************
196 */
197
198 /* Supported SDIO device table */
199 static const struct sdio_device_id mtk_sdio_id_tbl[] = {
200     /* MT6618 */ /* Not an SDIO standard class device */
201     { SDIO_DEVICE(0x037A, 0x018A) }, /* SDIO1:WIFI */
202     { SDIO_DEVICE(0x037A, 0x018B) }, /* SDIO2:FUNC1:BT+FM */
203     { SDIO_DEVICE(0x037A, 0x018C) }, /* 2-function (SDIO2:FUNC1:BT+FM, FUNC2:WIFI) */
204
205     /* MT6619 */ /* Not an SDIO standard class device */
206     { SDIO_DEVICE(0x037A, 0x6619) }, /* SDIO2:FUNC1:BT+FM+GPS */
207
208     /* MT6620 */ /* Not an SDIO standard class device */
209     { SDIO_DEVICE(0x037A, 0x020A) }, /* SDIO1:FUNC1:WIFI */
210     { SDIO_DEVICE(0x037A, 0x020B) }, /* SDIO2:FUNC1:BT+FM+GPS */
211     { SDIO_DEVICE(0x037A, 0x020C) }, /* 2-function (SDIO2:FUNC1:BT+FM+GPS, FUNC2:WIFI) */
212
213     /* MT5921 */ /* Not an SDIO standard class device */
214     { SDIO_DEVICE(0x037A, 0x5921) },
215     
216     /* MT6628 */ /* SDIO1: Wi-Fi, SDIO2: BGF */
217     { SDIO_DEVICE(0x037A, 0x6628) },
218     { /* end: all zeroes */ },
219 };
220
221 #if HIF_SDIO_SUPPORT_SUSPEND
222 static const struct dev_pm_ops mtk_sdio_pmops = {
223     .suspend = hif_sdio_suspend,
224     .resume = hif_sdio_resume,
225 };
226 #endif
227
228 static struct sdio_driver mtk_sdio_client_drv = {
229     .name = "mtk_sdio_client", /* MTK SDIO Client Driver */
230     .id_table = mtk_sdio_id_tbl, /* all supported struct sdio_device_id table */
231     .probe = hif_sdio_probe,
232     .remove = hif_sdio_remove,
233 #if HIF_SDIO_SUPPORT_SUSPEND
234     .drv = {
235        .pm = &mtk_sdio_pmops,
236     },
237 #endif
238 };
239
240 /* Registered client driver list */
241 /* static list g_hif_sdio_clt_drv_list */
242 static MTK_WCN_HIF_SDIO_REGISTINFO g_hif_sdio_clt_drv_list[CFG_CLIENT_COUNT];
243
244 /* MMC probed function list */
245 /* static list g_hif_sdio_probed_func_list */
246 static MTK_WCN_HIF_SDIO_PROBEINFO g_hif_sdio_probed_func_list[CFG_CLIENT_COUNT];
247
248 /* spin lock info for g_hif_sdio_clt_drv_list and g_hif_sdio_probed_func_list */
249 static MTK_WCN_HIF_SDIO_LOCKINFO g_hif_sdio_lock_info;
250
251 /* reference count, debug information? */
252 static int gRefCount;
253 static int (*fp_wmt_tra_sdio_update)(void) = NULL;
254
255
256 /*******************************************************************************
257 *                            P U B L I C   D A T A
258 ********************************************************************************
259 */
260 MODULE_LICENSE("GPL");
261 MODULE_AUTHOR("MediaTek Inc WCN_SE_CS3");
262 MODULE_DESCRIPTION("MediaTek MT6620 HIF SDIO Driver");
263
264 MODULE_DEVICE_TABLE(sdio, mtk_sdio_id_tbl);
265
266 UINT32 gHifSdioDbgLvl = HIF_SDIO_LOG_INFO;
267
268 /*******************************************************************************
269 *                              F U N C T I O N S
270 ********************************************************************************
271 */
272
273 #if (WMT_PLAT_APEX==0)
274 extern int mtk_wcn_sdio_irq_flag_set (int falg);
275 #else
276 int mtk_wcn_sdio_irq_flag_set (int falg)
277 {
278         return 0;
279 }
280 #endif
281
282
283
284 /*!
285  * \brief register the callback funciton for record the timestamp of sdio access 
286  *
287  * \param  callback function
288  *
289  * \retval -EINVAL, when registered callback is invalid
290  * \retval 0, when registered callback is valid
291  */
292 extern INT32 mtk_wcn_hif_sdio_update_cb_reg(int (*ts_update)(void))
293 {
294     if(ts_update){
295         fp_wmt_tra_sdio_update = ts_update;
296         return 0;
297     }
298     else {
299         return -EINVAL;
300     }
301 }
302
303
304 /*!
305  * \brief update the accessing time of SDIO via callback function
306  *
307  * \param  void
308  *
309  * \retval -EINVAL, when callback is not registered
310  * \retval returned value of callback
311  */
312 static INT32 wmt_tra_sdio_update(VOID)
313 {
314     if(fp_wmt_tra_sdio_update){     
315         return (*fp_wmt_tra_sdio_update)();
316     } 
317     else {
318         //HIF_SDIO_WARN_FUNC("wmt_tra_sdio_update == NULL\n");    
319         return -EINVAL;
320     }   
321 }
322 /*!
323  * \brief Translate CLTCTX into a pointer to struct sdio_func if it is valid
324  *
325  * Translate a CLTCTX into a pointer to struct sdio_func if it is
326  *  1) probed by mmc_core, and
327  *  2) client driver is registered, and
328  *  3) clt_idx of client driver is valid
329  *
330  * \param ctx a context provided by client driver
331  *
332  * \retval null if any condition is not valie
333  * \retval a pointer to a struct sdio_func mapped by provided ctx
334  */
335 static inline struct sdio_func* hif_sdio_ctx_to_func (
336     MTK_WCN_HIF_SDIO_CLTCTX ctx)
337 {
338     UINT32 probe_index;
339
340     //4 <1> check if ctx is valid, registered, and probed
341     probe_index = CLTCTX_IDX(ctx);
342     if (unlikely(!CLTCTX_IDX_VALID(probe_index)))   /* invalid index in CLTCTX */
343     {
344         HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx);
345         return NULL;
346     }
347     else
348     {
349         if (unlikely(g_hif_sdio_probed_func_list[probe_index].clt_idx < 0))   /* the client has not been registered */
350         {
351             HIF_SDIO_WARN_FUNC("can't find client idx in probed list!ctx(0x%x) prob_idx(%d) clt_idx(%d)\n",
352                 ctx, probe_index, g_hif_sdio_probed_func_list[probe_index].clt_idx);
353             return NULL;
354         }
355     }
356     return g_hif_sdio_probed_func_list[probe_index].func;
357 }
358
359 /*!
360  * \brief MTK hif sdio client registration function
361  *
362  * Client uses this function to register itself to hif_sdio driver
363  *
364  * \param pinfo a pointer of client's information
365  *
366  * \retval 0 register successfully
367  * \retval < 0 list error code here
368  */
369 INT32 mtk_wcn_hif_sdio_client_reg (
370     const MTK_WCN_HIF_SDIO_CLTINFO *pinfo
371     )
372 {
373     INT32   ret = -HIF_SDIO_ERR_FAIL;
374     INT32   clt_index = -1;
375     UINT32  i   = 0;
376     UINT32  j   = 0;
377     MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO *clt_probe_worker_info = 0;
378
379     HIF_SDIO_INFO_FUNC("start!\n");
380
381     //4 <1> check input pointer is valid
382     HIF_SDIO_ASSERT( pinfo );
383
384     //4 <2> check if input parameters are all supported and valid
385     for ( i=0; i<pinfo->func_tbl_size; i++ )
386     {
387         ret = hif_sdio_check_supported_sdio_id( pinfo->func_tbl[i].manf_id, pinfo->func_tbl[i].card_id );
388         if(ret)
389         {
390             HIF_SDIO_WARN_FUNC("vendor id(0x%x) and device id(0x%x) of sdio_func are not supported in mtk_sdio_id_tbl!\n",
391                 pinfo->func_tbl[i].manf_id,
392                 pinfo->func_tbl[i].card_id);
393             goto out;
394         }
395     }
396     HIF_SDIO_DBG_FUNC("hif_sdio_check_supported_sdio_id() done!\n");
397
398     //4 <3> check if the specific {manf id, card id, function number} tuple is
399     //4 already resigstered
400     for ( i=0; i<pinfo->func_tbl_size; i++ )
401     {
402         ret = hif_sdio_check_duplicate_sdio_id( pinfo->func_tbl[i].manf_id, pinfo->func_tbl[i].card_id, pinfo->func_tbl[i].func_num );
403         if(ret)
404         {
405             HIF_SDIO_WARN_FUNC("vendor id(0x%x), device id(0x%x), and fun_num(%d) of sdio_func are duplicated in g_hif_sdio_clt_drv_list!\n",
406                 pinfo->func_tbl[i].manf_id,
407                 pinfo->func_tbl[i].card_id,
408                 pinfo->func_tbl[i].func_num );
409             goto out;
410         }
411     }
412     HIF_SDIO_DBG_FUNC("hif_sdio_check_duplicate_sdio_id() done!\n");
413
414     //4 <4> add the specified {manf id, card id, function number} tuple to registered client list
415     HIF_SDIO_DBG_FUNC("pinfo->func_tbl_size:%d\n", pinfo->func_tbl_size);
416     for ( i=0; i<pinfo->func_tbl_size; i++ )
417     {
418         ret = hif_sdio_add_clt_list( &clt_index, pinfo, i );
419         if(ret)
420         {
421             HIF_SDIO_WARN_FUNC("client's info are added in registed client list failed (buffer is full)!\n");
422             goto out;
423         }
424         HIF_SDIO_DBG_FUNC("hif_sdio_add_clt_list() done (gRefCount=%d)!\n", gRefCount);
425
426     //4 <5> if the specific {manf id, card id, function number} tuple has already
427     //4 been probed by mmc, schedule another task to call client's .hif_clt_probe()
428         for ( j=0; j<CFG_CLIENT_COUNT; j++ )
429         {
430             // probed spin lock
431             spin_lock_bh( &g_hif_sdio_lock_info.probed_list_lock );
432             if ( g_hif_sdio_probed_func_list[j].func == 0 )
433             {
434                 // probed spin unlock
435                 spin_unlock_bh( &g_hif_sdio_lock_info.probed_list_lock );
436                 continue;
437             }
438             /* the function has been probed */
439             if ( (g_hif_sdio_clt_drv_list[clt_index].func_info->manf_id == g_hif_sdio_probed_func_list[j].func->vendor) &&\
440                  (g_hif_sdio_clt_drv_list[clt_index].func_info->card_id == g_hif_sdio_probed_func_list[j].func->device) &&\
441                  (g_hif_sdio_clt_drv_list[clt_index].func_info->func_num == g_hif_sdio_probed_func_list[j].func->num) )
442             {
443                 g_hif_sdio_probed_func_list[j].clt_idx = clt_index;
444                 // probed spin unlock
445                 spin_unlock_bh( &g_hif_sdio_lock_info.probed_list_lock );
446
447                 /* use worker thread to perform the client's .hif_clt_probe() */
448                 clt_probe_worker_info = vmalloc( sizeof(MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO) );
449                 INIT_WORK( &clt_probe_worker_info->probe_work, hif_sdio_clt_probe_worker );
450                 clt_probe_worker_info->registinfo_p = &g_hif_sdio_clt_drv_list[clt_index];
451                 clt_probe_worker_info->probe_idx = j;
452                 schedule_work( &clt_probe_worker_info->probe_work );
453
454         //4 <5.1> remember to do claim_irq for the func if it's irq had been released.
455                 if ( !(g_hif_sdio_probed_func_list[j].func->irq_handler) )
456                 {
457                     sdio_claim_host(g_hif_sdio_probed_func_list[j].func);
458                     ret = sdio_claim_irq(g_hif_sdio_probed_func_list[j].func, hif_sdio_irq);
459                     mtk_wcn_sdio_irq_flag_set (1);
460                     sdio_release_host(g_hif_sdio_probed_func_list[j].func);
461                     HIF_SDIO_INFO_FUNC("sdio_claim_irq for func(0x%p) j(%d) v(0x%x) d(0x%x) ok\n",
462                         g_hif_sdio_probed_func_list[j].func, j,
463                         g_hif_sdio_probed_func_list[j].func->vendor,
464                         g_hif_sdio_probed_func_list[j].func->device
465                         );
466                 }
467         //4 <5.2> Reset the block size of the function provided by client
468                 HIF_SDIO_INFO_FUNC("Reset sdio block size: %d!\n", g_hif_sdio_clt_drv_list[clt_index].func_info->blk_sz);
469                 sdio_claim_host(g_hif_sdio_probed_func_list[j].func);
470                 ret = sdio_set_block_size(g_hif_sdio_probed_func_list[j].func,\
471                                         g_hif_sdio_clt_drv_list[clt_index].func_info->blk_sz);
472                 sdio_release_host(g_hif_sdio_probed_func_list[j].func);
473             }
474             else
475             {
476                 // probed spin unlock
477                 spin_unlock_bh( &g_hif_sdio_lock_info.probed_list_lock );
478             }
479         }
480         HIF_SDIO_DBG_FUNC("map g_hif_sdio_clt_drv_list to g_hif_sdio_probed_func_list done!\n");
481     }
482     ret = HIF_SDIO_ERR_SUCCESS;
483     gRefCount++;
484
485 out:
486     //4 <last> error handling
487
488     HIF_SDIO_DBG_FUNC("end!\n");
489     return ret;
490 } /* end of mtk_wcn_hif_sdio_client_reg() */
491
492 /*!
493  * \brief MTK hif sdio client un-registration function
494  *
495  * Client uses this function to un-register itself
496  *
497  * \param pinfo a pointer of client's information
498  *
499  * \retval 0    register successfully
500  * \retval < 0  list error code here
501  */
502 INT32 mtk_wcn_hif_sdio_client_unreg (
503     const MTK_WCN_HIF_SDIO_CLTINFO *pinfo
504     )
505 {
506     INT32  ret = -HIF_SDIO_ERR_FAIL;
507     INT32  clt_list_index = 0;
508     UINT32 i = 0;
509     UINT32 j = 0;
510
511     HIF_SDIO_INFO_FUNC("start!\n");
512
513     //4 <1> check if input pointer is valid
514     HIF_SDIO_ASSERT( pinfo );
515
516     //4 <2> check if input parameters are all supported and valid
517     for ( i=0; i<pinfo->func_tbl_size; i++ )
518     {
519         ret = hif_sdio_check_supported_sdio_id( pinfo->func_tbl[i].manf_id, pinfo->func_tbl[i].card_id );
520         if(ret)
521         {
522             HIF_SDIO_WARN_FUNC("vendor id(0x%x) and device id(0x%x) of sdio_func are not supported in mtk_sdio_id_tbl!\n",
523                 pinfo->func_tbl[i].manf_id,
524                 pinfo->func_tbl[i].card_id);
525             goto out;
526         }
527     }
528
529     //4 <3> check if the specific {manf id, card id, function number} tuple is already resigstered
530     //4 and find the corresponding client ctx and call client's .hif_clt_remove() in THIS context
531     for ( i=0; i<pinfo->func_tbl_size; i++ )
532     {
533         clt_list_index = hif_sdio_find_clt_list_index(pinfo->func_tbl[i].manf_id, pinfo->func_tbl[i].card_id, pinfo->func_tbl[i].func_num);
534         if ( clt_list_index < 0 )
535         {
536             HIF_SDIO_WARN_FUNC("vendor id(0x%x), device id(0x%x), and fun_num(%d) client info is not in the client's registed list!\n",
537                 pinfo->func_tbl[i].manf_id,
538                 pinfo->func_tbl[i].card_id,
539                 pinfo->func_tbl[i].func_num );
540             ret = -HIF_SDIO_ERR_FAIL;
541             goto out;
542         }
543
544     //4 <4> mark the specified {manf id, card id, function number} tuple as
545     //4 un-registered and invalidate client's context
546         hif_sdio_init_clt_list( clt_list_index );
547
548         /* un-map g_hif_sdio_clt_drv_list index in g_hif_sdio_probed_func_list */
549         for ( j=0; j<CFG_CLIENT_COUNT; j++ )
550         {
551             if ( g_hif_sdio_probed_func_list[j].clt_idx == clt_list_index )
552             {
553                 g_hif_sdio_probed_func_list[j].clt_idx = -1;
554             }
555         }
556     }
557     gRefCount--;
558
559     ret = HIF_SDIO_ERR_SUCCESS;
560 out:
561     HIF_SDIO_INFO_FUNC("end (gRefCount=%d) !\n", gRefCount);
562     return ret;
563 }/* end of mtk_wcn_hif_sdio_client_unreg() */
564
565 /*!
566  * \brief
567  *
568  * detailed descriptions
569  *
570  * \param ctx client's context variable
571  *
572  * \retval 0    register successfully
573  * \retval < 0  list error code here
574  */
575 INT32 mtk_wcn_hif_sdio_readb (
576     MTK_WCN_HIF_SDIO_CLTCTX ctx,
577     UINT32 offset,
578     PUINT8 pvb
579     )
580 {
581 #if HIF_SDIO_UPDATE
582     INT32 ret;
583     struct sdio_func* func;
584 #else
585     INT32 ret = -HIF_SDIO_ERR_FAIL;
586     int probe_index = -1;
587     struct sdio_func* func = 0;
588 #endif
589
590     HIF_SDIO_DBG_FUNC("start!\n");
591     HIF_SDIO_ASSERT( pvb );
592
593     //4 <1> check if ctx is valid, registered, and probed
594 #if HIF_SDIO_UPDATE
595     ret = -HIF_SDIO_ERR_FAIL;
596     func = hif_sdio_ctx_to_func(ctx);
597     if (!func) {
598         ret = -HIF_SDIO_ERR_FAIL;
599         goto out;
600     }
601 #else
602     probe_index = CLTCTX_IDX(ctx);
603     if( probe_index < 0 )   /* the function has not been probed */
604     {
605         HIF_SDIO_WARN_FUNC("can't find client in probed list!\n");
606         ret = -HIF_SDIO_ERR_FAIL;
607         goto out;
608     }
609     else
610     {
611         if ( g_hif_sdio_probed_func_list[probe_index].clt_idx < 0 )   /* the client has not been registered */
612         {
613             HIF_SDIO_WARN_FUNC("can't find client in registered list!\n");
614             ret = -HIF_SDIO_ERR_FAIL;
615             goto out;
616         }
617     }
618     func = g_hif_sdio_probed_func_list[probe_index].func;
619 #endif
620
621     //4 <2>
622     sdio_claim_host(func);
623     *pvb = sdio_readb(func, offset, &ret);
624     sdio_release_host(func);
625
626     //4 <3> check result code and return proper error code
627
628 out:
629     HIF_SDIO_DBG_FUNC("end!\n");
630     return ret;
631 } /* end of mtk_wcn_hif_sdio_client_unreg() */
632
633 /*!
634  * \brief
635  *
636  * detailed descriptions
637  *
638  * \param ctx client's context variable
639  *
640  * \retval 0    register successfully
641  * \retval < 0  list error code here
642  */
643 INT32 mtk_wcn_hif_sdio_writeb (
644     MTK_WCN_HIF_SDIO_CLTCTX ctx,
645     UINT32 offset,
646     UINT8 vb
647     )
648 {
649 #if HIF_SDIO_UPDATE
650     INT32 ret;
651     struct sdio_func* func;
652 #else
653     INT32 ret = -HIF_SDIO_ERR_FAIL;
654     int probe_index = -1;
655     struct sdio_func* func = 0;
656 #endif
657
658     HIF_SDIO_DBG_FUNC("start!\n");
659
660     //4 <1> check if ctx is valid, registered, and probed
661 #if HIF_SDIO_UPDATE
662     ret = -HIF_SDIO_ERR_FAIL;
663     func = hif_sdio_ctx_to_func(ctx);
664     if (!func) {
665         ret = -HIF_SDIO_ERR_FAIL;
666         goto out;
667     }
668 #else
669     probe_index = CLTCTX_IDX(ctx);
670     if( probe_index < 0 )   /* the function has not been probed */
671     {
672         HIF_SDIO_WARN_FUNC("can't find client in probed list!\n");
673         ret = -HIF_SDIO_ERR_FAIL;
674         goto out;
675     }
676     else
677     {
678         if ( g_hif_sdio_probed_func_list[probe_index].clt_idx < 0 )   /* the client has not been registered */
679         {
680             HIF_SDIO_WARN_FUNC("can't find client in registered list!\n");
681             ret = -HIF_SDIO_ERR_FAIL;
682             goto out;
683         }
684     }
685     func = g_hif_sdio_probed_func_list[probe_index].func;
686 #endif
687
688     //4 <1.1> check if input parameters are valid
689
690     //4 <2>
691     wmt_tra_sdio_update();
692     sdio_claim_host(func);
693     sdio_writeb(func, vb, offset, &ret);
694     sdio_release_host(func);
695
696     //4 <3> check result code and return proper error code
697
698 out:
699     HIF_SDIO_DBG_FUNC("end!\n");
700     return ret;
701 } /* end of mtk_wcn_hif_sdio_client_unreg() */
702
703 /*!
704  * \brief
705  *
706  * detailed descriptions
707  *
708  * \param ctx client's context variable
709  *
710  * \retval 0    register successfully
711  * \retval < 0  list error code here
712  */
713 INT32 mtk_wcn_hif_sdio_readl (
714     MTK_WCN_HIF_SDIO_CLTCTX ctx,
715     UINT32 offset,
716     PUINT32 pvl
717     )
718 {
719 #if HIF_SDIO_UPDATE
720     INT32 ret;
721     struct sdio_func* func;
722 #else
723     INT32 ret = -HIF_SDIO_ERR_FAIL;
724     int probe_index = -1;
725     struct sdio_func* func = 0;
726 #endif
727
728     HIF_SDIO_DBG_FUNC("start!\n");
729     HIF_SDIO_ASSERT( pvl );
730
731     //4 <1> check if ctx is valid, registered, and probed
732 #if HIF_SDIO_UPDATE
733     ret = -HIF_SDIO_ERR_FAIL;
734     func = hif_sdio_ctx_to_func(ctx);
735     if (!func) {
736         ret = -HIF_SDIO_ERR_FAIL;
737         goto out;
738     }
739 #else
740     probe_index = CLTCTX_IDX(ctx);
741     if( probe_index < 0 )   /* the function has not been probed */
742     {
743         HIF_SDIO_WARN_FUNC("can't find client in probed list!\n");
744         ret = -HIF_SDIO_ERR_FAIL;
745         goto out;
746     }
747     else
748     {
749         if ( g_hif_sdio_probed_func_list[probe_index].clt_idx < 0 )   /* the client has not been registered */
750         {
751             HIF_SDIO_WARN_FUNC("can't find client in registered list!\n");
752             ret = -HIF_SDIO_ERR_FAIL;
753             goto out;
754         }
755     }
756     func = g_hif_sdio_probed_func_list[probe_index].func;
757 #endif
758     //4 <1.1> check if input parameters are valid
759
760     //4 <2>
761     sdio_claim_host(func);
762     *pvl = sdio_readl(func, offset, &ret);
763     sdio_release_host(func);
764
765     //4 <3> check result code and return proper error code
766
767 out:
768     HIF_SDIO_DBG_FUNC("end!\n");
769     return ret;
770 } /* end of mtk_wcn_hif_sdio_client_unreg() */
771
772 /*!
773  * \brief
774  *
775  * detailed descriptions
776  *
777  * \param ctx client's context variable
778  *
779  * \retval 0    register successfully
780  * \retval < 0  list error code here
781  */
782 INT32 mtk_wcn_hif_sdio_writel (
783     MTK_WCN_HIF_SDIO_CLTCTX ctx,
784     UINT32 offset,
785     UINT32 vl
786     )
787 {
788 #if HIF_SDIO_UPDATE
789     INT32 ret;
790     struct sdio_func* func;
791 #else
792     INT32 ret = -HIF_SDIO_ERR_FAIL;
793     int probe_index = -1;
794     struct sdio_func* func = 0;
795 #endif
796
797     HIF_SDIO_DBG_FUNC("start!\n");
798
799     //4 <1> check if ctx is valid, registered, and probed
800 #if HIF_SDIO_UPDATE
801     ret = -HIF_SDIO_ERR_FAIL;
802     func = hif_sdio_ctx_to_func(ctx);
803     if (!func) {
804         ret = -HIF_SDIO_ERR_FAIL;
805         goto out;
806     }
807 #else
808     probe_index = CLTCTX_IDX(ctx);
809     if( probe_index < 0 )   /* the function has not been probed */
810     {
811         HIF_SDIO_WARN_FUNC("can't find client in probed list!\n");
812         ret = -HIF_SDIO_ERR_FAIL;
813         goto out;
814     }
815     else
816     {
817         if ( g_hif_sdio_probed_func_list[probe_index].clt_idx < 0 )   /* the client has not been registered */
818         {
819             HIF_SDIO_WARN_FUNC("can't find client in registered list!\n");
820             ret = -HIF_SDIO_ERR_FAIL;
821             goto out;
822         }
823     }
824     func = g_hif_sdio_probed_func_list[probe_index].func;
825 #endif
826     //4 <1.1> check if input parameters are valid
827
828     //4 <2>
829     wmt_tra_sdio_update();
830     sdio_claim_host(func);
831     sdio_writel(func, vl, offset, &ret);
832     sdio_release_host(func);
833
834     //4 <3> check result code and return proper error code
835
836 out:
837     HIF_SDIO_DBG_FUNC("end!\n");
838     return ret;
839 } /* end of mtk_wcn_hif_sdio_client_unreg() */
840
841 /*!
842  * \brief
843  *
844  * detailed descriptions
845  *
846  * \param ctx client's context variable
847  *
848  * \retval 0    register successfully
849  * \retval < 0  list error code here
850  */
851 INT32 mtk_wcn_hif_sdio_read_buf (
852     MTK_WCN_HIF_SDIO_CLTCTX ctx,
853     UINT32 offset,
854     PUINT32 pbuf,
855     UINT32 len
856     )
857 {
858 #if HIF_SDIO_UPDATE
859     INT32 ret;
860     struct sdio_func* func;
861 #else
862     INT32 ret = -HIF_SDIO_ERR_FAIL;
863     int probe_index = -1;
864     struct sdio_func* func = 0;
865 #endif
866
867     HIF_SDIO_DBG_FUNC("start!\n");
868     HIF_SDIO_ASSERT( pbuf );
869
870     //4 <1> check if ctx is valid, registered, and probed
871 #if HIF_SDIO_UPDATE
872     ret = -HIF_SDIO_ERR_FAIL;
873     func = hif_sdio_ctx_to_func(ctx);
874     if (!func) {
875         ret = -HIF_SDIO_ERR_FAIL;
876         goto out;
877     }
878 #else
879     probe_index = CLTCTX_IDX(ctx);
880     if( probe_index < 0 )   /* the function has not been probed */
881     {
882         HIF_SDIO_WARN_FUNC("can't find client in probed list!\n");
883         ret = -HIF_SDIO_ERR_FAIL;
884         goto out;
885     }
886     else
887     {
888         if ( g_hif_sdio_probed_func_list[probe_index].clt_idx < 0 )   /* the client has not been registered */
889         {
890             HIF_SDIO_WARN_FUNC("can't find client in registered list!\n");
891             ret = -HIF_SDIO_ERR_FAIL;
892             goto out;
893         }
894     }
895     func = g_hif_sdio_probed_func_list[probe_index].func;
896 #endif
897     //4 <1.1> check if input parameters are valid
898
899     //4 <2>
900     sdio_claim_host(func);
901     ret = sdio_readsb(func, pbuf, offset, len);
902     sdio_release_host(func);
903
904     //4 <3> check result code and return proper error code
905
906 out:
907     HIF_SDIO_DBG_FUNC("end!\n");
908     return ret;
909 } /* end of mtk_wcn_hif_sdio_read_buf() */
910
911
912 /*!
913  * \brief
914  *
915  * detailed descriptions
916  *
917  * \param ctx client's context variable
918  *
919  * \retval 0    register successfully
920  * \retval < 0  list error code here
921  */
922 INT32 mtk_wcn_hif_sdio_write_buf (
923     MTK_WCN_HIF_SDIO_CLTCTX ctx,
924     UINT32 offset,
925     PUINT32 pbuf,
926     UINT32 len
927     )
928 {
929 #if HIF_SDIO_UPDATE
930     INT32 ret;
931     struct sdio_func* func;
932 #else
933     INT32 ret = -HIF_SDIO_ERR_FAIL;
934     int probe_index = -1;
935     struct sdio_func* func = 0;
936 #endif
937
938     HIF_SDIO_DBG_FUNC("start!\n");
939     HIF_SDIO_ASSERT( pbuf );
940
941     //4 <1> check if ctx is valid, registered, and probed
942 #if HIF_SDIO_UPDATE
943     ret = -HIF_SDIO_ERR_FAIL;
944     func = hif_sdio_ctx_to_func(ctx);
945     if (!func) {
946         ret = -HIF_SDIO_ERR_FAIL;
947         goto out;
948     }
949 #else
950     probe_index = CLTCTX_IDX(ctx);
951     if( probe_index < 0 )   /* the function has not been probed */
952     {
953         HIF_SDIO_WARN_FUNC("can't find client in probed list!\n");
954         ret = -HIF_SDIO_ERR_FAIL;
955         goto out;
956     }
957     else
958     {
959         if ( g_hif_sdio_probed_func_list[probe_index].clt_idx < 0 )   /* the client has not been registered */
960         {
961             HIF_SDIO_WARN_FUNC("can't find client in registered list!\n");
962             ret = -HIF_SDIO_ERR_FAIL;
963             goto out;
964         }
965     }
966     func = g_hif_sdio_probed_func_list[probe_index].func;
967 #endif
968     //4 <1.1> check if input parameters are valid
969
970     //4 <2>
971     wmt_tra_sdio_update();
972     sdio_claim_host(func);
973     ret = sdio_writesb(func, offset, pbuf, len);
974     sdio_release_host(func);
975
976     //4 <3> check result code and return proper error code
977
978 out:
979     HIF_SDIO_DBG_FUNC("ret(%d) end!\n", ret);
980
981     return ret;
982 } /* end of mtk_wcn_hif_sdio_write_buf() */
983
984 /*!
985  * \brief store client driver's private data function.
986  *
987  *
988  * \param clent's MTK_WCN_HIF_SDIO_CLTCTX.
989  *
990  * \retval none.
991  */
992 void mtk_wcn_hif_sdio_set_drvdata(
993     MTK_WCN_HIF_SDIO_CLTCTX ctx,
994     void* private_data_p
995     )
996 {
997     UINT8 probed_idx = CLTCTX_IDX(ctx);
998
999     if (unlikely(!CLTCTX_IDX_VALID(probed_idx))) {   /* invalid index in CLTCTX */
1000         HIF_SDIO_WARN_FUNC("invalid idx in ctx(0x%x), private_data_p not stored!\n", ctx);
1001     }
1002     else {
1003         /* store client driver's private data to dev driver */
1004         g_hif_sdio_probed_func_list[probed_idx].private_data_p = private_data_p;
1005         HIF_SDIO_DBG_FUNC("private_data_p(0x%p) for ctx(0x%x) probed idx(%d) stored!\n",
1006             private_data_p, ctx, probed_idx);
1007     }
1008 }
1009
1010 /*!
1011  * \brief get client driver's private data function.
1012  *
1013  *
1014  * \param clent's MTK_WCN_HIF_SDIO_CLTCTX.
1015  *
1016  * \retval private data pointer.
1017  */
1018 void* mtk_wcn_hif_sdio_get_drvdata(
1019     MTK_WCN_HIF_SDIO_CLTCTX ctx
1020     )
1021 {
1022     UINT8 probed_idx = CLTCTX_IDX(ctx);
1023
1024     /* get client driver's private data to dev driver */
1025     if (likely(CLTCTX_IDX_VALID(probed_idx)))
1026     {
1027         return g_hif_sdio_probed_func_list[probed_idx].private_data_p;
1028     }
1029     else
1030     {
1031         /* invalid index in CLTCTX */
1032         HIF_SDIO_WARN_FUNC("invalid idx in ctx(0x%x), return null!\n", ctx);
1033         return NULL;
1034     }
1035 }
1036
1037 /*!
1038  * \brief control stp/wifi on/off from wmt.
1039  *
1040  *
1041  * \param (1)control function type, (2)on/off control.
1042  *
1043  * \retval (1)control results ,(2)unknow type: -5.
1044  * \retval 0:success, -11:not probed, -12:already on, -13:not registered, other errors.
1045  */
1046 INT32
1047 mtk_wcn_hif_sdio_wmt_control (
1048     WMT_SDIO_FUNC_TYPE func_type,
1049     MTK_WCN_BOOL is_on
1050     )
1051 {
1052     // TODO:[FixMe][George]: return value of this function shall distinguish
1053     // 1) not probed by mmc_core yet or
1054     // 2) probed by mmc_core but init fail...
1055     switch (func_type) {
1056     case WMT_SDIO_FUNC_STP:
1057         if (is_on == MTK_WCN_BOOL_TRUE) {
1058             return hif_sdio_stp_on();
1059         }
1060         else {
1061             return hif_sdio_stp_off();
1062         }
1063         break;
1064
1065     case WMT_SDIO_FUNC_WIFI:
1066         if (is_on == MTK_WCN_BOOL_TRUE) {
1067             return hif_sdio_wifi_on();
1068         }
1069         else {
1070             return hif_sdio_wifi_off();
1071         }
1072         break;
1073
1074     default:
1075         HIF_SDIO_WARN_FUNC("unknown type(%d)\n", func_type);
1076         return HIF_SDIO_ERR_INVALID_PARAM;
1077     }
1078 }
1079
1080 /*!
1081  * \brief ???
1082  *
1083  * \detail ???
1084  *
1085  * \param ctx a context provided by client driver
1086  * \param struct device ** ???
1087  *
1088  * \retval none
1089  */
1090 void mtk_wcn_hif_sdio_get_dev(
1091     MTK_WCN_HIF_SDIO_CLTCTX ctx,
1092     struct device **dev
1093     )
1094 {
1095 #if HIF_SDIO_UPDATE
1096     struct sdio_func* func;
1097 #else
1098     UINT8 probe_index = CLTCTX_IDX(ctx);
1099 #endif
1100
1101 #if HIF_SDIO_UPDATE
1102     *dev = NULL; //ensure we does not return any invalid value back.
1103     func = hif_sdio_ctx_to_func(ctx);
1104     if (unlikely(!func)) {
1105         HIF_SDIO_WARN_FUNC("no valid *func with ctx(0x%x)\n", ctx);
1106         return;
1107     }
1108     else {
1109         *dev = &(func->dev);
1110         HIF_SDIO_DBG_FUNC("return *dev(0x%p) for ctx(0x%x)\n", *dev, ctx);
1111     }
1112 #else
1113     if (probe_index < 0) {
1114         HIF_SDIO_WARN_FUNC("func not probed, probe_index = %d", probe_index);
1115         return;
1116     }
1117     else{
1118         *dev = &g_hif_sdio_probed_func_list[probe_index].func->dev;
1119     }
1120 #endif
1121 }
1122
1123 /*!
1124  * \brief client's probe() function.
1125  *
1126  *
1127  * \param work queue structure.
1128  *
1129  * \retval none.
1130  */
1131 static int hif_sdio_clt_probe_func (
1132     MTK_WCN_HIF_SDIO_REGISTINFO *registinfo_p,
1133     INT8 probe_idx
1134     )
1135 {
1136     UINT16 card_id = 0;
1137     UINT16 func_num = 0;
1138     UINT16 blk_sz = 0;
1139     int ret;
1140
1141     HIF_SDIO_DBG_FUNC("start!\n");
1142     HIF_SDIO_ASSERT( registinfo_p );
1143     if (!registinfo_p) {
1144         HIF_SDIO_WARN_FUNC("registinfo_p NULL!!!\n");
1145         return -1;
1146     }
1147
1148     /* special case handling: if the clt's unregister is called during probe procedures */
1149     if ( !registinfo_p->func_info || !registinfo_p->sdio_cltinfo) {
1150         HIF_SDIO_WARN_FUNC("client's registinfo_p is cleared !!!\n");
1151         return -1;
1152     }
1153
1154     card_id = registinfo_p->func_info->card_id;
1155     func_num = registinfo_p->func_info->func_num;
1156     blk_sz = registinfo_p->func_info->blk_sz;
1157     ret = registinfo_p->sdio_cltinfo->hif_clt_probe( CLTCTX(card_id, func_num, blk_sz, probe_idx),\
1158                                                             registinfo_p->func_info );
1159
1160     HIF_SDIO_INFO_FUNC("clt_probe_func card_id(%x) func_num(%x) blk_sz(%d) prob_idx(%x) ret(%d) %s\n",
1161         card_id, func_num, blk_sz, probe_idx, ret, (ret) ? "fail" : "ok");
1162
1163     return ret;
1164 }
1165
1166 /*!
1167  * \brief client's probe() worker.
1168  *
1169  *
1170  * \param work queue structure.
1171  *
1172  * \retval none.
1173  */
1174 static void hif_sdio_clt_probe_worker(
1175     struct work_struct *work
1176     )
1177 {
1178     MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO *clt_worker_info_p = 0;
1179     UINT16 card_id = 0;
1180     UINT16 func_num = 0;
1181     UINT16 blk_sz = 0;
1182     INT8   prob_idx = 0;
1183
1184     HIF_SDIO_DBG_FUNC("start!\n");
1185
1186     HIF_SDIO_ASSERT( work );
1187
1188     /* get client's information */
1189     clt_worker_info_p = container_of( work, MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO, probe_work );
1190     HIF_SDIO_ASSERT( clt_worker_info_p );
1191     HIF_SDIO_ASSERT( clt_worker_info_p->registinfo_p );
1192
1193     /* special case handling: if the clt's unregister is called during probe procedures */
1194     if ( (clt_worker_info_p->registinfo_p->func_info == 0) || (clt_worker_info_p->registinfo_p->sdio_cltinfo==0) )
1195     {
1196         HIF_SDIO_WARN_FUNC("client's registinfo_p is cleared !!!\n");
1197         vfree( clt_worker_info_p );
1198         return;
1199     }
1200
1201     card_id = clt_worker_info_p->registinfo_p->func_info->card_id;
1202     func_num = clt_worker_info_p->registinfo_p->func_info->func_num;
1203     blk_sz = clt_worker_info_p->registinfo_p->func_info->blk_sz;
1204     prob_idx = clt_worker_info_p->probe_idx;
1205
1206     /* Execute client's probe() func */
1207     clt_worker_info_p->registinfo_p->sdio_cltinfo->hif_clt_probe( CLTCTX(card_id, func_num, blk_sz, prob_idx),\
1208                                                         clt_worker_info_p->registinfo_p->func_info );
1209
1210     vfree( clt_worker_info_p );
1211
1212     HIF_SDIO_DBG_FUNC("card_id(0x%x) func_num(0x%x) blk_sz(0x%x) prob_idx(0x%x)\n", card_id, func_num, blk_sz, prob_idx);
1213     HIF_SDIO_DBG_FUNC("end!\n");
1214 }
1215
1216 /*!
1217  * \brief client's probe() worker.
1218  *
1219  *
1220  * \param work queue structure.
1221  *
1222  * \retval none.
1223  */
1224 static void
1225 hif_sdio_dump_probe_list (void)
1226 {
1227     int i;
1228
1229     HIF_SDIO_DBG_FUNC("== DUMP probed list start ==\n");
1230
1231     for (i = 0; i < CFG_CLIENT_COUNT; i++) {
1232         if (g_hif_sdio_probed_func_list[i].func) {
1233             HIF_SDIO_DBG_FUNC("index(%d) func(0x%p) clt_idx(%d)\n",
1234                 i, g_hif_sdio_probed_func_list[i].func,
1235                 g_hif_sdio_probed_func_list[i].clt_idx);
1236
1237             HIF_SDIO_DBG_FUNC("vendor(0x%x) device(0x%x) num(0x%x) state(%d)\n",
1238                 g_hif_sdio_probed_func_list[i].func->vendor,
1239                 g_hif_sdio_probed_func_list[i].func->device,
1240                 g_hif_sdio_probed_func_list[i].func->num,
1241                 g_hif_sdio_probed_func_list[i].on_by_wmt);
1242
1243         }
1244     }
1245
1246     HIF_SDIO_DBG_FUNC("== DUMP probed list end ==\n");
1247 }
1248
1249
1250 /*!
1251  * \brief Initialize g_hif_sdio_probed_func_list
1252  *
1253  *
1254  * \param index of g_hif_sdio_probed_func_list.
1255  *
1256  * \retval none.
1257  */
1258 static void hif_sdio_init_probed_list(
1259     INT32 index
1260     )
1261 {
1262     if ( (index >= 0) && (index < CFG_CLIENT_COUNT) )
1263     {
1264         /* probed spin lock */
1265         spin_lock_bh( &g_hif_sdio_lock_info.probed_list_lock );
1266         g_hif_sdio_probed_func_list[index].func = 0;
1267         g_hif_sdio_probed_func_list[index].clt_idx = -1;
1268         g_hif_sdio_probed_func_list[index].private_data_p = 0;
1269         g_hif_sdio_probed_func_list[index].on_by_wmt = MTK_WCN_BOOL_FALSE;
1270         /* probed spin unlock */
1271         spin_unlock_bh( &g_hif_sdio_lock_info.probed_list_lock );
1272     }
1273     else
1274     {
1275         HIF_SDIO_ERR_FUNC("index is out of g_hif_sdio_probed_func_list[] boundary!\n");
1276     }
1277 }
1278
1279
1280 /*!
1281  * \brief Initialize g_hif_sdio_clt_drv_list
1282  *
1283  *
1284  * \param index of g_hif_sdio_clt_drv_list.
1285  *
1286  * \retval none.
1287  */
1288 static void hif_sdio_init_clt_list(
1289     INT32 index
1290     )
1291 {
1292     // client list spin lock
1293     spin_lock_bh( &g_hif_sdio_lock_info.clt_list_lock );
1294     if ( (index >= 0) && (index < CFG_CLIENT_COUNT) )
1295     {
1296         g_hif_sdio_clt_drv_list[index].sdio_cltinfo = 0;
1297         g_hif_sdio_clt_drv_list[index].func_info = 0;
1298     }
1299     else
1300     {
1301         HIF_SDIO_ERR_FUNC("index is out of g_hif_sdio_clt_drv_list[] boundary!\n");
1302     }
1303     // client list spin unlock
1304     spin_unlock_bh( &g_hif_sdio_lock_info.clt_list_lock );
1305 }
1306
1307
1308 /*!
1309  * \brief find matched g_hif_sdio_probed_func_list index from sdio function handler
1310  *
1311  *
1312  * \param sdio function handler
1313  *
1314  * \retval -1    index not found
1315  * \retval >= 0  return found index
1316  */
1317 static int hif_sdio_find_probed_list_index_by_func(
1318     struct sdio_func* func
1319     )
1320 {
1321     int i = 0;
1322
1323     HIF_SDIO_ASSERT( func );
1324
1325     for( i=0; i<CFG_CLIENT_COUNT; i++ )
1326     {
1327         if ( g_hif_sdio_probed_func_list[i].func == func )
1328         {
1329             return i;
1330         }
1331     }
1332
1333     return -1;
1334 }
1335
1336 /*!
1337  * \brief find matched g_hif_sdio_probed_func_list from vendor_id, device_id, and function number
1338  *
1339  *
1340  * \param vendor id, device id, and function number of the sdio card.
1341  *
1342  * \retval -1    index not found
1343  * \retval >= 0  return found index
1344  */
1345 static int hif_sdio_find_probed_list_index_by_id_func(
1346     UINT16 vendor,
1347     UINT16 device,
1348     UINT16 func_num
1349     )
1350 {
1351     int i;
1352     for (i = 0; i < CFG_CLIENT_COUNT; i++) {
1353         if (g_hif_sdio_probed_func_list[i].func) {
1354             HIF_SDIO_DBG_FUNC("probed entry: vendor(0x%x) device(0x%x) num(0x%x)\n",
1355                 g_hif_sdio_probed_func_list[i].func->vendor,
1356                 g_hif_sdio_probed_func_list[i].func->device,
1357                 g_hif_sdio_probed_func_list[i].func->num);
1358         }
1359     }
1360     for (i = 0; i < CFG_CLIENT_COUNT; i++) {
1361         if (!g_hif_sdio_probed_func_list[i].func) {
1362             continue;
1363         }
1364         else if ( (g_hif_sdio_probed_func_list[i].func->vendor == vendor) &&
1365             (g_hif_sdio_probed_func_list[i].func->device == device) &&
1366             (g_hif_sdio_probed_func_list[i].func->num == func_num)  )
1367         {
1368             return i;
1369         }
1370     }
1371
1372     if (i == CFG_CLIENT_COUNT ) {
1373         /*
1374         printk(KERN_INFO DRV_NAME "Cannot find vendor:0x%x, device:0x%x, func_num:0x%x, i=%d\n",
1375             vendor, device, func_num, i);
1376         */
1377         /* client func has not been probed */
1378         return -1;
1379     }
1380     return -1;
1381 }
1382
1383 /*!
1384  * \brief find matched g_hif_sdio_clt_drv_list index
1385  *
1386  * find the matched g_hif_sdio_clt_drv_list index from card_id and function number.
1387  *
1388  * \param vendor id, device id, and function number of the sdio card
1389  *
1390  * \retval -1    index not found
1391  * \retval >= 0  return found index
1392  */
1393 static int hif_sdio_find_clt_list_index (
1394     UINT16 vendor,
1395     UINT16 device,
1396     UINT16 func_num
1397     )
1398 {
1399     int i = 0;
1400
1401     for( i=0; i<CFG_CLIENT_COUNT; i++ )
1402     {
1403         if ( g_hif_sdio_clt_drv_list[i].func_info != 0 )
1404         {
1405             if ( (g_hif_sdio_clt_drv_list[i].func_info->manf_id == vendor ) &&\
1406                 (g_hif_sdio_clt_drv_list[i].func_info->card_id == device ) &&\
1407                 (g_hif_sdio_clt_drv_list[i].func_info->func_num == func_num ) )
1408             {
1409                 return i;
1410             }
1411         }
1412     }
1413
1414     return -1;
1415 }
1416
1417
1418 /*!
1419  * \brief check if the vendor, device ids are supported in mtk_sdio_id_tbl.
1420  *
1421  *
1422  * \param vendor id and device id of the sdio card
1423  *
1424  * \retval (-HIF_SDIO_ERR_FAIL)  vendor, device ids are not suppported
1425  * \retval HIF_SDIO_ERR_SUCCESS  vendor, device ids are suppported
1426  */
1427 static int hif_sdio_check_supported_sdio_id(
1428     UINT16 vendor,
1429     UINT16 device
1430     )
1431 {
1432     int i = 0;
1433
1434     for ( i=0; i<CFG_CLIENT_COUNT; i++ )
1435     {
1436         if ( (mtk_sdio_id_tbl[i].vendor == vendor) && (mtk_sdio_id_tbl[i].device == device) )
1437         {
1438             return HIF_SDIO_ERR_SUCCESS;  /* mtk_sdio_id is supported */
1439         }
1440     }
1441     return (-HIF_SDIO_ERR_FAIL);    /* mtk_sdio_id is not supported */
1442 }
1443
1444
1445 /*!
1446  * \brief check if the vendor, device ids are duplicated in g_hif_sdio_clt_drv_list.
1447  *
1448  *
1449  * \param vendor id, device id, and function number of the sdio card
1450  *
1451  * \retval (-HIF_SDIO_ERR_DUPLICATED)  vendor, device, func_num are duplicated
1452  * \retval HIF_SDIO_ERR_SUCCESS        vendor, device, func_num are not duplicated
1453  */
1454 static int hif_sdio_check_duplicate_sdio_id(
1455     UINT16 vendor,
1456     UINT16 device,
1457     UINT16 func_num
1458     )
1459 {
1460     int i = 0;
1461
1462     for ( i=0; i<CFG_CLIENT_COUNT; i++ )
1463     {
1464         if( g_hif_sdio_clt_drv_list[i].func_info != 0 )
1465         {
1466             if ( ( g_hif_sdio_clt_drv_list[i].func_info->manf_id == vendor ) &&\
1467                 ( g_hif_sdio_clt_drv_list[i].func_info->card_id == device ) &&\
1468                 ( g_hif_sdio_clt_drv_list[i].func_info->func_num == func_num ) )
1469             {
1470                 return (-HIF_SDIO_ERR_DUPLICATED);  /* duplicated */
1471             }
1472         }
1473     }
1474     return HIF_SDIO_ERR_SUCCESS;    /* Not duplicated */
1475 }
1476
1477
1478 /*!
1479  * \brief Add the client info into g_hif_sdio_clt_drv_list.
1480  *
1481  *
1482  * \param [output] client's index pointer.
1483  * \param MTK_WCN_HIF_SDIO_CLTINFO of client's contex.
1484  *
1485  * \retval (-HIF_SDIO_ERR_FAIL)  Add to clt_list successfully
1486  * \retval HIF_SDIO_ERR_SUCCESS  Add to clt_list failed (buffer is full)
1487  */
1488 static int hif_sdio_add_clt_list(
1489     INT32*  clt_index_p,
1490     const MTK_WCN_HIF_SDIO_CLTINFO *pinfo,
1491     UINT32 tbl_index
1492     )
1493 {
1494     int i = 0;
1495
1496     HIF_SDIO_ASSERT( clt_index_p );
1497     HIF_SDIO_ASSERT( pinfo );
1498
1499     for( i=0; i<CFG_CLIENT_COUNT; i++ )
1500     {
1501         // client list spin lock
1502         spin_lock_bh( &g_hif_sdio_lock_info.clt_list_lock );
1503         if( g_hif_sdio_clt_drv_list[i].func_info == 0 )
1504         {
1505             g_hif_sdio_clt_drv_list[i].func_info = &(pinfo->func_tbl[tbl_index]);
1506             g_hif_sdio_clt_drv_list[i].sdio_cltinfo = pinfo;
1507             // client list spin unlock
1508             spin_unlock_bh( &g_hif_sdio_lock_info.clt_list_lock );
1509             *clt_index_p = i;
1510             return HIF_SDIO_ERR_SUCCESS;    /* Add to client list successfully */
1511         }
1512         // client list spin unlock
1513         spin_unlock_bh( &g_hif_sdio_lock_info.clt_list_lock );
1514     }
1515     return (-HIF_SDIO_ERR_FAIL);    /* Add to client list failed (buffer is full) */
1516 }
1517
1518 #if HIF_SDIO_SUPPORT_SUSPEND
1519 static int hif_sdio_suspend (struct device *dev)
1520 {
1521     struct sdio_func* func;
1522     mmc_pm_flag_t flag;
1523     int ret;
1524
1525     if (!dev) {
1526         return -EINVAL;
1527     }
1528
1529     func = dev_to_sdio_func(dev);
1530     HIF_SDIO_DBG_FUNC("prepare for func(0x%p)\n", func);
1531
1532     flag = sdio_get_host_pm_caps(func);
1533     if (!(flag & MMC_PM_KEEP_POWER) || !(flag & MMC_PM_WAKE_SDIO_IRQ)) {
1534         HIF_SDIO_WARN_FUNC("neither MMC_PM_KEEP_POWER nor MMC_PM_WAKE_SDIO_IRQ is supported by host, return -ENOTSUPP\n");
1535         return -ENOTSUPP;
1536     }
1537
1538     /* set both */
1539     flag = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
1540     ret = sdio_set_host_pm_flags(func, flag);
1541     if (ret) {
1542         HIF_SDIO_INFO_FUNC("set MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ to host fail(%d)\n", ret);
1543         return -EFAULT;
1544     }
1545     sdio_claim_host(func);
1546     HIF_SDIO_INFO_FUNC("set MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ ok\n");
1547     return 0;
1548 }
1549
1550 static int hif_sdio_resume (struct device *dev)
1551 {
1552     struct sdio_func* func;
1553
1554     if (!dev) {
1555         HIF_SDIO_WARN_FUNC("null dev!\n");
1556         return -EINVAL;
1557     }
1558     func = dev_to_sdio_func(dev);
1559         sdio_release_host(func);
1560     HIF_SDIO_DBG_FUNC("do nothing for func(0x%p)\n", func);
1561
1562     return 0;
1563 }
1564 #endif
1565
1566 /*!
1567  * \brief hif_sdio probe function
1568  *
1569  * hif_sdio probe function called by mmc driver when any matched SDIO function
1570  * is detected by it.
1571  *
1572  * \param func
1573  * \param id
1574  *
1575  * \retval 0    register successfully
1576  * \retval < 0  list error code here
1577  */
1578 static int hif_sdio_probe (
1579     struct sdio_func *func,
1580     const struct sdio_device_id *id
1581     )
1582 {
1583     int ret = 0;
1584     int i = 0;
1585     MTK_WCN_HIF_SDIO_PROBEINFO* hif_sdio_probed_funcp = 0;
1586     INT32 probe_index = -1;
1587 #if 0
1588     INT32 clt_index = -1;
1589     MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO *clt_probe_worker_info = 0;
1590 #endif
1591
1592     HIF_SDIO_INFO_FUNC("start!\n");
1593     HIF_SDIO_ASSERT( func );
1594     hif_sdio_match_chipid_by_dev_id(id);
1595     //4 <0> display debug information
1596     HIF_SDIO_INFO_FUNC("vendor(0x%x) device(0x%x) num(0x%x)\n", func->vendor, func->device, func->num);
1597     for (i = 0;i < func->card->num_info;i++) {
1598         HIF_SDIO_INFO_FUNC("card->info[%d]: %s\n", i, func->card->info[i]);
1599     }
1600
1601     //4 <1> Check if this  is supported by us (mtk_sdio_id_tbl)
1602     ret = hif_sdio_check_supported_sdio_id( func->vendor, func->device );
1603     if (ret) {
1604         HIF_SDIO_WARN_FUNC("vendor id and device id of sdio_func are not supported in mtk_sdio_id_tbl!\n");
1605         goto out;
1606     }
1607
1608     //4 <2> Add this struct sdio_func *func to g_hif_sdio_probed_func_list
1609     for( i=0; i<CFG_CLIENT_COUNT; i++ )
1610     {
1611         /* probed spin lock */
1612         spin_lock_bh( &g_hif_sdio_lock_info.probed_list_lock );
1613         if ( g_hif_sdio_probed_func_list[i].func == 0 )
1614         {
1615             hif_sdio_probed_funcp = &g_hif_sdio_probed_func_list[i];
1616             hif_sdio_probed_funcp->func = func;
1617             hif_sdio_probed_funcp->clt_idx = hif_sdio_find_clt_list_index(func->vendor, func->device, func->num);
1618             hif_sdio_probed_funcp->on_by_wmt = MTK_WCN_BOOL_FALSE;
1619                         hif_sdio_probed_funcp->sdio_irq_enabled = MTK_WCN_BOOL_FALSE;
1620             /* probed spin unlock */
1621             spin_unlock_bh( &g_hif_sdio_lock_info.probed_list_lock );
1622             probe_index = i;
1623             break;
1624         }
1625         else
1626         {
1627             /* probed spin unlock */
1628             spin_unlock_bh( &g_hif_sdio_lock_info.probed_list_lock );
1629         }
1630     }
1631     if ( (probe_index < 0) || (probe_index >= CFG_CLIENT_COUNT) )
1632     {
1633         HIF_SDIO_ERR_FUNC("probe function list if full!\n");
1634         goto out;
1635     }
1636
1637     //4 <3> Initialize this function
1638     if ( g_hif_sdio_probed_func_list[probe_index].clt_idx < 0 )
1639     {
1640         for( i=0; i<CFG_CLIENT_COUNT; i++ )
1641         {
1642             // client list spin lock
1643             spin_lock_bh( &g_hif_sdio_lock_info.clt_list_lock );
1644             if ( g_hif_sdio_clt_drv_list[i].func_info == 0 )
1645             {
1646                 // client list spin unlock
1647                 spin_unlock_bh( &g_hif_sdio_lock_info.clt_list_lock );
1648                 continue;
1649             }
1650             HIF_SDIO_INFO_FUNC("manf_id:%x, card_id:%x, func_num:%d\n", g_hif_sdio_clt_drv_list[i].func_info->manf_id, g_hif_sdio_clt_drv_list[i].func_info->card_id, g_hif_sdio_clt_drv_list[i].func_info->func_num );
1651             if ( (g_hif_sdio_clt_drv_list[i].func_info->manf_id == g_hif_sdio_probed_func_list[probe_index].func->vendor)&&\
1652                  (g_hif_sdio_clt_drv_list[i].func_info->card_id == g_hif_sdio_probed_func_list[probe_index].func->device)&&\
1653                  (g_hif_sdio_clt_drv_list[i].func_info->func_num == g_hif_sdio_probed_func_list[probe_index].func->num) )
1654             {
1655                 g_hif_sdio_probed_func_list[probe_index].clt_idx = i;
1656                 // client list spin unlock
1657                 spin_unlock_bh( &g_hif_sdio_lock_info.clt_list_lock );
1658                 break;
1659             }
1660             else
1661             {
1662                 // client list spin unlock
1663                 spin_unlock_bh( &g_hif_sdio_lock_info.clt_list_lock );
1664             }
1665         }
1666         HIF_SDIO_INFO_FUNC("map to g_hif_sdio_clt_drv_list[] done: %d\n", g_hif_sdio_probed_func_list[probe_index].clt_idx );
1667     }
1668
1669     //4 <3.1> enable this function
1670     sdio_claim_host(func);
1671     ret = sdio_enable_func(func);
1672     sdio_release_host(func);
1673     if (ret) {
1674         HIF_SDIO_ERR_FUNC("sdio_enable_func failed!\n");
1675         goto out;
1676     }
1677
1678     //4 <3.2> set block size according to the table storing function characteristics
1679     if ( hif_sdio_probed_funcp == 0 )
1680     {
1681         HIF_SDIO_ERR_FUNC("hif_sdio_probed_funcp is null!\n");
1682         goto out;
1683     }
1684     if ( hif_sdio_probed_funcp->clt_idx >= 0 )   /* The clt contex has been registed */
1685     {
1686         sdio_claim_host(func);
1687         ret = sdio_set_block_size(func, g_hif_sdio_clt_drv_list[hif_sdio_probed_funcp->clt_idx].func_info->blk_sz);
1688         sdio_release_host(func);
1689     }
1690     else    /* The clt contex has not been registed */
1691     {
1692         sdio_claim_host(func);
1693         ret = sdio_set_block_size(func, HIF_DEFAULT_BLK_SIZE);
1694         sdio_release_host(func);
1695     }
1696     if (ret) {
1697         HIF_SDIO_ERR_FUNC("set sdio block size failed!\n");
1698         goto out;
1699     }
1700
1701     HIF_SDIO_INFO_FUNC("cur_blksize(%d) max(%d), host max blk_size(%d) blk_count(%d)\n",
1702         func->cur_blksize, func->max_blksize,
1703         func->card->host->max_blk_size, func->card->host->max_blk_count
1704         );
1705
1706     // TODO:[ChangeFeature][George]: explain why this block is marked
1707 #if 0
1708     //4 <3.3> claim irq for this function
1709     sdio_claim_host(func);
1710     ret = sdio_claim_irq(func, hif_sdio_irq);
1711     sdio_release_host(func);
1712     printk(KERN_INFO "sdio_claim_irq ret=%d\n", ret);
1713
1714     //4 <3.4> If this struct sdio_func *func is supported by any driver in
1715     //4 g_hif_sdio_clt_drv_list, schedule another task to call client's .hif_clt_probe()
1716     if ( (clt_index = g_hif_sdio_probed_func_list[probe_index].clt_idx) >= 0 )    /* the function has been registered */
1717     {
1718         /* use worker thread to perform the client's .hif_clt_probe() */
1719         clt_probe_worker_info = vmalloc( sizeof(MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO) );
1720         INIT_WORK( &clt_probe_worker_info->probe_work, hif_sdio_clt_probe_worker );
1721         clt_probe_worker_info->registinfo_p = &g_hif_sdio_clt_drv_list[clt_index];
1722         clt_probe_worker_info->probe_idx = probe_index;
1723         schedule_work( &clt_probe_worker_info->probe_work );
1724     }
1725 #endif
1726
1727     hif_sdio_dump_probe_list();
1728
1729 out:
1730     //4 <last> error handling
1731     return ret;
1732 }
1733
1734
1735 /*!
1736  * \brief hif_sdio remove function
1737  *
1738  * hif_sdio probe function called by mmc driver when the probed func should be
1739  * removed.
1740  *
1741  * \param func
1742  *
1743  */
1744 static void hif_sdio_remove (
1745     struct sdio_func *func
1746     )
1747 {
1748     int probed_list_index = 0;
1749 #if 0
1750     int registed_list_index = 0;
1751 #endif
1752
1753     HIF_SDIO_INFO_FUNC("start!\n");
1754     HIF_SDIO_ASSERT( func );
1755
1756     //4 <1> check input parameter is valid and has been probed previously
1757     if (func == NULL) {
1758         HIF_SDIO_ERR_FUNC("func null(%p)\n", func);
1759         return;
1760     }
1761
1762     //4 <2> if this function has been initialized by any client driver,
1763     //4 call client's .hif_clt_remove() call back in THIS context.
1764     probed_list_index = hif_sdio_find_probed_list_index_by_func( func );
1765     if ( probed_list_index < 0 )
1766     {
1767         HIF_SDIO_WARN_FUNC("sdio function pointer is not in g_hif_sdio_probed_func_list!\n");
1768         return;
1769     }
1770 #if 0
1771     registed_list_index = g_hif_sdio_probed_func_list[probed_list_index].clt_idx;
1772     if ( registed_list_index >= 0 )
1773     {
1774         g_hif_sdio_clt_drv_list[registed_list_index].sdio_cltinfo->hif_clt_remove( CLTCTX(func->device, func->num,\
1775                                                                             func->cur_blksize, probed_list_index) );
1776     }
1777 #endif
1778
1779     //4 <3> mark this function as de-initialized and invalidate client's context
1780     hif_sdio_init_probed_list(probed_list_index);
1781
1782 #if 0
1783     //4 <4> release irq for this function
1784     sdio_claim_host(func);
1785     sdio_release_irq(func);
1786     sdio_release_host(func);
1787 #endif
1788
1789     //4 <5> disable this function
1790     sdio_claim_host(func);
1791     sdio_disable_func(func);
1792     sdio_release_host(func);
1793
1794     //4 <6> mark this function as removed
1795
1796     HIF_SDIO_INFO_FUNC("sdio func(0x%p) is removed successfully!\n", func);
1797 }
1798
1799 /*!
1800  * \brief hif_sdio interrupt handler
1801  *
1802  * detailed descriptions
1803  *
1804  * \param ctx client's context variable
1805  *
1806  */
1807 static void hif_sdio_irq (
1808     struct sdio_func *func
1809     )
1810 {
1811     int probed_list_index = -1;
1812     int registed_list_index = -1;
1813
1814     HIF_SDIO_DBG_FUNC("start!\n");
1815
1816     //4 <1> check if func is valid
1817     HIF_SDIO_ASSERT( func );
1818
1819     //4 <2> if func has valid corresponding hif_sdio client's context, mark it
1820     //4 host-locked, use it to call client's .hif_clt_irq() callback function in
1821     //4 THIS context.
1822     probed_list_index = hif_sdio_find_probed_list_index_by_func( func );
1823     if ( (probed_list_index < 0) || (probed_list_index >= CFG_CLIENT_COUNT) )
1824     {
1825         HIF_SDIO_ERR_FUNC("probed_list_index not found!\n");
1826         return;
1827     }
1828     /* [George] added for sdio irq sync and mmc single_irq workaround. It's set
1829      * enabled later by client driver call mtk_wcn_hif_sdio_enable_irq()
1830      */
1831     /* skip smp_rmb() here */
1832     if (MTK_WCN_BOOL_FALSE == g_hif_sdio_probed_func_list[probed_list_index].sdio_irq_enabled) {
1833         HIF_SDIO_WARN_FUNC("func(0x%p),probed_idx(%d) sdio irq not enabled yet\n",
1834             func, probed_list_index);
1835         return;
1836     }
1837
1838     registed_list_index = g_hif_sdio_probed_func_list[probed_list_index].clt_idx;
1839 //    g_hif_sdio_probed_func_list[probed_list_index].interrupted = MTK_WCN_BOOL_TRUE;
1840     if ( (registed_list_index >= 0)
1841         && (registed_list_index < CFG_CLIENT_COUNT) ) {
1842         g_hif_sdio_clt_drv_list[registed_list_index].sdio_cltinfo->hif_clt_irq( CLTCTX(func->device,\
1843                                                                     func->num, func->cur_blksize, probed_list_index) );
1844     }
1845     else {
1846     //4 <3> if func has no VALID hif_sdio client's context, release irq for this
1847     //4 func and mark it in g_hif_sdio_probed_func_list (remember: donnot claim host in irq contex).
1848         HIF_SDIO_WARN_FUNC("release irq (func:0x%p) v(0x%x) d(0x%x) n(0x%x)\n",
1849             func, func->vendor, func->device, func->num);
1850         mtk_wcn_sdio_irq_flag_set (0);
1851         sdio_release_irq(func);
1852     }
1853
1854     return;
1855 }
1856
1857 /*!
1858  * \brief hif_sdio init function
1859  *
1860  * detailed descriptions
1861  *
1862  * \retval
1863  */
1864 static int __init hif_sdio_init(void)
1865 {
1866     int   ret = 0;
1867     INT32 i   = 0;
1868
1869     HIF_SDIO_INFO_FUNC("start!\n");
1870
1871     //4 <1> init all private variables
1872     /* init reference count to 0 */
1873     gRefCount = 0;
1874
1875     /* init spin lock information */
1876     spin_lock_init( &g_hif_sdio_lock_info.probed_list_lock );
1877     spin_lock_init( &g_hif_sdio_lock_info.clt_list_lock );
1878
1879     /* init probed function list and g_hif_sdio_clt_drv_list */
1880     for ( i=0; i<CFG_CLIENT_COUNT; i++ )
1881     {
1882         hif_sdio_init_probed_list(i);
1883         hif_sdio_init_clt_list(i);
1884     }
1885
1886     //4 <2> register to mmc driver
1887     ret = sdio_register_driver(&mtk_sdio_client_drv);
1888     HIF_SDIO_INFO_FUNC("sdio_register_driver() ret=%d\n", ret);
1889         
1890         //4 <3> create thread for query chip id and device node for launcher to access
1891         if (0 == hifsdiod_start())
1892         {
1893         hif_sdio_create_dev_node();
1894         }
1895     HIF_SDIO_DBG_FUNC("end!\n");
1896     return ret;
1897 }
1898
1899 /*!
1900  * \brief hif_sdio init function
1901  *
1902  * detailed descriptions
1903  *
1904  * \retval
1905  */
1906 static VOID __exit hif_sdio_exit(void)
1907 {
1908     HIF_SDIO_INFO_FUNC("start!\n");
1909         
1910         hif_sdio_remove_dev_node();
1911
1912         hifsdiod_stop();
1913     //4 <0> if client driver is not removed yet, we shall NOT be called...
1914
1915     //4 <1> check reference count
1916     if ( gRefCount !=0  )
1917     {
1918         HIF_SDIO_WARN_FUNC("gRefCount=%d !!!\n", gRefCount);
1919     }
1920
1921     //4 <2> check if there is any hif_sdio-registered clients. There should be
1922     //4 no registered client...
1923
1924     //4 <3> Reregister with mmc driver. Our remove handler hif_sdio_remove()
1925     //4 will be called later by mmc_core. Clean up driver resources there.
1926     sdio_unregister_driver(&mtk_sdio_client_drv);
1927
1928     HIF_SDIO_DBG_FUNC("end!\n");
1929     return;
1930 } /* end of exitWlan() */
1931
1932 /*!
1933  * \brief stp on by wmt (probe client driver).
1934  *
1935  *
1936  * \param none.
1937  *
1938  * \retval 0:success, -11:not probed, -12:already on, -13:not registered, other errors.
1939  */
1940 INT32 hif_sdio_stp_on(
1941     void
1942     )
1943 {
1944 #if 0
1945     MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO *clt_probe_worker_info = 0;
1946 #endif
1947     INT32 clt_index = -1;
1948     INT32 probe_index = -1;
1949     struct sdio_func *func = 0;
1950     int ret = -1;
1951     int ret2 = -1;
1952
1953     HIF_SDIO_INFO_FUNC("start!\n");
1954
1955     //4 <1> If stp client drv has not been probed, return error code
1956     /* MT6620 */
1957     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020B, 1)) >= 0 )
1958     {
1959         goto stp_on_exist;
1960     }
1961     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020C, 1)) >= 0 )
1962     {
1963         goto stp_on_exist;
1964     }
1965
1966     /* MT6628 */
1967     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6628, 2)) >= 0 )
1968     {
1969         goto stp_on_exist;
1970     }
1971     /* MT6619 */
1972     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6619, 1)) >= 0 )
1973     {
1974         goto stp_on_exist;
1975     }
1976
1977     /* MT6618 */
1978     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018B, 1)) >= 0 )
1979     {
1980         goto stp_on_exist;
1981     }
1982     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018C, 1)) >= 0 )
1983     {
1984         goto stp_on_exist;
1985     }
1986     else
1987     {
1988         //4 <2> If stp client drv has not been probed, return error code
1989         /* client func has not been probed */
1990         HIF_SDIO_INFO_FUNC("no supported func probed \n");
1991         return HIF_SDIO_ERR_NOT_PROBED;
1992     }
1993
1994 stp_on_exist:
1995     //4 <3> If stp client drv has been on by wmt, return error code
1996     if (MTK_WCN_BOOL_FALSE != g_hif_sdio_probed_func_list[probe_index].on_by_wmt) {
1997        HIF_SDIO_INFO_FUNC("already on...\n");
1998        return HIF_SDIO_ERR_ALRDY_ON;
1999     }
2000     else {
2001         g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_TRUE;
2002     }
2003
2004     if ( (clt_index = g_hif_sdio_probed_func_list[probe_index].clt_idx) >= 0 )    /* the function has been registered */
2005     {
2006         g_hif_sdio_probed_func_list[probe_index].sdio_irq_enabled = MTK_WCN_BOOL_FALSE;
2007         //4 <4> claim irq for this function
2008         func = g_hif_sdio_probed_func_list[probe_index].func;
2009         sdio_claim_host(func);
2010         ret = sdio_claim_irq(func, hif_sdio_irq);
2011         mtk_wcn_sdio_irq_flag_set (1);
2012         sdio_release_host(func);
2013         if (ret) {
2014             HIF_SDIO_WARN_FUNC("sdio_claim_irq() for stp fail(%d)\n", ret);
2015             return ret;
2016         }
2017         HIF_SDIO_INFO_FUNC("sdio_claim_irq() for stp ok\n");
2018
2019         //4 <5> If this struct sdio_func *func is supported by any driver in
2020         //4 g_hif_sdio_clt_drv_list, schedule another task to call client's .hif_clt_probe()
2021         // TODO: [FixMe][George] WHY probe worker is removed???
2022 #if 1
2023         /* Call client's .hif_clt_probe() */
2024         ret = hif_sdio_clt_probe_func(&g_hif_sdio_clt_drv_list[clt_index], probe_index);
2025         if (ret) {
2026             HIF_SDIO_WARN_FUNC("clt_probe_func() for stp fail(%d) release irq\n", ret);
2027             sdio_claim_host(func);
2028             mtk_wcn_sdio_irq_flag_set (0);
2029             ret2 = sdio_release_irq(func);
2030             sdio_release_host(func);
2031             if (ret2) {
2032                 HIF_SDIO_WARN_FUNC("sdio_release_irq() for stp fail(%d)\n", ret2);
2033             }
2034
2035             g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_FALSE;
2036             return ret;
2037         }
2038         HIF_SDIO_INFO_FUNC("ok!\n");
2039
2040         return 0;
2041 #else
2042         /* use worker thread to perform the client's .hif_clt_probe() */
2043         clt_probe_worker_info = vmalloc( sizeof(MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO) );
2044         INIT_WORK( &clt_probe_worker_info->probe_work, hif_sdio_clt_probe_worker );
2045         clt_probe_worker_info->registinfo_p = &g_hif_sdio_clt_drv_list[clt_index];
2046         clt_probe_worker_info->probe_idx = probe_index;
2047         schedule_work( &clt_probe_worker_info->probe_work );
2048 #endif
2049     }
2050     else {
2051         // TODO: [FixMe][George] check if clt_index is cleared in client's unregister function
2052         HIF_SDIO_WARN_FUNC("probed but not registered yet (%d)\n", ret);
2053         return HIF_SDIO_ERR_CLT_NOT_REG;
2054     }
2055 }
2056
2057 /*!
2058  * \brief stp off by wmt (remove client driver).
2059  *
2060  *
2061  * \param none.
2062  *
2063  * \retval 0:success, -11:not probed, -12:already off, -13:not registered, other errors.
2064  */
2065 INT32 hif_sdio_stp_off(
2066     void
2067     )
2068 {
2069     INT32 clt_index = -1;
2070     INT32 probe_index = -1;
2071     struct sdio_func *func = 0;
2072     int ret = -1;
2073     int ret2 = -1;
2074
2075     HIF_SDIO_INFO_FUNC("start!\n");
2076
2077     //4 <1> If stp client drv has not been probed, return error code
2078     /* MT6620 */
2079     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020B, 1)) >= 0 )
2080     {
2081         goto stp_off_exist;
2082     }
2083     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020C, 1)) >= 0 )
2084     {
2085         goto stp_off_exist;
2086     }
2087     
2088     /* MT6628 */
2089     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6628, 2)) >= 0 )
2090     {
2091         goto stp_off_exist;
2092     }
2093
2094     /* MT6619 */
2095     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6619, 1)) >= 0 )
2096     {
2097         goto stp_off_exist;
2098     }
2099
2100     /* MT6618 */
2101     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018B, 1)) >= 0 )
2102     {
2103         goto stp_off_exist;
2104     }
2105     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018C, 1)) >= 0 )
2106     {
2107         goto stp_off_exist;
2108     }
2109     else
2110     {
2111         //4 <2> If stp client drv has not been probed, return error code
2112         /* client func has not been probed */
2113         return HIF_SDIO_ERR_NOT_PROBED;
2114     }
2115
2116 stp_off_exist:
2117     //4 <3> If stp client drv has been off by wmt, return error code
2118     if (MTK_WCN_BOOL_FALSE == g_hif_sdio_probed_func_list[probe_index].on_by_wmt) {
2119         HIF_SDIO_WARN_FUNC("already off...\n");
2120         return HIF_SDIO_ERR_ALRDY_OFF;
2121     }
2122     else {
2123         g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_FALSE;
2124     }
2125
2126 #if 0 // TODO: [FixMe][George] moved below as done in stp_on.
2127     //4 <4> release irq for this function
2128     func = g_hif_sdio_probed_func_list[probe_index].func;
2129     sdio_claim_host(func);
2130     ret = sdio_release_irq(func);
2131     sdio_release_host(func);
2132     if (ret) {
2133         printk(KERN_WARNING DRV_NAME "sdio_release_irq for stp fail(%d)\n", ret);
2134     }
2135     else {
2136         printk(KERN_INFO DRV_NAME "sdio_release_irq for stp ok\n");
2137     }
2138 #endif
2139
2140     if ( (clt_index = g_hif_sdio_probed_func_list[probe_index].clt_idx) >= 0 )    /* the function has been registered */
2141     {
2142         func = g_hif_sdio_probed_func_list[probe_index].func;
2143         
2144         //4 <4> Callback to client driver's remove() func
2145         ret = g_hif_sdio_clt_drv_list[clt_index].sdio_cltinfo->hif_clt_remove(
2146             CLTCTX(func->device, func->num, func->cur_blksize, probe_index) );
2147         if (ret) {
2148             HIF_SDIO_WARN_FUNC("clt_remove for stp fail(%d)\n", ret);
2149         }
2150         else {
2151             HIF_SDIO_INFO_FUNC("ok!\n");
2152         }
2153         
2154         //4 <5> release irq for this function
2155         sdio_claim_host(func);
2156         mtk_wcn_sdio_irq_flag_set (0);
2157         ret2 = sdio_release_irq(func);
2158         sdio_release_host(func);
2159                 
2160         g_hif_sdio_probed_func_list[probe_index].sdio_irq_enabled = MTK_WCN_BOOL_FALSE;
2161         if (ret2) {
2162             HIF_SDIO_WARN_FUNC("sdio_release_irq() for stp fail(%d)\n", ret2);
2163         }
2164         else {
2165             HIF_SDIO_INFO_FUNC("sdio_release_irq() for stp ok\n");
2166         }
2167                 
2168         return (ret + ret2);
2169     }
2170     else {
2171         // TODO: [FixMe][George] check if clt_index is cleared in client's unregister function
2172         HIF_SDIO_WARN_FUNC("probed but not registered yet (%d)\n", ret);
2173         return HIF_SDIO_ERR_CLT_NOT_REG;
2174     }
2175 }
2176
2177 /*!
2178  * \brief wifi on by wmt (probe client driver).
2179  *
2180  *
2181  * \param none.
2182  *
2183  * \retval 0:success, -11:not probed, -12:already on, -13:not registered, other errors.
2184  */
2185 INT32
2186 hif_sdio_wifi_on (void)
2187 {
2188 #if 0
2189     MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO *clt_probe_worker_info = 0;
2190 #endif
2191     INT32 clt_index = -1;
2192     INT32 probe_index = -1;
2193     struct sdio_func *func = 0;
2194     int ret = 0;
2195     int ret2 = 0;
2196
2197     HIF_SDIO_INFO_FUNC("start!\n");
2198
2199     //4 <1> If wifi client drv has not been probed, return error code
2200     /* MT6620 */
2201     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020A, 1)) >= 0 )
2202     {
2203         goto wifi_on_exist;
2204     }
2205     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020C, 2)) >= 0 )
2206     {
2207         goto wifi_on_exist;
2208     }
2209      /* MT6628 */
2210     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6628, 1)) >= 0 )
2211     {
2212         goto wifi_on_exist;
2213     }
2214     /* MT6618 */
2215     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018A, 1)) >= 0 )
2216     {
2217         goto wifi_on_exist;
2218     }
2219     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018C, 2)) >= 0 )
2220     {
2221         goto wifi_on_exist;
2222     }
2223     else
2224     {
2225         //4 <2> If wifi client drv has not been probed, return error code
2226         /* client func has not been probed */
2227         return HIF_SDIO_ERR_NOT_PROBED;
2228     }
2229
2230 wifi_on_exist:
2231     //4 <3> If wifi client drv has been on by wmt, return error code
2232     if (g_hif_sdio_probed_func_list[probe_index].on_by_wmt) {
2233         HIF_SDIO_INFO_FUNC("probe_index (%d), already on...\n", probe_index);
2234         return HIF_SDIO_ERR_ALRDY_ON;
2235     }
2236
2237     if ( (clt_index = g_hif_sdio_probed_func_list[probe_index].clt_idx) >= 0 )    /* the function has been registered */
2238     {
2239          g_hif_sdio_probed_func_list[probe_index].sdio_irq_enabled = MTK_WCN_BOOL_FALSE;
2240         //4 <4> claim irq for this function
2241         func = g_hif_sdio_probed_func_list[probe_index].func;
2242         sdio_claim_host(func);
2243         ret = sdio_claim_irq(func, hif_sdio_irq);
2244         mtk_wcn_sdio_irq_flag_set (1);
2245         sdio_release_host(func);
2246         if (ret) {
2247             HIF_SDIO_WARN_FUNC("sdio_claim_irq() for wifi fail(%d)\n", ret);
2248             return ret;
2249         }
2250         HIF_SDIO_INFO_FUNC("sdio_claim_irq() for wifi ok\n");
2251
2252         //4 <5> If this struct sdio_func *func is supported by any driver in
2253         //4 g_hif_sdio_clt_drv_list, schedule another task to call client's .hif_clt_probe()
2254         // TODO: [FixMe][George] WHY probe worker is removed???
2255 #if 1
2256         /* Call client's .hif_clt_probe() */
2257         ret = hif_sdio_clt_probe_func(&g_hif_sdio_clt_drv_list[clt_index], probe_index);
2258         if (ret) {
2259             HIF_SDIO_WARN_FUNC("clt_probe_func() for wifi fail(%d) release irq\n", ret);
2260             sdio_claim_host(func);
2261             mtk_wcn_sdio_irq_flag_set (0);
2262             ret2 = sdio_release_irq(func);
2263             sdio_release_host(func);
2264             if (ret2) {
2265                 HIF_SDIO_WARN_FUNC("sdio_release_irq() for wifi fail(%d)\n", ret2);
2266             }
2267
2268             g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_FALSE;
2269             return ret;
2270         }
2271         else
2272         {
2273             g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_TRUE;
2274         }
2275         HIF_SDIO_INFO_FUNC("ok!\n");
2276         return 0;
2277 #else
2278         /* use worker thread to perform the client's .hif_clt_probe() */
2279         clt_probe_worker_info = vmalloc( sizeof(MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO) );
2280         INIT_WORK( &clt_probe_worker_info->probe_work, hif_sdio_clt_probe_worker );
2281         clt_probe_worker_info->registinfo_p = &g_hif_sdio_clt_drv_list[clt_index];
2282         clt_probe_worker_info->probe_idx = probe_index;
2283         schedule_work( &clt_probe_worker_info->probe_work );
2284 #endif
2285     }
2286     else {
2287         // TODO: [FixMe][George] check if clt_index is cleared in client's unregister function
2288         HIF_SDIO_WARN_FUNC("probed but not registered yet (%d)\n", ret);
2289         return HIF_SDIO_ERR_CLT_NOT_REG;
2290     }
2291 }
2292
2293 /*!
2294  * \brief wifi off by wmt (remove client driver).
2295  *
2296  *
2297  * \param none.
2298  *
2299  * \retval 0:success, -11:not probed, -12:already off, -13:not registered, other errors.
2300  */
2301 INT32 hif_sdio_wifi_off(
2302     void
2303     )
2304 {
2305     INT32 clt_index = -1;
2306     INT32 probe_index = -1;
2307     struct sdio_func *func = 0;
2308     int ret = -1;
2309     int ret2 = -1;
2310
2311     HIF_SDIO_INFO_FUNC("start!\n");
2312
2313     //4 <1> If wifi client drv has not been probed, return error code
2314     /* MT6620 */
2315     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020A, 1)) >= 0 )
2316     {
2317         goto wifi_off_exist;
2318     }
2319     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020C, 2)) >= 0 )
2320     {
2321         goto wifi_off_exist;
2322     }
2323
2324     /* MT6628 */
2325     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6628, 1)) >= 0 )
2326     {
2327         goto wifi_off_exist;
2328     }
2329     
2330     /* MT6618 */
2331     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018A, 1)) >= 0 )
2332     {
2333         goto wifi_off_exist;
2334     }
2335     if ( (probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018C, 2)) >= 0 )
2336     {
2337         goto wifi_off_exist;
2338     }
2339     else
2340     {
2341         //4 <2> If wifi client drv has not been probed, return error code
2342         /* client func has not been probed */
2343         return HIF_SDIO_ERR_NOT_PROBED;
2344     }
2345
2346 wifi_off_exist:
2347     //4 <3> If wifi client drv has been off by wmt, return error code
2348     if (MTK_WCN_BOOL_FALSE == g_hif_sdio_probed_func_list[probe_index].on_by_wmt) {
2349         HIF_SDIO_WARN_FUNC("already off...\n");
2350         return HIF_SDIO_ERR_ALRDY_OFF;
2351     }
2352     else {
2353         g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_FALSE;
2354     }
2355
2356 #if 0 // TODO: [FixMe][George] moved below as done in wifi_on.
2357     //4 <4> release irq for this function
2358     func = g_hif_sdio_probed_func_list[probe_index].func;
2359     sdio_claim_host(func);
2360     ret = sdio_release_irq(func);
2361     sdio_release_host(func);
2362     if (ret) {
2363         printk(KERN_WARNING DRV_NAME "sdio_release_irq for wifi fail(%d)\n", ret);
2364     }
2365     else {
2366         printk(KERN_INFO DRV_NAME "sdio_release_irq for wifi ok\n");
2367     }
2368 #endif
2369
2370     if ( (clt_index = g_hif_sdio_probed_func_list[probe_index].clt_idx) >= 0 )    /* the function has been registered */
2371     {
2372         func = g_hif_sdio_probed_func_list[probe_index].func;
2373
2374         //4 <4> Callback to client driver's remove() func
2375         ret = g_hif_sdio_clt_drv_list[clt_index].sdio_cltinfo->hif_clt_remove(
2376             CLTCTX(func->device, func->num, func->cur_blksize, probe_index) );
2377         if (ret) {
2378             HIF_SDIO_WARN_FUNC("clt_remove for wifi fail(%d)\n", ret);
2379         }
2380         else {
2381             HIF_SDIO_INFO_FUNC("ok!\n");
2382         }
2383
2384         //4 <5> release irq for this function
2385         sdio_claim_host(func);
2386         mtk_wcn_sdio_irq_flag_set (0);
2387         ret2 = sdio_release_irq(func);
2388         sdio_release_host(func);
2389                 g_hif_sdio_probed_func_list[probe_index].sdio_irq_enabled = MTK_WCN_BOOL_FALSE;
2390         if (ret2) {
2391             HIF_SDIO_WARN_FUNC("sdio_release_irq() for wifi fail(%d)\n", ret2);
2392         }
2393         else {
2394             HIF_SDIO_INFO_FUNC("sdio_release_irq() for wifi ok\n");
2395         }
2396         return (ret + ret2);
2397     }
2398     else {
2399         // TODO: [FixMe][George] check if clt_index is cleared in client's unregister function
2400         HIF_SDIO_WARN_FUNC("probed but not registered yet (%d)\n", ret);
2401         return HIF_SDIO_ERR_CLT_NOT_REG;
2402     }
2403 }
2404
2405 /*!
2406  * \brief set mmc power up/off
2407  *
2408  * detailed descriptions
2409  *
2410  * \param: 1. ctx client's context variable, 2.power state: 1:power up, other:power off
2411  *
2412  * \retval 0:success, -1:fail
2413  */
2414 INT32 mtk_wcn_hif_sdio_bus_set_power (
2415     MTK_WCN_HIF_SDIO_CLTCTX ctx,
2416     UINT32 pwrState
2417     )
2418 {
2419     int probe_index = -1;
2420     struct sdio_func *func = 0;
2421
2422     HIF_SDIO_INFO_FUNC("turn Bus Power to: %d\n", pwrState);
2423
2424     probe_index = CLTCTX_IDX(ctx);
2425     func = g_hif_sdio_probed_func_list[probe_index].func;
2426
2427     if ( !func )
2428     {
2429         HIF_SDIO_WARN_FUNC("Cannot find sdio_func !!!\n");
2430         return -1;
2431     }
2432
2433     if ( 1 == pwrState )
2434     {
2435         sdio_claim_host( func );
2436         mmc_power_up_ext( func->card->host );
2437         sdio_release_host( func );
2438         HIF_SDIO_WARN_FUNC("SDIO BUS Power UP\n");
2439     }
2440     else
2441     {
2442         sdio_claim_host( func );
2443         mmc_power_off_ext( func->card->host );
2444         sdio_release_host( func );
2445         HIF_SDIO_WARN_FUNC("SDIO BUS Power OFF\n");
2446     }
2447
2448     return 0;
2449 }
2450
2451 void mtk_wcn_hif_sdio_enable_irq(
2452     MTK_WCN_HIF_SDIO_CLTCTX ctx,
2453     MTK_WCN_BOOL enable
2454     )
2455 {
2456     UINT8 probed_idx = CLTCTX_IDX(ctx);
2457
2458     if (unlikely(!CLTCTX_IDX_VALID(probed_idx))) {   /* invalid index in CLTCTX */
2459         HIF_SDIO_WARN_FUNC("invalid idx in ctx(0x%x), sdio_irq no change\n", ctx);
2460         return;
2461     }
2462
2463     /* store client driver's private data to dev driver */
2464     g_hif_sdio_probed_func_list[probed_idx].sdio_irq_enabled = enable;
2465     smp_wmb();
2466     HIF_SDIO_INFO_FUNC("ctx(0x%x) sdio irq enable(%d)\n",
2467         ctx, (MTK_WCN_BOOL_FALSE == enable) ? 0 : 1);
2468
2469
2470 }
2471
2472 module_init(hif_sdio_init);
2473 module_exit(hif_sdio_exit);
2474
2475 EXPORT_SYMBOL(mtk_wcn_hif_sdio_update_cb_reg);
2476 EXPORT_SYMBOL(mtk_wcn_hif_sdio_client_reg);
2477 EXPORT_SYMBOL(mtk_wcn_hif_sdio_client_unreg);
2478 EXPORT_SYMBOL(mtk_wcn_hif_sdio_readb);
2479 EXPORT_SYMBOL(mtk_wcn_hif_sdio_writeb);
2480 EXPORT_SYMBOL(mtk_wcn_hif_sdio_readl);
2481 EXPORT_SYMBOL(mtk_wcn_hif_sdio_writel);
2482 EXPORT_SYMBOL(mtk_wcn_hif_sdio_read_buf);
2483 EXPORT_SYMBOL(mtk_wcn_hif_sdio_write_buf);
2484 EXPORT_SYMBOL(mtk_wcn_hif_sdio_set_drvdata);
2485 EXPORT_SYMBOL(mtk_wcn_hif_sdio_get_drvdata);
2486 EXPORT_SYMBOL(mtk_wcn_hif_sdio_wmt_control);
2487 EXPORT_SYMBOL(mtk_wcn_hif_sdio_bus_set_power);
2488 EXPORT_SYMBOL(mtk_wcn_hif_sdio_get_dev);
2489 EXPORT_SYMBOL(mtk_wcn_hif_sdio_enable_irq); 
2490
2491