diff options
author | Grazvydas Ignotas <notasas@gmail.com> | 2010-03-11 10:44:57 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-03-15 15:32:03 -0400 |
commit | 3f9e750d130b4a4d9f8226642b46ed17d8357f40 (patch) | |
tree | 761497200ae8a5c2ca0ac3b7ce9b9e44dde23533 /drivers/net | |
parent | 3c9cb9c38a1368b1e3f187f23c1a56883ec656c2 (diff) |
wl1251: fix ELP_CTRL register accesses when using SDIO
For some unknown reason ELP_CTRL can't be accesed using
sdio_memcpy_* functions (any attemts to do so result in timeouts):
wl1251: ERROR sdio write failed (-110)
wl1251: ERROR sdio read failed (-110)
wl1251: WARNING WLAN not ready
To fix this, add special IO functions for ELP_CTRL access that are
using sdio_readb/sdio_writeb. Similar handling is done in TI
reference driver from Android code drop.
Signed-off-by: Grazvydas Ignotas <notasas@gmail.com>
Cc: Bob Copeland <me@bobcopeland.com>
Acked-by: Kalle Valo <kalle.valo@iki.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_io.h | 20 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_main.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_ps.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_sdio.c | 28 |
5 files changed, 56 insertions, 6 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index 37c61c19cae5..4f5f02a26e62 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h | |||
@@ -256,6 +256,8 @@ struct wl1251_debugfs { | |||
256 | struct wl1251_if_operations { | 256 | struct wl1251_if_operations { |
257 | void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len); | 257 | void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len); |
258 | void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len); | 258 | void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len); |
259 | void (*read_elp)(struct wl1251 *wl, int addr, u32 *val); | ||
260 | void (*write_elp)(struct wl1251 *wl, int addr, u32 val); | ||
259 | void (*reset)(struct wl1251 *wl); | 261 | void (*reset)(struct wl1251 *wl); |
260 | void (*enable_irq)(struct wl1251 *wl); | 262 | void (*enable_irq)(struct wl1251 *wl); |
261 | void (*disable_irq)(struct wl1251 *wl); | 263 | void (*disable_irq)(struct wl1251 *wl); |
diff --git a/drivers/net/wireless/wl12xx/wl1251_io.h b/drivers/net/wireless/wl12xx/wl1251_io.h index b89d2ac62efb..c545e9d5f512 100644 --- a/drivers/net/wireless/wl12xx/wl1251_io.h +++ b/drivers/net/wireless/wl12xx/wl1251_io.h | |||
@@ -48,6 +48,26 @@ static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) | |||
48 | wl->if_ops->write(wl, addr, &val, sizeof(u32)); | 48 | wl->if_ops->write(wl, addr, &val, sizeof(u32)); |
49 | } | 49 | } |
50 | 50 | ||
51 | static inline u32 wl1251_read_elp(struct wl1251 *wl, int addr) | ||
52 | { | ||
53 | u32 response; | ||
54 | |||
55 | if (wl->if_ops->read_elp) | ||
56 | wl->if_ops->read_elp(wl, addr, &response); | ||
57 | else | ||
58 | wl->if_ops->read(wl, addr, &response, sizeof(u32)); | ||
59 | |||
60 | return response; | ||
61 | } | ||
62 | |||
63 | static inline void wl1251_write_elp(struct wl1251 *wl, int addr, u32 val) | ||
64 | { | ||
65 | if (wl->if_ops->write_elp) | ||
66 | wl->if_ops->write_elp(wl, addr, val); | ||
67 | else | ||
68 | wl->if_ops->write(wl, addr, &val, sizeof(u32)); | ||
69 | } | ||
70 | |||
51 | /* Memory target IO, address is translated to partition 0 */ | 71 | /* Memory target IO, address is translated to partition 0 */ |
52 | void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len); | 72 | void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len); |
53 | void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len); | 73 | void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len); |
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 24ae6a360ac8..0155653b7105 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c | |||
@@ -146,8 +146,8 @@ static void wl1251_fw_wakeup(struct wl1251 *wl) | |||
146 | u32 elp_reg; | 146 | u32 elp_reg; |
147 | 147 | ||
148 | elp_reg = ELPCTRL_WAKE_UP; | 148 | elp_reg = ELPCTRL_WAKE_UP; |
149 | wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); | 149 | wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); |
150 | elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); | 150 | elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); |
151 | 151 | ||
152 | if (!(elp_reg & ELPCTRL_WLAN_READY)) | 152 | if (!(elp_reg & ELPCTRL_WLAN_READY)) |
153 | wl1251_warning("WLAN not ready"); | 153 | wl1251_warning("WLAN not ready"); |
diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c index 851dfb65e474..b55cb2bd459a 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.c +++ b/drivers/net/wireless/wl12xx/wl1251_ps.c | |||
@@ -45,7 +45,7 @@ void wl1251_elp_work(struct work_struct *work) | |||
45 | goto out; | 45 | goto out; |
46 | 46 | ||
47 | wl1251_debug(DEBUG_PSM, "chip to elp"); | 47 | wl1251_debug(DEBUG_PSM, "chip to elp"); |
48 | wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); | 48 | wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); |
49 | wl->elp = true; | 49 | wl->elp = true; |
50 | 50 | ||
51 | out: | 51 | out: |
@@ -79,9 +79,9 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl) | |||
79 | start = jiffies; | 79 | start = jiffies; |
80 | timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT); | 80 | timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT); |
81 | 81 | ||
82 | wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); | 82 | wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); |
83 | 83 | ||
84 | elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); | 84 | elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); |
85 | 85 | ||
86 | /* | 86 | /* |
87 | * FIXME: we should wait for irq from chip but, as a temporary | 87 | * FIXME: we should wait for irq from chip but, as a temporary |
@@ -93,7 +93,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl) | |||
93 | return -ETIMEDOUT; | 93 | return -ETIMEDOUT; |
94 | } | 94 | } |
95 | msleep(1); | 95 | msleep(1); |
96 | elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); | 96 | elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); |
97 | } | 97 | } |
98 | 98 | ||
99 | wl1251_debug(DEBUG_PSM, "wakeup time: %u ms", | 99 | wl1251_debug(DEBUG_PSM, "wakeup time: %u ms", |
diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c index cfca232dc8cb..2051ef06e9ec 100644 --- a/drivers/net/wireless/wl12xx/wl1251_sdio.c +++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c | |||
@@ -82,6 +82,32 @@ static void wl1251_sdio_write(struct wl1251 *wl, int addr, | |||
82 | sdio_release_host(func); | 82 | sdio_release_host(func); |
83 | } | 83 | } |
84 | 84 | ||
85 | static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val) | ||
86 | { | ||
87 | int ret = 0; | ||
88 | struct sdio_func *func = wl_to_func(wl); | ||
89 | |||
90 | sdio_claim_host(func); | ||
91 | *val = sdio_readb(func, addr, &ret); | ||
92 | sdio_release_host(func); | ||
93 | |||
94 | if (ret) | ||
95 | wl1251_error("sdio_readb failed (%d)", ret); | ||
96 | } | ||
97 | |||
98 | static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val) | ||
99 | { | ||
100 | int ret = 0; | ||
101 | struct sdio_func *func = wl_to_func(wl); | ||
102 | |||
103 | sdio_claim_host(func); | ||
104 | sdio_writeb(func, val, addr, &ret); | ||
105 | sdio_release_host(func); | ||
106 | |||
107 | if (ret) | ||
108 | wl1251_error("sdio_writeb failed (%d)", ret); | ||
109 | } | ||
110 | |||
85 | static void wl1251_sdio_reset(struct wl1251 *wl) | 111 | static void wl1251_sdio_reset(struct wl1251 *wl) |
86 | { | 112 | { |
87 | } | 113 | } |
@@ -111,6 +137,8 @@ static void wl1251_sdio_set_power(bool enable) | |||
111 | static const struct wl1251_if_operations wl1251_sdio_ops = { | 137 | static const struct wl1251_if_operations wl1251_sdio_ops = { |
112 | .read = wl1251_sdio_read, | 138 | .read = wl1251_sdio_read, |
113 | .write = wl1251_sdio_write, | 139 | .write = wl1251_sdio_write, |
140 | .write_elp = wl1251_sdio_write_elp, | ||
141 | .read_elp = wl1251_sdio_read_elp, | ||
114 | .reset = wl1251_sdio_reset, | 142 | .reset = wl1251_sdio_reset, |
115 | .enable_irq = wl1251_sdio_enable_irq, | 143 | .enable_irq = wl1251_sdio_enable_irq, |
116 | .disable_irq = wl1251_sdio_disable_irq, | 144 | .disable_irq = wl1251_sdio_disable_irq, |