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