/* * Hardware access * We assume that nobdody can change the bank outside the driver.
*/
/* Must be called with data->update_lock held, except during initialization */ staticint w83795_set_bank(struct i2c_client *client, u8 bank)
{ struct w83795_data *data = i2c_get_clientdata(client); int err;
/* If the same bank is already set, nothing to do */ if ((data->bank & 0x07) == bank) return 0;
/* Change to new bank, preserve all other bits */
bank |= data->bank & ~0x07;
err = i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, bank); if (err < 0) {
dev_err(&client->dev, "Failed to set bank to %d, err %d\n",
(int)bank, err); return err;
}
data->bank = bank;
return 0;
}
/* Must be called with data->update_lock held, except during initialization */ static u8 w83795_read(struct i2c_client *client, u16 reg)
{ int err;
/* Must be called with data->update_lock held, except during initialization */ staticint w83795_write(struct i2c_client *client, u16 reg, u8 value)
{ int err;
err = i2c_smbus_write_byte_data(client, reg & 0xff, value); if (err < 0)
dev_err(&client->dev, "Failed to write to register 0x%03x, err %d\n",
(int)reg, err); return err;
}
staticvoid w83795_update_limits(struct i2c_client *client)
{ struct w83795_data *data = i2c_get_clientdata(client); int i, limit;
u8 lsb;
/* Read the voltage limits */ for (i = 0; i < ARRAY_SIZE(data->in); i++) { if (!(data->has_in & (1 << i))) continue;
data->in[i][IN_MAX] =
w83795_read(client, W83795_REG_IN[i][IN_MAX]);
data->in[i][IN_LOW] =
w83795_read(client, W83795_REG_IN[i][IN_LOW]);
} for (i = 0; i < ARRAY_SIZE(data->in_lsb); i++) { if ((i == 2 && data->chip_type == w83795adg) ||
(i >= 4 && !(data->has_in & (1 << (i + 11))))) continue;
data->in_lsb[i][IN_MAX] =
w83795_read(client, IN_LSB_REG(i, IN_MAX));
data->in_lsb[i][IN_LOW] =
w83795_read(client, IN_LSB_REG(i, IN_LOW));
}
/* Read the fan limits */
lsb = 0; /* Silent false gcc warning */ for (i = 0; i < ARRAY_SIZE(data->fan); i++) { /* * Each register contains LSB for 2 fans, but we want to * read it only once to save time
*/ if ((i & 1) == 0 && (data->has_fan & (3 << i)))
lsb = w83795_read(client, W83795_REG_FAN_MIN_LSB(i));
/* Read the temperature limits */ for (i = 0; i < ARRAY_SIZE(data->temp); i++) { if (!(data->has_temp & (1 << i))) continue; for (limit = TEMP_CRIT; limit <= TEMP_WARN_HYST; limit++)
data->temp[i][limit] =
w83795_read(client, W83795_REG_TEMP[i][limit]);
}
/* Read the DTS limits */ if (data->enable_dts) { for (limit = DTS_CRIT; limit <= DTS_WARN_HYST; limit++)
data->dts_ext[limit] =
w83795_read(client, W83795_REG_DTS_EXT(limit));
}
/* Read beep settings */ if (data->enable_beep) { for (i = 0; i < ARRAY_SIZE(data->beeps); i++)
data->beeps[i] =
w83795_read(client, W83795_REG_BEEP(i));
}
data->valid_limits = 1;
}
staticstruct w83795_data *w83795_update_pwm_config(struct device *dev)
{ struct i2c_client *client = to_i2c_client(dev); struct w83795_data *data = i2c_get_clientdata(client); int i, tmp;
mutex_lock(&data->update_lock);
if (data->valid_pwm_config) goto END;
/* Read temperature source selection */ for (i = 0; i < ARRAY_SIZE(data->temp_src); i++)
data->temp_src[i] = w83795_read(client, W83795_REG_TSS(i));
/* Read automatic fan speed control settings */
data->pwm_fcms[0] = w83795_read(client, W83795_REG_FCMS1);
data->pwm_fcms[1] = w83795_read(client, W83795_REG_FCMS2); for (i = 0; i < ARRAY_SIZE(data->pwm_tfmr); i++)
data->pwm_tfmr[i] = w83795_read(client, W83795_REG_TFMR(i));
data->pwm_fomc = w83795_read(client, W83795_REG_FOMC); for (i = 0; i < data->has_pwm; i++) { for (tmp = PWM_FREQ; tmp <= PWM_STOP_TIME; tmp++)
data->pwm[i][tmp] =
w83795_read(client, W83795_REG_PWM(i, tmp));
} for (i = 0; i < ARRAY_SIZE(data->target_speed); i++) {
data->target_speed[i] =
w83795_read(client, W83795_REG_FTSH(i)) << 4;
data->target_speed[i] |=
w83795_read(client, W83795_REG_FTSL(i)) >> 4;
}
data->tol_speed = w83795_read(client, W83795_REG_TFTS) & 0x3f;
/* Update fan */ for (i = 0; i < ARRAY_SIZE(data->fan); i++) { if (!(data->has_fan & (1 << i))) continue;
data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4;
data->fan[i] |= w83795_read(client, W83795_REG_VRLSB) >> 4;
}
/* Update temperature */ for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
data->temp[i][TEMP_READ] =
w83795_read(client, W83795_REG_TEMP[i][TEMP_READ]);
data->temp_read_vrlsb[i] =
w83795_read(client, W83795_REG_VRLSB);
}
/* Update dts temperature */ if (data->enable_dts) { for (i = 0; i < ARRAY_SIZE(data->dts); i++) { if (!(data->has_dts & (1 << i))) continue;
data->dts[i] =
w83795_read(client, W83795_REG_DTS(i));
data->dts_read_vrlsb[i] =
w83795_read(client, W83795_REG_VRLSB);
}
}
/* Update pwm output */ for (i = 0; i < data->has_pwm; i++) {
data->pwm[i][PWM_OUTPUT] =
w83795_read(client, W83795_REG_PWM(i, PWM_OUTPUT));
}
/* * Update intrusion and alarms * It is important to read intrusion first, because reading from * register SMI STS6 clears the interrupt status temporarily.
*/
tmp = w83795_read(client, W83795_REG_ALARM_CTRL); /* Switch to interrupt status for intrusion if needed */ if (tmp & ALARM_CTRL_RTSACS)
w83795_write(client, W83795_REG_ALARM_CTRL,
tmp & ~ALARM_CTRL_RTSACS);
intrusion = w83795_read(client, W83795_REG_ALARM(5)) & (1 << 6); /* Switch to real-time alarms */
w83795_write(client, W83795_REG_ALARM_CTRL, tmp | ALARM_CTRL_RTSACS); for (i = 0; i < ARRAY_SIZE(data->alarms); i++)
data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i));
data->alarms[5] |= intrusion; /* Restore original configuration if needed */ if (!(tmp & ALARM_CTRL_RTSACS))
w83795_write(client, W83795_REG_ALARM_CTRL,
tmp & ~ALARM_CTRL_RTSACS);
if (kstrtoul(buf, 10, &val)) return -EINVAL;
val = fan_to_reg(val);
mutex_lock(&data->update_lock);
data->fan_min[index] = val;
w83795_write(client, W83795_REG_FAN_MIN_HL(index), (val >> 4) & 0xff);
val &= 0x0f; if (index & 1) {
val <<= 4;
val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index))
& 0x0f;
} else {
val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index))
& 0xf0;
}
w83795_write(client, W83795_REG_FAN_MIN_LSB(index), val & 0xff);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t
show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
{ struct w83795_data *data; struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; int index = sensor_attr->index; unsignedint val;
data = nr == PWM_OUTPUT ? w83795_update_device(dev)
: w83795_update_pwm_config(dev);
switch (nr) { case PWM_STOP_TIME:
val = time_from_reg(data->pwm[index][nr]); break; case PWM_FREQ:
val = pwm_freq_from_reg(data->pwm[index][nr], data->clkin); break; default:
val = data->pwm[index][nr]; break;
}
return sprintf(buf, "%u\n", val);
}
static ssize_t
store_pwm(struct device *dev, struct device_attribute *attr, constchar *buf, size_t count)
{ struct i2c_client *client = to_i2c_client(dev); struct w83795_data *data = i2c_get_clientdata(client); struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; int index = sensor_attr->index; unsignedlong val;
if (kstrtoul(buf, 10, &val) < 0) return -EINVAL;
mutex_lock(&data->update_lock); switch (nr) { case PWM_STOP_TIME:
val = time_to_reg(val); break; case PWM_FREQ:
val = pwm_freq_to_reg(val, data->clkin); break; default:
val = clamp_val(val, 0, 0xff); break;
}
w83795_write(client, W83795_REG_PWM(index, nr), val);
data->pwm[index][nr] = val;
mutex_unlock(&data->update_lock); return count;
}
if (kstrtoul(buf, 10, &val) < 0) return -EINVAL; if (val < 1 || val > 2) return -EINVAL;
#ifndef CONFIG_SENSORS_W83795_FANCTRL if (val > 1) {
dev_warn(dev, "Automatic fan speed control support disabled\n");
dev_warn(dev, "Build with CONFIG_SENSORS_W83795_FANCTRL=y if you want it\n"); return -EOPNOTSUPP;
} #endif
if (data->pwm_fomc & (1 << index))
mode = 0; /* DC */ else
mode = 1; /* PWM */
return sprintf(buf, "%u\n", mode);
}
/* * Check whether a given temperature source can ever be useful. * Returns the number of selectable temperature channels which are * enabled.
*/ staticint w83795_tss_useful(conststruct w83795_data *data, int tsrc)
{ int useful = 0, i;
for (i = 0; i < 4; i++) { if (tss_map[i][tsrc] == TSS_MAP_RESERVED) continue; if (tss_map[i][tsrc] < 6) /* Analog */
useful += (data->has_temp >> tss_map[i][tsrc]) & 1; else/* Digital */
useful += (data->has_dts >> (tss_map[i][tsrc] - 6)) & 1;
}
/* Check if request can be fulfilled */ for (tmp = 0; tmp < 4; tmp++) { if (tss_map[tmp][index] == channel - 1) break;
} if (tmp == 4) /* No match */ return -EINVAL;
/* show/store VIN */ static ssize_t
show_in(struct device *dev, struct device_attribute *attr, char *buf)
{ struct sensor_device_attribute_2 *sensor_attr =
to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; int index = sensor_attr->index; struct w83795_data *data = w83795_update_device(dev);
u16 val = data->in[index][nr];
u8 lsb_idx;
switch (nr) { case IN_READ: /* calculate this value again by sensors as sensors3.conf */ if ((index >= 17) &&
!((data->has_gain >> (index - 17)) & 1))
val *= 8; break; case IN_MAX: case IN_LOW:
lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX];
val <<= 2;
val |= (data->in_lsb[lsb_idx][nr] >>
IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]) & 0x03; if ((index >= 17) &&
!((data->has_gain >> (index - 17)) & 1))
val *= 8; break;
}
val = in_from_reg(index, val);
switch (nr) { case SETUP_PWM_DEFAULT:
val = clamp_val(val, 0, 0xff); break; case SETUP_PWM_UPTIME: case SETUP_PWM_DOWNTIME:
val = time_to_reg(val); if (val == 0) return -EINVAL; break;
}
/* * Special case for rev. A chips; can't be checked first because later * revisions emulate this for compatibility
*/ if (device_id < 0 || (device_id & 0xf0) != 0x50) { int alt_id;
/* * If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR * should match
*/ if ((bank & 0x07) == 0) {
i2c_addr = i2c_smbus_read_byte_data(client,
W83795_REG_I2C_ADDR); if ((i2c_addr & 0x7f) != address) {
dev_dbg(&adapter->dev, "w83795: Detection failed at addr 0x%02hx, " "check %s\n", address, "i2c addr"); return -ENODEV;
}
}
/* * Check 795 chip type: 795G or 795ADG * Usually we don't write to chips during detection, but here we don't * quite have the choice; hopefully it's OK, we are about to return * success anyway
*/ if ((bank & 0x07) != 0)
i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL,
bank & ~0x07);
config = i2c_smbus_read_byte_data(client, W83795_REG_CONFIG); if (config & W83795_REG_CONFIG_CONFIG48)
chip_name = "w83795adg"; else
chip_name = "w83795g";
staticint w83795_handle_files(struct device *dev, int (*fn)(struct device *, conststruct device_attribute *))
{ struct w83795_data *data = dev_get_drvdata(dev); int err, i, j;
for (i = 0; i < ARRAY_SIZE(w83795_in); i++) { if (!(data->has_in & (1 << i))) continue; for (j = 0; j < ARRAY_SIZE(w83795_in[0]); j++) { if (j == 4 && !data->enable_beep) continue;
err = fn(dev, &w83795_in[i][j].dev_attr); if (err) return err;
}
}
for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) { if (!(data->has_fan & (1 << i))) continue; for (j = 0; j < ARRAY_SIZE(w83795_fan[0]); j++) { if (j == 3 && !data->enable_beep) continue;
err = fn(dev, &w83795_fan[i][j].dev_attr); if (err) return err;
}
}
for (i = 0; i < ARRAY_SIZE(w83795_tss); i++) {
j = w83795_tss_useful(data, i); if (!j) continue;
err = fn(dev, &w83795_tss[i].dev_attr); if (err) return err;
}
for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) {
err = fn(dev, &sda_single_files[i].dev_attr); if (err) return err;
}
if (data->enable_beep) { for (i = 0; i < ARRAY_SIZE(sda_beep_files); i++) {
err = fn(dev, &sda_beep_files[i].dev_attr); if (err) return err;
}
}
for (i = 0; i < data->has_pwm; i++) { for (j = 0; j < NUM_PWM_ATTRIBUTES; j++) {
err = fn(dev, &w83795_pwm[i][j].dev_attr); if (err) return err;
}
}
for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) { if (!(data->has_temp & (1 << i))) continue; for (j = 0; j < NUM_TEMP_ATTRIBUTES; j++) { if (j == 7 && !data->enable_beep) continue;
err = fn(dev, &w83795_temp[i][j].dev_attr); if (err) return err;
}
}
if (data->enable_dts) { for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) { if (!(data->has_dts & (1 << i))) continue; for (j = 0; j < ARRAY_SIZE(w83795_dts[0]); j++) { if (j == 7 && !data->enable_beep) continue;
err = fn(dev, &w83795_dts[i][j].dev_attr); if (err) return err;
}
}
}
return 0;
}
/* We need a wrapper that fits in w83795_handle_files */ staticint device_remove_file_wrapper(struct device *dev, conststruct device_attribute *attr)
{
device_remove_file(dev, attr); return 0;
}
staticvoid w83795_check_dynamic_in_limits(struct i2c_client *client)
{ struct w83795_data *data = i2c_get_clientdata(client);
u8 vid_ctl; int i, err_max, err_min;
data->has_dyn_in = (vid_ctl >> 3) & 0x07; for (i = 0; i < 2; i++) { if (!(data->has_dyn_in & (1 << i))) continue;
/* Voltage limits in dynamic mode, switch to read-only */
err_max = sysfs_chmod_file(&client->dev.kobj,
&w83795_in[i][2].dev_attr.attr,
S_IRUGO);
err_min = sysfs_chmod_file(&client->dev.kobj,
&w83795_in[i][3].dev_attr.attr,
S_IRUGO); if (err_max || err_min)
dev_warn(&client->dev, "Failed to set in%d limits read-only (%d, %d)\n",
i, err_max, err_min); else
dev_info(&client->dev, "in%d limits set dynamically from VID\n", i);
}
}
/* Check pins that can be used for either temperature or voltage monitoring */ staticvoid w83795_apply_temp_config(struct w83795_data *data, u8 config, int temp_chan, int in_chan)
{ /* config is a 2-bit value */ switch (config) { case 0x2: /* Voltage monitoring */
data->has_in |= 1 << in_chan; break; case 0x1: /* Thermal diode */ if (temp_chan >= 4) break;
data->temp_mode |= 1 << temp_chan;
fallthrough; case 0x3: /* Thermistor */
data->has_temp |= 1 << temp_chan; break;
}
}
staticint w83795_probe(struct i2c_client *client)
{ int i;
u8 tmp; struct device *dev = &client->dev; struct w83795_data *data; int err;
data = devm_kzalloc(dev, sizeof(struct w83795_data), GFP_KERNEL); if (!data) return -ENOMEM;
/* pwm and smart fan */ if (data->chip_type == w83795g)
data->has_pwm = 8; else
data->has_pwm = 2;
/* Check if BEEP pin is available */ if (data->chip_type == w83795g) { /* The W83795G has a dedicated BEEP pin */
data->enable_beep = 1;
} else { /* * The W83795ADG has a shared pin for OVT# and BEEP, so you * can't have both
*/
tmp = w83795_read(client, W83795_REG_OVT_CFG); if ((tmp & OVT_CFG_SEL) == 0)
data->enable_beep = 1;
}
err = w83795_handle_files(dev, device_create_file); if (err) goto exit_remove;
if (data->chip_type == w83795g)
w83795_check_dynamic_in_limits(client);
MODULE_AUTHOR("Wei Song, Jean Delvare ");
MODULE_DESCRIPTION("W83795G/ADG hardware monitoring driver");
MODULE_LICENSE("GPL");
Messung V0.5
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.26Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.