2018-07-30 10:56:06 +03:00
// SPDX-License-Identifier: GPL-2.0
2012-07-21 04:53:48 +04:00
/*
* R - Car THS / TSC thermal sensor driver
*
* Copyright ( C ) 2012 Renesas Solutions Corp .
* Kuninori Morimoto < kuninori . morimoto . gx @ renesas . com >
*/
# include <linux/delay.h>
# include <linux/err.h>
2013-01-31 13:04:48 +04:00
# include <linux/irq.h>
# include <linux/interrupt.h>
2012-07-21 04:53:48 +04:00
# include <linux/io.h>
# include <linux/module.h>
2016-01-28 05:45:08 +03:00
# include <linux/of_device.h>
2012-07-21 04:53:48 +04:00
# include <linux/platform_device.h>
2013-03-26 10:08:52 +04:00
# include <linux/pm_runtime.h>
2012-12-03 06:48:41 +04:00
# include <linux/reboot.h>
2012-07-21 04:53:48 +04:00
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/thermal.h>
2016-07-19 13:01:37 +03:00
# include "thermal_hwmon.h"
2012-12-03 06:48:41 +04:00
# define IDLE_INTERVAL 5000
2013-01-31 13:04:48 +04:00
# define COMMON_STR 0x00
# define COMMON_ENR 0x04
# define COMMON_INTMSK 0x0c
# define REG_POSNEG 0x20
# define REG_FILONOFF 0x28
2013-01-31 13:03:46 +04:00
# define REG_THSCR 0x2c
# define REG_THSSR 0x30
2013-01-31 13:04:48 +04:00
# define REG_INTCTRL 0x34
2012-07-21 04:53:48 +04:00
/* THSCR */
2013-01-31 13:03:11 +04:00
# define CPCTL (1 << 12)
2012-07-21 04:53:48 +04:00
/* THSSR */
# define CTEMP 0x3f
2013-01-31 13:03:33 +04:00
struct rcar_thermal_common {
void __iomem * base ;
struct device * dev ;
struct list_head head ;
2013-01-31 13:04:48 +04:00
spinlock_t lock ;
2013-01-31 13:03:33 +04:00
} ;
2012-07-21 04:53:48 +04:00
2018-05-20 12:26:17 +03:00
struct rcar_thermal_chip {
unsigned int use_of_thermal : 1 ;
unsigned int has_filonoff : 1 ;
unsigned int irq_per_ch : 1 ;
unsigned int needs_suspend_resume : 1 ;
unsigned int nirqs ;
2019-05-08 14:08:45 +03:00
unsigned int ctemp_bands ;
2018-05-20 12:26:17 +03:00
} ;
static const struct rcar_thermal_chip rcar_thermal = {
. use_of_thermal = 0 ,
. has_filonoff = 1 ,
. irq_per_ch = 0 ,
. needs_suspend_resume = 0 ,
. nirqs = 1 ,
2019-05-08 14:08:45 +03:00
. ctemp_bands = 1 ,
2018-05-20 12:26:17 +03:00
} ;
static const struct rcar_thermal_chip rcar_gen2_thermal = {
. use_of_thermal = 1 ,
. has_filonoff = 1 ,
. irq_per_ch = 0 ,
. needs_suspend_resume = 0 ,
. nirqs = 1 ,
2019-05-08 14:08:45 +03:00
. ctemp_bands = 1 ,
2018-05-20 12:26:17 +03:00
} ;
static const struct rcar_thermal_chip rcar_gen3_thermal = {
. use_of_thermal = 1 ,
. has_filonoff = 0 ,
. irq_per_ch = 1 ,
. needs_suspend_resume = 1 ,
/*
* The Gen3 chip has 3 interrupts , but this driver uses only 2
* interrupts to detect a temperature change , rise or fall .
*/
. nirqs = 2 ,
2019-05-08 14:08:45 +03:00
. ctemp_bands = 2 ,
2018-05-20 12:26:17 +03:00
} ;
2012-07-21 04:53:48 +04:00
struct rcar_thermal_priv {
void __iomem * base ;
2013-01-31 13:03:33 +04:00
struct rcar_thermal_common * common ;
struct thermal_zone_device * zone ;
2018-05-20 12:26:17 +03:00
const struct rcar_thermal_chip * chip ;
2013-01-31 13:04:48 +04:00
struct delayed_work work ;
2013-01-31 13:03:22 +04:00
struct mutex lock ;
2013-01-31 13:03:33 +04:00
struct list_head list ;
2013-01-31 13:04:48 +04:00
int id ;
2012-07-21 04:53:48 +04:00
} ;
2013-01-31 13:03:33 +04:00
# define rcar_thermal_for_each_priv(pos, common) \
list_for_each_entry ( pos , & common - > head , list )
2012-11-26 06:32:06 +04:00
# define MCELSIUS(temp) ((temp) * 1000)
2013-01-31 13:02:51 +04:00
# define rcar_zone_to_priv(zone) ((zone)->devdata)
2013-01-31 13:03:33 +04:00
# define rcar_priv_to_dev(priv) ((priv)->common->dev)
# define rcar_has_irq_support(priv) ((priv)->common->base)
2013-01-31 13:04:48 +04:00
# define rcar_id_to_shift(priv) ((priv)->id * 8)
2015-12-15 04:17:07 +03:00
static const struct of_device_id rcar_thermal_dt_ids [ ] = {
2018-05-20 12:26:17 +03:00
{
. compatible = " renesas,rcar-thermal " ,
. data = & rcar_thermal ,
} ,
{
. compatible = " renesas,rcar-gen2-thermal " ,
. data = & rcar_gen2_thermal ,
} ,
2018-12-13 23:23:10 +03:00
{
. compatible = " renesas,thermal-r8a774c0 " ,
. data = & rcar_gen3_thermal ,
} ,
2018-10-05 00:03:13 +03:00
{
. compatible = " renesas,thermal-r8a77970 " ,
. data = & rcar_gen3_thermal ,
} ,
2018-12-17 17:50:21 +03:00
{
. compatible = " renesas,thermal-r8a77990 " ,
. data = & rcar_gen3_thermal ,
} ,
2018-05-20 12:26:17 +03:00
{
. compatible = " renesas,thermal-r8a77995 " ,
. data = & rcar_gen3_thermal ,
} ,
2015-12-15 04:17:07 +03:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , rcar_thermal_dt_ids ) ;
2012-07-21 04:53:48 +04:00
/*
* basic functions
*/
2013-01-31 13:03:46 +04:00
# define rcar_thermal_common_read(c, r) \
_rcar_thermal_common_read ( c , COMMON_ # # r )
static u32 _rcar_thermal_common_read ( struct rcar_thermal_common * common ,
u32 reg )
{
return ioread32 ( common - > base + reg ) ;
}
# define rcar_thermal_common_write(c, r, d) \
_rcar_thermal_common_write ( c , COMMON_ # # r , d )
static void _rcar_thermal_common_write ( struct rcar_thermal_common * common ,
u32 reg , u32 data )
{
iowrite32 ( data , common - > base + reg ) ;
}
# define rcar_thermal_common_bset(c, r, m, d) \
_rcar_thermal_common_bset ( c , COMMON_ # # r , m , d )
static void _rcar_thermal_common_bset ( struct rcar_thermal_common * common ,
u32 reg , u32 mask , u32 data )
{
u32 val ;
val = ioread32 ( common - > base + reg ) ;
val & = ~ mask ;
val | = ( data & mask ) ;
iowrite32 ( val , common - > base + reg ) ;
}
# define rcar_thermal_read(p, r) _rcar_thermal_read(p, REG_ ##r)
static u32 _rcar_thermal_read ( struct rcar_thermal_priv * priv , u32 reg )
2012-07-21 04:53:48 +04:00
{
2013-01-31 13:03:22 +04:00
return ioread32 ( priv - > base + reg ) ;
2012-07-21 04:53:48 +04:00
}
2013-01-31 13:03:46 +04:00
# define rcar_thermal_write(p, r, d) _rcar_thermal_write(p, REG_ ##r, d)
static void _rcar_thermal_write ( struct rcar_thermal_priv * priv ,
u32 reg , u32 data )
2012-07-21 04:53:48 +04:00
{
iowrite32 ( data , priv - > base + reg ) ;
}
2013-01-31 13:03:46 +04:00
# define rcar_thermal_bset(p, r, m, d) _rcar_thermal_bset(p, REG_ ##r, m, d)
static void _rcar_thermal_bset ( struct rcar_thermal_priv * priv , u32 reg ,
u32 mask , u32 data )
2012-07-21 04:53:48 +04:00
{
u32 val ;
val = ioread32 ( priv - > base + reg ) ;
val & = ~ mask ;
val | = ( data & mask ) ;
iowrite32 ( val , priv - > base + reg ) ;
}
/*
* zone device functions
*/
2013-01-31 13:04:48 +04:00
static int rcar_thermal_update_temp ( struct rcar_thermal_priv * priv )
2012-07-21 04:53:48 +04:00
{
2013-01-31 13:03:11 +04:00
struct device * dev = rcar_priv_to_dev ( priv ) ;
2020-05-14 18:25:05 +03:00
int old , new , ctemp = - EINVAL ;
unsigned int i ;
2013-01-31 13:03:11 +04:00
2013-01-31 13:03:22 +04:00
mutex_lock ( & priv - > lock ) ;
2013-01-31 13:03:11 +04:00
/*
* TSC decides a value of CPTAP automatically ,
* and this is the conditions which validate interrupt .
*/
rcar_thermal_bset ( priv , THSCR , CPCTL , CPCTL ) ;
old = ~ 0 ;
for ( i = 0 ; i < 128 ; i + + ) {
2012-07-21 04:53:48 +04:00
/*
* we need to wait 300u s after changing comparator offset
* to get stable temperature .
* see " Usage Notes " on datasheet
*/
2020-01-15 15:54:17 +03:00
usleep_range ( 300 , 400 ) ;
2012-07-21 04:53:48 +04:00
2013-01-31 13:03:11 +04:00
new = rcar_thermal_read ( priv , THSSR ) & CTEMP ;
if ( new = = old ) {
ctemp = new ;
2012-07-21 04:53:48 +04:00
break ;
}
2013-01-31 13:03:11 +04:00
old = new ;
2012-07-21 04:53:48 +04:00
}
2020-05-14 18:25:05 +03:00
if ( ctemp < 0 ) {
2013-01-31 13:03:11 +04:00
dev_err ( dev , " thermal sensor was broken \n " ) ;
2013-02-22 17:22:39 +04:00
goto err_out_unlock ;
2013-01-31 13:03:11 +04:00
}
2013-01-31 13:04:48 +04:00
/*
* enable IRQ
*/
if ( rcar_has_irq_support ( priv ) ) {
2018-05-20 12:26:17 +03:00
if ( priv - > chip - > has_filonoff )
rcar_thermal_write ( priv , FILONOFF , 0 ) ;
2013-01-31 13:04:48 +04:00
/* enable Rising/Falling edge interrupt */
rcar_thermal_write ( priv , POSNEG , 0x1 ) ;
rcar_thermal_write ( priv , INTCTRL , ( ( ( ctemp - 0 ) < < 8 ) |
( ( ctemp - 1 ) < < 0 ) ) ) ;
}
2013-02-22 17:22:39 +04:00
err_out_unlock :
2013-01-31 13:03:22 +04:00
mutex_unlock ( & priv - > lock ) ;
2020-03-10 20:00:28 +03:00
2020-05-14 18:25:05 +03:00
return ctemp ;
2012-07-21 04:53:48 +04:00
}
2016-01-28 05:45:08 +03:00
static int rcar_thermal_get_current_temp ( struct rcar_thermal_priv * priv ,
int * temp )
2013-01-31 13:04:48 +04:00
{
2020-03-10 20:00:29 +03:00
int ctemp ;
2013-01-31 13:04:48 +04:00
2020-03-10 20:00:28 +03:00
ctemp = rcar_thermal_update_temp ( priv ) ;
if ( ctemp < 0 )
return ctemp ;
2013-01-31 13:04:48 +04:00
2020-03-10 20:00:29 +03:00
/* Guaranteed operating range is -45C to 125C. */
2019-05-08 14:08:45 +03:00
if ( priv - > chip - > ctemp_bands = = 1 )
2020-03-10 20:00:29 +03:00
* temp = MCELSIUS ( ( ctemp * 5 ) - 65 ) ;
2020-03-10 20:00:28 +03:00
else if ( ctemp < 24 )
2020-03-10 20:00:29 +03:00
* temp = MCELSIUS ( ( ( ctemp * 55 ) - 720 ) / 10 ) ;
2019-05-08 14:08:45 +03:00
else
2020-03-10 20:00:29 +03:00
* temp = MCELSIUS ( ( ctemp * 5 ) - 60 ) ;
2015-12-15 04:18:13 +03:00
2013-01-31 13:04:48 +04:00
return 0 ;
}
2016-01-28 05:45:08 +03:00
static int rcar_thermal_of_get_temp ( void * data , int * temp )
{
struct rcar_thermal_priv * priv = data ;
return rcar_thermal_get_current_temp ( priv , temp ) ;
}
static int rcar_thermal_get_temp ( struct thermal_zone_device * zone , int * temp )
{
struct rcar_thermal_priv * priv = rcar_zone_to_priv ( zone ) ;
return rcar_thermal_get_current_temp ( priv , temp ) ;
}
2012-12-03 06:48:41 +04:00
static int rcar_thermal_get_trip_type ( struct thermal_zone_device * zone ,
int trip , enum thermal_trip_type * type )
{
struct rcar_thermal_priv * priv = rcar_zone_to_priv ( zone ) ;
2013-01-31 13:03:33 +04:00
struct device * dev = rcar_priv_to_dev ( priv ) ;
2012-12-03 06:48:41 +04:00
/* see rcar_thermal_get_temp() */
switch ( trip ) {
case 0 : /* +90 <= temp */
* type = THERMAL_TRIP_CRITICAL ;
break ;
default :
2013-01-31 13:03:33 +04:00
dev_err ( dev , " rcar driver trip error \n " ) ;
2012-12-03 06:48:41 +04:00
return - EINVAL ;
}
return 0 ;
}
static int rcar_thermal_get_trip_temp ( struct thermal_zone_device * zone ,
2015-07-24 09:12:54 +03:00
int trip , int * temp )
2012-12-03 06:48:41 +04:00
{
struct rcar_thermal_priv * priv = rcar_zone_to_priv ( zone ) ;
2013-01-31 13:03:33 +04:00
struct device * dev = rcar_priv_to_dev ( priv ) ;
2012-12-03 06:48:41 +04:00
/* see rcar_thermal_get_temp() */
switch ( trip ) {
case 0 : /* +90 <= temp */
* temp = MCELSIUS ( 90 ) ;
break ;
default :
2013-01-31 13:03:33 +04:00
dev_err ( dev , " rcar driver trip error \n " ) ;
2012-12-03 06:48:41 +04:00
return - EINVAL ;
}
return 0 ;
}
static int rcar_thermal_notify ( struct thermal_zone_device * zone ,
int trip , enum thermal_trip_type type )
{
struct rcar_thermal_priv * priv = rcar_zone_to_priv ( zone ) ;
2013-01-31 13:03:33 +04:00
struct device * dev = rcar_priv_to_dev ( priv ) ;
2012-12-03 06:48:41 +04:00
switch ( type ) {
case THERMAL_TRIP_CRITICAL :
/* FIXME */
2013-01-31 13:03:33 +04:00
dev_warn ( dev , " Thermal reached to critical temperature \n " ) ;
2012-12-03 06:48:41 +04:00
break ;
default :
break ;
}
return 0 ;
}
2016-01-28 05:45:08 +03:00
static const struct thermal_zone_of_device_ops rcar_thermal_zone_of_ops = {
. get_temp = rcar_thermal_of_get_temp ,
} ;
2012-07-21 04:53:48 +04:00
static struct thermal_zone_device_ops rcar_thermal_zone_ops = {
2012-12-03 06:48:41 +04:00
. get_temp = rcar_thermal_get_temp ,
. get_trip_type = rcar_thermal_get_trip_type ,
. get_trip_temp = rcar_thermal_get_trip_temp ,
. notify = rcar_thermal_notify ,
2012-07-21 04:53:48 +04:00
} ;
2013-01-31 13:04:48 +04:00
/*
* interrupt
*/
# define rcar_thermal_irq_enable(p) _rcar_thermal_irq_ctrl(p, 1)
# define rcar_thermal_irq_disable(p) _rcar_thermal_irq_ctrl(p, 0)
static void _rcar_thermal_irq_ctrl ( struct rcar_thermal_priv * priv , int enable )
{
struct rcar_thermal_common * common = priv - > common ;
unsigned long flags ;
u32 mask = 0x3 < < rcar_id_to_shift ( priv ) ; /* enable Rising/Falling */
2015-12-15 04:17:56 +03:00
if ( ! rcar_has_irq_support ( priv ) )
return ;
2013-01-31 13:04:48 +04:00
spin_lock_irqsave ( & common - > lock , flags ) ;
rcar_thermal_common_bset ( common , INTMSK , mask , enable ? 0 : mask ) ;
spin_unlock_irqrestore ( & common - > lock , flags ) ;
}
static void rcar_thermal_work ( struct work_struct * work )
{
struct rcar_thermal_priv * priv ;
2015-12-15 04:17:40 +03:00
int ret ;
2013-01-31 13:04:48 +04:00
priv = container_of ( work , struct rcar_thermal_priv , work . work ) ;
2015-12-15 04:17:40 +03:00
ret = rcar_thermal_update_temp ( priv ) ;
if ( ret < 0 )
return ;
2013-01-31 13:04:48 +04:00
rcar_thermal_irq_enable ( priv ) ;
thermal: rcar-thermal: update thermal zone only when temperature changes
Avoid updating the thermal zone in case an IRQ was triggered but the
temperature didn't effectively change.
Note this is not a driver issue.
Below is a captured debug trace illustrating the purpose of this patch:
out of 8 thermal zone updates, only 2 are actually necessary.
[ 41.120000] rcar_thermal_work(): cctemp=25000
[ 41.120000] rcar_thermal_work(): nctemp=30000
[ 41.120000] rcar_thermal_work(): temp is now 30000C, update thermal zone
[ 58.990000] rcar_thermal_work(): cctemp=30000
[ 58.990000] rcar_thermal_work(): nctemp=30000
[ 58.990000] rcar_thermal_work(): same temp, do not update thermal zone
[ 59.290000] rcar_thermal_work(): cctemp=30000
[ 59.290000] rcar_thermal_work(): nctemp=30000
[ 59.290000] rcar_thermal_work(): same temp, do not update thermal zone
[ 59.590000] rcar_thermal_work(): cctemp=30000
[ 59.590000] rcar_thermal_work(): nctemp=30000
[ 59.590000] rcar_thermal_work(): same temp, do not update thermal zone
[ 59.890000] rcar_thermal_work(): cctemp=30000
[ 59.890000] rcar_thermal_work(): nctemp=30000
[ 59.890000] rcar_thermal_work(): same temp, do not update thermal zone
[ 60.190000] rcar_thermal_work(): cctemp=30000
[ 60.190000] rcar_thermal_work(): nctemp=30000
[ 60.190000] rcar_thermal_work(): same temp, do not update thermal zone
[ 60.490000] rcar_thermal_work(): cctemp=30000
[ 60.490000] rcar_thermal_work(): nctemp=30000
[ 60.490000] rcar_thermal_work(): same temp, do not update thermal zone
[ 60.790000] rcar_thermal_work(): cctemp=30000
[ 60.790000] rcar_thermal_work(): nctemp=35000
[ 60.790000] rcar_thermal_work(): temp is now 35000C, update thermal zone
I suspect this may be due to sensor sampling accuracy / fluctuation,
but no formal proof.
Signed-off-by: Patrick Titiano <ptitiano@baylibre.com>
Acked-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
2014-02-28 17:10:04 +04:00
2020-03-10 20:00:27 +03:00
thermal_zone_device_update ( priv - > zone , THERMAL_EVENT_UNSPECIFIED ) ;
2013-01-31 13:04:48 +04:00
}
static u32 rcar_thermal_had_changed ( struct rcar_thermal_priv * priv , u32 status )
{
struct device * dev = rcar_priv_to_dev ( priv ) ;
status = ( status > > rcar_id_to_shift ( priv ) ) & 0x3 ;
2014-02-28 17:10:03 +04:00
if ( status ) {
2013-01-31 13:04:48 +04:00
dev_dbg ( dev , " thermal%d %s%s \n " ,
priv - > id ,
( status & 0x2 ) ? " Rising " : " " ,
( status & 0x1 ) ? " Falling " : " " ) ;
}
return status ;
}
static irqreturn_t rcar_thermal_irq ( int irq , void * data )
{
struct rcar_thermal_common * common = data ;
struct rcar_thermal_priv * priv ;
unsigned long flags ;
u32 status , mask ;
spin_lock_irqsave ( & common - > lock , flags ) ;
mask = rcar_thermal_common_read ( common , INTMSK ) ;
status = rcar_thermal_common_read ( common , STR ) ;
rcar_thermal_common_write ( common , STR , 0x000F0F0F & mask ) ;
spin_unlock_irqrestore ( & common - > lock , flags ) ;
status = status & ~ mask ;
/*
* check the status
*/
rcar_thermal_for_each_priv ( priv , common ) {
if ( rcar_thermal_had_changed ( priv , status ) ) {
rcar_thermal_irq_disable ( priv ) ;
2018-10-12 10:20:15 +03:00
queue_delayed_work ( system_freezable_wq , & priv - > work ,
msecs_to_jiffies ( 300 ) ) ;
2013-01-31 13:04:48 +04:00
}
}
return IRQ_HANDLED ;
}
2012-07-21 04:53:48 +04:00
/*
* platform functions
*/
2015-11-10 05:12:06 +03:00
static int rcar_thermal_remove ( struct platform_device * pdev )
{
struct rcar_thermal_common * common = platform_get_drvdata ( pdev ) ;
struct device * dev = & pdev - > dev ;
struct rcar_thermal_priv * priv ;
rcar_thermal_for_each_priv ( priv , common ) {
2015-12-15 04:17:56 +03:00
rcar_thermal_irq_disable ( priv ) ;
2018-10-12 10:20:16 +03:00
cancel_delayed_work_sync ( & priv - > work ) ;
2018-05-20 12:26:17 +03:00
if ( priv - > chip - > use_of_thermal )
2016-07-19 13:01:37 +03:00
thermal_remove_hwmon_sysfs ( priv - > zone ) ;
2016-08-22 06:19:49 +03:00
else
thermal_zone_device_unregister ( priv - > zone ) ;
2015-11-10 05:12:06 +03:00
}
pm_runtime_put ( dev ) ;
pm_runtime_disable ( dev ) ;
return 0 ;
}
2012-07-21 04:53:48 +04:00
static int rcar_thermal_probe ( struct platform_device * pdev )
{
2013-01-31 13:03:33 +04:00
struct rcar_thermal_common * common ;
2012-07-21 04:53:48 +04:00
struct rcar_thermal_priv * priv ;
2013-01-31 13:03:33 +04:00
struct device * dev = & pdev - > dev ;
struct resource * res , * irq ;
2018-05-20 12:26:17 +03:00
const struct rcar_thermal_chip * chip = of_device_get_match_data ( dev ) ;
2013-01-31 13:03:33 +04:00
int mres = 0 ;
int i ;
2013-03-04 20:52:47 +04:00
int ret = - ENODEV ;
2013-01-31 13:04:48 +04:00
int idle = IDLE_INTERVAL ;
2015-01-07 04:13:10 +03:00
u32 enr_bits = 0 ;
2012-07-21 04:53:48 +04:00
2013-01-31 13:03:33 +04:00
common = devm_kzalloc ( dev , sizeof ( * common ) , GFP_KERNEL ) ;
2014-05-07 10:03:25 +04:00
if ( ! common )
2012-07-21 04:53:48 +04:00
return - ENOMEM ;
2015-11-10 05:12:06 +03:00
platform_set_drvdata ( pdev , common ) ;
2013-01-31 13:03:33 +04:00
INIT_LIST_HEAD ( & common - > head ) ;
2013-01-31 13:04:48 +04:00
spin_lock_init ( & common - > lock ) ;
2013-01-31 13:03:33 +04:00
common - > dev = dev ;
2013-03-26 10:08:52 +04:00
pm_runtime_enable ( dev ) ;
pm_runtime_get_sync ( dev ) ;
2018-05-20 12:26:17 +03:00
for ( i = 0 ; i < chip - > nirqs ; i + + ) {
2018-10-03 23:47:34 +03:00
irq = platform_get_resource ( pdev , IORESOURCE_IRQ , i ) ;
2018-05-20 12:26:17 +03:00
if ( ! irq )
continue ;
if ( ! common - > base ) {
/*
* platform has IRQ support .
* Then , driver uses common registers
* rcar_has_irq_support ( ) will be enabled
*/
res = platform_get_resource ( pdev , IORESOURCE_MEM ,
mres + + ) ;
common - > base = devm_ioremap_resource ( dev , res ) ;
2020-03-10 14:47:09 +03:00
if ( IS_ERR ( common - > base ) ) {
ret = PTR_ERR ( common - > base ) ;
goto error_unregister ;
}
2018-05-20 12:26:17 +03:00
idle = 0 ; /* polling delay is not needed */
}
2013-01-31 13:04:48 +04:00
2018-05-20 12:26:17 +03:00
ret = devm_request_irq ( dev , irq - > start , rcar_thermal_irq ,
IRQF_SHARED , dev_name ( dev ) , common ) ;
if ( ret ) {
dev_err ( dev , " irq request failed \n " ) ;
goto error_unregister ;
}
/* update ENR bits */
if ( chip - > irq_per_ch )
enr_bits | = 1 < < i ;
2012-07-21 04:53:48 +04:00
}
2013-01-31 13:03:33 +04:00
for ( i = 0 ; ; i + + ) {
res = platform_get_resource ( pdev , IORESOURCE_MEM , mres + + ) ;
if ( ! res )
break ;
priv = devm_kzalloc ( dev , sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv ) {
2013-03-26 10:08:10 +04:00
ret = - ENOMEM ;
goto error_unregister ;
2013-01-31 13:03:33 +04:00
}
2013-03-04 10:45:33 +04:00
priv - > base = devm_ioremap_resource ( dev , res ) ;
2013-03-26 10:08:10 +04:00
if ( IS_ERR ( priv - > base ) ) {
ret = PTR_ERR ( priv - > base ) ;
goto error_unregister ;
}
2013-01-31 13:03:33 +04:00
priv - > common = common ;
2013-01-31 13:04:48 +04:00
priv - > id = i ;
2018-05-20 12:26:17 +03:00
priv - > chip = chip ;
2013-01-31 13:03:33 +04:00
mutex_init ( & priv - > lock ) ;
INIT_LIST_HEAD ( & priv - > list ) ;
2013-01-31 13:04:48 +04:00
INIT_DELAYED_WORK ( & priv - > work , rcar_thermal_work ) ;
2015-12-15 04:17:40 +03:00
ret = rcar_thermal_update_temp ( priv ) ;
if ( ret < 0 )
goto error_unregister ;
2013-01-31 13:03:33 +04:00
2018-05-20 12:26:17 +03:00
if ( chip - > use_of_thermal )
2016-03-10 00:09:43 +03:00
priv - > zone = devm_thermal_zone_of_sensor_register (
2016-01-28 05:45:08 +03:00
dev , i , priv ,
& rcar_thermal_zone_of_ops ) ;
2020-06-29 15:29:22 +03:00
else {
2016-01-28 05:45:08 +03:00
priv - > zone = thermal_zone_device_register (
" rcar_thermal " ,
2013-01-31 13:03:33 +04:00
1 , 0 , priv ,
& rcar_thermal_zone_ops , NULL , 0 ,
2013-01-31 13:04:48 +04:00
idle ) ;
2020-06-29 15:29:22 +03:00
ret = thermal_zone_device_enable ( priv - > zone ) ;
if ( ret ) {
thermal_zone_device_unregister ( priv - > zone ) ;
priv - > zone = ERR_PTR ( ret ) ;
}
}
2013-01-31 13:03:33 +04:00
if ( IS_ERR ( priv - > zone ) ) {
dev_err ( dev , " can't register thermal zone \n " ) ;
2013-03-04 20:52:47 +04:00
ret = PTR_ERR ( priv - > zone ) ;
2016-04-21 13:24:55 +03:00
priv - > zone = NULL ;
2013-01-31 13:03:33 +04:00
goto error_unregister ;
}
2018-05-20 12:26:17 +03:00
if ( chip - > use_of_thermal ) {
2016-07-19 13:01:37 +03:00
/*
* thermal_zone doesn ' t enable hwmon as default ,
* but , enable it here to keep compatible
*/
priv - > zone - > tzp - > no_hwmon = false ;
ret = thermal_add_hwmon_sysfs ( priv - > zone ) ;
if ( ret )
goto error_unregister ;
}
2015-12-15 04:17:56 +03:00
rcar_thermal_irq_enable ( priv ) ;
2013-03-26 10:08:10 +04:00
list_move_tail ( & priv - > list , & common - > head ) ;
2015-01-07 04:13:10 +03:00
/* update ENR bits */
2018-05-20 12:26:17 +03:00
if ( ! chip - > irq_per_ch )
enr_bits | = 3 < < ( i * 8 ) ;
2012-07-21 04:53:48 +04:00
}
2018-07-24 14:14:13 +03:00
if ( common - > base & & enr_bits )
2015-01-07 04:13:10 +03:00
rcar_thermal_common_write ( common , ENR , enr_bits ) ;
2013-05-15 03:00:32 +04:00
dev_info ( dev , " %d sensor probed \n " , i ) ;
2012-07-21 04:53:48 +04:00
return 0 ;
2013-01-31 13:03:33 +04:00
error_unregister :
2015-11-10 05:12:06 +03:00
rcar_thermal_remove ( pdev ) ;
2013-03-26 10:08:52 +04:00
2013-03-04 20:52:47 +04:00
return ret ;
2012-07-21 04:53:48 +04:00
}
2018-05-20 12:26:17 +03:00
# ifdef CONFIG_PM_SLEEP
static int rcar_thermal_suspend ( struct device * dev )
{
struct rcar_thermal_common * common = dev_get_drvdata ( dev ) ;
struct rcar_thermal_priv * priv = list_first_entry ( & common - > head ,
typeof ( * priv ) , list ) ;
if ( priv - > chip - > needs_suspend_resume ) {
rcar_thermal_common_write ( common , ENR , 0 ) ;
rcar_thermal_irq_disable ( priv ) ;
rcar_thermal_bset ( priv , THSCR , CPCTL , 0 ) ;
}
return 0 ;
}
static int rcar_thermal_resume ( struct device * dev )
{
struct rcar_thermal_common * common = dev_get_drvdata ( dev ) ;
struct rcar_thermal_priv * priv = list_first_entry ( & common - > head ,
typeof ( * priv ) , list ) ;
int ret ;
if ( priv - > chip - > needs_suspend_resume ) {
ret = rcar_thermal_update_temp ( priv ) ;
if ( ret < 0 )
return ret ;
rcar_thermal_irq_enable ( priv ) ;
rcar_thermal_common_write ( common , ENR , 0x03 ) ;
}
return 0 ;
}
# endif
static SIMPLE_DEV_PM_OPS ( rcar_thermal_pm_ops , rcar_thermal_suspend ,
rcar_thermal_resume ) ;
2012-07-21 04:53:48 +04:00
static struct platform_driver rcar_thermal_driver = {
. driver = {
. name = " rcar_thermal " ,
2018-05-20 12:26:17 +03:00
. pm = & rcar_thermal_pm_ops ,
2013-01-31 13:05:26 +04:00
. of_match_table = rcar_thermal_dt_ids ,
2012-07-21 04:53:48 +04:00
} ,
. probe = rcar_thermal_probe ,
. remove = rcar_thermal_remove ,
} ;
module_platform_driver ( rcar_thermal_driver ) ;
2018-07-30 10:56:06 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;
2012-07-21 04:53:48 +04:00
MODULE_DESCRIPTION ( " R-Car THS/TSC thermal sensor driver " ) ;
MODULE_AUTHOR ( " Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> " ) ;