root/drivers/gpio/gpio-raspberrypi-exp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rpi_exp_gpio_get_polarity
  2. rpi_exp_gpio_dir_in
  3. rpi_exp_gpio_dir_out
  4. rpi_exp_gpio_get_direction
  5. rpi_exp_gpio_get
  6. rpi_exp_gpio_set
  7. rpi_exp_gpio_probe

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  *  Raspberry Pi 3 expander GPIO driver
   4  *
   5  *  Uses the firmware mailbox service to communicate with the
   6  *  GPIO expander on the VPU.
   7  *
   8  *  Copyright (C) 2017 Raspberry Pi Trading Ltd.
   9  */
  10 
  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>
  16 
  17 #define MODULE_NAME "raspberrypi-exp-gpio"
  18 #define NUM_GPIO 8
  19 
  20 #define RPI_EXP_GPIO_BASE       128
  21 
  22 #define RPI_EXP_GPIO_DIR_IN     0
  23 #define RPI_EXP_GPIO_DIR_OUT    1
  24 
  25 struct rpi_exp_gpio {
  26         struct gpio_chip gc;
  27         struct rpi_firmware *fw;
  28 };
  29 
  30 /* VC4 firmware mailbox interface data structures */
  31 
  32 struct gpio_set_config {
  33         u32 gpio;
  34         u32 direction;
  35         u32 polarity;
  36         u32 term_en;
  37         u32 term_pull_up;
  38         u32 state;
  39 };
  40 
  41 struct gpio_get_config {
  42         u32 gpio;
  43         u32 direction;
  44         u32 polarity;
  45         u32 term_en;
  46         u32 term_pull_up;
  47 };
  48 
  49 struct gpio_get_set_state {
  50         u32 gpio;
  51         u32 state;
  52 };
  53 
  54 static int rpi_exp_gpio_get_polarity(struct gpio_chip *gc, unsigned int off)
  55 {
  56         struct rpi_exp_gpio *gpio;
  57         struct gpio_get_config get;
  58         int ret;
  59 
  60         gpio = gpiochip_get_data(gc);
  61 
  62         get.gpio = off + RPI_EXP_GPIO_BASE;     /* GPIO to update */
  63 
  64         ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_CONFIG,
  65                                     &get, sizeof(get));
  66         if (ret || get.gpio != 0) {
  67                 dev_err(gc->parent, "Failed to get GPIO %u config (%d %x)\n",
  68                         off, ret, get.gpio);
  69                 return ret ? ret : -EIO;
  70         }
  71         return get.polarity;
  72 }
  73 
  74 static int rpi_exp_gpio_dir_in(struct gpio_chip *gc, unsigned int off)
  75 {
  76         struct rpi_exp_gpio *gpio;
  77         struct gpio_set_config set_in;
  78         int ret;
  79 
  80         gpio = gpiochip_get_data(gc);
  81 
  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 */
  87 
  88         ret = rpi_exp_gpio_get_polarity(gc, off);
  89         if (ret < 0)
  90                 return ret;
  91         set_in.polarity = ret;          /* Retain existing setting */
  92 
  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;
  99         }
 100         return 0;
 101 }
 102 
 103 static int rpi_exp_gpio_dir_out(struct gpio_chip *gc, unsigned int off, int val)
 104 {
 105         struct rpi_exp_gpio *gpio;
 106         struct gpio_set_config set_out;
 107         int ret;
 108 
 109         gpio = gpiochip_get_data(gc);
 110 
 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 */
 116 
 117         ret = rpi_exp_gpio_get_polarity(gc, off);
 118         if (ret < 0)
 119                 return ret;
 120         set_out.polarity = ret;         /* Retain existing setting */
 121 
 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;
 128         }
 129         return 0;
 130 }
 131 
 132 static int rpi_exp_gpio_get_direction(struct gpio_chip *gc, unsigned int off)
 133 {
 134         struct rpi_exp_gpio *gpio;
 135         struct gpio_get_config get;
 136         int ret;
 137 
 138         gpio = gpiochip_get_data(gc);
 139 
 140         get.gpio = off + RPI_EXP_GPIO_BASE;     /* GPIO to update */
 141 
 142         ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_CONFIG,
 143                                     &get, sizeof(get));
 144         if (ret || get.gpio != 0) {
 145                 dev_err(gc->parent,
 146                         "Failed to get GPIO %u config (%d %x)\n", off, ret,
 147                         get.gpio);
 148                 return ret ? ret : -EIO;
 149         }
 150         return !get.direction;
 151 }
 152 
 153 static int rpi_exp_gpio_get(struct gpio_chip *gc, unsigned int off)
 154 {
 155         struct rpi_exp_gpio *gpio;
 156         struct gpio_get_set_state get;
 157         int ret;
 158 
 159         gpio = gpiochip_get_data(gc);
 160 
 161         get.gpio = off + RPI_EXP_GPIO_BASE;     /* GPIO to update */
 162         get.state = 0;          /* storage for returned value */
 163 
 164         ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_STATE,
 165                                          &get, sizeof(get));
 166         if (ret || get.gpio != 0) {
 167                 dev_err(gc->parent,
 168                         "Failed to get GPIO %u state (%d %x)\n", off, ret,
 169                         get.gpio);
 170                 return ret ? ret : -EIO;
 171         }
 172         return !!get.state;
 173 }
 174 
 175 static void rpi_exp_gpio_set(struct gpio_chip *gc, unsigned int off, int val)
 176 {
 177         struct rpi_exp_gpio *gpio;
 178         struct gpio_get_set_state set;
 179         int ret;
 180 
 181         gpio = gpiochip_get_data(gc);
 182 
 183         set.gpio = off + RPI_EXP_GPIO_BASE;     /* GPIO to update */
 184         set.state = val;        /* Output state */
 185 
 186         ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_STATE,
 187                                          &set, sizeof(set));
 188         if (ret || set.gpio != 0)
 189                 dev_err(gc->parent,
 190                         "Failed to set GPIO %u state (%d %x)\n", off, ret,
 191                         set.gpio);
 192 }
 193 
 194 static int rpi_exp_gpio_probe(struct platform_device *pdev)
 195 {
 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;
 201 
 202         fw_node = of_get_parent(np);
 203         if (!fw_node) {
 204                 dev_err(dev, "Missing firmware node\n");
 205                 return -ENOENT;
 206         }
 207 
 208         fw = rpi_firmware_get(fw_node);
 209         of_node_put(fw_node);
 210         if (!fw)
 211                 return -EPROBE_DEFER;
 212 
 213         rpi_gpio = devm_kzalloc(dev, sizeof(*rpi_gpio), GFP_KERNEL);
 214         if (!rpi_gpio)
 215                 return -ENOMEM;
 216 
 217         rpi_gpio->fw = fw;
 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;
 224 
 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;
 231 
 232         return devm_gpiochip_add_data(dev, &rpi_gpio->gc, rpi_gpio);
 233 }
 234 
 235 static const struct of_device_id rpi_exp_gpio_ids[] = {
 236         { .compatible = "raspberrypi,firmware-gpio" },
 237         { }
 238 };
 239 MODULE_DEVICE_TABLE(of, rpi_exp_gpio_ids);
 240 
 241 static struct platform_driver rpi_exp_gpio_driver = {
 242         .driver = {
 243                 .name           = MODULE_NAME,
 244                 .of_match_table = of_match_ptr(rpi_exp_gpio_ids),
 245         },
 246         .probe  = rpi_exp_gpio_probe,
 247 };
 248 module_platform_driver(rpi_exp_gpio_driver);
 249 
 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");

/* [<][>][^][v][top][bottom][index][help] */