Pull misc-2.6.39 into release branch
[pandora-kernel.git] / arch / mips / ath79 / gpio.c
1 /*
2  *  Atheros AR71XX/AR724X/AR913X GPIO API support
3  *
4  *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
5  *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
6  *
7  *  This program is free software; you can redistribute it and/or modify it
8  *  under the terms of the GNU General Public License version 2 as published
9  *  by the Free Software Foundation.
10  */
11
12 #include <linux/kernel.h>
13 #include <linux/init.h>
14 #include <linux/module.h>
15 #include <linux/types.h>
16 #include <linux/spinlock.h>
17 #include <linux/io.h>
18 #include <linux/ioport.h>
19 #include <linux/gpio.h>
20
21 #include <asm/mach-ath79/ar71xx_regs.h>
22 #include <asm/mach-ath79/ath79.h>
23 #include "common.h"
24
25 static void __iomem *ath79_gpio_base;
26 static unsigned long ath79_gpio_count;
27 static DEFINE_SPINLOCK(ath79_gpio_lock);
28
29 static void __ath79_gpio_set_value(unsigned gpio, int value)
30 {
31         void __iomem *base = ath79_gpio_base;
32
33         if (value)
34                 __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_SET);
35         else
36                 __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_CLEAR);
37 }
38
39 static int __ath79_gpio_get_value(unsigned gpio)
40 {
41         return (__raw_readl(ath79_gpio_base + AR71XX_GPIO_REG_IN) >> gpio) & 1;
42 }
43
44 static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned offset)
45 {
46         return __ath79_gpio_get_value(offset);
47 }
48
49 static void ath79_gpio_set_value(struct gpio_chip *chip,
50                                   unsigned offset, int value)
51 {
52         __ath79_gpio_set_value(offset, value);
53 }
54
55 static int ath79_gpio_direction_input(struct gpio_chip *chip,
56                                        unsigned offset)
57 {
58         void __iomem *base = ath79_gpio_base;
59         unsigned long flags;
60
61         spin_lock_irqsave(&ath79_gpio_lock, flags);
62
63         __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset),
64                      base + AR71XX_GPIO_REG_OE);
65
66         spin_unlock_irqrestore(&ath79_gpio_lock, flags);
67
68         return 0;
69 }
70
71 static int ath79_gpio_direction_output(struct gpio_chip *chip,
72                                         unsigned offset, int value)
73 {
74         void __iomem *base = ath79_gpio_base;
75         unsigned long flags;
76
77         spin_lock_irqsave(&ath79_gpio_lock, flags);
78
79         if (value)
80                 __raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET);
81         else
82                 __raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR);
83
84         __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset),
85                      base + AR71XX_GPIO_REG_OE);
86
87         spin_unlock_irqrestore(&ath79_gpio_lock, flags);
88
89         return 0;
90 }
91
92 static struct gpio_chip ath79_gpio_chip = {
93         .label                  = "ath79",
94         .get                    = ath79_gpio_get_value,
95         .set                    = ath79_gpio_set_value,
96         .direction_input        = ath79_gpio_direction_input,
97         .direction_output       = ath79_gpio_direction_output,
98         .base                   = 0,
99 };
100
101 void ath79_gpio_function_enable(u32 mask)
102 {
103         void __iomem *base = ath79_gpio_base;
104         unsigned long flags;
105
106         spin_lock_irqsave(&ath79_gpio_lock, flags);
107
108         __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_FUNC) | mask,
109                      base + AR71XX_GPIO_REG_FUNC);
110         /* flush write */
111         __raw_readl(base + AR71XX_GPIO_REG_FUNC);
112
113         spin_unlock_irqrestore(&ath79_gpio_lock, flags);
114 }
115
116 void ath79_gpio_function_disable(u32 mask)
117 {
118         void __iomem *base = ath79_gpio_base;
119         unsigned long flags;
120
121         spin_lock_irqsave(&ath79_gpio_lock, flags);
122
123         __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_FUNC) & ~mask,
124                      base + AR71XX_GPIO_REG_FUNC);
125         /* flush write */
126         __raw_readl(base + AR71XX_GPIO_REG_FUNC);
127
128         spin_unlock_irqrestore(&ath79_gpio_lock, flags);
129 }
130
131 void ath79_gpio_function_setup(u32 set, u32 clear)
132 {
133         void __iomem *base = ath79_gpio_base;
134         unsigned long flags;
135
136         spin_lock_irqsave(&ath79_gpio_lock, flags);
137
138         __raw_writel((__raw_readl(base + AR71XX_GPIO_REG_FUNC) & ~clear) | set,
139                      base + AR71XX_GPIO_REG_FUNC);
140         /* flush write */
141         __raw_readl(base + AR71XX_GPIO_REG_FUNC);
142
143         spin_unlock_irqrestore(&ath79_gpio_lock, flags);
144 }
145
146 void __init ath79_gpio_init(void)
147 {
148         int err;
149
150         if (soc_is_ar71xx())
151                 ath79_gpio_count = AR71XX_GPIO_COUNT;
152         else if (soc_is_ar724x())
153                 ath79_gpio_count = AR724X_GPIO_COUNT;
154         else if (soc_is_ar913x())
155                 ath79_gpio_count = AR913X_GPIO_COUNT;
156         else
157                 BUG();
158
159         ath79_gpio_base = ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE);
160         ath79_gpio_chip.ngpio = ath79_gpio_count;
161
162         err = gpiochip_add(&ath79_gpio_chip);
163         if (err)
164                 panic("cannot add AR71xx GPIO chip, error=%d", err);
165 }
166
167 int gpio_get_value(unsigned gpio)
168 {
169         if (gpio < ath79_gpio_count)
170                 return __ath79_gpio_get_value(gpio);
171
172         return __gpio_get_value(gpio);
173 }
174 EXPORT_SYMBOL(gpio_get_value);
175
176 void gpio_set_value(unsigned gpio, int value)
177 {
178         if (gpio < ath79_gpio_count)
179                 __ath79_gpio_set_value(gpio, value);
180         else
181                 __gpio_set_value(gpio, value);
182 }
183 EXPORT_SYMBOL(gpio_set_value);
184
185 int gpio_to_irq(unsigned gpio)
186 {
187         /* FIXME */
188         return -EINVAL;
189 }
190 EXPORT_SYMBOL(gpio_to_irq);
191
192 int irq_to_gpio(unsigned irq)
193 {
194         /* FIXME */
195         return -EINVAL;
196 }
197 EXPORT_SYMBOL(irq_to_gpio);