2018-09-12 15:22:47 +05:30
// SPDX-License-Identifier: GPL-2.0
2016-05-05 14:21:43 +05:30
/*
* Copyright ( c ) 2015 , The Linux Foundation . All rights reserved .
*/
# include <linux/platform_device.h>
# include <linux/delay.h>
# include <linux/bitops.h>
# include <linux/regmap.h>
# include <linux/thermal.h>
# include "tsens.h"
# define CONFIG_ADDR 0x3640
# define CONFIG_ADDR_8660 0x3620
/* CONFIG_ADDR bitmasks */
# define CONFIG 0x9b
# define CONFIG_MASK 0xf
# define CONFIG_8660 1
# define CONFIG_SHIFT_8660 28
# define CONFIG_MASK_8660 (3 << CONFIG_SHIFT_8660)
# define CNTL_ADDR 0x3620
/* CNTL_ADDR bitmasks */
# define EN BIT(0)
# define SW_RST BIT(1)
2021-04-20 20:33:41 +02:00
2021-04-20 20:33:39 +02:00
# define MEASURE_PERIOD BIT(18)
2016-05-05 14:21:43 +05:30
# define SLP_CLK_ENA BIT(26)
# define SLP_CLK_ENA_8660 BIT(24)
# define SENSOR0_SHIFT 3
# define THRESHOLD_ADDR 0x3624
# define INT_STATUS_ADDR 0x363c
2021-04-20 20:33:36 +02:00
# define S0_STATUS_OFF 0x3628
# define S1_STATUS_OFF 0x362c
# define S2_STATUS_OFF 0x3630
# define S3_STATUS_OFF 0x3634
# define S4_STATUS_OFF 0x3638
# define S5_STATUS_OFF 0x3664 /* Sensors 5-10 found on apq8064/msm8960 */
# define S6_STATUS_OFF 0x3668
# define S7_STATUS_OFF 0x366c
# define S8_STATUS_OFF 0x3670
# define S9_STATUS_OFF 0x3674
# define S10_STATUS_OFF 0x3678
2021-04-20 20:33:40 +02:00
/* Original slope - 350 to compensate mC to C inaccuracy */
static u32 tsens_msm8960_slope [ ] = {
826 , 826 , 804 , 826 ,
761 , 782 , 782 , 849 ,
782 , 849 , 782
} ;
2019-03-20 18:47:44 +05:30
static int suspend_8960 ( struct tsens_priv * priv )
2016-05-05 14:21:43 +05:30
{
int ret ;
unsigned int mask ;
2019-03-20 18:47:44 +05:30
struct regmap * map = priv - > tm_map ;
2016-05-05 14:21:43 +05:30
2019-03-20 18:47:44 +05:30
ret = regmap_read ( map , THRESHOLD_ADDR , & priv - > ctx . threshold ) ;
2016-05-05 14:21:43 +05:30
if ( ret )
return ret ;
2019-03-20 18:47:44 +05:30
ret = regmap_read ( map , CNTL_ADDR , & priv - > ctx . control ) ;
2016-05-05 14:21:43 +05:30
if ( ret )
return ret ;
2019-03-20 18:47:44 +05:30
if ( priv - > num_sensors > 1 )
2016-05-05 14:21:43 +05:30
mask = SLP_CLK_ENA | EN ;
else
mask = SLP_CLK_ENA_8660 | EN ;
ret = regmap_update_bits ( map , CNTL_ADDR , mask , 0 ) ;
if ( ret )
return ret ;
return 0 ;
}
2019-03-20 18:47:44 +05:30
static int resume_8960 ( struct tsens_priv * priv )
2016-05-05 14:21:43 +05:30
{
int ret ;
2019-03-20 18:47:44 +05:30
struct regmap * map = priv - > tm_map ;
2016-05-05 14:21:43 +05:30
ret = regmap_update_bits ( map , CNTL_ADDR , SW_RST , SW_RST ) ;
if ( ret )
return ret ;
/*
* Separate CONFIG restore is not needed only for 8660 as
* config is part of CTRL Addr and its restored as such
*/
2019-03-20 18:47:44 +05:30
if ( priv - > num_sensors > 1 ) {
2016-05-05 14:21:43 +05:30
ret = regmap_update_bits ( map , CONFIG_ADDR , CONFIG_MASK , CONFIG ) ;
if ( ret )
return ret ;
}
2019-03-20 18:47:44 +05:30
ret = regmap_write ( map , THRESHOLD_ADDR , priv - > ctx . threshold ) ;
2016-05-05 14:21:43 +05:30
if ( ret )
return ret ;
2019-03-20 18:47:44 +05:30
ret = regmap_write ( map , CNTL_ADDR , priv - > ctx . control ) ;
2016-05-05 14:21:43 +05:30
if ( ret )
return ret ;
return 0 ;
}
2019-03-20 18:47:44 +05:30
static int enable_8960 ( struct tsens_priv * priv , int id )
2016-05-05 14:21:43 +05:30
{
int ret ;
2021-04-20 20:33:39 +02:00
u32 reg , mask = BIT ( id ) ;
2016-05-05 14:21:43 +05:30
2019-03-20 18:47:44 +05:30
ret = regmap_read ( priv - > tm_map , CNTL_ADDR , & reg ) ;
2016-05-05 14:21:43 +05:30
if ( ret )
return ret ;
2021-04-20 20:33:39 +02:00
/* HARDWARE BUG:
* On platforms with more than 6 sensors , all remaining sensors
* must be enabled together , otherwise undefined results are expected .
* ( Sensor 6 - 7 disabled , Sensor 3 disabled . . . ) In the original driver ,
* all the sensors are enabled in one step hence this bug is not
* triggered .
*/
if ( id > 5 )
mask = GENMASK ( 10 , 6 ) ;
mask < < = SENSOR0_SHIFT ;
/* Sensors already enabled. Skip. */
if ( ( reg & mask ) = = mask )
return 0 ;
2019-03-20 18:47:44 +05:30
ret = regmap_write ( priv - > tm_map , CNTL_ADDR , reg | SW_RST ) ;
2016-05-05 14:21:43 +05:30
if ( ret )
return ret ;
2021-04-20 20:33:39 +02:00
reg | = MEASURE_PERIOD ;
2019-03-20 18:47:44 +05:30
if ( priv - > num_sensors > 1 )
2016-05-05 14:21:43 +05:30
reg | = mask | SLP_CLK_ENA | EN ;
else
reg | = mask | SLP_CLK_ENA_8660 | EN ;
2019-03-20 18:47:44 +05:30
ret = regmap_write ( priv - > tm_map , CNTL_ADDR , reg ) ;
2016-05-05 14:21:43 +05:30
if ( ret )
return ret ;
return 0 ;
}
2019-03-20 18:47:44 +05:30
static void disable_8960 ( struct tsens_priv * priv )
2016-05-05 14:21:43 +05:30
{
int ret ;
u32 reg_cntl ;
u32 mask ;
2019-03-20 18:47:44 +05:30
mask = GENMASK ( priv - > num_sensors - 1 , 0 ) ;
2016-05-05 14:21:43 +05:30
mask < < = SENSOR0_SHIFT ;
mask | = EN ;
2019-03-20 18:47:44 +05:30
ret = regmap_read ( priv - > tm_map , CNTL_ADDR , & reg_cntl ) ;
2016-05-05 14:21:43 +05:30
if ( ret )
return ;
reg_cntl & = ~ mask ;
2019-03-20 18:47:44 +05:30
if ( priv - > num_sensors > 1 )
2016-05-05 14:21:43 +05:30
reg_cntl & = ~ SLP_CLK_ENA ;
else
reg_cntl & = ~ SLP_CLK_ENA_8660 ;
2019-03-20 18:47:44 +05:30
regmap_write ( priv - > tm_map , CNTL_ADDR , reg_cntl ) ;
2016-05-05 14:21:43 +05:30
}
2019-03-20 18:47:44 +05:30
static int calibrate_8960 ( struct tsens_priv * priv )
2016-05-05 14:21:43 +05:30
{
int i ;
char * data ;
2021-04-20 20:33:40 +02:00
u32 p1 [ 11 ] ;
2016-05-05 14:21:43 +05:30
2019-03-20 18:47:44 +05:30
data = qfprom_read ( priv - > dev , " calib " ) ;
2016-05-05 14:21:43 +05:30
if ( IS_ERR ( data ) )
2019-03-20 18:47:44 +05:30
data = qfprom_read ( priv - > dev , " calib_backup " ) ;
2016-05-05 14:21:43 +05:30
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
2021-04-20 20:33:40 +02:00
for ( i = 0 ; i < priv - > num_sensors ; i + + ) {
p1 [ i ] = data [ i ] ;
priv - > sensor [ i ] . slope = tsens_msm8960_slope [ i ] ;
}
compute_intercept_slope ( priv , p1 , NULL , ONE_PT_CALIB ) ;
2016-05-05 14:21:43 +05:30
2019-08-23 10:38:35 +01:00
kfree ( data ) ;
2016-05-05 14:21:43 +05:30
return 0 ;
}
2021-04-20 20:33:36 +02:00
static const struct reg_field tsens_8960_regfields [ MAX_REGFIELDS ] = {
/* ----- SROT ------ */
/* No VERSION information */
/* CNTL */
[ TSENS_EN ] = REG_FIELD ( CNTL_ADDR , 0 , 0 ) ,
[ TSENS_SW_RST ] = REG_FIELD ( CNTL_ADDR , 1 , 1 ) ,
/* 8960 has 5 sensors, 8660 has 11, we only handle 5 */
[ SENSOR_EN ] = REG_FIELD ( CNTL_ADDR , 3 , 7 ) ,
/* ----- TM ------ */
/* INTERRUPT ENABLE */
/* NO INTERRUPT ENABLE */
/* Single UPPER/LOWER TEMPERATURE THRESHOLD for all sensors */
[ LOW_THRESH_0 ] = REG_FIELD ( THRESHOLD_ADDR , 0 , 7 ) ,
[ UP_THRESH_0 ] = REG_FIELD ( THRESHOLD_ADDR , 8 , 15 ) ,
/* MIN_THRESH_0 and MAX_THRESH_0 are not present in the regfield
* Recycle CRIT_THRESH_0 and 1 to set the required regs to hardcoded temp
* MIN_THRESH_0 - > CRIT_THRESH_1
* MAX_THRESH_0 - > CRIT_THRESH_0
*/
[ CRIT_THRESH_1 ] = REG_FIELD ( THRESHOLD_ADDR , 16 , 23 ) ,
[ CRIT_THRESH_0 ] = REG_FIELD ( THRESHOLD_ADDR , 24 , 31 ) ,
/* UPPER/LOWER INTERRUPT [CLEAR/STATUS] */
/* 1 == clear, 0 == normal operation */
[ LOW_INT_CLEAR_0 ] = REG_FIELD ( CNTL_ADDR , 9 , 9 ) ,
[ UP_INT_CLEAR_0 ] = REG_FIELD ( CNTL_ADDR , 10 , 10 ) ,
/* NO CRITICAL INTERRUPT SUPPORT on 8960 */
/* Sn_STATUS */
[ LAST_TEMP_0 ] = REG_FIELD ( S0_STATUS_OFF , 0 , 7 ) ,
[ LAST_TEMP_1 ] = REG_FIELD ( S1_STATUS_OFF , 0 , 7 ) ,
[ LAST_TEMP_2 ] = REG_FIELD ( S2_STATUS_OFF , 0 , 7 ) ,
[ LAST_TEMP_3 ] = REG_FIELD ( S3_STATUS_OFF , 0 , 7 ) ,
[ LAST_TEMP_4 ] = REG_FIELD ( S4_STATUS_OFF , 0 , 7 ) ,
[ LAST_TEMP_5 ] = REG_FIELD ( S5_STATUS_OFF , 0 , 7 ) ,
[ LAST_TEMP_6 ] = REG_FIELD ( S6_STATUS_OFF , 0 , 7 ) ,
[ LAST_TEMP_7 ] = REG_FIELD ( S7_STATUS_OFF , 0 , 7 ) ,
[ LAST_TEMP_8 ] = REG_FIELD ( S8_STATUS_OFF , 0 , 7 ) ,
[ LAST_TEMP_9 ] = REG_FIELD ( S9_STATUS_OFF , 0 , 7 ) ,
[ LAST_TEMP_10 ] = REG_FIELD ( S10_STATUS_OFF , 0 , 7 ) ,
/* No VALID field on 8960 */
/* TSENS_INT_STATUS bits: 1 == threshold violated */
[ MIN_STATUS_0 ] = REG_FIELD ( INT_STATUS_ADDR , 0 , 0 ) ,
[ LOWER_STATUS_0 ] = REG_FIELD ( INT_STATUS_ADDR , 1 , 1 ) ,
[ UPPER_STATUS_0 ] = REG_FIELD ( INT_STATUS_ADDR , 2 , 2 ) ,
/* No CRITICAL field on 8960 */
[ MAX_STATUS_0 ] = REG_FIELD ( INT_STATUS_ADDR , 3 , 3 ) ,
/* TRDY: 1=ready, 0=in progress */
[ TRDY ] = REG_FIELD ( INT_STATUS_ADDR , 7 , 7 ) ,
} ;
2016-07-01 18:02:09 -07:00
static const struct tsens_ops ops_8960 = {
2021-04-20 20:33:38 +02:00
. init = init_common ,
2016-05-05 14:21:43 +05:30
. calibrate = calibrate_8960 ,
2021-04-20 20:33:40 +02:00
. get_temp = get_temp_common ,
2016-05-05 14:21:43 +05:30
. enable = enable_8960 ,
. disable = disable_8960 ,
. suspend = suspend_8960 ,
. resume = resume_8960 ,
} ;
2021-04-20 20:33:37 +02:00
static struct tsens_features tsens_8960_feat = {
. ver_major = VER_0 ,
. crit_int = 0 ,
2022-08-19 00:02:42 +02:00
. combo_int = 0 ,
2021-04-20 20:33:37 +02:00
. adc = 1 ,
. srot_split = 0 ,
. max_sensors = 11 ,
2022-08-19 00:02:43 +02:00
. trip_min_temp = - 40000 ,
. trip_max_temp = 120000 ,
2021-04-20 20:33:37 +02:00
} ;
2020-03-12 18:06:58 +05:30
struct tsens_plat_data data_8960 = {
2016-05-05 14:21:43 +05:30
. num_sensors = 11 ,
. ops = & ops_8960 ,
2021-04-20 20:33:37 +02:00
. feat = & tsens_8960_feat ,
2021-04-20 20:33:36 +02:00
. fields = tsens_8960_regfields ,
2016-05-05 14:21:43 +05:30
} ;