2012-09-05 13:56:00 +01:00
/*
* HID Sensors Driver
* Copyright ( c ) 2012 , Intel Corporation .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License along with
* this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin St - Fifth Floor , Boston , MA 02110 - 1301 USA .
*
*/
# include <linux/device.h>
# include <linux/platform_device.h>
# include <linux/module.h>
# include <linux/interrupt.h>
# include <linux/irq.h>
# include <linux/slab.h>
2015-01-07 10:55:53 -08:00
# include <linux/delay.h>
2012-09-05 13:56:00 +01:00
# include <linux/hid-sensor-hub.h>
# include <linux/iio/iio.h>
# include <linux/iio/trigger.h>
# include <linux/iio/sysfs.h>
# include "hid-sensor-trigger.h"
2015-01-07 10:55:53 -08:00
static int _hid_sensor_power_state ( struct hid_sensor_common * st , bool state )
2012-09-05 13:56:00 +01:00
{
int state_val ;
2013-11-27 22:19:00 +00:00
int report_val ;
2015-01-07 10:55:53 -08:00
s32 poll_value = 0 ;
2012-09-05 13:56:00 +01:00
2013-09-18 18:13:00 +01:00
if ( state ) {
2015-06-01 16:36:27 -07:00
if ( ! atomic_read ( & st - > user_requested_state ) )
return 0 ;
2013-09-18 18:13:00 +01:00
if ( sensor_hub_device_open ( st - > hsdev ) )
return - EIO ;
2014-04-19 00:22:00 +01:00
atomic_inc ( & st - > data_ready ) ;
2014-01-23 18:50:22 -08:00
state_val = hid_sensor_get_usage_index ( st - > hsdev ,
st - > power_state . report_id ,
st - > power_state . index ,
HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM ) ;
report_val = hid_sensor_get_usage_index ( st - > hsdev ,
st - > report_state . report_id ,
st - > report_state . index ,
HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM ) ;
2015-01-07 10:55:53 -08:00
poll_value = hid_sensor_read_poll_value ( st ) ;
2013-11-27 22:19:00 +00:00
} else {
2015-06-01 16:36:27 -07:00
int val ;
val = atomic_dec_if_positive ( & st - > data_ready ) ;
if ( val < 0 )
2014-04-19 00:22:00 +01:00
return 0 ;
2015-06-01 16:36:27 -07:00
2013-09-18 18:13:00 +01:00
sensor_hub_device_close ( st - > hsdev ) ;
2014-01-23 18:50:22 -08:00
state_val = hid_sensor_get_usage_index ( st - > hsdev ,
st - > power_state . report_id ,
st - > power_state . index ,
HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM ) ;
report_val = hid_sensor_get_usage_index ( st - > hsdev ,
st - > report_state . report_id ,
st - > report_state . index ,
HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM ) ;
2013-11-27 22:19:00 +00:00
}
2014-01-23 18:50:22 -08:00
if ( state_val > = 0 ) {
state_val + = st - > power_state . logical_minimum ;
sensor_hub_set_feature ( st - > hsdev , st - > power_state . report_id ,
2015-02-19 15:35:26 -08:00
st - > power_state . index , sizeof ( state_val ) ,
& state_val ) ;
2014-01-23 18:50:22 -08:00
}
2012-09-05 13:56:00 +01:00
2014-01-23 18:50:22 -08:00
if ( report_val > = 0 ) {
report_val + = st - > report_state . logical_minimum ;
sensor_hub_set_feature ( st - > hsdev , st - > report_state . report_id ,
2015-02-19 15:35:26 -08:00
st - > report_state . index ,
sizeof ( report_val ) ,
& report_val ) ;
2014-01-23 18:50:22 -08:00
}
2012-09-05 13:56:00 +01:00
2014-05-19 12:19:00 +01:00
sensor_hub_get_feature ( st - > hsdev , st - > power_state . report_id ,
2015-02-19 15:35:25 -08:00
st - > power_state . index ,
sizeof ( state_val ) , & state_val ) ;
2015-01-07 10:55:53 -08:00
if ( state & & poll_value )
msleep_interruptible ( poll_value * 2 ) ;
2012-09-05 13:56:00 +01:00
return 0 ;
}
2014-04-19 00:22:00 +01:00
EXPORT_SYMBOL ( hid_sensor_power_state ) ;
2015-01-07 10:55:53 -08:00
int hid_sensor_power_state ( struct hid_sensor_common * st , bool state )
{
2015-06-01 16:36:27 -07:00
2015-01-07 10:55:53 -08:00
# ifdef CONFIG_PM
int ret ;
2015-06-01 16:36:27 -07:00
atomic_set ( & st - > user_requested_state , state ) ;
2015-01-07 10:55:53 -08:00
if ( state )
ret = pm_runtime_get_sync ( & st - > pdev - > dev ) ;
else {
pm_runtime_mark_last_busy ( & st - > pdev - > dev ) ;
ret = pm_runtime_put_autosuspend ( & st - > pdev - > dev ) ;
}
if ( ret < 0 ) {
if ( state )
pm_runtime_put_noidle ( & st - > pdev - > dev ) ;
return ret ;
}
2016-04-14 21:36:40 +02:00
return 0 ;
2015-01-07 10:55:53 -08:00
# else
2015-06-01 16:36:27 -07:00
atomic_set ( & st - > user_requested_state , state ) ;
2015-01-07 10:55:53 -08:00
return _hid_sensor_power_state ( st , state ) ;
# endif
}
2016-08-15 12:12:47 -07:00
static void hid_sensor_set_power_work ( struct work_struct * work )
{
struct hid_sensor_common * attrb = container_of ( work ,
struct hid_sensor_common ,
work ) ;
_hid_sensor_power_state ( attrb , true ) ;
}
2014-04-19 00:22:00 +01:00
static int hid_sensor_data_rdy_trigger_set_state ( struct iio_trigger * trig ,
bool state )
{
return hid_sensor_power_state ( iio_trigger_get_drvdata ( trig ) , state ) ;
}
2012-09-05 13:56:00 +01:00
2013-10-30 22:48:00 +00:00
void hid_sensor_remove_trigger ( struct hid_sensor_common * attrb )
2012-09-05 13:56:00 +01:00
{
2016-08-15 12:12:47 -07:00
cancel_work_sync ( & attrb - > work ) ;
2013-10-30 22:48:00 +00:00
iio_trigger_unregister ( attrb - > trigger ) ;
iio_trigger_free ( attrb - > trigger ) ;
2012-09-05 13:56:00 +01:00
}
EXPORT_SYMBOL ( hid_sensor_remove_trigger ) ;
static const struct iio_trigger_ops hid_sensor_trigger_ops = {
. owner = THIS_MODULE ,
. set_trigger_state = & hid_sensor_data_rdy_trigger_set_state ,
} ;
int hid_sensor_setup_trigger ( struct iio_dev * indio_dev , const char * name ,
2012-12-15 12:45:00 +00:00
struct hid_sensor_common * attrb )
2012-09-05 13:56:00 +01:00
{
int ret ;
struct iio_trigger * trig ;
trig = iio_trigger_alloc ( " %s-dev%d " , name , indio_dev - > id ) ;
if ( trig = = NULL ) {
dev_err ( & indio_dev - > dev , " Trigger Allocate Failed \n " ) ;
ret = - ENOMEM ;
goto error_ret ;
}
trig - > dev . parent = indio_dev - > dev . parent ;
2013-03-25 08:58:00 +00:00
iio_trigger_set_drvdata ( trig , attrb ) ;
2012-09-05 13:56:00 +01:00
trig - > ops = & hid_sensor_trigger_ops ;
ret = iio_trigger_register ( trig ) ;
if ( ret ) {
dev_err ( & indio_dev - > dev , " Trigger Register Failed \n " ) ;
goto error_free_trig ;
}
2014-08-22 21:48:00 +01:00
attrb - > trigger = trig ;
indio_dev - > trig = iio_trigger_get ( trig ) ;
2012-09-05 13:56:00 +01:00
2015-01-07 10:55:53 -08:00
ret = pm_runtime_set_active ( & indio_dev - > dev ) ;
if ( ret )
goto error_unreg_trigger ;
2012-09-05 13:56:00 +01:00
2015-01-07 10:55:53 -08:00
iio_device_set_drvdata ( indio_dev , attrb ) ;
2016-08-15 12:12:47 -07:00
INIT_WORK ( & attrb - > work , hid_sensor_set_power_work ) ;
2015-01-07 10:55:53 -08:00
pm_suspend_ignore_children ( & attrb - > pdev - > dev , true ) ;
pm_runtime_enable ( & attrb - > pdev - > dev ) ;
/* Default to 3 seconds, but can be changed from sysfs */
pm_runtime_set_autosuspend_delay ( & attrb - > pdev - > dev ,
3000 ) ;
pm_runtime_use_autosuspend ( & attrb - > pdev - > dev ) ;
return ret ;
error_unreg_trigger :
iio_trigger_unregister ( trig ) ;
2012-09-05 13:56:00 +01:00
error_free_trig :
iio_trigger_free ( trig ) ;
error_ret :
return ret ;
}
EXPORT_SYMBOL ( hid_sensor_setup_trigger ) ;
2015-01-07 10:55:53 -08:00
# ifdef CONFIG_PM
static int hid_sensor_suspend ( struct device * dev )
{
struct platform_device * pdev = to_platform_device ( dev ) ;
struct iio_dev * indio_dev = platform_get_drvdata ( pdev ) ;
struct hid_sensor_common * attrb = iio_device_get_drvdata ( indio_dev ) ;
return _hid_sensor_power_state ( attrb , false ) ;
}
static int hid_sensor_resume ( struct device * dev )
{
struct platform_device * pdev = to_platform_device ( dev ) ;
struct iio_dev * indio_dev = platform_get_drvdata ( pdev ) ;
struct hid_sensor_common * attrb = iio_device_get_drvdata ( indio_dev ) ;
2016-08-15 12:12:47 -07:00
schedule_work ( & attrb - > work ) ;
return 0 ;
}
2015-01-07 10:55:53 -08:00
2016-08-15 12:12:47 -07:00
static int hid_sensor_runtime_resume ( struct device * dev )
{
struct platform_device * pdev = to_platform_device ( dev ) ;
struct iio_dev * indio_dev = platform_get_drvdata ( pdev ) ;
struct hid_sensor_common * attrb = iio_device_get_drvdata ( indio_dev ) ;
2015-01-07 10:55:53 -08:00
return _hid_sensor_power_state ( attrb , true ) ;
}
# endif
const struct dev_pm_ops hid_sensor_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS ( hid_sensor_suspend , hid_sensor_resume )
SET_RUNTIME_PM_OPS ( hid_sensor_suspend ,
2016-08-15 12:12:47 -07:00
hid_sensor_runtime_resume , NULL )
2015-01-07 10:55:53 -08:00
} ;
EXPORT_SYMBOL ( hid_sensor_pm_ops ) ;
2012-09-05 13:56:00 +01:00
MODULE_AUTHOR ( " Srinivas Pandruvada <srinivas.pandruvada@intel.com> " ) ;
MODULE_DESCRIPTION ( " HID Sensor trigger processing " ) ;
MODULE_LICENSE ( " GPL " ) ;