1313#include <zephyr/irq.h>
1414#include <zephyr/drivers/i2c.h>
1515
16+ #ifdef CONFIG_I2C_OMAP_BUS_RECOVERY
17+ #include "i2c_bitbang.h"
18+ #endif /* CONFIG_I2C_OMAP_BUS_RECOVERY */
19+
1620LOG_MODULE_REGISTER (omap_i2c , CONFIG_I2C_LOG_LEVEL );
1721
1822#define I2C_OMAP_TIMEOUT 100U
@@ -216,30 +220,6 @@ static int i2c_omap_set_speed(const struct device *dev, uint32_t speed)
216220 return 0 ;
217221}
218222
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-
243223/**
244224 * @brief Configure the OMAP I2C controller with the specified device configuration.
245225 *
@@ -322,12 +302,113 @@ static void i2c_omap_resize_fifo(const struct device *dev, uint8_t size)
322302 }
323303}
324304
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+
325405/**
326406 * @brief Wait for the bus to become free (no longer busy).
327407 *
328408 * This function waits for the bus to become free by continuously checking the
329409 * 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().
331412 *
332413 * @param dev The I2C device structure.
333414 * @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)
341422 while (i2c_base_addr -> STAT & I2C_OMAP_STAT_BB ) {
342423 if (k_uptime_get_32 () > timeout ) {
343424 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 */
344430 }
345431 k_busy_wait (100 );
346432 }
@@ -576,8 +662,35 @@ static int i2c_omap_transfer_polling(const struct device *dev, struct i2c_msg ms
576662static DEVICE_API (i2c , i2c_omap_api ) = {
577663 .transfer = i2c_omap_transfer_polling ,
578664 .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 */
579668};
580669
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+
581694#define I2C_OMAP_INIT (inst ) \
582695 LOG_INSTANCE_REGISTER(omap_i2c, inst, CONFIG_I2C_LOG_LEVEL); \
583696 static const struct i2c_omap_cfg i2c_omap_cfg_##inst = { \
0 commit comments