LCOV - code coverage report
Current view: top level - drivers/gpio - gpio-raspberrypi-exp.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_qemu_modules_combined.info Lines: 1 87 1.1 %
Date: 2020-09-30 20:25:01 Functions: 1 9 11.1 %
Branches: 0 44 0.0 %

           Branch data     Line data    Source code
       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                 :          0 : 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                 :          0 :         gpio = gpiochip_get_data(gc);
      61                 :            : 
      62                 :          0 :         get.gpio = off + RPI_EXP_GPIO_BASE;     /* GPIO to update */
      63                 :            : 
      64                 :          0 :         ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_CONFIG,
      65                 :            :                                     &get, sizeof(get));
      66   [ #  #  #  # ]:          0 :         if (ret || get.gpio != 0) {
      67                 :          0 :                 dev_err(gc->parent, "Failed to get GPIO %u config (%d %x)\n",
      68                 :            :                         off, ret, get.gpio);
      69         [ #  # ]:          0 :                 return ret ? ret : -EIO;
      70                 :            :         }
      71                 :          0 :         return get.polarity;
      72                 :            : }
      73                 :            : 
      74                 :          0 : 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                 :          0 :         gpio = gpiochip_get_data(gc);
      81                 :            : 
      82                 :          0 :         set_in.gpio = off + RPI_EXP_GPIO_BASE;  /* GPIO to update */
      83                 :          0 :         set_in.direction = RPI_EXP_GPIO_DIR_IN;
      84                 :          0 :         set_in.term_en = 0;             /* termination disabled */
      85                 :          0 :         set_in.term_pull_up = 0;        /* n/a as termination disabled */
      86                 :          0 :         set_in.state = 0;               /* n/a as configured as an input */
      87                 :            : 
      88                 :          0 :         ret = rpi_exp_gpio_get_polarity(gc, off);
      89         [ #  # ]:          0 :         if (ret < 0)
      90                 :            :                 return ret;
      91                 :          0 :         set_in.polarity = ret;          /* Retain existing setting */
      92                 :            : 
      93                 :          0 :         ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_CONFIG,
      94                 :            :                                     &set_in, sizeof(set_in));
      95   [ #  #  #  # ]:          0 :         if (ret || set_in.gpio != 0) {
      96                 :          0 :                 dev_err(gc->parent, "Failed to set GPIO %u to input (%d %x)\n",
      97                 :            :                         off, ret, set_in.gpio);
      98         [ #  # ]:          0 :                 return ret ? ret : -EIO;
      99                 :            :         }
     100                 :            :         return 0;
     101                 :            : }
     102                 :            : 
     103                 :          0 : 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                 :          0 :         gpio = gpiochip_get_data(gc);
     110                 :            : 
     111                 :          0 :         set_out.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
     112                 :          0 :         set_out.direction = RPI_EXP_GPIO_DIR_OUT;
     113                 :          0 :         set_out.term_en = 0;            /* n/a as an output */
     114                 :          0 :         set_out.term_pull_up = 0;       /* n/a as termination disabled */
     115                 :          0 :         set_out.state = val;            /* Output state */
     116                 :            : 
     117                 :          0 :         ret = rpi_exp_gpio_get_polarity(gc, off);
     118         [ #  # ]:          0 :         if (ret < 0)
     119                 :            :                 return ret;
     120                 :          0 :         set_out.polarity = ret;         /* Retain existing setting */
     121                 :            : 
     122                 :          0 :         ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_CONFIG,
     123                 :            :                                     &set_out, sizeof(set_out));
     124   [ #  #  #  # ]:          0 :         if (ret || set_out.gpio != 0) {
     125                 :          0 :                 dev_err(gc->parent, "Failed to set GPIO %u to output (%d %x)\n",
     126                 :            :                         off, ret, set_out.gpio);
     127         [ #  # ]:          0 :                 return ret ? ret : -EIO;
     128                 :            :         }
     129                 :            :         return 0;
     130                 :            : }
     131                 :            : 
     132                 :          0 : 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                 :          0 :         gpio = gpiochip_get_data(gc);
     139                 :            : 
     140                 :          0 :         get.gpio = off + RPI_EXP_GPIO_BASE;     /* GPIO to update */
     141                 :            : 
     142                 :          0 :         ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_CONFIG,
     143                 :            :                                     &get, sizeof(get));
     144   [ #  #  #  # ]:          0 :         if (ret || get.gpio != 0) {
     145                 :          0 :                 dev_err(gc->parent,
     146                 :            :                         "Failed to get GPIO %u config (%d %x)\n", off, ret,
     147                 :            :                         get.gpio);
     148         [ #  # ]:          0 :                 return ret ? ret : -EIO;
     149                 :            :         }
     150                 :          0 :         return !get.direction;
     151                 :            : }
     152                 :            : 
     153                 :          0 : 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                 :          0 :         gpio = gpiochip_get_data(gc);
     160                 :            : 
     161                 :          0 :         get.gpio = off + RPI_EXP_GPIO_BASE;     /* GPIO to update */
     162                 :          0 :         get.state = 0;          /* storage for returned value */
     163                 :            : 
     164                 :          0 :         ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_STATE,
     165                 :            :                                          &get, sizeof(get));
     166   [ #  #  #  # ]:          0 :         if (ret || get.gpio != 0) {
     167                 :          0 :                 dev_err(gc->parent,
     168                 :            :                         "Failed to get GPIO %u state (%d %x)\n", off, ret,
     169                 :            :                         get.gpio);
     170         [ #  # ]:          0 :                 return ret ? ret : -EIO;
     171                 :            :         }
     172                 :          0 :         return !!get.state;
     173                 :            : }
     174                 :            : 
     175                 :          0 : 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                 :          0 :         gpio = gpiochip_get_data(gc);
     182                 :            : 
     183                 :          0 :         set.gpio = off + RPI_EXP_GPIO_BASE;     /* GPIO to update */
     184                 :          0 :         set.state = val;        /* Output state */
     185                 :            : 
     186                 :          0 :         ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_STATE,
     187                 :            :                                          &set, sizeof(set));
     188   [ #  #  #  # ]:          0 :         if (ret || set.gpio != 0)
     189                 :          0 :                 dev_err(gc->parent,
     190                 :            :                         "Failed to set GPIO %u state (%d %x)\n", off, ret,
     191                 :            :                         set.gpio);
     192                 :          0 : }
     193                 :            : 
     194                 :          0 : static int rpi_exp_gpio_probe(struct platform_device *pdev)
     195                 :            : {
     196                 :          0 :         struct device *dev = &pdev->dev;
     197                 :          0 :         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                 :          0 :         fw_node = of_get_parent(np);
     203         [ #  # ]:          0 :         if (!fw_node) {
     204                 :          0 :                 dev_err(dev, "Missing firmware node\n");
     205                 :          0 :                 return -ENOENT;
     206                 :            :         }
     207                 :            : 
     208                 :          0 :         fw = rpi_firmware_get(fw_node);
     209                 :          0 :         of_node_put(fw_node);
     210         [ #  # ]:          0 :         if (!fw)
     211                 :            :                 return -EPROBE_DEFER;
     212                 :            : 
     213                 :            :         rpi_gpio = devm_kzalloc(dev, sizeof(*rpi_gpio), GFP_KERNEL);
     214         [ #  # ]:          0 :         if (!rpi_gpio)
     215                 :            :                 return -ENOMEM;
     216                 :            : 
     217                 :          0 :         rpi_gpio->fw = fw;
     218                 :          0 :         rpi_gpio->gc.parent = dev;
     219                 :          0 :         rpi_gpio->gc.label = MODULE_NAME;
     220                 :          0 :         rpi_gpio->gc.owner = THIS_MODULE;
     221                 :          0 :         rpi_gpio->gc.of_node = np;
     222                 :          0 :         rpi_gpio->gc.base = -1;
     223                 :          0 :         rpi_gpio->gc.ngpio = NUM_GPIO;
     224                 :            : 
     225                 :          0 :         rpi_gpio->gc.direction_input = rpi_exp_gpio_dir_in;
     226                 :          0 :         rpi_gpio->gc.direction_output = rpi_exp_gpio_dir_out;
     227                 :          0 :         rpi_gpio->gc.get_direction = rpi_exp_gpio_get_direction;
     228                 :          0 :         rpi_gpio->gc.get = rpi_exp_gpio_get;
     229                 :          0 :         rpi_gpio->gc.set = rpi_exp_gpio_set;
     230                 :          0 :         rpi_gpio->gc.can_sleep = true;
     231                 :            : 
     232                 :          0 :         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                 :        404 : 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");

Generated by: LCOV version 1.14