aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2010-04-23 14:43:45 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-04-23 14:43:45 -0400
commit3b51cc996e81d8a113416d8094fa4a88f8360a51 (patch)
treee75b98b228bb4e456c30673fcc4b56ffa1d09cf5 /drivers/net/wireless/wl12xx
parentc68ed255265968c3948fa2678bf59d15c471b055 (diff)
parent672724403b42da1d276c6cf811e8e34d15efd964 (diff)
Merge branch 'master' into for-davem
Conflicts: drivers/net/wireless/ath/ath9k/phy.c drivers/net/wireless/iwlwifi/iwl-6000.c drivers/net/wireless/iwlwifi/iwl-debugfs.c
Diffstat (limited to 'drivers/net/wireless/wl12xx')
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_main.c63
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_reg.h7
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_sdio.c96
3 files changed, 161 insertions, 5 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c
index 4d479708158d..51614d181ccb 100644
--- a/drivers/net/wireless/wl12xx/wl1251_main.c
+++ b/drivers/net/wireless/wl12xx/wl1251_main.c
@@ -1196,6 +1196,66 @@ static const struct ieee80211_ops wl1251_ops = {
1196 .conf_tx = wl1251_op_conf_tx, 1196 .conf_tx = wl1251_op_conf_tx,
1197}; 1197};
1198 1198
1199static int wl1251_read_eeprom_byte(struct wl1251 *wl, off_t offset, u8 *data)
1200{
1201 unsigned long timeout;
1202
1203 wl1251_reg_write32(wl, EE_ADDR, offset);
1204 wl1251_reg_write32(wl, EE_CTL, EE_CTL_READ);
1205
1206 /* EE_CTL_READ clears when data is ready */
1207 timeout = jiffies + msecs_to_jiffies(100);
1208 while (1) {
1209 if (!(wl1251_reg_read32(wl, EE_CTL) & EE_CTL_READ))
1210 break;
1211
1212 if (time_after(jiffies, timeout))
1213 return -ETIMEDOUT;
1214
1215 msleep(1);
1216 }
1217
1218 *data = wl1251_reg_read32(wl, EE_DATA);
1219 return 0;
1220}
1221
1222static int wl1251_read_eeprom(struct wl1251 *wl, off_t offset,
1223 u8 *data, size_t len)
1224{
1225 size_t i;
1226 int ret;
1227
1228 wl1251_reg_write32(wl, EE_START, 0);
1229
1230 for (i = 0; i < len; i++) {
1231 ret = wl1251_read_eeprom_byte(wl, offset + i, &data[i]);
1232 if (ret < 0)
1233 return ret;
1234 }
1235
1236 return 0;
1237}
1238
1239static int wl1251_read_eeprom_mac(struct wl1251 *wl)
1240{
1241 u8 mac[ETH_ALEN];
1242 int i, ret;
1243
1244 wl1251_set_partition(wl, 0, 0, REGISTERS_BASE, REGISTERS_DOWN_SIZE);
1245
1246 ret = wl1251_read_eeprom(wl, 0x1c, mac, sizeof(mac));
1247 if (ret < 0) {
1248 wl1251_warning("failed to read MAC address from EEPROM");
1249 return ret;
1250 }
1251
1252 /* MAC is stored in reverse order */
1253 for (i = 0; i < ETH_ALEN; i++)
1254 wl->mac_addr[i] = mac[ETH_ALEN - i - 1];
1255
1256 return 0;
1257}
1258
1199static int wl1251_register_hw(struct wl1251 *wl) 1259static int wl1251_register_hw(struct wl1251 *wl)
1200{ 1260{
1201 int ret; 1261 int ret;
@@ -1242,6 +1302,9 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
1242 1302
1243 wl->hw->queues = 4; 1303 wl->hw->queues = 4;
1244 1304
1305 if (wl->use_eeprom)
1306 wl1251_read_eeprom_mac(wl);
1307
1245 ret = wl1251_register_hw(wl); 1308 ret = wl1251_register_hw(wl);
1246 if (ret) 1309 if (ret)
1247 goto out; 1310 goto out;
diff --git a/drivers/net/wireless/wl12xx/wl1251_reg.h b/drivers/net/wireless/wl12xx/wl1251_reg.h
index 0ca3b4326056..d16edd9bf06c 100644
--- a/drivers/net/wireless/wl12xx/wl1251_reg.h
+++ b/drivers/net/wireless/wl12xx/wl1251_reg.h
@@ -46,7 +46,14 @@
46#define SOR_CFG (REGISTERS_BASE + 0x0800) 46#define SOR_CFG (REGISTERS_BASE + 0x0800)
47#define ECPU_CTRL (REGISTERS_BASE + 0x0804) 47#define ECPU_CTRL (REGISTERS_BASE + 0x0804)
48#define HI_CFG (REGISTERS_BASE + 0x0808) 48#define HI_CFG (REGISTERS_BASE + 0x0808)
49
50/* EEPROM registers */
49#define EE_START (REGISTERS_BASE + 0x080C) 51#define EE_START (REGISTERS_BASE + 0x080C)
52#define EE_CTL (REGISTERS_BASE + 0x2000)
53#define EE_DATA (REGISTERS_BASE + 0x2004)
54#define EE_ADDR (REGISTERS_BASE + 0x2008)
55
56#define EE_CTL_READ 2
50 57
51#define CHIP_ID_B (REGISTERS_BASE + 0x5674) 58#define CHIP_ID_B (REGISTERS_BASE + 0x5674)
52 59
diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c
index 2051ef06e9ec..d234285c2c81 100644
--- a/drivers/net/wireless/wl12xx/wl1251_sdio.c
+++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c
@@ -23,6 +23,9 @@
23#include <linux/mod_devicetable.h> 23#include <linux/mod_devicetable.h>
24#include <linux/mmc/sdio_func.h> 24#include <linux/mmc/sdio_func.h>
25#include <linux/mmc/sdio_ids.h> 25#include <linux/mmc/sdio_ids.h>
26#include <linux/platform_device.h>
27#include <linux/spi/wl12xx.h>
28#include <linux/irq.h>
26 29
27#include "wl1251.h" 30#include "wl1251.h"
28 31
@@ -34,6 +37,8 @@
34#define SDIO_DEVICE_ID_TI_WL1251 0x9066 37#define SDIO_DEVICE_ID_TI_WL1251 0x9066
35#endif 38#endif
36 39
40static struct wl12xx_platform_data *wl12xx_board_data;
41
37static struct sdio_func *wl_to_func(struct wl1251 *wl) 42static struct sdio_func *wl_to_func(struct wl1251 *wl)
38{ 43{
39 return wl->if_priv; 44 return wl->if_priv;
@@ -130,18 +135,60 @@ static void wl1251_sdio_disable_irq(struct wl1251 *wl)
130 sdio_release_host(func); 135 sdio_release_host(func);
131} 136}
132 137
138/* Interrupts when using dedicated WLAN_IRQ pin */
139static irqreturn_t wl1251_line_irq(int irq, void *cookie)
140{
141 struct wl1251 *wl = cookie;
142
143 ieee80211_queue_work(wl->hw, &wl->irq_work);
144
145 return IRQ_HANDLED;
146}
147
148static void wl1251_enable_line_irq(struct wl1251 *wl)
149{
150 return enable_irq(wl->irq);
151}
152
153static void wl1251_disable_line_irq(struct wl1251 *wl)
154{
155 return disable_irq(wl->irq);
156}
157
133static void wl1251_sdio_set_power(bool enable) 158static void wl1251_sdio_set_power(bool enable)
134{ 159{
135} 160}
136 161
137static const struct wl1251_if_operations wl1251_sdio_ops = { 162static struct wl1251_if_operations wl1251_sdio_ops = {
138 .read = wl1251_sdio_read, 163 .read = wl1251_sdio_read,
139 .write = wl1251_sdio_write, 164 .write = wl1251_sdio_write,
140 .write_elp = wl1251_sdio_write_elp, 165 .write_elp = wl1251_sdio_write_elp,
141 .read_elp = wl1251_sdio_read_elp, 166 .read_elp = wl1251_sdio_read_elp,
142 .reset = wl1251_sdio_reset, 167 .reset = wl1251_sdio_reset,
143 .enable_irq = wl1251_sdio_enable_irq, 168};
144 .disable_irq = wl1251_sdio_disable_irq, 169
170static int wl1251_platform_probe(struct platform_device *pdev)
171{
172 if (pdev->id != -1) {
173 wl1251_error("can only handle single device");
174 return -ENODEV;
175 }
176
177 wl12xx_board_data = pdev->dev.platform_data;
178 return 0;
179}
180
181/*
182 * Dummy platform_driver for passing platform_data to this driver,
183 * until we have a way to pass this through SDIO subsystem or
184 * some other way.
185 */
186static struct platform_driver wl1251_platform_driver = {
187 .driver = {
188 .name = "wl1251_data",
189 .owner = THIS_MODULE,
190 },
191 .probe = wl1251_platform_probe,
145}; 192};
146 193
147static int wl1251_sdio_probe(struct sdio_func *func, 194static int wl1251_sdio_probe(struct sdio_func *func,
@@ -163,20 +210,50 @@ static int wl1251_sdio_probe(struct sdio_func *func,
163 goto release; 210 goto release;
164 211
165 sdio_set_block_size(func, 512); 212 sdio_set_block_size(func, 512);
213 sdio_release_host(func);
166 214
167 SET_IEEE80211_DEV(hw, &func->dev); 215 SET_IEEE80211_DEV(hw, &func->dev);
168 wl->if_priv = func; 216 wl->if_priv = func;
169 wl->if_ops = &wl1251_sdio_ops; 217 wl->if_ops = &wl1251_sdio_ops;
170 wl->set_power = wl1251_sdio_set_power; 218 wl->set_power = wl1251_sdio_set_power;
171 219
172 sdio_release_host(func); 220 if (wl12xx_board_data != NULL) {
221 wl->set_power = wl12xx_board_data->set_power;
222 wl->irq = wl12xx_board_data->irq;
223 wl->use_eeprom = wl12xx_board_data->use_eeprom;
224 }
225
226 if (wl->irq) {
227 ret = request_irq(wl->irq, wl1251_line_irq, 0, "wl1251", wl);
228 if (ret < 0) {
229 wl1251_error("request_irq() failed: %d", ret);
230 goto disable;
231 }
232
233 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
234 disable_irq(wl->irq);
235
236 wl1251_sdio_ops.enable_irq = wl1251_enable_line_irq;
237 wl1251_sdio_ops.disable_irq = wl1251_disable_line_irq;
238
239 wl1251_info("using dedicated interrupt line");
240 } else {
241 wl1251_sdio_ops.enable_irq = wl1251_sdio_enable_irq;
242 wl1251_sdio_ops.disable_irq = wl1251_sdio_disable_irq;
243
244 wl1251_info("using SDIO interrupt");
245 }
246
173 ret = wl1251_init_ieee80211(wl); 247 ret = wl1251_init_ieee80211(wl);
174 if (ret) 248 if (ret)
175 goto disable; 249 goto out_free_irq;
176 250
177 sdio_set_drvdata(func, wl); 251 sdio_set_drvdata(func, wl);
178 return ret; 252 return ret;
179 253
254out_free_irq:
255 if (wl->irq)
256 free_irq(wl->irq, wl);
180disable: 257disable:
181 sdio_claim_host(func); 258 sdio_claim_host(func);
182 sdio_disable_func(func); 259 sdio_disable_func(func);
@@ -189,6 +266,8 @@ static void __devexit wl1251_sdio_remove(struct sdio_func *func)
189{ 266{
190 struct wl1251 *wl = sdio_get_drvdata(func); 267 struct wl1251 *wl = sdio_get_drvdata(func);
191 268
269 if (wl->irq)
270 free_irq(wl->irq, wl);
192 wl1251_free_hw(wl); 271 wl1251_free_hw(wl);
193 272
194 sdio_claim_host(func); 273 sdio_claim_host(func);
@@ -208,6 +287,12 @@ static int __init wl1251_sdio_init(void)
208{ 287{
209 int err; 288 int err;
210 289
290 err = platform_driver_register(&wl1251_platform_driver);
291 if (err) {
292 wl1251_error("failed to register platform driver: %d", err);
293 return err;
294 }
295
211 err = sdio_register_driver(&wl1251_sdio_driver); 296 err = sdio_register_driver(&wl1251_sdio_driver);
212 if (err) 297 if (err)
213 wl1251_error("failed to register sdio driver: %d", err); 298 wl1251_error("failed to register sdio driver: %d", err);
@@ -217,6 +302,7 @@ static int __init wl1251_sdio_init(void)
217static void __exit wl1251_sdio_exit(void) 302static void __exit wl1251_sdio_exit(void)
218{ 303{
219 sdio_unregister_driver(&wl1251_sdio_driver); 304 sdio_unregister_driver(&wl1251_sdio_driver);
305 platform_driver_unregister(&wl1251_platform_driver);
220 wl1251_notice("unloaded"); 306 wl1251_notice("unloaded");
221} 307}
222 308