xref: /openbsd/sys/dev/pci/ichiic.c (revision a4663606)
1*a4663606Sjsg /*	$OpenBSD: ichiic.c,v 1.49 2022/06/21 04:17:21 jsg Exp $	*/
23b00bf77Sgrange 
33b00bf77Sgrange /*
4a547cd46Sgrange  * Copyright (c) 2005, 2006 Alexander Yurchenko <grange@openbsd.org>
53b00bf77Sgrange  *
63b00bf77Sgrange  * Permission to use, copy, modify, and distribute this software for any
73b00bf77Sgrange  * purpose with or without fee is hereby granted, provided that the above
83b00bf77Sgrange  * copyright notice and this permission notice appear in all copies.
93b00bf77Sgrange  *
103b00bf77Sgrange  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
113b00bf77Sgrange  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
123b00bf77Sgrange  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
133b00bf77Sgrange  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
143b00bf77Sgrange  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
153b00bf77Sgrange  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
163b00bf77Sgrange  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
173b00bf77Sgrange  */
183b00bf77Sgrange 
193b00bf77Sgrange /*
203b00bf77Sgrange  * Intel ICH SMBus controller driver.
213b00bf77Sgrange  */
223b00bf77Sgrange 
233b00bf77Sgrange #include <sys/param.h>
243b00bf77Sgrange #include <sys/systm.h>
253b00bf77Sgrange #include <sys/device.h>
263b00bf77Sgrange #include <sys/kernel.h>
2773550447Sdlg #include <sys/rwlock.h>
283b00bf77Sgrange 
293b00bf77Sgrange #include <machine/bus.h>
303b00bf77Sgrange 
313b00bf77Sgrange #include <dev/pci/pcidevs.h>
323b00bf77Sgrange #include <dev/pci/pcireg.h>
333b00bf77Sgrange #include <dev/pci/pcivar.h>
343b00bf77Sgrange 
353b00bf77Sgrange #include <dev/pci/ichreg.h>
363b00bf77Sgrange 
373b00bf77Sgrange #include <dev/i2c/i2cvar.h>
383b00bf77Sgrange 
393b00bf77Sgrange #ifdef ICHIIC_DEBUG
403b00bf77Sgrange #define DPRINTF(x) printf x
413b00bf77Sgrange #else
423b00bf77Sgrange #define DPRINTF(x)
433b00bf77Sgrange #endif
443b00bf77Sgrange 
453b00bf77Sgrange #define ICHIIC_DELAY	100
463b00bf77Sgrange #define ICHIIC_TIMEOUT	1
473b00bf77Sgrange 
483b00bf77Sgrange struct ichiic_softc {
493b00bf77Sgrange 	struct device		sc_dev;
503b00bf77Sgrange 
513b00bf77Sgrange 	bus_space_tag_t		sc_iot;
523b00bf77Sgrange 	bus_space_handle_t	sc_ioh;
533b00bf77Sgrange 	void *			sc_ih;
54749dbd03Sgrange 	int			sc_poll;
553b00bf77Sgrange 
563b00bf77Sgrange 	struct i2c_controller	sc_i2c_tag;
5773550447Sdlg 	struct rwlock		sc_i2c_lock;
58c17198b5Sgrange 	struct {
593b00bf77Sgrange 		i2c_op_t     op;
603b00bf77Sgrange 		void *       buf;
613b00bf77Sgrange 		size_t       len;
623b00bf77Sgrange 		int          flags;
63c17198b5Sgrange 		volatile int error;
643b00bf77Sgrange 	}			sc_i2c_xfer;
653b00bf77Sgrange };
663b00bf77Sgrange 
673b00bf77Sgrange int	ichiic_match(struct device *, void *, void *);
683b00bf77Sgrange void	ichiic_attach(struct device *, struct device *, void *);
693b00bf77Sgrange 
703b00bf77Sgrange int	ichiic_i2c_acquire_bus(void *, int);
713b00bf77Sgrange void	ichiic_i2c_release_bus(void *, int);
723b00bf77Sgrange int	ichiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
733b00bf77Sgrange 	    void *, size_t, int);
743b00bf77Sgrange 
753b00bf77Sgrange int	ichiic_intr(void *);
763b00bf77Sgrange 
778d2c75e4Smpi const struct cfattach ichiic_ca = {
783b00bf77Sgrange 	sizeof(struct ichiic_softc),
793b00bf77Sgrange 	ichiic_match,
803b00bf77Sgrange 	ichiic_attach
813b00bf77Sgrange };
823b00bf77Sgrange 
833b00bf77Sgrange struct cfdriver ichiic_cd = {
843b00bf77Sgrange 	NULL, "ichiic", DV_DULL
853b00bf77Sgrange };
863b00bf77Sgrange 
873b00bf77Sgrange const struct pci_matchid ichiic_ids[] = {
888e056978Ssthen 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_3400_SMB },
89d22bb502Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6SERIES_SMB },
909eb33f7aSbrad 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6300ESB_SMB },
91ae7cc0c1Sbrad 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6321ESB_SMB },
92c9849cecSjasper 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_7SERIES_SMB },
93aa424616Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_8SERIES_SMB },
94aa424616Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_8SERIES_LP_SMB },
95fb0880c9Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_9SERIES_SMB },
96fb0880c9Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_9SERIES_LP_SMB },
973b00bf77Sgrange 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_SMB },
983b00bf77Sgrange 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AB_SMB },
993b00bf77Sgrange 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_SMB },
1003b00bf77Sgrange 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CA_SMB },
1013b00bf77Sgrange 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801DB_SMB },
1029eb33f7aSbrad 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801E_SMB },
1033b00bf77Sgrange 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801EB_SMB },
1043b00bf77Sgrange 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801FB_SMB },
105e182382cSbrad 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GB_SMB },
106a2cd58f7Sbrad 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801H_SMB },
107a54030c0Sbrad 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801I_SMB },
1088e056978Ssthen 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801JD_SMB },
10954d12d52Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801JI_SMB },
110d91cfd19Shenning 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_SMB },
111acabe721Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ATOMC2000_PCU_SMB },
112f00a52a0Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_BAYTRAIL_SMB },
113f00a52a0Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_BRASWELL_SMB },
114b19a9072Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C600_SMB },
115cb711e62Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C600_SMB_IDF_1 },
116cb711e62Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C600_SMB_IDF_2 },
117cb711e62Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C600_SMB_IDF_3 },
11818ec9edcSjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C610_SMB },
11918ec9edcSjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C610_MS_SMB_1 },
12018ec9edcSjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C610_MS_SMB_2 },
12118ec9edcSjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C610_MS_SMB_3 },
1228e8ebef9Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C620_SMB },
123cb711e62Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_DH8900_SMB },
124f5c876d9Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EP80579_SMBUS },
1258e8ebef9Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_GLK_SMB },
126266aef52Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_SMB },
127079a7ecbSjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_LP_SMB },
128c4dfe020Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_200SERIES_SMB },
129c4dfe020Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_300SERIES_SMB },
1308e8ebef9Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_300SERIES_U_SMB },
1318e8ebef9Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_400SERIES_SMB },
1328e8ebef9Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_400SERIES_LP_SMB },
1338e8ebef9Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_400SERIES_V_SMB },
1348e8ebef9Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_495SERIES_LP_SMB },
13577a9f4bbSjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_500SERIES_SMB },
1368e8ebef9Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_500SERIES_LP_SMB },
13761553a4eSjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_600SERIES_SMB },
138*a4663606Sjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_600SERIES_LP_SMB },
139d6969a1fSjsg 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_JSL_SMB },
1403b00bf77Sgrange };
1413b00bf77Sgrange 
1423b00bf77Sgrange int
1433b00bf77Sgrange ichiic_match(struct device *parent, void *match, void *aux)
1443b00bf77Sgrange {
1453b00bf77Sgrange 	return (pci_matchbyid(aux, ichiic_ids,
1463b00bf77Sgrange 	    sizeof(ichiic_ids) / sizeof(ichiic_ids[0])));
1473b00bf77Sgrange }
1483b00bf77Sgrange 
1493b00bf77Sgrange void
1503b00bf77Sgrange ichiic_attach(struct device *parent, struct device *self, void *aux)
1513b00bf77Sgrange {
1523b00bf77Sgrange 	struct ichiic_softc *sc = (struct ichiic_softc *)self;
1533b00bf77Sgrange 	struct pci_attach_args *pa = aux;
1543b00bf77Sgrange 	struct i2cbus_attach_args iba;
155749dbd03Sgrange 	pcireg_t conf;
1563b00bf77Sgrange 	bus_size_t iosize;
1573b00bf77Sgrange 	pci_intr_handle_t ih;
1583b00bf77Sgrange 	const char *intrstr = NULL;
1593b00bf77Sgrange 
160d204c798Sgrange 	/* Read configuration */
161d204c798Sgrange 	conf = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_SMB_HOSTC);
1626f23e57aSgrange 	DPRINTF((": conf 0x%08x", conf));
163d204c798Sgrange 
164d204c798Sgrange 	if ((conf & ICH_SMB_HOSTC_HSTEN) == 0) {
165d204c798Sgrange 		printf(": SMBus disabled\n");
166d204c798Sgrange 		return;
167d204c798Sgrange 	}
168d204c798Sgrange 
1693b00bf77Sgrange 	/* Map I/O space */
1703b00bf77Sgrange 	if (pci_mapreg_map(pa, ICH_SMB_BASE, PCI_MAPREG_TYPE_IO, 0,
1713b00bf77Sgrange 	    &sc->sc_iot, &sc->sc_ioh, NULL, &iosize, 0)) {
172e10c952fSsthen 		printf(": can't map i/o space\n");
1733b00bf77Sgrange 		return;
1743b00bf77Sgrange 	}
1753b00bf77Sgrange 
176749dbd03Sgrange 	sc->sc_poll = 1;
177e3269dfcSgrange 	if (conf & ICH_SMB_HOSTC_SMIEN) {
178e3269dfcSgrange 		/* No PCI IRQ */
179e3269dfcSgrange 		printf(": SMI");
180749dbd03Sgrange 	} else {
1813b00bf77Sgrange 		/* Install interrupt handler */
182e3269dfcSgrange 		if (pci_intr_map(pa, &ih) == 0) {
1833b00bf77Sgrange 			intrstr = pci_intr_string(pa->pa_pc, ih);
184749dbd03Sgrange 			sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
185749dbd03Sgrange 			    ichiic_intr, sc, sc->sc_dev.dv_xname);
186e3269dfcSgrange 			if (sc->sc_ih != NULL) {
1873b00bf77Sgrange 				printf(": %s", intrstr);
188e3269dfcSgrange 				sc->sc_poll = 0;
189e3269dfcSgrange 			}
190e3269dfcSgrange 		}
191e3269dfcSgrange 		if (sc->sc_poll)
192e3269dfcSgrange 			printf(": polling");
193749dbd03Sgrange 	}
1943b00bf77Sgrange 
1953b00bf77Sgrange 	printf("\n");
1963b00bf77Sgrange 
1973b00bf77Sgrange 	/* Attach I2C bus */
19873550447Sdlg 	rw_init(&sc->sc_i2c_lock, "iiclk");
1993b00bf77Sgrange 	sc->sc_i2c_tag.ic_cookie = sc;
2003b00bf77Sgrange 	sc->sc_i2c_tag.ic_acquire_bus = ichiic_i2c_acquire_bus;
2013b00bf77Sgrange 	sc->sc_i2c_tag.ic_release_bus = ichiic_i2c_release_bus;
2023b00bf77Sgrange 	sc->sc_i2c_tag.ic_exec = ichiic_i2c_exec;
203a5a63700Sderaadt 
204f57d9f10Sgrange 	bzero(&iba, sizeof(iba));
2053b00bf77Sgrange 	iba.iba_name = "iic";
2063b00bf77Sgrange 	iba.iba_tag = &sc->sc_i2c_tag;
2073b00bf77Sgrange 	config_found(self, &iba, iicbus_print);
2083b00bf77Sgrange 
2093b00bf77Sgrange 	return;
2103b00bf77Sgrange }
2113b00bf77Sgrange 
2123b00bf77Sgrange int
2133b00bf77Sgrange ichiic_i2c_acquire_bus(void *cookie, int flags)
2143b00bf77Sgrange {
2153b00bf77Sgrange 	struct ichiic_softc *sc = cookie;
2163b00bf77Sgrange 
2177ecfa26eSgrange 	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
2183b00bf77Sgrange 		return (0);
2193b00bf77Sgrange 
22073550447Sdlg 	return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
2213b00bf77Sgrange }
2223b00bf77Sgrange 
2233b00bf77Sgrange void
2243b00bf77Sgrange ichiic_i2c_release_bus(void *cookie, int flags)
2253b00bf77Sgrange {
2263b00bf77Sgrange 	struct ichiic_softc *sc = cookie;
2273b00bf77Sgrange 
2287ecfa26eSgrange 	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
2293b00bf77Sgrange 		return;
2303b00bf77Sgrange 
23173550447Sdlg 	rw_exit(&sc->sc_i2c_lock);
2323b00bf77Sgrange }
2333b00bf77Sgrange 
2343b00bf77Sgrange int
2353b00bf77Sgrange ichiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
2363b00bf77Sgrange     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
2373b00bf77Sgrange {
2383b00bf77Sgrange 	struct ichiic_softc *sc = cookie;
2393b00bf77Sgrange 	u_int8_t *b;
2403b00bf77Sgrange 	u_int8_t ctl, st;
2413b00bf77Sgrange 	int retries;
2423b00bf77Sgrange 
2436f23e57aSgrange 	DPRINTF(("%s: exec: op %d, addr 0x%02x, cmdlen %d, len %d, "
2446f23e57aSgrange 	    "flags 0x%02x\n", sc->sc_dev.dv_xname, op, addr, cmdlen,
2456f23e57aSgrange 	    len, flags));
246d204c798Sgrange 
247c90a9223Sgrange 	/* Wait for bus to be idle */
248c90a9223Sgrange 	for (retries = 100; retries > 0; retries--) {
249d204c798Sgrange 		st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
250c90a9223Sgrange 		if (!(st & ICH_SMB_HS_BUSY))
251c90a9223Sgrange 			break;
252c90a9223Sgrange 		DELAY(ICHIIC_DELAY);
253c90a9223Sgrange 	}
254d204c798Sgrange 	DPRINTF(("%s: exec: st 0x%b\n", sc->sc_dev.dv_xname, st,
255d204c798Sgrange 	    ICH_SMB_HS_BITS));
256d204c798Sgrange 	if (st & ICH_SMB_HS_BUSY)
257c5eaf0b6Sgrange 		return (1);
258749dbd03Sgrange 
2597ecfa26eSgrange 	if (cold || sc->sc_poll)
260749dbd03Sgrange 		flags |= I2C_F_POLL;
2613b00bf77Sgrange 
2623b00bf77Sgrange 	if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
263c5eaf0b6Sgrange 		return (1);
2643b00bf77Sgrange 
2653b00bf77Sgrange 	/* Setup transfer */
2663b00bf77Sgrange 	sc->sc_i2c_xfer.op = op;
2673b00bf77Sgrange 	sc->sc_i2c_xfer.buf = buf;
2683b00bf77Sgrange 	sc->sc_i2c_xfer.len = len;
2693b00bf77Sgrange 	sc->sc_i2c_xfer.flags = flags;
2703b00bf77Sgrange 	sc->sc_i2c_xfer.error = 0;
2713b00bf77Sgrange 
2723b00bf77Sgrange 	/* Set slave address and transfer direction */
2733b00bf77Sgrange 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_TXSLVA,
2743b00bf77Sgrange 	    ICH_SMB_TXSLVA_ADDR(addr) |
2753b00bf77Sgrange 	    (I2C_OP_READ_P(op) ? ICH_SMB_TXSLVA_READ : 0));
2763b00bf77Sgrange 
2773b00bf77Sgrange 	b = (void *)cmdbuf;
2783b00bf77Sgrange 	if (cmdlen > 0)
2793b00bf77Sgrange 		/* Set command byte */
2803b00bf77Sgrange 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HCMD, b[0]);
2813b00bf77Sgrange 
2823b00bf77Sgrange 	if (I2C_OP_WRITE_P(op)) {
2833b00bf77Sgrange 		/* Write data */
2843b00bf77Sgrange 		b = buf;
2853b00bf77Sgrange 		if (len > 0)
2863b00bf77Sgrange 			bus_space_write_1(sc->sc_iot, sc->sc_ioh,
2873b00bf77Sgrange 			    ICH_SMB_HD0, b[0]);
2883b00bf77Sgrange 		if (len > 1)
2893b00bf77Sgrange 			bus_space_write_1(sc->sc_iot, sc->sc_ioh,
2903b00bf77Sgrange 			    ICH_SMB_HD1, b[1]);
2913b00bf77Sgrange 	}
2923b00bf77Sgrange 
2933b00bf77Sgrange 	/* Set SMBus command */
2943b00bf77Sgrange 	if (len == 0)
2953b00bf77Sgrange 		ctl = ICH_SMB_HC_CMD_BYTE;
2963b00bf77Sgrange 	else if (len == 1)
2973b00bf77Sgrange 		ctl = ICH_SMB_HC_CMD_BDATA;
2983b00bf77Sgrange 	else if (len == 2)
2993b00bf77Sgrange 		ctl = ICH_SMB_HC_CMD_WDATA;
300c0d07f7cShaesbaert 	else
301c0d07f7cShaesbaert 		panic("%s: unexpected len %zd", __func__, len);
3023b00bf77Sgrange 
3033b00bf77Sgrange 	if ((flags & I2C_F_POLL) == 0)
3043b00bf77Sgrange 		ctl |= ICH_SMB_HC_INTREN;
3053b00bf77Sgrange 
3063b00bf77Sgrange 	/* Start transaction */
3073b00bf77Sgrange 	ctl |= ICH_SMB_HC_START;
3083b00bf77Sgrange 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HC, ctl);
3093b00bf77Sgrange 
3103b00bf77Sgrange 	if (flags & I2C_F_POLL) {
3113b00bf77Sgrange 		/* Poll for completion */
3123b00bf77Sgrange 		DELAY(ICHIIC_DELAY);
3133b00bf77Sgrange 		for (retries = 1000; retries > 0; retries--) {
3143b00bf77Sgrange 			st = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
3153b00bf77Sgrange 			    ICH_SMB_HS);
3163b00bf77Sgrange 			if ((st & ICH_SMB_HS_BUSY) == 0)
3173b00bf77Sgrange 				break;
3183b00bf77Sgrange 			DELAY(ICHIIC_DELAY);
3193b00bf77Sgrange 		}
320d204c798Sgrange 		if (st & ICH_SMB_HS_BUSY)
321d204c798Sgrange 			goto timeout;
3223b00bf77Sgrange 		ichiic_intr(sc);
3233b00bf77Sgrange 	} else {
324c17198b5Sgrange 		/* Wait for interrupt */
3258544fed6Smpi 		if (tsleep_nsec(sc, PRIBIO, "ichiic",
3268544fed6Smpi 		    SEC_TO_NSEC(ICHIIC_TIMEOUT)))
327d204c798Sgrange 			goto timeout;
3283b00bf77Sgrange 	}
3293b00bf77Sgrange 
3303b00bf77Sgrange 	if (sc->sc_i2c_xfer.error)
3313b00bf77Sgrange 		return (1);
3323b00bf77Sgrange 
3333b00bf77Sgrange 	return (0);
334d204c798Sgrange 
335d204c798Sgrange timeout:
336d204c798Sgrange 	/*
337d204c798Sgrange 	 * Transfer timeout. Kill the transaction and clear status bits.
338d204c798Sgrange 	 */
339d204c798Sgrange 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HC,
340d204c798Sgrange 	    ICH_SMB_HC_KILL);
341d204c798Sgrange 	DELAY(ICHIIC_DELAY);
342d204c798Sgrange 	st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
343d204c798Sgrange 	if ((st & ICH_SMB_HS_FAILED) == 0)
3446f23e57aSgrange 		printf("%s: abort failed, status 0x%b\n",
345d204c798Sgrange 		    sc->sc_dev.dv_xname, st, ICH_SMB_HS_BITS);
346d204c798Sgrange 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS, st);
347d204c798Sgrange 	return (1);
3483b00bf77Sgrange }
3493b00bf77Sgrange 
3503b00bf77Sgrange int
3513b00bf77Sgrange ichiic_intr(void *arg)
3523b00bf77Sgrange {
3533b00bf77Sgrange 	struct ichiic_softc *sc = arg;
3543b00bf77Sgrange 	u_int8_t st;
3553b00bf77Sgrange 	u_int8_t *b;
3563b00bf77Sgrange 	size_t len;
3573b00bf77Sgrange 
3583b00bf77Sgrange 	/* Read status */
3593b00bf77Sgrange 	st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
3600c9bc80bSstsp 
3610c9bc80bSstsp 	/* Clear status bits */
3620c9bc80bSstsp 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS, st);
3630c9bc80bSstsp 
3640c9bc80bSstsp 	/* XXX Ignore SMBALERT# for now */
3653b00bf77Sgrange 	if ((st & ICH_SMB_HS_BUSY) != 0 || (st & (ICH_SMB_HS_INTR |
3663b00bf77Sgrange 	    ICH_SMB_HS_DEVERR | ICH_SMB_HS_BUSERR | ICH_SMB_HS_FAILED |
3670c9bc80bSstsp 	    ICH_SMB_HS_BDONE)) == 0)
3683b00bf77Sgrange 		/* Interrupt was not for us */
3693b00bf77Sgrange 		return (0);
3703b00bf77Sgrange 
3713b00bf77Sgrange 	DPRINTF(("%s: intr st 0x%b\n", sc->sc_dev.dv_xname, st,
3723b00bf77Sgrange 	    ICH_SMB_HS_BITS));
3733b00bf77Sgrange 
3743b00bf77Sgrange 	/* Check for errors */
3753b00bf77Sgrange 	if (st & (ICH_SMB_HS_DEVERR | ICH_SMB_HS_BUSERR | ICH_SMB_HS_FAILED)) {
3763b00bf77Sgrange 		sc->sc_i2c_xfer.error = 1;
3773b00bf77Sgrange 		goto done;
3783b00bf77Sgrange 	}
3793b00bf77Sgrange 
3803b00bf77Sgrange 	if (st & ICH_SMB_HS_INTR) {
3813b00bf77Sgrange 		if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
3823b00bf77Sgrange 			goto done;
3833b00bf77Sgrange 
3843b00bf77Sgrange 		/* Read data */
3853b00bf77Sgrange 		b = sc->sc_i2c_xfer.buf;
3863b00bf77Sgrange 		len = sc->sc_i2c_xfer.len;
3873b00bf77Sgrange 		if (len > 0)
3883b00bf77Sgrange 			b[0] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
3893b00bf77Sgrange 			    ICH_SMB_HD0);
3903b00bf77Sgrange 		if (len > 1)
3913b00bf77Sgrange 			b[1] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
3923b00bf77Sgrange 			    ICH_SMB_HD1);
3933b00bf77Sgrange 	}
3943b00bf77Sgrange 
3953b00bf77Sgrange done:
3963b00bf77Sgrange 	if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
3973b00bf77Sgrange 		wakeup(sc);
3983b00bf77Sgrange 	return (1);
3993b00bf77Sgrange }
400