From ffdd27a3c2a23738c5869fedeaf19aa7f6a9c296 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 4 Nov 2005 20:59:18 +0000 Subject: [PATCH] Initial support for the Fintek F71805F/FG chip. git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@3169 7894878c-1315-0410-8ee3-d5d059ff63e0 --- CHANGES | 3 + CONTRIBUTORS | 3 +- README | 1 + doc/chips/SUMMARY | 3 + doc/chips/f71805f | 107 ++++++ doc/donations | 3 + etc/sensors.conf.eg | 64 ++++ kernel/chips/Module.mk | 3 + kernel/chips/f71805f.c | 751 +++++++++++++++++++++++++++++++++++++++++ lib/chips.c | 133 ++++++++ lib/chips.h | 20 ++ mkpatch/Config.in | 1 + mkpatch/FILES | 1 + mkpatch/mkpatch.pl | 12 + prog/sensors/chips.c | 80 +++++ prog/sensors/chips.h | 1 + prog/sensors/main.c | 1 + 17 files changed, 1186 insertions(+), 1 deletion(-) create mode 100644 doc/chips/f71805f create mode 100644 kernel/chips/f71805f.c diff --git a/CHANGES b/CHANGES index 71e7a865..5b5af26e 100644 --- a/CHANGES +++ b/CHANGES @@ -26,6 +26,7 @@ ask CVS about it: Drop I2C_FUNC_SMBUS_EMUL Library: Big update to use libsysfs. More TODO though. Fix bus matching code for Linux 2.6 (Karsten Petersen) + Add f71805f support Makefile: Compile user-space programs with -Wundef Module i2c-i810: Documentation update, PCI IDs cleanup Module i2c-keywest: Remove bus probing code (2.6 backport) @@ -41,6 +42,7 @@ ask CVS about it: not initialize i2c_adapter name to "unset" (2.6 backport) Module adm9240: Cleanups (2.6 backport) + Module f71805f: New, supports the Fintek F71805F/FG Super-I/O Module it87: Minor cleanups Module lm90: Support the ADM1032-2 and ADT7461-2 (2.6 backport) Module via686a: Cleanups @@ -62,6 +64,7 @@ ask CVS about it: Drop EEPROM support (Aurelien Jarno) Program sensors: Drop free_the_label Fix compilation with uclibc (no iconv) + Add f71805f support Program sensors-detect: Drop algorithm names Do not rely on i2cdetect -l printing algo names Simplify adapter name matching mechanism diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 25cd8f0c..d1b6c2e9 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -78,7 +78,8 @@ if you have questions, suggestions or problems. Author of the i2c-sis630 bus driver. Added Onsemi MC1066 support to the adm1021 driver. * Jean Delvare - Author of the lm63, lm83, lm90, pc87360 and w83l785ts chip drivers. + Author of the lm63, lm83, lm90 and w83l785ts SMBus chip drivers. + Author of the f71805f and pc87360 Super-I/O chip drivers. Author of the i2c-amd756-s4882 and pca9540 SMBus multiplexing drivers. Author of the decode-vaio.pl Vaio EEPROM decoder. Author of the decode-edid.pl EDID data decoder. diff --git a/README b/README index ca4ac566..3bd9c7de 100644 --- a/README +++ b/README @@ -78,6 +78,7 @@ At least the following hardware sensor chips are supported: Asus AS99127F, ASB100 Bach Dallas Semiconductor DS75, DS1621, DS1625, DS1775, and DS1780 Hewlett Packard Maxilife (several revisions including '99 NBA) + Fintek F71805F/FG Fujitsu Siemens Poseidon, Scylla, Hermes Genesys Logic GL518SM, GL520SM, GL523SM Intel Xeon processor embedded sensors diff --git a/doc/chips/SUMMARY b/doc/chips/SUMMARY index d8e6023a..34c28d02 100644 --- a/doc/chips/SUMMARY +++ b/doc/chips/SUMMARY @@ -97,6 +97,9 @@ ds1621 (the following chip is detected as a ds1621) ds1625 1 - - - yes no +f71805f + f71805f 9 3 3 - no yes + fscher fscher 3 3 3 - yes no diff --git a/doc/chips/f71805f b/doc/chips/f71805f new file mode 100644 index 00000000..8b7ab6ed --- /dev/null +++ b/doc/chips/f71805f @@ -0,0 +1,107 @@ +Kernel driver `f71805f.o' +========================= + +Status: Beta. + +Supported chips: + * Fintek F71805F/FG + Addresses scanned: none, address read from Super I/O config space + Prefix: 'f71805f' + Datasheet: Provided by Fintek on request + +Author: Jean Delvare + +Thanks to Denis Kieft from Barracuda Networks for the donation of a +test system (custom Jetway K8M8MS motherboard, with CPU and RAM) and +for providing initial documentation. + +Thanks to Kris Chen from Fintek for answering technical questions and +providing additional documentation. + +Thanks to Chris Lin from Jetway for providing wiring schematics and +anwsering technical questions. + + +Description +----------- + +The Fintek F71805F/FG Super I/O chip includes complete hardware monitoring +capabilities. It can monitor up to 9 voltages (counting its own power +source), 3 fans and 3 temperature sensors. + +This chip also has fan controlling features, using either DC or PWM, in +three different modes (one manual, two automatic). The driver doesn't +support these features yet. + +The driver assumes that no more than one chip is present, which seems +reasonable. + + +Voltage Monitoring +------------------ + +Voltages are sampled by an 8-bit ADC with a LSB of 8 mV. The supported +range is thus from 0 to 2.040 V. Voltage values outside of this range +need external resistors. An exception is in0, which is used to monitor +the chip's own power source (+3.3V), and is divided internally by a +factor 2. + +The two LSB of the voltage limit registers are not used (always 0), so +you can only set the limits in steps of 32 mV (before scaling). + +The wirings and resistor values suggested by Fintek are as follow: + + pin expected + name use R1 R2 divider raw val. + +in0 VCC VCC3.3V int. int. 2.00 1.65 V +in1 VIN1 VTT1.2V 10K - 1.00 1.20 V +in2 VIN2 VRAM 100K 100K 2.00 ~1.25 V (1) +in3 VIN3 VCHIPSET 47K 100K 1.47 2.24 V (2) +in4 VIN4 VCC5V 200K 47K 5.25 0.95 V +in5 VIN5 +12V 200K 20K 11.00 1.05 V +in6 VIN6 VCC1.5V 10K - 1.00 1.50 V +in7 VIN7 VCORE 10K - 1.00 ~1.40 V (1) +in8 VIN8 VSB5V 200K 47K 1.00 0.95 V + +(1) Depends on your hardware setup. +(2) Obviously not correct, swapping R1 and R2 would make more sense. + +These values can be used as hints at best, as motherboard manufacturers +are free to use a completely different setup. As a matter of fact, the +Jetway K8M8MS uses a significantly different setup. You will have to +find out documentation about your own motherboard, and edit sensors.conf +accordingly. + +Each voltage measured has associated low and high limits, each of which +triggers an alarm when crossed. + + +Fan Monitoring +-------------- + +Fan rotation speeds are reported as 12-bit values from a gated clock +signal. Speeds down to 366 RPM can be measured. There is no theoretical +high limit, but values over 6000 RPM seem to cause problem. The effective +resolution is much lower than you would expect, the step between different +register values being 10 rather than 1. + +The chip assumes 2 pulse-per-revolution fans. + +An alarm is triggered if the rotation speed drops below a programmable +limit or is too low to be measured. + + +Temperature Monitoring +---------------------- + +Temperatures are reported in degrees Celsius. Each temperature measured +has a high limit, those crossing triggers an alarm. There is an associated +hysteresis value, below which the temperature has to drop before the +alarm is cleared. + +All temperature channels are external, there is no embedded temperature +sensor. Each channel can be used for connecting either a thermal diode +or a thermistor. The driver reports the currently selected mode, but +doesn't allow changing it. In theory, the BIOS should have configured +everything properly. diff --git a/doc/donations b/doc/donations index 6cb6a4b2..fdc75bc7 100644 --- a/doc/donations +++ b/doc/donations @@ -85,3 +85,6 @@ Wincor Nixdorf Seagate Barracuda 7200.7 160GB harddisk drive 2004-10 Aweta Intel Server system 2005-09 Drivers developed: PC87431 (IPMI SMB) MDS + +Barracuda Jetway K8M8MS, Sempron 2600+, 256 MB RAM 2005-10 +Networks Drivers developed: f71805f Jean Delvare diff --git a/etc/sensors.conf.eg b/etc/sensors.conf.eg index 41b3c9a1..fe1bdd5e 100644 --- a/etc/sensors.conf.eg +++ b/etc/sensors.conf.eg @@ -2366,3 +2366,67 @@ chip "w83627ehf-*" set temp2_over 45 set temp2_hyst 40 + +# Fintek F71805F/FG configuration +# This is the recommended wiring and resistor values from the F71805F/FG +# datasheet. Your motherboard manufacturer may or may not have followed +# these. +chip "f71805f-*" +# Voltages + label in0 "+3.3V" + label in1 "Vtt1.2V" + label in2 "Vram" + label in3 "Vchip" + label in4 "+5V" + label in5 "+12V" + label in6 "Vcc1.5V" + label in7 "Vcore" + label in8 "5VSB" + + # in0 is scaled internally + compute in2 @*(1+100/100), @/(1+100/100) + compute in3 @*(1+100/47), @/(1+100/47) + compute in4 @*(1+200/47), @/(1+200/47) + compute in5 @*(1+200/20), @/(1+200/20) + compute in8 @*(1+200/47), @/(1+200/47) + + set in0_min 3.3 * 0.95 + set in0_max 3.3 * 1.05 + #set in1_min 1.2 * 0.95 + #set in1_max 1.2 * 1.05 + #set in2_min 2.5 * 0.95 + #set in2_max 2.6 * 1.05 + #set in3_min 3.3 * 0.95 + #set in3_max 3.3 * 1.05 + #set in4_min 5.0 * 0.95 + #set in4_max 5.0 * 1.05 + #set in5_min 12.0 * 0.95 + #set in5_max 12.0 * 1.05 + #set in6_min 1.5 * 0.95 + #set in6_max 1.5 * 1.05 + # in7 nominal value depends on the CPU model + #set in7_min 1.4 * 0.95 + #set in7_max 1.4 * 1.05 + #set in8_min 5.0 * 0.95 + #set in8_max 5.0 * 1.05 + +# Fans + label fan1 "CPU Fan" + label fan2 "Sys Fan" + label fan3 "Aux Fan" + + #set fan1_min 2100 + #set fan2_min 1400 + #set fan3_min 1400 + +# Temperatures + label temp1 "CPU Temp" + label temp2 "Sys Temp" + label temp3 "Aux Temp" + + #set temp1_max 60 + #set temp1_hyst 58 + #set temp2_max 50 + #set temp2_hyst 48 + #set temp3_max 50 + #set temp3_hyst 48 diff --git a/kernel/chips/Module.mk b/kernel/chips/Module.mk index 089d2f26..f8a7485a 100644 --- a/kernel/chips/Module.mk +++ b/kernel/chips/Module.mk @@ -71,6 +71,9 @@ endif ifneq ($(shell if grep -q '^CONFIG_SENSORS_EEPROM=y' $(LINUX)/.config; then echo 1; fi),1) KERNELCHIPSTARGETS += $(MODULE_DIR)/eeprom.o endif +ifneq ($(shell if grep -q '^CONFIG_SENSORS_F71805F=y' $(LINUX)/.config; then echo 1; fi),1) +KERNELCHIPSTARGETS += $(MODULE_DIR)/f71805f.o +endif ifneq ($(shell if grep -q '^CONFIG_SENSORS_FSCHER=y' $(LINUX)/.config; then echo 1; fi),1) KERNELCHIPSTARGETS += $(MODULE_DIR)/fscher.o endif diff --git a/kernel/chips/f71805f.c b/kernel/chips/f71805f.c new file mode 100644 index 00000000..5f605e61 --- /dev/null +++ b/kernel/chips/f71805f.c @@ -0,0 +1,751 @@ +/* + * f71805f.c - driver for the Fintek F71805F Super-I/O chip integrated + * hardware monitoring features + * Copyright (C) 2005 Jean Delvare + * + * The F71805F is a LPC Super-I/O chip made by Fintek. It integrates + * complete hardware monitoring features: voltage, fan and temperature + * sensors, and manual and automatic fan speed control. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "version.h" + +/* ISA address is read from Super-I/O configuration space */ +static unsigned short normal_i2c[] = { SENSORS_I2C_END }; +static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; +static unsigned int normal_isa[] = { 0, SENSORS_ISA_END }; +static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; + +SENSORS_INSMOD_1(f71805f); + +#define DRVNAME "f71805f" + +/* + * Super-I/O constants and functions + */ + +static int REG; /* The register to read from/write to */ +static int VAL; /* The value to read/write */ + +#define F71805F_LD_HWM 0x04 + +#define SIO_REG_LDSEL 0x07 /* Logical device select */ +#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ +#define SIO_REG_DEVREV 0x22 /* Device revision */ +#define SIO_REG_ENABLE 0x30 /* Logical device enable */ +#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ + +#define SIO_F71805F_ID 0x0406 + +static inline int +superio_inb(int reg) +{ + outb(reg, REG); + return inb(VAL); +} + +static int +superio_inw(int reg) +{ + int val; + outb(reg++, REG); + val = inb(VAL) << 8; + outb(reg, REG); + val |= inb(VAL); + return val; +} + +static inline void +superio_select(int ld) +{ + outb(SIO_REG_LDSEL, REG); + outb(ld, VAL); +} + +static inline void +superio_enter(void) +{ + outb(0x87, REG); + outb(0x87, REG); +} + +static inline void +superio_exit(void) +{ + outb(0xaa, REG); +} + +/* + * ISA constants + */ + +#define REGION_LENGTH 2 +#define ADDR_REG_OFFSET 0 +#define DATA_REG_OFFSET 1 + +/* + * Registers + */ + +/* in nr from 0 to 8 (8-bit values) */ +#define F71805F_REG_IN(nr) (0x10 + (nr)) +#define F71805F_REG_IN_HIGH(nr) (0x40 + 2 * (nr)) +#define F71805F_REG_IN_LOW(nr) (0x41 + 2 * (nr)) +/* fan nr from 0 to 2 (12-bit values, two registers) */ +#define F71805F_REG_FAN(nr) (0x20 + 2 * (nr)) +#define F71805F_REG_FAN_LOW(nr) (0x28 + 2 * (nr)) +#define F71805F_REG_FAN_CTRL(nr) (0x60 + 16 * (nr)) +/* temp nr from 0 to 2 (8-bit values) */ +#define F71805F_REG_TEMP(nr) (0x1B + (nr)) +#define F71805F_REG_TEMP_HIGH(nr) (0x54 + 2 * (nr)) +#define F71805F_REG_TEMP_HYST(nr) (0x55 + 2 * (nr)) +#define F71805F_REG_TEMP_MODE 0x01 + +#define F71805F_REG_START 0x00 +/* status nr from 0 to 2 */ +#define F71805F_REG_STATUS(nr) (0x36 + (nr)) + +/* + * Data structures and manipulation thereof + */ + +struct f71805f_data { + struct i2c_client client; + struct semaphore lock; + int sysctl_id; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + unsigned long last_limits; /* In jiffies */ + + /* Register values */ + u8 in[9]; + u8 in_high[9]; + u8 in_low[9]; + u16 fan[3]; + u16 fan_low[3]; + u8 fan_enabled; /* Read once at init time */ + u8 temp[3]; + u8 temp_high[3]; + u8 temp_hyst[3]; + u8 temp_mode; + u8 alarms[3]; +}; + +static inline long in_from_reg(u8 reg) +{ + return (reg * 8); +} + +/* The 2 least significant bits are not used */ +static inline u8 in_to_reg(long val) +{ + if (val <= 0) + return 0; + if (val >= 2016) + return 0xfc; + return (((val + 16) / 32) << 2); +} + +/* in0 is downscaled by a factor 2 internally */ +static inline long in0_from_reg(u8 reg) +{ + return (reg * 16); +} + +static inline u8 in0_to_reg(long val) +{ + if (val <= 0) + return 0; + if (val >= 4032) + return 0xfc; + return (((val + 32) / 64) << 2); +} + +/* The 4 most significant bits are not used */ +static inline long fan_from_reg(u16 reg) +{ + reg &= 0xfff; + if (!reg || reg == 0xfff) + return 0; + return (1500000 / reg); +} + +static inline u16 fan_to_reg(long rpm) +{ + /* If the low limit is set below what the chip can measure, + store the largest possible 12-bit value in the registers, + so that no alarm will ever trigger. */ + if (rpm < 367) + return 0xfff; + return (1500000 / rpm); +} + +static inline u8 temp_to_reg(long val) +{ + if (val < 0) + val = 0; + else if (val > 0xff) + val = 0xff; + return val; +} + +/* + * Driver and client management + */ + +static u8 f71805f_read8(struct i2c_client *client, u8 reg) +{ + struct f71805f_data *data = client->data; + u8 val; + + down(&data->lock); + outb_p(reg, client->addr + ADDR_REG_OFFSET); + val = inb_p(client->addr + DATA_REG_OFFSET); + up(&data->lock); + + return val; +} + +static void f71805f_write8(struct i2c_client *client, u8 reg, u8 val) +{ + struct f71805f_data *data = client->data; + + down(&data->lock); + outb_p(reg, client->addr + ADDR_REG_OFFSET); + outb_p(val, client->addr + DATA_REG_OFFSET); + up(&data->lock); +} + +/* It is important to read the MSB first, because doing so latches the + value of the LSB, so we are sure both bytes belong to the same value. */ +static u16 f71805f_read16(struct i2c_client *client, u8 reg) +{ + struct f71805f_data *data = client->data; + u16 val; + + down(&data->lock); + outb_p(reg, client->addr + ADDR_REG_OFFSET); + val = inb_p(client->addr + DATA_REG_OFFSET) << 8; + outb_p(++reg, client->addr + ADDR_REG_OFFSET); + val |= inb_p(client->addr + DATA_REG_OFFSET); + up(&data->lock); + + return val; +} + +static void f71805f_write16(struct i2c_client *client, u8 reg, u16 val) +{ + struct f71805f_data *data = client->data; + + down(&data->lock); + outb_p(reg, client->addr + ADDR_REG_OFFSET); + outb_p(val >> 8, client->addr + DATA_REG_OFFSET); + outb_p(++reg, client->addr + ADDR_REG_OFFSET); + outb_p(val & 0xff, client->addr + DATA_REG_OFFSET); + up(&data->lock); +} + +static struct i2c_driver f71805f_driver; +static ctl_table f71805f_dir_table_template[]; + +static void f71805f_init_client(struct i2c_client *client) +{ + struct f71805f_data *data = client->data; + u8 reg; + int i; + + reg = f71805f_read8(client, F71805F_REG_START); + if ((reg & 0x41) != 0x01) { + printk(KERN_DEBUG "%s: Starting monitoring operations\n", + DRVNAME); + f71805f_write8(client, + F71805F_REG_START, (reg | 0x01) & ~0x40); + } + + /* Fan monitoring can be disabled. If it is, we won't be polling + the register values, and instead set the cache to return 0 RPM. */ + for (i = 0; i < 3; i++) { + reg = f71805f_read8(client, F71805F_REG_FAN_CTRL(i)); + if (!(reg & 0x80)) + data->fan_enabled |= (1 << i); + else + data->fan[i] = data->fan_low[i] = 0xfff; + } +} + +static int f71805f_detect(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind) +{ + struct i2c_client *client; + struct f71805f_data *data; + int err = 0; + + if (!request_region(address, REGION_LENGTH, f71805f_driver.name)) { + err = -EBUSY; + goto exit; + } + + if (!(data = kmalloc(sizeof(struct f71805f_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit_release; + } + memset(data, 0, sizeof(struct f71805f_data)); + + /* Fill in the client fields */ + client = &data->client; + client->addr = address; + client->data = data; + client->adapter = adapter; + client->driver = &f71805f_driver; + strcpy(client->name, "F71805F chip"); + + init_MUTEX(&data->lock); + init_MUTEX(&data->update_lock); + + /* Tell the i2c core a new client has arrived */ + if ((err = i2c_attach_client(client))) + goto exit_free; + + /* Register a new directory entry in /proc */ + err = i2c_register_entry(client, "f71805f", + f71805f_dir_table_template, THIS_MODULE); + if (err < 0) + goto exit_detach; + data->sysctl_id = err; + + /* Initialize the F71805F chip */ + f71805f_init_client(client); + return 0; + +exit_detach: + i2c_detach_client(client); +exit_free: + kfree(data); +exit_release: + release_region(address, REGION_LENGTH); +exit: + return err; +} + +static int f71805f_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, f71805f_detect); +} + +static int f71805f_detach_client(struct i2c_client *client) +{ + int err; + struct f71805f_data *data = client->data; + + i2c_deregister_entry(data->sysctl_id); + if ((err = i2c_detach_client(client))) { + printk(KERN_ERR "%s: Client deregistration failed, " + "client not detached\n", DRVNAME); + return err; + } + + release_region(client->addr, REGION_LENGTH); + kfree(client->data); + + return 0; +} + +static void f71805f_update_client(struct i2c_client *client) +{ + struct f71805f_data *data = client->data; + int nr; + + down(&data->update_lock); + + /* Limit registers cache is refreshed after 60 seconds */ + if ((jiffies - data->last_limits > 60 * HZ) + || (jiffies < data->last_limits) + || !data->valid) { + for (nr = 0; nr < 9; nr++) { + data->in_high[nr] = f71805f_read8(client, + F71805F_REG_IN_HIGH(nr)); + data->in_low[nr] = f71805f_read8(client, + F71805F_REG_IN_LOW(nr)); + } + for (nr = 0; nr < 3; nr++) { + if (data->fan_enabled & (1 << nr)) + data->fan_low[nr] = f71805f_read16(client, + F71805F_REG_FAN_LOW(nr)); + } + for (nr = 0; nr < 3; nr++) { + data->temp_high[nr] = f71805f_read8(client, + F71805F_REG_TEMP_HIGH(nr)); + data->temp_hyst[nr] = f71805f_read8(client, + F71805F_REG_TEMP_HYST(nr)); + } + data->temp_mode = f71805f_read8(client, F71805F_REG_TEMP_MODE); + + data->last_limits = jiffies; + } + + /* Measurement registers cache is refreshed after 1 second */ + if ((jiffies - data->last_updated > HZ) + || (jiffies < data->last_updated) + || !data->valid) { + for (nr = 0; nr < 9; nr++) { + data->in[nr] = f71805f_read8(client, + F71805F_REG_IN(nr)); + } + for (nr = 0; nr < 3; nr++) { + if (data->fan_enabled & (1 << nr)) + data->fan[nr] = f71805f_read16(client, + F71805F_REG_FAN(nr)); + } + for (nr = 0; nr < 3; nr++) { + data->temp[nr] = f71805f_read8(client, + F71805F_REG_TEMP(nr)); + } + for (nr = 0; nr < 3; nr++) { + data->alarms[nr] = f71805f_read8(client, + F71805F_REG_STATUS(nr)); + } + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); +} + +/* -- SENSORS SYSCTL START -- */ +#define F71805F_SYSCTL_IN0 1000 +#define F71805F_SYSCTL_IN1 1001 +#define F71805F_SYSCTL_IN2 1002 +#define F71805F_SYSCTL_IN3 1003 +#define F71805F_SYSCTL_IN4 1004 +#define F71805F_SYSCTL_IN5 1005 +#define F71805F_SYSCTL_IN6 1006 +#define F71805F_SYSCTL_IN7 1007 +#define F71805F_SYSCTL_IN8 1008 +#define F71805F_SYSCTL_FAN1 1101 +#define F71805F_SYSCTL_FAN2 1102 +#define F71805F_SYSCTL_FAN3 1103 +#define F71805F_SYSCTL_TEMP1 1201 +#define F71805F_SYSCTL_TEMP2 1202 +#define F71805F_SYSCTL_TEMP3 1203 +#define F71805F_SYSCTL_SENSOR1 1211 +#define F71805F_SYSCTL_SENSOR2 1212 +#define F71805F_SYSCTL_SENSOR3 1213 +#define F71805F_SYSCTL_ALARMS_IN 1090 +#define F71805F_SYSCTL_ALARMS_FAN 1190 +#define F71805F_SYSCTL_ALARMS_TEMP 1290 +/* -- SENSORS SYSCTL END -- */ + +static void f71805f_in(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct f71805f_data *data = client->data; + int nr = ctl_name - F71805F_SYSCTL_IN0; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 3; + else if (operation == SENSORS_PROC_REAL_READ) { + f71805f_update_client(client); + results[0] = in_from_reg(data->in_low[nr]); + results[1] = in_from_reg(data->in_high[nr]); + results[2] = in_from_reg(data->in[nr]); + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag < 1) + return; + + down(&data->update_lock); + data->in_low[nr] = in_to_reg(results[0]); + f71805f_write8(client, F71805F_REG_IN_LOW(nr), + data->in_low[nr]); + + if (*nrels_mag >= 2) { + data->in_high[nr] = in_to_reg(results[1]); + f71805f_write8(client, F71805F_REG_IN_HIGH(nr), + data->in_high[nr]); + } + up(&data->update_lock); + } +} + +static void f71805f_in0(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct f71805f_data *data = client->data; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 3; + else if (operation == SENSORS_PROC_REAL_READ) { + f71805f_update_client(client); + results[0] = in0_from_reg(data->in_low[0]); + results[1] = in0_from_reg(data->in_high[0]); + results[2] = in0_from_reg(data->in[0]); + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag < 1) + return; + + down(&data->update_lock); + data->in_low[0] = in0_to_reg(results[0]); + f71805f_write8(client, F71805F_REG_IN_LOW(0), + data->in_low[0]); + + if (*nrels_mag >= 2) { + data->in_high[0] = in0_to_reg(results[1]); + f71805f_write8(client, F71805F_REG_IN_HIGH(0), + data->in_high[0]); + } + up(&data->update_lock); + } +} + +static void f71805f_fan(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct f71805f_data *data = client->data; + int nr = ctl_name - F71805F_SYSCTL_FAN1; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + f71805f_update_client(client); + results[0] = fan_from_reg(data->fan_low[nr]); + results[1] = fan_from_reg(data->fan[nr]); + *nrels_mag = 2; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag < 1) + return; + + down(&data->update_lock); + data->fan_low[nr] = fan_to_reg(results[0]); + f71805f_write16(client, F71805F_REG_FAN_LOW(nr), + data->fan_low[nr]); + up(&data->update_lock); + } +} + +static void f71805f_temp(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct f71805f_data *data = client->data; + int nr = ctl_name - F71805F_SYSCTL_TEMP1; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + f71805f_update_client(client); + results[0] = data->temp_high[nr]; + results[1] = data->temp_hyst[nr]; + results[2] = data->temp[nr]; + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag < 1) + return; + + down(&data->update_lock); + data->temp_high[nr] = temp_to_reg(results[0]); + f71805f_write8(client, F71805F_REG_TEMP_HIGH(nr), + data->temp_high[nr]); + + if (*nrels_mag >= 2) { + data->temp_hyst[nr] = temp_to_reg(results[1]); + f71805f_write8(client, F71805F_REG_TEMP_HYST(nr), + data->temp_hyst[nr]); + } + up(&data->update_lock); + } +} + +static void f71805f_sensor(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct f71805f_data *data = client->data; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + int nr = ctl_name - F71805F_SYSCTL_SENSOR1; + + f71805f_update_client(client); + results[0] = (data->temp_mode & (1 << nr)) ? 3 : 4; + *nrels_mag = 1; + } +} + +static void f71805f_alarms_in(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct f71805f_data *data = client->data; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + f71805f_update_client(client); + results[0] = data->alarms[0] + | ((data->alarms[1] & 0x01) << 8); + *nrels_mag = 1; + } +} + +static void f71805f_alarms_fan(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct f71805f_data *data = client->data; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + f71805f_update_client(client); + results[0] = data->alarms[2] & 0x07; + *nrels_mag = 1; + } +} + +static void f71805f_alarms_temp(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct f71805f_data *data = client->data; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + f71805f_update_client(client); + results[0] = (data->alarms[1] >> 3) & 0x07; + *nrels_mag = 1; + } +} + +static ctl_table f71805f_dir_table_template[] = { + { F71805F_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in0 }, + { F71805F_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, + { F71805F_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, + { F71805F_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, + { F71805F_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, + { F71805F_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, + { F71805F_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, + { F71805F_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, + { F71805F_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, + { F71805F_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_fan }, + { F71805F_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_fan }, + { F71805F_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_fan }, + { F71805F_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_temp }, + { F71805F_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_temp }, + { F71805F_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_temp }, + { F71805F_SYSCTL_SENSOR1, "sensor1", NULL, 0, 0444, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_sensor }, + { F71805F_SYSCTL_SENSOR2, "sensor2", NULL, 0, 0444, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_sensor }, + { F71805F_SYSCTL_SENSOR3, "sensor3", NULL, 0, 0444, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_sensor }, + { F71805F_SYSCTL_ALARMS_IN, "alarms_in", NULL, 0, 0444, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_alarms_in }, + { F71805F_SYSCTL_ALARMS_FAN, "alarms_fan", NULL, 0, 0444, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_alarms_fan }, + { F71805F_SYSCTL_ALARMS_TEMP, "alarms_temp", NULL, 0, 0444, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_alarms_temp }, + { 0 } +}; + +static struct i2c_driver f71805f_driver = { + .name = "F71805F sensor driver", + .flags = I2C_DF_NOTIFY, + .attach_adapter = f71805f_attach_adapter, + .detach_client = f71805f_detach_client, +}; + +static int __init f71805f_find(int sioaddr, unsigned int *address) +{ + int err = -ENODEV; + u16 devid; + + REG = sioaddr; + VAL = sioaddr + 1; + superio_enter(); + + devid = superio_inw(SIO_REG_DEVID); + if (devid != SIO_F71805F_ID) + goto exit; + + superio_select(F71805F_LD_HWM); + if (!(superio_inb(SIO_REG_ENABLE) & 0x01)) { + printk(KERN_WARNING "%s: Device not activated, skipping\n", + DRVNAME); + goto exit; + } + + *address = superio_inw(SIO_REG_ADDR); + if (*address == 0) { + printk(KERN_WARNING "%s: Base address not set, skipping\n", + DRVNAME); + goto exit; + } + + err = 0; + printk(KERN_INFO "%s: Found F71805F chip at %#x, revision %u\n", + DRVNAME, *address, superio_inb(SIO_REG_DEVREV)); + +exit: + superio_exit(); + return err; +} + +static int __init f71805f_init(void) +{ + printk("%s: Driver version %s (%s)\n", DRVNAME, LM_VERSION, LM_DATE); + + if (f71805f_find(0x2e, &normal_isa[0]) + && f71805f_find(0x4e, &normal_isa[0])) + return -ENODEV; + + return i2c_add_driver(&f71805f_driver); +} + +static void __exit f71805f_exit(void) +{ + i2c_del_driver(&f71805f_driver); +} + +MODULE_AUTHOR("Jean Delvare "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("F71805F hardware monitoring driver"); + +module_init(f71805f_init); +module_exit(f71805f_exit); diff --git a/lib/chips.c b/lib/chips.c index 708b81fb..60a2216b 100644 --- a/lib/chips.c +++ b/lib/chips.c @@ -5418,6 +5418,138 @@ static sensors_chip_feature smsc47b397_features[] = { 0 } }; +static sensors_chip_feature f71805f_features[] = +{ +/* 9 voltage inputs */ + { SENSORS_F71805F_IN(0), "in0", NOMAP, NOMAP, R, + F71805F_SYSCTL_IN0, VALUE(3), 3 }, + { SENSORS_F71805F_IN(1), "in1", NOMAP, NOMAP, R, + F71805F_SYSCTL_IN1, VALUE(3), 3 }, + { SENSORS_F71805F_IN(2), "in2", NOMAP, NOMAP, R, + F71805F_SYSCTL_IN2, VALUE(3), 3 }, + { SENSORS_F71805F_IN(3), "in3", NOMAP, NOMAP, R, + F71805F_SYSCTL_IN3, VALUE(3), 3 }, + { SENSORS_F71805F_IN(4), "in4", NOMAP, NOMAP, R, + F71805F_SYSCTL_IN4, VALUE(3), 3 }, + { SENSORS_F71805F_IN(5), "in5", NOMAP, NOMAP, R, + F71805F_SYSCTL_IN5, VALUE(3), 3 }, + { SENSORS_F71805F_IN(6), "in6", NOMAP, NOMAP, R, + F71805F_SYSCTL_IN6, VALUE(3), 3 }, + { SENSORS_F71805F_IN(7), "in7", NOMAP, NOMAP, R, + F71805F_SYSCTL_IN7, VALUE(3), 3 }, + { SENSORS_F71805F_IN(8), "in8", NOMAP, NOMAP, R, + F71805F_SYSCTL_IN8, VALUE(3), 3 }, + { SENSORS_F71805F_IN_MIN(0), "in0_min", + SENSORS_F71805F_IN(0), SENSORS_F71805F_IN(0), RW, + F71805F_SYSCTL_IN0, VALUE(1), 3 }, + { SENSORS_F71805F_IN_MIN(1), "in1_min", + SENSORS_F71805F_IN(1), SENSORS_F71805F_IN(1), RW, + F71805F_SYSCTL_IN1, VALUE(1), 3 }, + { SENSORS_F71805F_IN_MIN(2), "in2_min", + SENSORS_F71805F_IN(2), SENSORS_F71805F_IN(2), RW, + F71805F_SYSCTL_IN2, VALUE(1), 3 }, + { SENSORS_F71805F_IN_MIN(3), "in3_min", + SENSORS_F71805F_IN(3), SENSORS_F71805F_IN(3), RW, + F71805F_SYSCTL_IN3, VALUE(1), 3 }, + { SENSORS_F71805F_IN_MIN(4), "in4_min", + SENSORS_F71805F_IN(4), SENSORS_F71805F_IN(4), RW, + F71805F_SYSCTL_IN4, VALUE(1), 3 }, + { SENSORS_F71805F_IN_MIN(5), "in5_min", + SENSORS_F71805F_IN(5), SENSORS_F71805F_IN(5), RW, + F71805F_SYSCTL_IN5, VALUE(1), 3 }, + { SENSORS_F71805F_IN_MIN(6), "in6_min", + SENSORS_F71805F_IN(6), SENSORS_F71805F_IN(6), RW, + F71805F_SYSCTL_IN6, VALUE(1), 3 }, + { SENSORS_F71805F_IN_MIN(7), "in7_min", + SENSORS_F71805F_IN(7), SENSORS_F71805F_IN(7), RW, + F71805F_SYSCTL_IN7, VALUE(1), 3 }, + { SENSORS_F71805F_IN_MIN(8), "in8_min", + SENSORS_F71805F_IN(8), SENSORS_F71805F_IN(8), RW, + F71805F_SYSCTL_IN8, VALUE(1), 3 }, + { SENSORS_F71805F_IN_MAX(0), "in0_max", + SENSORS_F71805F_IN(0), SENSORS_F71805F_IN(0), RW, + F71805F_SYSCTL_IN0, VALUE(2), 3 }, + { SENSORS_F71805F_IN_MAX(1), "in1_max", + SENSORS_F71805F_IN(1), SENSORS_F71805F_IN(1), RW, + F71805F_SYSCTL_IN1, VALUE(2), 3 }, + { SENSORS_F71805F_IN_MAX(2), "in2_max", + SENSORS_F71805F_IN(2), SENSORS_F71805F_IN(2), RW, + F71805F_SYSCTL_IN2, VALUE(2), 3 }, + { SENSORS_F71805F_IN_MAX(3), "in3_max", + SENSORS_F71805F_IN(3), SENSORS_F71805F_IN(3), RW, + F71805F_SYSCTL_IN3, VALUE(2), 3 }, + { SENSORS_F71805F_IN_MAX(4), "in4_max", + SENSORS_F71805F_IN(4), SENSORS_F71805F_IN(4), RW, + F71805F_SYSCTL_IN4, VALUE(2), 3 }, + { SENSORS_F71805F_IN_MAX(5), "in5_max", + SENSORS_F71805F_IN(5), SENSORS_F71805F_IN(5), RW, + F71805F_SYSCTL_IN5, VALUE(2), 3 }, + { SENSORS_F71805F_IN_MAX(6), "in6_max", + SENSORS_F71805F_IN(6), SENSORS_F71805F_IN(6), RW, + F71805F_SYSCTL_IN6, VALUE(2), 3 }, + { SENSORS_F71805F_IN_MAX(7), "in7_max", + SENSORS_F71805F_IN(7), SENSORS_F71805F_IN(7), RW, + F71805F_SYSCTL_IN7, VALUE(2), 3 }, + { SENSORS_F71805F_IN_MAX(8), "in8_max", + SENSORS_F71805F_IN(8), SENSORS_F71805F_IN(8), RW, + F71805F_SYSCTL_IN8, VALUE(2), 3 }, +/* 3 fan tachometers */ + { SENSORS_F71805F_FAN(1), "fan1", NOMAP, NOMAP, R, + F71805F_SYSCTL_FAN1, VALUE(2), 0 }, + { SENSORS_F71805F_FAN(2), "fan2", NOMAP, NOMAP, R, + F71805F_SYSCTL_FAN2, VALUE(2), 0 }, + { SENSORS_F71805F_FAN(3), "fan3", NOMAP, NOMAP, R, + F71805F_SYSCTL_FAN3, VALUE(2), 0 }, + { SENSORS_F71805F_FAN_MIN(1), "fan1_min", + SENSORS_F71805F_FAN(1), SENSORS_F71805F_FAN(1), RW, + F71805F_SYSCTL_FAN1, VALUE(1), 0 }, + { SENSORS_F71805F_FAN_MIN(2), "fan2_min", + SENSORS_F71805F_FAN(2), SENSORS_F71805F_FAN(2), RW, + F71805F_SYSCTL_FAN2, VALUE(1), 0 }, + { SENSORS_F71805F_FAN_MIN(3), "fan3_min", + SENSORS_F71805F_FAN(3), SENSORS_F71805F_FAN(3), RW, + F71805F_SYSCTL_FAN3, VALUE(1), 0 }, +/* 3 temperature inputs */ + { SENSORS_F71805F_TEMP(1), "temp1", NOMAP, NOMAP, R, + F71805F_SYSCTL_TEMP1, VALUE(3), 0 }, + { SENSORS_F71805F_TEMP(2), "temp2", NOMAP, NOMAP, R, + F71805F_SYSCTL_TEMP2, VALUE(3), 0 }, + { SENSORS_F71805F_TEMP(3), "temp3", NOMAP, NOMAP, R, + F71805F_SYSCTL_TEMP3, VALUE(3), 0 }, + { SENSORS_F71805F_TEMP_MAX(1), "temp1_max", + SENSORS_F71805F_TEMP(1), SENSORS_F71805F_TEMP(1), RW, + F71805F_SYSCTL_TEMP1, VALUE(1), 0 }, + { SENSORS_F71805F_TEMP_MAX(2), "temp2_max", + SENSORS_F71805F_TEMP(2), SENSORS_F71805F_TEMP(2), RW, + F71805F_SYSCTL_TEMP2, VALUE(1), 0 }, + { SENSORS_F71805F_TEMP_MAX(3), "temp3_max", + SENSORS_F71805F_TEMP(3), SENSORS_F71805F_TEMP(3), RW, + F71805F_SYSCTL_TEMP3, VALUE(1), 0 }, + { SENSORS_F71805F_TEMP_HYST(1), "temp1_hyst", + SENSORS_F71805F_TEMP(1), SENSORS_F71805F_TEMP(1), RW, + F71805F_SYSCTL_TEMP1, VALUE(2), 0 }, + { SENSORS_F71805F_TEMP_HYST(2), "temp2_hyst", + SENSORS_F71805F_TEMP(2), SENSORS_F71805F_TEMP(2), RW, + F71805F_SYSCTL_TEMP2, VALUE(2), 0 }, + { SENSORS_F71805F_TEMP_HYST(3), "temp3_hyst", + SENSORS_F71805F_TEMP(3), SENSORS_F71805F_TEMP(3), RW, + F71805F_SYSCTL_TEMP3, VALUE(2), 0 }, + { SENSORS_F71805F_TEMP_TYPE(1), "sensor1", NOMAP, NOMAP, R, + F71805F_SYSCTL_SENSOR1, VALUE(1), 0 }, + { SENSORS_F71805F_TEMP_TYPE(2), "sensor2", NOMAP, NOMAP, R, + F71805F_SYSCTL_SENSOR2, VALUE(1), 0 }, + { SENSORS_F71805F_TEMP_TYPE(3), "sensor3", NOMAP, NOMAP, R, + F71805F_SYSCTL_SENSOR3, VALUE(1), 0 }, +/* 3 alarm bitvectors */ + { SENSORS_F71805F_ALARMS_IN, "alarms_in", NOMAP, NOMAP, R, + F71805F_SYSCTL_ALARMS_IN, VALUE(1), 0 }, + { SENSORS_F71805F_ALARMS_FAN, "alarms_fan", NOMAP, NOMAP, R, + F71805F_SYSCTL_ALARMS_FAN, VALUE(1), 0 }, + { SENSORS_F71805F_ALARMS_TEMP, "alarms_temp", NOMAP, NOMAP, R, + F71805F_SYSCTL_ALARMS_TEMP, VALUE(1), 0 }, + { 0 } +}; + sensors_chip_features sensors_chip_features_list[] = { { SENSORS_LM78_PREFIX, lm78_features }, @@ -5516,5 +5648,6 @@ sensors_chip_features sensors_chip_features_list[] = { SENSORS_ADM1031_PREFIX, adm1031_features }, { SENSORS_LM93_PREFIX, lm93_features }, { SENSORS_SMSC47B397_PREFIX, smsc47b397_features }, + { SENSORS_F71805F_PREFIX, f71805f_features }, { 0 } }; diff --git a/lib/chips.h b/lib/chips.h index 105ab784..f7f67fca 100644 --- a/lib/chips.h +++ b/lib/chips.h @@ -2090,4 +2090,24 @@ #define SENSORS_SMSC47B397_FAN3 0x13 /* R */ #define SENSORS_SMSC47B397_FAN4 0x14 /* R */ +/* Fintek F71805F chip */ +#define SENSORS_F71805F_PREFIX "f71805f" + +/* in n from 0 to 8 */ +#define SENSORS_F71805F_IN(n) (1 + (n)) +#define SENSORS_F71805F_IN_MIN(n) (16 + (n)) +#define SENSORS_F71805F_IN_MAX(n) (31 + (n)) +/* fan n from 1 to 3 */ +#define SENSORS_F71805F_FAN(n) (50 + (n)) +#define SENSORS_F71805F_FAN_MIN(n) (60 + (n)) +/* temp n from 1 to 3 */ +#define SENSORS_F71805F_TEMP(n) (80 + (n)) +#define SENSORS_F71805F_TEMP_MAX(n) (90 + (n)) +#define SENSORS_F71805F_TEMP_HYST(n) (100 + (n)) +#define SENSORS_F71805F_TEMP_TYPE(n) (110 + (n)) +/* alarms */ +#define SENSORS_F71805F_ALARMS_IN 200 +#define SENSORS_F71805F_ALARMS_FAN 201 +#define SENSORS_F71805F_ALARMS_TEMP 202 + #endif /* def LIB_SENSORS_CHIPS_H */ diff --git a/mkpatch/Config.in b/mkpatch/Config.in index d0da63b0..c032216e 100644 --- a/mkpatch/Config.in +++ b/mkpatch/Config.in @@ -20,6 +20,7 @@ if [ "$CONFIG_I2C_PROC" = "m" -o "$CONFIG_I2C_PROC" = "y" ] ; then dep_tristate ' Analog Devices ADM9240 and compatibles' CONFIG_SENSORS_ADM9240 $CONFIG_I2C $CONFIG_I2C_PROC dep_tristate ' Asus ASB100' CONFIG_SENSORS_ASB100 $CONFIG_I2C $CONFIG_I2C_PROC dep_tristate ' Dallas DS1621 and DS1625' CONFIG_SENSORS_DS1621 $CONFIG_I2C $CONFIG_I2C_PROC + dep_tristate ' Fintek F71805F' CONFIG_SENSORS_F71805F $CONFIG_I2C $CONFIG_I2C_PROC dep_tristate ' Fujitsu-Siemens Hermes' CONFIG_SENSORS_FSCHER $CONFIG_I2C $CONFIG_I2C_PROC dep_tristate ' Fujitsu-Siemens Poseidon' CONFIG_SENSORS_FSCPOS $CONFIG_I2C $CONFIG_I2C_PROC dep_tristate ' Fujitsu-Siemens Scylla' CONFIG_SENSORS_FSCSCY $CONFIG_I2C $CONFIG_I2C_PROC diff --git a/mkpatch/FILES b/mkpatch/FILES index 31bc57b7..73fff819 100644 --- a/mkpatch/FILES +++ b/mkpatch/FILES @@ -29,6 +29,7 @@ kernel/chips/bt869.c drivers/sensors/bt869.c kernel/chips/ddcmon.c drivers/sensors/ddcmon.c kernel/chips/ds1621.c drivers/sensors/ds1621.c kernel/chips/eeprom.c drivers/sensors/eeprom.c +kernel/chips/f71805f.c drivers/sensors/f71805f.c kernel/chips/fscher.c drivers/sensors/fscher.c kernel/chips/fscpos.c drivers/sensors/fscpos.c kernel/chips/fscscy.c drivers/sensors/fscscy.c diff --git a/mkpatch/mkpatch.pl b/mkpatch/mkpatch.pl index da9c0465..3a05e054 100755 --- a/mkpatch/mkpatch.pl +++ b/mkpatch/mkpatch.pl @@ -106,6 +106,7 @@ sub gen_Documentation_Configure_help m@Analog Devices ADM9240 and compatibles@ or m@Asus ASB100@ or m@Dallas DS1621 and DS1625@ or + m@Fintek F71805F@ or m@Fujitsu-Siemens Hermes@ or m@Fujitsu-Siemens Poseidon@ or m@Fujitsu-Siemens Scylla@ or @@ -378,6 +379,16 @@ CONFIG_SENSORS_DS1621 in the lm_sensors package, which you can download at http://www.lm-sensors.nu/ +Fintek F71805F +CONFIG_SENSORS_F71805F + If you say yes here you get support for the hardware monitoring + features of the Fintek F71805F/FG Super-I/O chip. This can also be + built as a module. + + You will also need the latest user-space utilities: you can find them + in the lm_sensors package, which you can download at + http://www.lm-sensors.nu/ + Fujitsu-Siemens Hermes CONFIG_SENSORS_FSCHER If you say yes here you get support for the Fujitsu-Siemens Hermes @@ -1016,6 +1027,7 @@ obj-$(CONFIG_SENSORS_BT869) += bt869.o obj-$(CONFIG_SENSORS_DDCMON) += ddcmon.o obj-$(CONFIG_SENSORS_DS1621) += ds1621.o obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o +obj-$(CONFIG_SENSORS_FSCHER) += f71085f.o obj-$(CONFIG_SENSORS_FSCHER) += fscher.o obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o obj-$(CONFIG_SENSORS_FSCSCY) += fscscy.o diff --git a/prog/sensors/chips.c b/prog/sensors/chips.c index c852a09d..c4b30539 100644 --- a/prog/sensors/chips.c +++ b/prog/sensors/chips.c @@ -5768,6 +5768,86 @@ void print_smsc47b397(const sensors_chip_name *name) PRINT_SMSC47B397_FAN(ii, name); } +void print_f71805f(const sensors_chip_name *name) +{ + char *label; + double cur, min, max; + int alarms, valid, i; + + if (!sensors_get_feature(*name, SENSORS_F71805F_ALARMS_IN, &cur)) + alarms = cur + 0.5; + else { + printf("ERROR: Can't get alarms_in data!\n"); + alarms = 0; + } + + for (i = 0; i < 9; i++) { + if (!sensors_get_label_and_valid(*name, SENSORS_F71805F_IN(i), + &label, &valid) + && !sensors_get_feature(*name, SENSORS_F71805F_IN(i), &cur) + && !sensors_get_feature(*name, SENSORS_F71805F_IN_MIN(i), &min) + && !sensors_get_feature(*name, SENSORS_F71805F_IN_MAX(i), &max)) { + if (valid) { + print_label(label, 10); + printf("%+6.2f V (min = %+6.2f V, max = %+6.2f V) %s\n", + cur, min, max, (alarms & (1 << i)) ? "ALARM" : ""); + } + } else + printf("ERROR: Can't get in%d data!\n", i); + free(label); + } + + if (!sensors_get_feature(*name, SENSORS_F71805F_ALARMS_FAN, &cur)) + alarms = cur + 0.5; + else { + printf("ERROR: Can't get alarms_fan data!\n"); + alarms = 0; + } + + for (i = 1; i <= 3; i++) { + if (!sensors_get_label_and_valid(*name, SENSORS_F71805F_FAN(i), + &label, &valid) + && !sensors_get_feature(*name, SENSORS_F71805F_FAN(i), &cur) + && !sensors_get_feature(*name, SENSORS_F71805F_FAN_MIN(i), &min)) { + if (valid) { + print_label(label, 10); + printf("%4.0f RPM (min = %4.0f RPM) %s\n", + cur, min, (alarms & (1 << (i - 1))) ? "ALARM" : ""); + } + } else + printf("ERROR: Can't get fan%d data!\n", i); + free(label); + } + + if (!sensors_get_feature(*name, SENSORS_F71805F_ALARMS_TEMP, &cur)) + alarms = cur + 0.5; + else { + printf("ERROR: Can't get alarms_temp data!\n"); + alarms = 0; + } + + for (i = 1; i <= 3; i++) { + if (!sensors_get_label_and_valid(*name, SENSORS_F71805F_TEMP(i), + &label, &valid) + && !sensors_get_feature(*name, SENSORS_F71805F_TEMP(i), &cur) + && !sensors_get_feature(*name, SENSORS_F71805F_TEMP_MAX(i), &max) + && !sensors_get_feature(*name, SENSORS_F71805F_TEMP_HYST(i), &min)) { + if (valid) { + print_label(label, 10); + print_temp_info(cur, max, min, HYST, 0, 0); + printf("%5s", (alarms & (1 << (i - 1))) ? "ALARM" : ""); + if (!sensors_get_feature(*name, SENSORS_F71805F_TEMP_TYPE(i), &cur)) { + int sensor = cur + 0.5; + printf(" [%s]", sensor == 3 ? "diode" : "thermistor"); + } + printf("\n"); + } + } else + printf("ERROR: Can't get temp%d data!\n", i); + free(label); + } +} + void print_unknown_chip(const sensors_chip_name *name) { int a,b,valid; diff --git a/prog/sensors/chips.h b/prog/sensors/chips.h index cd6fcb43..d1a1fc65 100644 --- a/prog/sensors/chips.h +++ b/prog/sensors/chips.h @@ -70,5 +70,6 @@ extern void print_xeontemp(const sensors_chip_name *name); extern void print_max6650(const sensors_chip_name *name); extern void print_adm1031(const sensors_chip_name *name); extern void print_smsc47b397(const sensors_chip_name *name); +extern void print_f71805f(const sensors_chip_name *name); #endif /* def PROG_SENSORS_CHIPS_H */ diff --git a/prog/sensors/main.c b/prog/sensors/main.c index 777bf4af..1ece756e 100644 --- a/prog/sensors/main.c +++ b/prog/sensors/main.c @@ -412,6 +412,7 @@ struct match matches[] = { { "adm1031", print_adm1031 }, { "lm93", print_lm93 }, { "smsc47b397", print_smsc47b397 }, + { "f71805f", print_f71805f }, { NULL, NULL } };