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#define to_pdc(c)       container_of(c, struct tz1090_pdc_gpio, chip)
  53
  54/* Register accesses into the PDC MMIO area */
  55
  56static inline void pdc_write(struct tz1090_pdc_gpio *priv, unsigned int reg_offs,
  57                      unsigned int data)
  58{
  59        writel(data, priv->reg + reg_offs);
  60}
  61
  62static inline unsigned int pdc_read(struct tz1090_pdc_gpio *priv,
  63                             unsigned int reg_offs)
  64{
  65        return readl(priv->reg + reg_offs);
  66}
  67
  68/* Generic GPIO interface */
  69
  70static int tz1090_pdc_gpio_direction_input(struct gpio_chip *chip,
  71                                           unsigned int offset)
  72{
  73        struct tz1090_pdc_gpio *priv = to_pdc(chip);
  74        u32 value;
  75        int lstat;
  76
  77        __global_lock2(lstat);
  78        value = pdc_read(priv, REG_SOC_GPIO_CONTROL1);
  79        value |= BIT(offset);
  80        pdc_write(priv, REG_SOC_GPIO_CONTROL1, value);
  81        __global_unlock2(lstat);
  82
  83        return 0;
  84}
  85
  86static int tz1090_pdc_gpio_direction_output(struct gpio_chip *chip,
  87                                            unsigned int offset,
  88                                            int output_value)
  89{
  90        struct tz1090_pdc_gpio *priv = to_pdc(chip);
  91        u32 value;
  92        int lstat;
  93
  94        __global_lock2(lstat);
  95        /* EXT_POWER doesn't seem to have an output value bit */
  96        if (offset < 6) {
  97                value = pdc_read(priv, REG_SOC_GPIO_CONTROL0);
  98                if (output_value)
  99                        value |= BIT(offset);
 100                else
 101                        value &= ~BIT(offset);
 102                pdc_write(priv, REG_SOC_GPIO_CONTROL0, value);
 103        }
 104
 105        value = pdc_read(priv, REG_SOC_GPIO_CONTROL1);
 106        value &= ~BIT(offset);
 107        pdc_write(priv, REG_SOC_GPIO_CONTROL1, value);
 108        __global_unlock2(lstat);
 109
 110        return 0;
 111}
 112
 113static int tz1090_pdc_gpio_get(struct gpio_chip *chip, unsigned int offset)
 114{
 115        struct tz1090_pdc_gpio *priv = to_pdc(chip);
 116        return pdc_read(priv, REG_SOC_GPIO_STATUS) & BIT(offset);
 117}
 118
 119static void tz1090_pdc_gpio_set(struct gpio_chip *chip, unsigned int offset,
 120                                int output_value)
 121{
 122        struct tz1090_pdc_gpio *priv = to_pdc(chip);
 123        u32 value;
 124        int lstat;
 125
 126        /* EXT_POWER doesn't seem to have an output value bit */
 127        if (offset >= 6)
 128                return;
 129
 130        __global_lock2(lstat);
 131        value = pdc_read(priv, REG_SOC_GPIO_CONTROL0);
 132        if (output_value)
 133                value |= BIT(offset);
 134        else
 135                value &= ~BIT(offset);
 136        pdc_write(priv, REG_SOC_GPIO_CONTROL0, value);
 137        __global_unlock2(lstat);
 138}
 139
 140static int tz1090_pdc_gpio_request(struct gpio_chip *chip, unsigned int offset)
 141{
 142        return pinctrl_request_gpio(chip->base + offset);
 143}
 144
 145static void tz1090_pdc_gpio_free(struct gpio_chip *chip, unsigned int offset)
 146{
 147        pinctrl_free_gpio(chip->base + offset);
 148}
 149
 150static int tz1090_pdc_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
 151{
 152        struct tz1090_pdc_gpio *priv = to_pdc(chip);
 153        unsigned int syswake = offset - GPIO_PDC_IRQ_FIRST;
 154        int irq;
 155
 156        /* only syswakes have irqs */
 157        if (syswake >= GPIO_PDC_NIRQ)
 158                return -EINVAL;
 159
 160        irq = priv->irq[syswake];
 161        if (!irq)
 162                return -EINVAL;
 163
 164        return irq;
 165}
 166
 167static int tz1090_pdc_gpio_probe(struct platform_device *pdev)
 168{
 169        struct device_node *np = pdev->dev.of_node;
 170        struct resource *res_regs;
 171        struct tz1090_pdc_gpio *priv;
 172        unsigned int i;
 173
 174        if (!np) {
 175                dev_err(&pdev->dev, "must be instantiated via devicetree\n");
 176                return -ENOENT;
 177        }
 178
 179        res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 180        if (!res_regs) {
 181                dev_err(&pdev->dev, "cannot find registers resource\n");
 182                return -ENOENT;
 183        }
 184
 185        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 186        if (!priv) {
 187                dev_err(&pdev->dev, "unable to allocate driver data\n");
 188                return -ENOMEM;
 189        }
 190
 191        /* Ioremap the registers */
 192        priv->reg = devm_ioremap(&pdev->dev, res_regs->start,
 193                                 res_regs->end - res_regs->start);
 194        if (!priv->reg) {
 195                dev_err(&pdev->dev, "unable to ioremap registers\n");
 196                return -ENOMEM;
 197        }
 198
 199        /* Set up GPIO chip */
 200        priv->chip.label                = "tz1090-pdc-gpio";
 201        priv->chip.dev                  = &pdev->dev;
 202        priv->chip.direction_input      = tz1090_pdc_gpio_direction_input;
 203        priv->chip.direction_output     = tz1090_pdc_gpio_direction_output;
 204        priv->chip.get                  = tz1090_pdc_gpio_get;
 205        priv->chip.set                  = tz1090_pdc_gpio_set;
 206        priv->chip.free                 = tz1090_pdc_gpio_free;
 207        priv->chip.request              = tz1090_pdc_gpio_request;
 208        priv->chip.to_irq               = tz1090_pdc_gpio_to_irq;
 209        priv->chip.of_node              = np;
 210
 211        /* GPIO numbering */
 212        priv->chip.base                 = GPIO_PDC_BASE;
 213        priv->chip.ngpio                = GPIO_PDC_NGPIO;
 214
 215        /* Map the syswake irqs */
 216        for (i = 0; i < GPIO_PDC_NIRQ; ++i)
 217                priv->irq[i] = irq_of_parse_and_map(np, i);
 218
 219        /* Add the GPIO bank */
 220        gpiochip_add(&priv->chip);
 221
 222        return 0;
 223}
 224
 225static struct of_device_id tz1090_pdc_gpio_of_match[] = {
 226        { .compatible = "img,tz1090-pdc-gpio" },
 227        { },
 228};
 229
 230static struct platform_driver tz1090_pdc_gpio_driver = {
 231        .driver = {
 232                .name           = "tz1090-pdc-gpio",
 233                .owner          = THIS_MODULE,
 234                .of_match_table = tz1090_pdc_gpio_of_match,
 235        },
 236        .probe          = tz1090_pdc_gpio_probe,
 237};
 238
 239static int __init tz1090_pdc_gpio_init(void)
 240{
 241        return platform_driver_register(&tz1090_pdc_gpio_driver);
 242}
 243subsys_initcall(tz1090_pdc_gpio_init);
 244
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.