xref: /freebsd-14-stable/sys/dev/iicbus/acpi_iicbus.c (revision 38dc6b814a6daed2bd54dfd652e9fe2f0fdb981a)
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 = 1;
80 TUNABLE_INT("hw.iicbus.enable_acpi_space_handler", &install_space_handler);
81 
82 static inline bool
acpi_resource_is_i2c_serialbus(ACPI_RESOURCE * res)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
acpi_iicbus_sendb(device_t dev,u_char slave,char byte)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
acpi_iicbus_recvb(device_t dev,u_char slave,char * byte)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
acpi_iicbus_write(device_t dev,u_char slave,char cmd,void * buf,uint16_t buflen)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
acpi_iicbus_read(device_t dev,u_char slave,char cmd,void * buf,uint16_t buflen)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
acpi_iicbus_bwrite(device_t dev,u_char slave,char cmd,u_char count,char * buf)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
acpi_iicbus_bread(device_t dev,u_char slave,char cmd,u_char * count,char * buf)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
acpi_iicbus_space_handler(UINT32 Function,ACPI_PHYSICAL_ADDRESS Address,UINT32 BitWidth,UINT64 * Value,void * HandlerContext,void * RegionContext)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 	/* the address is expected to need shifting */
259 	sb->SlaveAddress <<= 1;
260 
261 	switch (Function) {
262 	case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_SEND_RECEIVE, ACPI_READ):
263 		val = acpi_iicbus_recvb(dev, sb->SlaveAddress, gsb->data);
264 		break;
265 
266 	case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_SEND_RECEIVE, ACPI_WRITE):
267 		val = acpi_iicbus_sendb(dev, sb->SlaveAddress, gsb->data[0]);
268 		break;
269 
270 	case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTE, ACPI_READ):
271 		val = acpi_iicbus_read(dev, sb->SlaveAddress, Address,
272 		    gsb->data, 1);
273 		break;
274 
275 	case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTE, ACPI_WRITE):
276 		val = acpi_iicbus_write(dev, sb->SlaveAddress, Address,
277 		    gsb->data, 1);
278 		break;
279 
280 	case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_WORD, ACPI_READ):
281 		val = acpi_iicbus_read(dev, sb->SlaveAddress, Address,
282 		    gsb->data, 2);
283 		break;
284 
285 	case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_WORD, ACPI_WRITE):
286 		val = acpi_iicbus_write(dev, sb->SlaveAddress, Address,
287 		    gsb->data, 2);
288 		break;
289 
290 	case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BLOCK, ACPI_READ):
291 		val = acpi_iicbus_bread(dev, sb->SlaveAddress, Address,
292 		    &gsb->len, gsb->data);
293 		break;
294 
295 	case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BLOCK, ACPI_WRITE):
296 		val = acpi_iicbus_bwrite(dev, sb->SlaveAddress, Address,
297 		    gsb->len, gsb->data);
298 		break;
299 
300 	case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTES, ACPI_READ):
301 		val = acpi_iicbus_read(dev, sb->SlaveAddress, Address,
302 		    gsb->data, info->AccessLength);
303 		break;
304 
305 	case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTES, ACPI_WRITE):
306 		val = acpi_iicbus_write(dev, sb->SlaveAddress, Address,
307 		    gsb->data, info->AccessLength);
308 		break;
309 
310 	default:
311 		device_printf(dev, "protocol(0x%04x) is not supported.\n",
312 		    Function);
313 		s = AE_BAD_PARAMETER;
314 		goto err;
315 	}
316 
317 	gsb->status = val;
318 
319 err:
320 	ACPI_FREE(res);
321 
322 	return (s);
323 }
324 
325 static int
acpi_iicbus_install_address_space_handler(struct acpi_iicbus_softc * sc)326 acpi_iicbus_install_address_space_handler(struct acpi_iicbus_softc *sc)
327 {
328 	ACPI_HANDLE handle;
329 	ACPI_STATUS s;
330 
331 	handle = acpi_get_handle(device_get_parent(sc->super_sc.dev));
332 	s = AcpiInstallAddressSpaceHandler(handle, ACPI_ADR_SPACE_GSBUS,
333 	    &acpi_iicbus_space_handler, NULL, &sc->space_handler_info);
334 	if (ACPI_FAILURE(s)) {
335 		device_printf(sc->super_sc.dev,
336 		    "Failed to install GSBUS Address Space Handler in ACPI\n");
337 		return (ENXIO);
338 	}
339 
340 	return (0);
341 }
342 
343 static int
acpi_iicbus_remove_address_space_handler(struct acpi_iicbus_softc * sc)344 acpi_iicbus_remove_address_space_handler(struct acpi_iicbus_softc *sc)
345 {
346 	ACPI_HANDLE handle;
347 	ACPI_STATUS s;
348 
349 	handle = acpi_get_handle(device_get_parent(sc->super_sc.dev));
350 	s = AcpiRemoveAddressSpaceHandler(handle, ACPI_ADR_SPACE_GSBUS,
351 	    &acpi_iicbus_space_handler);
352 	if (ACPI_FAILURE(s)) {
353 		device_printf(sc->super_sc.dev,
354 		    "Failed to remove GSBUS Address Space Handler from ACPI\n");
355 		return (ENXIO);
356 	}
357 
358 	return (0);
359 }
360 
361 static ACPI_STATUS
acpi_iicbus_get_i2cres_cb(ACPI_RESOURCE * res,void * context)362 acpi_iicbus_get_i2cres_cb(ACPI_RESOURCE *res, void *context)
363 {
364 	ACPI_IICBUS_RESOURCE_I2C_SERIALBUS *sb = context;
365 	ACPI_STATUS status;
366 	ACPI_HANDLE handle;
367 
368 	if (acpi_resource_is_i2c_serialbus(res)) {
369 		status = AcpiGetHandle(ACPI_ROOT_OBJECT,
370 		    res->Data.I2cSerialBus.ResourceSource.StringPtr, &handle);
371 		if (ACPI_FAILURE(status))
372 			return (status);
373 		memcpy(sb, &res->Data.I2cSerialBus,
374 		    sizeof(ACPI_IICBUS_RESOURCE_I2C_SERIALBUS));
375 		/*
376 		 * replace "pointer to ACPI object name string" field
377 		 * with pointer to ACPI object itself.
378 		 */
379 		sb->ResourceSource_Handle = handle;
380 		return (AE_CTRL_TERMINATE);
381 	} else if (res->Type == ACPI_RESOURCE_TYPE_END_TAG)
382 		return (AE_NOT_FOUND);
383 
384 	return (AE_OK);
385 }
386 
387 static ACPI_STATUS
acpi_iicbus_get_i2cres(ACPI_HANDLE handle,ACPI_RESOURCE_I2C_SERIALBUS * sb)388 acpi_iicbus_get_i2cres(ACPI_HANDLE handle, ACPI_RESOURCE_I2C_SERIALBUS *sb)
389 {
390 
391 	return (AcpiWalkResources(handle, "_CRS",
392 	    acpi_iicbus_get_i2cres_cb, sb));
393 }
394 
395 static ACPI_STATUS
acpi_iicbus_parse_resources_cb(ACPI_RESOURCE * res,void * context)396 acpi_iicbus_parse_resources_cb(ACPI_RESOURCE *res, void *context)
397 {
398 	device_t dev = context;
399 	struct iicbus_ivar *super_devi = device_get_ivars(dev);
400 	struct resource_list *rl = &super_devi->rl;
401 	int irq, gpio_pin;
402 
403 	switch(res->Type) {
404 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
405 		if (res->Data.ExtendedIrq.InterruptCount > 0) {
406 			irq = res->Data.ExtendedIrq.Interrupts[0];
407 			if (bootverbose)
408 				printf("  IRQ:               %d\n", irq);
409 			resource_list_add_next(rl, SYS_RES_IRQ, irq, irq, 1);
410 			return (AE_CTRL_TERMINATE);
411 		}
412 		break;
413 	case ACPI_RESOURCE_TYPE_GPIO:
414 		if (res->Data.Gpio.ConnectionType ==
415 		    ACPI_RESOURCE_GPIO_TYPE_INT) {
416 			/* Not supported by FreeBSD yet */
417 			gpio_pin = res->Data.Gpio.PinTable[0];
418 			if (bootverbose)
419 				printf("  GPIO IRQ pin:      %d\n", gpio_pin);
420 			return (AE_CTRL_TERMINATE);
421 		}
422 		break;
423 	default:
424 		break;
425 	}
426 
427 	return (AE_OK);
428 }
429 
430 static ACPI_STATUS
acpi_iicbus_parse_resources(ACPI_HANDLE handle,device_t dev)431 acpi_iicbus_parse_resources(ACPI_HANDLE handle, device_t dev)
432 {
433 
434 	return (AcpiWalkResources(handle, "_CRS",
435 	    acpi_iicbus_parse_resources_cb, dev));
436 }
437 
438 static void
acpi_iicbus_dump_res(device_t dev,ACPI_IICBUS_RESOURCE_I2C_SERIALBUS * sb)439 acpi_iicbus_dump_res(device_t dev, ACPI_IICBUS_RESOURCE_I2C_SERIALBUS *sb)
440 {
441 	device_printf(dev, "found ACPI child\n");
442 	printf("  SlaveAddress:      0x%04hx\n", sb->SlaveAddress);
443 	printf("  ConnectionSpeed:   %uHz\n", sb->ConnectionSpeed);
444 	printf("  SlaveMode:         %s\n",
445 	    sb->SlaveMode == ACPI_CONTROLLER_INITIATED ?
446 	    "ControllerInitiated" : "DeviceInitiated");
447 	printf("  AddressingMode:    %uBit\n", sb->AccessMode == 0 ? 7 : 10);
448 	printf("  ConnectionSharing: %s\n", sb->ConnectionSharing == 0 ?
449 	    "Exclusive" : "Shared");
450 }
451 
452 static device_t
acpi_iicbus_add_child(device_t dev,u_int order,const char * name,int unit)453 acpi_iicbus_add_child(device_t dev, u_int order, const char *name, int unit)
454 {
455 
456 	return (iicbus_add_child_common(
457 	    dev, order, name, unit, sizeof(struct acpi_iicbus_ivars)));
458 }
459 
460 static ACPI_STATUS
acpi_iicbus_enumerate_child(ACPI_HANDLE handle,UINT32 level,void * context,void ** result)461 acpi_iicbus_enumerate_child(ACPI_HANDLE handle, UINT32 level,
462     void *context, void **result)
463 {
464 	device_t iicbus, child, acpi_child, acpi0;
465 	struct iicbus_softc *super_sc;
466 	ACPI_IICBUS_RESOURCE_I2C_SERIALBUS sb;
467 	ACPI_STATUS status;
468 	UINT32 sta;
469 
470 	iicbus = context;
471 	super_sc = device_get_softc(iicbus);
472 
473 	/*
474 	 * If no _STA method or if it failed, then assume that
475 	 * the device is present.
476 	 */
477 	if (!ACPI_FAILURE(acpi_GetInteger(handle, "_STA", &sta)) &&
478 	    !ACPI_DEVICE_PRESENT(sta))
479 		return (AE_OK);
480 
481 	if (!acpi_has_hid(handle))
482 		return (AE_OK);
483 
484 	/*
485 	 * Read "I2C Serial Bus Connection Resource Descriptor"
486 	 * described in p.19.6.57 of ACPI specification.
487 	 */
488 	bzero(&sb, sizeof(ACPI_IICBUS_RESOURCE_I2C_SERIALBUS));
489 	if (ACPI_FAILURE(acpi_iicbus_get_i2cres(handle, &sb)) ||
490 	    sb.SlaveAddress == 0)
491 		return (AE_OK);
492 	if (sb.ResourceSource_Handle !=
493 	    acpi_get_handle(device_get_parent(iicbus)))
494 		return (AE_OK);
495 	if (bootverbose)
496 		acpi_iicbus_dump_res(iicbus, &sb);
497 
498 	/* Find out speed of the slowest slave */
499 	if (super_sc->bus_freq == 0 || super_sc->bus_freq > sb.ConnectionSpeed)
500 		super_sc->bus_freq = sb.ConnectionSpeed;
501 
502 	/* Delete existing child of acpi bus */
503 	acpi_child = acpi_get_device(handle);
504 	if (acpi_child != NULL) {
505 		acpi0 = devclass_get_device(devclass_find("acpi"), 0);
506 		if (device_get_parent(acpi_child) != acpi0)
507 			return (AE_OK);
508 
509 		if (device_is_attached(acpi_child))
510 			return (AE_OK);
511 
512 		if (device_delete_child(acpi0, acpi_child) != 0)
513 			return (AE_OK);
514 	}
515 
516 	child = BUS_ADD_CHILD(iicbus, 0, NULL, -1);
517 	if (child == NULL) {
518 		device_printf(iicbus, "add child failed\n");
519 		return (AE_OK);
520 	}
521 
522 	iicbus_set_addr(child, sb.SlaveAddress);
523 	acpi_set_handle(child, handle);
524 	(void)acpi_iicbus_parse_resources(handle, child);
525 
526 	/*
527 	 * Update ACPI-CA to use the IIC enumerated device_t for this handle.
528 	 */
529 	status = AcpiAttachData(handle, acpi_fake_objhandler, child);
530 	if (ACPI_FAILURE(status))
531 		printf("WARNING: Unable to attach object data to %s - %s\n",
532 		    acpi_name(handle), AcpiFormatException(status));
533 
534 	return (AE_OK);
535 }
536 
537 static ACPI_STATUS
acpi_iicbus_enumerate_children(device_t dev)538 acpi_iicbus_enumerate_children(device_t dev)
539 {
540 
541 	return (AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
542 	    ACPI_UINT32_MAX, acpi_iicbus_enumerate_child, NULL, dev, NULL));
543 }
544 
545 static void
acpi_iicbus_set_power_children(device_t dev,int state,bool all_children)546 acpi_iicbus_set_power_children(device_t dev, int state, bool all_children)
547 {
548 	device_t *devlist;
549 	int i, numdevs;
550 
551 	if (device_get_children(dev, &devlist, &numdevs) != 0)
552 		return;
553 
554 	for (i = 0; i < numdevs; i++)
555 		if (all_children || device_is_attached(devlist[i]) != 0)
556 			acpi_set_powerstate(devlist[i], state);
557 
558 	free(devlist, M_TEMP);
559 }
560 
561 static int
acpi_iicbus_probe(device_t dev)562 acpi_iicbus_probe(device_t dev)
563 {
564 	ACPI_HANDLE handle;
565 	device_t controller;
566 
567 	if (acpi_disabled("iicbus"))
568 		return (ENXIO);
569 
570 	controller = device_get_parent(dev);
571 	if (controller == NULL)
572 		return (ENXIO);
573 
574 	handle = acpi_get_handle(controller);
575 	if (handle == NULL)
576 		return (ENXIO);
577 
578 	device_set_desc(dev, "Philips I2C bus (ACPI-hinted)");
579 	return (BUS_PROBE_DEFAULT);
580 }
581 
582 static int
acpi_iicbus_attach(device_t dev)583 acpi_iicbus_attach(device_t dev)
584 {
585 	struct acpi_iicbus_softc *sc = device_get_softc(dev);
586 	int error;
587 
588 	if (ACPI_FAILURE(acpi_iicbus_enumerate_children(dev)))
589 		device_printf(dev, "children enumeration failed\n");
590 
591 	acpi_iicbus_set_power_children(dev, ACPI_STATE_D0, true);
592 	error = iicbus_attach_common(dev, sc->super_sc.bus_freq);
593 	if (error == 0 && install_space_handler != 0 &&
594 	    acpi_iicbus_install_address_space_handler(sc) == 0)
595 		sc->space_handler_installed = true;
596 
597 	return (error);
598 }
599 
600 static int
acpi_iicbus_detach(device_t dev)601 acpi_iicbus_detach(device_t dev)
602 {
603 	struct acpi_iicbus_softc *sc = device_get_softc(dev);
604 
605 	if (sc->space_handler_installed)
606 		acpi_iicbus_remove_address_space_handler(sc);
607 	acpi_iicbus_set_power_children(dev, ACPI_STATE_D3, false);
608 
609 	return (iicbus_detach(dev));
610 }
611 
612 static int
acpi_iicbus_suspend(device_t dev)613 acpi_iicbus_suspend(device_t dev)
614 {
615 	int error;
616 
617 	error = bus_generic_suspend(dev);
618 	if (error == 0)
619 		acpi_iicbus_set_power_children(dev, ACPI_STATE_D3, false);
620 
621 	return (error);
622 }
623 
624 static int
acpi_iicbus_resume(device_t dev)625 acpi_iicbus_resume(device_t dev)
626 {
627 
628 	acpi_iicbus_set_power_children(dev, ACPI_STATE_D0, false);
629 
630 	return (bus_generic_resume(dev));
631 }
632 
633 /*
634  * If this device is an ACPI child but no one claimed it, attempt
635  * to power it off.  We'll power it back up when a driver is added.
636  */
637 static void
acpi_iicbus_probe_nomatch(device_t bus,device_t child)638 acpi_iicbus_probe_nomatch(device_t bus, device_t child)
639 {
640 
641 	iicbus_probe_nomatch(bus, child);
642 	acpi_set_powerstate(child, ACPI_STATE_D3);
643 }
644 
645 /*
646  * If a new driver has a chance to probe a child, first power it up.
647  */
648 static void
acpi_iicbus_driver_added(device_t dev,driver_t * driver)649 acpi_iicbus_driver_added(device_t dev, driver_t *driver)
650 {
651 	device_t child, *devlist;
652 	int i, numdevs;
653 
654 	DEVICE_IDENTIFY(driver, dev);
655 	if (device_get_children(dev, &devlist, &numdevs) != 0)
656 		return;
657 
658 	for (i = 0; i < numdevs; i++) {
659 		child = devlist[i];
660 		if (device_get_state(child) == DS_NOTPRESENT) {
661 			acpi_set_powerstate(child, ACPI_STATE_D0);
662 			if (device_probe_and_attach(child) != 0)
663 				acpi_set_powerstate(child, ACPI_STATE_D3);
664 		}
665 	}
666 	free(devlist, M_TEMP);
667 }
668 
669 static void
acpi_iicbus_child_deleted(device_t bus,device_t child)670 acpi_iicbus_child_deleted(device_t bus, device_t child)
671 {
672 	struct acpi_iicbus_ivars *devi = device_get_ivars(child);
673 
674 	if (acpi_get_device(devi->handle) == child)
675 		AcpiDetachData(devi->handle, acpi_fake_objhandler);
676 }
677 
678 static int
acpi_iicbus_read_ivar(device_t bus,device_t child,int which,uintptr_t * res)679 acpi_iicbus_read_ivar(device_t bus, device_t child, int which, uintptr_t *res)
680 {
681 	struct acpi_iicbus_ivars *devi = device_get_ivars(child);
682 
683 	switch (which) {
684 	case ACPI_IVAR_HANDLE:
685 		*res = (uintptr_t)devi->handle;
686 		break;
687 	default:
688 		return (iicbus_read_ivar(bus, child, which, res));
689 	}
690 
691 	return (0);
692 }
693 
694 static int
acpi_iicbus_write_ivar(device_t bus,device_t child,int which,uintptr_t val)695 acpi_iicbus_write_ivar(device_t bus, device_t child, int which, uintptr_t val)
696 {
697 	struct acpi_iicbus_ivars *devi = device_get_ivars(child);
698 
699 	switch (which) {
700 	case ACPI_IVAR_HANDLE:
701 		if (devi->handle != NULL)
702 			return (EINVAL);
703 		devi->handle = (ACPI_HANDLE)val;
704 		break;
705 	default:
706 		return (iicbus_write_ivar(bus, child, which, val));
707 	}
708 
709 	return (0);
710 }
711 
712 /* Location hint for devctl(8). Concatenate IIC and ACPI hints. */
713 static int
acpi_iicbus_child_location(device_t bus,device_t child,struct sbuf * sb)714 acpi_iicbus_child_location(device_t bus, device_t child, struct sbuf *sb)
715 {
716 	struct acpi_iicbus_ivars *devi = device_get_ivars(child);
717 	int error;
718 
719 	/* read IIC location hint string into the buffer. */
720 	error = iicbus_child_location(bus, child, sb);
721 	if (error != 0)
722 		return (error);
723 
724 	/* Place ACPI string right after IIC one's terminating NUL. */
725 	if (devi->handle != NULL)
726 		sbuf_printf(sb, " handle=%s", acpi_name(devi->handle));
727 
728 	return (0);
729 }
730 
731 /* PnP information for devctl(8). Concatenate IIC and ACPI info strings. */
732 static int
acpi_iicbus_child_pnpinfo(device_t bus,device_t child,struct sbuf * sb)733 acpi_iicbus_child_pnpinfo(device_t bus, device_t child, struct sbuf *sb)
734 {
735 	struct acpi_iicbus_ivars *devi = device_get_ivars(child);
736 	int error;
737 
738 	/* read IIC PnP string into the buffer. */
739 	error = iicbus_child_pnpinfo(bus, child, sb);
740 	if (error != 0)
741 		return (error);
742 
743 	if (devi->handle == NULL)
744 		return (0);
745 
746 	error = acpi_pnpinfo(devi->handle, sb);
747 
748 	return (error);
749 }
750 
751 static device_method_t acpi_iicbus_methods[] = {
752 	/* Device interface */
753 	DEVMETHOD(device_probe,		acpi_iicbus_probe),
754 	DEVMETHOD(device_attach,	acpi_iicbus_attach),
755 	DEVMETHOD(device_detach,	acpi_iicbus_detach),
756 	DEVMETHOD(device_suspend,	acpi_iicbus_suspend),
757 	DEVMETHOD(device_resume,	acpi_iicbus_resume),
758 
759 	/* Bus interface */
760 	DEVMETHOD(bus_add_child,	acpi_iicbus_add_child),
761 	DEVMETHOD(bus_probe_nomatch,	acpi_iicbus_probe_nomatch),
762 	DEVMETHOD(bus_driver_added,	acpi_iicbus_driver_added),
763 	DEVMETHOD(bus_child_deleted,	acpi_iicbus_child_deleted),
764 	DEVMETHOD(bus_read_ivar,	acpi_iicbus_read_ivar),
765 	DEVMETHOD(bus_write_ivar,	acpi_iicbus_write_ivar),
766 	DEVMETHOD(bus_child_location,	acpi_iicbus_child_location),
767 	DEVMETHOD(bus_child_pnpinfo,	acpi_iicbus_child_pnpinfo),
768 	DEVMETHOD(bus_get_device_path,	acpi_get_acpi_device_path),
769 
770 	DEVMETHOD_END,
771 };
772 
773 DEFINE_CLASS_1(iicbus, acpi_iicbus_driver, acpi_iicbus_methods,
774     sizeof(struct acpi_iicbus_softc), iicbus_driver);
775 MODULE_VERSION(acpi_iicbus, 1);
776 MODULE_DEPEND(acpi_iicbus, acpi, 1, 1, 1);
777