summaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorWolfram Sang <wsa+renesas@sang-engineering.com>2018-01-09 08:58:59 -0500
committerWolfram Sang <wsa@the-dreams.de>2018-01-15 18:04:48 -0500
commit7d2c17f021c656a9429df05e27a359041c1bada8 (patch)
tree3697b37ca9cb4702741d78aa7f10e556245966ba /drivers/i2c
parent2806e6ad77c71dd2538cb698aad476e8cf3af004 (diff)
i2c: rcar: implement bus recovery
We can force levels of SCL and SDA, so we can use that for bus recovery. Note that we cannot read SDA back, because we will only get the internal state of the bus free detection. Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-rcar.c54
1 files changed, 52 insertions, 2 deletions
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index 8a2ae3e6c561..d4b7b5380c29 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -132,6 +132,7 @@ struct rcar_i2c_priv {
132 int pos; 132 int pos;
133 u32 icccr; 133 u32 icccr;
134 u32 flags; 134 u32 flags;
135 u8 recovery_icmcr; /* protected by adapter lock */
135 enum rcar_i2c_type devtype; 136 enum rcar_i2c_type devtype;
136 struct i2c_client *slave; 137 struct i2c_client *slave;
137 138
@@ -158,6 +159,46 @@ static u32 rcar_i2c_read(struct rcar_i2c_priv *priv, int reg)
158 return readl(priv->io + reg); 159 return readl(priv->io + reg);
159} 160}
160 161
162static int rcar_i2c_get_scl(struct i2c_adapter *adap)
163{
164 struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
165
166 return !!(rcar_i2c_read(priv, ICMCR) & FSCL);
167
168};
169
170static void rcar_i2c_set_scl(struct i2c_adapter *adap, int val)
171{
172 struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
173
174 if (val)
175 priv->recovery_icmcr |= FSCL;
176 else
177 priv->recovery_icmcr &= ~FSCL;
178
179 rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr);
180};
181
182/* No get_sda, because the HW only reports its bus free logic, not SDA itself */
183
184static void rcar_i2c_set_sda(struct i2c_adapter *adap, int val)
185{
186 struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
187
188 if (val)
189 priv->recovery_icmcr |= FSDA;
190 else
191 priv->recovery_icmcr &= ~FSDA;
192
193 rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr);
194};
195
196static struct i2c_bus_recovery_info rcar_i2c_bri = {
197 .get_scl = rcar_i2c_get_scl,
198 .set_scl = rcar_i2c_set_scl,
199 .set_sda = rcar_i2c_set_sda,
200 .recover_bus = i2c_generic_scl_recovery,
201};
161static void rcar_i2c_init(struct rcar_i2c_priv *priv) 202static void rcar_i2c_init(struct rcar_i2c_priv *priv)
162{ 203{
163 /* reset master mode */ 204 /* reset master mode */
@@ -170,7 +211,7 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv)
170 211
171static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) 212static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
172{ 213{
173 int i; 214 int i, ret;
174 215
175 for (i = 0; i < LOOP_TIMEOUT; i++) { 216 for (i = 0; i < LOOP_TIMEOUT; i++) {
176 /* make sure that bus is not busy */ 217 /* make sure that bus is not busy */
@@ -179,7 +220,15 @@ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
179 udelay(1); 220 udelay(1);
180 } 221 }
181 222
182 return -EBUSY; 223 /* Waiting did not help, try to recover */
224 priv->recovery_icmcr = MDBS | OBPC | FSDA | FSCL;
225 ret = i2c_recover_bus(&priv->adap);
226
227 /* No failure when recovering, so check bus busy bit again */
228 if (ret == 0)
229 ret = (rcar_i2c_read(priv, ICMCR) & FSDA) ? -EBUSY : 0;
230
231 return ret;
183} 232}
184 233
185static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, struct i2c_timings *t) 234static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, struct i2c_timings *t)
@@ -851,6 +900,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)
851 adap->retries = 3; 900 adap->retries = 3;
852 adap->dev.parent = dev; 901 adap->dev.parent = dev;
853 adap->dev.of_node = dev->of_node; 902 adap->dev.of_node = dev->of_node;
903 adap->bus_recovery_info = &rcar_i2c_bri;
854 i2c_set_adapdata(adap, priv); 904 i2c_set_adapdata(adap, priv);
855 strlcpy(adap->name, pdev->name, sizeof(adap->name)); 905 strlcpy(adap->name, pdev->name, sizeof(adap->name));
856 906