it83xx: i2c: remove instructions that aren't necessary

- To i2c channel(d/e/f), we remove instructions that aren't necessary.
- Changes of i2c_reset():
  Before the change, we try to send a START/STOP bit if we get a reset.
  But i2c_unwedge() already done it, so we just need reset i2c module
  in i2c_reset().
- Add enhanced_i2c_start() to channel(d/e/f) for each transaction start:
  We prepare transaction start by calling i2c_reset(),
  but this doesn't match the definition of i2c_reset(),
  so we correct it.

BRANCH=none
BUG=none
TEST=1. console commands: "i2cscan", "charger" and "battery".
     2. sensors, battery, charger and mux work on reef_it8320.

Change-Id: I4e3595479e04a5994a5b19409cfc4e9a46f63d4f
Signed-off-by: Dino Li <Dino.Li@ite.com.tw>
Reviewed-on: https://chromium-review.googlesource.com/674467
Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
Dino Li
2017-09-20 10:58:50 +08:00
committed by chrome-bot
parent b440a0d099
commit dc8a8767fa
2 changed files with 93 additions and 227 deletions

View File

@@ -49,8 +49,13 @@ enum i2c_host_status {
HOSTA_TMOE = 0x40,
/* Byte done status */
HOSTA_BDS = 0x80,
HOSTA_NO_FINISH = 0xFF,
/* Error bit is set */
HOSTA_ANY_ERROR = (HOSTA_DVER | HOSTA_BSER |
HOSTA_FAIL | HOSTA_NACK | HOSTA_TMOE),
/* W/C for next byte */
HOSTA_NEXT_BYTE = HOSTA_BDS,
/* W/C host status register */
HOSTA_ALL_WC_BIT = (HOSTA_FINTR | HOSTA_ANY_ERROR | HOSTA_BDS),
};
enum enhanced_i2c_host_status {
@@ -70,8 +75,10 @@ enum enhanced_i2c_host_status {
E_HOSTA_AM = 0x40,
/* Byte done status */
E_HOSTA_BDS = 0x80,
E_HOSTA_NO_FINISH = 0xFF,
/* time out or lost arbitration */
E_HOSTA_ANY_ERROR = (E_HOSTA_TMOE | E_HOSTA_ARB),
/* Byte transfer done and ACK receive */
E_HOSTA_BDS_AND_ACK = (E_HOSTA_BDS | E_HOSTA_ACK),
};
enum enhanced_i2c_ctl {
@@ -91,22 +98,14 @@ enum enhanced_i2c_ctl {
E_INT_EN = 0x40,
/* 0 : Standard mode , 1 : Receive mode */
E_RX_MODE = 0x80,
/* State reset and hardware reset */
E_STS_AND_HW_RST = (E_STS_RST | E_HW_RST),
/* Generate start condition and transmit slave address */
E_START_ID = (E_INT_EN | E_MODE_SEL | E_ACK | E_START | E_HW_RST),
/* Generate stop condition */
E_FINISH = (E_INT_EN | E_MODE_SEL | E_ACK | E_STOP | E_HW_RST),
};
enum i2c_host_status_mask {
HOSTA_ANY_ERROR = (HOSTA_DVER | HOSTA_BSER |
HOSTA_FAIL | HOSTA_NACK | HOSTA_TMOE),
HOSTA_NEXT_BYTE = HOSTA_BDS,
HOSTA_ALL_WC_BIT = (HOSTA_FINTR | HOSTA_ANY_ERROR | HOSTA_BDS),
};
enum enhanced_i2c_host_status_mask {
E_HOSTA_ANY_ERROR = (E_HOSTA_TMOE | E_HOSTA_ARB),
E_HOSTA_NEXT_BYTE = E_HOSTA_BDS,
};
enum i2c_reset_cause {
I2C_RC_NO_IDLE_FOR_START = 1,
I2C_RC_TIMEOUT,
@@ -237,64 +236,17 @@ static void i2c_reset(int p, int cause)
if (p < I2C_STANDARD_PORT_COUNT) {
/* bit1, kill current transaction. */
IT83XX_SMB_HOCTL(p) |= 0x02;
IT83XX_SMB_HOCTL(p) &= ~0x02;
/* Disable the SMBus host interface */
IT83XX_SMB_HOCTL2(p) = 0x00;
/* clk pin output high */
*i2c_pin_regs[p].pin_clk = 0x40;
*i2c_pin_regs[p].pin_clk_ctrl |= i2c_pin_regs[p].clk_mask;
udelay(16);
/* data pin output high */
*i2c_pin_regs[p].pin_data = 0x40;
*i2c_pin_regs[p].pin_data_ctrl |= i2c_pin_regs[p].data_mask;
udelay(500);
/* start condition */
*i2c_pin_regs[p].pin_data_ctrl &= ~i2c_pin_regs[p].data_mask;
udelay(1000);
/* stop condition */
*i2c_pin_regs[p].pin_data_ctrl |= i2c_pin_regs[p].data_mask;
udelay(500);
/* I2C function */
*i2c_pin_regs[p].pin_clk = 0x00;
*i2c_pin_regs[p].pin_data = 0x00;
/* Enable the SMBus host interface */
IT83XX_SMB_HOCTL2(p) = 0x11;
IT83XX_SMB_HOCTL(p) = 0x2;
IT83XX_SMB_HOCTL(p) = 0;
/* W/C host status register */
IT83XX_SMB_HOSTA(p) = HOSTA_ALL_WC_BIT;
CPRINTS("I2C ch%d reset cause %d", p, cause);
} else {
/* Shift register */
p_ch = i2c_ch_reg_shift(p);
/* State reset and hardware reset */
IT83XX_I2C_CTR(p_ch) = 0x11;
IT83XX_I2C_CTR(p_ch) = 0x00;
/* Set i2c frequency */
IT83XX_I2C_PSR(p_ch) = pdata[p].freq;
IT83XX_I2C_HSPR(p_ch) = pdata[p].freq;
/* Set time out register */
IT83XX_I2C_TOR(p_ch) = 0xFF;
/* Time buffer from STOP signal to next START signal */
IT83XX_I2C_T_BUF(p_ch) = 0x3F;
/* Enable interrupt, Master mode, Ack needed */
IT83XX_I2C_CTR(p_ch) = 0x68;
/* Enable i2c d/e/f module */
IT83XX_I2C_CTR1(p_ch) = 0x32;
IT83XX_I2C_CTR(p_ch) = E_STS_AND_HW_RST;
}
CPRINTS("I2C ch%d reset cause %d", p, cause);
}
static void i2c_r_last_byte(int p)
@@ -332,42 +284,33 @@ static void i2c_pio_trans_data(int p, enum enhanced_i2c_transfer_direct direct,
{
struct i2c_port_data *pd = pdata + p;
int p_ch;
int nack = 0;
/* Shift register */
p_ch = i2c_ch_reg_shift(p);
if (first_byte) {
/* First byte must be slave address, transmit data */
IT83XX_I2C_DTR(p_ch) = data;
/* First byte must be slave address. */
IT83XX_I2C_DTR(p_ch) =
data | (direct == RX_DIRECT ? (1 << 0) : 0);
/* start or repeat start signal. */
IT83XX_I2C_CTR(p_ch) = E_START_ID;
} else {
if (direct == TX_DIRECT)
/* Transmit data*/
/* Transmit data */
IT83XX_I2C_DTR(p_ch) = data;
else {
/* Receive data, master need to ack */
IT83XX_I2C_CTR(p_ch) |= E_ACK;
/* Last byte should be NACK in the end of read cycle */
/*
* Receive data.
* Last byte should be NACK in the end of read cycle
*/
if (((pd->ridx + 1) == pd->in_size) &&
(pd->flags & I2C_XFER_STOP))
/* Clear ack bit */
IT83XX_I2C_CTR(p_ch) &= ~E_ACK;
nack = 1;
}
}
if (first_byte) {
/*
* Need start or repeat start signal
* Set hardware reset to start next transmission
*/
IT83XX_I2C_CTR(p_ch) |= (E_START | E_HW_RST);
} else {
/*
* Needn't start or repeat start signal
* Set hardware reset to start next transmission
*/
IT83XX_I2C_CTR(p_ch) &= ~(E_START);
IT83XX_I2C_CTR(p_ch) |= E_HW_RST;
/* Set hardware reset to start next transmission */
IT83XX_I2C_CTR(p_ch) =
E_INT_EN | E_MODE_SEL | E_HW_RST | (nack ? 0 : E_ACK);
}
}
@@ -498,6 +441,25 @@ static int i2c_tran_read(int p)
return 1;
}
static void enhanced_i2c_start(int p)
{
/* Shift register */
int p_ch = i2c_ch_reg_shift(p);
/* State reset and hardware reset */
IT83XX_I2C_CTR(p_ch) = E_STS_AND_HW_RST;
/* Set i2c frequency */
IT83XX_I2C_PSR(p_ch) = pdata[p].freq;
IT83XX_I2C_HSPR(p_ch) = pdata[p].freq;
/*
* Set time out register.
* I2C D/E/F clock/data low timeout.
*/
IT83XX_I2C_TOR(p_ch) = I2C_CLK_LOW_TIMEOUT;
/* bit1: Enable enhanced i2c module */
IT83XX_I2C_CTR1(p_ch) = (1 << 1);
}
static int enhanced_i2c_tran_write(int p)
{
struct i2c_port_data *pd = pdata + p;
@@ -510,30 +472,10 @@ static int enhanced_i2c_tran_write(int p)
if (pd->flags & I2C_XFER_START) {
/* Clear start bit */
pd->flags &= ~I2C_XFER_START;
/* Reset channel */
i2c_reset(p, 0);
enhanced_i2c_start(p);
/* Send ID */
i2c_pio_trans_data(p, TX_DIRECT, pd->addr, 1);
} else {
/*
* If device doesn't response ack, reset
* the channel and abort the transaction.
*/
if (!(IT83XX_I2C_STR(p_ch) & E_HOSTA_ACK)) {
pd->i2ccs = I2C_CH_NORMAL;
pd->err = E_HOSTA_ACK;
i2c_reset(p, 0);
/* Disable i2c module */
IT83XX_I2C_CTR1(p_ch) = 0x00;
return 0;
}
/* Wait for byte done */
if (!(IT83XX_I2C_STR(p_ch) & E_HOSTA_BDS))
return 1;
/* Host has completed the transmission of a byte */
if (pd->widx < pd->out_size) {
out_data = *(pd->out++);
@@ -552,8 +494,7 @@ static int enhanced_i2c_tran_write(int p)
/* Write to read protocol */
pd->i2ccs = I2C_CH_REPEAT_START;
/* Repeat Start */
i2c_pio_trans_data(p, RX_DIRECT,
(pd->addr + 1), 1);
i2c_pio_trans_data(p, RX_DIRECT, pd->addr, 1);
} else {
if (pd->flags & I2C_XFER_STOP) {
IT83XX_I2C_CTR(p_ch) = E_FINISH;
@@ -581,15 +522,11 @@ static int enhanced_i2c_tran_read(int p)
if (pd->flags & I2C_XFER_START) {
/* clear start flag */
pd->flags &= ~I2C_XFER_START;
/* reset channel */
i2c_reset(p, 0);
enhanced_i2c_start(p);
/* Direct read */
pd->i2ccs = I2C_CH_WAIT_READ;
/* Send ID */
i2c_pio_trans_data(p, RX_DIRECT, (pd->addr + 1), 1);
i2c_pio_trans_data(p, RX_DIRECT, pd->addr, 1);
} else {
if (pd->i2ccs) {
if (pd->i2ccs == I2C_CH_REPEAT_START) {
@@ -598,39 +535,18 @@ static int enhanced_i2c_tran_read(int p)
i2c_pio_trans_data(p, RX_DIRECT, in_data, 0);
} else if (pd->i2ccs == I2C_CH_WAIT_READ) {
pd->i2ccs = I2C_CH_NORMAL;
/*
* If device doesn't response ack, reset
* the channel and abort the transaction.
*/
if (!(IT83XX_I2C_STR(p_ch) & E_HOSTA_ACK)) {
pd->err = E_HOSTA_ACK;
i2c_reset(p, 0);
/* Disable i2c module */
IT83XX_I2C_CTR1(p_ch) = 0x00;
return 0;
}
/* Receive data */
i2c_pio_trans_data(p, RX_DIRECT, in_data, 0);
/* Direct write with direct read protocol */
task_clear_pending_irq(i2c_ctrl_regs[p].irq);
/* Turn on irq before next direct read */
task_enable_irq(i2c_ctrl_regs[p].irq);
} else {
/* Write to read */
pd->i2ccs = I2C_CH_WAIT_READ;
/* Send ID */
i2c_pio_trans_data(p, RX_DIRECT,
(pd->addr + 1), 1);
/* Direct write with direct read protocol */
task_clear_pending_irq(i2c_ctrl_regs[p].irq);
/* Turn on irq before next direct read */
i2c_pio_trans_data(p, RX_DIRECT, pd->addr, 1);
task_enable_irq(i2c_ctrl_regs[p].irq);
}
} else {
/* Wait for byte done */
if (!(IT83XX_I2C_STR(p_ch) & E_HOSTA_BDS))
return 1;
if (pd->ridx < pd->in_size) {
/* read data */
*(pd->in++) = IT83XX_I2C_DRR(p_ch);
@@ -657,6 +573,24 @@ static int enhanced_i2c_tran_read(int p)
return 1;
}
static int enhanced_i2c_error(int p)
{
struct i2c_port_data *pd = pdata + p;
/* Shift register */
int p_ch = i2c_ch_reg_shift(p);
int i2c_str = IT83XX_I2C_STR(p_ch);
if (i2c_str & E_HOSTA_ANY_ERROR) {
pd->err = i2c_str & E_HOSTA_ANY_ERROR;
/* device does not respond ACK */
} else if ((i2c_str & E_HOSTA_BDS_AND_ACK) == E_HOSTA_BDS) {
if (IT83XX_I2C_CTR(p_ch) & E_ACK)
pd->err = E_HOSTA_ACK;
}
return pd->err;
}
static int i2c_transaction(int p)
{
struct i2c_port_data *pd = pdata + p;
@@ -682,26 +616,18 @@ static int i2c_transaction(int p)
/* disable the SMBus host interface */
IT83XX_SMB_HOCTL2(p) = 0x00;
} else {
/* Shift register */
p_ch = i2c_ch_reg_shift(p);
/* check error */
if (IT83XX_I2C_STR(p_ch) & E_HOSTA_ANY_ERROR)
pd->err = (IT83XX_I2C_STR(p_ch) & E_HOSTA_ANY_ERROR);
else {
/* no error */
if (!(enhanced_i2c_error(p))) {
/* i2c write */
if (pd->out_size)
return enhanced_i2c_tran_write(p);
/* i2c read */
else if (pd->in_size)
return enhanced_i2c_tran_read(p);
/* transaction done */
if (pd->flags & I2C_XFER_STOP) {
/* disable i2c interface */
IT83XX_I2C_CTR1(p_ch) = 0;
IT83XX_I2C_CTR(p_ch) = 0;
}
}
p_ch = i2c_ch_reg_shift(p);
IT83XX_I2C_CTR(p_ch) = E_STS_AND_HW_RST;
IT83XX_I2C_CTR1(p_ch) = 0;
}
/* done doing work */
return 0;
@@ -712,7 +638,8 @@ int i2c_is_busy(int port)
int p_ch;
if (port < I2C_STANDARD_PORT_COUNT)
return (IT83XX_SMB_HOSTA(port) & HOSTA_HOBY);
return (IT83XX_SMB_HOSTA(port) &
(HOSTA_HOBY | HOSTA_ALL_WC_BIT));
p_ch = i2c_ch_reg_shift(port);
return (IT83XX_I2C_STR(p_ch) & E_HOSTA_BB);
@@ -743,26 +670,13 @@ int chip_i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_size,
pd->err = 0;
pd->addr = slave_addr;
if (port < I2C_STANDARD_PORT_COUNT) {
/* Make sure we're in a good state to start */
if ((flags & I2C_XFER_START) && (i2c_is_busy(port)
|| (IT83XX_SMB_HOSTA(port) & HOSTA_ALL_WC_BIT)
|| (i2c_get_line_levels(port) != I2C_LINE_IDLE))) {
/* Attempt to unwedge the port. */
i2c_unwedge(port);
/* reset i2c port */
i2c_reset(port, I2C_RC_NO_IDLE_FOR_START);
}
} else {
/* Make sure we're in a good state to start */
if ((flags & I2C_XFER_START) && (i2c_is_busy(port)
|| (i2c_get_line_levels(port) != I2C_LINE_IDLE))) {
/* Attempt to unwedge the port. */
i2c_unwedge(port);
/* reset i2c port */
i2c_reset(port, I2C_RC_NO_IDLE_FOR_START);
}
/* Make sure we're in a good state to start */
if ((flags & I2C_XFER_START) && (i2c_is_busy(port)
|| (i2c_get_line_levels(port) != I2C_LINE_IDLE))) {
/* Attempt to unwedge the port. */
i2c_unwedge(port);
/* reset i2c port */
i2c_reset(port, I2C_RC_NO_IDLE_FOR_START);
}
pd->task_waiting = task_get_current();
@@ -904,8 +818,6 @@ static void i2c_freq_changed(void)
/* Backup */
pdata[i2c_ports[i].port].freq = (psr & 0xFF);
}
/* I2C D/E/F clock/data low timeout. */
IT83XX_I2C_TOR(p_ch) = I2C_CLK_LOW_TIMEOUT;
}
}
/* This field defines the SMCLK0/1/2 clock/data low timeout. */
@@ -973,27 +885,10 @@ static void i2c_init(void)
/* Software reset */
IT83XX_I2C_DHTR(p_ch) |= 0x80;
IT83XX_I2C_DHTR(p_ch) &= 0x7F;
/* State reset and hardware reset */
IT83XX_I2C_CTR(p_ch) = 0x11;
IT83XX_I2C_CTR(p_ch) = 0x00;
/* Set time out condition */
IT83XX_I2C_TOR(p_ch) = 0xFF;
IT83XX_I2C_T_BUF(p_ch) = 0x3F;
/*
* bit3, Acknowledge
* bit5, Master mode
* bit6, Interrupt enable
*/
IT83XX_I2C_CTR(p_ch) = 0x68;
/*
* bit1, Module enable
* bit4-6 Support number of devices
*/
IT83XX_I2C_CTR1(p_ch) = 0x00;
IT83XX_I2C_CTR(p_ch) = E_STS_AND_HW_RST;
/* bit1, Module enable */
IT83XX_I2C_CTR1(p_ch) = 0;
}
pdata[i].task_waiting = TASK_ID_INVALID;
}

View File

@@ -1119,38 +1119,9 @@ enum bram_indices {
#define IT83XX_I2C_STR(ch) REG8(IT83XX_I2C_BASE+0x03+(ch << 7))
#define IT83XX_I2C_DHTR(ch) REG8(IT83XX_I2C_BASE+0x04+(ch << 7))
#define IT83XX_I2C_TOR(ch) REG8(IT83XX_I2C_BASE+0x05+(ch << 7))
#define IT83XX_I2C_IDR(ch) REG8(IT83XX_I2C_BASE+0x06+(ch << 7))
#define IT83XX_I2C_TOS(ch) REG8(IT83XX_I2C_BASE+0x07+(ch << 7))
#define IT83XX_I2C_DTR(ch) REG8(IT83XX_I2C_BASE+0x08+(ch << 7))
#define IT83XX_I2C_CTR(ch) REG8(IT83XX_I2C_BASE+0x09+(ch << 7))
#define IT83XX_I2C_CTR1(ch) REG8(IT83XX_I2C_BASE+0x0A+(ch << 7))
#define IT83XX_I2C_BYTE_CNT_H(ch) REG8(IT83XX_I2C_BASE+0x0B+(ch << 7))
#define IT83XX_I2C_BYTE_CNT_L(ch) REG8(IT83XX_I2C_BASE+0x0C+(ch << 7))
#define IT83XX_I2C_IRQ_ST(ch) REG8(IT83XX_I2C_BASE+0x0D+(ch << 7))
#define IT83XX_I2C_SLV_NUM_H(ch) REG8(IT83XX_I2C_BASE+0x10+(ch << 7))
#define IT83XX_I2C_SLV_NUM_L(ch) REG8(IT83XX_I2C_BASE+0x11+(ch << 7))
#define IT83XX_I2C_STR2(ch) REG8(IT83XX_I2C_BASE+0x12+(ch << 7))
#define IT83XX_I2C_NST(ch) REG8(IT83XX_I2C_BASE+0x13+(ch << 7))
#define IT83XX_I2C_T_BUF(ch) REG8(IT83XX_I2C_BASE+0x14+(ch << 7))
#define IT83XX_I2C_TH_ST(ch) REG8(IT83XX_I2C_BASE+0x16+(ch << 7))
#define IT83XX_I2C_TO_ARB_ST(ch) REG8(IT83XX_I2C_BASE+0x18+(ch << 7))
#define IT83XX_I2C_ERR_ST(ch) REG8(IT83XX_I2C_BASE+0x19+(ch << 7))
#define IT83XX_I2C_EN_TRIG(ch) REG8(IT83XX_I2C_BASE+0x1A+(ch << 7))
#define IT83XX_I2C_FST(ch) REG8(IT83XX_I2C_BASE+0x1B+(ch << 7))
#define IT83XX_I2C_EM(ch) REG8(IT83XX_I2C_BASE+0x1C+(ch << 7))
#define IT83XX_I2C_MODE_SEL(ch) REG8(IT83XX_I2C_BASE+0x1D+(ch << 7))
#define IT83XX_I2C_CSR(ch) REG8(IT83XX_I2C_BASE+0x1F+(ch << 7))
#define IT83XX_I2C_CTR2(ch) REG8(IT83XX_I2C_BASE+0x20+(ch << 7))
#define IT83XX_I2C_CMD_IDX_2(ch) REG8(IT83XX_I2C_BASE+0x21+(ch << 7))
#define IT83XX_I2C_WCSR_i(ch) REG8(IT83XX_I2C_BASE+0x22+(ch << 7))
#define IT83XX_I2C_RAMHA_i(ch) REG8(IT83XX_I2C_BASE+0x23+(ch << 7))
#define IT83XX_I2C_RAMLA_i(ch) REG8(IT83XX_I2C_BASE+0x24+(ch << 7))
#define IT83XX_I2C_CMD_ADDH_i(ch) REG8(IT83XX_I2C_BASE+0x25+(ch << 7))
#define IT83XX_I2C_CMD_ADDL_i(ch) REG8(IT83XX_I2C_BASE+0x26+(ch << 7))
#define IT83XX_I2C_LNGRH_i(ch) REG8(IT83XX_I2C_BASE+0x27+(ch << 7))
#define IT83XX_I2C_LNGRL_i(ch) REG8(IT83XX_I2C_BASE+0x28+(ch << 7))
#define IT83XX_I2C_LNGSTH_i(ch) REG8(IT83XX_I2C_BASE+0x29+(ch << 7))
#define IT83XX_I2C_TH_CTR(ch) REG8(IT83XX_I2C_BASE+0x2A+(ch << 7))
enum i2c_channels {
IT83XX_I2C_CH_A, /* GPIO.B3/B4 */