hwmon: Add support for Raspberry Pi voltage sensor
Subsystems (5)
cover hwmon: Add support for Raspberry Pi voltage sensor
A common issue for the Raspberry Pi is an inadequate power supply. Noralf Tr?nnes started a discussion [1] about writting such under-voltage conditions into the kernel log.
This series is a draft to upstream the resulting kernel patch and is not intended for 4.18.
[1] - https://github.com/raspberrypi/linux/issues/2367
Stefan Wahren (6):
ARM: bcm2835: Add GET_THROTTLED firmware property
dt-bindings: hwmon: Add Raspberry Pi voltage sensor
hwmon: Add support for RPi voltage sensor
ARM: bcm2835_defconfig: Enable RPi voltage sensor
ARM: multi_v7_defconfig: Enable RPi voltage sensor
arm64: defconfig: Enable RPi voltage sensor
.../bindings/hwmon/raspberrypi-hwmon.txt | 19 ++ arch/arm/configs/bcm2835_defconfig | 2 +- arch/arm/configs/multi_v7_defconfig | 1 + arch/arm64/configs/defconfig | 1 + drivers/hwmon/Kconfig | 10 + drivers/hwmon/Makefile | 1 + drivers/hwmon/raspberrypi-hwmon.c | 207 +++++++++++++++++++++ include/soc/bcm2835/raspberrypi-firmware.h | 1 + 8 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/hwmon/raspberrypi-hwmon.txt create mode 100644 drivers/hwmon/raspberrypi-hwmon.c
Signature · 1 line
2.7.4
RFC PATCH 1/6 ARM: bcm2835: Add GET_THROTTLED firmware property
Recent Raspberry Pi firmware provides a mailbox property to detect under-voltage conditions. Here is the current definition.
The u32 value returned by the firmware is divided into 2 parts:
- lower 16-bits are the live value
- upper 16-bits are the history or sticky value
Bits:
0: under-voltage
1: arm frequency capped
2: currently throttled
16: under-voltage has occurred
17: arm frequency capped has occurred
18: throttling has occurred
--- include/soc/bcm2835/raspberrypi-firmware.h | 1 + 1 file changed, 1 insertion(+)
include/soc/bcm2835/raspberrypi-firmware.h +1 -0
@@ -75,6 +75,7 @@ enum rpi_firmware_property_tag {RPI_FIRMWARE_GET_EDID_BLOCK =0x00030020 ,RPI_FIRMWARE_GET_CUSTOMER_OTP =0x00030021 ,RPI_FIRMWARE_GET_DOMAIN_STATE =0x00030030 , +RPI_FIRMWARE_GET_THROTTLED =0x00030046 ,RPI_FIRMWARE_SET_CLOCK_STATE =0x00038001 ,RPI_FIRMWARE_SET_CLOCK_RATE =0x00038002 , RPI_FIRMWARE_SET_VOLTAGE = 0x00038003,
Signature · 1 line
2.7.4
RFC PATCH 2/6 dt-bindings: hwmon: Add Raspberry Pi voltage sensor
In reply to Stefan WahrenRecent VC4 firmware provides a hardware-independent way to retrieve the under-voltage sensor on the following Raspberry Pi boards:
- Raspberry Pi B+ (via GPIO on SoC)
- Raspberry Pi A+ (via GPIO on SoC)
- Raspberry Pi 2 B (via GPIO on SoC)
- Raspberry Pi 3 B (via GPIO on port expander)
- Raspberry Pi 3 B+ (via PMIC)
TODO:
- try to make bcm2835 firmware a bus driver
--- .../devicetree/bindings/hwmon/raspberrypi-hwmon.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwmon/raspberrypi-hwmon.txt
Documentation/devicetree/bindings/hwmon/raspberrypi-hwmon.txt new file +19 -0
@@ -0,0 +1,19 @@ +Raspberry Pi voltage sensor +--------------------------- + +The VC4 firmware exposes a mailbox interface that allows the ARM core +to access the board's voltage sensor. + +Required properties : +- compatible : Should be "raspberrypi,bcm2835-hwmon" + +Example: + +firmware: firmware-rpi { + compatible = "raspberrypi,bcm2835-firmware"; + mboxes = <&mailbox>; + + voltage-sensor { + compatible = "raspberrypi,bcm2835-hwmon"; + }; +};
Signature · 1 line
2.7.4
RFC PATCH 2/6 dt-bindings: hwmon: Add Raspberry Pi voltage sensor
Quoted 10 lines · Stefan Wahren
Recent VC4 firmware provides a hardware-independent way to retrieve the under-voltage sensor on the following Raspberry Pi boards:
- Raspberry Pi B+ (via GPIO on SoC)
- Raspberry Pi A+ (via GPIO on SoC)
- Raspberry Pi 2 B (via GPIO on SoC)
- Raspberry Pi 3 B (via GPIO on port expander)
- Raspberry Pi 3 B+ (via PMIC)TODO:
- try to make bcm2835 firmware a bus driver
Do you actually need a DT binding? From the probe routine in patch 2 it looks like this capability can be discovered dynamically by asking the firmware, therefore it might be more straightforward for the firmware driver itself to probe that and create a child device iff the feature is present, which the hwmon driver can then bind to as a pure platform driver.
Robin.
Quoted 32 lines
Signed-off-by Stefan Wahren <[email protected]>--- .../devicetree/bindings/hwmon/raspberrypi-hwmon.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)create mode 100644
Documentation/devicetree/bindings/hwmon/raspberrypi-hwmon.txtDocumentation/devicetree/bindings/hwmon/raspberrypi-hwmon.txt new file +19
-0@@ -0,0 +1,19 @@ +Raspberry Pi voltage sensor +--------------------------- + +The VC4 firmware exposes a mailbox interface that allows the ARM core +to access the board's voltage sensor. + +Required properties : +- compatible : Should be "raspberrypi,bcm2835-hwmon" + +Example: + +firmware: firmware-rpi { + compatible = "raspberrypi,bcm2835-firmware"; + mboxes = <&mailbox>; + + voltage-sensor { + compatible = "raspberrypi,bcm2835-hwmon"; + }; +};
RFC PATCH 2/6 dt-bindings: hwmon: Add Raspberry Pi voltage sensor
Quoted 9 lines · Robin Murphy
Quoted 8 lines · Stefan Wahren
Recent VC4 firmware provides a hardware-independent way to retrieve the under-voltage sensor on the following Raspberry Pi boards:
- Raspberry Pi B+ (via GPIO on SoC)
- Raspberry Pi A+ (via GPIO on SoC)
- Raspberry Pi 2 B (via GPIO on SoC)
- Raspberry Pi 3 B (via GPIO on port expander)
- Raspberry Pi 3 B+ (via PMIC)
Quoted 8 lines
Quoted 2 lines
TODO:
- try to make bcm2835 firmware a bus driverDo you actually need a DT binding? From the probe routine in patch 2 it looks like this capability can be discovered dynamically by asking the firmware, therefore it might be more straightforward for the firmware driver itself to probe that and create a child device iff the feature is present, which the hwmon driver can then bind to as a pure platform driver.
Agreed, let's skip doing this in DT. I just switched the bcm2835-camera
driver over to not need DT, and I think you could do something similar
(and use the pdev->dev.parent to get at the firmware device).
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 832 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180516/14e9e2c9/attachment.sig>
Guenter Roeck
maintainerRFC PATCH 2/6 dt-bindings: hwmon: Add Raspberry Pi voltage sensor
In reply to Stefan WahrenQuoted 23 lines · Stefan Wahren
Recent VC4 firmware provides a hardware-independent way to retrieve the under-voltage sensor on the following Raspberry Pi boards:
- Raspberry Pi B+ (via GPIO on SoC)
- Raspberry Pi A+ (via GPIO on SoC)
- Raspberry Pi 2 B (via GPIO on SoC)
- Raspberry Pi 3 B (via GPIO on port expander)
- Raspberry Pi 3 B+ (via PMIC)TODO:
- try to make bcm2835 firmware a bus driverSigned-off-by Stefan Wahren <[email protected]>--- .../devicetree/bindings/hwmon/raspberrypi-hwmon.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwmon/raspberrypi-hwmon.txtDocumentation/devicetree/bindings/hwmon/raspberrypi-hwmon.txt new file +0
-0
Documentation/devicetree/bindings/hwmon/raspberrypi-hwmon.txt line 8
Quoted 8 lines
Documentation/devicetree/bindings/hwmon/raspberrypi-hwmon.txt new file +8
-0@@ -0,0 +1,19 @@ +Raspberry Pi voltage sensor +--------------------------- + +The VC4 firmware exposes a mailbox interface that allows the ARM core +to access the board's voltage sensor. + +Required properties : +- compatible : Should be "raspberrypi,bcm2835-hwmon"
'hwmon' is very Linux specific. DT bindings are supposed to be OS agnostic.
Guenter
Quoted 18 lines
Documentation/devicetree/bindings/hwmon/raspberrypi-hwmon.txt new file +11
-0+ +Example: + +firmware: firmware-rpi { + compatible = "raspberrypi,bcm2835-firmware"; + mboxes = <&mailbox>; + + voltage-sensor { + compatible = "raspberrypi,bcm2835-hwmon"; + }; +};Signature · 6 lines
2.7.4 -- To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
RFC PATCH 3/6 hwmon: Add support for RPi voltage sensor
In reply to Stefan WahrenCurrently 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.
--- 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
drivers/hwmon/Kconfig +10 -0
@@ -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
drivers/hwmon/Makefile +1 -0
@@ -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
drivers/hwmon/raspberrypi-hwmon.c new file +207 -0
207 lines not on this page · raw message
Signature · 1 line
2.7.4
RFC PATCH 3/6 hwmon: Add support for RPi voltage sensor
Hi Stefan,
Quoted 20 lines · Stefan Wahren
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" <[email protected]>Signed-off-by Stefan Wahren <[email protected]>--- 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.cdrivers/hwmon/Kconfig +0
-0
drivers/hwmon/Kconfig config SENSORS_PWM_FAN · line 1303
Quoted 6 lines
drivers/hwmon/Kconfig +3
-0@@ -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)
Since RASPBERRYPI_FIRMWARE already implies ARCH_BCM2835 (via BCM2835_MBOX), this is just a very roundabout way to say:
depends on RASPBERRYPI_FIRMWARE || COMPILE_TEST
Robin.
Quoted 236 lines
drivers/hwmon/Kconfig +7
-0+ 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_TESTdrivers/hwmon/Makefile +1
-0@@ -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.odrivers/hwmon/raspberrypi-hwmon.c new file +207
-0@@ -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 <[email protected]> +*/ +#include <linux/device.h> +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <soc/bcm2835/raspberrypi-firmware.h> + +#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 <[email protected]>" ); +MODULE_DESCRIPTION ("Raspberry Pi voltage sensor driver" ); +MODULE_LICENSE ("GPL v2" );
Guenter Roeck
maintainerRFC PATCH 3/6 hwmon: Add support for RPi voltage sensor
Quoted 32 lines · Robin Murphy
Hi Stefan,
Quoted 20 lines · Stefan Wahren
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" <[email protected]>Signed-off-by Stefan Wahren <[email protected]>--- 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.cdrivers/hwmon/Kconfig +0
-0drivers/hwmon/Kconfig config SENSORS_PWM_FAN · line 1302
Quoted 5 lines
drivers/hwmon/Kconfig +3
-0@@ -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)Since
RASPBERRYPI_FIRMWAREalready impliesARCH_BCM2835(viaBCM2835_MBOX), this is just a very roundabout way to say:
Quoted 2 lines
depends on RASPBERRYPI_FIRMWARE || COMPILE_TEST
That would permit SENSORS_RASPBERRYPI_HWMON=y combined with RASPBERRYPI_FIRMWARE=m, which AFAICS would result in a build error because include/soc/bcm2835/raspberrypi-firmware.h uses IS_ENABLED() and not IS_REACHABLE().
Guenter
Quoted 242 lines
Robin.
Quoted 226 lines
drivers/hwmon/Kconfig +7
-0+ 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_TESTdrivers/hwmon/Makefile +1
-0@@ -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.odrivers/hwmon/raspberrypi-hwmon.c new file +197
-0@@ -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 <[email protected]> +*/ +#include <linux/device.h> +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <soc/bcm2835/raspberrypi-firmware.h> + +#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,drivers/hwmon/raspberrypi-hwmon.c line 207
Quoted 10 lines
drivers/hwmon/raspberrypi-hwmon.c new file +10
-0+ .driver = { + .name = "raspberrypi-hwmon", + .of_match_table = rpi_hwmon_of_match, + }, +}; +module_platform_driver (rpi_hwmon_driver); + +MODULE_AUTHOR ("Stefan Wahren <[email protected]>" ); +MODULE_DESCRIPTION ("Raspberry Pi voltage sensor driver" ); +MODULE_LICENSE ("GPL v2" );--
To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
RFC PATCH 3/6 hwmon: Add support for RPi voltage sensor
Quoted 33 lines · Guenter Roeck
Quoted 32 lines · Robin Murphy
Hi Stefan,
Quoted 20 lines · Stefan Wahren
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" <[email protected]>Signed-off-by Stefan Wahren <[email protected]>--- 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.cdrivers/hwmon/Kconfig +0
-0drivers/hwmon/Kconfig config SENSORS_PWM_FAN · line 1302
Quoted 5 lines
drivers/hwmon/Kconfig +3
-0@@ -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)Since
RASPBERRYPI_FIRMWAREalready impliesARCH_BCM2835(viaBCM2835_MBOX), this is just a very roundabout way to say:
Quoted 6 lines
Quoted 2 lines
depends on RASPBERRYPI_FIRMWARE || COMPILE_TESTThat would permit SENSORS_RASPBERRYPI_HWMON=y combined with RASPBERRYPI_FIRMWARE=m, which AFAICS would result in a build error because
include/soc/bcm2835/raspberrypi-firmware.husesIS_ENABLED()and notIS_REACHABLE().
But that's only possible when COMPILE_TEST=y, where in any case there are stub definitions for the #else case in that header which should still be enough to build with, right? (and if not, that's probably its own bug)
Nobody's expecting COMPILE_TEST configs to actually boot and work perfectly, are they?
Robin.
Guenter Roeck
maintainerRFC PATCH 3/6 hwmon: Add support for RPi voltage sensor
In reply to Stefan WahrenQuoted 6 lines · Stefan Wahren
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.
My major concern is how this is displayed with the 'sensors' command. Can you test and report ?
Of course, it would be much better if the firmware would also report the actual voltage, but I guess we can't have everything.
More comments inline.
Thanks,
Guenter
Quoted 6 lines
CC "Noralf Tr?nnes" <[email protected]>Signed-off-by Stefan Wahren <[email protected]>--- drivers/hwmon/Kconfig | 10 ++ drivers/hwmon/Makefile | 1 + drivers/hwmon/raspberrypi-hwmon.c | 207 ++++++++++++++++++++++++++++++++++++++
Please also provide Documentation/hwmon/raspberrypi-hwmon.
Quoted 44 lines
3 files changed, 218 insertions(+) create mode 100644 drivers/hwmon/raspberrypi-hwmon.cdrivers/hwmon/Kconfig +10
-0@@ -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_TESTdrivers/hwmon/Makefile +1
-0@@ -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.odrivers/hwmon/raspberrypi-hwmon.c new file +2
-0@@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
drivers/hwmon/raspberrypi-hwmon.c line 12
Quoted 10 lines
drivers/hwmon/raspberrypi-hwmon.c new file +10
-0+* Raspberry Pi voltage sensor driver +* +* Based on firmware/raspberrypi.c by Noralf Tr?nnes +* +* Copyright (C) 2018 Stefan Wahren <[email protected]> +*/ +#include <linux/device.h> +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h>
Unnecessary include
Quoted 12 lines
drivers/hwmon/raspberrypi-hwmon.c new file +12
-0+#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <soc/bcm2835/raspberrypi-firmware.h> + +#define UNDERVOLTAGE_STICKY_BIT BIT(16) + +struct rpi_hwmon_data { +struct device *hwmon_dev; +struct rpi_firmware *fw;
drivers/hwmon/raspberrypi-hwmon.c line 34
Quoted 10 lines
drivers/hwmon/raspberrypi-hwmon.c new file +10
-0+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 */
Please make more explicit that this is a request/command sent to the firmware.
drivers/hwmon/raspberrypi-hwmon.c line 41
Quoted 7 lines
drivers/hwmon/raspberrypi-hwmon.c new file +7
-0+ 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);
The function name seems unnecessary.
Quoted 6 lines
drivers/hwmon/raspberrypi-hwmon.c new file +6
-0+return ; + } + + new_uv = value &UNDERVOLTAGE_STICKY_BIT ; + old_uv = data->last_throttled &UNDERVOLTAGE_STICKY_BIT ; + data->last_throttled = value;
drivers/hwmon/raspberrypi-hwmon.c line 57
Quoted 10 lines
drivers/hwmon/raspberrypi-hwmon.c new file +10
-0+ +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);
What value do those hex values provide to the user ?
Quoted 24 lines
drivers/hwmon/raspberrypi-hwmon.c new file +24
-0+ +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);
drivers/hwmon/raspberrypi-hwmon.c line 91
Quoted 10 lines
drivers/hwmon/raspberrypi-hwmon.c new file +10
-0+ +if (type != hwmon_in) +return -EOPNOTSUPP ; + +if (attr != hwmon_in_lcrit_alarm) +return -EOPNOTSUPP ; + +if (channel) +return -EOPNOTSUPP ; +
There is only one channel, one attribute, and one type supported. As such, the checks are unnecessary.
Quoted 5 lines
drivers/hwmon/raspberrypi-hwmon.c new file +5
-0+ *val = !!(data->last_throttled &UNDERVOLTAGE_STICKY_BIT ); +return 0 ; +} + +static umode_t rpi_is_visible(const void *_data, enum hwmon_sensor_types type,
drivers/hwmon/raspberrypi-hwmon.c line 106
Quoted 10 lines
drivers/hwmon/raspberrypi-hwmon.c new file +10
-0+ u32 attr, int channel) +{ +if (type != hwmon_in) +return 0 ; + +if (attr != hwmon_in_lcrit_alarm) +return 0 ; + +if (channel) +return 0 ;
Same as above. In the list below, there is not a single conditional attribute. Given that, the checks should be unnecessary, and it should be sufficient to just return 0444.
Quoted 46 lines
drivers/hwmon/raspberrypi-hwmon.c new file +46
-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 ; + } +
drivers/hwmon/raspberrypi-hwmon.c line 162
Quoted 10 lines
drivers/hwmon/raspberrypi-hwmon.c new file +10
-0+ 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" );
If this is an error -> dev_err().
drivers/hwmon/raspberrypi-hwmon.c line 163
Quoted 1 line
drivers/hwmon/raspberrypi-hwmon.c new file +1
-0+return -EOPNOTSUPP ;
or return -ENODEV.
Quoted 51 lines
drivers/hwmon/raspberrypi-hwmon.c new file +44
-0+ } + + 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 <[email protected]>" ); +MODULE_DESCRIPTION ("Raspberry Pi voltage sensor driver" ); +MODULE_LICENSE ("GPL v2" );Signature · 6 lines
2.7.4 -- To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
RFC PATCH 3/6 hwmon: Add support for RPi voltage sensor
Hi Guenter,
Quoted 11 lines
Guenter Roeck <[email protected]> hat am 16. Mai 2018 um 20:21 geschrieben:
Quoted 6 lines · Stefan Wahren
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.
Quoted 2 lines
My major concern is how this is displayed with the 'sensors' command. Can you test and report ?
I get the following output:
rpi_volt-isa-0000
Adapter: ISA adapter
in0: N/A
Quoted 3 lines
Of course, it would be much better if the firmware would also report the actual voltage, but I guess we can't have everything.
I think this isn't possible because the hardware only provide a binary value (GPIO).
Quoted 117 lines
More comments inline.
Thanks,
GuenterQuoted 6 lines
CC "Noralf Tr?nnes" <[email protected]>Signed-off-by Stefan Wahren <[email protected]>--- drivers/hwmon/Kconfig | 10 ++ drivers/hwmon/Makefile | 1 + drivers/hwmon/raspberrypi-hwmon.c | 207 ++++++++++++++++++++++++++++++++++++++Please also provide
Documentation/hwmon/raspberrypi-hwmon.Quoted 44 lines
3 files changed, 218 insertions(+) create mode 100644 drivers/hwmon/raspberrypi-hwmon.cdrivers/hwmon/Kconfig +10
-0@@ -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_TESTdrivers/hwmon/Makefile +1
-0@@ -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.odrivers/hwmon/raspberrypi-hwmon.c new file +2
-0@@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* drivers/hwmon/raspberrypi-hwmon.c line 12
Quoted 10 lines
drivers/hwmon/raspberrypi-hwmon.c new file +10
-0+* Raspberry Pi voltage sensor driver +* +* Based on firmware/raspberrypi.c by Noralf Tr?nnes +* +* Copyright (C) 2018 Stefan Wahren <[email protected]> +*/ +#include <linux/device.h> +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> Unnecessary include
Quoted 12 lines
drivers/hwmon/raspberrypi-hwmon.c new file +12
-0+#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <soc/bcm2835/raspberrypi-firmware.h> + +#define UNDERVOLTAGE_STICKY_BIT BIT(16) + +struct rpi_hwmon_data { +struct device *hwmon_dev; +struct rpi_firmware *fw;drivers/hwmon/raspberrypi-hwmon.c line 34
Quoted 10 lines
drivers/hwmon/raspberrypi-hwmon.c new file +10
-0+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 */ Please make more explicit that this is a request/command sent to the firmware.
drivers/hwmon/raspberrypi-hwmon.c line 41
Quoted 7 lines
drivers/hwmon/raspberrypi-hwmon.c new file +7
-0+ 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);The function name seems unnecessary.
Quoted 10 lines
drivers/hwmon/raspberrypi-hwmon.c new file +10
-0+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 ; +
Quoted 8 lines
drivers/hwmon/raspberrypi-hwmon.c line 57
Quoted 6 lines
drivers/hwmon/raspberrypi-hwmon.c new file +6
-0+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);What value do those hex values provide to the user ?
The actual definition of the bits can be found in the commit log of patch #1. But this isn't very helpful for an end user.
Quoted 108 lines
Quoted 25 lines
drivers/hwmon/raspberrypi-hwmon.c new file +24
-0+ +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);drivers/hwmon/raspberrypi-hwmon.c line 91
Quoted 10 lines
drivers/hwmon/raspberrypi-hwmon.c new file +10
-0+ +if (type != hwmon_in) +return -EOPNOTSUPP ; + +if (attr != hwmon_in_lcrit_alarm) +return -EOPNOTSUPP ; + +if (channel) +return -EOPNOTSUPP ; +There is only one channel, one attribute, and one type supported. As such, the checks are unnecessary.
Quoted 5 lines
drivers/hwmon/raspberrypi-hwmon.c new file +5
-0+ *val = !!(data->last_throttled &UNDERVOLTAGE_STICKY_BIT ); +return 0 ; +} + +static umode_t rpi_is_visible(const void *_data, enum hwmon_sensor_types type,drivers/hwmon/raspberrypi-hwmon.c line 106
Quoted 10 lines
drivers/hwmon/raspberrypi-hwmon.c new file +10
-0+ u32 attr, int channel) +{ +if (type != hwmon_in) +return 0 ; + +if (attr != hwmon_in_lcrit_alarm) +return 0 ; + +if (channel) +return 0 ;Same as above. In the list below, there is not a single conditional attribute. Given that, the checks should be unnecessary, and it should be sufficient to just return 0444.
Quoted 50 lines
drivers/hwmon/raspberrypi-hwmon.c new file +50
-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 ;
Quoted 8 lines
drivers/hwmon/raspberrypi-hwmon.c line 162
Quoted 6 lines
drivers/hwmon/raspberrypi-hwmon.c new file +6
-0+ + 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" );If this is an error ->
dev_err().
I wasn't sure. If the firmware is too old, we cannot provide this feature and it's a waste of resources to load this driver. On the other side i don't want to confuse people this is something bad.
Stefan
Quoted 61 lines
drivers/hwmon/raspberrypi-hwmon.c line 163
Quoted 2 lines
drivers/hwmon/raspberrypi-hwmon.c new file +1
-0+return -EOPNOTSUPP ;or return
-ENODEV.Quoted 51 lines
drivers/hwmon/raspberrypi-hwmon.c new file +44
-0+ } + + 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 <[email protected]>" ); +MODULE_DESCRIPTION ("Raspberry Pi voltage sensor driver" ); +MODULE_LICENSE ("GPL v2" );Signature · 6 lines
2.7.4 -- To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Guenter Roeck
maintainerRFC PATCH 3/6 hwmon: Add support for RPi voltage sensor
Quoted 13 lines · Stefan Wahren
Hi Guenter,
Quoted 11 lines
Guenter Roeck <[email protected]> hat am 16. Mai 2018 um 20:21 geschrieben:
Quoted 6 lines · Stefan Wahren
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.
Quoted 8 lines
Quoted 2 lines
My major concern is how this is displayed with the 'sensors' command. Can you test and report ?
I get the following output:
rpi_volt-isa-0000
Adapter: ISA adapter
in0: N/A
Ok, that works.
Quoted 132 lines
Quoted 3 lines
Of course, it would be much better if the firmware would also report the actual voltage, but I guess we can't have everything.
I think this isn't possible because the hardware only provide a binary value (GPIO).
Quoted 117 lines
More comments inline.
Thanks,
GuenterQuoted 6 lines
CC "Noralf Tr?nnes" <[email protected]>Signed-off-by Stefan Wahren <[email protected]>--- drivers/hwmon/Kconfig | 10 ++ drivers/hwmon/Makefile | 1 + drivers/hwmon/raspberrypi-hwmon.c | 207 ++++++++++++++++++++++++++++++++++++++Please also provide
Documentation/hwmon/raspberrypi-hwmon.Quoted 44 lines
3 files changed, 218 insertions(+) create mode 100644 drivers/hwmon/raspberrypi-hwmon.cdrivers/hwmon/Kconfig +10
-0@@ -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_TESTdrivers/hwmon/Makefile +1
-0@@ -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.odrivers/hwmon/raspberrypi-hwmon.c new file +2
-0@@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* drivers/hwmon/raspberrypi-hwmon.c line 12
Quoted 10 lines
drivers/hwmon/raspberrypi-hwmon.c new file +10
-0+* Raspberry Pi voltage sensor driver +* +* Based on firmware/raspberrypi.c by Noralf Tr?nnes +* +* Copyright (C) 2018 Stefan Wahren <[email protected]> +*/ +#include <linux/device.h> +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> Unnecessary include
Quoted 12 lines
drivers/hwmon/raspberrypi-hwmon.c new file +12
-0+#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <soc/bcm2835/raspberrypi-firmware.h> + +#define UNDERVOLTAGE_STICKY_BIT BIT(16) + +struct rpi_hwmon_data { +struct device *hwmon_dev; +struct rpi_firmware *fw;drivers/hwmon/raspberrypi-hwmon.c line 34
Quoted 10 lines
drivers/hwmon/raspberrypi-hwmon.c new file +10
-0+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 */ Please make more explicit that this is a request/command sent to the firmware.
drivers/hwmon/raspberrypi-hwmon.c line 41
Quoted 7 lines
drivers/hwmon/raspberrypi-hwmon.c new file +7
-0+ 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);The function name seems unnecessary.
Quoted 10 lines
drivers/hwmon/raspberrypi-hwmon.c new file +10
-0+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 ; +Quoted 8 lines
drivers/hwmon/raspberrypi-hwmon.c line 57
Quoted 6 lines
drivers/hwmon/raspberrypi-hwmon.c new file +6
-0+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);What value do those hex values provide to the user ?
Quoted 2 lines
The actual definition of the bits can be found in the commit log of patch #1. But this isn't very helpful for an end user.
I would suggest to drop the value from the log.
Quoted 117 lines
Quoted 108 lines
Quoted 25 lines
drivers/hwmon/raspberrypi-hwmon.c new file +24
-0+ +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);drivers/hwmon/raspberrypi-hwmon.c line 91
Quoted 10 lines
drivers/hwmon/raspberrypi-hwmon.c new file +10
-0+ +if (type != hwmon_in) +return -EOPNOTSUPP ; + +if (attr != hwmon_in_lcrit_alarm) +return -EOPNOTSUPP ; + +if (channel) +return -EOPNOTSUPP ; +There is only one channel, one attribute, and one type supported. As such, the checks are unnecessary.
Quoted 5 lines
drivers/hwmon/raspberrypi-hwmon.c new file +5
-0+ *val = !!(data->last_throttled &UNDERVOLTAGE_STICKY_BIT ); +return 0 ; +} + +static umode_t rpi_is_visible(const void *_data, enum hwmon_sensor_types type,drivers/hwmon/raspberrypi-hwmon.c line 106
Quoted 10 lines
drivers/hwmon/raspberrypi-hwmon.c new file +10
-0+ u32 attr, int channel) +{ +if (type != hwmon_in) +return 0 ; + +if (attr != hwmon_in_lcrit_alarm) +return 0 ; + +if (channel) +return 0 ;Same as above. In the list below, there is not a single conditional attribute. Given that, the checks should be unnecessary, and it should be sufficient to just return 0444.
Quoted 50 lines
drivers/hwmon/raspberrypi-hwmon.c new file +50
-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 ;Quoted 8 lines
drivers/hwmon/raspberrypi-hwmon.c line 162
Quoted 6 lines
drivers/hwmon/raspberrypi-hwmon.c new file +6
-0+ + 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" );If this is an error ->
dev_err().
Quoted 2 lines
I wasn't sure. If the firmware is too old, we cannot provide this feature and it's a waste of resources to load this driver. On the other side i don't want to confuse people this is something bad.
Then I would suggest to return -ENODEV.
Guenter
Quoted 63 lines
Stefan
Quoted 61 lines
drivers/hwmon/raspberrypi-hwmon.c line 163
Quoted 2 lines
drivers/hwmon/raspberrypi-hwmon.c new file +1
-0+return -EOPNOTSUPP ;or return
-ENODEV.Quoted 51 lines
drivers/hwmon/raspberrypi-hwmon.c new file +44
-0+ } + + 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 <[email protected]>" ); +MODULE_DESCRIPTION ("Raspberry Pi voltage sensor driver" ); +MODULE_LICENSE ("GPL v2" );Signature · 6 lines
2.7.4 -- To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
RFC PATCH 3/6 hwmon: Add support for RPi voltage sensor
Quoted 17 lines · Guenter Roeck
Quoted 16 lines · Stefan Wahren
Hi Guenter,
Quoted 13 lines
Guenter Roeck <[email protected]> hat am 16. Mai 2018 um 20:21 geschrieben:
Quoted 6 lines · Stefan Wahren
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.
My major concern is how this is displayed with the 'sensors' command. Can you test and report ?
Quoted 6 lines
Quoted 5 lines
I get the following output:
rpi_volt-isa-0000
Adapter: ISA adapter
in0: N/AOk, that works.
Thanks for the quick review on this, Guenter! This driver is going to
help save a lot of people debugging time on rpis in the upstream kernel.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 832 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180517/f9ce6988/attachment.sig>
RFC PATCH 4/6 ARM: bcm2835_defconfig: Enable RPi voltage sensor
In reply to Stefan WahrenThe patch enables the hwmon driver for the Raspberry Pi.
--- arch/arm/configs/bcm2835_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm/configs/bcm2835_defconfig +1 -1
@@ -86,7 +86,7 @@ CONFIG_SPI=y CONFIG_SPI_BCM2835=y CONFIG_SPI_BCM2835AUX=y CONFIG_GPIO_SYSFS=y -# CONFIG_HWMON is not set +CONFIG_SENSORS_RASPBERRYPI_HWMON=m CONFIG_THERMAL=y CONFIG_BCM2835_THERMAL=y CONFIG_WATCHDOG=y
Signature · 1 line
2.7.4
RFC PATCH 5/6 ARM: multi_v7_defconfig: Enable RPi voltage sensor
In reply to Stefan WahrenThe patch enables the hwmon driver for the Raspberry Pi.
--- arch/arm/configs/multi_v7_defconfig | 1 + 1 file changed, 1 insertion(+)
arch/arm/configs/multi_v7_defconfig +1 -0
@@ -477,6 +477,7 @@ CONFIG_SENSORS_LM90=y CONFIG_SENSORS_LM95245=y CONFIG_SENSORS_NTC_THERMISTOR=m CONFIG_SENSORS_PWM_FAN=m +CONFIG_SENSORS_RASPBERRYPI_HWMON=m CONFIG_SENSORS_INA2XX=m CONFIG_CPU_THERMAL=y CONFIG_BCM2835_THERMAL=m
Signature · 1 line
2.7.4
RFC PATCH 6/6 arm64: defconfig: Enable RPi voltage sensor
In reply to Stefan WahrenThe patch enables the hwmon driver for the Raspberry Pi.
--- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+)
arch/arm64/configs/defconfig +1 -0
@@ -352,6 +352,7 @@ CONFIG_BATTERY_BQ27XXX=y CONFIG_SENSORS_ARM_SCPI=y CONFIG_SENSORS_LM90=m CONFIG_SENSORS_INA2XX=m +CONFIG_SENSORS_RASPBERRYPI_HWMON=m CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y CONFIG_CPU_THERMAL=y CONFIG_THERMAL_EMULATION=y
Signature · 1 line
2.7.4