2019-10-05 23:42:55 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Common code for Intel Cherry Trail ACPI INT33FE pseudo device drivers
* ( USB Micro - B and Type - C connector variants ) .
*
* Copyright ( c ) 2019 Yauhen Kharuzhy < jekhor @ gmail . com >
*/
# include <linux/acpi.h>
# include <linux/i2c.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
# include "intel_cht_int33fe_common.h"
# define EXPECTED_PTYPE 4
static int cht_int33fe_i2c_res_filter ( struct acpi_resource * ares , void * data )
{
struct acpi_resource_i2c_serialbus * sb ;
int * count = data ;
if ( i2c_acpi_get_i2c_resource ( ares , & sb ) )
( * count ) + + ;
return 1 ;
}
static int cht_int33fe_count_i2c_clients ( struct device * dev )
{
2020-05-26 15:53:29 +03:00
struct acpi_device * adev = ACPI_COMPANION ( dev ) ;
2019-10-05 23:42:55 +03:00
LIST_HEAD ( resource_list ) ;
int count = 0 ;
2020-05-26 15:53:29 +03:00
int ret ;
2019-10-05 23:42:55 +03:00
2020-05-26 15:53:29 +03:00
ret = acpi_dev_get_resources ( adev , & resource_list ,
cht_int33fe_i2c_res_filter , & count ) ;
2019-10-05 23:42:55 +03:00
acpi_dev_free_resource_list ( & resource_list ) ;
2020-05-26 15:53:29 +03:00
if ( ret < 0 )
return ret ;
2019-10-05 23:42:55 +03:00
return count ;
}
static int cht_int33fe_check_hw_type ( struct device * dev )
{
unsigned long long ptyp ;
acpi_status status ;
int ret ;
status = acpi_evaluate_integer ( ACPI_HANDLE ( dev ) , " PTYP " , NULL , & ptyp ) ;
if ( ACPI_FAILURE ( status ) ) {
dev_err ( dev , " Error getting PTYPE \n " ) ;
return - ENODEV ;
}
/*
* The same ACPI HID is used for different configurations check PTYP
* to ensure that we are dealing with the expected config .
*/
if ( ptyp ! = EXPECTED_PTYPE )
return - ENODEV ;
/* Check presence of INT34D3 (hardware-rev 3) expected for ptype == 4 */
if ( ! acpi_dev_present ( " INT34D3 " , " 1 " , 3 ) ) {
dev_err ( dev , " Error PTYPE == %d, but no INT34D3 device \n " ,
EXPECTED_PTYPE ) ;
return - ENODEV ;
}
ret = cht_int33fe_count_i2c_clients ( dev ) ;
if ( ret < 0 )
return ret ;
switch ( ret ) {
case 2 :
return INT33FE_HW_MICROB ;
case 4 :
return INT33FE_HW_TYPEC ;
default :
return - ENODEV ;
}
}
static int cht_int33fe_probe ( struct platform_device * pdev )
{
struct cht_int33fe_data * data ;
struct device * dev = & pdev - > dev ;
int ret ;
ret = cht_int33fe_check_hw_type ( dev ) ;
if ( ret < 0 )
return ret ;
data = devm_kzalloc ( dev , sizeof ( * data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
data - > dev = dev ;
switch ( ret ) {
case INT33FE_HW_MICROB :
data - > probe = cht_int33fe_microb_probe ;
data - > remove = cht_int33fe_microb_remove ;
break ;
case INT33FE_HW_TYPEC :
data - > probe = cht_int33fe_typec_probe ;
data - > remove = cht_int33fe_typec_remove ;
break ;
}
platform_set_drvdata ( pdev , data ) ;
return data - > probe ( data ) ;
}
static int cht_int33fe_remove ( struct platform_device * pdev )
{
struct cht_int33fe_data * data = platform_get_drvdata ( pdev ) ;
return data - > remove ( data ) ;
}
static const struct acpi_device_id cht_int33fe_acpi_ids [ ] = {
{ " INT33FE " , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( acpi , cht_int33fe_acpi_ids ) ;
static struct platform_driver cht_int33fe_driver = {
. driver = {
. name = " Intel Cherry Trail ACPI INT33FE driver " ,
. acpi_match_table = ACPI_PTR ( cht_int33fe_acpi_ids ) ,
} ,
. probe = cht_int33fe_probe ,
. remove = cht_int33fe_remove ,
} ;
module_platform_driver ( cht_int33fe_driver ) ;
MODULE_DESCRIPTION ( " Intel Cherry Trail ACPI INT33FE pseudo device driver " ) ;
MODULE_AUTHOR ( " Yauhen Kharuzhy <jekhor@gmail.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;