[U-Boot] [PATCH 1/3] i2c: tegra: use repeated start for reads
Simon Glass
sjg at chromium.org
Thu Jun 26 04:12:29 CEST 2014
Hi Stephen,
On 25 June 2014 10:57, Stephen Warren <swarren at wwwdotorg.org> wrote:
>
> From: Stephen Warren <swarren at nvidia.com>
>
> I2C read transactions are typically implemented as follows:
>
> START(write) address REPEATED_START(read) data... STOP
>
> However, Tegra's I2C driver currently implements reads as follows:
>
> START(write) address STOP START(read) data... STOP
>
> This sequence confuses at least the AS3722 PMIC on the Jetson TK1 board,
> leading to corrupted read data in some cases. Fix the driver to chain
> the transactions together using repeated starts to solve this.
>
> Signed-off-by: Stephen Warren <swarren at nvidia.com>
> ---
> arch/arm/include/asm/arch-tegra/tegra_i2c.h | 2 ++
> drivers/i2c/tegra_i2c.c | 24 ++++++++++++++++--------
> 2 files changed, 18 insertions(+), 8 deletions(-)
>
> diff --git a/arch/arm/include/asm/arch-tegra/tegra_i2c.h b/arch/arm/include/asm/arch-tegra/tegra_i2c.h
> index 853e59bb6e65..7ca690700cb4 100644
> --- a/arch/arm/include/asm/arch-tegra/tegra_i2c.h
> +++ b/arch/arm/include/asm/arch-tegra/tegra_i2c.h
> @@ -124,6 +124,8 @@ struct i2c_ctlr {
> /* bit fields definitions for IO Packet Header 3 format */
> #define PKT_HDR3_READ_MODE_SHIFT 19
> #define PKT_HDR3_READ_MODE_MASK (1 << PKT_HDR3_READ_MODE_SHIFT)
> +#define PKT_HDR3_REPEAT_START_SHIFT 16
> +#define PKT_HDR3_REPEAT_START_MASK (1 << PKT_HDR3_REPEAT_START_SHIFT)
> #define PKT_HDR3_SLAVE_ADDR_SHIFT 0
> #define PKT_HDR3_SLAVE_ADDR_MASK (0x3ff << PKT_HDR3_SLAVE_ADDR_SHIFT)
>
> diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c
> index 594e5ddeb43e..97f0ca44c59a 100644
> --- a/drivers/i2c/tegra_i2c.c
> +++ b/drivers/i2c/tegra_i2c.c
> @@ -110,7 +110,8 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus)
> static void send_packet_headers(
> struct i2c_bus *i2c_bus,
> struct i2c_trans_info *trans,
> - u32 packet_id)
> + u32 packet_id,
> + bool end_with_repeated_start)
> {
> u32 data;
>
> @@ -132,6 +133,8 @@ static void send_packet_headers(
> /* Enable Read if it is not a write transaction */
> if (!(trans->flags & I2C_IS_WRITE))
> data |= PKT_HDR3_READ_MODE_MASK;
> + if (end_with_repeated_start)
> + data |= PKT_HDR3_REPEAT_START_MASK;
>
> /* Write I2C specific header */
> writel(data, &i2c_bus->control->tx_fifo);
> @@ -209,7 +212,8 @@ static int send_recv_packets(struct i2c_bus *i2c_bus,
> int_status = readl(&control->int_status);
> writel(int_status, &control->int_status);
>
> - send_packet_headers(i2c_bus, trans, 1);
> + send_packet_headers(i2c_bus, trans, 1,
> + trans->flags & I2C_USE_REPEATED_START);
I'm not sure if it is safe/advisable to pass this value to a bool
type. Perhaps the function parameter should be int? My understanding
of bool is that it is supposed to be 0 or 1, but I'm happy to be
corrected.
>
> words = DIV_ROUND_UP(trans->num_bytes, 4);
> last_bytes = trans->num_bytes & 3;
Regards,
Simon
More information about the U-Boot
mailing list