From 81f731b686a91f1c180f1804d4eaebc76fa7e621 Mon Sep 17 00:00:00 2001 From: Titan Chen Date: Tue, 25 Feb 2025 16:59:01 +0800 Subject: [PATCH] drivers: pwm: rts5912: port pwm driver on Zephyr Add PWM driver support for Realtek RTS5912 Signed-off-by: Titan Chen --- drivers/pwm/CMakeLists.txt | 1 + drivers/pwm/Kconfig | 2 + drivers/pwm/Kconfig.rts5912 | 9 ++ drivers/pwm/pwm_realtek_rts5912.c | 125 ++++++++++++++++++ dts/arm/realtek/ec/rts5912.dtsi | 65 +++++++++ dts/bindings/pwm/realtek,rts5912-pwm.yaml | 20 +++ soc/realtek/ec/rts5912/reg/reg_pwm.h | 26 ++++ .../build_all/pwm/boards/rts5912_evb.overlay | 15 +++ tests/drivers/build_all/pwm/testcase.yaml | 2 + 9 files changed, 265 insertions(+) create mode 100644 drivers/pwm/Kconfig.rts5912 create mode 100644 drivers/pwm/pwm_realtek_rts5912.c create mode 100644 dts/bindings/pwm/realtek,rts5912-pwm.yaml create mode 100644 soc/realtek/ec/rts5912/reg/reg_pwm.h create mode 100644 tests/drivers/build_all/pwm/boards/rts5912_evb.overlay diff --git a/drivers/pwm/CMakeLists.txt b/drivers/pwm/CMakeLists.txt index 4c1b22e9c630..f282da593a8b 100644 --- a/drivers/pwm/CMakeLists.txt +++ b/drivers/pwm/CMakeLists.txt @@ -54,3 +54,4 @@ zephyr_library_sources_ifdef(CONFIG_PWM_RENESAS_RZ_GPT pwm_renesas_rz_gpt.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE pwm_handlers.c) zephyr_library_sources_ifdef(CONFIG_PWM_CAPTURE pwm_capture.c) zephyr_library_sources_ifdef(CONFIG_PWM_SHELL pwm_shell.c) +zephyr_library_sources_ifdef(CONFIG_PWM_REALTEK_RTS5912 pwm_realtek_rts5912.c) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 57a684ca2d16..3475330434ca 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -122,4 +122,6 @@ source "drivers/pwm/Kconfig.fake" source "drivers/pwm/Kconfig.renesas_rz" +source "drivers/pwm/Kconfig.rts5912" + endif # PWM diff --git a/drivers/pwm/Kconfig.rts5912 b/drivers/pwm/Kconfig.rts5912 new file mode 100644 index 000000000000..c16ef1a54f46 --- /dev/null +++ b/drivers/pwm/Kconfig.rts5912 @@ -0,0 +1,9 @@ +# Copyright (c) 2025, Realtek, SIBG-SD7 +# SPDX-License-Identifier: Apache-2.0 + +config PWM_REALTEK_RTS5912 + bool "Realtek RTS5912 PWM Driver" + default y + depends on DT_HAS_REALTEK_RTS5912_PWM_ENABLED + help + Enable PWM driver for Realtek RTS5912 EC. diff --git a/drivers/pwm/pwm_realtek_rts5912.c b/drivers/pwm/pwm_realtek_rts5912.c new file mode 100644 index 000000000000..e6dd6f61e706 --- /dev/null +++ b/drivers/pwm/pwm_realtek_rts5912.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2025 Realtek, SIBG-SD7 + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT realtek_rts5912_pwm + +#include +#include +#include +#include +#include + +#include "reg/reg_pwm.h" + +LOG_MODULE_REGISTER(pwm, CONFIG_PWM_LOG_LEVEL); + +#define PWM_CYCLE_PER_SEC MHZ(50) + +struct pwm_rts5912_config { + volatile struct pwm_regs *pwm_regs; + uint32_t pwm_clk_grp; + uint32_t pwm_clk_idx; + const struct device *clk_dev; + const struct pinctrl_dev_config *pcfg; +}; + +static int pwm_rts5912_set_cycles(const struct device *dev, uint32_t channel, + uint32_t period_cycles, uint32_t pulse_cycles, pwm_flags_t flags) +{ + const struct pwm_rts5912_config *const pwm_config = dev->config; + volatile struct pwm_regs *pwm_regs = pwm_config->pwm_regs; + + uint32_t pwm_div, pwm_duty; + + if (channel > 0) { + return -EIO; + } + + pwm_div = period_cycles; + pwm_duty = pulse_cycles; + + pwm_regs->div = pwm_div; + pwm_regs->duty = pwm_duty; + + LOG_DBG("period_cycles=%d, pulse_cycles=%d, pwm_div=%d, pwm_duty=%d", period_cycles, + pulse_cycles, pwm_div, pwm_duty); + + if (flags == PWM_POLARITY_INVERTED) { + pwm_regs->ctrl |= PWM_CTRL_INVT; + } + pwm_regs->ctrl |= PWM_CTRL_EN; + + return 0; +} + +static int pwm_rts5912_get_cycles_per_sec(const struct device *dev, uint32_t channel, + uint64_t *cycles) +{ + ARG_UNUSED(dev); + + if (channel > 0) { + return -EIO; + } + + if (cycles) { + *cycles = PWM_CYCLE_PER_SEC; + } + + return 0; +} + +static DEVICE_API(pwm, pwm_rts5912_driver_api) = { + .set_cycles = pwm_rts5912_set_cycles, + .get_cycles_per_sec = pwm_rts5912_get_cycles_per_sec, +}; + +static int pwm_rts5912_init(const struct device *dev) +{ + const struct pwm_rts5912_config *const pwm_config = dev->config; + struct rts5912_sccon_subsys sccon; + + int rc = 0; +#ifdef CONFIG_PINCTRL + rc = pinctrl_apply_state(pwm_config->pcfg, PINCTRL_STATE_DEFAULT); + if (rc < 0) { + LOG_ERR("PWM pinctrl setup failed (%d)", rc); + return rc; + } +#endif +#ifdef CONFIG_CLOCK_CONTROL + if (!device_is_ready(pwm_config->clk_dev)) { + return -ENODEV; + } + + sccon.clk_grp = pwm_config->pwm_clk_grp; + sccon.clk_idx = pwm_config->pwm_clk_idx; + rc = clock_control_on(pwm_config->clk_dev, (clock_control_subsys_t)&sccon); + if (rc != 0) { + return rc; + } +#endif + return rc; +} + +#define RTS5912_PWM_PINCTRL_DEF(inst) PINCTRL_DT_INST_DEFINE(inst) + +#define RTS5912_PWM_CONFIG(inst) \ + static struct pwm_rts5912_config pwm_rts5912_config_##inst = { \ + .pwm_regs = (struct pwm_regs *)DT_INST_REG_ADDR(inst), \ + .pwm_clk_grp = DT_INST_CLOCKS_CELL(inst, clk_grp), \ + .pwm_clk_idx = DT_INST_CLOCKS_CELL(inst, clk_idx), \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + }; + +#define RTS5912_PWM_DEVICE_INIT(index) \ + RTS5912_PWM_PINCTRL_DEF(index); \ + RTS5912_PWM_CONFIG(index); \ + DEVICE_DT_INST_DEFINE(index, &pwm_rts5912_init, NULL, NULL, &pwm_rts5912_config_##index, \ + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &pwm_rts5912_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(RTS5912_PWM_DEVICE_INIT) diff --git a/dts/arm/realtek/ec/rts5912.dtsi b/dts/arm/realtek/ec/rts5912.dtsi index bb022acbf72e..d9ec0bca3995 100644 --- a/dts/arm/realtek/ec/rts5912.dtsi +++ b/dts/arm/realtek/ec/rts5912.dtsi @@ -8,6 +8,7 @@ #include #include #include +#include / { cpus { @@ -276,6 +277,70 @@ interrupts = <192 0>; status = "disabled"; }; + + pwm0: pwm@4000f000 { + compatible = "realtek,rts5912-pwm"; + clocks = <&sccon RTS5912_SCCON_PERIPH_GRP0 PERIPH_GRP0_PWM0_CLKPWR>; + reg = <0x4000f000 0x0c>; + status = "disabled"; + #pwm-cells = <3>; + }; + + pwm1: pwm@4000f00c { + compatible = "realtek,rts5912-pwm"; + clocks = <&sccon RTS5912_SCCON_PERIPH_GRP0 PERIPH_GRP0_PWM1_CLKPWR>; + reg = <0x4000f00c 0x0c>; + status = "disabled"; + #pwm-cells = <3>; + }; + + pwm2: pwm@4000f018 { + compatible = "realtek,rts5912-pwm"; + clocks = <&sccon RTS5912_SCCON_PERIPH_GRP0 PERIPH_GRP0_PWM2_CLKPWR>; + reg = <0x4000f018 0x0c>; + status = "disabled"; + #pwm-cells = <3>; + }; + + pwm3: pwm@4000f024 { + compatible = "realtek,rts5912-pwm"; + clocks = <&sccon RTS5912_SCCON_PERIPH_GRP0 PERIPH_GRP0_PWM3_CLKPWR>; + reg = <0x4000f024 0x0c>; + status = "disabled"; + #pwm-cells = <3>; + }; + + pwm4: pwm@4000f030 { + compatible = "realtek,rts5912-pwm"; + clocks = <&sccon RTS5912_SCCON_PERIPH_GRP0 PERIPH_GRP0_PWM4_CLKPWR>; + reg = <0x4000f030 0x0c>; + status = "disabled"; + #pwm-cells = <3>; + }; + + pwm5: pwm@4000f03c { + compatible = "realtek,rts5912-pwm"; + clocks = <&sccon RTS5912_SCCON_PERIPH_GRP0 PERIPH_GRP0_PWM5_CLKPWR>; + reg = <0x4000f03c 0x0c>; + status = "disabled"; + #pwm-cells = <3>; + }; + + pwm6: pwm@4000f048 { + compatible = "realtek,rts5912-pwm"; + clocks = <&sccon RTS5912_SCCON_PERIPH_GRP0 PERIPH_GRP0_PWM6_CLKPWR>; + reg = <0x4000f048 0x0c>; + status = "disabled"; + #pwm-cells = <3>; + }; + + pwm7: pwm@4000f054 { + compatible = "realtek,rts5912-pwm"; + clocks = <&sccon RTS5912_SCCON_PERIPH_GRP0 PERIPH_GRP0_PWM7_CLKPWR>; + reg = <0x4000f054 0x0c>; + status = "disabled"; + #pwm-cells = <3>; + }; }; swj_port: swj-port { diff --git a/dts/bindings/pwm/realtek,rts5912-pwm.yaml b/dts/bindings/pwm/realtek,rts5912-pwm.yaml new file mode 100644 index 000000000000..73c12f58a1b7 --- /dev/null +++ b/dts/bindings/pwm/realtek,rts5912-pwm.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2025, Realtek, SIBG-SD7 +# SPDX-License-Identifier: Apache-2.0 + +description: Realtek RTS5912 PWM + +include: [pwm-controller.yaml, base.yaml, pinctrl-device.yaml] + +compatible: "realtek,rts5912-pwm" + +properties: + reg: + required: true + + "#pwm-cells": + const: 3 + +pwm-cells: + - channel + - period + - flags diff --git a/soc/realtek/ec/rts5912/reg/reg_pwm.h b/soc/realtek/ec/rts5912/reg/reg_pwm.h new file mode 100644 index 000000000000..65b2d51fc90a --- /dev/null +++ b/soc/realtek/ec/rts5912/reg/reg_pwm.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025 Realtek, SIBG-SD7 + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_REALTEK_RTS5912_REG_PWM_H +#define ZEPHYR_SOC_REALTEK_RTS5912_REG_PWM_H + +/* + * @brief PWM Controller (PWM) + */ + +struct pwm_regs { + uint32_t duty; + uint32_t div; + uint32_t ctrl; +}; + +/* CTRL */ +#define PWM_CTRL_CLKSRC BIT(28) +#define PWM_CTRL_INVT BIT(29) +#define PWM_CTRL_RST BIT(30) +#define PWM_CTRL_EN BIT(31) + +#endif /* ZEPHYR_SOC_REALTEK_RTS5912_REG_PWM_H */ diff --git a/tests/drivers/build_all/pwm/boards/rts5912_evb.overlay b/tests/drivers/build_all/pwm/boards/rts5912_evb.overlay new file mode 100644 index 000000000000..1a455c43f7bd --- /dev/null +++ b/tests/drivers/build_all/pwm/boards/rts5912_evb.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2025 Realtek Corporation. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + pwm-0 = &pwm0; + }; +}; + +&pwm0 { + status = "okay"; +}; diff --git a/tests/drivers/build_all/pwm/testcase.yaml b/tests/drivers/build_all/pwm/testcase.yaml index d21744a22c52..92a18a5080e7 100644 --- a/tests/drivers/build_all/pwm/testcase.yaml +++ b/tests/drivers/build_all/pwm/testcase.yaml @@ -57,3 +57,5 @@ tests: drivers.pwm.max31790.build: platform_allow: nucleo_f429zi extra_args: DTC_OVERLAY_FILE=max31790.overlay + drivers.pwm.rts5912.build: + platform_allow: rts5912_evb