xref: /openbmc/linux/drivers/hwmon/occ/common.h (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1e2f05d60SEddie James /* SPDX-License-Identifier: GPL-2.0+ */
2e2f05d60SEddie James /* Copyright IBM Corp 2019 */
35b5513b8SEddie James 
45b5513b8SEddie James #ifndef OCC_COMMON_H
55b5513b8SEddie James #define OCC_COMMON_H
65b5513b8SEddie James 
754076cb3SEddie James #include <linux/hwmon-sysfs.h>
8c10e753dSEddie James #include <linux/mutex.h>
954076cb3SEddie James #include <linux/sysfs.h>
10c10e753dSEddie James 
115b5513b8SEddie James struct device;
125b5513b8SEddie James 
135b5513b8SEddie James #define OCC_RESP_DATA_BYTES		4089
145b5513b8SEddie James 
155b5513b8SEddie James /*
165b5513b8SEddie James  * Same response format for all OCC versions.
175b5513b8SEddie James  * Allocate the largest possible response.
185b5513b8SEddie James  */
195b5513b8SEddie James struct occ_response {
205b5513b8SEddie James 	u8 seq_no;
215b5513b8SEddie James 	u8 cmd_type;
225b5513b8SEddie James 	u8 return_status;
235b5513b8SEddie James 	__be16 data_length;
245b5513b8SEddie James 	u8 data[OCC_RESP_DATA_BYTES];
255b5513b8SEddie James 	__be16 checksum;
265b5513b8SEddie James } __packed;
275b5513b8SEddie James 
28aa195fe4SEddie James struct occ_sensor_data_block_header {
29aa195fe4SEddie James 	u8 eye_catcher[4];
30aa195fe4SEddie James 	u8 reserved;
31aa195fe4SEddie James 	u8 sensor_format;
32aa195fe4SEddie James 	u8 sensor_length;
33aa195fe4SEddie James 	u8 num_sensors;
34aa195fe4SEddie James } __packed;
35aa195fe4SEddie James 
36aa195fe4SEddie James struct occ_sensor_data_block {
37aa195fe4SEddie James 	struct occ_sensor_data_block_header header;
38aa195fe4SEddie James 	u32 data;
39aa195fe4SEddie James } __packed;
40aa195fe4SEddie James 
41aa195fe4SEddie James struct occ_poll_response_header {
42aa195fe4SEddie James 	u8 status;
43aa195fe4SEddie James 	u8 ext_status;
44aa195fe4SEddie James 	u8 occs_present;
45aa195fe4SEddie James 	u8 config_data;
46aa195fe4SEddie James 	u8 occ_state;
47aa195fe4SEddie James 	u8 mode;
48aa195fe4SEddie James 	u8 ips_status;
49aa195fe4SEddie James 	u8 error_log_id;
50aa195fe4SEddie James 	__be32 error_log_start_address;
51aa195fe4SEddie James 	__be16 error_log_length;
52aa195fe4SEddie James 	u16 reserved;
53aa195fe4SEddie James 	u8 occ_code_level[16];
54aa195fe4SEddie James 	u8 eye_catcher[6];
55aa195fe4SEddie James 	u8 num_sensor_data_blocks;
56aa195fe4SEddie James 	u8 sensor_data_block_header_version;
57aa195fe4SEddie James } __packed;
58aa195fe4SEddie James 
59aa195fe4SEddie James struct occ_poll_response {
60aa195fe4SEddie James 	struct occ_poll_response_header header;
61aa195fe4SEddie James 	struct occ_sensor_data_block block;
62aa195fe4SEddie James } __packed;
63aa195fe4SEddie James 
64aa195fe4SEddie James struct occ_sensor {
65aa195fe4SEddie James 	u8 num_sensors;
66aa195fe4SEddie James 	u8 version;
67aa195fe4SEddie James 	void *data;	/* pointer to sensor data start within response */
68aa195fe4SEddie James };
69aa195fe4SEddie James 
70aa195fe4SEddie James /*
71aa195fe4SEddie James  * OCC only provides one sensor data block of each type, but any number of
72aa195fe4SEddie James  * sensors within that block.
73aa195fe4SEddie James  */
74aa195fe4SEddie James struct occ_sensors {
75aa195fe4SEddie James 	struct occ_sensor temp;
76aa195fe4SEddie James 	struct occ_sensor freq;
77aa195fe4SEddie James 	struct occ_sensor power;
78aa195fe4SEddie James 	struct occ_sensor caps;
79aa195fe4SEddie James 	struct occ_sensor extended;
80aa195fe4SEddie James };
81aa195fe4SEddie James 
8254076cb3SEddie James /*
8354076cb3SEddie James  * Use our own attribute struct so we can dynamically allocate space for the
8454076cb3SEddie James  * name.
8554076cb3SEddie James  */
8654076cb3SEddie James struct occ_attribute {
8754076cb3SEddie James 	char name[32];
8854076cb3SEddie James 	struct sensor_device_attribute_2 sensor;
8954076cb3SEddie James };
9054076cb3SEddie James 
915b5513b8SEddie James struct occ {
925b5513b8SEddie James 	struct device *bus_dev;
935b5513b8SEddie James 
945b5513b8SEddie James 	struct occ_response resp;
95aa195fe4SEddie James 	struct occ_sensors sensors;
965b5513b8SEddie James 
97c10e753dSEddie James 	int powr_sample_time_us;	/* average power sample time */
985b5513b8SEddie James 	u8 poll_cmd_data;		/* to perform OCC poll command */
99*1bbb2809SEddie James 	int (*send_cmd)(struct occ *occ, u8 *cmd, size_t len, void *resp,
100*1bbb2809SEddie James 			size_t resp_len);
101c10e753dSEddie James 
1025216dff2SEddie James 	unsigned long next_update;
103c10e753dSEddie James 	struct mutex lock;		/* lock OCC access */
10454076cb3SEddie James 
10554076cb3SEddie James 	struct device *hwmon;
10654076cb3SEddie James 	struct occ_attribute *attrs;
10754076cb3SEddie James 	struct attribute_group group;
10854076cb3SEddie James 	const struct attribute_group *groups[2];
109df04ced6SEddie James 
110849b0156SEddie James 	bool active;
111b5c46a53SEddie James 	int error;                      /* final transfer error after retry */
112b5c46a53SEddie James 	int last_error;			/* latest transfer error */
113df04ced6SEddie James 	unsigned int error_count;       /* number of xfr errors observed */
114df04ced6SEddie James 	unsigned long last_safe;        /* time OCC entered "safe" state */
115df04ced6SEddie James 
116df04ced6SEddie James 	/*
117df04ced6SEddie James 	 * Store the previous state data for comparison in order to notify
118df04ced6SEddie James 	 * sysfs readers of state changes.
119df04ced6SEddie James 	 */
120df04ced6SEddie James 	int prev_error;
121df04ced6SEddie James 	u8 prev_stat;
122df04ced6SEddie James 	u8 prev_ext_stat;
123df04ced6SEddie James 	u8 prev_occs_present;
1246109c3e1SEddie James 	u8 prev_ips_status;
125a25126fcSEddie James 	u8 prev_mode;
1265b5513b8SEddie James };
1275b5513b8SEddie James 
128849b0156SEddie James int occ_active(struct occ *occ, bool active);
129849b0156SEddie James int occ_setup(struct occ *occ);
130df04ced6SEddie James int occ_setup_sysfs(struct occ *occ);
131df04ced6SEddie James void occ_shutdown(struct occ *occ);
132849b0156SEddie James void occ_shutdown_sysfs(struct occ *occ);
133df04ced6SEddie James void occ_sysfs_poll_done(struct occ *occ);
134df04ced6SEddie James int occ_update_response(struct occ *occ);
1355b5513b8SEddie James 
1365b5513b8SEddie James #endif /* OCC_COMMON_H */
137