[PATCH] i2c: imx: add slave support. v2

2016-01-26 Thread Dmitriy Baranov
Add I2C slave provider using the generic slave interface.
It also supports master transactions when the slave in the idle mode.

Issues:
Changes work only in PIO mode (when driver doesn`t use DMA)
It weren`t tested with DMA is enabled (in PIO mode it works well)
There are might be race conditions.

We hope that these changes will be helpfull.
Thank you.

Signed-off-by: Maxim Syrchin 
Signed-off-by: Dmitriy Baranov 
---
 drivers/i2c/busses/Kconfig   |   1 +
 drivers/i2c/busses/i2c-imx.c | 311 ---
 2 files changed, 291 insertions(+), 21 deletions(-)

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 0299dfa..bc7cbfd 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -587,6 +587,7 @@ config I2C_IMG
 config I2C_IMX
tristate "IMX I2C interface"
depends on ARCH_MXC || ARCH_LAYERSCAPE
+   select I2C_SLAVE
help
  Say Y here if you want to use the IIC bus controller on
  the Freescale i.MX/MXC or Layerscape processors.
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index a2b132c..3c286f1 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -53,6 +53,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* This will be the driver name the kernel reports */
 #define DRIVER_NAME "imx-i2c"
@@ -171,6 +172,18 @@ enum imx_i2c_type {
VF610_I2C,
 };
 
+enum imx_i2c_mode {
+   I2C_IMX_SLAVE,
+   I2C_IMX_MASTER,
+   I2C_IMX_UNDEFINED
+};
+
+enum imx_i2c_slave_state {
+   I2C_IMX_SLAVE_IDLE,
+   I2C_IMX_SLAVE_IRQ,
+   I2C_IMX_SLAVE_POLLING
+};
+
 struct imx_i2c_hwdata {
enum imx_i2c_type   devtype;
unsignedregshift;
@@ -193,10 +206,12 @@ struct imx_i2c_dma {
 
 struct imx_i2c_struct {
struct i2c_adapter  adapter;
+   struct i2c_client   *slave;
struct clk  *clk;
void __iomem*base;
wait_queue_head_t   queue;
unsigned long   i2csr;
+   unsigned long   i2csr_slave;
unsigned intdisable_delay;
int stopped;
unsigned intifdr; /* IMX_I2C_IFDR */
@@ -210,6 +225,11 @@ struct imx_i2c_struct {
struct pinctrl_state *pinctrl_pins_gpio;
 
struct imx_i2c_dma  *dma;
+
+   enum imx_i2c_mode   dev_mode;
+   atomic_tslave_state;
+   struct task_struct  *slave_task;
+   wait_queue_head_t   slave_queue;
 };
 
 static const struct imx_i2c_hwdata imx1_i2c_hwdata  = {
@@ -510,39 +530,97 @@ static void i2c_imx_set_clk(struct imx_i2c_struct 
*i2c_imx)
 #endif
 }
 
-static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
+static int i2c_imx_configure_clock(struct imx_i2c_struct *i2c_imx)
 {
-   unsigned int temp = 0;
int result;
 
-   dev_dbg(_imx->adapter.dev, "<%s>\n", __func__);
-
i2c_imx_set_clk(i2c_imx);
 
-   imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR);
-   /* Enable I2C controller */
-   imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, 
IMX_I2C_I2SR);
-   imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx, 
IMX_I2C_I2CR);
+   result = clk_prepare_enable(i2c_imx->clk);
+   if (result == 0)
+   imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR);
+
+   return result;
+}
+
+static void i2c_imx_enable_i2c_controller(struct imx_i2c_struct *i2c_imx)
+{
+   imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx,
+   IMX_I2C_I2SR);
+   imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx,
+   IMX_I2C_I2CR);
 
/* Wait controller to be stable */
udelay(50);
+}
+
+static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
+{
+   unsigned int temp = 0;
+   int result;
+
+   i2c_imx->dev_mode = I2C_IMX_UNDEFINED;
+
+   dev_dbg(_imx->adapter.dev, "<%s>\n", __func__);
+
+   result = i2c_imx_configure_clock(i2c_imx);
+   if (result != 0)
+   return result;
+
+   i2c_imx_enable_i2c_controller(i2c_imx);
 
/* Start I2C transaction */
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp |= I2CR_MSTA;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+
result = i2c_imx_bus_busy(i2c_imx, 1);
if (result)
return result;
i2c_imx->stopped = 0;
 
+   i2c_imx->dev_mode = I2C_IMX_MASTER;
+
temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
temp &= ~I2CR_DMAEN;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
return result;
 }
 
-static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
+static int i2c_imx_start_slave_mode(struct imx_i2c_struct *i2c_imx, bool 
enable)
+{
+   unsigned int temp;
+

Re: [PATCH] i2c: imx: add slave support

2016-01-26 Thread Dmitriy Baranov

Vladimir,

Thanks for the comment.
We are both the authors of this patch.


Could you please squash the changes (care about indentation in Kconfig also)
and resend it as v2 (probably you may want to wait for review comments some
more time)?
I suppose that after review, there will be many other things to fix in 
this patch.

Thus, if you don`t mind, we wont send fixed version for now.




On 26.01.2016 16:37, Vladimir Zapolskiy wrote:

On 26.01.2016 11:54, Dmitriy Baranov wrote:

Sorry, we should have added selecting this in our patch.
The following fixes it:

Subject: [PATCH] Select I2C_SLAVE for i2c-imx driver because it uses the
generic slave interface.

Signed-off-by: Dmitriy Baranov 
Signed-off-by: Maxim Syrchin 
---
   drivers/i2c/busses/Kconfig | 1 +
   1 file changed, 1 insertion(+)

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 0299dfa..bc7cbfd 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -587,6 +587,7 @@ config I2C_IMG
   config I2C_IMX
   tristate "IMX I2C interface"
   depends on ARCH_MXC || ARCH_LAYERSCAPE
+select I2C_SLAVE
   help
 Say Y here if you want to use the IIC bus controller on
 the Freescale i.MX/MXC or Layerscape processors.


Could you please squash the changes (care about indentation in Kconfig also)
and resend it as v2 (probably you may want to wait for review comments some
more time)?

Two more formal questions, why patch submitter's Signed-off-by: is not the
last in the list and why Maxim has Signed-off-by tag here? Who is the author
of the change?

See Documentation/SubmittingPatches "Sign your work" for details.

Best wishes,
Vladimir




Re: [PATCH] i2c: imx: add slave support

2016-01-26 Thread Dmitriy Baranov

Sorry, we should have added selecting this in our patch.
The following fixes it:

Subject: [PATCH] Select I2C_SLAVE for i2c-imx driver because it uses the 
generic slave interface.


Signed-off-by: Dmitriy Baranov 
Signed-off-by: Maxim Syrchin 
---
 drivers/i2c/busses/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 0299dfa..bc7cbfd 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -587,6 +587,7 @@ config I2C_IMG
 config I2C_IMX
 tristate "IMX I2C interface"
 depends on ARCH_MXC || ARCH_LAYERSCAPE
+select I2C_SLAVE
 help
   Say Y here if you want to use the IIC bus controller on
   the Freescale i.MX/MXC or Layerscape processors.
--
2.5.0




On 26.01.2016 11:36, Wolfram Sang wrote:

On Tue, Jan 26, 2016 at 11:22:24AM +0300, Dmitriy Baranov wrote:

Thank you for testing our patch.

Due to using the generic slave interface, It should be enabled in the config
file.
Please add the following in the config file:
CONFIG_I2C_SLAVE=y

For now, you need to select it to make randconfigs built.





Re: [PATCH] i2c: imx: add slave support

2016-01-26 Thread Dmitriy Baranov

Thank you for testing our patch.

Due to using the generic slave interface, It should be enabled in the 
config file.

Please add the following in the config file:
CONFIG_I2C_SLAVE=y



On 25.01.2016 21:09, kbuild test robot wrote:

Hi Dmitriy,

[auto build test ERROR on wsa/i2c/for-next]
[also build test ERROR on v4.5-rc1 next-20160125]
[if your patch is applied to the wrong git tree, please drop us a note to help 
improving the system]

url:
https://github.com/0day-ci/linux/commits/Dmitriy-Baranov/i2c-imx-add-slave-support/20160125-225538
base:   https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux i2c/for-next
config: arm-imx_v6_v7_defconfig (attached as .config)
reproduce:
 wget 
https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross
 -O ~/bin/make.cross
 chmod +x ~/bin/make.cross
 # save the attached .config to linux build tree
 make.cross ARCH=arm

All error/warnings (new ones prefixed by >>):

drivers/i2c/busses/i2c-imx.c: In function 'i2c_imx_slave_threadfn':

drivers/i2c/busses/i2c-imx.c:696:6: error: implicit declaration of function 
'i2c_slave_event' [-Werror=implicit-function-declaration]

  i2c_slave_event(i2c_imx->slave,
  ^

drivers/i2c/busses/i2c-imx.c:697:7: error: 'I2C_SLAVE_READ_REQUESTED' 
undeclared (first use in this function)

   I2C_SLAVE_READ_REQUESTED, );
   ^
drivers/i2c/busses/i2c-imx.c:697:7: note: each undeclared identifier is 
reported only once for each function it appears in

drivers/i2c/busses/i2c-imx.c:706:7: error: 'I2C_SLAVE_WRITE_REQUESTED' 
undeclared (first use in this function)

   I2C_SLAVE_WRITE_REQUESTED, );
   ^

drivers/i2c/busses/i2c-imx.c:719:8: error: 'I2C_SLAVE_READ_PROCESSED' 
undeclared (first use in this function)

I2C_SLAVE_READ_PROCESSED, );
^

drivers/i2c/busses/i2c-imx.c:744:7: error: 'I2C_SLAVE_WRITE_RECEIVED' 
undeclared (first use in this function)

   I2C_SLAVE_WRITE_RECEIVED, );
   ^

drivers/i2c/busses/i2c-imx.c:755:37: error: 'I2C_SLAVE_STOP' undeclared (first 
use in this function)

 i2c_slave_event(i2c_imx->slave, I2C_SLAVE_STOP, );
 ^
drivers/i2c/busses/i2c-imx.c: At top level:

drivers/i2c/busses/i2c-imx.c:1283:2: error: unknown field 'reg_slave' specified 
in initializer

  .reg_slave = i2c_imx_reg_slave,
  ^

drivers/i2c/busses/i2c-imx.c:1283:2: warning: excess elements in struct 
initializer

drivers/i2c/busses/i2c-imx.c:1283:2: warning: (near initialization for 
'i2c_imx_algo')

drivers/i2c/busses/i2c-imx.c:1284:2: error: unknown field 'unreg_slave' 
specified in initializer

  .unreg_slave = i2c_imx_unreg_slave,
  ^
drivers/i2c/busses/i2c-imx.c:1284:2: warning: excess elements in struct 
initializer
drivers/i2c/busses/i2c-imx.c:1284:2: warning: (near initialization for 
'i2c_imx_algo')
cc1: some warnings being treated as errors

vim +/i2c_slave_event +696 drivers/i2c/busses/i2c-imx.c

690 status = imx_i2c_read_reg(i2c_imx, 
IMX_I2C_I2SR);
691 ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
692 
693 if (status & I2SR_IAAS) {
694 if (status & I2SR_SRW) {
695 /* master wants to read from us 
*/
  > 696  
i2c_slave_event(i2c_imx->slave,
  > 697  
I2C_SLAVE_READ_REQUESTED, );
698 ctl |= I2CR_MTX;
699 imx_i2c_write_reg(ctl, i2c_imx, 
IMX_I2C_I2CR);
700 
701 /*send data */
702 imx_i2c_write_reg(data, 
i2c_imx, IMX_I2C_I2DR);
703 } else {
704 dev_dbg(_imx->adapter.dev, 
"write requested");
705 i2c_slave_event(i2c_imx->slave,
  > 706  
I2C_SLAVE_WRITE_REQUESTED, );
707 /*slave receive */
708 ctl &= ~I2CR_MTX;
709 imx_i2c_write_reg(ctl, i2c_imx, 
IMX_I2C_I2CR);
710 
711 /*dummy read */
712 data = 
imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
713 }
714 } else {
715 /* slave send */
716 if (ctl & I2CR_MTX) {
717 if (!(

Re: [PATCH] i2c: imx: add slave support

2016-01-26 Thread Dmitriy Baranov

Sorry, we should have added selecting this in our patch.
The following fixes it:

Subject: [PATCH] Select I2C_SLAVE for i2c-imx driver because it uses the 
generic slave interface.


Signed-off-by: Dmitriy Baranov <dbara...@dev.rtsoft.ru>
Signed-off-by: Maxim Syrchin <syrc...@dev.rtsoft.ru>
---
 drivers/i2c/busses/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 0299dfa..bc7cbfd 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -587,6 +587,7 @@ config I2C_IMG
 config I2C_IMX
 tristate "IMX I2C interface"
 depends on ARCH_MXC || ARCH_LAYERSCAPE
+select I2C_SLAVE
 help
   Say Y here if you want to use the IIC bus controller on
   the Freescale i.MX/MXC or Layerscape processors.
--
2.5.0




On 26.01.2016 11:36, Wolfram Sang wrote:

On Tue, Jan 26, 2016 at 11:22:24AM +0300, Dmitriy Baranov wrote:

Thank you for testing our patch.

Due to using the generic slave interface, It should be enabled in the config
file.
Please add the following in the config file:
CONFIG_I2C_SLAVE=y

For now, you need to select it to make randconfigs built.





Re: [PATCH] i2c: imx: add slave support

2016-01-26 Thread Dmitriy Baranov

Thank you for testing our patch.

Due to using the generic slave interface, It should be enabled in the 
config file.

Please add the following in the config file:
CONFIG_I2C_SLAVE=y



On 25.01.2016 21:09, kbuild test robot wrote:

Hi Dmitriy,

[auto build test ERROR on wsa/i2c/for-next]
[also build test ERROR on v4.5-rc1 next-20160125]
[if your patch is applied to the wrong git tree, please drop us a note to help 
improving the system]

url:
https://github.com/0day-ci/linux/commits/Dmitriy-Baranov/i2c-imx-add-slave-support/20160125-225538
base:   https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux i2c/for-next
config: arm-imx_v6_v7_defconfig (attached as .config)
reproduce:
 wget 
https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross
 -O ~/bin/make.cross
 chmod +x ~/bin/make.cross
 # save the attached .config to linux build tree
 make.cross ARCH=arm

All error/warnings (new ones prefixed by >>):

drivers/i2c/busses/i2c-imx.c: In function 'i2c_imx_slave_threadfn':

drivers/i2c/busses/i2c-imx.c:696:6: error: implicit declaration of function 
'i2c_slave_event' [-Werror=implicit-function-declaration]

  i2c_slave_event(i2c_imx->slave,
  ^

drivers/i2c/busses/i2c-imx.c:697:7: error: 'I2C_SLAVE_READ_REQUESTED' 
undeclared (first use in this function)

   I2C_SLAVE_READ_REQUESTED, );
   ^
drivers/i2c/busses/i2c-imx.c:697:7: note: each undeclared identifier is 
reported only once for each function it appears in

drivers/i2c/busses/i2c-imx.c:706:7: error: 'I2C_SLAVE_WRITE_REQUESTED' 
undeclared (first use in this function)

   I2C_SLAVE_WRITE_REQUESTED, );
   ^

drivers/i2c/busses/i2c-imx.c:719:8: error: 'I2C_SLAVE_READ_PROCESSED' 
undeclared (first use in this function)

I2C_SLAVE_READ_PROCESSED, );
^

drivers/i2c/busses/i2c-imx.c:744:7: error: 'I2C_SLAVE_WRITE_RECEIVED' 
undeclared (first use in this function)

   I2C_SLAVE_WRITE_RECEIVED, );
   ^

drivers/i2c/busses/i2c-imx.c:755:37: error: 'I2C_SLAVE_STOP' undeclared (first 
use in this function)

 i2c_slave_event(i2c_imx->slave, I2C_SLAVE_STOP, );
 ^
drivers/i2c/busses/i2c-imx.c: At top level:

drivers/i2c/busses/i2c-imx.c:1283:2: error: unknown field 'reg_slave' specified 
in initializer

  .reg_slave = i2c_imx_reg_slave,
  ^

drivers/i2c/busses/i2c-imx.c:1283:2: warning: excess elements in struct 
initializer

drivers/i2c/busses/i2c-imx.c:1283:2: warning: (near initialization for 
'i2c_imx_algo')

drivers/i2c/busses/i2c-imx.c:1284:2: error: unknown field 'unreg_slave' 
specified in initializer

  .unreg_slave = i2c_imx_unreg_slave,
  ^
drivers/i2c/busses/i2c-imx.c:1284:2: warning: excess elements in struct 
initializer
drivers/i2c/busses/i2c-imx.c:1284:2: warning: (near initialization for 
'i2c_imx_algo')
cc1: some warnings being treated as errors

vim +/i2c_slave_event +696 drivers/i2c/busses/i2c-imx.c

690 status = imx_i2c_read_reg(i2c_imx, 
IMX_I2C_I2SR);
691 ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
692 
693 if (status & I2SR_IAAS) {
694 if (status & I2SR_SRW) {
695 /* master wants to read from us 
*/
  > 696  
i2c_slave_event(i2c_imx->slave,
  > 697  
I2C_SLAVE_READ_REQUESTED, );
698 ctl |= I2CR_MTX;
699 imx_i2c_write_reg(ctl, i2c_imx, 
IMX_I2C_I2CR);
700 
701 /*send data */
702 imx_i2c_write_reg(data, 
i2c_imx, IMX_I2C_I2DR);
703 } else {
704 dev_dbg(_imx->adapter.dev, 
"write requested");
705 i2c_slave_event(i2c_imx->slave,
  > 706  
I2C_SLAVE_WRITE_REQUESTED, );
707 /*slave receive */
708 ctl &= ~I2CR_MTX;
709 imx_i2c_write_reg(ctl, i2c_imx, 
IMX_I2C_I2CR);
710 
711 /*dummy read */
712 data = 
imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
713 }
714 } else {
715 /* slave send */
716 if (ctl & I2CR_MTX) {
717 if (!(

Re: [PATCH] i2c: imx: add slave support

2016-01-26 Thread Dmitriy Baranov

Vladimir,

Thanks for the comment.
We are both the authors of this patch.


Could you please squash the changes (care about indentation in Kconfig also)
and resend it as v2 (probably you may want to wait for review comments some
more time)?
I suppose that after review, there will be many other things to fix in 
this patch.

Thus, if you don`t mind, we wont send fixed version for now.




On 26.01.2016 16:37, Vladimir Zapolskiy wrote:

On 26.01.2016 11:54, Dmitriy Baranov wrote:

Sorry, we should have added selecting this in our patch.
The following fixes it:

Subject: [PATCH] Select I2C_SLAVE for i2c-imx driver because it uses the
generic slave interface.

Signed-off-by: Dmitriy Baranov <dbara...@dev.rtsoft.ru>
Signed-off-by: Maxim Syrchin <syrc...@dev.rtsoft.ru>
---
   drivers/i2c/busses/Kconfig | 1 +
   1 file changed, 1 insertion(+)

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 0299dfa..bc7cbfd 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -587,6 +587,7 @@ config I2C_IMG
   config I2C_IMX
   tristate "IMX I2C interface"
   depends on ARCH_MXC || ARCH_LAYERSCAPE
+select I2C_SLAVE
   help
 Say Y here if you want to use the IIC bus controller on
 the Freescale i.MX/MXC or Layerscape processors.


Could you please squash the changes (care about indentation in Kconfig also)
and resend it as v2 (probably you may want to wait for review comments some
more time)?

Two more formal questions, why patch submitter's Signed-off-by: is not the
last in the list and why Maxim has Signed-off-by tag here? Who is the author
of the change?

See Documentation/SubmittingPatches "Sign your work" for details.

Best wishes,
Vladimir




[PATCH] i2c: imx: add slave support. v2

2016-01-26 Thread Dmitriy Baranov
Add I2C slave provider using the generic slave interface.
It also supports master transactions when the slave in the idle mode.

Issues:
Changes work only in PIO mode (when driver doesn`t use DMA)
It weren`t tested with DMA is enabled (in PIO mode it works well)
There are might be race conditions.

We hope that these changes will be helpfull.
Thank you.

Signed-off-by: Maxim Syrchin <syrc...@dev.rtsoft.ru>
Signed-off-by: Dmitriy Baranov <dbara...@dev.rtsoft.ru>
---
 drivers/i2c/busses/Kconfig   |   1 +
 drivers/i2c/busses/i2c-imx.c | 311 ---
 2 files changed, 291 insertions(+), 21 deletions(-)

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 0299dfa..bc7cbfd 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -587,6 +587,7 @@ config I2C_IMG
 config I2C_IMX
tristate "IMX I2C interface"
depends on ARCH_MXC || ARCH_LAYERSCAPE
+   select I2C_SLAVE
help
  Say Y here if you want to use the IIC bus controller on
  the Freescale i.MX/MXC or Layerscape processors.
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index a2b132c..3c286f1 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -53,6 +53,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* This will be the driver name the kernel reports */
 #define DRIVER_NAME "imx-i2c"
@@ -171,6 +172,18 @@ enum imx_i2c_type {
VF610_I2C,
 };
 
+enum imx_i2c_mode {
+   I2C_IMX_SLAVE,
+   I2C_IMX_MASTER,
+   I2C_IMX_UNDEFINED
+};
+
+enum imx_i2c_slave_state {
+   I2C_IMX_SLAVE_IDLE,
+   I2C_IMX_SLAVE_IRQ,
+   I2C_IMX_SLAVE_POLLING
+};
+
 struct imx_i2c_hwdata {
enum imx_i2c_type   devtype;
unsignedregshift;
@@ -193,10 +206,12 @@ struct imx_i2c_dma {
 
 struct imx_i2c_struct {
struct i2c_adapter  adapter;
+   struct i2c_client   *slave;
struct clk  *clk;
void __iomem*base;
wait_queue_head_t   queue;
unsigned long   i2csr;
+   unsigned long   i2csr_slave;
unsigned intdisable_delay;
int stopped;
unsigned intifdr; /* IMX_I2C_IFDR */
@@ -210,6 +225,11 @@ struct imx_i2c_struct {
struct pinctrl_state *pinctrl_pins_gpio;
 
struct imx_i2c_dma  *dma;
+
+   enum imx_i2c_mode   dev_mode;
+   atomic_tslave_state;
+   struct task_struct  *slave_task;
+   wait_queue_head_t   slave_queue;
 };
 
 static const struct imx_i2c_hwdata imx1_i2c_hwdata  = {
@@ -510,39 +530,97 @@ static void i2c_imx_set_clk(struct imx_i2c_struct 
*i2c_imx)
 #endif
 }
 
-static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
+static int i2c_imx_configure_clock(struct imx_i2c_struct *i2c_imx)
 {
-   unsigned int temp = 0;
int result;
 
-   dev_dbg(_imx->adapter.dev, "<%s>\n", __func__);
-
i2c_imx_set_clk(i2c_imx);
 
-   imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR);
-   /* Enable I2C controller */
-   imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, 
IMX_I2C_I2SR);
-   imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx, 
IMX_I2C_I2CR);
+   result = clk_prepare_enable(i2c_imx->clk);
+   if (result == 0)
+   imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR);
+
+   return result;
+}
+
+static void i2c_imx_enable_i2c_controller(struct imx_i2c_struct *i2c_imx)
+{
+   imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx,
+   IMX_I2C_I2SR);
+   imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx,
+   IMX_I2C_I2CR);
 
/* Wait controller to be stable */
udelay(50);
+}
+
+static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
+{
+   unsigned int temp = 0;
+   int result;
+
+   i2c_imx->dev_mode = I2C_IMX_UNDEFINED;
+
+   dev_dbg(_imx->adapter.dev, "<%s>\n", __func__);
+
+   result = i2c_imx_configure_clock(i2c_imx);
+   if (result != 0)
+   return result;
+
+   i2c_imx_enable_i2c_controller(i2c_imx);
 
/* Start I2C transaction */
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp |= I2CR_MSTA;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+
result = i2c_imx_bus_busy(i2c_imx, 1);
if (result)
return result;
i2c_imx->stopped = 0;
 
+   i2c_imx->dev_mode = I2C_IMX_MASTER;
+
temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
temp &= ~I2CR_DMAEN;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
return result;
 }
 
-static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
+static int i2c_imx_start_slave_mode(struct imx_i2c_struct *i

[PATCH] i2c: imx: add slave support

2016-01-25 Thread Dmitriy Baranov
Add I2C slave provider using the generic slave interface.
It also supports master transactions when the slave in the idle mode.
Changes work only in PIO mode (when driver doesn`t use DMA)
These changes weren`t tested with DMA is enabled.

Signed-off-by: Dmitriy Baranov 
Signed-off-by: Maxim Syrchin 
---
 drivers/i2c/busses/i2c-imx.c | 311 ---
 1 file changed, 290 insertions(+), 21 deletions(-)

diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index a2b132c..3c286f1 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -53,6 +53,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* This will be the driver name the kernel reports */
 #define DRIVER_NAME "imx-i2c"
@@ -171,6 +172,18 @@ enum imx_i2c_type {
VF610_I2C,
 };
 
+enum imx_i2c_mode {
+   I2C_IMX_SLAVE,
+   I2C_IMX_MASTER,
+   I2C_IMX_UNDEFINED
+};
+
+enum imx_i2c_slave_state {
+   I2C_IMX_SLAVE_IDLE,
+   I2C_IMX_SLAVE_IRQ,
+   I2C_IMX_SLAVE_POLLING
+};
+
 struct imx_i2c_hwdata {
enum imx_i2c_type   devtype;
unsignedregshift;
@@ -193,10 +206,12 @@ struct imx_i2c_dma {
 
 struct imx_i2c_struct {
struct i2c_adapter  adapter;
+   struct i2c_client   *slave;
struct clk  *clk;
void __iomem*base;
wait_queue_head_t   queue;
unsigned long   i2csr;
+   unsigned long   i2csr_slave;
unsigned intdisable_delay;
int stopped;
unsigned intifdr; /* IMX_I2C_IFDR */
@@ -210,6 +225,11 @@ struct imx_i2c_struct {
struct pinctrl_state *pinctrl_pins_gpio;
 
struct imx_i2c_dma  *dma;
+
+   enum imx_i2c_mode   dev_mode;
+   atomic_tslave_state;
+   struct task_struct  *slave_task;
+   wait_queue_head_t   slave_queue;
 };
 
 static const struct imx_i2c_hwdata imx1_i2c_hwdata  = {
@@ -510,39 +530,97 @@ static void i2c_imx_set_clk(struct imx_i2c_struct 
*i2c_imx)
 #endif
 }
 
-static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
+static int i2c_imx_configure_clock(struct imx_i2c_struct *i2c_imx)
 {
-   unsigned int temp = 0;
int result;
 
-   dev_dbg(_imx->adapter.dev, "<%s>\n", __func__);
-
i2c_imx_set_clk(i2c_imx);
 
-   imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR);
-   /* Enable I2C controller */
-   imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, 
IMX_I2C_I2SR);
-   imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx, 
IMX_I2C_I2CR);
+   result = clk_prepare_enable(i2c_imx->clk);
+   if (result == 0)
+   imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR);
+
+   return result;
+}
+
+static void i2c_imx_enable_i2c_controller(struct imx_i2c_struct *i2c_imx)
+{
+   imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx,
+   IMX_I2C_I2SR);
+   imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx,
+   IMX_I2C_I2CR);
 
/* Wait controller to be stable */
udelay(50);
+}
+
+static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
+{
+   unsigned int temp = 0;
+   int result;
+
+   i2c_imx->dev_mode = I2C_IMX_UNDEFINED;
+
+   dev_dbg(_imx->adapter.dev, "<%s>\n", __func__);
+
+   result = i2c_imx_configure_clock(i2c_imx);
+   if (result != 0)
+   return result;
+
+   i2c_imx_enable_i2c_controller(i2c_imx);
 
/* Start I2C transaction */
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp |= I2CR_MSTA;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+
result = i2c_imx_bus_busy(i2c_imx, 1);
if (result)
return result;
i2c_imx->stopped = 0;
 
+   i2c_imx->dev_mode = I2C_IMX_MASTER;
+
temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
temp &= ~I2CR_DMAEN;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
return result;
 }
 
-static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
+static int i2c_imx_start_slave_mode(struct imx_i2c_struct *i2c_imx, bool 
enable)
+{
+   unsigned int temp;
+   int result;
+
+   dev_dbg(_imx->adapter.dev, "<%s>\n", __func__);
+
+   i2c_imx->dev_mode = I2C_IMX_UNDEFINED;
+
+   if (enable) {
+   result = i2c_imx_configure_clock(i2c_imx);
+   if (result != 0)
+   return result;
+   }
+
+   /* Set the Slave bit */
+   temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+   temp &= ~I2CR_MSTA;
+   imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+
+   /* Set the Slave address */
+   imx_i2c_write_reg((i2c_imx->slave->addr << 1), i2c_imx, IMX_I2C_IADR);
+
+   

[PATCH] Remove extra spaces.

2016-01-25 Thread Dmitriy Baranov
Signed-off-by: Dmitriy Baranov 
---
 drivers/i2c/busses/i2c-imx.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index a2b132c..1ca7ef2 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -212,7 +212,7 @@ struct imx_i2c_struct {
struct imx_i2c_dma  *dma;
 };
 
-static const struct imx_i2c_hwdata imx1_i2c_hwdata  = {
+static const struct imx_i2c_hwdata imx1_i2c_hwdata = {
.devtype= IMX1_I2C,
.regshift   = IMX_I2C_REGSHIFT,
.clk_div= imx_i2c_clk_div,
@@ -222,7 +222,7 @@ static const struct imx_i2c_hwdata imx1_i2c_hwdata  = {
 
 };
 
-static const struct imx_i2c_hwdata imx21_i2c_hwdata  = {
+static const struct imx_i2c_hwdata imx21_i2c_hwdata = {
.devtype= IMX21_I2C,
.regshift   = IMX_I2C_REGSHIFT,
.clk_div= imx_i2c_clk_div,
@@ -871,7 +871,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, 
struct i2c_msg *msgs, bo
if ((!i) && block_data)
msgs->buf[0] = len;
else
-   msgs->buf[i] =  imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+   msgs->buf[i] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
dev_dbg(_imx->adapter.dev,
"<%s> read byte: B%d=0x%X\n",
__func__, i, msgs->buf[i]);
@@ -916,7 +916,7 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp |= I2CR_RSTA;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
-   result =  i2c_imx_bus_busy(i2c_imx, 1);
+   result = i2c_imx_bus_busy(i2c_imx, 1);
if (result)
goto fail0;
}
@@ -1192,7 +1192,7 @@ static int i2c_imx_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int i2c_imx_runtime_suspend(struct device *dev)
 {
-   struct imx_i2c_struct *i2c_imx  = dev_get_drvdata(dev);
+   struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
 
clk_disable_unprepare(i2c_imx->clk);
 
@@ -1201,7 +1201,7 @@ static int i2c_imx_runtime_suspend(struct device *dev)
 
 static int i2c_imx_runtime_resume(struct device *dev)
 {
-   struct imx_i2c_struct *i2c_imx  = dev_get_drvdata(dev);
+   struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
int ret;
 
ret = clk_prepare_enable(i2c_imx->clk);
-- 
2.5.0



[PATCH] Remove extra spaces.

2016-01-25 Thread Dmitriy Baranov
Signed-off-by: Dmitriy Baranov <dbara...@dev.rtsoft.ru>
---
 drivers/i2c/busses/i2c-imx.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index a2b132c..1ca7ef2 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -212,7 +212,7 @@ struct imx_i2c_struct {
struct imx_i2c_dma  *dma;
 };
 
-static const struct imx_i2c_hwdata imx1_i2c_hwdata  = {
+static const struct imx_i2c_hwdata imx1_i2c_hwdata = {
.devtype= IMX1_I2C,
.regshift   = IMX_I2C_REGSHIFT,
.clk_div= imx_i2c_clk_div,
@@ -222,7 +222,7 @@ static const struct imx_i2c_hwdata imx1_i2c_hwdata  = {
 
 };
 
-static const struct imx_i2c_hwdata imx21_i2c_hwdata  = {
+static const struct imx_i2c_hwdata imx21_i2c_hwdata = {
.devtype= IMX21_I2C,
.regshift   = IMX_I2C_REGSHIFT,
.clk_div= imx_i2c_clk_div,
@@ -871,7 +871,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, 
struct i2c_msg *msgs, bo
if ((!i) && block_data)
msgs->buf[0] = len;
else
-   msgs->buf[i] =  imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+   msgs->buf[i] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
dev_dbg(_imx->adapter.dev,
"<%s> read byte: B%d=0x%X\n",
__func__, i, msgs->buf[i]);
@@ -916,7 +916,7 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp |= I2CR_RSTA;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
-   result =  i2c_imx_bus_busy(i2c_imx, 1);
+   result = i2c_imx_bus_busy(i2c_imx, 1);
if (result)
goto fail0;
}
@@ -1192,7 +1192,7 @@ static int i2c_imx_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int i2c_imx_runtime_suspend(struct device *dev)
 {
-   struct imx_i2c_struct *i2c_imx  = dev_get_drvdata(dev);
+   struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
 
clk_disable_unprepare(i2c_imx->clk);
 
@@ -1201,7 +1201,7 @@ static int i2c_imx_runtime_suspend(struct device *dev)
 
 static int i2c_imx_runtime_resume(struct device *dev)
 {
-   struct imx_i2c_struct *i2c_imx  = dev_get_drvdata(dev);
+   struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
int ret;
 
ret = clk_prepare_enable(i2c_imx->clk);
-- 
2.5.0



[PATCH] i2c: imx: add slave support

2016-01-25 Thread Dmitriy Baranov
Add I2C slave provider using the generic slave interface.
It also supports master transactions when the slave in the idle mode.
Changes work only in PIO mode (when driver doesn`t use DMA)
These changes weren`t tested with DMA is enabled.

Signed-off-by: Dmitriy Baranov <dbara...@dev.rtsoft.ru>
Signed-off-by: Maxim Syrchin <syrc...@dev.rtsoft.ru>
---
 drivers/i2c/busses/i2c-imx.c | 311 ---
 1 file changed, 290 insertions(+), 21 deletions(-)

diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index a2b132c..3c286f1 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -53,6 +53,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* This will be the driver name the kernel reports */
 #define DRIVER_NAME "imx-i2c"
@@ -171,6 +172,18 @@ enum imx_i2c_type {
VF610_I2C,
 };
 
+enum imx_i2c_mode {
+   I2C_IMX_SLAVE,
+   I2C_IMX_MASTER,
+   I2C_IMX_UNDEFINED
+};
+
+enum imx_i2c_slave_state {
+   I2C_IMX_SLAVE_IDLE,
+   I2C_IMX_SLAVE_IRQ,
+   I2C_IMX_SLAVE_POLLING
+};
+
 struct imx_i2c_hwdata {
enum imx_i2c_type   devtype;
unsignedregshift;
@@ -193,10 +206,12 @@ struct imx_i2c_dma {
 
 struct imx_i2c_struct {
struct i2c_adapter  adapter;
+   struct i2c_client   *slave;
struct clk  *clk;
void __iomem*base;
wait_queue_head_t   queue;
unsigned long   i2csr;
+   unsigned long   i2csr_slave;
unsigned intdisable_delay;
int stopped;
unsigned intifdr; /* IMX_I2C_IFDR */
@@ -210,6 +225,11 @@ struct imx_i2c_struct {
struct pinctrl_state *pinctrl_pins_gpio;
 
struct imx_i2c_dma  *dma;
+
+   enum imx_i2c_mode   dev_mode;
+   atomic_tslave_state;
+   struct task_struct  *slave_task;
+   wait_queue_head_t   slave_queue;
 };
 
 static const struct imx_i2c_hwdata imx1_i2c_hwdata  = {
@@ -510,39 +530,97 @@ static void i2c_imx_set_clk(struct imx_i2c_struct 
*i2c_imx)
 #endif
 }
 
-static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
+static int i2c_imx_configure_clock(struct imx_i2c_struct *i2c_imx)
 {
-   unsigned int temp = 0;
int result;
 
-   dev_dbg(_imx->adapter.dev, "<%s>\n", __func__);
-
i2c_imx_set_clk(i2c_imx);
 
-   imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR);
-   /* Enable I2C controller */
-   imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, 
IMX_I2C_I2SR);
-   imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx, 
IMX_I2C_I2CR);
+   result = clk_prepare_enable(i2c_imx->clk);
+   if (result == 0)
+   imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR);
+
+   return result;
+}
+
+static void i2c_imx_enable_i2c_controller(struct imx_i2c_struct *i2c_imx)
+{
+   imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx,
+   IMX_I2C_I2SR);
+   imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx,
+   IMX_I2C_I2CR);
 
/* Wait controller to be stable */
udelay(50);
+}
+
+static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
+{
+   unsigned int temp = 0;
+   int result;
+
+   i2c_imx->dev_mode = I2C_IMX_UNDEFINED;
+
+   dev_dbg(_imx->adapter.dev, "<%s>\n", __func__);
+
+   result = i2c_imx_configure_clock(i2c_imx);
+   if (result != 0)
+   return result;
+
+   i2c_imx_enable_i2c_controller(i2c_imx);
 
/* Start I2C transaction */
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp |= I2CR_MSTA;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+
result = i2c_imx_bus_busy(i2c_imx, 1);
if (result)
return result;
i2c_imx->stopped = 0;
 
+   i2c_imx->dev_mode = I2C_IMX_MASTER;
+
temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
temp &= ~I2CR_DMAEN;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
return result;
 }
 
-static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
+static int i2c_imx_start_slave_mode(struct imx_i2c_struct *i2c_imx, bool 
enable)
+{
+   unsigned int temp;
+   int result;
+
+   dev_dbg(_imx->adapter.dev, "<%s>\n", __func__);
+
+   i2c_imx->dev_mode = I2C_IMX_UNDEFINED;
+
+   if (enable) {
+   result = i2c_imx_configure_clock(i2c_imx);
+   if (result != 0)
+   return result;
+   }
+
+   /* Set the Slave bit */
+   temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+   temp &= ~I2CR_MSTA;
+   imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+
+   /* Set the Slave address */
+   imx_i2c_write_reg((i2c_imx->