root/drivers/gpio/gpio-arizona.c

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

DEFINITIONS

This source file includes following definitions.
  1. arizona_gpio_direction_in
  2. arizona_gpio_get
  3. arizona_gpio_direction_out
  4. arizona_gpio_set
  5. arizona_gpio_probe

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * gpiolib support for Wolfson Arizona class devices
   4  *
   5  * Copyright 2012 Wolfson Microelectronics PLC.
   6  *
   7  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
   8  */
   9 
  10 #include <linux/kernel.h>
  11 #include <linux/slab.h>
  12 #include <linux/module.h>
  13 #include <linux/gpio/driver.h>
  14 #include <linux/platform_device.h>
  15 #include <linux/pm_runtime.h>
  16 #include <linux/seq_file.h>
  17 
  18 #include <linux/mfd/arizona/core.h>
  19 #include <linux/mfd/arizona/pdata.h>
  20 #include <linux/mfd/arizona/registers.h>
  21 
  22 struct arizona_gpio {
  23         struct arizona *arizona;
  24         struct gpio_chip gpio_chip;
  25 };
  26 
  27 static int arizona_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
  28 {
  29         struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
  30         struct arizona *arizona = arizona_gpio->arizona;
  31         bool persistent = gpiochip_line_is_persistent(chip, offset);
  32         bool change;
  33         int ret;
  34 
  35         ret = regmap_update_bits_check(arizona->regmap,
  36                                        ARIZONA_GPIO1_CTRL + offset,
  37                                        ARIZONA_GPN_DIR, ARIZONA_GPN_DIR,
  38                                        &change);
  39         if (ret < 0)
  40                 return ret;
  41 
  42         if (change && persistent) {
  43                 pm_runtime_mark_last_busy(chip->parent);
  44                 pm_runtime_put_autosuspend(chip->parent);
  45         }
  46 
  47         return 0;
  48 }
  49 
  50 static int arizona_gpio_get(struct gpio_chip *chip, unsigned offset)
  51 {
  52         struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
  53         struct arizona *arizona = arizona_gpio->arizona;
  54         unsigned int reg, val;
  55         int ret;
  56 
  57         reg = ARIZONA_GPIO1_CTRL + offset;
  58         ret = regmap_read(arizona->regmap, reg, &val);
  59         if (ret < 0)
  60                 return ret;
  61 
  62         /* Resume to read actual registers for input pins */
  63         if (val & ARIZONA_GPN_DIR) {
  64                 ret = pm_runtime_get_sync(chip->parent);
  65                 if (ret < 0) {
  66                         dev_err(chip->parent, "Failed to resume: %d\n", ret);
  67                         return ret;
  68                 }
  69 
  70                 /* Register is cached, drop it to ensure a physical read */
  71                 ret = regcache_drop_region(arizona->regmap, reg, reg);
  72                 if (ret < 0) {
  73                         dev_err(chip->parent, "Failed to drop cache: %d\n",
  74                                 ret);
  75                         return ret;
  76                 }
  77 
  78                 ret = regmap_read(arizona->regmap, reg, &val);
  79                 if (ret < 0)
  80                         return ret;
  81 
  82                 pm_runtime_mark_last_busy(chip->parent);
  83                 pm_runtime_put_autosuspend(chip->parent);
  84         }
  85 
  86         if (val & ARIZONA_GPN_LVL)
  87                 return 1;
  88         else
  89                 return 0;
  90 }
  91 
  92 static int arizona_gpio_direction_out(struct gpio_chip *chip,
  93                                      unsigned offset, int value)
  94 {
  95         struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
  96         struct arizona *arizona = arizona_gpio->arizona;
  97         bool persistent = gpiochip_line_is_persistent(chip, offset);
  98         unsigned int val;
  99         int ret;
 100 
 101         ret = regmap_read(arizona->regmap, ARIZONA_GPIO1_CTRL + offset, &val);
 102         if (ret < 0)
 103                 return ret;
 104 
 105         if ((val & ARIZONA_GPN_DIR) && persistent) {
 106                 ret = pm_runtime_get_sync(chip->parent);
 107                 if (ret < 0) {
 108                         dev_err(chip->parent, "Failed to resume: %d\n", ret);
 109                         return ret;
 110                 }
 111         }
 112 
 113         if (value)
 114                 value = ARIZONA_GPN_LVL;
 115 
 116         return regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset,
 117                                   ARIZONA_GPN_DIR | ARIZONA_GPN_LVL, value);
 118 }
 119 
 120 static void arizona_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 121 {
 122         struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
 123         struct arizona *arizona = arizona_gpio->arizona;
 124 
 125         if (value)
 126                 value = ARIZONA_GPN_LVL;
 127 
 128         regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset,
 129                            ARIZONA_GPN_LVL, value);
 130 }
 131 
 132 static const struct gpio_chip template_chip = {
 133         .label                  = "arizona",
 134         .owner                  = THIS_MODULE,
 135         .direction_input        = arizona_gpio_direction_in,
 136         .get                    = arizona_gpio_get,
 137         .direction_output       = arizona_gpio_direction_out,
 138         .set                    = arizona_gpio_set,
 139         .can_sleep              = true,
 140 };
 141 
 142 static int arizona_gpio_probe(struct platform_device *pdev)
 143 {
 144         struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
 145         struct arizona_pdata *pdata = &arizona->pdata;
 146         struct arizona_gpio *arizona_gpio;
 147         int ret;
 148 
 149         arizona_gpio = devm_kzalloc(&pdev->dev, sizeof(*arizona_gpio),
 150                                     GFP_KERNEL);
 151         if (!arizona_gpio)
 152                 return -ENOMEM;
 153 
 154         arizona_gpio->arizona = arizona;
 155         arizona_gpio->gpio_chip = template_chip;
 156         arizona_gpio->gpio_chip.parent = &pdev->dev;
 157 #ifdef CONFIG_OF_GPIO
 158         arizona_gpio->gpio_chip.of_node = arizona->dev->of_node;
 159 #endif
 160 
 161         switch (arizona->type) {
 162         case WM5102:
 163         case WM5110:
 164         case WM8280:
 165         case WM8997:
 166         case WM8998:
 167         case WM1814:
 168                 arizona_gpio->gpio_chip.ngpio = 5;
 169                 break;
 170         case WM1831:
 171         case CS47L24:
 172                 arizona_gpio->gpio_chip.ngpio = 2;
 173                 break;
 174         default:
 175                 dev_err(&pdev->dev, "Unknown chip variant %d\n",
 176                         arizona->type);
 177                 return -EINVAL;
 178         }
 179 
 180         if (pdata->gpio_base)
 181                 arizona_gpio->gpio_chip.base = pdata->gpio_base;
 182         else
 183                 arizona_gpio->gpio_chip.base = -1;
 184 
 185         pm_runtime_enable(&pdev->dev);
 186 
 187         ret = devm_gpiochip_add_data(&pdev->dev, &arizona_gpio->gpio_chip,
 188                                      arizona_gpio);
 189         if (ret < 0) {
 190                 dev_err(&pdev->dev, "Could not register gpiochip, %d\n",
 191                         ret);
 192                 return ret;
 193         }
 194 
 195         return 0;
 196 }
 197 
 198 static struct platform_driver arizona_gpio_driver = {
 199         .driver.name    = "arizona-gpio",
 200         .probe          = arizona_gpio_probe,
 201 };
 202 
 203 module_platform_driver(arizona_gpio_driver);
 204 
 205 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 206 MODULE_DESCRIPTION("GPIO interface for Arizona devices");
 207 MODULE_LICENSE("GPL");
 208 MODULE_ALIAS("platform:arizona-gpio");

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