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__ */