xref: /freebsd/sys/dev/iicbus/acpi_iicbus.c (revision 5e3190f700637fcfc1a52daeaa4a031fdd2557c7)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2019-2020 Vladimir Kondratyev <wulf@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 #include <sys/param.h>
30 #include <sys/bus.h>
31 #include <sys/endian.h>
32 #include <sys/kernel.h>
33 #include <sys/malloc.h>
34 #include <sys/module.h>
35 #include <sys/rman.h>
36 #include <sys/sbuf.h>
37 
38 #include <machine/resource.h>
39 
40 #include <contrib/dev/acpica/include/acpi.h>
41 #include <contrib/dev/acpica/include/accommon.h>
42 #include <contrib/dev/acpica/include/amlcode.h>
43 #include <dev/acpica/acpivar.h>
44 
45 #include <dev/iicbus/iiconf.h>
46 #include <dev/iicbus/iicbus.h>
47 
48 #define	ACPI_IICBUS_LOCAL_BUFSIZE	32	/* Fits max SMBUS block size */
49 
50 /*
51  * Make a copy of ACPI_RESOURCE_I2C_SERIALBUS type and replace "pointer to ACPI
52  * object name string" field with pointer to ACPI object itself.
53  * This saves us extra strdup()/free() pair on acpi_iicbus_get_i2cres call.
54  */
55 typedef	ACPI_RESOURCE_I2C_SERIALBUS	ACPI_IICBUS_RESOURCE_I2C_SERIALBUS;
56 #define	ResourceSource_Handle	ResourceSource.StringPtr
57 
58 /* Hooks for the ACPI CA debugging infrastructure. */
59 #define	_COMPONENT	ACPI_BUS
60 ACPI_MODULE_NAME("IIC")
61 
62 struct gsb_buffer {
63 	UINT8 status;
64 	UINT8 len;
65 	UINT8 data[];
66 } __packed;
67 
68 struct acpi_iicbus_softc {
69 	struct iicbus_softc	super_sc;
70 	ACPI_CONNECTION_INFO	space_handler_info;
71 	bool			space_handler_installed;
72 };
73 
74 struct acpi_iicbus_ivars {
75 	struct iicbus_ivar	super_ivar;
76 	ACPI_HANDLE		handle;
77 };
78 
79 static int install_space_handler = 0;
80 TUNABLE_INT("hw.iicbus.enable_acpi_space_handler", &install_space_handler);
81 
82 static inline bool
83 acpi_resource_is_i2c_serialbus(ACPI_RESOURCE *res)
84 {
85 
86 	return (res->Type == ACPI_RESOURCE_TYPE_SERIAL_BUS &&
87 	    res->Data.CommonSerialBus.Type == ACPI_RESOURCE_SERIAL_TYPE_I2C);
88 }
89 
90 /*
91  * IICBUS Address space handler
92  */
93 static int
94 acpi_iicbus_sendb(device_t dev, u_char slave, char byte)
95 {
96 	struct iic_msg msgs[] = {
97 	    { slave, IIC_M_WR, 1, &byte },
98 	};
99 
100 	return (iicbus_transfer(dev, msgs, nitems(msgs)));
101 }
102 
103 static int
104 acpi_iicbus_recvb(device_t dev, u_char slave, char *byte)
105 {
106 	char buf;
107 	struct iic_msg msgs[] = {
108 	    { slave, IIC_M_RD, 1, &buf },
109 	};
110 	int error;
111 
112 	error = iicbus_transfer(dev, msgs, nitems(msgs));
113 	if (error == 0)
114 		*byte = buf;
115 
116 	return (error);
117 }
118 
119 static int
120 acpi_iicbus_write(device_t dev, u_char slave, char cmd, void *buf,
121     uint16_t buflen)
122 {
123 	struct iic_msg msgs[] = {
124 	    { slave, IIC_M_WR | IIC_M_NOSTOP, 1, &cmd },
125 	    { slave, IIC_M_WR | IIC_M_NOSTART, buflen, buf },
126 	};
127 
128 	return (iicbus_transfer(dev, msgs, nitems(msgs)));
129 }
130 
131 static int
132 acpi_iicbus_read(device_t dev, u_char slave, char cmd, void *buf,
133     uint16_t buflen)
134 {
135 	uint8_t local_buffer[ACPI_IICBUS_LOCAL_BUFSIZE];
136 	struct iic_msg msgs[] = {
137 	    { slave, IIC_M_WR | IIC_M_NOSTOP, 1, &cmd },
138 	    { slave, IIC_M_RD, buflen, NULL },
139 	};
140 	int error;
141 
142 	if (buflen <= sizeof(local_buffer))
143 		msgs[1].buf = local_buffer;
144 	else
145 		msgs[1].buf = malloc(buflen, M_DEVBUF, M_WAITOK);
146 	error = iicbus_transfer(dev, msgs, nitems(msgs));
147 	if (error == 0)
148 		memcpy(buf, msgs[1].buf, buflen);
149 	if (msgs[1].buf != local_buffer)
150 		free(msgs[1].buf, M_DEVBUF);
151 
152 	return (error);
153 }
154 
155 static int
156 acpi_iicbus_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
157 {
158 	uint8_t bytes[2] = { cmd, count };
159 	struct iic_msg msgs[] = {
160 	    { slave, IIC_M_WR | IIC_M_NOSTOP, nitems(bytes), bytes },
161 	    { slave, IIC_M_WR | IIC_M_NOSTART, count, buf },
162 	};
163 
164 	if (count == 0)
165 		return (errno2iic(EINVAL));
166 
167 	return (iicbus_transfer(dev, msgs, nitems(msgs)));
168 }
169 
170 static int
171 acpi_iicbus_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
172 {
173 	uint8_t local_buffer[ACPI_IICBUS_LOCAL_BUFSIZE];
174 	u_char len;
175 	struct iic_msg msgs[] = {
176 	    { slave, IIC_M_WR | IIC_M_NOSTOP, 1, &cmd },
177 	    { slave, IIC_M_RD | IIC_M_NOSTOP, 1, &len },
178 	};
179 	struct iic_msg block_msg[] = {
180 	    { slave, IIC_M_RD | IIC_M_NOSTART, 0, NULL },
181 	};
182 	device_t parent = device_get_parent(dev);
183 	int error;
184 
185 	/* Have to do this because the command is split in two transfers. */
186 	error = iicbus_request_bus(parent, dev, IIC_WAIT);
187 	if (error == 0)
188 		error = iicbus_transfer(dev, msgs, nitems(msgs));
189 	if (error == 0) {
190 		/*
191 		 * If the slave offers an empty reply,
192 		 * read one byte to generate the stop or abort.
193 		 */
194 		if (len == 0)
195 			block_msg[0].len = 1;
196 		else
197 			block_msg[0].len = len;
198 		if (len <= sizeof(local_buffer))
199 			block_msg[0].buf = local_buffer;
200 		else
201 			block_msg[0].buf = malloc(len, M_DEVBUF, M_WAITOK);
202 		error = iicbus_transfer(dev, block_msg, nitems(block_msg));
203 		if (len == 0)
204 			error = errno2iic(EBADMSG);
205 		if (error == 0) {
206 			*count = len;
207 			memcpy(buf, block_msg[0].buf, len);
208 		}
209 		if (block_msg[0].buf != local_buffer)
210 			free(block_msg[0].buf, M_DEVBUF);
211 	}
212 	(void)iicbus_release_bus(parent, dev);
213 	return (error);
214 }
215 
216 static ACPI_STATUS
217 acpi_iicbus_space_handler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address,
218     UINT32 BitWidth, UINT64 *Value, void *HandlerContext, void *RegionContext)
219 {
220 	struct gsb_buffer *gsb;
221 	struct acpi_iicbus_softc *sc;
222 	device_t dev;
223 	ACPI_CONNECTION_INFO *info;
224 	ACPI_RESOURCE_I2C_SERIALBUS *sb;
225 	ACPI_RESOURCE *res;
226 	ACPI_STATUS s;
227 	int val;
228 
229 	gsb = (struct gsb_buffer *)Value;
230 	if (gsb == NULL)
231 		return (AE_BAD_PARAMETER);
232 
233 	info = HandlerContext;
234 	s = AcpiBufferToResource(info->Connection, info->Length, &res);
235 	if (ACPI_FAILURE(s))
236 		return (s);
237 
238 	if (!acpi_resource_is_i2c_serialbus(res)) {
239 		s = AE_BAD_PARAMETER;
240 		goto err;
241 	}
242 
243 	sb = &res->Data.I2cSerialBus;
244 
245 	/* XXX Ignore 10bit addressing for now */
246 	if (sb->AccessMode == ACPI_I2C_10BIT_MODE) {
247 		s = AE_BAD_PARAMETER;
248 		goto err;
249 	}
250 
251 #define	AML_FIELD_ATTRIB_MASK		0x0F
252 #define	AML_FIELD_ATTRIO(attr, io)	(((attr) << 16) | (io))
253 
254 	Function &= AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_MASK, ACPI_IO_MASK);
255 	sc = __containerof(info, struct acpi_iicbus_softc, space_handler_info);
256 	dev = sc->super_sc.dev;
257 
258 	switch (Function) {
259 	case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_SEND_RECEIVE, ACPI_READ):
260 		val = acpi_iicbus_recvb(dev, sb->SlaveAddress, gsb->data);
261 		break;
262 
263 	case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_SEND_RECEIVE, ACPI_WRITE):
264 		val = acpi_iicbus_sendb(dev, sb->SlaveAddress, gsb->data[0]);
265 		break;
266 
267 	case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTE, ACPI_READ):
268 		val = acpi_iicbus_read(dev, sb->SlaveAddress, Address,
269 		    gsb->data, 1);
270 		break;
271 
272 	case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTE, ACPI_WRITE):
273 		val = acpi_iicbus_write(dev, sb->SlaveAddress, Address,
274 		    gsb->data, 1);
275 		break;
276 
277 	case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_WORD, ACPI_READ):
278 		val = acpi_iicbus_read(dev, sb->SlaveAddress, Address,
279 		    gsb->data, 2);
280 		break;
281 
282 	case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_WORD, ACPI_WRITE):
283 		val = acpi_iicbus_write(dev, sb->SlaveAddress, Address,
284 		    gsb->data, 2);
285 		break;
286 
287 	case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BLOCK, ACPI_READ):
288 		val = acpi_iicbus_bread(dev, sb->SlaveAddress, Address,
289 		    &gsb->len, gsb->data);
290 		break;
291 
292 	case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BLOCK, ACPI_WRITE):
293 		val = acpi_iicbus_bwrite(dev, sb->SlaveAddress, Address,
294 		    gsb->len, gsb->data);
295 		break;
296 
297 	case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTES, ACPI_READ):
298 		val = acpi_iicbus_read(dev, sb->SlaveAddress, Address,
299 		    gsb->data, info->AccessLength);
300 		break;
301 
302 	case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTES, ACPI_WRITE):
303 		val = acpi_iicbus_write(dev, sb->SlaveAddress, Address,
304 		    gsb->data, info->AccessLength);
305 		break;
306 
307 	default:
308 		device_printf(dev, "protocol(0x%04x) is not supported.\n",
309 		    Function);
310 		s = AE_BAD_PARAMETER;
311 		goto err;
312 	}
313 
314 	gsb->status = val;
315 
316 err:
317 	ACPI_FREE(res);
318 
319 	return (s);
320 }
321 
322 static int
323 acpi_iicbus_install_address_space_handler(struct acpi_iicbus_softc *sc)
324 {
325 	ACPI_HANDLE handle;
326 	ACPI_STATUS s;
327 
328 	handle = acpi_get_handle(device_get_parent(sc->super_sc.dev));
329 	s = AcpiInstallAddressSpaceHandler(handle, ACPI_ADR_SPACE_GSBUS,
330 	    &acpi_iicbus_space_handler, NULL, &sc->space_handler_info);
331 	if (ACPI_FAILURE(s)) {
332 		device_printf(sc->super_sc.dev,
333 		    "Failed to install GSBUS Address Space Handler in ACPI\n");
334 		return (ENXIO);
335 	}
336 
337 	return (0);
338 }
339 
340 static int
341 acpi_iicbus_remove_address_space_handler(struct acpi_iicbus_softc *sc)
342 {
343 	ACPI_HANDLE handle;
344 	ACPI_STATUS s;
345 
346 	handle = acpi_get_handle(device_get_parent(sc->super_sc.dev));
347 	s = AcpiRemoveAddressSpaceHandler(handle, ACPI_ADR_SPACE_GSBUS,
348 	    &acpi_iicbus_space_handler);
349 	if (ACPI_FAILURE(s)) {
350 		device_printf(sc->super_sc.dev,
351 		    "Failed to remove GSBUS Address Space Handler from ACPI\n");
352 		return (ENXIO);
353 	}
354 
355 	return (0);
356 }
357 
358 static ACPI_STATUS
359 acpi_iicbus_get_i2cres_cb(ACPI_RESOURCE *res, void *context)
360 {
361 	ACPI_IICBUS_RESOURCE_I2C_SERIALBUS *sb = context;
362 	ACPI_STATUS status;
363 	ACPI_HANDLE handle;
364 
365 	if (acpi_resource_is_i2c_serialbus(res)) {
366 		status = AcpiGetHandle(ACPI_ROOT_OBJECT,
367 		    res->Data.I2cSerialBus.ResourceSource.StringPtr, &handle);
368 		if (ACPI_FAILURE(status))
369 			return (status);
370 		memcpy(sb, &res->Data.I2cSerialBus,
371 		    sizeof(ACPI_IICBUS_RESOURCE_I2C_SERIALBUS));
372 		/*
373 		 * replace "pointer to ACPI object name string" field
374 		 * with pointer to ACPI object itself.
375 		 */
376 		sb->ResourceSource_Handle = handle;
377 		return (AE_CTRL_TERMINATE);
378 	} else if (res->Type == ACPI_RESOURCE_TYPE_END_TAG)
379 		return (AE_NOT_FOUND);
380 
381 	return (AE_OK);
382 }
383 
384 static ACPI_STATUS
385 acpi_iicbus_get_i2cres(ACPI_HANDLE handle, ACPI_RESOURCE_I2C_SERIALBUS *sb)
386 {
387 
388 	return (AcpiWalkResources(handle, "_CRS",
389 	    acpi_iicbus_get_i2cres_cb, sb));
390 }
391 
392 static ACPI_STATUS
393 acpi_iicbus_parse_resources_cb(ACPI_RESOURCE *res, void *context)
394 {
395 	device_t dev = context;
396 	struct iicbus_ivar *super_devi = device_get_ivars(dev);
397 	struct resource_list *rl = &super_devi->rl;
398 	int irq, gpio_pin;
399 
400 	switch(res->Type) {
401 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
402 		if (res->Data.ExtendedIrq.InterruptCount > 0) {
403 			irq = res->Data.ExtendedIrq.Interrupts[0];
404 			if (bootverbose)
405 				printf("  IRQ:               %d\n", irq);
406 			resource_list_add_next(rl, SYS_RES_IRQ, irq, irq, 1);
407 			return (AE_CTRL_TERMINATE);
408 		}
409 		break;
410 	case ACPI_RESOURCE_TYPE_GPIO:
411 		if (res->Data.Gpio.ConnectionType ==
412 		    ACPI_RESOURCE_GPIO_TYPE_INT) {
413 			/* Not supported by FreeBSD yet */
414 			gpio_pin = res->Data.Gpio.PinTable[0];
415 			if (bootverbose)
416 				printf("  GPIO IRQ pin:      %d\n", gpio_pin);
417 			return (AE_CTRL_TERMINATE);
418 		}
419 		break;
420 	default:
421 		break;
422 	}
423 
424 	return (AE_OK);
425 }
426 
427 static ACPI_STATUS
428 acpi_iicbus_parse_resources(ACPI_HANDLE handle, device_t dev)
429 {
430 
431 	return (AcpiWalkResources(handle, "_CRS",
432 	    acpi_iicbus_parse_resources_cb, dev));
433 }
434 
435 static void
436 acpi_iicbus_dump_res(device_t dev, ACPI_IICBUS_RESOURCE_I2C_SERIALBUS *sb)
437 {
438 	device_printf(dev, "found ACPI child\n");
439 	printf("  SlaveAddress:      0x%04hx\n", sb->SlaveAddress);
440 	printf("  ConnectionSpeed:   %uHz\n", sb->ConnectionSpeed);
441 	printf("  SlaveMode:         %s\n",
442 	    sb->SlaveMode == ACPI_CONTROLLER_INITIATED ?
443 	    "ControllerInitiated" : "DeviceInitiated");
444 	printf("  AddressingMode:    %uBit\n", sb->AccessMode == 0 ? 7 : 10);
445 	printf("  ConnectionSharing: %s\n", sb->ConnectionSharing == 0 ?
446 	    "Exclusive" : "Shared");
447 }
448 
449 static device_t
450 acpi_iicbus_add_child(device_t dev, u_int order, const char *name, int unit)
451 {
452 
453 	return (iicbus_add_child_common(
454 	    dev, order, name, unit, sizeof(struct acpi_iicbus_ivars)));
455 }
456 
457 static ACPI_STATUS
458 acpi_iicbus_enumerate_child(ACPI_HANDLE handle, UINT32 level,
459     void *context, void **result)
460 {
461 	device_t iicbus, child, acpi_child, acpi0;
462 	struct iicbus_softc *super_sc;
463 	ACPI_IICBUS_RESOURCE_I2C_SERIALBUS sb;
464 	ACPI_STATUS status;
465 	UINT32 sta;
466 
467 	iicbus = context;
468 	super_sc = device_get_softc(iicbus);
469 
470 	/*
471 	 * If no _STA method or if it failed, then assume that
472 	 * the device is present.
473 	 */
474 	if (!ACPI_FAILURE(acpi_GetInteger(handle, "_STA", &sta)) &&
475 	    !ACPI_DEVICE_PRESENT(sta))
476 		return (AE_OK);
477 
478 	if (!acpi_has_hid(handle))
479 		return (AE_OK);
480 
481 	/*
482 	 * Read "I2C Serial Bus Connection Resource Descriptor"
483 	 * described in p.19.6.57 of ACPI specification.
484 	 */
485 	bzero(&sb, sizeof(ACPI_IICBUS_RESOURCE_I2C_SERIALBUS));
486 	if (ACPI_FAILURE(acpi_iicbus_get_i2cres(handle, &sb)) ||
487 	    sb.SlaveAddress == 0)
488 		return (AE_OK);
489 	if (sb.ResourceSource_Handle !=
490 	    acpi_get_handle(device_get_parent(iicbus)))
491 		return (AE_OK);
492 	if (bootverbose)
493 		acpi_iicbus_dump_res(iicbus, &sb);
494 
495 	/* Find out speed of the slowest slave */
496 	if (super_sc->bus_freq == 0 || super_sc->bus_freq > sb.ConnectionSpeed)
497 		super_sc->bus_freq = sb.ConnectionSpeed;
498 
499 	/* Delete existing child of acpi bus */
500 	acpi_child = acpi_get_device(handle);
501 	if (acpi_child != NULL) {
502 		acpi0 = devclass_get_device(devclass_find("acpi"), 0);
503 		if (device_get_parent(acpi_child) != acpi0)
504 			return (AE_OK);
505 
506 		if (device_is_attached(acpi_child))
507 			return (AE_OK);
508 
509 		if (device_delete_child(acpi0, acpi_child) != 0)
510 			return (AE_OK);
511 	}
512 
513 	child = BUS_ADD_CHILD(iicbus, 0, NULL, -1);
514 	if (child == NULL) {
515 		device_printf(iicbus, "add child failed\n");
516 		return (AE_OK);
517 	}
518 
519 	iicbus_set_addr(child, sb.SlaveAddress);
520 	acpi_set_handle(child, handle);
521 	(void)acpi_iicbus_parse_resources(handle, child);
522 
523 	/*
524 	 * Update ACPI-CA to use the IIC enumerated device_t for this handle.
525 	 */
526 	status = AcpiAttachData(handle, acpi_fake_objhandler, child);
527 	if (ACPI_FAILURE(status))
528 		printf("WARNING: Unable to attach object data to %s - %s\n",
529 		    acpi_name(handle), AcpiFormatException(status));
530 
531 	return (AE_OK);
532 }
533 
534 static ACPI_STATUS
535 acpi_iicbus_enumerate_children(device_t dev)
536 {
537 
538 	return (AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
539 	    ACPI_UINT32_MAX, acpi_iicbus_enumerate_child, NULL, dev, NULL));
540 }
541 
542 static void
543 acpi_iicbus_set_power_children(device_t dev, int state, bool all_children)
544 {
545 	device_t *devlist;
546 	int i, numdevs;
547 
548 	if (device_get_children(dev, &devlist, &numdevs) != 0)
549 		return;
550 
551 	for (i = 0; i < numdevs; i++)
552 		if (all_children || device_is_attached(devlist[i]) != 0)
553 			acpi_set_powerstate(devlist[i], state);
554 
555 	free(devlist, M_TEMP);
556 }
557 
558 static int
559 acpi_iicbus_probe(device_t dev)
560 {
561 	ACPI_HANDLE handle;
562 	device_t controller;
563 
564 	if (acpi_disabled("iicbus"))
565 		return (ENXIO);
566 
567 	controller = device_get_parent(dev);
568 	if (controller == NULL)
569 		return (ENXIO);
570 
571 	handle = acpi_get_handle(controller);
572 	if (handle == NULL)
573 		return (ENXIO);
574 
575 	device_set_desc(dev, "Philips I2C bus (ACPI-hinted)");
576 	return (BUS_PROBE_DEFAULT);
577 }
578 
579 static int
580 acpi_iicbus_attach(device_t dev)
581 {
582 	struct acpi_iicbus_softc *sc = device_get_softc(dev);
583 	int error;
584 
585 	if (ACPI_FAILURE(acpi_iicbus_enumerate_children(dev)))
586 		device_printf(dev, "children enumeration failed\n");
587 
588 	acpi_iicbus_set_power_children(dev, ACPI_STATE_D0, true);
589 	error = iicbus_attach_common(dev, sc->super_sc.bus_freq);
590 	if (error == 0 && install_space_handler != 0 &&
591 	    acpi_iicbus_install_address_space_handler(sc) == 0)
592 		sc->space_handler_installed = true;
593 
594 	return (error);
595 }
596 
597 static int
598 acpi_iicbus_detach(device_t dev)
599 {
600 	struct acpi_iicbus_softc *sc = device_get_softc(dev);
601 
602 	if (sc->space_handler_installed)
603 		acpi_iicbus_remove_address_space_handler(sc);
604 	acpi_iicbus_set_power_children(dev, ACPI_STATE_D3, false);
605 
606 	return (iicbus_detach(dev));
607 }
608 
609 static int
610 acpi_iicbus_suspend(device_t dev)
611 {
612 	int error;
613 
614 	error = bus_generic_suspend(dev);
615 	if (error == 0)
616 		acpi_iicbus_set_power_children(dev, ACPI_STATE_D3, false);
617 
618 	return (error);
619 }
620 
621 static int
622 acpi_iicbus_resume(device_t dev)
623 {
624 
625 	acpi_iicbus_set_power_children(dev, ACPI_STATE_D0, false);
626 
627 	return (bus_generic_resume(dev));
628 }
629 
630 /*
631  * If this device is an ACPI child but no one claimed it, attempt
632  * to power it off.  We'll power it back up when a driver is added.
633  */
634 static void
635 acpi_iicbus_probe_nomatch(device_t bus, device_t child)
636 {
637 
638 	iicbus_probe_nomatch(bus, child);
639 	acpi_set_powerstate(child, ACPI_STATE_D3);
640 }
641 
642 /*
643  * If a new driver has a chance to probe a child, first power it up.
644  */
645 static void
646 acpi_iicbus_driver_added(device_t dev, driver_t *driver)
647 {
648 	device_t child, *devlist;
649 	int i, numdevs;
650 
651 	DEVICE_IDENTIFY(driver, dev);
652 	if (device_get_children(dev, &devlist, &numdevs) != 0)
653 		return;
654 
655 	for (i = 0; i < numdevs; i++) {
656 		child = devlist[i];
657 		if (device_get_state(child) == DS_NOTPRESENT) {
658 			acpi_set_powerstate(child, ACPI_STATE_D0);
659 			if (device_probe_and_attach(child) != 0)
660 				acpi_set_powerstate(child, ACPI_STATE_D3);
661 		}
662 	}
663 	free(devlist, M_TEMP);
664 }
665 
666 static void
667 acpi_iicbus_child_deleted(device_t bus, device_t child)
668 {
669 	struct acpi_iicbus_ivars *devi = device_get_ivars(child);
670 
671 	if (acpi_get_device(devi->handle) == child)
672 		AcpiDetachData(devi->handle, acpi_fake_objhandler);
673 }
674 
675 static int
676 acpi_iicbus_read_ivar(device_t bus, device_t child, int which, uintptr_t *res)
677 {
678 	struct acpi_iicbus_ivars *devi = device_get_ivars(child);
679 
680 	switch (which) {
681 	case ACPI_IVAR_HANDLE:
682 		*res = (uintptr_t)devi->handle;
683 		break;
684 	default:
685 		return (iicbus_read_ivar(bus, child, which, res));
686 	}
687 
688 	return (0);
689 }
690 
691 static int
692 acpi_iicbus_write_ivar(device_t bus, device_t child, int which, uintptr_t val)
693 {
694 	struct acpi_iicbus_ivars *devi = device_get_ivars(child);
695 
696 	switch (which) {
697 	case ACPI_IVAR_HANDLE:
698 		if (devi->handle != NULL)
699 			return (EINVAL);
700 		devi->handle = (ACPI_HANDLE)val;
701 		break;
702 	default:
703 		return (iicbus_write_ivar(bus, child, which, val));
704 	}
705 
706 	return (0);
707 }
708 
709 /* Location hint for devctl(8). Concatenate IIC and ACPI hints. */
710 static int
711 acpi_iicbus_child_location(device_t bus, device_t child, struct sbuf *sb)
712 {
713 	struct acpi_iicbus_ivars *devi = device_get_ivars(child);
714 	int error;
715 
716 	/* read IIC location hint string into the buffer. */
717 	error = iicbus_child_location(bus, child, sb);
718 	if (error != 0)
719 		return (error);
720 
721 	/* Place ACPI string right after IIC one's terminating NUL. */
722 	if (devi->handle != NULL)
723 		sbuf_printf(sb, " handle=%s", acpi_name(devi->handle));
724 
725 	return (0);
726 }
727 
728 /* PnP information for devctl(8). Concatenate IIC and ACPI info strings. */
729 static int
730 acpi_iicbus_child_pnpinfo(device_t bus, device_t child, struct sbuf *sb)
731 {
732 	struct acpi_iicbus_ivars *devi = device_get_ivars(child);
733 	int error;
734 
735 	/* read IIC PnP string into the buffer. */
736 	error = iicbus_child_pnpinfo(bus, child, sb);
737 	if (error != 0)
738 		return (error);
739 
740 	if (devi->handle == NULL)
741 		return (0);
742 
743 	error = acpi_pnpinfo(devi->handle, sb);
744 
745 	return (error);
746 }
747 
748 static device_method_t acpi_iicbus_methods[] = {
749 	/* Device interface */
750 	DEVMETHOD(device_probe,		acpi_iicbus_probe),
751 	DEVMETHOD(device_attach,	acpi_iicbus_attach),
752 	DEVMETHOD(device_detach,	acpi_iicbus_detach),
753 	DEVMETHOD(device_suspend,	acpi_iicbus_suspend),
754 	DEVMETHOD(device_resume,	acpi_iicbus_resume),
755 
756 	/* Bus interface */
757 	DEVMETHOD(bus_add_child,	acpi_iicbus_add_child),
758 	DEVMETHOD(bus_probe_nomatch,	acpi_iicbus_probe_nomatch),
759 	DEVMETHOD(bus_driver_added,	acpi_iicbus_driver_added),
760 	DEVMETHOD(bus_child_deleted,	acpi_iicbus_child_deleted),
761 	DEVMETHOD(bus_read_ivar,	acpi_iicbus_read_ivar),
762 	DEVMETHOD(bus_write_ivar,	acpi_iicbus_write_ivar),
763 	DEVMETHOD(bus_child_location,	acpi_iicbus_child_location),
764 	DEVMETHOD(bus_child_pnpinfo,	acpi_iicbus_child_pnpinfo),
765 	DEVMETHOD(bus_get_device_path,	acpi_get_acpi_device_path),
766 
767 	DEVMETHOD_END,
768 };
769 
770 DEFINE_CLASS_1(iicbus, acpi_iicbus_driver, acpi_iicbus_methods,
771     sizeof(struct acpi_iicbus_softc), iicbus_driver);
772 MODULE_VERSION(acpi_iicbus, 1);
773 MODULE_DEPEND(acpi_iicbus, acpi, 1, 1, 1);
774