Re: [PATCH RFC 3/4] i2c: at91: added slave mode support

2017-11-02 Thread Ludovic Desroches
On Wed, Nov 01, 2017 at 02:04:18PM +0100, Juergen Fitschen wrote:
> Helle Ludovic,
> 
> while going through this patch a question related to the Atmel / Microchip HW
> came into mind:
> 
> On Fri, Oct 27, 2017 at 05:12:00PM +0200, Juergen Fitschen wrote:
> > diff --git a/drivers/i2c/busses/i2c-at91.h b/drivers/i2c/busses/i2c-at91.h
> > (...)
> >  #defineAT91_TWI_INT_MASK \
> > -   (AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK)
> > +   (AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK \
> > +   | AT91_TWI_SVACC | AT91_TWI_EOSACC)
> 
> The AT91_TWI_INT_MASK is used to disable all interrputs in the
> at91_disable_twi_interrupts function by writing the mask to the interrupt
> disable register (IDR). I wonder what happens on MPUs that don't have
> AT91_TWI_SVACC and AT91_TWI_EOSACC implemented, like the AT91RM9200? Do you
> think we should revise this and write specific masks depending on the current
> moude the I2C HW is in?
> 
> Something like this:
> 
> void at91_disable_twi_interrupts(struct at91_twi_dev *dev)
> {
> if (dev->slave_detected)
> at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_INT_MASK_SLAVE);
> else
> at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_INT_MASK_MASTER);
> }
> 

I don't think it's necessary. Usually, writing a bit which is unused don't
cause weird behaviors.

Regards

Ludovic


Re: [PATCH RFC 3/4] i2c: at91: added slave mode support

2017-11-02 Thread Ludovic Desroches
On Wed, Nov 01, 2017 at 02:04:18PM +0100, Juergen Fitschen wrote:
> Helle Ludovic,
> 
> while going through this patch a question related to the Atmel / Microchip HW
> came into mind:
> 
> On Fri, Oct 27, 2017 at 05:12:00PM +0200, Juergen Fitschen wrote:
> > diff --git a/drivers/i2c/busses/i2c-at91.h b/drivers/i2c/busses/i2c-at91.h
> > (...)
> >  #defineAT91_TWI_INT_MASK \
> > -   (AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK)
> > +   (AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK \
> > +   | AT91_TWI_SVACC | AT91_TWI_EOSACC)
> 
> The AT91_TWI_INT_MASK is used to disable all interrputs in the
> at91_disable_twi_interrupts function by writing the mask to the interrupt
> disable register (IDR). I wonder what happens on MPUs that don't have
> AT91_TWI_SVACC and AT91_TWI_EOSACC implemented, like the AT91RM9200? Do you
> think we should revise this and write specific masks depending on the current
> moude the I2C HW is in?
> 
> Something like this:
> 
> void at91_disable_twi_interrupts(struct at91_twi_dev *dev)
> {
> if (dev->slave_detected)
> at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_INT_MASK_SLAVE);
> else
> at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_INT_MASK_MASTER);
> }
> 

I don't think it's necessary. Usually, writing a bit which is unused don't
cause weird behaviors.

Regards

Ludovic


Re: [PATCH RFC 3/4] i2c: at91: added slave mode support

2017-11-01 Thread Juergen Fitschen
Helle Ludovic,

while going through this patch a question related to the Atmel / Microchip HW
came into mind:

On Fri, Oct 27, 2017 at 05:12:00PM +0200, Juergen Fitschen wrote:
> diff --git a/drivers/i2c/busses/i2c-at91.h b/drivers/i2c/busses/i2c-at91.h
> (...)
>  #define  AT91_TWI_INT_MASK \
> - (AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK)
> + (AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK \
> + | AT91_TWI_SVACC | AT91_TWI_EOSACC)

The AT91_TWI_INT_MASK is used to disable all interrputs in the
at91_disable_twi_interrupts function by writing the mask to the interrupt
disable register (IDR). I wonder what happens on MPUs that don't have
AT91_TWI_SVACC and AT91_TWI_EOSACC implemented, like the AT91RM9200? Do you
think we should revise this and write specific masks depending on the current
moude the I2C HW is in?

Something like this:

void at91_disable_twi_interrupts(struct at91_twi_dev *dev)
{
if (dev->slave_detected)
at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_INT_MASK_SLAVE);
else
at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_INT_MASK_MASTER);
}


Best regards
  Juergen


Re: [PATCH RFC 3/4] i2c: at91: added slave mode support

2017-11-01 Thread Juergen Fitschen
Helle Ludovic,

while going through this patch a question related to the Atmel / Microchip HW
came into mind:

On Fri, Oct 27, 2017 at 05:12:00PM +0200, Juergen Fitschen wrote:
> diff --git a/drivers/i2c/busses/i2c-at91.h b/drivers/i2c/busses/i2c-at91.h
> (...)
>  #define  AT91_TWI_INT_MASK \
> - (AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK)
> + (AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK \
> + | AT91_TWI_SVACC | AT91_TWI_EOSACC)

The AT91_TWI_INT_MASK is used to disable all interrputs in the
at91_disable_twi_interrupts function by writing the mask to the interrupt
disable register (IDR). I wonder what happens on MPUs that don't have
AT91_TWI_SVACC and AT91_TWI_EOSACC implemented, like the AT91RM9200? Do you
think we should revise this and write specific masks depending on the current
moude the I2C HW is in?

Something like this:

void at91_disable_twi_interrupts(struct at91_twi_dev *dev)
{
if (dev->slave_detected)
at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_INT_MASK_SLAVE);
else
at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_INT_MASK_MASTER);
}


Best regards
  Juergen


Re: [PATCH RFC 3/4] i2c: at91: added slave mode support

2017-11-01 Thread Juergen Fitschen
Hello Ludovic,

On Tue, Oct 31, 2017 at 04:55:42PM +0100, Ludovic Desroches wrote:
> On Fri, Oct 27, 2017 at 05:12:00PM +0200, Juergen Fitschen wrote:
> > Slave mode driver is based on the concept of i2c-designware driver.
> > 
> > Signed-off-by: Juergen Fitschen 
> > ---
> >  drivers/i2c/busses/Makefile |   3 +
> >  drivers/i2c/busses/i2c-at91-core.c  |  13 +++-
> >  drivers/i2c/busses/i2c-at91-slave.c | 147 
> > 
> >  drivers/i2c/busses/i2c-at91.h   |  30 +++-
> >  4 files changed, 189 insertions(+), 4 deletions(-)
> >  create mode 100644 drivers/i2c/busses/i2c-at91-slave.c
> > 
> 
> Adding an example in Documentation/devicetree/bindings/i2c/i2c-at91.txt
> could be useful.

I will add this.

> > diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> > index 2a79c3d..b38fb8e9 100644
> > --- a/drivers/i2c/busses/Makefile
> > +++ b/drivers/i2c/busses/Makefile
> > @@ -34,6 +34,9 @@ obj-$(CONFIG_I2C_ALTERA)  += i2c-altera.o
> >  obj-$(CONFIG_I2C_ASPEED)   += i2c-aspeed.o
> >  obj-$(CONFIG_I2C_AT91) += i2c-at91.o
> >  i2c-at91-objs  := i2c-at91-core.o i2c-at91-master.o
> > +ifeq ($(CONFIG_I2C_SLAVE),y)
> > +   i2c-at91-objs   += i2c-at91-slave.o
> > +endif
> 
> As Designware driver, I would add an entry in 'I2C Hardware Bus
> Support'.
> 
> If a user wants to use the I2C GPIO driver as the I2C slave (once it has
> the slave support), it's not useful to embed i2c-at91-slave code.

Good point.

> > +void at91_init_twi_bus_slave(struct at91_twi_dev *dev)
> > +{
> > +   at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_MSDIS);
> > +   if (dev->slave_detected && dev->smr) {
> 
> slave_detected has been checked in the caller. smr has been set just
> before calling at91_init_twi_bus().

Whoops! Better safe than sorry ;) I will remove that check.



Thank you for testing everything! I am curious about how the other MPUs will
perform with the patchset. I have a SAMA5D35 at hand and can test everything on
this MPU in the next days.


Best regards
  Juergen



Re: [PATCH RFC 3/4] i2c: at91: added slave mode support

2017-11-01 Thread Juergen Fitschen
Hello Ludovic,

On Tue, Oct 31, 2017 at 04:55:42PM +0100, Ludovic Desroches wrote:
> On Fri, Oct 27, 2017 at 05:12:00PM +0200, Juergen Fitschen wrote:
> > Slave mode driver is based on the concept of i2c-designware driver.
> > 
> > Signed-off-by: Juergen Fitschen 
> > ---
> >  drivers/i2c/busses/Makefile |   3 +
> >  drivers/i2c/busses/i2c-at91-core.c  |  13 +++-
> >  drivers/i2c/busses/i2c-at91-slave.c | 147 
> > 
> >  drivers/i2c/busses/i2c-at91.h   |  30 +++-
> >  4 files changed, 189 insertions(+), 4 deletions(-)
> >  create mode 100644 drivers/i2c/busses/i2c-at91-slave.c
> > 
> 
> Adding an example in Documentation/devicetree/bindings/i2c/i2c-at91.txt
> could be useful.

I will add this.

> > diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> > index 2a79c3d..b38fb8e9 100644
> > --- a/drivers/i2c/busses/Makefile
> > +++ b/drivers/i2c/busses/Makefile
> > @@ -34,6 +34,9 @@ obj-$(CONFIG_I2C_ALTERA)  += i2c-altera.o
> >  obj-$(CONFIG_I2C_ASPEED)   += i2c-aspeed.o
> >  obj-$(CONFIG_I2C_AT91) += i2c-at91.o
> >  i2c-at91-objs  := i2c-at91-core.o i2c-at91-master.o
> > +ifeq ($(CONFIG_I2C_SLAVE),y)
> > +   i2c-at91-objs   += i2c-at91-slave.o
> > +endif
> 
> As Designware driver, I would add an entry in 'I2C Hardware Bus
> Support'.
> 
> If a user wants to use the I2C GPIO driver as the I2C slave (once it has
> the slave support), it's not useful to embed i2c-at91-slave code.

Good point.

> > +void at91_init_twi_bus_slave(struct at91_twi_dev *dev)
> > +{
> > +   at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_MSDIS);
> > +   if (dev->slave_detected && dev->smr) {
> 
> slave_detected has been checked in the caller. smr has been set just
> before calling at91_init_twi_bus().

Whoops! Better safe than sorry ;) I will remove that check.



Thank you for testing everything! I am curious about how the other MPUs will
perform with the patchset. I have a SAMA5D35 at hand and can test everything on
this MPU in the next days.


Best regards
  Juergen



Re: [PATCH RFC 3/4] i2c: at91: added slave mode support

2017-10-31 Thread Ludovic Desroches
On Fri, Oct 27, 2017 at 05:12:00PM +0200, Juergen Fitschen wrote:
> Slave mode driver is based on the concept of i2c-designware driver.
> 
> Signed-off-by: Juergen Fitschen 
> ---
>  drivers/i2c/busses/Makefile |   3 +
>  drivers/i2c/busses/i2c-at91-core.c  |  13 +++-
>  drivers/i2c/busses/i2c-at91-slave.c | 147 
> 
>  drivers/i2c/busses/i2c-at91.h   |  30 +++-
>  4 files changed, 189 insertions(+), 4 deletions(-)
>  create mode 100644 drivers/i2c/busses/i2c-at91-slave.c
> 

Adding an example in Documentation/devicetree/bindings/i2c/i2c-at91.txt
could be useful.

> diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> index 2a79c3d..b38fb8e9 100644
> --- a/drivers/i2c/busses/Makefile
> +++ b/drivers/i2c/busses/Makefile
> @@ -34,6 +34,9 @@ obj-$(CONFIG_I2C_ALTERA)+= i2c-altera.o
>  obj-$(CONFIG_I2C_ASPEED) += i2c-aspeed.o
>  obj-$(CONFIG_I2C_AT91)   += i2c-at91.o
>  i2c-at91-objs:= i2c-at91-core.o i2c-at91-master.o
> +ifeq ($(CONFIG_I2C_SLAVE),y)
> + i2c-at91-objs   += i2c-at91-slave.o
> +endif

As Designware driver, I would add an entry in 'I2C Hardware Bus
Support'.

If a user wants to use the I2C GPIO driver as the I2C slave (once it has
the slave support), it's not useful to embed i2c-at91-slave code.

>  obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
>  obj-$(CONFIG_I2C_AXXIA)  += i2c-axxia.o
>  obj-$(CONFIG_I2C_BCM2835)+= i2c-bcm2835.o
> diff --git a/drivers/i2c/busses/i2c-at91-core.c 
> b/drivers/i2c/busses/i2c-at91-core.c
> index 4fed72d..3d7287c 100644
> --- a/drivers/i2c/busses/i2c-at91-core.c
> +++ b/drivers/i2c/busses/i2c-at91-core.c
> @@ -60,8 +60,10 @@ void at91_init_twi_bus(struct at91_twi_dev *dev)
>  {
>   at91_disable_twi_interrupts(dev);
>   at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST);
> -
> - at91_init_twi_bus_master(dev);
> + if (dev->slave_detected)
> + at91_init_twi_bus_slave(dev);
> + else
> + at91_init_twi_bus_master(dev);
>  }
>  
>  static struct at91_twi_pdata at91rm9200_config = {
> @@ -243,7 +245,12 @@ static int at91_twi_probe(struct platform_device *pdev)
>   dev->adapter.timeout = AT91_I2C_TIMEOUT;
>   dev->adapter.dev.of_node = pdev->dev.of_node;
>  
> - rc = at91_twi_probe_master(pdev, phy_addr, dev);
> + dev->slave_detected = i2c_detect_slave_mode(>dev);
> +
> + if (dev->slave_detected)
> + rc = at91_twi_probe_slave(pdev, phy_addr, dev);
> + else
> + rc = at91_twi_probe_master(pdev, phy_addr, dev);
>   if (rc)
>   return rc;
>  
> diff --git a/drivers/i2c/busses/i2c-at91-slave.c 
> b/drivers/i2c/busses/i2c-at91-slave.c

I need to have a look to the slave framework and to test this patch before
giving you more feedback.

Some minor comments below.

> new file mode 100644
> index 000..4b4808e
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-at91-slave.c
> @@ -0,0 +1,147 @@
> +/*
> + *  i2c slave support for Atmel's AT91 Two-Wire Interface (TWI)
> + *
> + *  Copyright (C) 2017 Juergen Fitschen 
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + */
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#include "i2c-at91.h"
> +
> +static irqreturn_t atmel_twi_interrupt_slave(int irq, void *dev_id)
> +{
> + struct at91_twi_dev *dev = dev_id;
> + const unsigned status = at91_twi_read(dev, AT91_TWI_SR);
> + const unsigned irqstatus = status & at91_twi_read(dev, AT91_TWI_IMR);
> + u8 value;
> +
> + if (!irqstatus)
> + return IRQ_NONE;
> +
> + /* slave address has been detected on I2C bus */
> + if (irqstatus & AT91_TWI_SVACC) {
> + if (status & AT91_TWI_SVREAD) {
> + i2c_slave_event(dev->slave,
> + I2C_SLAVE_READ_REQUESTED, );
> + writeb_relaxed(value, dev->base + AT91_TWI_THR);
> + at91_twi_write(dev, AT91_TWI_IER,
> +AT91_TWI_TXRDY | AT91_TWI_EOSACC);
> + } else {
> + i2c_slave_event(dev->slave,
> + I2C_SLAVE_WRITE_REQUESTED, );
> + at91_twi_write(dev, AT91_TWI_IER,
> +AT91_TWI_RXRDY | AT91_TWI_EOSACC);
> + }
> + at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_SVACC);
> + }
> +
> + /* byte transmitted to remote master */
> + if (irqstatus & AT91_TWI_TXRDY) {
> + i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED, );
> + writeb_relaxed(value, dev->base + AT91_TWI_THR);
> + }
> +
> + /* byte received from 

Re: [PATCH RFC 3/4] i2c: at91: added slave mode support

2017-10-31 Thread Ludovic Desroches
On Fri, Oct 27, 2017 at 05:12:00PM +0200, Juergen Fitschen wrote:
> Slave mode driver is based on the concept of i2c-designware driver.
> 
> Signed-off-by: Juergen Fitschen 
> ---
>  drivers/i2c/busses/Makefile |   3 +
>  drivers/i2c/busses/i2c-at91-core.c  |  13 +++-
>  drivers/i2c/busses/i2c-at91-slave.c | 147 
> 
>  drivers/i2c/busses/i2c-at91.h   |  30 +++-
>  4 files changed, 189 insertions(+), 4 deletions(-)
>  create mode 100644 drivers/i2c/busses/i2c-at91-slave.c
> 

Adding an example in Documentation/devicetree/bindings/i2c/i2c-at91.txt
could be useful.

> diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> index 2a79c3d..b38fb8e9 100644
> --- a/drivers/i2c/busses/Makefile
> +++ b/drivers/i2c/busses/Makefile
> @@ -34,6 +34,9 @@ obj-$(CONFIG_I2C_ALTERA)+= i2c-altera.o
>  obj-$(CONFIG_I2C_ASPEED) += i2c-aspeed.o
>  obj-$(CONFIG_I2C_AT91)   += i2c-at91.o
>  i2c-at91-objs:= i2c-at91-core.o i2c-at91-master.o
> +ifeq ($(CONFIG_I2C_SLAVE),y)
> + i2c-at91-objs   += i2c-at91-slave.o
> +endif

As Designware driver, I would add an entry in 'I2C Hardware Bus
Support'.

If a user wants to use the I2C GPIO driver as the I2C slave (once it has
the slave support), it's not useful to embed i2c-at91-slave code.

>  obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
>  obj-$(CONFIG_I2C_AXXIA)  += i2c-axxia.o
>  obj-$(CONFIG_I2C_BCM2835)+= i2c-bcm2835.o
> diff --git a/drivers/i2c/busses/i2c-at91-core.c 
> b/drivers/i2c/busses/i2c-at91-core.c
> index 4fed72d..3d7287c 100644
> --- a/drivers/i2c/busses/i2c-at91-core.c
> +++ b/drivers/i2c/busses/i2c-at91-core.c
> @@ -60,8 +60,10 @@ void at91_init_twi_bus(struct at91_twi_dev *dev)
>  {
>   at91_disable_twi_interrupts(dev);
>   at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST);
> -
> - at91_init_twi_bus_master(dev);
> + if (dev->slave_detected)
> + at91_init_twi_bus_slave(dev);
> + else
> + at91_init_twi_bus_master(dev);
>  }
>  
>  static struct at91_twi_pdata at91rm9200_config = {
> @@ -243,7 +245,12 @@ static int at91_twi_probe(struct platform_device *pdev)
>   dev->adapter.timeout = AT91_I2C_TIMEOUT;
>   dev->adapter.dev.of_node = pdev->dev.of_node;
>  
> - rc = at91_twi_probe_master(pdev, phy_addr, dev);
> + dev->slave_detected = i2c_detect_slave_mode(>dev);
> +
> + if (dev->slave_detected)
> + rc = at91_twi_probe_slave(pdev, phy_addr, dev);
> + else
> + rc = at91_twi_probe_master(pdev, phy_addr, dev);
>   if (rc)
>   return rc;
>  
> diff --git a/drivers/i2c/busses/i2c-at91-slave.c 
> b/drivers/i2c/busses/i2c-at91-slave.c

I need to have a look to the slave framework and to test this patch before
giving you more feedback.

Some minor comments below.

> new file mode 100644
> index 000..4b4808e
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-at91-slave.c
> @@ -0,0 +1,147 @@
> +/*
> + *  i2c slave support for Atmel's AT91 Two-Wire Interface (TWI)
> + *
> + *  Copyright (C) 2017 Juergen Fitschen 
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + */
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#include "i2c-at91.h"
> +
> +static irqreturn_t atmel_twi_interrupt_slave(int irq, void *dev_id)
> +{
> + struct at91_twi_dev *dev = dev_id;
> + const unsigned status = at91_twi_read(dev, AT91_TWI_SR);
> + const unsigned irqstatus = status & at91_twi_read(dev, AT91_TWI_IMR);
> + u8 value;
> +
> + if (!irqstatus)
> + return IRQ_NONE;
> +
> + /* slave address has been detected on I2C bus */
> + if (irqstatus & AT91_TWI_SVACC) {
> + if (status & AT91_TWI_SVREAD) {
> + i2c_slave_event(dev->slave,
> + I2C_SLAVE_READ_REQUESTED, );
> + writeb_relaxed(value, dev->base + AT91_TWI_THR);
> + at91_twi_write(dev, AT91_TWI_IER,
> +AT91_TWI_TXRDY | AT91_TWI_EOSACC);
> + } else {
> + i2c_slave_event(dev->slave,
> + I2C_SLAVE_WRITE_REQUESTED, );
> + at91_twi_write(dev, AT91_TWI_IER,
> +AT91_TWI_RXRDY | AT91_TWI_EOSACC);
> + }
> + at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_SVACC);
> + }
> +
> + /* byte transmitted to remote master */
> + if (irqstatus & AT91_TWI_TXRDY) {
> + i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED, );
> + writeb_relaxed(value, dev->base + AT91_TWI_THR);
> + }
> +
> + /* byte received from remote master */
> + 

[PATCH RFC 3/4] i2c: at91: added slave mode support

2017-10-27 Thread Juergen Fitschen
Slave mode driver is based on the concept of i2c-designware driver.

Signed-off-by: Juergen Fitschen 
---
 drivers/i2c/busses/Makefile |   3 +
 drivers/i2c/busses/i2c-at91-core.c  |  13 +++-
 drivers/i2c/busses/i2c-at91-slave.c | 147 
 drivers/i2c/busses/i2c-at91.h   |  30 +++-
 4 files changed, 189 insertions(+), 4 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-at91-slave.c

diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 2a79c3d..b38fb8e9 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -34,6 +34,9 @@ obj-$(CONFIG_I2C_ALTERA)  += i2c-altera.o
 obj-$(CONFIG_I2C_ASPEED)   += i2c-aspeed.o
 obj-$(CONFIG_I2C_AT91) += i2c-at91.o
 i2c-at91-objs  := i2c-at91-core.o i2c-at91-master.o
+ifeq ($(CONFIG_I2C_SLAVE),y)
+   i2c-at91-objs   += i2c-at91-slave.o
+endif
 obj-$(CONFIG_I2C_AU1550)   += i2c-au1550.o
 obj-$(CONFIG_I2C_AXXIA)+= i2c-axxia.o
 obj-$(CONFIG_I2C_BCM2835)  += i2c-bcm2835.o
diff --git a/drivers/i2c/busses/i2c-at91-core.c 
b/drivers/i2c/busses/i2c-at91-core.c
index 4fed72d..3d7287c 100644
--- a/drivers/i2c/busses/i2c-at91-core.c
+++ b/drivers/i2c/busses/i2c-at91-core.c
@@ -60,8 +60,10 @@ void at91_init_twi_bus(struct at91_twi_dev *dev)
 {
at91_disable_twi_interrupts(dev);
at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST);
-
-   at91_init_twi_bus_master(dev);
+   if (dev->slave_detected)
+   at91_init_twi_bus_slave(dev);
+   else
+   at91_init_twi_bus_master(dev);
 }
 
 static struct at91_twi_pdata at91rm9200_config = {
@@ -243,7 +245,12 @@ static int at91_twi_probe(struct platform_device *pdev)
dev->adapter.timeout = AT91_I2C_TIMEOUT;
dev->adapter.dev.of_node = pdev->dev.of_node;
 
-   rc = at91_twi_probe_master(pdev, phy_addr, dev);
+   dev->slave_detected = i2c_detect_slave_mode(>dev);
+
+   if (dev->slave_detected)
+   rc = at91_twi_probe_slave(pdev, phy_addr, dev);
+   else
+   rc = at91_twi_probe_master(pdev, phy_addr, dev);
if (rc)
return rc;
 
diff --git a/drivers/i2c/busses/i2c-at91-slave.c 
b/drivers/i2c/busses/i2c-at91-slave.c
new file mode 100644
index 000..4b4808e
--- /dev/null
+++ b/drivers/i2c/busses/i2c-at91-slave.c
@@ -0,0 +1,147 @@
+/*
+ *  i2c slave support for Atmel's AT91 Two-Wire Interface (TWI)
+ *
+ *  Copyright (C) 2017 Juergen Fitschen 
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ */
+
+#include 
+#include 
+#include 
+#include 
+
+#include "i2c-at91.h"
+
+static irqreturn_t atmel_twi_interrupt_slave(int irq, void *dev_id)
+{
+   struct at91_twi_dev *dev = dev_id;
+   const unsigned status = at91_twi_read(dev, AT91_TWI_SR);
+   const unsigned irqstatus = status & at91_twi_read(dev, AT91_TWI_IMR);
+   u8 value;
+
+   if (!irqstatus)
+   return IRQ_NONE;
+
+   /* slave address has been detected on I2C bus */
+   if (irqstatus & AT91_TWI_SVACC) {
+   if (status & AT91_TWI_SVREAD) {
+   i2c_slave_event(dev->slave,
+   I2C_SLAVE_READ_REQUESTED, );
+   writeb_relaxed(value, dev->base + AT91_TWI_THR);
+   at91_twi_write(dev, AT91_TWI_IER,
+  AT91_TWI_TXRDY | AT91_TWI_EOSACC);
+   } else {
+   i2c_slave_event(dev->slave,
+   I2C_SLAVE_WRITE_REQUESTED, );
+   at91_twi_write(dev, AT91_TWI_IER,
+  AT91_TWI_RXRDY | AT91_TWI_EOSACC);
+   }
+   at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_SVACC);
+   }
+
+   /* byte transmitted to remote master */
+   if (irqstatus & AT91_TWI_TXRDY) {
+   i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED, );
+   writeb_relaxed(value, dev->base + AT91_TWI_THR);
+   }
+
+   /* byte received from remote master */
+   if (irqstatus & AT91_TWI_RXRDY) {
+   value = readb_relaxed(dev->base + AT91_TWI_RHR);
+   i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED, );
+   }
+
+   /* master sent stop */
+   if (irqstatus & AT91_TWI_EOSACC) {
+   at91_twi_write(dev, AT91_TWI_IDR,
+  AT91_TWI_TXRDY | AT91_TWI_RXRDY | 
AT91_TWI_EOSACC);
+   at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_SVACC);
+   i2c_slave_event(dev->slave, I2C_SLAVE_STOP, );
+   }
+
+   return IRQ_HANDLED;
+}
+
+static int at91_reg_slave(struct i2c_client *slave)
+{
+ 

[PATCH RFC 3/4] i2c: at91: added slave mode support

2017-10-27 Thread Juergen Fitschen
Slave mode driver is based on the concept of i2c-designware driver.

Signed-off-by: Juergen Fitschen 
---
 drivers/i2c/busses/Makefile |   3 +
 drivers/i2c/busses/i2c-at91-core.c  |  13 +++-
 drivers/i2c/busses/i2c-at91-slave.c | 147 
 drivers/i2c/busses/i2c-at91.h   |  30 +++-
 4 files changed, 189 insertions(+), 4 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-at91-slave.c

diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 2a79c3d..b38fb8e9 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -34,6 +34,9 @@ obj-$(CONFIG_I2C_ALTERA)  += i2c-altera.o
 obj-$(CONFIG_I2C_ASPEED)   += i2c-aspeed.o
 obj-$(CONFIG_I2C_AT91) += i2c-at91.o
 i2c-at91-objs  := i2c-at91-core.o i2c-at91-master.o
+ifeq ($(CONFIG_I2C_SLAVE),y)
+   i2c-at91-objs   += i2c-at91-slave.o
+endif
 obj-$(CONFIG_I2C_AU1550)   += i2c-au1550.o
 obj-$(CONFIG_I2C_AXXIA)+= i2c-axxia.o
 obj-$(CONFIG_I2C_BCM2835)  += i2c-bcm2835.o
diff --git a/drivers/i2c/busses/i2c-at91-core.c 
b/drivers/i2c/busses/i2c-at91-core.c
index 4fed72d..3d7287c 100644
--- a/drivers/i2c/busses/i2c-at91-core.c
+++ b/drivers/i2c/busses/i2c-at91-core.c
@@ -60,8 +60,10 @@ void at91_init_twi_bus(struct at91_twi_dev *dev)
 {
at91_disable_twi_interrupts(dev);
at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST);
-
-   at91_init_twi_bus_master(dev);
+   if (dev->slave_detected)
+   at91_init_twi_bus_slave(dev);
+   else
+   at91_init_twi_bus_master(dev);
 }
 
 static struct at91_twi_pdata at91rm9200_config = {
@@ -243,7 +245,12 @@ static int at91_twi_probe(struct platform_device *pdev)
dev->adapter.timeout = AT91_I2C_TIMEOUT;
dev->adapter.dev.of_node = pdev->dev.of_node;
 
-   rc = at91_twi_probe_master(pdev, phy_addr, dev);
+   dev->slave_detected = i2c_detect_slave_mode(>dev);
+
+   if (dev->slave_detected)
+   rc = at91_twi_probe_slave(pdev, phy_addr, dev);
+   else
+   rc = at91_twi_probe_master(pdev, phy_addr, dev);
if (rc)
return rc;
 
diff --git a/drivers/i2c/busses/i2c-at91-slave.c 
b/drivers/i2c/busses/i2c-at91-slave.c
new file mode 100644
index 000..4b4808e
--- /dev/null
+++ b/drivers/i2c/busses/i2c-at91-slave.c
@@ -0,0 +1,147 @@
+/*
+ *  i2c slave support for Atmel's AT91 Two-Wire Interface (TWI)
+ *
+ *  Copyright (C) 2017 Juergen Fitschen 
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ */
+
+#include 
+#include 
+#include 
+#include 
+
+#include "i2c-at91.h"
+
+static irqreturn_t atmel_twi_interrupt_slave(int irq, void *dev_id)
+{
+   struct at91_twi_dev *dev = dev_id;
+   const unsigned status = at91_twi_read(dev, AT91_TWI_SR);
+   const unsigned irqstatus = status & at91_twi_read(dev, AT91_TWI_IMR);
+   u8 value;
+
+   if (!irqstatus)
+   return IRQ_NONE;
+
+   /* slave address has been detected on I2C bus */
+   if (irqstatus & AT91_TWI_SVACC) {
+   if (status & AT91_TWI_SVREAD) {
+   i2c_slave_event(dev->slave,
+   I2C_SLAVE_READ_REQUESTED, );
+   writeb_relaxed(value, dev->base + AT91_TWI_THR);
+   at91_twi_write(dev, AT91_TWI_IER,
+  AT91_TWI_TXRDY | AT91_TWI_EOSACC);
+   } else {
+   i2c_slave_event(dev->slave,
+   I2C_SLAVE_WRITE_REQUESTED, );
+   at91_twi_write(dev, AT91_TWI_IER,
+  AT91_TWI_RXRDY | AT91_TWI_EOSACC);
+   }
+   at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_SVACC);
+   }
+
+   /* byte transmitted to remote master */
+   if (irqstatus & AT91_TWI_TXRDY) {
+   i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED, );
+   writeb_relaxed(value, dev->base + AT91_TWI_THR);
+   }
+
+   /* byte received from remote master */
+   if (irqstatus & AT91_TWI_RXRDY) {
+   value = readb_relaxed(dev->base + AT91_TWI_RHR);
+   i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED, );
+   }
+
+   /* master sent stop */
+   if (irqstatus & AT91_TWI_EOSACC) {
+   at91_twi_write(dev, AT91_TWI_IDR,
+  AT91_TWI_TXRDY | AT91_TWI_RXRDY | 
AT91_TWI_EOSACC);
+   at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_SVACC);
+   i2c_slave_event(dev->slave, I2C_SLAVE_STOP, );
+   }
+
+   return IRQ_HANDLED;
+}
+
+static int at91_reg_slave(struct i2c_client *slave)
+{
+   struct at91_twi_dev