Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 52f842cc authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'i2c/for-current-fixed' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux

Pull i2c fixes from Wolfram Sang:
 "A set of driver bugfixes for the I2C subsystem"

* 'i2c/for-current-fixed' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux:
  i2c: uniphier-f: fix violation of tLOW requirement for Fast-mode
  i2c: uniphier: fix violation of tLOW requirement for Fast-mode
  i2c: uniphier-f: fill TX-FIFO only in IRQ handler for repeated START
  i2c: uniphier-f: fix timeout error after reading 8 bytes
  i2c: scmi: Fix probe error on devices with an empty SMB0001 ACPI device node
  i2c: axxia: properly handle master timeout
  i2c: rcar: check bus state before reinitializing
  i2c: nvidia-gpu: limit reads also for combined messages
  i2c: nvidia-gpu: adhere to I2C fault codes
parents c431b420 ece27a33
Loading
Loading
Loading
Loading
+29 −11
Original line number Diff line number Diff line
@@ -74,8 +74,7 @@
				 MST_STATUS_ND)
#define   MST_STATUS_ERR	(MST_STATUS_NAK | \
				 MST_STATUS_AL  | \
				 MST_STATUS_IP  | \
				 MST_STATUS_TSS)
				 MST_STATUS_IP)
#define MST_TX_BYTES_XFRD	0x50
#define MST_RX_BYTES_XFRD	0x54
#define SCL_HIGH_PERIOD		0x80
@@ -241,7 +240,7 @@ static int axxia_i2c_empty_rx_fifo(struct axxia_i2c_dev *idev)
			 */
			if (c <= 0 || c > I2C_SMBUS_BLOCK_MAX) {
				idev->msg_err = -EPROTO;
				i2c_int_disable(idev, ~0);
				i2c_int_disable(idev, ~MST_STATUS_TSS);
				complete(&idev->msg_complete);
				break;
			}
@@ -299,14 +298,19 @@ static irqreturn_t axxia_i2c_isr(int irq, void *_dev)

	if (status & MST_STATUS_SCC) {
		/* Stop completed */
		i2c_int_disable(idev, ~0);
		i2c_int_disable(idev, ~MST_STATUS_TSS);
		complete(&idev->msg_complete);
	} else if (status & MST_STATUS_SNS) {
		/* Transfer done */
		i2c_int_disable(idev, ~0);
		i2c_int_disable(idev, ~MST_STATUS_TSS);
		if (i2c_m_rd(idev->msg) && idev->msg_xfrd < idev->msg->len)
			axxia_i2c_empty_rx_fifo(idev);
		complete(&idev->msg_complete);
	} else if (status & MST_STATUS_TSS) {
		/* Transfer timeout */
		idev->msg_err = -ETIMEDOUT;
		i2c_int_disable(idev, ~MST_STATUS_TSS);
		complete(&idev->msg_complete);
	} else if (unlikely(status & MST_STATUS_ERR)) {
		/* Transfer error */
		i2c_int_disable(idev, ~0);
@@ -339,10 +343,10 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
	u32 rx_xfer, tx_xfer;
	u32 addr_1, addr_2;
	unsigned long time_left;
	unsigned int wt_value;

	idev->msg = msg;
	idev->msg_xfrd = 0;
	idev->msg_err = 0;
	reinit_completion(&idev->msg_complete);

	if (i2c_m_ten(msg)) {
@@ -383,9 +387,18 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
	else if (axxia_i2c_fill_tx_fifo(idev) != 0)
		int_mask |= MST_STATUS_TFL;

	wt_value = WT_VALUE(readl(idev->base + WAIT_TIMER_CONTROL));
	/* Disable wait timer temporarly */
	writel(wt_value, idev->base + WAIT_TIMER_CONTROL);
	/* Check if timeout error happened */
	if (idev->msg_err)
		goto out;

	/* Start manual mode */
	writel(CMD_MANUAL, idev->base + MST_COMMAND);

	writel(WT_EN | wt_value, idev->base + WAIT_TIMER_CONTROL);

	i2c_int_enable(idev, int_mask);

	time_left = wait_for_completion_timeout(&idev->msg_complete,
@@ -396,13 +409,15 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
	if (readl(idev->base + MST_COMMAND) & CMD_BUSY)
		dev_warn(idev->dev, "busy after xfer\n");

	if (time_left == 0)
	if (time_left == 0) {
		idev->msg_err = -ETIMEDOUT;

	if (idev->msg_err == -ETIMEDOUT)
		i2c_recover_bus(&idev->adapter);
		axxia_i2c_init(idev);
	}

	if (unlikely(idev->msg_err) && idev->msg_err != -ENXIO)
out:
	if (unlikely(idev->msg_err) && idev->msg_err != -ENXIO &&
			idev->msg_err != -ETIMEDOUT)
		axxia_i2c_init(idev);

	return idev->msg_err;
@@ -410,7 +425,7 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)

static int axxia_i2c_stop(struct axxia_i2c_dev *idev)
{
	u32 int_mask = MST_STATUS_ERR | MST_STATUS_SCC;
	u32 int_mask = MST_STATUS_ERR | MST_STATUS_SCC | MST_STATUS_TSS;
	unsigned long time_left;

	reinit_completion(&idev->msg_complete);
@@ -437,6 +452,9 @@ axxia_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
	int i;
	int ret = 0;

	idev->msg_err = 0;
	i2c_int_enable(idev, MST_STATUS_TSS);

	for (i = 0; ret == 0 && i < num; ++i)
		ret = axxia_i2c_xfer_msg(idev, &msgs[i]);

+4 −3
Original line number Diff line number Diff line
@@ -89,7 +89,7 @@ static int gpu_i2c_check_status(struct gpu_i2c_dev *i2cd)

	if (time_is_before_jiffies(target)) {
		dev_err(i2cd->dev, "i2c timeout error %x\n", val);
		return -ETIME;
		return -ETIMEDOUT;
	}

	val = readl(i2cd->regs + I2C_MST_CNTL);
@@ -97,9 +97,9 @@ static int gpu_i2c_check_status(struct gpu_i2c_dev *i2cd)
	case I2C_MST_CNTL_STATUS_OKAY:
		return 0;
	case I2C_MST_CNTL_STATUS_NO_ACK:
		return -EIO;
		return -ENXIO;
	case I2C_MST_CNTL_STATUS_TIMEOUT:
		return -ETIME;
		return -ETIMEDOUT;
	default:
		return 0;
	}
@@ -218,6 +218,7 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,

static const struct i2c_adapter_quirks gpu_i2c_quirks = {
	.max_read_len = 4,
	.max_comb_2nd_msg_len = 4,
	.flags = I2C_AQ_COMB_WRITE_THEN_READ,
};

+5 −4
Original line number Diff line number Diff line
@@ -779,6 +779,11 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,

	pm_runtime_get_sync(dev);

	/* Check bus state before init otherwise bus busy info will be lost */
	ret = rcar_i2c_bus_barrier(priv);
	if (ret < 0)
		goto out;

	/* Gen3 needs a reset before allowing RXDMA once */
	if (priv->devtype == I2C_RCAR_GEN3) {
		priv->flags |= ID_P_NO_RXDMA;
@@ -791,10 +796,6 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,

	rcar_i2c_init(priv);

	ret = rcar_i2c_bus_barrier(priv);
	if (ret < 0)
		goto out;

	for (i = 0; i < num; i++)
		rcar_i2c_request_dma(priv, msgs + i);

+7 −3
Original line number Diff line number Diff line
@@ -367,6 +367,7 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
{
	struct acpi_smbus_cmi *smbus_cmi;
	const struct acpi_device_id *id;
	int ret;

	smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL);
	if (!smbus_cmi)
@@ -388,8 +389,10 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
	acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1,
			    acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL);

	if (smbus_cmi->cap_info == 0)
	if (smbus_cmi->cap_info == 0) {
		ret = -ENODEV;
		goto err;
	}

	snprintf(smbus_cmi->adapter.name, sizeof(smbus_cmi->adapter.name),
		"SMBus CMI adapter %s",
@@ -400,7 +403,8 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
	smbus_cmi->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
	smbus_cmi->adapter.dev.parent = &device->dev;

	if (i2c_add_adapter(&smbus_cmi->adapter)) {
	ret = i2c_add_adapter(&smbus_cmi->adapter);
	if (ret) {
		dev_err(&device->dev, "Couldn't register adapter!\n");
		goto err;
	}
@@ -410,7 +414,7 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
err:
	kfree(smbus_cmi);
	device->driver_data = NULL;
	return -EIO;
	return ret;
}

static int acpi_smbus_cmi_remove(struct acpi_device *device)
+41 −8
Original line number Diff line number Diff line
@@ -173,8 +173,6 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)
		"interrupt: enabled_irqs=%04x, irq_status=%04x\n",
		priv->enabled_irqs, irq_status);

	uniphier_fi2c_clear_irqs(priv, irq_status);

	if (irq_status & UNIPHIER_FI2C_INT_STOP)
		goto complete;

@@ -214,7 +212,13 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)

	if (irq_status & (UNIPHIER_FI2C_INT_RF | UNIPHIER_FI2C_INT_RB)) {
		uniphier_fi2c_drain_rxfifo(priv);
		if (!priv->len)
		/*
		 * If the number of bytes to read is multiple of the FIFO size
		 * (msg->len == 8, 16, 24, ...), the INT_RF bit is set a little
		 * earlier than INT_RB. We wait for INT_RB to confirm the
		 * completion of the current message.
		 */
		if (!priv->len && (irq_status & UNIPHIER_FI2C_INT_RB))
			goto data_done;

		if (unlikely(priv->flags & UNIPHIER_FI2C_MANUAL_NACK)) {
@@ -253,12 +257,20 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)
	}

handled:
	/*
	 * This controller makes a pause while any bit of the IRQ status is
	 * asserted. Clear the asserted bit to kick the controller just before
	 * exiting the handler.
	 */
	uniphier_fi2c_clear_irqs(priv, irq_status);

	spin_unlock(&priv->lock);

	return IRQ_HANDLED;
}

static void uniphier_fi2c_tx_init(struct uniphier_fi2c_priv *priv, u16 addr)
static void uniphier_fi2c_tx_init(struct uniphier_fi2c_priv *priv, u16 addr,
				  bool repeat)
{
	priv->enabled_irqs |= UNIPHIER_FI2C_INT_TE;
	uniphier_fi2c_set_irqs(priv);
@@ -268,7 +280,11 @@ static void uniphier_fi2c_tx_init(struct uniphier_fi2c_priv *priv, u16 addr)
	/* set slave address */
	writel(UNIPHIER_FI2C_DTTX_CMD | addr << 1,
	       priv->membase + UNIPHIER_FI2C_DTTX);
	/* first chunk of data */
	/*
	 * First chunk of data. For a repeated START condition, do not write
	 * data to the TX fifo here to avoid the timing issue.
	 */
	if (!repeat)
		uniphier_fi2c_fill_txfifo(priv, true);
}

@@ -350,7 +366,7 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap,
	if (is_read)
		uniphier_fi2c_rx_init(priv, msg->addr);
	else
		uniphier_fi2c_tx_init(priv, msg->addr);
		uniphier_fi2c_tx_init(priv, msg->addr, repeat);

	dev_dbg(&adap->dev, "start condition\n");
	/*
@@ -502,9 +518,26 @@ static void uniphier_fi2c_hw_init(struct uniphier_fi2c_priv *priv)

	uniphier_fi2c_reset(priv);

	/*
	 *  Standard-mode: tLOW + tHIGH = 10 us
	 *  Fast-mode:     tLOW + tHIGH = 2.5 us
	 */
	writel(cyc, priv->membase + UNIPHIER_FI2C_CYC);
	writel(cyc / 2, priv->membase + UNIPHIER_FI2C_LCTL);
	/*
	 *  Standard-mode: tLOW = 4.7 us, tHIGH = 4.0 us, tBUF = 4.7 us
	 *  Fast-mode:     tLOW = 1.3 us, tHIGH = 0.6 us, tBUF = 1.3 us
	 * "tLow/tHIGH = 5/4" meets both.
	 */
	writel(cyc * 5 / 9, priv->membase + UNIPHIER_FI2C_LCTL);
	/*
	 *  Standard-mode: tHD;STA = 4.0 us, tSU;STA = 4.7 us, tSU;STO = 4.0 us
	 *  Fast-mode:     tHD;STA = 0.6 us, tSU;STA = 0.6 us, tSU;STO = 0.6 us
	 */
	writel(cyc / 2, priv->membase + UNIPHIER_FI2C_SSUT);
	/*
	 *  Standard-mode: tSU;DAT = 250 ns
	 *  Fast-mode:     tSU;DAT = 100 ns
	 */
	writel(cyc / 16, priv->membase + UNIPHIER_FI2C_DSUT);

	uniphier_fi2c_prepare_operation(priv);
Loading