aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2013-06-11 18:57:17 -0400
committerOlof Johansson <olof@lixom.net>2013-06-11 18:57:51 -0400
commitea36b02269e49ad9dad926197de2ceab377c4c95 (patch)
treed80e510716a055d325d670238957854d2a6715d6 /drivers/gpio
parentb67172ec0043bdc122aca334164979bd001450b6 (diff)
parent70423a379d5457f19b3b2ebc4239faebe64c602d (diff)
Merge branch 'clps711x/soc' into next/soc
From Alexander Shiyan, this is a series of cleanups of clps711x, movig it closer to multiplatform and cleans up a bunch of old code. * clps711x/soc: ARM: clps711x: Update defconfig ARM: clps711x: Add support for SYSCON driver ARM: clps711x: edb7211: Control LCD backlight via PWM ARM: clps711x: edb7211: Add support for I2C ARM: clps711x: Optimize interrupt handling ARM: clps711x: Add clocksource framework ARM: clps711x: Replace "arch_initcall" in common code with ".init_early" ARM: clps711x: Move specific definitions from hardware.h to boards files ARM: clps711x: p720t: Define PLD registers as GPIOs ARM: clps711x: autcpu12: Move remaining specific definitions to board file ARM: clps711x: autcpu12: Special driver for handling memory is removed ARM: clps711x: autcpu12: Add support for NOR flash ARM: clps711x: autcpu12: Move LCD DPOT definitions to board file ARM: clps711x: Set PLL clock to zero if we work from 13 mHz source ARM: clps711x: Remove NEED_MACH_MEMORY_H dependency ARM: clps711x: Re-add GPIO support GPIO: clps711x: Add DT support GPIO: clps711x: Rewrite driver for using generic GPIO code + Linux 3.10-rc4 Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig5
-rw-r--r--drivers/gpio/gpio-clps711x.c236
2 files changed, 72 insertions, 169 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 573c449c49b9..23d1d0155bb3 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -109,8 +109,11 @@ config GPIO_MAX730X
109comment "Memory mapped GPIO drivers:" 109comment "Memory mapped GPIO drivers:"
110 110
111config GPIO_CLPS711X 111config GPIO_CLPS711X
112 def_bool y 112 tristate "CLPS711X GPIO support"
113 depends on ARCH_CLPS711X 113 depends on ARCH_CLPS711X
114 select GPIO_GENERIC
115 help
116 Say yes here to support GPIO on CLPS711X SoCs.
114 117
115config GPIO_GENERIC_PLATFORM 118config GPIO_GENERIC_PLATFORM
116 tristate "Generic memory-mapped GPIO controller support (MMIO platform device)" 119 tristate "Generic memory-mapped GPIO controller support (MMIO platform device)"
diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c
index ce63b75b13f5..0edaf2ce9266 100644
--- a/drivers/gpio/gpio-clps711x.c
+++ b/drivers/gpio/gpio-clps711x.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * CLPS711X GPIO driver 2 * CLPS711X GPIO driver
3 * 3 *
4 * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru> 4 * Copyright (C) 2012,2013 Alexander Shiyan <shc_work@mail.ru>
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 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 7 * it under the terms of the GNU General Public License as published by
@@ -9,191 +9,91 @@
9 * (at your option) any later version. 9 * (at your option) any later version.
10 */ 10 */
11 11
12#include <linux/io.h> 12#include <linux/err.h>
13#include <linux/slab.h>
14#include <linux/gpio.h> 13#include <linux/gpio.h>
15#include <linux/module.h> 14#include <linux/module.h>
16#include <linux/spinlock.h> 15#include <linux/basic_mmio_gpio.h>
17#include <linux/platform_device.h> 16#include <linux/platform_device.h>
18 17
19#include <mach/hardware.h> 18static int clps711x_gpio_probe(struct platform_device *pdev)
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{ 19{
50 return !!(readb(clps711x_port(chip)) & (1 << offset)); 20 struct device_node *np = pdev->dev.of_node;
51} 21 void __iomem *dat, *dir;
22 struct bgpio_chip *bgc;
23 struct resource *res;
24 int err, id = np ? of_alias_get_id(np, "gpio") : pdev->id;
52 25
53static void gpio_clps711x_set(struct gpio_chip *chip, unsigned offset, 26 if ((id < 0) || (id > 4))
54 int value) 27 return -ENODEV;
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_dir_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 28
74 spin_lock_irqsave(&gpio->lock, flags); 29 bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
75 tmp = readb(clps711x_pdir(chip)) & ~(1 << offset); 30 if (!bgc)
76 writeb(tmp, clps711x_pdir(chip)); 31 return -ENOMEM;
77 spin_unlock_irqrestore(&gpio->lock, flags);
78 32
79 return 0; 33 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
80} 34 dat = devm_ioremap_resource(&pdev->dev, res);
35 if (IS_ERR(dat))
36 return PTR_ERR(dat);
37
38 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
39 dir = devm_ioremap_resource(&pdev->dev, res);
40 if (IS_ERR(dir))
41 return PTR_ERR(dir);
42
43 switch (id) {
44 case 3:
45 /* PORTD is inverted logic for direction register */
46 err = bgpio_init(bgc, &pdev->dev, 1, dat, NULL, NULL,
47 NULL, dir, 0);
48 break;
49 default:
50 err = bgpio_init(bgc, &pdev->dev, 1, dat, NULL, NULL,
51 dir, NULL, 0);
52 break;
53 }
81 54
82static int gpio_clps711x_dir_out(struct gpio_chip *chip, unsigned offset, 55 if (err)
83 int value) 56 return err;
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 57
101static int gpio_clps711x_dir_in_inv(struct gpio_chip *chip, unsigned offset) 58 switch (id) {
102{ 59 case 4:
103 int tmp; 60 /* PORTE is 3 lines only */
104 unsigned long flags; 61 bgc->gc.ngpio = 3;
105 struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); 62 break;
63 default:
64 break;
65 }
106 66
107 spin_lock_irqsave(&gpio->lock, flags); 67 bgc->gc.base = id * 8;
108 tmp = readb(clps711x_pdir(chip)) | (1 << offset); 68 platform_set_drvdata(pdev, bgc);
109 writeb(tmp, clps711x_pdir(chip));
110 spin_unlock_irqrestore(&gpio->lock, flags);
111 69
112 return 0; 70 return gpiochip_add(&bgc->gc);
113} 71}
114 72
115static int gpio_clps711x_dir_out_inv(struct gpio_chip *chip, unsigned offset, 73static int clps711x_gpio_remove(struct platform_device *pdev)
116 int value)
117{ 74{
118 int tmp; 75 struct bgpio_chip *bgc = platform_get_drvdata(pdev);
119 unsigned long flags; 76
120 struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); 77 return bgpio_remove(bgc);
121
122 spin_lock_irqsave(&gpio->lock, flags);
123 tmp = readb(clps711x_pdir(chip)) & ~(1 << offset);
124 writeb(tmp, clps711x_pdir(chip));
125 tmp = readb(clps711x_port(chip)) & ~(1 << offset);
126 if (value)
127 tmp |= 1 << offset;
128 writeb(tmp, clps711x_port(chip));
129 spin_unlock_irqrestore(&gpio->lock, flags);
130
131 return 0;
132} 78}
133 79
134static struct { 80static const struct of_device_id clps711x_gpio_ids[] = {
135 char *name; 81 { .compatible = "cirrus,clps711x-gpio" },
136 int nr; 82 { }
137 int inv_dir;
138} clps711x_gpio_ports[] __initconst = {
139 { "PORTA", 8, 0, },
140 { "PORTB", 8, 0, },
141 { "PORTC", 8, 0, },
142 { "PORTD", 8, 1, },
143 { "PORTE", 3, 0, },
144}; 83};
84MODULE_DEVICE_TABLE(of, clps711x_gpio_ids);
85
86static struct platform_driver clps711x_gpio_driver = {
87 .driver = {
88 .name = "clps711x-gpio",
89 .owner = THIS_MODULE,
90 .of_match_table = of_match_ptr(clps711x_gpio_ids),
91 },
92 .probe = clps711x_gpio_probe,
93 .remove = clps711x_gpio_remove,
94};
95module_platform_driver(clps711x_gpio_driver);
145 96
146static int __init gpio_clps711x_init(void) 97MODULE_LICENSE("GPL");
147{
148 int i;
149 struct platform_device *pdev;
150 struct clps711x_gpio *gpio;
151
152 pdev = platform_device_alloc(CLPS711X_GPIO_NAME, 0);
153 if (!pdev) {
154 pr_err("Cannot create platform device: %s\n",
155 CLPS711X_GPIO_NAME);
156 return -ENOMEM;
157 }
158
159 platform_device_add(pdev);
160
161 gpio = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_gpio),
162 GFP_KERNEL);
163 if (!gpio) {
164 dev_err(&pdev->dev, "GPIO allocating memory error\n");
165 platform_device_unregister(pdev);
166 return -ENOMEM;
167 }
168
169 platform_set_drvdata(pdev, gpio);
170
171 spin_lock_init(&gpio->lock);
172
173 for (i = 0; i < CLPS711X_GPIO_PORTS; i++) {
174 gpio->chip[i].owner = THIS_MODULE;
175 gpio->chip[i].dev = &pdev->dev;
176 gpio->chip[i].label = clps711x_gpio_ports[i].name;
177 gpio->chip[i].base = i * 8;
178 gpio->chip[i].ngpio = clps711x_gpio_ports[i].nr;
179 gpio->chip[i].get = gpio_clps711x_get;
180 gpio->chip[i].set = gpio_clps711x_set;
181 if (!clps711x_gpio_ports[i].inv_dir) {
182 gpio->chip[i].direction_input = gpio_clps711x_dir_in;
183 gpio->chip[i].direction_output = gpio_clps711x_dir_out;
184 } else {
185 gpio->chip[i].direction_input = gpio_clps711x_dir_in_inv;
186 gpio->chip[i].direction_output = gpio_clps711x_dir_out_inv;
187 }
188 WARN_ON(gpiochip_add(&gpio->chip[i]));
189 }
190
191 dev_info(&pdev->dev, "GPIO driver initialized\n");
192
193 return 0;
194}
195arch_initcall(gpio_clps711x_init);
196
197MODULE_LICENSE("GPL v2");
198MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); 98MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
199MODULE_DESCRIPTION("CLPS711X GPIO driver"); 99MODULE_DESCRIPTION("CLPS711X GPIO driver");