linux/drivers/gpio/gpio-vf610.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Freescale vf610 GPIO support through PORT and GPIO
   4 *
   5 * Copyright (c) 2014 Toradex AG.
   6 *
   7 * Author: Stefan Agner <stefan@agner.ch>.
   8 */
   9#include <linux/bitops.h>
  10#include <linux/clk.h>
  11#include <linux/err.h>
  12#include <linux/gpio/driver.h>
  13#include <linux/init.h>
  14#include <linux/interrupt.h>
  15#include <linux/io.h>
  16#include <linux/ioport.h>
  17#include <linux/irq.h>
  18#include <linux/platform_device.h>
  19#include <linux/of.h>
  20#include <linux/of_device.h>
  21#include <linux/of_irq.h>
  22
  23#define VF610_GPIO_PER_PORT             32
  24
  25struct fsl_gpio_soc_data {
  26        /* SoCs has a Port Data Direction Register (PDDR) */
  27        bool have_paddr;
  28};
  29
  30struct vf610_gpio_port {
  31        struct gpio_chip gc;
  32        struct irq_chip ic;
  33        void __iomem *base;
  34        void __iomem *gpio_base;
  35        const struct fsl_gpio_soc_data *sdata;
  36        u8 irqc[VF610_GPIO_PER_PORT];
  37        struct clk *clk_port;
  38        struct clk *clk_gpio;
  39        int irq;
  40};
  41
  42#define GPIO_PDOR               0x00
  43#define GPIO_PSOR               0x04
  44#define GPIO_PCOR               0x08
  45#define GPIO_PTOR               0x0c
  46#define GPIO_PDIR               0x10
  47#define GPIO_PDDR               0x14
  48
  49#define PORT_PCR(n)             ((n) * 0x4)
  50#define PORT_PCR_IRQC_OFFSET    16
  51
  52#define PORT_ISFR               0xa0
  53#define PORT_DFER               0xc0
  54#define PORT_DFCR               0xc4
  55#define PORT_DFWR               0xc8
  56
  57#define PORT_INT_OFF            0x0
  58#define PORT_INT_LOGIC_ZERO     0x8
  59#define PORT_INT_RISING_EDGE    0x9
  60#define PORT_INT_FALLING_EDGE   0xa
  61#define PORT_INT_EITHER_EDGE    0xb
  62#define PORT_INT_LOGIC_ONE      0xc
  63
  64static const struct fsl_gpio_soc_data imx_data = {
  65        .have_paddr = true,
  66};
  67
  68static const struct of_device_id vf610_gpio_dt_ids[] = {
  69        { .compatible = "fsl,vf610-gpio",       .data = NULL, },
  70        { .compatible = "fsl,imx7ulp-gpio",     .data = &imx_data, },
  71        { /* sentinel */ }
  72};
  73
  74static inline void vf610_gpio_writel(u32 val, void __iomem *reg)
  75{
  76        writel_relaxed(val, reg);
  77}
  78
  79static inline u32 vf610_gpio_readl(void __iomem *reg)
  80{
  81        return readl_relaxed(reg);
  82}
  83
  84static int vf610_gpio_get(struct gpio_chip *gc, unsigned int gpio)
  85{
  86        struct vf610_gpio_port *port = gpiochip_get_data(gc);
  87        unsigned long mask = BIT(gpio);
  88        unsigned long offset = GPIO_PDIR;
  89
  90        if (port->sdata && port->sdata->have_paddr) {
  91                mask &= vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
  92                if (mask)
  93                        offset = GPIO_PDOR;
  94        }
  95
  96        return !!(vf610_gpio_readl(port->gpio_base + offset) & BIT(gpio));
  97}
  98
  99static void vf610_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
 100{
 101        struct vf610_gpio_port *port = gpiochip_get_data(gc);
 102        unsigned long mask = BIT(gpio);
 103        unsigned long offset = val ? GPIO_PSOR : GPIO_PCOR;
 104
 105        vf610_gpio_writel(mask, port->gpio_base + offset);
 106}
 107
 108static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
 109{
 110        struct vf610_gpio_port *port = gpiochip_get_data(chip);
 111        unsigned long mask = BIT(gpio);
 112        u32 val;
 113
 114        if (port->sdata && port->sdata->have_paddr) {
 115                val = vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
 116                val &= ~mask;
 117                vf610_gpio_writel(val, port->gpio_base + GPIO_PDDR);
 118        }
 119
 120        return pinctrl_gpio_direction_input(chip->base + gpio);
 121}
 122
 123static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
 124                                       int value)
 125{
 126        struct vf610_gpio_port *port = gpiochip_get_data(chip);
 127        unsigned long mask = BIT(gpio);
 128
 129        if (port->sdata && port->sdata->have_paddr)
 130                vf610_gpio_writel(mask, port->gpio_base + GPIO_PDDR);
 131
 132        vf610_gpio_set(chip, gpio, value);
 133
 134        return pinctrl_gpio_direction_output(chip->base + gpio);
 135}
 136
 137static void vf610_gpio_irq_handler(struct irq_desc *desc)
 138{
 139        struct vf610_gpio_port *port =
 140                gpiochip_get_data(irq_desc_get_handler_data(desc));
 141        struct irq_chip *chip = irq_desc_get_chip(desc);
 142        int pin;
 143        unsigned long irq_isfr;
 144
 145        chained_irq_enter(chip, desc);
 146
 147        irq_isfr = vf610_gpio_readl(port->base + PORT_ISFR);
 148
 149        for_each_set_bit(pin, &irq_isfr, VF610_GPIO_PER_PORT) {
 150                vf610_gpio_writel(BIT(pin), port->base + PORT_ISFR);
 151
 152                generic_handle_irq(irq_find_mapping(port->gc.irq.domain, pin));
 153        }
 154
 155        chained_irq_exit(chip, desc);
 156}
 157
 158static void vf610_gpio_irq_ack(struct irq_data *d)
 159{
 160        struct vf610_gpio_port *port =
 161                gpiochip_get_data(irq_data_get_irq_chip_data(d));
 162        int gpio = d->hwirq;
 163
 164        vf610_gpio_writel(BIT(gpio), port->base + PORT_ISFR);
 165}
 166
 167static int vf610_gpio_irq_set_type(struct irq_data *d, u32 type)
 168{
 169        struct vf610_gpio_port *port =
 170                gpiochip_get_data(irq_data_get_irq_chip_data(d));
 171        u8 irqc;
 172
 173        switch (type) {
 174        case IRQ_TYPE_EDGE_RISING:
 175                irqc = PORT_INT_RISING_EDGE;
 176                break;
 177        case IRQ_TYPE_EDGE_FALLING:
 178                irqc = PORT_INT_FALLING_EDGE;
 179                break;
 180        case IRQ_TYPE_EDGE_BOTH:
 181                irqc = PORT_INT_EITHER_EDGE;
 182                break;
 183        case IRQ_TYPE_LEVEL_LOW:
 184                irqc = PORT_INT_LOGIC_ZERO;
 185                break;
 186        case IRQ_TYPE_LEVEL_HIGH:
 187                irqc = PORT_INT_LOGIC_ONE;
 188                break;
 189        default:
 190                return -EINVAL;
 191        }
 192
 193        port->irqc[d->hwirq] = irqc;
 194
 195        if (type & IRQ_TYPE_LEVEL_MASK)
 196                irq_set_handler_locked(d, handle_level_irq);
 197        else
 198                irq_set_handler_locked(d, handle_edge_irq);
 199
 200        return 0;
 201}
 202
 203static void vf610_gpio_irq_mask(struct irq_data *d)
 204{
 205        struct vf610_gpio_port *port =
 206                gpiochip_get_data(irq_data_get_irq_chip_data(d));
 207        void __iomem *pcr_base = port->base + PORT_PCR(d->hwirq);
 208
 209        vf610_gpio_writel(0, pcr_base);
 210}
 211
 212static void vf610_gpio_irq_unmask(struct irq_data *d)
 213{
 214        struct vf610_gpio_port *port =
 215                gpiochip_get_data(irq_data_get_irq_chip_data(d));
 216        void __iomem *pcr_base = port->base + PORT_PCR(d->hwirq);
 217
 218        vf610_gpio_writel(port->irqc[d->hwirq] << PORT_PCR_IRQC_OFFSET,
 219                          pcr_base);
 220}
 221
 222static int vf610_gpio_irq_set_wake(struct irq_data *d, u32 enable)
 223{
 224        struct vf610_gpio_port *port =
 225                gpiochip_get_data(irq_data_get_irq_chip_data(d));
 226
 227        if (enable)
 228                enable_irq_wake(port->irq);
 229        else
 230                disable_irq_wake(port->irq);
 231
 232        return 0;
 233}
 234
 235static void vf610_gpio_disable_clk(void *data)
 236{
 237        clk_disable_unprepare(data);
 238}
 239
 240static int vf610_gpio_probe(struct platform_device *pdev)
 241{
 242        struct device *dev = &pdev->dev;
 243        struct device_node *np = dev->of_node;
 244        struct vf610_gpio_port *port;
 245        struct gpio_chip *gc;
 246        struct gpio_irq_chip *girq;
 247        struct irq_chip *ic;
 248        int i;
 249        int ret;
 250
 251        port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
 252        if (!port)
 253                return -ENOMEM;
 254
 255        port->sdata = of_device_get_match_data(dev);
 256        port->base = devm_platform_ioremap_resource(pdev, 0);
 257        if (IS_ERR(port->base))
 258                return PTR_ERR(port->base);
 259
 260        port->gpio_base = devm_platform_ioremap_resource(pdev, 1);
 261        if (IS_ERR(port->gpio_base))
 262                return PTR_ERR(port->gpio_base);
 263
 264        port->irq = platform_get_irq(pdev, 0);
 265        if (port->irq < 0)
 266                return port->irq;
 267
 268        port->clk_port = devm_clk_get(dev, "port");
 269        ret = PTR_ERR_OR_ZERO(port->clk_port);
 270        if (!ret) {
 271                ret = clk_prepare_enable(port->clk_port);
 272                if (ret)
 273                        return ret;
 274                ret = devm_add_action_or_reset(dev, vf610_gpio_disable_clk,
 275                                               port->clk_port);
 276                if (ret)
 277                        return ret;
 278        } else if (ret == -EPROBE_DEFER) {
 279                /*
 280                 * Percolate deferrals, for anything else,
 281                 * just live without the clocking.
 282                 */
 283                return ret;
 284        }
 285
 286        port->clk_gpio = devm_clk_get(dev, "gpio");
 287        ret = PTR_ERR_OR_ZERO(port->clk_gpio);
 288        if (!ret) {
 289                ret = clk_prepare_enable(port->clk_gpio);
 290                if (ret)
 291                        return ret;
 292                ret = devm_add_action_or_reset(dev, vf610_gpio_disable_clk,
 293                                               port->clk_gpio);
 294                if (ret)
 295                        return ret;
 296        } else if (ret == -EPROBE_DEFER) {
 297                return ret;
 298        }
 299
 300        gc = &port->gc;
 301        gc->of_node = np;
 302        gc->parent = dev;
 303        gc->label = "vf610-gpio";
 304        gc->ngpio = VF610_GPIO_PER_PORT;
 305        gc->base = of_alias_get_id(np, "gpio") * VF610_GPIO_PER_PORT;
 306
 307        gc->request = gpiochip_generic_request;
 308        gc->free = gpiochip_generic_free;
 309        gc->direction_input = vf610_gpio_direction_input;
 310        gc->get = vf610_gpio_get;
 311        gc->direction_output = vf610_gpio_direction_output;
 312        gc->set = vf610_gpio_set;
 313
 314        ic = &port->ic;
 315        ic->name = "gpio-vf610";
 316        ic->irq_ack = vf610_gpio_irq_ack;
 317        ic->irq_mask = vf610_gpio_irq_mask;
 318        ic->irq_unmask = vf610_gpio_irq_unmask;
 319        ic->irq_set_type = vf610_gpio_irq_set_type;
 320        ic->irq_set_wake = vf610_gpio_irq_set_wake;
 321
 322        /* Mask all GPIO interrupts */
 323        for (i = 0; i < gc->ngpio; i++)
 324                vf610_gpio_writel(0, port->base + PORT_PCR(i));
 325
 326        /* Clear the interrupt status register for all GPIO's */
 327        vf610_gpio_writel(~0, port->base + PORT_ISFR);
 328
 329        girq = &gc->irq;
 330        girq->chip = ic;
 331        girq->parent_handler = vf610_gpio_irq_handler;
 332        girq->num_parents = 1;
 333        girq->parents = devm_kcalloc(&pdev->dev, 1,
 334                                     sizeof(*girq->parents),
 335                                     GFP_KERNEL);
 336        if (!girq->parents)
 337                return -ENOMEM;
 338        girq->parents[0] = port->irq;
 339        girq->default_type = IRQ_TYPE_NONE;
 340        girq->handler = handle_edge_irq;
 341
 342        return devm_gpiochip_add_data(dev, gc, port);
 343}
 344
 345static struct platform_driver vf610_gpio_driver = {
 346        .driver         = {
 347                .name   = "gpio-vf610",
 348                .of_match_table = vf610_gpio_dt_ids,
 349        },
 350        .probe          = vf610_gpio_probe,
 351};
 352
 353builtin_platform_driver(vf610_gpio_driver);
 354