Merge branch 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c fixes from Wolfram Sang: "Some driver bugfixes" * 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: i2c: imx: use open drain for recovery GPIO i2c: rcar: handle RXDMA HW behaviour on Gen3 i2c: imx: Fix reinit_completion() use i2c: davinci: Avoid zero value of CLKH
This commit is contained in:
commit
dd63bf22fc
|
@ -237,12 +237,16 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
|
||||||
/*
|
/*
|
||||||
* It's not always possible to have 1 to 2 ratio when d=7, so fall back
|
* It's not always possible to have 1 to 2 ratio when d=7, so fall back
|
||||||
* to minimal possible clkh in this case.
|
* to minimal possible clkh in this case.
|
||||||
|
*
|
||||||
|
* Note:
|
||||||
|
* CLKH is not allowed to be 0, in this case I2C clock is not generated
|
||||||
|
* at all
|
||||||
*/
|
*/
|
||||||
if (clk >= clkl + d) {
|
if (clk > clkl + d) {
|
||||||
clkh = clk - clkl - d;
|
clkh = clk - clkl - d;
|
||||||
clkl -= d;
|
clkl -= d;
|
||||||
} else {
|
} else {
|
||||||
clkh = 0;
|
clkh = 1;
|
||||||
clkl = clk - (d << 1);
|
clkl = clk - (d << 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -368,6 +368,7 @@ static int i2c_imx_dma_xfer(struct imx_i2c_struct *i2c_imx,
|
||||||
goto err_desc;
|
goto err_desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reinit_completion(&dma->cmd_complete);
|
||||||
txdesc->callback = i2c_imx_dma_callback;
|
txdesc->callback = i2c_imx_dma_callback;
|
||||||
txdesc->callback_param = i2c_imx;
|
txdesc->callback_param = i2c_imx;
|
||||||
if (dma_submit_error(dmaengine_submit(txdesc))) {
|
if (dma_submit_error(dmaengine_submit(txdesc))) {
|
||||||
|
@ -622,7 +623,6 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
|
||||||
* The first byte must be transmitted by the CPU.
|
* The first byte must be transmitted by the CPU.
|
||||||
*/
|
*/
|
||||||
imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR);
|
imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR);
|
||||||
reinit_completion(&i2c_imx->dma->cmd_complete);
|
|
||||||
time_left = wait_for_completion_timeout(
|
time_left = wait_for_completion_timeout(
|
||||||
&i2c_imx->dma->cmd_complete,
|
&i2c_imx->dma->cmd_complete,
|
||||||
msecs_to_jiffies(DMA_TIMEOUT));
|
msecs_to_jiffies(DMA_TIMEOUT));
|
||||||
|
@ -681,7 +681,6 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
|
||||||
if (result)
|
if (result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
reinit_completion(&i2c_imx->dma->cmd_complete);
|
|
||||||
time_left = wait_for_completion_timeout(
|
time_left = wait_for_completion_timeout(
|
||||||
&i2c_imx->dma->cmd_complete,
|
&i2c_imx->dma->cmd_complete,
|
||||||
msecs_to_jiffies(DMA_TIMEOUT));
|
msecs_to_jiffies(DMA_TIMEOUT));
|
||||||
|
@ -1010,7 +1009,7 @@ static int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx,
|
||||||
i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl,
|
i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl,
|
||||||
"gpio");
|
"gpio");
|
||||||
rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN);
|
rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN);
|
||||||
rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl", GPIOD_OUT_HIGH);
|
rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl", GPIOD_OUT_HIGH_OPEN_DRAIN);
|
||||||
|
|
||||||
if (PTR_ERR(rinfo->sda_gpiod) == -EPROBE_DEFER ||
|
if (PTR_ERR(rinfo->sda_gpiod) == -EPROBE_DEFER ||
|
||||||
PTR_ERR(rinfo->scl_gpiod) == -EPROBE_DEFER) {
|
PTR_ERR(rinfo->scl_gpiod) == -EPROBE_DEFER) {
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
|
#include <linux/reset.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
/* register offsets */
|
/* register offsets */
|
||||||
|
@ -111,8 +112,9 @@
|
||||||
#define ID_ARBLOST (1 << 3)
|
#define ID_ARBLOST (1 << 3)
|
||||||
#define ID_NACK (1 << 4)
|
#define ID_NACK (1 << 4)
|
||||||
/* persistent flags */
|
/* persistent flags */
|
||||||
|
#define ID_P_NO_RXDMA (1 << 30) /* HW forbids RXDMA sometimes */
|
||||||
#define ID_P_PM_BLOCKED (1 << 31)
|
#define ID_P_PM_BLOCKED (1 << 31)
|
||||||
#define ID_P_MASK ID_P_PM_BLOCKED
|
#define ID_P_MASK (ID_P_PM_BLOCKED | ID_P_NO_RXDMA)
|
||||||
|
|
||||||
enum rcar_i2c_type {
|
enum rcar_i2c_type {
|
||||||
I2C_RCAR_GEN1,
|
I2C_RCAR_GEN1,
|
||||||
|
@ -141,6 +143,8 @@ struct rcar_i2c_priv {
|
||||||
struct dma_chan *dma_rx;
|
struct dma_chan *dma_rx;
|
||||||
struct scatterlist sg;
|
struct scatterlist sg;
|
||||||
enum dma_data_direction dma_direction;
|
enum dma_data_direction dma_direction;
|
||||||
|
|
||||||
|
struct reset_control *rstc;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent)
|
#define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent)
|
||||||
|
@ -370,6 +374,11 @@ static void rcar_i2c_dma_unmap(struct rcar_i2c_priv *priv)
|
||||||
dma_unmap_single(chan->device->dev, sg_dma_address(&priv->sg),
|
dma_unmap_single(chan->device->dev, sg_dma_address(&priv->sg),
|
||||||
sg_dma_len(&priv->sg), priv->dma_direction);
|
sg_dma_len(&priv->sg), priv->dma_direction);
|
||||||
|
|
||||||
|
/* Gen3 can only do one RXDMA per transfer and we just completed it */
|
||||||
|
if (priv->devtype == I2C_RCAR_GEN3 &&
|
||||||
|
priv->dma_direction == DMA_FROM_DEVICE)
|
||||||
|
priv->flags |= ID_P_NO_RXDMA;
|
||||||
|
|
||||||
priv->dma_direction = DMA_NONE;
|
priv->dma_direction = DMA_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,8 +416,9 @@ static void rcar_i2c_dma(struct rcar_i2c_priv *priv)
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
/* Do not use DMA if it's not available or for messages < 8 bytes */
|
/* Do various checks to see if DMA is feasible at all */
|
||||||
if (IS_ERR(chan) || msg->len < 8 || !(msg->flags & I2C_M_DMA_SAFE))
|
if (IS_ERR(chan) || msg->len < 8 || !(msg->flags & I2C_M_DMA_SAFE) ||
|
||||||
|
(read && priv->flags & ID_P_NO_RXDMA))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (read) {
|
if (read) {
|
||||||
|
@ -739,6 +749,25 @@ static void rcar_i2c_release_dma(struct rcar_i2c_priv *priv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* I2C is a special case, we need to poll the status of a reset */
|
||||||
|
static int rcar_i2c_do_reset(struct rcar_i2c_priv *priv)
|
||||||
|
{
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
ret = reset_control_reset(priv->rstc);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
for (i = 0; i < LOOP_TIMEOUT; i++) {
|
||||||
|
ret = reset_control_status(priv->rstc);
|
||||||
|
if (ret == 0)
|
||||||
|
return 0;
|
||||||
|
udelay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
|
static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
|
||||||
struct i2c_msg *msgs,
|
struct i2c_msg *msgs,
|
||||||
int num)
|
int num)
|
||||||
|
@ -750,6 +779,16 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
|
||||||
|
|
||||||
pm_runtime_get_sync(dev);
|
pm_runtime_get_sync(dev);
|
||||||
|
|
||||||
|
/* Gen3 needs a reset before allowing RXDMA once */
|
||||||
|
if (priv->devtype == I2C_RCAR_GEN3) {
|
||||||
|
priv->flags |= ID_P_NO_RXDMA;
|
||||||
|
if (!IS_ERR(priv->rstc)) {
|
||||||
|
ret = rcar_i2c_do_reset(priv);
|
||||||
|
if (ret == 0)
|
||||||
|
priv->flags &= ~ID_P_NO_RXDMA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rcar_i2c_init(priv);
|
rcar_i2c_init(priv);
|
||||||
|
|
||||||
ret = rcar_i2c_bus_barrier(priv);
|
ret = rcar_i2c_bus_barrier(priv);
|
||||||
|
@ -920,6 +959,15 @@ static int rcar_i2c_probe(struct platform_device *pdev)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_pm_put;
|
goto out_pm_put;
|
||||||
|
|
||||||
|
if (priv->devtype == I2C_RCAR_GEN3) {
|
||||||
|
priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
|
||||||
|
if (!IS_ERR(priv->rstc)) {
|
||||||
|
ret = reset_control_status(priv->rstc);
|
||||||
|
if (ret < 0)
|
||||||
|
priv->rstc = ERR_PTR(-ENOTSUPP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Stay always active when multi-master to keep arbitration working */
|
/* Stay always active when multi-master to keep arbitration working */
|
||||||
if (of_property_read_bool(dev->of_node, "multi-master"))
|
if (of_property_read_bool(dev->of_node, "multi-master"))
|
||||||
priv->flags |= ID_P_PM_BLOCKED;
|
priv->flags |= ID_P_PM_BLOCKED;
|
||||||
|
|
Loading…
Reference in New Issue