From: <ph...@us...> - 2007-02-14 07:27:25
|
Revision: 806 http://svn.sourceforge.net/hackndev/?rev=806&view=rev Author: phiren Date: 2007-02-13 23:27:22 -0800 (Tue, 13 Feb 2007) Log Message: ----------- Buttons, keyboard and gpioed for zire31 Modified Paths: -------------- linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/Kconfig linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/Makefile linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/palmz31-gpio.h linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/palmz31.c Added Paths: ----------- linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/gpioed-ng.c linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/gpioed.c linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/palmz31_buttons.c Modified: linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/Kconfig =================================================================== --- linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/Kconfig 2007-02-13 16:54:05 UTC (rev 805) +++ linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/Kconfig 2007-02-14 07:27:22 UTC (rev 806) @@ -4,3 +4,27 @@ help Say Y here if you are going to run this kernel on a Palm Zire 31. +config PALMZ31_BUTTONS + tristate "Palm Zire 31 buttons driver" + depends on MACH_ZIRE31 + default y + help + This driver translates button presses on a Palm + Tungsten E2 to Linux input subsystem events. + + +config GPIOED + tristate "GPIOED" + depends on MACH_ZIRE31 + default n + help + Gpioed: only for debuging and testing! + + +config GPIOEDNG + tristate "GPIOEDNG" + depends on MACH_ZIRE31 + default n + help + Gpioed-ng: only for debuging and testing! + Modified: linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/Makefile =================================================================== --- linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/Makefile 2007-02-13 16:54:05 UTC (rev 805) +++ linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/Makefile 2007-02-14 07:27:22 UTC (rev 806) @@ -2,4 +2,7 @@ # Makefile for Palm Zire 31 support # -obj-$(CONFIG_MACH_ZIRE31) += palmz31.o +obj-$(CONFIG_MACH_ZIRE31) += palmz31.o +obj-$(CONFIG_PALMZ31_BUTTONS) += palmz31_buttons.o +obj-$(CONFIG_GPIOED) += gpioed.o +obj-$(CONFIG_GPIOEDNG) += gpioed-ng.o Added: linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/gpioed-ng.c =================================================================== --- linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/gpioed-ng.c (rev 0) +++ linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/gpioed-ng.c 2007-02-14 07:27:22 UTC (rev 806) @@ -0,0 +1,175 @@ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/proc_fs.h> + +#include <linux/interrupt.h> +#include <asm/irq.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach-types.h> +#include <asm/hardware.h> +#include <linux/sched.h> +#include <linux/workqueue.h> +#include <asm/arch/pxa-regs.h> +#include <asm/arch/irqs.h> +#include <asm/uaccess.h> + +#include <linux/debugfs.h> +#include <linux/seq_file.h> + +#define PROCFS_NAME "gpio" +#define DEBUGFS_NAME "gpio" + +static struct proc_dir_entry *proc_intf; +static struct dentry *debugfs_intf; + +#define PROCFS_MAX_SIZE 20 + +static char procfs_buffer[PROCFS_MAX_SIZE]; +static unsigned long procfs_buffer_size = 0; + +#define GPIO_TEST(reg, gp) (reg(gp) & GPIO_bit(gp)) +static int dfs_show(struct seq_file *s, void *_) +{ + int i,afn; + seq_printf(s, "GPIO lines status:\n"); + + for(i=0;i<121;i++) { + afn = (GAFR(i) & (0x3 << (((i) & 0xf)*2))) >> (((i) & 0xf)*2); + seq_printf(s, "%s%d: %s %s %s %s %lx\n", + i<10?"0":"", + i, + GPIO_TEST(GPLR, i)?"*":" ", + GPIO_TEST(GPDR, i)?"->":"<-", + GPIO_TEST(GRER, i)?"_/":" ", + GPIO_TEST(GFER, i)?"\\_":" ", + afn); + + } + + return 0; +} + +static int dfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, dfs_show, inode->u.generic_ip); +} + +static struct file_operations debug_fops = { + .open = dfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void gpio_set(int id, int on) +{ + do { + if (on) + GPSR(id) = GPIO_bit(id); + else + GPCR(id) = GPIO_bit(id); + } while (0); +} + +void set_afn(int gpio, int fn) +{ + int gafr; + gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2)); + GAFR(gpio) = gafr | (fn << (((gpio) & 0xf)*2)); +} + +void handle_request() +{ + char *p = NULL; + unsigned long id = simple_strtoul(procfs_buffer+2, &p, 10); + switch(procfs_buffer[0]) { + case 'L': + gpio_set(id, 1); + printk(KERN_ERR "GPIOed: GPIO %lu set high\n", id); + break; + case 'l': + gpio_set(id, 0); + printk(KERN_ERR "GPIOed: GPIO %lu set low\n", id); + break; + case 'd': + GPDR(id) &= ~(GPIO_bit(id)); + break; + case 'D': + GPDR(id) |= GPIO_bit(id); + break; + case '0': + set_afn(id, 0); + break; + case '1': + set_afn(id, 1); + break; + case '2': + set_afn(id, 2); + break; + default: + printk(KERN_ERR "GPIOed: Unknown request\n"); + break; + } +} + + +int procfile_write(struct file *file, const char *buffer, unsigned long count, void *data) +{ + procfs_buffer_size = count; + if (procfs_buffer_size > PROCFS_MAX_SIZE ) { + procfs_buffer_size = PROCFS_MAX_SIZE; + } + + /* write data to the buffer */ + if ( copy_from_user(procfs_buffer, buffer, procfs_buffer_size) ) { + return -EFAULT; + } + + handle_request(); + + return procfs_buffer_size; +} + + +static int __init gpioed_init(void) +{ + proc_intf = create_proc_entry(PROCFS_NAME, 0644, NULL); + if (proc_intf == NULL) { + remove_proc_entry(PROCFS_NAME, &proc_root); + printk(KERN_ALERT "Error: Could not initialize /proc/%s\n", PROCFS_NAME); + return -ENOMEM; + } + + /*proc_intf->read_proc = procfile_read;*/ + proc_intf->write_proc = procfile_write; + proc_intf->owner = THIS_MODULE; + proc_intf->mode = S_IFREG | S_IRUGO; + proc_intf->uid = 0; + proc_intf->gid = 0; + proc_intf->size = 37; + + debugfs_intf = debugfs_create_file(DEBUGFS_NAME, S_IRUGO, NULL, NULL, &debug_fops); + + printk(KERN_INFO "/proc/%s created\n", PROCFS_NAME); + + return 0; +} + +static void __exit gpioed_exit(void) +{ + debugfs_remove(debugfs_intf); + remove_proc_entry(PROCFS_NAME, &proc_root); + printk(KERN_INFO "/proc/%s removed\n", PROCFS_NAME); +} + + +/*** Some more stuff ***/ +module_init(gpioed_init); +module_exit(gpioed_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vladimir \"Farcaller\" Pouzanov <far...@gm...>"); +MODULE_DESCRIPTION("GPIO editor for PXA26x, second edition"); + Added: linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/gpioed.c =================================================================== --- linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/gpioed.c (rev 0) +++ linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/gpioed.c 2007-02-14 07:27:22 UTC (rev 806) @@ -0,0 +1,278 @@ +/*** Basic includes ***/ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/proc_fs.h> + +#include <linux/interrupt.h> +#include <asm/irq.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach-types.h> +#include <asm/hardware.h> +#include <linux/sched.h> +#include <linux/workqueue.h> +#include <asm/arch/pxa-regs.h> +#include <asm/arch/irqs.h> +#include <asm/uaccess.h> + +/*** GPIO macros ***/ +#define GET_PALMT3_GPIO(gpio) \ + (GPLR(GPIO_NR_PALMT3_ ## gpio) & GPIO_bit(GPIO_NR_PALMT3_ ## gpio)) + +#define SET_PALMT3_GPIO(gpio, setp) \ + do { \ + if (setp) \ + GPSR(GPIO_NR_PALMT3_ ## gpio) = GPIO_bit(GPIO_NR_PALMT3_ ## gpio); \ + else \ + GPCR(GPIO_NR_PALMT3_ ## gpio) = GPIO_bit(GPIO_NR_PALMT3_ ## gpio); \ + } while (0) + +#define SET_PALMT3_GPIO_N(gpio, setp) \ + do { \ + if (setp) \ + GPCR(GPIO_NR_PALMT3_ ## gpio) = GPIO_bit(GPIO_NR_PALMT3_ ## gpio); \ + else \ + GPSR(GPIO_NR_PALMT3_ ## gpio) = GPIO_bit(GPIO_NR_PALMT3_ ## gpio); \ + } while (0) + +#define GET_GPIO_REG(reg,gpio) (GP##reg(gpio) & GPIO_bit(gpio)) +#define GET_GPIO(gpio) (GPLR(gpio) & GPIO_bit(gpio)) +#define GET_GPIOD(gpio) (GPDR(gpio) & GPIO_bit(gpio)) + +/*** /proc interface ***/ +static struct proc_dir_entry *proc_intf; +#define procfs_name "gpioed" +#define PROCFS_MAX_SIZE 20 + +static char procfs_buffer[PROCFS_MAX_SIZE]; +static unsigned long procfs_buffer_size = 0; + +int gpio_info(char *buffer); + +int procfile_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, int *eof, void *data) +{ + int ret; + + if (offset > 0) { + /* we have finished to read, return 0 */ + ret = 0; + } else { + /* fill the buffer, return the buffer size */ + ret = gpio_info(buffer); + //ret = sprintf(buffer, "HelloWorld!\n"); + } + return ret; +} + +int gpio_info(char *buffer) +// output all knowen infomation about the gpios to /proc/gpioed +{ + int i; + int ret; + sprintf(buffer, "Infomation about gpios:\n| Gpio | Direction | State |\n"); + for(i=0; i<85; i++) + { + sprintf(buffer, "%s| %2i ", buffer, i); + if(GET_GPIOD(i) == 0) //In + sprintf(buffer, "%s| In ",buffer); + else //Out + sprintf(buffer, "%s| Out ",buffer); + if(GET_GPIO(i) == 0) //Low + sprintf(buffer, "%s| Low |\n", buffer); + else //high + sprintf(buffer, "%s| High |\n", buffer); + } + ret = sprintf(buffer, "%s---------------------------\n Alternate Functions:\n 0L: %X 0U: %X 1L: %X 1U: %X 2L: %X 2U: %X\n", buffer, GAFR0_L, GAFR0_U, GAFR1_L, GAFR1_U, GAFR2_L, GAFR2_U); + + return ret; +} + +void handle_request(void); + +int procfile_write(struct file *file, const char *buffer, unsigned long count, void *data) +{ + procfs_buffer_size = count; + if (procfs_buffer_size > PROCFS_MAX_SIZE ) { + procfs_buffer_size = PROCFS_MAX_SIZE; + } + + /* write data to the buffer */ + if ( copy_from_user(procfs_buffer, buffer, procfs_buffer_size) ) { + return -EFAULT; + } + + handle_request(); + + return procfs_buffer_size; +} + +/*** IRQ (GPIO) handling ***/ +static struct workqueue_struct *my_workqueue; +#define MY_WORK_QUEUE_NAME "GPIOed" + +static void handle_gpio(void* irq) +{ + int gpn = (int)irq; + printk(KERN_ERR "*** GPIO *** %d *** is *** %s ***\n", gpn, GET_GPIO(gpn) ? "high" : "low "); +} + +irqreturn_t gpio_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + static int initialised = 0; + static struct work_struct task; + + if (initialised == 0) { + INIT_WORK(&task, handle_gpio, dev_id); + initialised = 1; + } else { + PREPARE_WORK(&task, handle_gpio, dev_id); + } + + queue_work(my_workqueue, &task); + + return IRQ_HANDLED; +} + +/*** GPIO R/W ***/ +static int gpio_get(int id) +{ + return GET_GPIO(id); +} + +static void gpio_set(int id, int on) +{ + do { + if (on) + GPSR(id) = GPIO_bit(id); + else + GPCR(id) = GPIO_bit(id); + } while (0); +} + +static int gpio_watch(int x) +{ + int ret; + ret = request_irq (IRQ_GPIO(x), gpio_irq, SA_SAMPLE_RANDOM, "test_handler", (void*)x); + set_irq_type (IRQ_GPIO(x), IRQT_BOTHEDGE); + if(ret!=0) { + printk(KERN_ERR "GPIOed: failed to register for GPIO %d\n", x); + return 1; + } else { + printk(KERN_ERR "GPIOed: Registered GPIO %d\n", x); + return 0; + } +} + +void set_afn(int gpio, int fn) +{ + int gafr; + gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2)); + GAFR(gpio) = gafr | (fn << (((gpio) & 0xf)*2)); +} + + +/*** Request handler ***/ +void handle_request() +{ + char *p = NULL; + unsigned long base = 10; + unsigned long id; + + if((procfs_buffer[0] == 'P') || (procfs_buffer[0] == 'V')) + base = 16; + id = simple_strtoul(procfs_buffer+2, &p, base); + switch(procfs_buffer[0]) { + case 'r': + printk(KERN_ERR "GPIOed: GPIO %lu is %s\n", id, gpio_get(id)?"high":"low "); + break; + case 's': + gpio_watch(id); + break; + case 'h': + gpio_set(id, 1); + printk(KERN_ERR "GPIOed: GPIO %lu set high\n", id); + break; + case 'l': + gpio_set(id, 0); + printk(KERN_ERR "GPIOed: GPIO %lu set low\n", id); + break; + case 'd': + printk(KERN_ERR "GPIOed: GPIO %lu is %s\n", id, GET_GPIO_REG(DR,id)?"output":"input"); + break; + + case 'P': + printk(KERN_ERR "GPIOed: P-V for 0x%x is 0x%x\n", id, (unsigned int)phys_to_virt(id)); + break; + case 'V': + printk(KERN_ERR "GPIOed: V-P for 0x%x is 0x%x\n", id, (unsigned int)virt_to_phys(id)); + break; + case 'D': + base = *((unsigned int*)id); + printk(KERN_ERR "GPIOed: 0x%x = 0x%x\n", id, base); + break; + case 'o': + GPDR(id) &= ~(GPIO_bit(id)); + break; + case 'i': + GPDR(id) |= GPIO_bit(id); + break; + + case '0': + set_afn(id, 0); + break; + case '1': + set_afn(id, 1); + break; + case '2': + set_afn(id, 2); + break; + + default: + printk(KERN_ERR "GPIOed: Unknown request\n"); + break; + } +} + +/*** init&exit ***/ +static int __init gpioed_init(void) +{ + my_workqueue = create_workqueue(MY_WORK_QUEUE_NAME); + + proc_intf = create_proc_entry(procfs_name, 0644, NULL); + if (proc_intf == NULL) { + remove_proc_entry(procfs_name, &proc_root); + printk(KERN_ALERT "Error: Could not initialize /proc/%s\n", + procfs_name); + return -ENOMEM; + } + + proc_intf->read_proc = procfile_read; + proc_intf->write_proc = procfile_write; + proc_intf->owner = THIS_MODULE; + proc_intf->mode = S_IFREG | S_IRUGO; + proc_intf->uid = 0; + proc_intf->gid = 0; + proc_intf->size = 37; + + printk(KERN_INFO "/proc/%s created\n", procfs_name); + + return 0; +} + +static void __exit gpioed_exit(void) +{ + destroy_workqueue(my_workqueue); + remove_proc_entry(procfs_name, &proc_root); + printk(KERN_INFO "/proc/%s removed\n", procfs_name); +} + + +/*** Some more stuff ***/ +module_init(gpioed_init); +module_exit(gpioed_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vladimir \"Farcaller\" Pouzanov <far...@gm...>"); +MODULE_DESCRIPTION("GPIO editor for PXA26x"); + Modified: linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/palmz31-gpio.h =================================================================== --- linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/palmz31-gpio.h 2007-02-13 16:54:05 UTC (rev 805) +++ linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/palmz31-gpio.h 2007-02-14 07:27:22 UTC (rev 806) @@ -10,7 +10,9 @@ #include <asm/arch/pxa-regs.h> -// This should let us get usb working -#define GPIO_NR_PALMLD_USB_DETECT 4 +#define GPIO_NR_PALMTC_EARPHONE_DETECT 12 +#define GPIO_NR_PALMLD_POWER_DETECT 9 +#define GPIO_NR_PALMLD_USB_DETECT 7 +#define GPIO_NR_PALMZ31_USB_POWER 53 #endif Modified: linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/palmz31.c =================================================================== --- linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/palmz31.c 2007-02-13 16:54:05 UTC (rev 805) +++ linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/palmz31.c 2007-02-14 07:27:22 UTC (rev 806) @@ -29,6 +29,9 @@ #include <sound/initval.h> #include <sound/ac97_codec.h> +#include <linux/interrupt.h> +#include <asm/irq.h> + #include "../generic.h" #include "palmz31-gpio.h" #define DEBUG @@ -52,20 +55,81 @@ .dev = { .platform_data = &palmld_audio_ops }, }; +/** + * Buttons + */ + +struct platform_device palmz31_buttons = { + .name = "palmz31-buttons", + .id =-1, +}; + +/** + * USB + */ +static struct workqueue_struct *my_workqueue; + #define MY_WORK_QUEUE_NAME "Palmz31" +static void palmz31_usb_power(void* irq) +{ + int gpn = (int)irq; + + if ((GPLR(gpn) & GPIO_bit(gpn)) == 0) // If USB detect is low + //turn USB power off + GPCR(GPIO_NR_PALMZ31_USB_POWER) = GPIO_bit(GPIO_NR_PALMZ31_USB_POWER); + else // Else USB detect is high + //Turn USB power on + GPSR(GPIO_NR_PALMZ31_USB_POWER) = GPIO_bit(GPIO_NR_PALMZ31_USB_POWER); +} + +static irqreturn_t palmz31_usb_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + static struct work_struct task; + + INIT_WORK(&task, palmz31_usb_power, dev_id); + queue_work(my_workqueue, &task); + + return IRQ_HANDLED; +} + +static int palmz31_usb_init() +{ + int ret; + printk(KERN_ERR "Setting up USB..."); + // First set the USB power gpio to 'Out' + GPDR(GPIO_NR_PALMZ31_USB_POWER) |= GPIO_bit(GPIO_NR_PALMZ31_USB_POWER); + // Make sure USB is off, to save power + GPSR(GPIO_NR_PALMZ31_USB_POWER) = GPIO_bit(GPIO_NR_PALMZ31_USB_POWER); + // Then attach a interupt to USB detect + ret = request_irq (IRQ_GPIO(GPIO_NR_PALMLD_USB_DETECT), palmz31_usb_irq, 0, "Detect USB", NULL); + if(ret!=0){ //Check if it worked + printk(KERN_ERR "Whoops: Can't attach irq to USB detect"); + return 1; } + else + { + printk(KERN_ERR "Attached irq to USB detect"); + return 0; + } +} + static struct platform_device *devices[] __initdata = { &palmld_ac97, + &palmz31_buttons, }; +/** + * Backlight + */ + static void zire31_backlight_power(int on) { /* TODO */ if(on) { - PWM_CTRL1 = 0x1; - PWM_PWDUTY1 = 0x50; - PWM_PERVAL1 = 0x12b; - CKEN |= CKEN1_PWM1; + // PWM_CTRL1 = 0x1; + // PWM_PWDUTY1 = 0x50; + // PWM_PERVAL1 = 0x12b; + // CKEN |= CKEN1_PWM1; } else - CKEN &= ~CKEN1_PWM1; + CKEN &= ~3; } static struct pxafb_mach_info zire31_lcd __initdata = { @@ -92,7 +156,7 @@ set_pxa_fb_info(&zire31_lcd); GCR &= ~GCR_PRIRDY_IEN; - + palmz31_usb_init(); platform_add_devices(devices, ARRAY_SIZE(devices)); } Added: linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/palmz31_buttons.c =================================================================== --- linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/palmz31_buttons.c (rev 0) +++ linux4palm/linux/trunk/arch/arm/mach-pxa/palmz31/palmz31_buttons.c 2007-02-14 07:27:22 UTC (rev 806) @@ -0,0 +1,148 @@ +/* + * linux/arch/arm/mach-pxa/palmz31/palmz31-buttons.c + * + * Button driver for Palm Zire 31 + * + * Author: Scott Mansell <ph...@gm...> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/input.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <asm/irq.h> +#include <asm/mach/irq.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <asm/arch/hardware.h> +#include <asm/arch/pxa-regs.h> +#include <asm/arch/irqs.h> + +#define GET_GPIO(gpio) (GPLR(gpio) & GPIO_bit(gpio)) + +#define MAX_BUTTONS 23 + +struct input_dev *button_dev; +static struct device_driver palmz31_buttons_driver; + +static struct { + int keycode; + char *desc; +} palmz31_buttons[MAX_BUTTONS] = { + { -1, NULL }, /* GPIO 0 */ + { -1, NULL }, + { -1, "Power" }, + { -1, NULL }, + { -1, NULL }, + { -1, NULL }, /* GPIO 5 */ + { -1, NULL }, + { -1, NULL }, + { -1, NULL }, + { -1, NULL }, + { -1, NULL }, /* GPIO 10 */ + { KEY_LEFTSHIFT,"Contacts" }, + { -1, NULL }, + { KEY_PAGEUP, "Calander" }, + { KEY_ENTER, "Center" }, + { -1, NULL }, /* GPIO 15 */ + { -1, NULL }, + { -1, NULL }, + { -1, NULL }, + { KEY_LEFT, "Left" }, + { KEY_RIGHT, "Right" }, /* GPIO 20 */ + { KEY_DOWN, "Down" }, + { KEY_UP, "Up" } +}; + +static irqreturn_t palmz31_keypad_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + input_report_key(button_dev, palmz31_buttons[IRQ_TO_GPIO(irq)].keycode, + GET_GPIO(IRQ_TO_GPIO(irq)) ? 0 : 1); + return IRQ_HANDLED; +} + +static int palmz31_buttons_probe(struct device *dev) +{ + int err = 0; + int i; + + //if(!machine_is_tunge2()) + // return -ENODEV; + + button_dev = input_allocate_device(); + button_dev->evbit[0] = BIT(EV_KEY); + for(i=0;i<MAX_BUTTONS;i++) { + if(palmz31_buttons[i].keycode >= 0) { + button_dev->keybit[LONG(palmz31_buttons[i].keycode)] |= + BIT(palmz31_buttons[i].keycode); + } + } + button_dev->name = "Palm Zire 31 buttons"; + button_dev->id.bustype = BUS_HOST; + input_register_device(button_dev); + + for(i=0;i<MAX_BUTTONS;i++) { + if(palmz31_buttons[i].keycode >= 0) { + err += request_irq(IRQ_GPIO(i), + palmz31_keypad_irq_handler, + SA_SAMPLE_RANDOM | SA_INTERRUPT, + "keypad", (void*)i); + set_irq_type(IRQ_GPIO(i), IRQT_BOTHEDGE); + } + } + + if(err) { + printk("err = %d\n", err); + } + + return 0; +} + +static int palmz31_buttons_remove (struct device *dev) +{ + int i; + for(i=0;i<MAX_BUTTONS;i++) { + if(palmz31_buttons[i].keycode >= 0) { + free_irq(IRQ_GPIO(i), (void*)i); + } + } + return 0; +} + +static struct device_driver palmz31_buttons_driver = { + .name = "palmz31-buttons", + .bus = &platform_bus_type, + .probe = palmz31_buttons_probe, + .remove = palmz31_buttons_remove, +#ifdef CONFIG_PM + .suspend = NULL, + .resume = NULL, +#endif +}; + +static int __init palmz31_buttons_init(void) +{ + //if(!machine_is_tunge2()) + // return -ENODEV; + + return driver_register(&palmz31_buttons_driver); +} + +static void __exit palmz31_buttons_exit(void) +{ + input_unregister_device(button_dev); + driver_unregister(&palmz31_buttons_driver); +} + +module_init(palmz31_buttons_init); +module_exit(palmz31_buttons_exit); + +MODULE_AUTHOR ("Scott Mansell <ph...@gm..."); +MODULE_DESCRIPTION ("Button support for Palm Zire 31"); +MODULE_LICENSE ("GPL"); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |