static int gxiic_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *vcmd, size_t cmdlen, void *vbuf, size_t buflen, int flags) { struct gxiic_softc *sc = cookie; int rv = -1; if (I2C_OP_READ_P(op) && (cmdlen == 0) && (buflen == 1)) rv = pxa2x0_i2c_read(&sc->sc_pxa_i2c, addr, (u_char *)vbuf); if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 1)) { rv = pxa2x0_i2c_write(&sc->sc_pxa_i2c, addr, *(u_char *)vbuf); if (rv == 0) rv = pxa2x0_i2c_read(&sc->sc_pxa_i2c, addr, (u_char *)vbuf); } if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 2)) { rv = pxa2x0_i2c_write(&sc->sc_pxa_i2c, addr, *(u_char *)vbuf); if (rv == 0) rv = pxa2x0_i2c_read(&sc->sc_pxa_i2c, addr, (u_char *)vbuf); if (rv == 0) rv = pxa2x0_i2c_read(&sc->sc_pxa_i2c, addr, (u_char *)(vbuf) + 1); } if ((I2C_OP_WRITE_P(op)) && (cmdlen == 0) && (buflen == 1)) rv = pxa2x0_i2c_write(&sc->sc_pxa_i2c, addr, *(u_char *)vbuf); if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 1)) { rv = pxa2x0_i2c_write(&sc->sc_pxa_i2c, addr, *(const u_char *)vcmd); if (rv == 0) rv = pxa2x0_i2c_write(&sc->sc_pxa_i2c, addr, *(u_char *)vbuf); } if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 2)) { rv = pxa2x0_i2c_write(&sc->sc_pxa_i2c, addr, *(const u_char *)vcmd); if (rv == 0) rv = pxa2x0_i2c_write_2(&sc->sc_pxa_i2c, addr, *(u_short *)vbuf); } /* Handle quick_read/quick_write ops - XXX Untested XXX */ if ((cmdlen == 0) && (buflen == 0)) rv = pxa2x0_i2c_quick(&sc->sc_pxa_i2c, addr, I2C_OP_READ_P(op)?1:0); return rv; }
static int nfsmb_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmd, size_t cmdlen, void *vbuf, size_t buflen, int flags) { struct nfsmb_softc *sc = (struct nfsmb_softc *)cookie; uint8_t *p = vbuf; int rv; if (I2C_OP_READ_P(op) && (cmdlen == 0) && (buflen == 1)) { rv = nfsmb_receive_1(sc, addr, op, flags); if (rv == -1) return -1; *p = (uint8_t)rv; return 0; } if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 1)) { rv = nfsmb_read_1(sc, *(const uint8_t*)cmd, addr, op, flags); if (rv == -1) return -1; *p = (uint8_t)rv; return 0; } if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 2)) { rv = nfsmb_read_2(sc, *(const uint8_t*)cmd, addr, op, flags); if (rv == -1) return -1; *(uint16_t *)p = (uint16_t)rv; return 0; } if ((I2C_OP_WRITE_P(op)) && (cmdlen == 0) && (buflen == 1)) return nfsmb_send_1(sc, *(uint8_t*)vbuf, addr, op, flags); if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 1)) return nfsmb_write_1(sc, *(const uint8_t*)cmd, *(uint8_t*)vbuf, addr, op, flags); if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 2)) return nfsmb_write_2(sc, *(const uint8_t*)cmd, *((uint16_t *)vbuf), addr, op, flags); return -1; }
static int ichsmb_intr(void *arg) { struct ichsmb_softc *sc = arg; uint8_t st; uint8_t *b; size_t len; #ifdef ICHIIC_DEBUG char fbuf[64]; #endif /* Read status */ st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS); if ((st & LPCIB_SMB_HS_BUSY) != 0 || (st & (LPCIB_SMB_HS_INTR | LPCIB_SMB_HS_DEVERR | LPCIB_SMB_HS_BUSERR | LPCIB_SMB_HS_FAILED | LPCIB_SMB_HS_SMBAL | LPCIB_SMB_HS_BDONE)) == 0) /* Interrupt was not for us */ return (0); #ifdef ICHIIC_DEBUG snprintb(fbuf, sizeof(fbuf), LPCIB_SMB_HS_BITS, st); printf("%s: intr st 0x%s\n", device_xname(sc->sc_dev), fbuf); #endif /* Clear status bits */ bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS, st); /* Check for errors */ if (st & (LPCIB_SMB_HS_DEVERR | LPCIB_SMB_HS_BUSERR | LPCIB_SMB_HS_FAILED)) { sc->sc_i2c_xfer.error = 1; goto done; } if (st & LPCIB_SMB_HS_INTR) { if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op)) goto done; /* Read data */ b = sc->sc_i2c_xfer.buf; len = sc->sc_i2c_xfer.len; if (len > 0) b[0] = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HD0); if (len > 1) b[1] = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HD1); } done: if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0) wakeup(sc); return (1); }
static int amdpm_smbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmd, size_t cmdlen, void *vbuf, size_t buflen, int flags) { struct amdpm_softc *sc = (struct amdpm_softc *) cookie; sc->sc_smbus_slaveaddr = addr; uint8_t *p = vbuf; int rv; if ((cmdlen == 0) && (buflen == 0)) return amdpm_smbus_quick(sc, op); if (I2C_OP_READ_P(op) && (cmdlen == 0) && (buflen == 1)) { rv = amdpm_smbus_receive_1(sc, op); if (rv == -1) return -1; *p = (uint8_t)rv; return 0; } if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 1)) { rv = amdpm_smbus_read_1(sc, *(const uint8_t *)cmd, op); if (rv == -1) return -1; *p = (uint8_t)rv; return 0; } if ((I2C_OP_WRITE_P(op)) && (cmdlen == 0) && (buflen == 1)) return amdpm_smbus_send_1(sc, *(uint8_t*)vbuf, op); if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 1)) return amdpm_smbus_write_1(sc, *(const uint8_t*)cmd, *(uint8_t*)vbuf, op); return -1; }
int amdpm_intr(void *arg) { struct amdpm_softc *sc = arg; u_int16_t st, data; u_int8_t *b; size_t len; /* Read status */ st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT); if ((st & AMDPM_SMBSTAT_HBSY) != 0 || (st & (AMDPM_SMBSTAT_ABRT | AMDPM_SMBSTAT_COL | AMDPM_SMBSTAT_PRERR | AMDPM_SMBSTAT_CYC | AMDPM_SMBSTAT_TO | AMDPM_SMBSTAT_SNP | AMDPM_SMBSTAT_SLV | AMDPM_SMBSTAT_SMBA)) == 0) /* Interrupt was not for us */ return (0); DPRINTF("%s: intr: st 0x%b\n", sc->sc_dev.dv_xname, st, AMDPM_SMBSTAT_BITS); /* Clear status bits */ bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT, st); /* Check for errors */ if (st & (AMDPM_SMBSTAT_COL | AMDPM_SMBSTAT_PRERR | AMDPM_SMBSTAT_TO)) { sc->sc_i2c_xfer.error = 1; goto done; } if (st & AMDPM_SMBSTAT_CYC) { if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op)) goto done; /* Read data */ b = sc->sc_i2c_xfer.buf; len = sc->sc_i2c_xfer.len; if (len > 0) { data = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBDATA); b[0] = data & 0xff; } if (len > 1) b[1] = (data >> 8) & 0xff; } done: if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0) wakeup(sc); return (1); }
static int piixpm_intr(void *arg) { struct piixpm_smbus *smbus = arg; struct piixpm_softc *sc = smbus->softc; u_int8_t st; u_int8_t *b; size_t len; /* Read status */ st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS); if ((st & PIIX_SMB_HS_BUSY) != 0 || (st & (PIIX_SMB_HS_INTR | PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR | PIIX_SMB_HS_FAILED)) == 0) /* Interrupt was not for us */ return (0); DPRINTF(("%s: intr st 0x%d\n", device_xname(sc->sc_dev), st & 0xff)); /* Clear status bits */ bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS, st); /* Check for errors */ if (st & (PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR | PIIX_SMB_HS_FAILED)) { sc->sc_i2c_xfer.error = 1; goto done; } if (st & PIIX_SMB_HS_INTR) { if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op)) goto done; /* Read data */ b = sc->sc_i2c_xfer.buf; len = sc->sc_i2c_xfer.len; if (len > 0) b[0] = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HD0); if (len > 1) b[1] = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HD1); } done: if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0) wakeup(sc); return (1); }
int ichiic_intr(void *arg) { struct ichiic_softc *sc = arg; u_int8_t st; u_int8_t *b; size_t len; /* Read status */ st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS); if ((st & ICH_SMB_HS_BUSY) != 0 || (st & (ICH_SMB_HS_INTR | ICH_SMB_HS_DEVERR | ICH_SMB_HS_BUSERR | ICH_SMB_HS_FAILED | ICH_SMB_HS_SMBAL | ICH_SMB_HS_BDONE)) == 0) /* Interrupt was not for us */ return (0); DPRINTF(("%s: intr st 0x%b\n", sc->sc_dev.dv_xname, st, ICH_SMB_HS_BITS)); /* Clear status bits */ bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS, st); /* Check for errors */ if (st & (ICH_SMB_HS_DEVERR | ICH_SMB_HS_BUSERR | ICH_SMB_HS_FAILED)) { sc->sc_i2c_xfer.error = 1; goto done; } if (st & ICH_SMB_HS_INTR) { if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op)) goto done; /* Read data */ b = sc->sc_i2c_xfer.buf; len = sc->sc_i2c_xfer.len; if (len > 0) b[0] = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HD0); if (len > 1) b[1] = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HD1); } done: if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0) wakeup(sc); return (1); }
int amdiic_intr(void *arg) { struct amdiic_softc *sc = arg; int st; u_int8_t *b; size_t len; /* Read status */ if ((st = amdiic_read(sc, AMD8111_SMB_STAT)) == -1) return (-1); if (st == 0) /* Interrupt was not for us */ return (0); DPRINTF(("%s: intr: st 0x%02x\n", sc->sc_dev.dv_xname, st)); /* Check for errors */ if ((st & AMD8111_SMB_STAT_MASK) != 0) { sc->sc_i2c_xfer.error = 1; goto done; } if (st & AMD8111_SMB_STAT_DONE) { if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op)) goto done; /* Read data */ b = sc->sc_i2c_xfer.buf; len = sc->sc_i2c_xfer.len; if (len > 0) b[0] = amdiic_read(sc, AMD8111_SMB_DATA(0)); if (len > 1) b[1] = amdiic_read(sc, AMD8111_SMB_DATA(1)); } done: if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0) wakeup(sc); return (1); }
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) { struct ichiic_softc *sc = cookie; u_int8_t *b; u_int8_t ctl, st; int retries; DPRINTF(("%s: exec: op %d, addr 0x%02x, cmdlen %d, len %d, " "flags 0x%02x\n", sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags)); /* Wait for bus to be idle */ for (retries = 100; retries > 0; retries--) { st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS); if (!(st & ICH_SMB_HS_BUSY)) break; DELAY(ICHIIC_DELAY); } DPRINTF(("%s: exec: st 0x%b\n", sc->sc_dev.dv_xname, st, ICH_SMB_HS_BITS)); if (st & ICH_SMB_HS_BUSY) return (1); if (cold || sc->sc_poll) flags |= I2C_F_POLL; if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2) return (1); /* Setup transfer */ sc->sc_i2c_xfer.op = op; sc->sc_i2c_xfer.buf = buf; sc->sc_i2c_xfer.len = len; sc->sc_i2c_xfer.flags = flags; sc->sc_i2c_xfer.error = 0; /* Set slave address and transfer direction */ bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_TXSLVA, ICH_SMB_TXSLVA_ADDR(addr) | (I2C_OP_READ_P(op) ? ICH_SMB_TXSLVA_READ : 0)); b = (void *)cmdbuf; if (cmdlen > 0) /* Set command byte */ bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HCMD, b[0]); if (I2C_OP_WRITE_P(op)) { /* Write data */ b = buf; if (len > 0) bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HD0, b[0]); if (len > 1) bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HD1, b[1]); } /* Set SMBus command */ if (len == 0) ctl = ICH_SMB_HC_CMD_BYTE; else if (len == 1) ctl = ICH_SMB_HC_CMD_BDATA; else if (len == 2) ctl = ICH_SMB_HC_CMD_WDATA; if ((flags & I2C_F_POLL) == 0) ctl |= ICH_SMB_HC_INTREN; /* Start transaction */ ctl |= ICH_SMB_HC_START; bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HC, ctl); if (flags & I2C_F_POLL) { /* Poll for completion */ DELAY(ICHIIC_DELAY); for (retries = 1000; retries > 0; retries--) { st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS); if ((st & ICH_SMB_HS_BUSY) == 0) break; DELAY(ICHIIC_DELAY); } if (st & ICH_SMB_HS_BUSY) goto timeout; ichiic_intr(sc); } else { /* Wait for interrupt */ if (tsleep(sc, PRIBIO, "iicexec", ICHIIC_TIMEOUT * hz)) goto timeout; } if (sc->sc_i2c_xfer.error) return (1); return (0); timeout: /* * Transfer timeout. Kill the transaction and clear status bits. */ bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HC, ICH_SMB_HC_KILL); DELAY(ICHIIC_DELAY); st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS); if ((st & ICH_SMB_HS_FAILED) == 0) printf("%s: abort failed, status 0x%b\n", sc->sc_dev.dv_xname, st, ICH_SMB_HS_BITS); bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS, st); return (1); }
int amdpm_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) { struct amdpm_softc *sc = cookie; u_int8_t *b; u_int16_t st, ctl, data; int retries; DPRINTF("%s: exec: op %d, addr 0x%02x, cmdlen %d, len %d, " "flags 0x%02x\n", sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags); /* Wait for bus to be idle */ for (retries = 100; retries > 0; retries--) { st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT); if (!(st & AMDPM_SMBSTAT_BSY)) break; DELAY(AMDPM_SMBUS_DELAY); } DPRINTF("%s: exec: st 0x%b\n", sc->sc_dev.dv_xname, st, AMDPM_SMBSTAT_BITS); if (st & AMDPM_SMBSTAT_BSY) return (1); if (cold || sc->sc_poll) flags |= I2C_F_POLL; if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2) return (1); /* Setup transfer */ sc->sc_i2c_xfer.op = op; sc->sc_i2c_xfer.buf = buf; sc->sc_i2c_xfer.len = len; sc->sc_i2c_xfer.flags = flags; sc->sc_i2c_xfer.error = 0; /* Set slave address and transfer direction */ bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBADDR, AMDPM_SMBADDR_ADDR(addr) | (I2C_OP_READ_P(op) ? AMDPM_SMBADDR_READ : 0)); b = (void *)cmdbuf; if (cmdlen > 0) /* Set command byte */ bus_space_write_1(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCMD, b[0]); if (I2C_OP_WRITE_P(op)) { /* Write data */ data = 0; b = buf; if (len > 0) data = b[0]; if (len > 1) data |= ((u_int16_t)b[1] << 8); if (len > 0) bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBDATA, data); } /* Set SMBus command */ if (len == 0) ctl = AMDPM_SMBCTL_CMD_BYTE; else if (len == 1) ctl = AMDPM_SMBCTL_CMD_BDATA; else if (len == 2) ctl = AMDPM_SMBCTL_CMD_WDATA; else panic("%s: unexpected len %zd", __func__, len); if ((flags & I2C_F_POLL) == 0) ctl |= AMDPM_SMBCTL_CYCEN; /* Start transaction */ ctl |= AMDPM_SMBCTL_START; bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCTL, ctl); if (flags & I2C_F_POLL) { /* Poll for completion */ DELAY(AMDPM_SMBUS_DELAY); for (retries = 1000; retries > 0; retries--) { st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT); if ((st & AMDPM_SMBSTAT_HBSY) == 0) break; DELAY(AMDPM_SMBUS_DELAY); } if (st & AMDPM_SMBSTAT_HBSY) goto timeout; amdpm_intr(sc); } else { /* Wait for interrupt */ if (tsleep(sc, PRIBIO, "amdpm", AMDPM_SMBUS_TIMEOUT * hz)) goto timeout; } if (sc->sc_i2c_xfer.error) return (1); return (0); timeout: /* * Transfer timeout. Kill the transaction and clear status bits. */ printf("%s: exec: op %d, addr 0x%02x, cmdlen %zu, len %zu, " "flags 0x%02x: timeout, status 0x%b\n", sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags, st, AMDPM_SMBSTAT_BITS); bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCTL, AMDPM_SMBCTL_ABORT); DELAY(AMDPM_SMBUS_DELAY); st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT); if ((st & AMDPM_SMBSTAT_ABRT) == 0) printf("%s: abort failed, status 0x%b\n", sc->sc_dev.dv_xname, st, AMDPM_SMBSTAT_BITS); bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT, st); return (1); }
static int awin_p2wi_exec(void *priv, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) { struct awin_p2wi_softc *sc = priv; uint32_t dlen, ctrl; uint8_t rta; int error; KASSERT(mutex_owned(&sc->sc_lock)); if (cmdlen != 1 || (len != 1 && len != 2 && len != 4)) return EINVAL; if (sc->sc_rsb_p && sc->sc_rsb_last_da != addr) { switch (addr) { case AWIN_RSB_ADDR_AXP809: rta = AWIN_RSB_RTA_AXP809; break; case AWIN_RSB_ADDR_AXP806: rta = AWIN_RSB_RTA_AXP806; break; case AWIN_RSB_ADDR_AC100: rta = AWIN_RSB_RTA_AC100; break; default: return ENXIO; } error = awin_p2wi_rsb_config(sc, rta, addr, flags); if (error) { device_printf(sc->sc_dev, "SRTA failed, flags = %x, error = %d\n", flags, error); sc->sc_rsb_last_da = 0; return error; } sc->sc_rsb_last_da = addr; } /* Data byte register */ P2WI_WRITE(sc, AWIN_A31_P2WI_DADDR0_REG, *(const uint8_t *)cmdbuf); if (I2C_OP_WRITE_P(op)) { uint8_t *pbuf = buf; uint32_t data; /* Write data */ switch (len) { case 1: data = pbuf[0]; break; case 2: data = pbuf[0] | (pbuf[1] << 8); break; case 4: data = pbuf[0] | (pbuf[1] << 8) | (pbuf[2] << 16) | (pbuf[3] << 24); break; default: return EINVAL; } P2WI_WRITE(sc, AWIN_A31_P2WI_DATA0_REG, data); } if (sc->sc_rsb_p) { uint8_t cmd; if (I2C_OP_WRITE_P(op)) { switch (len) { case 1: cmd = AWIN_A80_RSB_CMD_IDX_WR8; break; case 2: cmd = AWIN_A80_RSB_CMD_IDX_WR16; break; case 4: cmd = AWIN_A80_RSB_CMD_IDX_WR32; break; default: return EINVAL; } } else { switch (len) { case 1: cmd = AWIN_A80_RSB_CMD_IDX_RD8; break; case 2: cmd = AWIN_A80_RSB_CMD_IDX_RD16; break; case 4: cmd = AWIN_A80_RSB_CMD_IDX_RD32; break; default: return EINVAL; } } P2WI_WRITE(sc, AWIN_A80_RSB_CMD_REG, cmd); } /* Program data length register; if reading, set read/write bit */ dlen = __SHIFTIN(len - 1, AWIN_A31_P2WI_DLEN_ACCESS_LENGTH); if (I2C_OP_READ_P(op)) { dlen |= AWIN_A31_P2WI_DLEN_READ_WRITE_FLAG; } P2WI_WRITE(sc, AWIN_A31_P2WI_DLEN_REG, dlen); /* Make sure the controller is idle */ ctrl = P2WI_READ(sc, AWIN_A31_P2WI_CTRL_REG); if (ctrl & AWIN_A31_P2WI_CTRL_START_TRANS) { device_printf(sc->sc_dev, "device is busy\n"); return EBUSY; } /* Start the transfer */ P2WI_WRITE(sc, AWIN_A31_P2WI_CTRL_REG, ctrl | AWIN_A31_P2WI_CTRL_START_TRANS); error = awin_p2wi_wait(sc, flags); if (error) { return error; } if (I2C_OP_READ_P(op)) { uint32_t data = P2WI_READ(sc, AWIN_A31_P2WI_DATA0_REG); switch (len) { case 4: *(uint32_t *)buf = data; break; case 2: *(uint16_t *)buf = data & 0xffff; break; case 1: *(uint8_t *)buf = data & 0xff; break; default: return EINVAL; } } return 0; }
static int ichsmb_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) { struct ichsmb_softc *sc = cookie; const uint8_t *b; uint8_t ctl = 0, st; int retries; char fbuf[64]; DPRINTF(("%s: exec: op %d, addr 0x%02x, cmdlen %zu, len %zu, " "flags 0x%02x\n", device_xname(sc->sc_dev), op, addr, cmdlen, len, flags)); /* Clear status bits */ bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS, LPCIB_SMB_HS_INTR | LPCIB_SMB_HS_DEVERR | LPCIB_SMB_HS_BUSERR | LPCIB_SMB_HS_FAILED); bus_space_barrier(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS, 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); /* Wait for bus to be idle */ for (retries = 100; retries > 0; retries--) { st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS); if (!(st & LPCIB_SMB_HS_BUSY)) break; DELAY(ICHIIC_DELAY); } #ifdef ICHIIC_DEBUG snprintb(fbuf, sizeof(fbuf), LPCIB_SMB_HS_BITS, st); printf("%s: exec: st 0x%s\n", device_xname(sc->sc_dev), fbuf); #endif if (st & LPCIB_SMB_HS_BUSY) return (1); if (cold || sc->sc_poll) flags |= I2C_F_POLL; if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2 || (cmdlen == 0 && len > 1)) return (1); /* Setup transfer */ sc->sc_i2c_xfer.op = op; sc->sc_i2c_xfer.buf = buf; sc->sc_i2c_xfer.len = len; sc->sc_i2c_xfer.flags = flags; sc->sc_i2c_xfer.error = 0; /* Set slave address and transfer direction */ bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_TXSLVA, LPCIB_SMB_TXSLVA_ADDR(addr) | (I2C_OP_READ_P(op) ? LPCIB_SMB_TXSLVA_READ : 0)); b = (const uint8_t *)cmdbuf; if (cmdlen > 0) /* Set command byte */ bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HCMD, b[0]); if (I2C_OP_WRITE_P(op)) { /* Write data */ b = buf; if (cmdlen == 0 && len == 1) bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HCMD, b[0]); else if (len > 0) bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HD0, b[0]); if (len > 1) bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HD1, b[1]); } /* Set SMBus command */ if (cmdlen == 0) { if (len == 0) ctl = LPCIB_SMB_HC_CMD_QUICK; else ctl = LPCIB_SMB_HC_CMD_BYTE; } else if (len == 1) ctl = LPCIB_SMB_HC_CMD_BDATA; else if (len == 2) ctl = LPCIB_SMB_HC_CMD_WDATA; if ((flags & I2C_F_POLL) == 0) ctl |= LPCIB_SMB_HC_INTREN; /* Start transaction */ ctl |= LPCIB_SMB_HC_START; bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HC, ctl); if (flags & I2C_F_POLL) { /* Poll for completion */ DELAY(ICHIIC_DELAY); for (retries = 1000; retries > 0; retries--) { st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS); if ((st & LPCIB_SMB_HS_BUSY) == 0) break; DELAY(ICHIIC_DELAY); } if (st & LPCIB_SMB_HS_BUSY) goto timeout; ichsmb_intr(sc); } else { /* Wait for interrupt */ if (tsleep(sc, PRIBIO, "iicexec", ICHIIC_TIMEOUT * hz)) goto timeout; } if (sc->sc_i2c_xfer.error) return (1); return (0); timeout: /* * Transfer timeout. Kill the transaction and clear status bits. */ snprintb(fbuf, sizeof(fbuf), LPCIB_SMB_HS_BITS, st); aprint_error_dev(sc->sc_dev, "exec: op %d, addr 0x%02x, cmdlen %zd, len %zd, " "flags 0x%02x: timeout, status 0x%s\n", op, addr, cmdlen, len, flags, fbuf); bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HC, LPCIB_SMB_HC_KILL); DELAY(ICHIIC_DELAY); st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS); if ((st & LPCIB_SMB_HS_FAILED) == 0) { snprintb(fbuf, sizeof(fbuf), LPCIB_SMB_HS_BITS, st); aprint_error_dev(sc->sc_dev, "abort failed, status 0x%s\n", fbuf); } bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS, st); return (1); }
static int piixpm_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) { struct piixpm_smbus *smbus = cookie; struct piixpm_softc *sc = smbus->softc; const u_int8_t *b; u_int8_t ctl = 0, st; int retries; DPRINTF(("%s: exec: op %d, addr 0x%x, cmdlen %zu, len %zu, flags 0x%x\n", device_xname(sc->sc_dev), op, addr, cmdlen, len, flags)); /* Clear status bits */ bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS, PIIX_SMB_HS_INTR | PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR | PIIX_SMB_HS_FAILED); bus_space_barrier(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS, 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); /* Wait for bus to be idle */ for (retries = 100; retries > 0; retries--) { st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS); if (!(st & PIIX_SMB_HS_BUSY)) break; DELAY(PIIXPM_DELAY); } DPRINTF(("%s: exec: st 0x%d\n", device_xname(sc->sc_dev), st & 0xff)); if (st & PIIX_SMB_HS_BUSY) return (1); if (cold || sc->sc_poll) flags |= I2C_F_POLL; if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2 || (cmdlen == 0 && len > 1)) return (1); /* Setup transfer */ sc->sc_i2c_xfer.op = op; sc->sc_i2c_xfer.buf = buf; sc->sc_i2c_xfer.len = len; sc->sc_i2c_xfer.flags = flags; sc->sc_i2c_xfer.error = 0; /* Set slave address and transfer direction */ bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_TXSLVA, PIIX_SMB_TXSLVA_ADDR(addr) | (I2C_OP_READ_P(op) ? PIIX_SMB_TXSLVA_READ : 0)); b = cmdbuf; if (cmdlen > 0) /* Set command byte */ bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HCMD, b[0]); if (I2C_OP_WRITE_P(op)) { /* Write data */ b = buf; if (cmdlen == 0 && len == 1) bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HCMD, b[0]); else if (len > 0) bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HD0, b[0]); if (len > 1) bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HD1, b[1]); } /* Set SMBus command */ if (cmdlen == 0) { if (len == 0) ctl = PIIX_SMB_HC_CMD_QUICK; else ctl = PIIX_SMB_HC_CMD_BYTE; } else if (len == 1) ctl = PIIX_SMB_HC_CMD_BDATA; else if (len == 2) ctl = PIIX_SMB_HC_CMD_WDATA; if ((flags & I2C_F_POLL) == 0) ctl |= PIIX_SMB_HC_INTREN; /* Start transaction */ ctl |= PIIX_SMB_HC_START; bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HC, ctl); if (flags & I2C_F_POLL) { /* Poll for completion */ if (PIIXPM_IS_CSB5(sc->sc_id)) DELAY(2*PIIXPM_DELAY); else DELAY(PIIXPM_DELAY); for (retries = 1000; retries > 0; retries--) { st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS); if ((st & PIIX_SMB_HS_BUSY) == 0) break; DELAY(PIIXPM_DELAY); } if (st & PIIX_SMB_HS_BUSY) goto timeout; piixpm_intr(smbus); } else { /* Wait for interrupt */ if (tsleep(sc, PRIBIO, "iicexec", PIIXPM_TIMEOUT * hz)) goto timeout; } if (sc->sc_i2c_xfer.error) return (1); return (0); timeout: /* * Transfer timeout. Kill the transaction and clear status bits. */ aprint_error_dev(sc->sc_dev, "timeout, status 0x%x\n", st); bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HC, PIIX_SMB_HC_KILL); DELAY(PIIXPM_DELAY); st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS); if ((st & PIIX_SMB_HS_FAILED) == 0) aprint_error_dev(sc->sc_dev, "transaction abort failed, status 0x%x\n", st); bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS, st); /* * CSB5 needs hard reset to unlock the smbus after timeout. */ if (PIIXPM_IS_CSB5(sc->sc_id)) piixpm_csb5_reset(sc); return (1); }
int nviic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) { struct nviic_controller *nc = arg; #ifdef NVIIC_DEBUG struct nviic_softc *sc = nc->nc_sc; #endif u_int8_t protocol; u_int8_t *b; u_int8_t sts; int i; DPRINTF("%s: exec op: %d addr: 0x%x cmdlen: %d len: %d flags 0x%x\n", DEVNAME(sc), op, addr, cmdlen, len, flags); if (cold) flags |= I2C_F_POLL; if (I2C_OP_STOP_P(op) == 0 || cmdlen > 1 || len > 2) return (1); /* set slave address */ nviic_write(nc, NVI_SMB_ADDR, addr << 1); /* set command byte */ if (cmdlen > 0) { b = (u_int8_t *)cmdbuf; nviic_write(nc, NVI_SMB_CMD, b[0]); } b = (u_int8_t *)buf; /* write data */ if (I2C_OP_WRITE_P(op)) { for (i = 0; i < len; i++) nviic_write(nc, NVI_SMB_DATA(i), b[i]); } switch (len) { case 0: protocol = NVI_SMB_PRTCL_BYTE; break; case 1: protocol = NVI_SMB_PRTCL_BYTE_DATA; break; case 2: protocol = NVI_SMB_PRTCL_WORD_DATA; break; } /* set direction */ if (I2C_OP_READ_P(op)) protocol |= NVI_SMB_PRTCL_READ; /* start transaction */ nviic_write(nc, NVI_SMB_PRTCL, protocol); for (i = 1000; i > 0; i--) { delay(100); if (nviic_read(nc, NVI_SMB_PRTCL) == 0) break; } if (i == 0) { DPRINTF("%s: timeout\n", DEVNAME(sc)); return (1); } sts = nviic_read(nc, NVI_SMB_STS); if (sts & NVI_SMB_STS_STATUS) return (1); /* read data */ if (I2C_OP_READ_P(op)) { for (i = 0; i < len; i++) b[i] = nviic_read(nc, NVI_SMB_DATA(i)); } return (0); }
int amdiic_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) { struct amdiic_softc *sc = cookie; u_int8_t *b; u_int8_t proto, st; int retries; DPRINTF(("%s: exec: op %d, addr 0x%02x, cmdlen %d, len %d, " "flags 0x%02x\n", sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags)); if (cold || sc->sc_poll) flags |= I2C_F_POLL; if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2) return (1); /* Setup transfer */ sc->sc_i2c_xfer.op = op; sc->sc_i2c_xfer.buf = buf; sc->sc_i2c_xfer.len = len; sc->sc_i2c_xfer.flags = flags; sc->sc_i2c_xfer.error = 0; /* Set slave address */ if (amdiic_write(sc, AMD8111_SMB_ADDR, addr << AMD8111_SMB_ADDR_SHIFT) == -1) return (1); b = (void *)cmdbuf; if (cmdlen > 0) /* Set command byte */ if (amdiic_write(sc, AMD8111_SMB_CMD, b[0]) == -1) return (1); if (I2C_OP_WRITE_P(op)) { /* Write data */ b = buf; if (len > 0) if (amdiic_write(sc, AMD8111_SMB_DATA(0), b[0]) == -1) return (1); if (len > 1) if (amdiic_write(sc, AMD8111_SMB_DATA(1), b[1]) == -1) return (1); } /* Set SMBus command */ if (len == 0) proto = AMD8111_SMB_PROTO_BYTE; else if (len == 1) proto = AMD8111_SMB_PROTO_BDATA; else if (len == 2) proto = AMD8111_SMB_PROTO_WDATA; /* Set direction */ if (I2C_OP_READ_P(op)) proto |= AMD8111_SMB_PROTO_READ; /* Start transaction */ amdiic_write(sc, AMD8111_SMB_PROTO, proto); if (flags & I2C_F_POLL) { /* Poll for completion */ DELAY(AMDIIC_DELAY); for (retries = 1000; retries > 0; retries--) { st = amdiic_read(sc, AMD8111_SMB_STAT); if (st != 0) break; DELAY(AMDIIC_DELAY); } if (st == 0) { printf("%s: exec: op %d, addr 0x%02x, cmdlen %d, " "len %d, flags 0x%02x: timeout\n", sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags); return (1); } amdiic_intr(sc); } else { /* Wait for interrupt */ if (tsleep(sc, PRIBIO, "amdiic", AMDIIC_TIMEOUT * hz)) return (1); } if (sc->sc_i2c_xfer.error) return (1); return (0); }
int sociic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr, const void *vcmdbuf, size_t cmdlen, void *vbuf, size_t buflen, int flags) { struct sociic_softc *sc = arg; const uint8_t *cmdbuf = vcmdbuf; uint8_t *buf = vbuf; int err = 0; size_t len; uint8_t val; /* Clear the bus. */ sociic_write(sc, I2C_SR, 0); sociic_write(sc, I2C_CR, I2C_CR_MEN); err = sociic_wait_bus(sc); if (err) return (err); if (cmdlen > 0) { sociic_write(sc, I2C_CR, I2C_CR_MEN|I2C_CR_MSTA|I2C_CR_MTX); sociic_write(sc, I2C_DR, addr << 1); err = sociic_wait(sc, I2C_F_WRITE); if (err) goto out; len = cmdlen; while (len--) { sociic_write(sc, I2C_DR, *cmdbuf++); err = sociic_wait(sc, I2C_F_WRITE); if (err) goto out; } } if (I2C_OP_READ_P(op) && buflen > 0) { /* RESTART if we did write a command above. */ val = I2C_CR_MEN|I2C_CR_MSTA|I2C_CR_MTX; if (cmdlen > 0) val |= I2C_CR_RSTA; sociic_write(sc, I2C_CR, val); sociic_write(sc, I2C_DR, (addr << 1) | 1); err = sociic_wait(sc, I2C_F_WRITE); if (err) goto out; /* NACK if we're only sending one byte. */ val = I2C_CR_MEN|I2C_CR_MSTA; if (buflen == 1) val |= I2C_CR_TXAK; sociic_write(sc, I2C_CR, val); /* Dummy read. */ sociic_read(sc, I2C_DR); len = buflen; while (len--) { err = sociic_wait(sc, I2C_F_READ); if (err) goto out; /* NACK on last byte. */ if (len == 1) sociic_write(sc, I2C_CR, I2C_CR_MEN|I2C_CR_MSTA|I2C_CR_TXAK); /* STOP after last byte. */ if (len == 0) sociic_write(sc, I2C_CR, I2C_CR_MEN|I2C_CR_TXAK); *buf++ = sociic_read(sc, I2C_DR); } } if (I2C_OP_WRITE_P(op) && cmdlen == 0 && buflen > 0) { /* START if we didn't write a command. */ sociic_write(sc, I2C_CR, I2C_CR_MEN|I2C_CR_MSTA|I2C_CR_MTX); sociic_write(sc, I2C_DR, addr << 1); err = sociic_wait(sc, I2C_F_WRITE); if (err) goto out; } if (I2C_OP_WRITE_P(op) && buflen > 0) { len = buflen; while (len--) { sociic_write(sc, I2C_DR, *buf++); err = sociic_wait(sc, I2C_F_WRITE); if (err) goto out; } } out: /* STOP if we're still holding the bus. */ sociic_write(sc, I2C_CR, I2C_CR_MEN); return (err); }