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