* [lm-sensors] NEW Nuvoton w83795 hw chip driver
@ 2009-03-03 8:20 Wsong
2009-03-12 13:06 ` Jean Delvare
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: Wsong @ 2009-03-03 8:20 UTC (permalink / raw)
To: lm-sensors
[-- Attachment #1.1: Type: text/plain, Size: 1994 bytes --]
Dear lm-sensor group,
I am glad to submit to you the driver for Nuvoton W83795G/ADG hw monitor chip.
The W83795G/ADG chip information are show at here:
http://www.nuvoton.com/hq/enu/ProductAndSales/ProductLines/ComputerIC/HardwareMonitor/HWMonitorforDesktopAndServer/
Driver files list:
The attach file "wb83795.c" is the main driver file. This driver passed test on kernel 2.6.28.7.
The attach file "Makefile" is used for compile the driver.
Patch files for lm-sensors 3.0.3:
The attach file "795_sensor3.conf" is the 795 related lines for sensor3.conf. But the exact names and settings may be changed for the motherboards.
The attach file "DESC" is the list of sys files which 795 driver would create.
The attach file "sensors-detect.3.0.3.patch" add detect 795 chip for "sensor-detect" tool in lm-sensors 3.0.3 package.
Until now, it seems there is not a motherboard based on W83795G/ADG in the market, and I am sure not the 795 SPEC could be share to you or not.
Please contact me if you need any help, want to know any information or have some other questions.
Thank you.
Best Regards,
wsong
===========================================================================================
The privileged confidential information contained in this email is intended for use only by the addressees as indicated by the original sender of this email. If you are not the addressee indicated in this email or are not responsible for delivery of the email to such a person, please kindly reply to the sender indicating this fact and delete all copies of it from your computer and network server immediately. Your cooperation is highly appreciated. It is advised that any unauthorized use of confidential information of Nuvoton is strictly prohibited; and any information in this email irrelevant to the official business of Nuvoton shall be deemed as neither given nor endorsed by Nuvoton.
[-- Attachment #1.2: Type: text/html, Size: 9599 bytes --]
[-- Attachment #2: 795_sensors3.conf --]
[-- Type: application/octet-stream, Size: 1211 bytes --]
# Here are configurations for Nuvoton W83795 chip.
chip "w83795-*"
label in0 "VSEN1"
label in1 "VSEN2"
label in2 "VSEN3"
label in3 "VSEN4"
label in4 "VSEN5"
label in5 "VSEN6"
label in6 "VSEN7"
label in7 "VSEN8"
label in8 "VSEN9"
label in9 "VSEN10"
label in10 "VSEN11"
label in11 "Vtt"
label in12 "3VDD"
label in13 "3VSB"
label in14 "VBAT"
label in15 "VSEN12"
label in16 "VSEN13"
label in17 "VSEN14"
label in18 "VSEN15"
label in19 "VSEN16"
label in20 "VSEN17"
label temp1 "Temp1"
label temp2 "Temp2"
label temp3 "Temp3"
label temp4 "Temp4"
label temp5 "Temp5"
label temp6 "Temp6"
label temp7 "DTS1"
label temp8 "DTS2"
label temp9 "DTS3"
label temp10 "DTS4"
label temp11 "DTS5"
label temp12 "DTS6"
label temp13 "DTS7"
label temp14 "DTS8"
compute in17 @/(8.0) , (8.0)*@
compute in18 @/(8.0) , (8.0)*@
compute in19 @/(8.0) , (8.0)*@
compute in20 @/(8.0) , (8.0)*@
# fan1 adjustments examples
# set fan1_min 1500
# temp2 limits examples
# set temp2_max 45
# set temp2_max_hyst 40
# ignore examples
# ignore fan7
# ignore temp3
[-- Attachment #3: DESC --]
[-- Type: application/octet-stream, Size: 7596 bytes --]
The description file of w83795g/adg hw driver.
Index
I. General Sysfs Interface
II. SmartFan Sysfs Interface
----------------------------------
I. General Sysfs Interface
1) Voltage sys files
in[0-20]_input The input values of current voltage.
RO
in[0-20]_max
in[0-20]_min
The max/min voltage value.
RW
2) Fan speed sys files
fan[1-14]_input The input values of fan speed.
RO
fan[1-14]_min
The min fan speed value.
RW
fan[1-8]_div The divisor of current fan.
Valid value range is 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 32, 64, 128.
3) Temperature sys files
temp[1-6]_input The input values of temperature.
RO
temp[1-6]_crit
temp[1-6]_crit_hyst
The critical and hyst of critical temperature value.
If temperature exceed the critical values, related FANCTL will be set to ouput 100%.
RW
temp[1-6]_max
temp[1-6]_max_hyst
The max and hyst of max temperature value.
These registers on 795 SPEC are named as "Critical" and "Critical Hystersis".
RW
temp[1-6]_warn
temp[1-6]_warn_hyst
The warning and hyst of warning temperature value.
RW
temp[1-6]_type 3: Thermal Diode, 4: Thermistor
temp5 and temp6 only support Thermistor type.
RW
4) DTS sys files
temp[7-14]_input The input values of DTS temperature.
RO
temp[7-14]_max
temp[7-14]_max_hyst
The max and hyst of max DTS temperature value.
These registers on 795 SPEC are named as "Critical" and "Critical Hystersis".
RW
temp[7-14]_warn
temp[7-14]_warn_hyst
The warning and hyst of warning DTS temperature value.
RW
temp[7-14]_type 5: AMD SB-TSI, 6: PECI
These arguments are selected by BIOS. Do not allow user change it.
RO
5) Alarm and Beep related sys files
in[0-20]_alarm
fan[1-14]_alarm
temp[1-6]_alarm
0: no alarm, 1: alarm.
RO
chassis
Read 0: no chassis alarm, Read 1: chassis alarm.
Write ANY value: clear alarm status.
RW
beep_enable 0: no beeps. 1: beeps.
RW
in[0-20]_beep
fan[1-14]_beep
temp[1-6]_beep
0: diable, 1: enable.
RW
6) Fault related sys files
in[0-20]_input_fault
fan[1-14]_input_fault
0: no fault. 1: fault.
RW
in_fault_enable 0: enable fault. 1: disable.
RW
fan_fault_enable 0: enable fault. 1: disable.
RW
7) Other
cpu[0-2]_vid CPU core reference voltage.
RO
Not always correct.
vrm Voltage Regulator Module version number.
RW
Do not change.
II. SmartFan Sysfs Interface
1. PWM related sys files
pwm[1-8] FANCTL1 - FANCTL8 fan output value.
Only in PWM mode, write value can control fan output speed.
RW
pwm[1-8]_nonstop
FANCTL1 - FANCTL8 fan output Nonstop value.
RW
pwm[1-8]_start
FANCTL1 - FANCTL8 fan output Start-up value.
RW
pwm[1-8]_stop_time
FANCTL1 - FANCTL8 fan output Stop Time.
RW
pwm_default
The initial speed of every fan. Only affect after next time system power on.
RW
pwm_uptime
pwm_downtime
The time interval of fan speed change time for smart fan or other reasons.
Never accept values less than 50.
RW
2. PWM mode and Smart Fan Mode Select
pwm[1-8]_enable
Modify values of temp*_auto_channels_pwm, the Temperature to Fan Mapping Relationships Registers.
value = 0: DC mode. FANCTL outputs full fan speed and ignore the values of pwm[1-8].
value = 1: PWM mode. FANCTL output values are controlled by pwm[1-8].
value = 2: Speed Cruise mode. FANCTL output value increases until related fan[1-8]_input value exceeds the fan[1-8]_target_speed.
value = 3: Current FANCTL output is not controlled by pwm[1-8]_enable. Refer temp[1-6]_auto_channels_pwm and temp[1-6]_pwm_enable to set its mode.
RW
[CAUTION] Never allow set pwm[1-8]_enable as '3'!
temp[1-6]_source_sel
Selction of Temperature Source. Valid value range is 0-15.
Refer Nuvoton W83795G/ADG H/W Monitor chip SPEC for more details.
RW
temp[1-6]_auto_channels_pwm
Temperature to Fan mapping Relationships.
RW
temp[1-6]_pwm_enable
Set Temp1 - Temp6 for Thermal Cruise mode (3) or Smart Fan IV mode (4).
value = 3: Thermal Cruise mode.
value = 4: Smart Fan IV mode.
RW
Thermal Cruise or Smart Fan IV mode Setting steps:
(1) Set pwm[1-8]_enable to 0 or 1.
(2) Set temp[1-6]_auto_channels_pwm for temperature to fan mapping.
(3) Set temp[1-6]_pwm_enable for Thermal Cruise or Smart Fan mode.
Now selected FANCTL is running under Thermal Cruise.
PWM mode check steps:
(1) Check file pwm[1-8]_enable. The value 0, 1, 2 is for DC Output, PWM and Speed Cruise mode.
(2) If the value is 3, check temp[1-6]_auto_channels_pwm and temp[1-6]_pwm_enable.
(3) temp[1-6]_auto_channels may make 1 TEMP controls several FANOUT, or make FANCTL affected by multi TEMP. Refer the SPEC for more details.
(4) Check temp[1-6]_pwm_enable. The value 3, 4 is for Thermal Cruise and Smart Fan IV mode.
[CAUTION] Set pwm[1-8]_enable would make the PWM related bits in temp[1-6]_auto_channels_pwm become '0'.
For example, set pwm1_enable as 0 will make all bit 0 in temp[1-6]_auto_channels_pwm become '0'.
Only when all related bits in tfmr set as '0', the FANCTL will be set as manual mode.
[CAUTION] The register values of Thermal Cruise or Smart Fan IV should be set before start these automatic mode.
So if you want to change these values, set related FANCTL mode to PWM. And resume the automatic mode after modified the setting register values.
3. Speed Cruise
speed_cruise[1-8]_target
Target fan speed in Speed Cruise Mode.
RW
speed_cruise_tolerance
Tolerance of target fan speed.
RW
4. Thermal Cruise
thermal_cruise[1-6]
Target temperature in Thermal Cruise Mode.
RW
temp[1-6]_operation_hyst
Hystersis of operation temperature for Thermal Cruise Mode and Smart Fan IV Mode.
RW
5. Smart Fan IV
temp[1-6]_auto_points[1-7]_pwm
PWM fan output values.
RW
temp[1-6]_auto_points[1-7]_temp
Smart Fan IV target temperature values.
RW
temp[1-6]_operation_hyst
Hystersis of operation temperature for Thermal Cruise Mode and Smart Fan IV Mode.
RW
[-- Attachment #4: sensors-detect.3.0.3.patch --]
[-- Type: application/octet-stream, Size: 1710 bytes --]
--- sensors-detect.bak 2008-11-27 14:39:25.000000000 -0500
+++ sensors-detect 2008-11-27 16:36:05.000000000 -0500
@@ -828,6 +828,12 @@
i2c_detect => sub { w83793_detect(0, @_); },
},
{
+ name => "Nuvoton W83795G/ADG",
+ driver => "w83795",
+ i2c_addrs => [0x2c..0x2f],
+ i2c_detect => sub { w83795_detect(0, @_); },
+ },
+ {
name => "Winbond W83791SD",
driver => "not-a-sensor",
i2c_addrs => [0x2c..0x2f],
@@ -4665,6 +4671,40 @@
return @res;
}
+# $_[0]: Chip to detect (0 = W83795)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected
+# 6 if detected and bank different from 0
+# 8 if detected, bank is 0
+# Registers used:
+# 0xfc: Full I2C Address
+# 0x00: Vendor ID byte selection, and bank selection(Bank 0, 1, 2)
+# 0xfd: Vendor ID(Bank 0, 1, 2)
+# 0xfe: Device ID(Bank 0, 1, 2)
+sub w83795_detect
+{
+ my ($bank, $reg, @res);
+ my ($chip, $file, $addr) = @_;
+
+ $bank = i2c_smbus_read_byte_data($file, 0x00);
+ $reg = i2c_smbus_read_byte_data($file, 0xfd);
+
+ return unless (($bank & 0x80) == 0x00 and $reg == 0xa3) or
+ (($bank & 0x80) == 0x80 and $reg == 0x5c);
+
+ $reg = i2c_smbus_read_byte_data($file, 0xfe);
+ return if $chip == 0 and $reg != 0x79;
+
+# If bank 0 is selected, we can do more checks
+ return 6 unless ($bank & 0x07) == 0;
+ $reg = i2c_smbus_read_byte_data($file, 0xfc) & 0x7f;
+ return unless ($reg == $addr);
+
+ @res = (8);
+ return @res;
+}
+
# $_[0]: A reference to the file descriptor to access this chip.
# $_[1]: Address
# Returns: undef if not detected, 3 if detected
[-- Attachment #5: wb83795.c --]
[-- Type: application/octet-stream, Size: 67480 bytes --]
/*
w83795.c - Linux kernel driver for hardware monitoring
Copyright (C) 2008 Nuvoton Technology Corp.
Wei Song
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation - version 2.
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., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Supports following chips:
Chip #vin #fanin #pwm #temp #dts wchipid vendid i2c ISA
w83795g 21 14 8 6 8 0x79 0x5ca3 yes no
w83795adg 18 14 2 6 8 0x79 0x5ca3 yes no
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-vid.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/delay.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(w83795);
static int reset;
module_param(reset, bool, 0);
MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended");
#define W83795_REG_BANKSEL 0x00
#define W83795_REG_VENDORID 0xfd
#define W83795_REG_CHIPID 0xfe
#define W83795_REG_DEVICEID 0xfb
#define W83795_REG_I2C_ADDR 0xfc
#define W83795_REG_CONFIG 0x01
#define W83795_REG_CONFIG_CONFIG48 0x04
/* Multi-Function Pin Ctrl Registers */
#define W83795_REG_VOLT_CTRL1 0x02
#define W83795_REG_VOLT_CTRL2 0x03
#define W83795_REG_TEMP_CTRL1 0x04
#define W83795_REG_TEMP_CTRL2 0x05
#define W83795_REG_FANIN_CTRL1 0x06
#define W83795_REG_FANIN_CTRL2 0x07
#define W83795_REG_VMIGB_CTRL 0x08
#define TEMP_CTRL_DISABLE 0
#define TEMP_CTRL_TD 1
#define TEMP_CTRL_VSEN 2
#define TEMP_CTRL_TR 3
#define TEMP_CTRL_SHIFT 4
#define TEMP_CTRL_HASIN_SHIFT 5
/* temp mode may effect VSEN17-12 (in20-15) */
static u16 W83795_REG_TEMP_CTRL[][6] = {
/* Disable, TD, VSEN, TR, register shift value, has_in shift num */
{0x00, 0x01, 0x02, 0x03, 0, 17}, // TR1
{0x00, 0x04, 0x08, 0x0C, 2, 18}, // TR2
{0x00, 0x10, 0x20, 0x30, 4, 19}, // TR3
{0x00, 0x40, 0x80, 0xC0, 6, 20}, // TR4
{0x00, 0x00, 0x02, 0x03, 0, 15}, // TR5
{0x00, 0x00, 0x08, 0x0C, 2, 16}, // TR6
};
#define TEMP_READ 0
#define TEMP_CRIT 1
#define TEMP_CRIT_HYST 2
#define TEMP_WARN 3
#define TEMP_WARN_HYST 4
/* only crit and crit_hyst affect real-time alarm status
current crit crit_hyst warn warn_hyst */
static u16 W83795_REG_TEMP[][5] = {
{0x21, 0x96, 0x97, 0x98, 0x99}, // TD1/TR1
{0x22, 0x9a, 0x9b, 0x9c, 0x9d}, // TD2/TR2
{0x23, 0x9e, 0x9f, 0xa0, 0xa1}, // TD3/TR3
{0x24, 0xa2, 0xa3, 0xa4, 0xa5}, // TD4/TR4
{0x1f, 0xa6, 0xa7, 0xa8, 0xa9}, // TR5
{0x20, 0xaa, 0xab, 0xac, 0xad}, // TR6
};
#define IN_READ 0
#define IN_MAX 1
#define IN_LOW 2
static const u16 W83795_REG_IN[][3] = {
/* Current, HL, LL */
{0x10, 0x70, 0x71}, /* VSEN1 */
{0x11, 0x72, 0x73}, /* VSEN2 */
{0x12, 0x74, 0x75}, /* VSEN3 */
{0x13, 0x76, 0x77}, /* VSEN4 */
{0x14, 0x78, 0x79}, /* VSEN5 */
{0x15, 0x7a, 0x7b}, /* VSEN6 */
{0x16, 0x7c, 0x7d}, /* VSEN7 */
{0x17, 0x7e, 0x7f}, /* VSEN8 */
{0x18, 0x80, 0x81}, /* VSEN9 */
{0x19, 0x82, 0x83}, /* VSEN10 */
{0x1A, 0x84, 0x85}, /* VSEN11 */
{0x1B, 0x86, 0x87}, /* VTT */
{0x1C, 0x88, 0x89}, /* 3VDD */
{0x1D, 0x8a, 0x8b}, /* 3VSB */
{0x1E, 0x8c, 0x8d}, /* VBAT */
{0x1F, 0xa6, 0xa7}, /* VSEN12 */
{0x20, 0xaa, 0xab}, /* VSEN13 */
{0x21, 0x96, 0x97}, /* VSEN14 */
{0x22, 0x9a, 0x9b}, /* VSEN15 */
{0x23, 0x9e, 0x9f}, /* VSEN16 */
{0x24, 0xa2, 0xa3}, /* VSEN17 */
};
#define W83795_REG_VRLSB 0x3C
#define VRLSB_SHIFT 6
static const u8 W83795_REG_IN_HL_LSB[] = {
0x8e, /* VSEN1-4 */
0x90, /* VSEN5-8 */
0x92, /* VSEN9-11 */
0x94, /* VTT, 3VDD, 3VSB, 3VBAT */
0xa8, /* VSEN12 */
0xac, /* VSEN13 */
0x98, /* VSEN14 */
0x9c, /* VSEN15 */
0xa0, /* VSEN16 */
0xa4, /* VSEN17 */
};
#define IN_LSB_REG(index, type) \
(((type) == 1) ? W83795_REG_IN_HL_LSB[(index)] \
: (W83795_REG_IN_HL_LSB[(index)] + 1))
#define IN_LSB_REG_NUM 10
#define IN_LSB_SHIFT 0
#define IN_LSB_IDX 1
static const u8 IN_LSB_SHIFT_IDX[][2] = {
/* High/Low LSB shift, LSB No. */
{0x00, 0x00}, /* VSEN1 */
{0x02, 0x00}, /* VSEN2 */
{0x04, 0x00}, /* VSEN3 */
{0x06, 0x00}, /* VSEN4 */
{0x00, 0x01}, /* VSEN5 */
{0x02, 0x01}, /* VSEN6 */
{0x04, 0x01}, /* VSEN7 */
{0x06, 0x01}, /* VSEN8 */
{0x00, 0x02}, /* VSEN9 */
{0x02, 0x02}, /* VSEN10 */
{0x04, 0x02}, /* VSEN11 */
{0x00, 0x03}, /* VTT */
{0x02, 0x03}, /* 3VDD */
{0x04, 0x03}, /* 3VSB */
{0x06, 0x03}, /* VBAT */
{0x06, 0x04}, /* VSEN12 */
{0x06, 0x05}, /* VSEN13 */
{0x06, 0x06}, /* VSEN14 */
{0x06, 0x07}, /* VSEN15 */
{0x06, 0x08}, /* VSEN16 */
{0x06, 0x09}, /* VSEN17 */
};
/*3VDD, 3VSB, VBAT * 0.006 */
#define REST_VLT_BEGIN 12 /* the 13th volt to 15th */
#define REST_VLT_END 14 /* the 13th volt to 15th */
#define W83795_REG_FAN(index) (0x2E + (index))
#define W83795_REG_FAN_MIN_HL(index) (0xB6 + (index))
#define W83795_REG_FAN_MIN_LSB(index) (0xC4 + (index) / 2)
#define W83795_REG_FAN_MIN_LSB_SHIFT(index) \
(((index) % 1) ? 4 : 0)
#define W83795_REG_FAN_CTRL_SHIFT(index) \
(((index) > 7) ? ((index) - 8) : (index))
#define W83795_REG_VID_CTRL 0x6A
#define W83795_REG_DVID_LIMHI 0x6B
#define W83795_REG_DVID_LIMLO 0x6C
#define W83795_REG_VSEN_VIDIN(index) (0x6D + (index))
#define ALARM_BEEP_REG_NUM 6
#define W83795_REG_ALARM(index) (0x41 + (index))
#define W83795_REG_BEEP(index) (0x50 + (index))
#define W83795_REG_CLR_CHASSIS 0x4D
#define IN_FAULT 0
#define FAN_FAULT 1
#define W83795_REG_FAULT(index, nr) \
((((nr) == 0) ? 0x65 : 0x68) + (index))
#define FAULT_NUM(index) \
(((index) <= 7) ? 0 : \
((index) <= 14) ? 1 : 2)
#define FAULT_SHIFT(index) \
(((index) <= 7) ? (index) : \
((index) <= 14) ? (index - 8) : (index - 15))
#define W83795_REG_FAULT_ENABLE(index) \
((index == 0) ? 0x67 : 0x69)
#define W83795_REG_TEMP_NUM 6
#define W83795_REG_FCMS1 0x201
#define W83795_REG_FCMS2 0x208
#define W83795_REG_TFMR(index) (0x202 + (index))
#define W83795_REG_FOMC 0x20F
#define W83795_REG_FOPFP(index) (0x218 + (index))
#define W83795_REG_TSS(index) ((index) + 0x209)
#define PWM_OUTPUT 0
#define PWM_START 1
#define PWM_NONSTOP 2
#define PWM_STOP_TIME 3
#define PWM_DIV 4
#define W83795_REG_PWM(index, nr) \
(((nr) == 0 ? 0x210 : \
(nr) == 1 ? 0x220 : \
(nr) == 2 ? 0x228 : \
(nr) == 3 ? 0x230 : 0x218) + (index))
#define W83795_REG_FOPFP_DIV(index) \
(((index) < 8) ? ((index) + 1) : \
((index) == 8) ? 12 : \
(16 << ((index) - 9)))
#define W83795_REG_FTSH(index) (0x240 + (index) * 2)
#define W83795_REG_FTSL(index) (0x241 + (index) * 2)
#define W83795_REG_TFTS 0x250
#define TEMP_PWM_TTTI 0
#define TEMP_PWM_CTFS 1
#define TEMP_PWM_HCT 2
#define TEMP_PWM_HOT 3
#define W83795_REG_TTTI(index) (0x260 + (index))
#define W83795_REG_CTFS(index) (0x268 + (index))
#define W83795_REG_HT(index) (0x270 + (index))
#define SF4_TEMP 0
#define SF4_PWM 1
#define W83795_REG_SF4_TEMP(temp_num, index) \
(0x280 + 0x10 * (temp_num) + (index))
#define W83795_REG_SF4_PWM(temp_num, index) \
(0x288 + 0x10 * (temp_num) + (index))
#define W83795_REG_DTSC 0x301
#define W83795_REG_DTSE 0x302
#define W83795_REG_DTS(index) (0x26 + (index))
#define DTS_CRIT 0
#define DTS_CRIT_HYST 1
#define DTS_WARN 2
#define DTS_WARN_HYST 3
#define W83795_REG_DTS_EXT(index) (0xB2 + (index))
#define SETUP_PWM_DEFAULT 0
#define SETUP_PWM_UPTIME 1
#define SETUP_PWM_DOWNTIME 2
#define W83795_REG_SETUP_PWM(index) (0x20C + (index))
static inline u16 IN_FROM_REG(u8 index, u16 val)
{
if ((index >= REST_VLT_BEGIN) && (index <= REST_VLT_END))
return (val * 6);
else
return (val * 2);
}
static inline u16 IN_TO_REG(u8 index, u16 val)
{
if ((index >= REST_VLT_BEGIN) && (index <= REST_VLT_END))
return (val / 6);
else
return (val / 2);
}
static inline unsigned long FAN_FROM_REG(u16 val)
{
if ((val >= 0xff0) || (val == 0))
return 0;
return (1350000UL / val);
}
static inline u16 FAN_TO_REG(long rpm)
{
if (rpm <= 0)
return 0x0fff;
return SENSORS_LIMIT((1350000 + (rpm >> 1)) / rpm, 1, 0xffe);
}
static inline unsigned long TIME_FROM_REG(u8 reg)
{
return (reg * 100);
}
static inline u8 TIME_TO_REG(unsigned long val)
{
return SENSORS_LIMIT((val + 50) / 100, 0, 0xff);
}
static inline long TEMP_FROM_REG(s8 reg)
{
return (reg * 1000);
}
static inline s8 TEMP_TO_REG(long val, s8 min, s8 max)
{
return SENSORS_LIMIT((val < 0 ? -val : val) / 1000, min, max);
}
enum chip_types {w83795g, w83795adg};
struct w83795_data {
struct device *hwmon_dev;
struct mutex update_lock;
unsigned long last_updated; /* In jiffies */
enum chip_types chip_type;
u8 bank;
u8 vrm;
u8 vid[3];
u8 has_vid; /* Enable monitor VID or not, affected by CR 0x6A */
u32 has_in; /* Enable monitor VIN or not, affected by CR 0x02, 0x03 */
u16 in[21][3]; /* Register value, read/high/low */
u8 in_lsb[10][3]; /* LSB Register value, high/low */
u8 has_gain; /* has gain: in17 -in20 * 8 */
u16 has_fan; /* Enable fan14-1 or not, affected by CR 0x06, 0x07 */
u16 fan[14]; /* Register value combine */
u16 fan_min[14]; /* Register value combine */
u8 has_temp; /* Enable monitor temp6-1 or not, affected by CR 0x04, 0x05 */
u8 temp[6][5]; /* current, crit, crit_hyst, warn, warn_hyst */
u8 temp_read_vrlsb[6];
u8 temp_mode; /* bit 0: TR mode, bit 1: TD mode */
u8 temp_src[3]; /* Register value */
u8 enable_dts; /* Enable PECI and SB-TSI,
* bit 0: =1 enable, =0 disable ,
* bit 1: =1 AMD SB-TSI, =0 Intel PECI */
u8 has_dts; /* Enable monitor DTS temp */
u8 dts[8]; /* Register value */
u8 dts_read_vrlsb[8]; /* Register value */
u8 dts_ext[4]; /* Register value */
u32 in_fault;
u16 fan_fault;
u8 fault_enable; /* bit 0: in, bit 1: fan */
u8 has_pwm; /* 795g supports 8 pwm, 795adg only supports 2, no config register, only affected by chip type */
u8 pwm[8][5]; /* Register value, output, start, non stop, stop time, div */
u8 pwm_fcms[2]; /* Register value */
u8 pwm_tfmr[6]; /* Register value */
u8 pwm_fomc; /* Register value */
u16 target_speed[8]; /* Register value, target speed for speed cruise */
u8 tol_speed; /* tolerance of target speed */
u8 pwm_temp[6][4]; /* TTTI, CTFS, HCT, HOT */
u8 sf4_reg[6][2][7]; /* 6 temp, temp/dcpwm, 7 registers */
u8 setup_pwm[3]; /* Register value */
u8 alarms[6]; /* Register value */
u8 beeps[6]; /* Register value */
u8 beep_enable;
char valid;
};
static u8 w83795_read_value(struct i2c_client *client, u16 reg);
static int w83795_write_value(struct i2c_client *client, u16 reg, u8 value);
static int w83795_probe(struct i2c_client *client,
const struct i2c_device_id *id);
static int w83795_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info);
static int w83795_remove(struct i2c_client *client);
static void w83795_init_client(struct i2c_client *client);
static struct w83795_data *w83795_update_device(struct device *dev);
static const struct i2c_device_id w83795_id[] = {
{ "w83795", w83795 },
{ }
};
MODULE_DEVICE_TABLE(i2c, w83795_id);
static struct i2c_driver w83795_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "w83795",
},
.probe = w83795_probe,
.remove = w83795_remove,
.id_table = w83795_id,
.detect = w83795_detect,
.address_data = &addr_data,
};
static ssize_t
show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
{
struct w83795_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", data->vrm);
}
static ssize_t
show_vid(struct device *dev, struct device_attribute *attr, char *buf)
{
struct w83795_data *data = w83795_update_device(dev);
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
return sprintf(buf, "%d\n", vid_from_reg(data->vid[nr], data->vrm));
}
static ssize_t
store_vrm(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct w83795_data *data = dev_get_drvdata(dev);
data->vrm = simple_strtoul(buf, NULL, 10);
return count;
}
#define ALARM_STATUS 0
#define BEEP_ENABLE 1
static ssize_t
show_alarm_beep(struct device *dev, struct device_attribute *attr, char *buf)
{
struct w83795_data *data = w83795_update_device(dev);
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index >> 3;
int bit = sensor_attr->index & 0x07;
u8 val;
if (ALARM_STATUS == nr) {
val = (data->alarms[index] >> (bit)) & 1;
} else { /* BEEP_ENABLE */
val = (data->beeps[index] >> (bit)) & 1;
}
return sprintf(buf, "%u\n", val);
}
static ssize_t
store_beep(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int index = sensor_attr->index >> 3;
int shift = sensor_attr->index & 0x07;
u8 beep_bit = 1 << shift;
u8 val;
val = simple_strtoul(buf, NULL, 10);
if (val != 0 && val != 1)
return -EINVAL;
mutex_lock(&data->update_lock);
data->beeps[index] = w83795_read_value(client, W83795_REG_BEEP(index));
data->beeps[index] &= ~beep_bit;
data->beeps[index] |= val << shift;
w83795_write_value(client, W83795_REG_BEEP(index), data->beeps[index]);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t
show_beep_enable(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
return sprintf(buf, "%u\n", data->beep_enable);
}
static ssize_t
store_beep_enable(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
u8 val = simple_strtoul(buf, NULL, 10);
u8 tmp;
if (val != 0 && val != 1)
return -EINVAL;
mutex_lock(&data->update_lock);
data->beep_enable = val;
tmp = w83795_read_value(client, W83795_REG_BEEP(5));
tmp &= 0x7f;
tmp |= val << 7;
w83795_write_value(client, W83795_REG_BEEP(5), tmp);
mutex_unlock(&data->update_lock);
return count;
}
/* Write any value to clear chassis alarm */
static ssize_t
store_chassis_clear(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
u8 val;
mutex_lock(&data->update_lock);
val = w83795_read_value(client, W83795_REG_CLR_CHASSIS);
val |= 0x80;
w83795_write_value(client, W83795_REG_CLR_CHASSIS, val);
mutex_unlock(&data->update_lock);
return count;
}
#define FAN_INPUT 0
#define FAN_MIN 1
static ssize_t
show_fan(struct device *dev, struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index;
struct w83795_data *data = w83795_update_device(dev);
u16 val;
if (FAN_INPUT == nr) {
val = data->fan[index] & 0x0fff;
} else {
val = data->fan_min[index] & 0x0fff;
}
return sprintf(buf, "%lu\n", FAN_FROM_REG(val));
}
static ssize_t
store_fan_min(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int index = sensor_attr->index;
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
u16 val = FAN_TO_REG(simple_strtoul(buf, NULL, 10));
mutex_lock(&data->update_lock);
data->fan_min[index] = val;
w83795_write_value(client, W83795_REG_FAN_MIN_HL(index),
(val >> 4) & 0xff);
val &= 0x0f;
if (index % 1) {
val <<= 4;
val |= w83795_read_value(client, W83795_REG_FAN_MIN_LSB(index)) & 0x0f;
} else {
val |= w83795_read_value(client, W83795_REG_FAN_MIN_LSB(index)) & 0xf0;
}
w83795_write_value(client, W83795_REG_FAN_MIN_LSB(index), val & 0xff);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t
show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
{
struct w83795_data *data = w83795_update_device(dev);
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index;
u16 val;
switch (nr) {
case PWM_STOP_TIME:
val = TIME_FROM_REG(data->pwm[index][nr]);
break;
case PWM_DIV:
val = W83795_REG_FOPFP_DIV(data->pwm[index][nr] & 0x0f);
break;
default:
val = data->pwm[index][nr];
break;
}
return sprintf(buf, "%u\n", val);
}
static ssize_t
store_pwm(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index;
u16 val;
int i;
mutex_lock(&data->update_lock);
switch (nr) {
case PWM_STOP_TIME:
val = TIME_TO_REG(simple_strtoul(buf, NULL, 10));
break;
case PWM_DIV:
val = simple_strtoul(buf, NULL, 10);
for (i = 0; i < 16; i ++) {
if (W83795_REG_FOPFP_DIV(i) == val) {
val = i;
break;
}
}
if (i >= 16)
goto err_end;
val |= w83795_read_value(client, W83795_REG_PWM(index, nr)) & 0x80;
break;
default:
val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 0xff);
break;
}
w83795_write_value(client, W83795_REG_PWM(index, nr), val);
data->pwm[index][nr] = val & 0xff;
mutex_unlock(&data->update_lock);
return count;
err_end:
mutex_unlock(&data->update_lock);
return -EINVAL;
}
static ssize_t
show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
int index = sensor_attr->index;
u8 tmp;
if (1 == (data->pwm_fcms[0] & (1 << index))) {
tmp = 2;
goto out;
}
for (tmp = 0; tmp < 6; tmp ++) {
if (data->pwm_tfmr[tmp] & (1 << index)) {
tmp = 3;
goto out;
}
}
if (data->pwm_fomc & (1 << index))
tmp = 0;
else
tmp = 1;
out:
return sprintf(buf, "%u\n", tmp);
}
static ssize_t
store_pwm_enable(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int index = sensor_attr->index;
u8 val = simple_strtoul(buf, NULL, 10);
int i;
if (val > 2)
return -EINVAL;
mutex_lock(&data->update_lock);
switch (val) {
case 0:
case 1:
data->pwm_fcms[0] &= ~(1 << index);
w83795_write_value(client, W83795_REG_FCMS1,
data->pwm_fcms[0]);
for (i = 0; i < 6; i ++) {
data->pwm_tfmr[i] &= ~(1 << index);
w83795_write_value(client, W83795_REG_TFMR(i),
data->pwm_tfmr[i]);
}
data->pwm_fomc |= 1 << index;
data->pwm_fomc ^= val << index;
w83795_write_value(client, W83795_REG_FOMC,
data->pwm_fomc);
break;
case 2:
data->pwm_fcms[0] |= (1 << index);
w83795_write_value(client, W83795_REG_FCMS1,
data->pwm_fcms[0]);
break;
}
mutex_unlock(&data->update_lock);
return count;
mutex_unlock(&data->update_lock);
return -EINVAL;
}
static ssize_t
show_temp_src(struct device *dev, struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
int index = sensor_attr->index;
u8 val = index / 2;
u8 tmp = data->temp_src[val];
if (index % 1)
val = 4;
else
val = 0;
tmp >>= val;
tmp &= 0x0f;
return sprintf(buf, "%u\n", tmp);
}
static ssize_t
store_temp_src(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int index = sensor_attr->index;
u8 tmp = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 15);
u8 val = index / 2;
mutex_lock(&data->update_lock);
if (index % 1) {
tmp <<= 4;
data->temp_src[val] &= 0x0f;
} else {
data->temp_src[val] &= 0xf0;
}
data->temp_src[val] |= tmp;
w83795_write_value(client, W83795_REG_TSS(val), data->temp_src[val]);
mutex_unlock(&data->update_lock);
return count;
}
#define TEMP_PWM_ENABLE 0
#define TEMP_PWM_FAN_MAP 1
static ssize_t
show_temp_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index;
u8 tmp = 0xff;
switch (nr) {
case TEMP_PWM_ENABLE:
tmp = (data->pwm_fcms[1] >> index) & 1;
if (tmp)
tmp = 4;
else
tmp = 3;
break;
case TEMP_PWM_FAN_MAP:
tmp = data->pwm_tfmr[index];
break;
}
return sprintf(buf, "%u\n", tmp);
}
static ssize_t
store_temp_pwm_enable(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index;
u8 tmp = simple_strtoul(buf, NULL, 10);
switch (nr) {
case TEMP_PWM_ENABLE:
if ((tmp != 3) && (tmp != 4))
return -EINVAL;
tmp -= 3;
mutex_lock(&data->update_lock);
data->pwm_fcms[1] &= ~(1 << index);
data->pwm_fcms[1] |= tmp << index;
w83795_write_value(client, W83795_REG_FCMS2,
data->pwm_fcms[1]);
mutex_unlock(&data->update_lock);
break;
case TEMP_PWM_FAN_MAP:
mutex_lock(&data->update_lock);
tmp = SENSORS_LIMIT(tmp, 0, 0xff);
w83795_write_value(client, W83795_REG_TFMR(index), tmp);
data->pwm_tfmr[index] = tmp;
mutex_unlock(&data->update_lock);
break;
}
return count;
}
#define FANIN_TARGET 0
#define FANIN_TOL 1
static ssize_t
show_fanin(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index;
u16 tmp = 0;
switch (nr) {
case FANIN_TARGET:
tmp = FAN_FROM_REG(data->target_speed[index]);
break;
case FANIN_TOL:
tmp = data->tol_speed;
break;
}
return sprintf(buf, "%u\n", tmp);
}
static ssize_t
store_fanin(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index;
u16 val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
switch (nr) {
case FANIN_TARGET:
val = FAN_TO_REG(SENSORS_LIMIT(val, 0, 0xfff));
w83795_write_value(client, W83795_REG_FTSH(index), (val >> 4) & 0xff);
w83795_write_value(client, W83795_REG_FTSL(index), (val << 4) & 0xf0);
data->target_speed[index] = val;
break;
case FANIN_TOL:
val = SENSORS_LIMIT(val, 0, 0x3f);
w83795_write_value(client, W83795_REG_TFTS, val);
data->tol_speed = val;
break;
}
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t
show_temp_pwm(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index;
long tmp = TEMP_FROM_REG(data->pwm_temp[index][nr]);
return sprintf(buf, "%ld\n", tmp);
}
static ssize_t
store_temp_pwm(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index;
u8 val = simple_strtoul(buf, NULL, 10) / 1000;
u8 tmp;
mutex_lock(&data->update_lock);
switch (nr) {
case TEMP_PWM_TTTI:
val = SENSORS_LIMIT(val, 0, 0x7f);
w83795_write_value(client, W83795_REG_TTTI(index), val);
break;
case TEMP_PWM_CTFS:
val = SENSORS_LIMIT(val, 0, 0x7f);
w83795_write_value(client, W83795_REG_CTFS(index), val);
break;
case TEMP_PWM_HCT:
val = SENSORS_LIMIT(val, 0, 0x0f);
tmp = w83795_read_value(client, W83795_REG_HT(index));
tmp &= 0x0f;
tmp |= (val << 4) & 0xf0;
w83795_write_value(client, W83795_REG_HT(index), tmp);
break;
case TEMP_PWM_HOT:
val = SENSORS_LIMIT(val, 0, 0x0f);
tmp = w83795_read_value(client, W83795_REG_HT(index));
tmp &= 0xf0;
tmp |= val & 0x0f;
w83795_write_value(client, W83795_REG_HT(index), tmp);
break;
}
data->pwm_temp[index][nr] = val;
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t
show_sf4_pwm(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index;
return sprintf(buf, "%u\n", data->sf4_reg[index][SF4_PWM][nr]);
}
static ssize_t
store_sf4_pwm(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index;
u8 val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
w83795_write_value(client, W83795_REG_SF4_PWM(index, nr), val);
data->sf4_reg[index][SF4_PWM][nr] = val;
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t
show_sf4_temp(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index;
return sprintf(buf, "%u\n",
(data->sf4_reg[index][SF4_TEMP][nr]) * 1000);
}
static ssize_t
store_sf4_temp(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index;
u8 val = simple_strtoul(buf, NULL, 10) / 1000;
mutex_lock(&data->update_lock);
w83795_write_value(client, W83795_REG_SF4_TEMP(index, nr), val);
data->sf4_reg[index][SF4_TEMP][nr] = val;
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t
show_temp(struct device *dev, struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index;
struct w83795_data *data = w83795_update_device(dev);
long temp = TEMP_FROM_REG(data->temp[index][nr] & 0x7f);
if (TEMP_READ == nr)
temp += ((data->temp_read_vrlsb[index] >> VRLSB_SHIFT) & 0x03) * 250;
if (data->temp[index][nr] & 0x80)
temp = -temp;
return sprintf(buf, "%ld\n", temp);
}
static ssize_t
store_temp(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index;
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
long tmp = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp[index][nr] = TEMP_TO_REG(tmp, -128, 127);
w83795_write_value(client, W83795_REG_TEMP[index][nr],
data->temp[index][nr]);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t
show_dts_mode(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int index = sensor_attr->index;
u8 tmp;
if (data->enable_dts == 0)
return sprintf(buf, "%d\n", 0);
if ((data->has_dts >> index) & 0x01) {
if (data->enable_dts & 2)
tmp = 5;
else
tmp = 6;
} else {
tmp = 0;
}
return sprintf(buf, "%d\n", tmp);
}
static ssize_t
show_dts(struct device *dev, struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int index = sensor_attr->index;
struct w83795_data *data = w83795_update_device(dev);
long temp = TEMP_FROM_REG(data->dts[index] & 0x7f);
temp += ((data->dts_read_vrlsb[index] >> VRLSB_SHIFT) & 0x03) * 250;
if (data->dts[index] & 0x80)
temp = -temp;
return sprintf(buf, "%ld\n", temp);
}
static ssize_t
show_dts_ext(struct device *dev, struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
long temp = TEMP_FROM_REG(data->dts_ext[nr] & 0x7f);
if (data->dts_ext[nr] & 0x80)
temp = -temp;
return sprintf(buf, "%ld\n", temp);
}
static ssize_t
store_dts_ext(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
long tmp = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->dts_ext[nr] = TEMP_TO_REG(tmp, -128, 127);
w83795_write_value(client, W83795_REG_DTS_EXT(nr),
data->dts_ext[nr]);
mutex_unlock(&data->update_lock);
return count;
}
/*
Type 3: Thermal diode
Type 4: Thermistor
Temp5-6, default TR
Temp1-4, default TD
*/
static ssize_t
show_temp_mode(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int index = sensor_attr->index;
u8 tmp;
if (data->has_temp >> index & 0x01) {
if (data->temp_mode >> index & 0x01) {
tmp = 3;
} else {
tmp = 4;
}
} else {
tmp = 0;
}
return sprintf(buf, "%d\n", tmp);
}
static ssize_t
store_temp_mode(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int index = sensor_attr->index;
u8 val = simple_strtoul(buf, NULL, 10);
u8 tmp;
u32 mask;
if ((val != 4) && (val != 3))
return -EINVAL;
if ((index > 3) && (val == 3))
return -EINVAL;
mutex_lock(&data->update_lock);
if (val == 3) {
val = TEMP_CTRL_TD;
data->has_temp |= 1 << index;
data->temp_mode |= 1 << index;
} else if (val == 4) {
val = TEMP_CTRL_TR;
data->has_temp |= 1 << index;
tmp = 1 << index;
data->temp_mode &= ~tmp;
}
if (index > 3)
tmp = w83795_read_value(client, W83795_REG_TEMP_CTRL1);
else
tmp = w83795_read_value(client, W83795_REG_TEMP_CTRL2);
mask = 0x03 << W83795_REG_TEMP_CTRL[index][TEMP_CTRL_SHIFT];
tmp &= ~mask;
tmp |= W83795_REG_TEMP_CTRL[index][val];
mask = 1 << W83795_REG_TEMP_CTRL[index][TEMP_CTRL_HASIN_SHIFT];
data->has_in &= ~mask;
if (index > 3)
w83795_write_value(client, W83795_REG_TEMP_CTRL1, tmp);
else
w83795_write_value(client, W83795_REG_TEMP_CTRL2, tmp);
mutex_unlock(&data->update_lock);
return count;
}
/* show/store VIN */
static ssize_t
show_in(struct device *dev, struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index;
struct w83795_data *data = w83795_update_device(dev);
u16 val = data->in[index][nr];
u8 lsb_idx;
switch (nr) {
case IN_READ:
/* calculate this value again by sensors as sensors3.conf */
if ((index >= 17) &&
((data->has_gain >> (index - 17)) & 1))
val *= 8;
break;
case IN_MAX:
case IN_LOW:
lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX];
val <<= 2;
val |= (data->in_lsb[lsb_idx][nr] >>
IN_LSB_SHIFT_IDX[lsb_idx][IN_LSB_SHIFT]) & 0x03;
if ((index >= 17) &&
((data->has_gain >> (index - 17)) & 1))
val *= 8;
break;
}
val = IN_FROM_REG(index, val);
return sprintf(buf, "%d\n", val);
}
static ssize_t
store_in(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index;
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
u16 val = IN_TO_REG(index, simple_strtoul(buf, NULL, 10));
u8 tmp;
u8 lsb_idx;
if ((index >= 17) &&
((data->has_gain >> (index - 17)) & 1))
val /= 8;
val = SENSORS_LIMIT(val, 0, 0x3FF);
mutex_lock(&data->update_lock);
lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX];
tmp = w83795_read_value(client, IN_LSB_REG(lsb_idx, nr));
tmp &= ~(0x03 << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]);
tmp |= (val & 0x03) << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT];
w83795_write_value(client, IN_LSB_REG(lsb_idx, nr), tmp);
data->in_lsb[lsb_idx][nr] = tmp;
tmp = (val >> 2) & 0xff;
w83795_write_value(client, W83795_REG_IN[index][nr], tmp);
data->in[index][nr] = tmp;
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t
show_enable(struct device *dev, struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
u8 val = (data->fault_enable >> nr) & 1;
return sprintf(buf, "%u\n", val);
}
static ssize_t
store_fault_enable(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
int nr = sensor_attr->nr;
u8 val = simple_strtoul(buf, NULL, 10);
u32 tmp;
if ((val != 1) && (val != 0))
return -EINVAL;
if (((data->fault_enable >> nr) & 1) == val)
return count;
mutex_lock(&data->update_lock);
data->fault_enable &= ~(1 << nr);
data->fault_enable |= val << nr;
tmp = w83795_read_value(client, W83795_REG_FAULT_ENABLE(nr));
tmp &= 0x7f;
tmp |= val << 7;
w83795_write_value(client, W83795_REG_FAULT_ENABLE(nr), tmp);
mutex_unlock(&data->update_lock);
return count;
}
/* show/store FAULT */
static ssize_t
show_fault(struct device *dev, struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index;
struct w83795_data *data = w83795_update_device(dev);
u8 val;
if (nr == IN_FAULT)
val = (data->in_fault >> index) & 1;
else
val = (data->fan_fault >> index) & 1;
return sprintf(buf, "%d\n", val);
}
static ssize_t
store_fault(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int index = sensor_attr->index;
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
u8 val = simple_strtoul(buf, NULL, 10);
u8 tmp;
if ((val != 1) && (val != 0))
return -EINVAL;
mutex_lock(&data->update_lock);
tmp = w83795_read_value(client,
W83795_REG_FAULT(FAULT_NUM(index), nr));
tmp &= ~(1 << FAULT_SHIFT(index));
tmp |= val << FAULT_SHIFT(index);
w83795_write_value(client,
W83795_REG_FAULT(FAULT_NUM(index), nr), tmp);
switch (nr) {
case IN_FAULT:
data->in_fault |= ~(1 << index);
data->in_fault &= val << index;
break;
case FAN_FAULT:
data->fan_fault |= ~(1 << index);
data->fan_fault &= val << index;
break;
}
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t
show_sf_setup(struct device *dev, struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
u16 val = data->setup_pwm[nr];
switch (nr) {
case SETUP_PWM_UPTIME:
case SETUP_PWM_DOWNTIME:
val = TIME_FROM_REG(val);
break;
}
return sprintf(buf, "%d\n", val);
}
static ssize_t
store_sf_setup(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
u8 val = 0;
switch (nr) {
case SETUP_PWM_DEFAULT:
val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 0xff);
break;
case SETUP_PWM_UPTIME:
case SETUP_PWM_DOWNTIME:
val = TIME_TO_REG(simple_strtoul(buf, NULL, 10));
if (val == 0)
return -EINVAL;
break;
}
mutex_lock(&data->update_lock);
data->setup_pwm[nr] = val;
w83795_write_value(client, W83795_REG_SETUP_PWM(nr), val);
mutex_unlock(&data->update_lock);
return count;
}
#define NOT_USED -1
#define SENSOR_ATTR_IN(index) \
SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL, \
IN_READ, index), \
SENSOR_ATTR_2(in##index##_input_fault, S_IRUGO, \
show_fault, store_fault, IN_FAULT, index), \
SENSOR_ATTR_2(in##index##_max, S_IRUGO | S_IWUSR, show_in, \
store_in, IN_MAX, index), \
SENSOR_ATTR_2(in##index##_min, S_IRUGO | S_IWUSR, show_in, \
store_in, IN_LOW, index), \
SENSOR_ATTR_2(in##index##_alarm, S_IRUGO, show_alarm_beep, \
NULL, ALARM_STATUS, index + ((index > 14) ? 1 : 0)), \
SENSOR_ATTR_2(in##index##_beep, S_IWUSR | S_IRUGO, \
show_alarm_beep, store_beep, BEEP_ENABLE, \
index + ((index > 14) ? 1 : 0))
#define SENSOR_ATTR_FAN(index) \
SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan, \
NULL, FAN_INPUT, index - 1), \
SENSOR_ATTR_2(fan##index##_input_fault, S_IRUGO, \
show_fault, store_fault, FAN_FAULT, index - 1), \
SENSOR_ATTR_2(fan##index##_min, S_IWUSR | S_IRUGO, \
show_fan, store_fan_min, FAN_MIN, index - 1), \
SENSOR_ATTR_2(fan##index##_alarm, S_IRUGO, show_alarm_beep, \
NULL, ALARM_STATUS, index + 31), \
SENSOR_ATTR_2(fan##index##_beep, S_IWUSR | S_IRUGO, \
show_alarm_beep, store_beep, BEEP_ENABLE, index + 31)
#define SENSOR_ATTR_PWM(index) \
SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm, \
store_pwm, PWM_OUTPUT, index - 1), \
SENSOR_ATTR_2(pwm##index##_nonstop, S_IWUSR | S_IRUGO, \
show_pwm, store_pwm, PWM_NONSTOP, index - 1), \
SENSOR_ATTR_2(pwm##index##_start, S_IWUSR | S_IRUGO, \
show_pwm, store_pwm, PWM_START, index - 1), \
SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO, \
show_pwm, store_pwm, PWM_STOP_TIME, index - 1), \
SENSOR_ATTR_2(fan##index##_div, S_IWUSR | S_IRUGO, \
show_pwm, store_pwm, PWM_DIV, index - 1), \
SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO, \
show_pwm_enable, store_pwm_enable, NOT_USED, index - 1)
#define SENSOR_ATTR_FANIN_TARGET(index) \
SENSOR_ATTR_2(speed_cruise##index##_target, S_IWUSR | S_IRUGO, \
show_fanin, store_fanin, FANIN_TARGET, index - 1)
#define SENSOR_ATTR_DTS(index) \
SENSOR_ATTR_2(temp##index##_type, S_IRUGO , \
show_dts_mode, NULL, NOT_USED, index - 7), \
SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_dts, \
NULL, NOT_USED, index - 7), \
SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_dts_ext, \
store_dts_ext, DTS_CRIT, NOT_USED), \
SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \
show_dts_ext, store_dts_ext, DTS_CRIT_HYST, NOT_USED), \
SENSOR_ATTR_2(temp##index##_warn, S_IRUGO | S_IWUSR, show_dts_ext, \
store_dts_ext, DTS_WARN, NOT_USED), \
SENSOR_ATTR_2(temp##index##_warn_hyst, S_IRUGO | S_IWUSR, \
show_dts_ext, store_dts_ext, DTS_WARN_HYST, NOT_USED), \
SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \
show_alarm_beep, NULL, ALARM_STATUS, index + 17), \
SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \
show_alarm_beep, store_beep, BEEP_ENABLE, index + 17)
#define SENSOR_ATTR_TEMP(index) \
SENSOR_ATTR_2(temp##index##_type, S_IRUGO | S_IWUSR, \
show_temp_mode, store_temp_mode, NOT_USED, index - 1), \
SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_temp, \
NULL, TEMP_READ, index - 1), \
SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_temp, \
store_temp, TEMP_CRIT, index - 1), \
SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \
show_temp, store_temp, TEMP_CRIT_HYST, index - 1), \
SENSOR_ATTR_2(temp##index##_warn, S_IRUGO | S_IWUSR, show_temp, \
store_temp, TEMP_WARN, index - 1), \
SENSOR_ATTR_2(temp##index##_warn_hyst, S_IRUGO | S_IWUSR, \
show_temp, store_temp, TEMP_WARN_HYST, index - 1), \
SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \
show_alarm_beep, NULL, ALARM_STATUS, index + (index > 4 ? 11 : 17)), \
SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \
show_alarm_beep, store_beep, BEEP_ENABLE, index + (index > 4 ? 11 : 17)), \
SENSOR_ATTR_2(temp##index##_source_sel, S_IWUSR | S_IRUGO, \
show_temp_src, store_temp_src, NOT_USED, index - 1), \
SENSOR_ATTR_2(temp##index##_pwm_enable, S_IWUSR | S_IRUGO, \
show_temp_pwm_enable, store_temp_pwm_enable, TEMP_PWM_ENABLE, index - 1), \
SENSOR_ATTR_2(temp##index##_auto_channels_pwm, S_IWUSR | S_IRUGO, \
show_temp_pwm_enable, store_temp_pwm_enable, TEMP_PWM_FAN_MAP, index - 1), \
SENSOR_ATTR_2(thermal_cruise##index, S_IWUSR | S_IRUGO, \
show_temp_pwm, store_temp_pwm, TEMP_PWM_TTTI, index - 1), \
SENSOR_ATTR_2(temp##index##_crit, S_IWUSR | S_IRUGO, \
show_temp_pwm, store_temp_pwm, TEMP_PWM_CTFS, index - 1), \
SENSOR_ATTR_2(temp##index##_crit_hyst, S_IWUSR | S_IRUGO, \
show_temp_pwm, store_temp_pwm, TEMP_PWM_HCT, index - 1), \
SENSOR_ATTR_2(temp##index##_operation_hyst, S_IWUSR | S_IRUGO, \
show_temp_pwm, store_temp_pwm, TEMP_PWM_HOT, index - 1), \
SENSOR_ATTR_2(temp##index##_auto_point1_pwm, S_IRUGO | S_IWUSR, \
show_sf4_pwm, store_sf4_pwm, 0, index - 1), \
SENSOR_ATTR_2(temp##index##_auto_point2_pwm, S_IRUGO | S_IWUSR, \
show_sf4_pwm, store_sf4_pwm, 1, index - 1), \
SENSOR_ATTR_2(temp##index##_auto_point3_pwm, S_IRUGO | S_IWUSR, \
show_sf4_pwm, store_sf4_pwm, 2, index - 1), \
SENSOR_ATTR_2(temp##index##_auto_point4_pwm, S_IRUGO | S_IWUSR, \
show_sf4_pwm, store_sf4_pwm, 3, index - 1), \
SENSOR_ATTR_2(temp##index##_auto_point5_pwm, S_IRUGO | S_IWUSR, \
show_sf4_pwm, store_sf4_pwm, 4, index - 1), \
SENSOR_ATTR_2(temp##index##_auto_point6_pwm, S_IRUGO | S_IWUSR, \
show_sf4_pwm, store_sf4_pwm, 5, index - 1), \
SENSOR_ATTR_2(temp##index##_auto_point7_pwm, S_IRUGO | S_IWUSR, \
show_sf4_pwm, store_sf4_pwm, 6, index - 1), \
SENSOR_ATTR_2(temp##index##_auto_point1_temp, S_IRUGO | S_IWUSR,\
show_sf4_temp, store_sf4_temp, 0, index - 1), \
SENSOR_ATTR_2(temp##index##_auto_point2_temp, S_IRUGO | S_IWUSR,\
show_sf4_temp, store_sf4_temp, 1, index - 1), \
SENSOR_ATTR_2(temp##index##_auto_point3_temp, S_IRUGO | S_IWUSR,\
show_sf4_temp, store_sf4_temp, 2, index - 1), \
SENSOR_ATTR_2(temp##index##_auto_point4_temp, S_IRUGO | S_IWUSR,\
show_sf4_temp, store_sf4_temp, 3, index - 1), \
SENSOR_ATTR_2(temp##index##_auto_point5_temp, S_IRUGO | S_IWUSR,\
show_sf4_temp, store_sf4_temp, 4, index - 1), \
SENSOR_ATTR_2(temp##index##_auto_point6_temp, S_IRUGO | S_IWUSR,\
show_sf4_temp, store_sf4_temp, 5, index - 1), \
SENSOR_ATTR_2(temp##index##_auto_point7_temp, S_IRUGO | S_IWUSR,\
show_sf4_temp, store_sf4_temp, 6, index - 1)
static struct sensor_device_attribute_2 w83795_in[] = {
SENSOR_ATTR_IN(0),
SENSOR_ATTR_IN(1),
SENSOR_ATTR_IN(2),
SENSOR_ATTR_IN(3),
SENSOR_ATTR_IN(4),
SENSOR_ATTR_IN(5),
SENSOR_ATTR_IN(6),
SENSOR_ATTR_IN(7),
SENSOR_ATTR_IN(8),
SENSOR_ATTR_IN(9),
SENSOR_ATTR_IN(10),
SENSOR_ATTR_IN(11),
SENSOR_ATTR_IN(12),
SENSOR_ATTR_IN(13),
SENSOR_ATTR_IN(14),
SENSOR_ATTR_IN(15),
SENSOR_ATTR_IN(16),
SENSOR_ATTR_IN(17),
SENSOR_ATTR_IN(18),
SENSOR_ATTR_IN(19),
SENSOR_ATTR_IN(20),
};
static struct sensor_device_attribute_2 w83795_fan[] = {
SENSOR_ATTR_FAN(1),
SENSOR_ATTR_FAN(2),
SENSOR_ATTR_FAN(3),
SENSOR_ATTR_FAN(4),
SENSOR_ATTR_FAN(5),
SENSOR_ATTR_FAN(6),
SENSOR_ATTR_FAN(7),
SENSOR_ATTR_FAN(8),
SENSOR_ATTR_FAN(9),
SENSOR_ATTR_FAN(10),
SENSOR_ATTR_FAN(11),
SENSOR_ATTR_FAN(12),
SENSOR_ATTR_FAN(13),
SENSOR_ATTR_FAN(14),
};
static struct sensor_device_attribute_2 w83795_temp[] = {
SENSOR_ATTR_TEMP(1),
SENSOR_ATTR_TEMP(2),
SENSOR_ATTR_TEMP(3),
SENSOR_ATTR_TEMP(4),
SENSOR_ATTR_TEMP(5),
SENSOR_ATTR_TEMP(6),
};
static struct sensor_device_attribute_2 w83795_dts[] = {
SENSOR_ATTR_DTS(7),
SENSOR_ATTR_DTS(8),
SENSOR_ATTR_DTS(9),
SENSOR_ATTR_DTS(10),
SENSOR_ATTR_DTS(11),
SENSOR_ATTR_DTS(12),
SENSOR_ATTR_DTS(13),
SENSOR_ATTR_DTS(14),
};
static struct sensor_device_attribute_2 w83795_static[] = {
SENSOR_ATTR_FANIN_TARGET(1),
SENSOR_ATTR_FANIN_TARGET(2),
SENSOR_ATTR_FANIN_TARGET(3),
SENSOR_ATTR_FANIN_TARGET(4),
SENSOR_ATTR_FANIN_TARGET(5),
SENSOR_ATTR_FANIN_TARGET(6),
SENSOR_ATTR_FANIN_TARGET(7),
SENSOR_ATTR_FANIN_TARGET(8),
SENSOR_ATTR_PWM(1),
SENSOR_ATTR_PWM(2),
};
/* all registers existed in 795g than 795adg,
* like PWM3 - PWM8 */
static struct sensor_device_attribute_2 w83795_left_reg[] = {
SENSOR_ATTR_PWM(3),
SENSOR_ATTR_PWM(4),
SENSOR_ATTR_PWM(5),
SENSOR_ATTR_PWM(6),
SENSOR_ATTR_PWM(7),
SENSOR_ATTR_PWM(8),
};
static struct sensor_device_attribute_2 w83795_vid[] = {
SENSOR_ATTR_2(cpu0_vid, S_IRUGO, show_vid, NULL, NOT_USED, 0),
SENSOR_ATTR_2(cpu1_vid, S_IRUGO, show_vid, NULL, NOT_USED, 1),
SENSOR_ATTR_2(cpu2_vid, S_IRUGO, show_vid, NULL, NOT_USED, 2),
};
static struct sensor_device_attribute_2 sda_single_files[] = {
SENSOR_ATTR_2(vrm, S_IWUSR | S_IRUGO, show_vrm, store_vrm,
NOT_USED, NOT_USED),
SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep,
store_chassis_clear, ALARM_STATUS, 46),
SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable,
store_beep_enable, NOT_USED, NOT_USED),
SENSOR_ATTR_2(speed_cruise_tolerance, S_IWUSR | S_IRUGO, show_fanin,
store_fanin, FANIN_TOL, NOT_USED),
SENSOR_ATTR_2(in_fault_enable, S_IWUSR | S_IRUGO,
show_enable, store_fault_enable, IN_FAULT, NOT_USED),
SENSOR_ATTR_2(fan_fault_enable, S_IWUSR | S_IRUGO,
show_enable, store_fault_enable, FAN_FAULT, NOT_USED),
SENSOR_ATTR_2(pwm_default, S_IWUSR | S_IRUGO, show_sf_setup,
store_sf_setup, SETUP_PWM_DEFAULT, NOT_USED),
SENSOR_ATTR_2(pwm_uptime, S_IWUSR | S_IRUGO, show_sf_setup,
store_sf_setup, SETUP_PWM_UPTIME, NOT_USED),
SENSOR_ATTR_2(pwm_downtime, S_IWUSR | S_IRUGO, show_sf_setup,
store_sf_setup, SETUP_PWM_DOWNTIME, NOT_USED),
};
static void w83795_init_client(struct i2c_client *client)
{
if (reset) {
w83795_write_value(client, W83795_REG_CONFIG, 0x80);
}
/* Start monitoring */
w83795_write_value(client, W83795_REG_CONFIG,
w83795_read_value(client, W83795_REG_CONFIG) | 0x01);
}
/* Return 0 if detection is successful, -ENODEV otherwise */
static int w83795_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
u8 tmp, bank;
struct i2c_adapter *adapter = client->adapter;
unsigned short address = client->addr;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
return -ENODEV;
}
bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL);
if (kind < 0) {
tmp = bank & 0x80 ? 0x5c : 0xa3;
/* Check Nuvoton vendor ID */
if (tmp != i2c_smbus_read_byte_data(client,
W83795_REG_VENDORID)) {
pr_debug("w83795: Detection failed at check "
"vendor id\n");
return -ENODEV;
}
/* If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR
should match */
if ((bank & 0x07) == 0
&& (i2c_smbus_read_byte_data(client, W83795_REG_I2C_ADDR) & 0x7f) !=
address) {
pr_debug("w83795: Detection failed at check "
"i2c addr\n");
return -ENODEV;
}
}
/* We have either had a force parameter, or we have already detected the
Nuvoton. Determine the chip type now */
if (kind <= 0) {
if (0x79 == i2c_smbus_read_byte_data(client,
W83795_REG_CHIPID)) {
kind = w83795;
} else {
if (kind == 0)
dev_warn(&adapter->dev, "w83795: Ignoring "
"'force' parameter for unknown chip "
"at address 0x%02x\n", address);
return -ENODEV;
}
}
#if 0
/* Check 795 chip type: 795G or 795ADG */
if (W83795_REG_CONFIG_CONFIG48 &
w83795_read_value(client, W83795_REG_CONFIG)) {
data->chip_type = w83795adg;
} else {
data->chip_type = w83795g;
}
#endif
/* Fill in the remaining client fields and put into the global list */
strlcpy(info->type, "w83795", I2C_NAME_SIZE);
return 0;
}
static int w83795_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int i;
u8 tmp;
struct device *dev = &client->dev;
struct w83795_data *data;
int err = 0;
if (!(data = kzalloc(sizeof(struct w83795_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
i2c_set_clientdata(client, data);
data->bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL);
mutex_init(&data->update_lock);
/* Initialize the chip */
w83795_init_client(client);
/* Check 795 chip type: 795G or 795ADG */
if (W83795_REG_CONFIG_CONFIG48 &
w83795_read_value(client, W83795_REG_CONFIG)) {
data->chip_type = w83795adg;
} else {
data->chip_type = w83795g;
}
data->has_in = w83795_read_value(client, W83795_REG_VOLT_CTRL1);
data->has_in |= w83795_read_value(client, W83795_REG_VOLT_CTRL2) << 8;
/* VSEN11-9 not for 795adg */
if (data->chip_type == w83795adg) {
data->has_in &= 0xf8ff;
}
data->has_fan = w83795_read_value(client, W83795_REG_FANIN_CTRL1);
data->has_fan |= w83795_read_value(client, W83795_REG_FANIN_CTRL2) << 8;
/* VDSEN12-17 and TR1-6, TD1-4 use same register */
tmp = w83795_read_value(client, W83795_REG_TEMP_CTRL1);
if (tmp & 0x20) {
data->enable_dts = 1;
} else {
data->enable_dts = 0;
}
data->has_temp = 0;
data->temp_mode = 0;
if (tmp & 0x08) {
if (tmp & 0x04) {
data->has_temp |= 0x20;
} else {
data->has_in |= 0x10000;
}
}
if (tmp & 0x02) {
if (tmp & 0x01) {
data->has_temp |= 0x10;
} else {
data->has_in |= 0x8000;
}
}
tmp = w83795_read_value(client, W83795_REG_TEMP_CTRL2);
if (tmp & 0x40) {
data->has_temp |= 0x08;
if (!(tmp & 0x80)) {
data->temp_mode |= 0x08;
}
} else if (tmp & 0x80) {
data->has_in |= 0x100000;
}
if (tmp & 0x10) {
data->has_temp |= 0x04;
if (!(tmp & 0x20)) {
data->temp_mode |= 0x04;
}
} else if (tmp & 0x20) {
data->has_in |= 0x80000;
}
if (tmp & 0x04) {
data->has_temp |= 0x02;
if (!(tmp & 0x08)) {
data->temp_mode |= 0x02;
}
} else if (tmp & 0x08) {
data->has_in |= 0x40000;
}
if (tmp & 0x01) {
data->has_temp |= 0x01;
if (!(tmp & 0x02)) {
data->temp_mode |= 0x01;
}
} else if (tmp & 0x02) {
data->has_in |= 0x20000;
}
/* Check DTS enable status */
if (data->enable_dts == 0) {
data->has_dts = 0;
} else {
if (1 & w83795_read_value(client, W83795_REG_DTSC))
data->enable_dts |= 2;
data->has_dts =
w83795_read_value(client, W83795_REG_DTSE);
}
/* First update the voltages measured value and limits */
for (i = 0; i < ARRAY_SIZE(data->in); i++) {
if (!(data->has_in & (1 << i))) {
continue;
}
data->in[i][IN_MAX] =
w83795_read_value(client, W83795_REG_IN[i][IN_MAX]);
data->in[i][IN_LOW] =
w83795_read_value(client, W83795_REG_IN[i][IN_LOW]);
tmp = w83795_read_value(client, W83795_REG_IN[i][IN_READ]) << 2;
tmp |= (w83795_read_value(client, W83795_REG_VRLSB) >> VRLSB_SHIFT) & 0x03;
data->in[i][IN_READ] = tmp;
}
for (i = 0; i < IN_LSB_REG_NUM; i++) {
data->in_lsb[i][IN_MAX] =
w83795_read_value(client, IN_LSB_REG(i, IN_MAX));
data->in_lsb[i][IN_LOW] =
w83795_read_value(client, IN_LSB_REG(i, IN_LOW));
}
data->has_gain =
w83795_read_value(client, W83795_REG_VMIGB_CTRL) & 0x0f;
/* First update fan and limits */
for (i = 0; i < ARRAY_SIZE(data->fan); i++) {
if (!(data->has_fan & (1 << i))) {
continue;
}
data->fan_min[i] =
w83795_read_value(client, W83795_REG_FAN_MIN_HL(i)) << 4;
data->fan_min[i] |=
(w83795_read_value(client, W83795_REG_FAN_MIN_LSB(i) >>
W83795_REG_FAN_MIN_LSB_SHIFT(i))) & 0x0F;
data->fan[i] =
w83795_read_value(client, W83795_REG_FAN(i)) << 4;
data->fan[i] |=
(w83795_read_value(client, W83795_REG_VRLSB >> 4)) & 0x0F;
}
/* temperature and limits */
for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
if (!(data->has_temp & (1 << i)))
continue;
data->temp[i][TEMP_CRIT] =
w83795_read_value(client, W83795_REG_TEMP[i][TEMP_CRIT]);
data->temp[i][TEMP_CRIT_HYST] =
w83795_read_value(client, W83795_REG_TEMP[i][TEMP_CRIT_HYST]);
data->temp[i][TEMP_WARN] =
w83795_read_value(client, W83795_REG_TEMP[i][TEMP_WARN]);
data->temp[i][TEMP_WARN_HYST] =
w83795_read_value(client, W83795_REG_TEMP[i][TEMP_WARN_HYST]);
data->temp[i][TEMP_READ] =
w83795_read_value(client, W83795_REG_TEMP[i][TEMP_READ]);
data->temp_read_vrlsb[i] =
w83795_read_value(client, W83795_REG_VRLSB);
}
/* dts temperature and limits */
if (data->enable_dts != 0) {
data->dts_ext[DTS_CRIT] =
w83795_read_value(client, W83795_REG_DTS_EXT(DTS_CRIT));
data->dts_ext[DTS_CRIT_HYST] =
w83795_read_value(client, W83795_REG_DTS_EXT(DTS_CRIT_HYST));
data->dts_ext[DTS_WARN] =
w83795_read_value(client, W83795_REG_DTS_EXT(DTS_WARN));
data->dts_ext[DTS_WARN_HYST] =
w83795_read_value(client, W83795_REG_DTS_EXT(DTS_WARN_HYST));
for (i = 0; i < ARRAY_SIZE(data->dts); i++) {
if (!(data->has_dts & (1 << i)))
continue;
data->dts[i] =
w83795_read_value(client, W83795_REG_DTS(i));
data->dts_read_vrlsb[i] =
w83795_read_value(client, W83795_REG_VRLSB);
}
}
/* First update temp source selction */
for (i = 0; i < 3; i ++) {
data->temp_src[i] =
w83795_read_value(client, W83795_REG_TSS(i));
}
/* First update voltage & fan fault */
data->in_fault = w83795_read_value(client,
W83795_REG_FAULT(0, IN_FAULT));
data->in_fault |= w83795_read_value(client,
W83795_REG_FAULT(1, IN_FAULT)) << 8;
data->in_fault |= (w83795_read_value(client,
W83795_REG_FAULT(2, IN_FAULT)) & 0x3f) << 15;
data->in_fault &= data->has_in;
data->fan_fault = w83795_read_value(client,
W83795_REG_FAULT(0, FAN_FAULT));
data->fan_fault |= (w83795_read_value(client,
W83795_REG_FAULT(1, FAN_FAULT)) & 0x3f) << 8;
data->fan_fault &= data->has_fan;
tmp = w83795_read_value(client,
W83795_REG_FAULT_ENABLE(IN_FAULT));
if (tmp & 0x80)
data->fault_enable = 1;
else
data->fault_enable = 0;
tmp = w83795_read_value(client,
W83795_REG_FAULT_ENABLE(FAN_FAULT));
if (tmp & 0x80)
data->fault_enable |= 0x02;
/* pwm and smart fan */
if (data->chip_type == w83795g)
data->has_pwm = 8;
else
data->has_pwm = 2;
data->pwm_fcms[0] = w83795_read_value(client, W83795_REG_FCMS1);
data->pwm_fcms[1] = w83795_read_value(client, W83795_REG_FCMS2);
/* w83795adg only support pwm2-0 */
for (i = 0; i < W83795_REG_TEMP_NUM; i ++) {
data->pwm_tfmr[i] =
w83795_read_value(client, W83795_REG_TFMR(i));
}
data->pwm_fomc =
w83795_read_value(client, W83795_REG_FOMC);
for (i = 0; i < data->has_pwm; i ++) {
for (tmp = 0; tmp < 5; tmp ++) {
data->pwm[i][tmp] =
w83795_read_value(client, W83795_REG_PWM(i, tmp));
}
}
for (i = 0; i < 8; i ++) {
data->target_speed[i] =
w83795_read_value(client, W83795_REG_FTSH(i)) << 4;
data->target_speed[i] |=
w83795_read_value(client, W83795_REG_FTSL(i)) >> 4;
}
data->tol_speed =
w83795_read_value(client, W83795_REG_TFTS) & 0x3f;
for (i = 0; i < W83795_REG_TEMP_NUM; i ++) {
data->pwm_temp[i][TEMP_PWM_TTTI] =
w83795_read_value(client, W83795_REG_TTTI(i)) & 0x7f;
data->pwm_temp[i][TEMP_PWM_CTFS] =
w83795_read_value(client, W83795_REG_CTFS(i));
tmp = w83795_read_value(client, W83795_REG_HT(i));
data->pwm_temp[i][TEMP_PWM_HCT] = (tmp >> 4) & 0x0f;
data->pwm_temp[i][TEMP_PWM_HOT] = tmp & 0x0f;
}
for (i = 0; i < W83795_REG_TEMP_NUM; i ++) {
for (tmp = 0; tmp < 7; tmp ++) {
data->sf4_reg[i][SF4_TEMP][tmp] =
w83795_read_value(client, W83795_REG_SF4_TEMP(i, tmp));
data->sf4_reg[i][SF4_PWM][tmp] =
w83795_read_value(client, W83795_REG_SF4_PWM(i, tmp));
}
}
/* Setup PWM Register */
for (i = 0; i < 3; i ++) {
data->setup_pwm[i] =
w83795_read_value(client, W83795_REG_SETUP_PWM(i));
}
/* vid */
data->vrm = vid_which_vrm();
if (data->chip_type == w83795adg) {
data->has_vid = 0;
} else {
data->has_vid =
(w83795_read_value(client, W83795_REG_VID_CTRL) >> 3) & 0x07;
}
/* alarm and beep */
for (i = 0; i < ALARM_BEEP_REG_NUM; i ++) {
data->alarms[i] =
w83795_read_value(client, W83795_REG_ALARM(i));
data->beeps[i] =
w83795_read_value(client, W83795_REG_BEEP(i));
}
data->beep_enable =
(w83795_read_value(client, W83795_REG_BEEP(5)) >> 7) & 0x01;
/* Register sysfs hooks */
for (i = 0; i < ARRAY_SIZE(w83795_in); i++) {
if (!(data->has_in & (1 << (i / 6))))
continue;
err = device_create_file(dev, &w83795_in[i].dev_attr);
if (err)
goto exit_remove;
}
for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) {
if (!(data->has_fan & (1 << (i / 5))))
continue;
err = device_create_file(dev, &w83795_fan[i].dev_attr);
if (err)
goto exit_remove;
}
for (i = 0; i < ARRAY_SIZE(w83795_vid); i++) {
if (!((data->has_vid >> i) & 1))
continue;
err = device_create_file(dev, &w83795_vid[i].dev_attr);
if (err)
goto exit_remove;
}
for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) {
err = device_create_file(dev, &sda_single_files[i].dev_attr);
if (err)
goto exit_remove;
}
for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) {
if (!(data->has_temp & (1 << (i / 29))))
continue;
err = device_create_file(dev, &w83795_temp[i].dev_attr);
if (err)
goto exit_remove;
}
if (data->enable_dts != 0) {
for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) {
if (!(data->has_dts & (1 << (i / 8))))
continue;
err = device_create_file(dev, &w83795_dts[i].dev_attr);
if (err)
goto exit_remove;
}
}
if (data->chip_type == w83795g) {
for (i = 0; i < ARRAY_SIZE(w83795_left_reg); i++) {
err = device_create_file(dev, &w83795_left_reg[i].dev_attr);
if (err)
goto exit_remove;
}
}
for (i = 0; i < ARRAY_SIZE(w83795_static); i++) {
err = device_create_file(dev, &w83795_static[i].dev_attr);
if (err)
goto exit_remove;
}
data->hwmon_dev = hwmon_device_register(dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
return 0;
/* Unregister sysfs hooks */
exit_remove:
for (i = 0; i < ARRAY_SIZE(w83795_in); i++)
device_remove_file(dev, &w83795_in[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(w83795_fan); i++)
device_remove_file(dev, &w83795_fan[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(sda_single_files); i++)
device_remove_file(dev, &sda_single_files[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(w83795_vid); i++) {
if (!((data->has_vid >> i) & 1))
continue;
device_remove_file(dev, &w83795_vid[i].dev_attr);
}
if (data->chip_type == w83795g) {
for (i = 0; i < ARRAY_SIZE(w83795_left_reg); i++)
device_remove_file(dev, &w83795_left_reg[i].dev_attr);
}
for (i = 0; i < ARRAY_SIZE(w83795_temp); i++)
device_remove_file(dev, &w83795_temp[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(w83795_dts); i++)
device_remove_file(dev, &w83795_dts[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(w83795_static); i++)
device_remove_file(dev, &w83795_static[i].dev_attr);
kfree(data);
exit:
return err;
}
static struct w83795_data *w83795_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83795_data *data = i2c_get_clientdata(client);
u16 tmp;
int i;
mutex_lock(&data->update_lock);
if (!(time_after(jiffies, data->last_updated + HZ * 2)
|| !data->valid))
goto END;
/* Update the voltages value */
for (i = 0; i < ARRAY_SIZE(data->in); i++) {
if (!(data->has_in & (1 << i))) {
continue;
}
tmp = w83795_read_value(client, W83795_REG_IN[i][IN_READ]) << 2;
tmp |= (w83795_read_value(client, W83795_REG_VRLSB) >> VRLSB_SHIFT) & 0x03;
data->in[i][IN_READ] = tmp;
}
/* Update fan */
for (i = 0; i < ARRAY_SIZE(data->fan); i++) {
if (!(data->has_fan & (1 << i))) {
continue;
}
data->fan[i] =
w83795_read_value(client, W83795_REG_FAN(i)) << 4;
data->fan[i] |=
(w83795_read_value(client, W83795_REG_VRLSB >> 4)) & 0x0F;
}
/* Update temperature */
for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
/* even stop monitor, register still keep value, just read out it */
if (!(data->has_temp & (1 << i))) {
data->temp[i][TEMP_READ] = 0;
data->temp_read_vrlsb[i] = 0;
continue;
}
data->temp[i][TEMP_READ] =
w83795_read_value(client, W83795_REG_TEMP[i][TEMP_READ]);
data->temp_read_vrlsb[i] =
w83795_read_value(client, W83795_REG_VRLSB);
}
/* Update dts temperature */
if (data->enable_dts != 0) {
for (i = 0; i < ARRAY_SIZE(data->dts); i++) {
if (!(data->has_dts & (1 << i)))
continue;
data->dts[i] =
w83795_read_value(client, W83795_REG_DTS(i));
data->dts_read_vrlsb[i] =
w83795_read_value(client, W83795_REG_VRLSB);
}
}
/* Update pwm output */
for (i = 0; i < data->has_pwm; i++) {
data->pwm[i][PWM_OUTPUT] =
w83795_read_value(client, W83795_REG_PWM(i, PWM_OUTPUT));
}
/* retrieve vid */
if (0 != data->has_vid) {
tmp = w83795_read_value(client, W83795_REG_VID_CTRL);
w83795_write_value(client, W83795_REG_VID_CTRL, tmp | 0x80);
for (i = 0; i < 3; i ++) {
data->vid[i] =
w83795_read_value(client, W83795_REG_VSEN_VIDIN(i));
}
}
/* update alarm and beep */
for (i = 0; i < ALARM_BEEP_REG_NUM; i ++) {
data->alarms[i] =
w83795_read_value(client, W83795_REG_ALARM(i));
}
data->last_updated = jiffies;
data->valid = 1;
END:
mutex_unlock(&data->update_lock);
return data;
}
static int w83795_remove(struct i2c_client *client)
{
struct w83795_data *data = i2c_get_clientdata(client);
struct device *dev = &client->dev;
int i;
hwmon_device_unregister(data->hwmon_dev);
for (i = 0; i < ARRAY_SIZE(w83795_in); i++)
device_remove_file(dev, &w83795_in[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(w83795_fan); i++)
device_remove_file(dev, &w83795_fan[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(sda_single_files); i++)
device_remove_file(dev, &sda_single_files[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(w83795_vid); i++) {
if (!((data->has_vid >> i) & 1))
continue;
device_remove_file(dev, &w83795_vid[i].dev_attr);
}
if (data->chip_type == w83795g) {
for (i = 0; i < ARRAY_SIZE(w83795_left_reg); i++)
device_remove_file(dev, &w83795_left_reg[i].dev_attr);
}
for (i = 0; i < ARRAY_SIZE(w83795_temp); i++)
device_remove_file(dev, &w83795_temp[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(w83795_dts); i++)
device_remove_file(dev, &w83795_dts[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(w83795_static); i++)
device_remove_file(dev, &w83795_static[i].dev_attr);
kfree(data);
return 0;
}
/* Ignore the possibility that somebody change bank outside the driver
Must be called with data->update_lock held, except during initialization */
static u8 w83795_read_value(struct i2c_client *client, u16 reg)
{
struct w83795_data *data = i2c_get_clientdata(client);
u8 res = 0xff;
u8 new_bank = reg >> 8;
new_bank |= data->bank & 0xfc;
if (data->bank != new_bank) {
if (i2c_smbus_write_byte_data
(client, W83795_REG_BANKSEL, new_bank) >= 0)
data->bank = new_bank;
else {
dev_err(&client->dev,
"set bank to %d failed, fall back "
"to bank %d, read reg 0x%x error\n",
new_bank, data->bank, reg);
res = 0x0; /* read 0x0 from the chip */
goto END;
}
}
res = i2c_smbus_read_byte_data(client, reg & 0xff);
END:
return res;
}
/* Must be called with data->update_lock held, except during initialization */
static int w83795_write_value(struct i2c_client *client, u16 reg, u8 value)
{
struct w83795_data *data = i2c_get_clientdata(client);
int res;
u8 new_bank = reg >> 8;
new_bank |= data->bank & 0xfc;
if (data->bank != new_bank) {
if ((res = i2c_smbus_write_byte_data
(client, W83795_REG_BANKSEL, new_bank)) >= 0)
data->bank = new_bank;
else {
dev_err(&client->dev,
"set bank to %d failed, fall back "
"to bank %d, write reg 0x%x error\n",
new_bank, data->bank, reg);
goto END;
}
}
res = i2c_smbus_write_byte_data(client, reg & 0xff, value);
END:
return res;
}
static int __init sensors_w83795_init(void)
{
return i2c_add_driver(&w83795_driver);
}
static void __exit sensors_w83795_exit(void)
{
i2c_del_driver(&w83795_driver);
}
MODULE_AUTHOR("Wei Song");
MODULE_DESCRIPTION("w83795 driver");
MODULE_LICENSE("GPL");
module_init(sensors_w83795_init);
module_exit(sensors_w83795_exit);
[-- Attachment #6: Makefile --]
[-- Type: application/octet-stream, Size: 554 bytes --]
# on Linux 2.6 kernel
# If KERNELRELEASE is defined, we've been invoked from the
# kernel build system and can use its language.
ifneq ($(KERNELRELEASE),)
obj-m := w83795.o
w83795-objs := wb83795.o
# Otherwise we were called directly from the command
# line; invoke the kernel build system.
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
# KERNELDIR ?= /tmp/down/linux-2.6.27.7/
PWD := $(shell pwd)
2.6:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules -Wall
clean:
rm -rf *.o *.ko *.mod.c Module.symvers .w83795.* .wb83795.* .tmp_versions
endif
[-- Attachment #7: Type: text/plain, Size: 153 bytes --]
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [lm-sensors] NEW Nuvoton w83795 hw chip driver
2009-03-03 8:20 [lm-sensors] NEW Nuvoton w83795 hw chip driver Wsong
@ 2009-03-12 13:06 ` Jean Delvare
2009-03-13 1:25 ` Wsong
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Jean Delvare @ 2009-03-12 13:06 UTC (permalink / raw)
To: lm-sensors
Hi Wei,
On Tue, 3 Mar 2009 16:20:15 +0800, Wsong@nuvoton.com wrote:
> Dear lm-sensor group,
>
> I am glad to submit to you the driver for Nuvoton W83795G/ADG hw monitor chip.
>
> The W83795G/ADG chip information are show at here:
> http://www.nuvoton.com/hq/enu/ProductAndSales/ProductLines/ComputerIC/HardwareMonitor/HWMonitorforDesktopAndServer/
I have added an entry for that chip to our wiki Devices page. Thanks a
lot for contributing code for your hardware, this is very appreciated.
> Driver files list:
> The attach file "wb83795.c" is the main driver file. This driver passed test on kernel 2.6.28.7.
Shouldn't this rather be w83795.c? This would be consistent with the
other driver names and with your sensors-detect patch.
> The attach file "Makefile" is used for compile the driver.
>
> Patch files for lm-sensors 3.0.3:
>
> The attach file "795_sensor3.conf" is the 795 related lines for sensor3.conf. But the exact names and settings may be changed for the motherboards.
>
> The attach file "DESC" is the list of sys files which 795 driver would create.
>
> The attach file "sensors-detect.3.0.3.patch" add detect 795 chip for "sensor-detect" tool in lm-sensors 3.0.3 package.
I have adjusted this patch so that it applies on top of 3.1.0 (there
have been a lot of changes in sensors-detect between 3.0.3 and 3.1.0.)
Can you please send me a dump of your W83795 chip so that I can test
the code before I commit it? You can obtain such a dump using the
i2c-dev kernel driver and "i2cdump" from the i2c-tools package:
# modprobe i2c-dev
# i2cdump 0 0x2d b
Replace 0 with the actual I2C bus number your chip sits on and 0x2d
with the actual I2C address of the chip. Remember to first unload the
w83795 driver if it is loaded.
> Until now, it seems there is not a motherboard based on W83795G/ADG in the market, and I am sure not the 795 SPEC could be share to you or not.
>
> Please contact me if you need any help, want to know any information or have some other questions.
Unfortunately I will not have the time to do more. Maybe later when
there are actual motherboards with this chip and users start asking for
support...
--
Jean Delvare
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [lm-sensors] NEW Nuvoton w83795 hw chip driver
2009-03-03 8:20 [lm-sensors] NEW Nuvoton w83795 hw chip driver Wsong
2009-03-12 13:06 ` Jean Delvare
@ 2009-03-13 1:25 ` Wsong
2009-03-13 1:28 ` Wsong
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Wsong @ 2009-03-13 1:25 UTC (permalink / raw)
To: lm-sensors
Hi Jean,
Thank you for your response.
I named main driver file as "wb83795.c" just for fit the Makefile. Please change its name to fit other drivers in kernel.
The attach file is the i2cdump result.
In fact I have made some subversions for kernel 2.6.5 (Suse 9), kernel 2.6.9 (RHEL 4), kernel 2.6.21 and kernel 2.6.27. You can contact with me if you need them.
Best Regards,
wsong
-----Original Message-----
From: Jean Delvare [mailto:khali@linux-fr.org]
Sent: 2009Äê3ÔÂ12ÈÕ 21:06
To: PS23 WSONG
Cc: lm-sensors@lm-sensors.org; PS23 WMWU; PS00 LCChen; PS23 JGONG
Subject: Re: [lm-sensors] NEW Nuvoton w83795 hw chip driver
Hi Wei,
On Tue, 3 Mar 2009 16:20:15 +0800, Wsong@nuvoton.com wrote:
> Dear lm-sensor group,
>
> I am glad to submit to you the driver for Nuvoton W83795G/ADG hw monitor chip.
>
> The W83795G/ADG chip information are show at here:
> http://www.nuvoton.com/hq/enu/ProductAndSales/ProductLines/ComputerIC/HardwareMonitor/HWMonitorforDesktopAndServer/
I have added an entry for that chip to our wiki Devices page. Thanks a
lot for contributing code for your hardware, this is very appreciated.
> Driver files list:
> The attach file "wb83795.c" is the main driver file. This driver passed test on kernel 2.6.28.7.
Shouldn't this rather be w83795.c? This would be consistent with the
other driver names and with your sensors-detect patch.
> The attach file "Makefile" is used for compile the driver.
>
> Patch files for lm-sensors 3.0.3:
>
> The attach file "795_sensor3.conf" is the 795 related lines for sensor3.conf. But the exact names and settings may be changed for the motherboards.
>
> The attach file "DESC" is the list of sys files which 795 driver would create.
>
> The attach file "sensors-detect.3.0.3.patch" add detect 795 chip for "sensor-detect" tool in lm-sensors 3.0.3 package.
I have adjusted this patch so that it applies on top of 3.1.0 (there
have been a lot of changes in sensors-detect between 3.0.3 and 3.1.0.)
Can you please send me a dump of your W83795 chip so that I can test
the code before I commit it? You can obtain such a dump using the
i2c-dev kernel driver and "i2cdump" from the i2c-tools package:
# modprobe i2c-dev
# i2cdump 0 0x2d b
Replace 0 with the actual I2C bus number your chip sits on and 0x2d
with the actual I2C address of the chip. Remember to first unload the
w83795 driver if it is loaded.
> Until now, it seems there is not a motherboard based on W83795G/ADG in the market, and I am sure not the 795 SPEC could be share to you or not.
>
> Please contact me if you need any help, want to know any information or have some other questions.
Unfortunately I will not have the time to do more. Maybe later when
there are actual motherboards with this chip and users start asking for
support...
--
Jean Delvare
=============================================The privileged confidential information contained in this email is intended for use only by the addressees as indicated by the original sender of this email. If you are not the addressee indicated in this email or are not responsible for delivery of the email to such a person, please kindly reply to the sender indicating this fact and delete all copies of it from your computer and network server immediately. Your cooperation is highly appreciated. It is advised that any unauthorized use of confidential information of Nuvoton is strictly prohibited; and any information in this email irrelevant to the official business of Nuvoton shall be deemed as neither given nor endorsed by Nuvoton.
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [lm-sensors] NEW Nuvoton w83795 hw chip driver
2009-03-03 8:20 [lm-sensors] NEW Nuvoton w83795 hw chip driver Wsong
2009-03-12 13:06 ` Jean Delvare
2009-03-13 1:25 ` Wsong
@ 2009-03-13 1:28 ` Wsong
2009-03-13 8:47 ` Jean Delvare
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Wsong @ 2009-03-13 1:28 UTC (permalink / raw)
To: lm-sensors
[-- Attachment #1: Type: text/plain, Size: 3671 bytes --]
Hi Jean,
Thank you for your response.
I named main driver file as "wb83795.c" just for fit the Makefile. Please change its name to fit other drivers in kernel.
The attach file is the i2cdump result.
In fact I have made some subversions for kernel 2.6.5 (Suse 9), kernel 2.6.9 (RHEL 4), kernel 2.6.21 and kernel 2.6.27. You can contact with me if you need them.
Best Regards,
wsong
-----Original Message-----
From: Jean Delvare [mailto:khali@linux-fr.org]
Sent: 2009年3月12日 21:06
To: PS23 WSONG
Cc: lm-sensors@lm-sensors.org; PS23 WMWU; PS00 LCChen; PS23 JGONG
Subject: Re: [lm-sensors] NEW Nuvoton w83795 hw chip driver
Hi Wei,
On Tue, 3 Mar 2009 16:20:15 +0800, Wsong@nuvoton.com wrote:
> Dear lm-sensor group,
>
> I am glad to submit to you the driver for Nuvoton W83795G/ADG hw monitor chip.
>
> The W83795G/ADG chip information are show at here:
> http://www.nuvoton.com/hq/enu/ProductAndSales/ProductLines/ComputerIC/HardwareMonitor/HWMonitorforDesktopAndServer/
I have added an entry for that chip to our wiki Devices page. Thanks a
lot for contributing code for your hardware, this is very appreciated.
> Driver files list:
> The attach file "wb83795.c" is the main driver file. This driver passed test on kernel 2.6.28.7.
Shouldn't this rather be w83795.c? This would be consistent with the
other driver names and with your sensors-detect patch.
> The attach file "Makefile" is used for compile the driver.
>
> Patch files for lm-sensors 3.0.3:
>
> The attach file "795_sensor3.conf" is the 795 related lines for sensor3.conf. But the exact names and settings may be changed for the motherboards.
>
> The attach file "DESC" is the list of sys files which 795 driver would create.
>
> The attach file "sensors-detect.3.0.3.patch" add detect 795 chip for "sensor-detect" tool in lm-sensors 3.0.3 package.
I have adjusted this patch so that it applies on top of 3.1.0 (there
have been a lot of changes in sensors-detect between 3.0.3 and 3.1.0.)
Can you please send me a dump of your W83795 chip so that I can test
the code before I commit it? You can obtain such a dump using the
i2c-dev kernel driver and "i2cdump" from the i2c-tools package:
# modprobe i2c-dev
# i2cdump 0 0x2d b
Replace 0 with the actual I2C bus number your chip sits on and 0x2d
with the actual I2C address of the chip. Remember to first unload the
w83795 driver if it is loaded.
> Until now, it seems there is not a motherboard based on W83795G/ADG in the market, and I am sure not the 795 SPEC could be share to you or not.
>
> Please contact me if you need any help, want to know any information or have some other questions.
Unfortunately I will not have the time to do more. Maybe later when
there are actual motherboards with this chip and users start asking for
support...
--
Jean Delvare
===========================================================================================
The privileged confidential information contained in this email is intended for use only by the addressees as indicated by the original sender of this email. If you are not the addressee indicated in this email or are not responsible for delivery of the email to such a person, please kindly reply to the sender indicating this fact and delete all copies of it from your computer and network server immediately. Your cooperation is highly appreciated. It is advised that any unauthorized use of confidential information of Nuvoton is strictly prohibited; and any information in this email irrelevant to the official business of Nuvoton shall be deemed as neither given nor endorsed by Nuvoton.
[-- Attachment #2: repo5.txt --]
[-- Type: text/plain, Size: 5866 bytes --]
linux-rei6:~ # i2cdump 0 0x2f b 0 0
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-0, address 0x2f, mode byte
Continue? [Y/n] y
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: 80 55 ff 78 3f a0 ff 00 0f 00 0f ff 00 00 00 00 ?U.x??..?.?.....
10: 7d 34 bf be 00 cc c7 7e 00 00 00 89 88 86 83 c1 }4??.??~...?????
20: c1 80 80 96 98 23 16 00 00 00 00 00 00 00 0f ff ?????#?.......?.
30: ff ff 12 ff ff ff 00 00 00 00 00 00 00 ff ff ff ..?.............
40: 90 f2 00 30 00 ee 00 00 00 40 00 ff 00 7f 3f ff ??.0.?...@...??.
50: 00 00 00 00 00 00 ff ff 81 00 03 00 00 00 00 00 ........?.?.....
60: 00 00 00 00 00 00 00 00 00 00 00 64 64 ff ff ff ...........dd...
70: af 57 af 57 ce a8 ce 89 ce 89 af 32 af 32 72 46 ?W?W???????2?2rF
80: ff 00 ff 00 ff 00 96 7d 96 7d 96 7d 96 4f 50 ba ......?}?}?}?OP?
90: 29 2a 3f 00 00 00 64 5f 55 50 64 5f 55 50 64 5f )*?...d_UPd_UPd_
a0: 55 50 64 5f 55 50 5a 57 55 52 5a 57 55 52 5a 57 UPd_UPZWURZWURZW
b0: 55 52 54 4f 55 50 ff ff d2 d2 d2 d2 d2 d2 ff ff URTOUP..??????..
c0: ff ff ff ff ee ff ff ff ee ee ee ff ff ff ff ff ....?...???.....
d0: 00 00 00 00 00 00 00 00 00 22 24 0a 60 00 00 00 ........."$?`...
e0: 00 00 00 00 00 00 bb c0 09 09 09 09 09 22 22 02 ......???????""?
f0: ff 00 00 00 00 00 00 00 00 0f ff 51 af 5c 79 50 .........?.Q?\yP
linux-rei6:~ # i2cdump 0 0x2f b 1 0
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-0, address 0x2f, mode byte
Probing bank 1 using bank register 0x00.
Continue? [Y/n] y
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: 81 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ?...............
10: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
20: c1 08 10 50 79 5a 00 24 00 00 00 00 a0 8e 54 4b ???PyZ.$....??TK
30: 3f 6a 13 ec ff ff ff ff ff ff ff ff ff ff ff 00 ?j??............
40: 03 03 07 07 07 07 07 07 07 07 07 07 07 07 07 07 ????????????????
50: 07 03 07 07 07 07 07 07 07 07 07 07 07 07 07 07 ????????????????
60: 07 07 07 07 07 07 07 07 07 03 03 03 03 03 03 03 ????????????????
70: 03 07 23 ff ff ff ff ff ff ff ff ff ff ff ff ff ??#.............
80: 01 02 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 ????????????????
90: 12 03 01 02 03 21 43 65 87 a9 cb ed 21 43 65 21 ?????!Ce????!Ce!
a0: 43 65 87 17 ff ff ff ff ff ff ff ff ff ff ff ff Ce??............
b0: 00 11 12 10 ff ff ff ff ff ff ff ff ff ff ff ff .???............
c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
f0: ff 00 00 00 00 00 00 00 00 0f ff 51 af 5c 79 50 .........?.Q?\yP
linux-rei6:~ # i2cdump 0 0x2f b 2 0
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-0, address 0x2f, mode byte
Probing bank 2 using bank register 0x00.
Continue? [Y/n] y
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: 82 00 03 03 00 00 00 00 3f 11 11 00 40 01 01 02 ?.??....???.@???
10: 4c 4c 4d 4d 4d 4d 4d 4d 84 85 85 85 85 85 85 85 LLMMMMMM????????
20: 30 30 30 30 30 30 30 30 10 10 10 10 10 10 10 10 00000000????????
30: 00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff ................
40: 60 00 60 00 60 00 60 00 60 00 60 00 60 00 60 00 `.`.`.`.`.`.`.`.
50: 10 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ?...............
60: 28 28 28 28 28 28 ff ff 4c 4c 60 60 60 60 ff ff ((((((..LL````..
70: 00 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ................
80: 1b 1b 1b 1b 1b 2f 4b ff 4c 4c 4c 4c 4c 80 ff ff ?????/K.LLLLL?..
90: 1b 1b 1b 1b 1b 2f 4b ff 4c 4c 4c 4c 4c 80 ff ff ?????/K.LLLLL?..
a0: 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ................
b0: 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ................
c0: 1b 1b 1b 1b 1b 2f 4b ff 4c 4c 4c 4c 4c 80 ff ff ?????/K.LLLLL?..
d0: 1b 1b 1b 1b 1b 2f 4b ff 4c 4c 4c 4c 4c 80 ff ff ?????/K.LLLLL?..
e0: 00 00 80 80 80 80 80 80 80 80 ff ff ff ff ff ff ..????????......
f0: ff 00 00 00 00 00 00 00 00 0f ff 51 af 5c 79 50 .........?.Q?\yP
linux-rei6:~ # i2cdump 0 0x2f b 3 0
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-0, address 0x2f, mode byte
Probing bank 3 using bank register 0x00.
Continue? [Y/n] y
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: 83 00 03 ff ff ff ff ff ff ff ff ff ff ff ff ff ?.?.............
10: 25 00 22 81 ff 03 ff 00 00 01 00 40 00 00 ff ff %."?.?...?.@....
20: 55 55 50 50 50 50 50 50 ff ff ff ff ff ff ff ff UUPPPPPP........
30: 00 00 00 00 00 00 20 00 01 00 01 ff ff ff ff ff ...... .?.?.....
40: f0 6c 80 00 f8 80 f8 80 f8 80 f8 80 f8 80 f8 80 ?l?.????????????
50: f8 80 f8 80 f8 80 f8 80 f8 80 f8 80 f8 80 f8 80 ????????????????
60: f9 00 f9 00 f9 00 f9 00 f9 00 f9 00 f9 00 f9 00 ?.?.?.?.?.?.?.?.
70: 00 00 00 00 00 00 00 00 00 00 00 00 ff ff ff ff ................
80: 00 00 00 00 00 40 ff ff f9 00 00 ff ff ff ff ff .....@..?.......
90: 02 17 00 0a 00 00 00 ef 42 90 ef ff ff ff ff ff ??.?...?B??.....
a0: 10 19 00 00 01 01 00 00 00 00 cf 00 ff ff ff ff ??..??....?.....
b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
f0: ff 00 00 00 00 00 00 00 00 0f ff 51 af 5c 79 50 .........?.Q?\yP
[-- Attachment #3: Type: text/plain, Size: 153 bytes --]
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [lm-sensors] NEW Nuvoton w83795 hw chip driver
2009-03-03 8:20 [lm-sensors] NEW Nuvoton w83795 hw chip driver Wsong
` (2 preceding siblings ...)
2009-03-13 1:28 ` Wsong
@ 2009-03-13 8:47 ` Jean Delvare
2009-03-31 1:12 ` Wsong
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Jean Delvare @ 2009-03-13 8:47 UTC (permalink / raw)
To: lm-sensors
Hi Wei,
On Fri, 13 Mar 2009 09:28:15 +0800, Wsong@nuvoton.com wrote:
> Hi Jean,
>
> Thank you for your response.
>
> I named main driver file as "wb83795.c" just for fit the Makefile. Please
> change its name to fit other drivers in kernel.
OK, we will rename it to w83795.c when we merge it.
> The attach file is the i2cdump result.
Thanks. I've used it to test the updated patch for sensors-detect, and
it worked well. I've committed the patch now. You can try the latest
version of the sensors-detect script, it should work OK for you as well:
http://www.lm-sensors.org/svn/lm-sensors/trunk/prog/detect/sensors-detect
> In fact I have made some subversions for kernel 2.6.5 (Suse 9), kernel
> 2.6.9 (RHEL 4), kernel 2.6.21 and kernel 2.6.27. You can contact with me
> if you need them.
OK, I'll try to remember if a user ever asks for this.
--
Jean Delvare
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [lm-sensors] NEW Nuvoton w83795 hw chip driver
2009-03-03 8:20 [lm-sensors] NEW Nuvoton w83795 hw chip driver Wsong
` (3 preceding siblings ...)
2009-03-13 8:47 ` Jean Delvare
@ 2009-03-31 1:12 ` Wsong
2012-04-05 10:17 ` Chislett, William
2012-04-05 14:32 ` Guenter Roeck
6 siblings, 0 replies; 8+ messages in thread
From: Wsong @ 2009-03-31 1:12 UTC (permalink / raw)
To: lm-sensors
Hi Jean,
For I will leave Nuvoton, my current email address will be stopped.
If you need continue support on 795 linux driver or documents, you can contact with my boss: LCCHEN@nuvoton.com.
Or you can contact with me by: rachine2@yahoo.com.cn.
Best Regards,
wsong
=============================================The privileged confidential information contained in this email is intended for use only by the addressees as indicated by the original sender of this email. If you are not the addressee indicated in this email or are not responsible for delivery of the email to such a person, please kindly reply to the sender indicating this fact and delete all copies of it from your computer and network server immediately. Your cooperation is highly appreciated. It is advised that any unauthorized use of confidential information of Nuvoton is strictly prohibited; and any information in this email irrelevant to the official business of Nuvoton shall be deemed as neither given nor endorsed by Nuvoton.
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [lm-sensors] NEW Nuvoton w83795 hw chip driver
2009-03-03 8:20 [lm-sensors] NEW Nuvoton w83795 hw chip driver Wsong
` (4 preceding siblings ...)
2009-03-31 1:12 ` Wsong
@ 2012-04-05 10:17 ` Chislett, William
2012-04-05 14:32 ` Guenter Roeck
6 siblings, 0 replies; 8+ messages in thread
From: Chislett, William @ 2012-04-05 10:17 UTC (permalink / raw)
To: lm-sensors
[-- Attachment #1: Type: text/plain, Size: 215 bytes --]
--===============8750259308404903534==
Content-class: urn:content-classes:message
Content-Type: multipart/alternative;
boundary="----_=_NextPart_001_01CD1315.3DF92C49"
This is a multi-part message in MIME format.
[-- Attachment #2: Type: text/plain, Size: 2371 bytes --]
Good Morning,
Apologies in advance as I realise the subject of this email may be
slightly outdated and the driver I'm referring to was created some time
ago (back in 2009!) but I've reached a dead-end trying to get reliable
sensor readings from a new ASUS server (ASUS ESC4000), and was hoping
someone might be able to help.
The issue I'm having is that lm-sensors only reads back realistic values
for about 10% of the time. The rest of the time all fanspeeds default
to 90,000rpm and all temperatures to -0.2degrees and over 80degrees,
which are obviously incorrect. I've tried using the latest version of
lm-sensors and the w83795 driver but keep running into this problem.
The w83795 driver provided on the lm-sensorswiki/Devices is the same as
that provided for this server via the ASUS website.
I'm using Linux CentOS 5.4 with a 2.6.18-164.el5 kernel (which isn't
listed as being supported by this driver unfortunately - probably part
of the issue). I've also seen similar problems, although mostly
involving sensor values locking-up, when using this driver and
ipmi-tools or similar hardware monitoring utilities.
I was wondering if you knew of any updated versions of this driver, or
alternatives I could try at all. Any sort of advice at all would be
massively appreciated!
Thanks for your time,
Will
______________________________________________
William Chislett
t +44 (0)207 812 4822 | m +44 (0)794 0023 001
a Detica | Surrey Research Park | Guildford | GU2 7YP | UK
______________________________________________
www.baesystemsdetica.com <http://www.baesystemsdetica.com/>
Please consider the environment before printing this email.
This message should be regarded as confidential. If you have received this email in error please notify the sender and destroy it immediately.
Statements of intent shall only become binding when confirmed in hard copy by an authorised signatory.
The contents of this email may relate to dealings with other companies under the control of BAE Systems plc details of which can be found at http://www.baesystems.com/Businesses/index.htm.
Detica Limited is a BAE Systems company trading as BAE Systems Detica.
Detica Limited is registered in England and Wales under No: 1337451.
Registered office: Surrey Research Park, Guildford, Surrey, GU2 7YP, England.
\r
[-- Attachment #3: Type: text/html, Size: 3983 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [lm-sensors] NEW Nuvoton w83795 hw chip driver
2009-03-03 8:20 [lm-sensors] NEW Nuvoton w83795 hw chip driver Wsong
` (5 preceding siblings ...)
2012-04-05 10:17 ` Chislett, William
@ 2012-04-05 14:32 ` Guenter Roeck
6 siblings, 0 replies; 8+ messages in thread
From: Guenter Roeck @ 2012-04-05 14:32 UTC (permalink / raw)
To: lm-sensors
On Thu, Apr 05, 2012 at 06:17:11AM -0400, Chislett, William wrote:
> Good Morning,
>
> Apologies in advance as I realise the subject of this email may be slightly
> outdated and the driver I'm referring to was created some time ago (back in
> 2009!) but I've reached a dead-end trying to get reliable sensor readings from
> a new ASUS server (ASUS ESC4000), and was hoping someone might be able to help.
>
> The issue I'm having is that lm-sensors only reads back realistic values for
> about 10% of the time. The rest of the time all fanspeeds default to 90,000rpm
> and all temperatures to -0.2degrees and over 80degrees, which are obviously
> incorrect. I've tried using the latest version of lm-sensors and the w83795
> driver but keep running into this problem. The w83795 driver provided on the
> lm-sensorswiki/Devices is the same as that provided for this server via the
> ASUS website.
>
> I'm using Linux CentOS 5.4 with a 2.6.18-164.el5 kernel (which isn't listed as
> being supported by this driver unfortunately - probably part of the issue).
> I've also seen similar problems, although mostly involving sensor values
> locking-up, when using this driver and ipmi-tools or similar hardware
> monitoring utilities.
>
> I was wondering if you knew of any updated versions of this driver, or
> alternatives I could try at all. Any sort of advice at all would be massively
> appreciated!
>
Hi,
the most likely reason for your problem is described here in detail:
http://hansdegoede.livejournal.com/7932.html
While that kernel change was made later, ASUS boards are known to use ACPI to access
the superio chip... which tends to result in exactly the behavior you are seeing.
You can try using the asus_atk0110 driver if it is supported in your kernel, or backport
it from a later kernel version, or update your kernel to one supporting it.
Guenter
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2012-04-05 14:32 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-03-03 8:20 [lm-sensors] NEW Nuvoton w83795 hw chip driver Wsong
2009-03-12 13:06 ` Jean Delvare
2009-03-13 1:25 ` Wsong
2009-03-13 1:28 ` Wsong
2009-03-13 8:47 ` Jean Delvare
2009-03-31 1:12 ` Wsong
2012-04-05 10:17 ` Chislett, William
2012-04-05 14:32 ` Guenter Roeck
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.