import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / connectivity / common_detect / sdio_detect.c
1 /*
2 * Copyright (C) 2011-2014 MediaTek Inc.
3 *
4 * This program is free software: you can redistribute it and/or modify it under the terms of the
5 * GNU General Public License version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9 * See the GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License along with this program.
12 * If not, see <http://www.gnu.org/licenses/>.
13 */
14
15 #ifdef DFT_TAG
16 #undef DFT_TAG
17 #endif
18 #define DFT_TAG "[SDIO-DETECT]"
19
20 #include "wmt_detect.h"
21
22 #if MTK_HIF_SDIO_AUTOK_ENABLED
23 #include <mach/mt_boot.h>
24 #endif
25
26 unsigned int gComboChipId = -1;
27 struct sdio_func *g_func = NULL;
28
29 MTK_WCN_HIF_SDIO_CHIP_INFO gChipInfoArray[] = {
30 /* MT6620 */ /* Not an SDIO standard class device */
31 { {SDIO_DEVICE(0x037A, 0x020A)}, 0x6620 }, /* SDIO1:FUNC1:WIFI */
32 { {SDIO_DEVICE(0x037A, 0x020B)}, 0x6620 }, /* SDIO2:FUNC1:BT+FM+GPS */
33 { {SDIO_DEVICE(0x037A, 0x020C)}, 0x6620 }, /* 2-function (SDIO2:FUNC1:BT+FM+GPS, FUNC2:WIFI) */
34
35 /* MT6628 */ /* SDIO1: Wi-Fi, SDIO2: BGF */
36 { {SDIO_DEVICE(0x037A, 0x6628)}, 0x6628},
37
38 /* MT6630 */ /* SDIO1: Wi-Fi, SDIO2: BGF */
39 { {SDIO_DEVICE(0x037A, 0x6630)}, 0x6630 },
40
41 };
42
43
44 /* Supported SDIO device table */
45 static const struct sdio_device_id mtk_sdio_id_tbl[] = {
46 /* MT6618 */ /* Not an SDIO standard class device */
47 { SDIO_DEVICE(0x037A, 0x018A) }, /* SDIO1:WIFI */
48 { SDIO_DEVICE(0x037A, 0x018B) }, /* SDIO2:FUNC1:BT+FM */
49 { SDIO_DEVICE(0x037A, 0x018C) }, /* 2-function (SDIO2:FUNC1:BT+FM, FUNC2:WIFI) */
50
51 /* MT6619 */ /* Not an SDIO standard class device */
52 { SDIO_DEVICE(0x037A, 0x6619) }, /* SDIO2:FUNC1:BT+FM+GPS */
53
54 /* MT6620 */ /* Not an SDIO standard class device */
55 { SDIO_DEVICE(0x037A, 0x020A) }, /* SDIO1:FUNC1:WIFI */
56 { SDIO_DEVICE(0x037A, 0x020B) }, /* SDIO2:FUNC1:BT+FM+GPS */
57 { SDIO_DEVICE(0x037A, 0x020C) }, /* 2-function (SDIO2:FUNC1:BT+FM+GPS, FUNC2:WIFI) */
58
59 /* MT5921 */ /* Not an SDIO standard class device */
60 { SDIO_DEVICE(0x037A, 0x5921) },
61
62 /* MT6628 */ /* SDIO1: Wi-Fi, SDIO2: BGF */
63 { SDIO_DEVICE(0x037A, 0x6628) },
64
65 /* MT6630 */ /* SDIO1: Wi-Fi, SDIO2: BGF */
66 { SDIO_DEVICE(0x037A, 0x6630) },
67 { /* end: all zeroes */ },
68 };
69
70 static int sdio_detect_probe (
71 struct sdio_func *func,
72 const struct sdio_device_id *id
73 );
74
75 static void sdio_detect_remove (
76 struct sdio_func *func
77 );
78
79 static struct sdio_driver mtk_sdio_client_drv = {
80 .name = "mtk_sdio_client", /* MTK SDIO Client Driver */
81 .id_table = mtk_sdio_id_tbl, /* all supported struct sdio_device_id table */
82 .probe = sdio_detect_probe,
83 .remove = sdio_detect_remove,
84 };
85
86 static int hif_sdio_match_chipid_by_dev_id (const struct sdio_device_id *id);
87
88
89 int hif_sdio_is_chipid_valid (int chipId)
90 {
91 int index = -1;
92
93 int left = 0;
94 int middle = 0;
95 int right = sizeof (gChipInfoArray) / sizeof (gChipInfoArray[0]) - 1;
96 if ((chipId < gChipInfoArray[left].chipId) || (chipId > gChipInfoArray[right].chipId))
97 return index;
98
99 middle = (left + right) / 2;
100
101 while (left <= right)
102 {
103 if (chipId > gChipInfoArray[middle].chipId)
104 {
105 left = middle + 1;
106 }
107 else if (chipId < gChipInfoArray[middle].chipId)
108 {
109 right = middle - 1;
110 }
111 else
112 {
113 index = middle;
114 break;
115 }
116 middle = (left + right) / 2;
117 }
118
119 if (0 > index)
120 {
121 WMT_DETECT_ERR_FUNC("no supported chipid found\n");
122 }
123 else
124 {
125 WMT_DETECT_INFO_FUNC("index:%d, chipId:0x%x\n", index, gChipInfoArray[index].chipId);
126 }
127
128 return index;
129 }
130
131 int hif_sdio_match_chipid_by_dev_id (const struct sdio_device_id *id)
132 {
133 int maxIndex = sizeof (gChipInfoArray) / sizeof (gChipInfoArray[0]);
134 int index = 0;
135 struct sdio_device_id *localId = NULL;
136 int chipId = -1;
137 for (index = 0; index < maxIndex; index++)
138 {
139 localId = &(gChipInfoArray[index].deviceId);
140 if ((localId->vendor == id->vendor) && (localId->device == id->device))
141 {
142 chipId = gChipInfoArray[index].chipId;
143 WMT_DETECT_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);
144 gComboChipId = chipId;
145 mtk_wcn_wmt_set_chipid(gComboChipId);
146 break;
147 }
148 }
149 if (0 > chipId)
150 {
151 WMT_DETECT_ERR_FUNC("No valid chipId found, vendor id(0x%x), device id(0x%x)\n", id->vendor, id->device);
152 }
153
154 return chipId;
155 }
156
157 int sdio_detect_query_chipid(int waitFlag)
158 {
159 unsigned int timeSlotMs = 200;
160 unsigned int maxTimeSlot = 15;
161 unsigned int counter = 0;
162 //gComboChipId = 0x6628;
163 if (0 == waitFlag)
164 return gComboChipId;
165 if (0 <= hif_sdio_is_chipid_valid(gComboChipId))
166 return gComboChipId;
167
168 while (counter < maxTimeSlot)
169 {
170 if (0 <= hif_sdio_is_chipid_valid(gComboChipId))
171 break;
172 msleep(timeSlotMs);
173 counter++;
174 }
175
176 return gComboChipId;
177 }
178
179 int sdio_detect_do_autok(int chipId)
180 {
181 int i_ret = 0;
182
183 #if MTK_HIF_SDIO_AUTOK_ENABLED
184 #if 0
185 BOOTMODE boot_mode;
186
187 boot_mode = get_boot_mode();
188
189 if (boot_mode == META_BOOT)
190 {
191 WMT_DETECT_INFO_FUNC("omit autok in meta mode\n");
192 return 0;
193 }
194 #endif
195 if (0x6630 == chipId)
196 {
197 #ifdef CONFIG_SDIOAUTOK_SUPPORT
198 if (NULL!= g_func)
199 {
200 WMT_DETECT_INFO_FUNC("wait_sdio_autok_ready++\n");
201 i_ret = wait_sdio_autok_ready(g_func->card->host);
202 WMT_DETECT_INFO_FUNC("wait_sdio_autok_ready--\n");
203 if (0 == i_ret)
204 {
205 WMT_DETECT_INFO_FUNC("wait_sdio_autok_ready return success\n");
206 }
207 else
208 {
209 WMT_DETECT_INFO_FUNC("wait_sdio_autok_ready return fail, i_ret:%d\n", i_ret);
210 gComboChipId = -1;
211 }
212 }
213 else
214 {
215 WMT_DETECT_INFO_FUNC("g_func NULL, omit autok\n");
216 }
217 #else
218 i_ret = 0;
219 WMT_DETECT_INFO_FUNC("MTK_SDIOAUTOK_SUPPORT not defined\n");
220 #endif
221 }
222 else
223 {
224 WMT_DETECT_INFO_FUNC("MT%x does not support SDIO3.0 autoK is not needed\n", chipId);
225 }
226 #else
227 i_ret = 0;
228 WMT_DETECT_INFO_FUNC("MTK_HIF_SDIO_AUTOK_ENABLED is not defined\n");
229 #endif
230 return i_ret;
231 }
232
233
234 /*!
235 * \brief hif_sdio probe function
236 *
237 * hif_sdio probe function called by mmc driver when any matched SDIO function
238 * is detected by it.
239 *
240 * \param func
241 * \param id
242 *
243 * \retval 0 register successfully
244 * \retval < 0 list error code here
245 */
246 static int sdio_detect_probe (
247 struct sdio_func *func,
248 const struct sdio_device_id *id
249 )
250 {
251 int chipId = 0;
252 WMT_DETECT_INFO_FUNC("vendor(0x%x) device(0x%x) num(0x%x)\n", func->vendor, func->device, func->num);
253 chipId = hif_sdio_match_chipid_by_dev_id(id);
254
255 if ((0x6630 == chipId) && (1 == func->num))
256 {
257 int ret = 0;
258 g_func = func;
259 WMT_DETECT_INFO_FUNC("autok function detected, func:0x%p\n", g_func);
260
261 sdio_claim_host(func);
262 ret = sdio_enable_func(func);
263 sdio_release_host(func);
264 if (ret) {
265 WMT_DETECT_ERR_FUNC("sdio_enable_func failed!\n");
266 }
267 }
268
269 return 0;
270 }
271
272
273 static void sdio_detect_remove (
274 struct sdio_func *func
275 )
276 {
277 if (g_func == func)
278 {
279 sdio_claim_host(func);
280 sdio_disable_func(func);
281 sdio_release_host(func);
282 g_func = NULL;
283 }
284 WMT_DETECT_INFO_FUNC("do sdio remove\n");
285 return ;
286 }
287
288
289
290 int sdio_detect_init(void)
291 {
292 int ret = -1;
293 //register to mmc driver
294 ret = sdio_register_driver(&mtk_sdio_client_drv);
295 WMT_DETECT_INFO_FUNC("sdio_register_driver() ret=%d\n", ret);
296 return 0;
297 }
298
299
300 int sdio_detect_exit(void)
301 {
302 g_func = NULL;
303 //register to mmc driver
304 sdio_unregister_driver(&mtk_sdio_client_drv);
305 WMT_DETECT_INFO_FUNC("sdio_unregister_driver\n");
306 return 0;
307 }
308