Compare commits

...

4 Commits

Author SHA1 Message Date
Serge Schneider
081f560bde overlays: Add rpi-poe-plus overlay
Signed-off-by: Serge Schneider <serge@raspberrypi.com>
2021-05-27 13:04:36 +01:00
Serge Schneider
87956affb2 configs: Enable Raspberry Pi PoE+ HAT support
Signed-off-by: Serge Schneider <serge@raspberrypi.com>
2021-05-27 13:04:36 +01:00
Serge Schneider
1d9b677e62 Add Raspberry Pi PoE+ HAT support
Signed-off-by: Serge Schneider <serge@raspberrypi.com>
2021-05-27 13:04:36 +01:00
Phil Elwell
3a33f11c48 ARM: dts: bcm2711-rpi-400: Limit MDIO clock speed
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
2021-04-29 20:34:42 +01:00
14 changed files with 311 additions and 11 deletions

View File

@@ -595,6 +595,10 @@
brcm,disable-headphones = <1>; brcm,disable-headphones = <1>;
}; };
&genet_mdio {
clock-frequency = <1950000>;
};
/ { / {
__overrides__ { __overrides__ {
act_led_gpio = <&act_led>,"gpios:4"; act_led_gpio = <&act_led>,"gpios:4";

View File

@@ -153,6 +153,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
rpi-display.dtbo \ rpi-display.dtbo \
rpi-ft5406.dtbo \ rpi-ft5406.dtbo \
rpi-poe.dtbo \ rpi-poe.dtbo \
rpi-poe-plus.dtbo \
rpi-proto.dtbo \ rpi-proto.dtbo \
rpi-sense.dtbo \ rpi-sense.dtbo \
rpi-tv.dtbo \ rpi-tv.dtbo \

View File

@@ -2412,6 +2412,27 @@ Params: poe_fan_temp0 Temperature (in millicelcius) at which the fan
the fan slows down (default 5000) the fan slows down (default 5000)
Name: rpi-poe-plus
Info: Raspberry Pi PoE+ HAT fan
Load: dtoverlay=rpi-poe-plus,<param>[=<val>]
Params: poe_fan_temp0 Temperature (in millicelcius) at which the fan
turns on (default 40000)
poe_fan_temp0_hyst Temperature delta (in millicelcius) at which
the fan turns off (default 2000)
poe_fan_temp1 Temperature (in millicelcius) at which the fan
speeds up (default 45000)
poe_fan_temp1_hyst Temperature delta (in millicelcius) at which
the fan slows down (default 2000)
poe_fan_temp2 Temperature (in millicelcius) at which the fan
speeds up (default 50000)
poe_fan_temp2_hyst Temperature delta (in millicelcius) at which
the fan slows down (default 2000)
poe_fan_temp3 Temperature (in millicelcius) at which the fan
speeds up (default 55000)
poe_fan_temp3_hyst Temperature delta (in millicelcius) at which
the fan slows down (default 5000)
Name: rpi-proto Name: rpi-proto
Info: Configures the RPi Proto audio card Info: Configures the RPi Proto audio card
Load: dtoverlay=rpi-proto Load: dtoverlay=rpi-proto

View File

@@ -0,0 +1,19 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
// Overlay for the Raspberry Pi PoE+ HAT.
#include "rpi-poe-overlay.dts"
/ {
compatible = "brcm,bcm2835";
fragment@3 {
target-path = "/";
__overlay__ {
rpi_poe_power_supply: rpi-poe-power-supply@0 {
compatible = "raspberrypi,rpi-poe-power-supply";
firmware = <&firmware>;
status = "okay";
};
};
};
};

View File

@@ -713,6 +713,7 @@ CONFIG_W1_SLAVE_DS28E04=m
CONFIG_W1_SLAVE_DS28E17=m CONFIG_W1_SLAVE_DS28E17=m
CONFIG_POWER_RESET=y CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_GPIO=y CONFIG_POWER_RESET_GPIO=y
CONFIG_RPI_POE_POWER=m
CONFIG_BATTERY_DS2760=m CONFIG_BATTERY_DS2760=m
CONFIG_BATTERY_MAX17040=m CONFIG_BATTERY_MAX17040=m
CONFIG_BATTERY_GAUGE_LTC2941=m CONFIG_BATTERY_GAUGE_LTC2941=m

View File

@@ -723,6 +723,7 @@ CONFIG_W1_SLAVE_DS28E04=m
CONFIG_W1_SLAVE_DS28E17=m CONFIG_W1_SLAVE_DS28E17=m
CONFIG_POWER_RESET=y CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_GPIO=y CONFIG_POWER_RESET_GPIO=y
CONFIG_RPI_POE_POWER=m
CONFIG_BATTERY_DS2760=m CONFIG_BATTERY_DS2760=m
CONFIG_BATTERY_MAX17040=m CONFIG_BATTERY_MAX17040=m
CONFIG_BATTERY_GAUGE_LTC2941=m CONFIG_BATTERY_GAUGE_LTC2941=m

View File

@@ -706,6 +706,7 @@ CONFIG_W1_SLAVE_DS28E04=m
CONFIG_W1_SLAVE_DS28E17=m CONFIG_W1_SLAVE_DS28E17=m
CONFIG_POWER_RESET=y CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_GPIO=y CONFIG_POWER_RESET_GPIO=y
CONFIG_RPI_POE_POWER=m
CONFIG_BATTERY_DS2760=m CONFIG_BATTERY_DS2760=m
CONFIG_BATTERY_MAX17040=m CONFIG_BATTERY_MAX17040=m
CONFIG_BATTERY_GAUGE_LTC2941=m CONFIG_BATTERY_GAUGE_LTC2941=m

View File

@@ -716,6 +716,7 @@ CONFIG_W1_SLAVE_DS2781=m
CONFIG_W1_SLAVE_DS28E04=m CONFIG_W1_SLAVE_DS28E04=m
CONFIG_W1_SLAVE_DS28E17=m CONFIG_W1_SLAVE_DS28E17=m
CONFIG_POWER_RESET_GPIO=y CONFIG_POWER_RESET_GPIO=y
CONFIG_RPI_POE_POWER=m
CONFIG_BATTERY_DS2760=m CONFIG_BATTERY_DS2760=m
CONFIG_BATTERY_MAX17040=m CONFIG_BATTERY_MAX17040=m
CONFIG_BATTERY_GAUGE_LTC2941=m CONFIG_BATTERY_GAUGE_LTC2941=m

View File

@@ -690,6 +690,7 @@ CONFIG_W1_SLAVE_DS2781=m
CONFIG_W1_SLAVE_DS28E04=m CONFIG_W1_SLAVE_DS28E04=m
CONFIG_W1_SLAVE_DS28E17=m CONFIG_W1_SLAVE_DS28E17=m
CONFIG_POWER_RESET_GPIO=y CONFIG_POWER_RESET_GPIO=y
CONFIG_RPI_POE_POWER=m
CONFIG_BATTERY_DS2760=m CONFIG_BATTERY_DS2760=m
CONFIG_BATTERY_MAX17040=m CONFIG_BATTERY_MAX17040=m
CONFIG_SENSORS_IIO_HWMON=m CONFIG_SENSORS_IIO_HWMON=m

View File

@@ -28,6 +28,7 @@
struct rpi_poe_fan_ctx { struct rpi_poe_fan_ctx {
struct mutex lock; struct mutex lock;
struct rpi_firmware *fw; struct rpi_firmware *fw;
u32 set_tag;
unsigned int pwm_value; unsigned int pwm_value;
unsigned int def_pwm_value; unsigned int def_pwm_value;
unsigned int rpi_poe_fan_state; unsigned int rpi_poe_fan_state;
@@ -43,13 +44,15 @@ struct fw_tag_data_s{
u32 ret; u32 ret;
}; };
static int write_reg(struct rpi_firmware *fw, u32 reg, u32 *val){ static int write_reg(struct rpi_firmware *fw, u32 reg, u32 *val, u32 set_tag)
{
struct fw_tag_data_s fw_tag_data = { struct fw_tag_data_s fw_tag_data = {
.reg = reg, .reg = reg,
.val = *val .val = *val
}; };
int ret; int ret;
ret = rpi_firmware_property(fw, RPI_FIRMWARE_SET_POE_HAT_VAL,
ret = rpi_firmware_property(fw, set_tag,
&fw_tag_data, sizeof(fw_tag_data)); &fw_tag_data, sizeof(fw_tag_data));
if (ret) { if (ret) {
return ret; return ret;
@@ -82,7 +85,7 @@ static int rpi_poe_reboot(struct notifier_block *nb, unsigned long code,
nb); nb);
if (ctx->pwm_value != ctx->def_pwm_value) if (ctx->pwm_value != ctx->def_pwm_value)
write_reg(ctx->fw, POE_CUR_PWM, &ctx->def_pwm_value); write_reg(ctx->fw, POE_CUR_PWM, &ctx->def_pwm_value, ctx->set_tag);
return NOTIFY_DONE; return NOTIFY_DONE;
} }
@@ -95,7 +98,7 @@ static int __set_pwm(struct rpi_poe_fan_ctx *ctx, u32 pwm)
if (ctx->pwm_value == pwm) if (ctx->pwm_value == pwm)
goto exit_set_pwm_err; goto exit_set_pwm_err;
ret = write_reg(ctx->fw, POE_CUR_PWM, &pwm); ret = write_reg(ctx->fw, POE_CUR_PWM, &pwm, ctx->set_tag);
if (!ret) if (!ret)
ctx->pwm_value = pwm; ctx->pwm_value = pwm;
exit_set_pwm_err: exit_set_pwm_err:
@@ -110,7 +113,7 @@ static int __set_def_pwm(struct rpi_poe_fan_ctx *ctx, u32 def_pwm)
if (ctx->def_pwm_value == def_pwm) if (ctx->def_pwm_value == def_pwm)
goto exit_set_def_pwm_err; goto exit_set_def_pwm_err;
ret = write_reg(ctx->fw, POE_DEF_PWM, &def_pwm); ret = write_reg(ctx->fw, POE_DEF_PWM, &def_pwm, ctx->set_tag);
if (!ret) if (!ret)
ctx->def_pwm_value = def_pwm; ctx->def_pwm_value = def_pwm;
exit_set_def_pwm_err: exit_set_def_pwm_err:
@@ -297,6 +300,7 @@ static int rpi_poe_fan_probe(struct platform_device *pdev)
struct device *hwmon; struct device *hwmon;
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct device_node *fw_node; struct device_node *fw_node;
u32 revision;
int ret; int ret;
fw_node = of_parse_phandle(np, "firmware", 0); fw_node = of_parse_phandle(np, "firmware", 0);
@@ -314,6 +318,17 @@ static int rpi_poe_fan_probe(struct platform_device *pdev)
ctx->fw = rpi_firmware_get(fw_node); ctx->fw = rpi_firmware_get(fw_node);
if (!ctx->fw) if (!ctx->fw)
return -EPROBE_DEFER; return -EPROBE_DEFER;
ret = rpi_firmware_property(ctx->fw,
RPI_FIRMWARE_GET_FIRMWARE_REVISION,
&revision, sizeof(revision));
if (ret) {
dev_err(&pdev->dev, "Failed to get firmware revision: %i\n", ret);
return ret;
}
if (revision < 0x60af72e8)
ctx->set_tag = RPI_FIRMWARE_SET_POE_HAT_VAL_OLD;
else
ctx->set_tag = RPI_FIRMWARE_SET_POE_HAT_VAL;
platform_set_drvdata(pdev, ctx); platform_set_drvdata(pdev, ctx);
@@ -378,9 +393,9 @@ static int rpi_poe_fan_remove(struct platform_device *pdev)
unregister_reboot_notifier(&ctx->nb); unregister_reboot_notifier(&ctx->nb);
thermal_cooling_device_unregister(ctx->cdev); thermal_cooling_device_unregister(ctx->cdev);
if (ctx->pwm_value != value) { if (ctx->pwm_value != value)
write_reg(ctx->fw, POE_CUR_PWM, &value); write_reg(ctx->fw, POE_CUR_PWM, &value, ctx->set_tag);
}
return 0; return 0;
} }
@@ -392,7 +407,7 @@ static int rpi_poe_fan_suspend(struct device *dev)
int ret = 0; int ret = 0;
if (ctx->pwm_value != value) if (ctx->pwm_value != value)
ret = write_reg(ctx->fw, POE_CUR_PWM, &value); ret = write_reg(ctx->fw, POE_CUR_PWM, &value, ctx->set_tag);
return ret; return ret;
} }
@@ -403,7 +418,7 @@ static int rpi_poe_fan_resume(struct device *dev)
int ret = 0; int ret = 0;
if (value != 0) if (value != 0)
ret = write_reg(ctx->fw, POE_CUR_PWM, &value); ret = write_reg(ctx->fw, POE_CUR_PWM, &value, ctx->set_tag);
return ret; return ret;
} }

View File

@@ -28,6 +28,12 @@ config POWER_SUPPLY_HWMON
Say 'Y' here if you want power supplies to Say 'Y' here if you want power supplies to
have hwmon sysfs interface too. have hwmon sysfs interface too.
config RPI_POE_POWER
tristate "Raspberry Pi PoE+ HAT power supply driver"
depends on RASPBERRYPI_FIRMWARE
help
Say Y here to enable support for Raspberry Pi PoE+ (Power over Ethernet
Plus) HAT current measurement.
config PDA_POWER config PDA_POWER
tristate "Generic PDA/phone power driver" tristate "Generic PDA/phone power driver"

View File

@@ -9,6 +9,7 @@ obj-$(CONFIG_POWER_SUPPLY) += power_supply.o
obj-$(CONFIG_POWER_SUPPLY_HWMON) += power_supply_hwmon.o obj-$(CONFIG_POWER_SUPPLY_HWMON) += power_supply_hwmon.o
obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o
obj-$(CONFIG_RPI_POE_POWER) += rpi_poe_power.o
obj-$(CONFIG_PDA_POWER) += pda_power.o obj-$(CONFIG_PDA_POWER) += pda_power.o
obj-$(CONFIG_APM_POWER) += apm_power.o obj-$(CONFIG_APM_POWER) += apm_power.o
obj-$(CONFIG_AXP20X_POWER) += axp20x_usb_power.o obj-$(CONFIG_AXP20X_POWER) += axp20x_usb_power.o

View File

@@ -0,0 +1,227 @@
// SPDX-License-Identifier: GPL-2.0
/*
* rpi-poe-power.c - Raspberry Pi PoE+ HAT power supply driver.
*
* Copyright (C) 2019 Raspberry Pi (Trading) Ltd.
* Based on axp20x_ac_power.c by Quentin Schulz <quentin.schulz@free-electrons.com>
*
* Author: Serge Schneider <serge@raspberrypi.org>
*/
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <soc/bcm2835/raspberrypi-firmware.h>
#define RPI_POE_ADC_REG 0x2
#define RPI_POE_FLAG_REG 0x4
#define RPI_POE_FLAG_AT BIT(0)
#define RPI_POE_FLAG_OC BIT(1)
#define RPI_POE_CURRENT_AF_MAX (2500 * 1000)
#define RPI_POE_CURRENT_AT_MAX (5000 * 1000)
#define DRVNAME "rpi-poe-power-supply"
struct rpi_poe_power_supply_ctx {
struct power_supply *supply;
struct rpi_firmware *fw;
};
struct fw_tag_data_s {
u32 reg;
u32 val;
u32 ret;
};
static int write_reg(struct rpi_firmware *fw, u32 reg, u32 *val)
{
struct fw_tag_data_s fw_tag_data = {
.reg = reg,
.val = *val
};
int ret;
ret = rpi_firmware_property(fw, RPI_FIRMWARE_SET_POE_HAT_VAL,
&fw_tag_data, sizeof(fw_tag_data));
if (ret)
return ret;
else if (fw_tag_data.ret)
return -EIO;
return 0;
}
static int read_reg(struct rpi_firmware *fw, u32 reg, u32 *val)
{
struct fw_tag_data_s fw_tag_data = {
.reg = reg,
.val = *val
};
int ret;
ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_POE_HAT_VAL,
&fw_tag_data, sizeof(fw_tag_data));
if (ret)
return ret;
else if (fw_tag_data.ret)
return -EIO;
*val = fw_tag_data.val;
return 0;
}
static int rpi_poe_power_supply_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *r_val)
{
struct rpi_poe_power_supply_ctx *ctx = power_supply_get_drvdata(psy);
int ret;
unsigned int val = 0;
switch (psp) {
case POWER_SUPPLY_PROP_HEALTH:
ret = read_reg(ctx->fw, RPI_POE_FLAG_REG, &val);
if (ret)
return ret;
if (val & RPI_POE_FLAG_OC) {
r_val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
val = RPI_POE_FLAG_OC;
ret = write_reg(ctx->fw, RPI_POE_FLAG_REG, &val);
if (ret)
return ret;
return 0;
}
r_val->intval = POWER_SUPPLY_HEALTH_GOOD;
return 0;
case POWER_SUPPLY_PROP_ONLINE:
ret = read_reg(ctx->fw, RPI_POE_ADC_REG, &val);
if (ret)
return ret;
r_val->intval = (val > 5);
return 0;
case POWER_SUPPLY_PROP_CURRENT_AVG:
val = 50;
ret = read_reg(ctx->fw, RPI_POE_ADC_REG, &val);
if (ret)
return ret;
val = (val * 3300)/9821;
r_val->intval = val * 1000;
return 0;
case POWER_SUPPLY_PROP_CURRENT_NOW:
ret = read_reg(ctx->fw, RPI_POE_ADC_REG, &val);
if (ret)
return ret;
val = (val * 3300)/9821;
r_val->intval = val * 1000;
return 0;
case POWER_SUPPLY_PROP_CURRENT_MAX:
ret = read_reg(ctx->fw, RPI_POE_FLAG_REG, &val);
if (ret)
return ret;
if (val & RPI_POE_FLAG_AT) {
r_val->intval = RPI_POE_CURRENT_AT_MAX;
return 0;
}
r_val->intval = RPI_POE_CURRENT_AF_MAX;
return 0;
default:
return -EINVAL;
}
return -EINVAL;
}
static enum power_supply_property rpi_poe_power_supply_properties[] = {
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_CURRENT_AVG,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CURRENT_MAX,
};
static const struct power_supply_desc rpi_poe_power_supply_desc = {
.name = "rpi-poe",
.type = POWER_SUPPLY_TYPE_MAINS,
.properties = rpi_poe_power_supply_properties,
.num_properties = ARRAY_SIZE(rpi_poe_power_supply_properties),
.get_property = rpi_poe_power_supply_get_property,
};
static int rpi_poe_power_supply_probe(struct platform_device *pdev)
{
struct power_supply_config psy_cfg = {};
struct rpi_poe_power_supply_ctx *ctx;
struct device_node *fw_node;
u32 revision;
if (!of_device_is_available(pdev->dev.of_node))
return -ENODEV;
fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
if (!fw_node) {
dev_err(&pdev->dev, "Missing firmware node\n");
return -ENOENT;
}
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->fw = rpi_firmware_get(fw_node);
if (!ctx->fw)
return -EPROBE_DEFER;
if (rpi_firmware_property(ctx->fw,
RPI_FIRMWARE_GET_FIRMWARE_REVISION,
&revision, sizeof(revision))) {
dev_err(&pdev->dev, "Failed to get firmware revision\n");
return -ENOENT;
}
if (revision < 0x60af72e8) {
dev_err(&pdev->dev, "Unsupported firmware\n");
return -ENOENT;
}
platform_set_drvdata(pdev, ctx);
psy_cfg.of_node = pdev->dev.of_node;
psy_cfg.drv_data = ctx;
ctx->supply = devm_power_supply_register(&pdev->dev,
&rpi_poe_power_supply_desc,
&psy_cfg);
if (IS_ERR(ctx->supply))
return PTR_ERR(ctx->supply);
return 0;
}
static const struct of_device_id of_rpi_poe_power_supply_match[] = {
{ .compatible = "raspberrypi,rpi-poe-power-supply", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_rpi_poe_power_supply_match);
static struct platform_driver rpi_poe_power_supply_driver = {
.probe = rpi_poe_power_supply_probe,
.driver = {
.name = DRVNAME,
.of_match_table = of_rpi_poe_power_supply_match
},
};
module_platform_driver(rpi_poe_power_supply_driver);
MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
MODULE_ALIAS("platform:" DRVNAME);
MODULE_DESCRIPTION("Raspberry Pi PoE+ HAT power supply driver");
MODULE_LICENSE("GPL");

View File

@@ -94,7 +94,8 @@ enum rpi_firmware_property_tag {
RPI_FIRMWARE_GET_PERIPH_REG = 0x00030045, RPI_FIRMWARE_GET_PERIPH_REG = 0x00030045,
RPI_FIRMWARE_SET_PERIPH_REG = 0x00038045, RPI_FIRMWARE_SET_PERIPH_REG = 0x00038045,
RPI_FIRMWARE_GET_POE_HAT_VAL = 0x00030049, RPI_FIRMWARE_GET_POE_HAT_VAL = 0x00030049,
RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00030050, RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00038049,
RPI_FIRMWARE_SET_POE_HAT_VAL_OLD = 0x00030050,
RPI_FIRMWARE_NOTIFY_XHCI_RESET = 0x00030058, RPI_FIRMWARE_NOTIFY_XHCI_RESET = 0x00030058,
RPI_FIRMWARE_GET_REBOOT_FLAGS = 0x00030064, RPI_FIRMWARE_GET_REBOOT_FLAGS = 0x00030064,
RPI_FIRMWARE_SET_REBOOT_FLAGS = 0x00038064, RPI_FIRMWARE_SET_REBOOT_FLAGS = 0x00038064,