MT6620: add the new driver JB2 V1.0
[firefly-linux-kernel-4.4.55.git] / drivers / mtk_wcn_combo / common / linux / hif_sdio_chrdev.c
1 #include "hif_sdio.h"
2 #include "hif_sdio_chrdev.h"
3
4
5
6 static int hif_sdio_proc(void * pvData);
7 static int hif_sdio_open(struct inode *inode, struct file *file);
8 static int hif_sdio_release(struct inode *inode, struct file *file);
9 static long hif_sdio_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
10 static ssize_t hif_sdio_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
11
12
13
14 unsigned int hifSdioMajor = 0;
15
16 #define COMBO_IOC_MAGIC        'h'
17 #define COMBO_IOCTL_GET_CHIP_ID  _IOR(COMBO_IOC_MAGIC, 0, int)
18 #define COMBO_IOCTL_SET_CHIP_ID  _IOW(COMBO_IOC_MAGIC, 1, int)
19
20 MTK_WCN_HIF_SDIO_CHIP_INFO gChipInfoArray[] = {
21     /* MT6620 */ /* Not an SDIO standard class device */
22     { {SDIO_DEVICE(0x037A, 0x020A)}, 0x6620 }, /* SDIO1:FUNC1:WIFI */
23     { {SDIO_DEVICE(0x037A, 0x020B)}, 0x6620 }, /* SDIO2:FUNC1:BT+FM+GPS */
24     { {SDIO_DEVICE(0x037A, 0x020C)}, 0x6620 }, /* 2-function (SDIO2:FUNC1:BT+FM+GPS, FUNC2:WIFI) */
25     
26     /* MT6628 */ /* SDIO1: Wi-Fi, SDIO2: BGF */
27     { {SDIO_DEVICE(0x037A, 0x6628)}, 0x6628},
28
29 };
30
31
32
33 struct file_operations hifDevOps = 
34 {
35         .owner = THIS_MODULE,
36         .open = hif_sdio_open,
37         .release = hif_sdio_release,
38         .unlocked_ioctl = hif_sdio_unlocked_ioctl,
39         .read = hif_sdio_read,
40 };
41
42 struct class *pHifClass = NULL;
43 struct device *pHifDev = NULL;
44 UCHAR *HifClassName = "hifsdiod";
45 UCHAR *kObjName = "hifsdiod";
46
47
48 struct task_struct *gConIdQueryThread;
49 wait_queue_head_t gHifsdiodEvent;
50
51 //OSAL_THREAD           gConIdQueryThread;
52 //OSAL_EVENT            gHifsdiodEvent;
53 UCHAR *gConIdQueryName = "consys-id-query";
54 INT32 gComboChipId = -1;
55
56
57
58 INT32 hifsdiod_start(void)
59 {
60     int iRet = -1;
61         init_waitqueue_head(&gHifsdiodEvent);
62 #if 0
63     osal_event_init(&gHifsdiodEvent);
64     gConIdQueryThread.pThreadData = (VOID *)NULL;
65     gConIdQueryThread.pThreadFunc = (VOID *)hif_sdio_proc;
66     osal_memcpy(gConIdQueryThread.threadName, gConIdQueryName , osal_strlen(gConIdQueryName));
67         
68
69     iRet = osal_thread_create(&gConIdQueryThread);
70     if (iRet < 0) 
71     {
72         HIF_SDIO_ERR_FUNC("osal_thread_create fail...\n");
73         goto ERR_EXIT1;
74     }
75 #else
76     gConIdQueryThread = kthread_create(hif_sdio_proc, NULL, gConIdQueryName);
77     if (NULL == gConIdQueryThread) 
78     {
79         HIF_SDIO_ERR_FUNC("osal_thread_create fail...\n");
80         goto ERR_EXIT1;
81     }
82
83 #endif
84
85 #if 0
86     /* Start STPd thread*/
87     iRet = osal_thread_run(&gConIdQueryThread);
88     if(iRet < 0)
89     {
90         HIF_SDIO_ERR_FUNC("osal_thread_run FAILS\n");
91         goto ERR_EXIT1;
92     }
93 #else
94     if (gConIdQueryThread) {
95         wake_up_process(gConIdQueryThread);
96     }
97         else
98         {
99             goto ERR_EXIT1;
100         }
101 #endif
102     iRet = 0;
103         HIF_SDIO_INFO_FUNC("succeed\n");
104
105         return iRet;
106         
107 ERR_EXIT1:
108         HIF_SDIO_ERR_FUNC("failed\n");
109         return iRet;
110  }
111
112
113 INT32 hifsdiod_stop(void)
114 {
115     if (gConIdQueryThread) {
116                 HIF_SDIO_INFO_FUNC("inform hifsdiod exit..\n");
117         kthread_stop(gConIdQueryThread);
118                 gConIdQueryThread = NULL;
119     }
120         return 0;
121 }
122
123
124 static int hif_sdio_proc(void * pvData)
125 {
126     while (!kthread_should_stop()) 
127     {
128         //HIF_SDIO_INFO_FUNC("enter sleep.\n");
129                 osal_msleep(10000);
130                 //HIF_SDIO_INFO_FUNC("wakeup\n");               
131     }
132     HIF_SDIO_INFO_FUNC("hifsdiod exit.\n"); 
133         return 0;
134 }
135
136
137 static int hif_sdio_open(struct inode *inode, struct file *file)
138 {
139     HIF_SDIO_INFO_FUNC(" ++\n");
140         HIF_SDIO_INFO_FUNC(" --\n");
141         return 0;
142 }
143
144 static int hif_sdio_release(struct inode *inode, struct file *file)
145 {
146     HIF_SDIO_INFO_FUNC(" ++\n");
147         HIF_SDIO_INFO_FUNC(" --\n");
148
149         return 0;
150 }
151
152
153 static ssize_t hif_sdio_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
154
155 {
156     HIF_SDIO_INFO_FUNC(" ++\n");
157         HIF_SDIO_INFO_FUNC(" --\n");
158
159     return 0;
160 }
161
162 static long hif_sdio_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
163 {
164     int retval = 0;
165
166     HIF_SDIO_DBG_FUNC("cmd (%d)\n", cmd);
167
168     switch(cmd)
169     {
170         case COMBO_IOCTL_GET_CHIP_ID:
171                         gComboChipId = 0x6628;
172                         retval = gComboChipId;
173                         HIF_SDIO_INFO_FUNC("get combo chip id: 0x%x\n", gComboChipId);
174                         break;
175                 case COMBO_IOCTL_SET_CHIP_ID:
176                         gComboChipId = arg;
177                         HIF_SDIO_INFO_FUNC("set combo chip id to 0x%x\n", gComboChipId);
178                         break;
179                 default:
180                         HIF_SDIO_WARN_FUNC("unknown cmd (%d)\n", cmd);
181                         retval = 0;
182                         break;
183     }
184         return retval;
185 }
186         
187
188 INT32 hif_sdio_is_chipid_valid (INT32 chipId)
189 {
190         INT32 index = -1;
191         
192     INT32 left = 0;
193         INT32 middle = 0;
194     INT32 right = sizeof (gChipInfoArray) / sizeof (gChipInfoArray[0]) - 1;
195         if ((chipId < gChipInfoArray[left].chipId) || (chipId > gChipInfoArray[right].chipId))
196                 return index;
197
198         middle = (left + right) / 2;
199         
200         while (left <= right)
201         {
202             if (chipId > gChipInfoArray[middle].chipId)
203             {
204                 left = middle + 1;
205             }
206                 else if (chipId < gChipInfoArray[middle].chipId)
207                 {
208                     right = middle - 1;
209                 }
210                 else
211                 {
212                     index = middle;
213                         break;
214                 }
215                 middle = (left + right) / 2;
216         }
217         
218     if (0 > index)
219     {
220         HIF_SDIO_ERR_FUNC("no supported chipid found\n");
221     }
222         else
223         {
224                 HIF_SDIO_INFO_FUNC("index:%d, chipId:0x%x\n", index, gChipInfoArray[index].chipId);
225         }
226
227         return index;
228 }
229
230 INT32 hif_sdio_match_chipid_by_dev_id (const struct sdio_device_id *id)
231 {
232     INT32 maxIndex = sizeof (gChipInfoArray) / sizeof (gChipInfoArray[0]);
233     INT32 index = 0;
234     struct sdio_device_id *localId = NULL;
235         INT32 chipId = -1;
236         for (index = 0; index < maxIndex; index++)
237         {
238             localId = &(gChipInfoArray[index].deviceId);
239             if ((localId->vendor == id->vendor) && (localId->device == id->device))
240             {
241                 chipId = gChipInfoArray[index].chipId;
242                         HIF_SDIO_INFO_FUNC("valid chipId found, index(%d), vendor id(0x%x), device id(0x%x), chip id(0x%x)\n", index, localId->vendor, localId->device, chipId);
243                         gComboChipId = chipId;
244                 break;
245             }
246         }
247         if (0 > chipId)
248         {
249             HIF_SDIO_ERR_FUNC("No valid chipId found, vendor id(0x%x), device id(0x%x)\n", id->vendor, id->device);
250         }
251         
252     return chipId;
253 }
254
255
256 INT32 mtk_wcn_hif_sdio_query_chipid(INT32 waitFlag)
257 {
258     UINT32 timeSlotMs = 200;
259         UINT32 maxTimeSlot = 15;
260         UINT32 counter = 0;
261     //gComboChipId = 0x6628;
262     if (0 == waitFlag)
263                 return gComboChipId;
264         if (0 <= hif_sdio_is_chipid_valid(gComboChipId))
265                 return gComboChipId;
266     wmt_plat_pwr_ctrl(FUNC_ON);
267         wmt_plat_sdio_ctrl(WMT_SDIO_SLOT_SDIO1, FUNC_ON);
268         while (counter < maxTimeSlot)
269         {
270             if (0 <= hif_sdio_is_chipid_valid(gComboChipId))
271                         break;
272             osal_msleep(timeSlotMs);
273             counter++;
274         }
275         
276         wmt_plat_sdio_ctrl(WMT_SDIO_SLOT_SDIO1, FUNC_OFF);
277         wmt_plat_pwr_ctrl(FUNC_OFF);
278         return gComboChipId;
279 }
280 EXPORT_SYMBOL(mtk_wcn_hif_sdio_query_chipid);
281
282 INT32 mtk_wcn_hif_sdio_tell_chipid(INT32 chipId)
283 {
284
285         gComboChipId = chipId;
286     HIF_SDIO_INFO_FUNC("set combo chip id to 0x%x\n", gComboChipId);
287
288         return gComboChipId;
289 }
290 EXPORT_SYMBOL(mtk_wcn_hif_sdio_tell_chipid);
291
292 INT32 hif_sdio_create_dev_node(void)
293 {
294
295         INT32 iResult = -1;
296         
297         HIF_SDIO_DBG_FUNC( "++");
298         iResult = register_chrdev(hifSdioMajor, kObjName, &hifDevOps);
299         if(0 > iResult)
300         {
301                 HIF_SDIO_ERR_FUNC("register_chrdev failed.\n");
302                 iResult = -1;
303         }
304         else
305         {
306                 hifSdioMajor = hifSdioMajor == 0 ? iResult : hifSdioMajor;
307                 HIF_SDIO_INFO_FUNC("register_chrdev succeed, mtk_jajor = %d\n", hifSdioMajor);
308                 pHifClass = class_create(THIS_MODULE, HifClassName);
309                 if(IS_ERR(pHifClass))
310                 {
311                         HIF_SDIO_ERR_FUNC("class_create error\n");
312                         iResult = -2;
313                 }
314                 else
315                 {
316                         pHifDev = device_create(pHifClass, NULL, MKDEV(hifSdioMajor, 0), NULL, HifClassName, "%d", 0);
317                         if(IS_ERR(pHifDev))
318                         {
319                                 HIF_SDIO_ERR_FUNC("device_create error:%ld\n", PTR_ERR(pHifDev));
320                                 iResult = -3;
321                         }
322                         else
323                         {
324                             HIF_SDIO_INFO_FUNC("device_create succeed\n");
325                             iResult = 0;
326                         }
327                 }
328         }
329     return iResult;
330 }
331
332
333 INT32 hif_sdio_remove_dev_node(void)
334 {
335     if(pHifDev != NULL)
336         {
337                 device_destroy(pHifClass, MKDEV(hifSdioMajor, 0));
338                 pHifDev = NULL;
339         }
340         if(pHifClass != NULL)
341         {
342                 class_destroy(pHifClass);
343                 pHifClass = NULL;
344         }
345         
346         if(hifSdioMajor != 0)
347         {
348                 unregister_chrdev(hifSdioMajor, kObjName);
349                 hifSdioMajor = 0;
350         }
351     return 0;
352 }
353
354