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"
struct request_list {
struct hid_device * hid ;
struct list_head list ;
u8 report_id ;
u8 sensor_idx ;
u8 report_type ;
u8 current_index ;
} ;
static struct request_list req_list ;
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 ;
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 ;
list_add ( & new - > list , & req_list . list ) ;
break ;
}
}
schedule_delayed_work ( & cli_data - > work , 0 ) ;
return 0 ;
}
static void amd_sfh_work ( struct work_struct * work )
{
struct amdtp_cl_data * cli_data = container_of ( work , struct amdtp_cl_data , work . work ) ;
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 ;
u8 report_id , node_type ;
u8 report_size = 0 ;
req_node = list_last_entry ( & req_list . list , struct request_list , list ) ;
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
if ( node_type = = HID_FEATURE_REPORT ) {
report_size = get_feature_report ( sensor_index , report_id ,
cli_data - > feature_report [ current_index ] ) ;
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 ) {
2021-06-18 13:48:37 +05:30
report_size = get_input_report ( 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 ] ) ;
}
static void amd_sfh_work_buffer ( struct work_struct * work )
{
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 ;
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 ) {
report_size = get_input_report
( i , cli_data - > sensor_idx [ i ] , cli_data - > report_id [ i ] , in_data ) ;
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 ) ) ;
}
2021-08-02 19:33:38 +05:30
u32 amd_sfh_wait_for_response ( struct amd_mp2_dev * mp2 , u8 sid , u32 sensor_sts )
{
if ( mp2 - > mp2_ops - > response )
sensor_sts = mp2 - > mp2_ops - > response ( mp2 , sid , sensor_sts ) ;
return sensor_sts ;
}
2022-05-09 18:50:21 +05:30
const char * get_sensor_name ( int idx )
{
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 " ;
}
}
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 ;
struct amd_mp2_sensor_info info ;
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 ;
dev = & privdata - > pdev - > dev ;
cl_data - > num_hid_devices = amd_mp2_get_sensor_num ( privdata , & cl_data - > sensor_idx [ 0 ] ) ;
INIT_DELAYED_WORK ( & cl_data - > work , amd_sfh_work ) ;
INIT_DELAYED_WORK ( & cl_data - > work_buffer , amd_sfh_work_buffer ) ;
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 ] ;
cl_data - > report_descr_sz [ i ] = get_descr_sz ( cl_idx , descr_size ) ;
if ( ! cl_data - > report_descr_sz [ i ] ) {
rc = - EINVAL ;
goto cleanup ;
}
feature_report_size = get_descr_sz ( cl_idx , feature_size ) ;
if ( ! feature_report_size ) {
rc = - EINVAL ;
goto cleanup ;
}
input_report_size = get_descr_sz ( cl_idx , input_size ) ;
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 ;
}
rc = get_report_descriptor ( cl_idx , cl_data - > report_descr [ i ] ) ;
if ( rc )
return rc ;
2021-06-18 13:48:36 +05:30
privdata - > 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 ) {
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 ( 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-05-09 18:50:20 +05:30
if ( privdata - > mp2_ops - > discovery_status & &
privdata - > mp2_ops - > discovery_status ( privdata ) = = 0 ) {
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 ;
}