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