blob: f2f04663627c2b43fb80b42c249748e4721ed30d [file] [log] [blame]
Teemu Paasikivi5129dff2010-02-22 08:38:27 +02001/*
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>
Ohad Ben-Cohen19b87172010-05-13 12:43:24 +030031#include <linux/gpio.h>
Ohad Ben-Cohen09cecc32010-09-16 01:31:35 +020032#include <linux/wl12xx.h>
Teemu Paasikivi5129dff2010-02-22 08:38:27 +020033
34#include "wl1271.h"
35#include "wl12xx_80211.h"
36#include "wl1271_io.h"
37
Teemu Paasikivi5129dff2010-02-22 08:38:27 +020038#ifndef SDIO_VENDOR_ID_TI
39#define SDIO_VENDOR_ID_TI 0x0097
40#endif
41
42#ifndef SDIO_DEVICE_ID_TI_WL1271
43#define SDIO_DEVICE_ID_TI_WL1271 0x4076
44#endif
45
46static const struct sdio_device_id wl1271_devices[] = {
47 { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) },
48 {}
49};
50MODULE_DEVICE_TABLE(sdio, wl1271_devices);
51
52static inline struct sdio_func *wl_to_func(struct wl1271 *wl)
53{
54 return wl->if_priv;
55}
56
57static struct device *wl1271_sdio_wl_to_dev(struct wl1271 *wl)
58{
59 return &(wl_to_func(wl)->dev);
60}
61
62static irqreturn_t wl1271_irq(int irq, void *cookie)
63{
64 struct wl1271 *wl = cookie;
65 unsigned long flags;
66
67 wl1271_debug(DEBUG_IRQ, "IRQ");
68
69 /* complete the ELP completion */
70 spin_lock_irqsave(&wl->wl_lock, flags);
71 if (wl->elp_compl) {
72 complete(wl->elp_compl);
73 wl->elp_compl = NULL;
74 }
75
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +020076 if (!test_and_set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags))
77 ieee80211_queue_work(wl->hw, &wl->irq_work);
78 set_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
Teemu Paasikivi5129dff2010-02-22 08:38:27 +020079 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,
Teemu Paasikivia3b8ea72010-03-18 12:26:41 +0200103 size_t len, bool fixed)
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200104{
105 int ret;
106 struct sdio_func *func = wl_to_func(wl);
107
Ohad Ben-Cohen49063a02010-09-07 04:24:21 +0300108 sdio_claim_host(func);
109
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200110 if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
111 ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
Teemu Paasikivia3b8ea72010-03-18 12:26:41 +0200112 wl1271_debug(DEBUG_SDIO, "sdio read 52 addr 0x%x, byte 0x%02x",
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200113 addr, ((u8 *)buf)[0]);
114 } else {
115 if (fixed)
116 ret = sdio_readsb(func, buf, addr, len);
117 else
118 ret = sdio_memcpy_fromio(func, buf, addr, len);
119
Teemu Paasikivi99e50312010-03-26 12:53:16 +0200120 wl1271_debug(DEBUG_SDIO, "sdio read 53 addr 0x%x, %zu bytes",
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200121 addr, len);
Teemu Paasikivia3b8ea72010-03-18 12:26:41 +0200122 wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len);
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200123 }
124
Ohad Ben-Cohen49063a02010-09-07 04:24:21 +0300125 sdio_release_host(func);
126
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200127 if (ret)
128 wl1271_error("sdio read failed (%d)", ret);
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200129}
130
131static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf,
Teemu Paasikivia3b8ea72010-03-18 12:26:41 +0200132 size_t len, bool fixed)
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200133{
134 int ret;
135 struct sdio_func *func = wl_to_func(wl);
136
Ohad Ben-Cohen49063a02010-09-07 04:24:21 +0300137 sdio_claim_host(func);
138
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200139 if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
140 sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
Teemu Paasikivia3b8ea72010-03-18 12:26:41 +0200141 wl1271_debug(DEBUG_SDIO, "sdio write 52 addr 0x%x, byte 0x%02x",
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200142 addr, ((u8 *)buf)[0]);
143 } else {
Teemu Paasikivi99e50312010-03-26 12:53:16 +0200144 wl1271_debug(DEBUG_SDIO, "sdio write 53 addr 0x%x, %zu bytes",
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200145 addr, len);
Teemu Paasikivia3b8ea72010-03-18 12:26:41 +0200146 wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len);
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200147
148 if (fixed)
149 ret = sdio_writesb(func, addr, buf, len);
150 else
151 ret = sdio_memcpy_toio(func, addr, buf, len);
152 }
Ohad Ben-Cohen49063a02010-09-07 04:24:21 +0300153
154 sdio_release_host(func);
155
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200156 if (ret)
157 wl1271_error("sdio write failed (%d)", ret);
Ohad Ben-Cohen49063a02010-09-07 04:24:21 +0300158}
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200159
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200160static int wl1271_sdio_power_on(struct wl1271 *wl)
Ohad Ben-Cohen49063a02010-09-07 04:24:21 +0300161{
162 struct sdio_func *func = wl_to_func(wl);
163
164 sdio_claim_host(func);
165 sdio_enable_func(func);
166 sdio_release_host(func);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200167
168 return 0;
Ohad Ben-Cohen49063a02010-09-07 04:24:21 +0300169}
170
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200171static int wl1271_sdio_power_off(struct wl1271 *wl)
Ohad Ben-Cohen49063a02010-09-07 04:24:21 +0300172{
173 struct sdio_func *func = wl_to_func(wl);
174
175 sdio_claim_host(func);
176 sdio_disable_func(func);
177 sdio_release_host(func);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200178
179 return 0;
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200180}
181
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200182static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable)
Teemu Paasikivibecd5512010-03-18 12:26:27 +0200183{
Teemu Paasikivia3b8ea72010-03-18 12:26:41 +0200184 /* Let the SDIO stack handle wlan_enable control, so we
185 * keep host claimed while wlan is in use to keep wl1271
186 * alive.
187 */
Ohad Ben-Cohen49063a02010-09-07 04:24:21 +0300188 if (enable)
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200189 return wl1271_sdio_power_on(wl);
Ohad Ben-Cohen49063a02010-09-07 04:24:21 +0300190 else
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200191 return wl1271_sdio_power_off(wl);
Teemu Paasikivibecd5512010-03-18 12:26:27 +0200192}
193
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200194static struct wl1271_if_operations sdio_ops = {
195 .read = wl1271_sdio_raw_read,
196 .write = wl1271_sdio_raw_write,
197 .reset = wl1271_sdio_reset,
198 .init = wl1271_sdio_init,
Teemu Paasikivibecd5512010-03-18 12:26:27 +0200199 .power = wl1271_sdio_set_power,
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200200 .dev = wl1271_sdio_wl_to_dev,
201 .enable_irq = wl1271_sdio_enable_interrupts,
202 .disable_irq = wl1271_sdio_disable_interrupts
203};
204
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200205static int __devinit wl1271_probe(struct sdio_func *func,
206 const struct sdio_device_id *id)
207{
208 struct ieee80211_hw *hw;
Ohad Ben-Cohen09cecc32010-09-16 01:31:35 +0200209 const struct wl12xx_platform_data *wlan_data;
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200210 struct wl1271 *wl;
211 int ret;
212
213 /* We are only able to handle the wlan function */
214 if (func->num != 0x02)
215 return -ENODEV;
216
217 hw = wl1271_alloc_hw();
218 if (IS_ERR(hw))
219 return PTR_ERR(hw);
220
221 wl = hw->priv;
222
223 wl->if_priv = func;
224 wl->if_ops = &sdio_ops;
225
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200226 /* Grab access to FN0 for ELP reg. */
227 func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
228
Ohad Ben-Cohen09cecc32010-09-16 01:31:35 +0200229 wlan_data = wl12xx_get_platform_data();
230 if (IS_ERR(wlan_data)) {
231 ret = PTR_ERR(wlan_data);
232 wl1271_error("missing wlan platform data: %d", ret);
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200233 goto out_free;
234 }
235
Ohad Ben-Cohen09cecc32010-09-16 01:31:35 +0200236 wl->irq = wlan_data->irq;
Ohad Ben-Cohen15cea992010-09-16 01:31:51 +0200237 wl->ref_clock = wlan_data->board_ref_clock;
Ohad Ben-Cohen09cecc32010-09-16 01:31:35 +0200238
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200239 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
240 if (ret < 0) {
241 wl1271_error("request_irq() failed: %d", ret);
242 goto out_free;
243 }
244
245 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
246
247 disable_irq(wl->irq);
248
249 ret = wl1271_init_ieee80211(wl);
250 if (ret)
251 goto out_irq;
252
253 ret = wl1271_register_hw(wl);
254 if (ret)
255 goto out_irq;
256
Teemu Paasikivi49d7f6d2010-02-22 08:38:29 +0200257 sdio_set_drvdata(func, wl);
258
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200259 wl1271_notice("initialized");
260
261 return 0;
262
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200263 out_irq:
264 free_irq(wl->irq, wl);
265
266
267 out_free:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +0200268 wl1271_free_hw(wl);
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200269
270 return ret;
271}
272
273static void __devexit wl1271_remove(struct sdio_func *func)
274{
275 struct wl1271 *wl = sdio_get_drvdata(func);
276
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200277 free_irq(wl->irq, wl);
278
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +0200279 wl1271_unregister_hw(wl);
Teemu Paasikivi801a6732010-03-18 12:26:42 +0200280 wl1271_free_hw(wl);
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200281}
282
283static struct sdio_driver wl1271_sdio_driver = {
Luciano Coelhof4b5d8d2010-04-01 11:38:17 +0300284 .name = "wl1271_sdio",
Teemu Paasikivi5129dff2010-02-22 08:38:27 +0200285 .id_table = wl1271_devices,
286 .probe = wl1271_probe,
287 .remove = __devexit_p(wl1271_remove),
288};
289
290static int __init wl1271_init(void)
291{
292 int ret;
293
294 ret = sdio_register_driver(&wl1271_sdio_driver);
295 if (ret < 0) {
296 wl1271_error("failed to register sdio driver: %d", ret);
297 goto out;
298 }
299
300out:
301 return ret;
302}
303
304static void __exit wl1271_exit(void)
305{
306 sdio_unregister_driver(&wl1271_sdio_driver);
307
308 wl1271_notice("unloaded");
309}
310
311module_init(wl1271_init);
312module_exit(wl1271_exit);
313
314MODULE_LICENSE("GPL");
315MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
316MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
317MODULE_FIRMWARE(WL1271_FW_NAME);