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