root/drivers/gpio/gpio-vf610.c

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

DEFINITIONS

This source file includes following definitions.
  1. vf610_gpio_writel
  2. vf610_gpio_readl
  3. vf610_gpio_get
  4. vf610_gpio_set
  5. vf610_gpio_direction_input
  6. vf610_gpio_direction_output
  7. vf610_gpio_irq_handler
  8. vf610_gpio_irq_ack
  9. vf610_gpio_irq_set_type
  10. vf610_gpio_irq_mask
  11. vf610_gpio_irq_unmask
  12. vf610_gpio_irq_set_wake
  13. vf610_gpio_disable_clk
  14. vf610_gpio_probe

   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 
  25 struct fsl_gpio_soc_data {
  26         /* SoCs has a Port Data Direction Register (PDDR) */
  27         bool have_paddr;
  28 };
  29 
  30 struct 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 
  64 static const struct fsl_gpio_soc_data imx_data = {
  65         .have_paddr = true,
  66 };
  67 
  68 static 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 
  74 static inline void vf610_gpio_writel(u32 val, void __iomem *reg)
  75 {
  76         writel_relaxed(val, reg);
  77 }
  78 
  79 static inline u32 vf610_gpio_readl(void __iomem *reg)
  80 {
  81         return readl_relaxed(reg);
  82 }
  83 
  84 static 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 
  99 static 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 
 108 static 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 
 123 static 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 
 137 static 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 
 158 static 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 
 167 static 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 
 203 static 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 
 212 static 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 
 222 static 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 
 235 static void vf610_gpio_disable_clk(void *data)
 236 {
 237         clk_disable_unprepare(data);
 238 }
 239 
 240 static 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 
 345 static 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 
 353 builtin_platform_driver(vf610_gpio_driver);

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