diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1251_sdio.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_sdio.c | 96 |
1 files changed, 91 insertions, 5 deletions
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 | ||