import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / connectivity / 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 UINT32 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 .owner = THIS_MODULE,
35 .open = hif_sdio_open,
36 .release = hif_sdio_release,
37 .unlocked_ioctl = hif_sdio_unlocked_ioctl,
38 .read = hif_sdio_read,
39 };
40
41 struct class *pHifClass = NULL;
42 struct device *pHifDev = NULL;
43 PUINT8 HifClassName = "hifsdiod";
44 PUINT8 kObjName = "hifsdiod";
45
46
47 struct task_struct *gConIdQueryThread;
48 wait_queue_head_t gHifsdiodEvent;
49
50 /* OSAL_THREAD gConIdQueryThread; */
51 /* OSAL_EVENT gHifsdiodEvent; */
52 PUINT8 gConIdQueryName = "consys-id-query";
53 INT32 gComboChipId = -1;
54
55
56
57 INT32 hifsdiod_start(VOID)
58 {
59 INT32 iRet = -1;
60 init_waitqueue_head(&gHifsdiodEvent);
61 #if 0
62 osal_event_init(&gHifsdiodEvent);
63 gConIdQueryThread.pThreadData = NULL;
64 gConIdQueryThread.pThreadFunc = (size_t *) hif_sdio_proc;
65 osal_memcpy(gConIdQueryThread.threadName, gConIdQueryName, osal_strlen(gConIdQueryName));
66
67
68 iRet = osal_thread_create(&gConIdQueryThread);
69 if (iRet < 0) {
70 HIF_SDIO_ERR_FUNC("osal_thread_create fail...\n");
71 goto ERR_EXIT1;
72 }
73 #else
74 gConIdQueryThread = kthread_create(hif_sdio_proc, NULL, gConIdQueryName);
75 if (NULL == gConIdQueryThread) {
76 HIF_SDIO_ERR_FUNC("osal_thread_create fail...\n");
77 goto ERR_EXIT1;
78 }
79 #endif
80
81 #if 0
82 /* Start STPd thread */
83 iRet = osal_thread_run(&gConIdQueryThread);
84 if (iRet < 0) {
85 HIF_SDIO_ERR_FUNC("osal_thread_run FAILS\n");
86 goto ERR_EXIT1;
87 }
88 #else
89 if (gConIdQueryThread) {
90 wake_up_process(gConIdQueryThread);
91 } else {
92 goto ERR_EXIT1;
93 }
94 #endif
95 iRet = 0;
96 HIF_SDIO_INFO_FUNC("succeed\n");
97
98 return iRet;
99
100 ERR_EXIT1:
101 HIF_SDIO_ERR_FUNC("failed\n");
102 return iRet;
103 }
104
105
106 INT32 hifsdiod_stop(VOID)
107 {
108 if (gConIdQueryThread) {
109 HIF_SDIO_INFO_FUNC("inform hifsdiod exit..\n");
110 kthread_stop(gConIdQueryThread);
111 gConIdQueryThread = NULL;
112 }
113 return 0;
114 }
115
116
117 static int hif_sdio_proc(void *pvData)
118 {
119 while (!kthread_should_stop()) {
120 /* HIF_SDIO_INFO_FUNC("enter sleep.\n"); */
121 osal_sleep_ms(10000);
122 /* HIF_SDIO_INFO_FUNC("wakeup\n"); */
123 }
124 HIF_SDIO_INFO_FUNC("hifsdiod exit.\n");
125 return 0;
126 }
127
128
129 static int hif_sdio_open(struct inode *inode, struct file *file)
130 {
131 HIF_SDIO_INFO_FUNC(" ++\n");
132 HIF_SDIO_INFO_FUNC(" --\n");
133 return 0;
134 }
135
136 static int hif_sdio_release(struct inode *inode, struct file *file)
137 {
138 HIF_SDIO_INFO_FUNC(" ++\n");
139 HIF_SDIO_INFO_FUNC(" --\n");
140
141 return 0;
142 }
143
144
145 static ssize_t hif_sdio_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
146 {
147 HIF_SDIO_INFO_FUNC(" ++\n");
148 HIF_SDIO_INFO_FUNC(" --\n");
149
150 return 0;
151 }
152
153 static long hif_sdio_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
154 {
155 INT32 retval = 0;
156
157 HIF_SDIO_DBG_FUNC("cmd (%d)\n", cmd);
158
159 switch (cmd) {
160 case COMBO_IOCTL_GET_CHIP_ID:
161 gComboChipId = 0x6628;
162 retval = gComboChipId;
163 HIF_SDIO_INFO_FUNC("get combo chip id: 0x%x\n", gComboChipId);
164 break;
165 case COMBO_IOCTL_SET_CHIP_ID:
166 gComboChipId = arg;
167 HIF_SDIO_INFO_FUNC("set combo chip id to 0x%x\n", gComboChipId);
168 break;
169 default:
170 HIF_SDIO_WARN_FUNC("unknown cmd (%d)\n", cmd);
171 retval = 0;
172 break;
173 }
174 return retval;
175 }
176
177
178 INT32 hif_sdio_is_chipid_valid(INT32 chipId)
179 {
180 INT32 index = -1;
181
182 INT32 left = 0;
183 INT32 middle = 0;
184 INT32 right = ARRAY_SIZE(gChipInfoArray) - 1;
185 if ((chipId < gChipInfoArray[left].chipId) || (chipId > gChipInfoArray[right].chipId))
186 return index;
187
188 middle = (left + right) / 2;
189
190 while (left <= right) {
191 if (chipId > gChipInfoArray[middle].chipId) {
192 left = middle + 1;
193 } else if (chipId < gChipInfoArray[middle].chipId) {
194 right = middle - 1;
195 } else {
196 index = middle;
197 break;
198 }
199 middle = (left + right) / 2;
200 }
201
202 if (0 > index) {
203 HIF_SDIO_ERR_FUNC("no supported chipid found\n");
204 } else {
205 HIF_SDIO_INFO_FUNC("index:%d, chipId:0x%x\n", index, gChipInfoArray[index].chipId);
206 }
207
208 return index;
209 }
210
211 INT32 hif_sdio_match_chipid_by_dev_id(const struct sdio_device_id *id)
212 {
213 INT32 maxIndex = ARRAY_SIZE(gChipInfoArray);
214 INT32 index = 0;
215 struct sdio_device_id *localId = NULL;
216 INT32 chipId = -1;
217 for (index = 0; index < maxIndex; index++) {
218 localId = &(gChipInfoArray[index].deviceId);
219 if ((localId->vendor == id->vendor) && (localId->device == id->device)) {
220 chipId = gChipInfoArray[index].chipId;
221 HIF_SDIO_INFO_FUNC
222 ("valid chipId found, index(%d), vendor id(0x%x), device id(0x%x), chip id(0x%x)\n",
223 index, localId->vendor, localId->device, chipId);
224 gComboChipId = chipId;
225 break;
226 }
227 }
228 if (0 > chipId) {
229 HIF_SDIO_ERR_FUNC("No valid chipId found, vendor id(0x%x), device id(0x%x)\n",
230 id->vendor, id->device);
231 }
232
233 return chipId;
234 }
235
236
237 INT32 mtk_wcn_hif_sdio_query_chipid(INT32 waitFlag)
238 {
239 UINT32 timeSlotMs = 200;
240 UINT32 maxTimeSlot = 15;
241 UINT32 counter = 0;
242 /* gComboChipId = 0x6628; */
243 if (0 == waitFlag)
244 return gComboChipId;
245 if (0 <= hif_sdio_is_chipid_valid(gComboChipId))
246 return gComboChipId;
247 wmt_plat_pwr_ctrl(FUNC_ON);
248 wmt_plat_sdio_ctrl(WMT_SDIO_SLOT_SDIO1, FUNC_ON);
249 while (counter < maxTimeSlot) {
250 if (0 <= hif_sdio_is_chipid_valid(gComboChipId))
251 break;
252 osal_sleep_ms(timeSlotMs);
253 counter++;
254 }
255
256 wmt_plat_sdio_ctrl(WMT_SDIO_SLOT_SDIO1, FUNC_OFF);
257 wmt_plat_pwr_ctrl(FUNC_OFF);
258 return gComboChipId;
259 }
260 EXPORT_SYMBOL(mtk_wcn_hif_sdio_query_chipid);
261
262 INT32 mtk_wcn_hif_sdio_tell_chipid(INT32 chipId)
263 {
264
265 gComboChipId = chipId;
266 HIF_SDIO_INFO_FUNC("set combo chip id to 0x%x\n", gComboChipId);
267
268 return gComboChipId;
269 }
270 EXPORT_SYMBOL(mtk_wcn_hif_sdio_tell_chipid);
271
272 INT32 hif_sdio_create_dev_node(VOID)
273 {
274
275 INT32 iResult = -1;
276
277 HIF_SDIO_DBG_FUNC("++");
278 iResult = register_chrdev(hifSdioMajor, kObjName, &hifDevOps);
279 if (0 > iResult) {
280 HIF_SDIO_ERR_FUNC("register_chrdev failed.\n");
281 iResult = -1;
282 } else {
283 hifSdioMajor = hifSdioMajor == 0 ? iResult : hifSdioMajor;
284 HIF_SDIO_INFO_FUNC("register_chrdev succeed, mtk_jajor = %d\n", hifSdioMajor);
285 pHifClass = class_create(THIS_MODULE, HifClassName);
286 if (IS_ERR(pHifClass)) {
287 HIF_SDIO_ERR_FUNC("class_create error\n");
288 iResult = -2;
289 } else {
290 pHifDev =
291 device_create(pHifClass, NULL, MKDEV(hifSdioMajor, 0), NULL,
292 HifClassName, "%d", 0);
293 if (IS_ERR(pHifDev)) {
294 HIF_SDIO_ERR_FUNC("device_create error:%ld\n", PTR_ERR(pHifDev));
295 iResult = -3;
296 } else {
297 HIF_SDIO_INFO_FUNC("device_create succeed\n");
298 iResult = 0;
299 }
300 }
301 }
302 return iResult;
303 }
304
305
306 INT32 hif_sdio_remove_dev_node(VOID)
307 {
308 if (pHifDev != NULL) {
309 device_destroy(pHifClass, MKDEV(hifSdioMajor, 0));
310 pHifDev = NULL;
311 }
312 if (pHifClass != NULL) {
313 class_destroy(pHifClass);
314 pHifClass = NULL;
315 }
316
317 if (hifSdioMajor != 0) {
318 unregister_chrdev(hifSdioMajor, kObjName);
319 hifSdioMajor = 0;
320 }
321 return 0;
322 }