Commit 3f9e750d authored by Grazvydas Ignotas's avatar Grazvydas Ignotas Committed by John W. Linville

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: default avatarGrazvydas Ignotas <notasas@gmail.com>
Cc: Bob Copeland <me@bobcopeland.com>
Acked-by: default avatarKalle Valo <kalle.valo@iki.fi>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 3c9cb9c3
...@@ -256,6 +256,8 @@ struct wl1251_debugfs { ...@@ -256,6 +256,8 @@ struct wl1251_debugfs {
struct wl1251_if_operations { struct wl1251_if_operations {
void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len); void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len);
void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len); void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len);
void (*read_elp)(struct wl1251 *wl, int addr, u32 *val);
void (*write_elp)(struct wl1251 *wl, int addr, u32 val);
void (*reset)(struct wl1251 *wl); void (*reset)(struct wl1251 *wl);
void (*enable_irq)(struct wl1251 *wl); void (*enable_irq)(struct wl1251 *wl);
void (*disable_irq)(struct wl1251 *wl); void (*disable_irq)(struct wl1251 *wl);
......
...@@ -48,6 +48,26 @@ static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) ...@@ -48,6 +48,26 @@ static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val)
wl->if_ops->write(wl, addr, &val, sizeof(u32)); wl->if_ops->write(wl, addr, &val, sizeof(u32));
} }
static inline u32 wl1251_read_elp(struct wl1251 *wl, int addr)
{
u32 response;
if (wl->if_ops->read_elp)
wl->if_ops->read_elp(wl, addr, &response);
else
wl->if_ops->read(wl, addr, &response, sizeof(u32));
return response;
}
static inline void wl1251_write_elp(struct wl1251 *wl, int addr, u32 val)
{
if (wl->if_ops->write_elp)
wl->if_ops->write_elp(wl, addr, val);
else
wl->if_ops->write(wl, addr, &val, sizeof(u32));
}
/* Memory target IO, address is translated to partition 0 */ /* Memory target IO, address is translated to partition 0 */
void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len); void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len);
void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len); void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len);
......
...@@ -146,8 +146,8 @@ static void wl1251_fw_wakeup(struct wl1251 *wl) ...@@ -146,8 +146,8 @@ static void wl1251_fw_wakeup(struct wl1251 *wl)
u32 elp_reg; u32 elp_reg;
elp_reg = ELPCTRL_WAKE_UP; elp_reg = ELPCTRL_WAKE_UP;
wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
if (!(elp_reg & ELPCTRL_WLAN_READY)) if (!(elp_reg & ELPCTRL_WLAN_READY))
wl1251_warning("WLAN not ready"); wl1251_warning("WLAN not ready");
......
...@@ -45,7 +45,7 @@ void wl1251_elp_work(struct work_struct *work) ...@@ -45,7 +45,7 @@ void wl1251_elp_work(struct work_struct *work)
goto out; goto out;
wl1251_debug(DEBUG_PSM, "chip to elp"); wl1251_debug(DEBUG_PSM, "chip to elp");
wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
wl->elp = true; wl->elp = true;
out: out:
...@@ -79,9 +79,9 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl) ...@@ -79,9 +79,9 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)
start = jiffies; start = jiffies;
timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT); timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT);
wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
/* /*
* FIXME: we should wait for irq from chip but, as a temporary * 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,7 +93,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)
return -ETIMEDOUT; return -ETIMEDOUT;
} }
msleep(1); msleep(1);
elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
} }
wl1251_debug(DEBUG_PSM, "wakeup time: %u ms", wl1251_debug(DEBUG_PSM, "wakeup time: %u ms",
......
...@@ -82,6 +82,32 @@ static void wl1251_sdio_write(struct wl1251 *wl, int addr, ...@@ -82,6 +82,32 @@ static void wl1251_sdio_write(struct wl1251 *wl, int addr,
sdio_release_host(func); sdio_release_host(func);
} }
static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val)
{
int ret = 0;
struct sdio_func *func = wl_to_func(wl);
sdio_claim_host(func);
*val = sdio_readb(func, addr, &ret);
sdio_release_host(func);
if (ret)
wl1251_error("sdio_readb failed (%d)", ret);
}
static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val)
{
int ret = 0;
struct sdio_func *func = wl_to_func(wl);
sdio_claim_host(func);
sdio_writeb(func, val, addr, &ret);
sdio_release_host(func);
if (ret)
wl1251_error("sdio_writeb failed (%d)", ret);
}
static void wl1251_sdio_reset(struct wl1251 *wl) static void wl1251_sdio_reset(struct wl1251 *wl)
{ {
} }
...@@ -111,6 +137,8 @@ static void wl1251_sdio_set_power(bool enable) ...@@ -111,6 +137,8 @@ static void wl1251_sdio_set_power(bool enable)
static const struct wl1251_if_operations wl1251_sdio_ops = { static const struct wl1251_if_operations wl1251_sdio_ops = {
.read = wl1251_sdio_read, .read = wl1251_sdio_read,
.write = wl1251_sdio_write, .write = wl1251_sdio_write,
.write_elp = wl1251_sdio_write_elp,
.read_elp = wl1251_sdio_read_elp,
.reset = wl1251_sdio_reset, .reset = wl1251_sdio_reset,
.enable_irq = wl1251_sdio_enable_irq, .enable_irq = wl1251_sdio_enable_irq,
.disable_irq = wl1251_sdio_disable_irq, .disable_irq = wl1251_sdio_disable_irq,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment