cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

intel-m10-bmc-hwmon.c (18231B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Intel MAX 10 BMC HWMON Driver
      4 *
      5 * Copyright (C) 2018-2020 Intel Corporation. All rights reserved.
      6 *
      7 */
      8#include <linux/device.h>
      9#include <linux/hwmon.h>
     10#include <linux/mfd/intel-m10-bmc.h>
     11#include <linux/module.h>
     12#include <linux/mod_devicetable.h>
     13#include <linux/platform_device.h>
     14
     15struct m10bmc_sdata {
     16	unsigned int reg_input;
     17	unsigned int reg_max;
     18	unsigned int reg_crit;
     19	unsigned int reg_hyst;
     20	unsigned int reg_min;
     21	unsigned int multiplier;
     22	const char *label;
     23};
     24
     25struct m10bmc_hwmon_board_data {
     26	const struct m10bmc_sdata *tables[hwmon_max];
     27	const struct hwmon_channel_info **hinfo;
     28};
     29
     30struct m10bmc_hwmon {
     31	struct device *dev;
     32	struct hwmon_chip_info chip;
     33	char *hw_name;
     34	struct intel_m10bmc *m10bmc;
     35	const struct m10bmc_hwmon_board_data *bdata;
     36};
     37
     38static const struct m10bmc_sdata n3000bmc_temp_tbl[] = {
     39	{ 0x100, 0x104, 0x108, 0x10c, 0x0, 500, "Board Temperature" },
     40	{ 0x110, 0x114, 0x118, 0x0, 0x0, 500, "FPGA Die Temperature" },
     41	{ 0x11c, 0x124, 0x120, 0x0, 0x0, 500, "QSFP0 Temperature" },
     42	{ 0x12c, 0x134, 0x130, 0x0, 0x0, 500, "QSFP1 Temperature" },
     43	{ 0x168, 0x0, 0x0, 0x0, 0x0, 500, "Retimer A Temperature" },
     44	{ 0x16c, 0x0, 0x0, 0x0, 0x0, 500, "Retimer A SerDes Temperature" },
     45	{ 0x170, 0x0, 0x0, 0x0, 0x0, 500, "Retimer B Temperature" },
     46	{ 0x174, 0x0, 0x0, 0x0, 0x0, 500, "Retimer B SerDes Temperature" },
     47};
     48
     49static const struct m10bmc_sdata n3000bmc_in_tbl[] = {
     50	{ 0x128, 0x0, 0x0, 0x0, 0x0, 1, "QSFP0 Supply Voltage" },
     51	{ 0x138, 0x0, 0x0, 0x0, 0x0, 1, "QSFP1 Supply Voltage" },
     52	{ 0x13c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Voltage" },
     53	{ 0x144, 0x0, 0x0, 0x0, 0x0, 1, "12V Backplane Voltage" },
     54	{ 0x14c, 0x0, 0x0, 0x0, 0x0, 1, "1.2V Voltage" },
     55	{ 0x150, 0x0, 0x0, 0x0, 0x0, 1, "12V AUX Voltage" },
     56	{ 0x158, 0x0, 0x0, 0x0, 0x0, 1, "1.8V Voltage" },
     57	{ 0x15c, 0x0, 0x0, 0x0, 0x0, 1, "3.3V Voltage" },
     58};
     59
     60static const struct m10bmc_sdata n3000bmc_curr_tbl[] = {
     61	{ 0x140, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Current" },
     62	{ 0x148, 0x0, 0x0, 0x0, 0x0, 1, "12V Backplane Current" },
     63	{ 0x154, 0x0, 0x0, 0x0, 0x0, 1, "12V AUX Current" },
     64};
     65
     66static const struct m10bmc_sdata n3000bmc_power_tbl[] = {
     67	{ 0x160, 0x0, 0x0, 0x0, 0x0, 1000, "Board Power" },
     68};
     69
     70static const struct hwmon_channel_info *n3000bmc_hinfo[] = {
     71	HWMON_CHANNEL_INFO(temp,
     72			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
     73			   HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
     74			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
     75			   HWMON_T_LABEL,
     76			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
     77			   HWMON_T_LABEL,
     78			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
     79			   HWMON_T_LABEL,
     80			   HWMON_T_INPUT | HWMON_T_LABEL,
     81			   HWMON_T_INPUT | HWMON_T_LABEL,
     82			   HWMON_T_INPUT | HWMON_T_LABEL,
     83			   HWMON_T_INPUT | HWMON_T_LABEL),
     84	HWMON_CHANNEL_INFO(in,
     85			   HWMON_I_INPUT | HWMON_I_LABEL,
     86			   HWMON_I_INPUT | HWMON_I_LABEL,
     87			   HWMON_I_INPUT | HWMON_I_LABEL,
     88			   HWMON_I_INPUT | HWMON_I_LABEL,
     89			   HWMON_I_INPUT | HWMON_I_LABEL,
     90			   HWMON_I_INPUT | HWMON_I_LABEL,
     91			   HWMON_I_INPUT | HWMON_I_LABEL,
     92			   HWMON_I_INPUT | HWMON_I_LABEL),
     93	HWMON_CHANNEL_INFO(curr,
     94			   HWMON_C_INPUT | HWMON_C_LABEL,
     95			   HWMON_C_INPUT | HWMON_C_LABEL,
     96			   HWMON_C_INPUT | HWMON_C_LABEL),
     97	HWMON_CHANNEL_INFO(power,
     98			   HWMON_P_INPUT | HWMON_P_LABEL),
     99	NULL
    100};
    101
    102static const struct m10bmc_sdata d5005bmc_temp_tbl[] = {
    103	{ 0x100, 0x104, 0x108, 0x10c, 0x0, 500, "Board Inlet Air Temperature" },
    104	{ 0x110, 0x114, 0x118, 0x0, 0x0, 500, "FPGA Core Temperature" },
    105	{ 0x11c, 0x120, 0x124, 0x128, 0x0, 500, "Board Exhaust Air Temperature" },
    106	{ 0x12c, 0x130, 0x134, 0x0, 0x0, 500, "FPGA Transceiver Temperature" },
    107	{ 0x138, 0x13c, 0x140, 0x144, 0x0, 500, "RDIMM0 Temperature" },
    108	{ 0x148, 0x14c, 0x150, 0x154, 0x0, 500, "RDIMM1 Temperature" },
    109	{ 0x158, 0x15c, 0x160, 0x164, 0x0, 500, "RDIMM2 Temperature" },
    110	{ 0x168, 0x16c, 0x170, 0x174, 0x0, 500, "RDIMM3 Temperature" },
    111	{ 0x178, 0x17c, 0x180, 0x0, 0x0, 500, "QSFP0 Temperature" },
    112	{ 0x188, 0x18c, 0x190, 0x0, 0x0, 500, "QSFP1 Temperature" },
    113	{ 0x1a0, 0x1a4, 0x1a8, 0x0, 0x0, 500, "3.3v Temperature" },
    114	{ 0x1bc, 0x1c0, 0x1c4, 0x0, 0x0, 500, "VCCERAM Temperature" },
    115	{ 0x1d8, 0x1dc, 0x1e0, 0x0, 0x0, 500, "VCCR Temperature" },
    116	{ 0x1f4, 0x1f8, 0x1fc, 0x0, 0x0, 500, "VCCT Temperature" },
    117	{ 0x210, 0x214, 0x218, 0x0, 0x0, 500, "1.8v Temperature" },
    118	{ 0x22c, 0x230, 0x234, 0x0, 0x0, 500, "12v Backplane Temperature" },
    119	{ 0x248, 0x24c, 0x250, 0x0, 0x0, 500, "12v AUX Temperature" },
    120};
    121
    122static const struct m10bmc_sdata d5005bmc_in_tbl[] = {
    123	{ 0x184, 0x0, 0x0, 0x0, 0x0, 1, "QSFP0 Supply Voltage" },
    124	{ 0x194, 0x0, 0x0, 0x0, 0x0, 1, "QSFP1 Supply Voltage" },
    125	{ 0x198, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Voltage" },
    126	{ 0x1ac, 0x1b0, 0x1b4, 0x0, 0x0, 1, "3.3v Voltage" },
    127	{ 0x1c8, 0x1cc, 0x1d0, 0x0, 0x0, 1, "VCCERAM Voltage" },
    128	{ 0x1e4, 0x1e8, 0x1ec, 0x0, 0x0, 1, "VCCR Voltage" },
    129	{ 0x200, 0x204, 0x208, 0x0, 0x0, 1, "VCCT Voltage" },
    130	{ 0x21c, 0x220, 0x224, 0x0, 0x0, 1, "1.8v Voltage" },
    131	{ 0x238, 0x0, 0x0, 0x0, 0x23c, 1, "12v Backplane Voltage" },
    132	{ 0x254, 0x0, 0x0, 0x0, 0x258, 1, "12v AUX Voltage" },
    133};
    134
    135static const struct m10bmc_sdata d5005bmc_curr_tbl[] = {
    136	{ 0x19c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Current" },
    137	{ 0x1b8, 0x0, 0x0, 0x0, 0x0, 1, "3.3v Current" },
    138	{ 0x1d4, 0x0, 0x0, 0x0, 0x0, 1, "VCCERAM Current" },
    139	{ 0x1f0, 0x0, 0x0, 0x0, 0x0, 1, "VCCR Current" },
    140	{ 0x20c, 0x0, 0x0, 0x0, 0x0, 1, "VCCT Current" },
    141	{ 0x228, 0x0, 0x0, 0x0, 0x0, 1, "1.8v Current" },
    142	{ 0x240, 0x244, 0x0, 0x0, 0x0, 1, "12v Backplane Current" },
    143	{ 0x25c, 0x260, 0x0, 0x0, 0x0, 1, "12v AUX Current" },
    144};
    145
    146static const struct m10bmc_hwmon_board_data n3000bmc_hwmon_bdata = {
    147	.tables = {
    148		[hwmon_temp] = n3000bmc_temp_tbl,
    149		[hwmon_in] = n3000bmc_in_tbl,
    150		[hwmon_curr] = n3000bmc_curr_tbl,
    151		[hwmon_power] = n3000bmc_power_tbl,
    152	},
    153
    154	.hinfo = n3000bmc_hinfo,
    155};
    156
    157static const struct hwmon_channel_info *d5005bmc_hinfo[] = {
    158	HWMON_CHANNEL_INFO(temp,
    159			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
    160			   HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
    161			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
    162			   HWMON_T_LABEL,
    163			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
    164			   HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
    165			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
    166			   HWMON_T_LABEL,
    167			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
    168			   HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
    169			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
    170			   HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
    171			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
    172			   HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
    173			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
    174			   HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
    175			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
    176			   HWMON_T_LABEL,
    177			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
    178			   HWMON_T_LABEL,
    179			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
    180			   HWMON_T_LABEL,
    181			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
    182			   HWMON_T_LABEL,
    183			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
    184			   HWMON_T_LABEL,
    185			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
    186			   HWMON_T_LABEL,
    187			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
    188			   HWMON_T_LABEL,
    189			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
    190			   HWMON_T_LABEL,
    191			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
    192			   HWMON_T_LABEL),
    193	HWMON_CHANNEL_INFO(in,
    194			   HWMON_I_INPUT | HWMON_I_LABEL,
    195			   HWMON_I_INPUT | HWMON_I_LABEL,
    196			   HWMON_I_INPUT | HWMON_I_LABEL,
    197			   HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT |
    198			   HWMON_I_LABEL,
    199			   HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT |
    200			   HWMON_I_LABEL,
    201			   HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT |
    202			   HWMON_I_LABEL,
    203			   HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT |
    204			   HWMON_I_LABEL,
    205			   HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT |
    206			   HWMON_I_LABEL,
    207			   HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_LABEL,
    208			   HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_LABEL),
    209	HWMON_CHANNEL_INFO(curr,
    210			   HWMON_C_INPUT | HWMON_C_LABEL,
    211			   HWMON_C_INPUT | HWMON_C_LABEL,
    212			   HWMON_C_INPUT | HWMON_C_LABEL,
    213			   HWMON_C_INPUT | HWMON_C_LABEL,
    214			   HWMON_C_INPUT | HWMON_C_LABEL,
    215			   HWMON_C_INPUT | HWMON_C_LABEL,
    216			   HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_LABEL,
    217			   HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_LABEL),
    218	NULL
    219};
    220
    221static const struct m10bmc_hwmon_board_data d5005bmc_hwmon_bdata = {
    222	.tables = {
    223		[hwmon_temp] = d5005bmc_temp_tbl,
    224		[hwmon_in] = d5005bmc_in_tbl,
    225		[hwmon_curr] = d5005bmc_curr_tbl,
    226	},
    227
    228	.hinfo = d5005bmc_hinfo,
    229};
    230
    231static const struct m10bmc_sdata n5010bmc_temp_tbl[] = {
    232	{ 0x100, 0x0, 0x104, 0x0, 0x0, 1000, "Board Local Temperature" },
    233	{ 0x108, 0x0, 0x10c, 0x0, 0x0, 1000, "FPGA 1 Temperature" },
    234	{ 0x110, 0x0, 0x114, 0x0, 0x0, 1000, "FPGA 2 Temperature" },
    235	{ 0x118, 0x0, 0x0, 0x0, 0x0, 1000, "Card Top Temperature" },
    236	{ 0x11c, 0x0, 0x0, 0x0, 0x0, 1000, "Card Bottom Temperature" },
    237	{ 0x128, 0x0, 0x0, 0x0, 0x0, 1000, "FPGA 1.2V Temperature" },
    238	{ 0x134, 0x0, 0x0, 0x0, 0x0, 1000, "FPGA 5V Temperature" },
    239	{ 0x140, 0x0, 0x0, 0x0, 0x0, 1000, "FPGA 0.9V Temperature" },
    240	{ 0x14c, 0x0, 0x0, 0x0, 0x0, 1000, "FPGA 0.85V Temperature" },
    241	{ 0x158, 0x0, 0x0, 0x0, 0x0, 1000, "AUX 12V Temperature" },
    242	{ 0x164, 0x0, 0x0, 0x0, 0x0, 1000, "Backplane 12V Temperature" },
    243	{ 0x1a8, 0x0, 0x0, 0x0, 0x0, 1000, "QSFP28-1 Temperature" },
    244	{ 0x1ac, 0x0, 0x0, 0x0, 0x0, 1000, "QSFP28-2 Temperature" },
    245	{ 0x1b0, 0x0, 0x0, 0x0, 0x0, 1000, "QSFP28-3 Temperature" },
    246	{ 0x1b4, 0x0, 0x0, 0x0, 0x0, 1000, "QSFP28-4 Temperature" },
    247	{ 0x1b8, 0x0, 0x0, 0x0, 0x0, 1000, "CVL1 Internal Temperature" },
    248	{ 0x1bc, 0x0, 0x0, 0x0, 0x0, 1000, "CVL2 Internal Temperature" },
    249};
    250
    251static const struct m10bmc_sdata n5010bmc_in_tbl[] = {
    252	{ 0x120, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 1.2V Voltage" },
    253	{ 0x12c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 5V Voltage" },
    254	{ 0x138, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 0.9V Voltage" },
    255	{ 0x144, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 0.85V Voltage" },
    256	{ 0x150, 0x0, 0x0, 0x0, 0x0, 1, "AUX 12V Voltage" },
    257	{ 0x15c, 0x0, 0x0, 0x0, 0x0, 1, "Backplane 12V Voltage" },
    258	{ 0x16c, 0x0, 0x0, 0x0, 0x0, 1, "DDR4 1.2V Voltage" },
    259	{ 0x17c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 1.8V Voltage" },
    260	{ 0x184, 0x0, 0x0, 0x0, 0x0, 1, "QDR 1.3V Voltage" },
    261	{ 0x18c, 0x0, 0x0, 0x0, 0x0, 1, "CVL1 0.8V Voltage" },
    262	{ 0x194, 0x0, 0x0, 0x0, 0x0, 1, "CVL1 1.05V Voltage" },
    263	{ 0x19c, 0x0, 0x0, 0x0, 0x0, 1, "CVL2 1.05V Voltage" },
    264	{ 0x1a4, 0x0, 0x0, 0x0, 0x0, 1, "CVL2 0.8V Voltage" },
    265};
    266
    267static const struct m10bmc_sdata n5010bmc_curr_tbl[] = {
    268	{ 0x124, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 1.2V Current" },
    269	{ 0x130, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 5V Current" },
    270	{ 0x13c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 0.9V Current" },
    271	{ 0x148, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 0.85V Current" },
    272	{ 0x154, 0x0, 0x0, 0x0, 0x0, 1, "AUX 12V Current" },
    273	{ 0x160, 0x0, 0x0, 0x0, 0x0, 1, "Backplane 12V Current" },
    274	{ 0x168, 0x0, 0x0, 0x0, 0x0, 1, "DDR4 1.2V Current" },
    275	{ 0x178, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 1.8V Current" },
    276	{ 0x180, 0x0, 0x0, 0x0, 0x0, 1, "QDR 1.3V Current" },
    277	{ 0x188, 0x0, 0x0, 0x0, 0x0, 1, "CVL1 0.8V Current" },
    278	{ 0x190, 0x0, 0x0, 0x0, 0x0, 1, "CVL1 1.05V Current" },
    279	{ 0x198, 0x0, 0x0, 0x0, 0x0, 1, "CVL2 1.05V Current" },
    280	{ 0x1a0, 0x0, 0x0, 0x0, 0x0, 1, "CVL2 0.8V Current" },
    281};
    282
    283static const struct hwmon_channel_info *n5010bmc_hinfo[] = {
    284	HWMON_CHANNEL_INFO(temp,
    285			   HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL,
    286			   HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL,
    287			   HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL,
    288			   HWMON_T_INPUT | HWMON_T_LABEL,
    289			   HWMON_T_INPUT | HWMON_T_LABEL,
    290			   HWMON_T_INPUT | HWMON_T_LABEL,
    291			   HWMON_T_INPUT | HWMON_T_LABEL,
    292			   HWMON_T_INPUT | HWMON_T_LABEL,
    293			   HWMON_T_INPUT | HWMON_T_LABEL,
    294			   HWMON_T_INPUT | HWMON_T_LABEL,
    295			   HWMON_T_INPUT | HWMON_T_LABEL,
    296			   HWMON_T_INPUT | HWMON_T_LABEL,
    297			   HWMON_T_INPUT | HWMON_T_LABEL,
    298			   HWMON_T_INPUT | HWMON_T_LABEL,
    299			   HWMON_T_INPUT | HWMON_T_LABEL,
    300			   HWMON_T_INPUT | HWMON_T_LABEL,
    301			   HWMON_T_INPUT | HWMON_T_LABEL),
    302	HWMON_CHANNEL_INFO(in,
    303			   HWMON_I_INPUT | HWMON_I_LABEL,
    304			   HWMON_I_INPUT | HWMON_I_LABEL,
    305			   HWMON_I_INPUT | HWMON_I_LABEL,
    306			   HWMON_I_INPUT | HWMON_I_LABEL,
    307			   HWMON_I_INPUT | HWMON_I_LABEL,
    308			   HWMON_I_INPUT | HWMON_I_LABEL,
    309			   HWMON_I_INPUT | HWMON_I_LABEL,
    310			   HWMON_I_INPUT | HWMON_I_LABEL,
    311			   HWMON_I_INPUT | HWMON_I_LABEL,
    312			   HWMON_I_INPUT | HWMON_I_LABEL,
    313			   HWMON_I_INPUT | HWMON_I_LABEL,
    314			   HWMON_I_INPUT | HWMON_I_LABEL,
    315			   HWMON_I_INPUT | HWMON_I_LABEL),
    316	HWMON_CHANNEL_INFO(curr,
    317			   HWMON_C_INPUT | HWMON_C_LABEL,
    318			   HWMON_C_INPUT | HWMON_C_LABEL,
    319			   HWMON_C_INPUT | HWMON_C_LABEL,
    320			   HWMON_C_INPUT | HWMON_C_LABEL,
    321			   HWMON_C_INPUT | HWMON_C_LABEL,
    322			   HWMON_C_INPUT | HWMON_C_LABEL,
    323			   HWMON_C_INPUT | HWMON_C_LABEL,
    324			   HWMON_C_INPUT | HWMON_C_LABEL,
    325			   HWMON_C_INPUT | HWMON_C_LABEL,
    326			   HWMON_C_INPUT | HWMON_C_LABEL,
    327			   HWMON_C_INPUT | HWMON_C_LABEL,
    328			   HWMON_C_INPUT | HWMON_C_LABEL,
    329			   HWMON_C_INPUT | HWMON_C_LABEL),
    330	NULL
    331};
    332
    333static const struct m10bmc_hwmon_board_data n5010bmc_hwmon_bdata = {
    334	.tables = {
    335		[hwmon_temp] = n5010bmc_temp_tbl,
    336		[hwmon_in] = n5010bmc_in_tbl,
    337		[hwmon_curr] = n5010bmc_curr_tbl,
    338	},
    339
    340	.hinfo = n5010bmc_hinfo,
    341};
    342
    343static umode_t
    344m10bmc_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
    345			u32 attr, int channel)
    346{
    347	return 0444;
    348}
    349
    350static const struct m10bmc_sdata *
    351find_sensor_data(struct m10bmc_hwmon *hw, enum hwmon_sensor_types type,
    352		 int channel)
    353{
    354	const struct m10bmc_sdata *tbl;
    355
    356	tbl = hw->bdata->tables[type];
    357	if (!tbl)
    358		return ERR_PTR(-EOPNOTSUPP);
    359
    360	return &tbl[channel];
    361}
    362
    363static int do_sensor_read(struct m10bmc_hwmon *hw,
    364			  const struct m10bmc_sdata *data,
    365			  unsigned int regoff, long *val)
    366{
    367	unsigned int regval;
    368	int ret;
    369
    370	ret = m10bmc_sys_read(hw->m10bmc, regoff, &regval);
    371	if (ret)
    372		return ret;
    373
    374	/*
    375	 * BMC Firmware will return 0xdeadbeef if the sensor value is invalid
    376	 * at that time. This usually happens on sensor channels which connect
    377	 * to external pluggable modules, e.g. QSFP temperature and voltage.
    378	 * When the QSFP is unplugged from cage, driver will get 0xdeadbeef
    379	 * from their registers.
    380	 */
    381	if (regval == 0xdeadbeef)
    382		return -ENODATA;
    383
    384	*val = regval * data->multiplier;
    385
    386	return 0;
    387}
    388
    389static int m10bmc_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
    390			     u32 attr, int channel, long *val)
    391{
    392	struct m10bmc_hwmon *hw = dev_get_drvdata(dev);
    393	unsigned int reg = 0, reg_hyst = 0;
    394	const struct m10bmc_sdata *data;
    395	long hyst, value;
    396	int ret;
    397
    398	data = find_sensor_data(hw, type, channel);
    399	if (IS_ERR(data))
    400		return PTR_ERR(data);
    401
    402	switch (type) {
    403	case hwmon_temp:
    404		switch (attr) {
    405		case hwmon_temp_input:
    406			reg = data->reg_input;
    407			break;
    408		case hwmon_temp_max_hyst:
    409			reg_hyst = data->reg_hyst;
    410			fallthrough;
    411		case hwmon_temp_max:
    412			reg = data->reg_max;
    413			break;
    414		case hwmon_temp_crit_hyst:
    415			reg_hyst = data->reg_hyst;
    416			fallthrough;
    417		case hwmon_temp_crit:
    418			reg = data->reg_crit;
    419			break;
    420		default:
    421			return -EOPNOTSUPP;
    422		}
    423		break;
    424	case hwmon_in:
    425		switch (attr) {
    426		case hwmon_in_input:
    427			reg = data->reg_input;
    428			break;
    429		case hwmon_in_max:
    430			reg = data->reg_max;
    431			break;
    432		case hwmon_in_crit:
    433			reg = data->reg_crit;
    434			break;
    435		case hwmon_in_min:
    436			reg = data->reg_min;
    437			break;
    438		default:
    439			return -EOPNOTSUPP;
    440		}
    441		break;
    442	case hwmon_curr:
    443		switch (attr) {
    444		case hwmon_curr_input:
    445			reg = data->reg_input;
    446			break;
    447		case hwmon_curr_max:
    448			reg = data->reg_max;
    449			break;
    450		case hwmon_curr_crit:
    451			reg = data->reg_crit;
    452			break;
    453		default:
    454			return -EOPNOTSUPP;
    455		}
    456		break;
    457	case hwmon_power:
    458		switch (attr) {
    459		case hwmon_power_input:
    460			reg = data->reg_input;
    461			break;
    462		default:
    463			return -EOPNOTSUPP;
    464		}
    465		break;
    466	default:
    467		return -EOPNOTSUPP;
    468	}
    469
    470	if (!reg)
    471		return -EOPNOTSUPP;
    472
    473	ret = do_sensor_read(hw, data, reg, &value);
    474	if (ret)
    475		return ret;
    476
    477	if (reg_hyst) {
    478		ret = do_sensor_read(hw, data, reg_hyst, &hyst);
    479		if (ret)
    480			return ret;
    481
    482		value -= hyst;
    483	}
    484
    485	*val = value;
    486
    487	return 0;
    488}
    489
    490static int m10bmc_hwmon_read_string(struct device *dev,
    491				    enum hwmon_sensor_types type,
    492				    u32 attr, int channel, const char **str)
    493{
    494	struct m10bmc_hwmon *hw = dev_get_drvdata(dev);
    495	const struct m10bmc_sdata *data;
    496
    497	data = find_sensor_data(hw, type, channel);
    498	if (IS_ERR(data))
    499		return PTR_ERR(data);
    500
    501	*str = data->label;
    502
    503	return 0;
    504}
    505
    506static const struct hwmon_ops m10bmc_hwmon_ops = {
    507	.is_visible = m10bmc_hwmon_is_visible,
    508	.read = m10bmc_hwmon_read,
    509	.read_string = m10bmc_hwmon_read_string,
    510};
    511
    512static int m10bmc_hwmon_probe(struct platform_device *pdev)
    513{
    514	const struct platform_device_id *id = platform_get_device_id(pdev);
    515	struct intel_m10bmc *m10bmc = dev_get_drvdata(pdev->dev.parent);
    516	struct device *hwmon_dev, *dev = &pdev->dev;
    517	struct m10bmc_hwmon *hw;
    518
    519	hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
    520	if (!hw)
    521		return -ENOMEM;
    522
    523	hw->dev = dev;
    524	hw->m10bmc = m10bmc;
    525	hw->bdata = (const struct m10bmc_hwmon_board_data *)id->driver_data;
    526
    527	hw->chip.info = hw->bdata->hinfo;
    528	hw->chip.ops = &m10bmc_hwmon_ops;
    529
    530	hw->hw_name = devm_hwmon_sanitize_name(dev, id->name);
    531	if (IS_ERR(hw->hw_name))
    532		return PTR_ERR(hw->hw_name);
    533
    534	hwmon_dev = devm_hwmon_device_register_with_info(dev, hw->hw_name,
    535							 hw, &hw->chip, NULL);
    536	return PTR_ERR_OR_ZERO(hwmon_dev);
    537}
    538
    539static const struct platform_device_id intel_m10bmc_hwmon_ids[] = {
    540	{
    541		.name = "n3000bmc-hwmon",
    542		.driver_data = (unsigned long)&n3000bmc_hwmon_bdata,
    543	},
    544	{
    545		.name = "d5005bmc-hwmon",
    546		.driver_data = (unsigned long)&d5005bmc_hwmon_bdata,
    547	},
    548	{
    549		.name = "n5010bmc-hwmon",
    550		.driver_data = (unsigned long)&n5010bmc_hwmon_bdata,
    551	},
    552	{ }
    553};
    554
    555static struct platform_driver intel_m10bmc_hwmon_driver = {
    556	.probe = m10bmc_hwmon_probe,
    557	.driver = {
    558		.name = "intel-m10-bmc-hwmon",
    559	},
    560	.id_table = intel_m10bmc_hwmon_ids,
    561};
    562module_platform_driver(intel_m10bmc_hwmon_driver);
    563
    564MODULE_DEVICE_TABLE(platform, intel_m10bmc_hwmon_ids);
    565MODULE_AUTHOR("Intel Corporation");
    566MODULE_DESCRIPTION("Intel MAX 10 BMC hardware monitor");
    567MODULE_LICENSE("GPL");