diff options
author | John W. Linville <linville@tuxdriver.com> | 2010-04-23 14:43:45 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-04-23 14:43:45 -0400 |
commit | 3b51cc996e81d8a113416d8094fa4a88f8360a51 (patch) | |
tree | e75b98b228bb4e456c30673fcc4b56ffa1d09cf5 /drivers/net/wireless/wl12xx | |
parent | c68ed255265968c3948fa2678bf59d15c471b055 (diff) | |
parent | 672724403b42da1d276c6cf811e8e34d15efd964 (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.c | 63 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_reg.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_sdio.c | 96 |
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 | ||
1199 | static 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 | |||
1222 | static 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 | |||
1239 | static 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 | |||
1199 | static int wl1251_register_hw(struct wl1251 *wl) | 1259 | static 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 | ||
40 | static struct wl12xx_platform_data *wl12xx_board_data; | ||
41 | |||
37 | static struct sdio_func *wl_to_func(struct wl1251 *wl) | 42 | static 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 */ | ||
139 | static 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 | |||
148 | static void wl1251_enable_line_irq(struct wl1251 *wl) | ||
149 | { | ||
150 | return enable_irq(wl->irq); | ||
151 | } | ||
152 | |||
153 | static void wl1251_disable_line_irq(struct wl1251 *wl) | ||
154 | { | ||
155 | return disable_irq(wl->irq); | ||
156 | } | ||
157 | |||
133 | static void wl1251_sdio_set_power(bool enable) | 158 | static void wl1251_sdio_set_power(bool enable) |
134 | { | 159 | { |
135 | } | 160 | } |
136 | 161 | ||
137 | static const struct wl1251_if_operations wl1251_sdio_ops = { | 162 | static 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 | |
170 | static 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 | */ | ||
186 | static 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 | ||
147 | static int wl1251_sdio_probe(struct sdio_func *func, | 194 | static 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 | ||
254 | out_free_irq: | ||
255 | if (wl->irq) | ||
256 | free_irq(wl->irq, wl); | ||
180 | disable: | 257 | disable: |
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) | |||
217 | static void __exit wl1251_sdio_exit(void) | 302 | static 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 | ||