From patchwork Wed May 16 13:37:04 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stefan Wahren X-Patchwork-Id: 10403959 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 3C27360155 for ; Wed, 16 May 2018 13:38:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 279C3288DB for ; Wed, 16 May 2018 13:38:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1BD5128919; Wed, 16 May 2018 13:38:37 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 551EC288F9 for ; Wed, 16 May 2018 13:38:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752100AbeEPNig (ORCPT ); Wed, 16 May 2018 09:38:36 -0400 Received: from mout.kundenserver.de ([212.227.17.24]:48707 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751389AbeEPNif (ORCPT ); Wed, 16 May 2018 09:38:35 -0400 Received: from localhost.localdomain ([37.4.249.136]) by mrelayeu.kundenserver.de (mreue105 [212.227.15.183]) with ESMTPSA (Nemesis) id 0Lb2eP-1eZ8TU17u5-00kcf0; Wed, 16 May 2018 15:37:41 +0200 From: Stefan Wahren To: Rob Herring , Mark Rutland , Jean Delvare , Guenter Roeck , Eric Anholt Cc: Florian Fainelli , Ray Jui , Scott Branden , Phil Elwell , bcm-kernel-feedback-list@broadcom.com, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-rpi-kernel@lists.infradead.org, linux-hwmon@vger.kernel.org, Stefan Wahren , =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Subject: [PATCH RFC 3/6] hwmon: Add support for RPi voltage sensor Date: Wed, 16 May 2018 15:37:04 +0200 Message-Id: <1526477827-10859-4-git-send-email-stefan.wahren@i2se.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1526477827-10859-1-git-send-email-stefan.wahren@i2se.com> References: <1526477827-10859-1-git-send-email-stefan.wahren@i2se.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:HHtdHzy6QSAQlj1j/ykrLcVuGnkmpMxM81RCbp0rtXbOOsbSB+x hR/GariYjzoHGvnKv/ivggsPGFm/+88O87aXfhxEzr2FHwkU+Fs/oo2Wd1hgZL2Qzid2PJT dPW8xKOKHTec378cv1+E0WT8bEmg1I6BUI8Ng9tybY2ocKrS8K5PFoBl8lLzIwuQdcfQm+j 9+hUDO6o8XEFrSIhXhfVQ== X-UI-Out-Filterresults: notjunk:1; V01:K0:X/MYxNZsU74=:OBJ61dyOUckcXA4Jle2VdU LzmYi8+0VmDLQW6cLpPT3SCUTbY/wTUW8apAAZyxNu71CcE97/LxhtgzOXSzfEcd30oy9SkId 0CSdnQuBPf4Fa67cvz9kk0lMDKDiDngFnBbpUvTdo47C8HscMdM2odghFRcGasVUXP9X2PiM2 RW0nsG7eKyHFt42ISFxt7KSxLFsdTw+5GoN8eJd6WkSK6qDKQxIeeBwiukD0YQDkqurgonF4P ZPvSo7AuPZ27OygNy20MMpMzw7QiFgukj2v6ws8xMOjV91bwApogcaKKj7f1FuDvynrk5a1u6 IzOTRg4o6K8X9ltwA4LihEVVTx49Htd/nI3jX6ls5rey6V0ke+ico5Js3g4IY6p/4/3GwDSxZ rd1zW5Mh0G6qlpQxbBvgK5aDz0cZduuTDIGemPzEhizTQFenAZQZLAHbgVDJDdJjHQx8PRtld FrwdkCLKF1hkJkK4CxV1iU7i3fRRAFyhXbtJPK3i0YDmiH2Daebu1UCw2KYNq+SMnTwPyZG0W p6HCmxEIxONTTuMj+ClZlFNQ7XVpfkBdgSQ9EuUQ/PmUdvVWH1Zv+UuAAiFWNOWTYyAB0+Epz ni7wydIxf34Hvld9aBGdcX2LA1UKEp0fVNsLaB3s9oBTML8x8/cl4avFC0w6G8laIWL3lV4TE 1/P+Qrj8yjlrHx5H5r1iSwZbXHEGUKYaNCT/oX0aVNNB+z1FPwanzDwJIq+jINWGhINFw1vqA O9G/GZdVpxfRVOSYmYN7cWND2EqaIBDK2Ds0dBUWKmnGxp7ibaE3UJK9gFmzGgmJi/BQyUBrx gGWFn6+ Sender: linux-hwmon-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-hwmon@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Currently there is no easy way to detect under-voltage conditions on a remote Raspberry Pi. This hwmon driver retrieves the state of the under-voltage sensor via mailbox interface. The handling based on Noralf's modifications to the downstream firmware driver. In case of an under-voltage condition only an entry is written to the kernel log. CC: "Noralf Trønnes" Signed-off-by: Stefan Wahren --- drivers/hwmon/Kconfig | 10 ++ drivers/hwmon/Makefile | 1 + drivers/hwmon/raspberrypi-hwmon.c | 207 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 218 insertions(+) create mode 100644 drivers/hwmon/raspberrypi-hwmon.c diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 768aed5..7f935cf 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1298,6 +1298,16 @@ config SENSORS_PWM_FAN This driver can also be built as a module. If so, the module will be called pwm-fan. +config SENSORS_RASPBERRYPI_HWMON + tristate "Raspberry Pi voltage monitor" + depends on (ARCH_BCM2835 && RASPBERRYPI_FIRMWARE) || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE) + help + If you say yes here you get support for voltage sensor on the + Raspberry Pi. + + This driver can also be built as a module. If so, the module + will be called raspberrypi-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 e7d52a3..a929770 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -141,6 +141,7 @@ obj-$(CONFIG_SENSORS_PC87427) += pc87427.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o +obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o diff --git a/drivers/hwmon/raspberrypi-hwmon.c b/drivers/hwmon/raspberrypi-hwmon.c new file mode 100644 index 0000000..2003f6c --- /dev/null +++ b/drivers/hwmon/raspberrypi-hwmon.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Raspberry Pi voltage sensor driver + * + * Based on firmware/raspberrypi.c by Noralf Trønnes + * + * Copyright (C) 2018 Stefan Wahren + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define UNDERVOLTAGE_STICKY_BIT BIT(16) + +struct rpi_hwmon_data { + struct device *hwmon_dev; + struct rpi_firmware *fw; + u32 last_throttled; + struct delayed_work get_values_poll_work; +}; + +static void rpi_firmware_get_throttled(struct rpi_hwmon_data *data) +{ + u32 new_uv, old_uv, value; + int ret; + + /* Clear sticky bits */ + value = 0xffff; + + ret = rpi_firmware_property(data->fw, RPI_FIRMWARE_GET_THROTTLED, + &value, sizeof(value)); + if (ret) { + dev_err_once(data->hwmon_dev, "%s: Failed to get throttled (%d)\n", + __func__, ret); + return; + } + + new_uv = value & UNDERVOLTAGE_STICKY_BIT; + old_uv = data->last_throttled & UNDERVOLTAGE_STICKY_BIT; + data->last_throttled = value; + + if (new_uv == old_uv) + return; + + if (new_uv) + dev_crit(data->hwmon_dev, "Under-voltage detected! (0x%08x)\n", + value); + else + dev_info(data->hwmon_dev, "Voltage normalised (0x%08x)\n", + value); + + sysfs_notify(&data->hwmon_dev->kobj, NULL, "in0_lcrit_alarm"); +} + +static void get_values_poll(struct work_struct *work) +{ + struct rpi_hwmon_data *data; + + data = container_of(work, struct rpi_hwmon_data, + get_values_poll_work.work); + + rpi_firmware_get_throttled(data); + + /* + * We can't run faster than the sticky shift (100ms) since we get + * flipping in the sticky bits that are cleared. + */ + schedule_delayed_work(&data->get_values_poll_work, 2 * HZ); +} + +static int rpi_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct rpi_hwmon_data *data = dev_get_drvdata(dev); + + if (type != hwmon_in) + return -EOPNOTSUPP; + + if (attr != hwmon_in_lcrit_alarm) + return -EOPNOTSUPP; + + if (channel) + return -EOPNOTSUPP; + + *val = !!(data->last_throttled & UNDERVOLTAGE_STICKY_BIT); + return 0; +} + +static umode_t rpi_is_visible(const void *_data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + if (type != hwmon_in) + return 0; + + if (attr != hwmon_in_lcrit_alarm) + return 0; + + if (channel) + return 0; + + return 0444; +} + +static const u32 rpi_in_config[] = { + HWMON_I_LCRIT_ALARM, + 0 +}; + +static const struct hwmon_channel_info rpi_in = { + .type = hwmon_in, + .config = rpi_in_config, +}; + +static const struct hwmon_channel_info *rpi_info[] = { + &rpi_in, + NULL +}; + +static const struct hwmon_ops rpi_hwmon_ops = { + .is_visible = rpi_is_visible, + .read = rpi_read, +}; + +static const struct hwmon_chip_info rpi_chip_info = { + .ops = &rpi_hwmon_ops, + .info = rpi_info, +}; + +static int rpi_hwmon_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *fw_node; + struct rpi_hwmon_data *data; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + fw_node = of_get_parent(dev->of_node); + if (!fw_node) { + dev_err(dev, "Missing firmware node\n"); + return -ENOENT; + } + + data->fw = rpi_firmware_get(fw_node); + of_node_put(fw_node); + if (!data->fw) + return -EPROBE_DEFER; + + ret = rpi_firmware_property(data->fw, RPI_FIRMWARE_GET_THROTTLED, + &data->last_throttled, + sizeof(data->last_throttled)); + if (ret) { + dev_info(dev, "Firmware doesn't support GET_THROTTLED\n"); + return -EOPNOTSUPP; + } + + data->hwmon_dev = devm_hwmon_device_register_with_info(dev, "rpi_volt", + data, + &rpi_chip_info, + NULL); + + INIT_DELAYED_WORK(&data->get_values_poll_work, get_values_poll); + platform_set_drvdata(pdev, data); + + if (!PTR_ERR_OR_ZERO(data->hwmon_dev)) + schedule_delayed_work(&data->get_values_poll_work, 2 * HZ); + + return PTR_ERR_OR_ZERO(data->hwmon_dev); +} + +static int rpi_hwmon_remove(struct platform_device *pdev) +{ + struct rpi_hwmon_data *data = platform_get_drvdata(pdev); + + cancel_delayed_work_sync(&data->get_values_poll_work); + + return 0; +} + +static const struct of_device_id rpi_hwmon_of_match[] = { + { .compatible = "raspberrypi,bcm2835-hwmon", }, + { /* sentinel */}, +}; +MODULE_DEVICE_TABLE(of, rpi_hwmon_of_match); + +static struct platform_driver rpi_hwmon_driver = { + .probe = rpi_hwmon_probe, + .remove = rpi_hwmon_remove, + .driver = { + .name = "raspberrypi-hwmon", + .of_match_table = rpi_hwmon_of_match, + }, +}; +module_platform_driver(rpi_hwmon_driver); + +MODULE_AUTHOR("Stefan Wahren "); +MODULE_DESCRIPTION("Raspberry Pi voltage sensor driver"); +MODULE_LICENSE("GPL v2");