diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1271_spi.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_spi.c | 315 |
1 files changed, 260 insertions, 55 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c index 053c84aceb49..5189b812f939 100644 --- a/drivers/net/wireless/wl12xx/wl1271_spi.c +++ b/drivers/net/wireless/wl12xx/wl1271_spi.c | |||
@@ -21,18 +21,69 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/irq.h> | ||
24 | #include <linux/module.h> | 25 | #include <linux/module.h> |
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/crc7.h> | 26 | #include <linux/crc7.h> |
27 | #include <linux/spi/spi.h> | 27 | #include <linux/spi/spi.h> |
28 | #include <linux/spi/wl12xx.h> | ||
28 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
29 | 30 | ||
30 | #include "wl1271.h" | 31 | #include "wl1271.h" |
31 | #include "wl12xx_80211.h" | 32 | #include "wl12xx_80211.h" |
32 | #include "wl1271_spi.h" | 33 | #include "wl1271_io.h" |
34 | |||
35 | #include "wl1271_reg.h" | ||
36 | |||
37 | #define WSPI_CMD_READ 0x40000000 | ||
38 | #define WSPI_CMD_WRITE 0x00000000 | ||
39 | #define WSPI_CMD_FIXED 0x20000000 | ||
40 | #define WSPI_CMD_BYTE_LENGTH 0x1FFE0000 | ||
41 | #define WSPI_CMD_BYTE_LENGTH_OFFSET 17 | ||
42 | #define WSPI_CMD_BYTE_ADDR 0x0001FFFF | ||
43 | |||
44 | #define WSPI_INIT_CMD_CRC_LEN 5 | ||
45 | |||
46 | #define WSPI_INIT_CMD_START 0x00 | ||
47 | #define WSPI_INIT_CMD_TX 0x40 | ||
48 | /* the extra bypass bit is sampled by the TNET as '1' */ | ||
49 | #define WSPI_INIT_CMD_BYPASS_BIT 0x80 | ||
50 | #define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07 | ||
51 | #define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80 | ||
52 | #define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00 | ||
53 | #define WSPI_INIT_CMD_IOD 0x40 | ||
54 | #define WSPI_INIT_CMD_IP 0x20 | ||
55 | #define WSPI_INIT_CMD_CS 0x10 | ||
56 | #define WSPI_INIT_CMD_WS 0x08 | ||
57 | #define WSPI_INIT_CMD_WSPI 0x01 | ||
58 | #define WSPI_INIT_CMD_END 0x01 | ||
59 | |||
60 | #define WSPI_INIT_CMD_LEN 8 | ||
61 | |||
62 | #define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ | ||
63 | ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32)) | ||
64 | #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 | ||
65 | |||
66 | static inline struct spi_device *wl_to_spi(struct wl1271 *wl) | ||
67 | { | ||
68 | return wl->if_priv; | ||
69 | } | ||
33 | 70 | ||
71 | static struct device *wl1271_spi_wl_to_dev(struct wl1271 *wl) | ||
72 | { | ||
73 | return &(wl_to_spi(wl)->dev); | ||
74 | } | ||
34 | 75 | ||
35 | void wl1271_spi_reset(struct wl1271 *wl) | 76 | static void wl1271_spi_disable_interrupts(struct wl1271 *wl) |
77 | { | ||
78 | disable_irq(wl->irq); | ||
79 | } | ||
80 | |||
81 | static void wl1271_spi_enable_interrupts(struct wl1271 *wl) | ||
82 | { | ||
83 | enable_irq(wl->irq); | ||
84 | } | ||
85 | |||
86 | static void wl1271_spi_reset(struct wl1271 *wl) | ||
36 | { | 87 | { |
37 | u8 *cmd; | 88 | u8 *cmd; |
38 | struct spi_transfer t; | 89 | struct spi_transfer t; |
@@ -53,12 +104,13 @@ void wl1271_spi_reset(struct wl1271 *wl) | |||
53 | t.len = WSPI_INIT_CMD_LEN; | 104 | t.len = WSPI_INIT_CMD_LEN; |
54 | spi_message_add_tail(&t, &m); | 105 | spi_message_add_tail(&t, &m); |
55 | 106 | ||
56 | spi_sync(wl->spi, &m); | 107 | spi_sync(wl_to_spi(wl), &m); |
108 | kfree(cmd); | ||
57 | 109 | ||
58 | wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); | 110 | wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); |
59 | } | 111 | } |
60 | 112 | ||
61 | void wl1271_spi_init(struct wl1271 *wl) | 113 | static void wl1271_spi_init(struct wl1271 *wl) |
62 | { | 114 | { |
63 | u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; | 115 | u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; |
64 | struct spi_transfer t; | 116 | struct spi_transfer t; |
@@ -107,48 +159,25 @@ void wl1271_spi_init(struct wl1271 *wl) | |||
107 | t.len = WSPI_INIT_CMD_LEN; | 159 | t.len = WSPI_INIT_CMD_LEN; |
108 | spi_message_add_tail(&t, &m); | 160 | spi_message_add_tail(&t, &m); |
109 | 161 | ||
110 | spi_sync(wl->spi, &m); | 162 | spi_sync(wl_to_spi(wl), &m); |
163 | kfree(cmd); | ||
111 | 164 | ||
112 | wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); | 165 | wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); |
113 | } | 166 | } |
114 | 167 | ||
115 | #define WL1271_BUSY_WORD_TIMEOUT 1000 | 168 | #define WL1271_BUSY_WORD_TIMEOUT 1000 |
116 | 169 | ||
117 | /* FIXME: Check busy words, removed due to SPI bug */ | 170 | static int wl1271_spi_read_busy(struct wl1271 *wl) |
118 | #if 0 | ||
119 | static void wl1271_spi_read_busy(struct wl1271 *wl, void *buf, size_t len) | ||
120 | { | 171 | { |
121 | struct spi_transfer t[1]; | 172 | struct spi_transfer t[1]; |
122 | struct spi_message m; | 173 | struct spi_message m; |
123 | u32 *busy_buf; | 174 | u32 *busy_buf; |
124 | int num_busy_bytes = 0; | 175 | int num_busy_bytes = 0; |
125 | 176 | ||
126 | wl1271_info("spi read BUSY!"); | ||
127 | |||
128 | /* | ||
129 | * Look for the non-busy word in the read buffer, and if found, | ||
130 | * read in the remaining data into the buffer. | ||
131 | */ | ||
132 | busy_buf = (u32 *)buf; | ||
133 | for (; (u32)busy_buf < (u32)buf + len; busy_buf++) { | ||
134 | num_busy_bytes += sizeof(u32); | ||
135 | if (*busy_buf & 0x1) { | ||
136 | spi_message_init(&m); | ||
137 | memset(t, 0, sizeof(t)); | ||
138 | memmove(buf, busy_buf, len - num_busy_bytes); | ||
139 | t[0].rx_buf = buf + (len - num_busy_bytes); | ||
140 | t[0].len = num_busy_bytes; | ||
141 | spi_message_add_tail(&t[0], &m); | ||
142 | spi_sync(wl->spi, &m); | ||
143 | return; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | /* | 177 | /* |
148 | * Read further busy words from SPI until a non-busy word is | 178 | * Read further busy words from SPI until a non-busy word is |
149 | * encountered, then read the data itself into the buffer. | 179 | * encountered, then read the data itself into the buffer. |
150 | */ | 180 | */ |
151 | wl1271_info("spi read BUSY-polling needed!"); | ||
152 | 181 | ||
153 | num_busy_bytes = WL1271_BUSY_WORD_TIMEOUT; | 182 | num_busy_bytes = WL1271_BUSY_WORD_TIMEOUT; |
154 | busy_buf = wl->buffer_busyword; | 183 | busy_buf = wl->buffer_busyword; |
@@ -158,28 +187,21 @@ static void wl1271_spi_read_busy(struct wl1271 *wl, void *buf, size_t len) | |||
158 | memset(t, 0, sizeof(t)); | 187 | memset(t, 0, sizeof(t)); |
159 | t[0].rx_buf = busy_buf; | 188 | t[0].rx_buf = busy_buf; |
160 | t[0].len = sizeof(u32); | 189 | t[0].len = sizeof(u32); |
190 | t[0].cs_change = true; | ||
161 | spi_message_add_tail(&t[0], &m); | 191 | spi_message_add_tail(&t[0], &m); |
162 | spi_sync(wl->spi, &m); | 192 | spi_sync(wl_to_spi(wl), &m); |
163 | 193 | ||
164 | if (*busy_buf & 0x1) { | 194 | if (*busy_buf & 0x1) |
165 | spi_message_init(&m); | 195 | return 0; |
166 | memset(t, 0, sizeof(t)); | ||
167 | t[0].rx_buf = buf; | ||
168 | t[0].len = len; | ||
169 | spi_message_add_tail(&t[0], &m); | ||
170 | spi_sync(wl->spi, &m); | ||
171 | return; | ||
172 | } | ||
173 | } | 196 | } |
174 | 197 | ||
175 | /* The SPI bus is unresponsive, the read failed. */ | 198 | /* The SPI bus is unresponsive, the read failed. */ |
176 | memset(buf, 0, len); | ||
177 | wl1271_error("SPI read busy-word timeout!\n"); | 199 | wl1271_error("SPI read busy-word timeout!\n"); |
200 | return -ETIMEDOUT; | ||
178 | } | 201 | } |
179 | #endif | ||
180 | 202 | ||
181 | void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, | 203 | static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, |
182 | size_t len, bool fixed) | 204 | size_t len, bool fixed) |
183 | { | 205 | { |
184 | struct spi_transfer t[3]; | 206 | struct spi_transfer t[3]; |
185 | struct spi_message m; | 207 | struct spi_message m; |
@@ -202,28 +224,38 @@ void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, | |||
202 | 224 | ||
203 | t[0].tx_buf = cmd; | 225 | t[0].tx_buf = cmd; |
204 | t[0].len = 4; | 226 | t[0].len = 4; |
227 | t[0].cs_change = true; | ||
205 | spi_message_add_tail(&t[0], &m); | 228 | spi_message_add_tail(&t[0], &m); |
206 | 229 | ||
207 | /* Busy and non busy words read */ | 230 | /* Busy and non busy words read */ |
208 | t[1].rx_buf = busy_buf; | 231 | t[1].rx_buf = busy_buf; |
209 | t[1].len = WL1271_BUSY_WORD_LEN; | 232 | t[1].len = WL1271_BUSY_WORD_LEN; |
233 | t[1].cs_change = true; | ||
210 | spi_message_add_tail(&t[1], &m); | 234 | spi_message_add_tail(&t[1], &m); |
211 | 235 | ||
212 | t[2].rx_buf = buf; | 236 | spi_sync(wl_to_spi(wl), &m); |
213 | t[2].len = len; | ||
214 | spi_message_add_tail(&t[2], &m); | ||
215 | 237 | ||
216 | spi_sync(wl->spi, &m); | 238 | if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) && |
239 | wl1271_spi_read_busy(wl)) { | ||
240 | memset(buf, 0, len); | ||
241 | return; | ||
242 | } | ||
217 | 243 | ||
218 | /* FIXME: Check busy words, removed due to SPI bug */ | 244 | spi_message_init(&m); |
219 | /* if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1)) | 245 | memset(t, 0, sizeof(t)); |
220 | wl1271_spi_read_busy(wl, buf, len); */ | 246 | |
247 | t[0].rx_buf = buf; | ||
248 | t[0].len = len; | ||
249 | t[0].cs_change = true; | ||
250 | spi_message_add_tail(&t[0], &m); | ||
251 | |||
252 | spi_sync(wl_to_spi(wl), &m); | ||
221 | 253 | ||
222 | wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); | 254 | wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); |
223 | wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); | 255 | wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); |
224 | } | 256 | } |
225 | 257 | ||
226 | void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, | 258 | static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, |
227 | size_t len, bool fixed) | 259 | size_t len, bool fixed) |
228 | { | 260 | { |
229 | struct spi_transfer t[2]; | 261 | struct spi_transfer t[2]; |
@@ -251,8 +283,181 @@ void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, | |||
251 | t[1].len = len; | 283 | t[1].len = len; |
252 | spi_message_add_tail(&t[1], &m); | 284 | spi_message_add_tail(&t[1], &m); |
253 | 285 | ||
254 | spi_sync(wl->spi, &m); | 286 | spi_sync(wl_to_spi(wl), &m); |
255 | 287 | ||
256 | wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); | 288 | wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); |
257 | wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); | 289 | wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); |
258 | } | 290 | } |
291 | |||
292 | static irqreturn_t wl1271_irq(int irq, void *cookie) | ||
293 | { | ||
294 | struct wl1271 *wl; | ||
295 | unsigned long flags; | ||
296 | |||
297 | wl1271_debug(DEBUG_IRQ, "IRQ"); | ||
298 | |||
299 | wl = cookie; | ||
300 | |||
301 | /* complete the ELP completion */ | ||
302 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
303 | if (wl->elp_compl) { | ||
304 | complete(wl->elp_compl); | ||
305 | wl->elp_compl = NULL; | ||
306 | } | ||
307 | |||
308 | if (!test_and_set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags)) | ||
309 | ieee80211_queue_work(wl->hw, &wl->irq_work); | ||
310 | set_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags); | ||
311 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
312 | |||
313 | return IRQ_HANDLED; | ||
314 | } | ||
315 | |||
316 | static void wl1271_spi_set_power(struct wl1271 *wl, bool enable) | ||
317 | { | ||
318 | if (wl->set_power) | ||
319 | wl->set_power(enable); | ||
320 | } | ||
321 | |||
322 | static struct wl1271_if_operations spi_ops = { | ||
323 | .read = wl1271_spi_raw_read, | ||
324 | .write = wl1271_spi_raw_write, | ||
325 | .reset = wl1271_spi_reset, | ||
326 | .init = wl1271_spi_init, | ||
327 | .power = wl1271_spi_set_power, | ||
328 | .dev = wl1271_spi_wl_to_dev, | ||
329 | .enable_irq = wl1271_spi_enable_interrupts, | ||
330 | .disable_irq = wl1271_spi_disable_interrupts | ||
331 | }; | ||
332 | |||
333 | static int __devinit wl1271_probe(struct spi_device *spi) | ||
334 | { | ||
335 | struct wl12xx_platform_data *pdata; | ||
336 | struct ieee80211_hw *hw; | ||
337 | struct wl1271 *wl; | ||
338 | int ret; | ||
339 | |||
340 | pdata = spi->dev.platform_data; | ||
341 | if (!pdata) { | ||
342 | wl1271_error("no platform data"); | ||
343 | return -ENODEV; | ||
344 | } | ||
345 | |||
346 | hw = wl1271_alloc_hw(); | ||
347 | if (IS_ERR(hw)) | ||
348 | return PTR_ERR(hw); | ||
349 | |||
350 | wl = hw->priv; | ||
351 | |||
352 | dev_set_drvdata(&spi->dev, wl); | ||
353 | wl->if_priv = spi; | ||
354 | |||
355 | wl->if_ops = &spi_ops; | ||
356 | |||
357 | /* This is the only SPI value that we need to set here, the rest | ||
358 | * comes from the board-peripherals file */ | ||
359 | spi->bits_per_word = 32; | ||
360 | |||
361 | ret = spi_setup(spi); | ||
362 | if (ret < 0) { | ||
363 | wl1271_error("spi_setup failed"); | ||
364 | goto out_free; | ||
365 | } | ||
366 | |||
367 | wl->set_power = pdata->set_power; | ||
368 | if (!wl->set_power) { | ||
369 | wl1271_error("set power function missing in platform data"); | ||
370 | ret = -ENODEV; | ||
371 | goto out_free; | ||
372 | } | ||
373 | |||
374 | wl->irq = spi->irq; | ||
375 | if (wl->irq < 0) { | ||
376 | wl1271_error("irq missing in platform data"); | ||
377 | ret = -ENODEV; | ||
378 | goto out_free; | ||
379 | } | ||
380 | |||
381 | ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl); | ||
382 | if (ret < 0) { | ||
383 | wl1271_error("request_irq() failed: %d", ret); | ||
384 | goto out_free; | ||
385 | } | ||
386 | |||
387 | set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); | ||
388 | |||
389 | disable_irq(wl->irq); | ||
390 | |||
391 | ret = wl1271_init_ieee80211(wl); | ||
392 | if (ret) | ||
393 | goto out_irq; | ||
394 | |||
395 | ret = wl1271_register_hw(wl); | ||
396 | if (ret) | ||
397 | goto out_irq; | ||
398 | |||
399 | wl1271_notice("initialized"); | ||
400 | |||
401 | return 0; | ||
402 | |||
403 | out_irq: | ||
404 | free_irq(wl->irq, wl); | ||
405 | |||
406 | out_free: | ||
407 | wl1271_free_hw(wl); | ||
408 | |||
409 | return ret; | ||
410 | } | ||
411 | |||
412 | static int __devexit wl1271_remove(struct spi_device *spi) | ||
413 | { | ||
414 | struct wl1271 *wl = dev_get_drvdata(&spi->dev); | ||
415 | |||
416 | free_irq(wl->irq, wl); | ||
417 | |||
418 | wl1271_unregister_hw(wl); | ||
419 | wl1271_free_hw(wl); | ||
420 | |||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | |||
425 | static struct spi_driver wl1271_spi_driver = { | ||
426 | .driver = { | ||
427 | .name = "wl1271_spi", | ||
428 | .bus = &spi_bus_type, | ||
429 | .owner = THIS_MODULE, | ||
430 | }, | ||
431 | |||
432 | .probe = wl1271_probe, | ||
433 | .remove = __devexit_p(wl1271_remove), | ||
434 | }; | ||
435 | |||
436 | static int __init wl1271_init(void) | ||
437 | { | ||
438 | int ret; | ||
439 | |||
440 | ret = spi_register_driver(&wl1271_spi_driver); | ||
441 | if (ret < 0) { | ||
442 | wl1271_error("failed to register spi driver: %d", ret); | ||
443 | goto out; | ||
444 | } | ||
445 | |||
446 | out: | ||
447 | return ret; | ||
448 | } | ||
449 | |||
450 | static void __exit wl1271_exit(void) | ||
451 | { | ||
452 | spi_unregister_driver(&wl1271_spi_driver); | ||
453 | |||
454 | wl1271_notice("unloaded"); | ||
455 | } | ||
456 | |||
457 | module_init(wl1271_init); | ||
458 | module_exit(wl1271_exit); | ||
459 | |||
460 | MODULE_LICENSE("GPL"); | ||
461 | MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>"); | ||
462 | MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); | ||
463 | MODULE_FIRMWARE(WL1271_FW_NAME); | ||