drivers: usb: device: nrf: Adapt to control clock using onoff

Change to use onoff service when controlling HFXO.

Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
Krzysztof Chruscinski 2020-02-13 14:03:29 +01:00 committed by Carles Cufí
commit 9e546fdf7e

View file

@ -242,6 +242,9 @@ K_MEM_POOL_DEFINE(ep_buf_pool, EP_BUF_POOL_BLOCK_MIN_SZ,
* @brief USBD control structure * @brief USBD control structure
* *
* @param status_cb Status callback for USB DC notifications * @param status_cb Status callback for USB DC notifications
* @param hfxo_cli Onoff client used to control HFXO
* @param hfxo_mgr Pointer to onoff manager associated with HFXO.
* @param clk_requested Flag used to protect against double stop.
* @param attached USBD Attached flag * @param attached USBD Attached flag
* @param ready USBD Ready flag set after pullup * @param ready USBD Ready flag set after pullup
* @param usb_work USBD work item * @param usb_work USBD work item
@ -251,6 +254,9 @@ K_MEM_POOL_DEFINE(ep_buf_pool, EP_BUF_POOL_BLOCK_MIN_SZ,
*/ */
struct nrf_usbd_ctx { struct nrf_usbd_ctx {
usb_dc_status_callback status_cb; usb_dc_status_callback status_cb;
struct onoff_client hfxo_cli;
struct onoff_manager *hfxo_mgr;
atomic_t clk_requested;
bool attached; bool attached;
bool ready; bool ready;
@ -523,62 +529,26 @@ void usb_dc_nrfx_power_event_callback(nrf_power_event_t event)
} }
} }
/** /* Stopping HFXO, algorithm supports case when stop comes before clock is
* @brief Enable/Disable the HF clock * started. In that case, it is stopped from the callback context.
*
* Toggle the HF clock. It needs to be enabled for USBD data exchange
*
* @param on Set true to enable the HF clock, false to disable.
* @param blocking Set true to block wait till HF clock stabilizes.
*
* @return 0 on success, error number otherwise
*/ */
static int hf_clock_enable(bool on, bool blocking) static int hfxo_stop(struct nrf_usbd_ctx *ctx)
{ {
int ret = -ENODEV; if (atomic_cas(&ctx->clk_requested, 1, 0)) {
struct device *clock; return onoff_cancel_or_release(ctx->hfxo_mgr, &ctx->hfxo_cli);
static bool clock_requested;
clock = device_get_binding(DT_LABEL(DT_INST(0, nordic_nrf_clock)));
if (!clock) {
LOG_ERR("NRF HF Clock device not found!");
return ret;
} }
if (on) { return 0;
if (clock_requested) { }
/* Do not request HFCLK multiple times. */
return 0; static int hfxo_start(struct nrf_usbd_ctx *ctx)
} {
ret = clock_control_on(clock, CLOCK_CONTROL_NRF_SUBSYS_HF); if (atomic_cas(&ctx->clk_requested, 0, 1)) {
while (blocking && sys_notify_init_spinwait(&ctx->hfxo_cli.notify);
clock_control_get_status(clock,
CLOCK_CONTROL_NRF_SUBSYS_HF) != return onoff_request(ctx->hfxo_mgr, &ctx->hfxo_cli);
CLOCK_CONTROL_STATUS_ON) {
}
} else {
if (!clock_requested) {
/* Cancel the operation if clock has not
* been requested by this driver before.
*/
return 0;
}
ret = clock_control_off(clock, CLOCK_CONTROL_NRF_SUBSYS_HF);
} }
if (ret && (blocking || (ret != -EINPROGRESS))) {
LOG_ERR("HF clock %s fail: %d",
on ? "start" : "stop", ret);
return ret;
}
clock_requested = on;
LOG_DBG("HF clock %s success (%d)", on ? "start" : "stop", ret);
/* NOTE: Non-blocking HF clock enable can return -EINPROGRESS
* if HF clock start was already requested. Such error code
* does not need to be propagated, hence returned value is 0.
*/
return 0; return 0;
} }
@ -766,13 +736,15 @@ static void eps_ctx_uninit(void)
static inline void usbd_work_process_pwr_events(struct usbd_pwr_event *pwr_evt) static inline void usbd_work_process_pwr_events(struct usbd_pwr_event *pwr_evt)
{ {
struct nrf_usbd_ctx *ctx = get_usbd_ctx(); struct nrf_usbd_ctx *ctx = get_usbd_ctx();
int err;
switch (pwr_evt->state) { switch (pwr_evt->state) {
case USBD_ATTACHED: case USBD_ATTACHED:
if (!nrfx_usbd_is_enabled()) { if (!nrfx_usbd_is_enabled()) {
LOG_DBG("USB detected"); LOG_DBG("USB detected");
nrfx_usbd_enable(); nrfx_usbd_enable();
(void) hf_clock_enable(true, false); err = hfxo_start(ctx);
__ASSERT_NO_MSG(err >= 0);
} }
/* No callback here. /* No callback here.
@ -795,7 +767,8 @@ static inline void usbd_work_process_pwr_events(struct usbd_pwr_event *pwr_evt)
case USBD_DETACHED: case USBD_DETACHED:
ctx->ready = false; ctx->ready = false;
nrfx_usbd_disable(); nrfx_usbd_disable();
(void) hf_clock_enable(false, false); err = hfxo_stop(ctx);
__ASSERT_NO_MSG(err >= 0);
LOG_DBG("USB Removed"); LOG_DBG("USB Removed");
@ -1363,6 +1336,8 @@ int usb_dc_attach(void)
k_work_init(&ctx->usb_work, usbd_work_handler); k_work_init(&ctx->usb_work, usbd_work_handler);
k_mutex_init(&ctx->drv_lock); k_mutex_init(&ctx->drv_lock);
ctx->hfxo_mgr =
z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF);
IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority),
nrfx_isr, nrfx_usbd_irq_handler, 0); nrfx_isr, nrfx_usbd_irq_handler, 0);
@ -1415,7 +1390,7 @@ int usb_dc_detach(void)
nrfx_usbd_uninit(); nrfx_usbd_uninit();
} }
(void) hf_clock_enable(false, false); (void)hfxo_stop(ctx);
nrf5_power_usb_power_int_enable(false); nrf5_power_usb_power_int_enable(false);
ctx->attached = false; ctx->attached = false;