Skip to content

Commit

Permalink
drivers: clock: siwx917: Add dumb clock driver
Browse files Browse the repository at this point in the history
This driver is mostly the initial seed for further implementation of a
real clock driver.

Currently, sinc ethe driver do not enable the clock sources, this driver
still contains the series of #ifdef to enable the clocks.

It also doesn't allow the user to choose the clock source for the
various peripherals. The driver hardcodes some sane values.

Signed-off-by: Jérôme Pouiller <[email protected]>
  • Loading branch information
jerome-pouiller committed Dec 20, 2024
1 parent 7fbc583 commit af6a902
Show file tree
Hide file tree
Showing 10 changed files with 288 additions and 45 deletions.
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 locks.

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.
205 changes: 205 additions & 0 deletions drivers/clock_control/clock_control_silabs_siwx917.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
/* 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 "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;
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 = 32000000;
return 0;
case SIWX917_CLK_UART1:
*rate = 25000000;
return 0;
case SIWX917_CLK_UART2:
*rate = 20000000;
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(ulpdma), okay)
siwx917_clock_on(dev, (clock_control_subsys_t)SIWX917_CLK_ULP_DMA);
#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

#if DT_NODE_HAS_STATUS(DT_NODELABEL(udma0), okay)
siwx917_clock_on(dev, (clock_control_subsys_t)SIWX917_CLK_DMA0);
#endif

return 0;
}

static const struct clock_control_driver_api siwx917_clock_api = {
.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);

DT_INST_FOREACH_STATUS_OKAY(SIWX917_CLOCK_INIT)
22 changes: 19 additions & 3 deletions dts/arm/silabs/siwg917.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <arm/armv7-m.dtsi>
#include <zephyr/dt-bindings/i2c/i2c.h>
#include <zephyr/dt-bindings/spi/spi.h>
#include <zephyr/dt-bindings/clock/silabs/siwx917-clock.h>

/ {
chosen {
Expand Down Expand Up @@ -41,6 +42,16 @@
};

soc {
clock0: clock@46000000 {
compatible = "silabs,siwx917-clock";
reg = <0x46000000 0x100>,
<0x46000800 0x100>,
<0x24041400 0x100>,
<0x24048000 0x200>;
#clock-cells = <1>;
status = "okay";
};

pinctrl0: pinctrl@46130000 {
compatible = "silabs,siwx917-pinctrl";
reg = <0x46130000 0x1000>;
Expand All @@ -64,7 +75,7 @@
reg = <0x24041800 0x1000>;
interrupts = <12 0>;
reg-shift = <2>;
clock-frequency = <32000000>;
clocks = <&clock0 SIWX917_CLK_ULP_UART>;
current-speed = <115200>;
status = "disabled";
};
Expand All @@ -74,7 +85,7 @@
reg = <0x44000000 0x1000>;
interrupts = <38 0>;
reg-shift = <2>;
clock-frequency = <25000000>;
clocks = <&clock0 SIWX917_CLK_UART1>;
current-speed = <115200>;
status = "disabled";
};
Expand All @@ -84,7 +95,7 @@
reg = <0x45020000 0x1000>;
interrupts = <39 0>;
reg-shift = <2>;
clock-frequency = <20000000>;
clocks = <&clock0 SIWX917_CLK_UART2>;
current-speed = <115200>;
status = "disabled";
};
Expand Down Expand Up @@ -194,6 +205,7 @@
reg = <0x44010000 0x100>;
interrupts = <42 0>;
interrupt-names = "i2c0";
clocks = <&clock0 SIWX917_CLK_I2C0>;
status = "disabled";
};

Expand All @@ -204,6 +216,7 @@
reg = <0x47040000 0x100>;
interrupts = <61 0>;
interrupt-names = "i2c1";
clocks = <&clock0 SIWX917_CLK_I2C1>;
status = "disabled";
};

Expand All @@ -214,6 +227,7 @@
reg = <0x24040000 0x100>;
interrupts = <13 0>;
interrupt-names = "i2c2";
clocks = <&clock0 SIWX917_CLK_ULP_I2C>;
status = "disabled";
};

Expand All @@ -229,6 +243,7 @@
reg = <0x44030000 0x82C>;
interrupts = <33 0>;
interrupt-names = "dma0";
clocks = <&clock0 SIWX917_CLK_DMA0>;
silabs,sram-desc-addr = <0x2fc00>;
#dma-cells = < 1>;
dma-channels = <32>;
Expand All @@ -242,6 +257,7 @@
reg = <0x24078000 0x82C>;
interrupts = <10 0>;
interrupt-names = "ulpdma";
clocks = <&clock0 SIWX917_CLK_ULP_DMA>;
silabs,sram-desc-addr = <0x24061c00>;
#dma-cells = < 1>;
dma-channels = <12>;
Expand Down
18 changes: 18 additions & 0 deletions dts/bindings/clock/silabs,siwx917-clock.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright (c) 2024 Silicon Laboratories Inc.
# SPDX-License-Identifier: Apache-2.0

description: Clocks embedded on Silabs SiWx917 chips

compatible: "silabs,siwx917-clock"

include: [clock-controller.yaml, base.yaml]

properties:
reg:
required: true

"#clock-cells":
const: 1

clock-cells:
- clkid
16 changes: 16 additions & 0 deletions include/zephyr/dt-bindings/clock/silabs/siwx917-clock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* Copyright (c) 2024 Silicon Laboratories Inc.
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_SILABS_SIWX917_CLOCK_H_
#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_SILABS_SIWX917_CLOCK_H_

#define SIWX917_CLK_ULP_UART 0
#define SIWX917_CLK_ULP_I2C 1
#define SIWX917_CLK_ULP_DMA 2
#define SIWX917_CLK_UART1 3
#define SIWX917_CLK_UART2 4
#define SIWX917_CLK_I2C0 5
#define SIWX917_CLK_I2C1 6
#define SIWX917_CLK_DMA0 7

#endif
Loading

0 comments on commit af6a902

Please sign in to comment.