On Mon, Mar 22 2021, Klemens Nanni <[email protected]> wrote:
> Better diff at the end thanks to jca's eyeballing, see comments inline.
>
> kettenis: I see room for improvement in our subsystems and their
> interactions, but I don't think the current situation is bad enough to
> leave those bits out for now.
>
> Feedback? OK?
>
[...]
>> > @@ -202,6 +217,12 @@ cwfg_attach(struct device *parent, struc
>> >
>> > sensor_task_register(sc, cwfg_update_sensors, 5);
>> >
>> > +#if NAPM > 0
>> > + /* make sure we have the apm state initialized before apm attaches */
>> > + cwfg_update_sensors(sc);
>> > + apm_setinfohook(cwfg_apminfo);
>> > +#endif
>> > +
>> > printf("\n");
>> > }
>> >
>> > @@ -324,6 +345,7 @@ cwfg_update_sensors(void *arg)
>> > uint32_t vcell, rtt, tmp;
>> > uint8_t val;
>> > int error, n;
>> > + u_char bat_percent;
>> >
>> > if ((error = cwfg_lock(sc)) != 0)
>> > return;
>> > @@ -348,6 +370,7 @@ cwfg_update_sensors(void *arg)
>> > if ((error = cwfg_read(sc, SOC_HI_REG, &val)) != 0)
>> > goto done;
>> > if (val != 0xff) {
>> > + bat_percent = val;
>> > sc->sc_sensor[CWFG_SENSOR_SOC].value = val * 1000;
>> > sc->sc_sensor[CWFG_SENSOR_SOC].flags &= ~SENSOR_FINVALID;
>> > }
>>
>> If val == 0xff bat_percent is unitialized. Note that in this error
>> condition the sensors code leaves sc->sc_sensor[CWFG_SENSOR_SOC].value
>> alone.
> Oops. Both `val' and `rtt' can be "useless" and we could end up with
> a partially updated `cwfg_power'.
With the current code, rtt is always meaningful. I was really talking
only about bat_percent being possibly uninitialized.
> If we always reset all values up front and then update whatever is
> possible, we can avoid the intermediate variable completely and end up
> with `cwfg_power' providing consistent readings.
Except if reading one register fails and we take the goto done shortcut.
In that case sensors and apm get out of sync, which is bad IMHO.
[...]
>> So to keep apm and sensors in sync I think it would be better to reuse
>> the cached sc->sc_sensor[CWFG_SENSOR_SOC].value.
> I did `sc->sc_sensor[CWFG_SENSOR_SOC].value / 1000' first but ended up
> with bogus values, hence the `bat_percent' buffer to avoid arithmetics.
>
>
>> I don't know whether the error condition mentioned above happens
>> frequently with this driver. Reporting APM_BATT_ABSENT (and similar for
>> sensors) would be useful, and could be done in a subsequent step.
> But that isn't the case? From apm(4):
>
> APM_BATTERY_ABSENT
> No battery installed.
>
> The driver just can't tell us enough, but the battery is still there
> (we get good percentage/liftime readings), so
>
> APM_BATT_UNKNOWN
> Cannot read the current battery state.
>
> is only appropiate here imho.
>
>
>> What's the underlying hardware, does it involve a pluggable battery?
> Nope, Pinebook Pro with one internal battery and AC.
Since the battery can't be removed in your pinebook, then obviously
APM_BATTERY_ABSENT isn't very meaningful. But maybe the CellWise
hardware supports pluggable batteries. Anyway...
The diff below is mostly your diff, except:
- statically initialize cwfg_power with proper values. That way there's
a reason less for initializing it early by forcefully calling
cwfg_update_sensors().
- only update cwfg_power when we already fetched new values for sensors.
I hope that this approach will make changing the cwfg_update_sensors()
code easier.
If it works for you and you agree with this tweaked proposal, ok jca@
Index: cwfg.c
===================================================================
RCS file: /d/cvs/src/sys/dev/fdt/cwfg.c,v
retrieving revision 1.2
diff -u -p -p -u -r1.2 cwfg.c
--- cwfg.c 22 Mar 2021 18:37:26 -0000 1.2
+++ cwfg.c 23 Mar 2021 23:49:22 -0000
@@ -32,12 +32,15 @@
#include <sys/malloc.h>
#include <sys/sensors.h>
+#include <machine/apmvar.h>
#include <machine/fdt.h>
#include <dev/ofw/openfirm.h>
#include <dev/i2c/i2cvar.h>
+#include "apm.h"
+
#define VERSION_REG 0x00
#define VCELL_HI_REG 0x02
#define VCELL_HI_MASK 0x3f
@@ -119,6 +122,22 @@ struct cfdriver cwfg_cd = {
NULL, "cwfg", DV_DULL
};
+#if NAPM > 0
+struct apm_power_info cwfg_power = {
+ .battery_state = APM_BATT_UNKNOWN,
+ .ac_state = APM_AC_UNKNOWN,
+ .battery_life = 0,
+ .minutes_left = -1,
+};
+
+int
+cwfg_apminfo(struct apm_power_info *info)
+{
+ memcpy(info, &cwfg_power, sizeof(*info));
+ return 0;
+}
+#endif
+
int
cwfg_match(struct device *parent, void *match, void *aux)
{
@@ -202,6 +221,10 @@ cwfg_attach(struct device *parent, struc
sensor_task_register(sc, cwfg_update_sensors, 5);
+#if NAPM > 0
+ apm_setinfohook(cwfg_apminfo);
+#endif
+
printf("\n");
}
@@ -350,6 +373,11 @@ cwfg_update_sensors(void *arg)
if (val != 0xff) {
sc->sc_sensor[CWFG_SENSOR_SOC].value = val * 1000;
sc->sc_sensor[CWFG_SENSOR_SOC].flags &= ~SENSOR_FINVALID;
+#if NAPM > 0
+ cwfg_power.battery_state = val > sc->sc_alert_level ?
+ APM_BATT_HIGH : APM_BATT_LOW;
+ cwfg_power.battery_life = val;
+#endif
}
/* RTT */
@@ -362,6 +390,9 @@ cwfg_update_sensors(void *arg)
if (rtt != 0x1fff) {
sc->sc_sensor[CWFG_SENSOR_RTT].value = rtt;
sc->sc_sensor[CWFG_SENSOR_RTT].flags &= ~SENSOR_FINVALID;
+#if NAPM > 0
+ cwfg_power.minutes_left = rtt;
+#endif
}
done:
--
jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF DDCC 0DFA 74AE 1524 E7EE