Messages in this thread | | | Date | Sun, 29 Jun 2008 22:26:16 +0100 | From | Alan Cox <> | Subject | Re: Drivers for selfmade hardware |
| |
On Sun, 29 Jun 2008 21:47:52 +0200 Michael Buesch <mb@bu3sch.de> wrote:
> I'm wondering what the policy is for selfmade hardware > or other hardware where only a few pieces exist. Is it desired > to get drivers for this kind of hardware merged upstream into the > mainline kernel? > > I have a tiny driver that can be used to drive a modified > Brooktree 8xx based card in 24-port GPIO mode. > So the card can be used as a cheap digital PCI GPIO card. > This hardware can be built with some soldering skills, a tiny > soldering tip and a few hours of free time. > > So what's the policy? Push to mainline or keep as seperate > patch? > > (The following patch is not complete, but just what I have for now > to show you...) > > Index: linux-2.6/drivers/gpio/Kconfig > =================================================================== > --- linux-2.6.orig/drivers/gpio/Kconfig 2008-05-01 13:19:48.000000000 +0200 > +++ linux-2.6/drivers/gpio/Kconfig 2008-06-29 21:19:26.000000000 +0200 > @@ -61,6 +61,24 @@ config GPIO_PCF857X > This driver provides an in-kernel interface to those GPIOs using > platform-neutral GPIO calls. > > +comment "PCI GPIO expanders:" > + > +config GPIO_BT8XX > + tristate "BT8XX GPIO abuser" > + depends on PCI && !VIDEO_BT848 > + help > + The BT8xx frame grabber chip has 24 GPIO pins than can be abused > + as a cheap PCI GPIO card. > + > + This chip can be found on Miro, Hauppauge and STB TV-cards. > + > + The card needs to be physically altered for using it as a > + GPIO card. For more information on how to build a GPIO card > + from a BT8xx TV card, see the following link: > + http://bu3sch.de/btgpio.php > + > + If unsure, say N. > + > comment "SPI GPIO expanders:" > > config GPIO_MCP23S08 > Index: linux-2.6/drivers/gpio/Makefile > =================================================================== > --- linux-2.6.orig/drivers/gpio/Makefile 2008-05-01 13:19:48.000000000 +0200 > +++ linux-2.6/drivers/gpio/Makefile 2008-06-29 17:58:05.000000000 +0200 > @@ -7,3 +7,4 @@ obj-$(CONFIG_HAVE_GPIO_LIB) += gpiolib.o > obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o > obj-$(CONFIG_GPIO_PCA953X) += pca953x.o > obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o > +obj-$(CONFIG_GPIO_BT8XX) += btgpio.o > Index: linux-2.6/drivers/gpio/btgpio.c > =================================================================== > --- /dev/null 1970-01-01 00:00:00.000000000 +0000 > +++ linux-2.6/drivers/gpio/btgpio.c 2008-06-29 19:21:23.000000000 +0200 > @@ -0,0 +1,334 @@ > +/* > + > + bt8xx GPIO abuser > + > + Copyright (C) 2008 Michael Buesch <mb@bu3sch.de> > + > + Please do _only_ contact Michael Buesch with issues related to this driver. > + All the other people listed below are not related to this driver. Their names > + are only here, because this driver is derived from the bt848 driver. > + > + > + Derived from the bt848 driver: > + > + Copyright (C) 1996,97,98 Ralph Metzler > + & Marcus Metzler > + (c) 1999-2002 Gerd Knorr > + > + some v4l2 code lines are taken from Justin's bttv2 driver which is > + (c) 2000 Justin Schoeman > + > + V4L1 removal from: > + (c) 2005-2006 Nickolay V. Shmyrev > + > + Fixes to be fully V4L2 compliant by > + (c) 2006 Mauro Carvalho Chehab > + > + Cropping and overscan support > + Copyright (C) 2005, 2006 Michael H. Schimek > + Sponsored by OPQ Systems AB > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 2 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program; if not, write to the Free Software > + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. > +*/ > + > +#include <linux/module.h> > +#include <linux/pci.h> > +#include <linux/spinlock.h> > +#include <asm/gpio.h> > + > +/* Steal the hardware definitions from the bttv driver. */ > +#include "../media/video/bt8xx/bt848.h" > + > + > +struct btgpio { > + spinlock_t lock; > + > + void __iomem *mmio; > + struct pci_dev *pdev; > + struct gpio_chip gpio; > + > +#ifdef CONFIG_PM > + u32 saved_outen; > + u32 saved_data; > +#endif > +}; > + > +#define bgwrite(dat,adr) writel((dat), bg->mmio+(adr)) > +#define bgread(adr) readl(bg->mmio+(adr)) > + > + > +static int btgpio_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) > +{ > + struct btgpio *bg = container_of(gpio, struct btgpio, gpio); > + unsigned long flags; > + u32 outen, data; > + > + spin_lock_irqsave(&bg->lock, flags); > + > + data = bgread(BT848_GPIO_DATA); > + data &= ~(1 << nr); > + bgwrite(data, BT848_GPIO_DATA); > + > + outen = bgread(BT848_GPIO_OUT_EN); > + outen &= ~(1 << nr); > + bgwrite(outen, BT848_GPIO_OUT_EN); > + > + spin_unlock_irqrestore(&bg->lock, flags); > + > + return 0; > +} > + > +static int btgpio_gpio_get(struct gpio_chip *gpio, unsigned nr) > +{ > + struct btgpio *bg = container_of(gpio, struct btgpio, gpio); > + unsigned long flags; > + u32 val; > + > + spin_lock_irqsave(&bg->lock, flags); > + val = bgread(BT848_GPIO_DATA); > + spin_unlock_irqrestore(&bg->lock, flags); > + > + return !!(val & (1 << nr)); > +} > + > +static int btgpio_gpio_direction_output(struct gpio_chip *gpio, > + unsigned nr, int val) > +{ > + struct btgpio *bg = container_of(gpio, struct btgpio, gpio); > + unsigned long flags; > + u32 outen, data; > + > + spin_lock_irqsave(&bg->lock, flags); > + > + data = bgread(BT848_GPIO_DATA); > + if (val) > + data |= (1 << nr); > + else > + data &= ~(1 << nr); > + bgwrite(data, BT848_GPIO_DATA); > + > + outen = bgread(BT848_GPIO_OUT_EN); > + outen |= (1 << nr); > + bgwrite(outen, BT848_GPIO_OUT_EN); > + > + spin_unlock_irqrestore(&bg->lock, flags); > + > + return 0; > +} > + > +static void btgpio_gpio_set(struct gpio_chip *gpio, > + unsigned nr, int val) > +{ > + struct btgpio *bg = container_of(gpio, struct btgpio, gpio); > + unsigned long flags; > + u32 data; > + > + spin_lock_irqsave(&bg->lock, flags); > + > + data = bgread(BT848_GPIO_DATA); > + if (val) > + data |= (1 << nr); > + else > + data &= ~(1 << nr); > + bgwrite(data, BT848_GPIO_DATA); > + > + spin_unlock_irqrestore(&bg->lock, flags); > +} > + > +static void btgpio_gpio_setup(struct btgpio *bg) > +{ > + struct gpio_chip *c = &bg->gpio; > + > + c->label = bg->pdev->dev.bus_id; > + c->owner = THIS_MODULE; > + c->direction_input = btgpio_gpio_direction_input; > + c->get = btgpio_gpio_get; > + c->direction_output = btgpio_gpio_direction_output; > + c->set = btgpio_gpio_set; > + c->dbg_show = NULL; > + c->base = -1; > + c->ngpio = 24; > + c->can_sleep = 0; > +} > + > +static int btgpio_probe(struct pci_dev *dev, > + const struct pci_device_id *pci_id) > +{ > + struct btgpio *bg; > + int err; > + > + bg = kzalloc(sizeof(*bg), GFP_KERNEL); > + if (!bg) > + return -ENOMEM; > + > + bg->pdev = dev; > + spin_lock_init(&bg->lock); > + > + err = pci_enable_device(dev); > + if (err) { > + printk(KERN_ERR "btgpio: Can't enable device.\n"); > + goto err_freebg; > + } > + if (!request_mem_region(pci_resource_start(dev, 0), > + pci_resource_len(dev, 0), > + "btgpio")) { > + printk(KERN_WARNING "btgpio: can't request iomem (0x%llx).\n", > + (unsigned long long)pci_resource_start(dev, 0)); > + err = -EBUSY; > + goto err_disable; > + } > + pci_set_master(dev); > + pci_set_drvdata(dev, bg); > + > + bg->mmio = ioremap(pci_resource_start(dev, 0), 0x1000); > + if (!bg->mmio) { > + printk(KERN_ERR "btgpio: ioremap() failed\n"); > + err = -EIO; > + goto err_release_mem; > + } > + > + /* Disable interrupts */ > + bgwrite(0, BT848_INT_MASK); > + > + /* gpio init */ > + bgwrite(0, BT848_GPIO_REG_INP); > + bgwrite(0, BT848_GPIO_OUT_EN); > + > + btgpio_gpio_setup(bg); > + err = gpiochip_add(&bg->gpio); > + if (err) { > + printk(KERN_ERR "btgpio: Failed to register GPIOs\n"); > + goto err_release_mem; > + } > + > + printk(KERN_INFO "btgpio: Abusing BT8xx card for GPIO\n"); > + > + return 0; > + > +err_release_mem: > + release_mem_region(pci_resource_start(dev, 0), > + pci_resource_len(dev, 0)); > + pci_set_drvdata(dev, NULL); > +err_disable: > + pci_disable_device(dev); > +err_freebg: > + kfree(bg); > + > + return err; > +} > + > +static void btgpio_remove(struct pci_dev *pdev) > +{ > + struct btgpio *bg = pci_get_drvdata(pdev); > + > + gpiochip_remove(&bg->gpio); > + > + bgwrite(0, BT848_INT_MASK); > + bgwrite(~0x0, BT848_INT_STAT); > + bgwrite(0x0, BT848_GPIO_OUT_EN); > + > + iounmap(bg->mmio); > + release_mem_region(pci_resource_start(pdev,0), > + pci_resource_len(pdev,0)); > + pci_disable_device(pdev); > + > + pci_set_drvdata(pdev, NULL); > + kfree(bg); > +} > + > +#ifdef CONFIG_PM > +static int btgpio_suspend(struct pci_dev *pdev, pm_message_t state) > +{ > + struct btgpio *bg = pci_get_drvdata(pdev); > + unsigned long flags; > + > + spin_lock_irqsave(&bg->lock, flags); > + > + bg->saved_outen = bgread(BT848_GPIO_OUT_EN); > + bg->saved_data = bgread(BT848_GPIO_DATA); > + > + bgwrite(0, BT848_INT_MASK); > + bgwrite(~0x0, BT848_INT_STAT); > + bgwrite(0x0, BT848_GPIO_OUT_EN); > + > + spin_unlock_irqrestore(&bg->lock, flags); > + > + pci_save_state(pdev); > + pci_disable_device(pdev); > + pci_set_power_state(pdev, pci_choose_state(pdev, state)); > + > + return 0; > +} > + > +static int btgpio_resume(struct pci_dev *pdev) > +{ > + struct btgpio *bg = pci_get_drvdata(pdev); > + unsigned long flags; > + int err; > + > + pci_set_power_state(pdev, 0); > + err = pci_enable_device(pdev); > + if (err) > + return err; > + pci_restore_state(pdev); > + > + spin_lock_irqsave(&bg->lock, flags); > + > + bgwrite(0, BT848_INT_MASK); > + bgwrite(0, BT848_GPIO_REG_INP); > + bgwrite(bg->saved_outen, BT848_GPIO_OUT_EN); > + bgwrite(bg->saved_data, BT848_GPIO_DATA); > + > + spin_unlock_irqrestore(&bg->lock, flags); > + > + return 0; > +} > +#endif /* CONFIG_PM */ > + > +static struct pci_device_id btgpio_pci_tbl[] = { > + { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848) }, > + { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849) }, > + { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878) }, > + { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879) }, > + { 0, }, > +}; > +MODULE_DEVICE_TABLE(pci, btgpio_pci_tbl); > + > +static struct pci_driver btgpio_pci_driver = { > + .name = "btgpio", > + .id_table = btgpio_pci_tbl, > + .probe = btgpio_probe, > + .remove = btgpio_remove, > +#ifdef CONFIG_PM > + .suspend = btgpio_suspend, > + .resume = btgpio_resume, > +#endif > +}; > + > +static int btgpio_init(void) > +{ > + return pci_register_driver(&btgpio_pci_driver); > +} > +module_init(btgpio_init) > + > +static void btgpio_exit(void) > +{ > + pci_unregister_driver(&btgpio_pci_driver); > +} > +module_exit(btgpio_exit) > + > +MODULE_LICENSE("GPL"); > +MODULE_AUTHOR("Michael Buesch"); > +MODULE_DESCRIPTION("Abuse a BT8xx framegrabber card as generic GPIO card"); >
-- -- "Alan, I'm getting a bit worried about you." -- Linus Torvalds
| |