root/drivers/gpio/gpio-siox.c

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

DEFINITIONS

This source file includes following definitions.
  1. gpio_siox_set_data
  2. gpio_siox_get_data
  3. gpio_siox_irq_ack
  4. gpio_siox_irq_mask
  5. gpio_siox_irq_unmask
  6. gpio_siox_irq_set_type
  7. gpio_siox_get
  8. gpio_siox_set
  9. gpio_siox_direction_input
  10. gpio_siox_direction_output
  11. gpio_siox_get_direction
  12. gpio_siox_probe

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (C) 2015-2018 Pengutronix, Uwe Kleine-König <kernel@pengutronix.de>
   4  */
   5 
   6 #include <linux/module.h>
   7 #include <linux/siox.h>
   8 #include <linux/gpio/driver.h>
   9 #include <linux/of.h>
  10 
  11 struct gpio_siox_ddata {
  12         struct gpio_chip gchip;
  13         struct irq_chip ichip;
  14         struct mutex lock;
  15         u8 setdata[1];
  16         u8 getdata[3];
  17 
  18         spinlock_t irqlock;
  19         u32 irq_enable;
  20         u32 irq_status;
  21         u32 irq_type[20];
  22 };
  23 
  24 /*
  25  * Note that this callback only sets the value that is clocked out in the next
  26  * cycle.
  27  */
  28 static int gpio_siox_set_data(struct siox_device *sdevice, u8 status, u8 buf[])
  29 {
  30         struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev);
  31 
  32         mutex_lock(&ddata->lock);
  33         buf[0] = ddata->setdata[0];
  34         mutex_unlock(&ddata->lock);
  35 
  36         return 0;
  37 }
  38 
  39 static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[])
  40 {
  41         struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev);
  42         size_t offset;
  43         u32 trigger;
  44 
  45         mutex_lock(&ddata->lock);
  46 
  47         spin_lock_irq(&ddata->irqlock);
  48 
  49         for (offset = 0; offset < 12; ++offset) {
  50                 unsigned int bitpos = 11 - offset;
  51                 unsigned int gpiolevel = buf[bitpos / 8] & (1 << bitpos % 8);
  52                 unsigned int prev_level =
  53                         ddata->getdata[bitpos / 8] & (1 << (bitpos % 8));
  54                 u32 irq_type = ddata->irq_type[offset];
  55 
  56                 if (gpiolevel) {
  57                         if ((irq_type & IRQ_TYPE_LEVEL_HIGH) ||
  58                             ((irq_type & IRQ_TYPE_EDGE_RISING) && !prev_level))
  59                                 ddata->irq_status |= 1 << offset;
  60                 } else {
  61                         if ((irq_type & IRQ_TYPE_LEVEL_LOW) ||
  62                             ((irq_type & IRQ_TYPE_EDGE_FALLING) && prev_level))
  63                                 ddata->irq_status |= 1 << offset;
  64                 }
  65         }
  66 
  67         trigger = ddata->irq_status & ddata->irq_enable;
  68 
  69         spin_unlock_irq(&ddata->irqlock);
  70 
  71         ddata->getdata[0] = buf[0];
  72         ddata->getdata[1] = buf[1];
  73         ddata->getdata[2] = buf[2];
  74 
  75         mutex_unlock(&ddata->lock);
  76 
  77         for (offset = 0; offset < 12; ++offset) {
  78                 if (trigger & (1 << offset)) {
  79                         struct irq_domain *irqdomain = ddata->gchip.irq.domain;
  80                         unsigned int irq = irq_find_mapping(irqdomain, offset);
  81 
  82                         /*
  83                          * Conceptually handle_nested_irq should call the flow
  84                          * handler of the irq chip. But it doesn't, so we have
  85                          * to clean the irq_status here.
  86                          */
  87                         spin_lock_irq(&ddata->irqlock);
  88                         ddata->irq_status &= ~(1 << offset);
  89                         spin_unlock_irq(&ddata->irqlock);
  90 
  91                         handle_nested_irq(irq);
  92                 }
  93         }
  94 
  95         return 0;
  96 }
  97 
  98 static void gpio_siox_irq_ack(struct irq_data *d)
  99 {
 100         struct irq_chip *ic = irq_data_get_irq_chip(d);
 101         struct gpio_siox_ddata *ddata =
 102                 container_of(ic, struct gpio_siox_ddata, ichip);
 103 
 104         spin_lock_irq(&ddata->irqlock);
 105         ddata->irq_status &= ~(1 << d->hwirq);
 106         spin_unlock_irq(&ddata->irqlock);
 107 }
 108 
 109 static void gpio_siox_irq_mask(struct irq_data *d)
 110 {
 111         struct irq_chip *ic = irq_data_get_irq_chip(d);
 112         struct gpio_siox_ddata *ddata =
 113                 container_of(ic, struct gpio_siox_ddata, ichip);
 114 
 115         spin_lock_irq(&ddata->irqlock);
 116         ddata->irq_enable &= ~(1 << d->hwirq);
 117         spin_unlock_irq(&ddata->irqlock);
 118 }
 119 
 120 static void gpio_siox_irq_unmask(struct irq_data *d)
 121 {
 122         struct irq_chip *ic = irq_data_get_irq_chip(d);
 123         struct gpio_siox_ddata *ddata =
 124                 container_of(ic, struct gpio_siox_ddata, ichip);
 125 
 126         spin_lock_irq(&ddata->irqlock);
 127         ddata->irq_enable |= 1 << d->hwirq;
 128         spin_unlock_irq(&ddata->irqlock);
 129 }
 130 
 131 static int gpio_siox_irq_set_type(struct irq_data *d, u32 type)
 132 {
 133         struct irq_chip *ic = irq_data_get_irq_chip(d);
 134         struct gpio_siox_ddata *ddata =
 135                 container_of(ic, struct gpio_siox_ddata, ichip);
 136 
 137         spin_lock_irq(&ddata->irqlock);
 138         ddata->irq_type[d->hwirq] = type;
 139         spin_unlock_irq(&ddata->irqlock);
 140 
 141         return 0;
 142 }
 143 
 144 static int gpio_siox_get(struct gpio_chip *chip, unsigned int offset)
 145 {
 146         struct gpio_siox_ddata *ddata =
 147                 container_of(chip, struct gpio_siox_ddata, gchip);
 148         int ret;
 149 
 150         mutex_lock(&ddata->lock);
 151 
 152         if (offset >= 12) {
 153                 unsigned int bitpos = 19 - offset;
 154 
 155                 ret = ddata->setdata[0] & (1 << bitpos);
 156         } else {
 157                 unsigned int bitpos = 11 - offset;
 158 
 159                 ret = ddata->getdata[bitpos / 8] & (1 << (bitpos % 8));
 160         }
 161 
 162         mutex_unlock(&ddata->lock);
 163 
 164         return ret;
 165 }
 166 
 167 static void gpio_siox_set(struct gpio_chip *chip,
 168                           unsigned int offset, int value)
 169 {
 170         struct gpio_siox_ddata *ddata =
 171                 container_of(chip, struct gpio_siox_ddata, gchip);
 172         u8 mask = 1 << (19 - offset);
 173 
 174         mutex_lock(&ddata->lock);
 175 
 176         if (value)
 177                 ddata->setdata[0] |= mask;
 178         else
 179                 ddata->setdata[0] &= ~mask;
 180 
 181         mutex_unlock(&ddata->lock);
 182 }
 183 
 184 static int gpio_siox_direction_input(struct gpio_chip *chip,
 185                                      unsigned int offset)
 186 {
 187         if (offset >= 12)
 188                 return -EINVAL;
 189 
 190         return 0;
 191 }
 192 
 193 static int gpio_siox_direction_output(struct gpio_chip *chip,
 194                                       unsigned int offset, int value)
 195 {
 196         if (offset < 12)
 197                 return -EINVAL;
 198 
 199         gpio_siox_set(chip, offset, value);
 200         return 0;
 201 }
 202 
 203 static int gpio_siox_get_direction(struct gpio_chip *chip, unsigned int offset)
 204 {
 205         if (offset < 12)
 206                 return 1; /* input */
 207         else
 208                 return 0; /* output */
 209 }
 210 
 211 static int gpio_siox_probe(struct siox_device *sdevice)
 212 {
 213         struct gpio_siox_ddata *ddata;
 214         struct gpio_irq_chip *girq;
 215         struct device *dev = &sdevice->dev;
 216         int ret;
 217 
 218         ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
 219         if (!ddata)
 220                 return -ENOMEM;
 221 
 222         dev_set_drvdata(dev, ddata);
 223 
 224         mutex_init(&ddata->lock);
 225         spin_lock_init(&ddata->irqlock);
 226 
 227         ddata->gchip.base = -1;
 228         ddata->gchip.can_sleep = 1;
 229         ddata->gchip.parent = dev;
 230         ddata->gchip.owner = THIS_MODULE;
 231         ddata->gchip.get = gpio_siox_get;
 232         ddata->gchip.set = gpio_siox_set;
 233         ddata->gchip.direction_input = gpio_siox_direction_input;
 234         ddata->gchip.direction_output = gpio_siox_direction_output;
 235         ddata->gchip.get_direction = gpio_siox_get_direction;
 236         ddata->gchip.ngpio = 20;
 237 
 238         ddata->ichip.name = "siox-gpio";
 239         ddata->ichip.irq_ack = gpio_siox_irq_ack;
 240         ddata->ichip.irq_mask = gpio_siox_irq_mask;
 241         ddata->ichip.irq_unmask = gpio_siox_irq_unmask;
 242         ddata->ichip.irq_set_type = gpio_siox_irq_set_type;
 243 
 244         girq = &ddata->gchip.irq;
 245         girq->chip = &ddata->ichip;
 246         girq->default_type = IRQ_TYPE_NONE;
 247         girq->handler = handle_level_irq;
 248 
 249         ret = devm_gpiochip_add_data(dev, &ddata->gchip, NULL);
 250         if (ret)
 251                 dev_err(dev, "Failed to register gpio chip (%d)\n", ret);
 252 
 253         return ret;
 254 }
 255 
 256 static struct siox_driver gpio_siox_driver = {
 257         .probe = gpio_siox_probe,
 258         .set_data = gpio_siox_set_data,
 259         .get_data = gpio_siox_get_data,
 260         .driver = {
 261                 .name = "gpio-siox",
 262         },
 263 };
 264 module_siox_driver(gpio_siox_driver);
 265 
 266 MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
 267 MODULE_DESCRIPTION("SIOX gpio driver");
 268 MODULE_LICENSE("GPL v2");

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