bcm27xx: add support for linux v5.15
[openwrt/staging/chunkeey.git] / target / linux / bcm27xx / patches-5.15 / 950-0660-power-rpi-poe-Add-option-of-being-created-by-MFD-or-.patch
1 From 2b9f5f00b22766743607b70d361875a9a1b0e1ed Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.com>
3 Date: Thu, 20 Jan 2022 15:50:27 +0000
4 Subject: [PATCH] power: rpi-poe: Add option of being created by MFD or
5 FW
6
7 The firmware can only use I2C0 if the kernel isn't, therefore
8 with libcamera and DRM using it the PoE HAT fan control needs
9 to move to the kernel.
10
11 Add the option for the driver to be created by the PoE HAT core
12 MFD driver, and use the I2C regmap that provides to control fan
13 functions.
14
15 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
16 ---
17 drivers/power/supply/rpi_poe_power.c | 124 ++++++++++++++++-----------
18 1 file changed, 75 insertions(+), 49 deletions(-)
19
20 --- a/drivers/power/supply/rpi_poe_power.c
21 +++ b/drivers/power/supply/rpi_poe_power.c
22 @@ -12,10 +12,13 @@
23 #include <linux/of.h>
24 #include <linux/platform_device.h>
25 #include <linux/power_supply.h>
26 +#include <linux/regmap.h>
27 #include <soc/bcm2835/raspberrypi-firmware.h>
28
29 -#define RPI_POE_ADC_REG 0x2
30 -#define RPI_POE_FLAG_REG 0x4
31 +#define RPI_POE_FW_BASE_REG 0x2
32 +
33 +#define RPI_POE_ADC_REG 0x0
34 +#define RPI_POE_FLAG_REG 0x2
35
36 #define RPI_POE_FLAG_AT BIT(0)
37 #define RPI_POE_FLAG_OC BIT(1)
38 @@ -26,8 +29,12 @@
39 #define DRVNAME "rpi-poe-power-supply"
40
41 struct rpi_poe_power_supply_ctx {
42 - struct power_supply *supply;
43 struct rpi_firmware *fw;
44 +
45 + struct regmap *regmap;
46 + u32 offset;
47 +
48 + struct power_supply *supply;
49 };
50
51 struct fw_tag_data_s {
52 @@ -36,40 +43,51 @@ struct fw_tag_data_s {
53 u32 ret;
54 };
55
56 -static int write_reg(struct rpi_firmware *fw, u32 reg, u32 *val)
57 +static int write_reg(struct rpi_poe_power_supply_ctx *ctx, u32 reg, u32 *val)
58 {
59 struct fw_tag_data_s fw_tag_data = {
60 - .reg = reg,
61 + .reg = reg + RPI_POE_FW_BASE_REG,
62 .val = *val
63 };
64 int ret;
65
66 - ret = rpi_firmware_property(fw, RPI_FIRMWARE_SET_POE_HAT_VAL,
67 - &fw_tag_data, sizeof(fw_tag_data));
68 - if (ret)
69 - return ret;
70 - else if (fw_tag_data.ret)
71 - return -EIO;
72 - return 0;
73 + if (ctx->fw) {
74 + ret = rpi_firmware_property(ctx->fw, RPI_FIRMWARE_SET_POE_HAT_VAL,
75 + &fw_tag_data, sizeof(fw_tag_data));
76 + if (!ret && fw_tag_data.ret)
77 + ret = -EIO;
78 + } else {
79 + ret = regmap_write(ctx->regmap, ctx->offset + reg, *val);
80 + }
81 +
82 + return ret;
83 }
84
85 -static int read_reg(struct rpi_firmware *fw, u32 reg, u32 *val)
86 +static int read_reg(struct rpi_poe_power_supply_ctx *ctx, u32 reg, u32 *val)
87 {
88 struct fw_tag_data_s fw_tag_data = {
89 - .reg = reg,
90 + .reg = reg + RPI_POE_FW_BASE_REG,
91 .val = *val
92 };
93 + u32 value;
94 int ret;
95
96 - ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_POE_HAT_VAL,
97 - &fw_tag_data, sizeof(fw_tag_data));
98 - if (ret)
99 - return ret;
100 - else if (fw_tag_data.ret)
101 - return -EIO;
102 + if (ctx->fw) {
103 + ret = rpi_firmware_property(ctx->fw, RPI_FIRMWARE_GET_POE_HAT_VAL,
104 + &fw_tag_data, sizeof(fw_tag_data));
105 + if (!ret && fw_tag_data.ret)
106 + ret = -EIO;
107 + *val = fw_tag_data.val;
108 + } else {
109 + ret = regmap_read(ctx->regmap, ctx->offset + reg, &value);
110 + if (!ret) {
111 + *val = value;
112 + ret = regmap_read(ctx->regmap, ctx->offset + reg + 1, &value);
113 + *val |= value << 8;
114 + }
115 + }
116
117 - *val = fw_tag_data.val;
118 - return 0;
119 + return ret;
120 }
121
122 static int rpi_poe_power_supply_get_property(struct power_supply *psy,
123 @@ -82,14 +100,14 @@ static int rpi_poe_power_supply_get_prop
124
125 switch (psp) {
126 case POWER_SUPPLY_PROP_HEALTH:
127 - ret = read_reg(ctx->fw, RPI_POE_FLAG_REG, &val);
128 + ret = read_reg(ctx, RPI_POE_FLAG_REG, &val);
129 if (ret)
130 return ret;
131
132 if (val & RPI_POE_FLAG_OC) {
133 r_val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
134 val = RPI_POE_FLAG_OC;
135 - ret = write_reg(ctx->fw, RPI_POE_FLAG_REG, &val);
136 + ret = write_reg(ctx, RPI_POE_FLAG_REG, &val);
137 if (ret)
138 return ret;
139 return 0;
140 @@ -99,7 +117,7 @@ static int rpi_poe_power_supply_get_prop
141 return 0;
142
143 case POWER_SUPPLY_PROP_ONLINE:
144 - ret = read_reg(ctx->fw, RPI_POE_ADC_REG, &val);
145 + ret = read_reg(ctx, RPI_POE_ADC_REG, &val);
146 if (ret)
147 return ret;
148
149 @@ -107,7 +125,7 @@ static int rpi_poe_power_supply_get_prop
150 return 0;
151
152 case POWER_SUPPLY_PROP_CURRENT_NOW:
153 - ret = read_reg(ctx->fw, RPI_POE_ADC_REG, &val);
154 + ret = read_reg(ctx, RPI_POE_ADC_REG, &val);
155 if (ret)
156 return ret;
157 val = (val * 3300)/9821;
158 @@ -115,15 +133,14 @@ static int rpi_poe_power_supply_get_prop
159 return 0;
160
161 case POWER_SUPPLY_PROP_CURRENT_MAX:
162 - ret = read_reg(ctx->fw, RPI_POE_FLAG_REG, &val);
163 + ret = read_reg(ctx, RPI_POE_FLAG_REG, &val);
164 if (ret)
165 return ret;
166
167 - if (val & RPI_POE_FLAG_AT) {
168 + if (val & RPI_POE_FLAG_AT)
169 r_val->intval = RPI_POE_CURRENT_AT_MAX;
170 - return 0;
171 - }
172 - r_val->intval = RPI_POE_CURRENT_AF_MAX;
173 + else
174 + r_val->intval = RPI_POE_CURRENT_AF_MAX;
175 return 0;
176
177 default:
178 @@ -158,29 +175,38 @@ static int rpi_poe_power_supply_probe(st
179 if (!of_device_is_available(pdev->dev.of_node))
180 return -ENODEV;
181
182 - fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
183 - if (!fw_node) {
184 - dev_err(&pdev->dev, "Missing firmware node\n");
185 - return -ENOENT;
186 - }
187 -
188 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
189 if (!ctx)
190 return -ENOMEM;
191
192 - ctx->fw = rpi_firmware_get(fw_node);
193 - if (!ctx->fw)
194 - return -EPROBE_DEFER;
195 - if (rpi_firmware_property(ctx->fw,
196 - RPI_FIRMWARE_GET_FIRMWARE_REVISION,
197 - &revision, sizeof(revision))) {
198 - dev_err(&pdev->dev, "Failed to get firmware revision\n");
199 - return -ENOENT;
200 - }
201 - if (revision < 0x60af72e8) {
202 - dev_err(&pdev->dev, "Unsupported firmware\n");
203 - return -ENOENT;
204 + if (pdev->dev.parent)
205 + ctx->regmap = dev_get_regmap(pdev->dev.parent, NULL);
206 +
207 + if (ctx->regmap) {
208 + if (device_property_read_u32(&pdev->dev, "reg", &ctx->offset))
209 + return -EINVAL;
210 + } else {
211 + fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
212 + if (!fw_node) {
213 + dev_err(&pdev->dev, "Missing firmware node\n");
214 + return -ENOENT;
215 + }
216 +
217 + ctx->fw = rpi_firmware_get(fw_node);
218 + if (!ctx->fw)
219 + return -EPROBE_DEFER;
220 + if (rpi_firmware_property(ctx->fw,
221 + RPI_FIRMWARE_GET_FIRMWARE_REVISION,
222 + &revision, sizeof(revision))) {
223 + dev_err(&pdev->dev, "Failed to get firmware revision\n");
224 + return -ENOENT;
225 + }
226 + if (revision < 0x60af72e8) {
227 + dev_err(&pdev->dev, "Unsupported firmware\n");
228 + return -ENOENT;
229 + }
230 }
231 +
232 platform_set_drvdata(pdev, ctx);
233
234 psy_cfg.of_node = pdev->dev.of_node;