|
From: <abe...@us...> - 2011-11-26 04:52:30
|
Revision: 5271
http://astlinux.svn.sourceforge.net/astlinux/?rev=5271&view=rev
Author: abelbeck
Date: 2011-11-26 04:52:22 +0000 (Sat, 26 Nov 2011)
Log Message:
-----------
kernel, add f71882fg patch to support newer Fintek chips found in Jetway boards
Added Paths:
-----------
branches/1.0/project/astlinux/kernel-patches/linux-500-hwmon-f71882fg.patch
Added: branches/1.0/project/astlinux/kernel-patches/linux-500-hwmon-f71882fg.patch
===================================================================
--- branches/1.0/project/astlinux/kernel-patches/linux-500-hwmon-f71882fg.patch (rev 0)
+++ branches/1.0/project/astlinux/kernel-patches/linux-500-hwmon-f71882fg.patch 2011-11-26 04:52:22 UTC (rev 5271)
@@ -0,0 +1,1324 @@
+--- a/drivers/hwmon/f71882fg.c 2011-04-28 10:21:24.000000000 -0500
++++ b/drivers/hwmon/f71882fg.c 2011-11-25 20:27:18.000000000 -0600
+@@ -1,6 +1,6 @@
+ /***************************************************************************
+ * Copyright (C) 2006 by Hans Edgington <ha...@ed...> *
+- * Copyright (C) 2007-2009 Hans de Goede <hde...@re...> *
++ * Copyright (C) 2007-2011 Hans de Goede <hde...@re...> *
+ * *
+ * 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 *
+@@ -18,6 +18,8 @@
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/slab.h>
+@@ -28,14 +30,73 @@
+ #include <linux/err.h>
+ #include <linux/mutex.h>
+ #include <linux/io.h>
++#include <linux/version.h>
++
++/*
++ * Compatibility glue
++ */
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
+ #include <linux/acpi.h>
++#else
++static inline int acpi_check_resource_conflict(struct resource *res)
++{
++ return 0;
++}
++#endif
++
++#ifndef request_muxed_region
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 28)
++#define request_muxed_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name))
++#else
++#define IORESOURCE_MUXED 0x00400000
++#define request_muxed_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), IORESOURCE_MUXED)
++#endif
++#endif
++
++#ifndef pr_warning
++#define pr_warning(fmt,arg...) \
++ printk(KERN_WARNING fmt,##arg)
++#endif
++
++#ifndef pr_err
++#define pr_err(fmt,arg...) \
++ printk(KERN_ERR fmt,##arg)
++#endif
++
++#ifndef pr_warn
++#define pr_warn pr_warning
++#endif
++
++/* Red Hat EL5 includes backports of these functions, so we can't redefine
++ * our own. */
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
++#if !(defined RHEL_MAJOR && RHEL_MAJOR == 5 && RHEL_MINOR >= 5)
++static inline int strict_strtoul(const char *cp, unsigned int base,
++ unsigned long *res)
++{
++ *res = simple_strtoul(cp, NULL, base);
++ return 0;
++}
++
++static inline int strict_strtol(const char *cp, unsigned int base, long *res)
++{
++ *res = simple_strtol(cp, NULL, base);
++ return 0;
++}
++#endif
++#endif
++
++/*
++ * End of compatibility glue
++ */
+
+ #define DRVNAME "f71882fg"
+
+ #define SIO_F71858FG_LD_HWM 0x02 /* Hardware monitor logical device */
+ #define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device */
+ #define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
+-#define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */
++#define SIO_LOCK_KEY 0xAA /* Key to disable Super-I/O */
+
+ #define SIO_REG_LDSEL 0x07 /* Logical device select */
+ #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
+@@ -45,22 +106,27 @@
+ #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
+
+ #define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
++#define SIO_F71808E_ID 0x0901 /* Chipset ID */
++#define SIO_F71808A_ID 0x1001 /* Chipset ID */
+ #define SIO_F71858_ID 0x0507 /* Chipset ID */
+ #define SIO_F71862_ID 0x0601 /* Chipset ID */
++#define SIO_F71869_ID 0x0814 /* Chipset ID */
++#define SIO_F71869A_ID 0x1007 /* Chipset ID */
+ #define SIO_F71882_ID 0x0541 /* Chipset ID */
+ #define SIO_F71889_ID 0x0723 /* Chipset ID */
++#define SIO_F71889E_ID 0x0909 /* Chipset ID */
++#define SIO_F71889A_ID 0x1005 /* Chipset ID */
+ #define SIO_F8000_ID 0x0581 /* Chipset ID */
++#define SIO_F81865_ID 0x0704 /* Chipset ID */
+
+ #define REGION_LENGTH 8
+ #define ADDR_REG_OFFSET 5
+ #define DATA_REG_OFFSET 6
+
+-#define F71882FG_REG_PECI 0x0A
+-
+-#define F71882FG_REG_IN_STATUS 0x12 /* f71882fg only */
+-#define F71882FG_REG_IN_BEEP 0x13 /* f71882fg only */
++#define F71882FG_REG_IN_STATUS 0x12 /* f7188x only */
++#define F71882FG_REG_IN_BEEP 0x13 /* f7188x only */
+ #define F71882FG_REG_IN(nr) (0x20 + (nr))
+-#define F71882FG_REG_IN1_HIGH 0x32 /* f71882fg only */
++#define F71882FG_REG_IN1_HIGH 0x32 /* f7188x only */
+
+ #define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
+ #define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
+@@ -84,26 +150,130 @@
+
+ #define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr))
+
++#define F71882FG_REG_FAN_FAULT_T 0x9F
++#define F71882FG_FAN_NEG_TEMP_EN 0x20
++#define F71882FG_FAN_PROG_SEL 0x80
++
+ #define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm)))
+ #define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm)))
+ #define F71882FG_REG_POINT_MAPPING(nr) (0xAF + 16 * (nr))
+
+ #define F71882FG_REG_START 0x01
+
++#define F71882FG_MAX_INS 9
++
+ #define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
+
+ static unsigned short force_id;
+ module_param(force_id, ushort, 0);
+ MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+-enum chips { f71858fg, f71862fg, f71882fg, f71889fg, f8000 };
++enum chips { f71808e, f71808a, f71858fg, f71862fg, f71869, f71869a, f71882fg,
++ f71889fg, f71889ed, f71889a, f8000, f81865f };
+
+ static const char *f71882fg_names[] = {
++ "f71808e",
++ "f71808a",
+ "f71858fg",
+ "f71862fg",
++ "f71869", /* Both f71869f and f71869e, reg. compatible and same id */
++ "f71869a",
+ "f71882fg",
+- "f71889fg",
++ "f71889fg", /* f81801u too, same id */
++ "f71889ed",
++ "f71889a",
+ "f8000",
++ "f81865f",
++};
++
++static const char f71882fg_has_in[][F71882FG_MAX_INS] = {
++ [f71808e] = { 1, 1, 1, 1, 1, 1, 0, 1, 1 },
++ [f71808a] = { 1, 1, 1, 1, 0, 0, 0, 1, 1 },
++ [f71858fg] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 },
++ [f71862fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
++ [f71869] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
++ [f71869a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
++ [f71882fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
++ [f71889fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
++ [f71889ed] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
++ [f71889a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
++ [f8000] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 },
++ [f81865f] = { 1, 1, 1, 1, 1, 1, 1, 0, 0 },
++};
++
++static const char f71882fg_has_in1_alarm[] = {
++ [f71808e] = 0,
++ [f71808a] = 0,
++ [f71858fg] = 0,
++ [f71862fg] = 0,
++ [f71869] = 0,
++ [f71869a] = 0,
++ [f71882fg] = 1,
++ [f71889fg] = 1,
++ [f71889ed] = 1,
++ [f71889a] = 1,
++ [f8000] = 0,
++ [f81865f] = 1,
++};
++
++static const char f71882fg_fan_has_beep[] = {
++ [f71808e] = 0,
++ [f71808a] = 0,
++ [f71858fg] = 0,
++ [f71862fg] = 1,
++ [f71869] = 1,
++ [f71869a] = 1,
++ [f71882fg] = 1,
++ [f71889fg] = 1,
++ [f71889ed] = 1,
++ [f71889a] = 1,
++ [f8000] = 0,
++ [f81865f] = 1,
++};
++
++static const char f71882fg_nr_fans[] = {
++ [f71808e] = 3,
++ [f71808a] = 2, /* +1 fan which is monitor + simple pwm only */
++ [f71858fg] = 3,
++ [f71862fg] = 3,
++ [f71869] = 3,
++ [f71869a] = 3,
++ [f71882fg] = 4,
++ [f71889fg] = 3,
++ [f71889ed] = 3,
++ [f71889a] = 3,
++ [f8000] = 3, /* +1 fan which is monitor only */
++ [f81865f] = 2,
++};
++
++static const char f71882fg_temp_has_beep[] = {
++ [f71808e] = 0,
++ [f71808a] = 1,
++ [f71858fg] = 0,
++ [f71862fg] = 1,
++ [f71869] = 1,
++ [f71869a] = 1,
++ [f71882fg] = 1,
++ [f71889fg] = 1,
++ [f71889ed] = 1,
++ [f71889a] = 1,
++ [f8000] = 0,
++ [f81865f] = 1,
++};
++
++static const char f71882fg_nr_temps[] = {
++ [f71808e] = 2,
++ [f71808a] = 2,
++ [f71858fg] = 3,
++ [f71862fg] = 3,
++ [f71869] = 3,
++ [f71869a] = 3,
++ [f71882fg] = 3,
++ [f71889fg] = 3,
++ [f71889ed] = 3,
++ [f71889a] = 3,
++ [f8000] = 3,
++ [f81865f] = 2,
+ };
+
+ static struct platform_device *f71882fg_pdev;
+@@ -111,7 +281,7 @@
+ /* Super-I/O Function prototypes */
+ static inline int superio_inb(int base, int reg);
+ static inline int superio_inw(int base, int reg);
+-static inline void superio_enter(int base);
++static inline int superio_enter(int base);
+ static inline void superio_select(int base, int ld);
+ static inline void superio_exit(int base);
+
+@@ -122,16 +292,21 @@
+ struct f71882fg_data {
+ unsigned short addr;
+ enum chips type;
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
++ struct class_device *hwmon_dev;
++#else
+ struct device *hwmon_dev;
++#endif
+
+ struct mutex update_lock;
+ int temp_start; /* temp numbering start (0 or 1) */
+ char valid; /* !=0 if following fields are valid */
++ char auto_point_temp_signed;
+ unsigned long last_updated; /* In jiffies */
+ unsigned long last_limits; /* In jiffies */
+
+ /* Register Values */
+- u8 in[9];
++ u8 in[F71882FG_MAX_INS];
+ u8 in1_max;
+ u8 in_status;
+ u8 in_beep;
+@@ -140,7 +315,7 @@
+ u16 fan_full_speed[4];
+ u8 fan_status;
+ u8 fan_beep;
+- /* Note: all models have only 3 temperature channels, but on some
++ /* Note: all models have max 3 temperature channels, but on some
+ they are addressed as 0-2 and on others as 1-3, so for coding
+ convenience we reserve space for 4 channels */
+ u16 temp[4];
+@@ -218,6 +393,10 @@
+ char *buf);
+ static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count);
++static ssize_t show_simple_pwm(struct device *dev,
++ struct device_attribute *devattr, char *buf);
++static ssize_t store_simple_pwm(struct device *dev,
++ struct device_attribute *devattr, const char *buf, size_t count);
+ static ssize_t show_pwm_enable(struct device *dev,
+ struct device_attribute *devattr, char *buf);
+ static ssize_t store_pwm_enable(struct device *dev,
+@@ -260,13 +439,9 @@
+
+ static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+-/* Temp and in attr for the f71858fg, the f71858fg is special as it
+- has its temperature indexes start at 0 (the others start at 1) and
+- it only has 3 voltage inputs */
+-static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = {
+- SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
+- SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
+- SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
++/* Temp attr for the f71858fg, the f71858fg is special as it has its
++ temperature indexes start at 0 (the others start at 1) */
++static struct sensor_device_attribute_2 f71858fg_temp_attr[] = {
+ SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
+ SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
+ store_temp_max, 0, 0),
+@@ -290,7 +465,6 @@
+ SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+ 0, 1),
+ SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
+- SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
+ SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
+ SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
+ SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
+@@ -306,17 +480,8 @@
+ SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
+ };
+
+-/* Temp and in attr common to the f71862fg, f71882fg and f71889fg */
+-static struct sensor_device_attribute_2 fxxxx_in_temp_attr[] = {
+- SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
+- SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
+- SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
+- SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
+- SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
+- SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
+- SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
+- SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
+- SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
++/* Temp attr for the standard models */
++static struct sensor_device_attribute_2 fxxxx_temp_attr[3][9] = { {
+ SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
+ SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
+ store_temp_max, 0, 1),
+@@ -326,17 +491,14 @@
+ the max and crit alarms separately and lm_sensors v2 depends on the
+ presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
+ SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
+- SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+- store_temp_beep, 0, 1),
+ SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+ store_temp_crit, 0, 1),
+ SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+ 0, 1),
+ SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
+- SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+- store_temp_beep, 0, 5),
+ SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
+ SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
++}, {
+ SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
+ SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
+ store_temp_max, 0, 2),
+@@ -344,17 +506,14 @@
+ store_temp_max_hyst, 0, 2),
+ /* Should be temp2_max_alarm, see temp1_alarm note */
+ SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
+- SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+- store_temp_beep, 0, 2),
+ SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+ store_temp_crit, 0, 2),
+ SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+ 0, 2),
+ SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
+- SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+- store_temp_beep, 0, 6),
+ SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
+ SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
++}, {
+ SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
+ SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
+ store_temp_max, 0, 3),
+@@ -362,37 +521,39 @@
+ store_temp_max_hyst, 0, 3),
+ /* Should be temp3_max_alarm, see temp1_alarm note */
+ SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
+- SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+- store_temp_beep, 0, 3),
+ SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+ store_temp_crit, 0, 3),
+ SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+ 0, 3),
+ SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
+- SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+- store_temp_beep, 0, 7),
+ SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
+ SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
+-};
++} };
+
+-/* For models with in1 alarm capability */
+-static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
+- SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
+- 0, 1),
+- SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
+- 0, 1),
+- SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
+-};
++/* Temp attr for models which can beep on temp alarm */
++static struct sensor_device_attribute_2 fxxxx_temp_beep_attr[3][2] = { {
++ SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
++ store_temp_beep, 0, 1),
++ SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
++ store_temp_beep, 0, 5),
++}, {
++ SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
++ store_temp_beep, 0, 2),
++ SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
++ store_temp_beep, 0, 6),
++}, {
++ SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
++ store_temp_beep, 0, 3),
++ SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
++ store_temp_beep, 0, 7),
++} };
+
+-/* Temp and in attr for the f8000
++/* Temp attr for the f8000
+ Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
+ is used as hysteresis value to clear alarms
+ Also like the f71858fg its temperature indexes start at 0
+ */
+-static struct sensor_device_attribute_2 f8000_in_temp_attr[] = {
+- SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
+- SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
+- SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
++static struct sensor_device_attribute_2 f8000_temp_attr[] = {
+ SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
+ SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
+ store_temp_crit, 0, 0),
+@@ -406,7 +567,6 @@
+ SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
+ store_temp_max, 0, 1),
+ SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
+- SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
+ SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
+ SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
+ SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
+@@ -417,6 +577,28 @@
+ SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
+ };
+
++/* in attr for all models */
++static struct sensor_device_attribute_2 fxxxx_in_attr[] = {
++ SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
++ SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
++ SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
++ SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
++ SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
++ SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
++ SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
++ SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
++ SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
++};
++
++/* For models with in1 alarm capability */
++static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
++ SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
++ 0, 1),
++ SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
++ 0, 1),
++ SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
++};
++
+ /* Fan / PWM attr common to all models */
+ static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
+ SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
+@@ -464,6 +646,14 @@
+ show_pwm_interpolate, store_pwm_interpolate, 0, 3),
+ } };
+
++/* Attr for the third fan of the f71808a, which only has manual pwm */
++static struct sensor_device_attribute_2 f71808a_fan3_attr[] = {
++ SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
++ SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
++ SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR,
++ show_simple_pwm, store_simple_pwm, 0, 2),
++};
++
+ /* Attr for models which can beep on Fan alarm */
+ static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
+ SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+@@ -477,7 +667,7 @@
+ };
+
+ /* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
+- f71858fg / f71882fg / f71889fg */
++ standard models */
+ static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
+ SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_channel,
+@@ -546,7 +736,87 @@
+ show_pwm_auto_point_temp_hyst, NULL, 3, 2),
+ };
+
+-/* PWM attr common to the f71858fg, f71882fg and f71889fg */
++/* PWM attr for the f71808e/f71869, almost identical to the f71862fg, but the
++ pwm setting when the temperature is above the pwmX_auto_point1_temp can be
++ programmed instead of being hardcoded to 0xff */
++static struct sensor_device_attribute_2 f71869_auto_pwm_attr[] = {
++ SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_channel,
++ store_pwm_auto_point_channel, 0, 0),
++ SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
++ 0, 0),
++ SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
++ 1, 0),
++ SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
++ 4, 0),
++ SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
++ 0, 0),
++ SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
++ 3, 0),
++ SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_temp_hyst,
++ store_pwm_auto_point_temp_hyst,
++ 0, 0),
++ SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
++ show_pwm_auto_point_temp_hyst, NULL, 3, 0),
++
++ SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_channel,
++ store_pwm_auto_point_channel, 0, 1),
++ SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
++ 0, 1),
++ SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
++ 1, 1),
++ SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
++ 4, 1),
++ SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
++ 0, 1),
++ SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
++ 3, 1),
++ SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_temp_hyst,
++ store_pwm_auto_point_temp_hyst,
++ 0, 1),
++ SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
++ show_pwm_auto_point_temp_hyst, NULL, 3, 1),
++
++ SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_channel,
++ store_pwm_auto_point_channel, 0, 2),
++ SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
++ 0, 2),
++ SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
++ 1, 2),
++ SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
++ 4, 2),
++ SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
++ 0, 2),
++ SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
++ 3, 2),
++ SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
++ show_pwm_auto_point_temp_hyst,
++ store_pwm_auto_point_temp_hyst,
++ 0, 2),
++ SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
++ show_pwm_auto_point_temp_hyst, NULL, 3, 2),
++};
++
++/* PWM attr for the standard models */
+ static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
+ SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_channel,
+@@ -861,11 +1131,19 @@
+ return val;
+ }
+
+-static inline void superio_enter(int base)
++static inline int superio_enter(int base)
+ {
++ /* Don't step on other drivers' I/O space by accident */
++ if (!request_muxed_region(base, 2, DRVNAME)) {
++ pr_err("I/O address 0x%04x already in use\n", base);
++ return -EBUSY;
++ }
++
+ /* according to the datasheet the key must be send twice! */
+ outb(SIO_UNLOCK_KEY, base);
+ outb(SIO_UNLOCK_KEY, base);
++
++ return 0;
+ }
+
+ static inline void superio_select(int base, int ld)
+@@ -877,6 +1155,7 @@
+ static inline void superio_exit(int base)
+ {
+ outb(SIO_LOCK_KEY, base);
++ release_region(base, 2);
+ }
+
+ static inline int fan_from_reg(u16 reg)
+@@ -932,16 +1211,16 @@
+ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
+ {
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+- int nr, reg = 0, reg2;
+- int nr_fans = (data->type == f71882fg) ? 4 : 3;
+- int nr_ins = (data->type == f71858fg || data->type == f8000) ? 3 : 9;
++ int nr_fans = f71882fg_nr_fans[data->type];
++ int nr_temps = f71882fg_nr_temps[data->type];
++ int nr, reg, point;
+
+ mutex_lock(&data->update_lock);
+
+ /* Update once every 60 seconds */
+ if (time_after(jiffies, data->last_limits + 60 * HZ) ||
+ !data->valid) {
+- if (data->type == f71882fg || data->type == f71889fg) {
++ if (f71882fg_has_in1_alarm[data->type]) {
+ data->in1_max =
+ f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
+ data->in_beep =
+@@ -949,7 +1228,8 @@
+ }
+
+ /* Get High & boundary temps*/
+- for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) {
++ for (nr = data->temp_start; nr < nr_temps + data->temp_start;
++ nr++) {
+ data->temp_ovt[nr] = f71882fg_read8(data,
+ F71882FG_REG_TEMP_OVT(nr));
+ data->temp_high[nr] = f71882fg_read8(data,
+@@ -962,45 +1242,21 @@
+ data->temp_hyst[1] = f71882fg_read8(data,
+ F71882FG_REG_TEMP_HYST(1));
+ }
++ /* All but the f71858fg / f8000 have this register */
++ if ((data->type != f71858fg) && (data->type != f8000)) {
++ reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
++ data->temp_type[1] = (reg & 0x02) ? 2 : 4;
++ data->temp_type[2] = (reg & 0x04) ? 2 : 4;
++ data->temp_type[3] = (reg & 0x08) ? 2 : 4;
++ }
+
+- if (data->type == f71862fg || data->type == f71882fg ||
+- data->type == f71889fg) {
++ if (f71882fg_fan_has_beep[data->type])
+ data->fan_beep = f71882fg_read8(data,
+ F71882FG_REG_FAN_BEEP);
++
++ if (f71882fg_temp_has_beep[data->type])
+ data->temp_beep = f71882fg_read8(data,
+ F71882FG_REG_TEMP_BEEP);
+- /* Have to hardcode type, because temp1 is special */
+- reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
+- data->temp_type[2] = (reg & 0x04) ? 2 : 4;
+- data->temp_type[3] = (reg & 0x08) ? 2 : 4;
+- }
+- /* Determine temp index 1 sensor type */
+- if (data->type == f71889fg) {
+- reg2 = f71882fg_read8(data, F71882FG_REG_START);
+- switch ((reg2 & 0x60) >> 5) {
+- case 0x00: /* BJT / Thermistor */
+- data->temp_type[1] = (reg & 0x02) ? 2 : 4;
+- break;
+- case 0x01: /* AMDSI */
+- data->temp_type[1] = 5;
+- break;
+- case 0x02: /* PECI */
+- case 0x03: /* Ibex Peak ?? Report as PECI for now */
+- data->temp_type[1] = 6;
+- break;
+- }
+- } else {
+- reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
+- if ((reg2 & 0x03) == 0x01)
+- data->temp_type[1] = 6; /* PECI */
+- else if ((reg2 & 0x03) == 0x02)
+- data->temp_type[1] = 5; /* AMDSI */
+- else if (data->type == f71862fg ||
+- data->type == f71882fg)
+- data->temp_type[1] = (reg & 0x02) ? 2 : 4;
+- else /* f71858fg and f8000 only support BJT */
+- data->temp_type[1] = 2;
+- }
+
+ data->pwm_enable = f71882fg_read8(data,
+ F71882FG_REG_PWM_ENABLE);
+@@ -1014,8 +1270,8 @@
+ f71882fg_read8(data,
+ F71882FG_REG_POINT_MAPPING(nr));
+
+- if (data->type != f71862fg) {
+- int point;
++ switch (data->type) {
++ default:
+ for (point = 0; point < 5; point++) {
+ data->pwm_auto_point_pwm[nr][point] =
+ f71882fg_read8(data,
+@@ -1028,7 +1284,14 @@
+ F71882FG_REG_POINT_TEMP
+ (nr, point));
+ }
+- } else {
++ break;
++ case f71808e:
++ case f71869:
++ data->pwm_auto_point_pwm[nr][0] =
++ f71882fg_read8(data,
++ F71882FG_REG_POINT_PWM(nr, 0));
++ /* Fall through */
++ case f71862fg:
+ data->pwm_auto_point_pwm[nr][1] =
+ f71882fg_read8(data,
+ F71882FG_REG_POINT_PWM
+@@ -1045,6 +1308,7 @@
+ f71882fg_read8(data,
+ F71882FG_REG_POINT_TEMP
+ (nr, 3));
++ break;
+ }
+ }
+ data->last_limits = jiffies;
+@@ -1056,7 +1320,8 @@
+ F71882FG_REG_TEMP_STATUS);
+ data->temp_diode_open = f71882fg_read8(data,
+ F71882FG_REG_TEMP_DIODE_OPEN);
+- for (nr = data->temp_start; nr < 3 + data->temp_start; nr++)
++ for (nr = data->temp_start; nr < nr_temps + data->temp_start;
++ nr++)
+ data->temp[nr] = f71882fg_read_temp(data, nr);
+
+ data->fan_status = f71882fg_read8(data,
+@@ -1072,17 +1337,24 @@
+ data->pwm[nr] =
+ f71882fg_read8(data, F71882FG_REG_PWM(nr));
+ }
+-
+- /* The f8000 can monitor 1 more fan, but has no pwm for it */
++ /* Some models have 1 more fan with limited capabilities */
++ if (data->type == f71808a) {
++ data->fan[2] = f71882fg_read16(data,
++ F71882FG_REG_FAN(2));
++ data->pwm[2] = f71882fg_read8(data,
++ F71882FG_REG_PWM(2));
++ }
+ if (data->type == f8000)
+ data->fan[3] = f71882fg_read16(data,
+ F71882FG_REG_FAN(3));
+- if (data->type == f71882fg || data->type == f71889fg)
++
++ if (f71882fg_has_in1_alarm[data->type])
+ data->in_status = f71882fg_read8(data,
+ F71882FG_REG_IN_STATUS);
+- for (nr = 0; nr < nr_ins; nr++)
+- data->in[nr] = f71882fg_read8(data,
+- F71882FG_REG_IN(nr));
++ for (nr = 0; nr < F71882FG_MAX_INS; nr++)
++ if (f71882fg_has_in[data->type][nr])
++ data->in[nr] = f71882fg_read8(data,
++ F71882FG_REG_IN(nr));
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+@@ -1561,6 +1833,38 @@
+ return count;
+ }
+
++static ssize_t show_simple_pwm(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ struct f71882fg_data *data = f71882fg_update_device(dev);
++ int val, nr = to_sensor_dev_attr_2(devattr)->index;
++
++ val = data->pwm[nr];
++ return sprintf(buf, "%d\n", val);
++}
++
++static ssize_t store_simple_pwm(struct device *dev,
++ struct device_attribute *devatt...
[truncated message content] |