1 // SPDX-License-Identifier: GPL-2.0-only
3 * sl28cpld hardware monitoring driver
5 * Copyright 2020 Kontron Europe GmbH
8 #include <linux/bitfield.h>
9 #include <linux/hwmon.h>
10 #include <linux/kernel.h>
11 #include <linux/mod_devicetable.h>
12 #include <linux/module.h>
13 #include <linux/platform_device.h>
14 #include <linux/property.h>
15 #include <linux/regmap.h>
17 #define FAN_INPUT 0x00
18 #define FAN_SCALE_X8 BIT(7)
19 #define FAN_VALUE_MASK GENMASK(6, 0)
21 struct sl28cpld_hwmon
{
22 struct regmap
*regmap
;
26 static umode_t
sl28cpld_hwmon_is_visible(const void *data
,
27 enum hwmon_sensor_types type
,
28 u32 attr
, int channel
)
33 static int sl28cpld_hwmon_read(struct device
*dev
,
34 enum hwmon_sensor_types type
, u32 attr
,
35 int channel
, long *input
)
37 struct sl28cpld_hwmon
*hwmon
= dev_get_drvdata(dev
);
43 ret
= regmap_read(hwmon
->regmap
, hwmon
->offset
+ FAN_INPUT
,
48 * The register has a 7 bit value and 1 bit which indicates the
49 * scale. If the MSB is set, then the lower 7 bit has to be
50 * multiplied by 8, to get the correct reading.
52 if (value
& FAN_SCALE_X8
)
53 value
= FIELD_GET(FAN_VALUE_MASK
, value
) << 3;
56 * The counter period is 1000ms and the sysfs specification
57 * says we should asssume 2 pulses per revolution.
70 static const u32 sl28cpld_hwmon_fan_config
[] = {
75 static const struct hwmon_channel_info sl28cpld_hwmon_fan
= {
77 .config
= sl28cpld_hwmon_fan_config
,
80 static const struct hwmon_channel_info
*sl28cpld_hwmon_info
[] = {
85 static const struct hwmon_ops sl28cpld_hwmon_ops
= {
86 .is_visible
= sl28cpld_hwmon_is_visible
,
87 .read
= sl28cpld_hwmon_read
,
90 static const struct hwmon_chip_info sl28cpld_hwmon_chip_info
= {
91 .ops
= &sl28cpld_hwmon_ops
,
92 .info
= sl28cpld_hwmon_info
,
95 static int sl28cpld_hwmon_probe(struct platform_device
*pdev
)
97 struct sl28cpld_hwmon
*hwmon
;
98 struct device
*hwmon_dev
;
101 if (!pdev
->dev
.parent
)
104 hwmon
= devm_kzalloc(&pdev
->dev
, sizeof(*hwmon
), GFP_KERNEL
);
108 hwmon
->regmap
= dev_get_regmap(pdev
->dev
.parent
, NULL
);
112 ret
= device_property_read_u32(&pdev
->dev
, "reg", &hwmon
->offset
);
116 hwmon_dev
= devm_hwmon_device_register_with_info(&pdev
->dev
,
117 "sl28cpld_hwmon", hwmon
,
118 &sl28cpld_hwmon_chip_info
, NULL
);
119 if (IS_ERR(hwmon_dev
))
120 dev_err(&pdev
->dev
, "failed to register as hwmon device");
122 return PTR_ERR_OR_ZERO(hwmon_dev
);
125 static const struct of_device_id sl28cpld_hwmon_of_match
[] = {
126 { .compatible
= "kontron,sl28cpld-fan" },
129 MODULE_DEVICE_TABLE(of
, sl28cpld_hwmon_of_match
);
131 static struct platform_driver sl28cpld_hwmon_driver
= {
132 .probe
= sl28cpld_hwmon_probe
,
134 .name
= "sl28cpld-fan",
135 .of_match_table
= sl28cpld_hwmon_of_match
,
138 module_platform_driver(sl28cpld_hwmon_driver
);
140 MODULE_DESCRIPTION("sl28cpld Hardware Monitoring Driver");
141 MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
142 MODULE_LICENSE("GPL");