summaryrefslogtreecommitdiffstats
path: root/bcm283x-gpio-expander.patch
diff options
context:
space:
mode:
authorPeter Robinson <pbrobinson@gmail.com>2018-03-03 22:51:13 +0000
committerPeter Robinson <pbrobinson@gmail.com>2018-03-03 22:51:13 +0000
commit60e272367a705ccdb067c5b1e33f28dfb9fea0b9 (patch)
treeb03ec11acd4b265daf323239ff788394a8354b60 /bcm283x-gpio-expander.patch
parent5860e766a687094612f3c37a219f248078148541 (diff)
downloadkernel-60e272367a705ccdb067c5b1e33f28dfb9fea0b9.tar.gz
kernel-60e272367a705ccdb067c5b1e33f28dfb9fea0b9.tar.xz
kernel-60e272367a705ccdb067c5b1e33f28dfb9fea0b9.zip
Add RPi3 GPIO expander, RPi fixes, OMAP serial update, general ARM fixes
Diffstat (limited to 'bcm283x-gpio-expander.patch')
-rw-r--r--bcm283x-gpio-expander.patch638
1 files changed, 638 insertions, 0 deletions
diff --git a/bcm283x-gpio-expander.patch b/bcm283x-gpio-expander.patch
new file mode 100644
index 000000000..55b7ec4d7
--- /dev/null
+++ b/bcm283x-gpio-expander.patch
@@ -0,0 +1,638 @@
+From patchwork Tue Feb 20 12:19:31 2018
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v5,1/5] ARM: bcm2835: sync firmware properties with downstream
+From: Baruch Siach <baruch@tkos.co.il>
+X-Patchwork-Id: 10229963
+Message-Id: <e7d1f1d0789f11d37957a8998bee23d035115aeb.1519128054.git.baruch@tkos.co.il>
+To: Linus Walleij <linus.walleij@linaro.org>,
+ Dave Stevenson <dave.stevenson@raspberrypi.org>,
+ Eric Anholt <eric@anholt.net>, Stefan Wahren <stefan.wahren@i2se.com>
+Cc: devicetree@vger.kernel.org, Baruch Siach <baruch@tkos.co.il>,
+ linux-gpio@vger.kernel.org, Michael Zoran <mzoran@crowfest.net>,
+ Rob Herring <robh+dt@kernel.org>, linux-rpi-kernel@lists.infradead.org,
+ Frank Rowand <frowand.list@gmail.com>, linux-arm-kernel@lists.infradead.org
+Date: Tue, 20 Feb 2018 14:19:31 +0200
+
+Add latest firmware property tags from the latest Raspberry Pi downstream
+kernel. This is needed for the GPIO tags, so we can control the GPIO
+multiplexor lines.
+
+Acked-by: Stefan Wahren <stefan.wahren@i2se.com>
+Signed-off-by: Baruch Siach <baruch@tkos.co.il>
+---
+v4: No change
+
+v3: Add Stefan's ack
+
+v2: No change
+---
+ include/soc/bcm2835/raspberrypi-firmware.h | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h
+index cb979ad90401..50df5b28d2c9 100644
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -63,6 +63,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_GET_MIN_VOLTAGE = 0x00030008,
+ RPI_FIRMWARE_GET_TURBO = 0x00030009,
+ RPI_FIRMWARE_GET_MAX_TEMPERATURE = 0x0003000a,
++ RPI_FIRMWARE_GET_STC = 0x0003000b,
+ RPI_FIRMWARE_ALLOCATE_MEMORY = 0x0003000c,
+ RPI_FIRMWARE_LOCK_MEMORY = 0x0003000d,
+ RPI_FIRMWARE_UNLOCK_MEMORY = 0x0003000e,
+@@ -72,12 +73,22 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_SET_ENABLE_QPU = 0x00030012,
+ RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014,
+ RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020,
++ RPI_FIRMWARE_GET_CUSTOMER_OTP = 0x00030021,
+ RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030,
+ RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001,
+ RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002,
+ RPI_FIRMWARE_SET_VOLTAGE = 0x00038003,
+ RPI_FIRMWARE_SET_TURBO = 0x00038009,
++ RPI_FIRMWARE_SET_CUSTOMER_OTP = 0x00038021,
+ RPI_FIRMWARE_SET_DOMAIN_STATE = 0x00038030,
++ RPI_FIRMWARE_GET_GPIO_STATE = 0x00030041,
++ RPI_FIRMWARE_SET_GPIO_STATE = 0x00038041,
++ RPI_FIRMWARE_SET_SDHOST_CLOCK = 0x00038042,
++ RPI_FIRMWARE_GET_GPIO_CONFIG = 0x00030043,
++ RPI_FIRMWARE_SET_GPIO_CONFIG = 0x00038043,
++ RPI_FIRMWARE_GET_PERIPH_REG = 0x00030045,
++ RPI_FIRMWARE_SET_PERIPH_REG = 0x00038045,
++
+
+ /* Dispmanx TAGS */
+ RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001,
+@@ -91,6 +102,8 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_OFFSET = 0x00040009,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE = 0x0004000b,
++ RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF = 0x0004000f,
++ RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF = 0x00040010,
+ RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 0x00044004,
+@@ -100,6 +113,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_OFFSET = 0x00044009,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN = 0x0004400a,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE = 0x0004400b,
++ RPI_FIRMWARE_FRAMEBUFFER_TEST_VSYNC = 0x0004400e,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH = 0x00048005,
+@@ -108,6 +122,10 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET = 0x00048009,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
++ RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF = 0x0004801f,
++ RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF = 0x00048020,
++ RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC = 0x0004800e,
++ RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f,
+
+ RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
+
+From patchwork Tue Feb 20 12:19:32 2018
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v5,2/5] dt-bindings: gpio: add raspberry pi GPIO expander binding
+From: Baruch Siach <baruch@tkos.co.il>
+X-Patchwork-Id: 10229965
+Message-Id: <f400b48cbcd8a138c39d4e8f63d6c1f569090dcc.1519128054.git.baruch@tkos.co.il>
+To: Linus Walleij <linus.walleij@linaro.org>,
+ Dave Stevenson <dave.stevenson@raspberrypi.org>,
+ Eric Anholt <eric@anholt.net>, Stefan Wahren <stefan.wahren@i2se.com>
+Cc: devicetree@vger.kernel.org, Baruch Siach <baruch@tkos.co.il>,
+ linux-gpio@vger.kernel.org, Michael Zoran <mzoran@crowfest.net>,
+ Rob Herring <robh+dt@kernel.org>, linux-rpi-kernel@lists.infradead.org,
+ Frank Rowand <frowand.list@gmail.com>, linux-arm-kernel@lists.infradead.org
+Date: Tue, 20 Feb 2018 14:19:32 +0200
+
+The Raspberry Pi 3 GPIO expander is controlled by the VC4 firmware over
+I2C. The firmware mailbox interface allows the ARM core to control the
+GPIO lines.
+
+Signed-off-by: Baruch Siach <baruch@tkos.co.il>
+Reviewed-by: Rob Herring <robh@kernel.org>
+---
+v5:
+ * Remove the 'firmware' property
+ * Note that the gpio node is a child of the firmware node
+
+v4:
+ * Move the example gpio node under the firmware node
+ * Rename gpio node name to plain 'gpio'
+
+v3:
+ * Rename node name.
+
+v2:
+ * Rename compatible string to raspberrypi,firmware-gpio
+---
+ .../bindings/gpio/raspberrypi,firmware-gpio.txt | 30 ++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/gpio/raspberrypi,firmware-gpio.txt
+
+diff --git a/Documentation/devicetree/bindings/gpio/raspberrypi,firmware-gpio.txt b/Documentation/devicetree/bindings/gpio/raspberrypi,firmware-gpio.txt
+new file mode 100644
+index 000000000000..ce97265e23ba
+--- /dev/null
++++ b/Documentation/devicetree/bindings/gpio/raspberrypi,firmware-gpio.txt
+@@ -0,0 +1,30 @@
++Raspberry Pi GPIO expander
++
++The Raspberry Pi 3 GPIO expander is controlled by the VC4 firmware. The
++firmware exposes a mailbox interface that allows the ARM core to control the
++GPIO lines on the expander.
++
++The Raspberry Pi GPIO expander node must be a child node of the Raspberry Pi
++firmware node.
++
++Required properties:
++
++- compatible : Should be "raspberrypi,firmware-gpio"
++- gpio-controller : Marks the device node as a gpio controller
++- #gpio-cells : Should be two. The first cell is the pin number, and
++ the second cell is used to specify the gpio polarity:
++ 0 = active high
++ 1 = active low
++
++Example:
++
++firmware: firmware-rpi {
++ compatible = "raspberrypi,bcm2835-firmware";
++ mboxes = <&mailbox>;
++
++ expgpio: gpio {
++ compatible = "raspberrypi,firmware-gpio";
++ gpio-controller;
++ #gpio-cells = <2>;
++ };
++};
+From patchwork Tue Feb 20 12:19:33 2018
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v5,
+ 3/5] gpio: raspberrypi-exp: Driver for RPi3 GPIO expander via mailbox
+ service
+From: Baruch Siach <baruch@tkos.co.il>
+X-Patchwork-Id: 10229967
+Message-Id: <8c34f287ee72b340fa9d693aa0e304b25541c74c.1519128054.git.baruch@tkos.co.il>
+To: Linus Walleij <linus.walleij@linaro.org>,
+ Dave Stevenson <dave.stevenson@raspberrypi.org>,
+ Eric Anholt <eric@anholt.net>, Stefan Wahren <stefan.wahren@i2se.com>
+Cc: devicetree@vger.kernel.org, Baruch Siach <baruch@tkos.co.il>,
+ linux-gpio@vger.kernel.org, Michael Zoran <mzoran@crowfest.net>,
+ Rob Herring <robh+dt@kernel.org>, linux-rpi-kernel@lists.infradead.org,
+ Frank Rowand <frowand.list@gmail.com>, linux-arm-kernel@lists.infradead.org
+Date: Tue, 20 Feb 2018 14:19:33 +0200
+
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+
+Pi3 and Compute Module 3 have a GPIO expander that the
+VPU communicates with.
+There is a mailbox service that now allows control of this
+expander, so add a kernel driver that can make use of it.
+
+Reviewed-by: Stefan Wahren <stefan.wahren@i2se.com>
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Signed-off-by: Baruch Siach <baruch@tkos.co.il>
+---
+v5:
+ * Use the parent node to find the firmware
+
+v4:
+ * Don't set the .owner driver field
+ * Add Stefan's review tag
+
+v3:
+ * Tweak Kconfig driver prompt
+ * Make GPIO_RASPBERRYPI_EXP tristate
+ * Make COMPILE_TEST independent of RASPBERRYPI_FIRMWARE
+ * Remove redundant DMA header
+ * Use less code lines for dev_err()
+ * Check rpi_exp_gpio_get_polarity() return value
+ * Remove redundant platform_set_drvdata() call
+
+v2:
+ * Rename driver to gpio-raspberrypi-exp
+ * Populate the gpiochip parent device pointer
+ * Use macro for the mailbox base GPIO number
+ * Drop linux/gpio.h and GPIOF_DIR_*
+ * Check and print firmware error value
+ * Use devm_gpiochip_add_data(); drop .remove
+ * A few more minor tweaks
+---
+ drivers/gpio/Kconfig | 9 ++
+ drivers/gpio/Makefile | 1 +
+ drivers/gpio/gpio-raspberrypi-exp.c | 252 ++++++++++++++++++++++++++++++++++++
+ 3 files changed, 262 insertions(+)
+ create mode 100644 drivers/gpio/gpio-raspberrypi-exp.c
+
+diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
+index 8dbb2280538d..fd0562a37f68 100644
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -122,6 +122,15 @@ config GPIO_ATH79
+ Select this option to enable GPIO driver for
+ Atheros AR71XX/AR724X/AR913X SoC devices.
+
++config GPIO_RASPBERRYPI_EXP
++ tristate "Raspberry Pi 3 GPIO Expander"
++ default RASPBERRYPI_FIRMWARE
++ depends on OF_GPIO
++ depends on (ARCH_BCM2835 && RASPBERRYPI_FIRMWARE) || COMPILE_TEST
++ help
++ Turn on GPIO support for the expander on Raspberry Pi 3 boards, using
++ the firmware mailbox to communicate with VideoCore on BCM283x chips.
++
+ config GPIO_BCM_KONA
+ bool "Broadcom Kona GPIO"
+ depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST)
+diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
+index cccb0d40846c..76dc0a02bd56 100644
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -32,6 +32,7 @@ obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
+ obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
+ obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
+ obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o
++obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
+ obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
+ obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
+ obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
+diff --git a/drivers/gpio/gpio-raspberrypi-exp.c b/drivers/gpio/gpio-raspberrypi-exp.c
+new file mode 100644
+index 000000000000..d6d36d537e37
+--- /dev/null
++++ b/drivers/gpio/gpio-raspberrypi-exp.c
+@@ -0,0 +1,252 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Raspberry Pi 3 expander GPIO driver
++ *
++ * Uses the firmware mailbox service to communicate with the
++ * GPIO expander on the VPU.
++ *
++ * Copyright (C) 2017 Raspberry Pi Trading Ltd.
++ */
++
++#include <linux/err.h>
++#include <linux/gpio/driver.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <soc/bcm2835/raspberrypi-firmware.h>
++
++#define MODULE_NAME "raspberrypi-exp-gpio"
++#define NUM_GPIO 8
++
++#define RPI_EXP_GPIO_BASE 128
++
++#define RPI_EXP_GPIO_DIR_IN 0
++#define RPI_EXP_GPIO_DIR_OUT 1
++
++struct rpi_exp_gpio {
++ struct gpio_chip gc;
++ struct rpi_firmware *fw;
++};
++
++/* VC4 firmware mailbox interface data structures */
++
++struct gpio_set_config {
++ u32 gpio;
++ u32 direction;
++ u32 polarity;
++ u32 term_en;
++ u32 term_pull_up;
++ u32 state;
++};
++
++struct gpio_get_config {
++ u32 gpio;
++ u32 direction;
++ u32 polarity;
++ u32 term_en;
++ u32 term_pull_up;
++};
++
++struct gpio_get_set_state {
++ u32 gpio;
++ u32 state;
++};
++
++static int rpi_exp_gpio_get_polarity(struct gpio_chip *gc, unsigned int off)
++{
++ struct rpi_exp_gpio *gpio;
++ struct gpio_get_config get;
++ int ret;
++
++ gpio = gpiochip_get_data(gc);
++
++ get.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
++
++ ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_CONFIG,
++ &get, sizeof(get));
++ if (ret || get.gpio != 0) {
++ dev_err(gc->parent, "Failed to get GPIO %u config (%d %x)\n",
++ off, ret, get.gpio);
++ return ret ? ret : -EIO;
++ }
++ return get.polarity;
++}
++
++static int rpi_exp_gpio_dir_in(struct gpio_chip *gc, unsigned int off)
++{
++ struct rpi_exp_gpio *gpio;
++ struct gpio_set_config set_in;
++ int ret;
++
++ gpio = gpiochip_get_data(gc);
++
++ set_in.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
++ set_in.direction = RPI_EXP_GPIO_DIR_IN;
++ set_in.term_en = 0; /* termination disabled */
++ set_in.term_pull_up = 0; /* n/a as termination disabled */
++ set_in.state = 0; /* n/a as configured as an input */
++
++ ret = rpi_exp_gpio_get_polarity(gc, off);
++ if (ret < 0)
++ return ret;
++ set_in.polarity = ret; /* Retain existing setting */
++
++ ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_CONFIG,
++ &set_in, sizeof(set_in));
++ if (ret || set_in.gpio != 0) {
++ dev_err(gc->parent, "Failed to set GPIO %u to input (%d %x)\n",
++ off, ret, set_in.gpio);
++ return ret ? ret : -EIO;
++ }
++ return 0;
++}
++
++static int rpi_exp_gpio_dir_out(struct gpio_chip *gc, unsigned int off, int val)
++{
++ struct rpi_exp_gpio *gpio;
++ struct gpio_set_config set_out;
++ int ret;
++
++ gpio = gpiochip_get_data(gc);
++
++ set_out.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
++ set_out.direction = RPI_EXP_GPIO_DIR_OUT;
++ set_out.term_en = 0; /* n/a as an output */
++ set_out.term_pull_up = 0; /* n/a as termination disabled */
++ set_out.state = val; /* Output state */
++
++ ret = rpi_exp_gpio_get_polarity(gc, off);
++ if (ret < 0)
++ return ret;
++ set_out.polarity = ret; /* Retain existing setting */
++
++ ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_CONFIG,
++ &set_out, sizeof(set_out));
++ if (ret || set_out.gpio != 0) {
++ dev_err(gc->parent, "Failed to set GPIO %u to output (%d %x)\n",
++ off, ret, set_out.gpio);
++ return ret ? ret : -EIO;
++ }
++ return 0;
++}
++
++static int rpi_exp_gpio_get_direction(struct gpio_chip *gc, unsigned int off)
++{
++ struct rpi_exp_gpio *gpio;
++ struct gpio_get_config get;
++ int ret;
++
++ gpio = gpiochip_get_data(gc);
++
++ get.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
++
++ ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_CONFIG,
++ &get, sizeof(get));
++ if (ret || get.gpio != 0) {
++ dev_err(gc->parent,
++ "Failed to get GPIO %u config (%d %x)\n", off, ret,
++ get.gpio);
++ return ret ? ret : -EIO;
++ }
++ return !get.direction;
++}
++
++static int rpi_exp_gpio_get(struct gpio_chip *gc, unsigned int off)
++{
++ struct rpi_exp_gpio *gpio;
++ struct gpio_get_set_state get;
++ int ret;
++
++ gpio = gpiochip_get_data(gc);
++
++ get.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
++ get.state = 0; /* storage for returned value */
++
++ ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_STATE,
++ &get, sizeof(get));
++ if (ret || get.gpio != 0) {
++ dev_err(gc->parent,
++ "Failed to get GPIO %u state (%d %x)\n", off, ret,
++ get.gpio);
++ return ret ? ret : -EIO;
++ }
++ return !!get.state;
++}
++
++static void rpi_exp_gpio_set(struct gpio_chip *gc, unsigned int off, int val)
++{
++ struct rpi_exp_gpio *gpio;
++ struct gpio_get_set_state set;
++ int ret;
++
++ gpio = gpiochip_get_data(gc);
++
++ set.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
++ set.state = val; /* Output state */
++
++ ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_STATE,
++ &set, sizeof(set));
++ if (ret || set.gpio != 0)
++ dev_err(gc->parent,
++ "Failed to set GPIO %u state (%d %x)\n", off, ret,
++ set.gpio);
++}
++
++static int rpi_exp_gpio_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct device_node *np = dev->of_node;
++ struct device_node *fw_node;
++ struct rpi_firmware *fw;
++ struct rpi_exp_gpio *rpi_gpio;
++
++ fw_node = of_get_parent(np);
++ if (!fw_node) {
++ dev_err(dev, "Missing firmware node\n");
++ return -ENOENT;
++ }
++
++ fw = rpi_firmware_get(fw_node);
++ if (!fw)
++ return -EPROBE_DEFER;
++
++ rpi_gpio = devm_kzalloc(dev, sizeof(*rpi_gpio), GFP_KERNEL);
++ if (!rpi_gpio)
++ return -ENOMEM;
++
++ rpi_gpio->fw = fw;
++ rpi_gpio->gc.parent = dev;
++ rpi_gpio->gc.label = MODULE_NAME;
++ rpi_gpio->gc.owner = THIS_MODULE;
++ rpi_gpio->gc.of_node = np;
++ rpi_gpio->gc.base = -1;
++ rpi_gpio->gc.ngpio = NUM_GPIO;
++
++ rpi_gpio->gc.direction_input = rpi_exp_gpio_dir_in;
++ rpi_gpio->gc.direction_output = rpi_exp_gpio_dir_out;
++ rpi_gpio->gc.get_direction = rpi_exp_gpio_get_direction;
++ rpi_gpio->gc.get = rpi_exp_gpio_get;
++ rpi_gpio->gc.set = rpi_exp_gpio_set;
++ rpi_gpio->gc.can_sleep = true;
++
++ return devm_gpiochip_add_data(dev, &rpi_gpio->gc, rpi_gpio);
++}
++
++static const struct of_device_id rpi_exp_gpio_ids[] = {
++ { .compatible = "raspberrypi,firmware-gpio" },
++ { }
++};
++MODULE_DEVICE_TABLE(of, rpi_exp_gpio_ids);
++
++static struct platform_driver rpi_exp_gpio_driver = {
++ .driver = {
++ .name = MODULE_NAME,
++ .of_match_table = of_match_ptr(rpi_exp_gpio_ids),
++ },
++ .probe = rpi_exp_gpio_probe,
++};
++module_platform_driver(rpi_exp_gpio_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.org>");
++MODULE_DESCRIPTION("Raspberry Pi 3 expander GPIO driver");
++MODULE_ALIAS("platform:rpi-exp-gpio");
+From patchwork Tue Feb 20 12:19:34 2018
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v5,4/5] ARM: dts: bcm2835: make the firmware node into a bus
+From: Baruch Siach <baruch@tkos.co.il>
+X-Patchwork-Id: 10229961
+Message-Id: <43f9082a6835df6d7bcd3e16d79db687c52826d2.1519128054.git.baruch@tkos.co.il>
+To: Linus Walleij <linus.walleij@linaro.org>,
+ Dave Stevenson <dave.stevenson@raspberrypi.org>,
+ Eric Anholt <eric@anholt.net>, Stefan Wahren <stefan.wahren@i2se.com>
+Cc: devicetree@vger.kernel.org, Baruch Siach <baruch@tkos.co.il>,
+ linux-gpio@vger.kernel.org, Michael Zoran <mzoran@crowfest.net>,
+ Rob Herring <robh+dt@kernel.org>, linux-rpi-kernel@lists.infradead.org,
+ Frank Rowand <frowand.list@gmail.com>, linux-arm-kernel@lists.infradead.org
+Date: Tue, 20 Feb 2018 14:19:34 +0200
+
+This allows adding devices for which the firmware exposes control interface
+via the mailbox. An example of such device is the GPIO expander.
+
+Signed-off-by: Baruch Siach <baruch@tkos.co.il>
+Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
+---
+v4: New patch in this series
+---
+ arch/arm/boot/dts/bcm2835-rpi.dtsi | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
+index e36c392a2b8f..0198bd46ef7c 100644
+--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
+@@ -18,7 +18,9 @@
+
+ soc {
+ firmware: firmware {
+- compatible = "raspberrypi,bcm2835-firmware";
++ compatible = "raspberrypi,bcm2835-firmware", "simple-bus";
++ #address-cells = <0>;
++ #size-cells = <0>;
+ mboxes = <&mailbox>;
+ };
+
+From patchwork Tue Feb 20 12:19:35 2018
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v5,5/5] ARM: dts: bcm2837-rpi-3-b: add GPIO expander
+From: Baruch Siach <baruch@tkos.co.il>
+X-Patchwork-Id: 10229995
+Message-Id: <a6d59692dc4847e0b1639a26542e28c95ad5240f.1519128054.git.baruch@tkos.co.il>
+To: Linus Walleij <linus.walleij@linaro.org>,
+ Dave Stevenson <dave.stevenson@raspberrypi.org>,
+ Eric Anholt <eric@anholt.net>, Stefan Wahren <stefan.wahren@i2se.com>
+Cc: devicetree@vger.kernel.org, Baruch Siach <baruch@tkos.co.il>,
+ linux-gpio@vger.kernel.org, Michael Zoran <mzoran@crowfest.net>,
+ Rob Herring <robh+dt@kernel.org>, linux-rpi-kernel@lists.infradead.org,
+ Frank Rowand <frowand.list@gmail.com>, linux-arm-kernel@lists.infradead.org
+Date: Tue, 20 Feb 2018 14:19:35 +0200
+
+Add a description of the RPi3 GPIO expander that the VC4 firmware controls.
+
+Acked-by: Stefan Wahren <stefan.wahren@i2se.com>
+Signed-off-by: Baruch Siach <baruch@tkos.co.il>
+Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
+---
+v5:
+ * Drop the 'firmware' property
+
+v4:
+ * Move the gpio node under the firmware node
+ * Rename the gpio node to plain 'gpio'
+ * Add Stefan's ack
+
+v3:
+ * List GPIO names one per line.
+
+v2:
+ * Move GPIO expander node out of the soc container
+ * Rename compatible string
+ * Add gpio-line-names property
+---
+ arch/arm/boot/dts/bcm2837-rpi-3-b.dts | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
+index 3e4ed7c5b0b3..0b31d995a066 100644
+--- a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
++++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
+@@ -25,6 +25,23 @@
+ };
+ };
+
++&firmware {
++ expgpio: gpio {
++ compatible = "raspberrypi,firmware-gpio";
++ gpio-controller;
++ #gpio-cells = <2>;
++ gpio-line-names = "BT_ON",
++ "WL_ON",
++ "STATUS_LED",
++ "LAN_RUN",
++ "HPD_N",
++ "CAM_GPIO0",
++ "CAM_GPIO1",
++ "PWR_LOW_N";
++ status = "okay";
++ };
++};
++
+ /* uart0 communicates with the BT module */
+ &uart0 {
+ pinctrl-names = "default";