From 5ee5661688c980e7dd27821570a8e994ae4df7e0 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 27 Apr 2022 15:41:55 +0000 Subject: [PATCH] hwmon: Add pwm based generic tachometer Add PWM based generic tachometer which capture the pwm and report the speed. Bug 3621819 Change-Id: I08d7fc808c3a29d6876026ce539e3467887f8112 Signed-off-by: Laxman Dewangan Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2703728 GVS: Gerrit_Virtual_Submit --- drivers/Makefile | 1 + drivers/hwmon/Makefile | 4 ++ drivers/hwmon/generic-pwm-tachometer.c | 97 ++++++++++++++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 drivers/hwmon/Makefile create mode 100644 drivers/hwmon/generic-pwm-tachometer.c diff --git a/drivers/Makefile b/drivers/Makefile index f802cd79..166e3a99 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -3,6 +3,7 @@ LINUXINCLUDE += -I$(srctree.nvidia-oot)/include +obj-m += hwmon/ obj-m += mfd/ obj-m += thermal/ obj-m += watchdog/ diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile new file mode 100644 index 00000000..a361bc47 --- /dev/null +++ b/drivers/hwmon/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. + +obj-m += generic-pwm-tachometer.o diff --git a/drivers/hwmon/generic-pwm-tachometer.c b/drivers/hwmon/generic-pwm-tachometer.c new file mode 100644 index 00000000..b183502e --- /dev/null +++ b/drivers/hwmon/generic-pwm-tachometer.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. + +#include +#include +#include +#include +#include +#include + +struct pwm_hwmon_tach { + struct device *dev; + struct pwm_device *pwm; + struct device *hwmon; +}; + +static ssize_t show_rpm(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pwm_hwmon_tach *ptt = dev_get_drvdata(dev); + struct pwm_device *pwm = ptt->pwm; + struct pwm_capture result; + unsigned int rpm = 0; + int ret; + + ret = pwm_capture(pwm, &result, 0); + if (ret < 0) { + dev_err(ptt->dev, "Failed to capture PWM: %d\n", ret); + return ret; + } + + if (result.period) + rpm = DIV_ROUND_CLOSEST_ULL(60ULL * NSEC_PER_SEC, + result.period); + + return sprintf(buf, "%u\n", rpm); +} +static SENSOR_DEVICE_ATTR(rpm, 0444, show_rpm, NULL, 0); + +static struct attribute *pwm_tach_attrs[] = { + &sensor_dev_attr_rpm.dev_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(pwm_tach); + +static int pwm_tach_probe(struct platform_device *pdev) +{ + struct pwm_hwmon_tach *ptt; + + ptt = devm_kzalloc(&pdev->dev, sizeof(*ptt), GFP_KERNEL); + if (!ptt) + return -ENOMEM; + + ptt->dev = &pdev->dev; + + platform_set_drvdata(pdev, ptt); + dev_set_drvdata(&pdev->dev, ptt); + + ptt->pwm = devm_of_pwm_get(&pdev->dev, pdev->dev.of_node, NULL); + if (IS_ERR(ptt->pwm)) { + if (PTR_ERR(ptt->pwm) != -EPROBE_DEFER) { + dev_err(&pdev->dev, "Failed to get pwm: %ld\n", + PTR_ERR(ptt->pwm)); + } + return PTR_ERR(ptt->pwm); + } + + ptt->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, + "pwm_tach", ptt, pwm_tach_groups); + if (IS_ERR(ptt->hwmon)) { + dev_err(&pdev->dev, "Failed to register hwmon device: %d\n", + PTR_ERR_OR_ZERO(ptt->hwmon)); + return PTR_ERR_OR_ZERO(ptt->hwmon); + } + + return 0; +} + +static const struct of_device_id pwm_tach_of_match[] = { + { .compatible = "generic-pwm-tachometer" }, + {} +}; +MODULE_DEVICE_TABLE(of, pwm_tach_of_match); + +static struct platform_driver pwm_tach_driver = { + .driver = { + .name = "generic-pwm-tachometer", + .of_match_table = pwm_tach_of_match, + }, + .probe = pwm_tach_probe, +}; + +module_platform_driver(pwm_tach_driver); + +MODULE_DESCRIPTION("PWM based Generic Tachometer driver"); +MODULE_AUTHOR("Laxman Dewangan "); +MODULE_AUTHOR("R Raj Kumar "); +MODULE_LICENSE("GPL v2");