2005-04-17 02:20:36 +04:00
/*
* lm90 . c - Part of lm_sensors , Linux kernel modules for hardware
* monitoring
2014-01-29 23:40:08 +04:00
* Copyright ( C ) 2003 - 2010 Jean Delvare < jdelvare @ suse . de >
2005-04-17 02:20:36 +04:00
*
* Based on the lm83 driver . The LM90 is a sensor chip made by National
* Semiconductor . It reports up to two temperatures ( its own plus up to
* one external one ) with a 0.125 deg resolution ( 1 deg for local
2008-10-17 19:51:10 +04:00
* temperature ) and a 3 - 4 deg accuracy .
2005-04-17 02:20:36 +04:00
*
* This driver also supports the LM89 and LM99 , two other sensor chips
* made by National Semiconductor . Both have an increased remote
* temperature measurement accuracy ( 1 degree ) , and the LM99
* additionally shifts remote temperatures ( measured and limits ) by 16
2008-10-26 19:04:39 +03:00
* degrees , which allows for higher temperatures measurement .
2005-05-04 04:21:25 +04:00
* Note that there is no way to differentiate between both chips .
2008-10-26 19:04:39 +03:00
* When device is auto - detected , the driver will assume an LM99 .
2005-04-17 02:20:36 +04:00
*
* This driver also supports the LM86 , another sensor chip made by
* National Semiconductor . It is exactly similar to the LM90 except it
* has a higher accuracy .
*
* This driver also supports the ADM1032 , a sensor chip made by Analog
* Devices . That chip is similar to the LM90 , with a few differences
2008-10-17 19:51:10 +04:00
* that are not handled by this driver . Among others , it has a higher
* accuracy than the LM90 , much like the LM86 does .
2005-04-17 02:20:36 +04:00
*
* This driver also supports the MAX6657 , MAX6658 and MAX6659 sensor
2008-10-17 19:51:10 +04:00
* chips made by Maxim . These chips are similar to the LM86 .
2005-05-04 04:21:25 +04:00
* Note that there is no easy way to differentiate between the three
2010-10-28 22:31:43 +04:00
* variants . We use the device address to detect MAX6659 , which will result
* in a detection as max6657 if it is on address 0x4c . The extra address
* and features of the MAX6659 are only supported if the chip is configured
* explicitly as max6659 , or if its address is not 0x4c .
* These chips lack the remote temperature offset feature .
2005-04-17 02:20:36 +04:00
*
2009-03-12 15:36:38 +03:00
* This driver also supports the MAX6646 , MAX6647 , MAX6648 , MAX6649 and
* MAX6692 chips made by Maxim . These are again similar to the LM86 ,
* but they use unsigned temperature values and can report temperatures
* from 0 to 145 degrees .
2008-10-17 19:51:11 +04:00
*
2007-06-09 18:11:16 +04:00
* This driver also supports the MAX6680 and MAX6681 , two other sensor
* chips made by Maxim . These are quite similar to the other Maxim
2008-10-17 19:51:10 +04:00
* chips . The MAX6680 and MAX6681 only differ in the pinout so they can
* be treated identically .
2007-06-09 18:11:16 +04:00
*
2010-10-28 22:31:43 +04:00
* This driver also supports the MAX6695 and MAX6696 , two other sensor
* chips made by Maxim . These are also quite similar to other Maxim
* chips , but support three temperature sensors instead of two . MAX6695
* and MAX6696 only differ in the pinout so they can be treated identically .
*
2011-04-29 18:33:35 +04:00
* This driver also supports ADT7461 and ADT7461A from Analog Devices as well as
* NCT1008 from ON Semiconductor . The chips are supported in both compatibility
* and extended mode . They are mostly compatible with LM90 except for a data
* format difference for the temperature value registers .
2005-04-17 02:20:36 +04:00
*
2011-06-06 14:40:45 +04:00
* This driver also supports the SA56004 from Philips . This device is
* pin - compatible with the LM86 , the ED / EDP parts are also address - compatible .
*
2012-03-23 13:02:18 +04:00
* This driver also supports the G781 from GMT . This device is compatible
* with the ADM1032 .
*
2013-11-15 13:40:39 +04:00
* This driver also supports TMP451 from Texas Instruments . This device is
* supported in both compatibility and extended mode . It ' s mostly compatible
* with ADT7461 except for local temperature low byte register and max
* conversion rate .
*
2005-04-17 02:20:36 +04:00
* Since the LM90 was the first chipset supported by this driver , most
* comments will refer to this chipset , but are actually general and
* concern all supported chipsets , unless mentioned otherwise .
*
* 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 ; either version 2 of the License , or
* ( at your option ) any later version .
*
* 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 . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/jiffies.h>
# include <linux/i2c.h>
2005-07-16 05:39:18 +04:00
# include <linux/hwmon.h>
# include <linux/err.h>
2006-01-19 01:19:26 +03:00
# include <linux/mutex.h>
2017-02-24 16:13:04 +03:00
# include <linux/of_device.h>
2006-09-24 23:16:40 +04:00
# include <linux/sysfs.h>
2013-11-15 13:40:39 +04:00
# include <linux/interrupt.h>
2013-11-15 13:40:39 +04:00
# include <linux/regulator/consumer.h>
2005-04-17 02:20:36 +04:00
/*
* Addresses to scan
* Address is fully defined internally and cannot be changed except for
2007-06-09 18:11:16 +04:00
* MAX6659 , MAX6680 and MAX6681 .
2011-04-29 18:33:35 +04:00
* LM86 , LM89 , LM90 , LM99 , ADM1032 , ADM1032 - 1 , ADT7461 , ADT7461A , MAX6649 ,
* MAX6657 , MAX6658 , NCT1008 and W83L771 have address 0x4c .
* ADM1032 - 2 , ADT7461 - 2 , ADT7461A - 2 , LM89 - 1 , LM99 - 1 , MAX6646 , and NCT1008D
* have address 0x4d .
2008-10-17 19:51:11 +04:00
* MAX6647 has address 0x4e .
2010-10-28 22:31:43 +04:00
* MAX6659 can have address 0x4c , 0x4d or 0x4e .
2007-06-09 18:11:16 +04:00
* MAX6680 and MAX6681 can have address 0x18 , 0x19 , 0x1a , 0x29 , 0x2a , 0x2b ,
* 0x4c , 0x4d or 0x4e .
2011-06-06 14:40:45 +04:00
* SA56004 can have address 0x48 through 0x4F .
2005-04-17 02:20:36 +04:00
*/
2008-02-18 06:28:03 +03:00
static const unsigned short normal_i2c [ ] = {
2011-06-06 14:40:45 +04:00
0x18 , 0x19 , 0x1a , 0x29 , 0x2a , 0x2b , 0x48 , 0x49 , 0x4a , 0x4b , 0x4c ,
0x4d , 0x4e , 0x4f , I2C_CLIENT_END } ;
2005-04-17 02:20:36 +04:00
2010-10-28 22:31:43 +04:00
enum chips { lm90 , adm1032 , lm99 , lm86 , max6657 , max6659 , adt7461 , max6680 ,
2013-11-15 13:40:39 +04:00
max6646 , w83l771 , max6696 , sa56004 , g781 , tmp451 } ;
2005-04-17 02:20:36 +04:00
/*
* The LM90 registers
*/
# define LM90_REG_R_MAN_ID 0xFE
# define LM90_REG_R_CHIP_ID 0xFF
# define LM90_REG_R_CONFIG1 0x03
# define LM90_REG_W_CONFIG1 0x09
# define LM90_REG_R_CONFIG2 0xBF
# define LM90_REG_W_CONFIG2 0xBF
# define LM90_REG_R_CONVRATE 0x04
# define LM90_REG_W_CONVRATE 0x0A
# define LM90_REG_R_STATUS 0x02
# define LM90_REG_R_LOCAL_TEMP 0x00
# define LM90_REG_R_LOCAL_HIGH 0x05
# define LM90_REG_W_LOCAL_HIGH 0x0B
# define LM90_REG_R_LOCAL_LOW 0x06
# define LM90_REG_W_LOCAL_LOW 0x0C
# define LM90_REG_R_LOCAL_CRIT 0x20
# define LM90_REG_W_LOCAL_CRIT 0x20
# define LM90_REG_R_REMOTE_TEMPH 0x01
# define LM90_REG_R_REMOTE_TEMPL 0x10
# define LM90_REG_R_REMOTE_OFFSH 0x11
# define LM90_REG_W_REMOTE_OFFSH 0x11
# define LM90_REG_R_REMOTE_OFFSL 0x12
# define LM90_REG_W_REMOTE_OFFSL 0x12
# define LM90_REG_R_REMOTE_HIGHH 0x07
# define LM90_REG_W_REMOTE_HIGHH 0x0D
# define LM90_REG_R_REMOTE_HIGHL 0x13
# define LM90_REG_W_REMOTE_HIGHL 0x13
# define LM90_REG_R_REMOTE_LOWH 0x08
# define LM90_REG_W_REMOTE_LOWH 0x0E
# define LM90_REG_R_REMOTE_LOWL 0x14
# define LM90_REG_W_REMOTE_LOWL 0x14
# define LM90_REG_R_REMOTE_CRIT 0x19
# define LM90_REG_W_REMOTE_CRIT 0x19
# define LM90_REG_R_TCRIT_HYST 0x21
# define LM90_REG_W_TCRIT_HYST 0x21
2010-10-28 22:31:43 +04:00
/* MAX6646/6647/6649/6657/6658/6659/6695/6696 registers */
2008-10-17 19:51:09 +04:00
# define MAX6657_REG_R_LOCAL_TEMPL 0x11
2010-10-28 22:31:43 +04:00
# define MAX6696_REG_R_STATUS2 0x12
2010-10-28 22:31:43 +04:00
# define MAX6659_REG_R_REMOTE_EMERG 0x16
# define MAX6659_REG_W_REMOTE_EMERG 0x16
# define MAX6659_REG_R_LOCAL_EMERG 0x17
# define MAX6659_REG_W_LOCAL_EMERG 0x17
2008-10-17 19:51:09 +04:00
2011-06-06 14:40:45 +04:00
/* SA56004 registers */
# define SA56004_REG_R_LOCAL_TEMPL 0x22
2010-10-28 22:31:44 +04:00
# define LM90_MAX_CONVRATE_MS 16000 /* Maximum conversion rate in ms */
2013-11-15 13:40:39 +04:00
/* TMP451 registers */
# define TMP451_REG_R_LOCAL_TEMPL 0x15
2008-10-17 19:51:10 +04:00
/*
* Device flags
*/
2010-10-28 22:31:43 +04:00
# define LM90_FLAG_ADT7461_EXT (1 << 0) /* ADT7461 extended mode */
/* Device features */
# define LM90_HAVE_OFFSET (1 << 1) /* temperature offset register */
# define LM90_HAVE_REM_LIMIT_EXT (1 << 3) /* extended remote limit */
2010-10-28 22:31:43 +04:00
# define LM90_HAVE_EMERGENCY (1 << 4) /* 3rd upper (emergency) limit */
2010-10-28 22:31:43 +04:00
# define LM90_HAVE_EMERGENCY_ALARM (1 << 5) /* emergency alarm */
# define LM90_HAVE_TEMP3 (1 << 6) /* 3rd temperature sensor */
2010-10-28 22:31:44 +04:00
# define LM90_HAVE_BROKEN_ALERT (1 << 7) /* Broken alert */
2008-10-17 19:51:10 +04:00
2013-11-15 13:40:38 +04:00
/* LM90 status */
# define LM90_STATUS_LTHRM (1 << 0) /* local THERM limit tripped */
# define LM90_STATUS_RTHRM (1 << 1) /* remote THERM limit tripped */
# define LM90_STATUS_ROPEN (1 << 2) /* remote is an open circuit */
# define LM90_STATUS_RLOW (1 << 3) /* remote low temp limit tripped */
# define LM90_STATUS_RHIGH (1 << 4) /* remote high temp limit tripped */
# define LM90_STATUS_LLOW (1 << 5) /* local low temp limit tripped */
# define LM90_STATUS_LHIGH (1 << 6) /* local high temp limit tripped */
# define MAX6696_STATUS2_R2THRM (1 << 1) /* remote2 THERM limit tripped */
# define MAX6696_STATUS2_R2OPEN (1 << 2) /* remote2 is an open circuit */
# define MAX6696_STATUS2_R2LOW (1 << 3) /* remote2 low temp limit tripped */
# define MAX6696_STATUS2_R2HIGH (1 << 4) /* remote2 high temp limit tripped */
# define MAX6696_STATUS2_ROT2 (1 << 5) /* remote emergency limit tripped */
# define MAX6696_STATUS2_R2OT2 (1 << 6) /* remote2 emergency limit tripped */
# define MAX6696_STATUS2_LOT2 (1 << 7) /* local emergency limit tripped */
2005-04-17 02:20:36 +04:00
/*
* Driver data ( common to all clients )
*/
2008-07-16 21:30:15 +04:00
static const struct i2c_device_id lm90_id [ ] = {
{ " adm1032 " , adm1032 } ,
{ " adt7461 " , adt7461 } ,
2011-04-29 18:33:35 +04:00
{ " adt7461a " , adt7461 } ,
2012-03-23 13:02:18 +04:00
{ " g781 " , g781 } ,
2008-07-16 21:30:15 +04:00
{ " lm90 " , lm90 } ,
{ " lm86 " , lm86 } ,
2008-10-26 19:04:39 +03:00
{ " lm89 " , lm86 } ,
{ " lm99 " , lm99 } ,
2008-10-17 19:51:11 +04:00
{ " max6646 " , max6646 } ,
{ " max6647 " , max6646 } ,
{ " max6649 " , max6646 } ,
2008-07-16 21:30:15 +04:00
{ " max6657 " , max6657 } ,
{ " max6658 " , max6657 } ,
2010-10-28 22:31:43 +04:00
{ " max6659 " , max6659 } ,
2008-07-16 21:30:15 +04:00
{ " max6680 " , max6680 } ,
{ " max6681 " , max6680 } ,
2010-10-28 22:31:43 +04:00
{ " max6695 " , max6696 } ,
{ " max6696 " , max6696 } ,
2011-04-29 18:33:35 +04:00
{ " nct1008 " , adt7461 } ,
2010-03-06 00:17:13 +03:00
{ " w83l771 " , w83l771 } ,
2011-06-06 14:40:45 +04:00
{ " sa56004 " , sa56004 } ,
2013-11-15 13:40:39 +04:00
{ " tmp451 " , tmp451 } ,
2008-07-16 21:30:15 +04:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , lm90_id ) ;
2017-02-24 16:13:04 +03:00
static const struct of_device_id lm90_of_match [ ] = {
{
. compatible = " adi,adm1032 " ,
. data = ( void * ) adm1032
} ,
{
. compatible = " adi,adt7461 " ,
. data = ( void * ) adt7461
} ,
{
. compatible = " adi,adt7461a " ,
. data = ( void * ) adt7461
} ,
{
. compatible = " gmt,g781 " ,
. data = ( void * ) g781
} ,
{
. compatible = " national,lm90 " ,
. data = ( void * ) lm90
} ,
{
. compatible = " national,lm86 " ,
. data = ( void * ) lm86
} ,
{
. compatible = " national,lm89 " ,
. data = ( void * ) lm86
} ,
{
. compatible = " national,lm99 " ,
. data = ( void * ) lm99
} ,
{
. compatible = " dallas,max6646 " ,
. data = ( void * ) max6646
} ,
{
. compatible = " dallas,max6647 " ,
. data = ( void * ) max6646
} ,
{
. compatible = " dallas,max6649 " ,
. data = ( void * ) max6646
} ,
{
. compatible = " dallas,max6657 " ,
. data = ( void * ) max6657
} ,
{
. compatible = " dallas,max6658 " ,
. data = ( void * ) max6657
} ,
{
. compatible = " dallas,max6659 " ,
. data = ( void * ) max6659
} ,
{
. compatible = " dallas,max6680 " ,
. data = ( void * ) max6680
} ,
{
. compatible = " dallas,max6681 " ,
. data = ( void * ) max6680
} ,
{
. compatible = " dallas,max6695 " ,
. data = ( void * ) max6696
} ,
{
. compatible = " dallas,max6696 " ,
. data = ( void * ) max6696
} ,
{
. compatible = " onnn,nct1008 " ,
. data = ( void * ) adt7461
} ,
{
. compatible = " winbond,w83l771 " ,
. data = ( void * ) w83l771
} ,
{
. compatible = " nxp,sa56004 " ,
. data = ( void * ) sa56004
} ,
{
. compatible = " ti,tmp451 " ,
. data = ( void * ) tmp451
} ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , lm90_of_match ) ;
2010-10-28 22:31:43 +04:00
/*
* chip type specific parameters
*/
struct lm90_params {
u32 flags ; /* Capabilities */
u16 alert_alarms ; /* Which alarm bits trigger ALERT# */
/* Upper 8 bits for max6695/96 */
2010-10-28 22:31:44 +04:00
u8 max_convrate ; /* Maximum conversion rate register value */
2011-07-28 10:22:25 +04:00
u8 reg_local_ext ; /* Extended local temp register (optional) */
2010-10-28 22:31:43 +04:00
} ;
static const struct lm90_params lm90_params [ ] = {
[ adm1032 ] = {
2010-10-28 22:31:44 +04:00
. flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
| LM90_HAVE_BROKEN_ALERT ,
2010-10-28 22:31:43 +04:00
. alert_alarms = 0x7c ,
2010-10-28 22:31:44 +04:00
. max_convrate = 10 ,
2010-10-28 22:31:43 +04:00
} ,
[ adt7461 ] = {
2010-10-28 22:31:44 +04:00
. flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
| LM90_HAVE_BROKEN_ALERT ,
2010-10-28 22:31:43 +04:00
. alert_alarms = 0x7c ,
2010-10-28 22:31:44 +04:00
. max_convrate = 10 ,
2010-10-28 22:31:43 +04:00
} ,
2012-03-23 13:02:18 +04:00
[ g781 ] = {
. flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
| LM90_HAVE_BROKEN_ALERT ,
. alert_alarms = 0x7c ,
. max_convrate = 8 ,
} ,
2010-10-28 22:31:43 +04:00
[ lm86 ] = {
. flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT ,
. alert_alarms = 0x7b ,
2010-10-28 22:31:44 +04:00
. max_convrate = 9 ,
2010-10-28 22:31:43 +04:00
} ,
[ lm90 ] = {
. flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT ,
. alert_alarms = 0x7b ,
2010-10-28 22:31:44 +04:00
. max_convrate = 9 ,
2010-10-28 22:31:43 +04:00
} ,
[ lm99 ] = {
. flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT ,
. alert_alarms = 0x7b ,
2010-10-28 22:31:44 +04:00
. max_convrate = 9 ,
2010-10-28 22:31:43 +04:00
} ,
[ max6646 ] = {
. alert_alarms = 0x7c ,
2010-10-28 22:31:44 +04:00
. max_convrate = 6 ,
2011-06-06 14:40:45 +04:00
. reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL ,
2010-10-28 22:31:43 +04:00
} ,
[ max6657 ] = {
. alert_alarms = 0x7c ,
2010-10-28 22:31:44 +04:00
. max_convrate = 8 ,
2011-06-06 14:40:45 +04:00
. reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL ,
2010-10-28 22:31:43 +04:00
} ,
[ max6659 ] = {
2011-07-28 10:22:25 +04:00
. flags = LM90_HAVE_EMERGENCY ,
2010-10-28 22:31:43 +04:00
. alert_alarms = 0x7c ,
2010-10-28 22:31:44 +04:00
. max_convrate = 8 ,
2011-06-06 14:40:45 +04:00
. reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL ,
2010-10-28 22:31:43 +04:00
} ,
[ max6680 ] = {
. flags = LM90_HAVE_OFFSET ,
. alert_alarms = 0x7c ,
2010-10-28 22:31:44 +04:00
. max_convrate = 7 ,
2010-10-28 22:31:43 +04:00
} ,
[ max6696 ] = {
2011-07-28 10:22:25 +04:00
. flags = LM90_HAVE_EMERGENCY
2010-10-28 22:31:43 +04:00
| LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3 ,
2013-11-15 13:40:38 +04:00
. alert_alarms = 0x1c7c ,
2010-10-28 22:31:44 +04:00
. max_convrate = 6 ,
2011-06-06 14:40:45 +04:00
. reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL ,
2010-10-28 22:31:43 +04:00
} ,
[ w83l771 ] = {
. flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT ,
. alert_alarms = 0x7c ,
2010-10-28 22:31:44 +04:00
. max_convrate = 8 ,
2010-10-28 22:31:43 +04:00
} ,
2011-06-06 14:40:45 +04:00
[ sa56004 ] = {
2011-07-28 10:22:25 +04:00
. flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT ,
2011-06-06 14:40:45 +04:00
. alert_alarms = 0x7b ,
. max_convrate = 9 ,
. reg_local_ext = SA56004_REG_R_LOCAL_TEMPL ,
} ,
2013-11-15 13:40:39 +04:00
[ tmp451 ] = {
. flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
| LM90_HAVE_BROKEN_ALERT ,
. alert_alarms = 0x7c ,
. max_convrate = 9 ,
. reg_local_ext = TMP451_REG_R_LOCAL_TEMPL ,
2016-06-19 05:56:08 +03:00
} ,
2010-10-28 22:31:43 +04:00
} ;
2013-11-15 13:40:39 +04:00
/*
* TEMP8 register index
*/
enum lm90_temp8_reg_index {
LOCAL_LOW = 0 ,
LOCAL_HIGH ,
LOCAL_CRIT ,
REMOTE_CRIT ,
LOCAL_EMERG , /* max6659 and max6695/96 */
REMOTE_EMERG , /* max6659 and max6695/96 */
REMOTE2_CRIT , /* max6695/96 only */
REMOTE2_EMERG , /* max6695/96 only */
TEMP8_REG_NUM
} ;
/*
* TEMP11 register index
*/
enum lm90_temp11_reg_index {
REMOTE_TEMP = 0 ,
REMOTE_LOW ,
REMOTE_HIGH ,
REMOTE_OFFSET , /* except max6646, max6657/58/59, and max6695/96 */
LOCAL_TEMP ,
REMOTE2_TEMP , /* max6695/96 only */
REMOTE2_LOW , /* max6695/96 only */
REMOTE2_HIGH , /* max6695/96 only */
TEMP11_REG_NUM
} ;
2005-04-17 02:20:36 +04:00
/*
* Client data ( each client gets its own )
*/
struct lm90_data {
2014-04-04 20:01:35 +04:00
struct i2c_client * client ;
2016-06-19 05:56:08 +03:00
u32 channel_config [ 4 ] ;
struct hwmon_channel_info temp_info ;
const struct hwmon_channel_info * info [ 3 ] ;
struct hwmon_chip_info chip ;
2006-01-19 01:19:26 +03:00
struct mutex update_lock ;
2016-06-19 01:39:08 +03:00
bool valid ; /* true if register values are valid */
2005-04-17 02:20:36 +04:00
unsigned long last_updated ; /* in jiffies */
int kind ;
2010-10-28 22:31:43 +04:00
u32 flags ;
2005-04-17 02:20:36 +04:00
2016-06-05 10:35:43 +03:00
unsigned int update_interval ; /* in milliseconds */
2010-10-28 22:31:44 +04:00
2010-03-06 00:17:14 +03:00
u8 config_orig ; /* Original configuration register value */
2010-10-28 22:31:44 +04:00
u8 convrate_orig ; /* Original conversion rate register value */
2010-10-28 22:31:43 +04:00
u16 alert_alarms ; /* Which alarm bits trigger ALERT# */
/* Upper 8 bits for max6695/96 */
2010-10-28 22:31:44 +04:00
u8 max_convrate ; /* Maximum conversion rate */
2011-06-06 14:40:45 +04:00
u8 reg_local_ext ; /* local extension register offset */
2010-03-06 00:17:14 +03:00
2005-04-17 02:20:36 +04:00
/* registers values */
2013-11-15 13:40:39 +04:00
s8 temp8 [ TEMP8_REG_NUM ] ;
s16 temp11 [ TEMP11_REG_NUM ] ;
2005-04-17 02:20:36 +04:00
u8 temp_hyst ;
2010-10-28 22:31:43 +04:00
u16 alarms ; /* bitvector (upper 8 bits for max6695/96) */
2005-04-17 02:20:36 +04:00
} ;
2010-10-28 22:31:43 +04:00
/*
* Support functions
*/
/*
* The ADM1032 supports PEC but not on write byte transactions , so we need
* to explicitly ask for a transaction without PEC .
*/
static inline s32 adm1032_write_byte ( struct i2c_client * client , u8 value )
{
return i2c_smbus_xfer ( client - > adapter , client - > addr ,
client - > flags & ~ I2C_CLIENT_PEC ,
I2C_SMBUS_WRITE , value , I2C_SMBUS_BYTE , NULL ) ;
}
/*
* It is assumed that client - > update_lock is held ( unless we are in
* detection or initialization steps ) . This matters when PEC is enabled ,
* because we don ' t want the address pointer to change between the write
* byte and the read byte transactions .
*/
2016-06-13 16:57:37 +03:00
static int lm90_read_reg ( struct i2c_client * client , u8 reg )
2010-10-28 22:31:43 +04:00
{
int err ;
if ( client - > flags & I2C_CLIENT_PEC ) {
err = adm1032_write_byte ( client , reg ) ;
if ( err > = 0 )
err = i2c_smbus_read_byte ( client ) ;
} else
err = i2c_smbus_read_byte_data ( client , reg ) ;
2016-06-13 16:57:37 +03:00
return err ;
2010-10-28 22:31:43 +04:00
}
2016-06-13 16:57:37 +03:00
static int lm90_read16 ( struct i2c_client * client , u8 regh , u8 regl )
2010-10-28 22:31:43 +04:00
{
2016-06-13 16:57:37 +03:00
int oldh , newh , l ;
2010-10-28 22:31:43 +04:00
/*
* There is a trick here . We have to read two registers to have the
* sensor temperature , but we have to beware a conversion could occur
2011-03-31 05:57:33 +04:00
* between the readings . The datasheet says we should either use
2010-10-28 22:31:43 +04:00
* the one - shot conversion register , which we don ' t want to do
* ( disables hardware monitoring ) or monitor the busy bit , which is
* impossible ( we can ' t read the values and monitor that bit at the
* exact same time ) . So the solution used here is to read the high
* byte once , then the low byte , then the high byte again . If the new
* high byte matches the old one , then we have a valid reading . Else
* we have to read the low byte again , and now we believe we have a
* correct reading .
*/
2016-06-13 16:57:37 +03:00
oldh = lm90_read_reg ( client , regh ) ;
if ( oldh < 0 )
return oldh ;
l = lm90_read_reg ( client , regl ) ;
if ( l < 0 )
return l ;
newh = lm90_read_reg ( client , regh ) ;
if ( newh < 0 )
return newh ;
2010-10-28 22:31:43 +04:00
if ( oldh ! = newh ) {
2016-06-13 16:57:37 +03:00
l = lm90_read_reg ( client , regl ) ;
if ( l < 0 )
return l ;
2010-10-28 22:31:43 +04:00
}
2016-06-13 16:57:37 +03:00
return ( newh < < 8 ) | l ;
2010-10-28 22:31:43 +04:00
}
/*
* client - > update_lock must be held when calling this function ( unless we are
* in detection or initialization steps ) , and while a remote channel other
* than channel 0 is selected . Also , calling code must make sure to re - select
* external channel 0 before releasing the lock . This is necessary because
* various registers have different meanings as a result of selecting a
* non - default remote channel .
*/
2016-06-13 16:57:37 +03:00
static inline int lm90_select_remote_channel ( struct i2c_client * client ,
struct lm90_data * data ,
int channel )
2010-10-28 22:31:43 +04:00
{
2016-06-13 16:57:37 +03:00
int config ;
2010-10-28 22:31:43 +04:00
if ( data - > kind = = max6696 ) {
2016-06-13 16:57:37 +03:00
config = lm90_read_reg ( client , LM90_REG_R_CONFIG1 ) ;
if ( config < 0 )
return config ;
2010-10-28 22:31:43 +04:00
config & = ~ 0x08 ;
if ( channel )
config | = 0x08 ;
i2c_smbus_write_byte_data ( client , LM90_REG_W_CONFIG1 ,
config ) ;
}
2016-06-13 16:57:37 +03:00
return 0 ;
2010-10-28 22:31:43 +04:00
}
2010-10-28 22:31:44 +04:00
/*
* Set conversion rate .
* client - > update_lock must be held when calling this function ( unless we are
* in detection or initialization steps ) .
*/
2016-06-19 05:56:08 +03:00
static int lm90_set_convrate ( struct i2c_client * client , struct lm90_data * data ,
unsigned int interval )
2010-10-28 22:31:44 +04:00
{
unsigned int update_interval ;
2016-06-19 05:56:08 +03:00
int i , err ;
2010-10-28 22:31:44 +04:00
/* Shift calculations to avoid rounding errors */
interval < < = 6 ;
/* find the nearest update rate */
for ( i = 0 , update_interval = LM90_MAX_CONVRATE_MS < < 6 ;
i < data - > max_convrate ; i + + , update_interval > > = 1 )
if ( interval > = update_interval * 3 / 4 )
break ;
2016-06-19 05:56:08 +03:00
err = i2c_smbus_write_byte_data ( client , LM90_REG_W_CONVRATE , i ) ;
2010-10-28 22:31:44 +04:00
data - > update_interval = DIV_ROUND_CLOSEST ( update_interval , 64 ) ;
2016-06-19 05:56:08 +03:00
return err ;
2010-10-28 22:31:44 +04:00
}
2016-06-14 05:26:45 +03:00
static int lm90_update_limits ( struct device * dev )
{
struct lm90_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
int val ;
val = lm90_read_reg ( client , LM90_REG_R_LOCAL_CRIT ) ;
if ( val < 0 )
return val ;
data - > temp8 [ LOCAL_CRIT ] = val ;
val = lm90_read_reg ( client , LM90_REG_R_REMOTE_CRIT ) ;
if ( val < 0 )
return val ;
data - > temp8 [ REMOTE_CRIT ] = val ;
val = lm90_read_reg ( client , LM90_REG_R_TCRIT_HYST ) ;
if ( val < 0 )
return val ;
data - > temp_hyst = val ;
2016-07-26 00:47:18 +03:00
val = lm90_read_reg ( client , LM90_REG_R_REMOTE_LOWH ) ;
2016-06-14 05:26:45 +03:00
if ( val < 0 )
return val ;
data - > temp11 [ REMOTE_LOW ] = val < < 8 ;
if ( data - > flags & LM90_HAVE_REM_LIMIT_EXT ) {
val = lm90_read_reg ( client , LM90_REG_R_REMOTE_LOWL ) ;
if ( val < 0 )
return val ;
data - > temp11 [ REMOTE_LOW ] | = val ;
}
val = lm90_read_reg ( client , LM90_REG_R_REMOTE_HIGHH ) ;
if ( val < 0 )
return val ;
data - > temp11 [ REMOTE_HIGH ] = val < < 8 ;
if ( data - > flags & LM90_HAVE_REM_LIMIT_EXT ) {
val = lm90_read_reg ( client , LM90_REG_R_REMOTE_HIGHL ) ;
if ( val < 0 )
return val ;
data - > temp11 [ REMOTE_HIGH ] | = val ;
}
if ( data - > flags & LM90_HAVE_OFFSET ) {
val = lm90_read16 ( client , LM90_REG_R_REMOTE_OFFSH ,
LM90_REG_R_REMOTE_OFFSL ) ;
if ( val < 0 )
return val ;
data - > temp11 [ REMOTE_OFFSET ] = val ;
}
if ( data - > flags & LM90_HAVE_EMERGENCY ) {
val = lm90_read_reg ( client , MAX6659_REG_R_LOCAL_EMERG ) ;
if ( val < 0 )
return val ;
data - > temp8 [ LOCAL_EMERG ] = val ;
val = lm90_read_reg ( client , MAX6659_REG_R_REMOTE_EMERG ) ;
if ( val < 0 )
return val ;
data - > temp8 [ REMOTE_EMERG ] = val ;
}
if ( data - > kind = = max6696 ) {
val = lm90_select_remote_channel ( client , data , 1 ) ;
if ( val < 0 )
return val ;
val = lm90_read_reg ( client , LM90_REG_R_REMOTE_CRIT ) ;
if ( val < 0 )
return val ;
data - > temp8 [ REMOTE2_CRIT ] = val ;
val = lm90_read_reg ( client , MAX6659_REG_R_REMOTE_EMERG ) ;
if ( val < 0 )
return val ;
data - > temp8 [ REMOTE2_EMERG ] = val ;
val = lm90_read_reg ( client , LM90_REG_R_REMOTE_LOWH ) ;
if ( val < 0 )
return val ;
data - > temp11 [ REMOTE2_LOW ] = val < < 8 ;
val = lm90_read_reg ( client , LM90_REG_R_REMOTE_HIGHH ) ;
if ( val < 0 )
return val ;
data - > temp11 [ REMOTE2_HIGH ] = val < < 8 ;
lm90_select_remote_channel ( client , data , 0 ) ;
}
return 0 ;
}
2016-06-19 05:56:08 +03:00
static int lm90_update_device ( struct device * dev )
2010-10-28 22:31:43 +04:00
{
2014-04-04 20:01:35 +04:00
struct lm90_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2010-10-28 22:31:44 +04:00
unsigned long next_update ;
2016-06-19 05:56:08 +03:00
int val ;
2010-10-28 22:31:43 +04:00
2016-06-14 05:26:45 +03:00
if ( ! data - > valid ) {
val = lm90_update_limits ( dev ) ;
if ( val < 0 )
2016-06-19 05:56:08 +03:00
return val ;
2016-06-14 05:26:45 +03:00
}
2013-07-08 16:18:24 +04:00
next_update = data - > last_updated +
msecs_to_jiffies ( data - > update_interval ) ;
2010-10-28 22:31:44 +04:00
if ( time_after ( jiffies , next_update ) | | ! data - > valid ) {
2010-10-28 22:31:43 +04:00
dev_dbg ( & client - > dev , " Updating lm90 data. \n " ) ;
2016-06-14 05:26:45 +03:00
2016-06-19 01:39:08 +03:00
data - > valid = false ;
2016-06-14 05:26:45 +03:00
2016-06-13 16:57:37 +03:00
val = lm90_read_reg ( client , LM90_REG_R_LOCAL_LOW ) ;
if ( val < 0 )
2016-06-19 05:56:08 +03:00
return val ;
2016-06-13 16:57:37 +03:00
data - > temp8 [ LOCAL_LOW ] = val ;
val = lm90_read_reg ( client , LM90_REG_R_LOCAL_HIGH ) ;
if ( val < 0 )
2016-06-19 05:56:08 +03:00
return val ;
2016-06-13 16:57:37 +03:00
data - > temp8 [ LOCAL_HIGH ] = val ;
2011-07-28 10:22:25 +04:00
if ( data - > reg_local_ext ) {
2016-06-13 16:57:37 +03:00
val = lm90_read16 ( client , LM90_REG_R_LOCAL_TEMP ,
data - > reg_local_ext ) ;
if ( val < 0 )
2016-06-19 05:56:08 +03:00
return val ;
2016-06-13 16:57:37 +03:00
data - > temp11 [ LOCAL_TEMP ] = val ;
2010-10-28 22:31:43 +04:00
} else {
2016-06-13 16:57:37 +03:00
val = lm90_read_reg ( client , LM90_REG_R_LOCAL_TEMP ) ;
if ( val < 0 )
2016-06-19 05:56:08 +03:00
return val ;
2016-06-13 16:57:37 +03:00
data - > temp11 [ LOCAL_TEMP ] = val < < 8 ;
2010-10-28 22:31:43 +04:00
}
2016-06-13 16:57:37 +03:00
val = lm90_read16 ( client , LM90_REG_R_REMOTE_TEMPH ,
LM90_REG_R_REMOTE_TEMPL ) ;
if ( val < 0 )
2016-06-19 05:56:08 +03:00
return val ;
2016-06-13 16:57:37 +03:00
data - > temp11 [ REMOTE_TEMP ] = val ;
val = lm90_read_reg ( client , LM90_REG_R_STATUS ) ;
if ( val < 0 )
2016-06-19 05:56:08 +03:00
return val ;
2016-06-13 16:57:37 +03:00
data - > alarms = val ; /* lower 8 bit of alarms */
2010-10-28 22:31:43 +04:00
if ( data - > kind = = max6696 ) {
2016-06-13 16:57:37 +03:00
val = lm90_select_remote_channel ( client , data , 1 ) ;
if ( val < 0 )
2016-06-19 05:56:08 +03:00
return val ;
2016-06-13 16:57:37 +03:00
val = lm90_read16 ( client , LM90_REG_R_REMOTE_TEMPH ,
LM90_REG_R_REMOTE_TEMPL ) ;
2016-06-19 05:56:08 +03:00
if ( val < 0 ) {
lm90_select_remote_channel ( client , data , 0 ) ;
return val ;
}
2016-06-13 16:57:37 +03:00
data - > temp11 [ REMOTE2_TEMP ] = val ;
2010-10-28 22:31:43 +04:00
lm90_select_remote_channel ( client , data , 0 ) ;
2016-06-13 16:57:37 +03:00
val = lm90_read_reg ( client , MAX6696_REG_R_STATUS2 ) ;
if ( val < 0 )
2016-06-19 05:56:08 +03:00
return val ;
2016-06-13 16:57:37 +03:00
data - > alarms | = val < < 8 ;
2010-10-28 22:31:43 +04:00
}
2012-03-23 13:02:18 +04:00
/*
* Re - enable ALERT # output if it was originally enabled and
* relevant alarms are all clear
*/
2016-06-13 16:57:37 +03:00
if ( ! ( data - > config_orig & 0x80 ) & &
! ( data - > alarms & data - > alert_alarms ) ) {
val = lm90_read_reg ( client , LM90_REG_R_CONFIG1 ) ;
if ( val < 0 )
2016-06-19 05:56:08 +03:00
return val ;
2010-10-28 22:31:43 +04:00
2016-06-13 16:57:37 +03:00
if ( val & 0x80 ) {
2010-10-28 22:31:43 +04:00
dev_dbg ( & client - > dev , " Re-enabling ALERT# \n " ) ;
i2c_smbus_write_byte_data ( client ,
LM90_REG_W_CONFIG1 ,
2016-06-13 16:57:37 +03:00
val & ~ 0x80 ) ;
2010-10-28 22:31:43 +04:00
}
}
data - > last_updated = jiffies ;
2016-06-19 01:39:08 +03:00
data - > valid = true ;
2010-10-28 22:31:43 +04:00
}
2016-06-19 05:56:08 +03:00
return 0 ;
2010-10-28 22:31:43 +04:00
}
2008-10-17 19:51:10 +04:00
/*
* Conversions
* For local temperatures and limits , critical limits and the hysteresis
* value , the LM90 uses signed 8 - bit values with LSB = 1 degree Celsius .
* For remote temperatures and limits , it uses signed 11 - bit values with
2008-10-17 19:51:11 +04:00
* LSB = 0.125 degree Celsius , left - justified in 16 - bit registers . Some
* Maxim chips use unsigned values .
2008-10-17 19:51:10 +04:00
*/
2008-10-17 19:51:10 +04:00
static inline int temp_from_s8 ( s8 val )
2008-10-17 19:51:10 +04:00
{
return val * 1000 ;
}
2008-10-17 19:51:11 +04:00
static inline int temp_from_u8 ( u8 val )
{
return val * 1000 ;
}
2008-10-17 19:51:10 +04:00
static inline int temp_from_s16 ( s16 val )
2008-10-17 19:51:10 +04:00
{
return val / 32 * 125 ;
}
2008-10-17 19:51:11 +04:00
static inline int temp_from_u16 ( u16 val )
{
return val / 32 * 125 ;
}
2008-10-17 19:51:10 +04:00
static s8 temp_to_s8 ( long val )
2008-10-17 19:51:10 +04:00
{
if ( val < = - 128000 )
return - 128 ;
if ( val > = 127000 )
return 127 ;
if ( val < 0 )
return ( val - 500 ) / 1000 ;
return ( val + 500 ) / 1000 ;
}
2008-10-17 19:51:11 +04:00
static u8 temp_to_u8 ( long val )
{
if ( val < = 0 )
return 0 ;
if ( val > = 255000 )
return 255 ;
return ( val + 500 ) / 1000 ;
}
2008-10-17 19:51:10 +04:00
static s16 temp_to_s16 ( long val )
2008-10-17 19:51:10 +04:00
{
if ( val < = - 128000 )
return 0x8000 ;
if ( val > = 127875 )
return 0x7FE0 ;
if ( val < 0 )
return ( val - 62 ) / 125 * 32 ;
return ( val + 62 ) / 125 * 32 ;
}
static u8 hyst_to_reg ( long val )
{
if ( val < = 0 )
return 0 ;
if ( val > = 30500 )
return 31 ;
return ( val + 500 ) / 1000 ;
}
/*
2008-10-17 19:51:10 +04:00
* ADT7461 in compatibility mode is almost identical to LM90 except that
* attempts to write values that are outside the range 0 < temp < 127 are
* treated as the boundary value .
*
* ADT7461 in " extended mode " operation uses unsigned integers offset by
* 64 ( e . g . , 0 - > - 64 degC ) . The range is restricted to - 64. .191 degC .
2008-10-17 19:51:10 +04:00
*/
2008-10-17 19:51:10 +04:00
static inline int temp_from_u8_adt7461 ( struct lm90_data * data , u8 val )
2008-10-17 19:51:10 +04:00
{
2008-10-17 19:51:10 +04:00
if ( data - > flags & LM90_FLAG_ADT7461_EXT )
return ( val - 64 ) * 1000 ;
2016-06-19 05:58:26 +03:00
return temp_from_s8 ( val ) ;
2008-10-17 19:51:10 +04:00
}
2008-10-17 19:51:10 +04:00
static inline int temp_from_u16_adt7461 ( struct lm90_data * data , u16 val )
2008-10-17 19:51:10 +04:00
{
2008-10-17 19:51:10 +04:00
if ( data - > flags & LM90_FLAG_ADT7461_EXT )
return ( val - 0x4000 ) / 64 * 250 ;
2016-06-19 05:58:26 +03:00
return temp_from_s16 ( val ) ;
2008-10-17 19:51:10 +04:00
}
2008-10-17 19:51:10 +04:00
static u8 temp_to_u8_adt7461 ( struct lm90_data * data , long val )
2008-10-17 19:51:10 +04:00
{
if ( data - > flags & LM90_FLAG_ADT7461_EXT ) {
if ( val < = - 64000 )
return 0 ;
if ( val > = 191000 )
return 0xFF ;
return ( val + 500 + 64000 ) / 1000 ;
}
2016-06-19 05:58:26 +03:00
if ( val < = 0 )
return 0 ;
if ( val > = 127000 )
return 127 ;
return ( val + 500 ) / 1000 ;
2008-10-17 19:51:10 +04:00
}
2008-10-17 19:51:10 +04:00
static u16 temp_to_u16_adt7461 ( struct lm90_data * data , long val )
2008-10-17 19:51:10 +04:00
{
if ( data - > flags & LM90_FLAG_ADT7461_EXT ) {
if ( val < = - 64000 )
return 0 ;
if ( val > = 191750 )
return 0xFFC0 ;
return ( val + 64000 + 125 ) / 250 * 64 ;
}
2016-06-19 05:58:26 +03:00
if ( val < = 0 )
return 0 ;
if ( val > = 127750 )
return 0x7FC0 ;
return ( val + 125 ) / 250 * 64 ;
2008-10-17 19:51:10 +04:00
}
2016-06-19 05:56:08 +03:00
/* pec used for ADM1032 only */
2016-12-22 15:05:22 +03:00
static ssize_t pec_show ( struct device * dev , struct device_attribute * dummy ,
2016-06-19 05:56:08 +03:00
char * buf )
2005-06-05 23:27:28 +04:00
{
2016-06-19 05:56:08 +03:00
struct i2c_client * client = to_i2c_client ( dev ) ;
2008-10-26 19:04:39 +03:00
2016-06-19 05:56:08 +03:00
return sprintf ( buf , " %d \n " , ! ! ( client - > flags & I2C_CLIENT_PEC ) ) ;
2005-06-05 23:27:28 +04:00
}
2016-12-22 15:05:22 +03:00
static ssize_t pec_store ( struct device * dev , struct device_attribute * dummy ,
const char * buf , size_t count )
2005-06-05 23:27:28 +04:00
{
2016-06-19 05:56:08 +03:00
struct i2c_client * client = to_i2c_client ( dev ) ;
2010-10-28 22:31:42 +04:00
long val ;
int err ;
2012-01-04 23:58:52 +04:00
err = kstrtol ( buf , 10 , & val ) ;
2010-10-28 22:31:42 +04:00
if ( err < 0 )
return err ;
2005-06-05 23:27:28 +04:00
2016-06-19 05:56:08 +03:00
switch ( val ) {
case 0 :
client - > flags & = ~ I2C_CLIENT_PEC ;
break ;
case 1 :
client - > flags | = I2C_CLIENT_PEC ;
break ;
default :
return - EINVAL ;
}
2010-10-28 22:31:43 +04:00
2005-06-05 23:27:28 +04:00
return count ;
2005-04-17 02:20:36 +04:00
}
2005-06-05 23:27:28 +04:00
2016-12-22 15:05:22 +03:00
static DEVICE_ATTR_RW ( pec ) ;
2016-06-19 05:56:08 +03:00
static int lm90_get_temp11 ( struct lm90_data * data , int index )
2005-06-05 23:27:28 +04:00
{
2016-06-19 05:56:08 +03:00
s16 temp11 = data - > temp11 [ index ] ;
2008-10-17 19:51:10 +04:00
int temp ;
2013-11-15 13:40:39 +04:00
if ( data - > kind = = adt7461 | | data - > kind = = tmp451 )
2016-06-19 05:56:08 +03:00
temp = temp_from_u16_adt7461 ( data , temp11 ) ;
2008-10-17 19:51:11 +04:00
else if ( data - > kind = = max6646 )
2016-06-19 05:56:08 +03:00
temp = temp_from_u16 ( temp11 ) ;
2008-10-17 19:51:10 +04:00
else
2016-06-19 05:56:08 +03:00
temp = temp_from_s16 ( temp11 ) ;
2008-10-17 19:51:10 +04:00
2008-10-26 19:04:39 +03:00
/* +16 degrees offset for temp2 for the LM99 */
2016-06-19 05:56:08 +03:00
if ( data - > kind = = lm99 & & index < = 2 )
2008-10-26 19:04:39 +03:00
temp + = 16000 ;
2016-06-19 05:56:08 +03:00
return temp ;
2005-04-17 02:20:36 +04:00
}
2005-06-05 23:27:28 +04:00
2016-06-19 05:56:08 +03:00
static int lm90_set_temp11 ( struct lm90_data * data , int index , long val )
2005-06-05 23:27:28 +04:00
{
2016-06-19 05:56:08 +03:00
static struct reg {
2010-10-28 22:31:43 +04:00
u8 high ;
u8 low ;
2016-06-19 05:56:08 +03:00
} reg [ ] = {
[ REMOTE_LOW ] = { LM90_REG_W_REMOTE_LOWH , LM90_REG_W_REMOTE_LOWL } ,
[ REMOTE_HIGH ] = { LM90_REG_W_REMOTE_HIGHH , LM90_REG_W_REMOTE_HIGHL } ,
[ REMOTE_OFFSET ] = { LM90_REG_W_REMOTE_OFFSH , LM90_REG_W_REMOTE_OFFSL } ,
[ REMOTE2_LOW ] = { LM90_REG_W_REMOTE_LOWH , LM90_REG_W_REMOTE_LOWL } ,
[ REMOTE2_HIGH ] = { LM90_REG_W_REMOTE_HIGHH , LM90_REG_W_REMOTE_HIGHL }
2005-06-05 23:27:28 +04:00
} ;
2014-04-04 20:01:35 +04:00
struct i2c_client * client = data - > client ;
2016-06-19 05:56:08 +03:00
struct reg * regp = & reg [ index ] ;
2010-10-28 22:31:42 +04:00
int err ;
2008-10-26 19:04:39 +03:00
/* +16 degrees offset for temp2 for the LM99 */
2010-10-28 22:31:43 +04:00
if ( data - > kind = = lm99 & & index < = 2 )
2008-10-26 19:04:39 +03:00
val - = 16000 ;
2013-11-15 13:40:39 +04:00
if ( data - > kind = = adt7461 | | data - > kind = = tmp451 )
2010-10-28 22:31:43 +04:00
data - > temp11 [ index ] = temp_to_u16_adt7461 ( data , val ) ;
2008-10-17 19:51:11 +04:00
else if ( data - > kind = = max6646 )
2010-10-28 22:31:43 +04:00
data - > temp11 [ index ] = temp_to_u8 ( val ) < < 8 ;
2010-10-28 22:31:43 +04:00
else if ( data - > flags & LM90_HAVE_REM_LIMIT_EXT )
2010-10-28 22:31:43 +04:00
data - > temp11 [ index ] = temp_to_s16 ( val ) ;
2010-10-28 22:31:43 +04:00
else
2010-10-28 22:31:43 +04:00
data - > temp11 [ index ] = temp_to_s8 ( val ) < < 8 ;
2008-10-17 19:51:09 +04:00
2016-06-19 05:56:08 +03:00
lm90_select_remote_channel ( client , data , index > = 3 ) ;
err = i2c_smbus_write_byte_data ( client , regp - > high ,
2010-10-28 22:31:43 +04:00
data - > temp11 [ index ] > > 8 ) ;
2016-06-19 05:56:08 +03:00
if ( err < 0 )
return err ;
2010-10-28 22:31:43 +04:00
if ( data - > flags & LM90_HAVE_REM_LIMIT_EXT )
2016-06-19 05:56:08 +03:00
err = i2c_smbus_write_byte_data ( client , regp - > low ,
data - > temp11 [ index ] & 0xff ) ;
2010-10-28 22:31:43 +04:00
2016-06-19 05:56:08 +03:00
lm90_select_remote_channel ( client , data , 0 ) ;
return err ;
2005-04-17 02:20:36 +04:00
}
2005-06-05 23:27:28 +04:00
2016-06-19 05:56:08 +03:00
static int lm90_get_temp8 ( struct lm90_data * data , int index )
2005-06-05 23:27:28 +04:00
{
2016-06-19 05:56:08 +03:00
s8 temp8 = data - > temp8 [ index ] ;
2008-10-17 19:51:10 +04:00
int temp ;
2013-11-15 13:40:39 +04:00
if ( data - > kind = = adt7461 | | data - > kind = = tmp451 )
2016-06-19 05:56:08 +03:00
temp = temp_from_u8_adt7461 ( data , temp8 ) ;
2008-10-26 19:04:39 +03:00
else if ( data - > kind = = max6646 )
2016-06-19 05:56:08 +03:00
temp = temp_from_u8 ( temp8 ) ;
2008-10-17 19:51:10 +04:00
else
2016-06-19 05:56:08 +03:00
temp = temp_from_s8 ( temp8 ) ;
2008-10-17 19:51:10 +04:00
2008-10-26 19:04:39 +03:00
/* +16 degrees offset for temp2 for the LM99 */
2016-06-19 05:56:08 +03:00
if ( data - > kind = = lm99 & & index = = 3 )
2008-10-26 19:04:39 +03:00
temp + = 16000 ;
2016-06-19 05:56:08 +03:00
return temp ;
2005-04-17 02:20:36 +04:00
}
2016-06-19 05:56:08 +03:00
static int lm90_set_temp8 ( struct lm90_data * data , int index , long val )
2005-04-17 02:20:36 +04:00
{
2016-06-19 05:56:08 +03:00
static const u8 reg [ TEMP8_REG_NUM ] = {
LM90_REG_W_LOCAL_LOW ,
LM90_REG_W_LOCAL_HIGH ,
LM90_REG_W_LOCAL_CRIT ,
LM90_REG_W_REMOTE_CRIT ,
MAX6659_REG_W_LOCAL_EMERG ,
MAX6659_REG_W_REMOTE_EMERG ,
LM90_REG_W_REMOTE_CRIT ,
MAX6659_REG_W_REMOTE_EMERG ,
} ;
2014-04-04 20:01:35 +04:00
struct i2c_client * client = data - > client ;
2010-10-28 22:31:42 +04:00
int err ;
2005-04-17 02:20:36 +04:00
2016-06-19 05:56:08 +03:00
/* +16 degrees offset for temp2 for the LM99 */
if ( data - > kind = = lm99 & & index = = 3 )
val - = 16000 ;
2010-10-28 22:31:42 +04:00
2013-11-15 13:40:39 +04:00
if ( data - > kind = = adt7461 | | data - > kind = = tmp451 )
2016-06-19 05:56:08 +03:00
data - > temp8 [ index ] = temp_to_u8_adt7461 ( data , val ) ;
2008-10-26 19:04:39 +03:00
else if ( data - > kind = = max6646 )
2016-06-19 05:56:08 +03:00
data - > temp8 [ index ] = temp_to_u8 ( val ) ;
2008-10-26 19:04:39 +03:00
else
2016-06-19 05:56:08 +03:00
data - > temp8 [ index ] = temp_to_s8 ( val ) ;
2008-10-26 19:04:39 +03:00
2016-06-19 05:56:08 +03:00
lm90_select_remote_channel ( client , data , index > = 6 ) ;
err = i2c_smbus_write_byte_data ( client , reg [ index ] , data - > temp8 [ index ] ) ;
lm90_select_remote_channel ( client , data , 0 ) ;
2016-06-13 16:57:37 +03:00
2016-06-19 05:56:08 +03:00
return err ;
2005-04-17 02:20:36 +04:00
}
2016-06-19 05:56:08 +03:00
static int lm90_get_temphyst ( struct lm90_data * data , int index )
2006-09-24 22:52:15 +04:00
{
2016-06-19 05:56:08 +03:00
int temp ;
2016-06-13 16:57:37 +03:00
2016-06-19 05:56:08 +03:00
if ( data - > kind = = adt7461 | | data - > kind = = tmp451 )
temp = temp_from_u8_adt7461 ( data , data - > temp8 [ index ] ) ;
else if ( data - > kind = = max6646 )
temp = temp_from_u8 ( data - > temp8 [ index ] ) ;
else
temp = temp_from_s8 ( data - > temp8 [ index ] ) ;
2006-09-24 22:52:15 +04:00
2016-06-19 05:56:08 +03:00
/* +16 degrees offset for temp2 for the LM99 */
if ( data - > kind = = lm99 & & index = = 3 )
temp + = 16000 ;
2010-10-28 22:31:44 +04:00
2016-06-19 05:56:08 +03:00
return temp - temp_from_s8 ( data - > temp_hyst ) ;
2010-10-28 22:31:44 +04:00
}
2016-06-19 05:56:08 +03:00
static int lm90_set_temphyst ( struct lm90_data * data , long val )
2010-10-28 22:31:44 +04:00
{
2014-04-04 20:01:35 +04:00
struct i2c_client * client = data - > client ;
2016-06-19 05:56:08 +03:00
int temp ;
2010-10-28 22:31:44 +04:00
int err ;
2016-06-19 05:56:08 +03:00
if ( data - > kind = = adt7461 | | data - > kind = = tmp451 )
temp = temp_from_u8_adt7461 ( data , data - > temp8 [ LOCAL_CRIT ] ) ;
else if ( data - > kind = = max6646 )
temp = temp_from_u8 ( data - > temp8 [ LOCAL_CRIT ] ) ;
else
temp = temp_from_s8 ( data - > temp8 [ LOCAL_CRIT ] ) ;
2010-10-28 22:31:44 +04:00
2016-06-19 05:56:08 +03:00
data - > temp_hyst = hyst_to_reg ( temp - val ) ;
err = i2c_smbus_write_byte_data ( client , LM90_REG_W_TCRIT_HYST ,
data - > temp_hyst ) ;
return err ;
2010-10-28 22:31:44 +04:00
}
2016-06-19 05:56:08 +03:00
static const u8 lm90_temp_index [ 3 ] = {
LOCAL_TEMP , REMOTE_TEMP , REMOTE2_TEMP
2006-09-24 23:16:40 +04:00
} ;
2016-06-19 05:56:08 +03:00
static const u8 lm90_temp_min_index [ 3 ] = {
LOCAL_LOW , REMOTE_LOW , REMOTE2_LOW
2006-09-24 23:16:40 +04:00
} ;
2016-06-19 05:56:08 +03:00
static const u8 lm90_temp_max_index [ 3 ] = {
LOCAL_HIGH , REMOTE_HIGH , REMOTE2_HIGH
2014-04-04 20:01:34 +04:00
} ;
2016-06-19 05:56:08 +03:00
static const u8 lm90_temp_crit_index [ 3 ] = {
LOCAL_CRIT , REMOTE_CRIT , REMOTE2_CRIT
2014-04-04 20:01:34 +04:00
} ;
2016-06-19 05:56:08 +03:00
static const u8 lm90_temp_emerg_index [ 3 ] = {
LOCAL_EMERG , REMOTE_EMERG , REMOTE2_EMERG
2010-10-28 22:31:43 +04:00
} ;
2016-06-19 05:56:08 +03:00
static const u8 lm90_min_alarm_bits [ 3 ] = { 5 , 3 , 11 } ;
2017-01-02 19:53:39 +03:00
static const u8 lm90_max_alarm_bits [ 3 ] = { 6 , 4 , 12 } ;
2016-06-19 05:56:08 +03:00
static const u8 lm90_crit_alarm_bits [ 3 ] = { 0 , 1 , 9 } ;
static const u8 lm90_emergency_alarm_bits [ 3 ] = { 15 , 13 , 14 } ;
static const u8 lm90_fault_bits [ 3 ] = { 0 , 2 , 10 } ;
2010-10-28 22:31:43 +04:00
2016-06-19 05:56:08 +03:00
static int lm90_temp_read ( struct device * dev , u32 attr , int channel , long * val )
{
struct lm90_data * data = dev_get_drvdata ( dev ) ;
int err ;
2010-10-28 22:31:43 +04:00
2016-06-19 05:56:08 +03:00
mutex_lock ( & data - > update_lock ) ;
err = lm90_update_device ( dev ) ;
mutex_unlock ( & data - > update_lock ) ;
if ( err )
return err ;
2010-10-28 22:31:43 +04:00
2016-06-19 05:56:08 +03:00
switch ( attr ) {
case hwmon_temp_input :
* val = lm90_get_temp11 ( data , lm90_temp_index [ channel ] ) ;
break ;
case hwmon_temp_min_alarm :
* val = ( data - > alarms > > lm90_min_alarm_bits [ channel ] ) & 1 ;
break ;
case hwmon_temp_max_alarm :
* val = ( data - > alarms > > lm90_max_alarm_bits [ channel ] ) & 1 ;
break ;
case hwmon_temp_crit_alarm :
* val = ( data - > alarms > > lm90_crit_alarm_bits [ channel ] ) & 1 ;
break ;
case hwmon_temp_emergency_alarm :
* val = ( data - > alarms > > lm90_emergency_alarm_bits [ channel ] ) & 1 ;
break ;
case hwmon_temp_fault :
* val = ( data - > alarms > > lm90_fault_bits [ channel ] ) & 1 ;
break ;
case hwmon_temp_min :
if ( channel = = 0 )
* val = lm90_get_temp8 ( data ,
lm90_temp_min_index [ channel ] ) ;
else
* val = lm90_get_temp11 ( data ,
lm90_temp_min_index [ channel ] ) ;
break ;
case hwmon_temp_max :
if ( channel = = 0 )
* val = lm90_get_temp8 ( data ,
lm90_temp_max_index [ channel ] ) ;
else
* val = lm90_get_temp11 ( data ,
lm90_temp_max_index [ channel ] ) ;
break ;
case hwmon_temp_crit :
* val = lm90_get_temp8 ( data , lm90_temp_crit_index [ channel ] ) ;
break ;
case hwmon_temp_crit_hyst :
* val = lm90_get_temphyst ( data , lm90_temp_crit_index [ channel ] ) ;
break ;
case hwmon_temp_emergency :
* val = lm90_get_temp8 ( data , lm90_temp_emerg_index [ channel ] ) ;
break ;
case hwmon_temp_emergency_hyst :
* val = lm90_get_temphyst ( data , lm90_temp_emerg_index [ channel ] ) ;
break ;
case hwmon_temp_offset :
* val = lm90_get_temp11 ( data , REMOTE_OFFSET ) ;
break ;
default :
return - EOPNOTSUPP ;
}
return 0 ;
}
2010-10-28 22:31:43 +04:00
2016-06-19 05:56:08 +03:00
static int lm90_temp_write ( struct device * dev , u32 attr , int channel , long val )
{
struct lm90_data * data = dev_get_drvdata ( dev ) ;
int err ;
2010-10-28 22:31:43 +04:00
2016-06-19 05:56:08 +03:00
mutex_lock ( & data - > update_lock ) ;
2010-10-28 22:31:43 +04:00
2016-06-19 05:56:08 +03:00
err = lm90_update_device ( dev ) ;
if ( err )
goto error ;
switch ( attr ) {
case hwmon_temp_min :
if ( channel = = 0 )
err = lm90_set_temp8 ( data ,
lm90_temp_min_index [ channel ] ,
val ) ;
else
err = lm90_set_temp11 ( data ,
lm90_temp_min_index [ channel ] ,
val ) ;
break ;
case hwmon_temp_max :
if ( channel = = 0 )
err = lm90_set_temp8 ( data ,
lm90_temp_max_index [ channel ] ,
val ) ;
else
err = lm90_set_temp11 ( data ,
lm90_temp_max_index [ channel ] ,
val ) ;
break ;
case hwmon_temp_crit :
err = lm90_set_temp8 ( data , lm90_temp_crit_index [ channel ] , val ) ;
break ;
case hwmon_temp_crit_hyst :
err = lm90_set_temphyst ( data , val ) ;
break ;
case hwmon_temp_emergency :
err = lm90_set_temp8 ( data , lm90_temp_emerg_index [ channel ] , val ) ;
break ;
case hwmon_temp_offset :
err = lm90_set_temp11 ( data , REMOTE_OFFSET , val ) ;
break ;
default :
err = - EOPNOTSUPP ;
break ;
}
error :
mutex_unlock ( & data - > update_lock ) ;
return err ;
}
static umode_t lm90_temp_is_visible ( const void * data , u32 attr , int channel )
2005-10-26 23:39:40 +04:00
{
2016-06-19 05:56:08 +03:00
switch ( attr ) {
case hwmon_temp_input :
case hwmon_temp_min_alarm :
case hwmon_temp_max_alarm :
case hwmon_temp_crit_alarm :
case hwmon_temp_emergency_alarm :
case hwmon_temp_emergency_hyst :
case hwmon_temp_fault :
return S_IRUGO ;
case hwmon_temp_min :
case hwmon_temp_max :
case hwmon_temp_crit :
case hwmon_temp_emergency :
case hwmon_temp_offset :
return S_IRUGO | S_IWUSR ;
case hwmon_temp_crit_hyst :
if ( channel = = 0 )
return S_IRUGO | S_IWUSR ;
return S_IRUGO ;
default :
return 0 ;
}
2005-10-26 23:39:40 +04:00
}
2016-06-19 05:56:08 +03:00
static int lm90_chip_read ( struct device * dev , u32 attr , int channel , long * val )
2005-10-26 23:39:40 +04:00
{
2016-06-19 05:56:08 +03:00
struct lm90_data * data = dev_get_drvdata ( dev ) ;
2010-10-28 22:31:42 +04:00
int err ;
2016-06-19 05:56:08 +03:00
mutex_lock ( & data - > update_lock ) ;
err = lm90_update_device ( dev ) ;
mutex_unlock ( & data - > update_lock ) ;
if ( err )
2010-10-28 22:31:42 +04:00
return err ;
2005-10-26 23:39:40 +04:00
2016-06-19 05:56:08 +03:00
switch ( attr ) {
case hwmon_chip_update_interval :
* val = data - > update_interval ;
2005-10-26 23:39:40 +04:00
break ;
2016-06-19 05:56:08 +03:00
case hwmon_chip_alarms :
* val = data - > alarms ;
2005-10-26 23:39:40 +04:00
break ;
default :
2016-06-19 05:56:08 +03:00
return - EOPNOTSUPP ;
2005-10-26 23:39:40 +04:00
}
2016-06-19 05:56:08 +03:00
return 0 ;
2005-10-26 23:39:40 +04:00
}
2016-06-19 05:56:08 +03:00
static int lm90_chip_write ( struct device * dev , u32 attr , int channel , long val )
{
struct lm90_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
int err ;
2005-10-26 23:39:40 +04:00
2016-06-19 05:56:08 +03:00
mutex_lock ( & data - > update_lock ) ;
err = lm90_update_device ( dev ) ;
if ( err )
goto error ;
switch ( attr ) {
case hwmon_chip_update_interval :
err = lm90_set_convrate ( client , data ,
clamp_val ( val , 0 , 100000 ) ) ;
break ;
default :
err = - EOPNOTSUPP ;
break ;
}
error :
mutex_unlock ( & data - > update_lock ) ;
return err ;
}
static umode_t lm90_chip_is_visible ( const void * data , u32 attr , int channel )
{
switch ( attr ) {
case hwmon_chip_update_interval :
return S_IRUGO | S_IWUSR ;
case hwmon_chip_alarms :
return S_IRUGO ;
default :
return 0 ;
}
}
static int lm90_read ( struct device * dev , enum hwmon_sensor_types type ,
u32 attr , int channel , long * val )
{
switch ( type ) {
case hwmon_chip :
return lm90_chip_read ( dev , attr , channel , val ) ;
case hwmon_temp :
return lm90_temp_read ( dev , attr , channel , val ) ;
default :
return - EOPNOTSUPP ;
}
}
static int lm90_write ( struct device * dev , enum hwmon_sensor_types type ,
u32 attr , int channel , long val )
{
switch ( type ) {
case hwmon_chip :
return lm90_chip_write ( dev , attr , channel , val ) ;
case hwmon_temp :
return lm90_temp_write ( dev , attr , channel , val ) ;
default :
return - EOPNOTSUPP ;
}
}
static umode_t lm90_is_visible ( const void * data , enum hwmon_sensor_types type ,
u32 attr , int channel )
{
switch ( type ) {
case hwmon_chip :
return lm90_chip_is_visible ( data , attr , channel ) ;
case hwmon_temp :
return lm90_temp_is_visible ( data , attr , channel ) ;
default :
return 0 ;
}
}
2005-04-17 02:20:36 +04:00
2010-10-28 22:31:43 +04:00
/* Return 0 if detection is successful, -ENODEV otherwise */
2011-11-04 15:00:47 +04:00
static int lm90_detect ( struct i2c_client * client ,
2010-10-28 22:31:43 +04:00
struct i2c_board_info * info )
2005-10-26 23:37:52 +04:00
{
2011-11-04 15:00:47 +04:00
struct i2c_adapter * adapter = client - > adapter ;
int address = client - > addr ;
2010-10-28 22:31:43 +04:00
const char * name = NULL ;
2011-11-04 15:00:47 +04:00
int man_id , chip_id , config1 , config2 , convrate ;
2005-10-26 23:37:52 +04:00
2010-10-28 22:31:43 +04:00
if ( ! i2c_check_functionality ( adapter , I2C_FUNC_SMBUS_BYTE_DATA ) )
return - ENODEV ;
2005-04-17 02:20:36 +04:00
2009-12-09 22:35:53 +03:00
/* detection and identification */
2011-11-04 15:00:47 +04:00
man_id = i2c_smbus_read_byte_data ( client , LM90_REG_R_MAN_ID ) ;
chip_id = i2c_smbus_read_byte_data ( client , LM90_REG_R_CHIP_ID ) ;
config1 = i2c_smbus_read_byte_data ( client , LM90_REG_R_CONFIG1 ) ;
convrate = i2c_smbus_read_byte_data ( client , LM90_REG_R_CONVRATE ) ;
if ( man_id < 0 | | chip_id < 0 | | config1 < 0 | | convrate < 0 )
2009-12-09 22:35:53 +03:00
return - ENODEV ;
2011-07-24 22:37:05 +04:00
if ( man_id = = 0x01 | | man_id = = 0x5C | | man_id = = 0x41 ) {
2011-11-04 15:00:47 +04:00
config2 = i2c_smbus_read_byte_data ( client , LM90_REG_R_CONFIG2 ) ;
if ( config2 < 0 )
2008-07-16 21:30:15 +04:00
return - ENODEV ;
2011-07-24 22:37:05 +04:00
} else
2011-11-04 15:00:47 +04:00
config2 = 0 ; /* Make compiler happy */
2009-12-09 22:35:53 +03:00
2011-07-24 22:37:05 +04:00
if ( ( address = = 0x4C | | address = = 0x4D )
& & man_id = = 0x01 ) { /* National Semiconductor */
2011-11-04 15:00:47 +04:00
if ( ( config1 & 0x2A ) = = 0x00
& & ( config2 & 0xF8 ) = = 0x00
& & convrate < = 0x09 ) {
2009-12-09 22:35:53 +03:00
if ( address = = 0x4C
& & ( chip_id & 0xF0 ) = = 0x20 ) { /* LM90 */
name = " lm90 " ;
2007-06-09 18:11:16 +04:00
} else
2009-12-09 22:35:53 +03:00
if ( ( chip_id & 0xF0 ) = = 0x30 ) { /* LM89/LM99 */
name = " lm99 " ;
dev_info ( & adapter - > dev ,
" Assuming LM99 chip at 0x%02x \n " ,
address ) ;
dev_info ( & adapter - > dev ,
" If it is an LM89, instantiate it "
" with the new_device sysfs "
" interface \n " ) ;
2008-10-17 19:51:11 +04:00
} else
2009-12-09 22:35:53 +03:00
if ( address = = 0x4C
& & ( chip_id & 0xF0 ) = = 0x10 ) { /* LM86 */
name = " lm86 " ;
2005-04-17 02:20:36 +04:00
}
}
2009-12-09 22:35:53 +03:00
} else
if ( ( address = = 0x4C | | address = = 0x4D )
& & man_id = = 0x41 ) { /* Analog Devices */
if ( ( chip_id & 0xF0 ) = = 0x40 /* ADM1032 */
2011-11-04 15:00:47 +04:00
& & ( config1 & 0x3F ) = = 0x00
& & convrate < = 0x0A ) {
2009-12-09 22:35:53 +03:00
name = " adm1032 " ;
2012-03-23 13:02:18 +04:00
/*
* The ADM1032 supports PEC , but only if combined
* transactions are not used .
*/
2009-12-09 22:35:53 +03:00
if ( i2c_check_functionality ( adapter ,
I2C_FUNC_SMBUS_BYTE ) )
info - > flags | = I2C_CLIENT_PEC ;
} else
if ( chip_id = = 0x51 /* ADT7461 */
2011-11-04 15:00:47 +04:00
& & ( config1 & 0x1B ) = = 0x00
& & convrate < = 0x0A ) {
2009-12-09 22:35:53 +03:00
name = " adt7461 " ;
2011-04-29 18:33:35 +04:00
} else
if ( chip_id = = 0x57 /* ADT7461A, NCT1008 */
2011-11-04 15:00:47 +04:00
& & ( config1 & 0x1B ) = = 0x00
& & convrate < = 0x0A ) {
2011-04-29 18:33:35 +04:00
name = " adt7461a " ;
2009-12-09 22:35:53 +03:00
}
} else
if ( man_id = = 0x4D ) { /* Maxim */
2011-11-04 15:00:47 +04:00
int emerg , emerg2 , status2 ;
2010-10-28 22:31:43 +04:00
/*
* We read MAX6659_REG_R_REMOTE_EMERG twice , and re - read
* LM90_REG_R_MAN_ID in between . If MAX6659_REG_R_REMOTE_EMERG
* exists , both readings will reflect the same value . Otherwise ,
* the readings will be different .
*/
2011-11-04 15:00:47 +04:00
emerg = i2c_smbus_read_byte_data ( client ,
MAX6659_REG_R_REMOTE_EMERG ) ;
man_id = i2c_smbus_read_byte_data ( client ,
2011-11-04 15:00:46 +04:00
LM90_REG_R_MAN_ID ) ;
2011-11-04 15:00:47 +04:00
emerg2 = i2c_smbus_read_byte_data ( client ,
2011-11-04 15:00:46 +04:00
MAX6659_REG_R_REMOTE_EMERG ) ;
2011-11-04 15:00:47 +04:00
status2 = i2c_smbus_read_byte_data ( client ,
MAX6696_REG_R_STATUS2 ) ;
if ( emerg < 0 | | man_id < 0 | | emerg2 < 0 | | status2 < 0 )
2010-10-28 22:31:43 +04:00
return - ENODEV ;
2009-12-09 22:35:53 +03:00
/*
* The MAX6657 , MAX6658 and MAX6659 do NOT have a chip_id
* register . Reading from that address will return the last
* read value , which in our case is those of the man_id
* register . Likewise , the config1 register seems to lack a
* low nibble , so the value will be those of the previous
* read , so in our case those of the man_id register .
2010-10-28 22:31:43 +04:00
* MAX6659 has a third set of upper temperature limit registers .
* Those registers also return values on MAX6657 and MAX6658 ,
* thus the only way to detect MAX6659 is by its address .
* For this reason it will be mis - detected as MAX6657 if its
* address is 0x4C .
2009-12-09 22:35:53 +03:00
*/
if ( chip_id = = man_id
2010-10-28 22:31:43 +04:00
& & ( address = = 0x4C | | address = = 0x4D | | address = = 0x4E )
2011-11-04 15:00:47 +04:00
& & ( config1 & 0x1F ) = = ( man_id & 0x0F )
& & convrate < = 0x09 ) {
2010-10-28 22:31:43 +04:00
if ( address = = 0x4C )
name = " max6657 " ;
else
name = " max6659 " ;
2009-12-09 22:35:53 +03:00
} else
2010-10-28 22:31:43 +04:00
/*
* Even though MAX6695 and MAX6696 do not have a chip ID
* register , reading it returns 0x01 . Bit 4 of the config1
* register is unused and should return zero when read . Bit 0 of
* the status2 register is unused and should return zero when
* read .
*
* MAX6695 and MAX6696 have an additional set of temperature
* limit registers . We can detect those chips by checking if
* one of those registers exists .
*/
if ( chip_id = = 0x01
2011-11-04 15:00:47 +04:00
& & ( config1 & 0x10 ) = = 0x00
& & ( status2 & 0x01 ) = = 0x00
& & emerg = = emerg2
& & convrate < = 0x07 ) {
2010-10-28 22:31:43 +04:00
name = " max6696 " ;
} else
2009-12-09 22:35:53 +03:00
/*
* The chip_id register of the MAX6680 and MAX6681 holds the
* revision of the chip . The lowest bit of the config1 register
* is unused and should return zero when read , so should the
* second to last bit of config1 ( software reset ) .
*/
if ( chip_id = = 0x01
2011-11-04 15:00:47 +04:00
& & ( config1 & 0x03 ) = = 0x00
& & convrate < = 0x07 ) {
2009-12-09 22:35:53 +03:00
name = " max6680 " ;
} else
/*
* The chip_id register of the MAX6646 / 6647 / 6649 holds the
* revision of the chip . The lowest 6 bits of the config1
* register are unused and should return zero when read .
*/
if ( chip_id = = 0x59
2011-11-04 15:00:47 +04:00
& & ( config1 & 0x3f ) = = 0x00
& & convrate < = 0x07 ) {
2009-12-09 22:35:53 +03:00
name = " max6646 " ;
2005-04-17 02:20:36 +04:00
}
2010-03-06 00:17:13 +03:00
} else
if ( address = = 0x4C
& & man_id = = 0x5C ) { /* Winbond/Nuvoton */
2011-11-04 15:00:47 +04:00
if ( ( config1 & 0x2A ) = = 0x00
& & ( config2 & 0xF8 ) = = 0x00 ) {
2010-10-28 22:31:44 +04:00
if ( chip_id = = 0x01 /* W83L771W/G */
2011-11-04 15:00:47 +04:00
& & convrate < = 0x09 ) {
2010-10-28 22:31:44 +04:00
name = " w83l771 " ;
} else
if ( ( chip_id & 0xFE ) = = 0x10 /* W83L771AWG/ASG */
2011-11-04 15:00:47 +04:00
& & convrate < = 0x08 ) {
2010-10-28 22:31:44 +04:00
name = " w83l771 " ;
}
2010-03-06 00:17:13 +03:00
}
2011-06-06 14:40:45 +04:00
} else
2011-07-24 22:36:15 +04:00
if ( address > = 0x48 & & address < = 0x4F
& & man_id = = 0xA1 ) { /* NXP Semiconductor/Philips */
if ( chip_id = = 0x00
2011-11-04 15:00:47 +04:00
& & ( config1 & 0x2A ) = = 0x00
& & ( config2 & 0xFE ) = = 0x00
& & convrate < = 0x09 ) {
2011-06-06 14:40:45 +04:00
name = " sa56004 " ;
}
2012-03-23 13:02:18 +04:00
} else
if ( ( address = = 0x4C | | address = = 0x4D )
& & man_id = = 0x47 ) { /* GMT */
if ( chip_id = = 0x01 /* G781 */
& & ( config1 & 0x3F ) = = 0x00
& & convrate < = 0x08 )
name = " g781 " ;
2013-11-15 13:40:39 +04:00
} else
if ( address = = 0x4C
& & man_id = = 0x55 ) { /* Texas Instruments */
int local_ext ;
local_ext = i2c_smbus_read_byte_data ( client ,
TMP451_REG_R_LOCAL_TEMPL ) ;
if ( chip_id = = 0x00 /* TMP451 */
& & ( config1 & 0x1B ) = = 0x00
& & convrate < = 0x09
& & ( local_ext & 0x0F ) = = 0x00 )
name = " tmp451 " ;
2005-04-17 02:20:36 +04:00
}
2009-12-09 22:35:53 +03:00
if ( ! name ) { /* identification failed */
dev_dbg ( & adapter - > dev ,
" Unsupported chip at 0x%02x (man_id=0x%02X, "
" chip_id=0x%02X) \n " , address , man_id , chip_id ) ;
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
2009-12-09 22:35:53 +03:00
2008-07-16 21:30:15 +04:00
strlcpy ( info - > type , name , I2C_NAME_SIZE ) ;
return 0 ;
}
2016-06-13 16:19:11 +03:00
static void lm90_restore_conf ( void * _data )
2012-03-23 13:02:18 +04:00
{
2016-06-13 16:19:11 +03:00
struct lm90_data * data = _data ;
struct i2c_client * client = data - > client ;
2012-03-23 13:02:18 +04:00
/* Restore initial configuration */
i2c_smbus_write_byte_data ( client , LM90_REG_W_CONVRATE ,
data - > convrate_orig ) ;
i2c_smbus_write_byte_data ( client , LM90_REG_W_CONFIG1 ,
data - > config_orig ) ;
}
2016-06-13 16:57:37 +03:00
static int lm90_init_client ( struct i2c_client * client , struct lm90_data * data )
2010-10-28 22:31:43 +04:00
{
2016-06-13 16:57:37 +03:00
int config , convrate ;
2010-10-28 22:31:43 +04:00
2016-06-13 16:57:37 +03:00
convrate = lm90_read_reg ( client , LM90_REG_R_CONVRATE ) ;
if ( convrate < 0 )
return convrate ;
2010-10-28 22:31:44 +04:00
data - > convrate_orig = convrate ;
2010-10-28 22:31:43 +04:00
/*
* Start the conversions .
*/
2010-10-28 22:31:44 +04:00
lm90_set_convrate ( client , data , 500 ) ; /* 500ms; 2Hz conversion rate */
2016-06-13 16:57:37 +03:00
config = lm90_read_reg ( client , LM90_REG_R_CONFIG1 ) ;
if ( config < 0 )
return config ;
2010-10-28 22:31:43 +04:00
data - > config_orig = config ;
/* Check Temperature Range Select */
2013-11-15 13:40:39 +04:00
if ( data - > kind = = adt7461 | | data - > kind = = tmp451 ) {
2010-10-28 22:31:43 +04:00
if ( config & 0x04 )
data - > flags | = LM90_FLAG_ADT7461_EXT ;
}
/*
* Put MAX6680 / MAX8881 into extended resolution ( bit 0x10 ,
* 0.125 degree resolution ) and range ( 0x08 , extend range
* to - 64 degree ) mode for the remote temperature sensor .
*/
if ( data - > kind = = max6680 )
config | = 0x18 ;
/*
* Select external channel 0 for max6695 / 96
*/
if ( data - > kind = = max6696 )
config & = ~ 0x08 ;
config & = 0xBF ; /* run */
if ( config ! = data - > config_orig ) /* Only write if changed */
i2c_smbus_write_byte_data ( client , LM90_REG_W_CONFIG1 , config ) ;
2016-06-13 16:19:11 +03:00
2016-07-26 00:53:23 +03:00
return devm_add_action_or_reset ( & client - > dev , lm90_restore_conf , data ) ;
2010-10-28 22:31:43 +04:00
}
2013-11-15 13:40:38 +04:00
static bool lm90_is_tripped ( struct i2c_client * client , u16 * status )
{
struct lm90_data * data = i2c_get_clientdata ( client ) ;
2016-06-13 16:57:37 +03:00
int st , st2 = 0 ;
2013-11-15 13:40:38 +04:00
2016-06-13 16:57:37 +03:00
st = lm90_read_reg ( client , LM90_REG_R_STATUS ) ;
if ( st < 0 )
return false ;
2013-11-15 13:40:38 +04:00
2016-06-13 16:57:37 +03:00
if ( data - > kind = = max6696 ) {
st2 = lm90_read_reg ( client , MAX6696_REG_R_STATUS2 ) ;
if ( st2 < 0 )
return false ;
}
2013-11-15 13:40:38 +04:00
* status = st | ( st2 < < 8 ) ;
if ( ( st & 0x7f ) = = 0 & & ( st2 & 0xfe ) = = 0 )
return false ;
if ( ( st & ( LM90_STATUS_LLOW | LM90_STATUS_LHIGH | LM90_STATUS_LTHRM ) ) | |
( st2 & MAX6696_STATUS2_LOT2 ) )
dev_warn ( & client - > dev ,
" temp%d out of range, please check! \n " , 1 ) ;
if ( ( st & ( LM90_STATUS_RLOW | LM90_STATUS_RHIGH | LM90_STATUS_RTHRM ) ) | |
( st2 & MAX6696_STATUS2_ROT2 ) )
dev_warn ( & client - > dev ,
" temp%d out of range, please check! \n " , 2 ) ;
if ( st & LM90_STATUS_ROPEN )
dev_warn ( & client - > dev ,
" temp%d diode open, please check! \n " , 2 ) ;
if ( st2 & ( MAX6696_STATUS2_R2LOW | MAX6696_STATUS2_R2HIGH |
MAX6696_STATUS2_R2THRM | MAX6696_STATUS2_R2OT2 ) )
dev_warn ( & client - > dev ,
" temp%d out of range, please check! \n " , 3 ) ;
if ( st2 & MAX6696_STATUS2_R2OPEN )
dev_warn ( & client - > dev ,
" temp%d diode open, please check! \n " , 3 ) ;
return true ;
}
2013-11-15 13:40:39 +04:00
static irqreturn_t lm90_irq_thread ( int irq , void * dev_id )
{
struct i2c_client * client = dev_id ;
u16 status ;
if ( lm90_is_tripped ( client , & status ) )
return IRQ_HANDLED ;
else
return IRQ_NONE ;
}
2016-06-13 16:19:11 +03:00
static void lm90_remove_pec ( void * dev )
{
device_remove_file ( dev , & dev_attr_pec ) ;
}
static void lm90_regulator_disable ( void * regulator )
{
regulator_disable ( regulator ) ;
}
2016-06-19 05:56:08 +03:00
static const u32 lm90_chip_config [ ] = {
HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL | HWMON_C_ALARMS ,
0
} ;
static const struct hwmon_channel_info lm90_chip_info = {
. type = hwmon_chip ,
. config = lm90_chip_config ,
} ;
static const struct hwmon_ops lm90_ops = {
. is_visible = lm90_is_visible ,
. read = lm90_read ,
. write = lm90_write ,
} ;
2011-11-04 15:00:47 +04:00
static int lm90_probe ( struct i2c_client * client ,
2008-07-16 21:30:15 +04:00
const struct i2c_device_id * id )
{
2011-11-04 15:00:47 +04:00
struct device * dev = & client - > dev ;
struct i2c_adapter * adapter = to_i2c_adapter ( dev - > parent ) ;
2016-06-19 05:56:08 +03:00
struct hwmon_channel_info * info ;
2013-11-15 13:40:39 +04:00
struct regulator * regulator ;
2016-06-13 16:28:03 +03:00
struct device * hwmon_dev ;
2016-06-19 05:56:08 +03:00
struct lm90_data * data ;
2008-07-16 21:30:15 +04:00
int err ;
2005-04-17 02:20:36 +04:00
2013-11-15 13:40:39 +04:00
regulator = devm_regulator_get ( dev , " vcc " ) ;
if ( IS_ERR ( regulator ) )
return PTR_ERR ( regulator ) ;
err = regulator_enable ( regulator ) ;
if ( err < 0 ) {
2014-04-04 20:01:35 +04:00
dev_err ( dev , " Failed to enable regulator: %d \n " , err ) ;
2013-11-15 13:40:39 +04:00
return err ;
}
2016-07-26 00:53:23 +03:00
err = devm_add_action_or_reset ( dev , lm90_regulator_disable , regulator ) ;
if ( err )
return err ;
2016-06-13 16:19:11 +03:00
2014-04-04 20:01:35 +04:00
data = devm_kzalloc ( dev , sizeof ( struct lm90_data ) , GFP_KERNEL ) ;
2012-06-02 20:58:10 +04:00
if ( ! data )
return - ENOMEM ;
2014-04-04 20:01:35 +04:00
data - > client = client ;
2011-11-04 15:00:47 +04:00
i2c_set_clientdata ( client , data ) ;
2006-01-19 01:19:26 +03:00
mutex_init ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
2008-07-16 21:30:15 +04:00
/* Set the device type */
2017-02-24 16:13:04 +03:00
if ( client - > dev . of_node )
data - > kind = ( enum chips ) of_device_get_match_data ( & client - > dev ) ;
else
data - > kind = id - > driver_data ;
2008-07-16 21:30:15 +04:00
if ( data - > kind = = adm1032 ) {
if ( ! i2c_check_functionality ( adapter , I2C_FUNC_SMBUS_BYTE ) )
2011-11-04 15:00:47 +04:00
client - > flags & = ~ I2C_CLIENT_PEC ;
2008-07-16 21:30:15 +04:00
}
2005-04-17 02:20:36 +04:00
2012-03-23 13:02:18 +04:00
/*
* Different devices have different alarm bits triggering the
* ALERT # output
*/
2010-10-28 22:31:43 +04:00
data - > alert_alarms = lm90_params [ data - > kind ] . alert_alarms ;
2010-03-06 00:17:15 +03:00
2010-10-28 22:31:43 +04:00
/* Set chip capabilities */
2010-10-28 22:31:43 +04:00
data - > flags = lm90_params [ data - > kind ] . flags ;
2016-06-19 05:56:08 +03:00
data - > chip . ops = & lm90_ops ;
data - > chip . info = data - > info ;
data - > info [ 0 ] = & lm90_chip_info ;
data - > info [ 1 ] = & data - > temp_info ;
info = & data - > temp_info ;
info - > type = hwmon_temp ;
info - > config = data - > channel_config ;
data - > channel_config [ 0 ] = HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM ;
data - > channel_config [ 1 ] = HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_FAULT ;
if ( data - > flags & LM90_HAVE_OFFSET )
data - > channel_config [ 1 ] | = HWMON_T_OFFSET ;
if ( data - > flags & LM90_HAVE_EMERGENCY ) {
data - > channel_config [ 0 ] | = HWMON_T_EMERGENCY |
HWMON_T_EMERGENCY_HYST ;
data - > channel_config [ 1 ] | = HWMON_T_EMERGENCY |
HWMON_T_EMERGENCY_HYST ;
}
if ( data - > flags & LM90_HAVE_EMERGENCY_ALARM ) {
data - > channel_config [ 0 ] | = HWMON_T_EMERGENCY_ALARM ;
data - > channel_config [ 1 ] | = HWMON_T_EMERGENCY_ALARM ;
}
if ( data - > flags & LM90_HAVE_TEMP3 ) {
data - > channel_config [ 2 ] = HWMON_T_INPUT |
HWMON_T_MIN | HWMON_T_MAX |
HWMON_T_CRIT | HWMON_T_CRIT_HYST |
HWMON_T_EMERGENCY | HWMON_T_EMERGENCY_HYST |
HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM |
HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY_ALARM |
HWMON_T_FAULT ;
}
2011-07-28 10:22:25 +04:00
data - > reg_local_ext = lm90_params [ data - > kind ] . reg_local_ext ;
2010-10-28 22:31:43 +04:00
2010-10-28 22:31:44 +04:00
/* Set maximum conversion rate */
data - > max_convrate = lm90_params [ data - > kind ] . max_convrate ;
2005-04-17 02:20:36 +04:00
/* Initialize the LM90 chip */
2016-06-13 16:57:37 +03:00
err = lm90_init_client ( client , data ) ;
if ( err < 0 ) {
dev_err ( dev , " Failed to initialize device \n " ) ;
return err ;
}
2005-04-17 02:20:36 +04:00
2016-06-19 05:56:08 +03:00
/*
* The ' pec ' attribute is attached to the i2c device and thus created
* separately .
*/
2011-11-04 15:00:47 +04:00
if ( client - > flags & I2C_CLIENT_PEC ) {
err = device_create_file ( dev , & dev_attr_pec ) ;
2010-10-28 22:31:42 +04:00
if ( err )
2016-06-13 16:19:11 +03:00
return err ;
2016-07-26 00:53:23 +03:00
err = devm_add_action_or_reset ( dev , lm90_remove_pec , dev ) ;
if ( err )
return err ;
2010-10-28 22:31:43 +04:00
}
2006-09-24 23:16:40 +04:00
2016-06-19 05:56:08 +03:00
hwmon_dev = devm_hwmon_device_register_with_info ( dev , client - > name ,
data , & data - > chip ,
NULL ) ;
2016-06-13 16:28:03 +03:00
if ( IS_ERR ( hwmon_dev ) )
return PTR_ERR ( hwmon_dev ) ;
2005-07-16 05:39:18 +04:00
2013-11-15 13:40:39 +04:00
if ( client - > irq ) {
dev_dbg ( dev , " IRQ: %d \n " , client - > irq ) ;
err = devm_request_threaded_irq ( dev , client - > irq ,
NULL , lm90_irq_thread ,
IRQF_TRIGGER_LOW | IRQF_ONESHOT ,
" lm90 " , client ) ;
if ( err < 0 ) {
dev_err ( dev , " cannot request IRQ %d \n " , client - > irq ) ;
2016-06-13 16:28:03 +03:00
return err ;
2013-11-15 13:40:39 +04:00
}
}
2005-04-17 02:20:36 +04:00
return 0 ;
}
2016-06-09 17:53:47 +03:00
static void lm90_alert ( struct i2c_client * client , enum i2c_alert_protocol type ,
unsigned int flag )
2010-03-06 00:17:15 +03:00
{
2013-11-15 13:40:38 +04:00
u16 alarms ;
2010-10-28 22:31:43 +04:00
2016-06-09 17:53:47 +03:00
if ( type ! = I2C_PROTOCOL_SMBUS_ALERT )
return ;
2013-11-15 13:40:38 +04:00
if ( lm90_is_tripped ( client , & alarms ) ) {
2012-03-23 13:02:18 +04:00
/*
* Disable ALERT # output , because these chips don ' t implement
* SMBus alert correctly ; they should only hold the alert line
* low briefly .
*/
2013-11-15 13:40:38 +04:00
struct lm90_data * data = i2c_get_clientdata ( client ) ;
2016-06-13 16:57:37 +03:00
if ( ( data - > flags & LM90_HAVE_BROKEN_ALERT ) & &
( alarms & data - > alert_alarms ) ) {
int config ;
2010-03-06 00:17:15 +03:00
dev_dbg ( & client - > dev , " Disabling ALERT# \n " ) ;
2016-06-13 16:57:37 +03:00
config = lm90_read_reg ( client , LM90_REG_R_CONFIG1 ) ;
if ( config > = 0 )
i2c_smbus_write_byte_data ( client ,
LM90_REG_W_CONFIG1 ,
config | 0x80 ) ;
2010-03-06 00:17:15 +03:00
}
2013-11-15 13:40:38 +04:00
} else {
dev_info ( & client - > dev , " Everything OK \n " ) ;
2010-03-06 00:17:15 +03:00
}
}
2010-10-28 22:31:43 +04:00
static struct i2c_driver lm90_driver = {
. class = I2C_CLASS_HWMON ,
. driver = {
. name = " lm90 " ,
2017-02-24 16:13:04 +03:00
. of_match_table = of_match_ptr ( lm90_of_match ) ,
2010-10-28 22:31:43 +04:00
} ,
. probe = lm90_probe ,
. alert = lm90_alert ,
. id_table = lm90_id ,
. detect = lm90_detect ,
. address_list = normal_i2c ,
} ;
2005-04-17 02:20:36 +04:00
2012-01-20 11:38:18 +04:00
module_i2c_driver ( lm90_driver ) ;
2005-04-17 02:20:36 +04:00
2014-01-29 23:40:08 +04:00
MODULE_AUTHOR ( " Jean Delvare <jdelvare@suse.de> " ) ;
2005-04-17 02:20:36 +04:00
MODULE_DESCRIPTION ( " LM90/ADM1032 driver " ) ;
MODULE_LICENSE ( " GPL " ) ;