[PATCH v4] GPIO: Add support for GPIO on CLPS711X-target platform

Russell King - ARM Linux linux at arm.linux.org.uk
Tue Oct 9 12:09:51 EDT 2012


On Tue, Oct 09, 2012 at 08:05:56PM +0400, Alexander Shiyan wrote:
> The CLPS711X CPUs provide some GPIOs for use in the system. This
> driver provides support for these via gpiolib. Due to platform
> limitations, driver does not support interrupts, only inputs and
> outputs.
> 
> Signed-off-by: Alexander Shiyan <shc_work at mail.ru>

This is much better, thanks.  As it's going via someone elses tree:

Acked-by: Russell King <rmk+kernel at arm.linux.org.uk>

> ---
>  arch/arm/Kconfig                           |    1 +
>  arch/arm/mach-clps711x/include/mach/gpio.h |   13 +++
>  drivers/gpio/Kconfig                       |    4 +
>  drivers/gpio/Makefile                      |    1 +
>  drivers/gpio/gpio-clps711x.c               |  163 ++++++++++++++++++++++++++++
>  5 files changed, 182 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/mach-clps711x/include/mach/gpio.h
>  create mode 100644 drivers/gpio/gpio-clps711x.c
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 2867a77..343b0c3 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -352,6 +352,7 @@ config ARCH_CLPS711X
>  	bool "Cirrus Logic CLPS711x/EP721x/EP731x-based"
>  	select CPU_ARM720T
>  	select ARCH_USES_GETTIMEOFFSET
> +	select ARCH_REQUIRE_GPIOLIB
>  	select COMMON_CLK
>  	select CLKDEV_LOOKUP
>  	select NEED_MACH_MEMORY_H
> diff --git a/arch/arm/mach-clps711x/include/mach/gpio.h b/arch/arm/mach-clps711x/include/mach/gpio.h
> new file mode 100644
> index 0000000..8ac6889
> --- /dev/null
> +++ b/arch/arm/mach-clps711x/include/mach/gpio.h
> @@ -0,0 +1,13 @@
> +/*
> + *  This file contains the CLPS711X GPIO definitions.
> + *
> + *  Copyright (C) 2012 Alexander Shiyan <shc_work at 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.
> + */
> +
> +/* Simple helper for convert port & pin to GPIO number */
> +#define CLPS711X_GPIO(port, bit)	((port) * 8 + (bit))
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index d055cee..fb76140 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -91,6 +91,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 9aeed67..a28725e 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_ARCH_DAVINCI)	+= gpio-davinci.o
> diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c
> new file mode 100644
> index 0000000..ea21822
> --- /dev/null
> +++ b/drivers/gpio/gpio-clps711x.c
> @@ -0,0 +1,163 @@
> +/*
> + *  CLPS711X GPIO driver
> + *
> + *  Copyright (C) 2012 Alexander Shiyan <shc_work at 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 at mail.ru>");
> +MODULE_DESCRIPTION("CLPS711X GPIO driver");
> -- 
> 1.7.8.6
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel



More information about the linux-arm-kernel mailing list