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