Root/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
24int 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}
42EXPORT_SYMBOL(s3c_gpio_cfgpin);
43
44int s3c_gpio_cfgpin_range(unsigned int start, unsigned int nr,
45              unsigned int cfg)
46{
47    int ret;
48
49    for (; nr > 0; nr--, start++) {
50        ret = s3c_gpio_cfgpin(start, cfg);
51        if (ret != 0)
52            return ret;
53    }
54
55    return 0;
56}
57EXPORT_SYMBOL_GPL(s3c_gpio_cfgpin_range);
58
59int s3c_gpio_cfgall_range(unsigned int start, unsigned int nr,
60              unsigned int cfg, s3c_gpio_pull_t pull)
61{
62    int ret;
63
64    for (; nr > 0; nr--, start++) {
65        s3c_gpio_setpull(start, pull);
66        ret = s3c_gpio_cfgpin(start, cfg);
67        if (ret != 0)
68            return ret;
69    }
70
71    return 0;
72}
73EXPORT_SYMBOL_GPL(s3c_gpio_cfgall_range);
74
75unsigned s3c_gpio_getcfg(unsigned int pin)
76{
77    struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin);
78    unsigned long flags;
79    unsigned ret = 0;
80    int offset;
81
82    if (chip) {
83        offset = pin - chip->chip.base;
84
85        s3c_gpio_lock(chip, flags);
86        ret = s3c_gpio_do_getcfg(chip, offset);
87        s3c_gpio_unlock(chip, flags);
88    }
89
90    return ret;
91}
92EXPORT_SYMBOL(s3c_gpio_getcfg);
93
94
95int s3c_gpio_setpull(unsigned int pin, s3c_gpio_pull_t pull)
96{
97    struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin);
98    unsigned long flags;
99    int offset, ret;
100
101    if (!chip)
102        return -EINVAL;
103
104    offset = pin - chip->chip.base;
105
106    s3c_gpio_lock(chip, flags);
107    ret = s3c_gpio_do_setpull(chip, offset, pull);
108    s3c_gpio_unlock(chip, flags);
109
110    return ret;
111}
112EXPORT_SYMBOL(s3c_gpio_setpull);
113
114s3c_gpio_pull_t s3c_gpio_getpull(unsigned int pin)
115{
116    struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin);
117    unsigned long flags;
118    int offset;
119    u32 pup = 0;
120
121    if (chip) {
122        offset = pin - chip->chip.base;
123
124        s3c_gpio_lock(chip, flags);
125        pup = s3c_gpio_do_getpull(chip, offset);
126        s3c_gpio_unlock(chip, flags);
127    }
128
129    return (__force s3c_gpio_pull_t)pup;
130}
131EXPORT_SYMBOL(s3c_gpio_getpull);
132
133#ifdef CONFIG_S3C_GPIO_CFG_S3C24XX
134int s3c_gpio_setcfg_s3c24xx_a(struct s3c_gpio_chip *chip,
135                  unsigned int off, unsigned int cfg)
136{
137    void __iomem *reg = chip->base;
138    unsigned int shift = off;
139    u32 con;
140
141    if (s3c_gpio_is_cfg_special(cfg)) {
142        cfg &= 0xf;
143
144        /* Map output to 0, and SFN2 to 1 */
145        cfg -= 1;
146        if (cfg > 1)
147            return -EINVAL;
148
149        cfg <<= shift;
150    }
151
152    con = __raw_readl(reg);
153    con &= ~(0x1 << shift);
154    con |= cfg;
155    __raw_writel(con, reg);
156
157    return 0;
158}
159
160unsigned s3c_gpio_getcfg_s3c24xx_a(struct s3c_gpio_chip *chip,
161                   unsigned int off)
162{
163    u32 con;
164
165    con = __raw_readl(chip->base);
166    con >>= off;
167    con &= 1;
168    con++;
169
170    return S3C_GPIO_SFN(con);
171}
172
173int s3c_gpio_setcfg_s3c24xx(struct s3c_gpio_chip *chip,
174                unsigned int off, unsigned int cfg)
175{
176    void __iomem *reg = chip->base;
177    unsigned int shift = off * 2;
178    u32 con;
179
180    if (s3c_gpio_is_cfg_special(cfg)) {
181        cfg &= 0xf;
182        if (cfg > 3)
183            return -EINVAL;
184
185        cfg <<= shift;
186    }
187
188    con = __raw_readl(reg);
189    con &= ~(0x3 << shift);
190    con |= cfg;
191    __raw_writel(con, reg);
192
193    return 0;
194}
195
196unsigned int s3c_gpio_getcfg_s3c24xx(struct s3c_gpio_chip *chip,
197                     unsigned int off)
198{
199    u32 con;
200
201    con = __raw_readl(chip->base);
202    con >>= off * 2;
203    con &= 3;
204
205    /* this conversion works for IN and OUT as well as special mode */
206    return S3C_GPIO_SPECIAL(con);
207}
208#endif
209
210#ifdef CONFIG_S3C_GPIO_CFG_S3C64XX
211int s3c_gpio_setcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip,
212                 unsigned int off, unsigned int cfg)
213{
214    void __iomem *reg = chip->base;
215    unsigned int shift = (off & 7) * 4;
216    u32 con;
217
218    if (off < 8 && chip->chip.ngpio > 8)
219        reg -= 4;
220
221    if (s3c_gpio_is_cfg_special(cfg)) {
222        cfg &= 0xf;
223        cfg <<= shift;
224    }
225
226    con = __raw_readl(reg);
227    con &= ~(0xf << shift);
228    con |= cfg;
229    __raw_writel(con, reg);
230
231    return 0;
232}
233
234unsigned s3c_gpio_getcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip,
235                      unsigned int off)
236{
237    void __iomem *reg = chip->base;
238    unsigned int shift = (off & 7) * 4;
239    u32 con;
240
241    if (off < 8 && chip->chip.ngpio > 8)
242        reg -= 4;
243
244    con = __raw_readl(reg);
245    con >>= shift;
246    con &= 0xf;
247
248    /* this conversion works for IN and OUT as well as special mode */
249    return S3C_GPIO_SPECIAL(con);
250}
251
252#endif /* CONFIG_S3C_GPIO_CFG_S3C64XX */
253
254#ifdef CONFIG_S3C_GPIO_PULL_UPDOWN
255int s3c_gpio_setpull_updown(struct s3c_gpio_chip *chip,
256                unsigned int off, s3c_gpio_pull_t pull)
257{
258    void __iomem *reg = chip->base + 0x08;
259    int shift = off * 2;
260    u32 pup;
261
262    pup = __raw_readl(reg);
263    pup &= ~(3 << shift);
264    pup |= pull << shift;
265    __raw_writel(pup, reg);
266
267    return 0;
268}
269
270s3c_gpio_pull_t s3c_gpio_getpull_updown(struct s3c_gpio_chip *chip,
271                    unsigned int off)
272{
273    void __iomem *reg = chip->base + 0x08;
274    int shift = off * 2;
275    u32 pup = __raw_readl(reg);
276
277    pup >>= shift;
278    pup &= 0x3;
279    return (__force s3c_gpio_pull_t)pup;
280}
281#endif
282
283#if defined(CONFIG_S3C_GPIO_PULL_UP) || defined(CONFIG_S3C_GPIO_PULL_DOWN)
284static int s3c_gpio_setpull_1(struct s3c_gpio_chip *chip,
285             unsigned int off, s3c_gpio_pull_t pull,
286             s3c_gpio_pull_t updown)
287{
288    void __iomem *reg = chip->base + 0x08;
289    u32 pup = __raw_readl(reg);
290
291    if (pull == updown)
292        pup &= ~(1 << off);
293    else if (pull == S3C_GPIO_PULL_NONE)
294        pup |= (1 << off);
295    else
296        return -EINVAL;
297
298    __raw_writel(pup, reg);
299    return 0;
300}
301
302static s3c_gpio_pull_t s3c_gpio_getpull_1(struct s3c_gpio_chip *chip,
303                     unsigned int off, s3c_gpio_pull_t updown)
304{
305    void __iomem *reg = chip->base + 0x08;
306    u32 pup = __raw_readl(reg);
307
308    pup &= (1 << off);
309    return pup ? S3C_GPIO_PULL_NONE : updown;
310}
311#endif /* CONFIG_S3C_GPIO_PULL_UP || CONFIG_S3C_GPIO_PULL_DOWN */
312
313#ifdef CONFIG_S3C_GPIO_PULL_UP
314s3c_gpio_pull_t s3c_gpio_getpull_1up(struct s3c_gpio_chip *chip,
315                     unsigned int off)
316{
317    return s3c_gpio_getpull_1(chip, off, S3C_GPIO_PULL_UP);
318}
319
320int s3c_gpio_setpull_1up(struct s3c_gpio_chip *chip,
321             unsigned int off, s3c_gpio_pull_t pull)
322{
323    return s3c_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_UP);
324}
325#endif /* CONFIG_S3C_GPIO_PULL_UP */
326
327#ifdef CONFIG_S3C_GPIO_PULL_DOWN
328s3c_gpio_pull_t s3c_gpio_getpull_1down(struct s3c_gpio_chip *chip,
329                     unsigned int off)
330{
331    return s3c_gpio_getpull_1(chip, off, S3C_GPIO_PULL_DOWN);
332}
333
334int s3c_gpio_setpull_1down(struct s3c_gpio_chip *chip,
335             unsigned int off, s3c_gpio_pull_t pull)
336{
337    return s3c_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_DOWN);
338}
339#endif /* CONFIG_S3C_GPIO_PULL_DOWN */
340
341#ifdef CONFIG_S5P_GPIO_DRVSTR
342s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin)
343{
344    struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin);
345    unsigned int off;
346    void __iomem *reg;
347    int shift;
348    u32 drvstr;
349
350    if (!chip)
351        return -EINVAL;
352
353    off = pin - chip->chip.base;
354    shift = off * 2;
355    reg = chip->base + 0x0C;
356
357    drvstr = __raw_readl(reg);
358    drvstr = drvstr >> shift;
359    drvstr &= 0x3;
360
361    return (__force s5p_gpio_drvstr_t)drvstr;
362}
363EXPORT_SYMBOL(s5p_gpio_get_drvstr);
364
365int s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr)
366{
367    struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin);
368    unsigned int off;
369    void __iomem *reg;
370    int shift;
371    u32 tmp;
372
373    if (!chip)
374        return -EINVAL;
375
376    off = pin - chip->chip.base;
377    shift = off * 2;
378    reg = chip->base + 0x0C;
379
380    tmp = __raw_readl(reg);
381    tmp &= ~(0x3 << shift);
382    tmp |= drvstr << shift;
383
384    __raw_writel(tmp, reg);
385
386    return 0;
387}
388EXPORT_SYMBOL(s5p_gpio_set_drvstr);
389#endif /* CONFIG_S5P_GPIO_DRVSTR */
390

Archive Download this file



interactive