diff options
author | Andy Green <andy@openmoko.com> | 2008-11-21 11:56:56 +0000 |
---|---|---|
committer | Andy Green <agreen@pads.home.warmcat.com> | 2008-11-21 11:56:56 +0000 |
commit | 979088837bfa0922c6cd551a9095a18988d94705 (patch) | |
tree | 40ea0f7fa50d79a77ac7053e79613beca25b3e27 /drivers/input/keyboard | |
parent | fffa54a4524f487c0fc438e2b210b2606015be7f (diff) |
uplevel-neo1973kbd-gta03-compatibility.patch
Signed-off-by: Andy Green <andy@openmoko.com>
Diffstat (limited to 'drivers/input/keyboard')
-rw-r--r-- | drivers/input/keyboard/neo1973kbd.c | 202 |
1 files changed, 123 insertions, 79 deletions
diff --git a/drivers/input/keyboard/neo1973kbd.c b/drivers/input/keyboard/neo1973kbd.c index a6a213b309e..4d412e0b980 100644 --- a/drivers/input/keyboard/neo1973kbd.c +++ b/drivers/input/keyboard/neo1973kbd.c @@ -29,9 +29,9 @@ extern int global_inside_suspend; struct neo1973kbd { + struct platform_device *pdev; struct input_dev *input; struct device *cdev; - unsigned int suspended; struct work_struct work; int work_in_progress; int hp_irq_count_in_work; @@ -41,12 +41,59 @@ struct neo1973kbd { static struct class *neo1973kbd_switch_class; -#define HEADSET_SWITCH "headset" +enum keys { + NEO1973_KEY_AUX, /* GTA01 / 02 only */ + NEO1973_KEY_HOLD, + NEO1973_KEY_JACK, + NEO1973_KEY_PLUS, /* GTA03 only */ + NEO1973_KEY_MINUS, /* GTA03 only */ +}; + +struct neo1973kbd_key { + const char * name; + irqreturn_t (*isr)(int irq, void *dev_id); + int irq; + int input_key; +}; + +static irqreturn_t neo1973kbd_aux_irq(int irq, void *dev_id); +static irqreturn_t neo1973kbd_headphone_irq(int irq, void *dev_id); +static irqreturn_t neo1973kbd_default_key_irq(int irq, void *dev_id); + + +static struct neo1973kbd_key keys[] = { + [NEO1973_KEY_AUX] = { + .name = "Neo1973 AUX button", + .isr = neo1973kbd_aux_irq, + .input_key = KEY_PHONE, + }, + [NEO1973_KEY_HOLD] = { + .name = "Neo1973 HOLD button", + .isr = neo1973kbd_default_key_irq, + .input_key = KEY_PAUSE, + }, + [NEO1973_KEY_JACK] = { + .name = "Neo1973 Headphone jack", + .isr = neo1973kbd_headphone_irq, + }, + [NEO1973_KEY_PLUS] = { + .name = "GTA03 PLUS button", + .isr = neo1973kbd_default_key_irq, + .input_key = KEY_KPPLUS, + }, + [NEO1973_KEY_MINUS] = { + .name = "GTA03 MINUS button", + .isr = neo1973kbd_default_key_irq, + .input_key = KEY_KPMINUS, + }, +}; + static irqreturn_t neo1973kbd_aux_irq(int irq, void *dev_id) { - struct neo1973kbd *neo1973kbd_data = dev_id; - int key_pressed = !gpio_get_value(irq_to_gpio(irq)); + struct neo1973kbd *kbd = dev_id; + int key_pressed = !gpio_get_value( + kbd->pdev->resource[NEO1973_KEY_AUX].start); int *p = NULL; if (global_inside_suspend) @@ -55,40 +102,49 @@ static irqreturn_t neo1973kbd_aux_irq(int irq, void *dev_id) /* GTA02 has inverted sense level compared to GTA01 */ if (machine_is_neo1973_gta02()) key_pressed = !key_pressed; - input_report_key(neo1973kbd_data->input, KEY_PHONE, key_pressed); - input_sync(neo1973kbd_data->input); + input_report_key(kbd->input, KEY_PHONE, key_pressed); + input_sync(kbd->input); return IRQ_HANDLED; } -static irqreturn_t neo1973kbd_hold_irq(int irq, void *dev_id) +static irqreturn_t neo1973kbd_default_key_irq(int irq, void *dev_id) { - struct neo1973kbd *neo1973kbd_data = dev_id; + struct neo1973kbd *kbd = dev_id; + int n; - int key_pressed = gpio_get_value(irq_to_gpio(irq)); - input_report_key(neo1973kbd_data->input, KEY_PAUSE, key_pressed); - input_sync(neo1973kbd_data->input); + for (n = 0; n < ARRAY_SIZE(keys); n++) { + + if (irq != keys[n].irq) + continue; + + input_report_key(kbd->input, keys[n].input_key, + gpio_get_value(kbd->pdev->resource[n].start)); + input_sync(kbd->input); + } return IRQ_HANDLED; } + +static const char *event_array_jack[2][4] = { + [0] = { + "SWITCH_NAME=headset", + "SWITCH_STATE=0", + "EVENT=remove", + NULL + }, + [1] = { + "SWITCH_NAME=headset", + "SWITCH_STATE=1", + "EVENT=insert", + NULL + }, +}; + static void neo1973kbd_jack_event(struct device *dev, int num) { - char name_string[] = "SWITCH_NAME=" HEADSET_SWITCH; - char event_string[32]; - char state_string[32]; - char *envp[] = { name_string, state_string, event_string, NULL }; - - if (num) { - sprintf(state_string, "SWITCH_STATE=1"); - sprintf(event_string, "EVENT=insert"); - } - else { - sprintf(state_string, "SWITCH_STATE=0"); - sprintf(event_string, "EVENT=remove"); - } - - kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); + kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, (char **)event_array_jack[!!num]); } @@ -97,6 +153,7 @@ static void neo1973kbd_debounce_jack(struct work_struct *work) struct neo1973kbd *kbd = container_of(work, struct neo1973kbd, work); unsigned long flags; int loop = 0; + int level; do { /* @@ -111,11 +168,10 @@ static void neo1973kbd_debounce_jack(struct work_struct *work) * no new interrupts on jack for 100ms... * ok we will report it */ - input_report_switch(kbd->input, SW_HEADPHONE_INSERT, - gpio_get_value(irq_to_gpio(kbd->jack_irq))); + level = gpio_get_value(kbd->pdev->resource[NEO1973_KEY_JACK].start); + input_report_switch(kbd->input, SW_HEADPHONE_INSERT, level); input_sync(kbd->input); - neo1973kbd_jack_event(kbd->cdev, - gpio_get_value(irq_to_gpio(kbd->jack_irq))); + neo1973kbd_jack_event(kbd->cdev, level); /* * we go around the outer loop again if we detect that more * interrupts came while we are servicing here. But we have @@ -173,19 +229,11 @@ static irqreturn_t neo1973kbd_headphone_irq(int irq, void *dev_id) #ifdef CONFIG_PM static int neo1973kbd_suspend(struct platform_device *dev, pm_message_t state) { - struct neo1973kbd *neo1973kbd = platform_get_drvdata(dev); - - neo1973kbd->suspended = 1; - return 0; } static int neo1973kbd_resume(struct platform_device *dev) { - struct neo1973kbd *neo1973kbd = platform_get_drvdata(dev); - - neo1973kbd->suspended = 0; - return 0; } #else @@ -204,7 +252,7 @@ static ssize_t neo1973kbd_switch_state_show(struct device *dev, { struct neo1973kbd *kbd = dev_get_drvdata(dev); return sprintf(buf, "%d\n", - gpio_get_value(irq_to_gpio(kbd->jack_irq)) ? 1 : 0); + gpio_get_value(kbd->pdev->resource[NEO1973_KEY_JACK].start)); } static DEVICE_ATTR(name, S_IRUGO , neo1973kbd_switch_name_show, NULL); @@ -214,7 +262,9 @@ static int neo1973kbd_probe(struct platform_device *pdev) { struct neo1973kbd *neo1973kbd; struct input_dev *input_dev; - int rc, irq_aux, irq_hold, irq_jack; + int rc; + int irq; + int n; neo1973kbd = kzalloc(sizeof(struct neo1973kbd), GFP_KERNEL); input_dev = input_allocate_device(); @@ -224,19 +274,9 @@ static int neo1973kbd_probe(struct platform_device *pdev) return -ENOMEM; } - if (pdev->resource[0].flags != 0) - return -EINVAL; - - irq_aux = gpio_to_irq(pdev->resource[0].start); - if (irq_aux < 0) - return -EINVAL; - - irq_hold = gpio_to_irq(pdev->resource[1].start); - if (irq_hold < 0) - return -EINVAL; + neo1973kbd->pdev = pdev; - irq_jack = gpio_to_irq(pdev->resource[2].start); - if (irq_jack < 0) + if (pdev->resource[0].flags != 0) return -EINVAL; platform_set_drvdata(pdev, neo1973kbd); @@ -263,8 +303,8 @@ static int neo1973kbd_probe(struct platform_device *pdev) goto out_register; neo1973kbd->cdev = device_create(neo1973kbd_switch_class, - &pdev->dev, 0, neo1973kbd, HEADSET_SWITCH); - if(unlikely(IS_ERR(neo1973kbd->cdev))) { + &pdev->dev, 0, neo1973kbd, "headset"); + if (unlikely(IS_ERR(neo1973kbd->cdev))) { rc = PTR_ERR(neo1973kbd->cdev); goto out_device_create; } @@ -277,11 +317,33 @@ static int neo1973kbd_probe(struct platform_device *pdev) if(rc) goto out_device_create_file; - if (request_irq(irq_aux, neo1973kbd_aux_irq, IRQF_DISABLED | - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - "Neo1973 AUX button", neo1973kbd)) { - dev_err(&pdev->dev, "Can't get IRQ %u\n", irq_aux); - goto out_aux; + /* register GPIO IRQs */ + + for(n = 0; n < ARRAY_SIZE(keys); n++) { + + if (!pdev->resource[0].start) + continue; + + irq = gpio_to_irq(pdev->resource[n].start); + if (irq < 0) + continue; + + if (request_irq(irq, keys[n].isr, IRQF_DISABLED | + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + keys[n].name, neo1973kbd)) { + dev_err(&pdev->dev, "Can't get IRQ %u\n", irq); + + /* unwind any irq registrations and fail */ + + while (n > 0) { + n--; + free_irq(gpio_to_irq(pdev->resource[n].start), + neo1973kbd); + } + goto out_device_create_file; + } + + keys[n].irq = irq; } /* @@ -289,30 +351,12 @@ static int neo1973kbd_probe(struct platform_device *pdev) * resume by AUX. */ if (machine_is_neo1973_gta01()) - enable_irq_wake(irq_aux); + enable_irq_wake(keys[NEO1973_KEY_AUX].irq); - if (request_irq(irq_hold, neo1973kbd_hold_irq, IRQF_DISABLED | - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - "Neo1973 HOLD button", neo1973kbd)) { - dev_err(&pdev->dev, "Can't get IRQ %u\n", irq_hold); - goto out_hold; - } - - if (request_irq(irq_jack, neo1973kbd_headphone_irq, IRQF_DISABLED | - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - "Neo1973 Headphone Jack", neo1973kbd)) { - dev_err(&pdev->dev, "Can't get IRQ %u\n", irq_jack); - goto out_jack; - } - enable_irq_wake(irq_jack); + enable_irq_wake(keys[NEO1973_KEY_JACK].irq); return 0; -out_jack: - free_irq(irq_hold, neo1973kbd); -out_hold: - free_irq(irq_aux, neo1973kbd); -out_aux: out_device_create_file: device_unregister(neo1973kbd->cdev); out_device_create: |