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