13
13
#include <zephyr/irq.h>
14
14
#include <zephyr/drivers/i2c.h>
15
15
16
+ #ifdef CONFIG_I2C_OMAP_BUS_RECOVERY
17
+ #include "i2c_bitbang.h"
18
+ #endif /* CONFIG_I2C_OMAP_BUS_RECOVERY */
19
+
16
20
LOG_MODULE_REGISTER (omap_i2c , CONFIG_I2C_LOG_LEVEL );
17
21
18
22
#define I2C_OMAP_TIMEOUT 100U
@@ -216,30 +220,6 @@ static int i2c_omap_set_speed(const struct device *dev, uint32_t speed)
216
220
return 0 ;
217
221
}
218
222
219
- /**
220
- * @brief Initialize the OMAP I2C controller.
221
- *
222
- * This function initializes the OMAP I2C controller by setting the speed and
223
- * performing any necessary initialization steps.
224
- *
225
- * @param dev Pointer to the device structure for the I2C controller.
226
- * @return 0 if successful, negative error code otherwise.
227
- */
228
- static int i2c_omap_init (const struct device * dev )
229
- {
230
- struct i2c_omap_data * data = DEV_DATA (dev );
231
- const struct i2c_omap_cfg * cfg = DEV_CFG (dev );
232
- k_sem_init (& data -> lock , 1 , 1 );
233
-
234
- /* Set the speed for I2C */
235
- if (i2c_omap_set_speed (dev , cfg -> speed )) {
236
- LOG_ERR ("Failed to set speed" );
237
- return - ENOTSUP ;
238
- }
239
- i2c_omap_init_ll (dev );
240
- return 0 ;
241
- }
242
-
243
223
/**
244
224
* @brief Configure the OMAP I2C controller with the specified device configuration.
245
225
*
@@ -322,12 +302,113 @@ static void i2c_omap_resize_fifo(const struct device *dev, uint8_t size)
322
302
}
323
303
}
324
304
305
+ #ifdef CONFIG_I2C_OMAP_BUS_RECOVERY
306
+ /**
307
+ * @brief Get the state of the SDA line.
308
+ *
309
+ * This function retrieves the state of the SDA (data) line for the OMAP I2C controller.
310
+ *
311
+ * @param io_context The I2C context.
312
+ * @return The state of the SDA line.
313
+ */
314
+ static int i2c_omap_get_sda (void * io_context )
315
+ {
316
+ const struct i2c_omap_cfg * cfg = (const struct i2c_omap_cfg * )io_context ;
317
+ i2c_omap_regs_t * i2c_base_addr = (i2c_omap_regs_t * )cfg -> base .addr ;
318
+
319
+ return (i2c_base_addr -> SYSTEST & I2C_OMAP_SYSTEST_SDA_I_FUNC ) ? 1 : 0 ;
320
+ }
321
+
322
+ /**
323
+ * @brief Set the state of the SDA line.
324
+ *
325
+ * This function sets the state of the SDA (data) line for the OMAP I2C controller.
326
+ *
327
+ * @param io_context The I2C context.
328
+ * @param state The state to set (0 for low, 1 for high).
329
+ */
330
+ static void i2c_omap_set_sda (void * io_context , int state )
331
+ {
332
+ const struct i2c_omap_cfg * cfg = (const struct i2c_omap_cfg * )io_context ;
333
+ i2c_omap_regs_t * i2c_base_addr = (i2c_omap_regs_t * )cfg -> base .addr ;
334
+
335
+ if (state ) {
336
+ i2c_base_addr -> SYSTEST |= I2C_OMAP_SYSTEST_SDA_O ;
337
+ } else {
338
+ i2c_base_addr -> SYSTEST &= ~I2C_OMAP_SYSTEST_SDA_O ;
339
+ }
340
+ }
341
+
342
+ /**
343
+ * @brief Set the state of the SCL line.
344
+ *
345
+ * This function sets the state of the SCL (clock) line for the OMAP I2C controller.
346
+ *
347
+ * @param io_context The I2C context.
348
+ * @param state The state to set (0 for low, 1 for high).
349
+ */
350
+ static void i2c_omap_set_scl (void * io_context , int state )
351
+ {
352
+ const struct i2c_omap_cfg * cfg = (const struct i2c_omap_cfg * )io_context ;
353
+ i2c_omap_regs_t * i2c_base_addr = (i2c_omap_regs_t * )cfg -> base .addr ;
354
+
355
+ if (state ) {
356
+ i2c_base_addr -> SYSTEST |= I2C_OMAP_SYSTEST_SCL_O ;
357
+ } else {
358
+ i2c_base_addr -> SYSTEST &= ~I2C_OMAP_SYSTEST_SCL_O ;
359
+ }
360
+ }
361
+ /**
362
+ * @brief Recovers the I2C bus using the OMAP I2C controller.
363
+ *
364
+ * This function attempts to recover the I2C bus by performing a bus recovery
365
+ * sequence using the OMAP I2C controller. It uses the provided device
366
+ * configuration and bit-banging operations to recover the bus.
367
+ *
368
+ * @param dev Pointer to the device structure.
369
+ * @return 0 on success, negative error code on failure.
370
+ */
371
+
372
+ static int i2c_omap_recover_bus (const struct device * dev )
373
+ {
374
+ const struct i2c_omap_cfg * cfg = DEV_CFG (dev );
375
+ i2c_omap_regs_t * i2c_base_addr = DEV_I2C_BASE (dev );
376
+ struct i2c_omap_data * data = DEV_DATA (dev );
377
+
378
+ struct i2c_bitbang bitbang_omap ;
379
+ struct i2c_bitbang_io bitbang_omap_io = {
380
+ .get_sda = i2c_omap_get_sda ,
381
+ .set_scl = i2c_omap_set_scl ,
382
+ .set_sda = i2c_omap_set_sda ,
383
+ };
384
+ int error = 0 ;
385
+
386
+ k_sem_take (& data -> lock , K_FOREVER );
387
+ i2c_base_addr -> SYSTEST |= I2C_OMAP_SYSTEST_ST_EN | (3 << I2C_OMAP_SYSTEST_TMODE_SHIFT ) |
388
+ I2C_OMAP_SYSTEST_SCL_O | I2C_OMAP_SYSTEST_SDA_O ;
389
+ i2c_bitbang_init (& bitbang_omap , & bitbang_omap_io , (void * )cfg );
390
+ error = i2c_bitbang_recover_bus (& bitbang_omap );
391
+ if (error != 0 ) {
392
+ LOG_ERR ("failed to recover bus (err %d)" , error );
393
+ goto restore ;
394
+ }
395
+
396
+ restore :
397
+ i2c_base_addr -> SYSTEST &= ~(I2C_OMAP_SYSTEST_ST_EN | I2C_OMAP_SYSTEST_TMODE_MASK |
398
+ I2C_OMAP_SYSTEST_SCL_O | I2C_OMAP_SYSTEST_SDA_O );
399
+ i2c_omap_reset (dev );
400
+ k_sem_give (& data -> lock );
401
+ return error ;
402
+ }
403
+ #endif /* CONFIG_I2C_OMAP_BUS_RECOVERY */
404
+
325
405
/**
326
406
* @brief Wait for the bus to become free (no longer busy).
327
407
*
328
408
* This function waits for the bus to become free by continuously checking the
329
409
* status register of the OMAP I2C controller. If the bus remains busy for a
330
- * certain timeout period, the function will return timeout error.
410
+ * certain timeout period, the function will return attempts to recover the bus by calling
411
+ * i2c_omap_recover_bus().
331
412
*
332
413
* @param dev The I2C device structure.
333
414
* @return 0 if the bus becomes free, or a negative error code if the bus cannot
@@ -341,6 +422,11 @@ static int i2c_omap_wait_for_bb(const struct device *dev)
341
422
while (i2c_base_addr -> STAT & I2C_OMAP_STAT_BB ) {
342
423
if (k_uptime_get_32 () > timeout ) {
343
424
LOG_ERR ("Bus busy timeout" );
425
+ #ifdef CONFIG_I2C_OMAP_BUS_RECOVERY
426
+ return i2c_omap_recover_bus (dev );
427
+ #else
428
+ return - ETIMEDOUT ;
429
+ #endif /* CONFIG_I2C_OMAP_BUS_RECOVERY */
344
430
}
345
431
k_busy_wait (100 );
346
432
}
@@ -576,8 +662,35 @@ static int i2c_omap_transfer_polling(const struct device *dev, struct i2c_msg ms
576
662
static DEVICE_API (i2c , i2c_omap_api ) = {
577
663
.transfer = i2c_omap_transfer_polling ,
578
664
.configure = i2c_omap_configure ,
665
+ #ifdef CONFIG_I2C_OMAP_BUS_RECOVERY
666
+ .recover_bus = i2c_omap_recover_bus ,
667
+ #endif /* CONFIG_I2C_OMAP_BUS_RECOVERY */
579
668
};
580
669
670
+ /**
671
+ * @brief Initialize the OMAP I2C controller.
672
+ *
673
+ * This function initializes the OMAP I2C controller by setting the speed and
674
+ * performing any necessary initialization steps.
675
+ *
676
+ * @param dev Pointer to the device structure for the I2C controller.
677
+ * @return 0 if successful, negative error code otherwise.
678
+ */
679
+ static int i2c_omap_init (const struct device * dev )
680
+ {
681
+ struct i2c_omap_data * data = DEV_DATA (dev );
682
+ const struct i2c_omap_cfg * cfg = DEV_CFG (dev );
683
+
684
+ k_sem_init (& data -> lock , 1 , 1 );
685
+ /* Set the speed for I2C */
686
+ if (i2c_omap_set_speed (dev , cfg -> speed )) {
687
+ LOG_ERR ("Failed to set speed" );
688
+ return - ENOTSUP ;
689
+ }
690
+ i2c_omap_init_ll (dev );
691
+ return 0 ;
692
+ }
693
+
581
694
#define I2C_OMAP_INIT (inst ) \
582
695
LOG_INSTANCE_REGISTER(omap_i2c, inst, CONFIG_I2C_LOG_LEVEL); \
583
696
static const struct i2c_omap_cfg i2c_omap_cfg_##inst = { \
0 commit comments