Re: [PATCH] i2c: at91: Send bus clear command if SCL or SDA is down

2019-09-19 Thread Codrin.Ciubotariu
On 19.09.2019 18:06, kbouhara wrote:
> 
> On 9/11/19 11:58 AM, Codrin Ciubotariu wrote:
>> After a transfer timeout, some faulty I2C slave devices might hold down
>> the SCL or the SDA pins. We can generate a bus clear command, hoping that
>> the slave might release the pins.
>>
>> Signed-off-by: Codrin Ciubotariu 
>> ---
>>   drivers/i2c/busses/i2c-at91-master.c | 20 
>>   drivers/i2c/busses/i2c-at91.h    |  6 +-
>>   2 files changed, 25 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/i2c/busses/i2c-at91-master.c 
>> b/drivers/i2c/busses/i2c-at91-master.c
>> index a3fcc35ffd3b..5f544a16db96 100644
>> --- a/drivers/i2c/busses/i2c-at91-master.c
>> +++ b/drivers/i2c/busses/i2c-at91-master.c
>> @@ -599,6 +599,26 @@ static int at91_do_twi_transfer(struct 
>> at91_twi_dev *dev)
>>   at91_twi_write(dev, AT91_TWI_CR,
>>  AT91_TWI_THRCLR | AT91_TWI_LOCKCLR);
>>   }
>> +
>> +    /*
>> + * After timeout, some faulty I2C slave devices might hold 
>> SCL/SDA down;
>> + * we can send a bus clear command, hoping that the pins will be
>> + * released
>> + */
>> +    if (!(dev->transfer_status & AT91_TWI_SDA) ||
>> +    !(dev->transfer_status & AT91_TWI_SCL)) {
>> +    dev_dbg(dev->dev,
>> +    "SDA/SCL are down; sending bus clear command\n");
>> +    if (dev->use_alt_cmd) {
>> +    unsigned int acr;
>> +
>> +    acr = at91_twi_read(dev, AT91_TWI_ACR);
>> +    acr &= ~AT91_TWI_ACR_DATAL_MASK;
>> +    at91_twi_write(dev, AT91_TWI_ACR, acr);
>> +    }
>> +    at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_CLEAR);
> 
> This bit is not documented on SoCs before SAMA5D2/D4, this write 
> shouldn't be done unconditionally.
> 
> 

Indeed, they are not present on SAMA5D4 or earlier SoCs. It is supported 
on SAMA5D2 though. I will make a new version and implement the CLEAR 
command only for the SoCs that support it.

Thank you for your review.

Best regards,
Codrin


Re: [PATCH] i2c: at91: Send bus clear command if SCL or SDA is down

2019-09-19 Thread kbouhara

On 9/11/19 11:58 AM, Codrin Ciubotariu wrote:

After a transfer timeout, some faulty I2C slave devices might hold down
the SCL or the SDA pins. We can generate a bus clear command, hoping that
the slave might release the pins.

Signed-off-by: Codrin Ciubotariu 
---
  drivers/i2c/busses/i2c-at91-master.c | 20 
  drivers/i2c/busses/i2c-at91.h|  6 +-
  2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-at91-master.c 
b/drivers/i2c/busses/i2c-at91-master.c
index a3fcc35ffd3b..5f544a16db96 100644
--- a/drivers/i2c/busses/i2c-at91-master.c
+++ b/drivers/i2c/busses/i2c-at91-master.c
@@ -599,6 +599,26 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
at91_twi_write(dev, AT91_TWI_CR,
   AT91_TWI_THRCLR | AT91_TWI_LOCKCLR);
}
+
+   /*
+* After timeout, some faulty I2C slave devices might hold SCL/SDA down;
+* we can send a bus clear command, hoping that the pins will be
+* released
+*/
+   if (!(dev->transfer_status & AT91_TWI_SDA) ||
+   !(dev->transfer_status & AT91_TWI_SCL)) {
+   dev_dbg(dev->dev,
+   "SDA/SCL are down; sending bus clear command\n");
+   if (dev->use_alt_cmd) {
+   unsigned int acr;
+
+   acr = at91_twi_read(dev, AT91_TWI_ACR);
+   acr &= ~AT91_TWI_ACR_DATAL_MASK;
+   at91_twi_write(dev, AT91_TWI_ACR, acr);
+   }
+   at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_CLEAR);


This bit is not documented on SoCs before SAMA5D2/D4, this write 
shouldn't be done unconditionally.



--
Kamel Bouhara, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com



Re: [PATCH] i2c: at91: Send bus clear command if SCL or SDA is down

2019-09-15 Thread Claudiu.Beznea


On 11.09.2019 12:58, Codrin Ciubotariu wrote:
> External E-Mail
> 
> 
> After a transfer timeout, some faulty I2C slave devices might hold down
> the SCL or the SDA pins. We can generate a bus clear command, hoping that
> the slave might release the pins.
> 
> Signed-off-by: Codrin Ciubotariu 

Reviewed-by: Claudiu Beznea 

> ---
>  drivers/i2c/busses/i2c-at91-master.c | 20 
>  drivers/i2c/busses/i2c-at91.h|  6 +-
>  2 files changed, 25 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/i2c/busses/i2c-at91-master.c 
> b/drivers/i2c/busses/i2c-at91-master.c
> index a3fcc35ffd3b..5f544a16db96 100644
> --- a/drivers/i2c/busses/i2c-at91-master.c
> +++ b/drivers/i2c/busses/i2c-at91-master.c
> @@ -599,6 +599,26 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
>   at91_twi_write(dev, AT91_TWI_CR,
>  AT91_TWI_THRCLR | AT91_TWI_LOCKCLR);
>   }
> +
> + /*
> +  * After timeout, some faulty I2C slave devices might hold SCL/SDA down;
> +  * we can send a bus clear command, hoping that the pins will be
> +  * released
> +  */
> + if (!(dev->transfer_status & AT91_TWI_SDA) ||
> + !(dev->transfer_status & AT91_TWI_SCL)) {
> + dev_dbg(dev->dev,
> + "SDA/SCL are down; sending bus clear command\n");
> + if (dev->use_alt_cmd) {
> + unsigned int acr;
> +
> + acr = at91_twi_read(dev, AT91_TWI_ACR);
> + acr &= ~AT91_TWI_ACR_DATAL_MASK;
> + at91_twi_write(dev, AT91_TWI_ACR, acr);
> + }
> + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_CLEAR);
> + }
> +
>   return ret;
>  }
>  
> diff --git a/drivers/i2c/busses/i2c-at91.h b/drivers/i2c/busses/i2c-at91.h
> index 499b506f6128..ffb870f3ffc6 100644
> --- a/drivers/i2c/busses/i2c-at91.h
> +++ b/drivers/i2c/busses/i2c-at91.h
> @@ -36,6 +36,7 @@
>  #define  AT91_TWI_SVDIS  BIT(5)  /* Slave Transfer Disable */
>  #define  AT91_TWI_QUICK  BIT(6)  /* SMBus quick command */
>  #define  AT91_TWI_SWRST  BIT(7)  /* Software Reset */
> +#define  AT91_TWI_CLEAR  BIT(15) /* Bus clear command */
>  #define  AT91_TWI_ACMEN  BIT(16) /* Alternative Command Mode 
> Enable */
>  #define  AT91_TWI_ACMDIS BIT(17) /* Alternative Command Mode 
> Disable */
>  #define  AT91_TWI_THRCLR BIT(24) /* Transmit Holding Register 
> Clear */
> @@ -69,6 +70,8 @@
>  #define  AT91_TWI_NACK   BIT(8)  /* Not Acknowledged */
>  #define  AT91_TWI_EOSACC BIT(11) /* End Of Slave Access */
>  #define  AT91_TWI_LOCK   BIT(23) /* TWI Lock due to Frame Errors 
> */
> +#define  AT91_TWI_SCLBIT(24) /* TWI SCL status */
> +#define  AT91_TWI_SDABIT(25) /* TWI SDA status */
>  
>  #define  AT91_TWI_INT_MASK \
>   (AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK \
> @@ -81,7 +84,8 @@
>  #define  AT91_TWI_THR0x0034  /* Transmit Holding Register */
>  
>  #define  AT91_TWI_ACR0x0040  /* Alternative Command Register 
> */
> -#define  AT91_TWI_ACR_DATAL(len) ((len) & 0xff)
> +#define  AT91_TWI_ACR_DATAL_MASK GENMASK(15, 0)
> +#define  AT91_TWI_ACR_DATAL(len) ((len) & AT91_TWI_ACR_DATAL_MASK)
>  #define  AT91_TWI_ACR_DIRBIT(8)
>  
>  #define  AT91_TWI_FMR0x0050  /* FIFO Mode Register */
> 


Re: [PATCH] i2c: at91: Send bus clear command if SCL or SDA is down

2019-09-14 Thread Ludovic Desroches
On Wed, Sep 11, 2019 at 12:58:54PM +0300, Codrin Ciubotariu wrote:
> After a transfer timeout, some faulty I2C slave devices might hold down
> the SCL or the SDA pins. We can generate a bus clear command, hoping that
> the slave might release the pins.
> 
> Signed-off-by: Codrin Ciubotariu 
Acked-by: Ludovic Desroches 

I'll be off for three weeks so if there are minor changes, you can keep my
ack.

Thanks

Ludovic

> ---
>  drivers/i2c/busses/i2c-at91-master.c | 20 
>  drivers/i2c/busses/i2c-at91.h|  6 +-
>  2 files changed, 25 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/i2c/busses/i2c-at91-master.c 
> b/drivers/i2c/busses/i2c-at91-master.c
> index a3fcc35ffd3b..5f544a16db96 100644
> --- a/drivers/i2c/busses/i2c-at91-master.c
> +++ b/drivers/i2c/busses/i2c-at91-master.c
> @@ -599,6 +599,26 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
>   at91_twi_write(dev, AT91_TWI_CR,
>  AT91_TWI_THRCLR | AT91_TWI_LOCKCLR);
>   }
> +
> + /*
> +  * After timeout, some faulty I2C slave devices might hold SCL/SDA down;
> +  * we can send a bus clear command, hoping that the pins will be
> +  * released
> +  */
> + if (!(dev->transfer_status & AT91_TWI_SDA) ||
> + !(dev->transfer_status & AT91_TWI_SCL)) {
> + dev_dbg(dev->dev,
> + "SDA/SCL are down; sending bus clear command\n");
> + if (dev->use_alt_cmd) {
> + unsigned int acr;
> +
> + acr = at91_twi_read(dev, AT91_TWI_ACR);
> + acr &= ~AT91_TWI_ACR_DATAL_MASK;
> + at91_twi_write(dev, AT91_TWI_ACR, acr);
> + }
> + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_CLEAR);
> + }
> +
>   return ret;
>  }
>  
> diff --git a/drivers/i2c/busses/i2c-at91.h b/drivers/i2c/busses/i2c-at91.h
> index 499b506f6128..ffb870f3ffc6 100644
> --- a/drivers/i2c/busses/i2c-at91.h
> +++ b/drivers/i2c/busses/i2c-at91.h
> @@ -36,6 +36,7 @@
>  #define  AT91_TWI_SVDIS  BIT(5)  /* Slave Transfer Disable */
>  #define  AT91_TWI_QUICK  BIT(6)  /* SMBus quick command */
>  #define  AT91_TWI_SWRST  BIT(7)  /* Software Reset */
> +#define  AT91_TWI_CLEAR  BIT(15) /* Bus clear command */
>  #define  AT91_TWI_ACMEN  BIT(16) /* Alternative Command Mode 
> Enable */
>  #define  AT91_TWI_ACMDIS BIT(17) /* Alternative Command Mode 
> Disable */
>  #define  AT91_TWI_THRCLR BIT(24) /* Transmit Holding Register 
> Clear */
> @@ -69,6 +70,8 @@
>  #define  AT91_TWI_NACK   BIT(8)  /* Not Acknowledged */
>  #define  AT91_TWI_EOSACC BIT(11) /* End Of Slave Access */
>  #define  AT91_TWI_LOCK   BIT(23) /* TWI Lock due to Frame Errors 
> */
> +#define  AT91_TWI_SCLBIT(24) /* TWI SCL status */
> +#define  AT91_TWI_SDABIT(25) /* TWI SDA status */
>  
>  #define  AT91_TWI_INT_MASK \
>   (AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK \
> @@ -81,7 +84,8 @@
>  #define  AT91_TWI_THR0x0034  /* Transmit Holding Register */
>  
>  #define  AT91_TWI_ACR0x0040  /* Alternative Command Register 
> */
> -#define  AT91_TWI_ACR_DATAL(len) ((len) & 0xff)
> +#define  AT91_TWI_ACR_DATAL_MASK GENMASK(15, 0)
> +#define  AT91_TWI_ACR_DATAL(len) ((len) & AT91_TWI_ACR_DATAL_MASK)
>  #define  AT91_TWI_ACR_DIRBIT(8)
>  
>  #define  AT91_TWI_FMR0x0050  /* FIFO Mode Register */
> -- 
> 2.20.1
> 


[PATCH] i2c: at91: Send bus clear command if SCL or SDA is down

2019-09-11 Thread Codrin Ciubotariu
After a transfer timeout, some faulty I2C slave devices might hold down
the SCL or the SDA pins. We can generate a bus clear command, hoping that
the slave might release the pins.

Signed-off-by: Codrin Ciubotariu 
---
 drivers/i2c/busses/i2c-at91-master.c | 20 
 drivers/i2c/busses/i2c-at91.h|  6 +-
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-at91-master.c 
b/drivers/i2c/busses/i2c-at91-master.c
index a3fcc35ffd3b..5f544a16db96 100644
--- a/drivers/i2c/busses/i2c-at91-master.c
+++ b/drivers/i2c/busses/i2c-at91-master.c
@@ -599,6 +599,26 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
at91_twi_write(dev, AT91_TWI_CR,
   AT91_TWI_THRCLR | AT91_TWI_LOCKCLR);
}
+
+   /*
+* After timeout, some faulty I2C slave devices might hold SCL/SDA down;
+* we can send a bus clear command, hoping that the pins will be
+* released
+*/
+   if (!(dev->transfer_status & AT91_TWI_SDA) ||
+   !(dev->transfer_status & AT91_TWI_SCL)) {
+   dev_dbg(dev->dev,
+   "SDA/SCL are down; sending bus clear command\n");
+   if (dev->use_alt_cmd) {
+   unsigned int acr;
+
+   acr = at91_twi_read(dev, AT91_TWI_ACR);
+   acr &= ~AT91_TWI_ACR_DATAL_MASK;
+   at91_twi_write(dev, AT91_TWI_ACR, acr);
+   }
+   at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_CLEAR);
+   }
+
return ret;
 }
 
diff --git a/drivers/i2c/busses/i2c-at91.h b/drivers/i2c/busses/i2c-at91.h
index 499b506f6128..ffb870f3ffc6 100644
--- a/drivers/i2c/busses/i2c-at91.h
+++ b/drivers/i2c/busses/i2c-at91.h
@@ -36,6 +36,7 @@
 #defineAT91_TWI_SVDIS  BIT(5)  /* Slave Transfer Disable */
 #defineAT91_TWI_QUICK  BIT(6)  /* SMBus quick command */
 #defineAT91_TWI_SWRST  BIT(7)  /* Software Reset */
+#defineAT91_TWI_CLEAR  BIT(15) /* Bus clear command */
 #defineAT91_TWI_ACMEN  BIT(16) /* Alternative Command Mode 
Enable */
 #defineAT91_TWI_ACMDIS BIT(17) /* Alternative Command Mode 
Disable */
 #defineAT91_TWI_THRCLR BIT(24) /* Transmit Holding Register 
Clear */
@@ -69,6 +70,8 @@
 #defineAT91_TWI_NACK   BIT(8)  /* Not Acknowledged */
 #defineAT91_TWI_EOSACC BIT(11) /* End Of Slave Access */
 #defineAT91_TWI_LOCK   BIT(23) /* TWI Lock due to Frame Errors 
*/
+#defineAT91_TWI_SCLBIT(24) /* TWI SCL status */
+#defineAT91_TWI_SDABIT(25) /* TWI SDA status */
 
 #defineAT91_TWI_INT_MASK \
(AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK \
@@ -81,7 +84,8 @@
 #defineAT91_TWI_THR0x0034  /* Transmit Holding Register */
 
 #defineAT91_TWI_ACR0x0040  /* Alternative Command Register 
*/
-#defineAT91_TWI_ACR_DATAL(len) ((len) & 0xff)
+#defineAT91_TWI_ACR_DATAL_MASK GENMASK(15, 0)
+#defineAT91_TWI_ACR_DATAL(len) ((len) & AT91_TWI_ACR_DATAL_MASK)
 #defineAT91_TWI_ACR_DIRBIT(8)
 
 #defineAT91_TWI_FMR0x0050  /* FIFO Mode Register */
-- 
2.20.1