static int owl_i2c_xfer_common()

in busses/i2c-owl.c [251:407]


static int owl_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg *msgs,
			       int num, bool atomic)
{
	struct owl_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
	struct i2c_msg *msg;
	unsigned long time_left, flags;
	unsigned int i2c_cmd, val;
	unsigned int addr;
	int ret, idx;

	spin_lock_irqsave(&i2c_dev->lock, flags);

	/* Reset I2C controller */
	owl_i2c_reset(i2c_dev);

	/* Set bus frequency */
	owl_i2c_set_freq(i2c_dev);

	/*
	 * Spinlock should be released before calling reset FIFO and
	 * bus busy check since those functions may sleep
	 */
	spin_unlock_irqrestore(&i2c_dev->lock, flags);

	/* Reset FIFO */
	ret = owl_i2c_reset_fifo(i2c_dev);
	if (ret)
		goto unlocked_err_exit;

	/* Check for bus busy */
	ret = owl_i2c_check_bus_busy(adap);
	if (ret)
		goto unlocked_err_exit;

	spin_lock_irqsave(&i2c_dev->lock, flags);

	/* Check for Arbitration lost */
	val = readl(i2c_dev->base + OWL_I2C_REG_STAT);
	if (val & OWL_I2C_STAT_LAB) {
		val &= ~OWL_I2C_STAT_LAB;
		writel(val, i2c_dev->base + OWL_I2C_REG_STAT);
		ret = -EAGAIN;
		goto err_exit;
	}

	if (!atomic)
		reinit_completion(&i2c_dev->msg_complete);

	/* Enable/disable I2C controller interrupt */
	owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
			   OWL_I2C_CTL_IRQE, !atomic);

	/*
	 * Select: FIFO enable, Master mode, Stop enable, Data count enable,
	 * Send start bit
	 */
	i2c_cmd = OWL_I2C_CMD_SECL | OWL_I2C_CMD_MSS | OWL_I2C_CMD_SE |
		  OWL_I2C_CMD_NS | OWL_I2C_CMD_DE | OWL_I2C_CMD_SBE;

	/* Handle repeated start condition */
	if (num > 1) {
		/* Set internal address length and enable repeated start */
		i2c_cmd |= OWL_I2C_CMD_AS(msgs[0].len + 1) |
			   OWL_I2C_CMD_SAS(1) | OWL_I2C_CMD_RBE;

		/* Write slave address */
		addr = i2c_8bit_addr_from_msg(&msgs[0]);
		writel(addr, i2c_dev->base + OWL_I2C_REG_TXDAT);

		/* Write internal register address */
		for (idx = 0; idx < msgs[0].len; idx++)
			writel(msgs[0].buf[idx],
			       i2c_dev->base + OWL_I2C_REG_TXDAT);

		msg = &msgs[1];
	} else {
		/* Set address length */
		i2c_cmd |= OWL_I2C_CMD_AS(1);
		msg = &msgs[0];
	}

	i2c_dev->msg = msg;
	i2c_dev->msg_ptr = 0;

	/* Set data count for the message */
	writel(msg->len, i2c_dev->base + OWL_I2C_REG_DATCNT);

	addr = i2c_8bit_addr_from_msg(msg);
	writel(addr, i2c_dev->base + OWL_I2C_REG_TXDAT);

	if (!(msg->flags & I2C_M_RD)) {
		/* Write data to FIFO */
		for (idx = 0; idx < msg->len; idx++) {
			/* Check for FIFO full */
			if (readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT) &
			    OWL_I2C_FIFOSTAT_TFF)
				break;

			writel(msg->buf[idx],
			       i2c_dev->base + OWL_I2C_REG_TXDAT);
		}

		i2c_dev->msg_ptr = idx;
	}

	/* Ignore the NACK if needed */
	if (msg->flags & I2C_M_IGNORE_NAK)
		owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOCTL,
				   OWL_I2C_FIFOCTL_NIB, true);
	else
		owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOCTL,
				   OWL_I2C_FIFOCTL_NIB, false);

	/* Start the transfer */
	writel(i2c_cmd, i2c_dev->base + OWL_I2C_REG_CMD);

	spin_unlock_irqrestore(&i2c_dev->lock, flags);

	if (atomic) {
		/* Wait for Command Execute Completed or NACK Error bits */
		ret = readl_poll_timeout_atomic(i2c_dev->base + OWL_I2C_REG_FIFOSTAT,
						val, val & (OWL_I2C_FIFOSTAT_CECB |
							    OWL_I2C_FIFOSTAT_RNB),
						10, OWL_I2C_TIMEOUT_MS * 1000);
	} else {
		time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
							adap->timeout);
		if (!time_left)
			ret = -ETIMEDOUT;
	}

	spin_lock_irqsave(&i2c_dev->lock, flags);

	if (ret) {
		dev_err(&adap->dev, "Transaction timed out\n");
		/* Send stop condition and release the bus */
		owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
				   OWL_I2C_CTL_GBCC_STOP | OWL_I2C_CTL_RB,
				   true);
		goto err_exit;
	}

	if (atomic)
		owl_i2c_xfer_data(i2c_dev);

	ret = i2c_dev->err < 0 ? i2c_dev->err : num;

err_exit:
	spin_unlock_irqrestore(&i2c_dev->lock, flags);

unlocked_err_exit:
	/* Disable I2C controller */
	owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
			   OWL_I2C_CTL_EN, false);

	return ret;
}