diff --git a/drivers/usbmisc/fusb303.c b/drivers/usbmisc/fusb303.c index 0eb37772d6..b66432fe34 100644 --- a/drivers/usbmisc/fusb303.c +++ b/drivers/usbmisc/fusb303.c @@ -92,7 +92,7 @@ int ret = fusb303_getreg((priv), (x)); \ if (ret < 0) \ { \ - fusb303_err("ERROR: Failed to read %s(0x%02X)\n", #x, (x)); \ + fusb303_err("ERROR: Failed to read %s(0x%02X)\n", #x, (x)); \ } \ else \ { \ @@ -121,7 +121,8 @@ struct fusb303_dev_s ****************************************************************************/ #ifdef CONFIG_DEBUG_FUSB303 -static int fusb303_dumpregs(FAR struct fusb303_dev_s *priv); +static int fusb303_dumpregs(FAR const char *funcname, + FAR struct fusb303_dev_s *priv); #endif static int fusb303_open(FAR struct file *filep); static int fusb303_close(FAR struct file *filep); @@ -313,8 +314,10 @@ static int fusb303_putreg(FAR struct fusb303_dev_s *priv, uint8_t regaddr, ****************************************************************************/ #ifdef CONFIG_DEBUG_FUSB303 -static int noinline_function fusb303_dumpregs(FAR struct fusb303_dev_s *priv) +static int noinline_function fusb303_dumpregs(FAR const char *funcname, + FAR struct fusb303_dev_s *priv) { + fusb303_info("'%s':\n", funcname); DUMPREG(priv, FUSB303_DEV_ID_REG); DUMPREG(priv, FUSB303_DEV_TYPE_REG); DUMPREG(priv, FUSB303_PORTROLE_REG); @@ -495,11 +498,56 @@ static int fusb303_setup(FAR struct fusb303_dev_s *priv, err_out: #ifdef CONFIG_DEBUG_FUSB303 - fusb303_dumpregs(priv); + fusb303_dumpregs("fusb303_setup", priv); #endif return ret; } +/**************************************************************************** + * Name: fusb303_toggle_control1_enable + * + * Description: + * Switch enable flag off and then on. + * + ****************************************************************************/ + +static int fusb303_toggle_control1_enable(FAR struct fusb303_dev_s *priv) +{ + int regval; + int ret; + + regval = fusb303_getreg(priv, FUSB303_CONTROL1_REG); + if (regval < 0) + { + fusb303_err("ERROR: Failed to read CONTROL1 register\n"); + return -1; + } + + if (!(regval & CONTROL1_ENABLE)) + { + /* Not enabled, skip toggling. */ + + return 0; + } + + ret = fusb303_putreg(priv, FUSB303_CONTROL1_REG, + regval & ~CONTROL1_ENABLE); + if (ret < 0) + { + fusb303_err("ERROR: Failed to write CONTROL1 register\n"); + return -1; + } + + ret = fusb303_putreg(priv, FUSB303_CONTROL1_REG, regval); + if (ret < 0) + { + fusb303_err("ERROR: Failed to write CONTROL1 register\n"); + return -1; + } + + return 0; +} + /**************************************************************************** * Name: fusb303_set_mode * @@ -728,18 +776,30 @@ static ssize_t fusb303_read(FAR struct file *filep, FAR char *buffer, return ret; } - flags = enter_critical_section(); - priv->int_pending = false; - leave_critical_section(flags); - ptr->status = fusb303_getreg(priv, FUSB303_STATUS_REG); ptr->status1 = fusb303_getreg(priv, FUSB303_STATUS1_REG); ptr->dev_type = fusb303_getreg(priv, FUSB303_TYPE_REG); #ifdef CONFIG_DEBUG_FUSB303 - fusb303_dumpregs(priv); + fusb303_dumpregs("fusb303_read", priv); #endif + if (!(ptr->status & STATUS_ATTACH) || + (ptr->status & STATUS_BC_LVL_3000) == STATUS_BC_LVL_UNATT) + { + /* Toggle enable bit when USB is not attached. This is needed to + * enable attach interrupt when orientation of USB-C cable changes. + */ + + (void)fusb303_toggle_control1_enable(priv); + + up_mdelay(1); /* Wait for initial interrupt. */ + } + + flags = enter_critical_section(); + priv->int_pending = false; + leave_critical_section(flags); + (void)fusb303_clear_interrupts(priv); nxsem_post(&priv->devsem); diff --git a/include/nuttx/usb/fusb303.h b/include/nuttx/usb/fusb303.h index 62f9cd76c2..d6d8fe889a 100644 --- a/include/nuttx/usb/fusb303.h +++ b/include/nuttx/usb/fusb303.h @@ -183,7 +183,7 @@ enum fusb303_reset_e enum fusb303_int_mask_e { - INT_MASK_ATTACK = (1 << 0), + INT_MASK_ATTACH = (1 << 0), INT_MASK_DETACH = (1 << 1), INT_MASK_BC_LVL = (1 << 2), INT_MASK_AUTOSNK = (1 << 3),