aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorChristian Lamparter <chunkeey@web.de>2009-01-10 19:18:38 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-01-29 16:00:25 -0500
commitcd8d3d321285a34b4e29cb7b04e552c49cc0f018 (patch)
treeca4960a84c0e5cd2cd5cd28d4e68b1cc5748d6ee /drivers/net
parent4628ae75583311fcbbd02f4eebcfc08514dfbd65 (diff)
p54spi: p54spi driver
This patch adds the p54spi driver. Signed-off-by: Christian Lamparter <chunkeey@web.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/p54/Kconfig10
-rw-r--r--drivers/net/wireless/p54/Makefile1
-rw-r--r--drivers/net/wireless/p54/p54.h9
-rw-r--r--drivers/net/wireless/p54/p54common.c3
-rw-r--r--drivers/net/wireless/p54/p54spi.c759
-rw-r--r--drivers/net/wireless/p54/p54spi.h127
6 files changed, 908 insertions, 1 deletions
diff --git a/drivers/net/wireless/p54/Kconfig b/drivers/net/wireless/p54/Kconfig
index d3469d08f966..cfc5f41aa136 100644
--- a/drivers/net/wireless/p54/Kconfig
+++ b/drivers/net/wireless/p54/Kconfig
@@ -61,3 +61,13 @@ config P54_PCI
61 http://prism54.org/ 61 http://prism54.org/
62 62
63 If you choose to build a module, it'll be called p54pci. 63 If you choose to build a module, it'll be called p54pci.
64
65config P54_SPI
66 tristate "Prism54 SPI (stlc45xx) support"
67 depends on P54_COMMON && SPI_MASTER
68 ---help---
69 This driver is for stlc4550 or stlc4560 based wireless chips.
70 This driver is experimental, untested and will probably only work on
71 Nokia's N800/N810 Portable Internet Tablet.
72
73 If you choose to build a module, it'll be called p54spi.
diff --git a/drivers/net/wireless/p54/Makefile b/drivers/net/wireless/p54/Makefile
index 4fa9ce717360..c2050dee6293 100644
--- a/drivers/net/wireless/p54/Makefile
+++ b/drivers/net/wireless/p54/Makefile
@@ -1,3 +1,4 @@
1obj-$(CONFIG_P54_COMMON) += p54common.o 1obj-$(CONFIG_P54_COMMON) += p54common.o
2obj-$(CONFIG_P54_USB) += p54usb.o 2obj-$(CONFIG_P54_USB) += p54usb.o
3obj-$(CONFIG_P54_PCI) += p54pci.o 3obj-$(CONFIG_P54_PCI) += p54pci.o
4obj-$(CONFIG_P54_SPI) += p54spi.o
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index ac11efd19db2..64492feca9b2 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -104,6 +104,14 @@ struct p54_cal_database {
104#define FW_LM87 0x4c4d3837 104#define FW_LM87 0x4c4d3837
105#define FW_LM20 0x4c4d3230 105#define FW_LM20 0x4c4d3230
106 106
107enum fw_state {
108 FW_STATE_OFF,
109 FW_STATE_BOOTING,
110 FW_STATE_READY,
111 FW_STATE_RESET,
112 FW_STATE_RESETTING,
113};
114
107struct p54_common { 115struct p54_common {
108 struct ieee80211_hw *hw; 116 struct ieee80211_hw *hw;
109 u32 rx_start; 117 u32 rx_start;
@@ -154,6 +162,7 @@ struct p54_common {
154int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); 162int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
155void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb); 163void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb);
156int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw); 164int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
165int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len);
157int p54_read_eeprom(struct ieee80211_hw *dev); 166int p54_read_eeprom(struct ieee80211_hw *dev);
158struct ieee80211_hw *p54_init_common(size_t priv_data_len); 167struct ieee80211_hw *p54_init_common(size_t priv_data_len);
159void p54_free_common(struct ieee80211_hw *dev); 168void p54_free_common(struct ieee80211_hw *dev);
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index 9fc0c9efe701..45c2e7ad3acd 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -483,7 +483,7 @@ static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src,
483 return dst; 483 return dst;
484} 484}
485 485
486static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) 486int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
487{ 487{
488 struct p54_common *priv = dev->priv; 488 struct p54_common *priv = dev->priv;
489 struct eeprom_pda_wrap *wrap = NULL; 489 struct eeprom_pda_wrap *wrap = NULL;
@@ -698,6 +698,7 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
698 wiphy_name(dev->wiphy)); 698 wiphy_name(dev->wiphy));
699 return err; 699 return err;
700} 700}
701EXPORT_SYMBOL_GPL(p54_parse_eeprom);
701 702
702static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi) 703static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi)
703{ 704{
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c
new file mode 100644
index 000000000000..b8dede741ef6
--- /dev/null
+++ b/drivers/net/wireless/p54/p54spi.c
@@ -0,0 +1,759 @@
1/*
2 * Copyright (C) 2008 Christian Lamparter <chunkeey@web.de>
3 * Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
4 *
5 * This driver is a port from stlc45xx:
6 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 */
22
23#include <linux/module.h>
24#include <linux/platform_device.h>
25#include <linux/interrupt.h>
26#include <linux/firmware.h>
27#include <linux/delay.h>
28#include <linux/irq.h>
29#include <linux/spi/spi.h>
30#include <linux/etherdevice.h>
31#include <linux/gpio.h>
32
33#include "p54spi.h"
34#include "p54spi_eeprom.h"
35#include "p54.h"
36
37#include "p54common.h"
38
39MODULE_FIRMWARE("3826.arm");
40MODULE_ALIAS("stlc45xx");
41
42static void p54spi_spi_read(struct p54s_priv *priv, u8 address,
43 void *buf, size_t len)
44{
45 struct spi_transfer t[2];
46 struct spi_message m;
47 __le16 addr;
48
49 /* We first push the address */
50 addr = cpu_to_le16(address << 8 | SPI_ADRS_READ_BIT_15);
51
52 spi_message_init(&m);
53 memset(t, 0, sizeof(t));
54
55 t[0].tx_buf = &addr;
56 t[0].len = sizeof(addr);
57 spi_message_add_tail(&t[0], &m);
58
59 t[1].rx_buf = buf;
60 t[1].len = len;
61 spi_message_add_tail(&t[1], &m);
62
63 spi_sync(priv->spi, &m);
64}
65
66
67static void p54spi_spi_write(struct p54s_priv *priv, u8 address,
68 const void *buf, size_t len)
69{
70 struct spi_transfer t[3];
71 struct spi_message m;
72 __le16 addr;
73
74 /* We first push the address */
75 addr = cpu_to_le16(address << 8);
76
77 spi_message_init(&m);
78 memset(t, 0, sizeof(t));
79
80 t[0].tx_buf = &addr;
81 t[0].len = sizeof(addr);
82 spi_message_add_tail(&t[0], &m);
83
84 t[1].tx_buf = buf;
85 t[1].len = len;
86 spi_message_add_tail(&t[1], &m);
87
88 if (len % 2) {
89 __le16 last_word;
90 last_word = cpu_to_le16(((u8 *)buf)[len - 1]);
91
92 t[2].tx_buf = &last_word;
93 t[2].len = sizeof(last_word);
94 spi_message_add_tail(&t[2], &m);
95 }
96
97 spi_sync(priv->spi, &m);
98}
99
100static u16 p54spi_read16(struct p54s_priv *priv, u8 addr)
101{
102 __le16 val;
103
104 p54spi_spi_read(priv, addr, &val, sizeof(val));
105
106 return le16_to_cpu(val);
107}
108
109static u32 p54spi_read32(struct p54s_priv *priv, u8 addr)
110{
111 __le32 val;
112
113 p54spi_spi_read(priv, addr, &val, sizeof(val));
114
115 return le32_to_cpu(val);
116}
117
118static inline void p54spi_write16(struct p54s_priv *priv, u8 addr, __le16 val)
119{
120 p54spi_spi_write(priv, addr, &val, sizeof(val));
121}
122
123static inline void p54spi_write32(struct p54s_priv *priv, u8 addr, __le32 val)
124{
125 p54spi_spi_write(priv, addr, &val, sizeof(val));
126}
127
128struct p54spi_spi_reg {
129 u16 address; /* __le16 ? */
130 u16 length;
131 char *name;
132};
133
134static const struct p54spi_spi_reg p54spi_registers_array[] =
135{
136 { SPI_ADRS_ARM_INTERRUPTS, 32, "ARM_INT " },
137 { SPI_ADRS_ARM_INT_EN, 32, "ARM_INT_ENA " },
138 { SPI_ADRS_HOST_INTERRUPTS, 32, "HOST_INT " },
139 { SPI_ADRS_HOST_INT_EN, 32, "HOST_INT_ENA" },
140 { SPI_ADRS_HOST_INT_ACK, 32, "HOST_INT_ACK" },
141 { SPI_ADRS_GEN_PURP_1, 32, "GP1_COMM " },
142 { SPI_ADRS_GEN_PURP_2, 32, "GP2_COMM " },
143 { SPI_ADRS_DEV_CTRL_STAT, 32, "DEV_CTRL_STA" },
144 { SPI_ADRS_DMA_DATA, 16, "DMA_DATA " },
145 { SPI_ADRS_DMA_WRITE_CTRL, 16, "DMA_WR_CTRL " },
146 { SPI_ADRS_DMA_WRITE_LEN, 16, "DMA_WR_LEN " },
147 { SPI_ADRS_DMA_WRITE_BASE, 32, "DMA_WR_BASE " },
148 { SPI_ADRS_DMA_READ_CTRL, 16, "DMA_RD_CTRL " },
149 { SPI_ADRS_DMA_READ_LEN, 16, "DMA_RD_LEN " },
150 { SPI_ADRS_DMA_WRITE_BASE, 32, "DMA_RD_BASE " }
151};
152
153static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits)
154{
155 int i;
156 __le32 buffer;
157
158 for (i = 0; i < 2000; i++) {
159 p54spi_spi_read(priv, reg, &buffer, sizeof(buffer));
160 if (buffer == bits)
161 return 1;
162
163 msleep(1);
164 }
165 return 0;
166}
167
168static int p54spi_request_firmware(struct ieee80211_hw *dev)
169{
170 struct p54s_priv *priv = dev->priv;
171 int ret;
172
173 /* FIXME: should driver use it's own struct device? */
174 ret = request_firmware(&priv->firmware, "3826.arm", &priv->spi->dev);
175
176 if (ret < 0) {
177 dev_err(&priv->spi->dev, "request_firmware() failed: %d", ret);
178 return ret;
179 }
180
181 ret = p54_parse_firmware(dev, priv->firmware);
182 if (ret) {
183 release_firmware(priv->firmware);
184 return ret;
185 }
186
187 return 0;
188}
189
190static int p54spi_request_eeprom(struct ieee80211_hw *dev)
191{
192 struct p54s_priv *priv = dev->priv;
193 const struct firmware *eeprom;
194 int ret;
195
196 /*
197 * allow users to customize their eeprom.
198 */
199
200 ret = request_firmware(&eeprom, "3826.eeprom", &priv->spi->dev);
201 if (ret < 0) {
202 dev_info(&priv->spi->dev, "loading default eeprom...\n");
203 ret = p54_parse_eeprom(dev, (void *) p54spi_eeprom,
204 sizeof(p54spi_eeprom));
205 } else {
206 dev_info(&priv->spi->dev, "loading user eeprom...\n");
207 ret = p54_parse_eeprom(dev, (void *) eeprom->data,
208 (int)eeprom->size);
209 release_firmware(eeprom);
210 }
211 return ret;
212}
213
214static int p54spi_upload_firmware(struct ieee80211_hw *dev)
215{
216 struct p54s_priv *priv = dev->priv;
217 unsigned long fw_len, fw_addr;
218 long _fw_len;
219
220 /* stop the device */
221 p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16(
222 SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_HOST_RESET |
223 SPI_CTRL_STAT_START_HALTED));
224
225 msleep(TARGET_BOOT_SLEEP);
226
227 p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16(
228 SPI_CTRL_STAT_HOST_OVERRIDE |
229 SPI_CTRL_STAT_START_HALTED));
230
231 msleep(TARGET_BOOT_SLEEP);
232
233 fw_addr = ISL38XX_DEV_FIRMWARE_ADDR;
234 fw_len = priv->firmware->size;
235
236 while (fw_len > 0) {
237 _fw_len = min_t(long, fw_len, SPI_MAX_PACKET_SIZE);
238
239 p54spi_write16(priv, SPI_ADRS_DMA_WRITE_CTRL,
240 cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE));
241
242 if (p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL,
243 cpu_to_le32(HOST_ALLOWED)) == 0) {
244 dev_err(&priv->spi->dev, "fw_upload not allowed "
245 "to DMA write.");
246 return -EAGAIN;
247 }
248
249 p54spi_write16(priv, SPI_ADRS_DMA_WRITE_LEN,
250 cpu_to_le16(_fw_len));
251 p54spi_write32(priv, SPI_ADRS_DMA_WRITE_BASE,
252 cpu_to_le32(fw_addr));
253
254 p54spi_spi_write(priv, SPI_ADRS_DMA_DATA,
255 &priv->firmware->data, _fw_len);
256
257 fw_len -= _fw_len;
258 fw_addr += _fw_len;
259
260 /* FIXME: I think this doesn't work if firmware is large,
261 * this loop goes to second round. fw->data is not
262 * increased at all! */
263 }
264
265 BUG_ON(fw_len != 0);
266
267 /* enable host interrupts */
268 p54spi_write32(priv, SPI_ADRS_HOST_INT_EN,
269 cpu_to_le32(SPI_HOST_INTS_DEFAULT));
270
271 /* boot the device */
272 p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16(
273 SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_HOST_RESET |
274 SPI_CTRL_STAT_RAM_BOOT));
275
276 msleep(TARGET_BOOT_SLEEP);
277
278 p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16(
279 SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_RAM_BOOT));
280 msleep(TARGET_BOOT_SLEEP);
281 return 0;
282}
283
284static void p54spi_power_off(struct p54s_priv *priv)
285{
286 disable_irq(gpio_to_irq(priv->config->irq_gpio));
287 gpio_set_value(priv->config->power_gpio, 0);
288}
289
290static void p54spi_power_on(struct p54s_priv *priv)
291{
292 gpio_set_value(priv->config->power_gpio, 1);
293 enable_irq(gpio_to_irq(priv->config->irq_gpio));
294
295 /*
296 * need to wait a while before device can be accessed, the lenght
297 * is just a guess
298 */
299 msleep(10);
300}
301
302static inline void p54spi_int_ack(struct p54s_priv *priv, u32 val)
303{
304 p54spi_write32(priv, SPI_ADRS_HOST_INT_ACK, cpu_to_le32(val));
305}
306
307static void p54spi_wakeup(struct p54s_priv *priv)
308{
309 unsigned long timeout;
310 u32 ints;
311
312 /* wake the chip */
313 p54spi_write32(priv, SPI_ADRS_ARM_INTERRUPTS,
314 cpu_to_le32(SPI_TARGET_INT_WAKEUP));
315
316 /* And wait for the READY interrupt */
317 timeout = jiffies + HZ;
318
319 ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS);
320 while (!(ints & SPI_HOST_INT_READY)) {
321 if (time_after(jiffies, timeout))
322 goto out;
323 ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS);
324 }
325
326 p54spi_int_ack(priv, SPI_HOST_INT_READY);
327
328out:
329 return;
330}
331
332static inline void p54spi_sleep(struct p54s_priv *priv)
333{
334 p54spi_write32(priv, SPI_ADRS_ARM_INTERRUPTS,
335 cpu_to_le32(SPI_TARGET_INT_SLEEP));
336}
337
338static void p54spi_int_ready(struct p54s_priv *priv)
339{
340 p54spi_write32(priv, SPI_ADRS_HOST_INT_EN, cpu_to_le32(
341 SPI_HOST_INT_UPDATE | SPI_HOST_INT_SW_UPDATE));
342
343 switch (priv->fw_state) {
344 case FW_STATE_BOOTING:
345 priv->fw_state = FW_STATE_READY;
346 complete(&priv->fw_comp);
347 break;
348 case FW_STATE_RESETTING:
349 priv->fw_state = FW_STATE_READY;
350 /* TODO: reinitialize state */
351 break;
352 default:
353 break;
354 }
355}
356
357static int p54spi_rx(struct p54s_priv *priv)
358{
359 struct sk_buff *skb;
360 u16 len;
361
362 p54spi_wakeup(priv);
363
364 /* dummy read to flush SPI DMA controller bug */
365 p54spi_read16(priv, SPI_ADRS_GEN_PURP_1);
366
367 len = p54spi_read16(priv, SPI_ADRS_DMA_DATA);
368
369 if (len == 0) {
370 dev_err(&priv->spi->dev, "rx request of zero bytes");
371 return 0;
372 }
373
374 skb = dev_alloc_skb(len);
375 if (!skb) {
376 dev_err(&priv->spi->dev, "could not alloc skb");
377 return 0;
378 }
379
380 p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, skb_put(skb, len), len);
381 p54spi_sleep(priv);
382
383 if (p54_rx(priv->hw, skb) == 0)
384 dev_kfree_skb(skb);
385
386 return 0;
387}
388
389
390static irqreturn_t p54spi_interrupt(int irq, void *config)
391{
392 struct spi_device *spi = config;
393 struct p54s_priv *priv = dev_get_drvdata(&spi->dev);
394
395 queue_work(priv->hw->workqueue, &priv->work);
396
397 return IRQ_HANDLED;
398}
399
400static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb)
401{
402 struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
403 struct p54s_dma_regs dma_regs;
404 unsigned long timeout;
405 int ret = 0;
406 u32 ints;
407
408 p54spi_wakeup(priv);
409
410 dma_regs.cmd = cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE);
411 dma_regs.len = cpu_to_le16(skb->len);
412 dma_regs.addr = hdr->req_id;
413
414 p54spi_spi_write(priv, SPI_ADRS_DMA_WRITE_CTRL, &dma_regs,
415 sizeof(dma_regs));
416
417 p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, skb->data, skb->len);
418
419 timeout = jiffies + 2 * HZ;
420 ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS);
421 while (!(ints & SPI_HOST_INT_WR_READY)) {
422 if (time_after(jiffies, timeout)) {
423 dev_err(&priv->spi->dev, "WR_READY timeout");
424 ret = -1;
425 goto out;
426 }
427 ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS);
428 }
429
430 p54spi_int_ack(priv, SPI_HOST_INT_WR_READY);
431 p54spi_sleep(priv);
432
433out:
434 if (FREE_AFTER_TX(skb))
435 p54_free_skb(priv->hw, skb);
436 return ret;
437}
438
439static int p54spi_wq_tx(struct p54s_priv *priv)
440{
441 struct p54s_tx_info *entry;
442 struct sk_buff *skb;
443 struct ieee80211_tx_info *info;
444 struct p54_tx_info *minfo;
445 struct p54s_tx_info *dinfo;
446 int ret = 0;
447
448 spin_lock_bh(&priv->tx_lock);
449
450 while (!list_empty(&priv->tx_pending)) {
451 entry = list_entry(priv->tx_pending.next,
452 struct p54s_tx_info, tx_list);
453
454 list_del_init(&entry->tx_list);
455
456 spin_unlock_bh(&priv->tx_lock);
457
458 dinfo = container_of((void *) entry, struct p54s_tx_info,
459 tx_list);
460 minfo = container_of((void *) dinfo, struct p54_tx_info,
461 data);
462 info = container_of((void *) minfo, struct ieee80211_tx_info,
463 rate_driver_data);
464 skb = container_of((void *) info, struct sk_buff, cb);
465
466 ret = p54spi_tx_frame(priv, skb);
467
468 spin_lock_bh(&priv->tx_lock);
469
470 if (ret < 0) {
471 p54_free_skb(priv->hw, skb);
472 goto out;
473 }
474 }
475
476out:
477 spin_unlock_bh(&priv->tx_lock);
478 return ret;
479}
480
481static void p54spi_op_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
482{
483 struct p54s_priv *priv = dev->priv;
484 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
485 struct p54_tx_info *mi = (struct p54_tx_info *) info->rate_driver_data;
486 struct p54s_tx_info *di = (struct p54s_tx_info *) mi->data;
487
488 BUILD_BUG_ON(sizeof(*di) > sizeof((mi->data)));
489
490 spin_lock_bh(&priv->tx_lock);
491 list_add_tail(&di->tx_list, &priv->tx_pending);
492 spin_unlock_bh(&priv->tx_lock);
493
494 queue_work(priv->hw->workqueue, &priv->work);
495}
496
497static void p54spi_work(struct work_struct *work)
498{
499 struct p54s_priv *priv = container_of(work, struct p54s_priv, work);
500 u32 ints;
501 int ret;
502
503 mutex_lock(&priv->mutex);
504
505 if (priv->fw_state == FW_STATE_OFF &&
506 priv->fw_state == FW_STATE_RESET)
507 goto out;
508
509 ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS);
510
511 if (ints & SPI_HOST_INT_READY) {
512 p54spi_int_ready(priv);
513 p54spi_int_ack(priv, SPI_HOST_INT_READY);
514 }
515
516 if (priv->fw_state != FW_STATE_READY)
517 goto out;
518
519 if (ints & SPI_HOST_INT_UPDATE) {
520 p54spi_int_ack(priv, SPI_HOST_INT_UPDATE);
521 ret = p54spi_rx(priv);
522 if (ret < 0)
523 goto out;
524 }
525 if (ints & SPI_HOST_INT_SW_UPDATE) {
526 p54spi_int_ack(priv, SPI_HOST_INT_SW_UPDATE);
527 ret = p54spi_rx(priv);
528 if (ret < 0)
529 goto out;
530 }
531
532 ret = p54spi_wq_tx(priv);
533 if (ret < 0)
534 goto out;
535
536 ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS);
537
538out:
539 mutex_unlock(&priv->mutex);
540}
541
542static int p54spi_op_start(struct ieee80211_hw *dev)
543{
544 struct p54s_priv *priv = dev->priv;
545 unsigned long timeout;
546 int ret = 0;
547
548 if (mutex_lock_interruptible(&priv->mutex)) {
549 ret = -EINTR;
550 goto out;
551 }
552
553 priv->fw_state = FW_STATE_BOOTING;
554
555 p54spi_power_on(priv);
556
557 ret = p54spi_upload_firmware(dev);
558 if (ret < 0) {
559 p54spi_power_off(priv);
560 goto out_unlock;
561 }
562
563 mutex_unlock(&priv->mutex);
564
565 timeout = msecs_to_jiffies(2000);
566 timeout = wait_for_completion_interruptible_timeout(&priv->fw_comp,
567 timeout);
568 if (!timeout) {
569 dev_err(&priv->spi->dev, "firmware boot failed");
570 p54spi_power_off(priv);
571 ret = -1;
572 goto out;
573 }
574
575 if (mutex_lock_interruptible(&priv->mutex)) {
576 ret = -EINTR;
577 p54spi_power_off(priv);
578 goto out;
579 }
580
581 WARN_ON(priv->fw_state != FW_STATE_READY);
582
583out_unlock:
584 mutex_unlock(&priv->mutex);
585
586out:
587 return ret;
588}
589
590static void p54spi_op_stop(struct ieee80211_hw *dev)
591{
592 struct p54s_priv *priv = dev->priv;
593
594 if (mutex_lock_interruptible(&priv->mutex)) {
595 /* FIXME: how to handle this error? */
596 return;
597 }
598
599 WARN_ON(priv->fw_state != FW_STATE_READY);
600
601 cancel_work_sync(&priv->work);
602
603 p54spi_power_off(priv);
604 spin_lock_bh(&priv->tx_lock);
605 INIT_LIST_HEAD(&priv->tx_pending);
606 spin_unlock_bh(&priv->tx_lock);
607
608 priv->fw_state = FW_STATE_OFF;
609 mutex_unlock(&priv->mutex);
610}
611
612static int __devinit p54spi_probe(struct spi_device *spi)
613{
614 struct p54s_priv *priv = NULL;
615 struct ieee80211_hw *hw;
616 int ret = -EINVAL;
617
618 hw = p54_init_common(sizeof(*priv));
619 if (!hw) {
620 dev_err(&priv->spi->dev, "could not alloc ieee80211_hw");
621 return -ENOMEM;
622 }
623
624 priv = hw->priv;
625 priv->hw = hw;
626 dev_set_drvdata(&spi->dev, priv);
627 priv->spi = spi;
628
629 priv->config = omap_get_config(OMAP_TAG_WLAN_CX3110X,
630 struct omap_wlan_cx3110x_config);
631
632 spi->bits_per_word = 16;
633 spi->max_speed_hz = 24000000;
634
635 ret = spi_setup(spi);
636 if (ret < 0) {
637 dev_err(&priv->spi->dev, "spi_setup failed");
638 goto err_free_common;
639 }
640
641 ret = gpio_request(priv->config->power_gpio, "p54spi power");
642 if (ret < 0) {
643 dev_err(&priv->spi->dev, "power GPIO request failed: %d", ret);
644 goto err_free_common;
645 }
646
647 ret = gpio_request(priv->config->irq_gpio, "p54spi irq");
648 if (ret < 0) {
649 dev_err(&priv->spi->dev, "irq GPIO request failed: %d", ret);
650 goto err_free_common;
651 }
652
653 gpio_direction_output(priv->config->power_gpio, 0);
654 gpio_direction_input(priv->config->irq_gpio);
655
656 ret = request_irq(OMAP_GPIO_IRQ(priv->config->irq_gpio),
657 p54spi_interrupt, IRQF_DISABLED, "p54spi",
658 priv->spi);
659 if (ret < 0) {
660 dev_err(&priv->spi->dev, "request_irq() failed");
661 goto err_free_common;
662 }
663
664 set_irq_type(gpio_to_irq(priv->config->irq_gpio),
665 IRQ_TYPE_EDGE_RISING);
666
667 disable_irq(gpio_to_irq(priv->config->irq_gpio));
668
669 INIT_WORK(&priv->work, p54spi_work);
670 init_completion(&priv->fw_comp);
671 INIT_LIST_HEAD(&priv->tx_pending);
672 mutex_init(&priv->mutex);
673 SET_IEEE80211_DEV(hw, &spi->dev);
674 priv->common.open = p54spi_op_start;
675 priv->common.stop = p54spi_op_stop;
676 priv->common.tx = p54spi_op_tx;
677
678 ret = p54spi_request_firmware(hw);
679 if (ret < 0)
680 goto err_free_common;
681
682 ret = p54spi_request_eeprom(hw);
683 if (ret)
684 goto err_free_common;
685
686 ret = ieee80211_register_hw(hw);
687 if (ret) {
688 dev_err(&priv->spi->dev, "unable to register "
689 "mac80211 hw: %d", ret);
690 goto err_free_common;
691 }
692
693 dev_info(&priv->spi->dev, "device is bound to %s\n",
694 wiphy_name(hw->wiphy));
695 return 0;
696
697err_free_common:
698 p54_free_common(priv->hw);
699 return ret;
700}
701
702static int __devexit p54spi_remove(struct spi_device *spi)
703{
704 struct p54s_priv *priv = dev_get_drvdata(&spi->dev);
705
706 ieee80211_unregister_hw(priv->hw);
707
708 free_irq(gpio_to_irq(priv->config->irq_gpio), spi);
709
710 gpio_free(priv->config->power_gpio);
711 gpio_free(priv->config->irq_gpio);
712 release_firmware(priv->firmware);
713
714 mutex_destroy(&priv->mutex);
715
716 p54_free_common(priv->hw);
717 ieee80211_free_hw(priv->hw);
718
719 return 0;
720}
721
722
723static struct spi_driver p54spi_driver = {
724 .driver = {
725 /* use cx3110x name because board-n800.c uses that for the
726 * SPI port */
727 .name = "cx3110x",
728 .bus = &spi_bus_type,
729 .owner = THIS_MODULE,
730 },
731
732 .probe = p54spi_probe,
733 .remove = __devexit_p(p54spi_remove),
734};
735
736static int __init p54spi_init(void)
737{
738 int ret;
739
740 ret = spi_register_driver(&p54spi_driver);
741 if (ret < 0) {
742 printk(KERN_ERR "failed to register SPI driver: %d", ret);
743 goto out;
744 }
745
746out:
747 return ret;
748}
749
750static void __exit p54spi_exit(void)
751{
752 spi_unregister_driver(&p54spi_driver);
753}
754
755module_init(p54spi_init);
756module_exit(p54spi_exit);
757
758MODULE_LICENSE("GPL");
759MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>");
diff --git a/drivers/net/wireless/p54/p54spi.h b/drivers/net/wireless/p54/p54spi.h
new file mode 100644
index 000000000000..5013ebc8712e
--- /dev/null
+++ b/drivers/net/wireless/p54/p54spi.h
@@ -0,0 +1,127 @@
1/*
2 * Copyright (C) 2008 Christian Lamparter <chunkeey@web.de>
3 *
4 * This driver is a port from stlc45xx:
5 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * version 2 as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19 * 02110-1301 USA
20 */
21
22#ifndef P54SPI_H
23#define P54SPI_H
24
25#include <linux/mutex.h>
26#include <linux/list.h>
27#include <net/mac80211.h>
28#include <mach/board.h>
29
30#include "p54.h"
31
32/* Bit 15 is read/write bit; ON = READ, OFF = WRITE */
33#define SPI_ADRS_READ_BIT_15 0x8000
34
35#define SPI_ADRS_ARM_INTERRUPTS 0x00
36#define SPI_ADRS_ARM_INT_EN 0x04
37
38#define SPI_ADRS_HOST_INTERRUPTS 0x08
39#define SPI_ADRS_HOST_INT_EN 0x0c
40#define SPI_ADRS_HOST_INT_ACK 0x10
41
42#define SPI_ADRS_GEN_PURP_1 0x14
43#define SPI_ADRS_GEN_PURP_2 0x18
44
45#define SPI_ADRS_DEV_CTRL_STAT 0x26 /* high word */
46
47#define SPI_ADRS_DMA_DATA 0x28
48
49#define SPI_ADRS_DMA_WRITE_CTRL 0x2c
50#define SPI_ADRS_DMA_WRITE_LEN 0x2e
51#define SPI_ADRS_DMA_WRITE_BASE 0x30
52
53#define SPI_ADRS_DMA_READ_CTRL 0x34
54#define SPI_ADRS_DMA_READ_LEN 0x36
55#define SPI_ADRS_DMA_READ_BASE 0x38
56
57#define SPI_CTRL_STAT_HOST_OVERRIDE 0x8000
58#define SPI_CTRL_STAT_START_HALTED 0x4000
59#define SPI_CTRL_STAT_RAM_BOOT 0x2000
60#define SPI_CTRL_STAT_HOST_RESET 0x1000
61#define SPI_CTRL_STAT_HOST_CPU_EN 0x0800
62
63#define SPI_DMA_WRITE_CTRL_ENABLE 0x0001
64#define SPI_DMA_READ_CTRL_ENABLE 0x0001
65#define HOST_ALLOWED (1 << 7)
66
67#define SPI_TIMEOUT 100 /* msec */
68
69#define SPI_MAX_TX_PACKETS 32
70
71#define SPI_MAX_PACKET_SIZE 32767
72
73#define SPI_TARGET_INT_WAKEUP 0x00000001
74#define SPI_TARGET_INT_SLEEP 0x00000002
75#define SPI_TARGET_INT_RDDONE 0x00000004
76
77#define SPI_TARGET_INT_CTS 0x00004000
78#define SPI_TARGET_INT_DR 0x00008000
79
80#define SPI_HOST_INT_READY 0x00000001
81#define SPI_HOST_INT_WR_READY 0x00000002
82#define SPI_HOST_INT_SW_UPDATE 0x00000004
83#define SPI_HOST_INT_UPDATE 0x10000000
84
85/* clear to send */
86#define SPI_HOST_INT_CR 0x00004000
87
88/* data ready */
89#define SPI_HOST_INT_DR 0x00008000
90
91#define SPI_HOST_INTS_DEFAULT \
92 (SPI_HOST_INT_READY | SPI_HOST_INT_UPDATE | SPI_HOST_INT_SW_UPDATE)
93
94#define TARGET_BOOT_SLEEP 50
95
96struct p54s_dma_regs {
97 __le16 cmd;
98 __le16 len;
99 __le32 addr;
100} __attribute__ ((packed));
101
102struct p54s_tx_info {
103 struct list_head tx_list;
104};
105
106struct p54s_priv {
107 /* p54_common has to be the first entry */
108 struct p54_common common;
109 struct ieee80211_hw *hw;
110 struct spi_device *spi;
111 const struct omap_wlan_cx3110x_config *config;
112
113 struct work_struct work;
114
115 struct mutex mutex;
116 struct completion fw_comp;
117
118 spinlock_t tx_lock;
119
120 /* protected by tx_lock */
121 struct list_head tx_pending;
122
123 enum fw_state fw_state;
124 const struct firmware *firmware;
125};
126
127#endif /* P54SPI_H */