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); }
/* * 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); }
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; }
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 nfsmb_read_2(struct nfsmb_softc *sc, uint8_t cmd, i2c_addr_t addr, i2c_op_t op, int flags) { uint8_t data, low, high; /* store cmd */ bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_COMMAND, cmd); /* write smbus slave address to register */ data = addr << 1; bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data); /* write smbus protocol to register */ data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_BYTE_DATA; if (flags & I2C_F_PEC) data |= NFORCE_SMB_PROTOCOL_PEC; bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data); /* check for errors */ if (nfsmb_check_done(sc) < 0) return -1; /* read data */ low = bus_space_read_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA); high = bus_space_read_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA); return low | high << 8; }
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; }
static int nfsmb_write_2(struct nfsmb_softc *sc, uint8_t cmd, uint16_t val, i2c_addr_t addr, i2c_op_t op, int flags) { uint8_t data, low, high; /* store cmd */ bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_COMMAND, cmd); /* store data */ low = val; bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA, low); high = val >> 8; bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA, high); /* write smbus slave address to register */ data = addr << 1; bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data); /* write smbus protocol to register */ data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_WORD_DATA; if (flags & I2C_F_PEC) data |= NFORCE_SMB_PROTOCOL_PEC; bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data); return nfsmb_check_done(sc); }
static int amdpm_smbus_quick(struct amdpm_softc *sc, i2c_op_t op) { uint16_t data = 0; int off = (sc->sc_nforce ? 0xe0 : 0); /* first clear gsr */ amdpm_smbus_clear_gsr(sc); /* write smbus slave address and read/write bit to register */ data = sc->sc_smbus_slaveaddr; data <<= 1; if (I2C_OP_READ_P(op)) data |= AMDPM_8111_SMBUS_READ; bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMDPM_8111_SMBUS_HOSTADDR - off, data); /* host start */ bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMDPM_8111_SMBUS_CTRL - off, AMDPM_8111_SMBUS_GSR_QUICK); return amdpm_smbus_check_done(sc, op); }
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 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; }
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; }
/* ARGSUSED */ static int nfsmb_send_1(struct nfsmb_softc *sc, uint8_t val, i2c_addr_t addr, i2c_op_t op, int flags) { uint8_t data; /* store cmd */ bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_COMMAND, val); /* write smbus slave address to register */ data = addr << 1; bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data); /* write smbus protocol to register */ data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_BYTE; bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data); return nfsmb_check_done(sc); }
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; }
/* ARGSUSED */ static int nfsmb_receive_1(struct nfsmb_softc *sc, i2c_addr_t addr, i2c_op_t op, int flags) { uint8_t data; /* write smbus slave address to register */ data = addr << 1; bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data); /* write smbus protocol to register */ data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_BYTE; bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data); /* check for errors */ if (nfsmb_check_done(sc) < 0) return -1; /* read data */ return bus_space_read_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA); }
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; }
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); }
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 exiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t _addr, const void *cmdbuf, size_t cmdlen, void *databuf, size_t datalen, int flags) { struct exiic_softc *sc = cookie; uint32_t ret = 0; u_int8_t addr = 0; int i = 0; addr = (_addr & 0x7f) << 1; /* clock gating */ //exccm_enable_i2c(sc->unit); if (exiic_wait_state(sc, I2C_STAT, I2C_STAT_BUSY_SIGNAL, 0)) { printf("%s: busy\n", __func__); return (EIO); } /* acknowledge generation */ HSET4(sc, I2C_CON, I2C_CON_ACK); /* Send the slave-address */ HWRITE4(sc, I2C_DS, addr); if (!I2C_OP_READ_P(op) || (cmdbuf && cmdlen)) HWRITE4(sc, I2C_STAT, I2C_STAT_MODE_SEL_MASTER_TX | I2C_STAT_SERIAL_OUTPUT | I2C_STAT_BUSY_SIGNAL); else HWRITE4(sc, I2C_STAT, I2C_STAT_MODE_SEL_MASTER_RX | I2C_STAT_SERIAL_OUTPUT | I2C_STAT_BUSY_SIGNAL); ret = exiic_xfer_wait(sc); if (ret != I2C_ACK) goto fail; /* transmit commands */ if (cmdbuf && cmdlen) { for (i = 0; i < cmdlen; i++) { HWRITE4(sc, I2C_DS, ((uint8_t *)cmdbuf)[i]); exiic_xfer_start(sc); ret = exiic_xfer_wait(sc); if (ret != I2C_ACK) goto fail; } } if (I2C_OP_READ_P(op)) { if (cmdbuf && cmdlen) { /* write slave chip address again for actual read */ HWRITE4(sc, I2C_DS, addr); /* restart */ HWRITE4(sc, I2C_STAT, I2C_STAT_MODE_SEL_MASTER_RX | I2C_STAT_SERIAL_OUTPUT | I2C_STAT_BUSY_SIGNAL); exiic_xfer_start(sc); ret = exiic_xfer_wait(sc); if (ret != I2C_ACK) goto fail; } for (i = 0; i < datalen && ret == I2C_ACK; i++) { /* disable ACK for final read */ if (i == datalen - 1) HCLR4(sc, I2C_CON, I2C_CON_ACK); exiic_xfer_start(sc); ret = exiic_xfer_wait(sc); ((uint8_t *)databuf)[i] = HREAD4(sc, I2C_DS); } if (ret == I2C_NACK) ret = I2C_ACK; /* Normal terminated read. */ } else { for (i = 0; i < datalen && ret == I2C_ACK; i++) { HWRITE4(sc, I2C_DS, ((uint8_t *)databuf)[i]); exiic_xfer_start(sc); ret = exiic_xfer_wait(sc); } } fail: /* send STOP */ if (op & I2C_OP_READ_WITH_STOP) { HWRITE4(sc, I2C_STAT, I2C_STAT_MODE_SEL_MASTER_RX | I2C_STAT_SERIAL_OUTPUT); exiic_xfer_start(sc); } return ret; }
static int cuda_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *_send, size_t send_len, void *_recv, size_t recv_len, int flags) { struct cuda_softc *sc = cookie; const uint8_t *send = _send; uint8_t *recv = _recv; uint8_t command[16] = {CUDA_PSEUDO, CMD_IIC}; DPRINTF("cuda_i2c_exec(%02x)\n", addr); command[2] = addr; /* Copy command and output data bytes, if any, to buffer */ if (send_len > 0) memcpy(&command[3], send, min((int)send_len, 12)); else if (I2C_OP_READ_P(op) && (recv_len == 0)) { /* * If no data bytes in either direction, it's a "quick" * i2c operation. We don't know how to do a quick_read * since that requires us to set the low bit of the * address byte after it has been left-shifted. */ sc->sc_error = 0; return -1; } sc->sc_iic_done = 0; cuda_send(sc, sc->sc_polling, send_len + 3, command); while ((sc->sc_iic_done == 0) && (sc->sc_error == 0)) { if (sc->sc_polling || cold) { cuda_poll(sc); } else tsleep(&sc->sc_todev, 0, "i2c", 1000); } if (sc->sc_error) { sc->sc_error = 0; aprint_error_dev(sc->sc_dev, "error doing I2C\n"); return -1; } /* see if we're supposed to do a read */ if (recv_len > 0) { sc->sc_iic_done = 0; command[2] |= 1; command[3] = 0; /* * XXX we need to do something to limit the size of the answer * - apparently the chip keeps sending until we tell it to stop */ sc->sc_i2c_read_len = recv_len; DPRINTF("rcv_len: %d\n", recv_len); cuda_send(sc, sc->sc_polling, 3, command); while ((sc->sc_iic_done == 0) && (sc->sc_error == 0)) { if (sc->sc_polling || cold) { cuda_poll(sc); } else tsleep(&sc->sc_todev, 0, "i2c", 1000); } if (sc->sc_error) { aprint_error_dev(sc->sc_dev, "error trying to read from I2C\n"); sc->sc_error = 0; return -1; } } DPRINTF("received: %d\n", sc->sc_iic_done); if ((sc->sc_iic_done > 3) && (recv_len > 0)) { int rlen; /* we got an answer */ rlen = min(sc->sc_iic_done - 3, recv_len); memcpy(recv, &sc->sc_in[4], rlen); #ifdef CUDA_DEBUG { int i; printf("ret:"); for (i = 0; i < rlen; i++) printf(" %02x", recv[i]); printf("\n"); } #endif return rlen; } return 0; }
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 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); }
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); }