1 // SPDX-License-Identifier: GPL-2.0
3 * Intel MAX 10 BMC HWMON Driver
5 * Copyright (C) 2018-2020 Intel Corporation. All rights reserved.
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>
16 unsigned int reg_input
;
18 unsigned int reg_crit
;
19 unsigned int reg_hyst
;
21 unsigned int multiplier
;
25 struct m10bmc_hwmon_board_data
{
26 const struct m10bmc_sdata
*tables
[hwmon_max
];
27 const struct hwmon_channel_info
**hinfo
;
32 struct hwmon_chip_info chip
;
34 struct intel_m10bmc
*m10bmc
;
35 const struct m10bmc_hwmon_board_data
*bdata
;
38 static 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" },
49 static 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" },
60 static 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" },
66 static const struct m10bmc_sdata n3000bmc_power_tbl
[] = {
67 { 0x160, 0x0, 0x0, 0x0, 0x0, 1000, "Board Power" },
70 static 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
|
76 HWMON_T_INPUT
| HWMON_T_MAX
| HWMON_T_CRIT
|
78 HWMON_T_INPUT
| HWMON_T_MAX
| HWMON_T_CRIT
|
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
),
102 static const struct m10bmc_hwmon_board_data n3000bmc_hwmon_bdata
= {
104 [hwmon_temp
] = n3000bmc_temp_tbl
,
105 [hwmon_in
] = n3000bmc_in_tbl
,
106 [hwmon_curr
] = n3000bmc_curr_tbl
,
107 [hwmon_power
] = n3000bmc_power_tbl
,
110 .hinfo
= n3000bmc_hinfo
,
114 m10bmc_hwmon_is_visible(const void *data
, enum hwmon_sensor_types type
,
115 u32 attr
, int channel
)
120 static const struct m10bmc_sdata
*
121 find_sensor_data(struct m10bmc_hwmon
*hw
, enum hwmon_sensor_types type
,
124 const struct m10bmc_sdata
*tbl
;
126 tbl
= hw
->bdata
->tables
[type
];
128 return ERR_PTR(-EOPNOTSUPP
);
130 return &tbl
[channel
];
133 static int do_sensor_read(struct m10bmc_hwmon
*hw
,
134 const struct m10bmc_sdata
*data
,
135 unsigned int regoff
, long *val
)
140 ret
= m10bmc_sys_read(hw
->m10bmc
, regoff
, ®val
);
145 * BMC Firmware will return 0xdeadbeef if the sensor value is invalid
146 * at that time. This usually happens on sensor channels which connect
147 * to external pluggable modules, e.g. QSFP temperature and voltage.
148 * When the QSFP is unplugged from cage, driver will get 0xdeadbeef
149 * from their registers.
151 if (regval
== 0xdeadbeef)
154 *val
= regval
* data
->multiplier
;
159 static int m10bmc_hwmon_read(struct device
*dev
, enum hwmon_sensor_types type
,
160 u32 attr
, int channel
, long *val
)
162 struct m10bmc_hwmon
*hw
= dev_get_drvdata(dev
);
163 unsigned int reg
= 0, reg_hyst
= 0;
164 const struct m10bmc_sdata
*data
;
168 data
= find_sensor_data(hw
, type
, channel
);
170 return PTR_ERR(data
);
175 case hwmon_temp_input
:
176 reg
= data
->reg_input
;
178 case hwmon_temp_max_hyst
:
179 reg_hyst
= data
->reg_hyst
;
184 case hwmon_temp_crit_hyst
:
185 reg_hyst
= data
->reg_hyst
;
187 case hwmon_temp_crit
:
188 reg
= data
->reg_crit
;
197 reg
= data
->reg_input
;
203 reg
= data
->reg_crit
;
214 case hwmon_curr_input
:
215 reg
= data
->reg_input
;
220 case hwmon_curr_crit
:
221 reg
= data
->reg_crit
;
229 case hwmon_power_input
:
230 reg
= data
->reg_input
;
243 ret
= do_sensor_read(hw
, data
, reg
, &value
);
248 ret
= do_sensor_read(hw
, data
, reg_hyst
, &hyst
);
260 static int m10bmc_hwmon_read_string(struct device
*dev
,
261 enum hwmon_sensor_types type
,
262 u32 attr
, int channel
, const char **str
)
264 struct m10bmc_hwmon
*hw
= dev_get_drvdata(dev
);
265 const struct m10bmc_sdata
*data
;
267 data
= find_sensor_data(hw
, type
, channel
);
269 return PTR_ERR(data
);
276 static const struct hwmon_ops m10bmc_hwmon_ops
= {
277 .is_visible
= m10bmc_hwmon_is_visible
,
278 .read
= m10bmc_hwmon_read
,
279 .read_string
= m10bmc_hwmon_read_string
,
282 static int m10bmc_hwmon_probe(struct platform_device
*pdev
)
284 const struct platform_device_id
*id
= platform_get_device_id(pdev
);
285 struct intel_m10bmc
*m10bmc
= dev_get_drvdata(pdev
->dev
.parent
);
286 struct device
*hwmon_dev
, *dev
= &pdev
->dev
;
287 struct m10bmc_hwmon
*hw
;
290 hw
= devm_kzalloc(dev
, sizeof(*hw
), GFP_KERNEL
);
296 hw
->bdata
= (const struct m10bmc_hwmon_board_data
*)id
->driver_data
;
298 hw
->chip
.info
= hw
->bdata
->hinfo
;
299 hw
->chip
.ops
= &m10bmc_hwmon_ops
;
301 hw
->hw_name
= devm_kstrdup(dev
, id
->name
, GFP_KERNEL
);
305 for (i
= 0; hw
->hw_name
[i
]; i
++)
306 if (hwmon_is_bad_char(hw
->hw_name
[i
]))
307 hw
->hw_name
[i
] = '_';
309 hwmon_dev
= devm_hwmon_device_register_with_info(dev
, hw
->hw_name
,
310 hw
, &hw
->chip
, NULL
);
311 return PTR_ERR_OR_ZERO(hwmon_dev
);
314 static const struct platform_device_id intel_m10bmc_hwmon_ids
[] = {
316 .name
= "n3000bmc-hwmon",
317 .driver_data
= (unsigned long)&n3000bmc_hwmon_bdata
,
322 static struct platform_driver intel_m10bmc_hwmon_driver
= {
323 .probe
= m10bmc_hwmon_probe
,
325 .name
= "intel-m10-bmc-hwmon",
327 .id_table
= intel_m10bmc_hwmon_ids
,
329 module_platform_driver(intel_m10bmc_hwmon_driver
);
331 MODULE_DEVICE_TABLE(platform
, intel_m10bmc_hwmon_ids
);
332 MODULE_AUTHOR("Intel Corporation");
333 MODULE_DESCRIPTION("Intel MAX 10 BMC hardware monitor");
334 MODULE_LICENSE("GPL");