These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / input / misc / rotary_encoder.c
index f27f81e..8aee719 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/of_gpio.h>
+#include <linux/pm.h>
 
 #define DRV_NAME "rotary-encoder"
 
@@ -142,6 +143,55 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id)
+{
+       struct rotary_encoder *encoder = dev_id;
+       unsigned char sum;
+       int state;
+
+       state = rotary_encoder_get_state(encoder->pdata);
+
+       /*
+        * We encode the previous and the current state using a byte.
+        * The previous state in the MSB nibble, the current state in the LSB
+        * nibble. Then use a table to decide the direction of the turn.
+        */
+       sum = (encoder->last_stable << 4) + state;
+       switch (sum) {
+       case 0x31:
+       case 0x10:
+       case 0x02:
+       case 0x23:
+               encoder->dir = 0; /* clockwise */
+               break;
+
+       case 0x13:
+       case 0x01:
+       case 0x20:
+       case 0x32:
+               encoder->dir = 1; /* counter-clockwise */
+               break;
+
+       default:
+               /*
+                * Ignore all other values. This covers the case when the
+                * state didn't change (a spurious interrupt) and the
+                * cases where the state changed by two steps, making it
+                * impossible to tell the direction.
+                *
+                * In either case, don't report any event and save the
+                * state for later.
+                */
+               goto out;
+       }
+
+       rotary_encoder_report_event(encoder);
+
+out:
+       encoder->last_stable = state;
+       return IRQ_HANDLED;
+}
+
 #ifdef CONFIG_OF
 static const struct of_device_id rotary_encoder_of_match[] = {
        { .compatible = "rotary-encoder", },
@@ -156,6 +206,7 @@ static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct devic
        struct device_node *np = dev->of_node;
        struct rotary_encoder_platform_data *pdata;
        enum of_gpio_flags flags;
+       int error;
 
        if (!of_id || !np)
                return NULL;
@@ -174,12 +225,27 @@ static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct devic
        pdata->gpio_b = of_get_gpio_flags(np, 1, &flags);
        pdata->inverted_b = flags & OF_GPIO_ACTIVE_LOW;
 
-       pdata->relative_axis = !!of_get_property(np,
-                                       "rotary-encoder,relative-axis", NULL);
-       pdata->rollover = !!of_get_property(np,
-                                       "rotary-encoder,rollover", NULL);
-       pdata->half_period = !!of_get_property(np,
-                                       "rotary-encoder,half-period", NULL);
+       pdata->relative_axis =
+               of_property_read_bool(np, "rotary-encoder,relative-axis");
+       pdata->rollover = of_property_read_bool(np, "rotary-encoder,rollover");
+
+       error = of_property_read_u32(np, "rotary-encoder,steps-per-period",
+                                    &pdata->steps_per_period);
+       if (error) {
+               /*
+                * The 'half-period' property has been deprecated, you must use
+                * 'steps-per-period' and set an appropriate value, but we still
+                * need to parse it to maintain compatibility.
+                */
+               if (of_property_read_bool(np, "rotary-encoder,half-period")) {
+                       pdata->steps_per_period = 2;
+               } else {
+                       /* Fallback to one step per period behavior */
+                       pdata->steps_per_period = 1;
+               }
+       }
+
+       pdata->wakeup_source = of_property_read_bool(np, "wakeup-source");
 
        return pdata;
 }
@@ -250,12 +316,23 @@ static int rotary_encoder_probe(struct platform_device *pdev)
        encoder->irq_a = gpio_to_irq(pdata->gpio_a);
        encoder->irq_b = gpio_to_irq(pdata->gpio_b);
 
-       /* request the IRQs */
-       if (pdata->half_period) {
+       switch (pdata->steps_per_period) {
+       case 4:
+               handler = &rotary_encoder_quarter_period_irq;
+               encoder->last_stable = rotary_encoder_get_state(pdata);
+               break;
+       case 2:
                handler = &rotary_encoder_half_period_irq;
                encoder->last_stable = rotary_encoder_get_state(pdata);
-       } else {
+               break;
+       case 1:
                handler = &rotary_encoder_irq;
+               break;
+       default:
+               dev_err(dev, "'%d' is not a valid steps-per-period value\n",
+                       pdata->steps_per_period);
+               err = -EINVAL;
+               goto exit_free_gpio_b;
        }
 
        err = request_irq(encoder->irq_a, handler,
@@ -280,6 +357,8 @@ static int rotary_encoder_probe(struct platform_device *pdev)
                goto exit_free_irq_b;
        }
 
+       device_init_wakeup(&pdev->dev, pdata->wakeup_source);
+
        platform_set_drvdata(pdev, encoder);
 
        return 0;
@@ -306,6 +385,8 @@ static int rotary_encoder_remove(struct platform_device *pdev)
        struct rotary_encoder *encoder = platform_get_drvdata(pdev);
        const struct rotary_encoder_platform_data *pdata = encoder->pdata;
 
+       device_init_wakeup(&pdev->dev, false);
+
        free_irq(encoder->irq_a, encoder);
        free_irq(encoder->irq_b, encoder);
        gpio_free(pdata->gpio_a);
@@ -320,11 +401,41 @@ static int rotary_encoder_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int rotary_encoder_suspend(struct device *dev)
+{
+       struct rotary_encoder *encoder = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev)) {
+               enable_irq_wake(encoder->irq_a);
+               enable_irq_wake(encoder->irq_b);
+       }
+
+       return 0;
+}
+
+static int rotary_encoder_resume(struct device *dev)
+{
+       struct rotary_encoder *encoder = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev)) {
+               disable_irq_wake(encoder->irq_a);
+               disable_irq_wake(encoder->irq_b);
+       }
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(rotary_encoder_pm_ops,
+                rotary_encoder_suspend, rotary_encoder_resume);
+
 static struct platform_driver rotary_encoder_driver = {
        .probe          = rotary_encoder_probe,
        .remove         = rotary_encoder_remove,
        .driver         = {
                .name   = DRV_NAME,
+               .pm     = &rotary_encoder_pm_ops,
                .of_match_table = of_match_ptr(rotary_encoder_of_match),
        }
 };