diff options
author | Jens Axboe <axboe@kernel.dk> | 2018-02-05 12:55:38 -0700 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2018-02-05 12:55:38 -0700 |
commit | 9e05c864993c5442227f83ae1694a737d7a102ed (patch) | |
tree | e35b60bb3c0c179f147e9acaad5444f1e5d9117e /drivers/i2c/busses/i2c-rcar.c | |
parent | 3c15f3f545afa320c5e3822825a9a53c664776b6 (diff) | |
parent | 35277995e17919ab838beae765f440674e8576eb (diff) |
Merge branch 'master' into test
* master: (688 commits)
dt-bindings: mailbox: qcom: Document the APCS clock binding
mailbox: qcom: Create APCS child device for clock controller
mailbox: qcom: Convert APCS IPC driver to use regmap
KVM/SVM: Allow direct access to MSR_IA32_SPEC_CTRL
KVM/VMX: Allow direct access to MSR_IA32_SPEC_CTRL
KVM/VMX: Emulate MSR_IA32_ARCH_CAPABILITIES
KVM/x86: Add IBPB support
KVM/x86: Update the reverse_cpuid list to include CPUID_7_EDX
pinctrl: remove include file from <linux/device.h>
firmware: dmi: handle missing DMI data gracefully
firmware: dmi_scan: Fix handling of empty DMI strings
firmware: dmi_scan: Drop dmi_initialized
firmware: dmi: Optimize dmi_matches
Revert "defer call to mem_cgroup_sk_alloc()"
soreuseport: fix mem leak in reuseport_add_sock()
net: qlge: use memmove instead of skb_copy_to_linear_data
net: qed: use correct strncpy() size
net: cxgb4: avoid memcpy beyond end of source buffer
cls_u32: add missing RCU annotation.
r8152: set rx mode early when linking on
...
Diffstat (limited to 'drivers/i2c/busses/i2c-rcar.c')
-rw-r--r-- | drivers/i2c/busses/i2c-rcar.c | 62 |
1 files changed, 56 insertions, 6 deletions
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 15d764afec3b..4159ebcec2bb 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -62,7 +62,7 @@ #define MIE (1 << 3) /* master if enable */ #define TSBE (1 << 2) #define FSB (1 << 1) /* force stop bit */ -#define ESG (1 << 0) /* en startbit gen */ +#define ESG (1 << 0) /* enable start bit gen */ /* ICSSR (also for ICSIER) */ #define GCAR (1 << 6) /* general call received */ @@ -132,6 +132,7 @@ struct rcar_i2c_priv { int pos; u32 icccr; u32 flags; + u8 recovery_icmcr; /* protected by adapter lock */ enum rcar_i2c_type devtype; struct i2c_client *slave; @@ -158,6 +159,46 @@ static u32 rcar_i2c_read(struct rcar_i2c_priv *priv, int reg) return readl(priv->io + reg); } +static int rcar_i2c_get_scl(struct i2c_adapter *adap) +{ + struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); + + return !!(rcar_i2c_read(priv, ICMCR) & FSCL); + +}; + +static void rcar_i2c_set_scl(struct i2c_adapter *adap, int val) +{ + struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); + + if (val) + priv->recovery_icmcr |= FSCL; + else + priv->recovery_icmcr &= ~FSCL; + + rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr); +}; + +/* No get_sda, because the HW only reports its bus free logic, not SDA itself */ + +static void rcar_i2c_set_sda(struct i2c_adapter *adap, int val) +{ + struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); + + if (val) + priv->recovery_icmcr |= FSDA; + else + priv->recovery_icmcr &= ~FSDA; + + rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr); +}; + +static struct i2c_bus_recovery_info rcar_i2c_bri = { + .get_scl = rcar_i2c_get_scl, + .set_scl = rcar_i2c_set_scl, + .set_sda = rcar_i2c_set_sda, + .recover_bus = i2c_generic_scl_recovery, +}; static void rcar_i2c_init(struct rcar_i2c_priv *priv) { /* reset master mode */ @@ -170,7 +211,7 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv) static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) { - int i; + int i, ret; for (i = 0; i < LOOP_TIMEOUT; i++) { /* make sure that bus is not busy */ @@ -179,7 +220,15 @@ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) udelay(1); } - return -EBUSY; + /* Waiting did not help, try to recover */ + priv->recovery_icmcr = MDBS | OBPC | FSDA | FSCL; + ret = i2c_recover_bus(&priv->adap); + + /* No failure when recovering, so check bus busy bit again */ + if (ret == 0) + ret = (rcar_i2c_read(priv, ICMCR) & FSDA) ? -EBUSY : 0; + + return ret; } static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, struct i2c_timings *t) @@ -282,7 +331,7 @@ static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv) rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | read); /* - * We don't have a testcase but the HW engineers say that the write order + * We don't have a test case but the HW engineers say that the write order * of ICMSR and ICMCR depends on whether we issue START or REP_START. Since * it didn't cause a drawback for me, let's rather be safe than sorry. */ @@ -359,7 +408,7 @@ static void rcar_i2c_dma(struct rcar_i2c_priv *priv) int len; /* Do not use DMA if it's not available or for messages < 8 bytes */ - if (IS_ERR(chan) || msg->len < 8) + if (IS_ERR(chan) || msg->len < 8 || !(msg->flags & I2C_M_DMA_SAFE)) return; if (read) { @@ -440,7 +489,7 @@ static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) /* * Try to use DMA to transmit the rest of the data if - * address transfer pashe just finished. + * address transfer phase just finished. */ if (msr & MAT) rcar_i2c_dma(priv); @@ -851,6 +900,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) adap->retries = 3; adap->dev.parent = dev; adap->dev.of_node = dev->of_node; + adap->bus_recovery_info = &rcar_i2c_bri; i2c_set_adapdata(adap, priv); strlcpy(adap->name, pdev->name, sizeof(adap->name)); |