| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 |
- Index: linux-2.6.21.7/arch/arm/Kconfig
- ===================================================================
- --- linux-2.6.21.7.orig/arch/arm/Kconfig
- +++ linux-2.6.21.7/arch/arm/Kconfig
- @@ -505,6 +505,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.21.7/drivers/Makefile
- ===================================================================
- --- linux-2.6.21.7.orig/drivers/Makefile
- +++ linux-2.6.21.7/drivers/Makefile
- @@ -81,3 +81,4 @@ obj-$(CONFIG_GENERIC_TIME) += clocksourc
- obj-$(CONFIG_DMA_ENGINE) += dma/
- obj-$(CONFIG_HID) += hid/
- obj-$(CONFIG_PPC_PS3) += ps3/
- +obj-$(CONFIG_PROC_GPIO) += gpio/
- Index: linux-2.6.21.7/drivers/gpio/Kconfig
- ===================================================================
- --- linux-2.6.21.7.orig/drivers/gpio/Kconfig
- +++ linux-2.6.21.7/drivers/gpio/Kconfig
- @@ -2,14 +2,27 @@ menuconfig NEW_GPIO
- bool "GPIO Support"
- depends on GENERIC_GPIO
- help
- - Say Y to enable Linux GPIO device support. This allows control of
- - GPIO pins using a character device
- + Say Y to enable Linux GPIO device support. This allows control of
- + GPIO pins using a character device
-
- if NEW_GPIO
-
- config GPIO_DEVICE
- tristate "GPIO device support"
- help
- - This option enables the gpio character device
- + This option enables the gpio character device
-
- endif # NEW_GPIO
- +
- +config PROC_GPIO
- + tristate "GPIO /proc interface"
- + depends on PXA25x || PXA27x
- + help
- + This enables an interface under /proc/gpio which allows reading or setting
- + of any GPIO, and also changing the GPIO alt function mode of any line.
- +
- +config PROC_GPIO_DEBUG
- + boolean "Enable /proc/gpio debug logging"
- + depends on PROC_GPIO
- + help
- + This enables printk logging of activity done through /proc/gpio
- Index: linux-2.6.21.7/drivers/gpio/Makefile
- ===================================================================
- --- linux-2.6.21.7.orig/drivers/gpio/Makefile
- +++ linux-2.6.21.7/drivers/gpio/Makefile
- @@ -1 +1,4 @@
- obj-$(CONFIG_GPIO_DEVICE) += gpio_dev.o
- +
- +# Expose GPIOs under /proc
- +obj-$(CONFIG_PROC_GPIO) += proc_gpio.o
- Index: linux-2.6.21.7/drivers/gpio/proc_gpio.c
- ===================================================================
- --- /dev/null
- +++ linux-2.6.21.7/drivers/gpio/proc_gpio.c
- @@ -0,0 +1,276 @@
- +/*
- + *
- + * 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/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[PXA_LAST_GPIO + 1];
- +
- +typedef struct
- +{
- + int gpio;
- + char name[32];
- +} gpio_summary_type;
- +
- +static gpio_summary_type gpio_summaries[PXA_LAST_GPIO + 1];
- +
- +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);
- + }
- +
- +#ifdef CONFIG_PROC_GPIO_DEBUG
- + 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);
- +#endif
- +
- + 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;
- +}
- +
- +
- +#ifdef CONFIG_PXA25x
- +static const char const *GAFR_DESC[] = { "GAFR0_L", "GAFR0_U", "GAFR1_L", "GAFR1_U", "GAFR2_L", "GAFR2_U" };
- +#elif defined(CONFIG_PXA27x)
- +static const char const *GAFR_DESC[] = { "GAFR0_L", "GAFR0_U", "GAFR1_L", "GAFR1_U", "GAFR2_L", "GAFR2_U", "GAFR3_L", "GAFR3_U" };
- +#endif
- +
- +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<ARRAY_SIZE(GAFR_DESC); 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 < (PXA_LAST_GPIO+1); i++)
- + {
- + gpio_summaries[i].gpio = i;
- + sprintf(gpio_summaries[i].name, "GPIO%d", 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 < (PXA_LAST_GPIO+1); 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");
|