diff options
Diffstat (limited to 'target/linux/layerscape/patches-5.4/808-i2c-0011-i2c-imx-support-slave-mode-for-imx-I2C-driver.patch')
-rw-r--r-- | target/linux/layerscape/patches-5.4/808-i2c-0011-i2c-imx-support-slave-mode-for-imx-I2C-driver.patch | 282 |
1 files changed, 0 insertions, 282 deletions
diff --git a/target/linux/layerscape/patches-5.4/808-i2c-0011-i2c-imx-support-slave-mode-for-imx-I2C-driver.patch b/target/linux/layerscape/patches-5.4/808-i2c-0011-i2c-imx-support-slave-mode-for-imx-I2C-driver.patch deleted file mode 100644 index 5377d05d0c..0000000000 --- a/target/linux/layerscape/patches-5.4/808-i2c-0011-i2c-imx-support-slave-mode-for-imx-I2C-driver.patch +++ /dev/null @@ -1,282 +0,0 @@ -From 865433df5d11aef7cfe5d51b362b6276bddb7a15 Mon Sep 17 00:00:00 2001 -From: Biwen Li <biwen.li@nxp.com> -Date: Fri, 2 Aug 2019 17:45:56 +0800 -Subject: [PATCH] i2c: imx: support slave mode for imx I2C driver - -The patch supports slave mode for imx I2C driver - -Reviewed-by: Clark Wang <xiaoning.wang@nxp.com> -Signed-off-by: Biwen Li <biwen.li@nxp.com> ---- - drivers/i2c/busses/i2c-imx.c | 219 +++++++++++++++++++++++++++++++++++++++---- - 1 file changed, 201 insertions(+), 18 deletions(-) - ---- a/drivers/i2c/busses/i2c-imx.c -+++ b/drivers/i2c/busses/i2c-imx.c -@@ -265,6 +265,9 @@ struct imx_i2c_struct { - int pmuxcr_set; - int pmuxcr_endian; - void __iomem *pmuxcr_addr; -+#if IS_ENABLED(CONFIG_I2C_SLAVE) -+ struct i2c_client *slave; -+#endif - }; - - static const struct imx_i2c_hwdata imx1_i2c_hwdata = { -@@ -357,6 +360,14 @@ static inline unsigned char imx_i2c_read - return readb(i2c_imx->base + (reg << i2c_imx->hwdata->regshift)); - } - -+/* Set up i2c controller register and i2c status register to default value. */ -+static void i2c_imx_reset_regs(struct imx_i2c_struct *i2c_imx) -+{ -+ imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, -+ i2c_imx, IMX_I2C_I2CR); -+ imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR); -+} -+ - /* Functions for DMA support */ - static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, - dma_addr_t phy_addr) -@@ -705,21 +716,33 @@ static void i2c_imx_stop(struct imx_i2c_ - imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); - } - --static irqreturn_t i2c_imx_isr(int irq, void *dev_id) -+/* Clear interrupt flag bit */ -+static void i2c_imx_clr_if_bit(unsigned int status, struct imx_i2c_struct *i2c_imx) - { -- struct imx_i2c_struct *i2c_imx = dev_id; -- unsigned int temp; -+ status &= ~I2SR_IIF; -+ status |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IIF); -+ imx_i2c_write_reg(status, i2c_imx, IMX_I2C_I2SR); -+} - -- temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); -- if (temp & I2SR_IIF) { -- /* save status register */ -- i2c_imx->i2csr = temp; -- i2c_imx_clear_irq(i2c_imx, I2SR_IIF); -- wake_up(&i2c_imx->queue); -- return IRQ_HANDLED; -- } -+/* Clear arbitration lost bit */ -+static void i2c_imx_clr_al_bit(unsigned int status, struct imx_i2c_struct *i2c_imx) -+{ -+ status &= ~I2SR_IAL; -+ status |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IAL); -+ imx_i2c_write_reg(status, i2c_imx, IMX_I2C_I2SR); -+} -+ -+static irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx) -+{ -+ unsigned int status; -+ -+ /* Save status register */ -+ status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); -+ i2c_imx->i2csr = status | I2SR_IIF; -+ -+ wake_up(&i2c_imx->queue); - -- return IRQ_NONE; -+ return IRQ_HANDLED; - } - - static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, -@@ -1094,6 +1117,13 @@ static int i2c_imx_xfer(struct i2c_adapt - - dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); - -+#if IS_ENABLED(CONFIG_I2C_SLAVE) -+ if (i2c_imx->slave) { -+ dev_err(&i2c_imx->adapter.dev, "Please not do operations of master mode in slave mode"); -+ return -EBUSY; -+ } -+#endif -+ - if (!pm_runtime_enabled(i2c_imx->adapter.dev.parent)) { - pm_runtime_enable(i2c_imx->adapter.dev.parent); - enable_runtime_pm = true; -@@ -1307,11 +1337,169 @@ static u32 i2c_imx_func(struct i2c_adapt - | I2C_FUNC_SMBUS_READ_BLOCK_DATA; - } - -+#if IS_ENABLED(CONFIG_I2C_SLAVE) -+static int i2c_imx_slave_init(struct imx_i2c_struct *i2c_imx) -+{ -+ int temp; -+ -+ /* Resume */ -+ temp = pm_runtime_get_sync(i2c_imx->adapter.dev.parent); -+ if (temp < 0) { -+ dev_err(&i2c_imx->adapter.dev, "failed to resume i2c controller"); -+ return temp; -+ } -+ -+ /* Set slave addr. */ -+ imx_i2c_write_reg((i2c_imx->slave->addr << 1), i2c_imx, IMX_I2C_IADR); -+ -+ i2c_imx_reset_regs(i2c_imx); -+ -+ /* Enable module */ -+ temp = i2c_imx->hwdata->i2cr_ien_opcode; -+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); -+ -+ /* Enable interrupt from i2c module */ -+ temp |= I2CR_IIEN; -+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); -+ -+ /* Wait controller to be stable */ -+ usleep_range(50, 150); -+ return 0; -+} -+ -+static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx) -+{ -+ unsigned int status, ctl; -+ u8 value; -+ -+ if (!i2c_imx->slave) { -+ dev_err(&i2c_imx->adapter.dev, "cannot deal with slave irq,i2c_imx->slave is null"); -+ return IRQ_NONE; -+ } -+ -+ status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); -+ ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); -+ if (status & I2SR_IAL) { /* Arbitration lost */ -+ i2c_imx_clr_al_bit(status, i2c_imx); -+ } else if (status & I2SR_IAAS) { /* Addressed as a slave */ -+ if (status & I2SR_SRW) { /* Master wants to read from us*/ -+ dev_dbg(&i2c_imx->adapter.dev, "read requested"); -+ i2c_slave_event(i2c_imx->slave, I2C_SLAVE_READ_REQUESTED, &value); -+ -+ /* Slave transmit */ -+ ctl |= I2CR_MTX; -+ imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR); -+ -+ /* Send data */ -+ imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR); -+ } else { /* Master wants to write to us */ -+ dev_dbg(&i2c_imx->adapter.dev, "write requested"); -+ i2c_slave_event(i2c_imx->slave, I2C_SLAVE_WRITE_REQUESTED, &value); -+ -+ /* Slave receive */ -+ ctl &= ~I2CR_MTX; -+ imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR); -+ /* Dummy read */ -+ imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); -+ } -+ } else if (!(ctl & I2CR_MTX)) { /* Receive mode */ -+ if (status & I2SR_IBB) { /* No STOP signal detected */ -+ ctl &= ~I2CR_MTX; -+ imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR); -+ -+ value = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); -+ i2c_slave_event(i2c_imx->slave, I2C_SLAVE_WRITE_RECEIVED, &value); -+ } else { /* STOP signal is detected */ -+ dev_dbg(&i2c_imx->adapter.dev, -+ "STOP signal detected"); -+ i2c_slave_event(i2c_imx->slave, I2C_SLAVE_STOP, &value); -+ } -+ } else if (!(status & I2SR_RXAK)) { /* Transmit mode received ACK */ -+ ctl |= I2CR_MTX; -+ imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR); -+ -+ i2c_slave_event(i2c_imx->slave, I2C_SLAVE_READ_PROCESSED, &value); -+ -+ imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR); -+ } else { /* Transmit mode received NAK */ -+ ctl &= ~I2CR_MTX; -+ imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR); -+ imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); -+ } -+ return IRQ_HANDLED; -+} -+ -+static int i2c_imx_reg_slave(struct i2c_client *client) -+{ -+ struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(client->adapter); -+ int ret; -+ if (i2c_imx->slave) -+ return -EBUSY; -+ -+ i2c_imx->slave = client; -+ -+ ret = i2c_imx_slave_init(i2c_imx); -+ if (ret < 0) -+ dev_err(&i2c_imx->adapter.dev, "failed to switch to slave mode"); -+ -+ return ret; -+} -+ -+static int i2c_imx_unreg_slave(struct i2c_client *client) -+{ -+ struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(client->adapter); -+ int ret; -+ -+ if (!i2c_imx->slave) -+ return -EINVAL; -+ -+ /* Reset slave address. */ -+ imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR); -+ -+ i2c_imx_reset_regs(i2c_imx); -+ -+ i2c_imx->slave = NULL; -+ -+ /* Suspend */ -+ ret = pm_runtime_put_sync(i2c_imx->adapter.dev.parent); -+ if (ret < 0) -+ dev_err(&i2c_imx->adapter.dev, "failed to suspend i2c controller"); -+ -+ return ret; -+} -+#endif -+ - static const struct i2c_algorithm i2c_imx_algo = { - .master_xfer = i2c_imx_xfer, - .functionality = i2c_imx_func, -+#if IS_ENABLED(CONFIG_I2C_SLAVE) -+ .reg_slave = i2c_imx_reg_slave, -+ .unreg_slave = i2c_imx_unreg_slave, -+#endif - }; - -+static irqreturn_t i2c_imx_isr(int irq, void *dev_id) -+{ -+ struct imx_i2c_struct *i2c_imx = dev_id; -+ unsigned int status, ctl; -+ irqreturn_t irq_status = IRQ_NONE; -+ -+ status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); -+ ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); -+ -+ if (status & I2SR_IIF) { -+ i2c_imx_clr_if_bit(status, i2c_imx); -+ if (ctl & I2CR_MSTA) -+ irq_status = i2c_imx_master_isr(i2c_imx); -+#if IS_ENABLED(CONFIG_I2C_SLAVE) -+ else -+ irq_status = i2c_imx_slave_isr(i2c_imx); -+#endif -+ } -+ -+ return irq_status; -+} -+ - static int i2c_imx_probe(struct platform_device *pdev) - { - struct imx_i2c_struct *i2c_imx; -@@ -1420,10 +1608,7 @@ static int i2c_imx_probe(struct platform - if (is_imx7d_i2c(i2c_imx) && i2c_imx->bitrate > IMX_I2C_MAX_E_BIT_RATE) - i2c_imx->bitrate = IMX_I2C_MAX_E_BIT_RATE; - -- /* Set up chip registers to defaults */ -- imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, -- i2c_imx, IMX_I2C_I2CR); -- imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR); -+ i2c_imx_reset_regs(i2c_imx); - - /* Init optional bus recovery */ - if (of_match_node(pinmux_of_match, pdev->dev.of_node)) |