xref: /openbsd/sys/dev/acpi/acpisbs.c (revision 6321bc94)
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