Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hwmon: Add support for the sl28cpld hardware monitoring controller

Add support for the hardware monitoring controller of the sl28cpld board
management controller. This driver is part of a multi-function device.

Signed-off-by: Michael Walle <michael@walle.cc>
Acked-by: Guenter Roeck <linux@roeck-us.net>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>

authored by

Michael Walle and committed by
Lee Jones
3f697027 b7536d87

+190
+1
Documentation/hwmon/index.rst
··· 154 154 sht3x 155 155 shtc1 156 156 sis5595 157 + sl28cpld 157 158 smm665 158 159 smsc47b397 159 160 smsc47m192
+36
Documentation/hwmon/sl28cpld.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0-only 2 + 3 + Kernel driver sl28cpld 4 + ====================== 5 + 6 + Supported chips: 7 + 8 + * Kontron sl28cpld 9 + 10 + Prefix: 'sl28cpld' 11 + 12 + Datasheet: not available 13 + 14 + Authors: Michael Walle <michael@walle.cc> 15 + 16 + Description 17 + ----------- 18 + 19 + The sl28cpld is a board management controller which also exposes a hardware 20 + monitoring controller. At the moment this controller supports a single fan 21 + supervisor. In the future there might be other flavours and additional 22 + hardware monitoring might be supported. 23 + 24 + The fan supervisor has a 7 bit counter register and a counter period of 1 25 + second. If the 7 bit counter overflows, the supervisor will automatically 26 + switch to x8 mode to support a wider input range at the loss of 27 + granularity. 28 + 29 + Sysfs entries 30 + ------------- 31 + 32 + The following attributes are supported. 33 + 34 + ======================= ======================================================== 35 + fan1_input Fan RPM. Assuming 2 pulses per revolution. 36 + ======================= ========================================================
+10
drivers/hwmon/Kconfig
··· 1479 1479 This driver can also be built as a module. If so, the module 1480 1480 will be called raspberrypi-hwmon. 1481 1481 1482 + config SENSORS_SL28CPLD 1483 + tristate "Kontron sl28cpld hardware monitoring driver" 1484 + depends on MFD_SL28CPLD || COMPILE_TEST 1485 + help 1486 + If you say yes here you get support for the fan supervisor of the 1487 + sl28cpld board management controller. 1488 + 1489 + This driver can also be built as a module. If so, the module 1490 + will be called sl28cpld-hwmon. 1491 + 1482 1492 config SENSORS_SHT15 1483 1493 tristate "Sensiron humidity and temperature sensors. SHT15 and compat." 1484 1494 depends on GPIOLIB || COMPILE_TEST
+1
drivers/hwmon/Makefile
··· 159 159 obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o 160 160 obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o 161 161 obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o 162 + obj-$(CONFIG_SENSORS_SL28CPLD) += sl28cpld-hwmon.o 162 163 obj-$(CONFIG_SENSORS_SHT15) += sht15.o 163 164 obj-$(CONFIG_SENSORS_SHT21) += sht21.o 164 165 obj-$(CONFIG_SENSORS_SHT3x) += sht3x.o
+142
drivers/hwmon/sl28cpld-hwmon.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * sl28cpld hardware monitoring driver 4 + * 5 + * Copyright 2020 Kontron Europe GmbH 6 + */ 7 + 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> 16 + 17 + #define FAN_INPUT 0x00 18 + #define FAN_SCALE_X8 BIT(7) 19 + #define FAN_VALUE_MASK GENMASK(6, 0) 20 + 21 + struct sl28cpld_hwmon { 22 + struct regmap *regmap; 23 + u32 offset; 24 + }; 25 + 26 + static umode_t sl28cpld_hwmon_is_visible(const void *data, 27 + enum hwmon_sensor_types type, 28 + u32 attr, int channel) 29 + { 30 + return 0444; 31 + } 32 + 33 + static int sl28cpld_hwmon_read(struct device *dev, 34 + enum hwmon_sensor_types type, u32 attr, 35 + int channel, long *input) 36 + { 37 + struct sl28cpld_hwmon *hwmon = dev_get_drvdata(dev); 38 + unsigned int value; 39 + int ret; 40 + 41 + switch (attr) { 42 + case hwmon_fan_input: 43 + ret = regmap_read(hwmon->regmap, hwmon->offset + FAN_INPUT, 44 + &value); 45 + if (ret) 46 + return ret; 47 + /* 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. 51 + */ 52 + if (value & FAN_SCALE_X8) 53 + value = FIELD_GET(FAN_VALUE_MASK, value) << 3; 54 + 55 + /* 56 + * The counter period is 1000ms and the sysfs specification 57 + * says we should asssume 2 pulses per revolution. 58 + */ 59 + value *= 60 / 2; 60 + 61 + break; 62 + default: 63 + return -EOPNOTSUPP; 64 + } 65 + 66 + *input = value; 67 + return 0; 68 + } 69 + 70 + static const u32 sl28cpld_hwmon_fan_config[] = { 71 + HWMON_F_INPUT, 72 + 0 73 + }; 74 + 75 + static const struct hwmon_channel_info sl28cpld_hwmon_fan = { 76 + .type = hwmon_fan, 77 + .config = sl28cpld_hwmon_fan_config, 78 + }; 79 + 80 + static const struct hwmon_channel_info *sl28cpld_hwmon_info[] = { 81 + &sl28cpld_hwmon_fan, 82 + NULL 83 + }; 84 + 85 + static const struct hwmon_ops sl28cpld_hwmon_ops = { 86 + .is_visible = sl28cpld_hwmon_is_visible, 87 + .read = sl28cpld_hwmon_read, 88 + }; 89 + 90 + static const struct hwmon_chip_info sl28cpld_hwmon_chip_info = { 91 + .ops = &sl28cpld_hwmon_ops, 92 + .info = sl28cpld_hwmon_info, 93 + }; 94 + 95 + static int sl28cpld_hwmon_probe(struct platform_device *pdev) 96 + { 97 + struct sl28cpld_hwmon *hwmon; 98 + struct device *hwmon_dev; 99 + int ret; 100 + 101 + if (!pdev->dev.parent) 102 + return -ENODEV; 103 + 104 + hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL); 105 + if (!hwmon) 106 + return -ENOMEM; 107 + 108 + hwmon->regmap = dev_get_regmap(pdev->dev.parent, NULL); 109 + if (!hwmon->regmap) 110 + return -ENODEV; 111 + 112 + ret = device_property_read_u32(&pdev->dev, "reg", &hwmon->offset); 113 + if (ret) 114 + return -EINVAL; 115 + 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"); 121 + 122 + return PTR_ERR_OR_ZERO(hwmon_dev); 123 + } 124 + 125 + static const struct of_device_id sl28cpld_hwmon_of_match[] = { 126 + { .compatible = "kontron,sl28cpld-fan" }, 127 + {} 128 + }; 129 + MODULE_DEVICE_TABLE(of, sl28cpld_hwmon_of_match); 130 + 131 + static struct platform_driver sl28cpld_hwmon_driver = { 132 + .probe = sl28cpld_hwmon_probe, 133 + .driver = { 134 + .name = "sl28cpld-fan", 135 + .of_match_table = sl28cpld_hwmon_of_match, 136 + }, 137 + }; 138 + module_platform_driver(sl28cpld_hwmon_driver); 139 + 140 + MODULE_DESCRIPTION("sl28cpld Hardware Monitoring Driver"); 141 + MODULE_AUTHOR("Michael Walle <michael@walle.cc>"); 142 + MODULE_LICENSE("GPL");