mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-27 18:25:05 +00:00
it8380dev: add i2c control module
Add i2c control module for emulation board. To rename CONFIG_ to CONFIG_IT83XX_ for IT83XX series configuration. Signed-off-by: Dino Li <dino.li@ite.com.tw> BRANCH=none BUG=none TEST=1. console command "i2cscan" found devices correctly. 2. console command "i2cxfer". 2-a. port2 + battery, i2cxfer r, r16, and rlen OK. 2-b. port1 + slave evb, i2cxfer r, r16, rlen, w, and w16 OK. Change-Id: I67165f7dcdef538ba6dd03b47f1621a73cc68379 Reviewed-on: https://chromium-review.googlesource.com/263678 Reviewed-by: Alec Berg <alecaberg@chromium.org> Commit-Queue: Dino Li <dino.li@ite.com.tw> Tested-by: Dino Li <dino.li@ite.com.tw>
This commit is contained in:
committed by
ChromeOS Commit Bot
parent
75b95672ac
commit
60e110acd1
@@ -23,6 +23,7 @@
|
||||
#include "lpc.h"
|
||||
#include "intc.h"
|
||||
#include "fan.h"
|
||||
#include "i2c.h"
|
||||
|
||||
/* Test GPIO interrupt function that toggles one LED. */
|
||||
void test_interrupt(enum gpio_signal signal)
|
||||
@@ -181,6 +182,21 @@ struct keyboard_scan_config keyscan_config = {
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* I2C channels (A, B, and C) are using the same timing registers (00h~07h)
|
||||
* at default.
|
||||
* In order to set frequency independently for each channels,
|
||||
* We use timing registers 09h~0Bh, and the supported frequency will be:
|
||||
* 50KHz, 100KHz, 400KHz, or 1MHz.
|
||||
*/
|
||||
/* I2C ports */
|
||||
const struct i2c_port_t i2c_ports[] = {
|
||||
{"battery", 2, 100, GPIO_I2C_C_SCL, GPIO_I2C_C_SDA},
|
||||
{"evb-1", 0, 100, GPIO_I2C_A_SCL, GPIO_I2C_A_SDA},
|
||||
{"evb-2", 1, 100, GPIO_I2C_B_SCL, GPIO_I2C_B_SDA},
|
||||
};
|
||||
const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Console commands */
|
||||
|
||||
|
||||
@@ -9,17 +9,18 @@
|
||||
#define __CROS_EC_BOARD_H
|
||||
|
||||
/* Optional features */
|
||||
#define CONFIG_POWER_BUTTON
|
||||
#define CONFIG_KEYBOARD_PROTOCOL_8042
|
||||
#define CONFIG_KEYBOARD_BOARD_CONFIG
|
||||
#undef CONFIG_KEYBOARD_KSI_WUC_INT
|
||||
#undef CONFIG_SPI_USE_CS1
|
||||
#define CONFIG_PECI_TJMAX 100
|
||||
/* For IT839X series and IT838X DX only. */
|
||||
#define CONFIG_PECI_WITH_INTERRUPT
|
||||
#define CONFIG_FANS 1
|
||||
#undef CHIP_FAMILY_IT839X
|
||||
|
||||
#define CONFIG_FANS 1
|
||||
#undef CONFIG_IT83XX_KEYBOARD_KSI_WUC_INT
|
||||
#define CONFIG_IT83XX_PECI_WITH_INTERRUPT
|
||||
#define CONFIG_IT83XX_SMCLK2_ON_GPC7
|
||||
#undef CONFIG_IT83XX_SPI_USE_CS1
|
||||
#define CONFIG_KEYBOARD_BOARD_CONFIG
|
||||
#define CONFIG_KEYBOARD_PROTOCOL_8042
|
||||
#define CONFIG_PECI_TJMAX 100
|
||||
#define CONFIG_POWER_BUTTON
|
||||
|
||||
/* Debug */
|
||||
#undef CONFIG_KEYBOARD_DEBUG
|
||||
#undef CONFIG_UART_TX_BUF_SIZE
|
||||
|
||||
@@ -33,16 +33,35 @@ GPIO(PCH_RCIN_L, PIN(B, 6), GPIO_OUT_HIGH)
|
||||
GPIO(LPC_CLKRUN_L, PIN(H, 0), GPIO_OUT_LOW)
|
||||
GPIO(PCH_WAKE_L, PIN(B, 7), GPIO_ODR_HIGH) /* Wake signal from EC to PCH */
|
||||
|
||||
GPIO(I2C_A_SCL, PIN(B, 3), GPIO_INPUT)
|
||||
GPIO(I2C_A_SDA, PIN(B, 4), GPIO_INPUT)
|
||||
GPIO(I2C_B_SCL, PIN(C, 1), GPIO_INPUT)
|
||||
GPIO(I2C_B_SDA, PIN(C, 2), GPIO_INPUT)
|
||||
#ifdef CONFIG_IT83XX_SMCLK2_ON_GPC7
|
||||
GPIO(I2C_C_SCL, PIN(C, 7), GPIO_INPUT)
|
||||
#else
|
||||
GPIO(I2C_C_SCL, PIN(F, 6), GPIO_INPUT)
|
||||
#endif
|
||||
GPIO(I2C_C_SDA, PIN(F, 7), GPIO_INPUT)
|
||||
|
||||
/* Unimplemented signals which we need to emulate for now */
|
||||
UNIMPLEMENTED(ENTERING_RW)
|
||||
|
||||
ALTERNATE(PIN_MASK(B, 0x03), 1, MODULE_UART, GPIO_PULL_UP) /* UART0 */
|
||||
ALTERNATE(PIN_MASK(A, 0x40), 3, MODULE_SPI, 0) /* SSCK of SPI */
|
||||
ALTERNATE(PIN_MASK(C, 0x28), 3, MODULE_SPI, 0) /* SMOSI/SMISO of SPI */
|
||||
#ifdef CONFIG_SPI_USE_CS1
|
||||
#ifdef CONFIG_IT83XX_SPI_USE_CS1
|
||||
ALTERNATE(PIN_MASK(G, 0x01), 3, MODULE_SPI, 0) /* SSCE1# of SPI */
|
||||
#else
|
||||
ALTERNATE(PIN_MASK(G, 0x04), 3, MODULE_SPI, 0) /* SSCE0# of SPI */
|
||||
#endif
|
||||
ALTERNATE(PIN_MASK(A, 0x80), 1, MODULE_PWM_FAN, 0) /* PWM7 for FAN1 */
|
||||
ALTERNATE(PIN_MASK(D, 0x40), 3, MODULE_PWM_FAN, 0) /* TACH0A for FAN1 */
|
||||
ALTERNATE(PIN_MASK(B, 0x18), 1, MODULE_I2C, 0) /* I2C A SCL/SDA */
|
||||
#ifdef CONFIG_IT83XX_SMCLK2_ON_GPC7
|
||||
ALTERNATE(PIN_MASK(C, 0x86), 1, MODULE_I2C, 0) /* I2C B SCL/SDA, C SCL */
|
||||
ALTERNATE(PIN_MASK(F, 0x80), 1, MODULE_I2C, 0) /* I2C C SDA */
|
||||
#else
|
||||
ALTERNATE(PIN_MASK(C, 0x06), 1, MODULE_I2C, 0) /* I2C B SCL/SDA */
|
||||
ALTERNATE(PIN_MASK(F, 0xC0), 1, MODULE_I2C, 0) /* I2C C SCL/SDA */
|
||||
#endif
|
||||
|
||||
@@ -24,3 +24,4 @@ chip-$(CONFIG_LPC)+=lpc.o
|
||||
chip-$(CONFIG_SPI)+=spi.o
|
||||
chip-$(CONFIG_PECI)+=peci.o
|
||||
chip-$(HAS_TASK_KEYSCAN)+=keyboard_raw.o
|
||||
chip-$(CONFIG_I2C)+=i2c.o
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
/* Default PLL frequency. */
|
||||
#define PLL_CLOCK 48000000
|
||||
|
||||
/* Number of I2C ports */
|
||||
#define I2C_PORT_COUNT 3
|
||||
|
||||
/****************************************************************************/
|
||||
/* Memory mapping */
|
||||
|
||||
@@ -76,15 +79,15 @@
|
||||
#define CONFIG_HW_SPECIFIC_UDELAY
|
||||
|
||||
/* Optional features present on this chip */
|
||||
#undef CONFIG_I2C
|
||||
#undef CONFIG_FLASH
|
||||
#undef CONFIG_WATCHDOG
|
||||
#define CONFIG_PWM
|
||||
#define CONFIG_ADC
|
||||
#define CONFIG_EC2I
|
||||
#undef CONFIG_FLASH
|
||||
#define CONFIG_I2C
|
||||
#define CONFIG_LPC
|
||||
#define CONFIG_SPI
|
||||
#define CONFIG_PECI
|
||||
#define CONFIG_PWM
|
||||
#define CONFIG_SPI
|
||||
#undef CONFIG_WATCHDOG
|
||||
|
||||
#define GPIO_PIN(port, index) GPIO_##port, (1 << index)
|
||||
#define GPIO_PIN_MASK(port, mask) GPIO_##port, (mask)
|
||||
|
||||
@@ -360,7 +360,7 @@ static void __gpio_irq(void)
|
||||
/* Determine interrupt number. */
|
||||
int irq = IT83XX_INTC_IVCT2 - 16;
|
||||
|
||||
#if defined(HAS_TASK_KEYSCAN) && defined(CONFIG_KEYBOARD_KSI_WUC_INT)
|
||||
#if defined(HAS_TASK_KEYSCAN) && defined(CONFIG_IT83XX_KEYBOARD_KSI_WUC_INT)
|
||||
if (irq == IT83XX_IRQ_WKINTC) {
|
||||
keyboard_raw_interrupt();
|
||||
return;
|
||||
|
||||
468
chip/it83xx/i2c.c
Normal file
468
chip/it83xx/i2c.c
Normal file
@@ -0,0 +1,468 @@
|
||||
/* 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)
|
||||
|
||||
/*
|
||||
* The count number of the counter for 25 ms register.
|
||||
* The 25 ms register is calculated by (count number *1.024 kHz).
|
||||
*/
|
||||
#define I2C_CLK_LOW_TIMEOUT 25 /* ~= 25ms */
|
||||
|
||||
#define I2C_LOOP_DELAY_US 16
|
||||
|
||||
/* Default maximum time we allow for an I2C transfer */
|
||||
#define I2C_TIMEOUT_DEFAULT_US (100 * MSEC)
|
||||
|
||||
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,
|
||||
|
||||
HOSTA_NO_FINISH = 0xFF,
|
||||
};
|
||||
|
||||
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 i2c_reset_cause {
|
||||
I2C_RC_NO_IDLE_FOR_START = 1,
|
||||
I2C_RC_READ_NO_FINISH,
|
||||
I2C_RC_WRITE_NO_FINISH,
|
||||
};
|
||||
|
||||
struct i2c_ch_freq {
|
||||
int kpbs;
|
||||
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
|
||||
};
|
||||
|
||||
/* 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; /* address of device */
|
||||
uint32_t timeout_us; /* Transaction timeout, or 0 to use default */
|
||||
};
|
||||
static struct i2c_port_data pdata[I2C_PORT_COUNT];
|
||||
|
||||
static void i2c_reset(int p, int cause)
|
||||
{
|
||||
/* 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;
|
||||
|
||||
/* W/C host status register */
|
||||
IT83XX_SMB_HOSTA(p) = HOSTA_ALL_WC_BIT;
|
||||
|
||||
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 int i2c_transaction(int p)
|
||||
{
|
||||
uint32_t num;
|
||||
struct i2c_port_data *pd = pdata + p;
|
||||
|
||||
/* i2c write */
|
||||
if (pd->out_size) {
|
||||
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 slave.
|
||||
*/
|
||||
IT83XX_SMB_TRASLA(p) = pd->addr;
|
||||
/* Send first byte */
|
||||
IT83XX_SMB_HOBDB(p) = *(pd->out++);
|
||||
pd->widx++;
|
||||
/*
|
||||
* bit0, Host interrupt enable.
|
||||
* bit[2:4}, Extend command.
|
||||
* bit6, start.
|
||||
*/
|
||||
IT83XX_SMB_HOCTL(p) = 0x5D;
|
||||
}
|
||||
|
||||
for (num = 0; num < pd->timeout_us; num += I2C_LOOP_DELAY_US) {
|
||||
/* 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++;
|
||||
} else {
|
||||
if (pd->in_size > 0) {
|
||||
i2c_w2r_change_direction(p);
|
||||
goto write_to_read;
|
||||
}
|
||||
|
||||
if (pd->flags & I2C_XFER_STOP)
|
||||
IT83XX_SMB_HOCTL2(p) = 0x11;
|
||||
else
|
||||
break;
|
||||
}
|
||||
/* W/C byte done for next byte or finish */
|
||||
IT83XX_SMB_HOSTA(p) = HOSTA_NEXT_BYTE;
|
||||
/* This bit will be set by termination of a command */
|
||||
} else if (IT83XX_SMB_HOSTA(p) & HOSTA_FINTR) {
|
||||
break;
|
||||
}
|
||||
/* - 1 since some time was used in the code above */
|
||||
udelay(I2C_LOOP_DELAY_US - 1);
|
||||
}
|
||||
|
||||
pd->err = IT83XX_SMB_HOSTA(p) & HOSTA_ANY_ERROR;
|
||||
|
||||
if (num > pd->timeout_us) {
|
||||
pd->err = HOSTA_NO_FINISH;
|
||||
i2c_reset(p, I2C_RC_WRITE_NO_FINISH);
|
||||
}
|
||||
|
||||
if (pd->flags & I2C_XFER_STOP) {
|
||||
IT83XX_SMB_HOCTL2(p) = 0x00;
|
||||
/* W/C */
|
||||
IT83XX_SMB_HOSTA(p) = HOSTA_ALL_WC_BIT;
|
||||
}
|
||||
return pd->err;
|
||||
/* i2c read */
|
||||
} else if (pd->in_size) {
|
||||
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 slave.
|
||||
*/
|
||||
IT83XX_SMB_TRASLA(p) = pd->addr | 0x01;
|
||||
/*
|
||||
* 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 {
|
||||
i2c_w2r_change_direction(p);
|
||||
}
|
||||
|
||||
write_to_read:
|
||||
for (num = 0; num < pd->timeout_us; num += I2C_LOOP_DELAY_US) {
|
||||
/* when the host controller has received a byte */
|
||||
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);
|
||||
}
|
||||
|
||||
if ((pd->ridx == pd->in_size) &&
|
||||
(!(pd->flags & I2C_XFER_STOP)))
|
||||
break;
|
||||
|
||||
/* W/C for next byte or finish */
|
||||
IT83XX_SMB_HOSTA(p) = HOSTA_NEXT_BYTE;
|
||||
/* This bit will be set by termination of a command */
|
||||
} else if (IT83XX_SMB_HOSTA(p) & HOSTA_FINTR) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* - 1 since some time was used in the code above */
|
||||
udelay(I2C_LOOP_DELAY_US - 1);
|
||||
}
|
||||
|
||||
pd->err = IT83XX_SMB_HOSTA(p) & HOSTA_ANY_ERROR;
|
||||
|
||||
if (num > pd->timeout_us) {
|
||||
pd->err = HOSTA_NO_FINISH;
|
||||
i2c_reset(p, I2C_RC_READ_NO_FINISH);
|
||||
}
|
||||
|
||||
if (pd->flags & I2C_XFER_STOP) {
|
||||
IT83XX_SMB_HOCTL2(p) = 0x00;
|
||||
/* W/C */
|
||||
IT83XX_SMB_HOSTA(p) = HOSTA_ALL_WC_BIT;
|
||||
}
|
||||
return pd->err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2c_is_busy(int port)
|
||||
{
|
||||
return IT83XX_SMB_HOSTA(port) & HOSTA_HOBY;
|
||||
}
|
||||
|
||||
int chip_i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_size,
|
||||
uint8_t *in, int in_size, int flags)
|
||||
{
|
||||
struct i2c_port_data *pd = pdata + port;
|
||||
|
||||
if (out_size == 0 && in_size == 0)
|
||||
return EC_SUCCESS;
|
||||
|
||||
/* 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 = slave_addr;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
/* Start transaction */
|
||||
i2c_transaction(port);
|
||||
|
||||
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)
|
||||
{
|
||||
return IT83XX_SMB_SMBPCTL(port) & 0x03;
|
||||
}
|
||||
|
||||
void i2c_set_timeout(int port, uint32_t timeout)
|
||||
{
|
||||
pdata[port].timeout_us = timeout ? timeout : I2C_TIMEOUT_DEFAULT_US;
|
||||
}
|
||||
|
||||
static void i2c_freq_changed(void)
|
||||
{
|
||||
int i, f;
|
||||
|
||||
for (i = 0; i < i2c_ports_used; i++) {
|
||||
for (f = ARRAY_SIZE(i2c_freq_select) - 1; f >= 0; f--) {
|
||||
if (i2c_ports[i].kbps >= i2c_freq_select[f].kpbs) {
|
||||
IT83XX_SMB_SCLKTS(i2c_ports[i].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;
|
||||
}
|
||||
DECLARE_HOOK(HOOK_FREQ_CHANGE, i2c_freq_changed, HOOK_PRIO_DEFAULT);
|
||||
|
||||
static void i2c_init(void)
|
||||
{
|
||||
int i, p;
|
||||
|
||||
/* 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;
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
i2c_freq_changed();
|
||||
|
||||
for (i = 0; i < I2C_PORT_COUNT; i++) {
|
||||
|
||||
/* Use default timeout */
|
||||
i2c_set_timeout(i, 0);
|
||||
}
|
||||
}
|
||||
DECLARE_HOOK(HOOK_INIT, i2c_init, HOOK_PRIO_INIT_I2C);
|
||||
@@ -24,7 +24,7 @@ void intc_cpu_int_group_5(void)
|
||||
lpc_kbc_ibf_interrupt();
|
||||
break;
|
||||
#endif
|
||||
#if defined(HAS_TASK_KEYSCAN) && !defined(CONFIG_KEYBOARD_KSI_WUC_INT)
|
||||
#if defined(HAS_TASK_KEYSCAN) && !defined(CONFIG_IT83XX_KEYBOARD_KSI_WUC_INT)
|
||||
case IT83XX_IRQ_KB_MATRIX:
|
||||
keyboard_raw_interrupt();
|
||||
break;
|
||||
|
||||
@@ -35,7 +35,7 @@ void keyboard_raw_init(void)
|
||||
/* KSO[15:8] pins low. */
|
||||
IT83XX_KBS_KSOH1 = 0x00;
|
||||
|
||||
#ifdef CONFIG_KEYBOARD_KSI_WUC_INT
|
||||
#ifdef CONFIG_IT83XX_KEYBOARD_KSI_WUC_INT
|
||||
/* KSI[0-7] falling-edge triggered is selected */
|
||||
IT83XX_WUC_WUEMR3 = 0xFF;
|
||||
|
||||
@@ -58,7 +58,7 @@ void keyboard_raw_init(void)
|
||||
*/
|
||||
void keyboard_raw_task_start(void)
|
||||
{
|
||||
#ifdef CONFIG_KEYBOARD_KSI_WUC_INT
|
||||
#ifdef CONFIG_IT83XX_KEYBOARD_KSI_WUC_INT
|
||||
IT83XX_WUC_WUESR3 = 0xFF;
|
||||
task_clear_pending_irq(IT83XX_IRQ_WKINTC);
|
||||
task_enable_irq(IT83XX_IRQ_WKINTC);
|
||||
@@ -105,7 +105,7 @@ test_mockable int keyboard_raw_read_rows(void)
|
||||
void keyboard_raw_enable_interrupt(int enable)
|
||||
{
|
||||
if (enable) {
|
||||
#ifdef CONFIG_KEYBOARD_KSI_WUC_INT
|
||||
#ifdef CONFIG_IT83XX_KEYBOARD_KSI_WUC_INT
|
||||
IT83XX_WUC_WUESR3 = 0xFF;
|
||||
task_clear_pending_irq(IT83XX_IRQ_WKINTC);
|
||||
task_enable_irq(IT83XX_IRQ_WKINTC);
|
||||
@@ -114,7 +114,7 @@ void keyboard_raw_enable_interrupt(int enable)
|
||||
task_enable_irq(IT83XX_IRQ_KB_MATRIX);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef CONFIG_KEYBOARD_KSI_WUC_INT
|
||||
#ifdef CONFIG_IT83XX_KEYBOARD_KSI_WUC_INT
|
||||
task_disable_irq(IT83XX_IRQ_WKINTC);
|
||||
#else
|
||||
task_disable_irq(IT83XX_IRQ_KB_MATRIX);
|
||||
@@ -127,7 +127,7 @@ void keyboard_raw_enable_interrupt(int enable)
|
||||
*/
|
||||
void keyboard_raw_interrupt(void)
|
||||
{
|
||||
#ifdef CONFIG_KEYBOARD_KSI_WUC_INT
|
||||
#ifdef CONFIG_IT83XX_KEYBOARD_KSI_WUC_INT
|
||||
task_disable_irq(IT83XX_IRQ_WKINTC);
|
||||
#else
|
||||
task_disable_irq(IT83XX_IRQ_KB_MATRIX);
|
||||
|
||||
@@ -182,7 +182,7 @@ static enum peci_status peci_transaction(uint8_t addr,
|
||||
IT83XX_PECI_HOWRDR = w_buf[index];
|
||||
|
||||
peci_current_task = task_get_current();
|
||||
#ifdef CONFIG_PECI_WITH_INTERRUPT
|
||||
#ifdef CONFIG_IT83XX_PECI_WITH_INTERRUPT
|
||||
task_clear_pending_irq(IT83XX_IRQ_PECI);
|
||||
task_enable_irq(IT83XX_IRQ_PECI);
|
||||
|
||||
|
||||
@@ -461,6 +461,10 @@
|
||||
|
||||
#define IT83XX_GPIO_GCR REG8(IT83XX_GPIO_BASE+0x00)
|
||||
|
||||
#define IT83XX_GPIO_GPDRB REG8(IT83XX_GPIO_BASE+0x02)
|
||||
#define IT83XX_GPIO_GPDRC REG8(IT83XX_GPIO_BASE+0x03)
|
||||
#define IT83XX_GPIO_GPDRF REG8(IT83XX_GPIO_BASE+0x06)
|
||||
|
||||
#define IT83XX_GPIO_GPCRA0 REG8(IT83XX_GPIO_BASE+0x10)
|
||||
#define IT83XX_GPIO_GPCRA1 REG8(IT83XX_GPIO_BASE+0x11)
|
||||
#define IT83XX_GPIO_GPCRA2 REG8(IT83XX_GPIO_BASE+0x12)
|
||||
@@ -470,6 +474,33 @@
|
||||
#define IT83XX_GPIO_GPCRA6 REG8(IT83XX_GPIO_BASE+0x16)
|
||||
#define IT83XX_GPIO_GPCRA7 REG8(IT83XX_GPIO_BASE+0x17)
|
||||
|
||||
#define IT83XX_GPIO_GPCRB0 REG8(IT83XX_GPIO_BASE+0x18)
|
||||
#define IT83XX_GPIO_GPCRB1 REG8(IT83XX_GPIO_BASE+0x19)
|
||||
#define IT83XX_GPIO_GPCRB2 REG8(IT83XX_GPIO_BASE+0x1A)
|
||||
#define IT83XX_GPIO_GPCRB3 REG8(IT83XX_GPIO_BASE+0x1B)
|
||||
#define IT83XX_GPIO_GPCRB4 REG8(IT83XX_GPIO_BASE+0x1C)
|
||||
#define IT83XX_GPIO_GPCRB5 REG8(IT83XX_GPIO_BASE+0x1D)
|
||||
#define IT83XX_GPIO_GPCRB6 REG8(IT83XX_GPIO_BASE+0x1E)
|
||||
#define IT83XX_GPIO_GPCRB7 REG8(IT83XX_GPIO_BASE+0x1F)
|
||||
|
||||
#define IT83XX_GPIO_GPCRC0 REG8(IT83XX_GPIO_BASE+0x20)
|
||||
#define IT83XX_GPIO_GPCRC1 REG8(IT83XX_GPIO_BASE+0x21)
|
||||
#define IT83XX_GPIO_GPCRC2 REG8(IT83XX_GPIO_BASE+0x22)
|
||||
#define IT83XX_GPIO_GPCRC3 REG8(IT83XX_GPIO_BASE+0x23)
|
||||
#define IT83XX_GPIO_GPCRC4 REG8(IT83XX_GPIO_BASE+0x24)
|
||||
#define IT83XX_GPIO_GPCRC5 REG8(IT83XX_GPIO_BASE+0x25)
|
||||
#define IT83XX_GPIO_GPCRC6 REG8(IT83XX_GPIO_BASE+0x26)
|
||||
#define IT83XX_GPIO_GPCRC7 REG8(IT83XX_GPIO_BASE+0x27)
|
||||
|
||||
#define IT83XX_GPIO_GPCRF0 REG8(IT83XX_GPIO_BASE+0x38)
|
||||
#define IT83XX_GPIO_GPCRF1 REG8(IT83XX_GPIO_BASE+0x39)
|
||||
#define IT83XX_GPIO_GPCRF2 REG8(IT83XX_GPIO_BASE+0x3A)
|
||||
#define IT83XX_GPIO_GPCRF3 REG8(IT83XX_GPIO_BASE+0x3B)
|
||||
#define IT83XX_GPIO_GPCRF4 REG8(IT83XX_GPIO_BASE+0x3C)
|
||||
#define IT83XX_GPIO_GPCRF5 REG8(IT83XX_GPIO_BASE+0x3D)
|
||||
#define IT83XX_GPIO_GPCRF6 REG8(IT83XX_GPIO_BASE+0x3E)
|
||||
#define IT83XX_GPIO_GPCRF7 REG8(IT83XX_GPIO_BASE+0x3F)
|
||||
|
||||
#define IT83XX_GPIO_GPCRF0 REG8(IT83XX_GPIO_BASE+0x38)
|
||||
#define IT83XX_GPIO_GPCRF1 REG8(IT83XX_GPIO_BASE+0x39)
|
||||
#define IT83XX_GPIO_GPCRF2 REG8(IT83XX_GPIO_BASE+0x3A)
|
||||
@@ -488,6 +519,10 @@
|
||||
#define IT83XX_GPIO_GPCRI6 REG8(IT83XX_GPIO_BASE+0x56)
|
||||
#define IT83XX_GPIO_GPCRI7 REG8(IT83XX_GPIO_BASE+0x57)
|
||||
|
||||
#define IT83XX_GPIO_GPDMRB REG8(IT83XX_GPIO_BASE+0x62)
|
||||
#define IT83XX_GPIO_GPDMRC REG8(IT83XX_GPIO_BASE+0x63)
|
||||
#define IT83XX_GPIO_GPDMRF REG8(IT83XX_GPIO_BASE+0x66)
|
||||
|
||||
#define IT83XX_GPIO_GRC1 REG8(IT83XX_GPIO_BASE+0xF0)
|
||||
#define IT83XX_GPIO_GRC2 REG8(IT83XX_GPIO_BASE+0xF1)
|
||||
#define IT83XX_GPIO_GRC3 REG8(IT83XX_GPIO_BASE+0xF2)
|
||||
@@ -856,12 +891,34 @@ REG8(IT83XX_PMC_BASE + (ch > LPC_PM2 ? 3 : 6) + (ch << 4))
|
||||
#define IT83XX_PECI_AWFCSV REG8(IT83XX_PECI_BASE+0x0D)
|
||||
#define IT83XX_PECI_PADCTLR REG8(IT83XX_PECI_BASE+0x0E)
|
||||
|
||||
/* SMBus/I2C Interface (SMB/I2C) */
|
||||
#define IT83XX_SMB_BASE 0x00F01C00
|
||||
|
||||
#define IT83XX_SMB_4P7USL REG8(IT83XX_SMB_BASE+0x00)
|
||||
#define IT83XX_SMB_4P0USL REG8(IT83XX_SMB_BASE+0x01)
|
||||
#define IT83XX_SMB_300NS REG8(IT83XX_SMB_BASE+0x02)
|
||||
#define IT83XX_SMB_250NS REG8(IT83XX_SMB_BASE+0x03)
|
||||
#define IT83XX_SMB_25MS REG8(IT83XX_SMB_BASE+0x04)
|
||||
#define IT83XX_SMB_45P3USL REG8(IT83XX_SMB_BASE+0x05)
|
||||
#define IT83XX_SMB_45P3USH REG8(IT83XX_SMB_BASE+0x06)
|
||||
#define IT83XX_SMB_4P7A4P0H REG8(IT83XX_SMB_BASE+0x07)
|
||||
#define IT83XX_SMB_SCLKTS(ch) REG8(IT83XX_SMB_BASE+0x09+ch)
|
||||
#define IT83XX_SMB_HOSTA(ch) REG8(IT83XX_SMB_BASE+0x40+(ch << 6))
|
||||
#define IT83XX_SMB_HOCTL(ch) REG8(IT83XX_SMB_BASE+0x41+(ch << 6))
|
||||
#define IT83XX_SMB_HOCMD(ch) REG8(IT83XX_SMB_BASE+0x42+(ch << 6))
|
||||
#define IT83XX_SMB_TRASLA(ch) REG8(IT83XX_SMB_BASE+0x43+(ch << 6))
|
||||
#define IT83XX_SMB_D0REG(ch) REG8(IT83XX_SMB_BASE+0x44+(ch << 6))
|
||||
#define IT83XX_SMB_D1REG(ch) REG8(IT83XX_SMB_BASE+0x45+(ch << 6))
|
||||
#define IT83XX_SMB_HOBDB(ch) REG8(IT83XX_SMB_BASE+0x46+(ch << 6))
|
||||
#define IT83XX_SMB_PECERC(ch) REG8(IT83XX_SMB_BASE+0x47+(ch << 6))
|
||||
#define IT83XX_SMB_SMBPCTL(ch) REG8(IT83XX_SMB_BASE+0x4A+(ch << 6))
|
||||
#define IT83XX_SMB_HOCTL2(ch) REG8(IT83XX_SMB_BASE+0x50+(ch << 6))
|
||||
|
||||
/* --- MISC (not implemented yet) --- */
|
||||
|
||||
#define IT83XX_PS2_BASE 0x00F01700
|
||||
#define IT83XX_DAC_BASE 0x00F01A00
|
||||
#define IT83XX_WUC_BASE 0x00F01B00
|
||||
#define IT83XX_SMB_BASE 0x00F01C00
|
||||
#define IT83XX_EGPIO_BASE 0x00F02100
|
||||
#define IT83XX_BRAM_BASE 0x00F02200
|
||||
#define IT83XX_CIR_BASE 0x00F02300
|
||||
|
||||
@@ -82,7 +82,7 @@ int spi_enable(int enable)
|
||||
* 01b: SSCK/SMOSI/SMISO/SSCE0# are enabled.
|
||||
* 11b: SSCK/SMOSI/SMISO/SSCE1#/SSCE0# are enabled.
|
||||
*/
|
||||
#ifdef CONFIG_SPI_USE_CS1
|
||||
#ifdef CONFIG_IT83XX_SPI_USE_CS1
|
||||
IT83XX_GPIO_GRC1 |= 0x20;
|
||||
#else
|
||||
IT83XX_GPIO_GRC1 |= 0x10;
|
||||
@@ -105,7 +105,7 @@ int spi_transaction(const uint8_t *txdata, int txlen,
|
||||
IT83XX_SSPI_SPICTRL2 &= ~0x04;
|
||||
for (idx = 0x00; idx < txlen; idx++) {
|
||||
IT83XX_SSPI_SPIDATA = txdata[idx];
|
||||
#ifdef CONFIG_SPI_USE_CS1
|
||||
#ifdef CONFIG_IT83XX_SPI_USE_CS1
|
||||
/* Write 1 to start the data transmission of CS1 */
|
||||
IT83XX_SSPI_SPISTS |= 0x08;
|
||||
#else
|
||||
@@ -117,7 +117,7 @@ int spi_transaction(const uint8_t *txdata, int txlen,
|
||||
/* bit[1]: Read cycle */
|
||||
IT83XX_SSPI_SPICTRL2 |= 0x04;
|
||||
for (idx = 0x00; idx < rxlen; idx++) {
|
||||
#ifdef CONFIG_SPI_USE_CS1
|
||||
#ifdef CONFIG_IT83XX_SPI_USE_CS1
|
||||
/* Write 1 to start the data transmission of CS1 */
|
||||
IT83XX_SSPI_SPISTS |= 0x08;
|
||||
#else
|
||||
|
||||
@@ -935,6 +935,18 @@
|
||||
/* Number of IRQs supported on the EC chip */
|
||||
#undef CONFIG_IRQ_COUNT
|
||||
|
||||
/* Enable Wake-up control interrupt from KSI */
|
||||
#undef CONFIG_IT83XX_KEYBOARD_KSI_WUC_INT
|
||||
|
||||
/* Interrupt for PECI module. (IT839X series and IT838X DX only) */
|
||||
#undef CONFIG_IT83XX_PECI_WITH_INTERRUPT
|
||||
|
||||
/* To define it, if I2C channel C and PECI used at the same time. */
|
||||
#undef CONFIG_IT83XX_SMCLK2_ON_GPC7
|
||||
|
||||
/* Use SSPI Chip Enable 1. */
|
||||
#undef CONFIG_IT83XX_SPI_USE_CS1
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Keyboard config */
|
||||
|
||||
@@ -955,9 +967,6 @@
|
||||
/* Enable extra debugging output from keyboard modules */
|
||||
#undef CONFIG_KEYBOARD_DEBUG
|
||||
|
||||
/* Enable Wake-up control interrupt from KSI */
|
||||
#undef CONFIG_KEYBOARD_KSI_WUC_INT
|
||||
|
||||
/* The board uses a negative edge-triggered GPIO for keyboard interrupts. */
|
||||
#undef CONFIG_KEYBOARD_IRQ_GPIO
|
||||
|
||||
@@ -1287,9 +1296,6 @@
|
||||
/* SPI module port. */
|
||||
#undef CONFIG_SPI_PORT
|
||||
|
||||
/* Use SSPI Chip Enable 1. */
|
||||
#undef CONFIG_SPI_USE_CS1
|
||||
|
||||
/* Support testing SPI slave controller driver. */
|
||||
#undef CONFIG_SPS_TEST
|
||||
|
||||
|
||||
Reference in New Issue
Block a user