Ejemplo n.º 1
0
static void rk30_irq_write_prepare(struct rk30_i2c *i2c)
{
    unsigned int data = 0, cnt = 0, i, j;
    unsigned char byte;

    if(is_msgend(i2c)) {
        rk30_i2c_stop(i2c, i2c->error);
        return;
    }
    for(i = 0; i < 8; i++) {
        data = 0;
        for(j = 0; j < 4; j++) {
            if(is_msgend(i2c))
                break;
            if(i2c->msg_ptr == 0 && cnt == 0)
                byte = (i2c->addr & 0x7f) << 1;
            else
                byte =  i2c->msg->buf[i2c->msg_ptr++];
            cnt++;
            data |= (byte << (j * 8));
        }
        i2c_writel(data, i2c->regs + I2C_TXDATA_BASE + 4 * i);
        if(is_msgend(i2c))
            break;
    }
    i2c_writel(cnt, i2c->regs + I2C_MTXCNT);
}
Ejemplo n.º 2
0
static void rk30_irq_read_prepare(struct rk30_i2c *i2c)
{
    unsigned int cnt, len = i2c->msg->len - i2c->msg_ptr;

    if(len <= 32 && i2c->msg_ptr != 0)
        rk30_set_rx_mode(i2c, 1);
    else if(i2c->msg_ptr != 0)
        rk30_set_rx_mode(i2c, 0);

    if(is_msgend(i2c)) {
        rk30_i2c_stop(i2c, i2c->error);
        return;
    }
    if(len > 32)
        cnt = 32;
    else
        cnt = len;
    i2c_writel(cnt, i2c->regs + I2C_MRXCNT);
}
Ejemplo n.º 3
0
static irqreturn_t synquacer_i2c_isr(int irq, void *dev_id)
{
	struct synquacer_i2c *i2c = dev_id;

	unsigned char byte;
	unsigned char bsr, bcr;
	int ret;

	bcr = readb(i2c->base + SYNQUACER_I2C_REG_BCR);
	bsr = readb(i2c->base + SYNQUACER_I2C_REG_BSR);
	dev_dbg(i2c->dev, "bsr:0x%02x, bcr:0x%02x\n", bsr, bcr);

	if (bcr & SYNQUACER_I2C_BCR_BER) {
		dev_err(i2c->dev, "bus error\n");
		synquacer_i2c_stop(i2c, -EAGAIN);
		goto out;
	}
	if ((bsr & SYNQUACER_I2C_BSR_AL) ||
	    !(bcr & SYNQUACER_I2C_BCR_MSS)) {
		dev_dbg(i2c->dev, "arbitration lost\n");
		synquacer_i2c_stop(i2c, -EAGAIN);
		goto out;
	}

	switch (i2c->state) {
	case STATE_START:
		if (bsr & SYNQUACER_I2C_BSR_LRB) {
			dev_dbg(i2c->dev, "ack was not received\n");
			synquacer_i2c_stop(i2c, -EAGAIN);
			goto out;
		}

		if (i2c->msg->flags & I2C_M_RD)
			i2c->state = STATE_READ;
		else
			i2c->state = STATE_WRITE;

		if (is_lastmsg(i2c) && i2c->msg->len == 0) {
			synquacer_i2c_stop(i2c, 0);
			goto out;
		}

		if (i2c->state == STATE_READ)
			goto prepare_read;

		/* fall through */

	case STATE_WRITE:
		if (bsr & SYNQUACER_I2C_BSR_LRB) {
			dev_dbg(i2c->dev, "WRITE: No Ack\n");
			synquacer_i2c_stop(i2c, -EAGAIN);
			goto out;
		}

		if (!is_msgend(i2c)) {
			writeb(i2c->msg->buf[i2c->msg_ptr++],
			       i2c->base + SYNQUACER_I2C_REG_DAR);

			/* clear IRQ, and continue */
			writeb(SYNQUACER_I2C_BCR_BEIE |
			       SYNQUACER_I2C_BCR_MSS |
			       SYNQUACER_I2C_BCR_INTE,
			       i2c->base + SYNQUACER_I2C_REG_BCR);
			break;
		}
		if (is_lastmsg(i2c)) {
			synquacer_i2c_stop(i2c, 0);
			break;
		}
		dev_dbg(i2c->dev, "WRITE: Next Message\n");

		i2c->msg_ptr = 0;
		i2c->msg_idx++;
		i2c->msg++;

		/* send the new start */
		ret = synquacer_i2c_master_start(i2c, i2c->msg);
		if (ret < 0) {
			dev_dbg(i2c->dev, "restart error (%d)\n", ret);
			synquacer_i2c_stop(i2c, -EAGAIN);
			break;
		}
		i2c->state = STATE_START;
		break;

	case STATE_READ:
		byte = readb(i2c->base + SYNQUACER_I2C_REG_DAR);
		if (!(bsr & SYNQUACER_I2C_BSR_FBT)) /* data */
			i2c->msg->buf[i2c->msg_ptr++] = byte;
		else /* address */
			dev_dbg(i2c->dev, "address:0x%02x. ignore it.\n", byte);

prepare_read:
		if (is_msglast(i2c)) {
			writeb(SYNQUACER_I2C_BCR_MSS |
			       SYNQUACER_I2C_BCR_BEIE |
			       SYNQUACER_I2C_BCR_INTE,
			       i2c->base + SYNQUACER_I2C_REG_BCR);
			break;
		}
		if (!is_msgend(i2c)) {
			writeb(SYNQUACER_I2C_BCR_MSS |
			       SYNQUACER_I2C_BCR_BEIE |
			       SYNQUACER_I2C_BCR_INTE |
			       SYNQUACER_I2C_BCR_ACK,
			       i2c->base + SYNQUACER_I2C_REG_BCR);
			break;
		}
		if (is_lastmsg(i2c)) {
			/* last message, send stop and complete */
			dev_dbg(i2c->dev, "READ: Send Stop\n");
			synquacer_i2c_stop(i2c, 0);
			break;
		}
		dev_dbg(i2c->dev, "READ: Next Transfer\n");

		i2c->msg_ptr = 0;
		i2c->msg_idx++;
		i2c->msg++;

		ret = synquacer_i2c_master_start(i2c, i2c->msg);
		if (ret < 0) {
			dev_dbg(i2c->dev, "restart error (%d)\n", ret);
			synquacer_i2c_stop(i2c, -EAGAIN);
		} else {
			i2c->state = STATE_START;
		}
		break;
	default:
		dev_err(i2c->dev, "called in err STATE (%d)\n", i2c->state);
		break;
	}

out:
	WAIT_PCLK(10, i2c->pclkrate);
	return IRQ_HANDLED;
}