linux/drivers/gpio/gpio-tz1090-pdc.c
<<
>>
Prefs
   1/*
   2 * Toumaz Xenif TZ1090 PDC GPIO handling.
   3 *
   4 * Copyright (C) 2012-2013 Imagination Technologies Ltd.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10
  11#include <linux/bitops.h>
  12#include <linux/gpio.h>
  13#include <linux/io.h>
  14#include <linux/module.h>
  15#include <linux/of_irq.h>
  16#include <linux/pinctrl/consumer.h>
  17#include <linux/platform_device.h>
  18#include <linux/slab.h>
  19#include <linux/syscore_ops.h>
  20#include <asm/global_lock.h>
  21
  22/* Register offsets from SOC_GPIO_CONTROL0 */
  23#define REG_SOC_GPIO_CONTROL0   0x00
  24#define REG_SOC_GPIO_CONTROL1   0x04
  25#define REG_SOC_GPIO_CONTROL2   0x08
  26#define REG_SOC_GPIO_CONTROL3   0x0c
  27#define REG_SOC_GPIO_STATUS     0x80
  28
  29/* PDC GPIOs go after normal GPIOs */
  30#define GPIO_PDC_BASE           90
  31#define GPIO_PDC_NGPIO          7
  32
  33/* Out of PDC gpios, only syswakes have irqs */
  34#define GPIO_PDC_IRQ_FIRST      2
  35#define GPIO_PDC_NIRQ           3
  36
  37/**
  38 * struct tz1090_pdc_gpio - GPIO bank private data
  39 * @chip:       Generic GPIO chip for GPIO bank
  40 * @reg:        Base of registers, offset for this GPIO bank
  41 * @irq:        IRQ numbers for Syswake GPIOs
  42 *
  43 * This is the main private data for the PDC GPIO driver. It encapsulates a
  44 * gpio_chip, and the callbacks for the gpio_chip can access the private data
  45 * with the to_pdc() macro below.
  46 */
  47struct tz1090_pdc_gpio {
  48        struct gpio_chip chip;
  49        void __iomem *reg;
  50        int irq[GPIO_PDC_NIRQ];
  51};
  52
  53/* Register accesses into the PDC MMIO area */
  54
  55static inline void pdc_write(struct tz1090_pdc_gpio *priv, unsigned int reg_offs,
  56                      unsigned int data)
  57{
  58        writel(data, priv->reg + reg_offs);
  59}
  60
  61static inline unsigned int pdc_read(struct tz1090_pdc_gpio *priv,
  62                             unsigned int reg_offs)
  63{
  64        return readl(priv->reg + reg_offs);
  65}
  66
  67/* Generic GPIO interface */
  68
  69static int tz1090_pdc_gpio_direction_input(struct gpio_chip *chip,
  70                                           unsigned int offset)
  71{
  72        struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip);
  73        u32 value;
  74        int lstat;
  75
  76        __global_lock2(lstat);
  77        value = pdc_read(priv, REG_SOC_GPIO_CONTROL1);
  78        value |= BIT(offset);
  79        pdc_write(priv, REG_SOC_GPIO_CONTROL1, value);
  80        __global_unlock2(lstat);
  81
  82        return 0;
  83}
  84
  85static int tz1090_pdc_gpio_direction_output(struct gpio_chip *chip,
  86                                            unsigned int offset,
  87                                            int output_value)
  88{
  89        struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip);
  90        u32 value;
  91        int lstat;
  92
  93        __global_lock2(lstat);
  94        /* EXT_POWER doesn't seem to have an output value bit */
  95        if (offset < 6) {
  96                value = pdc_read(priv, REG_SOC_GPIO_CONTROL0);
  97                if (output_value)
  98                        value |= BIT(offset);
  99                else
 100                        value &= ~BIT(offset);
 101                pdc_write(priv, REG_SOC_GPIO_CONTROL0, value);
 102        }
 103
 104        value = pdc_read(priv, REG_SOC_GPIO_CONTROL1);
 105        value &= ~BIT(offset);
 106        pdc_write(priv, REG_SOC_GPIO_CONTROL1, value);
 107        __global_unlock2(lstat);
 108
 109        return 0;
 110}
 111
 112static int tz1090_pdc_gpio_get(struct gpio_chip *chip, unsigned int offset)
 113{
 114        struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip);
 115        return !!(pdc_read(priv, REG_SOC_GPIO_STATUS) & BIT(offset));
 116}
 117
 118static void tz1090_pdc_gpio_set(struct gpio_chip *chip, unsigned int offset,
 119                                int output_value)
 120{
 121        struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip);
 122        u32 value;
 123        int lstat;
 124
 125        /* EXT_POWER doesn't seem to have an output value bit */
 126        if (offset >= 6)
 127                return;
 128
 129        __global_lock2(lstat);
 130        value = pdc_read(priv, REG_SOC_GPIO_CONTROL0);
 131        if (output_value)
 132                value |= BIT(offset);
 133        else
 134                value &= ~BIT(offset);
 135        pdc_write(priv, REG_SOC_GPIO_CONTROL0, value);
 136        __global_unlock2(lstat);
 137}
 138
 139static int tz1090_pdc_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
 140{
 141        struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip);
 142        unsigned int syswake = offset - GPIO_PDC_IRQ_FIRST;
 143        int irq;
 144
 145        /* only syswakes have irqs */
 146        if (syswake >= GPIO_PDC_NIRQ)
 147                return -EINVAL;
 148
 149        irq = priv->irq[syswake];
 150        if (!irq)
 151                return -EINVAL;
 152
 153        return irq;
 154}
 155
 156static int tz1090_pdc_gpio_probe(struct platform_device *pdev)
 157{
 158        struct device_node *np = pdev->dev.of_node;
 159        struct resource *res_regs;
 160        struct tz1090_pdc_gpio *priv;
 161        unsigned int i;
 162
 163        if (!np) {
 164                dev_err(&pdev->dev, "must be instantiated via devicetree\n");
 165                return -ENOENT;
 166        }
 167
 168        res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 169        if (!res_regs) {
 170                dev_err(&pdev->dev, "cannot find registers resource\n");
 171                return -ENOENT;
 172        }
 173
 174        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 175        if (!priv) {
 176                dev_err(&pdev->dev, "unable to allocate driver data\n");
 177                return -ENOMEM;
 178        }
 179
 180        /* Ioremap the registers */
 181        priv->reg = devm_ioremap(&pdev->dev, res_regs->start,
 182                                 resource_size(res_regs));
 183        if (!priv->reg) {
 184                dev_err(&pdev->dev, "unable to ioremap registers\n");
 185                return -ENOMEM;
 186        }
 187
 188        /* Set up GPIO chip */
 189        priv->chip.label                = "tz1090-pdc-gpio";
 190        priv->chip.parent               = &pdev->dev;
 191        priv->chip.direction_input      = tz1090_pdc_gpio_direction_input;
 192        priv->chip.direction_output     = tz1090_pdc_gpio_direction_output;
 193        priv->chip.get                  = tz1090_pdc_gpio_get;
 194        priv->chip.set                  = tz1090_pdc_gpio_set;
 195        priv->chip.free                 = gpiochip_generic_free;
 196        priv->chip.request              = gpiochip_generic_request;
 197        priv->chip.to_irq               = tz1090_pdc_gpio_to_irq;
 198        priv->chip.of_node              = np;
 199
 200        /* GPIO numbering */
 201        priv->chip.base                 = GPIO_PDC_BASE;
 202        priv->chip.ngpio                = GPIO_PDC_NGPIO;
 203
 204        /* Map the syswake irqs */
 205        for (i = 0; i < GPIO_PDC_NIRQ; ++i)
 206                priv->irq[i] = irq_of_parse_and_map(np, i);
 207
 208        /* Add the GPIO bank */
 209        gpiochip_add_data(&priv->chip, priv);
 210
 211        return 0;
 212}
 213
 214static struct of_device_id tz1090_pdc_gpio_of_match[] = {
 215        { .compatible = "img,tz1090-pdc-gpio" },
 216        { },
 217};
 218
 219static struct platform_driver tz1090_pdc_gpio_driver = {
 220        .driver = {
 221                .name           = "tz1090-pdc-gpio",
 222                .of_match_table = tz1090_pdc_gpio_of_match,
 223        },
 224        .probe          = tz1090_pdc_gpio_probe,
 225};
 226
 227static int __init tz1090_pdc_gpio_init(void)
 228{
 229        return platform_driver_register(&tz1090_pdc_gpio_driver);
 230}
 231subsys_initcall(tz1090_pdc_gpio_init);
 232