dae0a1cbff87534d140b6ed2cd85c61b66fb9959
[openwrt/staging/ansuel.git] /
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
5 readback
6
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
9 circuit is disabled.
10
11 Add sysfs attributes to read back the supported charge voltage range,
12 the measured battery voltage, and the charger setpoint.
13
14 Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
15 ---
16 drivers/rtc/rtc-rpi.c | 106 ++++++++++++++++++++++++++++++++++++++++--
17 1 file changed, 103 insertions(+), 3 deletions(-)
18
19 --- a/drivers/rtc/rtc-rpi.c
20 +++ b/drivers/rtc/rtc-rpi.c
21 @@ -19,11 +19,22 @@
22 struct rpi_rtc_data {
23 struct rtc_device *rtc;
24 struct rpi_firmware *fw;
25 + u32 bbat_vchg_microvolts;
26 };
27
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};
31 +
32 +enum {
33 + RTC_TIME,
34 + RTC_ALARM,
35 + RTC_ALARM_PENDING,
36 + RTC_ALARM_ENABLE,
37 + RTC_BBAT_CHG_VOLTS,
38 + RTC_BBAT_CHG_VOLTS_MIN,
39 + RTC_BBAT_CHG_VOLTS_MAX,
40 + RTC_BBAT_VOLTS
41 +};
42
43 static int rpi_rtc_read_time(struct device *dev, struct rtc_time *tm)
44 {
45 @@ -114,6 +125,83 @@ static const struct rtc_class_ops rpi_rt
46 .alarm_irq_enable = rpi_rtc_alarm_irq_enable,
47 };
48
49 +static int rpi_rtc_set_charge_voltage(struct device *dev)
50 +{
51 + struct rpi_rtc_data *vrtc = dev_get_drvdata(dev);
52 + u32 data[2] = {RTC_BBAT_CHG_VOLTS, vrtc->bbat_vchg_microvolts};
53 + int err;
54 +
55 + err = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_SET_RTC_REG,
56 + &data, sizeof(data));
57 +
58 + if (err)
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);
64 +
65 + return err;
66 +}
67 +
68 +static ssize_t rpi_rtc_print_uint_reg(struct device *dev, char *buf, u32 reg)
69 +{
70 + struct rpi_rtc_data *vrtc = dev_get_drvdata(dev->parent);
71 + u32 data[2] = {reg, 0};
72 + int ret = 0;
73 +
74 + ret = rpi_firmware_property(vrtc->fw, RPI_FIRMWARE_GET_RTC_REG,
75 + &data, sizeof(data));
76 + if (ret < 0)
77 + return ret;
78 +
79 + return sprintf(buf, "%u\n", data[1]);
80 +}
81 +
82 +static ssize_t charging_voltage_show(struct device *dev,
83 + struct device_attribute *attr,
84 + char *buf)
85 +{
86 + return rpi_rtc_print_uint_reg(dev, buf, RTC_BBAT_CHG_VOLTS);
87 +}
88 +static DEVICE_ATTR_RO(charging_voltage);
89 +
90 +static ssize_t charging_voltage_min_show(struct device *dev,
91 + struct device_attribute *attr,
92 + char *buf)
93 +{
94 + return rpi_rtc_print_uint_reg(dev, buf, RTC_BBAT_CHG_VOLTS_MIN);
95 +}
96 +static DEVICE_ATTR_RO(charging_voltage_min);
97 +
98 +static ssize_t charging_voltage_max_show(struct device *dev,
99 + struct device_attribute *attr,
100 + char *buf)
101 +{
102 + return rpi_rtc_print_uint_reg(dev, buf, RTC_BBAT_CHG_VOLTS_MAX);
103 +}
104 +static DEVICE_ATTR_RO(charging_voltage_max);
105 +
106 +static ssize_t battery_voltage_show(struct device *dev,
107 + struct device_attribute *attr,
108 + char *buf)
109 +{
110 + return rpi_rtc_print_uint_reg(dev, buf, RTC_BBAT_VOLTS);
111 +}
112 +static DEVICE_ATTR_RO(battery_voltage);
113 +
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,
119 + NULL
120 +};
121 +
122 +static const struct attribute_group rpi_rtc_sysfs_files = {
123 + .attrs = rpi_rtc_attrs,
124 +};
125 +
126 static int rpi_rtc_probe(struct platform_device *pdev)
127 {
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);
131
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);
135 + if (ret)
136 + return ret;
137
138 rpi_rtc_alarm_clear_pending(dev);
139 - return ret;
140 +
141 + /*
142 + * Optionally enable trickle charging - if the property isn't
143 + * present (or set to zero), trickle charging is disabled.
144 + */
145 + of_property_read_u32(np, "trickle-charge-microvolt",
146 + &vrtc->bbat_vchg_microvolts);
147 +
148 + rpi_rtc_set_charge_voltage(dev);
149 +
150 + return devm_rtc_register_device(vrtc->rtc);
151 }
152
153 static const struct of_device_id rpi_rtc_dt_match[] = {