drivers: udc_dwc2: rework vendor quirks

Rework and rename vendor quirks to better reflect where they intended to
be called. Number of quirks probably not final and will be trimmed
later.

Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
This commit is contained in:
Johann Fischer 2024-05-14 14:10:30 +02:00 committed by Fabio Baltieri
commit efb286dfdf
3 changed files with 83 additions and 32 deletions

View file

@ -6,7 +6,6 @@
#include "udc_common.h" #include "udc_common.h"
#include "udc_dwc2.h" #include "udc_dwc2.h"
#include "udc_dwc2_vendor_quirks.h"
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
@ -22,6 +21,7 @@
#include <zephyr/logging/log.h> #include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(udc_dwc2, CONFIG_UDC_DRIVER_LOG_LEVEL); LOG_MODULE_REGISTER(udc_dwc2, CONFIG_UDC_DRIVER_LOG_LEVEL);
#include "udc_dwc2_vendor_quirks.h"
enum dwc2_drv_event_type { enum dwc2_drv_event_type {
/* Trigger next transfer, must not be used for control OUT */ /* Trigger next transfer, must not be used for control OUT */
@ -904,9 +904,7 @@ static void udc_dwc2_isr_handler(const struct device *dev)
} }
} }
if (config->quirks != NULL && config->quirks->irq_clear != NULL) { (void)dwc2_quirk_irq_clear(dev);
config->quirks->irq_clear(dev);
}
} }
static int udc_dwc2_ep_enqueue(const struct device *dev, static int udc_dwc2_ep_enqueue(const struct device *dev,
@ -1523,18 +1521,21 @@ static int udc_dwc2_enable(const struct device *dev)
struct usb_dwc2_reg *const base = dwc2_get_base(dev); struct usb_dwc2_reg *const base = dwc2_get_base(dev);
int err; int err;
err = dwc2_quirk_pre_enable(dev);
if (err) {
LOG_ERR("Quirk pre enable failed %d", err);
return err;
}
err = udc_dwc2_init_controller(dev); err = udc_dwc2_init_controller(dev);
if (err) { if (err) {
return err; return err;
} }
/* Call vendor-specific function to enable peripheral */ err = dwc2_quirk_post_enable(dev);
if (config->quirks != NULL && config->quirks->pwr_on != NULL) { if (err) {
LOG_DBG("Enable vendor power"); LOG_ERR("Quirk post enable failed %d", err);
err = config->quirks->pwr_on(dev); return err;
if (err) {
return err;
}
} }
/* Enable global interrupt */ /* Enable global interrupt */
@ -1553,6 +1554,7 @@ static int udc_dwc2_disable(const struct device *dev)
const struct udc_dwc2_config *const config = dev->config; const struct udc_dwc2_config *const config = dev->config;
struct usb_dwc2_reg *const base = dwc2_get_base(dev); struct usb_dwc2_reg *const base = dwc2_get_base(dev);
mem_addr_t dctl_reg = (mem_addr_t)&base->dctl; mem_addr_t dctl_reg = (mem_addr_t)&base->dctl;
int err;
/* Enable soft disconnect */ /* Enable soft disconnect */
sys_set_bits(dctl_reg, USB_DWC2_DCTL_SFTDISCON); sys_set_bits(dctl_reg, USB_DWC2_DCTL_SFTDISCON);
@ -1571,20 +1573,23 @@ static int udc_dwc2_disable(const struct device *dev)
return -EIO; return -EIO;
} }
err = dwc2_quirk_disable(dev);
if (err) {
LOG_ERR("Quirk disable failed %d", err);
return err;
}
return 0; return 0;
} }
static int udc_dwc2_init(const struct device *dev) static int udc_dwc2_init(const struct device *dev)
{ {
const struct udc_dwc2_config *const config = dev->config;
int ret; int ret;
if (config->quirks != NULL && config->quirks->clk_enable != NULL) { ret = dwc2_quirk_init(dev);
LOG_DBG("Enable vendor clock"); if (ret) {
ret = config->quirks->clk_enable(dev); LOG_ERR("Quirk init failed %d", ret);
if (ret) { return ret;
return ret;
}
} }
return dwc2_init_pinctrl(dev); return dwc2_init_pinctrl(dev);
@ -1592,6 +1597,14 @@ static int udc_dwc2_init(const struct device *dev)
static int udc_dwc2_shutdown(const struct device *dev) static int udc_dwc2_shutdown(const struct device *dev)
{ {
int ret;
ret = dwc2_quirk_shutdown(dev);
if (ret) {
LOG_ERR("Quirk shutdown failed %d", ret);
return ret;
}
return 0; return 0;
} }

View file

@ -14,10 +14,17 @@
/* Vendor quirks per driver instance */ /* Vendor quirks per driver instance */
struct dwc2_vendor_quirks { struct dwc2_vendor_quirks {
int (*clk_enable)(const struct device *dev); /* Called at the beginning of udc_dwc2_init() */
int (*clk_disable)(const struct device *dev); int (*init)(const struct device *dev);
int (*pwr_on)(const struct device *dev); /* Called on udc_dwc2_enable() before the controller is initialized */
int (*pwr_off)(const struct device *dev); int (*pre_enable)(const struct device *dev);
/* Called on udc_dwc2_enable() after the controller is initialized */
int (*post_enable)(const struct device *dev);
/* Called at the end of udc_dwc2_disable() */
int (*disable)(const struct device *dev);
/* Called at the end of udc_dwc2_shutdown() */
int (*shutdown)(const struct device *dev);
/* Called at the end of IRQ handling */
int (*irq_clear)(const struct device *dev); int (*irq_clear)(const struct device *dev);
}; };
@ -37,4 +44,24 @@ struct udc_dwc2_config {
void (*irq_disable_func)(const struct device *dev); void (*irq_disable_func)(const struct device *dev);
}; };
#define DWC2_QUIRK_FUNC_DEFINE(fname) \
static inline int dwc2_quirk_##fname(const struct device *dev) \
{ \
const struct udc_dwc2_config *const config = dev->config; \
struct dwc2_vendor_quirks *quirks = config->quirks; \
\
if (quirks != NULL && config->quirks->fname != NULL) { \
return quirks->fname(dev); \
} \
\
return 0; \
}
DWC2_QUIRK_FUNC_DEFINE(init)
DWC2_QUIRK_FUNC_DEFINE(pre_enable)
DWC2_QUIRK_FUNC_DEFINE(post_enable)
DWC2_QUIRK_FUNC_DEFINE(disable)
DWC2_QUIRK_FUNC_DEFINE(shutdown)
DWC2_QUIRK_FUNC_DEFINE(irq_clear)
#endif /* ZEPHYR_DRIVERS_USB_UDC_DWC2_H */ #endif /* ZEPHYR_DRIVERS_USB_UDC_DWC2_H */

View file

@ -11,13 +11,13 @@
#include <stdint.h> #include <stdint.h>
#include <zephyr/device.h> #include <zephyr/device.h>
#include <zephyr/sys/sys_io.h>
#include <zephyr/drivers/clock_control/stm32_clock_control.h>
#include <usb_dwc2_hw.h>
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_fsotg) #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_fsotg)
#include <zephyr/sys/sys_io.h>
#include <zephyr/drivers/clock_control/stm32_clock_control.h>
#include <usb_dwc2_hw.h>
struct usb_dw_stm32_clk { struct usb_dw_stm32_clk {
const struct device *const dev; const struct device *const dev;
const struct stm32_pclken *const pclken; const struct stm32_pclken *const pclken;
@ -26,7 +26,7 @@ struct usb_dw_stm32_clk {
#define DT_DRV_COMPAT snps_dwc2 #define DT_DRV_COMPAT snps_dwc2
static inline int clk_enable_stm32f4_fsotg(const struct usb_dw_stm32_clk *const clk) static inline int stm32f4_fsotg_enable_clk(const struct usb_dw_stm32_clk *const clk)
{ {
int ret; int ret;
@ -59,7 +59,7 @@ static inline int clk_enable_stm32f4_fsotg(const struct usb_dw_stm32_clk *const
return clock_control_on(clk->dev, (void *)&clk->pclken[0]); return clock_control_on(clk->dev, (void *)&clk->pclken[0]);
} }
static inline int pwr_on_stm32f4_fsotg(const struct device *dev) static inline int stm32f4_fsotg_enable_phy(const struct device *dev)
{ {
const struct udc_dwc2_config *const config = dev->config; const struct udc_dwc2_config *const config = dev->config;
mem_addr_t ggpio_reg = (mem_addr_t)&config->base->ggpio; mem_addr_t ggpio_reg = (mem_addr_t)&config->base->ggpio;
@ -69,6 +69,16 @@ static inline int pwr_on_stm32f4_fsotg(const struct device *dev)
return 0; return 0;
} }
static inline int stm32f4_fsotg_disable_phy(const struct device *dev)
{
const struct udc_dwc2_config *const config = dev->config;
mem_addr_t ggpio_reg = (mem_addr_t)&config->base->ggpio;
sys_clear_bits(ggpio_reg, USB_DWC2_GGPIO_STM32_PWRDWN | USB_DWC2_GGPIO_STM32_VBDEN);
return 0;
}
#define QUIRK_STM32F4_FSOTG_DEFINE(n) \ #define QUIRK_STM32F4_FSOTG_DEFINE(n) \
static const struct stm32_pclken pclken_##n[] = STM32_DT_INST_CLOCKS(n);\ static const struct stm32_pclken pclken_##n[] = STM32_DT_INST_CLOCKS(n);\
\ \
@ -78,14 +88,15 @@ static inline int pwr_on_stm32f4_fsotg(const struct device *dev)
.pclken_len = DT_INST_NUM_CLOCKS(n), \ .pclken_len = DT_INST_NUM_CLOCKS(n), \
}; \ }; \
\ \
static int clk_enable_stm32f4_fsotg_##n(const struct device *dev) \ static int stm32f4_fsotg_enable_clk_##n(const struct device *dev) \
{ \ { \
return clk_enable_stm32f4_fsotg(&stm32f4_clk_##n); \ return stm32f4_fsotg_enable_clk(&stm32f4_clk_##n); \
} \ } \
\ \
struct dwc2_vendor_quirks dwc2_vendor_quirks_##n = { \ struct dwc2_vendor_quirks dwc2_vendor_quirks_##n = { \
.clk_enable = clk_enable_stm32f4_fsotg_##n, \ .pre_enable = stm32f4_fsotg_enable_clk_##n, \
.pwr_on = pwr_on_stm32f4_fsotg, \ .post_enable = stm32f4_fsotg_enable_phy, \
.disable = stm32f4_fsotg_disable_phy, \
.irq_clear = NULL, \ .irq_clear = NULL, \
}; };