/* Error codes */ #define MAX6621_TRAN_FAILED 0x8100 /* * PECI transaction failed for more * than the configured number of * consecutive retries.
*/ #define MAX6621_POOL_DIS 0x8101 /* * Polling disabled for requested * socket/domain.
*/ #define MAX6621_POOL_UNCOMPLETE 0x8102 /* * First poll not yet completed for * requested socket/domain (on * startup).
*/ #define MAX6621_SD_DIS 0x8103 /* * Read maximum temperature requested, * but no sockets/domains enabled or * all enabled sockets/domains have * errors; or read maximum temperature * address requested, but read maximum * temperature was not called.
*/ #define MAX6621_ALERT_DIS 0x8104 /* * Get alert socket/domain requested, * but no alert active.
*/ #define MAX6621_PECI_ERR_MIN 0x8000 /* Intel spec PECI error min value. */ #define MAX6621_PECI_ERR_MAX 0x80ff /* Intel spec PECI error max value. */
static umode_t
max6621_is_visible(constvoid *data, enum hwmon_sensor_types type, u32 attr, int channel)
{ /* Skip channels which are not physically conncted. */ if (((struct max6621_data *)data)->input_chan2reg[channel] < 0) return 0;
switch (type) { case hwmon_temp: switch (attr) { case hwmon_temp_input: case hwmon_temp_label: case hwmon_temp_crit_alarm: return 0444; case hwmon_temp_offset: case hwmon_temp_crit: return 0644; default: break;
} break; default: break;
}
switch (regval) { case MAX6621_TRAN_FAILED:
dev_dbg(dev, "PECI transaction failed - err 0x%04x.\n",
regval); return -EIO; case MAX6621_POOL_DIS:
dev_dbg(dev, "Polling disabled - err 0x%04x.\n", regval); return -EOPNOTSUPP; case MAX6621_POOL_UNCOMPLETE:
dev_dbg(dev, "First poll not completed on startup - err 0x%04x.\n",
regval); return -EIO; case MAX6621_SD_DIS:
dev_dbg(dev, "Resource is disabled - err 0x%04x.\n", regval); return -EOPNOTSUPP; case MAX6621_ALERT_DIS:
dev_dbg(dev, "No alert active - err 0x%04x.\n", regval); return -EOPNOTSUPP; default: return 0;
}
}
staticint
max6621_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val)
{ struct max6621_data *data = dev_get_drvdata(dev);
u32 regval; int reg;
s8 temp; int ret;
switch (type) { case hwmon_temp: switch (attr) { case hwmon_temp_input:
reg = data->input_chan2reg[channel];
ret = regmap_read(data->regmap, reg, ®val); if (ret) return ret;
ret = max6621_verify_reg_data(dev, regval); if (ret) return ret;
/* * Bit MAX6621_REG_TEMP_SHIFT represents 1 degree step. * The temperature is given in two's complement and 8 * bits is used for the register conversion.
*/
temp = (regval >> MAX6621_REG_TEMP_SHIFT);
*val = temp * 1000L;
break; case hwmon_temp_offset:
ret = regmap_read(data->regmap, MAX6621_CONFIG2_REG,
®val); if (ret) return ret;
ret = max6621_verify_reg_data(dev, regval); if (ret) return ret;
break; case hwmon_temp_crit:
channel -= MAX6621_TEMP_ALERT_CHAN_SHIFT;
reg = max6621_temp_alert_chan2reg[channel];
ret = regmap_read(data->regmap, reg, ®val); if (ret) return ret;
ret = max6621_verify_reg_data(dev, regval); if (ret) return ret;
*val = regval * 1000L;
break; case hwmon_temp_crit_alarm: /* * Set val to zero to recover the case, when reading * MAX6621_TEMP_ALERT_CAUSE_REG results in for example * MAX6621_ALERT_DIS. Reading will return with error, * but in such case alarm should be returned as 0.
*/
*val = 0;
ret = regmap_read(data->regmap,
MAX6621_TEMP_ALERT_CAUSE_REG,
®val); if (ret) return ret;
ret = max6621_verify_reg_data(dev, regval); if (ret) { /* Do not report error if alert is disabled. */ if (regval == MAX6621_ALERT_DIS) return 0; else return ret;
}
/* * Clear the alert automatically, using send-byte * smbus protocol for clearing alert.
*/ if (regval) {
ret = i2c_smbus_write_byte(data->client,
MAX6621_CLEAR_ALERT_REG); if (ret) return ret;
}
switch (type) { case hwmon_temp: switch (attr) { case hwmon_temp_offset: /* Clamp to allowed range to prevent overflow. */
val = clamp_val(val, MAX6621_TEMP_INPUT_MIN,
MAX6621_TEMP_INPUT_MAX);
val = max6621_temp_mc2reg(val);
return regmap_write(data->regmap,
MAX6621_CONFIG2_REG, val); case hwmon_temp_crit:
channel -= MAX6621_TEMP_ALERT_CHAN_SHIFT;
reg = max6621_temp_alert_chan2reg[channel]; /* Clamp to allowed range to prevent overflow. */
val = clamp_val(val, MAX6621_TEMP_INPUT_MIN,
MAX6621_TEMP_INPUT_MAX);
val = val / 1000L;
staticbool max6621_writeable_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case MAX6621_CONFIG0_REG: case MAX6621_CONFIG1_REG: case MAX6621_CONFIG2_REG: case MAX6621_CONFIG3_REG: case MAX6621_TEMP_S0_ALERT_REG: case MAX6621_TEMP_S1_ALERT_REG: case MAX6621_TEMP_S2_ALERT_REG: case MAX6621_TEMP_S3_ALERT_REG: case MAX6621_TEMP_ALERT_CAUSE_REG: returntrue;
} returnfalse;
}
staticbool max6621_readable_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case MAX6621_TEMP_S0D0_REG: case MAX6621_TEMP_S0D1_REG: case MAX6621_TEMP_S1D0_REG: case MAX6621_TEMP_S1D1_REG: case MAX6621_TEMP_S2D0_REG: case MAX6621_TEMP_S2D1_REG: case MAX6621_TEMP_S3D0_REG: case MAX6621_TEMP_S3D1_REG: case MAX6621_TEMP_MAX_REG: case MAX6621_TEMP_MAX_ADDR_REG: case MAX6621_CONFIG0_REG: case MAX6621_CONFIG1_REG: case MAX6621_CONFIG2_REG: case MAX6621_CONFIG3_REG: case MAX6621_TEMP_S0_ALERT_REG: case MAX6621_TEMP_S1_ALERT_REG: case MAX6621_TEMP_S2_ALERT_REG: case MAX6621_TEMP_S3_ALERT_REG: returntrue;
} returnfalse;
}
staticbool max6621_volatile_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case MAX6621_TEMP_S0D0_REG: case MAX6621_TEMP_S0D1_REG: case MAX6621_TEMP_S1D0_REG: case MAX6621_TEMP_S1D1_REG: case MAX6621_TEMP_S2D0_REG: case MAX6621_TEMP_S2D1_REG: case MAX6621_TEMP_S3D0_REG: case MAX6621_TEMP_S3D1_REG: case MAX6621_TEMP_MAX_REG: case MAX6621_TEMP_S0_ALERT_REG: case MAX6621_TEMP_S1_ALERT_REG: case MAX6621_TEMP_S2_ALERT_REG: case MAX6621_TEMP_S3_ALERT_REG: case MAX6621_TEMP_ALERT_CAUSE_REG: returntrue;
} returnfalse;
}
/* Set CONFIG0 register masking temperature alerts and PEC. */
ret = regmap_write(data->regmap, MAX6621_CONFIG0_REG,
MAX6621_CONFIG0_INIT); if (ret) return ret;
/* Set CONFIG1 register for PEC access retry number. */
ret = regmap_write(data->regmap, MAX6621_CONFIG1_REG,
MAX6621_CONFIG1_INIT); if (ret) return ret;
/* Sync registers with hardware. */
regcache_mark_dirty(data->regmap);
ret = regcache_sync(data->regmap); if (ret) return ret;
/* Verify which temperature input registers are enabled. */ for (i = 0; i < MAX6621_TEMP_INPUT_REG_NUM; i++) {
ret = i2c_smbus_read_word_data(client, max6621_temp_regs[i]); if (ret < 0) return ret;
ret = max6621_verify_reg_data(dev, ret); if (ret) {
data->input_chan2reg[i] = -1; continue;
}
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.