The core framework gained a clk provider helper, a clk consumer helper, and

some unit tests for the assigned clk rates feature in DeviceTree. On the vendor
 driver side, we gained a whole pile of SoC driver support detailed below. The
 majority in the diffstat is Qualcomm, but there's also quite a few Samsung and
 Mediatek clk driver additions in here as well. The top vendors is quite common,
 but the sheer amount of new drivers is uncommon, so I'm anticipating a larger
 number of fixes for clk drivers this cycle.
 
 Core:
  - devm_clk_bulk_get_all_enabled() to return number of clks acquired
  - devm_clk_hw_register_gate_parent_hw() helper to modernize drivers
  - KUnit tests for clk-assigned-rates{,-u64}
 
 New Drivers:
  - Marvell PXA1908 SoC clks
  - Mobileye EyeQ5, EyeQ6L and EyeQ6H clk driver
  - TWL6030 clk driver
  - Nuvoton Arbel BMC NPCM8XX SoC clks
  - MediaTek MT6735 SoC clks
  - MediaTek MT7620, MT7628 and MT7688 MMC clks
  - Add a driver for gated fixed rate clocks
  - Global clock controllers for Qualcomm QCS8300 and IPQ5424 SoCs
  - Camera, display and video clock controllers for Qualcomm SA8775P SoCs
  - Global, display, GPU, TCSR, and RPMh clock controllers for Qualcomm SAR2130P
  - Global, camera, display, GPU, and video clock controllers for Qualcomm
    SM8475 SoCs
  - RTC power domain and Battery Backup Function (VBATTB) clock support for the
    Renesas RZ/G3S SoC
  - Qualcomm IPQ9574 alpha PLLs
  - Support for i.MX91 CCM in the i.MX93 driver
  - Microchip LAN969X SoC clks
  - Cortex-A55 core clocks and Interrupt Control Unit (ICU) clock and reset on
    Renesas RZ/V2H(P)
  - Samsung ExynosAutov920 clk drivers for PERIC1, MISC, HSI0 and HSI1
  - Samsung Exynos8895 clk drivers for FSYS0/1, PERIC0/1, PERIS and TOP
 
 Updates:
  - Convert more clk bindings to YAML
  - Various clk driver cleanups: NULL checks, add const, etc.
  - Remove END/NUM #defines that count number of clks in various binding headers
  - Continue moving reset drivers to drivers/reset via auxiliary bus
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEE9L57QeeUxqYDyoaDrQKIl8bklSUFAmc/r1kRHHNib3lkQGtl
 cm5lbC5vcmcACgkQrQKIl8bklSUlaw/+NkmTMPSpgKy8NfZi6KoCk3U5llaknXvj
 Y/Y2pB7UpOFDTsSCKRcFrZ6JWS6GIogE70W9w+zxIht4QA4Ekd9vKT7VRhMl+8t/
 pz2i0c0Pm24hSye9LKM7JCVIVL8SNYonOs3wC1sfMVMDoUikVwupj6Bmj0nAYrBo
 hbJFBXtn/LbyYImJQ9hYqHnUtJKGp/N7hhpGu6kT/lbzcaWsBMp4lhH+s20DJz5e
 kdJVJGaLOELerAG/SHIxh9obtfznvex6x3itTB0o/d6/1DSDjjlxnZH8YV8eQWk0
 kK+ORuewA+qCi3RiPReHCPBIfPI4HL0z3k5JFA5eI7eD4VZIis+YBOa/Y8bQR9bG
 wDg5qh5su0fdeWBUvkFB03igNoMdtH68iYd2q3YE0ka95FGulcyvbqoyxTJnjIxW
 328PizYZV8LQ4+LGSdIFyp9f/SrjF0pAt7yTF8Dis3jq3ul/6ELX9G6OCNgtGKQz
 p0Hb01fKC4s7w48QI5OXQKfS382vS8G8a2NIwt2xxorc4+Dr2rjPvlDhErshCOAT
 nDEerIjGWr/0rQeTGxg+SLUx5ytq2aBkysg95/9WVe3b8kZeePiW9gEH4tgealY8
 eHzFvbqXutlKer0xLOYiLd3hOeHhkCJNj48QS8jVXtRGGeLjZONw5F1mjTNskPpx
 9jbKMcDjGyc=
 =FqLm
 -----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 framework gained a clk provider helper, a clk consumer
  helper, and some unit tests for the assigned clk rates feature in
  DeviceTree. On the vendor driver side, we gained a whole pile of SoC
  driver support detailed below. The majority in the diffstat is
  Qualcomm, but there's also quite a few Samsung and Mediatek clk driver
  additions in here as well. The top vendors is quite common, but the
  sheer amount of new drivers is uncommon, so I'm anticipating a larger
  number of fixes for clk drivers this cycle.

  Core:
   - devm_clk_bulk_get_all_enabled() to return number of clks acquired
   - devm_clk_hw_register_gate_parent_hw() helper to modernize drivers
   - KUnit tests for clk-assigned-rates{,-u64}

  New Drivers:
   - Marvell PXA1908 SoC clks
   - Mobileye EyeQ5, EyeQ6L and EyeQ6H clk driver
   - TWL6030 clk driver
   - Nuvoton Arbel BMC NPCM8XX SoC clks
   - MediaTek MT6735 SoC clks
   - MediaTek MT7620, MT7628 and MT7688 MMC clks
   - Add a driver for gated fixed rate clocks
   - Global clock controllers for Qualcomm QCS8300 and IPQ5424 SoCs
   - Camera, display and video clock controllers for Qualcomm SA8775P
     SoCs
   - Global, display, GPU, TCSR, and RPMh clock controllers for Qualcomm
     SAR2130P
   - Global, camera, display, GPU, and video clock controllers for
     Qualcomm SM8475 SoCs
   - RTC power domain and Battery Backup Function (VBATTB) clock support
     for the Renesas RZ/G3S SoC
   - Qualcomm IPQ9574 alpha PLLs
   - Support for i.MX91 CCM in the i.MX93 driver
   - Microchip LAN969X SoC clks
   - Cortex-A55 core clocks and Interrupt Control Unit (ICU) clock and
     reset on Renesas RZ/V2H(P)
   - Samsung ExynosAutov920 clk drivers for PERIC1, MISC, HSI0 and HSI1
   - Samsung Exynos8895 clk drivers for FSYS0/1, PERIC0/1, PERIS and TOP

  Updates:
   - Convert more clk bindings to YAML
   - Various clk driver cleanups: NULL checks, add const, etc.
   - Remove END/NUM #defines that count number of clks in various
     binding headers
   - Continue moving reset drivers to drivers/reset via auxiliary bus"

* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (162 commits)
  clk: clk-loongson2: Fix potential buffer overflow in flexible-array member access
  clk: Fix invalid execution of clk_set_rate
  clk: clk-loongson2: Fix memory corruption bug in struct loongson2_clk_provider
  clk: lan966x: make it selectable for ARCH_LAN969X
  clk: eyeq: add EyeQ6H west fixed factor clocks
  clk: eyeq: add EyeQ6H central fixed factor clocks
  clk: eyeq: add EyeQ5 fixed factor clocks
  clk: eyeq: add fixed factor clocks infrastructure
  clk: eyeq: require clock index with phandle in all cases
  clk: fixed-factor: add clk_hw_register_fixed_factor_index() function
  dt-bindings: clock: eyeq: add more Mobileye EyeQ5/EyeQ6H clocks
  dt-bindings: soc: mobileye: set `#clock-cells = <1>` for all compatibles
  clk: clk-axi-clkgen: make sure to enable the AXI bus clock
  dt-bindings: clock: axi-clkgen: include AXI clk
  clk: mmp: Add Marvell PXA1908 MPMU driver
  clk: mmp: Add Marvell PXA1908 APMU driver
  clk: mmp: Add Marvell PXA1908 APBCP driver
  clk: mmp: Add Marvell PXA1908 APBC driver
  dt-bindings: clock: Add Marvell PXA1908 clock bindings
  clk: mmp: Switch to use struct u32_fract instead of custom one
  ...
This commit is contained in:
Linus Torvalds 2024-11-22 17:02:25 -08:00
commit 9f3a2ba62c
242 changed files with 26307 additions and 2140 deletions

View File

@ -1,52 +0,0 @@
* Actions Semi Owl Clock Management Unit (CMU)
The Actions Semi Owl Clock Management Unit generates and supplies clock
to various controllers within the SoC. The clock binding described here is
applicable to S900, S700 and S500 SoC's.
Required Properties:
- compatible: should be one of the following,
"actions,s900-cmu"
"actions,s700-cmu"
"actions,s500-cmu"
- reg: physical base address of the controller and length of memory mapped
region.
- clocks: Reference to the parent clocks ("hosc", "losc")
- #clock-cells: should be 1.
- #reset-cells: should be 1.
Each clock is assigned an identifier, and client nodes can use this identifier
to specify the clock which they consume.
All available clocks are defined as preprocessor macros in corresponding
dt-bindings/clock/actions,s900-cmu.h or actions,s700-cmu.h or
actions,s500-cmu.h header and can be used in device tree sources.
External clocks:
The hosc clock used as input for the plls is generated outside the SoC. It is
expected that it is defined using standard clock bindings as "hosc".
Actions Semi S900 CMU also requires one more clock:
- "losc" - internal low frequency oscillator
Example: Clock Management Unit node:
cmu: clock-controller@e0160000 {
compatible = "actions,s900-cmu";
reg = <0x0 0xe0160000 0x0 0x1000>;
clocks = <&hosc>, <&losc>;
#clock-cells = <1>;
#reset-cells = <1>;
};
Example: UART controller node that consumes clock generated by the clock
management unit:
uart: serial@e012a000 {
compatible = "actions,s900-uart", "actions,owl-uart";
reg = <0x0 0xe012a000 0x0 0x2000>;
interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cmu CLK_UART5>;
};

View File

@ -0,0 +1,60 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/actions,owl-cmu.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Actions Semi Owl Clock Management Unit (CMU)
maintainers:
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
description: |
The Actions Semi Owl Clock Management Unit generates and supplies clock
to various controllers within the SoC.
See also:
include/dt-bindings/clock/actions,s500-cmu.h
include/dt-bindings/clock/actions,s700-cmu.h
include/dt-bindings/clock/actions,s900-cmu.h
properties:
compatible:
enum:
- actions,s500-cmu
- actions,s700-cmu
- actions,s900-cmu
reg:
maxItems: 1
clocks:
items:
- description: Host oscillator source
- description: Internal low frequency oscillator source
"#clock-cells":
const: 1
"#reset-cells":
const: 1
required:
- compatible
- reg
- clocks
- "#clock-cells"
- "#reset-cells"
additionalProperties: false
examples:
- |
clock-controller@e0160000 {
compatible = "actions,s900-cmu";
reg = <0xe0160000 0x1000>;
clocks = <&hosc>, <&losc>;
#clock-cells = <1>;
#reset-cells = <1>;
};
...

View File

@ -26,9 +26,21 @@ properties:
description:
Specifies the reference clock(s) from which the output frequency is
derived. This must either reference one clock if only the first clock
input is connected or two if both clock inputs are connected.
minItems: 1
maxItems: 2
input is connected or two if both clock inputs are connected. The last
clock is the AXI bus clock that needs to be enabled so we can access the
core registers.
minItems: 2
maxItems: 3
clock-names:
oneOf:
- items:
- const: clkin1
- const: s_axi_aclk
- items:
- const: clkin1
- const: clkin2
- const: s_axi_aclk
'#clock-cells':
const: 0
@ -40,6 +52,7 @@ required:
- compatible
- reg
- clocks
- clock-names
- '#clock-cells'
additionalProperties: false
@ -50,5 +63,6 @@ examples:
compatible = "adi,axi-clkgen-2.00.a";
#clock-cells = <0>;
reg = <0xff000000 0x1000>;
clocks = <&osc 1>;
clocks = <&osc 1>, <&clkc 15>;
clock-names = "clkin1", "s_axi_aclk";
};

View File

@ -34,8 +34,10 @@ properties:
- airoha,en7581-scu
reg:
minItems: 2
maxItems: 4
items:
- description: scu base address
- description: misc scu base address
minItems: 1
"#clock-cells":
description:
@ -60,9 +62,7 @@ allOf:
then:
properties:
reg:
items:
- description: scu base address
- description: misc scu base address
minItems: 2
'#reset-cells': false
@ -73,11 +73,7 @@ allOf:
then:
properties:
reg:
items:
- description: scu base address
- description: misc scu base address
- description: reset base address
- description: pb scu base address
maxItems: 1
additionalProperties: false
@ -96,12 +92,9 @@ examples:
#address-cells = <2>;
#size-cells = <2>;
scuclk: clock-controller@1fa20000 {
scuclk: clock-controller@1fb00000 {
compatible = "airoha,en7581-scu";
reg = <0x0 0x1fa20000 0x0 0x400>,
<0x0 0x1fb00000 0x0 0x90>,
<0x0 0x1fb00830 0x0 0x8>,
<0x0 0x1fbe3400 0x0 0xfc>;
reg = <0x0 0x1fb00000 0x0 0x970>;
#clock-cells = <1>;
#reset-cells = <1>;
};

View File

@ -0,0 +1,45 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/amlogic,meson8-clkc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic Meson8, Meson8b and Meson8m2 Clock and Reset Controller
maintainers:
- Neil Armstrong <neil.armstrong@linaro.org>
properties:
compatible:
oneOf:
- enum:
- amlogic,meson8-clkc
- amlogic,meson8b-clkc
- items:
- const: amlogic,meson8m2-clkc
- const: amlogic,meson8-clkc
clocks:
minItems: 2
maxItems: 3
clock-names:
minItems: 2
items:
- const: xtal
- const: ddr_pll
- const: clk_32k
'#clock-cells':
const: 1
'#reset-cells':
const: 1
required:
- compatible
- clocks
- clock-names
- '#reset-cells'
additionalProperties: false

View File

@ -1,51 +0,0 @@
* Amlogic Meson8, Meson8b and Meson8m2 Clock and Reset Unit
The Amlogic Meson8 / Meson8b / Meson8m2 clock controller generates and
supplies clock to various controllers within the SoC.
Required Properties:
- compatible: must be one of:
- "amlogic,meson8-clkc" for Meson8 (S802) SoCs
- "amlogic,meson8b-clkc" for Meson8 (S805) SoCs
- "amlogic,meson8m2-clkc" for Meson8m2 (S812) SoCs
- #clock-cells: should be 1.
- #reset-cells: should be 1.
- clocks: list of clock phandles, one for each entry in clock-names
- clock-names: should contain the following:
* "xtal": the 24MHz system oscillator
* "ddr_pll": the DDR PLL clock
* "clk_32k": (if present) the 32kHz clock signal from GPIOAO_6 (CLK_32K_IN)
Parent node should have the following properties :
- compatible: "amlogic,meson-hhi-sysctrl", "simple-mfd", "syscon"
- reg: base address and size of the HHI system control register space.
Each clock is assigned an identifier and client nodes can use this identifier
to specify the clock which they consume. All available clocks are defined as
preprocessor macros in the dt-bindings/clock/meson8b-clkc.h header and can be
used in device tree sources.
Similarly a preprocessor macro for each reset line is defined in
dt-bindings/reset/amlogic,meson8b-clkc-reset.h (which can be used from the
device tree sources).
Example: Clock controller node:
clkc: clock-controller {
compatible = "amlogic,meson8b-clkc";
#clock-cells = <1>;
#reset-cells = <1>;
};
Example: UART controller node that consumes the clock generated by the clock
controller:
uart_AO: serial@c81004c0 {
compatible = "amlogic,meson-uart";
reg = <0xc81004c0 0x14>;
interrupts = <0 90 1>;
clocks = <&clkc CLKID_CLK81>;
};

View File

@ -0,0 +1,49 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/gated-fixed-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Gated Fixed clock
maintainers:
- Heiko Stuebner <heiko@sntech.de>
properties:
compatible:
const: gated-fixed-clock
"#clock-cells":
const: 0
clock-frequency: true
clock-output-names:
maxItems: 1
enable-gpios:
description:
Contains a single GPIO specifier for the GPIO that enables and disables
the oscillator.
maxItems: 1
vdd-supply:
description: handle of the regulator that provides the supply voltage
required:
- compatible
- "#clock-cells"
- clock-frequency
- vdd-supply
additionalProperties: false
examples:
- |
clock-1000000000 {
compatible = "gated-fixed-clock";
#clock-cells = <0>;
clock-frequency = <1000000000>;
vdd-supply = <&reg_vdd>;
};
...

View File

@ -16,6 +16,7 @@ description: |
properties:
compatible:
enum:
- fsl,imx91-ccm
- fsl,imx93-ccm
reg:

View File

@ -0,0 +1,48 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/marvell,pxa1908.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Marvell PXA1908 Clock Controllers
maintainers:
- Duje Mihanović <duje.mihanovic@skole.hr>
description: |
The PXA1908 clock subsystem generates and supplies clock to various
controllers within the PXA1908 SoC. The PXA1908 contains numerous clock
controller blocks, with the ones currently supported being APBC, APBCP, MPMU
and APMU roughly corresponding to internal buses.
All these clock identifiers could be found in <include/dt-bindings/marvell,pxa1908.h>.
properties:
compatible:
enum:
- marvell,pxa1908-apbc
- marvell,pxa1908-apbcp
- marvell,pxa1908-mpmu
- marvell,pxa1908-apmu
reg:
maxItems: 1
'#clock-cells':
const: 1
required:
- compatible
- reg
- '#clock-cells'
additionalProperties: false
examples:
# APMU block:
- |
clock-controller@d4282800 {
compatible = "marvell,pxa1908-apmu";
reg = <0xd4282800 0x400>;
#clock-cells = <1>;
};

View File

@ -12,7 +12,8 @@ maintainers:
description:
The Mediatek apmixedsys controller provides PLLs to the system.
The clock values can be found in <dt-bindings/clock/mt*-clk.h>.
The clock values can be found in <dt-bindings/clock/mt*-clk.h>
and <dt-bindings/clock/mediatek,mt*-apmixedsys.h>.
properties:
compatible:
@ -34,6 +35,7 @@ properties:
- enum:
- mediatek,mt2701-apmixedsys
- mediatek,mt2712-apmixedsys
- mediatek,mt6735-apmixedsys
- mediatek,mt6765-apmixedsys
- mediatek,mt6779-apmixed
- mediatek,mt6795-apmixedsys

View File

@ -11,9 +11,10 @@ maintainers:
description:
The Mediatek infracfg controller provides various clocks and reset outputs
to the system. The clock values can be found in <dt-bindings/clock/mt*-clk.h>,
and reset values in <dt-bindings/reset/mt*-reset.h> and
<dt-bindings/reset/mt*-resets.h>.
to the system. The clock values can be found in <dt-bindings/clock/mt*-clk.h>
and <dt-bindings/clock/mediatek,mt*-infracfg.h>, and reset values in
<dt-bindings/reset/mt*-reset.h>, <dt-bindings/reset/mt*-resets.h> and
<dt-bindings/reset/mediatek,mt*-infracfg.h>.
properties:
compatible:
@ -22,6 +23,7 @@ properties:
- enum:
- mediatek,mt2701-infracfg
- mediatek,mt2712-infracfg
- mediatek,mt6735-infracfg
- mediatek,mt6765-infracfg
- mediatek,mt6795-infracfg
- mediatek,mt6779-infracfg_ao

View File

@ -20,6 +20,7 @@ properties:
- enum:
- mediatek,mt2701-pericfg
- mediatek,mt2712-pericfg
- mediatek,mt6735-pericfg
- mediatek,mt6765-pericfg
- mediatek,mt6795-pericfg
- mediatek,mt7622-pericfg

View File

@ -28,6 +28,10 @@ properties:
- mediatek,mt2712-mfgcfg
- mediatek,mt2712-vdecsys
- mediatek,mt2712-vencsys
- mediatek,mt6735-imgsys
- mediatek,mt6735-mfgcfg
- mediatek,mt6735-vdecsys
- mediatek,mt6735-vencsys
- mediatek,mt6765-camsys
- mediatek,mt6765-imgsys
- mediatek,mt6765-mipi0a

View File

@ -12,7 +12,8 @@ maintainers:
description:
The Mediatek topckgen controller provides various clocks to the system.
The clock values can be found in <dt-bindings/clock/mt*-clk.h>.
The clock values can be found in <dt-bindings/clock/mt*-clk.h> and
<dt-bindings/clock/mediatek,mt*-topckgen.h>.
properties:
compatible:
@ -31,6 +32,7 @@ properties:
- enum:
- mediatek,mt2701-topckgen
- mediatek,mt2712-topckgen
- mediatek,mt6735-topckgen
- mediatek,mt6765-topckgen
- mediatek,mt6779-topckgen
- mediatek,mt6795-topckgen

View File

@ -16,7 +16,18 @@ description: |
properties:
compatible:
const: microchip,lan966x-gck
oneOf:
- enum:
- microchip,lan966x-gck
- microchip,lan9691-gck
- items:
- enum:
- microchip,lan9698-gck
- microchip,lan9696-gck
- microchip,lan9694-gck
- microchip,lan9693-gck
- microchip,lan9692-gck
- const: microchip,lan9691-gck
reg:
minItems: 1

View File

@ -1,51 +0,0 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/mobileye,eyeq5-clk.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Mobileye EyeQ5 clock controller
description:
The EyeQ5 clock controller handles 10 read-only PLLs derived from the main
crystal clock. It also exposes one divider clock, a child of one of the PLLs.
Its registers live in a shared region called OLB.
maintainers:
- Grégory Clement <gregory.clement@bootlin.com>
- Théo Lebrun <theo.lebrun@bootlin.com>
- Vladimir Kondratiev <vladimir.kondratiev@mobileye.com>
properties:
compatible:
const: mobileye,eyeq5-clk
reg:
maxItems: 2
reg-names:
items:
- const: plls
- const: ospi
"#clock-cells":
const: 1
clocks:
maxItems: 1
description:
Input parent clock to all PLLs. Expected to be the main crystal.
clock-names:
items:
- const: ref
required:
- compatible
- reg
- reg-names
- "#clock-cells"
- clocks
- clock-names
additionalProperties: false

View File

@ -13,9 +13,10 @@ properties:
compatible:
items:
- enum:
- nxp,imx95-lvds-csr
- nxp,imx95-display-csr
- nxp,imx95-camera-csr
- nxp,imx95-display-csr
- nxp,imx95-hsio-blk-ctl
- nxp,imx95-lvds-csr
- nxp,imx95-netcmix-blk-ctrl
- nxp,imx95-vpu-csr
- const: syscon

View File

@ -17,7 +17,9 @@ description: |
properties:
compatible:
const: qcom,gcc-sm8450
enum:
- qcom,gcc-sm8450
- qcom,sm8475-gcc
clocks:
items:

View File

@ -4,31 +4,35 @@
$id: http://devicetree.org/schemas/clock/qcom,ipq5332-gcc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Global Clock & Reset Controller on IPQ5332
title: Qualcomm Global Clock & Reset Controller on IPQ5332 and IPQ5424
maintainers:
- Bjorn Andersson <andersson@kernel.org>
description: |
Qualcomm global clock control module provides the clocks, resets and power
domains on IPQ5332.
domains on IPQ5332 and IPQ5424.
See also:: include/dt-bindings/clock/qcom,gcc-ipq5332.h
allOf:
- $ref: qcom,gcc.yaml#
See also:
include/dt-bindings/clock/qcom,gcc-ipq5332.h
include/dt-bindings/clock/qcom,gcc-ipq5424.h
properties:
compatible:
const: qcom,ipq5332-gcc
enum:
- qcom,ipq5332-gcc
- qcom,ipq5424-gcc
clocks:
minItems: 5
items:
- description: Board XO clock source
- description: Sleep clock source
- description: PCIE 2lane PHY pipe clock source
- description: PCIE 2lane x1 PHY pipe clock source (For second lane)
- description: USB PCIE wrapper pipe clock source
- description: PCIE 2-lane PHY2 pipe clock source
- description: PCIE 2-lane PHY3 pipe clock source
'#power-domain-cells': false
'#interconnect-cells':
@ -38,6 +42,29 @@ required:
- compatible
- clocks
allOf:
- $ref: qcom,gcc.yaml#
- if:
properties:
compatible:
contains:
const: qcom,ipq5332-gcc
then:
properties:
clocks:
maxItems: 5
- if:
properties:
compatible:
contains:
const: qcom,ipq5424-gcc
then:
properties:
clocks:
minItems: 7
maxItems: 7
unevaluatedProperties: false
examples:

View File

@ -0,0 +1,66 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/qcom,qcs8300-gcc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Technologies, Inc. Global Clock & Reset Controller on QCS8300
maintainers:
- Taniya Das <quic_tdas@quicinc.com>
- Imran Shaik <quic_imrashai@quicinc.com>
description: |
Qualcomm Technologies, Inc. Global clock control module provides the clocks, resets and
power domains on QCS8300
See also: include/dt-bindings/clock/qcom,qcs8300-gcc.h
properties:
compatible:
const: qcom,qcs8300-gcc
clocks:
items:
- description: Board XO source
- description: Sleep clock source
- description: PCIE 0 Pipe clock source
- description: PCIE 1 Pipe clock source
- description: PCIE Phy Auxiliary clock source
- description: First EMAC controller reference clock
- description: UFS Phy Rx symbol 0 clock source
- description: UFS Phy Rx symbol 1 clock source
- description: UFS Phy Tx symbol 0 clock source
- description: USB3 Phy wrapper pipe clock source
required:
- compatible
- clocks
- '#power-domain-cells'
allOf:
- $ref: qcom,gcc.yaml#
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,rpmh.h>
clock-controller@100000 {
compatible = "qcom,qcs8300-gcc";
reg = <0x00100000 0xc7018>;
clocks = <&rpmhcc RPMH_CXO_CLK>,
<&sleep_clk>,
<&pcie_0_pipe_clk>,
<&pcie_1_pipe_clk>,
<&pcie_phy_aux_clk>,
<&rxc0_ref_clk>,
<&ufs_phy_rx_symbol_0_clk>,
<&ufs_phy_rx_symbol_1_clk>,
<&ufs_phy_tx_symbol_0_clk>,
<&usb3_phy_wrapper_gcc_usb30_prim_pipe_clk>;
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
};
...

View File

@ -19,6 +19,7 @@ properties:
enum:
- qcom,qdu1000-rpmh-clk
- qcom,sa8775p-rpmh-clk
- qcom,sar2130p-rpmh-clk
- qcom,sc7180-rpmh-clk
- qcom,sc7280-rpmh-clk
- qcom,sc8180x-rpmh-clk

View File

@ -0,0 +1,65 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/qcom,sar2130p-gcc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Global Clock & Reset Controller on sar2130p
maintainers:
- Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
description: |
Qualcomm global clock control module provides the clocks, resets and
power domains on sar2130p.
See also: include/dt-bindings/clock/qcom,sar2130p-gcc.h
properties:
compatible:
const: qcom,sar2130p-gcc
clocks:
items:
- description: XO reference clock
- description: Sleep clock
- description: PCIe 0 pipe clock
- description: PCIe 1 pipe clock
- description: Primary USB3 PHY wrapper pipe clock
protected-clocks:
maxItems: 240
power-domains:
maxItems: 1
required:
- compatible
- clocks
- '#power-domain-cells'
allOf:
- $ref: qcom,gcc.yaml#
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/power/qcom,rpmhpd.h>
gcc: clock-controller@100000 {
compatible = "qcom,sar2130p-gcc";
reg = <0x100000 0x1f4200>;
clocks = <&rpmhcc RPMH_CXO_CLK>,
<&sleep_clk>,
<&pcie_0_pipe_clk>,
<&pcie_1_pipe_clk>,
<&usb_0_ssphy>;
power-domains = <&rpmhpd RPMHPD_CX>;
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
};
...

View File

@ -26,6 +26,7 @@ properties:
enum:
- qcom,sc8280xp-camcc
- qcom,sm8450-camcc
- qcom,sm8475-camcc
- qcom,sm8550-camcc
- qcom,sm8650-camcc
- qcom,x1e80100-camcc

View File

@ -19,6 +19,7 @@ properties:
compatible:
enum:
- qcom,sm8450-dispcc
- qcom,sm8475-dispcc
clocks:
minItems: 3

View File

@ -14,6 +14,7 @@ description: |
domains on Qualcomm SoCs.
See also::
include/dt-bindings/clock/qcom,sar2130p-gpucc.h
include/dt-bindings/clock/qcom,sm4450-gpucc.h
include/dt-bindings/clock/qcom,sm8450-gpucc.h
include/dt-bindings/clock/qcom,sm8550-gpucc.h
@ -24,8 +25,10 @@ description: |
properties:
compatible:
enum:
- qcom,sar2130p-gpucc
- qcom,sm4450-gpucc
- qcom,sm8450-gpucc
- qcom,sm8475-gpucc
- qcom,sm8550-gpucc
- qcom,sm8650-gpucc
- qcom,x1e80100-gpucc

View File

@ -22,6 +22,7 @@ properties:
compatible:
enum:
- qcom,sm8450-videocc
- qcom,sm8475-videocc
- qcom,sm8550-videocc
- qcom,sm8650-videocc

View File

@ -22,6 +22,7 @@ description: |
properties:
compatible:
enum:
- qcom,sar2130p-dispcc
- qcom,sm8550-dispcc
- qcom,sm8650-dispcc
- qcom,x1e80100-dispcc

View File

@ -21,6 +21,7 @@ properties:
compatible:
items:
- enum:
- qcom,sar2130p-tcsr
- qcom,sm8550-tcsr
- qcom,sm8650-tcsr
- qcom,x1e80100-tcsr

View File

@ -1,58 +0,0 @@
* Rockchip RK3328 Clock and Reset Unit
The RK3328 clock controller generates and supplies clock to various
controllers within the SoC and also implements a reset controller for SoC
peripherals.
Required Properties:
- compatible: should be "rockchip,rk3328-cru"
- reg: physical base address of the controller and length of memory mapped
region.
- #clock-cells: should be 1.
- #reset-cells: should be 1.
Optional Properties:
- rockchip,grf: phandle to the syscon managing the "general register files"
If missing pll rates are not changeable, due to the missing pll lock status.
Each clock is assigned an identifier and client nodes can use this identifier
to specify the clock which they consume. All available clocks are defined as
preprocessor macros in the dt-bindings/clock/rk3328-cru.h headers and can be
used in device tree sources. Similar macros exist for the reset sources in
these files.
External clocks:
There are several clocks that are generated outside the SoC. It is expected
that they are defined using standard clock bindings with following
clock-output-names:
- "xin24m" - crystal input - required,
- "clkin_i2s" - external I2S clock - optional,
- "gmac_clkin" - external GMAC clock - optional
- "phy_50m_out" - output clock of the pll in the mac phy
- "hdmi_phy" - output clock of the hdmi phy pll - optional
Example: Clock controller node:
cru: clock-controller@ff440000 {
compatible = "rockchip,rk3328-cru";
reg = <0x0 0xff440000 0x0 0x1000>;
rockchip,grf = <&grf>;
#clock-cells = <1>;
#reset-cells = <1>;
};
Example: UART controller node that consumes the clock generated by the clock
controller:
uart0: serial@ff120000 {
compatible = "snps,dw-apb-uart";
reg = <0xff120000 0x100>;
interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
clocks = <&cru SCLK_UART0>;
};

View File

@ -0,0 +1,74 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/rockchip,rk3328-cru.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Rockchip RK3328 Clock and Reset Unit (CRU)
maintainers:
- Elaine Zhang <zhangqing@rock-chips.com>
- Heiko Stuebner <heiko@sntech.de>
description: |
The RK3328 clock controller generates and supplies clocks to various
controllers within the SoC and also implements a reset controller for SoC
peripherals.
Each clock is assigned an identifier and client nodes can use this identifier
to specify the clock which they consume. All available clocks are defined as
preprocessor macros in the dt-bindings/clock/rk3328-cru.h headers and can be
used in device tree sources. Similar macros exist for the reset sources in
these files.
There are several clocks that are generated outside the SoC. It is expected
that they are defined using standard clock bindings with following
clock-output-names:
- "xin24m" - crystal input - required,
- "clkin_i2s" - external I2S clock - optional,
- "gmac_clkin" - external GMAC clock - optional
- "phy_50m_out" - output clock of the pll in the mac phy
- "hdmi_phy" - output clock of the hdmi phy pll - optional
properties:
compatible:
enum:
- rockchip,rk3328-cru
reg:
maxItems: 1
"#clock-cells":
const: 1
"#reset-cells":
const: 1
clocks:
maxItems: 1
clock-names:
const: xin24m
rockchip,grf:
$ref: /schemas/types.yaml#/definitions/phandle
description:
Phandle to the syscon managing the "general register files" (GRF),
if missing pll rates are not changeable, due to the missing pll
lock status.
required:
- compatible
- reg
- "#clock-cells"
- "#reset-cells"
additionalProperties: false
examples:
- |
cru: clock-controller@ff440000 {
compatible = "rockchip,rk3328-cru";
reg = <0xff440000 0x1000>;
rockchip,grf = <&grf>;
#clock-cells = <1>;
#reset-cells = <1>;
};

View File

@ -16,8 +16,8 @@ merged to this clock. The component clocks shall be of one of the
"ti,*composite*-clock" types.
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
[2] Documentation/devicetree/bindings/clock/ti/mux.txt
[3] Documentation/devicetree/bindings/clock/ti/divider.txt
[2] Documentation/devicetree/bindings/clock/ti/ti,mux-clock.yaml
[3] Documentation/devicetree/bindings/clock/ti/ti,divider-clock.yaml
[4] Documentation/devicetree/bindings/clock/ti/gate.txt
Required properties:

View File

@ -1,115 +0,0 @@
Binding for TI divider clock
This binding uses the common clock binding[1]. It assumes a
register-mapped adjustable clock rate divider that does not gate and has
only one input clock or parent. By default the value programmed into
the register is one less than the actual divisor value. E.g:
register value actual divisor value
0 1
1 2
2 3
This assumption may be modified by the following optional properties:
ti,index-starts-at-one - valid divisor values start at 1, not the default
of 0. E.g:
register value actual divisor value
1 1
2 2
3 3
ti,index-power-of-two - valid divisor values are powers of two. E.g:
register value actual divisor value
0 1
1 2
2 4
Additionally an array of valid dividers may be supplied like so:
ti,dividers = <4>, <8>, <0>, <16>;
Which will map the resulting values to a divisor table by their index:
register value actual divisor value
0 4
1 8
2 <invalid divisor, skipped>
3 16
Any zero value in this array means the corresponding bit-value is invalid
and must not be used.
The binding must also provide the register to control the divider and
unless the divider array is provided, min and max dividers. Optionally
the number of bits to shift that mask, if necessary. If the shift value
is missing it is the same as supplying a zero shift.
This binding can also optionally provide support to the hardware autoidle
feature, see [2].
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
[2] Documentation/devicetree/bindings/clock/ti/autoidle.txt
Required properties:
- compatible : shall be "ti,divider-clock" or "ti,composite-divider-clock".
- #clock-cells : from common clock binding; shall be set to 0.
- clocks : link to phandle of parent clock
- reg : offset for register controlling adjustable divider
Optional properties:
- clock-output-names : from common clock binding.
- ti,dividers : array of integers defining divisors
- ti,bit-shift : number of bits to shift the divider value, defaults to 0
- ti,min-div : min divisor for dividing the input clock rate, only
needed if the first divisor is offset from the default value (1)
- ti,max-div : max divisor for dividing the input clock rate, only needed
if ti,dividers is not defined.
- ti,index-starts-at-one : valid divisor programming starts at 1, not zero,
only valid if ti,dividers is not defined.
- ti,index-power-of-two : valid divisor programming must be a power of two,
only valid if ti,dividers is not defined.
- ti,autoidle-shift : bit shift of the autoidle enable bit for the clock,
see [2]
- ti,invert-autoidle-bit : autoidle is enabled by setting the bit to 0,
see [2]
- ti,set-rate-parent : clk_set_rate is propagated to parent
- ti,latch-bit : latch the divider value to HW, only needed if the register
access requires this. As an example dra76x DPLL_GMAC H14 divider implements
such behavior.
Examples:
dpll_usb_m2_ck: dpll_usb_m2_ck@4a008190 {
#clock-cells = <0>;
compatible = "ti,divider-clock";
clocks = <&dpll_usb_ck>;
ti,max-div = <127>;
reg = <0x190>;
ti,index-starts-at-one;
};
aess_fclk: aess_fclk@4a004528 {
#clock-cells = <0>;
compatible = "ti,divider-clock";
clocks = <&abe_clk>;
ti,bit-shift = <24>;
reg = <0x528>;
ti,max-div = <2>;
};
dpll_core_m3x2_div_ck: dpll_core_m3x2_div_ck {
#clock-cells = <0>;
compatible = "ti,composite-divider-clock";
clocks = <&dpll_core_x2_ck>;
ti,max-div = <31>;
reg = <0x0134>;
ti,index-starts-at-one;
};
ssi_ssr_div_fck_3430es2: ssi_ssr_div_fck_3430es2 {
#clock-cells = <0>;
compatible = "ti,composite-divider-clock";
clocks = <&corex2_fck>;
ti,bit-shift = <8>;
reg = <0x0a40>;
ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>;
};

View File

@ -1,55 +0,0 @@
Binding for Texas Instruments interface clock.
This binding uses the common clock binding[1]. This clock is
quite much similar to the basic gate-clock [2], however,
it supports a number of additional features, including
companion clock finding (match corresponding functional gate
clock) and hardware autoidle enable / disable.
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
[2] Documentation/devicetree/bindings/clock/gpio-gate-clock.yaml
Required properties:
- compatible : shall be one of:
"ti,omap3-interface-clock" - basic OMAP3 interface clock
"ti,omap3-no-wait-interface-clock" - interface clock which has no hardware
capability for waiting clock to be ready
"ti,omap3-hsotgusb-interface-clock" - interface clock with USB specific HW
handling
"ti,omap3-dss-interface-clock" - interface clock with DSS specific HW handling
"ti,omap3-ssi-interface-clock" - interface clock with SSI specific HW handling
"ti,am35xx-interface-clock" - interface clock with AM35xx specific HW handling
"ti,omap2430-interface-clock" - interface clock with OMAP2430 specific HW
handling
- #clock-cells : from common clock binding; shall be set to 0
- clocks : link to phandle of parent clock
- reg : base address for the control register
Optional properties:
- clock-output-names : from common clock binding.
- ti,bit-shift : bit shift for the bit enabling/disabling the clock (default 0)
Examples:
aes1_ick: aes1_ick@48004a14 {
#clock-cells = <0>;
compatible = "ti,omap3-interface-clock";
clocks = <&security_l4_ick2>;
reg = <0x48004a14 0x4>;
ti,bit-shift = <3>;
};
cam_ick: cam_ick@48004f10 {
#clock-cells = <0>;
compatible = "ti,omap3-no-wait-interface-clock";
clocks = <&l4_ick>;
reg = <0x48004f10 0x4>;
ti,bit-shift = <0>;
};
ssi_ick_3430es2: ssi_ick_3430es2@48004a10 {
#clock-cells = <0>;
compatible = "ti,omap3-ssi-interface-clock";
clocks = <&ssi_l4_ick>;
reg = <0x48004a10 0x4>;
ti,bit-shift = <0>;
};

View File

@ -1,78 +0,0 @@
Binding for TI mux clock.
This binding uses the common clock binding[1]. It assumes a
register-mapped multiplexer with multiple input clock signals or
parents, one of which can be selected as output. This clock does not
gate or adjust the parent rate via a divider or multiplier.
By default the "clocks" property lists the parents in the same order
as they are programmed into the register. E.g:
clocks = <&foo_clock>, <&bar_clock>, <&baz_clock>;
results in programming the register as follows:
register value selected parent clock
0 foo_clock
1 bar_clock
2 baz_clock
Some clock controller IPs do not allow a value of zero to be programmed
into the register, instead indexing begins at 1. The optional property
"index-starts-at-one" modified the scheme as follows:
register value selected clock parent
1 foo_clock
2 bar_clock
3 baz_clock
The binding must provide the register to control the mux. Optionally
the number of bits to shift the control field in the register can be
supplied. If the shift value is missing it is the same as supplying
a zero shift.
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
Required properties:
- compatible : shall be "ti,mux-clock" or "ti,composite-mux-clock".
- #clock-cells : from common clock binding; shall be set to 0.
- clocks : link phandles of parent clocks
- reg : register offset for register controlling adjustable mux
Optional properties:
- clock-output-names : from common clock binding.
- ti,bit-shift : number of bits to shift the bit-mask, defaults to
0 if not present
- ti,index-starts-at-one : valid input select programming starts at 1, not
zero
- ti,set-rate-parent : clk_set_rate is propagated to parent clock,
not supported by the composite-mux-clock subtype
- ti,latch-bit : latch the mux value to HW, only needed if the register
access requires this. As an example, dra7x DPLL_GMAC H14 muxing
implements such behavior.
Examples:
sys_clkin_ck: sys_clkin_ck@4a306110 {
#clock-cells = <0>;
compatible = "ti,mux-clock";
clocks = <&virt_12000000_ck>, <&virt_13000000_ck>, <&virt_16800000_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_27000000_ck>, <&virt_38400000_ck>;
reg = <0x0110>;
ti,index-starts-at-one;
};
abe_dpll_bypass_clk_mux_ck: abe_dpll_bypass_clk_mux_ck@4a306108 {
#clock-cells = <0>;
compatible = "ti,mux-clock";
clocks = <&sys_clkin_ck>, <&sys_32k_ck>;
ti,bit-shift = <24>;
reg = <0x0108>;
};
mcbsp5_mux_fck: mcbsp5_mux_fck {
#clock-cells = <0>;
compatible = "ti,composite-mux-clock";
clocks = <&core_96m_fck>, <&mcbsp_clks>;
ti,bit-shift = <4>;
reg = <0x02d8>;
};

View File

@ -0,0 +1,193 @@
# SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/ti/ti,divider-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments divider clock
maintainers:
- Tero Kristo <kristo@kernel.org>
description: |
This clock It assumes a register-mapped adjustable clock rate divider
that does not gate and has only one input clock or parent. By default the
value programmed into the register is one less than the actual divisor value.
E.g:
register value actual divisor value
0 1
1 2
2 3
This assumption may be modified by the following optional properties:
ti,index-starts-at-one - valid divisor values start at 1, not the default
of 0. E.g:
register value actual divisor value
1 1
2 2
3 3
ti,index-power-of-two - valid divisor values are powers of two. E.g:
register value actual divisor value
0 1
1 2
2 4
Additionally an array of valid dividers may be supplied like so:
ti,dividers = <4>, <8>, <0>, <16>;
Which will map the resulting values to a divisor table by their index:
register value actual divisor value
0 4
1 8
2 <invalid divisor, skipped>
3 16
Any zero value in this array means the corresponding bit-value is invalid
and must not be used.
The binding must also provide the register to control the divider and
unless the divider array is provided, min and max dividers. Optionally
the number of bits to shift that mask, if necessary. If the shift value
is missing it is the same as supplying a zero shift.
This binding can also optionally provide support to the hardware autoidle
feature, see [1].
[1] Documentation/devicetree/bindings/clock/ti/autoidle.txt
properties:
compatible:
enum:
- ti,divider-clock
- ti,composite-divider-clock
"#clock-cells":
const: 0
clocks:
maxItems: 1
clock-output-names:
maxItems: 1
reg:
maxItems: 1
ti,dividers:
$ref: /schemas/types.yaml#/definitions/uint32-array
description:
array of integers defining divisors
ti,bit-shift:
$ref: /schemas/types.yaml#/definitions/uint32
description:
number of bits to shift the divider value
maximum: 31
default: 0
ti,min-div:
$ref: /schemas/types.yaml#/definitions/uint32
description:
min divisor for dividing the input clock rate, only
needed if the first divisor is offset from the default value (1)
minimum: 1
default: 1
ti,max-div:
$ref: /schemas/types.yaml#/definitions/uint32
description:
max divisor for dividing the input clock rate, only needed
if ti,dividers is not defined.
ti,index-starts-at-one:
type: boolean
description:
valid divisor programming starts at 1, not zero,
only valid if ti,dividers is not defined
ti,index-power-of-two:
type: boolean
description:
valid divisor programming must be a power of two,
only valid if ti,dividers is not defined.
ti,autoidle-shift:
$ref: /schemas/types.yaml#/definitions/uint32
description:
bit shift of the autoidle enable bit for the clock,
see [1].
maximum: 31
default: 0
ti,invert-autoidle-bit:
type: boolean
description:
autoidle is enabled by setting the bit to 0,
see [1]
ti,set-rate-parent:
type: boolean
description:
clk_set_rate is propagated to parent |
ti,latch-bit:
$ref: /schemas/types.yaml#/definitions/uint32
description:
latch the divider value to HW, only needed if the register
compatible access requires this. As an example dra76x DPLL_GMAC
H14 divider implements such behavior.
dependentSchemas:
ti,dividers:
properties:
ti,min-div: false
ti,max-div: false
ti,index-power-of-two: false
ti,index-starts-at-one: false
required:
- compatible
- "#clock-cells"
- clocks
- reg
additionalProperties: false
examples:
- |
bus {
#address-cells = <1>;
#size-cells = <0>;
clock-controller@190 {
#clock-cells = <0>;
compatible = "ti,divider-clock";
clocks = <&dpll_usb_ck>;
ti,max-div = <127>;
reg = <0x190>;
ti,index-starts-at-one;
};
clock-controller@528 {
#clock-cells = <0>;
compatible = "ti,divider-clock";
clocks = <&abe_clk>;
ti,bit-shift = <24>;
reg = <0x528>;
ti,max-div = <2>;
};
clock-controller@a40 {
#clock-cells = <0>;
compatible = "ti,composite-divider-clock";
clocks = <&corex2_fck>;
ti,bit-shift = <8>;
reg = <0x0a40>;
ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>;
};
};

View File

@ -0,0 +1,71 @@
# SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/ti/ti,interface-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments interface clock.
maintainers:
- Tero Kristo <kristo@kernel.org>
description: |
This clock is quite much similar to the basic gate-clock[1], however,
it supports a number of additional features, including
companion clock finding (match corresponding functional gate
clock) and hardware autoidle enable / disable.
[1] Documentation/devicetree/bindings/clock/gpio-gate-clock.yaml
properties:
compatible:
enum:
- ti,omap3-interface-clock # basic OMAP3 interface clock
- ti,omap3-no-wait-interface-clock # interface clock which has no hardware
# capability for waiting clock to be ready
- ti,omap3-hsotgusb-interface-clock # interface clock with USB specific HW handling
- ti,omap3-dss-interface-clock # interface clock with DSS specific HW handling
- ti,omap3-ssi-interface-clock # interface clock with SSI specific HW handling
- ti,am35xx-interface-clock # interface clock with AM35xx specific HW handling
- ti,omap2430-interface-clock # interface clock with OMAP2430 specific HW handling
"#clock-cells":
const: 0
clocks:
maxItems: 1
clock-output-names:
maxItems: 1
reg:
maxItems: 1
ti,bit-shift:
description:
bit shift for the bit enabling/disabling the clock
$ref: /schemas/types.yaml#/definitions/uint32
default: 0
maximum: 31
required:
- compatible
- clocks
- '#clock-cells'
- reg
additionalProperties: false
examples:
- |
bus {
#address-cells = <1>;
#size-cells = <0>;
aes1_ick: clock-controller@3 {
#clock-cells = <0>;
compatible = "ti,omap3-interface-clock";
clocks = <&security_l4_ick2>;
reg = <3>;
};
};

View File

@ -0,0 +1,125 @@
# SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/ti/ti,mux-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments mux clock
maintainers:
- Tero Kristo <kristo@kernel.org>
description: |
This clock assumes a register-mapped multiplexer with multiple inpt clock
signals or parents, one of which can be selected as output. This clock does
not gate or adjust the parent rate via a divider or multiplier.
By default the "clocks" property lists the parents in the same order
as they are programmed into the register. E.g:
clocks = <&foo_clock>, <&bar_clock>, <&baz_clock>;
Results in programming the register as follows:
register value selected parent clock
0 foo_clock
1 bar_clock
2 baz_clock
Some clock controller IPs do not allow a value of zero to be programmed
into the register, instead indexing begins at 1. The optional property
"index-starts-at-one" modified the scheme as follows:
register value selected clock parent
1 foo_clock
2 bar_clock
3 baz_clock
The binding must provide the register to control the mux. Optionally
the number of bits to shift the control field in the register can be
supplied. If the shift value is missing it is the same as supplying
a zero shift.
properties:
compatible:
enum:
- ti,mux-clock
- ti,composite-mux-clock
"#clock-cells":
const: 0
clocks: true
clock-output-names:
maxItems: 1
reg:
maxItems: 1
ti,bit-shift:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Number of bits to shift the bit-mask
maximum: 31
default: 0
ti,index-starts-at-one:
type: boolean
description:
Valid input select programming starts at 1, not zero
ti,set-rate-parent:
type: boolean
description:
clk_set_rate is propagated to parent clock,
not supported by the composite-mux-clock subtype.
ti,latch-bit:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Latch the mux value to HW, only needed if the register
access requires this. As an example, dra7x DPLL_GMAC H14 muxing
implements such behavior.
maximum: 31
if:
properties:
compatible:
contains:
const: ti,composite-mux-clock
then:
properties:
ti,set-rate-parent: false
required:
- compatible
- "#clock-cells"
- clocks
- reg
additionalProperties: false
examples:
- |
bus {
#address-cells = <1>;
#size-cells = <0>;
clock-controller@110 {
compatible = "ti,mux-clock";
reg = <0x0110>;
#clock-cells = <0>;
clocks = <&virt_12000000_ck>, <&virt_13000000_ck>, <&virt_16800000_ck>;
ti,index-starts-at-one;
ti,set-rate-parent;
};
clock-controller@120 {
compatible = "ti,composite-mux-clock";
reg = <0x0120>;
#clock-cells = <0>;
clocks = <&core_96m_fck>, <&mcbsp_clks>;
ti,bit-shift = <4>;
};
};

View File

@ -39,6 +39,11 @@ properties:
- const: clk_in1
- const: s_axi_aclk
xlnx,static-config:
$ref: /schemas/types.yaml#/definitions/flag
description:
Indicate whether the core has been configured without support for dynamic
runtime reconfguration of the clocking primitive MMCM/PLL.
xlnx,speed-grade:
$ref: /schemas/types.yaml#/definitions/uint32
@ -70,6 +75,7 @@ examples:
compatible = "xlnx,clocking-wizard";
reg = <0xb0000000 0x10000>;
#clock-cells = <1>;
xlnx,static-config;
xlnx,speed-grade = <1>;
xlnx,nr-outputs = <6>;
clock-names = "clk_in1", "s_axi_aclk";

View File

@ -21,6 +21,13 @@ properties:
'#reset-cells':
const: 2
'#clock-cells':
const: 1
clocks:
items:
- description: specify external 25MHz reference clock.
nuvoton,sysgcr:
$ref: /schemas/types.yaml#/definitions/phandle
description: a phandle to access GCR registers.
@ -39,6 +46,17 @@ required:
- '#reset-cells'
- nuvoton,sysgcr
if:
properties:
compatible:
contains:
enum:
- nuvoton,npcm845-reset
then:
required:
- '#clock-cells'
- clocks
additionalProperties: false
examples:

View File

@ -41,9 +41,7 @@ properties:
enum: [ 1, 2 ]
'#clock-cells':
description:
Cell is clock index. Optional if compatible has a single clock.
enum: [ 0, 1 ]
const: 1
clocks:
maxItems: 1
@ -312,26 +310,6 @@ allOf:
properties:
'#reset-cells': false
# Compatibles exposing a single clock.
- if:
properties:
compatible:
contains:
enum:
- mobileye,eyeq6h-central-olb
- mobileye,eyeq6h-east-olb
- mobileye,eyeq6h-west-olb
- mobileye,eyeq6h-ddr0-olb
- mobileye,eyeq6h-ddr1-olb
then:
properties:
'#clock-cells':
const: 0
else:
properties:
'#clock-cells':
const: 1
# Only EyeQ5 has pinctrl in OLB.
- if:
not:

View File

@ -2006,7 +2006,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
L: linux-actions@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/arm/actions.yaml
F: Documentation/devicetree/bindings/clock/actions,owl-cmu.txt
F: Documentation/devicetree/bindings/clock/actions,owl-cmu.yaml
F: Documentation/devicetree/bindings/dma/owl-dma.yaml
F: Documentation/devicetree/bindings/i2c/i2c-owl.yaml
F: Documentation/devicetree/bindings/interrupt-controller/actions,owl-sirq.yaml
@ -14570,6 +14570,32 @@ S: Maintained
F: Documentation/devicetree/bindings/mmc/mtk-sd.yaml
F: drivers/mmc/host/mtk-sd.c
MEDIATEK MT6735 CLOCK & RESET DRIVERS
M: Yassine Oudjana <y.oudjana@protonmail.com>
L: linux-clk@vger.kernel.org
L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: drivers/clk/mediatek/clk-mt6735-apmixedsys.c
F: drivers/clk/mediatek/clk-mt6735-imgsys.c
F: drivers/clk/mediatek/clk-mt6735-infracfg.c
F: drivers/clk/mediatek/clk-mt6735-mfgcfg.c
F: drivers/clk/mediatek/clk-mt6735-pericfg.c
F: drivers/clk/mediatek/clk-mt6735-topckgen.c
F: drivers/clk/mediatek/clk-mt6735-vdecsys.c
F: drivers/clk/mediatek/clk-mt6735-vencsys.c
F: include/dt-bindings/clock/mediatek,mt6735-apmixedsys.h
F: include/dt-bindings/clock/mediatek,mt6735-imgsys.h
F: include/dt-bindings/clock/mediatek,mt6735-infracfg.h
F: include/dt-bindings/clock/mediatek,mt6735-mfgcfg.h
F: include/dt-bindings/clock/mediatek,mt6735-pericfg.h
F: include/dt-bindings/clock/mediatek,mt6735-topckgen.h
F: include/dt-bindings/clock/mediatek,mt6735-vdecsys.h
F: include/dt-bindings/clock/mediatek,mt6735-vencsys.h
F: include/dt-bindings/reset/mediatek,mt6735-infracfg.h
F: include/dt-bindings/reset/mediatek,mt6735-mfgcfg.h
F: include/dt-bindings/reset/mediatek,mt6735-pericfg.h
F: include/dt-bindings/reset/mediatek,mt6735-vdecsys.h
MEDIATEK MT76 WIRELESS LAN DRIVER
M: Felix Fietkau <nbd@nbd.name>
M: Lorenzo Bianconi <lorenzo@kernel.org>

View File

@ -1,5 +1,6 @@
CONFIG_KUNIT=y
CONFIG_OF=y
CONFIG_OF_OVERLAY=y
CONFIG_COMMON_CLK=y
CONFIG_CLK_KUNIT_TEST=y
CONFIG_CLK_FIXED_RATE_KUNIT_TEST=y

View File

@ -226,6 +226,17 @@ config COMMON_CLK_EP93XX
help
This driver supports the SoC clocks on the Cirrus Logic ep93xx.
config COMMON_CLK_EYEQ
bool "Clock driver for the Mobileye EyeQ platform"
depends on MACH_EYEQ5 || MACH_EYEQ6H || COMPILE_TEST
select AUXILIARY_BUS
default MACH_EYEQ5 || MACH_EYEQ6H
help
This driver provides clocks found on Mobileye EyeQ5, EyeQ6L and Eye6H
SoCs. Controllers live in shared register regions called OLB. Driver
provides read-only PLLs, derived from the main crystal clock (which
must be constant). It also exposes some divider clocks.
config COMMON_CLK_FSL_FLEXSPI
tristate "Clock driver for FlexSPI on Layerscape SoCs"
depends on ARCH_LAYERSCAPE || COMPILE_TEST
@ -259,7 +270,7 @@ config COMMON_CLK_LAN966X
tristate "Generic Clock Controller driver for LAN966X SoC"
depends on HAS_IOMEM
depends on OF
depends on SOC_LAN966 || COMPILE_TEST
depends on SOC_LAN966 || ARCH_LAN969X || COMPILE_TEST
help
This driver provides support for Generic Clock Controller(GCK) on
LAN966X SoC. GCK generates and supplies clock to various peripherals
@ -291,7 +302,7 @@ config CLK_TWL
help
Enable support for controlling the clock resources on TWL family
PMICs. These devices have some 32K clock outputs which can be
controlled by software. For now, only the TWL6032 clocks are
controlled by software. For now, the TWL6032 and TWL6030 clocks are
supported.
config CLK_TWL6040
@ -342,6 +353,14 @@ config COMMON_CLK_LOCHNAGAR
This driver supports the clocking features of the Cirrus Logic
Lochnagar audio development board.
config COMMON_CLK_NPCM8XX
tristate "Clock driver for the NPCM8XX SoC Family"
depends on ARCH_NPCM || COMPILE_TEST
help
This driver supports the clocks on the Nuvoton BMC NPCM8XX SoC Family,
all the clocks are initialized by the bootloader, so this driver
allows only reading of current settings directly from the hardware.
config COMMON_CLK_LOONGSON2
bool "Clock driver for Loongson-2 SoC"
depends on LOONGARCH || COMPILE_TEST
@ -517,7 +536,6 @@ config CLK_KUNIT_TEST
tristate "Basic Clock Framework Kunit Tests" if !KUNIT_ALL_TESTS
depends on KUNIT
default KUNIT_ALL_TESTS
select OF_OVERLAY if OF
select DTC
help
Kunit tests for the common clock framework.
@ -526,7 +544,6 @@ 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.

View File

@ -4,6 +4,20 @@ obj-$(CONFIG_HAVE_CLK) += clk-devres.o clk-bulk.o clkdev.o
obj-$(CONFIG_COMMON_CLK) += clk.o
obj-$(CONFIG_CLK_KUNIT_TEST) += clk-test.o
clk-test-y := clk_test.o \
kunit_clk_assigned_rates_u64_one.dtbo.o \
kunit_clk_assigned_rates_u64_one_consumer.dtbo.o \
kunit_clk_assigned_rates_u64_multiple.dtbo.o \
kunit_clk_assigned_rates_u64_multiple_consumer.dtbo.o \
kunit_clk_assigned_rates_multiple.dtbo.o \
kunit_clk_assigned_rates_multiple_consumer.dtbo.o \
kunit_clk_assigned_rates_null.dtbo.o \
kunit_clk_assigned_rates_null_consumer.dtbo.o \
kunit_clk_assigned_rates_one.dtbo.o \
kunit_clk_assigned_rates_one_consumer.dtbo.o \
kunit_clk_assigned_rates_without.dtbo.o \
kunit_clk_assigned_rates_without_consumer.dtbo.o \
kunit_clk_assigned_rates_zero.dtbo.o \
kunit_clk_assigned_rates_zero_consumer.dtbo.o \
kunit_clk_parent_data_test.dtbo.o
obj-$(CONFIG_COMMON_CLK) += clk-divider.o
obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o
@ -42,6 +56,7 @@ obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
obj-$(CONFIG_COMMON_CLK_EP93XX) += clk-ep93xx.o
obj-$(CONFIG_ARCH_SPARX5) += clk-sparx5.o
obj-$(CONFIG_COMMON_CLK_EN7523) += clk-en7523.o
obj-$(CONFIG_COMMON_CLK_EYEQ) += clk-eyeq.o
obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o
obj-$(CONFIG_COMMON_CLK_FSL_FLEXSPI) += clk-fsl-flexspi.o
obj-$(CONFIG_COMMON_CLK_FSL_SAI) += clk-fsl-sai.o
@ -62,6 +77,7 @@ obj-$(CONFIG_ARCH_MILBEAUT_M10V) += clk-milbeaut.o
obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
obj-$(CONFIG_ARCH_NPCM7XX) += clk-npcm7xx.o
obj-$(CONFIG_COMMON_CLK_NPCM8XX) += clk-npcm8xx.o
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o
obj-$(CONFIG_CLK_LS1028A_PLLDIG) += clk-plldig.o

View File

@ -297,6 +297,9 @@ static int applnco_probe(struct platform_device *pdev)
memset(&init, 0, sizeof(init));
init.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"%s-%d", np->name, i);
if (!init.name)
return -ENOMEM;
init.ops = &applnco_ops;
init.parent_data = &pdata;
init.num_parents = 1;

View File

@ -7,6 +7,7 @@
*/
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/slab.h>
#include <linux/io.h>
@ -512,6 +513,7 @@ static int axi_clkgen_probe(struct platform_device *pdev)
struct clk_init_data init;
const char *parent_names[2];
const char *clk_name;
struct clk *axi_clk;
unsigned int i;
int ret;
@ -528,8 +530,24 @@ static int axi_clkgen_probe(struct platform_device *pdev)
return PTR_ERR(axi_clkgen->base);
init.num_parents = of_clk_get_parent_count(pdev->dev.of_node);
if (init.num_parents < 1 || init.num_parents > 2)
return -EINVAL;
axi_clk = devm_clk_get_enabled(&pdev->dev, "s_axi_aclk");
if (!IS_ERR(axi_clk)) {
if (init.num_parents < 2 || init.num_parents > 3)
return -EINVAL;
init.num_parents -= 1;
} else {
/*
* Legacy... So that old DTs which do not have clock-names still
* work. In this case we don't explicitly enable the AXI bus
* clock.
*/
if (PTR_ERR(axi_clk) != -ENOENT)
return PTR_ERR(axi_clk);
if (init.num_parents < 1 || init.num_parents > 2)
return -EINVAL;
}
for (i = 0; i < init.num_parents; i++) {
parent_names[i] = of_clk_get_parent_name(pdev->dev.of_node, i);

View File

@ -678,7 +678,7 @@ MODULE_DEVICE_TABLE(of, cdce706_dt_match);
#endif
static const struct i2c_device_id cdce706_id[] = {
{ "cdce706", 0 },
{ "cdce706" },
{ }
};
MODULE_DEVICE_TABLE(i2c, cdce706_id);

View File

@ -601,7 +601,7 @@ static int cdce925_regulator_enable(struct device *dev, const char *name)
/* The CDCE925 uses a funky way to read/write registers. Bulk mode is
* just weird, so just use the single byte mode exclusively. */
static struct regmap_bus regmap_cdce925_bus = {
static const struct regmap_bus regmap_cdce925_bus = {
.write = cdce925_regmap_i2c_write,
.read = cdce925_regmap_i2c_read,
};

View File

@ -218,8 +218,8 @@ static void devm_clk_bulk_release_all_enable(struct device *dev, void *res)
clk_bulk_put_all(devres->num_clks, devres->clks);
}
int __must_check devm_clk_bulk_get_all_enable(struct device *dev,
struct clk_bulk_data **clks)
int __must_check devm_clk_bulk_get_all_enabled(struct device *dev,
struct clk_bulk_data **clks)
{
struct clk_bulk_devres *devres;
int ret;
@ -244,11 +244,12 @@ int __must_check devm_clk_bulk_get_all_enable(struct device *dev,
} else {
clk_bulk_put_all(devres->num_clks, devres->clks);
devres_free(devres);
return ret;
}
return ret;
return devres->num_clks;
}
EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all_enable);
EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all_enabled);
static int devm_clk_match(struct device *dev, void *res, void *data)
{

View File

@ -72,6 +72,8 @@ static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width,
return clk_div_mask(width);
if (flags & CLK_DIVIDER_POWER_OF_TWO)
return 1 << clk_div_mask(width);
if (flags & CLK_DIVIDER_EVEN_INTEGERS)
return 2 * (clk_div_mask(width) + 1);
if (table)
return _get_table_maxdiv(table, width);
return clk_div_mask(width) + 1;
@ -97,6 +99,8 @@ static unsigned int _get_div(const struct clk_div_table *table,
return 1 << val;
if (flags & CLK_DIVIDER_MAX_AT_ZERO)
return val ? val : clk_div_mask(width) + 1;
if (flags & CLK_DIVIDER_EVEN_INTEGERS)
return 2 * (val + 1);
if (table)
return _get_table_div(table, val);
return val + 1;
@ -122,6 +126,8 @@ static unsigned int _get_val(const struct clk_div_table *table,
return __ffs(div);
if (flags & CLK_DIVIDER_MAX_AT_ZERO)
return (div == clk_div_mask(width) + 1) ? 0 : div;
if (flags & CLK_DIVIDER_EVEN_INTEGERS)
return (div >> 1) - 1;
if (table)
return _get_table_val(table, div);
return div - 1;
@ -538,7 +544,8 @@ struct clk_hw *__clk_hw_register_divider(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,
void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
void __iomem *reg, u8 shift, u8 width,
unsigned long clk_divider_flags,
const struct clk_div_table *table, spinlock_t *lock)
{
struct clk_divider *div;
@ -610,8 +617,8 @@ EXPORT_SYMBOL_GPL(__clk_hw_register_divider);
struct clk *clk_register_divider_table(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, const struct clk_div_table *table,
spinlock_t *lock)
unsigned long clk_divider_flags,
const struct clk_div_table *table, spinlock_t *lock)
{
struct clk_hw *hw;
@ -664,7 +671,8 @@ struct clk_hw *__devm_clk_hw_register_divider(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,
void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
void __iomem *reg, u8 shift, u8 width,
unsigned long clk_divider_flags,
const struct clk_div_table *table, spinlock_t *lock)
{
struct clk_hw **ptr, *hw;

View File

@ -3,8 +3,10 @@
#include <linux/delay.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/reset-controller.h>
#include <dt-bindings/clock/en7523-clk.h>
#include <dt-bindings/reset/airoha,en7581-reset.h>
@ -31,19 +33,14 @@
#define REG_RESET_CONTROL_PCIE1 BIT(27)
#define REG_RESET_CONTROL_PCIE2 BIT(26)
/* EN7581 */
#define REG_PCIE0_MEM 0x00
#define REG_PCIE0_MEM_MASK 0x04
#define REG_PCIE1_MEM 0x08
#define REG_PCIE1_MEM_MASK 0x0c
#define REG_PCIE2_MEM 0x10
#define REG_PCIE2_MEM_MASK 0x14
#define REG_NP_SCU_PCIC 0x88
#define REG_NP_SCU_SSTR 0x9c
#define REG_PCIE_XSI0_SEL_MASK GENMASK(14, 13)
#define REG_PCIE_XSI1_SEL_MASK GENMASK(12, 11)
#define REG_CRYPTO_CLKSRC2 0x20c
#define REG_RST_CTRL2 0x00
#define REG_RST_CTRL1 0x04
#define REG_RST_CTRL2 0x830
#define REG_RST_CTRL1 0x834
struct en_clk_desc {
int id;
@ -79,12 +76,8 @@ struct en_rst_data {
struct en_clk_soc_data {
const struct clk_ops pcie_ops;
struct {
const u16 *bank_ofs;
const u16 *idx_map;
u16 idx_map_nr;
} reset;
int (*hw_init)(struct platform_device *pdev, void __iomem *np_base);
int (*hw_init)(struct platform_device *pdev,
struct clk_hw_onecell_data *clk_data);
};
static const u32 gsw_base[] = { 400000000, 500000000 };
@ -92,6 +85,10 @@ static const u32 emi_base[] = { 333000000, 400000000 };
static const u32 bus_base[] = { 500000000, 540000000 };
static const u32 slic_base[] = { 100000000, 3125000 };
static const u32 npu_base[] = { 333000000, 400000000, 500000000 };
/* EN7581 */
static const u32 emi7581_base[] = { 540000000, 480000000, 400000000, 300000000 };
static const u32 npu7581_base[] = { 800000000, 750000000, 720000000, 600000000 };
static const u32 crypto_base[] = { 540000000, 480000000 };
static const struct en_clk_desc en7523_base_clks[] = {
{
@ -189,6 +186,102 @@ static const struct en_clk_desc en7523_base_clks[] = {
}
};
static const struct en_clk_desc en7581_base_clks[] = {
{
.id = EN7523_CLK_GSW,
.name = "gsw",
.base_reg = REG_GSW_CLK_DIV_SEL,
.base_bits = 1,
.base_shift = 8,
.base_values = gsw_base,
.n_base_values = ARRAY_SIZE(gsw_base),
.div_bits = 3,
.div_shift = 0,
.div_step = 1,
.div_offset = 1,
}, {
.id = EN7523_CLK_EMI,
.name = "emi",
.base_reg = REG_EMI_CLK_DIV_SEL,
.base_bits = 2,
.base_shift = 8,
.base_values = emi7581_base,
.n_base_values = ARRAY_SIZE(emi7581_base),
.div_bits = 3,
.div_shift = 0,
.div_step = 1,
.div_offset = 1,
}, {
.id = EN7523_CLK_BUS,
.name = "bus",
.base_reg = REG_BUS_CLK_DIV_SEL,
.base_bits = 1,
.base_shift = 8,
.base_values = bus_base,
.n_base_values = ARRAY_SIZE(bus_base),
.div_bits = 3,
.div_shift = 0,
.div_step = 1,
.div_offset = 1,
}, {
.id = EN7523_CLK_SLIC,
.name = "slic",
.base_reg = REG_SPI_CLK_FREQ_SEL,
.base_bits = 1,
.base_shift = 0,
.base_values = slic_base,
.n_base_values = ARRAY_SIZE(slic_base),
.div_reg = REG_SPI_CLK_DIV_SEL,
.div_bits = 5,
.div_shift = 24,
.div_val0 = 20,
.div_step = 2,
}, {
.id = EN7523_CLK_SPI,
.name = "spi",
.base_reg = REG_SPI_CLK_DIV_SEL,
.base_value = 400000000,
.div_bits = 5,
.div_shift = 8,
.div_val0 = 40,
.div_step = 2,
}, {
.id = EN7523_CLK_NPU,
.name = "npu",
.base_reg = REG_NPU_CLK_DIV_SEL,
.base_bits = 2,
.base_shift = 8,
.base_values = npu7581_base,
.n_base_values = ARRAY_SIZE(npu7581_base),
.div_bits = 3,
.div_shift = 0,
.div_step = 1,
.div_offset = 1,
}, {
.id = EN7523_CLK_CRYPTO,
.name = "crypto",
.base_reg = REG_CRYPTO_CLKSRC2,
.base_bits = 1,
.base_shift = 0,
.base_values = crypto_base,
.n_base_values = ARRAY_SIZE(crypto_base),
}
};
static const u16 en7581_rst_ofs[] = {
REG_RST_CTRL2,
REG_RST_CTRL1,
@ -252,15 +345,11 @@ static const u16 en7581_rst_map[] = {
[EN7581_XPON_MAC_RST] = RST_NR_PER_BANK + 31,
};
static unsigned int en7523_get_base_rate(void __iomem *base, unsigned int i)
static u32 en7523_get_base_rate(const struct en_clk_desc *desc, u32 val)
{
const struct en_clk_desc *desc = &en7523_base_clks[i];
u32 val;
if (!desc->base_bits)
return desc->base_value;
val = readl(base + desc->base_reg);
val >>= desc->base_shift;
val &= (1 << desc->base_bits) - 1;
@ -270,16 +359,11 @@ static unsigned int en7523_get_base_rate(void __iomem *base, unsigned int i)
return desc->base_values[val];
}
static u32 en7523_get_div(void __iomem *base, int i)
static u32 en7523_get_div(const struct en_clk_desc *desc, u32 val)
{
const struct en_clk_desc *desc = &en7523_base_clks[i];
u32 reg, val;
if (!desc->div_bits)
return 1;
reg = desc->div_reg ? desc->div_reg : desc->base_reg;
val = readl(base + reg);
val >>= desc->div_shift;
val &= (1 << desc->div_bits) - 1;
@ -412,32 +496,6 @@ static void en7581_pci_disable(struct clk_hw *hw)
usleep_range(1000, 2000);
}
static int en7581_clk_hw_init(struct platform_device *pdev,
void __iomem *np_base)
{
void __iomem *pb_base;
u32 val;
pb_base = devm_platform_ioremap_resource(pdev, 3);
if (IS_ERR(pb_base))
return PTR_ERR(pb_base);
val = readl(np_base + REG_NP_SCU_SSTR);
val &= ~(REG_PCIE_XSI0_SEL_MASK | REG_PCIE_XSI1_SEL_MASK);
writel(val, np_base + REG_NP_SCU_SSTR);
val = readl(np_base + REG_NP_SCU_PCIC);
writel(val | 3, np_base + REG_NP_SCU_PCIC);
writel(0x20000000, pb_base + REG_PCIE0_MEM);
writel(0xfc000000, pb_base + REG_PCIE0_MEM_MASK);
writel(0x24000000, pb_base + REG_PCIE1_MEM);
writel(0xfc000000, pb_base + REG_PCIE1_MEM_MASK);
writel(0x28000000, pb_base + REG_PCIE2_MEM);
writel(0xfc000000, pb_base + REG_PCIE2_MEM_MASK);
return 0;
}
static void en7523_register_clocks(struct device *dev, struct clk_hw_onecell_data *clk_data,
void __iomem *base, void __iomem *np_base)
{
@ -447,9 +505,12 @@ static void en7523_register_clocks(struct device *dev, struct clk_hw_onecell_dat
for (i = 0; i < ARRAY_SIZE(en7523_base_clks); i++) {
const struct en_clk_desc *desc = &en7523_base_clks[i];
u32 reg = desc->div_reg ? desc->div_reg : desc->base_reg;
u32 val = readl(base + desc->base_reg);
rate = en7523_get_base_rate(base, i);
rate /= en7523_get_div(base, i);
rate = en7523_get_base_rate(desc, val);
val = readl(base + reg);
rate /= en7523_get_div(desc, val);
hw = clk_hw_register_fixed_rate(dev, desc->name, NULL, 0, rate);
if (IS_ERR(hw)) {
@ -467,6 +528,68 @@ static void en7523_register_clocks(struct device *dev, struct clk_hw_onecell_dat
clk_data->num = EN7523_NUM_CLOCKS;
}
static int en7523_clk_hw_init(struct platform_device *pdev,
struct clk_hw_onecell_data *clk_data)
{
void __iomem *base, *np_base;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
np_base = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(np_base))
return PTR_ERR(np_base);
en7523_register_clocks(&pdev->dev, clk_data, base, np_base);
return 0;
}
static void en7581_register_clocks(struct device *dev, struct clk_hw_onecell_data *clk_data,
struct regmap *map, void __iomem *base)
{
struct clk_hw *hw;
u32 rate;
int i;
for (i = 0; i < ARRAY_SIZE(en7581_base_clks); i++) {
const struct en_clk_desc *desc = &en7581_base_clks[i];
u32 val, reg = desc->div_reg ? desc->div_reg : desc->base_reg;
int err;
err = regmap_read(map, desc->base_reg, &val);
if (err) {
pr_err("Failed reading fixed clk rate %s: %d\n",
desc->name, err);
continue;
}
rate = en7523_get_base_rate(desc, val);
err = regmap_read(map, reg, &val);
if (err) {
pr_err("Failed reading fixed clk div %s: %d\n",
desc->name, err);
continue;
}
rate /= en7523_get_div(desc, val);
hw = clk_hw_register_fixed_rate(dev, desc->name, NULL, 0, rate);
if (IS_ERR(hw)) {
pr_err("Failed to register clk %s: %ld\n",
desc->name, PTR_ERR(hw));
continue;
}
clk_data->hws[desc->id] = hw;
}
hw = en7523_register_pcie_clk(dev, base);
clk_data->hws[EN7523_CLK_PCIE] = hw;
clk_data->num = EN7523_NUM_CLOCKS;
}
static int en7523_reset_update(struct reset_controller_dev *rcdev,
unsigned long id, bool assert)
{
@ -516,38 +639,27 @@ static int en7523_reset_xlate(struct reset_controller_dev *rcdev,
return rst_data->idx_map[reset_spec->args[0]];
}
static const struct reset_control_ops en7523_reset_ops = {
static const struct reset_control_ops en7581_reset_ops = {
.assert = en7523_reset_assert,
.deassert = en7523_reset_deassert,
.status = en7523_reset_status,
};
static int en7523_reset_register(struct platform_device *pdev,
const struct en_clk_soc_data *soc_data)
static int en7581_reset_register(struct device *dev, void __iomem *base)
{
struct device *dev = &pdev->dev;
struct en_rst_data *rst_data;
void __iomem *base;
/* no reset lines available */
if (!soc_data->reset.idx_map_nr)
return 0;
base = devm_platform_ioremap_resource(pdev, 2);
if (IS_ERR(base))
return PTR_ERR(base);
rst_data = devm_kzalloc(dev, sizeof(*rst_data), GFP_KERNEL);
if (!rst_data)
return -ENOMEM;
rst_data->bank_ofs = soc_data->reset.bank_ofs;
rst_data->idx_map = soc_data->reset.idx_map;
rst_data->bank_ofs = en7581_rst_ofs;
rst_data->idx_map = en7581_rst_map;
rst_data->base = base;
rst_data->rcdev.nr_resets = soc_data->reset.idx_map_nr;
rst_data->rcdev.nr_resets = ARRAY_SIZE(en7581_rst_map);
rst_data->rcdev.of_xlate = en7523_reset_xlate;
rst_data->rcdev.ops = &en7523_reset_ops;
rst_data->rcdev.ops = &en7581_reset_ops;
rst_data->rcdev.of_node = dev->of_node;
rst_data->rcdev.of_reset_n_cells = 1;
rst_data->rcdev.owner = THIS_MODULE;
@ -556,28 +668,38 @@ static int en7523_reset_register(struct platform_device *pdev,
return devm_reset_controller_register(dev, &rst_data->rcdev);
}
static int en7523_clk_probe(struct platform_device *pdev)
static int en7581_clk_hw_init(struct platform_device *pdev,
struct clk_hw_onecell_data *clk_data)
{
struct device_node *node = pdev->dev.of_node;
const struct en_clk_soc_data *soc_data;
struct clk_hw_onecell_data *clk_data;
void __iomem *base, *np_base;
int r;
struct regmap *map;
void __iomem *base;
u32 val;
map = syscon_regmap_lookup_by_compatible("airoha,en7581-chip-scu");
if (IS_ERR(map))
return PTR_ERR(map);
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
np_base = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(np_base))
return PTR_ERR(np_base);
en7581_register_clocks(&pdev->dev, clk_data, map, base);
soc_data = device_get_match_data(&pdev->dev);
if (soc_data->hw_init) {
r = soc_data->hw_init(pdev, np_base);
if (r)
return r;
}
val = readl(base + REG_NP_SCU_SSTR);
val &= ~(REG_PCIE_XSI0_SEL_MASK | REG_PCIE_XSI1_SEL_MASK);
writel(val, base + REG_NP_SCU_SSTR);
val = readl(base + REG_NP_SCU_PCIC);
writel(val | 3, base + REG_NP_SCU_PCIC);
return en7581_reset_register(&pdev->dev, base);
}
static int en7523_clk_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
const struct en_clk_soc_data *soc_data;
struct clk_hw_onecell_data *clk_data;
int r;
clk_data = devm_kzalloc(&pdev->dev,
struct_size(clk_data, hws, EN7523_NUM_CLOCKS),
@ -585,21 +707,12 @@ static int en7523_clk_probe(struct platform_device *pdev)
if (!clk_data)
return -ENOMEM;
en7523_register_clocks(&pdev->dev, clk_data, base, np_base);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
soc_data = device_get_match_data(&pdev->dev);
r = soc_data->hw_init(pdev, clk_data);
if (r)
return dev_err_probe(&pdev->dev, r, "Could not register clock provider: %s\n",
pdev->name);
return r;
r = en7523_reset_register(pdev, soc_data);
if (r) {
of_clk_del_provider(node);
return dev_err_probe(&pdev->dev, r, "Could not register reset controller: %s\n",
pdev->name);
}
return 0;
return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
}
static const struct en_clk_soc_data en7523_data = {
@ -608,6 +721,7 @@ static const struct en_clk_soc_data en7523_data = {
.prepare = en7523_pci_prepare,
.unprepare = en7523_pci_unprepare,
},
.hw_init = en7523_clk_hw_init,
};
static const struct en_clk_soc_data en7581_data = {
@ -616,11 +730,6 @@ static const struct en_clk_soc_data en7581_data = {
.enable = en7581_pci_enable,
.disable = en7581_pci_disable,
},
.reset = {
.bank_ofs = en7581_rst_ofs,
.idx_map = en7581_rst_map,
.idx_map_nr = ARRAY_SIZE(en7581_rst_map),
},
.hw_init = en7581_clk_hw_init,
};

859
drivers/clk/clk-eyeq.c Normal file
View File

@ -0,0 +1,859 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* PLL clock driver for the Mobileye EyeQ5, EyeQ6L and EyeQ6H platforms.
*
* This controller handles:
* - Read-only PLLs, all derived from the same main crystal clock.
* - It also exposes divider clocks, those are children to PLLs.
* - Fixed factor clocks, children to PLLs.
*
* Parent clock is expected to be constant. This driver's registers live in a
* shared region called OLB. Some PLLs and fixed-factors are initialised early
* by of_clk_init(); if so, two clk providers are registered.
*
* We use eqc_ as prefix, as-in "EyeQ Clock", but way shorter.
*
* Copyright (C) 2024 Mobileye Vision Technologies Ltd.
*/
/*
* Set pr_fmt() for printing from eqc_early_init().
* It is called at of_clk_init() stage (read: really early).
*/
#define pr_fmt(fmt) "clk-eyeq: " fmt
#include <linux/array_size.h>
#include <linux/auxiliary_bus.h>
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/io-64-nonatomic-hi-lo.h>
#include <linux/io.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/overflow.h>
#include <linux/platform_device.h>
#include <linux/printk.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <dt-bindings/clock/mobileye,eyeq5-clk.h>
/* In frac mode, it enables fractional noise canceling DAC. Else, no function. */
#define PCSR0_DAC_EN BIT(0)
/* Fractional or integer mode */
#define PCSR0_DSM_EN BIT(1)
#define PCSR0_PLL_EN BIT(2)
/* All clocks output held at 0 */
#define PCSR0_FOUTPOSTDIV_EN BIT(3)
#define PCSR0_POST_DIV1 GENMASK(6, 4)
#define PCSR0_POST_DIV2 GENMASK(9, 7)
#define PCSR0_REF_DIV GENMASK(15, 10)
#define PCSR0_INTIN GENMASK(27, 16)
#define PCSR0_BYPASS BIT(28)
/* Bits 30..29 are reserved */
#define PCSR0_PLL_LOCKED BIT(31)
#define PCSR1_RESET BIT(0)
#define PCSR1_SSGC_DIV GENMASK(4, 1)
/* Spread amplitude (% = 0.1 * SPREAD[4:0]) */
#define PCSR1_SPREAD GENMASK(9, 5)
#define PCSR1_DIS_SSCG BIT(10)
/* Down-spread or center-spread */
#define PCSR1_DOWN_SPREAD BIT(11)
#define PCSR1_FRAC_IN GENMASK(31, 12)
struct eqc_pll {
unsigned int index;
const char *name;
unsigned int reg64;
};
/*
* Divider clock. Divider is 2*(v+1), with v the register value.
* Min divider is 2, max is 2*(2^width).
*/
struct eqc_div {
unsigned int index;
const char *name;
unsigned int parent;
unsigned int reg;
u8 shift;
u8 width;
};
struct eqc_fixed_factor {
unsigned int index;
const char *name;
unsigned int mult;
unsigned int div;
unsigned int parent;
};
struct eqc_match_data {
unsigned int pll_count;
const struct eqc_pll *plls;
unsigned int div_count;
const struct eqc_div *divs;
unsigned int fixed_factor_count;
const struct eqc_fixed_factor *fixed_factors;
const char *reset_auxdev_name;
const char *pinctrl_auxdev_name;
unsigned int early_clk_count;
};
struct eqc_early_match_data {
unsigned int early_pll_count;
const struct eqc_pll *early_plls;
unsigned int early_fixed_factor_count;
const struct eqc_fixed_factor *early_fixed_factors;
/*
* We want our of_xlate callback to EPROBE_DEFER instead of dev_err()
* and EINVAL. For that, we must know the total clock count.
*/
unsigned int late_clk_count;
};
/*
* Both factors (mult and div) must fit in 32 bits. When an operation overflows,
* this function throws away low bits so that factors still fit in 32 bits.
*
* Precision loss depends on amplitude of mult and div. Worst theorical
* loss is: (UINT_MAX+1) / UINT_MAX - 1 = 2.3e-10.
* This is 1Hz every 4.3GHz.
*/
static void eqc_pll_downshift_factors(unsigned long *mult, unsigned long *div)
{
unsigned long biggest;
unsigned int shift;
/* This function can be removed if mult/div switch to unsigned long. */
static_assert(sizeof_field(struct clk_fixed_factor, mult) == sizeof(unsigned int));
static_assert(sizeof_field(struct clk_fixed_factor, div) == sizeof(unsigned int));
/* No overflow, nothing to be done. */
if (*mult <= UINT_MAX && *div <= UINT_MAX)
return;
/*
* Compute the shift required to bring the biggest factor into unsigned
* int range. That is, shift its highest set bit to the unsigned int
* most significant bit.
*/
biggest = max(*mult, *div);
shift = __fls(biggest) - (BITS_PER_BYTE * sizeof(unsigned int)) + 1;
*mult >>= shift;
*div >>= shift;
}
static int eqc_pll_parse_registers(u32 r0, u32 r1, unsigned long *mult,
unsigned long *div, unsigned long *acc)
{
u32 spread;
if (r0 & PCSR0_BYPASS) {
*mult = 1;
*div = 1;
*acc = 0;
return 0;
}
if (!(r0 & PCSR0_PLL_LOCKED))
return -EINVAL;
*mult = FIELD_GET(PCSR0_INTIN, r0);
*div = FIELD_GET(PCSR0_REF_DIV, r0);
if (r0 & PCSR0_FOUTPOSTDIV_EN)
*div *= FIELD_GET(PCSR0_POST_DIV1, r0) * FIELD_GET(PCSR0_POST_DIV2, r0);
/* Fractional mode, in 2^20 (0x100000) parts. */
if (r0 & PCSR0_DSM_EN) {
*div *= (1ULL << 20);
*mult = *mult * (1ULL << 20) + FIELD_GET(PCSR1_FRAC_IN, r1);
}
if (!*mult || !*div)
return -EINVAL;
if (r1 & (PCSR1_RESET | PCSR1_DIS_SSCG)) {
*acc = 0;
return 0;
}
/*
* Spread spectrum.
*
* Spread is 1/1000 parts of frequency, accuracy is half of
* that. To get accuracy, convert to ppb (parts per billion).
*
* acc = spread * 1e6 / 2
* with acc in parts per billion and,
* spread in parts per thousand.
*/
spread = FIELD_GET(PCSR1_SPREAD, r1);
*acc = spread * 500000;
if (r1 & PCSR1_DOWN_SPREAD) {
/*
* Downspreading: the central frequency is half a
* spread lower.
*/
*mult *= 2000 - spread;
*div *= 2000;
/*
* Previous operation might overflow 32 bits. If it
* does, throw away the least amount of low bits.
*/
eqc_pll_downshift_factors(mult, div);
}
return 0;
}
static void eqc_probe_init_plls(struct device *dev, const struct eqc_match_data *data,
void __iomem *base, struct clk_hw_onecell_data *cells)
{
unsigned long mult, div, acc;
const struct eqc_pll *pll;
struct clk_hw *hw;
unsigned int i;
u32 r0, r1;
u64 val;
int ret;
for (i = 0; i < data->pll_count; i++) {
pll = &data->plls[i];
val = readq(base + pll->reg64);
r0 = val;
r1 = val >> 32;
ret = eqc_pll_parse_registers(r0, r1, &mult, &div, &acc);
if (ret) {
dev_warn(dev, "failed parsing state of %s\n", pll->name);
cells->hws[pll->index] = ERR_PTR(ret);
continue;
}
hw = clk_hw_register_fixed_factor_with_accuracy_fwname(dev,
dev->of_node, pll->name, "ref", 0, mult, div, acc);
cells->hws[pll->index] = hw;
if (IS_ERR(hw))
dev_warn(dev, "failed registering %s: %pe\n", pll->name, hw);
}
}
static void eqc_probe_init_divs(struct device *dev, const struct eqc_match_data *data,
void __iomem *base, struct clk_hw_onecell_data *cells)
{
struct clk_parent_data parent_data = { };
const struct eqc_div *div;
struct clk_hw *parent;
void __iomem *reg;
struct clk_hw *hw;
unsigned int i;
for (i = 0; i < data->div_count; i++) {
div = &data->divs[i];
reg = base + div->reg;
parent = cells->hws[div->parent];
if (IS_ERR(parent)) {
/* Parent is in early clk provider. */
parent_data.index = div->parent;
parent_data.hw = NULL;
} else {
/* Avoid clock lookup when we already have the hw reference. */
parent_data.index = 0;
parent_data.hw = parent;
}
hw = clk_hw_register_divider_table_parent_data(dev, div->name,
&parent_data, 0, reg, div->shift, div->width,
CLK_DIVIDER_EVEN_INTEGERS, NULL, NULL);
cells->hws[div->index] = hw;
if (IS_ERR(hw))
dev_warn(dev, "failed registering %s: %pe\n",
div->name, hw);
}
}
static void eqc_probe_init_fixed_factors(struct device *dev,
const struct eqc_match_data *data,
struct clk_hw_onecell_data *cells)
{
const struct eqc_fixed_factor *ff;
struct clk_hw *hw, *parent_hw;
unsigned int i;
for (i = 0; i < data->fixed_factor_count; i++) {
ff = &data->fixed_factors[i];
parent_hw = cells->hws[ff->parent];
if (IS_ERR(parent_hw)) {
/* Parent is in early clk provider. */
hw = clk_hw_register_fixed_factor_index(dev, ff->name,
ff->parent, 0, ff->mult, ff->div);
} else {
/* Avoid clock lookup when we already have the hw reference. */
hw = clk_hw_register_fixed_factor_parent_hw(dev, ff->name,
parent_hw, 0, ff->mult, ff->div);
}
cells->hws[ff->index] = hw;
if (IS_ERR(hw))
dev_warn(dev, "failed registering %s: %pe\n",
ff->name, hw);
}
}
static void eqc_auxdev_release(struct device *dev)
{
struct auxiliary_device *adev = to_auxiliary_dev(dev);
kfree(adev);
}
static int eqc_auxdev_create(struct device *dev, void __iomem *base,
const char *name, u32 id)
{
struct auxiliary_device *adev;
int ret;
adev = kzalloc(sizeof(*adev), GFP_KERNEL);
if (!adev)
return -ENOMEM;
adev->name = name;
adev->dev.parent = dev;
adev->dev.platform_data = (void __force *)base;
adev->dev.release = eqc_auxdev_release;
adev->id = id;
ret = auxiliary_device_init(adev);
if (ret)
return ret;
ret = auxiliary_device_add(adev);
if (ret)
auxiliary_device_uninit(adev);
return ret;
}
static int eqc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
const struct eqc_match_data *data;
struct clk_hw_onecell_data *cells;
unsigned int i, clk_count;
struct resource *res;
void __iomem *base;
int ret;
data = device_get_match_data(dev);
if (!data)
return 0; /* No clocks nor auxdevs, we are done. */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
base = ioremap(res->start, resource_size(res));
if (!base)
return -ENOMEM;
/* Init optional reset auxiliary device. */
if (data->reset_auxdev_name) {
ret = eqc_auxdev_create(dev, base, data->reset_auxdev_name, 0);
if (ret)
dev_warn(dev, "failed creating auxiliary device %s.%s: %d\n",
KBUILD_MODNAME, data->reset_auxdev_name, ret);
}
/* Init optional pinctrl auxiliary device. */
if (data->pinctrl_auxdev_name) {
ret = eqc_auxdev_create(dev, base, data->pinctrl_auxdev_name, 0);
if (ret)
dev_warn(dev, "failed creating auxiliary device %s.%s: %d\n",
KBUILD_MODNAME, data->pinctrl_auxdev_name, ret);
}
if (data->pll_count + data->div_count + data->fixed_factor_count == 0)
return 0; /* Zero clocks, we are done. */
clk_count = data->pll_count + data->div_count +
data->fixed_factor_count + data->early_clk_count;
cells = kzalloc(struct_size(cells, hws, clk_count), GFP_KERNEL);
if (!cells)
return -ENOMEM;
cells->num = clk_count;
/* Early PLLs are marked as errors: the early provider will get queried. */
for (i = 0; i < clk_count; i++)
cells->hws[i] = ERR_PTR(-EINVAL);
eqc_probe_init_plls(dev, data, base, cells);
eqc_probe_init_divs(dev, data, base, cells);
eqc_probe_init_fixed_factors(dev, data, cells);
return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, cells);
}
/* Required early for GIC timer (pll-cpu) and UARTs (pll-per). */
static const struct eqc_pll eqc_eyeq5_early_plls[] = {
{ .index = EQ5C_PLL_CPU, .name = "pll-cpu", .reg64 = 0x02C },
{ .index = EQ5C_PLL_PER, .name = "pll-per", .reg64 = 0x05C },
};
static const struct eqc_pll eqc_eyeq5_plls[] = {
{ .index = EQ5C_PLL_VMP, .name = "pll-vmp", .reg64 = 0x034 },
{ .index = EQ5C_PLL_PMA, .name = "pll-pma", .reg64 = 0x03C },
{ .index = EQ5C_PLL_VDI, .name = "pll-vdi", .reg64 = 0x044 },
{ .index = EQ5C_PLL_DDR0, .name = "pll-ddr0", .reg64 = 0x04C },
{ .index = EQ5C_PLL_PCI, .name = "pll-pci", .reg64 = 0x054 },
{ .index = EQ5C_PLL_PMAC, .name = "pll-pmac", .reg64 = 0x064 },
{ .index = EQ5C_PLL_MPC, .name = "pll-mpc", .reg64 = 0x06C },
{ .index = EQ5C_PLL_DDR1, .name = "pll-ddr1", .reg64 = 0x074 },
};
enum {
/*
* EQ5C_PLL_CPU children.
* EQ5C_PER_OCC_PCI is the last clock exposed in dt-bindings.
*/
EQ5C_CPU_OCC = EQ5C_PER_OCC_PCI + 1,
EQ5C_CPU_SI_CSS0,
EQ5C_CPU_CPC,
EQ5C_CPU_CM,
EQ5C_CPU_MEM,
EQ5C_CPU_OCC_ISRAM,
EQ5C_CPU_ISRAM,
EQ5C_CPU_OCC_DBU,
EQ5C_CPU_SI_DBU_TP,
/*
* EQ5C_PLL_VDI children.
*/
EQ5C_VDI_OCC_VDI,
EQ5C_VDI_VDI,
EQ5C_VDI_OCC_CAN_SER,
EQ5C_VDI_CAN_SER,
EQ5C_VDI_I2C_SER,
/*
* EQ5C_PLL_PER children.
*/
EQ5C_PER_PERIPH,
EQ5C_PER_CAN,
EQ5C_PER_TIMER,
EQ5C_PER_CCF,
EQ5C_PER_OCC_MJPEG,
EQ5C_PER_HSM,
EQ5C_PER_MJPEG,
EQ5C_PER_FCMU_A,
};
static const struct eqc_fixed_factor eqc_eyeq5_early_fixed_factors[] = {
/* EQ5C_PLL_CPU children */
{ EQ5C_CPU_OCC, "occ-cpu", 1, 1, EQ5C_PLL_CPU },
{ EQ5C_CPU_SI_CSS0, "si-css0", 1, 1, EQ5C_CPU_OCC },
{ EQ5C_CPU_CORE0, "core0", 1, 1, EQ5C_CPU_SI_CSS0 },
{ EQ5C_CPU_CORE1, "core1", 1, 1, EQ5C_CPU_SI_CSS0 },
{ EQ5C_CPU_CORE2, "core2", 1, 1, EQ5C_CPU_SI_CSS0 },
{ EQ5C_CPU_CORE3, "core3", 1, 1, EQ5C_CPU_SI_CSS0 },
/* EQ5C_PLL_PER children */
{ EQ5C_PER_OCC, "occ-periph", 1, 16, EQ5C_PLL_PER },
{ EQ5C_PER_UART, "uart", 1, 1, EQ5C_PER_OCC },
};
static const struct eqc_fixed_factor eqc_eyeq5_fixed_factors[] = {
/* EQ5C_PLL_CPU children */
{ EQ5C_CPU_CPC, "cpc", 1, 1, EQ5C_CPU_SI_CSS0 },
{ EQ5C_CPU_CM, "cm", 1, 1, EQ5C_CPU_SI_CSS0 },
{ EQ5C_CPU_MEM, "mem", 1, 1, EQ5C_CPU_SI_CSS0 },
{ EQ5C_CPU_OCC_ISRAM, "occ-isram", 1, 2, EQ5C_PLL_CPU },
{ EQ5C_CPU_ISRAM, "isram", 1, 1, EQ5C_CPU_OCC_ISRAM },
{ EQ5C_CPU_OCC_DBU, "occ-dbu", 1, 10, EQ5C_PLL_CPU },
{ EQ5C_CPU_SI_DBU_TP, "si-dbu-tp", 1, 1, EQ5C_CPU_OCC_DBU },
/* EQ5C_PLL_VDI children */
{ EQ5C_VDI_OCC_VDI, "occ-vdi", 1, 2, EQ5C_PLL_VDI },
{ EQ5C_VDI_VDI, "vdi", 1, 1, EQ5C_VDI_OCC_VDI },
{ EQ5C_VDI_OCC_CAN_SER, "occ-can-ser", 1, 16, EQ5C_PLL_VDI },
{ EQ5C_VDI_CAN_SER, "can-ser", 1, 1, EQ5C_VDI_OCC_CAN_SER },
{ EQ5C_VDI_I2C_SER, "i2c-ser", 1, 20, EQ5C_PLL_VDI },
/* EQ5C_PLL_PER children */
{ EQ5C_PER_PERIPH, "periph", 1, 1, EQ5C_PER_OCC },
{ EQ5C_PER_CAN, "can", 1, 1, EQ5C_PER_OCC },
{ EQ5C_PER_SPI, "spi", 1, 1, EQ5C_PER_OCC },
{ EQ5C_PER_I2C, "i2c", 1, 1, EQ5C_PER_OCC },
{ EQ5C_PER_TIMER, "timer", 1, 1, EQ5C_PER_OCC },
{ EQ5C_PER_GPIO, "gpio", 1, 1, EQ5C_PER_OCC },
{ EQ5C_PER_EMMC, "emmc-sys", 1, 10, EQ5C_PLL_PER },
{ EQ5C_PER_CCF, "ccf-ctrl", 1, 4, EQ5C_PLL_PER },
{ EQ5C_PER_OCC_MJPEG, "occ-mjpeg", 1, 2, EQ5C_PLL_PER },
{ EQ5C_PER_HSM, "hsm", 1, 1, EQ5C_PER_OCC_MJPEG },
{ EQ5C_PER_MJPEG, "mjpeg", 1, 1, EQ5C_PER_OCC_MJPEG },
{ EQ5C_PER_FCMU_A, "fcmu-a", 1, 20, EQ5C_PLL_PER },
{ EQ5C_PER_OCC_PCI, "occ-pci-sys", 1, 8, EQ5C_PLL_PER },
};
static const struct eqc_div eqc_eyeq5_divs[] = {
{
.index = EQ5C_DIV_OSPI,
.name = "div-ospi",
.parent = EQ5C_PLL_PER,
.reg = 0x11C,
.shift = 0,
.width = 4,
},
};
static const struct eqc_early_match_data eqc_eyeq5_early_match_data __initconst = {
.early_pll_count = ARRAY_SIZE(eqc_eyeq5_early_plls),
.early_plls = eqc_eyeq5_early_plls,
.early_fixed_factor_count = ARRAY_SIZE(eqc_eyeq5_early_fixed_factors),
.early_fixed_factors = eqc_eyeq5_early_fixed_factors,
.late_clk_count = ARRAY_SIZE(eqc_eyeq5_plls) + ARRAY_SIZE(eqc_eyeq5_divs) +
ARRAY_SIZE(eqc_eyeq5_fixed_factors),
};
static const struct eqc_match_data eqc_eyeq5_match_data = {
.pll_count = ARRAY_SIZE(eqc_eyeq5_plls),
.plls = eqc_eyeq5_plls,
.div_count = ARRAY_SIZE(eqc_eyeq5_divs),
.divs = eqc_eyeq5_divs,
.fixed_factor_count = ARRAY_SIZE(eqc_eyeq5_fixed_factors),
.fixed_factors = eqc_eyeq5_fixed_factors,
.reset_auxdev_name = "reset",
.pinctrl_auxdev_name = "pinctrl",
.early_clk_count = ARRAY_SIZE(eqc_eyeq5_early_plls) +
ARRAY_SIZE(eqc_eyeq5_early_fixed_factors),
};
static const struct eqc_pll eqc_eyeq6l_plls[] = {
{ .index = EQ6LC_PLL_DDR, .name = "pll-ddr", .reg64 = 0x02C },
{ .index = EQ6LC_PLL_CPU, .name = "pll-cpu", .reg64 = 0x034 }, /* also acc */
{ .index = EQ6LC_PLL_PER, .name = "pll-per", .reg64 = 0x03C },
{ .index = EQ6LC_PLL_VDI, .name = "pll-vdi", .reg64 = 0x044 },
};
static const struct eqc_match_data eqc_eyeq6l_match_data = {
.pll_count = ARRAY_SIZE(eqc_eyeq6l_plls),
.plls = eqc_eyeq6l_plls,
.reset_auxdev_name = "reset",
};
static const struct eqc_match_data eqc_eyeq6h_west_match_data = {
.reset_auxdev_name = "reset_west",
};
static const struct eqc_pll eqc_eyeq6h_east_plls[] = {
{ .index = 0, .name = "pll-east", .reg64 = 0x074 },
};
static const struct eqc_match_data eqc_eyeq6h_east_match_data = {
.pll_count = ARRAY_SIZE(eqc_eyeq6h_east_plls),
.plls = eqc_eyeq6h_east_plls,
.reset_auxdev_name = "reset_east",
};
static const struct eqc_pll eqc_eyeq6h_south_plls[] = {
{ .index = EQ6HC_SOUTH_PLL_VDI, .name = "pll-vdi", .reg64 = 0x000 },
{ .index = EQ6HC_SOUTH_PLL_PCIE, .name = "pll-pcie", .reg64 = 0x008 },
{ .index = EQ6HC_SOUTH_PLL_PER, .name = "pll-per", .reg64 = 0x010 },
{ .index = EQ6HC_SOUTH_PLL_ISP, .name = "pll-isp", .reg64 = 0x018 },
};
static const struct eqc_div eqc_eyeq6h_south_divs[] = {
{
.index = EQ6HC_SOUTH_DIV_EMMC,
.name = "div-emmc",
.parent = EQ6HC_SOUTH_PLL_PER,
.reg = 0x070,
.shift = 4,
.width = 4,
},
{
.index = EQ6HC_SOUTH_DIV_OSPI_REF,
.name = "div-ospi-ref",
.parent = EQ6HC_SOUTH_PLL_PER,
.reg = 0x090,
.shift = 4,
.width = 4,
},
{
.index = EQ6HC_SOUTH_DIV_OSPI_SYS,
.name = "div-ospi-sys",
.parent = EQ6HC_SOUTH_PLL_PER,
.reg = 0x090,
.shift = 8,
.width = 1,
},
{
.index = EQ6HC_SOUTH_DIV_TSU,
.name = "div-tsu",
.parent = EQ6HC_SOUTH_PLL_PCIE,
.reg = 0x098,
.shift = 4,
.width = 8,
},
};
static const struct eqc_match_data eqc_eyeq6h_south_match_data = {
.pll_count = ARRAY_SIZE(eqc_eyeq6h_south_plls),
.plls = eqc_eyeq6h_south_plls,
.div_count = ARRAY_SIZE(eqc_eyeq6h_south_divs),
.divs = eqc_eyeq6h_south_divs,
};
static const struct eqc_pll eqc_eyeq6h_ddr0_plls[] = {
{ .index = 0, .name = "pll-ddr0", .reg64 = 0x074 },
};
static const struct eqc_match_data eqc_eyeq6h_ddr0_match_data = {
.pll_count = ARRAY_SIZE(eqc_eyeq6h_ddr0_plls),
.plls = eqc_eyeq6h_ddr0_plls,
};
static const struct eqc_pll eqc_eyeq6h_ddr1_plls[] = {
{ .index = 0, .name = "pll-ddr1", .reg64 = 0x074 },
};
static const struct eqc_match_data eqc_eyeq6h_ddr1_match_data = {
.pll_count = ARRAY_SIZE(eqc_eyeq6h_ddr1_plls),
.plls = eqc_eyeq6h_ddr1_plls,
};
static const struct eqc_pll eqc_eyeq6h_acc_plls[] = {
{ .index = EQ6HC_ACC_PLL_XNN, .name = "pll-xnn", .reg64 = 0x040 },
{ .index = EQ6HC_ACC_PLL_VMP, .name = "pll-vmp", .reg64 = 0x050 },
{ .index = EQ6HC_ACC_PLL_PMA, .name = "pll-pma", .reg64 = 0x05C },
{ .index = EQ6HC_ACC_PLL_MPC, .name = "pll-mpc", .reg64 = 0x068 },
{ .index = EQ6HC_ACC_PLL_NOC, .name = "pll-noc", .reg64 = 0x070 },
};
static const struct eqc_match_data eqc_eyeq6h_acc_match_data = {
.pll_count = ARRAY_SIZE(eqc_eyeq6h_acc_plls),
.plls = eqc_eyeq6h_acc_plls,
.reset_auxdev_name = "reset_acc",
};
static const struct of_device_id eqc_match_table[] = {
{ .compatible = "mobileye,eyeq5-olb", .data = &eqc_eyeq5_match_data },
{ .compatible = "mobileye,eyeq6l-olb", .data = &eqc_eyeq6l_match_data },
{ .compatible = "mobileye,eyeq6h-west-olb", .data = &eqc_eyeq6h_west_match_data },
{ .compatible = "mobileye,eyeq6h-east-olb", .data = &eqc_eyeq6h_east_match_data },
{ .compatible = "mobileye,eyeq6h-south-olb", .data = &eqc_eyeq6h_south_match_data },
{ .compatible = "mobileye,eyeq6h-ddr0-olb", .data = &eqc_eyeq6h_ddr0_match_data },
{ .compatible = "mobileye,eyeq6h-ddr1-olb", .data = &eqc_eyeq6h_ddr1_match_data },
{ .compatible = "mobileye,eyeq6h-acc-olb", .data = &eqc_eyeq6h_acc_match_data },
{}
};
static struct platform_driver eqc_driver = {
.probe = eqc_probe,
.driver = {
.name = "clk-eyeq",
.of_match_table = eqc_match_table,
.suppress_bind_attrs = true,
},
};
builtin_platform_driver(eqc_driver);
/* Required early for GIC timer. */
static const struct eqc_pll eqc_eyeq6h_central_early_plls[] = {
{ .index = EQ6HC_CENTRAL_PLL_CPU, .name = "pll-cpu", .reg64 = 0x02C },
};
static const struct eqc_fixed_factor eqc_eyeq6h_central_early_fixed_factors[] = {
{ EQ6HC_CENTRAL_CPU_OCC, "occ-cpu", 1, 1, EQ6HC_CENTRAL_PLL_CPU },
};
static const struct eqc_early_match_data eqc_eyeq6h_central_early_match_data __initconst = {
.early_pll_count = ARRAY_SIZE(eqc_eyeq6h_central_early_plls),
.early_plls = eqc_eyeq6h_central_early_plls,
.early_fixed_factor_count = ARRAY_SIZE(eqc_eyeq6h_central_early_fixed_factors),
.early_fixed_factors = eqc_eyeq6h_central_early_fixed_factors,
};
/* Required early for UART. */
static const struct eqc_pll eqc_eyeq6h_west_early_plls[] = {
{ .index = EQ6HC_WEST_PLL_PER, .name = "pll-west", .reg64 = 0x074 },
};
static const struct eqc_fixed_factor eqc_eyeq6h_west_early_fixed_factors[] = {
{ EQ6HC_WEST_PER_OCC, "west-per-occ", 1, 10, EQ6HC_WEST_PLL_PER },
{ EQ6HC_WEST_PER_UART, "west-per-uart", 1, 1, EQ6HC_WEST_PER_OCC },
};
static const struct eqc_early_match_data eqc_eyeq6h_west_early_match_data __initconst = {
.early_pll_count = ARRAY_SIZE(eqc_eyeq6h_west_early_plls),
.early_plls = eqc_eyeq6h_west_early_plls,
.early_fixed_factor_count = ARRAY_SIZE(eqc_eyeq6h_west_early_fixed_factors),
.early_fixed_factors = eqc_eyeq6h_west_early_fixed_factors,
};
static void __init eqc_early_init(struct device_node *np,
const struct eqc_early_match_data *early_data)
{
struct clk_hw_onecell_data *cells;
unsigned int i, clk_count;
void __iomem *base;
int ret;
clk_count = early_data->early_pll_count + early_data->early_fixed_factor_count +
early_data->late_clk_count;
cells = kzalloc(struct_size(cells, hws, clk_count), GFP_KERNEL);
if (!cells) {
ret = -ENOMEM;
goto err;
}
cells->num = clk_count;
/*
* Mark all clocks as deferred; some are registered here, the rest at
* platform device probe.
*
* Once the platform device is probed, its provider will take priority
* when looking up clocks.
*/
for (i = 0; i < clk_count; i++)
cells->hws[i] = ERR_PTR(-EPROBE_DEFER);
/* Offsets (reg64) of early PLLs are relative to OLB block. */
base = of_iomap(np, 0);
if (!base) {
ret = -ENODEV;
goto err;
}
for (i = 0; i < early_data->early_pll_count; i++) {
const struct eqc_pll *pll = &early_data->early_plls[i];
unsigned long mult, div, acc;
struct clk_hw *hw;
u32 r0, r1;
u64 val;
val = readq(base + pll->reg64);
r0 = val;
r1 = val >> 32;
ret = eqc_pll_parse_registers(r0, r1, &mult, &div, &acc);
if (ret) {
pr_err("failed parsing state of %s\n", pll->name);
goto err;
}
hw = clk_hw_register_fixed_factor_with_accuracy_fwname(NULL,
np, pll->name, "ref", 0, mult, div, acc);
cells->hws[pll->index] = hw;
if (IS_ERR(hw)) {
pr_err("failed registering %s: %pe\n", pll->name, hw);
ret = PTR_ERR(hw);
goto err;
}
}
for (i = 0; i < early_data->early_fixed_factor_count; i++) {
const struct eqc_fixed_factor *ff = &early_data->early_fixed_factors[i];
struct clk_hw *parent_hw = cells->hws[ff->parent];
struct clk_hw *hw;
hw = clk_hw_register_fixed_factor_parent_hw(NULL, ff->name,
parent_hw, 0, ff->mult, ff->div);
cells->hws[ff->index] = hw;
if (IS_ERR(hw)) {
pr_err("failed registering %s: %pe\n", ff->name, hw);
ret = PTR_ERR(hw);
goto err;
}
}
ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, cells);
if (ret) {
pr_err("failed registering clk provider: %d\n", ret);
goto err;
}
return;
err:
/*
* We are doomed. The system will not be able to boot.
*
* Let's still try to be good citizens by freeing resources and print
* a last error message that might help debugging.
*/
pr_err("failed clk init: %d\n", ret);
if (cells) {
of_clk_del_provider(np);
for (i = 0; i < early_data->early_pll_count; i++) {
const struct eqc_pll *pll = &early_data->early_plls[i];
struct clk_hw *hw = cells->hws[pll->index];
if (!IS_ERR_OR_NULL(hw))
clk_hw_unregister_fixed_factor(hw);
}
kfree(cells);
}
}
static void __init eqc_eyeq5_early_init(struct device_node *np)
{
eqc_early_init(np, &eqc_eyeq5_early_match_data);
}
CLK_OF_DECLARE_DRIVER(eqc_eyeq5, "mobileye,eyeq5-olb", eqc_eyeq5_early_init);
static void __init eqc_eyeq6h_central_early_init(struct device_node *np)
{
eqc_early_init(np, &eqc_eyeq6h_central_early_match_data);
}
CLK_OF_DECLARE_DRIVER(eqc_eyeq6h_central, "mobileye,eyeq6h-central-olb",
eqc_eyeq6h_central_early_init);
static void __init eqc_eyeq6h_west_early_init(struct device_node *np)
{
eqc_early_init(np, &eqc_eyeq6h_west_early_match_data);
}
CLK_OF_DECLARE_DRIVER(eqc_eyeq6h_west, "mobileye,eyeq6h-west-olb",
eqc_eyeq6h_west_early_init);

View File

@ -241,6 +241,17 @@ struct clk_hw *clk_hw_register_fixed_factor_with_accuracy_fwname(struct device *
}
EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor_with_accuracy_fwname);
struct clk_hw *clk_hw_register_fixed_factor_index(struct device *dev,
const char *name, unsigned int index, unsigned long flags,
unsigned int mult, unsigned int div)
{
const struct clk_parent_data pdata = { .index = index };
return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, NULL, &pdata,
flags, mult, div, 0, 0, false);
}
EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor_index);
struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
unsigned int mult, unsigned int div)

View File

@ -17,13 +17,15 @@
#include <linux/device.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
/**
* DOC: basic gpio gated clock which can be enabled and disabled
* with gpio output
* Traits of this clock:
* prepare - clk_(un)prepare only ensures parent is (un)prepared
* enable - clk_enable and clk_disable are functional & control gpio
* prepare - clk_(un)prepare are functional and control a gpio that can sleep
* enable - clk_enable and clk_disable are functional & control
* non-sleeping gpio
* rate - inherits rate from parent. No clk_set_rate support
* parent - fixed parent. No clk_set_parent support
*/
@ -199,7 +201,6 @@ static int gpio_clk_driver_probe(struct platform_device *pdev)
struct gpio_desc *gpiod;
struct clk_hw *hw;
bool is_mux;
int ret;
is_mux = of_device_is_compatible(node, "gpio-mux-clock");
@ -211,17 +212,9 @@ static int gpio_clk_driver_probe(struct platform_device *pdev)
gpio_name = is_mux ? "select" : "enable";
gpiod = devm_gpiod_get(dev, gpio_name, GPIOD_OUT_LOW);
if (IS_ERR(gpiod)) {
ret = PTR_ERR(gpiod);
if (ret == -EPROBE_DEFER)
pr_debug("%pOFn: %s: GPIOs not yet available, retry later\n",
node, __func__);
else
pr_err("%pOFn: %s: Can't get '%s' named GPIO property\n",
node, __func__,
gpio_name);
return ret;
}
if (IS_ERR(gpiod))
return dev_err_probe(dev, PTR_ERR(gpiod),
"Can't get '%s' named GPIO property\n", gpio_name);
if (is_mux)
hw = clk_hw_register_gpio_mux(dev, gpiod);
@ -247,3 +240,187 @@ static struct platform_driver gpio_clk_driver = {
},
};
builtin_platform_driver(gpio_clk_driver);
/**
* DOC: gated fixed clock, controlled with a gpio output and a regulator
* Traits of this clock:
* prepare - clk_prepare and clk_unprepare are function & control regulator
* optionally a gpio that can sleep
* enable - clk_enable and clk_disable are functional & control gpio
* rate - rate is fixed and set on clock registration
* parent - fixed clock is a root clock and has no parent
*/
/**
* struct clk_gated_fixed - Gateable fixed rate clock
* @clk_gpio: instance of clk_gpio for gate-gpio
* @supply: supply regulator
* @rate: fixed rate
*/
struct clk_gated_fixed {
struct clk_gpio clk_gpio;
struct regulator *supply;
unsigned long rate;
};
#define to_clk_gated_fixed(_clk_gpio) container_of(_clk_gpio, struct clk_gated_fixed, clk_gpio)
static unsigned long clk_gated_fixed_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
return to_clk_gated_fixed(to_clk_gpio(hw))->rate;
}
static int clk_gated_fixed_prepare(struct clk_hw *hw)
{
struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw));
if (!clk->supply)
return 0;
return regulator_enable(clk->supply);
}
static void clk_gated_fixed_unprepare(struct clk_hw *hw)
{
struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw));
if (!clk->supply)
return;
regulator_disable(clk->supply);
}
static int clk_gated_fixed_is_prepared(struct clk_hw *hw)
{
struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw));
if (!clk->supply)
return true;
return regulator_is_enabled(clk->supply);
}
/*
* Fixed gated clock with non-sleeping gpio.
*
* Prepare operation turns on the supply regulator
* and the enable operation switches the enable-gpio.
*/
static const struct clk_ops clk_gated_fixed_ops = {
.prepare = clk_gated_fixed_prepare,
.unprepare = clk_gated_fixed_unprepare,
.is_prepared = clk_gated_fixed_is_prepared,
.enable = clk_gpio_gate_enable,
.disable = clk_gpio_gate_disable,
.is_enabled = clk_gpio_gate_is_enabled,
.recalc_rate = clk_gated_fixed_recalc_rate,
};
static int clk_sleeping_gated_fixed_prepare(struct clk_hw *hw)
{
int ret;
ret = clk_gated_fixed_prepare(hw);
if (ret)
return ret;
ret = clk_sleeping_gpio_gate_prepare(hw);
if (ret)
clk_gated_fixed_unprepare(hw);
return ret;
}
static void clk_sleeping_gated_fixed_unprepare(struct clk_hw *hw)
{
clk_gated_fixed_unprepare(hw);
clk_sleeping_gpio_gate_unprepare(hw);
}
/*
* Fixed gated clock with non-sleeping gpio.
*
* Enabling the supply regulator and switching the enable-gpio happens
* both in the prepare step.
* is_prepared only needs to check the gpio state, as toggling the
* gpio is the last step when preparing.
*/
static const struct clk_ops clk_sleeping_gated_fixed_ops = {
.prepare = clk_sleeping_gated_fixed_prepare,
.unprepare = clk_sleeping_gated_fixed_unprepare,
.is_prepared = clk_sleeping_gpio_gate_is_prepared,
.recalc_rate = clk_gated_fixed_recalc_rate,
};
static int clk_gated_fixed_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct clk_gated_fixed *clk;
const struct clk_ops *ops;
const char *clk_name;
u32 rate;
int ret;
clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL);
if (!clk)
return -ENOMEM;
ret = device_property_read_u32(dev, "clock-frequency", &rate);
if (ret)
return dev_err_probe(dev, ret, "Failed to get clock-frequency\n");
clk->rate = rate;
ret = device_property_read_string(dev, "clock-output-names", &clk_name);
if (ret)
clk_name = fwnode_get_name(dev->fwnode);
clk->supply = devm_regulator_get_optional(dev, "vdd");
if (IS_ERR(clk->supply)) {
if (PTR_ERR(clk->supply) != -ENODEV)
return dev_err_probe(dev, PTR_ERR(clk->supply),
"Failed to get regulator\n");
clk->supply = NULL;
}
clk->clk_gpio.gpiod = devm_gpiod_get_optional(dev, "enable",
GPIOD_OUT_LOW);
if (IS_ERR(clk->clk_gpio.gpiod))
return dev_err_probe(dev, PTR_ERR(clk->clk_gpio.gpiod),
"Failed to get gpio\n");
if (gpiod_cansleep(clk->clk_gpio.gpiod))
ops = &clk_sleeping_gated_fixed_ops;
else
ops = &clk_gated_fixed_ops;
clk->clk_gpio.hw.init = CLK_HW_INIT_NO_PARENT(clk_name, ops, 0);
/* register the clock */
ret = devm_clk_hw_register(dev, &clk->clk_gpio.hw);
if (ret)
return dev_err_probe(dev, ret,
"Failed to register clock\n");
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
&clk->clk_gpio.hw);
if (ret)
return dev_err_probe(dev, ret,
"Failed to register clock provider\n");
return 0;
}
static const struct of_device_id gated_fixed_clk_match_table[] = {
{ .compatible = "gated-fixed-clock" },
{ /* sentinel */ }
};
static struct platform_driver gated_fixed_clk_driver = {
.probe = clk_gated_fixed_probe,
.driver = {
.name = "gated-fixed-clk",
.of_match_table = gated_fixed_clk_match_table,
},
};
builtin_platform_driver(gated_fixed_clk_driver);

View File

@ -24,13 +24,20 @@
#define DIV_MAX 255
static const char *clk_names[N_CLOCKS] = {
static const char * const lan966x_clk_names[] = {
"qspi0", "qspi1", "qspi2", "sdmmc0",
"pi", "mcan0", "mcan1", "flexcom0",
"flexcom1", "flexcom2", "flexcom3",
"flexcom4", "timer1", "usb_refclk",
};
static const char * const lan969x_clk_names[] = {
"qspi0", "qspi2", "sdmmc0", "sdmmc1",
"mcan0", "mcan1", "flexcom0",
"flexcom1", "flexcom2", "flexcom3",
"timer1", "usb_refclk",
};
struct lan966x_gck {
struct clk_hw hw;
void __iomem *reg;
@ -53,7 +60,7 @@ struct clk_gate_soc_desc {
int bit_idx;
};
static const struct clk_gate_soc_desc clk_gate_desc[] = {
static const struct clk_gate_soc_desc lan966x_clk_gate_desc[] = {
{ "uhphs", 11 },
{ "udphs", 10 },
{ "mcramc", 9 },
@ -61,6 +68,37 @@ static const struct clk_gate_soc_desc clk_gate_desc[] = {
{ }
};
static const struct clk_gate_soc_desc lan969x_clk_gate_desc[] = {
{ "usb_drd", 10 },
{ "mcramc", 9 },
{ "hmatrix", 8 },
{ }
};
struct lan966x_match_data {
char *name;
const char * const *clk_name;
const struct clk_gate_soc_desc *clk_gate_desc;
u8 num_generic_clks;
u8 num_total_clks;
};
static struct lan966x_match_data lan966x_desc = {
.name = "lan966x",
.clk_name = lan966x_clk_names,
.clk_gate_desc = lan966x_clk_gate_desc,
.num_total_clks = 18,
.num_generic_clks = 14,
};
static struct lan966x_match_data lan969x_desc = {
.name = "lan969x",
.clk_name = lan969x_clk_names,
.clk_gate_desc = lan969x_clk_gate_desc,
.num_total_clks = 15,
.num_generic_clks = 12,
};
static DEFINE_SPINLOCK(clk_gate_lock);
static void __iomem *base;
@ -186,24 +224,26 @@ static struct clk_hw *lan966x_gck_clk_register(struct device *dev, int i)
};
static int lan966x_gate_clk_register(struct device *dev,
const struct lan966x_match_data *data,
struct clk_hw_onecell_data *hw_data,
void __iomem *gate_base)
{
int i;
for (int i = data->num_generic_clks; i < data->num_total_clks; ++i) {
int idx = i - data->num_generic_clks;
const struct clk_gate_soc_desc *desc;
for (i = GCK_GATE_UHPHS; i < N_CLOCKS; ++i) {
int idx = i - GCK_GATE_UHPHS;
desc = &data->clk_gate_desc[idx];
hw_data->hws[i] =
devm_clk_hw_register_gate(dev, clk_gate_desc[idx].name,
"lan966x", 0, gate_base,
clk_gate_desc[idx].bit_idx,
devm_clk_hw_register_gate(dev, desc->name,
data->name, 0, gate_base,
desc->bit_idx,
0, &clk_gate_lock);
if (IS_ERR(hw_data->hws[i]))
return dev_err_probe(dev, PTR_ERR(hw_data->hws[i]),
"failed to register %s clock\n",
clk_gate_desc[idx].name);
desc->name);
}
return 0;
@ -211,13 +251,18 @@ static int lan966x_gate_clk_register(struct device *dev,
static int lan966x_clk_probe(struct platform_device *pdev)
{
const struct lan966x_match_data *data;
struct clk_hw_onecell_data *hw_data;
struct device *dev = &pdev->dev;
void __iomem *gate_base;
struct resource *res;
int i, ret;
hw_data = devm_kzalloc(dev, struct_size(hw_data, hws, N_CLOCKS),
data = device_get_match_data(dev);
if (!data)
return -EINVAL;
hw_data = devm_kzalloc(dev, struct_size(hw_data, hws, data->num_total_clks),
GFP_KERNEL);
if (!hw_data)
return -ENOMEM;
@ -228,10 +273,10 @@ static int lan966x_clk_probe(struct platform_device *pdev)
init.ops = &lan966x_gck_ops;
hw_data->num = GCK_GATE_UHPHS;
hw_data->num = data->num_generic_clks;
for (i = 0; i < GCK_GATE_UHPHS; i++) {
init.name = clk_names[i];
for (i = 0; i < data->num_generic_clks; i++) {
init.name = data->clk_name[i];
hw_data->hws[i] = lan966x_gck_clk_register(dev, i);
if (IS_ERR(hw_data->hws[i])) {
dev_err(dev, "failed to register %s clock\n",
@ -246,9 +291,9 @@ static int lan966x_clk_probe(struct platform_device *pdev)
if (IS_ERR(gate_base))
return PTR_ERR(gate_base);
hw_data->num = N_CLOCKS;
hw_data->num = data->num_total_clks;
ret = lan966x_gate_clk_register(dev, hw_data, gate_base);
ret = lan966x_gate_clk_register(dev, data, hw_data, gate_base);
if (ret)
return ret;
}
@ -257,7 +302,8 @@ static int lan966x_clk_probe(struct platform_device *pdev)
}
static const struct of_device_id lan966x_clk_dt_ids[] = {
{ .compatible = "microchip,lan966x-gck", },
{ .compatible = "microchip,lan966x-gck", .data = &lan966x_desc },
{ .compatible = "microchip,lan9691-gck", .data = &lan969x_desc },
{ }
};
MODULE_DEVICE_TABLE(of, lan966x_clk_dt_ids);

View File

@ -29,8 +29,10 @@ enum loongson2_clk_type {
struct loongson2_clk_provider {
void __iomem *base;
struct device *dev;
struct clk_hw_onecell_data clk_data;
spinlock_t clk_lock; /* protect access to DIV registers */
/* Must be last --ends in a flexible-array member. */
struct clk_hw_onecell_data clk_data;
};
struct loongson2_clk_data {
@ -304,7 +306,7 @@ static int loongson2_clk_probe(struct platform_device *pdev)
return PTR_ERR(clp->base);
spin_lock_init(&clp->clk_lock);
clp->clk_data.num = clks_num + 1;
clp->clk_data.num = clks_num;
clp->dev = dev;
for (i = 0; i < clks_num; i++) {

430
drivers/clk/clk-npcm8xx.c Normal file
View File

@ -0,0 +1,430 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Nuvoton NPCM8xx Clock Generator
* All the clocks are initialized by the bootloader, so this driver allows only
* reading of current settings directly from the hardware.
*
* Copyright (C) 2020 Nuvoton Technologies
* Author: Tomer Maimon <tomer.maimon@nuvoton.com>
*/
#define pr_fmt(fmt) "npcm8xx_clk: " fmt
#include <linux/auxiliary_bus.h>
#include <linux/bitfield.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <dt-bindings/clock/nuvoton,npcm845-clk.h>
#include <soc/nuvoton/clock-npcm8xx.h>
/* npcm8xx clock registers*/
#define NPCM8XX_CLKSEL 0x04
#define NPCM8XX_CLKDIV1 0x08
#define NPCM8XX_CLKDIV2 0x2C
#define NPCM8XX_CLKDIV3 0x58
#define NPCM8XX_CLKDIV4 0x7C
#define NPCM8XX_PLLCON0 0x0C
#define NPCM8XX_PLLCON1 0x10
#define NPCM8XX_PLLCON2 0x54
#define NPCM8XX_PLLCONG 0x60
#define NPCM8XX_THRTL_CNT 0xC0
#define PLLCON_LOKI BIT(31)
#define PLLCON_LOKS BIT(30)
#define PLLCON_FBDV GENMASK(27, 16)
#define PLLCON_OTDV2 GENMASK(15, 13)
#define PLLCON_PWDEN BIT(12)
#define PLLCON_OTDV1 GENMASK(10, 8)
#define PLLCON_INDV GENMASK(5, 0)
static void __iomem *clk_base;
struct npcm8xx_clk_pll {
void __iomem *pllcon;
unsigned int id;
const char *name;
unsigned long flags;
struct clk_hw hw;
};
#define to_npcm8xx_clk_pll(_hw) container_of(_hw, struct npcm8xx_clk_pll, hw)
struct npcm8xx_clk_pll_data {
const char *name;
struct clk_parent_data parent;
unsigned int reg;
unsigned long flags;
struct clk_hw hw;
};
struct npcm8xx_clk_div_data {
u32 reg;
u8 shift;
u8 width;
const char *name;
const struct clk_hw *parent_hw;
unsigned long clk_divider_flags;
unsigned long flags;
int onecell_idx;
struct clk_hw hw;
};
struct npcm8xx_clk_mux_data {
u8 shift;
u32 mask;
const u32 *table;
const char *name;
const struct clk_parent_data *parent_data;
u8 num_parents;
unsigned long flags;
struct clk_hw hw;
};
static struct clk_hw hw_pll1_div2, hw_pll2_div2, hw_gfx_div2, hw_pre_clk;
static struct npcm8xx_clk_pll_data npcm8xx_pll_clks[] = {
{ "pll0", { .index = 0 }, NPCM8XX_PLLCON0, 0 },
{ "pll1", { .index = 0 }, NPCM8XX_PLLCON1, 0 },
{ "pll2", { .index = 0 }, NPCM8XX_PLLCON2, 0 },
{ "pll_gfx", { .index = 0 }, NPCM8XX_PLLCONG, 0 },
};
static const u32 cpuck_mux_table[] = { 0, 1, 2, 7 };
static const struct clk_parent_data cpuck_mux_parents[] = {
{ .hw = &npcm8xx_pll_clks[0].hw },
{ .hw = &npcm8xx_pll_clks[1].hw },
{ .index = 0 },
{ .hw = &npcm8xx_pll_clks[2].hw }
};
static const u32 pixcksel_mux_table[] = { 0, 2 };
static const struct clk_parent_data pixcksel_mux_parents[] = {
{ .hw = &npcm8xx_pll_clks[3].hw },
{ .index = 0 }
};
static const u32 default_mux_table[] = { 0, 1, 2, 3 };
static const struct clk_parent_data default_mux_parents[] = {
{ .hw = &npcm8xx_pll_clks[0].hw },
{ .hw = &npcm8xx_pll_clks[1].hw },
{ .index = 0 },
{ .hw = &hw_pll2_div2 }
};
static const u32 sucksel_mux_table[] = { 2, 3 };
static const struct clk_parent_data sucksel_mux_parents[] = {
{ .index = 0 },
{ .hw = &hw_pll2_div2 }
};
static const u32 mccksel_mux_table[] = { 0, 2 };
static const struct clk_parent_data mccksel_mux_parents[] = {
{ .hw = &hw_pll1_div2 },
{ .index = 0 }
};
static const u32 clkoutsel_mux_table[] = { 0, 1, 2, 3, 4 };
static const struct clk_parent_data clkoutsel_mux_parents[] = {
{ .hw = &npcm8xx_pll_clks[0].hw },
{ .hw = &npcm8xx_pll_clks[1].hw },
{ .index = 0 },
{ .hw = &hw_gfx_div2 },
{ .hw = &hw_pll2_div2 }
};
static const u32 gfxmsel_mux_table[] = { 2, 3 };
static const struct clk_parent_data gfxmsel_mux_parents[] = {
{ .index = 0 },
{ .hw = &npcm8xx_pll_clks[2].hw }
};
static const u32 dvcssel_mux_table[] = { 2, 3 };
static const struct clk_parent_data dvcssel_mux_parents[] = {
{ .index = 0 },
{ .hw = &npcm8xx_pll_clks[2].hw }
};
static const u32 default3_mux_table[] = { 0, 1, 2 };
static const struct clk_parent_data default3_mux_parents[] = {
{ .hw = &npcm8xx_pll_clks[0].hw },
{ .hw = &npcm8xx_pll_clks[1].hw },
{ .index = 0 }
};
static struct npcm8xx_clk_mux_data npcm8xx_muxes[] = {
{ 0, 3, cpuck_mux_table, "cpu_mux", cpuck_mux_parents,
ARRAY_SIZE(cpuck_mux_parents), CLK_IS_CRITICAL },
{ 4, 2, pixcksel_mux_table, "gfx_pixel_mux", pixcksel_mux_parents,
ARRAY_SIZE(pixcksel_mux_parents), 0 },
{ 6, 2, default_mux_table, "sd_mux", default_mux_parents,
ARRAY_SIZE(default_mux_parents), 0 },
{ 8, 2, default_mux_table, "uart_mux", default_mux_parents,
ARRAY_SIZE(default_mux_parents), 0 },
{ 10, 2, sucksel_mux_table, "serial_usb_mux", sucksel_mux_parents,
ARRAY_SIZE(sucksel_mux_parents), 0 },
{ 12, 2, mccksel_mux_table, "mc_mux", mccksel_mux_parents,
ARRAY_SIZE(mccksel_mux_parents), 0 },
{ 14, 2, default_mux_table, "adc_mux", default_mux_parents,
ARRAY_SIZE(default_mux_parents), 0 },
{ 16, 2, default_mux_table, "gfx_mux", default_mux_parents,
ARRAY_SIZE(default_mux_parents), 0 },
{ 18, 3, clkoutsel_mux_table, "clkout_mux", clkoutsel_mux_parents,
ARRAY_SIZE(clkoutsel_mux_parents), 0 },
{ 21, 2, gfxmsel_mux_table, "gfxm_mux", gfxmsel_mux_parents,
ARRAY_SIZE(gfxmsel_mux_parents), 0 },
{ 23, 2, dvcssel_mux_table, "dvc_mux", dvcssel_mux_parents,
ARRAY_SIZE(dvcssel_mux_parents), 0 },
{ 25, 2, default3_mux_table, "rg_mux", default3_mux_parents,
ARRAY_SIZE(default3_mux_parents), 0 },
{ 27, 2, default3_mux_table, "rcp_mux", default3_mux_parents,
ARRAY_SIZE(default3_mux_parents), 0 },
};
/* configurable pre dividers: */
static struct npcm8xx_clk_div_data npcm8xx_pre_divs[] = {
{ NPCM8XX_CLKDIV1, 21, 5, "pre_adc", &npcm8xx_muxes[6].hw, CLK_DIVIDER_READ_ONLY, 0, -1 },
{ NPCM8XX_CLKDIV1, 26, 2, "ahb", &hw_pre_clk, CLK_DIVIDER_READ_ONLY, CLK_IS_CRITICAL, NPCM8XX_CLK_AHB },
};
/* configurable dividers: */
static struct npcm8xx_clk_div_data npcm8xx_divs[] = {
{ NPCM8XX_CLKDIV1, 28, 3, "adc", &npcm8xx_pre_divs[0].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_ADC },
{ NPCM8XX_CLKDIV1, 16, 5, "uart", &npcm8xx_muxes[3].hw, 0, 0, NPCM8XX_CLK_UART },
{ NPCM8XX_CLKDIV1, 11, 5, "mmc", &npcm8xx_muxes[2].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_MMC },
{ NPCM8XX_CLKDIV1, 6, 5, "spi3", &npcm8xx_pre_divs[1].hw, 0, 0, NPCM8XX_CLK_SPI3 },
{ NPCM8XX_CLKDIV1, 2, 4, "pci", &npcm8xx_muxes[7].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_PCI },
{ NPCM8XX_CLKDIV2, 30, 2, "apb4", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB4 },
{ NPCM8XX_CLKDIV2, 28, 2, "apb3", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB3 },
{ NPCM8XX_CLKDIV2, 26, 2, "apb2", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB2 },
{ NPCM8XX_CLKDIV2, 24, 2, "apb1", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB1 },
{ NPCM8XX_CLKDIV2, 22, 2, "apb5", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB5 },
{ NPCM8XX_CLKDIV2, 16, 5, "clkout", &npcm8xx_muxes[8].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_CLKOUT },
{ NPCM8XX_CLKDIV2, 13, 3, "gfx", &npcm8xx_muxes[7].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_GFX },
{ NPCM8XX_CLKDIV2, 8, 5, "usb_bridge", &npcm8xx_muxes[4].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SU },
{ NPCM8XX_CLKDIV2, 4, 4, "usb_host", &npcm8xx_muxes[4].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SU48 },
{ NPCM8XX_CLKDIV2, 0, 4, "sdhc", &npcm8xx_muxes[2].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SDHC },
{ NPCM8XX_CLKDIV3, 16, 8, "spi1", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SPI1 },
{ NPCM8XX_CLKDIV3, 11, 5, "uart2", &npcm8xx_muxes[3].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_UART2 },
{ NPCM8XX_CLKDIV3, 6, 5, "spi0", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SPI0 },
{ NPCM8XX_CLKDIV3, 1, 5, "spix", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SPIX },
{ NPCM8XX_CLKDIV4, 28, 4, "rg", &npcm8xx_muxes[11].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_RG },
{ NPCM8XX_CLKDIV4, 12, 4, "rcp", &npcm8xx_muxes[12].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_RCP },
{ NPCM8XX_THRTL_CNT, 0, 2, "th", &npcm8xx_muxes[0].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_TH },
};
static unsigned long npcm8xx_clk_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct npcm8xx_clk_pll *pll = to_npcm8xx_clk_pll(hw);
unsigned long fbdv, indv, otdv1, otdv2;
unsigned int val;
u64 ret;
if (parent_rate == 0) {
pr_debug("%s: parent rate is zero\n", __func__);
return 0;
}
val = readl_relaxed(pll->pllcon);
indv = FIELD_GET(PLLCON_INDV, val);
fbdv = FIELD_GET(PLLCON_FBDV, val);
otdv1 = FIELD_GET(PLLCON_OTDV1, val);
otdv2 = FIELD_GET(PLLCON_OTDV2, val);
ret = (u64)parent_rate * fbdv;
do_div(ret, indv * otdv1 * otdv2);
return ret;
}
static const struct clk_ops npcm8xx_clk_pll_ops = {
.recalc_rate = npcm8xx_clk_pll_recalc_rate,
};
static struct clk_hw *
npcm8xx_clk_register_pll(struct device *dev, void __iomem *pllcon,
const char *name, const struct clk_parent_data *parent,
unsigned long flags)
{
struct npcm8xx_clk_pll *pll;
struct clk_init_data init = {};
int ret;
pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
if (!pll)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &npcm8xx_clk_pll_ops;
init.parent_data = parent;
init.num_parents = 1;
init.flags = flags;
pll->pllcon = pllcon;
pll->hw.init = &init;
ret = devm_clk_hw_register(dev, &pll->hw);
if (ret)
return ERR_PTR(ret);
return &pll->hw;
}
static DEFINE_SPINLOCK(npcm8xx_clk_lock);
static int npcm8xx_clk_probe(struct auxiliary_device *adev,
const struct auxiliary_device_id *id)
{
struct npcm_clock_adev *rdev = to_npcm_clock_adev(adev);
struct clk_hw_onecell_data *npcm8xx_clk_data;
struct device *dev = &adev->dev;
struct clk_hw *hw;
unsigned int i;
npcm8xx_clk_data = devm_kzalloc(dev, struct_size(npcm8xx_clk_data, hws,
NPCM8XX_NUM_CLOCKS),
GFP_KERNEL);
if (!npcm8xx_clk_data)
return -ENOMEM;
clk_base = rdev->base;
npcm8xx_clk_data->num = NPCM8XX_NUM_CLOCKS;
for (i = 0; i < NPCM8XX_NUM_CLOCKS; i++)
npcm8xx_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER);
/* Register plls */
for (i = 0; i < ARRAY_SIZE(npcm8xx_pll_clks); i++) {
struct npcm8xx_clk_pll_data *pll_clk = &npcm8xx_pll_clks[i];
hw = npcm8xx_clk_register_pll(dev, clk_base + pll_clk->reg,
pll_clk->name, &pll_clk->parent,
pll_clk->flags);
if (IS_ERR(hw))
return dev_err_probe(dev, PTR_ERR(hw), "Can't register pll\n");
pll_clk->hw = *hw;
}
/* Register fixed dividers */
hw = devm_clk_hw_register_fixed_factor(dev, "pll1_div2", "pll1", 0, 1, 2);
if (IS_ERR(hw))
return dev_err_probe(dev, PTR_ERR(hw), "Can't register fixed div\n");
hw_pll1_div2 = *hw;
hw = devm_clk_hw_register_fixed_factor(dev, "pll2_div2", "pll2", 0, 1, 2);
if (IS_ERR(hw))
return dev_err_probe(dev, PTR_ERR(hw), "Can't register pll2 div2\n");
hw_pll2_div2 = *hw;
hw = devm_clk_hw_register_fixed_factor(dev, "pll_gfx_div2", "pll_gfx", 0, 1, 2);
if (IS_ERR(hw))
return dev_err_probe(dev, PTR_ERR(hw), "Can't register gfx div2\n");
hw_gfx_div2 = *hw;
/* Register muxes */
for (i = 0; i < ARRAY_SIZE(npcm8xx_muxes); i++) {
struct npcm8xx_clk_mux_data *mux_data = &npcm8xx_muxes[i];
hw = devm_clk_hw_register_mux_parent_data_table(dev,
mux_data->name,
mux_data->parent_data,
mux_data->num_parents,
mux_data->flags,
clk_base + NPCM8XX_CLKSEL,
mux_data->shift,
mux_data->mask,
0,
mux_data->table,
&npcm8xx_clk_lock);
if (IS_ERR(hw))
return dev_err_probe(dev, PTR_ERR(hw), "Can't register mux\n");
mux_data->hw = *hw;
}
hw = devm_clk_hw_register_fixed_factor(dev, "pre_clk", "cpu_mux", 0, 1, 2);
if (IS_ERR(hw))
return dev_err_probe(dev, PTR_ERR(hw), "Can't register pre clk div2\n");
hw_pre_clk = *hw;
hw = devm_clk_hw_register_fixed_factor(dev, "axi", "th", 0, 1, 2);
if (IS_ERR(hw))
return dev_err_probe(dev, PTR_ERR(hw), "Can't register axi div2\n");
npcm8xx_clk_data->hws[NPCM8XX_CLK_AXI] = hw;
hw = devm_clk_hw_register_fixed_factor(dev, "atb", "axi", 0, 1, 2);
if (IS_ERR(hw))
return dev_err_probe(dev, PTR_ERR(hw), "Can't register atb div2\n");
npcm8xx_clk_data->hws[NPCM8XX_CLK_ATB] = hw;
/* Register pre dividers */
for (i = 0; i < ARRAY_SIZE(npcm8xx_pre_divs); i++) {
struct npcm8xx_clk_div_data *div_data = &npcm8xx_pre_divs[i];
hw = devm_clk_hw_register_divider_parent_hw(dev, div_data->name,
div_data->parent_hw,
div_data->flags,
clk_base + div_data->reg,
div_data->shift,
div_data->width,
div_data->clk_divider_flags,
&npcm8xx_clk_lock);
if (IS_ERR(hw))
return dev_err_probe(dev, PTR_ERR(hw), "Can't register pre div\n");
div_data->hw = *hw;
if (div_data->onecell_idx >= 0)
npcm8xx_clk_data->hws[div_data->onecell_idx] = hw;
}
/* Register dividers */
for (i = 0; i < ARRAY_SIZE(npcm8xx_divs); i++) {
struct npcm8xx_clk_div_data *div_data = &npcm8xx_divs[i];
hw = devm_clk_hw_register_divider_parent_hw(dev, div_data->name,
div_data->parent_hw,
div_data->flags,
clk_base + div_data->reg,
div_data->shift,
div_data->width,
div_data->clk_divider_flags,
&npcm8xx_clk_lock);
if (IS_ERR(hw))
return dev_err_probe(dev, PTR_ERR(hw), "Can't register div\n");
if (div_data->onecell_idx >= 0)
npcm8xx_clk_data->hws[div_data->onecell_idx] = hw;
}
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
npcm8xx_clk_data);
}
static const struct auxiliary_device_id npcm8xx_clock_ids[] = {
{
.name = "reset_npcm.clk-npcm8xx",
},
{ }
};
MODULE_DEVICE_TABLE(auxiliary, npcm8xx_clock_ids);
static struct auxiliary_driver npcm8xx_clock_driver = {
.probe = npcm8xx_clk_probe,
.id_table = npcm8xx_clock_ids,
};
module_auxiliary_driver(npcm8xx_clock_driver);
MODULE_DESCRIPTION("Clock driver for Nuvoton NPCM8XX BMC SoC");
MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
MODULE_LICENSE("GPL v2");

View File

@ -9,6 +9,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <dt-bindings/clock/fsl,qoriq-clockgen.h>
#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
@ -1065,11 +1066,8 @@ static void __init _clockgen_init(struct device_node *np, bool legacy);
static void __init legacy_init_clockgen(struct device_node *np)
{
if (!clockgen.node) {
struct device_node *parent_np;
parent_np = of_get_parent(np);
struct device_node *parent_np __free(device_node) = of_get_parent(np);
_clockgen_init(parent_np, true);
of_node_put(parent_np);
}
}

View File

@ -371,7 +371,7 @@ static int si514_probe(struct i2c_client *client)
}
static const struct i2c_device_id si514_id[] = {
{ "si514", 0 },
{ "si514" },
{ }
};
MODULE_DEVICE_TABLE(i2c, si514_id);

View File

@ -11,13 +11,29 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#define VREG_STATE 2
#define VREG_STATE 2
#define VREG_GRP 0
#define TWL6030_CFG_STATE_OFF 0x00
#define TWL6030_CFG_STATE_ON 0x01
#define TWL6030_CFG_STATE_MASK 0x03
#define TWL6030_CFG_STATE_GRP_SHIFT 5
#define TWL6030_CFG_STATE_APP_SHIFT 2
#define TWL6030_CFG_STATE_APP_MASK (0x03 << TWL6030_CFG_STATE_APP_SHIFT)
#define TWL6030_CFG_STATE_APP(v) (((v) & TWL6030_CFG_STATE_APP_MASK) >>\
TWL6030_CFG_STATE_APP_SHIFT)
#define P1_GRP BIT(0) /* processor power group */
#define P2_GRP BIT(1)
#define P3_GRP BIT(2)
#define ALL_GRP (P1_GRP | P2_GRP | P3_GRP)
enum twl_type {
TWL_TYPE_6030,
TWL_TYPE_6032,
};
struct twl_clock_info {
struct device *dev;
enum twl_type type;
u8 base;
struct clk_hw hw;
};
@ -56,14 +72,21 @@ static unsigned long twl_clks_recalc_rate(struct clk_hw *hw,
static int twl6032_clks_prepare(struct clk_hw *hw)
{
struct twl_clock_info *cinfo = to_twl_clks_info(hw);
int ret;
ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
TWL6030_CFG_STATE_ON);
if (ret < 0)
dev_err(cinfo->dev, "clk prepare failed\n");
if (cinfo->type == TWL_TYPE_6030) {
int grp;
return ret;
grp = twlclk_read(cinfo, TWL_MODULE_PM_RECEIVER, VREG_GRP);
if (grp < 0)
return grp;
return twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
grp << TWL6030_CFG_STATE_GRP_SHIFT |
TWL6030_CFG_STATE_ON);
}
return twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
TWL6030_CFG_STATE_ON);
}
static void twl6032_clks_unprepare(struct clk_hw *hw)
@ -71,32 +94,21 @@ static void twl6032_clks_unprepare(struct clk_hw *hw)
struct twl_clock_info *cinfo = to_twl_clks_info(hw);
int ret;
ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
TWL6030_CFG_STATE_OFF);
if (cinfo->type == TWL_TYPE_6030)
ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
ALL_GRP << TWL6030_CFG_STATE_GRP_SHIFT |
TWL6030_CFG_STATE_OFF);
else
ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
TWL6030_CFG_STATE_OFF);
if (ret < 0)
dev_err(cinfo->dev, "clk unprepare failed\n");
}
static int twl6032_clks_is_prepared(struct clk_hw *hw)
{
struct twl_clock_info *cinfo = to_twl_clks_info(hw);
int val;
val = twlclk_read(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE);
if (val < 0) {
dev_err(cinfo->dev, "clk read failed\n");
return val;
}
val &= TWL6030_CFG_STATE_MASK;
return val == TWL6030_CFG_STATE_ON;
}
static const struct clk_ops twl6032_clks_ops = {
.prepare = twl6032_clks_prepare,
.unprepare = twl6032_clks_unprepare,
.is_prepared = twl6032_clks_is_prepared,
.recalc_rate = twl_clks_recalc_rate,
};
@ -155,6 +167,7 @@ static int twl_clks_probe(struct platform_device *pdev)
for (i = 0; i < count; i++) {
cinfo[i].base = hw_data[i].base;
cinfo[i].dev = &pdev->dev;
cinfo[i].type = platform_get_device_id(pdev)->driver_data;
cinfo[i].hw.init = &hw_data[i].init;
ret = devm_clk_hw_register(&pdev->dev, &cinfo[i].hw);
if (ret) {
@ -176,7 +189,11 @@ static int twl_clks_probe(struct platform_device *pdev)
static const struct platform_device_id twl_clks_id[] = {
{
.name = "twl6030-clk",
.driver_data = TWL_TYPE_6030,
}, {
.name = "twl6032-clk",
.driver_data = TWL_TYPE_6032,
}, {
/* sentinel */
}

View File

@ -608,12 +608,6 @@ bool clk_hw_is_prepared(const struct clk_hw *hw)
}
EXPORT_SYMBOL_GPL(clk_hw_is_prepared);
bool clk_hw_rate_is_protected(const struct clk_hw *hw)
{
return clk_core_rate_is_protected(hw->core);
}
EXPORT_SYMBOL_GPL(clk_hw_rate_is_protected);
bool clk_hw_is_enabled(const struct clk_hw *hw)
{
return clk_core_is_enabled(hw->core);
@ -2536,7 +2530,7 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
rate = clk_core_req_round_rate_nolock(core, req_rate);
/* bail early if nothing to do */
if (rate == clk_core_get_rate_nolock(core))
if (rate == clk_core_get_rate_recalc(core))
return 0;
/* fail on a direct rate set of a protected provider */

View File

@ -203,5 +203,35 @@ int of_clk_hw_register_kunit(struct kunit *test, struct device_node *node, struc
}
EXPORT_SYMBOL_GPL(of_clk_hw_register_kunit);
KUNIT_DEFINE_ACTION_WRAPPER(of_clk_del_provider_wrapper,
of_clk_del_provider, struct device_node *);
/**
* of_clk_add_hw_provider_kunit() - Test managed of_clk_add_hw_provider()
* @test: The test context
* @np: Device node pointer associated with clock provider
* @get: Callback for decoding clk_hw
* @data: Context pointer for @get callback.
*
* Just like of_clk_add_hw_provider(), except the clk_hw provider 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_add_hw_provider_kunit(struct kunit *test, struct device_node *np,
struct clk_hw *(*get)(struct of_phandle_args *clkspec, void *data),
void *data)
{
int ret;
ret = of_clk_add_hw_provider(np, get, data);
if (ret)
return ret;
return kunit_add_action_or_reset(test, of_clk_del_provider_wrapper, np);
}
EXPORT_SYMBOL_GPL(of_clk_add_hw_provider_kunit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("KUnit helpers for clk providers and consumers");

View File

@ -4,6 +4,7 @@
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clk/clk-conf.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@ -15,6 +16,7 @@
#include <kunit/platform_device.h>
#include <kunit/test.h>
#include "kunit_clk_assigned_rates.h"
#include "clk_parent_data_test.h"
static const struct clk_ops empty_clk_ops = { };
@ -3075,7 +3077,326 @@ static struct kunit_suite clk_register_clk_parent_data_device_suite = {
.test_cases = clk_register_clk_parent_data_device_test_cases,
};
struct clk_assigned_rates_context {
struct clk_dummy_context clk0;
struct clk_dummy_context clk1;
};
/*
* struct clk_assigned_rates_test_param - Test parameters for clk_assigned_rates test
* @desc: Test description
* @overlay_begin: Pointer to start of DT overlay to apply for test
* @overlay_end: Pointer to end of DT overlay to apply for test
* @rate0: Initial rate of first clk
* @rate1: Initial rate of second clk
* @consumer_test: true if a consumer is being tested
*/
struct clk_assigned_rates_test_param {
const char *desc;
u8 *overlay_begin;
u8 *overlay_end;
unsigned long rate0;
unsigned long rate1;
bool consumer_test;
};
#define TEST_PARAM_OVERLAY(overlay_name) \
.overlay_begin = of_overlay_begin(overlay_name), \
.overlay_end = of_overlay_end(overlay_name)
static void
clk_assigned_rates_register_clk(struct kunit *test,
struct clk_dummy_context *ctx,
struct device_node *np, const char *name,
unsigned long rate)
{
struct clk_init_data init = { };
init.name = name;
init.ops = &clk_dummy_rate_ops;
ctx->hw.init = &init;
ctx->rate = rate;
KUNIT_ASSERT_EQ(test, 0, of_clk_hw_register_kunit(test, np, &ctx->hw));
KUNIT_ASSERT_EQ(test, ctx->rate, rate);
}
/*
* Does most of the work of the test:
*
* 1. Apply the overlay to test
* 2. Register the clk or clks to test
* 3. Register the clk provider
* 4. Apply clk defaults to the consumer device if this is a consumer test
*
* The tests will set different test_param values to test different scenarios
* and validate that in their test functions.
*/
static int clk_assigned_rates_test_init(struct kunit *test)
{
struct device_node *np, *consumer;
struct clk_hw_onecell_data *data;
struct clk_assigned_rates_context *ctx;
u32 clk_cells;
const struct clk_assigned_rates_test_param *test_param;
test_param = test->param_value;
KUNIT_ASSERT_EQ(test, 0, __of_overlay_apply_kunit(test,
test_param->overlay_begin,
test_param->overlay_end));
KUNIT_ASSERT_NOT_ERR_OR_NULL(test,
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL));
test->priv = ctx;
KUNIT_ASSERT_NOT_ERR_OR_NULL(test,
np = of_find_compatible_node(NULL, NULL, "test,clk-assigned-rates"));
of_node_put_kunit(test, np);
KUNIT_ASSERT_EQ(test, 0, of_property_read_u32(np, "#clock-cells", &clk_cells));
/* Only support #clock-cells = <0> or <1> */
KUNIT_ASSERT_LT(test, clk_cells, 2);
clk_assigned_rates_register_clk(test, &ctx->clk0, np,
"test_assigned_rate0", test_param->rate0);
if (clk_cells == 0) {
KUNIT_ASSERT_EQ(test, 0,
of_clk_add_hw_provider_kunit(test, np, of_clk_hw_simple_get,
&ctx->clk0.hw));
} else if (clk_cells == 1) {
clk_assigned_rates_register_clk(test, &ctx->clk1, np,
"test_assigned_rate1", test_param->rate1);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test,
data = kunit_kzalloc(test, struct_size(data, hws, 2), GFP_KERNEL));
data->num = 2;
data->hws[0] = &ctx->clk0.hw;
data->hws[1] = &ctx->clk1.hw;
KUNIT_ASSERT_EQ(test, 0,
of_clk_add_hw_provider_kunit(test, np, of_clk_hw_onecell_get, data));
}
/* Consumers are optional */
if (test_param->consumer_test) {
KUNIT_ASSERT_NOT_ERR_OR_NULL(test,
consumer = of_find_compatible_node(NULL, NULL, "test,clk-consumer"));
of_node_put_kunit(test, consumer);
KUNIT_ASSERT_EQ(test, 0, of_clk_set_defaults(consumer, false));
}
return 0;
}
static void clk_assigned_rates_assigns_one(struct kunit *test)
{
struct clk_assigned_rates_context *ctx = test->priv;
KUNIT_EXPECT_EQ(test, ctx->clk0.rate, ASSIGNED_RATES_0_RATE);
}
static void clk_assigned_rates_assigns_multiple(struct kunit *test)
{
struct clk_assigned_rates_context *ctx = test->priv;
KUNIT_EXPECT_EQ(test, ctx->clk0.rate, ASSIGNED_RATES_0_RATE);
KUNIT_EXPECT_EQ(test, ctx->clk1.rate, ASSIGNED_RATES_1_RATE);
}
static void clk_assigned_rates_skips(struct kunit *test)
{
struct clk_assigned_rates_context *ctx = test->priv;
const struct clk_assigned_rates_test_param *test_param = test->param_value;
KUNIT_EXPECT_NE(test, ctx->clk0.rate, ASSIGNED_RATES_0_RATE);
KUNIT_EXPECT_EQ(test, ctx->clk0.rate, test_param->rate0);
}
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_one);
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_one_consumer);
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_u64_one);
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_u64_one_consumer);
/* Test cases that assign one rate */
static const struct clk_assigned_rates_test_param clk_assigned_rates_assigns_one_test_params[] = {
{
/*
* Test that a single cell assigned-clock-rates property
* assigns the rate when the property is in the provider.
*/
.desc = "provider assigns",
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_one),
},
{
/*
* Test that a single cell assigned-clock-rates property
* assigns the rate when the property is in the consumer.
*/
.desc = "consumer assigns",
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_one_consumer),
.consumer_test = true,
},
{
/*
* Test that a single cell assigned-clock-rates-u64 property
* assigns the rate when the property is in the provider.
*/
.desc = "provider assigns u64",
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_u64_one),
},
{
/*
* Test that a single cell assigned-clock-rates-u64 property
* assigns the rate when the property is in the consumer.
*/
.desc = "consumer assigns u64",
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_u64_one_consumer),
.consumer_test = true,
},
};
KUNIT_ARRAY_PARAM_DESC(clk_assigned_rates_assigns_one,
clk_assigned_rates_assigns_one_test_params, desc)
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_multiple);
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_multiple_consumer);
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_u64_multiple);
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_u64_multiple_consumer);
/* Test cases that assign multiple rates */
static const struct clk_assigned_rates_test_param clk_assigned_rates_assigns_multiple_test_params[] = {
{
/*
* Test that a multiple cell assigned-clock-rates property
* assigns the rates when the property is in the provider.
*/
.desc = "provider assigns",
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_multiple),
},
{
/*
* Test that a multiple cell assigned-clock-rates property
* assigns the rates when the property is in the consumer.
*/
.desc = "consumer assigns",
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_multiple_consumer),
.consumer_test = true,
},
{
/*
* Test that a single cell assigned-clock-rates-u64 property
* assigns the rate when the property is in the provider.
*/
.desc = "provider assigns u64",
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_u64_multiple),
},
{
/*
* Test that a multiple cell assigned-clock-rates-u64 property
* assigns the rates when the property is in the consumer.
*/
.desc = "consumer assigns u64",
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_u64_multiple_consumer),
.consumer_test = true,
},
};
KUNIT_ARRAY_PARAM_DESC(clk_assigned_rates_assigns_multiple,
clk_assigned_rates_assigns_multiple_test_params,
desc)
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_without);
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_without_consumer);
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_zero);
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_zero_consumer);
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_null);
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_null_consumer);
/* Test cases that skip changing the rate due to malformed DT */
static const struct clk_assigned_rates_test_param clk_assigned_rates_skips_test_params[] = {
{
/*
* Test that an assigned-clock-rates property without an assigned-clocks
* property fails when the property is in the provider.
*/
.desc = "provider missing assigned-clocks",
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_without),
.rate0 = 3000,
},
{
/*
* Test that an assigned-clock-rates property without an assigned-clocks
* property fails when the property is in the consumer.
*/
.desc = "consumer missing assigned-clocks",
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_without_consumer),
.rate0 = 3000,
.consumer_test = true,
},
{
/*
* Test that an assigned-clock-rates property of zero doesn't
* set a rate when the property is in the provider.
*/
.desc = "provider assigned-clock-rates of zero",
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_zero),
.rate0 = 3000,
},
{
/*
* Test that an assigned-clock-rates property of zero doesn't
* set a rate when the property is in the consumer.
*/
.desc = "consumer assigned-clock-rates of zero",
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_zero_consumer),
.rate0 = 3000,
.consumer_test = true,
},
{
/*
* Test that an assigned-clocks property with a null phandle
* doesn't set a rate when the property is in the provider.
*/
.desc = "provider assigned-clocks null phandle",
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_null),
.rate0 = 3000,
},
{
/*
* Test that an assigned-clocks property with a null phandle
* doesn't set a rate when the property is in the consumer.
*/
.desc = "provider assigned-clocks null phandle",
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_null_consumer),
.rate0 = 3000,
.consumer_test = true,
},
};
KUNIT_ARRAY_PARAM_DESC(clk_assigned_rates_skips,
clk_assigned_rates_skips_test_params,
desc)
static struct kunit_case clk_assigned_rates_test_cases[] = {
KUNIT_CASE_PARAM(clk_assigned_rates_assigns_one,
clk_assigned_rates_assigns_one_gen_params),
KUNIT_CASE_PARAM(clk_assigned_rates_assigns_multiple,
clk_assigned_rates_assigns_multiple_gen_params),
KUNIT_CASE_PARAM(clk_assigned_rates_skips,
clk_assigned_rates_skips_gen_params),
{}
};
/*
* Test suite for assigned-clock-rates{-u64} DT property.
*/
static struct kunit_suite clk_assigned_rates_suite = {
.name = "clk_assigned_rates",
.test_cases = clk_assigned_rates_test_cases,
.init = clk_assigned_rates_test_init,
};
kunit_test_suites(
&clk_assigned_rates_suite,
&clk_leaf_mux_set_rate_parent_test_suite,
&clk_test_suite,
&clk_multiple_parents_mux_test_suite,

View File

@ -254,9 +254,11 @@ static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate,
pll_div = FIELD_PREP(PLL_RDIV_MASK, rate->rdiv) | rate->odiv |
FIELD_PREP(PLL_MFI_MASK, rate->mfi);
writel_relaxed(pll_div, pll->base + PLL_DIV);
readl(pll->base + PLL_DIV);
if (pll->flags & CLK_FRACN_GPPLL_FRACN) {
writel_relaxed(rate->mfd, pll->base + PLL_DENOMINATOR);
writel_relaxed(FIELD_PREP(PLL_MFN_MASK, rate->mfn), pll->base + PLL_NUMERATOR);
readl(pll->base + PLL_NUMERATOR);
}
/* Wait for 5us according to fracn mode pll doc */
@ -265,6 +267,7 @@ static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate,
/* Enable Powerup */
tmp |= POWERUP_MASK;
writel_relaxed(tmp, pll->base + PLL_CTRL);
readl(pll->base + PLL_CTRL);
/* Wait Lock */
ret = clk_fracn_gppll_wait_lock(pll);
@ -302,14 +305,15 @@ static int clk_fracn_gppll_prepare(struct clk_hw *hw)
val |= POWERUP_MASK;
writel_relaxed(val, pll->base + PLL_CTRL);
val |= CLKMUX_EN;
writel_relaxed(val, pll->base + PLL_CTRL);
readl(pll->base + PLL_CTRL);
ret = clk_fracn_gppll_wait_lock(pll);
if (ret)
return ret;
val |= CLKMUX_EN;
writel_relaxed(val, pll->base + PLL_CTRL);
val &= ~CLKMUX_BYPASS;
writel_relaxed(val, pll->base + PLL_CTRL);

View File

@ -294,9 +294,9 @@ static int clk_imx_acm_attach_pm_domains(struct device *dev,
DL_FLAG_STATELESS |
DL_FLAG_PM_RUNTIME |
DL_FLAG_RPM_ACTIVE);
if (IS_ERR(dev_pm->pd_dev_link[i])) {
if (!dev_pm->pd_dev_link[i]) {
dev_pm_domain_detach(dev_pm->pd_dev[i], false);
ret = PTR_ERR(dev_pm->pd_dev_link[i]);
ret = -EINVAL;
goto detach_pm;
}
}

View File

@ -15,6 +15,11 @@
#include "clk.h"
#define IMX93_CLK_END 207
#define PLAT_IMX93 BIT(0)
#define PLAT_IMX91 BIT(1)
enum clk_sel {
LOW_SPEED_IO_SEL,
NON_IO_SEL,
@ -53,6 +58,7 @@ static const struct imx93_clk_root {
u32 off;
enum clk_sel sel;
unsigned long flags;
unsigned long plat;
} root_array[] = {
/* a55/m33/bus critical clk for system run */
{ IMX93_CLK_A55_PERIPH, "a55_periph_root", 0x0000, FAST_SEL, CLK_IS_CRITICAL },
@ -63,7 +69,7 @@ static const struct imx93_clk_root {
{ IMX93_CLK_BUS_AON, "bus_aon_root", 0x0300, LOW_SPEED_IO_SEL, CLK_IS_CRITICAL },
{ IMX93_CLK_WAKEUP_AXI, "wakeup_axi_root", 0x0380, FAST_SEL, CLK_IS_CRITICAL },
{ IMX93_CLK_SWO_TRACE, "swo_trace_root", 0x0400, LOW_SPEED_IO_SEL, },
{ IMX93_CLK_M33_SYSTICK, "m33_systick_root", 0x0480, LOW_SPEED_IO_SEL, },
{ IMX93_CLK_M33_SYSTICK, "m33_systick_root", 0x0480, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, },
{ IMX93_CLK_FLEXIO1, "flexio1_root", 0x0500, LOW_SPEED_IO_SEL, },
{ IMX93_CLK_FLEXIO2, "flexio2_root", 0x0580, LOW_SPEED_IO_SEL, },
{ IMX93_CLK_LPTMR1, "lptmr1_root", 0x0700, LOW_SPEED_IO_SEL, },
@ -120,15 +126,15 @@ static const struct imx93_clk_root {
{ IMX93_CLK_HSIO_ACSCAN_80M, "hsio_acscan_80m_root", 0x1f80, LOW_SPEED_IO_SEL, },
{ IMX93_CLK_HSIO_ACSCAN_480M, "hsio_acscan_480m_root", 0x2000, MISC_SEL, },
{ IMX93_CLK_NIC_AXI, "nic_axi_root", 0x2080, FAST_SEL, CLK_IS_CRITICAL, },
{ IMX93_CLK_ML_APB, "ml_apb_root", 0x2180, LOW_SPEED_IO_SEL, },
{ IMX93_CLK_ML, "ml_root", 0x2200, FAST_SEL, },
{ IMX93_CLK_ML_APB, "ml_apb_root", 0x2180, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, },
{ IMX93_CLK_ML, "ml_root", 0x2200, FAST_SEL, 0, PLAT_IMX93, },
{ IMX93_CLK_MEDIA_AXI, "media_axi_root", 0x2280, FAST_SEL, },
{ IMX93_CLK_MEDIA_APB, "media_apb_root", 0x2300, LOW_SPEED_IO_SEL, },
{ IMX93_CLK_MEDIA_LDB, "media_ldb_root", 0x2380, VIDEO_SEL, },
{ IMX93_CLK_MEDIA_LDB, "media_ldb_root", 0x2380, VIDEO_SEL, 0, PLAT_IMX93, },
{ IMX93_CLK_MEDIA_DISP_PIX, "media_disp_pix_root", 0x2400, VIDEO_SEL, },
{ IMX93_CLK_CAM_PIX, "cam_pix_root", 0x2480, VIDEO_SEL, },
{ IMX93_CLK_MIPI_TEST_BYTE, "mipi_test_byte_root", 0x2500, VIDEO_SEL, },
{ IMX93_CLK_MIPI_PHY_CFG, "mipi_phy_cfg_root", 0x2580, VIDEO_SEL, },
{ IMX93_CLK_MIPI_TEST_BYTE, "mipi_test_byte_root", 0x2500, VIDEO_SEL, 0, PLAT_IMX93, },
{ IMX93_CLK_MIPI_PHY_CFG, "mipi_phy_cfg_root", 0x2580, VIDEO_SEL, 0, PLAT_IMX93, },
{ IMX93_CLK_ADC, "adc_root", 0x2700, LOW_SPEED_IO_SEL, },
{ IMX93_CLK_PDM, "pdm_root", 0x2780, AUDIO_SEL, },
{ IMX93_CLK_TSTMR1, "tstmr1_root", 0x2800, LOW_SPEED_IO_SEL, },
@ -137,13 +143,16 @@ static const struct imx93_clk_root {
{ IMX93_CLK_MQS2, "mqs2_root", 0x2980, AUDIO_SEL, },
{ IMX93_CLK_AUDIO_XCVR, "audio_xcvr_root", 0x2a00, NON_IO_SEL, },
{ IMX93_CLK_SPDIF, "spdif_root", 0x2a80, AUDIO_SEL, },
{ IMX93_CLK_ENET, "enet_root", 0x2b00, NON_IO_SEL, },
{ IMX93_CLK_ENET_TIMER1, "enet_timer1_root", 0x2b80, LOW_SPEED_IO_SEL, },
{ IMX93_CLK_ENET_TIMER2, "enet_timer2_root", 0x2c00, LOW_SPEED_IO_SEL, },
{ IMX93_CLK_ENET_REF, "enet_ref_root", 0x2c80, NON_IO_SEL, },
{ IMX93_CLK_ENET_REF_PHY, "enet_ref_phy_root", 0x2d00, LOW_SPEED_IO_SEL, },
{ IMX93_CLK_I3C1_SLOW, "i3c1_slow_root", 0x2d80, LOW_SPEED_IO_SEL, },
{ IMX93_CLK_I3C2_SLOW, "i3c2_slow_root", 0x2e00, LOW_SPEED_IO_SEL, },
{ IMX93_CLK_ENET, "enet_root", 0x2b00, NON_IO_SEL, 0, PLAT_IMX93, },
{ IMX93_CLK_ENET_TIMER1, "enet_timer1_root", 0x2b80, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, },
{ IMX93_CLK_ENET_TIMER2, "enet_timer2_root", 0x2c00, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, },
{ IMX93_CLK_ENET_REF, "enet_ref_root", 0x2c80, NON_IO_SEL, 0, PLAT_IMX93, },
{ IMX93_CLK_ENET_REF_PHY, "enet_ref_phy_root", 0x2d00, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, },
{ IMX91_CLK_ENET1_QOS_TSN, "enet1_qos_tsn_root", 0x2b00, NON_IO_SEL, 0, PLAT_IMX91, },
{ IMX91_CLK_ENET_TIMER, "enet_timer_root", 0x2b80, LOW_SPEED_IO_SEL, 0, PLAT_IMX91, },
{ IMX91_CLK_ENET2_REGULAR, "enet2_regular_root", 0x2c80, NON_IO_SEL, 0, PLAT_IMX91, },
{ IMX93_CLK_I3C1_SLOW, "i3c1_slow_root", 0x2d80, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, },
{ IMX93_CLK_I3C2_SLOW, "i3c2_slow_root", 0x2e00, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, },
{ IMX93_CLK_USB_PHY_BURUNIN, "usb_phy_root", 0x2e80, LOW_SPEED_IO_SEL, },
{ IMX93_CLK_PAL_CAME_SCAN, "pal_came_scan_root", 0x2f00, MISC_SEL, }
};
@ -155,6 +164,7 @@ static const struct imx93_clk_ccgr {
u32 off;
unsigned long flags;
u32 *shared_count;
unsigned long plat;
} ccgr_array[] = {
{ IMX93_CLK_A55_GATE, "a55_alt", "a55_alt_root", 0x8000, },
/* M33 critical clk for system run */
@ -244,8 +254,10 @@ static const struct imx93_clk_ccgr {
{ IMX93_CLK_AUD_XCVR_GATE, "aud_xcvr", "audio_xcvr_root", 0x9b80, },
{ IMX93_CLK_SPDIF_GATE, "spdif", "spdif_root", 0x9c00, },
{ IMX93_CLK_HSIO_32K_GATE, "hsio_32k", "osc_32k", 0x9dc0, },
{ IMX93_CLK_ENET1_GATE, "enet1", "wakeup_axi_root", 0x9e00, },
{ IMX93_CLK_ENET_QOS_GATE, "enet_qos", "wakeup_axi_root", 0x9e40, },
{ IMX93_CLK_ENET1_GATE, "enet1", "wakeup_axi_root", 0x9e00, 0, NULL, PLAT_IMX93, },
{ IMX93_CLK_ENET_QOS_GATE, "enet_qos", "wakeup_axi_root", 0x9e40, 0, NULL, PLAT_IMX93, },
{ IMX91_CLK_ENET2_REGULAR_GATE, "enet2_regular", "wakeup_axi_root", 0x9e00, 0, NULL, PLAT_IMX91, },
{ IMX91_CLK_ENET1_QOS_TSN_GATE, "enet1_qos_tsn", "wakeup_axi_root", 0x9e40, 0, NULL, PLAT_IMX91, },
/* Critical because clk accessed during CPU idle */
{ IMX93_CLK_SYS_CNT_GATE, "sys_cnt", "osc_24m", 0x9e80, CLK_IS_CRITICAL},
{ IMX93_CLK_TSTMR1_GATE, "tstmr1", "bus_aon_root", 0x9ec0, },
@ -265,6 +277,7 @@ static int imx93_clocks_probe(struct platform_device *pdev)
const struct imx93_clk_ccgr *ccgr;
void __iomem *base, *anatop_base;
int i, ret;
const unsigned long plat = (unsigned long)device_get_match_data(&pdev->dev);
clk_hw_data = devm_kzalloc(dev, struct_size(clk_hw_data, hws,
IMX93_CLK_END), GFP_KERNEL);
@ -314,17 +327,20 @@ static int imx93_clocks_probe(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(root_array); i++) {
root = &root_array[i];
clks[root->clk] = imx93_clk_composite_flags(root->name,
parent_names[root->sel],
4, base + root->off, 3,
root->flags);
if (!root->plat || root->plat & plat)
clks[root->clk] = imx93_clk_composite_flags(root->name,
parent_names[root->sel],
4, base + root->off, 3,
root->flags);
}
for (i = 0; i < ARRAY_SIZE(ccgr_array); i++) {
ccgr = &ccgr_array[i];
clks[ccgr->clk] = imx93_clk_gate(NULL, ccgr->name, ccgr->parent_name,
ccgr->flags, base + ccgr->off, 0, 1, 1, 3,
ccgr->shared_count);
if (!ccgr->plat || ccgr->plat & plat)
clks[ccgr->clk] = imx93_clk_gate(NULL,
ccgr->name, ccgr->parent_name,
ccgr->flags, base + ccgr->off, 0, 1, 1, 3,
ccgr->shared_count);
}
clks[IMX93_CLK_A55_SEL] = imx_clk_hw_mux2("a55_sel", base + 0x4820, 0, 1, a55_core_sels,
@ -354,7 +370,8 @@ static int imx93_clocks_probe(struct platform_device *pdev)
}
static const struct of_device_id imx93_clk_of_match[] = {
{ .compatible = "fsl,imx93-ccm" },
{ .compatible = "fsl,imx93-ccm", .data = (void *)PLAT_IMX93 },
{ .compatible = "fsl,imx91-ccm", .data = (void *)PLAT_IMX91 },
{ /* Sentinel */ },
};
MODULE_DEVICE_TABLE(of, imx93_clk_of_match);

View File

@ -277,6 +277,25 @@ static const struct imx95_blk_ctl_dev_data netcmix_dev_data = {
.clk_reg_offset = 0,
};
static const struct imx95_blk_ctl_clk_dev_data hsio_blk_ctl_clk_dev_data[] = {
[0] = {
.name = "hsio_blk_ctl_clk",
.parent_names = (const char *[]){ "hsio_pll", },
.num_parents = 1,
.reg = 0,
.bit_idx = 6,
.bit_width = 1,
.type = CLK_GATE,
.flags = CLK_SET_RATE_PARENT,
}
};
static const struct imx95_blk_ctl_dev_data hsio_blk_ctl_dev_data = {
.num_clks = 1,
.clk_dev_data = hsio_blk_ctl_clk_dev_data,
.clk_reg_offset = 0,
};
static int imx95_bc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@ -447,6 +466,7 @@ static const struct of_device_id imx95_bc_of_match[] = {
{ .compatible = "nxp,imx95-display-master-csr", },
{ .compatible = "nxp,imx95-lvds-csr", .data = &lvds_csr_dev_data },
{ .compatible = "nxp,imx95-display-csr", .data = &dispmix_csr_dev_data },
{ .compatible = "nxp,imx95-hsio-blk-ctl", .data = &hsio_blk_ctl_dev_data },
{ .compatible = "nxp,imx95-vpu-csr", .data = &vpublk_dev_data },
{ .compatible = "nxp,imx95-netcmix-blk-ctrl", .data = &netcmix_dev_data},
{ /* Sentinel */ },

View File

@ -6,10 +6,12 @@
#include <linux/bits.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/units.h>
#include "clk-scu.h"
@ -41,6 +43,29 @@ struct clk_lpcg_scu {
#define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw)
/* e10858 -LPCG clock gating register synchronization errata */
static void lpcg_e10858_writel(unsigned long rate, void __iomem *reg, u32 val)
{
writel(val, reg);
if (rate >= 24 * HZ_PER_MHZ || rate == 0) {
/*
* The time taken to access the LPCG registers from the AP core
* through the interconnect is longer than the minimum delay
* of 4 clock cycles required by the errata.
* Adding a readl will provide sufficient delay to prevent
* back-to-back writes.
*/
readl(reg);
} else {
/*
* For clocks running below 24MHz, wait a minimum of
* 4 clock cycles.
*/
ndelay(4 * (DIV_ROUND_UP(1000 * HZ_PER_MHZ, rate)));
}
}
static int clk_lpcg_scu_enable(struct clk_hw *hw)
{
struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
@ -57,7 +82,8 @@ static int clk_lpcg_scu_enable(struct clk_hw *hw)
val |= CLK_GATE_SCU_LPCG_HW_SEL;
reg |= val << clk->bit_idx;
writel(reg, clk->reg);
lpcg_e10858_writel(clk_hw_get_rate(hw), clk->reg, reg);
spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);
@ -74,7 +100,7 @@ static void clk_lpcg_scu_disable(struct clk_hw *hw)
reg = readl_relaxed(clk->reg);
reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx);
writel(reg, clk->reg);
lpcg_e10858_writel(clk_hw_get_rate(hw), clk->reg, reg);
spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);
}
@ -135,6 +161,9 @@ static int __maybe_unused imx_clk_lpcg_scu_suspend(struct device *dev)
{
struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
if (!strncmp("hdmi_lpcg", clk_hw_get_name(&clk->hw), strlen("hdmi_lpcg")))
return 0;
clk->state = readl_relaxed(clk->reg);
dev_dbg(dev, "save lpcg state 0x%x\n", clk->state);
@ -145,13 +174,11 @@ static int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev)
{
struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
/*
* FIXME: Sometimes writes don't work unless the CPU issues
* them twice
*/
if (!strncmp("hdmi_lpcg", clk_hw_get_name(&clk->hw), strlen("hdmi_lpcg")))
return 0;
writel(clk->state, clk->reg);
writel(clk->state, clk->reg);
lpcg_e10858_writel(0, clk->reg, clk->state);
dev_dbg(dev, "restore lpcg state 0x%x\n", clk->state);
return 0;

View File

@ -596,7 +596,7 @@ static int __maybe_unused imx_clk_scu_suspend(struct device *dev)
clk->rate = clk_scu_recalc_rate(&clk->hw, 0);
else
clk->rate = clk_hw_get_rate(&clk->hw);
clk->is_enabled = clk_hw_is_enabled(&clk->hw);
clk->is_enabled = clk_hw_is_prepared(&clk->hw);
if (clk->parent)
dev_dbg(dev, "save parent %s idx %u\n", clk_hw_get_name(clk->parent),

View File

@ -0,0 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _KUNIT_CLK_ASSIGNED_RATES_H
#define _KUNIT_CLK_ASSIGNED_RATES_H
#define ASSIGNED_RATES_0_RATE 1600000
#define ASSIGNED_RATES_1_RATE 9700000
#endif

View File

@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
#include "kunit_clk_assigned_rates.h"
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <1>;
assigned-clocks = <&clk 0>,
<&clk 1>;
assigned-clock-rates = <ASSIGNED_RATES_0_RATE>,
<ASSIGNED_RATES_1_RATE>;
};
};

View File

@ -0,0 +1,20 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
#include "kunit_clk_assigned_rates.h"
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <1>;
};
kunit-clock-consumer {
compatible = "test,clk-consumer";
assigned-clocks = <&clk 0>,
<&clk 1>;
assigned-clock-rates = <ASSIGNED_RATES_0_RATE>,
<ASSIGNED_RATES_1_RATE>;
};
};

View File

@ -0,0 +1,14 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
#include "kunit_clk_assigned_rates.h"
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <0>;
assigned-clocks = <0>;
assigned-clock-rates = <ASSIGNED_RATES_0_RATE>;
};
};

View File

@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
#include "kunit_clk_assigned_rates.h"
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <0>;
};
kunit-clock-consumer {
compatible = "test,clk-consumer";
assigned-clocks = <0>;
assigned-clock-rates = <ASSIGNED_RATES_0_RATE>;
};
};

View File

@ -0,0 +1,14 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
#include "kunit_clk_assigned_rates.h"
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <0>;
assigned-clocks = <&clk>;
assigned-clock-rates = <ASSIGNED_RATES_0_RATE>;
};
};

View File

@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
#include "kunit_clk_assigned_rates.h"
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <0>;
};
kunit-clock-consumer {
compatible = "test,clk-consumer";
assigned-clocks = <&clk>;
assigned-clock-rates = <ASSIGNED_RATES_0_RATE>;
};
};

View File

@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
#include "kunit_clk_assigned_rates.h"
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <1>;
assigned-clocks = <&clk 0>,
<&clk 1>;
assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>,
/bits/ 64 <ASSIGNED_RATES_1_RATE>;
};
};

View File

@ -0,0 +1,20 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
#include "kunit_clk_assigned_rates.h"
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <1>;
};
kunit-clock-consumer {
compatible = "test,clk-consumer";
assigned-clocks = <&clk 0>,
<&clk 1>;
assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>,
/bits/ 64 <ASSIGNED_RATES_1_RATE>;
};
};

View File

@ -0,0 +1,14 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
#include "kunit_clk_assigned_rates.h"
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <0>;
assigned-clocks = <&clk>;
assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>;
};
};

View File

@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
#include "kunit_clk_assigned_rates.h"
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <0>;
};
kunit-clock-consumer {
compatible = "test,clk-consumer";
assigned-clocks = <&clk>;
assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>;
};
};

View File

@ -0,0 +1,13 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
#include "kunit_clk_assigned_rates.h"
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <0>;
assigned-clock-rates = <ASSIGNED_RATES_0_RATE>;
};
};

View File

@ -0,0 +1,17 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
#include "kunit_clk_assigned_rates.h"
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <0>;
};
kunit-clock-consumer {
compatible = "test,clk-consumer";
assigned-clock-rates = <ASSIGNED_RATES_0_RATE>;
};
};

View File

@ -0,0 +1,12 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <0>;
assigned-clocks = <&clk>;
assigned-clock-rates = <0>;
};
};

View File

@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <0>;
};
kunit-clock-consumer {
compatible = "test,clk-consumer";
assigned-clocks = <&clk>;
assigned-clock-rates = <0>;
};
};

View File

@ -124,6 +124,43 @@ config COMMON_CLK_MT2712_VENCSYS
help
This driver supports MediaTek MT2712 vencsys clocks.
config COMMON_CLK_MT6735
tristate "Main clock drivers for MediaTek MT6735"
depends on ARCH_MEDIATEK || COMPILE_TEST
select COMMON_CLK_MEDIATEK
help
This enables drivers for clocks and resets provided
by apmixedsys, topckgen, infracfg and pericfg on the
MediaTek MT6735 SoC.
config COMMON_CLK_MT6735_IMGSYS
tristate "Clock driver for MediaTek MT6735 imgsys"
depends on COMMON_CLK_MT6735
help
This enables a driver for clocks provided by imgsys
on the MediaTek MT6735 SoC.
config COMMON_CLK_MT6735_MFGCFG
tristate "Clock driver for MediaTek MT6735 mfgcfg"
depends on COMMON_CLK_MT6735
help
This enables a driver for clocks and resets provided
by mfgcfg on the MediaTek MT6735 SoC.
config COMMON_CLK_MT6735_VDECSYS
tristate "Clock driver for MediaTek MT6735 vdecsys"
depends on COMMON_CLK_MT6735
help
This enables a driver for clocks and resets provided
by vdecsys on the MediaTek MT6735 SoC.
config COMMON_CLK_MT6735_VENCSYS
tristate "Clock driver for MediaTek MT6735 vencsys"
depends on COMMON_CLK_MT6735
help
This enables a driver for clocks provided by vencsys
on the MediaTek MT6735 SoC.
config COMMON_CLK_MT6765
bool "Clock driver for MediaTek MT6765"
depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST
@ -887,13 +924,6 @@ config COMMON_CLK_MT8195_APUSYS
help
This driver supports MediaTek MT8195 AI Processor Unit System clocks.
config COMMON_CLK_MT8195_AUDSYS
tristate "Clock driver for MediaTek MT8195 audsys"
depends on COMMON_CLK_MT8195
default COMMON_CLK_MT8195
help
This driver supports MediaTek MT8195 audsys clocks.
config COMMON_CLK_MT8195_IMP_IIC_WRAP
tristate "Clock driver for MediaTek MT8195 imp_iic_wrap"
depends on COMMON_CLK_MT8195
@ -908,14 +938,6 @@ config COMMON_CLK_MT8195_MFGCFG
help
This driver supports MediaTek MT8195 mfgcfg clocks.
config COMMON_CLK_MT8195_MSDC
tristate "Clock driver for MediaTek MT8195 msdc"
depends on COMMON_CLK_MT8195
default COMMON_CLK_MT8195
help
This driver supports MediaTek MT8195 MMC and SD Controller's
msdc and msdc_top clocks.
config COMMON_CLK_MT8195_SCP_ADSP
tristate "Clock driver for MediaTek MT8195 scp_adsp"
depends on COMMON_CLK_MT8195

View File

@ -2,6 +2,11 @@
obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o clk-cpumux.o reset.o clk-mux.o
obj-$(CONFIG_COMMON_CLK_MEDIATEK_FHCTL) += clk-fhctl.o clk-pllfh.o
obj-$(CONFIG_COMMON_CLK_MT6735) += clk-mt6735-apmixedsys.o clk-mt6735-infracfg.o clk-mt6735-pericfg.o clk-mt6735-topckgen.o
obj-$(CONFIG_COMMON_CLK_MT6735_IMGSYS) += clk-mt6735-imgsys.o
obj-$(CONFIG_COMMON_CLK_MT6735_MFGCFG) += clk-mt6735-mfgcfg.o
obj-$(CONFIG_COMMON_CLK_MT6735_VDECSYS) += clk-mt6735-vdecsys.o
obj-$(CONFIG_COMMON_CLK_MT6735_VENCSYS) += clk-mt6735-vencsys.o
obj-$(CONFIG_COMMON_CLK_MT6765) += clk-mt6765.o
obj-$(CONFIG_COMMON_CLK_MT6765_AUDIOSYS) += clk-mt6765-audio.o
obj-$(CONFIG_COMMON_CLK_MT6765_CAMSYS) += clk-mt6765-cam.o

View File

@ -0,0 +1,137 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2022 Yassine Oudjana <y.oudjana@protonmail.com>
*/
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include "clk-mtk.h"
#include "clk-pll.h"
#include <dt-bindings/clock/mediatek,mt6735-apmixedsys.h>
#define AP_PLL_CON_5 0x014
#define ARMPLL_CON0 0x200
#define ARMPLL_CON1 0x204
#define ARMPLL_PWR_CON0 0x20c
#define MAINPLL_CON0 0x210
#define MAINPLL_CON1 0x214
#define MAINPLL_PWR_CON0 0x21c
#define UNIVPLL_CON0 0x220
#define UNIVPLL_CON1 0x224
#define UNIVPLL_PWR_CON0 0x22c
#define MMPLL_CON0 0x230
#define MMPLL_CON1 0x234
#define MMPLL_PWR_CON0 0x23c
#define MSDCPLL_CON0 0x240
#define MSDCPLL_CON1 0x244
#define MSDCPLL_PWR_CON0 0x24c
#define VENCPLL_CON0 0x250
#define VENCPLL_CON1 0x254
#define VENCPLL_PWR_CON0 0x25c
#define TVDPLL_CON0 0x260
#define TVDPLL_CON1 0x264
#define TVDPLL_PWR_CON0 0x26c
#define APLL1_CON0 0x270
#define APLL1_CON1 0x274
#define APLL1_CON2 0x278
#define APLL1_PWR_CON0 0x280
#define APLL2_CON0 0x284
#define APLL2_CON1 0x288
#define APLL2_CON2 0x28c
#define APLL2_PWR_CON0 0x294
#define CON0_RST_BAR BIT(24)
#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _rst_bar_mask, \
_pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg, \
_tuner_en_bit, _pcw_reg, _pcwbits, _flags) { \
.id = _id, \
.name = _name, \
.parent_name = "clk26m", \
.reg = _reg, \
.pwr_reg = _pwr_reg, \
.en_mask = _en_mask, \
.rst_bar_mask = _rst_bar_mask, \
.pd_reg = _pd_reg, \
.pd_shift = _pd_shift, \
.tuner_reg = _tuner_reg, \
.tuner_en_reg = _tuner_en_reg, \
.tuner_en_bit = _tuner_en_bit, \
.pcw_reg = _pcw_reg, \
.pcw_chg_reg = _pcw_reg, \
.pcwbits = _pcwbits, \
.flags = _flags, \
}
static const struct mtk_pll_data apmixedsys_plls[] = {
PLL(CLK_APMIXED_ARMPLL, "armpll", ARMPLL_CON0, ARMPLL_PWR_CON0, 0x00000001, 0, ARMPLL_CON1, 24, 0, 0, 0, ARMPLL_CON1, 21, PLL_AO),
PLL(CLK_APMIXED_MAINPLL, "mainpll", MAINPLL_CON0, MAINPLL_PWR_CON0, 0xf0000101, CON0_RST_BAR, MAINPLL_CON1, 24, 0, 0, 0, MAINPLL_CON1, 21, HAVE_RST_BAR),
PLL(CLK_APMIXED_UNIVPLL, "univpll", UNIVPLL_CON0, UNIVPLL_PWR_CON0, 0xfc000001, CON0_RST_BAR, UNIVPLL_CON1, 24, 0, 0, 0, UNIVPLL_CON1, 21, HAVE_RST_BAR),
PLL(CLK_APMIXED_MMPLL, "mmpll", MMPLL_CON0, MMPLL_PWR_CON0, 0x00000001, 0, MMPLL_CON1, 24, 0, 0, 0, MMPLL_CON1, 21, 0),
PLL(CLK_APMIXED_MSDCPLL, "msdcpll", MSDCPLL_CON0, MSDCPLL_PWR_CON0, 0x00000001, 0, MSDCPLL_CON1, 24, 0, 0, 0, MSDCPLL_CON1, 21, 0),
PLL(CLK_APMIXED_VENCPLL, "vencpll", VENCPLL_CON0, VENCPLL_PWR_CON0, 0x00000001, CON0_RST_BAR, VENCPLL_CON1, 24, 0, 0, 0, VENCPLL_CON1, 21, HAVE_RST_BAR),
PLL(CLK_APMIXED_TVDPLL, "tvdpll", TVDPLL_CON0, TVDPLL_PWR_CON0, 0x00000001, 0, TVDPLL_CON1, 24, 0, 0, 0, TVDPLL_CON1, 21, 0),
PLL(CLK_APMIXED_APLL1, "apll1", APLL1_CON0, APLL1_PWR_CON0, 0x00000001, 0, APLL1_CON0, 4, APLL1_CON2, AP_PLL_CON_5, 0, APLL1_CON1, 31, 0),
PLL(CLK_APMIXED_APLL2, "apll2", APLL2_CON0, APLL2_PWR_CON0, 0x00000001, 0, APLL2_CON0, 4, APLL2_CON2, AP_PLL_CON_5, 1, APLL2_CON1, 31, 0)
};
static int clk_mt6735_apmixed_probe(struct platform_device *pdev)
{
void __iomem *base;
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct clk_hw_onecell_data *clk_data;
int ret;
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
clk_data = mtk_devm_alloc_clk_data(&pdev->dev, ARRAY_SIZE(apmixedsys_plls));
if (!clk_data)
return -ENOMEM;
platform_set_drvdata(pdev, clk_data);
ret = mtk_clk_register_plls(pdev->dev.of_node, apmixedsys_plls,
ARRAY_SIZE(apmixedsys_plls), clk_data);
if (ret) {
dev_err(&pdev->dev, "Failed to register PLLs: %d\n", ret);
return ret;
}
ret = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get,
clk_data);
if (ret)
dev_err(&pdev->dev,
"Failed to register clock provider: %d\n", ret);
return ret;
}
static void clk_mt6735_apmixed_remove(struct platform_device *pdev)
{
struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev);
mtk_clk_unregister_plls(apmixedsys_plls, ARRAY_SIZE(apmixedsys_plls), clk_data);
}
static const struct of_device_id of_match_mt6735_apmixedsys[] = {
{ .compatible = "mediatek,mt6735-apmixedsys" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_match_mt6735_apmixedsys);
static struct platform_driver clk_mt6735_apmixedsys = {
.probe = clk_mt6735_apmixed_probe,
.remove = clk_mt6735_apmixed_remove,
.driver = {
.name = "clk-mt6735-apmixedsys",
.of_match_table = of_match_mt6735_apmixedsys,
},
};
module_platform_driver(clk_mt6735_apmixedsys);
MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
MODULE_DESCRIPTION("MediaTek MT6735 apmixedsys clock driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,57 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2022 Yassine Oudjana <y.oudjana@protonmail.com>
*/
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include "clk-gate.h"
#include "clk-mtk.h"
#include <dt-bindings/clock/mediatek,mt6735-imgsys.h>
#define IMG_CG_CON 0x00
#define IMG_CG_SET 0x04
#define IMG_CG_CLR 0x08
static struct mtk_gate_regs imgsys_cg_regs = {
.set_ofs = IMG_CG_SET,
.clr_ofs = IMG_CG_CLR,
.sta_ofs = IMG_CG_CON,
};
static const struct mtk_gate imgsys_gates[] = {
GATE_MTK(CLK_IMG_SMI_LARB2, "smi_larb2", "mm_sel", &imgsys_cg_regs, 0, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_IMG_CAM_SMI, "cam_smi", "mm_sel", &imgsys_cg_regs, 5, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_IMG_CAM_CAM, "cam_cam", "mm_sel", &imgsys_cg_regs, 6, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_IMG_SEN_TG, "sen_tg", "mm_sel", &imgsys_cg_regs, 7, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_IMG_SEN_CAM, "sen_cam", "mm_sel", &imgsys_cg_regs, 8, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_IMG_CAM_SV, "cam_sv", "mm_sel", &imgsys_cg_regs, 9, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_IMG_SUFOD, "sufod", "mm_sel", &imgsys_cg_regs, 10, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_IMG_FD, "fd", "mm_sel", &imgsys_cg_regs, 11, &mtk_clk_gate_ops_setclr),
};
static const struct mtk_clk_desc imgsys_clks = {
.clks = imgsys_gates,
.num_clks = ARRAY_SIZE(imgsys_gates),
};
static const struct of_device_id of_match_mt6735_imgsys[] = {
{ .compatible = "mediatek,mt6735-imgsys", .data = &imgsys_clks },
{ /* sentinel */ }
};
static struct platform_driver clk_mt6735_imgsys = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt6735-imgsys",
.of_match_table = of_match_mt6735_imgsys,
},
};
module_platform_driver(clk_mt6735_imgsys);
MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
MODULE_DESCRIPTION("MediaTek MT6735 imgsys clock driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,107 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2022 Yassine Oudjana <y.oudjana@protonmail.com>
*/
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include "clk-gate.h"
#include "clk-mtk.h"
#include <dt-bindings/clock/mediatek,mt6735-infracfg.h>
#include <dt-bindings/reset/mediatek,mt6735-infracfg.h>
#define INFRA_RST0 0x30
#define INFRA_GLOBALCON_PDN0 0x40
#define INFRA_PDN1 0x44
#define INFRA_PDN_STA 0x48
#define RST_NR_PER_BANK 32
static struct mtk_gate_regs infra_cg_regs = {
.set_ofs = INFRA_GLOBALCON_PDN0,
.clr_ofs = INFRA_PDN1,
.sta_ofs = INFRA_PDN_STA,
};
static const struct mtk_gate infracfg_gates[] = {
GATE_MTK(CLK_INFRA_DBG, "dbg", "axi_sel", &infra_cg_regs, 0, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_INFRA_GCE, "gce", "axi_sel", &infra_cg_regs, 1, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_INFRA_TRBG, "trbg", "axi_sel", &infra_cg_regs, 2, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_INFRA_CPUM, "cpum", "axi_sel", &infra_cg_regs, 3, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_INFRA_DEVAPC, "devapc", "axi_sel", &infra_cg_regs, 4, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_INFRA_AUDIO, "audio", "aud_intbus_sel", &infra_cg_regs, 5, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_INFRA_GCPU, "gcpu", "axi_sel", &infra_cg_regs, 6, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_INFRA_L2C_SRAM, "l2csram", "axi_sel", &infra_cg_regs, 7, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_INFRA_M4U, "m4u", "axi_sel", &infra_cg_regs, 8, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_INFRA_CLDMA, "cldma", "axi_sel", &infra_cg_regs, 12, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_INFRA_CONNMCU_BUS, "connmcu_bus", "axi_sel", &infra_cg_regs, 15, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_INFRA_KP, "kp", "axi_sel", &infra_cg_regs, 16, &mtk_clk_gate_ops_setclr),
GATE_MTK_FLAGS(CLK_INFRA_APXGPT, "apxgpt", "axi_sel", &infra_cg_regs, 18, &mtk_clk_gate_ops_setclr, CLK_IS_CRITICAL),
GATE_MTK(CLK_INFRA_SEJ, "sej", "axi_sel", &infra_cg_regs, 19, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_INFRA_CCIF0_AP, "ccif0ap", "axi_sel", &infra_cg_regs, 20, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_INFRA_CCIF1_AP, "ccif1ap", "axi_sel", &infra_cg_regs, 21, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_INFRA_PMIC_SPI, "pmicspi", "pmicspi_sel", &infra_cg_regs, 22, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_INFRA_PMIC_WRAP, "pmicwrap", "axi_sel", &infra_cg_regs, 23, &mtk_clk_gate_ops_setclr)
};
static u16 infracfg_rst_bank_ofs[] = { INFRA_RST0 };
static u16 infracfg_rst_idx_map[] = {
[MT6735_INFRA_RST0_EMI_REG] = 0 * RST_NR_PER_BANK + 0,
[MT6735_INFRA_RST0_DRAMC0_AO] = 0 * RST_NR_PER_BANK + 1,
[MT6735_INFRA_RST0_AP_CIRQ_EINT] = 0 * RST_NR_PER_BANK + 3,
[MT6735_INFRA_RST0_APXGPT] = 0 * RST_NR_PER_BANK + 4,
[MT6735_INFRA_RST0_SCPSYS] = 0 * RST_NR_PER_BANK + 5,
[MT6735_INFRA_RST0_KP] = 0 * RST_NR_PER_BANK + 6,
[MT6735_INFRA_RST0_PMIC_WRAP] = 0 * RST_NR_PER_BANK + 7,
[MT6735_INFRA_RST0_CLDMA_AO_TOP] = 0 * RST_NR_PER_BANK + 8,
[MT6735_INFRA_RST0_USBSIF_TOP] = 0 * RST_NR_PER_BANK + 9,
[MT6735_INFRA_RST0_EMI] = 0 * RST_NR_PER_BANK + 16,
[MT6735_INFRA_RST0_CCIF] = 0 * RST_NR_PER_BANK + 17,
[MT6735_INFRA_RST0_DRAMC0] = 0 * RST_NR_PER_BANK + 18,
[MT6735_INFRA_RST0_EMI_AO_REG] = 0 * RST_NR_PER_BANK + 19,
[MT6735_INFRA_RST0_CCIF_AO] = 0 * RST_NR_PER_BANK + 20,
[MT6735_INFRA_RST0_TRNG] = 0 * RST_NR_PER_BANK + 21,
[MT6735_INFRA_RST0_SYS_CIRQ] = 0 * RST_NR_PER_BANK + 22,
[MT6735_INFRA_RST0_GCE] = 0 * RST_NR_PER_BANK + 23,
[MT6735_INFRA_RST0_M4U] = 0 * RST_NR_PER_BANK + 24,
[MT6735_INFRA_RST0_CCIF1] = 0 * RST_NR_PER_BANK + 25,
[MT6735_INFRA_RST0_CLDMA_TOP_PD] = 0 * RST_NR_PER_BANK + 26
};
static const struct mtk_clk_rst_desc infracfg_resets = {
.version = MTK_RST_SIMPLE,
.rst_bank_ofs = infracfg_rst_bank_ofs,
.rst_bank_nr = ARRAY_SIZE(infracfg_rst_bank_ofs),
.rst_idx_map = infracfg_rst_idx_map,
.rst_idx_map_nr = ARRAY_SIZE(infracfg_rst_idx_map)
};
static const struct mtk_clk_desc infracfg_clks = {
.clks = infracfg_gates,
.num_clks = ARRAY_SIZE(infracfg_gates),
.rst_desc = &infracfg_resets
};
static const struct of_device_id of_match_mt6735_infracfg[] = {
{ .compatible = "mediatek,mt6735-infracfg", .data = &infracfg_clks },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_match_mt6735_infracfg);
static struct platform_driver clk_mt6735_infracfg = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt6735-infracfg",
.of_match_table = of_match_mt6735_infracfg,
},
};
module_platform_driver(clk_mt6735_infracfg);
MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
MODULE_DESCRIPTION("MediaTek MT6735 infracfg clock and reset driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,61 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2022 Yassine Oudjana <y.oudjana@protonmail.com>
*/
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include "clk-gate.h"
#include "clk-mtk.h"
#include <dt-bindings/clock/mediatek,mt6735-mfgcfg.h>
#define MFG_CG_CON 0x00
#define MFG_CG_SET 0x04
#define MFG_CG_CLR 0x08
#define MFG_RESET 0x0c
static struct mtk_gate_regs mfgcfg_cg_regs = {
.set_ofs = MFG_CG_SET,
.clr_ofs = MFG_CG_CLR,
.sta_ofs = MFG_CG_CON,
};
static const struct mtk_gate mfgcfg_gates[] = {
GATE_MTK(CLK_MFG_BG3D, "bg3d", "mfg_sel", &mfgcfg_cg_regs, 0, &mtk_clk_gate_ops_setclr),
};
static u16 mfgcfg_rst_ofs[] = { MFG_RESET };
static const struct mtk_clk_rst_desc mfgcfg_resets = {
.version = MTK_RST_SIMPLE,
.rst_bank_ofs = mfgcfg_rst_ofs,
.rst_bank_nr = ARRAY_SIZE(mfgcfg_rst_ofs)
};
static const struct mtk_clk_desc mfgcfg_clks = {
.clks = mfgcfg_gates,
.num_clks = ARRAY_SIZE(mfgcfg_gates),
.rst_desc = &mfgcfg_resets
};
static const struct of_device_id of_match_mt6735_mfgcfg[] = {
{ .compatible = "mediatek,mt6735-mfgcfg", .data = &mfgcfg_clks },
{ /* sentinel */ }
};
static struct platform_driver clk_mt6735_mfgcfg = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt6735-mfgcfg",
.of_match_table = of_match_mt6735_mfgcfg,
},
};
module_platform_driver(clk_mt6735_mfgcfg);
MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
MODULE_DESCRIPTION("Mediatek MT6735 mfgcfg clock and reset driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,124 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2022 Yassine Oudjana <y.oudjana@protonmail.com>
*/
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include "clk-gate.h"
#include "clk-mtk.h"
#include <dt-bindings/clock/mediatek,mt6735-pericfg.h>
#include <dt-bindings/reset/mediatek,mt6735-pericfg.h>
#define PERI_GLOBALCON_RST0 0x00
#define PERI_GLOBALCON_RST1 0x04
#define PERI_GLOBALCON_PDN0_SET 0x08
#define PERI_GLOBALCON_PDN0_CLR 0x10
#define PERI_GLOBALCON_PDN0_STA 0x18
#define RST_NR_PER_BANK 32
static struct mtk_gate_regs peri_cg_regs = {
.set_ofs = PERI_GLOBALCON_PDN0_SET,
.clr_ofs = PERI_GLOBALCON_PDN0_CLR,
.sta_ofs = PERI_GLOBALCON_PDN0_STA,
};
static const struct mtk_gate pericfg_gates[] = {
GATE_MTK(CLK_PERI_DISP_PWM, "disp_pwm", "disppwm_sel", &peri_cg_regs, 0, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_THERM, "therm", "axi_sel", &peri_cg_regs, 1, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_PWM1, "pwm1", "axi_sel", &peri_cg_regs, 2, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_PWM2, "pwm2", "axi_sel", &peri_cg_regs, 3, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_PWM3, "pwm3", "axi_sel", &peri_cg_regs, 4, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_PWM4, "pwm4", "axi_sel", &peri_cg_regs, 5, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_PWM5, "pwm5", "axi_sel", &peri_cg_regs, 6, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_PWM6, "pwm6", "axi_sel", &peri_cg_regs, 7, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_PWM7, "pwm7", "axi_sel", &peri_cg_regs, 8, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_PWM, "pwm", "axi_sel", &peri_cg_regs, 9, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_USB0, "usb0", "usb20_sel", &peri_cg_regs, 10, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_IRDA, "irda", "irda_sel", &peri_cg_regs, 11, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_APDMA, "apdma", "axi_sel", &peri_cg_regs, 12, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_MSDC30_0, "msdc30_0", "msdc30_0_sel", &peri_cg_regs, 13, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_MSDC30_1, "msdc30_1", "msdc30_1_sel", &peri_cg_regs, 14, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_MSDC30_2, "msdc30_2", "msdc30_2_sel", &peri_cg_regs, 15, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_MSDC30_3, "msdc30_3", "msdc30_3_sel", &peri_cg_regs, 16, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_UART0, "uart0", "uart_sel", &peri_cg_regs, 17, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_UART1, "uart1", "uart_sel", &peri_cg_regs, 18, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_UART2, "uart2", "uart_sel", &peri_cg_regs, 19, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_UART3, "uart3", "uart_sel", &peri_cg_regs, 20, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_UART4, "uart4", "uart_sel", &peri_cg_regs, 21, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_BTIF, "btif", "axi_sel", &peri_cg_regs, 22, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_I2C0, "i2c0", "axi_sel", &peri_cg_regs, 23, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_I2C1, "i2c1", "axi_sel", &peri_cg_regs, 24, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_I2C2, "i2c2", "axi_sel", &peri_cg_regs, 25, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_I2C3, "i2c3", "axi_sel", &peri_cg_regs, 26, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_AUXADC, "auxadc", "axi_sel", &peri_cg_regs, 27, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_SPI0, "spi0", "spi_sel", &peri_cg_regs, 28, &mtk_clk_gate_ops_setclr),
GATE_MTK(CLK_PERI_IRTX, "irtx", "irtx_sel", &peri_cg_regs, 29, &mtk_clk_gate_ops_setclr)
};
static u16 pericfg_rst_bank_ofs[] = { PERI_GLOBALCON_RST0, PERI_GLOBALCON_RST1 };
static u16 pericfg_rst_idx_map[] = {
[MT6735_PERI_RST0_UART0] = 0 * RST_NR_PER_BANK + 0,
[MT6735_PERI_RST0_UART1] = 0 * RST_NR_PER_BANK + 1,
[MT6735_PERI_RST0_UART2] = 0 * RST_NR_PER_BANK + 2,
[MT6735_PERI_RST0_UART3] = 0 * RST_NR_PER_BANK + 3,
[MT6735_PERI_RST0_UART4] = 0 * RST_NR_PER_BANK + 4,
[MT6735_PERI_RST0_BTIF] = 0 * RST_NR_PER_BANK + 6,
[MT6735_PERI_RST0_DISP_PWM_PERI] = 0 * RST_NR_PER_BANK + 7,
[MT6735_PERI_RST0_PWM] = 0 * RST_NR_PER_BANK + 8,
[MT6735_PERI_RST0_AUXADC] = 0 * RST_NR_PER_BANK + 10,
[MT6735_PERI_RST0_DMA] = 0 * RST_NR_PER_BANK + 11,
[MT6735_PERI_RST0_IRDA] = 0 * RST_NR_PER_BANK + 12,
[MT6735_PERI_RST0_IRTX] = 0 * RST_NR_PER_BANK + 13,
[MT6735_PERI_RST0_THERM] = 0 * RST_NR_PER_BANK + 16,
[MT6735_PERI_RST0_MSDC2] = 0 * RST_NR_PER_BANK + 17,
[MT6735_PERI_RST0_MSDC3] = 0 * RST_NR_PER_BANK + 18,
[MT6735_PERI_RST0_MSDC0] = 0 * RST_NR_PER_BANK + 19,
[MT6735_PERI_RST0_MSDC1] = 0 * RST_NR_PER_BANK + 20,
[MT6735_PERI_RST0_I2C0] = 0 * RST_NR_PER_BANK + 22,
[MT6735_PERI_RST0_I2C1] = 0 * RST_NR_PER_BANK + 23,
[MT6735_PERI_RST0_I2C2] = 0 * RST_NR_PER_BANK + 24,
[MT6735_PERI_RST0_I2C3] = 0 * RST_NR_PER_BANK + 25,
[MT6735_PERI_RST0_USB] = 0 * RST_NR_PER_BANK + 28,
[MT6735_PERI_RST1_SPI0] = 1 * RST_NR_PER_BANK + 1,
};
static const struct mtk_clk_rst_desc pericfg_resets = {
.version = MTK_RST_SIMPLE,
.rst_bank_ofs = pericfg_rst_bank_ofs,
.rst_bank_nr = ARRAY_SIZE(pericfg_rst_bank_ofs),
.rst_idx_map = pericfg_rst_idx_map,
.rst_idx_map_nr = ARRAY_SIZE(pericfg_rst_idx_map)
};
static const struct mtk_clk_desc pericfg_clks = {
.clks = pericfg_gates,
.num_clks = ARRAY_SIZE(pericfg_gates),
.rst_desc = &pericfg_resets
};
static const struct of_device_id of_match_mt6735_pericfg[] = {
{ .compatible = "mediatek,mt6735-pericfg", .data = &pericfg_clks },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_match_mt6735_pericfg);
static struct platform_driver clk_mt6735_pericfg = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt6735-pericfg",
.of_match_table = of_match_mt6735_pericfg,
},
};
module_platform_driver(clk_mt6735_pericfg);
MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
MODULE_DESCRIPTION("MediaTek MT6735 pericfg clock driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,394 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2022 Yassine Oudjana <y.oudjana@protonmail.com>
*/
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include "clk-mtk.h"
#include "clk-mux.h"
#include <dt-bindings/clock/mediatek,mt6735-topckgen.h>
#define CLK_CFG_0 0x40
#define CLK_CFG_0_SET 0x44
#define CLK_CFG_0_CLR 0x48
#define CLK_CFG_1 0x50
#define CLK_CFG_1_SET 0x54
#define CLK_CFG_1_CLR 0x58
#define CLK_CFG_2 0x60
#define CLK_CFG_2_SET 0x64
#define CLK_CFG_2_CLR 0x68
#define CLK_CFG_3 0x70
#define CLK_CFG_3_SET 0x74
#define CLK_CFG_3_CLR 0x78
#define CLK_CFG_4 0x80
#define CLK_CFG_4_SET 0x84
#define CLK_CFG_4_CLR 0x88
#define CLK_CFG_5 0x90
#define CLK_CFG_5_SET 0x94
#define CLK_CFG_5_CLR 0x98
#define CLK_CFG_6 0xa0
#define CLK_CFG_6_SET 0xa4
#define CLK_CFG_6_CLR 0xa8
#define CLK_CFG_7 0xb0
#define CLK_CFG_7_SET 0xb4
#define CLK_CFG_7_CLR 0xb8
static DEFINE_SPINLOCK(mt6735_topckgen_lock);
/* Some clocks with unknown details are modeled as fixed clocks */
static const struct mtk_fixed_clk topckgen_fixed_clks[] = {
/*
* This clock is available as a parent option for multiple
* muxes and seems like an alternative name for clk26m at first,
* but it appears alongside it in several muxes which should
* mean it is a separate clock.
*/
FIXED_CLK(CLK_TOP_AD_SYS_26M_CK, "ad_sys_26m_ck", "clk26m", 26 * MHZ),
/*
* This clock is the parent of DMPLL divisors. It might be MEMPLL
* or its parent, as DMPLL appears to be an alternative name for
* MEMPLL.
*/
FIXED_CLK(CLK_TOP_CLKPH_MCK_O, "clkph_mck_o", NULL, 0),
/*
* DMPLL clock (dmpll_ck), controlled by DDRPHY.
*/
FIXED_CLK(CLK_TOP_DMPLL, "dmpll", "clkph_mck_o", 0),
/*
* MIPI DPI clock. Parent option for dpi0_sel. Unknown parent.
*/
FIXED_CLK(CLK_TOP_DPI_CK, "dpi_ck", NULL, 0),
/*
* This clock is a child of WHPLL which is controlled by
* the modem.
*/
FIXED_CLK(CLK_TOP_WHPLL_AUDIO_CK, "whpll_audio_ck", NULL, 0)
};
static const struct mtk_fixed_factor topckgen_factors[] = {
FACTOR(CLK_TOP_SYSPLL_D2, "syspll_d2", "mainpll", 1, 2),
FACTOR(CLK_TOP_SYSPLL_D3, "syspll_d3", "mainpll", 1, 3),
FACTOR(CLK_TOP_SYSPLL_D5, "syspll_d5", "mainpll", 1, 5),
FACTOR(CLK_TOP_SYSPLL1_D2, "syspll1_d2", "mainpll", 1, 2),
FACTOR(CLK_TOP_SYSPLL1_D4, "syspll1_d4", "mainpll", 1, 4),
FACTOR(CLK_TOP_SYSPLL1_D8, "syspll1_d8", "mainpll", 1, 8),
FACTOR(CLK_TOP_SYSPLL1_D16, "syspll1_d16", "mainpll", 1, 16),
FACTOR(CLK_TOP_SYSPLL2_D2, "syspll2_d2", "mainpll", 1, 2),
FACTOR(CLK_TOP_SYSPLL2_D4, "syspll2_d4", "mainpll", 1, 4),
FACTOR(CLK_TOP_SYSPLL3_D2, "syspll3_d2", "mainpll", 1, 2),
FACTOR(CLK_TOP_SYSPLL3_D4, "syspll3_d4", "mainpll", 1, 4),
FACTOR(CLK_TOP_SYSPLL4_D2, "syspll4_d2", "mainpll", 1, 2),
FACTOR(CLK_TOP_SYSPLL4_D4, "syspll4_d4", "mainpll", 1, 4),
FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univpll", 1, 2),
FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univpll", 1, 3),
FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll", 1, 5),
FACTOR(CLK_TOP_UNIVPLL_D26, "univpll_d26", "univpll", 1, 26),
FACTOR(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univpll", 1, 2),
FACTOR(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univpll", 1, 4),
FACTOR(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univpll", 1, 8),
FACTOR(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univpll", 1, 2),
FACTOR(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univpll", 1, 4),
FACTOR(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univpll", 1, 8),
FACTOR(CLK_TOP_UNIVPLL3_D2, "univpll3_d2", "univpll", 1, 2),
FACTOR(CLK_TOP_UNIVPLL3_D4, "univpll3_d4", "univpll", 1, 4),
FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll", 1, 2),
FACTOR(CLK_TOP_MSDCPLL_D4, "msdcpll_d4", "msdcpll", 1, 4),
FACTOR(CLK_TOP_MSDCPLL_D8, "msdcpll_d8", "msdcpll", 1, 8),
FACTOR(CLK_TOP_MSDCPLL_D16, "msdcpll_d16", "msdcpll", 1, 16),
FACTOR(CLK_TOP_VENCPLL_D3, "vencpll_d3", "vencpll", 1, 3),
FACTOR(CLK_TOP_TVDPLL_D2, "tvdpll_d2", "tvdpll", 1, 2),
FACTOR(CLK_TOP_TVDPLL_D4, "tvdpll_d4", "tvdpll", 1, 4),
FACTOR(CLK_TOP_DMPLL_D2, "dmpll_d2", "clkph_mck_o", 1, 2),
FACTOR(CLK_TOP_DMPLL_D4, "dmpll_d4", "clkph_mck_o", 1, 4),
FACTOR(CLK_TOP_DMPLL_D8, "dmpll_d8", "clkph_mck_o", 1, 8),
FACTOR(CLK_TOP_AD_SYS_26M_D2, "ad_sys_26m_d2", "clk26m", 1, 2)
};
static const char * const axi_sel_parents[] = {
"clk26m",
"syspll1_d2",
"syspll_d5",
"syspll1_d4",
"univpll_d5",
"univpll2_d2",
"dmpll",
"dmpll_d2"
};
static const char * const mem_sel_parents[] = {
"clk26m",
"dmpll"
};
static const char * const ddrphycfg_parents[] = {
"clk26m",
"syspll1_d8"
};
static const char * const mm_sel_parents[] = {
"clk26m",
"vencpll",
"syspll1_d2",
"syspll_d5",
"syspll1_d4",
"univpll_d5",
"univpll2_d2",
"dmpll"
};
static const char * const pwm_sel_parents[] = {
"clk26m",
"univpll2_d4",
"univpll3_d2",
"univpll1_d4"
};
static const char * const vdec_sel_parents[] = {
"clk26m",
"syspll1_d2",
"syspll_d5",
"syspll1_d4",
"univpll_d5",
"syspll_d2",
"syspll2_d2",
"msdcpll_d2"
};
static const char * const mfg_sel_parents[] = {
"clk26m",
"mmpll",
"clk26m",
"clk26m",
"clk26m",
"clk26m",
"clk26m",
"clk26m",
"clk26m",
"syspll_d3",
"syspll1_d2",
"syspll_d5",
"univpll_d3",
"univpll1_d2"
};
static const char * const camtg_sel_parents[] = {
"clk26m",
"univpll_d26",
"univpll2_d2",
"syspll3_d2",
"syspll3_d4",
"msdcpll_d4"
};
static const char * const uart_sel_parents[] = {
"clk26m",
"univpll2_d8"
};
static const char * const spi_sel_parents[] = {
"clk26m",
"syspll3_d2",
"msdcpll_d8",
"syspll2_d4",
"syspll4_d2",
"univpll2_d4",
"univpll1_d8"
};
static const char * const usb20_sel_parents[] = {
"clk26m",
"univpll1_d8",
"univpll3_d4"
};
static const char * const msdc50_0_sel_parents[] = {
"clk26m",
"syspll1_d2",
"syspll2_d2",
"syspll4_d2",
"univpll_d5",
"univpll1_d4"
};
static const char * const msdc30_0_sel_parents[] = {
"clk26m",
"msdcpll",
"msdcpll_d2",
"msdcpll_d4",
"syspll2_d2",
"syspll1_d4",
"univpll1_d4",
"univpll_d3",
"univpll_d26",
"syspll2_d4",
"univpll_d2"
};
static const char * const msdc30_1_2_sel_parents[] = {
"clk26m",
"univpll2_d2",
"msdcpll_d4",
"syspll2_d2",
"syspll1_d4",
"univpll1_d4",
"univpll_d26",
"syspll2_d4"
};
static const char * const msdc30_3_sel_parents[] = {
"clk26m",
"univpll2_d2",
"msdcpll_d4",
"syspll2_d2",
"syspll1_d4",
"univpll1_d4",
"univpll_d26",
"msdcpll_d16",
"syspll2_d4"
};
static const char * const audio_sel_parents[] = {
"clk26m",
"syspll3_d4",
"syspll4_d4",
"syspll1_d16"
};
static const char * const aud_intbus_sel_parents[] = {
"clk26m",
"syspll1_d4",
"syspll4_d2",
"dmpll_d4"
};
static const char * const pmicspi_sel_parents[] = {
"clk26m",
"syspll1_d8",
"syspll3_d4",
"syspll1_d16",
"univpll3_d4",
"univpll_d26",
"dmpll_d4",
"dmpll_d8"
};
static const char * const scp_sel_parents[] = {
"clk26m",
"syspll1_d8",
"dmpll_d2",
"dmpll_d4"
};
static const char * const atb_sel_parents[] = {
"clk26m",
"syspll1_d2",
"syspll_d5",
"dmpll"
};
static const char * const dpi0_sel_parents[] = {
"clk26m",
"tvdpll",
"tvdpll_d2",
"tvdpll_d4",
"dpi_ck"
};
static const char * const scam_sel_parents[] = {
"clk26m",
"syspll3_d2",
"univpll2_d4",
"vencpll_d3"
};
static const char * const mfg13m_sel_parents[] = {
"clk26m",
"ad_sys_26m_d2"
};
static const char * const aud_1_2_sel_parents[] = {
"clk26m",
"apll1"
};
static const char * const irda_sel_parents[] = {
"clk26m",
"univpll2_d4"
};
static const char * const irtx_sel_parents[] = {
"clk26m",
"ad_sys_26m_ck"
};
static const char * const disppwm_sel_parents[] = {
"clk26m",
"univpll2_d4",
"syspll4_d2_d8",
"ad_sys_26m_ck"
};
static const struct mtk_mux topckgen_muxes[] = {
MUX_CLR_SET_UPD(CLK_TOP_AXI_SEL, "axi_sel", axi_sel_parents, CLK_CFG_0, CLK_CFG_0_SET, CLK_CFG_0_CLR, 0, 3, 0, 0),
MUX_CLR_SET_UPD(CLK_TOP_MEM_SEL, "mem_sel", mem_sel_parents, CLK_CFG_0, CLK_CFG_0_SET, CLK_CFG_0_CLR, 8, 1, 0, 0),
MUX_CLR_SET_UPD(CLK_TOP_DDRPHY_SEL, "ddrphycfg_sel", ddrphycfg_parents, CLK_CFG_0, CLK_CFG_0_SET, CLK_CFG_0_CLR, 16, 1, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_MM_SEL, "mm_sel", mm_sel_parents, CLK_CFG_0, CLK_CFG_0_SET, CLK_CFG_0_CLR, 24, 3, 31, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_PWM_SEL, "pwm_sel", pwm_sel_parents, CLK_CFG_1, CLK_CFG_1_SET, CLK_CFG_1_CLR, 0, 2, 7, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_VDEC_SEL, "vdec_sel", vdec_sel_parents, CLK_CFG_1, CLK_CFG_1_SET, CLK_CFG_1_CLR, 8, 3, 15, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_MFG_SEL, "mfg_sel", mfg_sel_parents, CLK_CFG_1, CLK_CFG_1_SET, CLK_CFG_1_CLR, 16, 4, 23, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_CAMTG_SEL, "camtg_sel", camtg_sel_parents, CLK_CFG_1, CLK_CFG_1_SET, CLK_CFG_1_CLR, 24, 3, 31, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_UART_SEL, "uart_sel", uart_sel_parents, CLK_CFG_2, CLK_CFG_2_SET, CLK_CFG_2_CLR, 0, 1, 7, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI_SEL, "spi_sel", spi_sel_parents, CLK_CFG_2, CLK_CFG_2_SET, CLK_CFG_2_CLR, 8, 3, 15, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_USB20_SEL, "usb20_sel", usb20_sel_parents, CLK_CFG_2, CLK_CFG_2_SET, CLK_CFG_2_CLR, 16, 2, 23, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC50_0_SEL, "msdc50_0_sel", msdc50_0_sel_parents, CLK_CFG_2, CLK_CFG_2_SET, CLK_CFG_2_CLR, 24, 3, 31, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_0_SEL, "msdc30_0_sel", msdc30_0_sel_parents, CLK_CFG_3, CLK_CFG_3_SET, CLK_CFG_3_CLR, 0, 4, 7, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", msdc30_1_2_sel_parents, CLK_CFG_3, CLK_CFG_3_SET, CLK_CFG_3_CLR, 8, 3, 15, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel", msdc30_1_2_sel_parents, CLK_CFG_3, CLK_CFG_3_SET, CLK_CFG_3_CLR, 16, 3, 23, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_3_SEL, "msdc30_3_sel", msdc30_3_sel_parents, CLK_CFG_3, CLK_CFG_3_SET, CLK_CFG_3_CLR, 24, 4, 31, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_AUDIO_SEL, "audio_sel", audio_sel_parents, CLK_CFG_4, CLK_CFG_4_SET, CLK_CFG_4_CLR, 0, 2, 7, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_AUDINTBUS_SEL, "aud_intbus_sel", aud_intbus_sel_parents, CLK_CFG_4, CLK_CFG_4_SET, CLK_CFG_4_CLR, 8, 2, 15, 0, 0),
MUX_CLR_SET_UPD(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", pmicspi_sel_parents, CLK_CFG_4, CLK_CFG_4_SET, CLK_CFG_4_CLR, 16, 3, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_SCP_SEL, "scp_sel", scp_sel_parents, CLK_CFG_4, CLK_CFG_4_SET, CLK_CFG_4_CLR, 24, 2, 31, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_ATB_SEL, "atb_sel", atb_sel_parents, CLK_CFG_5, CLK_CFG_5_SET, CLK_CFG_5_CLR, 0, 2, 7, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_DPI0_SEL, "dpi0_sel", dpi0_sel_parents, CLK_CFG_5, CLK_CFG_5_SET, CLK_CFG_5_CLR, 8, 3, 15, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_SCAM_SEL, "scam_sel", scam_sel_parents, CLK_CFG_5, CLK_CFG_5_SET, CLK_CFG_5_CLR, 16, 2, 23, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_MFG13M_SEL, "mfg13m_sel", mfg13m_sel_parents, CLK_CFG_5, CLK_CFG_5_SET, CLK_CFG_5_CLR, 24, 1, 31, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD1_SEL, "aud_1_sel", aud_1_2_sel_parents, CLK_CFG_6, CLK_CFG_6_SET, CLK_CFG_6_CLR, 0, 1, 7, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD2_SEL, "aud_2_sel", aud_1_2_sel_parents, CLK_CFG_6, CLK_CFG_6_SET, CLK_CFG_6_CLR, 8, 1, 15, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_IRDA_SEL, "irda_sel", irda_sel_parents, CLK_CFG_6, CLK_CFG_6_SET, CLK_CFG_6_CLR, 16, 1, 23, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_IRTX_SEL, "irtx_sel", irtx_sel_parents, CLK_CFG_6, CLK_CFG_6_SET, CLK_CFG_6_CLR, 24, 1, 31, 0, 0),
MUX_GATE_CLR_SET_UPD(CLK_TOP_DISPPWM_SEL, "disppwm_sel", disppwm_sel_parents, CLK_CFG_7, CLK_CFG_7_SET, CLK_CFG_7_CLR, 0, 2, 7, 0, 0),
};
static const struct mtk_clk_desc topckgen_desc = {
.fixed_clks = topckgen_fixed_clks,
.num_fixed_clks = ARRAY_SIZE(topckgen_fixed_clks),
.factor_clks = topckgen_factors,
.num_factor_clks = ARRAY_SIZE(topckgen_factors),
.mux_clks = topckgen_muxes,
.num_mux_clks = ARRAY_SIZE(topckgen_muxes),
.clk_lock = &mt6735_topckgen_lock,
};
static const struct of_device_id of_match_mt6735_topckgen[] = {
{ .compatible = "mediatek,mt6735-topckgen", .data = &topckgen_desc},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_match_mt6735_topckgen);
static struct platform_driver clk_mt6735_topckgen = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt6735-topckgen",
.of_match_table = of_match_mt6735_topckgen,
},
};
module_platform_driver(clk_mt6735_topckgen);
MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
MODULE_DESCRIPTION("MediaTek MT6735 topckgen clock driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,79 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2022 Yassine Oudjana <y.oudjana@protonmail.com>
*/
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include "clk-gate.h"
#include "clk-mtk.h"
#include <dt-bindings/clock/mediatek,mt6735-vdecsys.h>
#include <dt-bindings/reset/mediatek,mt6735-vdecsys.h>
#define VDEC_CKEN_SET 0x00
#define VDEC_CKEN_CLR 0x04
#define SMI_LARB1_CKEN_SET 0x08
#define SMI_LARB1_CKEN_CLR 0x0c
#define VDEC_RESETB_CON 0x10
#define SMI_LARB1_RESETB_CON 0x14
#define RST_NR_PER_BANK 32
static struct mtk_gate_regs vdec_cg_regs = {
.set_ofs = VDEC_CKEN_SET,
.clr_ofs = VDEC_CKEN_CLR,
.sta_ofs = VDEC_CKEN_SET,
};
static struct mtk_gate_regs smi_larb1_cg_regs = {
.set_ofs = SMI_LARB1_CKEN_SET,
.clr_ofs = SMI_LARB1_CKEN_CLR,
.sta_ofs = SMI_LARB1_CKEN_SET,
};
static const struct mtk_gate vdecsys_gates[] = {
GATE_MTK(CLK_VDEC_VDEC, "vdec", "vdec_sel", &vdec_cg_regs, 0, &mtk_clk_gate_ops_setclr_inv),
GATE_MTK(CLK_VDEC_SMI_LARB1, "smi_larb1", "vdec_sel", &smi_larb1_cg_regs, 0, &mtk_clk_gate_ops_setclr_inv),
};
static u16 vdecsys_rst_bank_ofs[] = { VDEC_RESETB_CON, SMI_LARB1_RESETB_CON };
static u16 vdecsys_rst_idx_map[] = {
[MT6735_VDEC_RST0_VDEC] = 0 * RST_NR_PER_BANK + 0,
[MT6735_VDEC_RST1_SMI_LARB1] = 1 * RST_NR_PER_BANK + 0,
};
static const struct mtk_clk_rst_desc vdecsys_resets = {
.version = MTK_RST_SIMPLE,
.rst_bank_ofs = vdecsys_rst_bank_ofs,
.rst_bank_nr = ARRAY_SIZE(vdecsys_rst_bank_ofs),
.rst_idx_map = vdecsys_rst_idx_map,
.rst_idx_map_nr = ARRAY_SIZE(vdecsys_rst_idx_map)
};
static const struct mtk_clk_desc vdecsys_clks = {
.clks = vdecsys_gates,
.num_clks = ARRAY_SIZE(vdecsys_gates),
.rst_desc = &vdecsys_resets
};
static const struct of_device_id of_match_mt6735_vdecsys[] = {
{ .compatible = "mediatek,mt6735-vdecsys", .data = &vdecsys_clks },
{ /* sentinel */ }
};
static struct platform_driver clk_mt6735_vdecsys = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt6735-vdecsys",
.of_match_table = of_match_mt6735_vdecsys,
},
};
module_platform_driver(clk_mt6735_vdecsys);
MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
MODULE_DESCRIPTION("MediaTek MT6735 vdecsys clock and reset driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,53 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2022 Yassine Oudjana <y.oudjana@protonmail.com>
*/
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include "clk-gate.h"
#include "clk-mtk.h"
#include <dt-bindings/clock/mediatek,mt6735-vencsys.h>
#define VENC_CG_CON 0x00
#define VENC_CG_SET 0x04
#define VENC_CG_CLR 0x08
static struct mtk_gate_regs venc_cg_regs = {
.set_ofs = VENC_CG_SET,
.clr_ofs = VENC_CG_CLR,
.sta_ofs = VENC_CG_CON,
};
static const struct mtk_gate vencsys_gates[] = {
GATE_MTK(CLK_VENC_SMI_LARB3, "smi_larb3", "mm_sel", &venc_cg_regs, 0, &mtk_clk_gate_ops_setclr_inv),
GATE_MTK(CLK_VENC_VENC, "venc", "mm_sel", &venc_cg_regs, 4, &mtk_clk_gate_ops_setclr_inv),
GATE_MTK(CLK_VENC_JPGENC, "jpgenc", "mm_sel", &venc_cg_regs, 8, &mtk_clk_gate_ops_setclr_inv),
GATE_MTK(CLK_VENC_JPGDEC, "jpgdec", "mm_sel", &venc_cg_regs, 12, &mtk_clk_gate_ops_setclr_inv),
};
static const struct mtk_clk_desc vencsys_clks = {
.clks = vencsys_gates,
.num_clks = ARRAY_SIZE(vencsys_gates),
};
static const struct of_device_id of_match_mt6735_vencsys[] = {
{ .compatible = "mediatek,mt6735-vencsys", .data = &vencsys_clks },
{ /* sentinel */ }
};
static struct platform_driver clk_mt6735_vencsys = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt6735-vencsys",
.of_match_table = of_match_mt6735_vencsys,
},
};
module_platform_driver(clk_mt6735_vencsys);
MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
MODULE_DESCRIPTION("Mediatek MT6735 vencsys clock driver");
MODULE_LICENSE("GPL");

View File

@ -342,11 +342,14 @@ static const char * const dsp7_parents[] = {
"univpll_d3"
};
/*
* MFG can be also parented to "univpll_d6" and "univpll_d7":
* these have been removed from the parents list to let us
* achieve GPU DVFS without any special clock handlers.
*/
static const char * const mfg_core_tmp_parents[] = {
"clk26m",
"mainpll_d5_d2",
"univpll_d6",
"univpll_d7"
"mainpll_d5_d2"
};
static const char * const camtg_parents[] = {

View File

@ -106,6 +106,7 @@ config COMMON_CLK_AXG_AUDIO
select COMMON_CLK_MESON_SCLK_DIV
select COMMON_CLK_MESON_CLKC_UTILS
select REGMAP_MMIO
depends on RESET_MESON_AUX
help
Support for the audio clock controller on AmLogic A113D devices,
aka axg, Say Y if you want audio subsystem to work.

View File

@ -15,6 +15,8 @@
#include <linux/reset-controller.h>
#include <linux/slab.h>
#include <soc/amlogic/reset-meson-aux.h>
#include "meson-clkc-utils.h"
#include "axg-audio.h"
#include "clk-regmap.h"
@ -1678,84 +1680,6 @@ static struct clk_regmap *const sm1_clk_regmaps[] = {
&sm1_earcrx_dmac_clk,
};
struct axg_audio_reset_data {
struct reset_controller_dev rstc;
struct regmap *map;
unsigned int offset;
};
static void axg_audio_reset_reg_and_bit(struct axg_audio_reset_data *rst,
unsigned long id,
unsigned int *reg,
unsigned int *bit)
{
unsigned int stride = regmap_get_reg_stride(rst->map);
*reg = (id / (stride * BITS_PER_BYTE)) * stride;
*reg += rst->offset;
*bit = id % (stride * BITS_PER_BYTE);
}
static int axg_audio_reset_update(struct reset_controller_dev *rcdev,
unsigned long id, bool assert)
{
struct axg_audio_reset_data *rst =
container_of(rcdev, struct axg_audio_reset_data, rstc);
unsigned int offset, bit;
axg_audio_reset_reg_and_bit(rst, id, &offset, &bit);
regmap_update_bits(rst->map, offset, BIT(bit),
assert ? BIT(bit) : 0);
return 0;
}
static int axg_audio_reset_status(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct axg_audio_reset_data *rst =
container_of(rcdev, struct axg_audio_reset_data, rstc);
unsigned int val, offset, bit;
axg_audio_reset_reg_and_bit(rst, id, &offset, &bit);
regmap_read(rst->map, offset, &val);
return !!(val & BIT(bit));
}
static int axg_audio_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
return axg_audio_reset_update(rcdev, id, true);
}
static int axg_audio_reset_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
return axg_audio_reset_update(rcdev, id, false);
}
static int axg_audio_reset_toggle(struct reset_controller_dev *rcdev,
unsigned long id)
{
int ret;
ret = axg_audio_reset_assert(rcdev, id);
if (ret)
return ret;
return axg_audio_reset_deassert(rcdev, id);
}
static const struct reset_control_ops axg_audio_rstc_ops = {
.assert = axg_audio_reset_assert,
.deassert = axg_audio_reset_deassert,
.reset = axg_audio_reset_toggle,
.status = axg_audio_reset_status,
};
static struct regmap_config axg_audio_regmap_cfg = {
.reg_bits = 32,
.val_bits = 32,
@ -1766,16 +1690,14 @@ struct audioclk_data {
struct clk_regmap *const *regmap_clks;
unsigned int regmap_clk_num;
struct meson_clk_hw_data hw_clks;
unsigned int reset_offset;
unsigned int reset_num;
unsigned int max_register;
const char *rst_drvname;
};
static int axg_audio_clkc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct audioclk_data *data;
struct axg_audio_reset_data *rst;
struct regmap *map;
void __iomem *regs;
struct clk_hw *hw;
@ -1834,22 +1756,11 @@ static int axg_audio_clkc_probe(struct platform_device *pdev)
if (ret)
return ret;
/* Stop here if there is no reset */
if (!data->reset_num)
return 0;
/* Register auxiliary reset driver when applicable */
if (data->rst_drvname)
ret = devm_meson_rst_aux_register(dev, map, data->rst_drvname);
rst = devm_kzalloc(dev, sizeof(*rst), GFP_KERNEL);
if (!rst)
return -ENOMEM;
rst->map = map;
rst->offset = data->reset_offset;
rst->rstc.nr_resets = data->reset_num;
rst->rstc.ops = &axg_audio_rstc_ops;
rst->rstc.of_node = dev->of_node;
rst->rstc.owner = THIS_MODULE;
return devm_reset_controller_register(dev, &rst->rstc);
return ret;
}
static const struct audioclk_data axg_audioclk_data = {
@ -1869,9 +1780,8 @@ static const struct audioclk_data g12a_audioclk_data = {
.hws = g12a_audio_hw_clks,
.num = ARRAY_SIZE(g12a_audio_hw_clks),
},
.reset_offset = AUDIO_SW_RESET,
.reset_num = 26,
.max_register = AUDIO_CLK_SPDIFOUT_B_CTRL,
.rst_drvname = "rst-g12a",
};
static const struct audioclk_data sm1_audioclk_data = {
@ -1881,9 +1791,8 @@ static const struct audioclk_data sm1_audioclk_data = {
.hws = sm1_audio_hw_clks,
.num = ARRAY_SIZE(sm1_audio_hw_clks),
},
.reset_offset = AUDIO_SM1_SW_RESET0,
.reset_num = 39,
.max_register = AUDIO_EARCRX_DMAC_CLK_CTRL,
.rst_drvname = "rst-sm1",
};
static const struct of_device_id clkc_match_table[] = {

View File

@ -23,8 +23,6 @@
#include <dt-bindings/clock/axg-clkc.h>
static DEFINE_SPINLOCK(meson_clk_lock);
static struct clk_regmap axg_fixed_pll_dco = {
.data = &(struct meson_clk_pll_data){
.en = {
@ -506,7 +504,6 @@ static struct clk_regmap axg_mpll0_div = {
.shift = 0,
.width = 1,
},
.lock = &meson_clk_lock,
.flags = CLK_MESON_MPLL_ROUND_CLOSEST,
},
.hw.init = &(struct clk_init_data){
@ -557,7 +554,6 @@ static struct clk_regmap axg_mpll1_div = {
.shift = 1,
.width = 1,
},
.lock = &meson_clk_lock,
.flags = CLK_MESON_MPLL_ROUND_CLOSEST,
},
.hw.init = &(struct clk_init_data){
@ -613,7 +609,6 @@ static struct clk_regmap axg_mpll2_div = {
.shift = 2,
.width = 1,
},
.lock = &meson_clk_lock,
.flags = CLK_MESON_MPLL_ROUND_CLOSEST,
},
.hw.init = &(struct clk_init_data){
@ -664,7 +659,6 @@ static struct clk_regmap axg_mpll3_div = {
.shift = 3,
.width = 1,
},
.lock = &meson_clk_lock,
.flags = CLK_MESON_MPLL_ROUND_CLOSEST,
},
.hw.init = &(struct clk_init_data){

View File

@ -361,6 +361,7 @@ static struct clk_regmap hifi_pll_dco = {
.range = &c3_gp0_pll_mult_range,
.init_regs = c3_hifi_init_regs,
.init_count = ARRAY_SIZE(c3_hifi_init_regs),
.frac_max = 100000,
},
.hw.init = &(struct clk_init_data) {
.name = "hifi_pll_dco",

View File

@ -112,26 +112,15 @@ static int mpll_set_rate(struct clk_hw *hw,
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
unsigned int sdm, n2;
unsigned long flags = 0;
params_from_rate(rate, parent_rate, &sdm, &n2, mpll->flags);
if (mpll->lock)
spin_lock_irqsave(mpll->lock, flags);
else
__acquire(mpll->lock);
/* Set the fractional part */
meson_parm_write(clk->map, &mpll->sdm, sdm);
/* Set the integer divider part */
meson_parm_write(clk->map, &mpll->n2, n2);
if (mpll->lock)
spin_unlock_irqrestore(mpll->lock, flags);
else
__release(mpll->lock);
return 0;
}

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