linux/drivers/gpio/gpio-siox.c
<<
>>
Prefs
   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
  11struct 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 */
  28static 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
  39static 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
  98static 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
 109static 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
 120static 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
 131static 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
 144static 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
 167static 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
 184static 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
 193static 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
 203static 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
 211static 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
 256static 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};
 264module_siox_driver(gpio_siox_driver);
 265
 266MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
 267MODULE_DESCRIPTION("SIOX gpio driver");
 268MODULE_LICENSE("GPL v2");
 269