linux/drivers/gpio/gpio-visconti.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Toshiba Visconti GPIO Support
   4 *
   5 * (C) Copyright 2020 Toshiba Electronic Devices & Storage Corporation
   6 * (C) Copyright 2020 TOSHIBA CORPORATION
   7 *
   8 * Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
   9 */
  10
  11#include <linux/gpio/driver.h>
  12#include <linux/init.h>
  13#include <linux/interrupt.h>
  14#include <linux/module.h>
  15#include <linux/io.h>
  16#include <linux/of_irq.h>
  17#include <linux/platform_device.h>
  18#include <linux/bitops.h>
  19
  20/* register offset */
  21#define GPIO_DIR        0x00
  22#define GPIO_IDATA      0x08
  23#define GPIO_ODATA      0x10
  24#define GPIO_OSET       0x18
  25#define GPIO_OCLR       0x20
  26#define GPIO_INTMODE    0x30
  27
  28#define BASE_HW_IRQ 24
  29
  30struct visconti_gpio {
  31        void __iomem *base;
  32        spinlock_t lock; /* protect gpio register */
  33        struct gpio_chip gpio_chip;
  34        struct irq_chip irq_chip;
  35};
  36
  37static int visconti_gpio_irq_set_type(struct irq_data *d, unsigned int type)
  38{
  39        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
  40        struct visconti_gpio *priv = gpiochip_get_data(gc);
  41        u32 offset = irqd_to_hwirq(d);
  42        u32 bit = BIT(offset);
  43        u32 intc_type = IRQ_TYPE_EDGE_RISING;
  44        u32 intmode, odata;
  45        int ret = 0;
  46        unsigned long flags;
  47
  48        spin_lock_irqsave(&priv->lock, flags);
  49
  50        odata = readl(priv->base + GPIO_ODATA);
  51        intmode = readl(priv->base + GPIO_INTMODE);
  52
  53        switch (type) {
  54        case IRQ_TYPE_EDGE_RISING:
  55                odata &= ~bit;
  56                intmode &= ~bit;
  57                break;
  58        case IRQ_TYPE_EDGE_FALLING:
  59                odata |= bit;
  60                intmode &= ~bit;
  61                break;
  62        case IRQ_TYPE_EDGE_BOTH:
  63                intmode |= bit;
  64                break;
  65        case IRQ_TYPE_LEVEL_HIGH:
  66                intc_type = IRQ_TYPE_LEVEL_HIGH;
  67                odata &= ~bit;
  68                intmode &= ~bit;
  69                break;
  70        case IRQ_TYPE_LEVEL_LOW:
  71                intc_type = IRQ_TYPE_LEVEL_HIGH;
  72                odata |= bit;
  73                intmode &= ~bit;
  74                break;
  75        default:
  76                ret = -EINVAL;
  77                goto err;
  78        }
  79
  80        writel(odata, priv->base + GPIO_ODATA);
  81        writel(intmode, priv->base + GPIO_INTMODE);
  82        irq_set_irq_type(offset, intc_type);
  83
  84        ret = irq_chip_set_type_parent(d, type);
  85err:
  86        spin_unlock_irqrestore(&priv->lock, flags);
  87        return ret;
  88}
  89
  90static int visconti_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
  91                                               unsigned int child,
  92                                               unsigned int child_type,
  93                                               unsigned int *parent,
  94                                               unsigned int *parent_type)
  95{
  96        /* Interrupts 0..15 mapped to interrupts 24..39 on the GIC */
  97        if (child < 16) {
  98                /* All these interrupts are level high in the CPU */
  99                *parent_type = IRQ_TYPE_LEVEL_HIGH;
 100                *parent = child + BASE_HW_IRQ;
 101                return 0;
 102        }
 103        return -EINVAL;
 104}
 105
 106static void *visconti_gpio_populate_parent_fwspec(struct gpio_chip *chip,
 107                                                  unsigned int parent_hwirq,
 108                                                  unsigned int parent_type)
 109{
 110        struct irq_fwspec *fwspec;
 111
 112        fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
 113        if (!fwspec)
 114                return NULL;
 115
 116        fwspec->fwnode = chip->irq.parent_domain->fwnode;
 117        fwspec->param_count = 3;
 118        fwspec->param[0] = 0;
 119        fwspec->param[1] = parent_hwirq;
 120        fwspec->param[2] = parent_type;
 121
 122        return fwspec;
 123}
 124
 125static int visconti_gpio_probe(struct platform_device *pdev)
 126{
 127        struct device *dev = &pdev->dev;
 128        struct visconti_gpio *priv;
 129        struct irq_chip *irq_chip;
 130        struct gpio_irq_chip *girq;
 131        struct irq_domain *parent;
 132        struct device_node *irq_parent;
 133        struct fwnode_handle *fwnode;
 134        int ret;
 135
 136        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 137        if (!priv)
 138                return -ENOMEM;
 139
 140        spin_lock_init(&priv->lock);
 141
 142        priv->base = devm_platform_ioremap_resource(pdev, 0);
 143        if (IS_ERR(priv->base))
 144                return PTR_ERR(priv->base);
 145
 146        irq_parent = of_irq_find_parent(dev->of_node);
 147        if (!irq_parent) {
 148                dev_err(dev, "No IRQ parent node\n");
 149                return -ENODEV;
 150        }
 151
 152        parent = irq_find_host(irq_parent);
 153        if (!parent) {
 154                dev_err(dev, "No IRQ parent domain\n");
 155                return -ENODEV;
 156        }
 157
 158        fwnode = of_node_to_fwnode(irq_parent);
 159        of_node_put(irq_parent);
 160
 161        ret = bgpio_init(&priv->gpio_chip, dev, 4,
 162                         priv->base + GPIO_IDATA,
 163                         priv->base + GPIO_OSET,
 164                         priv->base + GPIO_OCLR,
 165                         priv->base + GPIO_DIR,
 166                         NULL,
 167                         0);
 168        if (ret) {
 169                dev_err(dev, "unable to init generic GPIO\n");
 170                return ret;
 171        }
 172
 173        irq_chip = &priv->irq_chip;
 174        irq_chip->name = dev_name(dev);
 175        irq_chip->irq_mask = irq_chip_mask_parent;
 176        irq_chip->irq_unmask = irq_chip_unmask_parent;
 177        irq_chip->irq_eoi = irq_chip_eoi_parent;
 178        irq_chip->irq_set_type = visconti_gpio_irq_set_type;
 179        irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
 180
 181        girq = &priv->gpio_chip.irq;
 182        girq->chip = irq_chip;
 183        girq->fwnode = fwnode;
 184        girq->parent_domain = parent;
 185        girq->child_to_parent_hwirq = visconti_gpio_child_to_parent_hwirq;
 186        girq->populate_parent_alloc_arg = visconti_gpio_populate_parent_fwspec;
 187        girq->default_type = IRQ_TYPE_NONE;
 188        girq->handler = handle_level_irq;
 189
 190        return devm_gpiochip_add_data(dev, &priv->gpio_chip, priv);
 191}
 192
 193static const struct of_device_id visconti_gpio_of_match[] = {
 194        { .compatible = "toshiba,gpio-tmpv7708", },
 195        { /* end of table */ }
 196};
 197MODULE_DEVICE_TABLE(of, visconti_gpio_of_match);
 198
 199static struct platform_driver visconti_gpio_driver = {
 200        .probe          = visconti_gpio_probe,
 201        .driver         = {
 202                .name   = "visconti_gpio",
 203                .of_match_table = of_match_ptr(visconti_gpio_of_match),
 204        }
 205};
 206module_platform_driver(visconti_gpio_driver);
 207
 208MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>");
 209MODULE_DESCRIPTION("Toshiba Visconti GPIO Driver");
 210MODULE_LICENSE("GPL v2");
 211