DM: I2C: Introduce 'u-boot, i2c-transaction-bytes' property

The 'u-boot,i2c-transaction-bytes' device tree property provides
information regarding number of bytes transferred by a device in a
single transaction.

This change is necessary to avoid hanging devices after soft reset.
One notable example is communication with MC34708 device:

1. Reset when communicating with MC34708 via I2C.

2. The u-boot (after reboot -f) tries to setup the I2C and then calls
force_idle_bus. In the same time MC34708 still has some data to be sent
(as it transfers data in 24 bits chunks).

3. The force_idle_bus() is not able to make the bus idle as 8 SCL
clocks may be not enough to have the full transmission.

4. We end up with I2C inconsistency with MC34708.

This PMIC device requires 24+ SCL cycles to make finish any pending I2C
transmission.

Signed-off-by: Lukasz Majewski <lukma@denx.de>
This commit is contained in:
Lukasz Majewski 2019-04-04 12:35:34 +02:00 committed by Heiko Schocher
parent 3c99166441
commit a40fe217d1
4 changed files with 48 additions and 2 deletions

View File

@ -12,6 +12,10 @@ property which allows the chip offset length to be selected.
Optional properties:
- u-boot,i2c-offset-len - length of chip offset in bytes. If omitted the
default value of 1 is used.
- u-boot,i2c-transaction-bytes - the length of single I2C transaction on
the bus. Some devices require more than single byte transmission
(e.g. mc34708 mfd). This information is necessary to correctly
initialize (put into idle state) I2C bus after soft reset.
- gpios = <sda ...>, <scl ...>;
pinctrl-names = "default", "gpio";
pinctrl-0 = <&i2c_xfer>;
@ -28,6 +32,7 @@ i2c4: i2c@12ca0000 {
compatible = "google,cros-ec";
i2c-max-frequency = <100000>;
u-boot,i2c-offset-len = <0>;
u-boot,i2c-transaction-bytes = <3>;
ec-interrupt = <&gpx1 6 GPIO_ACTIVE_LOW>;
};
};

View File

@ -593,6 +593,29 @@ int i2c_chip_ofdata_to_platdata(struct udevice *dev, struct dm_i2c_chip *chip)
}
#endif
static int i2c_pre_probe(struct udevice *dev)
{
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
struct dm_i2c_bus *i2c = dev_get_uclass_priv(dev);
unsigned int max = 0;
ofnode node;
int ret;
i2c->max_transaction_bytes = 0;
dev_for_each_subnode(node, dev) {
ret = ofnode_read_u32(node,
"u-boot,i2c-transaction-bytes",
&max);
if (!ret && max > i2c->max_transaction_bytes)
i2c->max_transaction_bytes = max;
}
debug("%s: I2C bus: %s max transaction bytes: %d\n", __func__,
dev->name, i2c->max_transaction_bytes);
#endif
return 0;
}
static int i2c_post_probe(struct udevice *dev)
{
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
@ -674,6 +697,7 @@ UCLASS_DRIVER(i2c) = {
.post_bind = i2c_post_bind,
.init = i2c_uclass_init,
.priv_auto_alloc_size = sizeof(struct i2c_priv),
.pre_probe = i2c_pre_probe,
.post_probe = i2c_post_probe,
.per_device_auto_alloc_size = sizeof(struct dm_i2c_bus),
.per_child_platdata_auto_alloc_size = sizeof(struct dm_i2c_chip),

View File

@ -354,9 +354,10 @@ int i2c_idle_bus(struct mxc_i2c_bus *i2c_bus)
int i2c_idle_bus(struct mxc_i2c_bus *i2c_bus)
{
struct udevice *bus = i2c_bus->bus;
struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
struct gpio_desc *scl_gpio = &i2c_bus->scl_gpio;
struct gpio_desc *sda_gpio = &i2c_bus->sda_gpio;
int sda, scl;
int sda, scl, idle_sclks;
int i, ret = 0;
ulong elapsed, start_time;
@ -380,8 +381,22 @@ int i2c_idle_bus(struct mxc_i2c_bus *i2c_bus)
if ((sda & scl) == 1)
goto exit; /* Bus is idle already */
/*
* In most cases it is just enough to generate 8 + 1 SCLK
* clocks to recover I2C slave device from 'stuck' state
* (when for example SW reset was performed, in the middle of
* I2C transmission).
*
* However, there are devices which send data in packets of
* N bytes (N > 1). In such case we do need N * 8 + 1 SCLK
* clocks.
*/
idle_sclks = 8 + 1;
if (i2c->max_transaction_bytes > 0)
idle_sclks = i2c->max_transaction_bytes * 8 + 1;
/* Send high and low on the SCL line */
for (i = 0; i < 9; i++) {
for (i = 0; i < idle_sclks; i++) {
dm_gpio_set_dir_flags(scl_gpio, GPIOD_IS_OUT);
dm_gpio_set_value(scl_gpio, 0);
udelay(50);

View File

@ -68,9 +68,11 @@ struct dm_i2c_chip {
* I2C bus udevice.
*
* @speed_hz: Bus speed in hertz (typically 100000)
* @max_transaction_bytes: Maximal size of single I2C transfer
*/
struct dm_i2c_bus {
int speed_hz;
int max_transaction_bytes;
};
/*