#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/ioport.h>
#include <asm/io.h>
#include "lm75.h"
+/* The actual ISA address is read from Super-I/O configuration space */
+static unsigned short address;
+
+#define DRVNAME "w83627hf"
+enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
+
static u16 force_addr;
module_param(force_addr, ushort, 0);
MODULE_PARM_DESC(force_addr,
MODULE_PARM_DESC(force_i2c,
"Initialize the i2c address of the sensors");
-/* The actual ISA address is read from Super-I/O configuration space */
-static unsigned short address;
-
-/* Insmod parameters */
-enum chips { any_chip, w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
-
static int reset;
module_param(reset, bool, 0);
MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
return ((u8) i);
}
-/* For each registered chip, we need to keep some data in memory. That
- data is pointed to by w83627hf_list[NR]->data. The structure itself is
- dynamically allocated, at the same time when a new client is allocated. */
+/* For each registered chip, we need to keep some data in memory.
+ The structure is dynamically allocated. */
struct w83627hf_data {
struct i2c_client client;
struct class_device *class_dev;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
- struct i2c_client *lm75; /* for secondary I2C addresses */
- /* pointer to array of 2 subclients */
-
u8 in[9]; /* Register value */
u8 in_max[9]; /* Register value */
u8 in_min[9]; /* Register value */
static struct i2c_driver w83627hf_driver = {
.driver = {
- .name = "w83627hf",
+ .owner = THIS_MODULE,
+ .name = DRVNAME,
},
.attach_adapter = w83627hf_detect,
.detach_client = w83627hf_detach_client,
static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
show_regs_in_max0, store_regs_in_max0);
-#define device_create_file_in(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_in##offset##_input); \
-device_create_file(&client->dev, &dev_attr_in##offset##_min); \
-device_create_file(&client->dev, &dev_attr_in##offset##_max); \
-} while (0)
-
#define show_fan_reg(reg) \
static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
{ \
sysfs_fan_offset(3);
sysfs_fan_min_offset(3);
-#define device_create_file_fan(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
-device_create_file(&client->dev, &dev_attr_fan##offset##_min); \
-} while (0)
-
#define show_temp_reg(reg) \
static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
{ \
sysfs_temp_offsets(2);
sysfs_temp_offsets(3);
-#define device_create_file_temp(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_temp##offset##_input); \
-device_create_file(&client->dev, &dev_attr_temp##offset##_max); \
-device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \
-} while (0)
-
static ssize_t
show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
}
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
-#define device_create_file_vid(client) \
-device_create_file(&client->dev, &dev_attr_cpu0_vid)
static ssize_t
show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
return count;
}
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
-#define device_create_file_vrm(client) \
-device_create_file(&client->dev, &dev_attr_vrm)
static ssize_t
show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", (long) data->alarms);
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
-#define device_create_file_alarms(client) \
-device_create_file(&client->dev, &dev_attr_alarms)
#define show_beep_reg(REG, reg) \
static ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
sysfs_beep(ENABLE, enable);
sysfs_beep(MASK, mask);
-#define device_create_file_beep(client) \
-do { \
-device_create_file(&client->dev, &dev_attr_beep_enable); \
-device_create_file(&client->dev, &dev_attr_beep_mask); \
-} while (0)
-
static ssize_t
show_fan_div_reg(struct device *dev, char *buf, int nr)
{
/* Note: we save and restore the fan minimum here, because its value is
determined in part by the fan divisor. This follows the principle of
- least suprise; the user doesn't expect the fan minimum to change just
+ least surprise; the user doesn't expect the fan minimum to change just
because the divisor changed. */
static ssize_t
store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
sysfs_fan_div(2);
sysfs_fan_div(3);
-#define device_create_file_fan_div(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
-} while (0)
-
static ssize_t
show_pwm_reg(struct device *dev, char *buf, int nr)
{
sysfs_pwm(2);
sysfs_pwm(3);
-#define device_create_file_pwm(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_pwm##offset); \
-} while (0)
-
static ssize_t
show_sensor_reg(struct device *dev, char *buf, int nr)
{
sysfs_sensor(2);
sysfs_sensor(3);
-#define device_create_file_sensor(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_temp##offset##_type); \
-} while (0)
-
-
static int __init w83627hf_find(int sioaddr, unsigned short *addr)
{
+ int err = -ENODEV;
u16 val;
REG = sioaddr;
val != W697_DEVID &&
val != W637_DEVID &&
val != W687THF_DEVID) {
- superio_exit();
- return -ENODEV;
+ goto exit;
}
superio_select(W83627HF_LD_HWM);
+ force_addr &= WINB_ALIGNMENT;
+ if (force_addr) {
+ printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
+ force_addr);
+ superio_outb(WINB_BASE_REG, force_addr >> 8);
+ superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
+ }
val = (superio_inb(WINB_BASE_REG) << 8) |
superio_inb(WINB_BASE_REG + 1);
*addr = val & WINB_ALIGNMENT;
- if (*addr == 0 && force_addr == 0) {
- superio_exit();
- return -ENODEV;
+ if (*addr == 0) {
+ printk(KERN_WARNING DRVNAME ": Base address not set, "
+ "skipping\n");
+ goto exit;
}
+ val = superio_inb(WINB_ACT_REG);
+ if (!(val & 0x01)) {
+ printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
+ superio_outb(WINB_ACT_REG, val | 0x01);
+ }
+
+ err = 0;
+
+ exit:
superio_exit();
- return 0;
+ return err;
}
+static struct attribute *w83627hf_attributes[] = {
+ &dev_attr_in0_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in3_max.attr,
+ &dev_attr_in4_input.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in4_max.attr,
+ &dev_attr_in7_input.attr,
+ &dev_attr_in7_min.attr,
+ &dev_attr_in7_max.attr,
+ &dev_attr_in8_input.attr,
+ &dev_attr_in8_min.attr,
+ &dev_attr_in8_max.attr,
+
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan2_div.attr,
+
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+ &dev_attr_temp1_type.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_temp2_max_hyst.attr,
+ &dev_attr_temp2_type.attr,
+
+ &dev_attr_alarms.attr,
+ &dev_attr_beep_enable.attr,
+ &dev_attr_beep_mask.attr,
+
+ &dev_attr_pwm1.attr,
+ &dev_attr_pwm2.attr,
+
+ NULL
+};
+
+static const struct attribute_group w83627hf_group = {
+ .attrs = w83627hf_attributes,
+};
+
+static struct attribute *w83627hf_attributes_opt[] = {
+ &dev_attr_in1_input.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in5_input.attr,
+ &dev_attr_in5_min.attr,
+ &dev_attr_in5_max.attr,
+ &dev_attr_in6_input.attr,
+ &dev_attr_in6_min.attr,
+ &dev_attr_in6_max.attr,
+
+ &dev_attr_fan3_input.attr,
+ &dev_attr_fan3_min.attr,
+ &dev_attr_fan3_div.attr,
+
+ &dev_attr_temp3_input.attr,
+ &dev_attr_temp3_max.attr,
+ &dev_attr_temp3_max_hyst.attr,
+ &dev_attr_temp3_type.attr,
+
+ &dev_attr_pwm3.attr,
+
+ NULL
+};
+
+static const struct attribute_group w83627hf_group_opt = {
+ .attrs = w83627hf_attributes_opt,
+};
+
static int w83627hf_detect(struct i2c_adapter *adapter)
{
int val, kind;
int err = 0;
const char *client_name = "";
- if(force_addr)
- address = force_addr & WINB_ALIGNMENT;
-
if (!request_region(address + WINB_REGION_OFFSET, WINB_REGION_SIZE,
w83627hf_driver.driver.name)) {
err = -EBUSY;
goto ERROR0;
}
- if(force_addr) {
- printk("w83627hf.o: forcing ISA address 0x%04X\n", address);
- superio_enter();
- superio_select(W83627HF_LD_HWM);
- superio_outb(WINB_BASE_REG, address >> 8);
- superio_outb(WINB_BASE_REG+1, address & 0xff);
- superio_exit();
- }
-
superio_enter();
val= superio_inb(DEVID);
if(val == W627_DEVID)
"Unsupported chip (dev_id=0x%02X).\n", val);
goto ERROR1;
}
-
- superio_select(W83627HF_LD_HWM);
- if((val = 0x01 & superio_inb(WINB_ACT_REG)) == 0)
- superio_outb(WINB_ACT_REG, 1);
superio_exit();
/* OK. For now, we presume we have a valid client. We now create the
if ((err = i2c_attach_client(new_client)))
goto ERROR2;
- data->lm75 = NULL;
-
/* Initialize the chip */
w83627hf_init_client(new_client);
data->fan_min[1] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(2));
data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3));
- /* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ /* Register common device attributes */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &w83627hf_group)))
goto ERROR3;
- }
- device_create_file_in(new_client, 0);
- if (kind != w83697hf)
- device_create_file_in(new_client, 1);
- device_create_file_in(new_client, 2);
- device_create_file_in(new_client, 3);
- device_create_file_in(new_client, 4);
- if (kind == w83627hf || kind == w83697hf) {
- device_create_file_in(new_client, 5);
- device_create_file_in(new_client, 6);
- }
- device_create_file_in(new_client, 7);
- device_create_file_in(new_client, 8);
-
- device_create_file_fan(new_client, 1);
- device_create_file_fan(new_client, 2);
- if (kind != w83697hf)
- device_create_file_fan(new_client, 3);
+ /* Register chip-specific device attributes */
+ if (kind == w83627hf || kind == w83697hf)
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in5_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in5_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in5_max))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in6_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in6_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in6_max)))
+ goto ERROR4;
- device_create_file_temp(new_client, 1);
- device_create_file_temp(new_client, 2);
if (kind != w83697hf)
- device_create_file_temp(new_client, 3);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in1_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in1_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in1_max))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan3_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan3_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan3_div))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp3_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp3_max))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp3_max_hyst))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp3_type)))
+ goto ERROR4;
if (kind != w83697hf && data->vid != 0xff) {
- device_create_file_vid(new_client);
- device_create_file_vrm(new_client);
+ /* Convert VID to voltage based on VRM */
+ data->vrm = vid_which_vrm();
+
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_cpu0_vid))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_vrm)))
+ goto ERROR4;
}
- device_create_file_fan_div(new_client, 1);
- device_create_file_fan_div(new_client, 2);
- if (kind != w83697hf)
- device_create_file_fan_div(new_client, 3);
-
- device_create_file_alarms(new_client);
-
- device_create_file_beep(new_client);
-
- device_create_file_pwm(new_client, 1);
- device_create_file_pwm(new_client, 2);
if (kind == w83627thf || kind == w83637hf || kind == w83687thf)
- device_create_file_pwm(new_client, 3);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_pwm3)))
+ goto ERROR4;
- device_create_file_sensor(new_client, 1);
- device_create_file_sensor(new_client, 2);
- if (kind != w83697hf)
- device_create_file_sensor(new_client, 3);
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR4;
+ }
return 0;
+ ERROR4:
+ sysfs_remove_group(&new_client->dev.kobj, &w83627hf_group);
+ sysfs_remove_group(&new_client->dev.kobj, &w83627hf_group_opt);
ERROR3:
i2c_detach_client(new_client);
ERROR2:
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &w83627hf_group);
+ sysfs_remove_group(&client->dev.kobj, &w83627hf_group_opt);
+
if ((err = i2c_detach_client(client)))
return err;
{
struct w83627hf_data *data = i2c_get_clientdata(client);
int i;
- int type = data->type;
+ enum chips type = data->type;
u8 tmp;
if (reset) {
w83627hf_write_value(client, W83781D_REG_I2C_ADDR, force_i2c);
/* Read VID only once */
- if (w83627hf == data->type || w83637hf == data->type) {
+ if (type == w83627hf || type == w83637hf) {
int lo = w83627hf_read_value(client, W83781D_REG_VID_FANDIV);
int hi = w83627hf_read_value(client, W83781D_REG_CHIPID);
data->vid = (lo & 0x0f) | ((hi & 0x01) << 4);
- } else if (w83627thf == data->type) {
+ } else if (type == w83627thf) {
data->vid = w83627thf_read_gpio5(client);
- } else if (w83687thf == data->type) {
+ } else if (type == w83687thf) {
data->vid = w83687thf_read_vid(client);
}
/* Read VRM & OVT Config only once */
- if (w83627thf == data->type || w83637hf == data->type
- || w83687thf == data->type) {
+ if (type == w83627thf || type == w83637hf || type == w83687thf) {
data->vrm_ovt =
w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG);
}
- /* Convert VID to voltage based on VRM */
- data->vrm = vid_which_vrm();
-
tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
for (i = 1; i <= 3; i++) {
if (!(tmp & BIT_SCFG1[i - 1])) {