aboutsummaryrefslogtreecommitdiff
path: root/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.c
blob: 7ac5ac73ef5d8c3be8c6f953223d917c922e8b1e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/*
* Copyright (C) 2011-2014 MediaTek Inc.
*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/

#ifdef DFT_TAG
#undef DFT_TAG
#endif
#define DFT_TAG         "[SDIO-DETECT]"

#include "wmt_detect.h"

#if MTK_HIF_SDIO_AUTOK_ENABLED
#include <mt_boot.h>
#endif

unsigned int gComboChipId = -1;
struct sdio_func *g_func = NULL;

MTK_WCN_HIF_SDIO_CHIP_INFO gChipInfoArray[] = {
	/* MT6620 *//* Not an SDIO standard class device */
	{{SDIO_DEVICE(0x037A, 0x020A)}, 0x6620},	/* SDIO1:FUNC1:WIFI */
	{{SDIO_DEVICE(0x037A, 0x020B)}, 0x6620},	/* SDIO2:FUNC1:BT+FM+GPS */
	{{SDIO_DEVICE(0x037A, 0x020C)}, 0x6620},	/* 2-function (SDIO2:FUNC1:BT+FM+GPS, FUNC2:WIFI) */

	/* MT6628 *//* SDIO1: Wi-Fi, SDIO2: BGF */
	{{SDIO_DEVICE(0x037A, 0x6628)}, 0x6628},

	/* MT6630 *//* SDIO1: Wi-Fi, SDIO2: BGF */
	{{SDIO_DEVICE(0x037A, 0x6630)}, 0x6630},

};

/* Supported SDIO device table */
static const struct sdio_device_id mtk_sdio_id_tbl[] = {
	/* MT6618 *//* Not an SDIO standard class device */
	{SDIO_DEVICE(0x037A, 0x018A)},	/* SDIO1:WIFI */
	{SDIO_DEVICE(0x037A, 0x018B)},	/* SDIO2:FUNC1:BT+FM */
	{SDIO_DEVICE(0x037A, 0x018C)},	/* 2-function (SDIO2:FUNC1:BT+FM, FUNC2:WIFI) */

	/* MT6619 *//* Not an SDIO standard class device */
	{SDIO_DEVICE(0x037A, 0x6619)},	/* SDIO2:FUNC1:BT+FM+GPS */

	/* MT6620 *//* Not an SDIO standard class device */
	{SDIO_DEVICE(0x037A, 0x020A)},	/* SDIO1:FUNC1:WIFI */
	{SDIO_DEVICE(0x037A, 0x020B)},	/* SDIO2:FUNC1:BT+FM+GPS */
	{SDIO_DEVICE(0x037A, 0x020C)},	/* 2-function (SDIO2:FUNC1:BT+FM+GPS, FUNC2:WIFI) */

	/* MT5921 *//* Not an SDIO standard class device */
	{SDIO_DEVICE(0x037A, 0x5921)},

	/* MT6628 *//* SDIO1: Wi-Fi, SDIO2: BGF */
	{SDIO_DEVICE(0x037A, 0x6628)},

	/* MT6630 *//* SDIO1: Wi-Fi, SDIO2: BGF */
	{SDIO_DEVICE(0x037A, 0x6630)},
	{ /* end: all zeroes */ },
};

static int sdio_detect_probe(struct sdio_func *func, const struct sdio_device_id *id);

static void sdio_detect_remove(struct sdio_func *func);

static struct sdio_driver mtk_sdio_client_drv = {
	.name = "mtk_sdio_client",	/* MTK SDIO Client Driver */
	.id_table = mtk_sdio_id_tbl,	/* all supported struct sdio_device_id table */
	.probe = sdio_detect_probe,
	.remove = sdio_detect_remove,
};

static int hif_sdio_match_chipid_by_dev_id(const struct sdio_device_id *id);

int hif_sdio_is_chipid_valid(int chipId)
{
	int index = -1;

	int left = 0;
	int middle = 0;
	int right = sizeof(gChipInfoArray) / sizeof(gChipInfoArray[0]) - 1;

	if ((chipId < gChipInfoArray[left].chipId) || (chipId > gChipInfoArray[right].chipId))
		return index;

	middle = (left + right) / 2;

	while (left <= right) {
		if (chipId > gChipInfoArray[middle].chipId) {
			left = middle + 1;
		} else if (chipId < gChipInfoArray[middle].chipId) {
			right = middle - 1;
		} else {
			index = middle;
			break;
		}
		middle = (left + right) / 2;
	}

	if (0 > index)
		WMT_DETECT_ERR_FUNC("no supported chipid found\n");
	else
		WMT_DETECT_INFO_FUNC("index:%d, chipId:0x%x\n", index, gChipInfoArray[index].chipId);

	return index;
}

int hif_sdio_match_chipid_by_dev_id(const struct sdio_device_id *id)
{
	int maxIndex = sizeof(gChipInfoArray) / sizeof(gChipInfoArray[0]);
	int index = 0;
	struct sdio_device_id *localId = NULL;
	int chipId = -1;

	for (index = 0; index < maxIndex; index++) {
		localId = &(gChipInfoArray[index].deviceId);
		if ((localId->vendor == id->vendor) && (localId->device == id->device)) {
			chipId = gChipInfoArray[index].chipId;
			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);
			gComboChipId = chipId;
			mtk_wcn_wmt_set_chipid(gComboChipId);
			break;
		}
	}
	if (0 > chipId) {
		WMT_DETECT_ERR_FUNC("No valid chipId found, vendor id(0x%x), device id(0x%x)\n", id->vendor,
				    id->device);
	}

	return chipId;
}

int sdio_detect_query_chipid(int waitFlag)
{
	unsigned int timeSlotMs = 200;
	unsigned int maxTimeSlot = 15;
	unsigned int counter = 0;
	/* gComboChipId = 0x6628; */
	if (0 == waitFlag)
		return gComboChipId;
	if (0 <= hif_sdio_is_chipid_valid(gComboChipId))
		return gComboChipId;

	while (counter < maxTimeSlot) {
		if (0 <= hif_sdio_is_chipid_valid(gComboChipId))
			break;
		msleep(timeSlotMs);
		counter++;
	}

	return gComboChipId;
}

int sdio_detect_do_autok(int chipId)
{
	int i_ret = 0;

#if MTK_HIF_SDIO_AUTOK_ENABLED
#if 0
	BOOTMODE boot_mode;

	boot_mode = get_boot_mode();

	if (boot_mode == META_BOOT) {
		WMT_DETECT_INFO_FUNC("omit autok in meta mode\n");
		return 0;
	}
#endif
	if (0x6630 == chipId) {
#ifdef CONFIG_SDIOAUTOK_SUPPORT
		if (NULL != g_func) {
			WMT_DETECT_INFO_FUNC("wait_sdio_autok_ready++\n");
			i_ret = wait_sdio_autok_ready(g_func->card->host);
			WMT_DETECT_INFO_FUNC("wait_sdio_autok_ready--\n");
			if (0 == i_ret) {
				WMT_DETECT_INFO_FUNC("wait_sdio_autok_ready return success\n");
			} else {
				WMT_DETECT_INFO_FUNC("wait_sdio_autok_ready return fail, i_ret:%d\n", i_ret);
				gComboChipId = -1;
			}
		} else {
			WMT_DETECT_INFO_FUNC("g_func NULL, omit autok\n");
		}
#else
		i_ret = 0;
		WMT_DETECT_INFO_FUNC("MTK_SDIOAUTOK_SUPPORT not defined\n");
#endif
	} else {
		WMT_DETECT_INFO_FUNC("MT%x does not support SDIO3.0 autoK is not needed\n", chipId);
	}
#else
	i_ret = 0;
	WMT_DETECT_INFO_FUNC("MTK_HIF_SDIO_AUTOK_ENABLED is not defined\n");
#endif
	return i_ret;
}

/*!
 * \brief hif_sdio probe function
 *
 * hif_sdio probe function called by mmc driver when any matched SDIO function
 * is detected by it.
 *
 * \param func
 * \param id
 *
 * \retval 0    register successfully
 * \retval < 0  list error code here
 */
static int sdio_detect_probe(struct sdio_func *func, const struct sdio_device_id *id)
{
	int chipId = 0;

	WMT_DETECT_INFO_FUNC("vendor(0x%x) device(0x%x) num(0x%x)\n", func->vendor, func->device, func->num);
	chipId = hif_sdio_match_chipid_by_dev_id(id);

	if ((0x6630 == chipId) && (1 == func->num)) {
		int ret = 0;

		g_func = func;
		WMT_DETECT_INFO_FUNC("autok function detected, func:0x%p\n", g_func);

		sdio_claim_host(func);
		ret = sdio_enable_func(func);
		sdio_release_host(func);
		if (ret)
			WMT_DETECT_ERR_FUNC("sdio_enable_func failed!\n");
	}

	return 0;
}

static void sdio_detect_remove(struct sdio_func *func)
{
	if (g_func == func) {
		sdio_claim_host(func);
		sdio_disable_func(func);
		sdio_release_host(func);
		g_func = NULL;
	}
	WMT_DETECT_INFO_FUNC("do sdio remove\n");
}

int sdio_detect_init(void)
{
	int ret = -1;
	/* register to mmc driver */
	ret = sdio_register_driver(&mtk_sdio_client_drv);
	WMT_DETECT_INFO_FUNC("sdio_register_driver() ret=%d\n", ret);
	return 0;
}

int sdio_detect_exit(void)
{
	g_func = NULL;
	/* register to mmc driver */
	sdio_unregister_driver(&mtk_sdio_client_drv);
	WMT_DETECT_INFO_FUNC("sdio_unregister_driver\n");
	return 0;
}