コード例 #1
0
ファイル: ki2c.c プロジェクト: avsm/openbsd-xen-sys
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);
}
コード例 #2
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;
}
コード例 #3
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);
}
コード例 #4
0
ファイル: piic.c プロジェクト: ajinkya93/OpenBSD
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);
}
コード例 #5
0
ファイル: drm_dp_helper.c プロジェクト: ajinkya93/OpenBSD
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;
}
コード例 #6
0
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;
}
コード例 #7
0
ファイル: ti_iic.c プロジェクト: enukane/openbsd-work
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;
}
コード例 #8
0
ファイル: ichiic.c プロジェクト: repos-holder/openbsd-patches
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);
}
コード例 #9
0
ファイル: amdpm.c プロジェクト: SylvestreG/bitrig
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);
}
コード例 #10
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);
}
コード例 #11
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);
}
コード例 #12
0
ファイル: nviic.c プロジェクト: SylvestreG/bitrig
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);
}
コード例 #13
0
ファイル: amdiic.c プロジェクト: alenichev/openbsd-kernel
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);
}
コード例 #14
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;
}