Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1406932 > unrolled thread

[RFC 0/1] i2c: omap: Add support for switching to slave mode

Started byRavikumar Kattekola <rk@ti.com>
First post2016-05-25 16:20 +0200
Last post2016-05-26 18:10 +0200
Articles 3 — 2 participants

Back to article view | Back to linux.kernel


Contents

  [RFC 0/1] i2c: omap: Add support for switching to slave mode Ravikumar Kattekola <rk@ti.com> - 2016-05-25 16:20 +0200
    [RFC 1/1] drivers: i2c: omap: Add slave support Ravikumar Kattekola <rk@ti.com> - 2016-05-25 16:20 +0200
      Re: [RFC 1/1] drivers: i2c: omap: Add slave support Manish Badarkhe <badarkhe.manish@gmail.com> - 2016-05-26 18:10 +0200

#1406932 — [RFC 0/1] i2c: omap: Add support for switching to slave mode

FromRavikumar Kattekola <rk@ti.com>
Date2016-05-25 16:20 +0200
Subject[RFC 0/1] i2c: omap: Add support for switching to slave mode
Message-ID<rCHPb-1YV-9@gated-at.bofh.it>
I2C controller on most of the omap devices has both master and slave
capability but the i2c framework has been missing support for registering
a bus in slave mode for long.
Recently the i2c slave support has been added to i2c framework, the following
patch adds the required support for omap_i2c driver to register a controller
as a slave device and be deriven by an external/internal master.

The slave interface requires us to add following mandatory events

1. I2C_SLAVE_WRITE_REQUESTED
2. I2C_SLAVE_READ_REQUESTED
3. I2C_SLAVE_WRITE_RECEIVED
4. I2C_SLAVE_READ_PROCESSED

and 

5. I2C_SLAVE_STOP

The omap i2c controller (at least on dra7x devices)
doesn't have  start/stop (STT/STP) support for slave mode
so event  #5 is not implemented in the driver.

Refer to Documentation/i2c/slave-interface for more info on 
i2c-slave-interface and Documentation/i2c/slave-eeprom-backend for 
sample backend driver.

Tested on:
DRA75x EVM Rev G3 and DRA72x EVM Rev B1 connected over i2c3 using DCAN2 lines [JP3]

Ravikumar Kattekola (1):
  drivers: i2c: omap: Add slave support

 drivers/i2c/busses/i2c-omap.c | 144 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 144 insertions(+)

-- 
2.8.2.396.g5fe494c

[toc] | [next] | [standalone]


#1406933 — [RFC 1/1] drivers: i2c: omap: Add slave support

FromRavikumar Kattekola <rk@ti.com>
Date2016-05-25 16:20 +0200
Subject[RFC 1/1] drivers: i2c: omap: Add slave support
Message-ID<rCHPb-1YV-7@gated-at.bofh.it>
In reply to#1406932
I2C controller on most of the omap devices has both master and slave
capability but the i2c framework has been missing support for registering
a bus in slave mode for long.

Recently the i2c slave support has been added to i2c framework,
the following patch adds the required support for omap_i2c driver to
register a controller as a slave device and be deriven by
an external/internal master.

The slave interface requires us to add following mandatory events

1. I2C_SLAVE_WRITE_REQUESTED
2. I2C_SLAVE_READ_REQUESTED
3. I2C_SLAVE_WRITE_RECEIVED
4. I2C_SLAVE_READ_PROCESSED

and

5. I2C_SLAVE_STOP

The omap i2c controller (at least on dra7x devices)
doesn't have  start/stop (STT/STP) support for slave mode
so event  #5 is not implemented in the driver.

Signed-off-by: Ravikumar Kattekola <rk@ti.com>
---
 drivers/i2c/busses/i2c-omap.c | 144 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 144 insertions(+)

diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index ab1279b..ccfc49f 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -89,6 +89,7 @@ enum {
 /* I2C Interrupt Enable Register (OMAP_I2C_IE): */
 #define OMAP_I2C_IE_XDR		(1 << 14)	/* TX Buffer drain int enable */
 #define OMAP_I2C_IE_RDR		(1 << 13)	/* RX Buffer drain int enable */
+#define OMAP_I2C_IE_AAS		(1 << 9)	/* Addressed as Slave int enable */
 #define OMAP_I2C_IE_XRDY	(1 << 4)	/* TX data ready int enable */
 #define OMAP_I2C_IE_RRDY	(1 << 3)	/* RX data ready int enable */
 #define OMAP_I2C_IE_ARDY	(1 << 2)	/* Access ready int enable */
@@ -202,6 +203,7 @@ struct omap_i2c_dev {
 	u8			*regs;
 	size_t			buf_len;
 	struct i2c_adapter	adapter;
+	struct i2c_client	*slave;
 	u8			threshold;
 	u8			fifo_size;	/* use as flag and value
 						 * fifo_size==0 implies no fifo
@@ -1003,6 +1005,62 @@ omap_i2c_isr(int irq, void *dev_id)
 	return ret;
 }
 
+#ifdef CONFIG_I2C_SLAVE
+static int omap_i2c_slave_irq(struct omap_i2c_dev *omap)
+{
+	u16 stat_raw;
+	u16 stat;
+	u16 bits;
+	u8 value;
+
+	stat_raw = omap_i2c_read_reg(omap, OMAP_I2C_IP_V2_IRQSTATUS_RAW);
+	bits = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
+	stat_raw &= bits;
+
+	if (stat_raw & OMAP_I2C_STAT_AAS) {
+		omap_i2c_ack_stat(omap, OMAP_I2C_STAT_AAS);
+		stat_raw &= ~OMAP_I2C_STAT_AAS;
+	}
+
+	/* Someone's just sayin Hi? okay bye..*/
+	if (!stat_raw)
+		goto out;
+
+	dev_dbg(omap->dev, "IRQ (ISR = 0x%04x)\n", stat_raw);
+
+	if (stat_raw & OMAP_I2C_STAT_RRDY)
+		i2c_slave_event(omap->slave, I2C_SLAVE_WRITE_REQUESTED, &value);
+
+	do {
+		bits = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
+		stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
+		stat &= bits;
+
+		if (stat & OMAP_I2C_STAT_AAS)
+			omap_i2c_ack_stat(omap, OMAP_I2C_STAT_AAS);
+
+		if (stat & OMAP_I2C_STAT_RRDY) {
+			value = omap_i2c_read_reg(omap, OMAP_I2C_DATA_REG);
+			i2c_slave_event(omap->slave, I2C_SLAVE_WRITE_RECEIVED,
+					&value);
+			omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RRDY);
+		}
+
+		if (stat & OMAP_I2C_STAT_XRDY) {
+			i2c_slave_event(omap->slave, I2C_SLAVE_READ_REQUESTED,
+					&value);
+			omap_i2c_write_reg(omap, OMAP_I2C_DATA_REG, value);
+			i2c_slave_event(omap->slave, I2C_SLAVE_READ_PROCESSED,
+					&value);
+			omap_i2c_ack_stat(omap, OMAP_I2C_STAT_XRDY);
+		}
+
+	} while (stat);
+out:
+	return 0;
+}
+#endif
+
 static irqreturn_t
 omap_i2c_isr_thread(int this_irq, void *dev_id)
 {
@@ -1011,6 +1069,13 @@ omap_i2c_isr_thread(int this_irq, void *dev_id)
 	u16 stat;
 	int err = 0, count = 0;
 
+#ifdef CONFIG_I2C_SLAVE
+	if (omap->slave) {
+		/* If a slave is registered pass on the interrupt */
+		err = omap_i2c_slave_irq(omap);
+		goto out;
+	}
+#endif
 	do {
 		bits = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
 		stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
@@ -1139,9 +1204,88 @@ out:
 	return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_I2C_SLAVE
+static int omap_i2c_reg_slave(struct i2c_client *slave)
+{
+	struct omap_i2c_dev *omap = i2c_get_adapdata(slave->adapter);
+	u16 reg;
+	int ret = 0;
+
+	dev_info(omap->dev, "Registering as a slave @ %x\n", slave->addr);
+
+	/* Already registered as a slave?
+	 * XXX: OMAP I2c controller supports up to four
+	 * different OA, can we register as four different
+	 * slaves?
+	 */
+	if (omap->slave)
+		return -EBUSY;
+
+	ret = pm_runtime_get_sync(omap->dev);
+	if (ret < 0)
+		return ret;
+
+	omap->slave = slave;
+
+	/* Write OA: So that master(s) can talk to us */
+	omap_i2c_write_reg(omap, OMAP_I2C_OA_REG, slave->addr);
+
+	/* Set / Switch to slave mode */
+	reg = omap_i2c_read_reg(omap, OMAP_I2C_CON_REG);
+	reg &= ~OMAP_I2C_CON_MST;
+	omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, reg);
+
+	/* Clear status */
+	omap_i2c_write_reg(omap, OMAP_I2C_SYSS_REG, 0);
+
+	/* As of now, We dont need all interrupts be enabled */
+	omap->iestate = OMAP_I2C_IE_AAS | OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY;
+
+	/* Clear interrupt mask */
+	omap_i2c_write_reg(omap, OMAP_I2C_IP_V2_IRQENABLE_CLR, 0xffff);
+
+	dev_dbg(omap->dev, "omap->iestate 0x%04x\n", omap->iestate);
+
+	/* Enable necessary interrupts */
+	omap_i2c_write_reg(omap, OMAP_I2C_IE_REG, omap->iestate);
+
+	return 0;
+
+}
+
+static int omap_i2c_unreg_slave(struct i2c_client *slave)
+{
+	struct omap_i2c_dev *omap = i2c_get_adapdata(slave->adapter);
+	u16 reg;
+
+	WARN_ON(!omap->slave);
+	omap->slave = NULL;
+
+	/* Switch to master mode */
+	reg = omap_i2c_read_reg(omap, OMAP_I2C_CON_REG);
+	reg |= OMAP_I2C_CON_MST;
+	omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, reg);
+
+	/* clear status */
+	omap_i2c_write_reg(omap, OMAP_I2C_SYSS_REG, 0);
+
+	/* Just to make sure re-init in master mode
+	 * Should we do a reset here?
+	 */
+	omap_i2c_init(omap);
+
+	pm_runtime_put(omap->dev);
+	return 0;
+}
+#endif
+
 static const struct i2c_algorithm omap_i2c_algo = {
 	.master_xfer	= omap_i2c_xfer,
 	.functionality	= omap_i2c_func,
+#ifdef CONFIG_I2C_SLAVE
+	.reg_slave	= omap_i2c_reg_slave,
+	.unreg_slave	= omap_i2c_unreg_slave,
+#endif /* CONFIG_I2C_SLAVE */
 };
 
 #ifdef CONFIG_OF
-- 
2.8.2.396.g5fe494c

[toc] | [prev] | [next] | [standalone]


#1407618 — Re: [RFC 1/1] drivers: i2c: omap: Add slave support

FromManish Badarkhe <badarkhe.manish@gmail.com>
Date2016-05-26 18:10 +0200
SubjectRe: [RFC 1/1] drivers: i2c: omap: Add slave support
Message-ID<rD61c-6U-11@gated-at.bofh.it>
In reply to#1406933
Hi Ravikumar

Some sanity comments, just good to have.

> +#ifdef CONFIG_I2C_SLAVE
> +static int omap_i2c_slave_irq(struct omap_i2c_dev *omap)
> +{
> +       u16 stat_raw;
> +       u16 stat;
> +       u16 bits;
> +       u8 value;
> +
> +       stat_raw = omap_i2c_read_reg(omap, OMAP_I2C_IP_V2_IRQSTATUS_RAW);
> +       bits = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
> +       stat_raw &= bits;
> +
> +       if (stat_raw & OMAP_I2C_STAT_AAS) {
> +               omap_i2c_ack_stat(omap, OMAP_I2C_STAT_AAS);
> +               stat_raw &= ~OMAP_I2C_STAT_AAS;
> +       }
> +
> +out:
> +       return 0;
> +}
> +#endif

This function always return 0.

> +#ifdef CONFIG_I2C_SLAVE
> +static int omap_i2c_reg_slave(struct i2c_client *slave)
> +{
> +       struct omap_i2c_dev *omap = i2c_get_adapdata(slave->adapter);
> +       u16 reg;
> +       int ret = 0;
> +       /* Enable necessary interrupts */
> +       omap_i2c_write_reg(omap, OMAP_I2C_IE_REG, omap->iestate);
> +
> +       return 0;
> +
> +}

Better to return "ret" here as already been initialized to 0

> +
> +static int omap_i2c_unreg_slave(struct i2c_client *slave)
> +{
> +       struct omap_i2c_dev *omap = i2c_get_adapdata(slave->adapter);
> +       u16 reg;
> +
> +       pm_runtime_put(omap->dev);
> +       return 0;
> +}
> +#endif

This function always return 0


Regards
Manish Badarkhe

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web