Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpio: add bt8xxgpio driver

This adds the bt8xxgpio driver. The purpose of the bt8xxgpio driver is to
export all of the 24 GPIO pins available on Brooktree 8xx chips to the
kernel GPIO infrastructure.

This makes it possible to use a physically modified BT8xx card as
cheap digital GPIO card.

[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Cc: David Brownell <david-b@pacbell.net>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Cc: Mauro Carvalho Chehab <mchehab@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Michael Buesch and committed by
Linus Torvalds
ff1d5c2f 8f1cc3b1

+440
+67
Documentation/bt8xxgpio.txt
··· 1 + =============================================================== 2 + == BT8XXGPIO driver == 3 + == == 4 + == A driver for a selfmade cheap BT8xx based PCI GPIO-card == 5 + == == 6 + == For advanced documentation, see == 7 + == http://www.bu3sch.de/btgpio.php == 8 + =============================================================== 9 + 10 + 11 + A generic digital 24-port PCI GPIO card can be built out of an ordinary 12 + Brooktree bt848, bt849, bt878 or bt879 based analog TV tuner card. The 13 + Brooktree chip is used in old analog Hauppauge WinTV PCI cards. You can easily 14 + find them used for low prices on the net. 15 + 16 + The bt8xx chip does have 24 digital GPIO ports. 17 + These ports are accessible via 24 pins on the SMD chip package. 18 + 19 + 20 + ============================================== 21 + == How to physically access the GPIO pins == 22 + ============================================== 23 + 24 + The are several ways to access these pins. One might unsolder the whole chip 25 + and put it on a custom PCI board, or one might only unsolder each individual 26 + GPIO pin and solder that to some tiny wire. As the chip package really is tiny 27 + there are some advanced soldering skills needed in any case. 28 + 29 + The physical pinouts are drawn in the following ASCII art. 30 + The GPIO pins are marked with G00-G23 31 + 32 + G G G G G G G G G G G G G G G G G G 33 + 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 34 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 35 + | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 36 + --------------------------------------------------------------------------- 37 + --| ^ ^ |-- 38 + --| pin 86 pin 67 |-- 39 + --| |-- 40 + --| pin 61 > |-- G18 41 + --| |-- G19 42 + --| |-- G20 43 + --| |-- G21 44 + --| |-- G22 45 + --| pin 56 > |-- G23 46 + --| |-- 47 + --| Brooktree 878/879 |-- 48 + --| |-- 49 + --| |-- 50 + --| |-- 51 + --| |-- 52 + --| |-- 53 + --| |-- 54 + --| |-- 55 + --| |-- 56 + --| |-- 57 + --| |-- 58 + --| |-- 59 + --| |-- 60 + --| |-- 61 + --| O |-- 62 + --| |-- 63 + --------------------------------------------------------------------------- 64 + | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 65 + ^ 66 + This is pin 1 67 +
+6
MAINTAINERS
··· 1043 1043 L: linux-scsi@vger.kernel.org 1044 1044 S: Supported 1045 1045 1046 + BT8XXGPIO DRIVER 1047 + P: Michael Buesch 1048 + M: mb@bu3sch.de 1049 + W: http://bu3sch.de/btgpio.php 1050 + S: Maintained 1051 + 1046 1052 BTTV VIDEO4LINUX DRIVER 1047 1053 P: Mauro Carvalho Chehab 1048 1054 M: mchehab@infradead.org
+18
drivers/gpio/Kconfig
··· 83 83 This driver provides an in-kernel interface to those GPIOs using 84 84 platform-neutral GPIO calls. 85 85 86 + comment "PCI GPIO expanders:" 87 + 88 + config GPIO_BT8XX 89 + tristate "BT8XX GPIO abuser" 90 + depends on PCI && VIDEO_BT848=n 91 + help 92 + The BT8xx frame grabber chip has 24 GPIO pins than can be abused 93 + as a cheap PCI GPIO card. 94 + 95 + This chip can be found on Miro, Hauppauge and STB TV-cards. 96 + 97 + The card needs to be physically altered for using it as a 98 + GPIO card. For more information on how to build a GPIO card 99 + from a BT8xx TV card, see the documentation file at 100 + Documentation/bt8xxgpio.txt 101 + 102 + If unsure, say N. 103 + 86 104 comment "SPI GPIO expanders:" 87 105 88 106 config GPIO_MAX7301
+1
drivers/gpio/Makefile
··· 8 8 obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o 9 9 obj-$(CONFIG_GPIO_PCA953X) += pca953x.o 10 10 obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o 11 + obj-$(CONFIG_GPIO_BT8XX) += bt8xxgpio.o
+348
drivers/gpio/bt8xxgpio.c
··· 1 + /* 2 + 3 + bt8xx GPIO abuser 4 + 5 + Copyright (C) 2008 Michael Buesch <mb@bu3sch.de> 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 + 50 + #include <asm/gpio.h> 51 + 52 + /* Steal the hardware definitions from the bttv driver. */ 53 + #include "../media/video/bt8xx/bt848.h" 54 + 55 + 56 + #define BT8XXGPIO_NR_GPIOS 24 /* We have 24 GPIO pins */ 57 + 58 + 59 + struct 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 + 76 + static int modparam_gpiobase = -1/* dynamic */; 77 + module_param_named(gpiobase, modparam_gpiobase, int, 0444); 78 + MODULE_PARM_DESC(gpiobase, "The GPIO number base. -1 means dynamic, which is the default."); 79 + 80 + 81 + static 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 + 102 + static 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 + 115 + static 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 + 140 + static 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 + 159 + static void bt8xxgpio_gpio_setup(struct bt8xxgpio *bg) 160 + { 161 + struct gpio_chip *c = &bg->gpio; 162 + 163 + c->label = bg->pdev->dev.bus_id; 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 + 175 + static 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 + printk(KERN_INFO "bt8xxgpio: Abusing BT8xx card for GPIOs %d to %d\n", 227 + bg->gpio.base, bg->gpio.base + BT8XXGPIO_NR_GPIOS - 1); 228 + 229 + return 0; 230 + 231 + err_release_mem: 232 + release_mem_region(pci_resource_start(dev, 0), 233 + pci_resource_len(dev, 0)); 234 + pci_set_drvdata(dev, NULL); 235 + err_disable: 236 + pci_disable_device(dev); 237 + err_freebg: 238 + kfree(bg); 239 + 240 + return err; 241 + } 242 + 243 + static void bt8xxgpio_remove(struct pci_dev *pdev) 244 + { 245 + struct bt8xxgpio *bg = pci_get_drvdata(pdev); 246 + 247 + gpiochip_remove(&bg->gpio); 248 + 249 + bgwrite(0, BT848_INT_MASK); 250 + bgwrite(~0x0, BT848_INT_STAT); 251 + bgwrite(0x0, BT848_GPIO_OUT_EN); 252 + 253 + iounmap(bg->mmio); 254 + release_mem_region(pci_resource_start(pdev, 0), 255 + pci_resource_len(pdev, 0)); 256 + pci_disable_device(pdev); 257 + 258 + pci_set_drvdata(pdev, NULL); 259 + kfree(bg); 260 + } 261 + 262 + #ifdef CONFIG_PM 263 + static int bt8xxgpio_suspend(struct pci_dev *pdev, pm_message_t state) 264 + { 265 + struct bt8xxgpio *bg = pci_get_drvdata(pdev); 266 + unsigned long flags; 267 + 268 + spin_lock_irqsave(&bg->lock, flags); 269 + 270 + bg->saved_outen = bgread(BT848_GPIO_OUT_EN); 271 + bg->saved_data = bgread(BT848_GPIO_DATA); 272 + 273 + bgwrite(0, BT848_INT_MASK); 274 + bgwrite(~0x0, BT848_INT_STAT); 275 + bgwrite(0x0, BT848_GPIO_OUT_EN); 276 + 277 + spin_unlock_irqrestore(&bg->lock, flags); 278 + 279 + pci_save_state(pdev); 280 + pci_disable_device(pdev); 281 + pci_set_power_state(pdev, pci_choose_state(pdev, state)); 282 + 283 + return 0; 284 + } 285 + 286 + static int bt8xxgpio_resume(struct pci_dev *pdev) 287 + { 288 + struct bt8xxgpio *bg = pci_get_drvdata(pdev); 289 + unsigned long flags; 290 + int err; 291 + 292 + pci_set_power_state(pdev, 0); 293 + err = pci_enable_device(pdev); 294 + if (err) 295 + return err; 296 + pci_restore_state(pdev); 297 + 298 + spin_lock_irqsave(&bg->lock, flags); 299 + 300 + bgwrite(0, BT848_INT_MASK); 301 + bgwrite(0, BT848_GPIO_DMA_CTL); 302 + bgwrite(0, BT848_GPIO_REG_INP); 303 + bgwrite(bg->saved_outen, BT848_GPIO_OUT_EN); 304 + bgwrite(bg->saved_data & bg->saved_outen, 305 + BT848_GPIO_DATA); 306 + 307 + spin_unlock_irqrestore(&bg->lock, flags); 308 + 309 + return 0; 310 + } 311 + #else 312 + #define bt8xxgpio_suspend NULL 313 + #define bt8xxgpio_resume NULL 314 + #endif /* CONFIG_PM */ 315 + 316 + static struct pci_device_id bt8xxgpio_pci_tbl[] = { 317 + { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848) }, 318 + { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849) }, 319 + { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878) }, 320 + { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879) }, 321 + { 0, }, 322 + }; 323 + MODULE_DEVICE_TABLE(pci, bt8xxgpio_pci_tbl); 324 + 325 + static struct pci_driver bt8xxgpio_pci_driver = { 326 + .name = "bt8xxgpio", 327 + .id_table = bt8xxgpio_pci_tbl, 328 + .probe = bt8xxgpio_probe, 329 + .remove = bt8xxgpio_remove, 330 + .suspend = bt8xxgpio_suspend, 331 + .resume = bt8xxgpio_resume, 332 + }; 333 + 334 + static int bt8xxgpio_init(void) 335 + { 336 + return pci_register_driver(&bt8xxgpio_pci_driver); 337 + } 338 + module_init(bt8xxgpio_init) 339 + 340 + static void bt8xxgpio_exit(void) 341 + { 342 + pci_unregister_driver(&bt8xxgpio_pci_driver); 343 + } 344 + module_exit(bt8xxgpio_exit) 345 + 346 + MODULE_LICENSE("GPL"); 347 + MODULE_AUTHOR("Michael Buesch"); 348 + MODULE_DESCRIPTION("Abuse a BT8xx framegrabber card as generic GPIO card");