lkml.org 
[lkml]   [2020]   [Jun]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v4 07/11] hwmon: add support for the sl28cpld hardware monitoring controller
    Date
    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>
    ---
    Documentation/hwmon/index.rst | 1 +
    Documentation/hwmon/sl28cpld.rst | 36 ++++++++
    drivers/hwmon/Kconfig | 10 +++
    drivers/hwmon/Makefile | 1 +
    drivers/hwmon/sl28cpld-hwmon.c | 150 +++++++++++++++++++++++++++++++
    5 files changed, 198 insertions(+)
    create mode 100644 Documentation/hwmon/sl28cpld.rst
    create mode 100644 drivers/hwmon/sl28cpld-hwmon.c

    diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
    index 55ff4b7c5349..1f4beb7449c7 100644
    --- a/Documentation/hwmon/index.rst
    +++ b/Documentation/hwmon/index.rst
    @@ -153,6 +153,7 @@ Hardware Monitoring Kernel Drivers
    sht3x
    shtc1
    sis5595
    + sl28cpld
    smm665
    smsc47b397
    smsc47m192
    diff --git a/Documentation/hwmon/sl28cpld.rst b/Documentation/hwmon/sl28cpld.rst
    new file mode 100644
    index 000000000000..7ed65f78250c
    --- /dev/null
    +++ b/Documentation/hwmon/sl28cpld.rst
    @@ -0,0 +1,36 @@
    +.. SPDX-License-Identifier: GPL-2.0-only
    +
    +Kernel driver sl28cpld
    +======================
    +
    +Supported chips:
    +
    + * Kontron sl28cpld
    +
    + Prefix: 'sl28cpld'
    +
    + Datasheet: not available
    +
    +Authors: Michael Walle <michael@walle.cc>
    +
    +Description
    +-----------
    +
    +The sl28cpld is a board management controller which also exposes a hardware
    +monitoring controller. At the moment this controller supports a single fan
    +supervisor. In the future there might be other flavours and additional
    +hardware monitoring might be supported.
    +
    +The fan supervisor has a 7 bit counter register and a counter period of 1
    +second. If the 7 bit counter overflows, the supervisor will automatically
    +switch to x8 mode to support a wider input range at the loss of
    +granularity.
    +
    +Sysfs entries
    +-------------
    +
    +The following attributes are supported.
    +
    +======================= ========================================================
    +fan1_input Fan RPM. Assuming 2 pulses per revolution.
    +======================= ========================================================
    diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
    index 288ae9f63588..e1cab08e80ce 100644
    --- a/drivers/hwmon/Kconfig
    +++ b/drivers/hwmon/Kconfig
    @@ -1459,6 +1459,16 @@ config SENSORS_RASPBERRYPI_HWMON
    This driver can also be built as a module. If so, the module
    will be called raspberrypi-hwmon.

    +config SENSORS_SL28CPLD
    + tristate "Kontron sl28cpl hardware monitoring driver"
    + depends on MFD_SL28CPLD
    + help
    + If you say yes here you get support for the fan supervisor of the
    + sl28cpld board management controller.
    +
    + This driver can also be built as a module. If so, the module
    + will be called sl28cpld-hwmon.
    +
    config SENSORS_SHT15
    tristate "Sensiron humidity and temperature sensors. SHT15 and compat."
    depends on GPIOLIB || COMPILE_TEST
    diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
    index 3e32c21f5efe..03822f6bf970 100644
    --- a/drivers/hwmon/Makefile
    +++ b/drivers/hwmon/Makefile
    @@ -158,6 +158,7 @@ obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o
    obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o
    obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o
    obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o
    +obj-$(CONFIG_SENSORS_SL28CPLD) += sl28cpld-hwmon.o
    obj-$(CONFIG_SENSORS_SHT15) += sht15.o
    obj-$(CONFIG_SENSORS_SHT21) += sht21.o
    obj-$(CONFIG_SENSORS_SHT3x) += sht3x.o
    diff --git a/drivers/hwmon/sl28cpld-hwmon.c b/drivers/hwmon/sl28cpld-hwmon.c
    new file mode 100644
    index 000000000000..de24964a7322
    --- /dev/null
    +++ b/drivers/hwmon/sl28cpld-hwmon.c
    @@ -0,0 +1,150 @@
    +// SPDX-License-Identifier: GPL-2.0-only
    +/*
    + * sl28cpld hardware monitoring driver.
    + *
    + * Copyright 2019 Kontron Europe GmbH
    + */
    +
    +#include <linux/bitfield.h>
    +#include <linux/hwmon.h>
    +#include <linux/kernel.h>
    +#include <linux/module.h>
    +#include <linux/of_device.h>
    +#include <linux/platform_device.h>
    +#include <linux/regmap.h>
    +
    +#define FAN_INPUT 0x00
    +#define FAN_SCALE_X8 BIT(7)
    +#define FAN_VALUE_MASK GENMASK(6, 0)
    +
    +struct sl28cpld_hwmon {
    + struct regmap *regmap;
    + u32 offset;
    +};
    +
    +static umode_t sl28cpld_hwmon_is_visible(const void *data,
    + enum hwmon_sensor_types type,
    + u32 attr, int channel)
    +{
    + return 0444;
    +}
    +
    +static int sl28cpld_hwmon_read(struct device *dev,
    + enum hwmon_sensor_types type, u32 attr,
    + int channel, long *input)
    +{
    + struct sl28cpld_hwmon *hwmon = dev_get_drvdata(dev);
    + unsigned int value;
    + int ret;
    +
    + switch (attr) {
    + case hwmon_fan_input:
    + ret = regmap_read(hwmon->regmap, hwmon->offset + FAN_INPUT,
    + &value);
    + if (ret)
    + return ret;
    + /*
    + * The register has a 7 bit value and 1 bit which indicates the
    + * scale. If the MSB is set, then the lower 7 bit has to be
    + * multiplied by 8, to get the correct reading.
    + */
    + if (value & FAN_SCALE_X8)
    + value = FIELD_GET(FAN_VALUE_MASK, value) << 3;
    +
    + /*
    + * The counter period is 1000ms and the sysfs specification
    + * says we should asssume 2 pulses per revolution.
    + */
    + value *= 60 / 2;
    +
    + break;
    + default:
    + return -EOPNOTSUPP;
    + }
    +
    + *input = value;
    + return 0;
    +}
    +
    +static const u32 sl28cpld_hwmon_fan_config[] = {
    + HWMON_F_INPUT,
    + 0
    +};
    +
    +static const struct hwmon_channel_info sl28cpld_hwmon_fan = {
    + .type = hwmon_fan,
    + .config = sl28cpld_hwmon_fan_config,
    +};
    +
    +static const struct hwmon_channel_info *sl28cpld_hwmon_info[] = {
    + &sl28cpld_hwmon_fan,
    + NULL
    +};
    +
    +static const struct hwmon_ops sl28cpld_hwmon_ops = {
    + .is_visible = sl28cpld_hwmon_is_visible,
    + .read = sl28cpld_hwmon_read,
    +};
    +
    +static const struct hwmon_chip_info sl28cpld_hwmon_chip_info = {
    + .ops = &sl28cpld_hwmon_ops,
    + .info = sl28cpld_hwmon_info,
    +};
    +
    +static int sl28cpld_hwmon_probe(struct platform_device *pdev)
    +{
    + struct sl28cpld_hwmon *hwmon;
    + struct device *hwmon_dev;
    + int ret;
    +
    + if (!pdev->dev.parent)
    + return -ENODEV;
    +
    + hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL);
    + if (!hwmon)
    + return -ENOMEM;
    +
    + hwmon->regmap = dev_get_regmap(pdev->dev.parent, NULL);
    + if (!hwmon->regmap)
    + return -ENODEV;
    +
    + ret = device_property_read_u32(&pdev->dev, "reg", &hwmon->offset);
    + if (ret)
    + return -EINVAL;
    +
    + hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
    + "sl28cpld_hwmon", hwmon,
    + &sl28cpld_hwmon_chip_info, NULL);
    + if (IS_ERR(hwmon_dev)) {
    + dev_err(&pdev->dev, "failed to register as hwmon device");
    + return PTR_ERR(hwmon_dev);
    + }
    +
    + return 0;
    +}
    +
    +static const struct of_device_id sl28cpld_hwmon_of_match[] = {
    + { .compatible = "kontron,sl28cpld-fan" },
    + {},
    +};
    +MODULE_DEVICE_TABLE(of, sl28cpld_hwmon_of_match);
    +
    +static const struct platform_device_id sl28cpld_hwmon_id_table[] = {
    + { "sl28cpld-fan" },
    + {}
    +};
    +MODULE_DEVICE_TABLE(platform, sl28cpld_hwmon_id_table);
    +
    +static struct platform_driver sl28cpld_hwmon_driver = {
    + .probe = sl28cpld_hwmon_probe,
    + .id_table = sl28cpld_hwmon_id_table,
    + .driver = {
    + .name = KBUILD_MODNAME,
    + .of_match_table = sl28cpld_hwmon_of_match,
    + },
    +};
    +module_platform_driver(sl28cpld_hwmon_driver);
    +
    +MODULE_DESCRIPTION("sl28cpld Hardware Monitoring Driver");
    +MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
    +MODULE_LICENSE("GPL");
    --
    2.20.1
    \
     
     \ /
      Last update: 2020-06-04 23:12    [W:3.563 / U:1.776 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site