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 CAL_MDEGC 30000
# 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 STATUS_CNTL_ADDR_8064 0x3660
# define CNTL_ADDR 0x3620
/* CNTL_ADDR bitmasks */
# define EN BIT(0)
# define SW_RST BIT(1)
# define SENSOR0_EN BIT(3)
# define SLP_CLK_ENA BIT(26)
# define SLP_CLK_ENA_8660 BIT(24)
# define MEASURE_PERIOD 1
# define SENSOR0_SHIFT 3
/* INT_STATUS_ADDR bitmasks */
# define MIN_STATUS_MASK BIT(0)
# define LOWER_STATUS_CLR BIT(1)
# define UPPER_STATUS_CLR BIT(2)
# define MAX_STATUS_MASK BIT(3)
# define THRESHOLD_ADDR 0x3624
/* THRESHOLD_ADDR bitmasks */
# define THRESHOLD_MAX_LIMIT_SHIFT 24
# define THRESHOLD_MIN_LIMIT_SHIFT 16
# define THRESHOLD_UPPER_LIMIT_SHIFT 8
# define THRESHOLD_LOWER_LIMIT_SHIFT 0
/* Initial temperature threshold values */
# define LOWER_LIMIT_TH 0x50
# define UPPER_LIMIT_TH 0xdf
# define MIN_LIMIT_TH 0x0
# define MAX_LIMIT_TH 0xff
# define S0_STATUS_ADDR 0x3628
# define INT_STATUS_ADDR 0x363c
# define TRDY_MASK BIT(7)
# define TIMEOUT_US 100
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 ;
u32 reg , mask ;
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 ;
mask = BIT ( id + SENSOR0_SHIFT ) ;
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 ;
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 init_8960 ( struct tsens_priv * priv )
2016-05-05 14:21:43 +05:30
{
int ret , i ;
u32 reg_cntl ;
2019-03-20 18:47:44 +05:30
priv - > tm_map = dev_get_regmap ( priv - > dev , NULL ) ;
if ( ! priv - > tm_map )
2016-05-05 14:21:43 +05:30
return - ENODEV ;
/*
* The status registers for each sensor are discontiguous
* because some SoCs have 5 sensors while others have more
* but the control registers stay in the same place , i . e
* directly after the first 5 status registers .
*/
2019-03-20 18:47:44 +05:30
for ( i = 0 ; i < priv - > num_sensors ; i + + ) {
2016-05-05 14:21:43 +05:30
if ( i > = 5 )
2019-03-20 18:47:44 +05:30
priv - > sensor [ i ] . status = S0_STATUS_ADDR + 40 ;
priv - > sensor [ i ] . status + = i * 4 ;
2016-05-05 14:21:43 +05:30
}
reg_cntl = SW_RST ;
2019-03-20 18:47:44 +05:30
ret = regmap_update_bits ( priv - > tm_map , CNTL_ADDR , SW_RST , reg_cntl ) ;
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
reg_cntl | = SLP_CLK_ENA | ( MEASURE_PERIOD < < 18 ) ;
reg_cntl & = ~ SW_RST ;
2019-03-20 18:47:44 +05:30
ret = regmap_update_bits ( priv - > tm_map , CONFIG_ADDR ,
2016-05-05 14:21:43 +05:30
CONFIG_MASK , CONFIG ) ;
} else {
reg_cntl | = SLP_CLK_ENA_8660 | ( MEASURE_PERIOD < < 16 ) ;
reg_cntl & = ~ CONFIG_MASK_8660 ;
reg_cntl | = CONFIG_8660 < < CONFIG_SHIFT_8660 ;
}
2019-03-20 18:47:44 +05:30
reg_cntl | = GENMASK ( priv - > num_sensors - 1 , 0 ) < < SENSOR0_SHIFT ;
ret = regmap_write ( priv - > tm_map , CNTL_ADDR , reg_cntl ) ;
2016-05-05 14:21:43 +05:30
if ( ret )
return ret ;
reg_cntl | = EN ;
2019-03-20 18:47:44 +05:30
ret = regmap_write ( priv - > tm_map , CNTL_ADDR , reg_cntl ) ;
2016-05-05 14:21:43 +05:30
if ( ret )
return ret ;
return 0 ;
}
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 ;
2019-03-20 18:47:44 +05:30
ssize_t num_read = priv - > num_sensors ;
struct tsens_sensor * s = priv - > sensor ;
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 ) ;
for ( i = 0 ; i < num_read ; i + + , s + + )
s - > offset = data [ i ] ;
2019-08-23 10:38:35 +01:00
kfree ( data ) ;
2016-05-05 14:21:43 +05:30
return 0 ;
}
/* Temperature on y axis and ADC-code on x-axis */
static inline int code_to_mdegC ( u32 adc_code , const struct tsens_sensor * s )
{
int slope , offset ;
slope = thermal_zone_get_slope ( s - > tzd ) ;
offset = CAL_MDEGC - slope * s - > offset ;
return adc_code * slope + offset ;
}
2019-11-01 00:07:25 +05:30
static int get_temp_8960 ( struct tsens_sensor * s , int * temp )
2016-05-05 14:21:43 +05:30
{
int ret ;
u32 code , trdy ;
2019-11-01 00:07:25 +05:30
struct tsens_priv * priv = s - > priv ;
2016-05-05 14:21:43 +05:30
unsigned long timeout ;
timeout = jiffies + usecs_to_jiffies ( TIMEOUT_US ) ;
do {
2019-03-20 18:47:44 +05:30
ret = regmap_read ( priv - > tm_map , INT_STATUS_ADDR , & trdy ) ;
2016-05-05 14:21:43 +05:30
if ( ret )
return ret ;
if ( ! ( trdy & TRDY_MASK ) )
continue ;
2019-03-20 18:47:44 +05:30
ret = regmap_read ( priv - > tm_map , s - > status , & code ) ;
2016-05-05 14:21:43 +05:30
if ( ret )
return ret ;
* temp = code_to_mdegC ( code , s ) ;
return 0 ;
} while ( time_before ( jiffies , timeout ) ) ;
return - ETIMEDOUT ;
}
2016-07-01 18:02:09 -07:00
static const struct tsens_ops ops_8960 = {
2016-05-05 14:21:43 +05:30
. init = init_8960 ,
. calibrate = calibrate_8960 ,
. get_temp = get_temp_8960 ,
. enable = enable_8960 ,
. disable = disable_8960 ,
. suspend = suspend_8960 ,
. resume = resume_8960 ,
} ;
2019-03-20 18:47:42 +05:30
const struct tsens_plat_data data_8960 = {
2016-05-05 14:21:43 +05:30
. num_sensors = 11 ,
. ops = & ops_8960 ,
} ;