Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux...
[pandora-kernel.git] / arch / arm / plat-samsung / gpio-config.c
1 /* linux/arch/arm/plat-s3c/gpio-config.c
2  *
3  * Copyright 2008 Openmoko, Inc.
4  * Copyright 2008-2010 Simtec Electronics
5  *      Ben Dooks <ben@simtec.co.uk>
6  *      http://armlinux.simtec.co.uk/
7  *
8  * S3C series GPIO configuration core
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13 */
14
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/gpio.h>
18 #include <linux/io.h>
19
20 #include <plat/gpio-core.h>
21 #include <plat/gpio-cfg.h>
22 #include <plat/gpio-cfg-helpers.h>
23
24 int s3c_gpio_cfgpin(unsigned int pin, unsigned int config)
25 {
26         struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin);
27         unsigned long flags;
28         int offset;
29         int ret;
30
31         if (!chip)
32                 return -EINVAL;
33
34         offset = pin - chip->chip.base;
35
36         s3c_gpio_lock(chip, flags);
37         ret = s3c_gpio_do_setcfg(chip, offset, config);
38         s3c_gpio_unlock(chip, flags);
39
40         return ret;
41 }
42 EXPORT_SYMBOL(s3c_gpio_cfgpin);
43
44 unsigned s3c_gpio_getcfg(unsigned int pin)
45 {
46         struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin);
47         unsigned long flags;
48         unsigned ret = 0;
49         int offset;
50
51         if (chip) {
52                 offset = pin - chip->chip.base;
53
54                 s3c_gpio_lock(chip, flags);
55                 ret = s3c_gpio_do_getcfg(chip, offset);
56                 s3c_gpio_unlock(chip, flags);
57         }
58
59         return ret;
60 }
61 EXPORT_SYMBOL(s3c_gpio_getcfg);
62
63
64 int s3c_gpio_setpull(unsigned int pin, s3c_gpio_pull_t pull)
65 {
66         struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin);
67         unsigned long flags;
68         int offset, ret;
69
70         if (!chip)
71                 return -EINVAL;
72
73         offset = pin - chip->chip.base;
74
75         s3c_gpio_lock(chip, flags);
76         ret = s3c_gpio_do_setpull(chip, offset, pull);
77         s3c_gpio_unlock(chip, flags);
78
79         return ret;
80 }
81 EXPORT_SYMBOL(s3c_gpio_setpull);
82
83 #ifdef CONFIG_S3C_GPIO_CFG_S3C24XX
84 int s3c_gpio_setcfg_s3c24xx_a(struct s3c_gpio_chip *chip,
85                               unsigned int off, unsigned int cfg)
86 {
87         void __iomem *reg = chip->base;
88         unsigned int shift = off;
89         u32 con;
90
91         if (s3c_gpio_is_cfg_special(cfg)) {
92                 cfg &= 0xf;
93
94                 /* Map output to 0, and SFN2 to 1 */
95                 cfg -= 1;
96                 if (cfg > 1)
97                         return -EINVAL;
98
99                 cfg <<= shift;
100         }
101
102         con = __raw_readl(reg);
103         con &= ~(0x1 << shift);
104         con |= cfg;
105         __raw_writel(con, reg);
106
107         return 0;
108 }
109
110 unsigned s3c_gpio_getcfg_s3c24xx_a(struct s3c_gpio_chip *chip,
111                                    unsigned int off)
112 {
113         u32 con;
114
115         con = __raw_readl(chip->base);
116         con >>= off;
117         con &= 1;
118         con++;
119
120         return S3C_GPIO_SFN(con);
121 }
122
123 int s3c_gpio_setcfg_s3c24xx(struct s3c_gpio_chip *chip,
124                             unsigned int off, unsigned int cfg)
125 {
126         void __iomem *reg = chip->base;
127         unsigned int shift = off * 2;
128         u32 con;
129
130         if (s3c_gpio_is_cfg_special(cfg)) {
131                 cfg &= 0xf;
132                 if (cfg > 3)
133                         return -EINVAL;
134
135                 cfg <<= shift;
136         }
137
138         con = __raw_readl(reg);
139         con &= ~(0x3 << shift);
140         con |= cfg;
141         __raw_writel(con, reg);
142
143         return 0;
144 }
145
146 unsigned int s3c_gpio_getcfg_s3c24xx(struct s3c_gpio_chip *chip,
147                                      unsigned int off)
148 {
149         u32 con;
150
151         con = __raw_readl(chip->base);
152         con >>= off * 2;
153         con &= 3;
154
155         /* this conversion works for IN and OUT as well as special mode */
156         return S3C_GPIO_SPECIAL(con);
157 }
158 #endif
159
160 #ifdef CONFIG_S3C_GPIO_CFG_S3C64XX
161 int s3c_gpio_setcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip,
162                                  unsigned int off, unsigned int cfg)
163 {
164         void __iomem *reg = chip->base;
165         unsigned int shift = (off & 7) * 4;
166         u32 con;
167
168         if (off < 8 && chip->chip.ngpio > 8)
169                 reg -= 4;
170
171         if (s3c_gpio_is_cfg_special(cfg)) {
172                 cfg &= 0xf;
173                 cfg <<= shift;
174         }
175
176         con = __raw_readl(reg);
177         con &= ~(0xf << shift);
178         con |= cfg;
179         __raw_writel(con, reg);
180
181         return 0;
182 }
183
184 unsigned s3c_gpio_getcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip,
185                                       unsigned int off)
186 {
187         void __iomem *reg = chip->base;
188         unsigned int shift = (off & 7) * 4;
189         u32 con;
190
191         if (off < 8 && chip->chip.ngpio > 8)
192                 reg -= 4;
193
194         con = __raw_readl(reg);
195         con >>= shift;
196         con &= 0xf;
197
198         /* this conversion works for IN and OUT as well as special mode */
199         return S3C_GPIO_SPECIAL(con);
200 }
201
202 #endif /* CONFIG_S3C_GPIO_CFG_S3C64XX */
203
204 #ifdef CONFIG_S3C_GPIO_PULL_UPDOWN
205 int s3c_gpio_setpull_updown(struct s3c_gpio_chip *chip,
206                             unsigned int off, s3c_gpio_pull_t pull)
207 {
208         void __iomem *reg = chip->base + 0x08;
209         int shift = off * 2;
210         u32 pup;
211
212         pup = __raw_readl(reg);
213         pup &= ~(3 << shift);
214         pup |= pull << shift;
215         __raw_writel(pup, reg);
216
217         return 0;
218 }
219
220 s3c_gpio_pull_t s3c_gpio_getpull_updown(struct s3c_gpio_chip *chip,
221                                         unsigned int off)
222 {
223         void __iomem *reg = chip->base + 0x08;
224         int shift = off * 2;
225         u32 pup = __raw_readl(reg);
226
227         pup >>= shift;
228         pup &= 0x3;
229         return (__force s3c_gpio_pull_t)pup;
230 }
231 #endif
232
233 #ifdef CONFIG_S3C_GPIO_PULL_UP
234 int s3c_gpio_setpull_1up(struct s3c_gpio_chip *chip,
235                          unsigned int off, s3c_gpio_pull_t pull)
236 {
237         void __iomem *reg = chip->base + 0x08;
238         u32 pup = __raw_readl(reg);
239
240         pup = __raw_readl(reg);
241
242         if (pup == S3C_GPIO_PULL_UP)
243                 pup &= ~(1 << off);
244         else if (pup == S3C_GPIO_PULL_NONE)
245                 pup |= (1 << off);
246         else
247                 return -EINVAL;
248
249         __raw_writel(pup, reg);
250         return 0;
251 }
252
253 s3c_gpio_pull_t s3c_gpio_getpull_1up(struct s3c_gpio_chip *chip,
254                                      unsigned int off)
255 {
256         void __iomem *reg = chip->base + 0x08;
257         u32 pup = __raw_readl(reg);
258
259         pup &= (1 << off);
260         return pup ? S3C_GPIO_PULL_NONE : S3C_GPIO_PULL_UP;
261 }
262 #endif /* CONFIG_S3C_GPIO_PULL_UP */
263
264 #ifdef CONFIG_S5P_GPIO_DRVSTR
265 s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin)
266 {
267         struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin);
268         unsigned int off;
269         void __iomem *reg;
270         int shift;
271         u32 drvstr;
272
273         if (!chip)
274                 return -EINVAL;
275
276         off = chip->chip.base - pin;
277         shift = off * 2;
278         reg = chip->base + 0x0C;
279
280         drvstr = __raw_readl(reg);
281         drvstr = 0xffff & (0x3 << shift);
282         drvstr = drvstr >> shift;
283
284         return (__force s5p_gpio_drvstr_t)drvstr;
285 }
286 EXPORT_SYMBOL(s5p_gpio_get_drvstr);
287
288 int s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr)
289 {
290         struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin);
291         unsigned int off;
292         void __iomem *reg;
293         int shift;
294         u32 tmp;
295
296         if (!chip)
297                 return -EINVAL;
298
299         off = chip->chip.base - pin;
300         shift = off * 2;
301         reg = chip->base + 0x0C;
302
303         tmp = __raw_readl(reg);
304         tmp |= drvstr << shift;
305
306         __raw_writel(tmp, reg);
307
308         return 0;
309 }
310 EXPORT_SYMBOL(s5p_gpio_set_drvstr);
311 #endif  /* CONFIG_S5P_GPIO_DRVSTR */