2019-05-29 16:57:50 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2012-07-12 19:02:29 +03:00
/*
2013-03-19 10:54:21 -04:00
* TI Bandgap temperature sensor driver
2012-07-12 19:02:29 +03:00
*
* Copyright ( C ) 2011 - 2012 Texas Instruments Incorporated - http : //www.ti.com/
* Author : J Keerthy < j - keerthy @ ti . com >
* Author : Moiz Sonasath < m - sonasath @ ti . com >
* Couple of fixes , DT and MFD adaptation :
* Eduardo Valentin < eduardo . valentin @ ti . com >
*/
# include <linux/module.h>
# include <linux/export.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/interrupt.h>
# include <linux/clk.h>
2020-02-29 22:05:32 +01:00
# include <linux/gpio/consumer.h>
2012-07-12 19:02:29 +03:00
# include <linux/platform_device.h>
# include <linux/err.h>
# include <linux/types.h>
2013-03-15 09:00:35 -04:00
# include <linux/spinlock.h>
2012-07-12 19:02:29 +03:00
# include <linux/reboot.h>
# include <linux/of_device.h>
# include <linux/of_platform.h>
# include <linux/of_irq.h>
2012-11-13 14:10:00 -04:00
# include <linux/io.h>
2020-09-11 07:31:56 -05:00
# include <linux/cpu_pm.h>
# include <linux/device.h>
# include <linux/pm_runtime.h>
# include <linux/pm.h>
# include <linux/of.h>
# include <linux/of_device.h>
2012-07-12 19:02:29 +03:00
2013-03-19 10:54:19 -04:00
# include "ti-bandgap.h"
2012-07-12 19:02:29 +03:00
2015-03-24 23:20:21 +01:00
static int ti_bandgap_force_single_read ( struct ti_bandgap * bgp , int id ) ;
2020-09-11 07:31:56 -05:00
# ifdef CONFIG_PM_SLEEP
static int bandgap_omap_cpu_notifier ( struct notifier_block * nb ,
unsigned long cmd , void * v ) ;
# endif
2015-03-24 23:20:21 +01:00
2013-03-15 09:00:05 -04:00
/*** Helper functions to access registers and their bitfields ***/
2013-03-15 08:59:56 -04:00
/**
2013-03-19 10:54:21 -04:00
* ti_bandgap_readl ( ) - simple read helper function
* @ bgp : pointer to ti_bandgap structure
2013-03-15 08:59:56 -04:00
* @ reg : desired register ( offset ) to be read
*
* Helper function to read bandgap registers . It uses the io remapped area .
2013-04-01 12:04:34 -04:00
* Return : the register value .
2013-03-15 08:59:56 -04:00
*/
2013-03-19 10:54:21 -04:00
static u32 ti_bandgap_readl ( struct ti_bandgap * bgp , u32 reg )
2012-07-12 19:02:29 +03:00
{
2013-03-19 10:54:18 -04:00
return readl ( bgp - > base + reg ) ;
2012-07-12 19:02:29 +03:00
}
2013-03-15 08:59:56 -04:00
/**
2013-03-19 10:54:21 -04:00
* ti_bandgap_writel ( ) - simple write helper function
* @ bgp : pointer to ti_bandgap structure
2013-03-15 08:59:56 -04:00
* @ val : desired register value to be written
* @ reg : desired register ( offset ) to be written
*
* Helper function to write bandgap registers . It uses the io remapped area .
*/
2013-03-19 10:54:21 -04:00
static void ti_bandgap_writel ( struct ti_bandgap * bgp , u32 val , u32 reg )
2012-07-12 19:02:29 +03:00
{
2013-03-19 10:54:18 -04:00
writel ( val , bgp - > base + reg ) ;
2012-07-12 19:02:29 +03:00
}
2013-03-15 08:59:56 -04:00
/**
* DOC : macro to update bits .
*
* RMW_BITS ( ) - used to read , modify and update bandgap bitfields .
* The value passed will be shifted .
*/
2013-03-19 10:54:18 -04:00
# define RMW_BITS(bgp, id, reg, mask, val) \
2013-03-15 08:59:55 -04:00
do { \
struct temp_sensor_registers * t ; \
u32 r ; \
\
2013-03-19 10:54:18 -04:00
t = bgp - > conf - > sensors [ ( id ) ] . registers ; \
2013-03-19 10:54:21 -04:00
r = ti_bandgap_readl ( bgp , t - > reg ) ; \
2013-03-15 08:59:55 -04:00
r & = ~ t - > mask ; \
r | = ( val ) < < __ffs ( t - > mask ) ; \
2013-03-19 10:54:21 -04:00
ti_bandgap_writel ( bgp , r , t - > reg ) ; \
2013-03-15 08:59:55 -04:00
} while ( 0 )
2013-03-15 09:00:06 -04:00
/*** Basic helper functions ***/
2013-03-15 08:59:58 -04:00
/**
2013-03-19 10:54:21 -04:00
* ti_bandgap_power ( ) - controls the power state of a bandgap device
* @ bgp : pointer to ti_bandgap structure
2013-03-15 08:59:58 -04:00
* @ on : desired power state ( 1 - on , 0 - off )
*
* Used to power on / off a bandgap device instance . Only used on those
* that features tempsoff bit .
2013-04-01 12:04:34 -04:00
*
* Return : 0 on success , - ENOTSUPP if tempsoff is not supported .
2013-03-15 08:59:58 -04:00
*/
2013-03-19 10:54:21 -04:00
static int ti_bandgap_power ( struct ti_bandgap * bgp , bool on )
2012-07-12 19:02:29 +03:00
{
2015-01-18 21:17:10 +01:00
int i ;
2012-07-12 19:02:29 +03:00
2015-01-18 21:17:10 +01:00
if ( ! TI_BANDGAP_HAS ( bgp , POWER_SWITCH ) )
return - ENOTSUPP ;
2012-07-12 19:02:29 +03:00
2013-03-19 10:54:18 -04:00
for ( i = 0 ; i < bgp - > conf - > sensor_count ; i + + )
2012-07-12 19:02:29 +03:00
/* active on 0 */
2013-03-19 10:54:18 -04:00
RMW_BITS ( bgp , i , temp_sensor_ctrl , bgap_tempsoff_mask , ! on ) ;
2015-01-18 21:17:10 +01:00
return 0 ;
2012-07-12 19:02:29 +03:00
}
2015-04-22 18:21:41 +05:30
/**
* ti_errata814_bandgap_read_temp ( ) - helper function to read dra7 sensor temperature
* @ bgp : pointer to ti_bandgap structure
* @ reg : desired register ( offset ) to be read
*
* Function to read dra7 bandgap sensor temperature . This is done separately
* so as to workaround the errata " Bandgap Temperature read Dtemp can be
* corrupted " - Errata ID: i814 " .
* Read accesses to registers listed below can be corrupted due to incorrect
* resynchronization between clock domains .
* Read access to registers below can be corrupted :
* CTRL_CORE_DTEMP_MPU / GPU / CORE / DSPEVE / IVA_n ( n = 0 to 4 )
* CTRL_CORE_TEMP_SENSOR_MPU / GPU / CORE / DSPEVE / IVA_n
*
* Return : the register value .
*/
static u32 ti_errata814_bandgap_read_temp ( struct ti_bandgap * bgp , u32 reg )
{
u32 val1 , val2 ;
val1 = ti_bandgap_readl ( bgp , reg ) ;
val2 = ti_bandgap_readl ( bgp , reg ) ;
/* If both times we read the same value then that is right */
if ( val1 = = val2 )
return val1 ;
/* if val1 and val2 are different read it third time */
return ti_bandgap_readl ( bgp , reg ) ;
}
2013-03-15 08:59:59 -04:00
/**
2013-03-19 10:54:21 -04:00
* ti_bandgap_read_temp ( ) - helper function to read sensor temperature
* @ bgp : pointer to ti_bandgap structure
2013-03-15 08:59:59 -04:00
* @ id : bandgap sensor id
*
* Function to concentrate the steps to read sensor temperature register .
* This function is desired because , depending on bandgap device version ,
* it might be needed to freeze the bandgap state machine , before fetching
* the register value .
2013-04-01 12:04:34 -04:00
*
* Return : temperature in ADC values .
2013-03-15 08:59:59 -04:00
*/
2013-03-19 10:54:21 -04:00
static u32 ti_bandgap_read_temp ( struct ti_bandgap * bgp , int id )
2013-02-26 18:53:33 -04:00
{
struct temp_sensor_registers * tsr ;
2013-03-15 08:59:55 -04:00
u32 temp , reg ;
2013-02-26 18:53:33 -04:00
2013-03-19 10:54:18 -04:00
tsr = bgp - > conf - > sensors [ id ] . registers ;
2013-02-26 18:53:33 -04:00
reg = tsr - > temp_sensor_ctrl ;
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , FREEZE_BIT ) ) {
2013-03-19 10:54:18 -04:00
RMW_BITS ( bgp , id , bgap_mask_ctrl , mask_freeze_mask , 1 ) ;
2013-02-26 18:53:33 -04:00
/*
* In case we cannot read from cur_dtemp / dtemp_0 ,
* then we read from the last valid temp read
*/
reg = tsr - > ctrl_dtemp_1 ;
}
/* read temperature */
2015-04-22 18:21:41 +05:30
if ( TI_BANDGAP_HAS ( bgp , ERRATA_814 ) )
temp = ti_errata814_bandgap_read_temp ( bgp , reg ) ;
else
temp = ti_bandgap_readl ( bgp , reg ) ;
2013-02-26 18:53:33 -04:00
temp & = tsr - > bgap_dtemp_mask ;
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , FREEZE_BIT ) )
2013-03-19 10:54:18 -04:00
RMW_BITS ( bgp , id , bgap_mask_ctrl , mask_freeze_mask , 0 ) ;
2013-02-26 18:53:33 -04:00
return temp ;
}
2013-03-15 09:00:07 -04:00
/*** IRQ handlers ***/
2013-03-15 09:00:01 -04:00
/**
2013-03-19 10:54:21 -04:00
* ti_bandgap_talert_irq_handler ( ) - handles Temperature alert IRQs
2013-03-15 09:00:01 -04:00
* @ irq : IRQ number
2013-03-19 10:54:21 -04:00
* @ data : private data ( struct ti_bandgap * )
2013-03-15 09:00:01 -04:00
*
* This is the Talert handler . Use it only if bandgap device features
* HAS ( TALERT ) . This handler goes over all sensors and checks their
* conditions and acts accordingly . In case there are events pending ,
* it will reset the event mask to wait for the opposite event ( next event ) .
* Every time there is a new event , it will be reported to thermal layer .
2013-04-01 12:04:34 -04:00
*
* Return : IRQ_HANDLED
2013-03-15 09:00:01 -04:00
*/
2013-03-19 10:54:21 -04:00
static irqreturn_t ti_bandgap_talert_irq_handler ( int irq , void * data )
2012-07-12 19:02:29 +03:00
{
2013-03-19 10:54:21 -04:00
struct ti_bandgap * bgp = data ;
2012-07-12 19:02:29 +03:00
struct temp_sensor_registers * tsr ;
2013-02-26 18:53:33 -04:00
u32 t_hot = 0 , t_cold = 0 , ctrl ;
2012-07-12 19:02:29 +03:00
int i ;
2013-03-19 10:54:18 -04:00
spin_lock ( & bgp - > lock ) ;
for ( i = 0 ; i < bgp - > conf - > sensor_count ; i + + ) {
tsr = bgp - > conf - > sensors [ i ] . registers ;
2013-03-19 10:54:21 -04:00
ctrl = ti_bandgap_readl ( bgp , tsr - > bgap_status ) ;
2013-03-15 09:00:04 -04:00
/* Read the status of t_hot */
t_hot = ctrl & tsr - > status_hot_mask ;
2012-07-12 19:02:29 +03:00
/* Read the status of t_cold */
2013-03-15 09:00:04 -04:00
t_cold = ctrl & tsr - > status_cold_mask ;
2012-07-12 19:02:29 +03:00
if ( ! t_cold & & ! t_hot )
continue ;
2013-03-19 10:54:21 -04:00
ctrl = ti_bandgap_readl ( bgp , tsr - > bgap_mask_ctrl ) ;
2012-07-12 19:02:29 +03:00
/*
* One TALERT interrupt : Two sources
* If the interrupt is due to t_hot then mask t_hot and
* and unmask t_cold else mask t_cold and unmask t_hot
*/
if ( t_hot ) {
ctrl & = ~ tsr - > mask_hot_mask ;
ctrl | = tsr - > mask_cold_mask ;
} else if ( t_cold ) {
ctrl & = ~ tsr - > mask_cold_mask ;
ctrl | = tsr - > mask_hot_mask ;
}
2013-03-19 10:54:21 -04:00
ti_bandgap_writel ( bgp , ctrl , tsr - > bgap_mask_ctrl ) ;
2012-07-12 19:02:29 +03:00
2013-03-19 10:54:18 -04:00
dev_dbg ( bgp - > dev ,
2012-11-13 14:10:03 -04:00
" %s: IRQ from %s sensor: hotevent %d coldevent %d \n " ,
2013-03-19 10:54:18 -04:00
__func__ , bgp - > conf - > sensors [ i ] . domain ,
2012-11-13 14:10:03 -04:00
t_hot , t_cold ) ;
2012-07-12 19:02:29 +03:00
/* report temperature to whom may concern */
2013-03-19 10:54:18 -04:00
if ( bgp - > conf - > report_temperature )
bgp - > conf - > report_temperature ( bgp , i ) ;
2012-07-12 19:02:29 +03:00
}
2013-03-19 10:54:18 -04:00
spin_unlock ( & bgp - > lock ) ;
2012-07-12 19:02:29 +03:00
return IRQ_HANDLED ;
}
2013-03-15 09:00:02 -04:00
/**
2013-03-19 10:54:21 -04:00
* ti_bandgap_tshut_irq_handler ( ) - handles Temperature shutdown signal
2013-03-15 09:00:02 -04:00
* @ irq : IRQ number
* @ data : private data ( unused )
*
* This is the Tshut handler . Use it only if bandgap device features
* HAS ( TSHUT ) . If any sensor fires the Tshut signal , we simply shutdown
* the system .
2013-04-01 12:04:34 -04:00
*
* Return : IRQ_HANDLED
2013-03-15 09:00:02 -04:00
*/
2013-03-19 10:54:21 -04:00
static irqreturn_t ti_bandgap_tshut_irq_handler ( int irq , void * data )
2012-07-12 19:02:29 +03:00
{
2013-02-26 18:53:24 -04:00
pr_emerg ( " %s: TSHUT temperature reached. Needs shut down... \n " ,
__func__ ) ;
2012-07-12 19:02:29 +03:00
orderly_poweroff ( true ) ;
return IRQ_HANDLED ;
}
2013-03-15 09:00:08 -04:00
/*** Helper functions which manipulate conversion ADC <-> mi Celsius ***/
2013-03-15 09:00:11 -04:00
/**
2013-03-19 10:54:21 -04:00
* ti_bandgap_adc_to_mcelsius ( ) - converts an ADC value to mCelsius scale
* @ bgp : struct ti_bandgap pointer
2013-03-15 09:00:11 -04:00
* @ adc_val : value in ADC representation
* @ t : address where to write the resulting temperature in mCelsius
*
* Simple conversion from ADC representation to mCelsius . In case the ADC value
* is out of the ADC conv table range , it returns - ERANGE , 0 on success .
* The conversion table is indexed by the ADC values .
2013-04-01 12:04:34 -04:00
*
* Return : 0 if conversion was successful , else - ERANGE in case the @ adc_val
* argument is out of the ADC conv table range .
2013-03-15 09:00:11 -04:00
*/
2012-07-12 19:02:29 +03:00
static
2013-03-19 10:54:21 -04:00
int ti_bandgap_adc_to_mcelsius ( struct ti_bandgap * bgp , int adc_val , int * t )
2012-07-12 19:02:29 +03:00
{
2013-03-19 10:54:23 -04:00
const struct ti_bandgap_data * conf = bgp - > conf ;
2012-07-12 19:02:29 +03:00
/* look up for temperature in the table and return the temperature */
2015-01-18 21:17:10 +01:00
if ( adc_val < conf - > adc_start_val | | adc_val > conf - > adc_end_val )
return - ERANGE ;
2012-07-12 19:02:29 +03:00
2013-03-19 10:54:18 -04:00
* t = bgp - > conf - > conv_table [ adc_val - conf - > adc_start_val ] ;
2015-01-18 21:17:10 +01:00
return 0 ;
2012-07-12 19:02:29 +03:00
}
2013-03-15 09:00:38 -04:00
/**
2013-03-19 10:54:21 -04:00
* ti_bandgap_validate ( ) - helper to check the sanity of a struct ti_bandgap
* @ bgp : struct ti_bandgap pointer
2013-03-15 09:00:38 -04:00
* @ id : bandgap sensor id
*
* Checks if the bandgap pointer is valid and if the sensor id is also
* applicable .
2013-04-01 12:04:34 -04:00
*
* Return : 0 if no errors , - EINVAL for invalid @ bgp pointer or - ERANGE if
* @ id cannot index @ bgp sensors .
2013-03-15 09:00:38 -04:00
*/
2013-03-19 10:54:21 -04:00
static inline int ti_bandgap_validate ( struct ti_bandgap * bgp , int id )
2012-07-12 19:02:29 +03:00
{
2013-05-29 15:07:43 +00:00
if ( ! bgp | | IS_ERR ( bgp ) ) {
2013-03-15 09:00:21 -04:00
pr_err ( " %s: invalid bandgap pointer \n " , __func__ ) ;
2015-01-18 21:17:10 +01:00
return - EINVAL ;
2012-07-12 19:02:29 +03:00
}
2013-03-19 10:54:18 -04:00
if ( ( id < 0 ) | | ( id > = bgp - > conf - > sensor_count ) ) {
dev_err ( bgp - > dev , " %s: sensor id out of range (%d) \n " ,
2013-03-15 09:00:21 -04:00
__func__ , id ) ;
2015-01-18 21:17:10 +01:00
return - ERANGE ;
2012-07-12 19:02:29 +03:00
}
2015-01-18 21:17:10 +01:00
return 0 ;
2012-07-12 19:02:29 +03:00
}
2013-04-01 12:04:42 -04:00
/**
* ti_bandgap_read_counter ( ) - read the sensor counter
* @ bgp : pointer to bandgap instance
* @ id : sensor id
* @ interval : resulting update interval in miliseconds
*/
static void ti_bandgap_read_counter ( struct ti_bandgap * bgp , int id ,
int * interval )
{
struct temp_sensor_registers * tsr ;
int time ;
tsr = bgp - > conf - > sensors [ id ] . registers ;
time = ti_bandgap_readl ( bgp , tsr - > bgap_counter ) ;
time = ( time & tsr - > counter_mask ) > >
__ffs ( tsr - > counter_mask ) ;
time = time * 1000 / bgp - > clk_rate ;
* interval = time ;
}
/**
* ti_bandgap_read_counter_delay ( ) - read the sensor counter delay
* @ bgp : pointer to bandgap instance
* @ id : sensor id
* @ interval : resulting update interval in miliseconds
*/
static void ti_bandgap_read_counter_delay ( struct ti_bandgap * bgp , int id ,
int * interval )
{
struct temp_sensor_registers * tsr ;
int reg_val ;
tsr = bgp - > conf - > sensors [ id ] . registers ;
reg_val = ti_bandgap_readl ( bgp , tsr - > bgap_mask_ctrl ) ;
reg_val = ( reg_val & tsr - > mask_counter_delay_mask ) > >
__ffs ( tsr - > mask_counter_delay_mask ) ;
switch ( reg_val ) {
case 0 :
* interval = 0 ;
break ;
case 1 :
* interval = 1 ;
break ;
case 2 :
* interval = 10 ;
break ;
case 3 :
* interval = 100 ;
break ;
case 4 :
* interval = 250 ;
break ;
case 5 :
* interval = 500 ;
break ;
default :
dev_warn ( bgp - > dev , " Wrong counter delay value read from register %X " ,
reg_val ) ;
}
}
2012-07-12 19:02:29 +03:00
/**
2013-03-19 10:54:21 -04:00
* ti_bandgap_read_update_interval ( ) - read the sensor update interval
2013-03-19 10:54:25 -04:00
* @ bgp : pointer to bandgap instance
* @ id : sensor id
* @ interval : resulting update interval in miliseconds
2012-07-12 19:02:29 +03:00
*
2013-04-01 12:04:34 -04:00
* Return : 0 on success or the proper error code
2012-07-12 19:02:29 +03:00
*/
2013-03-19 10:54:21 -04:00
int ti_bandgap_read_update_interval ( struct ti_bandgap * bgp , int id ,
int * interval )
2012-07-12 19:02:29 +03:00
{
2013-04-01 12:04:42 -04:00
int ret = 0 ;
2012-07-12 19:02:29 +03:00
2013-03-19 10:54:21 -04:00
ret = ti_bandgap_validate ( bgp , id ) ;
2012-07-12 19:02:29 +03:00
if ( ret )
2013-04-01 12:04:42 -04:00
goto exit ;
2012-07-12 19:02:29 +03:00
2013-04-01 12:04:42 -04:00
if ( ! TI_BANDGAP_HAS ( bgp , COUNTER ) & &
! TI_BANDGAP_HAS ( bgp , COUNTER_DELAY ) ) {
ret = - ENOTSUPP ;
goto exit ;
}
2012-07-12 19:02:29 +03:00
2013-04-01 12:04:42 -04:00
if ( TI_BANDGAP_HAS ( bgp , COUNTER ) ) {
ti_bandgap_read_counter ( bgp , id , interval ) ;
goto exit ;
}
2012-07-12 19:02:29 +03:00
2013-04-01 12:04:42 -04:00
ti_bandgap_read_counter_delay ( bgp , id , interval ) ;
exit :
return ret ;
}
/**
* ti_bandgap_write_counter_delay ( ) - set the counter_delay
* @ bgp : pointer to bandgap instance
* @ id : sensor id
* @ interval : desired update interval in miliseconds
*
* Return : 0 on success or the proper error code
*/
static int ti_bandgap_write_counter_delay ( struct ti_bandgap * bgp , int id ,
u32 interval )
{
int rval ;
switch ( interval ) {
case 0 : /* Immediate conversion */
rval = 0x0 ;
break ;
case 1 : /* Conversion after ever 1ms */
rval = 0x1 ;
break ;
case 10 : /* Conversion after ever 10ms */
rval = 0x2 ;
break ;
case 100 : /* Conversion after ever 100ms */
rval = 0x3 ;
break ;
case 250 : /* Conversion after ever 250ms */
rval = 0x4 ;
break ;
case 500 : /* Conversion after ever 500ms */
rval = 0x5 ;
break ;
default :
dev_warn ( bgp - > dev , " Delay %d ms is not supported \n " , interval ) ;
return - EINVAL ;
}
spin_lock ( & bgp - > lock ) ;
RMW_BITS ( bgp , id , bgap_mask_ctrl , mask_counter_delay_mask , rval ) ;
spin_unlock ( & bgp - > lock ) ;
2012-07-12 19:02:29 +03:00
return 0 ;
}
2013-04-01 12:04:42 -04:00
/**
* ti_bandgap_write_counter ( ) - set the bandgap sensor counter
* @ bgp : pointer to bandgap instance
* @ id : sensor id
* @ interval : desired update interval in miliseconds
*/
static void ti_bandgap_write_counter ( struct ti_bandgap * bgp , int id ,
u32 interval )
{
interval = interval * bgp - > clk_rate / 1000 ;
spin_lock ( & bgp - > lock ) ;
RMW_BITS ( bgp , id , bgap_counter , counter_mask , interval ) ;
spin_unlock ( & bgp - > lock ) ;
}
2012-07-12 19:02:29 +03:00
/**
2013-03-19 10:54:21 -04:00
* ti_bandgap_write_update_interval ( ) - set the update interval
2013-03-19 10:54:25 -04:00
* @ bgp : pointer to bandgap instance
* @ id : sensor id
* @ interval : desired update interval in miliseconds
2012-07-12 19:02:29 +03:00
*
2013-04-01 12:04:34 -04:00
* Return : 0 on success or the proper error code
2012-07-12 19:02:29 +03:00
*/
2013-03-19 10:54:21 -04:00
int ti_bandgap_write_update_interval ( struct ti_bandgap * bgp ,
int id , u32 interval )
2012-07-12 19:02:29 +03:00
{
2013-03-19 10:54:21 -04:00
int ret = ti_bandgap_validate ( bgp , id ) ;
2012-07-12 19:02:29 +03:00
if ( ret )
2013-04-01 12:04:42 -04:00
goto exit ;
2012-07-12 19:02:29 +03:00
2013-04-01 12:04:42 -04:00
if ( ! TI_BANDGAP_HAS ( bgp , COUNTER ) & &
! TI_BANDGAP_HAS ( bgp , COUNTER_DELAY ) ) {
ret = - ENOTSUPP ;
goto exit ;
}
2012-07-12 19:02:29 +03:00
2013-04-01 12:04:42 -04:00
if ( TI_BANDGAP_HAS ( bgp , COUNTER ) ) {
ti_bandgap_write_counter ( bgp , id , interval ) ;
goto exit ;
}
2012-07-12 19:02:29 +03:00
2013-04-01 12:04:42 -04:00
ret = ti_bandgap_write_counter_delay ( bgp , id , interval ) ;
exit :
return ret ;
2012-07-12 19:02:29 +03:00
}
/**
2013-03-19 10:54:21 -04:00
* ti_bandgap_read_temperature ( ) - report current temperature
2013-03-19 10:54:25 -04:00
* @ bgp : pointer to bandgap instance
* @ id : sensor id
* @ temperature : resulting temperature
2012-07-12 19:02:29 +03:00
*
2013-04-01 12:04:34 -04:00
* Return : 0 on success or the proper error code
2012-07-12 19:02:29 +03:00
*/
2013-03-19 10:54:21 -04:00
int ti_bandgap_read_temperature ( struct ti_bandgap * bgp , int id ,
int * temperature )
2012-07-12 19:02:29 +03:00
{
u32 temp ;
int ret ;
2013-03-19 10:54:21 -04:00
ret = ti_bandgap_validate ( bgp , id ) ;
2012-07-12 19:02:29 +03:00
if ( ret )
return ret ;
2015-03-24 23:20:21 +01:00
if ( ! TI_BANDGAP_HAS ( bgp , MODE_CONFIG ) ) {
ret = ti_bandgap_force_single_read ( bgp , id ) ;
if ( ret )
return ret ;
}
2013-03-19 10:54:18 -04:00
spin_lock ( & bgp - > lock ) ;
2013-03-19 10:54:21 -04:00
temp = ti_bandgap_read_temp ( bgp , id ) ;
2013-03-19 10:54:18 -04:00
spin_unlock ( & bgp - > lock ) ;
2012-07-12 19:02:29 +03:00
2015-01-18 21:17:10 +01:00
ret = ti_bandgap_adc_to_mcelsius ( bgp , temp , & temp ) ;
2012-07-12 19:02:29 +03:00
if ( ret )
return - EIO ;
* temperature = temp ;
return 0 ;
}
/**
2013-03-19 10:54:21 -04:00
* ti_bandgap_set_sensor_data ( ) - helper function to store thermal
2012-07-12 19:02:29 +03:00
* framework related data .
2013-03-19 10:54:25 -04:00
* @ bgp : pointer to bandgap instance
* @ id : sensor id
* @ data : thermal framework related data to be stored
2012-07-12 19:02:29 +03:00
*
2013-04-01 12:04:34 -04:00
* Return : 0 on success or the proper error code
2012-07-12 19:02:29 +03:00
*/
2013-03-19 10:54:21 -04:00
int ti_bandgap_set_sensor_data ( struct ti_bandgap * bgp , int id , void * data )
2012-07-12 19:02:29 +03:00
{
2013-03-19 10:54:21 -04:00
int ret = ti_bandgap_validate ( bgp , id ) ;
2012-07-12 19:02:29 +03:00
if ( ret )
return ret ;
2013-03-19 10:54:23 -04:00
bgp - > regval [ id ] . data = data ;
2012-07-12 19:02:29 +03:00
return 0 ;
}
/**
2013-03-19 10:54:21 -04:00
* ti_bandgap_get_sensor_data ( ) - helper function to get thermal
2012-07-12 19:02:29 +03:00
* framework related data .
2013-03-19 10:54:25 -04:00
* @ bgp : pointer to bandgap instance
* @ id : sensor id
2012-07-12 19:02:29 +03:00
*
2013-04-01 12:04:34 -04:00
* Return : data stored by set function with sensor id on success or NULL
2012-07-12 19:02:29 +03:00
*/
2013-03-19 10:54:21 -04:00
void * ti_bandgap_get_sensor_data ( struct ti_bandgap * bgp , int id )
2012-07-12 19:02:29 +03:00
{
2013-03-19 10:54:21 -04:00
int ret = ti_bandgap_validate ( bgp , id ) ;
2012-07-12 19:02:29 +03:00
if ( ret )
return ERR_PTR ( ret ) ;
2013-03-19 10:54:23 -04:00
return bgp - > regval [ id ] . data ;
2012-07-12 19:02:29 +03:00
}
2013-03-15 09:00:22 -04:00
/*** Helper functions used during device initialization ***/
2013-03-15 09:00:26 -04:00
/**
2013-03-19 10:54:21 -04:00
* ti_bandgap_force_single_read ( ) - executes 1 single ADC conversion
* @ bgp : pointer to struct ti_bandgap
2013-03-15 09:00:26 -04:00
* @ id : sensor id which it is desired to read 1 temperature
*
* Used to initialize the conversion state machine and set it to a valid
* state . Called during device initialization and context restore events .
2013-04-01 12:04:34 -04:00
*
* Return : 0
2013-03-15 09:00:26 -04:00
*/
2012-07-12 19:02:29 +03:00
static int
2013-03-19 10:54:21 -04:00
ti_bandgap_force_single_read ( struct ti_bandgap * bgp , int id )
2012-07-12 19:02:29 +03:00
{
2015-01-18 21:20:51 +01:00
u32 counter = 1000 ;
struct temp_sensor_registers * tsr ;
2012-07-12 19:02:29 +03:00
/* Select single conversion mode */
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , MODE_CONFIG ) )
2013-03-19 10:54:18 -04:00
RMW_BITS ( bgp , id , bgap_mode_ctrl , mode_ctrl_mask , 0 ) ;
2012-07-12 19:02:29 +03:00
/* Start of Conversion = 1 */
2013-03-19 10:54:18 -04:00
RMW_BITS ( bgp , id , temp_sensor_ctrl , bgap_soc_mask , 1 ) ;
2013-02-26 18:53:33 -04:00
2015-01-18 21:20:51 +01:00
/* Wait for EOCZ going up */
tsr = bgp - > conf - > sensors [ id ] . registers ;
while ( - - counter ) {
if ( ti_bandgap_readl ( bgp , tsr - > temp_sensor_ctrl ) &
tsr - > bgap_eocz_mask )
break ;
}
2013-02-26 18:53:33 -04:00
2012-07-12 19:02:29 +03:00
/* Start of Conversion = 0 */
2013-03-19 10:54:18 -04:00
RMW_BITS ( bgp , id , temp_sensor_ctrl , bgap_soc_mask , 0 ) ;
2012-07-12 19:02:29 +03:00
2015-01-18 21:20:51 +01:00
/* Wait for EOCZ going down */
counter = 1000 ;
while ( - - counter ) {
if ( ! ( ti_bandgap_readl ( bgp , tsr - > temp_sensor_ctrl ) &
tsr - > bgap_eocz_mask ) )
break ;
}
2012-07-12 19:02:29 +03:00
return 0 ;
}
/**
2017-04-26 17:11:28 +02:00
* ti_bandgap_set_continuous_mode ( ) - One time enabling of continuous mode
2013-03-19 10:54:21 -04:00
* @ bgp : pointer to struct ti_bandgap
2012-07-12 19:02:29 +03:00
*
2013-03-15 09:00:25 -04:00
* Call this function only if HAS ( MODE_CONFIG ) is set . As this driver may
* be used for junction temperature monitoring , it is desirable that the
* sensors are operational all the time , so that alerts are generated
* properly .
2013-04-01 12:04:34 -04:00
*
* Return : 0
2012-07-12 19:02:29 +03:00
*/
2013-03-19 10:54:21 -04:00
static int ti_bandgap_set_continuous_mode ( struct ti_bandgap * bgp )
2012-07-12 19:02:29 +03:00
{
int i ;
2013-03-19 10:54:18 -04:00
for ( i = 0 ; i < bgp - > conf - > sensor_count ; i + + ) {
2012-07-12 19:02:29 +03:00
/* Perform a single read just before enabling continuous */
2013-03-19 10:54:21 -04:00
ti_bandgap_force_single_read ( bgp , i ) ;
2013-03-19 10:54:18 -04:00
RMW_BITS ( bgp , i , bgap_mode_ctrl , mode_ctrl_mask , 1 ) ;
2012-07-12 19:02:29 +03:00
}
return 0 ;
}
2013-04-01 12:04:45 -04:00
/**
* ti_bandgap_get_trend ( ) - To fetch the temperature trend of a sensor
* @ bgp : pointer to struct ti_bandgap
* @ id : id of the individual sensor
* @ trend : Pointer to trend .
*
* This function needs to be called to fetch the temperature trend of a
* Particular sensor . The function computes the difference in temperature
* w . r . t time . For the bandgaps with built in history buffer the temperatures
* are read from the buffer and for those without the Buffer - ENOTSUPP is
* returned .
*
* Return : 0 if no error , else return corresponding error . If no
* error then the trend value is passed on to trend parameter
*/
int ti_bandgap_get_trend ( struct ti_bandgap * bgp , int id , int * trend )
{
struct temp_sensor_registers * tsr ;
u32 temp1 , temp2 , reg1 , reg2 ;
int t1 , t2 , interval , ret = 0 ;
ret = ti_bandgap_validate ( bgp , id ) ;
if ( ret )
goto exit ;
if ( ! TI_BANDGAP_HAS ( bgp , HISTORY_BUFFER ) | |
! TI_BANDGAP_HAS ( bgp , FREEZE_BIT ) ) {
ret = - ENOTSUPP ;
goto exit ;
}
2013-06-07 19:13:13 +00:00
spin_lock ( & bgp - > lock ) ;
2013-04-01 12:04:45 -04:00
tsr = bgp - > conf - > sensors [ id ] . registers ;
/* Freeze and read the last 2 valid readings */
2013-06-07 19:13:13 +00:00
RMW_BITS ( bgp , id , bgap_mask_ctrl , mask_freeze_mask , 1 ) ;
2013-04-01 12:04:45 -04:00
reg1 = tsr - > ctrl_dtemp_1 ;
reg2 = tsr - > ctrl_dtemp_2 ;
/* read temperature from history buffer */
temp1 = ti_bandgap_readl ( bgp , reg1 ) ;
temp1 & = tsr - > bgap_dtemp_mask ;
temp2 = ti_bandgap_readl ( bgp , reg2 ) ;
temp2 & = tsr - > bgap_dtemp_mask ;
/* Convert from adc values to mCelsius temperature */
ret = ti_bandgap_adc_to_mcelsius ( bgp , temp1 , & t1 ) ;
if ( ret )
2013-06-07 19:13:13 +00:00
goto unfreeze ;
2013-04-01 12:04:45 -04:00
ret = ti_bandgap_adc_to_mcelsius ( bgp , temp2 , & t2 ) ;
if ( ret )
2013-06-07 19:13:13 +00:00
goto unfreeze ;
2013-04-01 12:04:45 -04:00
/* Fetch the update interval */
ret = ti_bandgap_read_update_interval ( bgp , id , & interval ) ;
2013-08-23 11:08:23 -05:00
if ( ret )
2013-06-07 19:13:13 +00:00
goto unfreeze ;
2013-04-01 12:04:45 -04:00
2013-08-23 11:08:23 -05:00
/* Set the interval to 1 ms if bandgap counter delay is not set */
if ( interval = = 0 )
interval = 1 ;
2013-04-01 12:04:45 -04:00
* trend = ( t1 - t2 ) / interval ;
dev_dbg ( bgp - > dev , " The temperatures are t1 = %d and t2 = %d and trend =%d \n " ,
t1 , t2 , * trend ) ;
2013-06-07 19:13:13 +00:00
unfreeze :
RMW_BITS ( bgp , id , bgap_mask_ctrl , mask_freeze_mask , 0 ) ;
spin_unlock ( & bgp - > lock ) ;
2013-04-01 12:04:45 -04:00
exit :
return ret ;
}
2013-03-15 09:00:30 -04:00
/**
2013-03-19 10:54:21 -04:00
* ti_bandgap_tshut_init ( ) - setup and initialize tshut handling
* @ bgp : pointer to struct ti_bandgap
2013-03-15 09:00:30 -04:00
* @ pdev : pointer to device struct platform_device
*
* Call this function only in case the bandgap features HAS ( TSHUT ) .
* In this case , the driver needs to handle the TSHUT signal as an IRQ .
* The IRQ is wired as a GPIO , and for this purpose , it is required
* to specify which GPIO line is used . TSHUT IRQ is fired anytime
* one of the bandgap sensors violates the TSHUT high / hot threshold .
* And in that case , the system must go off .
2013-04-01 12:04:34 -04:00
*
* Return : 0 if no error , else error status
2013-03-15 09:00:30 -04:00
*/
2013-03-19 10:54:21 -04:00
static int ti_bandgap_tshut_init ( struct ti_bandgap * bgp ,
struct platform_device * pdev )
2012-07-12 19:02:29 +03:00
{
int status ;
2020-02-29 22:05:32 +01:00
status = request_irq ( gpiod_to_irq ( bgp - > tshut_gpiod ) ,
ti_bandgap_tshut_irq_handler ,
2013-03-19 10:54:21 -04:00
IRQF_TRIGGER_RISING , " tshut " , NULL ) ;
2020-02-29 22:05:32 +01:00
if ( status )
2013-03-19 10:54:18 -04:00
dev_err ( bgp - > dev , " request irq failed for TSHUT " ) ;
2012-07-12 19:02:29 +03:00
return 0 ;
}
2013-03-15 09:00:31 -04:00
/**
2013-03-19 10:54:21 -04:00
* ti_bandgap_alert_init ( ) - setup and initialize talert handling
* @ bgp : pointer to struct ti_bandgap
2013-03-15 09:00:31 -04:00
* @ pdev : pointer to device struct platform_device
*
* Call this function only in case the bandgap features HAS ( TALERT ) .
* In this case , the driver needs to handle the TALERT signals as an IRQs .
* TALERT is a normal IRQ and it is fired any time thresholds ( hot or cold )
* are violated . In these situation , the driver must reprogram the thresholds ,
* accordingly to specified policy .
2013-04-01 12:04:34 -04:00
*
* Return : 0 if no error , else return corresponding error .
2013-03-15 09:00:31 -04:00
*/
2013-03-19 10:54:21 -04:00
static int ti_bandgap_talert_init ( struct ti_bandgap * bgp ,
struct platform_device * pdev )
2012-07-12 19:02:29 +03:00
{
int ret ;
2013-03-19 10:54:18 -04:00
bgp - > irq = platform_get_irq ( pdev , 0 ) ;
2020-04-05 18:35:16 +02:00
if ( bgp - > irq < 0 )
2013-03-19 10:54:18 -04:00
return bgp - > irq ;
2020-04-05 18:35:16 +02:00
2013-03-19 10:54:18 -04:00
ret = request_threaded_irq ( bgp - > irq , NULL ,
2013-03-19 10:54:21 -04:00
ti_bandgap_talert_irq_handler ,
2012-07-12 19:02:29 +03:00
IRQF_TRIGGER_HIGH | IRQF_ONESHOT ,
2013-03-19 10:54:18 -04:00
" talert " , bgp ) ;
2012-07-12 19:02:29 +03:00
if ( ret ) {
dev_err ( & pdev - > dev , " Request threaded irq failed. \n " ) ;
return ret ;
}
return 0 ;
}
2013-03-19 10:54:25 -04:00
static const struct of_device_id of_ti_bandgap_match [ ] ;
2013-03-15 09:00:32 -04:00
/**
2013-03-19 10:54:21 -04:00
* ti_bandgap_build ( ) - parse DT and setup a struct ti_bandgap
2013-03-15 09:00:32 -04:00
* @ pdev : pointer to device struct platform_device
*
* Used to read the device tree properties accordingly to the bandgap
* matching version . Based on bandgap version and its capabilities it
2013-03-19 10:54:21 -04:00
* will build a struct ti_bandgap out of the required DT entries .
2013-04-01 12:04:34 -04:00
*
* Return : valid bandgap structure if successful , else returns ERR_PTR
* return value must be verified with IS_ERR .
2013-03-15 09:00:32 -04:00
*/
2013-03-19 10:54:21 -04:00
static struct ti_bandgap * ti_bandgap_build ( struct platform_device * pdev )
2012-07-12 19:02:29 +03:00
{
struct device_node * node = pdev - > dev . of_node ;
const struct of_device_id * of_id ;
2013-03-19 10:54:21 -04:00
struct ti_bandgap * bgp ;
2012-07-12 19:02:29 +03:00
struct resource * res ;
int i ;
/* just for the sake */
if ( ! node ) {
dev_err ( & pdev - > dev , " no platform information available \n " ) ;
return ERR_PTR ( - EINVAL ) ;
}
2013-03-19 10:54:24 -04:00
bgp = devm_kzalloc ( & pdev - > dev , sizeof ( * bgp ) , GFP_KERNEL ) ;
2017-04-26 17:03:07 +02:00
if ( ! bgp )
2012-07-12 19:02:29 +03:00
return ERR_PTR ( - ENOMEM ) ;
2013-03-19 10:54:21 -04:00
of_id = of_match_device ( of_ti_bandgap_match , & pdev - > dev ) ;
2012-07-12 19:02:29 +03:00
if ( of_id )
2013-03-19 10:54:18 -04:00
bgp - > conf = of_id - > data ;
2012-07-12 19:02:29 +03:00
2013-03-19 10:54:23 -04:00
/* register shadow for context save and restore */
2017-04-26 16:45:25 +02:00
bgp - > regval = devm_kcalloc ( & pdev - > dev , bgp - > conf - > sensor_count ,
sizeof ( * bgp - > regval ) , GFP_KERNEL ) ;
2017-04-26 17:03:07 +02:00
if ( ! bgp - > regval )
2013-03-19 10:54:23 -04:00
return ERR_PTR ( - ENOMEM ) ;
2012-07-12 19:02:29 +03:00
i = 0 ;
do {
void __iomem * chunk ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , i ) ;
if ( ! res )
break ;
2013-01-21 11:09:19 +01:00
chunk = devm_ioremap_resource ( & pdev - > dev , res ) ;
2012-07-12 19:02:29 +03:00
if ( i = = 0 )
2013-03-19 10:54:18 -04:00
bgp - > base = chunk ;
2013-01-21 11:09:19 +01:00
if ( IS_ERR ( chunk ) )
return ERR_CAST ( chunk ) ;
2013-03-15 08:59:53 -04:00
2012-07-12 19:02:29 +03:00
i + + ;
} while ( res ) ;
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , TSHUT ) ) {
2020-02-29 22:05:32 +01:00
bgp - > tshut_gpiod = devm_gpiod_get ( & pdev - > dev , NULL , GPIOD_IN ) ;
if ( IS_ERR ( bgp - > tshut_gpiod ) ) {
dev_err ( & pdev - > dev , " invalid gpio for tshut \n " ) ;
return ERR_CAST ( bgp - > tshut_gpiod ) ;
2012-07-12 19:02:29 +03:00
}
}
2013-03-19 10:54:18 -04:00
return bgp ;
2012-07-12 19:02:29 +03:00
}
2013-03-15 09:00:23 -04:00
/*** Device driver call backs ***/
2012-07-12 19:02:29 +03:00
static
2013-03-19 10:54:21 -04:00
int ti_bandgap_probe ( struct platform_device * pdev )
2012-07-12 19:02:29 +03:00
{
2013-03-19 10:54:21 -04:00
struct ti_bandgap * bgp ;
2016-03-02 13:00:55 +03:00
int clk_rate , ret , i ;
2012-07-12 19:02:29 +03:00
2013-03-19 10:54:21 -04:00
bgp = ti_bandgap_build ( pdev ) ;
2013-05-29 15:07:43 +00:00
if ( IS_ERR ( bgp ) ) {
2012-07-12 19:02:29 +03:00
dev_err ( & pdev - > dev , " failed to fetch platform data \n " ) ;
2013-03-19 10:54:18 -04:00
return PTR_ERR ( bgp ) ;
2012-07-12 19:02:29 +03:00
}
2013-03-19 10:54:18 -04:00
bgp - > dev = & pdev - > dev ;
2012-07-12 19:02:29 +03:00
2015-04-02 16:49:07 +02:00
if ( TI_BANDGAP_HAS ( bgp , UNRELIABLE ) )
dev_warn ( & pdev - > dev ,
" This OMAP thermal sensor is unreliable. You've been warned \n " ) ;
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , TSHUT ) ) {
ret = ti_bandgap_tshut_init ( bgp , pdev ) ;
2012-07-12 19:02:29 +03:00
if ( ret ) {
dev_err ( & pdev - > dev ,
" failed to initialize system tshut IRQ \n " ) ;
return ret ;
}
}
2013-03-19 10:54:18 -04:00
bgp - > fclock = clk_get ( NULL , bgp - > conf - > fclock_name ) ;
2016-03-02 13:00:55 +03:00
if ( IS_ERR ( bgp - > fclock ) ) {
2012-07-12 19:02:29 +03:00
dev_err ( & pdev - > dev , " failed to request fclock reference \n " ) ;
2013-05-29 15:07:43 +00:00
ret = PTR_ERR ( bgp - > fclock ) ;
2012-07-12 19:02:29 +03:00
goto free_irqs ;
}
2015-01-18 21:17:10 +01:00
bgp - > div_clk = clk_get ( NULL , bgp - > conf - > div_ck_name ) ;
2016-03-02 13:00:55 +03:00
if ( IS_ERR ( bgp - > div_clk ) ) {
2015-01-18 21:17:10 +01:00
dev_err ( & pdev - > dev , " failed to request div_ts_ck clock ref \n " ) ;
2013-05-29 15:07:43 +00:00
ret = PTR_ERR ( bgp - > div_clk ) ;
2016-11-16 22:15:22 +00:00
goto put_fclock ;
2012-07-12 19:02:29 +03:00
}
2013-03-19 10:54:18 -04:00
for ( i = 0 ; i < bgp - > conf - > sensor_count ; i + + ) {
2012-07-12 19:02:29 +03:00
struct temp_sensor_registers * tsr ;
u32 val ;
2013-03-19 10:54:18 -04:00
tsr = bgp - > conf - > sensors [ i ] . registers ;
2012-07-12 19:02:29 +03:00
/*
* check if the efuse has a non - zero value if not
* it is an untrimmed sample and the temperatures
* may not be accurate
*/
2013-03-19 10:54:21 -04:00
val = ti_bandgap_readl ( bgp , tsr - > bgap_efuse ) ;
2016-03-02 13:00:55 +03:00
if ( ! val )
2012-07-12 19:02:29 +03:00
dev_info ( & pdev - > dev ,
" Non-trimmed BGAP, Temp not accurate \n " ) ;
}
2013-03-19 10:54:18 -04:00
clk_rate = clk_round_rate ( bgp - > div_clk ,
bgp - > conf - > sensors [ 0 ] . ts_data - > max_freq ) ;
if ( clk_rate < bgp - > conf - > sensors [ 0 ] . ts_data - > min_freq | |
2013-12-09 18:09:22 -08:00
clk_rate < = 0 ) {
2012-07-12 19:02:29 +03:00
ret = - ENODEV ;
dev_err ( & pdev - > dev , " wrong clock rate (%d) \n " , clk_rate ) ;
goto put_clks ;
}
2013-03-19 10:54:18 -04:00
ret = clk_set_rate ( bgp - > div_clk , clk_rate ) ;
2012-07-12 19:02:29 +03:00
if ( ret )
dev_err ( & pdev - > dev , " Cannot re-set clock rate. Continuing \n " ) ;
2013-03-19 10:54:18 -04:00
bgp - > clk_rate = clk_rate ;
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , CLK_CTRL ) )
2013-03-19 10:54:18 -04:00
clk_prepare_enable ( bgp - > fclock ) ;
2013-02-26 18:53:25 -04:00
2012-07-12 19:02:29 +03:00
2013-03-19 10:54:18 -04:00
spin_lock_init ( & bgp - > lock ) ;
bgp - > dev = & pdev - > dev ;
platform_set_drvdata ( pdev , bgp ) ;
2012-07-12 19:02:29 +03:00
2013-03-19 10:54:21 -04:00
ti_bandgap_power ( bgp , true ) ;
2012-07-12 19:02:29 +03:00
/* Set default counter to 1 for now */
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , COUNTER ) )
2013-03-19 10:54:18 -04:00
for ( i = 0 ; i < bgp - > conf - > sensor_count ; i + + )
RMW_BITS ( bgp , i , bgap_counter , counter_mask , 1 ) ;
2012-07-12 19:02:29 +03:00
2013-03-15 08:59:55 -04:00
/* Set default thresholds for alert and shutdown */
2013-03-19 10:54:18 -04:00
for ( i = 0 ; i < bgp - > conf - > sensor_count ; i + + ) {
2012-07-12 19:02:29 +03:00
struct temp_sensor_data * ts_data ;
2013-03-19 10:54:18 -04:00
ts_data = bgp - > conf - > sensors [ i ] . ts_data ;
2012-07-12 19:02:29 +03:00
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , TALERT ) ) {
2013-03-15 08:59:55 -04:00
/* Set initial Talert thresholds */
2013-03-19 10:54:18 -04:00
RMW_BITS ( bgp , i , bgap_threshold ,
2013-03-15 08:59:55 -04:00
threshold_tcold_mask , ts_data - > t_cold ) ;
2013-03-19 10:54:18 -04:00
RMW_BITS ( bgp , i , bgap_threshold ,
2013-03-15 08:59:55 -04:00
threshold_thot_mask , ts_data - > t_hot ) ;
/* Enable the alert events */
2013-03-19 10:54:18 -04:00
RMW_BITS ( bgp , i , bgap_mask_ctrl , mask_hot_mask , 1 ) ;
RMW_BITS ( bgp , i , bgap_mask_ctrl , mask_cold_mask , 1 ) ;
2013-03-15 08:59:55 -04:00
}
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , TSHUT_CONFIG ) ) {
2013-03-15 08:59:55 -04:00
/* Set initial Tshut thresholds */
2013-03-19 10:54:18 -04:00
RMW_BITS ( bgp , i , tshut_threshold ,
2013-03-15 08:59:55 -04:00
tshut_hot_mask , ts_data - > tshut_hot ) ;
2013-03-19 10:54:18 -04:00
RMW_BITS ( bgp , i , tshut_threshold ,
2013-03-15 08:59:55 -04:00
tshut_cold_mask , ts_data - > tshut_cold ) ;
2012-07-12 19:02:29 +03:00
}
}
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , MODE_CONFIG ) )
ti_bandgap_set_continuous_mode ( bgp ) ;
2012-07-12 19:02:29 +03:00
/* Set .250 seconds time as default counter */
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , COUNTER ) )
2013-03-19 10:54:18 -04:00
for ( i = 0 ; i < bgp - > conf - > sensor_count ; i + + )
RMW_BITS ( bgp , i , bgap_counter , counter_mask ,
bgp - > clk_rate / 4 ) ;
2012-07-12 19:02:29 +03:00
/* Every thing is good? Then expose the sensors */
2013-03-19 10:54:18 -04:00
for ( i = 0 ; i < bgp - > conf - > sensor_count ; i + + ) {
2012-07-12 19:02:29 +03:00
char * domain ;
2013-04-08 08:19:13 -04:00
if ( bgp - > conf - > sensors [ i ] . register_cooling ) {
ret = bgp - > conf - > sensors [ i ] . register_cooling ( bgp , i ) ;
if ( ret )
goto remove_sensors ;
}
2012-09-11 19:06:55 +03:00
2013-04-08 08:19:13 -04:00
if ( bgp - > conf - > expose_sensor ) {
domain = bgp - > conf - > sensors [ i ] . domain ;
ret = bgp - > conf - > expose_sensor ( bgp , i , domain ) ;
if ( ret )
goto remove_last_cooling ;
}
2012-07-12 19:02:29 +03:00
}
/*
* Enable the Interrupts once everything is set . Otherwise irq handler
* might be called as soon as it is enabled where as rest of framework
* is still getting initialised .
*/
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , TALERT ) ) {
ret = ti_bandgap_talert_init ( bgp , pdev ) ;
2012-07-12 19:02:29 +03:00
if ( ret ) {
dev_err ( & pdev - > dev , " failed to initialize Talert IRQ \n " ) ;
2013-03-19 10:54:18 -04:00
i = bgp - > conf - > sensor_count ;
2012-07-12 19:02:29 +03:00
goto disable_clk ;
}
}
2020-09-11 07:31:56 -05:00
# ifdef CONFIG_PM_SLEEP
bgp - > nb . notifier_call = bandgap_omap_cpu_notifier ;
cpu_pm_register_notifier ( & bgp - > nb ) ;
# endif
2012-07-12 19:02:29 +03:00
return 0 ;
2013-04-08 08:19:13 -04:00
remove_last_cooling :
if ( bgp - > conf - > sensors [ i ] . unregister_cooling )
bgp - > conf - > sensors [ i ] . unregister_cooling ( bgp , i ) ;
remove_sensors :
for ( i - - ; i > = 0 ; i - - ) {
if ( bgp - > conf - > sensors [ i ] . unregister_cooling )
bgp - > conf - > sensors [ i ] . unregister_cooling ( bgp , i ) ;
if ( bgp - > conf - > remove_sensor )
bgp - > conf - > remove_sensor ( bgp , i ) ;
}
ti_bandgap_power ( bgp , false ) ;
2012-07-12 19:02:29 +03:00
disable_clk :
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , CLK_CTRL ) )
2013-03-19 10:54:18 -04:00
clk_disable_unprepare ( bgp - > fclock ) ;
2012-07-12 19:02:29 +03:00
put_clks :
2013-03-19 10:54:18 -04:00
clk_put ( bgp - > div_clk ) ;
2016-11-16 22:15:22 +00:00
put_fclock :
clk_put ( bgp - > fclock ) ;
2012-07-12 19:02:29 +03:00
free_irqs :
2020-02-29 22:05:32 +01:00
if ( TI_BANDGAP_HAS ( bgp , TSHUT ) )
free_irq ( gpiod_to_irq ( bgp - > tshut_gpiod ) , NULL ) ;
2012-07-12 19:02:29 +03:00
return ret ;
}
static
2013-03-19 10:54:21 -04:00
int ti_bandgap_remove ( struct platform_device * pdev )
2012-07-12 19:02:29 +03:00
{
2013-03-19 10:54:21 -04:00
struct ti_bandgap * bgp = platform_get_drvdata ( pdev ) ;
2012-07-12 19:02:29 +03:00
int i ;
2020-09-11 07:31:56 -05:00
cpu_pm_unregister_notifier ( & bgp - > nb ) ;
/* Remove sensor interfaces */
2013-03-19 10:54:18 -04:00
for ( i = 0 ; i < bgp - > conf - > sensor_count ; i + + ) {
2013-04-08 08:19:14 -04:00
if ( bgp - > conf - > sensors [ i ] . unregister_cooling )
2013-03-19 10:54:18 -04:00
bgp - > conf - > sensors [ i ] . unregister_cooling ( bgp , i ) ;
2012-07-12 19:02:29 +03:00
2013-03-19 10:54:18 -04:00
if ( bgp - > conf - > remove_sensor )
bgp - > conf - > remove_sensor ( bgp , i ) ;
2012-07-12 19:02:29 +03:00
}
2013-03-19 10:54:21 -04:00
ti_bandgap_power ( bgp , false ) ;
2012-07-12 19:02:29 +03:00
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , CLK_CTRL ) )
2013-03-19 10:54:18 -04:00
clk_disable_unprepare ( bgp - > fclock ) ;
clk_put ( bgp - > fclock ) ;
clk_put ( bgp - > div_clk ) ;
2012-07-12 19:02:29 +03:00
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , TALERT ) )
2013-03-19 10:54:18 -04:00
free_irq ( bgp - > irq , bgp ) ;
2012-07-12 19:02:29 +03:00
2020-02-29 22:05:32 +01:00
if ( TI_BANDGAP_HAS ( bgp , TSHUT ) )
free_irq ( gpiod_to_irq ( bgp - > tshut_gpiod ) , NULL ) ;
2012-07-12 19:02:29 +03:00
return 0 ;
}
2015-02-06 16:55:46 +02:00
# ifdef CONFIG_PM_SLEEP
2013-03-19 10:54:21 -04:00
static int ti_bandgap_save_ctxt ( struct ti_bandgap * bgp )
2012-07-12 19:02:29 +03:00
{
int i ;
2013-03-19 10:54:18 -04:00
for ( i = 0 ; i < bgp - > conf - > sensor_count ; i + + ) {
2012-07-12 19:02:29 +03:00
struct temp_sensor_registers * tsr ;
struct temp_sensor_regval * rval ;
2013-03-19 10:54:23 -04:00
rval = & bgp - > regval [ i ] ;
2013-03-19 10:54:18 -04:00
tsr = bgp - > conf - > sensors [ i ] . registers ;
2012-07-12 19:02:29 +03:00
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , MODE_CONFIG ) )
rval - > bg_mode_ctrl = ti_bandgap_readl ( bgp ,
2012-09-11 19:06:52 +03:00
tsr - > bgap_mode_ctrl ) ;
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , COUNTER ) )
rval - > bg_counter = ti_bandgap_readl ( bgp ,
2012-09-11 19:06:52 +03:00
tsr - > bgap_counter ) ;
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , TALERT ) ) {
rval - > bg_threshold = ti_bandgap_readl ( bgp ,
2012-09-11 19:06:52 +03:00
tsr - > bgap_threshold ) ;
2013-03-19 10:54:21 -04:00
rval - > bg_ctrl = ti_bandgap_readl ( bgp ,
2012-09-11 19:06:52 +03:00
tsr - > bgap_mask_ctrl ) ;
2012-07-12 19:02:29 +03:00
}
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , TSHUT_CONFIG ) )
rval - > tshut_threshold = ti_bandgap_readl ( bgp ,
2012-09-11 19:06:52 +03:00
tsr - > tshut_threshold ) ;
2012-07-12 19:02:29 +03:00
}
return 0 ;
}
2013-03-19 10:54:21 -04:00
static int ti_bandgap_restore_ctxt ( struct ti_bandgap * bgp )
2012-07-12 19:02:29 +03:00
{
int i ;
2013-03-19 10:54:18 -04:00
for ( i = 0 ; i < bgp - > conf - > sensor_count ; i + + ) {
2012-07-12 19:02:29 +03:00
struct temp_sensor_registers * tsr ;
struct temp_sensor_regval * rval ;
u32 val = 0 ;
2013-03-19 10:54:23 -04:00
rval = & bgp - > regval [ i ] ;
2013-03-19 10:54:18 -04:00
tsr = bgp - > conf - > sensors [ i ] . registers ;
2012-07-12 19:02:29 +03:00
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , COUNTER ) )
val = ti_bandgap_readl ( bgp , tsr - > bgap_counter ) ;
2012-07-12 19:02:29 +03:00
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , TSHUT_CONFIG ) )
ti_bandgap_writel ( bgp , rval - > tshut_threshold ,
tsr - > tshut_threshold ) ;
2012-11-13 14:10:04 -04:00
/* Force immediate temperature measurement and update
* of the DTEMP field
*/
2013-03-19 10:54:21 -04:00
ti_bandgap_force_single_read ( bgp , i ) ;
if ( TI_BANDGAP_HAS ( bgp , COUNTER ) )
ti_bandgap_writel ( bgp , rval - > bg_counter ,
tsr - > bgap_counter ) ;
if ( TI_BANDGAP_HAS ( bgp , MODE_CONFIG ) )
ti_bandgap_writel ( bgp , rval - > bg_mode_ctrl ,
tsr - > bgap_mode_ctrl ) ;
if ( TI_BANDGAP_HAS ( bgp , TALERT ) ) {
ti_bandgap_writel ( bgp , rval - > bg_threshold ,
tsr - > bgap_threshold ) ;
ti_bandgap_writel ( bgp , rval - > bg_ctrl ,
tsr - > bgap_mask_ctrl ) ;
2012-07-12 19:02:29 +03:00
}
}
return 0 ;
}
2013-03-19 10:54:21 -04:00
static int ti_bandgap_suspend ( struct device * dev )
2012-07-12 19:02:29 +03:00
{
2013-03-19 10:54:21 -04:00
struct ti_bandgap * bgp = dev_get_drvdata ( dev ) ;
2012-07-12 19:02:29 +03:00
int err ;
2013-03-19 10:54:21 -04:00
err = ti_bandgap_save_ctxt ( bgp ) ;
ti_bandgap_power ( bgp , false ) ;
2013-02-26 18:53:25 -04:00
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , CLK_CTRL ) )
2013-03-19 10:54:18 -04:00
clk_disable_unprepare ( bgp - > fclock ) ;
2012-07-12 19:02:29 +03:00
2020-09-11 07:31:56 -05:00
bgp - > is_suspended = true ;
2012-07-12 19:02:29 +03:00
return err ;
}
2020-09-11 07:31:56 -05:00
static int bandgap_omap_cpu_notifier ( struct notifier_block * nb ,
unsigned long cmd , void * v )
{
struct ti_bandgap * bgp ;
bgp = container_of ( nb , struct ti_bandgap , nb ) ;
spin_lock ( & bgp - > lock ) ;
switch ( cmd ) {
case CPU_CLUSTER_PM_ENTER :
if ( bgp - > is_suspended )
break ;
ti_bandgap_save_ctxt ( bgp ) ;
ti_bandgap_power ( bgp , false ) ;
if ( TI_BANDGAP_HAS ( bgp , CLK_CTRL ) )
clk_disable ( bgp - > fclock ) ;
break ;
case CPU_CLUSTER_PM_ENTER_FAILED :
case CPU_CLUSTER_PM_EXIT :
if ( bgp - > is_suspended )
break ;
if ( TI_BANDGAP_HAS ( bgp , CLK_CTRL ) )
clk_enable ( bgp - > fclock ) ;
ti_bandgap_power ( bgp , true ) ;
ti_bandgap_restore_ctxt ( bgp ) ;
break ;
}
spin_unlock ( & bgp - > lock ) ;
return NOTIFY_OK ;
}
2013-03-19 10:54:21 -04:00
static int ti_bandgap_resume ( struct device * dev )
2012-07-12 19:02:29 +03:00
{
2013-03-19 10:54:21 -04:00
struct ti_bandgap * bgp = dev_get_drvdata ( dev ) ;
2012-07-12 19:02:29 +03:00
2013-03-19 10:54:21 -04:00
if ( TI_BANDGAP_HAS ( bgp , CLK_CTRL ) )
2013-03-19 10:54:18 -04:00
clk_prepare_enable ( bgp - > fclock ) ;
2013-02-26 18:53:25 -04:00
2013-03-19 10:54:21 -04:00
ti_bandgap_power ( bgp , true ) ;
2020-09-11 07:31:56 -05:00
bgp - > is_suspended = false ;
2012-07-12 19:02:29 +03:00
2013-03-19 10:54:21 -04:00
return ti_bandgap_restore_ctxt ( bgp ) ;
2012-07-12 19:02:29 +03:00
}
2014-02-27 20:43:02 +09:00
static SIMPLE_DEV_PM_OPS ( ti_bandgap_dev_pm_ops , ti_bandgap_suspend ,
ti_bandgap_resume ) ;
2012-07-12 19:02:29 +03:00
2013-03-19 10:54:21 -04:00
# define DEV_PM_OPS (&ti_bandgap_dev_pm_ops)
2012-07-12 19:02:29 +03:00
# else
# define DEV_PM_OPS NULL
# endif
2013-03-19 10:54:21 -04:00
static const struct of_device_id of_ti_bandgap_match [ ] = {
2015-04-02 16:49:07 +02:00
# ifdef CONFIG_OMAP3_THERMAL
{
. compatible = " ti,omap34xx-bandgap " ,
. data = ( void * ) & omap34xx_data ,
} ,
2015-09-21 17:32:15 -07:00
{
. compatible = " ti,omap36xx-bandgap " ,
. data = ( void * ) & omap36xx_data ,
} ,
2015-04-02 16:49:07 +02:00
# endif
2012-07-12 19:02:31 +03:00
# ifdef CONFIG_OMAP4_THERMAL
{
. compatible = " ti,omap4430-bandgap " ,
. data = ( void * ) & omap4430_data ,
} ,
{
. compatible = " ti,omap4460-bandgap " ,
. data = ( void * ) & omap4460_data ,
} ,
{
. compatible = " ti,omap4470-bandgap " ,
. data = ( void * ) & omap4470_data ,
} ,
2012-07-12 19:02:32 +03:00
# endif
# ifdef CONFIG_OMAP5_THERMAL
{
. compatible = " ti,omap5430-bandgap " ,
. data = ( void * ) & omap5430_data ,
} ,
2013-05-29 15:07:45 +00:00
# endif
# ifdef CONFIG_DRA752_THERMAL
{
. compatible = " ti,dra752-bandgap " ,
. data = ( void * ) & dra752_data ,
} ,
2012-07-12 19:02:31 +03:00
# endif
2012-07-12 19:02:29 +03:00
/* Sentinel */
{ } ,
} ;
2013-03-19 10:54:21 -04:00
MODULE_DEVICE_TABLE ( of , of_ti_bandgap_match ) ;
2012-07-12 19:02:29 +03:00
2013-03-19 10:54:21 -04:00
static struct platform_driver ti_bandgap_sensor_driver = {
. probe = ti_bandgap_probe ,
. remove = ti_bandgap_remove ,
2012-07-12 19:02:29 +03:00
. driver = {
2013-03-19 10:54:21 -04:00
. name = " ti-soc-thermal " ,
2012-07-12 19:02:29 +03:00
. pm = DEV_PM_OPS ,
2013-03-19 10:54:21 -04:00
. of_match_table = of_ti_bandgap_match ,
2012-07-12 19:02:29 +03:00
} ,
} ;
2013-03-19 10:54:21 -04:00
module_platform_driver ( ti_bandgap_sensor_driver ) ;
2012-07-12 19:02:29 +03:00
MODULE_DESCRIPTION ( " OMAP4+ bandgap temperature sensor driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
2013-03-19 10:54:21 -04:00
MODULE_ALIAS ( " platform:ti-soc-thermal " ) ;
2012-07-12 19:02:29 +03:00
MODULE_AUTHOR ( " Texas Instrument Inc. " ) ;