1 /* $OpenBSD: acpisbs.c,v 1.11 2022/10/26 16:06:42 kn Exp $ */
2 /*
3 * Smart Battery subsystem device driver
4 * ACPI 5.0 spec section 10
5 *
6 * Copyright (c) 2016-2017 joshua stein <jcs@openbsd.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21 /*
22 * TODO: support multiple batteries based on _SBS, make sc_battery an array and
23 * poll each battery independently
24 */
25
26 #include <sys/param.h>
27 #include <sys/systm.h>
28 #include <sys/device.h>
29 #include <sys/malloc.h>
30
31 #include <machine/apmvar.h>
32
33 #include <dev/acpi/acpireg.h>
34 #include <dev/acpi/acpivar.h>
35 #include <dev/acpi/acpidev.h>
36 #include <dev/acpi/amltypes.h>
37 #include <dev/acpi/dsdt.h>
38
39 #include <sys/sensors.h>
40
41 /* #define ACPISBS_DEBUG */
42
43 #ifdef ACPISBS_DEBUG
44 #define DPRINTF(x) printf x
45 #else
46 #define DPRINTF(x)
47 #endif
48
49 /* how often (in seconds) to re-poll data */
50 #define ACPISBS_POLL_FREQ 30
51
52 /* number of polls for reading data */
53 #define SMBUS_TIMEOUT 50
54
55 #define CHECK(kind, cmd, val, senst, sens) { \
56 SMBUS_READ_##kind, SMBATT_CMD_##cmd, \
57 offsetof(struct acpisbs_battery, val), \
58 (SMBUS_READ_##kind == SMBUS_READ_BLOCK ? SMBUS_DATA_SIZE : 2), \
59 #val, senst, sens }
60
61 const struct acpisbs_battery_check {
62 uint8_t mode;
63 uint8_t command;
64 size_t offset;
65 int len;
66 char *name;
67 int sensor_type;
68 char *sensor_desc;
69 } acpisbs_battery_checks[] = {
70 /* mode must be checked first */
71 CHECK(WORD, BATTERY_MODE, mode, -1,
72 "mode flags"),
73 CHECK(WORD, TEMPERATURE, temperature, SENSOR_TEMP,
74 "internal temperature"),
75 CHECK(WORD, VOLTAGE, voltage, SENSOR_VOLTS_DC,
76 "voltage"),
77 CHECK(WORD, CURRENT, current, SENSOR_AMPS,
78 "current being supplied"),
79 CHECK(WORD, AVERAGE_CURRENT, avg_current, SENSOR_AMPS,
80 "average current supplied"),
81 CHECK(WORD, RELATIVE_STATE_OF_CHARGE, rel_charge, SENSOR_PERCENT,
82 "remaining capacity"),
83 CHECK(WORD, ABSOLUTE_STATE_OF_CHARGE, abs_charge, SENSOR_PERCENT,
84 "remaining of design capacity"),
85 CHECK(WORD, REMAINING_CAPACITY, capacity, SENSOR_AMPHOUR,
86 "remaining capacity"),
87 CHECK(WORD, FULL_CHARGE_CAPACITY, full_capacity, SENSOR_AMPHOUR,
88 "capacity when fully charged"),
89 CHECK(WORD, RUN_TIME_TO_EMPTY, run_time, SENSOR_INTEGER,
90 "remaining run time minutes"),
91 CHECK(WORD, AVERAGE_TIME_TO_EMPTY, avg_empty_time, SENSOR_INTEGER,
92 "avg remaining minutes"),
93 CHECK(WORD, AVERAGE_TIME_TO_FULL, avg_full_time, SENSOR_INTEGER,
94 "avg minutes until full charge"),
95 CHECK(WORD, CHARGING_CURRENT, charge_current, SENSOR_AMPS,
96 "desired charging rate"),
97 CHECK(WORD, CHARGING_VOLTAGE, charge_voltage, SENSOR_VOLTS_DC,
98 "desired charging voltage"),
99 CHECK(WORD, BATTERY_STATUS, status, -1,
100 "status"),
101 CHECK(WORD, CYCLE_COUNT, cycle_count, SENSOR_INTEGER,
102 "charge and discharge cycles"),
103 CHECK(WORD, DESIGN_CAPACITY, design_capacity, SENSOR_AMPHOUR,
104 "capacity of new battery"),
105 CHECK(WORD, DESIGN_VOLTAGE, design_voltage, SENSOR_VOLTS_DC,
106 "voltage of new battery"),
107 CHECK(WORD, SERIAL_NUMBER, serial, -1,
108 "serial number"),
109
110 CHECK(BLOCK, MANUFACTURER_NAME, manufacturer, -1,
111 "manufacturer name"),
112 CHECK(BLOCK, DEVICE_NAME, device_name, -1,
113 "battery model number"),
114 CHECK(BLOCK, DEVICE_CHEMISTRY, device_chemistry, -1,
115 "battery chemistry"),
116 #if 0
117 CHECK(WORD, SPECIFICATION_INFO, spec, -1,
118 NULL),
119 CHECK(WORD, MANUFACTURE_DATE, manufacture_date, -1,
120 "date battery was manufactured"),
121 CHECK(BLOCK, MANUFACTURER_DATA, oem_data, -1,
122 "manufacturer-specific data"),
123 #endif
124 };
125
126 extern void acpiec_read(struct acpiec_softc *, uint8_t, int, uint8_t *);
127 extern void acpiec_write(struct acpiec_softc *, uint8_t, int, uint8_t *);
128
129 int acpisbs_match(struct device *, void *, void *);
130 void acpisbs_attach(struct device *, struct device *, void *);
131 int acpisbs_activate(struct device *, int);
132 void acpisbs_setup_sensors(struct acpisbs_softc *);
133 void acpisbs_refresh_sensors(struct acpisbs_softc *);
134 void acpisbs_read(struct acpisbs_softc *);
135 int acpisbs_notify(struct aml_node *, int, void *);
136
137 int acpi_smbus_read(struct acpisbs_softc *, uint8_t, uint8_t, int, void *);
138
139 const struct cfattach acpisbs_ca = {
140 sizeof(struct acpisbs_softc),
141 acpisbs_match,
142 acpisbs_attach,
143 NULL,
144 acpisbs_activate,
145 };
146
147 struct cfdriver acpisbs_cd = {
148 NULL, "acpisbs", DV_DULL
149 };
150
151 const char *acpisbs_hids[] = {
152 ACPI_DEV_SBS,
153 NULL
154 };
155
156 int
acpisbs_match(struct device * parent,void * match,void * aux)157 acpisbs_match(struct device *parent, void *match, void *aux)
158 {
159 struct acpi_attach_args *aa = aux;
160 struct cfdata *cf = match;
161
162 return (acpi_matchhids(aa, acpisbs_hids, cf->cf_driver->cd_name));
163 }
164
165 void
acpisbs_attach(struct device * parent,struct device * self,void * aux)166 acpisbs_attach(struct device *parent, struct device *self, void *aux)
167 {
168 struct acpisbs_softc *sc = (struct acpisbs_softc *)self;
169 struct acpi_attach_args *aa = aux;
170 int64_t sbs, val;
171
172 sc->sc_acpi = (struct acpi_softc *)parent;
173 sc->sc_devnode = aa->aaa_node;
174 sc->sc_batteries_present = 0;
175
176 memset(&sc->sc_battery, 0, sizeof(sc->sc_battery));
177
178 getmicrouptime(&sc->sc_lastpoll);
179
180 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_SBS", 0, NULL, &sbs))
181 return;
182
183 /*
184 * The parent node of the device block containing the _HID must also
185 * have an _EC node, which contains the base address and query value.
186 */
187 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode->parent, "_EC", 0,
188 NULL, &val))
189 return;
190 sc->sc_ec_base = (val >> 8) & 0xff;
191
192 if (!sc->sc_acpi->sc_ec)
193 return;
194 sc->sc_ec = sc->sc_acpi->sc_ec;
195
196 printf(": %s", sc->sc_devnode->name);
197
198 if (sbs > 0)
199 acpisbs_read(sc);
200
201 if (sc->sc_batteries_present) {
202 if (sc->sc_battery.device_name[0])
203 printf(" model \"%s\"", sc->sc_battery.device_name);
204 if (sc->sc_battery.serial)
205 printf(" serial %d", sc->sc_battery.serial);
206 if (sc->sc_battery.device_chemistry[0])
207 printf(" type %s", sc->sc_battery.device_chemistry);
208 if (sc->sc_battery.manufacturer[0])
209 printf(" oem \"%s\"", sc->sc_battery.manufacturer);
210 }
211
212 printf("\n");
213
214 acpisbs_setup_sensors(sc);
215 acpisbs_refresh_sensors(sc);
216
217 /*
218 * Request notification of SCI events on the subsystem itself, but also
219 * periodically poll as a fallback in case those events never arrive.
220 */
221 aml_register_notify(sc->sc_devnode->parent, aa->aaa_dev,
222 acpisbs_notify, sc, ACPIDEV_POLL);
223
224 sc->sc_acpi->sc_havesbs = 1;
225 }
226
227 void
acpisbs_read(struct acpisbs_softc * sc)228 acpisbs_read(struct acpisbs_softc *sc)
229 {
230 int i;
231
232 for (i = 0; i < nitems(acpisbs_battery_checks); i++) {
233 const struct acpisbs_battery_check check =
234 acpisbs_battery_checks[i];
235 void *p = (void *)&sc->sc_battery + check.offset;
236
237 acpi_smbus_read(sc, check.mode, check.command, check.len, p);
238
239 if (check.mode == SMBUS_READ_BLOCK)
240 DPRINTF(("%s: %s: %s\n", sc->sc_dev.dv_xname,
241 check.name, (char *)p));
242 else
243 DPRINTF(("%s: %s: %u\n", sc->sc_dev.dv_xname,
244 check.name, *(uint16_t *)p));
245
246 if (check.command == SMBATT_CMD_BATTERY_MODE) {
247 uint16_t *ival = (uint16_t *)p;
248 if (*ival == 0) {
249 /* battery not present, skip further checks */
250 sc->sc_batteries_present = 0;
251 break;
252 }
253
254 sc->sc_batteries_present = 1;
255
256 if (*ival & SMBATT_BM_CAPACITY_MODE)
257 sc->sc_battery.units = ACPISBS_UNITS_MW;
258 else
259 sc->sc_battery.units = ACPISBS_UNITS_MA;
260 }
261 }
262 }
263
264 void
acpisbs_setup_sensors(struct acpisbs_softc * sc)265 acpisbs_setup_sensors(struct acpisbs_softc *sc)
266 {
267 int i;
268
269 memset(&sc->sc_sensordev, 0, sizeof(sc->sc_sensordev));
270 strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
271 sizeof(sc->sc_sensordev.xname));
272
273 sc->sc_sensors = mallocarray(sizeof(struct ksensor),
274 nitems(acpisbs_battery_checks), M_DEVBUF, M_WAITOK | M_ZERO);
275
276 for (i = 0; i < nitems(acpisbs_battery_checks); i++) {
277 const struct acpisbs_battery_check check =
278 acpisbs_battery_checks[i];
279
280 if (check.sensor_type < 0)
281 continue;
282
283 strlcpy(sc->sc_sensors[i].desc, check.sensor_desc,
284 sizeof(sc->sc_sensors[i].desc));
285
286 if (check.sensor_type == SENSOR_AMPHOUR &&
287 sc->sc_battery.units == ACPISBS_UNITS_MW)
288 /* translate to watt-hours */
289 sc->sc_sensors[i].type = SENSOR_WATTHOUR;
290 else
291 sc->sc_sensors[i].type = check.sensor_type;
292
293 sc->sc_sensors[i].value = 0;
294 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
295 }
296
297 sensordev_install(&sc->sc_sensordev);
298 }
299
300 void
acpisbs_refresh_sensors(struct acpisbs_softc * sc)301 acpisbs_refresh_sensors(struct acpisbs_softc *sc)
302 {
303 int i;
304
305 for (i = 0; i < nitems(acpisbs_battery_checks); i++) {
306 const struct acpisbs_battery_check check =
307 acpisbs_battery_checks[i];
308 void *p = (void *)&sc->sc_battery + check.offset;
309 uint16_t *ival = (uint16_t *)p;
310
311 if (check.sensor_type < 0)
312 continue;
313
314 if (sc->sc_batteries_present) {
315 sc->sc_sensors[i].flags = 0;
316 sc->sc_sensors[i].status = SENSOR_S_OK;
317
318 switch (check.sensor_type) {
319 case SENSOR_AMPS:
320 sc->sc_sensors[i].value = *ival * 100;
321 break;
322
323 case SENSOR_AMPHOUR:
324 case SENSOR_WATTHOUR:
325 sc->sc_sensors[i].value = *ival * 10000;
326 break;
327
328 case SENSOR_PERCENT:
329 sc->sc_sensors[i].value = *ival * 1000;
330 break;
331
332 #if 0
333 case SENSOR_STRING:
334 strlcpy(sc->sc_sensors[i].string, (char *)p,
335 sizeof(sc->sc_sensors[i].string));
336 break;
337 #endif
338 case SENSOR_TEMP:
339 /* .1 degK */
340 sc->sc_sensors[i].value = (*ival * 10000) +
341 273150000;
342 break;
343
344 case SENSOR_VOLTS_DC:
345 sc->sc_sensors[i].value = *ival * 1000;
346 break;
347
348 default:
349 if (*ival == ACPISBS_VALUE_UNKNOWN) {
350 sc->sc_sensors[i].value = 0;
351 sc->sc_sensors[i].status =
352 SENSOR_S_UNKNOWN;
353 sc->sc_sensors[i].flags =
354 SENSOR_FUNKNOWN;
355 } else
356 sc->sc_sensors[i].value = *ival;
357 }
358 } else {
359 sc->sc_sensors[i].value = 0;
360 sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
361 sc->sc_sensors[i].flags = SENSOR_FUNKNOWN;
362 }
363 }
364 }
365
366 int
acpisbs_activate(struct device * self,int act)367 acpisbs_activate(struct device *self, int act)
368 {
369 struct acpisbs_softc *sc = (struct acpisbs_softc *)self;
370
371 switch (act) {
372 case DVACT_WAKEUP:
373 acpisbs_read(sc);
374 acpisbs_refresh_sensors(sc);
375 break;
376 }
377
378 return 0;
379 }
380
381 int
acpisbs_notify(struct aml_node * node,int notify_type,void * arg)382 acpisbs_notify(struct aml_node *node, int notify_type, void *arg)
383 {
384 struct acpisbs_softc *sc = arg;
385 struct timeval diff, now;
386
387 DPRINTF(("%s: %s: %d\n", sc->sc_dev.dv_xname, __func__, notify_type));
388
389 getmicrouptime(&now);
390
391 switch (notify_type) {
392 case 0x00:
393 /* fallback poll */
394 case 0x80:
395 /*
396 * EC SCI will come for every data point, so only run once in a
397 * while
398 */
399 timersub(&now, &sc->sc_lastpoll, &diff);
400 if (diff.tv_sec > ACPISBS_POLL_FREQ) {
401 acpisbs_read(sc);
402 acpisbs_refresh_sensors(sc);
403 acpi_record_event(sc->sc_acpi, APM_POWER_CHANGE);
404 getmicrouptime(&sc->sc_lastpoll);
405 }
406 break;
407 default:
408 break;
409 }
410
411 return 0;
412 }
413
414 int
acpi_smbus_read(struct acpisbs_softc * sc,uint8_t type,uint8_t cmd,int len,void * buf)415 acpi_smbus_read(struct acpisbs_softc *sc, uint8_t type, uint8_t cmd, int len,
416 void *buf)
417 {
418 int j;
419 uint8_t addr = SMBATT_ADDRESS;
420 uint8_t val;
421
422 acpiec_write(sc->sc_ec, sc->sc_ec_base + SMBUS_ADDR, 1, &addr);
423 acpiec_write(sc->sc_ec, sc->sc_ec_base + SMBUS_CMD, 1, &cmd);
424 acpiec_write(sc->sc_ec, sc->sc_ec_base + SMBUS_PRTCL, 1, &type);
425
426 for (j = SMBUS_TIMEOUT; j > 0; j--) {
427 acpiec_read(sc->sc_ec, sc->sc_ec_base + SMBUS_PRTCL, 1, &val);
428 if (val == 0)
429 break;
430 }
431 if (j == 0) {
432 printf("%s: %s: timeout reading 0x%x\n", sc->sc_dev.dv_xname,
433 __func__, addr);
434 return 1;
435 }
436
437 acpiec_read(sc->sc_ec, sc->sc_ec_base + SMBUS_STS, 1, &val);
438 if (val & SMBUS_STS_MASK) {
439 printf("%s: %s: error reading status: 0x%x\n",
440 sc->sc_dev.dv_xname, __func__, addr);
441 return 1;
442 }
443
444 switch (type) {
445 case SMBUS_READ_WORD: {
446 uint8_t word[2];
447 acpiec_read(sc->sc_ec, sc->sc_ec_base + SMBUS_DATA, 2,
448 (uint8_t *)&word);
449
450 *(uint16_t *)buf = (word[1] << 8) | word[0];
451
452 break;
453 }
454 case SMBUS_READ_BLOCK:
455 bzero(buf, len);
456
457 /* find number of bytes to read */
458 acpiec_read(sc->sc_ec, sc->sc_ec_base + SMBUS_BCNT, 1, &val);
459 val &= 0x1f;
460 if (len > val)
461 len = val;
462
463 for (j = 0; j < len; j++) {
464 acpiec_read(sc->sc_ec, sc->sc_ec_base + SMBUS_DATA + j,
465 1, &val);
466 ((char *)buf)[j] = val;
467 }
468 break;
469 default:
470 printf("%s: %s: unknown mode 0x%x\n", sc->sc_dev.dv_xname,
471 __func__, type);
472 return 1;
473 }
474
475 return 0;
476 }
477