1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
From fd864dfdcaa04271c09767bba5d77247b0899a6e Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Wed, 19 Jan 2022 17:26:22 +0000
Subject: [PATCH] pwm: raspberrypi-poe: Add option of being created by
MFD or FW
The firmware can only use I2C0 if the kernel isn't, therefore
with libcamera and DRM using it the PoE HAT fan control needs
to move to the kernel.
Add the option for the driver to be created by the PoE HAT core
MFD driver, and use the I2C regmap that provides to control fan
functions.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/pwm/pwm-raspberrypi-poe.c | 81 ++++++++++++++++++-------------
1 file changed, 48 insertions(+), 33 deletions(-)
--- a/drivers/pwm/pwm-raspberrypi-poe.c
+++ b/drivers/pwm/pwm-raspberrypi-poe.c
@@ -16,6 +16,7 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pwm.h>
+#include <linux/regmap.h>
#include <soc/bcm2835/raspberrypi-firmware.h>
#include <dt-bindings/pwm/raspberrypi,firmware-poe-pwm.h>
@@ -27,6 +28,10 @@
struct raspberrypi_pwm {
struct rpi_firmware *firmware;
+
+ struct regmap *regmap;
+ u32 offset;
+
struct pwm_chip chip;
unsigned int duty_cycle;
};
@@ -43,7 +48,7 @@ struct raspberrypi_pwm *raspberrypi_pwm_
return container_of(chip, struct raspberrypi_pwm, chip);
}
-static int raspberrypi_pwm_set_property(struct rpi_firmware *firmware,
+static int raspberrypi_pwm_set_property(struct raspberrypi_pwm *pwm,
u32 reg, u32 val)
{
struct raspberrypi_pwm_prop msg = {
@@ -52,17 +57,19 @@ static int raspberrypi_pwm_set_property(
};
int ret;
- ret = rpi_firmware_property(firmware, RPI_FIRMWARE_SET_POE_HAT_VAL,
- &msg, sizeof(msg));
- if (ret)
- return ret;
- if (msg.ret)
- return -EIO;
+ if (pwm->firmware) {
+ ret = rpi_firmware_property(pwm->firmware, RPI_FIRMWARE_SET_POE_HAT_VAL,
+ &msg, sizeof(msg));
+ if (!ret && msg.ret)
+ ret = -EIO;
+ } else {
+ ret = regmap_write(pwm->regmap, pwm->offset + reg, val);
+ }
- return 0;
+ return ret;
}
-static int raspberrypi_pwm_get_property(struct rpi_firmware *firmware,
+static int raspberrypi_pwm_get_property(struct raspberrypi_pwm *pwm,
u32 reg, u32 *val)
{
struct raspberrypi_pwm_prop msg = {
@@ -70,16 +77,17 @@ static int raspberrypi_pwm_get_property(
};
int ret;
- ret = rpi_firmware_property(firmware, RPI_FIRMWARE_GET_POE_HAT_VAL,
- &msg, sizeof(msg));
- if (ret)
- return ret;
- if (msg.ret)
- return -EIO;
-
- *val = le32_to_cpu(msg.val);
+ if (pwm->firmware) {
+ ret = rpi_firmware_property(pwm->firmware, RPI_FIRMWARE_GET_POE_HAT_VAL,
+ &msg, sizeof(msg));
+ if (!ret && msg.ret)
+ ret = -EIO;
+ *val = le32_to_cpu(msg.val);
+ } else {
+ ret = regmap_read(pwm->regmap, pwm->offset + reg, val);
+ }
- return 0;
+ return ret;
}
static void raspberrypi_pwm_get_state(struct pwm_chip *chip,
@@ -117,7 +125,7 @@ static int raspberrypi_pwm_apply(struct
if (duty_cycle == rpipwm->duty_cycle)
return 0;
- ret = raspberrypi_pwm_set_property(rpipwm->firmware, RPI_PWM_CUR_DUTY_REG,
+ ret = raspberrypi_pwm_set_property(rpipwm, RPI_PWM_CUR_DUTY_REG,
duty_cycle);
if (ret) {
dev_err(chip->dev, "Failed to set duty cycle: %pe\n",
@@ -144,29 +152,35 @@ static int raspberrypi_pwm_probe(struct
struct raspberrypi_pwm *rpipwm;
int ret;
- firmware_node = of_get_parent(dev->of_node);
- if (!firmware_node) {
- dev_err(dev, "Missing firmware node\n");
- return -ENOENT;
- }
-
- firmware = devm_rpi_firmware_get(&pdev->dev, firmware_node);
- of_node_put(firmware_node);
- if (!firmware)
- return dev_err_probe(dev, -EPROBE_DEFER,
- "Failed to get firmware handle\n");
-
rpipwm = devm_kzalloc(&pdev->dev, sizeof(*rpipwm), GFP_KERNEL);
if (!rpipwm)
return -ENOMEM;
- rpipwm->firmware = firmware;
+ if (pdev->dev.parent)
+ rpipwm->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+
+ if (rpipwm->regmap) {
+ ret = device_property_read_u32(&pdev->dev, "reg", &rpipwm->offset);
+ if (ret)
+ return -EINVAL;
+ } else {
+ firmware_node = of_get_parent(dev->of_node);
+
+ firmware = devm_rpi_firmware_get(&pdev->dev, firmware_node);
+ of_node_put(firmware_node);
+ if (!firmware)
+ return dev_err_probe(dev, -EPROBE_DEFER,
+ "Failed to get firmware handle\n");
+
+ rpipwm->firmware = firmware;
+ }
+
rpipwm->chip.dev = dev;
rpipwm->chip.ops = &raspberrypi_pwm_ops;
rpipwm->chip.base = -1;
rpipwm->chip.npwm = RASPBERRYPI_FIRMWARE_PWM_NUM;
- ret = raspberrypi_pwm_get_property(rpipwm->firmware, RPI_PWM_CUR_DUTY_REG,
+ ret = raspberrypi_pwm_get_property(rpipwm, RPI_PWM_CUR_DUTY_REG,
&rpipwm->duty_cycle);
if (ret) {
dev_err(dev, "Failed to get duty cycle: %pe\n", ERR_PTR(ret));
@@ -178,6 +192,7 @@ static int raspberrypi_pwm_probe(struct
static const struct of_device_id raspberrypi_pwm_of_match[] = {
{ .compatible = "raspberrypi,firmware-poe-pwm", },
+ { .compatible = "raspberrypi,poe-pwm", },
{ }
};
MODULE_DEVICE_TABLE(of, raspberrypi_pwm_of_match);
|