gpio: Added timbgpio
PATCH 9/9 gpio: Added timbgpio
Supplied is a GPIO driver for the Timberdale FPGA found on the Intel Atom board Russellville.
Signed-off-by Richard Röjfors <[email protected]>
---
drivers/gpio/timbgpio.c +247 -0
@@ -0,0 +1,247 @@ +/* +* timbgpio.c timberdale FPGA GPIO driver +* Copyright (c) 2009 Intel Corporation +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* 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. +*/ + +/* Supports: +* Timberdale FPGA GPIO +*/ + +#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/pci.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> + +#define DRIVER_NAME "timb-gpio" + +#define TIMB_NR_GPIOS 16 + +#define TGPIOVAL 0 +#define TGPIODIR 0x04 +#define TGPIOINT 0x08 +#define TGPIOINT_STATUS 0x0c +#define TGPIOINT_PENDING 0x10 +#define TGPIOINT_CLR 0x14 +#define TGPIOFLK 0x18 +#define TGPIOLVL 0x1c + +struct timbgpio { +void __iomem *membase; +struct mutex lock;/* mutual exclusion */ +struct pci_dev *pdev; +struct gpio_chip gpio; +}; + +static u32 timbgpio_configure (struct gpio_chip *gpio,unsigned nr, +unsigned off,unsigned val) +{ + struct timbgpio *tgpio = container_of(gpio, struct timbgpio, gpio); + +u32 config, oldconfig, wconfig; + +mutex_lock (&tgpio->lock); + config =ioread32 (tgpio->membase + off); + oldconfig = config; + +if (val) + config |= (1 << nr); +else + config &= ~(1 << nr); + +iowrite32 (config, tgpio->membase + off); + wconfig =ioread32 (tgpio->membase + off); +mutex_unlock (&tgpio->lock); + +return oldconfig; +} + +static int timbgpio_gpio_direction_input (struct gpio_chip *gpio,unsigned nr) +{ +timbgpio_configure (gpio, nr,TGPIODIR ,1 ); +return 0 ; +} + +static int timbgpio_gpio_get (struct gpio_chip *gpio,unsigned nr) +{ + struct timbgpio *tgpio = container_of(gpio, struct timbgpio, gpio); +u32 value; + + value =ioread32 (tgpio->membase +TGPIOVAL ); +return (value & (1 << nr)) ?1 :0 ; +} + +static int timbgpio_gpio_direction_output (struct gpio_chip *gpio, +unsigned nr,int val) +{ +timbgpio_configure (gpio, nr,TGPIODIR ,0 ); +return 0 ; +} + + + +static void timbgpio_gpio_set (struct gpio_chip *gpio, +unsigned nr,int val) +{ +timbgpio_configure (gpio, nr,TGPIOVAL , val); +} + +static irqreturn_t timbgpio_handleinterrupt (int irq,void *devid) +{ +struct timbgpio *tgpio = (struct timbgpio *)devid; + +iowrite32 (0xffffffff , tgpio->membase +TGPIOINT_CLR ); + +return IRQ_HANDLED ; +} + +static int timbgpio_probe (struct platform_device *dev) +{ +int err, irq; +struct gpio_chip *gc; +struct timbgpio *tgpio; +struct resource *iomem; + + iomem =platform_get_resource (dev,IORESOURCE_MEM ,0 ); +if (!iomem) { + err = -EINVAL ; + goto err_mem; + } + + tgpio =kzalloc (sizeof (*tgpio),GFP_KERNEL ); +if (!tgpio) { + err = -EINVAL ; + goto err_mem; + } + +mutex_init (&tgpio->lock); + +if (!request_mem_region (iomem->start,resource_size (iomem), +DRIVER_NAME )) { + err = -EBUSY ; + goto err_request; + } + + tgpio->membase =ioremap (iomem->start,resource_size (iomem)); +if (!tgpio->membase) { + err = -ENOMEM ; + goto err_ioremap; + } + + gc = &tgpio->gpio; + + gc->label =DRIVER_NAME ; + gc->owner =THIS_MODULE ; + gc->direction_input = timbgpio_gpio_direction_input; + gc->get = timbgpio_gpio_get; + gc->direction_output = timbgpio_gpio_direction_output; + gc->set = timbgpio_gpio_set; + gc->dbg_show =NULL ; + gc->base =0 ; + gc->ngpio =TIMB_NR_GPIOS ; + gc->can_sleep =0 ; + + err =gpiochip_add (gc); +if (err) + goto err_chipadd; + +platform_set_drvdata (dev, tgpio); + +/* register interrupt */ + irq =platform_get_irq (dev,0 ); +if (irq <0 ) + goto err_get_irq; + +/* clear pending interrupts */ +iowrite32 (0xffffffff , tgpio->membase +TGPIOINT_CLR ); +iowrite32 (0x0 , tgpio->membase +TGPIOINT ); + +/* request IRQ */ + err =request_irq (irq, timbgpio_handleinterrupt,IRQF_SHARED , +DRIVER_NAME , tgpio); +if (err) { + printk(KERN_ERR DRIVER_NAME": Failed to request IRQ\n"); + goto err_get_irq; + } + +return err; + +err_get_irq: + err =gpiochip_remove (&tgpio->gpio); +if (err) + printk(KERN_ERR DRIVER_NAME": failed to remove gpio_chip\n"); +err_chipadd: +iounmap (tgpio->membase); +err_ioremap: +release_mem_region (iomem->start,resource_size (iomem)); +err_request: +kfree (tgpio); +err_mem: + printk(KERN_ERR DRIVER_NAME": Failed to register GPIOs: %d\n", err); + +return err; +} + +static int timbgpio_remove (struct platform_device *dev) +{ +int err; +struct timbgpio *tgpio =platform_get_drvdata (dev); +struct resource *iomem =platform_get_resource (dev,IORESOURCE_MEM ,0 ); + +/* disable interrupts */ +iowrite32 (0x0 , tgpio->membase +TGPIOINT ); + +free_irq (platform_get_irq (dev,0 ), tgpio); + err =gpiochip_remove (&tgpio->gpio); +if (err) + printk(KERN_ERR DRIVER_NAME": failed to remove gpio_chip\n"); + +iounmap (tgpio->membase); +release_mem_region (iomem->start,resource_size (iomem)); +kfree (tgpio); + +return 0 ; +} + +static struct platform_driver timbgpio_platform_driver = { + .driver = { + .name =DRIVER_NAME , + .owner =THIS_MODULE , + }, + .probe = timbgpio_probe, + .remove = timbgpio_remove, +}; + +/*--------------------------------------------------------------------------*/ + +static int __init timbgpio_init (void ) +{ +return platform_driver_register (&timbgpio_platform_driver); +} + +static void __exit timbgpio_exit(void) +{ +platform_driver_unregister (&timbgpio_platform_driver); +} + +module_init (timbgpio_init); +module_exit (timbgpio_exit); + +MODULE_DESCRIPTION ("Timberdale GPIO driver" ); +MODULE_LICENSE ("GPL v2" ); +MODULE_AUTHOR ("Mocean Laboratories" ); +MODULE_ALIAS ("platform:" DRIVER_NAME ); +
drivers/gpio/Kconfig +6 -0
@@ -161,6 +161,12 @@ If unsure, say N. +config GPIO_TIMBERDALE + tristate "Support for timberdale GPIO" + depends on MFD_TIMBERDALE && GPIOLIB + ---help--- + Add support for GPIO usage of some pins of the timberdale FPGA. + comment "SPI GPIO expanders:" config GPIO_MAX7301
drivers/gpio/Makefile +1 -0
@@ -12,5 +12,6 @@ obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o obj-$(CONFIG_GPIO_XILINX) += xilinx_gpio.o obj-$(CONFIG_GPIO_BT8XX) += bt8xxgpio.o +obj-$(CONFIG_GPIO_TIMBERDALE) += timbgpio.o obj-$(CONFIG_GPIO_MC33880) += mc33880.o