2019-05-20 10:19:02 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-04-17 02:20:36 +04:00
/*
2012-01-19 23:02:27 +04:00
* w83781d . c - Part of lm_sensors , Linux kernel modules for hardware
* monitoring
* Copyright ( c ) 1998 - 2001 Frodo Looijaard < frodol @ dds . nl > ,
* Philip Edelbrock < phil @ netroedge . com > ,
* and Mark Studebaker < mdsxyz123 @ yahoo . com >
2014-01-29 23:40:08 +04:00
* Copyright ( c ) 2007 - 2008 Jean Delvare < jdelvare @ suse . de >
2012-01-19 23:02:27 +04:00
*/
2005-04-17 02:20:36 +04:00
/*
2012-01-19 23:02:27 +04:00
* Supports following chips :
*
2012-11-06 00:54:40 +04:00
* Chip # vin # fanin # pwm # temp wchipid vendid i2c ISA
2012-01-19 23:02:27 +04:00
* as99127f 7 3 0 3 0x31 0x12c3 yes no
* as99127f rev .2 ( type_name = as99127f ) 0x31 0x5ca3 yes no
* w83781d 7 3 0 3 0x10 - 1 0x5ca3 yes yes
* w83782d 9 3 2 - 4 3 0x30 0x5ca3 yes yes
* w83783s 5 - 6 3 2 1 - 2 0x40 0x5ca3 yes no
*
*/
2005-04-17 02:20:36 +04:00
2011-01-12 23:55:11 +03:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2005-04-17 02:20:36 +04:00
# 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>
2005-07-31 23:52:01 +04:00
# include <linux/hwmon-vid.h>
2007-05-08 19:22:03 +04:00
# include <linux/hwmon-sysfs.h>
2006-09-24 23:22:52 +04:00
# include <linux/sysfs.h>
2005-07-16 05:39:18 +04:00
# include <linux/err.h>
2006-01-19 01:19:26 +03:00
# include <linux/mutex.h>
2008-10-17 19:51:18 +04:00
# ifdef CONFIG_ISA
# include <linux/platform_device.h>
# include <linux/ioport.h>
2009-09-15 19:18:13 +04:00
# include <linux/io.h>
2008-10-17 19:51:18 +04:00
# endif
2005-04-17 02:20:36 +04:00
2008-10-17 19:51:18 +04:00
# include "lm75.h"
2007-05-08 19:22:02 +04:00
2005-04-17 02:20:36 +04:00
/* Addresses to scan */
2008-02-18 06:28:03 +03:00
static const unsigned short normal_i2c [ ] = { 0x28 , 0x29 , 0x2a , 0x2b , 0x2c , 0x2d ,
0x2e , 0x2f , I2C_CLIENT_END } ;
2009-01-07 18:37:32 +03:00
2009-12-14 23:17:27 +03:00
enum chips { w83781d , w83782d , w83783s , as99127f } ;
/* Insmod parameters */
2009-01-07 18:37:32 +03:00
static unsigned short force_subclients [ 4 ] ;
module_param_array ( force_subclients , short , NULL , 0 ) ;
2013-01-10 22:01:24 +04:00
MODULE_PARM_DESC ( force_subclients ,
" List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2} " ) ;
2005-04-17 02:20:36 +04:00
2012-01-13 03:02:20 +04:00
static bool reset ;
2006-02-06 01:26:51 +03:00
module_param ( reset , bool , 0 ) ;
MODULE_PARM_DESC ( reset , " Set to one to reset chip on load " ) ;
2012-01-13 03:02:20 +04:00
static bool init = 1 ;
2005-04-17 02:20:36 +04:00
module_param ( init , bool , 0 ) ;
MODULE_PARM_DESC ( init , " Set to zero to bypass chip initialization " ) ;
/* Constants specified below */
/* Length of ISA address segment */
# define W83781D_EXTENT 8
/* Where are the ISA address/data registers relative to the base address */
# define W83781D_ADDR_REG_OFFSET 5
# define W83781D_DATA_REG_OFFSET 6
2007-05-08 19:22:03 +04:00
/* The device registers */
/* in nr from 0 to 8 */
2005-04-17 02:20:36 +04:00
# define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
( 0x554 + ( ( ( nr ) - 7 ) * 2 ) ) )
# define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
( 0x555 + ( ( ( nr ) - 7 ) * 2 ) ) )
# define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
( 0x550 + ( nr ) - 7 ) )
2007-05-08 19:22:03 +04:00
/* fan nr from 0 to 2 */
# define W83781D_REG_FAN_MIN(nr) (0x3b + (nr))
# define W83781D_REG_FAN(nr) (0x28 + (nr))
2005-04-17 02:20:36 +04:00
# define W83781D_REG_BANK 0x4E
# define W83781D_REG_TEMP2_CONFIG 0x152
# define W83781D_REG_TEMP3_CONFIG 0x252
2007-05-08 19:22:03 +04:00
/* temp nr from 1 to 3 */
2005-04-17 02:20:36 +04:00
# define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \
( ( nr = = 2 ) ? ( 0x0150 ) : \
( 0x27 ) ) )
# define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \
( ( nr = = 2 ) ? ( 0x153 ) : \
( 0x3A ) ) )
# define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \
( ( nr = = 2 ) ? ( 0x155 ) : \
( 0x39 ) ) )
# define W83781D_REG_CONFIG 0x40
2006-02-06 01:13:48 +03:00
/* Interrupt status (W83781D, AS99127F) */
2005-04-17 02:20:36 +04:00
# define W83781D_REG_ALARM1 0x41
# define W83781D_REG_ALARM2 0x42
2007-12-01 01:51:24 +03:00
/* Real-time status (W83782D, W83783S) */
2006-02-06 01:13:48 +03:00
# define W83782D_REG_ALARM1 0x459
# define W83782D_REG_ALARM2 0x45A
# define W83782D_REG_ALARM3 0x45B
2005-04-17 02:20:36 +04:00
# define W83781D_REG_BEEP_CONFIG 0x4D
# define W83781D_REG_BEEP_INTS1 0x56
# define W83781D_REG_BEEP_INTS2 0x57
# define W83781D_REG_BEEP_INTS3 0x453 /* not on W83781D */
# define W83781D_REG_VID_FANDIV 0x47
# define W83781D_REG_CHIPID 0x49
# define W83781D_REG_WCHIPID 0x58
# define W83781D_REG_CHIPMAN 0x4F
# define W83781D_REG_PIN 0x4B
/* 782D/783S only */
# define W83781D_REG_VBAT 0x5D
/* PWM 782D (1-4) and 783S (1-2) only */
2007-05-08 19:22:03 +04:00
static const u8 W83781D_REG_PWM [ ] = { 0x5B , 0x5A , 0x5E , 0x5F } ;
2005-04-17 02:20:36 +04:00
# define W83781D_REG_PWMCLK12 0x5C
# define W83781D_REG_PWMCLK34 0x45C
# define W83781D_REG_I2C_ADDR 0x48
# define W83781D_REG_I2C_SUBADDR 0x4A
2012-01-19 23:02:27 +04:00
/*
* The following are undocumented in the data sheets however we
* received the information in an email from Winbond tech support
*/
2005-04-17 02:20:36 +04:00
/* Sensor selection - not on 781d */
# define W83781D_REG_SCFG1 0x5D
static const u8 BIT_SCFG1 [ ] = { 0x02 , 0x04 , 0x08 } ;
# define W83781D_REG_SCFG2 0x59
static const u8 BIT_SCFG2 [ ] = { 0x10 , 0x20 , 0x40 } ;
# define W83781D_DEFAULT_BETA 3435
2007-05-08 19:22:03 +04:00
/* Conversions */
2013-01-09 20:09:34 +04:00
# define IN_TO_REG(val) clamp_val(((val) + 8) / 16, 0, 255)
2007-05-08 19:22:03 +04:00
# define IN_FROM_REG(val) ((val) * 16)
2005-04-17 02:20:36 +04:00
static inline u8
FAN_TO_REG ( long rpm , int div )
{
if ( rpm = = 0 )
return 255 ;
2013-01-09 20:09:34 +04:00
rpm = clamp_val ( rpm , 1 , 1000000 ) ;
return clamp_val ( ( 1350000 + rpm * div / 2 ) / ( rpm * div ) , 1 , 254 ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-08 19:22:03 +04:00
static inline long
FAN_FROM_REG ( u8 val , int div )
{
if ( val = = 0 )
return - 1 ;
if ( val = = 255 )
return 0 ;
return 1350000 / ( val * div ) ;
}
2005-04-17 02:20:36 +04:00
2013-01-09 20:09:34 +04:00
# define TEMP_TO_REG(val) clamp_val((val) / 1000, -127, 128)
2007-05-08 19:22:03 +04:00
# define TEMP_FROM_REG(val) ((val) * 1000)
2005-04-17 02:20:36 +04:00
2012-01-15 21:19:16 +04:00
# define BEEP_MASK_FROM_REG(val, type) ((type) == as99127f ? \
2008-10-17 19:51:18 +04:00
( ~ ( val ) ) & 0x7fff : ( val ) & 0xff7fff )
2012-01-15 21:19:16 +04:00
# define BEEP_MASK_TO_REG(val, type) ((type) == as99127f ? \
2008-10-17 19:51:18 +04:00
( ~ ( val ) ) & 0x7fff : ( val ) & 0xff7fff )
2005-04-17 02:20:36 +04:00
# define DIV_FROM_REG(val) (1 << (val))
static inline u8
DIV_TO_REG ( long val , enum chips type )
{
int i ;
2013-01-09 20:09:34 +04:00
val = clamp_val ( val , 1 ,
( ( type = = w83781d | | type = = as99127f ) ? 8 : 128 ) ) > > 1 ;
2005-05-12 07:41:51 +04:00
for ( i = 0 ; i < 7 ; i + + ) {
2005-04-17 02:20:36 +04:00
if ( val = = 0 )
break ;
val > > = 1 ;
}
2007-05-08 19:22:03 +04:00
return i ;
2005-04-17 02:20:36 +04:00
}
struct w83781d_data {
2008-10-17 19:51:19 +04:00
struct i2c_client * client ;
2007-08-21 00:46:20 +04:00
struct device * hwmon_dev ;
2006-01-19 01:19:26 +03:00
struct mutex lock ;
2005-04-17 02:20:36 +04:00
enum chips type ;
2008-10-17 19:51:19 +04:00
/* For ISA device only */
const char * name ;
int isa_addr ;
2006-01-19 01:19:26 +03:00
struct mutex update_lock ;
2021-09-24 22:52:02 +03:00
bool valid ; /* true if following fields are valid */
2005-04-17 02:20:36 +04:00
unsigned long last_updated ; /* In jiffies */
struct i2c_client * lm75 [ 2 ] ; /* for secondary I2C addresses */
/* array of 2 pointers to subclients */
u8 in [ 9 ] ; /* Register value - 8 & 9 for 782D only */
u8 in_max [ 9 ] ; /* Register value - 8 & 9 for 782D only */
u8 in_min [ 9 ] ; /* Register value - 8 & 9 for 782D only */
u8 fan [ 3 ] ; /* Register value */
u8 fan_min [ 3 ] ; /* Register value */
2007-05-08 19:22:03 +04:00
s8 temp ; /* Register value */
s8 temp_max ; /* Register value */
s8 temp_max_hyst ; /* Register value */
2005-04-17 02:20:36 +04:00
u16 temp_add [ 2 ] ; /* Register value */
u16 temp_max_add [ 2 ] ; /* Register value */
u16 temp_max_hyst_add [ 2 ] ; /* Register value */
u8 fan_div [ 3 ] ; /* Register encoding, shifted right */
u8 vid ; /* Register encoding, combined */
u32 alarms ; /* Register encoding, combined */
u32 beep_mask ; /* Register encoding, combined */
u8 pwm [ 4 ] ; /* Register value */
2007-05-08 19:22:03 +04:00
u8 pwm2_enable ; /* Boolean */
2012-01-19 23:02:27 +04:00
u16 sens [ 3 ] ; /*
* 782 D / 783 S only .
* 1 = pentium diode ; 2 = 3904 diode ;
* 4 = thermistor
*/
2005-04-17 02:20:36 +04:00
u8 vrm ;
} ;
2008-10-17 19:51:18 +04:00
static struct w83781d_data * w83781d_data_if_isa ( void ) ;
static int w83781d_alias_detect ( struct i2c_client * client , u8 chipid ) ;
2007-05-08 19:22:03 +04:00
static int w83781d_read_value ( struct w83781d_data * data , u16 reg ) ;
static int w83781d_write_value ( struct w83781d_data * data , u16 reg , u16 value ) ;
2005-04-17 02:20:36 +04:00
static struct w83781d_data * w83781d_update_device ( struct device * dev ) ;
2007-05-08 19:22:02 +04:00
static void w83781d_init_device ( struct device * dev ) ;
2005-04-17 02:20:36 +04:00
/* following are the sysfs callback functions */
# define show_in_reg(reg) \
2012-01-15 21:19:16 +04:00
static ssize_t show_ # # reg ( struct device * dev , struct device_attribute * da , \
2007-05-08 19:22:03 +04:00
char * buf ) \
2005-04-17 02:20:36 +04:00
{ \
2007-05-08 19:22:03 +04:00
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ; \
2005-04-17 02:20:36 +04:00
struct w83781d_data * data = w83781d_update_device ( dev ) ; \
2007-05-08 19:22:03 +04:00
return sprintf ( buf , " %ld \n " , \
( long ) IN_FROM_REG ( data - > reg [ attr - > index ] ) ) ; \
2005-04-17 02:20:36 +04:00
}
show_in_reg ( in ) ;
show_in_reg ( in_min ) ;
show_in_reg ( in_max ) ;
# define store_in_reg(REG, reg) \
2012-01-15 21:19:16 +04:00
static ssize_t store_in_ # # reg ( struct device * dev , struct device_attribute \
2007-05-08 19:22:03 +04:00
* da , const char * buf , size_t count ) \
2005-04-17 02:20:36 +04:00
{ \
2007-05-08 19:22:03 +04:00
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ; \
2007-05-08 19:22:02 +04:00
struct w83781d_data * data = dev_get_drvdata ( dev ) ; \
2007-05-08 19:22:03 +04:00
int nr = attr - > index ; \
2012-01-15 21:19:16 +04:00
unsigned long val ; \
int err = kstrtoul ( buf , 10 , & val ) ; \
if ( err ) \
return err ; \
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ; \
2005-04-17 02:20:36 +04:00
data - > in_ # # reg [ nr ] = IN_TO_REG ( val ) ; \
2012-01-15 21:19:16 +04:00
w83781d_write_value ( data , W83781D_REG_IN_ # # REG ( nr ) , \
data - > in_ # # reg [ nr ] ) ; \
\
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ; \
2005-04-17 02:20:36 +04:00
return count ; \
}
store_in_reg ( MIN , min ) ;
store_in_reg ( MAX , max ) ;
# define sysfs_in_offsets(offset) \
2007-05-08 19:22:03 +04:00
static SENSOR_DEVICE_ATTR ( in # # offset # # _input , S_IRUGO , \
show_in , NULL , offset ) ; \
static SENSOR_DEVICE_ATTR ( in # # offset # # _min , S_IRUGO | S_IWUSR , \
show_in_min , store_in_min , offset ) ; \
static SENSOR_DEVICE_ATTR ( in # # offset # # _max , S_IRUGO | S_IWUSR , \
show_in_max , store_in_max , offset )
2005-04-17 02:20:36 +04:00
sysfs_in_offsets ( 0 ) ;
sysfs_in_offsets ( 1 ) ;
sysfs_in_offsets ( 2 ) ;
sysfs_in_offsets ( 3 ) ;
sysfs_in_offsets ( 4 ) ;
sysfs_in_offsets ( 5 ) ;
sysfs_in_offsets ( 6 ) ;
sysfs_in_offsets ( 7 ) ;
sysfs_in_offsets ( 8 ) ;
# define show_fan_reg(reg) \
2012-01-15 21:19:16 +04:00
static ssize_t show_ # # reg ( struct device * dev , struct device_attribute * da , \
2007-05-08 19:22:03 +04:00
char * buf ) \
2005-04-17 02:20:36 +04:00
{ \
2007-05-08 19:22:03 +04:00
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ; \
2005-04-17 02:20:36 +04:00
struct w83781d_data * data = w83781d_update_device ( dev ) ; \
2012-01-15 21:19:16 +04:00
return sprintf ( buf , " %ld \n " , \
2007-05-08 19:22:03 +04:00
FAN_FROM_REG ( data - > reg [ attr - > index ] , \
DIV_FROM_REG ( data - > fan_div [ attr - > index ] ) ) ) ; \
2005-04-17 02:20:36 +04:00
}
show_fan_reg ( fan ) ;
show_fan_reg ( fan_min ) ;
static ssize_t
2007-05-08 19:22:03 +04:00
store_fan_min ( struct device * dev , struct device_attribute * da ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2007-05-08 19:22:03 +04:00
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ;
2007-05-08 19:22:02 +04:00
struct w83781d_data * data = dev_get_drvdata ( dev ) ;
2007-05-08 19:22:03 +04:00
int nr = attr - > index ;
2012-01-15 21:19:16 +04:00
unsigned long val ;
int err ;
2005-04-17 02:20:36 +04:00
2012-01-15 21:19:16 +04:00
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
2005-04-17 02:20:36 +04:00
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2007-05-08 19:22:03 +04:00
data - > fan_min [ nr ] =
FAN_TO_REG ( val , DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ;
2007-05-08 19:22:03 +04:00
w83781d_write_value ( data , W83781D_REG_FAN_MIN ( nr ) ,
2007-05-08 19:22:03 +04:00
data - > fan_min [ nr ] ) ;
2005-04-17 02:20:36 +04:00
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
2007-05-08 19:22:03 +04:00
static SENSOR_DEVICE_ATTR ( fan1_input , S_IRUGO , show_fan , NULL , 0 ) ;
static SENSOR_DEVICE_ATTR ( fan1_min , S_IRUGO | S_IWUSR ,
show_fan_min , store_fan_min , 0 ) ;
static SENSOR_DEVICE_ATTR ( fan2_input , S_IRUGO , show_fan , NULL , 1 ) ;
static SENSOR_DEVICE_ATTR ( fan2_min , S_IRUGO | S_IWUSR ,
show_fan_min , store_fan_min , 1 ) ;
static SENSOR_DEVICE_ATTR ( fan3_input , S_IRUGO , show_fan , NULL , 2 ) ;
static SENSOR_DEVICE_ATTR ( fan3_min , S_IRUGO | S_IWUSR ,
show_fan_min , store_fan_min , 2 ) ;
2005-04-17 02:20:36 +04:00
# define show_temp_reg(reg) \
2012-01-15 21:19:16 +04:00
static ssize_t show_ # # reg ( struct device * dev , struct device_attribute * da , \
2007-05-08 19:22:03 +04:00
char * buf ) \
2005-04-17 02:20:36 +04:00
{ \
2007-05-08 19:22:03 +04:00
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ; \
2005-04-17 02:20:36 +04:00
struct w83781d_data * data = w83781d_update_device ( dev ) ; \
2007-05-08 19:22:03 +04:00
int nr = attr - > index ; \
2005-04-17 02:20:36 +04:00
if ( nr > = 2 ) { /* TEMP2 and TEMP3 */ \
2012-01-15 21:19:16 +04:00
return sprintf ( buf , " %d \n " , \
2005-04-17 02:20:36 +04:00
LM75_TEMP_FROM_REG ( data - > reg # # _add [ nr - 2 ] ) ) ; \
} else { /* TEMP1 */ \
2012-01-15 21:19:16 +04:00
return sprintf ( buf , " %ld \n " , ( long ) TEMP_FROM_REG ( data - > reg ) ) ; \
2005-04-17 02:20:36 +04:00
} \
}
show_temp_reg ( temp ) ;
show_temp_reg ( temp_max ) ;
show_temp_reg ( temp_max_hyst ) ;
# define store_temp_reg(REG, reg) \
2012-01-15 21:19:16 +04:00
static ssize_t store_temp_ # # reg ( struct device * dev , \
2007-05-08 19:22:03 +04:00
struct device_attribute * da , const char * buf , size_t count ) \
2005-04-17 02:20:36 +04:00
{ \
2007-05-08 19:22:03 +04:00
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ; \
2007-05-08 19:22:02 +04:00
struct w83781d_data * data = dev_get_drvdata ( dev ) ; \
2007-05-08 19:22:03 +04:00
int nr = attr - > index ; \
2007-08-16 13:40:10 +04:00
long val ; \
2012-01-15 21:19:16 +04:00
int err = kstrtol ( buf , 10 , & val ) ; \
if ( err ) \
return err ; \
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ; \
2005-04-17 02:20:36 +04:00
\
if ( nr > = 2 ) { /* TEMP2 and TEMP3 */ \
data - > temp_ # # reg # # _add [ nr - 2 ] = LM75_TEMP_TO_REG ( val ) ; \
2007-05-08 19:22:03 +04:00
w83781d_write_value ( data , W83781D_REG_TEMP_ # # REG ( nr ) , \
2005-04-17 02:20:36 +04:00
data - > temp_ # # reg # # _add [ nr - 2 ] ) ; \
} else { /* TEMP1 */ \
data - > temp_ # # reg = TEMP_TO_REG ( val ) ; \
2007-05-08 19:22:03 +04:00
w83781d_write_value ( data , W83781D_REG_TEMP_ # # REG ( nr ) , \
2005-04-17 02:20:36 +04:00
data - > temp_ # # reg ) ; \
} \
\
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ; \
2005-04-17 02:20:36 +04:00
return count ; \
}
store_temp_reg ( OVER , max ) ;
store_temp_reg ( HYST , max_hyst ) ;
# define sysfs_temp_offsets(offset) \
2007-05-08 19:22:03 +04:00
static SENSOR_DEVICE_ATTR ( temp # # offset # # _input , S_IRUGO , \
show_temp , NULL , offset ) ; \
static SENSOR_DEVICE_ATTR ( temp # # offset # # _max , S_IRUGO | S_IWUSR , \
show_temp_max , store_temp_max , offset ) ; \
static SENSOR_DEVICE_ATTR ( temp # # offset # # _max_hyst , S_IRUGO | S_IWUSR , \
show_temp_max_hyst , store_temp_max_hyst , offset ) ;
2005-04-17 02:20:36 +04:00
sysfs_temp_offsets ( 1 ) ;
sysfs_temp_offsets ( 2 ) ;
sysfs_temp_offsets ( 3 ) ;
static ssize_t
2016-12-22 15:05:12 +03:00
cpu0_vid_show ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct w83781d_data * data = w83781d_update_device ( dev ) ;
return sprintf ( buf , " %ld \n " , ( long ) vid_from_reg ( data - > vid , data - > vrm ) ) ;
}
2016-12-22 15:05:12 +03:00
static DEVICE_ATTR_RO ( cpu0_vid ) ;
2006-09-24 23:22:52 +04:00
2005-04-17 02:20:36 +04:00
static ssize_t
2016-12-22 15:05:12 +03:00
vrm_show ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-10-08 20:24:35 +04:00
struct w83781d_data * data = dev_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
return sprintf ( buf , " %ld \n " , ( long ) data - > vrm ) ;
}
static ssize_t
2016-12-22 15:05:12 +03:00
vrm_store ( struct device * dev , struct device_attribute * attr , const char * buf ,
size_t count )
2005-04-17 02:20:36 +04:00
{
2007-05-08 19:22:02 +04:00
struct w83781d_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 21:19:16 +04:00
unsigned long val ;
int err ;
2005-04-17 02:20:36 +04:00
2012-01-15 21:19:16 +04:00
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
2013-01-09 20:09:34 +04:00
data - > vrm = clamp_val ( val , 0 , 255 ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
2016-12-22 15:05:12 +03:00
static DEVICE_ATTR_RW ( vrm ) ;
2006-09-24 23:22:52 +04:00
2005-04-17 02:20:36 +04:00
static ssize_t
2016-12-22 15:05:12 +03:00
alarms_show ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct w83781d_data * data = w83781d_update_device ( dev ) ;
2005-05-16 20:52:38 +04:00
return sprintf ( buf , " %u \n " , data - > alarms ) ;
2005-04-17 02:20:36 +04:00
}
2016-12-22 15:05:12 +03:00
static DEVICE_ATTR_RO ( alarms ) ;
2006-09-24 23:22:52 +04:00
2007-10-08 20:29:43 +04:00
static ssize_t show_alarm ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct w83781d_data * data = w83781d_update_device ( dev ) ;
int bitnr = to_sensor_dev_attr ( attr ) - > index ;
return sprintf ( buf , " %u \n " , ( data - > alarms > > bitnr ) & 1 ) ;
}
/* The W83781D has a single alarm bit for temp2 and temp3 */
static ssize_t show_temp3_alarm ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct w83781d_data * data = w83781d_update_device ( dev ) ;
int bitnr = ( data - > type = = w83781d ) ? 5 : 13 ;
return sprintf ( buf , " %u \n " , ( data - > alarms > > bitnr ) & 1 ) ;
}
static SENSOR_DEVICE_ATTR ( in0_alarm , S_IRUGO , show_alarm , NULL , 0 ) ;
static SENSOR_DEVICE_ATTR ( in1_alarm , S_IRUGO , show_alarm , NULL , 1 ) ;
static SENSOR_DEVICE_ATTR ( in2_alarm , S_IRUGO , show_alarm , NULL , 2 ) ;
static SENSOR_DEVICE_ATTR ( in3_alarm , S_IRUGO , show_alarm , NULL , 3 ) ;
static SENSOR_DEVICE_ATTR ( in4_alarm , S_IRUGO , show_alarm , NULL , 8 ) ;
static SENSOR_DEVICE_ATTR ( in5_alarm , S_IRUGO , show_alarm , NULL , 9 ) ;
static SENSOR_DEVICE_ATTR ( in6_alarm , S_IRUGO , show_alarm , NULL , 10 ) ;
static SENSOR_DEVICE_ATTR ( in7_alarm , S_IRUGO , show_alarm , NULL , 16 ) ;
static SENSOR_DEVICE_ATTR ( in8_alarm , S_IRUGO , show_alarm , NULL , 17 ) ;
static SENSOR_DEVICE_ATTR ( fan1_alarm , S_IRUGO , show_alarm , NULL , 6 ) ;
static SENSOR_DEVICE_ATTR ( fan2_alarm , S_IRUGO , show_alarm , NULL , 7 ) ;
static SENSOR_DEVICE_ATTR ( fan3_alarm , S_IRUGO , show_alarm , NULL , 11 ) ;
static SENSOR_DEVICE_ATTR ( temp1_alarm , S_IRUGO , show_alarm , NULL , 4 ) ;
static SENSOR_DEVICE_ATTR ( temp2_alarm , S_IRUGO , show_alarm , NULL , 5 ) ;
static SENSOR_DEVICE_ATTR ( temp3_alarm , S_IRUGO , show_temp3_alarm , NULL , 0 ) ;
2016-12-22 15:05:12 +03:00
static ssize_t beep_mask_show ( struct device * dev ,
2012-01-15 21:19:16 +04:00
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct w83781d_data * data = w83781d_update_device ( dev ) ;
return sprintf ( buf , " %ld \n " ,
( long ) BEEP_MASK_FROM_REG ( data - > beep_mask , data - > type ) ) ;
}
static ssize_t
2016-12-22 15:05:12 +03:00
beep_mask_store ( struct device * dev , struct device_attribute * attr ,
2007-05-08 19:22:03 +04:00
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2007-05-08 19:22:02 +04:00
struct w83781d_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 21:19:16 +04:00
unsigned long val ;
int err ;
2005-04-17 02:20:36 +04:00
2012-01-15 21:19:16 +04:00
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
2005-04-17 02:20:36 +04:00
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2008-10-17 19:51:18 +04:00
data - > beep_mask & = 0x8000 ; /* preserve beep enable */
data - > beep_mask | = BEEP_MASK_TO_REG ( val , data - > type ) ;
2007-05-08 19:22:03 +04:00
w83781d_write_value ( data , W83781D_REG_BEEP_INTS1 ,
data - > beep_mask & 0xff ) ;
w83781d_write_value ( data , W83781D_REG_BEEP_INTS2 ,
2008-10-17 19:51:18 +04:00
( data - > beep_mask > > 8 ) & 0xff ) ;
2007-05-08 19:22:03 +04:00
if ( data - > type ! = w83781d & & data - > type ! = as99127f ) {
w83781d_write_value ( data , W83781D_REG_BEEP_INTS3 ,
( ( data - > beep_mask ) > > 16 ) & 0xff ) ;
}
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
2007-05-08 19:22:03 +04:00
return count ;
}
2005-04-17 02:20:36 +04:00
2016-12-22 15:05:12 +03:00
static DEVICE_ATTR_RW ( beep_mask ) ;
2005-04-17 02:20:36 +04:00
2007-10-08 20:29:43 +04:00
static ssize_t show_beep ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct w83781d_data * data = w83781d_update_device ( dev ) ;
int bitnr = to_sensor_dev_attr ( attr ) - > index ;
return sprintf ( buf , " %u \n " , ( data - > beep_mask > > bitnr ) & 1 ) ;
}
static ssize_t
store_beep ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct w83781d_data * data = dev_get_drvdata ( dev ) ;
int bitnr = to_sensor_dev_attr ( attr ) - > index ;
u8 reg ;
2012-01-15 21:19:16 +04:00
unsigned long bit ;
int err ;
err = kstrtoul ( buf , 10 , & bit ) ;
if ( err )
return err ;
2007-10-08 20:29:43 +04:00
if ( bit & ~ 1 )
return - EINVAL ;
mutex_lock ( & data - > update_lock ) ;
if ( bit )
data - > beep_mask | = ( 1 < < bitnr ) ;
else
data - > beep_mask & = ~ ( 1 < < bitnr ) ;
if ( bitnr < 8 ) {
reg = w83781d_read_value ( data , W83781D_REG_BEEP_INTS1 ) ;
if ( bit )
reg | = ( 1 < < bitnr ) ;
else
reg & = ~ ( 1 < < bitnr ) ;
w83781d_write_value ( data , W83781D_REG_BEEP_INTS1 , reg ) ;
} else if ( bitnr < 16 ) {
reg = w83781d_read_value ( data , W83781D_REG_BEEP_INTS2 ) ;
if ( bit )
reg | = ( 1 < < ( bitnr - 8 ) ) ;
else
reg & = ~ ( 1 < < ( bitnr - 8 ) ) ;
w83781d_write_value ( data , W83781D_REG_BEEP_INTS2 , reg ) ;
} else {
reg = w83781d_read_value ( data , W83781D_REG_BEEP_INTS3 ) ;
if ( bit )
reg | = ( 1 < < ( bitnr - 16 ) ) ;
else
reg & = ~ ( 1 < < ( bitnr - 16 ) ) ;
w83781d_write_value ( data , W83781D_REG_BEEP_INTS3 , reg ) ;
}
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
/* The W83781D has a single beep bit for temp2 and temp3 */
static ssize_t show_temp3_beep ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct w83781d_data * data = w83781d_update_device ( dev ) ;
int bitnr = ( data - > type = = w83781d ) ? 5 : 13 ;
return sprintf ( buf , " %u \n " , ( data - > beep_mask > > bitnr ) & 1 ) ;
}
static SENSOR_DEVICE_ATTR ( in0_beep , S_IRUGO | S_IWUSR ,
show_beep , store_beep , 0 ) ;
static SENSOR_DEVICE_ATTR ( in1_beep , S_IRUGO | S_IWUSR ,
show_beep , store_beep , 1 ) ;
static SENSOR_DEVICE_ATTR ( in2_beep , S_IRUGO | S_IWUSR ,
show_beep , store_beep , 2 ) ;
static SENSOR_DEVICE_ATTR ( in3_beep , S_IRUGO | S_IWUSR ,
show_beep , store_beep , 3 ) ;
static SENSOR_DEVICE_ATTR ( in4_beep , S_IRUGO | S_IWUSR ,
show_beep , store_beep , 8 ) ;
static SENSOR_DEVICE_ATTR ( in5_beep , S_IRUGO | S_IWUSR ,
show_beep , store_beep , 9 ) ;
static SENSOR_DEVICE_ATTR ( in6_beep , S_IRUGO | S_IWUSR ,
show_beep , store_beep , 10 ) ;
static SENSOR_DEVICE_ATTR ( in7_beep , S_IRUGO | S_IWUSR ,
show_beep , store_beep , 16 ) ;
static SENSOR_DEVICE_ATTR ( in8_beep , S_IRUGO | S_IWUSR ,
show_beep , store_beep , 17 ) ;
static SENSOR_DEVICE_ATTR ( fan1_beep , S_IRUGO | S_IWUSR ,
show_beep , store_beep , 6 ) ;
static SENSOR_DEVICE_ATTR ( fan2_beep , S_IRUGO | S_IWUSR ,
show_beep , store_beep , 7 ) ;
static SENSOR_DEVICE_ATTR ( fan3_beep , S_IRUGO | S_IWUSR ,
show_beep , store_beep , 11 ) ;
static SENSOR_DEVICE_ATTR ( temp1_beep , S_IRUGO | S_IWUSR ,
show_beep , store_beep , 4 ) ;
static SENSOR_DEVICE_ATTR ( temp2_beep , S_IRUGO | S_IWUSR ,
show_beep , store_beep , 5 ) ;
static SENSOR_DEVICE_ATTR ( temp3_beep , S_IRUGO ,
show_temp3_beep , store_beep , 13 ) ;
2008-10-17 19:51:18 +04:00
static SENSOR_DEVICE_ATTR ( beep_enable , S_IRUGO | S_IWUSR ,
show_beep , store_beep , 15 ) ;
2007-10-08 20:29:43 +04:00
2005-04-17 02:20:36 +04:00
static ssize_t
2007-05-08 19:22:03 +04:00
show_fan_div ( struct device * dev , struct device_attribute * da , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-05-08 19:22:03 +04:00
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ;
2005-04-17 02:20:36 +04:00
struct w83781d_data * data = w83781d_update_device ( dev ) ;
return sprintf ( buf , " %ld \n " ,
2007-05-08 19:22:03 +04:00
( long ) DIV_FROM_REG ( data - > fan_div [ attr - > index ] ) ) ;
2005-04-17 02:20:36 +04:00
}
2012-01-19 23:02:27 +04:00
/*
* Note : we save and restore the fan minimum here , because its value is
* determined in part by the fan divisor . This follows the principle of
* least surprise ; the user doesn ' t expect the fan minimum to change just
* because the divisor changed .
*/
2005-04-17 02:20:36 +04:00
static ssize_t
2007-05-08 19:22:03 +04:00
store_fan_div ( struct device * dev , struct device_attribute * da ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2007-05-08 19:22:03 +04:00
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ;
2007-05-08 19:22:02 +04:00
struct w83781d_data * data = dev_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
unsigned long min ;
2007-05-08 19:22:03 +04:00
int nr = attr - > index ;
2005-04-17 02:20:36 +04:00
u8 reg ;
2012-01-15 21:19:16 +04:00
unsigned long val ;
int err ;
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
2005-04-17 02:20:36 +04:00
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2007-12-01 01:52:44 +03:00
2005-04-17 02:20:36 +04:00
/* Save fan_min */
min = FAN_FROM_REG ( data - > fan_min [ nr ] ,
DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ;
data - > fan_div [ nr ] = DIV_TO_REG ( val , data - > type ) ;
2012-01-15 21:19:16 +04:00
reg = ( w83781d_read_value ( data , nr = = 2 ?
W83781D_REG_PIN : W83781D_REG_VID_FANDIV )
& ( nr = = 0 ? 0xcf : 0x3f ) )
| ( ( data - > fan_div [ nr ] & 0x03 ) < < ( nr = = 0 ? 4 : 6 ) ) ;
w83781d_write_value ( data , nr = = 2 ?
W83781D_REG_PIN : W83781D_REG_VID_FANDIV , reg ) ;
2005-04-17 02:20:36 +04:00
/* w83781d and as99127f don't have extended divisor bits */
if ( data - > type ! = w83781d & & data - > type ! = as99127f ) {
2007-05-08 19:22:03 +04:00
reg = ( w83781d_read_value ( data , W83781D_REG_VBAT )
2005-04-17 02:20:36 +04:00
& ~ ( 1 < < ( 5 + nr ) ) )
| ( ( data - > fan_div [ nr ] & 0x04 ) < < ( 3 + nr ) ) ;
2007-05-08 19:22:03 +04:00
w83781d_write_value ( data , W83781D_REG_VBAT , reg ) ;
2005-04-17 02:20:36 +04:00
}
/* Restore fan_min */
data - > fan_min [ nr ] = FAN_TO_REG ( min , DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ;
2007-05-08 19:22:03 +04:00
w83781d_write_value ( data , W83781D_REG_FAN_MIN ( nr ) , data - > fan_min [ nr ] ) ;
2005-04-17 02:20:36 +04:00
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
2007-05-08 19:22:03 +04:00
static SENSOR_DEVICE_ATTR ( fan1_div , S_IRUGO | S_IWUSR ,
show_fan_div , store_fan_div , 0 ) ;
static SENSOR_DEVICE_ATTR ( fan2_div , S_IRUGO | S_IWUSR ,
show_fan_div , store_fan_div , 1 ) ;
static SENSOR_DEVICE_ATTR ( fan3_div , S_IRUGO | S_IWUSR ,
show_fan_div , store_fan_div , 2 ) ;
2005-04-17 02:20:36 +04:00
static ssize_t
2007-05-08 19:22:03 +04:00
show_pwm ( struct device * dev , struct device_attribute * da , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-05-08 19:22:03 +04:00
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ;
2005-04-17 02:20:36 +04:00
struct w83781d_data * data = w83781d_update_device ( dev ) ;
2007-05-08 19:22:03 +04:00
return sprintf ( buf , " %d \n " , ( int ) data - > pwm [ attr - > index ] ) ;
2005-04-17 02:20:36 +04:00
}
static ssize_t
2016-12-22 15:05:12 +03:00
pwm2_enable_show ( struct device * dev , struct device_attribute * da , char * buf )
2005-04-17 02:20:36 +04:00
{
struct w83781d_data * data = w83781d_update_device ( dev ) ;
2007-05-08 19:22:03 +04:00
return sprintf ( buf , " %d \n " , ( int ) data - > pwm2_enable ) ;
2005-04-17 02:20:36 +04:00
}
static ssize_t
2007-05-08 19:22:03 +04:00
store_pwm ( struct device * dev , struct device_attribute * da , const char * buf ,
size_t count )
2005-04-17 02:20:36 +04:00
{
2007-05-08 19:22:03 +04:00
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ;
2007-05-08 19:22:02 +04:00
struct w83781d_data * data = dev_get_drvdata ( dev ) ;
2007-05-08 19:22:03 +04:00
int nr = attr - > index ;
2012-01-15 21:19:16 +04:00
unsigned long val ;
int err ;
2005-04-17 02:20:36 +04:00
2012-01-15 21:19:16 +04:00
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
2005-04-17 02:20:36 +04:00
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2013-01-09 20:09:34 +04:00
data - > pwm [ nr ] = clamp_val ( val , 0 , 255 ) ;
2007-05-08 19:22:03 +04:00
w83781d_write_value ( data , W83781D_REG_PWM [ nr ] , data - > pwm [ nr ] ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
static ssize_t
2016-12-22 15:05:12 +03:00
pwm2_enable_store ( struct device * dev , struct device_attribute * da ,
2007-05-08 19:22:03 +04:00
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2007-05-08 19:22:02 +04:00
struct w83781d_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 21:19:16 +04:00
unsigned long val ;
u32 reg ;
int err ;
2005-04-17 02:20:36 +04:00
2012-01-15 21:19:16 +04:00
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
2005-04-17 02:20:36 +04:00
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
switch ( val ) {
case 0 :
case 1 :
2007-05-08 19:22:03 +04:00
reg = w83781d_read_value ( data , W83781D_REG_PWMCLK12 ) ;
w83781d_write_value ( data , W83781D_REG_PWMCLK12 ,
2005-04-17 02:20:36 +04:00
( reg & 0xf7 ) | ( val < < 3 ) ) ;
2007-05-08 19:22:03 +04:00
reg = w83781d_read_value ( data , W83781D_REG_BEEP_CONFIG ) ;
w83781d_write_value ( data , W83781D_REG_BEEP_CONFIG ,
2005-04-17 02:20:36 +04:00
( reg & 0xef ) | ( ! val < < 4 ) ) ;
2007-05-08 19:22:03 +04:00
data - > pwm2_enable = val ;
2005-04-17 02:20:36 +04:00
break ;
default :
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
2007-05-08 19:22:03 +04:00
static SENSOR_DEVICE_ATTR ( pwm1 , S_IRUGO | S_IWUSR , show_pwm , store_pwm , 0 ) ;
static SENSOR_DEVICE_ATTR ( pwm2 , S_IRUGO | S_IWUSR , show_pwm , store_pwm , 1 ) ;
static SENSOR_DEVICE_ATTR ( pwm3 , S_IRUGO | S_IWUSR , show_pwm , store_pwm , 2 ) ;
static SENSOR_DEVICE_ATTR ( pwm4 , S_IRUGO | S_IWUSR , show_pwm , store_pwm , 3 ) ;
/* only PWM2 can be enabled/disabled */
2016-12-22 15:05:12 +03:00
static DEVICE_ATTR_RW ( pwm2_enable ) ;
2005-04-17 02:20:36 +04:00
static ssize_t
2007-05-08 19:22:03 +04:00
show_sensor ( struct device * dev , struct device_attribute * da , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-05-08 19:22:03 +04:00
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ;
2005-04-17 02:20:36 +04:00
struct w83781d_data * data = w83781d_update_device ( dev ) ;
2007-05-08 19:22:03 +04:00
return sprintf ( buf , " %d \n " , ( int ) data - > sens [ attr - > index ] ) ;
2005-04-17 02:20:36 +04:00
}
static ssize_t
2007-05-08 19:22:03 +04:00
store_sensor ( struct device * dev , struct device_attribute * da ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2007-05-08 19:22:03 +04:00
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ;
2007-05-08 19:22:02 +04:00
struct w83781d_data * data = dev_get_drvdata ( dev ) ;
2007-05-08 19:22:03 +04:00
int nr = attr - > index ;
2012-01-15 21:19:16 +04:00
unsigned long val ;
u32 tmp ;
int err ;
2005-04-17 02:20:36 +04:00
2012-01-15 21:19:16 +04:00
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
2005-04-17 02:20:36 +04:00
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
switch ( val ) {
case 1 : /* PII/Celeron diode */
2007-05-08 19:22:03 +04:00
tmp = w83781d_read_value ( data , W83781D_REG_SCFG1 ) ;
w83781d_write_value ( data , W83781D_REG_SCFG1 ,
2007-05-08 19:22:03 +04:00
tmp | BIT_SCFG1 [ nr ] ) ;
2007-05-08 19:22:03 +04:00
tmp = w83781d_read_value ( data , W83781D_REG_SCFG2 ) ;
w83781d_write_value ( data , W83781D_REG_SCFG2 ,
2007-05-08 19:22:03 +04:00
tmp | BIT_SCFG2 [ nr ] ) ;
data - > sens [ nr ] = val ;
2005-04-17 02:20:36 +04:00
break ;
case 2 : /* 3904 */
2007-05-08 19:22:03 +04:00
tmp = w83781d_read_value ( data , W83781D_REG_SCFG1 ) ;
w83781d_write_value ( data , W83781D_REG_SCFG1 ,
2007-05-08 19:22:03 +04:00
tmp | BIT_SCFG1 [ nr ] ) ;
2007-05-08 19:22:03 +04:00
tmp = w83781d_read_value ( data , W83781D_REG_SCFG2 ) ;
w83781d_write_value ( data , W83781D_REG_SCFG2 ,
2007-05-08 19:22:03 +04:00
tmp & ~ BIT_SCFG2 [ nr ] ) ;
data - > sens [ nr ] = val ;
2005-04-17 02:20:36 +04:00
break ;
2007-08-16 16:30:01 +04:00
case W83781D_DEFAULT_BETA :
2013-01-10 22:01:24 +04:00
dev_warn ( dev ,
" Sensor type %d is deprecated, please use 4 instead \n " ,
W83781D_DEFAULT_BETA ) ;
2020-08-24 01:36:59 +03:00
fallthrough ;
2007-08-16 16:30:01 +04:00
case 4 : /* thermistor */
2007-05-08 19:22:03 +04:00
tmp = w83781d_read_value ( data , W83781D_REG_SCFG1 ) ;
w83781d_write_value ( data , W83781D_REG_SCFG1 ,
2007-05-08 19:22:03 +04:00
tmp & ~ BIT_SCFG1 [ nr ] ) ;
data - > sens [ nr ] = val ;
2005-04-17 02:20:36 +04:00
break ;
default :
2007-08-16 16:30:01 +04:00
dev_err ( dev , " Invalid sensor type %ld; must be 1, 2, or 4 \n " ,
( long ) val ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
2007-05-08 19:22:03 +04:00
static SENSOR_DEVICE_ATTR ( temp1_type , S_IRUGO | S_IWUSR ,
show_sensor , store_sensor , 0 ) ;
static SENSOR_DEVICE_ATTR ( temp2_type , S_IRUGO | S_IWUSR ,
2007-08-09 16:12:46 +04:00
show_sensor , store_sensor , 1 ) ;
2007-05-08 19:22:03 +04:00
static SENSOR_DEVICE_ATTR ( temp3_type , S_IRUGO | S_IWUSR ,
2007-08-09 16:12:46 +04:00
show_sensor , store_sensor , 2 ) ;
2005-04-17 02:20:36 +04:00
2012-01-19 23:02:27 +04:00
/*
* Assumes that adapter is of I2C , not ISA variety .
2005-04-17 02:20:36 +04:00
* OTHERWISE DON ' T CALL THIS
*/
static int
2008-10-17 19:51:19 +04:00
w83781d_detect_subclients ( struct i2c_client * new_client )
2005-04-17 02:20:36 +04:00
{
int i , val1 = 0 , id ;
int err ;
2008-10-17 19:51:19 +04:00
int address = new_client - > addr ;
unsigned short sc_addr [ 2 ] ;
struct i2c_adapter * adapter = new_client - > adapter ;
2005-04-17 02:20:36 +04:00
struct w83781d_data * data = i2c_get_clientdata ( new_client ) ;
2008-10-17 19:51:19 +04:00
enum chips kind = data - > type ;
2012-06-12 19:27:49 +04:00
int num_sc = 1 ;
2005-04-17 02:20:36 +04:00
id = i2c_adapter_id ( adapter ) ;
if ( force_subclients [ 0 ] = = id & & force_subclients [ 1 ] = = address ) {
for ( i = 2 ; i < = 3 ; i + + ) {
if ( force_subclients [ i ] < 0x48 | |
force_subclients [ i ] > 0x4f ) {
2013-01-10 22:01:24 +04:00
dev_err ( & new_client - > dev ,
" Invalid subclient address %d; must be 0x48-0x4f \n " ,
2005-04-17 02:20:36 +04:00
force_subclients [ i ] ) ;
err = - EINVAL ;
goto ERROR_SC_1 ;
}
}
2007-05-08 19:22:03 +04:00
w83781d_write_value ( data , W83781D_REG_I2C_SUBADDR ,
2005-04-17 02:20:36 +04:00
( force_subclients [ 2 ] & 0x07 ) |
( ( force_subclients [ 3 ] & 0x07 ) < < 4 ) ) ;
2008-10-17 19:51:19 +04:00
sc_addr [ 0 ] = force_subclients [ 2 ] ;
2005-04-17 02:20:36 +04:00
} else {
2007-05-08 19:22:03 +04:00
val1 = w83781d_read_value ( data , W83781D_REG_I2C_SUBADDR ) ;
2008-10-17 19:51:19 +04:00
sc_addr [ 0 ] = 0x48 + ( val1 & 0x07 ) ;
2005-04-17 02:20:36 +04:00
}
if ( kind ! = w83783s ) {
2012-06-12 19:27:49 +04:00
num_sc = 2 ;
2005-04-17 02:20:36 +04:00
if ( force_subclients [ 0 ] = = id & &
force_subclients [ 1 ] = = address ) {
2008-10-17 19:51:19 +04:00
sc_addr [ 1 ] = force_subclients [ 3 ] ;
2005-04-17 02:20:36 +04:00
} else {
2008-10-17 19:51:19 +04:00
sc_addr [ 1 ] = 0x48 + ( ( val1 > > 4 ) & 0x07 ) ;
2005-04-17 02:20:36 +04:00
}
2008-10-17 19:51:19 +04:00
if ( sc_addr [ 0 ] = = sc_addr [ 1 ] ) {
2005-04-17 02:20:36 +04:00
dev_err ( & new_client - > dev ,
" Duplicate addresses 0x%x for subclients. \n " ,
2008-10-17 19:51:19 +04:00
sc_addr [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
err = - EBUSY ;
goto ERROR_SC_2 ;
}
}
2012-06-12 19:27:49 +04:00
for ( i = 0 ; i < num_sc ; i + + ) {
2019-07-22 20:26:10 +03:00
data - > lm75 [ i ] = i2c_new_dummy_device ( adapter , sc_addr [ i ] ) ;
if ( IS_ERR ( data - > lm75 [ i ] ) ) {
2013-01-10 22:01:24 +04:00
dev_err ( & new_client - > dev ,
" Subclient %d registration at address 0x%x failed. \n " ,
i , sc_addr [ i ] ) ;
2019-07-22 20:26:10 +03:00
err = PTR_ERR ( data - > lm75 [ i ] ) ;
2005-04-17 02:20:36 +04:00
if ( i = = 1 )
goto ERROR_SC_3 ;
goto ERROR_SC_2 ;
}
}
return 0 ;
/* Undo inits in case of errors */
ERROR_SC_3 :
2008-10-17 19:51:19 +04:00
i2c_unregister_device ( data - > lm75 [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
ERROR_SC_2 :
ERROR_SC_1 :
return err ;
}
2007-05-08 19:22:03 +04:00
# define IN_UNIT_ATTRS(X) \
& sensor_dev_attr_in # # X # # _input . dev_attr . attr , \
& sensor_dev_attr_in # # X # # _min . dev_attr . attr , \
2007-12-01 01:52:44 +03:00
& sensor_dev_attr_in # # X # # _max . dev_attr . attr , \
2007-10-08 20:29:43 +04:00
& sensor_dev_attr_in # # X # # _alarm . dev_attr . attr , \
& sensor_dev_attr_in # # X # # _beep . dev_attr . attr
2006-09-24 23:22:52 +04:00
2007-05-08 19:22:03 +04:00
# define FAN_UNIT_ATTRS(X) \
& sensor_dev_attr_fan # # X # # _input . dev_attr . attr , \
& sensor_dev_attr_fan # # X # # _min . dev_attr . attr , \
2007-10-08 20:29:43 +04:00
& sensor_dev_attr_fan # # X # # _div . dev_attr . attr , \
& sensor_dev_attr_fan # # X # # _alarm . dev_attr . attr , \
& sensor_dev_attr_fan # # X # # _beep . dev_attr . attr
2006-09-24 23:22:52 +04:00
2007-05-08 19:22:03 +04:00
# define TEMP_UNIT_ATTRS(X) \
& sensor_dev_attr_temp # # X # # _input . dev_attr . attr , \
& sensor_dev_attr_temp # # X # # _max . dev_attr . attr , \
2007-10-08 20:29:43 +04:00
& sensor_dev_attr_temp # # X # # _max_hyst . dev_attr . attr , \
& sensor_dev_attr_temp # # X # # _alarm . dev_attr . attr , \
& sensor_dev_attr_temp # # X # # _beep . dev_attr . attr
2006-09-24 23:22:52 +04:00
2012-01-15 21:19:16 +04:00
static struct attribute * w83781d_attributes [ ] = {
2006-09-24 23:22:52 +04:00
IN_UNIT_ATTRS ( 0 ) ,
IN_UNIT_ATTRS ( 2 ) ,
IN_UNIT_ATTRS ( 3 ) ,
IN_UNIT_ATTRS ( 4 ) ,
IN_UNIT_ATTRS ( 5 ) ,
IN_UNIT_ATTRS ( 6 ) ,
FAN_UNIT_ATTRS ( 1 ) ,
FAN_UNIT_ATTRS ( 2 ) ,
FAN_UNIT_ATTRS ( 3 ) ,
TEMP_UNIT_ATTRS ( 1 ) ,
TEMP_UNIT_ATTRS ( 2 ) ,
& dev_attr_cpu0_vid . attr ,
& dev_attr_vrm . attr ,
& dev_attr_alarms . attr ,
& dev_attr_beep_mask . attr ,
2008-10-17 19:51:18 +04:00
& sensor_dev_attr_beep_enable . dev_attr . attr ,
2006-09-24 23:22:52 +04:00
NULL
} ;
static const struct attribute_group w83781d_group = {
. attrs = w83781d_attributes ,
} ;
2012-01-17 08:45:16 +04:00
static struct attribute * w83781d_attributes_in1 [ ] = {
2006-09-24 23:22:52 +04:00
IN_UNIT_ATTRS ( 1 ) ,
2012-01-17 08:45:16 +04:00
NULL
} ;
static const struct attribute_group w83781d_group_in1 = {
. attrs = w83781d_attributes_in1 ,
} ;
static struct attribute * w83781d_attributes_in78 [ ] = {
2006-09-24 23:22:52 +04:00
IN_UNIT_ATTRS ( 7 ) ,
IN_UNIT_ATTRS ( 8 ) ,
2012-01-17 08:45:16 +04:00
NULL
} ;
static const struct attribute_group w83781d_group_in78 = {
. attrs = w83781d_attributes_in78 ,
} ;
static struct attribute * w83781d_attributes_temp3 [ ] = {
2006-09-24 23:22:52 +04:00
TEMP_UNIT_ATTRS ( 3 ) ,
2012-01-17 08:45:16 +04:00
NULL
} ;
static const struct attribute_group w83781d_group_temp3 = {
. attrs = w83781d_attributes_temp3 ,
} ;
static struct attribute * w83781d_attributes_pwm12 [ ] = {
2007-05-08 19:22:03 +04:00
& sensor_dev_attr_pwm1 . dev_attr . attr ,
& sensor_dev_attr_pwm2 . dev_attr . attr ,
2012-01-17 08:45:16 +04:00
& dev_attr_pwm2_enable . attr ,
NULL
} ;
static const struct attribute_group w83781d_group_pwm12 = {
. attrs = w83781d_attributes_pwm12 ,
} ;
static struct attribute * w83781d_attributes_pwm34 [ ] = {
2007-05-08 19:22:03 +04:00
& sensor_dev_attr_pwm3 . dev_attr . attr ,
& sensor_dev_attr_pwm4 . dev_attr . attr ,
2012-01-17 08:45:16 +04:00
NULL
} ;
static const struct attribute_group w83781d_group_pwm34 = {
. attrs = w83781d_attributes_pwm34 ,
} ;
static struct attribute * w83781d_attributes_other [ ] = {
2007-05-08 19:22:03 +04:00
& sensor_dev_attr_temp1_type . dev_attr . attr ,
& sensor_dev_attr_temp2_type . dev_attr . attr ,
& sensor_dev_attr_temp3_type . dev_attr . attr ,
2006-09-24 23:22:52 +04:00
NULL
} ;
2012-01-17 08:45:16 +04:00
static const struct attribute_group w83781d_group_other = {
. attrs = w83781d_attributes_other ,
2006-09-24 23:22:52 +04:00
} ;
2007-05-08 19:22:02 +04:00
/* No clean up is done on error, it's up to the caller */
2005-04-17 02:20:36 +04:00
static int
2007-05-08 19:22:02 +04:00
w83781d_create_files ( struct device * dev , int kind , int is_isa )
2005-04-17 02:20:36 +04:00
{
int err ;
2012-01-15 21:19:16 +04:00
err = sysfs_create_group ( & dev - > kobj , & w83781d_group ) ;
if ( err )
2007-05-08 19:22:02 +04:00
return err ;
if ( kind ! = w83783s ) {
2012-01-17 08:45:16 +04:00
err = sysfs_create_group ( & dev - > kobj , & w83781d_group_in1 ) ;
if ( err )
2007-05-08 19:22:02 +04:00
return err ;
}
if ( kind ! = as99127f & & kind ! = w83781d & & kind ! = w83783s ) {
2012-01-17 08:45:16 +04:00
err = sysfs_create_group ( & dev - > kobj , & w83781d_group_in78 ) ;
if ( err )
2007-05-08 19:22:02 +04:00
return err ;
}
if ( kind ! = w83783s ) {
2012-01-17 08:45:16 +04:00
err = sysfs_create_group ( & dev - > kobj , & w83781d_group_temp3 ) ;
if ( err )
2007-05-08 19:22:02 +04:00
return err ;
2007-10-08 20:29:43 +04:00
2007-10-25 15:11:01 +04:00
if ( kind ! = w83781d ) {
2007-10-08 20:29:43 +04:00
err = sysfs_chmod_file ( & dev - > kobj ,
& sensor_dev_attr_temp3_alarm . dev_attr . attr ,
S_IRUGO | S_IWUSR ) ;
if ( err )
return err ;
2007-10-25 15:11:01 +04:00
}
2005-04-17 02:20:36 +04:00
}
2007-05-08 19:22:02 +04:00
if ( kind ! = w83781d & & kind ! = as99127f ) {
2012-01-17 08:45:16 +04:00
err = sysfs_create_group ( & dev - > kobj , & w83781d_group_pwm12 ) ;
if ( err )
2007-05-08 19:22:02 +04:00
return err ;
2005-04-17 02:20:36 +04:00
}
2007-05-08 19:22:02 +04:00
if ( kind = = w83782d & & ! is_isa ) {
2012-01-17 08:45:16 +04:00
err = sysfs_create_group ( & dev - > kobj , & w83781d_group_pwm34 ) ;
if ( err )
2007-05-08 19:22:02 +04:00
return err ;
}
if ( kind ! = as99127f & & kind ! = w83781d ) {
2012-01-17 08:45:16 +04:00
err = device_create_file ( dev ,
& sensor_dev_attr_temp1_type . dev_attr ) ;
if ( err )
return err ;
err = device_create_file ( dev ,
& sensor_dev_attr_temp2_type . dev_attr ) ;
if ( err )
2007-05-08 19:22:02 +04:00
return err ;
if ( kind ! = w83783s ) {
2012-01-15 21:19:16 +04:00
err = device_create_file ( dev ,
2012-01-17 08:45:16 +04:00
& sensor_dev_attr_temp3_type . dev_attr ) ;
2012-01-15 21:19:16 +04:00
if ( err )
2007-05-08 19:22:02 +04:00
return err ;
2005-04-17 02:20:36 +04:00
}
2007-05-08 19:22:02 +04:00
}
2005-04-17 02:20:36 +04:00
2007-05-08 19:22:02 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
2008-10-17 19:51:19 +04:00
/* Return 0 if detection is successful, -ENODEV otherwise */
2007-05-08 19:22:02 +04:00
static int
2009-12-14 23:17:23 +03:00
w83781d_detect ( struct i2c_client * client , struct i2c_board_info * info )
2007-05-08 19:22:02 +04:00
{
2009-12-09 22:35:54 +03:00
int val1 , val2 ;
2008-10-17 19:51:19 +04:00
struct w83781d_data * isa = w83781d_data_if_isa ( ) ;
struct i2c_adapter * adapter = client - > adapter ;
int address = client - > addr ;
2009-12-09 22:35:54 +03:00
const char * client_name ;
2007-05-08 19:22:02 +04:00
enum vendor { winbond , asus } vendid ;
2008-10-17 19:51:19 +04:00
if ( ! i2c_check_functionality ( adapter , I2C_FUNC_SMBUS_BYTE_DATA ) )
return - ENODEV ;
2005-04-17 02:20:36 +04:00
2012-01-19 23:02:27 +04:00
/*
* We block updates of the ISA device to minimize the risk of
* concurrent access to the same W83781D chip through different
* interfaces .
*/
2008-10-17 19:51:19 +04:00
if ( isa )
mutex_lock ( & isa - > update_lock ) ;
2005-04-17 02:20:36 +04:00
2009-12-09 22:35:54 +03:00
if ( i2c_smbus_read_byte_data ( client , W83781D_REG_CONFIG ) & 0x80 ) {
dev_dbg ( & adapter - > dev ,
" Detection of w83781d chip failed at step 3 \n " ) ;
goto err_nodev ;
}
val1 = i2c_smbus_read_byte_data ( client , W83781D_REG_BANK ) ;
val2 = i2c_smbus_read_byte_data ( client , W83781D_REG_CHIPMAN ) ;
/* Check for Winbond or Asus ID if in bank 0 */
if ( ! ( val1 & 0x07 ) & &
( ( ! ( val1 & 0x80 ) & & val2 ! = 0xa3 & & val2 ! = 0xc3 ) | |
2012-01-15 21:19:16 +04:00
( ( val1 & 0x80 ) & & val2 ! = 0x5c & & val2 ! = 0x12 ) ) ) {
2009-12-09 22:35:54 +03:00
dev_dbg ( & adapter - > dev ,
" Detection of w83781d chip failed at step 4 \n " ) ;
goto err_nodev ;
}
2012-01-19 23:02:27 +04:00
/*
* If Winbond SMBus , check address at 0x48 .
* Asus doesn ' t support , except for as99127f rev .2
*/
2009-12-09 22:35:54 +03:00
if ( ( ! ( val1 & 0x80 ) & & val2 = = 0xa3 ) | |
2012-01-15 21:19:16 +04:00
( ( val1 & 0x80 ) & & val2 = = 0x5c ) ) {
2009-12-09 22:35:54 +03:00
if ( i2c_smbus_read_byte_data ( client , W83781D_REG_I2C_ADDR )
! = address ) {
dev_dbg ( & adapter - > dev ,
" Detection of w83781d chip failed at step 5 \n " ) ;
2008-10-17 19:51:19 +04:00
goto err_nodev ;
2005-04-17 02:20:36 +04:00
}
}
2009-12-09 22:35:54 +03:00
/* Put it now into bank 0 and Vendor ID High Byte */
2008-10-17 19:51:19 +04:00
i2c_smbus_write_byte_data ( client , W83781D_REG_BANK ,
( i2c_smbus_read_byte_data ( client , W83781D_REG_BANK )
& 0x78 ) | 0x80 ) ;
2005-04-17 02:20:36 +04:00
2009-12-09 22:35:54 +03:00
/* Get the vendor ID */
val2 = i2c_smbus_read_byte_data ( client , W83781D_REG_CHIPMAN ) ;
if ( val2 = = 0x5c )
vendid = winbond ;
else if ( val2 = = 0x12 )
vendid = asus ;
else {
dev_dbg ( & adapter - > dev ,
" w83781d chip vendor is neither Winbond nor Asus \n " ) ;
goto err_nodev ;
2005-04-17 02:20:36 +04:00
}
2009-12-09 22:35:54 +03:00
/* Determine the chip type. */
val1 = i2c_smbus_read_byte_data ( client , W83781D_REG_WCHIPID ) ;
if ( ( val1 = = 0x10 | | val1 = = 0x11 ) & & vendid = = winbond )
2005-04-17 02:20:36 +04:00
client_name = " w83781d " ;
2009-12-09 22:35:54 +03:00
else if ( val1 = = 0x30 & & vendid = = winbond )
2005-04-17 02:20:36 +04:00
client_name = " w83782d " ;
2009-12-09 22:35:54 +03:00
else if ( val1 = = 0x40 & & vendid = = winbond & & address = = 0x2d )
2005-04-17 02:20:36 +04:00
client_name = " w83783s " ;
2009-12-09 22:35:54 +03:00
else if ( val1 = = 0x31 )
2005-04-17 02:20:36 +04:00
client_name = " as99127f " ;
2009-12-09 22:35:54 +03:00
else
goto err_nodev ;
if ( val1 < = 0x30 & & w83781d_alias_detect ( client , val1 ) ) {
2013-01-10 22:01:24 +04:00
dev_dbg ( & adapter - > dev ,
" Device at 0x%02x appears to be the same as ISA device \n " ,
address ) ;
2009-12-09 22:35:54 +03:00
goto err_nodev ;
2005-04-17 02:20:36 +04:00
}
2009-12-09 22:35:54 +03:00
if ( isa )
mutex_unlock ( & isa - > update_lock ) ;
2008-10-17 19:51:19 +04:00
strlcpy ( info - > type , client_name , I2C_NAME_SIZE ) ;
return 0 ;
err_nodev :
if ( isa )
mutex_unlock ( & isa - > update_lock ) ;
return - ENODEV ;
}
2012-01-17 08:45:16 +04:00
static void w83781d_remove_files ( struct device * dev )
{
sysfs_remove_group ( & dev - > kobj , & w83781d_group ) ;
sysfs_remove_group ( & dev - > kobj , & w83781d_group_in1 ) ;
sysfs_remove_group ( & dev - > kobj , & w83781d_group_in78 ) ;
sysfs_remove_group ( & dev - > kobj , & w83781d_group_temp3 ) ;
sysfs_remove_group ( & dev - > kobj , & w83781d_group_pwm12 ) ;
sysfs_remove_group ( & dev - > kobj , & w83781d_group_pwm34 ) ;
sysfs_remove_group ( & dev - > kobj , & w83781d_group_other ) ;
}
2020-08-13 19:02:22 +03:00
static const struct i2c_device_id w83781d_ids [ ] ;
static int w83781d_probe ( struct i2c_client * client )
2008-10-17 19:51:19 +04:00
{
struct device * dev = & client - > dev ;
struct w83781d_data * data ;
int err ;
2012-06-02 22:48:00 +04:00
data = devm_kzalloc ( dev , sizeof ( struct w83781d_data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
2008-10-17 19:51:19 +04:00
i2c_set_clientdata ( client , data ) ;
mutex_init ( & data - > lock ) ;
mutex_init ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
2020-08-13 19:02:22 +03:00
data - > type = i2c_match_id ( w83781d_ids , client ) - > driver_data ;
2008-10-17 19:51:19 +04:00
data - > client = client ;
2005-04-17 02:20:36 +04:00
/* attach secondary i2c lm75-like clients */
2008-10-17 19:51:19 +04:00
err = w83781d_detect_subclients ( client ) ;
if ( err )
2012-06-02 22:48:00 +04:00
return err ;
2005-04-17 02:20:36 +04:00
/* Initialize the chip */
2007-05-08 19:22:02 +04:00
w83781d_init_device ( dev ) ;
2005-04-17 02:20:36 +04:00
/* Register sysfs hooks */
2008-10-17 19:51:19 +04:00
err = w83781d_create_files ( dev , data - > type , 0 ) ;
2007-05-08 19:22:02 +04:00
if ( err )
2012-06-02 22:48:00 +04:00
goto exit_remove_files ;
2005-07-16 05:39:18 +04:00
2007-08-21 00:46:20 +04:00
data - > hwmon_dev = hwmon_device_register ( dev ) ;
if ( IS_ERR ( data - > hwmon_dev ) ) {
err = PTR_ERR ( data - > hwmon_dev ) ;
2012-06-02 22:48:00 +04:00
goto exit_remove_files ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
2012-06-02 22:48:00 +04:00
exit_remove_files :
2012-01-17 08:45:16 +04:00
w83781d_remove_files ( dev ) ;
2017-10-31 17:21:43 +03:00
i2c_unregister_device ( data - > lm75 [ 0 ] ) ;
i2c_unregister_device ( data - > lm75 [ 1 ] ) ;
2005-04-17 02:20:36 +04:00
return err ;
}
static int
2008-10-17 19:51:19 +04:00
w83781d_remove ( struct i2c_client * client )
2005-04-17 02:20:36 +04:00
{
2005-07-16 05:39:18 +04:00
struct w83781d_data * data = i2c_get_clientdata ( client ) ;
2008-10-17 19:51:19 +04:00
struct device * dev = & client - > dev ;
2005-04-17 02:20:36 +04:00
2008-10-17 19:51:19 +04:00
hwmon_device_unregister ( data - > hwmon_dev ) ;
2012-01-17 08:45:16 +04:00
w83781d_remove_files ( dev ) ;
2005-04-17 02:20:36 +04:00
2017-10-31 17:21:43 +03:00
i2c_unregister_device ( data - > lm75 [ 0 ] ) ;
i2c_unregister_device ( data - > lm75 [ 1 ] ) ;
2005-07-16 05:39:18 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int
2008-10-17 19:51:18 +04:00
w83781d_read_value_i2c ( struct w83781d_data * data , u16 reg )
2005-04-17 02:20:36 +04:00
{
2008-10-17 19:51:19 +04:00
struct i2c_client * client = data - > client ;
2008-10-17 19:51:18 +04:00
int res , bank ;
2005-04-17 02:20:36 +04:00
struct i2c_client * cl ;
2008-10-17 19:51:18 +04:00
bank = ( reg > > 8 ) & 0x0f ;
if ( bank > 2 )
/* switch banks */
i2c_smbus_write_byte_data ( client , W83781D_REG_BANK ,
bank ) ;
if ( bank = = 0 | | bank > 2 ) {
res = i2c_smbus_read_byte_data ( client , reg & 0xff ) ;
2005-04-17 02:20:36 +04:00
} else {
2008-10-17 19:51:18 +04:00
/* switch to subclient */
cl = data - > lm75 [ bank - 1 ] ;
/* convert from ISA to LM75 I2C addresses */
switch ( reg & 0xff ) {
case 0x50 : /* TEMP */
2011-11-04 15:00:47 +04:00
res = i2c_smbus_read_word_swapped ( cl , 0 ) ;
2008-10-17 19:51:18 +04:00
break ;
case 0x52 : /* CONFIG */
res = i2c_smbus_read_byte_data ( cl , 1 ) ;
break ;
case 0x53 : /* HYST */
2011-11-04 15:00:47 +04:00
res = i2c_smbus_read_word_swapped ( cl , 2 ) ;
2008-10-17 19:51:18 +04:00
break ;
case 0x55 : /* OVER */
default :
2011-11-04 15:00:47 +04:00
res = i2c_smbus_read_word_swapped ( cl , 3 ) ;
2008-10-17 19:51:18 +04:00
break ;
2005-04-17 02:20:36 +04:00
}
}
2008-10-17 19:51:18 +04:00
if ( bank > 2 )
i2c_smbus_write_byte_data ( client , W83781D_REG_BANK , 0 ) ;
2005-04-17 02:20:36 +04:00
return res ;
}
static int
2008-10-17 19:51:18 +04:00
w83781d_write_value_i2c ( struct w83781d_data * data , u16 reg , u16 value )
2005-04-17 02:20:36 +04:00
{
2008-10-17 19:51:19 +04:00
struct i2c_client * client = data - > client ;
2008-10-17 19:51:18 +04:00
int bank ;
2005-04-17 02:20:36 +04:00
struct i2c_client * cl ;
2008-10-17 19:51:18 +04:00
bank = ( reg > > 8 ) & 0x0f ;
if ( bank > 2 )
/* switch banks */
i2c_smbus_write_byte_data ( client , W83781D_REG_BANK ,
bank ) ;
if ( bank = = 0 | | bank > 2 ) {
i2c_smbus_write_byte_data ( client , reg & 0xff ,
value & 0xff ) ;
2005-04-17 02:20:36 +04:00
} else {
2008-10-17 19:51:18 +04:00
/* switch to subclient */
cl = data - > lm75 [ bank - 1 ] ;
/* convert from ISA to LM75 I2C addresses */
switch ( reg & 0xff ) {
case 0x52 : /* CONFIG */
i2c_smbus_write_byte_data ( cl , 1 , value & 0xff ) ;
break ;
case 0x53 : /* HYST */
2011-11-04 15:00:47 +04:00
i2c_smbus_write_word_swapped ( cl , 2 , value ) ;
2008-10-17 19:51:18 +04:00
break ;
case 0x55 : /* OVER */
2011-11-04 15:00:47 +04:00
i2c_smbus_write_word_swapped ( cl , 3 , value ) ;
2008-10-17 19:51:18 +04:00
break ;
2005-04-17 02:20:36 +04:00
}
}
2008-10-17 19:51:18 +04:00
if ( bank > 2 )
i2c_smbus_write_byte_data ( client , W83781D_REG_BANK , 0 ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static void
2007-05-08 19:22:02 +04:00
w83781d_init_device ( struct device * dev )
2005-04-17 02:20:36 +04:00
{
2007-05-08 19:22:02 +04:00
struct w83781d_data * data = dev_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
int i , p ;
int type = data - > type ;
u8 tmp ;
2012-01-19 23:02:27 +04:00
if ( reset & & type ! = as99127f ) { /*
* this resets registers we don ' t have
* documentation for on the as99127f
*/
/*
* Resetting the chip has been the default for a long time ,
* but it causes the BIOS initializations ( fan clock dividers ,
* thermal sensor types . . . ) to be lost , so it is now optional .
* It might even go away if nobody reports it as being useful ,
* as I see very little reason why this would be needed at
* all .
*/
2013-01-10 22:01:24 +04:00
dev_info ( dev ,
" If reset=1 solved a problem you were having, please report! \n " ) ;
2006-02-06 01:26:51 +03:00
2005-04-17 02:20:36 +04:00
/* save these registers */
2007-05-08 19:22:03 +04:00
i = w83781d_read_value ( data , W83781D_REG_BEEP_CONFIG ) ;
p = w83781d_read_value ( data , W83781D_REG_PWMCLK12 ) ;
2012-01-19 23:02:27 +04:00
/*
* Reset all except Watchdog values and last conversion values
* This sets fan - divs to 2 , among others
*/
2007-05-08 19:22:03 +04:00
w83781d_write_value ( data , W83781D_REG_CONFIG , 0x80 ) ;
2012-01-19 23:02:27 +04:00
/*
* Restore the registers and disable power - on abnormal beep .
* This saves FAN 1 / 2 / 3 input / output values set by BIOS .
*/
2007-05-08 19:22:03 +04:00
w83781d_write_value ( data , W83781D_REG_BEEP_CONFIG , i | 0x80 ) ;
w83781d_write_value ( data , W83781D_REG_PWMCLK12 , p ) ;
2012-01-15 21:19:16 +04:00
/*
* Disable master beep - enable ( reset turns it on ) .
* Individual beep_mask should be reset to off but for some
* reason disabling this bit helps some people not get beeped
*/
2007-05-08 19:22:03 +04:00
w83781d_write_value ( data , W83781D_REG_BEEP_INTS2 , 0 ) ;
2005-04-17 02:20:36 +04:00
}
2012-01-19 23:02:27 +04:00
/*
* Disable power - on abnormal beep , as advised by the datasheet .
* Already done if reset = 1.
*/
2006-02-06 01:26:51 +03:00
if ( init & & ! reset & & type ! = as99127f ) {
2007-05-08 19:22:03 +04:00
i = w83781d_read_value ( data , W83781D_REG_BEEP_CONFIG ) ;
w83781d_write_value ( data , W83781D_REG_BEEP_CONFIG , i | 0x80 ) ;
2006-02-06 01:26:51 +03:00
}
2005-07-31 23:52:01 +04:00
data - > vrm = vid_which_vrm ( ) ;
2005-04-17 02:20:36 +04:00
if ( ( type ! = w83781d ) & & ( type ! = as99127f ) ) {
2007-05-08 19:22:03 +04:00
tmp = w83781d_read_value ( data , W83781D_REG_SCFG1 ) ;
2005-04-17 02:20:36 +04:00
for ( i = 1 ; i < = 3 ; i + + ) {
if ( ! ( tmp & BIT_SCFG1 [ i - 1 ] ) ) {
2007-08-16 16:30:01 +04:00
data - > sens [ i - 1 ] = 4 ;
2005-04-17 02:20:36 +04:00
} else {
if ( w83781d_read_value
2007-05-08 19:22:03 +04:00
( data ,
2005-04-17 02:20:36 +04:00
W83781D_REG_SCFG2 ) & BIT_SCFG2 [ i - 1 ] )
data - > sens [ i - 1 ] = 1 ;
else
data - > sens [ i - 1 ] = 2 ;
}
2005-06-16 21:24:14 +04:00
if ( type = = w83783s & & i = = 2 )
2005-04-17 02:20:36 +04:00
break ;
}
}
if ( init & & type ! = as99127f ) {
/* Enable temp2 */
2007-05-08 19:22:03 +04:00
tmp = w83781d_read_value ( data , W83781D_REG_TEMP2_CONFIG ) ;
2005-04-17 02:20:36 +04:00
if ( tmp & 0x01 ) {
2013-01-10 22:01:24 +04:00
dev_warn ( dev ,
" Enabling temp2, readings might not make sense \n " ) ;
2007-05-08 19:22:03 +04:00
w83781d_write_value ( data , W83781D_REG_TEMP2_CONFIG ,
2005-04-17 02:20:36 +04:00
tmp & 0xfe ) ;
}
/* Enable temp3 */
2005-06-16 21:24:14 +04:00
if ( type ! = w83783s ) {
2007-05-08 19:22:03 +04:00
tmp = w83781d_read_value ( data ,
2005-04-17 02:20:36 +04:00
W83781D_REG_TEMP3_CONFIG ) ;
if ( tmp & 0x01 ) {
2013-01-10 22:01:24 +04:00
dev_warn ( dev ,
" Enabling temp3, readings might not make sense \n " ) ;
2007-05-08 19:22:03 +04:00
w83781d_write_value ( data ,
2005-04-17 02:20:36 +04:00
W83781D_REG_TEMP3_CONFIG , tmp & 0xfe ) ;
}
}
}
/* Start monitoring */
2007-05-08 19:22:03 +04:00
w83781d_write_value ( data , W83781D_REG_CONFIG ,
( w83781d_read_value ( data ,
2005-04-17 02:20:36 +04:00
W83781D_REG_CONFIG ) & 0xf7 )
| 0x01 ) ;
2007-05-08 19:22:02 +04:00
/* A few vars need to be filled upon startup */
2007-05-08 19:22:03 +04:00
for ( i = 0 ; i < 3 ; i + + ) {
data - > fan_min [ i ] = w83781d_read_value ( data ,
2007-05-08 19:22:02 +04:00
W83781D_REG_FAN_MIN ( i ) ) ;
}
mutex_init ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
}
static struct w83781d_data * w83781d_update_device ( struct device * dev )
{
2007-05-08 19:22:02 +04:00
struct w83781d_data * data = dev_get_drvdata ( dev ) ;
2008-10-17 19:51:19 +04:00
struct i2c_client * client = data - > client ;
2005-04-17 02:20:36 +04:00
int i ;
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
if ( time_after ( jiffies , data - > last_updated + HZ + HZ / 2 )
| | ! data - > valid ) {
dev_dbg ( dev , " Starting device update \n " ) ;
for ( i = 0 ; i < = 8 ; i + + ) {
2005-06-16 21:24:14 +04:00
if ( data - > type = = w83783s & & i = = 1 )
2005-04-17 02:20:36 +04:00
continue ; /* 783S has no in1 */
data - > in [ i ] =
2007-05-08 19:22:03 +04:00
w83781d_read_value ( data , W83781D_REG_IN ( i ) ) ;
2005-04-17 02:20:36 +04:00
data - > in_min [ i ] =
2007-05-08 19:22:03 +04:00
w83781d_read_value ( data , W83781D_REG_IN_MIN ( i ) ) ;
2005-04-17 02:20:36 +04:00
data - > in_max [ i ] =
2007-05-08 19:22:03 +04:00
w83781d_read_value ( data , W83781D_REG_IN_MAX ( i ) ) ;
2007-12-01 01:51:24 +03:00
if ( ( data - > type ! = w83782d ) & & ( i = = 6 ) )
2005-04-17 02:20:36 +04:00
break ;
}
2007-05-08 19:22:03 +04:00
for ( i = 0 ; i < 3 ; i + + ) {
data - > fan [ i ] =
2007-05-08 19:22:03 +04:00
w83781d_read_value ( data , W83781D_REG_FAN ( i ) ) ;
2007-05-08 19:22:03 +04:00
data - > fan_min [ i ] =
2007-05-08 19:22:03 +04:00
w83781d_read_value ( data , W83781D_REG_FAN_MIN ( i ) ) ;
2005-04-17 02:20:36 +04:00
}
if ( data - > type ! = w83781d & & data - > type ! = as99127f ) {
2007-05-08 19:22:03 +04:00
for ( i = 0 ; i < 4 ; i + + ) {
data - > pwm [ i ] =
2007-05-08 19:22:03 +04:00
w83781d_read_value ( data ,
2007-05-08 19:22:03 +04:00
W83781D_REG_PWM [ i ] ) ;
2009-05-08 22:27:28 +04:00
/* Only W83782D on SMBus has PWM3 and PWM4 */
if ( ( data - > type ! = w83782d | | ! client )
2007-05-08 19:22:03 +04:00
& & i = = 1 )
2005-04-17 02:20:36 +04:00
break ;
}
/* Only PWM2 can be disabled */
2007-05-08 19:22:03 +04:00
data - > pwm2_enable = ( w83781d_read_value ( data ,
2012-01-15 21:19:16 +04:00
W83781D_REG_PWMCLK12 ) & 0x08 ) > > 3 ;
2005-04-17 02:20:36 +04:00
}
2007-05-08 19:22:03 +04:00
data - > temp = w83781d_read_value ( data , W83781D_REG_TEMP ( 1 ) ) ;
2005-04-17 02:20:36 +04:00
data - > temp_max =
2007-05-08 19:22:03 +04:00
w83781d_read_value ( data , W83781D_REG_TEMP_OVER ( 1 ) ) ;
2005-04-17 02:20:36 +04:00
data - > temp_max_hyst =
2007-05-08 19:22:03 +04:00
w83781d_read_value ( data , W83781D_REG_TEMP_HYST ( 1 ) ) ;
2005-04-17 02:20:36 +04:00
data - > temp_add [ 0 ] =
2007-05-08 19:22:03 +04:00
w83781d_read_value ( data , W83781D_REG_TEMP ( 2 ) ) ;
2005-04-17 02:20:36 +04:00
data - > temp_max_add [ 0 ] =
2007-05-08 19:22:03 +04:00
w83781d_read_value ( data , W83781D_REG_TEMP_OVER ( 2 ) ) ;
2005-04-17 02:20:36 +04:00
data - > temp_max_hyst_add [ 0 ] =
2007-05-08 19:22:03 +04:00
w83781d_read_value ( data , W83781D_REG_TEMP_HYST ( 2 ) ) ;
2005-06-16 21:24:14 +04:00
if ( data - > type ! = w83783s ) {
2005-04-17 02:20:36 +04:00
data - > temp_add [ 1 ] =
2007-05-08 19:22:03 +04:00
w83781d_read_value ( data , W83781D_REG_TEMP ( 3 ) ) ;
2005-04-17 02:20:36 +04:00
data - > temp_max_add [ 1 ] =
2007-05-08 19:22:03 +04:00
w83781d_read_value ( data ,
2005-04-17 02:20:36 +04:00
W83781D_REG_TEMP_OVER ( 3 ) ) ;
data - > temp_max_hyst_add [ 1 ] =
2007-05-08 19:22:03 +04:00
w83781d_read_value ( data ,
2005-04-17 02:20:36 +04:00
W83781D_REG_TEMP_HYST ( 3 ) ) ;
}
2007-05-08 19:22:03 +04:00
i = w83781d_read_value ( data , W83781D_REG_VID_FANDIV ) ;
2005-06-16 21:24:14 +04:00
data - > vid = i & 0x0f ;
2007-05-08 19:22:03 +04:00
data - > vid | = ( w83781d_read_value ( data ,
2005-06-16 21:24:14 +04:00
W83781D_REG_CHIPID ) & 0x01 ) < < 4 ;
2005-04-17 02:20:36 +04:00
data - > fan_div [ 0 ] = ( i > > 4 ) & 0x03 ;
data - > fan_div [ 1 ] = ( i > > 6 ) & 0x03 ;
2007-05-08 19:22:03 +04:00
data - > fan_div [ 2 ] = ( w83781d_read_value ( data ,
2005-06-16 21:24:14 +04:00
W83781D_REG_PIN ) > > 6 ) & 0x03 ;
2005-04-17 02:20:36 +04:00
if ( ( data - > type ! = w83781d ) & & ( data - > type ! = as99127f ) ) {
2007-05-08 19:22:03 +04:00
i = w83781d_read_value ( data , W83781D_REG_VBAT ) ;
2005-04-17 02:20:36 +04:00
data - > fan_div [ 0 ] | = ( i > > 3 ) & 0x04 ;
data - > fan_div [ 1 ] | = ( i > > 4 ) & 0x04 ;
2005-06-16 21:24:14 +04:00
data - > fan_div [ 2 ] | = ( i > > 5 ) & 0x04 ;
2005-04-17 02:20:36 +04:00
}
2007-12-01 01:51:24 +03:00
if ( data - > type = = w83782d ) {
2007-05-08 19:22:03 +04:00
data - > alarms = w83781d_read_value ( data ,
2006-02-06 01:13:48 +03:00
W83782D_REG_ALARM1 )
2007-05-08 19:22:03 +04:00
| ( w83781d_read_value ( data ,
2006-02-06 01:13:48 +03:00
W83782D_REG_ALARM2 ) < < 8 )
2007-05-08 19:22:03 +04:00
| ( w83781d_read_value ( data ,
2006-02-06 01:13:48 +03:00
W83782D_REG_ALARM3 ) < < 16 ) ;
} else if ( data - > type = = w83783s ) {
2007-05-08 19:22:03 +04:00
data - > alarms = w83781d_read_value ( data ,
2006-02-06 01:13:48 +03:00
W83782D_REG_ALARM1 )
2007-05-08 19:22:03 +04:00
| ( w83781d_read_value ( data ,
2006-02-06 01:13:48 +03:00
W83782D_REG_ALARM2 ) < < 8 ) ;
} else {
2012-01-19 23:02:27 +04:00
/*
* No real - time status registers , fall back to
* interrupt status registers
*/
2007-05-08 19:22:03 +04:00
data - > alarms = w83781d_read_value ( data ,
2006-02-06 01:13:48 +03:00
W83781D_REG_ALARM1 )
2007-05-08 19:22:03 +04:00
| ( w83781d_read_value ( data ,
2006-02-06 01:13:48 +03:00
W83781D_REG_ALARM2 ) < < 8 ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-08 19:22:03 +04:00
i = w83781d_read_value ( data , W83781D_REG_BEEP_INTS2 ) ;
2008-10-17 19:51:18 +04:00
data - > beep_mask = ( i < < 8 ) +
2007-05-08 19:22:03 +04:00
w83781d_read_value ( data , W83781D_REG_BEEP_INTS1 ) ;
2005-04-17 02:20:36 +04:00
if ( ( data - > type ! = w83781d ) & & ( data - > type ! = as99127f ) ) {
data - > beep_mask | =
2007-05-08 19:22:03 +04:00
w83781d_read_value ( data ,
2005-04-17 02:20:36 +04:00
W83781D_REG_BEEP_INTS3 ) < < 16 ;
}
data - > last_updated = jiffies ;
2021-09-24 22:52:02 +03:00
data - > valid = true ;
2005-04-17 02:20:36 +04:00
}
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return data ;
}
2008-10-17 19:51:19 +04:00
static const struct i2c_device_id w83781d_ids [ ] = {
{ " w83781d " , w83781d , } ,
{ " w83782d " , w83782d , } ,
{ " w83783s " , w83783s , } ,
{ " as99127f " , as99127f } ,
{ /* LIST END */ }
} ;
MODULE_DEVICE_TABLE ( i2c , w83781d_ids ) ;
2021-07-30 02:05:43 +03:00
static const struct of_device_id w83781d_of_match [ ] = {
{ . compatible = " winbond,w83781d " } ,
{ . compatible = " winbond,w83781g " } ,
{ . compatible = " winbond,w83782d " } ,
{ . compatible = " winbond,w83783s " } ,
{ . compatible = " asus,as99127f " } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , w83781d_of_match ) ;
2008-10-17 19:51:19 +04:00
static struct i2c_driver w83781d_driver = {
. class = I2C_CLASS_HWMON ,
. driver = {
. name = " w83781d " ,
2021-07-30 02:05:43 +03:00
. of_match_table = w83781d_of_match ,
2008-10-17 19:51:19 +04:00
} ,
2020-08-13 19:02:22 +03:00
. probe_new = w83781d_probe ,
2008-10-17 19:51:19 +04:00
. remove = w83781d_remove ,
. id_table = w83781d_ids ,
. detect = w83781d_detect ,
2009-12-14 23:17:25 +03:00
. address_list = normal_i2c ,
2008-10-17 19:51:19 +04:00
} ;
/*
* ISA related code
*/
2008-10-17 19:51:18 +04:00
# ifdef CONFIG_ISA
/* ISA device, if found */
static struct platform_device * pdev ;
static unsigned short isa_address = 0x290 ;
2012-01-19 23:02:27 +04:00
/*
* I2C devices get this name attribute automatically , but for ISA devices
* we must create it by ourselves .
*/
2008-10-17 19:51:18 +04:00
static ssize_t
2016-12-22 15:05:12 +03:00
name_show ( struct device * dev , struct device_attribute * devattr , char * buf )
2008-10-17 19:51:18 +04:00
{
struct w83781d_data * data = dev_get_drvdata ( dev ) ;
2008-10-17 19:51:19 +04:00
return sprintf ( buf , " %s \n " , data - > name ) ;
2008-10-17 19:51:18 +04:00
}
2016-12-22 15:05:12 +03:00
static DEVICE_ATTR_RO ( name ) ;
2008-10-17 19:51:18 +04:00
static struct w83781d_data * w83781d_data_if_isa ( void )
{
return pdev ? platform_get_drvdata ( pdev ) : NULL ;
}
/* Returns 1 if the I2C chip appears to be an alias of the ISA chip */
static int w83781d_alias_detect ( struct i2c_client * client , u8 chipid )
{
2008-10-17 19:51:19 +04:00
struct w83781d_data * isa ;
2008-10-17 19:51:18 +04:00
int i ;
if ( ! pdev ) /* No ISA chip */
return 0 ;
isa = platform_get_drvdata ( pdev ) ;
if ( w83781d_read_value ( isa , W83781D_REG_I2C_ADDR ) ! = client - > addr )
return 0 ; /* Address doesn't match */
if ( w83781d_read_value ( isa , W83781D_REG_WCHIPID ) ! = chipid )
return 0 ; /* Chip type doesn't match */
2012-01-19 23:02:27 +04:00
/*
* We compare all the limit registers , the config register and the
* interrupt mask registers
*/
2008-10-17 19:51:18 +04:00
for ( i = 0x2b ; i < = 0x3d ; i + + ) {
2008-10-17 19:51:19 +04:00
if ( w83781d_read_value ( isa , i ) ! =
i2c_smbus_read_byte_data ( client , i ) )
2008-10-17 19:51:18 +04:00
return 0 ;
}
if ( w83781d_read_value ( isa , W83781D_REG_CONFIG ) ! =
2008-10-17 19:51:19 +04:00
i2c_smbus_read_byte_data ( client , W83781D_REG_CONFIG ) )
2008-10-17 19:51:18 +04:00
return 0 ;
for ( i = 0x43 ; i < = 0x46 ; i + + ) {
2008-10-17 19:51:19 +04:00
if ( w83781d_read_value ( isa , i ) ! =
i2c_smbus_read_byte_data ( client , i ) )
2008-10-17 19:51:18 +04:00
return 0 ;
}
return 1 ;
}
static int
w83781d_read_value_isa ( struct w83781d_data * data , u16 reg )
{
int word_sized , res ;
word_sized = ( ( ( reg & 0xff00 ) = = 0x100 )
| | ( ( reg & 0xff00 ) = = 0x200 ) )
& & ( ( ( reg & 0x00ff ) = = 0x50 )
| | ( ( reg & 0x00ff ) = = 0x53 )
| | ( ( reg & 0x00ff ) = = 0x55 ) ) ;
if ( reg & 0xff00 ) {
outb_p ( W83781D_REG_BANK ,
2008-10-17 19:51:19 +04:00
data - > isa_addr + W83781D_ADDR_REG_OFFSET ) ;
2008-10-17 19:51:18 +04:00
outb_p ( reg > > 8 ,
2008-10-17 19:51:19 +04:00
data - > isa_addr + W83781D_DATA_REG_OFFSET ) ;
2008-10-17 19:51:18 +04:00
}
2008-10-17 19:51:19 +04:00
outb_p ( reg & 0xff , data - > isa_addr + W83781D_ADDR_REG_OFFSET ) ;
res = inb_p ( data - > isa_addr + W83781D_DATA_REG_OFFSET ) ;
2008-10-17 19:51:18 +04:00
if ( word_sized ) {
outb_p ( ( reg & 0xff ) + 1 ,
2008-10-17 19:51:19 +04:00
data - > isa_addr + W83781D_ADDR_REG_OFFSET ) ;
2008-10-17 19:51:18 +04:00
res =
2008-10-17 19:51:19 +04:00
( res < < 8 ) + inb_p ( data - > isa_addr +
2008-10-17 19:51:18 +04:00
W83781D_DATA_REG_OFFSET ) ;
}
if ( reg & 0xff00 ) {
outb_p ( W83781D_REG_BANK ,
2008-10-17 19:51:19 +04:00
data - > isa_addr + W83781D_ADDR_REG_OFFSET ) ;
outb_p ( 0 , data - > isa_addr + W83781D_DATA_REG_OFFSET ) ;
2008-10-17 19:51:18 +04:00
}
return res ;
}
static void
w83781d_write_value_isa ( struct w83781d_data * data , u16 reg , u16 value )
{
int word_sized ;
word_sized = ( ( ( reg & 0xff00 ) = = 0x100 )
| | ( ( reg & 0xff00 ) = = 0x200 ) )
& & ( ( ( reg & 0x00ff ) = = 0x53 )
| | ( ( reg & 0x00ff ) = = 0x55 ) ) ;
if ( reg & 0xff00 ) {
outb_p ( W83781D_REG_BANK ,
2008-10-17 19:51:19 +04:00
data - > isa_addr + W83781D_ADDR_REG_OFFSET ) ;
2008-10-17 19:51:18 +04:00
outb_p ( reg > > 8 ,
2008-10-17 19:51:19 +04:00
data - > isa_addr + W83781D_DATA_REG_OFFSET ) ;
2008-10-17 19:51:18 +04:00
}
2008-10-17 19:51:19 +04:00
outb_p ( reg & 0xff , data - > isa_addr + W83781D_ADDR_REG_OFFSET ) ;
2008-10-17 19:51:18 +04:00
if ( word_sized ) {
outb_p ( value > > 8 ,
2008-10-17 19:51:19 +04:00
data - > isa_addr + W83781D_DATA_REG_OFFSET ) ;
2008-10-17 19:51:18 +04:00
outb_p ( ( reg & 0xff ) + 1 ,
2008-10-17 19:51:19 +04:00
data - > isa_addr + W83781D_ADDR_REG_OFFSET ) ;
2008-10-17 19:51:18 +04:00
}
2008-10-17 19:51:19 +04:00
outb_p ( value & 0xff , data - > isa_addr + W83781D_DATA_REG_OFFSET ) ;
2008-10-17 19:51:18 +04:00
if ( reg & 0xff00 ) {
outb_p ( W83781D_REG_BANK ,
2008-10-17 19:51:19 +04:00
data - > isa_addr + W83781D_ADDR_REG_OFFSET ) ;
outb_p ( 0 , data - > isa_addr + W83781D_DATA_REG_OFFSET ) ;
2008-10-17 19:51:18 +04:00
}
}
2012-01-19 23:02:27 +04:00
/*
* The SMBus locks itself , usually , but nothing may access the Winbond between
* bank switches . ISA access must always be locked explicitly !
* We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks ,
* would slow down the W83781D access and should not be necessary .
* There are some ugly typecasts here , but the good news is - they should
* nowhere else be necessary !
*/
2008-10-17 19:51:18 +04:00
static int
w83781d_read_value ( struct w83781d_data * data , u16 reg )
{
2008-10-17 19:51:19 +04:00
struct i2c_client * client = data - > client ;
2008-10-17 19:51:18 +04:00
int res ;
mutex_lock ( & data - > lock ) ;
2008-10-17 19:51:19 +04:00
if ( client )
2008-10-17 19:51:18 +04:00
res = w83781d_read_value_i2c ( data , reg ) ;
else
res = w83781d_read_value_isa ( data , reg ) ;
mutex_unlock ( & data - > lock ) ;
return res ;
}
static int
w83781d_write_value ( struct w83781d_data * data , u16 reg , u16 value )
{
2008-10-17 19:51:19 +04:00
struct i2c_client * client = data - > client ;
2008-10-17 19:51:18 +04:00
mutex_lock ( & data - > lock ) ;
2008-10-17 19:51:19 +04:00
if ( client )
2008-10-17 19:51:18 +04:00
w83781d_write_value_i2c ( data , reg , value ) ;
else
w83781d_write_value_isa ( data , reg , value ) ;
mutex_unlock ( & data - > lock ) ;
return 0 ;
}
2012-11-19 22:22:35 +04:00
static int
2008-10-17 19:51:18 +04:00
w83781d_isa_probe ( struct platform_device * pdev )
{
int err , reg ;
struct w83781d_data * data ;
struct resource * res ;
/* Reserve the ISA region */
res = platform_get_resource ( pdev , IORESOURCE_IO , 0 ) ;
2012-06-02 22:48:00 +04:00
if ( ! devm_request_region ( & pdev - > dev ,
res - > start + W83781D_ADDR_REG_OFFSET , 2 ,
" w83781d " ) )
return - EBUSY ;
data = devm_kzalloc ( & pdev - > dev , sizeof ( struct w83781d_data ) ,
GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
2008-10-17 19:51:18 +04:00
mutex_init ( & data - > lock ) ;
2008-10-17 19:51:19 +04:00
data - > isa_addr = res - > start ;
2008-10-17 19:51:18 +04:00
platform_set_drvdata ( pdev , data ) ;
reg = w83781d_read_value ( data , W83781D_REG_WCHIPID ) ;
switch ( reg ) {
case 0x30 :
data - > type = w83782d ;
2008-10-17 19:51:19 +04:00
data - > name = " w83782d " ;
2008-10-17 19:51:18 +04:00
break ;
default :
data - > type = w83781d ;
2008-10-17 19:51:19 +04:00
data - > name = " w83781d " ;
2008-10-17 19:51:18 +04:00
}
/* Initialize the W83781D chip */
w83781d_init_device ( & pdev - > dev ) ;
/* Register sysfs hooks */
err = w83781d_create_files ( & pdev - > dev , data - > type , 1 ) ;
if ( err )
goto exit_remove_files ;
err = device_create_file ( & pdev - > dev , & dev_attr_name ) ;
if ( err )
goto exit_remove_files ;
data - > hwmon_dev = hwmon_device_register ( & pdev - > dev ) ;
if ( IS_ERR ( data - > hwmon_dev ) ) {
err = PTR_ERR ( data - > hwmon_dev ) ;
goto exit_remove_files ;
}
return 0 ;
exit_remove_files :
2012-01-17 08:45:16 +04:00
w83781d_remove_files ( & pdev - > dev ) ;
2008-10-17 19:51:18 +04:00
device_remove_file ( & pdev - > dev , & dev_attr_name ) ;
return err ;
}
2012-11-19 22:25:51 +04:00
static int
2008-10-17 19:51:18 +04:00
w83781d_isa_remove ( struct platform_device * pdev )
{
struct w83781d_data * data = platform_get_drvdata ( pdev ) ;
hwmon_device_unregister ( data - > hwmon_dev ) ;
2012-01-17 08:45:16 +04:00
w83781d_remove_files ( & pdev - > dev ) ;
2008-10-17 19:51:18 +04:00
device_remove_file ( & pdev - > dev , & dev_attr_name ) ;
return 0 ;
}
static struct platform_driver w83781d_isa_driver = {
. driver = {
. name = " w83781d " ,
} ,
. probe = w83781d_isa_probe ,
2012-11-19 22:21:20 +04:00
. remove = w83781d_isa_remove ,
2008-10-17 19:51:18 +04:00
} ;
2007-05-08 19:22:02 +04:00
/* return 1 if a supported chip is found, 0 otherwise */
static int __init
w83781d_isa_found ( unsigned short address )
{
int val , save , found = 0 ;
2010-02-05 21:58:36 +03:00
int port ;
2012-01-19 23:02:27 +04:00
/*
* Some boards declare base + 0 to base + 7 as a PNP device , some base + 4
2010-02-05 21:58:36 +03:00
* to base + 7 and some base + 5 to base + 6. So we better request each port
2012-01-19 23:02:27 +04:00
* individually for the probing phase .
*/
2010-02-05 21:58:36 +03:00
for ( port = address ; port < address + W83781D_EXTENT ; port + + ) {
if ( ! request_region ( port , 1 , " w83781d " ) ) {
2011-01-12 23:55:11 +03:00
pr_debug ( " Failed to request port 0x%x \n " , port ) ;
2010-02-05 21:58:36 +03:00
goto release ;
}
2008-03-09 15:34:28 +03:00
}
2007-05-08 19:22:02 +04:00
# define REALLY_SLOW_IO
2012-01-19 23:02:27 +04:00
/*
* We need the timeouts for at least some W83781D - like
* chips . But only if we read ' undefined ' registers .
*/
2007-05-08 19:22:02 +04:00
val = inb_p ( address + 1 ) ;
if ( inb_p ( address + 2 ) ! = val
| | inb_p ( address + 3 ) ! = val
| | inb_p ( address + 7 ) ! = val ) {
2011-01-12 23:55:11 +03:00
pr_debug ( " Detection failed at step %d \n " , 1 ) ;
2007-05-08 19:22:02 +04:00
goto release ;
}
# undef REALLY_SLOW_IO
2012-01-19 23:02:27 +04:00
/*
* We should be able to change the 7 LSB of the address port . The
* MSB ( busy flag ) should be clear initially , set after the write .
*/
2007-05-08 19:22:02 +04:00
save = inb_p ( address + W83781D_ADDR_REG_OFFSET ) ;
if ( save & 0x80 ) {
2011-01-12 23:55:11 +03:00
pr_debug ( " Detection failed at step %d \n " , 2 ) ;
2007-05-08 19:22:02 +04:00
goto release ;
}
val = ~ save & 0x7f ;
outb_p ( val , address + W83781D_ADDR_REG_OFFSET ) ;
if ( inb_p ( address + W83781D_ADDR_REG_OFFSET ) ! = ( val | 0x80 ) ) {
outb_p ( save , address + W83781D_ADDR_REG_OFFSET ) ;
2011-01-12 23:55:11 +03:00
pr_debug ( " Detection failed at step %d \n " , 3 ) ;
2007-05-08 19:22:02 +04:00
goto release ;
}
/* We found a device, now see if it could be a W83781D */
outb_p ( W83781D_REG_CONFIG , address + W83781D_ADDR_REG_OFFSET ) ;
val = inb_p ( address + W83781D_DATA_REG_OFFSET ) ;
if ( val & 0x80 ) {
2011-01-12 23:55:11 +03:00
pr_debug ( " Detection failed at step %d \n " , 4 ) ;
2007-05-08 19:22:02 +04:00
goto release ;
}
outb_p ( W83781D_REG_BANK , address + W83781D_ADDR_REG_OFFSET ) ;
save = inb_p ( address + W83781D_DATA_REG_OFFSET ) ;
outb_p ( W83781D_REG_CHIPMAN , address + W83781D_ADDR_REG_OFFSET ) ;
val = inb_p ( address + W83781D_DATA_REG_OFFSET ) ;
if ( ( ! ( save & 0x80 ) & & ( val ! = 0xa3 ) )
| | ( ( save & 0x80 ) & & ( val ! = 0x5c ) ) ) {
2011-01-12 23:55:11 +03:00
pr_debug ( " Detection failed at step %d \n " , 5 ) ;
2007-05-08 19:22:02 +04:00
goto release ;
}
outb_p ( W83781D_REG_I2C_ADDR , address + W83781D_ADDR_REG_OFFSET ) ;
val = inb_p ( address + W83781D_DATA_REG_OFFSET ) ;
if ( val < 0x03 | | val > 0x77 ) { /* Not a valid I2C address */
2011-01-12 23:55:11 +03:00
pr_debug ( " Detection failed at step %d \n " , 6 ) ;
2007-05-08 19:22:02 +04:00
goto release ;
}
/* The busy flag should be clear again */
if ( inb_p ( address + W83781D_ADDR_REG_OFFSET ) & 0x80 ) {
2011-01-12 23:55:11 +03:00
pr_debug ( " Detection failed at step %d \n " , 7 ) ;
2007-05-08 19:22:02 +04:00
goto release ;
}
/* Determine the chip type */
outb_p ( W83781D_REG_BANK , address + W83781D_ADDR_REG_OFFSET ) ;
save = inb_p ( address + W83781D_DATA_REG_OFFSET ) ;
outb_p ( save & 0xf8 , address + W83781D_DATA_REG_OFFSET ) ;
outb_p ( W83781D_REG_WCHIPID , address + W83781D_ADDR_REG_OFFSET ) ;
val = inb_p ( address + W83781D_DATA_REG_OFFSET ) ;
if ( ( val & 0xfe ) = = 0x10 /* W83781D */
2007-12-01 01:51:24 +03:00
| | val = = 0x30 ) /* W83782D */
2007-05-08 19:22:02 +04:00
found = 1 ;
if ( found )
2011-01-12 23:55:11 +03:00
pr_info ( " Found a %s chip at %#x \n " ,
2007-05-08 19:22:02 +04:00
val = = 0x30 ? " W83782D " : " W83781D " , ( int ) address ) ;
release :
2010-02-05 21:58:36 +03:00
for ( port - - ; port > = address ; port - - )
release_region ( port , 1 ) ;
2007-05-08 19:22:02 +04:00
return found ;
}
static int __init
w83781d_isa_device_add ( unsigned short address )
{
struct resource res = {
. start = address ,
2007-08-29 12:39:57 +04:00
. end = address + W83781D_EXTENT - 1 ,
2007-05-08 19:22:02 +04:00
. name = " w83781d " ,
. flags = IORESOURCE_IO ,
} ;
int err ;
pdev = platform_device_alloc ( " w83781d " , address ) ;
if ( ! pdev ) {
err = - ENOMEM ;
2011-01-12 23:55:11 +03:00
pr_err ( " Device allocation failed \n " ) ;
2007-05-08 19:22:02 +04:00
goto exit ;
}
err = platform_device_add_resources ( pdev , & res , 1 ) ;
if ( err ) {
2011-01-12 23:55:11 +03:00
pr_err ( " Device resource addition failed (%d) \n " , err ) ;
2007-05-08 19:22:02 +04:00
goto exit_device_put ;
}
err = platform_device_add ( pdev ) ;
if ( err ) {
2011-01-12 23:55:11 +03:00
pr_err ( " Device addition failed (%d) \n " , err ) ;
2007-05-08 19:22:02 +04:00
goto exit_device_put ;
}
return 0 ;
exit_device_put :
platform_device_put ( pdev ) ;
exit :
pdev = NULL ;
return err ;
}
2005-04-17 02:20:36 +04:00
static int __init
2008-10-17 19:51:18 +04:00
w83781d_isa_register ( void )
2005-04-17 02:20:36 +04:00
{
[PATCH] I2C: Separate non-i2c hwmon drivers from i2c-core (3/9)
Convert the 10 ISA hardware monitoring drivers (it87, lm78, pc87360,
sis5595, smsc47b397, smsc47m1, via686a, w83627hf, w83627ehf, w83781d) to
explicitely register with i2c-isa. For hybrid drivers (it87, lm78,
w83781d), we now have two separate instances of i2c_driver, one for the
I2C interface of the chip, and one for ISA interface. In the long run,
the one for ISA will be replaced with a different driver type.
At this point, all drivers are working again, except for missing
dependencies in Kconfig.
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-07-20 01:51:07 +04:00
int res ;
2007-05-08 19:22:02 +04:00
if ( w83781d_isa_found ( isa_address ) ) {
res = platform_driver_register ( & w83781d_isa_driver ) ;
if ( res )
2008-10-17 19:51:18 +04:00
goto exit ;
[PATCH] I2C: Separate non-i2c hwmon drivers from i2c-core (3/9)
Convert the 10 ISA hardware monitoring drivers (it87, lm78, pc87360,
sis5595, smsc47b397, smsc47m1, via686a, w83627hf, w83627ehf, w83781d) to
explicitely register with i2c-isa. For hybrid drivers (it87, lm78,
w83781d), we now have two separate instances of i2c_driver, one for the
I2C interface of the chip, and one for ISA interface. In the long run,
the one for ISA will be replaced with a different driver type.
At this point, all drivers are working again, except for missing
dependencies in Kconfig.
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-07-20 01:51:07 +04:00
2007-05-08 19:22:02 +04:00
/* Sets global pdev as a side effect */
res = w83781d_isa_device_add ( isa_address ) ;
if ( res )
goto exit_unreg_isa_driver ;
}
[PATCH] I2C: Separate non-i2c hwmon drivers from i2c-core (3/9)
Convert the 10 ISA hardware monitoring drivers (it87, lm78, pc87360,
sis5595, smsc47b397, smsc47m1, via686a, w83627hf, w83627ehf, w83781d) to
explicitely register with i2c-isa. For hybrid drivers (it87, lm78,
w83781d), we now have two separate instances of i2c_driver, one for the
I2C interface of the chip, and one for ISA interface. In the long run,
the one for ISA will be replaced with a different driver type.
At this point, all drivers are working again, except for missing
dependencies in Kconfig.
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-07-20 01:51:07 +04:00
return 0 ;
2007-05-08 19:22:02 +04:00
2008-10-17 19:51:18 +04:00
exit_unreg_isa_driver :
2007-05-08 19:22:02 +04:00
platform_driver_unregister ( & w83781d_isa_driver ) ;
2008-10-17 19:51:18 +04:00
exit :
2007-05-08 19:22:02 +04:00
return res ;
2005-04-17 02:20:36 +04:00
}
2008-10-26 19:04:38 +03:00
static void
2008-10-17 19:51:18 +04:00
w83781d_isa_unregister ( void )
2005-04-17 02:20:36 +04:00
{
2007-05-08 19:22:02 +04:00
if ( pdev ) {
platform_device_unregister ( pdev ) ;
platform_driver_unregister ( & w83781d_isa_driver ) ;
}
2008-10-17 19:51:18 +04:00
}
# else /* !CONFIG_ISA */
static struct w83781d_data * w83781d_data_if_isa ( void )
{
return NULL ;
}
static int
w83781d_alias_detect ( struct i2c_client * client , u8 chipid )
{
return 0 ;
}
static int
w83781d_read_value ( struct w83781d_data * data , u16 reg )
{
int res ;
mutex_lock ( & data - > lock ) ;
res = w83781d_read_value_i2c ( data , reg ) ;
mutex_unlock ( & data - > lock ) ;
return res ;
}
static int
w83781d_write_value ( struct w83781d_data * data , u16 reg , u16 value )
{
mutex_lock ( & data - > lock ) ;
w83781d_write_value_i2c ( data , reg , value ) ;
mutex_unlock ( & data - > lock ) ;
return 0 ;
}
static int __init
w83781d_isa_register ( void )
{
return 0 ;
}
2008-10-26 19:04:38 +03:00
static void
2008-10-17 19:51:18 +04:00
w83781d_isa_unregister ( void )
{
}
# endif /* CONFIG_ISA */
static int __init
sensors_w83781d_init ( void )
{
int res ;
2012-01-19 23:02:27 +04:00
/*
* We register the ISA device first , so that we can skip the
* registration of an I2C interface to the same device .
*/
2008-10-17 19:51:18 +04:00
res = w83781d_isa_register ( ) ;
if ( res )
goto exit ;
res = i2c_add_driver ( & w83781d_driver ) ;
if ( res )
goto exit_unreg_isa ;
return 0 ;
exit_unreg_isa :
w83781d_isa_unregister ( ) ;
exit :
return res ;
}
static void __exit
sensors_w83781d_exit ( void )
{
w83781d_isa_unregister ( ) ;
2005-04-17 02:20:36 +04:00
i2c_del_driver ( & w83781d_driver ) ;
}
MODULE_AUTHOR ( " Frodo Looijaard <frodol@dds.nl>, "
" Philip Edelbrock <phil@netroedge.com>, "
" and Mark Studebaker <mdsxyz123@yahoo.com> " ) ;
MODULE_DESCRIPTION ( " W83781D driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
module_init ( sensors_w83781d_init ) ;
module_exit ( sensors_w83781d_exit ) ;