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