int ki2c_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 ki2c_bus *bus = cookie; u_int mode = I2C_STDSUBMODE; u_int8_t cmd = 0; if (!I2C_OP_STOP_P(op) || cmdlen > 1) return (EINVAL); if (cmdlen == 0) mode = I2C_STDMODE; else if (I2C_OP_READ_P(op)) mode = I2C_COMBMODE; if (cmdlen > 0) cmd = *(u_int8_t *)cmdbuf; ki2c_setmode(bus->sc, mode, bus->reg || addr & 0x80); addr &= 0x7f; if (I2C_OP_READ_P(op)) { if (ki2c_read(bus->sc, (addr << 1), cmd, buf, len) != 0) return (EIO); } else { if (ki2c_write(bus->sc, (addr << 1), cmd, buf, len) != 0) return (EIO); } return (0); }
int imxiic_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 imxiic_softc *sc = cookie; uint32_t ret = 0; u_int8_t cmd = 0; if (!I2C_OP_STOP_P(op) || cmdlen > 1) return (EINVAL); if (cmdlen > 0) cmd = *(u_int8_t *)cmdbuf; addr &= 0x7f; /* clock gating */ imxccm_enable_i2c(sc->unit); /* set speed to 100kHz */ imxiic_setspeed(sc, 100); /* enable the controller */ HWRITE2(sc, I2C_I2SR, 0); HWRITE2(sc, I2C_I2CR, I2C_I2CR_IEN); /* wait for it to be stable */ delay(50); /* start transaction */ HSET2(sc, I2C_I2CR, I2C_I2CR_MSTA); if (imxiic_wait_state(sc, I2C_I2SR_IBB, I2C_I2SR_IBB)) { ret = (EIO); goto fail; } sc->stopped = 0; HSET2(sc, I2C_I2CR, I2C_I2CR_IIEN | I2C_I2CR_MTX | I2C_I2CR_TXAK); if (I2C_OP_READ_P(op)) { if (imxiic_read(sc, (addr << 1), cmd, buf, len) != 0) ret = (EIO); } else { if (imxiic_write(sc, (addr << 1), cmd, buf, len) != 0) ret = (EIO); } fail: if (!sc->stopped) { HCLR2(sc, I2C_I2CR, I2C_I2CR_MSTA | I2C_I2CR_MTX); imxiic_wait_state(sc, I2C_I2SR_IBB, 0); sc->stopped = 1; } HWRITE2(sc, I2C_I2CR, 0); return ret; }
/* * iic_exec: * * Simplified I2C client interface engine. * * This and the SMBus routines are the preferred interface for * client access to I2C/SMBus, since many automated controllers * do not provide access to the low-level primitives of the I2C * bus protocol. */ int iic_exec(i2c_tag_t tag, i2c_op_t op, i2c_addr_t addr, const void *vcmd, size_t cmdlen, void *vbuf, size_t buflen, int flags) { const uint8_t *cmd = vcmd; uint8_t *buf = vbuf; int error; size_t len; /* * Defer to the controller if it provides an exec function. Use * it if it does. */ if (tag->ic_exec != NULL) return ((*tag->ic_exec)(tag->ic_cookie, op, addr, cmd, cmdlen, buf, buflen, flags)); if ((len = cmdlen) != 0) { if ((error = iic_initiate_xfer(tag, addr, flags)) != 0) goto bad; while (len--) { if ((error = iic_write_byte(tag, *cmd++, flags)) != 0) goto bad; } } if (I2C_OP_READ_P(op)) flags |= I2C_F_READ; len = buflen; while (len--) { if (len == 0 && I2C_OP_STOP_P(op)) flags |= I2C_F_STOP; if (I2C_OP_READ_P(op)) { /* Send REPEATED START. */ if ((len + 1) == buflen && (error = iic_initiate_xfer(tag, addr, flags)) != 0) goto bad; /* NACK on last byte. */ if (len == 0) flags |= I2C_F_LAST; if ((error = iic_read_byte(tag, buf++, flags)) != 0) goto bad; } else { /* Maybe send START. */ if ((len + 1) == buflen && cmdlen == 0 && (error = iic_initiate_xfer(tag, addr, flags)) != 0) goto bad; if ((error = iic_write_byte(tag, *buf++, flags)) != 0) goto bad; } } return (0); bad: iic_send_stop(tag, flags); return (error); }
int piic_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) { u_int8_t pmu_op = PMU_I2C_NORMAL; int retries = 10; PMData p; if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 5) return (EINVAL); if (cmdlen == 0) pmu_op = PMU_I2C_SIMPLE; else if (I2C_OP_READ_P(op)) pmu_op = PMU_I2C_COMBINED; p.command = PMU_I2C; p.num_data = 7 + len; p.s_buf = p.r_buf = p.data; p.data[0] = addr >> 7; /* bus number */ p.data[1] = pmu_op; p.data[2] = 0; p.data[3] = addr << 1; p.data[4] = *(u_int8_t *)cmdbuf; p.data[5] = addr << 1 | I2C_OP_READ_P(op); p.data[6] = len; memcpy(&p.data[7], buf, len); if (pmgrop(&p)) return (EIO); while (retries--) { p.command = PMU_I2C; p.num_data = 1; p.s_buf = p.r_buf = p.data; p.data[0] = 0; if (pmgrop(&p)) return (EIO); if (p.data[0] == 1) break; DELAY(10 * 1000); } if (I2C_OP_READ_P(op)) memcpy(buf, &p.data[1], len); return (0); }
static int i2c_algo_dp_aux_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf, size_t cmdlen, void *buffer, size_t len, int flags) { struct i2c_algo_dp_aux_data *algo_data = cookie; struct i2c_controller *adapter = algo_data->adapter; uint8_t *buf; int i, ret; buf = (void *)cmdbuf; if (cmdlen > 0) { ret = i2c_algo_dp_aux_address(adapter, addr, false); if (ret < 0) goto out; for (i = 0; i < cmdlen; i++) { ret = i2c_algo_dp_aux_put_byte(adapter, buf[i]); if (ret < 0) goto out; } } buf = buffer; ret = i2c_algo_dp_aux_address(adapter, addr, I2C_OP_READ_P(op)); if (ret < 0) goto out; if (I2C_OP_READ_P(op)) { for (i = 0; i < len; i++) { ret = i2c_algo_dp_aux_get_byte(adapter, &buf[i]); if (ret < 0) break; } } else { for (i = 0; i < len; i++) { ret = i2c_algo_dp_aux_put_byte(adapter, buf[i]); if (ret < 0) break; } } out: if (I2C_OP_STOP_P(op)) i2c_algo_dp_aux_stop(adapter, I2C_OP_READ_P(op)); if (ret >= 0) ret = 0; DRM_DEBUG_KMS("dp_aux_exec return %d\n", ret); return ret; }
static int emdtv_i2c_exec(void *opaque, i2c_op_t op, i2c_addr_t addr, const void *cmd, size_t cmdlen, void *vbuf, size_t buflen, int flags) { struct emdtv_softc *sc = opaque; int error; if (I2C_OP_READ_P(op)) { if (buflen == 0) error = emdtv_i2c_check(sc, addr); else error = emdtv_i2c_recv(sc, addr, vbuf, buflen); } else { error = emdtv_i2c_send(sc, addr, cmd, cmdlen, I2C_OP_STOP_P(op)); error = 0; } return error; }
static int ti_iic_exec(void *opaque, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) { struct ti_iic_softc *sc = opaque; int err; DPRINTF(("ti_iic_exec: op 0x%x cmdlen %zd len %zd flags 0x%x\n", op, cmdlen, len, flags)); #define __UNCONST(a) ((void *)(unsigned long)(const void *)(a)) if (cmdlen > 0) { err = ti_iic_op(sc, addr, TI_I2CWRITE, __UNCONST(cmdbuf), cmdlen, (I2C_OP_READ_P(op) ? 0 : I2C_F_STOP) | flags); if (err) goto done; } if (I2C_OP_STOP_P(op)) flags |= I2C_F_STOP; /* * I2C controller doesn't allow for zero-byte transfers. */ if (len == 0) goto done; if (I2C_OP_READ_P(op)) err = ti_iic_op(sc, addr, TI_I2CREAD, buf, len, flags); else err = ti_iic_op(sc, addr, TI_I2CWRITE, buf, len, flags); done: if (err) ti_iic_reset(sc); ti_iic_flush(sc); DPRINTF(("ti_iic_exec: done %d\n", err)); return err; }
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 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 motoi2c_exec(void *v, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf, size_t cmdlen, void *databuf, size_t datalen, int flags) { struct motoi2c_softc * const sc = v; uint8_t sr; uint8_t cr; int error; sr = I2C_READ(I2CSR); cr = I2C_READ(I2CCR); #if 0 DPRINTF(("%s(%#x,%#x,%p,%zu,%p,%zu,%#x): sr=%#x cr=%#x\n", __func__, op, addr, cmdbuf, cmdlen, databuf, datalen, flags, sr, cr)); #endif if ((cr & CR_MSTA) == 0 && (sr & SR_MBB) != 0) { /* wait for bus becoming available */ u_int timo = 100; do { DELAY(10); } while (--timo > 0 && ((sr = I2C_READ(I2CSR)) & SR_MBB) != 0); if (timo == 0) { DPRINTF(("%s: bus is busy (%#x)\n", __func__, sr)); return ETIMEDOUT; } } /* reset interrupt and arbitration-lost flags (all others are RO) */ I2C_WRITE(I2CSR, 0); sr = I2C_READ(I2CSR); /* * Generate start (or restart) condition */ /* CR_RTSA is write-only and transitory */ uint8_t rsta = (cr & CR_MSTA ? CR_RSTA : 0); cr = CR_MEN | CR_MTX | CR_MSTA; I2C_WRITE(I2CCR, cr | rsta); DPRINTF(("%s: started: sr=%#x cr=%#x/%#x\n", __func__, I2C_READ(I2CSR), cr, I2C_READ(I2CCR))); sr = I2C_READ(I2CSR); if (sr & SR_MAL) { DPRINTF(("%s: lost bus: sr=%#x cr=%#x/%#x\n", __func__, I2C_READ(I2CSR), cr, I2C_READ(I2CCR))); I2C_WRITE(I2CCR, 0); DELAY(10); I2C_WRITE(I2CCR, CR_MEN | CR_MTX | CR_MSTA); DELAY(10); sr = I2C_READ(I2CSR); if (sr & SR_MAL) { error = EBUSY; goto out; } DPRINTF(("%s: reacquired bus: sr=%#x cr=%#x/%#x\n", __func__, I2C_READ(I2CSR), cr, I2C_READ(I2CCR))); } /* send target address and transfer direction */ uint8_t addr_byte = (addr << 1) | (cmdlen == 0 && I2C_OP_READ_P(op) ? 1 : 0); I2C_WRITE(I2CDR, addr_byte); error = motoi2c_busy_wait(sc, cr); if (error) { DPRINTF(("%s: error sending address: %d\n", __func__, error)); if (error == EIO) error = ENXIO; goto out; } const uint8_t *cmdptr = cmdbuf; for (size_t i = 0; i < cmdlen; i++) { I2C_WRITE(I2CDR, *cmdptr++); error = motoi2c_busy_wait(sc, cr); if (error) { DPRINTF(("%s: error sending cmd byte %zu (cr=%#x/%#x):" " %d\n", __func__, i, I2C_READ(I2CCR), cr, error)); goto out; } } if (cmdlen > 0 && I2C_OP_READ_P(op)) { KASSERT(cr & CR_MTX); KASSERT((cr & CR_TXAK) == 0); I2C_WRITE(I2CCR, cr | CR_RSTA); #if 0 DPRINTF(("%s: restarted(read): sr=%#x cr=%#x(%#x)\n", __func__, I2C_READ(I2CSR), cr | CR_RSTA, I2C_READ(I2CCR))); #endif /* send target address and read transfer direction */ addr_byte |= 1; I2C_WRITE(I2CDR, addr_byte); error = motoi2c_busy_wait(sc, cr); if (error) { if (error == EIO) error = ENXIO; goto out; } } if (I2C_OP_READ_P(op)) { uint8_t *dataptr = databuf; cr &= ~CR_MTX; /* clear transmit flags */ if (datalen <= 1) cr |= CR_TXAK; I2C_WRITE(I2CCR, cr); DELAY(10); (void)I2C_READ(I2CDR); /* dummy read */ for (size_t i = 0; i < datalen; i++) { /* * If a master receiver wants to terminate a data * transfer, it must inform the slave transmitter by * not acknowledging the last byte of data (by setting * the transmit acknowledge bit (I2CCR[TXAK])) before * reading the next-to-last byte of data. */ error = motoi2c_busy_wait(sc, cr); if (error) { DPRINTF(("%s: error reading byte %zu: %d\n", __func__, i, error)); goto out; } if (i == datalen - 2) { cr |= CR_TXAK; I2C_WRITE(I2CCR, cr); } else if (i == datalen - 1 && I2C_OP_STOP_P(op)) { cr = CR_MEN; I2C_WRITE(I2CCR, cr); } *dataptr++ = I2C_READ(I2CDR); } if (datalen == 0) { if (I2C_OP_STOP_P(op)) { cr = CR_MEN; I2C_WRITE(I2CCR, cr); } (void)I2C_READ(I2CDR); /* dummy read */ error = motoi2c_busy_wait(sc, cr); if (error) { DPRINTF(("%s: error reading dummy last byte:" "%d\n", __func__, error)); goto out; } } } else { const uint8_t *dataptr = databuf; for (size_t i = 0; i < datalen; i++) { I2C_WRITE(I2CDR, *dataptr++); error = motoi2c_busy_wait(sc, cr); if (error) { DPRINTF(("%s: error sending data byte %zu:" " %d\n", __func__, i, error)); goto out; } } } out: /* * If we encountered an error condition or caller wants a STOP, * send a STOP. */ if (error || (cr & CR_TXAK) || ((cr & CR_MSTA) && I2C_OP_STOP_P(op))) { cr = CR_MEN; I2C_WRITE(I2CCR, cr); DPRINTF(("%s: stopping: cr=%#x/%#x\n", __func__, cr, I2C_READ(I2CCR))); } DPRINTF(("%s: exit sr=%#x cr=%#x: %d\n", __func__, I2C_READ(I2CSR), I2C_READ(I2CCR), error)); return error; }