Merge branch 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
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
This commit is contained in:
commit
86ba8b0aee
|
@ -101,6 +101,7 @@ struct at91_twi_dev {
|
||||||
unsigned twi_cwgr_reg;
|
unsigned twi_cwgr_reg;
|
||||||
struct at91_twi_pdata *pdata;
|
struct at91_twi_pdata *pdata;
|
||||||
bool use_dma;
|
bool use_dma;
|
||||||
|
bool recv_len_abort;
|
||||||
struct at91_twi_dma dma;
|
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 = at91_twi_read(dev, AT91_TWI_RHR) & 0xff;
|
||||||
--dev->buf_len;
|
--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 */
|
/* handle I2C_SMBUS_BLOCK_DATA */
|
||||||
if (unlikely(dev->msg->flags & I2C_M_RECV_LEN)) {
|
if (unlikely(dev->msg->flags & I2C_M_RECV_LEN)) {
|
||||||
dev->msg->flags &= ~I2C_M_RECV_LEN;
|
/* ensure length byte is a valid value */
|
||||||
dev->buf_len += *dev->buf;
|
if (*dev->buf <= I2C_SMBUS_BLOCK_MAX && *dev->buf > 0) {
|
||||||
dev->msg->len = dev->buf_len + 1;
|
dev->msg->flags &= ~I2C_M_RECV_LEN;
|
||||||
dev_dbg(dev->dev, "received block length %d\n", dev->buf_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);
|
||||||
|
} 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 */
|
/* send stop if second but last byte has been read */
|
||||||
|
@ -421,8 +434,8 @@ 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);
|
dev->adapter.timeout);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
dev_err(dev->dev, "controller timed out\n");
|
dev_err(dev->dev, "controller timed out\n");
|
||||||
at91_init_twi_bus(dev);
|
at91_init_twi_bus(dev);
|
||||||
|
@ -444,6 +457,12 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto error;
|
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");
|
dev_dbg(dev->dev, "transfer complete\n");
|
||||||
|
|
||||||
return 0;
|
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_len = m_start->len;
|
||||||
dev->buf = m_start->buf;
|
dev->buf = m_start->buf;
|
||||||
dev->msg = m_start;
|
dev->msg = m_start;
|
||||||
|
dev->recv_len_abort = false;
|
||||||
|
|
||||||
ret = at91_do_twi_transfer(dev);
|
ret = at91_do_twi_transfer(dev);
|
||||||
|
|
||||||
|
|
|
@ -746,8 +746,7 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
|
||||||
}
|
}
|
||||||
tclk = clk_get_rate(drv_data->clk);
|
tclk = clk_get_rate(drv_data->clk);
|
||||||
|
|
||||||
rc = of_property_read_u32(np, "clock-frequency", &bus_freq);
|
if (of_property_read_u32(np, "clock-frequency", &bus_freq))
|
||||||
if (rc)
|
|
||||||
bus_freq = 100000; /* 100kHz by default */
|
bus_freq = 100000; /* 100kHz by default */
|
||||||
|
|
||||||
if (!mv64xxx_find_baud_factors(bus_freq, tclk,
|
if (!mv64xxx_find_baud_factors(bus_freq, tclk,
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
/* register offsets */
|
/* register offsets */
|
||||||
#define ICSCR 0x00 /* slave ctrl */
|
#define ICSCR 0x00 /* slave ctrl */
|
||||||
|
@ -95,6 +96,7 @@ struct rcar_i2c_priv {
|
||||||
struct i2c_msg *msg;
|
struct i2c_msg *msg;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
|
|
||||||
|
spinlock_t lock;
|
||||||
wait_queue_head_t wait;
|
wait_queue_head_t wait;
|
||||||
|
|
||||||
int pos;
|
int pos;
|
||||||
|
@ -365,20 +367,20 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
|
||||||
struct rcar_i2c_priv *priv = ptr;
|
struct rcar_i2c_priv *priv = ptr;
|
||||||
u32 msr;
|
u32 msr;
|
||||||
|
|
||||||
|
/*-------------- spin lock -----------------*/
|
||||||
|
spin_lock(&priv->lock);
|
||||||
|
|
||||||
msr = rcar_i2c_read(priv, ICMSR);
|
msr = rcar_i2c_read(priv, ICMSR);
|
||||||
|
|
||||||
|
/* Only handle interrupts that are currently enabled */
|
||||||
|
msr &= rcar_i2c_read(priv, ICMIER);
|
||||||
|
|
||||||
/* Arbitration lost */
|
/* Arbitration lost */
|
||||||
if (msr & MAL) {
|
if (msr & MAL) {
|
||||||
rcar_i2c_flags_set(priv, (ID_DONE | ID_ARBLOST));
|
rcar_i2c_flags_set(priv, (ID_DONE | ID_ARBLOST));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stop */
|
|
||||||
if (msr & MST) {
|
|
||||||
rcar_i2c_flags_set(priv, ID_DONE);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Nack */
|
/* Nack */
|
||||||
if (msr & MNR) {
|
if (msr & MNR) {
|
||||||
/* go to stop phase */
|
/* go to stop phase */
|
||||||
|
@ -388,6 +390,12 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Stop */
|
||||||
|
if (msr & MST) {
|
||||||
|
rcar_i2c_flags_set(priv, ID_DONE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (rcar_i2c_is_recv(priv))
|
if (rcar_i2c_is_recv(priv))
|
||||||
rcar_i2c_flags_set(priv, rcar_i2c_irq_recv(priv, msr));
|
rcar_i2c_flags_set(priv, rcar_i2c_irq_recv(priv, msr));
|
||||||
else
|
else
|
||||||
|
@ -400,6 +408,9 @@ out:
|
||||||
wake_up(&priv->wait);
|
wake_up(&priv->wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_unlock(&priv->lock);
|
||||||
|
/*-------------- spin unlock -----------------*/
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
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 rcar_i2c_priv *priv = i2c_get_adapdata(adap);
|
||||||
struct device *dev = rcar_i2c_priv_to_dev(priv);
|
struct device *dev = rcar_i2c_priv_to_dev(priv);
|
||||||
|
unsigned long flags;
|
||||||
int i, ret, timeout;
|
int i, ret, timeout;
|
||||||
|
|
||||||
pm_runtime_get_sync(dev);
|
pm_runtime_get_sync(dev);
|
||||||
|
|
||||||
|
/*-------------- spin lock -----------------*/
|
||||||
|
spin_lock_irqsave(&priv->lock, flags);
|
||||||
|
|
||||||
rcar_i2c_init(priv);
|
rcar_i2c_init(priv);
|
||||||
/* start clock */
|
/* start clock */
|
||||||
rcar_i2c_write(priv, ICCCR, priv->icccr);
|
rcar_i2c_write(priv, ICCCR, priv->icccr);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&priv->lock, flags);
|
||||||
|
/*-------------- spin unlock -----------------*/
|
||||||
|
|
||||||
ret = rcar_i2c_bus_barrier(priv);
|
ret = rcar_i2c_bus_barrier(priv);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -428,6 +446,9 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*-------------- spin lock -----------------*/
|
||||||
|
spin_lock_irqsave(&priv->lock, flags);
|
||||||
|
|
||||||
/* init each data */
|
/* init each data */
|
||||||
priv->msg = &msgs[i];
|
priv->msg = &msgs[i];
|
||||||
priv->pos = 0;
|
priv->pos = 0;
|
||||||
|
@ -437,6 +458,9 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
|
||||||
|
|
||||||
ret = rcar_i2c_prepare_msg(priv);
|
ret = rcar_i2c_prepare_msg(priv);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&priv->lock, flags);
|
||||||
|
/*-------------- spin unlock -----------------*/
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -540,6 +564,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
irq = platform_get_irq(pdev, 0);
|
irq = platform_get_irq(pdev, 0);
|
||||||
init_waitqueue_head(&priv->wait);
|
init_waitqueue_head(&priv->wait);
|
||||||
|
spin_lock_init(&priv->lock);
|
||||||
|
|
||||||
adap = &priv->adap;
|
adap = &priv->adap;
|
||||||
adap->nr = pdev->id;
|
adap->nr = pdev->id;
|
||||||
|
|
|
@ -323,6 +323,10 @@ static void rk3x_i2c_handle_read(struct rk3x_i2c *i2c, unsigned int ipd)
|
||||||
/* ack interrupt */
|
/* ack interrupt */
|
||||||
i2c_writel(i2c, REG_INT_MBRF, REG_IPD);
|
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 */
|
/* read the data from receive buffer */
|
||||||
for (i = 0; i < len; ++i) {
|
for (i = 0; i < len; ++i) {
|
||||||
if (i % 4 == 0)
|
if (i % 4 == 0)
|
||||||
|
|
Loading…
Reference in New Issue