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

Commit 86ba8b0a authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull i2c bugfixes from Wolfram Sang:
 "I2C driver bugfixes for the 3.17 release.  Details can be found in the
  commit messages, yet I think this is typical driver stuff"

* 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux:
  Revert "i2c: rcar: remove spinlock"
  i2c: at91: add bound checking on SMBus block length bytes
  i2c: rk3x: fix bug that cause transfer fails in master receive mode
  i2c: at91: Fix a race condition during signal handling in at91_do_twi_xfer.
  i2c: mv64xxx: continue probe when clock-frequency is missing
  i2c: rcar: fix MNR interrupt handling
parents fb762340 91bfe298
Loading
Loading
Loading
Loading
+26 −6
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ struct at91_twi_dev {
	unsigned twi_cwgr_reg;
	struct at91_twi_pdata *pdata;
	bool use_dma;
	bool recv_len_abort;
	struct at91_twi_dma dma;
};

@@ -267,12 +268,24 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
	*dev->buf = at91_twi_read(dev, AT91_TWI_RHR) & 0xff;
	--dev->buf_len;

	/* return if aborting, we only needed to read RHR to clear RXRDY*/
	if (dev->recv_len_abort)
		return;

	/* handle I2C_SMBUS_BLOCK_DATA */
	if (unlikely(dev->msg->flags & I2C_M_RECV_LEN)) {
		/* ensure length byte is a valid value */
		if (*dev->buf <= I2C_SMBUS_BLOCK_MAX && *dev->buf > 0) {
			dev->msg->flags &= ~I2C_M_RECV_LEN;
			dev->buf_len += *dev->buf;
			dev->msg->len = dev->buf_len + 1;
		dev_dbg(dev->dev, "received block length %d\n", dev->buf_len);
			dev_dbg(dev->dev, "received block length %d\n",
					 dev->buf_len);
		} else {
			/* abort and send the stop by reading one more byte */
			dev->recv_len_abort = true;
			dev->buf_len = 1;
		}
	}

	/* send stop if second but last byte has been read */
@@ -421,7 +434,7 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
		}
	}

	ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
	ret = wait_for_completion_io_timeout(&dev->cmd_complete,
					     dev->adapter.timeout);
	if (ret == 0) {
		dev_err(dev->dev, "controller timed out\n");
@@ -444,6 +457,12 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
		ret = -EIO;
		goto error;
	}
	if (dev->recv_len_abort) {
		dev_err(dev->dev, "invalid smbus block length recvd\n");
		ret = -EPROTO;
		goto error;
	}

	dev_dbg(dev->dev, "transfer complete\n");

	return 0;
@@ -500,6 +519,7 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
	dev->buf_len = m_start->len;
	dev->buf = m_start->buf;
	dev->msg = m_start;
	dev->recv_len_abort = false;

	ret = at91_do_twi_transfer(dev);

+1 −2
Original line number Diff line number Diff line
@@ -746,8 +746,7 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
	}
	tclk = clk_get_rate(drv_data->clk);

	rc = of_property_read_u32(np, "clock-frequency", &bus_freq);
	if (rc)
	if (of_property_read_u32(np, "clock-frequency", &bus_freq))
		bus_freq = 100000; /* 100kHz by default */

	if (!mv64xxx_find_baud_factors(bus_freq, tclk,
+31 −6
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/spinlock.h>

/* register offsets */
#define ICSCR	0x00	/* slave ctrl */
@@ -95,6 +96,7 @@ struct rcar_i2c_priv {
	struct i2c_msg	*msg;
	struct clk *clk;

	spinlock_t lock;
	wait_queue_head_t wait;

	int pos;
@@ -365,20 +367,20 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
	struct rcar_i2c_priv *priv = ptr;
	u32 msr;

	/*-------------- spin lock -----------------*/
	spin_lock(&priv->lock);

	msr = rcar_i2c_read(priv, ICMSR);

	/* Only handle interrupts that are currently enabled */
	msr &= rcar_i2c_read(priv, ICMIER);

	/* Arbitration lost */
	if (msr & MAL) {
		rcar_i2c_flags_set(priv, (ID_DONE | ID_ARBLOST));
		goto out;
	}

	/* Stop */
	if (msr & MST) {
		rcar_i2c_flags_set(priv, ID_DONE);
		goto out;
	}

	/* Nack */
	if (msr & MNR) {
		/* go to stop phase */
@@ -388,6 +390,12 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
		goto out;
	}

	/* Stop */
	if (msr & MST) {
		rcar_i2c_flags_set(priv, ID_DONE);
		goto out;
	}

	if (rcar_i2c_is_recv(priv))
		rcar_i2c_flags_set(priv, rcar_i2c_irq_recv(priv, msr));
	else
@@ -400,6 +408,9 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
		wake_up(&priv->wait);
	}

	spin_unlock(&priv->lock);
	/*-------------- spin unlock -----------------*/

	return IRQ_HANDLED;
}

@@ -409,14 +420,21 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
{
	struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
	struct device *dev = rcar_i2c_priv_to_dev(priv);
	unsigned long flags;
	int i, ret, timeout;

	pm_runtime_get_sync(dev);

	/*-------------- spin lock -----------------*/
	spin_lock_irqsave(&priv->lock, flags);

	rcar_i2c_init(priv);
	/* start clock */
	rcar_i2c_write(priv, ICCCR, priv->icccr);

	spin_unlock_irqrestore(&priv->lock, flags);
	/*-------------- spin unlock -----------------*/

	ret = rcar_i2c_bus_barrier(priv);
	if (ret < 0)
		goto out;
@@ -428,6 +446,9 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
			break;
		}

		/*-------------- spin lock -----------------*/
		spin_lock_irqsave(&priv->lock, flags);

		/* init each data */
		priv->msg	= &msgs[i];
		priv->pos	= 0;
@@ -437,6 +458,9 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,

		ret = rcar_i2c_prepare_msg(priv);

		spin_unlock_irqrestore(&priv->lock, flags);
		/*-------------- spin unlock -----------------*/

		if (ret < 0)
			break;

@@ -540,6 +564,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)

	irq = platform_get_irq(pdev, 0);
	init_waitqueue_head(&priv->wait);
	spin_lock_init(&priv->lock);

	adap = &priv->adap;
	adap->nr = pdev->id;
+4 −0
Original line number Diff line number Diff line
@@ -323,6 +323,10 @@ static void rk3x_i2c_handle_read(struct rk3x_i2c *i2c, unsigned int ipd)
	/* ack interrupt */
	i2c_writel(i2c, REG_INT_MBRF, REG_IPD);

	/* Can only handle a maximum of 32 bytes at a time */
	if (len > 32)
		len = 32;

	/* read the data from receive buffer */
	for (i = 0; i < len; ++i) {
		if (i % 4 == 0)