root/drivers/gpio/gpio-sama5d2-piobu.c

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

DEFINITIONS

This source file includes following definitions.
  1. sama5d2_piobu_setup_pin
  2. sama5d2_piobu_write_value
  3. sama5d2_piobu_read_value
  4. sama5d2_piobu_get_direction
  5. sama5d2_piobu_direction_input
  6. sama5d2_piobu_direction_output
  7. sama5d2_piobu_get
  8. sama5d2_piobu_set
  9. sama5d2_piobu_probe

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * SAMA5D2 PIOBU GPIO controller
   4  *
   5  * Copyright (C) 2018 Microchip Technology Inc. and its subsidiaries
   6  *
   7  * Author: Andrei Stefanescu <andrei.stefanescu@microchip.com>
   8  *
   9  */
  10 #include <linux/bits.h>
  11 #include <linux/gpio/driver.h>
  12 #include <linux/init.h>
  13 #include <linux/kernel.h>
  14 #include <linux/mfd/syscon.h>
  15 #include <linux/module.h>
  16 #include <linux/of.h>
  17 #include <linux/platform_device.h>
  18 #include <linux/regmap.h>
  19 
  20 #define PIOBU_NUM 8
  21 #define PIOBU_REG_SIZE 4
  22 
  23 /*
  24  * backup mode protection register for tamper detection
  25  * normal mode protection register for tamper detection
  26  * wakeup signal generation
  27  */
  28 #define PIOBU_BMPR 0x7C
  29 #define PIOBU_NMPR 0x80
  30 #define PIOBU_WKPR 0x90
  31 
  32 #define PIOBU_BASE 0x18 /* PIOBU offset from SECUMOD base register address. */
  33 
  34 #define PIOBU_DET_OFFSET 16
  35 
  36 /* In the datasheet this bit is called OUTPUT */
  37 #define PIOBU_DIRECTION BIT(8)
  38 #define PIOBU_OUT BIT(8)
  39 #define PIOBU_IN 0
  40 
  41 #define PIOBU_SOD BIT(9)
  42 #define PIOBU_PDS BIT(10)
  43 
  44 #define PIOBU_HIGH BIT(9)
  45 #define PIOBU_LOW 0
  46 
  47 struct sama5d2_piobu {
  48         struct gpio_chip chip;
  49         struct regmap *regmap;
  50 };
  51 
  52 /**
  53  * sama5d2_piobu_setup_pin() - prepares a pin for set_direction call
  54  *
  55  * Do not consider pin for tamper detection (normal and backup modes)
  56  * Do not consider pin as tamper wakeup interrupt source
  57  */
  58 static int sama5d2_piobu_setup_pin(struct gpio_chip *chip, unsigned int pin)
  59 {
  60         int ret;
  61         struct sama5d2_piobu *piobu = container_of(chip, struct sama5d2_piobu,
  62                                                    chip);
  63         unsigned int mask = BIT(PIOBU_DET_OFFSET + pin);
  64 
  65         ret = regmap_update_bits(piobu->regmap, PIOBU_BMPR, mask, 0);
  66         if (ret)
  67                 return ret;
  68 
  69         ret = regmap_update_bits(piobu->regmap, PIOBU_NMPR, mask, 0);
  70         if (ret)
  71                 return ret;
  72 
  73         return regmap_update_bits(piobu->regmap, PIOBU_WKPR, mask, 0);
  74 }
  75 
  76 /**
  77  * sama5d2_piobu_write_value() - writes value & mask at the pin's PIOBU register
  78  */
  79 static int sama5d2_piobu_write_value(struct gpio_chip *chip, unsigned int pin,
  80                                      unsigned int mask, unsigned int value)
  81 {
  82         int reg;
  83         struct sama5d2_piobu *piobu = container_of(chip, struct sama5d2_piobu,
  84                                                    chip);
  85 
  86         reg = PIOBU_BASE + pin * PIOBU_REG_SIZE;
  87 
  88         return regmap_update_bits(piobu->regmap, reg, mask, value);
  89 }
  90 
  91 /**
  92  * sama5d2_piobu_read_value() - read the value with masking from the pin's PIOBU
  93  *                            register
  94  */
  95 static int sama5d2_piobu_read_value(struct gpio_chip *chip, unsigned int pin,
  96                                     unsigned int mask)
  97 {
  98         struct sama5d2_piobu *piobu = container_of(chip, struct sama5d2_piobu,
  99                                                    chip);
 100         unsigned int val, reg;
 101         int ret;
 102 
 103         reg = PIOBU_BASE + pin * PIOBU_REG_SIZE;
 104         ret = regmap_read(piobu->regmap, reg, &val);
 105         if (ret < 0)
 106                 return ret;
 107 
 108         return val & mask;
 109 }
 110 
 111 /**
 112  * sama5d2_piobu_get_direction() - gpiochip get_direction
 113  */
 114 static int sama5d2_piobu_get_direction(struct gpio_chip *chip,
 115                                        unsigned int pin)
 116 {
 117         int ret = sama5d2_piobu_read_value(chip, pin, PIOBU_DIRECTION);
 118 
 119         if (ret < 0)
 120                 return ret;
 121 
 122         return (ret == PIOBU_IN) ? 1 : 0;
 123 }
 124 
 125 /**
 126  * sama5d2_piobu_direction_input() - gpiochip direction_input
 127  */
 128 static int sama5d2_piobu_direction_input(struct gpio_chip *chip,
 129                                          unsigned int pin)
 130 {
 131         return sama5d2_piobu_write_value(chip, pin, PIOBU_DIRECTION, PIOBU_IN);
 132 }
 133 
 134 /**
 135  * sama5d2_piobu_direction_output() - gpiochip direction_output
 136  */
 137 static int sama5d2_piobu_direction_output(struct gpio_chip *chip,
 138                                           unsigned int pin, int value)
 139 {
 140         unsigned int val = PIOBU_OUT;
 141 
 142         if (value)
 143                 val |= PIOBU_HIGH;
 144 
 145         return sama5d2_piobu_write_value(chip, pin, PIOBU_DIRECTION | PIOBU_SOD,
 146                                          val);
 147 }
 148 
 149 /**
 150  * sama5d2_piobu_get() - gpiochip get
 151  */
 152 static int sama5d2_piobu_get(struct gpio_chip *chip, unsigned int pin)
 153 {
 154         /* if pin is input, read value from PDS else read from SOD */
 155         int ret = sama5d2_piobu_get_direction(chip, pin);
 156 
 157         if (ret == 1)
 158                 ret = sama5d2_piobu_read_value(chip, pin, PIOBU_PDS);
 159         else if (!ret)
 160                 ret = sama5d2_piobu_read_value(chip, pin, PIOBU_SOD);
 161 
 162         if (ret < 0)
 163                 return ret;
 164 
 165         return !!ret;
 166 }
 167 
 168 /**
 169  * sama5d2_piobu_set() - gpiochip set
 170  */
 171 static void sama5d2_piobu_set(struct gpio_chip *chip, unsigned int pin,
 172                               int value)
 173 {
 174         if (!value)
 175                 value = PIOBU_LOW;
 176         else
 177                 value = PIOBU_HIGH;
 178 
 179         sama5d2_piobu_write_value(chip, pin, PIOBU_SOD, value);
 180 }
 181 
 182 static int sama5d2_piobu_probe(struct platform_device *pdev)
 183 {
 184         struct sama5d2_piobu *piobu;
 185         int ret, i;
 186 
 187         piobu = devm_kzalloc(&pdev->dev, sizeof(*piobu), GFP_KERNEL);
 188         if (!piobu)
 189                 return -ENOMEM;
 190 
 191         platform_set_drvdata(pdev, piobu);
 192         piobu->chip.label = pdev->name;
 193         piobu->chip.parent = &pdev->dev;
 194         piobu->chip.of_node = pdev->dev.of_node;
 195         piobu->chip.owner = THIS_MODULE,
 196         piobu->chip.get_direction = sama5d2_piobu_get_direction,
 197         piobu->chip.direction_input = sama5d2_piobu_direction_input,
 198         piobu->chip.direction_output = sama5d2_piobu_direction_output,
 199         piobu->chip.get = sama5d2_piobu_get,
 200         piobu->chip.set = sama5d2_piobu_set,
 201         piobu->chip.base = -1,
 202         piobu->chip.ngpio = PIOBU_NUM,
 203         piobu->chip.can_sleep = 0,
 204 
 205         piobu->regmap = syscon_node_to_regmap(pdev->dev.of_node);
 206         if (IS_ERR(piobu->regmap)) {
 207                 dev_err(&pdev->dev, "Failed to get syscon regmap %ld\n",
 208                         PTR_ERR(piobu->regmap));
 209                 return PTR_ERR(piobu->regmap);
 210         }
 211 
 212         ret = devm_gpiochip_add_data(&pdev->dev, &piobu->chip, piobu);
 213         if (ret) {
 214                 dev_err(&pdev->dev, "Failed to add gpiochip %d\n", ret);
 215                 return ret;
 216         }
 217 
 218         for (i = 0; i < PIOBU_NUM; ++i) {
 219                 ret = sama5d2_piobu_setup_pin(&piobu->chip, i);
 220                 if (ret) {
 221                         dev_err(&pdev->dev, "Failed to setup pin: %d %d\n",
 222                                 i, ret);
 223                         return ret;
 224                 }
 225         }
 226 
 227         return 0;
 228 }
 229 
 230 static const struct of_device_id sama5d2_piobu_ids[] = {
 231         { .compatible = "atmel,sama5d2-secumod" },
 232         {},
 233 };
 234 MODULE_DEVICE_TABLE(of, sama5d2_piobu_ids);
 235 
 236 static struct platform_driver sama5d2_piobu_driver = {
 237         .driver = {
 238                 .name           = "sama5d2-piobu",
 239                 .of_match_table = of_match_ptr(sama5d2_piobu_ids)
 240         },
 241         .probe = sama5d2_piobu_probe,
 242 };
 243 
 244 module_platform_driver(sama5d2_piobu_driver);
 245 
 246 MODULE_VERSION("1.0");
 247 MODULE_LICENSE("GPL v2");
 248 MODULE_DESCRIPTION("SAMA5D2 PIOBU controller driver");
 249 MODULE_AUTHOR("Andrei Stefanescu <andrei.stefanescu@microchip.com>");

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