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
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
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
15 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
17 drivers/power/supply/rpi_poe_power.c | 124 ++++++++++++++++-----------
18 1 file changed, 75 insertions(+), 49 deletions(-)
20 --- a/drivers/power/supply/rpi_poe_power.c
21 +++ b/drivers/power/supply/rpi_poe_power.c
24 #include <linux/platform_device.h>
25 #include <linux/power_supply.h>
26 +#include <linux/regmap.h>
27 #include <soc/bcm2835/raspberrypi-firmware.h>
29 -#define RPI_POE_ADC_REG 0x2
30 -#define RPI_POE_FLAG_REG 0x4
31 +#define RPI_POE_FW_BASE_REG 0x2
33 +#define RPI_POE_ADC_REG 0x0
34 +#define RPI_POE_FLAG_REG 0x2
36 #define RPI_POE_FLAG_AT BIT(0)
37 #define RPI_POE_FLAG_OC BIT(1)
39 #define DRVNAME "rpi-poe-power-supply"
41 struct rpi_poe_power_supply_ctx {
42 - struct power_supply *supply;
43 struct rpi_firmware *fw;
45 + struct regmap *regmap;
48 + struct power_supply *supply;
51 struct fw_tag_data_s {
52 @@ -36,40 +43,51 @@ struct fw_tag_data_s {
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)
59 struct fw_tag_data_s fw_tag_data = {
61 + .reg = reg + RPI_POE_FW_BASE_REG,
66 - ret = rpi_firmware_property(fw, RPI_FIRMWARE_SET_POE_HAT_VAL,
67 - &fw_tag_data, sizeof(fw_tag_data));
70 - else if (fw_tag_data.ret)
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)
79 + ret = regmap_write(ctx->regmap, ctx->offset + reg, *val);
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)
88 struct fw_tag_data_s fw_tag_data = {
90 + .reg = reg + RPI_POE_FW_BASE_REG,
96 - ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_POE_HAT_VAL,
97 - &fw_tag_data, sizeof(fw_tag_data));
100 - else if (fw_tag_data.ret)
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)
107 + *val = fw_tag_data.val;
109 + ret = regmap_read(ctx->regmap, ctx->offset + reg, &value);
112 + ret = regmap_read(ctx->regmap, ctx->offset + reg + 1, &value);
113 + *val |= value << 8;
117 - *val = fw_tag_data.val;
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
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);
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);
140 @@ -99,7 +117,7 @@ static int rpi_poe_power_supply_get_prop
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);
149 @@ -107,7 +125,7 @@ static int rpi_poe_power_supply_get_prop
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);
157 val = (val * 3300)/9821;
158 @@ -115,15 +133,14 @@ static int rpi_poe_power_supply_get_prop
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);
167 - if (val & RPI_POE_FLAG_AT) {
168 + if (val & RPI_POE_FLAG_AT)
169 r_val->intval = RPI_POE_CURRENT_AT_MAX;
172 - r_val->intval = RPI_POE_CURRENT_AF_MAX;
174 + r_val->intval = RPI_POE_CURRENT_AF_MAX;
178 @@ -158,29 +175,38 @@ static int rpi_poe_power_supply_probe(st
179 if (!of_device_is_available(pdev->dev.of_node))
182 - fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
184 - dev_err(&pdev->dev, "Missing firmware node\n");
188 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
192 - ctx->fw = rpi_firmware_get(fw_node);
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");
201 - if (revision < 0x60af72e8) {
202 - dev_err(&pdev->dev, "Unsupported firmware\n");
204 + if (pdev->dev.parent)
205 + ctx->regmap = dev_get_regmap(pdev->dev.parent, NULL);
208 + if (device_property_read_u32(&pdev->dev, "reg", &ctx->offset))
211 + fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
213 + dev_err(&pdev->dev, "Missing firmware node\n");
217 + ctx->fw = rpi_firmware_get(fw_node);
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");
226 + if (revision < 0x60af72e8) {
227 + dev_err(&pdev->dev, "Unsupported firmware\n");
232 platform_set_drvdata(pdev, ctx);
234 psy_cfg.of_node = pdev->dev.of_node;