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