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 >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; version 2 of the License .
*
* This program is distributed in the hope that 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 .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA .
*/
# 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>
# 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>
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
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 ;
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 ;
int ctemp ;
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)
# ifdef DEBUG
# define rcar_force_update_temp(priv) 1
# else
# define rcar_force_update_temp(priv) 0
# endif
2012-11-26 06:32:06 +04:00
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 ) ;
int i ;
int ctemp , old , new ;
2013-02-22 17:22:39 +04:00
int ret = - EINVAL ;
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 ) ;
ctemp = 0 ;
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
*/
udelay ( 300 ) ;
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
}
2013-01-31 13:03:11 +04:00
if ( ! ctemp ) {
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 ) ) {
rcar_thermal_write ( priv , FILONOFF , 0 ) ;
/* enable Rising/Falling edge interrupt */
rcar_thermal_write ( priv , POSNEG , 0x1 ) ;
rcar_thermal_write ( priv , INTCTRL , ( ( ( ctemp - 0 ) < < 8 ) |
( ( ctemp - 1 ) < < 0 ) ) ) ;
}
dev_dbg ( dev , " thermal%d %d -> %d \n " , priv - > id , priv - > ctemp , ctemp ) ;
priv - > ctemp = ctemp ;
2013-02-22 17:22:39 +04:00
ret = 0 ;
err_out_unlock :
2013-01-31 13:03:22 +04:00
mutex_unlock ( & priv - > lock ) ;
2013-02-22 17:22:39 +04:00
return ret ;
2012-07-21 04:53:48 +04:00
}
2013-01-31 13:04:48 +04:00
static int rcar_thermal_get_temp ( struct thermal_zone_device * zone ,
unsigned long * temp )
{
struct rcar_thermal_priv * priv = rcar_zone_to_priv ( zone ) ;
if ( ! rcar_has_irq_support ( priv ) | | rcar_force_update_temp ( priv ) )
rcar_thermal_update_temp ( priv ) ;
mutex_lock ( & priv - > lock ) ;
* temp = MCELSIUS ( ( priv - > ctemp * 5 ) - 65 ) ;
mutex_unlock ( & priv - > lock ) ;
return 0 ;
}
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 ,
int trip , unsigned long * temp )
{
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 ;
}
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 */
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 ;
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
unsigned long cctemp , nctemp ;
2013-01-31 13:04:48 +04:00
priv = container_of ( work , struct rcar_thermal_priv , work . work ) ;
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
rcar_thermal_get_temp ( priv - > zone , & cctemp ) ;
2013-01-31 13:04:48 +04:00
rcar_thermal_update_temp ( priv ) ;
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
rcar_thermal_get_temp ( priv - > zone , & nctemp ) ;
if ( nctemp ! = cctemp )
thermal_zone_device_update ( priv - > zone ) ;
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 ) ;
schedule_delayed_work ( & priv - > work ,
msecs_to_jiffies ( 300 ) ) ;
}
}
return IRQ_HANDLED ;
}
2012-07-21 04:53:48 +04:00
/*
* platform functions
*/
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 ;
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 ;
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 ;
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 ) ;
2013-01-31 13:03:33 +04:00
irq = platform_get_resource ( pdev , IORESOURCE_IRQ , 0 ) ;
if ( irq ) {
2013-01-31 13:04:48 +04:00
int ret ;
2013-01-31 13:03:33 +04:00
/*
* platform has IRQ support .
* Then , drier use common register
*/
2013-01-31 13:04:48 +04:00
ret = devm_request_irq ( dev , irq - > start , rcar_thermal_irq , 0 ,
dev_name ( dev ) , common ) ;
if ( ret ) {
dev_err ( dev , " irq request failed \n " ) ;
return ret ;
}
2013-01-31 13:03:33 +04:00
/*
* rcar_has_irq_support ( ) will be enabled
*/
2013-05-10 12:17:11 +04:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , mres + + ) ;
2013-03-04 10:45:33 +04:00
common - > base = devm_ioremap_resource ( dev , res ) ;
if ( IS_ERR ( common - > base ) )
return PTR_ERR ( common - > base ) ;
2013-01-31 13:04:48 +04:00
/* enable temperature comparation */
rcar_thermal_common_write ( common , ENR , 0x00030303 ) ;
2014-01-07 22:57:16 +04:00
idle = 0 ; /* polling delay is not needed */
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 ;
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 ) ;
rcar_thermal_update_temp ( priv ) ;
2013-01-31 13:03:33 +04:00
priv - > zone = thermal_zone_device_register ( " rcar_thermal " ,
1 , 0 , priv ,
& rcar_thermal_zone_ops , NULL , 0 ,
2013-01-31 13:04:48 +04:00
idle ) ;
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 ) ;
2013-01-31 13:03:33 +04:00
goto error_unregister ;
}
2013-01-31 13:04:48 +04:00
if ( rcar_has_irq_support ( priv ) )
rcar_thermal_irq_enable ( priv ) ;
2013-03-26 10:08:10 +04:00
list_move_tail ( & priv - > list , & common - > head ) ;
2012-07-21 04:53:48 +04:00
}
2013-01-31 13:03:33 +04:00
platform_set_drvdata ( pdev , common ) ;
2012-07-21 04:53:48 +04:00
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 :
2013-03-26 10:08:10 +04:00
rcar_thermal_for_each_priv ( priv , common ) {
2013-01-31 13:03:33 +04:00
thermal_zone_device_unregister ( priv - > zone ) ;
2013-03-26 10:08:10 +04:00
if ( rcar_has_irq_support ( priv ) )
rcar_thermal_irq_disable ( priv ) ;
}
2013-01-31 13:03:33 +04:00
2014-04-14 21:02:55 +04:00
pm_runtime_put ( dev ) ;
2013-03-26 10:08:52 +04:00
pm_runtime_disable ( dev ) ;
2013-03-04 20:52:47 +04:00
return ret ;
2012-07-21 04:53:48 +04:00
}
static int rcar_thermal_remove ( struct platform_device * pdev )
{
2013-01-31 13:03:33 +04:00
struct rcar_thermal_common * common = platform_get_drvdata ( pdev ) ;
2013-03-26 10:08:52 +04:00
struct device * dev = & pdev - > dev ;
2013-01-31 13:03:33 +04:00
struct rcar_thermal_priv * priv ;
2013-03-26 10:08:10 +04:00
rcar_thermal_for_each_priv ( priv , common ) {
2013-01-31 13:03:33 +04:00
thermal_zone_device_unregister ( priv - > zone ) ;
2013-03-26 10:08:10 +04:00
if ( rcar_has_irq_support ( priv ) )
rcar_thermal_irq_disable ( priv ) ;
}
2012-07-21 04:53:48 +04:00
2014-04-14 21:02:55 +04:00
pm_runtime_put ( dev ) ;
2013-03-26 10:08:52 +04:00
pm_runtime_disable ( dev ) ;
2012-07-21 04:53:48 +04:00
return 0 ;
}
2013-02-15 02:26:58 +04:00
static const struct of_device_id rcar_thermal_dt_ids [ ] = {
2013-01-31 13:05:26 +04:00
{ . compatible = " renesas,rcar-thermal " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , rcar_thermal_dt_ids ) ;
2012-07-21 04:53:48 +04:00
static struct platform_driver rcar_thermal_driver = {
. driver = {
. name = " rcar_thermal " ,
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 ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " R-Car THS/TSC thermal sensor driver " ) ;
MODULE_AUTHOR ( " Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> " ) ;