xref: /openbsd/sys/dev/acpi/dwiic_acpi.c (revision 5dea098c)
1 /* $OpenBSD: dwiic_acpi.c,v 1.22 2023/07/08 02:43:02 jcs Exp $ */
2 /*
3  * Synopsys DesignWare I2C controller
4  *
5  * Copyright (c) 2015, 2016 joshua stein <jcs@openbsd.org>
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "iosf.h"
21 
22 #include <sys/param.h>
23 #include <sys/systm.h>
24 #include <sys/kernel.h>
25 
26 #include <dev/acpi/acpireg.h>
27 #include <dev/acpi/acpivar.h>
28 #include <dev/acpi/acpidev.h>
29 #include <dev/acpi/amltypes.h>
30 #include <dev/acpi/dsdt.h>
31 
32 #include <dev/ic/dwiicvar.h>
33 #include <dev/ic/iosfvar.h>
34 
35 struct dwiic_crs {
36 	int irq_int;
37 	uint8_t irq_flags;
38 	uint16_t i2c_addr;
39 	struct aml_node *devnode;
40 	struct aml_node *gpio_int_node;
41 	uint16_t gpio_int_pin;
42 	uint16_t gpio_int_flags;
43 };
44 
45 int		dwiic_acpi_match(struct device *, void *, void *);
46 void		dwiic_acpi_attach(struct device *, struct device *, void *);
47 
48 int		dwiic_acpi_parse_crs(int, union acpi_resource *, void *);
49 int		dwiic_acpi_found_ihidev(struct dwiic_softc *,
50 		    struct aml_node *, char *, struct dwiic_crs);
51 int		dwiic_acpi_found_iatp(struct dwiic_softc *, struct aml_node *,
52 		    char *, struct dwiic_crs);
53 int		dwiic_acpi_found_ietp(struct dwiic_softc *, struct aml_node *,
54 		    char *, struct dwiic_crs);
55 void		dwiic_acpi_get_params(struct dwiic_softc *, char *, uint16_t *,
56 		    uint16_t *, uint32_t *);
57 void		dwiic_acpi_power(struct dwiic_softc *, int);
58 void		dwiic_acpi_bus_scan(struct device *,
59 		    struct i2cbus_attach_args *, void *);
60 
61 #if NIOSF > 0
62 int		dwiic_acpi_acquire_bus(void *, int);
63 void		dwiic_acpi_release_bus(void *, int);
64 #endif
65 
66 const struct cfattach dwiic_acpi_ca = {
67 	sizeof(struct dwiic_softc),
68 	dwiic_acpi_match,
69 	dwiic_acpi_attach,
70 	NULL,
71 	dwiic_activate
72 };
73 
74 const char *dwiic_hids[] = {
75 	"AMDI0010",
76 	"APMC0D0F",
77 	"INT33C2",
78 	"INT33C3",
79 	"INT3432",
80 	"INT3433",
81 	"80860F41",
82 	"808622C1",
83 	NULL
84 };
85 
86 const char *ihidev_hids[] = {
87 	"PNP0C50",
88 	"ACPI0C50",
89 	NULL
90 };
91 
92 const char *ietp_hids[] = {
93 	"ELAN0000",
94 	"ELAN0100",
95 	"ELAN0600",
96 	"ELAN0601",
97 	"ELAN0602",
98 	"ELAN0603",
99 	"ELAN0604",
100 	"ELAN0605",
101 	"ELAN0606",
102 	"ELAN0607",
103 	"ELAN0608",
104 	"ELAN0609",
105 	"ELAN060B",
106 	"ELAN060C",
107 	"ELAN060F",
108 	"ELAN0610",
109 	"ELAN0611",
110 	"ELAN0612",
111 	"ELAN0615",
112 	"ELAN0616",
113 	"ELAN0617",
114 	"ELAN0618",
115 	"ELAN0619",
116 	"ELAN061A",
117 	"ELAN061B",
118 	"ELAN061C",
119 	"ELAN061D",
120 	"ELAN061E",
121 	"ELAN061F",
122 	"ELAN0620",
123 	"ELAN0621",
124 	"ELAN0622",
125 	"ELAN0623",
126 	"ELAN0624",
127 	"ELAN0625",
128 	"ELAN0626",
129 	"ELAN0627",
130 	"ELAN0628",
131 	"ELAN0629",
132 	"ELAN062A",
133 	"ELAN062B",
134 	"ELAN062C",
135 	"ELAN062D",
136 	"ELAN062E",	/* Lenovo V340 Whiskey Lake U */
137 	"ELAN062F",	/* Lenovo V340 Comet Lake U */
138 	"ELAN0631",
139 	"ELAN0632",
140 	"ELAN0633",	/* Lenovo S145 */
141 	"ELAN0634",	/* Lenovo V340 Ice lake */
142 	"ELAN0635",	/* Lenovo V1415-IIL */
143 	"ELAN0636",	/* Lenovo V1415-Dali */
144 	"ELAN0637",	/* Lenovo V1415-IGLR */
145 	"ELAN1000",
146 	NULL
147 };
148 
149 const char *iatp_hids[] = {
150 	"ATML0000",
151 	"ATML0001",
152 	NULL
153 };
154 
155 int
156 dwiic_acpi_match(struct device *parent, void *match, void *aux)
157 {
158 	struct acpi_attach_args *aaa = aux;
159 	struct cfdata *cf = match;
160 
161 	if (aaa->aaa_naddr < 1)
162 		return 0;
163 	return acpi_matchhids(aaa, dwiic_hids, cf->cf_driver->cd_name);
164 }
165 
166 void
167 dwiic_acpi_attach(struct device *parent, struct device *self, void *aux)
168 {
169 	struct dwiic_softc *sc = (struct dwiic_softc *)self;
170 	struct acpi_attach_args *aaa = aux;
171 	struct aml_value res;
172 	struct dwiic_crs crs;
173 	uint64_t sem;
174 
175 	sc->sc_acpi = (struct acpi_softc *)parent;
176 	sc->sc_devnode = aaa->aaa_node;
177 	memcpy(&sc->sc_hid, aaa->aaa_dev, sizeof(sc->sc_hid));
178 
179 	printf(" %s", sc->sc_devnode->name);
180 
181 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CRS", 0, NULL, &res)) {
182 		printf(", no _CRS method\n");
183 		return;
184 	}
185 	if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
186 		printf(", invalid _CRS object (type %d len %d)\n",
187 		    res.type, res.length);
188 		aml_freevalue(&res);
189 		return;
190 	}
191 	memset(&crs, 0, sizeof(crs));
192 	crs.devnode = sc->sc_devnode;
193 	aml_parse_resource(&res, dwiic_acpi_parse_crs, &crs);
194 	aml_freevalue(&res);
195 
196 	printf(" addr 0x%llx/0x%llx", aaa->aaa_addr[0], aaa->aaa_size[0]);
197 
198 	sc->sc_iot = aaa->aaa_bst[0];
199 	if (bus_space_map(sc->sc_iot, aaa->aaa_addr[0], aaa->aaa_size[0],
200 	    0, &sc->sc_ioh)) {
201 		printf(": can't map registers\n");
202 		return;
203 	}
204 
205 	/* power up the controller */
206 	dwiic_acpi_power(sc, 1);
207 
208 	/* fetch timing parameters */
209 	dwiic_acpi_get_params(sc, "SSCN", &sc->ss_hcnt, &sc->ss_lcnt, NULL);
210 	dwiic_acpi_get_params(sc, "FMCN", &sc->fs_hcnt, &sc->fs_lcnt,
211 	    &sc->sda_hold_time);
212 
213 	if (dwiic_init(sc)) {
214 		printf(", failed initializing\n");
215 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, aaa->aaa_size[0]);
216 		return;
217 	}
218 
219 	/* leave the controller disabled */
220 	dwiic_write(sc, DW_IC_INTR_MASK, 0);
221 	dwiic_enable(sc, 0);
222 	dwiic_read(sc, DW_IC_CLR_INTR);
223 
224 	/* try to register interrupt with apic, but not fatal without it */
225 	if (aaa->aaa_nirq > 0) {
226 		printf(" irq %d", aaa->aaa_irq[0]);
227 
228 		sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0],
229 		    IPL_BIO, dwiic_intr, sc, sc->sc_dev.dv_xname);
230 		if (sc->sc_ih == NULL)
231 			printf(": can't establish interrupt");
232 	}
233 
234 	if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode,
235 	    "_SEM", 0, NULL, &sem))
236 		sem = 0;
237 
238 	if (sem)
239 		printf(", sem");
240 
241 	printf("\n");
242 
243 	rw_init(&sc->sc_i2c_lock, "iiclk");
244 
245 	/* setup and attach iic bus */
246 	sc->sc_i2c_tag.ic_cookie = sc;
247 	sc->sc_i2c_tag.ic_acquire_bus = dwiic_i2c_acquire_bus;
248 	sc->sc_i2c_tag.ic_release_bus = dwiic_i2c_release_bus;
249 	sc->sc_i2c_tag.ic_exec = dwiic_i2c_exec;
250 	sc->sc_i2c_tag.ic_intr_establish = dwiic_i2c_intr_establish;
251 	sc->sc_i2c_tag.ic_intr_disestablish = dwiic_i2c_intr_disestablish;
252 	sc->sc_i2c_tag.ic_intr_string = dwiic_i2c_intr_string;
253 
254 #if NIOSF > 0
255 	if (sem) {
256 		sc->sc_i2c_tag.ic_acquire_bus = dwiic_acpi_acquire_bus;
257 		sc->sc_i2c_tag.ic_release_bus = dwiic_acpi_release_bus;
258 	}
259 #endif
260 
261 	bzero(&sc->sc_iba, sizeof(sc->sc_iba));
262 	sc->sc_iba.iba_name = "iic";
263 	sc->sc_iba.iba_tag = &sc->sc_i2c_tag;
264 	sc->sc_iba.iba_bus_scan = dwiic_acpi_bus_scan;
265 	sc->sc_iba.iba_bus_scan_arg = sc;
266 
267 	config_found((struct device *)sc, &sc->sc_iba, iicbus_print);
268 
269 #ifndef SMALL_KERNEL
270 	sc->sc_devnode->i2c = &sc->sc_i2c_tag;
271 	acpi_register_gsb(sc->sc_acpi, sc->sc_devnode);
272 #endif
273 }
274 
275 int
276 dwiic_acpi_parse_crs(int crsidx, union acpi_resource *crs, void *arg)
277 {
278 	struct dwiic_crs *sc_crs = arg;
279 	struct aml_node *node;
280 	uint16_t pin;
281 	uint8_t flags;
282 
283 	switch (AML_CRSTYPE(crs)) {
284 	case SR_IRQ:
285 		sc_crs->irq_int = ffs(letoh16(crs->sr_irq.irq_mask)) - 1;
286 		/* Default is exclusive, active-high, edge triggered. */
287 		if (AML_CRSLEN(crs) < 4)
288 			flags = SR_IRQ_MODE;
289 		else
290 			flags = crs->sr_irq.irq_flags;
291 		/* Map flags to those of the extended interrupt descriptor. */
292 		if (flags & SR_IRQ_SHR)
293 			sc_crs->irq_flags |= LR_EXTIRQ_SHR;
294 		if (flags & SR_IRQ_POLARITY)
295 			sc_crs->irq_flags |= LR_EXTIRQ_POLARITY;
296 		if (flags & SR_IRQ_MODE)
297 			sc_crs->irq_flags |= LR_EXTIRQ_MODE;
298 		break;
299 
300 	case LR_EXTIRQ:
301 		sc_crs->irq_int = letoh32(crs->lr_extirq.irq[0]);
302 		sc_crs->irq_flags = crs->lr_extirq.flags;
303 		break;
304 
305 	case LR_GPIO:
306 		node = aml_searchname(sc_crs->devnode,
307 		    (char *)&crs->pad[crs->lr_gpio.res_off]);
308 		pin = *(uint16_t *)&crs->pad[crs->lr_gpio.pin_off];
309 		if (crs->lr_gpio.type == LR_GPIO_INT) {
310 			sc_crs->gpio_int_node = node;
311 			sc_crs->gpio_int_pin = pin;
312 			sc_crs->gpio_int_flags = crs->lr_gpio.tflags;
313 		}
314 		break;
315 
316 	case LR_SERBUS:
317 		if (crs->lr_serbus.type == LR_SERBUS_I2C)
318 			sc_crs->i2c_addr = letoh16(crs->lr_i2cbus._adr);
319 		break;
320 
321 	case LR_MEM32:
322 	case LR_MEM32FIXED:
323 		break;
324 
325 	default:
326 		DPRINTF(("%s: unknown resource type %d\n", __func__,
327 		    AML_CRSTYPE(crs)));
328 	}
329 
330 	return 0;
331 }
332 
333 void
334 dwiic_acpi_get_params(struct dwiic_softc *sc, char *method, uint16_t *hcnt,
335     uint16_t *lcnt, uint32_t *sda_hold_time)
336 {
337 	struct aml_value res;
338 
339 	if (!aml_searchname(sc->sc_devnode, method))
340 		return;
341 
342 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, method, 0, NULL, &res)) {
343 		printf(": eval of %s at %s failed", method,
344 		    aml_nodename(sc->sc_devnode));
345 		return;
346 	}
347 
348 	if (res.type != AML_OBJTYPE_PACKAGE) {
349 		printf(": %s is not a package (%d)", method, res.type);
350 		aml_freevalue(&res);
351 		return;
352 	}
353 
354 	if (res.length <= 2) {
355 		printf(": %s returned package of len %d", method, res.length);
356 		aml_freevalue(&res);
357 		return;
358 	}
359 
360 	*hcnt = aml_val2int(res.v_package[0]);
361 	*lcnt = aml_val2int(res.v_package[1]);
362 	if (sda_hold_time)
363 		*sda_hold_time = aml_val2int(res.v_package[2]);
364 	aml_freevalue(&res);
365 }
366 
367 void
368 dwiic_acpi_bus_scan(struct device *iic, struct i2cbus_attach_args *iba,
369     void *aux)
370 {
371 	struct dwiic_softc *sc = (struct dwiic_softc *)aux;
372 
373 	sc->sc_iic = iic;
374 	aml_find_node(sc->sc_devnode, "_HID", dwiic_acpi_found_hid, sc);
375 }
376 
377 void *
378 dwiic_i2c_intr_establish(void *cookie, void *ih, int level,
379     int (*func)(void *), void *arg, const char *name)
380 {
381 	struct dwiic_crs *crs = ih;
382 
383 	if (crs->gpio_int_node) {
384 		if (!crs->gpio_int_node->gpio)
385 			/* found ACPI device but no driver for it */
386 			return NULL;
387 
388 		struct acpi_gpio *gpio = crs->gpio_int_node->gpio;
389 		gpio->intr_establish(gpio->cookie, crs->gpio_int_pin,
390 				     crs->gpio_int_flags, func, arg);
391 		return ih;
392 	}
393 
394 	return acpi_intr_establish(crs->irq_int, crs->irq_flags,
395 	    level, func, arg, name);
396 }
397 
398 void
399 dwiic_i2c_intr_disestablish(void *cookie, void *ih)
400 {
401 	/* XXX GPIO interrupts */
402 	acpi_intr_disestablish(ih);
403 }
404 
405 const char *
406 dwiic_i2c_intr_string(void *cookie, void *ih)
407 {
408 	struct dwiic_crs *crs = ih;
409 	static char irqstr[64];
410 
411 	if (crs->gpio_int_node) {
412 		if (crs->gpio_int_node->gpio)
413 			snprintf(irqstr, sizeof(irqstr), "gpio %d",
414 			    crs->gpio_int_pin);
415 	} else
416 		snprintf(irqstr, sizeof(irqstr), "irq %d", crs->irq_int);
417 
418 	return irqstr;
419 }
420 
421 int
422 dwiic_matchhids(const char *hid, const char *hids[])
423 {
424 	int i;
425 
426 	for (i = 0; hids[i]; i++)
427 		if (!strcmp(hid, hids[i]))
428 			return (1);
429 
430 	return (0);
431 }
432 
433 int
434 dwiic_acpi_found_hid(struct aml_node *node, void *arg)
435 {
436 	struct dwiic_softc *sc = (struct dwiic_softc *)arg;
437 	struct dwiic_crs crs;
438 	struct aml_value res;
439 	int64_t sta;
440 	char cdev[16], dev[16];
441 	struct i2c_attach_args ia;
442 
443 	/* Skip our own _HID. */
444 	if (node->parent == sc->sc_devnode)
445 		return 0;
446 
447 	if (acpi_parsehid(node, arg, cdev, dev, 16) != 0)
448 		return 0;
449 
450 	if (aml_evalinteger(acpi_softc, node->parent, "_STA", 0, NULL, &sta))
451 		sta = STA_PRESENT | STA_ENABLED | STA_DEV_OK | 0x1000;
452 
453 	if ((sta & STA_PRESENT) == 0)
454 		return 0;
455 
456 	DPRINTF(("%s: found HID %s at %s\n", sc->sc_dev.dv_xname, dev,
457 	    aml_nodename(node)));
458 
459 	if (aml_evalname(acpi_softc, node->parent, "_CRS", 0, NULL, &res))
460 		return 0;
461 
462 	if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
463 		printf("%s: invalid _CRS object (type %d len %d)\n",
464 		    sc->sc_dev.dv_xname, res.type, res.length);
465 		aml_freevalue(&res);
466 		return (0);
467 	}
468 	memset(&crs, 0, sizeof(crs));
469 	crs.devnode = sc->sc_devnode;
470 	aml_parse_resource(&res, dwiic_acpi_parse_crs, &crs);
471 	aml_freevalue(&res);
472 
473 	acpi_attach_deps(acpi_softc, node->parent);
474 
475 	if (dwiic_matchhids(cdev, ihidev_hids))
476 		return dwiic_acpi_found_ihidev(sc, node, dev, crs);
477 	else if (dwiic_matchhids(dev, iatp_hids))
478 		return dwiic_acpi_found_iatp(sc, node, dev, crs);
479 	else if (dwiic_matchhids(dev, ietp_hids) || dwiic_matchhids(cdev, ietp_hids))
480 		return dwiic_acpi_found_ietp(sc, node, dev, crs);
481 
482 	memset(&ia, 0, sizeof(ia));
483 	ia.ia_tag = sc->sc_iba.iba_tag;
484 	ia.ia_name = dev;
485 	ia.ia_addr = crs.i2c_addr;
486 	ia.ia_cookie = node->parent;
487 
488 	if (crs.irq_int != 0 || crs.gpio_int_node != NULL)
489 		ia.ia_intr = &crs;
490 
491 	config_found(sc->sc_iic, &ia, dwiic_i2c_print);
492 	node->parent->attached = 1;
493 
494 	return 0;
495 }
496 
497 int
498 dwiic_acpi_found_ihidev(struct dwiic_softc *sc, struct aml_node *node,
499     char *dev, struct dwiic_crs crs)
500 {
501 	struct i2c_attach_args ia;
502 	struct aml_value cmd[4], res;
503 
504 	/* 3cdff6f7-4267-4555-ad05-b30a3d8938de */
505 	static uint8_t i2c_hid_guid[] = {
506 		0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45,
507 		0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE,
508 	};
509 
510 	if (!aml_searchname(node->parent, "_DSM")) {
511 		printf("%s: couldn't find _DSM at %s\n", sc->sc_dev.dv_xname,
512 		    aml_nodename(node->parent));
513 		return 0;
514 	}
515 
516 	bzero(&cmd, sizeof(cmd));
517 	cmd[0].type = AML_OBJTYPE_BUFFER;
518 	cmd[0].v_buffer = (uint8_t *)&i2c_hid_guid;
519 	cmd[0].length = sizeof(i2c_hid_guid);
520 	/* rev */
521 	cmd[1].type = AML_OBJTYPE_INTEGER;
522 	cmd[1].v_integer = 1;
523 	cmd[1].length = 1;
524 	/* func */
525 	cmd[2].type = AML_OBJTYPE_INTEGER;
526 	cmd[2].v_integer = 1; /* HID */
527 	cmd[2].length = 1;
528 	/* not used */
529 	cmd[3].type = AML_OBJTYPE_PACKAGE;
530 	cmd[3].length = 0;
531 
532 	if (aml_evalname(acpi_softc, node->parent, "_DSM", 4, cmd, &res)) {
533 		printf("%s: eval of _DSM at %s failed\n",
534 		    sc->sc_dev.dv_xname, aml_nodename(node->parent));
535 		return 0;
536 	}
537 
538 	if (res.type != AML_OBJTYPE_INTEGER) {
539 		printf("%s: bad _DSM result at %s: %d\n",
540 		    sc->sc_dev.dv_xname, aml_nodename(node->parent), res.type);
541 		aml_freevalue(&res);
542 		return 0;
543 	}
544 
545 	memset(&ia, 0, sizeof(ia));
546 	ia.ia_tag = sc->sc_iba.iba_tag;
547 	ia.ia_size = 1;
548 	ia.ia_name = "ihidev";
549 	ia.ia_size = aml_val2int(&res); /* hid descriptor address */
550 	ia.ia_addr = crs.i2c_addr;
551 	ia.ia_cookie = dev;
552 
553 	aml_freevalue(&res);
554 
555 	if (sc->sc_poll_ihidev)
556 		ia.ia_poll = 1;
557 	if (!(crs.irq_int == 0 && crs.gpio_int_node == NULL))
558 		ia.ia_intr = &crs;
559 
560 	if (config_found(sc->sc_iic, &ia, dwiic_i2c_print)) {
561 		node->parent->attached = 1;
562 		return 0;
563 	}
564 
565 	return 1;
566 }
567 
568 int
569 dwiic_acpi_found_ietp(struct dwiic_softc *sc, struct aml_node *node,
570     char *dev, struct dwiic_crs crs)
571 {
572 	struct i2c_attach_args ia;
573 
574 	memset(&ia, 0, sizeof(ia));
575 	ia.ia_tag = sc->sc_iba.iba_tag;
576 	ia.ia_size = 1;
577 	ia.ia_name = "ietp";
578 	ia.ia_addr = crs.i2c_addr;
579 	ia.ia_cookie = dev;
580 
581 	if (sc->sc_poll_ihidev)
582 		ia.ia_poll = 1;
583 	if (!(crs.irq_int == 0 && crs.gpio_int_node == NULL))
584 		ia.ia_intr = &crs;
585 
586 	if (config_found(sc->sc_iic, &ia, dwiic_i2c_print)) {
587 		node->parent->attached = 1;
588 		return 0;
589 	}
590 
591 	return 1;
592 }
593 
594 int
595 dwiic_acpi_found_iatp(struct dwiic_softc *sc, struct aml_node *node, char *dev,
596     struct dwiic_crs crs)
597 {
598 	struct i2c_attach_args ia;
599 	struct aml_value res;
600 
601 	if (aml_evalname(acpi_softc, node->parent, "GPIO", 0, NULL, &res))
602 		/* no gpio, assume this is the bootloader interface */
603 		return (0);
604 
605 	memset(&ia, 0, sizeof(ia));
606 	ia.ia_tag = sc->sc_iba.iba_tag;
607 	ia.ia_size = 1;
608 	ia.ia_name = "iatp";
609 	ia.ia_addr = crs.i2c_addr;
610 	ia.ia_cookie = dev;
611 
612 	if (crs.irq_int <= 0 && crs.gpio_int_node == NULL) {
613 		printf("%s: couldn't find irq for %s\n", sc->sc_dev.dv_xname,
614 		   aml_nodename(node->parent));
615 		return 0;
616 	}
617 	ia.ia_intr = &crs;
618 
619 	if (config_found(sc->sc_iic, &ia, dwiic_i2c_print)) {
620 		node->parent->attached = 1;
621 		return 0;
622 	}
623 
624 	return 1;
625 }
626 
627 void
628 dwiic_acpi_power(struct dwiic_softc *sc, int power)
629 {
630 	char ps[] = "_PS0";
631 
632 	if (!power)
633 		ps[3] = '3';
634 
635 	if (aml_searchname(sc->sc_devnode, ps)) {
636 		if (aml_evalname(sc->sc_acpi, sc->sc_devnode, ps, 0, NULL,
637 		    NULL)) {
638 			printf("%s: failed powering %s with %s\n",
639 			    sc->sc_dev.dv_xname, power ? "on" : "off",
640 			    ps);
641 			return;
642 		}
643 
644 		DELAY(10000); /* 10 milliseconds */
645 	} else
646 		DPRINTF(("%s: no %s method\n", sc->sc_dev.dv_xname, ps));
647 
648 	if (strcmp(sc->sc_hid, "INT3432") == 0 ||
649 	    strcmp(sc->sc_hid, "INT3433") == 0) {
650 		/*
651 		 * XXX: broadwell i2c devices may need this for initial power
652 		 * up and/or after s3 resume.
653 		 *
654 		 * linux does this write via LPSS -> clk_register_gate ->
655 		 * clk_gate_enable -> clk_gate_endisable -> clk_writel
656 		 */
657 		dwiic_write(sc, 0x800, 1);
658 	}
659 }
660 
661 #if NIOSF > 0
662 extern int	iosf_i2c_acquire(int);
663 extern void	iosf_i2c_release(int);
664 
665 int
666 dwiic_acpi_acquire_bus(void *cookie, int flags)
667 {
668 	int rv;
669 
670 	rv = dwiic_i2c_acquire_bus(cookie, flags);
671 	if (rv != 0)
672 		return (rv);
673 
674 	return (iosf_i2c_acquire(flags));
675 }
676 
677 void
678 dwiic_acpi_release_bus(void *cookie, int flags)
679 {
680 	iosf_i2c_release(flags);
681 	dwiic_i2c_release_bus(cookie, flags);
682 }
683 #endif /* NIOSF > 0 */
684