#include <linux/interrupt.h>
#include <linux/irq.h>
#include <mach/gpio.h>
+#include <linux/earlysuspend.h>
+#include <linux/wakelock.h>
+#include <plat/board-mapphone.h>
#define PREFIX "debounce: "
+#define PADCONF_PULL_UP ( OMAP343X_PADCONF_OFF_WAKEUP_ENABLED | \
+ OMAP343X_PADCONF_INPUT_ENABLED | \
+ OMAP343X_PADCONF_PULL_UP | \
+ OMAP343X_PADCONF_PUD_ENABLED | \
+ OMAP343X_PADCONF_MUXMODE4 )
+
+#define PADCONF_PULL_DOWN ( OMAP343X_PADCONF_OFF_WAKEUP_ENABLED | \
+ OMAP343X_PADCONF_INPUT_ENABLED | \
+ OMAP343X_PADCONF_PULL_DOWN | \
+ OMAP343X_PADCONF_PUD_ENABLED | \
+ OMAP343X_PADCONF_MUXMODE4 )
+
+#define OMAP_CTRL_REGADDR(reg) (OMAP2_L4_IO_ADDRESS(OMAP343X_CTRL_BASE) + (reg))
+
static unsigned old_flags = 0;
static ktime_t old_debounce_delay;
static ktime_t old_settle_time;
static int hw_debounce = 0;
static int hw_debounce_time = 0;
+struct gpio_event {
+ struct gpio_event_input_devs *input_devs;
+ const struct gpio_event_platform_data *info;
+ struct early_suspend early_suspend;
+ void *state[0];
+};
+
+struct gpio_kp {
+ struct gpio_event_input_devs *input_devs;
+ struct gpio_event_matrix_info *keypad_info;
+ struct hrtimer timer;
+ struct wake_lock wake_lock;
+ int current_output;
+ unsigned int use_irq:1;
+ unsigned int key_state_changed:1;
+ unsigned int last_key_state_changed:1;
+ unsigned int some_keys_pressed:2;
+ unsigned long keys_pressed[0];
+};
+
+static struct gpio_kp *gpio_kp_state = NULL;
+
static int find_ms2_dev(struct device *dev, void *data)
{
if (!strncmp((char*)data, dev_name(dev), strlen((char*)data))) {
static ssize_t store_active_high_flag(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
unsigned flag;
+ int i;
if (!gpio_evmi)
return -ENODEV;
if (flag) {
gpio_evmi->flags |= GPIOKPF_ACTIVE_HIGH;
+ for (i = 0x7a; i <= 0x88; i += 2) {
+ __raw_writew(PADCONF_PULL_DOWN, OMAP_CTRL_REGADDR(i));
+ }
} else {
gpio_evmi->flags &= ~GPIOKPF_ACTIVE_HIGH;
+ for (i = 0x7a; i <= 0x88; i += 2) {
+ __raw_writew(PADCONF_PULL_UP, OMAP_CTRL_REGADDR(i));
+ }
}
set_irq_types();
{
int ret;
- printk(KERN_INFO PREFIX "0x%x\n", index);
+ printk(KERN_INFO PREFIX "key_state_changed: %d, last_key_state_changed: %d, some_keys_pressed: %d\n",
+ gpio_kp_state->key_state_changed,
+ gpio_kp_state->last_key_state_changed,
+ gpio_kp_state->some_keys_pressed);
ret = old_sw_fixup(index);
if (!ret)
- printk(KERN_INFO PREFIX "IGNORED!\n");
+ printk(KERN_INFO PREFIX "Index 0x%x ignored!\n", index);
return ret;
}
static int __init debounce_init(void)
{
struct device *event_dev = NULL;
+ struct platform_device *pdev = NULL;
struct gpio_event_platform_data *gpio_epd;
struct gpio_event_info *gpio_ei;
+ struct gpio_event *gpio_e;
int err = 0;
+ int i;
printk(KERN_INFO PREFIX "Searching for " GPIO_EVENT_DEV_NAME "...\n");
event_dev = device_find_child(&platform_bus, GPIO_EVENT_DEV_NAME, find_ms2_dev);
if (event_dev == NULL)
return -ENODEV;
-
+
+ pdev = container_of(event_dev, struct platform_device, dev);
+ if (pdev == NULL)
+ return -ENODEV;
+
gpio_epd = (struct gpio_event_platform_data*)event_dev->platform_data;
printk(KERN_INFO PREFIX "And there is a %s connected...\n", gpio_epd->name);
if (strcmp(gpio_epd->name, "sholes-keypad"))
gpio_ei = (struct gpio_event_info*)gpio_epd->info[0];
gpio_evmi = container_of(gpio_ei, struct gpio_event_matrix_info, info);
+ gpio_e = platform_get_drvdata(pdev);
+ printk(KERN_INFO PREFIX "Number of states: %d\n", gpio_e->info->info_count);
+
+ /* Search for correct gpio_event state */
+ for (i = 0; i < gpio_e->info->info_count; i++) {
+ if (gpio_e->info->info[i]->func == gpio_ei->func) {
+ printk(KERN_INFO PREFIX "Keypad state: %d\n", i);
+ gpio_kp_state = gpio_e->state[i];
+ }
+ }
+
+ if (!gpio_kp_state) {
+ printk(KERN_ERR PREFIX "Can't determine correct keypad state!\n");
+ return -ENODEV;
+ }
+
+ printk(KERN_INFO PREFIX "kp_use_irq: %d\n", gpio_kp_state->use_irq);
+#if 0
+ gpio_kp_state->use_irq=0;
+ hrtimer_start(&(gpio_kp_state->timer), gpio_evmi->poll_time, HRTIMER_MODE_REL);
+ printk(KERN_INFO PREFIX "kp_use_irq: %d\n", gpio_kp_state->use_irq);
+#endif
+
err = device_register(&debounce_device);
if (err) {
return err;
static void __exit debounce_exit(void)
{
+ int i;
+
if (gpio_evmi) {
if (gpio_evmi->debounce_delay.tv.nsec != old_debounce_delay.tv.nsec) {
printk(KERN_INFO PREFIX "Restoring debounce_delay\n");
printk(KERN_INFO PREFIX "Restoring flags\n");
gpio_evmi->flags = old_flags;
printk(KERN_INFO PREFIX "flags: 0x%x\n", gpio_evmi->flags);
+ if (gpio_evmi->flags & GPIOKPF_ACTIVE_HIGH) {
+ for (i = 0x7a; i <= 0x88; i += 2) {
+ __raw_writew(PADCONF_PULL_DOWN, OMAP_CTRL_REGADDR(i));
+ }
+ } else {
+ for (i = 0x7a; i <= 0x88; i += 2) {
+ __raw_writew(PADCONF_PULL_UP, OMAP_CTRL_REGADDR(i));
+ }
+ }
set_irq_types();
}
gpio_evmi->settle_time = old_settle_time;