]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
staging: iio: light: iqs253: Detect stylus always
authorSri Krishna chowdary <schowdary@nvidia.com>
Mon, 10 Feb 2014 13:02:45 +0000 (18:32 +0530)
committerSachin Nikam <snikam@nvidia.com>
Tue, 18 Feb 2014 10:03:01 +0000 (02:03 -0800)
Stylus detection should happen irrespective of AP is supended.

- Add work queue to detect stylus state at regular intervals of 2 secs
- send input event only on change in stylus state

Bug 1420230

Change-Id: Ie95ff724a438ca1f2e5d2bf406161d9e79b546ca
Signed-off-by: Sri Krishna chowdary <schowdary@nvidia.com>
Reviewed-on: http://git-master/r/365476
(cherry picked from commit 68198534ef64a64a1029bde81893c10d475eb2cd)
Reviewed-on: http://git-master/r/368241
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
drivers/staging/iio/light/iqs253.c

index 2305c4d79ec25b71932ca9add3f57278c4f0bcd4..7a87ccc0af3e93010109bf527d1fc036b44a352c 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/irqchip/tegra.h>
+#include <linux/input.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 #include <linux/iio/light/ls_sysfs.h>
@@ -98,6 +99,10 @@ struct iqs253_chip {
        struct regulator        *vddhi;
        u32                     using_regulator;
        struct lightsensor_spec *ls_spec;
+       struct workqueue_struct *wq;
+       struct delayed_work     dw;
+       struct input_dev        *idev;
+       u32                     stylus_inserted;
 };
 
 enum mode {
@@ -121,7 +126,7 @@ struct reg_val_pair reg_val_map[NUM_MODE][NUM_REG] = {
                { CH0_PTH, PROX_TH_CH0},
                { CH1_PTH, PROX_TH_CH1},
                { PROX_SETTINGS0, PROX_SETTING_NORMAL},
-               { ACTIVE_CHAN, PROXIMITY_ONLY},
+               { ACTIVE_CHAN, PROXIMITY_ONLY | STYLUS_ONLY},
                { DYCAL_CHANS, DISABLE_DYCAL},
                { EVENT_MODE_MASK, EVENT_PROX_ONLY}
        },
@@ -419,12 +424,89 @@ static SIMPLE_DEV_PM_OPS(iqs253_pm_ops, iqs253_suspend, iqs253_resume);
 #define IQS253_PM_OPS NULL
 #endif
 
+static void iqs253_stylus_detect_work(struct work_struct *ws)
+{
+       int ret;
+       struct iqs253_chip *chip;
+
+       chip = container_of(ws, struct iqs253_chip, dw.work);
+
+       if (!chip->using_regulator) {
+               ret = regulator_enable(chip->vddhi);
+               if (ret)
+                       goto finish;
+               chip->using_regulator = true;
+       }
+
+       if (chip->mode != NORMAL_MODE) {
+               ret = iqs253_set(chip, NORMAL_MODE);
+               if (ret)
+                       goto finish;
+
+               ret = iqs253_i2c_read_byte(chip, PROX_STATUS);
+               chip->stylus_inserted = (ret & STYLUS_ONLY);
+               input_report_switch(chip->idev, SW_TABLET_MODE,
+                                       !chip->stylus_inserted);
+               input_sync(chip->idev);
+       }
+
+       ret = iqs253_i2c_read_byte(chip, PROX_STATUS);
+       chip->value = -1;
+       if (ret >= 0) {
+               ret &= STYLUS_ONLY;
+               if (ret && !chip->stylus_inserted) {
+                       chip->stylus_inserted = true;
+                       input_report_switch(chip->idev, SW_TABLET_MODE, false);
+                       input_sync(chip->idev);
+               } else if (!ret && chip->stylus_inserted) {
+                       chip->stylus_inserted = false;
+                       input_report_switch(chip->idev, SW_TABLET_MODE, true);
+                       input_sync(chip->idev);
+               }
+       }
+
+finish:
+       queue_delayed_work(chip->wq, &chip->dw, msecs_to_jiffies(2000));
+}
+
+static struct input_dev *iqs253_stylus_input_init(struct iqs253_chip *chip)
+{
+       int ret;
+       struct input_dev *idev = input_allocate_device();
+       if (!idev)
+               return NULL;
+
+       idev->name = "stylus_detect";
+       set_bit(EV_SW, idev->evbit);
+       input_set_capability(idev, EV_SW, SW_TABLET_MODE);
+       ret = input_register_device(idev);
+       if (ret) {
+               input_free_device(idev);
+               return ERR_PTR(ret);
+       }
+
+       chip->wq = create_singlethread_workqueue("iqs253");
+       if (!chip->wq) {
+               dev_err(&chip->client->dev, "unable to create work queue\n");
+               input_unregister_device(idev);
+               input_free_device(idev);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       INIT_DELAYED_WORK(&chip->dw, iqs253_stylus_detect_work);
+
+       queue_delayed_work(chip->wq, &chip->dw, 0);
+
+       return idev;
+}
+
 static int iqs253_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        int ret;
        struct iqs253_chip *iqs253_chip;
        struct iio_dev *indio_dev;
+       struct input_dev *idev;
        int rdy_gpio = -1, wake_gpio = -1, sar_gpio = -1;
 
        rdy_gpio = of_get_named_gpio(client->dev.of_node, "rdy-gpio", 0);
@@ -526,6 +608,10 @@ static int iqs253_probe(struct i2c_client *client,
                goto err_gpio_request;
        }
 
+       idev = iqs253_stylus_input_init(iqs253_chip);
+       if (IS_ERR_OR_NULL(idev))
+               goto err_gpio_request;
+       iqs253_chip->idev = idev;
 
        dev_info(&client->dev, "devname:%s func:%s line:%d probe success\n",
                        id->name, __func__, __LINE__);
@@ -548,6 +634,9 @@ static int iqs253_remove(struct i2c_client *client)
        struct iio_dev *indio_dev = i2c_get_clientdata(client);
        struct iqs253_chip *chip = iio_priv(indio_dev);
        gpio_free(chip->rdy_gpio);
+       destroy_workqueue(chip->wq);
+       input_unregister_device(chip->idev);
+       input_free_device(chip->idev);
        iio_device_unregister(indio_dev);
        iio_device_free(indio_dev);
        return 0;