Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1406932 > unrolled thread
| Started by | Ravikumar Kattekola <rk@ti.com> |
|---|---|
| First post | 2016-05-25 16:20 +0200 |
| Last post | 2016-05-26 18:10 +0200 |
| Articles | 3 — 2 participants |
Back to article view | Back to linux.kernel
[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
| From | Ravikumar Kattekola <rk@ti.com> |
|---|---|
| Date | 2016-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]
| From | Ravikumar Kattekola <rk@ti.com> |
|---|---|
| Date | 2016-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]
| From | Manish Badarkhe <badarkhe.manish@gmail.com> |
|---|---|
| Date | 2016-05-26 18:10 +0200 |
| Subject | Re: [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