Commit b4ce237b authored by Guenter Roeck's avatar Guenter Roeck

hwmon: (pmbus) Introduce infrastructure to detect sensors and limit registers

This commit replaces hard-coded sensor and limit register detection code
with table based sensor detection. This change eliminates code block repetition
and reduces code size.
Signed-off-by: default avatarGuenter Roeck <guenter.roeck@ericsson.com>
Reviewed-by: default avatarTom Grennan <tom.grennan@ericsson.com>
parent f5bae264
...@@ -793,53 +793,6 @@ static void pmbus_add_label(struct pmbus_data *data, ...@@ -793,53 +793,6 @@ static void pmbus_add_label(struct pmbus_data *data,
data->num_labels++; data->num_labels++;
} }
static const int pmbus_temp_registers[] = {
PMBUS_READ_TEMPERATURE_1,
PMBUS_READ_TEMPERATURE_2,
PMBUS_READ_TEMPERATURE_3
};
static const int pmbus_temp_flags[] = {
PMBUS_HAVE_TEMP,
PMBUS_HAVE_TEMP2,
PMBUS_HAVE_TEMP3
};
static const int pmbus_fan_registers[] = {
PMBUS_READ_FAN_SPEED_1,
PMBUS_READ_FAN_SPEED_2,
PMBUS_READ_FAN_SPEED_3,
PMBUS_READ_FAN_SPEED_4
};
static const int pmbus_fan_config_registers[] = {
PMBUS_FAN_CONFIG_12,
PMBUS_FAN_CONFIG_12,
PMBUS_FAN_CONFIG_34,
PMBUS_FAN_CONFIG_34
};
static const int pmbus_fan_status_registers[] = {
PMBUS_STATUS_FAN_12,
PMBUS_STATUS_FAN_12,
PMBUS_STATUS_FAN_34,
PMBUS_STATUS_FAN_34
};
static const u32 pmbus_fan_flags[] = {
PMBUS_HAVE_FAN12,
PMBUS_HAVE_FAN12,
PMBUS_HAVE_FAN34,
PMBUS_HAVE_FAN34
};
static const u32 pmbus_fan_status_flags[] = {
PMBUS_HAVE_STATUS_FAN12,
PMBUS_HAVE_STATUS_FAN12,
PMBUS_HAVE_STATUS_FAN34,
PMBUS_HAVE_STATUS_FAN34
};
/* /*
* Determine maximum number of sensors, booleans, and labels. * Determine maximum number of sensors, booleans, and labels.
* To keep things simple, only make a rough high estimate. * To keep things simple, only make a rough high estimate.
...@@ -900,499 +853,431 @@ static void pmbus_find_max_attr(struct i2c_client *client, ...@@ -900,499 +853,431 @@ static void pmbus_find_max_attr(struct i2c_client *client,
/* /*
* Search for attributes. Allocate sensors, booleans, and labels as needed. * Search for attributes. Allocate sensors, booleans, and labels as needed.
*/ */
static void pmbus_find_attributes(struct i2c_client *client,
struct pmbus_data *data)
{
const struct pmbus_driver_info *info = data->info;
int page, i0, i1, in_index;
/* /*
* Input voltage sensors * The pmbus_limit_attr structure describes a single limit attribute
*/ * and its associated alarm attribute.
in_index = 1; */
if (info->func[0] & PMBUS_HAVE_VIN) { struct pmbus_limit_attr {
bool have_alarm = false; u8 reg; /* Limit register */
const char *attr; /* Attribute name */
i0 = data->num_sensors; const char *alarm; /* Alarm attribute name */
pmbus_add_label(data, "in", in_index, "vin", 0); u32 sbit; /* Alarm attribute status bit */
pmbus_add_sensor(data, "in", "input", in_index, 0, };
PMBUS_READ_VIN, PSC_VOLTAGE_IN, true, true);
if (pmbus_check_word_register(client, 0, /*
PMBUS_VIN_UV_WARN_LIMIT)) { * The pmbus_sensor_attr structure describes one sensor attribute. This
i1 = data->num_sensors; * description includes a reference to the associated limit attributes.
pmbus_add_sensor(data, "in", "min", in_index, */
0, PMBUS_VIN_UV_WARN_LIMIT, struct pmbus_sensor_attr {
PSC_VOLTAGE_IN, false, false); u8 reg; /* sensor register */
if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) { enum pmbus_sensor_classes class;/* sensor class */
pmbus_add_boolean_reg(data, "in", "min_alarm", const char *label; /* sensor label */
in_index, bool paged; /* true if paged sensor */
PB_STATUS_INPUT_BASE, bool update; /* true if update needed */
PB_VOLTAGE_UV_WARNING); bool compare; /* true if compare function needed */
have_alarm = true; u32 func; /* sensor mask */
} u32 sfunc; /* sensor status mask */
} int sbase; /* status base register */
if (pmbus_check_word_register(client, 0, u32 gbit; /* generic status bit */
PMBUS_VIN_UV_FAULT_LIMIT)) { const struct pmbus_limit_attr *limit;/* limit registers */
i1 = data->num_sensors; int nlimit; /* # of limit registers */
pmbus_add_sensor(data, "in", "lcrit", in_index, };
0, PMBUS_VIN_UV_FAULT_LIMIT,
PSC_VOLTAGE_IN, false, false); /*
if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) { * Add a set of limit attributes and, if supported, the associated
pmbus_add_boolean_reg(data, "in", "lcrit_alarm", * alarm attributes.
in_index, */
PB_STATUS_INPUT_BASE, static bool pmbus_add_limit_attrs(struct i2c_client *client,
PB_VOLTAGE_UV_FAULT); struct pmbus_data *data,
have_alarm = true; const struct pmbus_driver_info *info,
} const char *name, int index, int page,
} int cbase,
if (pmbus_check_word_register(client, 0, const struct pmbus_sensor_attr *attr)
PMBUS_VIN_OV_WARN_LIMIT)) { {
i1 = data->num_sensors; const struct pmbus_limit_attr *l = attr->limit;
pmbus_add_sensor(data, "in", "max", in_index, int nlimit = attr->nlimit;
0, PMBUS_VIN_OV_WARN_LIMIT, bool have_alarm = false;
PSC_VOLTAGE_IN, false, false); int i, cindex;
if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) {
pmbus_add_boolean_reg(data, "in", "max_alarm", for (i = 0; i < nlimit; i++) {
in_index, if (pmbus_check_word_register(client, page, l->reg)) {
PB_STATUS_INPUT_BASE, cindex = data->num_sensors;
PB_VOLTAGE_OV_WARNING); pmbus_add_sensor(data, name, l->attr, index, page,
have_alarm = true; l->reg, attr->class, attr->update,
} false);
} if (info->func[page] & attr->sfunc) {
if (pmbus_check_word_register(client, 0, if (attr->compare) {
PMBUS_VIN_OV_FAULT_LIMIT)) { pmbus_add_boolean_cmp(data, name,
i1 = data->num_sensors; l->alarm, index,
pmbus_add_sensor(data, "in", "crit", in_index, cbase, cindex,
0, PMBUS_VIN_OV_FAULT_LIMIT, attr->sbase + page, l->sbit);
PSC_VOLTAGE_IN, false, false); } else {
if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) { pmbus_add_boolean_reg(data, name,
pmbus_add_boolean_reg(data, "in", "crit_alarm", l->alarm, index,
in_index, attr->sbase + page, l->sbit);
PB_STATUS_INPUT_BASE, }
PB_VOLTAGE_OV_FAULT);
have_alarm = true; have_alarm = true;
} }
} }
/* l++;
* Add generic alarm attribute only if there are no individual
* attributes.
*/
if (!have_alarm)
pmbus_add_boolean_reg(data, "in", "alarm",
in_index,
PB_STATUS_BASE,
PB_STATUS_VIN_UV);
in_index++;
}
if (info->func[0] & PMBUS_HAVE_VCAP) {
pmbus_add_label(data, "in", in_index, "vcap", 0);
pmbus_add_sensor(data, "in", "input", in_index, 0,
PMBUS_READ_VCAP, PSC_VOLTAGE_IN, true, true);
in_index++;
} }
return have_alarm;
}
/* static void pmbus_add_sensor_attrs_one(struct i2c_client *client,
* Output voltage sensors struct pmbus_data *data,
*/ const struct pmbus_driver_info *info,
for (page = 0; page < info->pages; page++) { const char *name,
bool have_alarm = false; int index, int page,
const struct pmbus_sensor_attr *attr)
if (!(info->func[page] & PMBUS_HAVE_VOUT)) {
continue; bool have_alarm;
int cbase = data->num_sensors;
i0 = data->num_sensors;
pmbus_add_label(data, "in", in_index, "vout", page + 1); if (attr->label)
pmbus_add_sensor(data, "in", "input", in_index, page, pmbus_add_label(data, name, index, attr->label,
PMBUS_READ_VOUT, PSC_VOLTAGE_OUT, true, true); attr->paged ? page + 1 : 0);
if (pmbus_check_word_register(client, page, pmbus_add_sensor(data, name, "input", index, page, attr->reg,
PMBUS_VOUT_UV_WARN_LIMIT)) { attr->class, true, true);
i1 = data->num_sensors; if (attr->sfunc) {
pmbus_add_sensor(data, "in", "min", in_index, page, have_alarm = pmbus_add_limit_attrs(client, data, info, name,
PMBUS_VOUT_UV_WARN_LIMIT, index, page, cbase, attr);
PSC_VOLTAGE_OUT, false, false);
if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) {
pmbus_add_boolean_reg(data, "in", "min_alarm",
in_index,
PB_STATUS_VOUT_BASE +
page,
PB_VOLTAGE_UV_WARNING);
have_alarm = true;
}
}
if (pmbus_check_word_register(client, page,
PMBUS_VOUT_UV_FAULT_LIMIT)) {
i1 = data->num_sensors;
pmbus_add_sensor(data, "in", "lcrit", in_index, page,
PMBUS_VOUT_UV_FAULT_LIMIT,
PSC_VOLTAGE_OUT, false, false);
if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) {
pmbus_add_boolean_reg(data, "in", "lcrit_alarm",
in_index,
PB_STATUS_VOUT_BASE +
page,
PB_VOLTAGE_UV_FAULT);
have_alarm = true;
}
}
if (pmbus_check_word_register(client, page,
PMBUS_VOUT_OV_WARN_LIMIT)) {
i1 = data->num_sensors;
pmbus_add_sensor(data, "in", "max", in_index, page,
PMBUS_VOUT_OV_WARN_LIMIT,
PSC_VOLTAGE_OUT, false, false);
if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) {
pmbus_add_boolean_reg(data, "in", "max_alarm",
in_index,
PB_STATUS_VOUT_BASE +
page,
PB_VOLTAGE_OV_WARNING);
have_alarm = true;
}
}
if (pmbus_check_word_register(client, page,
PMBUS_VOUT_OV_FAULT_LIMIT)) {
i1 = data->num_sensors;
pmbus_add_sensor(data, "in", "crit", in_index, page,
PMBUS_VOUT_OV_FAULT_LIMIT,
PSC_VOLTAGE_OUT, false, false);
if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) {
pmbus_add_boolean_reg(data, "in", "crit_alarm",
in_index,
PB_STATUS_VOUT_BASE +
page,
PB_VOLTAGE_OV_FAULT);
have_alarm = true;
}
}
/* /*
* Add generic alarm attribute only if there are no individual * Add generic alarm attribute only if there are no individual
* attributes. * alarm attributes, and if there is a global alarm bit.
*/ */
if (!have_alarm) if (!have_alarm && attr->gbit)
pmbus_add_boolean_reg(data, "in", "alarm", pmbus_add_boolean_reg(data, name, "alarm", index,
in_index,
PB_STATUS_BASE + page, PB_STATUS_BASE + page,
PB_STATUS_VOUT_OV); attr->gbit);
in_index++;
} }
}
/* static void pmbus_add_sensor_attrs(struct i2c_client *client,
* Current sensors struct pmbus_data *data,
*/ const char *name,
const struct pmbus_sensor_attr *attrs,
int nattrs)
{
const struct pmbus_driver_info *info = data->info;
int index, i;
/* index = 1;
* Input current sensors for (i = 0; i < nattrs; i++) {
*/ int page, pages;
in_index = 1;
if (info->func[0] & PMBUS_HAVE_IIN) { pages = attrs->paged ? info->pages : 1;
i0 = data->num_sensors; for (page = 0; page < pages; page++) {
pmbus_add_label(data, "curr", in_index, "iin", 0); if (!(info->func[page] & attrs->func))
pmbus_add_sensor(data, "curr", "input", in_index, 0, continue;
PMBUS_READ_IIN, PSC_CURRENT_IN, true, true); pmbus_add_sensor_attrs_one(client, data, info, name,
if (pmbus_check_word_register(client, 0, index, page, attrs);
PMBUS_IIN_OC_WARN_LIMIT)) { index++;
i1 = data->num_sensors;
pmbus_add_sensor(data, "curr", "max", in_index,
0, PMBUS_IIN_OC_WARN_LIMIT,
PSC_CURRENT_IN, false, false);
if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) {
pmbus_add_boolean_reg(data, "curr", "max_alarm",
in_index,
PB_STATUS_INPUT_BASE,
PB_IIN_OC_WARNING);
}
}
if (pmbus_check_word_register(client, 0,
PMBUS_IIN_OC_FAULT_LIMIT)) {
i1 = data->num_sensors;
pmbus_add_sensor(data, "curr", "crit", in_index,
0, PMBUS_IIN_OC_FAULT_LIMIT,
PSC_CURRENT_IN, false, false);
if (info->func[0] & PMBUS_HAVE_STATUS_INPUT)
pmbus_add_boolean_reg(data, "curr",
"crit_alarm",
in_index,
PB_STATUS_INPUT_BASE,
PB_IIN_OC_FAULT);
} }
in_index++; attrs++;
} }
}
/* static const struct pmbus_limit_attr vin_limit_attrs[] = {
* Output current sensors {
*/ .reg = PMBUS_VIN_UV_WARN_LIMIT,
for (page = 0; page < info->pages; page++) { .attr = "min",
bool have_alarm = false; .alarm = "min_alarm",
.sbit = PB_VOLTAGE_UV_WARNING,
if (!(info->func[page] & PMBUS_HAVE_IOUT)) }, {
continue; .reg = PMBUS_VIN_UV_FAULT_LIMIT,
.attr = "lcrit",
i0 = data->num_sensors; .alarm = "lcrit_alarm",
pmbus_add_label(data, "curr", in_index, "iout", page + 1); .sbit = PB_VOLTAGE_UV_FAULT,
pmbus_add_sensor(data, "curr", "input", in_index, page, }, {
PMBUS_READ_IOUT, PSC_CURRENT_OUT, true, true); .reg = PMBUS_VIN_OV_WARN_LIMIT,
if (pmbus_check_word_register(client, page, .attr = "max",
PMBUS_IOUT_OC_WARN_LIMIT)) { .alarm = "max_alarm",
i1 = data->num_sensors; .sbit = PB_VOLTAGE_OV_WARNING,
pmbus_add_sensor(data, "curr", "max", in_index, page, }, {
PMBUS_IOUT_OC_WARN_LIMIT, .reg = PMBUS_VIN_OV_FAULT_LIMIT,
PSC_CURRENT_OUT, false, false); .attr = "crit",
if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) { .alarm = "crit_alarm",
pmbus_add_boolean_reg(data, "curr", "max_alarm", .sbit = PB_VOLTAGE_OV_FAULT,
in_index, },
PB_STATUS_IOUT_BASE + };
page, PB_IOUT_OC_WARNING);
have_alarm = true; static const struct pmbus_limit_attr vout_limit_attrs[] = {
} {
} .reg = PMBUS_VOUT_UV_WARN_LIMIT,
if (pmbus_check_word_register(client, page, .attr = "min",
PMBUS_IOUT_UC_FAULT_LIMIT)) { .alarm = "min_alarm",
i1 = data->num_sensors; .sbit = PB_VOLTAGE_UV_WARNING,
pmbus_add_sensor(data, "curr", "lcrit", in_index, page, }, {
PMBUS_IOUT_UC_FAULT_LIMIT, .reg = PMBUS_VOUT_UV_FAULT_LIMIT,
PSC_CURRENT_OUT, false, false); .attr = "lcrit",
if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) { .alarm = "lcrit_alarm",
pmbus_add_boolean_reg(data, "curr", .sbit = PB_VOLTAGE_UV_FAULT,
"lcrit_alarm", }, {
in_index, .reg = PMBUS_VOUT_OV_WARN_LIMIT,
PB_STATUS_IOUT_BASE + .attr = "max",
page, PB_IOUT_UC_FAULT); .alarm = "max_alarm",
have_alarm = true; .sbit = PB_VOLTAGE_OV_WARNING,
} }, {
} .reg = PMBUS_VOUT_OV_FAULT_LIMIT,
if (pmbus_check_word_register(client, page, .attr = "crit",
PMBUS_IOUT_OC_FAULT_LIMIT)) { .alarm = "crit_alarm",
i1 = data->num_sensors; .sbit = PB_VOLTAGE_OV_FAULT,
pmbus_add_sensor(data, "curr", "crit", in_index, page,
PMBUS_IOUT_OC_FAULT_LIMIT,
PSC_CURRENT_OUT, false, false);
if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) {
pmbus_add_boolean_reg(data, "curr",
"crit_alarm",
in_index,
PB_STATUS_IOUT_BASE +
page, PB_IOUT_OC_FAULT);
have_alarm = true;
}
}
/*
* Add generic alarm attribute only if there are no individual
* attributes.
*/
if (!have_alarm)
pmbus_add_boolean_reg(data, "curr", "alarm",
in_index,
PB_STATUS_BASE + page,
PB_STATUS_IOUT_OC);
in_index++;
} }
};
/* static const struct pmbus_sensor_attr voltage_attributes[] = {
* Power sensors {
*/ .reg = PMBUS_READ_VIN,
/* .class = PSC_VOLTAGE_IN,
* Input Power sensors .label = "vin",
*/ .func = PMBUS_HAVE_VIN,
in_index = 1; .sfunc = PMBUS_HAVE_STATUS_INPUT,
if (info->func[0] & PMBUS_HAVE_PIN) { .sbase = PB_STATUS_INPUT_BASE,
i0 = data->num_sensors; .gbit = PB_STATUS_VIN_UV,
pmbus_add_label(data, "power", in_index, "pin", 0); .limit = vin_limit_attrs,
pmbus_add_sensor(data, "power", "input", in_index, .nlimit = ARRAY_SIZE(vin_limit_attrs),
0, PMBUS_READ_PIN, PSC_POWER, true, true); }, {
if (pmbus_check_word_register(client, 0, .reg = PMBUS_READ_VCAP,
PMBUS_PIN_OP_WARN_LIMIT)) { .class = PSC_VOLTAGE_IN,
i1 = data->num_sensors; .label = "vcap",
pmbus_add_sensor(data, "power", "max", in_index, .func = PMBUS_HAVE_VCAP,
0, PMBUS_PIN_OP_WARN_LIMIT, PSC_POWER, }, {
false, false); .reg = PMBUS_READ_VOUT,
if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) .class = PSC_VOLTAGE_OUT,
pmbus_add_boolean_reg(data, "power", .label = "vout",
"alarm", .paged = true,
in_index, .func = PMBUS_HAVE_VOUT,
PB_STATUS_INPUT_BASE, .sfunc = PMBUS_HAVE_STATUS_VOUT,
PB_PIN_OP_WARNING); .sbase = PB_STATUS_VOUT_BASE,
} .gbit = PB_STATUS_VOUT_OV,
in_index++; .limit = vout_limit_attrs,
.nlimit = ARRAY_SIZE(vout_limit_attrs),
} }
};
/* /* Current attributes */
* Output Power sensors
*/ static const struct pmbus_limit_attr iin_limit_attrs[] = {
for (page = 0; page < info->pages; page++) { {
bool need_alarm = false; .reg = PMBUS_IIN_OC_WARN_LIMIT,
.attr = "max",
.alarm = "max_alarm",
.sbit = PB_IIN_OC_WARNING,
}, {
.reg = PMBUS_IIN_OC_FAULT_LIMIT,
.attr = "crit",
.alarm = "crit_alarm",
.sbit = PB_IIN_OC_FAULT,
}
};
if (!(info->func[page] & PMBUS_HAVE_POUT)) static const struct pmbus_limit_attr iout_limit_attrs[] = {
continue; {
.reg = PMBUS_IOUT_OC_WARN_LIMIT,
.attr = "max",
.alarm = "max_alarm",
.sbit = PB_IOUT_OC_WARNING,
}, {
.reg = PMBUS_IOUT_UC_FAULT_LIMIT,
.attr = "lcrit",
.alarm = "lcrit_alarm",
.sbit = PB_IOUT_UC_FAULT,
}, {
.reg = PMBUS_IOUT_OC_FAULT_LIMIT,
.attr = "crit",
.alarm = "crit_alarm",
.sbit = PB_IOUT_OC_FAULT,
}
};
i0 = data->num_sensors; static const struct pmbus_sensor_attr current_attributes[] = {
pmbus_add_label(data, "power", in_index, "pout", page + 1); {
pmbus_add_sensor(data, "power", "input", in_index, page, .reg = PMBUS_READ_IIN,
PMBUS_READ_POUT, PSC_POWER, true, true); .class = PSC_CURRENT_IN,
/* .label = "iin",
* Per hwmon sysfs API, power_cap is to be used to limit output .func = PMBUS_HAVE_IIN,
* power. .sfunc = PMBUS_HAVE_STATUS_INPUT,
* We have two registers related to maximum output power, .sbase = PB_STATUS_INPUT_BASE,
* PMBUS_POUT_MAX and PMBUS_POUT_OP_WARN_LIMIT. .limit = iin_limit_attrs,
* PMBUS_POUT_MAX matches the powerX_cap attribute definition. .nlimit = ARRAY_SIZE(iin_limit_attrs),
* There is no attribute in the API to match }, {
* PMBUS_POUT_OP_WARN_LIMIT. We use powerX_max for now. .reg = PMBUS_READ_IOUT,
*/ .class = PSC_CURRENT_OUT,
if (pmbus_check_word_register(client, page, PMBUS_POUT_MAX)) { .label = "iout",
i1 = data->num_sensors; .paged = true,
pmbus_add_sensor(data, "power", "cap", in_index, page, .func = PMBUS_HAVE_IOUT,
PMBUS_POUT_MAX, PSC_POWER, .sfunc = PMBUS_HAVE_STATUS_IOUT,
false, false); .sbase = PB_STATUS_IOUT_BASE,
need_alarm = true; .gbit = PB_STATUS_IOUT_OC,
} .limit = iout_limit_attrs,
if (pmbus_check_word_register(client, page, .nlimit = ARRAY_SIZE(iout_limit_attrs),
PMBUS_POUT_OP_WARN_LIMIT)) {
i1 = data->num_sensors;
pmbus_add_sensor(data, "power", "max", in_index, page,
PMBUS_POUT_OP_WARN_LIMIT, PSC_POWER,
false, false);
need_alarm = true;
}
if (need_alarm && (info->func[page] & PMBUS_HAVE_STATUS_IOUT))
pmbus_add_boolean_reg(data, "power", "alarm",
in_index,
PB_STATUS_IOUT_BASE + page,
PB_POUT_OP_WARNING
| PB_POWER_LIMITING);
if (pmbus_check_word_register(client, page,
PMBUS_POUT_OP_FAULT_LIMIT)) {
i1 = data->num_sensors;
pmbus_add_sensor(data, "power", "crit", in_index, page,
PMBUS_POUT_OP_FAULT_LIMIT, PSC_POWER,
false, false);
if (info->func[page] & PMBUS_HAVE_STATUS_IOUT)
pmbus_add_boolean_reg(data, "power",
"crit_alarm",
in_index,
PB_STATUS_IOUT_BASE
+ page,
PB_POUT_OP_FAULT);
}
in_index++;
} }
};
/* /* Power attributes */
* Temperature sensors
*/
in_index = 1;
for (page = 0; page < info->pages; page++) {
int t;
for (t = 0; t < ARRAY_SIZE(pmbus_temp_registers); t++) { static const struct pmbus_limit_attr pin_limit_attrs[] = {
bool have_alarm = false; {
.reg = PMBUS_PIN_OP_WARN_LIMIT,
.attr = "max",
.alarm = "alarm",
.sbit = PB_PIN_OP_WARNING,
}
};
/* static const struct pmbus_limit_attr pout_limit_attrs[] = {
* A PMBus chip may support any combination of {
* temperature registers on any page. So we can not .reg = PMBUS_POUT_MAX,
* abort after a failure to detect a register, but have .attr = "cap",
* to continue checking for all registers on all pages. .alarm = "cap_alarm",
*/ .sbit = PB_POWER_LIMITING,
if (!(info->func[page] & pmbus_temp_flags[t])) }, {
continue; .reg = PMBUS_POUT_OP_WARN_LIMIT,
.attr = "max",
.alarm = "max_alarm",
.sbit = PB_POUT_OP_WARNING,
}, {
.reg = PMBUS_POUT_OP_FAULT_LIMIT,
.attr = "crit",
.alarm = "crit_alarm",
.sbit = PB_POUT_OP_FAULT,
}
};
if (!pmbus_check_word_register static const struct pmbus_sensor_attr power_attributes[] = {
(client, page, pmbus_temp_registers[t])) {
continue; .reg = PMBUS_READ_PIN,
.class = PSC_POWER,
.label = "pin",
.func = PMBUS_HAVE_PIN,
.sfunc = PMBUS_HAVE_STATUS_INPUT,
.sbase = PB_STATUS_INPUT_BASE,
.limit = pin_limit_attrs,
.nlimit = ARRAY_SIZE(pin_limit_attrs),
}, {
.reg = PMBUS_READ_POUT,
.class = PSC_POWER,
.label = "pout",
.paged = true,
.func = PMBUS_HAVE_POUT,
.sfunc = PMBUS_HAVE_STATUS_IOUT,
.sbase = PB_STATUS_IOUT_BASE,
.limit = pout_limit_attrs,
.nlimit = ARRAY_SIZE(pout_limit_attrs),
}
};
i0 = data->num_sensors; /* Temperature atributes */
pmbus_add_sensor(data, "temp", "input", in_index, page,
pmbus_temp_registers[t], static const struct pmbus_limit_attr temp_limit_attrs[] = {
PSC_TEMPERATURE, true, true); {
.reg = PMBUS_UT_WARN_LIMIT,
.attr = "min",
.alarm = "min_alarm",
.sbit = PB_TEMP_UT_WARNING,
}, {
.reg = PMBUS_UT_FAULT_LIMIT,
.attr = "lcrit",
.alarm = "lcrit_alarm",
.sbit = PB_TEMP_UT_FAULT,
}, {
.reg = PMBUS_OT_WARN_LIMIT,
.attr = "max",
.alarm = "max_alarm",
.sbit = PB_TEMP_OT_WARNING,
}, {
.reg = PMBUS_OT_FAULT_LIMIT,
.attr = "crit",
.alarm = "crit_alarm",
.sbit = PB_TEMP_OT_FAULT,
}
};
/* static const struct pmbus_sensor_attr temp_attributes[] = {
* PMBus provides only one status register for TEMP1-3. {
* Thus, we can not use the status register to determine .reg = PMBUS_READ_TEMPERATURE_1,
* which of the three sensors actually caused an alarm. .class = PSC_TEMPERATURE,
* Always compare current temperature against the limit .paged = true,
* registers to determine alarm conditions for a .update = true,
* specific sensor. .compare = true,
* .func = PMBUS_HAVE_TEMP,
* Since there is only one set of limit registers for .sfunc = PMBUS_HAVE_STATUS_TEMP,
* up to three temperature sensors, we need to update .sbase = PB_STATUS_TEMP_BASE,
* all limit registers after the limit was changed for .gbit = PB_STATUS_TEMPERATURE,
* one of the sensors. This ensures that correct limits .limit = temp_limit_attrs,
* are reported for all temperature sensors. .nlimit = ARRAY_SIZE(temp_limit_attrs),
*/ }, {
if (pmbus_check_word_register .reg = PMBUS_READ_TEMPERATURE_2,
(client, page, PMBUS_UT_WARN_LIMIT)) { .class = PSC_TEMPERATURE,
i1 = data->num_sensors; .paged = true,
pmbus_add_sensor(data, "temp", "min", in_index, .update = true,
page, PMBUS_UT_WARN_LIMIT, .compare = true,
PSC_TEMPERATURE, true, false); .func = PMBUS_HAVE_TEMP2,
if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) { .sfunc = PMBUS_HAVE_STATUS_TEMP,
pmbus_add_boolean_cmp(data, "temp", .sbase = PB_STATUS_TEMP_BASE,
"min_alarm", in_index, i1, i0, .gbit = PB_STATUS_TEMPERATURE,
PB_STATUS_TEMP_BASE + page, .limit = temp_limit_attrs,
PB_TEMP_UT_WARNING); .nlimit = ARRAY_SIZE(temp_limit_attrs),
have_alarm = true; }, {
} .reg = PMBUS_READ_TEMPERATURE_3,
} .class = PSC_TEMPERATURE,
if (pmbus_check_word_register(client, page, .paged = true,
PMBUS_UT_FAULT_LIMIT)) { .update = true,
i1 = data->num_sensors; .compare = true,
pmbus_add_sensor(data, "temp", "lcrit", .func = PMBUS_HAVE_TEMP3,
in_index, page, .sfunc = PMBUS_HAVE_STATUS_TEMP,
PMBUS_UT_FAULT_LIMIT, .sbase = PB_STATUS_TEMP_BASE,
PSC_TEMPERATURE, true, false); .gbit = PB_STATUS_TEMPERATURE,
if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) { .limit = temp_limit_attrs,
pmbus_add_boolean_cmp(data, "temp", .nlimit = ARRAY_SIZE(temp_limit_attrs),
"lcrit_alarm", in_index, i1, i0,
PB_STATUS_TEMP_BASE + page,
PB_TEMP_UT_FAULT);
have_alarm = true;
}
}
if (pmbus_check_word_register
(client, page, PMBUS_OT_WARN_LIMIT)) {
i1 = data->num_sensors;
pmbus_add_sensor(data, "temp", "max", in_index,
page, PMBUS_OT_WARN_LIMIT,
PSC_TEMPERATURE, true, false);
if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) {
pmbus_add_boolean_cmp(data, "temp",
"max_alarm", in_index, i0, i1,
PB_STATUS_TEMP_BASE + page,
PB_TEMP_OT_WARNING);
have_alarm = true;
}
}
if (pmbus_check_word_register(client, page,
PMBUS_OT_FAULT_LIMIT)) {
i1 = data->num_sensors;
pmbus_add_sensor(data, "temp", "crit", in_index,
page, PMBUS_OT_FAULT_LIMIT,
PSC_TEMPERATURE, true, false);
if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) {
pmbus_add_boolean_cmp(data, "temp",
"crit_alarm", in_index, i0, i1,
PB_STATUS_TEMP_BASE + page,
PB_TEMP_OT_FAULT);
have_alarm = true;
}
}
/*
* Last resort - we were not able to create any alarm
* registers. Report alarm for all sensors using the
* status register temperature alarm bit.
*/
if (!have_alarm)
pmbus_add_boolean_reg(data, "temp", "alarm",
in_index,
PB_STATUS_BASE + page,
PB_STATUS_TEMPERATURE);
in_index++;
}
} }
};
static const int pmbus_fan_registers[] = {
PMBUS_READ_FAN_SPEED_1,
PMBUS_READ_FAN_SPEED_2,
PMBUS_READ_FAN_SPEED_3,
PMBUS_READ_FAN_SPEED_4
};
static const int pmbus_fan_config_registers[] = {
PMBUS_FAN_CONFIG_12,
PMBUS_FAN_CONFIG_12,
PMBUS_FAN_CONFIG_34,
PMBUS_FAN_CONFIG_34
};
static const int pmbus_fan_status_registers[] = {
PMBUS_STATUS_FAN_12,
PMBUS_STATUS_FAN_12,
PMBUS_STATUS_FAN_34,
PMBUS_STATUS_FAN_34
};
static const u32 pmbus_fan_flags[] = {
PMBUS_HAVE_FAN12,
PMBUS_HAVE_FAN12,
PMBUS_HAVE_FAN34,
PMBUS_HAVE_FAN34
};
static const u32 pmbus_fan_status_flags[] = {
PMBUS_HAVE_STATUS_FAN12,
PMBUS_HAVE_STATUS_FAN12,
PMBUS_HAVE_STATUS_FAN34,
PMBUS_HAVE_STATUS_FAN34
};
/* Fans */
static void pmbus_add_fan_attributes(struct i2c_client *client,
struct pmbus_data *data)
{
const struct pmbus_driver_info *info = data->info;
int index = 1;
int page;
/*
* Fans
*/
in_index = 1;
for (page = 0; page < info->pages; page++) { for (page = 0; page < info->pages; page++) {
int f; int f;
...@@ -1419,8 +1304,7 @@ static void pmbus_find_attributes(struct i2c_client *client, ...@@ -1419,8 +1304,7 @@ static void pmbus_find_attributes(struct i2c_client *client,
(!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4))))) (!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4)))))
continue; continue;
i0 = data->num_sensors; pmbus_add_sensor(data, "fan", "input", index, page,
pmbus_add_sensor(data, "fan", "input", in_index, page,
pmbus_fan_registers[f], PSC_FAN, true, pmbus_fan_registers[f], PSC_FAN, true,
true); true);
...@@ -1438,17 +1322,40 @@ static void pmbus_find_attributes(struct i2c_client *client, ...@@ -1438,17 +1322,40 @@ static void pmbus_find_attributes(struct i2c_client *client,
else else
base = PB_STATUS_FAN_BASE + page; base = PB_STATUS_FAN_BASE + page;
pmbus_add_boolean_reg(data, "fan", "alarm", pmbus_add_boolean_reg(data, "fan", "alarm",
in_index, base, index, base,
PB_FAN_FAN1_WARNING >> (f & 1)); PB_FAN_FAN1_WARNING >> (f & 1));
pmbus_add_boolean_reg(data, "fan", "fault", pmbus_add_boolean_reg(data, "fan", "fault",
in_index, base, index, base,
PB_FAN_FAN1_FAULT >> (f & 1)); PB_FAN_FAN1_FAULT >> (f & 1));
} }
in_index++; index++;
} }
} }
} }
static void pmbus_find_attributes(struct i2c_client *client,
struct pmbus_data *data)
{
/* Voltage sensors */
pmbus_add_sensor_attrs(client, data, "in", voltage_attributes,
ARRAY_SIZE(voltage_attributes));
/* Current sensors */
pmbus_add_sensor_attrs(client, data, "curr", current_attributes,
ARRAY_SIZE(current_attributes));
/* Power sensors */
pmbus_add_sensor_attrs(client, data, "power", power_attributes,
ARRAY_SIZE(power_attributes));
/* Temperature sensors */
pmbus_add_sensor_attrs(client, data, "temp", temp_attributes,
ARRAY_SIZE(temp_attributes));
/* Fans */
pmbus_add_fan_attributes(client, data);
}
/* /*
* Identify chip parameters. * Identify chip parameters.
* This function is called for all chips. * This function is called for all chips.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment