예제 #1
0
파일: i2c-pnx.c 프로젝트: c444b774/linux
/**
 * i2c_pnx_xfer - generic transfer entry point
 * @adap:		pointer to I2C adapter structure
 * @msgs:		array of messages
 * @num:		number of messages
 *
 * Initiates the transfer
 */
static int
i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
	struct i2c_msg *pmsg;
	int rc = 0, completed = 0, i;
	struct i2c_pnx_algo_data *alg_data = adap->algo_data;
	u32 stat = ioread32(I2C_REG_STS(alg_data));

	dev_dbg(&alg_data->adapter.dev,
		"%s(): entering: %d messages, stat = %04x.\n",
		__func__, num, ioread32(I2C_REG_STS(alg_data)));

	bus_reset_if_active(alg_data);

	/* Process transactions in a loop. */
	for (i = 0; rc >= 0 && i < num; i++) {
		u8 addr;

		pmsg = &msgs[i];
		addr = pmsg->addr;

		if (pmsg->flags & I2C_M_TEN) {
			dev_err(&alg_data->adapter.dev,
				"%s: 10 bits addr not supported!\n",
				alg_data->adapter.name);
			rc = -EINVAL;
			break;
		}

		alg_data->mif.buf = pmsg->buf;
		alg_data->mif.len = pmsg->len;
		alg_data->mif.order = pmsg->len;
		alg_data->mif.mode = (pmsg->flags & I2C_M_RD) ?
			I2C_SMBUS_READ : I2C_SMBUS_WRITE;
		alg_data->mif.ret = 0;
		alg_data->last = (i == num - 1);

		dev_dbg(&alg_data->adapter.dev, "%s(): mode %d, %d bytes\n",
			__func__, alg_data->mif.mode, alg_data->mif.len);

		i2c_pnx_arm_timer(alg_data);

		/* initialize the completion var */
		init_completion(&alg_data->mif.complete);

		/* Enable master interrupt */
		iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_afie |
				mcntrl_naie | mcntrl_drmie,
			  I2C_REG_CTL(alg_data));

		/* Put start-code and slave-address on the bus. */
		rc = i2c_pnx_start(addr, alg_data);
		if (rc < 0)
			break;

		/* Wait for completion */
		wait_for_completion(&alg_data->mif.complete);

		if (!(rc = alg_data->mif.ret))
			completed++;
		dev_dbg(&alg_data->adapter.dev,
			"%s(): Complete, return code = %d.\n",
			__func__, rc);

		/* Clear TDI and AFI bits in case they are set. */
		if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_tdi) {
			dev_dbg(&alg_data->adapter.dev,
				"%s: TDI still set... clearing now.\n",
				alg_data->adapter.name);
			iowrite32(stat, I2C_REG_STS(alg_data));
		}
		if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_afi) {
			dev_dbg(&alg_data->adapter.dev,
				"%s: AFI still set... clearing now.\n",
				alg_data->adapter.name);
			iowrite32(stat, I2C_REG_STS(alg_data));
		}
	}

	bus_reset_if_active(alg_data);

	/* Cleanup to be sure... */
	alg_data->mif.buf = NULL;
	alg_data->mif.len = 0;
	alg_data->mif.order = 0;

	dev_dbg(&alg_data->adapter.dev, "%s(): exiting, stat = %x\n",
		__func__, ioread32(I2C_REG_STS(alg_data)));

	if (completed != num)
		return ((rc < 0) ? rc : -EREMOTEIO);

	return num;
}
예제 #2
0
/*
 * Generic transfer entrypoint
 */
static int
i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{
	struct i2c_msg *pmsg;
	int rc = 0, completed = 0, i;
	i2c_pnx_algo_data_t * alg_data = (i2c_pnx_algo_data_t *) adap->algo_data;

	pr_debug ("%s: Entered\n", __FUNCTION__);

	/* Give an error if we're suspended. */
	if (adap->dev.parent->power.power_state)
		return -EBUSY;
		
	down(&alg_data->mif.sem);

	/* If the bus is still active, or there is already
	 * data in one of the fifo's, there is something wrong.
	 * Repair this by a reset ...
	 */
	if ((alg_data->master->sts & mstatus_active)) {
		alg_data->master->ctl |= mcntrl_reset;
		while (alg_data->master->ctl & mcntrl_reset);
	} else if (!(alg_data->master->sts & mstatus_rfe) ||
		!(alg_data->master->sts & mstatus_tfe)) {
		printk(KERN_ERR
			"%s: FIFO's contain already data before xfer. Reset it ...\n",
			adap->name);

		alg_data->master->ctl |= mcntrl_reset;
		while (alg_data->master->ctl & mcntrl_reset);
	}
 
	/* Process transactions in a loop. */
	for (i = 0; rc >= 0 && i < num;) {
		u8 addr;

		pmsg = &msgs[i++];
		addr = pmsg->addr;

		if (pmsg->flags & I2C_M_TEN) {
			printk(KERN_ERR
				"%s: 10 bits addr not supported !\n", adap->name);
			rc = -EINVAL;
			break;
		}
 
		/* Check address for sanity. */
		if (alg_data->slave && addr == alg_data->slave->adr) {
			printk("%s: An attempt was made to access our own slave address! :-)\n",
				adap->name);
			rc = -EINVAL;
			break;
		}

		/* Set up address and r/w bit */
		if (pmsg->flags & I2C_M_REV_DIR_ADDR) {
			addr ^= 1;
		}

		alg_data->mif.buf = pmsg->buf;
		alg_data->mif.len = pmsg->len;
		alg_data->mif.mode = (pmsg->flags & I2C_M_RD) ? rcv : xmit;
		alg_data->mif.ret = 0;

#if I2C_PNX010X_DEBUG
		pr_debug("%s: %s mode, %d bytes\n", __FUNCTION__,
			i2c_pnx_modestr[alg_data->mif.mode], alg_data->mif.len);
#endif

		/* Arm timer */
		i2c_pnx_arm_timer(&alg_data->mif.timer, (void *) alg_data);

		/* initialize the completion var */	
		init_completion(&alg_data->mif.complete);
		
		/* Enable master interrupt */
		alg_data->master->ctl = mcntrl_afie | mcntrl_naie | mcntrl_drmie;

		/* Put start-code and slave-address on the bus. */
		rc = i2c_pnx_start(addr, adap);
		if (0 != rc) {
			break;
		}
 
		pr_debug("%s(%d): stat = %04x, cntrl = %04x.\n",
			__FUNCTION__, __LINE__, alg_data->master->sts, alg_data->master->ctl);

		/* Wait for completion */
		wait_for_completion(&alg_data->mif.complete);

		if (!(rc = alg_data->mif.ret))
			completed++;
		pr_debug("%s: Return code = %d.\n", __FUNCTION__, rc);

		/* Clear TDI and AFI bits in case they are set. */
		if (alg_data->master->sts & mstatus_tdi) {
			printk("%s: TDI still set ... clearing now.\n", adap->name);
			alg_data->master->sts |= mstatus_tdi;
		}
		if (alg_data->master->sts & mstatus_afi) {
			printk("%s: AFI still set ... clearing now.\n", adap->name);
			alg_data->master->sts |= mstatus_afi;
		}
	}

	/* If the bus is still active, reset it to prevent
	 * corruption of future transactions.
	 */
	if ((alg_data->master->sts & mstatus_active)) {
		printk("%s: Bus is still active after xfer. Reset it ...\n",
			adap->name);
		alg_data->master->ctl |= mcntrl_reset;
		while (alg_data->master->ctl & mcntrl_reset);
	} else
		/* If there is data in the fifo's after transfer,
		 * flush fifo's by reset.
		 */
		if (!(alg_data->master->sts & mstatus_rfe) ||
			!(alg_data->master->sts & mstatus_tfe)) {
			alg_data->master->ctl |= mcntrl_reset;
			while (alg_data->master->ctl & mcntrl_reset);
		} else if ((alg_data->master->sts & mstatus_nai)) {
			alg_data->master->ctl |= mcntrl_reset;
			while (alg_data->master->ctl & mcntrl_reset);
		}

	/* Cleanup to be sure ... */
	alg_data->mif.buf = NULL;
	alg_data->mif.len = 0;

	/* Release sem */
	up(&alg_data->mif.sem);
	pr_debug ("%s: Exit\n", __FUNCTION__);

	if (completed != num) {
		return ((rc<0) ? rc : -EREMOTEIO);
	}
	return num ;
}