diff options
Diffstat (limited to 'drivers/misc/m4sensorhub_als.c')
| -rw-r--r-- | drivers/misc/m4sensorhub_als.c | 118 | 
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)); |