0edfe4f
From 08af112e79cab22f318ca0ad1a48187eee5ac2f0 Mon Sep 17 00:00:00 2001
37d0749
From: Baruch Siach <baruch@tkos.co.il>
37d0749
Date: Tue, 20 Feb 2018 14:19:31 +0200
0edfe4f
Subject: soc: bcm2835: sync firmware properties with downstream
37d0749
37d0749
Add latest firmware property tags from the latest Raspberry Pi downstream
37d0749
kernel. This is needed for the GPIO tags, so we can control the GPIO
37d0749
multiplexor lines.
37d0749
37d0749
Acked-by: Stefan Wahren <stefan.wahren@i2se.com>
37d0749
Signed-off-by: Baruch Siach <baruch@tkos.co.il>
0edfe4f
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
37d0749
---
37d0749
 include/soc/bcm2835/raspberrypi-firmware.h | 18 ++++++++++++++++++
37d0749
 1 file changed, 18 insertions(+)
37d0749
37d0749
diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h
0edfe4f
index cb979ad..50df5b2 100644
37d0749
--- a/include/soc/bcm2835/raspberrypi-firmware.h
37d0749
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
37d0749
@@ -63,6 +63,7 @@ enum rpi_firmware_property_tag {
37d0749
 	RPI_FIRMWARE_GET_MIN_VOLTAGE =                        0x00030008,
37d0749
 	RPI_FIRMWARE_GET_TURBO =                              0x00030009,
37d0749
 	RPI_FIRMWARE_GET_MAX_TEMPERATURE =                    0x0003000a,
37d0749
+	RPI_FIRMWARE_GET_STC =                                0x0003000b,
37d0749
 	RPI_FIRMWARE_ALLOCATE_MEMORY =                        0x0003000c,
37d0749
 	RPI_FIRMWARE_LOCK_MEMORY =                            0x0003000d,
37d0749
 	RPI_FIRMWARE_UNLOCK_MEMORY =                          0x0003000e,
37d0749
@@ -72,12 +73,22 @@ enum rpi_firmware_property_tag {
37d0749
 	RPI_FIRMWARE_SET_ENABLE_QPU =                         0x00030012,
37d0749
 	RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE =       0x00030014,
37d0749
 	RPI_FIRMWARE_GET_EDID_BLOCK =                         0x00030020,
37d0749
+	RPI_FIRMWARE_GET_CUSTOMER_OTP =                       0x00030021,
37d0749
 	RPI_FIRMWARE_GET_DOMAIN_STATE =                       0x00030030,
37d0749
 	RPI_FIRMWARE_SET_CLOCK_STATE =                        0x00038001,
37d0749
 	RPI_FIRMWARE_SET_CLOCK_RATE =                         0x00038002,
37d0749
 	RPI_FIRMWARE_SET_VOLTAGE =                            0x00038003,
37d0749
 	RPI_FIRMWARE_SET_TURBO =                              0x00038009,
37d0749
+	RPI_FIRMWARE_SET_CUSTOMER_OTP =                       0x00038021,
37d0749
 	RPI_FIRMWARE_SET_DOMAIN_STATE =                       0x00038030,
37d0749
+	RPI_FIRMWARE_GET_GPIO_STATE =                         0x00030041,
37d0749
+	RPI_FIRMWARE_SET_GPIO_STATE =                         0x00038041,
37d0749
+	RPI_FIRMWARE_SET_SDHOST_CLOCK =                       0x00038042,
37d0749
+	RPI_FIRMWARE_GET_GPIO_CONFIG =                        0x00030043,
37d0749
+	RPI_FIRMWARE_SET_GPIO_CONFIG =                        0x00038043,
37d0749
+	RPI_FIRMWARE_GET_PERIPH_REG =                         0x00030045,
37d0749
+	RPI_FIRMWARE_SET_PERIPH_REG =                         0x00038045,
37d0749
+
37d0749
 
37d0749
 	/* Dispmanx TAGS */
37d0749
 	RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE =                   0x00040001,
37d0749
@@ -91,6 +102,8 @@ enum rpi_firmware_property_tag {
37d0749
 	RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_OFFSET =         0x00040009,
37d0749
 	RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN =               0x0004000a,
37d0749
 	RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE =                0x0004000b,
37d0749
+	RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF =               0x0004000f,
37d0749
+	RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF =            0x00040010,
37d0749
 	RPI_FIRMWARE_FRAMEBUFFER_RELEASE =                    0x00048001,
37d0749
 	RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
37d0749
 	RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT =  0x00044004,
37d0749
@@ -100,6 +113,7 @@ enum rpi_firmware_property_tag {
37d0749
 	RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_OFFSET =        0x00044009,
37d0749
 	RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN =              0x0004400a,
37d0749
 	RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE =               0x0004400b,
37d0749
+	RPI_FIRMWARE_FRAMEBUFFER_TEST_VSYNC =                 0x0004400e,
37d0749
 	RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT =  0x00048003,
37d0749
 	RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT =   0x00048004,
37d0749
 	RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH =                  0x00048005,
37d0749
@@ -108,6 +122,10 @@ enum rpi_firmware_property_tag {
37d0749
 	RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET =         0x00048009,
37d0749
 	RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN =               0x0004800a,
37d0749
 	RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE =                0x0004800b,
37d0749
+	RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF =               0x0004801f,
37d0749
+	RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF =            0x00048020,
37d0749
+	RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC =                  0x0004800e,
37d0749
+	RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT =              0x0004800f,
37d0749
 
37d0749
 	RPI_FIRMWARE_VCHIQ_INIT =                             0x00048010,
37d0749
 
0edfe4f
-- 
0edfe4f
cgit v1.1
0edfe4f
From 9777d8099a4a9df1625b4caaee1388c0158478c5 Mon Sep 17 00:00:00 2001
37d0749
From: Baruch Siach <baruch@tkos.co.il>
37d0749
Date: Tue, 20 Feb 2018 14:19:32 +0200
0edfe4f
Subject: dt-bindings: gpio: add raspberry pi GPIO expander binding
37d0749
37d0749
The Raspberry Pi 3 GPIO expander is controlled by the VC4 firmware over
37d0749
I2C. The firmware mailbox interface allows the ARM core to control the
37d0749
GPIO lines.
37d0749
37d0749
Signed-off-by: Baruch Siach <baruch@tkos.co.il>
37d0749
Reviewed-by: Rob Herring <robh@kernel.org>
0edfe4f
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
37d0749
---
37d0749
 .../bindings/gpio/raspberrypi,firmware-gpio.txt    | 30 ++++++++++++++++++++++
37d0749
 1 file changed, 30 insertions(+)
37d0749
 create mode 100644 Documentation/devicetree/bindings/gpio/raspberrypi,firmware-gpio.txt
37d0749
37d0749
diff --git a/Documentation/devicetree/bindings/gpio/raspberrypi,firmware-gpio.txt b/Documentation/devicetree/bindings/gpio/raspberrypi,firmware-gpio.txt
37d0749
new file mode 100644
0edfe4f
index 0000000..ce97265
37d0749
--- /dev/null
37d0749
+++ b/Documentation/devicetree/bindings/gpio/raspberrypi,firmware-gpio.txt
37d0749
@@ -0,0 +1,30 @@
37d0749
+Raspberry Pi GPIO expander
37d0749
+
37d0749
+The Raspberry Pi 3 GPIO expander is controlled by the VC4 firmware. The
37d0749
+firmware exposes a mailbox interface that allows the ARM core to control the
37d0749
+GPIO lines on the expander.
37d0749
+
37d0749
+The Raspberry Pi GPIO expander node must be a child node of the Raspberry Pi
37d0749
+firmware node.
37d0749
+
37d0749
+Required properties:
37d0749
+
37d0749
+- compatible : Should be "raspberrypi,firmware-gpio"
37d0749
+- gpio-controller : Marks the device node as a gpio controller
37d0749
+- #gpio-cells : Should be two.  The first cell is the pin number, and
37d0749
+  the second cell is used to specify the gpio polarity:
37d0749
+  0 = active high
37d0749
+  1 = active low
37d0749
+
37d0749
+Example:
37d0749
+
37d0749
+firmware: firmware-rpi {
37d0749
+	compatible = "raspberrypi,bcm2835-firmware";
37d0749
+	mboxes = <&mailbox>;
37d0749
+
37d0749
+	expgpio: gpio {
37d0749
+		 compatible = "raspberrypi,firmware-gpio";
37d0749
+		 gpio-controller;
37d0749
+		 #gpio-cells = <2>;
37d0749
+	 };
37d0749
+};
0edfe4f
-- 
0edfe4f
cgit v1.1
0edfe4f
From a98d90e7d588045716c3c85d63f93dc3f15a079b Mon Sep 17 00:00:00 2001
37d0749
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
0edfe4f
Date: Tue, 20 Feb 2018 14:19:33 +0200
0edfe4f
Subject: gpio: raspberrypi-exp: Driver for RPi3 GPIO expander via mailbox
0edfe4f
 service
37d0749
37d0749
Pi3 and Compute Module 3 have a GPIO expander that the
37d0749
VPU communicates with.
37d0749
There is a mailbox service that now allows control of this
37d0749
expander, so add a kernel driver that can make use of it.
37d0749
37d0749
Reviewed-by: Stefan Wahren <stefan.wahren@i2se.com>
37d0749
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
37d0749
Signed-off-by: Baruch Siach <baruch@tkos.co.il>
0edfe4f
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
37d0749
---
37d0749
 drivers/gpio/Kconfig                |   9 ++
37d0749
 drivers/gpio/Makefile               |   1 +
37d0749
 drivers/gpio/gpio-raspberrypi-exp.c | 252 ++++++++++++++++++++++++++++++++++++
37d0749
 3 files changed, 262 insertions(+)
37d0749
 create mode 100644 drivers/gpio/gpio-raspberrypi-exp.c
37d0749
37d0749
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
0edfe4f
index 8dbb228..fd0562a 100644
37d0749
--- a/drivers/gpio/Kconfig
37d0749
+++ b/drivers/gpio/Kconfig
37d0749
@@ -122,6 +122,15 @@ config GPIO_ATH79
37d0749
 	  Select this option to enable GPIO driver for
37d0749
 	  Atheros AR71XX/AR724X/AR913X SoC devices.
37d0749
 
37d0749
+config GPIO_RASPBERRYPI_EXP
37d0749
+	tristate "Raspberry Pi 3 GPIO Expander"
37d0749
+	default RASPBERRYPI_FIRMWARE
37d0749
+	depends on OF_GPIO
37d0749
+	depends on (ARCH_BCM2835 && RASPBERRYPI_FIRMWARE) || COMPILE_TEST
37d0749
+	help
37d0749
+	  Turn on GPIO support for the expander on Raspberry Pi 3 boards, using
37d0749
+	  the firmware mailbox to communicate with VideoCore on BCM283x chips.
37d0749
+
37d0749
 config GPIO_BCM_KONA
37d0749
 	bool "Broadcom Kona GPIO"
37d0749
 	depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST)
37d0749
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
0edfe4f
index cccb0d4..76dc0a0 100644
37d0749
--- a/drivers/gpio/Makefile
37d0749
+++ b/drivers/gpio/Makefile
37d0749
@@ -32,6 +32,7 @@ obj-$(CONFIG_GPIO_AMDPT)	+= gpio-amdpt.o
37d0749
 obj-$(CONFIG_GPIO_ARIZONA)	+= gpio-arizona.o
37d0749
 obj-$(CONFIG_GPIO_ATH79)	+= gpio-ath79.o
37d0749
 obj-$(CONFIG_GPIO_ASPEED)	+= gpio-aspeed.o
37d0749
+obj-$(CONFIG_GPIO_RASPBERRYPI_EXP)	+= gpio-raspberrypi-exp.o
37d0749
 obj-$(CONFIG_GPIO_BCM_KONA)	+= gpio-bcm-kona.o
37d0749
 obj-$(CONFIG_GPIO_BD9571MWV)	+= gpio-bd9571mwv.o
37d0749
 obj-$(CONFIG_GPIO_BRCMSTB)	+= gpio-brcmstb.o
37d0749
diff --git a/drivers/gpio/gpio-raspberrypi-exp.c b/drivers/gpio/gpio-raspberrypi-exp.c
37d0749
new file mode 100644
0edfe4f
index 0000000..d6d36d5
37d0749
--- /dev/null
37d0749
+++ b/drivers/gpio/gpio-raspberrypi-exp.c
37d0749
@@ -0,0 +1,252 @@
37d0749
+// SPDX-License-Identifier: GPL-2.0+
37d0749
+/*
37d0749
+ *  Raspberry Pi 3 expander GPIO driver
37d0749
+ *
37d0749
+ *  Uses the firmware mailbox service to communicate with the
37d0749
+ *  GPIO expander on the VPU.
37d0749
+ *
37d0749
+ *  Copyright (C) 2017 Raspberry Pi Trading Ltd.
37d0749
+ */
37d0749
+
37d0749
+#include <linux/err.h>
37d0749
+#include <linux/gpio/driver.h>
37d0749
+#include <linux/module.h>
37d0749
+#include <linux/platform_device.h>
37d0749
+#include <soc/bcm2835/raspberrypi-firmware.h>
37d0749
+
37d0749
+#define MODULE_NAME "raspberrypi-exp-gpio"
37d0749
+#define NUM_GPIO 8
37d0749
+
37d0749
+#define RPI_EXP_GPIO_BASE	128
37d0749
+
37d0749
+#define RPI_EXP_GPIO_DIR_IN	0
37d0749
+#define RPI_EXP_GPIO_DIR_OUT	1
37d0749
+
37d0749
+struct rpi_exp_gpio {
37d0749
+	struct gpio_chip gc;
37d0749
+	struct rpi_firmware *fw;
37d0749
+};
37d0749
+
37d0749
+/* VC4 firmware mailbox interface data structures */
37d0749
+
37d0749
+struct gpio_set_config {
37d0749
+	u32 gpio;
37d0749
+	u32 direction;
37d0749
+	u32 polarity;
37d0749
+	u32 term_en;
37d0749
+	u32 term_pull_up;
37d0749
+	u32 state;
37d0749
+};
37d0749
+
37d0749
+struct gpio_get_config {
37d0749
+	u32 gpio;
37d0749
+	u32 direction;
37d0749
+	u32 polarity;
37d0749
+	u32 term_en;
37d0749
+	u32 term_pull_up;
37d0749
+};
37d0749
+
37d0749
+struct gpio_get_set_state {
37d0749
+	u32 gpio;
37d0749
+	u32 state;
37d0749
+};
37d0749
+
37d0749
+static int rpi_exp_gpio_get_polarity(struct gpio_chip *gc, unsigned int off)
37d0749
+{
37d0749
+	struct rpi_exp_gpio *gpio;
37d0749
+	struct gpio_get_config get;
37d0749
+	int ret;
37d0749
+
37d0749
+	gpio = gpiochip_get_data(gc);
37d0749
+
37d0749
+	get.gpio = off + RPI_EXP_GPIO_BASE;	/* GPIO to update */
37d0749
+
37d0749
+	ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_CONFIG,
37d0749
+				    &get, sizeof(get));
37d0749
+	if (ret || get.gpio != 0) {
37d0749
+		dev_err(gc->parent, "Failed to get GPIO %u config (%d %x)\n",
37d0749
+			off, ret, get.gpio);
37d0749
+		return ret ? ret : -EIO;
37d0749
+	}
37d0749
+	return get.polarity;
37d0749
+}
37d0749
+
37d0749
+static int rpi_exp_gpio_dir_in(struct gpio_chip *gc, unsigned int off)
37d0749
+{
37d0749
+	struct rpi_exp_gpio *gpio;
37d0749
+	struct gpio_set_config set_in;
37d0749
+	int ret;
37d0749
+
37d0749
+	gpio = gpiochip_get_data(gc);
37d0749
+
37d0749
+	set_in.gpio = off + RPI_EXP_GPIO_BASE;	/* GPIO to update */
37d0749
+	set_in.direction = RPI_EXP_GPIO_DIR_IN;
37d0749
+	set_in.term_en = 0;		/* termination disabled */
37d0749
+	set_in.term_pull_up = 0;	/* n/a as termination disabled */
37d0749
+	set_in.state = 0;		/* n/a as configured as an input */
37d0749
+
37d0749
+	ret = rpi_exp_gpio_get_polarity(gc, off);
37d0749
+	if (ret < 0)
37d0749
+		return ret;
37d0749
+	set_in.polarity = ret;		/* Retain existing setting */
37d0749
+
37d0749
+	ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_CONFIG,
37d0749
+				    &set_in, sizeof(set_in));
37d0749
+	if (ret || set_in.gpio != 0) {
37d0749
+		dev_err(gc->parent, "Failed to set GPIO %u to input (%d %x)\n",
37d0749
+			off, ret, set_in.gpio);
37d0749
+		return ret ? ret : -EIO;
37d0749
+	}
37d0749
+	return 0;
37d0749
+}
37d0749
+
37d0749
+static int rpi_exp_gpio_dir_out(struct gpio_chip *gc, unsigned int off, int val)
37d0749
+{
37d0749
+	struct rpi_exp_gpio *gpio;
37d0749
+	struct gpio_set_config set_out;
37d0749
+	int ret;
37d0749
+
37d0749
+	gpio = gpiochip_get_data(gc);
37d0749
+
37d0749
+	set_out.gpio = off + RPI_EXP_GPIO_BASE;	/* GPIO to update */
37d0749
+	set_out.direction = RPI_EXP_GPIO_DIR_OUT;
37d0749
+	set_out.term_en = 0;		/* n/a as an output */
37d0749
+	set_out.term_pull_up = 0;	/* n/a as termination disabled */
37d0749
+	set_out.state = val;		/* Output state */
37d0749
+
37d0749
+	ret = rpi_exp_gpio_get_polarity(gc, off);
37d0749
+	if (ret < 0)
37d0749
+		return ret;
37d0749
+	set_out.polarity = ret;		/* Retain existing setting */
37d0749
+
37d0749
+	ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_CONFIG,
37d0749
+				    &set_out, sizeof(set_out));
37d0749
+	if (ret || set_out.gpio != 0) {
37d0749
+		dev_err(gc->parent, "Failed to set GPIO %u to output (%d %x)\n",
37d0749
+			off, ret, set_out.gpio);
37d0749
+		return ret ? ret : -EIO;
37d0749
+	}
37d0749
+	return 0;
37d0749
+}
37d0749
+
37d0749
+static int rpi_exp_gpio_get_direction(struct gpio_chip *gc, unsigned int off)
37d0749
+{
37d0749
+	struct rpi_exp_gpio *gpio;
37d0749
+	struct gpio_get_config get;
37d0749
+	int ret;
37d0749
+
37d0749
+	gpio = gpiochip_get_data(gc);
37d0749
+
37d0749
+	get.gpio = off + RPI_EXP_GPIO_BASE;	/* GPIO to update */
37d0749
+
37d0749
+	ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_CONFIG,
37d0749
+				    &get, sizeof(get));
37d0749
+	if (ret || get.gpio != 0) {
37d0749
+		dev_err(gc->parent,
37d0749
+			"Failed to get GPIO %u config (%d %x)\n", off, ret,
37d0749
+			get.gpio);
37d0749
+		return ret ? ret : -EIO;
37d0749
+	}
37d0749
+	return !get.direction;
37d0749
+}
37d0749
+
37d0749
+static int rpi_exp_gpio_get(struct gpio_chip *gc, unsigned int off)
37d0749
+{
37d0749
+	struct rpi_exp_gpio *gpio;
37d0749
+	struct gpio_get_set_state get;
37d0749
+	int ret;
37d0749
+
37d0749
+	gpio = gpiochip_get_data(gc);
37d0749
+
37d0749
+	get.gpio = off + RPI_EXP_GPIO_BASE;	/* GPIO to update */
37d0749
+	get.state = 0;		/* storage for returned value */
37d0749
+
37d0749
+	ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_STATE,
37d0749
+					 &get, sizeof(get));
37d0749
+	if (ret || get.gpio != 0) {
37d0749
+		dev_err(gc->parent,
37d0749
+			"Failed to get GPIO %u state (%d %x)\n", off, ret,
37d0749
+			get.gpio);
37d0749
+		return ret ? ret : -EIO;
37d0749
+	}
37d0749
+	return !!get.state;
37d0749
+}
37d0749
+
37d0749
+static void rpi_exp_gpio_set(struct gpio_chip *gc, unsigned int off, int val)
37d0749
+{
37d0749
+	struct rpi_exp_gpio *gpio;
37d0749
+	struct gpio_get_set_state set;
37d0749
+	int ret;
37d0749
+
37d0749
+	gpio = gpiochip_get_data(gc);
37d0749
+
37d0749
+	set.gpio = off + RPI_EXP_GPIO_BASE;	/* GPIO to update */
37d0749
+	set.state = val;	/* Output state */
37d0749
+
37d0749
+	ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_STATE,
37d0749
+					 &set, sizeof(set));
37d0749
+	if (ret || set.gpio != 0)
37d0749
+		dev_err(gc->parent,
37d0749
+			"Failed to set GPIO %u state (%d %x)\n", off, ret,
37d0749
+			set.gpio);
37d0749
+}
37d0749
+
37d0749
+static int rpi_exp_gpio_probe(struct platform_device *pdev)
37d0749
+{
37d0749
+	struct device *dev = &pdev->dev;
37d0749
+	struct device_node *np = dev->of_node;
37d0749
+	struct device_node *fw_node;
37d0749
+	struct rpi_firmware *fw;
37d0749
+	struct rpi_exp_gpio *rpi_gpio;
37d0749
+
37d0749
+	fw_node = of_get_parent(np);
37d0749
+	if (!fw_node) {
37d0749
+		dev_err(dev, "Missing firmware node\n");
37d0749
+		return -ENOENT;
37d0749
+	}
37d0749
+
37d0749
+	fw = rpi_firmware_get(fw_node);
37d0749
+	if (!fw)
37d0749
+		return -EPROBE_DEFER;
37d0749
+
37d0749
+	rpi_gpio = devm_kzalloc(dev, sizeof(*rpi_gpio), GFP_KERNEL);
37d0749
+	if (!rpi_gpio)
37d0749
+		return -ENOMEM;
37d0749
+
37d0749
+	rpi_gpio->fw = fw;
37d0749
+	rpi_gpio->gc.parent = dev;
37d0749
+	rpi_gpio->gc.label = MODULE_NAME;
37d0749
+	rpi_gpio->gc.owner = THIS_MODULE;
37d0749
+	rpi_gpio->gc.of_node = np;
37d0749
+	rpi_gpio->gc.base = -1;
37d0749
+	rpi_gpio->gc.ngpio = NUM_GPIO;
37d0749
+
37d0749
+	rpi_gpio->gc.direction_input = rpi_exp_gpio_dir_in;
37d0749
+	rpi_gpio->gc.direction_output = rpi_exp_gpio_dir_out;
37d0749
+	rpi_gpio->gc.get_direction = rpi_exp_gpio_get_direction;
37d0749
+	rpi_gpio->gc.get = rpi_exp_gpio_get;
37d0749
+	rpi_gpio->gc.set = rpi_exp_gpio_set;
37d0749
+	rpi_gpio->gc.can_sleep = true;
37d0749
+
37d0749
+	return devm_gpiochip_add_data(dev, &rpi_gpio->gc, rpi_gpio);
37d0749
+}
37d0749
+
37d0749
+static const struct of_device_id rpi_exp_gpio_ids[] = {
37d0749
+	{ .compatible = "raspberrypi,firmware-gpio" },
37d0749
+	{ }
37d0749
+};
37d0749
+MODULE_DEVICE_TABLE(of, rpi_exp_gpio_ids);
37d0749
+
37d0749
+static struct platform_driver rpi_exp_gpio_driver = {
37d0749
+	.driver	= {
37d0749
+		.name		= MODULE_NAME,
37d0749
+		.of_match_table	= of_match_ptr(rpi_exp_gpio_ids),
37d0749
+	},
37d0749
+	.probe	= rpi_exp_gpio_probe,
37d0749
+};
37d0749
+module_platform_driver(rpi_exp_gpio_driver);
37d0749
+
37d0749
+MODULE_LICENSE("GPL");
37d0749
+MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.org>");
37d0749
+MODULE_DESCRIPTION("Raspberry Pi 3 expander GPIO driver");
37d0749
+MODULE_ALIAS("platform:rpi-exp-gpio");
0edfe4f
-- 
0edfe4f
cgit v1.1
0edfe4f
From b0c07c5af6d286f3d3b907743998e9d41f6ab042 Mon Sep 17 00:00:00 2001
37d0749
From: Baruch Siach <baruch@tkos.co.il>
37d0749
Date: Tue, 20 Feb 2018 14:19:34 +0200
0edfe4f
Subject: ARM: dts: bcm2835: make the firmware node into a bus
37d0749
37d0749
This allows adding devices for which the firmware exposes control interface
37d0749
via the mailbox. An example of such device is the GPIO expander.
37d0749
37d0749
Signed-off-by: Baruch Siach <baruch@tkos.co.il>
37d0749
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
0edfe4f
Reviewed-by: Eric Anholt <eric@anholt.net>
0edfe4f
Signed-off-by: Eric Anholt <eric@anholt.net>
37d0749
---
37d0749
 arch/arm/boot/dts/bcm2835-rpi.dtsi | 4 +++-
37d0749
 1 file changed, 3 insertions(+), 1 deletion(-)
37d0749
37d0749
diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
0edfe4f
index e36c392..0198bd4 100644
37d0749
--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
37d0749
+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
37d0749
@@ -18,7 +18,9 @@
37d0749
 
37d0749
 	soc {
37d0749
 		firmware: firmware {
37d0749
-			compatible = "raspberrypi,bcm2835-firmware";
37d0749
+			compatible = "raspberrypi,bcm2835-firmware", "simple-bus";
37d0749
+			#address-cells = <0>;
37d0749
+			#size-cells = <0>;
37d0749
 			mboxes = <&mailbox>;
37d0749
 		};
37d0749
 
0edfe4f
-- 
0edfe4f
cgit v1.1
0edfe4f
From 4d5b2eaf3ca80c56a59f230208c4ff11e3f68d55 Mon Sep 17 00:00:00 2001
37d0749
From: Baruch Siach <baruch@tkos.co.il>
37d0749
Date: Tue, 20 Feb 2018 14:19:35 +0200
0edfe4f
Subject: ARM: dts: bcm2837-rpi-3-b: add GPIO expander
37d0749
37d0749
Add a description of the RPi3 GPIO expander that the VC4 firmware controls.
37d0749
37d0749
Acked-by: Stefan Wahren <stefan.wahren@i2se.com>
37d0749
Signed-off-by: Baruch Siach <baruch@tkos.co.il>
37d0749
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
0edfe4f
Reviewed-by: Eric Anholt <eric@anholt.net>
0edfe4f
Signed-off-by: Eric Anholt <eric@anholt.net>
37d0749
---
37d0749
 arch/arm/boot/dts/bcm2837-rpi-3-b.dts | 17 +++++++++++++++++
37d0749
 1 file changed, 17 insertions(+)
37d0749
37d0749
diff --git a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
0edfe4f
index 3e4ed7c..0b31d99 100644
37d0749
--- a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
37d0749
+++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
37d0749
@@ -25,6 +25,23 @@
37d0749
 	};
37d0749
 };
37d0749
 
37d0749
+&firmware {
37d0749
+	expgpio: gpio {
37d0749
+		compatible = "raspberrypi,firmware-gpio";
37d0749
+		gpio-controller;
37d0749
+		#gpio-cells = <2>;
37d0749
+		gpio-line-names = "BT_ON",
37d0749
+				  "WL_ON",
37d0749
+				  "STATUS_LED",
37d0749
+				  "LAN_RUN",
37d0749
+				  "HPD_N",
37d0749
+				  "CAM_GPIO0",
37d0749
+				  "CAM_GPIO1",
37d0749
+				  "PWR_LOW_N";
37d0749
+		status = "okay";
37d0749
+	};
37d0749
+};
37d0749
+
37d0749
 /* uart0 communicates with the BT module */
37d0749
 &uart0 {
37d0749
 	pinctrl-names = "default";
0edfe4f
-- 
0edfe4f
cgit v1.1