summaryrefslogtreecommitdiff
path: root/chip/it83xx/i2c.c
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2021-11-04 12:11:58 -0600
committerCommit Bot <commit-bot@chromium.org>2021-11-05 04:22:34 +0000
commit252457d4b21f46889eebad61d4c0a65331919cec (patch)
tree01856c4d31d710b20e85a74c8d7b5836e35c3b98 /chip/it83xx/i2c.c
parent08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff)
downloadchrome-ec-stabilize-14588.14.B-ish.tar.gz
In the interest of making long-term branch maintenance incur as little technical debt on us as possible, we should not maintain any files on the branch we are not actually using. This has the added effect of making it extremely clear when merging CLs from the main branch when changes have the possibility to affect us. The follow-on CL adds a convenience script to actually pull updates from the main branch and generate a CL for the update. BUG=b:204206272 BRANCH=ish TEST=make BOARD=arcada_ish && make BOARD=drallion_ish Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Change-Id: I17e4694c38219b5a0823e0a3e55a28d1348f4b18 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3262038 Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Tom Hughes <tomhughes@chromium.org>
Diffstat (limited to 'chip/it83xx/i2c.c')
-rw-r--r--chip/it83xx/i2c.c946
1 files changed, 0 insertions, 946 deletions
diff --git a/chip/it83xx/i2c.c b/chip/it83xx/i2c.c
deleted file mode 100644
index 5aa8f8a460..0000000000
--- a/chip/it83xx/i2c.c
+++ /dev/null
@@ -1,946 +0,0 @@
-/* Copyright 2015 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-/* I2C module for Chrome EC */
-
-#include "clock.h"
-#include "common.h"
-#include "console.h"
-#include "gpio.h"
-#include "hooks.h"
-#include "i2c.h"
-#include "registers.h"
-#include "task.h"
-#include "timer.h"
-#include "util.h"
-
-#define CPRINTS(format, args...) cprints(CC_I2C, format, ## args)
-
-/* Default maximum time we allow for an I2C transfer */
-#define I2C_TIMEOUT_DEFAULT_US (100 * MSEC)
-
-enum enhanced_i2c_transfer_direct {
- TX_DIRECT,
- RX_DIRECT,
-};
-
-enum i2c_host_status {
- /* Host busy */
- HOSTA_HOBY = 0x01,
- /* Finish Interrupt */
- HOSTA_FINTR = 0x02,
- /* Device error */
- HOSTA_DVER = 0x04,
- /* Bus error */
- HOSTA_BSER = 0x08,
- /* Fail */
- HOSTA_FAIL = 0x10,
- /* Not response ACK */
- HOSTA_NACK = 0x20,
- /* Time-out error */
- HOSTA_TMOE = 0x40,
- /* Byte done status */
- HOSTA_BDS = 0x80,
- /* 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 {
- /* ACK receive */
- E_HOSTA_ACK = 0x01,
- /* Interrupt pending */
- E_HOSTA_INTP = 0x02,
- /* Read/Write */
- E_HOSTA_RW = 0x04,
- /* Time out error */
- E_HOSTA_TMOE = 0x08,
- /* Arbitration lost */
- E_HOSTA_ARB = 0x10,
- /* Bus busy */
- E_HOSTA_BB = 0x20,
- /* Address match */
- E_HOSTA_AM = 0x40,
- /* Byte done status */
- E_HOSTA_BDS = 0x80,
- /* 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 {
- /* Hardware reset */
- E_HW_RST = 0x01,
- /* Stop */
- E_STOP = 0x02,
- /* Start & Repeat start */
- E_START = 0x04,
- /* Acknowledge */
- E_ACK = 0x08,
- /* State reset */
- E_STS_RST = 0x10,
- /* Mode select */
- E_MODE_SEL = 0x20,
- /* I2C interrupt enable */
- 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 peripheral 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_reset_cause {
- I2C_RC_NO_IDLE_FOR_START = 1,
- I2C_RC_TIMEOUT,
-};
-
-struct i2c_ch_freq {
- int kbps;
- uint8_t freq_set;
-};
-
-static const struct i2c_ch_freq i2c_freq_select[] = {
- { 50, 1},
- { 100, 2},
- { 400, 3},
- { 1000, 4},
-};
-
-struct i2c_pin {
- volatile uint8_t *pin_clk;
- volatile uint8_t *pin_data;
- volatile uint8_t *pin_clk_ctrl;
- volatile uint8_t *pin_data_ctrl;
- volatile uint8_t *mirror_clk;
- volatile uint8_t *mirror_data;
- uint8_t clk_mask;
- uint8_t data_mask;
-};
-
-static const struct i2c_pin i2c_pin_regs[] = {
- { &IT83XX_GPIO_GPCRB3, &IT83XX_GPIO_GPCRB4,
- &IT83XX_GPIO_GPDRB, &IT83XX_GPIO_GPDRB,
- &IT83XX_GPIO_GPDMRB, &IT83XX_GPIO_GPDMRB,
- 0x08, 0x10},
- { &IT83XX_GPIO_GPCRC1, &IT83XX_GPIO_GPCRC2,
- &IT83XX_GPIO_GPDRC, &IT83XX_GPIO_GPDRC,
- &IT83XX_GPIO_GPDMRC, &IT83XX_GPIO_GPDMRC,
- 0x02, 0x04},
-#ifdef CONFIG_IT83XX_SMCLK2_ON_GPC7
- { &IT83XX_GPIO_GPCRC7, &IT83XX_GPIO_GPCRF7,
- &IT83XX_GPIO_GPDRC, &IT83XX_GPIO_GPDRF,
- &IT83XX_GPIO_GPDMRC, &IT83XX_GPIO_GPDMRF,
- 0x80, 0x80},
-#else
- { &IT83XX_GPIO_GPCRF6, &IT83XX_GPIO_GPCRF7,
- &IT83XX_GPIO_GPDRF, &IT83XX_GPIO_GPDRF,
- &IT83XX_GPIO_GPDMRF, &IT83XX_GPIO_GPDMRF,
- 0x40, 0x80},
-#endif
- { &IT83XX_GPIO_GPCRH1, &IT83XX_GPIO_GPCRH2,
- &IT83XX_GPIO_GPDRH, &IT83XX_GPIO_GPDRH,
- &IT83XX_GPIO_GPDMRH, &IT83XX_GPIO_GPDMRH,
- 0x02, 0x04},
- { &IT83XX_GPIO_GPCRE0, &IT83XX_GPIO_GPCRE7,
- &IT83XX_GPIO_GPDRE, &IT83XX_GPIO_GPDRE,
- &IT83XX_GPIO_GPDMRE, &IT83XX_GPIO_GPDMRE,
- 0x01, 0x80},
- { &IT83XX_GPIO_GPCRA4, &IT83XX_GPIO_GPCRA5,
- &IT83XX_GPIO_GPDRA, &IT83XX_GPIO_GPDRA,
- &IT83XX_GPIO_GPDMRA, &IT83XX_GPIO_GPDMRA,
- 0x10, 0x20},
-};
-
-struct i2c_ctrl_t {
- uint8_t irq;
- enum clock_gate_offsets clock_gate;
- int reg_shift;
-};
-
-const struct i2c_ctrl_t i2c_ctrl_regs[] = {
- {IT83XX_IRQ_SMB_A, CGC_OFFSET_SMBA, -1},
- {IT83XX_IRQ_SMB_B, CGC_OFFSET_SMBB, -1},
- {IT83XX_IRQ_SMB_C, CGC_OFFSET_SMBC, -1},
- {IT83XX_IRQ_SMB_D, CGC_OFFSET_SMBD, 3},
- {IT83XX_IRQ_SMB_E, CGC_OFFSET_SMBE, 0},
- {IT83XX_IRQ_SMB_F, CGC_OFFSET_SMBF, 1},
-};
-
-enum i2c_ch_status {
- I2C_CH_NORMAL = 0,
- I2C_CH_REPEAT_START,
- I2C_CH_WAIT_READ,
- I2C_CH_WAIT_NEXT_XFER,
-};
-
-/* I2C port state data */
-struct i2c_port_data {
- const uint8_t *out; /* Output data pointer */
- int out_size; /* Output data to transfer, in bytes */
- uint8_t *in; /* Input data pointer */
- int in_size; /* Input data to transfer, in bytes */
- int flags; /* Flags (I2C_XFER_*) */
- int widx; /* Index into output data */
- int ridx; /* Index into input data */
- int err; /* Error code, if any */
- uint8_t addr_8bit; /* address of device */
- uint32_t timeout_us; /* Transaction timeout, or 0 to use default */
- uint8_t freq; /* Frequency setting */
-
- enum i2c_ch_status i2ccs;
- /* Task waiting on port, or TASK_ID_INVALID if none. */
- volatile int task_waiting;
-};
-static struct i2c_port_data pdata[I2C_PORT_COUNT];
-
-static int i2c_ch_reg_shift(int p)
-{
- /*
- * only enhanced port needs to be changed the parameter of registers
- */
- ASSERT(p >= I2C_STANDARD_PORT_COUNT && p < I2C_PORT_COUNT);
-
- /*
- * The registers of i2c enhanced ports are not sequential.
- * This routine transfers the i2c port number to related
- * parameter of registers.
- *
- * IT83xx chip : i2c enhanced ports - channel D,E,F
- * channel D registers : 0x3680 ~ 0x36FF
- * channel E registers : 0x3500 ~ 0x357F
- * channel F registers : 0x3580 ~ 0x35FF
- */
- return i2c_ctrl_regs[p].reg_shift;
-}
-
-static void i2c_reset(int p, int cause)
-{
- int p_ch;
-
- if (p < I2C_STANDARD_PORT_COUNT) {
- /* bit1, kill current transaction. */
- IT83XX_SMB_HOCTL(p) = 0x2;
- IT83XX_SMB_HOCTL(p) = 0;
- /* W/C host status register */
- IT83XX_SMB_HOSTA(p) = HOSTA_ALL_WC_BIT;
- } else {
- /* Shift register */
- p_ch = i2c_ch_reg_shift(p);
- /* State reset and hardware reset */
- 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)
-{
- struct i2c_port_data *pd = pdata + p;
-
- /*
- * bit5, The firmware shall write 1 to this bit
- * when the next byte will be the last byte for i2c read.
- */
- if ((pd->flags & I2C_XFER_STOP) && (pd->ridx == pd->in_size - 1))
- IT83XX_SMB_HOCTL(p) |= 0x20;
-}
-
-static void i2c_w2r_change_direction(int p)
-{
- /* I2C switch direction */
- if (IT83XX_SMB_HOCTL2(p) & 0x08) {
- i2c_r_last_byte(p);
- IT83XX_SMB_HOSTA(p) = HOSTA_NEXT_BYTE;
- } else {
- /*
- * bit2, I2C switch direction wait.
- * bit3, I2C switch direction enable.
- */
- IT83XX_SMB_HOCTL2(p) |= 0x0C;
- IT83XX_SMB_HOSTA(p) = HOSTA_NEXT_BYTE;
- i2c_r_last_byte(p);
- IT83XX_SMB_HOCTL2(p) &= ~0x04;
- }
-}
-
-static void i2c_pio_trans_data(int p, enum enhanced_i2c_transfer_direct direct,
- uint8_t data, int first_byte)
-{
- 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 peripheral address. */
- IT83XX_I2C_DTR(p_ch) =
- data | (direct == RX_DIRECT ? BIT(0) : 0);
- /* start or repeat start signal. */
- IT83XX_I2C_CTR(p_ch) = E_START_ID;
- } else {
- if (direct == TX_DIRECT)
- /* Transmit data */
- IT83XX_I2C_DTR(p_ch) = data;
- else {
- /*
- * 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))
- nack = 1;
- }
- /* 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);
- }
-}
-
-static int i2c_tran_write(int p)
-{
- struct i2c_port_data *pd = pdata + p;
-
- if (pd->flags & I2C_XFER_START) {
- /* i2c enable */
- IT83XX_SMB_HOCTL2(p) = 0x13;
- /*
- * bit0, Direction of the host transfer.
- * bit[1:7}, Address of the targeted peripheral.
- */
- IT83XX_SMB_TRASLA(p) = pd->addr_8bit;
- /* Send first byte */
- IT83XX_SMB_HOBDB(p) = *(pd->out++);
- pd->widx++;
- /* clear start flag */
- pd->flags &= ~I2C_XFER_START;
- /*
- * bit0, Host interrupt enable.
- * bit[2:4}, Extend command.
- * bit6, start.
- */
- IT83XX_SMB_HOCTL(p) = 0x5D;
- } else {
- /* Host has completed the transmission of a byte */
- if (IT83XX_SMB_HOSTA(p) & HOSTA_BDS) {
- if (pd->widx < pd->out_size) {
- /* Send next byte */
- IT83XX_SMB_HOBDB(p) = *(pd->out++);
- pd->widx++;
- /* W/C byte done for next byte */
- IT83XX_SMB_HOSTA(p) = HOSTA_NEXT_BYTE;
- if (pd->i2ccs == I2C_CH_REPEAT_START) {
- pd->i2ccs = I2C_CH_NORMAL;
- task_enable_irq(i2c_ctrl_regs[p].irq);
- }
- } else {
- /* done */
- pd->out_size = 0;
- if (pd->in_size > 0) {
- /* write to read */
- i2c_w2r_change_direction(p);
- } else {
- if (pd->flags & I2C_XFER_STOP) {
- /* set I2C_EN = 0 */
- IT83XX_SMB_HOCTL2(p) = 0x11;
- /* W/C byte done for finish */
- IT83XX_SMB_HOSTA(p) =
- HOSTA_NEXT_BYTE;
- } else {
- pd->i2ccs = I2C_CH_REPEAT_START;
- return 0;
- }
- }
- }
- }
- }
- return 1;
-}
-
-static int i2c_tran_read(int p)
-{
- struct i2c_port_data *pd = pdata + p;
-
- if (pd->flags & I2C_XFER_START) {
- /* i2c enable */
- IT83XX_SMB_HOCTL2(p) = 0x13;
- /*
- * bit0, Direction of the host transfer.
- * bit[1:7}, Address of the targeted peripheral.
- */
- IT83XX_SMB_TRASLA(p) = pd->addr_8bit | 0x01;
- /* clear start flag */
- pd->flags &= ~I2C_XFER_START;
- /*
- * bit0, Host interrupt enable.
- * bit[2:4}, Extend command.
- * bit5, The firmware shall write 1 to this bit
- * when the next byte will be the last byte.
- * bit6, start.
- */
- if ((1 == pd->in_size) && (pd->flags & I2C_XFER_STOP))
- IT83XX_SMB_HOCTL(p) = 0x7D;
- else
- IT83XX_SMB_HOCTL(p) = 0x5D;
- } else {
- if ((pd->i2ccs == I2C_CH_REPEAT_START) ||
- (pd->i2ccs == I2C_CH_WAIT_READ)) {
- if (pd->i2ccs == I2C_CH_REPEAT_START) {
- /* write to read */
- i2c_w2r_change_direction(p);
- } else {
- /* For last byte */
- i2c_r_last_byte(p);
- /* W/C for next byte */
- IT83XX_SMB_HOSTA(p) = HOSTA_NEXT_BYTE;
- }
- pd->i2ccs = I2C_CH_NORMAL;
- task_enable_irq(i2c_ctrl_regs[p].irq);
- } else if (IT83XX_SMB_HOSTA(p) & HOSTA_BDS) {
- if (pd->ridx < pd->in_size) {
- /* To get received data. */
- *(pd->in++) = IT83XX_SMB_HOBDB(p);
- pd->ridx++;
- /* For last byte */
- i2c_r_last_byte(p);
- /* done */
- if (pd->ridx == pd->in_size) {
- pd->in_size = 0;
- if (pd->flags & I2C_XFER_STOP) {
- /* W/C for finish */
- IT83XX_SMB_HOSTA(p) =
- HOSTA_NEXT_BYTE;
- } else {
- pd->i2ccs = I2C_CH_WAIT_READ;
- return 0;
- }
- } else {
- /* W/C for next byte */
- IT83XX_SMB_HOSTA(p) = HOSTA_NEXT_BYTE;
- }
- }
- }
- }
- 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) = BIT(1);
-}
-
-static int enhanced_i2c_tran_write(int p)
-{
- struct i2c_port_data *pd = pdata + p;
- uint8_t out_data;
- int p_ch;
-
- /* Shift register */
- p_ch = i2c_ch_reg_shift(p);
-
- if (pd->flags & I2C_XFER_START) {
- /* Clear start bit */
- pd->flags &= ~I2C_XFER_START;
- enhanced_i2c_start(p);
- /* Send ID */
- i2c_pio_trans_data(p, TX_DIRECT, pd->addr_8bit, 1);
- } else {
- /* Host has completed the transmission of a byte */
- if (pd->widx < pd->out_size) {
- out_data = *(pd->out++);
- pd->widx++;
-
- /* Send Byte */
- i2c_pio_trans_data(p, TX_DIRECT, out_data, 0);
- if (pd->i2ccs == I2C_CH_WAIT_NEXT_XFER) {
- pd->i2ccs = I2C_CH_NORMAL;
- task_enable_irq(i2c_ctrl_regs[p].irq);
- }
- } else {
- /* done */
- pd->out_size = 0;
- if (pd->in_size > 0) {
- /* Write to read protocol */
- pd->i2ccs = I2C_CH_REPEAT_START;
- /* Repeat Start */
- i2c_pio_trans_data(p, RX_DIRECT,
- pd->addr_8bit, 1);
- } else {
- if (pd->flags & I2C_XFER_STOP) {
- IT83XX_I2C_CTR(p_ch) = E_FINISH;
- /* wait for stop bit interrupt*/
- return 1;
- }
- /* Direct write with direct read */
- pd->i2ccs = I2C_CH_WAIT_NEXT_XFER;
- return 0;
- }
- }
- }
- return 1;
-}
-
-static int enhanced_i2c_tran_read(int p)
-{
- struct i2c_port_data *pd = pdata + p;
- uint8_t in_data = 0;
- int p_ch;
-
- /* Shift register */
- p_ch = i2c_ch_reg_shift(p);
-
- if (pd->flags & I2C_XFER_START) {
- /* clear start flag */
- pd->flags &= ~I2C_XFER_START;
- enhanced_i2c_start(p);
- /* Direct read */
- pd->i2ccs = I2C_CH_WAIT_READ;
- /* Send ID */
- i2c_pio_trans_data(p, RX_DIRECT, pd->addr_8bit, 1);
- } else {
- if (pd->i2ccs) {
- if (pd->i2ccs == I2C_CH_REPEAT_START) {
- pd->i2ccs = I2C_CH_NORMAL;
- /* Receive data */
- i2c_pio_trans_data(p, RX_DIRECT, in_data, 0);
- } else if (pd->i2ccs == I2C_CH_WAIT_READ) {
- pd->i2ccs = I2C_CH_NORMAL;
- /* Receive data */
- i2c_pio_trans_data(p, RX_DIRECT, in_data, 0);
- /* 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_8bit, 1);
- task_enable_irq(i2c_ctrl_regs[p].irq);
- }
- } else {
- if (pd->ridx < pd->in_size) {
- /* read data */
- *(pd->in++) = IT83XX_I2C_DRR(p_ch);
- pd->ridx++;
-
- /* done */
- if (pd->ridx == pd->in_size) {
- pd->in_size = 0;
- if (pd->flags & I2C_XFER_STOP) {
- pd->i2ccs = I2C_CH_NORMAL;
- IT83XX_I2C_CTR(p_ch) = E_FINISH;
- /* wait for stop bit interrupt*/
- return 1;
- }
- /* End the transaction */
- pd->i2ccs = I2C_CH_WAIT_READ;
- return 0;
- }
- /* read next byte */
- i2c_pio_trans_data(p, RX_DIRECT, in_data, 0);
- }
- }
- }
- 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;
- int p_ch;
-
- if (p < I2C_STANDARD_PORT_COUNT) {
- /* any error */
- if (IT83XX_SMB_HOSTA(p) & HOSTA_ANY_ERROR) {
- pd->err = (IT83XX_SMB_HOSTA(p) & HOSTA_ANY_ERROR);
- } else {
- /* i2c write */
- if (pd->out_size)
- return i2c_tran_write(p);
- /* i2c read */
- else if (pd->in_size)
- return i2c_tran_read(p);
- /* wait finish */
- if (!(IT83XX_SMB_HOSTA(p) & HOSTA_FINTR))
- return 1;
- }
- /* W/C */
- IT83XX_SMB_HOSTA(p) = HOSTA_ALL_WC_BIT;
- /* disable the SMBus host interface */
- IT83XX_SMB_HOCTL2(p) = 0x00;
- } 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);
- }
- 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;
-}
-
-int i2c_is_busy(int port)
-{
- int p_ch;
-
- if (port < I2C_STANDARD_PORT_COUNT)
- 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);
-}
-
-int chip_i2c_xfer(int port, uint16_t addr_flags,
- const uint8_t *out, int out_size,
- uint8_t *in, int in_size, int flags)
-{
- struct i2c_port_data *pd = pdata + port;
- uint32_t events = 0;
-
- if (out_size == 0 && in_size == 0)
- return EC_SUCCESS;
-
- /*
- * Make the below i2c transaction work:
- * - i2c_xfer with I2C_XFER_START flag
- * - i2c_xfer with I2C_XFER_START flag
- * - xxx
- * - i2c_xfer with I2C_XFER_STOP flag
- */
- if (pd->i2ccs)
- flags &= ~I2C_XFER_START;
-
- /* Copy data to port struct */
- pd->out = out;
- pd->out_size = out_size;
- pd->in = in;
- pd->in_size = in_size;
- pd->flags = flags;
- pd->widx = 0;
- pd->ridx = 0;
- pd->err = 0;
- pd->addr_8bit = I2C_STRIP_FLAGS(addr_flags) << 1;
-
- /* 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. */
- pd->err = i2c_unwedge(port);
-
- /* reset i2c port */
- i2c_reset(port, I2C_RC_NO_IDLE_FOR_START);
-
- /* Return if port is still wedged */
- if (pd->err)
- return pd->err;
- }
-
- pd->task_waiting = task_get_current();
- if (pd->flags & I2C_XFER_START) {
- pd->i2ccs = I2C_CH_NORMAL;
- /* enable i2c interrupt */
- task_clear_pending_irq(i2c_ctrl_regs[port].irq);
- task_enable_irq(i2c_ctrl_regs[port].irq);
- }
- /* Start transaction */
- i2c_transaction(port);
- /* Wait for transfer complete or timeout */
- events = task_wait_event_mask(TASK_EVENT_I2C_IDLE, pd->timeout_us);
- /* disable i2c interrupt */
- task_disable_irq(i2c_ctrl_regs[port].irq);
- pd->task_waiting = TASK_ID_INVALID;
-
- /* Handle timeout */
- if (!(events & TASK_EVENT_I2C_IDLE)) {
- pd->err = EC_ERROR_TIMEOUT;
- /* reset i2c port */
- i2c_reset(port, I2C_RC_TIMEOUT);
- }
-
- /* reset i2c channel status */
- if (pd->err)
- pd->i2ccs = I2C_CH_NORMAL;
-
- return pd->err;
-}
-
-int i2c_raw_get_scl(int port)
-{
- enum gpio_signal g;
-
- if (get_scl_from_i2c_port(port, &g) == EC_SUCCESS)
- return !!(*i2c_pin_regs[port].mirror_clk &
- i2c_pin_regs[port].clk_mask);
-
- /* If no SCL pin defined for this port, then return 1 to appear idle */
- return 1;
-}
-
-int i2c_raw_get_sda(int port)
-{
- enum gpio_signal g;
-
- if (get_sda_from_i2c_port(port, &g) == EC_SUCCESS)
- return !!(*i2c_pin_regs[port].mirror_data &
- i2c_pin_regs[port].data_mask);
-
- /* If no SDA pin defined for this port, then return 1 to appear idle */
- return 1;
-}
-
-int i2c_get_line_levels(int port)
-{
- int pin_sts = 0;
-
- if (port < I2C_STANDARD_PORT_COUNT)
- return IT83XX_SMB_SMBPCTL(port) & 0x03;
-
- if (*i2c_pin_regs[port].mirror_clk & i2c_pin_regs[port].clk_mask)
- pin_sts |= I2C_LINE_SCL_HIGH;
- if (*i2c_pin_regs[port].mirror_data & i2c_pin_regs[port].data_mask)
- pin_sts |= I2C_LINE_SDA_HIGH;
-
- return pin_sts;
-}
-
-void i2c_set_timeout(int port, uint32_t timeout)
-{
- pdata[port].timeout_us = timeout ? timeout : I2C_TIMEOUT_DEFAULT_US;
-}
-
-void i2c_interrupt(int port)
-{
- int id = pdata[port].task_waiting;
-
- /* Clear the interrupt status */
- task_clear_pending_irq(i2c_ctrl_regs[port].irq);
-
- /* If no task is waiting, just return */
- if (id == TASK_ID_INVALID)
- return;
-
- /* If done doing work, wake up the task waiting for the transfer */
- if (!i2c_transaction(port)) {
- task_disable_irq(i2c_ctrl_regs[port].irq);
- task_set_event(id, TASK_EVENT_I2C_IDLE);
- }
-}
-
-/*
- * Set i2c standard port (A, B, or C) runs at 400kHz by using timing registers
- * (offset 0h ~ 7h).
- */
-static void i2c_standard_port_timing_regs_400khz(int port)
-{
- /* Port clock frequency depends on setting of timing registers. */
- IT83XX_SMB_SCLKTS(port) = 0;
- /* Suggested setting of timing registers of 400kHz. */
- IT83XX_SMB_4P7USL = 0x6;
- IT83XX_SMB_4P0USL = 0;
- IT83XX_SMB_300NS = 0x1;
- IT83XX_SMB_250NS = 0x2;
- IT83XX_SMB_45P3USL = 0x6a;
- IT83XX_SMB_45P3USH = 0x1;
- IT83XX_SMB_4P7A4P0H = 0;
-}
-
-/* Set clock frequency for i2c port A, B , or C */
-static void i2c_standard_port_set_frequency(int port, int freq_khz)
-{
- /*
- * If port's clock frequency is 400kHz, we use timing registers
- * for setting. So we can adjust tlow to meet timing.
- * The others use basic 50/100/1000 KHz setting.
- */
- if (freq_khz == 400) {
- i2c_standard_port_timing_regs_400khz(port);
- } else {
- for (int f = ARRAY_SIZE(i2c_freq_select) - 1; f >= 0; f--) {
- if (freq_khz >= i2c_freq_select[f].kbps) {
- IT83XX_SMB_SCLKTS(port) =
- i2c_freq_select[f].freq_set;
- break;
- }
- }
- }
-
- /* This field defines the SMCLK0/1/2 clock/data low timeout. */
- IT83XX_SMB_25MS = I2C_CLK_LOW_TIMEOUT;
-}
-
-/* Set clock frequency for i2c port D, E , or F */
-static void i2c_enhanced_port_set_frequency(int port, int freq_khz)
-{
- int port_reg_shift, clk_div, psr;
-
- /* Get base address of i2c enhanced port's registers. */
- port_reg_shift = i2c_ch_reg_shift(port);
- /*
- * Let psr(Prescale) = IT83XX_I2C_PSR(port_reg_shift)
- * Then, 1 SCL cycle = 2 x (psr + 2) x SMBus clock cycle
- * SMBus clock = PLL_CLOCK / clk_div
- * SMBus clock cycle = 1 / SMBus clock
- * 1 SCL cycle = 1 / (1000 x freq)
- * 1 / (1000 x freq) = 2 x (psr + 2) x (1 / (PLL_CLOCK / clk_div))
- * psr = ((PLL_CLOCK / clk_div) x (1 / (1000 x freq)) x (1 / 2)) - 2
- */
- if (freq_khz) {
- /* Get SMBus clock divide value */
- clk_div = (IT83XX_ECPM_SCDCR2 & 0x0F) + 1;
- /* Calculate PSR value */
- psr = (PLL_CLOCK / (clk_div * (2 * 1000 * freq_khz))) - 2;
- /* Set psr value under 0xFD */
- if (psr > 0xFD)
- psr = 0xFD;
-
- /* Set I2C Speed */
- IT83XX_I2C_PSR(port_reg_shift) = (psr & 0xFF);
- IT83XX_I2C_HSPR(port_reg_shift) = (psr & 0xFF);
- /* Backup */
- pdata[port].freq = (psr & 0xFF);
- }
-}
-
-static void i2c_freq_changed(void)
-{
- int i, freq, port;
-
- /* Set clock frequency for I2C ports */
- for (i = 0; i < i2c_ports_used; i++) {
- freq = i2c_ports[i].kbps;
- port = i2c_ports[i].port;
- if (port < I2C_STANDARD_PORT_COUNT)
- i2c_standard_port_set_frequency(port, freq);
- else
- i2c_enhanced_port_set_frequency(port, freq);
- }
-}
-DECLARE_HOOK(HOOK_FREQ_CHANGE, i2c_freq_changed, HOOK_PRIO_DEFAULT);
-
-void i2c_init(void)
-{
- int i, p, p_ch;
-
- /* Configure GPIOs */
- gpio_config_module(MODULE_I2C, 1);
-
-#ifdef CONFIG_IT83XX_SMCLK2_ON_GPC7
- /* bit7, 0: SMCLK2 is located on GPF6, 1: SMCLK2 is located on GPC7 */
- IT83XX_GPIO_GRC7 |= 0x80;
-#endif
-
- /* Enable I2C function. */
- for (i = 0; i < i2c_ports_used; i++) {
- /* I2c port mapping. */
- p = i2c_ports[i].port;
-
- clock_enable_peripheral(i2c_ctrl_regs[p].clock_gate, 0, 0);
-
- if (p < I2C_STANDARD_PORT_COUNT) {
- /*
- * bit0, The SMBus host interface is enabled.
- * bit1, Enable to communicate with I2C device
- * and support I2C-compatible cycles.
- * bit4, This bit controls the reset mechanism
- * of SMBus master to handle the SMDAT
- * line low if 25ms reg timeout.
- */
- IT83XX_SMB_HOCTL2(p) = 0x11;
- /*
- * bit1, Kill SMBus host transaction.
- * bit0, Enable the interrupt for the master interface.
- */
- IT83XX_SMB_HOCTL(p) = 0x03;
- IT83XX_SMB_HOCTL(p) = 0x01;
- /* W/C host status register */
- IT83XX_SMB_HOSTA(p) = HOSTA_ALL_WC_BIT;
- IT83XX_SMB_HOCTL2(p) = 0x00;
- } else {
- /* Shift register */
- p_ch = i2c_ch_reg_shift(p);
- switch (p) {
- case IT83XX_I2C_CH_D:
- #ifndef CONFIG_UART_HOST
- /* Enable SMBus D channel */
- IT83XX_GPIO_GRC2 |= 0x20;
- #endif
- break;
- case IT83XX_I2C_CH_E:
- /* Enable SMBus E channel */
- IT83XX_GCTRL_PMER1 |= 0x01;
- break;
- case IT83XX_I2C_CH_F:
- /* Enable SMBus F channel */
- IT83XX_GCTRL_PMER1 |= 0x02;
- break;
- }
- /* Software reset */
- IT83XX_I2C_DHTR(p_ch) |= 0x80;
- IT83XX_I2C_DHTR(p_ch) &= 0x7F;
- /* State reset and hardware reset */
- 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;
- }
-
- i2c_freq_changed();
-
- for (i = 0; i < I2C_PORT_COUNT; i++) {
- /* Use default timeout */
- i2c_set_timeout(i, 0);
- }
-}