2020-10-10 01:31:37 +05:30
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* AMD SFH Client Layer
2021-09-23 17:59:30 +05:30
* Copyright 2020 - 2021 Advanced Micro Devices , Inc .
2020-10-10 01:31:37 +05:30
* Authors : Nehal Bakulchandra Shah < Nehal - Bakulchandra . Shah @ amd . com >
* Sandeep Singh < Sandeep . singh @ amd . com >
2021-09-23 17:59:30 +05:30
* Basavaraj Natikar < Basavaraj . Natikar @ amd . com >
2020-10-10 01:31:37 +05:30
*/
# include <linux/dma-mapping.h>
# include <linux/hid.h>
# include <linux/list.h>
# include <linux/slab.h>
# include <linux/workqueue.h>
# include <linux/errno.h>
# include "hid_descriptor/amd_sfh_hid_desc.h"
# include "amd_sfh_pcie.h"
# include "amd_sfh_hid.h"
void amd_sfh_set_report ( struct hid_device * hid , int report_id ,
int report_type )
{
struct amdtp_hid_data * hid_data = hid - > driver_data ;
struct amdtp_cl_data * cli_data = hid_data - > cli_data ;
int i ;
for ( i = 0 ; i < cli_data - > num_hid_devices ; i + + ) {
if ( cli_data - > hid_sensor_hubs [ i ] = = hid ) {
cli_data - > cur_hid_dev = i ;
break ;
}
}
amdtp_hid_wakeup ( hid ) ;
}
int amd_sfh_get_report ( struct hid_device * hid , int report_id , int report_type )
{
struct amdtp_hid_data * hid_data = hid - > driver_data ;
struct amdtp_cl_data * cli_data = hid_data - > cli_data ;
2022-07-12 23:48:29 +05:30
struct request_list * req_list = & cli_data - > req_list ;
2020-10-10 01:31:37 +05:30
int i ;
for ( i = 0 ; i < cli_data - > num_hid_devices ; i + + ) {
if ( cli_data - > hid_sensor_hubs [ i ] = = hid ) {
struct request_list * new = kzalloc ( sizeof ( * new ) , GFP_KERNEL ) ;
if ( ! new )
return - ENOMEM ;
new - > current_index = i ;
new - > sensor_idx = cli_data - > sensor_idx [ i ] ;
new - > hid = hid ;
new - > report_type = report_type ;
new - > report_id = report_id ;
cli_data - > report_id [ i ] = report_id ;
cli_data - > request_done [ i ] = false ;
2022-07-12 23:48:29 +05:30
list_add ( & new - > list , & req_list - > list ) ;
2020-10-10 01:31:37 +05:30
break ;
}
}
schedule_delayed_work ( & cli_data - > work , 0 ) ;
return 0 ;
}
2022-07-12 23:48:34 +05:30
void amd_sfh_work ( struct work_struct * work )
2020-10-10 01:31:37 +05:30
{
struct amdtp_cl_data * cli_data = container_of ( work , struct amdtp_cl_data , work . work ) ;
2022-07-12 23:48:29 +05:30
struct request_list * req_list = & cli_data - > req_list ;
2021-06-18 13:48:37 +05:30
struct amd_input_data * in_data = cli_data - > in_data ;
2020-10-10 01:31:37 +05:30
struct request_list * req_node ;
u8 current_index , sensor_index ;
2022-07-12 23:48:30 +05:30
struct amd_mp2_ops * mp2_ops ;
struct amd_mp2_dev * mp2 ;
2020-10-10 01:31:37 +05:30
u8 report_id , node_type ;
u8 report_size = 0 ;
2022-07-12 23:48:29 +05:30
req_node = list_last_entry ( & req_list - > list , struct request_list , list ) ;
2020-10-10 01:31:37 +05:30
list_del ( & req_node - > list ) ;
current_index = req_node - > current_index ;
sensor_index = req_node - > sensor_idx ;
report_id = req_node - > report_id ;
node_type = req_node - > report_type ;
2021-05-12 18:41:56 +05:30
kfree ( req_node ) ;
2020-10-10 01:31:37 +05:30
2022-07-12 23:48:30 +05:30
mp2 = container_of ( in_data , struct amd_mp2_dev , in_data ) ;
mp2_ops = mp2 - > mp2_ops ;
2020-10-10 01:31:37 +05:30
if ( node_type = = HID_FEATURE_REPORT ) {
2022-07-12 23:48:30 +05:30
report_size = mp2_ops - > get_feat_rep ( sensor_index , report_id ,
cli_data - > feature_report [ current_index ] ) ;
2020-10-10 01:31:37 +05:30
if ( report_size )
hid_input_report ( cli_data - > hid_sensor_hubs [ current_index ] ,
cli_data - > report_type [ current_index ] ,
cli_data - > feature_report [ current_index ] , report_size , 0 ) ;
else
pr_err ( " AMDSFH: Invalid report size \n " ) ;
} else if ( node_type = = HID_INPUT_REPORT ) {
2022-07-12 23:48:30 +05:30
report_size = mp2_ops - > get_in_rep ( current_index , sensor_index , report_id , in_data ) ;
2020-10-10 01:31:37 +05:30
if ( report_size )
hid_input_report ( cli_data - > hid_sensor_hubs [ current_index ] ,
cli_data - > report_type [ current_index ] ,
2021-06-18 13:48:37 +05:30
in_data - > input_report [ current_index ] , report_size , 0 ) ;
2020-10-10 01:31:37 +05:30
else
pr_err ( " AMDSFH: Invalid report size \n " ) ;
}
cli_data - > cur_hid_dev = current_index ;
cli_data - > sensor_requested_cnt [ current_index ] = 0 ;
amdtp_hid_wakeup ( cli_data - > hid_sensor_hubs [ current_index ] ) ;
}
2022-07-12 23:48:34 +05:30
void amd_sfh_work_buffer ( struct work_struct * work )
2020-10-10 01:31:37 +05:30
{
struct amdtp_cl_data * cli_data = container_of ( work , struct amdtp_cl_data , work_buffer . work ) ;
2021-06-18 13:48:37 +05:30
struct amd_input_data * in_data = cli_data - > in_data ;
2022-07-12 23:48:30 +05:30
struct amd_mp2_dev * mp2 ;
2020-10-10 01:31:37 +05:30
u8 report_size ;
int i ;
for ( i = 0 ; i < cli_data - > num_hid_devices ; i + + ) {
2021-08-02 19:33:38 +05:30
if ( cli_data - > sensor_sts [ i ] = = SENSOR_ENABLED ) {
2022-07-12 23:48:30 +05:30
mp2 = container_of ( in_data , struct amd_mp2_dev , in_data ) ;
report_size = mp2 - > mp2_ops - > get_in_rep ( i , cli_data - > sensor_idx [ i ] ,
cli_data - > report_id [ i ] , in_data ) ;
2021-08-02 19:33:38 +05:30
hid_input_report ( cli_data - > hid_sensor_hubs [ i ] , HID_INPUT_REPORT ,
in_data - > input_report [ i ] , report_size , 0 ) ;
}
2020-10-10 01:31:37 +05:30
}
schedule_delayed_work ( & cli_data - > work_buffer , msecs_to_jiffies ( AMD_SFH_IDLE_LOOP ) ) ;
}
2022-07-12 23:48:33 +05:30
static u32 amd_sfh_wait_for_response ( struct amd_mp2_dev * mp2 , u8 sid , u32 sensor_sts )
2021-08-02 19:33:38 +05:30
{
if ( mp2 - > mp2_ops - > response )
sensor_sts = mp2 - > mp2_ops - > response ( mp2 , sid , sensor_sts ) ;
return sensor_sts ;
}
2022-07-12 23:48:33 +05:30
static const char * get_sensor_name ( int idx )
2022-05-09 18:50:21 +05:30
{
switch ( idx ) {
case accel_idx :
return " accelerometer " ;
case gyro_idx :
return " gyroscope " ;
case mag_idx :
return " magnetometer " ;
case als_idx :
return " ALS " ;
case HPD_IDX :
return " HPD " ;
default :
return " unknown sensor type " ;
}
}
2022-07-12 23:48:31 +05:30
static void amd_sfh_resume ( struct amd_mp2_dev * mp2 )
{
struct amdtp_cl_data * cl_data = mp2 - > cl_data ;
struct amd_mp2_sensor_info info ;
int i , status ;
for ( i = 0 ; i < cl_data - > num_hid_devices ; i + + ) {
if ( cl_data - > sensor_sts [ i ] = = SENSOR_DISABLED ) {
info . period = AMD_SFH_IDLE_LOOP ;
info . sensor_idx = cl_data - > sensor_idx [ i ] ;
info . dma_address = cl_data - > sensor_dma_addr [ i ] ;
mp2 - > mp2_ops - > start ( mp2 , info ) ;
status = amd_sfh_wait_for_response
( mp2 , cl_data - > sensor_idx [ i ] , SENSOR_ENABLED ) ;
if ( status = = SENSOR_ENABLED )
cl_data - > sensor_sts [ i ] = SENSOR_ENABLED ;
dev_dbg ( & mp2 - > pdev - > dev , " resume sid 0x%x (%s) status 0x%x \n " ,
cl_data - > sensor_idx [ i ] , get_sensor_name ( cl_data - > sensor_idx [ i ] ) ,
cl_data - > sensor_sts [ i ] ) ;
}
}
schedule_delayed_work ( & cl_data - > work_buffer , msecs_to_jiffies ( AMD_SFH_IDLE_LOOP ) ) ;
2022-07-12 23:48:35 +05:30
amd_sfh_clear_intr ( mp2 ) ;
2022-07-12 23:48:31 +05:30
}
static void amd_sfh_suspend ( struct amd_mp2_dev * mp2 )
{
struct amdtp_cl_data * cl_data = mp2 - > cl_data ;
int i , status ;
for ( i = 0 ; i < cl_data - > num_hid_devices ; i + + ) {
if ( cl_data - > sensor_idx [ i ] ! = HPD_IDX & &
cl_data - > sensor_sts [ i ] = = SENSOR_ENABLED ) {
mp2 - > mp2_ops - > stop ( mp2 , cl_data - > sensor_idx [ i ] ) ;
status = amd_sfh_wait_for_response
( mp2 , cl_data - > sensor_idx [ i ] , SENSOR_DISABLED ) ;
if ( status ! = SENSOR_ENABLED )
cl_data - > sensor_sts [ i ] = SENSOR_DISABLED ;
dev_dbg ( & mp2 - > pdev - > dev , " suspend sid 0x%x (%s) status 0x%x \n " ,
cl_data - > sensor_idx [ i ] , get_sensor_name ( cl_data - > sensor_idx [ i ] ) ,
cl_data - > sensor_sts [ i ] ) ;
}
}
cancel_delayed_work_sync ( & cl_data - > work_buffer ) ;
2022-07-12 23:48:35 +05:30
amd_sfh_clear_intr ( mp2 ) ;
2022-07-12 23:48:31 +05:30
}
2020-10-10 01:31:37 +05:30
int amd_sfh_hid_client_init ( struct amd_mp2_dev * privdata )
{
2021-06-18 13:48:37 +05:30
struct amd_input_data * in_data = & privdata - > in_data ;
2020-10-10 01:31:37 +05:30
struct amdtp_cl_data * cl_data = privdata - > cl_data ;
2022-07-12 23:48:30 +05:30
struct amd_mp2_ops * mp2_ops = privdata - > mp2_ops ;
2020-10-10 01:31:37 +05:30
struct amd_mp2_sensor_info info ;
2022-07-12 23:48:29 +05:30
struct request_list * req_list ;
2020-10-10 01:31:37 +05:30
struct device * dev ;
u32 feature_report_size ;
u32 input_report_size ;
2021-08-02 19:33:38 +05:30
int rc , i , status ;
2020-10-10 01:31:37 +05:30
u8 cl_idx ;
2022-07-12 23:48:29 +05:30
req_list = & cl_data - > req_list ;
2020-10-10 01:31:37 +05:30
dev = & privdata - > pdev - > dev ;
2022-07-12 23:48:30 +05:30
amd_sfh_set_desc_ops ( mp2_ops ) ;
2020-10-10 01:31:37 +05:30
2022-07-12 23:48:31 +05:30
mp2_ops - > suspend = amd_sfh_suspend ;
mp2_ops - > resume = amd_sfh_resume ;
2020-10-10 01:31:37 +05:30
cl_data - > num_hid_devices = amd_mp2_get_sensor_num ( privdata , & cl_data - > sensor_idx [ 0 ] ) ;
2022-07-23 11:40:33 +05:30
if ( cl_data - > num_hid_devices = = 0 )
return - ENODEV ;
2020-10-10 01:31:37 +05:30
INIT_DELAYED_WORK ( & cl_data - > work , amd_sfh_work ) ;
INIT_DELAYED_WORK ( & cl_data - > work_buffer , amd_sfh_work_buffer ) ;
2022-07-12 23:48:29 +05:30
INIT_LIST_HEAD ( & req_list - > list ) ;
2021-06-18 13:48:37 +05:30
cl_data - > in_data = in_data ;
2020-10-10 01:31:37 +05:30
for ( i = 0 ; i < cl_data - > num_hid_devices ; i + + ) {
2021-06-18 13:48:37 +05:30
in_data - > sensor_virt_addr [ i ] = dma_alloc_coherent ( dev , sizeof ( int ) * 8 ,
2021-01-03 14:53:55 +01:00
& cl_data - > sensor_dma_addr [ i ] ,
2020-10-10 01:31:37 +05:30
GFP_KERNEL ) ;
2021-08-02 19:33:38 +05:30
cl_data - > sensor_sts [ i ] = SENSOR_DISABLED ;
2020-10-10 01:31:37 +05:30
cl_data - > sensor_requested_cnt [ i ] = 0 ;
cl_data - > cur_hid_dev = i ;
cl_idx = cl_data - > sensor_idx [ i ] ;
2022-07-12 23:48:30 +05:30
cl_data - > report_descr_sz [ i ] = mp2_ops - > get_desc_sz ( cl_idx , descr_size ) ;
2020-10-10 01:31:37 +05:30
if ( ! cl_data - > report_descr_sz [ i ] ) {
rc = - EINVAL ;
goto cleanup ;
}
2022-07-12 23:48:30 +05:30
feature_report_size = mp2_ops - > get_desc_sz ( cl_idx , feature_size ) ;
2020-10-10 01:31:37 +05:30
if ( ! feature_report_size ) {
rc = - EINVAL ;
goto cleanup ;
}
2022-07-12 23:48:30 +05:30
input_report_size = mp2_ops - > get_desc_sz ( cl_idx , input_size ) ;
2020-10-10 01:31:37 +05:30
if ( ! input_report_size ) {
rc = - EINVAL ;
goto cleanup ;
}
2021-05-12 18:41:55 +05:30
cl_data - > feature_report [ i ] = devm_kzalloc ( dev , feature_report_size , GFP_KERNEL ) ;
2020-10-10 01:31:37 +05:30
if ( ! cl_data - > feature_report [ i ] ) {
rc = - ENOMEM ;
goto cleanup ;
}
2021-06-18 13:48:37 +05:30
in_data - > input_report [ i ] = devm_kzalloc ( dev , input_report_size , GFP_KERNEL ) ;
if ( ! in_data - > input_report [ i ] ) {
2020-10-10 01:31:37 +05:30
rc = - ENOMEM ;
goto cleanup ;
}
2021-08-02 19:33:37 +05:30
info . period = AMD_SFH_IDLE_LOOP ;
2020-10-10 01:31:37 +05:30
info . sensor_idx = cl_idx ;
2021-01-03 14:53:55 +01:00
info . dma_address = cl_data - > sensor_dma_addr [ i ] ;
2020-10-10 01:31:37 +05:30
2021-05-12 18:41:55 +05:30
cl_data - > report_descr [ i ] =
devm_kzalloc ( dev , cl_data - > report_descr_sz [ i ] , GFP_KERNEL ) ;
2020-10-10 01:31:37 +05:30
if ( ! cl_data - > report_descr [ i ] ) {
rc = - ENOMEM ;
goto cleanup ;
}
2022-07-12 23:48:30 +05:30
rc = mp2_ops - > get_rep_desc ( cl_idx , cl_data - > report_descr [ i ] ) ;
2020-10-10 01:31:37 +05:30
if ( rc )
return rc ;
2022-07-12 23:48:30 +05:30
mp2_ops - > start ( privdata , info ) ;
2021-08-02 19:33:38 +05:30
status = amd_sfh_wait_for_response
( privdata , cl_data - > sensor_idx [ i ] , SENSOR_ENABLED ) ;
2021-08-02 19:33:39 +05:30
if ( status = = SENSOR_ENABLED ) {
2021-08-02 19:33:38 +05:30
cl_data - > sensor_sts [ i ] = SENSOR_ENABLED ;
2021-08-02 19:33:39 +05:30
rc = amdtp_hid_probe ( cl_data - > cur_hid_dev , cl_data ) ;
if ( rc ) {
2022-07-12 23:48:30 +05:30
mp2_ops - > stop ( privdata , cl_data - > sensor_idx [ i ] ) ;
2021-08-02 19:33:39 +05:30
status = amd_sfh_wait_for_response
( privdata , cl_data - > sensor_idx [ i ] , SENSOR_DISABLED ) ;
if ( status ! = SENSOR_ENABLED )
cl_data - > sensor_sts [ i ] = SENSOR_DISABLED ;
2022-05-09 18:50:21 +05:30
dev_dbg ( dev , " sid 0x%x (%s) status 0x%x \n " ,
cl_data - > sensor_idx [ i ] ,
get_sensor_name ( cl_data - > sensor_idx [ i ] ) ,
cl_data - > sensor_sts [ i ] ) ;
2021-08-02 19:33:39 +05:30
goto cleanup ;
}
}
2022-05-09 18:50:21 +05:30
dev_dbg ( dev , " sid 0x%x (%s) status 0x%x \n " ,
cl_data - > sensor_idx [ i ] , get_sensor_name ( cl_data - > sensor_idx [ i ] ) ,
cl_data - > sensor_sts [ i ] ) ;
2020-10-10 01:31:37 +05:30
}
2022-07-12 23:48:30 +05:30
if ( mp2_ops - > discovery_status & & mp2_ops - > discovery_status ( privdata ) = = 0 ) {
2022-05-09 18:50:20 +05:30
amd_sfh_hid_client_deinit ( privdata ) ;
for ( i = 0 ; i < cl_data - > num_hid_devices ; i + + ) {
devm_kfree ( dev , cl_data - > feature_report [ i ] ) ;
devm_kfree ( dev , in_data - > input_report [ i ] ) ;
devm_kfree ( dev , cl_data - > report_descr [ i ] ) ;
}
dev_warn ( dev , " Failed to discover, sensors not enabled \n " ) ;
return - EOPNOTSUPP ;
}
2020-10-10 01:31:37 +05:30
schedule_delayed_work ( & cl_data - > work_buffer , msecs_to_jiffies ( AMD_SFH_IDLE_LOOP ) ) ;
return 0 ;
cleanup :
for ( i = 0 ; i < cl_data - > num_hid_devices ; i + + ) {
2021-06-18 13:48:37 +05:30
if ( in_data - > sensor_virt_addr [ i ] ) {
2020-10-10 01:31:37 +05:30
dma_free_coherent ( & privdata - > pdev - > dev , 8 * sizeof ( int ) ,
2021-06-18 13:48:37 +05:30
in_data - > sensor_virt_addr [ i ] ,
2021-01-03 14:53:55 +01:00
cl_data - > sensor_dma_addr [ i ] ) ;
2020-10-10 01:31:37 +05:30
}
2021-05-12 18:41:55 +05:30
devm_kfree ( dev , cl_data - > feature_report [ i ] ) ;
2021-06-18 13:48:37 +05:30
devm_kfree ( dev , in_data - > input_report [ i ] ) ;
2021-05-12 18:41:55 +05:30
devm_kfree ( dev , cl_data - > report_descr [ i ] ) ;
2020-10-10 01:31:37 +05:30
}
return rc ;
}
int amd_sfh_hid_client_deinit ( struct amd_mp2_dev * privdata )
{
struct amdtp_cl_data * cl_data = privdata - > cl_data ;
2021-06-18 13:48:37 +05:30
struct amd_input_data * in_data = cl_data - > in_data ;
2021-08-02 19:33:38 +05:30
int i , status ;
2020-10-10 01:31:37 +05:30
2021-08-02 19:33:38 +05:30
for ( i = 0 ; i < cl_data - > num_hid_devices ; i + + ) {
if ( cl_data - > sensor_sts [ i ] = = SENSOR_ENABLED ) {
privdata - > mp2_ops - > stop ( privdata , cl_data - > sensor_idx [ i ] ) ;
status = amd_sfh_wait_for_response
( privdata , cl_data - > sensor_idx [ i ] , SENSOR_DISABLED ) ;
if ( status ! = SENSOR_ENABLED )
cl_data - > sensor_sts [ i ] = SENSOR_DISABLED ;
2022-05-09 18:50:21 +05:30
dev_dbg ( & privdata - > pdev - > dev , " stopping sid 0x%x (%s) status 0x%x \n " ,
cl_data - > sensor_idx [ i ] , get_sensor_name ( cl_data - > sensor_idx [ i ] ) ,
cl_data - > sensor_sts [ i ] ) ;
2021-08-02 19:33:38 +05:30
}
}
2020-10-10 01:31:37 +05:30
cancel_delayed_work_sync ( & cl_data - > work ) ;
cancel_delayed_work_sync ( & cl_data - > work_buffer ) ;
amdtp_hid_remove ( cl_data ) ;
for ( i = 0 ; i < cl_data - > num_hid_devices ; i + + ) {
2021-06-18 13:48:37 +05:30
if ( in_data - > sensor_virt_addr [ i ] ) {
2020-10-10 01:31:37 +05:30
dma_free_coherent ( & privdata - > pdev - > dev , 8 * sizeof ( int ) ,
2021-06-18 13:48:37 +05:30
in_data - > sensor_virt_addr [ i ] ,
2021-01-03 14:53:55 +01:00
cl_data - > sensor_dma_addr [ i ] ) ;
2020-10-10 01:31:37 +05:30
}
}
return 0 ;
}