[ARM] pxa: update defconfig for Verdex Pro
[linux-2.6/verdex.git] / drivers / gpio / proc_gpio.c
blobefeb95760ce5abcbe4b73d95b7ba3cccc68f2701
1 /*
3 * PXA25x GPIOs exposed under /proc for reading and writing
4 * They will show up under /proc/gpio/NN
6 * Based on patch 1773/1 in the arm kernel patch repository at arm.linux.co.uk
8 */
10 #include <linux/module.h>
11 #include <linux/init.h>
12 #include <linux/proc_fs.h>
13 #include <linux/string.h>
14 #include <linux/ctype.h>
16 #include <mach/hardware.h>
17 #include <mach/gpio.h>
18 #include <asm/uaccess.h>
20 extern struct proc_dir_entry proc_root;
22 extern int pxa_last_gpio;
24 static struct proc_dir_entry *proc_gpio_parent;
25 static struct proc_dir_entry **proc_gpios;
27 typedef struct
29 int gpio;
30 char name[32];
31 } gpio_summary_type;
33 static gpio_summary_type *gpio_summaries;
35 static int proc_gpio_write(struct file *file, const char __user *buf,
36 unsigned long count, void *data)
38 char *cur, lbuf[count + 1];
39 gpio_summary_type *summary = data;
40 u32 altfn, direction, setclear, gafr;
42 if (!capable(CAP_SYS_ADMIN))
43 return -EACCES;
45 memset(lbuf, 0, count + 1);
47 if (copy_from_user(lbuf, buf, count))
48 return -EFAULT;
50 cur = lbuf;
52 // Initialize to current state
53 altfn = ((GAFR(summary->gpio) >> ((summary->gpio & 0x0f) << 0x01)) & 0x03);
54 direction = GPDR(summary->gpio) & GPIO_bit(summary->gpio);
55 setclear = GPLR(summary->gpio) & GPIO_bit(summary->gpio);
56 while(1)
58 // We accept options: {GPIO|AF1|AF2|AF3}, {set|clear}, {in|out}
59 // Anything else is an error
60 while(cur[0] && (isspace(cur[0]) || ispunct(cur[0]))) cur = &(cur[1]);
62 if('\0' == cur[0]) break;
64 // Ok, so now we're pointing at the start of something
65 switch(cur[0])
67 case 'G':
68 // Check that next is "PIO" -- '\0' will cause safe short-circuit if end of buf
69 if(!(cur[1] == 'P' && cur[2] == 'I' && cur[3] == 'O')) goto parse_error;
70 // Ok, so set this GPIO to GPIO (non-ALT) function
71 altfn = 0;
72 cur = &(cur[4]);
73 break;
74 case 'A':
75 if(!(cur[1] == 'F' && cur[2] >= '1' && cur[2] <= '3')) goto parse_error;
76 altfn = cur[2] - '0';
77 cur = &(cur[3]);
78 break;
79 case 's':
80 if(!(cur[1] == 'e' && cur[2] == 't')) goto parse_error;
81 setclear = 1;
82 cur = &(cur[3]);
83 break;
84 case 'c':
85 if(!(cur[1] == 'l' && cur[2] == 'e' && cur[3] == 'a' && cur[4] == 'r')) goto parse_error;
86 setclear = 0;
87 cur = &(cur[5]);
88 break;
89 case 'i':
90 if(!(cur[1] == 'n')) goto parse_error;
91 direction = 0;
92 cur = &(cur[2]);
93 break;
94 case 'o':
95 if(!(cur[1] == 'u' && cur[2] == 't')) goto parse_error;
96 direction = 1;
97 cur = &(cur[3]);
98 break;
99 default: goto parse_error;
102 // Ok, now set gpio mode and value
103 if(direction)
104 GPDR(summary->gpio) |= GPIO_bit(summary->gpio);
105 else
106 GPDR(summary->gpio) &= ~GPIO_bit(summary->gpio);
108 gafr = GAFR(summary->gpio) & ~(0x3 << (((summary->gpio) & 0xf)*2));
109 GAFR(summary->gpio) = gafr | (altfn << (((summary->gpio) & 0xf)*2));
111 if(direction && !altfn)
113 if(setclear) GPSR(summary->gpio) = GPIO_bit(summary->gpio);
114 else GPCR(summary->gpio) = GPIO_bit(summary->gpio);
117 #ifdef CONFIG_PROC_GPIO_DEBUG
118 printk(KERN_INFO "Set (%s,%s,%s) via /proc/gpio/%s\n",altfn ? (altfn == 1 ? "AF1" : (altfn == 2 ? "AF2" : "AF3")) : "GPIO",
119 direction ? "out" : "in",
120 setclear ? "set" : "clear",
121 summary->name);
122 #endif
124 return count;
126 parse_error:
127 printk(KERN_CRIT "Parse error: Expect \"[GPIO|AF1|AF2|AF3]|[set|clear]|[in|out] ...\"\n");
128 return -EINVAL;
131 static int proc_gpio_read(char *page, char **start, off_t off,
132 int count, int *eof, void *data)
134 char *p = page;
135 gpio_summary_type *summary = data;
136 int len, i, af;
137 i = summary->gpio;
139 p += sprintf(p, "%d\t%s\t%s\t%s\n", i,
140 (af = ((GAFR(i) >> ((i & 0x0f) << 0x01)) & 0x03)) ? (af == 1 ? "AF1" : (af == 2 ? "AF2" : "AF3")) : "GPIO",
141 (GPDR(i) & GPIO_bit(i)) ? "out" : "in",
142 (GPLR(i) & GPIO_bit(i)) ? "set" : "clear");
144 len = (p - page) - off;
146 if(len < 0)
148 len = 0;
151 *eof = (len <= count) ? 1 : 0;
152 *start = page + off;
154 return len;
158 #ifdef CONFIG_PXA25x
159 static const char const *GAFR_DESC[] = { "GAFR0_L", "GAFR0_U", "GAFR1_L", "GAFR1_U", "GAFR2_L", "GAFR2_U" };
160 #elif defined(CONFIG_PXA27x)
161 static const char const *GAFR_DESC[] = { "GAFR0_L", "GAFR0_U", "GAFR1_L", "GAFR1_U", "GAFR2_L", "GAFR2_U", "GAFR3_L", "GAFR3_U" };
162 #endif
164 static int proc_gafr_read(char *page, char **start, off_t off,
165 int count, int *eof, void *data)
167 char *p = page;
168 int i, len;
170 for(i=0; i<ARRAY_SIZE(GAFR_DESC); i++)
172 p += sprintf(p, "%s: %08x\n", GAFR_DESC[i], GAFR(i*16));
175 len = (p - page) - off;
177 if(len < 0)
179 len = 0;
182 *eof = (len <= count) ? 1 : 0;
183 *start = page + off;
185 return len;
188 static int proc_gpdr_read(char *page, char **start, off_t off,
189 int count, int *eof, void *data)
191 char *p = page;
192 int i, len;
194 for(i=0; i<=2; i++)
196 p += sprintf(p, "GPDR%d: %08x\n", i, GPDR(i * 32));
199 len = (p - page) - off;
201 if(len < 0)
203 len = 0;
206 *eof = (len <= count) ? 1 : 0;
207 *start = page + off;
209 return len;
212 static int proc_gplr_read(char *page, char **start, off_t off,
213 int count, int *eof, void *data)
215 char *p = page;
216 int i, len;
218 for(i=0; i<=2; i++)
220 p += sprintf(p, "GPLR%d: %08x\n", i, GPLR(i * 32));
223 len = (p - page) - off;
225 if(len < 0)
227 len = 0;
230 *eof = (len <= count) ? 1 : 0;
231 *start = page + off;
233 return len;
236 static int __init gpio_init(void)
238 int i;
240 proc_gpio_parent = NULL;
241 for (proc_gpio_parent = proc_root.subdir; proc_gpio_parent; proc_gpio_parent = proc_gpio_parent->next) {
242 if (( proc_gpio_parent->namelen == 4 ) && ( memcmp(proc_gpio_parent->name, "gpio", 4 ) == 0 ))
243 break;
246 // proc_gpio_parent will be non-NULL if the directory already exists
248 if (!proc_gpio_parent) {
249 proc_gpio_parent = create_proc_entry("gpio", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
252 if(!proc_gpio_parent) return 0;
254 proc_gpios = kmalloc(sizeof(struct proc_dir_entry *) * (pxa_last_gpio + 1), GFP_KERNEL);
255 if (!proc_gpios) {
256 return -ENOMEM;
258 gpio_summaries = kmalloc(sizeof(gpio_summary_type) * (pxa_last_gpio + 1), GFP_KERNEL);
259 if (!gpio_summaries) {
260 kfree(proc_gpios);
261 return -ENOMEM;
264 for(i=0; i < (pxa_last_gpio+1); i++)
266 gpio_summaries[i].gpio = i;
267 sprintf(gpio_summaries[i].name, "GPIO%d", i);
268 proc_gpios[i] = create_proc_entry(gpio_summaries[i].name, 0644, proc_gpio_parent);
269 if(proc_gpios[i])
271 proc_gpios[i]->data = &gpio_summaries[i];
272 proc_gpios[i]->read_proc = proc_gpio_read;
273 proc_gpios[i]->write_proc = proc_gpio_write;
277 create_proc_read_entry("GAFR", 0444, proc_gpio_parent, proc_gafr_read, NULL);
278 create_proc_read_entry("GPDR", 0444, proc_gpio_parent, proc_gpdr_read, NULL);
279 create_proc_read_entry("GPLR", 0444, proc_gpio_parent, proc_gplr_read, NULL);
281 return 0;
284 static void gpio_exit(void)
286 int i;
288 remove_proc_entry("GAFR", proc_gpio_parent);
289 remove_proc_entry("GPDR", proc_gpio_parent);
290 remove_proc_entry("GPLR", proc_gpio_parent);
292 for(i=0; i < (pxa_last_gpio+1); i++)
294 if(proc_gpios[i]) remove_proc_entry(gpio_summaries[i].name, proc_gpio_parent);
297 kfree(gpio_summaries);
298 kfree(proc_gpios);
300 if (proc_gpio_parent)
302 if (!proc_gpio_parent->subdir)
304 // Only remove /proc/gpio if it's empty.
305 remove_proc_entry( "gpio", NULL );
311 module_init(gpio_init);
312 module_exit(gpio_exit);
313 MODULE_LICENSE("GPL");