Discussion:
[lm-sensors] [PATCH v3 20/25] hwmon: (it87) Formatting cleanup
Guenter Roeck
2016-01-27 02:03:44 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

Fix various checkpatch complaints to clean up the code and
make it easier to read.

CHECK: Do not include the paragraph about writing to the FSF
CHECK: Alignment should match open parenthesis
CHECK: Logical continuations should be on the previous line
CHECK: No space is necessary after a cast
CHECK: Please don't use multiple blank lines
CHECK: Please use a blank line after function/struct/union/enum
declarations
CHECK: spaces preferred around that '+' (ctx:VxV)
WARNING: Missing a blank line after declarations

No functional change.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 155 ++++++++++++++++++++++++++-------------------------
1 file changed, 80 insertions(+), 75 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 118d4c756e40..515c5cd1890b 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -44,10 +44,6 @@
* 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.
*/

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -108,6 +104,7 @@ static inline void superio_outb(int ioreg, int reg, int val)
static int superio_inw(int ioreg, int reg)
{
int val;
+
outb(reg++, ioreg);
val = inb(ioreg + 1) << 8;
outb(reg, ioreg);
@@ -598,10 +595,10 @@ static int pwm_from_reg(const struct it87_data *data, u8 reg)
return (reg & 0x7f) << 1;
}

-
static int DIV_TO_REG(int val)
{
int answer = 0;
+
while (answer < 7 && (val >>= 1))
answer++;
return answer;
@@ -686,8 +683,8 @@ static struct it87_data *it87_update_device(struct device *dev)

mutex_lock(&data->update_lock);

- if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
- || !data->valid) {
+ if (time_after(jiffies, data->last_updated + HZ + HZ / 2) ||
+ !data->valid) {
if (update_vbat) {
/*
* Cleared after each update, so reenable. Value
@@ -798,10 +795,10 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
- int nr = sattr->nr;
+ struct it87_data *data = it87_update_device(dev);
int index = sattr->index;
+ int nr = sattr->nr;

- struct it87_data *data = it87_update_device(dev);
return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in[nr][index]));
}

@@ -809,10 +806,9 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
- int nr = sattr->nr;
- int index = sattr->index;
-
struct it87_data *data = dev_get_drvdata(dev);
+ int index = sattr->index;
+ int nr = sattr->nr;
unsigned long val;

if (kstrtoul(buf, 10, &val) < 0)
@@ -968,8 +964,8 @@ static ssize_t show_temp_type(struct device *dev, struct device_attribute *attr,
u8 reg = data->sensor; /* In case value is updated while used */
u8 extra = data->extra;

- if ((has_temp_peci(data, nr) && (reg >> 6 == nr + 1))
- || (has_temp_old_peci(data, nr) && (extra & 0x80)))
+ if ((has_temp_peci(data, nr) && (reg >> 6 == nr + 1)) ||
+ (has_temp_old_peci(data, nr) && (extra & 0x80)))
return sprintf(buf, "6\n"); /* Intel PECI */
if (reg & (1 << nr))
return sprintf(buf, "3\n"); /* thermal diode */
@@ -1065,35 +1061,38 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
}

static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ struct it87_data *data = it87_update_device(dev);
int nr = sensor_attr->index;

- struct it87_data *data = it87_update_device(dev);
return sprintf(buf, "%lu\n", DIV_FROM_REG(data->fan_div[nr]));
}
+
static ssize_t show_pwm_enable(struct device *dev,
- struct device_attribute *attr, char *buf)
+ struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ struct it87_data *data = it87_update_device(dev);
int nr = sensor_attr->index;

- struct it87_data *data = it87_update_device(dev);
return sprintf(buf, "%d\n", pwm_mode(data, nr));
}
+
static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ struct it87_data *data = it87_update_device(dev);
int nr = sensor_attr->index;

- struct it87_data *data = it87_update_device(dev);
return sprintf(buf, "%d\n",
pwm_from_reg(data, data->pwm_duty[nr]));
}
+
static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
struct it87_data *data = it87_update_device(dev);
@@ -1157,12 +1156,11 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
}

static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+ const char *buf, size_t count)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
- int nr = sensor_attr->index;
-
struct it87_data *data = dev_get_drvdata(dev);
+ int nr = sensor_attr->index;
unsigned long val;
int min;
u8 old;
@@ -1227,13 +1225,12 @@ static int check_trip_points(struct device *dev, int nr)
return err;
}

-static ssize_t set_pwm_enable(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
- int nr = sensor_attr->index;
-
struct it87_data *data = dev_get_drvdata(dev);
+ int nr = sensor_attr->index;
long val;

if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 2)
@@ -1280,13 +1277,13 @@ static ssize_t set_pwm_enable(struct device *dev,
mutex_unlock(&data->update_lock);
return count;
}
+
static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+ const char *buf, size_t count)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
- int nr = sensor_attr->index;
-
struct it87_data *data = dev_get_drvdata(dev);
+ int nr = sensor_attr->index;
long val;

if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 255)
@@ -1320,8 +1317,9 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t set_pwm_freq(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+
+static ssize_t set_pwm_freq(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
struct it87_data *data = dev_get_drvdata(dev);
@@ -1337,7 +1335,7 @@ static ssize_t set_pwm_freq(struct device *dev,

/* Search for the nearest available frequency */
for (i = 0; i < 7; i++) {
- if (val > (pwm_freq[i] + pwm_freq[i+1]) / 2)
+ if (val > (pwm_freq[i] + pwm_freq[i + 1]) / 2)
break;
}

@@ -1355,13 +1353,13 @@ static ssize_t set_pwm_freq(struct device *dev,

return count;
}
+
static ssize_t show_pwm_temp_map(struct device *dev,
- struct device_attribute *attr, char *buf)
+ struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
- int nr = sensor_attr->index;
-
struct it87_data *data = it87_update_device(dev);
+ int nr = sensor_attr->index;
int map;

if (data->pwm_temp_map[nr] < 3)
@@ -1370,13 +1368,14 @@ static ssize_t show_pwm_temp_map(struct device *dev,
map = 0; /* Should never happen */
return sprintf(buf, "%d\n", map);
}
+
static ssize_t set_pwm_temp_map(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+ struct device_attribute *attr, const char *buf,
+ size_t count)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
- int nr = sensor_attr->index;
-
struct it87_data *data = dev_get_drvdata(dev);
+ int nr = sensor_attr->index;
long val;
u8 reg;

@@ -1411,8 +1410,8 @@ static ssize_t set_pwm_temp_map(struct device *dev,
return count;
}

-static ssize_t show_auto_pwm(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t show_auto_pwm(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct it87_data *data = it87_update_device(dev);
struct sensor_device_attribute_2 *sensor_attr =
@@ -1424,8 +1423,8 @@ static ssize_t show_auto_pwm(struct device *dev,
pwm_from_reg(data, data->auto_pwm[nr][point]));
}

-static ssize_t set_auto_pwm(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t set_auto_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct it87_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute_2 *sensor_attr =
@@ -1445,8 +1444,8 @@ static ssize_t set_auto_pwm(struct device *dev,
return count;
}

-static ssize_t show_auto_temp(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t show_auto_temp(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct it87_data *data = it87_update_device(dev);
struct sensor_device_attribute_2 *sensor_attr =
@@ -1457,8 +1456,8 @@ static ssize_t show_auto_temp(struct device *dev,
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->auto_temp[nr][point]));
}

-static ssize_t set_auto_temp(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t set_auto_temp(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct it87_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute_2 *sensor_attr =
@@ -1607,27 +1606,30 @@ static SENSOR_DEVICE_ATTR(pwm6_auto_channels_temp, S_IRUGO,

/* Alarms */
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
struct it87_data *data = it87_update_device(dev);
+
return sprintf(buf, "%u\n", data->alarms);
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);

static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
- int bitnr = to_sensor_dev_attr(attr)->index;
struct it87_data *data = it87_update_device(dev);
+ int bitnr = to_sensor_dev_attr(attr)->index;
+
return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
}

-static ssize_t clear_intrusion(struct device *dev, struct device_attribute
- *attr, const char *buf, size_t count)
+static ssize_t clear_intrusion(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
{
struct it87_data *data = dev_get_drvdata(dev);
- long val;
int config;
+ long val;

if (kstrtol(buf, 10, &val) < 0 || val != 0)
return -EINVAL;
@@ -1668,21 +1670,22 @@ static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IRUGO | S_IWUSR,
show_alarm, clear_intrusion, 4);

static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
- int bitnr = to_sensor_dev_attr(attr)->index;
struct it87_data *data = it87_update_device(dev);
+ int bitnr = to_sensor_dev_attr(attr)->index;
+
return sprintf(buf, "%u\n", (data->beeps >> bitnr) & 1);
}
+
static ssize_t set_beep(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+ const char *buf, size_t count)
{
int bitnr = to_sensor_dev_attr(attr)->index;
struct it87_data *data = dev_get_drvdata(dev);
long val;

- if (kstrtol(buf, 10, &val) < 0
- || (val != 0 && val != 1))
+ if (kstrtol(buf, 10, &val) < 0 || (val != 0 && val != 1))
return -EINVAL;

mutex_lock(&data->update_lock);
@@ -1718,13 +1721,15 @@ static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO, show_beep, NULL, 2);
static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO, show_beep, NULL, 2);

static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
struct it87_data *data = dev_get_drvdata(dev);
+
return sprintf(buf, "%u\n", data->vrm);
}
+
static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+ const char *buf, size_t count)
{
struct it87_data *data = dev_get_drvdata(dev);
unsigned long val;
@@ -1739,15 +1744,16 @@ static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);

static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
struct it87_data *data = it87_update_device(dev);
- return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
+
+ return sprintf(buf, "%ld\n", (long)vid_from_reg(data->vid, data->vrm));
}
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);

static ssize_t show_label(struct device *dev, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
static const char * const labels[] = {
"+5V",
@@ -2272,8 +2278,8 @@ static int __init it87_find(int sioaddr, unsigned short *address,
/* Check if fan3 is there or not */
if ((reg27 & BIT(0)) || !(reg2c & BIT(2)))
sio_data->skip_fan |= BIT(2);
- if ((reg25 & BIT(4))
- || (!(reg2a & BIT(1)) && (regef & BIT(0))))
+ if ((reg25 & BIT(4)) ||
+ (!(reg2a & BIT(1)) && (regef & BIT(0))))
sio_data->skip_pwm |= BIT(2);

/* Check if fan2 is there or not */
@@ -2421,8 +2427,8 @@ static int __init it87_find(int sioaddr, unsigned short *address,
if (reg & BIT(2))
sio_data->skip_fan |= BIT(1);

- if ((sio_data->type == it8718 || sio_data->type == it8720)
- && !(sio_data->skip_vid))
+ if ((sio_data->type == it8718 || sio_data->type == it8720) &&
+ !(sio_data->skip_vid))
sio_data->vid_value = superio_inb(sioaddr,
IT87_SIO_VID_REG);

@@ -2478,8 +2484,8 @@ static int __init it87_find(int sioaddr, unsigned short *address,
board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
board_name = dmi_get_system_info(DMI_BOARD_NAME);
if (board_vendor && board_name) {
- if (strcmp(board_vendor, "nVIDIA") == 0
- && strcmp(board_name, "FN68PT") == 0) {
+ if (strcmp(board_vendor, "nVIDIA") == 0 &&
+ strcmp(board_name, "FN68PT") == 0) {
/*
* On the Shuttle SN68PT, FAN_CTL2 is apparently not
* connected to a fan, but to something else. One user
@@ -2718,8 +2724,8 @@ static int it87_probe(struct platform_device *pdev)
}

/* Now, we do the remaining detection. */
- if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80)
- || it87_read_value(data, IT87_REG_CHIPID) != 0x90)
+ if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80) ||
+ it87_read_value(data, IT87_REG_CHIPID) != 0x90)
return -ENODEV;

platform_set_drvdata(pdev, data);
@@ -2749,8 +2755,8 @@ static int it87_probe(struct platform_device *pdev)

data->has_temp = 0x07;
if (sio_data->skip_temp & BIT(2)) {
- if (sio_data->type == it8782
- && !(it87_read_value(data, IT87_REG_TEMP_EXTRA) & 0x80))
+ if (sio_data->type == it8782 &&
+ !(it87_read_value(data, IT87_REG_TEMP_EXTRA) & 0x80))
data->has_temp &= ~BIT(2);
}

@@ -2911,7 +2917,6 @@ static void __exit sm_it87_exit(void)
platform_driver_unregister(&it87_driver);
}

-
MODULE_AUTHOR("Chris Gauthron, Jean Delvare <***@suse.de>");
MODULE_DESCRIPTION("IT8705F/IT871xF/IT872xF hardware monitoring driver");
module_param(update_vbat, bool, 0);
--
2.1.4
Guenter Roeck
2016-01-27 02:03:43 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

Using array size defines makes it much easier to find errors
in index values and loop counts.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 58 ++++++++++++++++++++++++++++++----------------------
1 file changed, 34 insertions(+), 24 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 0d6d106d53a2..118d4c756e40 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -260,6 +260,16 @@ static const u8 IT87_REG_VIN[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,

#define IT87_REG_TEMP456_ENABLE 0x77

+#define NUM_VIN ARRAY_SIZE(IT87_REG_VIN)
+#define NUM_VIN_LIMIT 8
+#define NUM_TEMP 6
+#define NUM_TEMP_OFFSET ARRAY_SIZE(IT87_REG_TEMP_OFFSET)
+#define NUM_TEMP_LIMIT 3
+#define NUM_FAN ARRAY_SIZE(IT87_REG_FAN)
+#define NUM_FAN_DIV 3
+#define NUM_PWM ARRAY_SIZE(IT87_REG_PWM)
+#define NUM_AUTO_PWM ARRAY_SIZE(IT87_REG_PWM)
+
struct it87_devices {
const char *name;
const char * const suffix;
@@ -484,14 +494,14 @@ struct it87_data {
u16 in_scaled; /* Internal voltage sensors are scaled */
u16 in_internal; /* Bitfield, internal sensors (for labels) */
u16 has_in; /* Bitfield, voltage sensors enabled */
- u8 in[13][3]; /* [nr][0]=in, [1]=min, [2]=max */
+ u8 in[NUM_VIN][3]; /* [nr][0]=in, [1]=min, [2]=max */
u8 has_fan; /* Bitfield, fans enabled */
- u16 fan[6][2]; /* Register values, [nr][0]=fan, [1]=min */
+ u16 fan[NUM_FAN][2]; /* Register values, [nr][0]=fan, [1]=min */
u8 has_temp; /* Bitfield, temp sensors enabled */
- s8 temp[6][4]; /* [nr][0]=temp, [1]=min, [2]=max, [3]=offset */
+ s8 temp[NUM_TEMP][4]; /* [nr][0]=temp, [1]=min, [2]=max, [3]=offset */
u8 sensor; /* Register value (IT87_REG_TEMP_ENABLE) */
u8 extra; /* Register value (IT87_REG_TEMP_EXTRA) */
- u8 fan_div[3]; /* Register encoding, shifted right */
+ u8 fan_div[NUM_FAN_DIV];/* Register encoding, shifted right */
bool has_vid; /* True if VID supported */
u8 vid; /* Register encoding, combined */
u8 vrm;
@@ -512,13 +522,13 @@ struct it87_data {
* simple.
*/
u8 has_pwm; /* Bitfield, pwm control enabled */
- u8 pwm_ctrl[6]; /* Register value */
- u8 pwm_duty[6]; /* Manual PWM value set by user */
- u8 pwm_temp_map[6]; /* PWM to temp. chan. mapping (bits 1-0) */
+ u8 pwm_ctrl[NUM_PWM]; /* Register value */
+ u8 pwm_duty[NUM_PWM]; /* Manual PWM value set by user */
+ u8 pwm_temp_map[NUM_PWM];/* PWM to temp. chan. mapping (bits 1-0) */

/* Automatic fan speed control registers */
- u8 auto_pwm[3][4]; /* [nr][3] is hard-coded */
- s8 auto_temp[3][5]; /* [nr][0] is point1_temp_hyst */
+ u8 auto_pwm[NUM_AUTO_PWM][4]; /* [nr][3] is hard-coded */
+ s8 auto_temp[NUM_AUTO_PWM][5]; /* [nr][0] is point1_temp_hyst */
};

static int adc_lsb(const struct it87_data *data, int nr)
@@ -686,7 +696,7 @@ static struct it87_data *it87_update_device(struct device *dev)
it87_write_value(data, IT87_REG_CONFIG,
it87_read_value(data, IT87_REG_CONFIG) | 0x40);
}
- for (i = 0; i < ARRAY_SIZE(IT87_REG_VIN); i++) {
+ for (i = 0; i < NUM_VIN; i++) {
if (!(data->has_in & BIT(i)))
continue;

@@ -694,7 +704,7 @@ static struct it87_data *it87_update_device(struct device *dev)
it87_read_value(data, IT87_REG_VIN[i]);

/* VBAT and AVCC don't have limit registers */
- if (i >= 8)
+ if (i >= NUM_VIN_LIMIT)
continue;

data->in[i][1] =
@@ -703,7 +713,7 @@ static struct it87_data *it87_update_device(struct device *dev)
it87_read_value(data, IT87_REG_VIN_MAX(i));
}

- for (i = 0; i < 6; i++) {
+ for (i = 0; i < NUM_FAN; i++) {
/* Skip disabled fans */
if (!(data->has_fan & BIT(i)))
continue;
@@ -720,24 +730,24 @@ static struct it87_data *it87_update_device(struct device *dev)
IT87_REG_FANX_MIN[i]) << 8;
}
}
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < NUM_TEMP; i++) {
if (!(data->has_temp & BIT(i)))
continue;
data->temp[i][0] =
it87_read_value(data, IT87_REG_TEMP(i));

- /* No limits/offset for additional sensors */
- if (i >= 3)
+ if (has_temp_offset(data) && i < NUM_TEMP_OFFSET)
+ data->temp[i][3] =
+ it87_read_value(data,
+ IT87_REG_TEMP_OFFSET[i]);
+
+ if (i >= NUM_TEMP_LIMIT)
continue;

data->temp[i][1] =
it87_read_value(data, IT87_REG_TEMP_LOW(i));
data->temp[i][2] =
it87_read_value(data, IT87_REG_TEMP_HIGH(i));
- if (has_temp_offset(data))
- data->temp[i][3] =
- it87_read_value(data,
- IT87_REG_TEMP_OFFSET[i]);
}

/* Newer chips don't have clock dividers */
@@ -757,7 +767,7 @@ static struct it87_data *it87_update_device(struct device *dev)
data->fan_main_ctrl = it87_read_value(data,
IT87_REG_FAN_MAIN_CTRL);
data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL);
- for (i = 0; i < 6; i++)
+ for (i = 0; i < NUM_PWM; i++)
it87_update_pwm_ctrl(data, i);

data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
@@ -2509,7 +2519,7 @@ static void it87_init_device(struct platform_device *pdev)
* these have separate registers for the temperature mapping and the
* manual duty cycle.
*/
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < NUM_AUTO_PWM; i++) {
data->pwm_temp_map[i] = i;
data->pwm_duty[i] = 0x7f; /* Full speed */
data->auto_pwm[i][3] = 0x7f; /* Full speed, hard-coded */
@@ -2522,12 +2532,12 @@ static void it87_init_device(struct platform_device *pdev)
* means -1 degree C, which surprisingly doesn't trigger an alarm,
* but is still confusing, so change to 127 degrees C.
*/
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < NUM_VIN_LIMIT; i++) {
tmp = it87_read_value(data, IT87_REG_VIN_MIN(i));
if (tmp == 0xff)
it87_write_value(data, IT87_REG_VIN_MIN(i), 0);
}
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < NUM_TEMP_LIMIT; i++) {
tmp = it87_read_value(data, IT87_REG_TEMP_HIGH(i));
if (tmp == 0xff)
it87_write_value(data, IT87_REG_TEMP_HIGH(i), 127);
@@ -2620,7 +2630,7 @@ static int it87_check_pwm(struct device *dev)
int i;
u8 pwm[3];

- for (i = 0; i < 3; i++)
+ for (i = 0; i < ARRAY_SIZE(pwm); i++)
pwm[i] = it87_read_value(data,
IT87_REG_PWM[i]);
--
2.1.4
Guenter Roeck
2016-01-27 02:03:42 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

Using the BIT macro makes the code a little easier to read and has the
added benefit of making checkpatch happy.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 290 ++++++++++++++++++++++++++-------------------------
1 file changed, 146 insertions(+), 144 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 96876755376c..0d6d106d53a2 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -52,6 +52,7 @@

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

+#include <linux/bitops.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -267,23 +268,23 @@ struct it87_devices {
u8 old_peci_mask;
};

-#define FEAT_12MV_ADC (1 << 0)
-#define FEAT_NEWER_AUTOPWM (1 << 1)
-#define FEAT_OLD_AUTOPWM (1 << 2)
-#define FEAT_16BIT_FANS (1 << 3)
-#define FEAT_TEMP_OFFSET (1 << 4)
-#define FEAT_TEMP_PECI (1 << 5)
-#define FEAT_TEMP_OLD_PECI (1 << 6)
-#define FEAT_FAN16_CONFIG (1 << 7) /* Need to enable 16-bit fans */
-#define FEAT_FIVE_FANS (1 << 8) /* Supports five fans */
-#define FEAT_VID (1 << 9) /* Set if chip supports VID */
-#define FEAT_IN7_INTERNAL (1 << 10) /* Set if in7 is internal */
-#define FEAT_SIX_FANS (1 << 11) /* Supports six fans */
-#define FEAT_10_9MV_ADC (1 << 12)
-#define FEAT_AVCC3 (1 << 13) /* Chip supports in9/AVCC3 */
-#define FEAT_SIX_PWM (1 << 14) /* Chip supports 6 pwm chn */
-#define FEAT_PWM_FREQ2 (1 << 15) /* Separate pwm freq 2 */
-#define FEAT_SIX_TEMP (1 << 16) /* Up to 6 temp sensors */
+#define FEAT_12MV_ADC BIT(0)
+#define FEAT_NEWER_AUTOPWM BIT(1)
+#define FEAT_OLD_AUTOPWM BIT(2)
+#define FEAT_16BIT_FANS BIT(3)
+#define FEAT_TEMP_OFFSET BIT(4)
+#define FEAT_TEMP_PECI BIT(5)
+#define FEAT_TEMP_OLD_PECI BIT(6)
+#define FEAT_FAN16_CONFIG BIT(7) /* Need to enable 16-bit fans */
+#define FEAT_FIVE_FANS BIT(8) /* Supports five fans */
+#define FEAT_VID BIT(9) /* Set if chip supports VID */
+#define FEAT_IN7_INTERNAL BIT(10) /* Set if in7 is internal */
+#define FEAT_SIX_FANS BIT(11) /* Supports six fans */
+#define FEAT_10_9MV_ADC BIT(12)
+#define FEAT_AVCC3 BIT(13) /* Chip supports in9/AVCC3 */
+#define FEAT_SIX_PWM BIT(14) /* Chip supports 6 pwm chn */
+#define FEAT_PWM_FREQ2 BIT(15) /* Separate pwm freq 2 */
+#define FEAT_SIX_TEMP BIT(16) /* Up to 6 temp sensors */

static const struct it87_devices it87_devices[] = {
[it87] = {
@@ -433,10 +434,10 @@ static const struct it87_devices it87_devices[] = {
#define has_old_autopwm(data) ((data)->features & FEAT_OLD_AUTOPWM)
#define has_temp_offset(data) ((data)->features & FEAT_TEMP_OFFSET)
#define has_temp_peci(data, nr) (((data)->features & FEAT_TEMP_PECI) && \
- ((data)->peci_mask & (1 << nr)))
+ ((data)->peci_mask & BIT(nr)))
#define has_temp_old_peci(data, nr) \
(((data)->features & FEAT_TEMP_OLD_PECI) && \
- ((data)->old_peci_mask & (1 << nr)))
+ ((data)->old_peci_mask & BIT(nr)))
#define has_fan16_config(data) ((data)->features & FEAT_FAN16_CONFIG)
#define has_five_fans(data) ((data)->features & (FEAT_FIVE_FANS | \
FEAT_SIX_FANS))
@@ -530,7 +531,7 @@ static int adc_lsb(const struct it87_data *data, int nr)
lsb = 109;
else
lsb = 160;
- if (data->in_scaled & (1 << nr))
+ if (data->in_scaled & BIT(nr))
lsb <<= 1;
return lsb;
}
@@ -595,7 +596,8 @@ static int DIV_TO_REG(int val)
answer++;
return answer;
}
-#define DIV_FROM_REG(val) (1 << (val))
+
+#define DIV_FROM_REG(val) BIT(val)

/*
* PWM base frequencies. The frequency has to be divided by either 128 or 256,
@@ -685,7 +687,7 @@ static struct it87_data *it87_update_device(struct device *dev)
it87_read_value(data, IT87_REG_CONFIG) | 0x40);
}
for (i = 0; i < ARRAY_SIZE(IT87_REG_VIN); i++) {
- if (!(data->has_in & (1 << i)))
+ if (!(data->has_in & BIT(i)))
continue;

data->in[i][0] =
@@ -703,7 +705,7 @@ static struct it87_data *it87_update_device(struct device *dev)

for (i = 0; i < 6; i++) {
/* Skip disabled fans */
- if (!(data->has_fan & (1 << i)))
+ if (!(data->has_fan & BIT(i)))
continue;

data->fan[i][1] =
@@ -719,7 +721,7 @@ static struct it87_data *it87_update_device(struct device *dev)
}
}
for (i = 0; i < 6; i++) {
- if (!(data->has_temp & (1 << i)))
+ if (!(data->has_temp & BIT(i)))
continue;
data->temp[i][0] =
it87_read_value(data, IT87_REG_TEMP(i));
@@ -1026,7 +1028,7 @@ static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type,

static int pwm_mode(const struct it87_data *data, int nr)
{
- int ctrl = data->fan_main_ctrl & (1 << nr);
+ int ctrl = data->fan_main_ctrl & BIT(nr);

if (ctrl == 0 && data->type != it8603) /* Full speed */
return 0;
@@ -1059,7 +1061,7 @@ static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
int nr = sensor_attr->index;

struct it87_data *data = it87_update_device(dev);
- return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
+ return sprintf(buf, "%lu\n", DIV_FROM_REG(data->fan_div[nr]));
}
static ssize_t show_pwm_enable(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -1243,9 +1245,9 @@ static ssize_t set_pwm_enable(struct device *dev,
int tmp;
/* make sure the fan is on when in on/off mode */
tmp = it87_read_value(data, IT87_REG_FAN_CTL);
- it87_write_value(data, IT87_REG_FAN_CTL, tmp | (1 << nr));
+ it87_write_value(data, IT87_REG_FAN_CTL, tmp | BIT(nr));
/* set on/off mode */
- data->fan_main_ctrl &= ~(1 << nr);
+ data->fan_main_ctrl &= ~BIT(nr);
it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
data->fan_main_ctrl);
} else {
@@ -1259,7 +1261,7 @@ static ssize_t set_pwm_enable(struct device *dev,

if (data->type != it8603) {
/* set SmartGuardian mode */
- data->fan_main_ctrl |= (1 << nr);
+ data->fan_main_ctrl |= BIT(nr);
it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
data->fan_main_ctrl);
}
@@ -1353,7 +1355,7 @@ static ssize_t show_pwm_temp_map(struct device *dev,
int map;

if (data->pwm_temp_map[nr] < 3)
- map = 1 << data->pwm_temp_map[nr];
+ map = BIT(data->pwm_temp_map[nr]);
else
map = 0; /* Should never happen */
return sprintf(buf, "%d\n", map);
@@ -1372,13 +1374,13 @@ static ssize_t set_pwm_temp_map(struct device *dev,
return -EINVAL;

switch (val) {
- case (1 << 0):
+ case BIT(0):
reg = 0x00;
break;
- case (1 << 1):
+ case BIT(1):
reg = 0x01;
break;
- case (1 << 2):
+ case BIT(2):
reg = 0x02;
break;
default:
@@ -1625,7 +1627,7 @@ static ssize_t clear_intrusion(struct device *dev, struct device_attribute
if (config < 0) {
count = config;
} else {
- config |= 1 << 5;
+ config |= BIT(5);
it87_write_value(data, IT87_REG_CONFIG, config);
/* Invalidate cache to force re-read */
data->valid = 0;
@@ -1676,9 +1678,9 @@ static ssize_t set_beep(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->update_lock);
data->beeps = it87_read_value(data, IT87_REG_BEEP_ENABLE);
if (val)
- data->beeps |= (1 << bitnr);
+ data->beeps |= BIT(bitnr);
else
- data->beeps &= ~(1 << bitnr);
+ data->beeps &= ~BIT(bitnr);
it87_write_value(data, IT87_REG_BEEP_ENABLE, data->beeps);
mutex_unlock(&data->update_lock);
return count;
@@ -1777,7 +1779,7 @@ static umode_t it87_in_is_visible(struct kobject *kobj,
a = 0;
}

- if (!(data->has_in & (1 << i)))
+ if (!(data->has_in & BIT(i)))
return 0;

if (a == 4 && !data->has_beep)
@@ -1860,7 +1862,7 @@ static umode_t it87_temp_is_visible(struct kobject *kobj,
a = 0;
}

- if (!(data->has_temp & (1 << i)))
+ if (!(data->has_temp & BIT(i)))
return 0;

if (a == 5 && !has_temp_offset(data))
@@ -1917,7 +1919,7 @@ static umode_t it87_is_visible(struct kobject *kobj,
if ((index == 2 || index == 3) && !data->has_vid)
return 0;

- if (index > 3 && !(data->in_internal & (1 << (index - 4))))
+ if (index > 3 && !(data->in_internal & BIT(index - 4)))
return 0;

return attr->mode;
@@ -1953,7 +1955,7 @@ static umode_t it87_fan_is_visible(struct kobject *kobj,
a = (index - 15) % 4;
}

- if (!(data->has_fan & (1 << i)))
+ if (!(data->has_fan & BIT(i)))
return 0;

if (a == 3) { /* beep */
@@ -2019,7 +2021,7 @@ static umode_t it87_pwm_is_visible(struct kobject *kobj,
int i = index / 4; /* pwm index */
int a = index % 4; /* attribute index */

- if (!(data->has_pwm & (1 << i)))
+ if (!(data->has_pwm & BIT(i)))
return 0;

/* pwmX_auto_channels_temp is only writable for old auto pwm */
@@ -2079,7 +2081,7 @@ static umode_t it87_auto_pwm_is_visible(struct kobject *kobj,
struct it87_data *data = dev_get_drvdata(dev);
int i = index / 9; /* pwm index */

- if (!(data->has_pwm & (1 << i)))
+ if (!(data->has_pwm & BIT(i)))
return 0;

return attr->mode;
@@ -2223,19 +2225,19 @@ static int __init it87_find(int sioaddr, unsigned short *address,

/* in7 (VSB or VCCH5V) is always internal on some chips */
if (has_in7_internal(config))
- sio_data->internal |= (1 << 1);
+ sio_data->internal |= BIT(1);

/* in8 (Vbat) is always internal */
- sio_data->internal |= (1 << 2);
+ sio_data->internal |= BIT(2);

/* in9 (AVCC3), always internal if supported */
if (has_avcc3(config))
- sio_data->internal |= (1 << 3); /* in9 is AVCC */
+ sio_data->internal |= BIT(3); /* in9 is AVCC */
else
- sio_data->skip_in |= (1 << 9);
+ sio_data->skip_in |= BIT(9);

if (!has_six_pwm(config))
- sio_data->skip_pwm |= (1 << 3) | (1 << 4) | (1 << 5);
+ sio_data->skip_pwm |= BIT(3) | BIT(4) | BIT(5);

if (!has_vid(config))
sio_data->skip_vid = 1;
@@ -2258,31 +2260,31 @@ static int __init it87_find(int sioaddr, unsigned short *address,
regef = superio_inb(sioaddr, IT87_SIO_SPI_REG);

/* Check if fan3 is there or not */
- if ((reg27 & (1 << 0)) || !(reg2c & (1 << 2)))
- sio_data->skip_fan |= (1 << 2);
- if ((reg25 & (1 << 4))
- || (!(reg2a & (1 << 1)) && (regef & (1 << 0))))
- sio_data->skip_pwm |= (1 << 2);
+ if ((reg27 & BIT(0)) || !(reg2c & BIT(2)))
+ sio_data->skip_fan |= BIT(2);
+ if ((reg25 & BIT(4))
+ || (!(reg2a & BIT(1)) && (regef & BIT(0))))
+ sio_data->skip_pwm |= BIT(2);

/* Check if fan2 is there or not */
- if (reg27 & (1 << 7))
- sio_data->skip_fan |= (1 << 1);
- if (reg27 & (1 << 3))
- sio_data->skip_pwm |= (1 << 1);
+ if (reg27 & BIT(7))
+ sio_data->skip_fan |= BIT(1);
+ if (reg27 & BIT(3))
+ sio_data->skip_pwm |= BIT(1);

/* VIN5 */
- if ((reg27 & (1 << 0)) || (reg2c & (1 << 2)))
- sio_data->skip_in |= (1 << 5); /* No VIN5 */
+ if ((reg27 & BIT(0)) || (reg2c & BIT(2)))
+ sio_data->skip_in |= BIT(5); /* No VIN5 */

/* VIN6 */
- if (reg27 & (1 << 1))
- sio_data->skip_in |= (1 << 6); /* No VIN6 */
+ if (reg27 & BIT(1))
+ sio_data->skip_in |= BIT(6); /* No VIN6 */

/*
* VIN7
* Does not depend on bit 2 of Reg2C, contrary to datasheet.
*/
- if (reg27 & (1 << 2)) {
+ if (reg27 & BIT(2)) {
/*
* The data sheet is a bit unclear regarding the
* internal voltage divider for VCCH5V. It says
@@ -2296,8 +2298,8 @@ static int __init it87_find(int sioaddr, unsigned short *address,
* not the case, and ask the user to report if the
* resulting voltage is sane.
*/
- if (!(reg2c & (1 << 1))) {
- reg2c |= (1 << 1);
+ if (!(reg2c & BIT(1))) {
+ reg2c |= BIT(1);
superio_outb(sioaddr, IT87_SIO_PINX2_REG,
reg2c);
pr_notice("Routing internal VCCH5V to in7.\n");
@@ -2306,10 +2308,10 @@ static int __init it87_find(int sioaddr, unsigned short *address,
pr_notice("Please report if it displays a reasonable voltage.\n");
}

- if (reg2c & (1 << 0))
- sio_data->internal |= (1 << 0);
- if (reg2c & (1 << 1))
- sio_data->internal |= (1 << 1);
+ if (reg2c & BIT(0))
+ sio_data->internal |= BIT(0);
+ if (reg2c & BIT(1))
+ sio_data->internal |= BIT(1);

sio_data->beep_pin = superio_inb(sioaddr,
IT87_SIO_BEEP_PIN_REG) & 0x3f;
@@ -2321,20 +2323,20 @@ static int __init it87_find(int sioaddr, unsigned short *address,
reg27 = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);

/* Check if fan3 is there or not */
- if (reg27 & (1 << 6))
- sio_data->skip_pwm |= (1 << 2);
- if (reg27 & (1 << 7))
- sio_data->skip_fan |= (1 << 2);
+ if (reg27 & BIT(6))
+ sio_data->skip_pwm |= BIT(2);
+ if (reg27 & BIT(7))
+ sio_data->skip_fan |= BIT(2);

/* Check if fan2 is there or not */
reg29 = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
- if (reg29 & (1 << 1))
- sio_data->skip_pwm |= (1 << 1);
- if (reg29 & (1 << 2))
- sio_data->skip_fan |= (1 << 1);
+ if (reg29 & BIT(1))
+ sio_data->skip_pwm |= BIT(1);
+ if (reg29 & BIT(2))
+ sio_data->skip_fan |= BIT(1);

- sio_data->skip_in |= (1 << 5); /* No VIN5 */
- sio_data->skip_in |= (1 << 6); /* No VIN6 */
+ sio_data->skip_in |= BIT(5); /* No VIN5 */
+ sio_data->skip_in |= BIT(6); /* No VIN6 */

sio_data->beep_pin = superio_inb(sioaddr,
IT87_SIO_BEEP_PIN_REG) & 0x3f;
@@ -2345,38 +2347,38 @@ static int __init it87_find(int sioaddr, unsigned short *address,

/* Check for pwm5 */
reg = superio_inb(sioaddr, IT87_SIO_GPIO1_REG);
- if (reg & (1 << 6))
- sio_data->skip_pwm |= (1 << 4);
+ if (reg & BIT(6))
+ sio_data->skip_pwm |= BIT(4);

/* Check for fan4, fan5 */
reg = superio_inb(sioaddr, IT87_SIO_GPIO2_REG);
- if (!(reg & (1 << 5)))
- sio_data->skip_fan |= (1 << 3);
- if (!(reg & (1 << 4)))
- sio_data->skip_fan |= (1 << 4);
+ if (!(reg & BIT(5)))
+ sio_data->skip_fan |= BIT(3);
+ if (!(reg & BIT(4)))
+ sio_data->skip_fan |= BIT(4);

/* Check for pwm3, fan3 */
reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
- if (reg & (1 << 6))
- sio_data->skip_pwm |= (1 << 2);
- if (reg & (1 << 7))
- sio_data->skip_fan |= (1 << 2);
+ if (reg & BIT(6))
+ sio_data->skip_pwm |= BIT(2);
+ if (reg & BIT(7))
+ sio_data->skip_fan |= BIT(2);

/* Check for pwm4 */
reg = superio_inb(sioaddr, IT87_SIO_GPIO4_REG);
- if (!(reg & (1 << 2)))
- sio_data->skip_pwm |= (1 << 3);
+ if (!(reg & BIT(2)))
+ sio_data->skip_pwm |= BIT(3);

/* Check for pwm2, fan2 */
reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
- if (reg & (1 << 1))
- sio_data->skip_pwm |= (1 << 1);
- if (reg & (1 << 2))
- sio_data->skip_fan |= (1 << 1);
+ if (reg & BIT(1))
+ sio_data->skip_pwm |= BIT(1);
+ if (reg & BIT(2))
+ sio_data->skip_fan |= BIT(1);
/* Check for pwm6, fan6 */
- if (!(reg & (1 << 7))) {
- sio_data->skip_pwm |= (1 << 5);
- sio_data->skip_fan |= (1 << 5);
+ if (!(reg & BIT(7))) {
+ sio_data->skip_pwm |= BIT(5);
+ sio_data->skip_fan |= BIT(5);
}

sio_data->beep_pin = superio_inb(sioaddr,
@@ -2397,17 +2399,17 @@ static int __init it87_find(int sioaddr, unsigned short *address,
}

/* Check if fan3 is there or not */
- if (reg & (1 << 6))
- sio_data->skip_pwm |= (1 << 2);
- if (reg & (1 << 7))
- sio_data->skip_fan |= (1 << 2);
+ if (reg & BIT(6))
+ sio_data->skip_pwm |= BIT(2);
+ if (reg & BIT(7))
+ sio_data->skip_fan |= BIT(2);

/* Check if fan2 is there or not */
reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
- if (reg & (1 << 1))
- sio_data->skip_pwm |= (1 << 1);
- if (reg & (1 << 2))
- sio_data->skip_fan |= (1 << 1);
+ if (reg & BIT(1))
+ sio_data->skip_pwm |= BIT(1);
+ if (reg & BIT(2))
+ sio_data->skip_fan |= BIT(1);

if ((sio_data->type == it8718 || sio_data->type == it8720)
&& !(sio_data->skip_vid))
@@ -2416,7 +2418,7 @@ static int __init it87_find(int sioaddr, unsigned short *address,

reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG);

- uart6 = sio_data->type == it8782 && (reg & (1 << 2));
+ uart6 = sio_data->type == it8782 && (reg & BIT(2));

/*
* The IT8720F has no VIN7 pin, so VCCH should always be
@@ -2432,15 +2434,15 @@ static int __init it87_find(int sioaddr, unsigned short *address,
* If UART6 is enabled, re-route VIN7 to the internal divider
* if that is not already the case.
*/
- if ((sio_data->type == it8720 || uart6) && !(reg & (1 << 1))) {
- reg |= (1 << 1);
+ if ((sio_data->type == it8720 || uart6) && !(reg & BIT(1))) {
+ reg |= BIT(1);
superio_outb(sioaddr, IT87_SIO_PINX2_REG, reg);
pr_notice("Routing internal VCCH to in7\n");
}
- if (reg & (1 << 0))
- sio_data->internal |= (1 << 0);
- if (reg & (1 << 1))
- sio_data->internal |= (1 << 1);
+ if (reg & BIT(0))
+ sio_data->internal |= BIT(0);
+ if (reg & BIT(1))
+ sio_data->internal |= BIT(1);

/*
* On IT8782F, UART6 pins overlap with VIN5, VIN6, and VIN7.
@@ -2452,8 +2454,8 @@ static int __init it87_find(int sioaddr, unsigned short *address,
* temperature source here, skip_temp is preliminary.
*/
if (uart6) {
- sio_data->skip_in |= (1 << 5) | (1 << 6);
- sio_data->skip_temp |= (1 << 2);
+ sio_data->skip_in |= BIT(5) | BIT(6);
+ sio_data->skip_temp |= BIT(2);
}

sio_data->beep_pin = superio_inb(sioaddr,
@@ -2477,7 +2479,7 @@ static int __init it87_find(int sioaddr, unsigned short *address,
* the same board is ever used in other systems.
*/
pr_info("Disabling pwm2 due to hardware constraints\n");
- sio_data->skip_pwm = (1 << 1);
+ sio_data->skip_pwm = BIT(1);
}
}

@@ -2570,12 +2572,12 @@ static void it87_init_device(struct platform_device *pdev)

/* Check for additional fans */
if (has_five_fans(data)) {
- if (tmp & (1 << 4))
- data->has_fan |= (1 << 3); /* fan4 enabled */
- if (tmp & (1 << 5))
- data->has_fan |= (1 << 4); /* fan5 enabled */
- if (has_six_fans(data) && (tmp & (1 << 2)))
- data->has_fan |= (1 << 5); /* fan6 enabled */
+ if (tmp & BIT(4))
+ data->has_fan |= BIT(3); /* fan4 enabled */
+ if (tmp & BIT(5))
+ data->has_fan |= BIT(4); /* fan5 enabled */
+ if (has_six_fans(data) && (tmp & BIT(2)))
+ data->has_fan |= BIT(5); /* fan6 enabled */
}

/* Fan input pins may be used for alternative functions */
@@ -2586,9 +2588,9 @@ static void it87_init_device(struct platform_device *pdev)
/* The following code may be IT8620E specific */
tmp = it87_read_value(data, IT87_REG_FAN_DIV);
if ((tmp & 0xc0) == 0xc0)
- sio_data->skip_pwm |= (1 << 4);
- if (!(tmp & (1 << 3)))
- sio_data->skip_pwm |= (1 << 5);
+ sio_data->skip_pwm |= BIT(4);
+ if (!(tmp & BIT(3)))
+ sio_data->skip_pwm |= BIT(5);
}

/* Start monitoring */
@@ -2719,27 +2721,27 @@ static int it87_probe(struct platform_device *pdev)

/* Starting with IT8721F, we handle scaling of internal voltages */
if (has_12mv_adc(data)) {
- if (sio_data->internal & (1 << 0))
- data->in_scaled |= (1 << 3); /* in3 is AVCC */
- if (sio_data->internal & (1 << 1))
- data->in_scaled |= (1 << 7); /* in7 is VSB */
- if (sio_data->internal & (1 << 2))
- data->in_scaled |= (1 << 8); /* in8 is Vbat */
- if (sio_data->internal & (1 << 3))
- data->in_scaled |= (1 << 9); /* in9 is AVCC */
+ if (sio_data->internal & BIT(0))
+ data->in_scaled |= BIT(3); /* in3 is AVCC */
+ if (sio_data->internal & BIT(1))
+ data->in_scaled |= BIT(7); /* in7 is VSB */
+ if (sio_data->internal & BIT(2))
+ data->in_scaled |= BIT(8); /* in8 is Vbat */
+ if (sio_data->internal & BIT(3))
+ data->in_scaled |= BIT(9); /* in9 is AVCC */
} else if (sio_data->type == it8781 || sio_data->type == it8782 ||
sio_data->type == it8783) {
- if (sio_data->internal & (1 << 0))
- data->in_scaled |= (1 << 3); /* in3 is VCC5V */
- if (sio_data->internal & (1 << 1))
- data->in_scaled |= (1 << 7); /* in7 is VCCH5V */
+ if (sio_data->internal & BIT(0))
+ data->in_scaled |= BIT(3); /* in3 is VCC5V */
+ if (sio_data->internal & BIT(1))
+ data->in_scaled |= BIT(7); /* in7 is VCCH5V */
}

data->has_temp = 0x07;
- if (sio_data->skip_temp & (1 << 2)) {
+ if (sio_data->skip_temp & BIT(2)) {
if (sio_data->type == it8782
&& !(it87_read_value(data, IT87_REG_TEMP_EXTRA) & 0x80))
- data->has_temp &= ~(1 << 2);
+ data->has_temp &= ~BIT(2);
}

data->in_internal = sio_data->internal;
@@ -2750,19 +2752,19 @@ static int it87_probe(struct platform_device *pdev)

/* Check for additional temperature sensors */
if ((reg & 0x03) >= 0x02)
- data->has_temp |= (1 << 3);
+ data->has_temp |= BIT(3);
if (((reg >> 2) & 0x03) >= 0x02)
- data->has_temp |= (1 << 4);
+ data->has_temp |= BIT(4);
if (((reg >> 4) & 0x03) >= 0x02)
- data->has_temp |= (1 << 5);
+ data->has_temp |= BIT(5);

/* Check for additional voltage sensors */
if ((reg & 0x03) == 0x01)
- data->has_in |= (1 << 10);
+ data->has_in |= BIT(10);
if (((reg >> 2) & 0x03) == 0x01)
- data->has_in |= (1 << 11);
+ data->has_in |= BIT(11);
if (((reg >> 4) & 0x03) == 0x01)
- data->has_in |= (1 << 12);
+ data->has_in |= BIT(12);
}

data->has_beep = !!sio_data->beep_pin;
@@ -2784,7 +2786,7 @@ static int it87_probe(struct platform_device *pdev)
data->groups[3] = &it87_group_fan;

if (enable_pwm_interface) {
- data->has_pwm = (1 << ARRAY_SIZE(IT87_REG_PWM)) - 1;
+ data->has_pwm = BIT(ARRAY_SIZE(IT87_REG_PWM)) - 1;
data->has_pwm &= ~sio_data->skip_pwm;

data->groups[4] = &it87_group_pwm;
--
2.1.4
Guenter Roeck
2016-01-27 02:03:41 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

IT8620E supports three additional voltage sensors.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 29 ++++++++++++++++++++++++-----
1 file changed, 24 insertions(+), 5 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index aa3ec50527a3..96876755376c 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -219,7 +219,12 @@ static bool fix_pwm_polarity;
#define IT87_REG_FAN_DIV 0x0b
#define IT87_REG_FAN_16BIT 0x0c

-/* Monitors: 9 voltage (0 to 7, battery), 6 temp (1 to 6), 3 fan (1 to 3) */
+/*
+ * Monitors:
+ * - up to 13 voltage (0 to 7, battery, avcc, 10 to 12)
+ * - up to 6 temp (1 to 6)
+ * - up to 6 fan (1 to 6)
+ */

static const u8 IT87_REG_FAN[] = { 0x0d, 0x0e, 0x0f, 0x80, 0x82, 0x4c };
static const u8 IT87_REG_FAN_MIN[] = { 0x10, 0x11, 0x12, 0x84, 0x86, 0x4e };
@@ -233,7 +238,7 @@ static const u8 IT87_REG_PWM[] = { 0x15, 0x16, 0x17, 0x7f, 0xa7, 0xaf };
static const u8 IT87_REG_PWM_DUTY[] = { 0x63, 0x6b, 0x73, 0x7b, 0xa3, 0xab };

static const u8 IT87_REG_VIN[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
- 0x27, 0x28, 0x2f };
+ 0x27, 0x28, 0x2f, 0x2c, 0x2d, 0x2e };

#define IT87_REG_TEMP(nr) (0x29 + (nr))

@@ -478,7 +483,7 @@ struct it87_data {
u16 in_scaled; /* Internal voltage sensors are scaled */
u16 in_internal; /* Bitfield, internal sensors (for labels) */
u16 has_in; /* Bitfield, voltage sensors enabled */
- u8 in[10][3]; /* [nr][0]=in, [1]=min, [2]=max */
+ u8 in[13][3]; /* [nr][0]=in, [1]=min, [2]=max */
u8 has_fan; /* Bitfield, fans enabled */
u16 fan[6][2]; /* Register values, [nr][0]=fan, [1]=min */
u8 has_temp; /* Bitfield, temp sensors enabled */
@@ -861,6 +866,9 @@ static SENSOR_DEVICE_ATTR_2(in7_max, S_IRUGO | S_IWUSR, show_in, set_in,

static SENSOR_DEVICE_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 8, 0);
static SENSOR_DEVICE_ATTR_2(in9_input, S_IRUGO, show_in, NULL, 9, 0);
+static SENSOR_DEVICE_ATTR_2(in10_input, S_IRUGO, show_in, NULL, 10, 0);
+static SENSOR_DEVICE_ATTR_2(in11_input, S_IRUGO, show_in, NULL, 11, 0);
+static SENSOR_DEVICE_ATTR_2(in12_input, S_IRUGO, show_in, NULL, 12, 0);

/* Up to 6 temperatures */
static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
@@ -1764,7 +1772,7 @@ static umode_t it87_in_is_visible(struct kobject *kobj,
int i = index / 5; /* voltage index */
int a = index % 5; /* attribute index */

- if (index >= 40) { /* in8, in9 only have input attributes */
+ if (index >= 40) { /* in8 and higher only have input attributes */
i = index - 40 + 8;
a = 0;
}
@@ -1828,8 +1836,10 @@ static struct attribute *it87_attributes_in[] = {
&sensor_dev_attr_in7_beep.dev_attr.attr, /* 39 */

&sensor_dev_attr_in8_input.dev_attr.attr, /* 40 */
-
&sensor_dev_attr_in9_input.dev_attr.attr, /* 41 */
+ &sensor_dev_attr_in10_input.dev_attr.attr, /* 41 */
+ &sensor_dev_attr_in11_input.dev_attr.attr, /* 41 */
+ &sensor_dev_attr_in12_input.dev_attr.attr, /* 41 */
};

static const struct attribute_group it87_group_in = {
@@ -2738,12 +2748,21 @@ static int it87_probe(struct platform_device *pdev)
if (has_six_temp(data)) {
u8 reg = it87_read_value(data, IT87_REG_TEMP456_ENABLE);

+ /* Check for additional temperature sensors */
if ((reg & 0x03) >= 0x02)
data->has_temp |= (1 << 3);
if (((reg >> 2) & 0x03) >= 0x02)
data->has_temp |= (1 << 4);
if (((reg >> 4) & 0x03) >= 0x02)
data->has_temp |= (1 << 5);
+
+ /* Check for additional voltage sensors */
+ if ((reg & 0x03) == 0x01)
+ data->has_in |= (1 << 10);
+ if (((reg >> 2) & 0x03) == 0x01)
+ data->has_in |= (1 << 11);
+ if (((reg >> 4) & 0x03) == 0x01)
+ data->has_in |= (1 << 12);
}

data->has_beep = !!sio_data->beep_pin;
--
2.1.4
Guenter Roeck
2016-01-27 02:03:40 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

Voltage registers are non-sequential. Use a register array instead
of a macro to map sensor index to register to simplify the code
and to make it easier to add additional voltage sensors.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 22 +++++++++++++---------
1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 722d6de62d1c..aa3ec50527a3 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -232,10 +232,10 @@ static const u8 IT87_REG_TEMP_OFFSET[] = { 0x56, 0x57, 0x59 };
static const u8 IT87_REG_PWM[] = { 0x15, 0x16, 0x17, 0x7f, 0xa7, 0xaf };
static const u8 IT87_REG_PWM_DUTY[] = { 0x63, 0x6b, 0x73, 0x7b, 0xa3, 0xab };

-#define IT87_REG_VIN(nr) (0x20 + (nr))
-#define IT87_REG_TEMP(nr) (0x29 + (nr))
+static const u8 IT87_REG_VIN[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
+ 0x27, 0x28, 0x2f };

-#define IT87_REG_AVCC3 0x2f
+#define IT87_REG_TEMP(nr) (0x29 + (nr))

#define IT87_REG_VIN_MAX(nr) (0x30 + (nr) * 2)
#define IT87_REG_VIN_MIN(nr) (0x31 + (nr) * 2)
@@ -679,18 +679,22 @@ static struct it87_data *it87_update_device(struct device *dev)
it87_write_value(data, IT87_REG_CONFIG,
it87_read_value(data, IT87_REG_CONFIG) | 0x40);
}
- for (i = 0; i <= 7; i++) {
+ for (i = 0; i < ARRAY_SIZE(IT87_REG_VIN); i++) {
+ if (!(data->has_in & (1 << i)))
+ continue;
+
data->in[i][0] =
- it87_read_value(data, IT87_REG_VIN(i));
+ it87_read_value(data, IT87_REG_VIN[i]);
+
+ /* VBAT and AVCC don't have limit registers */
+ if (i >= 8)
+ continue;
+
data->in[i][1] =
it87_read_value(data, IT87_REG_VIN_MIN(i));
data->in[i][2] =
it87_read_value(data, IT87_REG_VIN_MAX(i));
}
- /* in8 (battery) has no limit registers */
- data->in[8][0] = it87_read_value(data, IT87_REG_VIN(8));
- if (has_avcc3(data))
- data->in[9][0] = it87_read_value(data, IT87_REG_AVCC3);

for (i = 0; i < 6; i++) {
/* Skip disabled fans */
--
2.1.4
Guenter Roeck
2016-01-27 02:03:39 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

Add support for the additional temperature sensors on IT8620E.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 48 ++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 40 insertions(+), 8 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index e02c972ef81e..722d6de62d1c 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -219,7 +219,7 @@ static bool fix_pwm_polarity;
#define IT87_REG_FAN_DIV 0x0b
#define IT87_REG_FAN_16BIT 0x0c

-/* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */
+/* Monitors: 9 voltage (0 to 7, battery), 6 temp (1 to 6), 3 fan (1 to 3) */

static const u8 IT87_REG_FAN[] = { 0x0d, 0x0e, 0x0f, 0x80, 0x82, 0x4c };
static const u8 IT87_REG_FAN_MIN[] = { 0x10, 0x11, 0x12, 0x84, 0x86, 0x4e };
@@ -252,10 +252,12 @@ static const u8 IT87_REG_PWM_DUTY[] = { 0x63, 0x6b, 0x73, 0x7b, 0xa3, 0xab };
#define IT87_REG_AUTO_TEMP(nr, i) (0x60 + (nr) * 8 + (i))
#define IT87_REG_AUTO_PWM(nr, i) (0x65 + (nr) * 8 + (i))

+#define IT87_REG_TEMP456_ENABLE 0x77
+
struct it87_devices {
const char *name;
const char * const suffix;
- u16 features;
+ u32 features;
u8 peci_mask;
u8 old_peci_mask;
};
@@ -276,6 +278,7 @@ struct it87_devices {
#define FEAT_AVCC3 (1 << 13) /* Chip supports in9/AVCC3 */
#define FEAT_SIX_PWM (1 << 14) /* Chip supports 6 pwm chn */
#define FEAT_PWM_FREQ2 (1 << 15) /* Separate pwm freq 2 */
+#define FEAT_SIX_TEMP (1 << 16) /* Up to 6 temp sensors */

static const struct it87_devices it87_devices[] = {
[it87] = {
@@ -412,7 +415,8 @@ static const struct it87_devices it87_devices[] = {
.suffix = "E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
- | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2,
+ | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
+ | FEAT_SIX_TEMP,
.peci_mask = 0x07,
},
};
@@ -437,6 +441,7 @@ static const struct it87_devices it87_devices[] = {
#define has_avcc3(data) ((data)->features & FEAT_AVCC3)
#define has_six_pwm(data) ((data)->features & FEAT_SIX_PWM)
#define has_pwm_freq2(data) ((data)->features & FEAT_PWM_FREQ2)
+#define has_six_temp(data) ((data)->features & FEAT_SIX_TEMP)

struct it87_sio_data {
enum chips type;
@@ -477,7 +482,7 @@ struct it87_data {
u8 has_fan; /* Bitfield, fans enabled */
u16 fan[6][2]; /* Register values, [nr][0]=fan, [1]=min */
u8 has_temp; /* Bitfield, temp sensors enabled */
- s8 temp[3][4]; /* [nr][0]=temp, [1]=min, [2]=max, [3]=offset */
+ s8 temp[6][4]; /* [nr][0]=temp, [1]=min, [2]=max, [3]=offset */
u8 sensor; /* Register value (IT87_REG_TEMP_ENABLE) */
u8 extra; /* Register value (IT87_REG_TEMP_EXTRA) */
u8 fan_div[3]; /* Register encoding, shifted right */
@@ -704,11 +709,16 @@ static struct it87_data *it87_update_device(struct device *dev)
IT87_REG_FANX_MIN[i]) << 8;
}
}
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < 6; i++) {
if (!(data->has_temp & (1 << i)))
continue;
data->temp[i][0] =
it87_read_value(data, IT87_REG_TEMP(i));
+
+ /* No limits/offset for additional sensors */
+ if (i >= 3)
+ continue;
+
data->temp[i][1] =
it87_read_value(data, IT87_REG_TEMP_LOW(i));
data->temp[i][2] =
@@ -848,7 +858,7 @@ static SENSOR_DEVICE_ATTR_2(in7_max, S_IRUGO | S_IWUSR, show_in, set_in,
static SENSOR_DEVICE_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 8, 0);
static SENSOR_DEVICE_ATTR_2(in9_input, S_IRUGO, show_in, NULL, 9, 0);

-/* 3 temperatures */
+/* Up to 6 temperatures */
static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -921,6 +931,9 @@ static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
2, 2);
static SENSOR_DEVICE_ATTR_2(temp3_offset, S_IRUGO | S_IWUSR, show_temp,
set_temp, 2, 3);
+static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, 0);
+static SENSOR_DEVICE_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, 0);
+static SENSOR_DEVICE_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, 0);

static ssize_t show_temp_type(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -1828,6 +1841,11 @@ static umode_t it87_temp_is_visible(struct kobject *kobj,
int i = index / 7; /* temperature index */
int a = index % 7; /* attribute index */

+ if (index >= 21) {
+ i = index - 21 + 3;
+ a = 0;
+ }
+
if (!(data->has_temp & (1 << i)))
return 0;

@@ -1849,7 +1867,7 @@ static struct attribute *it87_attributes_temp[] = {
&sensor_dev_attr_temp1_offset.dev_attr.attr, /* 5 */
&sensor_dev_attr_temp1_beep.dev_attr.attr, /* 6 */

- &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr, /* 7 */
&sensor_dev_attr_temp2_max.dev_attr.attr,
&sensor_dev_attr_temp2_min.dev_attr.attr,
&sensor_dev_attr_temp2_type.dev_attr.attr,
@@ -1857,7 +1875,7 @@ static struct attribute *it87_attributes_temp[] = {
&sensor_dev_attr_temp2_offset.dev_attr.attr,
&sensor_dev_attr_temp2_beep.dev_attr.attr,

- &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr, /* 14 */
&sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp3_min.dev_attr.attr,
&sensor_dev_attr_temp3_type.dev_attr.attr,
@@ -1865,6 +1883,9 @@ static struct attribute *it87_attributes_temp[] = {
&sensor_dev_attr_temp3_offset.dev_attr.attr,
&sensor_dev_attr_temp3_beep.dev_attr.attr,

+ &sensor_dev_attr_temp4_input.dev_attr.attr, /* 21 */
+ &sensor_dev_attr_temp5_input.dev_attr.attr,
+ &sensor_dev_attr_temp6_input.dev_attr.attr,
NULL
};

@@ -2710,6 +2731,17 @@ static int it87_probe(struct platform_device *pdev)
data->in_internal = sio_data->internal;
data->has_in = 0x3ff & ~sio_data->skip_in;

+ if (has_six_temp(data)) {
+ u8 reg = it87_read_value(data, IT87_REG_TEMP456_ENABLE);
+
+ if ((reg & 0x03) >= 0x02)
+ data->has_temp |= (1 << 3);
+ if (((reg >> 2) & 0x03) >= 0x02)
+ data->has_temp |= (1 << 4);
+ if (((reg >> 4) & 0x03) >= 0x02)
+ data->has_temp |= (1 << 5);
+ }
+
data->has_beep = !!sio_data->beep_pin;

/* Initialize the IT87 chip */
--
2.1.4
Guenter Roeck
2016-01-27 02:03:38 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

Convert to use devm_hwmon_device_register_with_groups to simplify
code and reduce code size. This also attaches sysfs attributes
to the hwmon device and no longer to the platform device.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 93 +++++++++++-----------------------------------------
1 file changed, 19 insertions(+), 74 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index e4fb466fd9c3..e02c972ef81e 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -458,7 +458,7 @@ struct it87_sio_data {
* The structure is dynamically allocated.
*/
struct it87_data {
- struct device *hwmon_dev;
+ const struct attribute_group *groups[7];
enum chips type;
u16 features;
u8 peci_mask;
@@ -1739,14 +1739,6 @@ static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 2);
/* AVCC3 */
static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 0);

-static ssize_t show_name(struct device *dev, struct device_attribute
- *devattr, char *buf)
-{
- struct it87_data *data = dev_get_drvdata(dev);
- return sprintf(buf, "%s\n", data->name);
-}
-static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
-
static umode_t it87_in_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
@@ -1887,10 +1879,10 @@ static umode_t it87_is_visible(struct kobject *kobj,
struct device *dev = container_of(kobj, struct device, kobj);
struct it87_data *data = dev_get_drvdata(dev);

- if ((index == 3 || index == 4) && !data->has_vid)
+ if ((index == 2 || index == 3) && !data->has_vid)
return 0;

- if (index > 4 && !(data->in_internal & (1 << (index - 5))))
+ if (index > 3 && !(data->in_internal & (1 << (index - 4))))
return 0;

return attr->mode;
@@ -1899,10 +1891,9 @@ static umode_t it87_is_visible(struct kobject *kobj,
static struct attribute *it87_attributes[] = {
&dev_attr_alarms.attr,
&sensor_dev_attr_intrusion0_alarm.dev_attr.attr,
- &dev_attr_name.attr,
- &dev_attr_vrm.attr, /* 3 */
- &dev_attr_cpu0_vid.attr, /* 4 */
- &sensor_dev_attr_in3_label.dev_attr.attr, /* 5 .. 8 */
+ &dev_attr_vrm.attr, /* 2 */
+ &dev_attr_cpu0_vid.attr, /* 3 */
+ &sensor_dev_attr_in3_label.dev_attr.attr, /* 4 .. 7 */
&sensor_dev_attr_in7_label.dev_attr.attr,
&sensor_dev_attr_in8_label.dev_attr.attr,
&sensor_dev_attr_in9_label.dev_attr.attr,
@@ -2460,16 +2451,6 @@ exit:
return err;
}

-static void it87_remove_files(struct device *dev)
-{
- sysfs_remove_group(&dev->kobj, &it87_group);
- sysfs_remove_group(&dev->kobj, &it87_group_in);
- sysfs_remove_group(&dev->kobj, &it87_group_temp);
- sysfs_remove_group(&dev->kobj, &it87_group_fan);
- sysfs_remove_group(&dev->kobj, &it87_group_pwm);
- sysfs_remove_group(&dev->kobj, &it87_group_auto_pwm);
-}
-
/* Called when we have found a new IT87. */
static void it87_init_device(struct platform_device *pdev)
{
@@ -2646,7 +2627,7 @@ static int it87_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct it87_sio_data *sio_data = dev_get_platdata(dev);
int enable_pwm_interface;
- int err = 0;
+ struct device *hwmon_dev;

res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT,
@@ -2666,7 +2647,6 @@ static int it87_probe(struct platform_device *pdev)
data->features = it87_devices[sio_data->type].features;
data->peci_mask = it87_devices[sio_data->type].peci_mask;
data->old_peci_mask = it87_devices[sio_data->type].old_peci_mask;
- data->name = it87_devices[sio_data->type].name;
/*
* IT8705F Datasheet 0.4.1, 3h == Version G.
* IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J.
@@ -2742,59 +2722,25 @@ static int it87_probe(struct platform_device *pdev)
data->vid = sio_data->vid_value;
}

- /* Register sysfs hooks */
- err = sysfs_create_group(&dev->kobj, &it87_group);
- if (err)
- return err;
-
- err = sysfs_create_group(&dev->kobj, &it87_group_in);
- if (err)
- goto error;
-
- err = sysfs_create_group(&dev->kobj, &it87_group_temp);
- if (err)
- goto error;
-
- err = sysfs_create_group(&dev->kobj, &it87_group_fan);
- if (err)
- goto error;
+ /* Prepare for sysfs hooks */
+ data->groups[0] = &it87_group;
+ data->groups[1] = &it87_group_in;
+ data->groups[2] = &it87_group_temp;
+ data->groups[3] = &it87_group_fan;

if (enable_pwm_interface) {
data->has_pwm = (1 << ARRAY_SIZE(IT87_REG_PWM)) - 1;
data->has_pwm &= ~sio_data->skip_pwm;

- err = sysfs_create_group(&dev->kobj, &it87_group_pwm);
- if (err)
- goto error;
- if (has_old_autopwm(data)) {
- err = sysfs_create_group(&dev->kobj,
- &it87_group_auto_pwm);
- if (err)
- goto error;
- }
- }
-
- data->hwmon_dev = hwmon_device_register(dev);
- if (IS_ERR(data->hwmon_dev)) {
- err = PTR_ERR(data->hwmon_dev);
- goto error;
+ data->groups[4] = &it87_group_pwm;
+ if (has_old_autopwm(data))
+ data->groups[5] = &it87_group_auto_pwm;
}

- return 0;
-
-error:
- it87_remove_files(dev);
- return err;
-}
-
-static int it87_remove(struct platform_device *pdev)
-{
- struct it87_data *data = platform_get_drvdata(pdev);
-
- hwmon_device_unregister(data->hwmon_dev);
- it87_remove_files(&pdev->dev);
-
- return 0;
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev,
+ it87_devices[sio_data->type].name,
+ data, data->groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}

static struct platform_driver it87_driver = {
@@ -2802,7 +2748,6 @@ static struct platform_driver it87_driver = {
.name = DRVNAME,
},
.probe = it87_probe,
- .remove = it87_remove,
};

static int __init it87_device_add(int index, unsigned short address,
--
2.1.4
Guenter Roeck
2016-01-27 02:03:37 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

Use is_visible to determine if attributes should be generated or not.
This simplifies the code and reduces object size by about 120 bytes
on x86_64.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 81 +++++++++++++++++++++-------------------------------
1 file changed, 33 insertions(+), 48 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 0c13d640bcc7..e4fb466fd9c3 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -471,6 +471,7 @@ struct it87_data {
unsigned long last_updated; /* In jiffies */

u16 in_scaled; /* Internal voltage sensors are scaled */
+ u16 in_internal; /* Bitfield, internal sensors (for labels) */
u16 has_in; /* Bitfield, voltage sensors enabled */
u8 in[10][3]; /* [nr][0]=in, [1]=min, [2]=max */
u8 has_fan; /* Bitfield, fans enabled */
@@ -480,6 +481,7 @@ struct it87_data {
u8 sensor; /* Register value (IT87_REG_TEMP_ENABLE) */
u8 extra; /* Register value (IT87_REG_TEMP_EXTRA) */
u8 fan_div[3]; /* Register encoding, shifted right */
+ bool has_vid; /* True if VID supported */
u8 vid; /* Register encoding, combined */
u8 vrm;
u32 alarms; /* Register encoding, combined */
@@ -1879,15 +1881,37 @@ static const struct attribute_group it87_group_temp = {
.is_visible = it87_temp_is_visible,
};

+static umode_t it87_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct it87_data *data = dev_get_drvdata(dev);
+
+ if ((index == 3 || index == 4) && !data->has_vid)
+ return 0;
+
+ if (index > 4 && !(data->in_internal & (1 << (index - 5))))
+ return 0;
+
+ return attr->mode;
+}
+
static struct attribute *it87_attributes[] = {
&dev_attr_alarms.attr,
&sensor_dev_attr_intrusion0_alarm.dev_attr.attr,
&dev_attr_name.attr,
+ &dev_attr_vrm.attr, /* 3 */
+ &dev_attr_cpu0_vid.attr, /* 4 */
+ &sensor_dev_attr_in3_label.dev_attr.attr, /* 5 .. 8 */
+ &sensor_dev_attr_in7_label.dev_attr.attr,
+ &sensor_dev_attr_in8_label.dev_attr.attr,
+ &sensor_dev_attr_in9_label.dev_attr.attr,
NULL
};

static const struct attribute_group it87_group = {
.attrs = it87_attributes,
+ .is_visible = it87_is_visible,
};

static umode_t it87_fan_is_visible(struct kobject *kobj,
@@ -2074,28 +2098,6 @@ static const struct attribute_group it87_group_auto_pwm = {
.is_visible = it87_auto_pwm_is_visible,
};

-static struct attribute *it87_attributes_vid[] = {
- &dev_attr_vrm.attr,
- &dev_attr_cpu0_vid.attr,
- NULL
-};
-
-static const struct attribute_group it87_group_vid = {
- .attrs = it87_attributes_vid,
-};
-
-static struct attribute *it87_attributes_label[] = {
- &sensor_dev_attr_in3_label.dev_attr.attr,
- &sensor_dev_attr_in7_label.dev_attr.attr,
- &sensor_dev_attr_in8_label.dev_attr.attr,
- &sensor_dev_attr_in9_label.dev_attr.attr,
- NULL
-};
-
-static const struct attribute_group it87_group_label = {
- .attrs = it87_attributes_label,
-};
-
/* SuperIO detection - will change isa_address if a chip is found */
static int __init it87_find(int sioaddr, unsigned short *address,
struct it87_sio_data *sio_data)
@@ -2460,18 +2462,12 @@ exit:

static void it87_remove_files(struct device *dev)
{
- struct it87_sio_data *sio_data = dev_get_platdata(dev);
-
sysfs_remove_group(&dev->kobj, &it87_group);
sysfs_remove_group(&dev->kobj, &it87_group_in);
sysfs_remove_group(&dev->kobj, &it87_group_temp);
sysfs_remove_group(&dev->kobj, &it87_group_fan);
sysfs_remove_group(&dev->kobj, &it87_group_pwm);
sysfs_remove_group(&dev->kobj, &it87_group_auto_pwm);
-
- if (!sio_data->skip_vid)
- sysfs_remove_group(&dev->kobj, &it87_group_vid);
- sysfs_remove_group(&dev->kobj, &it87_group_label);
}

/* Called when we have found a new IT87. */
@@ -2649,8 +2645,8 @@ static int it87_probe(struct platform_device *pdev)
struct resource *res;
struct device *dev = &pdev->dev;
struct it87_sio_data *sio_data = dev_get_platdata(dev);
- int err = 0, i;
int enable_pwm_interface;
+ int err = 0;

res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT,
@@ -2731,6 +2727,7 @@ static int it87_probe(struct platform_device *pdev)
data->has_temp &= ~(1 << 2);
}

+ data->in_internal = sio_data->internal;
data->has_in = 0x3ff & ~sio_data->skip_in;

data->has_beep = !!sio_data->beep_pin;
@@ -2738,6 +2735,13 @@ static int it87_probe(struct platform_device *pdev)
/* Initialize the IT87 chip */
it87_init_device(pdev);

+ if (!sio_data->skip_vid) {
+ data->has_vid = true;
+ data->vrm = vid_which_vrm();
+ /* VID reading from Super-I/O config space if available */
+ data->vid = sio_data->vid_value;
+ }
+
/* Register sysfs hooks */
err = sysfs_create_group(&dev->kobj, &it87_group);
if (err)
@@ -2770,25 +2774,6 @@ static int it87_probe(struct platform_device *pdev)
}
}

- if (!sio_data->skip_vid) {
- data->vrm = vid_which_vrm();
- /* VID reading from Super-I/O config space if available */
- data->vid = sio_data->vid_value;
- err = sysfs_create_group(&dev->kobj, &it87_group_vid);
- if (err)
- goto error;
- }
-
- /* Export labels for internal sensors */
- for (i = 0; i < 4; i++) {
- if (!(sio_data->internal & (1 << i)))
- continue;
- err = sysfs_create_file(&dev->kobj,
- it87_attributes_label[i]);
- if (err)
- goto error;
- }
-
data->hwmon_dev = hwmon_device_register(dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
--
2.1.4
Guenter Roeck
2016-01-27 02:03:36 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

Simplify code and reduce object size by about 250 bytes on x86_64.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 137 ++++++++++++++++++++++++---------------------------
1 file changed, 65 insertions(+), 72 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index e70d227c2bf8..0c13d640bcc7 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -498,6 +498,7 @@ struct it87_data {
* is no longer needed, but it is still done to keep the driver
* simple.
*/
+ u8 has_pwm; /* Bitfield, pwm control enabled */
u8 pwm_ctrl[6]; /* Register value */
u8 pwm_duty[6]; /* Manual PWM value set by user */
u8 pwm_temp_map[6]; /* PWM to temp. chan. mapping (bits 1-0) */
@@ -1340,15 +1341,6 @@ static ssize_t set_pwm_temp_map(struct device *dev,
long val;
u8 reg;

- /*
- * This check can go away if we ever support automatic fan speed
- * control on newer chips.
- */
- if (!has_old_autopwm(data)) {
- dev_notice(dev, "Mapping change disabled for safety reasons\n");
- return -EINVAL;
- }
-
if (kstrtol(buf, 10, &val) < 0)
return -EINVAL;

@@ -1482,7 +1474,7 @@ static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0);
static SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO | S_IWUSR, show_pwm_freq,
set_pwm_freq, 0);
-static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IRUGO | S_IWUSR,
+static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IRUGO,
show_pwm_temp_map, set_pwm_temp_map, 0);
static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR,
show_auto_pwm, set_auto_pwm, 0, 0);
@@ -1507,7 +1499,7 @@ static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 1);
static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 1);
static SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO, show_pwm_freq, set_pwm_freq, 1);
-static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IRUGO | S_IWUSR,
+static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IRUGO,
show_pwm_temp_map, set_pwm_temp_map, 1);
static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR,
show_auto_pwm, set_auto_pwm, 1, 0);
@@ -1532,7 +1524,7 @@ static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 2);
static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 2);
static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO, show_pwm_freq, NULL, 2);
-static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IRUGO | S_IWUSR,
+static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IRUGO,
show_pwm_temp_map, set_pwm_temp_map, 2);
static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR,
show_auto_pwm, set_auto_pwm, 2, 0);
@@ -1557,21 +1549,21 @@ static SENSOR_DEVICE_ATTR(pwm4_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 3);
static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 3);
static SENSOR_DEVICE_ATTR(pwm4_freq, S_IRUGO, show_pwm_freq, NULL, 3);
-static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IRUGO | S_IWUSR,
+static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IRUGO,
show_pwm_temp_map, set_pwm_temp_map, 3);

static SENSOR_DEVICE_ATTR(pwm5_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 4);
static SENSOR_DEVICE_ATTR(pwm5, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 4);
static SENSOR_DEVICE_ATTR(pwm5_freq, S_IRUGO, show_pwm_freq, NULL, 4);
-static SENSOR_DEVICE_ATTR(pwm5_auto_channels_temp, S_IRUGO | S_IWUSR,
+static SENSOR_DEVICE_ATTR(pwm5_auto_channels_temp, S_IRUGO,
show_pwm_temp_map, set_pwm_temp_map, 4);

static SENSOR_DEVICE_ATTR(pwm6_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 5);
static SENSOR_DEVICE_ATTR(pwm6, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 5);
static SENSOR_DEVICE_ATTR(pwm6_freq, S_IRUGO, show_pwm_freq, NULL, 5);
-static SENSOR_DEVICE_ATTR(pwm6_auto_channels_temp, S_IRUGO | S_IWUSR,
+static SENSOR_DEVICE_ATTR(pwm6_auto_channels_temp, S_IRUGO,
show_pwm_temp_map, set_pwm_temp_map, 5);

/* Alarms */
@@ -1969,67 +1961,81 @@ static const struct attribute_group it87_group_fan = {
.is_visible = it87_fan_is_visible,
};

-static struct attribute *it87_attributes_pwm[6][4+1] = { {
+static umode_t it87_pwm_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct it87_data *data = dev_get_drvdata(dev);
+ int i = index / 4; /* pwm index */
+ int a = index % 4; /* attribute index */
+
+ if (!(data->has_pwm & (1 << i)))
+ return 0;
+
+ /* pwmX_auto_channels_temp is only writable for old auto pwm */
+ if (a == 3 && has_old_autopwm(data))
+ return attr->mode | S_IWUSR;
+
+ /* pwm2_freq is writable if there are two pwm frequency selects */
+ if (has_pwm_freq2(data) && i == 1 && a == 2)
+ return attr->mode | S_IWUSR;
+
+ return attr->mode;
+}
+
+static struct attribute *it87_attributes_pwm[] = {
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
&sensor_dev_attr_pwm1.dev_attr.attr,
&sensor_dev_attr_pwm1_freq.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
- NULL
-}, {
+
&sensor_dev_attr_pwm2_enable.dev_attr.attr,
&sensor_dev_attr_pwm2.dev_attr.attr,
&sensor_dev_attr_pwm2_freq.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
- NULL
-}, {
+
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
&sensor_dev_attr_pwm3.dev_attr.attr,
&sensor_dev_attr_pwm3_freq.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
- NULL
-}, {
+
&sensor_dev_attr_pwm4_enable.dev_attr.attr,
&sensor_dev_attr_pwm4.dev_attr.attr,
&sensor_dev_attr_pwm4_freq.dev_attr.attr,
&sensor_dev_attr_pwm4_auto_channels_temp.dev_attr.attr,
- NULL
-}, {
+
&sensor_dev_attr_pwm5_enable.dev_attr.attr,
&sensor_dev_attr_pwm5.dev_attr.attr,
&sensor_dev_attr_pwm5_freq.dev_attr.attr,
&sensor_dev_attr_pwm5_auto_channels_temp.dev_attr.attr,
- NULL
-}, {
+
&sensor_dev_attr_pwm6_enable.dev_attr.attr,
&sensor_dev_attr_pwm6.dev_attr.attr,
&sensor_dev_attr_pwm6_freq.dev_attr.attr,
&sensor_dev_attr_pwm6_auto_channels_temp.dev_attr.attr,
+
NULL
-} };
+};

-static umode_t pwm_attribute_mode(struct kobject *kobj, struct attribute *attr,
- int index)
+static const struct attribute_group it87_group_pwm = {
+ .attrs = it87_attributes_pwm,
+ .is_visible = it87_pwm_is_visible,
+};
+
+static umode_t it87_auto_pwm_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct it87_data *data = dev_get_drvdata(dev);
+ int i = index / 9; /* pwm index */

- if (has_pwm_freq2(data) && index == 2)
- return attr->mode | S_IWUSR;
+ if (!(data->has_pwm & (1 << i)))
+ return 0;

return attr->mode;
}

-static const struct attribute_group it87_group_pwm[6] = {
- { .attrs = it87_attributes_pwm[0] },
- { .attrs = it87_attributes_pwm[1],
- .is_visible = pwm_attribute_mode, },
- { .attrs = it87_attributes_pwm[2] },
- { .attrs = it87_attributes_pwm[3] },
- { .attrs = it87_attributes_pwm[4] },
- { .attrs = it87_attributes_pwm[5] },
-};
-
-static struct attribute *it87_attributes_autopwm[3][9+1] = { {
+static struct attribute *it87_attributes_auto_pwm[] = {
&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr,
@@ -2039,8 +2045,7 @@ static struct attribute *it87_attributes_autopwm[3][9+1] = { {
&sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr,
- NULL
-}, {
+
&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point3_pwm.dev_attr.attr,
@@ -2050,8 +2055,7 @@ static struct attribute *it87_attributes_autopwm[3][9+1] = { {
&sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point4_temp.dev_attr.attr,
- NULL
-}, {
+
&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point3_pwm.dev_attr.attr,
@@ -2061,13 +2065,13 @@ static struct attribute *it87_attributes_autopwm[3][9+1] = { {
&sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point4_temp.dev_attr.attr,
- NULL
-} };

-static const struct attribute_group it87_group_autopwm[3] = {
- { .attrs = it87_attributes_autopwm[0] },
- { .attrs = it87_attributes_autopwm[1] },
- { .attrs = it87_attributes_autopwm[2] },
+ NULL,
+};
+
+static const struct attribute_group it87_group_auto_pwm = {
+ .attrs = it87_attributes_auto_pwm,
+ .is_visible = it87_auto_pwm_is_visible,
};

static struct attribute *it87_attributes_vid[] = {
@@ -2456,23 +2460,15 @@ exit:

static void it87_remove_files(struct device *dev)
{
- struct it87_data *data = dev_get_drvdata(dev);
struct it87_sio_data *sio_data = dev_get_platdata(dev);
- int i;

sysfs_remove_group(&dev->kobj, &it87_group);
sysfs_remove_group(&dev->kobj, &it87_group_in);
sysfs_remove_group(&dev->kobj, &it87_group_temp);
sysfs_remove_group(&dev->kobj, &it87_group_fan);
+ sysfs_remove_group(&dev->kobj, &it87_group_pwm);
+ sysfs_remove_group(&dev->kobj, &it87_group_auto_pwm);

- for (i = 0; i < 6; i++) {
- if (sio_data->skip_pwm & (1 << i))
- continue;
- sysfs_remove_group(&dev->kobj, &it87_group_pwm[i]);
- if (has_old_autopwm(data))
- sysfs_remove_group(&dev->kobj,
- &it87_group_autopwm[i]);
- }
if (!sio_data->skip_vid)
sysfs_remove_group(&dev->kobj, &it87_group_vid);
sysfs_remove_group(&dev->kobj, &it87_group_label);
@@ -2760,18 +2756,15 @@ static int it87_probe(struct platform_device *pdev)
goto error;

if (enable_pwm_interface) {
- for (i = 0; i < 6; i++) {
- if (sio_data->skip_pwm & (1 << i))
- continue;
- err = sysfs_create_group(&dev->kobj,
- &it87_group_pwm[i]);
- if (err)
- goto error;
+ data->has_pwm = (1 << ARRAY_SIZE(IT87_REG_PWM)) - 1;
+ data->has_pwm &= ~sio_data->skip_pwm;

- if (!has_old_autopwm(data))
- continue;
+ err = sysfs_create_group(&dev->kobj, &it87_group_pwm);
+ if (err)
+ goto error;
+ if (has_old_autopwm(data)) {
err = sysfs_create_group(&dev->kobj,
- &it87_group_autopwm[i]);
+ &it87_group_auto_pwm);
if (err)
goto error;
}
--
2.1.4
Guenter Roeck
2016-01-27 02:03:35 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

Simplify code and reduce object size by almost 500 bytes on x86_64.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 140 ++++++++++++++++++++-------------------------------
1 file changed, 55 insertions(+), 85 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index c7feea9a6f80..e70d227c2bf8 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -1898,51 +1898,75 @@ static const struct attribute_group it87_group = {
.attrs = it87_attributes,
};

-static struct attribute *it87_attributes_fan[6][3+1] = { {
+static umode_t it87_fan_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct it87_data *data = dev_get_drvdata(dev);
+ int i = index / 5; /* fan index */
+ int a = index % 5; /* attribute index */
+
+ if (index >= 15) { /* fan 4..6 don't have divisor attributes */
+ i = (index - 15) / 4 + 3;
+ a = (index - 15) % 4;
+ }
+
+ if (!(data->has_fan & (1 << i)))
+ return 0;
+
+ if (a == 3) { /* beep */
+ if (!data->has_beep)
+ return 0;
+ /* first fan beep attribute is writable */
+ if (i == __ffs(data->has_fan))
+ return attr->mode | S_IWUSR;
+ }
+
+ if (a == 4 && has_16bit_fans(data)) /* divisor */
+ return 0;
+
+ return attr->mode;
+}
+
+static struct attribute *it87_attributes_fan[] = {
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
&sensor_dev_attr_fan1_alarm.dev_attr.attr,
- NULL
-}, {
+ &sensor_dev_attr_fan1_beep.dev_attr.attr, /* 3 */
+ &sensor_dev_attr_fan1_div.dev_attr.attr, /* 4 */
+
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan2_min.dev_attr.attr,
&sensor_dev_attr_fan2_alarm.dev_attr.attr,
- NULL
-}, {
+ &sensor_dev_attr_fan2_beep.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr, /* 9 */
+
&sensor_dev_attr_fan3_input.dev_attr.attr,
&sensor_dev_attr_fan3_min.dev_attr.attr,
&sensor_dev_attr_fan3_alarm.dev_attr.attr,
- NULL
-}, {
- &sensor_dev_attr_fan4_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_beep.dev_attr.attr,
+ &sensor_dev_attr_fan3_div.dev_attr.attr, /* 14 */
+
+ &sensor_dev_attr_fan4_input.dev_attr.attr, /* 15 */
&sensor_dev_attr_fan4_min.dev_attr.attr,
&sensor_dev_attr_fan4_alarm.dev_attr.attr,
- NULL
-}, {
- &sensor_dev_attr_fan5_input.dev_attr.attr,
+ &sensor_dev_attr_fan4_beep.dev_attr.attr,
+
+ &sensor_dev_attr_fan5_input.dev_attr.attr, /* 19 */
&sensor_dev_attr_fan5_min.dev_attr.attr,
&sensor_dev_attr_fan5_alarm.dev_attr.attr,
- NULL
-}, {
- &sensor_dev_attr_fan6_input.dev_attr.attr,
+ &sensor_dev_attr_fan5_beep.dev_attr.attr,
+
+ &sensor_dev_attr_fan6_input.dev_attr.attr, /* 23 */
&sensor_dev_attr_fan6_min.dev_attr.attr,
&sensor_dev_attr_fan6_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan6_beep.dev_attr.attr,
NULL
-} };
-
-static const struct attribute_group it87_group_fan[6] = {
- { .attrs = it87_attributes_fan[0] },
- { .attrs = it87_attributes_fan[1] },
- { .attrs = it87_attributes_fan[2] },
- { .attrs = it87_attributes_fan[3] },
- { .attrs = it87_attributes_fan[4] },
- { .attrs = it87_attributes_fan[5] },
};

-static const struct attribute *it87_attributes_fan_div[] = {
- &sensor_dev_attr_fan1_div.dev_attr.attr,
- &sensor_dev_attr_fan2_div.dev_attr.attr,
- &sensor_dev_attr_fan3_div.dev_attr.attr,
+static const struct attribute_group it87_group_fan = {
+ .attrs = it87_attributes_fan,
+ .is_visible = it87_fan_is_visible,
};

static struct attribute *it87_attributes_pwm[6][4+1] = { {
@@ -2046,15 +2070,6 @@ static const struct attribute_group it87_group_autopwm[3] = {
{ .attrs = it87_attributes_autopwm[2] },
};

-static struct attribute *it87_attributes_fan_beep[] = {
- &sensor_dev_attr_fan1_beep.dev_attr.attr,
- &sensor_dev_attr_fan2_beep.dev_attr.attr,
- &sensor_dev_attr_fan3_beep.dev_attr.attr,
- &sensor_dev_attr_fan4_beep.dev_attr.attr,
- &sensor_dev_attr_fan5_beep.dev_attr.attr,
- &sensor_dev_attr_fan6_beep.dev_attr.attr,
-};
-
static struct attribute *it87_attributes_vid[] = {
&dev_attr_vrm.attr,
&dev_attr_cpu0_vid.attr,
@@ -2448,19 +2463,9 @@ static void it87_remove_files(struct device *dev)
sysfs_remove_group(&dev->kobj, &it87_group);
sysfs_remove_group(&dev->kobj, &it87_group_in);
sysfs_remove_group(&dev->kobj, &it87_group_temp);
+ sysfs_remove_group(&dev->kobj, &it87_group_fan);

for (i = 0; i < 6; i++) {
- if (!(data->has_fan & (1 << i)))
- continue;
- sysfs_remove_group(&dev->kobj, &it87_group_fan[i]);
- if (sio_data->beep_pin)
- sysfs_remove_file(&dev->kobj,
- it87_attributes_fan_beep[i]);
- if (i < 3 && !has_16bit_fans(data))
- sysfs_remove_file(&dev->kobj,
- it87_attributes_fan_div[i]);
- }
- for (i = 0; i < 6; i++) {
if (sio_data->skip_pwm & (1 << i))
continue;
sysfs_remove_group(&dev->kobj, &it87_group_pwm[i]);
@@ -2650,7 +2655,6 @@ static int it87_probe(struct platform_device *pdev)
struct it87_sio_data *sio_data = dev_get_platdata(dev);
int err = 0, i;
int enable_pwm_interface;
- int fan_beep_need_rw;

res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT,
@@ -2751,43 +2755,9 @@ static int it87_probe(struct platform_device *pdev)
if (err)
goto error;

- /* Do not create fan files for disabled fans */
- fan_beep_need_rw = 1;
- for (i = 0; i < 6; i++) {
- if (!(data->has_fan & (1 << i)))
- continue;
- err = sysfs_create_group(&dev->kobj, &it87_group_fan[i]);
- if (err)
- goto error;
-
- if (i < 3 && !has_16bit_fans(data)) {
- err = sysfs_create_file(&dev->kobj,
- it87_attributes_fan_div[i]);
- if (err)
- goto error;
- }
-
- if (sio_data->beep_pin) {
- err = sysfs_create_file(&dev->kobj,
- it87_attributes_fan_beep[i]);
- if (err)
- goto error;
- if (!fan_beep_need_rw)
- continue;
-
- /*
- * As we have a single beep enable bit for all fans,
- * only the first enabled fan has a writable attribute
- * for it.
- */
- if (sysfs_chmod_file(&dev->kobj,
- it87_attributes_fan_beep[i],
- S_IRUGO | S_IWUSR))
- dev_dbg(dev, "chmod +w fan%d_beep failed\n",
- i + 1);
- fan_beep_need_rw = 0;
- }
- }
+ err = sysfs_create_group(&dev->kobj, &it87_group_fan);
+ if (err)
+ goto error;

if (enable_pwm_interface) {
for (i = 0; i < 6; i++) {
--
2.1.4
Guenter Roeck
2016-01-27 02:03:34 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

Simplify code and reduce object size by more than 200 bytes on x86_64.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 87 ++++++++++++++++++++++------------------------------
1 file changed, 36 insertions(+), 51 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 81c11d1d67e2..c7feea9a6f80 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -1834,40 +1834,57 @@ static const struct attribute_group it87_group_in = {
.is_visible = it87_in_is_visible,
};

-static struct attribute *it87_attributes_temp[3][6] = {
+static umode_t it87_temp_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct it87_data *data = dev_get_drvdata(dev);
+ int i = index / 7; /* temperature index */
+ int a = index % 7; /* attribute index */
+
+ if (!(data->has_temp & (1 << i)))
+ return 0;
+
+ if (a == 5 && !has_temp_offset(data))
+ return 0;
+
+ if (a == 6 && !data->has_beep)
+ return 0;
+
+ return attr->mode;
+}
+
+static struct attribute *it87_attributes_temp[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_min.dev_attr.attr,
&sensor_dev_attr_temp1_type.dev_attr.attr,
&sensor_dev_attr_temp1_alarm.dev_attr.attr,
- NULL
-} , {
+ &sensor_dev_attr_temp1_offset.dev_attr.attr, /* 5 */
+ &sensor_dev_attr_temp1_beep.dev_attr.attr, /* 6 */
+
&sensor_dev_attr_temp2_input.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
&sensor_dev_attr_temp2_min.dev_attr.attr,
&sensor_dev_attr_temp2_type.dev_attr.attr,
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
- NULL
-} , {
+ &sensor_dev_attr_temp2_offset.dev_attr.attr,
+ &sensor_dev_attr_temp2_beep.dev_attr.attr,
+
&sensor_dev_attr_temp3_input.dev_attr.attr,
&sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp3_min.dev_attr.attr,
&sensor_dev_attr_temp3_type.dev_attr.attr,
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
- NULL
-} };
+ &sensor_dev_attr_temp3_offset.dev_attr.attr,
+ &sensor_dev_attr_temp3_beep.dev_attr.attr,

-static const struct attribute_group it87_group_temp[3] = {
- { .attrs = it87_attributes_temp[0] },
- { .attrs = it87_attributes_temp[1] },
- { .attrs = it87_attributes_temp[2] },
+ NULL
};

-static struct attribute *it87_attributes_temp_offset[] = {
- &sensor_dev_attr_temp1_offset.dev_attr.attr,
- &sensor_dev_attr_temp2_offset.dev_attr.attr,
- &sensor_dev_attr_temp3_offset.dev_attr.attr,
+static const struct attribute_group it87_group_temp = {
+ .attrs = it87_attributes_temp,
+ .is_visible = it87_temp_is_visible,
};

static struct attribute *it87_attributes[] = {
@@ -1881,12 +1898,6 @@ static const struct attribute_group it87_group = {
.attrs = it87_attributes,
};

-static struct attribute *it87_attributes_temp_beep[] = {
- &sensor_dev_attr_temp1_beep.dev_attr.attr,
- &sensor_dev_attr_temp2_beep.dev_attr.attr,
- &sensor_dev_attr_temp3_beep.dev_attr.attr,
-};
-
static struct attribute *it87_attributes_fan[6][3+1] = { {
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
@@ -2436,18 +2447,8 @@ static void it87_remove_files(struct device *dev)

sysfs_remove_group(&dev->kobj, &it87_group);
sysfs_remove_group(&dev->kobj, &it87_group_in);
+ sysfs_remove_group(&dev->kobj, &it87_group_temp);

- for (i = 0; i < 3; i++) {
- if (!(data->has_temp & (1 << i)))
- continue;
- sysfs_remove_group(&dev->kobj, &it87_group_temp[i]);
- if (has_temp_offset(data))
- sysfs_remove_file(&dev->kobj,
- it87_attributes_temp_offset[i]);
- if (sio_data->beep_pin)
- sysfs_remove_file(&dev->kobj,
- it87_attributes_temp_beep[i]);
- }
for (i = 0; i < 6; i++) {
if (!(data->has_fan & (1 << i)))
continue;
@@ -2746,25 +2747,9 @@ static int it87_probe(struct platform_device *pdev)
if (err)
goto error;

- for (i = 0; i < 3; i++) {
- if (!(data->has_temp & (1 << i)))
- continue;
- err = sysfs_create_group(&dev->kobj, &it87_group_temp[i]);
- if (err)
- goto error;
- if (has_temp_offset(data)) {
- err = sysfs_create_file(&dev->kobj,
- it87_attributes_temp_offset[i]);
- if (err)
- goto error;
- }
- if (sio_data->beep_pin) {
- err = sysfs_create_file(&dev->kobj,
- it87_attributes_temp_beep[i]);
- if (err)
- goto error;
- }
- }
+ err = sysfs_create_group(&dev->kobj, &it87_group_temp);
+ if (err)
+ goto error;

/* Do not create fan files for disabled fans */
fan_beep_need_rw = 1;
--
2.1.4
Guenter Roeck
2016-01-27 02:03:28 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

Return directly on errors if there is no cleanup necessary.
Don't create an error message on memory allocation errors.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 68c8d98e711a..9b36987d7949 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -2898,14 +2898,11 @@ static int __init it87_device_add(unsigned short address,

err = acpi_check_resource_conflict(&res);
if (err)
- goto exit;
+ return err;

pdev = platform_device_alloc(DRVNAME, address);
- if (!pdev) {
- err = -ENOMEM;
- pr_err("Device allocation failed\n");
- goto exit;
- }
+ if (!pdev)
+ return -ENOMEM;

err = platform_device_add_resources(pdev, &res, 1);
if (err) {
@@ -2930,7 +2927,6 @@ static int __init it87_device_add(unsigned short address,

exit_device_put:
platform_device_put(pdev);
-exit:
return err;
}
--
2.1.4
Guenter Roeck
2016-01-27 02:03:25 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

AVCC3 is supported on IT8620E, similar to IT8603E. Add feature flag
to indicate AVCC3 support. Don't enable it for now on IT8620E since
it is unclear if this chip supports it correctly.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 1896e26df634..146f93584cde 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -233,6 +233,8 @@ static const u8 IT87_REG_TEMP_OFFSET[] = { 0x56, 0x57, 0x59 };
#define IT87_REG_VIN(nr) (0x20 + (nr))
#define IT87_REG_TEMP(nr) (0x29 + (nr))

+#define IT87_REG_AVCC3 0x2f
+
#define IT87_REG_VIN_MAX(nr) (0x30 + (nr) * 2)
#define IT87_REG_VIN_MIN(nr) (0x31 + (nr) * 2)
#define IT87_REG_TEMP_HIGH(nr) (0x40 + (nr) * 2)
@@ -269,6 +271,7 @@ struct it87_devices {
#define FEAT_IN7_INTERNAL (1 << 10) /* Set if in7 is internal */
#define FEAT_SIX_FANS (1 << 11) /* Supports six fans */
#define FEAT_10_9MV_ADC (1 << 12)
+#define FEAT_AVCC3 (1 << 13) /* Chip supports in9/AVCC3 */

static const struct it87_devices it87_devices[] = {
[it87] = {
@@ -389,7 +392,8 @@ static const struct it87_devices it87_devices[] = {
.name = "it8603",
.suffix = "E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
- | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL,
+ | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
+ | FEAT_AVCC3,
.peci_mask = 0x07,
},
[it8620] = {
@@ -419,6 +423,7 @@ static const struct it87_devices it87_devices[] = {
#define has_vid(data) ((data)->features & FEAT_VID)
#define has_in7_internal(data) ((data)->features & FEAT_IN7_INTERNAL)
#define has_six_fans(data) ((data)->features & FEAT_SIX_FANS)
+#define has_avcc3(data) ((data)->features & FEAT_AVCC3)

struct it87_sio_data {
enum chips type;
@@ -1548,7 +1553,7 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr,
static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0);
static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1);
static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 2);
-/* special AVCC3 IT8603E in9 */
+/* AVCC3 */
static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 0);

static ssize_t show_name(struct device *dev, struct device_attribute
@@ -1944,8 +1949,10 @@ static int __init it87_find(unsigned short *address,
/* in8 (Vbat) is always internal */
sio_data->internal |= (1 << 2);

- /* Only the IT8603E has in9 */
- if (sio_data->type != it8603)
+ /* in9 (AVCC3), always internal if supported */
+ if (has_avcc3(config))
+ sio_data->internal |= (1 << 3); /* in9 is AVCC */
+ else
sio_data->skip_in |= (1 << 9);

if (!has_vid(config))
@@ -2044,8 +2051,6 @@ static int __init it87_find(unsigned short *address,
sio_data->skip_in |= (1 << 5); /* No VIN5 */
sio_data->skip_in |= (1 << 6); /* No VIN6 */

- sio_data->internal |= (1 << 3); /* in9 is AVCC */
-
sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
} else if (sio_data->type == it8620) {
int reg;
@@ -2689,8 +2694,8 @@ static struct it87_data *it87_update_device(struct device *dev)
}
/* in8 (battery) has no limit registers */
data->in[8][0] = it87_read_value(data, IT87_REG_VIN(8));
- if (data->type == it8603)
- data->in[9][0] = it87_read_value(data, 0x2f);
+ if (has_avcc3(data))
+ data->in[9][0] = it87_read_value(data, IT87_REG_AVCC3);

for (i = 0; i < 6; i++) {
/* Skip disabled fans */
--
2.1.4
Guenter Roeck
2016-01-27 02:03:27 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

Recent chips have a separate register to select the pwm2 frequency.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 100 +++++++++++++++++++++++++++++++++++----------------
1 file changed, 69 insertions(+), 31 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 916d73630224..68c8d98e711a 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -274,6 +274,7 @@ struct it87_devices {
#define FEAT_10_9MV_ADC (1 << 12)
#define FEAT_AVCC3 (1 << 13) /* Chip supports in9/AVCC3 */
#define FEAT_SIX_PWM (1 << 14) /* Chip supports 6 pwm chn */
+#define FEAT_PWM_FREQ2 (1 << 15) /* Separate pwm freq 2 */

static const struct it87_devices it87_devices[] = {
[it87] = {
@@ -291,20 +292,22 @@ static const struct it87_devices it87_devices[] = {
.name = "it8716",
.suffix = "F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
- | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS,
+ | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2,
},
[it8718] = {
.name = "it8718",
.suffix = "F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
- | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS,
+ | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
+ | FEAT_PWM_FREQ2,
.old_peci_mask = 0x4,
},
[it8720] = {
.name = "it8720",
.suffix = "F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
- | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS,
+ | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
+ | FEAT_PWM_FREQ2,
.old_peci_mask = 0x4,
},
[it8721] = {
@@ -312,7 +315,8 @@ static const struct it87_devices it87_devices[] = {
.suffix = "F",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
- | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_IN7_INTERNAL,
+ | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_IN7_INTERNAL
+ | FEAT_PWM_FREQ2,
.peci_mask = 0x05,
.old_peci_mask = 0x02, /* Actually reports PCH */
},
@@ -321,7 +325,7 @@ static const struct it87_devices it87_devices[] = {
.suffix = "F",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
- | FEAT_IN7_INTERNAL,
+ | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2,
.peci_mask = 0x07,
},
[it8732] = {
@@ -337,7 +341,8 @@ static const struct it87_devices it87_devices[] = {
.name = "it8771",
.suffix = "E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
- | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL,
+ | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
+ | FEAT_PWM_FREQ2,
/* PECI: guesswork */
/* 12mV ADC (OHM) */
/* 16 bit fans (OHM) */
@@ -348,7 +353,8 @@ static const struct it87_devices it87_devices[] = {
.name = "it8772",
.suffix = "E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
- | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL,
+ | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
+ | FEAT_PWM_FREQ2,
/* PECI (coreboot) */
/* 12mV ADC (HWSensors4, OHM) */
/* 16 bit fans (HWSensors4, OHM) */
@@ -359,35 +365,37 @@ static const struct it87_devices it87_devices[] = {
.name = "it8781",
.suffix = "F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
- | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG,
+ | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
.old_peci_mask = 0x4,
},
[it8782] = {
.name = "it8782",
.suffix = "F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
- | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG,
+ | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
.old_peci_mask = 0x4,
},
[it8783] = {
.name = "it8783",
.suffix = "E/F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
- | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG,
+ | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
.old_peci_mask = 0x4,
},
[it8786] = {
.name = "it8786",
.suffix = "E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
- | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL,
+ | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
+ | FEAT_PWM_FREQ2,
.peci_mask = 0x07,
},
[it8790] = {
.name = "it8790",
.suffix = "E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
- | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL,
+ | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
+ | FEAT_PWM_FREQ2,
.peci_mask = 0x07,
},
[it8603] = {
@@ -395,7 +403,7 @@ static const struct it87_devices it87_devices[] = {
.suffix = "E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
- | FEAT_AVCC3,
+ | FEAT_AVCC3 | FEAT_PWM_FREQ2,
.peci_mask = 0x07,
},
[it8620] = {
@@ -403,7 +411,7 @@ static const struct it87_devices it87_devices[] = {
.suffix = "E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
- | FEAT_IN7_INTERNAL | FEAT_SIX_PWM,
+ | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2,
.peci_mask = 0x07,
},
};
@@ -427,6 +435,7 @@ static const struct it87_devices it87_devices[] = {
#define has_six_fans(data) ((data)->features & FEAT_SIX_FANS)
#define has_avcc3(data) ((data)->features & FEAT_AVCC3)
#define has_six_pwm(data) ((data)->features & FEAT_SIX_PWM)
+#define has_pwm_freq2(data) ((data)->features & FEAT_PWM_FREQ2)

struct it87_sio_data {
enum chips type;
@@ -906,9 +915,16 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
char *buf)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
struct it87_data *data = it87_update_device(dev);
- int index = (data->fan_ctl >> 4) & 0x07;
+ int nr = sensor_attr->index;
unsigned int freq;
+ int index;
+
+ if (has_pwm_freq2(data) && nr == 1)
+ index = (data->extra >> 4) & 0x07;
+ else
+ index = (data->fan_ctl >> 4) & 0x07;

freq = pwm_freq[index] / (has_newer_autopwm(data) ? 256 : 128);

@@ -1127,7 +1143,9 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
static ssize_t set_pwm_freq(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
struct it87_data *data = dev_get_drvdata(dev);
+ int nr = sensor_attr->index;
unsigned long val;
int i;

@@ -1144,9 +1162,15 @@ static ssize_t set_pwm_freq(struct device *dev,
}

mutex_lock(&data->update_lock);
- data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL) & 0x8f;
- data->fan_ctl |= i << 4;
- it87_write_value(data, IT87_REG_FAN_CTL, data->fan_ctl);
+ if (nr == 0) {
+ data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL) & 0x8f;
+ data->fan_ctl |= i << 4;
+ it87_write_value(data, IT87_REG_FAN_CTL, data->fan_ctl);
+ } else {
+ data->extra = it87_read_value(data, IT87_REG_TEMP_EXTRA) & 0x8f;
+ data->extra |= i << 4;
+ it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra);
+ }
mutex_unlock(&data->update_lock);

return count;
@@ -1316,7 +1340,8 @@ static SENSOR_DEVICE_ATTR_2(fan6_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 0);
static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0);
-static DEVICE_ATTR(pwm1_freq, S_IRUGO | S_IWUSR, show_pwm_freq, set_pwm_freq);
+static SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO | S_IWUSR, show_pwm_freq,
+ set_pwm_freq, 0);
static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IRUGO | S_IWUSR,
show_pwm_temp_map, set_pwm_temp_map, 0);
static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR,
@@ -1341,7 +1366,7 @@ static SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_temp, S_IRUGO | S_IWUSR,
static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 1);
static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 1);
-static DEVICE_ATTR(pwm2_freq, S_IRUGO, show_pwm_freq, NULL);
+static SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO, show_pwm_freq, set_pwm_freq, 1);
static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IRUGO | S_IWUSR,
show_pwm_temp_map, set_pwm_temp_map, 1);
static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR,
@@ -1366,7 +1391,7 @@ static SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_temp, S_IRUGO | S_IWUSR,
static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 2);
static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 2);
-static DEVICE_ATTR(pwm3_freq, S_IRUGO, show_pwm_freq, NULL);
+static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO, show_pwm_freq, NULL, 2);
static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IRUGO | S_IWUSR,
show_pwm_temp_map, set_pwm_temp_map, 2);
static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR,
@@ -1391,21 +1416,21 @@ static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_temp, S_IRUGO | S_IWUSR,
static SENSOR_DEVICE_ATTR(pwm4_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 3);
static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 3);
-static DEVICE_ATTR(pwm4_freq, S_IRUGO | S_IWUSR, show_pwm_freq, set_pwm_freq);
+static SENSOR_DEVICE_ATTR(pwm4_freq, S_IRUGO, show_pwm_freq, NULL, 3);
static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IRUGO | S_IWUSR,
show_pwm_temp_map, set_pwm_temp_map, 3);

static SENSOR_DEVICE_ATTR(pwm5_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 4);
static SENSOR_DEVICE_ATTR(pwm5, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 4);
-static DEVICE_ATTR(pwm5_freq, S_IRUGO | S_IWUSR, show_pwm_freq, set_pwm_freq);
+static SENSOR_DEVICE_ATTR(pwm5_freq, S_IRUGO, show_pwm_freq, NULL, 4);
static SENSOR_DEVICE_ATTR(pwm5_auto_channels_temp, S_IRUGO | S_IWUSR,
show_pwm_temp_map, set_pwm_temp_map, 4);

static SENSOR_DEVICE_ATTR(pwm6_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 5);
static SENSOR_DEVICE_ATTR(pwm6, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 5);
-static DEVICE_ATTR(pwm6_freq, S_IRUGO | S_IWUSR, show_pwm_freq, set_pwm_freq);
+static SENSOR_DEVICE_ATTR(pwm6_freq, S_IRUGO, show_pwm_freq, NULL, 5);
static SENSOR_DEVICE_ATTR(pwm6_auto_channels_temp, S_IRUGO | S_IWUSR,
show_pwm_temp_map, set_pwm_temp_map, 5);

@@ -1774,44 +1799,57 @@ static const struct attribute *it87_attributes_fan_div[] = {
static struct attribute *it87_attributes_pwm[6][4+1] = { {
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
&sensor_dev_attr_pwm1.dev_attr.attr,
- &dev_attr_pwm1_freq.attr,
+ &sensor_dev_attr_pwm1_freq.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_pwm2_enable.dev_attr.attr,
&sensor_dev_attr_pwm2.dev_attr.attr,
- &dev_attr_pwm2_freq.attr,
+ &sensor_dev_attr_pwm2_freq.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
&sensor_dev_attr_pwm3.dev_attr.attr,
- &dev_attr_pwm3_freq.attr,
+ &sensor_dev_attr_pwm3_freq.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_pwm4_enable.dev_attr.attr,
&sensor_dev_attr_pwm4.dev_attr.attr,
- &dev_attr_pwm4_freq.attr,
+ &sensor_dev_attr_pwm4_freq.dev_attr.attr,
&sensor_dev_attr_pwm4_auto_channels_temp.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_pwm5_enable.dev_attr.attr,
&sensor_dev_attr_pwm5.dev_attr.attr,
- &dev_attr_pwm5_freq.attr,
+ &sensor_dev_attr_pwm5_freq.dev_attr.attr,
&sensor_dev_attr_pwm5_auto_channels_temp.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_pwm6_enable.dev_attr.attr,
&sensor_dev_attr_pwm6.dev_attr.attr,
- &dev_attr_pwm6_freq.attr,
+ &sensor_dev_attr_pwm6_freq.dev_attr.attr,
&sensor_dev_attr_pwm6_auto_channels_temp.dev_attr.attr,
NULL
} };

+static umode_t pwm_attribute_mode(struct kobject *kobj, struct attribute *attr,
+ int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct it87_data *data = dev_get_drvdata(dev);
+
+ if (has_pwm_freq2(data) && index == 2)
+ return attr->mode | S_IWUSR;
+
+ return attr->mode;
+}
+
static const struct attribute_group it87_group_pwm[6] = {
{ .attrs = it87_attributes_pwm[0] },
- { .attrs = it87_attributes_pwm[1] },
+ { .attrs = it87_attributes_pwm[1],
+ .is_visible = pwm_attribute_mode, },
{ .attrs = it87_attributes_pwm[2] },
{ .attrs = it87_attributes_pwm[3] },
{ .attrs = it87_attributes_pwm[4] },
--
2.1.4
Guenter Roeck
2016-01-27 02:03:26 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

IT8620E supports up to 6 pwm channels. Add support for it.
Also check if fan tachometers 4..6 are enabled before instantiating
the respective sysfs attributes.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 114 ++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 94 insertions(+), 20 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 146f93584cde..916d73630224 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -168,6 +168,7 @@ static inline void superio_exit(void)
#define IT87_SIO_GPIO1_REG 0x25
#define IT87_SIO_GPIO2_REG 0x26
#define IT87_SIO_GPIO3_REG 0x27
+#define IT87_SIO_GPIO4_REG 0x28
#define IT87_SIO_GPIO5_REG 0x29
#define IT87_SIO_PINX1_REG 0x2a /* Pin selection */
#define IT87_SIO_PINX2_REG 0x2c /* Pin selection */
@@ -227,8 +228,8 @@ static const u8 IT87_REG_TEMP_OFFSET[] = { 0x56, 0x57, 0x59 };

#define IT87_REG_FAN_MAIN_CTRL 0x13
#define IT87_REG_FAN_CTL 0x14
-#define IT87_REG_PWM(nr) (0x15 + (nr))
-#define IT87_REG_PWM_DUTY(nr) (0x63 + (nr) * 8)
+static const u8 IT87_REG_PWM[] = { 0x15, 0x16, 0x17, 0x7f, 0xa7, 0xaf };
+static const u8 IT87_REG_PWM_DUTY[] = { 0x63, 0x6b, 0x73, 0x7b, 0xa3, 0xab };

#define IT87_REG_VIN(nr) (0x20 + (nr))
#define IT87_REG_TEMP(nr) (0x29 + (nr))
@@ -272,6 +273,7 @@ struct it87_devices {
#define FEAT_SIX_FANS (1 << 11) /* Supports six fans */
#define FEAT_10_9MV_ADC (1 << 12)
#define FEAT_AVCC3 (1 << 13) /* Chip supports in9/AVCC3 */
+#define FEAT_SIX_PWM (1 << 14) /* Chip supports 6 pwm chn */

static const struct it87_devices it87_devices[] = {
[it87] = {
@@ -401,7 +403,7 @@ static const struct it87_devices it87_devices[] = {
.suffix = "E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
- | FEAT_IN7_INTERNAL,
+ | FEAT_IN7_INTERNAL | FEAT_SIX_PWM,
.peci_mask = 0x07,
},
};
@@ -424,6 +426,7 @@ static const struct it87_devices it87_devices[] = {
#define has_in7_internal(data) ((data)->features & FEAT_IN7_INTERNAL)
#define has_six_fans(data) ((data)->features & FEAT_SIX_FANS)
#define has_avcc3(data) ((data)->features & FEAT_AVCC3)
+#define has_six_pwm(data) ((data)->features & FEAT_SIX_PWM)

struct it87_sio_data {
enum chips type;
@@ -483,9 +486,9 @@ struct it87_data {
* is no longer needed, but it is still done to keep the driver
* simple.
*/
- u8 pwm_ctrl[3]; /* Register value */
- u8 pwm_duty[3]; /* Manual PWM value set by user */
- u8 pwm_temp_map[3]; /* PWM to temp. chan. mapping (bits 1-0) */
+ u8 pwm_ctrl[6]; /* Register value */
+ u8 pwm_duty[6]; /* Manual PWM value set by user */
+ u8 pwm_temp_map[6]; /* PWM to temp. chan. mapping (bits 1-0) */

/* Automatic fan speed control registers */
u8 auto_pwm[3][4]; /* [nr][3] is hard-coded */
@@ -1068,7 +1071,7 @@ static ssize_t set_pwm_enable(struct device *dev,
data->pwm_duty[nr];
else /* Automatic mode */
data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr];
- it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]);
+ it87_write_value(data, IT87_REG_PWM[nr], data->pwm_ctrl[nr]);

if (data->type != it8603) {
/* set SmartGuardian mode */
@@ -1104,7 +1107,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
return -EBUSY;
}
data->pwm_duty[nr] = pwm_to_reg(data, val);
- it87_write_value(data, IT87_REG_PWM_DUTY(nr),
+ it87_write_value(data, IT87_REG_PWM_DUTY[nr],
data->pwm_duty[nr]);
} else {
data->pwm_duty[nr] = pwm_to_reg(data, val);
@@ -1114,7 +1117,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
*/
if (!(data->pwm_ctrl[nr] & 0x80)) {
data->pwm_ctrl[nr] = data->pwm_duty[nr];
- it87_write_value(data, IT87_REG_PWM(nr),
+ it87_write_value(data, IT87_REG_PWM[nr],
data->pwm_ctrl[nr]);
}
}
@@ -1207,7 +1210,7 @@ static ssize_t set_pwm_temp_map(struct device *dev,
*/
if (data->pwm_ctrl[nr] & 0x80) {
data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr];
- it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]);
+ it87_write_value(data, IT87_REG_PWM[nr], data->pwm_ctrl[nr]);
}
mutex_unlock(&data->update_lock);
return count;
@@ -1385,6 +1388,27 @@ static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR,
static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_temp, S_IRUGO | S_IWUSR,
show_auto_temp, set_auto_temp, 2, 4);

+static SENSOR_DEVICE_ATTR(pwm4_enable, S_IRUGO | S_IWUSR,
+ show_pwm_enable, set_pwm_enable, 3);
+static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 3);
+static DEVICE_ATTR(pwm4_freq, S_IRUGO | S_IWUSR, show_pwm_freq, set_pwm_freq);
+static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IRUGO | S_IWUSR,
+ show_pwm_temp_map, set_pwm_temp_map, 3);
+
+static SENSOR_DEVICE_ATTR(pwm5_enable, S_IRUGO | S_IWUSR,
+ show_pwm_enable, set_pwm_enable, 4);
+static SENSOR_DEVICE_ATTR(pwm5, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 4);
+static DEVICE_ATTR(pwm5_freq, S_IRUGO | S_IWUSR, show_pwm_freq, set_pwm_freq);
+static SENSOR_DEVICE_ATTR(pwm5_auto_channels_temp, S_IRUGO | S_IWUSR,
+ show_pwm_temp_map, set_pwm_temp_map, 4);
+
+static SENSOR_DEVICE_ATTR(pwm6_enable, S_IRUGO | S_IWUSR,
+ show_pwm_enable, set_pwm_enable, 5);
+static SENSOR_DEVICE_ATTR(pwm6, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 5);
+static DEVICE_ATTR(pwm6_freq, S_IRUGO | S_IWUSR, show_pwm_freq, set_pwm_freq);
+static SENSOR_DEVICE_ATTR(pwm6_auto_channels_temp, S_IRUGO | S_IWUSR,
+ show_pwm_temp_map, set_pwm_temp_map, 5);
+
/* Alarms */
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -1747,7 +1771,7 @@ static const struct attribute *it87_attributes_fan_div[] = {
&sensor_dev_attr_fan3_div.dev_attr.attr,
};

-static struct attribute *it87_attributes_pwm[3][4+1] = { {
+static struct attribute *it87_attributes_pwm[6][4+1] = { {
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
&sensor_dev_attr_pwm1.dev_attr.attr,
&dev_attr_pwm1_freq.attr,
@@ -1765,12 +1789,33 @@ static struct attribute *it87_attributes_pwm[3][4+1] = { {
&dev_attr_pwm3_freq.attr,
&sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
NULL
+}, {
+ &sensor_dev_attr_pwm4_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm4.dev_attr.attr,
+ &dev_attr_pwm4_freq.attr,
+ &sensor_dev_attr_pwm4_auto_channels_temp.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_pwm5_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm5.dev_attr.attr,
+ &dev_attr_pwm5_freq.attr,
+ &sensor_dev_attr_pwm5_auto_channels_temp.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_pwm6_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm6.dev_attr.attr,
+ &dev_attr_pwm6_freq.attr,
+ &sensor_dev_attr_pwm6_auto_channels_temp.dev_attr.attr,
+ NULL
} };

-static const struct attribute_group it87_group_pwm[3] = {
+static const struct attribute_group it87_group_pwm[6] = {
{ .attrs = it87_attributes_pwm[0] },
{ .attrs = it87_attributes_pwm[1] },
{ .attrs = it87_attributes_pwm[2] },
+ { .attrs = it87_attributes_pwm[3] },
+ { .attrs = it87_attributes_pwm[4] },
+ { .attrs = it87_attributes_pwm[5] },
};

static struct attribute *it87_attributes_autopwm[3][9+1] = { {
@@ -1955,6 +2000,9 @@ static int __init it87_find(unsigned short *address,
else
sio_data->skip_in |= (1 << 9);

+ if (!has_six_pwm(config))
+ sio_data->skip_pwm |= (1 << 3) | (1 << 4) | (1 << 5);
+
if (!has_vid(config))
sio_data->skip_vid = 1;

@@ -2057,6 +2105,11 @@ static int __init it87_find(unsigned short *address,

superio_select(GPIO);

+ /* Check for pwm5 */
+ reg = superio_inb(IT87_SIO_GPIO1_REG);
+ if (reg & (1 << 6))
+ sio_data->skip_pwm |= (1 << 4);
+
/* Check for fan4, fan5 */
reg = superio_inb(IT87_SIO_GPIO2_REG);
if (!(reg & (1 << 5)))
@@ -2071,12 +2124,22 @@ static int __init it87_find(unsigned short *address,
if (reg & (1 << 7))
sio_data->skip_fan |= (1 << 2);

+ /* Check for pwm4 */
+ reg = superio_inb(IT87_SIO_GPIO4_REG);
+ if (!(reg & (1 << 2)))
+ sio_data->skip_pwm |= (1 << 3);
+
/* Check for pwm2, fan2 */
reg = superio_inb(IT87_SIO_GPIO5_REG);
if (reg & (1 << 1))
sio_data->skip_pwm |= (1 << 1);
if (reg & (1 << 2))
sio_data->skip_fan |= (1 << 1);
+ /* Check for pwm6, fan6 */
+ if (!(reg & (1 << 7))) {
+ sio_data->skip_pwm |= (1 << 5);
+ sio_data->skip_fan |= (1 << 5);
+ }

sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
} else {
@@ -2219,7 +2282,7 @@ static void it87_remove_files(struct device *dev)
sysfs_remove_file(&dev->kobj,
it87_attributes_fan_div[i]);
}
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < 6; i++) {
if (sio_data->skip_pwm & (1 << i))
continue;
sysfs_remove_group(&dev->kobj, &it87_group_pwm[i]);
@@ -2402,7 +2465,7 @@ static int it87_probe(struct platform_device *pdev)
}

if (enable_pwm_interface) {
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < 6; i++) {
if (sio_data->skip_pwm & (1 << i))
continue;
err = sysfs_create_group(&dev->kobj,
@@ -2505,7 +2568,7 @@ static int it87_check_pwm(struct device *dev)

for (i = 0; i < 3; i++)
pwm[i] = it87_read_value(data,
- IT87_REG_PWM(i));
+ IT87_REG_PWM[i]);

/*
* If any fan is in automatic pwm mode, the polarity
@@ -2520,7 +2583,7 @@ static int it87_check_pwm(struct device *dev)
tmp | 0x87);
for (i = 0; i < 3; i++)
it87_write_value(data,
- IT87_REG_PWM(i),
+ IT87_REG_PWM[i],
0x7f & ~pwm[i]);
return 1;
}
@@ -2635,6 +2698,16 @@ static void it87_init_device(struct platform_device *pdev)
/* Fan input pins may be used for alternative functions */
data->has_fan &= ~sio_data->skip_fan;

+ /* Check if pwm5, pwm6 are enabled */
+ if (has_six_pwm(data)) {
+ /* The following code may be IT8620E specific */
+ tmp = it87_read_value(data, IT87_REG_FAN_DIV);
+ if ((tmp & 0xc0) == 0xc0)
+ sio_data->skip_pwm |= (1 << 4);
+ if (!(tmp & (1 << 3)))
+ sio_data->skip_pwm |= (1 << 5);
+ }
+
/* Start monitoring */
it87_write_value(data, IT87_REG_CONFIG,
(it87_read_value(data, IT87_REG_CONFIG) & 0x3e)
@@ -2643,11 +2716,12 @@ static void it87_init_device(struct platform_device *pdev)

static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
{
- data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM(nr));
+ data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM[nr]);
if (has_newer_autopwm(data)) {
- data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
+ data->pwm_temp_map[nr] = (data->pwm_ctrl[nr] & 0x03) +
+ nr < 3 ? 0 : 3;
data->pwm_duty[nr] = it87_read_value(data,
- IT87_REG_PWM_DUTY(nr));
+ IT87_REG_PWM_DUTY[nr]);
} else {
if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */
data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
@@ -2746,7 +2820,7 @@ static struct it87_data *it87_update_device(struct device *dev)
data->fan_main_ctrl = it87_read_value(data,
IT87_REG_FAN_MAIN_CTRL);
data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL);
- for (i = 0; i < 3; i++)
+ for (i = 0; i < 6; i++)
it87_update_pwm_ctrl(data, i);

data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
--
2.1.4
Guenter Roeck
2016-01-27 02:03:49 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

IT8628E is functionally identical to IT8620E.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
Documentation/hwmon/it87 | 15 +++++++++------
drivers/hwmon/Kconfig | 3 ++-
drivers/hwmon/it87.c | 18 ++++++++++++++++--
3 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87
index 733296d65449..fff6f6bf55bc 100644
--- a/Documentation/hwmon/it87
+++ b/Documentation/hwmon/it87
@@ -9,6 +9,9 @@ Supported chips:
* IT8620E
Prefix: 'it8620'
Addresses scanned: from Super I/O config space (8 I/O ports)
+ * IT8628E
+ Prefix: 'it8628'
+ Addresses scanned: from Super I/O config space (8 I/O ports)
Datasheet: Not publicly available
* IT8705F
Prefix: 'it87'
@@ -114,8 +117,8 @@ motherboard models.
Description
-----------

-This driver implements support for the IT8603E, IT8620E, IT8623E, IT8705F,
-IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8732F,
+This driver implements support for the IT8603E, IT8620E, IT8623E, IT8628E,
+IT8705F, IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8732F,
IT8758E, IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E, and
SiS950 chips.

@@ -158,8 +161,8 @@ The IT8603E/IT8623E is a custom design, hardware monitoring part is similar to
IT8728F. It only supports 3 fans, 16-bit fan mode, and the full speed mode
of the fan is not supported (value 0 of pwmX_enable).

-The IT8620E is another custom design, hardware monitoring part is similar to
-IT8728F. It only supports 16-bit fan mode.
+The IT8620E and IT8628E are custom designs, hardware monitoring part is similar
+to IT8728F. It only supports 16-bit fan mode. Both chips support up to 6 fans.

The IT8790E supports up to 3 fans. 16-bit fan mode is always enabled.

@@ -187,8 +190,8 @@ of 0.016 volt. IT8603E, IT8721F/IT8758E and IT8728F can measure between 0 and
2.8 volts with a resolution of 0.0109 volt. The battery voltage in8 does not
have limit registers.

-On the IT8603E, IT8721F/IT8758E, IT8732F, IT8781F, IT8782F, and IT8783E/F, some
-voltage inputs are internal and scaled inside the chip:
+On the IT8603E, IT8620E, IT8628E, IT8721F/IT8758E, IT8732F, IT8781F, IT8782F,
+and IT8783E/F, some voltage inputs are internal and scaled inside the chip:
* in3 (optional)
* in7 (optional for IT8781F, IT8782F, and IT8783E/F)
* in8 (always)
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 852c8a85e1e8..ac22e3bbfecc 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -621,7 +621,8 @@ config SENSORS_IT87
If you say yes here you get support for ITE IT8705F, IT8712F, IT8716F,
IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8732F, IT8758E,
IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E,
- IT8603E, IT8620E, and IT8623E sensor chips, and the SiS950 clone.
+ IT8603E, IT8620E, IT8623E, and IT8628E sensor chips, and the SiS950
+ clone.

This driver can also be built as a module. If so, the module
will be called it87.
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index cde53c1109ea..730d84028260 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -13,6 +13,7 @@
* Supports: IT8603E Super I/O chip w/LPC interface
* IT8620E Super I/O chip w/LPC interface
* IT8623E Super I/O chip w/LPC interface
+ * IT8628E Super I/O chip w/LPC interface
* IT8705F Super I/O chip w/LPC interface
* IT8712F Super I/O chip w/LPC interface
* IT8716F Super I/O chip w/LPC interface
@@ -69,7 +70,7 @@

enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8732,
it8771, it8772, it8781, it8782, it8783, it8786, it8790, it8603,
- it8620 };
+ it8620, it8628 };

static unsigned short force_id;
module_param(force_id, ushort, 0);
@@ -160,6 +161,7 @@ static inline void superio_exit(int ioreg)
#define IT8603E_DEVID 0x8603
#define IT8620E_DEVID 0x8620
#define IT8623E_DEVID 0x8623
+#define IT8628E_DEVID 0x8628
#define IT87_ACT_REG 0x30
#define IT87_BASE_REG 0x60

@@ -434,6 +436,15 @@ static const struct it87_devices it87_devices[] = {
| FEAT_SIX_TEMP,
.peci_mask = 0x07,
},
+ [it8628] = {
+ .name = "it8628",
+ .suffix = "E",
+ .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
+ | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
+ | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
+ | FEAT_SIX_TEMP,
+ .peci_mask = 0x07,
+ },
};

#define has_16bit_fans(data) ((data)->features & FEAT_16BIT_FANS)
@@ -2402,6 +2413,9 @@ static int __init it87_find(int sioaddr, unsigned short *address,
case IT8620E_DEVID:
sio_data->type = it8620;
break;
+ case IT8628E_DEVID:
+ sio_data->type = it8628;
+ break;
case 0xffff: /* No device at all */
goto exit;
default:
@@ -2546,7 +2560,7 @@ static int __init it87_find(int sioaddr, unsigned short *address,

sio_data->beep_pin = superio_inb(sioaddr,
IT87_SIO_BEEP_PIN_REG) & 0x3f;
- } else if (sio_data->type == it8620) {
+ } else if (sio_data->type == it8620 || sio_data->type == it8628) {
int reg;

superio_select(sioaddr, GPIO);
--
2.1.4
Guenter Roeck
2016-01-27 02:03:31 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

The Super-IO chip can also reside at SIO address 0x4e, and there can be
two Super-IO chips in the system. Add support for it.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 49 ++++++++++++++++++++++++++++++++++---------------
1 file changed, 34 insertions(+), 15 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 4840f2d8c7b1..f877cc98b2fd 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -78,9 +78,10 @@ static unsigned short force_id;
module_param(force_id, ushort, 0);
MODULE_PARM_DESC(force_id, "Override the detected device ID");

-static struct platform_device *it87_pdev;
+static struct platform_device *it87_pdev[2];

#define REG_2E 0x2e /* The register to read/write */
+#define REG_4E 0x4e /* Secondary register to read/write */

#define DEV 0x07 /* Register: Logical device select */
#define PME 0x04 /* The device with the fan registers in it */
@@ -130,7 +131,7 @@ static inline int superio_enter(int ioreg)
outb(0x87, ioreg);
outb(0x01, ioreg);
outb(0x55, ioreg);
- outb(0x55, ioreg);
+ outb(ioreg == REG_4E ? 0xaa : 0x55, ioreg);
return 0;
}

@@ -2892,7 +2893,7 @@ static struct it87_data *it87_update_device(struct device *dev)
return data;
}

-static int __init it87_device_add(unsigned short address,
+static int __init it87_device_add(int index, unsigned short address,
const struct it87_sio_data *sio_data)
{
struct platform_device *pdev;
@@ -2931,7 +2932,7 @@ static int __init it87_device_add(unsigned short address,
goto exit_device_put;
}

- it87_pdev = pdev;
+ it87_pdev[index] = pdev;
return 0;

exit_device_put:
@@ -2941,30 +2942,48 @@ exit_device_put:

static int __init sm_it87_init(void)
{
- int err;
- unsigned short isa_address = 0;
+ int sioaddr[2] = { REG_2E, REG_4E };
struct it87_sio_data sio_data;
+ unsigned short isa_address;
+ bool found = false;
+ int i, err;

- memset(&sio_data, 0, sizeof(struct it87_sio_data));
- err = it87_find(REG_2E, &isa_address, &sio_data);
- if (err)
- return err;
err = platform_driver_register(&it87_driver);
if (err)
return err;

- err = it87_device_add(isa_address, &sio_data);
- if (err) {
- platform_driver_unregister(&it87_driver);
- return err;
+ for (i = 0; i < ARRAY_SIZE(sioaddr); i++) {
+ memset(&sio_data, 0, sizeof(struct it87_sio_data));
+ isa_address = 0;
+ err = it87_find(sioaddr[i], &isa_address, &sio_data);
+ if (err || isa_address == 0)
+ continue;
+
+ err = it87_device_add(i, isa_address, &sio_data);
+ if (err)
+ goto exit_dev_unregister;
+ found = true;
}

+ if (!found) {
+ err = -ENODEV;
+ goto exit_unregister;
+ }
return 0;
+
+exit_dev_unregister:
+ /* NULL check handled by platform_device_unregister */
+ platform_device_unregister(it87_pdev[0]);
+exit_unregister:
+ platform_driver_unregister(&it87_driver);
+ return err;
}

static void __exit sm_it87_exit(void)
{
- platform_device_unregister(it87_pdev);
+ /* NULL check handled by platform_device_unregister */
+ platform_device_unregister(it87_pdev[1]);
+ platform_device_unregister(it87_pdev[0]);
platform_driver_unregister(&it87_driver);
}
--
2.1.4
Guenter Roeck
2016-01-27 02:03:29 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

Using the same varible name for function names and as static
variable invites misuse and prevents us from adding support
for a second chip. Rename pdev to it87_pdev and limit its use
to where it is needed.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 9b36987d7949..8f28f9b04150 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -78,7 +78,7 @@ static unsigned short force_id;
module_param(force_id, ushort, 0);
MODULE_PARM_DESC(force_id, "Override the detected device ID");

-static struct platform_device *pdev;
+static struct platform_device *it87_pdev;

#define REG 0x2e /* The register to read/write */
#define DEV 0x07 /* Register: Logical device select */
@@ -2285,7 +2285,7 @@ exit:

static void it87_remove_files(struct device *dev)
{
- struct it87_data *data = platform_get_drvdata(pdev);
+ struct it87_data *data = dev_get_drvdata(dev);
struct it87_sio_data *sio_data = dev_get_platdata(dev);
int i;

@@ -2888,6 +2888,7 @@ static struct it87_data *it87_update_device(struct device *dev)
static int __init it87_device_add(unsigned short address,
const struct it87_sio_data *sio_data)
{
+ struct platform_device *pdev;
struct resource res = {
.start = address + IT87_EC_OFFSET,
.end = address + IT87_EC_OFFSET + IT87_EC_EXTENT - 1,
@@ -2923,6 +2924,7 @@ static int __init it87_device_add(unsigned short address,
goto exit_device_put;
}

+ it87_pdev = pdev;
return 0;

exit_device_put:
@@ -2955,7 +2957,7 @@ static int __init sm_it87_init(void)

static void __exit sm_it87_exit(void)
{
- platform_device_unregister(pdev);
+ platform_device_unregister(it87_pdev);
platform_driver_unregister(&it87_driver);
}
--
2.1.4
Guenter Roeck
2016-01-27 02:03:30 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

This will let us support more than one chip on different SIO addresses
with the same driver.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 137 +++++++++++++++++++++++++++------------------------
1 file changed, 72 insertions(+), 65 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 8f28f9b04150..4840f2d8c7b1 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -80,9 +80,9 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");

static struct platform_device *it87_pdev;

-#define REG 0x2e /* The register to read/write */
+#define REG_2E 0x2e /* The register to read/write */
+
#define DEV 0x07 /* Register: Logical device select */
-#define VAL 0x2f /* The value to read/write */
#define PME 0x04 /* The device with the fan registers in it */

/* The device with the IT8718F/IT8720F VID value in it */
@@ -91,54 +91,54 @@ static struct platform_device *it87_pdev;
#define DEVID 0x20 /* Register: Device ID */
#define DEVREV 0x22 /* Register: Device Revision */

-static inline int superio_inb(int reg)
+static inline int superio_inb(int ioreg, int reg)
{
- outb(reg, REG);
- return inb(VAL);
+ outb(reg, ioreg);
+ return inb(ioreg + 1);
}

-static inline void superio_outb(int reg, int val)
+static inline void superio_outb(int ioreg, int reg, int val)
{
- outb(reg, REG);
- outb(val, VAL);
+ outb(reg, ioreg);
+ outb(val, ioreg + 1);
}

-static int superio_inw(int reg)
+static int superio_inw(int ioreg, int reg)
{
int val;
- outb(reg++, REG);
- val = inb(VAL) << 8;
- outb(reg, REG);
- val |= inb(VAL);
+ outb(reg++, ioreg);
+ val = inb(ioreg + 1) << 8;
+ outb(reg, ioreg);
+ val |= inb(ioreg + 1);
return val;
}

-static inline void superio_select(int ldn)
+static inline void superio_select(int ioreg, int ldn)
{
- outb(DEV, REG);
- outb(ldn, VAL);
+ outb(DEV, ioreg);
+ outb(ldn, ioreg + 1);
}

-static inline int superio_enter(void)
+static inline int superio_enter(int ioreg)
{
/*
- * Try to reserve REG and REG + 1 for exclusive access.
+ * Try to reserve ioreg and ioreg + 1 for exclusive access.
*/
- if (!request_muxed_region(REG, 2, DRVNAME))
+ if (!request_muxed_region(ioreg, 2, DRVNAME))
return -EBUSY;

- outb(0x87, REG);
- outb(0x01, REG);
- outb(0x55, REG);
- outb(0x55, REG);
+ outb(0x87, ioreg);
+ outb(0x01, ioreg);
+ outb(0x55, ioreg);
+ outb(0x55, ioreg);
return 0;
}

-static inline void superio_exit(void)
+static inline void superio_exit(int ioreg)
{
- outb(0x02, REG);
- outb(0x02, VAL);
- release_region(REG, 2);
+ outb(0x02, ioreg);
+ outb(0x02, ioreg + 1);
+ release_region(ioreg, 2);
}

/* Logical device 4 registers */
@@ -1929,20 +1929,20 @@ static const struct attribute_group it87_group_label = {
};

/* SuperIO detection - will change isa_address if a chip is found */
-static int __init it87_find(unsigned short *address,
- struct it87_sio_data *sio_data)
+static int __init it87_find(int sioaddr, unsigned short *address,
+ struct it87_sio_data *sio_data)
{
int err;
u16 chip_type;
const char *board_vendor, *board_name;
const struct it87_devices *config;

- err = superio_enter();
+ err = superio_enter(sioaddr);
if (err)
return err;

err = -ENODEV;
- chip_type = force_id ? force_id : superio_inw(DEVID);
+ chip_type = force_id ? force_id : superio_inw(sioaddr, DEVID);

switch (chip_type) {
case IT8705F_DEVID:
@@ -2005,20 +2005,20 @@ static int __init it87_find(unsigned short *address,
goto exit;
}

- superio_select(PME);
- if (!(superio_inb(IT87_ACT_REG) & 0x01)) {
+ superio_select(sioaddr, PME);
+ if (!(superio_inb(sioaddr, IT87_ACT_REG) & 0x01)) {
pr_info("Device not activated, skipping\n");
goto exit;
}

- *address = superio_inw(IT87_BASE_REG) & ~(IT87_EXTENT - 1);
+ *address = superio_inw(sioaddr, IT87_BASE_REG) & ~(IT87_EXTENT - 1);
if (*address == 0) {
pr_info("Base address not set, skipping\n");
goto exit;
}

err = 0;
- sio_data->revision = superio_inb(DEVREV) & 0x0f;
+ sio_data->revision = superio_inb(sioaddr, DEVREV) & 0x0f;
pr_info("Found IT%04x%s chip at 0x%x, revision %d\n", chip_type,
it87_devices[sio_data->type].suffix,
*address, sio_data->revision);
@@ -2047,18 +2047,19 @@ static int __init it87_find(unsigned short *address,
/* Read GPIO config and VID value from LDN 7 (GPIO) */
if (sio_data->type == it87) {
/* The IT8705F has a different LD number for GPIO */
- superio_select(5);
- sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
+ superio_select(sioaddr, 5);
+ sio_data->beep_pin = superio_inb(sioaddr,
+ IT87_SIO_BEEP_PIN_REG) & 0x3f;
} else if (sio_data->type == it8783) {
int reg25, reg27, reg2a, reg2c, regef;

- superio_select(GPIO);
+ superio_select(sioaddr, GPIO);

- reg25 = superio_inb(IT87_SIO_GPIO1_REG);
- reg27 = superio_inb(IT87_SIO_GPIO3_REG);
- reg2a = superio_inb(IT87_SIO_PINX1_REG);
- reg2c = superio_inb(IT87_SIO_PINX2_REG);
- regef = superio_inb(IT87_SIO_SPI_REG);
+ reg25 = superio_inb(sioaddr, IT87_SIO_GPIO1_REG);
+ reg27 = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
+ reg2a = superio_inb(sioaddr, IT87_SIO_PINX1_REG);
+ reg2c = superio_inb(sioaddr, IT87_SIO_PINX2_REG);
+ regef = superio_inb(sioaddr, IT87_SIO_SPI_REG);

/* Check if fan3 is there or not */
if ((reg27 & (1 << 0)) || !(reg2c & (1 << 2)))
@@ -2101,7 +2102,8 @@ static int __init it87_find(unsigned short *address,
*/
if (!(reg2c & (1 << 1))) {
reg2c |= (1 << 1);
- superio_outb(IT87_SIO_PINX2_REG, reg2c);
+ superio_outb(sioaddr, IT87_SIO_PINX2_REG,
+ reg2c);
pr_notice("Routing internal VCCH5V to in7.\n");
}
pr_notice("in7 routed to internal voltage divider, with external pin disabled.\n");
@@ -2113,13 +2115,14 @@ static int __init it87_find(unsigned short *address,
if (reg2c & (1 << 1))
sio_data->internal |= (1 << 1);

- sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
+ sio_data->beep_pin = superio_inb(sioaddr,
+ IT87_SIO_BEEP_PIN_REG) & 0x3f;
} else if (sio_data->type == it8603) {
int reg27, reg29;

- superio_select(GPIO);
+ superio_select(sioaddr, GPIO);

- reg27 = superio_inb(IT87_SIO_GPIO3_REG);
+ reg27 = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);

/* Check if fan3 is there or not */
if (reg27 & (1 << 6))
@@ -2128,7 +2131,7 @@ static int __init it87_find(unsigned short *address,
sio_data->skip_fan |= (1 << 2);

/* Check if fan2 is there or not */
- reg29 = superio_inb(IT87_SIO_GPIO5_REG);
+ reg29 = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
if (reg29 & (1 << 1))
sio_data->skip_pwm |= (1 << 1);
if (reg29 & (1 << 2))
@@ -2137,38 +2140,39 @@ static int __init it87_find(unsigned short *address,
sio_data->skip_in |= (1 << 5); /* No VIN5 */
sio_data->skip_in |= (1 << 6); /* No VIN6 */

- sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
+ sio_data->beep_pin = superio_inb(sioaddr,
+ IT87_SIO_BEEP_PIN_REG) & 0x3f;
} else if (sio_data->type == it8620) {
int reg;

- superio_select(GPIO);
+ superio_select(sioaddr, GPIO);

/* Check for pwm5 */
- reg = superio_inb(IT87_SIO_GPIO1_REG);
+ reg = superio_inb(sioaddr, IT87_SIO_GPIO1_REG);
if (reg & (1 << 6))
sio_data->skip_pwm |= (1 << 4);

/* Check for fan4, fan5 */
- reg = superio_inb(IT87_SIO_GPIO2_REG);
+ reg = superio_inb(sioaddr, IT87_SIO_GPIO2_REG);
if (!(reg & (1 << 5)))
sio_data->skip_fan |= (1 << 3);
if (!(reg & (1 << 4)))
sio_data->skip_fan |= (1 << 4);

/* Check for pwm3, fan3 */
- reg = superio_inb(IT87_SIO_GPIO3_REG);
+ reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
if (reg & (1 << 6))
sio_data->skip_pwm |= (1 << 2);
if (reg & (1 << 7))
sio_data->skip_fan |= (1 << 2);

/* Check for pwm4 */
- reg = superio_inb(IT87_SIO_GPIO4_REG);
+ reg = superio_inb(sioaddr, IT87_SIO_GPIO4_REG);
if (!(reg & (1 << 2)))
sio_data->skip_pwm |= (1 << 3);

/* Check for pwm2, fan2 */
- reg = superio_inb(IT87_SIO_GPIO5_REG);
+ reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
if (reg & (1 << 1))
sio_data->skip_pwm |= (1 << 1);
if (reg & (1 << 2))
@@ -2179,14 +2183,15 @@ static int __init it87_find(unsigned short *address,
sio_data->skip_fan |= (1 << 5);
}

- sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
+ sio_data->beep_pin = superio_inb(sioaddr,
+ IT87_SIO_BEEP_PIN_REG) & 0x3f;
} else {
int reg;
bool uart6;

- superio_select(GPIO);
+ superio_select(sioaddr, GPIO);

- reg = superio_inb(IT87_SIO_GPIO3_REG);
+ reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
if (!sio_data->skip_vid) {
/* We need at least 4 VID pins */
if (reg & 0x0f) {
@@ -2202,7 +2207,7 @@ static int __init it87_find(unsigned short *address,
sio_data->skip_fan |= (1 << 2);

/* Check if fan2 is there or not */
- reg = superio_inb(IT87_SIO_GPIO5_REG);
+ reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
if (reg & (1 << 1))
sio_data->skip_pwm |= (1 << 1);
if (reg & (1 << 2))
@@ -2210,9 +2215,10 @@ static int __init it87_find(unsigned short *address,

if ((sio_data->type == it8718 || sio_data->type == it8720)
&& !(sio_data->skip_vid))
- sio_data->vid_value = superio_inb(IT87_SIO_VID_REG);
+ sio_data->vid_value = superio_inb(sioaddr,
+ IT87_SIO_VID_REG);

- reg = superio_inb(IT87_SIO_PINX2_REG);
+ reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG);

uart6 = sio_data->type == it8782 && (reg & (1 << 2));

@@ -2232,7 +2238,7 @@ static int __init it87_find(unsigned short *address,
*/
if ((sio_data->type == it8720 || uart6) && !(reg & (1 << 1))) {
reg |= (1 << 1);
- superio_outb(IT87_SIO_PINX2_REG, reg);
+ superio_outb(sioaddr, IT87_SIO_PINX2_REG, reg);
pr_notice("Routing internal VCCH to in7\n");
}
if (reg & (1 << 0))
@@ -2254,7 +2260,8 @@ static int __init it87_find(unsigned short *address,
sio_data->skip_temp |= (1 << 2);
}

- sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
+ sio_data->beep_pin = superio_inb(sioaddr,
+ IT87_SIO_BEEP_PIN_REG) & 0x3f;
}
if (sio_data->beep_pin)
pr_info("Beeping is supported\n");
@@ -2279,7 +2286,7 @@ static int __init it87_find(unsigned short *address,
}

exit:
- superio_exit();
+ superio_exit(sioaddr);
return err;
}

@@ -2939,7 +2946,7 @@ static int __init sm_it87_init(void)
struct it87_sio_data sio_data;

memset(&sio_data, 0, sizeof(struct it87_sio_data));
- err = it87_find(&isa_address, &sio_data);
+ err = it87_find(REG_2E, &isa_address, &sio_data);
if (err)
return err;
err = platform_driver_register(&it87_driver);
--
2.1.4
Guenter Roeck
2016-01-27 02:03:48 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index e3fbcf49afdb..cde53c1109ea 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -655,8 +655,7 @@ static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
{
data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM[nr]);
if (has_newer_autopwm(data)) {
- data->pwm_temp_map[nr] = (data->pwm_ctrl[nr] & 0x03) +
- nr < 3 ? 0 : 3;
+ data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
data->pwm_duty[nr] = it87_read_value(data,
IT87_REG_PWM_DUTY[nr]);
} else {
@@ -790,8 +789,11 @@ static struct it87_data *it87_update_device(struct device *dev)
data->fan_main_ctrl = it87_read_value(data,
IT87_REG_FAN_MAIN_CTRL);
data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL);
- for (i = 0; i < NUM_PWM; i++)
+ for (i = 0; i < NUM_PWM; i++) {
+ if (!(data->has_pwm & BIT(i)))
+ continue;
it87_update_pwm_ctrl(data, i);
+ }

data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
data->extra = it87_read_value(data, IT87_REG_TEMP_EXTRA);
@@ -1403,11 +1405,13 @@ static ssize_t show_pwm_temp_map(struct device *dev,
int nr = sensor_attr->index;
int map;

- if (data->pwm_temp_map[nr] < 3)
- map = BIT(data->pwm_temp_map[nr]);
- else
- map = 0; /* Should never happen */
- return sprintf(buf, "%d\n", map);
+ map = data->pwm_temp_map[nr];
+ if (map >= 3)
+ map = 0; /* Should never happen */
+ if (nr >= 3) /* pwm channels 3..6 map to temp4..6 */
+ map += 3;
+
+ return sprintf(buf, "%d\n", (int)BIT(map));
}

static ssize_t set_pwm_temp_map(struct device *dev,
@@ -1423,6 +1427,9 @@ static ssize_t set_pwm_temp_map(struct device *dev,
if (kstrtol(buf, 10, &val) < 0)
return -EINVAL;

+ if (nr >= 3)
+ val -= 3;
+
switch (val) {
case BIT(0):
reg = 0x00;
--
2.1.4
Guenter Roeck
2016-01-27 02:03:32 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

Cleanup only, no functional change.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 761 +++++++++++++++++++++++++--------------------------
1 file changed, 376 insertions(+), 385 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index f877cc98b2fd..4b38ecb91959 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -603,23 +603,160 @@ static const unsigned int pwm_freq[8] = {
750000,
};

-static int it87_probe(struct platform_device *pdev);
-static int it87_remove(struct platform_device *pdev);
+/*
+ * Must be called with data->update_lock held, except during initialization.
+ * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
+ * would slow down the IT87 access and should not be necessary.
+ */
+static int it87_read_value(struct it87_data *data, u8 reg)
+{
+ outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
+ return inb_p(data->addr + IT87_DATA_REG_OFFSET);
+}
+
+/*
+ * Must be called with data->update_lock held, except during initialization.
+ * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
+ * would slow down the IT87 access and should not be necessary.
+ */
+static void it87_write_value(struct it87_data *data, u8 reg, u8 value)
+{
+ outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
+ outb_p(value, data->addr + IT87_DATA_REG_OFFSET);
+}
+
+static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
+{
+ data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM[nr]);
+ if (has_newer_autopwm(data)) {
+ data->pwm_temp_map[nr] = (data->pwm_ctrl[nr] & 0x03) +
+ nr < 3 ? 0 : 3;
+ data->pwm_duty[nr] = it87_read_value(data,
+ IT87_REG_PWM_DUTY[nr]);
+ } else {
+ if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */
+ data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
+ else /* Manual mode */
+ data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f;
+ }

-static int it87_read_value(struct it87_data *data, u8 reg);
-static void it87_write_value(struct it87_data *data, u8 reg, u8 value);
-static struct it87_data *it87_update_device(struct device *dev);
-static int it87_check_pwm(struct device *dev);
-static void it87_init_device(struct platform_device *pdev);
+ if (has_old_autopwm(data)) {
+ int i;

+ for (i = 0; i < 5 ; i++)
+ data->auto_temp[nr][i] = it87_read_value(data,
+ IT87_REG_AUTO_TEMP(nr, i));
+ for (i = 0; i < 3 ; i++)
+ data->auto_pwm[nr][i] = it87_read_value(data,
+ IT87_REG_AUTO_PWM(nr, i));
+ }
+}

-static struct platform_driver it87_driver = {
- .driver = {
- .name = DRVNAME,
- },
- .probe = it87_probe,
- .remove = it87_remove,
-};
+static struct it87_data *it87_update_device(struct device *dev)
+{
+ struct it87_data *data = dev_get_drvdata(dev);
+ int i;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+ || !data->valid) {
+ if (update_vbat) {
+ /*
+ * Cleared after each update, so reenable. Value
+ * returned by this read will be previous value
+ */
+ it87_write_value(data, IT87_REG_CONFIG,
+ it87_read_value(data, IT87_REG_CONFIG) | 0x40);
+ }
+ for (i = 0; i <= 7; i++) {
+ data->in[i][0] =
+ it87_read_value(data, IT87_REG_VIN(i));
+ data->in[i][1] =
+ it87_read_value(data, IT87_REG_VIN_MIN(i));
+ data->in[i][2] =
+ it87_read_value(data, IT87_REG_VIN_MAX(i));
+ }
+ /* in8 (battery) has no limit registers */
+ data->in[8][0] = it87_read_value(data, IT87_REG_VIN(8));
+ if (has_avcc3(data))
+ data->in[9][0] = it87_read_value(data, IT87_REG_AVCC3);
+
+ for (i = 0; i < 6; i++) {
+ /* Skip disabled fans */
+ if (!(data->has_fan & (1 << i)))
+ continue;
+
+ data->fan[i][1] =
+ it87_read_value(data, IT87_REG_FAN_MIN[i]);
+ data->fan[i][0] = it87_read_value(data,
+ IT87_REG_FAN[i]);
+ /* Add high byte if in 16-bit mode */
+ if (has_16bit_fans(data)) {
+ data->fan[i][0] |= it87_read_value(data,
+ IT87_REG_FANX[i]) << 8;
+ data->fan[i][1] |= it87_read_value(data,
+ IT87_REG_FANX_MIN[i]) << 8;
+ }
+ }
+ for (i = 0; i < 3; i++) {
+ if (!(data->has_temp & (1 << i)))
+ continue;
+ data->temp[i][0] =
+ it87_read_value(data, IT87_REG_TEMP(i));
+ data->temp[i][1] =
+ it87_read_value(data, IT87_REG_TEMP_LOW(i));
+ data->temp[i][2] =
+ it87_read_value(data, IT87_REG_TEMP_HIGH(i));
+ if (has_temp_offset(data))
+ data->temp[i][3] =
+ it87_read_value(data,
+ IT87_REG_TEMP_OFFSET[i]);
+ }
+
+ /* Newer chips don't have clock dividers */
+ if ((data->has_fan & 0x07) && !has_16bit_fans(data)) {
+ i = it87_read_value(data, IT87_REG_FAN_DIV);
+ data->fan_div[0] = i & 0x07;
+ data->fan_div[1] = (i >> 3) & 0x07;
+ data->fan_div[2] = (i & 0x40) ? 3 : 1;
+ }
+
+ data->alarms =
+ it87_read_value(data, IT87_REG_ALARM1) |
+ (it87_read_value(data, IT87_REG_ALARM2) << 8) |
+ (it87_read_value(data, IT87_REG_ALARM3) << 16);
+ data->beeps = it87_read_value(data, IT87_REG_BEEP_ENABLE);
+
+ data->fan_main_ctrl = it87_read_value(data,
+ IT87_REG_FAN_MAIN_CTRL);
+ data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL);
+ for (i = 0; i < 6; i++)
+ it87_update_pwm_ctrl(data, i);
+
+ data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
+ data->extra = it87_read_value(data, IT87_REG_TEMP_EXTRA);
+ /*
+ * The IT8705F does not have VID capability.
+ * The IT8718F and later don't use IT87_REG_VID for the
+ * same purpose.
+ */
+ if (data->type == it8712 || data->type == it8716) {
+ data->vid = it87_read_value(data, IT87_REG_VID);
+ /*
+ * The older IT8712F revisions had only 5 VID pins,
+ * but we assume it is always safe to read 6 bits.
+ */
+ data->vid &= 0x3f;
+ }
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}

static ssize_t show_in(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -2341,64 +2478,233 @@ static void it87_remove_files(struct device *dev)
sysfs_remove_group(&dev->kobj, &it87_group_label);
}

-static int it87_probe(struct platform_device *pdev)
+/* Called when we have found a new IT87. */
+static void it87_init_device(struct platform_device *pdev)
{
- struct it87_data *data;
- struct resource *res;
- struct device *dev = &pdev->dev;
- struct it87_sio_data *sio_data = dev_get_platdata(dev);
- int err = 0, i;
- int enable_pwm_interface;
- int fan_beep_need_rw;
+ struct it87_sio_data *sio_data = dev_get_platdata(&pdev->dev);
+ struct it87_data *data = platform_get_drvdata(pdev);
+ int tmp, i;
+ u8 mask;

- res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT,
- DRVNAME)) {
- dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
- (unsigned long)res->start,
- (unsigned long)(res->start + IT87_EC_EXTENT - 1));
- return -EBUSY;
+ /*
+ * For each PWM channel:
+ * - If it is in automatic mode, setting to manual mode should set
+ * the fan to full speed by default.
+ * - If it is in manual mode, we need a mapping to temperature
+ * channels to use when later setting to automatic mode later.
+ * Use a 1:1 mapping by default (we are clueless.)
+ * In both cases, the value can (and should) be changed by the user
+ * prior to switching to a different mode.
+ * Note that this is no longer needed for the IT8721F and later, as
+ * these have separate registers for the temperature mapping and the
+ * manual duty cycle.
+ */
+ for (i = 0; i < 3; i++) {
+ data->pwm_temp_map[i] = i;
+ data->pwm_duty[i] = 0x7f; /* Full speed */
+ data->auto_pwm[i][3] = 0x7f; /* Full speed, hard-coded */
}

- data = devm_kzalloc(&pdev->dev, sizeof(struct it87_data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- data->addr = res->start;
- data->type = sio_data->type;
- data->features = it87_devices[sio_data->type].features;
- data->peci_mask = it87_devices[sio_data->type].peci_mask;
- data->old_peci_mask = it87_devices[sio_data->type].old_peci_mask;
- data->name = it87_devices[sio_data->type].name;
/*
- * IT8705F Datasheet 0.4.1, 3h == Version G.
- * IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J.
- * These are the first revisions with 16-bit tachometer support.
+ * Some chips seem to have default value 0xff for all limit
+ * registers. For low voltage limits it makes no sense and triggers
+ * alarms, so change to 0 instead. For high temperature limits, it
+ * means -1 degree C, which surprisingly doesn't trigger an alarm,
+ * but is still confusing, so change to 127 degrees C.
*/
- switch (data->type) {
- case it87:
- if (sio_data->revision >= 0x03) {
- data->features &= ~FEAT_OLD_AUTOPWM;
- data->features |= FEAT_FAN16_CONFIG | FEAT_16BIT_FANS;
- }
- break;
- case it8712:
- if (sio_data->revision >= 0x08) {
- data->features &= ~FEAT_OLD_AUTOPWM;
- data->features |= FEAT_FAN16_CONFIG | FEAT_16BIT_FANS |
- FEAT_FIVE_FANS;
- }
- break;
- default:
- break;
+ for (i = 0; i < 8; i++) {
+ tmp = it87_read_value(data, IT87_REG_VIN_MIN(i));
+ if (tmp == 0xff)
+ it87_write_value(data, IT87_REG_VIN_MIN(i), 0);
+ }
+ for (i = 0; i < 3; i++) {
+ tmp = it87_read_value(data, IT87_REG_TEMP_HIGH(i));
+ if (tmp == 0xff)
+ it87_write_value(data, IT87_REG_TEMP_HIGH(i), 127);
}

- /* Now, we do the remaining detection. */
- if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80)
- || it87_read_value(data, IT87_REG_CHIPID) != 0x90)
- return -ENODEV;
+ /*
+ * Temperature channels are not forcibly enabled, as they can be
+ * set to two different sensor types and we can't guess which one
+ * is correct for a given system. These channels can be enabled at
+ * run-time through the temp{1-3}_type sysfs accessors if needed.
+ */

- platform_set_drvdata(pdev, data);
+ /* Check if voltage monitors are reset manually or by some reason */
+ tmp = it87_read_value(data, IT87_REG_VIN_ENABLE);
+ if ((tmp & 0xff) == 0) {
+ /* Enable all voltage monitors */
+ it87_write_value(data, IT87_REG_VIN_ENABLE, 0xff);
+ }
+
+ /* Check if tachometers are reset manually or by some reason */
+ mask = 0x70 & ~(sio_data->skip_fan << 4);
+ data->fan_main_ctrl = it87_read_value(data, IT87_REG_FAN_MAIN_CTRL);
+ if ((data->fan_main_ctrl & mask) == 0) {
+ /* Enable all fan tachometers */
+ data->fan_main_ctrl |= mask;
+ it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
+ data->fan_main_ctrl);
+ }
+ data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
+
+ tmp = it87_read_value(data, IT87_REG_FAN_16BIT);
+
+ /* Set tachometers to 16-bit mode if needed */
+ if (has_fan16_config(data)) {
+ if (~tmp & 0x07 & data->has_fan) {
+ dev_dbg(&pdev->dev,
+ "Setting fan1-3 to 16-bit mode\n");
+ it87_write_value(data, IT87_REG_FAN_16BIT,
+ tmp | 0x07);
+ }
+ }
+
+ /* Check for additional fans */
+ if (has_five_fans(data)) {
+ if (tmp & (1 << 4))
+ data->has_fan |= (1 << 3); /* fan4 enabled */
+ if (tmp & (1 << 5))
+ data->has_fan |= (1 << 4); /* fan5 enabled */
+ if (has_six_fans(data) && (tmp & (1 << 2)))
+ data->has_fan |= (1 << 5); /* fan6 enabled */
+ }
+
+ /* Fan input pins may be used for alternative functions */
+ data->has_fan &= ~sio_data->skip_fan;
+
+ /* Check if pwm5, pwm6 are enabled */
+ if (has_six_pwm(data)) {
+ /* The following code may be IT8620E specific */
+ tmp = it87_read_value(data, IT87_REG_FAN_DIV);
+ if ((tmp & 0xc0) == 0xc0)
+ sio_data->skip_pwm |= (1 << 4);
+ if (!(tmp & (1 << 3)))
+ sio_data->skip_pwm |= (1 << 5);
+ }
+
+ /* Start monitoring */
+ it87_write_value(data, IT87_REG_CONFIG,
+ (it87_read_value(data, IT87_REG_CONFIG) & 0x3e)
+ | (update_vbat ? 0x41 : 0x01));
+}
+
+/* Return 1 if and only if the PWM interface is safe to use */
+static int it87_check_pwm(struct device *dev)
+{
+ struct it87_data *data = dev_get_drvdata(dev);
+ /*
+ * Some BIOSes fail to correctly configure the IT87 fans. All fans off
+ * and polarity set to active low is sign that this is the case so we
+ * disable pwm control to protect the user.
+ */
+ int tmp = it87_read_value(data, IT87_REG_FAN_CTL);
+
+ if ((tmp & 0x87) == 0) {
+ if (fix_pwm_polarity) {
+ /*
+ * The user asks us to attempt a chip reconfiguration.
+ * This means switching to active high polarity and
+ * inverting all fan speed values.
+ */
+ int i;
+ u8 pwm[3];
+
+ for (i = 0; i < 3; i++)
+ pwm[i] = it87_read_value(data,
+ IT87_REG_PWM[i]);
+
+ /*
+ * If any fan is in automatic pwm mode, the polarity
+ * might be correct, as suspicious as it seems, so we
+ * better don't change anything (but still disable the
+ * PWM interface).
+ */
+ if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) {
+ dev_info(dev,
+ "Reconfiguring PWM to active high polarity\n");
+ it87_write_value(data, IT87_REG_FAN_CTL,
+ tmp | 0x87);
+ for (i = 0; i < 3; i++)
+ it87_write_value(data,
+ IT87_REG_PWM[i],
+ 0x7f & ~pwm[i]);
+ return 1;
+ }
+
+ dev_info(dev,
+ "PWM configuration is too broken to be fixed\n");
+ }
+
+ dev_info(dev,
+ "Detected broken BIOS defaults, disabling PWM interface\n");
+ return 0;
+ } else if (fix_pwm_polarity) {
+ dev_info(dev,
+ "PWM configuration looks sane, won't touch\n");
+ }
+
+ return 1;
+}
+
+static int it87_probe(struct platform_device *pdev)
+{
+ struct it87_data *data;
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ struct it87_sio_data *sio_data = dev_get_platdata(dev);
+ int err = 0, i;
+ int enable_pwm_interface;
+ int fan_beep_need_rw;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT,
+ DRVNAME)) {
+ dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
+ (unsigned long)res->start,
+ (unsigned long)(res->start + IT87_EC_EXTENT - 1));
+ return -EBUSY;
+ }
+
+ data = devm_kzalloc(&pdev->dev, sizeof(struct it87_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->addr = res->start;
+ data->type = sio_data->type;
+ data->features = it87_devices[sio_data->type].features;
+ data->peci_mask = it87_devices[sio_data->type].peci_mask;
+ data->old_peci_mask = it87_devices[sio_data->type].old_peci_mask;
+ data->name = it87_devices[sio_data->type].name;
+ /*
+ * IT8705F Datasheet 0.4.1, 3h == Version G.
+ * IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J.
+ * These are the first revisions with 16-bit tachometer support.
+ */
+ switch (data->type) {
+ case it87:
+ if (sio_data->revision >= 0x03) {
+ data->features &= ~FEAT_OLD_AUTOPWM;
+ data->features |= FEAT_FAN16_CONFIG | FEAT_16BIT_FANS;
+ }
+ break;
+ case it8712:
+ if (sio_data->revision >= 0x08) {
+ data->features &= ~FEAT_OLD_AUTOPWM;
+ data->features |= FEAT_FAN16_CONFIG | FEAT_16BIT_FANS |
+ FEAT_FIVE_FANS;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Now, we do the remaining detection. */
+ if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80)
+ || it87_read_value(data, IT87_REG_CHIPID) != 0x90)
+ return -ENODEV;
+
+ platform_set_drvdata(pdev, data);

mutex_init(&data->update_lock);

@@ -2570,328 +2876,13 @@ static int it87_remove(struct platform_device *pdev)
return 0;
}

-/*
- * Must be called with data->update_lock held, except during initialization.
- * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
- * would slow down the IT87 access and should not be necessary.
- */
-static int it87_read_value(struct it87_data *data, u8 reg)
-{
- outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
- return inb_p(data->addr + IT87_DATA_REG_OFFSET);
-}
-
-/*
- * Must be called with data->update_lock held, except during initialization.
- * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
- * would slow down the IT87 access and should not be necessary.
- */
-static void it87_write_value(struct it87_data *data, u8 reg, u8 value)
-{
- outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
- outb_p(value, data->addr + IT87_DATA_REG_OFFSET);
-}
-
-/* Return 1 if and only if the PWM interface is safe to use */
-static int it87_check_pwm(struct device *dev)
-{
- struct it87_data *data = dev_get_drvdata(dev);
- /*
- * Some BIOSes fail to correctly configure the IT87 fans. All fans off
- * and polarity set to active low is sign that this is the case so we
- * disable pwm control to protect the user.
- */
- int tmp = it87_read_value(data, IT87_REG_FAN_CTL);
- if ((tmp & 0x87) == 0) {
- if (fix_pwm_polarity) {
- /*
- * The user asks us to attempt a chip reconfiguration.
- * This means switching to active high polarity and
- * inverting all fan speed values.
- */
- int i;
- u8 pwm[3];
-
- for (i = 0; i < 3; i++)
- pwm[i] = it87_read_value(data,
- IT87_REG_PWM[i]);
-
- /*
- * If any fan is in automatic pwm mode, the polarity
- * might be correct, as suspicious as it seems, so we
- * better don't change anything (but still disable the
- * PWM interface).
- */
- if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) {
- dev_info(dev,
- "Reconfiguring PWM to active high polarity\n");
- it87_write_value(data, IT87_REG_FAN_CTL,
- tmp | 0x87);
- for (i = 0; i < 3; i++)
- it87_write_value(data,
- IT87_REG_PWM[i],
- 0x7f & ~pwm[i]);
- return 1;
- }
-
- dev_info(dev,
- "PWM configuration is too broken to be fixed\n");
- }
-
- dev_info(dev,
- "Detected broken BIOS defaults, disabling PWM interface\n");
- return 0;
- } else if (fix_pwm_polarity) {
- dev_info(dev,
- "PWM configuration looks sane, won't touch\n");
- }
-
- return 1;
-}
-
-/* Called when we have found a new IT87. */
-static void it87_init_device(struct platform_device *pdev)
-{
- struct it87_sio_data *sio_data = dev_get_platdata(&pdev->dev);
- struct it87_data *data = platform_get_drvdata(pdev);
- int tmp, i;
- u8 mask;
-
- /*
- * For each PWM channel:
- * - If it is in automatic mode, setting to manual mode should set
- * the fan to full speed by default.
- * - If it is in manual mode, we need a mapping to temperature
- * channels to use when later setting to automatic mode later.
- * Use a 1:1 mapping by default (we are clueless.)
- * In both cases, the value can (and should) be changed by the user
- * prior to switching to a different mode.
- * Note that this is no longer needed for the IT8721F and later, as
- * these have separate registers for the temperature mapping and the
- * manual duty cycle.
- */
- for (i = 0; i < 3; i++) {
- data->pwm_temp_map[i] = i;
- data->pwm_duty[i] = 0x7f; /* Full speed */
- data->auto_pwm[i][3] = 0x7f; /* Full speed, hard-coded */
- }
-
- /*
- * Some chips seem to have default value 0xff for all limit
- * registers. For low voltage limits it makes no sense and triggers
- * alarms, so change to 0 instead. For high temperature limits, it
- * means -1 degree C, which surprisingly doesn't trigger an alarm,
- * but is still confusing, so change to 127 degrees C.
- */
- for (i = 0; i < 8; i++) {
- tmp = it87_read_value(data, IT87_REG_VIN_MIN(i));
- if (tmp == 0xff)
- it87_write_value(data, IT87_REG_VIN_MIN(i), 0);
- }
- for (i = 0; i < 3; i++) {
- tmp = it87_read_value(data, IT87_REG_TEMP_HIGH(i));
- if (tmp == 0xff)
- it87_write_value(data, IT87_REG_TEMP_HIGH(i), 127);
- }
-
- /*
- * Temperature channels are not forcibly enabled, as they can be
- * set to two different sensor types and we can't guess which one
- * is correct for a given system. These channels can be enabled at
- * run-time through the temp{1-3}_type sysfs accessors if needed.
- */
-
- /* Check if voltage monitors are reset manually or by some reason */
- tmp = it87_read_value(data, IT87_REG_VIN_ENABLE);
- if ((tmp & 0xff) == 0) {
- /* Enable all voltage monitors */
- it87_write_value(data, IT87_REG_VIN_ENABLE, 0xff);
- }
-
- /* Check if tachometers are reset manually or by some reason */
- mask = 0x70 & ~(sio_data->skip_fan << 4);
- data->fan_main_ctrl = it87_read_value(data, IT87_REG_FAN_MAIN_CTRL);
- if ((data->fan_main_ctrl & mask) == 0) {
- /* Enable all fan tachometers */
- data->fan_main_ctrl |= mask;
- it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
- data->fan_main_ctrl);
- }
- data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
-
- tmp = it87_read_value(data, IT87_REG_FAN_16BIT);
-
- /* Set tachometers to 16-bit mode if needed */
- if (has_fan16_config(data)) {
- if (~tmp & 0x07 & data->has_fan) {
- dev_dbg(&pdev->dev,
- "Setting fan1-3 to 16-bit mode\n");
- it87_write_value(data, IT87_REG_FAN_16BIT,
- tmp | 0x07);
- }
- }
-
- /* Check for additional fans */
- if (has_five_fans(data)) {
- if (tmp & (1 << 4))
- data->has_fan |= (1 << 3); /* fan4 enabled */
- if (tmp & (1 << 5))
- data->has_fan |= (1 << 4); /* fan5 enabled */
- if (has_six_fans(data) && (tmp & (1 << 2)))
- data->has_fan |= (1 << 5); /* fan6 enabled */
- }
-
- /* Fan input pins may be used for alternative functions */
- data->has_fan &= ~sio_data->skip_fan;
-
- /* Check if pwm5, pwm6 are enabled */
- if (has_six_pwm(data)) {
- /* The following code may be IT8620E specific */
- tmp = it87_read_value(data, IT87_REG_FAN_DIV);
- if ((tmp & 0xc0) == 0xc0)
- sio_data->skip_pwm |= (1 << 4);
- if (!(tmp & (1 << 3)))
- sio_data->skip_pwm |= (1 << 5);
- }
-
- /* Start monitoring */
- it87_write_value(data, IT87_REG_CONFIG,
- (it87_read_value(data, IT87_REG_CONFIG) & 0x3e)
- | (update_vbat ? 0x41 : 0x01));
-}
-
-static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
-{
- data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM[nr]);
- if (has_newer_autopwm(data)) {
- data->pwm_temp_map[nr] = (data->pwm_ctrl[nr] & 0x03) +
- nr < 3 ? 0 : 3;
- data->pwm_duty[nr] = it87_read_value(data,
- IT87_REG_PWM_DUTY[nr]);
- } else {
- if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */
- data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
- else /* Manual mode */
- data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f;
- }
-
- if (has_old_autopwm(data)) {
- int i;
-
- for (i = 0; i < 5 ; i++)
- data->auto_temp[nr][i] = it87_read_value(data,
- IT87_REG_AUTO_TEMP(nr, i));
- for (i = 0; i < 3 ; i++)
- data->auto_pwm[nr][i] = it87_read_value(data,
- IT87_REG_AUTO_PWM(nr, i));
- }
-}
-
-static struct it87_data *it87_update_device(struct device *dev)
-{
- struct it87_data *data = dev_get_drvdata(dev);
- int i;
-
- mutex_lock(&data->update_lock);
-
- if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
- || !data->valid) {
- if (update_vbat) {
- /*
- * Cleared after each update, so reenable. Value
- * returned by this read will be previous value
- */
- it87_write_value(data, IT87_REG_CONFIG,
- it87_read_value(data, IT87_REG_CONFIG) | 0x40);
- }
- for (i = 0; i <= 7; i++) {
- data->in[i][0] =
- it87_read_value(data, IT87_REG_VIN(i));
- data->in[i][1] =
- it87_read_value(data, IT87_REG_VIN_MIN(i));
- data->in[i][2] =
- it87_read_value(data, IT87_REG_VIN_MAX(i));
- }
- /* in8 (battery) has no limit registers */
- data->in[8][0] = it87_read_value(data, IT87_REG_VIN(8));
- if (has_avcc3(data))
- data->in[9][0] = it87_read_value(data, IT87_REG_AVCC3);
-
- for (i = 0; i < 6; i++) {
- /* Skip disabled fans */
- if (!(data->has_fan & (1 << i)))
- continue;
-
- data->fan[i][1] =
- it87_read_value(data, IT87_REG_FAN_MIN[i]);
- data->fan[i][0] = it87_read_value(data,
- IT87_REG_FAN[i]);
- /* Add high byte if in 16-bit mode */
- if (has_16bit_fans(data)) {
- data->fan[i][0] |= it87_read_value(data,
- IT87_REG_FANX[i]) << 8;
- data->fan[i][1] |= it87_read_value(data,
- IT87_REG_FANX_MIN[i]) << 8;
- }
- }
- for (i = 0; i < 3; i++) {
- if (!(data->has_temp & (1 << i)))
- continue;
- data->temp[i][0] =
- it87_read_value(data, IT87_REG_TEMP(i));
- data->temp[i][1] =
- it87_read_value(data, IT87_REG_TEMP_LOW(i));
- data->temp[i][2] =
- it87_read_value(data, IT87_REG_TEMP_HIGH(i));
- if (has_temp_offset(data))
- data->temp[i][3] =
- it87_read_value(data,
- IT87_REG_TEMP_OFFSET[i]);
- }
-
- /* Newer chips don't have clock dividers */
- if ((data->has_fan & 0x07) && !has_16bit_fans(data)) {
- i = it87_read_value(data, IT87_REG_FAN_DIV);
- data->fan_div[0] = i & 0x07;
- data->fan_div[1] = (i >> 3) & 0x07;
- data->fan_div[2] = (i & 0x40) ? 3 : 1;
- }
-
- data->alarms =
- it87_read_value(data, IT87_REG_ALARM1) |
- (it87_read_value(data, IT87_REG_ALARM2) << 8) |
- (it87_read_value(data, IT87_REG_ALARM3) << 16);
- data->beeps = it87_read_value(data, IT87_REG_BEEP_ENABLE);
-
- data->fan_main_ctrl = it87_read_value(data,
- IT87_REG_FAN_MAIN_CTRL);
- data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL);
- for (i = 0; i < 6; i++)
- it87_update_pwm_ctrl(data, i);
-
- data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
- data->extra = it87_read_value(data, IT87_REG_TEMP_EXTRA);
- /*
- * The IT8705F does not have VID capability.
- * The IT8718F and later don't use IT87_REG_VID for the
- * same purpose.
- */
- if (data->type == it8712 || data->type == it8716) {
- data->vid = it87_read_value(data, IT87_REG_VID);
- /*
- * The older IT8712F revisions had only 5 VID pins,
- * but we assume it is always safe to read 6 bits.
- */
- data->vid &= 0x3f;
- }
- data->last_updated = jiffies;
- data->valid = 1;
- }
-
- mutex_unlock(&data->update_lock);
-
- return data;
-}
+static struct platform_driver it87_driver = {
+ .driver = {
+ .name = DRVNAME,
+ },
+ .probe = it87_probe,
+ .remove = it87_remove,
+};

static int __init it87_device_add(int index, unsigned short address,
const struct it87_sio_data *sio_data)
--
2.1.4
Guenter Roeck
2016-01-27 02:03:46 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

Several of the chips supported by this driver have a configuration
register to enable fan4 and fan5. Use those registers to determine
if fan4 and fan5 tachometers are supported.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index f40d81a0a9fc..5adb269918fb 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -2415,6 +2415,29 @@ static int __init it87_find(int sioaddr, unsigned short *address,

superio_select(sioaddr, GPIO);

+ /* Check for fan4, fan5 */
+ if (has_five_fans(config)) {
+ reg = superio_inb(sioaddr, IT87_SIO_GPIO2_REG);
+ switch (sio_data->type) {
+ case it8718:
+ if (reg & BIT(5))
+ sio_data->skip_fan |= BIT(3);
+ if (reg & BIT(4))
+ sio_data->skip_fan |= BIT(4);
+ break;
+ case it8720:
+ case it8721:
+ case it8728:
+ if (!(reg & BIT(5)))
+ sio_data->skip_fan |= BIT(3);
+ if (!(reg & BIT(4)))
+ sio_data->skip_fan |= BIT(4);
+ break;
+ default:
+ break;
+ }
+ }
+
reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
if (!sio_data->skip_vid) {
/* We need at least 4 VID pins */
--
2.1.4
Guenter Roeck
2016-01-27 02:03:47 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 187 insertions(+), 14 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 5adb269918fb..e3fbcf49afdb 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -252,8 +252,10 @@ static const u8 IT87_REG_VIN[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,

#define IT87_REG_CHIPID 0x58

-#define IT87_REG_AUTO_TEMP(nr, i) (0x60 + (nr) * 8 + (i))
-#define IT87_REG_AUTO_PWM(nr, i) (0x65 + (nr) * 8 + (i))
+static const u8 IT87_REG_AUTO_BASE[] = { 0x60, 0x68, 0x70, 0x78, 0xa0, 0xa8 };
+
+#define IT87_REG_AUTO_TEMP(nr, i) (IT87_REG_AUTO_BASE[nr] + (i))
+#define IT87_REG_AUTO_PWM(nr, i) (IT87_REG_AUTO_BASE[nr] + 5 + (i))

#define IT87_REG_TEMP456_ENABLE 0x77

@@ -673,6 +675,30 @@ static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
for (i = 0; i < 3 ; i++)
data->auto_pwm[nr][i] = it87_read_value(data,
IT87_REG_AUTO_PWM(nr, i));
+ } else if (has_newer_autopwm(data)) {
+ int i;
+
+ /*
+ * 0: temperature hysteresis (base + 5)
+ * 1: fan off temperature (base + 0)
+ * 2: fan start temperature (base + 1)
+ * 3: fan max temperature (base + 2)
+ */
+ data->auto_temp[nr][0] =
+ it87_read_value(data, IT87_REG_AUTO_TEMP(nr, 5));
+
+ for (i = 0; i < 3 ; i++)
+ data->auto_temp[nr][i + 1] =
+ it87_read_value(data,
+ IT87_REG_AUTO_TEMP(nr, i));
+ /*
+ * 0: start pwm value (base + 3)
+ * 1: pwm slope (base + 4, 1/8th pwm)
+ */
+ data->auto_pwm[nr][0] =
+ it87_read_value(data, IT87_REG_AUTO_TEMP(nr, 3));
+ data->auto_pwm[nr][1] =
+ it87_read_value(data, IT87_REG_AUTO_TEMP(nr, 4));
}
}

@@ -1216,6 +1242,11 @@ static int check_trip_points(struct device *dev, int nr)
if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
err = -EINVAL;
}
+ } else if (has_newer_autopwm(data)) {
+ for (i = 1; i < 3; i++) {
+ if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
+ err = -EINVAL;
+ }
}

if (err) {
@@ -1441,6 +1472,7 @@ static ssize_t set_auto_pwm(struct device *dev, struct device_attribute *attr,
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int point = sensor_attr->index;
+ int regaddr;
long val;

if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 255)
@@ -1448,8 +1480,41 @@ static ssize_t set_auto_pwm(struct device *dev, struct device_attribute *attr,

mutex_lock(&data->update_lock);
data->auto_pwm[nr][point] = pwm_to_reg(data, val);
- it87_write_value(data, IT87_REG_AUTO_PWM(nr, point),
- data->auto_pwm[nr][point]);
+ if (has_newer_autopwm(data))
+ regaddr = IT87_REG_AUTO_TEMP(nr, 3);
+ else
+ regaddr = IT87_REG_AUTO_PWM(nr, point);
+ it87_write_value(data, regaddr, data->auto_pwm[nr][point]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t show_auto_pwm_slope(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct it87_data *data = it87_update_device(dev);
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+
+ return sprintf(buf, "%d\n", data->auto_pwm[nr][1] & 0x7f);
+}
+
+static ssize_t set_auto_pwm_slope(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct it87_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ unsigned long val;
+
+ if (kstrtoul(buf, 10, &val) < 0 || val > 127)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ data->auto_pwm[nr][1] = (data->auto_pwm[nr][1] & 0x80) | val;
+ it87_write_value(data, IT87_REG_AUTO_TEMP(nr, 4),
+ data->auto_pwm[nr][1]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -1462,8 +1527,14 @@ static ssize_t show_auto_temp(struct device *dev, struct device_attribute *attr,
to_sensor_dev_attr_2(attr);
int nr = sensor_attr->nr;
int point = sensor_attr->index;
+ int reg;
+
+ if (has_old_autopwm(data) || point)
+ reg = data->auto_temp[nr][point];
+ else
+ reg = data->auto_temp[nr][1] - (data->auto_temp[nr][0] & 0x1f);

- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->auto_temp[nr][point]));
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(reg));
}

static ssize_t set_auto_temp(struct device *dev, struct device_attribute *attr,
@@ -1475,14 +1546,24 @@ static ssize_t set_auto_temp(struct device *dev, struct device_attribute *attr,
int nr = sensor_attr->nr;
int point = sensor_attr->index;
long val;
+ int reg;

if (kstrtol(buf, 10, &val) < 0 || val < -128000 || val > 127000)
return -EINVAL;

mutex_lock(&data->update_lock);
- data->auto_temp[nr][point] = TEMP_TO_REG(val);
- it87_write_value(data, IT87_REG_AUTO_TEMP(nr, point),
- data->auto_temp[nr][point]);
+ if (has_newer_autopwm(data) && !point) {
+ reg = data->auto_temp[nr][1] - TEMP_TO_REG(val);
+ reg = clamp_val(reg, 0, 0x1f) | (data->auto_temp[nr][0] & 0xe0);
+ data->auto_temp[nr][0] = reg;
+ it87_write_value(data, IT87_REG_AUTO_TEMP(nr, 5), reg);
+ } else {
+ reg = TEMP_TO_REG(val);
+ data->auto_temp[nr][point] = reg;
+ if (has_newer_autopwm(data))
+ point--;
+ it87_write_value(data, IT87_REG_AUTO_TEMP(nr, point), reg);
+ }
mutex_unlock(&data->update_lock);
return count;
}
@@ -1542,6 +1623,10 @@ static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR,
show_auto_temp, set_auto_temp, 0, 3);
static SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_temp, S_IRUGO | S_IWUSR,
show_auto_temp, set_auto_temp, 0, 4);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_start, S_IRUGO | S_IWUSR,
+ show_auto_pwm, set_auto_pwm, 0, 0);
+static SENSOR_DEVICE_ATTR(pwm1_auto_slope, S_IRUGO | S_IWUSR,
+ show_auto_pwm_slope, set_auto_pwm_slope, 0);

static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 1);
@@ -1567,6 +1652,10 @@ static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR,
show_auto_temp, set_auto_temp, 1, 3);
static SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_temp, S_IRUGO | S_IWUSR,
show_auto_temp, set_auto_temp, 1, 4);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_start, S_IRUGO | S_IWUSR,
+ show_auto_pwm, set_auto_pwm, 1, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_slope, S_IRUGO | S_IWUSR,
+ show_auto_pwm_slope, set_auto_pwm_slope, 1);

static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 2);
@@ -1592,6 +1681,10 @@ static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR,
show_auto_temp, set_auto_temp, 2, 3);
static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_temp, S_IRUGO | S_IWUSR,
show_auto_temp, set_auto_temp, 2, 4);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_start, S_IRUGO | S_IWUSR,
+ show_auto_pwm, set_auto_pwm, 2, 0);
+static SENSOR_DEVICE_ATTR(pwm3_auto_slope, S_IRUGO | S_IWUSR,
+ show_auto_pwm_slope, set_auto_pwm_slope, 2);

static SENSOR_DEVICE_ATTR(pwm4_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 3);
@@ -1599,6 +1692,18 @@ static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 3);
static SENSOR_DEVICE_ATTR(pwm4_freq, S_IRUGO, show_pwm_freq, NULL, 3);
static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IRUGO,
show_pwm_temp_map, set_pwm_temp_map, 3);
+static SENSOR_DEVICE_ATTR_2(pwm4_auto_point1_temp, S_IRUGO | S_IWUSR,
+ show_auto_temp, set_auto_temp, 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
+ show_auto_temp, set_auto_temp, 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm4_auto_point2_temp, S_IRUGO | S_IWUSR,
+ show_auto_temp, set_auto_temp, 2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm4_auto_point3_temp, S_IRUGO | S_IWUSR,
+ show_auto_temp, set_auto_temp, 2, 3);
+static SENSOR_DEVICE_ATTR_2(pwm4_auto_start, S_IRUGO | S_IWUSR,
+ show_auto_pwm, set_auto_pwm, 3, 0);
+static SENSOR_DEVICE_ATTR(pwm4_auto_slope, S_IRUGO | S_IWUSR,
+ show_auto_pwm_slope, set_auto_pwm_slope, 3);

static SENSOR_DEVICE_ATTR(pwm5_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 4);
@@ -1606,6 +1711,18 @@ static SENSOR_DEVICE_ATTR(pwm5, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 4);
static SENSOR_DEVICE_ATTR(pwm5_freq, S_IRUGO, show_pwm_freq, NULL, 4);
static SENSOR_DEVICE_ATTR(pwm5_auto_channels_temp, S_IRUGO,
show_pwm_temp_map, set_pwm_temp_map, 4);
+static SENSOR_DEVICE_ATTR_2(pwm5_auto_point1_temp, S_IRUGO | S_IWUSR,
+ show_auto_temp, set_auto_temp, 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm5_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
+ show_auto_temp, set_auto_temp, 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm5_auto_point2_temp, S_IRUGO | S_IWUSR,
+ show_auto_temp, set_auto_temp, 2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm5_auto_point3_temp, S_IRUGO | S_IWUSR,
+ show_auto_temp, set_auto_temp, 2, 3);
+static SENSOR_DEVICE_ATTR_2(pwm5_auto_start, S_IRUGO | S_IWUSR,
+ show_auto_pwm, set_auto_pwm, 4, 0);
+static SENSOR_DEVICE_ATTR(pwm5_auto_slope, S_IRUGO | S_IWUSR,
+ show_auto_pwm_slope, set_auto_pwm_slope, 4);

static SENSOR_DEVICE_ATTR(pwm6_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 5);
@@ -1613,6 +1730,18 @@ static SENSOR_DEVICE_ATTR(pwm6, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 5);
static SENSOR_DEVICE_ATTR(pwm6_freq, S_IRUGO, show_pwm_freq, NULL, 5);
static SENSOR_DEVICE_ATTR(pwm6_auto_channels_temp, S_IRUGO,
show_pwm_temp_map, set_pwm_temp_map, 5);
+static SENSOR_DEVICE_ATTR_2(pwm6_auto_point1_temp, S_IRUGO | S_IWUSR,
+ show_auto_temp, set_auto_temp, 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm6_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
+ show_auto_temp, set_auto_temp, 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm6_auto_point2_temp, S_IRUGO | S_IWUSR,
+ show_auto_temp, set_auto_temp, 2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm6_auto_point3_temp, S_IRUGO | S_IWUSR,
+ show_auto_temp, set_auto_temp, 2, 3);
+static SENSOR_DEVICE_ATTR_2(pwm6_auto_start, S_IRUGO | S_IWUSR,
+ show_auto_pwm, set_auto_pwm, 5, 0);
+static SENSOR_DEVICE_ATTR(pwm6_auto_slope, S_IRUGO | S_IWUSR,
+ show_auto_pwm_slope, set_auto_pwm_slope, 5);

/* Alarms */
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
@@ -2050,8 +2179,8 @@ static umode_t it87_pwm_is_visible(struct kobject *kobj,
if (!(data->has_pwm & BIT(i)))
return 0;

- /* pwmX_auto_channels_temp is only writable for old auto pwm */
- if (a == 3 && has_old_autopwm(data))
+ /* pwmX_auto_channels_temp is only writable if auto pwm is supported */
+ if (a == 3 && (has_old_autopwm(data) || has_newer_autopwm(data)))
return attr->mode | S_IWUSR;

/* pwm2_freq is writable if there are two pwm frequency selects */
@@ -2105,11 +2234,28 @@ static umode_t it87_auto_pwm_is_visible(struct kobject *kobj,
{
struct device *dev = container_of(kobj, struct device, kobj);
struct it87_data *data = dev_get_drvdata(dev);
- int i = index / 9; /* pwm index */
+ int i = index / 11; /* pwm index */
+ int a = index % 11; /* attribute index */
+
+ if (index >= 33) { /* pwm 4..6 */
+ i = (index - 33) / 6 + 3;
+ a = (index - 33) % 6 + 4;
+ }

if (!(data->has_pwm & BIT(i)))
return 0;

+ if (has_newer_autopwm(data)) {
+ if (a < 4) /* no auto point pwm */
+ return 0;
+ if (a == 8) /* no auto_point4 */
+ return 0;
+ }
+ if (has_old_autopwm(data)) {
+ if (a >= 9) /* no pwm_auto_start, pwm_auto_slope */
+ return 0;
+ }
+
return attr->mode;
}

@@ -2123,8 +2269,10 @@ static struct attribute *it87_attributes_auto_pwm[] = {
&sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_start.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_slope.dev_attr.attr,

- &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, /* 11 */
&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point3_pwm.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point4_pwm.dev_attr.attr,
@@ -2133,8 +2281,10 @@ static struct attribute *it87_attributes_auto_pwm[] = {
&sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point4_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_start.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_slope.dev_attr.attr,

- &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, /* 22 */
&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point3_pwm.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point4_pwm.dev_attr.attr,
@@ -2143,6 +2293,29 @@ static struct attribute *it87_attributes_auto_pwm[] = {
&sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point4_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_start.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_slope.dev_attr.attr,
+
+ &sensor_dev_attr_pwm4_auto_point1_temp.dev_attr.attr, /* 33 */
+ &sensor_dev_attr_pwm4_auto_point1_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_pwm4_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm4_auto_point3_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm4_auto_start.dev_attr.attr,
+ &sensor_dev_attr_pwm4_auto_slope.dev_attr.attr,
+
+ &sensor_dev_attr_pwm5_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm5_auto_point1_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_pwm5_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm5_auto_point3_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm5_auto_start.dev_attr.attr,
+ &sensor_dev_attr_pwm5_auto_slope.dev_attr.attr,
+
+ &sensor_dev_attr_pwm6_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm6_auto_point1_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_pwm6_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm6_auto_point3_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm6_auto_start.dev_attr.attr,
+ &sensor_dev_attr_pwm6_auto_slope.dev_attr.attr,

NULL,
};
@@ -2839,7 +3012,7 @@ static int it87_probe(struct platform_device *pdev)
data->has_pwm &= ~sio_data->skip_pwm;

data->groups[4] = &it87_group_pwm;
- if (has_old_autopwm(data))
+ if (has_old_autopwm(data) || has_newer_autopwm(data))
data->groups[5] = &it87_group_auto_pwm;
}
--
2.1.4
Guenter Roeck
2016-01-27 02:03:45 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

On/Off mode is only supported for pwm controls 0-2, and not supported at all for
IT8603E/IT8623E. For pwm controls 3-6 and for IT8603E/IT8623E, SmartGuardian mode
is always enabled. Use it and set the pwm value to the maximum if fan control
is disabled.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 52 +++++++++++++++++++++++++++++++---------------------
1 file changed, 31 insertions(+), 21 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 515c5cd1890b..f40d81a0a9fc 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -1030,18 +1030,19 @@ static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR, show_temp_type,
static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type,
set_temp_type, 2);

-/* 3 Fans */
+/* 6 Fans */

static int pwm_mode(const struct it87_data *data, int nr)
{
- int ctrl = data->fan_main_ctrl & BIT(nr);
+ if (data->type != it8603 && nr < 3 && !(data->fan_main_ctrl & BIT(nr)))
+ return 0; /* Full speed */
+ if (data->pwm_ctrl[nr] & 0x80)
+ return 2; /* Automatic mode */
+ if ((data->type == it8603 || nr >= 3) &&
+ data->pwm_duty[nr] == pwm_to_reg(data, 0xff))
+ return 0; /* Full speed */

- if (ctrl == 0 && data->type != it8603) /* Full speed */
- return 0;
- if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */
- return 2;
- else /* Manual mode */
- return 1;
+ return 1; /* Manual mode */
}

static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
@@ -1242,21 +1243,30 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
return -EINVAL;
}

- /* IT8603E does not have on/off mode */
- if (val == 0 && data->type == it8603)
- return -EINVAL;
-
mutex_lock(&data->update_lock);

if (val == 0) {
- int tmp;
- /* make sure the fan is on when in on/off mode */
- tmp = it87_read_value(data, IT87_REG_FAN_CTL);
- it87_write_value(data, IT87_REG_FAN_CTL, tmp | BIT(nr));
- /* set on/off mode */
- data->fan_main_ctrl &= ~BIT(nr);
- it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
- data->fan_main_ctrl);
+ if (nr < 3 && data->type != it8603) {
+ int tmp;
+ /* make sure the fan is on when in on/off mode */
+ tmp = it87_read_value(data, IT87_REG_FAN_CTL);
+ it87_write_value(data, IT87_REG_FAN_CTL, tmp | BIT(nr));
+ /* set on/off mode */
+ data->fan_main_ctrl &= ~BIT(nr);
+ it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
+ data->fan_main_ctrl);
+ } else {
+ /* No on/off mode, set maximum pwm value */
+ data->pwm_duty[nr] = pwm_to_reg(data, 0xff);
+ it87_write_value(data, IT87_REG_PWM_DUTY[nr],
+ data->pwm_duty[nr]);
+ /* and set manual mode */
+ data->pwm_ctrl[nr] = has_newer_autopwm(data) ?
+ data->pwm_temp_map[nr] :
+ data->pwm_duty[nr];
+ it87_write_value(data, IT87_REG_PWM[nr],
+ data->pwm_ctrl[nr]);
+ }
} else {
if (val == 1) /* Manual mode */
data->pwm_ctrl[nr] = has_newer_autopwm(data) ?
@@ -1266,7 +1276,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr];
it87_write_value(data, IT87_REG_PWM[nr], data->pwm_ctrl[nr]);

- if (data->type != it8603) {
+ if (data->type != it8603 && nr < 3) {
/* set SmartGuardian mode */
data->fan_main_ctrl |= BIT(nr);
it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
--
2.1.4
Guenter Roeck
2016-01-27 02:03:33 UTC
Permalink
From: Guenter Roeck <***@roeck-us.net>

Simplify code and reduce object size by more than 300 bytes on x86_64.

Signed-off-by: Guenter Roeck <***@roeck-us.net>
---
drivers/hwmon/it87.c | 124 +++++++++++++++++++++++----------------------------
1 file changed, 56 insertions(+), 68 deletions(-)

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 4b38ecb91959..81c11d1d67e2 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -471,6 +471,7 @@ struct it87_data {
unsigned long last_updated; /* In jiffies */

u16 in_scaled; /* Internal voltage sensors are scaled */
+ u16 has_in; /* Bitfield, voltage sensors enabled */
u8 in[10][3]; /* [nr][0]=in, [1]=min, [2]=max */
u8 has_fan; /* Bitfield, fans enabled */
u16 fan[6][2]; /* Register values, [nr][0]=fan, [1]=min */
@@ -482,6 +483,7 @@ struct it87_data {
u8 vid; /* Register encoding, combined */
u8 vrm;
u32 alarms; /* Register encoding, combined */
+ bool has_beep; /* true if beep supported */
u8 beeps; /* Register encoding */
u8 fan_main_ctrl; /* Register value */
u8 fan_ctl; /* Register value */
@@ -1751,74 +1753,85 @@ static ssize_t show_name(struct device *dev, struct device_attribute
}
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);

-static struct attribute *it87_attributes_in[10][5] = {
+static umode_t it87_in_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct it87_data *data = dev_get_drvdata(dev);
+ int i = index / 5; /* voltage index */
+ int a = index % 5; /* attribute index */
+
+ if (index >= 40) { /* in8, in9 only have input attributes */
+ i = index - 40 + 8;
+ a = 0;
+ }
+
+ if (!(data->has_in & (1 << i)))
+ return 0;
+
+ if (a == 4 && !data->has_beep)
+ return 0;
+
+ return attr->mode;
+}
+
+static struct attribute *it87_attributes_in[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in0_min.dev_attr.attr,
&sensor_dev_attr_in0_max.dev_attr.attr,
&sensor_dev_attr_in0_alarm.dev_attr.attr,
- NULL
-}, {
+ &sensor_dev_attr_in0_beep.dev_attr.attr, /* 4 */
+
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in1_min.dev_attr.attr,
&sensor_dev_attr_in1_max.dev_attr.attr,
&sensor_dev_attr_in1_alarm.dev_attr.attr,
- NULL
-}, {
+ &sensor_dev_attr_in1_beep.dev_attr.attr, /* 9 */
+
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_in2_min.dev_attr.attr,
&sensor_dev_attr_in2_max.dev_attr.attr,
&sensor_dev_attr_in2_alarm.dev_attr.attr,
- NULL
-}, {
+ &sensor_dev_attr_in2_beep.dev_attr.attr, /* 14 */
+
&sensor_dev_attr_in3_input.dev_attr.attr,
&sensor_dev_attr_in3_min.dev_attr.attr,
&sensor_dev_attr_in3_max.dev_attr.attr,
&sensor_dev_attr_in3_alarm.dev_attr.attr,
- NULL
-}, {
+ &sensor_dev_attr_in3_beep.dev_attr.attr, /* 19 */
+
&sensor_dev_attr_in4_input.dev_attr.attr,
&sensor_dev_attr_in4_min.dev_attr.attr,
&sensor_dev_attr_in4_max.dev_attr.attr,
&sensor_dev_attr_in4_alarm.dev_attr.attr,
- NULL
-}, {
+ &sensor_dev_attr_in4_beep.dev_attr.attr, /* 24 */
+
&sensor_dev_attr_in5_input.dev_attr.attr,
&sensor_dev_attr_in5_min.dev_attr.attr,
&sensor_dev_attr_in5_max.dev_attr.attr,
&sensor_dev_attr_in5_alarm.dev_attr.attr,
- NULL
-}, {
+ &sensor_dev_attr_in5_beep.dev_attr.attr, /* 29 */
+
&sensor_dev_attr_in6_input.dev_attr.attr,
&sensor_dev_attr_in6_min.dev_attr.attr,
&sensor_dev_attr_in6_max.dev_attr.attr,
&sensor_dev_attr_in6_alarm.dev_attr.attr,
- NULL
-}, {
+ &sensor_dev_attr_in6_beep.dev_attr.attr, /* 34 */
+
&sensor_dev_attr_in7_input.dev_attr.attr,
&sensor_dev_attr_in7_min.dev_attr.attr,
&sensor_dev_attr_in7_max.dev_attr.attr,
&sensor_dev_attr_in7_alarm.dev_attr.attr,
- NULL
-}, {
- &sensor_dev_attr_in8_input.dev_attr.attr,
- NULL
-}, {
- &sensor_dev_attr_in9_input.dev_attr.attr,
- NULL
-} };
+ &sensor_dev_attr_in7_beep.dev_attr.attr, /* 39 */
+
+ &sensor_dev_attr_in8_input.dev_attr.attr, /* 40 */
+
+ &sensor_dev_attr_in9_input.dev_attr.attr, /* 41 */
+};

-static const struct attribute_group it87_group_in[10] = {
- { .attrs = it87_attributes_in[0] },
- { .attrs = it87_attributes_in[1] },
- { .attrs = it87_attributes_in[2] },
- { .attrs = it87_attributes_in[3] },
- { .attrs = it87_attributes_in[4] },
- { .attrs = it87_attributes_in[5] },
- { .attrs = it87_attributes_in[6] },
- { .attrs = it87_attributes_in[7] },
- { .attrs = it87_attributes_in[8] },
- { .attrs = it87_attributes_in[9] },
+static const struct attribute_group it87_group_in = {
+ .attrs = it87_attributes_in,
+ .is_visible = it87_in_is_visible,
};

static struct attribute *it87_attributes_temp[3][6] = {
@@ -1868,19 +1881,6 @@ static const struct attribute_group it87_group = {
.attrs = it87_attributes,
};

-static struct attribute *it87_attributes_in_beep[] = {
- &sensor_dev_attr_in0_beep.dev_attr.attr,
- &sensor_dev_attr_in1_beep.dev_attr.attr,
- &sensor_dev_attr_in2_beep.dev_attr.attr,
- &sensor_dev_attr_in3_beep.dev_attr.attr,
- &sensor_dev_attr_in4_beep.dev_attr.attr,
- &sensor_dev_attr_in5_beep.dev_attr.attr,
- &sensor_dev_attr_in6_beep.dev_attr.attr,
- &sensor_dev_attr_in7_beep.dev_attr.attr,
- NULL,
- NULL,
-};
-
static struct attribute *it87_attributes_temp_beep[] = {
&sensor_dev_attr_temp1_beep.dev_attr.attr,
&sensor_dev_attr_temp2_beep.dev_attr.attr,
@@ -2435,14 +2435,8 @@ static void it87_remove_files(struct device *dev)
int i;

sysfs_remove_group(&dev->kobj, &it87_group);
- for (i = 0; i < 10; i++) {
- if (sio_data->skip_in & (1 << i))
- continue;
- sysfs_remove_group(&dev->kobj, &it87_group_in[i]);
- if (it87_attributes_in_beep[i])
- sysfs_remove_file(&dev->kobj,
- it87_attributes_in_beep[i]);
- }
+ sysfs_remove_group(&dev->kobj, &it87_group_in);
+
for (i = 0; i < 3; i++) {
if (!(data->has_temp & (1 << i)))
continue;
@@ -2736,6 +2730,10 @@ static int it87_probe(struct platform_device *pdev)
data->has_temp &= ~(1 << 2);
}

+ data->has_in = 0x3ff & ~sio_data->skip_in;
+
+ data->has_beep = !!sio_data->beep_pin;
+
/* Initialize the IT87 chip */
it87_init_device(pdev);

@@ -2744,19 +2742,9 @@ static int it87_probe(struct platform_device *pdev)
if (err)
return err;

- for (i = 0; i < 10; i++) {
- if (sio_data->skip_in & (1 << i))
- continue;
- err = sysfs_create_group(&dev->kobj, &it87_group_in[i]);
- if (err)
- goto error;
- if (sio_data->beep_pin && it87_attributes_in_beep[i]) {
- err = sysfs_create_file(&dev->kobj,
- it87_attributes_in_beep[i]);
- if (err)
- goto error;
- }
- }
+ err = sysfs_create_group(&dev->kobj, &it87_group_in);
+ if (err)
+ goto error;

for (i = 0; i < 3; i++) {
if (!(data->has_temp & (1 << i)))
--
2.1.4
Guenter Roeck
2016-03-05 14:29:53 UTC
Permalink
This patch series builds on top of v4.5-rc1. The series was tested on
a system with IT8728F. Out-of-kernel versions were tested by various
people using a github repository.
Most of the patches in this series were previously submitted as part of
earlier patch series. No substantial changes were made to those patches
since the previous submission.
Jean,

Any idea what to do with this series ?

Guenter
----------------------------------------------------------------
hwmon: (it87) Add feature flag for AVCC3 support
hwmon: (it87) Add support for all pwm channels on IT8620E
hwmon: (it87) Add support for second pwm frequency register
hwmon: (it87) Simplify error return in it87_device_add
hwmon: (it87) Don't use pdev as static driver variable
hwmon: (it87) Pass SIO base address as parameter to superio functions
hwmon: (it87) Add support for second Super-IO chip
hwmon: (it87) Rearrange code to avoid forward declarations
hwmon: (it87) Use is_visible for voltage sensors
hwmon: (it87) Use is_visible for temperature sensors
hwmon: (it87) Use is_visible for fan attributes
hwmon: (it87) Use is_visible for pwm attributes
hwmon: (it87) Use single group and is_visible for miscellaneous attributes
hwmon: (it87) Convert to use new hwmon API
hwmon: (it87) Support up to 6 temperature sensors on IT8620E
hwmon: (it87) Simplify reading voltage registers
hwmon: (it87) Add support for VIN7 to VIN10 on IT8620E
hwmon: (it87) Use BIT macro
hwmon: (it87) Use defines for array sizes and sensor counts
hwmon: (it87) Formatting cleanup
hwmon: (it87) Support disabling fan control for all pwm control and chips
hwmon: (it87) Enhance validation for fan4 and fan5
hwmon: (it87) Support automatic pwm control on newer chips
hwmon: (it87) Fix pwm_temp_map for system with 6 pwm channels
hwmon: (it87) Add support for IT8628E
Documentation/hwmon/it87 | 15 +-
drivers/hwmon/Kconfig | 3 +-
drivers/hwmon/it87.c | 2281 ++++++++++++++++++++++++++--------------------
3 files changed, 1300 insertions(+), 999 deletions(-)
Guenter Roeck
2016-03-05 14:46:15 UTC
Permalink
This patch series builds on top of v4.5-rc1. The series was tested on
a system with IT8728F. Out-of-kernel versions were tested by various
people using a github repository.
Most of the patches in this series were previously submitted as part of
earlier patch series. No substantial changes were made to those patches
since the previous submission.
Jean,

any idea what to do with this patch series ?

Guenter
----------------------------------------------------------------
hwmon: (it87) Add feature flag for AVCC3 support
hwmon: (it87) Add support for all pwm channels on IT8620E
hwmon: (it87) Add support for second pwm frequency register
hwmon: (it87) Simplify error return in it87_device_add
hwmon: (it87) Don't use pdev as static driver variable
hwmon: (it87) Pass SIO base address as parameter to superio functions
hwmon: (it87) Add support for second Super-IO chip
hwmon: (it87) Rearrange code to avoid forward declarations
hwmon: (it87) Use is_visible for voltage sensors
hwmon: (it87) Use is_visible for temperature sensors
hwmon: (it87) Use is_visible for fan attributes
hwmon: (it87) Use is_visible for pwm attributes
hwmon: (it87) Use single group and is_visible for miscellaneous attributes
hwmon: (it87) Convert to use new hwmon API
hwmon: (it87) Support up to 6 temperature sensors on IT8620E
hwmon: (it87) Simplify reading voltage registers
hwmon: (it87) Add support for VIN7 to VIN10 on IT8620E
hwmon: (it87) Use BIT macro
hwmon: (it87) Use defines for array sizes and sensor counts
hwmon: (it87) Formatting cleanup
hwmon: (it87) Support disabling fan control for all pwm control and chips
hwmon: (it87) Enhance validation for fan4 and fan5
hwmon: (it87) Support automatic pwm control on newer chips
hwmon: (it87) Fix pwm_temp_map for system with 6 pwm channels
hwmon: (it87) Add support for IT8628E
Documentation/hwmon/it87 | 15 +-
drivers/hwmon/Kconfig | 3 +-
drivers/hwmon/it87.c | 2281 ++++++++++++++++++++++++++--------------------
3 files changed, 1300 insertions(+), 999 deletions(-)
Martin Blumenstingl
2016-04-09 09:33:15 UTC
Permalink
From: Guenter Roeck <linux <at> roeck-us.net>
This patch series builds on top of v4.5-rc1. The series was tested on
a system with IT8728F. Out-of-kernel versions were tested by various
people using a github repository.
I've been running the whole series on top of v4.5 for the past two
weeks on a system with IT8628E. I did not find any problems so far.
Guenter Roeck
2016-04-09 15:07:27 UTC
Permalink
Hi Martin,
Post by Martin Blumenstingl
From: Guenter Roeck <linux <at> roeck-us.net>
This patch series builds on top of v4.5-rc1. The series was tested on
a system with IT8728F. Out-of-kernel versions were tested by various
people using a github repository.
I've been running the whole series on top of v4.5 for the past two
weeks on a system with IT8628E. I did not find any problems so far.
thanks a lot for the feedback. It would be great if you can send me
an official Tested-by: that I can add into the series (or a permission
to do so).

With the experience gained with the off-list driver, I think this series
is good to go for upstream, even without code review feedback. Otherwise
I fear we'll never get there. Jean, any objections ?

Thanks,
Guenter
Martin Blumenstingl
2016-04-10 10:46:26 UTC
Permalink
Post by Guenter Roeck
Post by Martin Blumenstingl
This patch series builds on top of v4.5-rc1. The series was tested on
a system with IT8728F. Out-of-kernel versions were tested by various
people using a github repository.
I've been running the whole series on top of v4.5 for the past two
weeks on a system with IT8628E. I did not find any problems so far.
thanks a lot for the feedback. It would be great if you can send me
an official Tested-by: that I can add into the series (or a permission
to do so).
sure, feel free to add this to the whole series:
Tested-by: Martin Blumenstingl <***@googlemail.com>

PS: Thank you Guenter for your hard work on this!

Loading...