2019-05-29 07:18:02 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2014-04-07 13:57:15 -07:00
/*
* intel_soc_dts_thermal . c
* Copyright ( c ) 2014 , Intel Corporation .
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2018-06-02 22:16:38 +02:00
# include <linux/acpi.h>
2014-04-07 13:57:15 -07:00
# include <linux/module.h>
# include <linux/interrupt.h>
# include <asm/cpu_device_id.h>
2016-06-02 17:19:52 -07:00
# include <asm/intel-family.h>
2015-03-02 13:12:59 -08:00
# include "intel_soc_dts_iosf.h"
2014-04-07 13:57:15 -07:00
# define CRITICAL_OFFSET_FROM_TJ_MAX 5000
static int crit_offset = CRITICAL_OFFSET_FROM_TJ_MAX ;
module_param ( crit_offset , int , 0644 ) ;
MODULE_PARM_DESC ( crit_offset ,
" Critical Temperature offset from tj max in millidegree Celsius. " ) ;
2015-03-02 13:12:59 -08:00
/* IRQ 86 is a fixed APIC interrupt for BYT DTS Aux threshold notifications */
# define BYT_SOC_DTS_APIC_IRQ 86
2014-04-07 13:57:15 -07:00
2018-06-02 22:16:38 +02:00
static int soc_dts_thres_gsi ;
2015-03-02 13:12:59 -08:00
static int soc_dts_thres_irq ;
static struct intel_soc_dts_sensors * soc_dts ;
2014-04-07 13:57:15 -07:00
static irqreturn_t soc_irq_thread_fn ( int irq , void * dev_data )
{
pr_debug ( " proc_thermal_interrupt \n " ) ;
2015-03-02 13:12:59 -08:00
intel_soc_dts_iosf_interrupt_handler ( soc_dts ) ;
2014-04-07 13:57:15 -07:00
return IRQ_HANDLED ;
}
static const struct x86_cpu_id soc_thermal_ids [ ] = {
2020-03-20 14:13:58 +01:00
X86_MATCH_INTEL_FAM6_MODEL ( ATOM_SILVERMONT , BYT_SOC_DTS_APIC_IRQ ) ,
2014-04-07 13:57:15 -07:00
{ }
} ;
MODULE_DEVICE_TABLE ( x86cpu , soc_thermal_ids ) ;
static int __init intel_soc_thermal_init ( void )
{
int err = 0 ;
const struct x86_cpu_id * match_cpu ;
match_cpu = x86_match_cpu ( soc_thermal_ids ) ;
if ( ! match_cpu )
return - ENODEV ;
2015-03-02 13:12:59 -08:00
/* Create a zone with 2 trips with marked as read only */
soc_dts = intel_soc_dts_iosf_init ( INTEL_SOC_DTS_INTERRUPT_APIC , 2 , 1 ) ;
if ( IS_ERR ( soc_dts ) ) {
err = PTR_ERR ( soc_dts ) ;
return err ;
2014-04-07 13:57:15 -07:00
}
2018-06-02 22:16:38 +02:00
soc_dts_thres_gsi = ( int ) match_cpu - > driver_data ;
if ( soc_dts_thres_gsi ) {
/*
* Note the flags here MUST match the firmware defaults , rather
* then the request_irq flags , otherwise we get an EBUSY error .
*/
soc_dts_thres_irq = acpi_register_gsi ( NULL , soc_dts_thres_gsi ,
ACPI_LEVEL_SENSITIVE ,
ACPI_ACTIVE_LOW ) ;
if ( soc_dts_thres_irq < 0 ) {
pr_warn ( " intel_soc_dts: Could not get IRQ for GSI %d, err %d \n " ,
soc_dts_thres_gsi , soc_dts_thres_irq ) ;
soc_dts_thres_irq = 0 ;
}
}
2014-04-07 13:57:15 -07:00
2015-01-28 11:48:02 -08:00
if ( soc_dts_thres_irq ) {
err = request_threaded_irq ( soc_dts_thres_irq , NULL ,
soc_irq_thread_fn ,
IRQF_TRIGGER_RISING | IRQF_ONESHOT ,
" soc_dts " , soc_dts ) ;
if ( err ) {
2017-04-12 14:07:17 -07:00
/*
* Do not just error out because the user space thermal
* daemon such as DPTF may use polling instead of being
* interrupt driven .
*/
pr_warn ( " request_threaded_irq ret %d \n " , err ) ;
2015-01-28 11:48:02 -08:00
}
2014-04-07 13:57:15 -07:00
}
2015-03-02 13:12:59 -08:00
err = intel_soc_dts_iosf_add_read_only_critical_trip ( soc_dts ,
crit_offset ) ;
if ( err )
goto error_trips ;
2014-04-07 13:57:15 -07:00
return 0 ;
2015-03-02 13:12:59 -08:00
error_trips :
2018-06-02 22:16:38 +02:00
if ( soc_dts_thres_irq ) {
2015-01-28 11:48:02 -08:00
free_irq ( soc_dts_thres_irq , soc_dts ) ;
2018-06-02 22:16:38 +02:00
acpi_unregister_gsi ( soc_dts_thres_gsi ) ;
}
2015-03-02 13:12:59 -08:00
intel_soc_dts_iosf_exit ( soc_dts ) ;
2014-04-07 13:57:15 -07:00
return err ;
}
static void __exit intel_soc_thermal_exit ( void )
{
2018-06-02 22:16:38 +02:00
if ( soc_dts_thres_irq ) {
2015-01-28 11:48:02 -08:00
free_irq ( soc_dts_thres_irq , soc_dts ) ;
2018-06-02 22:16:38 +02:00
acpi_unregister_gsi ( soc_dts_thres_gsi ) ;
}
2015-03-02 13:12:59 -08:00
intel_soc_dts_iosf_exit ( soc_dts ) ;
2014-04-07 13:57:15 -07:00
}
module_init ( intel_soc_thermal_init )
module_exit ( intel_soc_thermal_exit )
MODULE_DESCRIPTION ( " Intel SoC DTS Thermal Driver " ) ;
MODULE_AUTHOR ( " Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;