1 // SPDX-License-Identifier: GPL-2.0+
3 * Raspberry Pi 3 expander GPIO driver
5 * Uses the firmware mailbox service to communicate with the
6 * GPIO expander on the VPU.
8 * Copyright (C) 2017 Raspberry Pi Trading Ltd.
11 #include <linux/err.h>
12 #include <linux/gpio/driver.h>
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <soc/bcm2835/raspberrypi-firmware.h>
17 #define MODULE_NAME "raspberrypi-exp-gpio"
20 #define RPI_EXP_GPIO_BASE 128
22 #define RPI_EXP_GPIO_DIR_IN 0
23 #define RPI_EXP_GPIO_DIR_OUT 1
27 struct rpi_firmware
*fw
;
30 /* VC4 firmware mailbox interface data structures */
32 struct gpio_set_config
{
41 struct gpio_get_config
{
49 struct gpio_get_set_state
{
54 static int rpi_exp_gpio_get_polarity(struct gpio_chip
*gc
, unsigned int off
)
56 struct rpi_exp_gpio
*gpio
;
57 struct gpio_get_config get
;
60 gpio
= gpiochip_get_data(gc
);
62 get
.gpio
= off
+ RPI_EXP_GPIO_BASE
; /* GPIO to update */
64 ret
= rpi_firmware_property(gpio
->fw
, RPI_FIRMWARE_GET_GPIO_CONFIG
,
66 if (ret
|| get
.gpio
!= 0) {
67 dev_err(gc
->parent
, "Failed to get GPIO %u config (%d %x)\n",
69 return ret
? ret
: -EIO
;
74 static int rpi_exp_gpio_dir_in(struct gpio_chip
*gc
, unsigned int off
)
76 struct rpi_exp_gpio
*gpio
;
77 struct gpio_set_config set_in
;
80 gpio
= gpiochip_get_data(gc
);
82 set_in
.gpio
= off
+ RPI_EXP_GPIO_BASE
; /* GPIO to update */
83 set_in
.direction
= RPI_EXP_GPIO_DIR_IN
;
84 set_in
.term_en
= 0; /* termination disabled */
85 set_in
.term_pull_up
= 0; /* n/a as termination disabled */
86 set_in
.state
= 0; /* n/a as configured as an input */
88 ret
= rpi_exp_gpio_get_polarity(gc
, off
);
91 set_in
.polarity
= ret
; /* Retain existing setting */
93 ret
= rpi_firmware_property(gpio
->fw
, RPI_FIRMWARE_SET_GPIO_CONFIG
,
94 &set_in
, sizeof(set_in
));
95 if (ret
|| set_in
.gpio
!= 0) {
96 dev_err(gc
->parent
, "Failed to set GPIO %u to input (%d %x)\n",
97 off
, ret
, set_in
.gpio
);
98 return ret
? ret
: -EIO
;
103 static int rpi_exp_gpio_dir_out(struct gpio_chip
*gc
, unsigned int off
, int val
)
105 struct rpi_exp_gpio
*gpio
;
106 struct gpio_set_config set_out
;
109 gpio
= gpiochip_get_data(gc
);
111 set_out
.gpio
= off
+ RPI_EXP_GPIO_BASE
; /* GPIO to update */
112 set_out
.direction
= RPI_EXP_GPIO_DIR_OUT
;
113 set_out
.term_en
= 0; /* n/a as an output */
114 set_out
.term_pull_up
= 0; /* n/a as termination disabled */
115 set_out
.state
= val
; /* Output state */
117 ret
= rpi_exp_gpio_get_polarity(gc
, off
);
120 set_out
.polarity
= ret
; /* Retain existing setting */
122 ret
= rpi_firmware_property(gpio
->fw
, RPI_FIRMWARE_SET_GPIO_CONFIG
,
123 &set_out
, sizeof(set_out
));
124 if (ret
|| set_out
.gpio
!= 0) {
125 dev_err(gc
->parent
, "Failed to set GPIO %u to output (%d %x)\n",
126 off
, ret
, set_out
.gpio
);
127 return ret
? ret
: -EIO
;
132 static int rpi_exp_gpio_get_direction(struct gpio_chip
*gc
, unsigned int off
)
134 struct rpi_exp_gpio
*gpio
;
135 struct gpio_get_config get
;
138 gpio
= gpiochip_get_data(gc
);
140 get
.gpio
= off
+ RPI_EXP_GPIO_BASE
; /* GPIO to update */
142 ret
= rpi_firmware_property(gpio
->fw
, RPI_FIRMWARE_GET_GPIO_CONFIG
,
144 if (ret
|| get
.gpio
!= 0) {
146 "Failed to get GPIO %u config (%d %x)\n", off
, ret
,
148 return ret
? ret
: -EIO
;
150 return !get
.direction
;
153 static int rpi_exp_gpio_get(struct gpio_chip
*gc
, unsigned int off
)
155 struct rpi_exp_gpio
*gpio
;
156 struct gpio_get_set_state get
;
159 gpio
= gpiochip_get_data(gc
);
161 get
.gpio
= off
+ RPI_EXP_GPIO_BASE
; /* GPIO to update */
162 get
.state
= 0; /* storage for returned value */
164 ret
= rpi_firmware_property(gpio
->fw
, RPI_FIRMWARE_GET_GPIO_STATE
,
166 if (ret
|| get
.gpio
!= 0) {
168 "Failed to get GPIO %u state (%d %x)\n", off
, ret
,
170 return ret
? ret
: -EIO
;
175 static void rpi_exp_gpio_set(struct gpio_chip
*gc
, unsigned int off
, int val
)
177 struct rpi_exp_gpio
*gpio
;
178 struct gpio_get_set_state set
;
181 gpio
= gpiochip_get_data(gc
);
183 set
.gpio
= off
+ RPI_EXP_GPIO_BASE
; /* GPIO to update */
184 set
.state
= val
; /* Output state */
186 ret
= rpi_firmware_property(gpio
->fw
, RPI_FIRMWARE_SET_GPIO_STATE
,
188 if (ret
|| set
.gpio
!= 0)
190 "Failed to set GPIO %u state (%d %x)\n", off
, ret
,
194 static int rpi_exp_gpio_probe(struct platform_device
*pdev
)
196 struct device
*dev
= &pdev
->dev
;
197 struct device_node
*np
= dev
->of_node
;
198 struct device_node
*fw_node
;
199 struct rpi_firmware
*fw
;
200 struct rpi_exp_gpio
*rpi_gpio
;
202 fw_node
= of_get_parent(np
);
204 dev_err(dev
, "Missing firmware node\n");
208 fw
= rpi_firmware_get(fw_node
);
209 of_node_put(fw_node
);
211 return -EPROBE_DEFER
;
213 rpi_gpio
= devm_kzalloc(dev
, sizeof(*rpi_gpio
), GFP_KERNEL
);
218 rpi_gpio
->gc
.parent
= dev
;
219 rpi_gpio
->gc
.label
= MODULE_NAME
;
220 rpi_gpio
->gc
.owner
= THIS_MODULE
;
221 rpi_gpio
->gc
.of_node
= np
;
222 rpi_gpio
->gc
.base
= -1;
223 rpi_gpio
->gc
.ngpio
= NUM_GPIO
;
225 rpi_gpio
->gc
.direction_input
= rpi_exp_gpio_dir_in
;
226 rpi_gpio
->gc
.direction_output
= rpi_exp_gpio_dir_out
;
227 rpi_gpio
->gc
.get_direction
= rpi_exp_gpio_get_direction
;
228 rpi_gpio
->gc
.get
= rpi_exp_gpio_get
;
229 rpi_gpio
->gc
.set
= rpi_exp_gpio_set
;
230 rpi_gpio
->gc
.can_sleep
= true;
232 return devm_gpiochip_add_data(dev
, &rpi_gpio
->gc
, rpi_gpio
);
235 static const struct of_device_id rpi_exp_gpio_ids
[] = {
236 { .compatible
= "raspberrypi,firmware-gpio" },
239 MODULE_DEVICE_TABLE(of
, rpi_exp_gpio_ids
);
241 static struct platform_driver rpi_exp_gpio_driver
= {
244 .of_match_table
= of_match_ptr(rpi_exp_gpio_ids
),
246 .probe
= rpi_exp_gpio_probe
,
248 module_platform_driver(rpi_exp_gpio_driver
);
250 MODULE_LICENSE("GPL");
251 MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.org>");
252 MODULE_DESCRIPTION("Raspberry Pi 3 expander GPIO driver");
253 MODULE_ALIAS("platform:rpi-exp-gpio");