aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTeemu Paasikivi <ext-teemu.3.paasikivi@nokia.com>2010-02-22 01:38:27 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-03-09 15:02:59 -0500
commit5129dffebd4eab1749e63bb4a1b7abdc92903227 (patch)
treefe6c4082c21028da185d70931c86ff5b79f0ca6c
parent50b3eb4bdda4690fc2848079f209b8d605c89fb5 (diff)
wl1271: Initial SDIO implementation
Added initial implementation of SDIO interfacte to the wl1271 driver. When selected, this adds new module called "wl1271_sdio". Signed-off-by: Teemu Paasikivi <ext-teemu.3.paasikivi@nokia.com> Reviewed-by: Juuso Oikarinen <juuso.oikarinen@nokia.com> Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/wl12xx/Kconfig12
-rw-r--r--drivers/net/wireless/wl12xx/Makefile1
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_sdio.c302
3 files changed, 315 insertions, 0 deletions
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index 9c6fdccf00f1..2f6733526f7f 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -63,3 +63,15 @@ config WL1271_SPI
63 If you choose to build a module, it'll be called wl1251_spi. 63 If you choose to build a module, it'll be called wl1251_spi.
64 Say N if unsure. 64 Say N if unsure.
65 65
66config WL1271_SDIO
67 tristate "TI wl1271 SDIO support"
68 depends on WL1271 && MMC
69 ---help---
70 This module adds support for the SDIO interface of adapters using
71 TI wl1271 chipset. Select this if your platform is using
72 the SDIO bus.
73
74 If you choose to build a module, it'll be called
75 wl1271_sdio. Say N if unsure.
76
77
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile
index 473a1e287997..27ddd2be0a91 100644
--- a/drivers/net/wireless/wl12xx/Makefile
+++ b/drivers/net/wireless/wl12xx/Makefile
@@ -15,3 +15,4 @@ wl1271-objs = wl1271_main.o wl1271_cmd.o wl1271_io.o \
15wl1271-$(CONFIG_NL80211_TESTMODE) += wl1271_testmode.o 15wl1271-$(CONFIG_NL80211_TESTMODE) += wl1271_testmode.o
16obj-$(CONFIG_WL1271) += wl1271.o 16obj-$(CONFIG_WL1271) += wl1271.o
17obj-$(CONFIG_WL1271_SPI) += wl1271_spi.o 17obj-$(CONFIG_WL1271_SPI) += wl1271_spi.o
18obj-$(CONFIG_WL1271_SDIO) += wl1271_sdio.o
diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/wl1271_sdio.c
new file mode 100644
index 000000000000..be5c14935bc3
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1271_sdio.c
@@ -0,0 +1,302 @@
1/*
2 * This file is part of wl1271
3 *
4 * Copyright (C) 2009-2010 Nokia Corporation
5 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
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
24#include <linux/irq.h>
25#include <linux/module.h>
26#include <linux/crc7.h>
27#include <linux/vmalloc.h>
28#include <linux/mmc/sdio_func.h>
29#include <linux/mmc/sdio_ids.h>
30#include <linux/mmc/card.h>
31#include <plat/gpio.h>
32
33#include "wl1271.h"
34#include "wl12xx_80211.h"
35#include "wl1271_io.h"
36
37
38#define RX71_WL1271_IRQ_GPIO 42
39
40#ifndef SDIO_VENDOR_ID_TI
41#define SDIO_VENDOR_ID_TI 0x0097
42#endif
43
44#ifndef SDIO_DEVICE_ID_TI_WL1271
45#define SDIO_DEVICE_ID_TI_WL1271 0x4076
46#endif
47
48static const struct sdio_device_id wl1271_devices[] = {
49 { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) },
50 {}
51};
52MODULE_DEVICE_TABLE(sdio, wl1271_devices);
53
54static inline struct sdio_func *wl_to_func(struct wl1271 *wl)
55{
56 return wl->if_priv;
57}
58
59static struct device *wl1271_sdio_wl_to_dev(struct wl1271 *wl)
60{
61 return &(wl_to_func(wl)->dev);
62}
63
64static irqreturn_t wl1271_irq(int irq, void *cookie)
65{
66 struct wl1271 *wl = cookie;
67 unsigned long flags;
68
69 wl1271_debug(DEBUG_IRQ, "IRQ");
70
71 /* complete the ELP completion */
72 spin_lock_irqsave(&wl->wl_lock, flags);
73 if (wl->elp_compl) {
74 complete(wl->elp_compl);
75 wl->elp_compl = NULL;
76 }
77
78 ieee80211_queue_work(wl->hw, &wl->irq_work);
79 spin_unlock_irqrestore(&wl->wl_lock, flags);
80
81 return IRQ_HANDLED;
82}
83
84static void wl1271_sdio_disable_interrupts(struct wl1271 *wl)
85{
86 disable_irq(wl->irq);
87}
88
89static void wl1271_sdio_enable_interrupts(struct wl1271 *wl)
90{
91 enable_irq(wl->irq);
92}
93
94static void wl1271_sdio_reset(struct wl1271 *wl)
95{
96}
97
98static void wl1271_sdio_init(struct wl1271 *wl)
99{
100}
101
102static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf,
103 size_t len, bool fixed)
104{
105 int ret;
106 struct sdio_func *func = wl_to_func(wl);
107
108 sdio_claim_host(func);
109 if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
110 ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
111 wl1271_debug(DEBUG_SPI, "sdio read 52 addr 0x%x, byte 0x%02x",
112 addr, ((u8 *)buf)[0]);
113 } else {
114 if (fixed)
115 ret = sdio_readsb(func, buf, addr, len);
116 else
117 ret = sdio_memcpy_fromio(func, buf, addr, len);
118
119 wl1271_debug(DEBUG_SPI, "sdio read 53 addr 0x%x, %d bytes",
120 addr, len);
121 wl1271_dump_ascii(DEBUG_SPI, "data: ", buf, len);
122 }
123
124 if (ret)
125 wl1271_error("sdio read failed (%d)", ret);
126
127 sdio_release_host(func);
128}
129
130static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf,
131 size_t len, bool fixed)
132{
133 int ret;
134 struct sdio_func *func = wl_to_func(wl);
135
136 sdio_claim_host(func);
137 if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
138 sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
139 wl1271_debug(DEBUG_SPI, "sdio write 52 addr 0x%x, byte 0x%02x",
140 addr, ((u8 *)buf)[0]);
141 } else {
142 wl1271_debug(DEBUG_SPI, "sdio write 53 addr 0x%x, %d bytes",
143 addr, len);
144 wl1271_dump_ascii(DEBUG_SPI, "data: ", buf, len);
145
146 if (fixed)
147 ret = sdio_writesb(func, addr, buf, len);
148 else
149 ret = sdio_memcpy_toio(func, addr, buf, len);
150 }
151 if (ret)
152 wl1271_error("sdio write failed (%d)", ret);
153
154 sdio_release_host(func);
155}
156
157static struct wl1271_if_operations sdio_ops = {
158 .read = wl1271_sdio_raw_read,
159 .write = wl1271_sdio_raw_write,
160 .reset = wl1271_sdio_reset,
161 .init = wl1271_sdio_init,
162 .dev = wl1271_sdio_wl_to_dev,
163 .enable_irq = wl1271_sdio_enable_interrupts,
164 .disable_irq = wl1271_sdio_disable_interrupts
165};
166
167static void wl1271_sdio_set_power(bool enable)
168{
169}
170
171static int __devinit wl1271_probe(struct sdio_func *func,
172 const struct sdio_device_id *id)
173{
174 struct ieee80211_hw *hw;
175 struct wl1271 *wl;
176 int ret;
177
178 /* We are only able to handle the wlan function */
179 if (func->num != 0x02)
180 return -ENODEV;
181
182 hw = wl1271_alloc_hw();
183 if (IS_ERR(hw))
184 return PTR_ERR(hw);
185
186 wl = hw->priv;
187
188 wl->if_priv = func;
189 wl->if_ops = &sdio_ops;
190
191 wl->set_power = wl1271_sdio_set_power;
192
193 /* Grab access to FN0 for ELP reg. */
194 func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
195
196 wl->irq = gpio_to_irq(RX71_WL1271_IRQ_GPIO);
197 if (wl->irq < 0) {
198 ret = wl->irq;
199 wl1271_error("could not get irq!");
200 goto out_free;
201 }
202
203 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
204 if (ret < 0) {
205 wl1271_error("request_irq() failed: %d", ret);
206 goto out_free;
207 }
208
209 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
210
211 disable_irq(wl->irq);
212
213 ret = wl1271_init_ieee80211(wl);
214 if (ret)
215 goto out_irq;
216
217 ret = wl1271_register_hw(wl);
218 if (ret)
219 goto out_irq;
220
221 sdio_claim_host(func);
222 ret = sdio_enable_func(func);
223 if (ret)
224 goto out_release;
225
226 sdio_release_host(func);
227
228 wl1271_notice("initialized");
229
230 return 0;
231
232 out_release:
233 sdio_release_host(func);
234
235 out_irq:
236 free_irq(wl->irq, wl);
237
238
239 out_free:
240 ieee80211_free_hw(hw);
241
242 return ret;
243}
244
245static void __devexit wl1271_remove(struct sdio_func *func)
246{
247 struct wl1271 *wl = sdio_get_drvdata(func);
248
249 sdio_claim_host(func);
250 sdio_disable_func(func);
251 sdio_release_host(func);
252 ieee80211_unregister_hw(wl->hw);
253
254 free_irq(wl->irq, wl);
255
256 kfree(wl->target_mem_map);
257 vfree(wl->fw);
258 wl->fw = NULL;
259 kfree(wl->nvs);
260 wl->nvs = NULL;
261
262 kfree(wl->fw_status);
263 kfree(wl->tx_res_if);
264
265 ieee80211_free_hw(wl->hw);
266}
267
268static struct sdio_driver wl1271_sdio_driver = {
269 .name = "wl1271",
270 .id_table = wl1271_devices,
271 .probe = wl1271_probe,
272 .remove = __devexit_p(wl1271_remove),
273};
274
275static int __init wl1271_init(void)
276{
277 int ret;
278
279 ret = sdio_register_driver(&wl1271_sdio_driver);
280 if (ret < 0) {
281 wl1271_error("failed to register sdio driver: %d", ret);
282 goto out;
283 }
284
285out:
286 return ret;
287}
288
289static void __exit wl1271_exit(void)
290{
291 sdio_unregister_driver(&wl1271_sdio_driver);
292
293 wl1271_notice("unloaded");
294}
295
296module_init(wl1271_init);
297module_exit(wl1271_exit);
298
299MODULE_LICENSE("GPL");
300MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
301MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
302MODULE_FIRMWARE(WL1271_FW_NAME);