Module Name: src Committed By: macallan Date: Thu Apr 23 12:56:40 UTC 2020
Modified Files: src/sys/arch/macppc/dev: lmu.c Log Message: make this work properly: - get rid of cargo-culted register assignments, I found the right ones by experiment, now both light sensors report sane values - keyboard brightness seems to max out at 16, act like it - do what MacOS does and fade keyboard brightness instead of just switching - add sysctls to configure keyboard brightness and environmental light thresholds - don't poll the chip more often than once a second To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/sys/arch/macppc/dev/lmu.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/macppc/dev/lmu.c diff -u src/sys/arch/macppc/dev/lmu.c:1.3 src/sys/arch/macppc/dev/lmu.c:1.4 --- src/sys/arch/macppc/dev/lmu.c:1.3 Thu Apr 23 09:47:31 2020 +++ src/sys/arch/macppc/dev/lmu.c Thu Apr 23 12:56:40 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: lmu.c,v 1.3 2020/04/23 09:47:31 macallan Exp $ */ +/* $NetBSD: lmu.c,v 1.4 2020/04/23 12:56:40 macallan Exp $ */ /*- * Copyright (c) 2020 Michael Lorenz @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: lmu.c,v 1.3 2020/04/23 09:47:31 macallan Exp $"); +__KERNEL_RCSID(0, "$NetBSD: lmu.c,v 1.4 2020/04/23 12:56:40 macallan Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -40,11 +40,18 @@ __KERNEL_RCSID(0, "$NetBSD: lmu.c,v 1.3 #include <sys/bus.h> #include <sys/time.h> #include <sys/callout.h> +#include <sys/sysctl.h> #include <dev/i2c/i2cvar.h> #include <dev/sysmon/sysmonvar.h> +#ifdef LMU_DEBUG +#define DPRINTF printf +#else +#define DPRINTF if (0) printf +#endif + struct lmu_softc { device_t sc_dev; i2c_tag_t sc_i2c; @@ -54,7 +61,9 @@ struct lmu_softc { struct sysmon_envsys *sc_sme; envsys_data_t sc_sensors[2]; callout_t sc_adjust; - int sc_thresh, sc_hyst, sc_level; + int sc_thresh, sc_hyst, sc_level, sc_target, sc_current; + int sc_lux[2]; + time_t sc_last; int sc_lid_state, sc_video_state; }; @@ -65,6 +74,8 @@ static void lmu_sensors_refresh(struct s static void lmu_set_brightness(struct lmu_softc *, int); static int lmu_get_brightness(struct lmu_softc *, int); static void lmu_adjust(void *); +static int lmu_sysctl(SYSCTLFN_ARGS); +static int lmu_sysctl_thresh(SYSCTLFN_ARGS); CFATTACH_DECL_NEW(lmu, sizeof(struct lmu_softc), lmu_match, lmu_attach, NULL, NULL); @@ -75,6 +86,11 @@ static const struct device_compatible_en { NULL, 0 } }; +/* time between polling the light sensors */ +#define LMU_POLL (hz * 2) +/* time between updates to keyboard brightness */ +#define LMU_FADE (hz / 16) + static void lmu_lid_open(device_t dev) { @@ -125,11 +141,13 @@ lmu_attach(device_t parent, device_t sel struct lmu_softc *sc = device_private(self); struct i2c_attach_args *ia = aux; envsys_data_t *s; + const struct sysctlnode *me; sc->sc_dev = self; sc->sc_i2c = ia->ia_tag; sc->sc_addr = ia->ia_addr; sc->sc_node = ia->ia_cookie; + sc->sc_last = 0; aprint_naive("\n"); aprint_normal(": ambient light sensor\n"); @@ -161,7 +179,7 @@ lmu_attach(device_t parent, device_t sel s->state = ENVSYS_SINVALID; s->units = ENVSYS_LUX; strcpy(s->desc, "left"); - s->private = 2; + s->private = 1; sysmon_envsys_sensor_attach(sc->sc_sme, s); sysmon_envsys_register(sc->sc_sme); @@ -169,7 +187,30 @@ lmu_attach(device_t parent, device_t sel /* TODO: make this adjustable via sysctl */ sc->sc_thresh = 300; sc->sc_hyst = 30; - sc->sc_level = 100; + sc->sc_level = 16; + sc->sc_target = 0; + sc->sc_current = 0; + + sysctl_createv(NULL, 0, NULL, &me, + CTLFLAG_READWRITE, + CTLTYPE_NODE, "lmu", + SYSCTL_DESCR("LMU driver"), + NULL, 0, NULL, 0, + CTL_HW, CTL_CREATE, CTL_EOL); + + sysctl_createv(NULL, 0, NULL, NULL, + CTLFLAG_READWRITE, + CTLTYPE_INT, "level", + SYSCTL_DESCR("keyboard brightness"), + lmu_sysctl, 0, (void *)sc, 0, + CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL); + + sysctl_createv(NULL, 0, NULL, NULL, + CTLFLAG_READWRITE, + CTLTYPE_INT, "threshold", + SYSCTL_DESCR("environmental light threshold"), + lmu_sysctl_thresh, 1, (void *)sc, 0, + CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL); callout_init(&sc->sc_adjust, 0); callout_setfunc(&sc->sc_adjust, lmu_adjust, sc); @@ -193,28 +234,38 @@ lmu_sensors_refresh(struct sysmon_envsys static int lmu_get_brightness(struct lmu_softc *sc, int reg) { - int error; - uint16_t buf; - uint8_t cmd = reg; + int error, i; + uint16_t buf[2]; + uint8_t cmd = 0; + + if (reg > 1) return -1; + if (time_second == sc->sc_last) + return sc->sc_lux[reg]; iic_acquire_bus(sc->sc_i2c, 0); error = iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP, - sc->sc_addr, &cmd, 1, &buf, 2, 0); + sc->sc_addr, &cmd, 1, buf, 4, 0); iic_release_bus(sc->sc_i2c, 0); if (error) return -1; - return be16toh(buf); + sc->sc_last = time_second; + + for (i = 0; i < 2; i++) + sc->sc_lux[i] = be16toh(buf[i]); + + DPRINTF("<%d %04x %04x>", reg, buf[0], buf[1]); + + return (sc->sc_lux[reg]); } static void lmu_set_brightness(struct lmu_softc *sc, int b) { - int bb; uint8_t cmd[3]; cmd[0] = 1; - bb = b * 255; - cmd[1] = (bb & 0xff00) >> 8; - cmd[2] = bb & 0xff; + + cmd[1] = (b & 0xff); + cmd[2] = (b & 0xff) >> 8; iic_acquire_bus(sc->sc_i2c, 0); iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP, @@ -226,18 +277,85 @@ static void lmu_adjust(void *cookie) { struct lmu_softc *sc = cookie; - int left, right, b; + int left, right, b, offset; - left = lmu_get_brightness(sc, 2); + left = lmu_get_brightness(sc, 1); right = lmu_get_brightness(sc, 0); b = left > right ? left : right; if ((b > (sc->sc_thresh + sc->sc_hyst)) || !(sc->sc_lid_state && sc->sc_video_state)) { - lmu_set_brightness(sc, 0); + sc->sc_target = 0; } else if (b < sc->sc_thresh) { - lmu_set_brightness(sc, sc->sc_level); + sc->sc_target = sc->sc_level; + } + + if (sc->sc_target == sc->sc_current) { + /* no update needed, check again later */ + callout_schedule(&sc->sc_adjust, LMU_POLL); + return; + } + + + offset = ((sc->sc_target - sc->sc_current) > 0) ? 2 : -2; + sc->sc_current += offset; + if (sc->sc_current > sc->sc_level) sc->sc_current = sc->sc_level; + if (sc->sc_current < 0) sc->sc_current = 0; + + DPRINTF("[%d]", sc->sc_current); + + lmu_set_brightness(sc, sc->sc_current); + + if (sc->sc_target == sc->sc_current) { + /* no update needed, check again later */ + callout_schedule(&sc->sc_adjust, LMU_POLL); + return; + } + + /* more updates upcoming */ + callout_schedule(&sc->sc_adjust, LMU_FADE); +} + +static int +lmu_sysctl(SYSCTLFN_ARGS) +{ + struct sysctlnode node = *rnode; + struct lmu_softc *sc = node.sysctl_data; + int target; + + target = sc->sc_level; + node.sysctl_data = ⌖ + if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { + int new_reg; + + new_reg = *(int *)node.sysctl_data; + if (new_reg != sc->sc_target) { + sc->sc_level = target; + sc->sc_target = target; + + } + return 0; } + return EINVAL; +} - callout_schedule(&sc->sc_adjust, hz * 2); +static int +lmu_sysctl_thresh(SYSCTLFN_ARGS) +{ + struct sysctlnode node = *rnode; + struct lmu_softc *sc = node.sysctl_data; + int thresh; + + thresh = sc->sc_thresh; + node.sysctl_data = &thresh; + if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { + int new_reg; + + new_reg = *(int *)node.sysctl_data; + if (new_reg != sc->sc_thresh && new_reg > 0) { + sc->sc_thresh = new_reg; + } + return 0; + } + return EINVAL; }