Exemplo n.º 1
0
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);
}
Exemplo n.º 2
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);
}
Exemplo n.º 3
0
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;
}
Exemplo n.º 4
0
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);
}
Exemplo n.º 5
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;
}
Exemplo n.º 6
0
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;
}
Exemplo n.º 7
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;
}
Exemplo n.º 8
0
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);
}
Exemplo n.º 9
0
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);
}
Exemplo n.º 10
0
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;
}
Exemplo n.º 11
0
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;
}
Exemplo n.º 12
0
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;  
}
Exemplo n.º 13
0
/* 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);
}
Exemplo n.º 14
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;
}
Exemplo n.º 15
0
/* 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);
}
Exemplo n.º 16
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;
}
Exemplo n.º 17
0
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);
}
Exemplo n.º 18
0
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);
}
Exemplo n.º 19
0
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;
}
Exemplo n.º 20
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);
}
Exemplo n.º 21
0
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);
}
Exemplo n.º 22
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;
}
Exemplo n.º 23
0
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;
}
Exemplo n.º 24
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);
}
Exemplo n.º 25
0
int
sociic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr,
    const void *vcmdbuf, size_t cmdlen, void *vbuf, size_t buflen, int flags)
{
	struct sociic_softc *sc = arg;
	const uint8_t *cmdbuf = vcmdbuf;
	uint8_t *buf = vbuf;
	int err = 0;
	size_t len;
	uint8_t val;

	/* Clear the bus. */
	sociic_write(sc, I2C_SR, 0);
	sociic_write(sc, I2C_CR, I2C_CR_MEN);
	err = sociic_wait_bus(sc);
	if (err)
		return (err);

	if (cmdlen > 0) {
		sociic_write(sc, I2C_CR, I2C_CR_MEN|I2C_CR_MSTA|I2C_CR_MTX);
		sociic_write(sc, I2C_DR, addr << 1);
		err = sociic_wait(sc, I2C_F_WRITE);
		if (err)
			goto out;

		len = cmdlen;
		while (len--) {
			sociic_write(sc, I2C_DR, *cmdbuf++);
			err = sociic_wait(sc, I2C_F_WRITE);
			if (err)
				goto out;
		}
	}

	if (I2C_OP_READ_P(op) && buflen > 0) {
		/* RESTART if we did write a command above. */
		val = I2C_CR_MEN|I2C_CR_MSTA|I2C_CR_MTX;
		if (cmdlen > 0)
			val |= I2C_CR_RSTA;
		sociic_write(sc, I2C_CR, val);
		sociic_write(sc, I2C_DR, (addr << 1) | 1);
		err = sociic_wait(sc, I2C_F_WRITE);
		if (err)
			goto out;

		/* NACK if we're only sending one byte. */
		val = I2C_CR_MEN|I2C_CR_MSTA;
		if (buflen == 1)
			val |= I2C_CR_TXAK;
		sociic_write(sc, I2C_CR, val);

		/* Dummy read. */
		sociic_read(sc, I2C_DR);

		len = buflen;
		while (len--) {
			err = sociic_wait(sc, I2C_F_READ);
			if (err)
				goto out;

			/* NACK on last byte. */
			if (len == 1)
				sociic_write(sc, I2C_CR,
				    I2C_CR_MEN|I2C_CR_MSTA|I2C_CR_TXAK);
			/* STOP after last byte. */
			if (len == 0)
				sociic_write(sc, I2C_CR,
				    I2C_CR_MEN|I2C_CR_TXAK);
			*buf++ = sociic_read(sc, I2C_DR);
		}
	}

	if (I2C_OP_WRITE_P(op) && cmdlen == 0 && buflen > 0) {
		/* START if we didn't write a command. */
		sociic_write(sc, I2C_CR, I2C_CR_MEN|I2C_CR_MSTA|I2C_CR_MTX);
		sociic_write(sc, I2C_DR, addr << 1);
		err = sociic_wait(sc, I2C_F_WRITE);
		if (err)
			goto out;
	}

	if (I2C_OP_WRITE_P(op) && buflen > 0) {
		len = buflen;
		while (len--) {
			sociic_write(sc, I2C_DR, *buf++);
			err = sociic_wait(sc, I2C_F_WRITE);
			if (err)
				goto out;
		}
	}

out:
	/* STOP if we're still holding the bus. */
	sociic_write(sc, I2C_CR, I2C_CR_MEN);
	return (err);
}
Exemplo n.º 26
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);
}