2020-10-09 23:01:37 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* AMD MP2 Sensors transport driver
*
2021-09-23 15:29:30 +03:00
* Copyright 2020 - 2021 Advanced Micro Devices , Inc .
2020-10-09 23:01:37 +03:00
* Authors : Nehal Bakulchandra Shah < Nehal - bakulchandra . shah @ amd . com >
* Sandeep Singh < sandeep . singh @ amd . com >
2021-09-23 15:29:30 +03:00
* Basavaraj Natikar < Basavaraj . Natikar @ amd . com >
2020-10-09 23:01:37 +03:00
*/
# include <linux/hid.h>
# include <linux/wait.h>
# include <linux/sched.h>
# include "amd_sfh_hid.h"
# define AMD_SFH_RESPONSE_TIMEOUT 1500
/**
* amdtp_hid_parse ( ) - hid - core . parse ( ) callback
* @ hid : hid device instance
*
* This function gets called during call to hid_add_device
*
* Return : 0 on success and non zero on error
*/
static int amdtp_hid_parse ( struct hid_device * hid )
{
struct amdtp_hid_data * hid_data = hid - > driver_data ;
struct amdtp_cl_data * cli_data = hid_data - > cli_data ;
return hid_parse_report ( hid , cli_data - > report_descr [ hid_data - > index ] ,
cli_data - > report_descr_sz [ hid_data - > index ] ) ;
}
/* Empty callbacks with success return code */
static int amdtp_hid_start ( struct hid_device * hid )
{
return 0 ;
}
static void amdtp_hid_stop ( struct hid_device * hid )
{
}
static int amdtp_hid_open ( struct hid_device * hid )
{
return 0 ;
}
static void amdtp_hid_close ( struct hid_device * hid )
{
}
static int amdtp_raw_request ( struct hid_device * hdev , u8 reportnum ,
u8 * buf , size_t len , u8 rtype , int reqtype )
{
return 0 ;
}
static void amdtp_hid_request ( struct hid_device * hid , struct hid_report * rep , int reqtype )
{
int rc ;
switch ( reqtype ) {
case HID_REQ_GET_REPORT :
rc = amd_sfh_get_report ( hid , rep - > id , rep - > type ) ;
if ( rc )
dev_err ( & hid - > dev , " AMDSFH get report error \n " ) ;
break ;
case HID_REQ_SET_REPORT :
amd_sfh_set_report ( hid , rep - > id , reqtype ) ;
break ;
default :
break ;
}
}
static int amdtp_wait_for_response ( struct hid_device * hid )
{
struct amdtp_hid_data * hid_data = hid - > driver_data ;
struct amdtp_cl_data * cli_data = hid_data - > cli_data ;
int i , ret = 0 ;
for ( i = 0 ; i < cli_data - > num_hid_devices ; i + + ) {
if ( cli_data - > hid_sensor_hubs [ i ] = = hid )
break ;
}
if ( ! cli_data - > request_done [ i ] )
ret = wait_event_interruptible_timeout ( hid_data - > hid_wait ,
cli_data - > request_done [ i ] ,
msecs_to_jiffies ( AMD_SFH_RESPONSE_TIMEOUT ) ) ;
2020-10-30 17:30:02 +03:00
if ( ret = = - ERESTARTSYS )
2020-10-09 23:01:37 +03:00
return - ERESTARTSYS ;
2020-10-30 17:30:02 +03:00
else if ( ret < 0 )
return - ETIMEDOUT ;
2020-10-09 23:01:37 +03:00
else
return 0 ;
}
void amdtp_hid_wakeup ( struct hid_device * hid )
{
struct amdtp_hid_data * hid_data = hid - > driver_data ;
struct amdtp_cl_data * cli_data = hid_data - > cli_data ;
cli_data - > request_done [ cli_data - > cur_hid_dev ] = true ;
wake_up_interruptible ( & hid_data - > hid_wait ) ;
}
static struct hid_ll_driver amdtp_hid_ll_driver = {
. parse = amdtp_hid_parse ,
. start = amdtp_hid_start ,
. stop = amdtp_hid_stop ,
. open = amdtp_hid_open ,
. close = amdtp_hid_close ,
. request = amdtp_hid_request ,
. wait = amdtp_wait_for_response ,
. raw_request = amdtp_raw_request ,
} ;
int amdtp_hid_probe ( u32 cur_hid_dev , struct amdtp_cl_data * cli_data )
{
struct hid_device * hid ;
struct amdtp_hid_data * hid_data ;
int rc ;
hid = hid_allocate_device ( ) ;
if ( IS_ERR ( hid ) )
return PTR_ERR ( hid ) ;
hid_data = kzalloc ( sizeof ( * hid_data ) , GFP_KERNEL ) ;
if ( ! hid_data ) {
rc = - ENOMEM ;
goto err_hid_data ;
}
hid - > ll_driver = & amdtp_hid_ll_driver ;
hid_data - > index = cur_hid_dev ;
hid_data - > cli_data = cli_data ;
init_waitqueue_head ( & hid_data - > hid_wait ) ;
hid - > driver_data = hid_data ;
cli_data - > hid_sensor_hubs [ cur_hid_dev ] = hid ;
hid - > bus = BUS_AMD_AMDTP ;
hid - > vendor = AMD_SFH_HID_VENDOR ;
hid - > product = AMD_SFH_HID_PRODUCT ;
snprintf ( hid - > name , sizeof ( hid - > name ) , " %s %04X:%04X " , " hid-amdtp " ,
hid - > vendor , hid - > product ) ;
rc = hid_add_device ( hid ) ;
if ( rc )
goto err_hid_device ;
return 0 ;
err_hid_device :
kfree ( hid_data ) ;
err_hid_data :
hid_destroy_device ( hid ) ;
return rc ;
}
void amdtp_hid_remove ( struct amdtp_cl_data * cli_data )
{
int i ;
for ( i = 0 ; i < cli_data - > num_hid_devices ; + + i ) {
if ( cli_data - > hid_sensor_hubs [ i ] ) {
kfree ( cli_data - > hid_sensor_hubs [ i ] - > driver_data ) ;
hid_destroy_device ( cli_data - > hid_sensor_hubs [ i ] ) ;
cli_data - > hid_sensor_hubs [ i ] = NULL ;
}
}
}