[PATCH linux dev-4.10 v2 2/5] drivers: hwmon: occ: Add new sensor versions and non-hwmon attributes

Eddie James eajames at linux.vnet.ibm.com
Sat Jun 10 04:01:02 AEST 2017


From: "Edward A. James" <eajames at us.ibm.com>

Switch to versioned sensors which can be used for both p8 and p9. This
adds more common code and removes the need for the processor-specific
functions (other than the OCC access code).

Also add non-hwmon attributes for OCC status.

Signed-off-by: Edward A. James <eajames at us.ibm.com>
---
 drivers/hwmon/occ/Makefile |   2 +-
 drivers/hwmon/occ/common.c | 991 ++++++++++++++++++++++++++++++++++++++++++++-
 drivers/hwmon/occ/common.h |  17 +
 drivers/hwmon/occ/p9.c     | 350 ----------------
 drivers/hwmon/occ/p9.h     |  17 -
 drivers/hwmon/occ/p9_sbe.c |  30 +-
 6 files changed, 1020 insertions(+), 387 deletions(-)
 delete mode 100644 drivers/hwmon/occ/p9.c
 delete mode 100644 drivers/hwmon/occ/p9.h

diff --git a/drivers/hwmon/occ/Makefile b/drivers/hwmon/occ/Makefile
index 3b0ddc6..6245c25 100644
--- a/drivers/hwmon/occ/Makefile
+++ b/drivers/hwmon/occ/Makefile
@@ -1 +1 @@
-obj-y += p9.o p9_sbe.o common.o
+obj-y += p9_sbe.o common.o
diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c
index 1f17def..bee64cd 100644
--- a/drivers/hwmon/occ/common.c
+++ b/drivers/hwmon/occ/common.c
@@ -7,8 +7,114 @@
  * (at your option) any later version.
  */
 
+#include <asm/unaligned.h>
 #include "common.h"
 
+#define OCC_NUM_STATUS_ATTRS		6
+
+#define OCC_STAT_ACTIVE			0x01
+#define OCC_EXT_STAT_DVFS_OT		0x80
+#define OCC_EXT_STAT_DVFS_POWER		0x40
+#define OCC_EXT_STAT_MEM_THROTTLE	0x20
+#define OCC_EXT_STAT_QUICK_DROP		0x10
+
+struct temp_sensor_1 {
+	u16 sensor_id;
+	u16 value;
+} __packed;
+
+struct temp_sensor_2 {
+	u32 sensor_id;
+	u8 fru_type;
+	u8 value;
+} __packed;
+
+struct freq_sensor_1 {
+	u16 sensor_id;
+	u16 value;
+} __packed;
+
+struct freq_sensor_2 {
+	u32 sensor_id;
+	u16 value;
+} __packed;
+
+struct power_sensor_1 {
+	u16 sensor_id;
+	u32 update_tag;
+	u32 accumulator;
+	u16 value;
+} __packed;
+
+struct power_sensor_2 {
+	u32 sensor_id;
+	u8 function_id;
+	u8 apss_channel;
+	u16 reserved;
+	u32 update_tag;
+	u64 accumulator;
+	u16 value;
+} __packed;
+
+struct power_sensor_data {
+	u16 value;
+	u32 update_tag;
+	u64 accumulator;
+} __packed;
+
+struct power_sensor_data_and_time {
+	u16 update_time;
+	u16 value;
+	u32 update_tag;
+	u64 accumulator;
+} __packed;
+
+struct power_sensor_a0 {
+	u32 sensor_id;
+	struct power_sensor_data_and_time system;
+	u32 reserved;
+	struct power_sensor_data_and_time proc;
+	struct power_sensor_data vdd;
+	struct power_sensor_data vdn;
+} __packed;
+
+struct caps_sensor_1 {
+	u16 curr_powercap;
+	u16 curr_powerreading;
+	u16 norm_powercap;
+	u16 max_powercap;
+	u16 min_powercap;
+	u16 user_powerlimit;
+} __packed;
+
+struct caps_sensor_2 {
+	u16 curr_powercap;
+	u16 curr_powerreading;
+	u16 norm_powercap;
+	u16 max_powercap;
+	u16 min_powercap;
+	u16 user_powerlimit;
+	u8 user_powerlimit_source;
+} __packed;
+
+struct caps_sensor_3 {
+	u16 curr_powercap;
+	u16 curr_powerreading;
+	u16 norm_powercap;
+	u16 max_powercap;
+	u16 hard_min_powercap;
+	u16 soft_min_powercap;
+	u16 user_powerlimit;
+	u8 user_powerlimit_source;
+} __packed;
+
+struct extended_sensor {
+	u8 name[4];
+	u8 flags;
+	u8 reserved;
+	u8 data[6];
+} __packed;
+
 void occ_parse_poll_response(struct occ *occ)
 {
 	unsigned int i, offset = 0, size = 0;
@@ -40,6 +146,8 @@ void occ_parse_poll_response(struct occ *occ)
 			sensor = &sensors->power;
 		else if (strncmp(block->header.eye_catcher, "CAPS", 4) == 0)
 			sensor = &sensors->caps;
+		else if (strncmp(block->header.eye_catcher, "EXTN", 4) == 0)
+			sensor = &sensors->extended;
 		else {
 			dev_warn(occ->bus_dev, "sensor not supported %.4s\n",
 				 block->header.eye_catcher);
@@ -47,6 +155,7 @@ void occ_parse_poll_response(struct occ *occ)
 		}
 
 		sensor->num_sensors = block->header.num_sensors;
+		sensor->version = block->header.sensor_format;
 		sensor->data = &block->data;
 	}
 }
@@ -73,8 +182,9 @@ int occ_set_user_power_cap(struct occ *occ, u16 user_power_cap)
 	int rc;
 	u8 cmd[8];
 	u16 checksum = 0x24;
+	__be16 user_power_cap_be;
 
-	user_power_cap = cpu_to_be16(user_power_cap);
+	user_power_cap_be = cpu_to_be16(user_power_cap);
 
 	cmd[0] = 0;
 	cmd[1] = 0x22;
@@ -108,3 +218,882 @@ int occ_update_response(struct occ *occ)
 	mutex_unlock(&occ->lock);
 	return rc;
 }
+
+static ssize_t occ_show_status(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	int rc;
+	int val;
+	struct occ *occ = dev_get_drvdata(dev);
+	struct occ_poll_response_header *header;
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+
+	rc = occ_update_response(occ);
+	if (rc)
+		return rc;
+
+	header = (struct occ_poll_response_header *)occ->resp.data;
+
+	switch (sattr->index) {
+	case 0:
+		val = header->status & OCC_STAT_ACTIVE;
+		break;
+	case 1:
+		val = header->ext_status & OCC_EXT_STAT_DVFS_OT;
+		break;
+	case 2:
+		val = header->ext_status & OCC_EXT_STAT_DVFS_POWER;
+		break;
+	case 3:
+		val = header->ext_status & OCC_EXT_STAT_MEM_THROTTLE;
+		break;
+	case 4:
+		val = header->ext_status & OCC_EXT_STAT_QUICK_DROP;
+		break;
+	case 5:
+		val = header->occ_state;
+		break;
+	}
+
+	return snprintf(buf, PAGE_SIZE - 1, "%d\n", val);
+}
+
+static ssize_t occ_show_temp_1(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	int rc;
+	u16 val = 0;
+	struct temp_sensor_1 *temp;
+	struct occ *occ = dev_get_drvdata(dev);
+	struct occ_sensors *sensors = &occ->sensors;
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+	rc = occ_update_response(occ);
+	if (rc)
+		return rc;
+
+	temp = ((struct temp_sensor_1 *)sensors->temp.data) + sattr->index;
+
+	switch (sattr->nr) {
+	case 0:
+		val = get_unaligned_be16(&temp->sensor_id);
+		break;
+	case 1:
+		val = get_unaligned_be16(&temp->value) * 1000;
+		break;
+	}
+
+	return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
+}
+
+static ssize_t occ_show_temp_2(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	int rc;
+	u32 val = 0;
+	struct temp_sensor_2 *temp;
+	struct occ *occ = dev_get_drvdata(dev);
+	struct occ_sensors *sensors = &occ->sensors;
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+	rc = occ_update_response(occ);
+	if (rc)
+		return rc;
+
+	temp = ((struct temp_sensor_2 *)sensors->temp.data) + sattr->index;
+
+	switch (sattr->nr) {
+	case 0:
+		val = get_unaligned_be32(&temp->sensor_id);
+		break;
+	case 1:
+		val = temp->value * 1000;
+		break;
+	case 2:
+		val = temp->fru_type;
+		break;
+	}
+
+	return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
+}
+
+static ssize_t occ_show_freq_1(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	int rc;
+	u16 val = 0;
+	struct freq_sensor_1 *freq;
+	struct occ *occ = dev_get_drvdata(dev);
+	struct occ_sensors *sensors = &occ->sensors;
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+	rc = occ_update_response(occ);
+	if (rc)
+		return rc;
+
+	freq = ((struct freq_sensor_1 *)sensors->freq.data) + sattr->index;
+
+	switch (sattr->nr) {
+	case 0:
+		val = get_unaligned_be16(&freq->sensor_id);
+		break;
+	case 1:
+		val = get_unaligned_be16(&freq->value);
+		break;
+	}
+
+	return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
+}
+
+static ssize_t occ_show_freq_2(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	int rc;
+	u32 val = 0;
+	struct freq_sensor_2 *freq;
+	struct occ *occ = dev_get_drvdata(dev);
+	struct occ_sensors *sensors = &occ->sensors;
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+	rc = occ_update_response(occ);
+	if (rc)
+		return rc;
+
+	freq = ((struct freq_sensor_2 *)sensors->freq.data) + sattr->index;
+
+	switch (sattr->nr) {
+	case 0:
+		val = get_unaligned_be32(&freq->sensor_id);
+		break;
+	case 1:
+		val = get_unaligned_be16(&freq->value);
+		break;
+	}
+
+	return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
+}
+
+static ssize_t occ_show_power_1(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int rc;
+	u32 val = 0;
+	struct power_sensor_1 *power;
+	struct occ *occ = dev_get_drvdata(dev);
+	struct occ_sensors *sensors = &occ->sensors;
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+	rc = occ_update_response(occ);
+	if (rc)
+		return rc;
+
+	power = ((struct power_sensor_1 *)sensors->power.data) + sattr->index;
+
+	switch (sattr->nr) {
+	case 0:
+		val = get_unaligned_be16(&power->sensor_id);
+		break;
+	case 1:
+		val = get_unaligned_be32(&power->update_tag);
+		break;
+	case 2:
+		val = get_unaligned_be32(&power->accumulator);
+		break;
+	case 3:
+		val = get_unaligned_be16(&power->value);
+		break;
+	}
+
+	return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
+}
+
+static ssize_t occ_show_power_2(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int rc;
+	u64 val = 0;
+	struct power_sensor_2 *power;
+	struct occ *occ = dev_get_drvdata(dev);
+	struct occ_sensors *sensors = &occ->sensors;
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+	rc = occ_update_response(occ);
+	if (rc)
+		return rc;
+
+	power = ((struct power_sensor_2 *)sensors->power.data) + sattr->index;
+
+	switch (sattr->nr) {
+	case 0:
+		val = get_unaligned_be32(&power->sensor_id);
+		break;
+	case 1:
+		val = get_unaligned_be32(&power->update_tag);
+		break;
+	case 2:
+		val = get_unaligned_be64(&power->accumulator);
+		break;
+	case 3:
+		val = get_unaligned_be16(&power->value);
+		break;
+	case 4:
+		val = power->function_id;
+		break;
+	case 5:
+		val = power->apss_channel;
+		break;
+	}
+
+	return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val);
+}
+
+static ssize_t occ_show_power_a0(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	int rc;
+	u64 val = 0;
+	struct power_sensor_a0 *power;
+	struct occ *occ = dev_get_drvdata(dev);
+	struct occ_sensors *sensors = &occ->sensors;
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+	rc = occ_update_response(occ);
+	if (rc)
+		return rc;
+
+	power = ((struct power_sensor_a0 *)sensors->power.data) + sattr->index;
+
+	switch (sattr->nr) {
+	case 0:
+		val = get_unaligned_be32(&power->sensor_id);
+		break;
+	case 1:
+		val = get_unaligned_be16(&power->system.update_time);
+		break;
+	case 2:
+		val = get_unaligned_be16(&power->system.value);
+		break;
+	case 3:
+		val = get_unaligned_be32(&power->system.update_tag);
+		break;
+	case 4:
+		val = get_unaligned_be64(&power->system.accumulator);
+		break;
+	case 5:
+		val = get_unaligned_be16(&power->proc.update_time);
+		break;
+	case 6:
+		val = get_unaligned_be16(&power->proc.value);
+		break;
+	case 7:
+		val = get_unaligned_be32(&power->proc.update_tag);
+		break;
+	case 8:
+		val = get_unaligned_be64(&power->proc.accumulator);
+		break;
+	case 9:
+		val = get_unaligned_be16(&power->vdd.value);
+		break;
+	case 10:
+		val = get_unaligned_be32(&power->vdd.update_tag);
+		break;
+	case 11:
+		val = get_unaligned_be64(&power->vdd.accumulator);
+		break;
+	case 12:
+		val = get_unaligned_be16(&power->vdn.value);
+		break;
+	case 13:
+		val = get_unaligned_be32(&power->vdn.update_tag);
+		break;
+	case 14:
+		val = get_unaligned_be64(&power->vdn.accumulator);
+		break;
+	}
+
+	return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val);
+}
+
+
+static ssize_t occ_show_caps_1(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	int rc;
+	u16 val = 0;
+	struct caps_sensor_1 *caps;
+	struct occ *occ = dev_get_drvdata(dev);
+	struct occ_sensors *sensors = &occ->sensors;
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+	rc = occ_update_response(occ);
+	if (rc)
+		return rc;
+
+	caps = ((struct caps_sensor_1 *)sensors->caps.data) + sattr->index;
+
+	switch (sattr->nr) {
+	case 0:
+		val = get_unaligned_be16(&caps->curr_powercap);
+		break;
+	case 1:
+		val = get_unaligned_be16(&caps->curr_powerreading);
+		break;
+	case 2:
+		val = get_unaligned_be16(&caps->norm_powercap);
+		break;
+	case 3:
+		val = get_unaligned_be16(&caps->max_powercap);
+		break;
+	case 4:
+		val = get_unaligned_be16(&caps->min_powercap);
+		break;
+	case 5:
+		val = get_unaligned_be16(&caps->user_powerlimit);
+		break;
+	}
+
+	return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
+}
+
+static ssize_t occ_show_caps_2(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	int rc;
+	u16 val = 0;
+	struct caps_sensor_2 *caps;
+	struct occ *occ = dev_get_drvdata(dev);
+	struct occ_sensors *sensors = &occ->sensors;
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+	rc = occ_update_response(occ);
+	if (rc)
+		return rc;
+
+	caps = ((struct caps_sensor_2 *)sensors->caps.data) + sattr->index;
+
+	switch (sattr->nr) {
+	case 0:
+		val = get_unaligned_be16(&caps->curr_powercap);
+		break;
+	case 1:
+		val = get_unaligned_be16(&caps->curr_powerreading);
+		break;
+	case 2:
+		val = get_unaligned_be16(&caps->norm_powercap);
+		break;
+	case 3:
+		val = get_unaligned_be16(&caps->max_powercap);
+		break;
+	case 4:
+		val = get_unaligned_be16(&caps->min_powercap);
+		break;
+	case 5:
+		val = get_unaligned_be16(&caps->user_powerlimit);
+		break;
+	case 6:
+		val = caps->user_powerlimit_source;
+		break;
+	}
+
+	return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
+}
+
+static ssize_t occ_show_caps_3(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	int rc;
+	u16 val = 0;
+	struct caps_sensor_3 *caps;
+	struct occ *occ = dev_get_drvdata(dev);
+	struct occ_sensors *sensors = &occ->sensors;
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+	rc = occ_update_response(occ);
+	if (rc)
+		return rc;
+
+	caps = ((struct caps_sensor_3 *)sensors->caps.data) + sattr->index;
+
+	switch (sattr->nr) {
+	case 0:
+		val = get_unaligned_be16(&caps->curr_powercap);
+		break;
+	case 1:
+		val = get_unaligned_be16(&caps->curr_powerreading);
+		break;
+	case 2:
+		val = get_unaligned_be16(&caps->norm_powercap);
+		break;
+	case 3:
+		val = get_unaligned_be16(&caps->max_powercap);
+		break;
+	case 4:
+		val = get_unaligned_be16(&caps->hard_min_powercap);
+		break;
+	case 5:
+		val = get_unaligned_be16(&caps->user_powerlimit);
+		break;
+	case 6:
+		val = caps->user_powerlimit_source;
+		break;
+	case 7:
+		val = get_unaligned_be16(&caps->soft_min_powercap);
+		break;
+	}
+
+	return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
+}
+
+
+static ssize_t occ_store_caps_user(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	int rc;
+	u16 user_power_cap;
+	struct occ *occ = dev_get_drvdata(dev);
+
+	rc = kstrtou16(buf, 0, &user_power_cap);
+	if (rc)
+		return rc;
+
+	rc = occ_set_user_power_cap(occ, user_power_cap);
+	if (rc)
+		return rc;
+
+	return count;
+}
+
+static ssize_t occ_show_extended(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	int rc;
+	struct extended_sensor *extn;
+	struct occ *occ = dev_get_drvdata(dev);
+	struct occ_sensors *sensors = &occ->sensors;
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+	rc = occ_update_response(occ);
+	if (rc)
+		return rc;
+
+	extn = ((struct extended_sensor *)sensors->extended.data) +
+		sattr->index;
+
+	switch (sattr->nr) {
+	case 0:
+		rc = snprintf(buf, PAGE_SIZE - 1, "%02x%02x%02x%02x\n",
+			      extn->name[0], extn->name[1], extn->name[2],
+			      extn->name[3]);
+		break;
+	case 1:
+		rc = snprintf(buf, PAGE_SIZE - 1, "%02x\n", extn->flags);
+		break;
+	case 2:
+		rc = snprintf(buf, PAGE_SIZE - 1, "%02x%02x%02x%02x%02x%02x\n",
+			      extn->data[0], extn->data[1], extn->data[2],
+			      extn->data[3], extn->data[4], extn->data[5]);
+		break;
+	}
+
+	return rc;
+}
+
+int occ_setup_sensor_attrs(struct occ *occ)
+{
+	unsigned int i, s;
+	struct device *dev = occ->bus_dev;
+	struct occ_sensors *sensors = &occ->sensors;
+	struct occ_attribute *attr;
+	ssize_t (*show_temp)(struct device *, struct device_attribute *,
+			     char *) = occ_show_temp_1;
+	ssize_t (*show_freq)(struct device *, struct device_attribute *,
+			     char *) = occ_show_freq_1;
+	ssize_t (*show_power)(struct device *, struct device_attribute *,
+			      char *) = occ_show_power_1;
+	ssize_t (*show_caps)(struct device *, struct device_attribute *,
+			     char *) = occ_show_caps_1;
+
+	occ->num_attrs = 0;
+
+	switch (sensors->temp.version) {
+	case 1:
+		occ->num_attrs += (sensors->temp.num_sensors * 2);
+		break;
+	case 2:
+		occ->num_attrs += (sensors->temp.num_sensors * 3);
+		show_temp = occ_show_temp_2;
+		break;
+	default:
+		sensors->temp.num_sensors = 0;
+	}
+
+	switch (sensors->freq.version) {
+	case 2:
+		show_freq = occ_show_freq_2;
+		/* fall through */
+	case 1:
+		occ->num_attrs += (sensors->freq.num_sensors * 2);
+		break;
+	default:
+		sensors->freq.num_sensors = 0;
+	}
+
+	switch (sensors->power.version) {
+	case 1:
+		occ->num_attrs += (sensors->power.num_sensors * 4);
+		break;
+	case 2:
+		occ->num_attrs += (sensors->power.num_sensors * 6);
+		show_power = occ_show_power_2;
+		break;
+	case 0xA0:
+		occ->num_attrs += (sensors->power.num_sensors * 15);
+		show_power = occ_show_power_a0;
+		break;
+	default:
+		sensors->power.num_sensors = 0;
+	}
+
+	switch (sensors->caps.version) {
+	case 1:
+		occ->num_attrs += (sensors->caps.num_sensors * 6);
+		break;
+	case 2:
+		occ->num_attrs += (sensors->caps.num_sensors * 7);
+		show_caps = occ_show_caps_2;
+		break;
+	case 3:
+		occ->num_attrs += (sensors->caps.num_sensors * 8);
+		show_caps = occ_show_caps_3;
+		break;
+	default:
+		sensors->caps.num_sensors = 0;
+	}
+
+	switch (sensors->extended.version) {
+	case 1:
+		occ->num_attrs += sensors->extended.num_sensors;
+		break;
+	default:
+		sensors->extended.num_sensors = 0;
+	}
+
+	occ->attrs = devm_kzalloc(dev, sizeof(*occ->attrs) * occ->num_attrs,
+				  GFP_KERNEL);
+	if (!occ->attrs)
+		return -ENOMEM;
+
+	occ->group.attrs = devm_kzalloc(dev, sizeof(*occ->group.attrs) *
+					occ->num_attrs + 1, GFP_KERNEL);
+	if (!occ->group.attrs)
+		return -ENOMEM;
+
+	attr = occ->attrs;
+
+	for (i = 0; i < sensors->temp.num_sensors; ++i) {
+		s = i + 1;
+
+		snprintf(attr->name, sizeof(attr->name), "temp%d_label", s);
+		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_temp, NULL,
+					     0, i);
+		attr++;
+
+		snprintf(attr->name, sizeof(attr->name), "temp%d_input", s);
+		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_temp, NULL,
+					     1, i);
+		attr++;
+
+		if (sensors->temp.version > 1) {
+			snprintf(attr->name, sizeof(attr->name),
+				 "temp%d_fru_type", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_temp, NULL, 2, i);
+			attr++;
+		}
+	}
+
+	for (i = 0; i < sensors->freq.num_sensors; ++i) {
+		s = i + 1;
+
+		snprintf(attr->name, sizeof(attr->name), "freq%d_label", s);
+		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_freq, NULL,
+					     0, i);
+		attr++;
+
+		snprintf(attr->name, sizeof(attr->name), "freq%d_input", s);
+		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_freq, NULL,
+					     1, i);
+		attr++;
+	}
+
+	if (sensors->power.version == 0xA0) {
+		for (i = 0; i < sensors->power.num_sensors; ++i) {
+			s = i + 1;
+
+			snprintf(attr->name, sizeof(attr->name),
+				 "power%d_label", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_power, NULL, 0, i);
+			attr++;
+
+			snprintf(attr->name, sizeof(attr->name),
+				 "power%d_system_update_time", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_power, NULL, 1, i);
+			attr++;
+
+			snprintf(attr->name, sizeof(attr->name),
+				 "power%d_system_value", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_power, NULL, 2, i);
+			attr++;
+
+			snprintf(attr->name, sizeof(attr->name),
+				 "power%d_system_update_tag", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_power, NULL, 3, i);
+			attr++;
+
+			snprintf(attr->name, sizeof(attr->name),
+				 "power%d_system_accumulator", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_power, NULL, 4, i);
+			attr++;
+
+			snprintf(attr->name, sizeof(attr->name),
+				 "power%d_proc_update_time", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_power, NULL, 5, i);
+			attr++;
+
+			snprintf(attr->name, sizeof(attr->name),
+				 "power%d_proc_value", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_power, NULL, 6, i);
+			attr++;
+
+			snprintf(attr->name, sizeof(attr->name),
+				 "power%d_proc_update_tag", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_power, NULL, 7, i);
+			attr++;
+
+			snprintf(attr->name, sizeof(attr->name),
+				 "power%d_proc_accumulator", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_power, NULL, 8, i);
+			attr++;
+
+			snprintf(attr->name, sizeof(attr->name),
+				 "power%d_vdd_value", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_power, NULL, 9, i);
+			attr++;
+
+			snprintf(attr->name, sizeof(attr->name),
+				 "power%d_vdd_update_tag", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_power, NULL, 10, i);
+			attr++;
+
+			snprintf(attr->name, sizeof(attr->name),
+				 "power%d_vdd_accumulator", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_power, NULL, 11, i);
+			attr++;
+
+			snprintf(attr->name, sizeof(attr->name),
+				 "power%d_vdn_value", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_power, NULL, 12, i);
+			attr++;
+
+			snprintf(attr->name, sizeof(attr->name),
+				 "power%d_vdn_update_tag", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_power, NULL, 13, i);
+			attr++;
+
+			snprintf(attr->name, sizeof(attr->name),
+				 "power%d_vdn_accumulator", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_power, NULL, 14, i);
+			attr++;
+		}
+	} else {
+		for (i = 0; i < sensors->power.num_sensors; ++i) {
+			s = i + 1;
+
+			snprintf(attr->name, sizeof(attr->name),
+				 "power%d_label", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_power, NULL, 0, i);
+			attr++;
+
+			snprintf(attr->name, sizeof(attr->name),
+				 "power%d_update_tag", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_power, NULL, 1, i);
+			attr++;
+
+			snprintf(attr->name, sizeof(attr->name),
+				 "power%d_accumulator", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_power, NULL, 2, i);
+			attr++;
+
+			snprintf(attr->name, sizeof(attr->name),
+				 "power%d_input", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_power, NULL, 3, i);
+			attr++;
+
+			if (sensors->power.version > 1) {
+				snprintf(attr->name, sizeof(attr->name),
+					 "power%d_function_id", s);
+				attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+							     show_power, NULL,
+							     4, i);
+				attr++;
+
+				snprintf(attr->name, sizeof(attr->name),
+					 "power%d_apss_channel", s);
+				attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+							     show_power, NULL,
+							     5, i);
+				attr++;
+			}
+		}
+	}
+
+	for (i = 0; i < sensors->caps.num_sensors; ++i) {
+		s = i + 1;
+
+		snprintf(attr->name, sizeof(attr->name), "caps%d_current", s);
+		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
+					     0, i);
+		attr++;
+
+		snprintf(attr->name, sizeof(attr->name), "caps%d_reading", s);
+		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
+					     1, i);
+		attr++;
+
+		snprintf(attr->name, sizeof(attr->name), "caps%d_norm", s);
+		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
+					     2, i);
+		attr++;
+
+		snprintf(attr->name, sizeof(attr->name), "caps%d_max", s);
+		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
+					     3, i);
+		attr++;
+
+		if (sensors->caps.version > 2) {
+			snprintf(attr->name, sizeof(attr->name),
+				 "caps%d_min_hard", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_caps, NULL, 4, i);
+			attr++;
+
+			snprintf(attr->name, sizeof(attr->name),
+				 "caps%d_min_soft", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_caps, NULL, 7, i);
+			attr++;
+		} else {
+			snprintf(attr->name, sizeof(attr->name), "caps%d_min",
+				 s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_caps, NULL, 4, i);
+			attr++;
+		}
+
+		snprintf(attr->name, sizeof(attr->name), "caps%d_user", s);
+		attr->sensor = OCC_INIT_ATTR(attr->name, 0644, show_caps,
+					     occ_store_caps_user, 5, i);
+		attr++;
+
+		if (sensors->caps.version > 1) {
+			snprintf(attr->name, sizeof(attr->name),
+				 "caps%d_user_source", s);
+			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+						     show_caps, NULL, 6, i);
+			attr++;
+		}
+	}
+
+	for (i = 0; i < sensors->extended.num_sensors; ++i) {
+		s = i + 1;
+
+		snprintf(attr->name, sizeof(attr->name), "extn%d_label", s);
+		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+					     occ_show_extended, NULL, 0, i);
+		attr++;
+
+		snprintf(attr->name, sizeof(attr->name), "extn%d_flags", s);
+		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+					     occ_show_extended, NULL, 1, i);
+		attr++;
+
+		snprintf(attr->name, sizeof(attr->name), "extn%d_value", s);
+		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+					     occ_show_extended, NULL, 2, i);
+		attr++;
+	}
+
+	/* put the sensors in the group */
+	for (i = 0; i < occ->num_attrs; ++i)
+		occ->group.attrs[i] = &occ->attrs[i].sensor.dev_attr.attr;
+
+	return 0;
+}
+
+int occ_create_status_attrs(struct occ *occ)
+{
+	int rc, i;
+	struct device *dev = occ->bus_dev;
+
+	occ->status_attrs = devm_kzalloc(dev, sizeof(*occ->status_attrs) *
+					 OCC_NUM_STATUS_ATTRS, GFP_KERNEL);
+	if (!occ->status_attrs)
+		return -ENOMEM;
+
+	occ->status_attrs[0] =
+		(struct sensor_device_attribute)SENSOR_ATTR(occ_active, 0444,
+							    occ_show_status,
+							    NULL, 0);
+	occ->status_attrs[1] =
+		(struct sensor_device_attribute)SENSOR_ATTR(occ_dvfs_ot, 0444,
+							    occ_show_status,
+							    NULL, 1);
+	occ->status_attrs[2] =
+		(struct sensor_device_attribute)SENSOR_ATTR(occ_dvfs_power,
+							    0444,
+							    occ_show_status,
+							    NULL, 2);
+	occ->status_attrs[3] =
+		(struct sensor_device_attribute)SENSOR_ATTR(occ_mem_throttle,
+							    0444,
+							    occ_show_status,
+							    NULL, 3);
+	occ->status_attrs[4] =
+		(struct sensor_device_attribute)SENSOR_ATTR(occ_quick_drop,
+							    0444,
+							    occ_show_status,
+							    NULL, 4);
+	occ->status_attrs[5] =
+		(struct sensor_device_attribute)SENSOR_ATTR(occ_status, 0444,
+							    occ_show_status,
+							    NULL, 5);
+
+	for (i = 0; i < OCC_NUM_STATUS_ATTRS; ++i) {
+		rc = device_create_file(dev, &occ->status_attrs[i].dev_attr);
+		if (rc)
+			dev_warn(dev, "error %d creating status attr %d\n", rc,
+				 i);
+	}
+
+	return 0;
+}
diff --git a/drivers/hwmon/occ/common.h b/drivers/hwmon/occ/common.h
index a3d733a..ad21538 100644
--- a/drivers/hwmon/occ/common.h
+++ b/drivers/hwmon/occ/common.h
@@ -16,6 +16,18 @@
 #define OCC_UPDATE_FREQUENCY		msecs_to_jiffies(1000)
 #define OCC_RESP_DATA_BYTES		4089
 
+#define OCC_TIMEOUT_MS			5000
+#define OCC_CMD_IN_PRG_MS		100
+
+#define RESP_RETURN_CMD_IN_PRG		0xFF
+#define RESP_RETURN_SUCCESS		0
+#define RESP_RETURN_CMD_INVAL		0x11
+#define RESP_RETURN_CMD_LEN		0x12
+#define RESP_RETURN_DATA_INVAL		0x13
+#define RESP_RETURN_CHKSUM		0x14
+#define RESP_RETURN_OCC_ERR		0x15
+#define RESP_RETURN_STATE		0x16
+
 struct occ_response {
 	u8 seq_no;
 	u8 cmd_type;
@@ -63,6 +75,7 @@ struct occ_poll_response {
 
 struct occ_sensor {
 	u8 num_sensors;
+	u8 version;
 	void *data;
 };
 
@@ -71,6 +84,7 @@ struct occ_sensors {
 	struct occ_sensor freq;
 	struct occ_sensor power;
 	struct occ_sensor caps;
+	struct occ_sensor extended;
 };
 
 struct occ_attribute {
@@ -92,6 +106,7 @@ struct occ {
 	struct occ_attribute *attrs;
 	struct attribute_group group;
 	const struct attribute_group *groups[2];
+	struct sensor_device_attribute *status_attrs;
 
 	u8 poll_cmd_data;
 	int (*send_cmd)(struct occ *occ, u8 *cmd);
@@ -120,5 +135,7 @@ struct occ {
 int occ_poll(struct occ *occ);
 int occ_set_user_power_cap(struct occ *occ, u16 user_power_cap);
 int occ_update_response(struct occ *occ);
+int occ_setup_sensor_attrs(struct occ *occ);
+int occ_create_status_attrs(struct occ *occ);
 
 #endif /* __OCC_COMMON_H__ */
diff --git a/drivers/hwmon/occ/p9.c b/drivers/hwmon/occ/p9.c
deleted file mode 100644
index 832d6ff..0000000
--- a/drivers/hwmon/occ/p9.c
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Copyright 2017 IBM Corp.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <asm/unaligned.h>
-#include "common.h"
-
-struct p9_temp_sensor {
-	u32 sensor_id;
-	u8 fru_type;
-	u8 value;
-} __packed;
-
-struct p9_freq_sensor {
-	u32 sensor_id;
-	u16 value;
-} __packed;
-
-struct p9_power_sensor {
-	u32 sensor_id;
-	u8 function_id;
-	u8 apss_channel;
-	u16 reserved;
-	u32 update_tag;
-	u64 accumulator;
-	u16 value;
-} __packed;
-
-struct p9_caps_sensor {
-	u16 curr_powercap;
-	u16 curr_powerreading;
-	u16 norm_powercap;
-	u16 max_powercap;
-	u16 min_powercap;
-	u16 user_powerlimit;
-	u8 user_powerlimit_source;
-} __packed;
-
-static ssize_t p9_occ_show_temp(struct device *dev,
-				struct device_attribute *attr,
-				char *buf)
-{
-	int rc;
-	u32 val = 0;
-	struct p9_temp_sensor *temp;
-	struct occ *occ = dev_get_drvdata(dev);
-	struct occ_sensors *sensors = &occ->sensors;
-	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-
-	rc = occ_update_response(occ);
-	if (rc)
-		return rc;
-
-	temp = ((struct p9_temp_sensor *)sensors->temp.data) + sattr->index;
-
-	switch (sattr->nr) {
-	case 0:
-		val = be32_to_cpu(get_unaligned(&temp->sensor_id));
-		break;
-	case 1:
-		val = temp->fru_type;
-		break;
-	case 2:
-		/* millidegree */
-		val = temp->value * 1000;
-		break;
-	}
-
-	return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
-}
-
-static ssize_t p9_occ_show_freq(struct device *dev,
-				struct device_attribute *attr,
-				char *buf)
-{
-	int rc;
-	u32 val = 0;
-	struct p9_freq_sensor *freq;
-	struct occ *occ = dev_get_drvdata(dev);
-	struct occ_sensors *sensors = &occ->sensors;
-	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-
-	rc = occ_update_response(occ);
-	if (rc)
-		return rc;
-
-	freq = ((struct p9_freq_sensor *)sensors->freq.data) + sattr->index;
-
-	switch (sattr->nr) {
-	case 0:
-		val = be32_to_cpu(get_unaligned(&freq->sensor_id));
-		break;
-	case 1:
-		val = be16_to_cpu(get_unaligned(&freq->value));
-		break;
-	}
-
-	return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
-}
-
-static ssize_t p9_occ_show_power(struct device *dev,
-				 struct device_attribute *attr,
-				 char *buf)
-{
-	int rc;
-	u64 val = 0;
-	struct p9_power_sensor *power;
-	struct occ *occ = dev_get_drvdata(dev);
-	struct occ_sensors *sensors = &occ->sensors;
-	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-
-	rc = occ_update_response(occ);
-	if (rc)
-		return rc;
-
-	power = ((struct p9_power_sensor *)sensors->power.data) + sattr->index;
-
-	switch (sattr->nr) {
-	case 0:
-		val = be32_to_cpu(get_unaligned(&power->sensor_id));
-		break;
-	case 1:
-		val = power->function_id;
-		break;
-	case 2:
-		val = power->apss_channel;
-		break;
-	case 3:
-		val = be32_to_cpu(get_unaligned(&power->update_tag));
-		break;
-	case 4:
-		val = be64_to_cpu(get_unaligned(&power->accumulator));
-		break;
-	case 5:
-		val = be16_to_cpu(get_unaligned(&power->value));
-		break;
-	}
-
-	return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val);
-}
-
-static ssize_t p9_occ_show_caps(struct device *dev,
-				struct device_attribute *attr,
-				char *buf)
-{
-	int rc;
-	u16 val = 0;
-	struct p9_caps_sensor *caps;
-	struct occ *occ = dev_get_drvdata(dev);
-	struct occ_sensors *sensors = &occ->sensors;
-	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-
-	rc = occ_update_response(occ);
-	if (rc)
-		return rc;
-
-	caps = ((struct p9_caps_sensor *)sensors->caps.data) + sattr->index;
-
-	switch (sattr->nr) {
-	case 0:
-		val = be16_to_cpu(get_unaligned(&caps->curr_powercap));
-		break;
-	case 1:
-		val = be16_to_cpu(get_unaligned(&caps->curr_powerreading));
-		break;
-	case 2:
-		val = be16_to_cpu(get_unaligned(&caps->norm_powercap));
-		break;
-	case 3:
-		val = be16_to_cpu(get_unaligned(&caps->max_powercap));
-		break;
-	case 4:
-		val = be16_to_cpu(get_unaligned(&caps->min_powercap));
-		break;
-	case 5:
-		val = be16_to_cpu(get_unaligned(&caps->user_powerlimit));
-		break;
-	case 6:
-		val = caps->user_powerlimit_source;
-		break;
-	}
-
-	return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
-}
-
-static ssize_t p9_occ_store_caps_user(struct device *dev,
-				      struct device_attribute *attr,
-				      const char *buf, size_t count)
-{
-	int rc;
-	u16 user_power_cap;
-	struct occ *occ = dev_get_drvdata(dev);
-
-	rc = kstrtou16(buf, 0, &user_power_cap);
-	if (rc)
-		return rc;
-
-	rc = occ_set_user_power_cap(occ, user_power_cap);
-	if (rc)
-		return rc;
-
-	return count;
-}
-
-int p9_occ_setup_sensor_attrs(struct occ *occ)
-{
-	unsigned int i, s;
-	struct device *dev = occ->bus_dev;
-	struct occ_sensors *sensors = &occ->sensors;
-	struct occ_attribute *attr;
-
-	occ->num_attrs = (sensors->temp.num_sensors * 3);
-	occ->num_attrs += (sensors->freq.num_sensors * 2);
-	occ->num_attrs += (sensors->power.num_sensors * 6);
-	occ->num_attrs += (sensors->caps.num_sensors * 7);
-
-	occ->attrs = devm_kzalloc(dev, sizeof(*occ->attrs) * occ->num_attrs,
-				  GFP_KERNEL);
-	if (!occ->attrs)
-		return -ENOMEM;
-
-	occ->group.attrs = devm_kzalloc(dev, sizeof(*occ->group.attrs) *
-					occ->num_attrs + 1, GFP_KERNEL);
-	if (!occ->group.attrs)
-		return -ENOMEM;
-
-	attr = occ->attrs;
-	for (i = 0; i < sensors->temp.num_sensors; ++i) {
-		s = i + 1;
-
-		snprintf(attr->name, sizeof(attr->name), "temp%d_label", s);
-		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
-					     p9_occ_show_temp, NULL, 0, i);
-		attr++;
-
-		snprintf(attr->name, sizeof(attr->name), "temp%d_fru_type", s);
-		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
-					     p9_occ_show_temp, NULL, 1, i);
-		attr++;
-
-		snprintf(attr->name, sizeof(attr->name), "temp%d_input", s);
-		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
-					     p9_occ_show_temp, NULL, 2, i);
-		attr++;
-	}
-
-	for (i = 0; i < sensors->freq.num_sensors; ++i) {
-		s = i + 1;
-
-		snprintf(attr->name, sizeof(attr->name), "freq%d_label", s);
-		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
-					     p9_occ_show_freq, NULL, 0, i);
-		attr++;
-
-		snprintf(attr->name, sizeof(attr->name), "freq%d_input", s);
-		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
-					     p9_occ_show_freq, NULL, 1, i);
-		attr++;
-	}
-
-	for (i = 0; i < sensors->power.num_sensors; ++i) {
-		s = i + 1;
-
-		snprintf(attr->name, sizeof(attr->name), "power%d_label", s);
-		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
-					     p9_occ_show_power, NULL, 0, i);
-		attr++;
-
-		snprintf(attr->name, sizeof(attr->name), "power%d_function_id",
-			 s);
-		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
-					     p9_occ_show_power, NULL, 1, i);
-		attr++;
-
-		snprintf(attr->name, sizeof(attr->name),
-			 "power%d_apss_channel", s);
-		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
-					     p9_occ_show_power, NULL, 2, i);
-		attr++;
-
-		snprintf(attr->name, sizeof(attr->name), "power%d_update_tag",
-			 s);
-		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
-					     p9_occ_show_power, NULL, 3, i);
-		attr++;
-
-		snprintf(attr->name, sizeof(attr->name), "power%d_accumulator",
-			 s);
-		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
-					     p9_occ_show_power, NULL, 4, i);
-		attr++;
-
-		snprintf(attr->name, sizeof(attr->name), "power%d_input", s);
-		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
-					     p9_occ_show_power, NULL, 5, i);
-		attr++;
-	}
-
-	for (i = 0; i < sensors->caps.num_sensors; ++i) {
-		s = i + 1;
-
-		snprintf(attr->name, sizeof(attr->name), "caps%d_curr", s);
-		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
-					     p9_occ_show_caps, NULL, 0, i);
-		attr++;
-
-		snprintf(attr->name, sizeof(attr->name), "caps%d_reading", s);
-		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
-					     p9_occ_show_caps, NULL, 1, i);
-		attr++;
-
-		snprintf(attr->name, sizeof(attr->name), "caps%d_norm", s);
-		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
-					     p9_occ_show_caps, NULL, 2, i);
-		attr++;
-
-		snprintf(attr->name, sizeof(attr->name), "caps%d_max", s);
-		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
-					     p9_occ_show_caps, NULL, 3, i);
-		attr++;
-
-		snprintf(attr->name, sizeof(attr->name), "caps%d_min", s);
-		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
-					     p9_occ_show_caps, NULL, 4, i);
-		attr++;
-
-		snprintf(attr->name, sizeof(attr->name), "caps%d_user", s);
-		attr->sensor = OCC_INIT_ATTR(attr->name, 0644,
-					     p9_occ_show_caps,
-					     p9_occ_store_caps_user, 5, i);
-		attr++;
-
-		snprintf(attr->name, sizeof(attr->name), "caps%d_user_source",
-			 s);
-		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
-					     p9_occ_show_caps, NULL, 6, i);
-		attr++;
-	}
-
-	/* put the sensors in the group */
-	for (i = 0; i < occ->num_attrs; ++i)
-		occ->group.attrs[i] = &occ->attrs[i].sensor.dev_attr.attr;
-
-	return 0;
-}
diff --git a/drivers/hwmon/occ/p9.h b/drivers/hwmon/occ/p9.h
deleted file mode 100644
index 12d1bc5..0000000
--- a/drivers/hwmon/occ/p9.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright 2017 IBM Corp.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __OCC_P9_H__
-#define __OCC_P9_H__
-
-struct occ;
-
-int p9_occ_setup_sensor_attrs(struct occ *occ);
-
-#endif /* __OCC_P9_H__ */
diff --git a/drivers/hwmon/occ/p9_sbe.c b/drivers/hwmon/occ/p9_sbe.c
index 88f71b1..fe435ef 100644
--- a/drivers/hwmon/occ/p9_sbe.c
+++ b/drivers/hwmon/occ/p9_sbe.c
@@ -15,21 +15,8 @@
 #include <linux/occ.h>
 #include <linux/sched.h>
 #include <linux/workqueue.h>
-#include "p9.h"
 
-#define P9_SBE_OCC_SETUP_DELAY		2500
-
-#define OCC_TIMEOUT_MS			5000
-#define OCC_CMD_IN_PRG_MS		100
-
-#define RESP_RETURN_CMD_IN_PRG		0xFF
-#define RESP_RETURN_SUCCESS		0
-#define RESP_RETURN_CMD_INVAL		0x11
-#define RESP_RETURN_CMD_LEN		0x12
-#define RESP_RETURN_DATA_INVAL		0x13
-#define RESP_RETURN_CHKSUM		0x14
-#define RESP_RETURN_OCC_ERR		0x15
-#define RESP_RETURN_STATE		0x16
+#define P9_SBE_OCC_SETUP_DELAY		5000
 
 struct p9_sbe_occ {
 	struct occ occ;
@@ -66,7 +53,8 @@ static int p9_sbe_occ_send_cmd(struct occ *occ, u8 *cmd)
 
 	switch (resp->return_status) {
 	case RESP_RETURN_CMD_IN_PRG:
-		if (time_after(jiffies, start + msecs_to_jiffies(OCC_TIMEOUT_MS)))
+		if (time_after(jiffies,
+			       start + msecs_to_jiffies(OCC_TIMEOUT_MS)))
 			rc = -EALREADY;
 		else {
 			set_current_state(TASK_INTERRUPTIBLE);
@@ -123,7 +111,7 @@ static void p9_sbe_occ_setup(struct work_struct *work)
 
 	occ_parse_poll_response(occ);
 
-	rc = p9_occ_setup_sensor_attrs(occ);
+	rc = occ_setup_sensor_attrs(occ);
 	if (rc) {
 		dev_err(occ->bus_dev, "failed to setup p9 attrs: %d\n", rc);
 		return;
@@ -137,6 +125,10 @@ static void p9_sbe_occ_setup(struct work_struct *work)
 			PTR_ERR(occ->hwmon));
 		return;
 	}
+
+	rc = occ_create_status_attrs(occ);
+	if (rc)
+		dev_err(occ->bus_dev, "failed to setup p9 status attrs: %d\n", rc);
 }
 
 static int p9_sbe_occ_probe(struct platform_device *pdev)
@@ -157,7 +149,8 @@ static int p9_sbe_occ_probe(struct platform_device *pdev)
 	occ->send_cmd = p9_sbe_occ_send_cmd;
 	mutex_init(&occ->lock);
 	INIT_DELAYED_WORK(&p9_sbe_occ->setup, p9_sbe_occ_setup);
-	platform_set_drvdata(pdev, p9_sbe_occ);
+
+	platform_set_drvdata(pdev, occ);
 
 	schedule_delayed_work(&p9_sbe_occ->setup,
 			      msecs_to_jiffies(P9_SBE_OCC_SETUP_DELAY));
@@ -167,7 +160,8 @@ static int p9_sbe_occ_probe(struct platform_device *pdev)
 
 static int p9_sbe_occ_remove(struct platform_device *pdev)
 {
-	struct p9_sbe_occ *p9_sbe_occ = platform_get_drvdata(pdev);
+	struct occ *occ = platform_get_drvdata(pdev);
+	struct p9_sbe_occ *p9_sbe_occ = to_p9_sbe_occ(occ);
 
 	cancel_delayed_work_sync(&p9_sbe_occ->setup);
 
-- 
1.8.3.1



More information about the openbmc mailing list