bcm27xx: add support for linux v5.15
[openwrt/staging/chunkeey.git] / target / linux / bcm27xx / patches-5.15 / 950-0497-Add-Raspberry-Pi-PoE-HAT-support.patch
1 From cffd250da79aa00b07b14ba9fc36ae7349f0d733 Mon Sep 17 00:00:00 2001
2 From: Serge Schneider <serge@raspberrypi.com>
3 Date: Mon, 2 Dec 2019 14:48:05 +0000
4 Subject: [PATCH] Add Raspberry Pi PoE+ HAT support
5
6 Signed-off-by: Serge Schneider <serge@raspberrypi.com>
7 ---
8 drivers/power/supply/Kconfig | 6 +
9 drivers/power/supply/Makefile | 1 +
10 drivers/power/supply/rpi_poe_power.c | 227 +++++++++++++++++++++
11 include/soc/bcm2835/raspberrypi-firmware.h | 3 +-
12 4 files changed, 236 insertions(+), 1 deletion(-)
13 create mode 100644 drivers/power/supply/rpi_poe_power.c
14
15 --- a/drivers/power/supply/Kconfig
16 +++ b/drivers/power/supply/Kconfig
17 @@ -28,6 +28,12 @@ config POWER_SUPPLY_HWMON
18 Say 'Y' here if you want power supplies to
19 have hwmon sysfs interface too.
20
21 +config RPI_POE_POWER
22 + tristate "Raspberry Pi PoE+ HAT power supply driver"
23 + depends on RASPBERRYPI_FIRMWARE
24 + help
25 + Say Y here to enable support for Raspberry Pi PoE+ (Power over Ethernet
26 + Plus) HAT current measurement.
27
28 config PDA_POWER
29 tristate "Generic PDA/phone power driver"
30 --- a/drivers/power/supply/Makefile
31 +++ b/drivers/power/supply/Makefile
32 @@ -9,6 +9,7 @@ obj-$(CONFIG_POWER_SUPPLY) += power_supp
33 obj-$(CONFIG_POWER_SUPPLY_HWMON) += power_supply_hwmon.o
34 obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o
35
36 +obj-$(CONFIG_RPI_POE_POWER) += rpi_poe_power.o
37 obj-$(CONFIG_PDA_POWER) += pda_power.o
38 obj-$(CONFIG_APM_POWER) += apm_power.o
39 obj-$(CONFIG_AXP20X_POWER) += axp20x_usb_power.o
40 --- /dev/null
41 +++ b/drivers/power/supply/rpi_poe_power.c
42 @@ -0,0 +1,227 @@
43 +// SPDX-License-Identifier: GPL-2.0
44 +/*
45 + * rpi-poe-power.c - Raspberry Pi PoE+ HAT power supply driver.
46 + *
47 + * Copyright (C) 2019 Raspberry Pi (Trading) Ltd.
48 + * Based on axp20x_ac_power.c by Quentin Schulz <quentin.schulz@free-electrons.com>
49 + *
50 + * Author: Serge Schneider <serge@raspberrypi.org>
51 + */
52 +
53 +#include <linux/module.h>
54 +#include <linux/of.h>
55 +#include <linux/platform_device.h>
56 +#include <linux/power_supply.h>
57 +#include <soc/bcm2835/raspberrypi-firmware.h>
58 +
59 +#define RPI_POE_ADC_REG 0x2
60 +#define RPI_POE_FLAG_REG 0x4
61 +
62 +#define RPI_POE_FLAG_AT BIT(0)
63 +#define RPI_POE_FLAG_OC BIT(1)
64 +
65 +#define RPI_POE_CURRENT_AF_MAX (2500 * 1000)
66 +#define RPI_POE_CURRENT_AT_MAX (5000 * 1000)
67 +
68 +#define DRVNAME "rpi-poe-power-supply"
69 +
70 +struct rpi_poe_power_supply_ctx {
71 + struct power_supply *supply;
72 + struct rpi_firmware *fw;
73 +};
74 +
75 +struct fw_tag_data_s {
76 + u32 reg;
77 + u32 val;
78 + u32 ret;
79 +};
80 +
81 +static int write_reg(struct rpi_firmware *fw, u32 reg, u32 *val)
82 +{
83 + struct fw_tag_data_s fw_tag_data = {
84 + .reg = reg,
85 + .val = *val
86 + };
87 + int ret;
88 +
89 + ret = rpi_firmware_property(fw, RPI_FIRMWARE_SET_POE_HAT_VAL,
90 + &fw_tag_data, sizeof(fw_tag_data));
91 + if (ret)
92 + return ret;
93 + else if (fw_tag_data.ret)
94 + return -EIO;
95 + return 0;
96 +}
97 +
98 +static int read_reg(struct rpi_firmware *fw, u32 reg, u32 *val)
99 +{
100 + struct fw_tag_data_s fw_tag_data = {
101 + .reg = reg,
102 + .val = *val
103 + };
104 + int ret;
105 +
106 + ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_POE_HAT_VAL,
107 + &fw_tag_data, sizeof(fw_tag_data));
108 + if (ret)
109 + return ret;
110 + else if (fw_tag_data.ret)
111 + return -EIO;
112 +
113 + *val = fw_tag_data.val;
114 + return 0;
115 +}
116 +
117 +static int rpi_poe_power_supply_get_property(struct power_supply *psy,
118 + enum power_supply_property psp,
119 + union power_supply_propval *r_val)
120 +{
121 + struct rpi_poe_power_supply_ctx *ctx = power_supply_get_drvdata(psy);
122 + int ret;
123 + unsigned int val = 0;
124 +
125 + switch (psp) {
126 + case POWER_SUPPLY_PROP_HEALTH:
127 + ret = read_reg(ctx->fw, RPI_POE_FLAG_REG, &val);
128 + if (ret)
129 + return ret;
130 +
131 + if (val & RPI_POE_FLAG_OC) {
132 + r_val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
133 + val = RPI_POE_FLAG_OC;
134 + ret = write_reg(ctx->fw, RPI_POE_FLAG_REG, &val);
135 + if (ret)
136 + return ret;
137 + return 0;
138 + }
139 +
140 + r_val->intval = POWER_SUPPLY_HEALTH_GOOD;
141 + return 0;
142 +
143 + case POWER_SUPPLY_PROP_ONLINE:
144 + ret = read_reg(ctx->fw, RPI_POE_ADC_REG, &val);
145 + if (ret)
146 + return ret;
147 +
148 + r_val->intval = (val > 5);
149 + return 0;
150 +
151 + case POWER_SUPPLY_PROP_CURRENT_AVG:
152 + val = 50;
153 + ret = read_reg(ctx->fw, RPI_POE_ADC_REG, &val);
154 + if (ret)
155 + return ret;
156 + val = (val * 3300)/9821;
157 + r_val->intval = val * 1000;
158 + return 0;
159 +
160 + case POWER_SUPPLY_PROP_CURRENT_NOW:
161 + ret = read_reg(ctx->fw, RPI_POE_ADC_REG, &val);
162 + if (ret)
163 + return ret;
164 + val = (val * 3300)/9821;
165 + r_val->intval = val * 1000;
166 + return 0;
167 +
168 + case POWER_SUPPLY_PROP_CURRENT_MAX:
169 + ret = read_reg(ctx->fw, RPI_POE_FLAG_REG, &val);
170 + if (ret)
171 + return ret;
172 +
173 + if (val & RPI_POE_FLAG_AT) {
174 + r_val->intval = RPI_POE_CURRENT_AT_MAX;
175 + return 0;
176 + }
177 + r_val->intval = RPI_POE_CURRENT_AF_MAX;
178 + return 0;
179 +
180 + default:
181 + return -EINVAL;
182 + }
183 +
184 + return -EINVAL;
185 +}
186 +
187 +static enum power_supply_property rpi_poe_power_supply_properties[] = {
188 + POWER_SUPPLY_PROP_HEALTH,
189 + POWER_SUPPLY_PROP_ONLINE,
190 + POWER_SUPPLY_PROP_CURRENT_AVG,
191 + POWER_SUPPLY_PROP_CURRENT_NOW,
192 + POWER_SUPPLY_PROP_CURRENT_MAX,
193 +};
194 +
195 +static const struct power_supply_desc rpi_poe_power_supply_desc = {
196 + .name = "rpi-poe",
197 + .type = POWER_SUPPLY_TYPE_MAINS,
198 + .properties = rpi_poe_power_supply_properties,
199 + .num_properties = ARRAY_SIZE(rpi_poe_power_supply_properties),
200 + .get_property = rpi_poe_power_supply_get_property,
201 +};
202 +
203 +static int rpi_poe_power_supply_probe(struct platform_device *pdev)
204 +{
205 + struct power_supply_config psy_cfg = {};
206 + struct rpi_poe_power_supply_ctx *ctx;
207 + struct device_node *fw_node;
208 + u32 revision;
209 +
210 + if (!of_device_is_available(pdev->dev.of_node))
211 + return -ENODEV;
212 +
213 + fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
214 + if (!fw_node) {
215 + dev_err(&pdev->dev, "Missing firmware node\n");
216 + return -ENOENT;
217 + }
218 +
219 + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
220 + if (!ctx)
221 + return -ENOMEM;
222 +
223 + ctx->fw = rpi_firmware_get(fw_node);
224 + if (!ctx->fw)
225 + return -EPROBE_DEFER;
226 + if (rpi_firmware_property(ctx->fw,
227 + RPI_FIRMWARE_GET_FIRMWARE_REVISION,
228 + &revision, sizeof(revision))) {
229 + dev_err(&pdev->dev, "Failed to get firmware revision\n");
230 + return -ENOENT;
231 + }
232 + if (revision < 0x60af72e8) {
233 + dev_err(&pdev->dev, "Unsupported firmware\n");
234 + return -ENOENT;
235 + }
236 + platform_set_drvdata(pdev, ctx);
237 +
238 + psy_cfg.of_node = pdev->dev.of_node;
239 + psy_cfg.drv_data = ctx;
240 +
241 + ctx->supply = devm_power_supply_register(&pdev->dev,
242 + &rpi_poe_power_supply_desc,
243 + &psy_cfg);
244 + if (IS_ERR(ctx->supply))
245 + return PTR_ERR(ctx->supply);
246 +
247 + return 0;
248 +}
249 +
250 +static const struct of_device_id of_rpi_poe_power_supply_match[] = {
251 + { .compatible = "raspberrypi,rpi-poe-power-supply", },
252 + { /* sentinel */ }
253 +};
254 +MODULE_DEVICE_TABLE(of, of_rpi_poe_power_supply_match);
255 +
256 +static struct platform_driver rpi_poe_power_supply_driver = {
257 + .probe = rpi_poe_power_supply_probe,
258 + .driver = {
259 + .name = DRVNAME,
260 + .of_match_table = of_rpi_poe_power_supply_match
261 + },
262 +};
263 +
264 +module_platform_driver(rpi_poe_power_supply_driver);
265 +
266 +MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
267 +MODULE_ALIAS("platform:" DRVNAME);
268 +MODULE_DESCRIPTION("Raspberry Pi PoE+ HAT power supply driver");
269 +MODULE_LICENSE("GPL");
270 --- a/include/soc/bcm2835/raspberrypi-firmware.h
271 +++ b/include/soc/bcm2835/raspberrypi-firmware.h
272 @@ -92,7 +92,8 @@ enum rpi_firmware_property_tag {
273 RPI_FIRMWARE_GET_PERIPH_REG = 0x00030045,
274 RPI_FIRMWARE_SET_PERIPH_REG = 0x00038045,
275 RPI_FIRMWARE_GET_POE_HAT_VAL = 0x00030049,
276 - RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00030050,
277 + RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00038049,
278 + RPI_FIRMWARE_SET_POE_HAT_VAL_OLD = 0x00030050,
279 RPI_FIRMWARE_NOTIFY_XHCI_RESET = 0x00030058,
280 RPI_FIRMWARE_GET_REBOOT_FLAGS = 0x00030064,
281 RPI_FIRMWARE_SET_REBOOT_FLAGS = 0x00038064,