2015-05-20 14:16:37 +03:00
/*
2021-03-30 09:45:33 +03:00
* HiSilicon thermal sensor driver
2015-05-20 14:16:37 +03:00
*
2021-03-30 09:45:33 +03:00
* Copyright ( c ) 2014 - 2015 HiSilicon Limited .
2015-05-20 14:16:37 +03:00
* Copyright ( c ) 2014 - 2015 Linaro Limited .
*
* Xinwei Kong < kong . kongxinwei @ hisilicon . com >
* Leo Yan < leo . yan @ linaro . org >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* This program is distributed " as is " WITHOUT ANY WARRANTY of any
* kind , whether express or implied ; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/cpufreq.h>
# include <linux/delay.h>
# include <linux/interrupt.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/io.h>
2017-10-22 11:54:34 +03:00
# include <linux/of_device.h>
2015-05-20 14:16:37 +03:00
# include "thermal_core.h"
2017-10-22 11:54:33 +03:00
# define HI6220_TEMP0_LAG (0x0)
# define HI6220_TEMP0_TH (0x4)
# define HI6220_TEMP0_RST_TH (0x8)
# define HI6220_TEMP0_CFG (0xC)
2017-10-22 11:54:34 +03:00
# define HI6220_TEMP0_CFG_SS_MSK (0xF000)
2017-10-22 11:54:33 +03:00
# define HI6220_TEMP0_CFG_HDAK_MSK (0x30)
# define HI6220_TEMP0_EN (0x10)
# define HI6220_TEMP0_INT_EN (0x14)
# define HI6220_TEMP0_INT_CLR (0x18)
# define HI6220_TEMP0_RST_MSK (0x1C)
# define HI6220_TEMP0_VALUE (0x28)
2017-10-22 11:54:35 +03:00
# define HI3660_OFFSET(chan) ((chan) * 0x40)
# define HI3660_TEMP(chan) (HI3660_OFFSET(chan) + 0x1C)
# define HI3660_TH(chan) (HI3660_OFFSET(chan) + 0x20)
# define HI3660_LAG(chan) (HI3660_OFFSET(chan) + 0x28)
# define HI3660_INT_EN(chan) (HI3660_OFFSET(chan) + 0x2C)
# define HI3660_INT_CLR(chan) (HI3660_OFFSET(chan) + 0x30)
2017-10-22 11:54:33 +03:00
# define HI6220_TEMP_BASE (-60000)
# define HI6220_TEMP_RESET (100000)
# define HI6220_TEMP_STEP (785)
2017-10-22 11:54:34 +03:00
# define HI6220_TEMP_LAG (3500)
2017-10-22 11:54:33 +03:00
2017-10-22 11:54:35 +03:00
# define HI3660_TEMP_BASE (-63780)
# define HI3660_TEMP_STEP (205)
# define HI3660_TEMP_LAG (4000)
2018-09-25 12:03:05 +03:00
# define HI6220_CLUSTER0_SENSOR 2
2018-09-25 12:03:10 +03:00
# define HI6220_CLUSTER1_SENSOR 1
# define HI3660_LITTLE_SENSOR 0
2018-09-25 12:03:05 +03:00
# define HI3660_BIG_SENSOR 1
2018-09-25 12:03:10 +03:00
# define HI3660_G3D_SENSOR 2
# define HI3660_MODEM_SENSOR 3
2015-05-20 14:16:37 +03:00
2018-09-25 12:03:00 +03:00
struct hisi_thermal_data ;
2015-05-20 14:16:37 +03:00
struct hisi_thermal_sensor {
2018-09-25 12:03:00 +03:00
struct hisi_thermal_data * data ;
2015-05-20 14:16:37 +03:00
struct thermal_zone_device * tzd ;
2018-09-25 12:03:07 +03:00
const char * irq_name ;
2015-05-20 14:16:37 +03:00
uint32_t id ;
uint32_t thres_temp ;
} ;
2018-09-25 12:02:59 +03:00
struct hisi_thermal_ops {
2018-09-25 12:03:00 +03:00
int ( * get_temp ) ( struct hisi_thermal_sensor * sensor ) ;
int ( * enable_sensor ) ( struct hisi_thermal_sensor * sensor ) ;
int ( * disable_sensor ) ( struct hisi_thermal_sensor * sensor ) ;
int ( * irq_handler ) ( struct hisi_thermal_sensor * sensor ) ;
2018-09-25 12:02:59 +03:00
int ( * probe ) ( struct hisi_thermal_data * data ) ;
} ;
struct hisi_thermal_data {
const struct hisi_thermal_ops * ops ;
2018-09-25 12:03:03 +03:00
struct hisi_thermal_sensor * sensor ;
2015-05-20 14:16:37 +03:00
struct platform_device * pdev ;
struct clk * clk ;
void __iomem * regs ;
2018-09-25 12:03:03 +03:00
int nr_sensors ;
2015-05-20 14:16:37 +03:00
} ;
2017-10-19 20:05:46 +03:00
/*
* The temperature computation on the tsensor is as follow :
* Unit : millidegree Celsius
2017-10-19 20:05:57 +03:00
* Step : 200 / 255 ( 0.7843 )
2017-10-19 20:05:46 +03:00
* Temperature base : - 60 ° C
*
2017-10-19 20:05:57 +03:00
* The register is programmed in temperature steps , every step is 785
2017-10-19 20:05:46 +03:00
* millidegree and begins at - 60 000 m ° C
*
* The temperature from the steps :
*
2017-10-19 20:05:57 +03:00
* Temp = TempBase + ( steps x 785 )
2017-10-19 20:05:46 +03:00
*
* and the steps from the temperature :
*
2017-10-19 20:05:57 +03:00
* steps = ( Temp - TempBase ) / 785
2017-10-19 20:05:46 +03:00
*
*/
2017-10-22 11:54:33 +03:00
static inline int hi6220_thermal_step_to_temp ( int step )
2015-05-20 14:16:37 +03:00
{
2017-10-22 11:54:33 +03:00
return HI6220_TEMP_BASE + ( step * HI6220_TEMP_STEP ) ;
2015-05-20 14:16:37 +03:00
}
2017-10-22 11:54:33 +03:00
static inline int hi6220_thermal_temp_to_step ( int temp )
2015-05-20 14:16:37 +03:00
{
2017-10-22 11:54:33 +03:00
return DIV_ROUND_UP ( temp - HI6220_TEMP_BASE , HI6220_TEMP_STEP ) ;
2017-10-19 20:05:47 +03:00
}
2017-10-22 11:54:35 +03:00
/*
* for Hi3660 ,
* Step : 189 / 922 ( 0.205 )
* Temperature base : - 63.780 ° C
*
* The register is programmed in temperature steps , every step is 205
* millidegree and begins at - 63 780 m ° C
*/
static inline int hi3660_thermal_step_to_temp ( int step )
{
return HI3660_TEMP_BASE + step * HI3660_TEMP_STEP ;
}
static inline int hi3660_thermal_temp_to_step ( int temp )
{
return DIV_ROUND_UP ( temp - HI3660_TEMP_BASE , HI3660_TEMP_STEP ) ;
}
2017-10-19 20:05:51 +03:00
/*
* The lag register contains 5 bits encoding the temperature in steps .
*
* Each time the temperature crosses the threshold boundary , an
* interrupt is raised . It could be when the temperature is going
* above the threshold or below . However , if the temperature is
* fluctuating around this value due to the load , we can receive
* several interrupts which may not desired .
*
* We can setup a temperature representing the delta between the
* threshold and the current temperature when the temperature is
* decreasing .
*
* For instance : the lag register is 5 ° C , the threshold is 65 ° C , when
* the temperature reaches 65 ° C an interrupt is raised and when the
* temperature decrease to 65 ° C - 5 ° C another interrupt is raised .
*
* A very short lag can lead to an interrupt storm , a long lag
* increase the latency to react to the temperature changes . In our
* case , that is not really a problem as we are polling the
* temperature .
*
* [ 0 : 4 ] : lag register
*
2017-10-22 11:54:33 +03:00
* The temperature is coded in steps , cf . HI6220_TEMP_STEP .
2017-10-19 20:05:51 +03:00
*
* Min : 0x00 : 0.0 ° C
* Max : 0x1F : 24.3 ° C
*
* The ' value ' parameter is in milliCelsius .
*/
2017-10-22 11:54:33 +03:00
static inline void hi6220_thermal_set_lag ( void __iomem * addr , int value )
2017-10-19 20:05:49 +03:00
{
2017-10-22 11:54:33 +03:00
writel ( DIV_ROUND_UP ( value , HI6220_TEMP_STEP ) & 0x1F ,
addr + HI6220_TEMP0_LAG ) ;
2017-10-19 20:05:49 +03:00
}
2017-10-22 11:54:33 +03:00
static inline void hi6220_thermal_alarm_clear ( void __iomem * addr , int value )
2017-10-19 20:05:49 +03:00
{
2017-10-22 11:54:33 +03:00
writel ( value , addr + HI6220_TEMP0_INT_CLR ) ;
2017-10-19 20:05:49 +03:00
}
2017-10-22 11:54:33 +03:00
static inline void hi6220_thermal_alarm_enable ( void __iomem * addr , int value )
2017-10-19 20:05:49 +03:00
{
2017-10-22 11:54:33 +03:00
writel ( value , addr + HI6220_TEMP0_INT_EN ) ;
2017-10-19 20:05:49 +03:00
}
2017-10-22 11:54:33 +03:00
static inline void hi6220_thermal_alarm_set ( void __iomem * addr , int temp )
2017-10-19 20:05:49 +03:00
{
2017-10-22 11:54:33 +03:00
writel ( hi6220_thermal_temp_to_step ( temp ) | 0x0FFFFFF00 ,
addr + HI6220_TEMP0_TH ) ;
2017-10-19 20:05:49 +03:00
}
2017-10-22 11:54:33 +03:00
static inline void hi6220_thermal_reset_set ( void __iomem * addr , int temp )
2017-10-19 20:05:49 +03:00
{
2017-10-22 11:54:33 +03:00
writel ( hi6220_thermal_temp_to_step ( temp ) , addr + HI6220_TEMP0_RST_TH ) ;
2017-10-19 20:05:49 +03:00
}
2017-10-22 11:54:33 +03:00
static inline void hi6220_thermal_reset_enable ( void __iomem * addr , int value )
2017-10-19 20:05:49 +03:00
{
2017-10-22 11:54:33 +03:00
writel ( value , addr + HI6220_TEMP0_RST_MSK ) ;
2017-10-19 20:05:49 +03:00
}
2017-10-22 11:54:33 +03:00
static inline void hi6220_thermal_enable ( void __iomem * addr , int value )
2017-10-19 20:05:49 +03:00
{
2017-10-22 11:54:33 +03:00
writel ( value , addr + HI6220_TEMP0_EN ) ;
2017-10-19 20:05:49 +03:00
}
2017-10-22 11:54:33 +03:00
static inline int hi6220_thermal_get_temperature ( void __iomem * addr )
2017-10-19 20:05:49 +03:00
{
2017-10-22 11:54:33 +03:00
return hi6220_thermal_step_to_temp ( readl ( addr + HI6220_TEMP0_VALUE ) ) ;
2017-10-19 20:05:49 +03:00
}
2017-10-22 11:54:35 +03:00
/*
* [ 0 : 6 ] lag register
*
* The temperature is coded in steps , cf . HI3660_TEMP_STEP .
*
* Min : 0x00 : 0.0 ° C
* Max : 0x7F : 26.0 ° C
*
*/
static inline void hi3660_thermal_set_lag ( void __iomem * addr ,
int id , int value )
{
writel ( DIV_ROUND_UP ( value , HI3660_TEMP_STEP ) & 0x7F ,
addr + HI3660_LAG ( id ) ) ;
}
static inline void hi3660_thermal_alarm_clear ( void __iomem * addr ,
int id , int value )
{
writel ( value , addr + HI3660_INT_CLR ( id ) ) ;
}
static inline void hi3660_thermal_alarm_enable ( void __iomem * addr ,
int id , int value )
{
writel ( value , addr + HI3660_INT_EN ( id ) ) ;
}
static inline void hi3660_thermal_alarm_set ( void __iomem * addr ,
int id , int value )
{
writel ( value , addr + HI3660_TH ( id ) ) ;
}
static inline int hi3660_thermal_get_temperature ( void __iomem * addr , int id )
{
return hi3660_thermal_step_to_temp ( readl ( addr + HI3660_TEMP ( id ) ) ) ;
}
2017-10-19 20:05:50 +03:00
/*
* Temperature configuration register - Sensor selection
*
* Bits [ 19 : 12 ]
*
* 0x0 : local sensor ( default )
* 0x1 : remote sensor 1 ( ACPU cluster 1 )
* 0x2 : remote sensor 2 ( ACPU cluster 0 )
* 0x3 : remote sensor 3 ( G3D )
*/
2017-10-22 11:54:33 +03:00
static inline void hi6220_thermal_sensor_select ( void __iomem * addr , int sensor )
2017-10-19 20:05:49 +03:00
{
2017-10-22 11:54:33 +03:00
writel ( ( readl ( addr + HI6220_TEMP0_CFG ) & ~ HI6220_TEMP0_CFG_SS_MSK ) |
( sensor < < 12 ) , addr + HI6220_TEMP0_CFG ) ;
2017-10-19 20:05:49 +03:00
}
2017-10-19 20:05:50 +03:00
/*
* Temperature configuration register - Hdak conversion polling interval
*
* Bits [ 5 : 4 ]
*
* 0x0 : 0.768 ms
* 0x1 : 6.144 ms
* 0x2 : 49.152 ms
* 0x3 : 393.216 ms
*/
2017-10-22 11:54:33 +03:00
static inline void hi6220_thermal_hdak_set ( void __iomem * addr , int value )
2017-10-19 20:05:49 +03:00
{
2017-10-22 11:54:33 +03:00
writel ( ( readl ( addr + HI6220_TEMP0_CFG ) & ~ HI6220_TEMP0_CFG_HDAK_MSK ) |
( value < < 4 ) , addr + HI6220_TEMP0_CFG ) ;
2017-10-19 20:05:49 +03:00
}
2018-09-25 12:03:00 +03:00
static int hi6220_thermal_irq_handler ( struct hisi_thermal_sensor * sensor )
2017-10-22 11:54:34 +03:00
{
2018-09-25 12:03:00 +03:00
struct hisi_thermal_data * data = sensor - > data ;
2017-10-22 11:54:34 +03:00
hi6220_thermal_alarm_clear ( data - > regs , 1 ) ;
return 0 ;
}
2018-09-25 12:03:00 +03:00
static int hi3660_thermal_irq_handler ( struct hisi_thermal_sensor * sensor )
2017-10-22 11:54:35 +03:00
{
2018-09-25 12:03:00 +03:00
struct hisi_thermal_data * data = sensor - > data ;
hi3660_thermal_alarm_clear ( data - > regs , sensor - > id , 1 ) ;
2017-10-22 11:54:35 +03:00
return 0 ;
}
2018-09-25 12:03:00 +03:00
static int hi6220_thermal_get_temp ( struct hisi_thermal_sensor * sensor )
2017-10-22 11:54:34 +03:00
{
2018-09-25 12:03:00 +03:00
struct hisi_thermal_data * data = sensor - > data ;
2017-10-22 11:54:34 +03:00
return hi6220_thermal_get_temperature ( data - > regs ) ;
}
2018-09-25 12:03:00 +03:00
static int hi3660_thermal_get_temp ( struct hisi_thermal_sensor * sensor )
2017-10-22 11:54:35 +03:00
{
2018-09-25 12:03:00 +03:00
struct hisi_thermal_data * data = sensor - > data ;
return hi3660_thermal_get_temperature ( data - > regs , sensor - > id ) ;
2017-10-22 11:54:35 +03:00
}
2018-09-25 12:03:00 +03:00
static int hi6220_thermal_disable_sensor ( struct hisi_thermal_sensor * sensor )
2015-05-20 14:16:37 +03:00
{
2018-09-25 12:03:00 +03:00
struct hisi_thermal_data * data = sensor - > data ;
2015-05-20 14:16:37 +03:00
/* disable sensor module */
2017-10-22 11:54:33 +03:00
hi6220_thermal_enable ( data - > regs , 0 ) ;
hi6220_thermal_alarm_enable ( data - > regs , 0 ) ;
hi6220_thermal_reset_enable ( data - > regs , 0 ) ;
2017-10-19 20:05:56 +03:00
clk_disable_unprepare ( data - > clk ) ;
2017-10-22 11:54:34 +03:00
return 0 ;
2015-05-20 14:16:37 +03:00
}
2018-09-25 12:03:00 +03:00
static int hi3660_thermal_disable_sensor ( struct hisi_thermal_sensor * sensor )
2017-10-22 11:54:35 +03:00
{
2018-09-25 12:03:00 +03:00
struct hisi_thermal_data * data = sensor - > data ;
2017-10-22 11:54:35 +03:00
/* disable sensor module */
2018-09-25 12:03:00 +03:00
hi3660_thermal_alarm_enable ( data - > regs , sensor - > id , 0 ) ;
2017-10-22 11:54:35 +03:00
return 0 ;
}
2018-09-25 12:03:00 +03:00
static int hi6220_thermal_enable_sensor ( struct hisi_thermal_sensor * sensor )
2017-10-22 11:54:32 +03:00
{
2018-09-25 12:03:00 +03:00
struct hisi_thermal_data * data = sensor - > data ;
2017-10-22 11:54:32 +03:00
int ret ;
/* enable clock for tsensor */
ret = clk_prepare_enable ( data - > clk ) ;
if ( ret )
return ret ;
/* disable module firstly */
2017-10-22 11:54:33 +03:00
hi6220_thermal_reset_enable ( data - > regs , 0 ) ;
hi6220_thermal_enable ( data - > regs , 0 ) ;
2017-10-22 11:54:32 +03:00
/* select sensor id */
2017-10-22 11:54:33 +03:00
hi6220_thermal_sensor_select ( data - > regs , sensor - > id ) ;
2017-10-22 11:54:32 +03:00
/* setting the hdak time */
2017-10-22 11:54:33 +03:00
hi6220_thermal_hdak_set ( data - > regs , 0 ) ;
2017-10-22 11:54:32 +03:00
/* setting lag value between current temp and the threshold */
2017-10-22 11:54:33 +03:00
hi6220_thermal_set_lag ( data - > regs , HI6220_TEMP_LAG ) ;
2017-10-22 11:54:32 +03:00
/* enable for interrupt */
2017-10-22 11:54:33 +03:00
hi6220_thermal_alarm_set ( data - > regs , sensor - > thres_temp ) ;
2017-10-22 11:54:32 +03:00
2017-10-22 11:54:33 +03:00
hi6220_thermal_reset_set ( data - > regs , HI6220_TEMP_RESET ) ;
2017-10-22 11:54:32 +03:00
/* enable module */
2017-10-22 11:54:33 +03:00
hi6220_thermal_reset_enable ( data - > regs , 1 ) ;
hi6220_thermal_enable ( data - > regs , 1 ) ;
2017-10-22 11:54:32 +03:00
2017-10-22 11:54:33 +03:00
hi6220_thermal_alarm_clear ( data - > regs , 0 ) ;
hi6220_thermal_alarm_enable ( data - > regs , 1 ) ;
2017-10-22 11:54:32 +03:00
return 0 ;
}
2018-09-25 12:03:00 +03:00
static int hi3660_thermal_enable_sensor ( struct hisi_thermal_sensor * sensor )
2017-10-22 11:54:35 +03:00
{
unsigned int value ;
2018-09-25 12:03:00 +03:00
struct hisi_thermal_data * data = sensor - > data ;
2017-10-22 11:54:35 +03:00
/* disable interrupt */
hi3660_thermal_alarm_enable ( data - > regs , sensor - > id , 0 ) ;
/* setting lag value between current temp and the threshold */
hi3660_thermal_set_lag ( data - > regs , sensor - > id , HI3660_TEMP_LAG ) ;
/* set interrupt threshold */
value = hi3660_thermal_temp_to_step ( sensor - > thres_temp ) ;
hi3660_thermal_alarm_set ( data - > regs , sensor - > id , value ) ;
/* enable interrupt */
hi3660_thermal_alarm_clear ( data - > regs , sensor - > id , 1 ) ;
hi3660_thermal_alarm_enable ( data - > regs , sensor - > id , 1 ) ;
return 0 ;
}
2017-10-22 11:54:34 +03:00
static int hi6220_thermal_probe ( struct hisi_thermal_data * data )
{
struct platform_device * pdev = data - > pdev ;
struct device * dev = & pdev - > dev ;
int ret ;
data - > clk = devm_clk_get ( dev , " thermal_clk " ) ;
if ( IS_ERR ( data - > clk ) ) {
ret = PTR_ERR ( data - > clk ) ;
if ( ret ! = - EPROBE_DEFER )
dev_err ( dev , " failed to get thermal clk: %d \n " , ret ) ;
return ret ;
}
2018-09-25 12:03:03 +03:00
data - > sensor = devm_kzalloc ( dev , sizeof ( * data - > sensor ) , GFP_KERNEL ) ;
if ( ! data - > sensor )
return - ENOMEM ;
2018-09-25 12:03:05 +03:00
data - > sensor [ 0 ] . id = HI6220_CLUSTER0_SENSOR ;
2018-09-25 12:03:07 +03:00
data - > sensor [ 0 ] . irq_name = " tsensor_intr " ;
2018-09-25 12:03:03 +03:00
data - > sensor [ 0 ] . data = data ;
data - > nr_sensors = 1 ;
2017-10-22 11:54:34 +03:00
return 0 ;
}
2017-10-22 11:54:35 +03:00
static int hi3660_thermal_probe ( struct hisi_thermal_data * data )
{
2018-09-25 12:03:03 +03:00
struct platform_device * pdev = data - > pdev ;
struct device * dev = & pdev - > dev ;
2018-11-30 11:00:32 +03:00
data - > nr_sensors = 1 ;
2018-09-25 12:03:12 +03:00
data - > sensor = devm_kzalloc ( dev , sizeof ( * data - > sensor ) *
data - > nr_sensors , GFP_KERNEL ) ;
2018-09-25 12:03:03 +03:00
if ( ! data - > sensor )
return - ENOMEM ;
2018-09-25 12:03:05 +03:00
data - > sensor [ 0 ] . id = HI3660_BIG_SENSOR ;
2018-09-25 12:03:07 +03:00
data - > sensor [ 0 ] . irq_name = " tsensor_a73 " ;
2018-09-25 12:03:03 +03:00
data - > sensor [ 0 ] . data = data ;
2018-09-25 12:03:12 +03:00
data - > sensor [ 1 ] . id = HI3660_LITTLE_SENSOR ;
data - > sensor [ 1 ] . irq_name = " tsensor_a53 " ;
data - > sensor [ 1 ] . data = data ;
2017-10-22 11:54:35 +03:00
return 0 ;
}
2017-10-19 20:05:54 +03:00
static int hisi_thermal_get_temp ( void * __data , int * temp )
2015-05-20 14:16:37 +03:00
{
2018-09-25 12:03:01 +03:00
struct hisi_thermal_sensor * sensor = __data ;
struct hisi_thermal_data * data = sensor - > data ;
2015-05-20 14:16:37 +03:00
2018-09-25 12:03:00 +03:00
* temp = data - > ops - > get_temp ( sensor ) ;
2015-05-20 14:16:37 +03:00
2018-09-25 12:03:12 +03:00
dev_dbg ( & data - > pdev - > dev , " tzd=%p, id=%d, temp=%d, thres=%d \n " ,
sensor - > tzd , sensor - > id , * temp , sensor - > thres_temp ) ;
2015-05-20 14:16:37 +03:00
return 0 ;
}
2017-08-08 18:08:55 +03:00
static const struct thermal_zone_of_device_ops hisi_of_thermal_ops = {
2015-05-20 14:16:37 +03:00
. get_temp = hisi_thermal_get_temp ,
} ;
2017-10-19 20:05:51 +03:00
static irqreturn_t hisi_thermal_alarm_irq_thread ( int irq , void * dev )
2015-05-20 14:16:37 +03:00
{
2018-09-25 12:03:04 +03:00
struct hisi_thermal_sensor * sensor = dev ;
struct hisi_thermal_data * data = sensor - > data ;
2017-10-22 11:54:33 +03:00
int temp = 0 ;
2015-05-20 14:16:37 +03:00
2018-09-25 12:03:00 +03:00
data - > ops - > irq_handler ( sensor ) ;
2015-05-20 14:16:37 +03:00
2018-09-25 12:03:01 +03:00
hisi_thermal_get_temp ( sensor , & temp ) ;
2015-05-20 14:16:37 +03:00
2017-10-19 20:05:51 +03:00
if ( temp > = sensor - > thres_temp ) {
2018-09-25 12:03:04 +03:00
dev_crit ( & data - > pdev - > dev ,
" sensor <%d> THERMAL ALARM: %d > %d \n " ,
sensor - > id , temp , sensor - > thres_temp ) ;
2015-05-20 14:16:37 +03:00
2018-09-25 12:03:04 +03:00
thermal_zone_device_update ( sensor - > tzd ,
2017-10-19 20:05:51 +03:00
THERMAL_EVENT_UNSPECIFIED ) ;
2015-05-20 14:16:37 +03:00
2017-10-22 11:54:33 +03:00
} else {
2018-09-25 12:03:04 +03:00
dev_crit ( & data - > pdev - > dev ,
" sensor <%d> THERMAL ALARM stopped: %d < %d \n " ,
sensor - > id , temp , sensor - > thres_temp ) ;
2017-10-19 20:05:51 +03:00
}
2015-05-20 14:16:37 +03:00
return IRQ_HANDLED ;
}
static int hisi_thermal_register_sensor ( struct platform_device * pdev ,
2017-10-22 11:54:34 +03:00
struct hisi_thermal_sensor * sensor )
2015-05-20 14:16:37 +03:00
{
int ret , i ;
const struct thermal_trip * trip ;
2016-03-10 00:07:13 +03:00
sensor - > tzd = devm_thermal_zone_of_sensor_register ( & pdev - > dev ,
2018-09-25 12:03:01 +03:00
sensor - > id , sensor ,
2017-10-19 20:05:54 +03:00
& hisi_of_thermal_ops ) ;
2015-05-20 14:16:37 +03:00
if ( IS_ERR ( sensor - > tzd ) ) {
ret = PTR_ERR ( sensor - > tzd ) ;
2016-03-29 14:27:12 +03:00
sensor - > tzd = NULL ;
2015-05-20 14:16:37 +03:00
dev_err ( & pdev - > dev , " failed to register sensor id %d: %d \n " ,
sensor - > id , ret ) ;
return ret ;
}
trip = of_thermal_get_trip_points ( sensor - > tzd ) ;
for ( i = 0 ; i < of_thermal_get_ntrips ( sensor - > tzd ) ; i + + ) {
if ( trip [ i ] . type = = THERMAL_TRIP_PASSIVE ) {
2017-10-19 20:05:57 +03:00
sensor - > thres_temp = trip [ i ] . temperature ;
2015-05-20 14:16:37 +03:00
break ;
}
}
return 0 ;
}
2018-09-25 12:02:59 +03:00
static const struct hisi_thermal_ops hi6220_ops = {
. get_temp = hi6220_thermal_get_temp ,
. enable_sensor = hi6220_thermal_enable_sensor ,
. disable_sensor = hi6220_thermal_disable_sensor ,
. irq_handler = hi6220_thermal_irq_handler ,
. probe = hi6220_thermal_probe ,
} ;
static const struct hisi_thermal_ops hi3660_ops = {
. get_temp = hi3660_thermal_get_temp ,
. enable_sensor = hi3660_thermal_enable_sensor ,
. disable_sensor = hi3660_thermal_disable_sensor ,
. irq_handler = hi3660_thermal_irq_handler ,
. probe = hi3660_thermal_probe ,
} ;
2015-05-20 14:16:37 +03:00
static const struct of_device_id of_hisi_thermal_match [ ] = {
2017-10-22 11:54:35 +03:00
{
. compatible = " hisilicon,tsensor " ,
2018-09-25 12:02:59 +03:00
. data = & hi6220_ops ,
2017-10-22 11:54:35 +03:00
} ,
{
. compatible = " hisilicon,hi3660-tsensor " ,
2018-09-25 12:02:59 +03:00
. data = & hi3660_ops ,
2017-10-22 11:54:35 +03:00
} ,
2015-05-20 14:16:37 +03:00
{ /* end */ }
} ;
MODULE_DEVICE_TABLE ( of , of_hisi_thermal_match ) ;
static void hisi_thermal_toggle_sensor ( struct hisi_thermal_sensor * sensor ,
bool on )
{
struct thermal_zone_device * tzd = sensor - > tzd ;
thermal: Use mode helpers in drivers
Use thermal_zone_device_{en|dis}able() and thermal_zone_device_is_enabled().
Consequently, all set_mode() implementations in drivers:
- can stop modifying tzd's "mode" member,
- shall stop taking tzd's lock, as it is taken in the helpers
- shall stop calling thermal_zone_device_update() as it is called in the
helpers
- can assume they are called when the mode truly changes, so checks to
verify that can be dropped
Not providing set_mode() by a driver no longer prevents the core from
being able to set tzd's mode, so the relevant check in mode_store() is
removed.
Other comments:
- acpi/thermal.c: tz->thermal_zone->mode will be updated only after we
return from set_mode(), so use function parameter in thermal_set_mode()
instead, no need to call acpi_thermal_check() in set_mode()
- thermal/imx_thermal.c: regmap writes and mode assignment are done in
thermal_zone_device_{en|dis}able() and set_mode() callback
- thermal/intel/intel_quark_dts_thermal.c: soc_dts_{en|dis}able() are a
part of set_mode() callback, so they don't need to modify tzd->mode, and
don't need to fall back to the opposite mode if unsuccessful, as the return
value will be propagated to thermal_zone_device_{en|dis}able() and
ultimately tzd's member will not be changed in thermal_zone_device_set_mode().
- thermal/of-thermal.c: no need to set zone->mode to DISABLED in
of_parse_thermal_zones() as a tzd is kzalloc'ed so mode is DISABLED anyway
Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
[for acerhdf]
Acked-by: Peter Kaestle <peter@piie.net>
Reviewed-by: Amit Kucheria <amit.kucheria@linaro.org>
Reviewed-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Link: https://lore.kernel.org/r/20200629122925.21729-8-andrzej.p@collabora.com
2020-06-29 15:29:21 +03:00
if ( on )
thermal_zone_device_enable ( tzd ) ;
else
thermal_zone_device_disable ( tzd ) ;
2015-05-20 14:16:37 +03:00
}
static int hisi_thermal_probe ( struct platform_device * pdev )
{
struct hisi_thermal_data * data ;
2017-10-22 11:54:34 +03:00
struct device * dev = & pdev - > dev ;
2018-09-25 12:03:02 +03:00
struct resource * res ;
2018-09-25 12:03:04 +03:00
int i , ret ;
2015-05-20 14:16:37 +03:00
2017-10-22 11:54:34 +03:00
data = devm_kzalloc ( dev , sizeof ( * data ) , GFP_KERNEL ) ;
2015-05-20 14:16:37 +03:00
if ( ! data )
return - ENOMEM ;
data - > pdev = pdev ;
2017-10-22 11:54:34 +03:00
platform_set_drvdata ( pdev , data ) ;
2018-09-25 12:02:59 +03:00
data - > ops = of_device_get_match_data ( dev ) ;
2015-05-20 14:16:37 +03:00
2018-09-25 12:03:02 +03:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
data - > regs = devm_ioremap_resource ( dev , res ) ;
2021-04-09 10:52:24 +03:00
if ( IS_ERR ( data - > regs ) )
2018-09-25 12:03:02 +03:00
return PTR_ERR ( data - > regs ) ;
2018-09-25 12:02:59 +03:00
ret = data - > ops - > probe ( data ) ;
2017-10-22 11:54:34 +03:00
if ( ret )
2015-05-20 14:16:37 +03:00
return ret ;
2018-09-25 12:03:04 +03:00
for ( i = 0 ; i < data - > nr_sensors ; i + + ) {
struct hisi_thermal_sensor * sensor = & data - > sensor [ i ] ;
2015-05-20 14:16:37 +03:00
2018-09-25 12:03:04 +03:00
ret = hisi_thermal_register_sensor ( pdev , sensor ) ;
if ( ret ) {
dev_err ( dev , " failed to register thermal sensor: %d \n " ,
ret ) ;
return ret ;
}
2018-11-30 11:00:31 +03:00
ret = platform_get_irq ( pdev , 0 ) ;
2018-09-25 12:03:09 +03:00
if ( ret < 0 )
return ret ;
2017-10-19 20:05:44 +03:00
2018-09-25 12:03:09 +03:00
ret = devm_request_threaded_irq ( dev , ret , NULL ,
2018-09-25 12:03:04 +03:00
hisi_thermal_alarm_irq_thread ,
2018-09-25 12:03:07 +03:00
IRQF_ONESHOT , sensor - > irq_name ,
2018-09-25 12:03:04 +03:00
sensor ) ;
2017-10-22 11:54:34 +03:00
if ( ret < 0 ) {
2018-09-25 12:03:09 +03:00
dev_err ( dev , " Failed to request alarm irq: %d \n " , ret ) ;
2017-10-22 11:54:34 +03:00
return ret ;
}
2017-10-19 20:05:45 +03:00
2018-09-25 12:03:04 +03:00
ret = data - > ops - > enable_sensor ( sensor ) ;
if ( ret ) {
dev_err ( dev , " Failed to setup the sensor: %d \n " , ret ) ;
return ret ;
}
hisi_thermal_toggle_sensor ( sensor , true ) ;
}
2017-10-19 20:05:43 +03:00
2015-05-20 14:16:37 +03:00
return 0 ;
}
static int hisi_thermal_remove ( struct platform_device * pdev )
{
struct hisi_thermal_data * data = platform_get_drvdata ( pdev ) ;
2018-09-25 12:03:04 +03:00
int i ;
2015-05-20 14:16:37 +03:00
2018-09-25 12:03:04 +03:00
for ( i = 0 ; i < data - > nr_sensors ; i + + ) {
struct hisi_thermal_sensor * sensor = & data - > sensor [ i ] ;
2017-10-22 11:54:34 +03:00
2018-09-25 12:03:04 +03:00
hisi_thermal_toggle_sensor ( sensor , false ) ;
data - > ops - > disable_sensor ( sensor ) ;
}
2015-05-20 14:16:37 +03:00
return 0 ;
}
# ifdef CONFIG_PM_SLEEP
static int hisi_thermal_suspend ( struct device * dev )
{
struct hisi_thermal_data * data = dev_get_drvdata ( dev ) ;
2018-09-25 12:03:04 +03:00
int i ;
2015-05-20 14:16:37 +03:00
2018-09-25 12:03:04 +03:00
for ( i = 0 ; i < data - > nr_sensors ; i + + )
data - > ops - > disable_sensor ( & data - > sensor [ i ] ) ;
2015-05-20 14:16:37 +03:00
return 0 ;
}
static int hisi_thermal_resume ( struct device * dev )
{
struct hisi_thermal_data * data = dev_get_drvdata ( dev ) ;
2018-09-25 12:03:04 +03:00
int i , ret = 0 ;
for ( i = 0 ; i < data - > nr_sensors ; i + + )
ret | = data - > ops - > enable_sensor ( & data - > sensor [ i ] ) ;
2015-05-20 14:16:37 +03:00
2018-09-25 12:03:04 +03:00
return ret ;
2015-05-20 14:16:37 +03:00
}
# endif
static SIMPLE_DEV_PM_OPS ( hisi_thermal_pm_ops ,
hisi_thermal_suspend , hisi_thermal_resume ) ;
static struct platform_driver hisi_thermal_driver = {
. driver = {
. name = " hisi_thermal " ,
. pm = & hisi_thermal_pm_ops ,
. of_match_table = of_hisi_thermal_match ,
} ,
. probe = hisi_thermal_probe ,
. remove = hisi_thermal_remove ,
} ;
module_platform_driver ( hisi_thermal_driver ) ;
MODULE_AUTHOR ( " Xinwei Kong <kong.kongxinwei@hisilicon.com> " ) ;
MODULE_AUTHOR ( " Leo Yan <leo.yan@linaro.org> " ) ;
2021-03-30 09:45:33 +03:00
MODULE_DESCRIPTION ( " HiSilicon thermal driver " ) ;
2015-05-20 14:16:37 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;