summaryrefslogtreecommitdiff
path: root/recipes/linux/linux-gumstix-2.6.15/proc-gpio.patch
diff options
context:
space:
mode:
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.patch401
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");