diff options
author | Alexander Shiyan <shc_work@mail.ru> | 2013-04-26 11:47:28 -0400 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2013-06-11 18:44:02 -0400 |
commit | 55fe14ab872ab7a60944332c79640d561e93dfe8 (patch) | |
tree | 6d74f8aba9dfdb59485c72350a0d38a84141582d /drivers/gpio | |
parent | d683b96b072dc4680fc74964eca77e6a23d1fa6e (diff) |
GPIO: clps711x: Rewrite driver for using generic GPIO code
This patch provides rewritten driver for CLPS711X GPIO which uses
generic GPIO code.
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 5 | ||||
-rw-r--r-- | drivers/gpio/gpio-clps711x.c | 226 |
2 files changed, 63 insertions, 168 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 | |||
109 | comment "Memory mapped GPIO drivers:" | 109 | comment "Memory mapped GPIO drivers:" |
110 | 110 | ||
111 | config GPIO_CLPS711X | 111 | config 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 | ||
115 | config GPIO_GENERIC_PLATFORM | 118 | config 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..6ce8a8c1669e 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,83 @@ | |||
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> | 18 | static int clps711x_gpio_probe(struct platform_device *pdev) |
20 | |||
21 | #define CLPS711X_GPIO_PORTS 5 | ||
22 | #define CLPS711X_GPIO_NAME "gpio-clps711x" | ||
23 | |||
24 | struct clps711x_gpio { | ||
25 | struct gpio_chip chip[CLPS711X_GPIO_PORTS]; | ||
26 | spinlock_t lock; | ||
27 | }; | ||
28 | |||
29 | static 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 | |||
37 | static 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 | |||
48 | static int gpio_clps711x_get(struct gpio_chip *chip, unsigned offset) | ||
49 | { | 19 | { |
50 | return !!(readb(clps711x_port(chip)) & (1 << offset)); | 20 | void __iomem *dat, *dir; |
51 | } | 21 | struct bgpio_chip *bgc; |
22 | struct resource *res; | ||
23 | int err, id = pdev->id; | ||
52 | 24 | ||
53 | static void gpio_clps711x_set(struct gpio_chip *chip, unsigned offset, | 25 | if ((id < 0) || (id > 4)) |
54 | int value) | 26 | return -ENODEV; |
55 | { | ||
56 | int tmp; | ||
57 | unsigned long flags; | ||
58 | struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); | ||
59 | 27 | ||
60 | spin_lock_irqsave(&gpio->lock, flags); | 28 | bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL); |
61 | tmp = readb(clps711x_port(chip)) & ~(1 << offset); | 29 | if (!bgc) |
62 | if (value) | 30 | return -ENOMEM; |
63 | tmp |= 1 << offset; | ||
64 | writeb(tmp, clps711x_port(chip)); | ||
65 | spin_unlock_irqrestore(&gpio->lock, flags); | ||
66 | } | ||
67 | |||
68 | static 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 | |||
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 | 31 | ||
82 | static int gpio_clps711x_dir_out(struct gpio_chip *chip, unsigned offset, | 32 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
83 | int value) | 33 | dat = devm_ioremap_resource(&pdev->dev, res); |
84 | { | 34 | if (IS_ERR(dat)) |
85 | int tmp; | 35 | return PTR_ERR(dat); |
86 | unsigned long flags; | 36 | |
87 | struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); | 37 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
38 | dir = devm_ioremap_resource(&pdev->dev, res); | ||
39 | if (IS_ERR(dir)) | ||
40 | return PTR_ERR(dir); | ||
41 | |||
42 | switch (id) { | ||
43 | case 3: | ||
44 | /* PORTD is inverted logic for direction register */ | ||
45 | err = bgpio_init(bgc, &pdev->dev, 1, dat, NULL, NULL, | ||
46 | NULL, dir, 0); | ||
47 | break; | ||
48 | default: | ||
49 | err = bgpio_init(bgc, &pdev->dev, 1, dat, NULL, NULL, | ||
50 | dir, NULL, 0); | ||
51 | break; | ||
52 | } | ||
88 | 53 | ||
89 | spin_lock_irqsave(&gpio->lock, flags); | 54 | if (err) |
90 | tmp = readb(clps711x_pdir(chip)) | (1 << offset); | 55 | return err; |
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 | 56 | ||
98 | return 0; | 57 | switch (id) { |
99 | } | 58 | case 4: |
100 | 59 | /* PORTE is 3 lines only */ | |
101 | static int gpio_clps711x_dir_in_inv(struct gpio_chip *chip, unsigned offset) | 60 | bgc->gc.ngpio = 3; |
102 | { | 61 | break; |
103 | int tmp; | 62 | default: |
104 | unsigned long flags; | 63 | break; |
105 | struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); | 64 | } |
106 | 65 | ||
107 | spin_lock_irqsave(&gpio->lock, flags); | 66 | bgc->gc.base = id * 8; |
108 | tmp = readb(clps711x_pdir(chip)) | (1 << offset); | 67 | platform_set_drvdata(pdev, bgc); |
109 | writeb(tmp, clps711x_pdir(chip)); | ||
110 | spin_unlock_irqrestore(&gpio->lock, flags); | ||
111 | 68 | ||
112 | return 0; | 69 | return gpiochip_add(&bgc->gc); |
113 | } | 70 | } |
114 | 71 | ||
115 | static int gpio_clps711x_dir_out_inv(struct gpio_chip *chip, unsigned offset, | 72 | static int clps711x_gpio_remove(struct platform_device *pdev) |
116 | int value) | ||
117 | { | 73 | { |
118 | int tmp; | 74 | struct bgpio_chip *bgc = platform_get_drvdata(pdev); |
119 | unsigned long flags; | ||
120 | struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); | ||
121 | 75 | ||
122 | spin_lock_irqsave(&gpio->lock, flags); | 76 | return bgpio_remove(bgc); |
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 | } | 77 | } |
133 | 78 | ||
134 | static struct { | 79 | static struct platform_driver clps711x_gpio_driver = { |
135 | char *name; | 80 | .driver = { |
136 | int nr; | 81 | .name = "clps711x-gpio", |
137 | int inv_dir; | 82 | .owner = THIS_MODULE, |
138 | } clps711x_gpio_ports[] __initconst = { | 83 | }, |
139 | { "PORTA", 8, 0, }, | 84 | .probe = clps711x_gpio_probe, |
140 | { "PORTB", 8, 0, }, | 85 | .remove = clps711x_gpio_remove, |
141 | { "PORTC", 8, 0, }, | ||
142 | { "PORTD", 8, 1, }, | ||
143 | { "PORTE", 3, 0, }, | ||
144 | }; | 86 | }; |
87 | module_platform_driver(clps711x_gpio_driver); | ||
145 | 88 | ||
146 | static int __init gpio_clps711x_init(void) | 89 | MODULE_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 | } | ||
195 | arch_initcall(gpio_clps711x_init); | ||
196 | |||
197 | MODULE_LICENSE("GPL v2"); | ||
198 | MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); | 90 | MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); |
199 | MODULE_DESCRIPTION("CLPS711X GPIO driver"); | 91 | MODULE_DESCRIPTION("CLPS711X GPIO driver"); |