[POWERPC] 85xx: Add support for Wind River SBC8560 in arch/powerpc
[linux-2.6] / arch / arm / mach-ks8695 / gpio.c
1 /*
2  * arch/arm/mach-ks8695/gpio.c
3  *
4  * Copyright (C) 2006 Andrew Victor
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include <linux/kernel.h>
21 #include <linux/mm.h>
22 #include <linux/init.h>
23 #include <linux/module.h>
24
25 #include <asm/io.h>
26 #include <asm/hardware.h>
27 #include <asm/mach/irq.h>
28
29 #include <asm/arch/regs-gpio.h>
30 #include <asm/arch/gpio.h>
31
32 /*
33  * Configure a GPIO line for either GPIO function, or its internal
34  * function (Interrupt, Timer, etc).
35  */
36 static void __init_or_module ks8695_gpio_mode(unsigned int pin, short gpio)
37 {
38         unsigned int enable[] = { IOPC_IOEINT0EN, IOPC_IOEINT1EN, IOPC_IOEINT2EN, IOPC_IOEINT3EN, IOPC_IOTIM0EN, IOPC_IOTIM1EN };
39         unsigned long x, flags;
40
41         if (pin > KS8695_GPIO_5)        /* only GPIO 0..5 have internal functions */
42                 return;
43
44         local_irq_save(flags);
45
46         x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC);
47         if (gpio)                       /* GPIO: set bit to 0 */
48                 x &= ~enable[pin];
49         else                            /* Internal function: set bit to 1 */
50                 x |= enable[pin];
51         __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPC);
52
53         local_irq_restore(flags);
54 }
55
56
57 static unsigned short gpio_irq[] = { KS8695_IRQ_EXTERN0, KS8695_IRQ_EXTERN1, KS8695_IRQ_EXTERN2, KS8695_IRQ_EXTERN3 };
58
59 /*
60  * Configure GPIO pin as external interrupt source.
61  */
62 int __init_or_module ks8695_gpio_interrupt(unsigned int pin, unsigned int type)
63 {
64         unsigned long x, flags;
65
66         if (pin > KS8695_GPIO_3)        /* only GPIO 0..3 can generate IRQ */
67                 return -EINVAL;
68
69         local_irq_save(flags);
70
71         /* set pin as input */
72         x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
73         x &= ~IOPM_(pin);
74         __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
75
76         local_irq_restore(flags);
77
78         /* Set IRQ triggering type */
79         set_irq_type(gpio_irq[pin], type);
80
81         /* enable interrupt mode */
82         ks8695_gpio_mode(pin, 0);
83
84         return 0;
85 }
86 EXPORT_SYMBOL(ks8695_gpio_interrupt);
87
88
89
90 /* .... Generic GPIO interface .............................................. */
91
92 /*
93  * Configure the GPIO line as an input.
94  */
95 int __init_or_module gpio_direction_input(unsigned int pin)
96 {
97         unsigned long x, flags;
98
99         if (pin > KS8695_GPIO_15)
100                 return -EINVAL;
101
102         /* set pin to GPIO mode */
103         ks8695_gpio_mode(pin, 1);
104
105         local_irq_save(flags);
106
107         /* set pin as input */
108         x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
109         x &= ~IOPM_(pin);
110         __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
111
112         local_irq_restore(flags);
113
114         return 0;
115 }
116 EXPORT_SYMBOL(gpio_direction_input);
117
118
119 /*
120  * Configure the GPIO line as an output, with default state.
121  */
122 int __init_or_module gpio_direction_output(unsigned int pin, unsigned int state)
123 {
124         unsigned long x, flags;
125
126         if (pin > KS8695_GPIO_15)
127                 return -EINVAL;
128
129         /* set pin to GPIO mode */
130         ks8695_gpio_mode(pin, 1);
131
132         local_irq_save(flags);
133
134         /* set line state */
135         x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
136         if (state)
137                 x |= (1 << pin);
138         else
139                 x &= ~(1 << pin);
140         __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD);
141
142         /* set pin as output */
143         x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
144         x |= IOPM_(pin);
145         __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
146
147         local_irq_restore(flags);
148
149         return 0;
150 }
151 EXPORT_SYMBOL(gpio_direction_output);
152
153
154 /*
155  * Set the state of an output GPIO line.
156  */
157 void gpio_set_value(unsigned int pin, unsigned int state)
158 {
159         unsigned long x, flags;
160
161         if (pin > KS8695_GPIO_15)
162                 return;
163
164         local_irq_save(flags);
165
166         /* set output line state */
167         x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
168         if (state)
169                 x |= (1 << pin);
170         else
171                 x &= ~(1 << pin);
172         __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD);
173
174         local_irq_restore(flags);
175 }
176 EXPORT_SYMBOL(gpio_set_value);
177
178
179 /*
180  * Read the state of a GPIO line.
181  */
182 int gpio_get_value(unsigned int pin)
183 {
184         unsigned long x;
185
186         if (pin > KS8695_GPIO_15)
187                 return -EINVAL;
188
189         x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
190         return (x & (1 << pin)) != 0;
191 }
192 EXPORT_SYMBOL(gpio_get_value);
193
194
195 /*
196  * Map GPIO line to IRQ number.
197  */
198 int gpio_to_irq(unsigned int pin)
199 {
200         if (pin > KS8695_GPIO_3)        /* only GPIO 0..3 can generate IRQ */
201                 return -EINVAL;
202
203         return gpio_irq[pin];
204 }
205 EXPORT_SYMBOL(gpio_to_irq);
206
207
208 /*
209  * Map IRQ number to GPIO line.
210  */
211 int irq_to_gpio(unsigned int irq)
212 {
213         if ((irq < KS8695_IRQ_EXTERN0) || (irq > KS8695_IRQ_EXTERN3))
214                 return -EINVAL;
215
216         return (irq - KS8695_IRQ_EXTERN0);
217 }
218 EXPORT_SYMBOL(irq_to_gpio);