Skip to content

Commit a02b105

Browse files
DimitriFedrauUwe Kleine-König
authored andcommitted
hwmon: add support for MC33XS2410 hardware monitoring
The device is able to monitor temperature, voltage and current of each of the four outputs. Add basic support for monitoring the temperature of the four outputs and the die temperature. Signed-off-by: Dimitri Fedrau <[email protected]> Acked-by: Guenter Roeck <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Uwe Kleine-König <[email protected]>
1 parent 28517c8 commit a02b105

File tree

5 files changed

+224
-0
lines changed

5 files changed

+224
-0
lines changed

Documentation/hwmon/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ Hardware Monitoring Kernel Drivers
167167
max77705
168168
max8688
169169
mc13783-adc
170+
mc33xs2410_hwmon
170171
mc34vr500
171172
mcp3021
172173
menf21bmc
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
.. SPDX-License-Identifier: GPL-2.0
2+
3+
Kernel driver mc33xs2410_hwmon
4+
==============================
5+
6+
Supported devices:
7+
8+
* NXPs MC33XS2410
9+
10+
Datasheet: https://www.nxp.com/docs/en/data-sheet/MC33XS2410.pdf
11+
12+
Authors:
13+
14+
Dimitri Fedrau <[email protected]>
15+
16+
Description
17+
-----------
18+
19+
The MC33XS2410 is a four channel self-protected high-side switch featuring
20+
hardware monitoring functions such as temperature, current and voltages for each
21+
of the four channels.
22+
23+
Sysfs entries
24+
-------------
25+
26+
======================= ======================================================
27+
temp1_label "Central die temperature"
28+
temp1_input Measured temperature of central die
29+
30+
temp[2-5]_label "Channel [1-4] temperature"
31+
temp[2-5]_input Measured temperature of a single channel
32+
temp[2-5]_alarm Temperature alarm
33+
temp[2-5]_max Maximal temperature
34+
======================= ======================================================

drivers/hwmon/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,16 @@ config SENSORS_MC13783_ADC
700700
help
701701
Support for the A/D converter on MC13783 and MC13892 PMIC.
702702

703+
config SENSORS_MC33XS2410
704+
tristate "MC33XS2410 HWMON support"
705+
depends on PWM_MC33XS2410
706+
help
707+
If you say yes here you get hardware monitoring support for
708+
MC33XS2410.
709+
710+
This driver can also be built as a module. If so, the module
711+
will be called mc33xs2410_hwmon.
712+
703713
config SENSORS_FSCHMD
704714
tristate "Fujitsu Siemens Computers sensor chips"
705715
depends on (X86 || COMPILE_TEST) && I2C

drivers/hwmon/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ obj-$(CONFIG_SENSORS_MAX31790) += max31790.o
165165
obj-$(CONFIG_MAX31827) += max31827.o
166166
obj-$(CONFIG_SENSORS_MAX77705) += max77705-hwmon.o
167167
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
168+
obj-$(CONFIG_SENSORS_MC33XS2410) += mc33xs2410_hwmon.o
168169
obj-$(CONFIG_SENSORS_MC34VR500) += mc34vr500.o
169170
obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o
170171
obj-$(CONFIG_SENSORS_TC654) += tc654.o

drivers/hwmon/mc33xs2410_hwmon.c

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (C) 2025 Liebherr-Electronics and Drives GmbH
4+
*/
5+
6+
#include <linux/auxiliary_bus.h>
7+
#include <linux/bitfield.h>
8+
#include <linux/bitops.h>
9+
#include <linux/hwmon.h>
10+
#include <linux/mc33xs2410.h>
11+
#include <linux/module.h>
12+
13+
/* ctrl registers */
14+
15+
#define MC33XS2410_TEMP_WT 0x29
16+
#define MC33XS2410_TEMP_WT_MASK GENMASK(7, 0)
17+
18+
/* diag registers */
19+
20+
/* chan in { 1 ... 4 } */
21+
#define MC33XS2410_OUT_STA(chan) (0x02 + (chan) - 1)
22+
#define MC33XS2410_OUT_STA_OTW BIT(8)
23+
24+
#define MC33XS2410_TS_TEMP_DIE 0x26
25+
#define MC33XS2410_TS_TEMP_MASK GENMASK(9, 0)
26+
27+
/* chan in { 1 ... 4 } */
28+
#define MC33XS2410_TS_TEMP(chan) (0x2f + (chan) - 1)
29+
30+
static const struct hwmon_channel_info * const mc33xs2410_hwmon_info[] = {
31+
HWMON_CHANNEL_INFO(temp,
32+
HWMON_T_LABEL | HWMON_T_INPUT,
33+
HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX |
34+
HWMON_T_ALARM,
35+
HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX |
36+
HWMON_T_ALARM,
37+
HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX |
38+
HWMON_T_ALARM,
39+
HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX |
40+
HWMON_T_ALARM),
41+
NULL,
42+
};
43+
44+
static umode_t mc33xs2410_hwmon_is_visible(const void *data,
45+
enum hwmon_sensor_types type,
46+
u32 attr, int channel)
47+
{
48+
switch (attr) {
49+
case hwmon_temp_input:
50+
case hwmon_temp_alarm:
51+
case hwmon_temp_label:
52+
return 0444;
53+
case hwmon_temp_max:
54+
return 0644;
55+
default:
56+
return 0;
57+
}
58+
}
59+
60+
static int mc33xs2410_hwmon_read(struct device *dev,
61+
enum hwmon_sensor_types type,
62+
u32 attr, int channel, long *val)
63+
{
64+
struct spi_device *spi = dev_get_drvdata(dev);
65+
u16 reg_val;
66+
int ret;
67+
u8 reg;
68+
69+
switch (attr) {
70+
case hwmon_temp_input:
71+
reg = (channel == 0) ? MC33XS2410_TS_TEMP_DIE :
72+
MC33XS2410_TS_TEMP(channel);
73+
ret = mc33xs2410_read_reg_diag(spi, reg, &reg_val);
74+
if (ret < 0)
75+
return ret;
76+
77+
/* LSB is 0.25 degree celsius */
78+
*val = FIELD_GET(MC33XS2410_TS_TEMP_MASK, reg_val) * 250 - 40000;
79+
return 0;
80+
case hwmon_temp_alarm:
81+
ret = mc33xs2410_read_reg_diag(spi, MC33XS2410_OUT_STA(channel),
82+
&reg_val);
83+
if (ret < 0)
84+
return ret;
85+
86+
*val = FIELD_GET(MC33XS2410_OUT_STA_OTW, reg_val);
87+
return 0;
88+
case hwmon_temp_max:
89+
ret = mc33xs2410_read_reg_ctrl(spi, MC33XS2410_TEMP_WT, &reg_val);
90+
if (ret < 0)
91+
return ret;
92+
93+
/* LSB is 1 degree celsius */
94+
*val = FIELD_GET(MC33XS2410_TEMP_WT_MASK, reg_val) * 1000 - 40000;
95+
return 0;
96+
default:
97+
return -EOPNOTSUPP;
98+
}
99+
}
100+
101+
static int mc33xs2410_hwmon_write(struct device *dev,
102+
enum hwmon_sensor_types type, u32 attr,
103+
int channel, long val)
104+
{
105+
struct spi_device *spi = dev_get_drvdata(dev);
106+
107+
switch (attr) {
108+
case hwmon_temp_max:
109+
val = clamp_val(val, -40000, 215000);
110+
111+
/* LSB is 1 degree celsius */
112+
val = (val / 1000) + 40;
113+
return mc33xs2410_modify_reg(spi, MC33XS2410_TEMP_WT,
114+
MC33XS2410_TEMP_WT_MASK, val);
115+
default:
116+
return -EOPNOTSUPP;
117+
}
118+
}
119+
120+
static const char *const mc33xs2410_temp_label[] = {
121+
"Central die temperature",
122+
"Channel 1 temperature",
123+
"Channel 2 temperature",
124+
"Channel 3 temperature",
125+
"Channel 4 temperature",
126+
};
127+
128+
static int mc33xs2410_read_string(struct device *dev,
129+
enum hwmon_sensor_types type,
130+
u32 attr, int channel, const char **str)
131+
{
132+
*str = mc33xs2410_temp_label[channel];
133+
134+
return 0;
135+
}
136+
137+
static const struct hwmon_ops mc33xs2410_hwmon_hwmon_ops = {
138+
.is_visible = mc33xs2410_hwmon_is_visible,
139+
.read = mc33xs2410_hwmon_read,
140+
.read_string = mc33xs2410_read_string,
141+
.write = mc33xs2410_hwmon_write,
142+
};
143+
144+
static const struct hwmon_chip_info mc33xs2410_hwmon_chip_info = {
145+
.ops = &mc33xs2410_hwmon_hwmon_ops,
146+
.info = mc33xs2410_hwmon_info,
147+
};
148+
149+
static int mc33xs2410_hwmon_probe(struct auxiliary_device *adev,
150+
const struct auxiliary_device_id *id)
151+
{
152+
struct device *dev = &adev->dev;
153+
struct spi_device *spi = container_of(dev->parent, struct spi_device, dev);
154+
struct device *hwmon;
155+
156+
hwmon = devm_hwmon_device_register_with_info(dev, NULL, spi,
157+
&mc33xs2410_hwmon_chip_info,
158+
NULL);
159+
return PTR_ERR_OR_ZERO(hwmon);
160+
}
161+
162+
static const struct auxiliary_device_id mc33xs2410_hwmon_ids[] = {
163+
{
164+
.name = "pwm_mc33xs2410.hwmon",
165+
},
166+
{ }
167+
};
168+
MODULE_DEVICE_TABLE(auxiliary, mc33xs2410_hwmon_ids);
169+
170+
static struct auxiliary_driver mc33xs2410_hwmon_driver = {
171+
.probe = mc33xs2410_hwmon_probe,
172+
.id_table = mc33xs2410_hwmon_ids,
173+
};
174+
module_auxiliary_driver(mc33xs2410_hwmon_driver);
175+
176+
MODULE_DESCRIPTION("NXP MC33XS2410 hwmon driver");
177+
MODULE_AUTHOR("Dimitri Fedrau <[email protected]>");
178+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)