123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802 |
- /*
- w83627ehf - Driver for the hardware monitoring functionality of
- the Winbond W83627EHF Super-I/O chip
- Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
- Shamelessly ripped from the w83627hf driver
- Copyright (C) 2003 Mark Studebaker
- Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help
- in testing and debugging this driver.
- This driver also supports the W83627EHG, which is the lead-free
- version of the W83627EHF.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- Supports the following chips:
- Chip #vin #fan #pwm #temp chip_id man_id
- w83627ehf - 5 - 3 0x88 0x5ca3
- This is a preliminary version of the driver, only supporting the
- fan and temperature inputs. The chip does much more than that.
- */
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/slab.h>
- #include <linux/i2c.h>
- #include <linux/i2c-isa.h>
- #include <linux/hwmon.h>
- #include <linux/hwmon-sysfs.h>
- #include <linux/err.h>
- #include <linux/mutex.h>
- #include <asm/io.h>
- #include "lm75.h"
- /* The actual ISA address is read from Super-I/O configuration space */
- static unsigned short address;
- /*
- * Super-I/O constants and functions
- */
- static int REG; /* The register to read/write */
- static int VAL; /* The value to read/write */
- #define W83627EHF_LD_HWM 0x0b
- #define SIO_REG_LDSEL 0x07 /* Logical device select */
- #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
- #define SIO_REG_ENABLE 0x30 /* Logical device enable */
- #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
- #define SIO_W83627EHF_ID 0x8840
- #define SIO_ID_MASK 0xFFC0
- static inline void
- superio_outb(int reg, int val)
- {
- outb(reg, REG);
- outb(val, VAL);
- }
- static inline int
- superio_inb(int reg)
- {
- outb(reg, REG);
- return inb(VAL);
- }
- static inline void
- superio_select(int ld)
- {
- outb(SIO_REG_LDSEL, REG);
- outb(ld, VAL);
- }
- static inline void
- superio_enter(void)
- {
- outb(0x87, REG);
- outb(0x87, REG);
- }
- static inline void
- superio_exit(void)
- {
- outb(0x02, REG);
- outb(0x02, VAL);
- }
- /*
- * ISA constants
- */
- #define REGION_ALIGNMENT ~7
- #define REGION_OFFSET 5
- #define REGION_LENGTH 2
- #define ADDR_REG_OFFSET 5
- #define DATA_REG_OFFSET 6
- #define W83627EHF_REG_BANK 0x4E
- #define W83627EHF_REG_CONFIG 0x40
- #define W83627EHF_REG_CHIP_ID 0x49
- #define W83627EHF_REG_MAN_ID 0x4F
- static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
- static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
- #define W83627EHF_REG_TEMP1 0x27
- #define W83627EHF_REG_TEMP1_HYST 0x3a
- #define W83627EHF_REG_TEMP1_OVER 0x39
- static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 };
- static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 };
- static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 };
- static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
- /* Fan clock dividers are spread over the following five registers */
- #define W83627EHF_REG_FANDIV1 0x47
- #define W83627EHF_REG_FANDIV2 0x4B
- #define W83627EHF_REG_VBAT 0x5D
- #define W83627EHF_REG_DIODE 0x59
- #define W83627EHF_REG_SMI_OVT 0x4C
- /*
- * Conversions
- */
- static inline unsigned int
- fan_from_reg(u8 reg, unsigned int div)
- {
- if (reg == 0 || reg == 255)
- return 0;
- return 1350000U / (reg * div);
- }
- static inline unsigned int
- div_from_reg(u8 reg)
- {
- return 1 << reg;
- }
- static inline int
- temp1_from_reg(s8 reg)
- {
- return reg * 1000;
- }
- static inline s8
- temp1_to_reg(int temp)
- {
- if (temp <= -128000)
- return -128;
- if (temp >= 127000)
- return 127;
- if (temp < 0)
- return (temp - 500) / 1000;
- return (temp + 500) / 1000;
- }
- /*
- * Data structures and manipulation thereof
- */
- struct w83627ehf_data {
- struct i2c_client client;
- struct class_device *class_dev;
- struct mutex lock;
- struct mutex update_lock;
- char valid; /* !=0 if following fields are valid */
- unsigned long last_updated; /* In jiffies */
- /* Register values */
- u8 fan[5];
- u8 fan_min[5];
- u8 fan_div[5];
- u8 has_fan; /* some fan inputs can be disabled */
- s8 temp1;
- s8 temp1_max;
- s8 temp1_max_hyst;
- s16 temp[2];
- s16 temp_max[2];
- s16 temp_max_hyst[2];
- };
- static inline int is_word_sized(u16 reg)
- {
- return (((reg & 0xff00) == 0x100
- || (reg & 0xff00) == 0x200)
- && ((reg & 0x00ff) == 0x50
- || (reg & 0x00ff) == 0x53
- || (reg & 0x00ff) == 0x55));
- }
- /* We assume that the default bank is 0, thus the following two functions do
- nothing for registers which live in bank 0. For others, they respectively
- set the bank register to the correct value (before the register is
- accessed), and back to 0 (afterwards). */
- static inline void w83627ehf_set_bank(struct i2c_client *client, u16 reg)
- {
- if (reg & 0xff00) {
- outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
- outb_p(reg >> 8, client->addr + DATA_REG_OFFSET);
- }
- }
- static inline void w83627ehf_reset_bank(struct i2c_client *client, u16 reg)
- {
- if (reg & 0xff00) {
- outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
- outb_p(0, client->addr + DATA_REG_OFFSET);
- }
- }
- static u16 w83627ehf_read_value(struct i2c_client *client, u16 reg)
- {
- struct w83627ehf_data *data = i2c_get_clientdata(client);
- int res, word_sized = is_word_sized(reg);
- mutex_lock(&data->lock);
- w83627ehf_set_bank(client, reg);
- outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
- res = inb_p(client->addr + DATA_REG_OFFSET);
- if (word_sized) {
- outb_p((reg & 0xff) + 1,
- client->addr + ADDR_REG_OFFSET);
- res = (res << 8) + inb_p(client->addr + DATA_REG_OFFSET);
- }
- w83627ehf_reset_bank(client, reg);
- mutex_unlock(&data->lock);
- return res;
- }
- static int w83627ehf_write_value(struct i2c_client *client, u16 reg, u16 value)
- {
- struct w83627ehf_data *data = i2c_get_clientdata(client);
- int word_sized = is_word_sized(reg);
- mutex_lock(&data->lock);
- w83627ehf_set_bank(client, reg);
- outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
- if (word_sized) {
- outb_p(value >> 8, client->addr + DATA_REG_OFFSET);
- outb_p((reg & 0xff) + 1,
- client->addr + ADDR_REG_OFFSET);
- }
- outb_p(value & 0xff, client->addr + DATA_REG_OFFSET);
- w83627ehf_reset_bank(client, reg);
- mutex_unlock(&data->lock);
- return 0;
- }
- /* This function assumes that the caller holds data->update_lock */
- static void w83627ehf_write_fan_div(struct i2c_client *client, int nr)
- {
- struct w83627ehf_data *data = i2c_get_clientdata(client);
- u8 reg;
- switch (nr) {
- case 0:
- reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf)
- | ((data->fan_div[0] & 0x03) << 4);
- w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
- reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf)
- | ((data->fan_div[0] & 0x04) << 3);
- w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
- break;
- case 1:
- reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f)
- | ((data->fan_div[1] & 0x03) << 6);
- w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
- reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf)
- | ((data->fan_div[1] & 0x04) << 4);
- w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
- break;
- case 2:
- reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV2) & 0x3f)
- | ((data->fan_div[2] & 0x03) << 6);
- w83627ehf_write_value(client, W83627EHF_REG_FANDIV2, reg);
- reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0x7f)
- | ((data->fan_div[2] & 0x04) << 5);
- w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
- break;
- case 3:
- reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0xfc)
- | (data->fan_div[3] & 0x03);
- w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
- reg = (w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT) & 0x7f)
- | ((data->fan_div[3] & 0x04) << 5);
- w83627ehf_write_value(client, W83627EHF_REG_SMI_OVT, reg);
- break;
- case 4:
- reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0x73)
- | ((data->fan_div[4] & 0x03) << 3)
- | ((data->fan_div[4] & 0x04) << 5);
- w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
- break;
- }
- }
- static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
- {
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627ehf_data *data = i2c_get_clientdata(client);
- int i;
- mutex_lock(&data->update_lock);
- if (time_after(jiffies, data->last_updated + HZ)
- || !data->valid) {
- /* Fan clock dividers */
- i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
- data->fan_div[0] = (i >> 4) & 0x03;
- data->fan_div[1] = (i >> 6) & 0x03;
- i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2);
- data->fan_div[2] = (i >> 6) & 0x03;
- i = w83627ehf_read_value(client, W83627EHF_REG_VBAT);
- data->fan_div[0] |= (i >> 3) & 0x04;
- data->fan_div[1] |= (i >> 4) & 0x04;
- data->fan_div[2] |= (i >> 5) & 0x04;
- if (data->has_fan & ((1 << 3) | (1 << 4))) {
- i = w83627ehf_read_value(client, W83627EHF_REG_DIODE);
- data->fan_div[3] = i & 0x03;
- data->fan_div[4] = ((i >> 2) & 0x03)
- | ((i >> 5) & 0x04);
- }
- if (data->has_fan & (1 << 3)) {
- i = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT);
- data->fan_div[3] |= (i >> 5) & 0x04;
- }
- /* Measured fan speeds and limits */
- for (i = 0; i < 5; i++) {
- if (!(data->has_fan & (1 << i)))
- continue;
- data->fan[i] = w83627ehf_read_value(client,
- W83627EHF_REG_FAN[i]);
- data->fan_min[i] = w83627ehf_read_value(client,
- W83627EHF_REG_FAN_MIN[i]);
- /* If we failed to measure the fan speed and clock
- divider can be increased, let's try that for next
- time */
- if (data->fan[i] == 0xff
- && data->fan_div[i] < 0x07) {
- dev_dbg(&client->dev, "Increasing fan %d "
- "clock divider from %u to %u\n",
- i, div_from_reg(data->fan_div[i]),
- div_from_reg(data->fan_div[i] + 1));
- data->fan_div[i]++;
- w83627ehf_write_fan_div(client, i);
- /* Preserve min limit if possible */
- if (data->fan_min[i] >= 2
- && data->fan_min[i] != 255)
- w83627ehf_write_value(client,
- W83627EHF_REG_FAN_MIN[i],
- (data->fan_min[i] /= 2));
- }
- }
- /* Measured temperatures and limits */
- data->temp1 = w83627ehf_read_value(client,
- W83627EHF_REG_TEMP1);
- data->temp1_max = w83627ehf_read_value(client,
- W83627EHF_REG_TEMP1_OVER);
- data->temp1_max_hyst = w83627ehf_read_value(client,
- W83627EHF_REG_TEMP1_HYST);
- for (i = 0; i < 2; i++) {
- data->temp[i] = w83627ehf_read_value(client,
- W83627EHF_REG_TEMP[i]);
- data->temp_max[i] = w83627ehf_read_value(client,
- W83627EHF_REG_TEMP_OVER[i]);
- data->temp_max_hyst[i] = w83627ehf_read_value(client,
- W83627EHF_REG_TEMP_HYST[i]);
- }
- data->last_updated = jiffies;
- data->valid = 1;
- }
- mutex_unlock(&data->update_lock);
- return data;
- }
- /*
- * Sysfs callback functions
- */
- #define show_fan_reg(reg) \
- static ssize_t \
- show_##reg(struct device *dev, struct device_attribute *attr, \
- char *buf) \
- { \
- struct w83627ehf_data *data = w83627ehf_update_device(dev); \
- struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
- int nr = sensor_attr->index; \
- return sprintf(buf, "%d\n", \
- fan_from_reg(data->reg[nr], \
- div_from_reg(data->fan_div[nr]))); \
- }
- show_fan_reg(fan);
- show_fan_reg(fan_min);
- static ssize_t
- show_fan_div(struct device *dev, struct device_attribute *attr,
- char *buf)
- {
- struct w83627ehf_data *data = w83627ehf_update_device(dev);
- struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
- int nr = sensor_attr->index;
- return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
- }
- static ssize_t
- store_fan_min(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627ehf_data *data = i2c_get_clientdata(client);
- struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
- int nr = sensor_attr->index;
- unsigned int val = simple_strtoul(buf, NULL, 10);
- unsigned int reg;
- u8 new_div;
- mutex_lock(&data->update_lock);
- if (!val) {
- /* No min limit, alarm disabled */
- data->fan_min[nr] = 255;
- new_div = data->fan_div[nr]; /* No change */
- dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
- } else if ((reg = 1350000U / val) >= 128 * 255) {
- /* Speed below this value cannot possibly be represented,
- even with the highest divider (128) */
- data->fan_min[nr] = 254;
- new_div = 7; /* 128 == (1 << 7) */
- dev_warn(dev, "fan%u low limit %u below minimum %u, set to "
- "minimum\n", nr + 1, val, fan_from_reg(254, 128));
- } else if (!reg) {
- /* Speed above this value cannot possibly be represented,
- even with the lowest divider (1) */
- data->fan_min[nr] = 1;
- new_div = 0; /* 1 == (1 << 0) */
- dev_warn(dev, "fan%u low limit %u above maximum %u, set to "
- "maximum\n", nr + 1, val, fan_from_reg(1, 1));
- } else {
- /* Automatically pick the best divider, i.e. the one such
- that the min limit will correspond to a register value
- in the 96..192 range */
- new_div = 0;
- while (reg > 192 && new_div < 7) {
- reg >>= 1;
- new_div++;
- }
- data->fan_min[nr] = reg;
- }
- /* Write both the fan clock divider (if it changed) and the new
- fan min (unconditionally) */
- if (new_div != data->fan_div[nr]) {
- if (new_div > data->fan_div[nr])
- data->fan[nr] >>= (data->fan_div[nr] - new_div);
- else
- data->fan[nr] <<= (new_div - data->fan_div[nr]);
- dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
- nr + 1, div_from_reg(data->fan_div[nr]),
- div_from_reg(new_div));
- data->fan_div[nr] = new_div;
- w83627ehf_write_fan_div(client, nr);
- }
- w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr],
- data->fan_min[nr]);
- mutex_unlock(&data->update_lock);
- return count;
- }
- static struct sensor_device_attribute sda_fan_input[] = {
- SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
- SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
- SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
- SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
- SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
- };
- static struct sensor_device_attribute sda_fan_min[] = {
- SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
- store_fan_min, 0),
- SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
- store_fan_min, 1),
- SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
- store_fan_min, 2),
- SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
- store_fan_min, 3),
- SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
- store_fan_min, 4),
- };
- static struct sensor_device_attribute sda_fan_div[] = {
- SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
- SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
- SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
- SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
- SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
- };
- static void device_create_file_fan(struct device *dev, int i)
- {
- device_create_file(dev, &sda_fan_input[i].dev_attr);
- device_create_file(dev, &sda_fan_div[i].dev_attr);
- device_create_file(dev, &sda_fan_min[i].dev_attr);
- }
- #define show_temp1_reg(reg) \
- static ssize_t \
- show_##reg(struct device *dev, struct device_attribute *attr, \
- char *buf) \
- { \
- struct w83627ehf_data *data = w83627ehf_update_device(dev); \
- return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \
- }
- show_temp1_reg(temp1);
- show_temp1_reg(temp1_max);
- show_temp1_reg(temp1_max_hyst);
- #define store_temp1_reg(REG, reg) \
- static ssize_t \
- store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
- { \
- struct i2c_client *client = to_i2c_client(dev); \
- struct w83627ehf_data *data = i2c_get_clientdata(client); \
- u32 val = simple_strtoul(buf, NULL, 10); \
- \
- mutex_lock(&data->update_lock); \
- data->temp1_##reg = temp1_to_reg(val); \
- w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \
- data->temp1_##reg); \
- mutex_unlock(&data->update_lock); \
- return count; \
- }
- store_temp1_reg(OVER, max);
- store_temp1_reg(HYST, max_hyst);
- #define show_temp_reg(reg) \
- static ssize_t \
- show_##reg(struct device *dev, struct device_attribute *attr, \
- char *buf) \
- { \
- struct w83627ehf_data *data = w83627ehf_update_device(dev); \
- struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
- int nr = sensor_attr->index; \
- return sprintf(buf, "%d\n", \
- LM75_TEMP_FROM_REG(data->reg[nr])); \
- }
- show_temp_reg(temp);
- show_temp_reg(temp_max);
- show_temp_reg(temp_max_hyst);
- #define store_temp_reg(REG, reg) \
- static ssize_t \
- store_##reg(struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
- { \
- struct i2c_client *client = to_i2c_client(dev); \
- struct w83627ehf_data *data = i2c_get_clientdata(client); \
- struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
- int nr = sensor_attr->index; \
- u32 val = simple_strtoul(buf, NULL, 10); \
- \
- mutex_lock(&data->update_lock); \
- data->reg[nr] = LM75_TEMP_TO_REG(val); \
- w83627ehf_write_value(client, W83627EHF_REG_TEMP_##REG[nr], \
- data->reg[nr]); \
- mutex_unlock(&data->update_lock); \
- return count; \
- }
- store_temp_reg(OVER, temp_max);
- store_temp_reg(HYST, temp_max_hyst);
- static struct sensor_device_attribute sda_temp[] = {
- SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
- SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
- SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1),
- SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max,
- store_temp1_max, 0),
- SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
- store_temp_max, 0),
- SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
- store_temp_max, 1),
- SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst,
- store_temp1_max_hyst, 0),
- SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
- store_temp_max_hyst, 0),
- SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
- store_temp_max_hyst, 1),
- };
- /*
- * Driver and client management
- */
- static struct i2c_driver w83627ehf_driver;
- static void w83627ehf_init_client(struct i2c_client *client)
- {
- int i;
- u8 tmp;
- /* Start monitoring is needed */
- tmp = w83627ehf_read_value(client, W83627EHF_REG_CONFIG);
- if (!(tmp & 0x01))
- w83627ehf_write_value(client, W83627EHF_REG_CONFIG,
- tmp | 0x01);
- /* Enable temp2 and temp3 if needed */
- for (i = 0; i < 2; i++) {
- tmp = w83627ehf_read_value(client,
- W83627EHF_REG_TEMP_CONFIG[i]);
- if (tmp & 0x01)
- w83627ehf_write_value(client,
- W83627EHF_REG_TEMP_CONFIG[i],
- tmp & 0xfe);
- }
- }
- static int w83627ehf_detect(struct i2c_adapter *adapter)
- {
- struct i2c_client *client;
- struct w83627ehf_data *data;
- struct device *dev;
- int i, err = 0;
- if (!request_region(address + REGION_OFFSET, REGION_LENGTH,
- w83627ehf_driver.driver.name)) {
- err = -EBUSY;
- goto exit;
- }
- if (!(data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit_release;
- }
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = address;
- mutex_init(&data->lock);
- client->adapter = adapter;
- client->driver = &w83627ehf_driver;
- client->flags = 0;
- dev = &client->dev;
- strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE);
- data->valid = 0;
- mutex_init(&data->update_lock);
- /* Tell the i2c layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exit_free;
- /* Initialize the chip */
- w83627ehf_init_client(client);
- /* A few vars need to be filled upon startup */
- for (i = 0; i < 5; i++)
- data->fan_min[i] = w83627ehf_read_value(client,
- W83627EHF_REG_FAN_MIN[i]);
- /* It looks like fan4 and fan5 pins can be alternatively used
- as fan on/off switches */
- data->has_fan = 0x07; /* fan1, fan2 and fan3 */
- i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
- if (i & (1 << 2))
- data->has_fan |= (1 << 3);
- if (i & (1 << 0))
- data->has_fan |= (1 << 4);
- /* Register sysfs hooks */
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
- goto exit_detach;
- }
- for (i = 0; i < 5; i++) {
- if (data->has_fan & (1 << i))
- device_create_file_fan(dev, i);
- }
- for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
- device_create_file(dev, &sda_temp[i].dev_attr);
- return 0;
- exit_detach:
- i2c_detach_client(client);
- exit_free:
- kfree(data);
- exit_release:
- release_region(address + REGION_OFFSET, REGION_LENGTH);
- exit:
- return err;
- }
- static int w83627ehf_detach_client(struct i2c_client *client)
- {
- struct w83627ehf_data *data = i2c_get_clientdata(client);
- int err;
- hwmon_device_unregister(data->class_dev);
- if ((err = i2c_detach_client(client)))
- return err;
- release_region(client->addr + REGION_OFFSET, REGION_LENGTH);
- kfree(data);
- return 0;
- }
- static struct i2c_driver w83627ehf_driver = {
- .driver = {
- .name = "w83627ehf",
- },
- .attach_adapter = w83627ehf_detect,
- .detach_client = w83627ehf_detach_client,
- };
- static int __init w83627ehf_find(int sioaddr, unsigned short *addr)
- {
- u16 val;
- REG = sioaddr;
- VAL = sioaddr + 1;
- superio_enter();
- val = (superio_inb(SIO_REG_DEVID) << 8)
- | superio_inb(SIO_REG_DEVID + 1);
- if ((val & SIO_ID_MASK) != SIO_W83627EHF_ID) {
- superio_exit();
- return -ENODEV;
- }
- superio_select(W83627EHF_LD_HWM);
- val = (superio_inb(SIO_REG_ADDR) << 8)
- | superio_inb(SIO_REG_ADDR + 1);
- *addr = val & REGION_ALIGNMENT;
- if (*addr == 0) {
- superio_exit();
- return -ENODEV;
- }
- /* Activate logical device if needed */
- val = superio_inb(SIO_REG_ENABLE);
- if (!(val & 0x01))
- superio_outb(SIO_REG_ENABLE, val | 0x01);
- superio_exit();
- return 0;
- }
- static int __init sensors_w83627ehf_init(void)
- {
- if (w83627ehf_find(0x2e, &address)
- && w83627ehf_find(0x4e, &address))
- return -ENODEV;
- return i2c_isa_add_driver(&w83627ehf_driver);
- }
- static void __exit sensors_w83627ehf_exit(void)
- {
- i2c_isa_del_driver(&w83627ehf_driver);
- }
- MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
- MODULE_DESCRIPTION("W83627EHF driver");
- MODULE_LICENSE("GPL");
- module_init(sensors_w83627ehf_init);
- module_exit(sensors_w83627ehf_exit);
|