devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Naveen Krishna Chatradhi <ch.naveen-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
To: linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: grundler-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org,
	w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org,
	ben-linux-elnMNo+KYs3YtjvyW6yDsg@public.gmane.org,
	khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org,
	naveen-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org
Subject: [PATCH 1/2] i2c-core: Add gpio based bus arbitration implementation
Date: Fri, 14 Dec 2012 11:20:53 +0530	[thread overview]
Message-ID: <1355464254-12768-2-git-send-email-ch.naveen@samsung.com> (raw)
In-Reply-To: <1355464254-12768-1-git-send-email-ch.naveen-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>

The arbitrator is a general purpose function which uses two GPIOs to
communicate with another device to claim/release a bus.

i2c_transfer()
	if adapter->gpio_arbit
		i2c_bus_claim();
			__i2c_transfer();
		i2c_bus_release();

Signed-off-by: Simon Glass <sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Cc: Grant Grundler <grundler-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Signed-off-by: Naveen Krishna Chatradhi <ch.naveen-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
 .../devicetree/bindings/i2c/arbitrator-i2c.txt     |   56 ++++++++++++++++
 drivers/i2c/i2c-core.c                             |   67 ++++++++++++++++++++
 drivers/of/of_i2c.c                                |   27 ++++++++
 include/linux/i2c.h                                |   17 +++++
 include/linux/of_i2c.h                             |    2 +
 5 files changed, 169 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i2c/arbitrator-i2c.txt

diff --git a/Documentation/devicetree/bindings/i2c/arbitrator-i2c.txt b/Documentation/devicetree/bindings/i2c/arbitrator-i2c.txt
new file mode 100644
index 0000000..cb91ea8
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/arbitrator-i2c.txt
@@ -0,0 +1,56 @@
+Device-Tree bindings for i2c gpio based bus arbitrator
+
+bus-arbitration-gpios :
+	Two GPIOs to use with the GPIO-based bus arbitration protocol
+(see below).
+The first should be an output, and is used to claim the I2C bus,
+the second should be an input, and signals that the other side (Client)
+wants to claim the bus. This allows two masters to share the same I2C bus.
+
+Required properties:
+	- bus-needs-gpio-arbitration;
+	- bus-arbitration-gpios: AP_CLAIM and Client_CLAIM gpios
+	- bus-arbitration-slew-delay-us:
+	- bus-arbitration-wait-retry-us:
+	- bus-arbitration-wait-free-us:
+
+Example nodes:
+
+i2c@0 {
+	/* If you want GPIO-based bus arbitration */
+	bus-needs-gpio-arbitration;
+	bus-arbitration-gpios = <&gpf0 3 1 0 0>, /* AP_CLAIM */
+		<&gpe0 4 0 3 0>; /* EC_CLAIM */
+
+	bus-arbitration-slew-delay-us = <10>;
+	bus-arbitration-wait-retry-us = <2000>;
+	bus-arbitration-wait-free-us = <50000>;
+};
+
+GPIO-based Arbitration
+======================
+This uses GPIO lines between the AP (SoC) and an attached EC (embedded
+controller) which both want to talk on the same I2C bus as master.
+
+The AP and EC each have a 'bus claim' line, which is an output that the
+other can see. These are both active low, with pull-ups enabled.
+
+- AP_CLAIM: output from AP, signalling to the EC that the AP wants the bus
+- EC_CLAIM: output from EC, signalling to the AP that the EC wants the bus
+
+
+Algorithm
+---------
+The basic algorithm is to assert your line when you want the bus, then make
+sure that the other side doesn't want it also. A detailed explanation is best
+done with an example.
+
+Let's say the AP wants to claim the bus. It:
+1. Asserts AP_CLAIM
+2. Waits a little bit for the other side to notice (slew time, say 10
+microseconds)
+3. Checks EC_CLAIM. If this is not asserted, then the AP has the bus, and
+we are done
+4. Otherwise, wait for a few milliseconds and see if EC_CLAIM is released
+5. If not, back off, release the claim and wait for a few more milliseconds
+6. Go back to 1 (until retry time has expired)
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index a7edf98..222a6da 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -32,6 +32,7 @@
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/idr.h>
+#include <linux/delay.h>
 #include <linux/mutex.h>
 #include <linux/of_device.h>
 #include <linux/completion.h>
@@ -39,6 +40,7 @@
 #include <linux/irqflags.h>
 #include <linux/rwsem.h>
 #include <linux/pm_runtime.h>
+#include <linux/gpio.h>
 #include <asm/uaccess.h>
 
 #include "i2c-core.h"
@@ -1256,6 +1258,59 @@ void i2c_release_client(struct i2c_client *client)
 }
 EXPORT_SYMBOL(i2c_release_client);
 
+/**
+ * If we have enabled arbitration on this bus, claim the i2c bus, using
+ * the GPIO-based signalling protocol.
+ */
+static int i2c_bus_claim(struct i2c_gpio_arbit *i2c_arbit)
+{
+	unsigned long stop_retry, stop_time;
+	unsigned int gpio;
+
+	/* Start a round of trying to claim the bus */
+	stop_time = jiffies + usecs_to_jiffies(i2c_arbit->wait_free_us) + 1;
+	do {
+		/* Indicate that we want to claim the bus */
+		gpio_set_value(i2c_arbit->arb_gpios[I2C_ARB_GPIO_AP], 0);
+		udelay(i2c_arbit->slew_delay_us);
+
+		/* Wait for the EC to release it */
+		stop_retry = jiffies +
+			usecs_to_jiffies(i2c_arbit->wait_retry_us) + 1;
+		while (time_before(jiffies, stop_retry)) {
+			gpio = i2c_arbit->arb_gpios[I2C_ARB_GPIO_EC];
+			if (gpio_get_value(gpio)) {
+				/* We got it, so return */
+				return 0;
+			}
+
+			usleep_range(50, 200);
+		}
+
+		/* It didn't release, so give up, wait, and try again */
+		gpio_set_value(i2c_arbit->arb_gpios[I2C_ARB_GPIO_AP], 1);
+
+		usleep_range(i2c_arbit->wait_retry_us,
+					i2c_arbit->wait_retry_us * 2);
+	} while (time_before(jiffies, stop_time));
+
+	/* Give up, release our claim */
+	gpio_set_value(i2c_arbit->arb_gpios[I2C_ARB_GPIO_AP], 1);
+	udelay(i2c_arbit->slew_delay_us);
+
+	return -EBUSY;
+}
+
+/**
+ * If we have enabled arbitration on this bus, release the i2c bus.
+ */
+static void i2c_bus_release(struct i2c_gpio_arbit *i2c_arbit)
+{
+	/* Release the bus and wait for the EC to notice */
+	gpio_set_value(i2c_arbit->arb_gpios[I2C_ARB_GPIO_AP], 1);
+	udelay(i2c_arbit->slew_delay_us);
+}
+
 struct i2c_cmd_arg {
 	unsigned	cmd;
 	void		*arg;
@@ -1412,7 +1467,19 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 			i2c_lock_adapter(adap);
 		}
 
+		if (adap->gpio_arbit) {
+			if (i2c_bus_claim(adap->gpio_arbit)) {
+				dev_err(&adap->dev, "I2C: Could not claim bus, timeout\n");
+				return -EBUSY;
+			}
+		}
+
 		ret = __i2c_transfer(adap, msgs, num);
+
+		/* Release the bus if needed */
+		if (adap->gpio_arbit)
+			i2c_bus_release(adap->gpio_arbit);
+
 		i2c_unlock_adapter(adap);
 
 		return ret;
diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c
index 3550f3b..4ec3f44 100644
--- a/drivers/of/of_i2c.c
+++ b/drivers/of/of_i2c.c
@@ -111,4 +111,31 @@ struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
 }
 EXPORT_SYMBOL(of_find_i2c_adapter_by_node);
 
+/*
+ * Property "bus-needs-gpio-arbitration" in DT node enables
+ * GPIO based bus arbitration.
+ * Populates the default timing values if not specified.
+ *
+ * Returns NULL, if "bus-needs-gpio-arbitration" is not specified.
+ */
+struct i2c_gpio_arbit *of_get_arbitrator_info(struct device_node *np,
+				struct i2c_gpio_arbit *i2c_arbit)
+{
+	if (of_get_property(np, "bus-needs-gpio-arbitration", NULL)) {
+		if (of_property_read_u32(np, "bus-arbitration-slew-delay-us",
+				&i2c_arbit->slew_delay_us))
+			i2c_arbit->slew_delay_us = 10;
+		if (of_property_read_u32(np, "bus-arbitration-wait-retry-us",
+				&i2c_arbit->wait_retry_us))
+			i2c_arbit->wait_retry_us = 2000;
+		if (of_property_read_u32(np, "bus-arbitration-wait-free-us",
+				&i2c_arbit->wait_free_us))
+			i2c_arbit->wait_free_us = 50000;
+	} else
+		i2c_arbit = NULL;
+
+	return i2c_arbit;
+}
+EXPORT_SYMBOL_GPL(of_get_arbitrator_info);
+
 MODULE_LICENSE("GPL");
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 800de22..d1ae491 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -295,6 +295,22 @@ struct i2c_board_info {
 #define I2C_BOARD_INFO(dev_type, dev_addr) \
 	.type = dev_type, .addr = (dev_addr)
 
+enum {
+	I2C_ARB_GPIO_AP,		/* AP claims i2c bus */
+	I2C_ARB_GPIO_EC,		/* EC claims i2c bus */
+
+	I2C_ARB_GPIO_COUNT,
+};
+
+/* I2C bus GPIO based arbitration information */
+struct i2c_gpio_arbit {
+	int			arb_gpios[I2C_ARB_GPIO_COUNT];
+
+	/* Arbitration parameters */
+	unsigned int		slew_delay_us;
+	unsigned int		wait_retry_us;
+	unsigned int		wait_free_us;
+};
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 /* Add-on boards should register/unregister their devices; e.g. a board
@@ -388,6 +404,7 @@ struct i2c_adapter {
 	int nr;
 	char name[48];
 	struct completion dev_released;
+	struct i2c_gpio_arbit *gpio_arbit;
 
 	struct mutex userspace_clients_lock;
 	struct list_head userspace_clients;
diff --git a/include/linux/of_i2c.h b/include/linux/of_i2c.h
index 1cb775f..c57ffba 100644
--- a/include/linux/of_i2c.h
+++ b/include/linux/of_i2c.h
@@ -24,6 +24,8 @@ extern struct i2c_client *of_find_i2c_device_by_node(struct device_node *node);
 extern struct i2c_adapter *of_find_i2c_adapter_by_node(
 						struct device_node *node);
 
+extern struct i2c_gpio_arbit *of_get_arbitrator_info(struct device_node *node,
+					struct i2c_gpio_arbit *i2c_arbit);
 #else
 static inline void of_i2c_register_devices(struct i2c_adapter *adap)
 {
-- 
1.7.9.5

  parent reply	other threads:[~2012-12-14  5:50 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-12-14  5:50 [PATCH 0/2] i2c: Implement generic gpio based bus arbitration Naveen Krishna Chatradhi
     [not found] ` <1355464254-12768-1-git-send-email-ch.naveen-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2012-12-14  5:50   ` Naveen Krishna Chatradhi [this message]
2012-12-14 16:06     ` [PATCH 1/2] i2c-core: Add gpio based bus arbitration implementation Stephen Warren
2012-12-15 14:21       ` Mark Brown
     [not found]         ` <20121215142135.GB22033-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
2013-01-24 11:13           ` Wolfram Sang
     [not found]             ` <20130124111329.GC12933-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2013-01-24 11:18               ` Mark Brown
     [not found]                 ` <20130124111845.GO4955-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
2013-01-24 11:39                   ` Wolfram Sang
     [not found]                     ` <20130124113948.GD12933-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2013-01-26  5:00                       ` Mark Brown
     [not found]     ` <1355464254-12768-2-git-send-email-ch.naveen-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2012-12-19 12:32       ` Grant Likely
2012-12-19 17:14         ` Mark Brown
2012-12-20  0:17           ` Simon Glass
     [not found]             ` <CAPnjgZ30MQS1OT3GOFLG9HntoD8NrzNw6bB_d1fiJEgHcMDGUA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-12-20  0:58               ` Grant Likely
     [not found]           ` <20121219171423.GW4985-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
2012-12-20  0:53             ` Grant Likely
2012-12-14  5:50 ` [PATCH 2/2] i2c-s3c2410: Add GPIO based bus arbitration functionality Naveen Krishna Chatradhi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1355464254-12768-2-git-send-email-ch.naveen@samsung.com \
    --to=ch.naveen-sze3o3uu22jbdgjk7y7tuq@public.gmane.org \
    --cc=ben-linux-elnMNo+KYs3YtjvyW6yDsg@public.gmane.org \
    --cc=broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org \
    --cc=devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org \
    --cc=grundler-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org \
    --cc=khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org \
    --cc=linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=naveen-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org \
    --cc=w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).