/* SPDX-License-Identifier: GPL-2.0+ */ /* Copyright IBM Corp 2019 */ #ifndef OCC_COMMON_H #define OCC_COMMON_H #include <linux/hwmon-sysfs.h> #include <linux/mutex.h> #include <linux/sysfs.h> struct device; #define OCC_RESP_DATA_BYTES 4089 /* * Same response format for all OCC versions. * Allocate the largest possible response. */ struct occ_response { u8 seq_no; u8 cmd_type; u8 return_status; __be16 data_length; u8 data[OCC_RESP_DATA_BYTES]; __be16 checksum; } __packed; struct occ_sensor_data_block_header { u8 eye_catcher[4]; u8 reserved; u8 sensor_format; u8 sensor_length; u8 num_sensors; } __packed; struct occ_sensor_data_block { struct occ_sensor_data_block_header header; u32 data; } __packed; struct occ_poll_response_header { u8 status; u8 ext_status; u8 occs_present; u8 config_data; u8 occ_state; u8 mode; u8 ips_status; u8 error_log_id; __be32 error_log_start_address; __be16 error_log_length; u16 reserved; u8 occ_code_level[16]; u8 eye_catcher[6]; u8 num_sensor_data_blocks; u8 sensor_data_block_header_version; } __packed; struct occ_poll_response { struct occ_poll_response_header header; struct occ_sensor_data_block block; } __packed; struct occ_sensor { u8 num_sensors; u8 version; void *data; /* pointer to sensor data start within response */ }; /* * OCC only provides one sensor data block of each type, but any number of * sensors within that block. */ struct occ_sensors { struct occ_sensor temp; struct occ_sensor freq; struct occ_sensor power; struct occ_sensor caps; struct occ_sensor extended; }; /* * Use our own attribute struct so we can dynamically allocate space for the * name. */ struct occ_attribute { char name[32]; struct sensor_device_attribute_2 sensor; }; struct occ { struct device *bus_dev; struct occ_response resp; struct occ_sensors sensors; int powr_sample_time_us; /* average power sample time */ u8 poll_cmd_data; /* to perform OCC poll command */ int (*send_cmd)(struct occ *occ, u8 *cmd, size_t len, void *resp, size_t resp_len); unsigned long next_update; struct mutex lock; /* lock OCC access */ struct device *hwmon; struct occ_attribute *attrs; struct attribute_group group; const struct attribute_group *groups[2]; bool active; int error; /* final transfer error after retry */ int last_error; /* latest transfer error */ unsigned int error_count; /* number of xfr errors observed */ unsigned long last_safe; /* time OCC entered "safe" state */ /* * Store the previous state data for comparison in order to notify * sysfs readers of state changes. */ int prev_error; u8 prev_stat; u8 prev_ext_stat; u8 prev_occs_present; u8 prev_ips_status; u8 prev_mode; }; int occ_active(struct occ *occ, bool active); int occ_setup(struct occ *occ); int occ_setup_sysfs(struct occ *occ); void occ_shutdown(struct occ *occ); void occ_shutdown_sysfs(struct occ *occ); void occ_sysfs_poll_done(struct occ *occ); int occ_update_response(struct occ *occ); #endif /* OCC_COMMON_H */