The core clk framework is left largely untouched this time around except for

support for the newly ratified DT property 'assigned-clock-rates-u64'. I'm much
 more excited about the support for loading DT overlays from KUnit tests so that
 we can test how the clk framework parses DT nodes during clk registration. The
 clk framework has some places that are highly DeviceTree dependent so this
 charts the path to extend the KUnit tests to cover even more framework code in
 the future. I've got some more tests on the list that use the DT overlay
 support, but they uncovered issues with clk unregistration that I'm still
 working on fixing.
 
 Outside the core, the clk driver update pile is dominated by Qualcomm and
 Renesas SoCs, making it fairly usual. Looking closer, there are fixes for
 things all over the place, like adding missing clk frequencies or moving
 defines for the number of clks out of DT binding headers into the drivers.
 There are even conversions of DT bindings to YAML and migration away from
 strings to describe clk topology. Overall it doesn't look unusual so I expect
 the new drivers to be where we'll have fixes in the coming weeks.
 
 Core:
  - KUnit tests for clk registration and fixed rate basic clk type
  - A couple more devm helpers, one consumer and one provider
  - Support for assigned-clock-rates-u64
 
 New Drivers:
  - Camera, display and GPU clocks on Qualcomm SM4450
  - Camera clocks on Qualcomm SM8150
  - Rockchip rk3576 clks
  - Microchip SAM9X7 clks
  - Renesas RZ/V2H(P) (R9A09G057) clks
 
 Updates:
  - Mark a bunch of struct freq_tbl const to reduce .data usage
  - Add Qualcomm MSM8226 A7PLL and Regera PLL support
  - Fix the Qualcomm Lucid 5LPE PLL configuration sequence to not reuse
    Trion, as they do differ
  - A number of fixes to the Qualcomm SM8550 display clock driver
  - Fold Qualcomm SM8650 display clock driver into SM8550 one
  - Add missing clocks and GDSCs needed for audio on Qualcomm MSM8998
  - Add missing USB MP resets, GPLL9, and QUPv3 DFS to Qualcomm SC8180X
  - Fix sdcc clk frequency tables on Qualcomm SC8180X
  - Drop the Qualcomm SM8150 gcc_cpuss_ahb_clk_src
  - Mark Qualcomm PCIe GDSCs as RET_ON on sm8250 and sm8540 to avoid them
    turning off during suspend
  - Use the HW_CTRL mechanism on Qualcomm SM8550 video clock controller
    GDSCs
  - Get rid of CLK_NR_CLKS defines in Rockchip DT binding headers
  - Some fixes for Rockchip rk3228 and rk3588
  - Exynos850: Add clock for Thermal Management Unit
  - Exynos7885: Fix duplicated ID in the header, add missing TOP PLLs and
    add clocks for USB block in the FSYS clock controller
  - ExynosAutov9: Add DPUM clock controller
  - ExynosAutov920: Add new (first) clock controllers: TOP and PERIC0
    (and a bit more complete bindings)
  - Use clk_hw pointer instead of fw_name for acm_aud_clk[0-1]_sel clocks
    on i.MX8Q as parents in ACM provider
  - Add i.MX95 NETCMIX support to the block control provider
  - Fix parents for ENETx_REF_SEL clocks on i.MX6UL
  - Add USB clocks, resets and power domains on Renesas RZ/G3S
  - Add Generic Timer (GTM), I2C Bus Interface (RIIC), SD/MMC Host
    Interface (SDHI) and Watchdog Timer (WDT) clocks and resets on
    Renesas RZ/V2H
  - Add PCIe, PWM, and CAN-FD clocks on Renesas R-Car V4M
  - Add LCD controller clocks and resets on Renesas RZ/G2UL
  - Add DMA clocks and resets on Renesas RZ/G3S
  - Add fractional multiplication PLL support on Renesas R-Car Gen4
  - Document support for the Renesas RZ/G2M v3.0 (r8a774a3) SoC
  - Support for the Microchip SAM9X7 SoC as follows:
  - Updates for the Microchip PLL drivers
  - DT binding documentation updates (for the new clock driver and for
    the slow clock controller that SAM9X7 is using)
  - A fix for the Microchip SAMA7G5 clock driver to avoid allocating more
    memory than necessary
  - Constify some Amlogic structs
  - Add SM1 eARC clocks for Amlogic
  - Introduce a symbol namespace for Amlogic clock specific symbols
  - Add reset controller support to audiomix block control on i.MX
  - Add CLK_SET_RATE_PARENT flag to all audiomix clocks and to
    i.MX7D lcdif_pixel_src clock
  - Fix parent clocks for earc_phy and audpll on i.MX8MP
  - Fix default parents for enet[12]_ref_sel on i.MX6UL
  - Add ops in composite 8M and 93 that allow no-op on disable
  - Add check for PCC present bit on composite 7ULP register
  - Fix fractional part for fracn-gppll on prepare in i.MX
  - Fix clock tree update for TF-A managed clocks on i.MX8M
  - Drop CLK_SET_PARENT_GATE for DRAM mux on i.MX7D
  - Add the SAI7 IPG clock for i.MX8MN
  - Mark the 'nand_usdhc_bus' clock as non-critical on i.MX8MM
  - Add LVDS bypass clocks on i.MX8QXP
  - Add muxes for MIPI and PHY ref clocks on i.MX
  - Reorder dc0_bypass0_clk, lcd_pxl and dc1_disp clocks on i.MX8QXP
  - Add 1039.5MHz and 800MHz rates to fracn-gppll table on i.MX
  - Add CLK_SET_RATE_PARENT for media_disp pixel clocks on i.MX8QXP
  - Add some module descriptions to the i.MX generic and the
    i.MXRT1050 driver
  - Fix return value for bypass for composite i.MX7ULP
  - Move Mediatek clk bindings to clock/
  - Convert some more clk bindings to dt schema
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEE9L57QeeUxqYDyoaDrQKIl8bklSUFAmbxswcRHHNib3lkQGtl
 cm5lbC5vcmcACgkQrQKIl8bklSXjoQ/9GRwTJsRBHhFKZscwklDGHJiFOowsLnzC
 q+fk0J2in+7rLezNv/5nkANOtm7eicYv5kkiY/OQArHB704neHkdVfXvSuaGMMM5
 SXPLq7YtH/4haOWhs/HYfx551+cWGHv9orTVDJpF8GHQ5t37C1BX4KphLlUcgxFe
 X0ZvbLdecp/VS4BiU+HM2zPM/SLU8V4xNmARUMZhur9QQ1P2n4YY8zGU87bWLaTB
 u1wrwm9LMtq+A+LR6ViMRwLZKYXaR9o+rndbhCVURvYZEmrIB+x5iYS8RPJa2kvy
 utsPOghOP0VRqZLT2VvLmKud7lk2Th1Uzng4xwcPxdDtpo6D5y+18VoA8tSHD2Zr
 uwirN8pGbJm+7Ak9K9I4KcA9/9JgGRMsPBgCqdnvJxFgD1c7kT2/aJ5AEWmG8GBD
 zUtqLzmSSnNfYBxXeWAqdrGNFzYZju53tl0ACI01W3lwUffPoJwnvHAdI4aiWMv1
 WdzABSnieX7YcGJrnGzV7ZaIdGwUUyR9OQ5JEi+ajD+qCbnI+oXJgEa+tHI5/XLY
 3As5WJlktmRkWzyacAPiGKsyYJYLNTy0TGwBw1CKQIrtIwjR/HF5THEr2qcy6cze
 YiT7xAzhHcjUlMjjcDEe6Qg5R9ykvYSrFixRscWXbdehP1GpWJkqdgzc1+aBJWGW
 QLLHSYHPkXo=
 =XmiQ
 -----END PGP SIGNATURE-----

Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux

Pull clk updates from Stephen Boyd:
 "The core clk framework is left largely untouched this time around
  except for support for the newly ratified DT property
  'assigned-clock-rates-u64'.

  I'm much more excited about the support for loading DT overlays from
  KUnit tests so that we can test how the clk framework parses DT nodes
  during clk registration. The clk framework has some places that are
  highly DeviceTree dependent so this charts the path to extend the
  KUnit tests to cover even more framework code in the future. I've got
  some more tests on the list that use the DT overlay support, but they
  uncovered issues with clk unregistration that I'm still working on
  fixing.

  Outside the core, the clk driver update pile is dominated by Qualcomm
  and Renesas SoCs, making it fairly usual. Looking closer, there are
  fixes for things all over the place, like adding missing clk
  frequencies or moving defines for the number of clks out of DT binding
  headers into the drivers. There are even conversions of DT bindings to
  YAML and migration away from strings to describe clk topology. Overall
  it doesn't look unusual so I expect the new drivers to be where we'll
  have fixes in the coming weeks.

  Core:
   - KUnit tests for clk registration and fixed rate basic clk type
   - A couple more devm helpers, one consumer and one provider
   - Support for assigned-clock-rates-u64

  New Drivers:
   - Camera, display and GPU clocks on Qualcomm SM4450
   - Camera clocks on Qualcomm SM8150
   - Rockchip rk3576 clks
   - Microchip SAM9X7 clks
   - Renesas RZ/V2H(P) (R9A09G057) clks

  Updates:
   - Mark a bunch of struct freq_tbl const to reduce .data usage
   - Add Qualcomm MSM8226 A7PLL and Regera PLL support
   - Fix the Qualcomm Lucid 5LPE PLL configuration sequence to not reuse
     Trion, as they do differ
   - A number of fixes to the Qualcomm SM8550 display clock driver
   - Fold Qualcomm SM8650 display clock driver into SM8550 one
   - Add missing clocks and GDSCs needed for audio on Qualcomm MSM8998
   - Add missing USB MP resets, GPLL9, and QUPv3 DFS to Qualcomm SC8180X
   - Fix sdcc clk frequency tables on Qualcomm SC8180X
   - Drop the Qualcomm SM8150 gcc_cpuss_ahb_clk_src
   - Mark Qualcomm PCIe GDSCs as RET_ON on sm8250 and sm8540 to avoid
     them turning off during suspend
   - Use the HW_CTRL mechanism on Qualcomm SM8550 video clock controller
     GDSCs
   - Get rid of CLK_NR_CLKS defines in Rockchip DT binding headers
   - Some fixes for Rockchip rk3228 and rk3588
   - Exynos850: Add clock for Thermal Management Unit
   - Exynos7885: Fix duplicated ID in the header, add missing TOP PLLs
     and add clocks for USB block in the FSYS clock controller
   - ExynosAutov9: Add DPUM clock controller
   - ExynosAutov920: Add new (first) clock controllers: TOP and PERIC0
     (and a bit more complete bindings)
   - Use clk_hw pointer instead of fw_name for acm_aud_clk[0-1]_sel
     clocks on i.MX8Q as parents in ACM provider
   - Add i.MX95 NETCMIX support to the block control provider
   - Fix parents for ENETx_REF_SEL clocks on i.MX6UL
   - Add USB clocks, resets and power domains on Renesas RZ/G3S
   - Add Generic Timer (GTM), I2C Bus Interface (RIIC), SD/MMC Host
     Interface (SDHI) and Watchdog Timer (WDT) clocks and resets on
     Renesas RZ/V2H
   - Add PCIe, PWM, and CAN-FD clocks on Renesas R-Car V4M
   - Add LCD controller clocks and resets on Renesas RZ/G2UL
   - Add DMA clocks and resets on Renesas RZ/G3S
   - Add fractional multiplication PLL support on Renesas R-Car Gen4
   - Document support for the Renesas RZ/G2M v3.0 (r8a774a3) SoC
   - Support for the Microchip SAM9X7 SoC as follows:
   - Updates for the Microchip PLL drivers
   - DT binding documentation updates (for the new clock driver and for
     the slow clock controller that SAM9X7 is using)
   - A fix for the Microchip SAMA7G5 clock driver to avoid allocating
     more memory than necessary
   - Constify some Amlogic structs
   - Add SM1 eARC clocks for Amlogic
   - Introduce a symbol namespace for Amlogic clock specific symbols
   - Add reset controller support to audiomix block control on i.MX
   - Add CLK_SET_RATE_PARENT flag to all audiomix clocks and to i.MX7D
     lcdif_pixel_src clock
   - Fix parent clocks for earc_phy and audpll on i.MX8MP
   - Fix default parents for enet[12]_ref_sel on i.MX6UL
   - Add ops in composite 8M and 93 that allow no-op on disable
   - Add check for PCC present bit on composite 7ULP register
   - Fix fractional part for fracn-gppll on prepare in i.MX
   - Fix clock tree update for TF-A managed clocks on i.MX8M
   - Drop CLK_SET_PARENT_GATE for DRAM mux on i.MX7D
   - Add the SAI7 IPG clock for i.MX8MN
   - Mark the 'nand_usdhc_bus' clock as non-critical on i.MX8MM
   - Add LVDS bypass clocks on i.MX8QXP
   - Add muxes for MIPI and PHY ref clocks on i.MX
   - Reorder dc0_bypass0_clk, lcd_pxl and dc1_disp clocks on i.MX8QXP
   - Add 1039.5MHz and 800MHz rates to fracn-gppll table on i.MX
   - Add CLK_SET_RATE_PARENT for media_disp pixel clocks on i.MX8QXP
   - Add some module descriptions to the i.MX generic and the i.MXRT1050
     driver
   - Fix return value for bypass for composite i.MX7ULP
   - Move Mediatek clk bindings to clock/
   - Convert some more clk bindings to dt schema"

* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (180 commits)
  clk: Switch back to struct platform_driver::remove()
  dt-bindings: clock, reset: fix top-comment indentation rk3576 headers
  clk: rockchip: remove unused mclk_pdm0_p/pdm0_p definitions
  clk: provide devm_clk_get_optional_enabled_with_rate()
  clk: fixed-rate: add devm_clk_hw_register_fixed_rate_parent_data()
  clk: imx6ul: fix clock parent for IMX6UL_CLK_ENETx_REF_SEL
  clk: renesas: r9a09g057: Add clock and reset entries for GTM/RIIC/SDHI/WDT
  clk: renesas: rzv2h: Add support for dynamic switching divider clocks
  clk: renesas: r9a08g045: Add clocks, resets and power domains for USB
  clk: rockchip: fix error for unknown clocks
  clk: rockchip: rk3588: drop unused code
  clk: rockchip: Add clock controller for the RK3576
  clk: rockchip: Add new pll type pll_rk3588_ddr
  dt-bindings: clock, reset: Add support for rk3576
  dt-bindings: clock: rockchip,rk3588-cru: drop unneeded assigned-clocks
  clk: rockchip: rk3588: Fix 32k clock name for pmu_24m_32k_100m_src_p
  clk: imx95: enable the clock of NETCMIX block control
  dt-bindings: clock: add RMII clock selection
  dt-bindings: clock: add i.MX95 NETCMIX block control
  clk: imx: imx8: Use clk_hw pointer for self registered clock in clk_parent_data
  ...
This commit is contained in:
Linus Torvalds 2024-09-23 15:01:48 -07:00
commit 9ab27b0186
423 changed files with 16999 additions and 3450 deletions

View File

@ -0,0 +1,10 @@
.. SPDX-License-Identifier: GPL-2.0
========
Clk API
========
The KUnit clk API is used to test clk providers and clk consumers.
.. kernel-doc:: drivers/clk/clk_kunit_helpers.c
:export:

View File

@ -9,11 +9,17 @@ API Reference
test test
resource resource
functionredirection functionredirection
clk
of
platformdevice
This page documents the KUnit kernel testing API. It is divided into the This page documents the KUnit kernel testing API. It is divided into the
following sections: following sections:
Core KUnit API
==============
Documentation/dev-tools/kunit/api/test.rst Documentation/dev-tools/kunit/api/test.rst
- Documents all of the standard testing API - Documents all of the standard testing API
@ -25,3 +31,18 @@ Documentation/dev-tools/kunit/api/resource.rst
Documentation/dev-tools/kunit/api/functionredirection.rst Documentation/dev-tools/kunit/api/functionredirection.rst
- Documents the KUnit Function Redirection API - Documents the KUnit Function Redirection API
Driver KUnit API
================
Documentation/dev-tools/kunit/api/clk.rst
- Documents the KUnit clk API
Documentation/dev-tools/kunit/api/of.rst
- Documents the KUnit device tree (OF) API
Documentation/dev-tools/kunit/api/platformdevice.rst
- Documents the KUnit platform device API

View File

@ -0,0 +1,13 @@
.. SPDX-License-Identifier: GPL-2.0
====================
Device Tree (OF) API
====================
The KUnit device tree API is used to test device tree (of_*) dependent code.
.. kernel-doc:: include/kunit/of.h
:internal:
.. kernel-doc:: drivers/of/of_kunit_helpers.c
:export:

View File

@ -0,0 +1,10 @@
.. SPDX-License-Identifier: GPL-2.0
===================
Platform Device API
===================
The KUnit platform device API is used to test platform devices.
.. kernel-doc:: lib/kunit/platform.c
:export:

View File

@ -1,24 +0,0 @@
Mediatek bdpsys controller
============================
The Mediatek bdpsys controller provides various clocks to the system.
Required Properties:
- compatible: Should be:
- "mediatek,mt2701-bdpsys", "syscon"
- "mediatek,mt2712-bdpsys", "syscon"
- "mediatek,mt7623-bdpsys", "mediatek,mt2701-bdpsys", "syscon"
- #clock-cells: Must be 1
The bdpsys controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
Example:
bdpsys: clock-controller@1c000000 {
compatible = "mediatek,mt2701-bdpsys", "syscon";
reg = <0 0x1c000000 0 0x1000>;
#clock-cells = <1>;
};

View File

@ -1,24 +0,0 @@
MediaTek CAMSYS controller
============================
The MediaTek camsys controller provides various clocks to the system.
Required Properties:
- compatible: Should be one of:
- "mediatek,mt6765-camsys", "syscon"
- "mediatek,mt6779-camsys", "syscon"
- "mediatek,mt8183-camsys", "syscon"
- #clock-cells: Must be 1
The camsys controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
Example:
camsys: camsys@1a000000 {
compatible = "mediatek,mt8183-camsys", "syscon";
reg = <0 0x1a000000 0 0x1000>;
#clock-cells = <1>;
};

View File

@ -1,30 +0,0 @@
Mediatek imgsys controller
============================
The Mediatek imgsys controller provides various clocks to the system.
Required Properties:
- compatible: Should be one of:
- "mediatek,mt2701-imgsys", "syscon"
- "mediatek,mt2712-imgsys", "syscon"
- "mediatek,mt6765-imgsys", "syscon"
- "mediatek,mt6779-imgsys", "syscon"
- "mediatek,mt6797-imgsys", "syscon"
- "mediatek,mt7623-imgsys", "mediatek,mt2701-imgsys", "syscon"
- "mediatek,mt8167-imgsys", "syscon"
- "mediatek,mt8173-imgsys", "syscon"
- "mediatek,mt8183-imgsys", "syscon"
- #clock-cells: Must be 1
The imgsys controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
Example:
imgsys: clock-controller@15000000 {
compatible = "mediatek,mt8173-imgsys", "syscon";
reg = <0 0x15000000 0 0x1000>;
#clock-cells = <1>;
};

View File

@ -1,22 +0,0 @@
Mediatek ipesys controller
============================
The Mediatek ipesys controller provides various clocks to the system.
Required Properties:
- compatible: Should be one of:
- "mediatek,mt6779-ipesys", "syscon"
- #clock-cells: Must be 1
The ipesys controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
Example:
ipesys: clock-controller@1b000000 {
compatible = "mediatek,mt6779-ipesys", "syscon";
reg = <0 0x1b000000 0 0x1000>;
#clock-cells = <1>;
};

View File

@ -1,43 +0,0 @@
Mediatek IPU controller
============================
The Mediatek ipu controller provides various clocks to the system.
Required Properties:
- compatible: Should be one of:
- "mediatek,mt8183-ipu_conn", "syscon"
- "mediatek,mt8183-ipu_adl", "syscon"
- "mediatek,mt8183-ipu_core0", "syscon"
- "mediatek,mt8183-ipu_core1", "syscon"
- #clock-cells: Must be 1
The ipu controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
Example:
ipu_conn: syscon@19000000 {
compatible = "mediatek,mt8183-ipu_conn", "syscon";
reg = <0 0x19000000 0 0x1000>;
#clock-cells = <1>;
};
ipu_adl: syscon@19010000 {
compatible = "mediatek,mt8183-ipu_adl", "syscon";
reg = <0 0x19010000 0 0x1000>;
#clock-cells = <1>;
};
ipu_core0: syscon@19180000 {
compatible = "mediatek,mt8183-ipu_core0", "syscon";
reg = <0 0x19180000 0 0x1000>;
#clock-cells = <1>;
};
ipu_core1: syscon@19280000 {
compatible = "mediatek,mt8183-ipu_core1", "syscon";
reg = <0 0x19280000 0 0x1000>;
#clock-cells = <1>;
};

View File

@ -1,22 +0,0 @@
Mediatek jpgdecsys controller
============================
The Mediatek jpgdecsys controller provides various clocks to the system.
Required Properties:
- compatible: Should be:
- "mediatek,mt2712-jpgdecsys", "syscon"
- #clock-cells: Must be 1
The jpgdecsys controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
Example:
jpgdecsys: syscon@19000000 {
compatible = "mediatek,mt2712-jpgdecsys", "syscon";
reg = <0 0x19000000 0 0x1000>;
#clock-cells = <1>;
};

View File

@ -1,23 +0,0 @@
Mediatek mcucfg controller
============================
The Mediatek mcucfg controller provides various clocks to the system.
Required Properties:
- compatible: Should be one of:
- "mediatek,mt2712-mcucfg", "syscon"
- "mediatek,mt8183-mcucfg", "syscon"
- #clock-cells: Must be 1
The mcucfg controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
Example:
mcucfg: syscon@10220000 {
compatible = "mediatek,mt2712-mcucfg", "syscon";
reg = <0 0x10220000 0 0x1000>;
#clock-cells = <1>;
};

View File

@ -1,25 +0,0 @@
Mediatek mfgcfg controller
============================
The Mediatek mfgcfg controller provides various clocks to the system.
Required Properties:
- compatible: Should be one of:
- "mediatek,mt2712-mfgcfg", "syscon"
- "mediatek,mt6779-mfgcfg", "syscon"
- "mediatek,mt8167-mfgcfg", "syscon"
- "mediatek,mt8183-mfgcfg", "syscon"
- #clock-cells: Must be 1
The mfgcfg controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
Example:
mfgcfg: syscon@13000000 {
compatible = "mediatek,mt2712-mfgcfg", "syscon";
reg = <0 0x13000000 0 0x1000>;
#clock-cells = <1>;
};

View File

@ -1,28 +0,0 @@
Mediatek mipi0a (mipi_rx_ana_csi0a) controller
============================
The Mediatek mipi0a controller provides various clocks
to the system.
Required Properties:
- compatible: Should be one of:
- "mediatek,mt6765-mipi0a", "syscon"
- #clock-cells: Must be 1
The mipi0a controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
The mipi0a controller also uses the common power domain from
Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
The available power domains are defined in dt-bindings/power/mt*-power.h.
Example:
mipi0a: clock-controller@11c10000 {
compatible = "mediatek,mt6765-mipi0a", "syscon";
reg = <0 0x11c10000 0 0x1000>;
power-domains = <&scpsys MT6765_POWER_DOMAIN_CAM>;
#clock-cells = <1>;
};

View File

@ -1,27 +0,0 @@
Mediatek vcodecsys controller
============================
The Mediatek vcodecsys controller provides various clocks to the system.
Required Properties:
- compatible: Should be one of:
- "mediatek,mt6765-vcodecsys", "syscon"
- #clock-cells: Must be 1
The vcodecsys controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
The vcodecsys controller also uses the common power domain from
Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
The available power domains are defined in dt-bindings/power/mt*-power.h.
Example:
venc_gcon: clock-controller@17000000 {
compatible = "mediatek,mt6765-vcodecsys", "syscon";
reg = <0 0x17000000 0 0x10000>;
power-domains = <&scpsys MT6765_POWER_DOMAIN_VCODEC>;
#clock-cells = <1>;
};

View File

@ -1,29 +0,0 @@
Mediatek vdecsys controller
============================
The Mediatek vdecsys controller provides various clocks to the system.
Required Properties:
- compatible: Should be one of:
- "mediatek,mt2701-vdecsys", "syscon"
- "mediatek,mt2712-vdecsys", "syscon"
- "mediatek,mt6779-vdecsys", "syscon"
- "mediatek,mt6797-vdecsys", "syscon"
- "mediatek,mt7623-vdecsys", "mediatek,mt2701-vdecsys", "syscon"
- "mediatek,mt8167-vdecsys", "syscon"
- "mediatek,mt8173-vdecsys", "syscon"
- "mediatek,mt8183-vdecsys", "syscon"
- #clock-cells: Must be 1
The vdecsys controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
Example:
vdecsys: clock-controller@16000000 {
compatible = "mediatek,mt8173-vdecsys", "syscon";
reg = <0 0x16000000 0 0x1000>;
#clock-cells = <1>;
};

View File

@ -1,22 +0,0 @@
Mediatek vencltsys controller
============================
The Mediatek vencltsys controller provides various clocks to the system.
Required Properties:
- compatible: Should be:
- "mediatek,mt8173-vencltsys", "syscon"
- #clock-cells: Must be 1
The vencltsys controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
Example:
vencltsys: clock-controller@19000000 {
compatible = "mediatek,mt8173-vencltsys", "syscon";
reg = <0 0x19000000 0 0x1000>;
#clock-cells = <1>;
};

View File

@ -1,26 +0,0 @@
Mediatek vencsys controller
============================
The Mediatek vencsys controller provides various clocks to the system.
Required Properties:
- compatible: Should be one of:
- "mediatek,mt2712-vencsys", "syscon"
- "mediatek,mt6779-vencsys", "syscon"
- "mediatek,mt6797-vencsys", "syscon"
- "mediatek,mt8173-vencsys", "syscon"
- "mediatek,mt8183-vencsys", "syscon"
- #clock-cells: Must be 1
The vencsys controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
Example:
vencsys: clock-controller@18000000 {
compatible = "mediatek,mt8173-vencsys", "syscon";
reg = <0 0x18000000 0 0x1000>;
#clock-cells = <1>;
};

View File

@ -42,6 +42,7 @@ properties:
- atmel,sama5d3-pmc - atmel,sama5d3-pmc
- atmel,sama5d4-pmc - atmel,sama5d4-pmc
- microchip,sam9x60-pmc - microchip,sam9x60-pmc
- microchip,sam9x7-pmc
- microchip,sama7g5-pmc - microchip,sama7g5-pmc
- const: syscon - const: syscon
@ -88,6 +89,7 @@ allOf:
contains: contains:
enum: enum:
- microchip,sam9x60-pmc - microchip,sam9x60-pmc
- microchip,sam9x7-pmc
- microchip,sama7g5-pmc - microchip,sama7g5-pmc
then: then:
properties: properties:

View File

@ -18,7 +18,9 @@ properties:
- atmel,sama5d4-sckc - atmel,sama5d4-sckc
- microchip,sam9x60-sckc - microchip,sam9x60-sckc
- items: - items:
- const: microchip,sama7g5-sckc - enum:
- microchip,sam9x7-sckc
- microchip,sama7g5-sckc
- const: microchip,sam9x60-sckc - const: microchip,sam9x60-sckc
reg: reg:

View File

@ -134,9 +134,13 @@ properties:
"#reset-cells": "#reset-cells":
const: 1 const: 1
clocks: true clocks:
minItems: 3
maxItems: 4
clock-names: true clock-names:
minItems: 3
maxItems: 4
additionalProperties: false additionalProperties: false

View File

@ -67,9 +67,9 @@ properties:
minItems: 1 minItems: 1
maxItems: 19 maxItems: 19
clocks: true clocks:
assigned-clocks: true minItems: 1
assigned-clock-parents: true maxItems: 19
additionalProperties: false additionalProperties: false

View File

@ -44,6 +44,9 @@ properties:
ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mp-clock.h ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mp-clock.h
for the full list of i.MX8MP IMX8MP_CLK_AUDIOMIX_ clock IDs. for the full list of i.MX8MP IMX8MP_CLK_AUDIOMIX_ clock IDs.
'#reset-cells':
const: 1
required: required:
- compatible - compatible
- reg - reg

View File

@ -35,7 +35,7 @@ properties:
- mediatek,mt2701-apmixedsys - mediatek,mt2701-apmixedsys
- mediatek,mt2712-apmixedsys - mediatek,mt2712-apmixedsys
- mediatek,mt6765-apmixedsys - mediatek,mt6765-apmixedsys
- mediatek,mt6779-apmixedsys - mediatek,mt6779-apmixed
- mediatek,mt6795-apmixedsys - mediatek,mt6795-apmixedsys
- mediatek,mt7629-apmixedsys - mediatek,mt7629-apmixedsys
- mediatek,mt8167-apmixedsys - mediatek,mt8167-apmixedsys

View File

@ -1,7 +1,7 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2 %YAML 1.2
--- ---
$id: http://devicetree.org/schemas/arm/mediatek/mediatek,infracfg.yaml# $id: http://devicetree.org/schemas/clock/mediatek,infracfg.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek Infrastructure System Configuration Controller title: MediaTek Infrastructure System Configuration Controller

View File

@ -1,7 +1,7 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2 %YAML 1.2
--- ---
$id: http://devicetree.org/schemas/arm/mediatek/mediatek,mt8186-clock.yaml# $id: http://devicetree.org/schemas/clock/mediatek,mt8186-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek Functional Clock Controller for MT8186 title: MediaTek Functional Clock Controller for MT8186

View File

@ -1,7 +1,7 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2 %YAML 1.2
--- ---
$id: http://devicetree.org/schemas/arm/mediatek/mediatek,mt8186-sys-clock.yaml# $id: http://devicetree.org/schemas/clock/mediatek,mt8186-sys-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek System Clock Controller for MT8186 title: MediaTek System Clock Controller for MT8186

View File

@ -1,7 +1,7 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2 %YAML 1.2
--- ---
$id: http://devicetree.org/schemas/arm/mediatek/mediatek,mt8192-clock.yaml# $id: http://devicetree.org/schemas/clock/mediatek,mt8192-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek Functional Clock Controller for MT8192 title: MediaTek Functional Clock Controller for MT8192

View File

@ -1,7 +1,7 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2 %YAML 1.2
--- ---
$id: http://devicetree.org/schemas/arm/mediatek/mediatek,mt8192-sys-clock.yaml# $id: http://devicetree.org/schemas/clock/mediatek,mt8192-sys-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek System Clock Controller for MT8192 title: MediaTek System Clock Controller for MT8192

View File

@ -1,7 +1,7 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2 %YAML 1.2
--- ---
$id: http://devicetree.org/schemas/arm/mediatek/mediatek,mt8195-clock.yaml# $id: http://devicetree.org/schemas/clock/mediatek,mt8195-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek Functional Clock Controller for MT8195 title: MediaTek Functional Clock Controller for MT8195

View File

@ -1,7 +1,7 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2 %YAML 1.2
--- ---
$id: http://devicetree.org/schemas/arm/mediatek/mediatek,mt8195-sys-clock.yaml# $id: http://devicetree.org/schemas/clock/mediatek,mt8195-sys-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek System Clock Controller for MT8195 title: MediaTek System Clock Controller for MT8195

View File

@ -1,7 +1,7 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2 %YAML 1.2
--- ---
$id: http://devicetree.org/schemas/arm/mediatek/mediatek,pericfg.yaml# $id: http://devicetree.org/schemas/clock/mediatek,pericfg.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek Peripheral Configuration Controller title: MediaTek Peripheral Configuration Controller

View File

@ -0,0 +1,93 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/mediatek,syscon.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek Clock controller syscon's
maintainers:
- Matthias Brugger <matthias.bgg@gmail.com>
- AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
description:
The MediaTek clock controller syscon's provide various clocks to the system.
properties:
compatible:
oneOf:
- items:
- enum:
- mediatek,mt2701-bdpsys
- mediatek,mt2701-imgsys
- mediatek,mt2701-vdecsys
- mediatek,mt2712-bdpsys
- mediatek,mt2712-imgsys
- mediatek,mt2712-jpgdecsys
- mediatek,mt2712-mcucfg
- mediatek,mt2712-mfgcfg
- mediatek,mt2712-vdecsys
- mediatek,mt2712-vencsys
- mediatek,mt6765-camsys
- mediatek,mt6765-imgsys
- mediatek,mt6765-mipi0a
- mediatek,mt6765-vcodecsys
- mediatek,mt6779-camsys
- mediatek,mt6779-imgsys
- mediatek,mt6779-ipesys
- mediatek,mt6779-mfgcfg
- mediatek,mt6779-vdecsys
- mediatek,mt6779-vencsys
- mediatek,mt6797-imgsys
- mediatek,mt6797-vdecsys
- mediatek,mt6797-vencsys
- mediatek,mt8167-imgsys
- mediatek,mt8167-mfgcfg
- mediatek,mt8167-vdecsys
- mediatek,mt8173-imgsys
- mediatek,mt8173-vdecsys
- mediatek,mt8173-vencltsys
- mediatek,mt8173-vencsys
- mediatek,mt8183-camsys
- mediatek,mt8183-imgsys
- mediatek,mt8183-ipu_conn
- mediatek,mt8183-ipu_adl
- mediatek,mt8183-ipu_core0
- mediatek,mt8183-ipu_core1
- mediatek,mt8183-mcucfg
- mediatek,mt8183-mfgcfg
- mediatek,mt8183-vdecsys
- mediatek,mt8183-vencsys
- const: syscon
- items:
- const: mediatek,mt7623-bdpsys
- const: mediatek,mt2701-bdpsys
- const: syscon
- items:
- const: mediatek,mt7623-imgsys
- const: mediatek,mt2701-imgsys
- const: syscon
- items:
- const: mediatek,mt7623-vdecsys
- const: mediatek,mt2701-vdecsys
- const: syscon
reg:
maxItems: 1
'#clock-cells':
const: 1
required:
- compatible
- '#clock-cells'
additionalProperties: false
examples:
- |
clock-controller@11220000 {
compatible = "mediatek,mt2701-bdpsys", "syscon";
reg = <0x11220000 0x2000>;
#clock-cells = <1>;
};

View File

@ -16,6 +16,7 @@ properties:
- nxp,imx95-lvds-csr - nxp,imx95-lvds-csr
- nxp,imx95-display-csr - nxp,imx95-display-csr
- nxp,imx95-camera-csr - nxp,imx95-camera-csr
- nxp,imx95-netcmix-blk-ctrl
- nxp,imx95-vpu-csr - nxp,imx95-vpu-csr
- const: syscon - const: syscon

View File

@ -1,30 +0,0 @@
NXP LPC32xx Clock Controller
Required properties:
- compatible: should be "nxp,lpc3220-clk"
- reg: should contain clock controller registers location and length
- #clock-cells: must be 1, the cell holds id of a clock provided by the
clock controller
- clocks: phandles of external oscillators, the list must contain one
32768 Hz oscillator and may have one optional high frequency oscillator
- clock-names: list of external oscillator clock names, must contain
"xtal_32k" and may have optional "xtal"
Examples:
/* System Control Block */
scb {
compatible = "simple-bus";
ranges = <0x0 0x040004000 0x00001000>;
#address-cells = <1>;
#size-cells = <1>;
clk: clock-controller@0 {
compatible = "nxp,lpc3220-clk";
reg = <0x00 0x114>;
#clock-cells = <1>;
clocks = <&xtal_32k>, <&xtal>;
clock-names = "xtal_32k", "xtal";
};
};

View File

@ -0,0 +1,51 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/nxp,lpc3220-clk.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP LPC32xx Clock Controller
maintainers:
- Animesh Agarwal <animeshagarwal28@gmail.com>
properties:
compatible:
const: nxp,lpc3220-clk
reg:
maxItems: 1
'#clock-cells':
const: 1
clocks:
minItems: 1
items:
- description: External 32768 Hz oscillator.
- description: Optional high frequency oscillator.
clock-names:
minItems: 1
items:
- const: xtal_32k
- const: xtal
required:
- compatible
- reg
- '#clock-cells'
- clocks
- clock-names
additionalProperties: false
examples:
- |
clock-controller@0 {
compatible = "nxp,lpc3220-clk";
reg = <0x00 0x114>;
#clock-cells = <1>;
clocks = <&xtal_32k>, <&xtal>;
clock-names = "xtal_32k", "xtal";
};

View File

@ -1,22 +0,0 @@
NXP LPC32xx USB Clock Controller
Required properties:
- compatible: should be "nxp,lpc3220-usb-clk"
- reg: should contain clock controller registers location and length
- #clock-cells: must be 1, the cell holds id of a clock provided by the
USB clock controller
Examples:
usb {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
ranges = <0x0 0x31020000 0x00001000>;
usbclk: clock-controller@f00 {
compatible = "nxp,lpc3220-usb-clk";
reg = <0xf00 0x100>;
#clock-cells = <1>;
};
};

View File

@ -0,0 +1,35 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/nxp,lpc3220-usb-clk.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP LPC32xx USB Clock Controller
maintainers:
- Animesh Agarwal <animeshagarwal28@gmail.com>
properties:
compatible:
const: nxp,lpc3220-usb-clk
reg:
maxItems: 1
'#clock-cells':
const: 1
required:
- compatible
- reg
- '#clock-cells'
additionalProperties: false
examples:
- |
clock-controller@f00 {
compatible = "nxp,lpc3220-usb-clk";
reg = <0xf00 0x100>;
#clock-cells = <1>;
};

View File

@ -21,6 +21,7 @@ properties:
- qcom,ipq6018-a53pll - qcom,ipq6018-a53pll
- qcom,ipq8074-a53pll - qcom,ipq8074-a53pll
- qcom,ipq9574-a73pll - qcom,ipq9574-a73pll
- qcom,msm8226-a7pll
- qcom,msm8916-a53pll - qcom,msm8916-a53pll
- qcom,msm8939-a53pll - qcom,msm8939-a53pll
@ -40,6 +41,9 @@ properties:
operating-points-v2: true operating-points-v2: true
opp-table:
type: object
required: required:
- compatible - compatible
- reg - reg

View File

@ -0,0 +1,47 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/qcom,qcs404-turingcc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Turing Clock & Reset Controller on QCS404
maintainers:
- Bjorn Andersson <andersson@kernel.org>
properties:
compatible:
const: qcom,qcs404-turingcc
reg:
maxItems: 1
clocks:
maxItems: 1
'#clock-cells':
const: 1
'#reset-cells':
const: 1
required:
- compatible
- reg
- clocks
- '#clock-cells'
- '#reset-cells'
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,gcc-qcs404.h>
clock-controller@800000 {
compatible = "qcom,qcs404-turingcc";
reg = <0x00800000 0x30000>;
clocks = <&gcc GCC_CDSP_CFG_AHB_CLK>;
#clock-cells = <1>;
#reset-cells = <1>;
};

View File

@ -18,9 +18,16 @@ description: |
properties: properties:
compatible: compatible:
enum: oneOf:
- qcom,sc8280xp-lpassaudiocc - enum:
- qcom,sc8280xp-lpasscc - qcom,sc8280xp-lpassaudiocc
- qcom,sc8280xp-lpasscc
- items:
- const: qcom,x1e80100-lpassaudiocc
- const: qcom,sc8280xp-lpassaudiocc
- items:
- const: qcom,x1e80100-lpasscc
- const: qcom,sc8280xp-lpasscc
reg: reg:
maxItems: 1 maxItems: 1

View File

@ -21,9 +21,6 @@ description: |
include/dt-bindings/clock/qcom,sm8650-camcc.h include/dt-bindings/clock/qcom,sm8650-camcc.h
include/dt-bindings/clock/qcom,x1e80100-camcc.h include/dt-bindings/clock/qcom,x1e80100-camcc.h
allOf:
- $ref: qcom,gcc.yaml#
properties: properties:
compatible: compatible:
enum: enum:
@ -57,7 +54,21 @@ required:
- compatible - compatible
- clocks - clocks
- power-domains - power-domains
- required-opps
allOf:
- $ref: qcom,gcc.yaml#
- if:
properties:
compatible:
contains:
enum:
- qcom,sc8280xp-camcc
- qcom,sm8450-camcc
- qcom,sm8550-camcc
- qcom,x1e80100-camcc
then:
required:
- required-opps
unevaluatedProperties: false unevaluatedProperties: false

View File

@ -44,11 +44,20 @@ required:
- compatible - compatible
- clocks - clocks
- power-domains - power-domains
- required-opps
- '#power-domain-cells' - '#power-domain-cells'
allOf: allOf:
- $ref: qcom,gcc.yaml# - $ref: qcom,gcc.yaml#
- if:
properties:
compatible:
contains:
enum:
- qcom,sm8450-videocc
- qcom,sm8550-videocc
then:
required:
- required-opps
unevaluatedProperties: false unevaluatedProperties: false

View File

@ -1,19 +0,0 @@
Qualcomm Turing Clock & Reset Controller Binding
------------------------------------------------
Required properties :
- compatible: shall contain "qcom,qcs404-turingcc".
- reg: shall contain base register location and length.
- clocks: ahb clock for the TuringCC
- #clock-cells: from common clock binding, shall contain 1.
- #reset-cells: from common reset binding, shall contain 1.
Example:
turingcc: clock-controller@800000 {
compatible = "qcom,qcs404-turingcc";
reg = <0x00800000 0x30000>;
clocks = <&gcc GCC_CDSP_CFG_AHB_CLK>;
#clock-cells = <1>;
#reset-cells = <1>;
};

View File

@ -32,12 +32,16 @@ properties:
reg: reg:
maxItems: 1 maxItems: 1
clocks: true clocks:
minItems: 1
maxItems: 3
'#clock-cells': '#clock-cells':
const: 1 const: 1
clock-output-names: true clock-output-names:
minItems: 3
maxItems: 17
renesas,mode: renesas,mode:
description: Board-specific settings of the MD_CK* bits on R-Mobile A1 description: Board-specific settings of the MD_CK* bits on R-Mobile A1

View File

@ -31,6 +31,7 @@ properties:
- renesas,r8a7745-cpg-mssr # RZ/G1E - renesas,r8a7745-cpg-mssr # RZ/G1E
- renesas,r8a77470-cpg-mssr # RZ/G1C - renesas,r8a77470-cpg-mssr # RZ/G1C
- renesas,r8a774a1-cpg-mssr # RZ/G2M - renesas,r8a774a1-cpg-mssr # RZ/G2M
- renesas,r8a774a3-cpg-mssr # RZ/G2M v3.0
- renesas,r8a774b1-cpg-mssr # RZ/G2N - renesas,r8a774b1-cpg-mssr # RZ/G2N
- renesas,r8a774c0-cpg-mssr # RZ/G2E - renesas,r8a774c0-cpg-mssr # RZ/G2E
- renesas,r8a774e1-cpg-mssr # RZ/G2H - renesas,r8a774e1-cpg-mssr # RZ/G2H

View File

@ -0,0 +1,56 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/rockchip,rk3576-cru.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Rockchip rk3576 Family Clock and Reset Control Module
maintainers:
- Elaine Zhang <zhangqing@rock-chips.com>
- Heiko Stuebner <heiko@sntech.de>
- Detlev Casanova <detlev.casanova@collabora.com>
description:
The RK3576 clock controller generates the clock and also implements a reset
controller for SoC peripherals. For example it provides SCLK_UART2 and
PCLK_UART2, as well as SRST_P_UART2 and SRST_S_UART2 for the second UART
module.
properties:
compatible:
const: rockchip,rk3576-cru
reg:
maxItems: 1
"#clock-cells":
const: 1
"#reset-cells":
const: 1
clocks:
maxItems: 2
clock-names:
items:
- const: xin24m
- const: xin32k
required:
- compatible
- reg
- "#clock-cells"
- "#reset-cells"
additionalProperties: false
examples:
- |
clock-controller@27200000 {
compatible = "rockchip,rk3576-cru";
reg = <0xfd7c0000 0x5c000>;
#clock-cells = <1>;
#reset-cells = <1>;
};

View File

@ -42,10 +42,6 @@ properties:
- const: xin24m - const: xin24m
- const: xin32k - const: xin32k
assigned-clocks: true
assigned-clock-rates: true
rockchip,grf: rockchip,grf:
$ref: /schemas/types.yaml#/definitions/phandle $ref: /schemas/types.yaml#/definitions/phandle
description: > description: >

View File

@ -60,8 +60,14 @@ properties:
- st,stm32mp1-rcc - st,stm32mp1-rcc
- st,stm32mp13-rcc - st,stm32mp13-rcc
- const: syscon - const: syscon
clocks: true
clock-names: true clocks:
minItems: 1
maxItems: 5
clock-names:
minItems: 1
maxItems: 5
reg: reg:
maxItems: 1 maxItems: 1

View File

@ -164,6 +164,7 @@ allOf:
contains: contains:
enum: enum:
- qcom,ipq4019-dwc3 - qcom,ipq4019-dwc3
- qcom,ipq5332-dwc3
then: then:
properties: properties:
clocks: clocks:
@ -267,7 +268,6 @@ allOf:
contains: contains:
enum: enum:
- qcom,ipq5018-dwc3 - qcom,ipq5018-dwc3
- qcom,ipq5332-dwc3
- qcom,msm8994-dwc3 - qcom,msm8994-dwc3
- qcom,qcs404-dwc3 - qcom,qcs404-dwc3
then: then:

View File

@ -1478,6 +1478,8 @@ patternProperties:
description: Terasic Inc. description: Terasic Inc.
"^tesla,.*": "^tesla,.*":
description: Tesla, Inc. description: Tesla, Inc.
"^test,.*":
description: Reserved for use by tests. For example, KUnit.
"^tfc,.*": "^tfc,.*":
description: Three Five Corp description: Three Five Corp
"^thead,.*": "^thead,.*":

View File

@ -393,6 +393,7 @@ bool device_is_bound(struct device *dev)
{ {
return dev->p && klist_node_attached(&dev->p->knode_driver); return dev->p && klist_node_attached(&dev->p->knode_driver);
} }
EXPORT_SYMBOL_GPL(device_is_bound);
static void driver_bound(struct device *dev) static void driver_bound(struct device *dev)
{ {

View File

@ -1,6 +1,8 @@
CONFIG_KUNIT=y CONFIG_KUNIT=y
CONFIG_OF=y
CONFIG_COMMON_CLK=y CONFIG_COMMON_CLK=y
CONFIG_CLK_KUNIT_TEST=y CONFIG_CLK_KUNIT_TEST=y
CONFIG_CLK_FIXED_RATE_KUNIT_TEST=y
CONFIG_CLK_GATE_KUNIT_TEST=y CONFIG_CLK_GATE_KUNIT_TEST=y
CONFIG_CLK_FD_KUNIT_TEST=y CONFIG_CLK_FD_KUNIT_TEST=y
CONFIG_UML_PCI_OVER_VIRTIO=n CONFIG_UML_PCI_OVER_VIRTIO=n

View File

@ -509,9 +509,20 @@ config CLK_KUNIT_TEST
tristate "Basic Clock Framework Kunit Tests" if !KUNIT_ALL_TESTS tristate "Basic Clock Framework Kunit Tests" if !KUNIT_ALL_TESTS
depends on KUNIT depends on KUNIT
default KUNIT_ALL_TESTS default KUNIT_ALL_TESTS
select OF_OVERLAY if OF
select DTC
help help
Kunit tests for the common clock framework. Kunit tests for the common clock framework.
config CLK_FIXED_RATE_KUNIT_TEST
tristate "Basic fixed rate clk type KUnit test" if !KUNIT_ALL_TESTS
depends on KUNIT
default KUNIT_ALL_TESTS
select OF_OVERLAY if OF
select DTC
help
KUnit tests for the basic fixed rate clk type.
config CLK_GATE_KUNIT_TEST config CLK_GATE_KUNIT_TEST
tristate "Basic gate type Kunit test" if !KUNIT_ALL_TESTS tristate "Basic gate type Kunit test" if !KUNIT_ALL_TESTS
depends on KUNIT depends on KUNIT

View File

@ -2,10 +2,14 @@
# common clock types # common clock types
obj-$(CONFIG_HAVE_CLK) += clk-devres.o clk-bulk.o clkdev.o obj-$(CONFIG_HAVE_CLK) += clk-devres.o clk-bulk.o clkdev.o
obj-$(CONFIG_COMMON_CLK) += clk.o obj-$(CONFIG_COMMON_CLK) += clk.o
obj-$(CONFIG_CLK_KUNIT_TEST) += clk_test.o obj-$(CONFIG_CLK_KUNIT_TEST) += clk-test.o
clk-test-y := clk_test.o \
kunit_clk_parent_data_test.dtbo.o
obj-$(CONFIG_COMMON_CLK) += clk-divider.o obj-$(CONFIG_COMMON_CLK) += clk-divider.o
obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o
obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o
obj-$(CONFIG_CLK_FIXED_RATE_KUNIT_TEST) += clk-fixed-rate-test.o
clk-fixed-rate-test-y := clk-fixed-rate_test.o kunit_clk_fixed_rate_test.dtbo.o
obj-$(CONFIG_COMMON_CLK) += clk-gate.o obj-$(CONFIG_COMMON_CLK) += clk-gate.o
obj-$(CONFIG_CLK_GATE_KUNIT_TEST) += clk-gate_test.o obj-$(CONFIG_CLK_GATE_KUNIT_TEST) += clk-gate_test.o
obj-$(CONFIG_COMMON_CLK) += clk-multiplier.o obj-$(CONFIG_COMMON_CLK) += clk-multiplier.o
@ -18,6 +22,11 @@ ifeq ($(CONFIG_OF), y)
obj-$(CONFIG_COMMON_CLK) += clk-conf.o obj-$(CONFIG_COMMON_CLK) += clk-conf.o
endif endif
# KUnit specific helpers
ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_KUNIT) += clk_kunit_helpers.o
endif
# hardware specific clock types # hardware specific clock types
# please keep this section sorted lexicographically by file path name # please keep this section sorted lexicographically by file path name
obj-$(CONFIG_COMMON_CLK_APPLE_NCO) += clk-apple-nco.o obj-$(CONFIG_COMMON_CLK_APPLE_NCO) += clk-apple-nco.o

View File

@ -20,6 +20,7 @@ obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o dt-compat.
obj-$(CONFIG_SOC_AT91SAM9) += at91sam9g45.o dt-compat.o obj-$(CONFIG_SOC_AT91SAM9) += at91sam9g45.o dt-compat.o
obj-$(CONFIG_SOC_AT91SAM9) += at91sam9n12.o at91sam9x5.o dt-compat.o obj-$(CONFIG_SOC_AT91SAM9) += at91sam9n12.o at91sam9x5.o dt-compat.o
obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o
obj-$(CONFIG_SOC_SAM9X7) += sam9x7.o
obj-$(CONFIG_SOC_SAMA5D3) += sama5d3.o dt-compat.o obj-$(CONFIG_SOC_SAMA5D3) += sama5d3.o dt-compat.o
obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o dt-compat.o obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o dt-compat.o
obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o dt-compat.o obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o dt-compat.o

View File

@ -23,9 +23,6 @@
#define UPLL_DIV 2 #define UPLL_DIV 2
#define PLL_MUL_MAX (FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1) #define PLL_MUL_MAX (FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1)
#define FCORE_MIN (600000000)
#define FCORE_MAX (1200000000)
#define PLL_MAX_ID 7 #define PLL_MAX_ID 7
struct sam9x60_pll_core { struct sam9x60_pll_core {
@ -76,9 +73,15 @@ static unsigned long sam9x60_frac_pll_recalc_rate(struct clk_hw *hw,
{ {
struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw); struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
struct sam9x60_frac *frac = to_sam9x60_frac(core); struct sam9x60_frac *frac = to_sam9x60_frac(core);
unsigned long freq;
return parent_rate * (frac->mul + 1) + freq = parent_rate * (frac->mul + 1) +
DIV_ROUND_CLOSEST_ULL((u64)parent_rate * frac->frac, (1 << 22)); DIV_ROUND_CLOSEST_ULL((u64)parent_rate * frac->frac, (1 << 22));
if (core->layout->div2)
freq >>= 1;
return freq;
} }
static int sam9x60_frac_pll_set(struct sam9x60_pll_core *core) static int sam9x60_frac_pll_set(struct sam9x60_pll_core *core)
@ -194,7 +197,8 @@ static long sam9x60_frac_pll_compute_mul_frac(struct sam9x60_pll_core *core,
unsigned long nmul = 0; unsigned long nmul = 0;
unsigned long nfrac = 0; unsigned long nfrac = 0;
if (rate < FCORE_MIN || rate > FCORE_MAX) if (rate < core->characteristics->core_output[0].min ||
rate > core->characteristics->core_output[0].max)
return -ERANGE; return -ERANGE;
/* /*
@ -214,7 +218,8 @@ static long sam9x60_frac_pll_compute_mul_frac(struct sam9x60_pll_core *core,
} }
/* Check if resulted rate is a valid. */ /* Check if resulted rate is a valid. */
if (tmprate < FCORE_MIN || tmprate > FCORE_MAX) if (tmprate < core->characteristics->core_output[0].min ||
tmprate > core->characteristics->core_output[0].max)
return -ERANGE; return -ERANGE;
if (update) { if (update) {
@ -433,6 +438,12 @@ static unsigned long sam9x60_div_pll_recalc_rate(struct clk_hw *hw,
return DIV_ROUND_CLOSEST_ULL(parent_rate, (div->div + 1)); return DIV_ROUND_CLOSEST_ULL(parent_rate, (div->div + 1));
} }
static unsigned long sam9x60_fixed_div_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
return parent_rate >> 1;
}
static long sam9x60_div_pll_compute_div(struct sam9x60_pll_core *core, static long sam9x60_div_pll_compute_div(struct sam9x60_pll_core *core,
unsigned long *parent_rate, unsigned long *parent_rate,
unsigned long rate) unsigned long rate)
@ -607,6 +618,16 @@ static const struct clk_ops sam9x60_div_pll_ops_chg = {
.restore_context = sam9x60_div_pll_restore_context, .restore_context = sam9x60_div_pll_restore_context,
}; };
static const struct clk_ops sam9x60_fixed_div_pll_ops = {
.prepare = sam9x60_div_pll_prepare,
.unprepare = sam9x60_div_pll_unprepare,
.is_prepared = sam9x60_div_pll_is_prepared,
.recalc_rate = sam9x60_fixed_div_pll_recalc_rate,
.round_rate = sam9x60_div_pll_round_rate,
.save_context = sam9x60_div_pll_save_context,
.restore_context = sam9x60_div_pll_restore_context,
};
struct clk_hw * __init struct clk_hw * __init
sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock, sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
const char *name, const char *parent_name, const char *name, const char *parent_name,
@ -669,7 +690,8 @@ sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
goto free; goto free;
} }
ret = sam9x60_frac_pll_compute_mul_frac(&frac->core, FCORE_MIN, ret = sam9x60_frac_pll_compute_mul_frac(&frac->core,
characteristics->core_output[0].min,
parent_rate, true); parent_rate, true);
if (ret < 0) { if (ret < 0) {
hw = ERR_PTR(ret); hw = ERR_PTR(ret);
@ -725,10 +747,14 @@ sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock,
else else
init.parent_names = &parent_name; init.parent_names = &parent_name;
init.num_parents = 1; init.num_parents = 1;
if (flags & CLK_SET_RATE_GATE)
if (layout->div2)
init.ops = &sam9x60_fixed_div_pll_ops;
else if (flags & CLK_SET_RATE_GATE)
init.ops = &sam9x60_div_pll_ops; init.ops = &sam9x60_div_pll_ops;
else else
init.ops = &sam9x60_div_pll_ops_chg; init.ops = &sam9x60_div_pll_ops_chg;
init.flags = flags; init.flags = flags;
div->core.id = id; div->core.id = id;

View File

@ -563,9 +563,10 @@ of_at91_clk_pll_get_characteristics(struct device_node *np)
if (num_cells < 2 || num_cells > 4) if (num_cells < 2 || num_cells > 4)
return NULL; return NULL;
if (!of_get_property(np, "atmel,pll-clk-output-ranges", &tmp)) num_output = of_property_count_u32_elems(np, "atmel,pll-clk-output-ranges");
if (num_output <= 0)
return NULL; return NULL;
num_output = tmp / (sizeof(u32) * num_cells); num_output /= num_cells;
characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL); characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL);
if (!characteristics) if (!characteristics)

View File

@ -64,6 +64,7 @@ struct clk_pll_layout {
u8 frac_shift; u8 frac_shift;
u8 div_shift; u8 div_shift;
u8 endiv_shift; u8 endiv_shift;
u8 div2;
}; };
extern const struct clk_pll_layout at91rm9200_pll_layout; extern const struct clk_pll_layout at91rm9200_pll_layout;
@ -75,6 +76,7 @@ struct clk_pll_characteristics {
struct clk_range input; struct clk_range input;
int num_output; int num_output;
const struct clk_range *output; const struct clk_range *output;
const struct clk_range *core_output;
u16 *icpll; u16 *icpll;
u8 *out; u8 *out;
u8 upll : 1; u8 upll : 1;
@ -119,6 +121,22 @@ struct at91_clk_pms {
#define ndck(a, s) (a[s - 1].id + 1) #define ndck(a, s) (a[s - 1].id + 1)
#define nck(a) (a[ARRAY_SIZE(a) - 1].id + 1) #define nck(a) (a[ARRAY_SIZE(a) - 1].id + 1)
#define PMC_INIT_TABLE(_table, _count) \
do { \
u8 _i; \
for (_i = 0; _i < (_count); _i++) \
(_table)[_i] = _i; \
} while (0)
#define PMC_FILL_TABLE(_to, _from, _count) \
do { \
u8 _i; \
for (_i = 0; _i < (_count); _i++) { \
(_to)[_i] = (_from)[_i]; \
} \
} while (0)
struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem, struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem,
unsigned int nperiph, unsigned int ngck, unsigned int nperiph, unsigned int ngck,
unsigned int npck); unsigned int npck);

View File

@ -26,10 +26,16 @@ static const struct clk_range plla_outputs[] = {
{ .min = 2343750, .max = 1200000000 }, { .min = 2343750, .max = 1200000000 },
}; };
/* Fractional PLL core output range. */
static const struct clk_range core_outputs[] = {
{ .min = 600000000, .max = 1200000000 },
};
static const struct clk_pll_characteristics plla_characteristics = { static const struct clk_pll_characteristics plla_characteristics = {
.input = { .min = 12000000, .max = 48000000 }, .input = { .min = 12000000, .max = 48000000 },
.num_output = ARRAY_SIZE(plla_outputs), .num_output = ARRAY_SIZE(plla_outputs),
.output = plla_outputs, .output = plla_outputs,
.core_output = core_outputs,
}; };
static const struct clk_range upll_outputs[] = { static const struct clk_range upll_outputs[] = {
@ -40,6 +46,7 @@ static const struct clk_pll_characteristics upll_characteristics = {
.input = { .min = 12000000, .max = 48000000 }, .input = { .min = 12000000, .max = 48000000 },
.num_output = ARRAY_SIZE(upll_outputs), .num_output = ARRAY_SIZE(upll_outputs),
.output = upll_outputs, .output = upll_outputs,
.core_output = core_outputs,
.upll = true, .upll = true,
}; };

946
drivers/clk/at91/sam9x7.c Normal file
View File

@ -0,0 +1,946 @@
// SPDX-License-Identifier: GPL-2.0
/*
* SAM9X7 PMC code.
*
* Copyright (C) 2023 Microchip Technology Inc. and its subsidiaries
*
* Author: Varshini Rajendran <varshini.rajendran@microchip.com>
*
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/mfd/syscon.h>
#include <linux/slab.h>
#include <dt-bindings/clock/at91.h>
#include "pmc.h"
static DEFINE_SPINLOCK(pmc_pll_lock);
static DEFINE_SPINLOCK(mck_lock);
/**
* enum pll_ids - PLL clocks identifiers
* @PLL_ID_PLLA: PLLA identifier
* @PLL_ID_UPLL: UPLL identifier
* @PLL_ID_AUDIO: Audio PLL identifier
* @PLL_ID_LVDS: LVDS PLL identifier
* @PLL_ID_PLLA_DIV2: PLLA DIV2 identifier
* @PLL_ID_MAX: Max PLL Identifier
*/
enum pll_ids {
PLL_ID_PLLA,
PLL_ID_UPLL,
PLL_ID_AUDIO,
PLL_ID_LVDS,
PLL_ID_PLLA_DIV2,
PLL_ID_MAX,
};
/**
* enum pll_type - PLL type identifiers
* @PLL_TYPE_FRAC: fractional PLL identifier
* @PLL_TYPE_DIV: divider PLL identifier
*/
enum pll_type {
PLL_TYPE_FRAC,
PLL_TYPE_DIV,
};
static const struct clk_master_characteristics mck_characteristics = {
.output = { .min = 32000000, .max = 266666667 },
.divisors = { 1, 2, 4, 3, 5},
.have_div3_pres = 1,
};
static const struct clk_master_layout sam9x7_master_layout = {
.mask = 0x373,
.pres_shift = 4,
.offset = 0x28,
};
/* Fractional PLL core output range. */
static const struct clk_range plla_core_outputs[] = {
{ .min = 375000000, .max = 1600000000 },
};
static const struct clk_range upll_core_outputs[] = {
{ .min = 600000000, .max = 1200000000 },
};
static const struct clk_range lvdspll_core_outputs[] = {
{ .min = 400000000, .max = 800000000 },
};
static const struct clk_range audiopll_core_outputs[] = {
{ .min = 400000000, .max = 800000000 },
};
static const struct clk_range plladiv2_core_outputs[] = {
{ .min = 375000000, .max = 1600000000 },
};
/* Fractional PLL output range. */
static const struct clk_range plla_outputs[] = {
{ .min = 732421, .max = 800000000 },
};
static const struct clk_range upll_outputs[] = {
{ .min = 300000000, .max = 600000000 },
};
static const struct clk_range lvdspll_outputs[] = {
{ .min = 10000000, .max = 800000000 },
};
static const struct clk_range audiopll_outputs[] = {
{ .min = 10000000, .max = 800000000 },
};
static const struct clk_range plladiv2_outputs[] = {
{ .min = 366210, .max = 400000000 },
};
/* PLL characteristics. */
static const struct clk_pll_characteristics plla_characteristics = {
.input = { .min = 20000000, .max = 50000000 },
.num_output = ARRAY_SIZE(plla_outputs),
.output = plla_outputs,
.core_output = plla_core_outputs,
};
static const struct clk_pll_characteristics upll_characteristics = {
.input = { .min = 20000000, .max = 50000000 },
.num_output = ARRAY_SIZE(upll_outputs),
.output = upll_outputs,
.core_output = upll_core_outputs,
.upll = true,
};
static const struct clk_pll_characteristics lvdspll_characteristics = {
.input = { .min = 20000000, .max = 50000000 },
.num_output = ARRAY_SIZE(lvdspll_outputs),
.output = lvdspll_outputs,
.core_output = lvdspll_core_outputs,
};
static const struct clk_pll_characteristics audiopll_characteristics = {
.input = { .min = 20000000, .max = 50000000 },
.num_output = ARRAY_SIZE(audiopll_outputs),
.output = audiopll_outputs,
.core_output = audiopll_core_outputs,
};
static const struct clk_pll_characteristics plladiv2_characteristics = {
.input = { .min = 20000000, .max = 50000000 },
.num_output = ARRAY_SIZE(plladiv2_outputs),
.output = plladiv2_outputs,
.core_output = plladiv2_core_outputs,
};
/* Layout for fractional PLL ID PLLA. */
static const struct clk_pll_layout plla_frac_layout = {
.mul_mask = GENMASK(31, 24),
.frac_mask = GENMASK(21, 0),
.mul_shift = 24,
.frac_shift = 0,
.div2 = 1,
};
/* Layout for fractional PLLs. */
static const struct clk_pll_layout pll_frac_layout = {
.mul_mask = GENMASK(31, 24),
.frac_mask = GENMASK(21, 0),
.mul_shift = 24,
.frac_shift = 0,
};
/* Layout for DIV PLLs. */
static const struct clk_pll_layout pll_divpmc_layout = {
.div_mask = GENMASK(7, 0),
.endiv_mask = BIT(29),
.div_shift = 0,
.endiv_shift = 29,
};
/* Layout for DIV PLL ID PLLADIV2. */
static const struct clk_pll_layout plladiv2_divpmc_layout = {
.div_mask = GENMASK(7, 0),
.endiv_mask = BIT(29),
.div_shift = 0,
.endiv_shift = 29,
.div2 = 1,
};
/* Layout for DIVIO dividers. */
static const struct clk_pll_layout pll_divio_layout = {
.div_mask = GENMASK(19, 12),
.endiv_mask = BIT(30),
.div_shift = 12,
.endiv_shift = 30,
};
/*
* PLL clocks description
* @n: clock name
* @p: clock parent
* @l: clock layout
* @t: clock type
* @c: pll characteristics
* @f: clock flags
* @eid: export index in sam9x7->chws[] array
*/
static const struct {
const char *n;
const char *p;
const struct clk_pll_layout *l;
u8 t;
const struct clk_pll_characteristics *c;
unsigned long f;
u8 eid;
} sam9x7_plls[][3] = {
[PLL_ID_PLLA] = {
{
.n = "plla_fracck",
.p = "mainck",
.l = &plla_frac_layout,
.t = PLL_TYPE_FRAC,
/*
* This feeds plla_divpmcck which feeds CPU. It should
* not be disabled.
*/
.f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE,
.c = &plla_characteristics,
},
{
.n = "plla_divpmcck",
.p = "plla_fracck",
.l = &pll_divpmc_layout,
.t = PLL_TYPE_DIV,
/* This feeds CPU. It should not be disabled */
.f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE,
.eid = PMC_PLLACK,
.c = &plla_characteristics,
},
},
[PLL_ID_UPLL] = {
{
.n = "upll_fracck",
.p = "main_osc",
.l = &pll_frac_layout,
.t = PLL_TYPE_FRAC,
.f = CLK_SET_RATE_GATE,
.c = &upll_characteristics,
},
{
.n = "upll_divpmcck",
.p = "upll_fracck",
.l = &pll_divpmc_layout,
.t = PLL_TYPE_DIV,
.f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
CLK_SET_RATE_PARENT,
.eid = PMC_UTMI,
.c = &upll_characteristics,
},
},
[PLL_ID_AUDIO] = {
{
.n = "audiopll_fracck",
.p = "main_osc",
.l = &pll_frac_layout,
.f = CLK_SET_RATE_GATE,
.c = &audiopll_characteristics,
.t = PLL_TYPE_FRAC,
},
{
.n = "audiopll_divpmcck",
.p = "audiopll_fracck",
.l = &pll_divpmc_layout,
.f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
CLK_SET_RATE_PARENT,
.c = &audiopll_characteristics,
.eid = PMC_AUDIOPMCPLL,
.t = PLL_TYPE_DIV,
},
{
.n = "audiopll_diviock",
.p = "audiopll_fracck",
.l = &pll_divio_layout,
.f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
CLK_SET_RATE_PARENT,
.c = &audiopll_characteristics,
.eid = PMC_AUDIOIOPLL,
.t = PLL_TYPE_DIV,
},
},
[PLL_ID_LVDS] = {
{
.n = "lvdspll_fracck",
.p = "main_osc",
.l = &pll_frac_layout,
.f = CLK_SET_RATE_GATE,
.c = &lvdspll_characteristics,
.t = PLL_TYPE_FRAC,
},
{
.n = "lvdspll_divpmcck",
.p = "lvdspll_fracck",
.l = &pll_divpmc_layout,
.f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
CLK_SET_RATE_PARENT,
.c = &lvdspll_characteristics,
.eid = PMC_LVDSPLL,
.t = PLL_TYPE_DIV,
},
},
[PLL_ID_PLLA_DIV2] = {
{
.n = "plla_div2pmcck",
.p = "plla_fracck",
.l = &plladiv2_divpmc_layout,
/*
* This may feed critical parts of the system like timers.
* It should not be disabled.
*/
.f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE,
.c = &plladiv2_characteristics,
.eid = PMC_PLLADIV2,
.t = PLL_TYPE_DIV,
},
},
};
static const struct clk_programmable_layout sam9x7_programmable_layout = {
.pres_mask = 0xff,
.pres_shift = 8,
.css_mask = 0x1f,
.have_slck_mck = 0,
.is_pres_direct = 1,
};
static const struct clk_pcr_layout sam9x7_pcr_layout = {
.offset = 0x88,
.cmd = BIT(31),
.gckcss_mask = GENMASK(12, 8),
.pid_mask = GENMASK(6, 0),
};
static const struct {
char *n;
char *p;
u8 id;
unsigned long flags;
} sam9x7_systemck[] = {
/*
* ddrck feeds DDR controller and is enabled by bootloader thus we need
* to keep it enabled in case there is no Linux consumer for it.
*/
{ .n = "ddrck", .p = "masterck_div", .id = 2, .flags = CLK_IS_CRITICAL },
{ .n = "uhpck", .p = "usbck", .id = 6 },
{ .n = "pck0", .p = "prog0", .id = 8 },
{ .n = "pck1", .p = "prog1", .id = 9 },
};
/*
* Peripheral clocks description
* @n: clock name
* @f: clock flags
* @id: peripheral id
*/
static const struct {
char *n;
unsigned long f;
u8 id;
} sam9x7_periphck[] = {
{ .n = "pioA_clk", .id = 2, },
{ .n = "pioB_clk", .id = 3, },
{ .n = "pioC_clk", .id = 4, },
{ .n = "flex0_clk", .id = 5, },
{ .n = "flex1_clk", .id = 6, },
{ .n = "flex2_clk", .id = 7, },
{ .n = "flex3_clk", .id = 8, },
{ .n = "flex6_clk", .id = 9, },
{ .n = "flex7_clk", .id = 10, },
{ .n = "flex8_clk", .id = 11, },
{ .n = "sdmmc0_clk", .id = 12, },
{ .n = "flex4_clk", .id = 13, },
{ .n = "flex5_clk", .id = 14, },
{ .n = "flex9_clk", .id = 15, },
{ .n = "flex10_clk", .id = 16, },
{ .n = "tcb0_clk", .id = 17, },
{ .n = "pwm_clk", .id = 18, },
{ .n = "adc_clk", .id = 19, },
{ .n = "dma0_clk", .id = 20, },
{ .n = "uhphs_clk", .id = 22, },
{ .n = "udphs_clk", .id = 23, },
{ .n = "macb0_clk", .id = 24, },
{ .n = "lcd_clk", .id = 25, },
{ .n = "sdmmc1_clk", .id = 26, },
{ .n = "ssc_clk", .id = 28, },
{ .n = "can0_clk", .id = 29, },
{ .n = "can1_clk", .id = 30, },
{ .n = "flex11_clk", .id = 32, },
{ .n = "flex12_clk", .id = 33, },
{ .n = "i2s_clk", .id = 34, },
{ .n = "qspi_clk", .id = 35, },
{ .n = "gfx2d_clk", .id = 36, },
{ .n = "pit64b0_clk", .id = 37, },
{ .n = "trng_clk", .id = 38, },
{ .n = "aes_clk", .id = 39, },
{ .n = "tdes_clk", .id = 40, },
{ .n = "sha_clk", .id = 41, },
{ .n = "classd_clk", .id = 42, },
{ .n = "isi_clk", .id = 43, },
{ .n = "pioD_clk", .id = 44, },
{ .n = "tcb1_clk", .id = 45, },
{ .n = "dbgu_clk", .id = 47, },
/*
* mpddr_clk feeds DDR controller and is enabled by bootloader thus we
* need to keep it enabled in case there is no Linux consumer for it.
*/
{ .n = "mpddr_clk", .id = 49, .f = CLK_IS_CRITICAL },
{ .n = "csi2dc_clk", .id = 52, },
{ .n = "csi4l_clk", .id = 53, },
{ .n = "dsi4l_clk", .id = 54, },
{ .n = "lvdsc_clk", .id = 56, },
{ .n = "pit64b1_clk", .id = 58, },
{ .n = "puf_clk", .id = 59, },
{ .n = "gmactsu_clk", .id = 67, },
};
/*
* Generic clock description
* @n: clock name
* @pp: PLL parents
* @pp_mux_table: PLL parents mux table
* @r: clock output range
* @pp_chg_id: id in parent array of changeable PLL parent
* @pp_count: PLL parents count
* @id: clock id
*/
static const struct {
const char *n;
const char *pp[8];
const char pp_mux_table[8];
struct clk_range r;
int pp_chg_id;
u8 pp_count;
u8 id;
} sam9x7_gck[] = {
{
.n = "flex0_gclk",
.id = 5,
.pp = { "plla_div2pmcck", },
.pp_mux_table = { 8, },
.pp_count = 1,
.pp_chg_id = INT_MIN,
},
{
.n = "flex1_gclk",
.id = 6,
.pp = { "plla_div2pmcck", },
.pp_mux_table = { 8, },
.pp_count = 1,
.pp_chg_id = INT_MIN,
},
{
.n = "flex2_gclk",
.id = 7,
.pp = { "plla_div2pmcck", },
.pp_mux_table = { 8, },
.pp_count = 1,
.pp_chg_id = INT_MIN,
},
{
.n = "flex3_gclk",
.id = 8,
.pp = { "plla_div2pmcck", },
.pp_mux_table = { 8, },
.pp_count = 1,
.pp_chg_id = INT_MIN,
},
{
.n = "flex6_gclk",
.id = 9,
.pp = { "plla_div2pmcck", },
.pp_mux_table = { 8, },
.pp_count = 1,
.pp_chg_id = INT_MIN,
},
{
.n = "flex7_gclk",
.id = 10,
.pp = { "plla_div2pmcck", },
.pp_mux_table = { 8, },
.pp_count = 1,
.pp_chg_id = INT_MIN,
},
{
.n = "flex8_gclk",
.id = 11,
.pp = { "plla_div2pmcck", },
.pp_mux_table = { 8, },
.pp_count = 1,
.pp_chg_id = INT_MIN,
},
{
.n = "sdmmc0_gclk",
.id = 12,
.r = { .max = 105000000 },
.pp = { "audiopll_divpmcck", "plla_div2pmcck", },
.pp_mux_table = { 6, 8, },
.pp_count = 2,
.pp_chg_id = INT_MIN,
},
{
.n = "flex4_gclk",
.id = 13,
.pp = { "plla_div2pmcck", },
.pp_mux_table = { 8, },
.pp_count = 1,
.pp_chg_id = INT_MIN,
},
{
.n = "flex5_gclk",
.id = 14,
.pp = { "plla_div2pmcck", },
.pp_mux_table = { 8, },
.pp_count = 1,
.pp_chg_id = INT_MIN,
},
{
.n = "flex9_gclk",
.id = 15,
.pp = { "plla_div2pmcck", },
.pp_mux_table = { 8, },
.pp_count = 1,
.pp_chg_id = INT_MIN,
},
{
.n = "flex10_gclk",
.id = 16,
.pp = { "plla_div2pmcck", },
.pp_mux_table = { 8, },
.pp_count = 1,
.pp_chg_id = INT_MIN,
},
{
.n = "tcb0_gclk",
.id = 17,
.pp = { "audiopll_divpmcck", "plla_div2pmcck", },
.pp_mux_table = { 6, 8, },
.pp_count = 2,
.pp_chg_id = INT_MIN,
},
{
.n = "adc_gclk",
.id = 19,
.pp = { "upll_divpmcck", "plla_div2pmcck", },
.pp_mux_table = { 5, 8, },
.pp_count = 2,
.pp_chg_id = INT_MIN,
},
{
.n = "lcd_gclk",
.id = 25,
.r = { .max = 75000000 },
.pp = { "audiopll_divpmcck", "plla_div2pmcck", },
.pp_mux_table = { 6, 8, },
.pp_count = 2,
.pp_chg_id = INT_MIN,
},
{
.n = "sdmmc1_gclk",
.id = 26,
.r = { .max = 105000000 },
.pp = { "audiopll_divpmcck", "plla_div2pmcck", },
.pp_mux_table = { 6, 8, },
.pp_count = 2,
.pp_chg_id = INT_MIN,
},
{
.n = "mcan0_gclk",
.id = 29,
.r = { .max = 80000000 },
.pp = { "upll_divpmcck", "plla_div2pmcck", },
.pp_mux_table = { 5, 8, },
.pp_count = 2,
.pp_chg_id = INT_MIN,
},
{
.n = "mcan1_gclk",
.id = 30,
.r = { .max = 80000000 },
.pp = { "upll_divpmcck", "plla_div2pmcck", },
.pp_mux_table = { 5, 8, },
.pp_count = 2,
.pp_chg_id = INT_MIN,
},
{
.n = "flex11_gclk",
.id = 32,
.pp = { "plla_div2pmcck", },
.pp_mux_table = { 8, },
.pp_count = 1,
.pp_chg_id = INT_MIN,
},
{
.n = "flex12_gclk",
.id = 33,
.pp = { "plla_div2pmcck", },
.pp_mux_table = { 8, },
.pp_count = 1,
.pp_chg_id = INT_MIN,
},
{
.n = "i2s_gclk",
.id = 34,
.r = { .max = 100000000 },
.pp = { "audiopll_divpmcck", "plla_div2pmcck", },
.pp_mux_table = { 6, 8, },
.pp_count = 2,
.pp_chg_id = INT_MIN,
},
{
.n = "qspi_gclk",
.id = 35,
.r = { .max = 200000000 },
.pp = { "audiopll_divpmcck", "plla_div2pmcck", },
.pp_mux_table = { 6, 8, },
.pp_count = 2,
.pp_chg_id = INT_MIN,
},
{
.n = "pit64b0_gclk",
.id = 37,
.pp = { "plla_div2pmcck", },
.pp_mux_table = { 8, },
.pp_count = 1,
.pp_chg_id = INT_MIN,
},
{
.n = "classd_gclk",
.id = 42,
.r = { .max = 100000000 },
.pp = { "audiopll_divpmcck", "plla_div2pmcck", },
.pp_mux_table = { 6, 8, },
.pp_count = 2,
.pp_chg_id = INT_MIN,
},
{
.n = "tcb1_gclk",
.id = 45,
.pp = { "audiopll_divpmcck", "plla_div2pmcck", },
.pp_mux_table = { 6, 8, },
.pp_count = 2,
.pp_chg_id = INT_MIN,
},
{
.n = "dbgu_gclk",
.id = 47,
.pp = { "plla_div2pmcck", },
.pp_mux_table = { 8, },
.pp_count = 1,
.pp_chg_id = INT_MIN,
},
{
.n = "mipiphy_gclk",
.id = 55,
.r = { .max = 27000000 },
.pp = { "plla_div2pmcck", },
.pp_mux_table = { 8, },
.pp_count = 1,
.pp_chg_id = INT_MIN,
},
{
.n = "pit64b1_gclk",
.id = 58,
.pp = { "plla_div2pmcck", },
.pp_mux_table = { 8, },
.pp_count = 1,
.pp_chg_id = INT_MIN,
},
{
.n = "gmac_gclk",
.id = 67,
.pp = { "audiopll_divpmcck", "plla_div2pmcck", },
.pp_mux_table = { 6, 8, },
.pp_count = 2,
.pp_chg_id = INT_MIN,
},
};
static void __init sam9x7_pmc_setup(struct device_node *np)
{
struct clk_range range = CLK_RANGE(0, 0);
const char *td_slck_name, *md_slck_name, *mainxtal_name;
struct pmc_data *sam9x7_pmc;
const char *parent_names[9];
void **clk_mux_buffer = NULL;
int clk_mux_buffer_size = 0;
struct clk_hw *main_osc_hw;
struct regmap *regmap;
struct clk_hw *hw;
int i, j;
i = of_property_match_string(np, "clock-names", "td_slck");
if (i < 0)
return;
td_slck_name = of_clk_get_parent_name(np, i);
i = of_property_match_string(np, "clock-names", "md_slck");
if (i < 0)
return;
md_slck_name = of_clk_get_parent_name(np, i);
i = of_property_match_string(np, "clock-names", "main_xtal");
if (i < 0)
return;
mainxtal_name = of_clk_get_parent_name(np, i);
regmap = device_node_to_regmap(np);
if (IS_ERR(regmap))
return;
sam9x7_pmc = pmc_data_allocate(PMC_LVDSPLL + 1,
nck(sam9x7_systemck),
nck(sam9x7_periphck),
nck(sam9x7_gck), 8);
if (!sam9x7_pmc)
return;
clk_mux_buffer = kmalloc(sizeof(void *) *
(ARRAY_SIZE(sam9x7_gck)),
GFP_KERNEL);
if (!clk_mux_buffer)
goto err_free;
hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000,
50000000);
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, NULL, 0);
if (IS_ERR(hw))
goto err_free;
main_osc_hw = hw;
parent_names[0] = "main_rc_osc";
parent_names[1] = "main_osc";
hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, NULL, 2);
if (IS_ERR(hw))
goto err_free;
sam9x7_pmc->chws[PMC_MAIN] = hw;
for (i = 0; i < PLL_ID_MAX; i++) {
for (j = 0; j < 3; j++) {
struct clk_hw *parent_hw;
if (!sam9x7_plls[i][j].n)
continue;
switch (sam9x7_plls[i][j].t) {
case PLL_TYPE_FRAC:
if (!strcmp(sam9x7_plls[i][j].p, "mainck"))
parent_hw = sam9x7_pmc->chws[PMC_MAIN];
else if (!strcmp(sam9x7_plls[i][j].p, "main_osc"))
parent_hw = main_osc_hw;
else
parent_hw = __clk_get_hw(of_clk_get_by_name
(np, sam9x7_plls[i][j].p));
hw = sam9x60_clk_register_frac_pll(regmap,
&pmc_pll_lock,
sam9x7_plls[i][j].n,
sam9x7_plls[i][j].p,
parent_hw, i,
sam9x7_plls[i][j].c,
sam9x7_plls[i][j].l,
sam9x7_plls[i][j].f);
break;
case PLL_TYPE_DIV:
hw = sam9x60_clk_register_div_pll(regmap,
&pmc_pll_lock,
sam9x7_plls[i][j].n,
sam9x7_plls[i][j].p, NULL, i,
sam9x7_plls[i][j].c,
sam9x7_plls[i][j].l,
sam9x7_plls[i][j].f, 0);
break;
default:
continue;
}
if (IS_ERR(hw))
goto err_free;
if (sam9x7_plls[i][j].eid)
sam9x7_pmc->chws[sam9x7_plls[i][j].eid] = hw;
}
}
parent_names[0] = md_slck_name;
parent_names[1] = "mainck";
parent_names[2] = "plla_divpmcck";
parent_names[3] = "upll_divpmcck";
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
parent_names, NULL, &sam9x7_master_layout,
&mck_characteristics, &mck_lock);
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_master_div(regmap, "masterck_div",
"masterck_pres", NULL, &sam9x7_master_layout,
&mck_characteristics, &mck_lock,
CLK_SET_RATE_GATE, 0);
if (IS_ERR(hw))
goto err_free;
sam9x7_pmc->chws[PMC_MCK] = hw;
parent_names[0] = "plla_divpmcck";
parent_names[1] = "upll_divpmcck";
parent_names[2] = "main_osc";
hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 3);
if (IS_ERR(hw))
goto err_free;
parent_names[0] = md_slck_name;
parent_names[1] = td_slck_name;
parent_names[2] = "mainck";
parent_names[3] = "masterck_div";
parent_names[4] = "plla_divpmcck";
parent_names[5] = "upll_divpmcck";
parent_names[6] = "audiopll_divpmcck";
for (i = 0; i < 2; i++) {
char name[6];
snprintf(name, sizeof(name), "prog%d", i);
hw = at91_clk_register_programmable(regmap, name,
parent_names, NULL, 7, i,
&sam9x7_programmable_layout,
NULL);
if (IS_ERR(hw))
goto err_free;
sam9x7_pmc->pchws[i] = hw;
}
for (i = 0; i < ARRAY_SIZE(sam9x7_systemck); i++) {
hw = at91_clk_register_system(regmap, sam9x7_systemck[i].n,
sam9x7_systemck[i].p, NULL,
sam9x7_systemck[i].id,
sam9x7_systemck[i].flags);
if (IS_ERR(hw))
goto err_free;
sam9x7_pmc->shws[sam9x7_systemck[i].id] = hw;
}
for (i = 0; i < ARRAY_SIZE(sam9x7_periphck); i++) {
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
&sam9x7_pcr_layout,
sam9x7_periphck[i].n,
"masterck_div", NULL,
sam9x7_periphck[i].id,
&range, INT_MIN,
sam9x7_periphck[i].f);
if (IS_ERR(hw))
goto err_free;
sam9x7_pmc->phws[sam9x7_periphck[i].id] = hw;
}
parent_names[0] = md_slck_name;
parent_names[1] = td_slck_name;
parent_names[2] = "mainck";
parent_names[3] = "masterck_div";
for (i = 0; i < ARRAY_SIZE(sam9x7_gck); i++) {
u8 num_parents = 4 + sam9x7_gck[i].pp_count;
u32 *mux_table;
mux_table = kmalloc_array(num_parents, sizeof(*mux_table),
GFP_KERNEL);
if (!mux_table)
goto err_free;
PMC_INIT_TABLE(mux_table, 4);
PMC_FILL_TABLE(&mux_table[4], sam9x7_gck[i].pp_mux_table,
sam9x7_gck[i].pp_count);
PMC_FILL_TABLE(&parent_names[4], sam9x7_gck[i].pp,
sam9x7_gck[i].pp_count);
hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
&sam9x7_pcr_layout,
sam9x7_gck[i].n,
parent_names, NULL, mux_table,
num_parents,
sam9x7_gck[i].id,
&sam9x7_gck[i].r,
sam9x7_gck[i].pp_chg_id);
if (IS_ERR(hw))
goto err_free;
sam9x7_pmc->ghws[sam9x7_gck[i].id] = hw;
clk_mux_buffer[clk_mux_buffer_size++] = mux_table;
}
of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sam9x7_pmc);
kfree(clk_mux_buffer);
return;
err_free:
if (clk_mux_buffer) {
for (i = 0; i < clk_mux_buffer_size; i++)
kfree(clk_mux_buffer[i]);
kfree(clk_mux_buffer);
}
kfree(sam9x7_pmc);
}
/* Some clks are used for a clocksource */
CLK_OF_DECLARE(sam9x7_pmc, "microchip,sam9x7-pmc", sam9x7_pmc_setup);

View File

@ -16,21 +16,6 @@
#include "pmc.h" #include "pmc.h"
#define SAMA7G5_INIT_TABLE(_table, _count) \
do { \
u8 _i; \
for (_i = 0; _i < (_count); _i++) \
(_table)[_i] = _i; \
} while (0)
#define SAMA7G5_FILL_TABLE(_to, _from, _count) \
do { \
u8 _i; \
for (_i = 0; _i < (_count); _i++) { \
(_to)[_i] = (_from)[_i]; \
} \
} while (0)
static DEFINE_SPINLOCK(pmc_pll_lock); static DEFINE_SPINLOCK(pmc_pll_lock);
static DEFINE_SPINLOCK(pmc_mck0_lock); static DEFINE_SPINLOCK(pmc_mck0_lock);
static DEFINE_SPINLOCK(pmc_mckX_lock); static DEFINE_SPINLOCK(pmc_mckX_lock);
@ -66,6 +51,7 @@ enum pll_component_id {
PLL_COMPID_FRAC, PLL_COMPID_FRAC,
PLL_COMPID_DIV0, PLL_COMPID_DIV0,
PLL_COMPID_DIV1, PLL_COMPID_DIV1,
PLL_COMPID_MAX,
}; };
/* /*
@ -116,11 +102,17 @@ static const struct clk_range pll_outputs[] = {
{ .min = 2343750, .max = 1200000000 }, { .min = 2343750, .max = 1200000000 },
}; };
/* Fractional PLL core output range. */
static const struct clk_range core_outputs[] = {
{ .min = 600000000, .max = 1200000000 },
};
/* CPU PLL characteristics. */ /* CPU PLL characteristics. */
static const struct clk_pll_characteristics cpu_pll_characteristics = { static const struct clk_pll_characteristics cpu_pll_characteristics = {
.input = { .min = 12000000, .max = 50000000 }, .input = { .min = 12000000, .max = 50000000 },
.num_output = ARRAY_SIZE(cpu_pll_outputs), .num_output = ARRAY_SIZE(cpu_pll_outputs),
.output = cpu_pll_outputs, .output = cpu_pll_outputs,
.core_output = core_outputs,
}; };
/* PLL characteristics. */ /* PLL characteristics. */
@ -128,6 +120,7 @@ static const struct clk_pll_characteristics pll_characteristics = {
.input = { .min = 12000000, .max = 50000000 }, .input = { .min = 12000000, .max = 50000000 },
.num_output = ARRAY_SIZE(pll_outputs), .num_output = ARRAY_SIZE(pll_outputs),
.output = pll_outputs, .output = pll_outputs,
.core_output = core_outputs,
}; };
/* /*
@ -165,7 +158,7 @@ static struct sama7g5_pll {
u8 t; u8 t;
u8 eid; u8 eid;
u8 safe_div; u8 safe_div;
} sama7g5_plls[][PLL_ID_MAX] = { } sama7g5_plls[][PLL_COMPID_MAX] = {
[PLL_ID_CPU] = { [PLL_ID_CPU] = {
[PLL_COMPID_FRAC] = { [PLL_COMPID_FRAC] = {
.n = "cpupll_fracck", .n = "cpupll_fracck",
@ -1038,7 +1031,7 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
sama7g5_pmc->chws[PMC_MAIN] = hw; sama7g5_pmc->chws[PMC_MAIN] = hw;
for (i = 0; i < PLL_ID_MAX; i++) { for (i = 0; i < PLL_ID_MAX; i++) {
for (j = 0; j < 3; j++) { for (j = 0; j < PLL_COMPID_MAX; j++) {
struct clk_hw *parent_hw; struct clk_hw *parent_hw;
if (!sama7g5_plls[i][j].n) if (!sama7g5_plls[i][j].n)
@ -1112,17 +1105,17 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
if (!mux_table) if (!mux_table)
goto err_free; goto err_free;
SAMA7G5_INIT_TABLE(mux_table, 3); PMC_INIT_TABLE(mux_table, 3);
SAMA7G5_FILL_TABLE(&mux_table[3], sama7g5_mckx[i].ep_mux_table, PMC_FILL_TABLE(&mux_table[3], sama7g5_mckx[i].ep_mux_table,
sama7g5_mckx[i].ep_count); sama7g5_mckx[i].ep_count);
for (j = 0; j < sama7g5_mckx[i].ep_count; j++) { for (j = 0; j < sama7g5_mckx[i].ep_count; j++) {
u8 pll_id = sama7g5_mckx[i].ep[j].pll_id; u8 pll_id = sama7g5_mckx[i].ep[j].pll_id;
u8 pll_compid = sama7g5_mckx[i].ep[j].pll_compid; u8 pll_compid = sama7g5_mckx[i].ep[j].pll_compid;
tmp_parent_hws[j] = sama7g5_plls[pll_id][pll_compid].hw; tmp_parent_hws[j] = sama7g5_plls[pll_id][pll_compid].hw;
} }
SAMA7G5_FILL_TABLE(&parent_hws[3], tmp_parent_hws, PMC_FILL_TABLE(&parent_hws[3], tmp_parent_hws,
sama7g5_mckx[i].ep_count); sama7g5_mckx[i].ep_count);
hw = at91_clk_sama7g5_register_master(regmap, sama7g5_mckx[i].n, hw = at91_clk_sama7g5_register_master(regmap, sama7g5_mckx[i].n,
num_parents, NULL, parent_hws, mux_table, num_parents, NULL, parent_hws, mux_table,
@ -1208,17 +1201,17 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
if (!mux_table) if (!mux_table)
goto err_free; goto err_free;
SAMA7G5_INIT_TABLE(mux_table, 3); PMC_INIT_TABLE(mux_table, 3);
SAMA7G5_FILL_TABLE(&mux_table[3], sama7g5_gck[i].pp_mux_table, PMC_FILL_TABLE(&mux_table[3], sama7g5_gck[i].pp_mux_table,
sama7g5_gck[i].pp_count); sama7g5_gck[i].pp_count);
for (j = 0; j < sama7g5_gck[i].pp_count; j++) { for (j = 0; j < sama7g5_gck[i].pp_count; j++) {
u8 pll_id = sama7g5_gck[i].pp[j].pll_id; u8 pll_id = sama7g5_gck[i].pp[j].pll_id;
u8 pll_compid = sama7g5_gck[i].pp[j].pll_compid; u8 pll_compid = sama7g5_gck[i].pp[j].pll_compid;
tmp_parent_hws[j] = sama7g5_plls[pll_id][pll_compid].hw; tmp_parent_hws[j] = sama7g5_plls[pll_id][pll_compid].hw;
} }
SAMA7G5_FILL_TABLE(&parent_hws[3], tmp_parent_hws, PMC_FILL_TABLE(&parent_hws[3], tmp_parent_hws,
sama7g5_gck[i].pp_count); sama7g5_gck[i].pp_count);
hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
&sama7g5_pcr_layout, &sama7g5_pcr_layout,

View File

@ -215,7 +215,7 @@ static struct platform_driver i2s_pll_clk_driver = {
.of_match_table = i2s_pll_clk_id, .of_match_table = i2s_pll_clk_id,
}, },
.probe = i2s_pll_clk_probe, .probe = i2s_pll_clk_probe,
.remove_new = i2s_pll_clk_remove, .remove = i2s_pll_clk_remove,
}; };
module_platform_driver(i2s_pll_clk_driver); module_platform_driver(i2s_pll_clk_driver);

View File

@ -110,7 +110,7 @@ MODULE_DEVICE_TABLE(of, clk_dvp_dt_ids);
static struct platform_driver clk_dvp_driver = { static struct platform_driver clk_dvp_driver = {
.probe = clk_dvp_probe, .probe = clk_dvp_probe,
.remove_new = clk_dvp_remove, .remove = clk_dvp_remove,
.driver = { .driver = {
.name = "brcm2711-dvp", .name = "brcm2711-dvp",
.of_match_table = clk_dvp_dt_ids, .of_match_table = clk_dvp_dt_ids,

View File

@ -112,7 +112,7 @@ static void bcm53573_ilp_init(struct device_node *np)
goto err_free_ilp; goto err_free_ilp;
} }
ilp->regmap = syscon_node_to_regmap(of_get_parent(np)); ilp->regmap = syscon_node_to_regmap(np->parent);
if (IS_ERR(ilp->regmap)) { if (IS_ERR(ilp->regmap)) {
err = PTR_ERR(ilp->regmap); err = PTR_ERR(ilp->regmap);
goto err_free_ilp; goto err_free_ilp;

View File

@ -567,7 +567,7 @@ static const struct of_device_id clk_bcm63xx_dt_ids[] = {
static struct platform_driver clk_bcm63xx = { static struct platform_driver clk_bcm63xx = {
.probe = clk_bcm63xx_probe, .probe = clk_bcm63xx_probe,
.remove_new = clk_bcm63xx_remove, .remove = clk_bcm63xx_remove,
.driver = { .driver = {
.name = "bcm63xx-clock", .name = "bcm63xx-clock",
.of_match_table = clk_bcm63xx_dt_ids, .of_match_table = clk_bcm63xx_dt_ids,

View File

@ -458,7 +458,7 @@ static struct platform_driver raspberrypi_clk_driver = {
.of_match_table = raspberrypi_clk_match, .of_match_table = raspberrypi_clk_match,
}, },
.probe = raspberrypi_clk_probe, .probe = raspberrypi_clk_probe,
.remove_new = raspberrypi_clk_remove, .remove = raspberrypi_clk_remove,
}; };
module_platform_driver(raspberrypi_clk_driver); module_platform_driver(raspberrypi_clk_driver);

View File

@ -10,6 +10,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/printk.h> #include <linux/printk.h>
#include <linux/slab.h>
static int __set_clk_parents(struct device_node *node, bool clk_supplier) static int __set_clk_parents(struct device_node *node, bool clk_supplier)
{ {
@ -81,11 +82,44 @@ err:
static int __set_clk_rates(struct device_node *node, bool clk_supplier) static int __set_clk_rates(struct device_node *node, bool clk_supplier)
{ {
struct of_phandle_args clkspec; struct of_phandle_args clkspec;
int rc, index = 0; int rc, count, count_64, index;
struct clk *clk; struct clk *clk;
u32 rate; u64 *rates_64 __free(kfree) = NULL;
u32 *rates __free(kfree) = NULL;
count = of_property_count_u32_elems(node, "assigned-clock-rates");
count_64 = of_property_count_u64_elems(node, "assigned-clock-rates-u64");
if (count_64 > 0) {
count = count_64;
rates_64 = kcalloc(count, sizeof(*rates_64), GFP_KERNEL);
if (!rates_64)
return -ENOMEM;
rc = of_property_read_u64_array(node,
"assigned-clock-rates-u64",
rates_64, count);
} else if (count > 0) {
rates = kcalloc(count, sizeof(*rates), GFP_KERNEL);
if (!rates)
return -ENOMEM;
rc = of_property_read_u32_array(node, "assigned-clock-rates",
rates, count);
} else {
return 0;
}
if (rc)
return rc;
for (index = 0; index < count; index++) {
unsigned long rate;
if (rates_64)
rate = rates_64[index];
else
rate = rates[index];
of_property_for_each_u32(node, "assigned-clock-rates", rate) {
if (rate) { if (rate) {
rc = of_parse_phandle_with_args(node, "assigned-clocks", rc = of_parse_phandle_with_args(node, "assigned-clocks",
"#clock-cells", index, &clkspec); "#clock-cells", index, &clkspec);
@ -112,12 +146,11 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier)
rc = clk_set_rate(clk, rate); rc = clk_set_rate(clk, rate);
if (rc < 0) if (rc < 0)
pr_err("clk: couldn't set %s clk rate to %u (%d), current rate: %lu\n", pr_err("clk: couldn't set %s clk rate to %lu (%d), current rate: %lu\n",
__clk_get_name(clk), rate, rc, __clk_get_name(clk), rate, rc,
clk_get_rate(clk)); clk_get_rate(clk));
clk_put(clk); clk_put(clk);
} }
index++;
} }
return 0; return 0;
} }

View File

@ -99,6 +99,34 @@ struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id)
} }
EXPORT_SYMBOL_GPL(devm_clk_get_optional_enabled); EXPORT_SYMBOL_GPL(devm_clk_get_optional_enabled);
struct clk *devm_clk_get_optional_enabled_with_rate(struct device *dev,
const char *id,
unsigned long rate)
{
struct clk *clk;
int ret;
clk = __devm_clk_get(dev, id, clk_get_optional, NULL,
clk_disable_unprepare);
if (IS_ERR(clk))
return ERR_CAST(clk);
ret = clk_set_rate(clk, rate);
if (ret)
goto out_put_clk;
ret = clk_prepare_enable(clk);
if (ret)
goto out_put_clk;
return clk;
out_put_clk:
devm_clk_put(dev, clk);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(devm_clk_get_optional_enabled_with_rate);
struct clk_bulk_devres { struct clk_bulk_devres {
struct clk_bulk_data *clks; struct clk_bulk_data *clks;
int num_clks; int num_clks;

View File

@ -405,7 +405,7 @@ static struct platform_driver of_fixed_factor_clk_driver = {
.of_match_table = of_fixed_factor_clk_ids, .of_match_table = of_fixed_factor_clk_ids,
}, },
.probe = of_fixed_factor_clk_probe, .probe = of_fixed_factor_clk_probe,
.remove_new = of_fixed_factor_clk_remove, .remove = of_fixed_factor_clk_remove,
}; };
builtin_platform_driver(of_fixed_factor_clk_driver); builtin_platform_driver(of_fixed_factor_clk_driver);
#endif #endif

View File

@ -91,7 +91,7 @@ static struct platform_driver of_fixed_mmio_clk_driver = {
.of_match_table = of_fixed_mmio_clk_ids, .of_match_table = of_fixed_mmio_clk_ids,
}, },
.probe = of_fixed_mmio_clk_probe, .probe = of_fixed_mmio_clk_probe,
.remove_new = of_fixed_mmio_clk_remove, .remove = of_fixed_mmio_clk_remove,
}; };
module_platform_driver(of_fixed_mmio_clk_driver); module_platform_driver(of_fixed_mmio_clk_driver);

View File

@ -232,7 +232,7 @@ static struct platform_driver of_fixed_clk_driver = {
.of_match_table = of_fixed_clk_ids, .of_match_table = of_fixed_clk_ids,
}, },
.probe = of_fixed_clk_probe, .probe = of_fixed_clk_probe,
.remove_new = of_fixed_clk_remove, .remove = of_fixed_clk_remove,
}; };
builtin_platform_driver(of_fixed_clk_driver); builtin_platform_driver(of_fixed_clk_driver);
#endif #endif

View File

@ -0,0 +1,380 @@
// SPDX-License-Identifier: GPL-2.0
/*
* KUnit test for clk fixed rate basic type
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/completion.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <kunit/clk.h>
#include <kunit/of.h>
#include <kunit/platform_device.h>
#include <kunit/resource.h>
#include <kunit/test.h>
#include "clk-fixed-rate_test.h"
/**
* struct clk_hw_fixed_rate_kunit_params - Parameters to pass to __clk_hw_register_fixed_rate()
* @dev: device registering clk
* @np: device_node of device registering clk
* @name: name of clk
* @parent_name: parent name of clk
* @parent_hw: clk_hw pointer to parent of clk
* @parent_data: parent_data describing parent of clk
* @flags: clk framework flags
* @fixed_rate: frequency of clk
* @fixed_accuracy: accuracy of clk
* @clk_fixed_flags: fixed rate specific clk flags
*/
struct clk_hw_fixed_rate_kunit_params {
struct device *dev;
struct device_node *np;
const char *name;
const char *parent_name;
const struct clk_hw *parent_hw;
const struct clk_parent_data *parent_data;
unsigned long flags;
unsigned long fixed_rate;
unsigned long fixed_accuracy;
unsigned long clk_fixed_flags;
};
static int
clk_hw_register_fixed_rate_kunit_init(struct kunit_resource *res, void *context)
{
struct clk_hw_fixed_rate_kunit_params *params = context;
struct clk_hw *hw;
hw = __clk_hw_register_fixed_rate(params->dev, params->np,
params->name,
params->parent_name,
params->parent_hw,
params->parent_data,
params->flags,
params->fixed_rate,
params->fixed_accuracy,
params->clk_fixed_flags,
false);
if (IS_ERR(hw))
return PTR_ERR(hw);
res->data = hw;
return 0;
}
static void clk_hw_register_fixed_rate_kunit_exit(struct kunit_resource *res)
{
struct clk_hw *hw = res->data;
clk_hw_unregister_fixed_rate(hw);
}
/**
* clk_hw_register_fixed_rate_kunit() - Test managed __clk_hw_register_fixed_rate()
* @test: The test context
* @params: Arguments to __clk_hw_register_fixed_rate()
*
* Return: Registered fixed rate clk_hw or ERR_PTR on failure
*/
static struct clk_hw *
clk_hw_register_fixed_rate_kunit(struct kunit *test,
struct clk_hw_fixed_rate_kunit_params *params)
{
struct clk_hw *hw;
hw = kunit_alloc_resource(test,
clk_hw_register_fixed_rate_kunit_init,
clk_hw_register_fixed_rate_kunit_exit,
GFP_KERNEL, params);
if (!hw)
return ERR_PTR(-EINVAL);
return hw;
}
/**
* clk_hw_unregister_fixed_rate_kunit() - Test managed clk_hw_unregister_fixed_rate()
* @test: The test context
* @hw: fixed rate clk to unregister upon test completion
*
* Automatically unregister @hw when @test is complete via
* clk_hw_unregister_fixed_rate().
*
* Return: 0 on success or negative errno on failure
*/
static int clk_hw_unregister_fixed_rate_kunit(struct kunit *test, struct clk_hw *hw)
{
if (!kunit_alloc_resource(test, NULL,
clk_hw_register_fixed_rate_kunit_exit,
GFP_KERNEL, hw))
return -ENOMEM;
return 0;
}
/*
* Test that clk_get_rate() on a fixed rate clk registered with
* clk_hw_register_fixed_rate() gets the proper frequency.
*/
static void clk_fixed_rate_rate_test(struct kunit *test)
{
struct clk_hw *hw;
struct clk *clk;
const unsigned long fixed_rate = 230000;
hw = clk_hw_register_fixed_rate(NULL, "test-fixed-rate", NULL, 0, fixed_rate);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
KUNIT_ASSERT_EQ(test, 0, clk_hw_unregister_fixed_rate_kunit(test, hw));
clk = clk_hw_get_clk_prepared_enabled_kunit(test, hw, __func__);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk);
KUNIT_EXPECT_EQ(test, fixed_rate, clk_get_rate(clk));
}
/*
* Test that clk_get_accuracy() on a fixed rate clk registered via
* clk_hw_register_fixed_rate_with_accuracy() gets the proper accuracy.
*/
static void clk_fixed_rate_accuracy_test(struct kunit *test)
{
struct clk_hw *hw;
struct clk *clk;
const unsigned long fixed_accuracy = 5000;
hw = clk_hw_register_fixed_rate_with_accuracy(NULL, "test-fixed-rate",
NULL, 0, 0,
fixed_accuracy);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
KUNIT_ASSERT_EQ(test, 0, clk_hw_unregister_fixed_rate_kunit(test, hw));
clk = clk_hw_get_clk_kunit(test, hw, __func__);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk);
KUNIT_EXPECT_EQ(test, fixed_accuracy, clk_get_accuracy(clk));
}
/* Test suite for a fixed rate clk without any parent */
static struct kunit_case clk_fixed_rate_test_cases[] = {
KUNIT_CASE(clk_fixed_rate_rate_test),
KUNIT_CASE(clk_fixed_rate_accuracy_test),
{}
};
static struct kunit_suite clk_fixed_rate_suite = {
.name = "clk_fixed_rate",
.test_cases = clk_fixed_rate_test_cases,
};
/*
* Test that clk_get_parent() on a fixed rate clk gets the proper parent.
*/
static void clk_fixed_rate_parent_test(struct kunit *test)
{
struct clk_hw *hw, *parent_hw;
struct clk *expected_parent, *actual_parent;
struct clk *clk;
const char *parent_name = "test-fixed-rate-parent";
struct clk_hw_fixed_rate_kunit_params parent_params = {
.name = parent_name,
};
parent_hw = clk_hw_register_fixed_rate_kunit(test, &parent_params);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_hw);
KUNIT_ASSERT_STREQ(test, parent_name, clk_hw_get_name(parent_hw));
expected_parent = clk_hw_get_clk_kunit(test, parent_hw, __func__);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, expected_parent);
hw = clk_hw_register_fixed_rate(NULL, "test-fixed-rate", parent_name, 0, 0);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
KUNIT_ASSERT_EQ(test, 0, clk_hw_unregister_fixed_rate_kunit(test, hw));
clk = clk_hw_get_clk_kunit(test, hw, __func__);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk);
actual_parent = clk_get_parent(clk);
KUNIT_EXPECT_TRUE(test, clk_is_match(expected_parent, actual_parent));
}
/*
* Test that clk_get_rate() on a fixed rate clk ignores the parent rate.
*/
static void clk_fixed_rate_parent_rate_test(struct kunit *test)
{
struct clk_hw *hw, *parent_hw;
struct clk *clk;
const unsigned long expected_rate = 1405;
const unsigned long parent_rate = 90402;
const char *parent_name = "test-fixed-rate-parent";
struct clk_hw_fixed_rate_kunit_params parent_params = {
.name = parent_name,
.fixed_rate = parent_rate,
};
parent_hw = clk_hw_register_fixed_rate_kunit(test, &parent_params);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_hw);
KUNIT_ASSERT_STREQ(test, parent_name, clk_hw_get_name(parent_hw));
hw = clk_hw_register_fixed_rate(NULL, "test-fixed-rate", parent_name, 0,
expected_rate);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
KUNIT_ASSERT_EQ(test, 0, clk_hw_unregister_fixed_rate_kunit(test, hw));
clk = clk_hw_get_clk_prepared_enabled_kunit(test, hw, __func__);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk);
KUNIT_EXPECT_EQ(test, expected_rate, clk_get_rate(clk));
}
/*
* Test that clk_get_accuracy() on a fixed rate clk ignores the parent accuracy.
*/
static void clk_fixed_rate_parent_accuracy_test(struct kunit *test)
{
struct clk_hw *hw, *parent_hw;
struct clk *clk;
const unsigned long expected_accuracy = 900;
const unsigned long parent_accuracy = 24000;
const char *parent_name = "test-fixed-rate-parent";
struct clk_hw_fixed_rate_kunit_params parent_params = {
.name = parent_name,
.fixed_accuracy = parent_accuracy,
};
parent_hw = clk_hw_register_fixed_rate_kunit(test, &parent_params);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_hw);
KUNIT_ASSERT_STREQ(test, parent_name, clk_hw_get_name(parent_hw));
hw = clk_hw_register_fixed_rate_with_accuracy(NULL, "test-fixed-rate",
parent_name, 0, 0,
expected_accuracy);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
KUNIT_ASSERT_EQ(test, 0, clk_hw_unregister_fixed_rate_kunit(test, hw));
clk = clk_hw_get_clk_kunit(test, hw, __func__);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk);
KUNIT_EXPECT_EQ(test, expected_accuracy, clk_get_accuracy(clk));
}
/* Test suite for a fixed rate clk with a parent */
static struct kunit_case clk_fixed_rate_parent_test_cases[] = {
KUNIT_CASE(clk_fixed_rate_parent_test),
KUNIT_CASE(clk_fixed_rate_parent_rate_test),
KUNIT_CASE(clk_fixed_rate_parent_accuracy_test),
{}
};
static struct kunit_suite clk_fixed_rate_parent_suite = {
.name = "clk_fixed_rate_parent",
.test_cases = clk_fixed_rate_parent_test_cases,
};
struct clk_fixed_rate_of_test_context {
struct device *dev;
struct platform_driver pdrv;
struct completion probed;
};
static inline struct clk_fixed_rate_of_test_context *
pdev_to_clk_fixed_rate_of_test_context(struct platform_device *pdev)
{
return container_of(to_platform_driver(pdev->dev.driver),
struct clk_fixed_rate_of_test_context,
pdrv);
}
/*
* Test that of_fixed_clk_setup() registers a fixed rate clk with the proper
* rate.
*/
static void clk_fixed_rate_of_probe_test(struct kunit *test)
{
struct clk_fixed_rate_of_test_context *ctx = test->priv;
struct device *dev = ctx->dev;
struct clk *clk;
clk = clk_get_kunit(test, dev, NULL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk);
KUNIT_ASSERT_EQ(test, 0, clk_prepare_enable_kunit(test, clk));
KUNIT_EXPECT_EQ(test, TEST_FIXED_FREQUENCY, clk_get_rate(clk));
}
/*
* Test that of_fixed_clk_setup() registers a fixed rate clk with the proper
* accuracy.
*/
static void clk_fixed_rate_of_accuracy_test(struct kunit *test)
{
struct clk_fixed_rate_of_test_context *ctx = test->priv;
struct device *dev = ctx->dev;
struct clk *clk;
clk = clk_get_kunit(test, dev, NULL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk);
KUNIT_EXPECT_EQ(test, TEST_FIXED_ACCURACY, clk_get_accuracy(clk));
}
static struct kunit_case clk_fixed_rate_of_cases[] = {
KUNIT_CASE(clk_fixed_rate_of_probe_test),
KUNIT_CASE(clk_fixed_rate_of_accuracy_test),
{}
};
static int clk_fixed_rate_of_test_probe(struct platform_device *pdev)
{
struct clk_fixed_rate_of_test_context *ctx;
ctx = pdev_to_clk_fixed_rate_of_test_context(pdev);
ctx->dev = &pdev->dev;
complete(&ctx->probed);
return 0;
}
static int clk_fixed_rate_of_init(struct kunit *test)
{
struct clk_fixed_rate_of_test_context *ctx;
static const struct of_device_id match_table[] = {
{ .compatible = "test,single-clk-consumer" },
{ }
};
KUNIT_ASSERT_EQ(test, 0, of_overlay_apply_kunit(test, kunit_clk_fixed_rate_test));
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
test->priv = ctx;
ctx->pdrv.probe = clk_fixed_rate_of_test_probe;
ctx->pdrv.driver.of_match_table = match_table;
ctx->pdrv.driver.name = __func__;
ctx->pdrv.driver.owner = THIS_MODULE;
init_completion(&ctx->probed);
KUNIT_ASSERT_EQ(test, 0, kunit_platform_driver_register(test, &ctx->pdrv));
KUNIT_ASSERT_NE(test, 0, wait_for_completion_timeout(&ctx->probed, HZ));
return 0;
}
static struct kunit_suite clk_fixed_rate_of_suite = {
.name = "clk_fixed_rate_of",
.init = clk_fixed_rate_of_init,
.test_cases = clk_fixed_rate_of_cases,
};
kunit_test_suites(
&clk_fixed_rate_suite,
&clk_fixed_rate_of_suite,
&clk_fixed_rate_parent_suite,
);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("KUnit test for clk fixed rate basic type");

View File

@ -0,0 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _CLK_FIXED_RATE_TEST_H
#define _CLK_FIXED_RATE_TEST_H
#define TEST_FIXED_FREQUENCY 50000000
#define TEST_FIXED_ACCURACY 300
#endif

View File

@ -1405,16 +1405,12 @@ static int lmk04832_probe(struct spi_device *spi)
lmk->dev = &spi->dev; lmk->dev = &spi->dev;
lmk->oscin = devm_clk_get(lmk->dev, "oscin"); lmk->oscin = devm_clk_get_enabled(lmk->dev, "oscin");
if (IS_ERR(lmk->oscin)) { if (IS_ERR(lmk->oscin)) {
dev_err(lmk->dev, "failed to get oscin clock\n"); dev_err(lmk->dev, "failed to get oscin clock\n");
return PTR_ERR(lmk->oscin); return PTR_ERR(lmk->oscin);
} }
ret = clk_prepare_enable(lmk->oscin);
if (ret)
return ret;
lmk->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", lmk->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset",
GPIOD_OUT_LOW); GPIOD_OUT_LOW);
@ -1422,14 +1418,14 @@ static int lmk04832_probe(struct spi_device *spi)
sizeof(struct lmk_dclk), GFP_KERNEL); sizeof(struct lmk_dclk), GFP_KERNEL);
if (!lmk->dclk) { if (!lmk->dclk) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_disable_oscin; return ret;
} }
lmk->clkout = devm_kcalloc(lmk->dev, info->num_channels, lmk->clkout = devm_kcalloc(lmk->dev, info->num_channels,
sizeof(*lmk->clkout), GFP_KERNEL); sizeof(*lmk->clkout), GFP_KERNEL);
if (!lmk->clkout) { if (!lmk->clkout) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_disable_oscin; return ret;
} }
lmk->clk_data = devm_kzalloc(lmk->dev, struct_size(lmk->clk_data, hws, lmk->clk_data = devm_kzalloc(lmk->dev, struct_size(lmk->clk_data, hws,
@ -1437,7 +1433,7 @@ static int lmk04832_probe(struct spi_device *spi)
GFP_KERNEL); GFP_KERNEL);
if (!lmk->clk_data) { if (!lmk->clk_data) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_disable_oscin; return ret;
} }
device_property_read_u32(lmk->dev, "ti,vco-hz", &lmk->vco_rate); device_property_read_u32(lmk->dev, "ti,vco-hz", &lmk->vco_rate);
@ -1465,7 +1461,7 @@ static int lmk04832_probe(struct spi_device *spi)
dev_err(lmk->dev, "missing reg property in child: %s\n", dev_err(lmk->dev, "missing reg property in child: %s\n",
child->full_name); child->full_name);
of_node_put(child); of_node_put(child);
goto err_disable_oscin; return ret;
} }
of_property_read_u32(child, "ti,clkout-fmt", of_property_read_u32(child, "ti,clkout-fmt",
@ -1486,7 +1482,7 @@ static int lmk04832_probe(struct spi_device *spi)
__func__, PTR_ERR(lmk->regmap)); __func__, PTR_ERR(lmk->regmap));
ret = PTR_ERR(lmk->regmap); ret = PTR_ERR(lmk->regmap);
goto err_disable_oscin; return ret;
} }
regmap_write(lmk->regmap, LMK04832_REG_RST3W, LMK04832_BIT_RESET); regmap_write(lmk->regmap, LMK04832_REG_RST3W, LMK04832_BIT_RESET);
@ -1496,7 +1492,7 @@ static int lmk04832_probe(struct spi_device *spi)
&rdbk_pin); &rdbk_pin);
ret = lmk04832_set_spi_rdbk(lmk, rdbk_pin); ret = lmk04832_set_spi_rdbk(lmk, rdbk_pin);
if (ret) if (ret)
goto err_disable_oscin; return ret;
} }
regmap_bulk_read(lmk->regmap, LMK04832_REG_ID_PROD_MSB, &tmp, 3); regmap_bulk_read(lmk->regmap, LMK04832_REG_ID_PROD_MSB, &tmp, 3);
@ -1504,13 +1500,13 @@ static int lmk04832_probe(struct spi_device *spi)
dev_err(lmk->dev, "unsupported device type: pid 0x%04x, maskrev 0x%02x\n", dev_err(lmk->dev, "unsupported device type: pid 0x%04x, maskrev 0x%02x\n",
tmp[0] << 8 | tmp[1], tmp[2]); tmp[0] << 8 | tmp[1], tmp[2]);
ret = -EINVAL; ret = -EINVAL;
goto err_disable_oscin; return ret;
} }
ret = lmk04832_register_vco(lmk); ret = lmk04832_register_vco(lmk);
if (ret) { if (ret) {
dev_err(lmk->dev, "failed to init device clock path\n"); dev_err(lmk->dev, "failed to init device clock path\n");
goto err_disable_oscin; return ret;
} }
if (lmk->vco_rate) { if (lmk->vco_rate) {
@ -1518,21 +1514,21 @@ static int lmk04832_probe(struct spi_device *spi)
ret = clk_set_rate(lmk->vco.clk, lmk->vco_rate); ret = clk_set_rate(lmk->vco.clk, lmk->vco_rate);
if (ret) { if (ret) {
dev_err(lmk->dev, "failed to set VCO rate\n"); dev_err(lmk->dev, "failed to set VCO rate\n");
goto err_disable_oscin; return ret;
} }
} }
ret = lmk04832_register_sclk(lmk); ret = lmk04832_register_sclk(lmk);
if (ret) { if (ret) {
dev_err(lmk->dev, "failed to init SYNC/SYSREF clock path\n"); dev_err(lmk->dev, "failed to init SYNC/SYSREF clock path\n");
goto err_disable_oscin; return ret;
} }
for (i = 0; i < info->num_channels; i++) { for (i = 0; i < info->num_channels; i++) {
ret = lmk04832_register_clkout(lmk, i); ret = lmk04832_register_clkout(lmk, i);
if (ret) { if (ret) {
dev_err(lmk->dev, "failed to register clk %d\n", i); dev_err(lmk->dev, "failed to register clk %d\n", i);
goto err_disable_oscin; return ret;
} }
} }
@ -1541,24 +1537,12 @@ static int lmk04832_probe(struct spi_device *spi)
lmk->clk_data); lmk->clk_data);
if (ret) { if (ret) {
dev_err(lmk->dev, "failed to add provider (%d)\n", ret); dev_err(lmk->dev, "failed to add provider (%d)\n", ret);
goto err_disable_oscin; return ret;
} }
spi_set_drvdata(spi, lmk); spi_set_drvdata(spi, lmk);
return 0; return 0;
err_disable_oscin:
clk_disable_unprepare(lmk->oscin);
return ret;
}
static void lmk04832_remove(struct spi_device *spi)
{
struct lmk04832 *lmk = spi_get_drvdata(spi);
clk_disable_unprepare(lmk->oscin);
} }
static const struct spi_device_id lmk04832_id[] = { static const struct spi_device_id lmk04832_id[] = {
@ -1579,7 +1563,6 @@ static struct spi_driver lmk04832_driver = {
.of_match_table = lmk04832_of_id, .of_match_table = lmk04832_of_id,
}, },
.probe = lmk04832_probe, .probe = lmk04832_probe,
.remove = lmk04832_remove,
.id_table = lmk04832_id, .id_table = lmk04832_id,
}; };
module_spi_driver(lmk04832_driver); module_spi_driver(lmk04832_driver);

View File

@ -281,7 +281,7 @@ static struct platform_driver palmas_clks_driver = {
.of_match_table = palmas_clks_of_match, .of_match_table = palmas_clks_of_match,
}, },
.probe = palmas_clks_probe, .probe = palmas_clks_probe,
.remove_new = palmas_clks_remove, .remove = palmas_clks_remove,
}; };
module_platform_driver(palmas_clks_driver); module_platform_driver(palmas_clks_driver);

View File

@ -142,7 +142,7 @@ MODULE_DEVICE_TABLE(of, clk_pwm_dt_ids);
static struct platform_driver clk_pwm_driver = { static struct platform_driver clk_pwm_driver = {
.probe = clk_pwm_probe, .probe = clk_pwm_probe,
.remove_new = clk_pwm_remove, .remove = clk_pwm_remove,
.driver = { .driver = {
.name = "pwm-clock", .name = "pwm-clock",
.of_match_table = clk_pwm_dt_ids, .of_match_table = clk_pwm_dt_ids,

View File

@ -263,7 +263,7 @@ static struct platform_driver s2mps11_clk_driver = {
.name = "s2mps11-clk", .name = "s2mps11-clk",
}, },
.probe = s2mps11_clk_probe, .probe = s2mps11_clk_probe,
.remove_new = s2mps11_clk_remove, .remove = s2mps11_clk_remove,
.id_table = s2mps11_clk_id, .id_table = s2mps11_clk_id,
}; };
module_platform_driver(s2mps11_clk_driver); module_platform_driver(s2mps11_clk_driver);

View File

@ -156,13 +156,13 @@ static void scmi_clk_atomic_disable(struct clk_hw *hw)
scmi_proto_clk_ops->disable(clk->ph, clk->id, ATOMIC); scmi_proto_clk_ops->disable(clk->ph, clk->id, ATOMIC);
} }
static int scmi_clk_atomic_is_enabled(struct clk_hw *hw) static int __scmi_clk_is_enabled(struct clk_hw *hw, bool atomic)
{ {
int ret; int ret;
bool enabled = false; bool enabled = false;
struct scmi_clk *clk = to_scmi_clk(hw); struct scmi_clk *clk = to_scmi_clk(hw);
ret = scmi_proto_clk_ops->state_get(clk->ph, clk->id, &enabled, ATOMIC); ret = scmi_proto_clk_ops->state_get(clk->ph, clk->id, &enabled, atomic);
if (ret) if (ret)
dev_warn(clk->dev, dev_warn(clk->dev,
"Failed to get state for clock ID %d\n", clk->id); "Failed to get state for clock ID %d\n", clk->id);
@ -170,6 +170,16 @@ static int scmi_clk_atomic_is_enabled(struct clk_hw *hw)
return !!enabled; return !!enabled;
} }
static int scmi_clk_atomic_is_enabled(struct clk_hw *hw)
{
return __scmi_clk_is_enabled(hw, ATOMIC);
}
static int scmi_clk_is_enabled(struct clk_hw *hw)
{
return __scmi_clk_is_enabled(hw, NOT_ATOMIC);
}
static int scmi_clk_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) static int scmi_clk_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty)
{ {
int ret; int ret;
@ -285,6 +295,8 @@ scmi_clk_ops_alloc(struct device *dev, unsigned long feats_key)
if (feats_key & BIT(SCMI_CLK_ATOMIC_SUPPORTED)) if (feats_key & BIT(SCMI_CLK_ATOMIC_SUPPORTED))
ops->is_enabled = scmi_clk_atomic_is_enabled; ops->is_enabled = scmi_clk_atomic_is_enabled;
else
ops->is_prepared = scmi_clk_is_enabled;
/* Rate ops */ /* Rate ops */
ops->recalc_rate = scmi_clk_recalc_rate; ops->recalc_rate = scmi_clk_recalc_rate;

View File

@ -303,7 +303,7 @@ static struct platform_driver scpi_clocks_driver = {
.of_match_table = scpi_clocks_ids, .of_match_table = scpi_clocks_ids,
}, },
.probe = scpi_clocks_probe, .probe = scpi_clocks_probe,
.remove_new = scpi_clocks_remove, .remove = scpi_clocks_remove,
}; };
module_platform_driver(scpi_clocks_driver); module_platform_driver(scpi_clocks_driver);

View File

@ -4762,7 +4762,7 @@ void __clk_put(struct clk *clk)
clk->exclusive_count = 0; clk->exclusive_count = 0;
} }
hlist_del(&clk->clks_node); clk_core_unlink_consumer(clk);
/* If we had any boundaries on that clock, let's drop them. */ /* If we had any boundaries on that clock, let's drop them. */
if (clk->min_rate > 0 || clk->max_rate < ULONG_MAX) if (clk->min_rate > 0 || clk->max_rate < ULONG_MAX)
@ -5232,7 +5232,7 @@ static int of_parse_clkspec(const struct device_node *np, int index,
* clocks. * clocks.
*/ */
np = np->parent; np = np->parent;
if (np && !of_get_property(np, "clock-ranges", NULL)) if (np && !of_property_present(np, "clock-ranges"))
break; break;
index = 0; index = 0;
} }

View File

@ -0,0 +1,207 @@
// SPDX-License-Identifier: GPL-2.0
/*
* KUnit helpers for clk providers and consumers
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <kunit/clk.h>
#include <kunit/resource.h>
KUNIT_DEFINE_ACTION_WRAPPER(clk_disable_unprepare_wrapper,
clk_disable_unprepare, struct clk *);
/**
* clk_prepare_enable_kunit() - Test managed clk_prepare_enable()
* @test: The test context
* @clk: clk to prepare and enable
*
* Return: 0 on success, or negative errno on failure.
*/
int clk_prepare_enable_kunit(struct kunit *test, struct clk *clk)
{
int ret;
ret = clk_prepare_enable(clk);
if (ret)
return ret;
return kunit_add_action_or_reset(test, clk_disable_unprepare_wrapper,
clk);
}
EXPORT_SYMBOL_GPL(clk_prepare_enable_kunit);
KUNIT_DEFINE_ACTION_WRAPPER(clk_put_wrapper, clk_put, struct clk *);
static struct clk *__clk_get_kunit(struct kunit *test, struct clk *clk)
{
int ret;
if (IS_ERR(clk))
return clk;
ret = kunit_add_action_or_reset(test, clk_put_wrapper, clk);
if (ret)
return ERR_PTR(ret);
return clk;
}
/**
* clk_get_kunit() - Test managed clk_get()
* @test: The test context
* @dev: device for clock "consumer"
* @con_id: clock consumer ID
*
* Just like clk_get(), except the clk is managed by the test case and is
* automatically put with clk_put() after the test case concludes.
*
* Return: new clk consumer or ERR_PTR on failure.
*/
struct clk *
clk_get_kunit(struct kunit *test, struct device *dev, const char *con_id)
{
struct clk *clk;
clk = clk_get(dev, con_id);
return __clk_get_kunit(test, clk);
}
EXPORT_SYMBOL_GPL(clk_get_kunit);
/**
* of_clk_get_kunit() - Test managed of_clk_get()
* @test: The test context
* @np: device_node for clock "consumer"
* @index: index in 'clocks' property of @np
*
* Just like of_clk_get(), except the clk is managed by the test case and is
* automatically put with clk_put() after the test case concludes.
*
* Return: new clk consumer or ERR_PTR on failure.
*/
struct clk *
of_clk_get_kunit(struct kunit *test, struct device_node *np, int index)
{
struct clk *clk;
clk = of_clk_get(np, index);
return __clk_get_kunit(test, clk);
}
EXPORT_SYMBOL_GPL(of_clk_get_kunit);
/**
* clk_hw_get_clk_kunit() - Test managed clk_hw_get_clk()
* @test: The test context
* @hw: clk_hw associated with the clk being consumed
* @con_id: connection ID string on device
*
* Just like clk_hw_get_clk(), except the clk is managed by the test case and
* is automatically put with clk_put() after the test case concludes.
*
* Return: new clk consumer or ERR_PTR on failure.
*/
struct clk *
clk_hw_get_clk_kunit(struct kunit *test, struct clk_hw *hw, const char *con_id)
{
struct clk *clk;
clk = clk_hw_get_clk(hw, con_id);
return __clk_get_kunit(test, clk);
}
EXPORT_SYMBOL_GPL(clk_hw_get_clk_kunit);
/**
* clk_hw_get_clk_prepared_enabled_kunit() - Test managed clk_hw_get_clk() + clk_prepare_enable()
* @test: The test context
* @hw: clk_hw associated with the clk being consumed
* @con_id: connection ID string on device
*
* Just like
*
* .. code-block:: c
*
* struct clk *clk = clk_hw_get_clk(...);
* clk_prepare_enable(clk);
*
* except the clk is managed by the test case and is automatically disabled and
* unprepared with clk_disable_unprepare() and put with clk_put() after the
* test case concludes.
*
* Return: new clk consumer that is prepared and enabled or ERR_PTR on failure.
*/
struct clk *
clk_hw_get_clk_prepared_enabled_kunit(struct kunit *test, struct clk_hw *hw,
const char *con_id)
{
int ret;
struct clk *clk;
clk = clk_hw_get_clk_kunit(test, hw, con_id);
if (IS_ERR(clk))
return clk;
ret = clk_prepare_enable_kunit(test, clk);
if (ret)
return ERR_PTR(ret);
return clk;
}
EXPORT_SYMBOL_GPL(clk_hw_get_clk_prepared_enabled_kunit);
KUNIT_DEFINE_ACTION_WRAPPER(clk_hw_unregister_wrapper,
clk_hw_unregister, struct clk_hw *);
/**
* clk_hw_register_kunit() - Test managed clk_hw_register()
* @test: The test context
* @dev: device that is registering this clock
* @hw: link to hardware-specific clock data
*
* Just like clk_hw_register(), except the clk registration is managed by the
* test case and is automatically unregistered after the test case concludes.
*
* Return: 0 on success or a negative errno value on failure.
*/
int clk_hw_register_kunit(struct kunit *test, struct device *dev, struct clk_hw *hw)
{
int ret;
ret = clk_hw_register(dev, hw);
if (ret)
return ret;
return kunit_add_action_or_reset(test, clk_hw_unregister_wrapper, hw);
}
EXPORT_SYMBOL_GPL(clk_hw_register_kunit);
/**
* of_clk_hw_register_kunit() - Test managed of_clk_hw_register()
* @test: The test context
* @node: device_node of device that is registering this clock
* @hw: link to hardware-specific clock data
*
* Just like of_clk_hw_register(), except the clk registration is managed by
* the test case and is automatically unregistered after the test case
* concludes.
*
* Return: 0 on success or a negative errno value on failure.
*/
int of_clk_hw_register_kunit(struct kunit *test, struct device_node *node, struct clk_hw *hw)
{
int ret;
ret = of_clk_hw_register(node, hw);
if (ret)
return ret;
return kunit_add_action_or_reset(test, clk_hw_unregister_wrapper, hw);
}
EXPORT_SYMBOL_GPL(of_clk_hw_register_kunit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("KUnit helpers for clk providers and consumers");

View File

@ -0,0 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _CLK_PARENT_DATA_TEST_H
#define _CLK_PARENT_DATA_TEST_H
#define CLK_PARENT_DATA_1MHZ_NAME "1mhz_fixed_legacy"
#define CLK_PARENT_DATA_PARENT1 "parent_fwname"
#define CLK_PARENT_DATA_PARENT2 "50"
#define CLK_PARENT_DATA_50MHZ_NAME "50_clk"
#endif

View File

@ -4,12 +4,19 @@
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/platform_device.h>
/* Needed for clk_hw_get_clk() */ /* Needed for clk_hw_get_clk() */
#include "clk.h" #include "clk.h"
#include <kunit/clk.h>
#include <kunit/of.h>
#include <kunit/platform_device.h>
#include <kunit/test.h> #include <kunit/test.h>
#include "clk_parent_data_test.h"
static const struct clk_ops empty_clk_ops = { }; static const struct clk_ops empty_clk_ops = { };
#define DUMMY_CLOCK_INIT_RATE (42 * 1000 * 1000) #define DUMMY_CLOCK_INIT_RATE (42 * 1000 * 1000)
@ -2659,6 +2666,448 @@ static struct kunit_suite clk_mux_no_reparent_test_suite = {
.test_cases = clk_mux_no_reparent_test_cases, .test_cases = clk_mux_no_reparent_test_cases,
}; };
struct clk_register_clk_parent_data_test_case {
const char *desc;
struct clk_parent_data pdata;
};
static void
clk_register_clk_parent_data_test_case_to_desc(
const struct clk_register_clk_parent_data_test_case *t, char *desc)
{
strcpy(desc, t->desc);
}
static const struct clk_register_clk_parent_data_test_case
clk_register_clk_parent_data_of_cases[] = {
{
/*
* Test that a clk registered with a struct device_node can
* find a parent based on struct clk_parent_data::index.
*/
.desc = "clk_parent_data_of_index_test",
.pdata.index = 0,
},
{
/*
* Test that a clk registered with a struct device_node can
* find a parent based on struct clk_parent_data::fwname.
*/
.desc = "clk_parent_data_of_fwname_test",
.pdata.fw_name = CLK_PARENT_DATA_PARENT1,
},
{
/*
* Test that a clk registered with a struct device_node can
* find a parent based on struct clk_parent_data::name.
*/
.desc = "clk_parent_data_of_name_test",
/* The index must be negative to indicate firmware not used */
.pdata.index = -1,
.pdata.name = CLK_PARENT_DATA_1MHZ_NAME,
},
{
/*
* Test that a clk registered with a struct device_node can
* find a parent based on struct
* clk_parent_data::{fw_name,name}.
*/
.desc = "clk_parent_data_of_fwname_name_test",
.pdata.fw_name = CLK_PARENT_DATA_PARENT1,
.pdata.name = "not_matching",
},
{
/*
* Test that a clk registered with a struct device_node can
* find a parent based on struct clk_parent_data::{index,name}.
* Index takes priority.
*/
.desc = "clk_parent_data_of_index_name_priority_test",
.pdata.index = 0,
.pdata.name = "not_matching",
},
{
/*
* Test that a clk registered with a struct device_node can
* find a parent based on struct
* clk_parent_data::{index,fwname,name}. The fw_name takes
* priority over index and name.
*/
.desc = "clk_parent_data_of_index_fwname_name_priority_test",
.pdata.index = 1,
.pdata.fw_name = CLK_PARENT_DATA_PARENT1,
.pdata.name = "not_matching",
},
};
KUNIT_ARRAY_PARAM(clk_register_clk_parent_data_of_test, clk_register_clk_parent_data_of_cases,
clk_register_clk_parent_data_test_case_to_desc)
/**
* struct clk_register_clk_parent_data_of_ctx - Context for clk_parent_data OF tests
* @np: device node of clk under test
* @hw: clk_hw for clk under test
*/
struct clk_register_clk_parent_data_of_ctx {
struct device_node *np;
struct clk_hw hw;
};
static int clk_register_clk_parent_data_of_test_init(struct kunit *test)
{
struct clk_register_clk_parent_data_of_ctx *ctx;
KUNIT_ASSERT_EQ(test, 0,
of_overlay_apply_kunit(test, kunit_clk_parent_data_test));
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
test->priv = ctx;
ctx->np = of_find_compatible_node(NULL, NULL, "test,clk-parent-data");
if (!ctx->np)
return -ENODEV;
of_node_put_kunit(test, ctx->np);
return 0;
}
/*
* Test that a clk registered with a struct device_node can find a parent based on
* struct clk_parent_data when the hw member isn't set.
*/
static void clk_register_clk_parent_data_of_test(struct kunit *test)
{
struct clk_register_clk_parent_data_of_ctx *ctx = test->priv;
struct clk_hw *parent_hw;
const struct clk_register_clk_parent_data_test_case *test_param;
struct clk_init_data init = { };
struct clk *expected_parent, *actual_parent;
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->np);
expected_parent = of_clk_get_kunit(test, ctx->np, 0);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, expected_parent);
test_param = test->param_value;
init.parent_data = &test_param->pdata;
init.num_parents = 1;
init.name = "parent_data_of_test_clk";
init.ops = &clk_dummy_single_parent_ops;
ctx->hw.init = &init;
KUNIT_ASSERT_EQ(test, 0, of_clk_hw_register_kunit(test, ctx->np, &ctx->hw));
parent_hw = clk_hw_get_parent(&ctx->hw);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_hw);
actual_parent = clk_hw_get_clk_kunit(test, parent_hw, __func__);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, actual_parent);
KUNIT_EXPECT_TRUE(test, clk_is_match(expected_parent, actual_parent));
}
static struct kunit_case clk_register_clk_parent_data_of_test_cases[] = {
KUNIT_CASE_PARAM(clk_register_clk_parent_data_of_test,
clk_register_clk_parent_data_of_test_gen_params),
{}
};
/*
* Test suite for registering clks with struct clk_parent_data and a struct
* device_node.
*/
static struct kunit_suite clk_register_clk_parent_data_of_suite = {
.name = "clk_register_clk_parent_data_of",
.init = clk_register_clk_parent_data_of_test_init,
.test_cases = clk_register_clk_parent_data_of_test_cases,
};
/**
* struct clk_register_clk_parent_data_device_ctx - Context for clk_parent_data device tests
* @dev: device of clk under test
* @hw: clk_hw for clk under test
* @pdrv: driver to attach to find @dev
*/
struct clk_register_clk_parent_data_device_ctx {
struct device *dev;
struct clk_hw hw;
struct platform_driver pdrv;
};
static inline struct clk_register_clk_parent_data_device_ctx *
clk_register_clk_parent_data_driver_to_test_context(struct platform_device *pdev)
{
return container_of(to_platform_driver(pdev->dev.driver),
struct clk_register_clk_parent_data_device_ctx, pdrv);
}
static int clk_register_clk_parent_data_device_probe(struct platform_device *pdev)
{
struct clk_register_clk_parent_data_device_ctx *ctx;
ctx = clk_register_clk_parent_data_driver_to_test_context(pdev);
ctx->dev = &pdev->dev;
return 0;
}
static void clk_register_clk_parent_data_device_driver(struct kunit *test)
{
struct clk_register_clk_parent_data_device_ctx *ctx = test->priv;
static const struct of_device_id match_table[] = {
{ .compatible = "test,clk-parent-data" },
{ }
};
ctx->pdrv.probe = clk_register_clk_parent_data_device_probe;
ctx->pdrv.driver.of_match_table = match_table;
ctx->pdrv.driver.name = __func__;
ctx->pdrv.driver.owner = THIS_MODULE;
KUNIT_ASSERT_EQ(test, 0, kunit_platform_driver_register(test, &ctx->pdrv));
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->dev);
}
static const struct clk_register_clk_parent_data_test_case
clk_register_clk_parent_data_device_cases[] = {
{
/*
* Test that a clk registered with a struct device can find a
* parent based on struct clk_parent_data::index.
*/
.desc = "clk_parent_data_device_index_test",
.pdata.index = 1,
},
{
/*
* Test that a clk registered with a struct device can find a
* parent based on struct clk_parent_data::fwname.
*/
.desc = "clk_parent_data_device_fwname_test",
.pdata.fw_name = CLK_PARENT_DATA_PARENT2,
},
{
/*
* Test that a clk registered with a struct device can find a
* parent based on struct clk_parent_data::name.
*/
.desc = "clk_parent_data_device_name_test",
/* The index must be negative to indicate firmware not used */
.pdata.index = -1,
.pdata.name = CLK_PARENT_DATA_50MHZ_NAME,
},
{
/*
* Test that a clk registered with a struct device can find a
* parent based on struct clk_parent_data::{fw_name,name}.
*/
.desc = "clk_parent_data_device_fwname_name_test",
.pdata.fw_name = CLK_PARENT_DATA_PARENT2,
.pdata.name = "not_matching",
},
{
/*
* Test that a clk registered with a struct device can find a
* parent based on struct clk_parent_data::{index,name}. Index
* takes priority.
*/
.desc = "clk_parent_data_device_index_name_priority_test",
.pdata.index = 1,
.pdata.name = "not_matching",
},
{
/*
* Test that a clk registered with a struct device can find a
* parent based on struct clk_parent_data::{index,fwname,name}.
* The fw_name takes priority over index and name.
*/
.desc = "clk_parent_data_device_index_fwname_name_priority_test",
.pdata.index = 0,
.pdata.fw_name = CLK_PARENT_DATA_PARENT2,
.pdata.name = "not_matching",
},
};
KUNIT_ARRAY_PARAM(clk_register_clk_parent_data_device_test,
clk_register_clk_parent_data_device_cases,
clk_register_clk_parent_data_test_case_to_desc)
/*
* Test that a clk registered with a struct device can find a parent based on
* struct clk_parent_data when the hw member isn't set.
*/
static void clk_register_clk_parent_data_device_test(struct kunit *test)
{
struct clk_register_clk_parent_data_device_ctx *ctx;
const struct clk_register_clk_parent_data_test_case *test_param;
struct clk_hw *parent_hw;
struct clk_init_data init = { };
struct clk *expected_parent, *actual_parent;
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
test->priv = ctx;
clk_register_clk_parent_data_device_driver(test);
expected_parent = clk_get_kunit(test, ctx->dev, "50");
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, expected_parent);
test_param = test->param_value;
init.parent_data = &test_param->pdata;
init.num_parents = 1;
init.name = "parent_data_device_test_clk";
init.ops = &clk_dummy_single_parent_ops;
ctx->hw.init = &init;
KUNIT_ASSERT_EQ(test, 0, clk_hw_register_kunit(test, ctx->dev, &ctx->hw));
parent_hw = clk_hw_get_parent(&ctx->hw);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_hw);
actual_parent = clk_hw_get_clk_kunit(test, parent_hw, __func__);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, actual_parent);
KUNIT_EXPECT_TRUE(test, clk_is_match(expected_parent, actual_parent));
}
static const struct clk_register_clk_parent_data_test_case
clk_register_clk_parent_data_device_hw_cases[] = {
{
/*
* Test that a clk registered with a struct device can find a
* parent based on struct clk_parent_data::hw.
*/
.desc = "clk_parent_data_device_hw_index_test",
/* The index must be negative to indicate firmware not used */
.pdata.index = -1,
},
{
/*
* Test that a clk registered with a struct device can find a
* parent based on struct clk_parent_data::hw when
* struct clk_parent_data::fw_name is set.
*/
.desc = "clk_parent_data_device_hw_fwname_test",
.pdata.fw_name = CLK_PARENT_DATA_PARENT2,
},
{
/*
* Test that a clk registered with a struct device can find a
* parent based on struct clk_parent_data::hw when struct
* clk_parent_data::name is set.
*/
.desc = "clk_parent_data_device_hw_name_test",
/* The index must be negative to indicate firmware not used */
.pdata.index = -1,
.pdata.name = CLK_PARENT_DATA_50MHZ_NAME,
},
{
/*
* Test that a clk registered with a struct device can find a
* parent based on struct clk_parent_data::hw when struct
* clk_parent_data::{fw_name,name} are set.
*/
.desc = "clk_parent_data_device_hw_fwname_name_test",
.pdata.fw_name = CLK_PARENT_DATA_PARENT2,
.pdata.name = "not_matching",
},
{
/*
* Test that a clk registered with a struct device can find a
* parent based on struct clk_parent_data::hw when struct
* clk_parent_data::index is set. The hw pointer takes
* priority.
*/
.desc = "clk_parent_data_device_hw_index_priority_test",
.pdata.index = 0,
},
{
/*
* Test that a clk registered with a struct device can find a
* parent based on struct clk_parent_data::hw when
* struct clk_parent_data::{index,fwname,name} are set.
* The hw pointer takes priority over everything else.
*/
.desc = "clk_parent_data_device_hw_index_fwname_name_priority_test",
.pdata.index = 0,
.pdata.fw_name = CLK_PARENT_DATA_PARENT2,
.pdata.name = "not_matching",
},
};
KUNIT_ARRAY_PARAM(clk_register_clk_parent_data_device_hw_test,
clk_register_clk_parent_data_device_hw_cases,
clk_register_clk_parent_data_test_case_to_desc)
/*
* Test that a clk registered with a struct device can find a
* parent based on struct clk_parent_data::hw.
*/
static void clk_register_clk_parent_data_device_hw_test(struct kunit *test)
{
struct clk_register_clk_parent_data_device_ctx *ctx;
const struct clk_register_clk_parent_data_test_case *test_param;
struct clk_dummy_context *parent;
struct clk_hw *parent_hw;
struct clk_parent_data pdata = { };
struct clk_init_data init = { };
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
test->priv = ctx;
clk_register_clk_parent_data_device_driver(test);
parent = kunit_kzalloc(test, sizeof(*parent), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
parent_hw = &parent->hw;
parent_hw->init = CLK_HW_INIT_NO_PARENT("parent-clk",
&clk_dummy_rate_ops, 0);
KUNIT_ASSERT_EQ(test, 0, clk_hw_register_kunit(test, ctx->dev, parent_hw));
test_param = test->param_value;
memcpy(&pdata, &test_param->pdata, sizeof(pdata));
pdata.hw = parent_hw;
init.parent_data = &pdata;
init.num_parents = 1;
init.ops = &clk_dummy_single_parent_ops;
init.name = "parent_data_device_hw_test_clk";
ctx->hw.init = &init;
KUNIT_ASSERT_EQ(test, 0, clk_hw_register_kunit(test, ctx->dev, &ctx->hw));
KUNIT_EXPECT_PTR_EQ(test, parent_hw, clk_hw_get_parent(&ctx->hw));
}
static struct kunit_case clk_register_clk_parent_data_device_test_cases[] = {
KUNIT_CASE_PARAM(clk_register_clk_parent_data_device_test,
clk_register_clk_parent_data_device_test_gen_params),
KUNIT_CASE_PARAM(clk_register_clk_parent_data_device_hw_test,
clk_register_clk_parent_data_device_hw_test_gen_params),
{}
};
static int clk_register_clk_parent_data_device_init(struct kunit *test)
{
KUNIT_ASSERT_EQ(test, 0,
of_overlay_apply_kunit(test, kunit_clk_parent_data_test));
return 0;
}
/*
* Test suite for registering clks with struct clk_parent_data and a struct
* device.
*/
static struct kunit_suite clk_register_clk_parent_data_device_suite = {
.name = "clk_register_clk_parent_data_device",
.init = clk_register_clk_parent_data_device_init,
.test_cases = clk_register_clk_parent_data_device_test_cases,
};
kunit_test_suites( kunit_test_suites(
&clk_leaf_mux_set_rate_parent_test_suite, &clk_leaf_mux_set_rate_parent_test_suite,
&clk_test_suite, &clk_test_suite,
@ -2671,8 +3120,10 @@ kunit_test_suites(
&clk_range_test_suite, &clk_range_test_suite,
&clk_range_maximize_test_suite, &clk_range_maximize_test_suite,
&clk_range_minimize_test_suite, &clk_range_minimize_test_suite,
&clk_register_clk_parent_data_of_suite,
&clk_register_clk_parent_data_device_suite,
&clk_single_parent_mux_test_suite, &clk_single_parent_mux_test_suite,
&clk_uncached_test_suite &clk_uncached_test_suite,
); );
MODULE_DESCRIPTION("Kunit tests for clk framework"); MODULE_DESCRIPTION("Kunit tests for clk framework");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");

View File

@ -513,8 +513,7 @@ da8xx_cfgchip_register_usb0_clk48(struct device *dev,
fck_clk = devm_clk_get(dev, "fck"); fck_clk = devm_clk_get(dev, "fck");
if (IS_ERR(fck_clk)) { if (IS_ERR(fck_clk)) {
dev_err_probe(dev, PTR_ERR(fck_clk), "Missing fck clock\n"); return dev_err_cast_probe(dev, fck_clk, "Missing fck clock\n");
return ERR_CAST(fck_clk);
} }
usb0 = devm_kzalloc(dev, sizeof(*usb0), GFP_KERNEL); usb0 = devm_kzalloc(dev, sizeof(*usb0), GFP_KERNEL);
@ -749,11 +748,9 @@ static int da8xx_cfgchip_probe(struct platform_device *pdev)
clk_init = device_get_match_data(dev); clk_init = device_get_match_data(dev);
if (clk_init) { if (clk_init) {
struct device_node *parent; struct device_node *parent __free(device_node) = of_get_parent(dev->of_node);
parent = of_get_parent(dev->of_node);
regmap = syscon_node_to_regmap(parent); regmap = syscon_node_to_regmap(parent);
of_node_put(parent);
} else if (pdev->id_entry && pdata) { } else if (pdev->id_entry && pdata) {
clk_init = (void *)pdev->id_entry->driver_data; clk_init = (void *)pdev->id_entry->driver_data;
regmap = pdata->cfgchip; regmap = pdata->cfgchip;

View File

@ -179,7 +179,7 @@ MODULE_DEVICE_TABLE(of, hi3519_clk_match_table);
static struct platform_driver hi3519_clk_driver = { static struct platform_driver hi3519_clk_driver = {
.probe = hi3519_clk_probe, .probe = hi3519_clk_probe,
.remove_new = hi3519_clk_remove, .remove = hi3519_clk_remove,
.driver = { .driver = {
.name = "hi3519-clk", .name = "hi3519-clk",
.of_match_table = hi3519_clk_match_table, .of_match_table = hi3519_clk_match_table,

View File

@ -407,7 +407,7 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct hi3559av100_clk_pll *clk = to_pll_clk(hw); struct hi3559av100_clk_pll *clk = to_pll_clk(hw);
u64 frac_val, fbdiv_val, refdiv_val; u64 frac_val, fbdiv_val;
u32 postdiv1_val, postdiv2_val; u32 postdiv1_val, postdiv2_val;
u32 val; u32 val;
u64 tmp, rate; u64 tmp, rate;
@ -435,14 +435,13 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
val = readl_relaxed(clk->ctrl_reg2); val = readl_relaxed(clk->ctrl_reg2);
val = val >> clk->refdiv_shift; val = val >> clk->refdiv_shift;
val &= ((1 << clk->refdiv_width) - 1); val &= ((1 << clk->refdiv_width) - 1);
refdiv_val = val;
/* rate = 24000000 * (fbdiv + frac / (1<<24) ) / refdiv */ /* rate = 24000000 * (fbdiv + frac / (1<<24) ) / refdiv */
rate = 0; rate = 0;
tmp = 24000000 * fbdiv_val + (24000000 * frac_val) / (1 << 24); tmp = 24000000 * fbdiv_val + (24000000 * frac_val) / (1 << 24);
rate += tmp; rate += tmp;
do_div(rate, refdiv_val); rate = div_u64(rate, val);
do_div(rate, postdiv1_val * postdiv2_val); rate = div_u64(rate, postdiv1_val * postdiv2_val);
return rate; return rate;
} }
@ -818,7 +817,7 @@ static void hi3559av100_crg_remove(struct platform_device *pdev)
static struct platform_driver hi3559av100_crg_driver = { static struct platform_driver hi3559av100_crg_driver = {
.probe = hi3559av100_crg_probe, .probe = hi3559av100_crg_probe,
.remove_new = hi3559av100_crg_remove, .remove = hi3559av100_crg_remove,
.driver = { .driver = {
.name = "hi3559av100-clock", .name = "hi3559av100-clock",
.of_match_table = hi3559av100_crg_match_table, .of_match_table = hi3559av100_crg_match_table,

View File

@ -294,7 +294,7 @@ static void hi3516cv300_crg_remove(struct platform_device *pdev)
static struct platform_driver hi3516cv300_crg_driver = { static struct platform_driver hi3516cv300_crg_driver = {
.probe = hi3516cv300_crg_probe, .probe = hi3516cv300_crg_probe,
.remove_new = hi3516cv300_crg_remove, .remove = hi3516cv300_crg_remove,
.driver = { .driver = {
.name = "hi3516cv300-crg", .name = "hi3516cv300-crg",
.of_match_table = hi3516cv300_crg_match_table, .of_match_table = hi3516cv300_crg_match_table,

View File

@ -377,7 +377,7 @@ static void hi3798cv200_crg_remove(struct platform_device *pdev)
static struct platform_driver hi3798cv200_crg_driver = { static struct platform_driver hi3798cv200_crg_driver = {
.probe = hi3798cv200_crg_probe, .probe = hi3798cv200_crg_probe,
.remove_new = hi3798cv200_crg_remove, .remove = hi3798cv200_crg_remove,
.driver = { .driver = {
.name = "hi3798cv200-crg", .name = "hi3798cv200-crg",
.of_match_table = hi3798cv200_crg_match_table, .of_match_table = hi3798cv200_crg_match_table,

View File

@ -81,6 +81,7 @@ config CLK_IMX8MP
tristate "IMX8MP CCM Clock Driver" tristate "IMX8MP CCM Clock Driver"
depends on ARCH_MXC || COMPILE_TEST depends on ARCH_MXC || COMPILE_TEST
select MXC_CLK select MXC_CLK
select AUXILIARY_BUS if RESET_CONTROLLER
help help
Build the driver for i.MX8MP CCM Clock Driver Build the driver for i.MX8MP CCM Clock Driver

View File

@ -14,6 +14,7 @@
#include "../clk-fractional-divider.h" #include "../clk-fractional-divider.h"
#include "clk.h" #include "clk.h"
#define PCG_PR_MASK BIT(31)
#define PCG_PCS_SHIFT 24 #define PCG_PCS_SHIFT 24
#define PCG_PCS_MASK 0x7 #define PCG_PCS_MASK 0x7
#define PCG_CGC_SHIFT 30 #define PCG_CGC_SHIFT 30
@ -78,6 +79,12 @@ static struct clk_hw *imx_ulp_clk_hw_composite(const char *name,
struct clk_hw *hw; struct clk_hw *hw;
u32 val; u32 val;
val = readl(reg);
if (!(val & PCG_PR_MASK)) {
pr_info("PCC PR is 0 for clk:%s, bypass\n", name);
return NULL;
}
if (mux_present) { if (mux_present) {
mux = kzalloc(sizeof(*mux), GFP_KERNEL); mux = kzalloc(sizeof(*mux), GFP_KERNEL);
if (!mux) if (!mux)

View File

@ -204,6 +204,34 @@ static const struct clk_ops imx8m_clk_composite_mux_ops = {
.determine_rate = imx8m_clk_composite_mux_determine_rate, .determine_rate = imx8m_clk_composite_mux_determine_rate,
}; };
static int imx8m_clk_composite_gate_enable(struct clk_hw *hw)
{
struct clk_gate *gate = to_clk_gate(hw);
unsigned long flags;
u32 val;
spin_lock_irqsave(gate->lock, flags);
val = readl(gate->reg);
val |= BIT(gate->bit_idx);
writel(val, gate->reg);
spin_unlock_irqrestore(gate->lock, flags);
return 0;
}
static void imx8m_clk_composite_gate_disable(struct clk_hw *hw)
{
/* composite clk requires the disable hook */
}
static const struct clk_ops imx8m_clk_composite_gate_ops = {
.enable = imx8m_clk_composite_gate_enable,
.disable = imx8m_clk_composite_gate_disable,
.is_enabled = clk_gate_is_enabled,
};
struct clk_hw *__imx8m_clk_hw_composite(const char *name, struct clk_hw *__imx8m_clk_hw_composite(const char *name,
const char * const *parent_names, const char * const *parent_names,
int num_parents, void __iomem *reg, int num_parents, void __iomem *reg,
@ -217,6 +245,7 @@ struct clk_hw *__imx8m_clk_hw_composite(const char *name,
struct clk_mux *mux; struct clk_mux *mux;
const struct clk_ops *divider_ops; const struct clk_ops *divider_ops;
const struct clk_ops *mux_ops; const struct clk_ops *mux_ops;
const struct clk_ops *gate_ops;
mux = kzalloc(sizeof(*mux), GFP_KERNEL); mux = kzalloc(sizeof(*mux), GFP_KERNEL);
if (!mux) if (!mux)
@ -257,20 +286,22 @@ struct clk_hw *__imx8m_clk_hw_composite(const char *name,
div->flags = CLK_DIVIDER_ROUND_CLOSEST; div->flags = CLK_DIVIDER_ROUND_CLOSEST;
/* skip registering the gate ops if M4 is enabled */ /* skip registering the gate ops if M4 is enabled */
if (!mcore_booted) { gate = kzalloc(sizeof(*gate), GFP_KERNEL);
gate = kzalloc(sizeof(*gate), GFP_KERNEL); if (!gate)
if (!gate) goto free_div;
goto free_div;
gate_hw = &gate->hw; gate_hw = &gate->hw;
gate->reg = reg; gate->reg = reg;
gate->bit_idx = PCG_CGC_SHIFT; gate->bit_idx = PCG_CGC_SHIFT;
gate->lock = &imx_ccm_lock; gate->lock = &imx_ccm_lock;
} if (!mcore_booted)
gate_ops = &clk_gate_ops;
else
gate_ops = &imx8m_clk_composite_gate_ops;
hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
mux_hw, mux_ops, div_hw, mux_hw, mux_ops, div_hw,
divider_ops, gate_hw, &clk_gate_ops, flags); divider_ops, gate_hw, gate_ops, flags);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto free_gate; goto free_gate;

View File

@ -76,6 +76,13 @@ static int imx93_clk_composite_gate_enable(struct clk_hw *hw)
static void imx93_clk_composite_gate_disable(struct clk_hw *hw) static void imx93_clk_composite_gate_disable(struct clk_hw *hw)
{ {
/*
* Skip disable the root clock gate if mcore enabled.
* The root clock may be used by the mcore.
*/
if (mcore_booted)
return;
imx93_clk_composite_gate_endisable(hw, 0); imx93_clk_composite_gate_endisable(hw, 0);
} }
@ -222,7 +229,7 @@ struct clk_hw *imx93_clk_composite_flags(const char *name, const char * const *p
hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
mux_hw, &clk_mux_ro_ops, div_hw, mux_hw, &clk_mux_ro_ops, div_hw,
&clk_divider_ro_ops, NULL, NULL, flags); &clk_divider_ro_ops, NULL, NULL, flags);
} else if (!mcore_booted) { } else {
gate = kzalloc(sizeof(*gate), GFP_KERNEL); gate = kzalloc(sizeof(*gate), GFP_KERNEL);
if (!gate) if (!gate)
goto fail; goto fail;
@ -238,12 +245,6 @@ struct clk_hw *imx93_clk_composite_flags(const char *name, const char * const *p
&imx93_clk_composite_divider_ops, gate_hw, &imx93_clk_composite_divider_ops, gate_hw,
&imx93_clk_composite_gate_ops, &imx93_clk_composite_gate_ops,
flags | CLK_SET_RATE_NO_REPARENT); flags | CLK_SET_RATE_NO_REPARENT);
} else {
hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
mux_hw, &imx93_clk_composite_mux_ops, div_hw,
&imx93_clk_composite_divider_ops, NULL,
&imx93_clk_composite_gate_ops,
flags | CLK_SET_RATE_NO_REPARENT);
} }
if (IS_ERR(hw)) if (IS_ERR(hw))

View File

@ -78,6 +78,7 @@ struct clk_fracn_gppll {
* The Fvco should be in range 2.5Ghz to 5Ghz * The Fvco should be in range 2.5Ghz to 5Ghz
*/ */
static const struct imx_fracn_gppll_rate_table fracn_tbl[] = { static const struct imx_fracn_gppll_rate_table fracn_tbl[] = {
PLL_FRACN_GP(1039500000U, 173, 25, 100, 1, 4),
PLL_FRACN_GP(650000000U, 162, 50, 100, 0, 6), PLL_FRACN_GP(650000000U, 162, 50, 100, 0, 6),
PLL_FRACN_GP(594000000U, 198, 0, 1, 0, 8), PLL_FRACN_GP(594000000U, 198, 0, 1, 0, 8),
PLL_FRACN_GP(560000000U, 140, 0, 1, 0, 6), PLL_FRACN_GP(560000000U, 140, 0, 1, 0, 6),
@ -106,6 +107,7 @@ static const struct imx_fracn_gppll_rate_table int_tbl[] = {
PLL_FRACN_GP_INTEGER(1700000000U, 141, 1, 2), PLL_FRACN_GP_INTEGER(1700000000U, 141, 1, 2),
PLL_FRACN_GP_INTEGER(1400000000U, 175, 1, 3), PLL_FRACN_GP_INTEGER(1400000000U, 175, 1, 3),
PLL_FRACN_GP_INTEGER(900000000U, 150, 1, 4), PLL_FRACN_GP_INTEGER(900000000U, 150, 1, 4),
PLL_FRACN_GP_INTEGER(800000000U, 200, 1, 6),
}; };
struct imx_fracn_gppll_clk imx_fracn_gppll_integer = { struct imx_fracn_gppll_clk imx_fracn_gppll_integer = {
@ -291,6 +293,10 @@ static int clk_fracn_gppll_prepare(struct clk_hw *hw)
if (val & POWERUP_MASK) if (val & POWERUP_MASK)
return 0; return 0;
if (pll->flags & CLK_FRACN_GPPLL_FRACN)
writel_relaxed(readl_relaxed(pll->base + PLL_NUMERATOR),
pll->base + PLL_NUMERATOR);
val |= CLKMUX_BYPASS; val |= CLKMUX_BYPASS;
writel_relaxed(val, pll->base + PLL_CTRL); writel_relaxed(val, pll->base + PLL_CTRL);

View File

@ -542,8 +542,8 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clk_set_parent(hws[IMX6UL_CLK_ENFC_SEL]->clk, hws[IMX6UL_CLK_PLL2_PFD2]->clk); clk_set_parent(hws[IMX6UL_CLK_ENFC_SEL]->clk, hws[IMX6UL_CLK_PLL2_PFD2]->clk);
clk_set_parent(hws[IMX6UL_CLK_ENET1_REF_SEL]->clk, hws[IMX6UL_CLK_ENET_REF]->clk); clk_set_parent(hws[IMX6UL_CLK_ENET1_REF_SEL]->clk, hws[IMX6UL_CLK_ENET1_REF_125M]->clk);
clk_set_parent(hws[IMX6UL_CLK_ENET2_REF_SEL]->clk, hws[IMX6UL_CLK_ENET2_REF]->clk); clk_set_parent(hws[IMX6UL_CLK_ENET2_REF_SEL]->clk, hws[IMX6UL_CLK_ENET2_REF_125M]->clk);
imx_register_uart_clocks(); imx_register_uart_clocks();
} }

View File

@ -498,14 +498,14 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
hws[IMX7D_ENET_AXI_ROOT_SRC] = imx_clk_hw_mux2_flags("enet_axi_src", base + 0x8900, 24, 3, enet_axi_sel, ARRAY_SIZE(enet_axi_sel), CLK_SET_PARENT_GATE); hws[IMX7D_ENET_AXI_ROOT_SRC] = imx_clk_hw_mux2_flags("enet_axi_src", base + 0x8900, 24, 3, enet_axi_sel, ARRAY_SIZE(enet_axi_sel), CLK_SET_PARENT_GATE);
hws[IMX7D_NAND_USDHC_BUS_ROOT_SRC] = imx_clk_hw_mux2_flags("nand_usdhc_src", base + 0x8980, 24, 3, nand_usdhc_bus_sel, ARRAY_SIZE(nand_usdhc_bus_sel), CLK_SET_PARENT_GATE); hws[IMX7D_NAND_USDHC_BUS_ROOT_SRC] = imx_clk_hw_mux2_flags("nand_usdhc_src", base + 0x8980, 24, 3, nand_usdhc_bus_sel, ARRAY_SIZE(nand_usdhc_bus_sel), CLK_SET_PARENT_GATE);
hws[IMX7D_DRAM_PHYM_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_phym_src", base + 0x9800, 24, 1, dram_phym_sel, ARRAY_SIZE(dram_phym_sel), CLK_SET_PARENT_GATE); hws[IMX7D_DRAM_PHYM_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_phym_src", base + 0x9800, 24, 1, dram_phym_sel, ARRAY_SIZE(dram_phym_sel), CLK_SET_PARENT_GATE);
hws[IMX7D_DRAM_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_src", base + 0x9880, 24, 1, dram_sel, ARRAY_SIZE(dram_sel), CLK_SET_PARENT_GATE); hws[IMX7D_DRAM_ROOT_SRC] = imx_clk_hw_mux2("dram_src", base + 0x9880, 24, 1, dram_sel, ARRAY_SIZE(dram_sel));
hws[IMX7D_DRAM_PHYM_ALT_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_phym_alt_src", base + 0xa000, 24, 3, dram_phym_alt_sel, ARRAY_SIZE(dram_phym_alt_sel), CLK_SET_PARENT_GATE); hws[IMX7D_DRAM_PHYM_ALT_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_phym_alt_src", base + 0xa000, 24, 3, dram_phym_alt_sel, ARRAY_SIZE(dram_phym_alt_sel), CLK_SET_PARENT_GATE);
hws[IMX7D_DRAM_ALT_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_alt_src", base + 0xa080, 24, 3, dram_alt_sel, ARRAY_SIZE(dram_alt_sel), CLK_SET_PARENT_GATE); hws[IMX7D_DRAM_ALT_ROOT_SRC] = imx_clk_hw_mux2("dram_alt_src", base + 0xa080, 24, 3, dram_alt_sel, ARRAY_SIZE(dram_alt_sel));
hws[IMX7D_USB_HSIC_ROOT_SRC] = imx_clk_hw_mux2_flags("usb_hsic_src", base + 0xa100, 24, 3, usb_hsic_sel, ARRAY_SIZE(usb_hsic_sel), CLK_SET_PARENT_GATE); hws[IMX7D_USB_HSIC_ROOT_SRC] = imx_clk_hw_mux2_flags("usb_hsic_src", base + 0xa100, 24, 3, usb_hsic_sel, ARRAY_SIZE(usb_hsic_sel), CLK_SET_PARENT_GATE);
hws[IMX7D_PCIE_CTRL_ROOT_SRC] = imx_clk_hw_mux2_flags("pcie_ctrl_src", base + 0xa180, 24, 3, pcie_ctrl_sel, ARRAY_SIZE(pcie_ctrl_sel), CLK_SET_PARENT_GATE); hws[IMX7D_PCIE_CTRL_ROOT_SRC] = imx_clk_hw_mux2_flags("pcie_ctrl_src", base + 0xa180, 24, 3, pcie_ctrl_sel, ARRAY_SIZE(pcie_ctrl_sel), CLK_SET_PARENT_GATE);
hws[IMX7D_PCIE_PHY_ROOT_SRC] = imx_clk_hw_mux2_flags("pcie_phy_src", base + 0xa200, 24, 3, pcie_phy_sel, ARRAY_SIZE(pcie_phy_sel), CLK_SET_PARENT_GATE); hws[IMX7D_PCIE_PHY_ROOT_SRC] = imx_clk_hw_mux2_flags("pcie_phy_src", base + 0xa200, 24, 3, pcie_phy_sel, ARRAY_SIZE(pcie_phy_sel), CLK_SET_PARENT_GATE);
hws[IMX7D_EPDC_PIXEL_ROOT_SRC] = imx_clk_hw_mux2_flags("epdc_pixel_src", base + 0xa280, 24, 3, epdc_pixel_sel, ARRAY_SIZE(epdc_pixel_sel), CLK_SET_PARENT_GATE); hws[IMX7D_EPDC_PIXEL_ROOT_SRC] = imx_clk_hw_mux2_flags("epdc_pixel_src", base + 0xa280, 24, 3, epdc_pixel_sel, ARRAY_SIZE(epdc_pixel_sel), CLK_SET_PARENT_GATE);
hws[IMX7D_LCDIF_PIXEL_ROOT_SRC] = imx_clk_hw_mux2_flags("lcdif_pixel_src", base + 0xa300, 24, 3, lcdif_pixel_sel, ARRAY_SIZE(lcdif_pixel_sel), CLK_SET_PARENT_GATE); hws[IMX7D_LCDIF_PIXEL_ROOT_SRC] = imx_clk_hw_mux2_flags("lcdif_pixel_src", base + 0xa300, 24, 3, lcdif_pixel_sel, ARRAY_SIZE(lcdif_pixel_sel), CLK_SET_PARENT_GATE | CLK_SET_RATE_PARENT);
hws[IMX7D_MIPI_DSI_ROOT_SRC] = imx_clk_hw_mux2_flags("mipi_dsi_src", base + 0xa380, 24, 3, mipi_dsi_sel, ARRAY_SIZE(mipi_dsi_sel), CLK_SET_PARENT_GATE); hws[IMX7D_MIPI_DSI_ROOT_SRC] = imx_clk_hw_mux2_flags("mipi_dsi_src", base + 0xa380, 24, 3, mipi_dsi_sel, ARRAY_SIZE(mipi_dsi_sel), CLK_SET_PARENT_GATE);
hws[IMX7D_MIPI_CSI_ROOT_SRC] = imx_clk_hw_mux2_flags("mipi_csi_src", base + 0xa400, 24, 3, mipi_csi_sel, ARRAY_SIZE(mipi_csi_sel), CLK_SET_PARENT_GATE); hws[IMX7D_MIPI_CSI_ROOT_SRC] = imx_clk_hw_mux2_flags("mipi_csi_src", base + 0xa400, 24, 3, mipi_csi_sel, ARRAY_SIZE(mipi_csi_sel), CLK_SET_PARENT_GATE);
hws[IMX7D_MIPI_DPHY_ROOT_SRC] = imx_clk_hw_mux2_flags("mipi_dphy_src", base + 0xa480, 24, 3, mipi_dphy_sel, ARRAY_SIZE(mipi_dphy_sel), CLK_SET_PARENT_GATE); hws[IMX7D_MIPI_DPHY_ROOT_SRC] = imx_clk_hw_mux2_flags("mipi_dphy_src", base + 0xa480, 24, 3, mipi_dphy_sel, ARRAY_SIZE(mipi_dphy_sel), CLK_SET_PARENT_GATE);

View File

@ -54,10 +54,12 @@ struct clk_imx8_acm_sel {
* struct imx8_acm_soc_data - soc specific data * struct imx8_acm_soc_data - soc specific data
* @sels: pointer to struct clk_imx8_acm_sel * @sels: pointer to struct clk_imx8_acm_sel
* @num_sels: numbers of items * @num_sels: numbers of items
* @mclk_sels: pointer to imx8qm/qxp/dxl_mclk_sels
*/ */
struct imx8_acm_soc_data { struct imx8_acm_soc_data {
struct clk_imx8_acm_sel *sels; struct clk_imx8_acm_sel *sels;
unsigned int num_sels; unsigned int num_sels;
struct clk_parent_data *mclk_sels;
}; };
/** /**
@ -111,11 +113,14 @@ static const struct clk_parent_data imx8qm_mclk_out_sels[] = {
{ .fw_name = "sai6_rx_bclk" }, { .fw_name = "sai6_rx_bclk" },
}; };
static const struct clk_parent_data imx8qm_mclk_sels[] = { #define ACM_AUD_CLK0_SEL_INDEX 2
#define ACM_AUD_CLK1_SEL_INDEX 3
static struct clk_parent_data imx8qm_mclk_sels[] = {
{ .fw_name = "aud_pll_div_clk0_lpcg_clk" }, { .fw_name = "aud_pll_div_clk0_lpcg_clk" },
{ .fw_name = "aud_pll_div_clk1_lpcg_clk" }, { .fw_name = "aud_pll_div_clk1_lpcg_clk" },
{ .fw_name = "acm_aud_clk0_sel" }, { }, /* clk_hw pointer of "acm_aud_clk0_sel" */
{ .fw_name = "acm_aud_clk1_sel" }, { }, /* clk_hw pointer of "acm_aud_clk1_sel" */
}; };
static const struct clk_parent_data imx8qm_asrc_mux_clk_sels[] = { static const struct clk_parent_data imx8qm_asrc_mux_clk_sels[] = {
@ -176,11 +181,11 @@ static const struct clk_parent_data imx8qxp_mclk_out_sels[] = {
{ .fw_name = "sai4_rx_bclk" }, { .fw_name = "sai4_rx_bclk" },
}; };
static const struct clk_parent_data imx8qxp_mclk_sels[] = { static struct clk_parent_data imx8qxp_mclk_sels[] = {
{ .fw_name = "aud_pll_div_clk0_lpcg_clk" }, { .fw_name = "aud_pll_div_clk0_lpcg_clk" },
{ .fw_name = "aud_pll_div_clk1_lpcg_clk" }, { .fw_name = "aud_pll_div_clk1_lpcg_clk" },
{ .fw_name = "acm_aud_clk0_sel" }, { }, /* clk_hw pointer of "acm_aud_clk0_sel" */
{ .fw_name = "acm_aud_clk1_sel" }, { }, /* clk_hw pointer of "acm_aud_clk1_sel" */
}; };
static struct clk_imx8_acm_sel imx8qxp_sels[] = { static struct clk_imx8_acm_sel imx8qxp_sels[] = {
@ -228,11 +233,11 @@ static const struct clk_parent_data imx8dxl_mclk_out_sels[] = {
{ .index = -1 }, { .index = -1 },
}; };
static const struct clk_parent_data imx8dxl_mclk_sels[] = { static struct clk_parent_data imx8dxl_mclk_sels[] = {
{ .fw_name = "aud_pll_div_clk0_lpcg_clk" }, { .fw_name = "aud_pll_div_clk0_lpcg_clk" },
{ .fw_name = "aud_pll_div_clk1_lpcg_clk" }, { .fw_name = "aud_pll_div_clk1_lpcg_clk" },
{ .fw_name = "acm_aud_clk0_sel" }, { }, /* clk_hw pointer of "acm_aud_clk0_sel" */
{ .fw_name = "acm_aud_clk1_sel" }, { }, /* clk_hw pointer of "acm_aud_clk1_sel" */
}; };
static struct clk_imx8_acm_sel imx8dxl_sels[] = { static struct clk_imx8_acm_sel imx8dxl_sels[] = {
@ -375,6 +380,18 @@ static int imx8_acm_clk_probe(struct platform_device *pdev)
imx_check_clk_hws(hws, IMX_ADMA_ACM_CLK_END); imx_check_clk_hws(hws, IMX_ADMA_ACM_CLK_END);
goto err_clk_register; goto err_clk_register;
} }
/*
* The IMX_ADMA_ACM_AUD_CLK0_SEL and IMX_ADMA_ACM_AUD_CLK1_SEL are
* registered first. After registration, update the clk_hw pointer
* to imx8qm/qxp/dxl_mclk_sels structures.
*/
if (sels[i].clkid == IMX_ADMA_ACM_AUD_CLK0_SEL)
priv->soc_data->mclk_sels[ACM_AUD_CLK0_SEL_INDEX].hw =
hws[IMX_ADMA_ACM_AUD_CLK0_SEL];
if (sels[i].clkid == IMX_ADMA_ACM_AUD_CLK1_SEL)
priv->soc_data->mclk_sels[ACM_AUD_CLK1_SEL_INDEX].hw =
hws[IMX_ADMA_ACM_AUD_CLK1_SEL];
} }
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_hw_data); ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_hw_data);
@ -406,16 +423,19 @@ static void imx8_acm_clk_remove(struct platform_device *pdev)
static const struct imx8_acm_soc_data imx8qm_acm_data = { static const struct imx8_acm_soc_data imx8qm_acm_data = {
.sels = imx8qm_sels, .sels = imx8qm_sels,
.num_sels = ARRAY_SIZE(imx8qm_sels), .num_sels = ARRAY_SIZE(imx8qm_sels),
.mclk_sels = imx8qm_mclk_sels,
}; };
static const struct imx8_acm_soc_data imx8qxp_acm_data = { static const struct imx8_acm_soc_data imx8qxp_acm_data = {
.sels = imx8qxp_sels, .sels = imx8qxp_sels,
.num_sels = ARRAY_SIZE(imx8qxp_sels), .num_sels = ARRAY_SIZE(imx8qxp_sels),
.mclk_sels = imx8qxp_mclk_sels,
}; };
static const struct imx8_acm_soc_data imx8dxl_acm_data = { static const struct imx8_acm_soc_data imx8dxl_acm_data = {
.sels = imx8dxl_sels, .sels = imx8dxl_sels,
.num_sels = ARRAY_SIZE(imx8dxl_sels), .num_sels = ARRAY_SIZE(imx8dxl_sels),
.mclk_sels = imx8dxl_mclk_sels,
}; };
static const struct of_device_id imx8_acm_match[] = { static const struct of_device_id imx8_acm_match[] = {
@ -468,7 +488,7 @@ static struct platform_driver imx8_acm_clk_driver = {
.pm = &imx8_acm_pm_ops, .pm = &imx8_acm_pm_ops,
}, },
.probe = imx8_acm_clk_probe, .probe = imx8_acm_clk_probe,
.remove_new = imx8_acm_clk_remove, .remove = imx8_acm_clk_remove,
}; };
module_platform_driver(imx8_acm_clk_driver); module_platform_driver(imx8_acm_clk_driver);

View File

@ -432,7 +432,7 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
/* BUS */ /* BUS */
hws[IMX8MM_CLK_MAIN_AXI] = imx8m_clk_hw_composite_bus_critical("main_axi", imx8mm_main_axi_sels, base + 0x8800); hws[IMX8MM_CLK_MAIN_AXI] = imx8m_clk_hw_composite_bus_critical("main_axi", imx8mm_main_axi_sels, base + 0x8800);
hws[IMX8MM_CLK_ENET_AXI] = imx8m_clk_hw_composite_bus("enet_axi", imx8mm_enet_axi_sels, base + 0x8880); hws[IMX8MM_CLK_ENET_AXI] = imx8m_clk_hw_composite_bus("enet_axi", imx8mm_enet_axi_sels, base + 0x8880);
hws[IMX8MM_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite_bus_critical("nand_usdhc_bus", imx8mm_nand_usdhc_sels, base + 0x8900); hws[IMX8MM_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite("nand_usdhc_bus", imx8mm_nand_usdhc_sels, base + 0x8900);
hws[IMX8MM_CLK_VPU_BUS] = imx8m_clk_hw_composite_bus("vpu_bus", imx8mm_vpu_bus_sels, base + 0x8980); hws[IMX8MM_CLK_VPU_BUS] = imx8m_clk_hw_composite_bus("vpu_bus", imx8mm_vpu_bus_sels, base + 0x8980);
hws[IMX8MM_CLK_DISP_AXI] = imx8m_clk_hw_composite_bus("disp_axi", imx8mm_disp_axi_sels, base + 0x8a00); hws[IMX8MM_CLK_DISP_AXI] = imx8m_clk_hw_composite_bus("disp_axi", imx8mm_disp_axi_sels, base + 0x8a00);
hws[IMX8MM_CLK_DISP_APB] = imx8m_clk_hw_composite_bus("disp_apb", imx8mm_disp_apb_sels, base + 0x8a80); hws[IMX8MM_CLK_DISP_APB] = imx8m_clk_hw_composite_bus("disp_apb", imx8mm_disp_apb_sels, base + 0x8a80);

View File

@ -583,6 +583,7 @@ static int imx8mn_clocks_probe(struct platform_device *pdev)
hws[IMX8MN_CLK_SDMA2_ROOT] = imx_clk_hw_gate4("sdma2_clk", "ipg_audio_root", base + 0x43b0, 0); hws[IMX8MN_CLK_SDMA2_ROOT] = imx_clk_hw_gate4("sdma2_clk", "ipg_audio_root", base + 0x43b0, 0);
hws[IMX8MN_CLK_SDMA3_ROOT] = imx_clk_hw_gate4("sdma3_clk", "ipg_audio_root", base + 0x45f0, 0); hws[IMX8MN_CLK_SDMA3_ROOT] = imx_clk_hw_gate4("sdma3_clk", "ipg_audio_root", base + 0x45f0, 0);
hws[IMX8MN_CLK_SAI7_ROOT] = imx_clk_hw_gate2_shared2("sai7_root_clk", "sai7", base + 0x4650, 0, &share_count_sai7); hws[IMX8MN_CLK_SAI7_ROOT] = imx_clk_hw_gate2_shared2("sai7_root_clk", "sai7", base + 0x4650, 0, &share_count_sai7);
hws[IMX8MN_CLK_SAI7_IPG] = imx_clk_hw_gate2_shared2("sai7_ipg_clk", "ipg_audio_root", base + 0x4650, 0, &share_count_sai7);
hws[IMX8MN_CLK_GPT_3M] = imx_clk_hw_fixed_factor("gpt_3m", "osc_24m", 1, 8); hws[IMX8MN_CLK_GPT_3M] = imx_clk_hw_fixed_factor("gpt_3m", "osc_24m", 1, 8);

View File

@ -5,6 +5,7 @@
* Copyright (C) 2022 Marek Vasut <marex@denx.de> * Copyright (C) 2022 Marek Vasut <marex@denx.de>
*/ */
#include <linux/auxiliary_bus.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/io.h> #include <linux/io.h>
@ -13,6 +14,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <dt-bindings/clock/imx8mp-clock.h> #include <dt-bindings/clock/imx8mp-clock.h>
@ -154,6 +156,15 @@ static const struct clk_parent_data clk_imx8mp_audiomix_pll_bypass_sels[] = {
PDM_SEL, 2, 0 \ PDM_SEL, 2, 0 \
} }
#define CLK_GATE_PARENT(gname, cname, pname) \
{ \
gname"_cg", \
IMX8MP_CLK_AUDIOMIX_##cname, \
{ .fw_name = pname, .name = pname }, NULL, 1, \
CLKEN0 + 4 * !!(IMX8MP_CLK_AUDIOMIX_##cname / 32), \
1, IMX8MP_CLK_AUDIOMIX_##cname % 32 \
}
struct clk_imx8mp_audiomix_sel { struct clk_imx8mp_audiomix_sel {
const char *name; const char *name;
int clkid; int clkid;
@ -171,14 +182,14 @@ static struct clk_imx8mp_audiomix_sel sels[] = {
CLK_GATE("earc", EARC_IPG), CLK_GATE("earc", EARC_IPG),
CLK_GATE("ocrama", OCRAMA_IPG), CLK_GATE("ocrama", OCRAMA_IPG),
CLK_GATE("aud2htx", AUD2HTX_IPG), CLK_GATE("aud2htx", AUD2HTX_IPG),
CLK_GATE("earc_phy", EARC_PHY), CLK_GATE_PARENT("earc_phy", EARC_PHY, "sai_pll_out_div2"),
CLK_GATE("sdma2", SDMA2_ROOT), CLK_GATE("sdma2", SDMA2_ROOT),
CLK_GATE("sdma3", SDMA3_ROOT), CLK_GATE("sdma3", SDMA3_ROOT),
CLK_GATE("spba2", SPBA2_ROOT), CLK_GATE("spba2", SPBA2_ROOT),
CLK_GATE("dsp", DSP_ROOT), CLK_GATE("dsp", DSP_ROOT),
CLK_GATE("dspdbg", DSPDBG_ROOT), CLK_GATE("dspdbg", DSPDBG_ROOT),
CLK_GATE("edma", EDMA_ROOT), CLK_GATE("edma", EDMA_ROOT),
CLK_GATE("audpll", AUDPLL_ROOT), CLK_GATE_PARENT("audpll", AUDPLL_ROOT, "osc_24m"),
CLK_GATE("mu2", MU2_ROOT), CLK_GATE("mu2", MU2_ROOT),
CLK_GATE("mu3", MU3_ROOT), CLK_GATE("mu3", MU3_ROOT),
CLK_PDM, CLK_PDM,
@ -217,6 +228,63 @@ struct clk_imx8mp_audiomix_priv {
struct clk_hw_onecell_data clk_data; struct clk_hw_onecell_data clk_data;
}; };
#if IS_ENABLED(CONFIG_RESET_CONTROLLER)
static void clk_imx8mp_audiomix_reset_unregister_adev(void *_adev)
{
struct auxiliary_device *adev = _adev;
auxiliary_device_delete(adev);
auxiliary_device_uninit(adev);
}
static void clk_imx8mp_audiomix_reset_adev_release(struct device *dev)
{
struct auxiliary_device *adev = to_auxiliary_dev(dev);
kfree(adev);
}
static int clk_imx8mp_audiomix_reset_controller_register(struct device *dev,
struct clk_imx8mp_audiomix_priv *priv)
{
struct auxiliary_device *adev __free(kfree) = NULL;
int ret;
if (!of_property_present(dev->of_node, "#reset-cells"))
return 0;
adev = kzalloc(sizeof(*adev), GFP_KERNEL);
if (!adev)
return -ENOMEM;
adev->name = "reset";
adev->dev.parent = dev;
adev->dev.release = clk_imx8mp_audiomix_reset_adev_release;
ret = auxiliary_device_init(adev);
if (ret)
return ret;
ret = auxiliary_device_add(adev);
if (ret) {
auxiliary_device_uninit(adev);
return ret;
}
return devm_add_action_or_reset(dev, clk_imx8mp_audiomix_reset_unregister_adev,
no_free_ptr(adev));
}
#else /* !CONFIG_RESET_CONTROLLER */
static int clk_imx8mp_audiomix_reset_controller_register(struct clk_imx8mp_audiomix_priv *priv)
{
return 0;
}
#endif /* !CONFIG_RESET_CONTROLLER */
static void clk_imx8mp_audiomix_save_restore(struct device *dev, bool save) static void clk_imx8mp_audiomix_save_restore(struct device *dev, bool save)
{ {
struct clk_imx8mp_audiomix_priv *priv = dev_get_drvdata(dev); struct clk_imx8mp_audiomix_priv *priv = dev_get_drvdata(dev);
@ -269,12 +337,12 @@ static int clk_imx8mp_audiomix_probe(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(sels); i++) { for (i = 0; i < ARRAY_SIZE(sels); i++) {
if (sels[i].num_parents == 1) { if (sels[i].num_parents == 1) {
hw = devm_clk_hw_register_gate_parent_data(dev, hw = devm_clk_hw_register_gate_parent_data(dev,
sels[i].name, &sels[i].parent, 0, sels[i].name, &sels[i].parent, CLK_SET_RATE_PARENT,
base + sels[i].reg, sels[i].shift, 0, NULL); base + sels[i].reg, sels[i].shift, 0, NULL);
} else { } else {
hw = devm_clk_hw_register_mux_parent_data_table(dev, hw = devm_clk_hw_register_mux_parent_data_table(dev,
sels[i].name, sels[i].parents, sels[i].name, sels[i].parents,
sels[i].num_parents, 0, sels[i].num_parents, CLK_SET_RATE_PARENT,
base + sels[i].reg, base + sels[i].reg,
sels[i].shift, sels[i].width, sels[i].shift, sels[i].width,
0, NULL, NULL); 0, NULL, NULL);
@ -317,7 +385,8 @@ static int clk_imx8mp_audiomix_probe(struct platform_device *pdev)
clk_hw_data->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_BYPASS] = hw; clk_hw_data->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_BYPASS] = hw;
hw = devm_clk_hw_register_gate(dev, "sai_pll_out", "sai_pll_bypass", hw = devm_clk_hw_register_gate(dev, "sai_pll_out", "sai_pll_bypass",
0, base + SAI_PLL_GNRL_CTL, 13, CLK_SET_RATE_PARENT,
base + SAI_PLL_GNRL_CTL, 13,
0, NULL); 0, NULL);
if (IS_ERR(hw)) { if (IS_ERR(hw)) {
ret = PTR_ERR(hw); ret = PTR_ERR(hw);
@ -326,7 +395,8 @@ static int clk_imx8mp_audiomix_probe(struct platform_device *pdev)
clk_hw_data->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_OUT] = hw; clk_hw_data->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_OUT] = hw;
hw = devm_clk_hw_register_fixed_factor(dev, "sai_pll_out_div2", hw = devm_clk_hw_register_fixed_factor(dev, "sai_pll_out_div2",
"sai_pll_out", 0, 1, 2); "sai_pll_out",
CLK_SET_RATE_PARENT, 1, 2);
if (IS_ERR(hw)) { if (IS_ERR(hw)) {
ret = PTR_ERR(hw); ret = PTR_ERR(hw);
goto err_clk_register; goto err_clk_register;
@ -337,6 +407,10 @@ static int clk_imx8mp_audiomix_probe(struct platform_device *pdev)
if (ret) if (ret)
goto err_clk_register; goto err_clk_register;
ret = clk_imx8mp_audiomix_reset_controller_register(dev, priv);
if (ret)
goto err_clk_register;
pm_runtime_put_sync(dev); pm_runtime_put_sync(dev);
return 0; return 0;
@ -380,7 +454,7 @@ MODULE_DEVICE_TABLE(of, clk_imx8mp_audiomix_of_match);
static struct platform_driver clk_imx8mp_audiomix_driver = { static struct platform_driver clk_imx8mp_audiomix_driver = {
.probe = clk_imx8mp_audiomix_probe, .probe = clk_imx8mp_audiomix_probe,
.remove_new = clk_imx8mp_audiomix_remove, .remove = clk_imx8mp_audiomix_remove,
.driver = { .driver = {
.name = "imx8mp-audio-blk-ctrl", .name = "imx8mp-audio-blk-ctrl",
.of_match_table = clk_imx8mp_audiomix_of_match, .of_match_table = clk_imx8mp_audiomix_of_match,

View File

@ -547,12 +547,12 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
hws[IMX8MP_CLK_AHB] = imx8m_clk_hw_composite_bus_critical("ahb_root", imx8mp_ahb_sels, ccm_base + 0x9000); hws[IMX8MP_CLK_AHB] = imx8m_clk_hw_composite_bus_critical("ahb_root", imx8mp_ahb_sels, ccm_base + 0x9000);
hws[IMX8MP_CLK_AUDIO_AHB] = imx8m_clk_hw_composite_bus("audio_ahb", imx8mp_audio_ahb_sels, ccm_base + 0x9100); hws[IMX8MP_CLK_AUDIO_AHB] = imx8m_clk_hw_composite_bus("audio_ahb", imx8mp_audio_ahb_sels, ccm_base + 0x9100);
hws[IMX8MP_CLK_MIPI_DSI_ESC_RX] = imx8m_clk_hw_composite_bus("mipi_dsi_esc_rx", imx8mp_mipi_dsi_esc_rx_sels, ccm_base + 0x9200); hws[IMX8MP_CLK_MIPI_DSI_ESC_RX] = imx8m_clk_hw_composite_bus("mipi_dsi_esc_rx", imx8mp_mipi_dsi_esc_rx_sels, ccm_base + 0x9200);
hws[IMX8MP_CLK_MEDIA_DISP2_PIX] = imx8m_clk_hw_composite_bus("media_disp2_pix", imx8mp_media_disp_pix_sels, ccm_base + 0x9300); hws[IMX8MP_CLK_MEDIA_DISP2_PIX] = imx8m_clk_hw_composite_bus_flags("media_disp2_pix", imx8mp_media_disp_pix_sels, ccm_base + 0x9300, CLK_SET_RATE_PARENT);
hws[IMX8MP_CLK_IPG_ROOT] = imx_clk_hw_divider2("ipg_root", "ahb_root", ccm_base + 0x9080, 0, 1); hws[IMX8MP_CLK_IPG_ROOT] = imx_clk_hw_divider2("ipg_root", "ahb_root", ccm_base + 0x9080, 0, 1);
hws[IMX8MP_CLK_DRAM_ALT] = imx8m_clk_hw_composite("dram_alt", imx8mp_dram_alt_sels, ccm_base + 0xa000); hws[IMX8MP_CLK_DRAM_ALT] = imx8m_clk_hw_fw_managed_composite("dram_alt", imx8mp_dram_alt_sels, ccm_base + 0xa000);
hws[IMX8MP_CLK_DRAM_APB] = imx8m_clk_hw_composite_critical("dram_apb", imx8mp_dram_apb_sels, ccm_base + 0xa080); hws[IMX8MP_CLK_DRAM_APB] = imx8m_clk_hw_fw_managed_composite_critical("dram_apb", imx8mp_dram_apb_sels, ccm_base + 0xa080);
hws[IMX8MP_CLK_VPU_G1] = imx8m_clk_hw_composite("vpu_g1", imx8mp_vpu_g1_sels, ccm_base + 0xa100); hws[IMX8MP_CLK_VPU_G1] = imx8m_clk_hw_composite("vpu_g1", imx8mp_vpu_g1_sels, ccm_base + 0xa100);
hws[IMX8MP_CLK_VPU_G2] = imx8m_clk_hw_composite("vpu_g2", imx8mp_vpu_g2_sels, ccm_base + 0xa180); hws[IMX8MP_CLK_VPU_G2] = imx8m_clk_hw_composite("vpu_g2", imx8mp_vpu_g2_sels, ccm_base + 0xa180);
hws[IMX8MP_CLK_CAN1] = imx8m_clk_hw_composite("can1", imx8mp_can1_sels, ccm_base + 0xa200); hws[IMX8MP_CLK_CAN1] = imx8m_clk_hw_composite("can1", imx8mp_can1_sels, ccm_base + 0xa200);
@ -609,7 +609,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
hws[IMX8MP_CLK_USDHC3] = imx8m_clk_hw_composite("usdhc3", imx8mp_usdhc3_sels, ccm_base + 0xbc80); hws[IMX8MP_CLK_USDHC3] = imx8m_clk_hw_composite("usdhc3", imx8mp_usdhc3_sels, ccm_base + 0xbc80);
hws[IMX8MP_CLK_MEDIA_CAM1_PIX] = imx8m_clk_hw_composite("media_cam1_pix", imx8mp_media_cam1_pix_sels, ccm_base + 0xbd00); hws[IMX8MP_CLK_MEDIA_CAM1_PIX] = imx8m_clk_hw_composite("media_cam1_pix", imx8mp_media_cam1_pix_sels, ccm_base + 0xbd00);
hws[IMX8MP_CLK_MEDIA_MIPI_PHY1_REF] = imx8m_clk_hw_composite("media_mipi_phy1_ref", imx8mp_media_mipi_phy1_ref_sels, ccm_base + 0xbd80); hws[IMX8MP_CLK_MEDIA_MIPI_PHY1_REF] = imx8m_clk_hw_composite("media_mipi_phy1_ref", imx8mp_media_mipi_phy1_ref_sels, ccm_base + 0xbd80);
hws[IMX8MP_CLK_MEDIA_DISP1_PIX] = imx8m_clk_hw_composite("media_disp1_pix", imx8mp_media_disp_pix_sels, ccm_base + 0xbe00); hws[IMX8MP_CLK_MEDIA_DISP1_PIX] = imx8m_clk_hw_composite_bus_flags("media_disp1_pix", imx8mp_media_disp_pix_sels, ccm_base + 0xbe00, CLK_SET_RATE_PARENT);
hws[IMX8MP_CLK_MEDIA_CAM2_PIX] = imx8m_clk_hw_composite("media_cam2_pix", imx8mp_media_cam2_pix_sels, ccm_base + 0xbe80); hws[IMX8MP_CLK_MEDIA_CAM2_PIX] = imx8m_clk_hw_composite("media_cam2_pix", imx8mp_media_cam2_pix_sels, ccm_base + 0xbe80);
hws[IMX8MP_CLK_MEDIA_LDB] = imx8m_clk_hw_composite("media_ldb", imx8mp_media_ldb_sels, ccm_base + 0xbf00); hws[IMX8MP_CLK_MEDIA_LDB] = imx8m_clk_hw_composite("media_ldb", imx8mp_media_ldb_sels, ccm_base + 0xbf00);
hws[IMX8MP_CLK_MEMREPAIR] = imx8m_clk_hw_composite_critical("mem_repair", imx8mp_memrepair_sels, ccm_base + 0xbf80); hws[IMX8MP_CLK_MEMREPAIR] = imx8m_clk_hw_composite_critical("mem_repair", imx8mp_memrepair_sels, ccm_base + 0xbf80);

Some files were not shown because too many files have changed in this diff Show More