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: 914633 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=i2se.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="aFISmle4"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40mFtq2ncwz9s0y for ; Wed, 16 May 2018 23:40:35 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=zNDxqjHVmSnVBrx2W5NPgWtPJk/QFE3HiIq62sNC7UM=; b=aFISmle4Xftc6k UETt/xr5JVj/2x4kxMa8QumJV5tJXBa2UVXSrdbM9C0MnGhIo7Dr61U7PqBJ4BFW6+dOytLcmXkH/ mzaZXPDjFCeb2V19lUYY3MxRSW1d/az+RN9yhOJ/DuH2FOHxcZ3wL36CWZC35G9B3WlcY4OrC1dvb G8KTngKdtl0F2UEsQKR3rjTsrQFES4dsG/kYhO9eU8GkBv4h5WgN74xL6v92TqU5Moq81j+nD+Iig poE0AToLVBHtyh5dxJ6pXHMJ/4IBBDMF2X1LtH0mTfSSh8Xn19j2aVe+4QvzsulqBjkY5jBLzaIaM bPKZHShJbShvfJ1jdTFQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fIwfO-0001RC-Hh; Wed, 16 May 2018 13:40:30 +0000 Received: from mout.kundenserver.de ([212.227.17.24]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fIwdQ-0007wO-4Z; Wed, 16 May 2018 13:38:30 +0000 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 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+ X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180516_063828_572373_D111A8FE X-CRM114-Status: GOOD ( 24.91 ) X-Spam-Score: 0.0 (/) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [212.227.17.24 listed in list.dnswl.org] X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-hwmon@vger.kernel.org, devicetree@vger.kernel.org, Florian Fainelli , Scott Branden , Ray Jui , Stefan Wahren , Phil Elwell , =?utf-8?q?Noralf_Tr=C3=B8nnes?= , bcm-kernel-feedback-list@broadcom.com, linux-rpi-kernel@lists.infradead.org, linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org 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");