static int msm_ssbi_read_bytes(struct msm_ssbi *ssbi, u16 addr, u8 *buf, int len) { u32 cmd = SSBI_CMD_RDWRN | ((addr & 0xff) << 16); int ret = 0; if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) { u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2); mode2 = SET_SSBI_MODE2_REG_ADDR_15_8(mode2, addr); ssbi_writel(ssbi, mode2, SSBI2_MODE2); } if (ssbi->controller_type == FSM_SBI_CTRL_SSBI) cmd = SSBI_FSM_CMD_READ(addr); else cmd = SSBI_CMD_RDWRN | ((addr & 0xff) << 16); while (len) { ret = ssbi_wait_mask(ssbi, SSBI_STATUS_READY, 0); if (ret) goto err; ssbi_writel(ssbi, cmd, SSBI2_CMD); ret = ssbi_wait_mask(ssbi, SSBI_STATUS_RD_READY, 0); if (ret) goto err; *buf++ = ssbi_readl(ssbi, SSBI2_RD) & 0xff; len--; } err: return ret; }
static inline int i2c_ssbi_pa_transfer(struct i2c_ssbi_dev *ssbi, u32 cmd, u8 *data) { u32 rd_status; u32 timeout = SSBI_TIMEOUT_US; ssbi_writel(ssbi, SSBI_PA_CMD, cmd); rd_status = ssbi_readl(ssbi, SSBI_PA_RD_STATUS); while ((rd_status & (SSBI_PA_RD_STATUS_TRANS_COMPLETE)) == 0) { if (--timeout == 0) { dev_err(ssbi->dev, "%s: timeout, status %x\n", __func__, rd_status); return -ETIMEDOUT; } udelay(1); rd_status = ssbi_readl(ssbi, SSBI_PA_RD_STATUS); } if (rd_status & SSBI_PA_RD_STATUS_TRANS_DENIED) { dev_err(ssbi->dev, "%s: transaction denied, status %x\n", __func__, rd_status); return -EPERM; } if (data) *data = (rd_status & SSBI_PA_RD_STATUS_REG_DATA_MASK) >> SSBI_PA_CMD_REG_DATA_SHFT; return 0; }
static int ssbi_wait_mask(struct msm_ssbi *ssbi, u32 set_mask, u32 clr_mask) { u32 timeout = SSBI_TIMEOUT_US; u32 val; while (timeout--) { val = ssbi_readl(ssbi, SSBI2_STATUS); if (((val & set_mask) == set_mask) && ((val & clr_mask) == 0)) return 0; udelay(1); } dev_err(ssbi->dev, "%s: timeout (status %x set_mask %x clr_mask %x)\n", __func__, ssbi_readl(ssbi, SSBI2_STATUS), set_mask, clr_mask); return -ETIMEDOUT; }
static inline int msm_ssbi_pa_transfer(struct msm_ssbi *ssbi, u32 cmd, u8 *data) { u32 timeout = SSBI_TIMEOUT_US; u32 rd_status = 0; ssbi_writel(ssbi, cmd, SSBI_PA_CMD); while (timeout--) { rd_status = ssbi_readl(ssbi, SSBI_PA_RD_STATUS); if (rd_status & SSBI_PA_RD_STATUS_TRANS_DENIED) { dev_err(ssbi->dev, "%s: transaction denied (0x%x)\n", __func__, rd_status); return -EPERM; } if (rd_status & SSBI_PA_RD_STATUS_TRANS_DONE) { if (data) *data = rd_status & 0xff; return 0; } udelay(1); } dev_err(ssbi->dev, "%s: timeout, status 0x%x\n", __func__, rd_status); return -ETIMEDOUT; }
static int msm_ssbi_write_bytes(struct msm_ssbi *ssbi, u16 addr, u8 *buf, int len) { int ret = 0; if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) { u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2); mode2 = SET_SSBI_MODE2_REG_ADDR_15_8(mode2, addr); ssbi_writel(ssbi, mode2, SSBI2_MODE2); } while (len) { ret = ssbi_wait_mask(ssbi, SSBI_STATUS_READY, 0); if (ret) goto err; if (ssbi->controller_type == FSM_SBI_CTRL_SSBI) ssbi_writel(ssbi, SSBI_FSM_CMD_WRITE(addr, *buf), SSBI2_CMD); else ssbi_writel(ssbi, ((addr & 0xff) << 16) | *buf, SSBI2_CMD); ret = ssbi_wait_mask(ssbi, 0, SSBI_STATUS_MCHN_BUSY); if (ret) goto err; buf++; len--; } err: return ret; }
static inline int i2c_ssbi_poll_for_transfer_completed(struct i2c_ssbi_dev *ssbi) { u32 timeout = SSBI_TIMEOUT_US; while ((ssbi_readl(ssbi, SSBI2_STATUS) & SSBI_STATUS_MCHN_BUSY)) { if (--timeout == 0) { dev_err(ssbi->dev, "%s: timeout, status %x\n", __func__, ssbi_readl(ssbi, SSBI2_STATUS)); return -ETIMEDOUT; } udelay(1); } return 0; }
static inline int i2c_ssbi_poll_for_device_ready(struct i2c_ssbi_dev *ssbi) { u32 timeout = SSBI_TIMEOUT_US; while (!(ssbi_readl(ssbi, SSBI2_STATUS) & SSBI_STATUS_READY)) { if (--timeout == 0) { dev_err(ssbi->dev, "%s: timeout, status %x\n", __func__, ssbi_readl(ssbi, SSBI2_STATUS)); return -ETIMEDOUT; } udelay(1); } return 0; }
static int i2c_ssbi_read_bytes(struct i2c_ssbi_dev *ssbi, struct i2c_msg *msg) { int ret = 0; u8 *buf = msg->buf; u16 len = msg->len; u16 addr = msg->addr; u32 read_cmd; if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) { u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2); ssbi_writel(ssbi, SSBI2_MODE2, SSBI_MODE2_REG_ADDR_15_8(mode2, addr)); } if (ssbi->controller_type == FSM_SBI_CTRL_SSBI) read_cmd = SSBI_FSM_CMD_READ(addr); else read_cmd = SSBI_CMD_READ(addr); while (len) { ret = i2c_ssbi_poll_for_device_ready(ssbi); if (ret) goto read_failed; ssbi_writel(ssbi, SSBI2_CMD, read_cmd); ret = i2c_ssbi_poll_for_read_completed(ssbi); if (ret) goto read_failed; *buf++ = ssbi_readl(ssbi, SSBI2_RD) & SSBI_RD_REG_DATA_MASK; len--; } read_failed: return ret; }
/* * Via private exchange with one of the original authors, the hardware * should generally finish a transaction in about 5us. The worst * case, is when using the arbiter and both other CPUs have just * started trying to use the SSBI bus will result in a time of about * 20us. It should never take longer than this. * * As such, this wait merely spins, with a udelay. */ static int ssbi_wait_mask(struct ssbi *ssbi, u32 set_mask, u32 clr_mask) { u32 timeout = SSBI_TIMEOUT_US; u32 val; while (timeout--) { val = ssbi_readl(ssbi, SSBI2_STATUS); if (((val & set_mask) == set_mask) && ((val & clr_mask) == 0)) return 0; udelay(1); } return -ETIMEDOUT; }
/* * See ssbi_wait_mask for an explanation of the time and the * busywait. */ static inline int ssbi_pa_transfer(struct ssbi *ssbi, u32 cmd, u8 *data) { u32 timeout = SSBI_TIMEOUT_US; u32 rd_status = 0; ssbi_writel(ssbi, cmd, SSBI_PA_CMD); while (timeout--) { rd_status = ssbi_readl(ssbi, SSBI_PA_RD_STATUS); if (rd_status & SSBI_PA_RD_STATUS_TRANS_DENIED) return -EPERM; if (rd_status & SSBI_PA_RD_STATUS_TRANS_DONE) { if (data) *data = rd_status & 0xff; return 0; } udelay(1); } return -ETIMEDOUT; }
static int i2c_ssbi_write_bytes(struct i2c_ssbi_dev *ssbi, struct i2c_msg *msg) { int ret = 0; u8 *buf = msg->buf; u16 len = msg->len; u16 addr = msg->addr; if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) { u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2); ssbi_writel(ssbi, SSBI2_MODE2, SSBI_MODE2_REG_ADDR_15_8(mode2, addr)); } while (len) { ret = i2c_ssbi_poll_for_device_ready(ssbi); if (ret) goto write_failed; if (ssbi->controller_type == FSM_SBI_CTRL_SSBI) ssbi_writel(ssbi, SSBI2_CMD, SSBI_FSM_CMD_WRITE(addr, *buf++)); else ssbi_writel(ssbi, SSBI2_CMD, SSBI_CMD_WRITE(addr, *buf++)); ret = i2c_ssbi_poll_for_transfer_completed(ssbi); if (ret) goto write_failed; len--; } write_failed: return ret; }