aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGrazvydas Ignotas <notasas@gmail.com>2010-06-08 07:33:31 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-06-08 09:31:21 -0400
commit832c10fd733893f86c63bde1c65b005d5a2fe346 (patch)
tree4c46420f7a8ac9f0261205383489dea4b042d91c
parentabe37c4b84502d6931e04e94c9c2c45b4da8c889 (diff)
wl1251: fix ELP_CTRL register reads
Reading the ELP_CTRL register with sdio_readb causes problems because hardware seems to be performing a write using stuff bits in the request (those bits contain write data in write request). This indicates that it actually expects RAW (read after write) type of request, so perform that when reading ELP_CTRL instead. Also cache last written value so we know what to write when doing RAW request. Because of the above it was not possible to wake the chip from ELP power saving mode, PM had to be disabled to have the driver usable in SDIO mode. After this patch PM is functional. For backporting to 2.6.34 or earlier, this patch depends on 6c1f716e8154ee9315534782b9b1eedea0559a24, which adds the required SDIO funcion. Signed-off-by: Grazvydas Ignotas <notasas@gmail.com> Acked-by: Kalle Valo <kvalo@adurom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_sdio.c40
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
40struct wl1251_sdio {
41 struct sdio_func *func;
42 u32 elp_val;
43};
44
40static struct wl12xx_platform_data *wl12xx_board_data; 45static struct wl12xx_platform_data *wl12xx_board_data;
41 46
42static struct sdio_func *wl_to_func(struct wl1251 *wl) 47static 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
47static void wl1251_sdio_interrupt(struct sdio_func *func) 53static void wl1251_sdio_interrupt(struct sdio_func *func)
@@ -90,10 +96,17 @@ static void wl1251_sdio_write(struct wl1251 *wl, int addr,
90static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val) 96static 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)
103static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val) 116static 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
116static void wl1251_sdio_reset(struct wl1251 *wl) 132static 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);
260release: 284release:
261 sdio_release_host(func); 285 sdio_release_host(func);
286 kfree(wl_sdio);
287out_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:
266static void __devexit wl1251_sdio_remove(struct sdio_func *func) 292static 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);