Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i2c: omap: implement bus recovery

implement bus recovery methods for i2c-omap
so we can recover from situations where SCL/SDA
are stuck low.

Signed-off-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>

authored by

Felipe Balbi and committed by
Wolfram Sang
9dcb0e7b e9a02a3d

+65 -4
+65 -4
drivers/i2c/busses/i2c-omap.c
··· 482 482 483 483 timeout = jiffies + OMAP_I2C_TIMEOUT; 484 484 while (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) { 485 - if (time_after(jiffies, timeout)) { 486 - dev_warn(dev->dev, "timeout waiting for bus ready\n"); 487 - return -ETIMEDOUT; 488 - } 485 + if (time_after(jiffies, timeout)) 486 + return i2c_recover_bus(&dev->adapter); 489 487 msleep(1); 490 488 } 491 489 ··· 1208 1210 #define OMAP_I2C_SCHEME_0 0 1209 1211 #define OMAP_I2C_SCHEME_1 1 1210 1212 1213 + static int omap_i2c_get_scl(struct i2c_adapter *adap) 1214 + { 1215 + struct omap_i2c_dev *dev = i2c_get_adapdata(adap); 1216 + u32 reg; 1217 + 1218 + reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); 1219 + 1220 + return reg & OMAP_I2C_SYSTEST_SCL_I_FUNC; 1221 + } 1222 + 1223 + static int omap_i2c_get_sda(struct i2c_adapter *adap) 1224 + { 1225 + struct omap_i2c_dev *dev = i2c_get_adapdata(adap); 1226 + u32 reg; 1227 + 1228 + reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); 1229 + 1230 + return reg & OMAP_I2C_SYSTEST_SDA_I_FUNC; 1231 + } 1232 + 1233 + static void omap_i2c_set_scl(struct i2c_adapter *adap, int val) 1234 + { 1235 + struct omap_i2c_dev *dev = i2c_get_adapdata(adap); 1236 + u32 reg; 1237 + 1238 + reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); 1239 + if (val) 1240 + reg |= OMAP_I2C_SYSTEST_SCL_O; 1241 + else 1242 + reg &= ~OMAP_I2C_SYSTEST_SCL_O; 1243 + omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg); 1244 + } 1245 + 1246 + static void omap_i2c_prepare_recovery(struct i2c_adapter *adap) 1247 + { 1248 + struct omap_i2c_dev *dev = i2c_get_adapdata(adap); 1249 + u32 reg; 1250 + 1251 + reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); 1252 + reg |= OMAP_I2C_SYSTEST_ST_EN; 1253 + omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg); 1254 + } 1255 + 1256 + static void omap_i2c_unprepare_recovery(struct i2c_adapter *adap) 1257 + { 1258 + struct omap_i2c_dev *dev = i2c_get_adapdata(adap); 1259 + u32 reg; 1260 + 1261 + reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); 1262 + reg &= ~OMAP_I2C_SYSTEST_ST_EN; 1263 + omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg); 1264 + } 1265 + 1266 + static struct i2c_bus_recovery_info omap_i2c_bus_recovery_info = { 1267 + .get_scl = omap_i2c_get_scl, 1268 + .get_sda = omap_i2c_get_sda, 1269 + .set_scl = omap_i2c_set_scl, 1270 + .prepare_recovery = omap_i2c_prepare_recovery, 1271 + .unprepare_recovery = omap_i2c_unprepare_recovery, 1272 + .recover_bus = i2c_generic_scl_recovery, 1273 + }; 1274 + 1211 1275 static int 1212 1276 omap_i2c_probe(struct platform_device *pdev) 1213 1277 { ··· 1419 1359 adap->algo = &omap_i2c_algo; 1420 1360 adap->dev.parent = &pdev->dev; 1421 1361 adap->dev.of_node = pdev->dev.of_node; 1362 + adap->bus_recovery_info = &omap_i2c_bus_recovery_info; 1422 1363 1423 1364 /* i2c device drivers may be active on return from add_adapter() */ 1424 1365 adap->nr = pdev->id;