bcm27xx: update 6.1 patches to latest version
[openwrt/staging/dangole.git] / target / linux / bcm27xx / patches-6.1 / 950-0919-rtc-rtc-rpi-Add-simple-RTC-driver-for-Raspberry-Pi.patch
1 From 222dedcdc09247126d39364a614ff2019789f52a Mon Sep 17 00:00:00 2001
2 From: Dom Cobley <popcornmix@gmail.com>
3 Date: Fri, 7 Jul 2023 20:00:45 +0100
4 Subject: [PATCH] rtc: rtc-rpi: Add simple RTC driver for Raspberry Pi
5
6 This supports setting and reading the real time clock
7 and supports wakeup alarms.
8
9 To support wake up alarms you want this bootloader config:
10 POWER_OFF_ON_HALT=1
11 WAKE_ON_GPIO=0
12
13 You can test with:
14 echo +600 | sudo tee /sys/class/rtc/rtc0/wakealarm
15 sudo halt
16
17 That will halt (in an almost no power state),
18 then wake and restart after 10 minutes.
19
20 Signed-off-by: Dom Cobley <popcornmix@gmail.com>
21 ---
22 drivers/rtc/Kconfig | 11 +++
23 drivers/rtc/Makefile | 1 +
24 drivers/rtc/rtc-rpi.c | 177 ++++++++++++++++++++++++++++++++++++++++++
25 3 files changed, 189 insertions(+)
26 create mode 100644 drivers/rtc/rtc-rpi.c
27
28 --- a/drivers/rtc/Kconfig
29 +++ b/drivers/rtc/Kconfig
30 @@ -223,6 +223,17 @@ config RTC_DRV_AC100
31 This driver can also be built as a module. If so, the module
32 will be called rtc-ac100.
33
34 +config RTC_DRV_RPI
35 + tristate "Raspberry Pi RTC"
36 + depends on ARCH_BRCMSTB || COMPILE_TEST
37 + default ARCH_BRCMSTB
38 + help
39 + If you say yes here you get support for the RTC found on
40 + Raspberry Pi devices.
41 +
42 + This driver can also be built as a module. If so, the module
43 + will be called rtc-rpi.
44 +
45 config RTC_DRV_BRCMSTB
46 tristate "Broadcom STB wake-timer"
47 depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST
48 --- a/drivers/rtc/Makefile
49 +++ b/drivers/rtc/Makefile
50 @@ -140,6 +140,7 @@ obj-$(CONFIG_RTC_DRV_RC5T583) += rtc-rc5
51 obj-$(CONFIG_RTC_DRV_RC5T619) += rtc-rc5t619.o
52 obj-$(CONFIG_RTC_DRV_RK808) += rtc-rk808.o
53 obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c01.o
54 +obj-$(CONFIG_RTC_DRV_RPI) += rtc-rpi.o
55 obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
56 obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
57 obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
58 --- /dev/null
59 +++ b/drivers/rtc/rtc-rpi.c
60 @@ -0,0 +1,177 @@
61 +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
62 +/**
63 + * rtc-rpi.c
64 + *
65 + * RTC driver using firmware mailbox
66 + * Supports battery backed RTC and wake alarms
67 + *
68 + * Based on rtc-meson-vrtc by Neil Armstrong
69 + *
70 + * Copyright (c) 2023, Raspberry Pi Ltd.
71 + */
72 +
73 +#include <linux/module.h>
74 +#include <linux/platform_device.h>
75 +#include <linux/rtc.h>
76 +#include <linux/of.h>
77 +#include <soc/bcm2835/raspberrypi-firmware.h>
78 +
79 +struct rpi_rtc_data {
80 + struct rtc_device *rtc;
81 + struct rpi_firmware *fw;
82 +};
83 +
84 +#define RPI_FIRMWARE_GET_RTC_REG 0x00030087
85 +#define RPI_FIRMWARE_SET_RTC_REG 0x00038087
86 +enum {RTC_TIME, RTC_ALARM, RTC_ALARM_PENDING, RTC_ALARM_ENABLE};
87 +
88 +static int rpi_rtc_read_time(struct device *dev, struct rtc_time *tm)
89 +{
90 + struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
91 + u32 data[2] = {RTC_TIME};
92 + int err;
93 +
94 + err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG,
95 + &data, sizeof(data));
96 + rtc_time64_to_tm(data[1], tm);
97 + return err;
98 +}
99 +
100 +static int rpi_rtc_set_time(struct device *dev, struct rtc_time *tm)
101 +{
102 + struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
103 + u32 data[2] = {RTC_TIME, rtc_tm_to_time64(tm)};
104 +
105 + return rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG,
106 + &data, sizeof(data));
107 +}
108 +
109 +static int rpi_rtc_alarm_irq_is_enabled(struct device *dev, unsigned char *enabled)
110 +{
111 + struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
112 + u32 data[2] = {RTC_ALARM_ENABLE};
113 + s32 err = 0;
114 +
115 + err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG,
116 + &data, sizeof(data));
117 + *enabled = data[1] & 0x1;
118 + return err;
119 +}
120 +
121 +static int rpi_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
122 +{
123 + struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
124 + u32 data[2] = {RTC_ALARM_ENABLE, enabled};
125 +
126 + return rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG,
127 + &data, sizeof(data));
128 +}
129 +
130 +static int rpi_rtc_alarm_clear_pending(struct device *dev)
131 +{
132 + struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
133 + u32 data[2] = {RTC_ALARM_PENDING, 1};
134 +
135 + return rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG,
136 + &data, sizeof(data));
137 +}
138 +
139 +static int rpi_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
140 +{
141 + struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
142 + u32 data[2] = {RTC_ALARM};
143 + s32 err = 0;
144 +
145 + err = rpi_rtc_alarm_irq_is_enabled(dev, &alarm->enabled);
146 + if (!err)
147 + err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG,
148 + &data, sizeof(data));
149 + rtc_time64_to_tm(data[1], &alarm->time);
150 +
151 + return err;
152 +}
153 +
154 +static int rpi_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
155 +{
156 + struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
157 + u32 data[2] = {RTC_ALARM, rtc_tm_to_time64(&alarm->time)};
158 + int err;
159 +
160 + err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG,
161 + &data, sizeof(data));
162 +
163 + if (err == 0)
164 + err = rpi_rtc_alarm_irq_enable(dev, alarm->enabled);
165 +
166 + return err;
167 +}
168 +
169 +static const struct rtc_class_ops rpi_rtc_ops = {
170 + .read_time = rpi_rtc_read_time,
171 + .set_time = rpi_rtc_set_time,
172 + .read_alarm = rpi_rtc_read_alarm,
173 + .set_alarm = rpi_rtc_set_alarm,
174 + .alarm_irq_enable = rpi_rtc_alarm_irq_enable,
175 +};
176 +
177 +static int rpi_rtc_probe(struct platform_device *pdev)
178 +{
179 + struct rpi_rtc_data *vrtc;
180 + struct device *dev = &pdev->dev;
181 + struct device_node *np = dev->of_node;
182 + struct device_node *fw_node;
183 + struct rpi_firmware *fw;
184 + int ret;
185 +
186 + fw_node = of_parse_phandle(np, "firmware", 0);
187 + if (!fw_node) {
188 + dev_err(dev, "Missing firmware node\n");
189 + return -ENOENT;
190 + }
191 +
192 + fw = rpi_firmware_get(fw_node);
193 + if (!fw)
194 + return -EPROBE_DEFER;
195 +
196 + vrtc = devm_kzalloc(&pdev->dev, sizeof(*vrtc), GFP_KERNEL);
197 + if (!vrtc)
198 + return -ENOMEM;
199 +
200 + vrtc->fw = fw;
201 +
202 + device_init_wakeup(&pdev->dev, 1);
203 +
204 + platform_set_drvdata(pdev, vrtc);
205 +
206 + vrtc->rtc = devm_rtc_allocate_device(&pdev->dev);
207 + if (IS_ERR(vrtc->rtc))
208 + return PTR_ERR(vrtc->rtc);
209 +
210 + set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, vrtc->rtc->features);
211 + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, vrtc->rtc->features);
212 +
213 + vrtc->rtc->ops = &rpi_rtc_ops;
214 + ret = devm_rtc_register_device(vrtc->rtc);
215 +
216 + rpi_rtc_alarm_clear_pending(dev);
217 + return ret;
218 +}
219 +
220 +static const struct of_device_id rpi_rtc_dt_match[] = {
221 + { .compatible = "raspberrypi,rpi-rtc"},
222 + {},
223 +};
224 +MODULE_DEVICE_TABLE(of, rpi_rtc_dt_match);
225 +
226 +static struct platform_driver rpi_rtc_driver = {
227 + .probe = rpi_rtc_probe,
228 + .driver = {
229 + .name = "rpi-rtc",
230 + .of_match_table = rpi_rtc_dt_match,
231 + },
232 +};
233 +
234 +module_platform_driver(rpi_rtc_driver);
235 +
236 +MODULE_DESCRIPTION("Raspberry Pi RTC driver");
237 +MODULE_LICENSE("GPL");