struct pmbus_label {
char name[PMBUS_NAME_SIZE]; /* sysfs label name */
- struct sensor_device_attribute attribute;
+ struct device_attribute attribute;
char label[PMBUS_NAME_SIZE]; /* label */
};
+#define to_pmbus_label(_attr) \
+ container_of(_attr, struct pmbus_label, attribute)
struct pmbus_data {
+ struct device *dev;
struct device *hwmon_dev;
u32 flags; /* from platform data */
int max_sensors;
int num_sensors;
struct pmbus_sensor *sensors;
- /*
- * Booleans are used for alarms.
- * Values are determined from status registers.
- */
- int max_booleans;
- int num_booleans;
- struct pmbus_boolean *booleans;
- /*
- * Labels are used to map generic names (e.g., "in1")
- * to PMBus specific names (e.g., "vin" or "vout1").
- */
- int max_labels;
- int num_labels;
- struct pmbus_label *labels;
struct mutex update_lock;
bool valid;
static ssize_t pmbus_show_label(struct device *dev,
struct device_attribute *da, char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct pmbus_data *data = i2c_get_clientdata(client);
- struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct pmbus_label *label = to_pmbus_label(da);
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", label->label);
+}
- return snprintf(buf, PAGE_SIZE, "%s\n",
- data->labels[attr->index].label);
+static void pmbus_dev_attr_init(struct device_attribute *dev_attr,
+ const char *name,
+ umode_t mode,
+ ssize_t (*show)(struct device *dev,
+ struct device_attribute *attr,
+ char *buf),
+ ssize_t (*store)(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count))
+{
+ sysfs_attr_init(&dev_attr->attr);
+ dev_attr->attr.name = name;
+ dev_attr->attr.mode = mode;
+ dev_attr->show = show;
+ dev_attr->store = store;
}
static void pmbus_attr_init(struct sensor_device_attribute *a,
const char *buf, size_t count),
int idx)
{
- sysfs_attr_init(&a->dev_attr.attr);
- a->dev_attr.attr.name = name;
- a->dev_attr.attr.mode = mode;
- a->dev_attr.show = show;
- a->dev_attr.store = store;
+ pmbus_dev_attr_init(&a->dev_attr, name, mode, show, store);
a->index = idx;
}
-static void pmbus_add_boolean(struct pmbus_data *data,
- const char *name, const char *type, int seq,
- int idx)
+static int pmbus_add_boolean(struct pmbus_data *data,
+ const char *name, const char *type, int seq,
+ int idx)
{
struct pmbus_boolean *boolean;
struct sensor_device_attribute *a;
- BUG_ON(data->num_booleans >= data->max_booleans ||
- data->num_attributes >= data->max_attributes);
+ BUG_ON(data->num_attributes >= data->max_attributes);
+
+ boolean = devm_kzalloc(data->dev, sizeof(*boolean), GFP_KERNEL);
+ if (!boolean)
+ return -ENOMEM;
- boolean = &data->booleans[data->num_booleans];
a = &boolean->attribute;
snprintf(boolean->name, sizeof(boolean->name), "%s%d_%s",
pmbus_attr_init(a, boolean->name, S_IRUGO, pmbus_show_boolean, NULL,
idx);
data->attributes[data->num_attributes++] = &a->dev_attr.attr;
- data->num_booleans++;
+
+ return 0;
}
-static void pmbus_add_boolean_reg(struct pmbus_data *data,
- const char *name, const char *type,
- int seq, int reg, int bit)
+static int pmbus_add_boolean_reg(struct pmbus_data *data,
+ const char *name, const char *type,
+ int seq, int reg, int bit)
{
- pmbus_add_boolean(data, name, type, seq, (reg << 8) | bit);
+ return pmbus_add_boolean(data, name, type, seq, (reg << 8) | bit);
}
-static void pmbus_add_boolean_cmp(struct pmbus_data *data,
- const char *name, const char *type,
- int seq, int i1, int i2, int reg, int mask)
+static int pmbus_add_boolean_cmp(struct pmbus_data *data,
+ const char *name, const char *type,
+ int seq, int i1, int i2, int reg, int mask)
{
- pmbus_add_boolean(data, name, type, seq,
- (i1 << 24) | (i2 << 16) | (reg << 8) | mask);
+ return pmbus_add_boolean(data, name, type, seq,
+ (i1 << 24) | (i2 << 16) | (reg << 8) | mask);
}
static void pmbus_add_sensor(struct pmbus_data *data,
data->num_sensors++;
}
-static void pmbus_add_label(struct pmbus_data *data,
- const char *name, int seq,
- const char *lstring, int index)
+static int pmbus_add_label(struct pmbus_data *data,
+ const char *name, int seq,
+ const char *lstring, int index)
{
struct pmbus_label *label;
- struct sensor_device_attribute *a;
+ struct device_attribute *a;
- BUG_ON(data->num_labels >= data->max_labels ||
- data->num_attributes >= data->max_attributes);
+ BUG_ON(data->num_attributes >= data->max_attributes);
+
+ label = devm_kzalloc(data->dev, sizeof(*label), GFP_KERNEL);
+ if (!label)
+ return -ENOMEM;
- label = &data->labels[data->num_labels];
a = &label->attribute;
snprintf(label->name, sizeof(label->name), "%s%d_label", name, seq);
snprintf(label->label, sizeof(label->label), "%s%d", lstring,
index);
- pmbus_attr_init(a, label->name, S_IRUGO, pmbus_show_label, NULL,
- data->num_labels);
- data->attributes[data->num_attributes++] = &a->dev_attr.attr;
- data->num_labels++;
+ pmbus_dev_attr_init(a, label->name, S_IRUGO, pmbus_show_label, NULL);
+ data->attributes[data->num_attributes++] = &a->attr;
+ return 0;
}
/*
}
}
data->max_sensors = max_sensors;
- data->max_booleans = max_booleans;
- data->max_labels = max_labels;
data->max_attributes = max_sensors + max_booleans + max_labels;
}
/*
* Add a set of limit attributes and, if supported, the associated
* alarm attributes.
+ * returns 0 if no alarm register found, 1 if an alarm register was found,
+ * < 0 on errors.
*/
-static bool pmbus_add_limit_attrs(struct i2c_client *client,
- struct pmbus_data *data,
- const struct pmbus_driver_info *info,
- const char *name, int index, int page,
- int cbase,
- const struct pmbus_sensor_attr *attr)
+static int pmbus_add_limit_attrs(struct i2c_client *client,
+ struct pmbus_data *data,
+ const struct pmbus_driver_info *info,
+ const char *name, int index, int page,
+ int cbase,
+ const struct pmbus_sensor_attr *attr)
{
const struct pmbus_limit_attr *l = attr->limit;
int nlimit = attr->nlimit;
- bool have_alarm = false;
+ int have_alarm = 0;
int i, cindex;
+ int ret;
for (i = 0; i < nlimit; i++) {
if (pmbus_check_word_register(client, page, l->reg)) {
false);
if (l->sbit && (info->func[page] & attr->sfunc)) {
if (attr->compare) {
- pmbus_add_boolean_cmp(data, name,
+ ret = pmbus_add_boolean_cmp(data, name,
l->alarm, index,
l->low ? cindex : cbase,
l->low ? cbase : cindex,
attr->sbase + page, l->sbit);
+ if (ret)
+ return ret;
} else {
- pmbus_add_boolean_reg(data, name,
+ ret = pmbus_add_boolean_reg(data, name,
l->alarm, index,
attr->sbase + page, l->sbit);
+ if (ret)
+ return ret;
}
- have_alarm = true;
+ have_alarm = 1;
}
}
l++;
return have_alarm;
}
-static void pmbus_add_sensor_attrs_one(struct i2c_client *client,
- struct pmbus_data *data,
- const struct pmbus_driver_info *info,
- const char *name,
- int index, int page,
- const struct pmbus_sensor_attr *attr)
+static int pmbus_add_sensor_attrs_one(struct i2c_client *client,
+ struct pmbus_data *data,
+ const struct pmbus_driver_info *info,
+ const char *name,
+ int index, int page,
+ const struct pmbus_sensor_attr *attr)
{
- bool have_alarm;
int cbase = data->num_sensors;
+ int ret;
- if (attr->label)
- pmbus_add_label(data, name, index, attr->label,
- attr->paged ? page + 1 : 0);
+ if (attr->label) {
+ ret = pmbus_add_label(data, name, index, attr->label,
+ attr->paged ? page + 1 : 0);
+ if (ret)
+ return ret;
+ }
pmbus_add_sensor(data, name, "input", index, page, attr->reg,
attr->class, true, true);
if (attr->sfunc) {
- have_alarm = pmbus_add_limit_attrs(client, data, info, name,
- index, page, cbase, attr);
+ ret = pmbus_add_limit_attrs(client, data, info, name,
+ index, page, cbase, attr);
+ if (ret < 0)
+ return ret;
/*
* Add generic alarm attribute only if there are no individual
* alarm attributes, if there is a global alarm bit, and if
* the generic status register for this page is accessible.
*/
- if (!have_alarm && attr->gbit &&
- pmbus_check_byte_register(client, page, PMBUS_STATUS_BYTE))
- pmbus_add_boolean_reg(data, name, "alarm", index,
- PB_STATUS_BASE + page,
- attr->gbit);
+ if (!ret && attr->gbit &&
+ pmbus_check_byte_register(client, page,
+ PMBUS_STATUS_BYTE)) {
+ ret = pmbus_add_boolean_reg(data, name, "alarm", index,
+ PB_STATUS_BASE + page,
+ attr->gbit);
+ if (ret)
+ return ret;
+ }
}
+ return 0;
}
-static void pmbus_add_sensor_attrs(struct i2c_client *client,
- struct pmbus_data *data,
- const char *name,
- const struct pmbus_sensor_attr *attrs,
- int nattrs)
+static int pmbus_add_sensor_attrs(struct i2c_client *client,
+ 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;
+ int ret;
index = 1;
for (i = 0; i < nattrs; i++) {
for (page = 0; page < pages; page++) {
if (!(info->func[page] & attrs->func))
continue;
- pmbus_add_sensor_attrs_one(client, data, info, name,
- index, page, attrs);
+ ret = pmbus_add_sensor_attrs_one(client, data, info,
+ name, index, page,
+ attrs);
+ if (ret)
+ return ret;
index++;
}
attrs++;
}
+ return 0;
}
static const struct pmbus_limit_attr vin_limit_attrs[] = {
};
/* Fans */
-static void pmbus_add_fan_attributes(struct i2c_client *client,
- struct pmbus_data *data)
+static int 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;
+ int ret;
for (page = 0; page < info->pages; page++) {
int f;
base = PB_STATUS_FAN34_BASE + page;
else
base = PB_STATUS_FAN_BASE + page;
- pmbus_add_boolean_reg(data, "fan", "alarm",
- index, base,
+ ret = pmbus_add_boolean_reg(data, "fan",
+ "alarm", index, base,
PB_FAN_FAN1_WARNING >> (f & 1));
- pmbus_add_boolean_reg(data, "fan", "fault",
- index, base,
+ if (ret)
+ return ret;
+ ret = pmbus_add_boolean_reg(data, "fan",
+ "fault", index, base,
PB_FAN_FAN1_FAULT >> (f & 1));
+ if (ret)
+ return ret;
}
index++;
}
}
+ return 0;
}
-static void pmbus_find_attributes(struct i2c_client *client,
- struct pmbus_data *data)
+static int pmbus_find_attributes(struct i2c_client *client,
+ struct pmbus_data *data)
{
+ int ret;
+
/* Voltage sensors */
- pmbus_add_sensor_attrs(client, data, "in", voltage_attributes,
- ARRAY_SIZE(voltage_attributes));
+ ret = pmbus_add_sensor_attrs(client, data, "in", voltage_attributes,
+ ARRAY_SIZE(voltage_attributes));
+ if (ret)
+ return ret;
/* Current sensors */
- pmbus_add_sensor_attrs(client, data, "curr", current_attributes,
- ARRAY_SIZE(current_attributes));
+ ret = pmbus_add_sensor_attrs(client, data, "curr", current_attributes,
+ ARRAY_SIZE(current_attributes));
+ if (ret)
+ return ret;
/* Power sensors */
- pmbus_add_sensor_attrs(client, data, "power", power_attributes,
- ARRAY_SIZE(power_attributes));
+ ret = pmbus_add_sensor_attrs(client, data, "power", power_attributes,
+ ARRAY_SIZE(power_attributes));
+ if (ret)
+ return ret;
/* Temperature sensors */
- pmbus_add_sensor_attrs(client, data, "temp", temp_attributes,
- ARRAY_SIZE(temp_attributes));
+ ret = pmbus_add_sensor_attrs(client, data, "temp", temp_attributes,
+ ARRAY_SIZE(temp_attributes));
+ if (ret)
+ return ret;
/* Fans */
- pmbus_add_fan_attributes(client, data);
+ ret = pmbus_add_fan_attributes(client, data);
+ return ret;
}
/*
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
+ data->dev = dev;
/* Bail out if PMBus status register does not exist. */
if (i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE) < 0) {
if (!data->sensors)
return -ENOMEM;
- data->booleans = devm_kzalloc(dev, sizeof(struct pmbus_boolean)
- * data->max_booleans, GFP_KERNEL);
- if (!data->booleans)
- return -ENOMEM;
-
- data->labels = devm_kzalloc(dev, sizeof(struct pmbus_label)
- * data->max_labels, GFP_KERNEL);
- if (!data->labels)
- return -ENOMEM;
-
data->attributes = devm_kzalloc(dev, sizeof(struct attribute *)
* data->max_attributes, GFP_KERNEL);
if (!data->attributes)
return -ENOMEM;
- pmbus_find_attributes(client, data);
+ ret = pmbus_find_attributes(client, data);
+ if (ret)
+ return ret;
/*
* If there are no attributes, something is wrong.