linux/drivers/gpio/gpio-bt8xx.c
<<
>>
Prefs
   1/*
   2
   3    bt8xx GPIO abuser
   4
   5    Copyright (C) 2008 Michael Buesch <m@bues.ch>
   6
   7    Please do _only_ contact the people listed _above_ with issues related to this driver.
   8    All the other people listed below are not related to this driver. Their names
   9    are only here, because this driver is derived from the bt848 driver.
  10
  11
  12    Derived from the bt848 driver:
  13
  14    Copyright (C) 1996,97,98 Ralph  Metzler
  15                           & Marcus Metzler
  16    (c) 1999-2002 Gerd Knorr
  17
  18    some v4l2 code lines are taken from Justin's bttv2 driver which is
  19    (c) 2000 Justin Schoeman
  20
  21    V4L1 removal from:
  22    (c) 2005-2006 Nickolay V. Shmyrev
  23
  24    Fixes to be fully V4L2 compliant by
  25    (c) 2006 Mauro Carvalho Chehab
  26
  27    Cropping and overscan support
  28    Copyright (C) 2005, 2006 Michael H. Schimek
  29    Sponsored by OPQ Systems AB
  30
  31    This program is free software; you can redistribute it and/or modify
  32    it under the terms of the GNU General Public License as published by
  33    the Free Software Foundation; either version 2 of the License, or
  34    (at your option) any later version.
  35
  36    This program is distributed in the hope that it will be useful,
  37    but WITHOUT ANY WARRANTY; without even the implied warranty of
  38    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  39    GNU General Public License for more details.
  40
  41    You should have received a copy of the GNU General Public License
  42    along with this program; if not, write to the Free Software
  43    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  44*/
  45
  46#include <linux/module.h>
  47#include <linux/pci.h>
  48#include <linux/spinlock.h>
  49#include <linux/gpio.h>
  50#include <linux/slab.h>
  51
  52/* Steal the hardware definitions from the bttv driver. */
  53#include "../media/pci/bt8xx/bt848.h"
  54
  55
  56#define BT8XXGPIO_NR_GPIOS              24 /* We have 24 GPIO pins */
  57
  58
  59struct bt8xxgpio {
  60        spinlock_t lock;
  61
  62        void __iomem *mmio;
  63        struct pci_dev *pdev;
  64        struct gpio_chip gpio;
  65
  66#ifdef CONFIG_PM
  67        u32 saved_outen;
  68        u32 saved_data;
  69#endif
  70};
  71
  72#define bgwrite(dat, adr)       writel((dat), bg->mmio+(adr))
  73#define bgread(adr)             readl(bg->mmio+(adr))
  74
  75
  76static int modparam_gpiobase = -1/* dynamic */;
  77module_param_named(gpiobase, modparam_gpiobase, int, 0444);
  78MODULE_PARM_DESC(gpiobase, "The GPIO number base. -1 means dynamic, which is the default.");
  79
  80
  81static int bt8xxgpio_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
  82{
  83        struct bt8xxgpio *bg = container_of(gpio, struct bt8xxgpio, gpio);
  84        unsigned long flags;
  85        u32 outen, data;
  86
  87        spin_lock_irqsave(&bg->lock, flags);
  88
  89        data = bgread(BT848_GPIO_DATA);
  90        data &= ~(1 << nr);
  91        bgwrite(data, BT848_GPIO_DATA);
  92
  93        outen = bgread(BT848_GPIO_OUT_EN);
  94        outen &= ~(1 << nr);
  95        bgwrite(outen, BT848_GPIO_OUT_EN);
  96
  97        spin_unlock_irqrestore(&bg->lock, flags);
  98
  99        return 0;
 100}
 101
 102static int bt8xxgpio_gpio_get(struct gpio_chip *gpio, unsigned nr)
 103{
 104        struct bt8xxgpio *bg = container_of(gpio, struct bt8xxgpio, gpio);
 105        unsigned long flags;
 106        u32 val;
 107
 108        spin_lock_irqsave(&bg->lock, flags);
 109        val = bgread(BT848_GPIO_DATA);
 110        spin_unlock_irqrestore(&bg->lock, flags);
 111
 112        return !!(val & (1 << nr));
 113}
 114
 115static int bt8xxgpio_gpio_direction_output(struct gpio_chip *gpio,
 116                                        unsigned nr, int val)
 117{
 118        struct bt8xxgpio *bg = container_of(gpio, struct bt8xxgpio, gpio);
 119        unsigned long flags;
 120        u32 outen, data;
 121
 122        spin_lock_irqsave(&bg->lock, flags);
 123
 124        outen = bgread(BT848_GPIO_OUT_EN);
 125        outen |= (1 << nr);
 126        bgwrite(outen, BT848_GPIO_OUT_EN);
 127
 128        data = bgread(BT848_GPIO_DATA);
 129        if (val)
 130                data |= (1 << nr);
 131        else
 132                data &= ~(1 << nr);
 133        bgwrite(data, BT848_GPIO_DATA);
 134
 135        spin_unlock_irqrestore(&bg->lock, flags);
 136
 137        return 0;
 138}
 139
 140static void bt8xxgpio_gpio_set(struct gpio_chip *gpio,
 141                            unsigned nr, int val)
 142{
 143        struct bt8xxgpio *bg = container_of(gpio, struct bt8xxgpio, gpio);
 144        unsigned long flags;
 145        u32 data;
 146
 147        spin_lock_irqsave(&bg->lock, flags);
 148
 149        data = bgread(BT848_GPIO_DATA);
 150        if (val)
 151                data |= (1 << nr);
 152        else
 153                data &= ~(1 << nr);
 154        bgwrite(data, BT848_GPIO_DATA);
 155
 156        spin_unlock_irqrestore(&bg->lock, flags);
 157}
 158
 159static void bt8xxgpio_gpio_setup(struct bt8xxgpio *bg)
 160{
 161        struct gpio_chip *c = &bg->gpio;
 162
 163        c->label = dev_name(&bg->pdev->dev);
 164        c->owner = THIS_MODULE;
 165        c->direction_input = bt8xxgpio_gpio_direction_input;
 166        c->get = bt8xxgpio_gpio_get;
 167        c->direction_output = bt8xxgpio_gpio_direction_output;
 168        c->set = bt8xxgpio_gpio_set;
 169        c->dbg_show = NULL;
 170        c->base = modparam_gpiobase;
 171        c->ngpio = BT8XXGPIO_NR_GPIOS;
 172        c->can_sleep = 0;
 173}
 174
 175static int bt8xxgpio_probe(struct pci_dev *dev,
 176                        const struct pci_device_id *pci_id)
 177{
 178        struct bt8xxgpio *bg;
 179        int err;
 180
 181        bg = kzalloc(sizeof(*bg), GFP_KERNEL);
 182        if (!bg)
 183                return -ENOMEM;
 184
 185        bg->pdev = dev;
 186        spin_lock_init(&bg->lock);
 187
 188        err = pci_enable_device(dev);
 189        if (err) {
 190                printk(KERN_ERR "bt8xxgpio: Can't enable device.\n");
 191                goto err_freebg;
 192        }
 193        if (!request_mem_region(pci_resource_start(dev, 0),
 194                                pci_resource_len(dev, 0),
 195                                "bt8xxgpio")) {
 196                printk(KERN_WARNING "bt8xxgpio: Can't request iomem (0x%llx).\n",
 197                       (unsigned long long)pci_resource_start(dev, 0));
 198                err = -EBUSY;
 199                goto err_disable;
 200        }
 201        pci_set_master(dev);
 202        pci_set_drvdata(dev, bg);
 203
 204        bg->mmio = ioremap(pci_resource_start(dev, 0), 0x1000);
 205        if (!bg->mmio) {
 206                printk(KERN_ERR "bt8xxgpio: ioremap() failed\n");
 207                err = -EIO;
 208                goto err_release_mem;
 209        }
 210
 211        /* Disable interrupts */
 212        bgwrite(0, BT848_INT_MASK);
 213
 214        /* gpio init */
 215        bgwrite(0, BT848_GPIO_DMA_CTL);
 216        bgwrite(0, BT848_GPIO_REG_INP);
 217        bgwrite(0, BT848_GPIO_OUT_EN);
 218
 219        bt8xxgpio_gpio_setup(bg);
 220        err = gpiochip_add(&bg->gpio);
 221        if (err) {
 222                printk(KERN_ERR "bt8xxgpio: Failed to register GPIOs\n");
 223                goto err_release_mem;
 224        }
 225
 226        return 0;
 227
 228err_release_mem:
 229        release_mem_region(pci_resource_start(dev, 0),
 230                           pci_resource_len(dev, 0));
 231        pci_set_drvdata(dev, NULL);
 232err_disable:
 233        pci_disable_device(dev);
 234err_freebg:
 235        kfree(bg);
 236
 237        return err;
 238}
 239
 240static void bt8xxgpio_remove(struct pci_dev *pdev)
 241{
 242        struct bt8xxgpio *bg = pci_get_drvdata(pdev);
 243
 244        gpiochip_remove(&bg->gpio);
 245
 246        bgwrite(0, BT848_INT_MASK);
 247        bgwrite(~0x0, BT848_INT_STAT);
 248        bgwrite(0x0, BT848_GPIO_OUT_EN);
 249
 250        iounmap(bg->mmio);
 251        release_mem_region(pci_resource_start(pdev, 0),
 252                           pci_resource_len(pdev, 0));
 253        pci_disable_device(pdev);
 254
 255        pci_set_drvdata(pdev, NULL);
 256        kfree(bg);
 257}
 258
 259#ifdef CONFIG_PM
 260static int bt8xxgpio_suspend(struct pci_dev *pdev, pm_message_t state)
 261{
 262        struct bt8xxgpio *bg = pci_get_drvdata(pdev);
 263        unsigned long flags;
 264
 265        spin_lock_irqsave(&bg->lock, flags);
 266
 267        bg->saved_outen = bgread(BT848_GPIO_OUT_EN);
 268        bg->saved_data = bgread(BT848_GPIO_DATA);
 269
 270        bgwrite(0, BT848_INT_MASK);
 271        bgwrite(~0x0, BT848_INT_STAT);
 272        bgwrite(0x0, BT848_GPIO_OUT_EN);
 273
 274        spin_unlock_irqrestore(&bg->lock, flags);
 275
 276        pci_save_state(pdev);
 277        pci_disable_device(pdev);
 278        pci_set_power_state(pdev, pci_choose_state(pdev, state));
 279
 280        return 0;
 281}
 282
 283static int bt8xxgpio_resume(struct pci_dev *pdev)
 284{
 285        struct bt8xxgpio *bg = pci_get_drvdata(pdev);
 286        unsigned long flags;
 287        int err;
 288
 289        pci_set_power_state(pdev, PCI_D0);
 290        err = pci_enable_device(pdev);
 291        if (err)
 292                return err;
 293        pci_restore_state(pdev);
 294
 295        spin_lock_irqsave(&bg->lock, flags);
 296
 297        bgwrite(0, BT848_INT_MASK);
 298        bgwrite(0, BT848_GPIO_DMA_CTL);
 299        bgwrite(0, BT848_GPIO_REG_INP);
 300        bgwrite(bg->saved_outen, BT848_GPIO_OUT_EN);
 301        bgwrite(bg->saved_data & bg->saved_outen,
 302                BT848_GPIO_DATA);
 303
 304        spin_unlock_irqrestore(&bg->lock, flags);
 305
 306        return 0;
 307}
 308#else
 309#define bt8xxgpio_suspend NULL
 310#define bt8xxgpio_resume NULL
 311#endif /* CONFIG_PM */
 312
 313static DEFINE_PCI_DEVICE_TABLE(bt8xxgpio_pci_tbl) = {
 314        { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848) },
 315        { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849) },
 316        { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878) },
 317        { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879) },
 318        { 0, },
 319};
 320MODULE_DEVICE_TABLE(pci, bt8xxgpio_pci_tbl);
 321
 322static struct pci_driver bt8xxgpio_pci_driver = {
 323        .name           = "bt8xxgpio",
 324        .id_table       = bt8xxgpio_pci_tbl,
 325        .probe          = bt8xxgpio_probe,
 326        .remove         = bt8xxgpio_remove,
 327        .suspend        = bt8xxgpio_suspend,
 328        .resume         = bt8xxgpio_resume,
 329};
 330
 331module_pci_driver(bt8xxgpio_pci_driver);
 332
 333MODULE_LICENSE("GPL");
 334MODULE_AUTHOR("Michael Buesch");
 335MODULE_DESCRIPTION("Abuse a BT8xx framegrabber card as generic GPIO card");
 336
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.