@@ -30,10 +30,12 @@ struct gpio_button_data {
struct input_dev *input;
struct timer_list timer;
struct work_struct work;
+ u8 state; /* event state */
};
struct gpio_keys_drvdata {
struct input_dev *input;
+ struct gpio_keys_platform_data *pdata;
struct gpio_button_data data[0];
};
@@ -73,6 +75,69 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static int gpio_keys_get_event_state(struct input_dev *dev,
+ struct input_event_state *st)
+{
+ const struct gpio_keys_drvdata *ddata = input_get_drvdata(dev);
+ const struct gpio_keys_platform_data *pdata = ddata->pdata;
+ int i;
+
+ for (i = 0; i < pdata->nbuttons; i++) {
+ const struct gpio_keys_button *button = &pdata->buttons[i];
+ const struct gpio_button_data *bdata = &ddata->data[i];
+
+ if (button->code == st->code && button->type == st->type) {
+ st->state = bdata->state;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+/*
+ * This function is used to enable/disable hardware interrupts from
+ * GPIO lines that are aggregated into single gpio-keys input device.
+ */
+static int gpio_keys_set_event_state(struct input_dev *dev,
+ const struct input_event_state *st)
+{
+ struct gpio_keys_drvdata *ddata = input_get_drvdata(dev);
+ struct gpio_keys_platform_data *pdata = ddata->pdata;
+ int i;
+
+ for (i = 0; i < pdata->nbuttons; i++) {
+ struct gpio_keys_button *button = &pdata->buttons[i];
+ struct gpio_button_data *bdata = &ddata->data[i];
+
+ if (button->code == st->code && button->type == st->type) {
+ switch (st->state) {
+ case EVENT_STATE_DISABLE:
+ if (bdata->state == EVENT_STATE_ENABLE) {
+ bdata->state = EVENT_STATE_DISABLE;
+ /*
+ * Disable physical irq line. This is
+ * enough also for keeping device from
+ * waking up during sleep so no need
+ * to change wakeup flags for this irq.
+ */
+ disable_irq(gpio_to_irq(button->gpio));
+ }
+ break;
+ case EVENT_STATE_ENABLE:
+ if (bdata->state == EVENT_STATE_DISABLE) {
+ bdata->state = EVENT_STATE_ENABLE;
+ enable_irq(gpio_to_irq(button->gpio));
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
static int __devinit gpio_keys_setup_key(struct device *dev,
struct gpio_button_data *bdata,
struct gpio_keys_button *button)
@@ -154,11 +219,19 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
input->id.product = 0x0001;
input->id.version = 0x0100;
+ /*
+ * We support setting/getting event state ioctl.
+ */
+ input->get_event_state = gpio_keys_get_event_state;
+ input->set_event_state = gpio_keys_set_event_state;
+ input_set_drvdata(input, ddata);
+
/* Enable auto repeat feature of Linux input subsystem */
if (pdata->rep)
__set_bit(EV_REP, input->evbit);
ddata->input = input;
+ ddata->pdata = pdata;
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
@@ -167,6 +240,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
bdata->input = input;
bdata->button = button;
+ bdata->state = EVENT_STATE_ENABLE; /* enabled by default */
error = gpio_keys_setup_key(dev, bdata, button);
if (error)
@@ -200,6 +274,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
fail1:
+ input_set_drvdata(input, NULL);
input_free_device(input);
kfree(ddata);