^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) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Intel MAX 10 BMC HWMON Driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2018-2020 Intel Corporation. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/hwmon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/mfd/intel-m10-bmc.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/mod_devicetable.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) struct m10bmc_sdata {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) unsigned int reg_input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) unsigned int reg_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) unsigned int reg_crit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) unsigned int reg_hyst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) unsigned int reg_min;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) unsigned int multiplier;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) const char *label;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct m10bmc_hwmon_board_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) const struct m10bmc_sdata *tables[hwmon_max];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) const struct hwmon_channel_info **hinfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct m10bmc_hwmon {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct hwmon_chip_info chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) char *hw_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct intel_m10bmc *m10bmc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) const struct m10bmc_hwmon_board_data *bdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static const struct m10bmc_sdata n3000bmc_temp_tbl[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) { 0x100, 0x104, 0x108, 0x10c, 0x0, 500, "Board Temperature" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) { 0x110, 0x114, 0x118, 0x0, 0x0, 500, "FPGA Die Temperature" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) { 0x11c, 0x124, 0x120, 0x0, 0x0, 500, "QSFP0 Temperature" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) { 0x12c, 0x134, 0x130, 0x0, 0x0, 500, "QSFP1 Temperature" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) { 0x168, 0x0, 0x0, 0x0, 0x0, 500, "Retimer A Temperature" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) { 0x16c, 0x0, 0x0, 0x0, 0x0, 500, "Retimer A SerDes Temperature" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) { 0x170, 0x0, 0x0, 0x0, 0x0, 500, "Retimer B Temperature" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) { 0x174, 0x0, 0x0, 0x0, 0x0, 500, "Retimer B SerDes Temperature" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static const struct m10bmc_sdata n3000bmc_in_tbl[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) { 0x128, 0x0, 0x0, 0x0, 0x0, 1, "QSFP0 Supply Voltage" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) { 0x138, 0x0, 0x0, 0x0, 0x0, 1, "QSFP1 Supply Voltage" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) { 0x13c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Voltage" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) { 0x144, 0x0, 0x0, 0x0, 0x0, 1, "12V Backplane Voltage" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) { 0x14c, 0x0, 0x0, 0x0, 0x0, 1, "1.2V Voltage" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) { 0x150, 0x0, 0x0, 0x0, 0x0, 1, "12V AUX Voltage" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) { 0x158, 0x0, 0x0, 0x0, 0x0, 1, "1.8V Voltage" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) { 0x15c, 0x0, 0x0, 0x0, 0x0, 1, "3.3V Voltage" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) static const struct m10bmc_sdata n3000bmc_curr_tbl[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) { 0x140, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Current" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) { 0x148, 0x0, 0x0, 0x0, 0x0, 1, "12V Backplane Current" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) { 0x154, 0x0, 0x0, 0x0, 0x0, 1, "12V AUX Current" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static const struct m10bmc_sdata n3000bmc_power_tbl[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) { 0x160, 0x0, 0x0, 0x0, 0x0, 1000, "Board Power" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static const struct hwmon_channel_info *n3000bmc_hinfo[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) HWMON_CHANNEL_INFO(temp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) HWMON_T_LABEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) HWMON_T_LABEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) HWMON_T_LABEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) HWMON_T_INPUT | HWMON_T_LABEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) HWMON_T_INPUT | HWMON_T_LABEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) HWMON_T_INPUT | HWMON_T_LABEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) HWMON_T_INPUT | HWMON_T_LABEL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) HWMON_CHANNEL_INFO(in,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) HWMON_I_INPUT | HWMON_I_LABEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) HWMON_I_INPUT | HWMON_I_LABEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) HWMON_I_INPUT | HWMON_I_LABEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) HWMON_I_INPUT | HWMON_I_LABEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) HWMON_I_INPUT | HWMON_I_LABEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) HWMON_I_INPUT | HWMON_I_LABEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) HWMON_I_INPUT | HWMON_I_LABEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) HWMON_I_INPUT | HWMON_I_LABEL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) HWMON_CHANNEL_INFO(curr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) HWMON_C_INPUT | HWMON_C_LABEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) HWMON_C_INPUT | HWMON_C_LABEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) HWMON_C_INPUT | HWMON_C_LABEL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) HWMON_CHANNEL_INFO(power,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) HWMON_P_INPUT | HWMON_P_LABEL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static const struct m10bmc_hwmon_board_data n3000bmc_hwmon_bdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) .tables = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) [hwmon_temp] = n3000bmc_temp_tbl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) [hwmon_in] = n3000bmc_in_tbl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) [hwmon_curr] = n3000bmc_curr_tbl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) [hwmon_power] = n3000bmc_power_tbl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) .hinfo = n3000bmc_hinfo,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) static umode_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) m10bmc_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) u32 attr, int channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return 0444;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) static const struct m10bmc_sdata *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) find_sensor_data(struct m10bmc_hwmon *hw, enum hwmon_sensor_types type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) int channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) const struct m10bmc_sdata *tbl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) tbl = hw->bdata->tables[type];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (!tbl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return ERR_PTR(-EOPNOTSUPP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) return &tbl[channel];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) static int do_sensor_read(struct m10bmc_hwmon *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) const struct m10bmc_sdata *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) unsigned int regoff, long *val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) unsigned int regval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) ret = m10bmc_sys_read(hw->m10bmc, regoff, ®val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) * BMC Firmware will return 0xdeadbeef if the sensor value is invalid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * at that time. This usually happens on sensor channels which connect
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * to external pluggable modules, e.g. QSFP temperature and voltage.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) * When the QSFP is unplugged from cage, driver will get 0xdeadbeef
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * from their registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (regval == 0xdeadbeef)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return -ENODATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) *val = regval * data->multiplier;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) static int m10bmc_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) u32 attr, int channel, long *val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) struct m10bmc_hwmon *hw = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) unsigned int reg = 0, reg_hyst = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) const struct m10bmc_sdata *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) long hyst, value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) data = find_sensor_data(hw, type, channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (IS_ERR(data))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) return PTR_ERR(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) switch (type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) case hwmon_temp:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) switch (attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) case hwmon_temp_input:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) reg = data->reg_input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) case hwmon_temp_max_hyst:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) reg_hyst = data->reg_hyst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) case hwmon_temp_max:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) reg = data->reg_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) case hwmon_temp_crit_hyst:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) reg_hyst = data->reg_hyst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) case hwmon_temp_crit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) reg = data->reg_crit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) case hwmon_in:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) switch (attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) case hwmon_in_input:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) reg = data->reg_input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) case hwmon_in_max:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) reg = data->reg_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) case hwmon_in_crit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) reg = data->reg_crit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) case hwmon_in_min:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) reg = data->reg_min;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) case hwmon_curr:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) switch (attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) case hwmon_curr_input:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) reg = data->reg_input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) case hwmon_curr_max:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) reg = data->reg_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) case hwmon_curr_crit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) reg = data->reg_crit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) case hwmon_power:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) switch (attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) case hwmon_power_input:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) reg = data->reg_input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) if (!reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) ret = do_sensor_read(hw, data, reg, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) if (reg_hyst) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) ret = do_sensor_read(hw, data, reg_hyst, &hyst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) value -= hyst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) *val = value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) static int m10bmc_hwmon_read_string(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) enum hwmon_sensor_types type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) u32 attr, int channel, const char **str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) struct m10bmc_hwmon *hw = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) const struct m10bmc_sdata *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) data = find_sensor_data(hw, type, channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) if (IS_ERR(data))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) return PTR_ERR(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) *str = data->label;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) static const struct hwmon_ops m10bmc_hwmon_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) .is_visible = m10bmc_hwmon_is_visible,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) .read = m10bmc_hwmon_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) .read_string = m10bmc_hwmon_read_string,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) static int m10bmc_hwmon_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) const struct platform_device_id *id = platform_get_device_id(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) struct intel_m10bmc *m10bmc = dev_get_drvdata(pdev->dev.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) struct device *hwmon_dev, *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) struct m10bmc_hwmon *hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) if (!hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) hw->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) hw->m10bmc = m10bmc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) hw->bdata = (const struct m10bmc_hwmon_board_data *)id->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) hw->chip.info = hw->bdata->hinfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) hw->chip.ops = &m10bmc_hwmon_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) hw->hw_name = devm_kstrdup(dev, id->name, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) if (!hw->hw_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) for (i = 0; hw->hw_name[i]; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) if (hwmon_is_bad_char(hw->hw_name[i]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) hw->hw_name[i] = '_';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) hwmon_dev = devm_hwmon_device_register_with_info(dev, hw->hw_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) hw, &hw->chip, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) return PTR_ERR_OR_ZERO(hwmon_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) static const struct platform_device_id intel_m10bmc_hwmon_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) .name = "n3000bmc-hwmon",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) .driver_data = (unsigned long)&n3000bmc_hwmon_bdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) static struct platform_driver intel_m10bmc_hwmon_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) .probe = m10bmc_hwmon_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) .name = "intel-m10-bmc-hwmon",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) .id_table = intel_m10bmc_hwmon_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) module_platform_driver(intel_m10bmc_hwmon_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) MODULE_DEVICE_TABLE(platform, intel_m10bmc_hwmon_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) MODULE_AUTHOR("Intel Corporation");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) MODULE_DESCRIPTION("Intel MAX 10 BMC hardware monitor");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) MODULE_LICENSE("GPL");