1*b9a034e3Sjsg /* $OpenBSD: ichiic.c,v 1.56 2024/07/16 01:14:23 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>
2673550447Sdlg #include <sys/rwlock.h>
273b00bf77Sgrange
283b00bf77Sgrange #include <machine/bus.h>
293b00bf77Sgrange
303b00bf77Sgrange #include <dev/pci/pcidevs.h>
313b00bf77Sgrange #include <dev/pci/pcireg.h>
323b00bf77Sgrange #include <dev/pci/pcivar.h>
333b00bf77Sgrange
343b00bf77Sgrange #include <dev/pci/ichreg.h>
353b00bf77Sgrange
363b00bf77Sgrange #include <dev/i2c/i2cvar.h>
373b00bf77Sgrange
383b00bf77Sgrange #ifdef ICHIIC_DEBUG
393b00bf77Sgrange #define DPRINTF(x) printf x
403b00bf77Sgrange #else
413b00bf77Sgrange #define DPRINTF(x)
423b00bf77Sgrange #endif
433b00bf77Sgrange
443b00bf77Sgrange #define ICHIIC_DELAY 100
453b00bf77Sgrange #define ICHIIC_TIMEOUT 1
463b00bf77Sgrange
473b00bf77Sgrange struct ichiic_softc {
483b00bf77Sgrange struct device sc_dev;
493b00bf77Sgrange
503b00bf77Sgrange bus_space_tag_t sc_iot;
513b00bf77Sgrange bus_space_handle_t sc_ioh;
523b00bf77Sgrange void * sc_ih;
53749dbd03Sgrange int sc_poll;
543b00bf77Sgrange
553b00bf77Sgrange struct i2c_controller sc_i2c_tag;
5673550447Sdlg struct rwlock sc_i2c_lock;
57c17198b5Sgrange struct {
583b00bf77Sgrange i2c_op_t op;
593b00bf77Sgrange void * buf;
603b00bf77Sgrange size_t len;
613b00bf77Sgrange int flags;
62c17198b5Sgrange volatile int error;
633b00bf77Sgrange } sc_i2c_xfer;
643b00bf77Sgrange };
653b00bf77Sgrange
663b00bf77Sgrange int ichiic_match(struct device *, void *, void *);
673b00bf77Sgrange void ichiic_attach(struct device *, struct device *, void *);
683b00bf77Sgrange
693b00bf77Sgrange int ichiic_i2c_acquire_bus(void *, int);
703b00bf77Sgrange void ichiic_i2c_release_bus(void *, int);
713b00bf77Sgrange int ichiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
723b00bf77Sgrange void *, size_t, int);
733b00bf77Sgrange
743b00bf77Sgrange int ichiic_intr(void *);
753b00bf77Sgrange
768d2c75e4Smpi const struct cfattach ichiic_ca = {
773b00bf77Sgrange sizeof(struct ichiic_softc),
783b00bf77Sgrange ichiic_match,
793b00bf77Sgrange ichiic_attach
803b00bf77Sgrange };
813b00bf77Sgrange
823b00bf77Sgrange struct cfdriver ichiic_cd = {
833b00bf77Sgrange NULL, "ichiic", DV_DULL
843b00bf77Sgrange };
853b00bf77Sgrange
863b00bf77Sgrange const struct pci_matchid ichiic_ids[] = {
878e056978Ssthen { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_3400_SMB },
88d22bb502Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6SERIES_SMB },
899eb33f7aSbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6300ESB_SMB },
90ae7cc0c1Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6321ESB_SMB },
91c9849cecSjasper { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_7SERIES_SMB },
92aa424616Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_8SERIES_SMB },
93aa424616Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_8SERIES_LP_SMB },
94fb0880c9Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_9SERIES_SMB },
95fb0880c9Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_9SERIES_LP_SMB },
963b00bf77Sgrange { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_SMB },
973b00bf77Sgrange { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AB_SMB },
983b00bf77Sgrange { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_SMB },
993b00bf77Sgrange { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CA_SMB },
1003b00bf77Sgrange { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801DB_SMB },
1019eb33f7aSbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801E_SMB },
1023b00bf77Sgrange { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801EB_SMB },
1033b00bf77Sgrange { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801FB_SMB },
104e182382cSbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GB_SMB },
105a2cd58f7Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801H_SMB },
106a54030c0Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801I_SMB },
1078e056978Ssthen { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801JD_SMB },
10854d12d52Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801JI_SMB },
109d91cfd19Shenning { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_SMB },
110acabe721Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ATOMC2000_PCU_SMB },
111*b9a034e3Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C3000_SMB_2 },
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 },
123921b38aeSjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C740_SMB },
124cb711e62Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_DH8900_SMB },
125f5c876d9Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EP80579_SMBUS },
1268e8ebef9Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_GLK_SMB },
127266aef52Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_SMB },
128079a7ecbSjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_LP_SMB },
129c4dfe020Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_200SERIES_SMB },
130c4dfe020Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_300SERIES_SMB },
1318e8ebef9Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_300SERIES_U_SMB },
1328e8ebef9Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_400SERIES_SMB },
1338e8ebef9Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_400SERIES_LP_SMB },
1348e8ebef9Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_400SERIES_V_SMB },
1358e8ebef9Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_495SERIES_LP_SMB },
13677a9f4bbSjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_500SERIES_SMB },
1378e8ebef9Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_500SERIES_LP_SMB },
13861553a4eSjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_600SERIES_SMB },
139a4663606Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_600SERIES_LP_SMB },
1402f265c1fSjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_700SERIES_SMB },
141d6969a1fSjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_JSL_SMB },
142f9c5e991Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EHL_SMB },
1433f438978Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ADL_N_SMB },
144272d3fc4Sjsg { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MTL_SMB },
1453b00bf77Sgrange };
1463b00bf77Sgrange
1473b00bf77Sgrange int
ichiic_match(struct device * parent,void * match,void * aux)1483b00bf77Sgrange ichiic_match(struct device *parent, void *match, void *aux)
1493b00bf77Sgrange {
1503b00bf77Sgrange return (pci_matchbyid(aux, ichiic_ids,
1513b00bf77Sgrange sizeof(ichiic_ids) / sizeof(ichiic_ids[0])));
1523b00bf77Sgrange }
1533b00bf77Sgrange
1543b00bf77Sgrange void
ichiic_attach(struct device * parent,struct device * self,void * aux)1553b00bf77Sgrange ichiic_attach(struct device *parent, struct device *self, void *aux)
1563b00bf77Sgrange {
1573b00bf77Sgrange struct ichiic_softc *sc = (struct ichiic_softc *)self;
1583b00bf77Sgrange struct pci_attach_args *pa = aux;
1593b00bf77Sgrange struct i2cbus_attach_args iba;
160749dbd03Sgrange pcireg_t conf;
1613b00bf77Sgrange bus_size_t iosize;
1623b00bf77Sgrange pci_intr_handle_t ih;
1633b00bf77Sgrange const char *intrstr = NULL;
1643b00bf77Sgrange
165d204c798Sgrange /* Read configuration */
166d204c798Sgrange conf = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_SMB_HOSTC);
1676f23e57aSgrange DPRINTF((": conf 0x%08x", conf));
168d204c798Sgrange
169d204c798Sgrange if ((conf & ICH_SMB_HOSTC_HSTEN) == 0) {
170d204c798Sgrange printf(": SMBus disabled\n");
171d204c798Sgrange return;
172d204c798Sgrange }
173d204c798Sgrange
1743b00bf77Sgrange /* Map I/O space */
1753b00bf77Sgrange if (pci_mapreg_map(pa, ICH_SMB_BASE, PCI_MAPREG_TYPE_IO, 0,
1763b00bf77Sgrange &sc->sc_iot, &sc->sc_ioh, NULL, &iosize, 0)) {
177e10c952fSsthen printf(": can't map i/o space\n");
1783b00bf77Sgrange return;
1793b00bf77Sgrange }
1803b00bf77Sgrange
181749dbd03Sgrange sc->sc_poll = 1;
182e3269dfcSgrange if (conf & ICH_SMB_HOSTC_SMIEN) {
183e3269dfcSgrange /* No PCI IRQ */
184e3269dfcSgrange printf(": SMI");
185749dbd03Sgrange } else {
1863b00bf77Sgrange /* Install interrupt handler */
187e3269dfcSgrange if (pci_intr_map(pa, &ih) == 0) {
1883b00bf77Sgrange intrstr = pci_intr_string(pa->pa_pc, ih);
189749dbd03Sgrange sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
190749dbd03Sgrange ichiic_intr, sc, sc->sc_dev.dv_xname);
191e3269dfcSgrange if (sc->sc_ih != NULL) {
1923b00bf77Sgrange printf(": %s", intrstr);
193e3269dfcSgrange sc->sc_poll = 0;
194e3269dfcSgrange }
195e3269dfcSgrange }
196e3269dfcSgrange if (sc->sc_poll)
197e3269dfcSgrange printf(": polling");
198749dbd03Sgrange }
1993b00bf77Sgrange
2003b00bf77Sgrange printf("\n");
2013b00bf77Sgrange
2023b00bf77Sgrange /* Attach I2C bus */
20373550447Sdlg rw_init(&sc->sc_i2c_lock, "iiclk");
2043b00bf77Sgrange sc->sc_i2c_tag.ic_cookie = sc;
2053b00bf77Sgrange sc->sc_i2c_tag.ic_acquire_bus = ichiic_i2c_acquire_bus;
2063b00bf77Sgrange sc->sc_i2c_tag.ic_release_bus = ichiic_i2c_release_bus;
2073b00bf77Sgrange sc->sc_i2c_tag.ic_exec = ichiic_i2c_exec;
208a5a63700Sderaadt
209f57d9f10Sgrange bzero(&iba, sizeof(iba));
2103b00bf77Sgrange iba.iba_name = "iic";
2113b00bf77Sgrange iba.iba_tag = &sc->sc_i2c_tag;
2123b00bf77Sgrange config_found(self, &iba, iicbus_print);
2133b00bf77Sgrange
2143b00bf77Sgrange return;
2153b00bf77Sgrange }
2163b00bf77Sgrange
2173b00bf77Sgrange int
ichiic_i2c_acquire_bus(void * cookie,int flags)2183b00bf77Sgrange ichiic_i2c_acquire_bus(void *cookie, int flags)
2193b00bf77Sgrange {
2203b00bf77Sgrange struct ichiic_softc *sc = cookie;
2213b00bf77Sgrange
2227ecfa26eSgrange if (cold || sc->sc_poll || (flags & I2C_F_POLL))
2233b00bf77Sgrange return (0);
2243b00bf77Sgrange
22573550447Sdlg return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
2263b00bf77Sgrange }
2273b00bf77Sgrange
2283b00bf77Sgrange void
ichiic_i2c_release_bus(void * cookie,int flags)2293b00bf77Sgrange ichiic_i2c_release_bus(void *cookie, int flags)
2303b00bf77Sgrange {
2313b00bf77Sgrange struct ichiic_softc *sc = cookie;
2323b00bf77Sgrange
2337ecfa26eSgrange if (cold || sc->sc_poll || (flags & I2C_F_POLL))
2343b00bf77Sgrange return;
2353b00bf77Sgrange
23673550447Sdlg rw_exit(&sc->sc_i2c_lock);
2373b00bf77Sgrange }
2383b00bf77Sgrange
2393b00bf77Sgrange int
ichiic_i2c_exec(void * cookie,i2c_op_t op,i2c_addr_t addr,const void * cmdbuf,size_t cmdlen,void * buf,size_t len,int flags)2403b00bf77Sgrange ichiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
2413b00bf77Sgrange const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
2423b00bf77Sgrange {
2433b00bf77Sgrange struct ichiic_softc *sc = cookie;
2443b00bf77Sgrange u_int8_t *b;
2453b00bf77Sgrange u_int8_t ctl, st;
2463b00bf77Sgrange int retries;
2473b00bf77Sgrange
2486f23e57aSgrange DPRINTF(("%s: exec: op %d, addr 0x%02x, cmdlen %d, len %d, "
2496f23e57aSgrange "flags 0x%02x\n", sc->sc_dev.dv_xname, op, addr, cmdlen,
2506f23e57aSgrange len, flags));
251d204c798Sgrange
252c90a9223Sgrange /* Wait for bus to be idle */
253c90a9223Sgrange for (retries = 100; retries > 0; retries--) {
254d204c798Sgrange st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
255c90a9223Sgrange if (!(st & ICH_SMB_HS_BUSY))
256c90a9223Sgrange break;
257c90a9223Sgrange DELAY(ICHIIC_DELAY);
258c90a9223Sgrange }
259d204c798Sgrange DPRINTF(("%s: exec: st 0x%b\n", sc->sc_dev.dv_xname, st,
260d204c798Sgrange ICH_SMB_HS_BITS));
261d204c798Sgrange if (st & ICH_SMB_HS_BUSY)
262c5eaf0b6Sgrange return (1);
263749dbd03Sgrange
2647ecfa26eSgrange if (cold || sc->sc_poll)
265749dbd03Sgrange flags |= I2C_F_POLL;
2663b00bf77Sgrange
2673b00bf77Sgrange if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
268c5eaf0b6Sgrange return (1);
2693b00bf77Sgrange
2703b00bf77Sgrange /* Setup transfer */
2713b00bf77Sgrange sc->sc_i2c_xfer.op = op;
2723b00bf77Sgrange sc->sc_i2c_xfer.buf = buf;
2733b00bf77Sgrange sc->sc_i2c_xfer.len = len;
2743b00bf77Sgrange sc->sc_i2c_xfer.flags = flags;
2753b00bf77Sgrange sc->sc_i2c_xfer.error = 0;
2763b00bf77Sgrange
2773b00bf77Sgrange /* Set slave address and transfer direction */
2783b00bf77Sgrange bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_TXSLVA,
2793b00bf77Sgrange ICH_SMB_TXSLVA_ADDR(addr) |
2803b00bf77Sgrange (I2C_OP_READ_P(op) ? ICH_SMB_TXSLVA_READ : 0));
2813b00bf77Sgrange
2823b00bf77Sgrange b = (void *)cmdbuf;
2833b00bf77Sgrange if (cmdlen > 0)
2843b00bf77Sgrange /* Set command byte */
2853b00bf77Sgrange bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HCMD, b[0]);
2863b00bf77Sgrange
2873b00bf77Sgrange if (I2C_OP_WRITE_P(op)) {
2883b00bf77Sgrange /* Write data */
2893b00bf77Sgrange b = buf;
2903b00bf77Sgrange if (len > 0)
2913b00bf77Sgrange bus_space_write_1(sc->sc_iot, sc->sc_ioh,
2923b00bf77Sgrange ICH_SMB_HD0, b[0]);
2933b00bf77Sgrange if (len > 1)
2943b00bf77Sgrange bus_space_write_1(sc->sc_iot, sc->sc_ioh,
2953b00bf77Sgrange ICH_SMB_HD1, b[1]);
2963b00bf77Sgrange }
2973b00bf77Sgrange
2983b00bf77Sgrange /* Set SMBus command */
2993b00bf77Sgrange if (len == 0)
3003b00bf77Sgrange ctl = ICH_SMB_HC_CMD_BYTE;
3013b00bf77Sgrange else if (len == 1)
3023b00bf77Sgrange ctl = ICH_SMB_HC_CMD_BDATA;
3033b00bf77Sgrange else if (len == 2)
3043b00bf77Sgrange ctl = ICH_SMB_HC_CMD_WDATA;
305c0d07f7cShaesbaert else
306c0d07f7cShaesbaert panic("%s: unexpected len %zd", __func__, len);
3073b00bf77Sgrange
3083b00bf77Sgrange if ((flags & I2C_F_POLL) == 0)
3093b00bf77Sgrange ctl |= ICH_SMB_HC_INTREN;
3103b00bf77Sgrange
3113b00bf77Sgrange /* Start transaction */
3123b00bf77Sgrange ctl |= ICH_SMB_HC_START;
3133b00bf77Sgrange bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HC, ctl);
3143b00bf77Sgrange
3153b00bf77Sgrange if (flags & I2C_F_POLL) {
3163b00bf77Sgrange /* Poll for completion */
3173b00bf77Sgrange DELAY(ICHIIC_DELAY);
3183b00bf77Sgrange for (retries = 1000; retries > 0; retries--) {
3193b00bf77Sgrange st = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
3203b00bf77Sgrange ICH_SMB_HS);
3213b00bf77Sgrange if ((st & ICH_SMB_HS_BUSY) == 0)
3223b00bf77Sgrange break;
3233b00bf77Sgrange DELAY(ICHIIC_DELAY);
3243b00bf77Sgrange }
325d204c798Sgrange if (st & ICH_SMB_HS_BUSY)
326d204c798Sgrange goto timeout;
3273b00bf77Sgrange ichiic_intr(sc);
3283b00bf77Sgrange } else {
329c17198b5Sgrange /* Wait for interrupt */
3308544fed6Smpi if (tsleep_nsec(sc, PRIBIO, "ichiic",
3318544fed6Smpi SEC_TO_NSEC(ICHIIC_TIMEOUT)))
332d204c798Sgrange goto timeout;
3333b00bf77Sgrange }
3343b00bf77Sgrange
3353b00bf77Sgrange if (sc->sc_i2c_xfer.error)
3363b00bf77Sgrange return (1);
3373b00bf77Sgrange
3383b00bf77Sgrange return (0);
339d204c798Sgrange
340d204c798Sgrange timeout:
341d204c798Sgrange /*
342d204c798Sgrange * Transfer timeout. Kill the transaction and clear status bits.
343d204c798Sgrange */
344d204c798Sgrange bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HC,
345d204c798Sgrange ICH_SMB_HC_KILL);
346d204c798Sgrange DELAY(ICHIIC_DELAY);
347d204c798Sgrange st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
348d204c798Sgrange if ((st & ICH_SMB_HS_FAILED) == 0)
3496f23e57aSgrange printf("%s: abort failed, status 0x%b\n",
350d204c798Sgrange sc->sc_dev.dv_xname, st, ICH_SMB_HS_BITS);
351d204c798Sgrange bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS, st);
352d204c798Sgrange return (1);
3533b00bf77Sgrange }
3543b00bf77Sgrange
3553b00bf77Sgrange int
ichiic_intr(void * arg)3563b00bf77Sgrange ichiic_intr(void *arg)
3573b00bf77Sgrange {
3583b00bf77Sgrange struct ichiic_softc *sc = arg;
3593b00bf77Sgrange u_int8_t st;
3603b00bf77Sgrange u_int8_t *b;
3613b00bf77Sgrange size_t len;
3623b00bf77Sgrange
3633b00bf77Sgrange /* Read status */
3643b00bf77Sgrange st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
3650c9bc80bSstsp
3660c9bc80bSstsp /* Clear status bits */
3670c9bc80bSstsp bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS, st);
3680c9bc80bSstsp
3690c9bc80bSstsp /* XXX Ignore SMBALERT# for now */
3703b00bf77Sgrange if ((st & ICH_SMB_HS_BUSY) != 0 || (st & (ICH_SMB_HS_INTR |
3713b00bf77Sgrange ICH_SMB_HS_DEVERR | ICH_SMB_HS_BUSERR | ICH_SMB_HS_FAILED |
3720c9bc80bSstsp ICH_SMB_HS_BDONE)) == 0)
3733b00bf77Sgrange /* Interrupt was not for us */
3743b00bf77Sgrange return (0);
3753b00bf77Sgrange
3763b00bf77Sgrange DPRINTF(("%s: intr st 0x%b\n", sc->sc_dev.dv_xname, st,
3773b00bf77Sgrange ICH_SMB_HS_BITS));
3783b00bf77Sgrange
3793b00bf77Sgrange /* Check for errors */
3803b00bf77Sgrange if (st & (ICH_SMB_HS_DEVERR | ICH_SMB_HS_BUSERR | ICH_SMB_HS_FAILED)) {
3813b00bf77Sgrange sc->sc_i2c_xfer.error = 1;
3823b00bf77Sgrange goto done;
3833b00bf77Sgrange }
3843b00bf77Sgrange
3853b00bf77Sgrange if (st & ICH_SMB_HS_INTR) {
3863b00bf77Sgrange if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
3873b00bf77Sgrange goto done;
3883b00bf77Sgrange
3893b00bf77Sgrange /* Read data */
3903b00bf77Sgrange b = sc->sc_i2c_xfer.buf;
3913b00bf77Sgrange len = sc->sc_i2c_xfer.len;
3923b00bf77Sgrange if (len > 0)
3933b00bf77Sgrange b[0] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
3943b00bf77Sgrange ICH_SMB_HD0);
3953b00bf77Sgrange if (len > 1)
3963b00bf77Sgrange b[1] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
3973b00bf77Sgrange ICH_SMB_HD1);
3983b00bf77Sgrange }
3993b00bf77Sgrange
4003b00bf77Sgrange done:
4013b00bf77Sgrange if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
4023b00bf77Sgrange wakeup(sc);
4033b00bf77Sgrange return (1);
4043b00bf77Sgrange }
405