1414#include <zephyr/drivers/pinctrl.h>
1515#include <zephyr/drivers/reset.h>
1616
17+ #ifdef CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY
18+ #include "i2c_bitbang.h"
19+ #include <zephyr/drivers/gpio.h>
20+ #endif /* CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY */
21+
1722#include <zephyr/logging/log.h>
1823#include <zephyr/irq.h>
1924LOG_MODULE_REGISTER (mcux_flexcomm );
@@ -34,6 +39,10 @@ struct mcux_flexcomm_config {
3439 uint32_t bitrate ;
3540 const struct pinctrl_dev_config * pincfg ;
3641 const struct reset_dt_spec reset ;
42+ #ifdef CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY
43+ struct gpio_dt_spec scl ;
44+ struct gpio_dt_spec sda ;
45+ #endif /* CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY */
3746};
3847
3948#ifdef CONFIG_I2C_TARGET
@@ -204,6 +213,89 @@ static int mcux_flexcomm_transfer(const struct device *dev,
204213 return ret ;
205214}
206215
216+ #if CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY
217+ static void mcux_flexcomm_bitbang_set_scl (void * io_context , int state )
218+ {
219+ const struct mcux_flexcomm_config * config = io_context ;
220+
221+ gpio_pin_set_dt (& config -> scl , state );
222+ }
223+
224+ static void mcux_flexcomm_bitbang_set_sda (void * io_context , int state )
225+ {
226+ const struct mcux_flexcomm_config * config = io_context ;
227+
228+ gpio_pin_set_dt (& config -> sda , state );
229+ }
230+
231+ static int mcux_flexcomm_bitbang_get_sda (void * io_context )
232+ {
233+ const struct mcux_flexcomm_config * config = io_context ;
234+
235+ return gpio_pin_get_dt (& config -> sda ) == 0 ? 0 : 1 ;
236+ }
237+
238+ static int mcux_flexcomm_recover_bus (const struct device * dev )
239+ {
240+ const struct mcux_flexcomm_config * config = dev -> config ;
241+ struct mcux_flexcomm_data * data = dev -> data ;
242+ struct i2c_bitbang bitbang_ctx ;
243+ struct i2c_bitbang_io bitbang_io = {
244+ .set_scl = mcux_flexcomm_bitbang_set_scl ,
245+ .set_sda = mcux_flexcomm_bitbang_set_sda ,
246+ .get_sda = mcux_flexcomm_bitbang_get_sda ,
247+ };
248+ uint32_t bitrate_cfg ;
249+ int error = 0 ;
250+
251+ if (!gpio_is_ready_dt (& config -> scl )) {
252+ LOG_ERR ("SCL GPIO device not ready" );
253+ return - EIO ;
254+ }
255+
256+ if (!gpio_is_ready_dt (& config -> sda )) {
257+ LOG_ERR ("SDA GPIO device not ready" );
258+ return - EIO ;
259+ }
260+
261+ k_sem_take (& data -> lock , K_FOREVER );
262+
263+ error = gpio_pin_configure_dt (& config -> scl , GPIO_OUTPUT_HIGH );
264+ if (error != 0 ) {
265+ LOG_ERR ("failed to configure SCL GPIO (err %d)" , error );
266+ goto restore ;
267+ }
268+
269+ error = gpio_pin_configure_dt (& config -> sda , GPIO_OUTPUT_HIGH );
270+ if (error != 0 ) {
271+ LOG_ERR ("failed to configure SDA GPIO (err %d)" , error );
272+ goto restore ;
273+ }
274+
275+ i2c_bitbang_init (& bitbang_ctx , & bitbang_io , (void * )config );
276+
277+ bitrate_cfg = i2c_map_dt_bitrate (config -> bitrate ) | I2C_MODE_CONTROLLER ;
278+ error = i2c_bitbang_configure (& bitbang_ctx , bitrate_cfg );
279+ if (error != 0 ) {
280+ LOG_ERR ("failed to configure I2C bitbang (err %d)" , error );
281+ goto restore ;
282+ }
283+
284+ error = i2c_bitbang_recover_bus (& bitbang_ctx );
285+ if (error != 0 ) {
286+ LOG_ERR ("failed to recover bus (err %d)" , error );
287+ goto restore ;
288+ }
289+
290+ restore :
291+ (void )pinctrl_apply_state (config -> pincfg , PINCTRL_STATE_DEFAULT );
292+
293+ k_sem_give (& data -> lock );
294+
295+ return error ;
296+ }
297+ #endif /* CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY */
298+
207299#if defined(CONFIG_I2C_TARGET )
208300
209301static struct mcux_flexcomm_target_data * mcux_flexcomm_find_free_target (
@@ -522,6 +614,9 @@ static int mcux_flexcomm_init(const struct device *dev)
522614static DEVICE_API (i2c , mcux_flexcomm_driver_api ) = {
523615 .configure = mcux_flexcomm_configure ,
524616 .transfer = mcux_flexcomm_transfer ,
617+ #if CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY
618+ .recover_bus = mcux_flexcomm_recover_bus ,
619+ #endif /* CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY */
525620#if defined(CONFIG_I2C_TARGET )
526621 .target_register = mcux_flexcomm_target_register ,
527622 .target_unregister = mcux_flexcomm_target_unregister ,
@@ -531,6 +626,14 @@ static DEVICE_API(i2c, mcux_flexcomm_driver_api) = {
531626#endif
532627};
533628
629+ #if CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY
630+ #define I2C_MCUX_FLEXCOMM_SCL_INIT (n ) .scl = GPIO_DT_SPEC_INST_GET_OR(n, scl_gpios, {0}),
631+ #define I2C_MCUX_FLEXCOMM_SDA_INIT (n ) .sda = GPIO_DT_SPEC_INST_GET_OR(n, sda_gpios, {0}),
632+ #else
633+ #define I2C_MCUX_FLEXCOMM_SCL_INIT (n )
634+ #define I2C_MCUX_FLEXCOMM_SDA_INIT (n )
635+ #endif /* CONFIG_I2C_MCUX_FLEXCOMM_BUS_RECOVERY */
636+
534637#define I2C_MCUX_FLEXCOMM_DEVICE (id ) \
535638 PINCTRL_DT_INST_DEFINE(id); \
536639 static void mcux_flexcomm_config_func_##id(const struct device *dev); \
@@ -542,6 +645,8 @@ static DEVICE_API(i2c, mcux_flexcomm_driver_api) = {
542645 .irq_config_func = mcux_flexcomm_config_func_##id, \
543646 .bitrate = DT_INST_PROP(id, clock_frequency), \
544647 .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \
648+ I2C_MCUX_FLEXCOMM_SCL_INIT(id) \
649+ I2C_MCUX_FLEXCOMM_SDA_INIT(id) \
545650 .reset = RESET_DT_SPEC_INST_GET(id), \
546651 }; \
547652 static struct mcux_flexcomm_data mcux_flexcomm_data_##id; \
0 commit comments