summaryrefslogtreecommitdiff
path: root/chip/ish/i2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'chip/ish/i2c.c')
-rw-r--r--chip/ish/i2c.c546
1 files changed, 0 insertions, 546 deletions
diff --git a/chip/ish/i2c.c b/chip/ish/i2c.c
deleted file mode 100644
index 7e297a20eb..0000000000
--- a/chip/ish/i2c.c
+++ /dev/null
@@ -1,546 +0,0 @@
-/* Copyright 2016 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 port module for ISH */
-
-#include "common.h"
-#include "console.h"
-#include "config_chip.h"
-#include "gpio.h"
-#include "hooks.h"
-#include "i2c.h"
-#include "registers.h"
-#include "ish_i2c.h"
-#include "task.h"
-#include "timer.h"
-#include "hwtimer.h"
-#include "util.h"
-
-#define CPUTS(outstr) cputs(CC_I2C, outstr)
-#define CPRINTS(format, args...) cprints(CC_I2C, format, ## args)
-#define CPRINTF(format, args...) cprintf(CC_I2C, format, ## args)
-
-/*25MHz, 50MHz, 100MHz, 120MHz, 40MHz, 20MHz, 37MHz*/
-static uint16_t default_hcnt_scl_100[] = {
- 4000, 4420, 4920, 4400, 4000, 4000, 4300
-};
-
-static uint16_t default_lcnt_scl_100[] = {
- 4720, 5180, 4990, 5333, 4700, 5200, 4950
-};
-
-static uint16_t default_hcnt_scl_400[] = {
- 600, 820, 1120, 800, 600, 600, 450
-};
-
-static uint16_t default_lcnt_scl_400[] = {
- 1320, 1380, 1300, 1550, 1300, 1200, 1250
-};
-
-static uint16_t default_hcnt_scl_1000[] = {
- 260, 260, 260, 305, 260, 260, 260
-};
-
-static uint16_t default_lcnt_scl_1000[] = {
- 500, 500, 500, 525, 500, 500, 500
-};
-
-static uint16_t default_hcnt_scl_hs[] = { 160, 300, 160, 166, 175, 150, 162 };
-static uint16_t default_lcnt_scl_hs[] = { 320, 340, 320, 325, 325, 300, 297 };
-
-
-#ifdef CHIP_VARIANT_ISH5P4
-/* Change to I2C_FREQ_100 in real silicon platform */
-static uint8_t bus_freq[ISH_I2C_PORT_COUNT] = {
- I2C_FREQ_100, I2C_FREQ_100, I2C_FREQ_100
-};
-#else
-static uint8_t bus_freq[ISH_I2C_PORT_COUNT] = {
- I2C_FREQ_120, I2C_FREQ_120, I2C_FREQ_120
-};
-#endif
-
-static struct i2c_context i2c_ctxs[ISH_I2C_PORT_COUNT] = {
- {
- .bus = 0,
- .base = (uint32_t *) ISH_I2C0_BASE,
- .speed = I2C_SPEED_400KHZ,
- .int_pin = ISH_I2C0_IRQ,
- },
- {
- .bus = 1,
- .base = (uint32_t *) ISH_I2C1_BASE,
- .speed = I2C_SPEED_400KHZ,
- .int_pin = ISH_I2C1_IRQ,
- },
- {
- .bus = 2,
- .base = (uint32_t *) ISH_I2C2_BASE,
- .speed = I2C_SPEED_400KHZ,
- .int_pin = ISH_I2C2_IRQ,
- },
-};
-
-static struct i2c_bus_info board_config[ISH_I2C_PORT_COUNT] = {
- {
- .bus_id = 0,
- .std_speed.sda_hold = DEFAULT_SDA_HOLD_STD,
- .fast_speed.sda_hold = DEFAULT_SDA_HOLD_FAST,
- .fast_plus_speed.sda_hold = DEFAULT_SDA_HOLD_FAST_PLUS,
- .high_speed.sda_hold = DEFAULT_SDA_HOLD_HIGH,
- },
- {
- .bus_id = 1,
- .std_speed.sda_hold = DEFAULT_SDA_HOLD_STD,
- .fast_speed.sda_hold = DEFAULT_SDA_HOLD_FAST,
- .fast_plus_speed.sda_hold = DEFAULT_SDA_HOLD_FAST_PLUS,
- .high_speed.sda_hold = DEFAULT_SDA_HOLD_HIGH,
- },
- {
- .bus_id = 2,
- .std_speed.sda_hold = DEFAULT_SDA_HOLD_STD,
- .fast_speed.sda_hold = DEFAULT_SDA_HOLD_FAST,
- .fast_plus_speed.sda_hold = DEFAULT_SDA_HOLD_FAST_PLUS,
- .high_speed.sda_hold = DEFAULT_SDA_HOLD_HIGH,
- },
-};
-
-static inline void i2c_mmio_write(uint32_t *base, uint8_t offset,
- uint32_t data)
-{
- REG32((uint32_t) ((uint8_t *)base + offset)) = data;
-}
-
-static inline uint32_t i2c_mmio_read(uint32_t *base, uint8_t offset)
-{
- return REG32((uint32_t) ((uint8_t *)base + offset));
-}
-
-static inline uint8_t i2c_read_byte(uint32_t *addr, uint8_t reg,
- uint8_t offset)
-{
- uint32_t ret = i2c_mmio_read(addr, reg) >> offset;
-
- return ret & 0xff;
-}
-
-static void i2c_intr_switch(uint32_t *base, int mode)
-{
- switch (mode) {
-
- case ENABLE_WRITE_INT:
- i2c_mmio_write(base, IC_INTR_MASK, IC_INTR_WRITE_MASK_VAL);
- break;
-
- case ENABLE_READ_INT:
- i2c_mmio_write(base, IC_INTR_MASK, IC_INTR_READ_MASK_VAL);
- break;
-
- case DISABLE_INT:
- i2c_mmio_write(base, IC_INTR_MASK, 0);
- /* clear interrupts: TX_ABORT
- * Because the DW_apb_i2c's TX FIFO is forced into a
- * flushed/reset state whenever a TX_ABRT event occurs, it
- * is necessary for software to release the DW_apb_i2c from
- * this state by reading the IC_CLR_TX_ABRT register before
- * attempting to write into the TX FIFO
- */
- i2c_mmio_read(base, IC_CLR_TX_ABRT);
- /* STOP_DET */
- i2c_mmio_read(base, IC_CLR_STOP_DET);
- break;
-
- default:
- break;
- }
-}
-
-static void i2c_init_transaction(struct i2c_context *ctx,
- uint16_t slave_addr, uint8_t flags)
-{
- uint32_t con_value;
- uint32_t *base = ctx->base;
- struct i2c_bus_info *bus_info = &board_config[ctx->bus];
- uint32_t clk_in_val = clk_in[bus_freq[ctx->bus]];
-
- /* disable interrupts */
- i2c_intr_switch(base, DISABLE_INT);
-
- i2c_mmio_write(base, IC_ENABLE, IC_ENABLE_DISABLE);
- i2c_mmio_write(base, IC_TAR, (slave_addr << IC_TAR_OFFSET) |
- TAR_SPECIAL_VAL | IC_10BITADDR_MASTER_VAL);
-
- /* set Clock SCL Count */
- switch (ctx->speed) {
-
- case I2C_SPEED_100KHZ:
- i2c_mmio_write(base, IC_SS_SCL_HCNT,
- NS_2_COUNTERS(bus_info->std_speed.hcnt,
- clk_in_val));
- i2c_mmio_write(base, IC_SS_SCL_LCNT,
- NS_2_COUNTERS(bus_info->std_speed.lcnt,
- clk_in_val));
- i2c_mmio_write(base, IC_SDA_HOLD,
- NS_2_COUNTERS(bus_info->std_speed.sda_hold,
- clk_in_val));
- break;
-
- case I2C_SPEED_400KHZ:
- i2c_mmio_write(base, IC_FS_SCL_HCNT,
- NS_2_COUNTERS(bus_info->fast_speed.hcnt,
- clk_in_val));
- i2c_mmio_write(base, IC_FS_SCL_LCNT,
- NS_2_COUNTERS(bus_info->fast_speed.lcnt,
- clk_in_val));
- i2c_mmio_write(base, IC_SDA_HOLD,
- NS_2_COUNTERS(bus_info->fast_speed.sda_hold,
- clk_in_val));
- break;
-
- case I2C_SPEED_1MHZ:
- i2c_mmio_write(base, IC_FS_SCL_HCNT,
- NS_2_COUNTERS(bus_info->fast_plus_speed.hcnt,
- clk_in_val));
- i2c_mmio_write(base, IC_FS_SCL_LCNT,
- NS_2_COUNTERS(bus_info->fast_plus_speed.lcnt,
- clk_in_val));
- i2c_mmio_write(base, IC_SDA_HOLD,
- NS_2_COUNTERS(bus_info->fast_plus_speed.sda_hold,
- clk_in_val));
- break;
-
- case I2C_SPEED_3M4HZ:
- i2c_mmio_write(base, IC_HS_SCL_HCNT,
- NS_2_COUNTERS(bus_info->high_speed.hcnt,
- clk_in_val));
- i2c_mmio_write(base, IC_HS_SCL_LCNT,
- NS_2_COUNTERS(bus_info->high_speed.lcnt,
- clk_in_val));
- i2c_mmio_write(base, IC_SDA_HOLD,
- NS_2_COUNTERS(bus_info->high_speed.sda_hold,
- clk_in_val));
-
- i2c_mmio_write(base, IC_FS_SCL_HCNT,
- NS_2_COUNTERS(bus_info->fast_speed.hcnt,
- clk_in_val));
- i2c_mmio_write(base, IC_FS_SCL_LCNT,
- NS_2_COUNTERS(bus_info->fast_speed.lcnt,
- clk_in_val));
- break;
-
- default:
- break;
- }
-
- /* in SPT HW we need to sync between I2C clock and data signals */
- con_value = i2c_mmio_read(base, IC_CON);
-
- if (flags != 0)
- con_value |= IC_RESTART_EN_VAL;
- else
- con_value &= ~IC_RESTART_EN_VAL;
-
- i2c_mmio_write(base, IC_CON, con_value);
- i2c_mmio_write(base, IC_FS_SPKLEN, spkln[bus_freq[ctx->bus]]);
- i2c_mmio_write(base, IC_HS_SPKLEN, spkln[bus_freq[ctx->bus]]);
- i2c_mmio_write(base, IC_ENABLE, IC_ENABLE_ENABLE);
-}
-
-static void i2c_write_buffer(uint32_t *base, uint8_t len,
- const uint8_t *buffer, ssize_t *cur_index,
- ssize_t total_len)
-{
- int i;
- uint16_t out;
-
- for (i = 0; i < len; i++) {
-
- ++(*cur_index);
- out = (buffer[i] << DATA_CMD_DAT_OFFSET) | DATA_CMD_WRITE_VAL;
-
- /* if Write ONLY and Last byte */
- if (*cur_index == total_len) {
- out |= DATA_CMD_STOP_VAL;
- }
-
- i2c_mmio_write(base, IC_DATA_CMD, out);
- }
-}
-
-static void i2c_write_read_commands(uint32_t *base, uint8_t len, int more_data,
- unsigned restart_flag)
-{
- /* this routine just set RX FIFO's control bit(s),
- * READ command or RESTART */
- int i;
- uint32_t data_cmd;
-
- for (i = 0; i < len; i++) {
- data_cmd = DATA_CMD_READ_VAL;
-
- if ((i == 0) && restart_flag)
- /* if restart for first byte */
- data_cmd |= DATA_CMD_RESTART_VAL;
-
- /* if last byte & less than FIFO size
- * or only one byte to read */
- if (i == (len - 1) && !more_data)
- data_cmd |= DATA_CMD_STOP_VAL;
-
- i2c_mmio_write(base, IC_DATA_CMD, data_cmd);
- }
-}
-
-int chip_i2c_xfer(const int port, const uint16_t slave_addr_flags,
- const uint8_t *out, int out_size,
- uint8_t *in, int in_size, int flags)
-{
- int i;
- ssize_t total_len;
- uint64_t expire_ts;
- struct i2c_context *ctx;
- ssize_t curr_index = 0;
- uint16_t addr = I2C_GET_ADDR(slave_addr_flags);
- int begin_indx;
- uint8_t repeat_start = 0;
-
- if (out_size == 0 && in_size == 0)
- return EC_SUCCESS;
-
- if (port < 0 || port >= ISH_I2C_PORT_COUNT)
- return EC_ERROR_INVAL;
-
- /* Check for reserved I2C addresses, pg. 74 in DW_apb_i2c.pdf
- * Address cannot be any of the reserved address locations
- */
- if (addr < I2C_FIRST_VALID_ADDR || addr > I2C_LAST_VALID_ADDR)
- return EC_ERROR_INVAL;
-
- /* assume that if both out_size and in_size are not zero,
- * then, it is 'repeated Start' condition. */
- if (in_size != 0 && out_size != 0)
- repeat_start = 1;
-
- ctx = &i2c_ctxs[port];
- ctx->error_flag = 0;
- ctx->wait_task_id = task_get_current();
-
- total_len = in_size + out_size;
-
- i2c_init_transaction(ctx, addr, repeat_start);
-
- /* Write W data */
- if (out_size)
- i2c_write_buffer(ctx->base, out_size, out,
- &curr_index, total_len);
-
- /* Wait here until Tx is completed so that FIFO becomes empty.
- * This is optimized for smaller Tx data size.
- * If need to write big data ( > ISH_I2C_FIFO_SIZE ),
- * it is better to use Tx FIFO threshold interrupt(as in Rx) for
- * better CPU usuage.
- * */
- expire_ts = __hw_clock_source_read() + I2C_TX_FLUSH_TIMEOUT_USEC;
- if (in_size > (ISH_I2C_FIFO_SIZE - out_size)) {
-
- while ((i2c_mmio_read(ctx->base, IC_STATUS) &
- BIT(IC_STATUS_TFE)) == 0) {
-
- if (__hw_clock_source_read() >= expire_ts) {
- ctx->error_flag = 1;
- break;
- }
- CPU_RELAX();
- }
- }
-
- begin_indx = 0;
- while (in_size) {
- int rd_size; /* read size for on i2c transaction */
-
- /*
- * check if in_size > ISH_I2C_FIFO_SIZE, then try to read
- * FIFO_SIZE each time.
- */
- if (in_size > ISH_I2C_FIFO_SIZE) {
- rd_size = ISH_I2C_FIFO_SIZE;
- in_size -= ISH_I2C_FIFO_SIZE;
- } else {
- rd_size = in_size;
- in_size = 0;
- }
- /* Set rx_threshold */
- i2c_mmio_write(ctx->base, IC_RX_TL, rd_size - 1);
-
- i2c_intr_switch(ctx->base, ENABLE_READ_INT);
-
- /*
- * RESTART only once for entire i2c transaction.
- * assume that if both out_size and in_size are not zero,
- * then, it is 'repeated Start' condition.
- * set R commands bit, start to read
- */
- i2c_write_read_commands(ctx->base, rd_size, in_size,
- (begin_indx == 0) && (repeat_start != 0));
-
-
- /* need timeout in case no ACK from slave */
- task_wait_event_mask(TASK_EVENT_I2C_IDLE, 2*MSEC);
-
- if (ctx->interrupts & M_TX_ABRT) {
- ctx->error_flag = 1;
- break; /* when bus abort, no more reading !*/
- }
-
- /* read data */
- for (i = begin_indx; i < begin_indx + rd_size; i++)
- in[i] = i2c_read_byte(ctx->base,
- IC_DATA_CMD, 0);
-
- begin_indx += rd_size;
- } /* while (in_size) */
-
- ctx->reason = 0;
- ctx->interrupts = 0;
-
- /* do not disable device before master is idle */
- expire_ts = __hw_clock_source_read() + I2C_TSC_TIMEOUT;
-
- while ((i2c_mmio_read(ctx->base, IC_STATUS) &
- (BIT(IC_STATUS_MASTER_ACTIVITY) | BIT(IC_STATUS_TFE))) !=
- BIT(IC_STATUS_TFE)) {
-
- if (__hw_clock_source_read() >= expire_ts) {
- ctx->error_flag = 1;
- break;
- }
- }
-
- i2c_intr_switch(ctx->base, DISABLE_INT);
- i2c_mmio_write(ctx->base, IC_ENABLE, IC_ENABLE_DISABLE);
-
- if (ctx->error_flag)
- return EC_ERROR_INVAL;
-
- return EC_SUCCESS;
-}
-
-static void i2c_interrupt_handler(struct i2c_context *ctx)
-{
- uint32_t raw_intr;
-
- if (IS_ENABLED(INTR_DEBUG))
- raw_intr = 0x0000FFFF & i2c_mmio_read(ctx->base,
- IC_RAW_INTR_STAT);
-
- /* check interrupts */
- ctx->interrupts = i2c_mmio_read(ctx->base, IC_INTR_STAT);
- ctx->reason = (uint16_t) i2c_mmio_read(ctx->base, IC_TX_ABRT_SOURCE);
-
- if (IS_ENABLED(INTR_DEBUG))
- CPRINTS("INTR_STAT = 0x%04x, TX_ABORT_SRC = 0x%04x, "
- "RAW_INTR_STAT = 0x%04x",
- ctx->interrupts, ctx->reason, raw_intr);
-
- /* disable interrupts */
- i2c_intr_switch(ctx->base, DISABLE_INT);
- task_set_event(ctx->wait_task_id, TASK_EVENT_I2C_IDLE, 0);
-}
-
-static void i2c_isr_bus0(void)
-{
- i2c_interrupt_handler(&i2c_ctxs[0]);
-}
-DECLARE_IRQ(ISH_I2C0_IRQ, i2c_isr_bus0);
-
-static void i2c_isr_bus1(void)
-{
- i2c_interrupt_handler(&i2c_ctxs[1]);
-}
-DECLARE_IRQ(ISH_I2C1_IRQ, i2c_isr_bus1);
-
-static void i2c_isr_bus2(void)
-{
- i2c_interrupt_handler(&i2c_ctxs[2]);
-}
-DECLARE_IRQ(ISH_I2C2_IRQ, i2c_isr_bus2);
-
-static void i2c_config_speed(struct i2c_context *ctx, int kbps)
-{
-
- if (kbps > 1000)
- ctx->speed = I2C_SPEED_3M4HZ;
- else if (kbps > 400)
- ctx->speed = I2C_SPEED_1MHZ;
- else if (kbps > 100)
- ctx->speed = I2C_SPEED_400KHZ;
- else
- ctx->speed = I2C_SPEED_100KHZ;
-
-}
-
-static void i2c_init_hardware(struct i2c_context *ctx)
-{
- static const uint8_t speed_val_arr[] = {
- [I2C_SPEED_100KHZ] = STD_SPEED_VAL,
- [I2C_SPEED_400KHZ] = FAST_SPEED_VAL,
- [I2C_SPEED_1MHZ] = FAST_SPEED_VAL,
- [I2C_SPEED_3M4HZ] = HIGH_SPEED_VAL,
- };
-
- uint32_t *base = ctx->base;
-
- /* disable interrupts */
- i2c_intr_switch(base, DISABLE_INT);
- i2c_mmio_write(base, IC_ENABLE, IC_ENABLE_DISABLE);
- i2c_mmio_write(base, IC_CON, (MASTER_MODE_VAL
- | speed_val_arr[ctx->speed]
- | IC_RESTART_EN_VAL
- | IC_SLAVE_DISABLE_VAL));
-
- i2c_mmio_write(base, IC_FS_SPKLEN, spkln[bus_freq[ctx->bus]]);
- i2c_mmio_write(base, IC_HS_SPKLEN, spkln[bus_freq[ctx->bus]]);
-
- /* get RX_FIFO and TX_FIFO depth */
- ctx->max_rx_depth = i2c_read_byte(base, IC_COMP_PARAM_1,
- RX_BUFFER_DEPTH_OFFSET) + 1;
- ctx->max_tx_depth = i2c_read_byte(base, IC_COMP_PARAM_1,
- TX_BUFFER_DEPTH_OFFSET) + 1;
-}
-
-static void i2c_initial_board_config(struct i2c_context *ctx)
-{
- uint8_t freq = bus_freq[ctx->bus];
- struct i2c_bus_info *bus_info = &board_config[ctx->bus];
-
- bus_info->std_speed.hcnt = default_hcnt_scl_100[freq];
- bus_info->std_speed.lcnt = default_lcnt_scl_100[freq];
-
- bus_info->fast_speed.hcnt = default_hcnt_scl_400[freq];
- bus_info->fast_speed.lcnt = default_lcnt_scl_400[freq];
-
- bus_info->fast_plus_speed.hcnt = default_hcnt_scl_1000[freq];
- bus_info->fast_plus_speed.lcnt = default_lcnt_scl_1000[freq];
-
- bus_info->high_speed.hcnt = default_hcnt_scl_hs[freq];
- bus_info->high_speed.lcnt = default_lcnt_scl_hs[freq];
-}
-
-void i2c_init(void)
-{
- int i;
-
- for (i = 0; i < i2c_ports_used; i++) {
- int port = i2c_ports[i].port;
- i2c_initial_board_config(&i2c_ctxs[port]);
- /* Config speed from i2c_ports[] defined in board.c */
- i2c_config_speed(&i2c_ctxs[port], i2c_ports[i].kbps);
- i2c_init_hardware(&i2c_ctxs[port]);
-
- task_enable_irq((&i2c_ctxs[port])->int_pin);
- }
-
- CPRINTS("Done i2c_init");
-}