2005-04-17 02:20:36 +04:00
/*
2005-05-20 22:33:25 +04:00
* w1_therm . c
2005-04-17 02:20:36 +04:00
*
2011-08-26 02:59:06 +04:00
* Copyright ( c ) 2004 Evgeniy Polyakov < zbr @ ioremap . net >
2005-05-20 22:33:25 +04:00
*
2005-04-17 02:20:36 +04:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the therms 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 . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <asm/types.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/moduleparam.h>
2006-10-18 09:47:25 +04:00
# include <linux/sched.h>
2005-04-17 02:20:36 +04:00
# include <linux/device.h>
# include <linux/types.h>
2014-01-16 08:29:24 +04:00
# include <linux/slab.h>
2005-04-17 02:20:36 +04:00
# include <linux/delay.h>
2005-12-06 13:38:28 +03:00
# include "../w1.h"
# include "../w1_int.h"
# include "../w1_family.h"
2005-04-17 02:20:36 +04:00
2008-10-16 09:04:43 +04:00
/* Allow the strong pullup to be disabled, but default to enabled.
* If it was disabled a parasite powered device might not get the require
* current to do a temperature conversion . If it is enabled parasite powered
* devices have a better chance of getting the current required .
2013-02-17 23:51:20 +04:00
* In case the parasite power - detection is not working ( seems to be the case
* for some DS18S20 ) the strong pullup can also be forced , regardless of the
* power state of the devices .
*
* Summary of options :
* - strong_pullup = 0 Disable strong pullup completely
* - strong_pullup = 1 Enable automatic strong pullup detection
* - strong_pullup = 2 Force strong pullup
2008-10-16 09:04:43 +04:00
*/
static int w1_strong_pullup = 1 ;
module_param_named ( strong_pullup , w1_strong_pullup , int , 0 ) ;
2015-05-09 03:51:50 +03:00
struct w1_therm_family_data {
uint8_t rom [ 9 ] ;
atomic_t refcnt ;
} ;
/* return the address of the refcnt in the family data */
# define THERM_REFCNT(family_data) \
2016-07-22 07:33:35 +03:00
( & ( ( struct w1_therm_family_data * ) family_data ) - > refcnt )
2015-05-09 03:51:50 +03:00
2014-01-16 08:29:24 +04:00
static int w1_therm_add_slave ( struct w1_slave * sl )
{
2015-05-09 03:51:50 +03:00
sl - > family_data = kzalloc ( sizeof ( struct w1_therm_family_data ) ,
GFP_KERNEL ) ;
2014-01-16 08:29:24 +04:00
if ( ! sl - > family_data )
return - ENOMEM ;
2015-05-09 03:51:50 +03:00
atomic_set ( THERM_REFCNT ( sl - > family_data ) , 1 ) ;
2014-01-16 08:29:24 +04:00
return 0 ;
}
static void w1_therm_remove_slave ( struct w1_slave * sl )
{
2015-05-09 03:51:50 +03:00
int refcnt = atomic_sub_return ( 1 , THERM_REFCNT ( sl - > family_data ) ) ;
2016-07-22 07:33:35 +03:00
2016-07-22 07:33:33 +03:00
while ( refcnt ) {
2015-05-09 03:51:50 +03:00
msleep ( 1000 ) ;
refcnt = atomic_read ( THERM_REFCNT ( sl - > family_data ) ) ;
}
2014-01-16 08:29:24 +04:00
kfree ( sl - > family_data ) ;
sl - > family_data = NULL ;
}
2005-04-17 02:20:36 +04:00
2013-08-22 02:44:56 +04:00
static ssize_t w1_slave_show ( struct device * device ,
2008-10-16 09:04:51 +04:00
struct device_attribute * attr , char * buf ) ;
2005-04-17 02:20:36 +04:00
2016-05-02 00:23:33 +03:00
static ssize_t w1_slave_store ( struct device * device ,
struct device_attribute * attr , const char * buf , size_t size ) ;
2015-04-28 14:44:17 +03:00
static ssize_t w1_seq_show ( struct device * device ,
struct device_attribute * attr , char * buf ) ;
2016-05-02 00:23:33 +03:00
static DEVICE_ATTR_RW ( w1_slave ) ;
2015-04-28 14:44:17 +03:00
static DEVICE_ATTR_RO ( w1_seq ) ;
2005-08-11 17:27:50 +04:00
2013-08-22 02:44:56 +04:00
static struct attribute * w1_therm_attrs [ ] = {
& dev_attr_w1_slave . attr ,
NULL ,
} ;
2015-04-28 14:44:17 +03:00
static struct attribute * w1_ds28ea00_attrs [ ] = {
& dev_attr_w1_slave . attr ,
& dev_attr_w1_seq . attr ,
NULL ,
} ;
2013-08-22 02:44:56 +04:00
ATTRIBUTE_GROUPS ( w1_therm ) ;
2015-04-28 14:44:17 +03:00
ATTRIBUTE_GROUPS ( w1_ds28ea00 ) ;
2005-08-11 17:27:50 +04:00
2005-04-17 02:20:36 +04:00
static struct w1_family_ops w1_therm_fops = {
2014-01-16 08:29:24 +04:00
. add_slave = w1_therm_add_slave ,
. remove_slave = w1_therm_remove_slave ,
2013-08-22 02:44:56 +04:00
. groups = w1_therm_groups ,
2005-04-17 02:20:36 +04:00
} ;
2015-04-28 14:44:17 +03:00
static struct w1_family_ops w1_ds28ea00_fops = {
. add_slave = w1_therm_add_slave ,
. remove_slave = w1_therm_remove_slave ,
. groups = w1_ds28ea00_groups ,
} ;
2005-04-17 22:58:14 +04:00
static struct w1_family w1_therm_family_DS18S20 = {
. fid = W1_THERM_DS18S20 ,
. fops = & w1_therm_fops ,
} ;
static struct w1_family w1_therm_family_DS18B20 = {
. fid = W1_THERM_DS18B20 ,
. fops = & w1_therm_fops ,
} ;
2005-08-11 17:27:50 +04:00
2005-04-17 22:58:14 +04:00
static struct w1_family w1_therm_family_DS1822 = {
. fid = W1_THERM_DS1822 ,
. fops = & w1_therm_fops ,
} ;
2011-07-27 03:08:55 +04:00
static struct w1_family w1_therm_family_DS28EA00 = {
. fid = W1_THERM_DS28EA00 ,
2015-04-28 14:44:17 +03:00
. fops = & w1_ds28ea00_fops ,
2011-07-27 03:08:55 +04:00
} ;
2012-08-16 20:56:40 +04:00
static struct w1_family w1_therm_family_DS1825 = {
. fid = W1_THERM_DS1825 ,
. fops = & w1_therm_fops ,
} ;
2016-07-22 07:33:33 +03:00
struct w1_therm_family_converter {
2005-04-17 22:58:14 +04:00
u8 broken ;
u16 reserved ;
struct w1_family * f ;
int ( * convert ) ( u8 rom [ 9 ] ) ;
2016-05-02 00:23:33 +03:00
int ( * precision ) ( struct device * device , int val ) ;
int ( * eeprom ) ( struct device * device ) ;
2005-04-17 22:58:14 +04:00
} ;
2016-05-02 00:23:33 +03:00
/* write configuration to eeprom */
static inline int w1_therm_eeprom ( struct device * device ) ;
/* Set precision for conversion */
static inline int w1_DS18B20_precision ( struct device * device , int val ) ;
static inline int w1_DS18S20_precision ( struct device * device , int val ) ;
2008-02-06 12:38:09 +03:00
/* The return value is millidegrees Centigrade. */
2005-04-17 22:58:14 +04:00
static inline int w1_DS18B20_convert_temp ( u8 rom [ 9 ] ) ;
static inline int w1_DS18S20_convert_temp ( u8 rom [ 9 ] ) ;
static struct w1_therm_family_converter w1_therm_families [ ] = {
{
. f = & w1_therm_family_DS18S20 ,
2016-05-02 00:23:33 +03:00
. convert = w1_DS18S20_convert_temp ,
. precision = w1_DS18S20_precision ,
. eeprom = w1_therm_eeprom
2005-04-17 22:58:14 +04:00
} ,
{
. f = & w1_therm_family_DS1822 ,
2016-05-02 00:23:33 +03:00
. convert = w1_DS18B20_convert_temp ,
. precision = w1_DS18S20_precision ,
. eeprom = w1_therm_eeprom
2005-04-17 22:58:14 +04:00
} ,
{
. f = & w1_therm_family_DS18B20 ,
2016-05-02 00:23:33 +03:00
. convert = w1_DS18B20_convert_temp ,
. precision = w1_DS18B20_precision ,
. eeprom = w1_therm_eeprom
2005-04-17 22:58:14 +04:00
} ,
2011-07-27 03:08:55 +04:00
{
. f = & w1_therm_family_DS28EA00 ,
2016-05-02 00:23:33 +03:00
. convert = w1_DS18B20_convert_temp ,
. precision = w1_DS18S20_precision ,
. eeprom = w1_therm_eeprom
2011-07-27 03:08:55 +04:00
} ,
2012-08-16 20:56:40 +04:00
{
. f = & w1_therm_family_DS1825 ,
2016-05-02 00:23:33 +03:00
. convert = w1_DS18B20_convert_temp ,
. precision = w1_DS18S20_precision ,
. eeprom = w1_therm_eeprom
2012-08-16 20:56:40 +04:00
}
2005-04-17 22:58:14 +04:00
} ;
2016-05-02 00:23:33 +03:00
static inline int w1_therm_eeprom ( struct device * device )
{
struct w1_slave * sl = dev_to_w1_slave ( device ) ;
struct w1_master * dev = sl - > master ;
u8 rom [ 9 ] , external_power ;
int ret , max_trying = 10 ;
u8 * family_data = sl - > family_data ;
ret = mutex_lock_interruptible ( & dev - > bus_mutex ) ;
if ( ret ! = 0 )
goto post_unlock ;
if ( ! sl - > family_data ) {
ret = - ENODEV ;
goto pre_unlock ;
}
/* prevent the slave from going away in sleep */
atomic_inc ( THERM_REFCNT ( family_data ) ) ;
memset ( rom , 0 , sizeof ( rom ) ) ;
while ( max_trying - - ) {
if ( ! w1_reset_select_slave ( sl ) ) {
unsigned int tm = 10 ;
unsigned long sleep_rem ;
/* check if in parasite mode */
w1_write_8 ( dev , W1_READ_PSUPPLY ) ;
external_power = w1_read_8 ( dev ) ;
if ( w1_reset_select_slave ( sl ) )
continue ;
/* 10ms strong pullup/delay after the copy command */
if ( w1_strong_pullup = = 2 | |
( ! external_power & & w1_strong_pullup ) )
w1_next_pullup ( dev , tm ) ;
w1_write_8 ( dev , W1_COPY_SCRATCHPAD ) ;
if ( external_power ) {
mutex_unlock ( & dev - > bus_mutex ) ;
sleep_rem = msleep_interruptible ( tm ) ;
if ( sleep_rem ! = 0 ) {
ret = - EINTR ;
goto post_unlock ;
}
ret = mutex_lock_interruptible ( & dev - > bus_mutex ) ;
if ( ret ! = 0 )
goto post_unlock ;
} else if ( ! w1_strong_pullup ) {
sleep_rem = msleep_interruptible ( tm ) ;
if ( sleep_rem ! = 0 ) {
ret = - EINTR ;
goto pre_unlock ;
}
}
break ;
}
}
pre_unlock :
mutex_unlock ( & dev - > bus_mutex ) ;
post_unlock :
atomic_dec ( THERM_REFCNT ( family_data ) ) ;
return ret ;
}
/* DS18S20 does not feature configuration register */
static inline int w1_DS18S20_precision ( struct device * device , int val )
{
return 0 ;
}
static inline int w1_DS18B20_precision ( struct device * device , int val )
{
struct w1_slave * sl = dev_to_w1_slave ( device ) ;
struct w1_master * dev = sl - > master ;
u8 rom [ 9 ] , crc ;
int ret , max_trying = 10 ;
u8 * family_data = sl - > family_data ;
uint8_t precision_bits ;
uint8_t mask = 0x60 ;
2016-07-22 07:33:33 +03:00
if ( val > 12 | | val < 9 ) {
2016-05-02 00:23:33 +03:00
pr_warn ( " Unsupported precision \n " ) ;
return - 1 ;
}
ret = mutex_lock_interruptible ( & dev - > bus_mutex ) ;
if ( ret ! = 0 )
goto post_unlock ;
if ( ! sl - > family_data ) {
ret = - ENODEV ;
goto pre_unlock ;
}
/* prevent the slave from going away in sleep */
atomic_inc ( THERM_REFCNT ( family_data ) ) ;
memset ( rom , 0 , sizeof ( rom ) ) ;
/* translate precision to bitmask (see datasheet page 9) */
switch ( val ) {
case 9 :
precision_bits = 0x00 ;
break ;
case 10 :
precision_bits = 0x20 ;
break ;
case 11 :
precision_bits = 0x40 ;
break ;
case 12 :
default :
precision_bits = 0x60 ;
break ;
}
while ( max_trying - - ) {
crc = 0 ;
if ( ! w1_reset_select_slave ( sl ) ) {
int count = 0 ;
/* read values to only alter precision bits */
w1_write_8 ( dev , W1_READ_SCRATCHPAD ) ;
2016-07-22 07:33:34 +03:00
count = w1_read_block ( dev , rom , 9 ) ;
if ( count ! = 9 )
2016-05-02 00:23:33 +03:00
dev_warn ( device , " w1_read_block() returned %u instead of 9. \n " , count ) ;
crc = w1_calc_crc8 ( rom , 8 ) ;
if ( rom [ 8 ] = = crc ) {
rom [ 4 ] = ( rom [ 4 ] & ~ mask ) | ( precision_bits & mask ) ;
if ( ! w1_reset_select_slave ( sl ) ) {
w1_write_8 ( dev , W1_WRITE_SCRATCHPAD ) ;
w1_write_8 ( dev , rom [ 2 ] ) ;
w1_write_8 ( dev , rom [ 3 ] ) ;
w1_write_8 ( dev , rom [ 4 ] ) ;
break ;
}
}
}
}
pre_unlock :
mutex_unlock ( & dev - > bus_mutex ) ;
post_unlock :
atomic_dec ( THERM_REFCNT ( family_data ) ) ;
return ret ;
}
2005-04-17 22:58:14 +04:00
static inline int w1_DS18B20_convert_temp ( u8 rom [ 9 ] )
{
2010-04-23 21:17:53 +04:00
s16 t = le16_to_cpup ( ( __le16 * ) rom ) ;
2016-07-22 07:33:35 +03:00
2010-04-23 21:17:53 +04:00
return t * 1000 / 16 ;
2005-04-17 22:58:14 +04:00
}
static inline int w1_DS18S20_convert_temp ( u8 rom [ 9 ] )
2005-04-17 02:20:36 +04:00
{
int t , h ;
2005-04-17 22:58:14 +04:00
if ( ! rom [ 7 ] )
return 0 ;
2005-12-06 13:38:28 +03:00
2005-04-17 02:20:36 +04:00
if ( rom [ 1 ] = = 0 )
t = ( ( s32 ) rom [ 0 ] > > 1 ) * 1000 ;
else
t = 1000 * ( - 1 * ( s32 ) ( 0x100 - rom [ 0 ] ) > > 1 ) ;
2005-12-06 13:38:28 +03:00
2005-04-17 02:20:36 +04:00
t - = 250 ;
h = 1000 * ( ( s32 ) rom [ 7 ] - ( s32 ) rom [ 6 ] ) ;
h / = ( s32 ) rom [ 7 ] ;
t + = h ;
return t ;
}
2005-04-17 22:58:14 +04:00
static inline int w1_convert_temp ( u8 rom [ 9 ] , u8 fid )
{
int i ;
2007-02-12 11:52:05 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( w1_therm_families ) ; + + i )
2005-05-20 22:50:33 +04:00
if ( w1_therm_families [ i ] . f - > fid = = fid )
2005-04-17 22:58:14 +04:00
return w1_therm_families [ i ] . convert ( rom ) ;
return 0 ;
}
2016-05-02 00:23:33 +03:00
static ssize_t w1_slave_store ( struct device * device ,
struct device_attribute * attr , const char * buf ,
size_t size )
{
int val , ret ;
struct w1_slave * sl = dev_to_w1_slave ( device ) ;
int i ;
ret = kstrtoint ( buf , 0 , & val ) ;
if ( ret )
return ret ;
for ( i = 0 ; i < ARRAY_SIZE ( w1_therm_families ) ; + + i ) {
if ( w1_therm_families [ i ] . f - > fid = = sl - > family - > fid ) {
/* zero value indicates to write current configuration to eeprom */
2016-07-22 07:33:35 +03:00
if ( val = = 0 )
2016-05-02 00:23:33 +03:00
ret = w1_therm_families [ i ] . eeprom ( device ) ;
else
ret = w1_therm_families [ i ] . precision ( device , val ) ;
break ;
}
}
return ret ? : size ;
}
2005-04-17 02:20:36 +04:00
2013-08-22 02:44:56 +04:00
static ssize_t w1_slave_show ( struct device * device ,
2008-10-16 09:04:51 +04:00
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2008-10-16 09:04:51 +04:00
struct w1_slave * sl = dev_to_w1_slave ( device ) ;
2005-04-17 02:20:36 +04:00
struct w1_master * dev = sl - > master ;
2011-11-16 03:43:16 +04:00
u8 rom [ 9 ] , crc , verdict , external_power ;
2015-05-09 03:51:50 +03:00
int i , ret , max_trying = 10 ;
2008-10-16 09:04:51 +04:00
ssize_t c = PAGE_SIZE ;
2015-05-09 03:51:50 +03:00
u8 * family_data = sl - > family_data ;
ret = mutex_lock_interruptible ( & dev - > bus_mutex ) ;
if ( ret ! = 0 )
goto post_unlock ;
2005-04-17 02:20:36 +04:00
2016-07-22 07:33:33 +03:00
if ( ! sl - > family_data ) {
2015-05-09 03:51:50 +03:00
ret = - ENODEV ;
goto pre_unlock ;
}
2005-04-17 02:20:36 +04:00
2015-05-09 03:51:50 +03:00
/* prevent the slave from going away in sleep */
atomic_inc ( THERM_REFCNT ( family_data ) ) ;
2005-04-17 02:20:36 +04:00
memset ( rom , 0 , sizeof ( rom ) ) ;
while ( max_trying - - ) {
2012-12-18 05:37:56 +04:00
verdict = 0 ;
crc = 0 ;
2005-08-11 17:27:49 +04:00
if ( ! w1_reset_select_slave ( sl ) ) {
2005-04-17 02:20:36 +04:00
int count = 0 ;
unsigned int tm = 750 ;
2011-11-16 03:43:16 +04:00
unsigned long sleep_rem ;
w1_write_8 ( dev , W1_READ_PSUPPLY ) ;
external_power = w1_read_8 ( dev ) ;
if ( w1_reset_select_slave ( sl ) )
continue ;
2005-04-17 02:20:36 +04:00
2008-10-16 09:04:43 +04:00
/* 750ms strong pullup (or delay) after the convert */
2013-02-17 23:51:20 +04:00
if ( w1_strong_pullup = = 2 | |
( ! external_power & & w1_strong_pullup ) )
2008-10-16 09:04:43 +04:00
w1_next_pullup ( dev , tm ) ;
2011-11-16 03:43:16 +04:00
2005-04-17 02:20:36 +04:00
w1_write_8 ( dev , W1_CONVERT_TEMP ) ;
2011-11-16 03:43:16 +04:00
if ( external_power ) {
2012-05-18 09:59:52 +04:00
mutex_unlock ( & dev - > bus_mutex ) ;
2011-11-16 03:43:16 +04:00
sleep_rem = msleep_interruptible ( tm ) ;
2015-05-09 03:51:50 +03:00
if ( sleep_rem ! = 0 ) {
ret = - EINTR ;
goto post_unlock ;
}
2011-11-16 03:43:16 +04:00
2015-05-09 03:51:50 +03:00
ret = mutex_lock_interruptible ( & dev - > bus_mutex ) ;
if ( ret ! = 0 )
goto post_unlock ;
2011-11-16 03:43:16 +04:00
} else if ( ! w1_strong_pullup ) {
sleep_rem = msleep_interruptible ( tm ) ;
if ( sleep_rem ! = 0 ) {
2015-05-09 03:51:50 +03:00
ret = - EINTR ;
goto pre_unlock ;
2011-11-16 03:43:16 +04:00
}
}
2005-04-17 02:20:36 +04:00
2005-08-11 17:27:49 +04:00
if ( ! w1_reset_select_slave ( sl ) ) {
2005-05-20 22:33:25 +04:00
2005-04-17 02:20:36 +04:00
w1_write_8 ( dev , W1_READ_SCRATCHPAD ) ;
2016-07-22 07:33:34 +03:00
count = w1_read_block ( dev , rom , 9 ) ;
if ( count ! = 9 ) {
2008-10-16 09:04:51 +04:00
dev_warn ( device , " w1_read_block() "
" returned %u instead of 9. \n " ,
count ) ;
2005-04-17 02:20:36 +04:00
}
crc = w1_calc_crc8 ( rom , 8 ) ;
W1: w1_therm.c is flagging 0C etc as invalid
The extra rom[0] check is flagging valid temperatures as invalid when
there is already a CRC data transmission check.
w1_therm_read_bin()
if (rom[8] == crc && rom[0])
verdict = 1;
Requiring rom[0] to be non-zero will flag as invalid temperature
conversions when the low byte is zero, specifically the temperatures 0C,
16C, 32C, 48C, -16C, -32C, and -48C.
The CRC check is produced on the device for the previous 8 bytes and is
required to ensure the data integrity in transmission. I don't see why the
extra check for rom[0] being non-zero is in there. Evgeniy Polyakov didn't
know either. Just for a check I unplugged the sensor, executed a
temperature conversion, and read the results. The read was all ff's, which
also failed the CRC, so it doesn't need to protect against a disconnected
sensor.
I have more extensive patches in the work, but these two trivial ones will
do for today. I would like to hear from people who use the ds2490 USB to
one wire dongle. 1 if you would be willing to test the patches as I
currently only have the one sensor on a short parisite powered wire, 2 if
there is any cheap sources for the ds2490.
Signed-off-by: David Fries <david@fries.net>
Acked-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-01-22 14:31:39 +03:00
if ( rom [ 8 ] = = crc )
2005-04-17 02:20:36 +04:00
verdict = 1 ;
}
}
2012-12-18 05:37:56 +04:00
if ( verdict )
2005-04-17 02:20:36 +04:00
break ;
}
for ( i = 0 ; i < 9 ; + + i )
2008-10-16 09:04:51 +04:00
c - = snprintf ( buf + PAGE_SIZE - c , c , " %02x " , rom [ i ] ) ;
c - = snprintf ( buf + PAGE_SIZE - c , c , " : crc=%02x %s \n " ,
2016-05-02 00:23:33 +03:00
crc , ( verdict ) ? " YES " : " NO " ) ;
2005-04-17 02:20:36 +04:00
if ( verdict )
2015-05-09 03:51:50 +03:00
memcpy ( family_data , rom , sizeof ( rom ) ) ;
2005-04-17 02:20:36 +04:00
else
2012-12-18 05:37:56 +04:00
dev_warn ( device , " Read failed CRC check \n " ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < 9 ; + + i )
2014-01-16 08:29:24 +04:00
c - = snprintf ( buf + PAGE_SIZE - c , c , " %02x " ,
2015-05-09 03:51:50 +03:00
( ( u8 * ) family_data ) [ i ] ) ;
2005-12-06 13:38:28 +03:00
2008-10-16 09:04:51 +04:00
c - = snprintf ( buf + PAGE_SIZE - c , c , " t=%d \n " ,
w1_convert_temp ( rom , sl - > family - > fid ) ) ;
2015-05-09 03:51:50 +03:00
ret = PAGE_SIZE - c ;
pre_unlock :
2012-05-18 09:59:52 +04:00
mutex_unlock ( & dev - > bus_mutex ) ;
2005-04-17 02:20:36 +04:00
2015-05-09 03:51:50 +03:00
post_unlock :
atomic_dec ( THERM_REFCNT ( family_data ) ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
2015-04-28 14:44:17 +03:00
# define W1_42_CHAIN 0x99
# define W1_42_CHAIN_OFF 0x3C
# define W1_42_CHAIN_OFF_INV 0xC3
# define W1_42_CHAIN_ON 0x5A
# define W1_42_CHAIN_ON_INV 0xA5
# define W1_42_CHAIN_DONE 0x96
# define W1_42_CHAIN_DONE_INV 0x69
# define W1_42_COND_READ 0x0F
# define W1_42_SUCCESS_CONFIRM_BYTE 0xAA
# define W1_42_FINISHED_BYTE 0xFF
static ssize_t w1_seq_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct w1_slave * sl = dev_to_w1_slave ( device ) ;
ssize_t c = PAGE_SIZE ;
int rv ;
int i ;
u8 ack ;
u64 rn ;
struct w1_reg_num * reg_num ;
int seq = 0 ;
2015-06-04 12:04:12 +03:00
mutex_lock ( & sl - > master - > bus_mutex ) ;
2015-04-28 14:44:17 +03:00
/* Place all devices in CHAIN state */
if ( w1_reset_bus ( sl - > master ) )
goto error ;
w1_write_8 ( sl - > master , W1_SKIP_ROM ) ;
w1_write_8 ( sl - > master , W1_42_CHAIN ) ;
w1_write_8 ( sl - > master , W1_42_CHAIN_ON ) ;
w1_write_8 ( sl - > master , W1_42_CHAIN_ON_INV ) ;
msleep ( sl - > master - > pullup_duration ) ;
/* check for acknowledgment */
ack = w1_read_8 ( sl - > master ) ;
if ( ack ! = W1_42_SUCCESS_CONFIRM_BYTE )
goto error ;
/* In case the bus fails to send 0xFF, limit*/
for ( i = 0 ; i < = 64 ; i + + ) {
if ( w1_reset_bus ( sl - > master ) )
goto error ;
w1_write_8 ( sl - > master , W1_42_COND_READ ) ;
rv = w1_read_block ( sl - > master , ( u8 * ) & rn , 8 ) ;
reg_num = ( struct w1_reg_num * ) & rn ;
2015-06-01 12:55:37 +03:00
if ( reg_num - > family = = W1_42_FINISHED_BYTE )
2015-04-28 14:44:17 +03:00
break ;
if ( sl - > reg_num . id = = reg_num - > id )
seq = i ;
w1_write_8 ( sl - > master , W1_42_CHAIN ) ;
w1_write_8 ( sl - > master , W1_42_CHAIN_DONE ) ;
w1_write_8 ( sl - > master , W1_42_CHAIN_DONE_INV ) ;
w1_read_block ( sl - > master , & ack , sizeof ( ack ) ) ;
/* check for acknowledgment */
ack = w1_read_8 ( sl - > master ) ;
if ( ack ! = W1_42_SUCCESS_CONFIRM_BYTE )
goto error ;
}
/* Exit from CHAIN state */
if ( w1_reset_bus ( sl - > master ) )
goto error ;
w1_write_8 ( sl - > master , W1_SKIP_ROM ) ;
w1_write_8 ( sl - > master , W1_42_CHAIN ) ;
w1_write_8 ( sl - > master , W1_42_CHAIN_OFF ) ;
w1_write_8 ( sl - > master , W1_42_CHAIN_OFF_INV ) ;
/* check for acknowledgment */
ack = w1_read_8 ( sl - > master ) ;
if ( ack ! = W1_42_SUCCESS_CONFIRM_BYTE )
goto error ;
2015-06-04 12:04:12 +03:00
mutex_unlock ( & sl - > master - > bus_mutex ) ;
2015-04-28 14:44:17 +03:00
c - = snprintf ( buf + PAGE_SIZE - c , c , " %d \n " , seq ) ;
return PAGE_SIZE - c ;
error :
mutex_unlock ( & sl - > master - > bus_mutex ) ;
return - EIO ;
}
2005-04-17 02:20:36 +04:00
static int __init w1_therm_init ( void )
{
2005-04-17 22:58:14 +04:00
int err , i ;
2007-02-12 11:52:05 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( w1_therm_families ) ; + + i ) {
2005-04-17 22:58:14 +04:00
err = w1_register_family ( w1_therm_families [ i ] . f ) ;
if ( err )
w1_therm_families [ i ] . broken = 1 ;
}
return 0 ;
2005-04-17 02:20:36 +04:00
}
static void __exit w1_therm_fini ( void )
{
2005-04-17 22:58:14 +04:00
int i ;
2007-02-12 11:52:05 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( w1_therm_families ) ; + + i )
2005-04-17 22:58:14 +04:00
if ( ! w1_therm_families [ i ] . broken )
w1_unregister_family ( w1_therm_families [ i ] . f ) ;
2005-04-17 02:20:36 +04:00
}
module_init ( w1_therm_init ) ;
module_exit ( w1_therm_fini ) ;
2017-05-16 23:02:12 +03:00
MODULE_AUTHOR ( " Evgeniy Polyakov <zbr@ioremap.net> " ) ;
MODULE_DESCRIPTION ( " Driver for 1-wire Dallas network protocol, temperature family. " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " w1-family- " __stringify ( W1_THERM_DS18S20 ) ) ;
MODULE_ALIAS ( " w1-family- " __stringify ( W1_THERM_DS1822 ) ) ;
MODULE_ALIAS ( " w1-family- " __stringify ( W1_THERM_DS18B20 ) ) ;
MODULE_ALIAS ( " w1-family- " __stringify ( W1_THERM_DS1825 ) ) ;
MODULE_ALIAS ( " w1-family- " __stringify ( W1_THERM_DS28EA00 ) ) ;