Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  *  Raspberry Pi 3 expander GPIO driver
0004  *
0005  *  Uses the firmware mailbox service to communicate with the
0006  *  GPIO expander on the VPU.
0007  *
0008  *  Copyright (C) 2017 Raspberry Pi Trading Ltd.
0009  */
0010 
0011 #include <linux/err.h>
0012 #include <linux/gpio/driver.h>
0013 #include <linux/module.h>
0014 #include <linux/platform_device.h>
0015 #include <soc/bcm2835/raspberrypi-firmware.h>
0016 
0017 #define MODULE_NAME "raspberrypi-exp-gpio"
0018 #define NUM_GPIO 8
0019 
0020 #define RPI_EXP_GPIO_BASE   128
0021 
0022 #define RPI_EXP_GPIO_DIR_IN 0
0023 #define RPI_EXP_GPIO_DIR_OUT    1
0024 
0025 struct rpi_exp_gpio {
0026     struct gpio_chip gc;
0027     struct rpi_firmware *fw;
0028 };
0029 
0030 /* VC4 firmware mailbox interface data structures */
0031 
0032 struct gpio_set_config {
0033     u32 gpio;
0034     u32 direction;
0035     u32 polarity;
0036     u32 term_en;
0037     u32 term_pull_up;
0038     u32 state;
0039 };
0040 
0041 struct gpio_get_config {
0042     u32 gpio;
0043     u32 direction;
0044     u32 polarity;
0045     u32 term_en;
0046     u32 term_pull_up;
0047 };
0048 
0049 struct gpio_get_set_state {
0050     u32 gpio;
0051     u32 state;
0052 };
0053 
0054 static int rpi_exp_gpio_get_polarity(struct gpio_chip *gc, unsigned int off)
0055 {
0056     struct rpi_exp_gpio *gpio;
0057     struct gpio_get_config get;
0058     int ret;
0059 
0060     gpio = gpiochip_get_data(gc);
0061 
0062     get.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
0063 
0064     ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_CONFIG,
0065                     &get, sizeof(get));
0066     if (ret || get.gpio != 0) {
0067         dev_err(gc->parent, "Failed to get GPIO %u config (%d %x)\n",
0068             off, ret, get.gpio);
0069         return ret ? ret : -EIO;
0070     }
0071     return get.polarity;
0072 }
0073 
0074 static int rpi_exp_gpio_dir_in(struct gpio_chip *gc, unsigned int off)
0075 {
0076     struct rpi_exp_gpio *gpio;
0077     struct gpio_set_config set_in;
0078     int ret;
0079 
0080     gpio = gpiochip_get_data(gc);
0081 
0082     set_in.gpio = off + RPI_EXP_GPIO_BASE;  /* GPIO to update */
0083     set_in.direction = RPI_EXP_GPIO_DIR_IN;
0084     set_in.term_en = 0;     /* termination disabled */
0085     set_in.term_pull_up = 0;    /* n/a as termination disabled */
0086     set_in.state = 0;       /* n/a as configured as an input */
0087 
0088     ret = rpi_exp_gpio_get_polarity(gc, off);
0089     if (ret < 0)
0090         return ret;
0091     set_in.polarity = ret;      /* Retain existing setting */
0092 
0093     ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_CONFIG,
0094                     &set_in, sizeof(set_in));
0095     if (ret || set_in.gpio != 0) {
0096         dev_err(gc->parent, "Failed to set GPIO %u to input (%d %x)\n",
0097             off, ret, set_in.gpio);
0098         return ret ? ret : -EIO;
0099     }
0100     return 0;
0101 }
0102 
0103 static int rpi_exp_gpio_dir_out(struct gpio_chip *gc, unsigned int off, int val)
0104 {
0105     struct rpi_exp_gpio *gpio;
0106     struct gpio_set_config set_out;
0107     int ret;
0108 
0109     gpio = gpiochip_get_data(gc);
0110 
0111     set_out.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
0112     set_out.direction = RPI_EXP_GPIO_DIR_OUT;
0113     set_out.term_en = 0;        /* n/a as an output */
0114     set_out.term_pull_up = 0;   /* n/a as termination disabled */
0115     set_out.state = val;        /* Output state */
0116 
0117     ret = rpi_exp_gpio_get_polarity(gc, off);
0118     if (ret < 0)
0119         return ret;
0120     set_out.polarity = ret;     /* Retain existing setting */
0121 
0122     ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_CONFIG,
0123                     &set_out, sizeof(set_out));
0124     if (ret || set_out.gpio != 0) {
0125         dev_err(gc->parent, "Failed to set GPIO %u to output (%d %x)\n",
0126             off, ret, set_out.gpio);
0127         return ret ? ret : -EIO;
0128     }
0129     return 0;
0130 }
0131 
0132 static int rpi_exp_gpio_get_direction(struct gpio_chip *gc, unsigned int off)
0133 {
0134     struct rpi_exp_gpio *gpio;
0135     struct gpio_get_config get;
0136     int ret;
0137 
0138     gpio = gpiochip_get_data(gc);
0139 
0140     get.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
0141 
0142     ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_CONFIG,
0143                     &get, sizeof(get));
0144     if (ret || get.gpio != 0) {
0145         dev_err(gc->parent,
0146             "Failed to get GPIO %u config (%d %x)\n", off, ret,
0147             get.gpio);
0148         return ret ? ret : -EIO;
0149     }
0150     if (get.direction)
0151         return GPIO_LINE_DIRECTION_OUT;
0152 
0153     return GPIO_LINE_DIRECTION_IN;
0154 }
0155 
0156 static int rpi_exp_gpio_get(struct gpio_chip *gc, unsigned int off)
0157 {
0158     struct rpi_exp_gpio *gpio;
0159     struct gpio_get_set_state get;
0160     int ret;
0161 
0162     gpio = gpiochip_get_data(gc);
0163 
0164     get.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
0165     get.state = 0;      /* storage for returned value */
0166 
0167     ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_STATE,
0168                      &get, sizeof(get));
0169     if (ret || get.gpio != 0) {
0170         dev_err(gc->parent,
0171             "Failed to get GPIO %u state (%d %x)\n", off, ret,
0172             get.gpio);
0173         return ret ? ret : -EIO;
0174     }
0175     return !!get.state;
0176 }
0177 
0178 static void rpi_exp_gpio_set(struct gpio_chip *gc, unsigned int off, int val)
0179 {
0180     struct rpi_exp_gpio *gpio;
0181     struct gpio_get_set_state set;
0182     int ret;
0183 
0184     gpio = gpiochip_get_data(gc);
0185 
0186     set.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
0187     set.state = val;    /* Output state */
0188 
0189     ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_STATE,
0190                      &set, sizeof(set));
0191     if (ret || set.gpio != 0)
0192         dev_err(gc->parent,
0193             "Failed to set GPIO %u state (%d %x)\n", off, ret,
0194             set.gpio);
0195 }
0196 
0197 static int rpi_exp_gpio_probe(struct platform_device *pdev)
0198 {
0199     struct device *dev = &pdev->dev;
0200     struct device_node *np = dev->of_node;
0201     struct device_node *fw_node;
0202     struct rpi_firmware *fw;
0203     struct rpi_exp_gpio *rpi_gpio;
0204 
0205     fw_node = of_get_parent(np);
0206     if (!fw_node) {
0207         dev_err(dev, "Missing firmware node\n");
0208         return -ENOENT;
0209     }
0210 
0211     fw = devm_rpi_firmware_get(&pdev->dev, fw_node);
0212     of_node_put(fw_node);
0213     if (!fw)
0214         return -EPROBE_DEFER;
0215 
0216     rpi_gpio = devm_kzalloc(dev, sizeof(*rpi_gpio), GFP_KERNEL);
0217     if (!rpi_gpio)
0218         return -ENOMEM;
0219 
0220     rpi_gpio->fw = fw;
0221     rpi_gpio->gc.parent = dev;
0222     rpi_gpio->gc.label = MODULE_NAME;
0223     rpi_gpio->gc.owner = THIS_MODULE;
0224     rpi_gpio->gc.base = -1;
0225     rpi_gpio->gc.ngpio = NUM_GPIO;
0226 
0227     rpi_gpio->gc.direction_input = rpi_exp_gpio_dir_in;
0228     rpi_gpio->gc.direction_output = rpi_exp_gpio_dir_out;
0229     rpi_gpio->gc.get_direction = rpi_exp_gpio_get_direction;
0230     rpi_gpio->gc.get = rpi_exp_gpio_get;
0231     rpi_gpio->gc.set = rpi_exp_gpio_set;
0232     rpi_gpio->gc.can_sleep = true;
0233 
0234     return devm_gpiochip_add_data(dev, &rpi_gpio->gc, rpi_gpio);
0235 }
0236 
0237 static const struct of_device_id rpi_exp_gpio_ids[] = {
0238     { .compatible = "raspberrypi,firmware-gpio" },
0239     { }
0240 };
0241 MODULE_DEVICE_TABLE(of, rpi_exp_gpio_ids);
0242 
0243 static struct platform_driver rpi_exp_gpio_driver = {
0244     .driver = {
0245         .name       = MODULE_NAME,
0246         .of_match_table = of_match_ptr(rpi_exp_gpio_ids),
0247     },
0248     .probe  = rpi_exp_gpio_probe,
0249 };
0250 module_platform_driver(rpi_exp_gpio_driver);
0251 
0252 MODULE_LICENSE("GPL");
0253 MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.org>");
0254 MODULE_DESCRIPTION("Raspberry Pi 3 expander GPIO driver");
0255 MODULE_ALIAS("platform:rpi-exp-gpio");