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
35struct 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
45int		dwiic_acpi_match(struct device *, void *, void *);
46void		dwiic_acpi_attach(struct device *, struct device *, void *);
47
48int		dwiic_acpi_parse_crs(int, union acpi_resource *, void *);
49int		dwiic_acpi_found_ihidev(struct dwiic_softc *,
50		    struct aml_node *, char *, struct dwiic_crs);
51int		dwiic_acpi_found_iatp(struct dwiic_softc *, struct aml_node *,
52		    char *, struct dwiic_crs);
53int		dwiic_acpi_found_ietp(struct dwiic_softc *, struct aml_node *,
54		    char *, struct dwiic_crs);
55void		dwiic_acpi_get_params(struct dwiic_softc *, char *, uint16_t *,
56		    uint16_t *, uint32_t *);
57void		dwiic_acpi_power(struct dwiic_softc *, int);
58void		dwiic_acpi_bus_scan(struct device *,
59		    struct i2cbus_attach_args *, void *);
60
61#if NIOSF > 0
62int		dwiic_acpi_acquire_bus(void *, int);
63void		dwiic_acpi_release_bus(void *, int);
64#endif
65
66const 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
74const char *dwiic_hids[] = {
75	"AMDI0010",
76	"APMC0D0F",
77	"INT33C2",
78	"INT33C3",
79	"INT3432",
80	"INT3433",
81	"80860F41",
82	"808622C1",
83	NULL
84};
85
86const char *ihidev_hids[] = {
87	"PNP0C50",
88	"ACPI0C50",
89	NULL
90};
91
92const 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
149const char *iatp_hids[] = {
150	"ATML0000",
151	"ATML0001",
152	NULL
153};
154
155int
156dwiic_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
166void
167dwiic_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
275int
276dwiic_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
333void
334dwiic_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
367void
368dwiic_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
377void *
378dwiic_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
398void
399dwiic_i2c_intr_disestablish(void *cookie, void *ih)
400{
401	/* XXX GPIO interrupts */
402	acpi_intr_disestablish(ih);
403}
404
405const char *
406dwiic_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
421int
422dwiic_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
433int
434dwiic_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
497int
498dwiic_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
568int
569dwiic_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
594int
595dwiic_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
627void
628dwiic_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
662extern int	iosf_i2c_acquire(int);
663extern void	iosf_i2c_release(int);
664
665int
666dwiic_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
677void
678dwiic_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