struct hw_params {
u16 thigh; /* HIGH period of the SCL clock in clock ticks */
u16 tlow; /* LOW period of the SCL clock */
u16 tsu_sto; /* set-up time for STOP condition */
u16 tsu_sta; /* set-up time for a repeated START condition */
u16 thd_dat; /* data hold time */
u16 thd_sta; /* hold time (repeated) START condition */
u16 tbuf; /* bus free time between a STOP and START condition */
u8 scl_stretch_en;
u16 trdhld;
u16 tsp; /* pulse width of spikes suppressed by the input filter */
};
struct cci;
struct cci_master { struct i2c_adapter adap;
u16 master;
u8 mode; int status; struct completion irq_complete; struct cci *cci;
};
if (val & CCI_IRQ_STATUS_0_RST_DONE_ACK) {
complete(&cci->master[0].irq_complete); if (cci->master[1].master)
complete(&cci->master[1].irq_complete);
ret = IRQ_HANDLED;
}
if (val & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE ||
val & CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT ||
val & CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT) {
cci->master[0].status = 0;
complete(&cci->master[0].irq_complete);
ret = IRQ_HANDLED;
}
if (val & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE ||
val & CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT ||
val & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT) {
cci->master[1].status = 0;
complete(&cci->master[1].irq_complete);
ret = IRQ_HANDLED;
}
if (unlikely(val & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK)) {
reset = CCI_RESET_CMD_M0_MASK;
ret = IRQ_HANDLED;
}
if (unlikely(val & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK)) {
reset = CCI_RESET_CMD_M1_MASK;
ret = IRQ_HANDLED;
}
if (unlikely(reset))
writel(reset, cci->base + CCI_RESET_CMD);
if (unlikely(val & CCI_IRQ_STATUS_0_I2C_M0_ERROR)) { if (val & CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERR ||
val & CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERR)
cci->master[0].status = -ENXIO; else
cci->master[0].status = -EIO;
writel(CCI_HALT_REQ_I2C_M0_Q0Q1, cci->base + CCI_HALT_REQ);
ret = IRQ_HANDLED;
}
if (unlikely(val & CCI_IRQ_STATUS_0_I2C_M1_ERROR)) { if (val & CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERR ||
val & CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERR)
cci->master[1].status = -ENXIO; else
cci->master[1].status = -EIO;
writel(CCI_HALT_REQ_I2C_M1_Q0Q1, cci->base + CCI_HALT_REQ);
ret = IRQ_HANDLED;
}
if (!wait_for_completion_timeout(&master->irq_complete, CCI_TIMEOUT)) {
dev_err(cci->dev, "CCI halt timeout\n"); return -ETIMEDOUT;
}
return 0;
}
staticint cci_reset(struct cci *cci)
{ /* * we reset the whole controller, here and for implicity use * master[0].xxx for waiting on it.
*/
reinit_completion(&cci->master[0].irq_complete);
writel(CCI_RESET_CMD_MASK, cci->base + CCI_RESET_CMD);
val = readl(cci->base + CCI_I2C_Mm_Qn_CUR_WORD_CNT(master, queue)); if (val == cci->data->queue_size[queue]) return -EINVAL;
if (!val) return 0;
val = CCI_I2C_REPORT | CCI_I2C_REPORT_IRQ_EN;
writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue));
return cci_run_queue(cci, master, queue);
}
staticint cci_i2c_read(struct cci *cci, u16 master,
u16 addr, u8 *buf, u16 len)
{
u32 val, words_read, words_exp;
u8 queue = QUEUE_1; int i, index = 0, ret; bool first = true;
/* * Call validate queue to make sure queue is empty before starting. * This is to avoid overflow / underflow of queue.
*/
ret = cci_validate_queue(cci, master, queue); if (ret < 0) return ret;
do {
val = readl(cci->base + CCI_I2C_Mm_READ_DATA(master));
for (i = 0; i < 4 && index < len; i++) { if (first) { /* The LS byte of this register represents the * first byte read from the slave during a read * access.
*/
first = false; continue;
}
buf[index++] = (val >> (i * 8)) & 0xff;
}
} while (--words_read);
/* * Call validate queue to make sure queue is empty before starting. * This is to avoid overflow / underflow of queue.
*/
ret = cci_validate_queue(cci, master, queue); if (ret < 0) return ret;
for (j = 0; j < i; j += 4) {
val = load[j];
val |= load[j + 1] << 8;
val |= load[j + 2] << 16;
val |= load[j + 3] << 24;
writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue));
}
val = CCI_I2C_REPORT | CCI_I2C_REPORT_IRQ_EN;
writel(val, cci->base + CCI_I2C_Mm_Qn_LOAD_DATA(master, queue));
return cci_run_queue(cci, master, queue);
}
staticint cci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{ struct cci_master *cci_master = i2c_get_adapdata(adap); struct cci *cci = cci_master->cci; int i, ret;
ret = pm_runtime_get_sync(cci->dev); if (ret < 0) goto err;
for (i = 0; i < num; i++) { if (msgs[i].flags & I2C_M_RD)
ret = cci_i2c_read(cci, cci_master->master,
msgs[i].addr, msgs[i].buf,
msgs[i].len); else
ret = cci_i2c_write(cci, cci_master->master,
msgs[i].addr, msgs[i].buf,
msgs[i].len);
for (--i ; i >= 0; i--) { if (cci->master[i].cci) {
i2c_del_adapter(&cci->master[i].adap);
of_node_put(cci->master[i].adap.dev.of_node);
}
}
error:
disable_irq(cci->irq);
disable_clocks:
cci_disable_clocks(cci);
return ret;
}
staticvoid cci_remove(struct platform_device *pdev)
{ struct cci *cci = platform_get_drvdata(pdev); int i;
for (i = 0; i < cci->data->num_masters; i++) { if (cci->master[i].cci) {
i2c_del_adapter(&cci->master[i].adap);
of_node_put(cci->master[i].adap.dev.of_node);
}
cci_halt(cci, i);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.