summaryrefslogtreecommitdiff
path: root/drivers/misc/m4sensorhub_als.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/m4sensorhub_als.c')
-rw-r--r--drivers/misc/m4sensorhub_als.c118
1 files changed, 107 insertions, 11 deletions
diff --git a/drivers/misc/m4sensorhub_als.c b/drivers/misc/m4sensorhub_als.c
index 3f61edefff2..6445d9f0181 100644
--- a/drivers/misc/m4sensorhub_als.c
+++ b/drivers/misc/m4sensorhub_als.c
@@ -28,12 +28,21 @@
#include <linux/m4sensorhub.h>
#include <linux/input.h>
#include <linux/slab.h>
+#include <linux/delay.h>
+#ifdef CONFIG_WAKEUP_SOURCE_NOTIFY
+#include <linux/notifier.h>
+#include <linux/als_notify.h>
+#ifdef CONFIG_ALS_WHILE_CHARGING
+#include <linux/wakeup_source_notify.h>
+#endif /* CONFIG_ALS_WHILE_CHARGING */
+#endif
#define m4als_err(format, args...) KDEBUG(M4SH_ERROR, format, ## args)
#define M4ALS_DRIVER_NAME "m4sensorhub_als"
#define M4ALS_IRQ_ENABLED_BIT 0
+#define ALS_SAMPLERATE_WHILE_DOCKED 10 /* in seconds */
struct m4als_driver_data {
struct platform_device *pdev;
@@ -42,13 +51,39 @@ struct m4als_driver_data {
struct input_dev *indev;
struct delayed_work m4als_work;
+ /* Beware of changing this from uint16, check als_notify.h
+ since notifier uses values outside luminosity range for
+ conveying enable/disable status */
uint16_t luminosity;
int16_t samplerate;
int16_t latest_samplerate;
int16_t fastest_rate;
uint16_t status;
+#ifdef CONFIG_ALS_WHILE_CHARGING
+ struct notifier_block charger_nb;
+ bool chargerstatus;
+#endif
};
+#ifdef CONFIG_ALS_WHILE_CHARGING
+static int charger_notify(struct notifier_block *self,
+ unsigned long action, void *dev)
+{
+ struct m4als_driver_data *dd =
+ container_of(self, struct m4als_driver_data, charger_nb);
+ switch (action) {
+ case DISPLAY_WAKE_EVENT_DOCKON:
+ case DISPLAY_WAKE_EVENT_DOCKOFF:
+ dd->chargerstatus = (action == DISPLAY_WAKE_EVENT_DOCKON);
+ pr_info("%s: dd->chargerstatus is %d\n",
+ __func__, dd->chargerstatus);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+#endif
+
static void m4als_work_func(struct work_struct *work)
{
int err = 0;
@@ -81,8 +116,18 @@ static void m4als_work_func(struct work_struct *work)
dd->luminosity = luminosity;
- input_event(dd->indev, EV_MSC, MSC_RAW, dd->luminosity);
- input_sync(dd->indev);
+#ifdef CONFIG_ALS_WHILE_CHARGING
+ if (dd->chargerstatus == true) {
+ als_notify_subscriber(luminosity);
+ } else {
+ input_event(dd->indev, EV_MSC, MSC_RAW, dd->luminosity);
+ input_sync(dd->indev);
+ }
+#else
+ input_event(dd->indev, EV_MSC, MSC_RAW, dd->luminosity);
+ input_sync(dd->indev);
+#endif
+
if (dd->samplerate > 0)
queue_delayed_work(system_freezable_wq, &(dd->m4als_work),
msecs_to_jiffies(dd->samplerate));
@@ -101,6 +146,12 @@ static int m4als_set_samplerate(struct m4als_driver_data *dd, int16_t rate)
int err = 0;
int size = 0;
+#ifdef CONFIG_ALS_WHILE_CHARGING
+ if (rate == -1 && dd->chargerstatus == true) {
+ rate = ALS_SAMPLERATE_WHILE_DOCKED * 1000;
+ }
+#endif
+
if ((rate >= 0) && (rate <= dd->fastest_rate))
rate = dd->fastest_rate;
@@ -132,9 +183,17 @@ static int m4als_set_samplerate(struct m4als_driver_data *dd, int16_t rate)
}
cancel_delayed_work(&(dd->m4als_work));
dd->samplerate = rate;
- if (dd->samplerate > 0)
+ if (dd->samplerate > 0) {
queue_delayed_work(system_freezable_wq, &(dd->m4als_work),
msecs_to_jiffies(rate));
+#ifdef CONFIG_WAKEUP_SOURCE_NOTIFY
+ als_notify_subscriber(ALS_ENABLED);
+#endif
+ } else {
+#ifdef CONFIG_WAKEUP_SOURCE_NOTIFY
+ als_notify_subscriber(ALS_DISABLED);
+#endif
+ }
m4als_set_samplerate_fail:
return err;
@@ -153,6 +212,8 @@ static ssize_t m4als_setrate_store(struct device *dev,
int err = 0;
struct m4als_driver_data *dd = dev_get_drvdata(dev);
int value = 0;
+ int regsize = 0;
+ uint16_t luminosity = 0;
mutex_lock(&(dd->mutex));
@@ -175,6 +236,32 @@ static ssize_t m4als_setrate_store(struct device *dev,
goto m4als_enable_store_exit;
}
+ /* Read and send raw value for gesture wakeup */
+ msleep(120);
+ regsize = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_LIGHTSENSOR_SIGNAL);
+ if (regsize < 0) {
+ m4als_err("%s: Reading from invalid register %d.\n",
+ __func__, regsize);
+ err = regsize;
+ goto m4als_enable_store_exit;
+ }
+
+ err = m4sensorhub_reg_read(dd->m4, M4SH_REG_LIGHTSENSOR_SIGNAL,
+ (char *)&luminosity);
+ if (err < 0) {
+ m4als_err("%s: Failed to read luminosity data.\n", __func__);
+ goto m4als_enable_store_exit;
+ } else if (err != regsize) {
+ m4als_err("%s: Read %d bytes instead of %d.\n",
+ __func__, err, regsize);
+ goto m4als_enable_store_exit;
+ }
+
+ dd->luminosity = luminosity;
+
+ input_event(dd->indev, EV_MSC, MSC_RAW, dd->luminosity);
+ input_sync(dd->indev);
+
m4als_enable_store_exit:
if (err < 0)
m4als_err("%s: Failed with error code %d.\n", __func__, err);
@@ -304,12 +391,6 @@ static int m4als_driver_init(struct init_calldata *p_arg)
goto m4als_driver_init_fail;
}
- err = m4als_create_sysfs(dd);
- if (err < 0) {
- m4als_err("%s: Failed to create sysfs.\n", __func__);
- goto m4als_driver_init_sysfs_fail;
- }
-
INIT_DELAYED_WORK(&(dd->m4als_work), m4als_work_func);
err = m4sensorhub_panic_register(dd->m4, PANICHDL_ALS_RESTORE,
@@ -318,8 +399,6 @@ static int m4als_driver_init(struct init_calldata *p_arg)
KDEBUG(M4SH_ERROR, "Als panic callback register failed\n");
goto m4als_driver_init_exit;
-m4als_driver_init_sysfs_fail:
- input_unregister_device(dd->indev);
m4als_driver_init_fail:
m4als_err("%s: Init failed with error code %d.\n", __func__, err);
m4als_driver_init_exit:
@@ -359,8 +438,22 @@ static int m4als_probe(struct platform_device *pdev)
goto m4als_probe_fail;
}
+ err = m4als_create_sysfs(dd);
+ if (err < 0) {
+ m4als_err("%s: Failed to create sysfs.\n", __func__);
+ goto m4als_driver_init_sysfs_fail;
+ }
+
+#ifdef CONFIG_ALS_WHILE_CHARGING
+ dd->chargerstatus = false;
+ dd->charger_nb.notifier_call = charger_notify;
+ wakeup_source_register_notify(&dd->charger_nb);
+#endif
+
return 0;
+m4als_driver_init_sysfs_fail:
+ m4sensorhub_unregister_initcall(m4als_driver_init);
m4als_probe_fail:
mutex_destroy(&(dd->mutex));
kfree(dd);
@@ -377,6 +470,9 @@ static int __exit m4als_remove(struct platform_device *pdev)
cancel_delayed_work(&(dd->m4als_work));
m4als_remove_sysfs(dd);
m4sensorhub_unregister_initcall(m4als_driver_init);
+#ifdef CONFIG_ALS_WHILE_CHARGING
+ wakeup_source_unregister_notify(&dd->charger_nb);
+#endif
if (dd->indev != NULL)
input_unregister_device(dd->indev);
mutex_destroy(&(dd->mutex));