Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions boards/nordic/nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@
regulator-initial-mode = <NRF5X_REG_MODE_DCDC>;
};

&vregusb {
status = "okay";
};

&grtc {
owned-channels = <0 1 2 3 4 5 6 7 8 9 10 11>;
/* Channels 7-11 reserved for Zero Latency IRQs, 3-4 for FLPR */
Expand Down
1 change: 1 addition & 0 deletions drivers/regulator/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ zephyr_library_sources_ifdef(CONFIG_REGULATOR_NPM1100 regulator_npm1100.c)
zephyr_library_sources_ifdef(CONFIG_REGULATOR_NPM13XX regulator_npm13xx.c)
zephyr_library_sources_ifdef(CONFIG_REGULATOR_NPM2100 regulator_npm2100.c)
zephyr_library_sources_ifdef(CONFIG_REGULATOR_NPM6001 regulator_npm6001.c)
zephyr_library_sources_ifdef(CONFIG_REGULATOR_NRF_VREGUSB regulator_nrf_vregusb.c)
zephyr_library_sources_ifdef(CONFIG_REGULATOR_PCA9420 regulator_pca9420.c)
zephyr_library_sources_ifdef(CONFIG_REGULATOR_PCA9422 regulator_pca9422.c)
zephyr_library_sources_ifdef(CONFIG_REGULATOR_PF1550 regulator_pf1550.c)
Expand Down
1 change: 1 addition & 0 deletions drivers/regulator/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ source "drivers/regulator/Kconfig.npm1100"
source "drivers/regulator/Kconfig.npm13xx"
source "drivers/regulator/Kconfig.npm2100"
source "drivers/regulator/Kconfig.npm6001"
source "drivers/regulator/Kconfig.nrf_vregusb"
source "drivers/regulator/Kconfig.pca9420"
source "drivers/regulator/Kconfig.pca9422"
source "drivers/regulator/Kconfig.pf1550"
Expand Down
16 changes: 16 additions & 0 deletions drivers/regulator/Kconfig.nrf_vregusb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

config REGULATOR_NRF_VREGUSB
bool "Nordic USB VBUS regulator driver"
default y
depends on DT_HAS_NORDIC_VREGUSB_REGULATOR_ENABLED
help
Enable Nordic USB VBUS regulator driver.

config REGULATOR_NRF_VREGUSB_INIT_PRIORITY
int "Nordic VBUS regulator driver init priority"
default KERNEL_INIT_PRIORITY_DEVICE
depends on REGULATOR_NRF_VREGUSB
help
Init priority for the Nordic USB VBUS regulator driver.
133 changes: 133 additions & 0 deletions drivers/regulator/regulator_nrf_vregusb.c
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be implemented on top of aligned/extended nrfx_power_usb* API.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation of this reg in nrfx may help reach USB support in NCS bare metal option.
cc @lemrey

Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*
* Copyright Nordic Semiconductor ASA
* SPDX-License-Identifier: Apache-2.0
*/

#include <nrf.h>
#include <errno.h>
#include <stdint.h>
#include <zephyr/drivers/regulator.h>
#include <zephyr/logging/log.h>

LOG_MODULE_REGISTER(vregusb, CONFIG_REGULATOR_LOG_LEVEL);

struct vregusb_config {
struct regulator_common_config common;
NRF_VREGUSB_Type *base;
void (*irq_enable_func)(const struct device *dev);
void (*irq_disable_func)(const struct device *dev);
};

struct vregusb_data {
struct regulator_common_data data;
regulator_callback_t cb;
const void *user_data;
};

static void vregusb_isr(void *const arg)
{
const struct device *const dev = arg;
const struct vregusb_config *const config = dev->config;
struct vregusb_data *const data = dev->data;
NRF_VREGUSB_Type *const base = config->base;
struct regulator_event event;

if (base->EVENTS_VBUSDETECTED) {
LOG_DBG("VBUS detected");
base->EVENTS_VBUSDETECTED = 0;
event.type = REGULATOR_VOLTAGE_DETECTED;
}

if (base->EVENTS_VBUSREMOVED) {
LOG_DBG("VBUS removed");
base->EVENTS_VBUSREMOVED = 0;
event.type = REGULATOR_VOLTAGE_REMOVED;
}

if (data->cb != NULL) {
data->cb(dev, &event, data->user_data);
}
}

static int vregusb_enable(const struct device *const dev)
{
const struct vregusb_config *const config = dev->config;
NRF_VREGUSB_Type *const base = config->base;

base->INTEN = VREGUSB_INTEN_VBUSDETECTED_Msk | VREGUSB_INTEN_VBUSREMOVED_Msk;
config->irq_enable_func(dev);

base->TASKS_START = 1;

return 0;
}

static int vregusb_disable(const struct device *const dev)
{
const struct vregusb_config *const config = dev->config;
NRF_VREGUSB_Type *const base = config->base;

config->irq_disable_func(dev);
base->TASKS_STOP = 1;

return 0;
}

static int vregusb_set_callback(const struct device *const dev,
regulator_callback_t cb, const void *const user_data)
{
struct vregusb_data *const data = dev->data;

data->cb = cb;
data->user_data = user_data;

return 0;
}

static int regulator_vregusb_init(const struct device *const dev)
{
regulator_common_data_init(dev);

return 0;
}

static DEVICE_API(regulator, api) = {
.enable = vregusb_enable,
.disable = vregusb_disable,
.set_callback = vregusb_set_callback,
};

#define DT_DRV_COMPAT nordic_vregusb_regulator

#define REGULATOR_VREGUSB_DEFINE(n) \
static void irq_enable_func_##n(const struct device *const dev) \
{ \
IRQ_CONNECT(DT_INST_IRQN(n), \
DT_INST_IRQ(n, priority), \
vregusb_isr, \
DEVICE_DT_INST_GET(n), \
0); \
\
irq_enable(DT_INST_IRQN(n)); \
} \
\
static void irq_disable_func_##n(const struct device *const dev) \
{ \
irq_disable(DT_INST_IRQN(n)); \
} \
\
static struct vregusb_data data_##n; \
\
static const struct vregusb_config config_##n = { \
.base = (void *)(DT_INST_REG_ADDR(n)), \
.common = REGULATOR_DT_INST_COMMON_CONFIG_INIT(n), \
.irq_enable_func = irq_enable_func_##n, \
.irq_disable_func = irq_disable_func_##n, \
}; \
\
DEVICE_DT_INST_DEFINE(n, regulator_vregusb_init, NULL, \
&data_##n, &config_##n, \
POST_KERNEL, \
CONFIG_REGULATOR_NRF_VREGUSB_INIT_PRIORITY, &api);\

DT_INST_FOREACH_STATUS_OKAY(REGULATOR_VREGUSB_DEFINE)
1 change: 1 addition & 0 deletions drivers/usb/udc/Kconfig.dwc2
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ config UDC_DWC2
select NRFS if NRFS_HAS_VBUS_DETECTOR_SERVICE
select NRFS_VBUS_DETECTOR_SERVICE_ENABLED if NRFS_HAS_VBUS_DETECTOR_SERVICE
select EVENTS
select REGULATOR if SOC_SERIES_NRF54LX || SOC_SERIES_NRF92X
help
DWC2 USB device controller driver.

Expand Down
50 changes: 26 additions & 24 deletions drivers/usb/udc/udc_dwc2_vendor_quirks.h
Original file line number Diff line number Diff line change
Expand Up @@ -326,14 +326,13 @@ DT_INST_FOREACH_STATUS_OKAY(QUIRK_NRF_USBHS_DEFINE)

#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_usbhs_nrf54l)

#define USBHS_DT_WRAPPER_REG_ADDR(n) UINT_TO_POINTER(DT_INST_REG_ADDR_BY_NAME(n, wrapper))
#define USBHS_DT_WRAPPER_REG_ADDR(n) UINT_TO_POINTER(DT_REG_ADDR(DT_INST_PARENT(n)))

#include <nrf.h>
#include <zephyr/logging/log.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/clock_control/nrf_clock_control.h>

#define NRF_DEFAULT_IRQ_PRIORITY 1
#include <zephyr/drivers/regulator.h>

/*
* On USBHS, we cannot access the DWC2 register until VBUS is detected and
Expand All @@ -345,42 +344,46 @@ DT_INST_FOREACH_STATUS_OKAY(QUIRK_NRF_USBHS_DEFINE)
static K_EVENT_DEFINE(usbhs_events);
#define USBHS_VBUS_READY BIT(0)

const static struct device *const vregusb_dev =
DEVICE_DT_GET(DT_PHANDLE(DT_INST_PARENT(0), regulator));
static struct onoff_manager *pclk24m_mgr;
static struct onoff_client pclk24m_cli;

static void vregusb_isr(const void *arg)
static void vregusb_event_cb(const struct device *dev,
const struct regulator_event *const evt,
const void *const user_data)
{
const struct device *dev = arg;
ARG_UNUSED(dev);
const struct device *const udc_dev = user_data;

if (NRF_VREGUSB->EVENTS_VBUSDETECTED) {
NRF_VREGUSB->EVENTS_VBUSDETECTED = 0;
if (evt->type == REGULATOR_VOLTAGE_DETECTED) {
k_event_post(&usbhs_events, USBHS_VBUS_READY);
udc_submit_event(dev, UDC_EVT_VBUS_READY, 0);
udc_submit_event(udc_dev, UDC_EVT_VBUS_READY, 0);
}

if (NRF_VREGUSB->EVENTS_VBUSREMOVED) {
NRF_VREGUSB->EVENTS_VBUSREMOVED = 0;
if (evt->type == REGULATOR_VOLTAGE_REMOVED) {
k_event_set_masked(&usbhs_events, 0, USBHS_VBUS_READY);
udc_submit_event(dev, UDC_EVT_VBUS_REMOVED, 0);
udc_submit_event(udc_dev, UDC_EVT_VBUS_REMOVED, 0);
}
}

static inline int usbhs_init_vreg_and_clock(const struct device *dev)
{
IRQ_CONNECT(VREGUSB_IRQn, NRF_DEFAULT_IRQ_PRIORITY,
vregusb_isr, DEVICE_DT_INST_GET(0), 0);
LOG_MODULE_DECLARE(udc_dwc2, CONFIG_UDC_DRIVER_LOG_LEVEL);
int err;

NRF_VREGUSB->INTEN = VREGUSB_INTEN_VBUSDETECTED_Msk |
VREGUSB_INTEN_VBUSREMOVED_Msk;
NRF_VREGUSB->TASKS_START = 1;
err = regulator_set_callback(vregusb_dev, vregusb_event_cb, dev);
if (err) {
LOG_ERR("Failed to set regulator callback");
return err;
}

/* TODO: Determine conditions when VBUSDETECTED is not generated */
if (sys_read32((mem_addr_t)NRF_VREGUSB + 0x400) & BIT(2)) {
k_event_post(&usbhs_events, USBHS_VBUS_READY);
udc_submit_event(dev, UDC_EVT_VBUS_READY, 0);
err = regulator_enable(vregusb_dev);
if (err) {
LOG_ERR("Failed to enable regulator");
return err;
}

irq_enable(VREGUSB_IRQn);
pclk24m_mgr = z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF24M);

return 0;
Expand Down Expand Up @@ -463,10 +466,9 @@ static inline int usbhs_disable_core(const struct device *dev)

static inline int usbhs_disable_vreg(const struct device *dev)
{
NRF_VREGUSB->INTEN = 0;
NRF_VREGUSB->TASKS_STOP = 1;
ARG_UNUSED(dev);

return 0;
return regulator_disable(vregusb_dev);
}

static inline int usbhs_init_caps(const struct device *dev)
Expand Down
20 changes: 20 additions & 0 deletions dts/bindings/regulator/nordic,vregusb-regulator.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

description: |
Nordic VBUS regulator for USB peripheral

compatible: "nordic,vregusb-regulator"

include:
- name: base.yaml
- name: regulator.yaml
property-allowlist:
- regulator-name

properties:
reg:
required: true

regulator-name:
required: true
18 changes: 18 additions & 0 deletions dts/bindings/usb/nordic,nrf-usbhs-wrapper.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
description: |
Nordic wrapper for USB controller and PHY hardware. The wrapper is used to
configure, control, and enable/disable the USB PHY, and to enable/disable USB
controller.
compatible: "nordic,nrf-usbhs-wrapper"

include: [base.yaml]

properties:
reg:
required: true

regulator:
required: true
type: phandle
description: |
USB PHY and controller function depends on the USB regulator VREGUSB.
Comment on lines +14 to +18
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the nordic,nrf-usbhs-wrapper also be used for nRF54H20? How would the nrfs be modelled then?

37 changes: 26 additions & 11 deletions dts/vendor/nordic/nrf54lm20a.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -210,17 +210,24 @@
prescaler = <0>;
};

usbhs: usbhs@5a000 {
compatible = "nordic,nrf-usbhs-nrf54l", "snps,dwc2";
reg = <0x5a000 0x1000>, <0x50020000 0x1a000>;
reg-names = "wrapper", "core";
interrupts = <90 NRF_DEFAULT_IRQ_PRIORITY>;
num-in-eps = <16>;
num-out-eps = <16>;
ghwcfg1 = <0x0>;
ghwcfg2 = <0x22affc52>;
ghwcfg4 = <0x3e10aa60>;
status = "disabled";
usbhs_wrapper: usbhs_wrapper@5a000 {
compatible = "nordic,nrf-usbhs-wrapper";
reg = <0x5a000 0x1000>;
regulator = <&vregusb>;
#address-cells = <1>;
#size-cells = <1>;
Comment on lines +213 to +218
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you expand on what the wrapper does?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In short USBHS wrapper provides a way to enable underlying DWC2 controller (core), enable power to both core and USB PHY, configure USB PHY and make it possible to get core and USB PHY out of reset.


usbhs: usbhs@50020000 {
compatible = "nordic,nrf-usbhs-nrf54l", "snps,dwc2";
reg = <0x50020000 0x1a000>;
interrupts = <90 NRF_DEFAULT_IRQ_PRIORITY>;
num-in-eps = <16>;
num-out-eps = <16>;
ghwcfg1 = <0x0>;
ghwcfg2 = <0x22affc52>;
ghwcfg4 = <0x3e10aa60>;
status = "disabled";
};
};

dppic10: dppic@82000 {
Expand Down Expand Up @@ -827,6 +834,14 @@
regulator-name = "VREGMAIN";
regulator-initial-mode = <NRF5X_REG_MODE_LDO>;
};

vregusb: regulator@50121000 {
compatible = "nordic,vregusb-regulator";
reg = <0x50121000 0x1>;
interrupts = <289 NRF_DEFAULT_IRQ_PRIORITY>;
status = "disabled";
regulator-name = "VREGUSB";
};
};
};

Expand Down
Loading
Loading