outb(ld, ioreg + 1);
}
-static inline void
+static inline int
superio_enter(int ioreg)
{
+ /*
+ * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
+ */
+ if (!request_muxed_region(ioreg, 2, DRVNAME))
+ return -EBUSY;
+
outb(0x87, ioreg);
outb(0x87, ioreg);
+
+ return 0;
}
static inline void
outb(0xaa, ioreg);
outb(0x02, ioreg);
outb(0x02, ioreg + 1);
+ release_region(ioreg, 2);
}
/*
0x105, 0x205, 0x305, 0x805, 0x905 };
static const u16 NCT6775_REG_FAN_START_OUTPUT[]
= { 0x106, 0x206, 0x306, 0x806, 0x906 };
+static const u16 NCT6775_REG_FAN_STEP_ENABLE[] = {
+ 0x120, 0x220, 0x320, 0x820, 0x920 };
static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
const u16 *REG_CRITICAL_TEMP_TOLERANCE;
const u16 *REG_TEMP_SOURCE; /* temp register sources */
- const u16 *REG_TEMP_SEL[2]; /* pwm temp, 0=base, 1=weight */
+ const u16 *REG_TEMP_SEL[3]; /* pwm temp:
+ * 0=base, 1=weight, 2=step enable
+ */
const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=hyst, 2=step */
u8 pwm_temp_sel[2][5];
- bool pwm_sel_enable[2][5];/* 0->stop_val, 1->weight;
+ bool pwm_sel_enable[3][5];/* 0->stop_val, 1->weight, 2->step;
* false->off, true->on
*/
u8 weight_temp[3][5]; /* 0->temp_step, 1->temp_step_tol,
reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
| ((data->fan_div[1] << 4) & 0x70);
nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
+ break;
case 2:
reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
| (data->fan_div[2] & 0x7);
data->pwm_sel_enable[1][i] =
nct6775_read_value(data, data->REG_TEMP_SEL[1][i])
& 0x80;
+ data->pwm_sel_enable[2][i] =
+ nct6775_read_value(data, data->REG_TEMP_SEL[2][i])
+ & 0x01;
/* Weight data */
for (j = 0; j < 2; j++) {
unsigned long val;
int err;
u8 reg;
+ static const u8 bit[] = { 0x80, 0x80, 0x01 };
+
err = kstrtoul(buf, 10, &val);
if (err < 0)
mutex_lock(&data->update_lock);
data->pwm_sel_enable[index][nr] = val;
reg = nct6775_read_value(data, data->REG_TEMP_SEL[index][nr]);
- reg &= 0x7f;
+ reg &= ~bit[index];
if (val)
- reg |= 0x80;
+ reg |= bit[index];
nct6775_write_value(data, data->REG_TEMP_SEL[index][nr], reg);
mutex_unlock(&data->update_lock);
return count;
static SENSOR_DEVICE_ATTR_2(pwm5_weight_enable, S_IWUSR | S_IRUGO,
show_pwm_sel_enable, store_pwm_sel_enable, 4, 1);
+static SENSOR_DEVICE_ATTR_2(pwm1_step_enable, S_IWUSR | S_IRUGO,
+ show_pwm_sel_enable, store_pwm_sel_enable, 0, 2);
+static SENSOR_DEVICE_ATTR_2(pwm2_step_enable, S_IWUSR | S_IRUGO,
+ show_pwm_sel_enable, store_pwm_sel_enable, 1, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_step_enable, S_IWUSR | S_IRUGO,
+ show_pwm_sel_enable, store_pwm_sel_enable, 2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm4_step_enable, S_IWUSR | S_IRUGO,
+ show_pwm_sel_enable, store_pwm_sel_enable, 3, 2);
+static SENSOR_DEVICE_ATTR_2(pwm5_step_enable, S_IWUSR | S_IRUGO,
+ show_pwm_sel_enable, store_pwm_sel_enable, 4, 2);
+
static SENSOR_DEVICE_ATTR_2(pwm1_weight_temp_sel, S_IWUSR | S_IRUGO,
show_pwm_temp_sel, store_pwm_temp_sel, 0, 1);
static SENSOR_DEVICE_ATTR_2(pwm2_weight_temp_sel, S_IWUSR | S_IRUGO,
4, 4),
};
-static struct attribute *nct6775_attributes_pwm[5][19] = {
+static struct attribute *nct6775_attributes_pwm[5][20] = {
{
&sensor_dev_attr_pwm1.dev_attr.attr,
&sensor_dev_attr_pwm1_mode.dev_attr.attr,
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
&sensor_dev_attr_pwm1_stop_output_enable.dev_attr.attr,
&sensor_dev_attr_pwm1_weight_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm1_step_enable.dev_attr.attr,
&sensor_dev_attr_pwm1_temp_sel.dev_attr.attr,
&sensor_dev_attr_pwm1_target.dev_attr.attr,
&sensor_dev_attr_pwm1_stop_time.dev_attr.attr,
&sensor_dev_attr_pwm2_enable.dev_attr.attr,
&sensor_dev_attr_pwm2_stop_output_enable.dev_attr.attr,
&sensor_dev_attr_pwm2_weight_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm2_step_enable.dev_attr.attr,
&sensor_dev_attr_pwm2_temp_sel.dev_attr.attr,
&sensor_dev_attr_pwm2_target.dev_attr.attr,
&sensor_dev_attr_pwm2_stop_time.dev_attr.attr,
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
&sensor_dev_attr_pwm3_stop_output_enable.dev_attr.attr,
&sensor_dev_attr_pwm3_weight_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm3_step_enable.dev_attr.attr,
&sensor_dev_attr_pwm3_temp_sel.dev_attr.attr,
&sensor_dev_attr_pwm3_target.dev_attr.attr,
&sensor_dev_attr_pwm3_stop_time.dev_attr.attr,
&sensor_dev_attr_pwm4_enable.dev_attr.attr,
&sensor_dev_attr_pwm4_stop_output_enable.dev_attr.attr,
&sensor_dev_attr_pwm4_weight_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm4_step_enable.dev_attr.attr,
&sensor_dev_attr_pwm4_temp_sel.dev_attr.attr,
&sensor_dev_attr_pwm4_target.dev_attr.attr,
&sensor_dev_attr_pwm4_stop_time.dev_attr.attr,
&sensor_dev_attr_pwm5_enable.dev_attr.attr,
&sensor_dev_attr_pwm5_stop_output_enable.dev_attr.attr,
&sensor_dev_attr_pwm5_weight_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm5_step_enable.dev_attr.attr,
&sensor_dev_attr_pwm5_temp_sel.dev_attr.attr,
&sensor_dev_attr_pwm5_target.dev_attr.attr,
&sensor_dev_attr_pwm5_stop_time.dev_attr.attr,
int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
unsigned long val;
u8 reg;
+ int ret;
if (kstrtoul(buf, 10, &val) || val != 0)
return -EINVAL;
* The CR registers are the same for all chips, and not all chips
* support clearing the caseopen status through "regular" registers.
*/
- superio_enter(sio_data->sioreg);
+ ret = superio_enter(sio_data->sioreg);
+ if (ret) {
+ count = ret;
+ goto error;
+ }
+
superio_select(sio_data->sioreg, NCT6775_LD_ACPI);
reg = superio_inb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
superio_exit(sio_data->sioreg);
data->valid = 0; /* Force cache refresh */
-
+error:
mutex_unlock(&data->update_lock);
-
return count;
}
}
}
-static void __devinit
+static int __devinit
nct6775_check_fan_inputs(const struct nct6775_sio_data *sio_data,
struct nct6775_data *data)
{
int regval;
bool fan3pin, fan3min, fan4pin, fan4min, fan5pin;
bool pwm3pin, pwm4pin, pwm5pin;
+ int ret;
- superio_enter(sio_data->sioreg);
+ ret = superio_enter(sio_data->sioreg);
+ if (ret)
+ return ret;
/* fan4 and fan5 share some pins with the GPIO and serial flash */
if (data->kind == nct6775) {
data->has_fan_min |= (fan4min << 3) | (fan5pin << 4);
data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) | (pwm5pin << 4);
+
+ return 0;
}
static int __devinit nct6775_probe(struct platform_device *pdev)
data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
data->REG_TEMP_SEL[0] = NCT6775_REG_TEMP_SEL;
data->REG_TEMP_SEL[1] = NCT6775_REG_WEIGHT_TEMP_SEL;
+ data->REG_TEMP_SEL[2] = NCT6775_REG_FAN_STEP_ENABLE;
data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
data->REG_TEMP_SEL[0] = NCT6775_REG_TEMP_SEL;
data->REG_TEMP_SEL[1] = NCT6775_REG_WEIGHT_TEMP_SEL;
+ data->REG_TEMP_SEL[2] = NCT6775_REG_FAN_STEP_ENABLE;
data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
data->REG_TEMP_SEL[0] = NCT6775_REG_TEMP_SEL;
data->REG_TEMP_SEL[1] = NCT6775_REG_WEIGHT_TEMP_SEL;
+ data->REG_TEMP_SEL[2] = NCT6775_REG_FAN_STEP_ENABLE;
data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
nct6775_init_device(data);
data->vrm = vid_which_vrm();
- superio_enter(sio_data->sioreg);
+ err = superio_enter(sio_data->sioreg);
+ if (err)
+ return err;
+
/*
* Read VID value
* We can get the VID input values directly at logical device D 0xe3.
if (err)
return err;
- nct6775_check_fan_inputs(sio_data, data);
+ err = nct6775_check_fan_inputs(sio_data, data);
+ if (err)
+ goto exit_remove;
/* Read fan clock dividers immediately */
nct6775_update_fan_div_common(dev, data);
u16 val;
const char *sio_name;
+ int err;
- superio_enter(sioaddr);
+ err = superio_enter(sioaddr);
+ if (err)
+ return err;
if (force_id)
val = force_id;