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>
This commit is contained in:
parent
3c9cb9c38a
commit
3f9e750d13
5 changed files with 56 additions and 6 deletions
|
@ -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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
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)
|
||||||
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,
|
||||||
|
|
Loading…
Reference in a new issue