summaryrefslogtreecommitdiff
path: root/drivers/hwmon
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/pmbus/pmbus.h6
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c85
2 files changed, 68 insertions, 23 deletions
diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
index 27c7ae0ffa6b..18e06fc6c53f 100644
--- a/drivers/hwmon/pmbus/pmbus.h
+++ b/drivers/hwmon/pmbus/pmbus.h
@@ -362,6 +362,7 @@ enum pmbus_sensor_classes {
};
#define PMBUS_PAGES 32 /* Per PMBus specification */
+#define PMBUS_PHASES 8 /* Maximum number of phases per page */
/* Functionality bit mask */
#define PMBUS_HAVE_VIN BIT(0)
@@ -388,13 +389,15 @@ enum pmbus_sensor_classes {
#define PMBUS_HAVE_PWM34 BIT(21)
#define PMBUS_HAVE_SAMPLES BIT(22)
-#define PMBUS_PAGE_VIRTUAL BIT(31)
+#define PMBUS_PHASE_VIRTUAL BIT(30) /* Phases on this page are virtual */
+#define PMBUS_PAGE_VIRTUAL BIT(31) /* Page is virtual */
enum pmbus_data_format { linear = 0, direct, vid };
enum vrm_version { vr11 = 0, vr12, vr13, imvp9, amd625mv };
struct pmbus_driver_info {
int pages; /* Total number of pages */
+ u8 phases[PMBUS_PAGES]; /* Number of phases per page */
enum pmbus_data_format format[PSC_NUM_CLASSES];
enum vrm_version vrm_version[PMBUS_PAGES]; /* vrm version per page */
/*
@@ -406,6 +409,7 @@ struct pmbus_driver_info {
int R[PSC_NUM_CLASSES]; /* exponent */
u32 func[PMBUS_PAGES]; /* Functionality, per page */
+ u32 pfunc[PMBUS_PHASES];/* Functionality, per phase */
/*
* The following functions map manufacturing specific register values
* to PMBus standard register values. Specify only if mapping is
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 9343ca7d4069..8d321bf7d15b 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -49,6 +49,7 @@ struct pmbus_sensor {
char name[PMBUS_NAME_SIZE]; /* sysfs sensor name */
struct device_attribute attribute;
u8 page; /* page number */
+ u8 phase; /* phase number, 0xff for all phases */
u16 reg; /* register */
enum pmbus_sensor_classes class; /* sensor class */
bool update; /* runtime sensor update needed */
@@ -109,6 +110,7 @@ struct pmbus_data {
int (*read_status)(struct i2c_client *client, int page);
u8 currpage;
+ u8 currphase; /* current phase, 0xff for all */
};
struct pmbus_debugfs_entry {
@@ -151,10 +153,11 @@ int pmbus_set_page(struct i2c_client *client, int page, int phase)
struct pmbus_data *data = i2c_get_clientdata(client);
int rv;
- if (page < 0 || page == data->currpage)
+ if (page < 0)
return 0;
- if (!(data->info->func[page] & PMBUS_PAGE_VIRTUAL)) {
+ if (!(data->info->func[page] & PMBUS_PAGE_VIRTUAL) &&
+ data->info->pages > 1 && page != data->currpage) {
rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
if (rv < 0)
return rv;
@@ -166,9 +169,17 @@ int pmbus_set_page(struct i2c_client *client, int page, int phase)
if (rv != page)
return -EIO;
}
-
data->currpage = page;
+ if (data->info->phases[page] && data->currphase != phase &&
+ !(data->info->func[page] & PMBUS_PHASE_VIRTUAL)) {
+ rv = i2c_smbus_write_byte_data(client, PMBUS_PHASE,
+ phase);
+ if (rv)
+ return rv;
+ }
+ data->currphase = phase;
+
return 0;
}
EXPORT_SYMBOL_GPL(pmbus_set_page);
@@ -602,7 +613,7 @@ static struct pmbus_data *pmbus_update_device(struct device *dev)
sensor->data
= _pmbus_read_word_data(client,
sensor->page,
- 0xff,
+ sensor->phase,
sensor->reg);
}
pmbus_clear_faults(client);
@@ -1084,7 +1095,8 @@ static int pmbus_add_boolean(struct pmbus_data *data,
static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
const char *name, const char *type,
- int seq, int page, int reg,
+ int seq, int page, int phase,
+ int reg,
enum pmbus_sensor_classes class,
bool update, bool readonly,
bool convert)
@@ -1108,6 +1120,7 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
readonly = true;
sensor->page = page;
+ sensor->phase = phase;
sensor->reg = reg;
sensor->class = class;
sensor->update = update;
@@ -1127,7 +1140,7 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
static int pmbus_add_label(struct pmbus_data *data,
const char *name, int seq,
- const char *lstring, int index)
+ const char *lstring, int index, int phase)
{
struct pmbus_label *label;
struct device_attribute *a;
@@ -1139,11 +1152,21 @@ static int pmbus_add_label(struct pmbus_data *data,
a = &label->attribute;
snprintf(label->name, sizeof(label->name), "%s%d_label", name, seq);
- if (!index)
- strncpy(label->label, lstring, sizeof(label->label) - 1);
- else
- snprintf(label->label, sizeof(label->label), "%s%d", lstring,
- index);
+ if (!index) {
+ if (phase == 0xff)
+ strncpy(label->label, lstring,
+ sizeof(label->label) - 1);
+ else
+ snprintf(label->label, sizeof(label->label), "%s.%d",
+ lstring, phase);
+ } else {
+ if (phase == 0xff)
+ snprintf(label->label, sizeof(label->label), "%s%d",
+ lstring, index);
+ else
+ snprintf(label->label, sizeof(label->label), "%s%d.%d",
+ lstring, index, phase);
+ }
pmbus_dev_attr_init(a, label->name, 0444, pmbus_show_label, NULL);
return pmbus_add_attribute(data, &a->attr);
@@ -1208,7 +1231,7 @@ static int pmbus_add_limit_attrs(struct i2c_client *client,
for (i = 0; i < nlimit; i++) {
if (pmbus_check_word_register(client, page, l->reg)) {
curr = pmbus_add_sensor(data, name, l->attr, index,
- page, l->reg, attr->class,
+ page, 0xff, l->reg, attr->class,
attr->update || l->update,
false, true);
if (!curr)
@@ -1235,7 +1258,7 @@ 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,
+ int index, int page, int phase,
const struct pmbus_sensor_attr *attr,
bool paged)
{
@@ -1245,15 +1268,16 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client,
if (attr->label) {
ret = pmbus_add_label(data, name, index, attr->label,
- paged ? page + 1 : 0);
+ paged ? page + 1 : 0, phase);
if (ret)
return ret;
}
- base = pmbus_add_sensor(data, name, "input", index, page, attr->reg,
- attr->class, true, true, true);
+ base = pmbus_add_sensor(data, name, "input", index, page, phase,
+ attr->reg, attr->class, true, true, true);
if (!base)
return -ENOMEM;
- if (attr->sfunc) {
+ /* No limit and alarm attributes for phase specific sensors */
+ if (attr->sfunc && phase == 0xff) {
ret = pmbus_add_limit_attrs(client, data, info, name,
index, page, base, attr);
if (ret < 0)
@@ -1323,10 +1347,25 @@ static int pmbus_add_sensor_attrs(struct i2c_client *client,
continue;
ret = pmbus_add_sensor_attrs_one(client, data, info,
name, index, page,
- attrs, paged);
+ 0xff, attrs, paged);
if (ret)
return ret;
index++;
+ if (info->phases[page]) {
+ int phase;
+
+ for (phase = 0; phase < info->phases[page];
+ phase++) {
+ if (!(info->pfunc[phase] & attrs->func))
+ continue;
+ ret = pmbus_add_sensor_attrs_one(client,
+ data, info, name, index, page,
+ phase, attrs, paged);
+ if (ret)
+ return ret;
+ index++;
+ }
+ }
}
attrs++;
}
@@ -1830,7 +1869,7 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client,
struct pmbus_sensor *sensor;
sensor = pmbus_add_sensor(data, "fan", "target", index, page,
- PMBUS_VIRT_FAN_TARGET_1 + id, PSC_FAN,
+ PMBUS_VIRT_FAN_TARGET_1 + id, 0xff, PSC_FAN,
false, false, true);
if (!sensor)
@@ -1841,14 +1880,14 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client,
return 0;
sensor = pmbus_add_sensor(data, "pwm", NULL, index, page,
- PMBUS_VIRT_PWM_1 + id, PSC_PWM,
+ PMBUS_VIRT_PWM_1 + id, 0xff, PSC_PWM,
false, false, true);
if (!sensor)
return -ENOMEM;
sensor = pmbus_add_sensor(data, "pwm", "enable", index, page,
- PMBUS_VIRT_PWM_ENABLE_1 + id, PSC_PWM,
+ PMBUS_VIRT_PWM_ENABLE_1 + id, 0xff, PSC_PWM,
true, false, false);
if (!sensor)
@@ -1890,7 +1929,7 @@ static int pmbus_add_fan_attributes(struct i2c_client *client,
continue;
if (pmbus_add_sensor(data, "fan", "input", index,
- page, pmbus_fan_registers[f],
+ page, pmbus_fan_registers[f], 0xff,
PSC_FAN, true, true, true) == NULL)
return -ENOMEM;
@@ -2490,6 +2529,8 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
if (pdata)
data->flags = pdata->flags;
data->info = info;
+ data->currpage = 0xff;
+ data->currphase = 0xfe;
ret = pmbus_init_common(client, data, info);
if (ret < 0)