2014-11-24 07:58:59 +03:00
/*
2016-04-18 06:35:58 +03:00
* Copyright ( c ) 2014 - 2016 , Fuzhou Rockchip Electronics Co . , Ltd
2015-11-09 07:48:59 +03:00
* Caesar Wang < wxt @ rock - chips . com >
*
2014-11-24 07:58:59 +03:00
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*/
# include <linux/clk.h>
# include <linux/delay.h>
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/of_irq.h>
# include <linux/platform_device.h>
2016-04-18 06:35:56 +03:00
# include <linux/regmap.h>
2014-11-24 07:58:59 +03:00
# include <linux/reset.h>
# include <linux/thermal.h>
2016-04-18 06:35:56 +03:00
# include <linux/mfd/syscon.h>
2015-11-12 06:43:11 +03:00
# include <linux/pinctrl/consumer.h>
2014-11-24 07:58:59 +03:00
/**
* If the temperature over a period of time High ,
* the resulting TSHUT gave CRU module , let it reset the entire chip ,
* or via GPIO give PMIC .
*/
enum tshut_mode {
TSHUT_MODE_CRU = 0 ,
TSHUT_MODE_GPIO ,
} ;
/**
2015-12-03 11:48:39 +03:00
* The system Temperature Sensors tshut ( tshut ) polarity
2014-11-24 07:58:59 +03:00
* the bit 8 is tshut polarity .
* 0 : low active , 1 : high active
*/
enum tshut_polarity {
TSHUT_LOW_ACTIVE = 0 ,
TSHUT_HIGH_ACTIVE ,
} ;
/**
2015-11-05 08:17:58 +03:00
* The system has two Temperature Sensors .
* sensor0 is for CPU , and sensor1 is for GPU .
2014-11-24 07:58:59 +03:00
*/
enum sensor_id {
2015-11-05 08:17:58 +03:00
SENSOR_CPU = 0 ,
2014-11-24 07:58:59 +03:00
SENSOR_GPU ,
} ;
2015-11-09 07:48:57 +03:00
/**
2015-12-03 11:48:39 +03:00
* The conversion table has the adc value and temperature .
2016-02-15 10:33:30 +03:00
* ADC_DECREMENT : the adc value is of diminishing . ( e . g . rk3288_code_table )
* ADC_INCREMENT : the adc value is incremental . ( e . g . rk3368_code_table )
2015-12-03 11:48:39 +03:00
*/
2015-11-09 07:48:57 +03:00
enum adc_sort_mode {
ADC_DECREMENT = 0 ,
ADC_INCREMENT ,
} ;
2015-11-05 08:17:58 +03:00
/**
* The max sensors is two in rockchip SoCs .
* Two sensors : CPU and GPU sensor .
*/
# define SOC_MAX_SENSORS 2
2015-12-03 11:48:39 +03:00
/**
2016-04-18 06:35:58 +03:00
* struct chip_tsadc_table - hold information about chip - specific differences
2015-12-03 11:48:39 +03:00
* @ id : conversion table
* @ length : size of conversion table
* @ data_mask : mask to apply on data inputs
* @ mode : sort mode of this adc variant ( incrementing or decrementing )
*/
2015-11-09 07:48:56 +03:00
struct chip_tsadc_table {
const struct tsadc_table * id ;
unsigned int length ;
u32 data_mask ;
2015-11-09 07:48:57 +03:00
enum adc_sort_mode mode ;
2015-11-09 07:48:56 +03:00
} ;
2016-04-18 06:35:58 +03:00
/**
* struct rockchip_tsadc_chip - hold the private data of tsadc chip
* @ chn_id [ SOC_MAX_SENSORS ] : the sensor id of chip correspond to the channel
* @ chn_num : the channel number of tsadc chip
* @ tshut_temp : the hardware - controlled shutdown temperature value
* @ tshut_mode : the hardware - controlled shutdown mode ( 0 : CRU 1 : GPIO )
* @ tshut_polarity : the hardware - controlled active polarity ( 0 : LOW 1 : HIGH )
* @ initialize : SoC special initialize tsadc controller method
* @ irq_ack : clear the interrupt
* @ get_temp : get the temperature
* @ set_tshut_temp : set the hardware - controlled shutdown temperature
* @ set_tshut_mode : set the hardware - controlled shutdown mode
* @ table : the chip - specific conversion table
*/
2014-11-24 07:58:59 +03:00
struct rockchip_tsadc_chip {
2015-11-05 08:17:58 +03:00
/* The sensor id of chip correspond to the ADC channel */
int chn_id [ SOC_MAX_SENSORS ] ;
int chn_num ;
2014-11-24 07:58:59 +03:00
/* The hardware-controlled tshut property */
2015-11-09 07:48:58 +03:00
int tshut_temp ;
2014-11-24 07:58:59 +03:00
enum tshut_mode tshut_mode ;
enum tshut_polarity tshut_polarity ;
/* Chip-wide methods */
2016-04-18 06:35:56 +03:00
void ( * initialize ) ( struct regmap * grf ,
void __iomem * reg , enum tshut_polarity p ) ;
2014-11-24 07:58:59 +03:00
void ( * irq_ack ) ( void __iomem * reg ) ;
void ( * control ) ( void __iomem * reg , bool on ) ;
/* Per-sensor methods */
2015-11-09 07:48:56 +03:00
int ( * get_temp ) ( struct chip_tsadc_table table ,
int chn , void __iomem * reg , int * temp ) ;
void ( * set_tshut_temp ) ( struct chip_tsadc_table table ,
2015-11-09 07:48:58 +03:00
int chn , void __iomem * reg , int temp ) ;
2014-11-24 07:58:59 +03:00
void ( * set_tshut_mode ) ( int chn , void __iomem * reg , enum tshut_mode m ) ;
2015-11-09 07:48:56 +03:00
/* Per-table methods */
struct chip_tsadc_table table ;
2014-11-24 07:58:59 +03:00
} ;
2016-04-18 06:35:58 +03:00
/**
* struct rockchip_thermal_sensor - hold the information of thermal sensor
* @ thermal : pointer to the platform / configuration data
* @ tzd : pointer to a thermal zone
* @ id : identifier of the thermal sensor
*/
2014-11-24 07:58:59 +03:00
struct rockchip_thermal_sensor {
struct rockchip_thermal_data * thermal ;
struct thermal_zone_device * tzd ;
2015-11-05 08:17:58 +03:00
int id ;
2014-11-24 07:58:59 +03:00
} ;
2016-04-18 06:35:58 +03:00
/**
* struct rockchip_thermal_data - hold the private data of thermal driver
* @ chip : pointer to the platform / configuration data
* @ pdev : platform device of thermal
* @ reset : the reset controller of tsadc
* @ sensors [ SOC_MAX_SENSORS ] : the thermal sensor
* @ clk : the controller clock is divided by the exteral 24 MHz
* @ pclk : the advanced peripherals bus clock
* @ grf : the general register file will be used to do static set by software
* @ regs : the base address of tsadc controller
* @ tshut_temp : the hardware - controlled shutdown temperature value
* @ tshut_mode : the hardware - controlled shutdown mode ( 0 : CRU 1 : GPIO )
* @ tshut_polarity : the hardware - controlled active polarity ( 0 : LOW 1 : HIGH )
*/
2014-11-24 07:58:59 +03:00
struct rockchip_thermal_data {
const struct rockchip_tsadc_chip * chip ;
struct platform_device * pdev ;
struct reset_control * reset ;
2015-11-05 08:17:58 +03:00
struct rockchip_thermal_sensor sensors [ SOC_MAX_SENSORS ] ;
2014-11-24 07:58:59 +03:00
struct clk * clk ;
struct clk * pclk ;
2016-04-18 06:35:56 +03:00
struct regmap * grf ;
2014-11-24 07:58:59 +03:00
void __iomem * regs ;
2015-11-09 07:48:58 +03:00
int tshut_temp ;
2014-11-24 07:58:59 +03:00
enum tshut_mode tshut_mode ;
enum tshut_polarity tshut_polarity ;
} ;
2016-02-15 10:33:30 +03:00
/**
* TSADC Sensor Register description :
*
* TSADCV2_ * are used for RK3288 SoCs , the other chips can reuse it .
* TSADCV3_ * are used for newer SoCs than RK3288 . ( e . g : RK3228 , RK3399 )
*
*/
2016-04-18 06:35:56 +03:00
# define TSADCV2_USER_CON 0x00
2014-11-24 07:58:59 +03:00
# define TSADCV2_AUTO_CON 0x04
# define TSADCV2_INT_EN 0x08
# define TSADCV2_INT_PD 0x0c
# define TSADCV2_DATA(chn) (0x20 + (chn) * 0x04)
# define TSADCV2_COMP_SHUT(chn) (0x40 + (chn) * 0x04)
# define TSADCV2_HIGHT_INT_DEBOUNCE 0x60
# define TSADCV2_HIGHT_TSHUT_DEBOUNCE 0x64
# define TSADCV2_AUTO_PERIOD 0x68
# define TSADCV2_AUTO_PERIOD_HT 0x6c
# define TSADCV2_AUTO_EN BIT(0)
# define TSADCV2_AUTO_SRC_EN(chn) BIT(4 + (chn))
# define TSADCV2_AUTO_TSHUT_POLARITY_HIGH BIT(8)
2016-04-18 06:35:58 +03:00
2016-02-15 10:33:31 +03:00
# define TSADCV3_AUTO_Q_SEL_EN BIT(1)
2014-11-24 07:58:59 +03:00
# define TSADCV2_INT_SRC_EN(chn) BIT(chn)
# define TSADCV2_SHUT_2GPIO_SRC_EN(chn) BIT(4 + (chn))
# define TSADCV2_SHUT_2CRU_SRC_EN(chn) BIT(8 + (chn))
2015-08-08 00:00:52 +03:00
# define TSADCV2_INT_PD_CLEAR_MASK ~BIT(8)
2016-02-15 10:33:30 +03:00
# define TSADCV3_INT_PD_CLEAR_MASK ~BIT(16)
2014-11-24 07:58:59 +03:00
# define TSADCV2_DATA_MASK 0xfff
2015-11-09 07:48:59 +03:00
# define TSADCV3_DATA_MASK 0x3ff
2014-11-24 07:58:59 +03:00
# define TSADCV2_HIGHT_INT_DEBOUNCE_COUNT 4
# define TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT 4
# define TSADCV2_AUTO_PERIOD_TIME 250 /* msec */
# define TSADCV2_AUTO_PERIOD_HT_TIME 50 /* msec */
2016-04-18 06:35:56 +03:00
# define TSADCV2_USER_INTER_PD_SOC 0x340 /* 13 clocks */
# define GRF_SARADC_TESTBIT 0x0e644
# define GRF_TSADC_TESTBIT_L 0x0e648
# define GRF_TSADC_TESTBIT_H 0x0e64c
# define GRF_TSADC_TSEN_PD_ON (0x30003 << 0)
# define GRF_TSADC_TSEN_PD_OFF (0x30000 << 0)
# define GRF_SARADC_TESTBIT_ON (0x10001 << 2)
# define GRF_TSADC_TESTBIT_H_ON (0x10001 << 2)
2014-11-24 07:58:59 +03:00
2015-12-03 11:48:42 +03:00
/**
2016-04-18 06:35:58 +03:00
* struct tsadc_table - code to temperature conversion table
* @ code : the value of adc channel
* @ temp : the temperature
2015-12-03 11:48:42 +03:00
* Note :
2016-04-18 06:35:58 +03:00
* code to temperature mapping of the temperature sensor is a piece wise linear
2015-12-03 11:48:42 +03:00
* curve . Any temperature , code faling between to 2 give temperatures can be
* linearly interpolated .
2016-04-18 06:35:58 +03:00
* Code to Temperature mapping should be updated based on manufacturer results .
2015-12-03 11:48:42 +03:00
*/
2016-04-18 06:35:58 +03:00
struct tsadc_table {
u32 code ;
int temp ;
} ;
2016-02-15 10:33:30 +03:00
static const struct tsadc_table rk3228_code_table [ ] = {
2016-02-15 10:33:31 +03:00
{ 0 , - 40000 } ,
{ 588 , - 40000 } ,
{ 593 , - 35000 } ,
{ 598 , - 30000 } ,
{ 603 , - 25000 } ,
{ 608 , - 20000 } ,
{ 613 , - 15000 } ,
{ 618 , - 10000 } ,
{ 623 , - 5000 } ,
{ 629 , 0 } ,
{ 634 , 5000 } ,
{ 639 , 10000 } ,
{ 644 , 15000 } ,
{ 649 , 20000 } ,
{ 654 , 25000 } ,
{ 660 , 30000 } ,
{ 665 , 35000 } ,
{ 670 , 40000 } ,
{ 675 , 45000 } ,
{ 681 , 50000 } ,
{ 686 , 55000 } ,
{ 691 , 60000 } ,
{ 696 , 65000 } ,
{ 702 , 70000 } ,
{ 707 , 75000 } ,
{ 712 , 80000 } ,
{ 717 , 85000 } ,
{ 723 , 90000 } ,
{ 728 , 95000 } ,
{ 733 , 100000 } ,
{ 738 , 105000 } ,
{ 744 , 110000 } ,
{ 749 , 115000 } ,
{ 754 , 120000 } ,
{ 760 , 125000 } ,
{ TSADCV2_DATA_MASK , 125000 } ,
2015-12-03 11:48:42 +03:00
} ;
2016-02-15 10:33:30 +03:00
static const struct tsadc_table rk3288_code_table [ ] = {
2014-11-24 07:58:59 +03:00
{ TSADCV2_DATA_MASK , - 40000 } ,
{ 3800 , - 40000 } ,
{ 3792 , - 35000 } ,
{ 3783 , - 30000 } ,
{ 3774 , - 25000 } ,
{ 3765 , - 20000 } ,
{ 3756 , - 15000 } ,
{ 3747 , - 10000 } ,
{ 3737 , - 5000 } ,
{ 3728 , 0 } ,
{ 3718 , 5000 } ,
{ 3708 , 10000 } ,
{ 3698 , 15000 } ,
{ 3688 , 20000 } ,
{ 3678 , 25000 } ,
{ 3667 , 30000 } ,
{ 3656 , 35000 } ,
{ 3645 , 40000 } ,
{ 3634 , 45000 } ,
{ 3623 , 50000 } ,
{ 3611 , 55000 } ,
{ 3600 , 60000 } ,
{ 3588 , 65000 } ,
{ 3575 , 70000 } ,
{ 3563 , 75000 } ,
{ 3550 , 80000 } ,
{ 3537 , 85000 } ,
{ 3524 , 90000 } ,
{ 3510 , 95000 } ,
{ 3496 , 100000 } ,
{ 3482 , 105000 } ,
{ 3467 , 110000 } ,
{ 3452 , 115000 } ,
{ 3437 , 120000 } ,
{ 3421 , 125000 } ,
} ;
2016-02-15 10:33:30 +03:00
static const struct tsadc_table rk3368_code_table [ ] = {
2015-11-09 07:48:59 +03:00
{ 0 , - 40000 } ,
{ 106 , - 40000 } ,
{ 108 , - 35000 } ,
{ 110 , - 30000 } ,
{ 112 , - 25000 } ,
{ 114 , - 20000 } ,
{ 116 , - 15000 } ,
{ 118 , - 10000 } ,
{ 120 , - 5000 } ,
{ 122 , 0 } ,
{ 124 , 5000 } ,
{ 126 , 10000 } ,
{ 128 , 15000 } ,
{ 130 , 20000 } ,
{ 132 , 25000 } ,
{ 134 , 30000 } ,
{ 136 , 35000 } ,
{ 138 , 40000 } ,
{ 140 , 45000 } ,
{ 142 , 50000 } ,
{ 144 , 55000 } ,
{ 146 , 60000 } ,
{ 148 , 65000 } ,
{ 150 , 70000 } ,
{ 152 , 75000 } ,
{ 154 , 80000 } ,
{ 156 , 85000 } ,
{ 158 , 90000 } ,
{ 160 , 95000 } ,
{ 162 , 100000 } ,
{ 163 , 105000 } ,
{ 165 , 110000 } ,
{ 167 , 115000 } ,
{ 169 , 120000 } ,
{ 171 , 125000 } ,
{ TSADCV3_DATA_MASK , 125000 } ,
} ;
2016-02-15 10:33:30 +03:00
static const struct tsadc_table rk3399_code_table [ ] = {
2016-02-15 10:33:31 +03:00
{ 0 , - 40000 } ,
2016-04-18 06:35:55 +03:00
{ 402 , - 40000 } ,
{ 410 , - 35000 } ,
{ 419 , - 30000 } ,
{ 427 , - 25000 } ,
{ 436 , - 20000 } ,
{ 444 , - 15000 } ,
{ 453 , - 10000 } ,
{ 461 , - 5000 } ,
{ 470 , 0 } ,
{ 478 , 5000 } ,
{ 487 , 10000 } ,
{ 496 , 15000 } ,
{ 504 , 20000 } ,
{ 513 , 25000 } ,
{ 521 , 30000 } ,
{ 530 , 35000 } ,
{ 538 , 40000 } ,
{ 547 , 45000 } ,
{ 555 , 50000 } ,
{ 564 , 55000 } ,
{ 573 , 60000 } ,
{ 581 , 65000 } ,
{ 590 , 70000 } ,
{ 599 , 75000 } ,
{ 607 , 80000 } ,
{ 616 , 85000 } ,
{ 624 , 90000 } ,
{ 633 , 95000 } ,
{ 642 , 100000 } ,
{ 650 , 105000 } ,
{ 659 , 110000 } ,
{ 668 , 115000 } ,
{ 677 , 120000 } ,
{ 685 , 125000 } ,
2016-02-15 10:33:31 +03:00
{ TSADCV3_DATA_MASK , 125000 } ,
2015-12-03 11:48:43 +03:00
} ;
2015-11-09 07:48:56 +03:00
static u32 rk_tsadcv2_temp_to_code ( struct chip_tsadc_table table ,
2015-11-09 07:48:58 +03:00
int temp )
2014-11-24 07:58:59 +03:00
{
int high , low , mid ;
low = 0 ;
2015-11-09 07:48:56 +03:00
high = table . length - 1 ;
2014-11-24 07:58:59 +03:00
mid = ( high + low ) / 2 ;
2015-11-09 07:48:56 +03:00
if ( temp < table . id [ low ] . temp | | temp > table . id [ high ] . temp )
2014-11-24 07:58:59 +03:00
return 0 ;
while ( low < = high ) {
2015-11-09 07:48:56 +03:00
if ( temp = = table . id [ mid ] . temp )
return table . id [ mid ] . code ;
else if ( temp < table . id [ mid ] . temp )
2014-11-24 07:58:59 +03:00
high = mid - 1 ;
else
low = mid + 1 ;
mid = ( low + high ) / 2 ;
}
return 0 ;
}
2015-11-09 07:48:56 +03:00
static int rk_tsadcv2_code_to_temp ( struct chip_tsadc_table table , u32 code ,
int * temp )
2014-11-24 07:58:59 +03:00
{
2015-08-07 23:59:23 +03:00
unsigned int low = 1 ;
2015-11-09 07:48:56 +03:00
unsigned int high = table . length - 1 ;
2015-01-25 05:11:11 +03:00
unsigned int mid = ( low + high ) / 2 ;
unsigned int num ;
unsigned long denom ;
2015-11-09 07:48:56 +03:00
WARN_ON ( table . length < 2 ) ;
2015-01-25 05:11:11 +03:00
2015-11-09 07:48:57 +03:00
switch ( table . mode ) {
case ADC_DECREMENT :
code & = table . data_mask ;
if ( code < table . id [ high ] . code )
return - EAGAIN ; /* Incorrect reading */
while ( low < = high ) {
if ( code > = table . id [ mid ] . code & &
code < table . id [ mid - 1 ] . code )
break ;
else if ( code < table . id [ mid ] . code )
low = mid + 1 ;
else
high = mid - 1 ;
mid = ( low + high ) / 2 ;
}
break ;
case ADC_INCREMENT :
code & = table . data_mask ;
if ( code < table . id [ low ] . code )
return - EAGAIN ; /* Incorrect reading */
while ( low < = high ) {
2016-04-18 06:35:54 +03:00
if ( code < = table . id [ mid ] . code & &
code > table . id [ mid - 1 ] . code )
2015-11-09 07:48:57 +03:00
break ;
else if ( code > table . id [ mid ] . code )
low = mid + 1 ;
else
high = mid - 1 ;
mid = ( low + high ) / 2 ;
}
break ;
default :
pr_err ( " Invalid the conversion table \n " ) ;
2014-11-24 07:58:59 +03:00
}
2015-01-25 05:11:11 +03:00
/*
* The 5 C granularity provided by the table is too much . Let ' s
* assume that the relationship between sensor readings and
* temperature between 2 table entries is linear and interpolate
* to produce less granular result .
*/
2016-02-15 10:33:29 +03:00
num = table . id [ mid ] . temp - table . id [ mid - 1 ] . temp ;
2015-11-09 07:48:57 +03:00
num * = abs ( table . id [ mid - 1 ] . code - code ) ;
denom = abs ( table . id [ mid - 1 ] . code - table . id [ mid ] . code ) ;
2015-11-09 07:48:56 +03:00
* temp = table . id [ mid - 1 ] . temp + ( num / denom ) ;
2015-08-07 23:59:23 +03:00
return 0 ;
2014-11-24 07:58:59 +03:00
}
/**
2015-11-05 08:17:59 +03:00
* rk_tsadcv2_initialize - initialize TASDC Controller .
*
* ( 1 ) Set TSADC_V2_AUTO_PERIOD :
* Configure the interleave between every two accessing of
* TSADC in normal operation .
*
* ( 2 ) Set TSADCV2_AUTO_PERIOD_HT :
* Configure the interleave between every two accessing of
* TSADC after the temperature is higher than COM_SHUT or COM_INT .
*
* ( 3 ) Set TSADCV2_HIGH_INT_DEBOUNCE and TSADC_HIGHT_TSHUT_DEBOUNCE :
* If the temperature is higher than COMP_INT or COMP_SHUT for
* " debounce " times , TSADC controller will generate interrupt or TSHUT .
2014-11-24 07:58:59 +03:00
*/
2016-04-18 06:35:56 +03:00
static void rk_tsadcv2_initialize ( struct regmap * grf , void __iomem * regs ,
2014-11-24 07:58:59 +03:00
enum tshut_polarity tshut_polarity )
{
if ( tshut_polarity = = TSHUT_HIGH_ACTIVE )
2015-08-08 00:00:52 +03:00
writel_relaxed ( 0U | TSADCV2_AUTO_TSHUT_POLARITY_HIGH ,
2014-11-24 07:58:59 +03:00
regs + TSADCV2_AUTO_CON ) ;
else
2015-08-08 00:00:52 +03:00
writel_relaxed ( 0U & ~ TSADCV2_AUTO_TSHUT_POLARITY_HIGH ,
2014-11-24 07:58:59 +03:00
regs + TSADCV2_AUTO_CON ) ;
writel_relaxed ( TSADCV2_AUTO_PERIOD_TIME , regs + TSADCV2_AUTO_PERIOD ) ;
writel_relaxed ( TSADCV2_HIGHT_INT_DEBOUNCE_COUNT ,
regs + TSADCV2_HIGHT_INT_DEBOUNCE ) ;
writel_relaxed ( TSADCV2_AUTO_PERIOD_HT_TIME ,
regs + TSADCV2_AUTO_PERIOD_HT ) ;
writel_relaxed ( TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT ,
regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE ) ;
2016-04-18 06:35:56 +03:00
if ( IS_ERR ( grf ) ) {
pr_warn ( " %s: Missing rockchip,grf property \n " , __func__ ) ;
return ;
}
}
/**
* rk_tsadcv3_initialize - initialize TASDC Controller .
2016-04-18 06:35:58 +03:00
*
2016-04-18 06:35:56 +03:00
* ( 1 ) The tsadc control power sequence .
*
* ( 2 ) Set TSADC_V2_AUTO_PERIOD :
* Configure the interleave between every two accessing of
* TSADC in normal operation .
*
* ( 2 ) Set TSADCV2_AUTO_PERIOD_HT :
* Configure the interleave between every two accessing of
* TSADC after the temperature is higher than COM_SHUT or COM_INT .
*
* ( 3 ) Set TSADCV2_HIGH_INT_DEBOUNCE and TSADC_HIGHT_TSHUT_DEBOUNCE :
* If the temperature is higher than COMP_INT or COMP_SHUT for
* " debounce " times , TSADC controller will generate interrupt or TSHUT .
*/
static void rk_tsadcv3_initialize ( struct regmap * grf , void __iomem * regs ,
enum tshut_polarity tshut_polarity )
{
/* The tsadc control power sequence */
if ( IS_ERR ( grf ) ) {
/* Set interleave value to workround ic time sync issue */
writel_relaxed ( TSADCV2_USER_INTER_PD_SOC , regs +
TSADCV2_USER_CON ) ;
} else {
regmap_write ( grf , GRF_TSADC_TESTBIT_L , GRF_TSADC_TSEN_PD_ON ) ;
mdelay ( 10 ) ;
regmap_write ( grf , GRF_TSADC_TESTBIT_L , GRF_TSADC_TSEN_PD_OFF ) ;
2016-05-03 05:23:50 +03:00
usleep_range ( 15 , 100 ) ; /* The spec note says at least 15 us */
2016-04-18 06:35:56 +03:00
regmap_write ( grf , GRF_SARADC_TESTBIT , GRF_SARADC_TESTBIT_ON ) ;
regmap_write ( grf , GRF_TSADC_TESTBIT_H , GRF_TSADC_TESTBIT_H_ON ) ;
2016-05-03 05:23:50 +03:00
usleep_range ( 90 , 200 ) ; /* The spec note says at least 90 us */
2016-04-18 06:35:56 +03:00
}
if ( tshut_polarity = = TSHUT_HIGH_ACTIVE )
writel_relaxed ( 0U | TSADCV2_AUTO_TSHUT_POLARITY_HIGH ,
regs + TSADCV2_AUTO_CON ) ;
else
writel_relaxed ( 0U & ~ TSADCV2_AUTO_TSHUT_POLARITY_HIGH ,
regs + TSADCV2_AUTO_CON ) ;
writel_relaxed ( TSADCV2_AUTO_PERIOD_TIME , regs + TSADCV2_AUTO_PERIOD ) ;
writel_relaxed ( TSADCV2_HIGHT_INT_DEBOUNCE_COUNT ,
regs + TSADCV2_HIGHT_INT_DEBOUNCE ) ;
writel_relaxed ( TSADCV2_AUTO_PERIOD_HT_TIME ,
regs + TSADCV2_AUTO_PERIOD_HT ) ;
writel_relaxed ( TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT ,
regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE ) ;
2014-11-24 07:58:59 +03:00
}
2016-02-15 10:33:30 +03:00
static void rk_tsadcv2_irq_ack ( void __iomem * regs )
2015-12-03 11:48:42 +03:00
{
u32 val ;
val = readl_relaxed ( regs + TSADCV2_INT_PD ) ;
2016-02-15 10:33:30 +03:00
writel_relaxed ( val & TSADCV2_INT_PD_CLEAR_MASK , regs + TSADCV2_INT_PD ) ;
2015-12-03 11:48:42 +03:00
}
2016-02-15 10:33:30 +03:00
static void rk_tsadcv3_irq_ack ( void __iomem * regs )
2014-11-24 07:58:59 +03:00
{
u32 val ;
val = readl_relaxed ( regs + TSADCV2_INT_PD ) ;
2016-02-15 10:33:30 +03:00
writel_relaxed ( val & TSADCV3_INT_PD_CLEAR_MASK , regs + TSADCV2_INT_PD ) ;
2014-11-24 07:58:59 +03:00
}
static void rk_tsadcv2_control ( void __iomem * regs , bool enable )
{
u32 val ;
val = readl_relaxed ( regs + TSADCV2_AUTO_CON ) ;
if ( enable )
val | = TSADCV2_AUTO_EN ;
else
val & = ~ TSADCV2_AUTO_EN ;
writel_relaxed ( val , regs + TSADCV2_AUTO_CON ) ;
}
2016-02-15 10:33:31 +03:00
/**
2016-04-18 06:35:58 +03:00
* rk_tsadcv3_control - the tsadc controller is enabled or disabled .
*
* NOTE : TSADC controller works at auto mode , and some SoCs need set the
* tsadc_q_sel bit on TSADCV2_AUTO_CON [ 1 ] . The ( 1024 - tsadc_q ) as output
* adc value if setting this bit to enable .
2016-02-15 10:33:31 +03:00
*/
static void rk_tsadcv3_control ( void __iomem * regs , bool enable )
{
u32 val ;
val = readl_relaxed ( regs + TSADCV2_AUTO_CON ) ;
if ( enable )
val | = TSADCV2_AUTO_EN | TSADCV3_AUTO_Q_SEL_EN ;
else
val & = ~ TSADCV2_AUTO_EN ;
writel_relaxed ( val , regs + TSADCV2_AUTO_CON ) ;
}
2015-11-09 07:48:56 +03:00
static int rk_tsadcv2_get_temp ( struct chip_tsadc_table table ,
int chn , void __iomem * regs , int * temp )
2014-11-24 07:58:59 +03:00
{
u32 val ;
val = readl_relaxed ( regs + TSADCV2_DATA ( chn ) ) ;
2015-11-09 07:48:56 +03:00
return rk_tsadcv2_code_to_temp ( table , val , temp ) ;
2014-11-24 07:58:59 +03:00
}
2015-11-09 07:48:56 +03:00
static void rk_tsadcv2_tshut_temp ( struct chip_tsadc_table table ,
2015-11-09 07:48:58 +03:00
int chn , void __iomem * regs , int temp )
2014-11-24 07:58:59 +03:00
{
u32 tshut_value , val ;
2015-11-09 07:48:56 +03:00
tshut_value = rk_tsadcv2_temp_to_code ( table , temp ) ;
2014-11-24 07:58:59 +03:00
writel_relaxed ( tshut_value , regs + TSADCV2_COMP_SHUT ( chn ) ) ;
/* TSHUT will be valid */
val = readl_relaxed ( regs + TSADCV2_AUTO_CON ) ;
writel_relaxed ( val | TSADCV2_AUTO_SRC_EN ( chn ) , regs + TSADCV2_AUTO_CON ) ;
}
static void rk_tsadcv2_tshut_mode ( int chn , void __iomem * regs ,
enum tshut_mode mode )
{
u32 val ;
val = readl_relaxed ( regs + TSADCV2_INT_EN ) ;
if ( mode = = TSHUT_MODE_GPIO ) {
val & = ~ TSADCV2_SHUT_2CRU_SRC_EN ( chn ) ;
val | = TSADCV2_SHUT_2GPIO_SRC_EN ( chn ) ;
} else {
val & = ~ TSADCV2_SHUT_2GPIO_SRC_EN ( chn ) ;
val | = TSADCV2_SHUT_2CRU_SRC_EN ( chn ) ;
}
writel_relaxed ( val , regs + TSADCV2_INT_EN ) ;
}
2015-12-03 11:48:42 +03:00
static const struct rockchip_tsadc_chip rk3228_tsadc_data = {
. chn_id [ SENSOR_CPU ] = 0 , /* cpu sensor is channel 0 */
. chn_num = 1 , /* one channel for tsadc */
. tshut_mode = TSHUT_MODE_GPIO , /* default TSHUT via GPIO give PMIC */
. tshut_polarity = TSHUT_LOW_ACTIVE , /* default TSHUT LOW ACTIVE */
. tshut_temp = 95000 ,
. initialize = rk_tsadcv2_initialize ,
2016-02-15 10:33:30 +03:00
. irq_ack = rk_tsadcv3_irq_ack ,
2016-02-15 10:33:31 +03:00
. control = rk_tsadcv3_control ,
2015-12-03 11:48:42 +03:00
. get_temp = rk_tsadcv2_get_temp ,
. set_tshut_temp = rk_tsadcv2_tshut_temp ,
. set_tshut_mode = rk_tsadcv2_tshut_mode ,
. table = {
2016-02-15 10:33:30 +03:00
. id = rk3228_code_table ,
. length = ARRAY_SIZE ( rk3228_code_table ) ,
2015-12-03 11:48:42 +03:00
. data_mask = TSADCV3_DATA_MASK ,
2016-02-15 10:33:31 +03:00
. mode = ADC_INCREMENT ,
2015-12-03 11:48:42 +03:00
} ,
} ;
2014-11-24 07:58:59 +03:00
static const struct rockchip_tsadc_chip rk3288_tsadc_data = {
2015-11-05 08:17:58 +03:00
. chn_id [ SENSOR_CPU ] = 1 , /* cpu sensor is channel 1 */
. chn_id [ SENSOR_GPU ] = 2 , /* gpu sensor is channel 2 */
. chn_num = 2 , /* two channels for tsadc */
2014-11-24 07:58:59 +03:00
. tshut_mode = TSHUT_MODE_GPIO , /* default TSHUT via GPIO give PMIC */
. tshut_polarity = TSHUT_LOW_ACTIVE , /* default TSHUT LOW ACTIVE */
. tshut_temp = 95000 ,
. initialize = rk_tsadcv2_initialize ,
. irq_ack = rk_tsadcv2_irq_ack ,
. control = rk_tsadcv2_control ,
. get_temp = rk_tsadcv2_get_temp ,
. set_tshut_temp = rk_tsadcv2_tshut_temp ,
. set_tshut_mode = rk_tsadcv2_tshut_mode ,
2015-11-09 07:48:56 +03:00
. table = {
2016-02-15 10:33:30 +03:00
. id = rk3288_code_table ,
. length = ARRAY_SIZE ( rk3288_code_table ) ,
2015-11-09 07:48:56 +03:00
. data_mask = TSADCV2_DATA_MASK ,
2015-11-09 07:48:57 +03:00
. mode = ADC_DECREMENT ,
2015-11-09 07:48:56 +03:00
} ,
2014-11-24 07:58:59 +03:00
} ;
2016-04-18 06:35:57 +03:00
static const struct rockchip_tsadc_chip rk3366_tsadc_data = {
. chn_id [ SENSOR_CPU ] = 0 , /* cpu sensor is channel 0 */
. chn_id [ SENSOR_GPU ] = 1 , /* gpu sensor is channel 1 */
. chn_num = 2 , /* two channels for tsadc */
. tshut_mode = TSHUT_MODE_GPIO , /* default TSHUT via GPIO give PMIC */
. tshut_polarity = TSHUT_LOW_ACTIVE , /* default TSHUT LOW ACTIVE */
. tshut_temp = 95000 ,
. initialize = rk_tsadcv3_initialize ,
. irq_ack = rk_tsadcv3_irq_ack ,
. control = rk_tsadcv3_control ,
. get_temp = rk_tsadcv2_get_temp ,
. set_tshut_temp = rk_tsadcv2_tshut_temp ,
. set_tshut_mode = rk_tsadcv2_tshut_mode ,
. table = {
. id = rk3228_code_table ,
. length = ARRAY_SIZE ( rk3228_code_table ) ,
. data_mask = TSADCV3_DATA_MASK ,
. mode = ADC_INCREMENT ,
} ,
} ;
2015-11-09 07:48:59 +03:00
static const struct rockchip_tsadc_chip rk3368_tsadc_data = {
. chn_id [ SENSOR_CPU ] = 0 , /* cpu sensor is channel 0 */
. chn_id [ SENSOR_GPU ] = 1 , /* gpu sensor is channel 1 */
. chn_num = 2 , /* two channels for tsadc */
. tshut_mode = TSHUT_MODE_GPIO , /* default TSHUT via GPIO give PMIC */
. tshut_polarity = TSHUT_LOW_ACTIVE , /* default TSHUT LOW ACTIVE */
. tshut_temp = 95000 ,
. initialize = rk_tsadcv2_initialize ,
. irq_ack = rk_tsadcv2_irq_ack ,
. control = rk_tsadcv2_control ,
. get_temp = rk_tsadcv2_get_temp ,
. set_tshut_temp = rk_tsadcv2_tshut_temp ,
. set_tshut_mode = rk_tsadcv2_tshut_mode ,
. table = {
2016-02-15 10:33:30 +03:00
. id = rk3368_code_table ,
. length = ARRAY_SIZE ( rk3368_code_table ) ,
2015-11-09 07:48:59 +03:00
. data_mask = TSADCV3_DATA_MASK ,
. mode = ADC_INCREMENT ,
} ,
} ;
2015-12-03 11:48:43 +03:00
static const struct rockchip_tsadc_chip rk3399_tsadc_data = {
. chn_id [ SENSOR_CPU ] = 0 , /* cpu sensor is channel 0 */
. chn_id [ SENSOR_GPU ] = 1 , /* gpu sensor is channel 1 */
. chn_num = 2 , /* two channels for tsadc */
. tshut_mode = TSHUT_MODE_GPIO , /* default TSHUT via GPIO give PMIC */
. tshut_polarity = TSHUT_LOW_ACTIVE , /* default TSHUT LOW ACTIVE */
. tshut_temp = 95000 ,
2016-04-18 06:35:56 +03:00
. initialize = rk_tsadcv3_initialize ,
2016-02-15 10:33:30 +03:00
. irq_ack = rk_tsadcv3_irq_ack ,
2016-02-15 10:33:31 +03:00
. control = rk_tsadcv3_control ,
2015-12-03 11:48:43 +03:00
. get_temp = rk_tsadcv2_get_temp ,
. set_tshut_temp = rk_tsadcv2_tshut_temp ,
. set_tshut_mode = rk_tsadcv2_tshut_mode ,
. table = {
2016-02-15 10:33:30 +03:00
. id = rk3399_code_table ,
. length = ARRAY_SIZE ( rk3399_code_table ) ,
2015-12-03 11:48:43 +03:00
. data_mask = TSADCV3_DATA_MASK ,
2016-02-15 10:33:31 +03:00
. mode = ADC_INCREMENT ,
2015-12-03 11:48:43 +03:00
} ,
} ;
2014-11-24 07:58:59 +03:00
static const struct of_device_id of_rockchip_thermal_match [ ] = {
2015-12-03 11:48:42 +03:00
{
. compatible = " rockchip,rk3228-tsadc " ,
. data = ( void * ) & rk3228_tsadc_data ,
} ,
2014-11-24 07:58:59 +03:00
{
. compatible = " rockchip,rk3288-tsadc " ,
. data = ( void * ) & rk3288_tsadc_data ,
} ,
2016-04-18 06:35:57 +03:00
{
. compatible = " rockchip,rk3366-tsadc " ,
. data = ( void * ) & rk3366_tsadc_data ,
} ,
2015-11-09 07:48:59 +03:00
{
. compatible = " rockchip,rk3368-tsadc " ,
. data = ( void * ) & rk3368_tsadc_data ,
} ,
2015-12-03 11:48:43 +03:00
{
. compatible = " rockchip,rk3399-tsadc " ,
. data = ( void * ) & rk3399_tsadc_data ,
} ,
2014-11-24 07:58:59 +03:00
{ /* end */ } ,
} ;
MODULE_DEVICE_TABLE ( of , of_rockchip_thermal_match ) ;
static void
rockchip_thermal_toggle_sensor ( struct rockchip_thermal_sensor * sensor , bool on )
{
struct thermal_zone_device * tzd = sensor - > tzd ;
tzd - > ops - > set_mode ( tzd ,
on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED ) ;
}
static irqreturn_t rockchip_thermal_alarm_irq_thread ( int irq , void * dev )
{
struct rockchip_thermal_data * thermal = dev ;
int i ;
dev_dbg ( & thermal - > pdev - > dev , " thermal alarm \n " ) ;
thermal - > chip - > irq_ack ( thermal - > regs ) ;
2015-11-05 08:17:58 +03:00
for ( i = 0 ; i < thermal - > chip - > chn_num ; i + + )
2014-11-24 07:58:59 +03:00
thermal_zone_device_update ( thermal - > sensors [ i ] . tzd ) ;
return IRQ_HANDLED ;
}
2015-07-24 09:12:54 +03:00
static int rockchip_thermal_get_temp ( void * _sensor , int * out_temp )
2014-11-24 07:58:59 +03:00
{
struct rockchip_thermal_sensor * sensor = _sensor ;
struct rockchip_thermal_data * thermal = sensor - > thermal ;
const struct rockchip_tsadc_chip * tsadc = sensor - > thermal - > chip ;
int retval ;
2015-11-09 07:48:56 +03:00
retval = tsadc - > get_temp ( tsadc - > table ,
sensor - > id , thermal - > regs , out_temp ) ;
2015-07-24 09:12:54 +03:00
dev_dbg ( & thermal - > pdev - > dev , " sensor %d - temp: %d, retval: %d \n " ,
2014-11-24 07:58:59 +03:00
sensor - > id , * out_temp , retval ) ;
return retval ;
}
static const struct thermal_zone_of_device_ops rockchip_of_thermal_ops = {
. get_temp = rockchip_thermal_get_temp ,
} ;
static int rockchip_configure_from_dt ( struct device * dev ,
struct device_node * np ,
struct rockchip_thermal_data * thermal )
{
u32 shut_temp , tshut_mode , tshut_polarity ;
if ( of_property_read_u32 ( np , " rockchip,hw-tshut-temp " , & shut_temp ) ) {
dev_warn ( dev ,
2015-11-09 07:48:58 +03:00
" Missing tshut temp property, using default %d \n " ,
2014-11-24 07:58:59 +03:00
thermal - > chip - > tshut_temp ) ;
thermal - > tshut_temp = thermal - > chip - > tshut_temp ;
} else {
2016-02-15 10:33:28 +03:00
if ( shut_temp > INT_MAX ) {
dev_err ( dev , " Invalid tshut temperature specified: %d \n " ,
shut_temp ) ;
return - ERANGE ;
}
2014-11-24 07:58:59 +03:00
thermal - > tshut_temp = shut_temp ;
}
if ( of_property_read_u32 ( np , " rockchip,hw-tshut-mode " , & tshut_mode ) ) {
dev_warn ( dev ,
" Missing tshut mode property, using default (%s) \n " ,
thermal - > chip - > tshut_mode = = TSHUT_MODE_GPIO ?
" gpio " : " cru " ) ;
thermal - > tshut_mode = thermal - > chip - > tshut_mode ;
} else {
thermal - > tshut_mode = tshut_mode ;
}
if ( thermal - > tshut_mode > 1 ) {
dev_err ( dev , " Invalid tshut mode specified: %d \n " ,
thermal - > tshut_mode ) ;
return - EINVAL ;
}
if ( of_property_read_u32 ( np , " rockchip,hw-tshut-polarity " ,
& tshut_polarity ) ) {
dev_warn ( dev ,
" Missing tshut-polarity property, using default (%s) \n " ,
thermal - > chip - > tshut_polarity = = TSHUT_LOW_ACTIVE ?
" low " : " high " ) ;
thermal - > tshut_polarity = thermal - > chip - > tshut_polarity ;
} else {
thermal - > tshut_polarity = tshut_polarity ;
}
if ( thermal - > tshut_polarity > 1 ) {
dev_err ( dev , " Invalid tshut-polarity specified: %d \n " ,
thermal - > tshut_polarity ) ;
return - EINVAL ;
}
2016-04-18 06:35:56 +03:00
/* The tsadc wont to handle the error in here since some SoCs didn't
* need this property .
*/
thermal - > grf = syscon_regmap_lookup_by_phandle ( np , " rockchip,grf " ) ;
2014-11-24 07:58:59 +03:00
return 0 ;
}
static int
rockchip_thermal_register_sensor ( struct platform_device * pdev ,
struct rockchip_thermal_data * thermal ,
struct rockchip_thermal_sensor * sensor ,
2015-11-05 08:17:58 +03:00
int id )
2014-11-24 07:58:59 +03:00
{
const struct rockchip_tsadc_chip * tsadc = thermal - > chip ;
int error ;
tsadc - > set_tshut_mode ( id , thermal - > regs , thermal - > tshut_mode ) ;
2015-11-09 07:48:56 +03:00
tsadc - > set_tshut_temp ( tsadc - > table , id , thermal - > regs ,
thermal - > tshut_temp ) ;
2014-11-24 07:58:59 +03:00
sensor - > thermal = thermal ;
sensor - > id = id ;
2016-03-10 00:10:28 +03:00
sensor - > tzd = devm_thermal_zone_of_sensor_register ( & pdev - > dev , id ,
sensor , & rockchip_of_thermal_ops ) ;
2014-11-24 07:58:59 +03:00
if ( IS_ERR ( sensor - > tzd ) ) {
error = PTR_ERR ( sensor - > tzd ) ;
dev_err ( & pdev - > dev , " failed to register sensor %d: %d \n " ,
id , error ) ;
return error ;
}
return 0 ;
}
2015-12-03 11:48:39 +03:00
/**
2014-11-24 07:58:59 +03:00
* Reset TSADC Controller , reset all tsadc registers .
*/
static void rockchip_thermal_reset_controller ( struct reset_control * reset )
{
reset_control_assert ( reset ) ;
usleep_range ( 10 , 20 ) ;
reset_control_deassert ( reset ) ;
}
static int rockchip_thermal_probe ( struct platform_device * pdev )
{
struct device_node * np = pdev - > dev . of_node ;
struct rockchip_thermal_data * thermal ;
const struct of_device_id * match ;
struct resource * res ;
int irq ;
2016-03-10 00:10:28 +03:00
int i ;
2014-11-24 07:58:59 +03:00
int error ;
match = of_match_node ( of_rockchip_thermal_match , np ) ;
if ( ! match )
return - ENXIO ;
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 ) {
dev_err ( & pdev - > dev , " no irq resource? \n " ) ;
return - EINVAL ;
}
thermal = devm_kzalloc ( & pdev - > dev , sizeof ( struct rockchip_thermal_data ) ,
GFP_KERNEL ) ;
if ( ! thermal )
return - ENOMEM ;
thermal - > pdev = pdev ;
thermal - > chip = ( const struct rockchip_tsadc_chip * ) match - > data ;
if ( ! thermal - > chip )
return - EINVAL ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
thermal - > regs = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( thermal - > regs ) )
return PTR_ERR ( thermal - > regs ) ;
thermal - > reset = devm_reset_control_get ( & pdev - > dev , " tsadc-apb " ) ;
if ( IS_ERR ( thermal - > reset ) ) {
error = PTR_ERR ( thermal - > reset ) ;
dev_err ( & pdev - > dev , " failed to get tsadc reset: %d \n " , error ) ;
return error ;
}
thermal - > clk = devm_clk_get ( & pdev - > dev , " tsadc " ) ;
if ( IS_ERR ( thermal - > clk ) ) {
error = PTR_ERR ( thermal - > clk ) ;
dev_err ( & pdev - > dev , " failed to get tsadc clock: %d \n " , error ) ;
return error ;
}
thermal - > pclk = devm_clk_get ( & pdev - > dev , " apb_pclk " ) ;
if ( IS_ERR ( thermal - > pclk ) ) {
2015-04-21 12:34:10 +03:00
error = PTR_ERR ( thermal - > pclk ) ;
2014-11-24 07:58:59 +03:00
dev_err ( & pdev - > dev , " failed to get apb_pclk clock: %d \n " ,
error ) ;
return error ;
}
error = clk_prepare_enable ( thermal - > clk ) ;
if ( error ) {
dev_err ( & pdev - > dev , " failed to enable converter clock: %d \n " ,
error ) ;
return error ;
}
error = clk_prepare_enable ( thermal - > pclk ) ;
if ( error ) {
dev_err ( & pdev - > dev , " failed to enable pclk: %d \n " , error ) ;
goto err_disable_clk ;
}
rockchip_thermal_reset_controller ( thermal - > reset ) ;
error = rockchip_configure_from_dt ( & pdev - > dev , np , thermal ) ;
if ( error ) {
dev_err ( & pdev - > dev , " failed to parse device tree data: %d \n " ,
error ) ;
goto err_disable_pclk ;
}
2016-04-18 06:35:56 +03:00
thermal - > chip - > initialize ( thermal - > grf , thermal - > regs ,
thermal - > tshut_polarity ) ;
2014-11-24 07:58:59 +03:00
2015-11-05 08:17:58 +03:00
for ( i = 0 ; i < thermal - > chip - > chn_num ; i + + ) {
error = rockchip_thermal_register_sensor ( pdev , thermal ,
& thermal - > sensors [ i ] ,
thermal - > chip - > chn_id [ i ] ) ;
if ( error ) {
dev_err ( & pdev - > dev ,
" failed to register sensor[%d] : error = %d \n " ,
i , error ) ;
goto err_disable_pclk ;
}
2014-11-24 07:58:59 +03:00
}
error = devm_request_threaded_irq ( & pdev - > dev , irq , NULL ,
& rockchip_thermal_alarm_irq_thread ,
IRQF_ONESHOT ,
" rockchip_thermal " , thermal ) ;
if ( error ) {
dev_err ( & pdev - > dev ,
" failed to request tsadc irq: %d \n " , error ) ;
2016-03-10 00:10:28 +03:00
goto err_disable_pclk ;
2014-11-24 07:58:59 +03:00
}
thermal - > chip - > control ( thermal - > regs , true ) ;
2015-11-05 08:17:58 +03:00
for ( i = 0 ; i < thermal - > chip - > chn_num ; i + + )
2014-11-24 07:58:59 +03:00
rockchip_thermal_toggle_sensor ( & thermal - > sensors [ i ] , true ) ;
platform_set_drvdata ( pdev , thermal ) ;
return 0 ;
err_disable_pclk :
clk_disable_unprepare ( thermal - > pclk ) ;
err_disable_clk :
clk_disable_unprepare ( thermal - > clk ) ;
return error ;
}
static int rockchip_thermal_remove ( struct platform_device * pdev )
{
struct rockchip_thermal_data * thermal = platform_get_drvdata ( pdev ) ;
int i ;
2015-11-05 08:17:58 +03:00
for ( i = 0 ; i < thermal - > chip - > chn_num ; i + + ) {
2014-11-24 07:58:59 +03:00
struct rockchip_thermal_sensor * sensor = & thermal - > sensors [ i ] ;
rockchip_thermal_toggle_sensor ( sensor , false ) ;
}
thermal - > chip - > control ( thermal - > regs , false ) ;
clk_disable_unprepare ( thermal - > pclk ) ;
clk_disable_unprepare ( thermal - > clk ) ;
return 0 ;
}
static int __maybe_unused rockchip_thermal_suspend ( struct device * dev )
{
struct platform_device * pdev = to_platform_device ( dev ) ;
struct rockchip_thermal_data * thermal = platform_get_drvdata ( pdev ) ;
int i ;
2015-11-05 08:17:58 +03:00
for ( i = 0 ; i < thermal - > chip - > chn_num ; i + + )
2014-11-24 07:58:59 +03:00
rockchip_thermal_toggle_sensor ( & thermal - > sensors [ i ] , false ) ;
thermal - > chip - > control ( thermal - > regs , false ) ;
clk_disable ( thermal - > pclk ) ;
clk_disable ( thermal - > clk ) ;
2015-10-23 14:25:27 +03:00
pinctrl_pm_select_sleep_state ( dev ) ;
2014-11-24 07:58:59 +03:00
return 0 ;
}
static int __maybe_unused rockchip_thermal_resume ( struct device * dev )
{
struct platform_device * pdev = to_platform_device ( dev ) ;
struct rockchip_thermal_data * thermal = platform_get_drvdata ( pdev ) ;
int i ;
int error ;
error = clk_enable ( thermal - > clk ) ;
if ( error )
return error ;
error = clk_enable ( thermal - > pclk ) ;
2016-04-18 06:35:53 +03:00
if ( error ) {
clk_disable ( thermal - > clk ) ;
2014-11-24 07:58:59 +03:00
return error ;
2016-04-18 06:35:53 +03:00
}
2014-11-24 07:58:59 +03:00
rockchip_thermal_reset_controller ( thermal - > reset ) ;
2016-04-18 06:35:56 +03:00
thermal - > chip - > initialize ( thermal - > grf , thermal - > regs ,
thermal - > tshut_polarity ) ;
2014-11-24 07:58:59 +03:00
2015-11-05 08:17:58 +03:00
for ( i = 0 ; i < thermal - > chip - > chn_num ; i + + ) {
int id = thermal - > sensors [ i ] . id ;
2014-11-24 07:58:59 +03:00
thermal - > chip - > set_tshut_mode ( id , thermal - > regs ,
thermal - > tshut_mode ) ;
2015-11-09 07:48:56 +03:00
thermal - > chip - > set_tshut_temp ( thermal - > chip - > table ,
id , thermal - > regs ,
2014-11-24 07:58:59 +03:00
thermal - > tshut_temp ) ;
}
thermal - > chip - > control ( thermal - > regs , true ) ;
2015-11-05 08:17:58 +03:00
for ( i = 0 ; i < thermal - > chip - > chn_num ; i + + )
2014-11-24 07:58:59 +03:00
rockchip_thermal_toggle_sensor ( & thermal - > sensors [ i ] , true ) ;
2015-10-23 14:25:27 +03:00
pinctrl_pm_select_default_state ( dev ) ;
2014-11-24 07:58:59 +03:00
return 0 ;
}
static SIMPLE_DEV_PM_OPS ( rockchip_thermal_pm_ops ,
rockchip_thermal_suspend , rockchip_thermal_resume ) ;
static struct platform_driver rockchip_thermal_driver = {
. driver = {
. name = " rockchip-thermal " ,
. pm = & rockchip_thermal_pm_ops ,
. of_match_table = of_rockchip_thermal_match ,
} ,
. probe = rockchip_thermal_probe ,
. remove = rockchip_thermal_remove ,
} ;
module_platform_driver ( rockchip_thermal_driver ) ;
MODULE_DESCRIPTION ( " ROCKCHIP THERMAL Driver " ) ;
MODULE_AUTHOR ( " Rockchip, Inc. " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_ALIAS ( " platform:rockchip-thermal " ) ;