011-proc-gpio.patch 8.9 KB

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