Newer
Older
* one.
*/
reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
if (data->temp_src[2] == 2 && (reg & 0x01))
data->have_temp &= ~(1 << 2);
if ((data->temp_src[2] == 2 && (data->have_temp & (1 << 2)))
|| (data->temp_src[3] == 2 && (data->have_temp & (1 << 3))))
data->in6_skip = 1;
data->temp_label = w83667hg_b_temp_label;
} else {
/* Temperature sources are fixed */
for (i = 0; i < 3; i++) {
data->reg_temp[i] = W83627EHF_REG_TEMP[i];
data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i];
data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i];
data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i];
}
if (sio_data->kind == nct6775) {
data->has_fan_div = true;
data->fan_from_reg = fan_from_reg16;
data->fan_from_reg_min = fan_from_reg8;
data->REG_PWM = NCT6775_REG_PWM;
data->REG_TARGET = NCT6775_REG_TARGET;
data->REG_FAN = NCT6775_REG_FAN;
data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
data->REG_FAN_MAX_OUTPUT = NCT6775_REG_FAN_MAX_OUTPUT;
data->REG_FAN_STEP_OUTPUT = NCT6775_REG_FAN_STEP_OUTPUT;
} else if (sio_data->kind == nct6776) {
data->has_fan_div = false;
data->fan_from_reg = fan_from_reg13;
data->fan_from_reg_min = fan_from_reg13;
data->REG_PWM = NCT6775_REG_PWM;
data->REG_TARGET = NCT6775_REG_TARGET;
data->REG_FAN = NCT6775_REG_FAN;
data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
} else if (sio_data->kind == w83667hg_b) {
data->has_fan_div = true;
data->fan_from_reg = fan_from_reg8;
data->fan_from_reg_min = fan_from_reg8;
data->REG_PWM = W83627EHF_REG_PWM;
data->REG_TARGET = W83627EHF_REG_TARGET;
data->REG_FAN = W83627EHF_REG_FAN;
data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
data->REG_FAN_MAX_OUTPUT =
W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B;
data->REG_FAN_STEP_OUTPUT =
W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B;
} else {
data->has_fan_div = true;
data->fan_from_reg = fan_from_reg8;
data->fan_from_reg_min = fan_from_reg8;
data->REG_PWM = W83627EHF_REG_PWM;
data->REG_TARGET = W83627EHF_REG_TARGET;
data->REG_FAN = W83627EHF_REG_FAN;
data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
data->REG_FAN_MAX_OUTPUT =
W83627EHF_REG_FAN_MAX_OUTPUT_COMMON;
data->REG_FAN_STEP_OUTPUT =
W83627EHF_REG_FAN_STEP_OUTPUT_COMMON;
}
/* Initialize the chip */
w83627ehf_init_device(data, sio_data->kind);
data->vrm = vid_which_vrm();
superio_enter(sio_data->sioreg);
/* Read VID value */
if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b ||
sio_data->kind == nct6775 || sio_data->kind == nct6776) {
/* W83667HG has different pins for VID input and output, so
we can get the VID input values directly at logical device D
0xe3. */
superio_select(sio_data->sioreg, W83667HG_LD_VID);
data->vid = superio_inb(sio_data->sioreg, 0xe3);
err = device_create_file(dev, &dev_attr_cpu0_vid);
if (err)
goto exit_release;
} else {
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
/* Set VID input sensibility if needed. In theory the
BIOS should have set it, but in practice it's not
always the case. We only do it for the W83627EHF/EHG
because the W83627DHG is more complex in this
respect. */
if (sio_data->kind == w83627ehf) {
en_vrm10 = superio_inb(sio_data->sioreg,
SIO_REG_EN_VRM10);
if ((en_vrm10 & 0x08) && data->vrm == 90) {
dev_warn(dev, "Setting VID input "
"voltage to TTL\n");
superio_outb(sio_data->sioreg,
SIO_REG_EN_VRM10,
en_vrm10 & ~0x08);
} else if (!(en_vrm10 & 0x08)
&& data->vrm == 100) {
dev_warn(dev, "Setting VID input "
"voltage to VRM10\n");
superio_outb(sio_data->sioreg,
SIO_REG_EN_VRM10,
en_vrm10 | 0x08);
}
}
data->vid = superio_inb(sio_data->sioreg,
SIO_REG_VID_DATA);
if (sio_data->kind == w83627ehf) /* 6 VID pins only */
data->vid &= 0x3f;
err = device_create_file(dev, &dev_attr_cpu0_vid);
if (err)
goto exit_release;
} else {
dev_info(dev, "VID pins in output mode, CPU VID not "
"available\n");
}
/* fan4 and fan5 share some pins with the GPIO and serial flash */
if (sio_data->kind == nct6775) {
/* On NCT6775, fan4 shares pins with the fdc interface */
fan3pin = 1;
fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80);
fan4min = 0;
fan5pin = 0;
} else if (sio_data->kind == nct6776) {
fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40);
fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x01);
fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x02);
fan4min = fan4pin;
} else if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
fan3pin = 1;
fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
fan4min = fan4pin;
fan3pin = 1;
fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
fan4min = fan4pin;
if (fan_debounce &&
(sio_data->kind == nct6775 || sio_data->kind == nct6776)) {
u8 tmp;
superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
tmp = superio_inb(sio_data->sioreg, NCT6775_REG_FAN_DEBOUNCE);
if (sio_data->kind == nct6776)
superio_outb(sio_data->sioreg, NCT6775_REG_FAN_DEBOUNCE,
0x3e | tmp);
else
superio_outb(sio_data->sioreg, NCT6775_REG_FAN_DEBOUNCE,
0x1e | tmp);
pr_info("Enabled fan debounce for chip %s\n", data->name);
}
superio_exit(sio_data->sioreg);
/* It looks like fan4 and fan5 pins can be alternatively used
as fan on/off switches, but fan5 control is write only :/
We assume that if the serial interface is disabled, designers
connected fan5 as input unless they are emitting log 1, which
is not the default. */
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */
data->has_fan |= (fan3pin << 2);
data->has_fan_min |= (fan3pin << 2);
/*
* NCT6775F and NCT6776F don't have the W83627EHF_REG_FANDIV1 register
*/
if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
data->has_fan |= (fan4pin << 3) | (fan5pin << 4);
data->has_fan_min |= (fan4min << 3) | (fan5pin << 4);
} else {
i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
if ((i & (1 << 2)) && fan4pin) {
data->has_fan |= (1 << 3);
data->has_fan_min |= (1 << 3);
}
if (!(i & (1 << 1)) && fan5pin) {
data->has_fan |= (1 << 4);
data->has_fan_min |= (1 << 4);
}
}
/* Read fan clock dividers immediately */
w83627ehf_update_fan_div_common(dev, data);
/* Read pwm data to save original values */
w83627ehf_update_pwm_common(dev, data);
for (i = 0; i < data->pwm_num; i++)
data->pwm_enable_orig[i] = data->pwm_enable[i];
Guenter Roeck
committed
/* Read pwm data to save original values */
w83627ehf_update_pwm_common(dev, data);
for (i = 0; i < data->pwm_num; i++)
data->pwm_enable_orig[i] = data->pwm_enable[i];
/* Register sysfs hooks */
for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) {
err = device_create_file(dev, &sda_sf3_arrays[i].dev_attr);
if (err)
for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
struct sensor_device_attribute *attr =
&sda_sf3_max_step_arrays[i];
if (data->REG_FAN_STEP_OUTPUT &&
data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) {
err = device_create_file(dev, &attr->dev_attr);
if (err)
goto exit_remove;
}
}
/* if fan4 is enabled create the sf3 files for it */
if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4)
for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
err = device_create_file(dev,
&sda_sf3_arrays_fan4[i].dev_attr);
if (err)
for (i = 0; i < data->in_num; i++) {
if ((i == 6) && data->in6_skip)
continue;
if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
|| (err = device_create_file(dev,
&sda_in_alarm[i].dev_attr))
|| (err = device_create_file(dev,
&sda_in_min[i].dev_attr))
|| (err = device_create_file(dev,
&sda_in_max[i].dev_attr)))
goto exit_remove;
if (data->has_fan & (1 << i)) {
if ((err = device_create_file(dev,
&sda_fan_input[i].dev_attr))
|| (err = device_create_file(dev,
&sda_fan_alarm[i].dev_attr)))
if (sio_data->kind != nct6776) {
err = device_create_file(dev,
&sda_fan_div[i].dev_attr);
if (err)
goto exit_remove;
}
if (data->has_fan_min & (1 << i)) {
err = device_create_file(dev,
&sda_fan_min[i].dev_attr);
if (err)
goto exit_remove;
}
((err = device_create_file(dev,
&sda_pwm[i].dev_attr))
|| (err = device_create_file(dev,
&sda_pwm_mode[i].dev_attr))
|| (err = device_create_file(dev,
&sda_pwm_enable[i].dev_attr))
|| (err = device_create_file(dev,
&sda_target_temp[i].dev_attr))
|| (err = device_create_file(dev,
&sda_tolerance[i].dev_attr))))
goto exit_remove;
for (i = 0; i < NUM_REG_TEMP; i++) {
if (!(data->have_temp & (1 << i)))
err = device_create_file(dev, &sda_temp_input[i].dev_attr);
if (err)
goto exit_remove;
if (data->temp_label) {
err = device_create_file(dev,
&sda_temp_label[i].dev_attr);
if (err)
goto exit_remove;
}
if (data->reg_temp_over[i]) {
err = device_create_file(dev,
&sda_temp_max[i].dev_attr);
if (err)
goto exit_remove;
}
if (data->reg_temp_hyst[i]) {
err = device_create_file(dev,
&sda_temp_max_hyst[i].dev_attr);
if (err)
goto exit_remove;
}
continue;
if ((err = device_create_file(dev,
&sda_temp_alarm[i].dev_attr))
|| (err = device_create_file(dev,
&sda_temp_type[i].dev_attr)))
err = device_create_file(dev, &sda_caseopen[0].dev_attr);
if (err)
goto exit_remove;
if (sio_data->kind == nct6776) {
err = device_create_file(dev, &sda_caseopen[1].dev_attr);
if (err)
goto exit_remove;
}
err = device_create_file(dev, &dev_attr_name);
if (err)
goto exit_remove;
data->hwmon_dev = hwmon_device_register(dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
return 0;
exit_remove:
w83627ehf_device_remove_files(dev);
platform_set_drvdata(pdev, NULL);
release_region(res->start, IOREGION_LENGTH);
exit:
return err;
}
static int __devexit w83627ehf_remove(struct platform_device *pdev)
struct w83627ehf_data *data = platform_get_drvdata(pdev);
hwmon_device_unregister(data->hwmon_dev);
w83627ehf_device_remove_files(&pdev->dev);
release_region(data->addr, IOREGION_LENGTH);
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_driver w83627ehf_driver = {
.probe = w83627ehf_probe,
.remove = __devexit_p(w83627ehf_remove),
/* w83627ehf_find() looks for a '627 in the Super-I/O config space */
static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
struct w83627ehf_sio_data *sio_data)
static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P";
static const char __initdata sio_name_W83667HG[] = "W83667HG";
static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B";
static const char __initdata sio_name_NCT6775[] = "NCT6775F";
static const char __initdata sio_name_NCT6776[] = "NCT6776F";
if (force_id)
val = force_id;
else
val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
| superio_inb(sioaddr, SIO_REG_DEVID + 1);
switch (val & SIO_ID_MASK) {
case SIO_W83627EHF_ID:
sio_data->kind = w83627ehf;
sio_name = sio_name_W83627EHF;
break;
case SIO_W83627EHG_ID:
sio_data->kind = w83627ehf;
sio_name = sio_name_W83627EHG;
break;
case SIO_W83627DHG_ID:
sio_data->kind = w83627dhg;
sio_name = sio_name_W83627DHG;
case SIO_W83627DHG_P_ID:
sio_data->kind = w83627dhg_p;
sio_name = sio_name_W83627DHG_P;
break;
case SIO_W83667HG_ID:
sio_data->kind = w83667hg;
sio_name = sio_name_W83667HG;
break;
case SIO_W83667HG_B_ID:
sio_data->kind = w83667hg_b;
sio_name = sio_name_W83667HG_B;
break;
case SIO_NCT6775_ID:
sio_data->kind = nct6775;
sio_name = sio_name_NCT6775;
break;
case SIO_NCT6776_ID:
sio_data->kind = nct6776;
sio_name = sio_name_NCT6776;
break;
pr_debug("unsupported chip ID: 0x%04x\n", val);
return -ENODEV;
}
/* We have a known chip, find the HWM I/O address */
superio_select(sioaddr, W83627EHF_LD_HWM);
val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
| superio_inb(sioaddr, SIO_REG_ADDR + 1);
*addr = val & IOREGION_ALIGNMENT;
if (*addr == 0) {
pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
return -ENODEV;
}
/* Activate logical device if needed */
val = superio_inb(sioaddr, SIO_REG_ENABLE);
if (!(val & 0x01)) {
pr_warn("Forcibly enabling Super-I/O. "
"Sensor is probably unusable.\n");
superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
superio_exit(sioaddr);
pr_info("Found %s chip at %#x\n", sio_name, *addr);
sio_data->sioreg = sioaddr;
return 0;
}
/* when Super-I/O functions move to a separate file, the Super-I/O
* bus will manage the lifetime of the device and this module will only keep
* track of the w83627ehf driver. But since we platform_device_alloc(), we
* must keep track of the device */
static struct platform_device *pdev;
static int __init sensors_w83627ehf_init(void)
{
int err;
unsigned short address;
struct resource res;
struct w83627ehf_sio_data sio_data;
/* initialize sio_data->kind and sio_data->sioreg.
*
* when Super-I/O functions move to a separate file, the Super-I/O
* driver will probe 0x2e and 0x4e and auto-detect the presence of a
* w83627ehf hardware monitor, and call probe() */
if (w83627ehf_find(0x2e, &address, &sio_data) &&
w83627ehf_find(0x4e, &address, &sio_data))
return -ENODEV;
err = platform_driver_register(&w83627ehf_driver);
if (err)
goto exit;
pdev = platform_device_alloc(DRVNAME, address);
if (!pdev) {
pr_err("Device allocation failed\n");
goto exit_unregister;
}
err = platform_device_add_data(pdev, &sio_data,
sizeof(struct w83627ehf_sio_data));
if (err) {
pr_err("Platform data allocation failed\n");
goto exit_device_put;
}
memset(&res, 0, sizeof(res));
res.name = DRVNAME;
res.start = address + IOREGION_OFFSET;
res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
res.flags = IORESOURCE_IO;
err = acpi_check_resource_conflict(&res);
if (err)
err = platform_device_add_resources(pdev, &res, 1);
if (err) {
pr_err("Device resource addition failed (%d)\n", err);
goto exit_device_put;
}
/* platform_device_add calls probe() */
err = platform_device_add(pdev);
if (err) {
pr_err("Device addition failed (%d)\n", err);
goto exit_device_put;
}
return 0;
exit_device_put:
platform_device_put(pdev);
exit_unregister:
platform_driver_unregister(&w83627ehf_driver);
exit:
return err;
}
static void __exit sensors_w83627ehf_exit(void)
{
platform_device_unregister(pdev);
platform_driver_unregister(&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);