From cc1cd4d65bfceee5a1ba50caab1cef0deb0f3d63 Mon Sep 17 00:00:00 2001 From: Antonio Tessarolo Date: Wed, 20 Oct 2021 15:20:29 +0200 Subject: [PATCH] arm: Nxp imx6sx added PWM support This commit adds support for IMX6SX PWM. The PWM module is the same module present on the IMX7D and so dts bindings has been renamed following the one present on linux. Signed-off-by: Antonio Tessarolo --- drivers/pwm/pwm_imx.c | 4 +- dts/arm/nxp/nxp_imx6sx_m4.dtsi | 113 ++++++++++++++++++ dts/arm/nxp/nxp_imx7d_m4.dtsi | 8 +- ...{fsl,imx7d-pwm.yaml => fsl,imx27-pwm.yaml} | 9 +- soc/arm/nxp_imx/mcimx6x_m4/CMakeLists.txt | 5 +- .../mcimx6x_m4/Kconfig.defconfig.mcimx6x_m4 | 4 + soc/arm/nxp_imx/mcimx6x_m4/soc.c | 67 +++++++++++ soc/arm/nxp_imx/mcimx6x_m4/soc.h | 1 + soc/arm/nxp_imx/mcimx6x_m4/soc_clk_freq.c | 79 ++++++++++++ soc/arm/nxp_imx/mcimx6x_m4/soc_clk_freq.h | 30 +++++ 10 files changed, 311 insertions(+), 9 deletions(-) rename dts/bindings/pwm/{fsl,imx7d-pwm.yaml => fsl,imx27-pwm.yaml} (60%) create mode 100644 soc/arm/nxp_imx/mcimx6x_m4/soc_clk_freq.c create mode 100644 soc/arm/nxp_imx/mcimx6x_m4/soc_clk_freq.h diff --git a/drivers/pwm/pwm_imx.c b/drivers/pwm/pwm_imx.c index 70294ef62b9..70789e3bdaf 100644 --- a/drivers/pwm/pwm_imx.c +++ b/drivers/pwm/pwm_imx.c @@ -172,7 +172,7 @@ static const struct pwm_driver_api imx_pwm_driver_api = { CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ &imx_pwm_driver_api); -#if DT_HAS_COMPAT_STATUS_OKAY(fsl_imx7d_pwm) -#define DT_DRV_COMPAT fsl_imx7d_pwm +#if DT_HAS_COMPAT_STATUS_OKAY(fsl_imx27_pwm) +#define DT_DRV_COMPAT fsl_imx27_pwm DT_INST_FOREACH_STATUS_OKAY(PWM_IMX_INIT) #endif diff --git a/dts/arm/nxp/nxp_imx6sx_m4.dtsi b/dts/arm/nxp/nxp_imx6sx_m4.dtsi index 5381ffa7096..ef646178b69 100644 --- a/dts/arm/nxp/nxp_imx6sx_m4.dtsi +++ b/dts/arm/nxp/nxp_imx6sx_m4.dtsi @@ -339,6 +339,119 @@ label = "I2C_4"; status = "disabled"; }; + + pwm1: pwm@42080000 { + compatible = "fsl,imx6sx-pwm", "fsl,imx27-pwm"; + reg = <0x42080000 0x4000>; + interrupts = <83 0>; + rdc = <(RDC_DOMAIN_PERM(A9_DOMAIN_ID,\ + RDC_DOMAIN_PERM_RW)|\ + RDC_DOMAIN_PERM(M4_DOMAIN_ID,\ + RDC_DOMAIN_PERM_RW))>; + label = "PWM_1"; + prescaler = <0>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm2: pwm@42084000 { + compatible = "fsl,imx6sx-pwm", "fsl,imx27-pwm"; + reg = <0x42084000 0x4000>; + interrupts = <84 0>; + rdc = <(RDC_DOMAIN_PERM(A9_DOMAIN_ID,\ + RDC_DOMAIN_PERM_RW)|\ + RDC_DOMAIN_PERM(M4_DOMAIN_ID,\ + RDC_DOMAIN_PERM_RW))>; + label = "PWM_2"; + prescaler = <0>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm3: pwm@42088000 { + compatible = "fsl,imx6sx-pwm", "fsl,imx27-pwm"; + reg = <0x42088000 0x4000>; + interrupts = <85 0>; + rdc = <(RDC_DOMAIN_PERM(A9_DOMAIN_ID,\ + RDC_DOMAIN_PERM_RW)|\ + RDC_DOMAIN_PERM(M4_DOMAIN_ID,\ + RDC_DOMAIN_PERM_RW))>; + label = "PWM_3"; + prescaler = <0>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm4: pwm@4208c000 { + compatible = "fsl,imx6sx-pwm", "fsl,imx27-pwm"; + reg = <0x4208c000 0x4000>; + interrupts = <86 0>; + rdc = <(RDC_DOMAIN_PERM(A9_DOMAIN_ID,\ + RDC_DOMAIN_PERM_RW)|\ + RDC_DOMAIN_PERM(M4_DOMAIN_ID,\ + RDC_DOMAIN_PERM_RW))>; + label = "PWM_4"; + prescaler = <0>; + #pwm-cells = <2>; + status = "disabled"; + }; + + + pwm5: pwm@422a4000 { + compatible = "fsl,imx6sx-pwm", "fsl,imx27-pwm"; + reg = <0x422a4000 0x4000>; + interrupts = <83 0>; + rdc = <(RDC_DOMAIN_PERM(A9_DOMAIN_ID,\ + RDC_DOMAIN_PERM_RW)|\ + RDC_DOMAIN_PERM(M4_DOMAIN_ID,\ + RDC_DOMAIN_PERM_RW))>; + label = "PWM_5"; + prescaler = <0>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm6: pwm@422a8000 { + compatible = "fsl,imx6sx-pwm", "fsl,imx27-pwm"; + reg = <0x422a8000 0x4000>; + interrupts = <84 0>; + rdc = <(RDC_DOMAIN_PERM(A9_DOMAIN_ID,\ + RDC_DOMAIN_PERM_RW)|\ + RDC_DOMAIN_PERM(M4_DOMAIN_ID,\ + RDC_DOMAIN_PERM_RW))>; + label = "PWM_6"; + prescaler = <0>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm7: pwm@422ac000 { + compatible = "fsl,imx6sx-pwm", "fsl,imx27-pwm"; + reg = <0x422ac000 0x4000>; + interrupts = <85 0>; + rdc = <(RDC_DOMAIN_PERM(A9_DOMAIN_ID,\ + RDC_DOMAIN_PERM_RW)|\ + RDC_DOMAIN_PERM(M4_DOMAIN_ID,\ + RDC_DOMAIN_PERM_RW))>; + label = "PWM_7"; + prescaler = <0>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm8: pwm@422ab000 { + compatible = "fsl,imx6sx-pwm", "fsl,imx27-pwm"; + reg = <0x422ab000 0x4000>; + interrupts = <86 0>; + rdc = <(RDC_DOMAIN_PERM(A9_DOMAIN_ID,\ + RDC_DOMAIN_PERM_RW)|\ + RDC_DOMAIN_PERM(M4_DOMAIN_ID,\ + RDC_DOMAIN_PERM_RW))>; + label = "PWM_8"; + prescaler = <0>; + #pwm-cells = <2>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/nxp/nxp_imx7d_m4.dtsi b/dts/arm/nxp/nxp_imx7d_m4.dtsi index bdc2628f9f1..ea557750a6e 100644 --- a/dts/arm/nxp/nxp_imx7d_m4.dtsi +++ b/dts/arm/nxp/nxp_imx7d_m4.dtsi @@ -331,7 +331,7 @@ }; pwm1: pwm@30660000 { - compatible = "fsl,imx7d-pwm"; + compatible = "fsl,imx7d-pwm", "fsl,imx27-pwm"; reg = <0x30660000 0x10000>; interrupts = <81 0>; prescaler = <0>; @@ -345,7 +345,7 @@ }; pwm2: pwm@30670000 { - compatible = "fsl,imx7d-pwm"; + compatible = "fsl,imx7d-pwm", "fsl,imx27-pwm"; reg = <0x30670000 0x10000>; interrupts = <82 0>; prescaler = <0>; @@ -359,7 +359,7 @@ }; pwm3: pwm@30680000 { - compatible = "fsl,imx7d-pwm"; + compatible = "fsl,imx7d-pwm", "fsl,imx27-pwm"; reg = <0x30680000 0x10000>; interrupts = <83 0>; prescaler = <0>; @@ -373,7 +373,7 @@ }; pwm4: pwm@30690000 { - compatible = "fsl,imx7d-pwm"; + compatible = "fsl,imx7d-pwm", "fsl,imx27-pwm"; reg = <0x30690000 0x10000>; interrupts = <84 0>; prescaler = <0>; diff --git a/dts/bindings/pwm/fsl,imx7d-pwm.yaml b/dts/bindings/pwm/fsl,imx27-pwm.yaml similarity index 60% rename from dts/bindings/pwm/fsl,imx7d-pwm.yaml rename to dts/bindings/pwm/fsl,imx27-pwm.yaml index 9033cfa4e27..87434435b80 100644 --- a/dts/bindings/pwm/fsl,imx7d-pwm.yaml +++ b/dts/bindings/pwm/fsl,imx27-pwm.yaml @@ -1,9 +1,14 @@ # Copyright (c) 2018, Diego Sueiro # SPDX-License-Identifier: Apache-2.0 -description: i.MX7D PWM +description: | + This driver supports both i.MX6SX and i.MX7D PWM. + The compatible string is named "imx27" because the hardware module is the + same module present starting from imx27 CPUs and this driver can potentially + support other CPUs with imx27 module. This is also the same string used + in the Linux kernel. -compatible: "fsl,imx7d-pwm" +compatible: "fsl,imx27-pwm" include: [pwm-controller.yaml, base.yaml] diff --git a/soc/arm/nxp_imx/mcimx6x_m4/CMakeLists.txt b/soc/arm/nxp_imx/mcimx6x_m4/CMakeLists.txt index 3976cdf1344..a720300fca1 100644 --- a/soc/arm/nxp_imx/mcimx6x_m4/CMakeLists.txt +++ b/soc/arm/nxp_imx/mcimx6x_m4/CMakeLists.txt @@ -4,4 +4,7 @@ # SPDX-License-Identifier: Apache-2.0 # -zephyr_sources(soc.c) +zephyr_sources( + soc.c + soc_clk_freq.c +) diff --git a/soc/arm/nxp_imx/mcimx6x_m4/Kconfig.defconfig.mcimx6x_m4 b/soc/arm/nxp_imx/mcimx6x_m4/Kconfig.defconfig.mcimx6x_m4 index 6a035ce6a1c..b38cea3d91c 100644 --- a/soc/arm/nxp_imx/mcimx6x_m4/Kconfig.defconfig.mcimx6x_m4 +++ b/soc/arm/nxp_imx/mcimx6x_m4/Kconfig.defconfig.mcimx6x_m4 @@ -31,4 +31,8 @@ config COUNTER_IMX_EPIT default y depends on COUNTER +config PWM_IMX + default y + depends on PWM + endif # SOC_MCIMX6X_M4 diff --git a/soc/arm/nxp_imx/mcimx6x_m4/soc.c b/soc/arm/nxp_imx/mcimx6x_m4/soc.c index 6714b800c43..31e4515728f 100644 --- a/soc/arm/nxp_imx/mcimx6x_m4/soc.c +++ b/soc/arm/nxp_imx/mcimx6x_m4/soc.c @@ -104,6 +104,39 @@ static void SOC_RdcInit(void) /* Set access to I2C-4 for M4 core */ RDC_SetPdapAccess(RDC, rdcPdapI2c4, RDC_DT_VAL(i2c4), false, false); #endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm1), okay) + /* Set access to PWM-1 for M4 core */ + RDC_SetPdapAccess(RDC, rdcPdapPwm1, RDC_DT_VAL(pwm1), false, false); +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm2), okay) + /* Set access to PWM-2 for M4 core */ + RDC_SetPdapAccess(RDC, rdcPdapPwm2, RDC_DT_VAL(pwm2), false, false); +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm3), okay) + /* Set access to PWM-3 for M4 core */ + RDC_SetPdapAccess(RDC, rdcPdapPwm3, RDC_DT_VAL(pwm3), false, false); +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm4), okay) + /* Set access to PWM-4 for M4 core */ + RDC_SetPdapAccess(RDC, rdcPdapPwm4, RDC_DT_VAL(pwm4), false, false); +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm5), okay) + /* Set access to PWM-5 for M4 core */ + RDC_SetPdapAccess(RDC, rdcPdapPwm5, RDC_DT_VAL(pwm5), false, false); +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm6), okay) + /* Set access to PWM-6 for M4 core */ + RDC_SetPdapAccess(RDC, rdcPdapPwm6, RDC_DT_VAL(pwm6), false, false); +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm7), okay) + /* Set access to PWM-7 for M4 core */ + RDC_SetPdapAccess(RDC, rdcPdapPwm7, RDC_DT_VAL(pwm7), false, false); +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm8), okay) + /* Set access to PWM-8 for M4 core */ + RDC_SetPdapAccess(RDC, rdcPdapPwm8, RDC_DT_VAL(pwm8), false, false); +#endif } /* Initialize cache. */ @@ -196,7 +229,41 @@ static void SOC_ClockInit(void) #if DT_NODE_HAS_STATUS(DT_NODELABEL(i2c4), okay) CCM_ControlGate(CCM, ccmCcgrGateI2c4Serialclk, ccmClockNeededAll); #endif +#endif /* CONFIG_I2C_IMX */ + +#ifdef CONFIG_PWM_IMX + /* Select PWM clock is derived from OSC (24M) */ + CCM_SetRootMux(CCM, ccmRootPerclkClkSel, ccmRootmuxPerclkClkOsc24m); + + /* Set relevant divider = 1. */ + CCM_SetRootDivider(CCM, ccmRootPerclkPodf, 0); + + /* Enable PWM clock */ +#if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm1), okay) + CCM_ControlGate(CCM, ccmCcgrGatePwm1Clk, ccmClockNeededAll); #endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm2), okay) + CCM_ControlGate(CCM, ccmCcgrGatePwm2Clk, ccmClockNeededAll); +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm3), okay) + CCM_ControlGate(CCM, ccmCcgrGatePwm3Clk, ccmClockNeededAll); +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm4), okay) + CCM_ControlGate(CCM, ccmCcgrGatePwm4Clk, ccmClockNeededAll); +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm5), okay) + CCM_ControlGate(CCM, ccmCcgrGatePwm5Clk, ccmClockNeededAll); +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm6), okay) + CCM_ControlGate(CCM, ccmCcgrGatePwm6Clk, ccmClockNeededAll); +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm7), okay) + CCM_ControlGate(CCM, ccmCcgrGatePwm7Clk, ccmClockNeededAll); +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm8), okay) + CCM_ControlGate(CCM, ccmCcgrGatePwm8Clk, ccmClockNeededAll); +#endif +#endif /* CONFIG_PWM_IMX */ } /** diff --git a/soc/arm/nxp_imx/mcimx6x_m4/soc.h b/soc/arm/nxp_imx/mcimx6x_m4/soc.h index 33679cb1842..bdaf9a5f563 100644 --- a/soc/arm/nxp_imx/mcimx6x_m4/soc.h +++ b/soc/arm/nxp_imx/mcimx6x_m4/soc.h @@ -13,6 +13,7 @@ #include "rdc_defs_imx6sx.h" #include "ccm_imx6sx.h" #include "clock_freq.h" +#include "soc_clk_freq.h" #endif /* !_ASMLANGUAGE */ diff --git a/soc/arm/nxp_imx/mcimx6x_m4/soc_clk_freq.c b/soc/arm/nxp_imx/mcimx6x_m4/soc_clk_freq.c new file mode 100644 index 00000000000..f927e0e5557 --- /dev/null +++ b/soc/arm/nxp_imx/mcimx6x_m4/soc_clk_freq.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2021, Antonio Tessarolo + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "soc_clk_freq.h" + +#ifdef CONFIG_PWM_IMX + +uint32_t get_pwm_clock_freq(PWM_Type *base) +{ + uint32_t root; + uint32_t hz; + uint32_t divPerclkPodf, divIpgPodf, divAhbPodf, divPeriphClk2Podf; + + /* Different instance has the same clock root, it's different from i.mx7d. */ + /* Get the clock root according to the mux node of clock tree. */ + if (CCM_GetRootMux(CCM, ccmRootPerclkClkSel) == + ccmRootmuxPerclkClkOsc24m) { + root = ccmRootmuxPerclkClkOsc24m; + hz = 24000000; + divPerclkPodf = CCM_GetRootDivider(CCM, ccmRootPerclkPodf); + divIpgPodf = 0; + divAhbPodf = 0; + divPeriphClk2Podf = 0; + } else if (CCM_GetRootMux(CCM, ccmRootPeriphClkSel) == + ccmRootmuxPeriphClkPrePeriphClkSel) { + root = CCM_GetRootMux(CCM, ccmRootPrePeriphClkSel); + /* Here do not show all the clock root source, + * if user use other clock root source, such as PLL2_PFD2, please + * add it as follows according to the clock tree of CCM in reference manual. + */ + switch (root) { + case ccmRootmuxPrePeriphClkPll2: + hz = CCM_ANALOG_GetPllFreq(CCM_ANALOG, ccmAnalogPllSysControl); + divPerclkPodf = CCM_GetRootDivider(CCM, ccmRootPerclkPodf); + divIpgPodf = CCM_GetRootDivider(CCM, ccmRootIpgPodf); + divAhbPodf = CCM_GetRootDivider(CCM, ccmRootAhbPodf); + divPeriphClk2Podf = 0; + break; + default: + return 0; + } + } else if (CCM_GetRootMux(CCM, ccmRootPeriphClk2Sel) == + ccmRootmuxPeriphClk2OSC24m) { + root = ccmRootmuxPeriphClk2OSC24m; + hz = 24000000; + divPerclkPodf = CCM_GetRootDivider(CCM, ccmRootPerclkPodf); + divIpgPodf = CCM_GetRootDivider(CCM, ccmRootIpgPodf); + divAhbPodf = CCM_GetRootDivider(CCM, ccmRootAhbPodf); + divPeriphClk2Podf = CCM_GetRootDivider(CCM, ccmRootPeriphClk2Podf); + } else { + root = CCM_GetRootMux(CCM, ccmRootPll3SwClkSel); + /* Here do not show all the clock root source, + * if user use other clock root source, such as PLL3_BYP, please + * add it as follows according to the clock tree of CCM in reference manual. + */ + switch (root) { + case ccmRootmuxPll3SwClkPll3: + hz = CCM_ANALOG_GetPllFreq(CCM_ANALOG, ccmAnalogPllUsb1Control); + divPerclkPodf = CCM_GetRootDivider(CCM, ccmRootPerclkPodf); + divIpgPodf = CCM_GetRootDivider(CCM, ccmRootIpgPodf); + divAhbPodf = CCM_GetRootDivider(CCM, ccmRootAhbPodf); + divPeriphClk2Podf = + CCM_GetRootDivider(CCM, ccmRootPeriphClk2Podf); + break; + default: + return 0; + } + } + + return hz / (divPerclkPodf + 1) / (divIpgPodf + 1) / + (divAhbPodf + 1) / (divPeriphClk2Podf + 1); +} + +#endif /* CONFIG_PWM_IMX */ diff --git a/soc/arm/nxp_imx/mcimx6x_m4/soc_clk_freq.h b/soc/arm/nxp_imx/mcimx6x_m4/soc_clk_freq.h new file mode 100644 index 00000000000..73cb0ff0a38 --- /dev/null +++ b/soc/arm/nxp_imx/mcimx6x_m4/soc_clk_freq.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2021, Antonio Tessarolo + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __SOC_CLOCK_FREQ_H__ +#define __SOC_CLOCK_FREQ_H__ + +#include "device_imx.h" +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifdef CONFIG_PWM_IMX +/*! + * @brief Get clock frequency applies to the PWM module + * + * @param base PWM base pointer. + * @return clock frequency (in HZ) applies to the PWM module + */ +uint32_t get_pwm_clock_freq(PWM_Type *base); +#endif /* CONFIG_PWM_IMX */ + +#if defined(__cplusplus) +} +#endif +#endif /* __SOC_CLOCK_FREQ_H__ */