Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Intel MAX 10 BMC HWMON Driver
0004  *
0005  * Copyright (C) 2018-2020 Intel Corporation. All rights reserved.
0006  *
0007  */
0008 #include <linux/device.h>
0009 #include <linux/hwmon.h>
0010 #include <linux/mfd/intel-m10-bmc.h>
0011 #include <linux/module.h>
0012 #include <linux/mod_devicetable.h>
0013 #include <linux/platform_device.h>
0014 
0015 struct m10bmc_sdata {
0016     unsigned int reg_input;
0017     unsigned int reg_max;
0018     unsigned int reg_crit;
0019     unsigned int reg_hyst;
0020     unsigned int reg_min;
0021     unsigned int multiplier;
0022     const char *label;
0023 };
0024 
0025 struct m10bmc_hwmon_board_data {
0026     const struct m10bmc_sdata *tables[hwmon_max];
0027     const struct hwmon_channel_info **hinfo;
0028 };
0029 
0030 struct m10bmc_hwmon {
0031     struct device *dev;
0032     struct hwmon_chip_info chip;
0033     char *hw_name;
0034     struct intel_m10bmc *m10bmc;
0035     const struct m10bmc_hwmon_board_data *bdata;
0036 };
0037 
0038 static const struct m10bmc_sdata n3000bmc_temp_tbl[] = {
0039     { 0x100, 0x104, 0x108, 0x10c, 0x0, 500, "Board Temperature" },
0040     { 0x110, 0x114, 0x118, 0x0, 0x0, 500, "FPGA Die Temperature" },
0041     { 0x11c, 0x124, 0x120, 0x0, 0x0, 500, "QSFP0 Temperature" },
0042     { 0x12c, 0x134, 0x130, 0x0, 0x0, 500, "QSFP1 Temperature" },
0043     { 0x168, 0x0, 0x0, 0x0, 0x0, 500, "Retimer A Temperature" },
0044     { 0x16c, 0x0, 0x0, 0x0, 0x0, 500, "Retimer A SerDes Temperature" },
0045     { 0x170, 0x0, 0x0, 0x0, 0x0, 500, "Retimer B Temperature" },
0046     { 0x174, 0x0, 0x0, 0x0, 0x0, 500, "Retimer B SerDes Temperature" },
0047 };
0048 
0049 static const struct m10bmc_sdata n3000bmc_in_tbl[] = {
0050     { 0x128, 0x0, 0x0, 0x0, 0x0, 1, "QSFP0 Supply Voltage" },
0051     { 0x138, 0x0, 0x0, 0x0, 0x0, 1, "QSFP1 Supply Voltage" },
0052     { 0x13c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Voltage" },
0053     { 0x144, 0x0, 0x0, 0x0, 0x0, 1, "12V Backplane Voltage" },
0054     { 0x14c, 0x0, 0x0, 0x0, 0x0, 1, "1.2V Voltage" },
0055     { 0x150, 0x0, 0x0, 0x0, 0x0, 1, "12V AUX Voltage" },
0056     { 0x158, 0x0, 0x0, 0x0, 0x0, 1, "1.8V Voltage" },
0057     { 0x15c, 0x0, 0x0, 0x0, 0x0, 1, "3.3V Voltage" },
0058 };
0059 
0060 static const struct m10bmc_sdata n3000bmc_curr_tbl[] = {
0061     { 0x140, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Current" },
0062     { 0x148, 0x0, 0x0, 0x0, 0x0, 1, "12V Backplane Current" },
0063     { 0x154, 0x0, 0x0, 0x0, 0x0, 1, "12V AUX Current" },
0064 };
0065 
0066 static const struct m10bmc_sdata n3000bmc_power_tbl[] = {
0067     { 0x160, 0x0, 0x0, 0x0, 0x0, 1000, "Board Power" },
0068 };
0069 
0070 static const struct hwmon_channel_info *n3000bmc_hinfo[] = {
0071     HWMON_CHANNEL_INFO(temp,
0072                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
0073                HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
0074                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
0075                HWMON_T_LABEL,
0076                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
0077                HWMON_T_LABEL,
0078                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
0079                HWMON_T_LABEL,
0080                HWMON_T_INPUT | HWMON_T_LABEL,
0081                HWMON_T_INPUT | HWMON_T_LABEL,
0082                HWMON_T_INPUT | HWMON_T_LABEL,
0083                HWMON_T_INPUT | HWMON_T_LABEL),
0084     HWMON_CHANNEL_INFO(in,
0085                HWMON_I_INPUT | HWMON_I_LABEL,
0086                HWMON_I_INPUT | HWMON_I_LABEL,
0087                HWMON_I_INPUT | HWMON_I_LABEL,
0088                HWMON_I_INPUT | HWMON_I_LABEL,
0089                HWMON_I_INPUT | HWMON_I_LABEL,
0090                HWMON_I_INPUT | HWMON_I_LABEL,
0091                HWMON_I_INPUT | HWMON_I_LABEL,
0092                HWMON_I_INPUT | HWMON_I_LABEL),
0093     HWMON_CHANNEL_INFO(curr,
0094                HWMON_C_INPUT | HWMON_C_LABEL,
0095                HWMON_C_INPUT | HWMON_C_LABEL,
0096                HWMON_C_INPUT | HWMON_C_LABEL),
0097     HWMON_CHANNEL_INFO(power,
0098                HWMON_P_INPUT | HWMON_P_LABEL),
0099     NULL
0100 };
0101 
0102 static const struct m10bmc_sdata d5005bmc_temp_tbl[] = {
0103     { 0x100, 0x104, 0x108, 0x10c, 0x0, 500, "Board Inlet Air Temperature" },
0104     { 0x110, 0x114, 0x118, 0x0, 0x0, 500, "FPGA Core Temperature" },
0105     { 0x11c, 0x120, 0x124, 0x128, 0x0, 500, "Board Exhaust Air Temperature" },
0106     { 0x12c, 0x130, 0x134, 0x0, 0x0, 500, "FPGA Transceiver Temperature" },
0107     { 0x138, 0x13c, 0x140, 0x144, 0x0, 500, "RDIMM0 Temperature" },
0108     { 0x148, 0x14c, 0x150, 0x154, 0x0, 500, "RDIMM1 Temperature" },
0109     { 0x158, 0x15c, 0x160, 0x164, 0x0, 500, "RDIMM2 Temperature" },
0110     { 0x168, 0x16c, 0x170, 0x174, 0x0, 500, "RDIMM3 Temperature" },
0111     { 0x178, 0x17c, 0x180, 0x0, 0x0, 500, "QSFP0 Temperature" },
0112     { 0x188, 0x18c, 0x190, 0x0, 0x0, 500, "QSFP1 Temperature" },
0113     { 0x1a0, 0x1a4, 0x1a8, 0x0, 0x0, 500, "3.3v Temperature" },
0114     { 0x1bc, 0x1c0, 0x1c4, 0x0, 0x0, 500, "VCCERAM Temperature" },
0115     { 0x1d8, 0x1dc, 0x1e0, 0x0, 0x0, 500, "VCCR Temperature" },
0116     { 0x1f4, 0x1f8, 0x1fc, 0x0, 0x0, 500, "VCCT Temperature" },
0117     { 0x210, 0x214, 0x218, 0x0, 0x0, 500, "1.8v Temperature" },
0118     { 0x22c, 0x230, 0x234, 0x0, 0x0, 500, "12v Backplane Temperature" },
0119     { 0x248, 0x24c, 0x250, 0x0, 0x0, 500, "12v AUX Temperature" },
0120 };
0121 
0122 static const struct m10bmc_sdata d5005bmc_in_tbl[] = {
0123     { 0x184, 0x0, 0x0, 0x0, 0x0, 1, "QSFP0 Supply Voltage" },
0124     { 0x194, 0x0, 0x0, 0x0, 0x0, 1, "QSFP1 Supply Voltage" },
0125     { 0x198, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Voltage" },
0126     { 0x1ac, 0x1b0, 0x1b4, 0x0, 0x0, 1, "3.3v Voltage" },
0127     { 0x1c8, 0x1cc, 0x1d0, 0x0, 0x0, 1, "VCCERAM Voltage" },
0128     { 0x1e4, 0x1e8, 0x1ec, 0x0, 0x0, 1, "VCCR Voltage" },
0129     { 0x200, 0x204, 0x208, 0x0, 0x0, 1, "VCCT Voltage" },
0130     { 0x21c, 0x220, 0x224, 0x0, 0x0, 1, "1.8v Voltage" },
0131     { 0x238, 0x0, 0x0, 0x0, 0x23c, 1, "12v Backplane Voltage" },
0132     { 0x254, 0x0, 0x0, 0x0, 0x258, 1, "12v AUX Voltage" },
0133 };
0134 
0135 static const struct m10bmc_sdata d5005bmc_curr_tbl[] = {
0136     { 0x19c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Current" },
0137     { 0x1b8, 0x0, 0x0, 0x0, 0x0, 1, "3.3v Current" },
0138     { 0x1d4, 0x0, 0x0, 0x0, 0x0, 1, "VCCERAM Current" },
0139     { 0x1f0, 0x0, 0x0, 0x0, 0x0, 1, "VCCR Current" },
0140     { 0x20c, 0x0, 0x0, 0x0, 0x0, 1, "VCCT Current" },
0141     { 0x228, 0x0, 0x0, 0x0, 0x0, 1, "1.8v Current" },
0142     { 0x240, 0x244, 0x0, 0x0, 0x0, 1, "12v Backplane Current" },
0143     { 0x25c, 0x260, 0x0, 0x0, 0x0, 1, "12v AUX Current" },
0144 };
0145 
0146 static const struct m10bmc_hwmon_board_data n3000bmc_hwmon_bdata = {
0147     .tables = {
0148         [hwmon_temp] = n3000bmc_temp_tbl,
0149         [hwmon_in] = n3000bmc_in_tbl,
0150         [hwmon_curr] = n3000bmc_curr_tbl,
0151         [hwmon_power] = n3000bmc_power_tbl,
0152     },
0153 
0154     .hinfo = n3000bmc_hinfo,
0155 };
0156 
0157 static const struct hwmon_channel_info *d5005bmc_hinfo[] = {
0158     HWMON_CHANNEL_INFO(temp,
0159                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
0160                HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
0161                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
0162                HWMON_T_LABEL,
0163                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
0164                HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
0165                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
0166                HWMON_T_LABEL,
0167                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
0168                HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
0169                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
0170                HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
0171                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
0172                HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
0173                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
0174                HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
0175                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
0176                HWMON_T_LABEL,
0177                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
0178                HWMON_T_LABEL,
0179                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
0180                HWMON_T_LABEL,
0181                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
0182                HWMON_T_LABEL,
0183                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
0184                HWMON_T_LABEL,
0185                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
0186                HWMON_T_LABEL,
0187                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
0188                HWMON_T_LABEL,
0189                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
0190                HWMON_T_LABEL,
0191                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
0192                HWMON_T_LABEL),
0193     HWMON_CHANNEL_INFO(in,
0194                HWMON_I_INPUT | HWMON_I_LABEL,
0195                HWMON_I_INPUT | HWMON_I_LABEL,
0196                HWMON_I_INPUT | HWMON_I_LABEL,
0197                HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT |
0198                HWMON_I_LABEL,
0199                HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT |
0200                HWMON_I_LABEL,
0201                HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT |
0202                HWMON_I_LABEL,
0203                HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT |
0204                HWMON_I_LABEL,
0205                HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT |
0206                HWMON_I_LABEL,
0207                HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_LABEL,
0208                HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_LABEL),
0209     HWMON_CHANNEL_INFO(curr,
0210                HWMON_C_INPUT | HWMON_C_LABEL,
0211                HWMON_C_INPUT | HWMON_C_LABEL,
0212                HWMON_C_INPUT | HWMON_C_LABEL,
0213                HWMON_C_INPUT | HWMON_C_LABEL,
0214                HWMON_C_INPUT | HWMON_C_LABEL,
0215                HWMON_C_INPUT | HWMON_C_LABEL,
0216                HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_LABEL,
0217                HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_LABEL),
0218     NULL
0219 };
0220 
0221 static const struct m10bmc_hwmon_board_data d5005bmc_hwmon_bdata = {
0222     .tables = {
0223         [hwmon_temp] = d5005bmc_temp_tbl,
0224         [hwmon_in] = d5005bmc_in_tbl,
0225         [hwmon_curr] = d5005bmc_curr_tbl,
0226     },
0227 
0228     .hinfo = d5005bmc_hinfo,
0229 };
0230 
0231 static const struct m10bmc_sdata n5010bmc_temp_tbl[] = {
0232     { 0x100, 0x0, 0x104, 0x0, 0x0, 1000, "Board Local Temperature" },
0233     { 0x108, 0x0, 0x10c, 0x0, 0x0, 1000, "FPGA 1 Temperature" },
0234     { 0x110, 0x0, 0x114, 0x0, 0x0, 1000, "FPGA 2 Temperature" },
0235     { 0x118, 0x0, 0x0, 0x0, 0x0, 1000, "Card Top Temperature" },
0236     { 0x11c, 0x0, 0x0, 0x0, 0x0, 1000, "Card Bottom Temperature" },
0237     { 0x128, 0x0, 0x0, 0x0, 0x0, 1000, "FPGA 1.2V Temperature" },
0238     { 0x134, 0x0, 0x0, 0x0, 0x0, 1000, "FPGA 5V Temperature" },
0239     { 0x140, 0x0, 0x0, 0x0, 0x0, 1000, "FPGA 0.9V Temperature" },
0240     { 0x14c, 0x0, 0x0, 0x0, 0x0, 1000, "FPGA 0.85V Temperature" },
0241     { 0x158, 0x0, 0x0, 0x0, 0x0, 1000, "AUX 12V Temperature" },
0242     { 0x164, 0x0, 0x0, 0x0, 0x0, 1000, "Backplane 12V Temperature" },
0243     { 0x1a8, 0x0, 0x0, 0x0, 0x0, 1000, "QSFP28-1 Temperature" },
0244     { 0x1ac, 0x0, 0x0, 0x0, 0x0, 1000, "QSFP28-2 Temperature" },
0245     { 0x1b0, 0x0, 0x0, 0x0, 0x0, 1000, "QSFP28-3 Temperature" },
0246     { 0x1b4, 0x0, 0x0, 0x0, 0x0, 1000, "QSFP28-4 Temperature" },
0247     { 0x1b8, 0x0, 0x0, 0x0, 0x0, 1000, "CVL1 Internal Temperature" },
0248     { 0x1bc, 0x0, 0x0, 0x0, 0x0, 1000, "CVL2 Internal Temperature" },
0249 };
0250 
0251 static const struct m10bmc_sdata n5010bmc_in_tbl[] = {
0252     { 0x120, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 1.2V Voltage" },
0253     { 0x12c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 5V Voltage" },
0254     { 0x138, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 0.9V Voltage" },
0255     { 0x144, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 0.85V Voltage" },
0256     { 0x150, 0x0, 0x0, 0x0, 0x0, 1, "AUX 12V Voltage" },
0257     { 0x15c, 0x0, 0x0, 0x0, 0x0, 1, "Backplane 12V Voltage" },
0258     { 0x16c, 0x0, 0x0, 0x0, 0x0, 1, "DDR4 1.2V Voltage" },
0259     { 0x17c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 1.8V Voltage" },
0260     { 0x184, 0x0, 0x0, 0x0, 0x0, 1, "QDR 1.3V Voltage" },
0261     { 0x18c, 0x0, 0x0, 0x0, 0x0, 1, "CVL1 0.8V Voltage" },
0262     { 0x194, 0x0, 0x0, 0x0, 0x0, 1, "CVL1 1.05V Voltage" },
0263     { 0x19c, 0x0, 0x0, 0x0, 0x0, 1, "CVL2 1.05V Voltage" },
0264     { 0x1a4, 0x0, 0x0, 0x0, 0x0, 1, "CVL2 0.8V Voltage" },
0265 };
0266 
0267 static const struct m10bmc_sdata n5010bmc_curr_tbl[] = {
0268     { 0x124, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 1.2V Current" },
0269     { 0x130, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 5V Current" },
0270     { 0x13c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 0.9V Current" },
0271     { 0x148, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 0.85V Current" },
0272     { 0x154, 0x0, 0x0, 0x0, 0x0, 1, "AUX 12V Current" },
0273     { 0x160, 0x0, 0x0, 0x0, 0x0, 1, "Backplane 12V Current" },
0274     { 0x168, 0x0, 0x0, 0x0, 0x0, 1, "DDR4 1.2V Current" },
0275     { 0x178, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 1.8V Current" },
0276     { 0x180, 0x0, 0x0, 0x0, 0x0, 1, "QDR 1.3V Current" },
0277     { 0x188, 0x0, 0x0, 0x0, 0x0, 1, "CVL1 0.8V Current" },
0278     { 0x190, 0x0, 0x0, 0x0, 0x0, 1, "CVL1 1.05V Current" },
0279     { 0x198, 0x0, 0x0, 0x0, 0x0, 1, "CVL2 1.05V Current" },
0280     { 0x1a0, 0x0, 0x0, 0x0, 0x0, 1, "CVL2 0.8V Current" },
0281 };
0282 
0283 static const struct hwmon_channel_info *n5010bmc_hinfo[] = {
0284     HWMON_CHANNEL_INFO(temp,
0285                HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL,
0286                HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL,
0287                HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL,
0288                HWMON_T_INPUT | HWMON_T_LABEL,
0289                HWMON_T_INPUT | HWMON_T_LABEL,
0290                HWMON_T_INPUT | HWMON_T_LABEL,
0291                HWMON_T_INPUT | HWMON_T_LABEL,
0292                HWMON_T_INPUT | HWMON_T_LABEL,
0293                HWMON_T_INPUT | HWMON_T_LABEL,
0294                HWMON_T_INPUT | HWMON_T_LABEL,
0295                HWMON_T_INPUT | HWMON_T_LABEL,
0296                HWMON_T_INPUT | HWMON_T_LABEL,
0297                HWMON_T_INPUT | HWMON_T_LABEL,
0298                HWMON_T_INPUT | HWMON_T_LABEL,
0299                HWMON_T_INPUT | HWMON_T_LABEL,
0300                HWMON_T_INPUT | HWMON_T_LABEL,
0301                HWMON_T_INPUT | HWMON_T_LABEL),
0302     HWMON_CHANNEL_INFO(in,
0303                HWMON_I_INPUT | HWMON_I_LABEL,
0304                HWMON_I_INPUT | HWMON_I_LABEL,
0305                HWMON_I_INPUT | HWMON_I_LABEL,
0306                HWMON_I_INPUT | HWMON_I_LABEL,
0307                HWMON_I_INPUT | HWMON_I_LABEL,
0308                HWMON_I_INPUT | HWMON_I_LABEL,
0309                HWMON_I_INPUT | HWMON_I_LABEL,
0310                HWMON_I_INPUT | HWMON_I_LABEL,
0311                HWMON_I_INPUT | HWMON_I_LABEL,
0312                HWMON_I_INPUT | HWMON_I_LABEL,
0313                HWMON_I_INPUT | HWMON_I_LABEL,
0314                HWMON_I_INPUT | HWMON_I_LABEL,
0315                HWMON_I_INPUT | HWMON_I_LABEL),
0316     HWMON_CHANNEL_INFO(curr,
0317                HWMON_C_INPUT | HWMON_C_LABEL,
0318                HWMON_C_INPUT | HWMON_C_LABEL,
0319                HWMON_C_INPUT | HWMON_C_LABEL,
0320                HWMON_C_INPUT | HWMON_C_LABEL,
0321                HWMON_C_INPUT | HWMON_C_LABEL,
0322                HWMON_C_INPUT | HWMON_C_LABEL,
0323                HWMON_C_INPUT | HWMON_C_LABEL,
0324                HWMON_C_INPUT | HWMON_C_LABEL,
0325                HWMON_C_INPUT | HWMON_C_LABEL,
0326                HWMON_C_INPUT | HWMON_C_LABEL,
0327                HWMON_C_INPUT | HWMON_C_LABEL,
0328                HWMON_C_INPUT | HWMON_C_LABEL,
0329                HWMON_C_INPUT | HWMON_C_LABEL),
0330     NULL
0331 };
0332 
0333 static const struct m10bmc_hwmon_board_data n5010bmc_hwmon_bdata = {
0334     .tables = {
0335         [hwmon_temp] = n5010bmc_temp_tbl,
0336         [hwmon_in] = n5010bmc_in_tbl,
0337         [hwmon_curr] = n5010bmc_curr_tbl,
0338     },
0339 
0340     .hinfo = n5010bmc_hinfo,
0341 };
0342 
0343 static umode_t
0344 m10bmc_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
0345             u32 attr, int channel)
0346 {
0347     return 0444;
0348 }
0349 
0350 static const struct m10bmc_sdata *
0351 find_sensor_data(struct m10bmc_hwmon *hw, enum hwmon_sensor_types type,
0352          int channel)
0353 {
0354     const struct m10bmc_sdata *tbl;
0355 
0356     tbl = hw->bdata->tables[type];
0357     if (!tbl)
0358         return ERR_PTR(-EOPNOTSUPP);
0359 
0360     return &tbl[channel];
0361 }
0362 
0363 static int do_sensor_read(struct m10bmc_hwmon *hw,
0364               const struct m10bmc_sdata *data,
0365               unsigned int regoff, long *val)
0366 {
0367     unsigned int regval;
0368     int ret;
0369 
0370     ret = m10bmc_sys_read(hw->m10bmc, regoff, &regval);
0371     if (ret)
0372         return ret;
0373 
0374     /*
0375      * BMC Firmware will return 0xdeadbeef if the sensor value is invalid
0376      * at that time. This usually happens on sensor channels which connect
0377      * to external pluggable modules, e.g. QSFP temperature and voltage.
0378      * When the QSFP is unplugged from cage, driver will get 0xdeadbeef
0379      * from their registers.
0380      */
0381     if (regval == 0xdeadbeef)
0382         return -ENODATA;
0383 
0384     *val = regval * data->multiplier;
0385 
0386     return 0;
0387 }
0388 
0389 static int m10bmc_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
0390                  u32 attr, int channel, long *val)
0391 {
0392     struct m10bmc_hwmon *hw = dev_get_drvdata(dev);
0393     unsigned int reg = 0, reg_hyst = 0;
0394     const struct m10bmc_sdata *data;
0395     long hyst, value;
0396     int ret;
0397 
0398     data = find_sensor_data(hw, type, channel);
0399     if (IS_ERR(data))
0400         return PTR_ERR(data);
0401 
0402     switch (type) {
0403     case hwmon_temp:
0404         switch (attr) {
0405         case hwmon_temp_input:
0406             reg = data->reg_input;
0407             break;
0408         case hwmon_temp_max_hyst:
0409             reg_hyst = data->reg_hyst;
0410             fallthrough;
0411         case hwmon_temp_max:
0412             reg = data->reg_max;
0413             break;
0414         case hwmon_temp_crit_hyst:
0415             reg_hyst = data->reg_hyst;
0416             fallthrough;
0417         case hwmon_temp_crit:
0418             reg = data->reg_crit;
0419             break;
0420         default:
0421             return -EOPNOTSUPP;
0422         }
0423         break;
0424     case hwmon_in:
0425         switch (attr) {
0426         case hwmon_in_input:
0427             reg = data->reg_input;
0428             break;
0429         case hwmon_in_max:
0430             reg = data->reg_max;
0431             break;
0432         case hwmon_in_crit:
0433             reg = data->reg_crit;
0434             break;
0435         case hwmon_in_min:
0436             reg = data->reg_min;
0437             break;
0438         default:
0439             return -EOPNOTSUPP;
0440         }
0441         break;
0442     case hwmon_curr:
0443         switch (attr) {
0444         case hwmon_curr_input:
0445             reg = data->reg_input;
0446             break;
0447         case hwmon_curr_max:
0448             reg = data->reg_max;
0449             break;
0450         case hwmon_curr_crit:
0451             reg = data->reg_crit;
0452             break;
0453         default:
0454             return -EOPNOTSUPP;
0455         }
0456         break;
0457     case hwmon_power:
0458         switch (attr) {
0459         case hwmon_power_input:
0460             reg = data->reg_input;
0461             break;
0462         default:
0463             return -EOPNOTSUPP;
0464         }
0465         break;
0466     default:
0467         return -EOPNOTSUPP;
0468     }
0469 
0470     if (!reg)
0471         return -EOPNOTSUPP;
0472 
0473     ret = do_sensor_read(hw, data, reg, &value);
0474     if (ret)
0475         return ret;
0476 
0477     if (reg_hyst) {
0478         ret = do_sensor_read(hw, data, reg_hyst, &hyst);
0479         if (ret)
0480             return ret;
0481 
0482         value -= hyst;
0483     }
0484 
0485     *val = value;
0486 
0487     return 0;
0488 }
0489 
0490 static int m10bmc_hwmon_read_string(struct device *dev,
0491                     enum hwmon_sensor_types type,
0492                     u32 attr, int channel, const char **str)
0493 {
0494     struct m10bmc_hwmon *hw = dev_get_drvdata(dev);
0495     const struct m10bmc_sdata *data;
0496 
0497     data = find_sensor_data(hw, type, channel);
0498     if (IS_ERR(data))
0499         return PTR_ERR(data);
0500 
0501     *str = data->label;
0502 
0503     return 0;
0504 }
0505 
0506 static const struct hwmon_ops m10bmc_hwmon_ops = {
0507     .is_visible = m10bmc_hwmon_is_visible,
0508     .read = m10bmc_hwmon_read,
0509     .read_string = m10bmc_hwmon_read_string,
0510 };
0511 
0512 static int m10bmc_hwmon_probe(struct platform_device *pdev)
0513 {
0514     const struct platform_device_id *id = platform_get_device_id(pdev);
0515     struct intel_m10bmc *m10bmc = dev_get_drvdata(pdev->dev.parent);
0516     struct device *hwmon_dev, *dev = &pdev->dev;
0517     struct m10bmc_hwmon *hw;
0518 
0519     hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
0520     if (!hw)
0521         return -ENOMEM;
0522 
0523     hw->dev = dev;
0524     hw->m10bmc = m10bmc;
0525     hw->bdata = (const struct m10bmc_hwmon_board_data *)id->driver_data;
0526 
0527     hw->chip.info = hw->bdata->hinfo;
0528     hw->chip.ops = &m10bmc_hwmon_ops;
0529 
0530     hw->hw_name = devm_hwmon_sanitize_name(dev, id->name);
0531     if (IS_ERR(hw->hw_name))
0532         return PTR_ERR(hw->hw_name);
0533 
0534     hwmon_dev = devm_hwmon_device_register_with_info(dev, hw->hw_name,
0535                              hw, &hw->chip, NULL);
0536     return PTR_ERR_OR_ZERO(hwmon_dev);
0537 }
0538 
0539 static const struct platform_device_id intel_m10bmc_hwmon_ids[] = {
0540     {
0541         .name = "n3000bmc-hwmon",
0542         .driver_data = (unsigned long)&n3000bmc_hwmon_bdata,
0543     },
0544     {
0545         .name = "d5005bmc-hwmon",
0546         .driver_data = (unsigned long)&d5005bmc_hwmon_bdata,
0547     },
0548     {
0549         .name = "n5010bmc-hwmon",
0550         .driver_data = (unsigned long)&n5010bmc_hwmon_bdata,
0551     },
0552     { }
0553 };
0554 
0555 static struct platform_driver intel_m10bmc_hwmon_driver = {
0556     .probe = m10bmc_hwmon_probe,
0557     .driver = {
0558         .name = "intel-m10-bmc-hwmon",
0559     },
0560     .id_table = intel_m10bmc_hwmon_ids,
0561 };
0562 module_platform_driver(intel_m10bmc_hwmon_driver);
0563 
0564 MODULE_DEVICE_TABLE(platform, intel_m10bmc_hwmon_ids);
0565 MODULE_AUTHOR("Intel Corporation");
0566 MODULE_DESCRIPTION("Intel MAX 10 BMC hardware monitor");
0567 MODULE_LICENSE("GPL");