1 From 33b514cb16dbf13395a0becf7442d19676ae4224 Mon Sep 17 00:00:00 2001
2 From: Jonathan Bell <jonathan@raspberrypi.com>
3 Date: Fri, 15 Sep 2023 17:33:03 +0100
4 Subject: [PATCH] drivers: rtc-rpi: add battery charge circuit control and
7 Parse devicetree for a charger voltage and apply it. If nonzero and a
8 valid voltage, the firmware will enable charging, otherwise the charger
11 Add sysfs attributes to read back the supported charge voltage range,
12 the measured battery voltage, and the charger setpoint.
14 Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
16 drivers/rtc/rtc-rpi.c | 106 ++++++++++++++++++++++++++++++++++++++++--
17 1 file changed, 103 insertions(+), 3 deletions(-)
19 --- a/drivers/rtc/rtc-rpi.c
20 +++ b/drivers/rtc/rtc-rpi.c
23 struct rtc_device *rtc;
24 struct rpi_firmware *fw;
25 + u32 bbat_vchg_microvolts;
28 #define RPI_FIRMWARE_GET_RTC_REG 0x00030087
29 #define RPI_FIRMWARE_SET_RTC_REG 0x00038087
30 -enum {RTC_TIME, RTC_ALARM, RTC_ALARM_PENDING, RTC_ALARM_ENABLE};
38 + RTC_BBAT_CHG_VOLTS_MIN,
39 + RTC_BBAT_CHG_VOLTS_MAX,
43 static int rpi_rtc_read_time(struct device *dev, struct rtc_time *tm)
45 @@ -114,6 +125,83 @@ static const struct rtc_class_ops rpi_rt
46 .alarm_irq_enable = rpi_rtc_alarm_irq_enable,
49 +static int rpi_rtc_set_charge_voltage(struct device *dev)
51 + struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
52 + u32 data[2] = {RTC_BBAT_CHG_VOLTS, vrtc->bbat_vchg_microvolts};
55 + err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG,
56 + &data, sizeof(data));
59 + dev_err(dev, "failed to set trickle charge voltage to %uuV: %d\n",
60 + vrtc->bbat_vchg_microvolts, err);
61 + else if (vrtc->bbat_vchg_microvolts)
62 + dev_info(dev, "trickle charging enabled at %uuV\n",
63 + vrtc->bbat_vchg_microvolts);
68 +static ssize_t rpi_rtc_print_uint_reg(struct device *dev, char *buf, u32 reg)
70 + struct rpi_rtc_data *vrtc = dev_get_drvdata(dev->parent);
71 + u32 data[2] = {reg, 0};
74 + ret = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG,
75 + &data, sizeof(data));
79 + return sprintf(buf, "%u\n", data[1]);
82 +static ssize_t charging_voltage_show(struct device *dev,
83 + struct device_attribute *attr,
86 + return rpi_rtc_print_uint_reg(dev, buf, RTC_BBAT_CHG_VOLTS);
88 +static DEVICE_ATTR_RO(charging_voltage);
90 +static ssize_t charging_voltage_min_show(struct device *dev,
91 + struct device_attribute *attr,
94 + return rpi_rtc_print_uint_reg(dev, buf, RTC_BBAT_CHG_VOLTS_MIN);
96 +static DEVICE_ATTR_RO(charging_voltage_min);
98 +static ssize_t charging_voltage_max_show(struct device *dev,
99 + struct device_attribute *attr,
102 + return rpi_rtc_print_uint_reg(dev, buf, RTC_BBAT_CHG_VOLTS_MAX);
104 +static DEVICE_ATTR_RO(charging_voltage_max);
106 +static ssize_t battery_voltage_show(struct device *dev,
107 + struct device_attribute *attr,
110 + return rpi_rtc_print_uint_reg(dev, buf, RTC_BBAT_VOLTS);
112 +static DEVICE_ATTR_RO(battery_voltage);
114 +static struct attribute *rpi_rtc_attrs[] = {
115 + &dev_attr_charging_voltage.attr,
116 + &dev_attr_charging_voltage_min.attr,
117 + &dev_attr_charging_voltage_max.attr,
118 + &dev_attr_battery_voltage.attr,
122 +static const struct attribute_group rpi_rtc_sysfs_files = {
123 + .attrs = rpi_rtc_attrs,
126 static int rpi_rtc_probe(struct platform_device *pdev)
128 struct rpi_rtc_data *vrtc;
129 @@ -151,10 +239,22 @@ static int rpi_rtc_probe(struct platform
130 clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, vrtc->rtc->features);
132 vrtc->rtc->ops = &rpi_rtc_ops;
133 - ret = devm_rtc_register_device(vrtc->rtc);
134 + ret = rtc_add_group(vrtc->rtc, &rpi_rtc_sysfs_files);
138 rpi_rtc_alarm_clear_pending(dev);
142 + * Optionally enable trickle charging - if the property isn't
143 + * present (or set to zero), trickle charging is disabled.
145 + of_property_read_u32(np, "trickle-charge-microvolt",
146 + &vrtc->bbat_vchg_microvolts);
148 + rpi_rtc_set_charge_voltage(dev);
150 + return devm_rtc_register_device(vrtc->rtc);
153 static const struct of_device_id rpi_rtc_dt_match[] = {