mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-17 09:57:46 +07:00
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
|
||||
* 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;
|
||||
clkl -= d;
|
||||
} else {
|
||||
clkh = 0;
|
||||
clkh = 1;
|
||||
clkl = clk - (d << 1);
|
||||
}
|
||||
|
||||
|
@ -368,6 +368,7 @@ static int i2c_imx_dma_xfer(struct imx_i2c_struct *i2c_imx,
|
||||
goto err_desc;
|
||||
}
|
||||
|
||||
reinit_completion(&dma->cmd_complete);
|
||||
txdesc->callback = i2c_imx_dma_callback;
|
||||
txdesc->callback_param = i2c_imx;
|
||||
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.
|
||||
*/
|
||||
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(
|
||||
&i2c_imx->dma->cmd_complete,
|
||||
msecs_to_jiffies(DMA_TIMEOUT));
|
||||
@ -681,7 +681,6 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
reinit_completion(&i2c_imx->dma->cmd_complete);
|
||||
time_left = wait_for_completion_timeout(
|
||||
&i2c_imx->dma->cmd_complete,
|
||||
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,
|
||||
"gpio");
|
||||
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 ||
|
||||
PTR_ERR(rinfo->scl_gpiod) == -EPROBE_DEFER) {
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* register offsets */
|
||||
@ -111,8 +112,9 @@
|
||||
#define ID_ARBLOST (1 << 3)
|
||||
#define ID_NACK (1 << 4)
|
||||
/* persistent flags */
|
||||
#define ID_P_NO_RXDMA (1 << 30) /* HW forbids RXDMA sometimes */
|
||||
#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 {
|
||||
I2C_RCAR_GEN1,
|
||||
@ -141,6 +143,8 @@ struct rcar_i2c_priv {
|
||||
struct dma_chan *dma_rx;
|
||||
struct scatterlist sg;
|
||||
enum dma_data_direction dma_direction;
|
||||
|
||||
struct reset_control *rstc;
|
||||
};
|
||||
|
||||
#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),
|
||||
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;
|
||||
}
|
||||
|
||||
@ -407,8 +416,9 @@ static void rcar_i2c_dma(struct rcar_i2c_priv *priv)
|
||||
unsigned char *buf;
|
||||
int len;
|
||||
|
||||
/* Do not use DMA if it's not available or for messages < 8 bytes */
|
||||
if (IS_ERR(chan) || msg->len < 8 || !(msg->flags & I2C_M_DMA_SAFE))
|
||||
/* Do various checks to see if DMA is feasible at all */
|
||||
if (IS_ERR(chan) || msg->len < 8 || !(msg->flags & I2C_M_DMA_SAFE) ||
|
||||
(read && priv->flags & ID_P_NO_RXDMA))
|
||||
return;
|
||||
|
||||
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,
|
||||
struct i2c_msg *msgs,
|
||||
int num)
|
||||
@ -750,6 +779,16 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
|
||||
|
||||
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);
|
||||
|
||||
ret = rcar_i2c_bus_barrier(priv);
|
||||
@ -920,6 +959,15 @@ static int rcar_i2c_probe(struct platform_device *pdev)
|
||||
if (ret < 0)
|
||||
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 */
|
||||
if (of_property_read_bool(dev->of_node, "multi-master"))
|
||||
priv->flags |= ID_P_PM_BLOCKED;
|
||||
|
Loading…
Reference in New Issue
Block a user