[U-Boot] [PATCH] i2c: add NACK logic in write
Vadim Bendebury
vbendeb at chromium.org
Tue Apr 23 04:44:09 CEST 2013
On Mon, Mar 25, 2013 at 4:17 AM, Akshay Saraswat <akshay.s at samsung.com> wrote:
>
> From: Naveen Krishna Chatradhi <ch.naveen at samsung.com>
>
> Adding NACK logic for i2c write.
> Verified by reading and writing to device with address 9 on i2c-0.
>
> Signed-off-by: Naveen Krishna Chatradhi <ch.naveen at samsung.com>
> Signed-off-by: Akshay Saraswat <akshay.s at samsung.com>
> ---
> drivers/i2c/s3c24x0_i2c.c | 111
> +++++++++++++++++++++++-----------------------
> 1 file changed, 56 insertions(+), 55 deletions(-)
>
> diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c
> index 769a2ba..d2b4eb0 100644
> --- a/drivers/i2c/s3c24x0_i2c.c
> +++ b/drivers/i2c/s3c24x0_i2c.c
> @@ -201,6 +201,35 @@ unsigned int i2c_get_bus_num(void)
> }
> #endif
>
> +/*
> + * Verify the whether I2C ACK was received or not
> + *
> + * @param i2c pointer to I2C register base
> + * @param buf array of data
> + * @param len length of data
> + * return I2C_OK when transmission done
> + * I2C_NACK otherwise
> + */
> +static int i2c_send_verify(struct s3c24x0_i2c *i2c, unsigned char buf[],
> + unsigned char len)
> +{
> + int i, result = I2C_OK;
> +
> + if (IsACK(i2c)) {
> + for (i = 0; (i < len) && (result == I2C_OK); i++) {
> + writel(buf[i], &i2c->iicds);
> + ReadWriteByte(i2c);
> + result = WaitForXfer(i2c);
> + if (!IsACK(i2c))
> + result = I2C_NACK;
> + }
> + } else {
> + result = I2C_NACK;
> + }
> +
> + return result;
> +}
> +
> void i2c_init(int speed, int slaveadd)
> {
> struct s3c24x0_i2c *i2c;
> @@ -302,41 +331,30 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
> return I2C_NOK_TOUT;
>
> writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon);
> - result = I2C_OK;
> +
> + if (addr && addr_len) {
> + writel(chip, &i2c->iicds);
> + /* send START */
> + writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP,
> + &i2c->iicstat);
> + if (WaitForXfer(i2c) == I2C_OK)
> + result = i2c_send_verify(i2c, addr, addr_len);
> + else
> + result = I2C_NACK;
> + } else
> + result = I2C_NACK;
>
> switch (cmd_type) {
> case I2C_WRITE:
> - if (addr && addr_len) {
> - writel(chip, &i2c->iicds);
> - /* send START */
> - writel(I2C_MODE_MT | I2C_TXRX_ENA |
> I2C_START_STOP,
> - &i2c->iicstat);
> - i = 0;
> - while ((i < addr_len) && (result == I2C_OK)) {
> - result = WaitForXfer(i2c);
> - writel(addr[i], &i2c->iicds);
> - ReadWriteByte(i2c);
> - i++;
> - }
> - i = 0;
> - while ((i < data_len) && (result == I2C_OK)) {
> - result = WaitForXfer(i2c);
> - writel(data[i], &i2c->iicds);
> - ReadWriteByte(i2c);
> - i++;
> - }
> - } else {
> + if (result == I2C_OK)
> + result = i2c_send_verify(i2c, data, data_len);
> + else {
> writel(chip, &i2c->iicds);
> /* send START */
> writel(I2C_MODE_MT | I2C_TXRX_ENA |
> I2C_START_STOP,
> - &i2c->iicstat);
> - i = 0;
> - while ((i < data_len) && (result = I2C_OK)) {
> - result = WaitForXfer(i2c);
> - writel(data[i], &i2c->iicds);
> - ReadWriteByte(i2c);
> - i++;
> - }
> + &i2c->iicstat);
> + if (WaitForXfer(i2c) == I2C_OK)
> + result = i2c_send_verify(i2c, data,
> data_len);
> }
>
> if (result == I2C_OK)
> @@ -348,42 +366,25 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
> break;
>
> case I2C_READ:
> - if (addr && addr_len) {
> - writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
> + if (result == I2C_OK) {
> + writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
> writel(chip, &i2c->iicds);
> /* send START */
> writel(readl(&i2c->iicstat) | I2C_START_STOP,
> &i2c->iicstat);
> - result = WaitForXfer(i2c);
> - if (IsACK(i2c)) {
> - i = 0;
> - while ((i < addr_len) && (result ==
> I2C_OK)) {
> - writel(addr[i], &i2c->iicds);
> - ReadWriteByte(i2c);
> - result = WaitForXfer(i2c);
> - i++;
> - }
> -
> - writel(chip, &i2c->iicds);
> - /* resend START */
> - writel(I2C_MODE_MR | I2C_TXRX_ENA |
> - I2C_START_STOP, &i2c->iicstat);
> ReadWriteByte(i2c);
> result = WaitForXfer(i2c);
> - i = 0;
> - while ((i < data_len) && (result ==
> I2C_OK)) {
> - /* disable ACK for final READ */
> - if (i == data_len - 1)
> - writel(readl(&i2c->iiccon)
> + i = 0;
> + while ((i < data_len) && (result == I2C_OK)) {
> + /* disable ACK for final READ */
> + if (i == data_len - 1)
> + writel(readl(&i2c->iiccon)
> & ~I2CCON_ACKGEN,
> &i2c->iiccon);
> ReadWriteByte(i2c);
> result = WaitForXfer(i2c);
> - data[i] = readl(&i2c->iicds);
> - i++;
> - }
> - } else {
> - result = I2C_NACK;
> + data[i] = readl(&i2c->iicds);
> + i++;
> }
>
> } else {
> --
> 1.8.0
>
Guys, can we please hold on to this. I have a version which was
debugged and worked with the Infineon TPM, (which is generates NACKs
quite liberally, and not just on writes, but on reads too). I will
submit it a bit later.
--vb
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
More information about the U-Boot
mailing list