xref: /openbsd/sys/dev/acpi/acpisbs.c (revision e5dd7070)
1 /* $OpenBSD: acpisbs.c,v 1.10 2020/06/10 22:26:40 jca 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 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
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
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
228 acpisbs_read(struct acpisbs_softc *sc)
229 {
230 	int i;
231 
232 	for (i = 0; i < nitems(acpisbs_battery_checks); i++) {
233 		struct acpisbs_battery_check check = acpisbs_battery_checks[i];
234 		void *p = (void *)&sc->sc_battery + check.offset;
235 
236 		acpi_smbus_read(sc, check.mode, check.command, check.len, p);
237 
238 		if (check.mode == SMBUS_READ_BLOCK)
239 			DPRINTF(("%s: %s: %s\n", sc->sc_dev.dv_xname,
240 			    check.name, (char *)p));
241 		else
242 			DPRINTF(("%s: %s: %u\n", sc->sc_dev.dv_xname,
243 			    check.name, *(uint16_t *)p));
244 
245 		if (check.command == SMBATT_CMD_BATTERY_MODE) {
246 			uint16_t *ival = (uint16_t *)p;
247 			if (*ival == 0) {
248 				/* battery not present, skip further checks */
249 				sc->sc_batteries_present = 0;
250 				break;
251 			}
252 
253 			sc->sc_batteries_present = 1;
254 
255 			if (*ival & SMBATT_BM_CAPACITY_MODE)
256 				sc->sc_battery.units = ACPISBS_UNITS_MW;
257 			else
258 				sc->sc_battery.units = ACPISBS_UNITS_MA;
259 		}
260 	}
261 }
262 
263 void
264 acpisbs_setup_sensors(struct acpisbs_softc *sc)
265 {
266 	int i;
267 
268 	memset(&sc->sc_sensordev, 0, sizeof(sc->sc_sensordev));
269 	strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
270 	    sizeof(sc->sc_sensordev.xname));
271 
272 	sc->sc_sensors = mallocarray(sizeof(struct ksensor),
273 	    nitems(acpisbs_battery_checks), M_DEVBUF, M_WAITOK | M_ZERO);
274 
275 	for (i = 0; i < nitems(acpisbs_battery_checks); i++) {
276 		struct acpisbs_battery_check check = acpisbs_battery_checks[i];
277 
278 		if (check.sensor_type < 0)
279 			continue;
280 
281 		strlcpy(sc->sc_sensors[i].desc, check.sensor_desc,
282 		    sizeof(sc->sc_sensors[i].desc));
283 
284 		if (check.sensor_type == SENSOR_AMPHOUR &&
285 		    sc->sc_battery.units == ACPISBS_UNITS_MW)
286 			/* translate to watt-hours */
287 			sc->sc_sensors[i].type = SENSOR_WATTHOUR;
288 		else
289 			sc->sc_sensors[i].type = check.sensor_type;
290 
291 		sc->sc_sensors[i].value = 0;
292 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
293 	}
294 
295 	sensordev_install(&sc->sc_sensordev);
296 }
297 
298 void
299 acpisbs_refresh_sensors(struct acpisbs_softc *sc)
300 {
301 	int i;
302 
303 	for (i = 0; i < nitems(acpisbs_battery_checks); i++) {
304 		struct acpisbs_battery_check check = acpisbs_battery_checks[i];
305 		void *p = (void *)&sc->sc_battery + check.offset;
306 		uint16_t *ival = (uint16_t *)p;
307 
308 		if (check.sensor_type < 0)
309 			continue;
310 
311 		if (sc->sc_batteries_present) {
312 			sc->sc_sensors[i].flags = 0;
313 			sc->sc_sensors[i].status = SENSOR_S_OK;
314 
315 			switch (check.sensor_type) {
316 			case SENSOR_AMPS:
317 				sc->sc_sensors[i].value = *ival * 100;
318 				break;
319 
320 			case SENSOR_AMPHOUR:
321 			case SENSOR_WATTHOUR:
322 				sc->sc_sensors[i].value = *ival * 10000;
323 				break;
324 
325 			case SENSOR_PERCENT:
326 				sc->sc_sensors[i].value = *ival * 1000;
327 				break;
328 
329 #if 0
330 			case SENSOR_STRING:
331 				strlcpy(sc->sc_sensors[i].string, (char *)p,
332 				    sizeof(sc->sc_sensors[i].string));
333 				break;
334 #endif
335 			case SENSOR_TEMP:
336 				/* .1 degK */
337 				sc->sc_sensors[i].value = (*ival * 10000) +
338 				    273150000;
339 				break;
340 
341 			case SENSOR_VOLTS_DC:
342 				sc->sc_sensors[i].value = *ival * 1000;
343 				break;
344 
345 			default:
346 				if (*ival == ACPISBS_VALUE_UNKNOWN) {
347 					sc->sc_sensors[i].value = 0;
348 					sc->sc_sensors[i].status =
349 					    SENSOR_S_UNKNOWN;
350 					sc->sc_sensors[i].flags =
351 					    SENSOR_FUNKNOWN;
352 				} else
353 					sc->sc_sensors[i].value = *ival;
354 			}
355 		} else {
356 			sc->sc_sensors[i].value = 0;
357 			sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
358 			sc->sc_sensors[i].flags = SENSOR_FUNKNOWN;
359 		}
360 	}
361 }
362 
363 int
364 acpisbs_activate(struct device *self, int act)
365 {
366 	struct acpisbs_softc *sc = (struct acpisbs_softc *)self;
367 
368 	switch (act) {
369 	case DVACT_WAKEUP:
370 		acpisbs_read(sc);
371 		acpisbs_refresh_sensors(sc);
372 		break;
373 	}
374 
375 	return 0;
376 }
377 
378 int
379 acpisbs_notify(struct aml_node *node, int notify_type, void *arg)
380 {
381 	struct acpisbs_softc *sc = arg;
382 	struct timeval diff, now;
383 
384 	DPRINTF(("%s: %s: %d\n", sc->sc_dev.dv_xname, __func__, notify_type));
385 
386 	getmicrouptime(&now);
387 
388 	switch (notify_type) {
389 	case 0x00:
390 		/* fallback poll */
391 	case 0x80:
392 		/*
393 		 * EC SCI will come for every data point, so only run once in a
394 		 * while
395 		 */
396 		timersub(&now, &sc->sc_lastpoll, &diff);
397 		if (diff.tv_sec > ACPISBS_POLL_FREQ) {
398 			acpisbs_read(sc);
399 			acpisbs_refresh_sensors(sc);
400 			acpi_record_event(sc->sc_acpi, APM_POWER_CHANGE);
401 			getmicrouptime(&sc->sc_lastpoll);
402 		}
403 		break;
404 	default:
405 		break;
406 	}
407 
408 	return 0;
409 }
410 
411 int
412 acpi_smbus_read(struct acpisbs_softc *sc, uint8_t type, uint8_t cmd, int len,
413     void *buf)
414 {
415 	int j;
416 	uint8_t addr = SMBATT_ADDRESS;
417 	uint8_t val;
418 
419 	acpiec_write(sc->sc_ec, sc->sc_ec_base + SMBUS_ADDR, 1, &addr);
420 	acpiec_write(sc->sc_ec, sc->sc_ec_base + SMBUS_CMD, 1, &cmd);
421 	acpiec_write(sc->sc_ec, sc->sc_ec_base + SMBUS_PRTCL, 1, &type);
422 
423 	for (j = SMBUS_TIMEOUT; j > 0; j--) {
424 		acpiec_read(sc->sc_ec, sc->sc_ec_base + SMBUS_PRTCL, 1, &val);
425 		if (val == 0)
426 			break;
427 	}
428 	if (j == 0) {
429 		printf("%s: %s: timeout reading 0x%x\n", sc->sc_dev.dv_xname,
430 		    __func__, addr);
431 		return 1;
432 	}
433 
434 	acpiec_read(sc->sc_ec, sc->sc_ec_base + SMBUS_STS, 1, &val);
435 	if (val & SMBUS_STS_MASK) {
436 		printf("%s: %s: error reading status: 0x%x\n",
437 		    sc->sc_dev.dv_xname, __func__, addr);
438 		return 1;
439 	}
440 
441 	switch (type) {
442         case SMBUS_READ_WORD: {
443 		uint8_t word[2];
444 		acpiec_read(sc->sc_ec, sc->sc_ec_base + SMBUS_DATA, 2,
445 		    (uint8_t *)&word);
446 
447 		*(uint16_t *)buf = (word[1] << 8) | word[0];
448 
449 		break;
450 	}
451 	case SMBUS_READ_BLOCK:
452 		bzero(buf, len);
453 
454 		/* find number of bytes to read */
455 		acpiec_read(sc->sc_ec, sc->sc_ec_base + SMBUS_BCNT, 1, &val);
456 		val &= 0x1f;
457 		if (len > val)
458 			len = val;
459 
460 		for (j = 0; j < len; j++) {
461 			acpiec_read(sc->sc_ec, sc->sc_ec_base + SMBUS_DATA + j,
462 			    1, &val);
463 			((char *)buf)[j] = val;
464 		}
465 		break;
466 	default:
467 		printf("%s: %s: unknown mode 0x%x\n", sc->sc_dev.dv_xname,
468 		    __func__, type);
469 		return 1;
470 	}
471 
472 	return 0;
473 }
474