linux/drivers/gpio/langwell_gpio.c
<<
>>
Prefs
   1/* langwell_gpio.c Moorestown platform Langwell chip GPIO driver
   2 * Copyright (c) 2008 - 2009,  Intel Corporation.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 *
  13 * You should have received a copy of the GNU General Public License
  14 * along with this program; if not, write to the Free Software
  15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16 */
  17
  18/* Supports:
  19 * Moorestown platform Langwell chip.
  20 */
  21
  22#include <linux/module.h>
  23#include <linux/pci.h>
  24#include <linux/kernel.h>
  25#include <linux/delay.h>
  26#include <linux/stddef.h>
  27#include <linux/interrupt.h>
  28#include <linux/init.h>
  29#include <linux/irq.h>
  30#include <linux/io.h>
  31#include <linux/gpio.h>
  32
  33struct lnw_gpio_register {
  34        u32     GPLR[2];
  35        u32     GPDR[2];
  36        u32     GPSR[2];
  37        u32     GPCR[2];
  38        u32     GRER[2];
  39        u32     GFER[2];
  40        u32     GEDR[2];
  41};
  42
  43struct lnw_gpio {
  44        struct gpio_chip                chip;
  45        struct lnw_gpio_register        *reg_base;
  46        spinlock_t                      lock;
  47        unsigned                        irq_base;
  48};
  49
  50static int lnw_gpio_get(struct gpio_chip *chip, unsigned offset)
  51{
  52        struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
  53        u8 reg = offset / 32;
  54        void __iomem *gplr;
  55
  56        gplr = (void __iomem *)(&lnw->reg_base->GPLR[reg]);
  57        return readl(gplr) & BIT(offset % 32);
  58}
  59
  60static void lnw_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
  61{
  62        struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
  63        u8 reg = offset / 32;
  64        void __iomem *gpsr, *gpcr;
  65
  66        if (value) {
  67                gpsr = (void __iomem *)(&lnw->reg_base->GPSR[reg]);
  68                writel(BIT(offset % 32), gpsr);
  69        } else {
  70                gpcr = (void __iomem *)(&lnw->reg_base->GPCR[reg]);
  71                writel(BIT(offset % 32), gpcr);
  72        }
  73}
  74
  75static int lnw_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
  76{
  77        struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
  78        u8 reg = offset / 32;
  79        u32 value;
  80        unsigned long flags;
  81        void __iomem *gpdr;
  82
  83        gpdr = (void __iomem *)(&lnw->reg_base->GPDR[reg]);
  84        spin_lock_irqsave(&lnw->lock, flags);
  85        value = readl(gpdr);
  86        value &= ~BIT(offset % 32);
  87        writel(value, gpdr);
  88        spin_unlock_irqrestore(&lnw->lock, flags);
  89        return 0;
  90}
  91
  92static int lnw_gpio_direction_output(struct gpio_chip *chip,
  93                        unsigned offset, int value)
  94{
  95        struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
  96        u8 reg = offset / 32;
  97        unsigned long flags;
  98        void __iomem *gpdr;
  99
 100        lnw_gpio_set(chip, offset, value);
 101        gpdr = (void __iomem *)(&lnw->reg_base->GPDR[reg]);
 102        spin_lock_irqsave(&lnw->lock, flags);
 103        value = readl(gpdr);
 104        value |= BIT(offset % 32);;
 105        writel(value, gpdr);
 106        spin_unlock_irqrestore(&lnw->lock, flags);
 107        return 0;
 108}
 109
 110static int lnw_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 111{
 112        struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
 113        return lnw->irq_base + offset;
 114}
 115
 116static int lnw_irq_type(unsigned irq, unsigned type)
 117{
 118        struct lnw_gpio *lnw = get_irq_chip_data(irq);
 119        u32 gpio = irq - lnw->irq_base;
 120        u8 reg = gpio / 32;
 121        unsigned long flags;
 122        u32 value;
 123        void __iomem *grer = (void __iomem *)(&lnw->reg_base->GRER[reg]);
 124        void __iomem *gfer = (void __iomem *)(&lnw->reg_base->GFER[reg]);
 125
 126        if (gpio < 0 || gpio > lnw->chip.ngpio)
 127                return -EINVAL;
 128        spin_lock_irqsave(&lnw->lock, flags);
 129        if (type & IRQ_TYPE_EDGE_RISING)
 130                value = readl(grer) | BIT(gpio % 32);
 131        else
 132                value = readl(grer) & (~BIT(gpio % 32));
 133        writel(value, grer);
 134
 135        if (type & IRQ_TYPE_EDGE_FALLING)
 136                value = readl(gfer) | BIT(gpio % 32);
 137        else
 138                value = readl(gfer) & (~BIT(gpio % 32));
 139        writel(value, gfer);
 140        spin_unlock_irqrestore(&lnw->lock, flags);
 141
 142        return 0;
 143};
 144
 145static void lnw_irq_unmask(unsigned irq)
 146{
 147};
 148
 149static void lnw_irq_mask(unsigned irq)
 150{
 151};
 152
 153static struct irq_chip lnw_irqchip = {
 154        .name           = "LNW-GPIO",
 155        .mask           = lnw_irq_mask,
 156        .unmask         = lnw_irq_unmask,
 157        .set_type       = lnw_irq_type,
 158};
 159
 160static struct pci_device_id lnw_gpio_ids[] = {
 161        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f) },
 162        { 0, }
 163};
 164MODULE_DEVICE_TABLE(pci, lnw_gpio_ids);
 165
 166static void lnw_irq_handler(unsigned irq, struct irq_desc *desc)
 167{
 168        struct lnw_gpio *lnw = (struct lnw_gpio *)get_irq_data(irq);
 169        u32 reg, gpio;
 170        void __iomem *gedr;
 171        u32 gedr_v;
 172
 173        /* check GPIO controller to check which pin triggered the interrupt */
 174        for (reg = 0; reg < lnw->chip.ngpio / 32; reg++) {
 175                gedr = (void __iomem *)(&lnw->reg_base->GEDR[reg]);
 176                gedr_v = readl(gedr);
 177                if (!gedr_v)
 178                        continue;
 179                for (gpio = reg*32; gpio < reg*32+32; gpio++)
 180                        if (gedr_v & BIT(gpio % 32)) {
 181                                pr_debug("pin %d triggered\n", gpio);
 182                                generic_handle_irq(lnw->irq_base + gpio);
 183                        }
 184                /* clear the edge detect status bit */
 185                writel(gedr_v, gedr);
 186        }
 187        desc->chip->eoi(irq);
 188}
 189
 190static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
 191                        const struct pci_device_id *id)
 192{
 193        void *base;
 194        int i;
 195        resource_size_t start, len;
 196        struct lnw_gpio *lnw;
 197        u32 irq_base;
 198        u32 gpio_base;
 199        int retval = 0;
 200
 201        retval = pci_enable_device(pdev);
 202        if (retval)
 203                goto done;
 204
 205        retval = pci_request_regions(pdev, "langwell_gpio");
 206        if (retval) {
 207                dev_err(&pdev->dev, "error requesting resources\n");
 208                goto err2;
 209        }
 210        /* get the irq_base from bar1 */
 211        start = pci_resource_start(pdev, 1);
 212        len = pci_resource_len(pdev, 1);
 213        base = ioremap_nocache(start, len);
 214        if (!base) {
 215                dev_err(&pdev->dev, "error mapping bar1\n");
 216                goto err3;
 217        }
 218        irq_base = *(u32 *)base;
 219        gpio_base = *((u32 *)base + 1);
 220        /* release the IO mapping, since we already get the info from bar1 */
 221        iounmap(base);
 222        /* get the register base from bar0 */
 223        start = pci_resource_start(pdev, 0);
 224        len = pci_resource_len(pdev, 0);
 225        base = ioremap_nocache(start, len);
 226        if (!base) {
 227                dev_err(&pdev->dev, "error mapping bar0\n");
 228                retval = -EFAULT;
 229                goto err3;
 230        }
 231
 232        lnw = kzalloc(sizeof(struct lnw_gpio), GFP_KERNEL);
 233        if (!lnw) {
 234                dev_err(&pdev->dev, "can't allocate langwell_gpio chip data\n");
 235                retval = -ENOMEM;
 236                goto err4;
 237        }
 238        lnw->reg_base = base;
 239        lnw->irq_base = irq_base;
 240        lnw->chip.label = dev_name(&pdev->dev);
 241        lnw->chip.direction_input = lnw_gpio_direction_input;
 242        lnw->chip.direction_output = lnw_gpio_direction_output;
 243        lnw->chip.get = lnw_gpio_get;
 244        lnw->chip.set = lnw_gpio_set;
 245        lnw->chip.to_irq = lnw_gpio_to_irq;
 246        lnw->chip.base = gpio_base;
 247        lnw->chip.ngpio = 64;
 248        lnw->chip.can_sleep = 0;
 249        pci_set_drvdata(pdev, lnw);
 250        retval = gpiochip_add(&lnw->chip);
 251        if (retval) {
 252                dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval);
 253                goto err5;
 254        }
 255        set_irq_data(pdev->irq, lnw);
 256        set_irq_chained_handler(pdev->irq, lnw_irq_handler);
 257        for (i = 0; i < lnw->chip.ngpio; i++) {
 258                set_irq_chip_and_handler_name(i + lnw->irq_base, &lnw_irqchip,
 259                                        handle_simple_irq, "demux");
 260                set_irq_chip_data(i + lnw->irq_base, lnw);
 261        }
 262
 263        spin_lock_init(&lnw->lock);
 264        goto done;
 265err5:
 266        kfree(lnw);
 267err4:
 268        iounmap(base);
 269err3:
 270        pci_release_regions(pdev);
 271err2:
 272        pci_disable_device(pdev);
 273done:
 274        return retval;
 275}
 276
 277static struct pci_driver lnw_gpio_driver = {
 278        .name           = "langwell_gpio",
 279        .id_table       = lnw_gpio_ids,
 280        .probe          = lnw_gpio_probe,
 281};
 282
 283static int __init lnw_gpio_init(void)
 284{
 285        return pci_register_driver(&lnw_gpio_driver);
 286}
 287
 288device_initcall(lnw_gpio_init);
 289