diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/spi.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/spi.c | 215 |
1 files changed, 81 insertions, 134 deletions
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index 0f9718677860..92caa7ce6053 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/crc7.h> | 27 | #include <linux/crc7.h> |
28 | #include <linux/spi/spi.h> | 28 | #include <linux/spi/spi.h> |
29 | #include <linux/wl12xx.h> | 29 | #include <linux/wl12xx.h> |
30 | #include <linux/platform_device.h> | ||
30 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
31 | 32 | ||
32 | #include "wl12xx.h" | 33 | #include "wl12xx.h" |
@@ -69,35 +70,22 @@ | |||
69 | 70 | ||
70 | #define WSPI_MAX_NUM_OF_CHUNKS (WL1271_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) | 71 | #define WSPI_MAX_NUM_OF_CHUNKS (WL1271_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) |
71 | 72 | ||
72 | static inline struct spi_device *wl_to_spi(struct wl1271 *wl) | 73 | struct wl12xx_spi_glue { |
73 | { | 74 | struct device *dev; |
74 | return wl->if_priv; | 75 | struct platform_device *core; |
75 | } | 76 | }; |
76 | |||
77 | static struct device *wl1271_spi_wl_to_dev(struct wl1271 *wl) | ||
78 | { | ||
79 | return &(wl_to_spi(wl)->dev); | ||
80 | } | ||
81 | |||
82 | static void wl1271_spi_disable_interrupts(struct wl1271 *wl) | ||
83 | { | ||
84 | disable_irq(wl->irq); | ||
85 | } | ||
86 | |||
87 | static void wl1271_spi_enable_interrupts(struct wl1271 *wl) | ||
88 | { | ||
89 | enable_irq(wl->irq); | ||
90 | } | ||
91 | 77 | ||
92 | static void wl1271_spi_reset(struct wl1271 *wl) | 78 | static void wl12xx_spi_reset(struct device *child) |
93 | { | 79 | { |
80 | struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); | ||
94 | u8 *cmd; | 81 | u8 *cmd; |
95 | struct spi_transfer t; | 82 | struct spi_transfer t; |
96 | struct spi_message m; | 83 | struct spi_message m; |
97 | 84 | ||
98 | cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); | 85 | cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); |
99 | if (!cmd) { | 86 | if (!cmd) { |
100 | wl1271_error("could not allocate cmd for spi reset"); | 87 | dev_err(child->parent, |
88 | "could not allocate cmd for spi reset\n"); | ||
101 | return; | 89 | return; |
102 | } | 90 | } |
103 | 91 | ||
@@ -110,21 +98,22 @@ static void wl1271_spi_reset(struct wl1271 *wl) | |||
110 | t.len = WSPI_INIT_CMD_LEN; | 98 | t.len = WSPI_INIT_CMD_LEN; |
111 | spi_message_add_tail(&t, &m); | 99 | spi_message_add_tail(&t, &m); |
112 | 100 | ||
113 | spi_sync(wl_to_spi(wl), &m); | 101 | spi_sync(to_spi_device(glue->dev), &m); |
114 | 102 | ||
115 | wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); | ||
116 | kfree(cmd); | 103 | kfree(cmd); |
117 | } | 104 | } |
118 | 105 | ||
119 | static void wl1271_spi_init(struct wl1271 *wl) | 106 | static void wl12xx_spi_init(struct device *child) |
120 | { | 107 | { |
108 | struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); | ||
121 | u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; | 109 | u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; |
122 | struct spi_transfer t; | 110 | struct spi_transfer t; |
123 | struct spi_message m; | 111 | struct spi_message m; |
124 | 112 | ||
125 | cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); | 113 | cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); |
126 | if (!cmd) { | 114 | if (!cmd) { |
127 | wl1271_error("could not allocate cmd for spi init"); | 115 | dev_err(child->parent, |
116 | "could not allocate cmd for spi init\n"); | ||
128 | return; | 117 | return; |
129 | } | 118 | } |
130 | 119 | ||
@@ -165,15 +154,16 @@ static void wl1271_spi_init(struct wl1271 *wl) | |||
165 | t.len = WSPI_INIT_CMD_LEN; | 154 | t.len = WSPI_INIT_CMD_LEN; |
166 | spi_message_add_tail(&t, &m); | 155 | spi_message_add_tail(&t, &m); |
167 | 156 | ||
168 | spi_sync(wl_to_spi(wl), &m); | 157 | spi_sync(to_spi_device(glue->dev), &m); |
169 | wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); | ||
170 | kfree(cmd); | 158 | kfree(cmd); |
171 | } | 159 | } |
172 | 160 | ||
173 | #define WL1271_BUSY_WORD_TIMEOUT 1000 | 161 | #define WL1271_BUSY_WORD_TIMEOUT 1000 |
174 | 162 | ||
175 | static int wl1271_spi_read_busy(struct wl1271 *wl) | 163 | static int wl12xx_spi_read_busy(struct device *child) |
176 | { | 164 | { |
165 | struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); | ||
166 | struct wl1271 *wl = dev_get_drvdata(child); | ||
177 | struct spi_transfer t[1]; | 167 | struct spi_transfer t[1]; |
178 | struct spi_message m; | 168 | struct spi_message m; |
179 | u32 *busy_buf; | 169 | u32 *busy_buf; |
@@ -194,20 +184,22 @@ static int wl1271_spi_read_busy(struct wl1271 *wl) | |||
194 | t[0].len = sizeof(u32); | 184 | t[0].len = sizeof(u32); |
195 | t[0].cs_change = true; | 185 | t[0].cs_change = true; |
196 | spi_message_add_tail(&t[0], &m); | 186 | spi_message_add_tail(&t[0], &m); |
197 | spi_sync(wl_to_spi(wl), &m); | 187 | spi_sync(to_spi_device(glue->dev), &m); |
198 | 188 | ||
199 | if (*busy_buf & 0x1) | 189 | if (*busy_buf & 0x1) |
200 | return 0; | 190 | return 0; |
201 | } | 191 | } |
202 | 192 | ||
203 | /* The SPI bus is unresponsive, the read failed. */ | 193 | /* The SPI bus is unresponsive, the read failed. */ |
204 | wl1271_error("SPI read busy-word timeout!\n"); | 194 | dev_err(child->parent, "SPI read busy-word timeout!\n"); |
205 | return -ETIMEDOUT; | 195 | return -ETIMEDOUT; |
206 | } | 196 | } |
207 | 197 | ||
208 | static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, | 198 | static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf, |
209 | size_t len, bool fixed) | 199 | size_t len, bool fixed) |
210 | { | 200 | { |
201 | struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); | ||
202 | struct wl1271 *wl = dev_get_drvdata(child); | ||
211 | struct spi_transfer t[2]; | 203 | struct spi_transfer t[2]; |
212 | struct spi_message m; | 204 | struct spi_message m; |
213 | u32 *busy_buf; | 205 | u32 *busy_buf; |
@@ -243,10 +235,10 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, | |||
243 | t[1].cs_change = true; | 235 | t[1].cs_change = true; |
244 | spi_message_add_tail(&t[1], &m); | 236 | spi_message_add_tail(&t[1], &m); |
245 | 237 | ||
246 | spi_sync(wl_to_spi(wl), &m); | 238 | spi_sync(to_spi_device(glue->dev), &m); |
247 | 239 | ||
248 | if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) && | 240 | if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) && |
249 | wl1271_spi_read_busy(wl)) { | 241 | wl12xx_spi_read_busy(child)) { |
250 | memset(buf, 0, chunk_len); | 242 | memset(buf, 0, chunk_len); |
251 | return; | 243 | return; |
252 | } | 244 | } |
@@ -259,10 +251,7 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, | |||
259 | t[0].cs_change = true; | 251 | t[0].cs_change = true; |
260 | spi_message_add_tail(&t[0], &m); | 252 | spi_message_add_tail(&t[0], &m); |
261 | 253 | ||
262 | spi_sync(wl_to_spi(wl), &m); | 254 | spi_sync(to_spi_device(glue->dev), &m); |
263 | |||
264 | wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); | ||
265 | wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, chunk_len); | ||
266 | 255 | ||
267 | if (!fixed) | 256 | if (!fixed) |
268 | addr += chunk_len; | 257 | addr += chunk_len; |
@@ -271,9 +260,10 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, | |||
271 | } | 260 | } |
272 | } | 261 | } |
273 | 262 | ||
274 | static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, | 263 | static void wl12xx_spi_raw_write(struct device *child, int addr, void *buf, |
275 | size_t len, bool fixed) | 264 | size_t len, bool fixed) |
276 | { | 265 | { |
266 | struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); | ||
277 | struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS]; | 267 | struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS]; |
278 | struct spi_message m; | 268 | struct spi_message m; |
279 | u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; | 269 | u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; |
@@ -308,9 +298,6 @@ static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, | |||
308 | t[i].len = chunk_len; | 298 | t[i].len = chunk_len; |
309 | spi_message_add_tail(&t[i++], &m); | 299 | spi_message_add_tail(&t[i++], &m); |
310 | 300 | ||
311 | wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); | ||
312 | wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, chunk_len); | ||
313 | |||
314 | if (!fixed) | 301 | if (!fixed) |
315 | addr += chunk_len; | 302 | addr += chunk_len; |
316 | buf += chunk_len; | 303 | buf += chunk_len; |
@@ -318,72 +305,41 @@ static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, | |||
318 | cmd++; | 305 | cmd++; |
319 | } | 306 | } |
320 | 307 | ||
321 | spi_sync(wl_to_spi(wl), &m); | 308 | spi_sync(to_spi_device(glue->dev), &m); |
322 | } | ||
323 | |||
324 | static irqreturn_t wl1271_hardirq(int irq, void *cookie) | ||
325 | { | ||
326 | struct wl1271 *wl = cookie; | ||
327 | unsigned long flags; | ||
328 | |||
329 | wl1271_debug(DEBUG_IRQ, "IRQ"); | ||
330 | |||
331 | /* complete the ELP completion */ | ||
332 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
333 | set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); | ||
334 | if (wl->elp_compl) { | ||
335 | complete(wl->elp_compl); | ||
336 | wl->elp_compl = NULL; | ||
337 | } | ||
338 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
339 | |||
340 | return IRQ_WAKE_THREAD; | ||
341 | } | ||
342 | |||
343 | static int wl1271_spi_set_power(struct wl1271 *wl, bool enable) | ||
344 | { | ||
345 | if (wl->set_power) | ||
346 | wl->set_power(enable); | ||
347 | |||
348 | return 0; | ||
349 | } | 309 | } |
350 | 310 | ||
351 | static struct wl1271_if_operations spi_ops = { | 311 | static struct wl1271_if_operations spi_ops = { |
352 | .read = wl1271_spi_raw_read, | 312 | .read = wl12xx_spi_raw_read, |
353 | .write = wl1271_spi_raw_write, | 313 | .write = wl12xx_spi_raw_write, |
354 | .reset = wl1271_spi_reset, | 314 | .reset = wl12xx_spi_reset, |
355 | .init = wl1271_spi_init, | 315 | .init = wl12xx_spi_init, |
356 | .power = wl1271_spi_set_power, | ||
357 | .dev = wl1271_spi_wl_to_dev, | ||
358 | .enable_irq = wl1271_spi_enable_interrupts, | ||
359 | .disable_irq = wl1271_spi_disable_interrupts, | ||
360 | .set_block_size = NULL, | 316 | .set_block_size = NULL, |
361 | }; | 317 | }; |
362 | 318 | ||
363 | static int __devinit wl1271_probe(struct spi_device *spi) | 319 | static int __devinit wl1271_probe(struct spi_device *spi) |
364 | { | 320 | { |
321 | struct wl12xx_spi_glue *glue; | ||
365 | struct wl12xx_platform_data *pdata; | 322 | struct wl12xx_platform_data *pdata; |
366 | struct ieee80211_hw *hw; | 323 | struct resource res[1]; |
367 | struct wl1271 *wl; | 324 | int ret = -ENOMEM; |
368 | unsigned long irqflags; | ||
369 | int ret; | ||
370 | 325 | ||
371 | pdata = spi->dev.platform_data; | 326 | pdata = spi->dev.platform_data; |
372 | if (!pdata) { | 327 | if (!pdata) { |
373 | wl1271_error("no platform data"); | 328 | dev_err(&spi->dev, "no platform data\n"); |
374 | return -ENODEV; | 329 | return -ENODEV; |
375 | } | 330 | } |
376 | 331 | ||
377 | hw = wl1271_alloc_hw(); | 332 | pdata->ops = &spi_ops; |
378 | if (IS_ERR(hw)) | ||
379 | return PTR_ERR(hw); | ||
380 | 333 | ||
381 | wl = hw->priv; | 334 | glue = kzalloc(sizeof(*glue), GFP_KERNEL); |
335 | if (!glue) { | ||
336 | dev_err(&spi->dev, "can't allocate glue\n"); | ||
337 | goto out; | ||
338 | } | ||
382 | 339 | ||
383 | dev_set_drvdata(&spi->dev, wl); | 340 | glue->dev = &spi->dev; |
384 | wl->if_priv = spi; | ||
385 | 341 | ||
386 | wl->if_ops = &spi_ops; | 342 | spi_set_drvdata(spi, glue); |
387 | 343 | ||
388 | /* This is the only SPI value that we need to set here, the rest | 344 | /* This is the only SPI value that we need to set here, the rest |
389 | * comes from the board-peripherals file */ | 345 | * comes from the board-peripherals file */ |
@@ -391,69 +347,61 @@ static int __devinit wl1271_probe(struct spi_device *spi) | |||
391 | 347 | ||
392 | ret = spi_setup(spi); | 348 | ret = spi_setup(spi); |
393 | if (ret < 0) { | 349 | if (ret < 0) { |
394 | wl1271_error("spi_setup failed"); | 350 | dev_err(glue->dev, "spi_setup failed\n"); |
395 | goto out_free; | 351 | goto out_free_glue; |
396 | } | 352 | } |
397 | 353 | ||
398 | wl->set_power = pdata->set_power; | 354 | glue->core = platform_device_alloc("wl12xx", -1); |
399 | if (!wl->set_power) { | 355 | if (!glue->core) { |
400 | wl1271_error("set power function missing in platform data"); | 356 | dev_err(glue->dev, "can't allocate platform_device\n"); |
401 | ret = -ENODEV; | 357 | ret = -ENOMEM; |
402 | goto out_free; | 358 | goto out_free_glue; |
403 | } | 359 | } |
404 | 360 | ||
405 | wl->ref_clock = pdata->board_ref_clock; | 361 | glue->core->dev.parent = &spi->dev; |
406 | wl->tcxo_clock = pdata->board_tcxo_clock; | ||
407 | wl->platform_quirks = pdata->platform_quirks; | ||
408 | 362 | ||
409 | if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) | 363 | memset(res, 0x00, sizeof(res)); |
410 | irqflags = IRQF_TRIGGER_RISING; | ||
411 | else | ||
412 | irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; | ||
413 | 364 | ||
414 | wl->irq = spi->irq; | 365 | res[0].start = spi->irq; |
415 | if (wl->irq < 0) { | 366 | res[0].flags = IORESOURCE_IRQ; |
416 | wl1271_error("irq missing in platform data"); | 367 | res[0].name = "irq"; |
417 | ret = -ENODEV; | ||
418 | goto out_free; | ||
419 | } | ||
420 | 368 | ||
421 | ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq, | 369 | ret = platform_device_add_resources(glue->core, res, ARRAY_SIZE(res)); |
422 | irqflags, | 370 | if (ret) { |
423 | DRIVER_NAME, wl); | 371 | dev_err(glue->dev, "can't add resources\n"); |
424 | if (ret < 0) { | 372 | goto out_dev_put; |
425 | wl1271_error("request_irq() failed: %d", ret); | ||
426 | goto out_free; | ||
427 | } | 373 | } |
428 | 374 | ||
429 | disable_irq(wl->irq); | 375 | ret = platform_device_add_data(glue->core, pdata, sizeof(*pdata)); |
430 | 376 | if (ret) { | |
431 | ret = wl1271_init_ieee80211(wl); | 377 | dev_err(glue->dev, "can't add platform data\n"); |
432 | if (ret) | 378 | goto out_dev_put; |
433 | goto out_irq; | 379 | } |
434 | 380 | ||
435 | ret = wl1271_register_hw(wl); | 381 | ret = platform_device_add(glue->core); |
436 | if (ret) | 382 | if (ret) { |
437 | goto out_irq; | 383 | dev_err(glue->dev, "can't register platform device\n"); |
384 | goto out_dev_put; | ||
385 | } | ||
438 | 386 | ||
439 | return 0; | 387 | return 0; |
440 | 388 | ||
441 | out_irq: | 389 | out_dev_put: |
442 | free_irq(wl->irq, wl); | 390 | platform_device_put(glue->core); |
443 | |||
444 | out_free: | ||
445 | wl1271_free_hw(wl); | ||
446 | 391 | ||
392 | out_free_glue: | ||
393 | kfree(glue); | ||
394 | out: | ||
447 | return ret; | 395 | return ret; |
448 | } | 396 | } |
449 | 397 | ||
450 | static int __devexit wl1271_remove(struct spi_device *spi) | 398 | static int __devexit wl1271_remove(struct spi_device *spi) |
451 | { | 399 | { |
452 | struct wl1271 *wl = dev_get_drvdata(&spi->dev); | 400 | struct wl12xx_spi_glue *glue = spi_get_drvdata(spi); |
453 | 401 | ||
454 | wl1271_unregister_hw(wl); | 402 | platform_device_del(glue->core); |
455 | free_irq(wl->irq, wl); | 403 | platform_device_put(glue->core); |
456 | wl1271_free_hw(wl); | 404 | kfree(glue); |
457 | 405 | ||
458 | return 0; | 406 | return 0; |
459 | } | 407 | } |
@@ -462,7 +410,6 @@ static int __devexit wl1271_remove(struct spi_device *spi) | |||
462 | static struct spi_driver wl1271_spi_driver = { | 410 | static struct spi_driver wl1271_spi_driver = { |
463 | .driver = { | 411 | .driver = { |
464 | .name = "wl1271_spi", | 412 | .name = "wl1271_spi", |
465 | .bus = &spi_bus_type, | ||
466 | .owner = THIS_MODULE, | 413 | .owner = THIS_MODULE, |
467 | }, | 414 | }, |
468 | 415 | ||