xref: /openbsd-src/sys/dev/acpi/acpisbs.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /* $OpenBSD: acpisbs.c,v 1.9 2020/01/27 11:04:18 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 void	acpisbs_setup_sensors(struct acpisbs_softc *);
132 void	acpisbs_refresh_sensors(struct acpisbs_softc *);
133 void	acpisbs_read(struct acpisbs_softc *);
134 int	acpisbs_notify(struct aml_node *, int, void *);
135 
136 int	acpi_smbus_read(struct acpisbs_softc *, uint8_t, uint8_t, int, void *);
137 
138 const struct cfattach acpisbs_ca = {
139 	sizeof(struct acpisbs_softc),
140 	acpisbs_match,
141 	acpisbs_attach,
142 };
143 
144 struct cfdriver acpisbs_cd = {
145 	NULL, "acpisbs", DV_DULL
146 };
147 
148 const char *acpisbs_hids[] = {
149 	ACPI_DEV_SBS,
150 	NULL
151 };
152 
153 int
154 acpisbs_match(struct device *parent, void *match, void *aux)
155 {
156 	struct acpi_attach_args *aa = aux;
157 	struct cfdata *cf = match;
158 
159 	return (acpi_matchhids(aa, acpisbs_hids, cf->cf_driver->cd_name));
160 }
161 
162 void
163 acpisbs_attach(struct device *parent, struct device *self, void *aux)
164 {
165 	struct acpisbs_softc *sc = (struct acpisbs_softc *)self;
166 	struct acpi_attach_args *aa = aux;
167 	int64_t sbs, val;
168 
169 	sc->sc_acpi = (struct acpi_softc *)parent;
170 	sc->sc_devnode = aa->aaa_node;
171 	sc->sc_batteries_present = 0;
172 
173 	memset(&sc->sc_battery, 0, sizeof(sc->sc_battery));
174 
175 	getmicrouptime(&sc->sc_lastpoll);
176 
177 	if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_SBS", 0, NULL, &sbs))
178 		return;
179 
180 	/*
181 	 * The parent node of the device block containing the _HID must also
182 	 * have an _EC node, which contains the base address and query value.
183 	 */
184 	if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode->parent, "_EC", 0,
185 	    NULL, &val))
186 		return;
187 	sc->sc_ec_base = (val >> 8) & 0xff;
188 
189 	if (!sc->sc_acpi->sc_ec)
190 		return;
191 	sc->sc_ec = sc->sc_acpi->sc_ec;
192 
193 	printf(": %s", sc->sc_devnode->name);
194 
195 	if (sbs > 0)
196 		acpisbs_read(sc);
197 
198 	if (sc->sc_batteries_present) {
199 		if (sc->sc_battery.device_name[0])
200 			printf(" model \"%s\"", sc->sc_battery.device_name);
201 		if (sc->sc_battery.serial)
202 			printf(" serial %d", sc->sc_battery.serial);
203 		if (sc->sc_battery.device_chemistry[0])
204 			printf(" type %s", sc->sc_battery.device_chemistry);
205 		if (sc->sc_battery.manufacturer[0])
206 			printf(" oem \"%s\"", sc->sc_battery.manufacturer);
207 	}
208 
209 	printf("\n");
210 
211 	acpisbs_setup_sensors(sc);
212 	acpisbs_refresh_sensors(sc);
213 
214 	/*
215 	 * Request notification of SCI events on the subsystem itself, but also
216 	 * periodically poll as a fallback in case those events never arrive.
217 	 */
218 	aml_register_notify(sc->sc_devnode->parent, aa->aaa_dev,
219 	    acpisbs_notify, sc, ACPIDEV_POLL);
220 
221 	sc->sc_acpi->sc_havesbs = 1;
222 }
223 
224 void
225 acpisbs_read(struct acpisbs_softc *sc)
226 {
227 	int i;
228 
229 	for (i = 0; i < nitems(acpisbs_battery_checks); i++) {
230 		struct acpisbs_battery_check check = acpisbs_battery_checks[i];
231 		void *p = (void *)&sc->sc_battery + check.offset;
232 
233 		acpi_smbus_read(sc, check.mode, check.command, check.len, p);
234 
235 		if (check.mode == SMBUS_READ_BLOCK)
236 			DPRINTF(("%s: %s: %s\n", sc->sc_dev.dv_xname,
237 			    check.name, (char *)p));
238 		else
239 			DPRINTF(("%s: %s: %u\n", sc->sc_dev.dv_xname,
240 			    check.name, *(uint16_t *)p));
241 
242 		if (check.command == SMBATT_CMD_BATTERY_MODE) {
243 			uint16_t *ival = (uint16_t *)p;
244 			if (*ival == 0) {
245 				/* battery not present, skip further checks */
246 				sc->sc_batteries_present = 0;
247 				break;
248 			}
249 
250 			sc->sc_batteries_present = 1;
251 
252 			if (*ival & SMBATT_BM_CAPACITY_MODE)
253 				sc->sc_battery.units = ACPISBS_UNITS_MW;
254 			else
255 				sc->sc_battery.units = ACPISBS_UNITS_MA;
256 		}
257 	}
258 }
259 
260 void
261 acpisbs_setup_sensors(struct acpisbs_softc *sc)
262 {
263 	int i;
264 
265 	memset(&sc->sc_sensordev, 0, sizeof(sc->sc_sensordev));
266 	strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
267 	    sizeof(sc->sc_sensordev.xname));
268 
269 	sc->sc_sensors = mallocarray(sizeof(struct ksensor),
270 	    nitems(acpisbs_battery_checks), M_DEVBUF, M_WAITOK | M_ZERO);
271 
272 	for (i = 0; i < nitems(acpisbs_battery_checks); i++) {
273 		struct acpisbs_battery_check check = acpisbs_battery_checks[i];
274 
275 		if (check.sensor_type < 0)
276 			continue;
277 
278 		strlcpy(sc->sc_sensors[i].desc, check.sensor_desc,
279 		    sizeof(sc->sc_sensors[i].desc));
280 
281 		if (check.sensor_type == SENSOR_AMPHOUR &&
282 		    sc->sc_battery.units == ACPISBS_UNITS_MW)
283 			/* translate to watt-hours */
284 			sc->sc_sensors[i].type = SENSOR_WATTHOUR;
285 		else
286 			sc->sc_sensors[i].type = check.sensor_type;
287 
288 		sc->sc_sensors[i].value = 0;
289 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
290 	}
291 
292 	sensordev_install(&sc->sc_sensordev);
293 }
294 
295 void
296 acpisbs_refresh_sensors(struct acpisbs_softc *sc)
297 {
298 	int i;
299 
300 	for (i = 0; i < nitems(acpisbs_battery_checks); i++) {
301 		struct acpisbs_battery_check check = acpisbs_battery_checks[i];
302 		void *p = (void *)&sc->sc_battery + check.offset;
303 		uint16_t *ival = (uint16_t *)p;
304 
305 		if (check.sensor_type < 0)
306 			continue;
307 
308 		if (sc->sc_batteries_present) {
309 			sc->sc_sensors[i].flags = 0;
310 			sc->sc_sensors[i].status = SENSOR_S_OK;
311 
312 			switch (check.sensor_type) {
313 			case SENSOR_AMPS:
314 				sc->sc_sensors[i].value = *ival * 100;
315 				break;
316 
317 			case SENSOR_AMPHOUR:
318 			case SENSOR_WATTHOUR:
319 				sc->sc_sensors[i].value = *ival * 10000;
320 				break;
321 
322 			case SENSOR_PERCENT:
323 				sc->sc_sensors[i].value = *ival * 1000;
324 				break;
325 
326 #if 0
327 			case SENSOR_STRING:
328 				strlcpy(sc->sc_sensors[i].string, (char *)p,
329 				    sizeof(sc->sc_sensors[i].string));
330 				break;
331 #endif
332 			case SENSOR_TEMP:
333 				/* .1 degK */
334 				sc->sc_sensors[i].value = (*ival * 10000) +
335 				    273150000;
336 				break;
337 
338 			case SENSOR_VOLTS_DC:
339 				sc->sc_sensors[i].value = *ival * 1000;
340 				break;
341 
342 			default:
343 				if (*ival == ACPISBS_VALUE_UNKNOWN) {
344 					sc->sc_sensors[i].value = 0;
345 					sc->sc_sensors[i].status =
346 					    SENSOR_S_UNKNOWN;
347 					sc->sc_sensors[i].flags =
348 					    SENSOR_FUNKNOWN;
349 				} else
350 					sc->sc_sensors[i].value = *ival;
351 			}
352 		} else {
353 			sc->sc_sensors[i].value = 0;
354 			sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
355 			sc->sc_sensors[i].flags = SENSOR_FUNKNOWN;
356 		}
357 	}
358 }
359 
360 int
361 acpisbs_notify(struct aml_node *node, int notify_type, void *arg)
362 {
363 	struct acpisbs_softc *sc = arg;
364 	struct timeval diff, now;
365 
366 	DPRINTF(("%s: %s: %d\n", sc->sc_dev.dv_xname, __func__, notify_type));
367 
368 	getmicrouptime(&now);
369 
370 	switch (notify_type) {
371 	case 0x00:
372 		/* fallback poll */
373 	case 0x80:
374 		/*
375 		 * EC SCI will come for every data point, so only run once in a
376 		 * while
377 		 */
378 		timersub(&now, &sc->sc_lastpoll, &diff);
379 		if (diff.tv_sec > ACPISBS_POLL_FREQ) {
380 			acpisbs_read(sc);
381 			acpisbs_refresh_sensors(sc);
382 			acpi_record_event(sc->sc_acpi, APM_POWER_CHANGE);
383 			getmicrouptime(&sc->sc_lastpoll);
384 		}
385 		break;
386 	default:
387 		break;
388 	}
389 
390 	return 0;
391 }
392 
393 int
394 acpi_smbus_read(struct acpisbs_softc *sc, uint8_t type, uint8_t cmd, int len,
395     void *buf)
396 {
397 	int j;
398 	uint8_t addr = SMBATT_ADDRESS;
399 	uint8_t val;
400 
401 	acpiec_write(sc->sc_ec, sc->sc_ec_base + SMBUS_ADDR, 1, &addr);
402 	acpiec_write(sc->sc_ec, sc->sc_ec_base + SMBUS_CMD, 1, &cmd);
403 	acpiec_write(sc->sc_ec, sc->sc_ec_base + SMBUS_PRTCL, 1, &type);
404 
405 	for (j = SMBUS_TIMEOUT; j > 0; j--) {
406 		acpiec_read(sc->sc_ec, sc->sc_ec_base + SMBUS_PRTCL, 1, &val);
407 		if (val == 0)
408 			break;
409 	}
410 	if (j == 0) {
411 		printf("%s: %s: timeout reading 0x%x\n", sc->sc_dev.dv_xname,
412 		    __func__, addr);
413 		return 1;
414 	}
415 
416 	acpiec_read(sc->sc_ec, sc->sc_ec_base + SMBUS_STS, 1, &val);
417 	if (val & SMBUS_STS_MASK) {
418 		printf("%s: %s: error reading status: 0x%x\n",
419 		    sc->sc_dev.dv_xname, __func__, addr);
420 		return 1;
421 	}
422 
423 	switch (type) {
424         case SMBUS_READ_WORD: {
425 		uint8_t word[2];
426 		acpiec_read(sc->sc_ec, sc->sc_ec_base + SMBUS_DATA, 2,
427 		    (uint8_t *)&word);
428 
429 		*(uint16_t *)buf = (word[1] << 8) | word[0];
430 
431 		break;
432 	}
433 	case SMBUS_READ_BLOCK:
434 		bzero(buf, len);
435 
436 		/* find number of bytes to read */
437 		acpiec_read(sc->sc_ec, sc->sc_ec_base + SMBUS_BCNT, 1, &val);
438 		val &= 0x1f;
439 		if (len > val)
440 			len = val;
441 
442 		for (j = 0; j < len; j++) {
443 			acpiec_read(sc->sc_ec, sc->sc_ec_base + SMBUS_DATA + j,
444 			    1, &val);
445 			((char *)buf)[j] = val;
446 		}
447 		break;
448 	default:
449 		printf("%s: %s: unknown mode 0x%x\n", sc->sc_dev.dv_xname,
450 		    __func__, type);
451 		return 1;
452 	}
453 
454 	return 0;
455 }
456