Skip to content

Commit

Permalink
ath6kl: move diag commands to hif driver
Browse files Browse the repository at this point in the history
This is preparation for USB support which will have different diag
commands.

Based on code by Kevin Fang.

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
  • Loading branch information
Kalle Valo committed Nov 13, 2011
1 parent 1f4c894 commit c711149
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 72 deletions.
20 changes: 20 additions & 0 deletions drivers/net/wireless/ath/ath6kl/hif-ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,26 @@ static inline int ath6kl_hif_suspend(struct ath6kl *ar,
return ar->hif_ops->suspend(ar, wow);
}

/*
* Read from the ATH6KL through its diagnostic window. No cooperation from
* the Target is required for this.
*/
static inline int ath6kl_hif_diag_read32(struct ath6kl *ar, u32 address,
u32 *value)
{
return ar->hif_ops->diag_read32(ar, address, value);
}

/*
* Write to the ATH6KL through its diagnostic window. No cooperation from
* the Target is required for this.
*/
static inline int ath6kl_hif_diag_write32(struct ath6kl *ar, u32 address,
__le32 value)
{
return ar->hif_ops->diag_write32(ar, address, value);
}

static inline int ath6kl_hif_bmi_read(struct ath6kl *ar, u8 *buf, u32 len)
{
return ar->hif_ops->bmi_read(ar, buf, len);
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/wireless/ath/ath6kl/hif.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,8 @@ struct ath6kl_hif_ops {
void (*cleanup_scatter)(struct ath6kl *ar);
int (*suspend)(struct ath6kl *ar, struct cfg80211_wowlan *wow);
int (*resume)(struct ath6kl *ar);
int (*diag_read32)(struct ath6kl *ar, u32 address, u32 *value);
int (*diag_write32)(struct ath6kl *ar, u32 address, __le32 value);
int (*bmi_read)(struct ath6kl *ar, u8 *buf, u32 len);
int (*bmi_write)(struct ath6kl *ar, u8 *buf, u32 len);
int (*power_on)(struct ath6kl *ar);
Expand Down
76 changes: 4 additions & 72 deletions drivers/net/wireless/ath/ath6kl/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,64 +175,6 @@ void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie)
ar->cookie_count++;
}

/* set the window address register (using 4-byte register access ). */
static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr)
{
int status;
s32 i;
__le32 addr_val;

/*
* Write bytes 1,2,3 of the register to set the upper address bytes,
* the LSB is written last to initiate the access cycle
*/

for (i = 1; i <= 3; i++) {
/*
* Fill the buffer with the address byte value we want to
* hit 4 times. No need to worry about endianness as the
* same byte is copied to all four bytes of addr_val at
* any time.
*/
memset((u8 *)&addr_val, ((u8 *)&addr)[i], 4);

/*
* Hit each byte of the register address with a 4-byte
* write operation to the same address, this is a harmless
* operation.
*/
status = hif_read_write_sync(ar, reg_addr + i, (u8 *)&addr_val,
4, HIF_WR_SYNC_BYTE_FIX);
if (status)
break;
}

if (status) {
ath6kl_err("failed to write initial bytes of 0x%x to window reg: 0x%X\n",
addr, reg_addr);
return status;
}

/*
* Write the address register again, this time write the whole
* 4-byte value. The effect here is that the LSB write causes the
* cycle to start, the extra 3 byte write to bytes 1,2,3 has no
* effect since we are writing the same values again
*/
addr_val = cpu_to_le32(addr);
status = hif_read_write_sync(ar, reg_addr,
(u8 *)&(addr_val),
4, HIF_WR_SYNC_BYTE_INC);

if (status) {
ath6kl_err("failed to write 0x%x to window reg: 0x%X\n",
addr, reg_addr);
return status;
}

return 0;
}

/*
* Read from the hardware through its diagnostic window. No cooperation
* from the firmware is required for this.
Expand All @@ -241,14 +183,7 @@ int ath6kl_diag_read32(struct ath6kl *ar, u32 address, u32 *value)
{
int ret;

/* set window register to start read cycle */
ret = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS, address);
if (ret)
return ret;

/* read the data */
ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) value,
sizeof(*value), HIF_RD_SYNC_BYTE_INC);
ret = ath6kl_hif_diag_read32(ar, address, value);
if (ret) {
ath6kl_warn("failed to read32 through diagnose window: %d\n",
ret);
Expand All @@ -266,18 +201,15 @@ int ath6kl_diag_write32(struct ath6kl *ar, u32 address, __le32 value)
{
int ret;

/* set write data */
ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) &value,
sizeof(value), HIF_WR_SYNC_BYTE_INC);
ret = ath6kl_hif_diag_write32(ar, address, value);

if (ret) {
ath6kl_err("failed to write 0x%x during diagnose window to 0x%d\n",
address, value);
return ret;
}

/* set window register, which starts the write cycle */
return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS,
address);
return 0;
}

int ath6kl_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length)
Expand Down
100 changes: 100 additions & 0 deletions drivers/net/wireless/ath/ath6kl/sdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,104 @@ static int ath6kl_sdio_resume(struct ath6kl *ar)
return 0;
}

/* set the window address register (using 4-byte register access ). */
static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr)
{
int status;
u8 addr_val[4];
s32 i;

/*
* Write bytes 1,2,3 of the register to set the upper address bytes,
* the LSB is written last to initiate the access cycle
*/

for (i = 1; i <= 3; i++) {
/*
* Fill the buffer with the address byte value we want to
* hit 4 times.
*/
memset(addr_val, ((u8 *)&addr)[i], 4);

/*
* Hit each byte of the register address with a 4-byte
* write operation to the same address, this is a harmless
* operation.
*/
status = ath6kl_sdio_read_write_sync(ar, reg_addr + i, addr_val,
4, HIF_WR_SYNC_BYTE_FIX);
if (status)
break;
}

if (status) {
ath6kl_err("%s: failed to write initial bytes of 0x%x "
"to window reg: 0x%X\n", __func__,
addr, reg_addr);
return status;
}

/*
* Write the address register again, this time write the whole
* 4-byte value. The effect here is that the LSB write causes the
* cycle to start, the extra 3 byte write to bytes 1,2,3 has no
* effect since we are writing the same values again
*/
status = ath6kl_sdio_read_write_sync(ar, reg_addr, (u8 *)(&addr),
4, HIF_WR_SYNC_BYTE_INC);

if (status) {
ath6kl_err("%s: failed to write 0x%x to window reg: 0x%X\n",
__func__, addr, reg_addr);
return status;
}

return 0;
}

static int ath6kl_sdio_diag_read32(struct ath6kl *ar, u32 address, u32 *data)
{
int status;

/* set window register to start read cycle */
status = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS,
address);

if (status)
return status;

/* read the data */
status = ath6kl_sdio_read_write_sync(ar, WINDOW_DATA_ADDRESS,
(u8 *)data, sizeof(u32), HIF_RD_SYNC_BYTE_INC);
if (status) {
ath6kl_err("%s: failed to read from window data addr\n",
__func__);
return status;
}

return status;
}

static int ath6kl_sdio_diag_write32(struct ath6kl *ar, u32 address,
__le32 data)
{
int status;
u32 val = (__force u32) data;

/* set write data */
status = ath6kl_sdio_read_write_sync(ar, WINDOW_DATA_ADDRESS,
(u8 *) &val, sizeof(u32), HIF_WR_SYNC_BYTE_INC);
if (status) {
ath6kl_err("%s: failed to write 0x%x to window data addr\n",
__func__, data);
return status;
}

/* set window register, which starts the write cycle */
return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS,
address);
}

static int ath6kl_sdio_bmi_credits(struct ath6kl *ar)
{
u32 addr;
Expand Down Expand Up @@ -1049,6 +1147,8 @@ static const struct ath6kl_hif_ops ath6kl_sdio_ops = {
.cleanup_scatter = ath6kl_sdio_cleanup_scatter,
.suspend = ath6kl_sdio_suspend,
.resume = ath6kl_sdio_resume,
.diag_read32 = ath6kl_sdio_diag_read32,
.diag_write32 = ath6kl_sdio_diag_write32,
.bmi_read = ath6kl_sdio_bmi_read,
.bmi_write = ath6kl_sdio_bmi_write,
.power_on = ath6kl_sdio_power_on,
Expand Down

0 comments on commit c711149

Please sign in to comment.