Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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, &regval);
^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");