diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/gpio/Kconfig | 4 | ||||
| -rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
| -rw-r--r-- | drivers/gpio/gpio-clps711x.c | 163 | 
3 files changed, 168 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 150eeb705fb..9e3fb343871 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -102,6 +102,10 @@ config GPIO_MAX730X  comment "Memory mapped GPIO drivers:" +config GPIO_CLPS711X +	def_bool y +	depends on ARCH_CLPS711X +  config GPIO_GENERIC_PLATFORM  	tristate "Generic memory-mapped GPIO controller support (MMIO platform device)"  	select GPIO_GENERIC diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index e6f8e379a2e..1c1b63fcaeb 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_GPIO_ADP5588)	+= gpio-adp5588.o  obj-$(CONFIG_GPIO_AMD8111)	+= gpio-amd8111.o  obj-$(CONFIG_GPIO_ARIZONA)	+= gpio-arizona.o  obj-$(CONFIG_GPIO_BT8XX)	+= gpio-bt8xx.o +obj-$(CONFIG_GPIO_CLPS711X)	+= gpio-clps711x.o  obj-$(CONFIG_GPIO_CS5535)	+= gpio-cs5535.o  obj-$(CONFIG_GPIO_DA9052)	+= gpio-da9052.o  obj-$(CONFIG_GPIO_DA9055)	+= gpio-da9055.o diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c new file mode 100644 index 00000000000..ea21822b3de --- /dev/null +++ b/drivers/gpio/gpio-clps711x.c @@ -0,0 +1,163 @@ +/* + *  CLPS711X GPIO driver + * + *  Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru> + * + * 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. + */ + +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/platform_device.h> + +#include <mach/hardware.h> + +#define CLPS711X_GPIO_PORTS	5 +#define CLPS711X_GPIO_NAME	"gpio-clps711x" + +struct clps711x_gpio { +	struct gpio_chip	chip[CLPS711X_GPIO_PORTS]; +	spinlock_t		lock; +}; + +static void __iomem *clps711x_ports[] = { +	CLPS711X_VIRT_BASE + PADR, +	CLPS711X_VIRT_BASE + PBDR, +	CLPS711X_VIRT_BASE + PCDR, +	CLPS711X_VIRT_BASE + PDDR, +	CLPS711X_VIRT_BASE + PEDR, +}; + +static void __iomem *clps711x_pdirs[] = { +	CLPS711X_VIRT_BASE + PADDR, +	CLPS711X_VIRT_BASE + PBDDR, +	CLPS711X_VIRT_BASE + PCDDR, +	CLPS711X_VIRT_BASE + PDDDR, +	CLPS711X_VIRT_BASE + PEDDR, +}; + +#define clps711x_port(x)	clps711x_ports[x->base / 8] +#define clps711x_pdir(x)	clps711x_pdirs[x->base / 8] + +static int gpio_clps711x_get(struct gpio_chip *chip, unsigned offset) +{ +	return !!readb(clps711x_port(chip)) & (1 << offset); +} + +static void gpio_clps711x_set(struct gpio_chip *chip, unsigned offset, +			      int value) +{ +	int tmp; +	unsigned long flags; +	struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); + +	spin_lock_irqsave(&gpio->lock, flags); +	tmp = readb(clps711x_port(chip)) & ~(1 << offset); +	if (value) +		tmp |= 1 << offset; +	writeb(tmp, clps711x_port(chip)); +	spin_unlock_irqrestore(&gpio->lock, flags); +} + +static int gpio_clps711x_direction_in(struct gpio_chip *chip, unsigned offset) +{ +	int tmp; +	unsigned long flags; +	struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); + +	spin_lock_irqsave(&gpio->lock, flags); +	tmp = readb(clps711x_pdir(chip)) & ~(1 << offset); +	writeb(tmp, clps711x_pdir(chip)); +	spin_unlock_irqrestore(&gpio->lock, flags); + +	return 0; +} + +static int gpio_clps711x_direction_out(struct gpio_chip *chip, unsigned offset, +				       int value) +{ +	int tmp; +	unsigned long flags; +	struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); + +	spin_lock_irqsave(&gpio->lock, flags); +	tmp = readb(clps711x_pdir(chip)) | (1 << offset); +	writeb(tmp, clps711x_pdir(chip)); +	tmp = readb(clps711x_port(chip)) & ~(1 << offset); +	if (value) +		tmp |= 1 << offset; +	writeb(tmp, clps711x_port(chip)); +	spin_unlock_irqrestore(&gpio->lock, flags); + +	return 0; +} + +struct clps711x_gpio_port { +	char	*name; +	int	nr; +}; + +static const struct clps711x_gpio_port clps711x_gpio_ports[] __initconst = { +	{ "PORTA", 8, }, +	{ "PORTB", 8, }, +	{ "PORTC", 8, }, +	{ "PORTD", 8, }, +	{ "PORTE", 3, }, +}; + +static int __init gpio_clps711x_init(void) +{ +	int i; +	struct platform_device *pdev; +	struct clps711x_gpio *gpio; + +	pdev = platform_device_alloc(CLPS711X_GPIO_NAME, 0); +	if (!pdev) { +		pr_err("Cannot create platform device: %s\n", +		       CLPS711X_GPIO_NAME); +		return -ENOMEM; +	} + +	platform_device_add(pdev); + +	gpio = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_gpio), +			    GFP_KERNEL); +	if (!gpio) { +		dev_err(&pdev->dev, "GPIO allocating memory error\n"); +		platform_device_del(pdev); +		platform_device_put(pdev); +		return -ENOMEM; +	} + +	platform_set_drvdata(pdev, gpio); + +	spin_lock_init(&gpio->lock); + +	for (i = 0; i < CLPS711X_GPIO_PORTS; i++) { +		gpio->chip[i].owner		= THIS_MODULE; +		gpio->chip[i].dev		= &pdev->dev; +		gpio->chip[i].label		= clps711x_gpio_ports[i].name; +		gpio->chip[i].base		= i * 8; +		gpio->chip[i].ngpio		= clps711x_gpio_ports[i].nr; +		gpio->chip[i].direction_input	= gpio_clps711x_direction_in; +		gpio->chip[i].get		= gpio_clps711x_get; +		gpio->chip[i].direction_output	= gpio_clps711x_direction_out; +		gpio->chip[i].set		= gpio_clps711x_set; +		WARN_ON(gpiochip_add(&gpio->chip[i])); +	} + +	dev_info(&pdev->dev, "GPIO driver initialized\n"); + +	return 0; +} +arch_initcall(gpio_clps711x_init); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); +MODULE_DESCRIPTION("CLPS711X GPIO driver");  |