|
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.
|