[PATCH 3/3] gpio: sx150x: add dts support for sx150x driver

Barry Song 21cnbao at gmail.com
Thu Dec 4 04:12:10 PST 2014


From: Wei Chen <Wei.Chen at csr.com>

Current sx150x gpio expander driver doesn't support DT. Now we added DT support
for this driver.

Signed-off-by: Wei Chen <Wei.Chen at csr.com>
Signed-off-by: Barry Song <Baohua.Song at csr.com>
---
 .../devicetree/bindings/gpio/gpio-sx150x.txt       | 69 ++++++++++++++++++
 .../devicetree/bindings/vendor-prefixes.txt        |  1 +
 drivers/gpio/gpio-sx150x.c                         | 83 +++++++++++++++++++++-
 3 files changed, 151 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/gpio/gpio-sx150x.txt

diff --git a/Documentation/devicetree/bindings/gpio/gpio-sx150x.txt b/Documentation/devicetree/bindings/gpio/gpio-sx150x.txt
new file mode 100644
index 0000000..7f8a61b
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-sx150x.txt
@@ -0,0 +1,69 @@
+SEMTECH SX150x GPIO expander bindings
+
+
+Required properties:
+
+- compatible: should be "semtech,sx1506q",
+			"semtech,sx1508q",
+			"semtech,sx1509q".
+
+- reg: The I2C slave address for this device.
+
+- interrupt-parent: phandle of the parent interrupt controller.
+
+- interrupts: Interrupt specifier for the controllers interrupt.
+
+- #gpio-cells: Should be 2. The first cell is the GPIO number and the
+		second cell is used to specify optional parameters:
+		bit 0: polarity (0: normal, 1: inverted)
+
+- gpio-controller: Marks the device as a GPIO controller.
+
+- interrupt-controller: Marks the device as a interrupt controller.
+
+Optional properties:
+- oscio_is_gpo: Boolean.
+	Whether the HW considers OSCIO as a GPO instead of as an
+	oscillator.
+
+- reset_during_probe: Boolean.
+	Whether the HW supports full reset of the chip at the beginning
+	of the probe.
+
+-pullup_ena:A bit-mask which enables or disables the pull-up resistor
+	for each IO line in the expander. = <0x0>;
+
+-pulldn_ena:A bit-mask which enables-or disables the pull-down resistor
+	for each IO line in the expander.
+
+-open_drain_ena:A bit-mask which enables-or disables open-drain
+	operation for each IO line in the expander.
+
+-polarity: A bit-mask which enables polarity inversion for each IO line
+	in the expander.
+
+The GPIO expander can optionally be used as an interrupt controller, in
+which case it uses the default two cell specifier as described in
+Documentation/devicetree/bindings/interrupt-controller/interrupts.txt.
+
+Example:
+
+	i2c_gpio_expander at 20{
+		#gpio-cells = <2>;
+		#interrupt-cells = <2>;
+		compatible = "semtech,sx1506q";
+		reg = <0x20>;
+		interrupt-parent = <&gpio_1>;
+		interrupts = <16 0>;
+
+		gpio-controller;
+		interrupt-controller;
+
+		oscio_is_gpo;
+		reset_during_probe;
+
+		pullup_ena = <0x01>;
+		pulldn_ena = <0x10>;
+		open_drain_ena = <0x40>;
+		polarity = <0x02>;
+	};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index c177cd7..6968148 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -140,6 +140,7 @@ sandisk	Sandisk Corporation
 sbs	Smart Battery System
 schindler	Schindler
 seagate	Seagate Technology PLC
+semtech	Semtech Corporation
 sil	Silicon Image
 silabs	Silicon Laboratories
 simtek
diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c
index b32fb38..28d2f03 100644
--- a/drivers/gpio/gpio-sx150x.c
+++ b/drivers/gpio/gpio-sx150x.c
@@ -23,6 +23,11 @@
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/i2c/sx150x.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
 
 #define NO_UPDATE_PENDING	-1
 
@@ -147,6 +152,13 @@ static const struct i2c_device_id sx150x_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, sx150x_id);
 
+static const struct of_device_id sx150x_dt_id[] = {
+	{ .compatible = "semtech,sx1508q", .data = &sx150x_devices[0]},
+	{ .compatible = "semtech,sx1509q", .data = &sx150x_devices[1]},
+	{ .compatible = "semtech,sx1506q", .data = &sx150x_devices[2]},
+	{},
+};
+
 static s32 sx150x_i2c_write(struct i2c_client *client, u8 reg, u8 val)
 {
 	s32 err = i2c_smbus_write_byte_data(client, reg, val);
@@ -472,6 +484,8 @@ static void sx150x_init_chip(struct sx150x_chip *chip,
 	chip->gpio_chip.base             = pdata->gpio_base;
 	chip->gpio_chip.can_sleep        = true;
 	chip->gpio_chip.ngpio            = chip->dev_cfg->ngpios;
+	chip->gpio_chip.of_node          = client->dev.of_node;
+	chip->gpio_chip.of_gpio_n_cells  = 2;
 	if (pdata->oscio_is_gpo)
 		++chip->gpio_chip.ngpio;
 
@@ -607,6 +621,66 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip,
 	return err;
 }
 
+static struct sx150x_platform_data *of_sx150x_get_platdata(
+					struct i2c_client *client)
+{
+	int rc, gpio;
+	struct sx150x_platform_data *pdata;
+	struct device_node *np;
+
+	if (!client->dev.of_node)
+		return NULL;
+
+	np = client->dev.of_node;
+
+	pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return ERR_PTR(-ENOMEM);
+
+	gpio = of_get_named_gpio(np, "int-gpios", 0);
+	if (gpio_is_valid(gpio)) {
+		rc = devm_gpio_request_one(&client->dev, gpio,
+			GPIOF_DIR_IN, "sx150x_interrupt");
+		if (rc)
+			return ERR_PTR(rc);
+	}
+
+	pdata->irq_summary = irq_of_parse_and_map(np, 0);
+	if (!pdata->irq_summary)
+		return ERR_PTR(-EPROBE_DEFER);
+
+	pdata->oscio_is_gpo = of_property_read_bool(np, "oscio_is_gpo");
+	pdata->reset_during_probe =
+			of_property_read_bool(np, "reset_during_probe");
+
+	rc = of_property_read_u16(np, "pullup_ena",
+				&pdata->io_pullup_ena);
+	if (rc)
+		pdata->io_pullup_ena = 0;
+
+	rc = of_property_read_u16(np, "pulldn_ena",
+				&pdata->io_pulldn_ena);
+	if (rc)
+		pdata->io_pulldn_ena = 0;
+
+	rc = of_property_read_u16(np, "open_drain_ena",
+				&pdata->io_open_drain_ena);
+	if (rc)
+		pdata->io_open_drain_ena = 0;
+
+	rc = of_property_read_u16(np, "polarity",
+				&pdata->io_polarity);
+	if (rc)
+		pdata->io_polarity = 0;
+
+	/* Let OF gpiochip_add to detect dynamical gpio_base & irq_base */
+	pdata->gpio_base = -1;
+	/* We should use the dynamical irq_base */
+	pdata->irq_base = 0;
+
+	return pdata;
+}
+
 static int sx150x_probe(struct i2c_client *client,
 				const struct i2c_device_id *id)
 {
@@ -617,8 +691,13 @@ static int sx150x_probe(struct i2c_client *client,
 	int rc;
 
 	pdata = dev_get_platdata(&client->dev);
-	if (!pdata)
-		return -EINVAL;
+	if (!pdata) {
+		pdata = of_sx150x_get_platdata(client);
+		if (!pdata)
+			return -EINVAL;
+		else if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+	}
 
 	if (!i2c_check_functionality(client->adapter, i2c_funcs))
 		return -ENOSYS;
-- 
2.2.0




More information about the linux-arm-kernel mailing list