[PATCH] i2c: imx: add slave support. v2
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
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
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
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
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
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
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
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
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.
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.
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
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->