2005-04-17 02:20:36 +04:00
/*
2012-01-15 23:07:26 +04:00
* w83627hf . c - Part of lm_sensors , Linux kernel modules for hardware
* monitoring
* Copyright ( c ) 1998 - 2003 Frodo Looijaard < frodol @ dds . nl > ,
* Philip Edelbrock < phil @ netroedge . com > ,
* and Mark Studebaker < mdsxyz123 @ yahoo . com >
* Ported to 2.6 by Bernhard C . Schrenk < clemy @ clemy . org >
2014-01-29 23:40:08 +04:00
* Copyright ( c ) 2007 - 1012 Jean Delvare < jdelvare @ suse . de >
2012-01-15 23:07:26 +04:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
2005-04-17 02:20:36 +04:00
/*
2012-01-15 23:07:26 +04:00
* Supports following chips :
*
2012-11-06 00:54:40 +04:00
* Chip # vin # fanin # pwm # temp wchipid vendid i2c ISA
2012-01-15 23:07:26 +04:00
* w83627hf 9 3 2 3 0x20 0x5ca3 no yes ( LPC )
* w83627thf 7 3 3 3 0x90 0x5ca3 no yes ( LPC )
* w83637hf 7 3 3 3 0x80 0x5ca3 no yes ( LPC )
* w83687thf 7 3 3 3 0x90 0x5ca3 no yes ( LPC )
* w83697hf 8 2 2 2 0x60 0x5ca3 no yes ( LPC )
*
* For other winbond chips , and for i2c support in the above chips ,
* use w83781d . c .
*
* Note : automatic ( " cruise " ) fan control for 697 , 637 & 627 thf not
* supported yet .
*/
2005-04-17 02:20:36 +04:00
2010-10-20 10:51:55 +04: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>
2007-05-08 19:22:00 +04:00
# include <linux/platform_device.h>
2005-07-16 05:39:18 +04:00
# include <linux/hwmon.h>
2007-10-12 23:08:00 +04:00
# include <linux/hwmon-sysfs.h>
2005-07-31 23:52:01 +04:00
# include <linux/hwmon-vid.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>
2007-05-08 19:21:59 +04:00
# include <linux/ioport.h>
2009-01-07 18:37:35 +03:00
# include <linux/acpi.h>
2009-09-15 19:18:13 +04:00
# include <linux/io.h>
2005-04-17 02:20:36 +04:00
# include "lm75.h"
2007-05-08 19:22:00 +04:00
static struct platform_device * pdev ;
2007-05-08 19:21:59 +04:00
# define DRVNAME "w83627hf"
enum chips { w83627hf , w83627thf , w83697hf , w83637hf , w83687thf } ;
2009-12-09 22:35:49 +03:00
struct w83627hf_sio_data {
enum chips type ;
int sioaddr ;
} ;
2005-04-17 02:20:36 +04:00
static u8 force_i2c = 0x1f ;
module_param ( force_i2c , byte , 0 ) ;
MODULE_PARM_DESC ( force_i2c ,
" Initialize the i2c address of the sensors " ) ;
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 " ) ;
2007-12-07 01:13:42 +03:00
static unsigned short force_id ;
module_param ( force_id , ushort , 0 ) ;
MODULE_PARM_DESC ( force_id , " Override the detected device ID " ) ;
2005-04-17 02:20:36 +04:00
/* modified from kernel/include/traps.c */
2012-01-15 23:07:26 +04:00
# define DEV 0x07 /* Register: Logical device select */
2005-04-17 02:20:36 +04:00
/* logical device numbers for superio_select (below) */
# define W83627HF_LD_FDC 0x00
# define W83627HF_LD_PRT 0x01
# define W83627HF_LD_UART1 0x02
# define W83627HF_LD_UART2 0x03
# define W83627HF_LD_KBC 0x05
# define W83627HF_LD_CIR 0x06 /* w83627hf only */
# define W83627HF_LD_GAME 0x07
# define W83627HF_LD_MIDI 0x07
# define W83627HF_LD_GPIO1 0x07
# define W83627HF_LD_GPIO5 0x07 /* w83627thf only */
# define W83627HF_LD_GPIO2 0x08
# define W83627HF_LD_GPIO3 0x09
# define W83627HF_LD_GPIO4 0x09 /* w83627thf only */
# define W83627HF_LD_ACPI 0x0a
# define W83627HF_LD_HWM 0x0b
2012-01-15 23:07:26 +04:00
# define DEVID 0x20 /* Register: Device ID */
2005-04-17 02:20:36 +04:00
# define W83627THF_GPIO5_EN 0x30 /* w83627thf only */
# define W83627THF_GPIO5_IOSR 0xf3 /* w83627thf only */
# define W83627THF_GPIO5_DR 0xf4 /* w83627thf only */
2006-01-19 01:22:12 +03:00
# define W83687THF_VID_EN 0x29 /* w83687thf only */
# define W83687THF_VID_CFG 0xF0 /* w83687thf only */
# define W83687THF_VID_DATA 0xF1 /* w83687thf only */
2005-04-17 02:20:36 +04:00
static inline void
2009-12-09 22:35:49 +03:00
superio_outb ( struct w83627hf_sio_data * sio , int reg , int val )
2005-04-17 02:20:36 +04:00
{
2009-12-09 22:35:49 +03:00
outb ( reg , sio - > sioaddr ) ;
outb ( val , sio - > sioaddr + 1 ) ;
2005-04-17 02:20:36 +04:00
}
static inline int
2009-12-09 22:35:49 +03:00
superio_inb ( struct w83627hf_sio_data * sio , int reg )
2005-04-17 02:20:36 +04:00
{
2009-12-09 22:35:49 +03:00
outb ( reg , sio - > sioaddr ) ;
return inb ( sio - > sioaddr + 1 ) ;
2005-04-17 02:20:36 +04:00
}
static inline void
2009-12-09 22:35:49 +03:00
superio_select ( struct w83627hf_sio_data * sio , int ld )
2005-04-17 02:20:36 +04:00
{
2009-12-09 22:35:49 +03:00
outb ( DEV , sio - > sioaddr ) ;
outb ( ld , sio - > sioaddr + 1 ) ;
2005-04-17 02:20:36 +04:00
}
static inline void
2009-12-09 22:35:49 +03:00
superio_enter ( struct w83627hf_sio_data * sio )
2005-04-17 02:20:36 +04:00
{
2009-12-09 22:35:49 +03:00
outb ( 0x87 , sio - > sioaddr ) ;
outb ( 0x87 , sio - > sioaddr ) ;
2005-04-17 02:20:36 +04:00
}
static inline void
2009-12-09 22:35:49 +03:00
superio_exit ( struct w83627hf_sio_data * sio )
2005-04-17 02:20:36 +04:00
{
2009-12-09 22:35:49 +03:00
outb ( 0xAA , sio - > sioaddr ) ;
2005-04-17 02:20:36 +04:00
}
# define W627_DEVID 0x52
# define W627THF_DEVID 0x82
# define W697_DEVID 0x60
# define W637_DEVID 0x70
2006-01-19 01:22:12 +03:00
# define W687THF_DEVID 0x85
2005-04-17 02:20:36 +04:00
# define WINB_ACT_REG 0x30
# define WINB_BASE_REG 0x60
/* Constants specified below */
2005-10-08 01:11:03 +04:00
/* Alignment of the base address */
# define WINB_ALIGNMENT ~7
2005-04-17 02:20:36 +04:00
2005-10-08 01:11:03 +04:00
/* Offset & size of I/O region we are interested in */
# define WINB_REGION_OFFSET 5
# define WINB_REGION_SIZE 2
2007-05-08 19:22:00 +04:00
/* Where are the sensors address/data registers relative to the region offset */
# define W83781D_ADDR_REG_OFFSET 0
# define W83781D_DATA_REG_OFFSET 1
2005-04-17 02:20:36 +04:00
/* The W83781D registers */
/* The W83782D registers for nr=7,8 are in bank 5 */
# 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-10-15 03:20:50 +04:00
/* nr:0-2 for fans:1-3 */
# define W83627HF_REG_FAN_MIN(nr) (0x3b + (nr))
# define W83627HF_REG_FAN(nr) (0x28 + (nr))
2005-04-17 02:20:36 +04:00
2007-10-15 03:10:52 +04:00
# define W83627HF_REG_TEMP2_CONFIG 0x152
# define W83627HF_REG_TEMP3_CONFIG 0x252
/* these are zero-based, unlike config constants above */
static const u16 w83627hf_reg_temp [ ] = { 0x27 , 0x150 , 0x250 } ;
static const u16 w83627hf_reg_temp_hyst [ ] = { 0x3A , 0x153 , 0x253 } ;
static const u16 w83627hf_reg_temp_over [ ] = { 0x39 , 0x155 , 0x255 } ;
2005-04-17 02:20:36 +04:00
# define W83781D_REG_BANK 0x4E
# define W83781D_REG_CONFIG 0x40
2005-11-08 00:19:04 +03:00
# define W83781D_REG_ALARM1 0x459
# define W83781D_REG_ALARM2 0x45A
# define W83781D_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
# 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
# define W83781D_REG_VBAT 0x5D
# define W83627HF_REG_PWM1 0x5A
# define W83627HF_REG_PWM2 0x5B
2008-08-07 00:41:04 +04:00
static const u8 W83627THF_REG_PWM_ENABLE [ ] = {
0x04 , /* FAN 1 mode */
0x04 , /* FAN 2 mode */
0x12 , /* FAN AUX mode */
} ;
static const u8 W83627THF_PWM_ENABLE_SHIFT [ ] = { 2 , 4 , 1 } ;
2006-01-19 01:22:12 +03:00
# define W83627THF_REG_PWM1 0x01 /* 697HF/637HF/687THF too */
# define W83627THF_REG_PWM2 0x03 /* 697HF/637HF/687THF too */
# define W83627THF_REG_PWM3 0x11 /* 637HF/687THF too */
2005-04-17 02:20:36 +04:00
2006-01-19 01:22:12 +03:00
# define W83627THF_REG_VRM_OVT_CFG 0x18 /* 637HF/687THF too */
2005-04-17 02:20:36 +04:00
static const u8 regpwm_627hf [ ] = { W83627HF_REG_PWM1 , W83627HF_REG_PWM2 } ;
static const u8 regpwm [ ] = { W83627THF_REG_PWM1 , W83627THF_REG_PWM2 ,
W83627THF_REG_PWM3 } ;
# define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \
2007-10-12 23:08:00 +04:00
regpwm_627hf [ nr ] : regpwm [ nr ] )
2005-04-17 02:20:36 +04:00
2007-06-09 18:11:16 +04:00
# define W83627HF_REG_PWM_FREQ 0x5C /* Only for the 627HF */
# define W83637HF_REG_PWM_FREQ1 0x00 /* 697HF/687THF too */
# define W83637HF_REG_PWM_FREQ2 0x02 /* 697HF/687THF too */
# define W83637HF_REG_PWM_FREQ3 0x10 /* 687THF too */
static const u8 W83637HF_REG_PWM_FREQ [ ] = { W83637HF_REG_PWM_FREQ1 ,
W83637HF_REG_PWM_FREQ2 ,
W83637HF_REG_PWM_FREQ3 } ;
# define W83627HF_BASE_PWM_FREQ 46870
2005-04-17 02:20:36 +04:00
# define W83781D_REG_I2C_ADDR 0x48
# define W83781D_REG_I2C_SUBADDR 0x4A
/* Sensor selection */
# 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
2012-01-15 23:07:26 +04:00
/*
* Conversions . Limit checking is only done on the TO_REG
* variants . Note that you should be a bit careful with which arguments
* these macros are called : arguments may be evaluated more than once .
* Fixing this is just not worth it .
*/
2013-01-09 20:09:34 +04:00
# define IN_TO_REG(val) (clamp_val((((val) + 8) / 16), 0, 255))
2005-04-17 02:20:36 +04:00
# define IN_FROM_REG(val) ((val) * 16)
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
}
# define TEMP_MIN (-128000)
# define TEMP_MAX ( 127000)
2012-01-15 23:07:26 +04:00
/*
* TEMP : 0.001 C / bit ( - 128 C to + 127 C )
* REG : 1 C / bit , two ' s complement
*/
2007-08-16 13:40:10 +04:00
static u8 TEMP_TO_REG ( long temp )
2005-04-17 02:20:36 +04:00
{
2013-01-09 20:09:34 +04:00
int ntemp = clamp_val ( temp , TEMP_MIN , TEMP_MAX ) ;
ntemp + = ( ntemp < 0 ? - 500 : 500 ) ;
return ( u8 ) ( ntemp / 1000 ) ;
2005-04-17 02:20:36 +04:00
}
static int TEMP_FROM_REG ( u8 reg )
{
return ( s8 ) reg * 1000 ;
}
# define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000 / ((val)*(div)))
2013-01-09 20:09:34 +04:00
# define PWM_TO_REG(val) (clamp_val((val), 0, 255))
2005-04-17 02:20:36 +04:00
2007-06-09 18:11:16 +04:00
static inline unsigned long pwm_freq_from_reg_627hf ( u8 reg )
{
unsigned long freq ;
freq = W83627HF_BASE_PWM_FREQ > > reg ;
return freq ;
}
static inline u8 pwm_freq_to_reg_627hf ( unsigned long val )
{
u8 i ;
2012-01-15 23:07:26 +04:00
/*
* Only 5 dividers ( 1 2 4 8 16 )
* Search for the nearest available frequency
*/
2007-06-09 18:11:16 +04:00
for ( i = 0 ; i < 4 ; i + + ) {
if ( val > ( ( ( W83627HF_BASE_PWM_FREQ > > i ) +
( W83627HF_BASE_PWM_FREQ > > ( i + 1 ) ) ) / 2 ) )
break ;
}
return i ;
}
static inline unsigned long pwm_freq_from_reg ( u8 reg )
{
/* Clock bit 8 -> 180 kHz or 24 MHz */
unsigned long clock = ( reg & 0x80 ) ? 180000UL : 24000000UL ;
reg & = 0x7f ;
/* This should not happen but anyway... */
if ( reg = = 0 )
reg + + ;
2012-01-05 22:50:18 +04:00
return clock / ( reg < < 8 ) ;
2007-06-09 18:11:16 +04:00
}
static inline u8 pwm_freq_to_reg ( unsigned long val )
{
/* Minimum divider value is 0x01 and maximum is 0x7F */
if ( val > = 93750 ) /* The highest we can do */
return 0x01 ;
if ( val > = 720 ) /* Use 24 MHz clock */
2012-01-05 22:50:18 +04:00
return 24000000UL / ( val < < 8 ) ;
2007-06-09 18:11:16 +04:00
if ( val < 6 ) /* The lowest we can do */
return 0xFF ;
else /* Use 180 kHz clock */
2012-01-05 22:50:18 +04:00
return 0x80 | ( 180000UL / ( val < < 8 ) ) ;
2007-06-09 18:11:16 +04:00
}
2008-01-04 01:04:55 +03:00
# define BEEP_MASK_FROM_REG(val) ((val) & 0xff7fff)
# define BEEP_MASK_TO_REG(val) ((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 )
{
int i ;
2013-01-09 20:09:34 +04:00
val = clamp_val ( val , 1 , 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 ;
}
2012-01-05 22:50:18 +04:00
return ( u8 ) i ;
2005-04-17 02:20:36 +04:00
}
2012-01-15 23:07:26 +04:00
/*
* For each registered chip , we need to keep some data in memory .
* The structure is dynamically allocated .
*/
2005-04-17 02:20:36 +04:00
struct w83627hf_data {
2007-05-08 19:22:00 +04:00
unsigned short addr ;
const char * name ;
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 ;
2006-01-19 01:19:26 +03:00
struct mutex update_lock ;
2005-04-17 02:20:36 +04:00
char valid ; /* !=0 if following fields are valid */
unsigned long last_updated ; /* In jiffies */
u8 in [ 9 ] ; /* Register value */
u8 in_max [ 9 ] ; /* Register value */
u8 in_min [ 9 ] ; /* Register value */
u8 fan [ 3 ] ; /* Register value */
u8 fan_min [ 3 ] ; /* Register value */
2007-10-15 03:10:52 +04:00
u16 temp [ 3 ] ; /* Register value */
u16 temp_max [ 3 ] ; /* Register value */
u16 temp_max_hyst [ 3 ] ; /* Register value */
2005-04-17 02:20:36 +04:00
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 [ 3 ] ; /* Register value */
2008-08-07 00:41:04 +04:00
u8 pwm_enable [ 3 ] ; /* 1 = manual
2012-01-15 23:07:26 +04:00
* 2 = thermal cruise ( also called SmartFan I )
* 3 = fan speed cruise
*/
2007-06-09 18:11:16 +04:00
u8 pwm_freq [ 3 ] ; /* Register value */
2007-08-16 16:30:01 +04:00
u16 sens [ 3 ] ; /* 1 = pentium diode; 2 = 3904 diode;
2012-01-15 23:07:26 +04:00
* 4 = thermistor
*/
2005-04-17 02:20:36 +04:00
u8 vrm ;
2006-01-19 01:22:12 +03:00
u8 vrm_ovt ; /* Register value, 627THF/637HF/687THF only */
2012-12-20 01:16:59 +04:00
# ifdef CONFIG_PM
/* Remember extra register values over suspend/resume */
u8 scfg1 ;
u8 scfg2 ;
# endif
2005-04-17 02:20:36 +04:00
} ;
2007-05-08 19:22:00 +04:00
static int w83627hf_probe ( struct platform_device * pdev ) ;
2012-11-19 22:25:51 +04:00
static int w83627hf_remove ( struct platform_device * pdev ) ;
2007-05-08 19:22:00 +04:00
static int w83627hf_read_value ( struct w83627hf_data * data , u16 reg ) ;
static int w83627hf_write_value ( struct w83627hf_data * data , u16 reg , u16 value ) ;
2007-10-12 23:53:07 +04:00
static void w83627hf_update_fan_div ( struct w83627hf_data * data ) ;
2005-04-17 02:20:36 +04:00
static struct w83627hf_data * w83627hf_update_device ( struct device * dev ) ;
2007-05-08 19:22:00 +04:00
static void w83627hf_init_device ( struct platform_device * pdev ) ;
2005-04-17 02:20:36 +04:00
2012-12-20 01:16:59 +04:00
# ifdef CONFIG_PM
static int w83627hf_suspend ( struct device * dev )
{
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
mutex_lock ( & data - > update_lock ) ;
data - > scfg1 = w83627hf_read_value ( data , W83781D_REG_SCFG1 ) ;
data - > scfg2 = w83627hf_read_value ( data , W83781D_REG_SCFG2 ) ;
mutex_unlock ( & data - > update_lock ) ;
return 0 ;
}
static int w83627hf_resume ( struct device * dev )
{
struct w83627hf_data * data = dev_get_drvdata ( dev ) ;
int i , num_temps = ( data - > type = = w83697hf ) ? 2 : 3 ;
/* Restore limits */
mutex_lock ( & data - > update_lock ) ;
for ( i = 0 ; i < = 8 ; i + + ) {
/* skip missing sensors */
if ( ( ( data - > type = = w83697hf ) & & ( i = = 1 ) ) | |
( ( data - > type ! = w83627hf & & data - > type ! = w83697hf )
& & ( i = = 5 | | i = = 6 ) ) )
continue ;
w83627hf_write_value ( data , W83781D_REG_IN_MAX ( i ) ,
data - > in_max [ i ] ) ;
w83627hf_write_value ( data , W83781D_REG_IN_MIN ( i ) ,
data - > in_min [ i ] ) ;
}
for ( i = 0 ; i < = 2 ; i + + )
w83627hf_write_value ( data , W83627HF_REG_FAN_MIN ( i ) ,
data - > fan_min [ i ] ) ;
for ( i = 0 ; i < num_temps ; i + + ) {
w83627hf_write_value ( data , w83627hf_reg_temp_over [ i ] ,
data - > temp_max [ i ] ) ;
w83627hf_write_value ( data , w83627hf_reg_temp_hyst [ i ] ,
data - > temp_max_hyst [ i ] ) ;
}
/* Fixup BIOS bugs */
if ( data - > type = = w83627thf | | data - > type = = w83637hf | |
data - > type = = w83687thf )
w83627hf_write_value ( data , W83627THF_REG_VRM_OVT_CFG ,
data - > vrm_ovt ) ;
w83627hf_write_value ( data , W83781D_REG_SCFG1 , data - > scfg1 ) ;
w83627hf_write_value ( data , W83781D_REG_SCFG2 , data - > scfg2 ) ;
/* Force re-reading all values */
data - > valid = 0 ;
mutex_unlock ( & data - > update_lock ) ;
return 0 ;
}
static const struct dev_pm_ops w83627hf_dev_pm_ops = {
. suspend = w83627hf_suspend ,
. resume = w83627hf_resume ,
} ;
# define W83627HF_DEV_PM_OPS (&w83627hf_dev_pm_ops)
# else
# define W83627HF_DEV_PM_OPS NULL
# endif /* CONFIG_PM */
2007-05-08 19:22:00 +04:00
static struct platform_driver w83627hf_driver = {
2005-11-26 22:37:41 +03:00
. driver = {
2007-05-08 19:21:59 +04:00
. name = DRVNAME ,
2012-12-20 01:16:59 +04:00
. pm = W83627HF_DEV_PM_OPS ,
2005-11-26 22:37:41 +03:00
} ,
2007-05-08 19:22:00 +04:00
. probe = w83627hf_probe ,
2012-11-19 22:21:20 +04:00
. remove = w83627hf_remove ,
2005-04-17 02:20:36 +04:00
} ;
2007-10-12 23:08:00 +04:00
static ssize_t
show_in_input ( struct device * dev , struct device_attribute * devattr , char * buf )
{
int nr = to_sensor_dev_attr ( devattr ) - > index ;
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
return sprintf ( buf , " %ld \n " , ( long ) IN_FROM_REG ( data - > in [ nr ] ) ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-12 23:08:00 +04:00
static ssize_t
show_in_min ( struct device * dev , struct device_attribute * devattr , char * buf )
{
int nr = to_sensor_dev_attr ( devattr ) - > index ;
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
return sprintf ( buf , " %ld \n " , ( long ) IN_FROM_REG ( data - > in_min [ nr ] ) ) ;
}
static ssize_t
show_in_max ( struct device * dev , struct device_attribute * devattr , char * buf )
{
int nr = to_sensor_dev_attr ( devattr ) - > index ;
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
return sprintf ( buf , " %ld \n " , ( long ) IN_FROM_REG ( data - > in_max [ nr ] ) ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-12 23:08:00 +04:00
static ssize_t
store_in_min ( struct device * dev , struct device_attribute * devattr ,
const char * buf , size_t count )
{
int nr = to_sensor_dev_attr ( devattr ) - > index ;
struct w83627hf_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 23:07:26 +04:00
long val ;
int err ;
err = kstrtol ( buf , 10 , & val ) ;
if ( err )
return err ;
2005-04-17 02:20:36 +04:00
2007-10-12 23:08:00 +04:00
mutex_lock ( & data - > update_lock ) ;
data - > in_min [ nr ] = IN_TO_REG ( val ) ;
w83627hf_write_value ( data , W83781D_REG_IN_MIN ( nr ) , data - > in_min [ nr ] ) ;
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
static ssize_t
store_in_max ( struct device * dev , struct device_attribute * devattr ,
const char * buf , size_t count )
{
int nr = to_sensor_dev_attr ( devattr ) - > index ;
struct w83627hf_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 23:07:26 +04:00
long val ;
int err ;
err = kstrtol ( buf , 10 , & val ) ;
if ( err )
return err ;
2005-04-17 02:20:36 +04:00
2007-10-12 23:08:00 +04:00
mutex_lock ( & data - > update_lock ) ;
data - > in_max [ nr ] = IN_TO_REG ( val ) ;
w83627hf_write_value ( data , W83781D_REG_IN_MAX ( nr ) , data - > in_max [ nr ] ) ;
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
# define sysfs_vin_decl(offset) \
static SENSOR_DEVICE_ATTR ( in # # offset # # _input , S_IRUGO , \
show_in_input , 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 ) ;
sysfs_vin_decl ( 1 ) ;
sysfs_vin_decl ( 2 ) ;
sysfs_vin_decl ( 3 ) ;
sysfs_vin_decl ( 4 ) ;
sysfs_vin_decl ( 5 ) ;
sysfs_vin_decl ( 6 ) ;
sysfs_vin_decl ( 7 ) ;
sysfs_vin_decl ( 8 ) ;
2005-04-17 02:20:36 +04:00
/* use a different set of functions for in0 */
static ssize_t show_in_0 ( struct w83627hf_data * data , char * buf , u8 reg )
{
long in0 ;
if ( ( data - > vrm_ovt & 0x01 ) & &
2006-01-19 01:22:12 +03:00
( w83627thf = = data - > type | | w83637hf = = data - > type
| | w83687thf = = data - > type ) )
2005-04-17 02:20:36 +04:00
/* use VRM9 calculation */
in0 = ( long ) ( ( reg * 488 + 70000 + 50 ) / 100 ) ;
else
/* use VRM8 (standard) calculation */
in0 = ( long ) IN_FROM_REG ( reg ) ;
return sprintf ( buf , " %ld \n " , in0 ) ;
}
2005-05-17 14:42:25 +04:00
static ssize_t show_regs_in_0 ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
return show_in_0 ( data , buf , data - > in [ 0 ] ) ;
}
2005-05-17 14:42:25 +04:00
static ssize_t show_regs_in_min0 ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
return show_in_0 ( data , buf , data - > in_min [ 0 ] ) ;
}
2005-05-17 14:42:25 +04:00
static ssize_t show_regs_in_max0 ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
return show_in_0 ( data , buf , data - > in_max [ 0 ] ) ;
}
2005-05-17 14:42:25 +04:00
static ssize_t store_regs_in_min0 ( struct device * dev , struct device_attribute * attr ,
2005-04-17 02:20:36 +04:00
const char * buf , size_t count )
{
2007-05-08 19:22:00 +04:00
struct w83627hf_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 23:07:26 +04:00
unsigned long val ;
int err ;
2005-04-17 02:20:36 +04:00
2012-01-15 23:07:26 +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
if ( ( data - > vrm_ovt & 0x01 ) & &
2006-01-19 01:22:12 +03:00
( w83627thf = = data - > type | | w83637hf = = data - > type
| | w83687thf = = data - > type ) )
2005-04-17 02:20:36 +04:00
/* use VRM9 calculation */
2005-11-24 02:44:21 +03:00
data - > in_min [ 0 ] =
2013-01-09 20:09:34 +04:00
clamp_val ( ( ( val * 100 ) - 70000 + 244 ) / 488 , 0 , 255 ) ;
2005-04-17 02:20:36 +04:00
else
/* use VRM8 (standard) calculation */
data - > in_min [ 0 ] = IN_TO_REG ( val ) ;
2007-05-08 19:22:00 +04:00
w83627hf_write_value ( data , W83781D_REG_IN_MIN ( 0 ) , data - > in_min [ 0 ] ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
2005-05-17 14:42:25 +04:00
static ssize_t store_regs_in_max0 ( struct device * dev , struct device_attribute * attr ,
2005-04-17 02:20:36 +04:00
const char * buf , size_t count )
{
2007-05-08 19:22:00 +04:00
struct w83627hf_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 23:07:26 +04:00
unsigned long val ;
int err ;
2005-04-17 02:20:36 +04:00
2012-01-15 23:07:26 +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
if ( ( data - > vrm_ovt & 0x01 ) & &
2006-01-19 01:22:12 +03:00
( w83627thf = = data - > type | | w83637hf = = data - > type
| | w83687thf = = data - > type ) )
2005-04-17 02:20:36 +04:00
/* use VRM9 calculation */
2005-11-24 02:44:21 +03:00
data - > in_max [ 0 ] =
2013-01-09 20:09:34 +04:00
clamp_val ( ( ( val * 100 ) - 70000 + 244 ) / 488 , 0 , 255 ) ;
2005-04-17 02:20:36 +04:00
else
/* use VRM8 (standard) calculation */
data - > in_max [ 0 ] = IN_TO_REG ( val ) ;
2007-05-08 19:22:00 +04:00
w83627hf_write_value ( data , W83781D_REG_IN_MAX ( 0 ) , data - > in_max [ 0 ] ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
static DEVICE_ATTR ( in0_input , S_IRUGO , show_regs_in_0 , NULL ) ;
static DEVICE_ATTR ( in0_min , S_IRUGO | S_IWUSR ,
show_regs_in_min0 , store_regs_in_min0 ) ;
static DEVICE_ATTR ( in0_max , S_IRUGO | S_IWUSR ,
show_regs_in_max0 , store_regs_in_max0 ) ;
2007-10-12 23:08:00 +04:00
static ssize_t
show_fan_input ( struct device * dev , struct device_attribute * devattr , char * buf )
{
int nr = to_sensor_dev_attr ( devattr ) - > index ;
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
return sprintf ( buf , " %ld \n " , FAN_FROM_REG ( data - > fan [ nr ] ,
( long ) DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ) ;
}
static ssize_t
show_fan_min ( struct device * dev , struct device_attribute * devattr , char * buf )
{
int nr = to_sensor_dev_attr ( devattr ) - > index ;
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
return sprintf ( buf , " %ld \n " , FAN_FROM_REG ( data - > fan_min [ nr ] ,
( long ) DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ) ;
2005-04-17 02:20:36 +04:00
}
static ssize_t
2007-10-12 23:08:00 +04:00
store_fan_min ( struct device * dev , struct device_attribute * devattr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2007-10-12 23:08:00 +04:00
int nr = to_sensor_dev_attr ( devattr ) - > index ;
2007-05-08 19:22:00 +04:00
struct w83627hf_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 23:07:26 +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-10-12 23:08:00 +04:00
data - > fan_min [ nr ] = FAN_TO_REG ( val , DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ;
2007-10-15 03:20:50 +04:00
w83627hf_write_value ( data , W83627HF_REG_FAN_MIN ( nr ) ,
2007-10-12 23:08:00 +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-10-12 23:08:00 +04:00
# define sysfs_fan_decl(offset) \
static SENSOR_DEVICE_ATTR ( fan # # offset # # _input , S_IRUGO , \
show_fan_input , NULL , offset - 1 ) ; \
static SENSOR_DEVICE_ATTR ( fan # # offset # # _min , S_IRUGO | S_IWUSR , \
show_fan_min , store_fan_min , offset - 1 ) ;
2005-04-17 02:20:36 +04:00
2007-10-12 23:08:00 +04:00
sysfs_fan_decl ( 1 ) ;
sysfs_fan_decl ( 2 ) ;
sysfs_fan_decl ( 3 ) ;
2005-04-17 02:20:36 +04:00
2007-10-12 23:08:00 +04:00
static ssize_t
show_temp ( struct device * dev , struct device_attribute * devattr , char * buf )
{
int nr = to_sensor_dev_attr ( devattr ) - > index ;
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
2007-10-15 03:10:52 +04:00
u16 tmp = data - > temp [ nr ] ;
return sprintf ( buf , " %ld \n " , ( nr ) ? ( long ) LM75_TEMP_FROM_REG ( tmp )
: ( long ) TEMP_FROM_REG ( tmp ) ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-12 23:08:00 +04:00
static ssize_t
show_temp_max ( struct device * dev , struct device_attribute * devattr ,
char * buf )
{
int nr = to_sensor_dev_attr ( devattr ) - > index ;
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
2007-10-15 03:10:52 +04:00
u16 tmp = data - > temp_max [ nr ] ;
return sprintf ( buf , " %ld \n " , ( nr ) ? ( long ) LM75_TEMP_FROM_REG ( tmp )
: ( long ) TEMP_FROM_REG ( tmp ) ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-12 23:08:00 +04:00
static ssize_t
show_temp_max_hyst ( struct device * dev , struct device_attribute * devattr ,
char * buf )
{
int nr = to_sensor_dev_attr ( devattr ) - > index ;
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
2007-10-15 03:10:52 +04:00
u16 tmp = data - > temp_max_hyst [ nr ] ;
return sprintf ( buf , " %ld \n " , ( nr ) ? ( long ) LM75_TEMP_FROM_REG ( tmp )
: ( long ) TEMP_FROM_REG ( tmp ) ) ;
2007-10-12 23:08:00 +04:00
}
2005-04-17 02:20:36 +04:00
2007-10-12 23:08:00 +04:00
static ssize_t
store_temp_max ( struct device * dev , struct device_attribute * devattr ,
const char * buf , size_t count )
{
int nr = to_sensor_dev_attr ( devattr ) - > index ;
struct w83627hf_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 23:07:26 +04:00
u16 tmp ;
long val ;
int err ;
2005-04-17 02:20:36 +04:00
2012-01-15 23:07:26 +04:00
err = kstrtol ( buf , 10 , & val ) ;
if ( err )
return err ;
tmp = ( nr ) ? LM75_TEMP_TO_REG ( val ) : TEMP_TO_REG ( val ) ;
2007-10-12 23:08:00 +04:00
mutex_lock ( & data - > update_lock ) ;
2007-10-15 03:10:52 +04:00
data - > temp_max [ nr ] = tmp ;
w83627hf_write_value ( data , w83627hf_reg_temp_over [ nr ] , tmp ) ;
2007-10-12 23:08:00 +04:00
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
static ssize_t
store_temp_max_hyst ( struct device * dev , struct device_attribute * devattr ,
const char * buf , size_t count )
{
int nr = to_sensor_dev_attr ( devattr ) - > index ;
struct w83627hf_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 23:07:26 +04:00
u16 tmp ;
long val ;
int err ;
err = kstrtol ( buf , 10 , & val ) ;
if ( err )
return err ;
2007-10-12 23:08:00 +04:00
2012-01-15 23:07:26 +04:00
tmp = ( nr ) ? LM75_TEMP_TO_REG ( val ) : TEMP_TO_REG ( val ) ;
2007-10-12 23:08:00 +04:00
mutex_lock ( & data - > update_lock ) ;
2007-10-15 03:10:52 +04:00
data - > temp_max_hyst [ nr ] = tmp ;
w83627hf_write_value ( data , w83627hf_reg_temp_hyst [ nr ] , tmp ) ;
2007-10-12 23:08:00 +04:00
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
# define sysfs_temp_decl(offset) \
static SENSOR_DEVICE_ATTR ( temp # # offset # # _input , S_IRUGO , \
2007-10-15 03:10:52 +04:00
show_temp , NULL , offset - 1 ) ; \
2007-10-12 23:08:00 +04:00
static SENSOR_DEVICE_ATTR ( temp # # offset # # _max , S_IRUGO | S_IWUSR , \
2007-10-15 03:10:52 +04:00
show_temp_max , store_temp_max , offset - 1 ) ; \
2007-10-12 23:08:00 +04:00
static SENSOR_DEVICE_ATTR ( temp # # offset # # _max_hyst , S_IRUGO | S_IWUSR , \
2007-10-15 03:10:52 +04:00
show_temp_max_hyst , store_temp_max_hyst , offset - 1 ) ;
2007-10-12 23:08:00 +04:00
sysfs_temp_decl ( 1 ) ;
sysfs_temp_decl ( 2 ) ;
sysfs_temp_decl ( 3 ) ;
2005-04-17 02:20:36 +04:00
static ssize_t
2005-05-17 14:42:25 +04:00
show_vid_reg ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
return sprintf ( buf , " %ld \n " , ( long ) vid_from_reg ( data - > vid , data - > vrm ) ) ;
}
static DEVICE_ATTR ( cpu0_vid , S_IRUGO , show_vid_reg , NULL ) ;
static ssize_t
2005-05-17 14:42:25 +04:00
show_vrm_reg ( 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 w83627hf_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
2005-05-17 14:42:25 +04:00
store_vrm_reg ( 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:00 +04:00
struct w83627hf_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 23:07:26 +04:00
unsigned long val ;
int err ;
2005-04-17 02:20:36 +04:00
2012-01-15 23:07:26 +04:00
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
2014-08-06 04:27:11 +04:00
if ( val > 255 )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
data - > vrm = val ;
return count ;
}
static DEVICE_ATTR ( vrm , S_IRUGO | S_IWUSR , show_vrm_reg , store_vrm_reg ) ;
static ssize_t
2005-05-17 14:42:25 +04:00
show_alarms_reg ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
return sprintf ( buf , " %ld \n " , ( long ) data - > alarms ) ;
}
static DEVICE_ATTR ( alarms , S_IRUGO , show_alarms_reg , NULL ) ;
2008-01-04 01:00:30 +03:00
static ssize_t
show_alarm ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
int bitnr = to_sensor_dev_attr ( attr ) - > index ;
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_alarm , NULL , 13 ) ;
2008-01-04 01:04:55 +03:00
static ssize_t
show_beep_mask ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
return sprintf ( buf , " %ld \n " ,
( long ) BEEP_MASK_FROM_REG ( data - > beep_mask ) ) ;
2005-04-17 02:20:36 +04:00
}
static ssize_t
2008-01-04 01:04:55 +03:00
store_beep_mask ( 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:00 +04:00
struct w83627hf_data * data = dev_get_drvdata ( dev ) ;
2008-01-04 01:04:55 +03:00
unsigned long val ;
2012-01-15 23:07:26 +04:00
int err ;
2005-04-17 02:20:36 +04:00
2012-01-15 23:07:26 +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
2008-01-04 01:04:55 +03:00
/* preserve beep enable */
data - > beep_mask = ( data - > beep_mask & 0x8000 )
| BEEP_MASK_TO_REG ( val ) ;
w83627hf_write_value ( data , W83781D_REG_BEEP_INTS1 ,
data - > beep_mask & 0xff ) ;
w83627hf_write_value ( data , W83781D_REG_BEEP_INTS3 ,
( ( data - > beep_mask ) > > 16 ) & 0xff ) ;
2007-05-08 19:22:00 +04:00
w83627hf_write_value ( data , W83781D_REG_BEEP_INTS2 ,
2008-01-04 01:04:55 +03:00
( data - > beep_mask > > 8 ) & 0xff ) ;
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 ;
}
2008-01-04 01:04:55 +03:00
static DEVICE_ATTR ( beep_mask , S_IRUGO | S_IWUSR ,
show_beep_mask , store_beep_mask ) ;
2005-04-17 02:20:36 +04:00
2008-01-04 01:00:30 +03:00
static ssize_t
show_beep ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct w83627hf_data * data = w83627hf_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 w83627hf_data * data = dev_get_drvdata ( dev ) ;
int bitnr = to_sensor_dev_attr ( attr ) - > index ;
u8 reg ;
2012-01-15 23:07:26 +04:00
unsigned long bit ;
int err ;
err = kstrtoul ( buf , 10 , & bit ) ;
if ( err )
return err ;
2008-01-04 01:00:30 +03: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 = w83627hf_read_value ( data , W83781D_REG_BEEP_INTS1 ) ;
if ( bit )
reg | = ( 1 < < bitnr ) ;
else
reg & = ~ ( 1 < < bitnr ) ;
w83627hf_write_value ( data , W83781D_REG_BEEP_INTS1 , reg ) ;
} else if ( bitnr < 16 ) {
reg = w83627hf_read_value ( data , W83781D_REG_BEEP_INTS2 ) ;
if ( bit )
reg | = ( 1 < < ( bitnr - 8 ) ) ;
else
reg & = ~ ( 1 < < ( bitnr - 8 ) ) ;
w83627hf_write_value ( data , W83781D_REG_BEEP_INTS2 , reg ) ;
} else {
reg = w83627hf_read_value ( data , W83781D_REG_BEEP_INTS3 ) ;
if ( bit )
reg | = ( 1 < < ( bitnr - 16 ) ) ;
else
reg & = ~ ( 1 < < ( bitnr - 16 ) ) ;
w83627hf_write_value ( data , W83781D_REG_BEEP_INTS3 , reg ) ;
}
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
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 | S_IWUSR ,
show_beep , store_beep , 13 ) ;
2008-01-04 01:04:55 +03:00
static SENSOR_DEVICE_ATTR ( beep_enable , S_IRUGO | S_IWUSR ,
show_beep , store_beep , 15 ) ;
2008-01-04 01:00:30 +03:00
2005-04-17 02:20:36 +04:00
static ssize_t
2007-10-12 23:08:00 +04:00
show_fan_div ( struct device * dev , struct device_attribute * devattr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-10-12 23:08:00 +04:00
int nr = to_sensor_dev_attr ( devattr ) - > index ;
2005-04-17 02:20:36 +04:00
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
return sprintf ( buf , " %ld \n " ,
2007-10-12 23:08:00 +04:00
( long ) DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ;
2005-04-17 02:20:36 +04:00
}
2012-01-15 23:07:26 +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-10-12 23:08:00 +04:00
store_fan_div ( struct device * dev , struct device_attribute * devattr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2007-10-12 23:08:00 +04:00
int nr = to_sensor_dev_attr ( devattr ) - > index ;
2007-05-08 19:22:00 +04:00
struct w83627hf_data * data = dev_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
unsigned long min ;
u8 reg ;
2012-01-15 23:07:26 +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 ) ;
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 ) ;
2007-05-08 19:22:00 +04:00
reg = ( w83627hf_read_value ( data , nr = = 2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV )
2005-04-17 02:20:36 +04:00
& ( nr = = 0 ? 0xcf : 0x3f ) )
| ( ( data - > fan_div [ nr ] & 0x03 ) < < ( nr = = 0 ? 4 : 6 ) ) ;
2007-05-08 19:22:00 +04:00
w83627hf_write_value ( data , nr = = 2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV , reg ) ;
2005-04-17 02:20:36 +04:00
2007-05-08 19:22:00 +04:00
reg = ( w83627hf_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:00 +04:00
w83627hf_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-10-15 03:20:50 +04:00
w83627hf_write_value ( data , W83627HF_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-10-12 23:08:00 +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-10-12 23:08:00 +04:00
show_pwm ( struct device * dev , struct device_attribute * devattr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-10-12 23:08:00 +04:00
int nr = to_sensor_dev_attr ( devattr ) - > index ;
2005-04-17 02:20:36 +04:00
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
2007-10-12 23:08:00 +04:00
return sprintf ( buf , " %ld \n " , ( long ) data - > pwm [ nr ] ) ;
2005-04-17 02:20:36 +04:00
}
static ssize_t
2007-10-12 23:08:00 +04:00
store_pwm ( struct device * dev , struct device_attribute * devattr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2007-10-12 23:08:00 +04:00
int nr = to_sensor_dev_attr ( devattr ) - > index ;
2007-05-08 19:22:00 +04:00
struct w83627hf_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 23:07:26 +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 ) ;
2005-04-17 02:20:36 +04:00
if ( data - > type = = w83627thf ) {
/* bits 0-3 are reserved in 627THF */
2007-10-12 23:08:00 +04:00
data - > pwm [ nr ] = PWM_TO_REG ( val ) & 0xf0 ;
2007-05-08 19:22:00 +04:00
w83627hf_write_value ( data ,
2005-04-17 02:20:36 +04:00
W836X7HF_REG_PWM ( data - > type , nr ) ,
2007-10-12 23:08:00 +04:00
data - > pwm [ nr ] |
2007-05-08 19:22:00 +04:00
( w83627hf_read_value ( data ,
2005-04-17 02:20:36 +04:00
W836X7HF_REG_PWM ( data - > type , nr ) ) & 0x0f ) ) ;
} else {
2007-10-12 23:08:00 +04:00
data - > pwm [ nr ] = PWM_TO_REG ( val ) ;
2007-05-08 19:22:00 +04:00
w83627hf_write_value ( data ,
2005-04-17 02:20:36 +04:00
W836X7HF_REG_PWM ( data - > type , nr ) ,
2007-10-12 23:08:00 +04:00
data - > pwm [ 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-10-12 23:08:00 +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 ) ;
2005-04-17 02:20:36 +04:00
2008-08-07 00:41:04 +04:00
static ssize_t
show_pwm_enable ( struct device * dev , struct device_attribute * devattr , char * buf )
{
int nr = to_sensor_dev_attr ( devattr ) - > index ;
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , data - > pwm_enable [ nr ] ) ;
}
static ssize_t
store_pwm_enable ( struct device * dev , struct device_attribute * devattr ,
const char * buf , size_t count )
{
int nr = to_sensor_dev_attr ( devattr ) - > index ;
struct w83627hf_data * data = dev_get_drvdata ( dev ) ;
u8 reg ;
2012-01-15 23:07:26 +04:00
unsigned long val ;
int err ;
2008-08-07 00:41:04 +04:00
2012-01-15 23:07:26 +04:00
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
if ( ! val | | val > 3 ) /* modes 1, 2 and 3 are supported */
2008-08-07 00:41:04 +04:00
return - EINVAL ;
mutex_lock ( & data - > update_lock ) ;
data - > pwm_enable [ nr ] = val ;
reg = w83627hf_read_value ( data , W83627THF_REG_PWM_ENABLE [ nr ] ) ;
reg & = ~ ( 0x03 < < W83627THF_PWM_ENABLE_SHIFT [ nr ] ) ;
reg | = ( val - 1 ) < < W83627THF_PWM_ENABLE_SHIFT [ nr ] ;
w83627hf_write_value ( data , W83627THF_REG_PWM_ENABLE [ nr ] , reg ) ;
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
static SENSOR_DEVICE_ATTR ( pwm1_enable , S_IRUGO | S_IWUSR , show_pwm_enable ,
store_pwm_enable , 0 ) ;
static SENSOR_DEVICE_ATTR ( pwm2_enable , S_IRUGO | S_IWUSR , show_pwm_enable ,
store_pwm_enable , 1 ) ;
static SENSOR_DEVICE_ATTR ( pwm3_enable , S_IRUGO | S_IWUSR , show_pwm_enable ,
store_pwm_enable , 2 ) ;
2007-06-09 18:11:16 +04:00
static ssize_t
2007-10-12 23:08:00 +04:00
show_pwm_freq ( struct device * dev , struct device_attribute * devattr , char * buf )
2007-06-09 18:11:16 +04:00
{
2007-10-12 23:08:00 +04:00
int nr = to_sensor_dev_attr ( devattr ) - > index ;
2007-06-09 18:11:16 +04:00
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
if ( data - > type = = w83627hf )
return sprintf ( buf , " %ld \n " ,
2007-10-12 23:08:00 +04:00
pwm_freq_from_reg_627hf ( data - > pwm_freq [ nr ] ) ) ;
2007-06-09 18:11:16 +04:00
else
return sprintf ( buf , " %ld \n " ,
2007-10-12 23:08:00 +04:00
pwm_freq_from_reg ( data - > pwm_freq [ nr ] ) ) ;
2007-06-09 18:11:16 +04:00
}
static ssize_t
2007-10-12 23:08:00 +04:00
store_pwm_freq ( struct device * dev , struct device_attribute * devattr ,
const char * buf , size_t count )
2007-06-09 18:11:16 +04:00
{
2007-10-12 23:08:00 +04:00
int nr = to_sensor_dev_attr ( devattr ) - > index ;
2007-06-09 18:11:16 +04:00
struct w83627hf_data * data = dev_get_drvdata ( dev ) ;
static const u8 mask [ ] = { 0xF8 , 0x8F } ;
2012-01-15 23:07:26 +04:00
unsigned long val ;
int err ;
2007-06-09 18:11:16 +04:00
2012-01-15 23:07:26 +04:00
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
2007-06-09 18:11:16 +04:00
mutex_lock ( & data - > update_lock ) ;
if ( data - > type = = w83627hf ) {
2007-10-12 23:08:00 +04:00
data - > pwm_freq [ nr ] = pwm_freq_to_reg_627hf ( val ) ;
2007-06-09 18:11:16 +04:00
w83627hf_write_value ( data , W83627HF_REG_PWM_FREQ ,
2007-10-12 23:08:00 +04:00
( data - > pwm_freq [ nr ] < < ( nr * 4 ) ) |
2007-06-09 18:11:16 +04:00
( w83627hf_read_value ( data ,
2007-10-12 23:08:00 +04:00
W83627HF_REG_PWM_FREQ ) & mask [ nr ] ) ) ;
2007-06-09 18:11:16 +04:00
} else {
2007-10-12 23:08:00 +04:00
data - > pwm_freq [ nr ] = pwm_freq_to_reg ( val ) ;
w83627hf_write_value ( data , W83637HF_REG_PWM_FREQ [ nr ] ,
data - > pwm_freq [ nr ] ) ;
2007-06-09 18:11:16 +04:00
}
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
2007-10-12 23:08:00 +04:00
static SENSOR_DEVICE_ATTR ( pwm1_freq , S_IRUGO | S_IWUSR ,
show_pwm_freq , store_pwm_freq , 0 ) ;
static SENSOR_DEVICE_ATTR ( pwm2_freq , S_IRUGO | S_IWUSR ,
show_pwm_freq , store_pwm_freq , 1 ) ;
static SENSOR_DEVICE_ATTR ( pwm3_freq , S_IRUGO | S_IWUSR ,
show_pwm_freq , store_pwm_freq , 2 ) ;
2007-06-09 18:11:16 +04:00
2005-04-17 02:20:36 +04:00
static ssize_t
2007-10-12 23:08:00 +04:00
show_temp_type ( struct device * dev , struct device_attribute * devattr ,
char * buf )
2005-04-17 02:20:36 +04:00
{
2007-10-12 23:08:00 +04:00
int nr = to_sensor_dev_attr ( devattr ) - > index ;
2005-04-17 02:20:36 +04:00
struct w83627hf_data * data = w83627hf_update_device ( dev ) ;
2007-10-12 23:08:00 +04:00
return sprintf ( buf , " %ld \n " , ( long ) data - > sens [ nr ] ) ;
2005-04-17 02:20:36 +04:00
}
static ssize_t
2007-10-12 23:08:00 +04:00
store_temp_type ( struct device * dev , struct device_attribute * devattr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2007-10-12 23:08:00 +04:00
int nr = to_sensor_dev_attr ( devattr ) - > index ;
2007-05-08 19:22:00 +04:00
struct w83627hf_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 23:07:26 +04:00
unsigned long val ;
u32 tmp ;
int err ;
2005-04-17 02:20:36 +04:00
2012-01-15 23:07:26 +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:00 +04:00
tmp = w83627hf_read_value ( data , W83781D_REG_SCFG1 ) ;
w83627hf_write_value ( data , W83781D_REG_SCFG1 ,
2007-10-12 23:08:00 +04:00
tmp | BIT_SCFG1 [ nr ] ) ;
2007-05-08 19:22:00 +04:00
tmp = w83627hf_read_value ( data , W83781D_REG_SCFG2 ) ;
w83627hf_write_value ( data , W83781D_REG_SCFG2 ,
2007-10-12 23:08:00 +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:00 +04:00
tmp = w83627hf_read_value ( data , W83781D_REG_SCFG1 ) ;
w83627hf_write_value ( data , W83781D_REG_SCFG1 ,
2007-10-12 23:08:00 +04:00
tmp | BIT_SCFG1 [ nr ] ) ;
2007-05-08 19:22:00 +04:00
tmp = w83627hf_read_value ( data , W83781D_REG_SCFG2 ) ;
w83627hf_write_value ( data , W83781D_REG_SCFG2 ,
2007-10-12 23:08:00 +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 :
dev_warn ( dev , " Sensor type %d is deprecated, please use 4 "
" instead \n " , W83781D_DEFAULT_BETA ) ;
/* fall through */
case 4 : /* thermistor */
2007-05-08 19:22:00 +04:00
tmp = w83627hf_read_value ( data , W83781D_REG_SCFG1 ) ;
w83627hf_write_value ( data , W83781D_REG_SCFG1 ,
2007-10-12 23:08:00 +04:00
tmp & ~ BIT_SCFG1 [ nr ] ) ;
data - > sens [ nr ] = val ;
2005-04-17 02:20:36 +04:00
break ;
default :
2007-05-08 19:22:00 +04:00
dev_err ( dev ,
2007-08-16 16:30:01 +04:00
" 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-10-12 23:08:00 +04:00
# define sysfs_temp_type(offset) \
static SENSOR_DEVICE_ATTR ( temp # # offset # # _type , S_IRUGO | S_IWUSR , \
show_temp_type , store_temp_type , offset - 1 ) ;
2005-04-17 02:20:36 +04:00
2007-10-12 23:08:00 +04:00
sysfs_temp_type ( 1 ) ;
sysfs_temp_type ( 2 ) ;
sysfs_temp_type ( 3 ) ;
2005-04-17 02:20:36 +04:00
2007-10-12 23:08:00 +04:00
static ssize_t
show_name ( struct device * dev , struct device_attribute * devattr , char * buf )
2007-05-08 19:22:00 +04:00
{
struct w83627hf_data * data = dev_get_drvdata ( dev ) ;
return sprintf ( buf , " %s \n " , data - > name ) ;
}
static DEVICE_ATTR ( name , S_IRUGO , show_name , NULL ) ;
static int __init w83627hf_find ( int sioaddr , unsigned short * addr ,
struct w83627hf_sio_data * sio_data )
2005-04-17 02:20:36 +04:00
{
2007-05-08 19:21:59 +04:00
int err = - ENODEV ;
2005-04-17 02:20:36 +04:00
u16 val ;
2012-08-18 21:30:05 +04:00
static __initconst char * const names [ ] = {
2007-05-08 19:22:00 +04:00
" W83627HF " ,
" W83627THF " ,
" W83697HF " ,
" W83637HF " ,
" W83687THF " ,
} ;
2009-12-16 23:38:29 +03:00
sio_data - > sioaddr = sioaddr ;
2009-12-09 22:35:49 +03:00
superio_enter ( sio_data ) ;
val = force_id ? force_id : superio_inb ( sio_data , DEVID ) ;
2007-05-08 19:22:00 +04:00
switch ( val ) {
case W627_DEVID :
sio_data - > type = w83627hf ;
break ;
case W627THF_DEVID :
sio_data - > type = w83627thf ;
break ;
case W697_DEVID :
sio_data - > type = w83697hf ;
break ;
case W637_DEVID :
sio_data - > type = w83637hf ;
break ;
case W687THF_DEVID :
sio_data - > type = w83687thf ;
break ;
2007-05-28 00:17:43 +04:00
case 0xff : /* No device at all */
goto exit ;
2007-05-08 19:22:00 +04:00
default :
2007-05-28 00:17:43 +04:00
pr_debug ( DRVNAME " : Unsupported chip (DEVID=0x%02x) \n " , val ) ;
2007-05-08 19:21:59 +04:00
goto exit ;
2005-04-17 02:20:36 +04:00
}
2009-12-09 22:35:49 +03:00
superio_select ( sio_data , W83627HF_LD_HWM ) ;
val = ( superio_inb ( sio_data , WINB_BASE_REG ) < < 8 ) |
superio_inb ( sio_data , WINB_BASE_REG + 1 ) ;
2005-10-08 01:11:03 +04:00
* addr = val & WINB_ALIGNMENT ;
2007-05-08 19:21:59 +04:00
if ( * addr = = 0 ) {
2010-10-20 10:51:55 +04:00
pr_warn ( " Base address not set, skipping \n " ) ;
2007-05-08 19:21:59 +04:00
goto exit ;
2005-04-17 02:20:36 +04:00
}
2009-12-09 22:35:49 +03:00
val = superio_inb ( sio_data , WINB_ACT_REG ) ;
2007-05-08 19:21:59 +04:00
if ( ! ( val & 0x01 ) ) {
2010-10-20 10:51:55 +04:00
pr_warn ( " Enabling HWM logical device \n " ) ;
2009-12-09 22:35:49 +03:00
superio_outb ( sio_data , WINB_ACT_REG , val | 0x01 ) ;
2007-05-08 19:21:59 +04:00
}
err = 0 ;
2007-05-08 19:22:00 +04:00
pr_info ( DRVNAME " : Found %s chip at %#x \n " ,
names [ sio_data - > type ] , * addr ) ;
2007-05-08 19:21:59 +04:00
exit :
2009-12-09 22:35:49 +03:00
superio_exit ( sio_data ) ;
2007-05-08 19:21:59 +04:00
return err ;
2005-04-17 02:20:36 +04:00
}
2007-10-12 23:08:00 +04:00
# define VIN_UNIT_ATTRS(_X_) \
& sensor_dev_attr_in # # _X_ # # _input . dev_attr . attr , \
& sensor_dev_attr_in # # _X_ # # _min . dev_attr . attr , \
2008-01-04 01:00:30 +03:00
& sensor_dev_attr_in # # _X_ # # _max . dev_attr . attr , \
& sensor_dev_attr_in # # _X_ # # _alarm . dev_attr . attr , \
& sensor_dev_attr_in # # _X_ # # _beep . dev_attr . attr
2007-10-12 23:08:00 +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 , \
2008-01-04 01:00:30 +03: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
2007-10-12 23:08:00 +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 , \
& sensor_dev_attr_temp # # _X_ # # _max_hyst . dev_attr . attr , \
2008-01-04 01:00:30 +03:00
& sensor_dev_attr_temp # # _X_ # # _type . dev_attr . attr , \
& sensor_dev_attr_temp # # _X_ # # _alarm . dev_attr . attr , \
& sensor_dev_attr_temp # # _X_ # # _beep . dev_attr . attr
2007-10-12 23:08:00 +04:00
2006-09-24 22:59:49 +04:00
static struct attribute * w83627hf_attributes [ ] = {
& dev_attr_in0_input . attr ,
& dev_attr_in0_min . attr ,
& dev_attr_in0_max . attr ,
2008-01-04 01:00:30 +03:00
& sensor_dev_attr_in0_alarm . dev_attr . attr ,
& sensor_dev_attr_in0_beep . dev_attr . attr ,
2007-10-12 23:08:00 +04:00
VIN_UNIT_ATTRS ( 2 ) ,
VIN_UNIT_ATTRS ( 3 ) ,
VIN_UNIT_ATTRS ( 4 ) ,
VIN_UNIT_ATTRS ( 7 ) ,
VIN_UNIT_ATTRS ( 8 ) ,
FAN_UNIT_ATTRS ( 1 ) ,
FAN_UNIT_ATTRS ( 2 ) ,
TEMP_UNIT_ATTRS ( 1 ) ,
TEMP_UNIT_ATTRS ( 2 ) ,
2006-09-24 22:59:49 +04:00
& dev_attr_alarms . attr ,
2008-01-04 01:04:55 +03:00
& sensor_dev_attr_beep_enable . dev_attr . attr ,
2006-09-24 22:59:49 +04:00
& dev_attr_beep_mask . attr ,
2007-10-12 23:08:00 +04:00
& sensor_dev_attr_pwm1 . dev_attr . attr ,
& sensor_dev_attr_pwm2 . dev_attr . attr ,
2007-05-08 19:22:00 +04:00
& dev_attr_name . attr ,
2006-09-24 22:59:49 +04:00
NULL
} ;
static const struct attribute_group w83627hf_group = {
. attrs = w83627hf_attributes ,
} ;
static struct attribute * w83627hf_attributes_opt [ ] = {
2007-10-12 23:08:00 +04:00
VIN_UNIT_ATTRS ( 1 ) ,
VIN_UNIT_ATTRS ( 5 ) ,
VIN_UNIT_ATTRS ( 6 ) ,
FAN_UNIT_ATTRS ( 3 ) ,
TEMP_UNIT_ATTRS ( 3 ) ,
& sensor_dev_attr_pwm3 . dev_attr . attr ,
& sensor_dev_attr_pwm1_freq . dev_attr . attr ,
& sensor_dev_attr_pwm2_freq . dev_attr . attr ,
& sensor_dev_attr_pwm3_freq . dev_attr . attr ,
2008-08-07 00:41:04 +04:00
& sensor_dev_attr_pwm1_enable . dev_attr . attr ,
& sensor_dev_attr_pwm2_enable . dev_attr . attr ,
& sensor_dev_attr_pwm3_enable . dev_attr . attr ,
2006-09-24 22:59:49 +04:00
NULL
} ;
static const struct attribute_group w83627hf_group_opt = {
. attrs = w83627hf_attributes_opt ,
} ;
2012-11-19 22:22:35 +04:00
static int w83627hf_probe ( struct platform_device * pdev )
2005-04-17 02:20:36 +04:00
{
2007-05-08 19:22:00 +04:00
struct device * dev = & pdev - > dev ;
2013-07-30 12:13:06 +04:00
struct w83627hf_sio_data * sio_data = dev_get_platdata ( dev ) ;
2005-04-17 02:20:36 +04:00
struct w83627hf_data * data ;
2007-05-08 19:22:00 +04:00
struct resource * res ;
2007-10-15 03:20:50 +04:00
int err , i ;
2005-04-17 02:20:36 +04:00
2007-05-08 19:22:00 +04:00
static const char * names [ ] = {
" w83627hf " ,
" w83627thf " ,
" w83697hf " ,
" w83637hf " ,
" w83687thf " ,
} ;
res = platform_get_resource ( pdev , IORESOURCE_IO , 0 ) ;
2012-06-02 22:47:59 +04:00
if ( ! devm_request_region ( dev , res - > start , WINB_REGION_SIZE , DRVNAME ) ) {
2007-05-08 19:22:00 +04:00
dev_err ( dev , " Failed to request region 0x%lx-0x%lx \n " ,
( unsigned long ) res - > start ,
( unsigned long ) ( res - > start + WINB_REGION_SIZE - 1 ) ) ;
2012-06-02 22:47:59 +04:00
return - EBUSY ;
2005-04-17 02:20:36 +04:00
}
2012-06-02 22:47:59 +04:00
data = devm_kzalloc ( dev , sizeof ( struct w83627hf_data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
2007-05-08 19:22:00 +04:00
data - > addr = res - > start ;
data - > type = sio_data - > type ;
data - > name = names [ sio_data - > type ] ;
2006-01-19 01:19:26 +03:00
mutex_init ( & data - > lock ) ;
mutex_init ( & data - > update_lock ) ;
2007-05-08 19:22:00 +04:00
platform_set_drvdata ( pdev , data ) ;
2005-04-17 02:20:36 +04:00
/* Initialize the chip */
2007-05-08 19:22:00 +04:00
w83627hf_init_device ( pdev ) ;
2005-04-17 02:20:36 +04:00
/* A few vars need to be filled upon startup */
2007-10-15 03:20:50 +04:00
for ( i = 0 ; i < = 2 ; i + + )
data - > fan_min [ i ] = w83627hf_read_value (
data , W83627HF_REG_FAN_MIN ( i ) ) ;
2007-10-12 23:53:07 +04:00
w83627hf_update_fan_div ( data ) ;
2005-04-17 02:20:36 +04:00
2006-09-24 22:59:49 +04:00
/* Register common device attributes */
2012-01-15 23:07:26 +04:00
err = sysfs_create_group ( & dev - > kobj , & w83627hf_group ) ;
if ( err )
2012-06-02 22:47:59 +04:00
return err ;
2005-04-17 02:20:36 +04:00
2006-09-24 22:59:49 +04:00
/* Register chip-specific device attributes */
2007-05-08 19:22:00 +04:00
if ( data - > type = = w83627hf | | data - > type = = w83697hf )
2007-10-12 23:08:00 +04:00
if ( ( err = device_create_file ( dev ,
& sensor_dev_attr_in5_input . dev_attr ) )
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_in5_min . dev_attr ) )
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_in5_max . dev_attr ) )
2008-01-04 01:00:30 +03:00
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_in5_alarm . dev_attr ) )
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_in5_beep . dev_attr ) )
2007-10-12 23:08:00 +04:00
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_in6_input . dev_attr ) )
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_in6_min . dev_attr ) )
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_in6_max . dev_attr ) )
2008-01-04 01:00:30 +03:00
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_in6_alarm . dev_attr ) )
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_in6_beep . dev_attr ) )
2007-10-12 23:08:00 +04:00
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_pwm1_freq . dev_attr ) )
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_pwm2_freq . dev_attr ) ) )
2012-06-02 22:47:59 +04:00
goto error ;
2005-04-17 02:20:36 +04:00
2007-05-08 19:22:00 +04:00
if ( data - > type ! = w83697hf )
2007-10-12 23:08:00 +04:00
if ( ( err = device_create_file ( dev ,
& sensor_dev_attr_in1_input . dev_attr ) )
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_in1_min . dev_attr ) )
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_in1_max . dev_attr ) )
2008-01-04 01:00:30 +03:00
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_in1_alarm . dev_attr ) )
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_in1_beep . dev_attr ) )
2007-10-12 23:08:00 +04:00
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_fan3_input . dev_attr ) )
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_fan3_min . dev_attr ) )
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_fan3_div . dev_attr ) )
2008-01-04 01:00:30 +03:00
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_fan3_alarm . dev_attr ) )
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_fan3_beep . dev_attr ) )
2007-10-12 23:08:00 +04:00
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_temp3_input . dev_attr ) )
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_temp3_max . dev_attr ) )
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_temp3_max_hyst . dev_attr ) )
2008-01-04 01:00:30 +03:00
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_temp3_alarm . dev_attr ) )
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_temp3_beep . dev_attr ) )
2007-10-12 23:08:00 +04:00
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_temp3_type . dev_attr ) ) )
2012-06-02 22:47:59 +04:00
goto error ;
2006-09-24 22:59:49 +04:00
2007-05-08 19:22:00 +04:00
if ( data - > type ! = w83697hf & & data - > vid ! = 0xff ) {
2007-05-08 19:21:59 +04:00
/* Convert VID to voltage based on VRM */
data - > vrm = vid_which_vrm ( ) ;
2007-05-08 19:22:00 +04:00
if ( ( err = device_create_file ( dev , & dev_attr_cpu0_vid ) )
| | ( err = device_create_file ( dev , & dev_attr_vrm ) ) )
2012-06-02 22:47:59 +04:00
goto error ;
2007-05-08 19:21:59 +04:00
}
2005-04-17 02:20:36 +04:00
2007-05-08 19:22:00 +04:00
if ( data - > type = = w83627thf | | data - > type = = w83637hf
2012-01-15 23:07:26 +04:00
| | data - > type = = w83687thf ) {
err = device_create_file ( dev , & sensor_dev_attr_pwm3 . dev_attr ) ;
if ( err )
2012-06-02 22:47:59 +04:00
goto error ;
2012-01-15 23:07:26 +04:00
}
2005-04-17 02:20:36 +04:00
2007-06-09 18:11:16 +04:00
if ( data - > type = = w83637hf | | data - > type = = w83687thf )
2007-10-12 23:08:00 +04:00
if ( ( err = device_create_file ( dev ,
& sensor_dev_attr_pwm1_freq . dev_attr ) )
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_pwm2_freq . dev_attr ) )
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_pwm3_freq . dev_attr ) ) )
2012-06-02 22:47:59 +04:00
goto error ;
2007-06-09 18:11:16 +04:00
2008-08-07 00:41:04 +04:00
if ( data - > type ! = w83627hf )
if ( ( err = device_create_file ( dev ,
& sensor_dev_attr_pwm1_enable . dev_attr ) )
| | ( err = device_create_file ( dev ,
& sensor_dev_attr_pwm2_enable . dev_attr ) ) )
2012-06-02 22:47:59 +04:00
goto error ;
2008-08-07 00:41:04 +04:00
if ( data - > type = = w83627thf | | data - > type = = w83637hf
2012-01-15 23:07:26 +04:00
| | data - > type = = w83687thf ) {
err = device_create_file ( dev ,
& sensor_dev_attr_pwm3_enable . dev_attr ) ;
if ( err )
2012-06-02 22:47:59 +04:00
goto error ;
2012-01-15 23:07:26 +04:00
}
2008-08-07 00:41:04 +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:47:59 +04:00
goto error ;
2006-09-24 22:59:49 +04:00
}
2005-04-17 02:20:36 +04:00
return 0 ;
2012-06-02 22:47:59 +04:00
error :
2007-05-08 19:22:00 +04:00
sysfs_remove_group ( & dev - > kobj , & w83627hf_group ) ;
sysfs_remove_group ( & dev - > kobj , & w83627hf_group_opt ) ;
2005-04-17 02:20:36 +04:00
return err ;
}
2012-11-19 22:25:51 +04:00
static int w83627hf_remove ( struct platform_device * pdev )
2005-04-17 02:20:36 +04:00
{
2007-05-08 19:22:00 +04:00
struct w83627hf_data * data = platform_get_drvdata ( pdev ) ;
2005-04-17 02:20:36 +04:00
2007-08-21 00:46:20 +04:00
hwmon_device_unregister ( data - > hwmon_dev ) ;
2005-07-16 05:39:18 +04:00
2007-05-08 19:22:00 +04:00
sysfs_remove_group ( & pdev - > dev . kobj , & w83627hf_group ) ;
sysfs_remove_group ( & pdev - > dev . kobj , & w83627hf_group_opt ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-10-10 18:30:23 +04:00
/* Registers 0x50-0x5f are banked */
static inline void w83627hf_set_bank ( struct w83627hf_data * data , u16 reg )
{
if ( ( reg & 0x00f0 ) = = 0x50 ) {
outb_p ( W83781D_REG_BANK , data - > addr + W83781D_ADDR_REG_OFFSET ) ;
outb_p ( reg > > 8 , data - > addr + W83781D_DATA_REG_OFFSET ) ;
}
}
/* Not strictly necessary, but play it safe for now */
static inline void w83627hf_reset_bank ( struct w83627hf_data * data , u16 reg )
{
if ( reg & 0xff00 ) {
outb_p ( W83781D_REG_BANK , data - > addr + W83781D_ADDR_REG_OFFSET ) ;
outb_p ( 0 , data - > addr + W83781D_DATA_REG_OFFSET ) ;
}
}
2007-05-08 19:22:00 +04:00
static int w83627hf_read_value ( struct w83627hf_data * data , u16 reg )
2005-04-17 02:20:36 +04:00
{
int res , word_sized ;
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > lock ) ;
2005-04-17 02:20:36 +04:00
word_sized = ( ( ( reg & 0xff00 ) = = 0x100 )
| | ( ( reg & 0xff00 ) = = 0x200 ) )
& & ( ( ( reg & 0x00ff ) = = 0x50 )
| | ( ( reg & 0x00ff ) = = 0x53 )
| | ( ( reg & 0x00ff ) = = 0x55 ) ) ;
2007-10-10 18:30:23 +04:00
w83627hf_set_bank ( data , reg ) ;
2007-05-08 19:22:00 +04:00
outb_p ( reg & 0xff , data - > addr + W83781D_ADDR_REG_OFFSET ) ;
res = inb_p ( data - > addr + W83781D_DATA_REG_OFFSET ) ;
2005-04-17 02:20:36 +04:00
if ( word_sized ) {
outb_p ( ( reg & 0xff ) + 1 ,
2007-05-08 19:22:00 +04:00
data - > addr + W83781D_ADDR_REG_OFFSET ) ;
2005-04-17 02:20:36 +04:00
res =
2007-05-08 19:22:00 +04:00
( res < < 8 ) + inb_p ( data - > addr +
2005-04-17 02:20:36 +04:00
W83781D_DATA_REG_OFFSET ) ;
}
2007-10-10 18:30:23 +04:00
w83627hf_reset_bank ( data , reg ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > lock ) ;
2005-04-17 02:20:36 +04:00
return res ;
}
2012-11-19 22:22:35 +04:00
static int w83627thf_read_gpio5 ( struct platform_device * pdev )
2005-04-17 02:20:36 +04:00
{
2013-07-30 12:13:06 +04:00
struct w83627hf_sio_data * sio_data = dev_get_platdata ( & pdev - > dev ) ;
2005-04-17 02:20:36 +04:00
int res = 0xff , sel ;
2009-12-09 22:35:49 +03:00
superio_enter ( sio_data ) ;
superio_select ( sio_data , W83627HF_LD_GPIO5 ) ;
2005-04-17 02:20:36 +04:00
/* Make sure these GPIO pins are enabled */
2009-12-09 22:35:49 +03:00
if ( ! ( superio_inb ( sio_data , W83627THF_GPIO5_EN ) & ( 1 < < 3 ) ) ) {
2007-05-08 19:22:00 +04:00
dev_dbg ( & pdev - > dev , " GPIO5 disabled, no VID function \n " ) ;
2005-04-17 02:20:36 +04:00
goto exit ;
}
2012-01-15 23:07:26 +04:00
/*
* Make sure the pins are configured for input
* There must be at least five ( VRM 9 ) , and possibly 6 ( VRM 10 )
*/
2009-12-09 22:35:49 +03:00
sel = superio_inb ( sio_data , W83627THF_GPIO5_IOSR ) & 0x3f ;
2005-04-17 02:20:36 +04:00
if ( ( sel & 0x1f ) ! = 0x1f ) {
2007-05-08 19:22:00 +04:00
dev_dbg ( & pdev - > dev , " GPIO5 not configured for VID "
2005-04-17 02:20:36 +04:00
" function \n " ) ;
goto exit ;
}
2007-05-08 19:22:00 +04:00
dev_info ( & pdev - > dev , " Reading VID from GPIO5 \n " ) ;
2009-12-09 22:35:49 +03:00
res = superio_inb ( sio_data , W83627THF_GPIO5_DR ) & sel ;
2005-04-17 02:20:36 +04:00
exit :
2009-12-09 22:35:49 +03:00
superio_exit ( sio_data ) ;
2005-04-17 02:20:36 +04:00
return res ;
}
2012-11-19 22:22:35 +04:00
static int w83687thf_read_vid ( struct platform_device * pdev )
2006-01-19 01:22:12 +03:00
{
2013-07-30 12:13:06 +04:00
struct w83627hf_sio_data * sio_data = dev_get_platdata ( & pdev - > dev ) ;
2006-01-19 01:22:12 +03:00
int res = 0xff ;
2009-12-09 22:35:49 +03:00
superio_enter ( sio_data ) ;
superio_select ( sio_data , W83627HF_LD_HWM ) ;
2006-01-19 01:22:12 +03:00
/* Make sure these GPIO pins are enabled */
2009-12-09 22:35:49 +03:00
if ( ! ( superio_inb ( sio_data , W83687THF_VID_EN ) & ( 1 < < 2 ) ) ) {
2007-05-08 19:22:00 +04:00
dev_dbg ( & pdev - > dev , " VID disabled, no VID function \n " ) ;
2006-01-19 01:22:12 +03:00
goto exit ;
}
/* Make sure the pins are configured for input */
2009-12-09 22:35:49 +03:00
if ( ! ( superio_inb ( sio_data , W83687THF_VID_CFG ) & ( 1 < < 4 ) ) ) {
2007-05-08 19:22:00 +04:00
dev_dbg ( & pdev - > dev , " VID configured as output, "
2006-01-19 01:22:12 +03:00
" no VID function \n " ) ;
goto exit ;
}
2009-12-09 22:35:49 +03:00
res = superio_inb ( sio_data , W83687THF_VID_DATA ) & 0x3f ;
2006-01-19 01:22:12 +03:00
exit :
2009-12-09 22:35:49 +03:00
superio_exit ( sio_data ) ;
2006-01-19 01:22:12 +03:00
return res ;
}
2007-05-08 19:22:00 +04:00
static int w83627hf_write_value ( struct w83627hf_data * data , u16 reg , u16 value )
2005-04-17 02:20:36 +04:00
{
int word_sized ;
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > lock ) ;
2005-04-17 02:20:36 +04:00
word_sized = ( ( ( reg & 0xff00 ) = = 0x100 )
| | ( ( reg & 0xff00 ) = = 0x200 ) )
& & ( ( ( reg & 0x00ff ) = = 0x53 )
| | ( ( reg & 0x00ff ) = = 0x55 ) ) ;
2007-10-10 18:30:23 +04:00
w83627hf_set_bank ( data , reg ) ;
2007-05-08 19:22:00 +04:00
outb_p ( reg & 0xff , data - > addr + W83781D_ADDR_REG_OFFSET ) ;
2005-04-17 02:20:36 +04:00
if ( word_sized ) {
outb_p ( value > > 8 ,
2007-05-08 19:22:00 +04:00
data - > addr + W83781D_DATA_REG_OFFSET ) ;
2005-04-17 02:20:36 +04:00
outb_p ( ( reg & 0xff ) + 1 ,
2007-05-08 19:22:00 +04:00
data - > addr + W83781D_ADDR_REG_OFFSET ) ;
2005-04-17 02:20:36 +04:00
}
outb_p ( value & 0xff ,
2007-05-08 19:22:00 +04:00
data - > addr + W83781D_DATA_REG_OFFSET ) ;
2007-10-10 18:30:23 +04:00
w83627hf_reset_bank ( data , reg ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > lock ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2012-11-19 22:22:35 +04:00
static void w83627hf_init_device ( struct platform_device * pdev )
2005-04-17 02:20:36 +04:00
{
2007-05-08 19:22:00 +04:00
struct w83627hf_data * data = platform_get_drvdata ( pdev ) ;
2005-04-17 02:20:36 +04:00
int i ;
2007-05-08 19:21:59 +04:00
enum chips type = data - > type ;
2005-04-17 02:20:36 +04:00
u8 tmp ;
/* Minimize conflicts with other winbond i2c-only clients... */
/* disable i2c subclients... how to disable main i2c client?? */
/* force i2c address to relatively uncommon address */
2012-12-20 01:17:00 +04:00
if ( type = = w83627hf ) {
w83627hf_write_value ( data , W83781D_REG_I2C_SUBADDR , 0x89 ) ;
w83627hf_write_value ( data , W83781D_REG_I2C_ADDR , force_i2c ) ;
}
2005-04-17 02:20:36 +04:00
/* Read VID only once */
2007-05-08 19:21:59 +04:00
if ( type = = w83627hf | | type = = w83637hf ) {
2007-05-08 19:22:00 +04:00
int lo = w83627hf_read_value ( data , W83781D_REG_VID_FANDIV ) ;
int hi = w83627hf_read_value ( data , W83781D_REG_CHIPID ) ;
2005-04-17 02:20:36 +04:00
data - > vid = ( lo & 0x0f ) | ( ( hi & 0x01 ) < < 4 ) ;
2007-05-08 19:21:59 +04:00
} else if ( type = = w83627thf ) {
2007-05-08 19:22:00 +04:00
data - > vid = w83627thf_read_gpio5 ( pdev ) ;
2007-05-08 19:21:59 +04:00
} else if ( type = = w83687thf ) {
2007-05-08 19:22:00 +04:00
data - > vid = w83687thf_read_vid ( pdev ) ;
2005-04-17 02:20:36 +04:00
}
/* Read VRM & OVT Config only once */
2007-05-08 19:21:59 +04:00
if ( type = = w83627thf | | type = = w83637hf | | type = = w83687thf ) {
2005-04-17 02:20:36 +04:00
data - > vrm_ovt =
2007-05-08 19:22:00 +04:00
w83627hf_read_value ( data , W83627THF_REG_VRM_OVT_CFG ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-08 19:22:00 +04:00
tmp = w83627hf_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 ( w83627hf_read_value
2007-05-08 19:22:00 +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 ;
}
if ( ( type = = w83697hf ) & & ( i = = 2 ) )
break ;
}
if ( init ) {
/* Enable temp2 */
2007-10-15 03:10:52 +04:00
tmp = w83627hf_read_value ( data , W83627HF_REG_TEMP2_CONFIG ) ;
2005-04-17 02:20:36 +04:00
if ( tmp & 0x01 ) {
2007-05-08 19:22:00 +04:00
dev_warn ( & pdev - > dev , " Enabling temp2, readings "
2005-04-17 02:20:36 +04:00
" might not make sense \n " ) ;
2007-10-15 03:10:52 +04:00
w83627hf_write_value ( data , W83627HF_REG_TEMP2_CONFIG ,
2005-04-17 02:20:36 +04:00
tmp & 0xfe ) ;
}
/* Enable temp3 */
if ( type ! = w83697hf ) {
2007-05-08 19:22:00 +04:00
tmp = w83627hf_read_value ( data ,
2007-10-15 03:10:52 +04:00
W83627HF_REG_TEMP3_CONFIG ) ;
2005-04-17 02:20:36 +04:00
if ( tmp & 0x01 ) {
2007-05-08 19:22:00 +04:00
dev_warn ( & pdev - > dev , " Enabling temp3, "
2005-04-17 02:20:36 +04:00
" readings might not make sense \n " ) ;
2007-05-08 19:22:00 +04:00
w83627hf_write_value ( data ,
2007-10-15 03:10:52 +04:00
W83627HF_REG_TEMP3_CONFIG , tmp & 0xfe ) ;
2005-04-17 02:20:36 +04:00
}
}
}
/* Start monitoring */
2007-05-08 19:22:00 +04:00
w83627hf_write_value ( data , W83781D_REG_CONFIG ,
( w83627hf_read_value ( data ,
2005-04-17 02:20:36 +04:00
W83781D_REG_CONFIG ) & 0xf7 )
| 0x01 ) ;
2008-01-04 00:54:13 +03:00
/* Enable VBAT monitoring if needed */
tmp = w83627hf_read_value ( data , W83781D_REG_VBAT ) ;
if ( ! ( tmp & 0x01 ) )
w83627hf_write_value ( data , W83781D_REG_VBAT , tmp | 0x01 ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-12 23:53:07 +04:00
static void w83627hf_update_fan_div ( struct w83627hf_data * data )
{
int reg ;
reg = w83627hf_read_value ( data , W83781D_REG_VID_FANDIV ) ;
data - > fan_div [ 0 ] = ( reg > > 4 ) & 0x03 ;
data - > fan_div [ 1 ] = ( reg > > 6 ) & 0x03 ;
if ( data - > type ! = w83697hf ) {
data - > fan_div [ 2 ] = ( w83627hf_read_value ( data ,
W83781D_REG_PIN ) > > 6 ) & 0x03 ;
}
reg = w83627hf_read_value ( data , W83781D_REG_VBAT ) ;
data - > fan_div [ 0 ] | = ( reg > > 3 ) & 0x04 ;
data - > fan_div [ 1 ] | = ( reg > > 4 ) & 0x04 ;
if ( data - > type ! = w83697hf )
data - > fan_div [ 2 ] | = ( reg > > 5 ) & 0x04 ;
}
2005-04-17 02:20:36 +04:00
static struct w83627hf_data * w83627hf_update_device ( struct device * dev )
{
2007-05-08 19:22:00 +04:00
struct w83627hf_data * data = dev_get_drvdata ( dev ) ;
2007-10-15 03:10:52 +04:00
int i , num_temps = ( data - > type = = w83697hf ) ? 2 : 3 ;
2008-08-07 00:41:04 +04:00
int num_pwms = ( data - > type = = w83697hf ) ? 2 : 3 ;
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
if ( time_after ( jiffies , data - > last_updated + HZ + HZ / 2 )
| | ! data - > valid ) {
for ( i = 0 ; i < = 8 ; i + + ) {
/* skip missing sensors */
if ( ( ( data - > type = = w83697hf ) & & ( i = = 1 ) ) | |
2006-01-19 01:22:12 +03:00
( ( data - > type ! = w83627hf & & data - > type ! = w83697hf )
2005-11-08 00:19:04 +03:00
& & ( i = = 5 | | i = = 6 ) ) )
2005-04-17 02:20:36 +04:00
continue ;
data - > in [ i ] =
2007-05-08 19:22:00 +04:00
w83627hf_read_value ( data , W83781D_REG_IN ( i ) ) ;
2005-04-17 02:20:36 +04:00
data - > in_min [ i ] =
2007-05-08 19:22:00 +04:00
w83627hf_read_value ( data ,
2005-04-17 02:20:36 +04:00
W83781D_REG_IN_MIN ( i ) ) ;
data - > in_max [ i ] =
2007-05-08 19:22:00 +04:00
w83627hf_read_value ( data ,
2005-04-17 02:20:36 +04:00
W83781D_REG_IN_MAX ( i ) ) ;
}
2007-10-15 03:20:50 +04:00
for ( i = 0 ; i < = 2 ; i + + ) {
data - > fan [ i ] =
w83627hf_read_value ( data , W83627HF_REG_FAN ( i ) ) ;
data - > fan_min [ i ] =
2007-05-08 19:22:00 +04:00
w83627hf_read_value ( data ,
2007-10-15 03:20:50 +04:00
W83627HF_REG_FAN_MIN ( i ) ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-12 23:08:00 +04:00
for ( i = 0 ; i < = 2 ; i + + ) {
2007-05-08 19:22:00 +04:00
u8 tmp = w83627hf_read_value ( data ,
2005-04-17 02:20:36 +04:00
W836X7HF_REG_PWM ( data - > type , i ) ) ;
/* bits 0-3 are reserved in 627THF */
if ( data - > type = = w83627thf )
tmp & = 0xf0 ;
2007-10-12 23:08:00 +04:00
data - > pwm [ i ] = tmp ;
if ( i = = 1 & &
( data - > type = = w83627hf | | data - > type = = w83697hf ) )
2005-04-17 02:20:36 +04:00
break ;
}
2007-06-09 18:11:16 +04:00
if ( data - > type = = w83627hf ) {
u8 tmp = w83627hf_read_value ( data ,
W83627HF_REG_PWM_FREQ ) ;
data - > pwm_freq [ 0 ] = tmp & 0x07 ;
data - > pwm_freq [ 1 ] = ( tmp > > 4 ) & 0x07 ;
} else if ( data - > type ! = w83627thf ) {
for ( i = 1 ; i < = 3 ; i + + ) {
data - > pwm_freq [ i - 1 ] =
w83627hf_read_value ( data ,
W83637HF_REG_PWM_FREQ [ i - 1 ] ) ;
if ( i = = 2 & & ( data - > type = = w83697hf ) )
break ;
}
}
2008-08-07 00:41:04 +04:00
if ( data - > type ! = w83627hf ) {
for ( i = 0 ; i < num_pwms ; i + + ) {
u8 tmp = w83627hf_read_value ( data ,
W83627THF_REG_PWM_ENABLE [ i ] ) ;
data - > pwm_enable [ i ] =
( ( tmp > > W83627THF_PWM_ENABLE_SHIFT [ i ] )
& 0x03 ) + 1 ;
}
}
2007-10-15 03:10:52 +04:00
for ( i = 0 ; i < num_temps ; i + + ) {
data - > temp [ i ] = w83627hf_read_value (
data , w83627hf_reg_temp [ i ] ) ;
data - > temp_max [ i ] = w83627hf_read_value (
data , w83627hf_reg_temp_over [ i ] ) ;
data - > temp_max_hyst [ i ] = w83627hf_read_value (
data , w83627hf_reg_temp_hyst [ i ] ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-12 23:53:07 +04:00
w83627hf_update_fan_div ( data ) ;
2005-04-17 02:20:36 +04:00
data - > alarms =
2007-05-08 19:22:00 +04:00
w83627hf_read_value ( data , W83781D_REG_ALARM1 ) |
( w83627hf_read_value ( data , W83781D_REG_ALARM2 ) < < 8 ) |
( w83627hf_read_value ( data , W83781D_REG_ALARM3 ) < < 16 ) ;
i = w83627hf_read_value ( data , W83781D_REG_BEEP_INTS2 ) ;
2008-01-04 01:04:55 +03:00
data - > beep_mask = ( i < < 8 ) |
2007-05-08 19:22:00 +04:00
w83627hf_read_value ( data , W83781D_REG_BEEP_INTS1 ) |
w83627hf_read_value ( data , W83781D_REG_BEEP_INTS3 ) < < 16 ;
2005-04-17 02:20:36 +04:00
data - > last_updated = jiffies ;
data - > valid = 1 ;
}
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return data ;
}
2007-05-08 19:22:00 +04:00
static int __init w83627hf_device_add ( unsigned short address ,
const struct w83627hf_sio_data * sio_data )
{
struct resource res = {
. start = address + WINB_REGION_OFFSET ,
. end = address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1 ,
. name = DRVNAME ,
. flags = IORESOURCE_IO ,
} ;
int err ;
2009-01-07 18:37:35 +03:00
err = acpi_check_resource_conflict ( & res ) ;
if ( err )
goto exit ;
2007-05-08 19:22:00 +04:00
pdev = platform_device_alloc ( DRVNAME , address ) ;
if ( ! pdev ) {
err = - ENOMEM ;
2010-10-20 10:51:55 +04:00
pr_err ( " Device allocation failed \n " ) ;
2007-05-08 19:22:00 +04:00
goto exit ;
}
err = platform_device_add_resources ( pdev , & res , 1 ) ;
if ( err ) {
2010-10-20 10:51:55 +04:00
pr_err ( " Device resource addition failed (%d) \n " , err ) ;
2007-05-08 19:22:00 +04:00
goto exit_device_put ;
}
2007-06-09 18:11:16 +04:00
err = platform_device_add_data ( pdev , sio_data ,
sizeof ( struct w83627hf_sio_data ) ) ;
if ( err ) {
2010-10-20 10:51:55 +04:00
pr_err ( " Platform data allocation failed \n " ) ;
2007-05-08 19:22:00 +04:00
goto exit_device_put ;
}
err = platform_device_add ( pdev ) ;
if ( err ) {
2010-10-20 10:51:55 +04:00
pr_err ( " Device addition failed (%d) \n " , err ) ;
2007-05-08 19:22:00 +04:00
goto exit_device_put ;
}
return 0 ;
exit_device_put :
platform_device_put ( pdev ) ;
exit :
return err ;
}
2005-04-17 02:20:36 +04:00
static int __init sensors_w83627hf_init ( void )
{
2007-05-08 19:22:00 +04:00
int err ;
unsigned short address ;
struct w83627hf_sio_data sio_data ;
if ( w83627hf_find ( 0x2e , & address , & sio_data )
& & w83627hf_find ( 0x4e , & address , & sio_data ) )
2005-04-17 02:20:36 +04:00
return - ENODEV ;
2007-05-08 19:22:00 +04:00
err = platform_driver_register ( & w83627hf_driver ) ;
if ( err )
goto exit ;
/* Sets global pdev as a side effect */
err = w83627hf_device_add ( address , & sio_data ) ;
if ( err )
goto exit_driver ;
return 0 ;
exit_driver :
platform_driver_unregister ( & w83627hf_driver ) ;
exit :
return err ;
2005-04-17 02:20:36 +04:00
}
static void __exit sensors_w83627hf_exit ( void )
{
2007-05-08 19:22:00 +04:00
platform_device_unregister ( pdev ) ;
platform_driver_unregister ( & w83627hf_driver ) ;
2005-04-17 02:20:36 +04:00
}
MODULE_AUTHOR ( " Frodo Looijaard <frodol@dds.nl>, "
" Philip Edelbrock <phil@netroedge.com>, "
" and Mark Studebaker <mdsxyz123@yahoo.com> " ) ;
MODULE_DESCRIPTION ( " W83627HF driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
module_init ( sensors_w83627hf_init ) ;
module_exit ( sensors_w83627hf_exit ) ;