1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
5 * RTC driver using firmware mailbox
6 * Supports battery backed RTC and wake alarms
8 * Based on rtc-meson-vrtc by Neil Armstrong
10 * Copyright (c) 2023, Raspberry Pi Ltd.
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/rtc.h>
17 #include <soc/bcm2835/raspberrypi-firmware.h>
20 struct rtc_device *rtc;
21 struct rpi_firmware *fw;
22 u32 bbat_vchg_microvolts;
25 #define RPI_FIRMWARE_GET_RTC_REG 0x00030087
26 #define RPI_FIRMWARE_SET_RTC_REG 0x00038087
34 RTC_BBAT_CHG_VOLTS_MIN,
35 RTC_BBAT_CHG_VOLTS_MAX,
39 static int rpi_rtc_read_time(struct device *dev, struct rtc_time *tm)
41 struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
42 u32 data[2] = {RTC_TIME};
45 err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG,
47 rtc_time64_to_tm(data[1], tm);
51 static int rpi_rtc_set_time(struct device *dev, struct rtc_time *tm)
53 struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
54 u32 data[2] = {RTC_TIME, rtc_tm_to_time64(tm)};
56 return rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG,
60 static int rpi_rtc_alarm_irq_is_enabled(struct device *dev, unsigned char *enabled)
62 struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
63 u32 data[2] = {RTC_ALARM_ENABLE};
66 err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG,
68 *enabled = data[1] & 0x1;
72 static int rpi_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
74 struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
75 u32 data[2] = {RTC_ALARM_ENABLE, enabled};
77 return rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG,
81 static int rpi_rtc_alarm_clear_pending(struct device *dev)
83 struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
84 u32 data[2] = {RTC_ALARM_PENDING, 1};
86 return rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG,
90 static int rpi_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
92 struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
93 u32 data[2] = {RTC_ALARM};
96 err = rpi_rtc_alarm_irq_is_enabled(dev, &alarm->enabled);
98 err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG,
100 rtc_time64_to_tm(data[1], &alarm->time);
105 static int rpi_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
107 struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
108 u32 data[2] = {RTC_ALARM, rtc_tm_to_time64(&alarm->time)};
111 err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG,
112 &data, sizeof(data));
115 err = rpi_rtc_alarm_irq_enable(dev, alarm->enabled);
120 static const struct rtc_class_ops rpi_rtc_ops = {
121 .read_time = rpi_rtc_read_time,
122 .set_time = rpi_rtc_set_time,
123 .read_alarm = rpi_rtc_read_alarm,
124 .set_alarm = rpi_rtc_set_alarm,
125 .alarm_irq_enable = rpi_rtc_alarm_irq_enable,
128 static int rpi_rtc_set_charge_voltage(struct device *dev)
130 struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
131 u32 data[2] = {RTC_BBAT_CHG_VOLTS, vrtc->bbat_vchg_microvolts};
134 err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG,
135 &data, sizeof(data));
138 dev_err(dev, "failed to set trickle charge voltage to %uuV: %d\n",
139 vrtc->bbat_vchg_microvolts, err);
140 else if (vrtc->bbat_vchg_microvolts)
141 dev_info(dev, "trickle charging enabled at %uuV\n",
142 vrtc->bbat_vchg_microvolts);
147 static ssize_t rpi_rtc_print_uint_reg(struct device *dev, char *buf, u32 reg)
149 struct rpi_rtc_data *vrtc = dev_get_drvdata(dev->parent);
150 u32 data[2] = {reg, 0};
153 ret = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG,
154 &data, sizeof(data));
158 return sprintf(buf, "%u\n", data[1]);
161 static ssize_t charging_voltage_show(struct device *dev,
162 struct device_attribute *attr,
165 return rpi_rtc_print_uint_reg(dev, buf, RTC_BBAT_CHG_VOLTS);
167 static DEVICE_ATTR_RO(charging_voltage);
169 static ssize_t charging_voltage_min_show(struct device *dev,
170 struct device_attribute *attr,
173 return rpi_rtc_print_uint_reg(dev, buf, RTC_BBAT_CHG_VOLTS_MIN);
175 static DEVICE_ATTR_RO(charging_voltage_min);
177 static ssize_t charging_voltage_max_show(struct device *dev,
178 struct device_attribute *attr,
181 return rpi_rtc_print_uint_reg(dev, buf, RTC_BBAT_CHG_VOLTS_MAX);
183 static DEVICE_ATTR_RO(charging_voltage_max);
185 static ssize_t battery_voltage_show(struct device *dev,
186 struct device_attribute *attr,
189 return rpi_rtc_print_uint_reg(dev, buf, RTC_BBAT_VOLTS);
191 static DEVICE_ATTR_RO(battery_voltage);
193 static struct attribute *rpi_rtc_attrs[] = {
194 &dev_attr_charging_voltage.attr,
195 &dev_attr_charging_voltage_min.attr,
196 &dev_attr_charging_voltage_max.attr,
197 &dev_attr_battery_voltage.attr,
201 static const struct attribute_group rpi_rtc_sysfs_files = {
202 .attrs = rpi_rtc_attrs,
205 static int rpi_rtc_probe(struct platform_device *pdev)
207 struct rpi_rtc_data *vrtc;
208 struct device *dev = &pdev->dev;
209 struct device_node *np = dev->of_node;
210 struct device_node *fw_node;
211 struct rpi_firmware *fw;
214 fw_node = of_parse_phandle(np, "firmware", 0);
216 dev_err(dev, "Missing firmware node\n");
220 fw = rpi_firmware_get(fw_node);
222 return -EPROBE_DEFER;
224 vrtc = devm_kzalloc(&pdev->dev, sizeof(*vrtc), GFP_KERNEL);
230 device_init_wakeup(&pdev->dev, 1);
232 platform_set_drvdata(pdev, vrtc);
234 vrtc->rtc = devm_rtc_allocate_device(&pdev->dev);
235 if (IS_ERR(vrtc->rtc))
236 return PTR_ERR(vrtc->rtc);
238 set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, vrtc->rtc->features);
239 clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, vrtc->rtc->features);
241 vrtc->rtc->ops = &rpi_rtc_ops;
242 ret = rtc_add_group(vrtc->rtc, &rpi_rtc_sysfs_files);
246 rpi_rtc_alarm_clear_pending(dev);
249 * Optionally enable trickle charging - if the property isn't
250 * present (or set to zero), trickle charging is disabled.
252 of_property_read_u32(np, "trickle-charge-microvolt",
253 &vrtc->bbat_vchg_microvolts);
255 rpi_rtc_set_charge_voltage(dev);
257 return devm_rtc_register_device(vrtc->rtc);
260 static const struct of_device_id rpi_rtc_dt_match[] = {
261 { .compatible = "raspberrypi,rpi-rtc"},
264 MODULE_DEVICE_TABLE(of, rpi_rtc_dt_match);
266 static struct platform_driver rpi_rtc_driver = {
267 .probe = rpi_rtc_probe,
270 .of_match_table = rpi_rtc_dt_match,
274 module_platform_driver(rpi_rtc_driver);
276 MODULE_DESCRIPTION("Raspberry Pi RTC driver");
277 MODULE_LICENSE("GPL");