diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_sdio.c | 40 |
1 files changed, 34 insertions, 6 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c index c561332e7009..b901b6135654 100644 --- a/drivers/net/wireless/wl12xx/wl1251_sdio.c +++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c | |||
@@ -37,11 +37,17 @@ | |||
37 | #define SDIO_DEVICE_ID_TI_WL1251 0x9066 | 37 | #define SDIO_DEVICE_ID_TI_WL1251 0x9066 |
38 | #endif | 38 | #endif |
39 | 39 | ||
40 | struct wl1251_sdio { | ||
41 | struct sdio_func *func; | ||
42 | u32 elp_val; | ||
43 | }; | ||
44 | |||
40 | static struct wl12xx_platform_data *wl12xx_board_data; | 45 | static struct wl12xx_platform_data *wl12xx_board_data; |
41 | 46 | ||
42 | static struct sdio_func *wl_to_func(struct wl1251 *wl) | 47 | static struct sdio_func *wl_to_func(struct wl1251 *wl) |
43 | { | 48 | { |
44 | return wl->if_priv; | 49 | struct wl1251_sdio *wl_sdio = wl->if_priv; |
50 | return wl_sdio->func; | ||
45 | } | 51 | } |
46 | 52 | ||
47 | static void wl1251_sdio_interrupt(struct sdio_func *func) | 53 | static void wl1251_sdio_interrupt(struct sdio_func *func) |
@@ -90,10 +96,17 @@ static void wl1251_sdio_write(struct wl1251 *wl, int addr, | |||
90 | static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val) | 96 | static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val) |
91 | { | 97 | { |
92 | int ret = 0; | 98 | int ret = 0; |
93 | struct sdio_func *func = wl_to_func(wl); | 99 | struct wl1251_sdio *wl_sdio = wl->if_priv; |
94 | 100 | struct sdio_func *func = wl_sdio->func; | |
101 | |||
102 | /* | ||
103 | * The hardware only supports RAW (read after write) access for | ||
104 | * reading, regular sdio_readb won't work here (it interprets | ||
105 | * the unused bits of CMD52 as write data even if we send read | ||
106 | * request). | ||
107 | */ | ||
95 | sdio_claim_host(func); | 108 | sdio_claim_host(func); |
96 | *val = sdio_readb(func, addr, &ret); | 109 | *val = sdio_writeb_readb(func, wl_sdio->elp_val, addr, &ret); |
97 | sdio_release_host(func); | 110 | sdio_release_host(func); |
98 | 111 | ||
99 | if (ret) | 112 | if (ret) |
@@ -103,7 +116,8 @@ static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val) | |||
103 | static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val) | 116 | static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val) |
104 | { | 117 | { |
105 | int ret = 0; | 118 | int ret = 0; |
106 | struct sdio_func *func = wl_to_func(wl); | 119 | struct wl1251_sdio *wl_sdio = wl->if_priv; |
120 | struct sdio_func *func = wl_sdio->func; | ||
107 | 121 | ||
108 | sdio_claim_host(func); | 122 | sdio_claim_host(func); |
109 | sdio_writeb(func, val, addr, &ret); | 123 | sdio_writeb(func, val, addr, &ret); |
@@ -111,6 +125,8 @@ static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val) | |||
111 | 125 | ||
112 | if (ret) | 126 | if (ret) |
113 | wl1251_error("sdio_writeb failed (%d)", ret); | 127 | wl1251_error("sdio_writeb failed (%d)", ret); |
128 | else | ||
129 | wl_sdio->elp_val = val; | ||
114 | } | 130 | } |
115 | 131 | ||
116 | static void wl1251_sdio_reset(struct wl1251 *wl) | 132 | static void wl1251_sdio_reset(struct wl1251 *wl) |
@@ -197,6 +213,7 @@ static int wl1251_sdio_probe(struct sdio_func *func, | |||
197 | int ret; | 213 | int ret; |
198 | struct wl1251 *wl; | 214 | struct wl1251 *wl; |
199 | struct ieee80211_hw *hw; | 215 | struct ieee80211_hw *hw; |
216 | struct wl1251_sdio *wl_sdio; | ||
200 | 217 | ||
201 | hw = wl1251_alloc_hw(); | 218 | hw = wl1251_alloc_hw(); |
202 | if (IS_ERR(hw)) | 219 | if (IS_ERR(hw)) |
@@ -204,6 +221,12 @@ static int wl1251_sdio_probe(struct sdio_func *func, | |||
204 | 221 | ||
205 | wl = hw->priv; | 222 | wl = hw->priv; |
206 | 223 | ||
224 | wl_sdio = kzalloc(sizeof(*wl_sdio), GFP_KERNEL); | ||
225 | if (wl_sdio == NULL) { | ||
226 | ret = -ENOMEM; | ||
227 | goto out_free_hw; | ||
228 | } | ||
229 | |||
207 | sdio_claim_host(func); | 230 | sdio_claim_host(func); |
208 | ret = sdio_enable_func(func); | 231 | ret = sdio_enable_func(func); |
209 | if (ret) | 232 | if (ret) |
@@ -213,7 +236,8 @@ static int wl1251_sdio_probe(struct sdio_func *func, | |||
213 | sdio_release_host(func); | 236 | sdio_release_host(func); |
214 | 237 | ||
215 | SET_IEEE80211_DEV(hw, &func->dev); | 238 | SET_IEEE80211_DEV(hw, &func->dev); |
216 | wl->if_priv = func; | 239 | wl_sdio->func = func; |
240 | wl->if_priv = wl_sdio; | ||
217 | wl->if_ops = &wl1251_sdio_ops; | 241 | wl->if_ops = &wl1251_sdio_ops; |
218 | wl->set_power = wl1251_sdio_set_power; | 242 | wl->set_power = wl1251_sdio_set_power; |
219 | 243 | ||
@@ -259,6 +283,8 @@ disable: | |||
259 | sdio_disable_func(func); | 283 | sdio_disable_func(func); |
260 | release: | 284 | release: |
261 | sdio_release_host(func); | 285 | sdio_release_host(func); |
286 | kfree(wl_sdio); | ||
287 | out_free_hw: | ||
262 | wl1251_free_hw(wl); | 288 | wl1251_free_hw(wl); |
263 | return ret; | 289 | return ret; |
264 | } | 290 | } |
@@ -266,9 +292,11 @@ release: | |||
266 | static void __devexit wl1251_sdio_remove(struct sdio_func *func) | 292 | static void __devexit wl1251_sdio_remove(struct sdio_func *func) |
267 | { | 293 | { |
268 | struct wl1251 *wl = sdio_get_drvdata(func); | 294 | struct wl1251 *wl = sdio_get_drvdata(func); |
295 | struct wl1251_sdio *wl_sdio = wl->if_priv; | ||
269 | 296 | ||
270 | if (wl->irq) | 297 | if (wl->irq) |
271 | free_irq(wl->irq, wl); | 298 | free_irq(wl->irq, wl); |
299 | kfree(wl_sdio); | ||
272 | wl1251_free_hw(wl); | 300 | wl1251_free_hw(wl); |
273 | 301 | ||
274 | sdio_claim_host(func); | 302 | sdio_claim_host(func); |