All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] emev2: add slave support
@ 2015-12-05 17:51 ` Niklas Söderlund
  0 siblings, 0 replies; 8+ messages in thread
From: Niklas Söderlund @ 2015-12-05 17:51 UTC (permalink / raw)
  To: wsa, linux-i2c
  Cc: ian.molton, laurent.pinchart, magnus.damm, linux-sh,
	Niklas Söderlund

Add i2c slave support to EMEV2.

Tested using a EMEV2, BeagleBone Black and a 24c02 eeprom. While the
EMEV2 provided a emulated eeprom on iic0 using slave-24c02 the Bone
could talk to both the physical and the emulated eeprom. The EMEV2 could
talk to the physical eeprom while still provide the emulated eeprom.

Changes since v1:
- Fixed sparse errors, thanks Wolfram
- Updated email to contain +renesas

Niklas Söderlund (1):
  i2c: emev2: add slave support

 drivers/i2c/busses/i2c-emev2.c | 112 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 111 insertions(+), 1 deletion(-)

--
2.6.3


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2] emev2: add slave support
@ 2015-12-05 17:51 ` Niklas Söderlund
  0 siblings, 0 replies; 8+ messages in thread
From: Niklas Söderlund @ 2015-12-05 17:51 UTC (permalink / raw)
  To: wsa, linux-i2c
  Cc: ian.molton, laurent.pinchart, magnus.damm, linux-sh,
	Niklas Söderlund

Add i2c slave support to EMEV2.

Tested using a EMEV2, BeagleBone Black and a 24c02 eeprom. While the
EMEV2 provided a emulated eeprom on iic0 using slave-24c02 the Bone
could talk to both the physical and the emulated eeprom. The EMEV2 could
talk to the physical eeprom while still provide the emulated eeprom.

Changes since v1:
- Fixed sparse errors, thanks Wolfram
- Updated email to contain +renesas

Niklas Söderlund (1):
  i2c: emev2: add slave support

 drivers/i2c/busses/i2c-emev2.c | 112 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 111 insertions(+), 1 deletion(-)

--
2.6.3


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2] i2c: emev2: add slave support
  2015-12-05 17:51 ` Niklas Söderlund
@ 2015-12-05 17:51   ` Niklas Söderlund
  -1 siblings, 0 replies; 8+ messages in thread
From: Niklas Söderlund @ 2015-12-05 17:51 UTC (permalink / raw)
  To: wsa, linux-i2c
  Cc: ian.molton, laurent.pinchart, magnus.damm, linux-sh,
	Niklas Söderlund

Add I2C slave provider using the generic slave interface.

Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/i2c/busses/i2c-emev2.c | 112 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 111 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-emev2.c b/drivers/i2c/busses/i2c-emev2.c
index 192ef6b..96bb4e7 100644
--- a/drivers/i2c/busses/i2c-emev2.c
+++ b/drivers/i2c/busses/i2c-emev2.c
@@ -71,6 +71,7 @@ struct em_i2c_device {
 	struct i2c_adapter adap;
 	struct completion msg_done;
 	struct clk *sclk;
+	struct i2c_client *slave;
 };
 
 static inline void em_clear_set_bit(struct em_i2c_device *priv, u8 clear, u8 set, u8 reg)
@@ -226,22 +227,131 @@ static int em_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
 	return num;
 }
 
+static bool em_i2c_slave_irq(struct em_i2c_device *priv)
+{
+	u8 status, value;
+	enum i2c_slave_event event;
+	int ret;
+
+	if (!priv->slave)
+		return false;
+
+	status = readb(priv->base + I2C_OFS_IICSE0);
+
+	/* Extension code, do not participate */
+	if (status & I2C_BIT_EXC0) {
+		em_clear_set_bit(priv, 0, I2C_BIT_LREL0, I2C_OFS_IICC0);
+		return true;
+	}
+
+	/* Stop detected, we don't know if it's for slave or master */
+	if (status & I2C_BIT_SPD0) {
+		/* Notify slave device */
+		i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &value);
+		/* Pretend we did not handle the interrupt */
+		return false;
+	}
+
+	/* Only handle interrupts addressed to us */
+	if (!(status & I2C_BIT_COI0))
+		return false;
+
+	/* Enable stop interrupts */
+	em_clear_set_bit(priv, 0, I2C_BIT_SPIE0, I2C_OFS_IICC0);
+
+	/* Transmission or Reception */
+	if (status & I2C_BIT_TRC0) {
+		if (status & I2C_BIT_ACKD0) {
+			/* 9 bit interrupt mode */
+			em_clear_set_bit(priv, 0, I2C_BIT_WTIM0, I2C_OFS_IICC0);
+
+			/* Send data */
+			event = status & I2C_BIT_STD0 ?
+				I2C_SLAVE_READ_REQUESTED :
+				I2C_SLAVE_READ_PROCESSED;
+			i2c_slave_event(priv->slave, event, &value);
+			writeb(value, priv->base + I2C_OFS_IIC0);
+		} else {
+			/* NACK, stop transmitting */
+			em_clear_set_bit(priv, 0, I2C_BIT_LREL0, I2C_OFS_IICC0);
+		}
+	} else {
+		/* 8 bit interrupt mode */
+		em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_ACKE0,
+				I2C_OFS_IICC0);
+		em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_WREL0,
+				I2C_OFS_IICC0);
+
+		if (status & I2C_BIT_STD0) {
+			i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED,
+					&value);
+		} else {
+			/* Recv data */
+			value = readb(priv->base + I2C_OFS_IIC0);
+			ret = i2c_slave_event(priv->slave,
+					I2C_SLAVE_WRITE_RECEIVED, &value);
+			if (ret < 0)
+				em_clear_set_bit(priv, I2C_BIT_ACKE0, 0,
+						I2C_OFS_IICC0);
+		}
+	}
+
+	return true;
+}
+
 static irqreturn_t em_i2c_irq_handler(int this_irq, void *dev_id)
 {
 	struct em_i2c_device *priv = dev_id;
 
+	if (em_i2c_slave_irq(priv))
+		return IRQ_HANDLED;
+
 	complete(&priv->msg_done);
+
 	return IRQ_HANDLED;
 }
 
 static u32 em_i2c_func(struct i2c_adapter *adap)
 {
-	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SLAVE;
+}
+
+static int em_i2c_reg_slave(struct i2c_client *slave)
+{
+	struct em_i2c_device *priv = i2c_get_adapdata(slave->adapter);
+
+	if (priv->slave)
+		return -EBUSY;
+
+	if (slave->flags & I2C_CLIENT_TEN)
+		return -EAFNOSUPPORT;
+
+	priv->slave = slave;
+
+	/* Set slave address */
+	writeb(slave->addr << 1, priv->base + I2C_OFS_SVA0);
+
+	return 0;
+}
+
+static int em_i2c_unreg_slave(struct i2c_client *slave)
+{
+	struct em_i2c_device *priv = i2c_get_adapdata(slave->adapter);
+
+	WARN_ON(!priv->slave);
+
+	writeb(0, priv->base + I2C_OFS_SVA0);
+
+	priv->slave = NULL;
+
+	return 0;
 }
 
 static struct i2c_algorithm em_i2c_algo = {
 	.master_xfer = em_i2c_xfer,
 	.functionality = em_i2c_func,
+	.reg_slave      = em_i2c_reg_slave,
+	.unreg_slave    = em_i2c_unreg_slave,
 };
 
 static int em_i2c_probe(struct platform_device *pdev)
-- 
2.6.3

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2] i2c: emev2: add slave support
@ 2015-12-05 17:51   ` Niklas Söderlund
  0 siblings, 0 replies; 8+ messages in thread
From: Niklas Söderlund @ 2015-12-05 17:51 UTC (permalink / raw)
  To: wsa, linux-i2c
  Cc: ian.molton, laurent.pinchart, magnus.damm, linux-sh,
	Niklas Söderlund

Add I2C slave provider using the generic slave interface.

Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/i2c/busses/i2c-emev2.c | 112 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 111 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-emev2.c b/drivers/i2c/busses/i2c-emev2.c
index 192ef6b..96bb4e7 100644
--- a/drivers/i2c/busses/i2c-emev2.c
+++ b/drivers/i2c/busses/i2c-emev2.c
@@ -71,6 +71,7 @@ struct em_i2c_device {
 	struct i2c_adapter adap;
 	struct completion msg_done;
 	struct clk *sclk;
+	struct i2c_client *slave;
 };
 
 static inline void em_clear_set_bit(struct em_i2c_device *priv, u8 clear, u8 set, u8 reg)
@@ -226,22 +227,131 @@ static int em_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
 	return num;
 }
 
+static bool em_i2c_slave_irq(struct em_i2c_device *priv)
+{
+	u8 status, value;
+	enum i2c_slave_event event;
+	int ret;
+
+	if (!priv->slave)
+		return false;
+
+	status = readb(priv->base + I2C_OFS_IICSE0);
+
+	/* Extension code, do not participate */
+	if (status & I2C_BIT_EXC0) {
+		em_clear_set_bit(priv, 0, I2C_BIT_LREL0, I2C_OFS_IICC0);
+		return true;
+	}
+
+	/* Stop detected, we don't know if it's for slave or master */
+	if (status & I2C_BIT_SPD0) {
+		/* Notify slave device */
+		i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &value);
+		/* Pretend we did not handle the interrupt */
+		return false;
+	}
+
+	/* Only handle interrupts addressed to us */
+	if (!(status & I2C_BIT_COI0))
+		return false;
+
+	/* Enable stop interrupts */
+	em_clear_set_bit(priv, 0, I2C_BIT_SPIE0, I2C_OFS_IICC0);
+
+	/* Transmission or Reception */
+	if (status & I2C_BIT_TRC0) {
+		if (status & I2C_BIT_ACKD0) {
+			/* 9 bit interrupt mode */
+			em_clear_set_bit(priv, 0, I2C_BIT_WTIM0, I2C_OFS_IICC0);
+
+			/* Send data */
+			event = status & I2C_BIT_STD0 ?
+				I2C_SLAVE_READ_REQUESTED :
+				I2C_SLAVE_READ_PROCESSED;
+			i2c_slave_event(priv->slave, event, &value);
+			writeb(value, priv->base + I2C_OFS_IIC0);
+		} else {
+			/* NACK, stop transmitting */
+			em_clear_set_bit(priv, 0, I2C_BIT_LREL0, I2C_OFS_IICC0);
+		}
+	} else {
+		/* 8 bit interrupt mode */
+		em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_ACKE0,
+				I2C_OFS_IICC0);
+		em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_WREL0,
+				I2C_OFS_IICC0);
+
+		if (status & I2C_BIT_STD0) {
+			i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED,
+					&value);
+		} else {
+			/* Recv data */
+			value = readb(priv->base + I2C_OFS_IIC0);
+			ret = i2c_slave_event(priv->slave,
+					I2C_SLAVE_WRITE_RECEIVED, &value);
+			if (ret < 0)
+				em_clear_set_bit(priv, I2C_BIT_ACKE0, 0,
+						I2C_OFS_IICC0);
+		}
+	}
+
+	return true;
+}
+
 static irqreturn_t em_i2c_irq_handler(int this_irq, void *dev_id)
 {
 	struct em_i2c_device *priv = dev_id;
 
+	if (em_i2c_slave_irq(priv))
+		return IRQ_HANDLED;
+
 	complete(&priv->msg_done);
+
 	return IRQ_HANDLED;
 }
 
 static u32 em_i2c_func(struct i2c_adapter *adap)
 {
-	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SLAVE;
+}
+
+static int em_i2c_reg_slave(struct i2c_client *slave)
+{
+	struct em_i2c_device *priv = i2c_get_adapdata(slave->adapter);
+
+	if (priv->slave)
+		return -EBUSY;
+
+	if (slave->flags & I2C_CLIENT_TEN)
+		return -EAFNOSUPPORT;
+
+	priv->slave = slave;
+
+	/* Set slave address */
+	writeb(slave->addr << 1, priv->base + I2C_OFS_SVA0);
+
+	return 0;
+}
+
+static int em_i2c_unreg_slave(struct i2c_client *slave)
+{
+	struct em_i2c_device *priv = i2c_get_adapdata(slave->adapter);
+
+	WARN_ON(!priv->slave);
+
+	writeb(0, priv->base + I2C_OFS_SVA0);
+
+	priv->slave = NULL;
+
+	return 0;
 }
 
 static struct i2c_algorithm em_i2c_algo = {
 	.master_xfer = em_i2c_xfer,
 	.functionality = em_i2c_func,
+	.reg_slave      = em_i2c_reg_slave,
+	.unreg_slave    = em_i2c_unreg_slave,
 };
 
 static int em_i2c_probe(struct platform_device *pdev)
-- 
2.6.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2] i2c: emev2: add slave support
  2015-12-05 17:51   ` Niklas Söderlund
@ 2015-12-05 18:56     ` Wolfram Sang
  -1 siblings, 0 replies; 8+ messages in thread
From: Wolfram Sang @ 2015-12-05 18:56 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: linux-i2c, ian.molton, laurent.pinchart, magnus.damm, linux-sh,
	Niklas Söderlund

[-- Attachment #1: Type: text/plain, Size: 243 bytes --]

On Sat, Dec 05, 2015 at 06:51:31PM +0100, Niklas Söderlund wrote:
> Add I2C slave provider using the generic slave interface.
> 
> Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

Applied to for-next, thanks!


[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2] i2c: emev2: add slave support
@ 2015-12-05 18:56     ` Wolfram Sang
  0 siblings, 0 replies; 8+ messages in thread
From: Wolfram Sang @ 2015-12-05 18:56 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: linux-i2c, ian.molton, laurent.pinchart, magnus.damm, linux-sh,
	Niklas Söderlund

[-- Attachment #1: Type: text/plain, Size: 243 bytes --]

On Sat, Dec 05, 2015 at 06:51:31PM +0100, Niklas Söderlund wrote:
> Add I2C slave provider using the generic slave interface.
> 
> Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

Applied to for-next, thanks!


[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2] emev2: add slave support
  2015-12-05 17:51 ` Niklas Söderlund
@ 2015-12-05 18:59   ` Wolfram Sang
  -1 siblings, 0 replies; 8+ messages in thread
From: Wolfram Sang @ 2015-12-05 18:59 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: linux-i2c, ian.molton, laurent.pinchart, magnus.damm, linux-sh,
	Niklas Söderlund

[-- Attachment #1: Type: text/plain, Size: 85 bytes --]


> - Updated email to contain +renesas

This mail address did not work a second ago.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2] emev2: add slave support
@ 2015-12-05 18:59   ` Wolfram Sang
  0 siblings, 0 replies; 8+ messages in thread
From: Wolfram Sang @ 2015-12-05 18:59 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: linux-i2c, ian.molton, laurent.pinchart, magnus.damm, linux-sh,
	Niklas Söderlund

[-- Attachment #1: Type: text/plain, Size: 85 bytes --]


> - Updated email to contain +renesas

This mail address did not work a second ago.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2015-12-05 18:59 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-05 17:51 [PATCH v2] emev2: add slave support Niklas Söderlund
2015-12-05 17:51 ` Niklas Söderlund
2015-12-05 17:51 ` [PATCH v2] i2c: " Niklas Söderlund
2015-12-05 17:51   ` Niklas Söderlund
2015-12-05 18:56   ` Wolfram Sang
2015-12-05 18:56     ` Wolfram Sang
2015-12-05 18:59 ` [PATCH v2] " Wolfram Sang
2015-12-05 18:59   ` Wolfram Sang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.