Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

siwx917: Add clock driver #77

Merged
merged 6 commits into from
Jan 15, 2025
Merged
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
10 changes: 5 additions & 5 deletions boards/silabs/radio_boards/siwx917_rb4338a/siwx917_rb4338a.dts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
chosen {
zephyr,sram = &sram0;
zephyr,code-partition = &code_partition;
zephyr,console = &ulpuart0;
zephyr,shell-uart = &ulpuart0;
zephyr,console = &ulpuart;
zephyr,shell-uart = &ulpuart;
zephyr,bt-hci = &bt_hci_silabs_siwx917;
};

Expand Down Expand Up @@ -63,9 +63,9 @@
status = "okay";
};

&ulpuart0 {
&ulpuart {
status = "okay";
pinctrl-0 = <&ulpuart0_default>;
pinctrl-0 = <&ulpuart_default>;
pinctrl-names = "default";
};

Expand All @@ -83,7 +83,7 @@
};

&pinctrl0 {
ulpuart0_default: ulpuart0_default {
ulpuart_default: ulpuart_default {
out {
pinmux = <ULPUART_TX_ULP11>;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
CONFIG_SERIAL=y
CONFIG_PINCTRL=y
CONFIG_CLOCK_CONTROL=y
CONFIG_SIWX917_FLASH_MODE_COMMON=y
CONFIG_USE_DT_CODE_PARTITION=y
1 change: 1 addition & 0 deletions drivers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# SPDX-License-Identifier: Apache-2.0

add_subdirectory(bluetooth)
add_subdirectory(clock_control)
add_subdirectory(entropy)
add_subdirectory(flash)
add_subdirectory(gpio)
Expand Down
5 changes: 5 additions & 0 deletions drivers/clock_control/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright (c) 2024 Silicon Laboratories Inc.
# SPDX-License-Identifier: Apache-2.0

zephyr_library_amend()
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SILABS_SIWX917 clock_control_silabs_siwx917.c)
8 changes: 8 additions & 0 deletions drivers/clock_control/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) 2024 Silicon Laboratories Inc.
# SPDX-License-Identifier: Apache-2.0

if CLOCK_CONTROL

rsource "Kconfig.siwx917"

endif
15 changes: 15 additions & 0 deletions drivers/clock_control/Kconfig.siwx917
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright (c) 2024 Silicon Laboratories Inc.
# SPDX-License-Identifier: Apache-2.0

config CLOCK_CONTROL_SILABS_SIWX917
bool "SiWx917 clock control driver"
default y
depends on DT_HAS_SILABS_SIWX917_CLOCK_ENABLED
help
Enable clock management on Silicon Labs SiWx917 chips. This driver
includes support for HP (High Performace), ULP (Ultra Low Power), and
ULP VBAT clocks.

The original hardware allow to customize the various clocks offered for
every devices. This driver does not provide such customizations. It
just hardcodes sane default parameters for every devices.
198 changes: 198 additions & 0 deletions drivers/clock_control/clock_control_silabs_siwx917.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
/* Copyright (c) 2024 Silicon Laboratories Inc.
* SPDX-License-Identifier: Apache-2.0
*
* Poor man driver for 917 clocks. 917 includes High Performace (HP) clock
* (@46000000), Ultra Lower Power (ULP) clock (@24041400) and ULP VBAT (@24048000)
*
*/
#include <zephyr/dt-bindings/clock/silabs/siwx917-clock.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/logging/log.h>

#include "rsi_power_save.h"
#include "rsi_rom_ulpss_clk.h"
#include "rsi_rom_clks.h"
#include "clock_update.h"
#include "sl_si91x_clock_manager.h"

#define DT_DRV_COMPAT silabs_siwx917_clock

LOG_MODULE_REGISTER(siwx917_clock, CONFIG_CLOCK_CONTROL_LOG_LEVEL);

struct siwx917_clock_data {
uint32_t enable;
};

static int siwx917_clock_on(const struct device *dev, clock_control_subsys_t sys)
{
struct siwx917_clock_data *data = dev->data;
uintptr_t clockid = (uintptr_t)sys;

switch (clockid) {
case SIWX917_CLK_ULP_UART:
RSI_PS_UlpssPeriPowerUp(ULPSS_PWRGATE_ULP_UART);
RSI_ULPSS_UlpUartClkConfig(ULPCLK, ENABLE_STATIC_CLK,
false, ULP_UART_ULP_32MHZ_RC_CLK, 1);
break;

Check notice on line 36 in drivers/clock_control/clock_control_silabs_siwx917.c

View workflow job for this annotation

GitHub Actions / compliance

You may want to run clang-format on this change

drivers/clock_control/clock_control_silabs_siwx917.c:36 - RSI_ULPSS_UlpUartClkConfig(ULPCLK, ENABLE_STATIC_CLK, - false, ULP_UART_ULP_32MHZ_RC_CLK, 1); + RSI_ULPSS_UlpUartClkConfig(ULPCLK, ENABLE_STATIC_CLK, false, + ULP_UART_ULP_32MHZ_RC_CLK, 1);
case SIWX917_CLK_ULP_I2C:
RSI_PS_UlpssPeriPowerUp(ULPSS_PWRGATE_ULP_I2C);
RSI_ULPSS_PeripheralEnable(ULPCLK, ULP_I2C_CLK, ENABLE_STATIC_CLK);
break;
case SIWX917_CLK_ULP_DMA:
RSI_PS_UlpssPeriPowerUp(ULPSS_PWRGATE_ULP_UDMA);
RSI_ULPSS_PeripheralEnable(ULPCLK, ULP_UDMA_CLK, ENABLE_STATIC_CLK);
break;
case SIWX917_CLK_UART1:
RSI_PS_M4ssPeriPowerUp(M4SS_PWRGATE_ULP_EFUSE_PERI);
/* RSI_CLK_UsartClkConfig() calls RSI_CLK_PeripheralClkEnable(); */
RSI_CLK_UsartClkConfig(M4CLK, ENABLE_STATIC_CLK, 0, USART1, 0, 1);
break;
case SIWX917_CLK_UART2:
RSI_PS_M4ssPeriPowerUp(M4SS_PWRGATE_ULP_EFUSE_PERI);
/* RSI_CLK_UsartClkConfig() calls RSI_CLK_PeripheralClkEnable(); */
RSI_CLK_UsartClkConfig(M4CLK, ENABLE_STATIC_CLK, 0, USART2, 0, 1);
break;
case SIWX917_CLK_I2C0:
RSI_PS_M4ssPeriPowerUp(M4SS_PWRGATE_ULP_EFUSE_PERI);
RSI_CLK_I2CClkConfig(M4CLK, true, 0);
break;
case SIWX917_CLK_I2C1:
RSI_PS_M4ssPeriPowerUp(M4SS_PWRGATE_ULP_EFUSE_PERI);
RSI_CLK_I2CClkConfig(M4CLK, true, 1);
break;
case SIWX917_CLK_DMA0:
RSI_PS_M4ssPeriPowerUp(M4SS_PWRGATE_ULP_EFUSE_PERI);
RSI_CLK_PeripheralClkEnable(M4CLK, UDMA_CLK, ENABLE_STATIC_CLK);
break;
default:
return -EINVAL;
}
data->enable |= BIT(clockid);

return 0;
}

static int siwx917_clock_off(const struct device *dev, clock_control_subsys_t sys)
{
struct siwx917_clock_data *data = dev->data;
uintptr_t clockid = (uintptr_t)sys;

switch (clockid) {
case SIWX917_CLK_ULP_I2C:
RSI_ULPSS_PeripheralDisable(ULPCLK, ULP_I2C_CLK);
break;
case SIWX917_CLK_ULP_DMA:
RSI_ULPSS_PeripheralDisable(ULPCLK, ULP_UDMA_CLK);
break;
case SIWX917_CLK_UART1:
RSI_CLK_PeripheralClkDisable(M4CLK, USART1_CLK);
break;
case SIWX917_CLK_UART2:
RSI_CLK_PeripheralClkDisable(M4CLK, USART2_CLK);
break;
case SIWX917_CLK_DMA0:
RSI_CLK_PeripheralClkDisable(M4CLK, UDMA_CLK);
break;
case SIWX917_CLK_ULP_UART:
case SIWX917_CLK_I2C0:
case SIWX917_CLK_I2C1:
/* Not supported */
return 0;
default:
return -EINVAL;
}

data->enable &= ~BIT(clockid);
return 0;
}

static int siwx917_clock_get_rate(const struct device *dev, clock_control_subsys_t sys,
uint32_t *rate)
{
uintptr_t clockid = (uintptr_t)sys;

switch (clockid) {
case SIWX917_CLK_ULP_UART:
*rate = RSI_CLK_GetBaseClock(ULPSS_UART);
return 0;
case SIWX917_CLK_UART1:
*rate = RSI_CLK_GetBaseClock(M4_USART0);
return 0;
case SIWX917_CLK_UART2:
*rate = RSI_CLK_GetBaseClock(M4_UART1);
return 0;
default:
/* For now, no other driver need clock rate */
return -EINVAL;
}
}

static enum clock_control_status siwx917_clock_get_status(const struct device *dev,
clock_control_subsys_t sys)
{
struct siwx917_clock_data *data = dev->data;
uintptr_t clockid = (uintptr_t)sys;

if (data->enable & BIT(clockid)) {
return CLOCK_CONTROL_STATUS_ON;
} else {
return CLOCK_CONTROL_STATUS_OFF;
}
}

static int siwx917_clock_init(const struct device *dev)
{
SystemCoreClockUpdate();

/* Use SoC PLL at configured frequency as core clock */
sl_si91x_clock_manager_m4_set_core_clk(M4_SOCPLLCLK, CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC);

/* Use interface PLL at configured frequency as peripheral clock */
sl_si91x_clock_manager_set_pll_freq(INFT_PLL, CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC,
PLL_REF_CLK_VAL_XTAL);

/* FIXME: Currently the clock consumer use clocks without power on them.
* This should be fixed in drivers. Meanwhile, get the list of required
* clocks using DT labels.
*/
#if DT_NODE_HAS_STATUS(DT_NODELABEL(ulpuart), okay)
siwx917_clock_on(dev, (clock_control_subsys_t)SIWX917_CLK_ULP_UART);
#endif

#if DT_NODE_HAS_STATUS(DT_NODELABEL(ulpi2c), okay)
siwx917_clock_on(dev, (clock_control_subsys_t)SIWX917_CLK_ULP_I2C);
#endif

#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart1), okay)
siwx917_clock_on(dev, (clock_control_subsys_t)SIWX917_CLK_UART1);
#endif

#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart2), okay)
siwx917_clock_on(dev, (clock_control_subsys_t)SIWX917_CLK_UART2);
#endif

#if DT_NODE_HAS_STATUS(DT_NODELABEL(i2c0), okay)
siwx917_clock_on(dev, (clock_control_subsys_t)SIWX917_CLK_I2C0);
#endif

#if DT_NODE_HAS_STATUS(DT_NODELABEL(i2c1), okay)
siwx917_clock_on(dev, (clock_control_subsys_t)SIWX917_CLK_I2C1);
#endif

return 0;
}

static const struct clock_control_driver_api siwx917_clock_api = {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I believe this should be using DEVICE_API() like here:
https://github.com/zephyrproject-rtos/zephyr/blob/59c94db6f052c9d848b4cec2008152d32d8ee597/drivers/clock_control/clock_control_nrf.c#L695-L700

It's a fairly new convention, so if we're not pointing at a recent enough upstream yet, then that needs to be fixed first. Most likely the same update will need to be made to any other of our downstream 917 drivers.

.on = siwx917_clock_on,
.off = siwx917_clock_off,
.get_rate = siwx917_clock_get_rate,
.get_status = siwx917_clock_get_status,
};

#define SIWX917_CLOCK_INIT(p) \
static struct siwx917_clock_data siwx917_clock_data_##p; \
DEVICE_DT_INST_DEFINE(p, siwx917_clock_init, NULL, &siwx917_clock_data_##p, NULL, \
PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, \
&siwx917_clock_api);

Check notice on line 196 in drivers/clock_control/clock_control_silabs_siwx917.c

View workflow job for this annotation

GitHub Actions / compliance

You may want to run clang-format on this change

drivers/clock_control/clock_control_silabs_siwx917.c:196 -#define SIWX917_CLOCK_INIT(p) \ - static struct siwx917_clock_data siwx917_clock_data_##p; \ - DEVICE_DT_INST_DEFINE(p, siwx917_clock_init, NULL, &siwx917_clock_data_##p, NULL, \ - PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, \ +#define SIWX917_CLOCK_INIT(p) \ + static struct siwx917_clock_data siwx917_clock_data_##p; \ + DEVICE_DT_INST_DEFINE(p, siwx917_clock_init, NULL, &siwx917_clock_data_##p, NULL, \ + PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, \

DT_INST_FOREACH_STATUS_OKAY(SIWX917_CLOCK_INIT)
21 changes: 16 additions & 5 deletions drivers/dma/dma_silabs_siwx917.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <zephyr/sys/util.h>
#include <zephyr/device.h>
#include <zephyr/drivers/dma.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/logging/log.h>
#include <zephyr/types.h>
#include "rsi_rom_udma_wrapper.h"
Expand All @@ -29,6 +30,8 @@ struct dma_siwx917_config {
uint8_t channels; /* UDMA channel count */
uint8_t irq_number; /* IRQ number */
RSI_UDMA_DESC_T *sram_desc_addr; /* SRAM Address for UDMA Descriptor Storage */
const struct device *clock_dev;
clock_control_subsys_t clock_subsys;
void (*irq_configure)(void); /* IRQ configure function */
};

Expand Down Expand Up @@ -169,7 +172,7 @@ static int dma_siwx917_configure(const struct device *dev, uint32_t channel,
void *udma_handle = &data->dma_rom_buff;
int status;

/* Expecting a fixed channel number between 0-31 for udma0 and 0-11 for udma1 */
/* Expecting a fixed channel number between 0-31 for dma0 and 0-11 for ulpdma */
if (channel >= cfg->channels) {
return -EINVAL;
}
Expand Down Expand Up @@ -204,7 +207,7 @@ static int dma_siwx917_reload(const struct device *dev, uint32_t channel, uint32
uint32_t length;
RSI_UDMA_DESC_T *udma_table = cfg->sram_desc_addr;

/* Expecting a fixed channel number between 0-31 for udma0 and 0-11 for udma1 */
/* Expecting a fixed channel number between 0-31 for dma0 and 0-11 for ulpdma */
if (channel >= cfg->channels) {
return -EINVAL;
}
Expand Down Expand Up @@ -252,7 +255,7 @@ static int dma_siwx917_start(const struct device *dev, uint32_t channel)
struct dma_siwx917_data *data = dev->data;
void *udma_handle = &data->dma_rom_buff;

/* Expecting a fixed channel number between 0-31 for udma0 and 0-11 for udma1 */
/* Expecting a fixed channel number between 0-31 for dma0 and 0-11 for ulpdma */
if (channel >= cfg->channels) {
return -EINVAL;
}
Expand All @@ -276,7 +279,7 @@ static int dma_siwx917_stop(const struct device *dev, uint32_t channel)
struct dma_siwx917_data *data = dev->data;
void *udma_handle = &data->dma_rom_buff;

/* Expecting a fixed channel number between 0-31 for udma0 and 0-11 for udma1 */
/* Expecting a fixed channel number between 0-31 for dma0 and 0-11 for ulpdma */
if (channel >= cfg->channels) {
return -EINVAL;
}
Expand All @@ -293,7 +296,7 @@ static int dma_siwx917_get_status(const struct device *dev, uint32_t channel,
const struct dma_siwx917_config *cfg = dev->config;
RSI_UDMA_DESC_T *udma_table = cfg->sram_desc_addr;

/* Expecting a fixed channel number between 0-31 for udma0 and 0-11 for udma1 */
/* Expecting a fixed channel number between 0-31 for dma0 and 0-11 for ulpdma */
if (channel >= cfg->channels) {
return -EINVAL;
}
Expand Down Expand Up @@ -326,6 +329,12 @@ static int dma_siwx917_init(const struct device *dev)
.udma_irq_num = cfg->irq_number,
.desc = cfg->sram_desc_addr,
};
int ret;

ret = clock_control_on(cfg->clock_dev, cfg->clock_subsys);
if (ret) {
return ret;
}

udma_handle = UDMAx_Initialize(&udma_resources, udma_resources.desc, NULL,
(uint32_t *)&data->dma_rom_buff);
Expand Down Expand Up @@ -406,6 +415,8 @@ static const struct dma_driver_api siwx917_dma_driver_api = {
irq_enable(DT_INST_IRQ(inst, irq)); \
} \
static const struct dma_siwx917_config dma##inst##_cfg = { \
.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \
.clock_subsys = (clock_control_subsys_t)DT_INST_PHA(inst, clocks, clkid), \
.reg = (UDMA0_Type *)DT_INST_REG_ADDR(inst), \
.channels = DT_INST_PROP(inst, dma_channels), \
.irq_number = DT_INST_PROP_BY_IDX(inst, interrupts, 0), \
Expand Down
Loading
Loading