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