[pxa] refresh 2.6.21 patches
[openwrt/svn-archive/archive.git] / target / linux / pxa / patches-2.6.21 / 011-proc-gpio.patch
1 --- a/arch/arm/Kconfig
2 +++ b/arch/arm/Kconfig
3 @@ -505,6 +505,8 @@ config PCI_HOST_VIA82C505
4 depends on PCI && ARCH_SHARK
5 default y
6
7 +source "drivers/gpio/Kconfig"
8 +
9 source "drivers/pci/Kconfig"
10
11 source "drivers/pcmcia/Kconfig"
12 --- a/drivers/Makefile
13 +++ b/drivers/Makefile
14 @@ -81,3 +81,4 @@ obj-$(CONFIG_GENERIC_TIME) += clocksourc
15 obj-$(CONFIG_DMA_ENGINE) += dma/
16 obj-$(CONFIG_HID) += hid/
17 obj-$(CONFIG_PPC_PS3) += ps3/
18 +obj-$(CONFIG_PROC_GPIO) += gpio/
19 --- /dev/null
20 +++ b/drivers/gpio/Kconfig
21 @@ -0,0 +1,13 @@
22 +config PROC_GPIO
23 + tristate "GPIO /proc interface"
24 + depends on PXA25x || PXA27x
25 + help
26 + This enables an interface under /proc/gpio which allows reading or setting
27 + of any GPIO, and also changing the GPIO alt function mode of any line.
28 +
29 +config PROC_GPIO_DEBUG
30 + boolean "Enable /proc/gpio debug logging"
31 + depends on PROC_GPIO
32 + help
33 + This enables printk logging of activity done through /proc/gpio
34 +
35 --- /dev/null
36 +++ b/drivers/gpio/Makefile
37 @@ -0,0 +1,2 @@
38 +# Expose GPIOs under /proc
39 +obj-$(CONFIG_PROC_GPIO) += proc_gpio.o
40 --- /dev/null
41 +++ b/drivers/gpio/proc_gpio.c
42 @@ -0,0 +1,276 @@
43 +/*
44 + *
45 + * PXA25x GPIOs exposed under /proc for reading and writing
46 + * They will show up under /proc/gpio/NN
47 + *
48 + * Based on patch 1773/1 in the arm kernel patch repository at arm.linux.co.uk
49 + *
50 + */
51 +
52 +#include <linux/module.h>
53 +#include <linux/init.h>
54 +#include <linux/proc_fs.h>
55 +#include <linux/string.h>
56 +#include <linux/ctype.h>
57 +
58 +#include <asm/hardware.h>
59 +#include <asm/arch/pxa-regs.h>
60 +#include <asm/uaccess.h>
61 +
62 +static struct proc_dir_entry *proc_gpio_parent;
63 +static struct proc_dir_entry *proc_gpios[PXA_LAST_GPIO + 1];
64 +
65 +typedef struct
66 +{
67 + int gpio;
68 + char name[32];
69 +} gpio_summary_type;
70 +
71 +static gpio_summary_type gpio_summaries[PXA_LAST_GPIO + 1];
72 +
73 +static int proc_gpio_write(struct file *file, const char __user *buf,
74 + unsigned long count, void *data)
75 +{
76 + char *cur, lbuf[count + 1];
77 + gpio_summary_type *summary = data;
78 + u32 altfn, direction, setclear, gafr;
79 +
80 + if (!capable(CAP_SYS_ADMIN))
81 + return -EACCES;
82 +
83 + memset(lbuf, 0, count + 1);
84 +
85 + if (copy_from_user(lbuf, buf, count))
86 + return -EFAULT;
87 +
88 + cur = lbuf;
89 +
90 + // Initialize to current state
91 + altfn = ((GAFR(summary->gpio) >> ((summary->gpio & 0x0f) << 0x01)) & 0x03);
92 + direction = GPDR(summary->gpio) & GPIO_bit(summary->gpio);
93 + setclear = GPLR(summary->gpio) & GPIO_bit(summary->gpio);
94 + while(1)
95 + {
96 + // We accept options: {GPIO|AF1|AF2|AF3}, {set|clear}, {in|out}
97 + // Anything else is an error
98 + while(cur[0] && (isspace(cur[0]) || ispunct(cur[0]))) cur = &(cur[1]);
99 +
100 + if('\0' == cur[0]) break;
101 +
102 + // Ok, so now we're pointing at the start of something
103 + switch(cur[0])
104 + {
105 + case 'G':
106 + // Check that next is "PIO" -- '\0' will cause safe short-circuit if end of buf
107 + if(!(cur[1] == 'P' && cur[2] == 'I' && cur[3] == 'O')) goto parse_error;
108 + // Ok, so set this GPIO to GPIO (non-ALT) function
109 + altfn = 0;
110 + cur = &(cur[4]);
111 + break;
112 + case 'A':
113 + if(!(cur[1] == 'F' && cur[2] >= '1' && cur[2] <= '3')) goto parse_error;
114 + altfn = cur[2] - '0';
115 + cur = &(cur[3]);
116 + break;
117 + case 's':
118 + if(!(cur[1] == 'e' && cur[2] == 't')) goto parse_error;
119 + setclear = 1;
120 + cur = &(cur[3]);
121 + break;
122 + case 'c':
123 + if(!(cur[1] == 'l' && cur[2] == 'e' && cur[3] == 'a' && cur[4] == 'r')) goto parse_error;
124 + setclear = 0;
125 + cur = &(cur[5]);
126 + break;
127 + case 'i':
128 + if(!(cur[1] == 'n')) goto parse_error;
129 + direction = 0;
130 + cur = &(cur[2]);
131 + break;
132 + case 'o':
133 + if(!(cur[1] == 'u' && cur[2] == 't')) goto parse_error;
134 + direction = 1;
135 + cur = &(cur[3]);
136 + break;
137 + default: goto parse_error;
138 + }
139 + }
140 + // Ok, now set gpio mode and value
141 + if(direction)
142 + GPDR(summary->gpio) |= GPIO_bit(summary->gpio);
143 + else
144 + GPDR(summary->gpio) &= ~GPIO_bit(summary->gpio);
145 +
146 + gafr = GAFR(summary->gpio) & ~(0x3 << (((summary->gpio) & 0xf)*2));
147 + GAFR(summary->gpio) = gafr | (altfn << (((summary->gpio) & 0xf)*2));
148 +
149 + if(direction && !altfn)
150 + {
151 + if(setclear) GPSR(summary->gpio) = GPIO_bit(summary->gpio);
152 + else GPCR(summary->gpio) = GPIO_bit(summary->gpio);
153 + }
154 +
155 +#ifdef CONFIG_PROC_GPIO_DEBUG
156 + printk(KERN_INFO "Set (%s,%s,%s) via /proc/gpio/%s\n",altfn ? (altfn == 1 ? "AF1" : (altfn == 2 ? "AF2" : "AF3")) : "GPIO",
157 + direction ? "out" : "in",
158 + setclear ? "set" : "clear",
159 + summary->name);
160 +#endif
161 +
162 + return count;
163 +
164 +parse_error:
165 + printk(KERN_CRIT "Parse error: Expect \"[GPIO|AF1|AF2|AF3]|[set|clear]|[in|out] ...\"\n");
166 + return -EINVAL;
167 +}
168 +
169 +static int proc_gpio_read(char *page, char **start, off_t off,
170 + int count, int *eof, void *data)
171 +{
172 + char *p = page;
173 + gpio_summary_type *summary = data;
174 + int len, i, af;
175 + i = summary->gpio;
176 +
177 + p += sprintf(p, "%d\t%s\t%s\t%s\n", i,
178 + (af = ((GAFR(i) >> ((i & 0x0f) << 0x01)) & 0x03)) ? (af == 1 ? "AF1" : (af == 2 ? "AF2" : "AF3")) : "GPIO",
179 + (GPDR(i) & GPIO_bit(i)) ? "out" : "in",
180 + (GPLR(i) & GPIO_bit(i)) ? "set" : "clear");
181 +
182 + len = (p - page) - off;
183 +
184 + if(len < 0)
185 + {
186 + len = 0;
187 + }
188 +
189 + *eof = (len <= count) ? 1 : 0;
190 + *start = page + off;
191 +
192 + return len;
193 +}
194 +
195 +
196 +#ifdef CONFIG_PXA25x
197 +static const char const *GAFR_DESC[] = { "GAFR0_L", "GAFR0_U", "GAFR1_L", "GAFR1_U", "GAFR2_L", "GAFR2_U" };
198 +#elif defined(CONFIG_PXA27x)
199 +static const char const *GAFR_DESC[] = { "GAFR0_L", "GAFR0_U", "GAFR1_L", "GAFR1_U", "GAFR2_L", "GAFR2_U", "GAFR3_L", "GAFR3_U" };
200 +#endif
201 +
202 +static int proc_gafr_read(char *page, char **start, off_t off,
203 + int count, int *eof, void *data)
204 +{
205 + char *p = page;
206 + int i, len;
207 +
208 + for(i=0; i<ARRAY_SIZE(GAFR_DESC); i++)
209 + {
210 + p += sprintf(p, "%s: %08x\n", GAFR_DESC[i], GAFR(i*16));
211 + }
212 +
213 + len = (p - page) - off;
214 +
215 + if(len < 0)
216 + {
217 + len = 0;
218 + }
219 +
220 + *eof = (len <= count) ? 1 : 0;
221 + *start = page + off;
222 +
223 + return len;
224 +}
225 +
226 +static int proc_gpdr_read(char *page, char **start, off_t off,
227 + int count, int *eof, void *data)
228 +{
229 + char *p = page;
230 + int i, len;
231 +
232 + for(i=0; i<=2; i++)
233 + {
234 + p += sprintf(p, "GPDR%d: %08x\n", i, GPDR(i * 32));
235 + }
236 +
237 + len = (p - page) - off;
238 +
239 + if(len < 0)
240 + {
241 + len = 0;
242 + }
243 +
244 + *eof = (len <= count) ? 1 : 0;
245 + *start = page + off;
246 +
247 + return len;
248 +}
249 +
250 +static int proc_gplr_read(char *page, char **start, off_t off,
251 + int count, int *eof, void *data)
252 +{
253 + char *p = page;
254 + int i, len;
255 +
256 + for(i=0; i<=2; i++)
257 + {
258 + p += sprintf(p, "GPLR%d: %08x\n", i, GPLR(i * 32));
259 + }
260 +
261 + len = (p - page) - off;
262 +
263 + if(len < 0)
264 + {
265 + len = 0;
266 + }
267 +
268 + *eof = (len <= count) ? 1 : 0;
269 + *start = page + off;
270 +
271 + return len;
272 +}
273 +
274 +static int __init gpio_init(void)
275 +{
276 + int i;
277 +
278 + proc_gpio_parent = create_proc_entry("gpio", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
279 + if(!proc_gpio_parent) return 0;
280 +
281 + for(i=0; i < (PXA_LAST_GPIO+1); i++)
282 + {
283 + gpio_summaries[i].gpio = i;
284 + sprintf(gpio_summaries[i].name, "GPIO%d", i);
285 + proc_gpios[i] = create_proc_entry(gpio_summaries[i].name, 0644, proc_gpio_parent);
286 + if(proc_gpios[i])
287 + {
288 + proc_gpios[i]->data = &gpio_summaries[i];
289 + proc_gpios[i]->read_proc = proc_gpio_read;
290 + proc_gpios[i]->write_proc = proc_gpio_write;
291 + }
292 + }
293 +
294 + create_proc_read_entry("GAFR", 0444, proc_gpio_parent, proc_gafr_read, NULL);
295 + create_proc_read_entry("GPDR", 0444, proc_gpio_parent, proc_gpdr_read, NULL);
296 + create_proc_read_entry("GPLR", 0444, proc_gpio_parent, proc_gplr_read, NULL);
297 +
298 + return 0;
299 +}
300 +
301 +static void gpio_exit(void)
302 +{
303 + int i;
304 +
305 + remove_proc_entry("GAFR", proc_gpio_parent);
306 + remove_proc_entry("GPDR", proc_gpio_parent);
307 + remove_proc_entry("GPLR", proc_gpio_parent);
308 +
309 + for(i=0; i < (PXA_LAST_GPIO+1); i++)
310 + {
311 + if(proc_gpios[i]) remove_proc_entry(gpio_summaries[i].name, proc_gpio_parent);
312 + }
313 + if(proc_gpio_parent) remove_proc_entry("gpio", NULL);
314 +}
315 +
316 +module_init(gpio_init);
317 +module_exit(gpio_exit);
318 +MODULE_LICENSE("GPL");