diff options
Diffstat (limited to 'recipes/linux/linux-gumstix-2.6.15/proc-gpio.patch')
-rw-r--r-- | recipes/linux/linux-gumstix-2.6.15/proc-gpio.patch | 401 |
1 files changed, 401 insertions, 0 deletions
diff --git a/recipes/linux/linux-gumstix-2.6.15/proc-gpio.patch b/recipes/linux/linux-gumstix-2.6.15/proc-gpio.patch new file mode 100644 index 0000000000..1a53d1b1d0 --- /dev/null +++ b/recipes/linux/linux-gumstix-2.6.15/proc-gpio.patch @@ -0,0 +1,401 @@ +Index: linux-2.6.15gum/arch/arm/Kconfig +=================================================================== +--- linux-2.6.15gum.orig/arch/arm/Kconfig ++++ linux-2.6.15gum/arch/arm/Kconfig +@@ -316,6 +316,8 @@ config PCI_HOST_VIA82C505 + depends on PCI && ARCH_SHARK + default y + ++source "drivers/gpio/Kconfig" ++ + source "drivers/pci/Kconfig" + + source "drivers/pcmcia/Kconfig" +Index: linux-2.6.15gum/drivers/Makefile +=================================================================== +--- linux-2.6.15gum.orig/drivers/Makefile ++++ linux-2.6.15gum/drivers/Makefile +@@ -70,3 +70,4 @@ obj-$(CONFIG_SGI_IOC4) += sn/ + obj-y += firmware/ + obj-$(CONFIG_CRYPTO) += crypto/ + obj-$(CONFIG_SUPERH) += sh/ ++obj-$(CONFIG_PROC_GPIO) += gpio/ +Index: linux-2.6.15gum/drivers/gpio/Kconfig +=================================================================== +--- /dev/null ++++ linux-2.6.15gum/drivers/gpio/Kconfig +@@ -0,0 +1,6 @@ ++config PROC_GPIO ++ tristate "GPIO /proc interface" ++ depends on PXA25x ++ help ++ This enables an interface under /proc/gpio which allows reading or setting ++ of any GPIO. Currently only reading is supported. +Index: linux-2.6.15gum/drivers/gpio/Makefile +=================================================================== +--- /dev/null ++++ linux-2.6.15gum/drivers/gpio/Makefile +@@ -0,0 +1,3 @@ ++# Expose GPIOs under /proc ++obj-$(CONFIG_PROC_GPIO) += proc_gpio.o ++ +Index: linux-2.6.15gum/drivers/gpio/proc_gpio.c +=================================================================== +--- /dev/null ++++ linux-2.6.15gum/drivers/gpio/proc_gpio.c +@@ -0,0 +1,355 @@ ++/* ++ * ++ * PXA25x GPIOs exposed under /proc for reading and writing ++ * They will show up under /proc/gpio/NN ++ * ++ * Based on patch 1773/1 in the arm kernel patch repository at arm.linux.co.uk ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/proc_fs.h> ++#include <linux/string.h> ++#include <linux/ctype.h> ++ ++#include <asm/hardware.h> ++#include <asm/arch/pxa-regs.h> ++#include <asm/uaccess.h> ++ ++static struct proc_dir_entry *proc_gpio_parent; ++static struct proc_dir_entry *proc_gpios[85]; ++ ++typedef struct ++{ ++ int gpio; ++ char name[32]; ++} gpio_summary_type; ++ ++static gpio_summary_type gpio_summaries[85] = ++{ ++ { 0, "GPIO0" }, ++ { 1, "GPIO1" }, ++ { 2, "GPIO2" }, ++ { 3, "GPIO3" }, ++ { 4, "GPIO4" }, ++ { 5, "GPIO5" }, ++ { 6, "GPIO6" }, ++ { 7, "GPIO7" }, ++ { 8, "GPIO8" }, ++ { 9, "GPIO9" }, ++ { 10, "GPIO10" }, ++ { 11, "GPIO11" }, ++ { 12, "GPIO12" }, ++ { 13, "GPIO13" }, ++ { 14, "GPIO14" }, ++ { 15, "GPIO15" }, ++ { 16, "GPIO16" }, ++ { 17, "GPIO17" }, ++ { 18, "GPIO18" }, ++ { 19, "GPIO19" }, ++ { 20, "GPIO20" }, ++ { 21, "GPIO21" }, ++ { 22, "GPIO22" }, ++ { 23, "GPIO23" }, ++ { 24, "GPIO24" }, ++ { 25, "GPIO25" }, ++ { 26, "GPIO26" }, ++ { 27, "GPIO27" }, ++ { 28, "GPIO28" }, ++ { 29, "GPIO29" }, ++ { 30, "GPIO30" }, ++ { 31, "GPIO31" }, ++ { 32, "GPIO32" }, ++ { 33, "GPIO33" }, ++ { 34, "GPIO34" }, ++ { 35, "GPIO35" }, ++ { 36, "GPIO36" }, ++ { 37, "GPIO37" }, ++ { 38, "GPIO38" }, ++ { 39, "GPIO39" }, ++ { 40, "GPIO40" }, ++ { 41, "GPIO41" }, ++ { 42, "GPIO42" }, ++ { 43, "GPIO43" }, ++ { 44, "GPIO44" }, ++ { 45, "GPIO45" }, ++ { 46, "GPIO46" }, ++ { 47, "GPIO47" }, ++ { 48, "GPIO48" }, ++ { 49, "GPIO49" }, ++ { 50, "GPIO50" }, ++ { 51, "GPIO51" }, ++ { 52, "GPIO52" }, ++ { 53, "GPIO53" }, ++ { 54, "GPIO54" }, ++ { 55, "GPIO55" }, ++ { 56, "GPIO56" }, ++ { 57, "GPIO57" }, ++ { 58, "GPIO58" }, ++ { 59, "GPIO59" }, ++ { 60, "GPIO60" }, ++ { 61, "GPIO61" }, ++ { 62, "GPIO62" }, ++ { 63, "GPIO63" }, ++ { 64, "GPIO64" }, ++ { 65, "GPIO65" }, ++ { 66, "GPIO66" }, ++ { 67, "GPIO67" }, ++ { 68, "GPIO68" }, ++ { 69, "GPIO69" }, ++ { 70, "GPIO70" }, ++ { 71, "GPIO71" }, ++ { 72, "GPIO72" }, ++ { 73, "GPIO73" }, ++ { 74, "GPIO74" }, ++ { 75, "GPIO75" }, ++ { 76, "GPIO76" }, ++ { 77, "GPIO77" }, ++ { 78, "GPIO78" }, ++ { 79, "GPIO79" }, ++ { 80, "GPIO80" }, ++ { 81, "GPIO81" }, ++ { 82, "GPIO82" }, ++ { 83, "GPIO83" }, ++ { 84, "GPIO84" }, ++}; ++ ++static int proc_gpio_write(struct file *file, const char __user *buf, ++ unsigned long count, void *data) ++{ ++ char *cur, lbuf[count + 1]; ++ gpio_summary_type *summary = data; ++ u32 altfn, direction, setclear, gafr; ++ ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EACCES; ++ ++ memset(lbuf, 0, count + 1); ++ ++ if (copy_from_user(lbuf, buf, count)) ++ return -EFAULT; ++ ++ cur = lbuf; ++ ++ // Initialize to current state ++ altfn = ((GAFR(summary->gpio) >> ((summary->gpio & 0x0f) << 0x01)) & 0x03); ++ direction = GPDR(summary->gpio) & GPIO_bit(summary->gpio); ++ setclear = GPLR(summary->gpio) & GPIO_bit(summary->gpio); ++ while(1) ++ { ++ // We accept options: {GPIO|AF1|AF2|AF3}, {set|clear}, {in|out} ++ // Anything else is an error ++ while(cur[0] && (isspace(cur[0]) || ispunct(cur[0]))) cur = &(cur[1]); ++ ++ if('\0' == cur[0]) break; ++ ++ // Ok, so now we're pointing at the start of something ++ switch(cur[0]) ++ { ++ case 'G': ++ // Check that next is "PIO" -- '\0' will cause safe short-circuit if end of buf ++ if(!(cur[1] == 'P' && cur[2] == 'I' && cur[3] == 'O')) goto parse_error; ++ // Ok, so set this GPIO to GPIO (non-ALT) function ++ altfn = 0; ++ cur = &(cur[4]); ++ break; ++ case 'A': ++ if(!(cur[1] == 'F' && cur[2] >= '1' && cur[2] <= '3')) goto parse_error; ++ altfn = cur[2] - '0'; ++ cur = &(cur[3]); ++ break; ++ case 's': ++ if(!(cur[1] == 'e' && cur[2] == 't')) goto parse_error; ++ setclear = 1; ++ cur = &(cur[3]); ++ break; ++ case 'c': ++ if(!(cur[1] == 'l' && cur[2] == 'e' && cur[3] == 'a' && cur[4] == 'r')) goto parse_error; ++ setclear = 0; ++ cur = &(cur[5]); ++ break; ++ case 'i': ++ if(!(cur[1] == 'n')) goto parse_error; ++ direction = 0; ++ cur = &(cur[2]); ++ break; ++ case 'o': ++ if(!(cur[1] == 'u' && cur[2] == 't')) goto parse_error; ++ direction = 1; ++ cur = &(cur[3]); ++ break; ++ default: goto parse_error; ++ } ++ } ++ // Ok, now set gpio mode and value ++ if(direction) ++ GPDR(summary->gpio) |= GPIO_bit(summary->gpio); ++ else ++ GPDR(summary->gpio) &= ~GPIO_bit(summary->gpio); ++ ++ gafr = GAFR(summary->gpio) & ~(0x3 << (((summary->gpio) & 0xf)*2)); ++ GAFR(summary->gpio) = gafr | (altfn << (((summary->gpio) & 0xf)*2)); ++ ++ if(direction && !altfn) ++ { ++ if(setclear) GPSR(summary->gpio) = GPIO_bit(summary->gpio); ++ else GPCR(summary->gpio) = GPIO_bit(summary->gpio); ++ } ++ ++ printk(KERN_INFO "Set (%s,%s,%s) via /proc/gpio/%s\n",altfn ? (altfn == 1 ? "AF1" : (altfn == 2 ? "AF2" : "AF3")) : "GPIO", ++ direction ? "out" : "in", ++ setclear ? "set" : "clear", ++ summary->name); ++ ++ return count; ++ ++parse_error: ++ printk(KERN_CRIT "Parse error: Expect \"[GPIO|AF1|AF2|AF3]|[set|clear]|[in|out] ...\"\n"); ++ return -EINVAL; ++} ++ ++static int proc_gpio_read(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ char *p = page; ++ gpio_summary_type *summary = data; ++ int len, i, af; ++ i = summary->gpio; ++ ++ p += sprintf(p, "%d\t%s\t%s\t%s\n", i, ++ (af = ((GAFR(i) >> ((i & 0x0f) << 0x01)) & 0x03)) ? (af == 1 ? "AF1" : (af == 2 ? "AF2" : "AF3")) : "GPIO", ++ (GPDR(i) & GPIO_bit(i)) ? "out" : "in", ++ (GPLR(i) & GPIO_bit(i)) ? "set" : "clear"); ++ ++ len = (p - page) - off; ++ ++ if(len < 0) ++ { ++ len = 0; ++ } ++ ++ *eof = (len <= count) ? 1 : 0; ++ *start = page + off; ++ ++ return len; ++} ++ ++static const char const *GAFR_DESC[] = { "GAFR0_L", "GAFR0_U", "GAFR1_L", "GAFR1_U", "GAFR2_L", "GAFR2_U" }; ++ ++static int proc_gafr_read(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ char *p = page; ++ int i, len; ++ ++ for(i=0; i<=5; i++) ++ { ++ p += sprintf(p, "%s: %08x\n", GAFR_DESC[i], GAFR(i*16)); ++ } ++ ++ len = (p - page) - off; ++ ++ if(len < 0) ++ { ++ len = 0; ++ } ++ ++ *eof = (len <= count) ? 1 : 0; ++ *start = page + off; ++ ++ return len; ++} ++ ++static int proc_gpdr_read(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ char *p = page; ++ int i, len; ++ ++ for(i=0; i<=2; i++) ++ { ++ p += sprintf(p, "GPDR%d: %08x\n", i, GPDR(i * 32)); ++ } ++ ++ len = (p - page) - off; ++ ++ if(len < 0) ++ { ++ len = 0; ++ } ++ ++ *eof = (len <= count) ? 1 : 0; ++ *start = page + off; ++ ++ return len; ++} ++ ++static int proc_gplr_read(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ char *p = page; ++ int i, len; ++ ++ for(i=0; i<=2; i++) ++ { ++ p += sprintf(p, "GPLR%d: %08x\n", i, GPLR(i * 32)); ++ } ++ ++ len = (p - page) - off; ++ ++ if(len < 0) ++ { ++ len = 0; ++ } ++ ++ *eof = (len <= count) ? 1 : 0; ++ *start = page + off; ++ ++ return len; ++} ++ ++static int __init gpio_init(void) ++{ ++ int i; ++ ++ proc_gpio_parent = create_proc_entry("gpio", S_IFDIR | S_IRUGO | S_IXUGO, NULL); ++ if(!proc_gpio_parent) return 0; ++ ++ for(i=0; i < 85; i++) ++ { ++ proc_gpios[i] = create_proc_entry(gpio_summaries[i].name, 0644, proc_gpio_parent); ++ if(proc_gpios[i]) ++ { ++ proc_gpios[i]->data = &gpio_summaries[i]; ++ proc_gpios[i]->read_proc = proc_gpio_read; ++ proc_gpios[i]->write_proc = proc_gpio_write; ++ } ++ } ++ ++ create_proc_read_entry("GAFR", 0444, proc_gpio_parent, proc_gafr_read, NULL); ++ create_proc_read_entry("GPDR", 0444, proc_gpio_parent, proc_gpdr_read, NULL); ++ create_proc_read_entry("GPLR", 0444, proc_gpio_parent, proc_gplr_read, NULL); ++ ++ return 0; ++} ++ ++static void gpio_exit(void) ++{ ++ int i; ++ ++ remove_proc_entry("GAFR", proc_gpio_parent); ++ remove_proc_entry("GPDR", proc_gpio_parent); ++ remove_proc_entry("GPLR", proc_gpio_parent); ++ ++ for(i=0; i < 85; i++) ++ { ++ if(proc_gpios[i]) remove_proc_entry(gpio_summaries[i].name, proc_gpio_parent); ++ } ++ if(proc_gpio_parent) remove_proc_entry("gpio", NULL); ++} ++ ++module_init(gpio_init); ++module_exit(gpio_exit); ++MODULE_LICENSE("GPL"); |