// SPDX-License-Identifier: GPL-2.0-or-later /* * w83791d.c - Part of lm_sensors, Linux kernel modules for hardware * monitoring * * Copyright (C) 2006-2007 Charles Spirakis <bezaur@gmail.com>
*/
/* * Supports following chips: * * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA * w83791d 10 5 5 3 0x71 0x5ca3 yes no * * The w83791d chip appears to be part way between the 83781d and the * 83792d. Thus, this file is derived from both the w83792d.c and * w83781d.c files. * * The w83791g chip is the same as the w83791d but lead-free.
*/
staticconst u8 W83791D_REG_TEMP1[3] = {
0x27, /* TEMP 1 in DataSheet */
0x39, /* TEMP 1 Over in DataSheet */
0x3A, /* TEMP 1 Hyst in DataSheet */
};
staticconst u8 W83791D_REG_TEMP_ADD[2][6] = {
{0xC0, /* TEMP 2 in DataSheet */
0xC1, /* TEMP 2(0.5 deg) in DataSheet */
0xC5, /* TEMP 2 Over High part in DataSheet */
0xC6, /* TEMP 2 Over Low part in DataSheet */
0xC3, /* TEMP 2 Thyst High part in DataSheet */
0xC4}, /* TEMP 2 Thyst Low part in DataSheet */
{0xC8, /* TEMP 3 in DataSheet */
0xC9, /* TEMP 3(0.5 deg) in DataSheet */
0xCD, /* TEMP 3 Over High part in DataSheet */
0xCE, /* TEMP 3 Over Low part in DataSheet */
0xCB, /* TEMP 3 Thyst High part in DataSheet */
0xCC} /* TEMP 3 Thyst Low part in DataSheet */
};
#define W83791D_REG_BEEP_CONFIG 0x4D
staticconst u8 W83791D_REG_BEEP_CTRL[3] = {
0x56, /* BEEP Control Register 1 */
0x57, /* BEEP Control Register 2 */
0xA3, /* BEEP Control Register 3 */
};
/* * The SMBus locks itself. The Winbond W83791D has a bank select register * (index 0x4e), but the driver only accesses registers in bank 0. Since * we don't switch banks, we don't need any special code to handle * locking access between bank switches
*/ staticinlineint w83791d_read(struct i2c_client *client, u8 reg)
{ return i2c_smbus_read_byte_data(client, reg);
}
/* * The analog voltage inputs have 16mV LSB. Since the sysfs output is * in mV as would be measured on the chip input pin, need to just * multiply/divide by 16 to translate from/to register values.
*/ #define IN_TO_REG(val) (clamp_val((((val) + 8) / 16), 0, 255)) #define IN_FROM_REG(val) ((val) * 16)
/* * for temp2 and temp3 which are 9-bit resolution, LSB = 0.5 degree Celsius * Assumes the top 8 bits are the integral amount and the bottom 8 bits * are the fractional amount. Since we only have 0.5 degree resolution, * the bottom 7 bits will always be zero
*/ #define TEMP23_FROM_REG(val) ((val) / 128 * 500) #define TEMP23_TO_REG(val) (DIV_ROUND_CLOSEST(clamp_val((val), -128000, \
127500), 500) * 128)
bool valid; /* true if following fields are valid */ unsignedlong last_updated; /* In jiffies */
/* volts */
u8 in[NUMBER_OF_VIN]; /* Register value */
u8 in_max[NUMBER_OF_VIN]; /* Register value */
u8 in_min[NUMBER_OF_VIN]; /* Register value */
/* fans */
u8 fan[NUMBER_OF_FANIN]; /* Register value */
u8 fan_min[NUMBER_OF_FANIN]; /* Register value */
u8 fan_div[NUMBER_OF_FANIN]; /* Register encoding, shifted right */
/* Temperature sensors */
s8 temp1[3]; /* current, over, thyst */
s16 temp_add[2][3]; /* fixed point value. Top 8 bits are the * integral part, bottom 8 bits are the * fractional part. We only use the top * 9 bits as the resolution is only * to the 0.5 degree C... * two sensors with three values * (cur, over, hyst)
*/
/* PWMs */
u8 pwm[5]; /* pwm duty cycle */
u8 pwm_enable[3]; /* pwm enable status for fan 1-3 * (fan 4-5 only support manual mode)
*/
u8 temp_target[3]; /* pwm 1-3 target temperature */
u8 temp_tolerance[3]; /* pwm 1-3 temperature tolerance */
/* Misc */
u32 alarms; /* realtime status register encoding,combined */
u8 beep_enable; /* Global beep enable */
u32 beep_mask; /* Mask off specific beeps */
u8 vid; /* Register encoding, combined */
u8 vrm; /* hwmon-vid */
};
/* * 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 surprise; the user doesn't expect the fan minimum to change just * because the divisor changed.
*/ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr, constchar *buf, size_t count)
{ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); struct i2c_client *client = to_i2c_client(dev); struct w83791d_data *data = i2c_get_clientdata(client); int nr = sensor_attr->index; unsignedlong min;
u8 tmp_fan_div;
u8 fan_div_reg;
u8 vbat_reg; int indx = 0;
u8 keep_mask = 0;
u8 new_shift = 0; unsignedlong val; int err;
err = kstrtoul(buf, 10, &val); if (err) return err;
/* Save fan_min */
min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]));
static ssize_t store_beep_mask(struct device *dev, struct device_attribute *attr, constchar *buf, size_t count)
{ struct i2c_client *client = to_i2c_client(dev); struct w83791d_data *data = i2c_get_clientdata(client); int i; long val; int err;
err = kstrtol(buf, 10, &val); if (err) return err;
mutex_lock(&data->update_lock);
/* * The beep_enable state overrides any enabling request from * the masks
*/
data->beep_mask = BEEP_MASK_TO_REG(val) & ~GLOBAL_BEEP_ENABLE_MASK;
data->beep_mask |= (data->beep_enable << GLOBAL_BEEP_ENABLE_SHIFT);
val = data->beep_mask;
for (i = 0; i < 3; i++) {
w83791d_write(client, W83791D_REG_BEEP_CTRL[i], (val & 0xff));
val >>= 8;
}
err = kstrtol(buf, 10, &val); if (err) return err;
mutex_lock(&data->update_lock);
data->beep_enable = val ? 1 : 0;
/* Keep the full mask value in sync with the current enable */
data->beep_mask &= ~GLOBAL_BEEP_ENABLE_MASK;
data->beep_mask |= (data->beep_enable << GLOBAL_BEEP_ENABLE_SHIFT);
/* * The global control is in the second beep control register * so only need to update that register
*/
val = (data->beep_mask >> 8) & 0xff;
/* * Separate group of attributes for fan/pwm 4-5. Their pins can also be * in use for GPIO in which case their sysfs-interface should not be made * available
*/ staticstruct attribute *w83791d_attributes_fanpwm45[] = {
FAN_UNIT_ATTRS(3),
FAN_UNIT_ATTRS(4),
&sda_pwm[3].dev_attr.attr,
&sda_pwm[4].dev_attr.attr,
NULL
};
/* Return 0 if detection is successful, -ENODEV otherwise */ staticint w83791d_detect(struct i2c_client *client, struct i2c_board_info *info)
{ struct i2c_adapter *adapter = client->adapter; int val1, val2; unsignedshort address = client->addr;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV;
if (w83791d_read(client, W83791D_REG_CONFIG) & 0x80) return -ENODEV;
val1 = w83791d_read(client, W83791D_REG_BANK);
val2 = w83791d_read(client, W83791D_REG_CHIPMAN); /* Check for Winbond ID if in bank 0 */ if (!(val1 & 0x07)) { if ((!(val1 & 0x80) && val2 != 0xa3) ||
((val1 & 0x80) && val2 != 0x5c)) { return -ENODEV;
}
} /* * If Winbond chip, address of chip and W83791D_REG_I2C_ADDR * should match
*/ if (w83791d_read(client, W83791D_REG_I2C_ADDR) != address) return -ENODEV;
/* We want bank 0 and Vendor ID high byte */
val1 = w83791d_read(client, W83791D_REG_BANK) & 0x78;
w83791d_write(client, W83791D_REG_BANK, val1 | 0x80);
/* Verify it is a Winbond w83791d */
val1 = w83791d_read(client, W83791D_REG_WCHIPID);
val2 = w83791d_read(client, W83791D_REG_CHIPMAN); if (val1 != 0x71 || val2 != 0x5c) return -ENODEV;
strscpy(info->type, "w83791d", I2C_NAME_SIZE);
return 0;
}
staticint w83791d_probe(struct i2c_client *client)
{ struct w83791d_data *data; struct device *dev = &client->dev; int i, err;
u8 has_fanpwm45;
err = w83791d_detect_subclients(client); if (err) return err;
/* Initialize the chip */
w83791d_init_client(client);
/* * If the fan_div is changed, make sure there is a rational * fan_min in place
*/ for (i = 0; i < NUMBER_OF_FANIN; i++)
data->fan_min[i] = w83791d_read(client, W83791D_REG_FAN_MIN[i]);
/* Check if pins of fan/pwm 4-5 are in use as GPIO */
has_fanpwm45 = w83791d_read(client, W83791D_REG_GPIO) & 0x10; if (has_fanpwm45) {
err = sysfs_create_group(&client->dev.kobj,
&w83791d_group_fanpwm45); if (err) goto error4;
}
/* Everything is ready, now register the working device */
data->hwmon_dev = hwmon_device_register(dev); if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev); goto error5;
}
/* * The difference between reset and init is that reset * does a hard reset of the chip via index 0x40, bit 7, * but init simply forces certain registers to have "sane" * values. The hope is that the BIOS has done the right * thing (which is why the default is reset=0, init=0), * but if not, reset is the hard hammer and init * is the soft mallet both of which are trying to whack * things into place... * NOTE: The data sheet makes a distinction between * "power on defaults" and "reset by MR". As far as I can tell, * the hard reset puts everything into a power-on state so I'm * not sure what "reset by MR" means or how it can happen.
*/ if (reset || init) { /* keep some BIOS settings when we... */
old_beep = w83791d_read(client, W83791D_REG_BEEP_CONFIG);
if (reset) { /* ... reset the chip and ... */
w83791d_write(client, W83791D_REG_CONFIG, 0x80);
}
/* disable the global beep (not done by hard reset) */
tmp = w83791d_read(client, W83791D_REG_BEEP_CTRL[1]);
w83791d_write(client, W83791D_REG_BEEP_CTRL[1], tmp & 0xef);
if (init) { /* Make sure monitoring is turned on for add-ons */
tmp = w83791d_read(client, W83791D_REG_TEMP2_CONFIG); if (tmp & 1) {
w83791d_write(client, W83791D_REG_TEMP2_CONFIG,
tmp & 0xfe);
}
/* Update the voltages measured value and limits */ for (i = 0; i < NUMBER_OF_VIN; i++) {
data->in[i] = w83791d_read(client,
W83791D_REG_IN[i]);
data->in_max[i] = w83791d_read(client,
W83791D_REG_IN_MAX[i]);
data->in_min[i] = w83791d_read(client,
W83791D_REG_IN_MIN[i]);
}
/* Update the fan counts and limits */ for (i = 0; i < NUMBER_OF_FANIN; i++) { /* Update the Fan measured value and limits */
data->fan[i] = w83791d_read(client,
W83791D_REG_FAN[i]);
data->fan_min[i] = w83791d_read(client,
W83791D_REG_FAN_MIN[i]);
}
/* * The fan divisor for fans 0-2 get bit 2 from * bits 5-7 respectively of vbat register
*/
vbat_reg = w83791d_read(client, W83791D_REG_VBAT); for (i = 0; i < 3; i++)
data->fan_div[i] |= (vbat_reg >> (3 + i)) & 0x04;
/* Update PWM duty cycle */ for (i = 0; i < NUMBER_OF_PWM; i++) {
data->pwm[i] = w83791d_read(client,
W83791D_REG_PWM[i]);
}
/* Extract global beep enable flag */
data->beep_enable =
(data->beep_mask >> GLOBAL_BEEP_ENABLE_SHIFT) & 0x01;
/* Update the cpu voltage information */
i = w83791d_read(client, W83791D_REG_VID_FANDIV);
data->vid = i & 0x0f;
data->vid |= (w83791d_read(client, W83791D_REG_DID_VID4) & 0x01)
<< 4;
#ifdef DEBUG staticvoid w83791d_print_debug(struct w83791d_data *data, struct device *dev)
{ int i = 0, j = 0;
dev_dbg(dev, "======Start of w83791d debug values======\n");
dev_dbg(dev, "%d set of Voltages: ===>\n", NUMBER_OF_VIN); for (i = 0; i < NUMBER_OF_VIN; i++) {
dev_dbg(dev, "vin[%d] is: 0x%02x\n", i, data->in[i]);
dev_dbg(dev, "vin[%d] min is: 0x%02x\n", i, data->in_min[i]);
dev_dbg(dev, "vin[%d] max is: 0x%02x\n", i, data->in_max[i]);
}
dev_dbg(dev, "%d set of Fan Counts/Divisors: ===>\n", NUMBER_OF_FANIN); for (i = 0; i < NUMBER_OF_FANIN; i++) {
dev_dbg(dev, "fan[%d] is: 0x%02x\n", i, data->fan[i]);
dev_dbg(dev, "fan[%d] min is: 0x%02x\n", i, data->fan_min[i]);
dev_dbg(dev, "fan_div[%d] is: 0x%02x\n", i, data->fan_div[i]);
}
/* * temperature math is signed, but only print out the * bits that matter
*/
dev_dbg(dev, "%d set of Temperatures: ===>\n", NUMBER_OF_TEMPIN); for (i = 0; i < 3; i++)
dev_dbg(dev, "temp1[%d] is: 0x%02x\n", i, (u8) data->temp1[i]); for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) {
dev_dbg(dev, "temp_add[%d][%d] is: 0x%04x\n", i, j,
(u16) data->temp_add[i][j]);
}
}
dev_dbg(dev, "Misc Information: ===>\n");
dev_dbg(dev, "alarm is: 0x%08x\n", data->alarms);
dev_dbg(dev, "beep_mask is: 0x%08x\n", data->beep_mask);
dev_dbg(dev, "beep_enable is: %d\n", data->beep_enable);
dev_dbg(dev, "vid is: 0x%02x\n", data->vid);
dev_dbg(dev, "vrm is: 0x%02x\n", data->vrm);
dev_dbg(dev, "=======End of w83791d debug values========\n");
dev_dbg(dev, "\n");
} #endif
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.