xref: /OK3568_Linux_fs/kernel/drivers/hwmon/occ/common.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun // Copyright IBM Corp 2019
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun #include <linux/device.h>
5*4882a593Smuzhiyun #include <linux/export.h>
6*4882a593Smuzhiyun #include <linux/hwmon.h>
7*4882a593Smuzhiyun #include <linux/hwmon-sysfs.h>
8*4882a593Smuzhiyun #include <linux/jiffies.h>
9*4882a593Smuzhiyun #include <linux/kernel.h>
10*4882a593Smuzhiyun #include <linux/math64.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/mutex.h>
13*4882a593Smuzhiyun #include <linux/sysfs.h>
14*4882a593Smuzhiyun #include <asm/unaligned.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include "common.h"
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #define EXTN_FLAG_SENSOR_ID		BIT(7)
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #define OCC_ERROR_COUNT_THRESHOLD	2	/* required by OCC spec */
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define OCC_STATE_SAFE			4
23*4882a593Smuzhiyun #define OCC_SAFE_TIMEOUT		msecs_to_jiffies(60000) /* 1 min */
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #define OCC_UPDATE_FREQUENCY		msecs_to_jiffies(1000)
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #define OCC_TEMP_SENSOR_FAULT		0xFF
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #define OCC_FRU_TYPE_VRM		3
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /* OCC sensor type and version definitions */
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun struct temp_sensor_1 {
34*4882a593Smuzhiyun 	u16 sensor_id;
35*4882a593Smuzhiyun 	u16 value;
36*4882a593Smuzhiyun } __packed;
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun struct temp_sensor_2 {
39*4882a593Smuzhiyun 	u32 sensor_id;
40*4882a593Smuzhiyun 	u8 fru_type;
41*4882a593Smuzhiyun 	u8 value;
42*4882a593Smuzhiyun } __packed;
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun struct freq_sensor_1 {
45*4882a593Smuzhiyun 	u16 sensor_id;
46*4882a593Smuzhiyun 	u16 value;
47*4882a593Smuzhiyun } __packed;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun struct freq_sensor_2 {
50*4882a593Smuzhiyun 	u32 sensor_id;
51*4882a593Smuzhiyun 	u16 value;
52*4882a593Smuzhiyun } __packed;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun struct power_sensor_1 {
55*4882a593Smuzhiyun 	u16 sensor_id;
56*4882a593Smuzhiyun 	u32 update_tag;
57*4882a593Smuzhiyun 	u32 accumulator;
58*4882a593Smuzhiyun 	u16 value;
59*4882a593Smuzhiyun } __packed;
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun struct power_sensor_2 {
62*4882a593Smuzhiyun 	u32 sensor_id;
63*4882a593Smuzhiyun 	u8 function_id;
64*4882a593Smuzhiyun 	u8 apss_channel;
65*4882a593Smuzhiyun 	u16 reserved;
66*4882a593Smuzhiyun 	u32 update_tag;
67*4882a593Smuzhiyun 	u64 accumulator;
68*4882a593Smuzhiyun 	u16 value;
69*4882a593Smuzhiyun } __packed;
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun struct power_sensor_data {
72*4882a593Smuzhiyun 	u16 value;
73*4882a593Smuzhiyun 	u32 update_tag;
74*4882a593Smuzhiyun 	u64 accumulator;
75*4882a593Smuzhiyun } __packed;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun struct power_sensor_data_and_time {
78*4882a593Smuzhiyun 	u16 update_time;
79*4882a593Smuzhiyun 	u16 value;
80*4882a593Smuzhiyun 	u32 update_tag;
81*4882a593Smuzhiyun 	u64 accumulator;
82*4882a593Smuzhiyun } __packed;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun struct power_sensor_a0 {
85*4882a593Smuzhiyun 	u32 sensor_id;
86*4882a593Smuzhiyun 	struct power_sensor_data_and_time system;
87*4882a593Smuzhiyun 	u32 reserved;
88*4882a593Smuzhiyun 	struct power_sensor_data_and_time proc;
89*4882a593Smuzhiyun 	struct power_sensor_data vdd;
90*4882a593Smuzhiyun 	struct power_sensor_data vdn;
91*4882a593Smuzhiyun } __packed;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun struct caps_sensor_2 {
94*4882a593Smuzhiyun 	u16 cap;
95*4882a593Smuzhiyun 	u16 system_power;
96*4882a593Smuzhiyun 	u16 n_cap;
97*4882a593Smuzhiyun 	u16 max;
98*4882a593Smuzhiyun 	u16 min;
99*4882a593Smuzhiyun 	u16 user;
100*4882a593Smuzhiyun 	u8 user_source;
101*4882a593Smuzhiyun } __packed;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun struct caps_sensor_3 {
104*4882a593Smuzhiyun 	u16 cap;
105*4882a593Smuzhiyun 	u16 system_power;
106*4882a593Smuzhiyun 	u16 n_cap;
107*4882a593Smuzhiyun 	u16 max;
108*4882a593Smuzhiyun 	u16 hard_min;
109*4882a593Smuzhiyun 	u16 soft_min;
110*4882a593Smuzhiyun 	u16 user;
111*4882a593Smuzhiyun 	u8 user_source;
112*4882a593Smuzhiyun } __packed;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun struct extended_sensor {
115*4882a593Smuzhiyun 	union {
116*4882a593Smuzhiyun 		u8 name[4];
117*4882a593Smuzhiyun 		u32 sensor_id;
118*4882a593Smuzhiyun 	};
119*4882a593Smuzhiyun 	u8 flags;
120*4882a593Smuzhiyun 	u8 reserved;
121*4882a593Smuzhiyun 	u8 data[6];
122*4882a593Smuzhiyun } __packed;
123*4882a593Smuzhiyun 
occ_poll(struct occ * occ)124*4882a593Smuzhiyun static int occ_poll(struct occ *occ)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun 	int rc;
127*4882a593Smuzhiyun 	u16 checksum = occ->poll_cmd_data + occ->seq_no + 1;
128*4882a593Smuzhiyun 	u8 cmd[8];
129*4882a593Smuzhiyun 	struct occ_poll_response_header *header;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	/* big endian */
132*4882a593Smuzhiyun 	cmd[0] = occ->seq_no++;		/* sequence number */
133*4882a593Smuzhiyun 	cmd[1] = 0;			/* cmd type */
134*4882a593Smuzhiyun 	cmd[2] = 0;			/* data length msb */
135*4882a593Smuzhiyun 	cmd[3] = 1;			/* data length lsb */
136*4882a593Smuzhiyun 	cmd[4] = occ->poll_cmd_data;	/* data */
137*4882a593Smuzhiyun 	cmd[5] = checksum >> 8;		/* checksum msb */
138*4882a593Smuzhiyun 	cmd[6] = checksum & 0xFF;	/* checksum lsb */
139*4882a593Smuzhiyun 	cmd[7] = 0;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	/* mutex should already be locked if necessary */
142*4882a593Smuzhiyun 	rc = occ->send_cmd(occ, cmd);
143*4882a593Smuzhiyun 	if (rc) {
144*4882a593Smuzhiyun 		occ->last_error = rc;
145*4882a593Smuzhiyun 		if (occ->error_count++ > OCC_ERROR_COUNT_THRESHOLD)
146*4882a593Smuzhiyun 			occ->error = rc;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 		goto done;
149*4882a593Smuzhiyun 	}
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	/* clear error since communication was successful */
152*4882a593Smuzhiyun 	occ->error_count = 0;
153*4882a593Smuzhiyun 	occ->last_error = 0;
154*4882a593Smuzhiyun 	occ->error = 0;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	/* check for safe state */
157*4882a593Smuzhiyun 	header = (struct occ_poll_response_header *)occ->resp.data;
158*4882a593Smuzhiyun 	if (header->occ_state == OCC_STATE_SAFE) {
159*4882a593Smuzhiyun 		if (occ->last_safe) {
160*4882a593Smuzhiyun 			if (time_after(jiffies,
161*4882a593Smuzhiyun 				       occ->last_safe + OCC_SAFE_TIMEOUT))
162*4882a593Smuzhiyun 				occ->error = -EHOSTDOWN;
163*4882a593Smuzhiyun 		} else {
164*4882a593Smuzhiyun 			occ->last_safe = jiffies;
165*4882a593Smuzhiyun 		}
166*4882a593Smuzhiyun 	} else {
167*4882a593Smuzhiyun 		occ->last_safe = 0;
168*4882a593Smuzhiyun 	}
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun done:
171*4882a593Smuzhiyun 	occ_sysfs_poll_done(occ);
172*4882a593Smuzhiyun 	return rc;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun 
occ_set_user_power_cap(struct occ * occ,u16 user_power_cap)175*4882a593Smuzhiyun static int occ_set_user_power_cap(struct occ *occ, u16 user_power_cap)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun 	int rc;
178*4882a593Smuzhiyun 	u8 cmd[8];
179*4882a593Smuzhiyun 	u16 checksum = 0x24;
180*4882a593Smuzhiyun 	__be16 user_power_cap_be = cpu_to_be16(user_power_cap);
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	cmd[0] = 0;
183*4882a593Smuzhiyun 	cmd[1] = 0x22;
184*4882a593Smuzhiyun 	cmd[2] = 0;
185*4882a593Smuzhiyun 	cmd[3] = 2;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	memcpy(&cmd[4], &user_power_cap_be, 2);
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	checksum += cmd[4] + cmd[5];
190*4882a593Smuzhiyun 	cmd[6] = checksum >> 8;
191*4882a593Smuzhiyun 	cmd[7] = checksum & 0xFF;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	rc = mutex_lock_interruptible(&occ->lock);
194*4882a593Smuzhiyun 	if (rc)
195*4882a593Smuzhiyun 		return rc;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	rc = occ->send_cmd(occ, cmd);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	mutex_unlock(&occ->lock);
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	return rc;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun 
occ_update_response(struct occ * occ)204*4882a593Smuzhiyun int occ_update_response(struct occ *occ)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun 	int rc = mutex_lock_interruptible(&occ->lock);
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	if (rc)
209*4882a593Smuzhiyun 		return rc;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	/* limit the maximum rate of polling the OCC */
212*4882a593Smuzhiyun 	if (time_after(jiffies, occ->next_update)) {
213*4882a593Smuzhiyun 		rc = occ_poll(occ);
214*4882a593Smuzhiyun 		occ->next_update = jiffies + OCC_UPDATE_FREQUENCY;
215*4882a593Smuzhiyun 	} else {
216*4882a593Smuzhiyun 		rc = occ->last_error;
217*4882a593Smuzhiyun 	}
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	mutex_unlock(&occ->lock);
220*4882a593Smuzhiyun 	return rc;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun 
occ_show_temp_1(struct device * dev,struct device_attribute * attr,char * buf)223*4882a593Smuzhiyun static ssize_t occ_show_temp_1(struct device *dev,
224*4882a593Smuzhiyun 			       struct device_attribute *attr, char *buf)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun 	int rc;
227*4882a593Smuzhiyun 	u32 val = 0;
228*4882a593Smuzhiyun 	struct temp_sensor_1 *temp;
229*4882a593Smuzhiyun 	struct occ *occ = dev_get_drvdata(dev);
230*4882a593Smuzhiyun 	struct occ_sensors *sensors = &occ->sensors;
231*4882a593Smuzhiyun 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	rc = occ_update_response(occ);
234*4882a593Smuzhiyun 	if (rc)
235*4882a593Smuzhiyun 		return rc;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	temp = ((struct temp_sensor_1 *)sensors->temp.data) + sattr->index;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	switch (sattr->nr) {
240*4882a593Smuzhiyun 	case 0:
241*4882a593Smuzhiyun 		val = get_unaligned_be16(&temp->sensor_id);
242*4882a593Smuzhiyun 		break;
243*4882a593Smuzhiyun 	case 1:
244*4882a593Smuzhiyun 		/*
245*4882a593Smuzhiyun 		 * If a sensor reading has expired and couldn't be refreshed,
246*4882a593Smuzhiyun 		 * OCC returns 0xFFFF for that sensor.
247*4882a593Smuzhiyun 		 */
248*4882a593Smuzhiyun 		if (temp->value == 0xFFFF)
249*4882a593Smuzhiyun 			return -EREMOTEIO;
250*4882a593Smuzhiyun 		val = get_unaligned_be16(&temp->value) * 1000;
251*4882a593Smuzhiyun 		break;
252*4882a593Smuzhiyun 	default:
253*4882a593Smuzhiyun 		return -EINVAL;
254*4882a593Smuzhiyun 	}
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun 
occ_show_temp_2(struct device * dev,struct device_attribute * attr,char * buf)259*4882a593Smuzhiyun static ssize_t occ_show_temp_2(struct device *dev,
260*4882a593Smuzhiyun 			       struct device_attribute *attr, char *buf)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun 	int rc;
263*4882a593Smuzhiyun 	u32 val = 0;
264*4882a593Smuzhiyun 	struct temp_sensor_2 *temp;
265*4882a593Smuzhiyun 	struct occ *occ = dev_get_drvdata(dev);
266*4882a593Smuzhiyun 	struct occ_sensors *sensors = &occ->sensors;
267*4882a593Smuzhiyun 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	rc = occ_update_response(occ);
270*4882a593Smuzhiyun 	if (rc)
271*4882a593Smuzhiyun 		return rc;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	temp = ((struct temp_sensor_2 *)sensors->temp.data) + sattr->index;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	switch (sattr->nr) {
276*4882a593Smuzhiyun 	case 0:
277*4882a593Smuzhiyun 		val = get_unaligned_be32(&temp->sensor_id);
278*4882a593Smuzhiyun 		break;
279*4882a593Smuzhiyun 	case 1:
280*4882a593Smuzhiyun 		val = temp->value;
281*4882a593Smuzhiyun 		if (val == OCC_TEMP_SENSOR_FAULT)
282*4882a593Smuzhiyun 			return -EREMOTEIO;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 		/*
285*4882a593Smuzhiyun 		 * VRM doesn't return temperature, only alarm bit. This
286*4882a593Smuzhiyun 		 * attribute maps to tempX_alarm instead of tempX_input for
287*4882a593Smuzhiyun 		 * VRM
288*4882a593Smuzhiyun 		 */
289*4882a593Smuzhiyun 		if (temp->fru_type != OCC_FRU_TYPE_VRM) {
290*4882a593Smuzhiyun 			/* sensor not ready */
291*4882a593Smuzhiyun 			if (val == 0)
292*4882a593Smuzhiyun 				return -EAGAIN;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 			val *= 1000;
295*4882a593Smuzhiyun 		}
296*4882a593Smuzhiyun 		break;
297*4882a593Smuzhiyun 	case 2:
298*4882a593Smuzhiyun 		val = temp->fru_type;
299*4882a593Smuzhiyun 		break;
300*4882a593Smuzhiyun 	case 3:
301*4882a593Smuzhiyun 		val = temp->value == OCC_TEMP_SENSOR_FAULT;
302*4882a593Smuzhiyun 		break;
303*4882a593Smuzhiyun 	default:
304*4882a593Smuzhiyun 		return -EINVAL;
305*4882a593Smuzhiyun 	}
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun 
occ_show_freq_1(struct device * dev,struct device_attribute * attr,char * buf)310*4882a593Smuzhiyun static ssize_t occ_show_freq_1(struct device *dev,
311*4882a593Smuzhiyun 			       struct device_attribute *attr, char *buf)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun 	int rc;
314*4882a593Smuzhiyun 	u16 val = 0;
315*4882a593Smuzhiyun 	struct freq_sensor_1 *freq;
316*4882a593Smuzhiyun 	struct occ *occ = dev_get_drvdata(dev);
317*4882a593Smuzhiyun 	struct occ_sensors *sensors = &occ->sensors;
318*4882a593Smuzhiyun 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	rc = occ_update_response(occ);
321*4882a593Smuzhiyun 	if (rc)
322*4882a593Smuzhiyun 		return rc;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	freq = ((struct freq_sensor_1 *)sensors->freq.data) + sattr->index;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	switch (sattr->nr) {
327*4882a593Smuzhiyun 	case 0:
328*4882a593Smuzhiyun 		val = get_unaligned_be16(&freq->sensor_id);
329*4882a593Smuzhiyun 		break;
330*4882a593Smuzhiyun 	case 1:
331*4882a593Smuzhiyun 		val = get_unaligned_be16(&freq->value);
332*4882a593Smuzhiyun 		break;
333*4882a593Smuzhiyun 	default:
334*4882a593Smuzhiyun 		return -EINVAL;
335*4882a593Smuzhiyun 	}
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun 
occ_show_freq_2(struct device * dev,struct device_attribute * attr,char * buf)340*4882a593Smuzhiyun static ssize_t occ_show_freq_2(struct device *dev,
341*4882a593Smuzhiyun 			       struct device_attribute *attr, char *buf)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun 	int rc;
344*4882a593Smuzhiyun 	u32 val = 0;
345*4882a593Smuzhiyun 	struct freq_sensor_2 *freq;
346*4882a593Smuzhiyun 	struct occ *occ = dev_get_drvdata(dev);
347*4882a593Smuzhiyun 	struct occ_sensors *sensors = &occ->sensors;
348*4882a593Smuzhiyun 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	rc = occ_update_response(occ);
351*4882a593Smuzhiyun 	if (rc)
352*4882a593Smuzhiyun 		return rc;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	freq = ((struct freq_sensor_2 *)sensors->freq.data) + sattr->index;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	switch (sattr->nr) {
357*4882a593Smuzhiyun 	case 0:
358*4882a593Smuzhiyun 		val = get_unaligned_be32(&freq->sensor_id);
359*4882a593Smuzhiyun 		break;
360*4882a593Smuzhiyun 	case 1:
361*4882a593Smuzhiyun 		val = get_unaligned_be16(&freq->value);
362*4882a593Smuzhiyun 		break;
363*4882a593Smuzhiyun 	default:
364*4882a593Smuzhiyun 		return -EINVAL;
365*4882a593Smuzhiyun 	}
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun 
occ_show_power_1(struct device * dev,struct device_attribute * attr,char * buf)370*4882a593Smuzhiyun static ssize_t occ_show_power_1(struct device *dev,
371*4882a593Smuzhiyun 				struct device_attribute *attr, char *buf)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun 	int rc;
374*4882a593Smuzhiyun 	u64 val = 0;
375*4882a593Smuzhiyun 	struct power_sensor_1 *power;
376*4882a593Smuzhiyun 	struct occ *occ = dev_get_drvdata(dev);
377*4882a593Smuzhiyun 	struct occ_sensors *sensors = &occ->sensors;
378*4882a593Smuzhiyun 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	rc = occ_update_response(occ);
381*4882a593Smuzhiyun 	if (rc)
382*4882a593Smuzhiyun 		return rc;
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	power = ((struct power_sensor_1 *)sensors->power.data) + sattr->index;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	switch (sattr->nr) {
387*4882a593Smuzhiyun 	case 0:
388*4882a593Smuzhiyun 		val = get_unaligned_be16(&power->sensor_id);
389*4882a593Smuzhiyun 		break;
390*4882a593Smuzhiyun 	case 1:
391*4882a593Smuzhiyun 		val = get_unaligned_be32(&power->accumulator) /
392*4882a593Smuzhiyun 			get_unaligned_be32(&power->update_tag);
393*4882a593Smuzhiyun 		val *= 1000000ULL;
394*4882a593Smuzhiyun 		break;
395*4882a593Smuzhiyun 	case 2:
396*4882a593Smuzhiyun 		val = (u64)get_unaligned_be32(&power->update_tag) *
397*4882a593Smuzhiyun 			   occ->powr_sample_time_us;
398*4882a593Smuzhiyun 		break;
399*4882a593Smuzhiyun 	case 3:
400*4882a593Smuzhiyun 		val = get_unaligned_be16(&power->value) * 1000000ULL;
401*4882a593Smuzhiyun 		break;
402*4882a593Smuzhiyun 	default:
403*4882a593Smuzhiyun 		return -EINVAL;
404*4882a593Smuzhiyun 	}
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val);
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun 
occ_get_powr_avg(u64 * accum,u32 * samples)409*4882a593Smuzhiyun static u64 occ_get_powr_avg(u64 *accum, u32 *samples)
410*4882a593Smuzhiyun {
411*4882a593Smuzhiyun 	u64 divisor = get_unaligned_be32(samples);
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	return (divisor == 0) ? 0 :
414*4882a593Smuzhiyun 		div64_u64(get_unaligned_be64(accum) * 1000000ULL, divisor);
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun 
occ_show_power_2(struct device * dev,struct device_attribute * attr,char * buf)417*4882a593Smuzhiyun static ssize_t occ_show_power_2(struct device *dev,
418*4882a593Smuzhiyun 				struct device_attribute *attr, char *buf)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun 	int rc;
421*4882a593Smuzhiyun 	u64 val = 0;
422*4882a593Smuzhiyun 	struct power_sensor_2 *power;
423*4882a593Smuzhiyun 	struct occ *occ = dev_get_drvdata(dev);
424*4882a593Smuzhiyun 	struct occ_sensors *sensors = &occ->sensors;
425*4882a593Smuzhiyun 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	rc = occ_update_response(occ);
428*4882a593Smuzhiyun 	if (rc)
429*4882a593Smuzhiyun 		return rc;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	power = ((struct power_sensor_2 *)sensors->power.data) + sattr->index;
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	switch (sattr->nr) {
434*4882a593Smuzhiyun 	case 0:
435*4882a593Smuzhiyun 		return snprintf(buf, PAGE_SIZE - 1, "%u_%u_%u\n",
436*4882a593Smuzhiyun 				get_unaligned_be32(&power->sensor_id),
437*4882a593Smuzhiyun 				power->function_id, power->apss_channel);
438*4882a593Smuzhiyun 	case 1:
439*4882a593Smuzhiyun 		val = occ_get_powr_avg(&power->accumulator,
440*4882a593Smuzhiyun 				       &power->update_tag);
441*4882a593Smuzhiyun 		break;
442*4882a593Smuzhiyun 	case 2:
443*4882a593Smuzhiyun 		val = (u64)get_unaligned_be32(&power->update_tag) *
444*4882a593Smuzhiyun 			   occ->powr_sample_time_us;
445*4882a593Smuzhiyun 		break;
446*4882a593Smuzhiyun 	case 3:
447*4882a593Smuzhiyun 		val = get_unaligned_be16(&power->value) * 1000000ULL;
448*4882a593Smuzhiyun 		break;
449*4882a593Smuzhiyun 	default:
450*4882a593Smuzhiyun 		return -EINVAL;
451*4882a593Smuzhiyun 	}
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val);
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun 
occ_show_power_a0(struct device * dev,struct device_attribute * attr,char * buf)456*4882a593Smuzhiyun static ssize_t occ_show_power_a0(struct device *dev,
457*4882a593Smuzhiyun 				 struct device_attribute *attr, char *buf)
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun 	int rc;
460*4882a593Smuzhiyun 	u64 val = 0;
461*4882a593Smuzhiyun 	struct power_sensor_a0 *power;
462*4882a593Smuzhiyun 	struct occ *occ = dev_get_drvdata(dev);
463*4882a593Smuzhiyun 	struct occ_sensors *sensors = &occ->sensors;
464*4882a593Smuzhiyun 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	rc = occ_update_response(occ);
467*4882a593Smuzhiyun 	if (rc)
468*4882a593Smuzhiyun 		return rc;
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	power = ((struct power_sensor_a0 *)sensors->power.data) + sattr->index;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	switch (sattr->nr) {
473*4882a593Smuzhiyun 	case 0:
474*4882a593Smuzhiyun 		return snprintf(buf, PAGE_SIZE - 1, "%u_system\n",
475*4882a593Smuzhiyun 				get_unaligned_be32(&power->sensor_id));
476*4882a593Smuzhiyun 	case 1:
477*4882a593Smuzhiyun 		val = occ_get_powr_avg(&power->system.accumulator,
478*4882a593Smuzhiyun 				       &power->system.update_tag);
479*4882a593Smuzhiyun 		break;
480*4882a593Smuzhiyun 	case 2:
481*4882a593Smuzhiyun 		val = (u64)get_unaligned_be32(&power->system.update_tag) *
482*4882a593Smuzhiyun 			   occ->powr_sample_time_us;
483*4882a593Smuzhiyun 		break;
484*4882a593Smuzhiyun 	case 3:
485*4882a593Smuzhiyun 		val = get_unaligned_be16(&power->system.value) * 1000000ULL;
486*4882a593Smuzhiyun 		break;
487*4882a593Smuzhiyun 	case 4:
488*4882a593Smuzhiyun 		return snprintf(buf, PAGE_SIZE - 1, "%u_proc\n",
489*4882a593Smuzhiyun 				get_unaligned_be32(&power->sensor_id));
490*4882a593Smuzhiyun 	case 5:
491*4882a593Smuzhiyun 		val = occ_get_powr_avg(&power->proc.accumulator,
492*4882a593Smuzhiyun 				       &power->proc.update_tag);
493*4882a593Smuzhiyun 		break;
494*4882a593Smuzhiyun 	case 6:
495*4882a593Smuzhiyun 		val = (u64)get_unaligned_be32(&power->proc.update_tag) *
496*4882a593Smuzhiyun 			   occ->powr_sample_time_us;
497*4882a593Smuzhiyun 		break;
498*4882a593Smuzhiyun 	case 7:
499*4882a593Smuzhiyun 		val = get_unaligned_be16(&power->proc.value) * 1000000ULL;
500*4882a593Smuzhiyun 		break;
501*4882a593Smuzhiyun 	case 8:
502*4882a593Smuzhiyun 		return snprintf(buf, PAGE_SIZE - 1, "%u_vdd\n",
503*4882a593Smuzhiyun 				get_unaligned_be32(&power->sensor_id));
504*4882a593Smuzhiyun 	case 9:
505*4882a593Smuzhiyun 		val = occ_get_powr_avg(&power->vdd.accumulator,
506*4882a593Smuzhiyun 				       &power->vdd.update_tag);
507*4882a593Smuzhiyun 		break;
508*4882a593Smuzhiyun 	case 10:
509*4882a593Smuzhiyun 		val = (u64)get_unaligned_be32(&power->vdd.update_tag) *
510*4882a593Smuzhiyun 			   occ->powr_sample_time_us;
511*4882a593Smuzhiyun 		break;
512*4882a593Smuzhiyun 	case 11:
513*4882a593Smuzhiyun 		val = get_unaligned_be16(&power->vdd.value) * 1000000ULL;
514*4882a593Smuzhiyun 		break;
515*4882a593Smuzhiyun 	case 12:
516*4882a593Smuzhiyun 		return snprintf(buf, PAGE_SIZE - 1, "%u_vdn\n",
517*4882a593Smuzhiyun 				get_unaligned_be32(&power->sensor_id));
518*4882a593Smuzhiyun 	case 13:
519*4882a593Smuzhiyun 		val = occ_get_powr_avg(&power->vdn.accumulator,
520*4882a593Smuzhiyun 				       &power->vdn.update_tag);
521*4882a593Smuzhiyun 		break;
522*4882a593Smuzhiyun 	case 14:
523*4882a593Smuzhiyun 		val = (u64)get_unaligned_be32(&power->vdn.update_tag) *
524*4882a593Smuzhiyun 			   occ->powr_sample_time_us;
525*4882a593Smuzhiyun 		break;
526*4882a593Smuzhiyun 	case 15:
527*4882a593Smuzhiyun 		val = get_unaligned_be16(&power->vdn.value) * 1000000ULL;
528*4882a593Smuzhiyun 		break;
529*4882a593Smuzhiyun 	default:
530*4882a593Smuzhiyun 		return -EINVAL;
531*4882a593Smuzhiyun 	}
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val);
534*4882a593Smuzhiyun }
535*4882a593Smuzhiyun 
occ_show_caps_1_2(struct device * dev,struct device_attribute * attr,char * buf)536*4882a593Smuzhiyun static ssize_t occ_show_caps_1_2(struct device *dev,
537*4882a593Smuzhiyun 				 struct device_attribute *attr, char *buf)
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun 	int rc;
540*4882a593Smuzhiyun 	u64 val = 0;
541*4882a593Smuzhiyun 	struct caps_sensor_2 *caps;
542*4882a593Smuzhiyun 	struct occ *occ = dev_get_drvdata(dev);
543*4882a593Smuzhiyun 	struct occ_sensors *sensors = &occ->sensors;
544*4882a593Smuzhiyun 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun 	rc = occ_update_response(occ);
547*4882a593Smuzhiyun 	if (rc)
548*4882a593Smuzhiyun 		return rc;
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	caps = ((struct caps_sensor_2 *)sensors->caps.data) + sattr->index;
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	switch (sattr->nr) {
553*4882a593Smuzhiyun 	case 0:
554*4882a593Smuzhiyun 		return snprintf(buf, PAGE_SIZE - 1, "system\n");
555*4882a593Smuzhiyun 	case 1:
556*4882a593Smuzhiyun 		val = get_unaligned_be16(&caps->cap) * 1000000ULL;
557*4882a593Smuzhiyun 		break;
558*4882a593Smuzhiyun 	case 2:
559*4882a593Smuzhiyun 		val = get_unaligned_be16(&caps->system_power) * 1000000ULL;
560*4882a593Smuzhiyun 		break;
561*4882a593Smuzhiyun 	case 3:
562*4882a593Smuzhiyun 		val = get_unaligned_be16(&caps->n_cap) * 1000000ULL;
563*4882a593Smuzhiyun 		break;
564*4882a593Smuzhiyun 	case 4:
565*4882a593Smuzhiyun 		val = get_unaligned_be16(&caps->max) * 1000000ULL;
566*4882a593Smuzhiyun 		break;
567*4882a593Smuzhiyun 	case 5:
568*4882a593Smuzhiyun 		val = get_unaligned_be16(&caps->min) * 1000000ULL;
569*4882a593Smuzhiyun 		break;
570*4882a593Smuzhiyun 	case 6:
571*4882a593Smuzhiyun 		val = get_unaligned_be16(&caps->user) * 1000000ULL;
572*4882a593Smuzhiyun 		break;
573*4882a593Smuzhiyun 	case 7:
574*4882a593Smuzhiyun 		if (occ->sensors.caps.version == 1)
575*4882a593Smuzhiyun 			return -EINVAL;
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 		val = caps->user_source;
578*4882a593Smuzhiyun 		break;
579*4882a593Smuzhiyun 	default:
580*4882a593Smuzhiyun 		return -EINVAL;
581*4882a593Smuzhiyun 	}
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val);
584*4882a593Smuzhiyun }
585*4882a593Smuzhiyun 
occ_show_caps_3(struct device * dev,struct device_attribute * attr,char * buf)586*4882a593Smuzhiyun static ssize_t occ_show_caps_3(struct device *dev,
587*4882a593Smuzhiyun 			       struct device_attribute *attr, char *buf)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun 	int rc;
590*4882a593Smuzhiyun 	u64 val = 0;
591*4882a593Smuzhiyun 	struct caps_sensor_3 *caps;
592*4882a593Smuzhiyun 	struct occ *occ = dev_get_drvdata(dev);
593*4882a593Smuzhiyun 	struct occ_sensors *sensors = &occ->sensors;
594*4882a593Smuzhiyun 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	rc = occ_update_response(occ);
597*4882a593Smuzhiyun 	if (rc)
598*4882a593Smuzhiyun 		return rc;
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	caps = ((struct caps_sensor_3 *)sensors->caps.data) + sattr->index;
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	switch (sattr->nr) {
603*4882a593Smuzhiyun 	case 0:
604*4882a593Smuzhiyun 		return snprintf(buf, PAGE_SIZE - 1, "system\n");
605*4882a593Smuzhiyun 	case 1:
606*4882a593Smuzhiyun 		val = get_unaligned_be16(&caps->cap) * 1000000ULL;
607*4882a593Smuzhiyun 		break;
608*4882a593Smuzhiyun 	case 2:
609*4882a593Smuzhiyun 		val = get_unaligned_be16(&caps->system_power) * 1000000ULL;
610*4882a593Smuzhiyun 		break;
611*4882a593Smuzhiyun 	case 3:
612*4882a593Smuzhiyun 		val = get_unaligned_be16(&caps->n_cap) * 1000000ULL;
613*4882a593Smuzhiyun 		break;
614*4882a593Smuzhiyun 	case 4:
615*4882a593Smuzhiyun 		val = get_unaligned_be16(&caps->max) * 1000000ULL;
616*4882a593Smuzhiyun 		break;
617*4882a593Smuzhiyun 	case 5:
618*4882a593Smuzhiyun 		val = get_unaligned_be16(&caps->hard_min) * 1000000ULL;
619*4882a593Smuzhiyun 		break;
620*4882a593Smuzhiyun 	case 6:
621*4882a593Smuzhiyun 		val = get_unaligned_be16(&caps->user) * 1000000ULL;
622*4882a593Smuzhiyun 		break;
623*4882a593Smuzhiyun 	case 7:
624*4882a593Smuzhiyun 		val = caps->user_source;
625*4882a593Smuzhiyun 		break;
626*4882a593Smuzhiyun 	default:
627*4882a593Smuzhiyun 		return -EINVAL;
628*4882a593Smuzhiyun 	}
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val);
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun 
occ_store_caps_user(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)633*4882a593Smuzhiyun static ssize_t occ_store_caps_user(struct device *dev,
634*4882a593Smuzhiyun 				   struct device_attribute *attr,
635*4882a593Smuzhiyun 				   const char *buf, size_t count)
636*4882a593Smuzhiyun {
637*4882a593Smuzhiyun 	int rc;
638*4882a593Smuzhiyun 	u16 user_power_cap;
639*4882a593Smuzhiyun 	unsigned long long value;
640*4882a593Smuzhiyun 	struct occ *occ = dev_get_drvdata(dev);
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	rc = kstrtoull(buf, 0, &value);
643*4882a593Smuzhiyun 	if (rc)
644*4882a593Smuzhiyun 		return rc;
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun 	user_power_cap = div64_u64(value, 1000000ULL); /* microwatt to watt */
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	rc = occ_set_user_power_cap(occ, user_power_cap);
649*4882a593Smuzhiyun 	if (rc)
650*4882a593Smuzhiyun 		return rc;
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	return count;
653*4882a593Smuzhiyun }
654*4882a593Smuzhiyun 
occ_show_extended(struct device * dev,struct device_attribute * attr,char * buf)655*4882a593Smuzhiyun static ssize_t occ_show_extended(struct device *dev,
656*4882a593Smuzhiyun 				 struct device_attribute *attr, char *buf)
657*4882a593Smuzhiyun {
658*4882a593Smuzhiyun 	int rc;
659*4882a593Smuzhiyun 	struct extended_sensor *extn;
660*4882a593Smuzhiyun 	struct occ *occ = dev_get_drvdata(dev);
661*4882a593Smuzhiyun 	struct occ_sensors *sensors = &occ->sensors;
662*4882a593Smuzhiyun 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	rc = occ_update_response(occ);
665*4882a593Smuzhiyun 	if (rc)
666*4882a593Smuzhiyun 		return rc;
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	extn = ((struct extended_sensor *)sensors->extended.data) +
669*4882a593Smuzhiyun 		sattr->index;
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	switch (sattr->nr) {
672*4882a593Smuzhiyun 	case 0:
673*4882a593Smuzhiyun 		if (extn->flags & EXTN_FLAG_SENSOR_ID)
674*4882a593Smuzhiyun 			rc = snprintf(buf, PAGE_SIZE - 1, "%u",
675*4882a593Smuzhiyun 				      get_unaligned_be32(&extn->sensor_id));
676*4882a593Smuzhiyun 		else
677*4882a593Smuzhiyun 			rc = snprintf(buf, PAGE_SIZE - 1, "%02x%02x%02x%02x\n",
678*4882a593Smuzhiyun 				      extn->name[0], extn->name[1],
679*4882a593Smuzhiyun 				      extn->name[2], extn->name[3]);
680*4882a593Smuzhiyun 		break;
681*4882a593Smuzhiyun 	case 1:
682*4882a593Smuzhiyun 		rc = snprintf(buf, PAGE_SIZE - 1, "%02x\n", extn->flags);
683*4882a593Smuzhiyun 		break;
684*4882a593Smuzhiyun 	case 2:
685*4882a593Smuzhiyun 		rc = snprintf(buf, PAGE_SIZE - 1, "%02x%02x%02x%02x%02x%02x\n",
686*4882a593Smuzhiyun 			      extn->data[0], extn->data[1], extn->data[2],
687*4882a593Smuzhiyun 			      extn->data[3], extn->data[4], extn->data[5]);
688*4882a593Smuzhiyun 		break;
689*4882a593Smuzhiyun 	default:
690*4882a593Smuzhiyun 		return -EINVAL;
691*4882a593Smuzhiyun 	}
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 	return rc;
694*4882a593Smuzhiyun }
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun /*
697*4882a593Smuzhiyun  * Some helper macros to make it easier to define an occ_attribute. Since these
698*4882a593Smuzhiyun  * are dynamically allocated, we shouldn't use the existing kernel macros which
699*4882a593Smuzhiyun  * stringify the name argument.
700*4882a593Smuzhiyun  */
701*4882a593Smuzhiyun #define ATTR_OCC(_name, _mode, _show, _store) {				\
702*4882a593Smuzhiyun 	.attr	= {							\
703*4882a593Smuzhiyun 		.name = _name,						\
704*4882a593Smuzhiyun 		.mode = VERIFY_OCTAL_PERMISSIONS(_mode),		\
705*4882a593Smuzhiyun 	},								\
706*4882a593Smuzhiyun 	.show	= _show,						\
707*4882a593Smuzhiyun 	.store	= _store,						\
708*4882a593Smuzhiyun }
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun #define SENSOR_ATTR_OCC(_name, _mode, _show, _store, _nr, _index) {	\
711*4882a593Smuzhiyun 	.dev_attr	= ATTR_OCC(_name, _mode, _show, _store),	\
712*4882a593Smuzhiyun 	.index		= _index,					\
713*4882a593Smuzhiyun 	.nr		= _nr,						\
714*4882a593Smuzhiyun }
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun #define OCC_INIT_ATTR(_name, _mode, _show, _store, _nr, _index)		\
717*4882a593Smuzhiyun 	((struct sensor_device_attribute_2)				\
718*4882a593Smuzhiyun 		SENSOR_ATTR_OCC(_name, _mode, _show, _store, _nr, _index))
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun /*
721*4882a593Smuzhiyun  * Allocate and instatiate sensor_device_attribute_2s. It's most efficient to
722*4882a593Smuzhiyun  * use our own instead of the built-in hwmon attribute types.
723*4882a593Smuzhiyun  */
occ_setup_sensor_attrs(struct occ * occ)724*4882a593Smuzhiyun static int occ_setup_sensor_attrs(struct occ *occ)
725*4882a593Smuzhiyun {
726*4882a593Smuzhiyun 	unsigned int i, s, num_attrs = 0;
727*4882a593Smuzhiyun 	struct device *dev = occ->bus_dev;
728*4882a593Smuzhiyun 	struct occ_sensors *sensors = &occ->sensors;
729*4882a593Smuzhiyun 	struct occ_attribute *attr;
730*4882a593Smuzhiyun 	struct temp_sensor_2 *temp;
731*4882a593Smuzhiyun 	ssize_t (*show_temp)(struct device *, struct device_attribute *,
732*4882a593Smuzhiyun 			     char *) = occ_show_temp_1;
733*4882a593Smuzhiyun 	ssize_t (*show_freq)(struct device *, struct device_attribute *,
734*4882a593Smuzhiyun 			     char *) = occ_show_freq_1;
735*4882a593Smuzhiyun 	ssize_t (*show_power)(struct device *, struct device_attribute *,
736*4882a593Smuzhiyun 			      char *) = occ_show_power_1;
737*4882a593Smuzhiyun 	ssize_t (*show_caps)(struct device *, struct device_attribute *,
738*4882a593Smuzhiyun 			     char *) = occ_show_caps_1_2;
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 	switch (sensors->temp.version) {
741*4882a593Smuzhiyun 	case 1:
742*4882a593Smuzhiyun 		num_attrs += (sensors->temp.num_sensors * 2);
743*4882a593Smuzhiyun 		break;
744*4882a593Smuzhiyun 	case 2:
745*4882a593Smuzhiyun 		num_attrs += (sensors->temp.num_sensors * 4);
746*4882a593Smuzhiyun 		show_temp = occ_show_temp_2;
747*4882a593Smuzhiyun 		break;
748*4882a593Smuzhiyun 	default:
749*4882a593Smuzhiyun 		sensors->temp.num_sensors = 0;
750*4882a593Smuzhiyun 	}
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	switch (sensors->freq.version) {
753*4882a593Smuzhiyun 	case 2:
754*4882a593Smuzhiyun 		show_freq = occ_show_freq_2;
755*4882a593Smuzhiyun 		fallthrough;
756*4882a593Smuzhiyun 	case 1:
757*4882a593Smuzhiyun 		num_attrs += (sensors->freq.num_sensors * 2);
758*4882a593Smuzhiyun 		break;
759*4882a593Smuzhiyun 	default:
760*4882a593Smuzhiyun 		sensors->freq.num_sensors = 0;
761*4882a593Smuzhiyun 	}
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 	switch (sensors->power.version) {
764*4882a593Smuzhiyun 	case 2:
765*4882a593Smuzhiyun 		show_power = occ_show_power_2;
766*4882a593Smuzhiyun 		fallthrough;
767*4882a593Smuzhiyun 	case 1:
768*4882a593Smuzhiyun 		num_attrs += (sensors->power.num_sensors * 4);
769*4882a593Smuzhiyun 		break;
770*4882a593Smuzhiyun 	case 0xA0:
771*4882a593Smuzhiyun 		num_attrs += (sensors->power.num_sensors * 16);
772*4882a593Smuzhiyun 		show_power = occ_show_power_a0;
773*4882a593Smuzhiyun 		break;
774*4882a593Smuzhiyun 	default:
775*4882a593Smuzhiyun 		sensors->power.num_sensors = 0;
776*4882a593Smuzhiyun 	}
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 	switch (sensors->caps.version) {
779*4882a593Smuzhiyun 	case 1:
780*4882a593Smuzhiyun 		num_attrs += (sensors->caps.num_sensors * 7);
781*4882a593Smuzhiyun 		break;
782*4882a593Smuzhiyun 	case 3:
783*4882a593Smuzhiyun 		show_caps = occ_show_caps_3;
784*4882a593Smuzhiyun 		fallthrough;
785*4882a593Smuzhiyun 	case 2:
786*4882a593Smuzhiyun 		num_attrs += (sensors->caps.num_sensors * 8);
787*4882a593Smuzhiyun 		break;
788*4882a593Smuzhiyun 	default:
789*4882a593Smuzhiyun 		sensors->caps.num_sensors = 0;
790*4882a593Smuzhiyun 	}
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 	switch (sensors->extended.version) {
793*4882a593Smuzhiyun 	case 1:
794*4882a593Smuzhiyun 		num_attrs += (sensors->extended.num_sensors * 3);
795*4882a593Smuzhiyun 		break;
796*4882a593Smuzhiyun 	default:
797*4882a593Smuzhiyun 		sensors->extended.num_sensors = 0;
798*4882a593Smuzhiyun 	}
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 	occ->attrs = devm_kzalloc(dev, sizeof(*occ->attrs) * num_attrs,
801*4882a593Smuzhiyun 				  GFP_KERNEL);
802*4882a593Smuzhiyun 	if (!occ->attrs)
803*4882a593Smuzhiyun 		return -ENOMEM;
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun 	/* null-terminated list */
806*4882a593Smuzhiyun 	occ->group.attrs = devm_kzalloc(dev, sizeof(*occ->group.attrs) *
807*4882a593Smuzhiyun 					num_attrs + 1, GFP_KERNEL);
808*4882a593Smuzhiyun 	if (!occ->group.attrs)
809*4882a593Smuzhiyun 		return -ENOMEM;
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun 	attr = occ->attrs;
812*4882a593Smuzhiyun 
813*4882a593Smuzhiyun 	for (i = 0; i < sensors->temp.num_sensors; ++i) {
814*4882a593Smuzhiyun 		s = i + 1;
815*4882a593Smuzhiyun 		temp = ((struct temp_sensor_2 *)sensors->temp.data) + i;
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun 		snprintf(attr->name, sizeof(attr->name), "temp%d_label", s);
818*4882a593Smuzhiyun 		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_temp, NULL,
819*4882a593Smuzhiyun 					     0, i);
820*4882a593Smuzhiyun 		attr++;
821*4882a593Smuzhiyun 
822*4882a593Smuzhiyun 		if (sensors->temp.version > 1 &&
823*4882a593Smuzhiyun 		    temp->fru_type == OCC_FRU_TYPE_VRM) {
824*4882a593Smuzhiyun 			snprintf(attr->name, sizeof(attr->name),
825*4882a593Smuzhiyun 				 "temp%d_alarm", s);
826*4882a593Smuzhiyun 		} else {
827*4882a593Smuzhiyun 			snprintf(attr->name, sizeof(attr->name),
828*4882a593Smuzhiyun 				 "temp%d_input", s);
829*4882a593Smuzhiyun 		}
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun 		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_temp, NULL,
832*4882a593Smuzhiyun 					     1, i);
833*4882a593Smuzhiyun 		attr++;
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun 		if (sensors->temp.version > 1) {
836*4882a593Smuzhiyun 			snprintf(attr->name, sizeof(attr->name),
837*4882a593Smuzhiyun 				 "temp%d_fru_type", s);
838*4882a593Smuzhiyun 			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
839*4882a593Smuzhiyun 						     show_temp, NULL, 2, i);
840*4882a593Smuzhiyun 			attr++;
841*4882a593Smuzhiyun 
842*4882a593Smuzhiyun 			snprintf(attr->name, sizeof(attr->name),
843*4882a593Smuzhiyun 				 "temp%d_fault", s);
844*4882a593Smuzhiyun 			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
845*4882a593Smuzhiyun 						     show_temp, NULL, 3, i);
846*4882a593Smuzhiyun 			attr++;
847*4882a593Smuzhiyun 		}
848*4882a593Smuzhiyun 	}
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun 	for (i = 0; i < sensors->freq.num_sensors; ++i) {
851*4882a593Smuzhiyun 		s = i + 1;
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun 		snprintf(attr->name, sizeof(attr->name), "freq%d_label", s);
854*4882a593Smuzhiyun 		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_freq, NULL,
855*4882a593Smuzhiyun 					     0, i);
856*4882a593Smuzhiyun 		attr++;
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun 		snprintf(attr->name, sizeof(attr->name), "freq%d_input", s);
859*4882a593Smuzhiyun 		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_freq, NULL,
860*4882a593Smuzhiyun 					     1, i);
861*4882a593Smuzhiyun 		attr++;
862*4882a593Smuzhiyun 	}
863*4882a593Smuzhiyun 
864*4882a593Smuzhiyun 	if (sensors->power.version == 0xA0) {
865*4882a593Smuzhiyun 		/*
866*4882a593Smuzhiyun 		 * Special case for many-attribute power sensor. Split it into
867*4882a593Smuzhiyun 		 * a sensor number per power type, emulating several sensors.
868*4882a593Smuzhiyun 		 */
869*4882a593Smuzhiyun 		for (i = 0; i < sensors->power.num_sensors; ++i) {
870*4882a593Smuzhiyun 			unsigned int j;
871*4882a593Smuzhiyun 			unsigned int nr = 0;
872*4882a593Smuzhiyun 
873*4882a593Smuzhiyun 			s = (i * 4) + 1;
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun 			for (j = 0; j < 4; ++j) {
876*4882a593Smuzhiyun 				snprintf(attr->name, sizeof(attr->name),
877*4882a593Smuzhiyun 					 "power%d_label", s);
878*4882a593Smuzhiyun 				attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
879*4882a593Smuzhiyun 							     show_power, NULL,
880*4882a593Smuzhiyun 							     nr++, i);
881*4882a593Smuzhiyun 				attr++;
882*4882a593Smuzhiyun 
883*4882a593Smuzhiyun 				snprintf(attr->name, sizeof(attr->name),
884*4882a593Smuzhiyun 					 "power%d_average", s);
885*4882a593Smuzhiyun 				attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
886*4882a593Smuzhiyun 							     show_power, NULL,
887*4882a593Smuzhiyun 							     nr++, i);
888*4882a593Smuzhiyun 				attr++;
889*4882a593Smuzhiyun 
890*4882a593Smuzhiyun 				snprintf(attr->name, sizeof(attr->name),
891*4882a593Smuzhiyun 					 "power%d_average_interval", s);
892*4882a593Smuzhiyun 				attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
893*4882a593Smuzhiyun 							     show_power, NULL,
894*4882a593Smuzhiyun 							     nr++, i);
895*4882a593Smuzhiyun 				attr++;
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun 				snprintf(attr->name, sizeof(attr->name),
898*4882a593Smuzhiyun 					 "power%d_input", s);
899*4882a593Smuzhiyun 				attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
900*4882a593Smuzhiyun 							     show_power, NULL,
901*4882a593Smuzhiyun 							     nr++, i);
902*4882a593Smuzhiyun 				attr++;
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun 				s++;
905*4882a593Smuzhiyun 			}
906*4882a593Smuzhiyun 		}
907*4882a593Smuzhiyun 
908*4882a593Smuzhiyun 		s = (sensors->power.num_sensors * 4) + 1;
909*4882a593Smuzhiyun 	} else {
910*4882a593Smuzhiyun 		for (i = 0; i < sensors->power.num_sensors; ++i) {
911*4882a593Smuzhiyun 			s = i + 1;
912*4882a593Smuzhiyun 
913*4882a593Smuzhiyun 			snprintf(attr->name, sizeof(attr->name),
914*4882a593Smuzhiyun 				 "power%d_label", s);
915*4882a593Smuzhiyun 			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
916*4882a593Smuzhiyun 						     show_power, NULL, 0, i);
917*4882a593Smuzhiyun 			attr++;
918*4882a593Smuzhiyun 
919*4882a593Smuzhiyun 			snprintf(attr->name, sizeof(attr->name),
920*4882a593Smuzhiyun 				 "power%d_average", s);
921*4882a593Smuzhiyun 			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
922*4882a593Smuzhiyun 						     show_power, NULL, 1, i);
923*4882a593Smuzhiyun 			attr++;
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun 			snprintf(attr->name, sizeof(attr->name),
926*4882a593Smuzhiyun 				 "power%d_average_interval", s);
927*4882a593Smuzhiyun 			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
928*4882a593Smuzhiyun 						     show_power, NULL, 2, i);
929*4882a593Smuzhiyun 			attr++;
930*4882a593Smuzhiyun 
931*4882a593Smuzhiyun 			snprintf(attr->name, sizeof(attr->name),
932*4882a593Smuzhiyun 				 "power%d_input", s);
933*4882a593Smuzhiyun 			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
934*4882a593Smuzhiyun 						     show_power, NULL, 3, i);
935*4882a593Smuzhiyun 			attr++;
936*4882a593Smuzhiyun 		}
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun 		s = sensors->power.num_sensors + 1;
939*4882a593Smuzhiyun 	}
940*4882a593Smuzhiyun 
941*4882a593Smuzhiyun 	if (sensors->caps.num_sensors >= 1) {
942*4882a593Smuzhiyun 		snprintf(attr->name, sizeof(attr->name), "power%d_label", s);
943*4882a593Smuzhiyun 		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
944*4882a593Smuzhiyun 					     0, 0);
945*4882a593Smuzhiyun 		attr++;
946*4882a593Smuzhiyun 
947*4882a593Smuzhiyun 		snprintf(attr->name, sizeof(attr->name), "power%d_cap", s);
948*4882a593Smuzhiyun 		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
949*4882a593Smuzhiyun 					     1, 0);
950*4882a593Smuzhiyun 		attr++;
951*4882a593Smuzhiyun 
952*4882a593Smuzhiyun 		snprintf(attr->name, sizeof(attr->name), "power%d_input", s);
953*4882a593Smuzhiyun 		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
954*4882a593Smuzhiyun 					     2, 0);
955*4882a593Smuzhiyun 		attr++;
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun 		snprintf(attr->name, sizeof(attr->name),
958*4882a593Smuzhiyun 			 "power%d_cap_not_redundant", s);
959*4882a593Smuzhiyun 		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
960*4882a593Smuzhiyun 					     3, 0);
961*4882a593Smuzhiyun 		attr++;
962*4882a593Smuzhiyun 
963*4882a593Smuzhiyun 		snprintf(attr->name, sizeof(attr->name), "power%d_cap_max", s);
964*4882a593Smuzhiyun 		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
965*4882a593Smuzhiyun 					     4, 0);
966*4882a593Smuzhiyun 		attr++;
967*4882a593Smuzhiyun 
968*4882a593Smuzhiyun 		snprintf(attr->name, sizeof(attr->name), "power%d_cap_min", s);
969*4882a593Smuzhiyun 		attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
970*4882a593Smuzhiyun 					     5, 0);
971*4882a593Smuzhiyun 		attr++;
972*4882a593Smuzhiyun 
973*4882a593Smuzhiyun 		snprintf(attr->name, sizeof(attr->name), "power%d_cap_user",
974*4882a593Smuzhiyun 			 s);
975*4882a593Smuzhiyun 		attr->sensor = OCC_INIT_ATTR(attr->name, 0644, show_caps,
976*4882a593Smuzhiyun 					     occ_store_caps_user, 6, 0);
977*4882a593Smuzhiyun 		attr++;
978*4882a593Smuzhiyun 
979*4882a593Smuzhiyun 		if (sensors->caps.version > 1) {
980*4882a593Smuzhiyun 			snprintf(attr->name, sizeof(attr->name),
981*4882a593Smuzhiyun 				 "power%d_cap_user_source", s);
982*4882a593Smuzhiyun 			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
983*4882a593Smuzhiyun 						     show_caps, NULL, 7, 0);
984*4882a593Smuzhiyun 			attr++;
985*4882a593Smuzhiyun 		}
986*4882a593Smuzhiyun 	}
987*4882a593Smuzhiyun 
988*4882a593Smuzhiyun 	for (i = 0; i < sensors->extended.num_sensors; ++i) {
989*4882a593Smuzhiyun 		s = i + 1;
990*4882a593Smuzhiyun 
991*4882a593Smuzhiyun 		snprintf(attr->name, sizeof(attr->name), "extn%d_label", s);
992*4882a593Smuzhiyun 		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
993*4882a593Smuzhiyun 					     occ_show_extended, NULL, 0, i);
994*4882a593Smuzhiyun 		attr++;
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun 		snprintf(attr->name, sizeof(attr->name), "extn%d_flags", s);
997*4882a593Smuzhiyun 		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
998*4882a593Smuzhiyun 					     occ_show_extended, NULL, 1, i);
999*4882a593Smuzhiyun 		attr++;
1000*4882a593Smuzhiyun 
1001*4882a593Smuzhiyun 		snprintf(attr->name, sizeof(attr->name), "extn%d_input", s);
1002*4882a593Smuzhiyun 		attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
1003*4882a593Smuzhiyun 					     occ_show_extended, NULL, 2, i);
1004*4882a593Smuzhiyun 		attr++;
1005*4882a593Smuzhiyun 	}
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 	/* put the sensors in the group */
1008*4882a593Smuzhiyun 	for (i = 0; i < num_attrs; ++i) {
1009*4882a593Smuzhiyun 		sysfs_attr_init(&occ->attrs[i].sensor.dev_attr.attr);
1010*4882a593Smuzhiyun 		occ->group.attrs[i] = &occ->attrs[i].sensor.dev_attr.attr;
1011*4882a593Smuzhiyun 	}
1012*4882a593Smuzhiyun 
1013*4882a593Smuzhiyun 	return 0;
1014*4882a593Smuzhiyun }
1015*4882a593Smuzhiyun 
1016*4882a593Smuzhiyun /* only need to do this once at startup, as OCC won't change sensors on us */
occ_parse_poll_response(struct occ * occ)1017*4882a593Smuzhiyun static void occ_parse_poll_response(struct occ *occ)
1018*4882a593Smuzhiyun {
1019*4882a593Smuzhiyun 	unsigned int i, old_offset, offset = 0, size = 0;
1020*4882a593Smuzhiyun 	struct occ_sensor *sensor;
1021*4882a593Smuzhiyun 	struct occ_sensors *sensors = &occ->sensors;
1022*4882a593Smuzhiyun 	struct occ_response *resp = &occ->resp;
1023*4882a593Smuzhiyun 	struct occ_poll_response *poll =
1024*4882a593Smuzhiyun 		(struct occ_poll_response *)&resp->data[0];
1025*4882a593Smuzhiyun 	struct occ_poll_response_header *header = &poll->header;
1026*4882a593Smuzhiyun 	struct occ_sensor_data_block *block = &poll->block;
1027*4882a593Smuzhiyun 
1028*4882a593Smuzhiyun 	dev_info(occ->bus_dev, "OCC found, code level: %.16s\n",
1029*4882a593Smuzhiyun 		 header->occ_code_level);
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun 	for (i = 0; i < header->num_sensor_data_blocks; ++i) {
1032*4882a593Smuzhiyun 		block = (struct occ_sensor_data_block *)((u8 *)block + offset);
1033*4882a593Smuzhiyun 		old_offset = offset;
1034*4882a593Smuzhiyun 		offset = (block->header.num_sensors *
1035*4882a593Smuzhiyun 			  block->header.sensor_length) + sizeof(block->header);
1036*4882a593Smuzhiyun 		size += offset;
1037*4882a593Smuzhiyun 
1038*4882a593Smuzhiyun 		/* validate all the length/size fields */
1039*4882a593Smuzhiyun 		if ((size + sizeof(*header)) >= OCC_RESP_DATA_BYTES) {
1040*4882a593Smuzhiyun 			dev_warn(occ->bus_dev, "exceeded response buffer\n");
1041*4882a593Smuzhiyun 			return;
1042*4882a593Smuzhiyun 		}
1043*4882a593Smuzhiyun 
1044*4882a593Smuzhiyun 		dev_dbg(occ->bus_dev, " %04x..%04x: %.4s (%d sensors)\n",
1045*4882a593Smuzhiyun 			old_offset, offset - 1, block->header.eye_catcher,
1046*4882a593Smuzhiyun 			block->header.num_sensors);
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun 		/* match sensor block type */
1049*4882a593Smuzhiyun 		if (strncmp(block->header.eye_catcher, "TEMP", 4) == 0)
1050*4882a593Smuzhiyun 			sensor = &sensors->temp;
1051*4882a593Smuzhiyun 		else if (strncmp(block->header.eye_catcher, "FREQ", 4) == 0)
1052*4882a593Smuzhiyun 			sensor = &sensors->freq;
1053*4882a593Smuzhiyun 		else if (strncmp(block->header.eye_catcher, "POWR", 4) == 0)
1054*4882a593Smuzhiyun 			sensor = &sensors->power;
1055*4882a593Smuzhiyun 		else if (strncmp(block->header.eye_catcher, "CAPS", 4) == 0)
1056*4882a593Smuzhiyun 			sensor = &sensors->caps;
1057*4882a593Smuzhiyun 		else if (strncmp(block->header.eye_catcher, "EXTN", 4) == 0)
1058*4882a593Smuzhiyun 			sensor = &sensors->extended;
1059*4882a593Smuzhiyun 		else {
1060*4882a593Smuzhiyun 			dev_warn(occ->bus_dev, "sensor not supported %.4s\n",
1061*4882a593Smuzhiyun 				 block->header.eye_catcher);
1062*4882a593Smuzhiyun 			continue;
1063*4882a593Smuzhiyun 		}
1064*4882a593Smuzhiyun 
1065*4882a593Smuzhiyun 		sensor->num_sensors = block->header.num_sensors;
1066*4882a593Smuzhiyun 		sensor->version = block->header.sensor_format;
1067*4882a593Smuzhiyun 		sensor->data = &block->data;
1068*4882a593Smuzhiyun 	}
1069*4882a593Smuzhiyun 
1070*4882a593Smuzhiyun 	dev_dbg(occ->bus_dev, "Max resp size: %u+%zd=%zd\n", size,
1071*4882a593Smuzhiyun 		sizeof(*header), size + sizeof(*header));
1072*4882a593Smuzhiyun }
1073*4882a593Smuzhiyun 
occ_setup(struct occ * occ,const char * name)1074*4882a593Smuzhiyun int occ_setup(struct occ *occ, const char *name)
1075*4882a593Smuzhiyun {
1076*4882a593Smuzhiyun 	int rc;
1077*4882a593Smuzhiyun 
1078*4882a593Smuzhiyun 	mutex_init(&occ->lock);
1079*4882a593Smuzhiyun 	occ->groups[0] = &occ->group;
1080*4882a593Smuzhiyun 
1081*4882a593Smuzhiyun 	/* no need to lock */
1082*4882a593Smuzhiyun 	rc = occ_poll(occ);
1083*4882a593Smuzhiyun 	if (rc == -ESHUTDOWN) {
1084*4882a593Smuzhiyun 		dev_info(occ->bus_dev, "host is not ready\n");
1085*4882a593Smuzhiyun 		return rc;
1086*4882a593Smuzhiyun 	} else if (rc < 0) {
1087*4882a593Smuzhiyun 		dev_err(occ->bus_dev, "failed to get OCC poll response: %d\n",
1088*4882a593Smuzhiyun 			rc);
1089*4882a593Smuzhiyun 		return rc;
1090*4882a593Smuzhiyun 	}
1091*4882a593Smuzhiyun 
1092*4882a593Smuzhiyun 	occ->next_update = jiffies + OCC_UPDATE_FREQUENCY;
1093*4882a593Smuzhiyun 	occ_parse_poll_response(occ);
1094*4882a593Smuzhiyun 
1095*4882a593Smuzhiyun 	rc = occ_setup_sensor_attrs(occ);
1096*4882a593Smuzhiyun 	if (rc) {
1097*4882a593Smuzhiyun 		dev_err(occ->bus_dev, "failed to setup sensor attrs: %d\n",
1098*4882a593Smuzhiyun 			rc);
1099*4882a593Smuzhiyun 		return rc;
1100*4882a593Smuzhiyun 	}
1101*4882a593Smuzhiyun 
1102*4882a593Smuzhiyun 	occ->hwmon = devm_hwmon_device_register_with_groups(occ->bus_dev, name,
1103*4882a593Smuzhiyun 							    occ, occ->groups);
1104*4882a593Smuzhiyun 	if (IS_ERR(occ->hwmon)) {
1105*4882a593Smuzhiyun 		rc = PTR_ERR(occ->hwmon);
1106*4882a593Smuzhiyun 		dev_err(occ->bus_dev, "failed to register hwmon device: %d\n",
1107*4882a593Smuzhiyun 			rc);
1108*4882a593Smuzhiyun 		return rc;
1109*4882a593Smuzhiyun 	}
1110*4882a593Smuzhiyun 
1111*4882a593Smuzhiyun 	rc = occ_setup_sysfs(occ);
1112*4882a593Smuzhiyun 	if (rc)
1113*4882a593Smuzhiyun 		dev_err(occ->bus_dev, "failed to setup sysfs: %d\n", rc);
1114*4882a593Smuzhiyun 
1115*4882a593Smuzhiyun 	return rc;
1116*4882a593Smuzhiyun }
1117*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(occ_setup);
1118*4882a593Smuzhiyun 
1119*4882a593Smuzhiyun MODULE_AUTHOR("Eddie James <eajames@linux.ibm.com>");
1120*4882a593Smuzhiyun MODULE_DESCRIPTION("Common OCC hwmon code");
1121*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1122