lmu.c revision 1.1 1 1.1 macallan /* $NetBSD: lmu.c,v 1.1 2020/01/10 06:24:17 macallan Exp $ */
2 1.1 macallan
3 1.1 macallan /*-
4 1.1 macallan * Copyright (c) 2020 Michael Lorenz
5 1.1 macallan * All rights reserved.
6 1.1 macallan *
7 1.1 macallan * Redistribution and use in source and binary forms, with or without
8 1.1 macallan * modification, are permitted provided that the following conditions
9 1.1 macallan * are met:
10 1.1 macallan * 1. Redistributions of source code must retain the above copyright
11 1.1 macallan * notice, this list of conditions and the following disclaimer.
12 1.1 macallan * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 macallan * notice, this list of conditions and the following disclaimer in the
14 1.1 macallan * documentation and/or other materials provided with the distribution.
15 1.1 macallan *
16 1.1 macallan * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 1.1 macallan * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.1 macallan * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.1 macallan * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 1.1 macallan * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.1 macallan * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.1 macallan * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.1 macallan * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.1 macallan * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.1 macallan * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.1 macallan * POSSIBILITY OF SUCH DAMAGE.
27 1.1 macallan */
28 1.1 macallan
29 1.1 macallan /*
30 1.1 macallan * ambient light controller found in PowerBook5,6
31 1.1 macallan */
32 1.1 macallan
33 1.1 macallan #include <sys/cdefs.h>
34 1.1 macallan __KERNEL_RCSID(0, "$NetBSD: lmu.c,v 1.1 2020/01/10 06:24:17 macallan Exp $");
35 1.1 macallan
36 1.1 macallan #include <sys/param.h>
37 1.1 macallan #include <sys/systm.h>
38 1.1 macallan #include <sys/device.h>
39 1.1 macallan #include <sys/conf.h>
40 1.1 macallan #include <sys/bus.h>
41 1.1 macallan #include <sys/time.h>
42 1.1 macallan #include <sys/callout.h>
43 1.1 macallan
44 1.1 macallan #include <dev/ofw/openfirm.h>
45 1.1 macallan
46 1.1 macallan #include <dev/i2c/i2cvar.h>
47 1.1 macallan
48 1.1 macallan #include <dev/sysmon/sysmonvar.h>
49 1.1 macallan
50 1.1 macallan struct lmu_softc {
51 1.1 macallan device_t sc_dev;
52 1.1 macallan i2c_tag_t sc_i2c;
53 1.1 macallan i2c_addr_t sc_addr;
54 1.1 macallan int sc_node;
55 1.1 macallan
56 1.1 macallan struct sysmon_envsys *sc_sme;
57 1.1 macallan envsys_data_t sc_sensors[2];
58 1.1 macallan callout_t sc_adjust;
59 1.1 macallan int sc_thresh, sc_hyst;
60 1.1 macallan };
61 1.1 macallan
62 1.1 macallan static int lmu_match(device_t, cfdata_t, void *);
63 1.1 macallan static void lmu_attach(device_t, device_t, void *);
64 1.1 macallan
65 1.1 macallan static void lmu_sensors_refresh(struct sysmon_envsys *, envsys_data_t *);
66 1.1 macallan static void lmu_set_brightness(struct lmu_softc *, int);
67 1.1 macallan static int lmu_get_brightness(struct lmu_softc *, int);
68 1.1 macallan static void lmu_adjust(void *);
69 1.1 macallan
70 1.1 macallan CFATTACH_DECL_NEW(lmu, sizeof(struct lmu_softc),
71 1.1 macallan lmu_match, lmu_attach, NULL, NULL);
72 1.1 macallan
73 1.1 macallan static const struct device_compatible_entry compat_data[] = {
74 1.1 macallan { "lmu-micro", 0 },
75 1.1 macallan { "lmu-controller", 0 },
76 1.1 macallan { NULL, 0 }
77 1.1 macallan };
78 1.1 macallan
79 1.1 macallan static int
80 1.1 macallan lmu_match(device_t parent, cfdata_t match, void *aux)
81 1.1 macallan {
82 1.1 macallan struct i2c_attach_args *ia = aux;
83 1.1 macallan int match_result;
84 1.1 macallan
85 1.1 macallan if (iic_use_direct_match(ia, match, compat_data, &match_result))
86 1.1 macallan return match_result;
87 1.1 macallan
88 1.1 macallan return 0;
89 1.1 macallan }
90 1.1 macallan
91 1.1 macallan static void
92 1.1 macallan lmu_attach(device_t parent, device_t self, void *aux)
93 1.1 macallan {
94 1.1 macallan struct lmu_softc *sc = device_private(self);
95 1.1 macallan struct i2c_attach_args *ia = aux;
96 1.1 macallan envsys_data_t *s;
97 1.1 macallan
98 1.1 macallan sc->sc_dev = self;
99 1.1 macallan sc->sc_i2c = ia->ia_tag;
100 1.1 macallan sc->sc_addr = ia->ia_addr;
101 1.1 macallan sc->sc_node = ia->ia_cookie;
102 1.1 macallan
103 1.1 macallan aprint_naive("\n");
104 1.1 macallan aprint_normal(": ambient light sensor\n");
105 1.1 macallan
106 1.1 macallan sc->sc_sme = sysmon_envsys_create();
107 1.1 macallan sc->sc_sme->sme_name = device_xname(self);
108 1.1 macallan sc->sc_sme->sme_cookie = sc;
109 1.1 macallan sc->sc_sme->sme_refresh = lmu_sensors_refresh;
110 1.1 macallan
111 1.1 macallan s = &sc->sc_sensors[0];
112 1.1 macallan s->state = ENVSYS_SINVALID;
113 1.1 macallan s->units = ENVSYS_LUX;
114 1.1 macallan strcpy(s->desc, "right");
115 1.1 macallan s->private = 0;
116 1.1 macallan sysmon_envsys_sensor_attach(sc->sc_sme, s);
117 1.1 macallan
118 1.1 macallan s = &sc->sc_sensors[1];
119 1.1 macallan s->state = ENVSYS_SINVALID;
120 1.1 macallan s->units = ENVSYS_LUX;
121 1.1 macallan strcpy(s->desc, "left");
122 1.1 macallan s->private = 2;
123 1.1 macallan sysmon_envsys_sensor_attach(sc->sc_sme, s);
124 1.1 macallan
125 1.1 macallan sysmon_envsys_register(sc->sc_sme);
126 1.1 macallan
127 1.1 macallan /* TODO: make this adjustable via sysctl */
128 1.1 macallan sc->sc_thresh = 300;
129 1.1 macallan sc->sc_hyst = 30;
130 1.1 macallan
131 1.1 macallan callout_init(&sc->sc_adjust, 0);
132 1.1 macallan callout_setfunc(&sc->sc_adjust, lmu_adjust, sc);
133 1.1 macallan callout_schedule(&sc->sc_adjust, 0);
134 1.1 macallan }
135 1.1 macallan
136 1.1 macallan static void
137 1.1 macallan lmu_sensors_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
138 1.1 macallan {
139 1.1 macallan struct lmu_softc *sc = sme->sme_cookie;
140 1.1 macallan int ret;
141 1.1 macallan
142 1.1 macallan if ( edata->private < 3) {
143 1.1 macallan ret = lmu_get_brightness(sc, edata->private);
144 1.1 macallan if (ret == -1) return;
145 1.1 macallan edata->value_cur = ret;
146 1.1 macallan }
147 1.1 macallan edata->state = ENVSYS_SVALID;
148 1.1 macallan }
149 1.1 macallan
150 1.1 macallan static int
151 1.1 macallan lmu_get_brightness(struct lmu_softc *sc, int reg)
152 1.1 macallan {
153 1.1 macallan int error;
154 1.1 macallan uint16_t buf;
155 1.1 macallan uint8_t cmd = reg;
156 1.1 macallan
157 1.1 macallan iic_acquire_bus(sc->sc_i2c, 0);
158 1.1 macallan error = iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP,
159 1.1 macallan sc->sc_addr, &cmd, 1, &buf, 2, 0);
160 1.1 macallan iic_release_bus(sc->sc_i2c, 0);
161 1.1 macallan if (error) return -1;
162 1.1 macallan return be16toh(buf);
163 1.1 macallan }
164 1.1 macallan
165 1.1 macallan static void
166 1.1 macallan lmu_set_brightness(struct lmu_softc *sc, int b)
167 1.1 macallan {
168 1.1 macallan int bb;
169 1.1 macallan uint8_t cmd[3];
170 1.1 macallan
171 1.1 macallan cmd[0] = 1;
172 1.1 macallan bb = b * 255;
173 1.1 macallan cmd[1] = (bb & 0xff00) >> 8;
174 1.1 macallan cmd[2] = bb & 0xff;
175 1.1 macallan
176 1.1 macallan iic_acquire_bus(sc->sc_i2c, 0);
177 1.1 macallan iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP,
178 1.1 macallan sc->sc_addr, &cmd, 3, NULL, 0, 0);
179 1.1 macallan iic_release_bus(sc->sc_i2c, 0);
180 1.1 macallan }
181 1.1 macallan
182 1.1 macallan static void
183 1.1 macallan lmu_adjust(void *cookie)
184 1.1 macallan {
185 1.1 macallan struct lmu_softc *sc = cookie;
186 1.1 macallan int left, right, b;
187 1.1 macallan
188 1.1 macallan left = lmu_get_brightness(sc, 2);
189 1.1 macallan right = lmu_get_brightness(sc, 0);
190 1.1 macallan b = left > right ? left : right;
191 1.1 macallan
192 1.1 macallan if (b > (sc->sc_thresh + sc->sc_hyst)) {
193 1.1 macallan lmu_set_brightness(sc, 0);
194 1.1 macallan } else if (b < sc->sc_thresh) {
195 1.1 macallan lmu_set_brightness(sc, 100);
196 1.1 macallan }
197 1.1 macallan
198 1.1 macallan callout_schedule(&sc->sc_adjust, hz * 2);
199 1.1 macallan }
200