aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlexander Shiyan <shc_work@mail.ru>2012-10-09 12:05:56 -0400
committerLinus Walleij <linus.walleij@linaro.org>2012-10-15 15:25:00 -0400
commita3b8d4a513574e6adf76bcacad21c95ee6b8ce4b (patch)
treecc6a18b926ff546560fabb303a399c19304d0988 /drivers
parent04ed4279715f685857b8d5b84a48bf7bd43a36c5 (diff)
GPIO: Add support for GPIO on CLPS711X-target platform
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@mail.ru> Acked-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpio/Kconfig4
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-clps711x.c163
3 files changed, 168 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 150eeb705fbc..9e3fb3438718 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -102,6 +102,10 @@ config GPIO_MAX730X
102 102
103comment "Memory mapped GPIO drivers:" 103comment "Memory mapped GPIO drivers:"
104 104
105config GPIO_CLPS711X
106 def_bool y
107 depends on ARCH_CLPS711X
108
105config GPIO_GENERIC_PLATFORM 109config GPIO_GENERIC_PLATFORM
106 tristate "Generic memory-mapped GPIO controller support (MMIO platform device)" 110 tristate "Generic memory-mapped GPIO controller support (MMIO platform device)"
107 select GPIO_GENERIC 111 select GPIO_GENERIC
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index e6f8e379a2ec..1c1b63fcaeb3 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o
16obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o 16obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
17obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o 17obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
18obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o 18obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
19obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
19obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o 20obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
20obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o 21obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
21obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o 22obj-$(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 000000000000..ea21822b3de9
--- /dev/null
+++ b/drivers/gpio/gpio-clps711x.c
@@ -0,0 +1,163 @@
1/*
2 * CLPS711X GPIO driver
3 *
4 * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/io.h>
13#include <linux/slab.h>
14#include <linux/gpio.h>
15#include <linux/module.h>
16#include <linux/spinlock.h>
17#include <linux/platform_device.h>
18
19#include <mach/hardware.h>
20
21#define CLPS711X_GPIO_PORTS 5
22#define CLPS711X_GPIO_NAME "gpio-clps711x"
23
24struct clps711x_gpio {
25 struct gpio_chip chip[CLPS711X_GPIO_PORTS];
26 spinlock_t lock;
27};
28
29static void __iomem *clps711x_ports[] = {
30 CLPS711X_VIRT_BASE + PADR,
31 CLPS711X_VIRT_BASE + PBDR,
32 CLPS711X_VIRT_BASE + PCDR,
33 CLPS711X_VIRT_BASE + PDDR,
34 CLPS711X_VIRT_BASE + PEDR,
35};
36
37static void __iomem *clps711x_pdirs[] = {
38 CLPS711X_VIRT_BASE + PADDR,
39 CLPS711X_VIRT_BASE + PBDDR,
40 CLPS711X_VIRT_BASE + PCDDR,
41 CLPS711X_VIRT_BASE + PDDDR,
42 CLPS711X_VIRT_BASE + PEDDR,
43};
44
45#define clps711x_port(x) clps711x_ports[x->base / 8]
46#define clps711x_pdir(x) clps711x_pdirs[x->base / 8]
47
48static int gpio_clps711x_get(struct gpio_chip *chip, unsigned offset)
49{
50 return !!readb(clps711x_port(chip)) & (1 << offset);
51}
52
53static void gpio_clps711x_set(struct gpio_chip *chip, unsigned offset,
54 int value)
55{
56 int tmp;
57 unsigned long flags;
58 struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
59
60 spin_lock_irqsave(&gpio->lock, flags);
61 tmp = readb(clps711x_port(chip)) & ~(1 << offset);
62 if (value)
63 tmp |= 1 << offset;
64 writeb(tmp, clps711x_port(chip));
65 spin_unlock_irqrestore(&gpio->lock, flags);
66}
67
68static int gpio_clps711x_direction_in(struct gpio_chip *chip, unsigned offset)
69{
70 int tmp;
71 unsigned long flags;
72 struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
73
74 spin_lock_irqsave(&gpio->lock, flags);
75 tmp = readb(clps711x_pdir(chip)) & ~(1 << offset);
76 writeb(tmp, clps711x_pdir(chip));
77 spin_unlock_irqrestore(&gpio->lock, flags);
78
79 return 0;
80}
81
82static int gpio_clps711x_direction_out(struct gpio_chip *chip, unsigned offset,
83 int value)
84{
85 int tmp;
86 unsigned long flags;
87 struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
88
89 spin_lock_irqsave(&gpio->lock, flags);
90 tmp = readb(clps711x_pdir(chip)) | (1 << offset);
91 writeb(tmp, clps711x_pdir(chip));
92 tmp = readb(clps711x_port(chip)) & ~(1 << offset);
93 if (value)
94 tmp |= 1 << offset;
95 writeb(tmp, clps711x_port(chip));
96 spin_unlock_irqrestore(&gpio->lock, flags);
97
98 return 0;
99}
100
101struct clps711x_gpio_port {
102 char *name;
103 int nr;
104};
105
106static const struct clps711x_gpio_port clps711x_gpio_ports[] __initconst = {
107 { "PORTA", 8, },
108 { "PORTB", 8, },
109 { "PORTC", 8, },
110 { "PORTD", 8, },
111 { "PORTE", 3, },
112};
113
114static int __init gpio_clps711x_init(void)
115{
116 int i;
117 struct platform_device *pdev;
118 struct clps711x_gpio *gpio;
119
120 pdev = platform_device_alloc(CLPS711X_GPIO_NAME, 0);
121 if (!pdev) {
122 pr_err("Cannot create platform device: %s\n",
123 CLPS711X_GPIO_NAME);
124 return -ENOMEM;
125 }
126
127 platform_device_add(pdev);
128
129 gpio = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_gpio),
130 GFP_KERNEL);
131 if (!gpio) {
132 dev_err(&pdev->dev, "GPIO allocating memory error\n");
133 platform_device_del(pdev);
134 platform_device_put(pdev);
135 return -ENOMEM;
136 }
137
138 platform_set_drvdata(pdev, gpio);
139
140 spin_lock_init(&gpio->lock);
141
142 for (i = 0; i < CLPS711X_GPIO_PORTS; i++) {
143 gpio->chip[i].owner = THIS_MODULE;
144 gpio->chip[i].dev = &pdev->dev;
145 gpio->chip[i].label = clps711x_gpio_ports[i].name;
146 gpio->chip[i].base = i * 8;
147 gpio->chip[i].ngpio = clps711x_gpio_ports[i].nr;
148 gpio->chip[i].direction_input = gpio_clps711x_direction_in;
149 gpio->chip[i].get = gpio_clps711x_get;
150 gpio->chip[i].direction_output = gpio_clps711x_direction_out;
151 gpio->chip[i].set = gpio_clps711x_set;
152 WARN_ON(gpiochip_add(&gpio->chip[i]));
153 }
154
155 dev_info(&pdev->dev, "GPIO driver initialized\n");
156
157 return 0;
158}
159arch_initcall(gpio_clps711x_init);
160
161MODULE_LICENSE("GPL v2");
162MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
163MODULE_DESCRIPTION("CLPS711X GPIO driver");