diff options
author | Dino Li <Dino.Li@ite.com.tw> | 2017-09-20 10:58:50 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-09-26 22:35:20 -0700 |
commit | dc8a8767fae01e22e6504e272dca17448c7a25af (patch) | |
tree | 2adb4968dcee6b1a160fa3a9a454ea5391a59b47 /chip | |
parent | b440a0d099d4b4b8cf519f6f834ff233b29bb384 (diff) | |
download | chrome-ec-dc8a8767fae01e22e6504e272dca17448c7a25af.tar.gz |
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>
Diffstat (limited to 'chip')
-rw-r--r-- | chip/it83xx/i2c.c | 291 | ||||
-rw-r--r-- | chip/it83xx/registers.h | 29 |
2 files changed, 93 insertions, 227 deletions
diff --git a/chip/it83xx/i2c.c b/chip/it83xx/i2c.c index f746bd94b4..a88599b380 100644 --- a/chip/it83xx/i2c.c +++ b/chip/it83xx/i2c.c @@ -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; } diff --git a/chip/it83xx/registers.h b/chip/it83xx/registers.h index adda028dd9..21d8e7fc1a 100644 --- a/chip/it83xx/registers.h +++ b/chip/it83xx/registers.h @@ -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 */ |