aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAndy Green <andy@openmoko.com>2008-11-21 11:56:56 +0000
committerAndy Green <agreen@pads.home.warmcat.com>2008-11-21 11:56:56 +0000
commit979088837bfa0922c6cd551a9095a18988d94705 (patch)
tree40ea0f7fa50d79a77ac7053e79613beca25b3e27 /drivers
parentfffa54a4524f487c0fc438e2b210b2606015be7f (diff)
uplevel-neo1973kbd-gta03-compatibility.patch
Signed-off-by: Andy Green <andy@openmoko.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/keyboard/neo1973kbd.c202
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: