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 int sl28cpld_hwmon_read(struct device
*dev
,
27 enum hwmon_sensor_types type
, u32 attr
,
28 int channel
, long *input
)
30 struct sl28cpld_hwmon
*hwmon
= dev_get_drvdata(dev
);
36 ret
= regmap_read(hwmon
->regmap
, hwmon
->offset
+ FAN_INPUT
,
41 * The register has a 7 bit value and 1 bit which indicates the
42 * scale. If the MSB is set, then the lower 7 bit has to be
43 * multiplied by 8, to get the correct reading.
45 if (value
& FAN_SCALE_X8
)
46 value
= FIELD_GET(FAN_VALUE_MASK
, value
) << 3;
49 * The counter period is 1000ms and the sysfs specification
50 * says we should assume 2 pulses per revolution.
63 static const struct hwmon_channel_info
* const sl28cpld_hwmon_info
[] = {
64 HWMON_CHANNEL_INFO(fan
, HWMON_F_INPUT
),
68 static const struct hwmon_ops sl28cpld_hwmon_ops
= {
70 .read
= sl28cpld_hwmon_read
,
73 static const struct hwmon_chip_info sl28cpld_hwmon_chip_info
= {
74 .ops
= &sl28cpld_hwmon_ops
,
75 .info
= sl28cpld_hwmon_info
,
78 static int sl28cpld_hwmon_probe(struct platform_device
*pdev
)
80 struct sl28cpld_hwmon
*hwmon
;
81 struct device
*hwmon_dev
;
84 if (!pdev
->dev
.parent
)
87 hwmon
= devm_kzalloc(&pdev
->dev
, sizeof(*hwmon
), GFP_KERNEL
);
91 hwmon
->regmap
= dev_get_regmap(pdev
->dev
.parent
, NULL
);
95 ret
= device_property_read_u32(&pdev
->dev
, "reg", &hwmon
->offset
);
99 hwmon_dev
= devm_hwmon_device_register_with_info(&pdev
->dev
,
100 "sl28cpld_hwmon", hwmon
,
101 &sl28cpld_hwmon_chip_info
, NULL
);
102 if (IS_ERR(hwmon_dev
))
103 dev_err(&pdev
->dev
, "failed to register as hwmon device");
105 return PTR_ERR_OR_ZERO(hwmon_dev
);
108 static const struct of_device_id sl28cpld_hwmon_of_match
[] = {
109 { .compatible
= "kontron,sl28cpld-fan" },
112 MODULE_DEVICE_TABLE(of
, sl28cpld_hwmon_of_match
);
114 static struct platform_driver sl28cpld_hwmon_driver
= {
115 .probe
= sl28cpld_hwmon_probe
,
117 .name
= "sl28cpld-fan",
118 .of_match_table
= sl28cpld_hwmon_of_match
,
121 module_platform_driver(sl28cpld_hwmon_driver
);
123 MODULE_DESCRIPTION("sl28cpld Hardware Monitoring Driver");
124 MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
125 MODULE_LICENSE("GPL");