zephyr/drivers/i2c/i2c_ite_it8xxx2.c
Tim Lin 19724ba002 ITE: drivers/i2c: Enable I2C interrupt after completing configuration
Fix the flow of I2C enable interrupt. We should enable the interrupt
after I2C configuration is completed to avoid pending interrupts and
cause errors irq.

Test port:
i2c_ite_it8xxx2: i2c0
i2c_ite_enhance: i2c4
Test:
tests\drivers\i2c\i2c_api --> pass

Signed-off-by: Tim Lin <tim2.lin@ite.corp-partner.google.com>
2022-06-20 10:24:27 +02:00

789 lines
21 KiB
C

/*
* Copyright (c) 2020 ITE Corporation. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT ite_it8xxx2_i2c
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/pinctrl.h>
#include <errno.h>
#include <soc.h>
#include <soc_dt.h>
#include <zephyr/sys/util.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(i2c_ite_it8xxx2, CONFIG_I2C_LOG_LEVEL);
#include "i2c-priv.h"
/* Start smbus session from idle state */
#define I2C_MSG_START BIT(5)
#define I2C_LINE_SCL_HIGH BIT(0)
#define I2C_LINE_SDA_HIGH BIT(1)
#define I2C_LINE_IDLE (I2C_LINE_SCL_HIGH | I2C_LINE_SDA_HIGH)
struct i2c_it8xxx2_config {
void (*irq_config_func)(void);
uint32_t bitrate;
uint8_t *base;
uint8_t i2c_irq_base;
uint8_t port;
/* SCL GPIO cells */
struct gpio_dt_spec scl_gpios;
/* SDA GPIO cells */
struct gpio_dt_spec sda_gpios;
/* I2C alternate configuration */
const struct pinctrl_dev_config *pcfg;
uint32_t clock_gate_offset;
};
enum i2c_pin_fun {
SCL = 0,
SDA,
};
enum i2c_ch_status {
I2C_CH_NORMAL = 0,
I2C_CH_REPEAT_START,
I2C_CH_WAIT_READ,
I2C_CH_WAIT_NEXT_XFER,
};
struct i2c_it8xxx2_data {
enum i2c_ch_status i2ccs;
struct i2c_msg *msgs;
struct k_mutex mutex;
struct k_sem device_sync_sem;
/* Index into output data */
size_t widx;
/* Index into input data */
size_t ridx;
/* operation freq of i2c */
uint32_t bus_freq;
/* Error code, if any */
uint32_t err;
/* address of device */
uint16_t addr_16bit;
/* Frequency setting */
uint8_t freq;
/* wait for stop bit interrupt */
uint8_t stop;
};
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 i2c_reset_cause {
I2C_RC_NO_IDLE_FOR_START = 1,
I2C_RC_TIMEOUT,
};
static int i2c_parsing_return_value(const struct device *dev)
{
struct i2c_it8xxx2_data *data = dev->data;
if (!data->err) {
return 0;
}
/* Connection timed out */
if (data->err == ETIMEDOUT) {
return -ETIMEDOUT;
}
/* The device does not respond ACK */
if (data->err == HOSTA_NACK) {
return -ENXIO;
} else {
return -EIO;
}
}
static int i2c_get_line_levels(const struct device *dev)
{
const struct i2c_it8xxx2_config *config = dev->config;
uint8_t *base = config->base;
return (IT8XXX2_SMB_SMBPCTL(base) &
(IT8XXX2_SMB_SMBDCS | IT8XXX2_SMB_SMBCS));
}
static int i2c_is_busy(const struct device *dev)
{
const struct i2c_it8xxx2_config *config = dev->config;
uint8_t *base = config->base;
return (IT8XXX2_SMB_HOSTA(base) &
(HOSTA_HOBY | HOSTA_ALL_WC_BIT));
}
static int i2c_bus_not_available(const struct device *dev)
{
if (i2c_is_busy(dev) ||
(i2c_get_line_levels(dev) != I2C_LINE_IDLE)) {
return -EIO;
}
return 0;
}
static void i2c_reset(const struct device *dev)
{
const struct i2c_it8xxx2_config *config = dev->config;
uint8_t *base = config->base;
/* bit1, kill current transaction. */
IT8XXX2_SMB_HOCTL(base) = IT8XXX2_SMB_KILL;
IT8XXX2_SMB_HOCTL(base) = 0;
/* W/C host status register */
IT8XXX2_SMB_HOSTA(base) = HOSTA_ALL_WC_BIT;
}
/*
* 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(uint8_t port)
{
/* Port clock frequency depends on setting of timing registers. */
IT8XXX2_SMB_SCLKTS(port) = 0;
/* Suggested setting of timing registers of 400kHz. */
IT8XXX2_SMB_4P7USL = 0x3;
IT8XXX2_SMB_4P0USL = 0;
IT8XXX2_SMB_300NS = 0x1;
IT8XXX2_SMB_250NS = 0x5;
IT8XXX2_SMB_45P3USL = 0x6a;
IT8XXX2_SMB_45P3USH = 0x1;
IT8XXX2_SMB_4P7A4P0H = 0;
}
/* Set clock frequency for i2c port A, B , or C */
static void i2c_standard_port_set_frequency(const struct device *dev,
int freq_hz, int freq_set)
{
const struct i2c_it8xxx2_config *config = dev->config;
/*
* 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_hz == I2C_BITRATE_FAST) {
i2c_standard_port_timing_regs_400khz(config->port);
} else {
IT8XXX2_SMB_SCLKTS(config->port) = freq_set;
}
/* This field defines the SMCLK0/1/2 clock/data low timeout. */
IT8XXX2_SMB_25MS = I2C_CLK_LOW_TIMEOUT;
}
static int i2c_it8xxx2_configure(const struct device *dev,
uint32_t dev_config_raw)
{
const struct i2c_it8xxx2_config *config = dev->config;
struct i2c_it8xxx2_data *const data = dev->data;
uint32_t freq_set;
if (!(I2C_MODE_MASTER & dev_config_raw)) {
return -EINVAL;
}
if (I2C_ADDR_10_BITS & dev_config_raw) {
return -EINVAL;
}
data->bus_freq = I2C_SPEED_GET(dev_config_raw);
switch (data->bus_freq) {
case I2C_SPEED_DT:
freq_set = IT8XXX2_SMB_SMCLKS_50K;
break;
case I2C_SPEED_STANDARD:
freq_set = IT8XXX2_SMB_SMCLKS_100K;
break;
case I2C_SPEED_FAST:
freq_set = IT8XXX2_SMB_SMCLKS_400K;
break;
case I2C_SPEED_FAST_PLUS:
freq_set = IT8XXX2_SMB_SMCLKS_1M;
break;
default:
return -EINVAL;
}
i2c_standard_port_set_frequency(dev, config->bitrate, freq_set);
return 0;
}
static int i2c_it8xxx2_get_config(const struct device *dev,
uint32_t *dev_config)
{
struct i2c_it8xxx2_data *const data = dev->data;
uint32_t speed;
if (!data->bus_freq) {
LOG_ERR("The bus frequency is not initially configured.");
return -EIO;
}
switch (data->bus_freq) {
case I2C_SPEED_DT:
case I2C_SPEED_STANDARD:
case I2C_SPEED_FAST:
case I2C_SPEED_FAST_PLUS:
speed = I2C_SPEED_SET(data->bus_freq);
break;
default:
return -ERANGE;
}
*dev_config = (I2C_MODE_MASTER | speed);
return 0;
}
static void i2c_r_last_byte(const struct device *dev)
{
struct i2c_it8xxx2_data *data = dev->data;
const struct i2c_it8xxx2_config *config = dev->config;
uint8_t *base = config->base;
/*
* bit5, The firmware shall write 1 to this bit
* when the next byte will be the last byte for i2c read.
*/
if ((data->msgs->flags & I2C_MSG_STOP) &&
(data->ridx == data->msgs->len - 1)) {
IT8XXX2_SMB_HOCTL(base) |= IT8XXX2_SMB_LABY;
}
}
static void i2c_w2r_change_direction(const struct device *dev)
{
const struct i2c_it8xxx2_config *config = dev->config;
uint8_t *base = config->base;
/* I2C switch direction */
if (IT8XXX2_SMB_HOCTL2(base) & IT8XXX2_SMB_I2C_SW_EN) {
i2c_r_last_byte(dev);
IT8XXX2_SMB_HOSTA(base) = HOSTA_NEXT_BYTE;
} else {
/*
* bit2, I2C switch direction wait.
* bit3, I2C switch direction enable.
*/
IT8XXX2_SMB_HOCTL2(base) |= IT8XXX2_SMB_I2C_SW_EN |
IT8XXX2_SMB_I2C_SW_WAIT;
IT8XXX2_SMB_HOSTA(base) = HOSTA_NEXT_BYTE;
i2c_r_last_byte(dev);
IT8XXX2_SMB_HOCTL2(base) &= ~IT8XXX2_SMB_I2C_SW_WAIT;
}
}
static int i2c_tran_read(const struct device *dev)
{
struct i2c_it8xxx2_data *data = dev->data;
const struct i2c_it8xxx2_config *config = dev->config;
uint8_t *base = config->base;
if (data->msgs->flags & I2C_MSG_START) {
/* i2c enable */
IT8XXX2_SMB_HOCTL2(base) = IT8XXX2_SMB_SMD_TO_EN |
IT8XXX2_SMB_I2C_EN |
IT8XXX2_SMB_SMHEN;
/*
* bit0, Direction of the host transfer.
* bit[1:7}, Address of the targeted slave.
*/
IT8XXX2_SMB_TRASLA(base) = (uint8_t)(data->addr_16bit << 1) |
IT8XXX2_SMB_DIR;
/* clear start flag */
data->msgs->flags &= ~I2C_MSG_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 ((data->msgs->len == 1) &&
(data->msgs->flags & I2C_MSG_STOP)) {
IT8XXX2_SMB_HOCTL(base) = IT8XXX2_SMB_SRT |
IT8XXX2_SMB_LABY |
IT8XXX2_SMB_SMCD_EXTND |
IT8XXX2_SMB_INTREN;
} else {
IT8XXX2_SMB_HOCTL(base) = IT8XXX2_SMB_SRT |
IT8XXX2_SMB_SMCD_EXTND |
IT8XXX2_SMB_INTREN;
}
} else {
if ((data->i2ccs == I2C_CH_REPEAT_START) ||
(data->i2ccs == I2C_CH_WAIT_READ)) {
if (data->i2ccs == I2C_CH_REPEAT_START) {
/* write to read */
i2c_w2r_change_direction(dev);
} else {
/* For last byte */
i2c_r_last_byte(dev);
/* W/C for next byte */
IT8XXX2_SMB_HOSTA(base) = HOSTA_NEXT_BYTE;
}
data->i2ccs = I2C_CH_NORMAL;
} else if (IT8XXX2_SMB_HOSTA(base) & HOSTA_BDS) {
if (data->ridx < data->msgs->len) {
/* To get received data. */
*(data->msgs->buf++) = IT8XXX2_SMB_HOBDB(base);
data->ridx++;
/* For last byte */
i2c_r_last_byte(dev);
/* done */
if (data->ridx == data->msgs->len) {
data->msgs->len = 0;
if (data->msgs->flags & I2C_MSG_STOP) {
/* W/C for finish */
IT8XXX2_SMB_HOSTA(base) =
HOSTA_NEXT_BYTE;
data->stop = 1;
} else {
data->i2ccs = I2C_CH_WAIT_READ;
return 0;
}
} else {
/* W/C for next byte */
IT8XXX2_SMB_HOSTA(base) =
HOSTA_NEXT_BYTE;
}
}
}
}
return 1;
}
static int i2c_tran_write(const struct device *dev)
{
struct i2c_it8xxx2_data *data = dev->data;
const struct i2c_it8xxx2_config *config = dev->config;
uint8_t *base = config->base;
if (data->msgs->flags & I2C_MSG_START) {
/* i2c enable */
IT8XXX2_SMB_HOCTL2(base) = IT8XXX2_SMB_SMD_TO_EN |
IT8XXX2_SMB_I2C_EN |
IT8XXX2_SMB_SMHEN;
/*
* bit0, Direction of the host transfer.
* bit[1:7}, Address of the targeted slave.
*/
IT8XXX2_SMB_TRASLA(base) = (uint8_t)data->addr_16bit << 1;
/* Send first byte */
IT8XXX2_SMB_HOBDB(base) = *(data->msgs->buf++);
data->widx++;
/* clear start flag */
data->msgs->flags &= ~I2C_MSG_START;
/*
* bit0, Host interrupt enable.
* bit[2:4}, Extend command.
* bit6, start.
*/
IT8XXX2_SMB_HOCTL(base) = IT8XXX2_SMB_SRT |
IT8XXX2_SMB_SMCD_EXTND |
IT8XXX2_SMB_INTREN;
} else {
/* Host has completed the transmission of a byte */
if (IT8XXX2_SMB_HOSTA(base) & HOSTA_BDS) {
if (data->widx < data->msgs->len) {
/* Send next byte */
IT8XXX2_SMB_HOBDB(base) = *(data->msgs->buf++);
data->widx++;
/* W/C byte done for next byte */
IT8XXX2_SMB_HOSTA(base) = HOSTA_NEXT_BYTE;
if (data->i2ccs == I2C_CH_REPEAT_START) {
data->i2ccs = I2C_CH_NORMAL;
}
} else {
/* done */
data->msgs->len = 0;
if (data->msgs->flags & I2C_MSG_STOP) {
/* set I2C_EN = 0 */
IT8XXX2_SMB_HOCTL2(base) = IT8XXX2_SMB_SMD_TO_EN |
IT8XXX2_SMB_SMHEN;
/* W/C byte done for finish */
IT8XXX2_SMB_HOSTA(base) = HOSTA_NEXT_BYTE;
data->stop = 1;
} else {
data->i2ccs = I2C_CH_REPEAT_START;
return 0;
}
}
}
}
return 1;
}
static int i2c_transaction(const struct device *dev)
{
struct i2c_it8xxx2_data *data = dev->data;
const struct i2c_it8xxx2_config *config = dev->config;
uint8_t *base = config->base;
/* any error */
if (IT8XXX2_SMB_HOSTA(base) & HOSTA_ANY_ERROR) {
data->err = (IT8XXX2_SMB_HOSTA(base) & HOSTA_ANY_ERROR);
} else {
if (!data->stop) {
/*
* The return value indicates if there is more data
* to be read or written. If the return value = 1,
* it means that the interrupt cannot be disable and
* continue to transmit data.
*/
if (data->msgs->flags & I2C_MSG_READ) {
return i2c_tran_read(dev);
} else {
return i2c_tran_write(dev);
}
}
/* wait finish */
if (!(IT8XXX2_SMB_HOSTA(base) & HOSTA_FINTR)) {
return 1;
}
}
/* W/C */
IT8XXX2_SMB_HOSTA(base) = HOSTA_ALL_WC_BIT;
/* disable the SMBus host interface */
IT8XXX2_SMB_HOCTL2(base) = 0x00;
data->stop = 0;
/* done doing work */
return 0;
}
static int i2c_it8xxx2_transfer(const struct device *dev, struct i2c_msg *msgs,
uint8_t num_msgs, uint16_t addr)
{
struct i2c_it8xxx2_data *data = dev->data;
const struct i2c_it8xxx2_config *config = dev->config;
int res;
/* Lock mutex of i2c controller */
k_mutex_lock(&data->mutex, K_FOREVER);
/*
* If the transaction of write to read is divided into two
* transfers, the repeat start transfer uses this flag to
* exclude checking bus busy.
*/
if (data->i2ccs == I2C_CH_NORMAL) {
/* Make sure we're in a good state to start */
if (i2c_bus_not_available(dev)) {
/* Recovery I2C bus */
i2c_recover_bus(dev);
/*
* After resetting I2C bus, if I2C bus is not available
* (No external pull-up), drop the transaction.
*/
if (i2c_bus_not_available(dev)) {
/* Unlock mutex of i2c controller */
k_mutex_unlock(&data->mutex);
return -EIO;
}
}
msgs->flags |= I2C_MSG_START;
}
for (int i = 0; i < num_msgs; i++) {
data->widx = 0;
data->ridx = 0;
data->err = 0;
data->msgs = &(msgs[i]);
data->addr_16bit = addr;
if (msgs->flags & I2C_MSG_START) {
data->i2ccs = I2C_CH_NORMAL;
}
/*
* Start transaction.
* The return value indicates if the initial configuration
* of I2C transaction for read or write has been completed.
*/
if (i2c_transaction(dev)) {
/* Enable I2C interrupt. */
irq_enable(config->i2c_irq_base);
}
/* Wait for the transfer to complete */
/* TODO: the timeout should be adjustable */
res = k_sem_take(&data->device_sync_sem, K_MSEC(100));
/*
* The irq will be enabled at the condition of start or
* repeat start of I2C. If timeout occurs without being
* wake up during suspend(ex: interrupt is not fired),
* the irq should be disabled immediately.
*/
irq_disable(config->i2c_irq_base);
/*
* The transaction is dropped on any error(timeout, NACK, fail,
* bus error, device error).
*/
if (data->err) {
break;
}
if (res != 0) {
data->err = ETIMEDOUT;
/* reset i2c port */
i2c_reset(dev);
LOG_ERR("I2C ch%d:0x%X reset cause %d",
config->port, data->addr_16bit, I2C_RC_TIMEOUT);
/* If this message is sent fail, drop the transaction. */
break;
}
}
/* reset i2c channel status */
if (data->err || (msgs->flags & I2C_MSG_STOP)) {
data->i2ccs = I2C_CH_NORMAL;
}
/* Unlock mutex of i2c controller */
k_mutex_unlock(&data->mutex);
return i2c_parsing_return_value(dev);
}
static void i2c_it8xxx2_isr(const struct device *dev)
{
struct i2c_it8xxx2_data *data = dev->data;
const struct i2c_it8xxx2_config *config = dev->config;
/* If done doing work, wake up the task waiting for the transfer */
if (!i2c_transaction(dev)) {
irq_disable(config->i2c_irq_base);
k_sem_give(&data->device_sync_sem);
}
}
static int i2c_it8xxx2_init(const struct device *dev)
{
struct i2c_it8xxx2_data *data = dev->data;
const struct i2c_it8xxx2_config *config = dev->config;
uint8_t *base = config->base;
uint32_t bitrate_cfg;
int error, status;
/*
* This register is a pre-define hardware slave A and can
* be accessed through I2C0. It is not currently used, so
* it can be disabled to avoid illegal access.
*/
IT8XXX2_SMB_SFFCTL &= ~IT8XXX2_SMB_HSAPE;
/* Initialize mutex and semaphore */
k_mutex_init(&data->mutex);
k_sem_init(&data->device_sync_sem, 0, K_SEM_MAX_LIMIT);
/* Enable clock to specified peripheral */
volatile uint8_t *reg = (volatile uint8_t *)
(IT8XXX2_ECPM_BASE + (config->clock_gate_offset >> 8));
uint8_t reg_mask = config->clock_gate_offset & 0xff;
*reg &= ~reg_mask;
/* Enable SMBus function */
/*
* 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.
*/
IT8XXX2_SMB_HOCTL2(base) = IT8XXX2_SMB_SMD_TO_EN | IT8XXX2_SMB_SMHEN;
/*
* bit1, Kill SMBus host transaction.
* bit0, Enable the interrupt for the master interface.
*/
IT8XXX2_SMB_HOCTL(base) = IT8XXX2_SMB_KILL | IT8XXX2_SMB_SMHEN;
IT8XXX2_SMB_HOCTL(base) = IT8XXX2_SMB_SMHEN;
/* W/C host status register */
IT8XXX2_SMB_HOSTA(base) = HOSTA_ALL_WC_BIT;
IT8XXX2_SMB_HOCTL2(base) = 0x00;
/* Set clock frequency for I2C ports */
if (config->bitrate == I2C_BITRATE_STANDARD ||
config->bitrate == I2C_BITRATE_FAST ||
config->bitrate == I2C_BITRATE_FAST_PLUS) {
bitrate_cfg = i2c_map_dt_bitrate(config->bitrate);
} else {
/* Device tree specified speed */
bitrate_cfg = I2C_SPEED_DT << I2C_SPEED_SHIFT;
}
error = i2c_it8xxx2_configure(dev, I2C_MODE_MASTER | bitrate_cfg);
data->i2ccs = I2C_CH_NORMAL;
if (error) {
LOG_ERR("i2c: failure initializing");
return error;
}
/* Set the pin to I2C alternate function. */
status = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
if (status < 0) {
LOG_ERR("Failed to configure I2C pins");
return status;
}
return 0;
}
static int i2c_it8xxx2_recover_bus(const struct device *dev)
{
const struct i2c_it8xxx2_config *config = dev->config;
int i, status;
/* Set SCL of I2C as GPIO pin */
gpio_pin_configure_dt(&config->scl_gpios, GPIO_OUTPUT);
/* Set SDA of I2C as GPIO pin */
gpio_pin_configure_dt(&config->sda_gpios, GPIO_OUTPUT);
/*
* In I2C recovery bus, 1ms sleep interval for bitbanging i2c
* is mainly to ensure that gpio has enough time to go from
* low to high or high to low.
*/
/* Pull SCL and SDA pin to high */
gpio_pin_set_dt(&config->scl_gpios, 1);
gpio_pin_set_dt(&config->sda_gpios, 1);
k_msleep(1);
/* Start condition */
gpio_pin_set_dt(&config->sda_gpios, 0);
k_msleep(1);
gpio_pin_set_dt(&config->scl_gpios, 0);
k_msleep(1);
/* 9 cycles of SCL with SDA held high */
for (i = 0; i < 9; i++) {
/* SDA */
gpio_pin_set_dt(&config->sda_gpios, 1);
/* SCL */
gpio_pin_set_dt(&config->scl_gpios, 1);
k_msleep(1);
/* SCL */
gpio_pin_set_dt(&config->scl_gpios, 0);
k_msleep(1);
}
/* SDA */
gpio_pin_set_dt(&config->sda_gpios, 0);
k_msleep(1);
/* Stop condition */
gpio_pin_set_dt(&config->scl_gpios, 1);
k_msleep(1);
gpio_pin_set_dt(&config->sda_gpios, 1);
k_msleep(1);
/* Set GPIO back to I2C alternate function of SCL */
status = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
if (status < 0) {
LOG_ERR("Failed to configure I2C pins");
return status;
}
/* reset i2c port */
i2c_reset(dev);
LOG_ERR("I2C ch%d reset cause %d", config->port,
I2C_RC_NO_IDLE_FOR_START);
return 0;
}
static const struct i2c_driver_api i2c_it8xxx2_driver_api = {
.configure = i2c_it8xxx2_configure,
.get_config = i2c_it8xxx2_get_config,
.transfer = i2c_it8xxx2_transfer,
.recover_bus = i2c_it8xxx2_recover_bus,
};
#define I2C_ITE_IT8XXX2_INIT(inst) \
PINCTRL_DT_INST_DEFINE(inst); \
BUILD_ASSERT((DT_INST_PROP(inst, clock_frequency) == \
50000) || \
(DT_INST_PROP(inst, clock_frequency) == \
I2C_BITRATE_STANDARD) || \
(DT_INST_PROP(inst, clock_frequency) == \
I2C_BITRATE_FAST) || \
(DT_INST_PROP(inst, clock_frequency) == \
I2C_BITRATE_FAST_PLUS), "Not support I2C bit rate value"); \
static void i2c_it8xxx2_config_func_##inst(void); \
\
static const struct i2c_it8xxx2_config i2c_it8xxx2_cfg_##inst = { \
.base = (uint8_t *)(DT_INST_REG_ADDR(inst)), \
.irq_config_func = i2c_it8xxx2_config_func_##inst, \
.bitrate = DT_INST_PROP(inst, clock_frequency), \
.i2c_irq_base = DT_INST_IRQN(inst), \
.port = DT_INST_PROP(inst, port_num), \
.scl_gpios = GPIO_DT_SPEC_INST_GET(inst, scl_gpios), \
.sda_gpios = GPIO_DT_SPEC_INST_GET(inst, sda_gpios), \
.clock_gate_offset = DT_INST_PROP(inst, clock_gate_offset), \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
}; \
\
static struct i2c_it8xxx2_data i2c_it8xxx2_data_##inst; \
\
I2C_DEVICE_DT_INST_DEFINE(inst, i2c_it8xxx2_init, \
NULL, \
&i2c_it8xxx2_data_##inst, \
&i2c_it8xxx2_cfg_##inst, \
POST_KERNEL, \
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
&i2c_it8xxx2_driver_api); \
\
static void i2c_it8xxx2_config_func_##inst(void) \
{ \
IRQ_CONNECT(DT_INST_IRQN(inst), \
0, \
i2c_it8xxx2_isr, \
DEVICE_DT_INST_GET(inst), 0); \
}
DT_INST_FOREACH_STATUS_OKAY(I2C_ITE_IT8XXX2_INIT)