ITE: driver/i2c: add I2C recovery function

Use GPIO output high and low to simulate I2C start and stop
conditions to restore i2c to normal.

Signed-off-by: Tim Lin <tim2.lin@ite.corp-partner.google.com>
This commit is contained in:
Tim Lin 2021-07-03 09:16:29 +08:00 committed by Christopher Friedt
parent 8fdcc11d6b
commit abe27c5bca
3 changed files with 73 additions and 3 deletions

View file

@ -6,6 +6,7 @@
#define DT_DRV_COMPAT ite_it8xxx2_i2c
#include <drivers/gpio.h>
#include <drivers/i2c.h>
#include <drivers/pinmux.h>
#include <errno.h>
@ -52,6 +53,8 @@ struct i2c_it8xxx2_config {
/* Alternate function */
uint8_t clk_alt_fun;
uint8_t data_alt_fun;
/* GPIO handle */
const struct device *gpio_dev;
};
enum i2c_ch_status {
@ -766,8 +769,8 @@ static int i2c_it8xxx2_transfer(const struct device *dev, struct i2c_msg *msgs,
if (data->i2ccs == I2C_CH_NORMAL) {
/* Make sure we're in a good state to start */
if (i2c_bus_not_available(dev)) {
/* reset i2c port */
i2c_reset(dev);
/* Recovery I2C bus */
i2c_recover_bus(dev);
printk("I2C ch%d reset cause %d\n", config->port,
I2C_RC_NO_IDLE_FOR_START);
/*
@ -936,9 +939,64 @@ static int i2c_it8xxx2_init(const struct device *dev)
return 0;
}
static int i2c_it8xxx2_recover_bus(const struct device *dev)
{
const struct i2c_it8xxx2_config *config = DEV_CFG(dev);
int i;
/* Set clock of I2C as GPIO pin */
pinmux_pin_input_enable(config->clk_pinctrls, config->clk_pin,
PINMUX_OUTPUT_ENABLED);
/* Set data of I2C as GPIO pin */
pinmux_pin_input_enable(config->data_pinctrls, config->data_pin,
PINMUX_OUTPUT_ENABLED);
gpio_pin_set(config->gpio_dev, config->clk_pin, 1);
gpio_pin_set(config->gpio_dev, config->data_pin, 1);
k_msleep(1);
/* Start condition */
gpio_pin_set(config->gpio_dev, config->data_pin, 0);
k_msleep(1);
gpio_pin_set(config->gpio_dev, config->clk_pin, 0);
k_msleep(1);
/* 9 cycles of SCL with SDA held high */
for (i = 0; i < 9; i++) {
gpio_pin_set(config->gpio_dev, config->data_pin, 1);
gpio_pin_set(config->gpio_dev, config->clk_pin, 1);
k_msleep(1);
gpio_pin_set(config->gpio_dev, config->clk_pin, 0);
k_msleep(1);
}
gpio_pin_set(config->gpio_dev, config->data_pin, 0);
k_msleep(1);
/* Stop condition */
gpio_pin_set(config->gpio_dev, config->clk_pin, 1);
k_msleep(1);
gpio_pin_set(config->gpio_dev, config->data_pin, 1);
k_msleep(1);
/* Set GPIO back to I2C alternate function of clock */
pinmux_pin_set(config->clk_pinctrls, config->clk_pin,
config->clk_alt_fun);
/* Set GPIO back to I2C alternate function of data */
pinmux_pin_set(config->data_pinctrls, config->data_pin,
config->data_alt_fun);
/* reset i2c port */
i2c_reset(dev);
printk("I2C ch%d reset cause %d\n", config->port,
I2C_RC_NO_IDLE_FOR_START);
return 0;
}
static const struct i2c_driver_api i2c_it8xxx2_driver_api = {
.configure = i2c_it8xxx2_configure,
.transfer = i2c_it8xxx2_transfer,
.recover_bus = i2c_it8xxx2_recover_bus,
};
#define I2C_ITE_IT8XXX2_INIT(idx) \
@ -955,7 +1013,8 @@ static const struct i2c_driver_api i2c_it8xxx2_driver_api = {
.clk_pin = DEV_CLK_PIN(idx), \
.data_pin = DEV_DATA_PIN(idx), \
.clk_alt_fun = DEV_CLK_ALT_FUNC(idx), \
.data_alt_fun = DEV_DATA_ALT_FUNC(idx) \
.data_alt_fun = DEV_DATA_ALT_FUNC(idx), \
.gpio_dev = DEVICE_DT_GET(DT_INST_PHANDLE(idx, gpio_dev)), \
}; \
\
static struct i2c_it8xxx2_data i2c_it8xxx2_data_##idx; \

View file

@ -22,6 +22,11 @@ properties:
required: true
description: Ordinal identifying the port
gpio-dev:
type: phandle
required: true
description: Get the handle of the GPIO device
pinctrl-0:
type: phandle
required: true

View file

@ -603,6 +603,7 @@
status = "disabled";
label = "I2C_0";
port-num = <0>;
gpio-dev = <&gpiob>;
pinctrl-0 = <&pinctrl_i2c_clk0>; /* GPB3 */
pinctrl-1 = <&pinctrl_i2c_data0>; /* GPB4 */
};
@ -616,6 +617,7 @@
status = "disabled";
label = "I2C_1";
port-num = <1>;
gpio-dev = <&gpioc>;
pinctrl-0 = <&pinctrl_i2c_clk1>; /* GPC1 */
pinctrl-1 = <&pinctrl_i2c_data1>; /* GPC2 */
};
@ -629,6 +631,7 @@
status = "disabled";
label = "I2C_2";
port-num = <2>;
gpio-dev = <&gpiof>;
pinctrl-0 = <&pinctrl_i2c_clk2>; /* GPF6 */
pinctrl-1 = <&pinctrl_i2c_data2>; /* GPF7 */
};
@ -642,6 +645,7 @@
status = "disabled";
label = "I2C_3";
port-num = <3>;
gpio-dev = <&gpioh>;
pinctrl-0 = <&pinctrl_i2c_clk3>; /* GPH1 */
pinctrl-1 = <&pinctrl_i2c_data3>; /* GPH2 */
};
@ -655,6 +659,7 @@
status = "disabled";
label = "I2C_4";
port-num = <4>;
gpio-dev = <&gpioe>;
pinctrl-0 = <&pinctrl_i2c_clk4>; /* GPE0 */
pinctrl-1 = <&pinctrl_i2c_data4>; /* GPE7 */
};
@ -668,6 +673,7 @@
status = "disabled";
label = "I2C_5";
port-num = <5>;
gpio-dev = <&gpioa>;
pinctrl-0 = <&pinctrl_i2c_clk5>; /* GPA4 */
pinctrl-1 = <&pinctrl_i2c_data5>; /* GPA5 */
};