2020-09-15 16:18:14 -07:00
// SPDX-License-Identifier: GPL-2.0-only
/*
* dptf_pch_fivr : DPTF PCH FIVR Participant driver
* Copyright ( c ) 2020 , Intel Corporation .
*/
# include <linux/acpi.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/platform_device.h>
2021-07-27 09:18:24 -07:00
struct pch_fivr_resp {
u64 status ;
u64 result ;
} ;
static int pch_fivr_read ( acpi_handle handle , char * method , struct pch_fivr_resp * fivr_resp )
{
struct acpi_buffer resp = { sizeof ( struct pch_fivr_resp ) , fivr_resp } ;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER , NULL } ;
struct acpi_buffer format = { sizeof ( " NN " ) , " NN " } ;
union acpi_object * obj ;
acpi_status status ;
int ret = - EFAULT ;
status = acpi_evaluate_object ( handle , method , NULL , & buffer ) ;
if ( ACPI_FAILURE ( status ) )
return ret ;
obj = buffer . pointer ;
if ( ! obj | | obj - > type ! = ACPI_TYPE_PACKAGE )
goto release_buffer ;
status = acpi_extract_package ( obj , & format , & resp ) ;
if ( ACPI_FAILURE ( status ) )
goto release_buffer ;
if ( fivr_resp - > status )
goto release_buffer ;
ret = 0 ;
release_buffer :
kfree ( buffer . pointer ) ;
return ret ;
}
2020-09-15 16:18:14 -07:00
/*
2021-11-12 17:30:29 +05:30
* Presentation of attributes which are defined for INTC10xx
2020-09-15 16:18:14 -07:00
* They are :
* freq_mhz_low_clock : Set PCH FIVR switching freq for
* FIVR clock 19.2 MHz and 24 MHz
* freq_mhz_high_clock : Set PCH FIVR switching freq for
* FIVR clock 38.4 MHz
*/
# define PCH_FIVR_SHOW(name, method) \
static ssize_t name # # _show ( struct device * dev , \
struct device_attribute * attr , \
char * buf ) \
{ \
struct acpi_device * acpi_dev = dev_get_drvdata ( dev ) ; \
2021-07-27 09:18:24 -07:00
struct pch_fivr_resp fivr_resp ; \
int status ; \
\
status = pch_fivr_read ( acpi_dev - > handle , # method , & fivr_resp ) ; \
if ( status ) \
return status ; \
2020-09-15 16:18:14 -07:00
\
2021-07-27 09:18:24 -07:00
return sprintf ( buf , " %llu \n " , fivr_resp . result ) ; \
2020-09-15 16:18:14 -07:00
}
# define PCH_FIVR_STORE(name, method) \
static ssize_t name # # _store ( struct device * dev , \
struct device_attribute * attr , \
const char * buf , size_t count ) \
{ \
struct acpi_device * acpi_dev = dev_get_drvdata ( dev ) ; \
acpi_status status ; \
u32 val ; \
\
if ( kstrtouint ( buf , 0 , & val ) < 0 ) \
return - EINVAL ; \
\
status = acpi_execute_simple_method ( acpi_dev - > handle , # method , val ) ; \
if ( ACPI_SUCCESS ( status ) ) \
return count ; \
\
return - EINVAL ; \
}
PCH_FIVR_SHOW ( freq_mhz_low_clock , GFC0 )
PCH_FIVR_SHOW ( freq_mhz_high_clock , GFC1 )
2021-07-27 09:22:40 -07:00
PCH_FIVR_SHOW ( ssc_clock_info , GEMI )
PCH_FIVR_SHOW ( fivr_switching_freq_mhz , GFCS )
PCH_FIVR_SHOW ( fivr_switching_fault_status , GFFS )
2020-09-15 16:18:14 -07:00
PCH_FIVR_STORE ( freq_mhz_low_clock , RFC0 )
PCH_FIVR_STORE ( freq_mhz_high_clock , RFC1 )
static DEVICE_ATTR_RW ( freq_mhz_low_clock ) ;
static DEVICE_ATTR_RW ( freq_mhz_high_clock ) ;
2021-07-27 09:22:40 -07:00
static DEVICE_ATTR_RO ( ssc_clock_info ) ;
static DEVICE_ATTR_RO ( fivr_switching_freq_mhz ) ;
static DEVICE_ATTR_RO ( fivr_switching_fault_status ) ;
2020-09-15 16:18:14 -07:00
static struct attribute * fivr_attrs [ ] = {
& dev_attr_freq_mhz_low_clock . attr ,
& dev_attr_freq_mhz_high_clock . attr ,
2021-07-27 09:22:40 -07:00
& dev_attr_ssc_clock_info . attr ,
& dev_attr_fivr_switching_freq_mhz . attr ,
& dev_attr_fivr_switching_fault_status . attr ,
2020-09-15 16:18:14 -07:00
NULL
} ;
static const struct attribute_group pch_fivr_attribute_group = {
. attrs = fivr_attrs ,
. name = " pch_fivr_switch_frequency "
} ;
static int pch_fivr_add ( struct platform_device * pdev )
{
struct acpi_device * acpi_dev ;
unsigned long long ptype ;
acpi_status status ;
int result ;
acpi_dev = ACPI_COMPANION ( & ( pdev - > dev ) ) ;
if ( ! acpi_dev )
return - ENODEV ;
status = acpi_evaluate_integer ( acpi_dev - > handle , " PTYP " , NULL , & ptype ) ;
if ( ACPI_FAILURE ( status ) | | ptype ! = 0x05 )
return - ENODEV ;
result = sysfs_create_group ( & pdev - > dev . kobj ,
& pch_fivr_attribute_group ) ;
if ( result )
return result ;
platform_set_drvdata ( pdev , acpi_dev ) ;
return 0 ;
}
static int pch_fivr_remove ( struct platform_device * pdev )
{
sysfs_remove_group ( & pdev - > dev . kobj , & pch_fivr_attribute_group ) ;
return 0 ;
}
static const struct acpi_device_id pch_fivr_device_ids [ ] = {
{ " INTC1045 " , 0 } ,
2020-11-10 09:50:58 -08:00
{ " INTC1049 " , 0 } ,
2022-05-23 23:16:30 +05:30
{ " INTC1064 " , 0 } ,
2022-01-14 15:24:33 -08:00
{ " INTC10A3 " , 0 } ,
2020-09-15 16:18:14 -07:00
{ " " , 0 } ,
} ;
MODULE_DEVICE_TABLE ( acpi , pch_fivr_device_ids ) ;
static struct platform_driver pch_fivr_driver = {
. probe = pch_fivr_add ,
. remove = pch_fivr_remove ,
. driver = {
2020-10-15 18:58:43 +02:00
. name = " dptf_pch_fivr " ,
2020-09-15 16:18:14 -07:00
. acpi_match_table = pch_fivr_device_ids ,
} ,
} ;
module_platform_driver ( pch_fivr_driver ) ;
MODULE_AUTHOR ( " Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " ACPI DPTF PCH FIVR driver " ) ;