aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx/sdio_test.c
diff options
context:
space:
mode:
authorLuciano Coelho <luciano.coelho@nokia.com>2010-12-15 09:10:12 -0500
committerLuciano Coelho <luciano.coelho@nokia.com>2010-12-15 10:09:27 -0500
commit248daa084cee4b212ff4408e9c9b05b3bdc0da0d (patch)
treed525ac39d421a323ec7c8f42356e7844fbff1395 /drivers/net/wireless/wl12xx/sdio_test.c
parent6742f554db14da94172da9eb1875a1aa944a827f (diff)
wl12xx_sdio_test: rename files to match current style
Change some file names and Kconfig settings so that this new module matches the new way of using wl12xx instead of wl1271. Also fix SDIO power enabling and disabling to match the latest way of doing it. Cc: Roger Quadros <roger.quadros@nokia.com> Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
Diffstat (limited to 'drivers/net/wireless/wl12xx/sdio_test.c')
-rw-r--r--drivers/net/wireless/wl12xx/sdio_test.c520
1 files changed, 520 insertions, 0 deletions
diff --git a/drivers/net/wireless/wl12xx/sdio_test.c b/drivers/net/wireless/wl12xx/sdio_test.c
new file mode 100644
index 00000000000..9fcbd3dd849
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/sdio_test.c
@@ -0,0 +1,520 @@
1/*
2 * SDIO testing driver for wl12xx
3 *
4 * Copyright (C) 2010 Nokia Corporation
5 *
6 * Contact: Roger Quadros <roger.quadros@nokia.com>
7 *
8 * wl12xx read/write routines taken from the main module
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * version 2 as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA
23 *
24 */
25
26#include <linux/irq.h>
27#include <linux/module.h>
28#include <linux/crc7.h>
29#include <linux/vmalloc.h>
30#include <linux/mmc/sdio_func.h>
31#include <linux/mmc/sdio_ids.h>
32#include <linux/mmc/card.h>
33#include <linux/gpio.h>
34#include <linux/wl12xx.h>
35#include <linux/kthread.h>
36#include <linux/firmware.h>
37#include <linux/pm_runtime.h>
38
39#include "wl12xx.h"
40#include "io.h"
41#include "boot.h"
42
43#ifndef SDIO_VENDOR_ID_TI
44#define SDIO_VENDOR_ID_TI 0x0097
45#endif
46
47#ifndef SDIO_DEVICE_ID_TI_WL1271
48#define SDIO_DEVICE_ID_TI_WL1271 0x4076
49#endif
50
51static bool rx, tx;
52
53module_param(rx, bool, S_IRUGO | S_IWUSR);
54MODULE_PARM_DESC(rx, "Perform rx test. Default (0). "
55 "This test continuously reads data from the SDIO device.\n");
56
57module_param(tx, bool, S_IRUGO | S_IWUSR);
58MODULE_PARM_DESC(tx, "Perform tx test. Default (0). "
59 "This test continuously writes data to the SDIO device.\n");
60
61struct wl1271_test {
62 struct wl1271 wl;
63 struct task_struct *test_task;
64};
65
66static const struct sdio_device_id wl1271_devices[] = {
67 { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) },
68 {}
69};
70
71static inline struct sdio_func *wl_to_func(struct wl1271 *wl)
72{
73 return wl->if_priv;
74}
75
76static struct device *wl1271_sdio_wl_to_dev(struct wl1271 *wl)
77{
78 return &(wl_to_func(wl)->dev);
79}
80
81static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf,
82 size_t len, bool fixed)
83{
84 int ret = 0;
85 struct sdio_func *func = wl_to_func(wl);
86
87 if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
88 ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
89 wl1271_debug(DEBUG_SDIO, "sdio read 52 addr 0x%x, byte 0x%02x",
90 addr, ((u8 *)buf)[0]);
91 } else {
92 if (fixed)
93 ret = sdio_readsb(func, buf, addr, len);
94 else
95 ret = sdio_memcpy_fromio(func, buf, addr, len);
96
97 wl1271_debug(DEBUG_SDIO, "sdio read 53 addr 0x%x, %zu bytes",
98 addr, len);
99 wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len);
100 }
101
102 if (ret)
103 wl1271_error("sdio read failed (%d)", ret);
104}
105
106static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf,
107 size_t len, bool fixed)
108{
109 int ret = 0;
110 struct sdio_func *func = wl_to_func(wl);
111
112 if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
113 sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
114 wl1271_debug(DEBUG_SDIO, "sdio write 52 addr 0x%x, byte 0x%02x",
115 addr, ((u8 *)buf)[0]);
116 } else {
117 wl1271_debug(DEBUG_SDIO, "sdio write 53 addr 0x%x, %zu bytes",
118 addr, len);
119 wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len);
120
121 if (fixed)
122 ret = sdio_writesb(func, addr, buf, len);
123 else
124 ret = sdio_memcpy_toio(func, addr, buf, len);
125 }
126 if (ret)
127 wl1271_error("sdio write failed (%d)", ret);
128
129}
130
131static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable)
132{
133 struct sdio_func *func = wl_to_func(wl);
134 int ret;
135
136 /* Let the SDIO stack handle wlan_enable control, so we
137 * keep host claimed while wlan is in use to keep wl1271
138 * alive.
139 */
140 if (enable) {
141 /* Power up the card */
142 ret = pm_runtime_get_sync(&func->dev);
143 if (ret < 0)
144 goto out;
145 sdio_claim_host(func);
146 sdio_enable_func(func);
147 sdio_release_host(func);
148 } else {
149 sdio_claim_host(func);
150 sdio_disable_func(func);
151 sdio_release_host(func);
152
153 /* Power down the card */
154 ret = pm_runtime_put_sync(&func->dev);
155 }
156
157out:
158 return ret;
159}
160
161static void wl1271_sdio_disable_interrupts(struct wl1271 *wl)
162{
163}
164
165static void wl1271_sdio_enable_interrupts(struct wl1271 *wl)
166{
167}
168
169
170static struct wl1271_if_operations sdio_ops = {
171 .read = wl1271_sdio_raw_read,
172 .write = wl1271_sdio_raw_write,
173 .power = wl1271_sdio_set_power,
174 .dev = wl1271_sdio_wl_to_dev,
175 .enable_irq = wl1271_sdio_enable_interrupts,
176 .disable_irq = wl1271_sdio_disable_interrupts,
177};
178
179static void wl1271_fw_wakeup(struct wl1271 *wl)
180{
181 u32 elp_reg;
182
183 elp_reg = ELPCTRL_WAKE_UP;
184 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
185}
186
187static int wl1271_fetch_firmware(struct wl1271 *wl)
188{
189 const struct firmware *fw;
190 int ret;
191
192 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
193
194 if (ret < 0) {
195 wl1271_error("could not get firmware: %d", ret);
196 return ret;
197 }
198
199 if (fw->size % 4) {
200 wl1271_error("firmware size is not multiple of 32 bits: %zu",
201 fw->size);
202 ret = -EILSEQ;
203 goto out;
204 }
205
206 wl->fw_len = fw->size;
207 wl->fw = vmalloc(wl->fw_len);
208
209 if (!wl->fw) {
210 wl1271_error("could not allocate memory for the firmware");
211 ret = -ENOMEM;
212 goto out;
213 }
214
215 memcpy(wl->fw, fw->data, wl->fw_len);
216
217 ret = 0;
218
219out:
220 release_firmware(fw);
221
222 return ret;
223}
224
225static int wl1271_fetch_nvs(struct wl1271 *wl)
226{
227 const struct firmware *fw;
228 int ret;
229
230 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
231
232 if (ret < 0) {
233 wl1271_error("could not get nvs file: %d", ret);
234 return ret;
235 }
236
237 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
238
239 if (!wl->nvs) {
240 wl1271_error("could not allocate memory for the nvs file");
241 ret = -ENOMEM;
242 goto out;
243 }
244
245 wl->nvs_len = fw->size;
246
247out:
248 release_firmware(fw);
249
250 return ret;
251}
252
253static int wl1271_chip_wakeup(struct wl1271 *wl)
254{
255 struct wl1271_partition_set partition;
256 int ret;
257
258 msleep(WL1271_PRE_POWER_ON_SLEEP);
259 ret = wl1271_power_on(wl);
260 if (ret)
261 return ret;
262
263 msleep(WL1271_POWER_ON_SLEEP);
264
265 /* We don't need a real memory partition here, because we only want
266 * to use the registers at this point. */
267 memset(&partition, 0, sizeof(partition));
268 partition.reg.start = REGISTERS_BASE;
269 partition.reg.size = REGISTERS_DOWN_SIZE;
270 wl1271_set_partition(wl, &partition);
271
272 /* ELP module wake up */
273 wl1271_fw_wakeup(wl);
274
275 /* whal_FwCtrl_BootSm() */
276
277 /* 0. read chip id from CHIP_ID */
278 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
279
280 /* 1. check if chip id is valid */
281
282 switch (wl->chip.id) {
283 case CHIP_ID_1271_PG10:
284 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
285 wl->chip.id);
286 break;
287 case CHIP_ID_1271_PG20:
288 wl1271_notice("chip id 0x%x (1271 PG20)",
289 wl->chip.id);
290 break;
291 default:
292 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
293 return -ENODEV;
294 }
295
296 return ret;
297}
298
299static struct wl1271_partition_set part_down = {
300 .mem = {
301 .start = 0x00000000,
302 .size = 0x000177c0
303 },
304 .reg = {
305 .start = REGISTERS_BASE,
306 .size = 0x00008800
307 },
308 .mem2 = {
309 .start = 0x00000000,
310 .size = 0x00000000
311 },
312 .mem3 = {
313 .start = 0x00000000,
314 .size = 0x00000000
315 },
316};
317
318static int tester(void *data)
319{
320 struct wl1271 *wl = data;
321 struct sdio_func *func = wl_to_func(wl);
322 struct device *pdev = &func->dev;
323 int ret = 0;
324 bool rx_started = 0;
325 bool tx_started = 0;
326 uint8_t *tx_buf, *rx_buf;
327 int test_size = PAGE_SIZE;
328 u32 addr = 0;
329 struct wl1271_partition_set partition;
330
331 /* We assume chip is powered up and firmware fetched */
332
333 memcpy(&partition, &part_down, sizeof(partition));
334 partition.mem.start = addr;
335 wl1271_set_partition(wl, &partition);
336
337 tx_buf = kmalloc(test_size, GFP_KERNEL);
338 rx_buf = kmalloc(test_size, GFP_KERNEL);
339 if (!tx_buf || !rx_buf) {
340 dev_err(pdev,
341 "Could not allocate memory. Test will not run.\n");
342 ret = -ENOMEM;
343 goto free;
344 }
345
346 memset(tx_buf, 0x5a, test_size);
347
348 /* write something in data area so we can read it back */
349 wl1271_write(wl, addr, tx_buf, test_size, false);
350
351 while (!kthread_should_stop()) {
352 if (rx && !rx_started) {
353 dev_info(pdev, "starting rx test\n");
354 rx_started = 1;
355 } else if (!rx && rx_started) {
356 dev_info(pdev, "stopping rx test\n");
357 rx_started = 0;
358 }
359
360 if (tx && !tx_started) {
361 dev_info(pdev, "starting tx test\n");
362 tx_started = 1;
363 } else if (!tx && tx_started) {
364 dev_info(pdev, "stopping tx test\n");
365 tx_started = 0;
366 }
367
368 if (rx_started)
369 wl1271_read(wl, addr, rx_buf, test_size, false);
370
371 if (tx_started)
372 wl1271_write(wl, addr, tx_buf, test_size, false);
373
374 if (!rx_started && !tx_started)
375 msleep(100);
376 }
377
378free:
379 kfree(tx_buf);
380 kfree(rx_buf);
381 return ret;
382}
383
384static int __devinit wl1271_probe(struct sdio_func *func,
385 const struct sdio_device_id *id)
386{
387 const struct wl12xx_platform_data *wlan_data;
388 struct wl1271 *wl;
389 struct wl1271_test *wl_test;
390 int ret = 0;
391
392 /* wl1271 has 2 sdio functions we handle just the wlan part */
393 if (func->num != 0x02)
394 return -ENODEV;
395
396 wl_test = kzalloc(sizeof(struct wl1271_test), GFP_KERNEL);
397 if (!wl_test) {
398 dev_err(&func->dev, "Could not allocate memory\n");
399 return -ENOMEM;
400 }
401
402 wl = &wl_test->wl;
403
404 wl->if_priv = func;
405 wl->if_ops = &sdio_ops;
406
407 /* Grab access to FN0 for ELP reg. */
408 func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
409
410 wlan_data = wl12xx_get_platform_data();
411 if (IS_ERR(wlan_data)) {
412 ret = PTR_ERR(wlan_data);
413 dev_err(&func->dev, "missing wlan platform data: %d\n", ret);
414 goto out_free;
415 }
416
417 wl->irq = wlan_data->irq;
418 wl->ref_clock = wlan_data->board_ref_clock;
419
420 sdio_set_drvdata(func, wl_test);
421
422
423 /* power up the device */
424 ret = wl1271_chip_wakeup(wl);
425 if (ret) {
426 dev_err(&func->dev, "could not wake up chip\n");
427 goto out_free;
428 }
429
430 if (wl->fw == NULL) {
431 ret = wl1271_fetch_firmware(wl);
432 if (ret < 0) {
433 dev_err(&func->dev, "firmware fetch error\n");
434 goto out_off;
435 }
436 }
437
438 /* fetch NVS */
439 if (wl->nvs == NULL) {
440 ret = wl1271_fetch_nvs(wl);
441 if (ret < 0) {
442 dev_err(&func->dev, "NVS fetch error\n");
443 goto out_off;
444 }
445 }
446
447 ret = wl1271_load_firmware(wl);
448 if (ret < 0) {
449 dev_err(&func->dev, "firmware load error: %d\n", ret);
450 goto out_free;
451 }
452
453 dev_info(&func->dev, "initialized\n");
454
455 /* I/O testing will be done in the tester thread */
456
457 wl_test->test_task = kthread_run(tester, wl, "sdio_tester");
458 if (IS_ERR(wl_test->test_task)) {
459 dev_err(&func->dev, "unable to create kernel thread\n");
460 ret = PTR_ERR(wl_test->test_task);
461 goto out_free;
462 }
463
464 return 0;
465
466out_off:
467 /* power off the chip */
468 wl1271_power_off(wl);
469
470out_free:
471 kfree(wl_test);
472 return ret;
473}
474
475static void __devexit wl1271_remove(struct sdio_func *func)
476{
477 struct wl1271_test *wl_test = sdio_get_drvdata(func);
478
479 /* stop the I/O test thread */
480 kthread_stop(wl_test->test_task);
481
482 /* power off the chip */
483 wl1271_power_off(&wl_test->wl);
484
485 vfree(wl_test->wl.fw);
486 wl_test->wl.fw = NULL;
487 kfree(wl_test->wl.nvs);
488 wl_test->wl.nvs = NULL;
489
490 kfree(wl_test);
491}
492
493static struct sdio_driver wl1271_sdio_driver = {
494 .name = "wl12xx_sdio_test",
495 .id_table = wl1271_devices,
496 .probe = wl1271_probe,
497 .remove = __devexit_p(wl1271_remove),
498};
499
500static int __init wl1271_init(void)
501{
502 int ret;
503
504 ret = sdio_register_driver(&wl1271_sdio_driver);
505 if (ret < 0)
506 pr_err("failed to register sdio driver: %d\n", ret);
507
508 return ret;
509}
510module_init(wl1271_init);
511
512static void __exit wl1271_exit(void)
513{
514 sdio_unregister_driver(&wl1271_sdio_driver);
515}
516module_exit(wl1271_exit);
517
518MODULE_LICENSE("GPL");
519MODULE_AUTHOR("Roger Quadros <roger.quadros@nokia.com>");
520