2017-06-06 11:38:10 +01:00
// SPDX-License-Identifier: GPL-2.0
/*
* System Control and Management Interface ( SCMI ) Sensor Protocol
*
2021-03-16 12:48:26 +00:00
* Copyright ( C ) 2018 - 2021 ARM Ltd .
2017-06-06 11:38:10 +01:00
*/
2020-07-01 16:53:46 +01:00
# define pr_fmt(fmt) "SCMI Notifications SENSOR - " fmt
2020-11-19 17:49:02 +00:00
# include <linux/bitfield.h>
2021-03-16 12:49:02 +00:00
# include <linux/module.h>
2020-07-01 16:53:46 +01:00
# include <linux/scmi_protocol.h>
2017-06-06 11:38:10 +01:00
# include "common.h"
2020-07-01 16:53:46 +01:00
# include "notify.h"
2017-06-06 11:38:10 +01:00
2020-11-19 17:49:02 +00:00
# define SCMI_MAX_NUM_SENSOR_AXIS 63
# define SCMIv2_SENSOR_PROTOCOL 0x10000
2017-06-06 11:38:10 +01:00
enum scmi_sensor_protocol_cmd {
SENSOR_DESCRIPTION_GET = 0x3 ,
2019-07-08 09:40:33 +01:00
SENSOR_TRIP_POINT_NOTIFY = 0x4 ,
SENSOR_TRIP_POINT_CONFIG = 0x5 ,
2017-06-06 11:38:10 +01:00
SENSOR_READING_GET = 0x6 ,
2020-11-19 17:49:02 +00:00
SENSOR_AXIS_DESCRIPTION_GET = 0x7 ,
SENSOR_LIST_UPDATE_INTERVALS = 0x8 ,
2020-11-19 17:49:05 +00:00
SENSOR_CONFIG_GET = 0x9 ,
SENSOR_CONFIG_SET = 0xA ,
2020-11-19 17:49:06 +00:00
SENSOR_CONTINUOUS_UPDATE_NOTIFY = 0xB ,
2017-06-06 11:38:10 +01:00
} ;
struct scmi_msg_resp_sensor_attributes {
__le16 num_sensors ;
u8 max_requests ;
u8 reserved ;
__le32 reg_addr_low ;
__le32 reg_addr_high ;
__le32 reg_size ;
} ;
2020-11-19 17:49:02 +00:00
/* v3 attributes_low macros */
# define SUPPORTS_UPDATE_NOTIFY(x) FIELD_GET(BIT(30), (x))
# define SENSOR_TSTAMP_EXP(x) FIELD_GET(GENMASK(14, 10), (x))
# define SUPPORTS_TIMESTAMP(x) FIELD_GET(BIT(9), (x))
# define SUPPORTS_EXTEND_ATTRS(x) FIELD_GET(BIT(8), (x))
/* v2 attributes_high macros */
# define SENSOR_UPDATE_BASE(x) FIELD_GET(GENMASK(31, 27), (x))
# define SENSOR_UPDATE_SCALE(x) FIELD_GET(GENMASK(26, 22), (x))
/* v3 attributes_high macros */
# define SENSOR_AXIS_NUMBER(x) FIELD_GET(GENMASK(21, 16), (x))
# define SUPPORTS_AXIS(x) FIELD_GET(BIT(8), (x))
/* v3 resolution macros */
# define SENSOR_RES(x) FIELD_GET(GENMASK(26, 0), (x))
# define SENSOR_RES_EXP(x) FIELD_GET(GENMASK(31, 27), (x))
struct scmi_msg_resp_attrs {
__le32 min_range_low ;
__le32 min_range_high ;
__le32 max_range_low ;
__le32 max_range_high ;
} ;
2017-06-06 11:38:10 +01:00
struct scmi_msg_resp_sensor_description {
__le16 num_returned ;
__le16 num_remaining ;
2020-11-19 17:49:02 +00:00
struct scmi_sensor_descriptor {
__le32 id ;
__le32 attributes_low ;
/* Common attributes_low macros */
# define SUPPORTS_ASYNC_READ(x) FIELD_GET(BIT(31), (x))
# define NUM_TRIP_POINTS(x) FIELD_GET(GENMASK(7, 0), (x))
__le32 attributes_high ;
/* Common attributes_high macros */
# define SENSOR_SCALE(x) FIELD_GET(GENMASK(15, 11), (x))
# define SENSOR_SCALE_SIGN BIT(4)
# define SENSOR_SCALE_EXTEND GENMASK(31, 5)
# define SENSOR_TYPE(x) FIELD_GET(GENMASK(7, 0), (x))
u8 name [ SCMI_MAX_STR_SIZE ] ;
/* only for version > 2.0 */
__le32 power ;
__le32 resolution ;
struct scmi_msg_resp_attrs scalar_attrs ;
} desc [ ] ;
} ;
/* Base scmi_sensor_descriptor size excluding extended attrs after name */
# define SCMI_MSG_RESP_SENS_DESCR_BASE_SZ 28
/* Sign extend to a full s32 */
# define S32_EXT(v) \
( { \
int __v = ( v ) ; \
\
if ( __v & SENSOR_SCALE_SIGN ) \
__v | = SENSOR_SCALE_EXTEND ; \
__v ; \
} )
struct scmi_msg_sensor_axis_description_get {
__le32 id ;
__le32 axis_desc_index ;
} ;
struct scmi_msg_resp_sensor_axis_description {
__le32 num_axis_flags ;
# define NUM_AXIS_RETURNED(x) FIELD_GET(GENMASK(5, 0), (x))
# define NUM_AXIS_REMAINING(x) FIELD_GET(GENMASK(31, 26), (x))
struct scmi_axis_descriptor {
2017-06-06 11:38:10 +01:00
__le32 id ;
__le32 attributes_low ;
__le32 attributes_high ;
2020-11-19 17:49:02 +00:00
u8 name [ SCMI_MAX_STR_SIZE ] ;
__le32 resolution ;
struct scmi_msg_resp_attrs attrs ;
} desc [ ] ;
} ;
/* Base scmi_axis_descriptor size excluding extended attrs after name */
# define SCMI_MSG_RESP_AXIS_DESCR_BASE_SZ 28
struct scmi_msg_sensor_list_update_intervals {
__le32 id ;
__le32 index ;
} ;
struct scmi_msg_resp_sensor_list_update_intervals {
__le32 num_intervals_flags ;
# define NUM_INTERVALS_RETURNED(x) FIELD_GET(GENMASK(11, 0), (x))
# define SEGMENTED_INTVL_FORMAT(x) FIELD_GET(BIT(12), (x))
# define NUM_INTERVALS_REMAINING(x) FIELD_GET(GENMASK(31, 16), (x))
__le32 intervals [ ] ;
2017-06-06 11:38:10 +01:00
} ;
2020-11-19 17:49:06 +00:00
struct scmi_msg_sensor_request_notify {
2017-06-06 11:38:10 +01:00
__le32 id ;
__le32 event_control ;
2020-11-19 17:49:06 +00:00
# define SENSOR_NOTIFY_ALL BIT(0)
2017-06-06 11:38:10 +01:00
} ;
struct scmi_msg_set_sensor_trip_point {
__le32 id ;
__le32 event_control ;
# define SENSOR_TP_EVENT_MASK (0x3)
# define SENSOR_TP_DISABLED 0x0
# define SENSOR_TP_POSITIVE 0x1
# define SENSOR_TP_NEGATIVE 0x2
# define SENSOR_TP_BOTH 0x3
# define SENSOR_TP_ID(x) (((x) & 0xff) << 4)
__le32 value_low ;
__le32 value_high ;
} ;
2020-11-19 17:49:05 +00:00
struct scmi_msg_sensor_config_set {
__le32 id ;
__le32 sensor_config ;
} ;
2017-06-06 11:38:10 +01:00
struct scmi_msg_sensor_reading_get {
__le32 id ;
__le32 flags ;
# define SENSOR_READ_ASYNC BIT(0)
} ;
2020-11-19 17:49:04 +00:00
struct scmi_resp_sensor_reading_complete {
__le32 id ;
2021-06-28 18:00:42 +01:00
__le32 readings_low ;
__le32 readings_high ;
2020-11-19 17:49:04 +00:00
} ;
2020-11-23 16:20:08 +00:00
struct scmi_sensor_reading_resp {
2020-11-19 17:49:04 +00:00
__le32 sensor_value_low ;
__le32 sensor_value_high ;
__le32 timestamp_low ;
__le32 timestamp_high ;
} ;
struct scmi_resp_sensor_reading_complete_v3 {
__le32 id ;
2020-11-23 16:20:08 +00:00
struct scmi_sensor_reading_resp readings [ ] ;
2020-11-19 17:49:04 +00:00
} ;
2020-07-01 16:53:46 +01:00
struct scmi_sensor_trip_notify_payld {
__le32 agent_id ;
__le32 sensor_id ;
__le32 trip_point_desc ;
} ;
2020-11-19 17:49:06 +00:00
struct scmi_sensor_update_notify_payld {
__le32 agent_id ;
__le32 sensor_id ;
2020-11-23 16:20:08 +00:00
struct scmi_sensor_reading_resp readings [ ] ;
2020-11-19 17:49:06 +00:00
} ;
2017-06-06 11:38:10 +01:00
struct sensors_info {
2019-11-22 14:48:40 +00:00
u32 version ;
2017-06-06 11:38:10 +01:00
int num_sensors ;
int max_requests ;
u64 reg_addr ;
u32 reg_size ;
struct scmi_sensor_info * sensors ;
} ;
2021-03-16 12:48:48 +00:00
static int scmi_sensor_attributes_get ( const struct scmi_protocol_handle * ph ,
2017-06-06 11:38:10 +01:00
struct sensors_info * si )
{
int ret ;
struct scmi_xfer * t ;
struct scmi_msg_resp_sensor_attributes * attr ;
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > xfer_get_init ( ph , PROTOCOL_ATTRIBUTES ,
0 , sizeof ( * attr ) , & t ) ;
2017-06-06 11:38:10 +01:00
if ( ret )
return ret ;
attr = t - > rx . buf ;
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > do_xfer ( ph , t ) ;
2017-06-06 11:38:10 +01:00
if ( ! ret ) {
si - > num_sensors = le16_to_cpu ( attr - > num_sensors ) ;
si - > max_requests = attr - > max_requests ;
si - > reg_addr = le32_to_cpu ( attr - > reg_addr_low ) |
( u64 ) le32_to_cpu ( attr - > reg_addr_high ) < < 32 ;
si - > reg_size = le32_to_cpu ( attr - > reg_size ) ;
}
2021-03-16 12:48:48 +00:00
ph - > xops - > xfer_put ( ph , t ) ;
2017-06-06 11:38:10 +01:00
return ret ;
}
2020-11-19 17:49:02 +00:00
static inline void scmi_parse_range_attrs ( struct scmi_range_attrs * out ,
struct scmi_msg_resp_attrs * in )
{
out - > min_range = get_unaligned_le64 ( ( void * ) & in - > min_range_low ) ;
out - > max_range = get_unaligned_le64 ( ( void * ) & in - > max_range_low ) ;
}
2021-03-16 12:48:48 +00:00
static int scmi_sensor_update_intervals ( const struct scmi_protocol_handle * ph ,
2020-11-19 17:49:02 +00:00
struct scmi_sensor_info * s )
{
int ret , cnt ;
u32 desc_index = 0 ;
u16 num_returned , num_remaining ;
struct scmi_xfer * ti ;
struct scmi_msg_resp_sensor_list_update_intervals * buf ;
struct scmi_msg_sensor_list_update_intervals * msg ;
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > xfer_get_init ( ph , SENSOR_LIST_UPDATE_INTERVALS ,
sizeof ( * msg ) , 0 , & ti ) ;
2020-11-19 17:49:02 +00:00
if ( ret )
return ret ;
buf = ti - > rx . buf ;
do {
u32 flags ;
msg = ti - > tx . buf ;
/* Set the number of sensors to be skipped/already read */
msg - > id = cpu_to_le32 ( s - > id ) ;
msg - > index = cpu_to_le32 ( desc_index ) ;
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > do_xfer ( ph , ti ) ;
2020-11-19 17:49:02 +00:00
if ( ret )
break ;
flags = le32_to_cpu ( buf - > num_intervals_flags ) ;
num_returned = NUM_INTERVALS_RETURNED ( flags ) ;
num_remaining = NUM_INTERVALS_REMAINING ( flags ) ;
/*
* Max intervals is not declared previously anywhere so we
* assume it ' s returned + remaining .
*/
if ( ! s - > intervals . count ) {
s - > intervals . segmented = SEGMENTED_INTVL_FORMAT ( flags ) ;
s - > intervals . count = num_returned + num_remaining ;
/* segmented intervals are reported in one triplet */
if ( s - > intervals . segmented & &
( num_remaining | | num_returned ! = 3 ) ) {
2021-03-16 12:48:48 +00:00
dev_err ( ph - > dev ,
2020-11-19 17:49:02 +00:00
" Sensor ID:%d advertises an invalid segmented interval (%d) \n " ,
s - > id , s - > intervals . count ) ;
s - > intervals . segmented = false ;
s - > intervals . count = 0 ;
ret = - EINVAL ;
break ;
}
/* Direct allocation when exceeding pre-allocated */
if ( s - > intervals . count > = SCMI_MAX_PREALLOC_POOL ) {
s - > intervals . desc =
2021-03-16 12:48:48 +00:00
devm_kcalloc ( ph - > dev ,
2020-11-19 17:49:02 +00:00
s - > intervals . count ,
sizeof ( * s - > intervals . desc ) ,
GFP_KERNEL ) ;
if ( ! s - > intervals . desc ) {
s - > intervals . segmented = false ;
s - > intervals . count = 0 ;
ret = - ENOMEM ;
break ;
}
}
} else if ( desc_index + num_returned > s - > intervals . count ) {
2021-03-16 12:48:48 +00:00
dev_err ( ph - > dev ,
2020-11-19 17:49:02 +00:00
" No. of update intervals can't exceed %d \n " ,
s - > intervals . count ) ;
ret = - EINVAL ;
break ;
}
for ( cnt = 0 ; cnt < num_returned ; cnt + + )
s - > intervals . desc [ desc_index + cnt ] =
le32_to_cpu ( buf - > intervals [ cnt ] ) ;
desc_index + = num_returned ;
2021-03-16 12:48:48 +00:00
ph - > xops - > reset_rx_to_maxsz ( ph , ti ) ;
2020-11-19 17:49:02 +00:00
/*
* check for both returned and remaining to avoid infinite
* loop due to buggy firmware
*/
} while ( num_returned & & num_remaining ) ;
2021-03-16 12:48:48 +00:00
ph - > xops - > xfer_put ( ph , ti ) ;
2020-11-19 17:49:02 +00:00
return ret ;
}
2021-03-16 12:48:48 +00:00
static int scmi_sensor_axis_description ( const struct scmi_protocol_handle * ph ,
2020-11-19 17:49:02 +00:00
struct scmi_sensor_info * s )
{
int ret , cnt ;
u32 desc_index = 0 ;
u16 num_returned , num_remaining ;
struct scmi_xfer * te ;
struct scmi_msg_resp_sensor_axis_description * buf ;
struct scmi_msg_sensor_axis_description_get * msg ;
2021-03-16 12:48:48 +00:00
s - > axis = devm_kcalloc ( ph - > dev , s - > num_axis ,
2020-11-19 17:49:02 +00:00
sizeof ( * s - > axis ) , GFP_KERNEL ) ;
if ( ! s - > axis )
return - ENOMEM ;
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > xfer_get_init ( ph , SENSOR_AXIS_DESCRIPTION_GET ,
sizeof ( * msg ) , 0 , & te ) ;
2020-11-19 17:49:02 +00:00
if ( ret )
return ret ;
buf = te - > rx . buf ;
do {
u32 flags ;
struct scmi_axis_descriptor * adesc ;
msg = te - > tx . buf ;
/* Set the number of sensors to be skipped/already read */
msg - > id = cpu_to_le32 ( s - > id ) ;
msg - > axis_desc_index = cpu_to_le32 ( desc_index ) ;
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > do_xfer ( ph , te ) ;
2020-11-19 17:49:02 +00:00
if ( ret )
break ;
flags = le32_to_cpu ( buf - > num_axis_flags ) ;
num_returned = NUM_AXIS_RETURNED ( flags ) ;
num_remaining = NUM_AXIS_REMAINING ( flags ) ;
if ( desc_index + num_returned > s - > num_axis ) {
2021-03-16 12:48:48 +00:00
dev_err ( ph - > dev , " No. of axis can't exceed %d \n " ,
2020-11-19 17:49:02 +00:00
s - > num_axis ) ;
break ;
}
adesc = & buf - > desc [ 0 ] ;
for ( cnt = 0 ; cnt < num_returned ; cnt + + ) {
u32 attrh , attrl ;
struct scmi_sensor_axis_info * a ;
size_t dsize = SCMI_MSG_RESP_AXIS_DESCR_BASE_SZ ;
attrl = le32_to_cpu ( adesc - > attributes_low ) ;
a = & s - > axis [ desc_index + cnt ] ;
a - > id = le32_to_cpu ( adesc - > id ) ;
a - > extended_attrs = SUPPORTS_EXTEND_ATTRS ( attrl ) ;
attrh = le32_to_cpu ( adesc - > attributes_high ) ;
a - > scale = S32_EXT ( SENSOR_SCALE ( attrh ) ) ;
a - > type = SENSOR_TYPE ( attrh ) ;
strlcpy ( a - > name , adesc - > name , SCMI_MAX_STR_SIZE ) ;
if ( a - > extended_attrs ) {
unsigned int ares =
le32_to_cpu ( adesc - > resolution ) ;
a - > resolution = SENSOR_RES ( ares ) ;
a - > exponent =
S32_EXT ( SENSOR_RES_EXP ( ares ) ) ;
dsize + = sizeof ( adesc - > resolution ) ;
scmi_parse_range_attrs ( & a - > attrs ,
& adesc - > attrs ) ;
dsize + = sizeof ( adesc - > attrs ) ;
}
adesc = ( typeof ( adesc ) ) ( ( u8 * ) adesc + dsize ) ;
}
desc_index + = num_returned ;
2021-03-16 12:48:48 +00:00
ph - > xops - > reset_rx_to_maxsz ( ph , te ) ;
2020-11-19 17:49:02 +00:00
/*
* check for both returned and remaining to avoid infinite
* loop due to buggy firmware
*/
} while ( num_returned & & num_remaining ) ;
2021-03-16 12:48:48 +00:00
ph - > xops - > xfer_put ( ph , te ) ;
2020-11-19 17:49:02 +00:00
return ret ;
}
2021-03-16 12:48:48 +00:00
static int scmi_sensor_description_get ( const struct scmi_protocol_handle * ph ,
2017-06-06 11:38:10 +01:00
struct sensors_info * si )
{
int ret , cnt ;
u32 desc_index = 0 ;
u16 num_returned , num_remaining ;
struct scmi_xfer * t ;
struct scmi_msg_resp_sensor_description * buf ;
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > xfer_get_init ( ph , SENSOR_DESCRIPTION_GET ,
sizeof ( __le32 ) , 0 , & t ) ;
2017-06-06 11:38:10 +01:00
if ( ret )
return ret ;
buf = t - > rx . buf ;
do {
2020-11-19 17:49:02 +00:00
struct scmi_sensor_descriptor * sdesc ;
2017-06-06 11:38:10 +01:00
/* Set the number of sensors to be skipped/already read */
2019-08-07 13:46:27 +01:00
put_unaligned_le32 ( desc_index , t - > tx . buf ) ;
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > do_xfer ( ph , t ) ;
2017-06-06 11:38:10 +01:00
if ( ret )
break ;
num_returned = le16_to_cpu ( buf - > num_returned ) ;
num_remaining = le16_to_cpu ( buf - > num_remaining ) ;
if ( desc_index + num_returned > si - > num_sensors ) {
2021-03-16 12:48:48 +00:00
dev_err ( ph - > dev , " No. of sensors can't exceed %d " ,
2017-06-06 11:38:10 +01:00
si - > num_sensors ) ;
break ;
}
2020-11-19 17:49:02 +00:00
sdesc = & buf - > desc [ 0 ] ;
2017-06-06 11:38:10 +01:00
for ( cnt = 0 ; cnt < num_returned ; cnt + + ) {
2019-07-08 09:41:01 +01:00
u32 attrh , attrl ;
2017-06-06 11:38:10 +01:00
struct scmi_sensor_info * s ;
2020-11-19 17:49:02 +00:00
size_t dsize = SCMI_MSG_RESP_SENS_DESCR_BASE_SZ ;
2017-06-06 11:38:10 +01:00
s = & si - > sensors [ desc_index + cnt ] ;
2020-11-19 17:49:02 +00:00
s - > id = le32_to_cpu ( sdesc - > id ) ;
attrl = le32_to_cpu ( sdesc - > attributes_low ) ;
/* common bitfields parsing */
2019-07-08 09:41:01 +01:00
s - > async = SUPPORTS_ASYNC_READ ( attrl ) ;
s - > num_trip_points = NUM_TRIP_POINTS ( attrl ) ;
2020-11-19 17:49:02 +00:00
/**
* only SCMIv3 .0 specific bitfield below .
* Such bitfields are assumed to be zeroed on non
* relevant fw versions . . . assuming fw not buggy !
*/
s - > update = SUPPORTS_UPDATE_NOTIFY ( attrl ) ;
s - > timestamped = SUPPORTS_TIMESTAMP ( attrl ) ;
if ( s - > timestamped )
s - > tstamp_scale =
S32_EXT ( SENSOR_TSTAMP_EXP ( attrl ) ) ;
s - > extended_scalar_attrs =
SUPPORTS_EXTEND_ATTRS ( attrl ) ;
attrh = le32_to_cpu ( sdesc - > attributes_high ) ;
/* common bitfields parsing */
s - > scale = S32_EXT ( SENSOR_SCALE ( attrh ) ) ;
s - > type = SENSOR_TYPE ( attrh ) ;
/* Use pre-allocated pool wherever possible */
s - > intervals . desc = s - > intervals . prealloc_pool ;
if ( si - > version = = SCMIv2_SENSOR_PROTOCOL ) {
s - > intervals . segmented = false ;
s - > intervals . count = 1 ;
/*
* Convert SCMIv2 .0 update interval format to
* SCMIv3 .0 to be used as the common exposed
* descriptor , accessible via common macros .
*/
s - > intervals . desc [ 0 ] =
( SENSOR_UPDATE_BASE ( attrh ) < < 5 ) |
SENSOR_UPDATE_SCALE ( attrh ) ;
} else {
/*
* From SCMIv3 .0 update intervals are retrieved
* via a dedicated ( optional ) command .
* Since the command is optional , on error carry
* on without any update interval .
*/
2021-03-16 12:48:48 +00:00
if ( scmi_sensor_update_intervals ( ph , s ) )
dev_dbg ( ph - > dev ,
2020-11-19 17:49:02 +00:00
" Update Intervals not available for sensor ID:%d \n " ,
s - > id ) ;
}
/**
* only > SCMIv2 .0 specific bitfield below .
* Such bitfields are assumed to be zeroed on non
* relevant fw versions . . . assuming fw not buggy !
*/
s - > num_axis = min_t ( unsigned int ,
SUPPORTS_AXIS ( attrh ) ?
SENSOR_AXIS_NUMBER ( attrh ) : 0 ,
SCMI_MAX_NUM_SENSOR_AXIS ) ;
strlcpy ( s - > name , sdesc - > name , SCMI_MAX_STR_SIZE ) ;
if ( s - > extended_scalar_attrs ) {
s - > sensor_power = le32_to_cpu ( sdesc - > power ) ;
dsize + = sizeof ( sdesc - > power ) ;
/* Only for sensors reporting scalar values */
if ( s - > num_axis = = 0 ) {
unsigned int sres =
le32_to_cpu ( sdesc - > resolution ) ;
s - > resolution = SENSOR_RES ( sres ) ;
s - > exponent =
S32_EXT ( SENSOR_RES_EXP ( sres ) ) ;
dsize + = sizeof ( sdesc - > resolution ) ;
scmi_parse_range_attrs ( & s - > scalar_attrs ,
& sdesc - > scalar_attrs ) ;
dsize + = sizeof ( sdesc - > scalar_attrs ) ;
}
}
if ( s - > num_axis > 0 ) {
2021-03-16 12:48:48 +00:00
ret = scmi_sensor_axis_description ( ph , s ) ;
2020-11-19 17:49:02 +00:00
if ( ret )
goto out ;
}
sdesc = ( typeof ( sdesc ) ) ( ( u8 * ) sdesc + dsize ) ;
2017-06-06 11:38:10 +01:00
}
desc_index + = num_returned ;
2020-10-12 14:26:24 +01:00
2021-03-16 12:48:48 +00:00
ph - > xops - > reset_rx_to_maxsz ( ph , t ) ;
2017-06-06 11:38:10 +01:00
/*
* check for both returned and remaining to avoid infinite
* loop due to buggy firmware
*/
} while ( num_returned & & num_remaining ) ;
2020-11-19 17:49:02 +00:00
out :
2021-03-16 12:48:48 +00:00
ph - > xops - > xfer_put ( ph , t ) ;
2017-06-06 11:38:10 +01:00
return ret ;
}
2020-11-19 17:49:06 +00:00
static inline int
2021-03-16 12:48:48 +00:00
scmi_sensor_request_notify ( const struct scmi_protocol_handle * ph , u32 sensor_id ,
2020-11-19 17:49:06 +00:00
u8 message_id , bool enable )
2017-06-06 11:38:10 +01:00
{
int ret ;
2020-11-19 17:49:06 +00:00
u32 evt_cntl = enable ? SENSOR_NOTIFY_ALL : 0 ;
2017-06-06 11:38:10 +01:00
struct scmi_xfer * t ;
2020-11-19 17:49:06 +00:00
struct scmi_msg_sensor_request_notify * cfg ;
2017-06-06 11:38:10 +01:00
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > xfer_get_init ( ph , message_id , sizeof ( * cfg ) , 0 , & t ) ;
2017-06-06 11:38:10 +01:00
if ( ret )
return ret ;
cfg = t - > tx . buf ;
cfg - > id = cpu_to_le32 ( sensor_id ) ;
cfg - > event_control = cpu_to_le32 ( evt_cntl ) ;
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > do_xfer ( ph , t ) ;
2017-06-06 11:38:10 +01:00
2021-03-16 12:48:48 +00:00
ph - > xops - > xfer_put ( ph , t ) ;
2017-06-06 11:38:10 +01:00
return ret ;
}
2021-03-16 12:48:48 +00:00
static int scmi_sensor_trip_point_notify ( const struct scmi_protocol_handle * ph ,
2020-11-19 17:49:06 +00:00
u32 sensor_id , bool enable )
{
2021-03-16 12:48:48 +00:00
return scmi_sensor_request_notify ( ph , sensor_id ,
2020-11-19 17:49:06 +00:00
SENSOR_TRIP_POINT_NOTIFY ,
enable ) ;
}
static int
2021-03-16 12:48:48 +00:00
scmi_sensor_continuous_update_notify ( const struct scmi_protocol_handle * ph ,
2020-11-19 17:49:06 +00:00
u32 sensor_id , bool enable )
{
2021-03-16 12:48:48 +00:00
return scmi_sensor_request_notify ( ph , sensor_id ,
2020-11-19 17:49:06 +00:00
SENSOR_CONTINUOUS_UPDATE_NOTIFY ,
enable ) ;
}
2019-07-08 09:40:33 +01:00
static int
2021-03-16 12:48:48 +00:00
scmi_sensor_trip_point_config ( const struct scmi_protocol_handle * ph ,
u32 sensor_id , u8 trip_id , u64 trip_value )
2017-06-06 11:38:10 +01:00
{
int ret ;
u32 evt_cntl = SENSOR_TP_BOTH ;
struct scmi_xfer * t ;
struct scmi_msg_set_sensor_trip_point * trip ;
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > xfer_get_init ( ph , SENSOR_TRIP_POINT_CONFIG ,
sizeof ( * trip ) , 0 , & t ) ;
2017-06-06 11:38:10 +01:00
if ( ret )
return ret ;
trip = t - > tx . buf ;
trip - > id = cpu_to_le32 ( sensor_id ) ;
trip - > event_control = cpu_to_le32 ( evt_cntl | SENSOR_TP_ID ( trip_id ) ) ;
trip - > value_low = cpu_to_le32 ( trip_value & 0xffffffff ) ;
trip - > value_high = cpu_to_le32 ( trip_value > > 32 ) ;
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > do_xfer ( ph , t ) ;
2017-06-06 11:38:10 +01:00
2021-03-16 12:48:48 +00:00
ph - > xops - > xfer_put ( ph , t ) ;
2017-06-06 11:38:10 +01:00
return ret ;
}
2021-03-16 12:48:48 +00:00
static int scmi_sensor_config_get ( const struct scmi_protocol_handle * ph ,
2020-11-19 17:49:05 +00:00
u32 sensor_id , u32 * sensor_config )
{
int ret ;
struct scmi_xfer * t ;
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > xfer_get_init ( ph , SENSOR_CONFIG_GET ,
sizeof ( __le32 ) , sizeof ( __le32 ) , & t ) ;
2020-11-19 17:49:05 +00:00
if ( ret )
return ret ;
put_unaligned_le32 ( cpu_to_le32 ( sensor_id ) , t - > tx . buf ) ;
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > do_xfer ( ph , t ) ;
2020-11-19 17:49:05 +00:00
if ( ! ret ) {
2021-03-16 12:48:48 +00:00
struct sensors_info * si = ph - > get_priv ( ph ) ;
2020-11-19 17:49:05 +00:00
struct scmi_sensor_info * s = si - > sensors + sensor_id ;
* sensor_config = get_unaligned_le64 ( t - > rx . buf ) ;
s - > sensor_config = * sensor_config ;
}
2021-03-16 12:48:48 +00:00
ph - > xops - > xfer_put ( ph , t ) ;
2020-11-19 17:49:05 +00:00
return ret ;
}
2021-03-16 12:48:48 +00:00
static int scmi_sensor_config_set ( const struct scmi_protocol_handle * ph ,
2020-11-19 17:49:05 +00:00
u32 sensor_id , u32 sensor_config )
{
int ret ;
struct scmi_xfer * t ;
struct scmi_msg_sensor_config_set * msg ;
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > xfer_get_init ( ph , SENSOR_CONFIG_SET ,
sizeof ( * msg ) , 0 , & t ) ;
2020-11-19 17:49:05 +00:00
if ( ret )
return ret ;
msg = t - > tx . buf ;
msg - > id = cpu_to_le32 ( sensor_id ) ;
msg - > sensor_config = cpu_to_le32 ( sensor_config ) ;
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > do_xfer ( ph , t ) ;
2020-11-19 17:49:05 +00:00
if ( ! ret ) {
2021-03-16 12:48:48 +00:00
struct sensors_info * si = ph - > get_priv ( ph ) ;
2020-11-19 17:49:05 +00:00
struct scmi_sensor_info * s = si - > sensors + sensor_id ;
s - > sensor_config = sensor_config ;
}
2021-03-16 12:48:48 +00:00
ph - > xops - > xfer_put ( ph , t ) ;
2020-11-19 17:49:05 +00:00
return ret ;
}
2020-11-19 17:49:04 +00:00
/**
* scmi_sensor_reading_get - Read scalar sensor value
2021-03-16 12:48:48 +00:00
* @ ph : Protocol handle
2020-11-19 17:49:04 +00:00
* @ sensor_id : Sensor ID
* @ value : The 64 bit value sensor reading
*
* This function returns a single 64 bit reading value representing the sensor
* value ; if the platform SCMI Protocol implementation and the sensor support
* multiple axis and timestamped - reads , this just returns the first axis while
* dropping the timestamp value .
* Use instead the @ scmi_sensor_reading_get_timestamped to retrieve the array of
* timestamped multi - axis values .
*
* Return : 0 on Success
*/
2021-03-16 12:48:48 +00:00
static int scmi_sensor_reading_get ( const struct scmi_protocol_handle * ph ,
2019-07-08 09:40:57 +01:00
u32 sensor_id , u64 * value )
2017-06-06 11:38:10 +01:00
{
int ret ;
struct scmi_xfer * t ;
struct scmi_msg_sensor_reading_get * sensor ;
2021-03-16 12:48:48 +00:00
struct sensors_info * si = ph - > get_priv ( ph ) ;
2019-07-08 09:41:01 +01:00
struct scmi_sensor_info * s = si - > sensors + sensor_id ;
2017-06-06 11:38:10 +01:00
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > xfer_get_init ( ph , SENSOR_READING_GET ,
sizeof ( * sensor ) , 0 , & t ) ;
2017-06-06 11:38:10 +01:00
if ( ret )
return ret ;
sensor = t - > tx . buf ;
sensor - > id = cpu_to_le32 ( sensor_id ) ;
2019-07-08 09:41:01 +01:00
if ( s - > async ) {
sensor - > flags = cpu_to_le32 ( SENSOR_READ_ASYNC ) ;
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > do_xfer_with_response ( ph , t ) ;
2020-11-19 17:49:04 +00:00
if ( ! ret ) {
struct scmi_resp_sensor_reading_complete * resp ;
resp = t - > rx . buf ;
if ( le32_to_cpu ( resp - > id ) = = sensor_id )
2021-06-28 18:00:42 +01:00
* value =
get_unaligned_le64 ( & resp - > readings_low ) ;
2020-11-19 17:49:04 +00:00
else
ret = - EPROTO ;
}
2019-07-08 09:41:01 +01:00
} else {
sensor - > flags = cpu_to_le32 ( 0 ) ;
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > do_xfer ( ph , t ) ;
2019-08-07 13:46:27 +01:00
if ( ! ret )
* value = get_unaligned_le64 ( t - > rx . buf ) ;
2017-06-06 11:38:10 +01:00
}
2021-03-16 12:48:48 +00:00
ph - > xops - > xfer_put ( ph , t ) ;
2017-06-06 11:38:10 +01:00
return ret ;
}
2020-11-19 17:49:04 +00:00
static inline void
scmi_parse_sensor_readings ( struct scmi_sensor_reading * out ,
2020-11-23 16:20:08 +00:00
const struct scmi_sensor_reading_resp * in )
2020-11-19 17:49:04 +00:00
{
out - > value = get_unaligned_le64 ( ( void * ) & in - > sensor_value_low ) ;
out - > timestamp = get_unaligned_le64 ( ( void * ) & in - > timestamp_low ) ;
}
/**
* scmi_sensor_reading_get_timestamped - Read multiple - axis timestamped values
2021-03-16 12:48:48 +00:00
* @ ph : Protocol handle
2020-11-19 17:49:04 +00:00
* @ sensor_id : Sensor ID
* @ count : The length of the provided @ readings array
* @ readings : An array of elements each representing a timestamped per - axis
* reading of type @ struct scmi_sensor_reading .
* Returned readings are ordered as the @ axis descriptors array
* included in @ struct scmi_sensor_info and the max number of
* returned elements is min ( @ count , @ num_axis ) ; ideally the provided
* array should be of length @ count equal to @ num_axis .
*
* Return : 0 on Success
*/
static int
2021-03-16 12:48:48 +00:00
scmi_sensor_reading_get_timestamped ( const struct scmi_protocol_handle * ph ,
2020-11-19 17:49:04 +00:00
u32 sensor_id , u8 count ,
struct scmi_sensor_reading * readings )
{
int ret ;
struct scmi_xfer * t ;
struct scmi_msg_sensor_reading_get * sensor ;
2021-03-16 12:48:48 +00:00
struct sensors_info * si = ph - > get_priv ( ph ) ;
2020-11-19 17:49:04 +00:00
struct scmi_sensor_info * s = si - > sensors + sensor_id ;
if ( ! count | | ! readings | |
( ! s - > num_axis & & count > 1 ) | | ( s - > num_axis & & count > s - > num_axis ) )
return - EINVAL ;
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > xfer_get_init ( ph , SENSOR_READING_GET ,
sizeof ( * sensor ) , 0 , & t ) ;
2020-11-19 17:49:04 +00:00
if ( ret )
return ret ;
sensor = t - > tx . buf ;
sensor - > id = cpu_to_le32 ( sensor_id ) ;
if ( s - > async ) {
sensor - > flags = cpu_to_le32 ( SENSOR_READ_ASYNC ) ;
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > do_xfer_with_response ( ph , t ) ;
2020-11-19 17:49:04 +00:00
if ( ! ret ) {
int i ;
struct scmi_resp_sensor_reading_complete_v3 * resp ;
resp = t - > rx . buf ;
/* Retrieve only the number of requested axis anyway */
if ( le32_to_cpu ( resp - > id ) = = sensor_id )
for ( i = 0 ; i < count ; i + + )
scmi_parse_sensor_readings ( & readings [ i ] ,
& resp - > readings [ i ] ) ;
else
ret = - EPROTO ;
}
} else {
sensor - > flags = cpu_to_le32 ( 0 ) ;
2021-03-16 12:48:48 +00:00
ret = ph - > xops - > do_xfer ( ph , t ) ;
2020-11-19 17:49:04 +00:00
if ( ! ret ) {
int i ;
2020-11-23 16:20:08 +00:00
struct scmi_sensor_reading_resp * resp_readings ;
2020-11-19 17:49:04 +00:00
resp_readings = t - > rx . buf ;
for ( i = 0 ; i < count ; i + + )
scmi_parse_sensor_readings ( & readings [ i ] ,
& resp_readings [ i ] ) ;
}
}
2021-03-16 12:48:48 +00:00
ph - > xops - > xfer_put ( ph , t ) ;
2020-11-19 17:49:04 +00:00
return ret ;
}
2017-06-06 11:38:10 +01:00
static const struct scmi_sensor_info *
2021-03-16 12:48:48 +00:00
scmi_sensor_info_get ( const struct scmi_protocol_handle * ph , u32 sensor_id )
2017-06-06 11:38:10 +01:00
{
2021-03-16 12:48:48 +00:00
struct sensors_info * si = ph - > get_priv ( ph ) ;
2017-06-06 11:38:10 +01:00
return si - > sensors + sensor_id ;
}
2021-03-16 12:48:48 +00:00
static int scmi_sensor_count_get ( const struct scmi_protocol_handle * ph )
{
struct sensors_info * si = ph - > get_priv ( ph ) ;
2017-06-06 11:38:10 +01:00
return si - > num_sensors ;
}
2021-03-16 12:48:48 +00:00
static const struct scmi_sensor_proto_ops sensor_proto_ops = {
2017-06-06 11:38:10 +01:00
. count_get = scmi_sensor_count_get ,
. info_get = scmi_sensor_info_get ,
2019-07-08 09:40:33 +01:00
. trip_point_config = scmi_sensor_trip_point_config ,
2017-06-06 11:38:10 +01:00
. reading_get = scmi_sensor_reading_get ,
2020-11-19 17:49:04 +00:00
. reading_get_timestamped = scmi_sensor_reading_get_timestamped ,
2020-11-19 17:49:05 +00:00
. config_get = scmi_sensor_config_get ,
. config_set = scmi_sensor_config_set ,
2017-06-06 11:38:10 +01:00
} ;
2021-03-16 12:48:59 +00:00
static int scmi_sensor_set_notify_enabled ( const struct scmi_protocol_handle * ph ,
2020-07-01 16:53:46 +01:00
u8 evt_id , u32 src_id , bool enable )
{
int ret ;
2020-11-19 17:49:06 +00:00
switch ( evt_id ) {
case SCMI_EVENT_SENSOR_TRIP_POINT_EVENT :
2021-03-16 12:48:48 +00:00
ret = scmi_sensor_trip_point_notify ( ph , src_id , enable ) ;
2020-11-19 17:49:06 +00:00
break ;
case SCMI_EVENT_SENSOR_UPDATE :
2021-03-16 12:48:48 +00:00
ret = scmi_sensor_continuous_update_notify ( ph , src_id , enable ) ;
2020-11-19 17:49:06 +00:00
break ;
default :
ret = - EINVAL ;
break ;
}
2020-07-01 16:53:46 +01:00
if ( ret )
pr_debug ( " FAIL_ENABLED - evt[%X] dom[%d] - ret:%d \n " ,
evt_id , src_id , ret ) ;
return ret ;
}
2021-03-16 12:48:59 +00:00
static void *
scmi_sensor_fill_custom_report ( const struct scmi_protocol_handle * ph ,
u8 evt_id , ktime_t timestamp ,
const void * payld , size_t payld_sz ,
void * report , u32 * src_id )
2020-07-01 16:53:46 +01:00
{
2020-11-19 17:49:06 +00:00
void * rep = NULL ;
2020-07-01 16:53:46 +01:00
2020-11-19 17:49:06 +00:00
switch ( evt_id ) {
case SCMI_EVENT_SENSOR_TRIP_POINT_EVENT :
{
const struct scmi_sensor_trip_notify_payld * p = payld ;
struct scmi_sensor_trip_point_report * r = report ;
2020-07-01 16:53:46 +01:00
2020-11-19 17:49:06 +00:00
if ( sizeof ( * p ) ! = payld_sz )
break ;
2020-07-01 16:53:46 +01:00
2020-11-19 17:49:06 +00:00
r - > timestamp = timestamp ;
r - > agent_id = le32_to_cpu ( p - > agent_id ) ;
r - > sensor_id = le32_to_cpu ( p - > sensor_id ) ;
r - > trip_point_desc = le32_to_cpu ( p - > trip_point_desc ) ;
* src_id = r - > sensor_id ;
rep = r ;
break ;
}
case SCMI_EVENT_SENSOR_UPDATE :
{
int i ;
struct scmi_sensor_info * s ;
const struct scmi_sensor_update_notify_payld * p = payld ;
struct scmi_sensor_update_report * r = report ;
2021-03-16 12:48:59 +00:00
struct sensors_info * sinfo = ph - > get_priv ( ph ) ;
2020-11-19 17:49:06 +00:00
/* payld_sz is variable for this event */
r - > sensor_id = le32_to_cpu ( p - > sensor_id ) ;
if ( r - > sensor_id > = sinfo - > num_sensors )
break ;
r - > timestamp = timestamp ;
r - > agent_id = le32_to_cpu ( p - > agent_id ) ;
s = & sinfo - > sensors [ r - > sensor_id ] ;
/*
* The generated report r ( @ struct scmi_sensor_update_report )
* was pre - allocated to contain up to SCMI_MAX_NUM_SENSOR_AXIS
* readings : here it is filled with the effective @ num_axis
* readings defined for this sensor or 1 for scalar sensors .
*/
r - > readings_count = s - > num_axis ? : 1 ;
for ( i = 0 ; i < r - > readings_count ; i + + )
scmi_parse_sensor_readings ( & r - > readings [ i ] ,
& p - > readings [ i ] ) ;
* src_id = r - > sensor_id ;
rep = r ;
break ;
}
default :
break ;
}
return rep ;
2020-07-01 16:53:46 +01:00
}
2021-03-16 12:48:59 +00:00
static int scmi_sensor_get_num_sources ( const struct scmi_protocol_handle * ph )
2021-03-16 12:48:31 +00:00
{
2021-03-16 12:48:59 +00:00
struct sensors_info * si = ph - > get_priv ( ph ) ;
2021-03-16 12:48:31 +00:00
return si - > num_sensors ;
}
2020-07-01 16:53:46 +01:00
static const struct scmi_event sensor_events [ ] = {
{
. id = SCMI_EVENT_SENSOR_TRIP_POINT_EVENT ,
. max_payld_sz = sizeof ( struct scmi_sensor_trip_notify_payld ) ,
. max_report_sz = sizeof ( struct scmi_sensor_trip_point_report ) ,
} ,
2020-11-19 17:49:06 +00:00
{
. id = SCMI_EVENT_SENSOR_UPDATE ,
. max_payld_sz =
sizeof ( struct scmi_sensor_update_notify_payld ) +
SCMI_MAX_NUM_SENSOR_AXIS *
2020-11-23 16:20:08 +00:00
sizeof ( struct scmi_sensor_reading_resp ) ,
2020-11-19 17:49:06 +00:00
. max_report_sz = sizeof ( struct scmi_sensor_update_report ) +
SCMI_MAX_NUM_SENSOR_AXIS *
sizeof ( struct scmi_sensor_reading ) ,
} ,
2020-07-01 16:53:46 +01:00
} ;
static const struct scmi_event_ops sensor_event_ops = {
2021-03-16 12:48:31 +00:00
. get_num_sources = scmi_sensor_get_num_sources ,
2020-07-01 16:53:46 +01:00
. set_notify_enabled = scmi_sensor_set_notify_enabled ,
. fill_custom_report = scmi_sensor_fill_custom_report ,
} ;
2021-03-16 12:48:31 +00:00
static const struct scmi_protocol_events sensor_protocol_events = {
. queue_sz = SCMI_PROTO_QUEUE_SZ ,
. ops = & sensor_event_ops ,
. evts = sensor_events ,
. num_events = ARRAY_SIZE ( sensor_events ) ,
} ;
2021-03-16 12:48:48 +00:00
static int scmi_sensors_protocol_init ( const struct scmi_protocol_handle * ph )
2017-06-06 11:38:10 +01:00
{
u32 version ;
2020-11-19 17:49:01 +00:00
int ret ;
2017-06-06 11:38:10 +01:00
struct sensors_info * sinfo ;
2021-03-16 12:48:48 +00:00
ph - > xops - > version_get ( ph , & version ) ;
2017-06-06 11:38:10 +01:00
2021-03-16 12:48:48 +00:00
dev_dbg ( ph - > dev , " Sensor Version %d.%d \n " ,
2017-06-06 11:38:10 +01:00
PROTOCOL_REV_MAJOR ( version ) , PROTOCOL_REV_MINOR ( version ) ) ;
2021-03-16 12:48:48 +00:00
sinfo = devm_kzalloc ( ph - > dev , sizeof ( * sinfo ) , GFP_KERNEL ) ;
2017-06-06 11:38:10 +01:00
if ( ! sinfo )
return - ENOMEM ;
2020-11-19 17:49:01 +00:00
sinfo - > version = version ;
2017-06-06 11:38:10 +01:00
2021-03-16 12:48:48 +00:00
ret = scmi_sensor_attributes_get ( ph , sinfo ) ;
2020-11-19 17:49:01 +00:00
if ( ret )
return ret ;
2021-03-16 12:48:48 +00:00
sinfo - > sensors = devm_kcalloc ( ph - > dev , sinfo - > num_sensors ,
2017-06-06 11:38:10 +01:00
sizeof ( * sinfo - > sensors ) , GFP_KERNEL ) ;
if ( ! sinfo - > sensors )
return - ENOMEM ;
2021-03-16 12:48:48 +00:00
ret = scmi_sensor_description_get ( ph , sinfo ) ;
2020-11-19 17:49:01 +00:00
if ( ret )
return ret ;
2017-06-06 11:38:10 +01:00
2021-03-16 12:48:48 +00:00
return ph - > set_priv ( ph , sinfo ) ;
2017-06-06 11:38:10 +01:00
}
2021-03-16 12:48:26 +00:00
static const struct scmi_protocol scmi_sensors = {
. id = SCMI_PROTOCOL_SENSOR ,
2021-03-16 12:49:02 +00:00
. owner = THIS_MODULE ,
2021-03-16 12:48:48 +00:00
. instance_init = & scmi_sensors_protocol_init ,
. ops = & sensor_proto_ops ,
2021-03-16 12:48:31 +00:00
. events = & sensor_protocol_events ,
2021-03-16 12:48:26 +00:00
} ;
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER ( sensors , scmi_sensors )