2019-05-29 16:57:49 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2012-09-05 13:56:00 +01:00
/*
* HID Sensors Driver
* Copyright ( c ) 2012 , Intel Corporation .
*/
# 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>
2020-04-24 07:34:18 +03:00
# include <linux/iio/triggered_buffer.h>
# include <linux/iio/trigger_consumer.h>
2017-04-07 19:22:06 -07:00
# include <linux/iio/buffer.h>
2012-09-05 13:56:00 +01:00
# include <linux/iio/sysfs.h>
# include "hid-sensor-trigger.h"
2017-04-07 19:22:06 -07:00
static ssize_t _hid_sensor_set_report_latency ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t len )
{
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
struct hid_sensor_common * attrb = iio_device_get_drvdata ( indio_dev ) ;
int integer , fract , ret ;
int latency ;
ret = iio_str_to_fixpoint ( buf , 100000 , & integer , & fract ) ;
if ( ret )
return ret ;
latency = integer * 1000 + fract / 1000 ;
ret = hid_sensor_set_report_latency ( attrb , latency ) ;
if ( ret < 0 )
return len ;
attrb - > latency_ms = hid_sensor_get_report_latency ( attrb ) ;
return len ;
}
static ssize_t _hid_sensor_get_report_latency ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
struct hid_sensor_common * attrb = iio_device_get_drvdata ( indio_dev ) ;
int latency ;
latency = hid_sensor_get_report_latency ( attrb ) ;
if ( latency < 0 )
return latency ;
return sprintf ( buf , " %d.%06u \n " , latency / 1000 , ( latency % 1000 ) * 1000 ) ;
}
static ssize_t _hid_sensor_get_fifo_state ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
struct hid_sensor_common * attrb = iio_device_get_drvdata ( indio_dev ) ;
int latency ;
latency = hid_sensor_get_report_latency ( attrb ) ;
if ( latency < 0 )
return latency ;
return sprintf ( buf , " %d \n " , ! ! latency ) ;
}
static IIO_DEVICE_ATTR ( hwfifo_timeout , 0644 ,
_hid_sensor_get_report_latency ,
_hid_sensor_set_report_latency , 0 ) ;
static IIO_DEVICE_ATTR ( hwfifo_enabled , 0444 ,
_hid_sensor_get_fifo_state , NULL , 0 ) ;
static const struct attribute * hid_sensor_fifo_attributes [ ] = {
& iio_dev_attr_hwfifo_timeout . dev_attr . attr ,
& iio_dev_attr_hwfifo_enabled . dev_attr . attr ,
NULL ,
} ;
static void hid_sensor_setup_batch_mode ( struct iio_dev * indio_dev ,
struct hid_sensor_common * st )
{
if ( ! hid_sensor_batch_mode_supported ( st ) )
return ;
iio_buffer_set_attrs ( indio_dev - > buffer , hid_sensor_fifo_attributes ) ;
}
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 ) {
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 ) ;
2017-04-07 17:13:17 -07: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
2017-08-12 09:09:21 -07:00
pr_debug ( " HID_SENSOR %s set power_state %d report_state %d \n " ,
st - > pdev - > name , state_val , report_val ) ;
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 ) ;
2017-04-07 17:13:17 -07:00
if ( state & & poll_value )
2015-01-07 10:55:53 -08:00
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 ;
2017-10-11 09:35:01 -07:00
if ( atomic_add_unless ( & st - > runtime_pm_enable , 1 , 1 ) )
pm_runtime_enable ( & st - > pdev - > dev ) ;
2018-04-14 17:09:09 +02:00
if ( state ) {
atomic_inc ( & st - > user_requested_state ) ;
2015-01-07 10:55:53 -08:00
ret = pm_runtime_get_sync ( & st - > pdev - > dev ) ;
2018-04-14 17:09:09 +02:00
} else {
atomic_dec ( & st - > user_requested_state ) ;
2015-01-07 10:55:53 -08:00
pm_runtime_mark_last_busy ( & st - > pdev - > dev ) ;
2017-08-12 09:09:21 -07:00
pm_runtime_use_autosuspend ( & st - > pdev - > dev ) ;
2015-01-07 10:55:53 -08:00
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 ) ;
2017-04-07 17:13:17 -07:00
if ( attrb - > poll_interval > = 0 )
sensor_hub_set_feature ( attrb - > hsdev , attrb - > poll . report_id ,
attrb - > poll . index ,
sizeof ( attrb - > poll_interval ) ,
& attrb - > poll_interval ) ;
if ( attrb - > raw_hystersis > = 0 )
sensor_hub_set_feature ( attrb - > hsdev ,
attrb - > sensitivity . report_id ,
attrb - > sensitivity . index ,
sizeof ( attrb - > raw_hystersis ) ,
& attrb - > raw_hystersis ) ;
2017-04-07 19:22:06 -07:00
if ( attrb - > latency_ms > 0 )
hid_sensor_set_report_latency ( attrb , attrb - > latency_ms ) ;
2017-10-11 09:35:01 -07:00
if ( atomic_read ( & attrb - > user_requested_state ) )
_hid_sensor_power_state ( attrb , true ) ;
2016-08-15 12:12:47 -07:00
}
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
2020-04-24 07:34:18 +03:00
void hid_sensor_remove_trigger ( struct iio_dev * indio_dev ,
struct hid_sensor_common * attrb )
2012-09-05 13:56:00 +01:00
{
2017-10-11 09:35:01 -07:00
if ( atomic_read ( & attrb - > runtime_pm_enable ) )
pm_runtime_disable ( & attrb - > pdev - > dev ) ;
2017-04-07 17:16:34 -07:00
pm_runtime_set_suspended ( & attrb - > pdev - > dev ) ;
pm_runtime_put_noidle ( & attrb - > pdev - > dev ) ;
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 ) ;
2020-04-24 07:34:18 +03:00
iio_triggered_buffer_cleanup ( indio_dev ) ;
2012-09-05 13:56:00 +01:00
}
EXPORT_SYMBOL ( hid_sensor_remove_trigger ) ;
static const struct iio_trigger_ops hid_sensor_trigger_ops = {
. 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 ;
2020-04-24 07:34:18 +03:00
ret = iio_triggered_buffer_setup ( indio_dev , & iio_pollfunc_store_time ,
NULL , NULL ) ;
if ( ret ) {
dev_err ( & indio_dev - > dev , " Triggered Buffer Setup Failed \n " ) ;
return ret ;
}
2012-09-05 13:56:00 +01:00
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 ;
2020-04-24 07:34:18 +03:00
goto error_triggered_buffer_cleanup ;
2012-09-05 13:56:00 +01:00
}
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
2017-04-07 19:22:06 -07:00
hid_sensor_setup_batch_mode ( indio_dev , attrb ) ;
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 ) ;
/* Default to 3 seconds, but can be changed from sysfs */
pm_runtime_set_autosuspend_delay ( & attrb - > pdev - > dev ,
3000 ) ;
return ret ;
error_unreg_trigger :
iio_trigger_unregister ( trig ) ;
2012-09-05 13:56:00 +01:00
error_free_trig :
iio_trigger_free ( trig ) ;
2020-04-24 07:34:18 +03:00
error_triggered_buffer_cleanup :
iio_triggered_buffer_cleanup ( indio_dev ) ;
2012-09-05 13:56:00 +01:00
return ret ;
}
EXPORT_SYMBOL ( hid_sensor_setup_trigger ) ;
2016-08-26 17:29:35 +02:00
static int __maybe_unused hid_sensor_suspend ( struct device * dev )
2015-01-07 10:55:53 -08:00
{
2018-04-19 16:05:49 +02:00
struct iio_dev * indio_dev = dev_get_drvdata ( dev ) ;
2015-01-07 10:55:53 -08:00
struct hid_sensor_common * attrb = iio_device_get_drvdata ( indio_dev ) ;
return _hid_sensor_power_state ( attrb , false ) ;
}
2016-08-26 17:29:35 +02:00
static int __maybe_unused hid_sensor_resume ( struct device * dev )
2015-01-07 10:55:53 -08:00
{
2018-04-19 16:05:49 +02:00
struct iio_dev * indio_dev = dev_get_drvdata ( dev ) ;
2015-01-07 10:55:53 -08:00
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-26 17:29:35 +02:00
static int __maybe_unused hid_sensor_runtime_resume ( struct device * dev )
2016-08-15 12:12:47 -07:00
{
2018-04-19 16:05:49 +02:00
struct iio_dev * indio_dev = dev_get_drvdata ( dev ) ;
2016-08-15 12:12:47 -07:00
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 ) ;
}
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 " ) ;