[PATCH 5/7] i2c: i2c_gpio: add devicetree support
Antony Pavlov
antonynpavlov at gmail.com
Mon Jun 23 14:21:11 PDT 2014
Signed-off-by: Antony Pavlov <antonynpavlov at gmail.com>
---
.../devicetree/bindings/gpio/gpio_i2c.txt | 32 +++++++++++++
drivers/i2c/busses/i2c-gpio.c | 54 +++++++++++++++++++--
include/of_gpio.h | 55 ++++++++++++++++++++++
3 files changed, 138 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/gpio/gpio_i2c.txt b/Documentation/devicetree/bindings/gpio/gpio_i2c.txt
new file mode 100644
index 0000000..4f8ec94
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio_i2c.txt
@@ -0,0 +1,32 @@
+Device-Tree bindings for i2c gpio driver
+
+Required properties:
+ - compatible = "i2c-gpio";
+ - gpios: sda and scl gpio
+
+
+Optional properties:
+ - i2c-gpio,sda-open-drain: sda as open drain
+ - i2c-gpio,scl-open-drain: scl as open drain
+ - i2c-gpio,scl-output-only: scl as output only
+ - i2c-gpio,delay-us: delay between GPIO operations (may depend on each platform)
+ - i2c-gpio,timeout-ms: timeout to get data
+
+Example nodes:
+
+i2c at 0 {
+ compatible = "i2c-gpio";
+ gpios = <&pioA 23 0 /* sda */
+ &pioA 24 0 /* scl */
+ >;
+ i2c-gpio,sda-open-drain;
+ i2c-gpio,scl-open-drain;
+ i2c-gpio,delay-us = <2>; /* ~100 kHz */
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rv3029c2 at 56 {
+ compatible = "rv3029c2";
+ reg = <0x56>;
+ };
+};
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
index 8b49c2c..29dc3d2 100644
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -15,6 +15,7 @@
#include <i2c/i2c-gpio.h>
#include <init.h>
#include <gpio.h>
+#include <of_gpio.h>
struct i2c_gpio_private_data {
struct i2c_adapter adap;
@@ -83,6 +84,38 @@ static int i2c_gpio_getscl(void *data)
return gpio_get_value(pdata->scl_pin);
}
+static int of_i2c_gpio_probe(struct device_node *np,
+ struct i2c_gpio_platform_data *pdata)
+{
+ u32 reg;
+
+ if (of_gpio_count(np) < 2)
+ return -ENODEV;
+
+ pdata->sda_pin = of_get_gpio(np, 0);
+ pdata->scl_pin = of_get_gpio(np, 1);
+
+ if (!gpio_is_valid(pdata->sda_pin) || !gpio_is_valid(pdata->scl_pin)) {
+ pr_err("%s: invalid GPIO pins, sda=%d/scl=%d\n",
+ np->full_name, pdata->sda_pin, pdata->scl_pin);
+ return -ENODEV;
+ }
+
+ of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay);
+
+ if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", ®))
+ pdata->timeout_ms = reg;
+
+ pdata->sda_is_open_drain =
+ of_property_read_bool(np, "i2c-gpio,sda-open-drain");
+ pdata->scl_is_open_drain =
+ of_property_read_bool(np, "i2c-gpio,scl-open-drain");
+ pdata->scl_is_output_only =
+ of_property_read_bool(np, "i2c-gpio,scl-output-only");
+
+ return 0;
+}
+
static int i2c_gpio_probe(struct device_d *dev)
{
struct i2c_gpio_private_data *priv;
@@ -97,9 +130,15 @@ static int i2c_gpio_probe(struct device_d *dev)
bit_data = &priv->bit_data;
pdata = &priv->pdata;
- if (!dev->platform_data)
- return -ENXIO;
- memcpy(pdata, dev->platform_data, sizeof(*pdata));
+ if (dev->device_node) {
+ ret = of_i2c_gpio_probe(dev->device_node, pdata);
+ if (ret)
+ return ret;
+ } else {
+ if (!dev->platform_data)
+ return -ENXIO;
+ memcpy(pdata, dev->platform_data, sizeof(*pdata));
+ }
ret = gpio_request(pdata->sda_pin, "sda");
if (ret)
@@ -144,6 +183,7 @@ static int i2c_gpio_probe(struct device_d *dev)
adap->algo_data = bit_data;
adap->dev.parent = dev;
+ adap->dev.device_node = dev->device_node;
adap->nr = dev->id;
ret = i2c_bit_add_numbered_bus(adap);
@@ -165,8 +205,16 @@ err_request_sda:
return ret;
}
+#if defined(CONFIG_OFDEVICE)
+static struct of_device_id i2c_gpio_dt_ids[] = {
+ { .compatible = "i2c-gpio", },
+ { /* sentinel */ }
+};
+#endif
+
static struct driver_d i2c_gpio_driver = {
.name = "i2c-gpio",
.probe = i2c_gpio_probe,
+ .of_compatible = DRV_OF_COMPAT(i2c_gpio_dt_ids),
};
device_platform_driver(i2c_gpio_driver);
diff --git a/include/of_gpio.h b/include/of_gpio.h
index d42b18e..95a454c 100644
--- a/include/of_gpio.h
+++ b/include/of_gpio.h
@@ -35,10 +35,65 @@ static inline int of_get_named_gpio_flags(struct device_node *np,
#endif /* CONFIG_OF_GPIO */
+/**
+ * of_gpio_named_count() - Count GPIOs for a device
+ * @np: device node to count GPIOs for
+ * @propname: property name containing gpio specifier(s)
+ *
+ * The function returns the count of GPIOs specified for a node.
+ * Note that the empty GPIO specifiers count too. Returns either
+ * Number of gpios defined in property,
+ * -EINVAL for an incorrectly formed gpios property, or
+ * -ENOENT for a missing gpios property
+ *
+ * Example:
+ * gpios = <0
+ * &gpio1 1 2
+ * 0
+ * &gpio2 3 4>;
+ *
+ * The above example defines four GPIOs, two of which are not specified.
+ * This function will return '4'
+ */
+static inline int of_gpio_named_count(struct device_node *np, const char* propname)
+{
+ return of_count_phandle_with_args(np, propname, "#gpio-cells");
+}
+
+/**
+ * of_gpio_count() - Count GPIOs for a device
+ * @np: device node to count GPIOs for
+ *
+ * Same as of_gpio_named_count, but hard coded to use the 'gpios' property
+ */
+static inline int of_gpio_count(struct device_node *np)
+{
+ return of_gpio_named_count(np, "gpios");
+}
+
+static inline int of_get_gpio_flags(struct device_node *np, int index,
+ enum of_gpio_flags *flags)
+{
+ return of_get_named_gpio_flags(np, "gpios", index, flags);
+}
+
static inline int of_get_named_gpio(struct device_node *np,
const char *list_name, int index)
{
return of_get_named_gpio_flags(np, list_name, index, NULL);
}
+/**
+ * of_get_gpio() - Get a GPIO number to use with GPIO API
+ * @np: device node to get GPIO from
+ * @index: index of the GPIO
+ *
+ * Returns GPIO number to use with Linux generic GPIO API, or one of the errno
+ * value on the error condition.
+ */
+static inline int of_get_gpio(struct device_node *np, int index)
+{
+ return of_get_gpio_flags(np, index, NULL);
+}
+
#endif
--
1.9.2
More information about the barebox
mailing list