mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 10:58:48 +09:00
Merge 9512433987 ("Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux") into android-mainline
Steps on the way to 5.18-rc1 Resolves conflicts in: drivers/clk/clk.c Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: If598f86de1255b718285149b3128cefc693606e1
This commit is contained in:
@@ -86,6 +86,7 @@ This binding uses the common clock binding[1].
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of:
|
||||
"fsl,imx8dxl-clk"
|
||||
"fsl,imx8qm-clk"
|
||||
"fsl,imx8qxp-clk"
|
||||
followed by "fsl,scu-clk"
|
||||
|
||||
62
Documentation/devicetree/bindings/clock/apple,nco.yaml
Normal file
62
Documentation/devicetree/bindings/clock/apple,nco.yaml
Normal file
@@ -0,0 +1,62 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/apple,nco.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Apple SoCs' NCO block
|
||||
|
||||
maintainers:
|
||||
- Martin Povišer <povik+lin@cutebit.org>
|
||||
|
||||
description: |
|
||||
The NCO (Numerically Controlled Oscillator) block found on Apple SoCs
|
||||
such as the t8103 (M1) is a programmable clock generator performing
|
||||
fractional division of a high frequency input clock.
|
||||
|
||||
It carries a number of independent channels and is typically used for
|
||||
generation of audio bitclocks.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- apple,t6000-nco
|
||||
- apple,t8103-nco
|
||||
- const: apple,nco
|
||||
|
||||
clocks:
|
||||
description:
|
||||
Specifies the reference clock from which the output clocks
|
||||
are derived through fractional division.
|
||||
maxItems: 1
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- '#clock-cells'
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
nco_clkref: clock-ref {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <900000000>;
|
||||
clock-output-names = "nco-ref";
|
||||
};
|
||||
|
||||
nco: clock-controller@23b044000 {
|
||||
compatible = "apple,t8103-nco", "apple,nco";
|
||||
reg = <0x3b044000 0x14000>;
|
||||
#clock-cells = <1>;
|
||||
clocks = <&nco_clkref>;
|
||||
};
|
||||
@@ -61,16 +61,4 @@ examples:
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
# Example UART controller node that consumes clock generated by the clock controller:
|
||||
- |
|
||||
uart0: serial@58018000 {
|
||||
compatible = "snps,dw-apb-uart";
|
||||
reg = <0x58018000 0x2000>;
|
||||
clocks = <&clk 45>, <&clk 46>;
|
||||
clock-names = "baudclk", "apb_pclk";
|
||||
interrupts = <0 9 4>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <4>;
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/cirrus,cs2000-cp.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Binding CIRRUS LOGIC Fractional-N Clock Synthesizer & Clock Multiplier
|
||||
|
||||
maintainers:
|
||||
- Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
|
||||
description: |
|
||||
The CS2000-CP is an extremely versatile system clocking device that
|
||||
utilizes a programmable phase lock loop.
|
||||
|
||||
Link: https://www.cirrus.com/products/cs2000/
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- cirrus,cs2000-cp
|
||||
|
||||
clocks:
|
||||
description:
|
||||
Common clock binding for CLK_IN, XTI/REF_CLK
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: clk_in
|
||||
- const: ref_clk
|
||||
|
||||
'#clock-cells':
|
||||
const: 0
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
cirrus,aux-output-source:
|
||||
description:
|
||||
Specifies the function of the auxiliary clock output pin
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum:
|
||||
- 0 # CS2000CP_AUX_OUTPUT_REF_CLK: ref_clk input
|
||||
- 1 # CS2000CP_AUX_OUTPUT_CLK_IN: clk_in input
|
||||
- 2 # CS2000CP_AUX_OUTPUT_CLK_OUT: clk_out output
|
||||
- 3 # CS2000CP_AUX_OUTPUT_PLL_LOCK: pll lock status
|
||||
default: 0
|
||||
|
||||
cirrus,clock-skip:
|
||||
description:
|
||||
This mode allows the PLL to maintain lock even when CLK_IN
|
||||
has missing pulses for up to 20 ms.
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
|
||||
cirrus,dynamic-mode:
|
||||
description:
|
||||
In dynamic mode, the CLK_IN input is used to drive the
|
||||
digital PLL of the silicon.
|
||||
If not given, the static mode shall be used to derive the
|
||||
output signal directly from the REF_CLK input.
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#clock-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/cirrus,cs2000-cp.h>
|
||||
|
||||
i2c@0 {
|
||||
reg = <0x0 0x100>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clock-controller@4f {
|
||||
#clock-cells = <0>;
|
||||
compatible = "cirrus,cs2000-cp";
|
||||
reg = <0x4f>;
|
||||
clocks = <&rcar_sound 0>, <&x12_clk>;
|
||||
clock-names = "clk_in", "ref_clk";
|
||||
cirrus,aux-output-source = <CS2000CP_AUX_OUTPUT_CLK_OUT>;
|
||||
};
|
||||
};
|
||||
@@ -1,22 +0,0 @@
|
||||
CIRRUS LOGIC Fractional-N Clock Synthesizer & Clock Multiplier
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: "cirrus,cs2000-cp"
|
||||
- reg: The chip select number on the I2C bus
|
||||
- clocks: common clock binding for CLK_IN, XTI/REF_CLK
|
||||
- clock-names: CLK_IN : clk_in, XTI/REF_CLK : ref_clk
|
||||
- #clock-cells: must be <0>
|
||||
|
||||
Example:
|
||||
|
||||
&i2c2 {
|
||||
...
|
||||
cs2000: clk_multiplier@4f {
|
||||
#clock-cells = <0>;
|
||||
compatible = "cirrus,cs2000-cp";
|
||||
reg = <0x4f>;
|
||||
clocks = <&rcar_sound 0>, <&x12_clk>;
|
||||
clock-names = "clk_in", "ref_clk";
|
||||
};
|
||||
};
|
||||
@@ -191,11 +191,4 @@ examples:
|
||||
};
|
||||
};
|
||||
|
||||
/* Consumer referencing the 5P49V5923 pin OUT1 */
|
||||
consumer {
|
||||
/* ... */
|
||||
clocks = <&vc5 1>;
|
||||
/* ... */
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
@@ -40,12 +40,3 @@ examples:
|
||||
compatible = "fsl,imx1-ccm";
|
||||
reg = <0x0021b000 0x1000>;
|
||||
};
|
||||
|
||||
pwm@208000 {
|
||||
#pwm-cells = <2>;
|
||||
compatible = "fsl,imx1-pwm";
|
||||
reg = <0x00208000 0x1000>;
|
||||
interrupts = <34>;
|
||||
clocks = <&clks IMX1_CLK_DUMMY>, <&clks IMX1_CLK_PER1>;
|
||||
clock-names = "ipg", "per";
|
||||
};
|
||||
|
||||
@@ -40,12 +40,3 @@ examples:
|
||||
reg = <0x10027000 0x800>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
serial@1000a000 {
|
||||
compatible = "fsl,imx21-uart";
|
||||
reg = <0x1000a000 0x1000>;
|
||||
interrupts = <20>;
|
||||
clocks = <&clks IMX21_CLK_UART1_IPG_GATE>,
|
||||
<&clks IMX21_CLK_PER1>;
|
||||
clock-names = "ipg", "per";
|
||||
};
|
||||
|
||||
@@ -83,12 +83,3 @@ examples:
|
||||
reg = <0x80040000 0x2000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
serial@8006c000 {
|
||||
compatible = "fsl,imx23-auart";
|
||||
reg = <0x8006c000 0x2000>;
|
||||
interrupts = <24>;
|
||||
clocks = <&clks 32>;
|
||||
dmas = <&dma_apbx 6>, <&dma_apbx 7>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
@@ -176,11 +176,3 @@ examples:
|
||||
interrupts = <31>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
serial@43f90000 {
|
||||
compatible = "fsl,imx25-uart", "fsl,imx21-uart";
|
||||
reg = <0x43f90000 0x4000>;
|
||||
interrupts = <45>;
|
||||
clocks = <&clks 79>, <&clks 50>;
|
||||
clock-names = "ipg", "per";
|
||||
};
|
||||
|
||||
@@ -44,12 +44,3 @@ examples:
|
||||
interrupts = <31>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
serial@1000a000 {
|
||||
compatible = "fsl,imx27-uart", "fsl,imx21-uart";
|
||||
reg = <0x1000a000 0x1000>;
|
||||
interrupts = <20>;
|
||||
clocks = <&clks IMX27_CLK_UART1_IPG_GATE>,
|
||||
<&clks IMX27_CLK_PER1_GATE>;
|
||||
clock-names = "ipg", "per";
|
||||
};
|
||||
|
||||
@@ -106,12 +106,3 @@ examples:
|
||||
reg = <0x80040000 0x2000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
serial@8006a000 {
|
||||
compatible = "fsl,imx28-auart";
|
||||
reg = <0x8006a000 0x2000>;
|
||||
interrupts = <112>;
|
||||
dmas = <&dma_apbx 8>, <&dma_apbx 9>;
|
||||
dma-names = "rx", "tx";
|
||||
clocks = <&clks 45>;
|
||||
};
|
||||
|
||||
@@ -110,11 +110,3 @@ examples:
|
||||
interrupts = <31>, <53>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
serial@43f90000 {
|
||||
compatible = "fsl,imx31-uart", "fsl,imx21-uart";
|
||||
reg = <0x43f90000 0x4000>;
|
||||
interrupts = <45>;
|
||||
clocks = <&clks 10>, <&clks 30>;
|
||||
clock-names = "ipg", "per";
|
||||
};
|
||||
|
||||
@@ -129,11 +129,3 @@ examples:
|
||||
interrupts = <31>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
mmc@53fb4000 {
|
||||
compatible = "fsl,imx35-esdhc";
|
||||
reg = <0x53fb4000 0x4000>;
|
||||
interrupts = <7>;
|
||||
clocks = <&clks 9>, <&clks 8>, <&clks 43>;
|
||||
clock-names = "ipg", "ahb", "per";
|
||||
};
|
||||
|
||||
@@ -108,14 +108,3 @@ examples:
|
||||
"upll", "sosc_bus_clk", "firc_bus_clk",
|
||||
"rosc", "spll_bus_clk";
|
||||
};
|
||||
|
||||
mmc@40380000 {
|
||||
compatible = "fsl,imx7ulp-usdhc";
|
||||
reg = <0x40380000 0x10000>;
|
||||
interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>,
|
||||
<&scg1 IMX7ULP_CLK_NIC1_DIV>,
|
||||
<&pcc2 IMX7ULP_CLK_USDHC1>;
|
||||
clock-names ="ipg", "ahb", "per";
|
||||
bus-width = <4>;
|
||||
};
|
||||
|
||||
@@ -86,14 +86,3 @@ examples:
|
||||
"firc", "upll";
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
mmc@40380000 {
|
||||
compatible = "fsl,imx7ulp-usdhc";
|
||||
reg = <0x40380000 0x10000>;
|
||||
interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>,
|
||||
<&scg1 IMX7ULP_CLK_NIC1_DIV>,
|
||||
<&pcc2 IMX7ULP_CLK_USDHC1>;
|
||||
clock-names ="ipg", "ahb", "per";
|
||||
bus-width = <4>;
|
||||
};
|
||||
|
||||
@@ -101,14 +101,3 @@ examples:
|
||||
"sdhc0_lpcg_ahb_clk";
|
||||
power-domains = <&pd IMX_SC_R_SDHC_0>;
|
||||
};
|
||||
|
||||
mmc@5b010000 {
|
||||
compatible = "fsl,imx8qxp-usdhc", "fsl,imx7d-usdhc";
|
||||
interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>;
|
||||
reg = <0x5b010000 0x10000>;
|
||||
clocks = <&sdhc0_lpcg IMX_LPCG_CLK_4>,
|
||||
<&sdhc0_lpcg IMX_LPCG_CLK_5>,
|
||||
<&sdhc0_lpcg IMX_LPCG_CLK_0>;
|
||||
clock-names = "ipg", "ahb", "per";
|
||||
power-domains = <&pd IMX_SC_R_SDHC_0>;
|
||||
};
|
||||
|
||||
62
Documentation/devicetree/bindings/clock/imx93-clock.yaml
Normal file
62
Documentation/devicetree/bindings/clock/imx93-clock.yaml
Normal file
@@ -0,0 +1,62 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/imx93-clock.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NXP i.MX93 Clock Control Module Binding
|
||||
|
||||
maintainers:
|
||||
- Peng Fan <peng.fan@nxp.com>
|
||||
|
||||
description: |
|
||||
i.MX93 clock control module is an integrated clock controller, which
|
||||
includes clock generator, clock gate and supplies to all modules.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,imx93-ccm
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
description:
|
||||
specify the external clocks used by the CCM module.
|
||||
items:
|
||||
- description: 32k osc
|
||||
- description: 24m osc
|
||||
- description: ext1 clock input
|
||||
|
||||
clock-names:
|
||||
description:
|
||||
specify the external clocks names used by the CCM module.
|
||||
items:
|
||||
- const: osc_32k
|
||||
- const: osc_24m
|
||||
- const: clk_ext1
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
description:
|
||||
See include/dt-bindings/clock/imx93-clock.h for the full list of
|
||||
i.MX93 clock IDs.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
# Clock Control Module node:
|
||||
- |
|
||||
clock-controller@44450000 {
|
||||
compatible = "fsl,imx93-ccm";
|
||||
reg = <0x44450000 0x10000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
...
|
||||
59
Documentation/devicetree/bindings/clock/imxrt1050-clock.yaml
Normal file
59
Documentation/devicetree/bindings/clock/imxrt1050-clock.yaml
Normal file
@@ -0,0 +1,59 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/imxrt1050-clock.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Clock bindings for Freescale i.MXRT
|
||||
|
||||
maintainers:
|
||||
- Giulio Benetti <giulio.benetti@benettiengineering.com>
|
||||
- Jesse Taube <Mr.Bossman075@gmail.com>
|
||||
|
||||
description: |
|
||||
The clock consumer should specify the desired clock by having the clock
|
||||
ID in its "clocks" phandle cell. See include/dt-bindings/clock/imxrt*-clock.h
|
||||
for the full list of i.MXRT clock IDs.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: fsl,imxrt1050-ccm
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 2
|
||||
|
||||
clocks:
|
||||
description: 24m osc
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
const: osc
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#clock-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/imxrt1050-clock.h>
|
||||
|
||||
clks: clock-controller@400fc000 {
|
||||
compatible = "fsl,imxrt1050-ccm";
|
||||
reg = <0x400fc000 0x4000>;
|
||||
interrupts = <95>, <96>;
|
||||
clocks = <&osc>;
|
||||
clock-names = "osc";
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
@@ -106,10 +106,3 @@ examples:
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
usb-controller@c5004000 {
|
||||
compatible = "nvidia,tegra20-ehci";
|
||||
reg = <0xc5004000 0x4000>;
|
||||
clocks = <&car TEGRA124_CLK_USB2>;
|
||||
resets = <&car TEGRA124_CLK_USB2>;
|
||||
};
|
||||
|
||||
@@ -97,10 +97,3 @@ examples:
|
||||
power-domains = <&domain>;
|
||||
};
|
||||
};
|
||||
|
||||
usb-controller@c5004000 {
|
||||
compatible = "nvidia,tegra20-ehci";
|
||||
reg = <0xc5004000 0x4000>;
|
||||
clocks = <&car TEGRA20_CLK_USB2>;
|
||||
resets = <&car TEGRA20_CLK_USB2>;
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@ maintainers:
|
||||
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
description:
|
||||
The A7 PLL on the Qualcomm platforms like SDX55 is used to provide high
|
||||
The A7 PLL on the Qualcomm platforms like SDX55, SDX65 is used to provide high
|
||||
frequency clock to the CPU.
|
||||
|
||||
properties:
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
Qualcomm Camera Clock & Reset Controller Binding
|
||||
------------------------------------------------
|
||||
|
||||
Required properties :
|
||||
- compatible : shall contain "qcom,sdm845-camcc".
|
||||
- reg : shall contain base register location and length.
|
||||
- #clock-cells : from common clock binding, shall contain 1.
|
||||
- #reset-cells : from common reset binding, shall contain 1.
|
||||
- #power-domain-cells : from generic power domain binding, shall contain 1.
|
||||
|
||||
Example:
|
||||
camcc: clock-controller@ad00000 {
|
||||
compatible = "qcom,sdm845-camcc";
|
||||
reg = <0xad00000 0x10000>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
@@ -0,0 +1,87 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,dispcc-sm6125.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Display Clock Controller Binding for SM6125
|
||||
|
||||
maintainers:
|
||||
- Martin Botka <martin.botka@somainline.org>
|
||||
|
||||
description: |
|
||||
Qualcomm display clock control module which supports the clocks and
|
||||
power domains on SM6125.
|
||||
|
||||
See also:
|
||||
dt-bindings/clock/qcom,dispcc-sm6125.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,sm6125-dispcc
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Board XO source
|
||||
- description: Byte clock from DSI PHY0
|
||||
- description: Pixel clock from DSI PHY0
|
||||
- description: Pixel clock from DSI PHY1
|
||||
- description: Link clock from DP PHY
|
||||
- description: VCO DIV clock from DP PHY
|
||||
- description: AHB config clock from GCC
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: bi_tcxo
|
||||
- const: dsi0_phy_pll_out_byteclk
|
||||
- const: dsi0_phy_pll_out_dsiclk
|
||||
- const: dsi1_phy_pll_out_dsiclk
|
||||
- const: dp_phy_pll_link_clk
|
||||
- const: dp_phy_pll_vco_div_clk
|
||||
- const: cfg_ahb_clk
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#clock-cells'
|
||||
- '#power-domain-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,rpmcc.h>
|
||||
#include <dt-bindings/clock/qcom,gcc-sm6125.h>
|
||||
clock-controller@5f00000 {
|
||||
compatible = "qcom,sm6125-dispcc";
|
||||
reg = <0x5f00000 0x20000>;
|
||||
clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>,
|
||||
<&dsi0_phy 0>,
|
||||
<&dsi0_phy 1>,
|
||||
<&dsi1_phy 1>,
|
||||
<&dp_phy 0>,
|
||||
<&dp_phy 1>,
|
||||
<&gcc GCC_DISP_AHB_CLK>;
|
||||
clock-names = "bi_tcxo",
|
||||
"dsi0_phy_pll_out_byteclk",
|
||||
"dsi0_phy_pll_out_dsiclk",
|
||||
"dsi1_phy_pll_out_dsiclk",
|
||||
"dp_phy_pll_link_clk",
|
||||
"dp_phy_pll_vco_div_clk",
|
||||
"cfg_ahb_clk";
|
||||
#clock-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
...
|
||||
@@ -0,0 +1,86 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,dispcc-sm6350.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Display Clock & Reset Controller Binding for SM6350
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konrad.dybcio@somainline.org>
|
||||
|
||||
description: |
|
||||
Qualcomm display clock control module which supports the clocks, resets and
|
||||
power domains on SM6350.
|
||||
|
||||
See also dt-bindings/clock/qcom,dispcc-sm6350.h.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,sm6350-dispcc
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Board XO source
|
||||
- description: GPLL0 source from GCC
|
||||
- description: Byte clock from DSI PHY
|
||||
- description: Pixel clock from DSI PHY
|
||||
- description: Link clock from DP PHY
|
||||
- description: VCO DIV clock from DP PHY
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: bi_tcxo
|
||||
- const: gcc_disp_gpll0_clk
|
||||
- const: dsi0_phy_pll_out_byteclk
|
||||
- const: dsi0_phy_pll_out_dsiclk
|
||||
- const: dp_phy_pll_link_clk
|
||||
- const: dp_phy_pll_vco_div_clk
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- '#power-domain-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,gcc-sm6350.h>
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
clock-controller@af00000 {
|
||||
compatible = "qcom,sm6350-dispcc";
|
||||
reg = <0x0af00000 0x20000>;
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>,
|
||||
<&gcc GCC_DISP_GPLL0_CLK>,
|
||||
<&dsi_phy 0>,
|
||||
<&dsi_phy 1>,
|
||||
<&dp_phy 0>,
|
||||
<&dp_phy 1>;
|
||||
clock-names = "bi_tcxo",
|
||||
"gcc_disp_gpll0_clk",
|
||||
"dsi0_phy_pll_out_byteclk",
|
||||
"dsi0_phy_pll_out_dsiclk",
|
||||
"dp_phy_pll_link_clk",
|
||||
"dp_phy_pll_vco_div_clk";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
...
|
||||
@@ -6,6 +6,9 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Global Clock & Reset Controller Binding for APQ8064
|
||||
|
||||
allOf:
|
||||
- $ref: qcom,gcc.yaml#
|
||||
|
||||
maintainers:
|
||||
- Stephen Boyd <sboyd@kernel.org>
|
||||
- Taniya Das <tdas@codeaurora.org>
|
||||
@@ -17,22 +20,12 @@ description: |
|
||||
See also:
|
||||
- dt-bindings/clock/qcom,gcc-msm8960.h
|
||||
- dt-bindings/reset/qcom,gcc-msm8960.h
|
||||
- dt-bindings/clock/qcom,gcc-apq8084.h
|
||||
- dt-bindings/reset/qcom,gcc-apq8084.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,gcc-apq8064
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
const: qcom,gcc-apq8084
|
||||
|
||||
nvmem-cells:
|
||||
minItems: 1
|
||||
@@ -53,21 +46,13 @@ properties:
|
||||
'#thermal-sensor-cells':
|
||||
const: 1
|
||||
|
||||
protected-clocks:
|
||||
description:
|
||||
Protected clock specifier list as per common clock binding.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- '#power-domain-cells'
|
||||
- nvmem-cells
|
||||
- nvmem-cell-names
|
||||
- '#thermal-sensor-cells'
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,gcc-ipq8064.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Global Clock & Reset Controller Binding for IPQ8064
|
||||
|
||||
allOf:
|
||||
- $ref: qcom,gcc.yaml#
|
||||
|
||||
maintainers:
|
||||
- Ansuel Smith <ansuelsmth@gmail.com>
|
||||
|
||||
description: |
|
||||
Qualcomm global clock control module which supports the clocks, resets and
|
||||
power domains on IPQ8064.
|
||||
|
||||
See also:
|
||||
- dt-bindings/clock/qcom,gcc-ipq806x.h (qcom,gcc-ipq8064)
|
||||
- dt-bindings/reset/qcom,gcc-ipq806x.h (qcom,gcc-ipq8064)
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: qcom,gcc-ipq8064
|
||||
- const: syscon
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: PXO source
|
||||
- description: CXO source
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: pxo
|
||||
- const: cxo
|
||||
|
||||
thermal-sensor:
|
||||
type: object
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/thermal/qcom-tsens.yaml#
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
gcc: clock-controller@900000 {
|
||||
compatible = "qcom,gcc-ipq8064", "syscon";
|
||||
reg = <0x00900000 0x4000>;
|
||||
clocks = <&pxo_board>, <&cxo_board>;
|
||||
clock-names = "pxo", "cxo";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
|
||||
tsens: thermal-sensor {
|
||||
compatible = "qcom,ipq8064-tsens";
|
||||
|
||||
nvmem-cells = <&tsens_calib>, <&tsens_calib_backup>;
|
||||
nvmem-cell-names = "calib", "calib_backup";
|
||||
interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "uplow";
|
||||
|
||||
#qcom,sensors = <11>;
|
||||
#thermal-sensor-cells = <1>;
|
||||
};
|
||||
};
|
||||
70
Documentation/devicetree/bindings/clock/qcom,gcc-other.yaml
Normal file
70
Documentation/devicetree/bindings/clock/qcom,gcc-other.yaml
Normal file
@@ -0,0 +1,70 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,gcc-other.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Global Clock & Reset Controller Binding
|
||||
|
||||
maintainers:
|
||||
- Stephen Boyd <sboyd@kernel.org>
|
||||
- Taniya Das <tdas@codeaurora.org>
|
||||
|
||||
description: |
|
||||
Qualcomm global clock control module which supports the clocks, resets and
|
||||
power domains.
|
||||
|
||||
See also:
|
||||
- dt-bindings/clock/qcom,gcc-ipq4019.h
|
||||
- dt-bindings/clock/qcom,gcc-ipq6018.h
|
||||
- dt-bindings/reset/qcom,gcc-ipq6018.h
|
||||
- dt-bindings/clock/qcom,gcc-msm8939.h
|
||||
- dt-bindings/clock/qcom,gcc-msm8953.h
|
||||
- dt-bindings/reset/qcom,gcc-msm8939.h
|
||||
- dt-bindings/clock/qcom,gcc-msm8660.h
|
||||
- dt-bindings/reset/qcom,gcc-msm8660.h
|
||||
- dt-bindings/clock/qcom,gcc-msm8974.h (qcom,gcc-msm8226 and qcom,gcc-msm8974)
|
||||
- dt-bindings/reset/qcom,gcc-msm8974.h (qcom,gcc-msm8226 and qcom,gcc-msm8974)
|
||||
- dt-bindings/clock/qcom,gcc-mdm9607.h
|
||||
- dt-bindings/clock/qcom,gcc-mdm9615.h
|
||||
- dt-bindings/reset/qcom,gcc-mdm9615.h
|
||||
- dt-bindings/clock/qcom,gcc-sdm660.h (qcom,gcc-sdm630 and qcom,gcc-sdm660)
|
||||
|
||||
allOf:
|
||||
- $ref: "qcom,gcc.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,gcc-ipq4019
|
||||
- qcom,gcc-ipq6018
|
||||
- qcom,gcc-mdm9607
|
||||
- qcom,gcc-msm8226
|
||||
- qcom,gcc-msm8660
|
||||
- qcom,gcc-msm8916
|
||||
- qcom,gcc-msm8939
|
||||
- qcom,gcc-msm8953
|
||||
- qcom,gcc-msm8960
|
||||
- qcom,gcc-msm8974
|
||||
- qcom,gcc-msm8974pro
|
||||
- qcom,gcc-msm8974pro-ac
|
||||
- qcom,gcc-mdm9615
|
||||
- qcom,gcc-sdm630
|
||||
- qcom,gcc-sdm660
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
# Example for GCC for MSM8960:
|
||||
- |
|
||||
clock-controller@900000 {
|
||||
compatible = "qcom,gcc-msm8960";
|
||||
reg = <0x900000 0x4000>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
...
|
||||
@@ -4,57 +4,17 @@
|
||||
$id: http://devicetree.org/schemas/clock/qcom,gcc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Global Clock & Reset Controller Binding
|
||||
title: Qualcomm Global Clock & Reset Controller Binding Common Bindings
|
||||
|
||||
maintainers:
|
||||
- Stephen Boyd <sboyd@kernel.org>
|
||||
- Taniya Das <tdas@codeaurora.org>
|
||||
|
||||
description: |
|
||||
Qualcomm global clock control module which supports the clocks, resets and
|
||||
power domains.
|
||||
|
||||
See also:
|
||||
- dt-bindings/clock/qcom,gcc-apq8084.h
|
||||
- dt-bindings/reset/qcom,gcc-apq8084.h
|
||||
- dt-bindings/clock/qcom,gcc-ipq4019.h
|
||||
- dt-bindings/clock/qcom,gcc-ipq6018.h
|
||||
- dt-bindings/reset/qcom,gcc-ipq6018.h
|
||||
- dt-bindings/clock/qcom,gcc-ipq806x.h (qcom,gcc-ipq8064)
|
||||
- dt-bindings/reset/qcom,gcc-ipq806x.h (qcom,gcc-ipq8064)
|
||||
- dt-bindings/clock/qcom,gcc-msm8939.h
|
||||
- dt-bindings/clock/qcom,gcc-msm8953.h
|
||||
- dt-bindings/reset/qcom,gcc-msm8939.h
|
||||
- dt-bindings/clock/qcom,gcc-msm8660.h
|
||||
- dt-bindings/reset/qcom,gcc-msm8660.h
|
||||
- dt-bindings/clock/qcom,gcc-msm8974.h (qcom,gcc-msm8226 and qcom,gcc-msm8974)
|
||||
- dt-bindings/reset/qcom,gcc-msm8974.h (qcom,gcc-msm8226 and qcom,gcc-msm8974)
|
||||
- dt-bindings/clock/qcom,gcc-mdm9607.h
|
||||
- dt-bindings/clock/qcom,gcc-mdm9615.h
|
||||
- dt-bindings/reset/qcom,gcc-mdm9615.h
|
||||
- dt-bindings/clock/qcom,gcc-sdm660.h (qcom,gcc-sdm630 and qcom,gcc-sdm660)
|
||||
Common bindings for Qualcomm global clock control module which supports
|
||||
the clocks, resets and power domains.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,gcc-apq8084
|
||||
- qcom,gcc-ipq4019
|
||||
- qcom,gcc-ipq6018
|
||||
- qcom,gcc-ipq8064
|
||||
- qcom,gcc-mdm9607
|
||||
- qcom,gcc-msm8226
|
||||
- qcom,gcc-msm8660
|
||||
- qcom,gcc-msm8916
|
||||
- qcom,gcc-msm8939
|
||||
- qcom,gcc-msm8953
|
||||
- qcom,gcc-msm8960
|
||||
- qcom,gcc-msm8974
|
||||
- qcom,gcc-msm8974pro
|
||||
- qcom,gcc-msm8974pro-ac
|
||||
- qcom,gcc-mdm9615
|
||||
- qcom,gcc-sdm630
|
||||
- qcom,gcc-sdm660
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
@@ -72,22 +32,11 @@ properties:
|
||||
Protected clock specifier list as per common clock binding.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- '#power-domain-cells'
|
||||
|
||||
additionalProperties: false
|
||||
additionalProperties: true
|
||||
|
||||
examples:
|
||||
# Example for GCC for MSM8960:
|
||||
- |
|
||||
clock-controller@900000 {
|
||||
compatible = "qcom,gcc-msm8960";
|
||||
reg = <0x900000 0x4000>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
...
|
||||
|
||||
@@ -17,6 +17,7 @@ description: |
|
||||
dt-bindings/clock/qcom,gpucc-sdm845.h
|
||||
dt-bindings/clock/qcom,gpucc-sc7180.h
|
||||
dt-bindings/clock/qcom,gpucc-sc7280.h
|
||||
dt-bindings/clock/qcom,gpucc-sm6350.h
|
||||
dt-bindings/clock/qcom,gpucc-sm8150.h
|
||||
dt-bindings/clock/qcom,gpucc-sm8250.h
|
||||
|
||||
@@ -27,6 +28,7 @@ properties:
|
||||
- qcom,sc7180-gpucc
|
||||
- qcom,sc7280-gpucc
|
||||
- qcom,sc8180x-gpucc
|
||||
- qcom,sm6350-gpucc
|
||||
- qcom,sm8150-gpucc
|
||||
- qcom,sm8250-gpucc
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ properties:
|
||||
enum:
|
||||
- qcom,mmcc-apq8064
|
||||
- qcom,mmcc-apq8084
|
||||
- qcom,mmcc-msm8226
|
||||
- qcom,mmcc-msm8660
|
||||
- qcom,mmcc-msm8960
|
||||
- qcom,mmcc-msm8974
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,qcm2290-dispcc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Display Clock & Reset Controller Binding for qcm2290
|
||||
|
||||
maintainers:
|
||||
- Loic Poulain <loic.poulain@linaro.org>
|
||||
|
||||
description: |
|
||||
Qualcomm display clock control module which supports the clocks, resets and
|
||||
power domains on qcm2290.
|
||||
|
||||
See also dt-bindings/clock/qcom,dispcc-qcm2290.h.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,qcm2290-dispcc
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Board XO source
|
||||
- description: Board active-only XO source
|
||||
- description: GPLL0 source from GCC
|
||||
- description: GPLL0 div source from GCC
|
||||
- description: Byte clock from DSI PHY
|
||||
- description: Pixel clock from DSI PHY
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: bi_tcxo
|
||||
- const: bi_tcxo_ao
|
||||
- const: gcc_disp_gpll0_clk_src
|
||||
- const: gcc_disp_gpll0_div_clk_src
|
||||
- const: dsi0_phy_pll_out_byteclk
|
||||
- const: dsi0_phy_pll_out_dsiclk
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- '#power-domain-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,dispcc-qcm2290.h>
|
||||
#include <dt-bindings/clock/qcom,gcc-qcm2290.h>
|
||||
#include <dt-bindings/clock/qcom,rpmcc.h>
|
||||
clock-controller@5f00000 {
|
||||
compatible = "qcom,qcm2290-dispcc";
|
||||
reg = <0x5f00000 0x20000>;
|
||||
clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>,
|
||||
<&rpmcc RPM_SMD_XO_A_CLK_SRC>,
|
||||
<&gcc GCC_DISP_GPLL0_CLK_SRC>,
|
||||
<&gcc GCC_DISP_GPLL0_DIV_CLK_SRC>,
|
||||
<&dsi0_phy 0>,
|
||||
<&dsi0_phy 1>;
|
||||
clock-names = "bi_tcxo",
|
||||
"bi_tcxo_ao",
|
||||
"gcc_disp_gpll0_clk_src",
|
||||
"gcc_disp_gpll0_div_clk_src",
|
||||
"dsi0_phy_pll_out_byteclk",
|
||||
"dsi0_phy_pll_out_dsiclk";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
...
|
||||
@@ -20,6 +20,7 @@ properties:
|
||||
- qcom,sc7180-rpmh-clk
|
||||
- qcom,sc7280-rpmh-clk
|
||||
- qcom,sc8180x-rpmh-clk
|
||||
- qcom,sc8280xp-rpmh-clk
|
||||
- qcom,sdm845-rpmh-clk
|
||||
- qcom,sdx55-rpmh-clk
|
||||
- qcom,sdx65-rpmh-clk
|
||||
|
||||
@@ -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,sdm845-camcc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Camera Clock & Reset Controller Binding for SDM845
|
||||
|
||||
maintainers:
|
||||
- Bjorn Andersson <bjorn.andersson@linaro.org>
|
||||
|
||||
description: |
|
||||
Qualcomm camera clock control module which supports the clocks, resets and
|
||||
power domains on SDM845.
|
||||
|
||||
See also dt-bindings/clock/qcom,camcc-sm845.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,sdm845-camcc
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Board XO source
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: bi_tcxo
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- '#power-domain-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
clock-controller@ad00000 {
|
||||
compatible = "qcom,sdm845-camcc";
|
||||
reg = <0x0ad00000 0x10000>;
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>;
|
||||
clock-names = "bi_tcxo";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
...
|
||||
97
Documentation/devicetree/bindings/clock/renesas,9series.yaml
Normal file
97
Documentation/devicetree/bindings/clock/renesas,9series.yaml
Normal file
@@ -0,0 +1,97 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/renesas,9series.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Binding for Renesas 9-series I2C PCIe clock generators
|
||||
|
||||
description: |
|
||||
The Renesas 9-series are I2C PCIe clock generators providing
|
||||
from 1 to 20 output clocks.
|
||||
|
||||
When referencing the provided clock in the DT using phandle
|
||||
and clock specifier, the following mapping applies:
|
||||
|
||||
- 9FGV0241:
|
||||
0 -- DIF0
|
||||
1 -- DIF1
|
||||
|
||||
maintainers:
|
||||
- Marek Vasut <marex@denx.de>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- renesas,9fgv0241
|
||||
|
||||
reg:
|
||||
description: I2C device address
|
||||
enum: [ 0x68, 0x6a ]
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: XTal input clock
|
||||
|
||||
renesas,out-amplitude-microvolt:
|
||||
enum: [ 600000, 700000, 800000, 900000 ]
|
||||
description: Output clock signal amplitude
|
||||
|
||||
renesas,out-spread-spectrum:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [ 100000, 99750, 99500 ]
|
||||
description: Output clock down spread in pcm (1/1000 of percent)
|
||||
|
||||
patternProperties:
|
||||
"^DIF[0-19]$":
|
||||
type: object
|
||||
description:
|
||||
Description of one of the outputs (DIF0..DIF19).
|
||||
|
||||
properties:
|
||||
renesas,slew-rate:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [ 2000000, 3000000 ]
|
||||
description: Output clock slew rate select in V/ns
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- '#clock-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
/* 25MHz reference crystal */
|
||||
ref25: ref25m {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <25000000>;
|
||||
};
|
||||
|
||||
i2c@0 {
|
||||
reg = <0x0 0x100>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
rs9: clock-generator@6a {
|
||||
compatible = "renesas,9fgv0241";
|
||||
reg = <0x6a>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clocks = <&ref25m>;
|
||||
|
||||
DIF0 {
|
||||
renesas,slew-rate = <3000000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -51,6 +51,18 @@ additionalProperties: false
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r8a73a4-clock.h>
|
||||
|
||||
cpg_clocks: cpg_clocks@e6150000 {
|
||||
compatible = "renesas,r8a73a4-cpg-clocks";
|
||||
reg = <0xe6150000 0x10000>;
|
||||
clocks = <&extal1_clk>, <&extal2_clk>;
|
||||
#clock-cells = <1>;
|
||||
clock-output-names = "main", "pll0", "pll1", "pll2",
|
||||
"pll2s", "pll2h", "z", "z2",
|
||||
"i", "m3", "b", "m1", "m2",
|
||||
"zx", "zs", "hp";
|
||||
};
|
||||
|
||||
sdhi2_clk: sdhi2_clk@e615007c {
|
||||
compatible = "renesas,r8a73a4-div6-clock", "renesas,cpg-div6-clock";
|
||||
reg = <0xe615007c 4>;
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
$id: "http://devicetree.org/schemas/clock/renesas,rzg2l-cpg.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: Renesas RZ/G2L Clock Pulse Generator / Module Standby Mode
|
||||
title: Renesas RZ/{G2L,V2L} Clock Pulse Generator / Module Standby Mode
|
||||
|
||||
maintainers:
|
||||
- Geert Uytterhoeven <geert+renesas@glider.be>
|
||||
|
||||
description: |
|
||||
On Renesas RZ/G2L SoC, the CPG (Clock Pulse Generator) and Module
|
||||
On Renesas RZ/{G2L,V2L} SoC, the CPG (Clock Pulse Generator) and Module
|
||||
Standby Mode share the same register block.
|
||||
|
||||
They provide the following functionalities:
|
||||
@@ -22,7 +22,9 @@ description: |
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: renesas,r9a07g044-cpg # RZ/G2{L,LC}
|
||||
enum:
|
||||
- renesas,r9a07g044-cpg # RZ/G2{L,LC}
|
||||
- renesas,r9a07g054-cpg # RZ/V2L
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@@ -40,9 +42,9 @@ properties:
|
||||
description: |
|
||||
- For CPG core clocks, the two clock specifier cells must be "CPG_CORE"
|
||||
and a core clock reference, as defined in
|
||||
<dt-bindings/clock/r9a07g044-cpg.h>
|
||||
<dt-bindings/clock/r9a07g*-cpg.h>
|
||||
- For module clocks, the two clock specifier cells must be "CPG_MOD" and
|
||||
a module number, as defined in the <dt-bindings/clock/r9a07g044-cpg.h>.
|
||||
a module number, as defined in the <dt-bindings/clock/r9a07g0*-cpg.h>.
|
||||
const: 2
|
||||
|
||||
'#power-domain-cells':
|
||||
@@ -56,7 +58,7 @@ properties:
|
||||
'#reset-cells':
|
||||
description:
|
||||
The single reset specifier cell must be the module number, as defined in
|
||||
the <dt-bindings/clock/r9a07g044-cpg.h>.
|
||||
the <dt-bindings/clock/r9a07g0*-cpg.h>.
|
||||
const: 1
|
||||
|
||||
required:
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/starfive,jh7100-audclk.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: StarFive JH7100 Audio Clock Generator
|
||||
|
||||
maintainers:
|
||||
- Emil Renner Berthing <kernel@esmil.dk>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: starfive,jh7100-audclk
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Audio source clock
|
||||
- description: External 12.288MHz clock
|
||||
- description: Domain 7 AHB bus clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: audio_src
|
||||
- const: audio_12288
|
||||
- const: dom7ahb_bus
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
description:
|
||||
See <dt-bindings/clock/starfive-jh7100-audio.h> for valid indices.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#clock-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/starfive-jh7100.h>
|
||||
|
||||
clock-controller@10480000 {
|
||||
compatible = "starfive,jh7100-audclk";
|
||||
reg = <0x10480000 0x10000>;
|
||||
clocks = <&clkgen JH7100_CLK_AUDIO_SRC>,
|
||||
<&clkgen JH7100_CLK_AUDIO_12288>,
|
||||
<&clkgen JH7100_CLK_DOM7AHB_BUS>;
|
||||
clock-names = "audio_src", "audio_12288", "dom7ahb_bus";
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
@@ -79,7 +79,7 @@ examples:
|
||||
interrupts = <7>, <8>, <9>, <10>, <11>, <12>, <13>, <14>, <15>, <16>,
|
||||
<17>, <18>, <19>, <20>, <21>, <22>;
|
||||
reg = <0x10060000 0x1000>;
|
||||
clocks = <&tlclk PRCI_CLK_TLCLK>;
|
||||
clocks = <&tlclk FU540_PRCI_CLK_TLCLK>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
|
||||
@@ -104,7 +104,7 @@ examples:
|
||||
<0x0 0x0 0x0 0x2 &plic0 58>,
|
||||
<0x0 0x0 0x0 0x3 &plic0 59>,
|
||||
<0x0 0x0 0x0 0x4 &plic0 60>;
|
||||
clocks = <&prci PRCI_CLK_PCIE_AUX>;
|
||||
clocks = <&prci FU740_PRCI_CLK_PCIE_AUX>;
|
||||
resets = <&prci 4>;
|
||||
pwren-gpios = <&gpio 5 0>;
|
||||
reset-gpios = <&gpio 8 0>;
|
||||
|
||||
@@ -59,7 +59,7 @@ examples:
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <80>;
|
||||
reg = <0x10010000 0x1000>;
|
||||
clocks = <&prci PRCI_CLK_TLCLK>;
|
||||
clocks = <&prci FU540_PRCI_CLK_TLCLK>;
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
13
MAINTAINERS
13
MAINTAINERS
@@ -1833,6 +1833,7 @@ C: irc://irc.oftc.net/asahi-dev
|
||||
T: git https://github.com/AsahiLinux/linux.git
|
||||
F: Documentation/devicetree/bindings/arm/apple.yaml
|
||||
F: Documentation/devicetree/bindings/arm/apple/*
|
||||
F: Documentation/devicetree/bindings/clock/apple,nco.yaml
|
||||
F: Documentation/devicetree/bindings/i2c/apple,i2c.yaml
|
||||
F: Documentation/devicetree/bindings/interrupt-controller/apple,*
|
||||
F: Documentation/devicetree/bindings/mailbox/apple,mailbox.yaml
|
||||
@@ -1841,6 +1842,7 @@ F: Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml
|
||||
F: Documentation/devicetree/bindings/power/apple*
|
||||
F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
|
||||
F: arch/arm64/boot/dts/apple/
|
||||
F: drivers/clk/clk-apple-nco.c
|
||||
F: drivers/i2c/busses/i2c-pasemi-core.c
|
||||
F: drivers/i2c/busses/i2c-pasemi-platform.c
|
||||
F: drivers/irqchip/irq-apple-aic.c
|
||||
@@ -14072,7 +14074,10 @@ M: Abel Vesa <abel.vesa@nxp.com>
|
||||
L: linux-clk@vger.kernel.org
|
||||
L: linux-imx@nxp.com
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/abelvesa/linux.git clk/imx
|
||||
F: Documentation/devicetree/bindings/clock/imx*
|
||||
F: drivers/clk/imx/
|
||||
F: include/dt-bindings/clock/imx*
|
||||
|
||||
NXP i.MX 8MQ DCSS DRIVER
|
||||
M: Laurentiu Palcu <laurentiu.palcu@oss.nxp.com>
|
||||
@@ -18730,12 +18735,12 @@ M: Ion Badulescu <ionut@badula.org>
|
||||
S: Odd Fixes
|
||||
F: drivers/net/ethernet/adaptec/starfire*
|
||||
|
||||
STARFIVE JH7100 CLOCK DRIVER
|
||||
STARFIVE JH7100 CLOCK DRIVERS
|
||||
M: Emil Renner Berthing <kernel@esmil.dk>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/clock/starfive,jh7100-clkgen.yaml
|
||||
F: drivers/clk/starfive/clk-starfive-jh7100.c
|
||||
F: include/dt-bindings/clock/starfive-jh7100.h
|
||||
F: Documentation/devicetree/bindings/clock/starfive,jh7100-*.yaml
|
||||
F: drivers/clk/starfive/clk-starfive-jh7100*
|
||||
F: include/dt-bindings/clock/starfive-jh7100*.h
|
||||
|
||||
STARFIVE JH7100 PINCTRL DRIVER
|
||||
M: Emil Renner Berthing <kernel@esmil.dk>
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
reg = <0x0 0x10010000 0x0 0x1000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <4>;
|
||||
clocks = <&prci PRCI_CLK_TLCLK>;
|
||||
clocks = <&prci FU540_PRCI_CLK_TLCLK>;
|
||||
status = "disabled";
|
||||
};
|
||||
dma: dma@3000000 {
|
||||
@@ -180,7 +180,7 @@
|
||||
reg = <0x0 0x10011000 0x0 0x1000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <5>;
|
||||
clocks = <&prci PRCI_CLK_TLCLK>;
|
||||
clocks = <&prci FU540_PRCI_CLK_TLCLK>;
|
||||
status = "disabled";
|
||||
};
|
||||
i2c0: i2c@10030000 {
|
||||
@@ -188,7 +188,7 @@
|
||||
reg = <0x0 0x10030000 0x0 0x1000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <50>;
|
||||
clocks = <&prci PRCI_CLK_TLCLK>;
|
||||
clocks = <&prci FU540_PRCI_CLK_TLCLK>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <1>;
|
||||
#address-cells = <1>;
|
||||
@@ -201,7 +201,7 @@
|
||||
<0x0 0x20000000 0x0 0x10000000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <51>;
|
||||
clocks = <&prci PRCI_CLK_TLCLK>;
|
||||
clocks = <&prci FU540_PRCI_CLK_TLCLK>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
@@ -212,7 +212,7 @@
|
||||
<0x0 0x30000000 0x0 0x10000000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <52>;
|
||||
clocks = <&prci PRCI_CLK_TLCLK>;
|
||||
clocks = <&prci FU540_PRCI_CLK_TLCLK>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
@@ -222,7 +222,7 @@
|
||||
reg = <0x0 0x10050000 0x0 0x1000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <6>;
|
||||
clocks = <&prci PRCI_CLK_TLCLK>;
|
||||
clocks = <&prci FU540_PRCI_CLK_TLCLK>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
@@ -235,8 +235,8 @@
|
||||
<0x0 0x100a0000 0x0 0x1000>;
|
||||
local-mac-address = [00 00 00 00 00 00];
|
||||
clock-names = "pclk", "hclk";
|
||||
clocks = <&prci PRCI_CLK_GEMGXLPLL>,
|
||||
<&prci PRCI_CLK_GEMGXLPLL>;
|
||||
clocks = <&prci FU540_PRCI_CLK_GEMGXLPLL>,
|
||||
<&prci FU540_PRCI_CLK_GEMGXLPLL>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
@@ -246,7 +246,7 @@
|
||||
reg = <0x0 0x10020000 0x0 0x1000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <42>, <43>, <44>, <45>;
|
||||
clocks = <&prci PRCI_CLK_TLCLK>;
|
||||
clocks = <&prci FU540_PRCI_CLK_TLCLK>;
|
||||
#pwm-cells = <3>;
|
||||
status = "disabled";
|
||||
};
|
||||
@@ -255,7 +255,7 @@
|
||||
reg = <0x0 0x10021000 0x0 0x1000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <46>, <47>, <48>, <49>;
|
||||
clocks = <&prci PRCI_CLK_TLCLK>;
|
||||
clocks = <&prci FU540_PRCI_CLK_TLCLK>;
|
||||
#pwm-cells = <3>;
|
||||
status = "disabled";
|
||||
};
|
||||
@@ -281,7 +281,7 @@
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
clocks = <&prci PRCI_CLK_TLCLK>;
|
||||
clocks = <&prci FU540_PRCI_CLK_TLCLK>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -166,7 +166,7 @@
|
||||
reg = <0x0 0x10010000 0x0 0x1000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <39>;
|
||||
clocks = <&prci PRCI_CLK_PCLK>;
|
||||
clocks = <&prci FU740_PRCI_CLK_PCLK>;
|
||||
status = "disabled";
|
||||
};
|
||||
uart1: serial@10011000 {
|
||||
@@ -174,7 +174,7 @@
|
||||
reg = <0x0 0x10011000 0x0 0x1000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <40>;
|
||||
clocks = <&prci PRCI_CLK_PCLK>;
|
||||
clocks = <&prci FU740_PRCI_CLK_PCLK>;
|
||||
status = "disabled";
|
||||
};
|
||||
i2c0: i2c@10030000 {
|
||||
@@ -182,7 +182,7 @@
|
||||
reg = <0x0 0x10030000 0x0 0x1000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <52>;
|
||||
clocks = <&prci PRCI_CLK_PCLK>;
|
||||
clocks = <&prci FU740_PRCI_CLK_PCLK>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <1>;
|
||||
#address-cells = <1>;
|
||||
@@ -194,7 +194,7 @@
|
||||
reg = <0x0 0x10031000 0x0 0x1000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <53>;
|
||||
clocks = <&prci PRCI_CLK_PCLK>;
|
||||
clocks = <&prci FU740_PRCI_CLK_PCLK>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <1>;
|
||||
#address-cells = <1>;
|
||||
@@ -207,7 +207,7 @@
|
||||
<0x0 0x20000000 0x0 0x10000000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <41>;
|
||||
clocks = <&prci PRCI_CLK_PCLK>;
|
||||
clocks = <&prci FU740_PRCI_CLK_PCLK>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
@@ -218,7 +218,7 @@
|
||||
<0x0 0x30000000 0x0 0x10000000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <42>;
|
||||
clocks = <&prci PRCI_CLK_PCLK>;
|
||||
clocks = <&prci FU740_PRCI_CLK_PCLK>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
@@ -228,7 +228,7 @@
|
||||
reg = <0x0 0x10050000 0x0 0x1000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <43>;
|
||||
clocks = <&prci PRCI_CLK_PCLK>;
|
||||
clocks = <&prci FU740_PRCI_CLK_PCLK>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
@@ -241,8 +241,8 @@
|
||||
<0x0 0x100a0000 0x0 0x1000>;
|
||||
local-mac-address = [00 00 00 00 00 00];
|
||||
clock-names = "pclk", "hclk";
|
||||
clocks = <&prci PRCI_CLK_GEMGXLPLL>,
|
||||
<&prci PRCI_CLK_GEMGXLPLL>;
|
||||
clocks = <&prci FU740_PRCI_CLK_GEMGXLPLL>,
|
||||
<&prci FU740_PRCI_CLK_GEMGXLPLL>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
@@ -252,7 +252,7 @@
|
||||
reg = <0x0 0x10020000 0x0 0x1000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <44>, <45>, <46>, <47>;
|
||||
clocks = <&prci PRCI_CLK_PCLK>;
|
||||
clocks = <&prci FU740_PRCI_CLK_PCLK>;
|
||||
#pwm-cells = <3>;
|
||||
status = "disabled";
|
||||
};
|
||||
@@ -261,7 +261,7 @@
|
||||
reg = <0x0 0x10021000 0x0 0x1000>;
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <48>, <49>, <50>, <51>;
|
||||
clocks = <&prci PRCI_CLK_PCLK>;
|
||||
clocks = <&prci FU740_PRCI_CLK_PCLK>;
|
||||
#pwm-cells = <3>;
|
||||
status = "disabled";
|
||||
};
|
||||
@@ -287,7 +287,7 @@
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
clocks = <&prci PRCI_CLK_PCLK>;
|
||||
clocks = <&prci FU740_PRCI_CLK_PCLK>;
|
||||
status = "disabled";
|
||||
};
|
||||
pcie@e00000000 {
|
||||
@@ -316,7 +316,7 @@
|
||||
<0x0 0x0 0x0 0x3 &plic0 59>,
|
||||
<0x0 0x0 0x0 0x4 &plic0 60>;
|
||||
clock-names = "pcie_aux";
|
||||
clocks = <&prci PRCI_CLK_PCIE_AUX>;
|
||||
clocks = <&prci FU740_PRCI_CLK_PCIE_AUX>;
|
||||
pwren-gpios = <&gpio 5 0>;
|
||||
reset-gpios = <&gpio 8 0>;
|
||||
resets = <&prci 4>;
|
||||
|
||||
4
drivers/clk/.kunitconfig
Normal file
4
drivers/clk/.kunitconfig
Normal file
@@ -0,0 +1,4 @@
|
||||
CONFIG_KUNIT=y
|
||||
CONFIG_COMMON_CLK=y
|
||||
CONFIG_CLK_KUNIT_TEST=y
|
||||
CONFIG_CLK_GATE_KUNIT_TEST=y
|
||||
@@ -59,6 +59,15 @@ config LMK04832
|
||||
Say yes here to build support for Texas Instruments' LMK04832 Ultra
|
||||
Low-Noise JESD204B Compliant Clock Jitter Cleaner With Dual Loop PLLs
|
||||
|
||||
config COMMON_CLK_APPLE_NCO
|
||||
tristate "Clock driver for Apple SoC NCOs"
|
||||
depends on ARCH_APPLE || COMPILE_TEST
|
||||
default ARCH_APPLE
|
||||
help
|
||||
This driver supports NCO (Numerically Controlled Oscillator) blocks
|
||||
found on Apple SoCs such as t8103 (M1). The blocks are typically
|
||||
generators of audio clocks.
|
||||
|
||||
config COMMON_CLK_MAX77686
|
||||
tristate "Clock driver for Maxim 77620/77686/77802 MFD"
|
||||
depends on MFD_MAX77686 || MFD_MAX77620 || COMPILE_TEST
|
||||
@@ -197,6 +206,7 @@ config COMMON_CLK_CDCE925
|
||||
config COMMON_CLK_CS2000_CP
|
||||
tristate "Clock driver for CS2000 Fractional-N Clock Synthesizer & Clock Multiplier"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you get support for the CS2000 clock multiplier.
|
||||
|
||||
@@ -233,6 +243,7 @@ config COMMON_CLK_LAN966X
|
||||
bool "Generic Clock Controller driver for LAN966X SoC"
|
||||
depends on HAS_IOMEM
|
||||
depends on OF
|
||||
depends on SOC_LAN966 || COMPILE_TEST
|
||||
help
|
||||
This driver provides support for Generic Clock Controller(GCK) on
|
||||
LAN966X SoC. GCK generates and supplies clock to various peripherals
|
||||
@@ -332,9 +343,6 @@ config COMMON_CLK_PXA
|
||||
help
|
||||
Support for the Marvell PXA SoC.
|
||||
|
||||
config COMMON_CLK_PIC32
|
||||
def_bool COMMON_CLK && MACH_PIC32
|
||||
|
||||
config COMMON_CLK_OXNAS
|
||||
bool "Clock driver for the OXNAS SoC Family"
|
||||
depends on ARCH_OXNAS || COMPILE_TEST
|
||||
@@ -342,6 +350,15 @@ config COMMON_CLK_OXNAS
|
||||
help
|
||||
Support for the OXNAS SoC Family clocks.
|
||||
|
||||
config COMMON_CLK_RS9_PCIE
|
||||
tristate "Clock driver for Renesas 9-series PCIe clock generators"
|
||||
depends on I2C
|
||||
depends on OF
|
||||
select REGMAP_I2C
|
||||
help
|
||||
This driver supports the Renesas 9-series PCIe clock generator
|
||||
models 9FGV/9DBV/9DMV/9FGL/9DML/9QXL/9SQ.
|
||||
|
||||
config COMMON_CLK_VC5
|
||||
tristate "Clock driver for IDT VersaClock 5,6 devices"
|
||||
depends on I2C
|
||||
@@ -409,6 +426,7 @@ source "drivers/clk/keystone/Kconfig"
|
||||
source "drivers/clk/mediatek/Kconfig"
|
||||
source "drivers/clk/meson/Kconfig"
|
||||
source "drivers/clk/mstar/Kconfig"
|
||||
source "drivers/clk/microchip/Kconfig"
|
||||
source "drivers/clk/mvebu/Kconfig"
|
||||
source "drivers/clk/pistachio/Kconfig"
|
||||
source "drivers/clk/qcom/Kconfig"
|
||||
@@ -430,4 +448,19 @@ source "drivers/clk/x86/Kconfig"
|
||||
source "drivers/clk/xilinx/Kconfig"
|
||||
source "drivers/clk/zynqmp/Kconfig"
|
||||
|
||||
# Kunit test cases
|
||||
config CLK_KUNIT_TEST
|
||||
tristate "Basic Clock Framework Kunit Tests" if !KUNIT_ALL_TESTS
|
||||
depends on KUNIT
|
||||
default KUNIT_ALL_TESTS
|
||||
help
|
||||
Kunit tests for the common clock framework.
|
||||
|
||||
config CLK_GATE_KUNIT_TEST
|
||||
tristate "Basic gate type Kunit test" if !KUNIT_ALL_TESTS
|
||||
depends on KUNIT
|
||||
default KUNIT_ALL_TESTS
|
||||
help
|
||||
Kunit test for the basic clk gate type.
|
||||
|
||||
endif
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
# common clock types
|
||||
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
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-divider.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-gate.o
|
||||
obj-$(CONFIG_CLK_GATE_KUNIT_TEST) += clk-gate_test.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-multiplier.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-mux.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-composite.o
|
||||
@@ -17,6 +19,7 @@ endif
|
||||
|
||||
# hardware specific clock types
|
||||
# please keep this section sorted lexicographically by file path name
|
||||
obj-$(CONFIG_COMMON_CLK_APPLE_NCO) += clk-apple-nco.o
|
||||
obj-$(CONFIG_MACH_ASM9260) += clk-asm9260.o
|
||||
obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
|
||||
obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o
|
||||
@@ -67,6 +70,7 @@ obj-$(CONFIG_COMMON_CLK_STM32MP157) += clk-stm32mp1.o
|
||||
obj-$(CONFIG_COMMON_CLK_TPS68470) += clk-tps68470.o
|
||||
obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
|
||||
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
|
||||
obj-$(CONFIG_COMMON_CLK_RS9_PCIE) += clk-renesas-pcie.o
|
||||
obj-$(CONFIG_COMMON_CLK_VC5) += clk-versaclock5.o
|
||||
obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
|
||||
obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o
|
||||
@@ -91,7 +95,7 @@ obj-$(CONFIG_ARCH_KEYSTONE) += keystone/
|
||||
obj-$(CONFIG_MACH_LOONGSON32) += loongson1/
|
||||
obj-y += mediatek/
|
||||
obj-$(CONFIG_ARCH_MESON) += meson/
|
||||
obj-$(CONFIG_MACH_PIC32) += microchip/
|
||||
obj-y += microchip/
|
||||
ifeq ($(CONFIG_COMMON_CLK), y)
|
||||
obj-$(CONFIG_ARCH_MMP) += mmp/
|
||||
endif
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
|
||||
static const struct clk_pll_table clk_audio_pll_table[] = {
|
||||
{ 0, 45158400 }, { 1, 49152000 },
|
||||
{ 0, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
/* pll clocks */
|
||||
@@ -138,46 +138,46 @@ static struct clk_factor_table sd_factor_table[] = {
|
||||
{ 272, 1, 17 * 128 }, { 273, 1, 18 * 128 }, { 274, 1, 19 * 128 }, { 275, 1, 20 * 128 },
|
||||
{ 276, 1, 21 * 128 }, { 277, 1, 22 * 128 }, { 278, 1, 23 * 128 }, { 279, 1, 24 * 128 },
|
||||
{ 280, 1, 25 * 128 },
|
||||
{ 0, 0, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_factor_table de_factor_table[] = {
|
||||
{ 0, 1, 1 }, { 1, 2, 3 }, { 2, 1, 2 }, { 3, 2, 5 },
|
||||
{ 4, 1, 3 }, { 5, 1, 4 }, { 6, 1, 6 }, { 7, 1, 8 },
|
||||
{ 8, 1, 12 },
|
||||
{ 0, 0, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_factor_table hde_factor_table[] = {
|
||||
{ 0, 1, 1 }, { 1, 2, 3 }, { 2, 1, 2 }, { 3, 2, 5 },
|
||||
{ 4, 1, 3 }, { 5, 1, 4 }, { 6, 1, 6 }, { 7, 1, 8 },
|
||||
{ 0, 0, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_div_table rmii_ref_div_table[] = {
|
||||
{ 0, 4 }, { 1, 10 },
|
||||
{ 0, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_div_table std12rate_div_table[] = {
|
||||
{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
|
||||
{ 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
|
||||
{ 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
|
||||
{ 0, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_div_table i2s_div_table[] = {
|
||||
{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
|
||||
{ 4, 6 }, { 5, 8 }, { 6, 12 }, { 7, 16 },
|
||||
{ 8, 24 },
|
||||
{ 0, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_div_table nand_div_table[] = {
|
||||
{ 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 6 },
|
||||
{ 4, 8 }, { 5, 10 }, { 6, 12 }, { 7, 14 },
|
||||
{ 8, 16 }, { 9, 18 }, { 10, 20 }, { 11, 22 },
|
||||
{ 0, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
/* mux clock */
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
|
||||
static struct clk_pll_table clk_audio_pll_table[] = {
|
||||
{0, 45158400}, {1, 49152000},
|
||||
{0, 0},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_pll_table clk_cvbs_pll_table[] = {
|
||||
@@ -82,7 +82,8 @@ static struct clk_pll_table clk_cvbs_pll_table[] = {
|
||||
{33, 35 * 12000000}, {34, 36 * 12000000}, {35, 37 * 12000000},
|
||||
{36, 38 * 12000000}, {37, 39 * 12000000}, {38, 40 * 12000000},
|
||||
{39, 41 * 12000000}, {40, 42 * 12000000}, {41, 43 * 12000000},
|
||||
{42, 44 * 12000000}, {43, 45 * 12000000}, {0, 0},
|
||||
{42, 44 * 12000000}, {43, 45 * 12000000},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
/* pll clocks */
|
||||
@@ -137,7 +138,7 @@ static struct clk_factor_table sd_factor_table[] = {
|
||||
{276, 1, 21 * 128}, {277, 1, 22 * 128}, {278, 1, 23 * 128}, {279, 1, 24 * 128},
|
||||
{280, 1, 25 * 128}, {281, 1, 26 * 128},
|
||||
|
||||
{0, 0},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_factor_table lcd_factor_table[] = {
|
||||
@@ -150,18 +151,19 @@ static struct clk_factor_table lcd_factor_table[] = {
|
||||
{256, 1, 1 * 7}, {257, 1, 2 * 7}, {258, 1, 3 * 7}, {259, 1, 4 * 7},
|
||||
{260, 1, 5 * 7}, {261, 1, 6 * 7}, {262, 1, 7 * 7}, {263, 1, 8 * 7},
|
||||
{264, 1, 9 * 7}, {265, 1, 10 * 7}, {266, 1, 11 * 7}, {267, 1, 12 * 7},
|
||||
{0, 0},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_div_table hdmia_div_table[] = {
|
||||
{0, 1}, {1, 2}, {2, 3}, {3, 4},
|
||||
{4, 6}, {5, 8}, {6, 12}, {7, 16},
|
||||
{8, 24},
|
||||
{0, 0},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_div_table rmii_div_table[] = {
|
||||
{0, 4}, {1, 10},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
/* divider clocks */
|
||||
@@ -178,13 +180,14 @@ static OWL_DIVIDER(clk_rmii_ref, "rmii_ref", "ethernet_pll", CMU_ETHERNETPLL, 2,
|
||||
static struct clk_factor_table de_factor_table[] = {
|
||||
{0, 1, 1}, {1, 2, 3}, {2, 1, 2}, {3, 2, 5},
|
||||
{4, 1, 3}, {5, 1, 4}, {6, 1, 6}, {7, 1, 8},
|
||||
{8, 1, 12}, {0, 0, 0},
|
||||
{8, 1, 12},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_factor_table hde_factor_table[] = {
|
||||
{0, 1, 1}, {1, 2, 3}, {2, 1, 2}, {3, 2, 5},
|
||||
{4, 1, 3}, {5, 1, 4}, {6, 1, 6}, {7, 1, 8},
|
||||
{0, 0, 0},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
/* gate clocks */
|
||||
|
||||
@@ -73,12 +73,12 @@
|
||||
|
||||
static struct clk_pll_table clk_audio_pll_table[] = {
|
||||
{ 0, 45158400 }, { 1, 49152000 },
|
||||
{ 0, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_pll_table clk_edp_pll_table[] = {
|
||||
{ 0, 810000000 }, { 1, 135000000 }, { 2, 270000000 },
|
||||
{ 0, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
/* pll clocks */
|
||||
@@ -120,41 +120,41 @@ static struct clk_div_table nand_div_table[] = {
|
||||
{ 4, 8 }, { 5, 10 }, { 6, 12 }, { 7, 14 },
|
||||
{ 8, 16 }, { 9, 18 }, { 10, 20 }, { 11, 22 },
|
||||
{ 12, 24 }, { 13, 26 }, { 14, 28 }, { 15, 30 },
|
||||
{ 0, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_div_table apb_div_table[] = {
|
||||
{ 1, 2 }, { 2, 3 }, { 3, 4 },
|
||||
{ 0, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_div_table eth_mac_div_table[] = {
|
||||
{ 0, 2 }, { 1, 4 },
|
||||
{ 0, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_div_table rmii_ref_div_table[] = {
|
||||
{ 0, 4 }, { 1, 10 },
|
||||
{ 0, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_div_table usb3_mac_div_table[] = {
|
||||
{ 1, 2 }, { 2, 3 }, { 3, 4 },
|
||||
{ 0, 8 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_div_table i2s_div_table[] = {
|
||||
{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
|
||||
{ 4, 6 }, { 5, 8 }, { 6, 12 }, { 7, 16 },
|
||||
{ 8, 24 },
|
||||
{ 0, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_div_table hdmia_div_table[] = {
|
||||
{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
|
||||
{ 4, 6 }, { 5, 8 }, { 6, 12 }, { 7, 16 },
|
||||
{ 8, 24 },
|
||||
{ 0, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
/* divider clocks */
|
||||
@@ -185,24 +185,24 @@ static struct clk_factor_table sd_factor_table[] = {
|
||||
{ 280, 1, 25 * 128 }, { 281, 1, 26 * 128 }, { 282, 1, 27 * 128 }, { 283, 1, 28 * 128 },
|
||||
{ 284, 1, 29 * 128 }, { 285, 1, 30 * 128 }, { 286, 1, 31 * 128 }, { 287, 1, 32 * 128 },
|
||||
|
||||
{ 0, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_factor_table dmm_factor_table[] = {
|
||||
{ 0, 1, 1 }, { 1, 2, 3 }, { 2, 1, 2 }, { 3, 1, 3 },
|
||||
{ 4, 1, 4 },
|
||||
{ 0, 0, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_factor_table noc_factor_table[] = {
|
||||
{ 0, 1, 1 }, { 1, 2, 3 }, { 2, 1, 2 }, { 3, 1, 3 }, { 4, 1, 4 },
|
||||
{ 0, 0, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_factor_table bisp_factor_table[] = {
|
||||
{ 0, 1, 1 }, { 1, 2, 3 }, { 2, 1, 2 }, { 3, 2, 5 },
|
||||
{ 4, 1, 3 }, { 5, 1, 4 }, { 6, 1, 6 }, { 7, 1, 8 },
|
||||
{ 0, 0, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
/* factor clocks */
|
||||
|
||||
@@ -143,8 +143,7 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
|
||||
parent_names,
|
||||
&at91rm9200_master_layout,
|
||||
&rm9200_mck_characteristics,
|
||||
&rm9200_mck_lock, CLK_SET_RATE_GATE,
|
||||
INT_MIN);
|
||||
&rm9200_mck_lock);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
||||
@@ -419,8 +419,7 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
|
||||
parent_names,
|
||||
&at91rm9200_master_layout,
|
||||
data->mck_characteristics,
|
||||
&at91sam9260_mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
&at91sam9260_mck_lock);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
||||
@@ -154,8 +154,7 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
|
||||
parent_names,
|
||||
&at91rm9200_master_layout,
|
||||
&mck_characteristics,
|
||||
&at91sam9g45_mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
&at91sam9g45_mck_lock);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
||||
@@ -181,8 +181,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
|
||||
parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics,
|
||||
&at91sam9n12_mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
&at91sam9n12_mck_lock);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
||||
@@ -123,8 +123,7 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
|
||||
parent_names,
|
||||
&at91rm9200_master_layout,
|
||||
&sam9rl_mck_characteristics,
|
||||
&sam9rl_mck_lock, CLK_SET_RATE_GATE,
|
||||
INT_MIN);
|
||||
&sam9rl_mck_lock);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
||||
@@ -201,8 +201,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
&mck_characteristics, &mck_lock);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
||||
@@ -374,85 +374,6 @@ static void clk_sama7g5_master_best_diff(struct clk_rate_request *req,
|
||||
}
|
||||
}
|
||||
|
||||
static int clk_master_pres_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
struct clk_rate_request req_parent = *req;
|
||||
const struct clk_master_characteristics *characteristics =
|
||||
master->characteristics;
|
||||
struct clk_hw *parent;
|
||||
long best_rate = LONG_MIN, best_diff = LONG_MIN;
|
||||
u32 pres;
|
||||
int i;
|
||||
|
||||
if (master->chg_pid < 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
parent = clk_hw_get_parent_by_index(hw, master->chg_pid);
|
||||
if (!parent)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
for (i = 0; i <= MASTER_PRES_MAX; i++) {
|
||||
if (characteristics->have_div3_pres && i == MASTER_PRES_MAX)
|
||||
pres = 3;
|
||||
else
|
||||
pres = 1 << i;
|
||||
|
||||
req_parent.rate = req->rate * pres;
|
||||
if (__clk_determine_rate(parent, &req_parent))
|
||||
continue;
|
||||
|
||||
clk_sama7g5_master_best_diff(req, parent, req_parent.rate,
|
||||
&best_diff, &best_rate, pres);
|
||||
if (!best_diff)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_master_pres_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
unsigned long flags;
|
||||
unsigned int pres, mckr, tmp;
|
||||
int ret;
|
||||
|
||||
pres = DIV_ROUND_CLOSEST(parent_rate, rate);
|
||||
if (pres > MASTER_PRES_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
else if (pres == 3)
|
||||
pres = MASTER_PRES_MAX;
|
||||
else if (pres)
|
||||
pres = ffs(pres) - 1;
|
||||
|
||||
spin_lock_irqsave(master->lock, flags);
|
||||
ret = regmap_read(master->regmap, master->layout->offset, &mckr);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
|
||||
mckr &= master->layout->mask;
|
||||
tmp = (mckr >> master->layout->pres_shift) & MASTER_PRES_MASK;
|
||||
if (pres == tmp)
|
||||
goto unlock;
|
||||
|
||||
mckr &= ~(MASTER_PRES_MASK << master->layout->pres_shift);
|
||||
mckr |= (pres << master->layout->pres_shift);
|
||||
ret = regmap_write(master->regmap, master->layout->offset, mckr);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
|
||||
while (!clk_master_ready(master))
|
||||
cpu_relax();
|
||||
unlock:
|
||||
spin_unlock_irqrestore(master->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned long clk_master_pres_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
@@ -539,13 +460,6 @@ static void clk_master_pres_restore_context(struct clk_hw *hw)
|
||||
pr_warn("MCKR PRES was not configured properly by firmware!\n");
|
||||
}
|
||||
|
||||
static void clk_master_pres_restore_context_chg(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
|
||||
clk_master_pres_set_rate(hw, master->pms.rate, master->pms.parent_rate);
|
||||
}
|
||||
|
||||
static const struct clk_ops master_pres_ops = {
|
||||
.prepare = clk_master_prepare,
|
||||
.is_prepared = clk_master_is_prepared,
|
||||
@@ -555,25 +469,13 @@ static const struct clk_ops master_pres_ops = {
|
||||
.restore_context = clk_master_pres_restore_context,
|
||||
};
|
||||
|
||||
static const struct clk_ops master_pres_ops_chg = {
|
||||
.prepare = clk_master_prepare,
|
||||
.is_prepared = clk_master_is_prepared,
|
||||
.determine_rate = clk_master_pres_determine_rate,
|
||||
.recalc_rate = clk_master_pres_recalc_rate,
|
||||
.get_parent = clk_master_pres_get_parent,
|
||||
.set_rate = clk_master_pres_set_rate,
|
||||
.save_context = clk_master_pres_save_context,
|
||||
.restore_context = clk_master_pres_restore_context_chg,
|
||||
};
|
||||
|
||||
static struct clk_hw * __init
|
||||
at91_clk_register_master_internal(struct regmap *regmap,
|
||||
const char *name, int num_parents,
|
||||
const char **parent_names,
|
||||
const struct clk_master_layout *layout,
|
||||
const struct clk_master_characteristics *characteristics,
|
||||
const struct clk_ops *ops, spinlock_t *lock, u32 flags,
|
||||
int chg_pid)
|
||||
const struct clk_ops *ops, spinlock_t *lock, u32 flags)
|
||||
{
|
||||
struct clk_master *master;
|
||||
struct clk_init_data init;
|
||||
@@ -599,7 +501,6 @@ at91_clk_register_master_internal(struct regmap *regmap,
|
||||
master->layout = layout;
|
||||
master->characteristics = characteristics;
|
||||
master->regmap = regmap;
|
||||
master->chg_pid = chg_pid;
|
||||
master->lock = lock;
|
||||
|
||||
if (ops == &master_div_ops_chg) {
|
||||
@@ -628,19 +529,13 @@ at91_clk_register_master_pres(struct regmap *regmap,
|
||||
const char **parent_names,
|
||||
const struct clk_master_layout *layout,
|
||||
const struct clk_master_characteristics *characteristics,
|
||||
spinlock_t *lock, u32 flags, int chg_pid)
|
||||
spinlock_t *lock)
|
||||
{
|
||||
const struct clk_ops *ops;
|
||||
|
||||
if (flags & CLK_SET_RATE_GATE)
|
||||
ops = &master_pres_ops;
|
||||
else
|
||||
ops = &master_pres_ops_chg;
|
||||
|
||||
return at91_clk_register_master_internal(regmap, name, num_parents,
|
||||
parent_names, layout,
|
||||
characteristics, ops,
|
||||
lock, flags, chg_pid);
|
||||
characteristics,
|
||||
&master_pres_ops,
|
||||
lock, CLK_SET_RATE_GATE);
|
||||
}
|
||||
|
||||
struct clk_hw * __init
|
||||
@@ -661,7 +556,7 @@ at91_clk_register_master_div(struct regmap *regmap,
|
||||
hw = at91_clk_register_master_internal(regmap, name, 1,
|
||||
&parent_name, layout,
|
||||
characteristics, ops,
|
||||
lock, flags, -EINVAL);
|
||||
lock, flags);
|
||||
|
||||
if (!IS_ERR(hw) && safe_div) {
|
||||
master_div = to_clk_master(hw);
|
||||
|
||||
@@ -392,8 +392,7 @@ of_at91_clk_master_setup(struct device_node *np,
|
||||
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", num_parents,
|
||||
parent_names, layout,
|
||||
characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
characteristics, &mck_lock);
|
||||
if (IS_ERR(hw))
|
||||
goto out_free_characteristics;
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ at91_clk_register_master_pres(struct regmap *regmap, const char *name,
|
||||
int num_parents, const char **parent_names,
|
||||
const struct clk_master_layout *layout,
|
||||
const struct clk_master_characteristics *characteristics,
|
||||
spinlock_t *lock, u32 flags, int chg_pid);
|
||||
spinlock_t *lock);
|
||||
|
||||
struct clk_hw * __init
|
||||
at91_clk_register_master_div(struct regmap *regmap, const char *name,
|
||||
|
||||
@@ -271,8 +271,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
|
||||
parent_names[2] = "pllack_divck";
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 3,
|
||||
parent_names, &sam9x60_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
&mck_characteristics, &mck_lock);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
||||
@@ -168,7 +168,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
sama5d2_pmc = pmc_data_allocate(PMC_AUDIOPLLCK + 1,
|
||||
sama5d2_pmc = pmc_data_allocate(PMC_AUDIOPINCK + 1,
|
||||
nck(sama5d2_systemck),
|
||||
nck(sama5d2_periph32ck),
|
||||
nck(sama5d2_gck), 3);
|
||||
@@ -216,6 +216,8 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
sama5d2_pmc->chws[PMC_AUDIOPINCK] = hw;
|
||||
|
||||
hw = at91_clk_register_audio_pll_pmc(regmap, "audiopll_pmcck",
|
||||
"audiopll_fracck");
|
||||
if (IS_ERR(hw))
|
||||
@@ -240,8 +242,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
&mck_characteristics, &mck_lock);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
||||
@@ -175,8 +175,7 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
&mck_characteristics, &mck_lock);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
||||
@@ -190,8 +190,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
&mck_characteristics, &mck_lock);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
||||
@@ -302,6 +302,7 @@ static const struct {
|
||||
* @ep_count: extra parents count
|
||||
* @ep_mux_table: mux table for extra parents
|
||||
* @id: clock id
|
||||
* @eid: export index in sama7g5->chws[] array
|
||||
* @c: true if clock is critical and cannot be disabled
|
||||
*/
|
||||
static const struct {
|
||||
@@ -311,6 +312,7 @@ static const struct {
|
||||
u8 ep_count;
|
||||
u8 ep_mux_table[4];
|
||||
u8 id;
|
||||
u8 eid;
|
||||
u8 c;
|
||||
} sama7g5_mckx[] = {
|
||||
{ .n = "mck1",
|
||||
@@ -319,6 +321,7 @@ static const struct {
|
||||
.ep_mux_table = { 5, },
|
||||
.ep_count = 1,
|
||||
.ep_chg_id = INT_MIN,
|
||||
.eid = PMC_MCK1,
|
||||
.c = 1, },
|
||||
|
||||
{ .n = "mck2",
|
||||
@@ -696,16 +699,16 @@ static const struct {
|
||||
{ .n = "pdmc0_gclk",
|
||||
.id = 68,
|
||||
.r = { .max = 50000000 },
|
||||
.pp = { "syspll_divpmcck", "baudpll_divpmcck", },
|
||||
.pp_mux_table = { 5, 8, },
|
||||
.pp = { "syspll_divpmcck", "audiopll_divpmcck", },
|
||||
.pp_mux_table = { 5, 9, },
|
||||
.pp_count = 2,
|
||||
.pp_chg_id = INT_MIN, },
|
||||
|
||||
{ .n = "pdmc1_gclk",
|
||||
.id = 69,
|
||||
.r = { .max = 50000000, },
|
||||
.pp = { "syspll_divpmcck", "baudpll_divpmcck", },
|
||||
.pp_mux_table = { 5, 8, },
|
||||
.pp = { "syspll_divpmcck", "audiopll_divpmcck", },
|
||||
.pp_mux_table = { 5, 9, },
|
||||
.pp_count = 2,
|
||||
.pp_chg_id = INT_MIN, },
|
||||
|
||||
@@ -913,7 +916,7 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
sama7g5_pmc = pmc_data_allocate(PMC_CPU + 1,
|
||||
sama7g5_pmc = pmc_data_allocate(PMC_MCK1 + 1,
|
||||
nck(sama7g5_systemck),
|
||||
nck(sama7g5_periphck),
|
||||
nck(sama7g5_gck), 8);
|
||||
@@ -1027,6 +1030,9 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
|
||||
goto err_free;
|
||||
|
||||
alloc_mem[alloc_mem_size++] = mux_table;
|
||||
|
||||
if (sama7g5_mckx[i].eid)
|
||||
sama7g5_pmc->chws[sama7g5_mckx[i].eid] = hw;
|
||||
}
|
||||
|
||||
hw = at91_clk_sama7g5_register_utmi(regmap, "utmick", "main_xtal");
|
||||
|
||||
@@ -535,7 +535,7 @@ static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw)
|
||||
|
||||
/*
|
||||
* Assume that if it has already been selected (for example by the
|
||||
* bootloader), enough time has aready passed.
|
||||
* bootloader), enough time has already passed.
|
||||
*/
|
||||
if ((readl(osc->sckcr) & osc->bits->cr_oscsel)) {
|
||||
osc->prepared = true;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/*
|
||||
* ARTPEC-6 clock initialization
|
||||
*
|
||||
* Copyright 2015-2016 Axis Comunications AB.
|
||||
* Copyright 2015-2016 Axis Communications AB.
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
@@ -939,10 +939,8 @@ static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
|
||||
u32 unused_frac_mask =
|
||||
GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1;
|
||||
u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS;
|
||||
u64 rem;
|
||||
u32 div, mindiv, maxdiv;
|
||||
|
||||
rem = do_div(temp, rate);
|
||||
div = temp;
|
||||
div &= ~unused_frac_mask;
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
* Parameters for VCO frequency configuration
|
||||
*
|
||||
* VCO frequency =
|
||||
* ((ndiv_int + ndiv_frac / 2^20) * (ref freqeuncy / pdiv)
|
||||
* ((ndiv_int + ndiv_frac / 2^20) * (ref frequency / pdiv)
|
||||
*/
|
||||
struct iproc_pll_vco_param {
|
||||
unsigned long rate;
|
||||
|
||||
@@ -510,7 +510,7 @@ static bool kona_clk_valid(struct kona_clk *bcm_clk)
|
||||
* placeholders for non-supported clocks. Keep track of the
|
||||
* position of each clock name in the original array.
|
||||
*
|
||||
* Allocates an array of pointers to to hold the names of all
|
||||
* Allocates an array of pointers to hold the names of all
|
||||
* non-null entries in the original array, and returns a pointer to
|
||||
* that array in *names. This will be used for registering the
|
||||
* clock with the common clock code. On successful return,
|
||||
|
||||
@@ -56,6 +56,8 @@ static char *rpi_firmware_clk_names[] = {
|
||||
#define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0)
|
||||
#define RPI_FIRMWARE_STATE_WAIT_BIT BIT(1)
|
||||
|
||||
struct raspberrypi_clk_variant;
|
||||
|
||||
struct raspberrypi_clk {
|
||||
struct device *dev;
|
||||
struct rpi_firmware *firmware;
|
||||
@@ -66,10 +68,72 @@ struct raspberrypi_clk_data {
|
||||
struct clk_hw hw;
|
||||
|
||||
unsigned int id;
|
||||
struct raspberrypi_clk_variant *variant;
|
||||
|
||||
struct raspberrypi_clk *rpi;
|
||||
};
|
||||
|
||||
struct raspberrypi_clk_variant {
|
||||
bool export;
|
||||
char *clkdev;
|
||||
unsigned long min_rate;
|
||||
bool minimize;
|
||||
};
|
||||
|
||||
static struct raspberrypi_clk_variant
|
||||
raspberrypi_clk_variants[RPI_FIRMWARE_NUM_CLK_ID] = {
|
||||
[RPI_FIRMWARE_ARM_CLK_ID] = {
|
||||
.export = true,
|
||||
.clkdev = "cpu0",
|
||||
},
|
||||
[RPI_FIRMWARE_CORE_CLK_ID] = {
|
||||
.export = true,
|
||||
|
||||
/*
|
||||
* The clock is shared between the HVS and the CSI
|
||||
* controllers, on the BCM2711 and will change depending
|
||||
* on the pixels composited on the HVS and the capture
|
||||
* resolution on Unicam.
|
||||
*
|
||||
* Since the rate can get quite large, and we need to
|
||||
* coordinate between both driver instances, let's
|
||||
* always use the minimum the drivers will let us.
|
||||
*/
|
||||
.minimize = true,
|
||||
},
|
||||
[RPI_FIRMWARE_M2MC_CLK_ID] = {
|
||||
.export = true,
|
||||
|
||||
/*
|
||||
* If we boot without any cable connected to any of the
|
||||
* HDMI connector, the firmware will skip the HSM
|
||||
* initialization and leave it with a rate of 0,
|
||||
* resulting in a bus lockup when we're accessing the
|
||||
* registers even if it's enabled.
|
||||
*
|
||||
* Let's put a sensible default so that we don't end up
|
||||
* in this situation.
|
||||
*/
|
||||
.min_rate = 120000000,
|
||||
|
||||
/*
|
||||
* The clock is shared between the two HDMI controllers
|
||||
* on the BCM2711 and will change depending on the
|
||||
* resolution output on each. Since the rate can get
|
||||
* quite large, and we need to coordinate between both
|
||||
* driver instances, let's always use the minimum the
|
||||
* drivers will let us.
|
||||
*/
|
||||
.minimize = true,
|
||||
},
|
||||
[RPI_FIRMWARE_V3D_CLK_ID] = {
|
||||
.export = true,
|
||||
},
|
||||
[RPI_FIRMWARE_PIXEL_BVB_CLK_ID] = {
|
||||
.export = true,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure of the message passed to Raspberry Pi's firmware in order to
|
||||
* change clock rates. The 'disable_turbo' option is only available to the ARM
|
||||
@@ -165,12 +229,26 @@ static int raspberrypi_fw_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
static int raspberrypi_fw_dumb_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct raspberrypi_clk_data *data =
|
||||
container_of(hw, struct raspberrypi_clk_data, hw);
|
||||
struct raspberrypi_clk_variant *variant = data->variant;
|
||||
|
||||
/*
|
||||
* The firmware will do the rounding but that isn't part of
|
||||
* the interface with the firmware, so we just do our best
|
||||
* here.
|
||||
*/
|
||||
|
||||
req->rate = clamp(req->rate, req->min_rate, req->max_rate);
|
||||
|
||||
/*
|
||||
* We want to aggressively reduce the clock rate here, so let's
|
||||
* just ignore the requested rate and return the bare minimum
|
||||
* rate we can get away with.
|
||||
*/
|
||||
if (variant->minimize && req->min_rate > 0)
|
||||
req->rate = req->min_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -183,7 +261,8 @@ static const struct clk_ops raspberrypi_firmware_clk_ops = {
|
||||
|
||||
static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi,
|
||||
unsigned int parent,
|
||||
unsigned int id)
|
||||
unsigned int id,
|
||||
struct raspberrypi_clk_variant *variant)
|
||||
{
|
||||
struct raspberrypi_clk_data *data;
|
||||
struct clk_init_data init = {};
|
||||
@@ -195,6 +274,7 @@ static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi,
|
||||
return ERR_PTR(-ENOMEM);
|
||||
data->rpi = rpi;
|
||||
data->id = id;
|
||||
data->variant = variant;
|
||||
|
||||
init.name = devm_kasprintf(rpi->dev, GFP_KERNEL,
|
||||
"fw-clk-%s",
|
||||
@@ -228,15 +308,28 @@ static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi,
|
||||
|
||||
clk_hw_set_rate_range(&data->hw, min_rate, max_rate);
|
||||
|
||||
if (id == RPI_FIRMWARE_ARM_CLK_ID) {
|
||||
if (variant->clkdev) {
|
||||
ret = devm_clk_hw_register_clkdev(rpi->dev, &data->hw,
|
||||
NULL, "cpu0");
|
||||
NULL, variant->clkdev);
|
||||
if (ret) {
|
||||
dev_err(rpi->dev, "Failed to initialize clkdev\n");
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
}
|
||||
|
||||
if (variant->min_rate) {
|
||||
unsigned long rate;
|
||||
|
||||
clk_hw_set_rate_range(&data->hw, variant->min_rate, max_rate);
|
||||
|
||||
rate = raspberrypi_fw_get_rate(&data->hw, 0);
|
||||
if (rate < variant->min_rate) {
|
||||
ret = raspberrypi_fw_set_rate(&data->hw, variant->min_rate, 0);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
}
|
||||
|
||||
return &data->hw;
|
||||
}
|
||||
|
||||
@@ -264,27 +357,27 @@ static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi,
|
||||
return ret;
|
||||
|
||||
while (clks->id) {
|
||||
struct clk_hw *hw;
|
||||
struct raspberrypi_clk_variant *variant;
|
||||
|
||||
if (clks->id > RPI_FIRMWARE_NUM_CLK_ID) {
|
||||
dev_err(rpi->dev, "Unknown clock id: %u", clks->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
variant = &raspberrypi_clk_variants[clks->id];
|
||||
if (variant->export) {
|
||||
struct clk_hw *hw;
|
||||
|
||||
switch (clks->id) {
|
||||
case RPI_FIRMWARE_ARM_CLK_ID:
|
||||
case RPI_FIRMWARE_CORE_CLK_ID:
|
||||
case RPI_FIRMWARE_M2MC_CLK_ID:
|
||||
case RPI_FIRMWARE_V3D_CLK_ID:
|
||||
case RPI_FIRMWARE_PIXEL_BVB_CLK_ID:
|
||||
hw = raspberrypi_clk_register(rpi, clks->parent,
|
||||
clks->id);
|
||||
clks->id, variant);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
|
||||
data->hws[clks->id] = hw;
|
||||
data->num = clks->id + 1;
|
||||
fallthrough;
|
||||
|
||||
default:
|
||||
clks++;
|
||||
break;
|
||||
}
|
||||
|
||||
clks++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
334
drivers/clk/clk-apple-nco.c
Normal file
334
drivers/clk/clk-apple-nco.c
Normal file
@@ -0,0 +1,334 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR MIT
|
||||
/*
|
||||
* Driver for an SoC block (Numerically Controlled Oscillator)
|
||||
* found on t8103 (M1) and other Apple chips
|
||||
*
|
||||
* Copyright (C) The Asahi Linux Contributors
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define NCO_CHANNEL_STRIDE 0x4000
|
||||
#define NCO_CHANNEL_REGSIZE 20
|
||||
|
||||
#define REG_CTRL 0
|
||||
#define CTRL_ENABLE BIT(31)
|
||||
#define REG_DIV 4
|
||||
#define DIV_FINE GENMASK(1, 0)
|
||||
#define DIV_COARSE GENMASK(12, 2)
|
||||
#define REG_INC1 8
|
||||
#define REG_INC2 12
|
||||
#define REG_ACCINIT 16
|
||||
|
||||
/*
|
||||
* Theory of operation (postulated)
|
||||
*
|
||||
* The REG_DIV register indirectly expresses a base integer divisor, roughly
|
||||
* corresponding to twice the desired ratio of input to output clock. This
|
||||
* base divisor is adjusted on a cycle-by-cycle basis based on the state of a
|
||||
* 32-bit phase accumulator to achieve a desired precise clock ratio over the
|
||||
* long term.
|
||||
*
|
||||
* Specifically an output clock cycle is produced after (REG_DIV divisor)/2
|
||||
* or (REG_DIV divisor + 1)/2 input cycles, the latter taking effect when top
|
||||
* bit of the 32-bit accumulator is set. The accumulator is incremented each
|
||||
* produced output cycle, by the value from either REG_INC1 or REG_INC2, which
|
||||
* of the two is selected depending again on the accumulator's current top bit.
|
||||
*
|
||||
* Because the NCO hardware implements counting of input clock cycles in part
|
||||
* in a Galois linear-feedback shift register, the higher bits of divisor
|
||||
* are programmed into REG_DIV by picking an appropriate LFSR state. See
|
||||
* applnco_compute_tables/applnco_div_translate for details on this.
|
||||
*/
|
||||
|
||||
#define LFSR_POLY 0xa01
|
||||
#define LFSR_INIT 0x7ff
|
||||
#define LFSR_LEN 11
|
||||
#define LFSR_PERIOD ((1 << LFSR_LEN) - 1)
|
||||
#define LFSR_TBLSIZE (1 << LFSR_LEN)
|
||||
|
||||
/* The minimal attainable coarse divisor (first value in table) */
|
||||
#define COARSE_DIV_OFFSET 2
|
||||
|
||||
struct applnco_tables {
|
||||
u16 fwd[LFSR_TBLSIZE];
|
||||
u16 inv[LFSR_TBLSIZE];
|
||||
};
|
||||
|
||||
struct applnco_channel {
|
||||
void __iomem *base;
|
||||
struct applnco_tables *tbl;
|
||||
struct clk_hw hw;
|
||||
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
#define to_applnco_channel(_hw) container_of(_hw, struct applnco_channel, hw)
|
||||
|
||||
static void applnco_enable_nolock(struct clk_hw *hw)
|
||||
{
|
||||
struct applnco_channel *chan = to_applnco_channel(hw);
|
||||
u32 val;
|
||||
|
||||
val = readl_relaxed(chan->base + REG_CTRL);
|
||||
writel_relaxed(val | CTRL_ENABLE, chan->base + REG_CTRL);
|
||||
}
|
||||
|
||||
static void applnco_disable_nolock(struct clk_hw *hw)
|
||||
{
|
||||
struct applnco_channel *chan = to_applnco_channel(hw);
|
||||
u32 val;
|
||||
|
||||
val = readl_relaxed(chan->base + REG_CTRL);
|
||||
writel_relaxed(val & ~CTRL_ENABLE, chan->base + REG_CTRL);
|
||||
}
|
||||
|
||||
static int applnco_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct applnco_channel *chan = to_applnco_channel(hw);
|
||||
|
||||
return (readl_relaxed(chan->base + REG_CTRL) & CTRL_ENABLE) != 0;
|
||||
}
|
||||
|
||||
static void applnco_compute_tables(struct applnco_tables *tbl)
|
||||
{
|
||||
int i;
|
||||
u32 state = LFSR_INIT;
|
||||
|
||||
/*
|
||||
* Go through the states of a Galois LFSR and build
|
||||
* a coarse divisor translation table.
|
||||
*/
|
||||
for (i = LFSR_PERIOD; i > 0; i--) {
|
||||
if (state & 1)
|
||||
state = (state >> 1) ^ (LFSR_POLY >> 1);
|
||||
else
|
||||
state = (state >> 1);
|
||||
tbl->fwd[i] = state;
|
||||
tbl->inv[state] = i;
|
||||
}
|
||||
|
||||
/* Zero value is special-cased */
|
||||
tbl->fwd[0] = 0;
|
||||
tbl->inv[0] = 0;
|
||||
}
|
||||
|
||||
static bool applnco_div_out_of_range(unsigned int div)
|
||||
{
|
||||
unsigned int coarse = div / 4;
|
||||
|
||||
return coarse < COARSE_DIV_OFFSET ||
|
||||
coarse >= COARSE_DIV_OFFSET + LFSR_TBLSIZE;
|
||||
}
|
||||
|
||||
static u32 applnco_div_translate(struct applnco_tables *tbl, unsigned int div)
|
||||
{
|
||||
unsigned int coarse = div / 4;
|
||||
|
||||
if (WARN_ON(applnco_div_out_of_range(div)))
|
||||
return 0;
|
||||
|
||||
return FIELD_PREP(DIV_COARSE, tbl->fwd[coarse - COARSE_DIV_OFFSET]) |
|
||||
FIELD_PREP(DIV_FINE, div % 4);
|
||||
}
|
||||
|
||||
static unsigned int applnco_div_translate_inv(struct applnco_tables *tbl, u32 regval)
|
||||
{
|
||||
unsigned int coarse, fine;
|
||||
|
||||
coarse = tbl->inv[FIELD_GET(DIV_COARSE, regval)] + COARSE_DIV_OFFSET;
|
||||
fine = FIELD_GET(DIV_FINE, regval);
|
||||
|
||||
return coarse * 4 + fine;
|
||||
}
|
||||
|
||||
static int applnco_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct applnco_channel *chan = to_applnco_channel(hw);
|
||||
unsigned long flags;
|
||||
u32 div, inc1, inc2;
|
||||
bool was_enabled;
|
||||
|
||||
div = 2 * parent_rate / rate;
|
||||
inc1 = 2 * parent_rate - div * rate;
|
||||
inc2 = inc1 - rate;
|
||||
|
||||
if (applnco_div_out_of_range(div))
|
||||
return -EINVAL;
|
||||
|
||||
div = applnco_div_translate(chan->tbl, div);
|
||||
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
was_enabled = applnco_is_enabled(hw);
|
||||
applnco_disable_nolock(hw);
|
||||
|
||||
writel_relaxed(div, chan->base + REG_DIV);
|
||||
writel_relaxed(inc1, chan->base + REG_INC1);
|
||||
writel_relaxed(inc2, chan->base + REG_INC2);
|
||||
|
||||
/* Presumably a neutral initial value for accumulator */
|
||||
writel_relaxed(1 << 31, chan->base + REG_ACCINIT);
|
||||
|
||||
if (was_enabled)
|
||||
applnco_enable_nolock(hw);
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long applnco_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct applnco_channel *chan = to_applnco_channel(hw);
|
||||
u32 div, inc1, inc2, incbase;
|
||||
|
||||
div = applnco_div_translate_inv(chan->tbl,
|
||||
readl_relaxed(chan->base + REG_DIV));
|
||||
|
||||
inc1 = readl_relaxed(chan->base + REG_INC1);
|
||||
inc2 = readl_relaxed(chan->base + REG_INC2);
|
||||
|
||||
/*
|
||||
* We don't support wraparound of accumulator
|
||||
* nor the edge case of both increments being zero
|
||||
*/
|
||||
if (inc1 >= (1 << 31) || inc2 < (1 << 31) || (inc1 == 0 && inc2 == 0))
|
||||
return 0;
|
||||
|
||||
/* Scale both sides of division by incbase to maintain precision */
|
||||
incbase = inc1 - inc2;
|
||||
|
||||
return div64_u64(((u64) parent_rate) * 2 * incbase,
|
||||
((u64) div) * incbase + inc1);
|
||||
}
|
||||
|
||||
static long applnco_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
unsigned long lo = *parent_rate / (COARSE_DIV_OFFSET + LFSR_TBLSIZE) + 1;
|
||||
unsigned long hi = *parent_rate / COARSE_DIV_OFFSET;
|
||||
|
||||
return clamp(rate, lo, hi);
|
||||
}
|
||||
|
||||
static int applnco_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct applnco_channel *chan = to_applnco_channel(hw);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
applnco_enable_nolock(hw);
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void applnco_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct applnco_channel *chan = to_applnco_channel(hw);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
applnco_disable_nolock(hw);
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
}
|
||||
|
||||
static const struct clk_ops applnco_ops = {
|
||||
.set_rate = applnco_set_rate,
|
||||
.recalc_rate = applnco_recalc_rate,
|
||||
.round_rate = applnco_round_rate,
|
||||
.enable = applnco_enable,
|
||||
.disable = applnco_disable,
|
||||
.is_enabled = applnco_is_enabled,
|
||||
};
|
||||
|
||||
static int applnco_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct clk_parent_data pdata = { .index = 0 };
|
||||
struct clk_init_data init;
|
||||
struct clk_hw_onecell_data *onecell_data;
|
||||
void __iomem *base;
|
||||
struct resource *res;
|
||||
struct applnco_tables *tbl;
|
||||
unsigned int nchannels;
|
||||
int ret, i;
|
||||
|
||||
base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
if (resource_size(res) < NCO_CHANNEL_REGSIZE)
|
||||
return -EINVAL;
|
||||
nchannels = (resource_size(res) - NCO_CHANNEL_REGSIZE)
|
||||
/ NCO_CHANNEL_STRIDE + 1;
|
||||
|
||||
onecell_data = devm_kzalloc(&pdev->dev, struct_size(onecell_data, hws,
|
||||
nchannels), GFP_KERNEL);
|
||||
if (!onecell_data)
|
||||
return -ENOMEM;
|
||||
onecell_data->num = nchannels;
|
||||
|
||||
tbl = devm_kzalloc(&pdev->dev, sizeof(*tbl), GFP_KERNEL);
|
||||
if (!tbl)
|
||||
return -ENOMEM;
|
||||
applnco_compute_tables(tbl);
|
||||
|
||||
for (i = 0; i < nchannels; i++) {
|
||||
struct applnco_channel *chan;
|
||||
|
||||
chan = devm_kzalloc(&pdev->dev, sizeof(*chan), GFP_KERNEL);
|
||||
if (!chan)
|
||||
return -ENOMEM;
|
||||
chan->base = base + NCO_CHANNEL_STRIDE * i;
|
||||
chan->tbl = tbl;
|
||||
spin_lock_init(&chan->lock);
|
||||
|
||||
memset(&init, 0, sizeof(init));
|
||||
init.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
|
||||
"%s-%d", np->name, i);
|
||||
init.ops = &applnco_ops;
|
||||
init.parent_data = &pdata;
|
||||
init.num_parents = 1;
|
||||
init.flags = 0;
|
||||
|
||||
chan->hw.init = &init;
|
||||
ret = devm_clk_hw_register(&pdev->dev, &chan->hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
onecell_data->hws[i] = &chan->hw;
|
||||
}
|
||||
|
||||
return devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get,
|
||||
onecell_data);
|
||||
}
|
||||
|
||||
static const struct of_device_id applnco_ids[] = {
|
||||
{ .compatible = "apple,nco" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, applnco_ids);
|
||||
|
||||
static struct platform_driver applnco_driver = {
|
||||
.driver = {
|
||||
.name = "apple-nco",
|
||||
.of_match_table = applnco_ids,
|
||||
},
|
||||
.probe = applnco_probe,
|
||||
};
|
||||
module_platform_driver(applnco_driver);
|
||||
|
||||
MODULE_AUTHOR("Martin Povišer <povik+lin@cutebit.org>");
|
||||
MODULE_DESCRIPTION("Clock driver for NCO blocks on Apple SoCs");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -28,11 +28,13 @@ static const struct clk_div_table spi_div_table[] = {
|
||||
{ .val = 1, .div = 8, },
|
||||
{ .val = 2, .div = 2, },
|
||||
{ .val = 3, .div = 1, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static const struct clk_div_table timer_div_table[] = {
|
||||
{ .val = 0, .div = 256, },
|
||||
{ .val = 1, .div = 1, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
struct clps711x_clk {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define CH_MAX 4
|
||||
#define RATIO_REG_SIZE 4
|
||||
@@ -39,6 +40,8 @@
|
||||
/* DEVICE_CFG1 */
|
||||
#define RSEL(x) (((x) & 0x3) << 3)
|
||||
#define RSEL_MASK RSEL(0x3)
|
||||
#define AUXOUTSRC(x) (((x) & 0x3) << 1)
|
||||
#define AUXOUTSRC_MASK AUXOUTSRC(0x3)
|
||||
#define ENDEV1 (0x1)
|
||||
|
||||
/* DEVICE_CFG2 */
|
||||
@@ -47,9 +50,10 @@
|
||||
#define LOCKCLK_MASK LOCKCLK(0x3)
|
||||
#define FRACNSRC_MASK (1 << 0)
|
||||
#define FRACNSRC_STATIC (0 << 0)
|
||||
#define FRACNSRC_DYNAMIC (1 << 1)
|
||||
#define FRACNSRC_DYNAMIC (1 << 0)
|
||||
|
||||
/* GLOBAL_CFG */
|
||||
#define FREEZE (1 << 7)
|
||||
#define ENDEV2 (0x1)
|
||||
|
||||
/* FUNC_CFG1 */
|
||||
@@ -71,11 +75,40 @@
|
||||
#define REF_CLK 1
|
||||
#define CLK_MAX 2
|
||||
|
||||
static bool cs2000_readable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return reg > 0;
|
||||
}
|
||||
|
||||
static bool cs2000_writeable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return reg != DEVICE_ID;
|
||||
}
|
||||
|
||||
static bool cs2000_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return reg == DEVICE_CTRL;
|
||||
}
|
||||
|
||||
static const struct regmap_config cs2000_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = FUNC_CFG2,
|
||||
.readable_reg = cs2000_readable_reg,
|
||||
.writeable_reg = cs2000_writeable_reg,
|
||||
.volatile_reg = cs2000_volatile_reg,
|
||||
};
|
||||
|
||||
struct cs2000_priv {
|
||||
struct clk_hw hw;
|
||||
struct i2c_client *client;
|
||||
struct clk *clk_in;
|
||||
struct clk *ref_clk;
|
||||
struct regmap *regmap;
|
||||
|
||||
bool dynamic_mode;
|
||||
bool lf_ratio;
|
||||
bool clk_skip;
|
||||
|
||||
/* suspend/resume */
|
||||
unsigned long saved_rate;
|
||||
@@ -94,55 +127,30 @@ static const struct i2c_device_id cs2000_id[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cs2000_id);
|
||||
|
||||
#define cs2000_read(priv, addr) \
|
||||
i2c_smbus_read_byte_data(priv_to_client(priv), addr)
|
||||
#define cs2000_write(priv, addr, val) \
|
||||
i2c_smbus_write_byte_data(priv_to_client(priv), addr, val)
|
||||
|
||||
static int cs2000_bset(struct cs2000_priv *priv, u8 addr, u8 mask, u8 val)
|
||||
{
|
||||
s32 data;
|
||||
|
||||
data = cs2000_read(priv, addr);
|
||||
if (data < 0)
|
||||
return data;
|
||||
|
||||
data &= ~mask;
|
||||
data |= (val & mask);
|
||||
|
||||
return cs2000_write(priv, addr, data);
|
||||
}
|
||||
|
||||
static int cs2000_enable_dev_config(struct cs2000_priv *priv, bool enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = cs2000_bset(priv, DEVICE_CFG1, ENDEV1,
|
||||
enable ? ENDEV1 : 0);
|
||||
ret = regmap_update_bits(priv->regmap, DEVICE_CFG1, ENDEV1,
|
||||
enable ? ENDEV1 : 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = cs2000_bset(priv, GLOBAL_CFG, ENDEV2,
|
||||
enable ? ENDEV2 : 0);
|
||||
ret = regmap_update_bits(priv->regmap, GLOBAL_CFG, ENDEV2,
|
||||
enable ? ENDEV2 : 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = cs2000_bset(priv, FUNC_CFG1, CLKSKIPEN,
|
||||
enable ? CLKSKIPEN : 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* FIXME: for Static ratio mode */
|
||||
ret = cs2000_bset(priv, FUNC_CFG2, LFRATIO_MASK,
|
||||
LFRATIO_12_20);
|
||||
ret = regmap_update_bits(priv->regmap, FUNC_CFG1, CLKSKIPEN,
|
||||
(enable && priv->clk_skip) ? CLKSKIPEN : 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs2000_clk_in_bound_rate(struct cs2000_priv *priv,
|
||||
u32 rate_in)
|
||||
static int cs2000_ref_clk_bound_rate(struct cs2000_priv *priv,
|
||||
u32 rate_in)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
@@ -155,21 +163,21 @@ static int cs2000_clk_in_bound_rate(struct cs2000_priv *priv,
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return cs2000_bset(priv, FUNC_CFG1,
|
||||
REFCLKDIV_MASK,
|
||||
REFCLKDIV(val));
|
||||
return regmap_update_bits(priv->regmap, FUNC_CFG1,
|
||||
REFCLKDIV_MASK,
|
||||
REFCLKDIV(val));
|
||||
}
|
||||
|
||||
static int cs2000_wait_pll_lock(struct cs2000_priv *priv)
|
||||
{
|
||||
struct device *dev = priv_to_dev(priv);
|
||||
s32 val;
|
||||
unsigned int i;
|
||||
unsigned int i, val;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
val = cs2000_read(priv, DEVICE_CTRL);
|
||||
if (val < 0)
|
||||
return val;
|
||||
ret = regmap_read(priv->regmap, DEVICE_CTRL, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (!(val & PLL_UNLOCK))
|
||||
return 0;
|
||||
udelay(1);
|
||||
@@ -183,41 +191,43 @@ static int cs2000_wait_pll_lock(struct cs2000_priv *priv)
|
||||
static int cs2000_clk_out_enable(struct cs2000_priv *priv, bool enable)
|
||||
{
|
||||
/* enable both AUX_OUT, CLK_OUT */
|
||||
return cs2000_bset(priv, DEVICE_CTRL,
|
||||
(AUXOUTDIS | CLKOUTDIS),
|
||||
enable ? 0 :
|
||||
(AUXOUTDIS | CLKOUTDIS));
|
||||
return regmap_update_bits(priv->regmap, DEVICE_CTRL,
|
||||
(AUXOUTDIS | CLKOUTDIS),
|
||||
enable ? 0 :
|
||||
(AUXOUTDIS | CLKOUTDIS));
|
||||
}
|
||||
|
||||
static u32 cs2000_rate_to_ratio(u32 rate_in, u32 rate_out)
|
||||
static u32 cs2000_rate_to_ratio(u32 rate_in, u32 rate_out, bool lf_ratio)
|
||||
{
|
||||
u64 ratio;
|
||||
u32 multiplier = lf_ratio ? 12 : 20;
|
||||
|
||||
/*
|
||||
* ratio = rate_out / rate_in * 2^20
|
||||
* ratio = rate_out / rate_in * 2^multiplier
|
||||
*
|
||||
* To avoid over flow, rate_out is u64.
|
||||
* The result should be u32.
|
||||
*/
|
||||
ratio = (u64)rate_out << 20;
|
||||
ratio = (u64)rate_out << multiplier;
|
||||
do_div(ratio, rate_in);
|
||||
|
||||
return ratio;
|
||||
}
|
||||
|
||||
static unsigned long cs2000_ratio_to_rate(u32 ratio, u32 rate_in)
|
||||
static unsigned long cs2000_ratio_to_rate(u32 ratio, u32 rate_in, bool lf_ratio)
|
||||
{
|
||||
u64 rate_out;
|
||||
u32 multiplier = lf_ratio ? 12 : 20;
|
||||
|
||||
/*
|
||||
* ratio = rate_out / rate_in * 2^20
|
||||
* ratio = rate_out / rate_in * 2^multiplier
|
||||
*
|
||||
* To avoid over flow, rate_out is u64.
|
||||
* The result should be u32 or unsigned long.
|
||||
*/
|
||||
|
||||
rate_out = (u64)ratio * rate_in;
|
||||
return rate_out >> 20;
|
||||
return rate_out >> multiplier;
|
||||
}
|
||||
|
||||
static int cs2000_ratio_set(struct cs2000_priv *priv,
|
||||
@@ -230,9 +240,9 @@ static int cs2000_ratio_set(struct cs2000_priv *priv,
|
||||
if (CH_SIZE_ERR(ch))
|
||||
return -EINVAL;
|
||||
|
||||
val = cs2000_rate_to_ratio(rate_in, rate_out);
|
||||
val = cs2000_rate_to_ratio(rate_in, rate_out, priv->lf_ratio);
|
||||
for (i = 0; i < RATIO_REG_SIZE; i++) {
|
||||
ret = cs2000_write(priv,
|
||||
ret = regmap_write(priv->regmap,
|
||||
Ratio_Add(ch, i),
|
||||
Ratio_Val(val, i));
|
||||
if (ret < 0)
|
||||
@@ -244,14 +254,14 @@ static int cs2000_ratio_set(struct cs2000_priv *priv,
|
||||
|
||||
static u32 cs2000_ratio_get(struct cs2000_priv *priv, int ch)
|
||||
{
|
||||
s32 tmp;
|
||||
unsigned int tmp, i;
|
||||
u32 val;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
val = 0;
|
||||
for (i = 0; i < RATIO_REG_SIZE; i++) {
|
||||
tmp = cs2000_read(priv, Ratio_Add(ch, i));
|
||||
if (tmp < 0)
|
||||
ret = regmap_read(priv->regmap, Ratio_Add(ch, i), &tmp);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
|
||||
val |= Val_Ratio(tmp, i);
|
||||
@@ -263,22 +273,20 @@ static u32 cs2000_ratio_get(struct cs2000_priv *priv, int ch)
|
||||
static int cs2000_ratio_select(struct cs2000_priv *priv, int ch)
|
||||
{
|
||||
int ret;
|
||||
u8 fracnsrc;
|
||||
|
||||
if (CH_SIZE_ERR(ch))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* FIXME
|
||||
*
|
||||
* this driver supports static ratio mode only at this point.
|
||||
*/
|
||||
ret = cs2000_bset(priv, DEVICE_CFG1, RSEL_MASK, RSEL(ch));
|
||||
ret = regmap_update_bits(priv->regmap, DEVICE_CFG1, RSEL_MASK, RSEL(ch));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = cs2000_bset(priv, DEVICE_CFG2,
|
||||
(AUTORMOD | LOCKCLK_MASK | FRACNSRC_MASK),
|
||||
(LOCKCLK(ch) | FRACNSRC_STATIC));
|
||||
fracnsrc = priv->dynamic_mode ? FRACNSRC_DYNAMIC : FRACNSRC_STATIC;
|
||||
|
||||
ret = regmap_update_bits(priv->regmap, DEVICE_CFG2,
|
||||
AUTORMOD | LOCKCLK_MASK | FRACNSRC_MASK,
|
||||
LOCKCLK(ch) | fracnsrc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -294,17 +302,39 @@ static unsigned long cs2000_recalc_rate(struct clk_hw *hw,
|
||||
|
||||
ratio = cs2000_ratio_get(priv, ch);
|
||||
|
||||
return cs2000_ratio_to_rate(ratio, parent_rate);
|
||||
return cs2000_ratio_to_rate(ratio, parent_rate, priv->lf_ratio);
|
||||
}
|
||||
|
||||
static long cs2000_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct cs2000_priv *priv = hw_to_priv(hw);
|
||||
u32 ratio;
|
||||
|
||||
ratio = cs2000_rate_to_ratio(*parent_rate, rate);
|
||||
ratio = cs2000_rate_to_ratio(*parent_rate, rate, priv->lf_ratio);
|
||||
|
||||
return cs2000_ratio_to_rate(ratio, *parent_rate);
|
||||
return cs2000_ratio_to_rate(ratio, *parent_rate, priv->lf_ratio);
|
||||
}
|
||||
|
||||
static int cs2000_select_ratio_mode(struct cs2000_priv *priv,
|
||||
unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
/*
|
||||
* From the datasheet:
|
||||
*
|
||||
* | It is recommended that the 12.20 High-Resolution format be
|
||||
* | utilized whenever the desired ratio is less than 4096 since
|
||||
* | the output frequency accuracy of the PLL is directly proportional
|
||||
* | to the accuracy of the timing reference clock and the resolution
|
||||
* | of the R_UD.
|
||||
*
|
||||
* This mode is only available in dynamic mode.
|
||||
*/
|
||||
priv->lf_ratio = priv->dynamic_mode && ((rate / parent_rate) > 4096);
|
||||
|
||||
return regmap_update_bits(priv->regmap, FUNC_CFG2, LFRATIO_MASK,
|
||||
priv->lf_ratio ? LFRATIO_20_12 : LFRATIO_12_20);
|
||||
}
|
||||
|
||||
static int __cs2000_set_rate(struct cs2000_priv *priv, int ch,
|
||||
@@ -313,7 +343,11 @@ static int __cs2000_set_rate(struct cs2000_priv *priv, int ch,
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = cs2000_clk_in_bound_rate(priv, parent_rate);
|
||||
ret = regmap_update_bits(priv->regmap, GLOBAL_CFG, FREEZE, FREEZE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = cs2000_select_ratio_mode(priv, rate, parent_rate);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -325,6 +359,10 @@ static int __cs2000_set_rate(struct cs2000_priv *priv, int ch,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_update_bits(priv->regmap, GLOBAL_CFG, FREEZE, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
priv->saved_rate = rate;
|
||||
priv->saved_parent_rate = parent_rate;
|
||||
|
||||
@@ -380,8 +418,13 @@ static void cs2000_disable(struct clk_hw *hw)
|
||||
|
||||
static u8 cs2000_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
/* always return REF_CLK */
|
||||
return REF_CLK;
|
||||
struct cs2000_priv *priv = hw_to_priv(hw);
|
||||
|
||||
/*
|
||||
* In dynamic mode, output rates are derived from CLK_IN.
|
||||
* In static mode, CLK_IN is ignored, so we return REF_CLK instead.
|
||||
*/
|
||||
return priv->dynamic_mode ? CLK_IN : REF_CLK;
|
||||
}
|
||||
|
||||
static const struct clk_ops cs2000_ops = {
|
||||
@@ -421,22 +464,44 @@ static int cs2000_clk_register(struct cs2000_priv *priv)
|
||||
struct clk_init_data init;
|
||||
const char *name = np->name;
|
||||
static const char *parent_names[CLK_MAX];
|
||||
u32 aux_out = 0;
|
||||
int ref_clk_rate;
|
||||
int ch = 0; /* it uses ch0 only at this point */
|
||||
int rate;
|
||||
int ret;
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
|
||||
/*
|
||||
* set default rate as 1/1.
|
||||
* otherwise .set_rate which setup ratio
|
||||
* is never called if user requests 1/1 rate
|
||||
*/
|
||||
rate = clk_get_rate(priv->ref_clk);
|
||||
ret = __cs2000_set_rate(priv, ch, rate, rate);
|
||||
priv->dynamic_mode = of_property_read_bool(np, "cirrus,dynamic-mode");
|
||||
dev_info(dev, "operating in %s mode\n",
|
||||
priv->dynamic_mode ? "dynamic" : "static");
|
||||
|
||||
of_property_read_u32(np, "cirrus,aux-output-source", &aux_out);
|
||||
ret = regmap_update_bits(priv->regmap, DEVICE_CFG1,
|
||||
AUXOUTSRC_MASK, AUXOUTSRC(aux_out));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
priv->clk_skip = of_property_read_bool(np, "cirrus,clock-skip");
|
||||
|
||||
ref_clk_rate = clk_get_rate(priv->ref_clk);
|
||||
ret = cs2000_ref_clk_bound_rate(priv, ref_clk_rate);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (priv->dynamic_mode) {
|
||||
/* Default to low-frequency mode to allow for large ratios */
|
||||
priv->lf_ratio = true;
|
||||
} else {
|
||||
/*
|
||||
* set default rate as 1/1.
|
||||
* otherwise .set_rate which setup ratio
|
||||
* is never called if user requests 1/1 rate
|
||||
*/
|
||||
ret = __cs2000_set_rate(priv, ch, ref_clk_rate, ref_clk_rate);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
parent_names[CLK_IN] = __clk_get_name(priv->clk_in);
|
||||
parent_names[REF_CLK] = __clk_get_name(priv->ref_clk);
|
||||
|
||||
@@ -464,12 +529,13 @@ static int cs2000_clk_register(struct cs2000_priv *priv)
|
||||
static int cs2000_version_print(struct cs2000_priv *priv)
|
||||
{
|
||||
struct device *dev = priv_to_dev(priv);
|
||||
s32 val;
|
||||
const char *revision;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
val = cs2000_read(priv, DEVICE_ID);
|
||||
if (val < 0)
|
||||
return val;
|
||||
ret = regmap_read(priv->regmap, DEVICE_ID, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* CS2000 should be 0x0 */
|
||||
if (val >> 3)
|
||||
@@ -518,6 +584,10 @@ static int cs2000_probe(struct i2c_client *client,
|
||||
priv->client = client;
|
||||
i2c_set_clientdata(client, priv);
|
||||
|
||||
priv->regmap = devm_regmap_init_i2c(client, &cs2000_regmap_config);
|
||||
if (IS_ERR(priv->regmap))
|
||||
return PTR_ERR(priv->regmap);
|
||||
|
||||
ret = cs2000_clk_get(priv);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -131,6 +131,28 @@ __clk_hw_register_fixed_factor(struct device *dev, struct device_node *np,
|
||||
return hw;
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_clk_hw_register_fixed_factor_index - Register a fixed factor clock with
|
||||
* parent from DT index
|
||||
* @dev: device that is registering this clock
|
||||
* @name: name of this clock
|
||||
* @index: index of phandle in @dev 'clocks' property
|
||||
* @flags: fixed factor flags
|
||||
* @mult: multiplier
|
||||
* @div: divider
|
||||
*
|
||||
* Return: Pointer to fixed factor clk_hw structure that was registered or
|
||||
* an error pointer.
|
||||
*/
|
||||
struct clk_hw *devm_clk_hw_register_fixed_factor_index(struct device *dev,
|
||||
const char *name, unsigned int index, unsigned long flags,
|
||||
unsigned int mult, unsigned int div)
|
||||
{
|
||||
return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, index,
|
||||
flags, mult, div, true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor_index);
|
||||
|
||||
struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
|
||||
const char *name, const char *parent_name, unsigned long flags,
|
||||
unsigned int mult, unsigned int div)
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
* and assume that the IP, that needs m and n, has also its own
|
||||
* prescaler, which is capable to divide by 2^scale. In this way
|
||||
* we get the denominator to satisfy the desired range (2) and
|
||||
* at the same time much much better result of m and n than simple
|
||||
* at the same time a much better result of m and n than simple
|
||||
* saturated values.
|
||||
*/
|
||||
|
||||
|
||||
464
drivers/clk/clk-gate_test.c
Normal file
464
drivers/clk/clk-gate_test.c
Normal file
@@ -0,0 +1,464 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Kunit test for clk gate basic type
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <kunit/test.h>
|
||||
|
||||
static void clk_gate_register_test_dev(struct kunit *test)
|
||||
{
|
||||
struct clk_hw *ret;
|
||||
struct platform_device *pdev;
|
||||
|
||||
pdev = platform_device_register_simple("test_gate_device", -1, NULL, 0);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
|
||||
|
||||
ret = clk_hw_register_gate(&pdev->dev, "test_gate", NULL, 0, NULL,
|
||||
0, 0, NULL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret);
|
||||
KUNIT_EXPECT_STREQ(test, "test_gate", clk_hw_get_name(ret));
|
||||
KUNIT_EXPECT_EQ(test, 0UL, clk_hw_get_flags(ret));
|
||||
|
||||
clk_hw_unregister_gate(ret);
|
||||
platform_device_put(pdev);
|
||||
}
|
||||
|
||||
static void clk_gate_register_test_parent_names(struct kunit *test)
|
||||
{
|
||||
struct clk_hw *parent;
|
||||
struct clk_hw *ret;
|
||||
|
||||
parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
|
||||
1000000);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
|
||||
|
||||
ret = clk_hw_register_gate(NULL, "test_gate", "test_parent", 0, NULL,
|
||||
0, 0, NULL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret);
|
||||
KUNIT_EXPECT_PTR_EQ(test, parent, clk_hw_get_parent(ret));
|
||||
|
||||
clk_hw_unregister_gate(ret);
|
||||
clk_hw_unregister_fixed_rate(parent);
|
||||
}
|
||||
|
||||
static void clk_gate_register_test_parent_data(struct kunit *test)
|
||||
{
|
||||
struct clk_hw *parent;
|
||||
struct clk_hw *ret;
|
||||
struct clk_parent_data pdata = { };
|
||||
|
||||
parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
|
||||
1000000);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
|
||||
pdata.hw = parent;
|
||||
|
||||
ret = clk_hw_register_gate_parent_data(NULL, "test_gate", &pdata, 0,
|
||||
NULL, 0, 0, NULL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret);
|
||||
KUNIT_EXPECT_PTR_EQ(test, parent, clk_hw_get_parent(ret));
|
||||
|
||||
clk_hw_unregister_gate(ret);
|
||||
clk_hw_unregister_fixed_rate(parent);
|
||||
}
|
||||
|
||||
static void clk_gate_register_test_parent_data_legacy(struct kunit *test)
|
||||
{
|
||||
struct clk_hw *parent;
|
||||
struct clk_hw *ret;
|
||||
struct clk_parent_data pdata = { };
|
||||
|
||||
parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
|
||||
1000000);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
|
||||
pdata.name = "test_parent";
|
||||
|
||||
ret = clk_hw_register_gate_parent_data(NULL, "test_gate", &pdata, 0,
|
||||
NULL, 0, 0, NULL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret);
|
||||
KUNIT_EXPECT_PTR_EQ(test, parent, clk_hw_get_parent(ret));
|
||||
|
||||
clk_hw_unregister_gate(ret);
|
||||
clk_hw_unregister_fixed_rate(parent);
|
||||
}
|
||||
|
||||
static void clk_gate_register_test_parent_hw(struct kunit *test)
|
||||
{
|
||||
struct clk_hw *parent;
|
||||
struct clk_hw *ret;
|
||||
|
||||
parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
|
||||
1000000);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
|
||||
|
||||
ret = clk_hw_register_gate_parent_hw(NULL, "test_gate", parent, 0, NULL,
|
||||
0, 0, NULL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret);
|
||||
KUNIT_EXPECT_PTR_EQ(test, parent, clk_hw_get_parent(ret));
|
||||
|
||||
clk_hw_unregister_gate(ret);
|
||||
clk_hw_unregister_fixed_rate(parent);
|
||||
}
|
||||
|
||||
static void clk_gate_register_test_hiword_invalid(struct kunit *test)
|
||||
{
|
||||
struct clk_hw *ret;
|
||||
|
||||
ret = clk_hw_register_gate(NULL, "test_gate", NULL, 0, NULL,
|
||||
20, CLK_GATE_HIWORD_MASK, NULL);
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, IS_ERR(ret));
|
||||
}
|
||||
|
||||
static struct kunit_case clk_gate_register_test_cases[] = {
|
||||
KUNIT_CASE(clk_gate_register_test_dev),
|
||||
KUNIT_CASE(clk_gate_register_test_parent_names),
|
||||
KUNIT_CASE(clk_gate_register_test_parent_data),
|
||||
KUNIT_CASE(clk_gate_register_test_parent_data_legacy),
|
||||
KUNIT_CASE(clk_gate_register_test_parent_hw),
|
||||
KUNIT_CASE(clk_gate_register_test_hiword_invalid),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite clk_gate_register_test_suite = {
|
||||
.name = "clk-gate-register-test",
|
||||
.test_cases = clk_gate_register_test_cases,
|
||||
};
|
||||
|
||||
struct clk_gate_test_context {
|
||||
void __iomem *fake_mem;
|
||||
struct clk_hw *hw;
|
||||
struct clk_hw *parent;
|
||||
u32 fake_reg; /* Keep at end, KASAN can detect out of bounds */
|
||||
};
|
||||
|
||||
static struct clk_gate_test_context *clk_gate_test_alloc_ctx(struct kunit *test)
|
||||
{
|
||||
struct clk_gate_test_context *ctx;
|
||||
|
||||
test->priv = ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
|
||||
ctx->fake_mem = (void __force __iomem *)&ctx->fake_reg;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static void clk_gate_test_parent_rate(struct kunit *test)
|
||||
{
|
||||
struct clk_gate_test_context *ctx = test->priv;
|
||||
struct clk_hw *parent = ctx->parent;
|
||||
struct clk_hw *hw = ctx->hw;
|
||||
unsigned long prate = clk_hw_get_rate(parent);
|
||||
unsigned long rate = clk_hw_get_rate(hw);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, prate, rate);
|
||||
}
|
||||
|
||||
static void clk_gate_test_enable(struct kunit *test)
|
||||
{
|
||||
struct clk_gate_test_context *ctx = test->priv;
|
||||
struct clk_hw *parent = ctx->parent;
|
||||
struct clk_hw *hw = ctx->hw;
|
||||
struct clk *clk = hw->clk;
|
||||
u32 enable_val = BIT(5);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, enable_val, ctx->fake_reg);
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw));
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw));
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent));
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(parent));
|
||||
}
|
||||
|
||||
static void clk_gate_test_disable(struct kunit *test)
|
||||
{
|
||||
struct clk_gate_test_context *ctx = test->priv;
|
||||
struct clk_hw *parent = ctx->parent;
|
||||
struct clk_hw *hw = ctx->hw;
|
||||
struct clk *clk = hw->clk;
|
||||
u32 enable_val = BIT(5);
|
||||
u32 disable_val = 0;
|
||||
|
||||
KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
|
||||
KUNIT_ASSERT_EQ(test, enable_val, ctx->fake_reg);
|
||||
|
||||
clk_disable_unprepare(clk);
|
||||
KUNIT_EXPECT_EQ(test, disable_val, ctx->fake_reg);
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw));
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw));
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent));
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(parent));
|
||||
}
|
||||
|
||||
static struct kunit_case clk_gate_test_cases[] = {
|
||||
KUNIT_CASE(clk_gate_test_parent_rate),
|
||||
KUNIT_CASE(clk_gate_test_enable),
|
||||
KUNIT_CASE(clk_gate_test_disable),
|
||||
{}
|
||||
};
|
||||
|
||||
static int clk_gate_test_init(struct kunit *test)
|
||||
{
|
||||
struct clk_hw *parent;
|
||||
struct clk_hw *hw;
|
||||
struct clk_gate_test_context *ctx;
|
||||
|
||||
ctx = clk_gate_test_alloc_ctx(test);
|
||||
parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
|
||||
2000000);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
|
||||
|
||||
hw = clk_hw_register_gate_parent_hw(NULL, "test_gate", parent, 0,
|
||||
ctx->fake_mem, 5, 0, NULL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
|
||||
|
||||
ctx->hw = hw;
|
||||
ctx->parent = parent;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_gate_test_exit(struct kunit *test)
|
||||
{
|
||||
struct clk_gate_test_context *ctx = test->priv;
|
||||
|
||||
clk_hw_unregister_gate(ctx->hw);
|
||||
clk_hw_unregister_fixed_rate(ctx->parent);
|
||||
}
|
||||
|
||||
static struct kunit_suite clk_gate_test_suite = {
|
||||
.name = "clk-gate-test",
|
||||
.init = clk_gate_test_init,
|
||||
.exit = clk_gate_test_exit,
|
||||
.test_cases = clk_gate_test_cases,
|
||||
};
|
||||
|
||||
static void clk_gate_test_invert_enable(struct kunit *test)
|
||||
{
|
||||
struct clk_gate_test_context *ctx = test->priv;
|
||||
struct clk_hw *parent = ctx->parent;
|
||||
struct clk_hw *hw = ctx->hw;
|
||||
struct clk *clk = hw->clk;
|
||||
u32 enable_val = 0;
|
||||
|
||||
KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, enable_val, ctx->fake_reg);
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw));
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw));
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent));
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(parent));
|
||||
}
|
||||
|
||||
static void clk_gate_test_invert_disable(struct kunit *test)
|
||||
{
|
||||
struct clk_gate_test_context *ctx = test->priv;
|
||||
struct clk_hw *parent = ctx->parent;
|
||||
struct clk_hw *hw = ctx->hw;
|
||||
struct clk *clk = hw->clk;
|
||||
u32 enable_val = 0;
|
||||
u32 disable_val = BIT(15);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
|
||||
KUNIT_ASSERT_EQ(test, enable_val, ctx->fake_reg);
|
||||
|
||||
clk_disable_unprepare(clk);
|
||||
KUNIT_EXPECT_EQ(test, disable_val, ctx->fake_reg);
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw));
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw));
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent));
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(parent));
|
||||
}
|
||||
|
||||
static struct kunit_case clk_gate_test_invert_cases[] = {
|
||||
KUNIT_CASE(clk_gate_test_invert_enable),
|
||||
KUNIT_CASE(clk_gate_test_invert_disable),
|
||||
{}
|
||||
};
|
||||
|
||||
static int clk_gate_test_invert_init(struct kunit *test)
|
||||
{
|
||||
struct clk_hw *parent;
|
||||
struct clk_hw *hw;
|
||||
struct clk_gate_test_context *ctx;
|
||||
|
||||
ctx = clk_gate_test_alloc_ctx(test);
|
||||
parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
|
||||
2000000);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
|
||||
|
||||
ctx->fake_reg = BIT(15); /* Default to off */
|
||||
hw = clk_hw_register_gate_parent_hw(NULL, "test_gate", parent, 0,
|
||||
ctx->fake_mem, 15,
|
||||
CLK_GATE_SET_TO_DISABLE, NULL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
|
||||
|
||||
ctx->hw = hw;
|
||||
ctx->parent = parent;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct kunit_suite clk_gate_test_invert_suite = {
|
||||
.name = "clk-gate-invert-test",
|
||||
.init = clk_gate_test_invert_init,
|
||||
.exit = clk_gate_test_exit,
|
||||
.test_cases = clk_gate_test_invert_cases,
|
||||
};
|
||||
|
||||
static void clk_gate_test_hiword_enable(struct kunit *test)
|
||||
{
|
||||
struct clk_gate_test_context *ctx = test->priv;
|
||||
struct clk_hw *parent = ctx->parent;
|
||||
struct clk_hw *hw = ctx->hw;
|
||||
struct clk *clk = hw->clk;
|
||||
u32 enable_val = BIT(9) | BIT(9 + 16);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, enable_val, ctx->fake_reg);
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw));
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw));
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent));
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(parent));
|
||||
}
|
||||
|
||||
static void clk_gate_test_hiword_disable(struct kunit *test)
|
||||
{
|
||||
struct clk_gate_test_context *ctx = test->priv;
|
||||
struct clk_hw *parent = ctx->parent;
|
||||
struct clk_hw *hw = ctx->hw;
|
||||
struct clk *clk = hw->clk;
|
||||
u32 enable_val = BIT(9) | BIT(9 + 16);
|
||||
u32 disable_val = BIT(9 + 16);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
|
||||
KUNIT_ASSERT_EQ(test, enable_val, ctx->fake_reg);
|
||||
|
||||
clk_disable_unprepare(clk);
|
||||
KUNIT_EXPECT_EQ(test, disable_val, ctx->fake_reg);
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw));
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw));
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent));
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(parent));
|
||||
}
|
||||
|
||||
static struct kunit_case clk_gate_test_hiword_cases[] = {
|
||||
KUNIT_CASE(clk_gate_test_hiword_enable),
|
||||
KUNIT_CASE(clk_gate_test_hiword_disable),
|
||||
{}
|
||||
};
|
||||
|
||||
static int clk_gate_test_hiword_init(struct kunit *test)
|
||||
{
|
||||
struct clk_hw *parent;
|
||||
struct clk_hw *hw;
|
||||
struct clk_gate_test_context *ctx;
|
||||
|
||||
ctx = clk_gate_test_alloc_ctx(test);
|
||||
parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
|
||||
2000000);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
|
||||
|
||||
hw = clk_hw_register_gate_parent_hw(NULL, "test_gate", parent, 0,
|
||||
ctx->fake_mem, 9,
|
||||
CLK_GATE_HIWORD_MASK, NULL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
|
||||
|
||||
ctx->hw = hw;
|
||||
ctx->parent = parent;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct kunit_suite clk_gate_test_hiword_suite = {
|
||||
.name = "clk-gate-hiword-test",
|
||||
.init = clk_gate_test_hiword_init,
|
||||
.exit = clk_gate_test_exit,
|
||||
.test_cases = clk_gate_test_hiword_cases,
|
||||
};
|
||||
|
||||
static void clk_gate_test_is_enabled(struct kunit *test)
|
||||
{
|
||||
struct clk_hw *hw;
|
||||
struct clk_gate_test_context *ctx;
|
||||
|
||||
ctx = clk_gate_test_alloc_ctx(test);
|
||||
ctx->fake_reg = BIT(7);
|
||||
hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 7,
|
||||
0, NULL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
|
||||
KUNIT_ASSERT_TRUE(test, clk_hw_is_enabled(hw));
|
||||
|
||||
clk_hw_unregister_gate(hw);
|
||||
}
|
||||
|
||||
static void clk_gate_test_is_disabled(struct kunit *test)
|
||||
{
|
||||
struct clk_hw *hw;
|
||||
struct clk_gate_test_context *ctx;
|
||||
|
||||
ctx = clk_gate_test_alloc_ctx(test);
|
||||
ctx->fake_reg = BIT(4);
|
||||
hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 7,
|
||||
0, NULL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
|
||||
KUNIT_ASSERT_FALSE(test, clk_hw_is_enabled(hw));
|
||||
|
||||
clk_hw_unregister_gate(hw);
|
||||
}
|
||||
|
||||
static void clk_gate_test_is_enabled_inverted(struct kunit *test)
|
||||
{
|
||||
struct clk_hw *hw;
|
||||
struct clk_gate_test_context *ctx;
|
||||
|
||||
ctx = clk_gate_test_alloc_ctx(test);
|
||||
ctx->fake_reg = BIT(31);
|
||||
hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 2,
|
||||
CLK_GATE_SET_TO_DISABLE, NULL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
|
||||
KUNIT_ASSERT_TRUE(test, clk_hw_is_enabled(hw));
|
||||
|
||||
clk_hw_unregister_gate(hw);
|
||||
}
|
||||
|
||||
static void clk_gate_test_is_disabled_inverted(struct kunit *test)
|
||||
{
|
||||
struct clk_hw *hw;
|
||||
struct clk_gate_test_context *ctx;
|
||||
|
||||
ctx = clk_gate_test_alloc_ctx(test);
|
||||
ctx->fake_reg = BIT(29);
|
||||
hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 29,
|
||||
CLK_GATE_SET_TO_DISABLE, NULL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
|
||||
KUNIT_ASSERT_FALSE(test, clk_hw_is_enabled(hw));
|
||||
|
||||
clk_hw_unregister_gate(hw);
|
||||
}
|
||||
|
||||
static struct kunit_case clk_gate_test_enabled_cases[] = {
|
||||
KUNIT_CASE(clk_gate_test_is_enabled),
|
||||
KUNIT_CASE(clk_gate_test_is_disabled),
|
||||
KUNIT_CASE(clk_gate_test_is_enabled_inverted),
|
||||
KUNIT_CASE(clk_gate_test_is_disabled_inverted),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite clk_gate_test_enabled_suite = {
|
||||
.name = "clk-gate-is_enabled-test",
|
||||
.test_cases = clk_gate_test_enabled_cases,
|
||||
};
|
||||
|
||||
kunit_test_suites(
|
||||
&clk_gate_register_test_suite,
|
||||
&clk_gate_test_suite,
|
||||
&clk_gate_test_invert_suite,
|
||||
&clk_gate_test_hiword_suite,
|
||||
&clk_gate_test_enabled_suite
|
||||
);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -40,7 +40,7 @@ static inline void clk_mux_writel(struct clk_mux *mux, u32 val)
|
||||
writel(val, mux->reg);
|
||||
}
|
||||
|
||||
int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags,
|
||||
int clk_mux_val_to_index(struct clk_hw *hw, const u32 *table, unsigned int flags,
|
||||
unsigned int val)
|
||||
{
|
||||
int num_parents = clk_hw_get_num_parents(hw);
|
||||
@@ -67,7 +67,7 @@ int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_mux_val_to_index);
|
||||
|
||||
unsigned int clk_mux_index_to_val(u32 *table, unsigned int flags, u8 index)
|
||||
unsigned int clk_mux_index_to_val(const u32 *table, unsigned int flags, u8 index)
|
||||
{
|
||||
unsigned int val = index;
|
||||
|
||||
@@ -152,7 +152,7 @@ struct clk_hw *__clk_hw_register_mux(struct device *dev, struct device_node *np,
|
||||
const struct clk_hw **parent_hws,
|
||||
const struct clk_parent_data *parent_data,
|
||||
unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
|
||||
u8 clk_mux_flags, u32 *table, spinlock_t *lock)
|
||||
u8 clk_mux_flags, const u32 *table, spinlock_t *lock)
|
||||
{
|
||||
struct clk_mux *mux;
|
||||
struct clk_hw *hw;
|
||||
@@ -218,7 +218,7 @@ struct clk_hw *__devm_clk_hw_register_mux(struct device *dev, struct device_node
|
||||
const struct clk_hw **parent_hws,
|
||||
const struct clk_parent_data *parent_data,
|
||||
unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
|
||||
u8 clk_mux_flags, u32 *table, spinlock_t *lock)
|
||||
u8 clk_mux_flags, const u32 *table, spinlock_t *lock)
|
||||
{
|
||||
struct clk_hw **ptr, *hw;
|
||||
|
||||
@@ -244,7 +244,7 @@ EXPORT_SYMBOL_GPL(__devm_clk_hw_register_mux);
|
||||
struct clk *clk_register_mux_table(struct device *dev, const char *name,
|
||||
const char * const *parent_names, u8 num_parents,
|
||||
unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
|
||||
u8 clk_mux_flags, u32 *table, spinlock_t *lock)
|
||||
u8 clk_mux_flags, const u32 *table, spinlock_t *lock)
|
||||
{
|
||||
struct clk_hw *hw;
|
||||
|
||||
|
||||
@@ -209,15 +209,11 @@ static int oxnas_stdclk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
const struct oxnas_stdclk_data *data;
|
||||
const struct of_device_id *id;
|
||||
struct regmap *regmap;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
id = of_match_device(oxnas_stdclk_dt_ids, &pdev->dev);
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
data = id->data;
|
||||
data = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
regmap = syscon_node_to_regmap(of_get_parent(np));
|
||||
if (IS_ERR(regmap)) {
|
||||
|
||||
322
drivers/clk/clk-renesas-pcie.c
Normal file
322
drivers/clk/clk-renesas-pcie.c
Normal file
@@ -0,0 +1,322 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Driver for Renesas 9-series PCIe clock generator driver
|
||||
*
|
||||
* The following series can be supported:
|
||||
* - 9FGV/9DBV/9DMV/9FGL/9DML/9QXL/9SQ
|
||||
* Currently supported:
|
||||
* - 9FGV0241
|
||||
*
|
||||
* Copyright (C) 2022 Marek Vasut <marex@denx.de>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define RS9_REG_OE 0x0
|
||||
#define RS9_REG_OE_DIF_OE(n) BIT((n) + 1)
|
||||
#define RS9_REG_SS 0x1
|
||||
#define RS9_REG_SS_AMP_0V6 0x0
|
||||
#define RS9_REG_SS_AMP_0V7 0x1
|
||||
#define RS9_REG_SS_AMP_0V8 0x2
|
||||
#define RS9_REG_SS_AMP_0V9 0x3
|
||||
#define RS9_REG_SS_AMP_MASK 0x3
|
||||
#define RS9_REG_SS_SSC_100 0
|
||||
#define RS9_REG_SS_SSC_M025 (1 << 3)
|
||||
#define RS9_REG_SS_SSC_M050 (3 << 3)
|
||||
#define RS9_REG_SS_SSC_MASK (3 << 3)
|
||||
#define RS9_REG_SS_SSC_LOCK BIT(5)
|
||||
#define RS9_REG_SR 0x2
|
||||
#define RS9_REG_SR_2V0_DIF(n) 0
|
||||
#define RS9_REG_SR_3V0_DIF(n) BIT((n) + 1)
|
||||
#define RS9_REG_SR_DIF_MASK(n) BIT((n) + 1)
|
||||
#define RS9_REG_REF 0x3
|
||||
#define RS9_REG_REF_OE BIT(4)
|
||||
#define RS9_REG_REF_OD BIT(5)
|
||||
#define RS9_REG_REF_SR_SLOWEST 0
|
||||
#define RS9_REG_REF_SR_SLOW (1 << 6)
|
||||
#define RS9_REG_REF_SR_FAST (2 << 6)
|
||||
#define RS9_REG_REF_SR_FASTER (3 << 6)
|
||||
#define RS9_REG_VID 0x5
|
||||
#define RS9_REG_DID 0x6
|
||||
#define RS9_REG_BCP 0x7
|
||||
|
||||
/* Supported Renesas 9-series models. */
|
||||
enum rs9_model {
|
||||
RENESAS_9FGV0241,
|
||||
};
|
||||
|
||||
/* Structure to describe features of a particular 9-series model */
|
||||
struct rs9_chip_info {
|
||||
const enum rs9_model model;
|
||||
unsigned int num_clks;
|
||||
};
|
||||
|
||||
struct rs9_driver_data {
|
||||
struct i2c_client *client;
|
||||
struct regmap *regmap;
|
||||
const struct rs9_chip_info *chip_info;
|
||||
struct clk *pin_xin;
|
||||
struct clk_hw *clk_dif[2];
|
||||
u8 pll_amplitude;
|
||||
u8 pll_ssc;
|
||||
u8 clk_dif_sr;
|
||||
};
|
||||
|
||||
/*
|
||||
* Renesas 9-series i2c regmap
|
||||
*/
|
||||
static const struct regmap_range rs9_readable_ranges[] = {
|
||||
regmap_reg_range(RS9_REG_OE, RS9_REG_REF),
|
||||
regmap_reg_range(RS9_REG_VID, RS9_REG_BCP),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table rs9_readable_table = {
|
||||
.yes_ranges = rs9_readable_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(rs9_readable_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_range rs9_writeable_ranges[] = {
|
||||
regmap_reg_range(RS9_REG_OE, RS9_REG_REF),
|
||||
regmap_reg_range(RS9_REG_BCP, RS9_REG_BCP),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table rs9_writeable_table = {
|
||||
.yes_ranges = rs9_writeable_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(rs9_writeable_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_config rs9_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_FLAT,
|
||||
.max_register = 0x8,
|
||||
.rd_table = &rs9_readable_table,
|
||||
.wr_table = &rs9_writeable_table,
|
||||
};
|
||||
|
||||
static int rs9_get_output_config(struct rs9_driver_data *rs9, int idx)
|
||||
{
|
||||
struct i2c_client *client = rs9->client;
|
||||
unsigned char name[5] = "DIF0";
|
||||
struct device_node *np;
|
||||
int ret;
|
||||
u32 sr;
|
||||
|
||||
/* Set defaults */
|
||||
rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx);
|
||||
rs9->clk_dif_sr |= RS9_REG_SR_3V0_DIF(idx);
|
||||
|
||||
snprintf(name, 5, "DIF%d", idx);
|
||||
np = of_get_child_by_name(client->dev.of_node, name);
|
||||
if (!np)
|
||||
return 0;
|
||||
|
||||
/* Output clock slew rate */
|
||||
ret = of_property_read_u32(np, "renesas,slew-rate", &sr);
|
||||
of_node_put(np);
|
||||
if (!ret) {
|
||||
if (sr == 2000000) { /* 2V/ns */
|
||||
rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx);
|
||||
rs9->clk_dif_sr |= RS9_REG_SR_2V0_DIF(idx);
|
||||
} else if (sr == 3000000) { /* 3V/ns (default) */
|
||||
rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx);
|
||||
rs9->clk_dif_sr |= RS9_REG_SR_3V0_DIF(idx);
|
||||
} else
|
||||
ret = dev_err_probe(&client->dev, -EINVAL,
|
||||
"Invalid renesas,slew-rate value\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rs9_get_common_config(struct rs9_driver_data *rs9)
|
||||
{
|
||||
struct i2c_client *client = rs9->client;
|
||||
struct device_node *np = client->dev.of_node;
|
||||
unsigned int amp, ssc;
|
||||
int ret;
|
||||
|
||||
/* Set defaults */
|
||||
rs9->pll_amplitude = RS9_REG_SS_AMP_0V7;
|
||||
rs9->pll_ssc = RS9_REG_SS_SSC_100;
|
||||
|
||||
/* Output clock amplitude */
|
||||
ret = of_property_read_u32(np, "renesas,out-amplitude-microvolt",
|
||||
&);
|
||||
if (!ret) {
|
||||
if (amp == 600000) /* 0.6V */
|
||||
rs9->pll_amplitude = RS9_REG_SS_AMP_0V6;
|
||||
else if (amp == 700000) /* 0.7V (default) */
|
||||
rs9->pll_amplitude = RS9_REG_SS_AMP_0V7;
|
||||
else if (amp == 800000) /* 0.8V */
|
||||
rs9->pll_amplitude = RS9_REG_SS_AMP_0V8;
|
||||
else if (amp == 900000) /* 0.9V */
|
||||
rs9->pll_amplitude = RS9_REG_SS_AMP_0V9;
|
||||
else
|
||||
return dev_err_probe(&client->dev, -EINVAL,
|
||||
"Invalid renesas,out-amplitude-microvolt value\n");
|
||||
}
|
||||
|
||||
/* Output clock spread spectrum */
|
||||
ret = of_property_read_u32(np, "renesas,out-spread-spectrum", &ssc);
|
||||
if (!ret) {
|
||||
if (ssc == 100000) /* 100% ... no spread (default) */
|
||||
rs9->pll_ssc = RS9_REG_SS_SSC_100;
|
||||
else if (ssc == 99750) /* -0.25% ... down spread */
|
||||
rs9->pll_ssc = RS9_REG_SS_SSC_M025;
|
||||
else if (ssc == 99500) /* -0.50% ... down spread */
|
||||
rs9->pll_ssc = RS9_REG_SS_SSC_M050;
|
||||
else
|
||||
return dev_err_probe(&client->dev, -EINVAL,
|
||||
"Invalid renesas,out-spread-spectrum value\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rs9_update_config(struct rs9_driver_data *rs9)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* If amplitude is non-default, update it. */
|
||||
if (rs9->pll_amplitude != RS9_REG_SS_AMP_0V7) {
|
||||
regmap_update_bits(rs9->regmap, RS9_REG_SS, RS9_REG_SS_AMP_MASK,
|
||||
rs9->pll_amplitude);
|
||||
}
|
||||
|
||||
/* If SSC is non-default, update it. */
|
||||
if (rs9->pll_ssc != RS9_REG_SS_SSC_100) {
|
||||
regmap_update_bits(rs9->regmap, RS9_REG_SS, RS9_REG_SS_SSC_MASK,
|
||||
rs9->pll_ssc);
|
||||
}
|
||||
|
||||
for (i = 0; i < rs9->chip_info->num_clks; i++) {
|
||||
if (rs9->clk_dif_sr & RS9_REG_SR_3V0_DIF(i))
|
||||
continue;
|
||||
|
||||
regmap_update_bits(rs9->regmap, RS9_REG_SR, RS9_REG_SR_3V0_DIF(i),
|
||||
rs9->clk_dif_sr & RS9_REG_SR_3V0_DIF(i));
|
||||
}
|
||||
}
|
||||
|
||||
static struct clk_hw *
|
||||
rs9_of_clk_get(struct of_phandle_args *clkspec, void *data)
|
||||
{
|
||||
struct rs9_driver_data *rs9 = data;
|
||||
unsigned int idx = clkspec->args[0];
|
||||
|
||||
return rs9->clk_dif[idx];
|
||||
}
|
||||
|
||||
static int rs9_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
{
|
||||
unsigned char name[5] = "DIF0";
|
||||
struct rs9_driver_data *rs9;
|
||||
struct clk_hw *hw;
|
||||
int i, ret;
|
||||
|
||||
rs9 = devm_kzalloc(&client->dev, sizeof(*rs9), GFP_KERNEL);
|
||||
if (!rs9)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, rs9);
|
||||
rs9->client = client;
|
||||
rs9->chip_info = device_get_match_data(&client->dev);
|
||||
if (!rs9->chip_info)
|
||||
return -EINVAL;
|
||||
|
||||
/* Fetch common configuration from DT (if specified) */
|
||||
ret = rs9_get_common_config(rs9);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Fetch DIFx output configuration from DT (if specified) */
|
||||
for (i = 0; i < rs9->chip_info->num_clks; i++) {
|
||||
ret = rs9_get_output_config(rs9, i);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
rs9->regmap = devm_regmap_init_i2c(client, &rs9_regmap_config);
|
||||
if (IS_ERR(rs9->regmap))
|
||||
return dev_err_probe(&client->dev, PTR_ERR(rs9->regmap),
|
||||
"Failed to allocate register map\n");
|
||||
|
||||
/* Register clock */
|
||||
for (i = 0; i < rs9->chip_info->num_clks; i++) {
|
||||
snprintf(name, 5, "DIF%d", i);
|
||||
hw = devm_clk_hw_register_fixed_factor_index(&client->dev, name,
|
||||
0, 0, 4, 1);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
|
||||
rs9->clk_dif[i] = hw;
|
||||
}
|
||||
|
||||
ret = devm_of_clk_add_hw_provider(&client->dev, rs9_of_clk_get, rs9);
|
||||
if (!ret)
|
||||
rs9_update_config(rs9);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused rs9_suspend(struct device *dev)
|
||||
{
|
||||
struct rs9_driver_data *rs9 = dev_get_drvdata(dev);
|
||||
|
||||
regcache_cache_only(rs9->regmap, true);
|
||||
regcache_mark_dirty(rs9->regmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused rs9_resume(struct device *dev)
|
||||
{
|
||||
struct rs9_driver_data *rs9 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
regcache_cache_only(rs9->regmap, false);
|
||||
ret = regcache_sync(rs9->regmap);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to restore register map: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct rs9_chip_info renesas_9fgv0241_info = {
|
||||
.model = RENESAS_9FGV0241,
|
||||
.num_clks = 2,
|
||||
};
|
||||
|
||||
static const struct i2c_device_id rs9_id[] = {
|
||||
{ "9fgv0241", .driver_data = RENESAS_9FGV0241 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, rs9_id);
|
||||
|
||||
static const struct of_device_id clk_rs9_of_match[] = {
|
||||
{ .compatible = "renesas,9fgv0241", .data = &renesas_9fgv0241_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, clk_rs9_of_match);
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(rs9_pm_ops, rs9_suspend, rs9_resume);
|
||||
|
||||
static struct i2c_driver rs9_driver = {
|
||||
.driver = {
|
||||
.name = "clk-renesas-pcie-9series",
|
||||
.pm = &rs9_pm_ops,
|
||||
.of_match_table = clk_rs9_of_match,
|
||||
},
|
||||
.probe = rs9_probe,
|
||||
.id_table = rs9_id,
|
||||
};
|
||||
module_i2c_driver(rs9_driver);
|
||||
|
||||
MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
|
||||
MODULE_DESCRIPTION("Renesas 9-series PCIe clock generator driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -655,7 +655,7 @@ static unsigned long si5341_synth_clk_recalc_rate(struct clk_hw *hw,
|
||||
f = synth->data->freq_vco;
|
||||
f *= n_den >> 4;
|
||||
|
||||
/* Now we need to to 64-bit division: f/n_num */
|
||||
/* Now we need to do 64-bit division: f/n_num */
|
||||
/* And compensate for the 4 bits we dropped */
|
||||
f = div64_u64(f, (n_num >> 4));
|
||||
|
||||
@@ -798,6 +798,15 @@ static unsigned long si5341_output_clk_recalc_rate(struct clk_hw *hw,
|
||||
u32 r_divider;
|
||||
u8 r[3];
|
||||
|
||||
err = regmap_read(output->data->regmap,
|
||||
SI5341_OUT_CONFIG(output), &val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* If SI5341_OUT_CFG_RDIV_FORCE2 is set, r_divider is 2 */
|
||||
if (val & SI5341_OUT_CFG_RDIV_FORCE2)
|
||||
return parent_rate / 2;
|
||||
|
||||
err = regmap_bulk_read(output->data->regmap,
|
||||
SI5341_OUT_R_REG(output), r, 3);
|
||||
if (err < 0)
|
||||
@@ -814,13 +823,6 @@ static unsigned long si5341_output_clk_recalc_rate(struct clk_hw *hw,
|
||||
r_divider += 1;
|
||||
r_divider <<= 1;
|
||||
|
||||
err = regmap_read(output->data->regmap,
|
||||
SI5341_OUT_CONFIG(output), &val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (val & SI5341_OUT_CFG_RDIV_FORCE2)
|
||||
r_divider = 2;
|
||||
|
||||
return parent_rate / r_divider;
|
||||
}
|
||||
@@ -1468,7 +1470,7 @@ static ssize_t input_present_show(struct device *dev,
|
||||
if (res < 0)
|
||||
return res;
|
||||
res = !(status & SI5341_STATUS_LOSREF);
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", res);
|
||||
return sysfs_emit(buf, "%d\n", res);
|
||||
}
|
||||
static DEVICE_ATTR_RO(input_present);
|
||||
|
||||
@@ -1483,7 +1485,7 @@ static ssize_t input_present_sticky_show(struct device *dev,
|
||||
if (res < 0)
|
||||
return res;
|
||||
res = !(status & SI5341_STATUS_LOSREF);
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", res);
|
||||
return sysfs_emit(buf, "%d\n", res);
|
||||
}
|
||||
static DEVICE_ATTR_RO(input_present_sticky);
|
||||
|
||||
@@ -1498,7 +1500,7 @@ static ssize_t pll_locked_show(struct device *dev,
|
||||
if (res < 0)
|
||||
return res;
|
||||
res = !(status & SI5341_STATUS_LOL);
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", res);
|
||||
return sysfs_emit(buf, "%d\n", res);
|
||||
}
|
||||
static DEVICE_ATTR_RO(pll_locked);
|
||||
|
||||
@@ -1513,7 +1515,7 @@ static ssize_t pll_locked_sticky_show(struct device *dev,
|
||||
if (res < 0)
|
||||
return res;
|
||||
res = !(status & SI5341_STATUS_LOL);
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", res);
|
||||
return sysfs_emit(buf, "%d\n", res);
|
||||
}
|
||||
static DEVICE_ATTR_RO(pll_locked_sticky);
|
||||
|
||||
|
||||
@@ -155,6 +155,10 @@ static const char * const eth_src[] = {
|
||||
"pll4_p", "pll3_q"
|
||||
};
|
||||
|
||||
const struct clk_parent_data ethrx_src[] = {
|
||||
{ .name = "ethck_k", .fw_name = "ETH_RX_CLK/ETH_REF_CLK" },
|
||||
};
|
||||
|
||||
static const char * const rng_src[] = {
|
||||
"ck_csi", "pll4_r", "ck_lse", "ck_lsi"
|
||||
};
|
||||
@@ -317,6 +321,7 @@ struct clock_config {
|
||||
const char *name;
|
||||
const char *parent_name;
|
||||
const char * const *parent_names;
|
||||
const struct clk_parent_data *parent_data;
|
||||
int num_parents;
|
||||
unsigned long flags;
|
||||
void *cfg;
|
||||
@@ -576,6 +581,7 @@ static struct clk_hw *
|
||||
clk_stm32_register_gate_ops(struct device *dev,
|
||||
const char *name,
|
||||
const char *parent_name,
|
||||
const struct clk_parent_data *parent_data,
|
||||
unsigned long flags,
|
||||
void __iomem *base,
|
||||
const struct stm32_gate_cfg *cfg,
|
||||
@@ -586,7 +592,10 @@ clk_stm32_register_gate_ops(struct device *dev,
|
||||
int ret;
|
||||
|
||||
init.name = name;
|
||||
init.parent_names = &parent_name;
|
||||
if (parent_name)
|
||||
init.parent_names = &parent_name;
|
||||
if (parent_data)
|
||||
init.parent_data = parent_data;
|
||||
init.num_parents = 1;
|
||||
init.flags = flags;
|
||||
|
||||
@@ -611,6 +620,7 @@ clk_stm32_register_gate_ops(struct device *dev,
|
||||
static struct clk_hw *
|
||||
clk_stm32_register_composite(struct device *dev,
|
||||
const char *name, const char * const *parent_names,
|
||||
const struct clk_parent_data *parent_data,
|
||||
int num_parents, void __iomem *base,
|
||||
const struct stm32_composite_cfg *cfg,
|
||||
unsigned long flags, spinlock_t *lock)
|
||||
@@ -1135,6 +1145,7 @@ _clk_stm32_register_gate(struct device *dev,
|
||||
return clk_stm32_register_gate_ops(dev,
|
||||
cfg->name,
|
||||
cfg->parent_name,
|
||||
cfg->parent_data,
|
||||
cfg->flags,
|
||||
base,
|
||||
cfg->cfg,
|
||||
@@ -1148,8 +1159,8 @@ _clk_stm32_register_composite(struct device *dev,
|
||||
const struct clock_config *cfg)
|
||||
{
|
||||
return clk_stm32_register_composite(dev, cfg->name, cfg->parent_names,
|
||||
cfg->num_parents, base, cfg->cfg,
|
||||
cfg->flags, lock);
|
||||
cfg->parent_data, cfg->num_parents,
|
||||
base, cfg->cfg, cfg->flags, lock);
|
||||
}
|
||||
|
||||
#define GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\
|
||||
@@ -1258,6 +1269,16 @@ _clk_stm32_register_composite(struct device *dev,
|
||||
.func = _clk_stm32_register_gate,\
|
||||
}
|
||||
|
||||
#define STM32_GATE_PDATA(_id, _name, _parent, _flags, _gate)\
|
||||
{\
|
||||
.id = _id,\
|
||||
.name = _name,\
|
||||
.parent_data = _parent,\
|
||||
.flags = _flags,\
|
||||
.cfg = (struct stm32_gate_cfg *) {_gate},\
|
||||
.func = _clk_stm32_register_gate,\
|
||||
}
|
||||
|
||||
#define _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags, _mgate, _ops)\
|
||||
(&(struct stm32_gate_cfg) {\
|
||||
&(struct gate_cfg) {\
|
||||
@@ -1291,6 +1312,10 @@ _clk_stm32_register_composite(struct device *dev,
|
||||
STM32_GATE(_id, _name, _parent, _flags,\
|
||||
_STM32_MGATE(_mgate))
|
||||
|
||||
#define MGATE_MP1_PDATA(_id, _name, _parent, _flags, _mgate)\
|
||||
STM32_GATE_PDATA(_id, _name, _parent, _flags,\
|
||||
_STM32_MGATE(_mgate))
|
||||
|
||||
#define _STM32_DIV(_div_offset, _div_shift, _div_width,\
|
||||
_div_flags, _div_table, _ops)\
|
||||
.div = &(struct stm32_div_cfg) {\
|
||||
@@ -1354,6 +1379,9 @@ _clk_stm32_register_composite(struct device *dev,
|
||||
#define PCLK(_id, _name, _parent, _flags, _mgate)\
|
||||
MGATE_MP1(_id, _name, _parent, _flags, _mgate)
|
||||
|
||||
#define PCLK_PDATA(_id, _name, _parent, _flags, _mgate)\
|
||||
MGATE_MP1_PDATA(_id, _name, _parent, _flags, _mgate)
|
||||
|
||||
#define KCLK(_id, _name, _parents, _flags, _mgate, _mmux)\
|
||||
COMPOSITE(_id, _name, _parents, CLK_OPS_PARENT_ENABLE |\
|
||||
CLK_SET_RATE_NO_REPARENT | _flags,\
|
||||
@@ -1951,7 +1979,7 @@ static const struct clock_config stm32mp1_clock_cfg[] = {
|
||||
PCLK(MDMA, "mdma", "ck_axi", 0, G_MDMA),
|
||||
PCLK(GPU, "gpu", "ck_axi", 0, G_GPU),
|
||||
PCLK(ETHTX, "ethtx", "ck_axi", 0, G_ETHTX),
|
||||
PCLK(ETHRX, "ethrx", "ck_axi", 0, G_ETHRX),
|
||||
PCLK_PDATA(ETHRX, "ethrx", ethrx_src, 0, G_ETHRX),
|
||||
PCLK(ETHMAC, "ethmac", "ck_axi", 0, G_ETHMAC),
|
||||
PCLK(FMC, "fmc", "ck_axi", CLK_IGNORE_UNUSED, G_FMC),
|
||||
PCLK(QSPI, "qspi", "ck_axi", CLK_IGNORE_UNUSED, G_QSPI),
|
||||
@@ -2008,7 +2036,6 @@ static const struct clock_config stm32mp1_clock_cfg[] = {
|
||||
KCLK(DSI_K, "dsi_k", dsi_src, 0, G_DSI, M_DSI),
|
||||
KCLK(ADFSDM_K, "adfsdm_k", sai_src, 0, G_ADFSDM, M_SAI1),
|
||||
KCLK(USBO_K, "usbo_k", usbo_src, 0, G_USBO, M_USBO),
|
||||
KCLK(ETHCK_K, "ethck_k", eth_src, 0, G_ETHCK, M_ETHCK),
|
||||
|
||||
/* Particulary Kernel Clocks (no mux or no gate) */
|
||||
MGATE_MP1(DFSDM_K, "dfsdm_k", "ck_mcu", 0, G_DFSDM),
|
||||
@@ -2017,11 +2044,16 @@ static const struct clock_config stm32mp1_clock_cfg[] = {
|
||||
MGATE_MP1(GPU_K, "gpu_k", "pll2_q", 0, G_GPU),
|
||||
MGATE_MP1(DAC12_K, "dac12_k", "ck_lsi", 0, G_DAC12),
|
||||
|
||||
COMPOSITE(ETHPTP_K, "ethptp_k", eth_src, CLK_OPS_PARENT_ENABLE |
|
||||
COMPOSITE(NO_ID, "ck_ker_eth", eth_src, CLK_OPS_PARENT_ENABLE |
|
||||
CLK_SET_RATE_NO_REPARENT,
|
||||
_NO_GATE,
|
||||
_MMUX(M_ETHCK),
|
||||
_DIV(RCC_ETHCKSELR, 4, 4, 0, NULL)),
|
||||
_NO_DIV),
|
||||
|
||||
MGATE_MP1(ETHCK_K, "ethck_k", "ck_ker_eth", 0, G_ETHCK),
|
||||
|
||||
DIV(ETHPTP_K, "ethptp_k", "ck_ker_eth", CLK_OPS_PARENT_ENABLE |
|
||||
CLK_SET_RATE_NO_REPARENT, RCC_ETHCKSELR, 4, 4, 0),
|
||||
|
||||
/* RTC clock */
|
||||
COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE,
|
||||
|
||||
@@ -37,7 +37,7 @@ static HLIST_HEAD(clk_root_list);
|
||||
static HLIST_HEAD(clk_orphan_list);
|
||||
static LIST_HEAD(clk_notifier_list);
|
||||
|
||||
static struct hlist_head *all_lists[] = {
|
||||
static const struct hlist_head *all_lists[] = {
|
||||
&clk_root_list,
|
||||
&clk_orphan_list,
|
||||
NULL,
|
||||
@@ -634,6 +634,24 @@ static void clk_core_get_boundaries(struct clk_core *core,
|
||||
*max_rate = min(*max_rate, clk_user->max_rate);
|
||||
}
|
||||
|
||||
static bool clk_core_check_boundaries(struct clk_core *core,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate)
|
||||
{
|
||||
struct clk *user;
|
||||
|
||||
lockdep_assert_held(&prepare_lock);
|
||||
|
||||
if (min_rate > core->max_rate || max_rate < core->min_rate)
|
||||
return false;
|
||||
|
||||
hlist_for_each_entry(user, &core->clks, clks_node)
|
||||
if (min_rate > user->max_rate || max_rate < user->min_rate)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void clk_hw_set_rate_range(struct clk_hw *hw, unsigned long min_rate,
|
||||
unsigned long max_rate)
|
||||
{
|
||||
@@ -1372,6 +1390,8 @@ static int clk_core_determine_round_nolock(struct clk_core *core,
|
||||
if (!core)
|
||||
return 0;
|
||||
|
||||
req->rate = clamp(req->rate, req->min_rate, req->max_rate);
|
||||
|
||||
/*
|
||||
* At this point, core protection will be disabled
|
||||
* - if the provider is not protected at all
|
||||
@@ -2391,19 +2411,15 @@ int clk_set_rate_exclusive(struct clk *clk, unsigned long rate)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_set_rate_exclusive);
|
||||
|
||||
/**
|
||||
* clk_set_rate_range - set a rate range for a clock source
|
||||
* @clk: clock source
|
||||
* @min: desired minimum clock rate in Hz, inclusive
|
||||
* @max: desired maximum clock rate in Hz, inclusive
|
||||
*
|
||||
* Returns success (0) or negative errno.
|
||||
*/
|
||||
int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)
|
||||
static int clk_set_rate_range_nolock(struct clk *clk,
|
||||
unsigned long min,
|
||||
unsigned long max)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long old_min, old_max, rate;
|
||||
|
||||
lockdep_assert_held(&prepare_lock);
|
||||
|
||||
if (!clk)
|
||||
return 0;
|
||||
|
||||
@@ -2416,8 +2432,6 @@ int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
clk_prepare_lock();
|
||||
|
||||
if (clk->exclusive_count)
|
||||
clk_core_rate_unprotect(clk->core);
|
||||
|
||||
@@ -2427,37 +2441,62 @@ int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)
|
||||
clk->min_rate = min;
|
||||
clk->max_rate = max;
|
||||
|
||||
rate = clk_core_get_rate_nolock(clk->core);
|
||||
if (rate < min || rate > max) {
|
||||
/*
|
||||
* FIXME:
|
||||
* We are in bit of trouble here, current rate is outside the
|
||||
* the requested range. We are going try to request appropriate
|
||||
* range boundary but there is a catch. It may fail for the
|
||||
* usual reason (clock broken, clock protected, etc) but also
|
||||
* because:
|
||||
* - round_rate() was not favorable and fell on the wrong
|
||||
* side of the boundary
|
||||
* - the determine_rate() callback does not really check for
|
||||
* this corner case when determining the rate
|
||||
*/
|
||||
|
||||
if (rate < min)
|
||||
rate = min;
|
||||
else
|
||||
rate = max;
|
||||
|
||||
ret = clk_core_set_rate_nolock(clk->core, rate);
|
||||
if (ret) {
|
||||
/* rollback the changes */
|
||||
clk->min_rate = old_min;
|
||||
clk->max_rate = old_max;
|
||||
}
|
||||
if (!clk_core_check_boundaries(clk->core, min, max)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since the boundaries have been changed, let's give the
|
||||
* opportunity to the provider to adjust the clock rate based on
|
||||
* the new boundaries.
|
||||
*
|
||||
* We also need to handle the case where the clock is currently
|
||||
* outside of the boundaries. Clamping the last requested rate
|
||||
* to the current minimum and maximum will also handle this.
|
||||
*
|
||||
* FIXME:
|
||||
* There is a catch. It may fail for the usual reason (clock
|
||||
* broken, clock protected, etc) but also because:
|
||||
* - round_rate() was not favorable and fell on the wrong
|
||||
* side of the boundary
|
||||
* - the determine_rate() callback does not really check for
|
||||
* this corner case when determining the rate
|
||||
*/
|
||||
rate = clamp(clk->core->req_rate, min, max);
|
||||
ret = clk_core_set_rate_nolock(clk->core, rate);
|
||||
if (ret) {
|
||||
/* rollback the changes */
|
||||
clk->min_rate = old_min;
|
||||
clk->max_rate = old_max;
|
||||
}
|
||||
|
||||
out:
|
||||
if (clk->exclusive_count)
|
||||
clk_core_rate_protect(clk->core);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* clk_set_rate_range - set a rate range for a clock source
|
||||
* @clk: clock source
|
||||
* @min: desired minimum clock rate in Hz, inclusive
|
||||
* @max: desired maximum clock rate in Hz, inclusive
|
||||
*
|
||||
* Return: 0 for success or negative errno on failure.
|
||||
*/
|
||||
int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!clk)
|
||||
return 0;
|
||||
|
||||
clk_prepare_lock();
|
||||
|
||||
ret = clk_set_rate_range_nolock(clk, min, max);
|
||||
|
||||
clk_prepare_unlock();
|
||||
|
||||
return ret;
|
||||
@@ -3518,6 +3557,19 @@ static void clk_core_reparent_orphans_nolock(void)
|
||||
__clk_recalc_accuracies(orphan);
|
||||
__clk_recalc_rates(orphan, 0);
|
||||
__clk_core_update_orphan_hold_state(orphan);
|
||||
|
||||
/*
|
||||
* __clk_init_parent() will set the initial req_rate to
|
||||
* 0 if the clock doesn't have clk_ops::recalc_rate and
|
||||
* is an orphan when it's registered.
|
||||
*
|
||||
* 'req_rate' is used by clk_set_rate_range() and
|
||||
* clk_put() to trigger a clk_set_rate() call whenever
|
||||
* the boundaries are modified. Let's make sure
|
||||
* 'req_rate' is set to something non-zero so that
|
||||
* clk_set_rate_range() doesn't drop the frequency.
|
||||
*/
|
||||
orphan->req_rate = orphan->rate;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3838,8 +3890,9 @@ struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw,
|
||||
struct clk *clk_hw_get_clk(struct clk_hw *hw, const char *con_id)
|
||||
{
|
||||
struct device *dev = hw->core->dev;
|
||||
const char *name = dev ? dev_name(dev) : NULL;
|
||||
|
||||
return clk_hw_create_clk(dev, hw, dev_name(dev), con_id);
|
||||
return clk_hw_create_clk(dev, hw, name, con_id);
|
||||
}
|
||||
EXPORT_SYMBOL(clk_hw_get_clk);
|
||||
|
||||
@@ -4144,7 +4197,7 @@ static const struct clk_ops clk_nodrv_ops = {
|
||||
};
|
||||
|
||||
static void clk_core_evict_parent_cache_subtree(struct clk_core *root,
|
||||
struct clk_core *target)
|
||||
const struct clk_core *target)
|
||||
{
|
||||
int i;
|
||||
struct clk_core *child;
|
||||
@@ -4160,7 +4213,7 @@ static void clk_core_evict_parent_cache_subtree(struct clk_core *root,
|
||||
/* Remove this clk from all parent caches */
|
||||
static void clk_core_evict_parent_cache(struct clk_core *core)
|
||||
{
|
||||
struct hlist_head **lists;
|
||||
const struct hlist_head **lists;
|
||||
struct clk_core *root;
|
||||
|
||||
lockdep_assert_held(&prepare_lock);
|
||||
@@ -4431,9 +4484,7 @@ void __clk_put(struct clk *clk)
|
||||
}
|
||||
|
||||
hlist_del(&clk->clks_node);
|
||||
if (clk->min_rate > clk->core->req_rate ||
|
||||
clk->max_rate < clk->core->req_rate)
|
||||
clk_core_set_rate_nolock(clk->core, clk->core->req_rate);
|
||||
clk_set_rate_range_nolock(clk, 0, ULONG_MAX);
|
||||
|
||||
owner = clk->core->owner;
|
||||
kref_put(&clk->core->ref, __clk_release);
|
||||
|
||||
1008
drivers/clk/clk_test.c
Normal file
1008
drivers/clk/clk_test.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -611,8 +611,8 @@ static struct hisi_mux_clock hi3559av100_shub_mux_clks[] = {
|
||||
|
||||
|
||||
/* shub div clk */
|
||||
static struct clk_div_table shub_spi_clk_table[] = {{0, 8}, {1, 4}, {2, 2}};
|
||||
static struct clk_div_table shub_uart_div_clk_table[] = {{1, 8}, {2, 4}};
|
||||
static struct clk_div_table shub_spi_clk_table[] = {{0, 8}, {1, 4}, {2, 2}, {/*sentinel*/}};
|
||||
static struct clk_div_table shub_uart_div_clk_table[] = {{1, 8}, {2, 4}, {/*sentinel*/}};
|
||||
|
||||
static struct hisi_divider_clock hi3559av100_shub_div_clks[] = {
|
||||
{ HI3559AV100_SHUB_SPI_SOURCE_CLK, "clk_spi_clk", "shub_clk", 0, 0x20, 24, 2,
|
||||
|
||||
@@ -162,7 +162,7 @@ int hisi_clk_register_mux(const struct hisi_mux_clock *clks,
|
||||
clks[i].num_parents, clks[i].flags,
|
||||
base + clks[i].offset, clks[i].shift,
|
||||
mask, clks[i].mux_flags,
|
||||
(u32 *)clks[i].table, &hisi_clk_lock);
|
||||
clks[i].table, &hisi_clk_lock);
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err("%s: failed to register clock %s\n",
|
||||
__func__, clks[i].name);
|
||||
|
||||
@@ -105,3 +105,17 @@ config CLK_IMX8ULP
|
||||
select MXC_CLK
|
||||
help
|
||||
Build the driver for i.MX8ULP CCM Clock Driver
|
||||
|
||||
config CLK_IMX93
|
||||
tristate "IMX93 CCM Clock Driver"
|
||||
depends on ARCH_MXC || COMPILE_TEST
|
||||
select MXC_CLK
|
||||
help
|
||||
Build the driver for i.MX93 CCM Clock Driver
|
||||
|
||||
config CLK_IMXRT1050
|
||||
tristate "IMXRT1050 CCM Clock Driver"
|
||||
depends on SOC_IMXRT
|
||||
select MXC_CLK
|
||||
help
|
||||
Build the driver for i.MXRT1050 CCM Clock Driver
|
||||
|
||||
@@ -4,6 +4,8 @@ mxc-clk-objs += clk.o
|
||||
mxc-clk-objs += clk-busy.o
|
||||
mxc-clk-objs += clk-composite-7ulp.o
|
||||
mxc-clk-objs += clk-composite-8m.o
|
||||
mxc-clk-objs += clk-composite-93.o
|
||||
mxc-clk-objs += clk-fracn-gppll.o
|
||||
mxc-clk-objs += clk-cpu.o
|
||||
mxc-clk-objs += clk-divider-gate.o
|
||||
mxc-clk-objs += clk-fixup-div.o
|
||||
@@ -26,9 +28,12 @@ obj-$(CONFIG_CLK_IMX8MN) += clk-imx8mn.o
|
||||
obj-$(CONFIG_CLK_IMX8MP) += clk-imx8mp.o
|
||||
obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o
|
||||
|
||||
obj-$(CONFIG_CLK_IMX93) += clk-imx93.o
|
||||
|
||||
obj-$(CONFIG_MXC_CLK_SCU) += clk-imx-scu.o clk-imx-lpcg-scu.o
|
||||
clk-imx-scu-$(CONFIG_CLK_IMX8QXP) += clk-scu.o clk-imx8qxp.o \
|
||||
clk-imx8qxp-rsrc.o clk-imx8qm-rsrc.o
|
||||
clk-imx8qxp-rsrc.o clk-imx8qm-rsrc.o \
|
||||
clk-imx8dxl-rsrc.o
|
||||
clk-imx-lpcg-scu-$(CONFIG_CLK_IMX8QXP) += clk-lpcg-scu.o clk-imx8qxp-lpcg.o
|
||||
|
||||
obj-$(CONFIG_CLK_IMX8ULP) += clk-imx8ulp.o
|
||||
@@ -46,4 +51,5 @@ obj-$(CONFIG_CLK_IMX6SX) += clk-imx6sx.o
|
||||
obj-$(CONFIG_CLK_IMX6UL) += clk-imx6ul.o
|
||||
obj-$(CONFIG_CLK_IMX7D) += clk-imx7d.o
|
||||
obj-$(CONFIG_CLK_IMX7ULP) += clk-imx7ulp.o
|
||||
obj-$(CONFIG_CLK_IMXRT1050) += clk-imxrt1050.o
|
||||
obj-$(CONFIG_CLK_VF610) += clk-vf610.o
|
||||
|
||||
93
drivers/clk/imx/clk-composite-93.c
Normal file
93
drivers/clk/imx/clk-composite-93.c
Normal file
@@ -0,0 +1,93 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2021 NXP
|
||||
*
|
||||
* Peng Fan <peng.fan@nxp.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
#define CCM_DIV_SHIFT 0
|
||||
#define CCM_DIV_WIDTH 8
|
||||
#define CCM_MUX_SHIFT 8
|
||||
#define CCM_MUX_MASK 3
|
||||
#define CCM_OFF_SHIFT 24
|
||||
|
||||
#define AUTHEN_OFFSET 0x30
|
||||
#define TZ_NS_SHIFT 9
|
||||
#define TZ_NS_MASK BIT(9)
|
||||
|
||||
struct clk_hw *imx93_clk_composite_flags(const char *name, const char * const *parent_names,
|
||||
int num_parents, void __iomem *reg,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct clk_hw *hw = ERR_PTR(-ENOMEM), *mux_hw;
|
||||
struct clk_hw *div_hw, *gate_hw;
|
||||
struct clk_divider *div = NULL;
|
||||
struct clk_gate *gate = NULL;
|
||||
struct clk_mux *mux = NULL;
|
||||
bool clk_ro = false;
|
||||
|
||||
mux = kzalloc(sizeof(*mux), GFP_KERNEL);
|
||||
if (!mux)
|
||||
goto fail;
|
||||
|
||||
mux_hw = &mux->hw;
|
||||
mux->reg = reg;
|
||||
mux->shift = CCM_MUX_SHIFT;
|
||||
mux->mask = CCM_MUX_MASK;
|
||||
mux->lock = &imx_ccm_lock;
|
||||
|
||||
div = kzalloc(sizeof(*div), GFP_KERNEL);
|
||||
if (!div)
|
||||
goto fail;
|
||||
|
||||
div_hw = &div->hw;
|
||||
div->reg = reg;
|
||||
div->shift = CCM_DIV_SHIFT;
|
||||
div->width = CCM_DIV_WIDTH;
|
||||
div->lock = &imx_ccm_lock;
|
||||
div->flags = CLK_DIVIDER_ROUND_CLOSEST;
|
||||
|
||||
if (!(readl(reg + AUTHEN_OFFSET) & TZ_NS_MASK))
|
||||
clk_ro = true;
|
||||
|
||||
if (clk_ro) {
|
||||
hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
|
||||
mux_hw, &clk_mux_ro_ops, div_hw,
|
||||
&clk_divider_ro_ops, NULL, NULL, flags);
|
||||
} else {
|
||||
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
|
||||
if (!gate)
|
||||
goto fail;
|
||||
|
||||
gate_hw = &gate->hw;
|
||||
gate->reg = reg;
|
||||
gate->bit_idx = CCM_OFF_SHIFT;
|
||||
gate->lock = &imx_ccm_lock;
|
||||
gate->flags = CLK_GATE_SET_TO_DISABLE;
|
||||
|
||||
hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
|
||||
mux_hw, &clk_mux_ops, div_hw,
|
||||
&clk_divider_ops, gate_hw,
|
||||
&clk_gate_ops, flags | CLK_SET_RATE_NO_REPARENT);
|
||||
}
|
||||
|
||||
if (IS_ERR(hw))
|
||||
goto fail;
|
||||
|
||||
return hw;
|
||||
|
||||
fail:
|
||||
kfree(gate);
|
||||
kfree(div);
|
||||
kfree(mux);
|
||||
return ERR_CAST(hw);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(imx93_clk_composite_flags);
|
||||
323
drivers/clk/imx/clk-fracn-gppll.c
Normal file
323
drivers/clk/imx/clk-fracn-gppll.c
Normal file
@@ -0,0 +1,323 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright 2021 NXP
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
#define PLL_CTRL 0x0
|
||||
#define CLKMUX_BYPASS BIT(2)
|
||||
#define CLKMUX_EN BIT(1)
|
||||
#define POWERUP_MASK BIT(0)
|
||||
|
||||
#define PLL_ANA_PRG 0x10
|
||||
#define PLL_SPREAD_SPECTRUM 0x30
|
||||
|
||||
#define PLL_NUMERATOR 0x40
|
||||
#define PLL_MFN_MASK GENMASK(31, 2)
|
||||
|
||||
#define PLL_DENOMINATOR 0x50
|
||||
#define PLL_MFD_MASK GENMASK(29, 0)
|
||||
|
||||
#define PLL_DIV 0x60
|
||||
#define PLL_MFI_MASK GENMASK(24, 16)
|
||||
#define PLL_RDIV_MASK GENMASK(15, 13)
|
||||
#define PLL_ODIV_MASK GENMASK(7, 0)
|
||||
|
||||
#define PLL_DFS_CTRL(x) (0x70 + (x) * 0x10)
|
||||
|
||||
#define PLL_STATUS 0xF0
|
||||
#define LOCK_STATUS BIT(0)
|
||||
|
||||
#define DFS_STATUS 0xF4
|
||||
|
||||
#define LOCK_TIMEOUT_US 200
|
||||
|
||||
#define PLL_FRACN_GP(_rate, _mfi, _mfn, _mfd, _rdiv, _odiv) \
|
||||
{ \
|
||||
.rate = (_rate), \
|
||||
.mfi = (_mfi), \
|
||||
.mfn = (_mfn), \
|
||||
.mfd = (_mfd), \
|
||||
.rdiv = (_rdiv), \
|
||||
.odiv = (_odiv), \
|
||||
}
|
||||
|
||||
struct clk_fracn_gppll {
|
||||
struct clk_hw hw;
|
||||
void __iomem *base;
|
||||
const struct imx_fracn_gppll_rate_table *rate_table;
|
||||
int rate_count;
|
||||
};
|
||||
|
||||
/*
|
||||
* Fvco = Fref * (MFI + MFN / MFD)
|
||||
* Fout = Fvco / (rdiv * odiv)
|
||||
*/
|
||||
static const struct imx_fracn_gppll_rate_table fracn_tbl[] = {
|
||||
PLL_FRACN_GP(650000000U, 81, 0, 0, 0, 3),
|
||||
PLL_FRACN_GP(594000000U, 198, 0, 0, 0, 8),
|
||||
PLL_FRACN_GP(560000000U, 70, 0, 0, 0, 3),
|
||||
PLL_FRACN_GP(400000000U, 50, 0, 0, 0, 3),
|
||||
PLL_FRACN_GP(393216000U, 81, 92, 100, 0, 5)
|
||||
};
|
||||
|
||||
struct imx_fracn_gppll_clk imx_fracn_gppll = {
|
||||
.rate_table = fracn_tbl,
|
||||
.rate_count = ARRAY_SIZE(fracn_tbl),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(imx_fracn_gppll);
|
||||
|
||||
static inline struct clk_fracn_gppll *to_clk_fracn_gppll(struct clk_hw *hw)
|
||||
{
|
||||
return container_of(hw, struct clk_fracn_gppll, hw);
|
||||
}
|
||||
|
||||
static const struct imx_fracn_gppll_rate_table *
|
||||
imx_get_pll_settings(struct clk_fracn_gppll *pll, unsigned long rate)
|
||||
{
|
||||
const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pll->rate_count; i++)
|
||||
if (rate == rate_table[i].rate)
|
||||
return &rate_table[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static long clk_fracn_gppll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
|
||||
const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table;
|
||||
int i;
|
||||
|
||||
/* Assuming rate_table is in descending order */
|
||||
for (i = 0; i < pll->rate_count; i++)
|
||||
if (rate >= rate_table[i].rate)
|
||||
return rate_table[i].rate;
|
||||
|
||||
/* return minimum supported value */
|
||||
return rate_table[pll->rate_count - 1].rate;
|
||||
}
|
||||
|
||||
static unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
||||
{
|
||||
struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
|
||||
const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table;
|
||||
u32 pll_numerator, pll_denominator, pll_div;
|
||||
u32 mfi, mfn, mfd, rdiv, odiv;
|
||||
u64 fvco = parent_rate;
|
||||
long rate = 0;
|
||||
int i;
|
||||
|
||||
pll_numerator = readl_relaxed(pll->base + PLL_NUMERATOR);
|
||||
mfn = FIELD_GET(PLL_MFN_MASK, pll_numerator);
|
||||
|
||||
pll_denominator = readl_relaxed(pll->base + PLL_DENOMINATOR);
|
||||
mfd = FIELD_GET(PLL_MFD_MASK, pll_denominator);
|
||||
|
||||
pll_div = readl_relaxed(pll->base + PLL_DIV);
|
||||
mfi = FIELD_GET(PLL_MFI_MASK, pll_div);
|
||||
|
||||
rdiv = FIELD_GET(PLL_RDIV_MASK, pll_div);
|
||||
rdiv = rdiv + 1;
|
||||
odiv = FIELD_GET(PLL_ODIV_MASK, pll_div);
|
||||
switch (odiv) {
|
||||
case 0:
|
||||
odiv = 2;
|
||||
break;
|
||||
case 1:
|
||||
odiv = 3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sometimes, the recalculated rate has deviation due to
|
||||
* the frac part. So find the accurate pll rate from the table
|
||||
* first, if no match rate in the table, use the rate calculated
|
||||
* from the equation below.
|
||||
*/
|
||||
for (i = 0; i < pll->rate_count; i++) {
|
||||
if (rate_table[i].mfn == mfn && rate_table[i].mfi == mfi &&
|
||||
rate_table[i].mfd == mfd && rate_table[i].rdiv == rdiv &&
|
||||
rate_table[i].odiv == odiv)
|
||||
rate = rate_table[i].rate;
|
||||
}
|
||||
|
||||
if (rate)
|
||||
return (unsigned long)rate;
|
||||
|
||||
/* Fvco = Fref * (MFI + MFN / MFD) */
|
||||
fvco = fvco * mfi * mfd + fvco * mfn;
|
||||
do_div(fvco, mfd * rdiv * odiv);
|
||||
|
||||
return (unsigned long)fvco;
|
||||
}
|
||||
|
||||
static int clk_fracn_gppll_wait_lock(struct clk_fracn_gppll *pll)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
return readl_poll_timeout(pll->base + PLL_STATUS, val,
|
||||
val & LOCK_STATUS, 0, LOCK_TIMEOUT_US);
|
||||
}
|
||||
|
||||
static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate,
|
||||
unsigned long prate)
|
||||
{
|
||||
struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
|
||||
const struct imx_fracn_gppll_rate_table *rate;
|
||||
u32 tmp, pll_div, ana_mfn;
|
||||
int ret;
|
||||
|
||||
rate = imx_get_pll_settings(pll, drate);
|
||||
|
||||
/* Disable output */
|
||||
tmp = readl_relaxed(pll->base + PLL_CTRL);
|
||||
tmp &= ~CLKMUX_EN;
|
||||
writel_relaxed(tmp, pll->base + PLL_CTRL);
|
||||
|
||||
/* Power Down */
|
||||
tmp &= ~POWERUP_MASK;
|
||||
writel_relaxed(tmp, pll->base + PLL_CTRL);
|
||||
|
||||
/* Disable BYPASS */
|
||||
tmp &= ~CLKMUX_BYPASS;
|
||||
writel_relaxed(tmp, pll->base + PLL_CTRL);
|
||||
|
||||
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);
|
||||
writel_relaxed(rate->mfd, pll->base + PLL_DENOMINATOR);
|
||||
writel_relaxed(FIELD_PREP(PLL_MFN_MASK, rate->mfn), pll->base + PLL_NUMERATOR);
|
||||
|
||||
/* Wait for 5us according to fracn mode pll doc */
|
||||
udelay(5);
|
||||
|
||||
/* Enable Powerup */
|
||||
tmp |= POWERUP_MASK;
|
||||
writel_relaxed(tmp, pll->base + PLL_CTRL);
|
||||
|
||||
/* Wait Lock */
|
||||
ret = clk_fracn_gppll_wait_lock(pll);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable output */
|
||||
tmp |= CLKMUX_EN;
|
||||
writel_relaxed(tmp, pll->base + PLL_CTRL);
|
||||
|
||||
ana_mfn = readl_relaxed(pll->base + PLL_STATUS);
|
||||
ana_mfn = FIELD_GET(PLL_MFN_MASK, ana_mfn);
|
||||
|
||||
WARN(ana_mfn != rate->mfn, "ana_mfn != rate->mfn\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_fracn_gppll_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
val = readl_relaxed(pll->base + PLL_CTRL);
|
||||
if (val & POWERUP_MASK)
|
||||
return 0;
|
||||
|
||||
val |= CLKMUX_BYPASS;
|
||||
writel_relaxed(val, pll->base + PLL_CTRL);
|
||||
|
||||
val |= POWERUP_MASK;
|
||||
writel_relaxed(val, pll->base + PLL_CTRL);
|
||||
|
||||
val |= CLKMUX_EN;
|
||||
writel_relaxed(val, pll->base + PLL_CTRL);
|
||||
|
||||
ret = clk_fracn_gppll_wait_lock(pll);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val &= ~CLKMUX_BYPASS;
|
||||
writel_relaxed(val, pll->base + PLL_CTRL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_fracn_gppll_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
|
||||
u32 val;
|
||||
|
||||
val = readl_relaxed(pll->base + PLL_CTRL);
|
||||
|
||||
return (val & POWERUP_MASK) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void clk_fracn_gppll_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
|
||||
u32 val;
|
||||
|
||||
val = readl_relaxed(pll->base + PLL_CTRL);
|
||||
val &= ~POWERUP_MASK;
|
||||
writel_relaxed(val, pll->base + PLL_CTRL);
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_fracn_gppll_ops = {
|
||||
.prepare = clk_fracn_gppll_prepare,
|
||||
.unprepare = clk_fracn_gppll_unprepare,
|
||||
.is_prepared = clk_fracn_gppll_is_prepared,
|
||||
.recalc_rate = clk_fracn_gppll_recalc_rate,
|
||||
.round_rate = clk_fracn_gppll_round_rate,
|
||||
.set_rate = clk_fracn_gppll_set_rate,
|
||||
};
|
||||
|
||||
struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base,
|
||||
const struct imx_fracn_gppll_clk *pll_clk)
|
||||
{
|
||||
struct clk_fracn_gppll *pll;
|
||||
struct clk_hw *hw;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
|
||||
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
|
||||
if (!pll)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.flags = pll_clk->flags;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
init.ops = &clk_fracn_gppll_ops;
|
||||
|
||||
pll->base = base;
|
||||
pll->hw.init = &init;
|
||||
pll->rate_table = pll_clk->rate_table;
|
||||
pll->rate_count = pll_clk->rate_count;
|
||||
|
||||
hw = &pll->hw;
|
||||
|
||||
ret = clk_hw_register(NULL, hw);
|
||||
if (ret) {
|
||||
pr_err("%s: failed to register pll %s %d\n", __func__, name, ret);
|
||||
kfree(pll);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(imx_clk_fracn_gppll);
|
||||
@@ -849,7 +849,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
|
||||
hws[IMX7D_WDOG4_ROOT_CLK] = imx_clk_hw_gate4("wdog4_root_clk", "wdog_post_div", base + 0x49f0, 0);
|
||||
hws[IMX7D_KPP_ROOT_CLK] = imx_clk_hw_gate4("kpp_root_clk", "ipg_root_clk", base + 0x4aa0, 0);
|
||||
hws[IMX7D_CSI_MCLK_ROOT_CLK] = imx_clk_hw_gate4("csi_mclk_root_clk", "csi_mclk_post_div", base + 0x4490, 0);
|
||||
hws[IMX7D_AUDIO_MCLK_ROOT_CLK] = imx_clk_hw_gate4("audio_mclk_root_clk", "audio_mclk_post_div", base + 0x4790, 0);
|
||||
hws[IMX7D_WRCLK_ROOT_CLK] = imx_clk_hw_gate4("wrclk_root_clk", "wrclk_post_div", base + 0x47a0, 0);
|
||||
hws[IMX7D_USB_CTRL_CLK] = imx_clk_hw_gate4("usb_ctrl_clk", "ahb_root_clk", base + 0x4680, 0);
|
||||
hws[IMX7D_USB_PHY1_CLK] = imx_clk_hw_gate4("usb_phy1_clk", "pll_usb1_main_clk", base + 0x46a0, 0);
|
||||
|
||||
66
drivers/clk/imx/clk-imx8dxl-rsrc.c
Normal file
66
drivers/clk/imx/clk-imx8dxl-rsrc.c
Normal file
@@ -0,0 +1,66 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2019~2020 NXP
|
||||
*/
|
||||
|
||||
#include <dt-bindings/firmware/imx/rsrc.h>
|
||||
|
||||
#include "clk-scu.h"
|
||||
|
||||
/* Keep sorted in the ascending order */
|
||||
static u32 imx8dxl_clk_scu_rsrc_table[] = {
|
||||
IMX_SC_R_SPI_0,
|
||||
IMX_SC_R_SPI_1,
|
||||
IMX_SC_R_SPI_2,
|
||||
IMX_SC_R_SPI_3,
|
||||
IMX_SC_R_UART_0,
|
||||
IMX_SC_R_UART_1,
|
||||
IMX_SC_R_UART_2,
|
||||
IMX_SC_R_UART_3,
|
||||
IMX_SC_R_I2C_0,
|
||||
IMX_SC_R_I2C_1,
|
||||
IMX_SC_R_I2C_2,
|
||||
IMX_SC_R_I2C_3,
|
||||
IMX_SC_R_ADC_0,
|
||||
IMX_SC_R_FTM_0,
|
||||
IMX_SC_R_FTM_1,
|
||||
IMX_SC_R_CAN_0,
|
||||
IMX_SC_R_LCD_0,
|
||||
IMX_SC_R_LCD_0_PWM_0,
|
||||
IMX_SC_R_PWM_0,
|
||||
IMX_SC_R_PWM_1,
|
||||
IMX_SC_R_PWM_2,
|
||||
IMX_SC_R_PWM_3,
|
||||
IMX_SC_R_PWM_4,
|
||||
IMX_SC_R_PWM_5,
|
||||
IMX_SC_R_PWM_6,
|
||||
IMX_SC_R_PWM_7,
|
||||
IMX_SC_R_GPT_0,
|
||||
IMX_SC_R_GPT_1,
|
||||
IMX_SC_R_GPT_2,
|
||||
IMX_SC_R_GPT_3,
|
||||
IMX_SC_R_GPT_4,
|
||||
IMX_SC_R_FSPI_0,
|
||||
IMX_SC_R_FSPI_1,
|
||||
IMX_SC_R_SDHC_0,
|
||||
IMX_SC_R_SDHC_1,
|
||||
IMX_SC_R_SDHC_2,
|
||||
IMX_SC_R_ENET_0,
|
||||
IMX_SC_R_ENET_1,
|
||||
IMX_SC_R_MLB_0,
|
||||
IMX_SC_R_USB_1,
|
||||
IMX_SC_R_NAND,
|
||||
IMX_SC_R_M4_0_I2C,
|
||||
IMX_SC_R_M4_0_UART,
|
||||
IMX_SC_R_ELCDIF_PLL,
|
||||
IMX_SC_R_AUDIO_PLL_0,
|
||||
IMX_SC_R_AUDIO_PLL_1,
|
||||
IMX_SC_R_AUDIO_CLK_0,
|
||||
IMX_SC_R_AUDIO_CLK_1,
|
||||
IMX_SC_R_A35
|
||||
};
|
||||
|
||||
const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8dxl = {
|
||||
.rsrc = imx8dxl_clk_scu_rsrc_table,
|
||||
.num = ARRAY_SIZE(imx8dxl_clk_scu_rsrc_table),
|
||||
};
|
||||
@@ -366,45 +366,28 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
|
||||
hws[IMX8MM_SYS_PLL3_OUT] = imx_clk_hw_gate("sys_pll3_out", "sys_pll3_bypass", base + 0x114, 11);
|
||||
|
||||
/* SYS PLL1 fixed output */
|
||||
hws[IMX8MM_SYS_PLL1_40M_CG] = imx_clk_hw_gate("sys_pll1_40m_cg", "sys_pll1", base + 0x94, 27);
|
||||
hws[IMX8MM_SYS_PLL1_80M_CG] = imx_clk_hw_gate("sys_pll1_80m_cg", "sys_pll1", base + 0x94, 25);
|
||||
hws[IMX8MM_SYS_PLL1_100M_CG] = imx_clk_hw_gate("sys_pll1_100m_cg", "sys_pll1", base + 0x94, 23);
|
||||
hws[IMX8MM_SYS_PLL1_133M_CG] = imx_clk_hw_gate("sys_pll1_133m_cg", "sys_pll1", base + 0x94, 21);
|
||||
hws[IMX8MM_SYS_PLL1_160M_CG] = imx_clk_hw_gate("sys_pll1_160m_cg", "sys_pll1", base + 0x94, 19);
|
||||
hws[IMX8MM_SYS_PLL1_200M_CG] = imx_clk_hw_gate("sys_pll1_200m_cg", "sys_pll1", base + 0x94, 17);
|
||||
hws[IMX8MM_SYS_PLL1_266M_CG] = imx_clk_hw_gate("sys_pll1_266m_cg", "sys_pll1", base + 0x94, 15);
|
||||
hws[IMX8MM_SYS_PLL1_400M_CG] = imx_clk_hw_gate("sys_pll1_400m_cg", "sys_pll1", base + 0x94, 13);
|
||||
hws[IMX8MM_SYS_PLL1_OUT] = imx_clk_hw_gate("sys_pll1_out", "sys_pll1", base + 0x94, 11);
|
||||
|
||||
hws[IMX8MM_SYS_PLL1_40M] = imx_clk_hw_fixed_factor("sys_pll1_40m", "sys_pll1_40m_cg", 1, 20);
|
||||
hws[IMX8MM_SYS_PLL1_80M] = imx_clk_hw_fixed_factor("sys_pll1_80m", "sys_pll1_80m_cg", 1, 10);
|
||||
hws[IMX8MM_SYS_PLL1_100M] = imx_clk_hw_fixed_factor("sys_pll1_100m", "sys_pll1_100m_cg", 1, 8);
|
||||
hws[IMX8MM_SYS_PLL1_133M] = imx_clk_hw_fixed_factor("sys_pll1_133m", "sys_pll1_133m_cg", 1, 6);
|
||||
hws[IMX8MM_SYS_PLL1_160M] = imx_clk_hw_fixed_factor("sys_pll1_160m", "sys_pll1_160m_cg", 1, 5);
|
||||
hws[IMX8MM_SYS_PLL1_200M] = imx_clk_hw_fixed_factor("sys_pll1_200m", "sys_pll1_200m_cg", 1, 4);
|
||||
hws[IMX8MM_SYS_PLL1_266M] = imx_clk_hw_fixed_factor("sys_pll1_266m", "sys_pll1_266m_cg", 1, 3);
|
||||
hws[IMX8MM_SYS_PLL1_400M] = imx_clk_hw_fixed_factor("sys_pll1_400m", "sys_pll1_400m_cg", 1, 2);
|
||||
hws[IMX8MM_SYS_PLL1_40M] = imx_clk_hw_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20);
|
||||
hws[IMX8MM_SYS_PLL1_80M] = imx_clk_hw_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10);
|
||||
hws[IMX8MM_SYS_PLL1_100M] = imx_clk_hw_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8);
|
||||
hws[IMX8MM_SYS_PLL1_133M] = imx_clk_hw_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6);
|
||||
hws[IMX8MM_SYS_PLL1_160M] = imx_clk_hw_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5);
|
||||
hws[IMX8MM_SYS_PLL1_200M] = imx_clk_hw_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4);
|
||||
hws[IMX8MM_SYS_PLL1_266M] = imx_clk_hw_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3);
|
||||
hws[IMX8MM_SYS_PLL1_400M] = imx_clk_hw_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2);
|
||||
hws[IMX8MM_SYS_PLL1_800M] = imx_clk_hw_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1);
|
||||
|
||||
/* SYS PLL2 fixed output */
|
||||
hws[IMX8MM_SYS_PLL2_50M_CG] = imx_clk_hw_gate("sys_pll2_50m_cg", "sys_pll2", base + 0x104, 27);
|
||||
hws[IMX8MM_SYS_PLL2_100M_CG] = imx_clk_hw_gate("sys_pll2_100m_cg", "sys_pll2", base + 0x104, 25);
|
||||
hws[IMX8MM_SYS_PLL2_125M_CG] = imx_clk_hw_gate("sys_pll2_125m_cg", "sys_pll2", base + 0x104, 23);
|
||||
hws[IMX8MM_SYS_PLL2_166M_CG] = imx_clk_hw_gate("sys_pll2_166m_cg", "sys_pll2", base + 0x104, 21);
|
||||
hws[IMX8MM_SYS_PLL2_200M_CG] = imx_clk_hw_gate("sys_pll2_200m_cg", "sys_pll2", base + 0x104, 19);
|
||||
hws[IMX8MM_SYS_PLL2_250M_CG] = imx_clk_hw_gate("sys_pll2_250m_cg", "sys_pll2", base + 0x104, 17);
|
||||
hws[IMX8MM_SYS_PLL2_333M_CG] = imx_clk_hw_gate("sys_pll2_333m_cg", "sys_pll2", base + 0x104, 15);
|
||||
hws[IMX8MM_SYS_PLL2_500M_CG] = imx_clk_hw_gate("sys_pll2_500m_cg", "sys_pll2", base + 0x104, 13);
|
||||
hws[IMX8MM_SYS_PLL2_OUT] = imx_clk_hw_gate("sys_pll2_out", "sys_pll2", base + 0x104, 11);
|
||||
|
||||
hws[IMX8MM_SYS_PLL2_50M] = imx_clk_hw_fixed_factor("sys_pll2_50m", "sys_pll2_50m_cg", 1, 20);
|
||||
hws[IMX8MM_SYS_PLL2_100M] = imx_clk_hw_fixed_factor("sys_pll2_100m", "sys_pll2_100m_cg", 1, 10);
|
||||
hws[IMX8MM_SYS_PLL2_125M] = imx_clk_hw_fixed_factor("sys_pll2_125m", "sys_pll2_125m_cg", 1, 8);
|
||||
hws[IMX8MM_SYS_PLL2_166M] = imx_clk_hw_fixed_factor("sys_pll2_166m", "sys_pll2_166m_cg", 1, 6);
|
||||
hws[IMX8MM_SYS_PLL2_200M] = imx_clk_hw_fixed_factor("sys_pll2_200m", "sys_pll2_200m_cg", 1, 5);
|
||||
hws[IMX8MM_SYS_PLL2_250M] = imx_clk_hw_fixed_factor("sys_pll2_250m", "sys_pll2_250m_cg", 1, 4);
|
||||
hws[IMX8MM_SYS_PLL2_333M] = imx_clk_hw_fixed_factor("sys_pll2_333m", "sys_pll2_333m_cg", 1, 3);
|
||||
hws[IMX8MM_SYS_PLL2_500M] = imx_clk_hw_fixed_factor("sys_pll2_500m", "sys_pll2_500m_cg", 1, 2);
|
||||
hws[IMX8MM_SYS_PLL2_50M] = imx_clk_hw_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20);
|
||||
hws[IMX8MM_SYS_PLL2_100M] = imx_clk_hw_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10);
|
||||
hws[IMX8MM_SYS_PLL2_125M] = imx_clk_hw_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8);
|
||||
hws[IMX8MM_SYS_PLL2_166M] = imx_clk_hw_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6);
|
||||
hws[IMX8MM_SYS_PLL2_200M] = imx_clk_hw_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5);
|
||||
hws[IMX8MM_SYS_PLL2_250M] = imx_clk_hw_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4);
|
||||
hws[IMX8MM_SYS_PLL2_333M] = imx_clk_hw_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3);
|
||||
hws[IMX8MM_SYS_PLL2_500M] = imx_clk_hw_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2);
|
||||
hws[IMX8MM_SYS_PLL2_1000M] = imx_clk_hw_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1);
|
||||
|
||||
hws[IMX8MM_CLK_CLKOUT1_SEL] = imx_clk_hw_mux2("clkout1_sel", base + 0x128, 4, 4, clkout_sels, ARRAY_SIZE(clkout_sels));
|
||||
|
||||
@@ -364,45 +364,27 @@ static int imx8mn_clocks_probe(struct platform_device *pdev)
|
||||
hws[IMX8MN_SYS_PLL3_OUT] = imx_clk_hw_gate("sys_pll3_out", "sys_pll3_bypass", base + 0x114, 11);
|
||||
|
||||
/* SYS PLL1 fixed output */
|
||||
hws[IMX8MN_SYS_PLL1_40M_CG] = imx_clk_hw_gate("sys_pll1_40m_cg", "sys_pll1", base + 0x94, 27);
|
||||
hws[IMX8MN_SYS_PLL1_80M_CG] = imx_clk_hw_gate("sys_pll1_80m_cg", "sys_pll1", base + 0x94, 25);
|
||||
hws[IMX8MN_SYS_PLL1_100M_CG] = imx_clk_hw_gate("sys_pll1_100m_cg", "sys_pll1", base + 0x94, 23);
|
||||
hws[IMX8MN_SYS_PLL1_133M_CG] = imx_clk_hw_gate("sys_pll1_133m_cg", "sys_pll1", base + 0x94, 21);
|
||||
hws[IMX8MN_SYS_PLL1_160M_CG] = imx_clk_hw_gate("sys_pll1_160m_cg", "sys_pll1", base + 0x94, 19);
|
||||
hws[IMX8MN_SYS_PLL1_200M_CG] = imx_clk_hw_gate("sys_pll1_200m_cg", "sys_pll1", base + 0x94, 17);
|
||||
hws[IMX8MN_SYS_PLL1_266M_CG] = imx_clk_hw_gate("sys_pll1_266m_cg", "sys_pll1", base + 0x94, 15);
|
||||
hws[IMX8MN_SYS_PLL1_400M_CG] = imx_clk_hw_gate("sys_pll1_400m_cg", "sys_pll1", base + 0x94, 13);
|
||||
hws[IMX8MN_SYS_PLL1_OUT] = imx_clk_hw_gate("sys_pll1_out", "sys_pll1", base + 0x94, 11);
|
||||
|
||||
hws[IMX8MN_SYS_PLL1_40M] = imx_clk_hw_fixed_factor("sys_pll1_40m", "sys_pll1_40m_cg", 1, 20);
|
||||
hws[IMX8MN_SYS_PLL1_80M] = imx_clk_hw_fixed_factor("sys_pll1_80m", "sys_pll1_80m_cg", 1, 10);
|
||||
hws[IMX8MN_SYS_PLL1_100M] = imx_clk_hw_fixed_factor("sys_pll1_100m", "sys_pll1_100m_cg", 1, 8);
|
||||
hws[IMX8MN_SYS_PLL1_133M] = imx_clk_hw_fixed_factor("sys_pll1_133m", "sys_pll1_133m_cg", 1, 6);
|
||||
hws[IMX8MN_SYS_PLL1_160M] = imx_clk_hw_fixed_factor("sys_pll1_160m", "sys_pll1_160m_cg", 1, 5);
|
||||
hws[IMX8MN_SYS_PLL1_200M] = imx_clk_hw_fixed_factor("sys_pll1_200m", "sys_pll1_200m_cg", 1, 4);
|
||||
hws[IMX8MN_SYS_PLL1_266M] = imx_clk_hw_fixed_factor("sys_pll1_266m", "sys_pll1_266m_cg", 1, 3);
|
||||
hws[IMX8MN_SYS_PLL1_400M] = imx_clk_hw_fixed_factor("sys_pll1_400m", "sys_pll1_400m_cg", 1, 2);
|
||||
hws[IMX8MN_SYS_PLL1_40M] = imx_clk_hw_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20);
|
||||
hws[IMX8MN_SYS_PLL1_80M] = imx_clk_hw_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10);
|
||||
hws[IMX8MN_SYS_PLL1_100M] = imx_clk_hw_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8);
|
||||
hws[IMX8MN_SYS_PLL1_133M] = imx_clk_hw_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6);
|
||||
hws[IMX8MN_SYS_PLL1_160M] = imx_clk_hw_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5);
|
||||
hws[IMX8MN_SYS_PLL1_200M] = imx_clk_hw_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4);
|
||||
hws[IMX8MN_SYS_PLL1_266M] = imx_clk_hw_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3);
|
||||
hws[IMX8MN_SYS_PLL1_400M] = imx_clk_hw_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2);
|
||||
hws[IMX8MN_SYS_PLL1_800M] = imx_clk_hw_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1);
|
||||
|
||||
/* SYS PLL2 fixed output */
|
||||
hws[IMX8MN_SYS_PLL2_50M_CG] = imx_clk_hw_gate("sys_pll2_50m_cg", "sys_pll2", base + 0x104, 27);
|
||||
hws[IMX8MN_SYS_PLL2_100M_CG] = imx_clk_hw_gate("sys_pll2_100m_cg", "sys_pll2", base + 0x104, 25);
|
||||
hws[IMX8MN_SYS_PLL2_125M_CG] = imx_clk_hw_gate("sys_pll2_125m_cg", "sys_pll2", base + 0x104, 23);
|
||||
hws[IMX8MN_SYS_PLL2_166M_CG] = imx_clk_hw_gate("sys_pll2_166m_cg", "sys_pll2", base + 0x104, 21);
|
||||
hws[IMX8MN_SYS_PLL2_200M_CG] = imx_clk_hw_gate("sys_pll2_200m_cg", "sys_pll2", base + 0x104, 19);
|
||||
hws[IMX8MN_SYS_PLL2_250M_CG] = imx_clk_hw_gate("sys_pll2_250m_cg", "sys_pll2", base + 0x104, 17);
|
||||
hws[IMX8MN_SYS_PLL2_333M_CG] = imx_clk_hw_gate("sys_pll2_333m_cg", "sys_pll2", base + 0x104, 15);
|
||||
hws[IMX8MN_SYS_PLL2_500M_CG] = imx_clk_hw_gate("sys_pll2_500m_cg", "sys_pll2", base + 0x104, 13);
|
||||
hws[IMX8MN_SYS_PLL2_OUT] = imx_clk_hw_gate("sys_pll2_out", "sys_pll2", base + 0x104, 11);
|
||||
|
||||
hws[IMX8MN_SYS_PLL2_50M] = imx_clk_hw_fixed_factor("sys_pll2_50m", "sys_pll2_50m_cg", 1, 20);
|
||||
hws[IMX8MN_SYS_PLL2_100M] = imx_clk_hw_fixed_factor("sys_pll2_100m", "sys_pll2_100m_cg", 1, 10);
|
||||
hws[IMX8MN_SYS_PLL2_125M] = imx_clk_hw_fixed_factor("sys_pll2_125m", "sys_pll2_125m_cg", 1, 8);
|
||||
hws[IMX8MN_SYS_PLL2_166M] = imx_clk_hw_fixed_factor("sys_pll2_166m", "sys_pll2_166m_cg", 1, 6);
|
||||
hws[IMX8MN_SYS_PLL2_200M] = imx_clk_hw_fixed_factor("sys_pll2_200m", "sys_pll2_200m_cg", 1, 5);
|
||||
hws[IMX8MN_SYS_PLL2_250M] = imx_clk_hw_fixed_factor("sys_pll2_250m", "sys_pll2_250m_cg", 1, 4);
|
||||
hws[IMX8MN_SYS_PLL2_333M] = imx_clk_hw_fixed_factor("sys_pll2_333m", "sys_pll2_333m_cg", 1, 3);
|
||||
hws[IMX8MN_SYS_PLL2_500M] = imx_clk_hw_fixed_factor("sys_pll2_500m", "sys_pll2_500m_cg", 1, 2);
|
||||
hws[IMX8MN_SYS_PLL2_50M] = imx_clk_hw_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20);
|
||||
hws[IMX8MN_SYS_PLL2_100M] = imx_clk_hw_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10);
|
||||
hws[IMX8MN_SYS_PLL2_125M] = imx_clk_hw_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8);
|
||||
hws[IMX8MN_SYS_PLL2_166M] = imx_clk_hw_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6);
|
||||
hws[IMX8MN_SYS_PLL2_200M] = imx_clk_hw_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5);
|
||||
hws[IMX8MN_SYS_PLL2_250M] = imx_clk_hw_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4);
|
||||
hws[IMX8MN_SYS_PLL2_333M] = imx_clk_hw_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3);
|
||||
hws[IMX8MN_SYS_PLL2_500M] = imx_clk_hw_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2);
|
||||
hws[IMX8MN_SYS_PLL2_1000M] = imx_clk_hw_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1);
|
||||
|
||||
hws[IMX8MN_CLK_CLKOUT1_SEL] = imx_clk_hw_mux2("clkout1_sel", base + 0x128, 4, 4, clkout_sels, ARRAY_SIZE(clkout_sels));
|
||||
|
||||
@@ -480,44 +480,28 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
|
||||
hws[IMX8MP_ARM_PLL_OUT] = imx_clk_hw_gate("arm_pll_out", "arm_pll_bypass", anatop_base + 0x84, 11);
|
||||
hws[IMX8MP_SYS_PLL3_OUT] = imx_clk_hw_gate("sys_pll3_out", "sys_pll3_bypass", anatop_base + 0x114, 11);
|
||||
|
||||
hws[IMX8MP_SYS_PLL1_40M_CG] = imx_clk_hw_gate("sys_pll1_40m_cg", "sys_pll1_bypass", anatop_base + 0x94, 27);
|
||||
hws[IMX8MP_SYS_PLL1_80M_CG] = imx_clk_hw_gate("sys_pll1_80m_cg", "sys_pll1_bypass", anatop_base + 0x94, 25);
|
||||
hws[IMX8MP_SYS_PLL1_100M_CG] = imx_clk_hw_gate("sys_pll1_100m_cg", "sys_pll1_bypass", anatop_base + 0x94, 23);
|
||||
hws[IMX8MP_SYS_PLL1_133M_CG] = imx_clk_hw_gate("sys_pll1_133m_cg", "sys_pll1_bypass", anatop_base + 0x94, 21);
|
||||
hws[IMX8MP_SYS_PLL1_160M_CG] = imx_clk_hw_gate("sys_pll1_160m_cg", "sys_pll1_bypass", anatop_base + 0x94, 19);
|
||||
hws[IMX8MP_SYS_PLL1_200M_CG] = imx_clk_hw_gate("sys_pll1_200m_cg", "sys_pll1_bypass", anatop_base + 0x94, 17);
|
||||
hws[IMX8MP_SYS_PLL1_266M_CG] = imx_clk_hw_gate("sys_pll1_266m_cg", "sys_pll1_bypass", anatop_base + 0x94, 15);
|
||||
hws[IMX8MP_SYS_PLL1_400M_CG] = imx_clk_hw_gate("sys_pll1_400m_cg", "sys_pll1_bypass", anatop_base + 0x94, 13);
|
||||
hws[IMX8MP_SYS_PLL1_OUT] = imx_clk_hw_gate("sys_pll1_out", "sys_pll1_bypass", anatop_base + 0x94, 11);
|
||||
|
||||
hws[IMX8MP_SYS_PLL1_40M] = imx_clk_hw_fixed_factor("sys_pll1_40m", "sys_pll1_40m_cg", 1, 20);
|
||||
hws[IMX8MP_SYS_PLL1_80M] = imx_clk_hw_fixed_factor("sys_pll1_80m", "sys_pll1_80m_cg", 1, 10);
|
||||
hws[IMX8MP_SYS_PLL1_100M] = imx_clk_hw_fixed_factor("sys_pll1_100m", "sys_pll1_100m_cg", 1, 8);
|
||||
hws[IMX8MP_SYS_PLL1_133M] = imx_clk_hw_fixed_factor("sys_pll1_133m", "sys_pll1_133m_cg", 1, 6);
|
||||
hws[IMX8MP_SYS_PLL1_160M] = imx_clk_hw_fixed_factor("sys_pll1_160m", "sys_pll1_160m_cg", 1, 5);
|
||||
hws[IMX8MP_SYS_PLL1_200M] = imx_clk_hw_fixed_factor("sys_pll1_200m", "sys_pll1_200m_cg", 1, 4);
|
||||
hws[IMX8MP_SYS_PLL1_266M] = imx_clk_hw_fixed_factor("sys_pll1_266m", "sys_pll1_266m_cg", 1, 3);
|
||||
hws[IMX8MP_SYS_PLL1_400M] = imx_clk_hw_fixed_factor("sys_pll1_400m", "sys_pll1_400m_cg", 1, 2);
|
||||
hws[IMX8MP_SYS_PLL1_40M] = imx_clk_hw_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20);
|
||||
hws[IMX8MP_SYS_PLL1_80M] = imx_clk_hw_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10);
|
||||
hws[IMX8MP_SYS_PLL1_100M] = imx_clk_hw_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8);
|
||||
hws[IMX8MP_SYS_PLL1_133M] = imx_clk_hw_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6);
|
||||
hws[IMX8MP_SYS_PLL1_160M] = imx_clk_hw_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5);
|
||||
hws[IMX8MP_SYS_PLL1_200M] = imx_clk_hw_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4);
|
||||
hws[IMX8MP_SYS_PLL1_266M] = imx_clk_hw_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3);
|
||||
hws[IMX8MP_SYS_PLL1_400M] = imx_clk_hw_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2);
|
||||
hws[IMX8MP_SYS_PLL1_800M] = imx_clk_hw_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1);
|
||||
|
||||
hws[IMX8MP_SYS_PLL2_50M_CG] = imx_clk_hw_gate("sys_pll2_50m_cg", "sys_pll2_bypass", anatop_base + 0x104, 27);
|
||||
hws[IMX8MP_SYS_PLL2_100M_CG] = imx_clk_hw_gate("sys_pll2_100m_cg", "sys_pll2_bypass", anatop_base + 0x104, 25);
|
||||
hws[IMX8MP_SYS_PLL2_125M_CG] = imx_clk_hw_gate("sys_pll2_125m_cg", "sys_pll2_bypass", anatop_base + 0x104, 23);
|
||||
hws[IMX8MP_SYS_PLL2_166M_CG] = imx_clk_hw_gate("sys_pll2_166m_cg", "sys_pll2_bypass", anatop_base + 0x104, 21);
|
||||
hws[IMX8MP_SYS_PLL2_200M_CG] = imx_clk_hw_gate("sys_pll2_200m_cg", "sys_pll2_bypass", anatop_base + 0x104, 19);
|
||||
hws[IMX8MP_SYS_PLL2_250M_CG] = imx_clk_hw_gate("sys_pll2_250m_cg", "sys_pll2_bypass", anatop_base + 0x104, 17);
|
||||
hws[IMX8MP_SYS_PLL2_333M_CG] = imx_clk_hw_gate("sys_pll2_333m_cg", "sys_pll2_bypass", anatop_base + 0x104, 15);
|
||||
hws[IMX8MP_SYS_PLL2_500M_CG] = imx_clk_hw_gate("sys_pll2_500m_cg", "sys_pll2_bypass", anatop_base + 0x104, 13);
|
||||
hws[IMX8MP_SYS_PLL2_OUT] = imx_clk_hw_gate("sys_pll2_out", "sys_pll2_bypass", anatop_base + 0x104, 11);
|
||||
|
||||
hws[IMX8MP_SYS_PLL2_50M] = imx_clk_hw_fixed_factor("sys_pll2_50m", "sys_pll2_50m_cg", 1, 20);
|
||||
hws[IMX8MP_SYS_PLL2_100M] = imx_clk_hw_fixed_factor("sys_pll2_100m", "sys_pll2_100m_cg", 1, 10);
|
||||
hws[IMX8MP_SYS_PLL2_125M] = imx_clk_hw_fixed_factor("sys_pll2_125m", "sys_pll2_125m_cg", 1, 8);
|
||||
hws[IMX8MP_SYS_PLL2_166M] = imx_clk_hw_fixed_factor("sys_pll2_166m", "sys_pll2_166m_cg", 1, 6);
|
||||
hws[IMX8MP_SYS_PLL2_200M] = imx_clk_hw_fixed_factor("sys_pll2_200m", "sys_pll2_200m_cg", 1, 5);
|
||||
hws[IMX8MP_SYS_PLL2_250M] = imx_clk_hw_fixed_factor("sys_pll2_250m", "sys_pll2_250m_cg", 1, 4);
|
||||
hws[IMX8MP_SYS_PLL2_333M] = imx_clk_hw_fixed_factor("sys_pll2_333m", "sys_pll2_333m_cg", 1, 3);
|
||||
hws[IMX8MP_SYS_PLL2_500M] = imx_clk_hw_fixed_factor("sys_pll2_500m", "sys_pll2_500m_cg", 1, 2);
|
||||
hws[IMX8MP_SYS_PLL2_50M] = imx_clk_hw_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20);
|
||||
hws[IMX8MP_SYS_PLL2_100M] = imx_clk_hw_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10);
|
||||
hws[IMX8MP_SYS_PLL2_125M] = imx_clk_hw_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8);
|
||||
hws[IMX8MP_SYS_PLL2_166M] = imx_clk_hw_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6);
|
||||
hws[IMX8MP_SYS_PLL2_200M] = imx_clk_hw_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5);
|
||||
hws[IMX8MP_SYS_PLL2_250M] = imx_clk_hw_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4);
|
||||
hws[IMX8MP_SYS_PLL2_333M] = imx_clk_hw_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3);
|
||||
hws[IMX8MP_SYS_PLL2_500M] = imx_clk_hw_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2);
|
||||
hws[IMX8MP_SYS_PLL2_1000M] = imx_clk_hw_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1);
|
||||
|
||||
hws[IMX8MP_CLK_A53_DIV] = imx8m_clk_hw_composite_core("arm_a53_div", imx8mp_a53_sels, ccm_base + 0x8000);
|
||||
@@ -694,6 +678,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
|
||||
hws[IMX8MP_CLK_MEDIA_CAM2_PIX_ROOT] = imx_clk_hw_gate2_shared2("media_cam2_pix_root_clk", "media_cam2_pix", ccm_base + 0x45d0, 0, &share_count_media);
|
||||
hws[IMX8MP_CLK_MEDIA_DISP1_PIX_ROOT] = imx_clk_hw_gate2_shared2("media_disp1_pix_root_clk", "media_disp1_pix", ccm_base + 0x45d0, 0, &share_count_media);
|
||||
hws[IMX8MP_CLK_MEDIA_DISP2_PIX_ROOT] = imx_clk_hw_gate2_shared2("media_disp2_pix_root_clk", "media_disp2_pix", ccm_base + 0x45d0, 0, &share_count_media);
|
||||
hws[IMX8MP_CLK_MEDIA_MIPI_PHY1_REF_ROOT] = imx_clk_hw_gate2_shared2("media_mipi_phy1_ref_root", "media_mipi_phy1_ref", ccm_base + 0x45d0, 0, &share_count_media);
|
||||
hws[IMX8MP_CLK_MEDIA_ISP_ROOT] = imx_clk_hw_gate2_shared2("media_isp_root_clk", "media_isp", ccm_base + 0x45d0, 0, &share_count_media);
|
||||
|
||||
hws[IMX8MP_CLK_USDHC3_ROOT] = imx_clk_hw_gate4("usdhc3_root_clk", "usdhc3", ccm_base + 0x45e0, 0);
|
||||
|
||||
@@ -248,7 +248,7 @@ static int imx_lpcg_parse_clks_from_dt(struct platform_device *pdev,
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
idx = bit_offset[i] / 4;
|
||||
if (idx > IMX_LPCG_MAX_CLKS) {
|
||||
if (idx >= IMX_LPCG_MAX_CLKS) {
|
||||
dev_warn(&pdev->dev, "invalid bit offset of clock %d\n",
|
||||
i);
|
||||
ret = -EINVAL;
|
||||
|
||||
@@ -295,6 +295,7 @@ static int imx8qxp_clk_probe(struct platform_device *pdev)
|
||||
|
||||
static const struct of_device_id imx8qxp_match[] = {
|
||||
{ .compatible = "fsl,scu-clk", },
|
||||
{ .compatible = "fsl,imx8dxl-clk", &imx_clk_scu_rsrc_imx8dxl, },
|
||||
{ .compatible = "fsl,imx8qxp-clk", &imx_clk_scu_rsrc_imx8qxp, },
|
||||
{ .compatible = "fsl,imx8qm-clk", &imx_clk_scu_rsrc_imx8qm, },
|
||||
{ /* sentinel */ }
|
||||
|
||||
341
drivers/clk/imx/clk-imx93.c
Normal file
341
drivers/clk/imx/clk-imx93.c
Normal file
@@ -0,0 +1,341 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright 2021 NXP.
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <dt-bindings/clock/imx93-clock.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
enum clk_sel {
|
||||
LOW_SPEED_IO_SEL,
|
||||
NON_IO_SEL,
|
||||
FAST_SEL,
|
||||
AUDIO_SEL,
|
||||
VIDEO_SEL,
|
||||
TPM_SEL,
|
||||
CKO1_SEL,
|
||||
CKO2_SEL,
|
||||
MISC_SEL,
|
||||
MAX_SEL
|
||||
};
|
||||
|
||||
static const char *parent_names[MAX_SEL][4] = {
|
||||
{"osc_24m", "sys_pll_pfd0_div2", "sys_pll_pfd1_div2", "video_pll"},
|
||||
{"osc_24m", "sys_pll_pfd0_div2", "sys_pll_pfd1_div2", "sys_pll_pfd2_div2"},
|
||||
{"osc_24m", "sys_pll_pfd0", "sys_pll_pfd1", "sys_pll_pfd2"},
|
||||
{"osc_24m", "audio_pll", "video_pll", "clk_ext1"},
|
||||
{"osc_24m", "audio_pll", "video_pll", "sys_pll_pfd0"},
|
||||
{"osc_24m", "sys_pll_pfd0", "audio_pll", "clk_ext1"},
|
||||
{"osc_24m", "sys_pll_pfd0", "sys_pll_pfd1", "audio_pll"},
|
||||
{"osc_24m", "sys_pll_pfd0", "sys_pll_pfd1", "video_pll"},
|
||||
{"osc_24m", "audio_pll", "video_pll", "sys_pll_pfd2"},
|
||||
};
|
||||
|
||||
static const struct imx93_clk_root {
|
||||
u32 clk;
|
||||
char *name;
|
||||
u32 off;
|
||||
enum clk_sel sel;
|
||||
unsigned long flags;
|
||||
} root_array[] = {
|
||||
/* a55/m33/bus critical clk for system run */
|
||||
{ IMX93_CLK_A55_PERIPH, "a55_periph_root", 0x0000, FAST_SEL, CLK_IS_CRITICAL },
|
||||
{ IMX93_CLK_A55_MTR_BUS, "a55_mtr_bus_root", 0x0080, LOW_SPEED_IO_SEL, CLK_IS_CRITICAL },
|
||||
{ IMX93_CLK_A55, "a55_root", 0x0100, FAST_SEL, CLK_IS_CRITICAL },
|
||||
{ IMX93_CLK_M33, "m33_root", 0x0180, LOW_SPEED_IO_SEL, CLK_IS_CRITICAL },
|
||||
{ IMX93_CLK_BUS_WAKEUP, "bus_wakeup_root", 0x0280, LOW_SPEED_IO_SEL, CLK_IS_CRITICAL },
|
||||
{ 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_FLEXIO1, "flexio1_root", 0x0500, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_FLEXIO2, "flexio2_root", 0x0580, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPIT1, "lpit1_root", 0x0600, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPIT2, "lpit2_root", 0x0680, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPTMR1, "lptmr1_root", 0x0700, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPTMR2, "lptmr2_root", 0x0780, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_TPM1, "tpm1_root", 0x0800, TPM_SEL, },
|
||||
{ IMX93_CLK_TPM2, "tpm2_root", 0x0880, TPM_SEL, },
|
||||
{ IMX93_CLK_TPM3, "tpm3_root", 0x0900, TPM_SEL, },
|
||||
{ IMX93_CLK_TPM4, "tpm4_root", 0x0980, TPM_SEL, },
|
||||
{ IMX93_CLK_TPM5, "tpm5_root", 0x0a00, TPM_SEL, },
|
||||
{ IMX93_CLK_TPM6, "tpm6_root", 0x0a80, TPM_SEL, },
|
||||
{ IMX93_CLK_FLEXSPI1, "flexspi1_root", 0x0b00, FAST_SEL, },
|
||||
{ IMX93_CLK_CAN1, "can1_root", 0x0b80, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_CAN2, "can2_root", 0x0c00, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPUART1, "lpuart1_root", 0x0c80, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPUART2, "lpuart2_root", 0x0d00, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPUART3, "lpuart3_root", 0x0d80, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPUART4, "lpuart4_root", 0x0e00, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPUART5, "lpuart5_root", 0x0e80, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPUART6, "lpuart6_root", 0x0f00, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPUART7, "lpuart7_root", 0x0f80, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPUART8, "lpuart8_root", 0x1000, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPI2C1, "lpi2c1_root", 0x1080, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPI2C2, "lpi2c2_root", 0x1100, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPI2C3, "lpi2c3_root", 0x1180, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPI2C4, "lpi2c4_root", 0x1200, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPI2C5, "lpi2c5_root", 0x1280, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPI2C6, "lpi2c6_root", 0x1300, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPI2C7, "lpi2c7_root", 0x1380, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPI2C8, "lpi2c8_root", 0x1400, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPSPI1, "lpspi1_root", 0x1480, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPSPI2, "lpspi2_root", 0x1500, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPSPI3, "lpspi3_root", 0x1580, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPSPI4, "lpspi4_root", 0x1600, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPSPI5, "lpspi5_root", 0x1680, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPSPI6, "lpspi6_root", 0x1700, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPSPI7, "lpspi7_root", 0x1780, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPSPI8, "lpspi8_root", 0x1800, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_I3C1, "i3c1_root", 0x1880, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_I3C2, "i3c2_root", 0x1900, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_USDHC1, "usdhc1_root", 0x1980, FAST_SEL, },
|
||||
{ IMX93_CLK_USDHC2, "usdhc2_root", 0x1a00, FAST_SEL, },
|
||||
{ IMX93_CLK_USDHC3, "usdhc3_root", 0x1a80, FAST_SEL, },
|
||||
{ IMX93_CLK_SAI1, "sai1_root", 0x1b00, AUDIO_SEL, },
|
||||
{ IMX93_CLK_SAI2, "sai2_root", 0x1b80, AUDIO_SEL, },
|
||||
{ IMX93_CLK_SAI3, "sai3_root", 0x1c00, AUDIO_SEL, },
|
||||
{ IMX93_CLK_CCM_CKO1, "ccm_cko1_root", 0x1c80, CKO1_SEL, },
|
||||
{ IMX93_CLK_CCM_CKO2, "ccm_cko2_root", 0x1d00, CKO2_SEL, },
|
||||
{ IMX93_CLK_CCM_CKO3, "ccm_cko3_root", 0x1d80, CKO1_SEL, },
|
||||
{ IMX93_CLK_CCM_CKO4, "ccm_cko4_root", 0x1e00, CKO2_SEL, },
|
||||
{ IMX93_CLK_HSIO, "hsio_root", 0x1e80, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_HSIO_USB_TEST_60M, "hsio_usb_test_60m_root", 0x1f00, LOW_SPEED_IO_SEL, },
|
||||
{ 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_ML_APB, "ml_apb_root", 0x2180, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_ML, "ml_root", 0x2200, FAST_SEL, },
|
||||
{ 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_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_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, },
|
||||
{ IMX93_CLK_TSTMR2, "tstmr2_root", 0x2880, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_MQS1, "mqs1_root", 0x2900, AUDIO_SEL, },
|
||||
{ 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_USB_PHY_BURUNIN, "usb_phy_root", 0x2e80, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_PAL_CAME_SCAN, "pal_came_scan_root", 0x2f00, MISC_SEL, }
|
||||
};
|
||||
|
||||
static const struct imx93_clk_ccgr {
|
||||
u32 clk;
|
||||
char *name;
|
||||
char *parent_name;
|
||||
u32 off;
|
||||
unsigned long flags;
|
||||
} ccgr_array[] = {
|
||||
{ IMX93_CLK_A55_GATE, "a55", "a55_root", 0x8000, },
|
||||
/* M33 critical clk for system run */
|
||||
{ IMX93_CLK_CM33_GATE, "cm33", "m33_root", 0x8040, CLK_IS_CRITICAL },
|
||||
{ IMX93_CLK_ADC1_GATE, "adc1", "osc_24m", 0x82c0, },
|
||||
{ IMX93_CLK_WDOG1_GATE, "wdog1", "osc_24m", 0x8300, },
|
||||
{ IMX93_CLK_WDOG2_GATE, "wdog2", "osc_24m", 0x8340, },
|
||||
{ IMX93_CLK_WDOG3_GATE, "wdog3", "osc_24m", 0x8380, },
|
||||
{ IMX93_CLK_WDOG4_GATE, "wdog4", "osc_24m", 0x83c0, },
|
||||
{ IMX93_CLK_WDOG5_GATE, "wdog5", "osc_24m", 0x8400, },
|
||||
{ IMX93_CLK_SEMA1_GATE, "sema1", "bus_aon_root", 0x8440, },
|
||||
{ IMX93_CLK_SEMA2_GATE, "sema2", "bus_wakeup_root", 0x8480, },
|
||||
{ IMX93_CLK_MU_A_GATE, "mu_a", "bus_aon_root", 0x84c0, },
|
||||
{ IMX93_CLK_MU_B_GATE, "mu_b", "bus_aon_root", 0x8500, },
|
||||
{ IMX93_CLK_EDMA1_GATE, "edma1", "wakeup_axi_root", 0x8540, },
|
||||
{ IMX93_CLK_EDMA2_GATE, "edma2", "wakeup_axi_root", 0x8580, },
|
||||
{ IMX93_CLK_FLEXSPI1_GATE, "flexspi", "flexspi_root", 0x8640, },
|
||||
{ IMX93_CLK_GPIO1_GATE, "gpio1", "m33_root", 0x8880, },
|
||||
{ IMX93_CLK_GPIO2_GATE, "gpio2", "bus_wakeup_root", 0x88c0, },
|
||||
{ IMX93_CLK_GPIO3_GATE, "gpio3", "bus_wakeup_root", 0x8900, },
|
||||
{ IMX93_CLK_GPIO4_GATE, "gpio4", "bus_wakeup_root", 0x8940, },
|
||||
{ IMX93_CLK_FLEXIO1_GATE, "flexio1", "flexio1_root", 0x8980, },
|
||||
{ IMX93_CLK_FLEXIO2_GATE, "flexio2", "flexio2_root", 0x89c0, },
|
||||
{ IMX93_CLK_LPIT1_GATE, "lpit1", "lpit1_root", 0x8a00, },
|
||||
{ IMX93_CLK_LPIT2_GATE, "lpit2", "lpit2_root", 0x8a40, },
|
||||
{ IMX93_CLK_LPTMR1_GATE, "lptmr1", "lptmr1_root", 0x8a80, },
|
||||
{ IMX93_CLK_LPTMR2_GATE, "lptmr2", "lptmr2_root", 0x8ac0, },
|
||||
{ IMX93_CLK_TPM1_GATE, "tpm1", "tpm1_root", 0x8b00, },
|
||||
{ IMX93_CLK_TPM2_GATE, "tpm2", "tpm2_root", 0x8b40, },
|
||||
{ IMX93_CLK_TPM3_GATE, "tpm3", "tpm3_root", 0x8b80, },
|
||||
{ IMX93_CLK_TPM4_GATE, "tpm4", "tpm4_root", 0x8bc0, },
|
||||
{ IMX93_CLK_TPM5_GATE, "tpm5", "tpm5_root", 0x8c00, },
|
||||
{ IMX93_CLK_TPM6_GATE, "tpm6", "tpm6_root", 0x8c40, },
|
||||
{ IMX93_CLK_CAN1_GATE, "can1", "can1_root", 0x8c80, },
|
||||
{ IMX93_CLK_CAN2_GATE, "can2", "can2_root", 0x8cc0, },
|
||||
{ IMX93_CLK_LPUART1_GATE, "lpuart1", "lpuart1_root", 0x8d00, },
|
||||
{ IMX93_CLK_LPUART2_GATE, "lpuart2", "lpuart2_root", 0x8d40, },
|
||||
{ IMX93_CLK_LPUART3_GATE, "lpuart3", "lpuart3_root", 0x8d80, },
|
||||
{ IMX93_CLK_LPUART4_GATE, "lpuart4", "lpuart4_root", 0x8dc0, },
|
||||
{ IMX93_CLK_LPUART5_GATE, "lpuart5", "lpuart5_root", 0x8e00, },
|
||||
{ IMX93_CLK_LPUART6_GATE, "lpuart6", "lpuart6_root", 0x8e40, },
|
||||
{ IMX93_CLK_LPUART7_GATE, "lpuart7", "lpuart7_root", 0x8e80, },
|
||||
{ IMX93_CLK_LPUART8_GATE, "lpuart8", "lpuart8_root", 0x8ec0, },
|
||||
{ IMX93_CLK_LPI2C1_GATE, "lpi2c1", "lpi2c1_root", 0x8f00, },
|
||||
{ IMX93_CLK_LPI2C2_GATE, "lpi2c2", "lpi2c2_root", 0x8f40, },
|
||||
{ IMX93_CLK_LPI2C3_GATE, "lpi2c3", "lpi2c3_root", 0x8f80, },
|
||||
{ IMX93_CLK_LPI2C4_GATE, "lpi2c4", "lpi2c4_root", 0x8fc0, },
|
||||
{ IMX93_CLK_LPI2C5_GATE, "lpi2c5", "lpi2c5_root", 0x9000, },
|
||||
{ IMX93_CLK_LPI2C6_GATE, "lpi2c6", "lpi2c6_root", 0x9040, },
|
||||
{ IMX93_CLK_LPI2C7_GATE, "lpi2c7", "lpi2c7_root", 0x9080, },
|
||||
{ IMX93_CLK_LPI2C8_GATE, "lpi2c8", "lpi2c8_root", 0x90c0, },
|
||||
{ IMX93_CLK_LPSPI1_GATE, "lpspi1", "lpspi1_root", 0x9100, },
|
||||
{ IMX93_CLK_LPSPI2_GATE, "lpspi2", "lpspi2_root", 0x9140, },
|
||||
{ IMX93_CLK_LPSPI3_GATE, "lpspi3", "lpspi3_root", 0x9180, },
|
||||
{ IMX93_CLK_LPSPI4_GATE, "lpspi4", "lpspi4_root", 0x91c0, },
|
||||
{ IMX93_CLK_LPSPI5_GATE, "lpspi5", "lpspi5_root", 0x9200, },
|
||||
{ IMX93_CLK_LPSPI6_GATE, "lpspi6", "lpspi6_root", 0x9240, },
|
||||
{ IMX93_CLK_LPSPI7_GATE, "lpspi7", "lpspi7_root", 0x9280, },
|
||||
{ IMX93_CLK_LPSPI8_GATE, "lpspi8", "lpspi8_root", 0x92c0, },
|
||||
{ IMX93_CLK_I3C1_GATE, "i3c1", "i3c1_root", 0x9300, },
|
||||
{ IMX93_CLK_I3C2_GATE, "i3c2", "i3c2_root", 0x9340, },
|
||||
{ IMX93_CLK_USDHC1_GATE, "usdhc1", "usdhc1_root", 0x9380, },
|
||||
{ IMX93_CLK_USDHC2_GATE, "usdhc2", "usdhc2_root", 0x93c0, },
|
||||
{ IMX93_CLK_USDHC3_GATE, "usdhc3", "usdhc3_root", 0x9400, },
|
||||
{ IMX93_CLK_SAI1_GATE, "sai1", "sai1_root", 0x9440, },
|
||||
{ IMX93_CLK_SAI2_GATE, "sai2", "sai2_root", 0x9480, },
|
||||
{ IMX93_CLK_SAI3_GATE, "sai3", "sai3_root", 0x94c0, },
|
||||
{ IMX93_CLK_MIPI_CSI_GATE, "mipi_csi", "media_apb_root", 0x9580, },
|
||||
{ IMX93_CLK_MIPI_DSI_GATE, "mipi_dsi", "media_apb_root", 0x95c0, },
|
||||
{ IMX93_CLK_LVDS_GATE, "lvds", "media_ldb_root", 0x9600, },
|
||||
{ IMX93_CLK_LCDIF_GATE, "lcdif", "media_apb_root", 0x9640, },
|
||||
{ IMX93_CLK_PXP_GATE, "pxp", "media_apb_root", 0x9680, },
|
||||
{ IMX93_CLK_ISI_GATE, "isi", "media_apb_root", 0x96c0, },
|
||||
{ IMX93_CLK_NIC_MEDIA_GATE, "nic_media", "media_apb_root", 0x9700, },
|
||||
{ IMX93_CLK_USB_CONTROLLER_GATE, "usb_controller", "hsio_root", 0x9a00, },
|
||||
{ IMX93_CLK_USB_TEST_60M_GATE, "usb_test_60m", "hsio_usb_test_60m_root", 0x9a40, },
|
||||
{ IMX93_CLK_HSIO_TROUT_24M_GATE, "hsio_trout_24m", "osc_24m", 0x9a80, },
|
||||
{ IMX93_CLK_PDM_GATE, "pdm", "pdm_root", 0x9ac0, },
|
||||
{ IMX93_CLK_MQS1_GATE, "mqs1", "sai1_root", 0x9b00, },
|
||||
{ IMX93_CLK_MQS2_GATE, "mqs2", "sai3_root", 0x9b40, },
|
||||
{ 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", "enet_root", 0x9e00, },
|
||||
{ IMX93_CLK_ENET_QOS_GATE, "enet_qos", "wakeup_axi_root", 0x9e40, },
|
||||
{ IMX93_CLK_SYS_CNT_GATE, "sys_cnt", "osc_24m", 0x9e80, },
|
||||
{ IMX93_CLK_TSTMR1_GATE, "tstmr1", "bus_aon_root", 0x9ec0, },
|
||||
{ IMX93_CLK_TSTMR2_GATE, "tstmr2", "bus_wakeup_root", 0x9f00, },
|
||||
{ IMX93_CLK_TMC_GATE, "tmc", "osc_24m", 0x9f40, },
|
||||
{ IMX93_CLK_PMRO_GATE, "pmro", "osc_24m", 0x9f80, }
|
||||
};
|
||||
|
||||
static struct clk_hw_onecell_data *clk_hw_data;
|
||||
static struct clk_hw **clks;
|
||||
|
||||
static int imx93_clocks_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
const struct imx93_clk_root *root;
|
||||
const struct imx93_clk_ccgr *ccgr;
|
||||
void __iomem *base = NULL;
|
||||
int i, ret;
|
||||
|
||||
clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
|
||||
IMX93_CLK_END), GFP_KERNEL);
|
||||
if (!clk_hw_data)
|
||||
return -ENOMEM;
|
||||
|
||||
clk_hw_data->num = IMX93_CLK_END;
|
||||
clks = clk_hw_data->hws;
|
||||
|
||||
clks[IMX93_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
|
||||
clks[IMX93_CLK_24M] = imx_obtain_fixed_clk_hw(np, "osc_24m");
|
||||
clks[IMX93_CLK_32K] = imx_obtain_fixed_clk_hw(np, "osc_32k");
|
||||
clks[IMX93_CLK_EXT1] = imx_obtain_fixed_clk_hw(np, "clk_ext1");
|
||||
|
||||
clks[IMX93_CLK_SYS_PLL_PFD0] = imx_clk_hw_fixed("sys_pll_pfd0", 1000000000);
|
||||
clks[IMX93_CLK_SYS_PLL_PFD0_DIV2] = imx_clk_hw_fixed_factor("sys_pll_pfd0_div2",
|
||||
"sys_pll_pfd0", 1, 2);
|
||||
clks[IMX93_CLK_SYS_PLL_PFD1] = imx_clk_hw_fixed("sys_pll_pfd1", 800000000);
|
||||
clks[IMX93_CLK_SYS_PLL_PFD1_DIV2] = imx_clk_hw_fixed_factor("sys_pll_pfd1_div2",
|
||||
"sys_pll_pfd1", 1, 2);
|
||||
clks[IMX93_CLK_SYS_PLL_PFD2] = imx_clk_hw_fixed("sys_pll_pfd2", 625000000);
|
||||
clks[IMX93_CLK_SYS_PLL_PFD2_DIV2] = imx_clk_hw_fixed_factor("sys_pll_pfd2_div2",
|
||||
"sys_pll_pfd2", 1, 2);
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "fsl,imx93-anatop");
|
||||
base = of_iomap(np, 0);
|
||||
of_node_put(np);
|
||||
if (WARN_ON(!base))
|
||||
return -ENOMEM;
|
||||
|
||||
clks[IMX93_CLK_AUDIO_PLL] = imx_clk_fracn_gppll("audio_pll", "osc_24m", base + 0x1200,
|
||||
&imx_fracn_gppll);
|
||||
clks[IMX93_CLK_VIDEO_PLL] = imx_clk_fracn_gppll("video_pll", "osc_24m", base + 0x1400,
|
||||
&imx_fracn_gppll);
|
||||
|
||||
np = dev->of_node;
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (WARN_ON(IS_ERR(base)))
|
||||
return PTR_ERR(base);
|
||||
|
||||
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,
|
||||
root->flags);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ccgr_array); i++) {
|
||||
ccgr = &ccgr_array[i];
|
||||
clks[ccgr->clk] = imx_clk_hw_gate4_flags(ccgr->name,
|
||||
ccgr->parent_name,
|
||||
base + ccgr->off, 0,
|
||||
ccgr->flags);
|
||||
}
|
||||
|
||||
imx_check_clk_hws(clks, IMX93_CLK_END);
|
||||
|
||||
ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to register clks for i.MX93\n");
|
||||
goto unregister_hws;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
unregister_hws:
|
||||
imx_unregister_hw_clocks(clks, IMX93_CLK_END);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id imx93_clk_of_match[] = {
|
||||
{ .compatible = "fsl,imx93-ccm" },
|
||||
{ /* Sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imx93_clk_of_match);
|
||||
|
||||
static struct platform_driver imx93_clk_driver = {
|
||||
.probe = imx93_clocks_probe,
|
||||
.driver = {
|
||||
.name = "imx93-ccm",
|
||||
.suppress_bind_attrs = true,
|
||||
.of_match_table = of_match_ptr(imx93_clk_of_match),
|
||||
},
|
||||
};
|
||||
module_platform_driver(imx93_clk_driver);
|
||||
|
||||
MODULE_DESCRIPTION("NXP i.MX93 clock driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
168
drivers/clk/imx/clk-imxrt1050.c
Normal file
168
drivers/clk/imx/clk-imxrt1050.c
Normal file
@@ -0,0 +1,168 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
|
||||
/*
|
||||
* Copyright (C) 2021
|
||||
* Author(s):
|
||||
* Jesse Taube <Mr.Bossman075@gmail.com>
|
||||
* Giulio Benetti <giulio.benetti@benettiengineering.com>
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <dt-bindings/clock/imxrt1050-clock.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
static const char * const pll_ref_sels[] = {"osc", "dummy", };
|
||||
static const char * const per_sels[] = {"ipg_pdof", "osc", };
|
||||
static const char * const pll1_bypass_sels[] = {"pll1_arm", "pll1_arm_ref_sel", };
|
||||
static const char * const pll2_bypass_sels[] = {"pll2_sys", "pll2_sys_ref_sel", };
|
||||
static const char * const pll3_bypass_sels[] = {"pll3_usb_otg", "pll3_usb_otg_ref_sel", };
|
||||
static const char * const pll5_bypass_sels[] = {"pll5_video", "pll5_video_ref_sel", };
|
||||
static const char *const pre_periph_sels[] = {
|
||||
"pll2_sys", "pll2_pfd2_396m", "pll2_pfd0_352m", "arm_podf", };
|
||||
static const char *const periph_sels[] = { "pre_periph_sel", "todo", };
|
||||
static const char *const usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
|
||||
static const char *const lpuart_sels[] = { "pll3_80m", "osc", };
|
||||
static const char *const lcdif_sels[] = {
|
||||
"pll2_sys", "pll3_pfd3_454_74m", "pll5_video", "pll2_pfd0_352m",
|
||||
"pll2_pfd1_594m", "pll3_pfd1_664_62m", };
|
||||
static const char *const semc_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_664_62m", };
|
||||
static const char *const semc_sels[] = { "periph_sel", "semc_alt_sel", };
|
||||
|
||||
static struct clk_hw **hws;
|
||||
static struct clk_hw_onecell_data *clk_hw_data;
|
||||
|
||||
static int imxrt1050_clocks_probe(struct platform_device *pdev)
|
||||
{
|
||||
void __iomem *ccm_base;
|
||||
void __iomem *pll_base;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct device_node *anp;
|
||||
int ret;
|
||||
|
||||
clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
|
||||
IMXRT1050_CLK_END), GFP_KERNEL);
|
||||
if (WARN_ON(!clk_hw_data))
|
||||
return -ENOMEM;
|
||||
|
||||
clk_hw_data->num = IMXRT1050_CLK_END;
|
||||
hws = clk_hw_data->hws;
|
||||
|
||||
hws[IMXRT1050_CLK_OSC] = imx_obtain_fixed_clk_hw(np, "osc");
|
||||
|
||||
anp = of_find_compatible_node(NULL, NULL, "fsl,imxrt-anatop");
|
||||
pll_base = of_iomap(anp, 0);
|
||||
of_node_put(anp);
|
||||
if (WARN_ON(!pll_base))
|
||||
return -ENOMEM;
|
||||
|
||||
/* Anatop clocks */
|
||||
hws[IMXRT1050_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0UL);
|
||||
|
||||
hws[IMXRT1050_CLK_PLL1_REF_SEL] = imx_clk_hw_mux("pll1_arm_ref_sel",
|
||||
pll_base + 0x0, 14, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
|
||||
hws[IMXRT1050_CLK_PLL2_REF_SEL] = imx_clk_hw_mux("pll2_sys_ref_sel",
|
||||
pll_base + 0x30, 14, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
|
||||
hws[IMXRT1050_CLK_PLL3_REF_SEL] = imx_clk_hw_mux("pll3_usb_otg_ref_sel",
|
||||
pll_base + 0x10, 14, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
|
||||
hws[IMXRT1050_CLK_PLL5_REF_SEL] = imx_clk_hw_mux("pll5_video_ref_sel",
|
||||
pll_base + 0xa0, 14, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
|
||||
|
||||
hws[IMXRT1050_CLK_PLL1_ARM] = imx_clk_hw_pllv3(IMX_PLLV3_SYS, "pll1_arm",
|
||||
"pll1_arm_ref_sel", pll_base + 0x0, 0x7f);
|
||||
hws[IMXRT1050_CLK_PLL2_SYS] = imx_clk_hw_pllv3(IMX_PLLV3_GENERIC, "pll2_sys",
|
||||
"pll2_sys_ref_sel", pll_base + 0x30, 0x1);
|
||||
hws[IMXRT1050_CLK_PLL3_USB_OTG] = imx_clk_hw_pllv3(IMX_PLLV3_USB, "pll3_usb_otg",
|
||||
"pll3_usb_otg_ref_sel", pll_base + 0x10, 0x1);
|
||||
hws[IMXRT1050_CLK_PLL5_VIDEO] = imx_clk_hw_pllv3(IMX_PLLV3_AV, "pll5_video",
|
||||
"pll5_video_ref_sel", pll_base + 0xa0, 0x7f);
|
||||
|
||||
/* PLL bypass out */
|
||||
hws[IMXRT1050_CLK_PLL1_BYPASS] = imx_clk_hw_mux_flags("pll1_bypass", pll_base + 0x0, 16, 1,
|
||||
pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
hws[IMXRT1050_CLK_PLL2_BYPASS] = imx_clk_hw_mux_flags("pll2_bypass", pll_base + 0x30, 16, 1,
|
||||
pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
hws[IMXRT1050_CLK_PLL3_BYPASS] = imx_clk_hw_mux_flags("pll3_bypass", pll_base + 0x10, 16, 1,
|
||||
pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
hws[IMXRT1050_CLK_PLL5_BYPASS] = imx_clk_hw_mux_flags("pll5_bypass", pll_base + 0xa0, 16, 1,
|
||||
pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
|
||||
hws[IMXRT1050_CLK_VIDEO_POST_DIV_SEL] = imx_clk_hw_divider("video_post_div_sel",
|
||||
"pll5_video", pll_base + 0xa0, 19, 2);
|
||||
hws[IMXRT1050_CLK_VIDEO_DIV] = imx_clk_hw_divider("video_div",
|
||||
"video_post_div_sel", pll_base + 0x170, 30, 2);
|
||||
|
||||
hws[IMXRT1050_CLK_PLL3_80M] = imx_clk_hw_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6);
|
||||
|
||||
hws[IMXRT1050_CLK_PLL2_PFD0_352M] = imx_clk_hw_pfd("pll2_pfd0_352m", "pll2_sys", pll_base + 0x100, 0);
|
||||
hws[IMXRT1050_CLK_PLL2_PFD1_594M] = imx_clk_hw_pfd("pll2_pfd1_594m", "pll2_sys", pll_base + 0x100, 1);
|
||||
hws[IMXRT1050_CLK_PLL2_PFD2_396M] = imx_clk_hw_pfd("pll2_pfd2_396m", "pll2_sys", pll_base + 0x100, 2);
|
||||
hws[IMXRT1050_CLK_PLL3_PFD1_664_62M] = imx_clk_hw_pfd("pll3_pfd1_664_62m", "pll3_usb_otg", pll_base + 0xf0, 1);
|
||||
hws[IMXRT1050_CLK_PLL3_PFD3_454_74M] = imx_clk_hw_pfd("pll3_pfd3_454_74m", "pll3_usb_otg", pll_base + 0xf0, 3);
|
||||
|
||||
/* CCM clocks */
|
||||
ccm_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (WARN_ON(IS_ERR(ccm_base)))
|
||||
return PTR_ERR(ccm_base);
|
||||
|
||||
hws[IMXRT1050_CLK_ARM_PODF] = imx_clk_hw_divider("arm_podf", "pll1_arm", ccm_base + 0x10, 0, 3);
|
||||
hws[IMXRT1050_CLK_PRE_PERIPH_SEL] = imx_clk_hw_mux("pre_periph_sel", ccm_base + 0x18, 18, 2,
|
||||
pre_periph_sels, ARRAY_SIZE(pre_periph_sels));
|
||||
hws[IMXRT1050_CLK_PERIPH_SEL] = imx_clk_hw_mux("periph_sel", ccm_base + 0x14, 25, 1,
|
||||
periph_sels, ARRAY_SIZE(periph_sels));
|
||||
hws[IMXRT1050_CLK_USDHC1_SEL] = imx_clk_hw_mux("usdhc1_sel", ccm_base + 0x1c, 16, 1,
|
||||
usdhc_sels, ARRAY_SIZE(usdhc_sels));
|
||||
hws[IMXRT1050_CLK_USDHC2_SEL] = imx_clk_hw_mux("usdhc2_sel", ccm_base + 0x1c, 17, 1,
|
||||
usdhc_sels, ARRAY_SIZE(usdhc_sels));
|
||||
hws[IMXRT1050_CLK_LPUART_SEL] = imx_clk_hw_mux("lpuart_sel", ccm_base + 0x24, 6, 1,
|
||||
lpuart_sels, ARRAY_SIZE(lpuart_sels));
|
||||
hws[IMXRT1050_CLK_LCDIF_SEL] = imx_clk_hw_mux("lcdif_sel", ccm_base + 0x38, 15, 3,
|
||||
lcdif_sels, ARRAY_SIZE(lcdif_sels));
|
||||
hws[IMXRT1050_CLK_PER_CLK_SEL] = imx_clk_hw_mux("per_sel", ccm_base + 0x1C, 6, 1,
|
||||
per_sels, ARRAY_SIZE(per_sels));
|
||||
hws[IMXRT1050_CLK_SEMC_ALT_SEL] = imx_clk_hw_mux("semc_alt_sel", ccm_base + 0x14, 7, 1,
|
||||
semc_alt_sels, ARRAY_SIZE(semc_alt_sels));
|
||||
hws[IMXRT1050_CLK_SEMC_SEL] = imx_clk_hw_mux_flags("semc_sel", ccm_base + 0x14, 6, 1,
|
||||
semc_sels, ARRAY_SIZE(semc_sels), CLK_IS_CRITICAL);
|
||||
|
||||
hws[IMXRT1050_CLK_AHB_PODF] = imx_clk_hw_divider("ahb", "periph_sel", ccm_base + 0x14, 10, 3);
|
||||
hws[IMXRT1050_CLK_IPG_PDOF] = imx_clk_hw_divider("ipg", "ahb", ccm_base + 0x14, 8, 2);
|
||||
hws[IMXRT1050_CLK_PER_PDOF] = imx_clk_hw_divider("per", "per_sel", ccm_base + 0x1C, 0, 5);
|
||||
|
||||
hws[IMXRT1050_CLK_USDHC1_PODF] = imx_clk_hw_divider("usdhc1_podf", "usdhc1_sel", ccm_base + 0x24, 11, 3);
|
||||
hws[IMXRT1050_CLK_USDHC2_PODF] = imx_clk_hw_divider("usdhc2_podf", "usdhc2_sel", ccm_base + 0x24, 16, 3);
|
||||
hws[IMXRT1050_CLK_LPUART_PODF] = imx_clk_hw_divider("lpuart_podf", "lpuart_sel", ccm_base + 0x24, 0, 6);
|
||||
hws[IMXRT1050_CLK_LCDIF_PRED] = imx_clk_hw_divider("lcdif_pred", "lcdif_sel", ccm_base + 0x38, 12, 3);
|
||||
hws[IMXRT1050_CLK_LCDIF_PODF] = imx_clk_hw_divider("lcdif_podf", "lcdif_pred", ccm_base + 0x18, 23, 3);
|
||||
|
||||
hws[IMXRT1050_CLK_USDHC1] = imx_clk_hw_gate2("usdhc1", "usdhc1_podf", ccm_base + 0x80, 2);
|
||||
hws[IMXRT1050_CLK_USDHC2] = imx_clk_hw_gate2("usdhc2", "usdhc2_podf", ccm_base + 0x80, 4);
|
||||
hws[IMXRT1050_CLK_LPUART1] = imx_clk_hw_gate2("lpuart1", "lpuart_podf", ccm_base + 0x7c, 24);
|
||||
hws[IMXRT1050_CLK_LCDIF_APB] = imx_clk_hw_gate2("lcdif", "lcdif_podf", ccm_base + 0x74, 10);
|
||||
hws[IMXRT1050_CLK_DMA] = imx_clk_hw_gate("dma", "ipg", ccm_base + 0x7C, 6);
|
||||
hws[IMXRT1050_CLK_DMA_MUX] = imx_clk_hw_gate("dmamux0", "ipg", ccm_base + 0x7C, 7);
|
||||
imx_check_clk_hws(hws, IMXRT1050_CLK_END);
|
||||
|
||||
ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to register clks for i.MXRT1050.\n");
|
||||
imx_unregister_hw_clocks(hws, IMXRT1050_CLK_END);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static const struct of_device_id imxrt1050_clk_of_match[] = {
|
||||
{ .compatible = "fsl,imxrt1050-ccm" },
|
||||
{ /* Sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imxrt1050_clk_of_match);
|
||||
|
||||
static struct platform_driver imxrt1050_clk_driver = {
|
||||
.probe = imxrt1050_clocks_probe,
|
||||
.driver = {
|
||||
.name = "imxrt1050-ccm",
|
||||
.of_match_table = imxrt1050_clk_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(imxrt1050_clk_driver);
|
||||
@@ -3,6 +3,9 @@
|
||||
* Copyright 2017-2018 NXP.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "pll14xx: " fmt
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
@@ -15,20 +18,19 @@
|
||||
#include "clk.h"
|
||||
|
||||
#define GNRL_CTL 0x0
|
||||
#define DIV_CTL 0x4
|
||||
#define DIV_CTL0 0x4
|
||||
#define DIV_CTL1 0x8
|
||||
#define LOCK_STATUS BIT(31)
|
||||
#define LOCK_SEL_MASK BIT(29)
|
||||
#define CLKE_MASK BIT(11)
|
||||
#define RST_MASK BIT(9)
|
||||
#define BYPASS_MASK BIT(4)
|
||||
#define MDIV_SHIFT 12
|
||||
#define MDIV_MASK GENMASK(21, 12)
|
||||
#define PDIV_SHIFT 4
|
||||
#define PDIV_MASK GENMASK(9, 4)
|
||||
#define SDIV_SHIFT 0
|
||||
#define SDIV_MASK GENMASK(2, 0)
|
||||
#define KDIV_SHIFT 0
|
||||
#define KDIV_MASK GENMASK(15, 0)
|
||||
#define KDIV_MIN SHRT_MIN
|
||||
#define KDIV_MAX SHRT_MAX
|
||||
|
||||
#define LOCK_TIMEOUT_US 10000
|
||||
|
||||
@@ -99,54 +101,10 @@ static const struct imx_pll14xx_rate_table *imx_get_pll_settings(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static long clk_pll14xx_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static long pll14xx_calc_rate(struct clk_pll14xx *pll, int mdiv, int pdiv,
|
||||
int sdiv, int kdiv, unsigned long prate)
|
||||
{
|
||||
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
|
||||
const struct imx_pll14xx_rate_table *rate_table = pll->rate_table;
|
||||
int i;
|
||||
|
||||
/* Assumming rate_table is in descending order */
|
||||
for (i = 0; i < pll->rate_count; i++)
|
||||
if (rate >= rate_table[i].rate)
|
||||
return rate_table[i].rate;
|
||||
|
||||
/* return minimum supported value */
|
||||
return rate_table[i - 1].rate;
|
||||
}
|
||||
|
||||
static unsigned long clk_pll1416x_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
|
||||
u32 mdiv, pdiv, sdiv, pll_div;
|
||||
u64 fvco = parent_rate;
|
||||
|
||||
pll_div = readl_relaxed(pll->base + 4);
|
||||
mdiv = (pll_div & MDIV_MASK) >> MDIV_SHIFT;
|
||||
pdiv = (pll_div & PDIV_MASK) >> PDIV_SHIFT;
|
||||
sdiv = (pll_div & SDIV_MASK) >> SDIV_SHIFT;
|
||||
|
||||
fvco *= mdiv;
|
||||
do_div(fvco, pdiv << sdiv);
|
||||
|
||||
return fvco;
|
||||
}
|
||||
|
||||
static unsigned long clk_pll1443x_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
|
||||
u32 mdiv, pdiv, sdiv, pll_div_ctl0, pll_div_ctl1;
|
||||
short int kdiv;
|
||||
u64 fvco = parent_rate;
|
||||
|
||||
pll_div_ctl0 = readl_relaxed(pll->base + 4);
|
||||
pll_div_ctl1 = readl_relaxed(pll->base + 8);
|
||||
mdiv = (pll_div_ctl0 & MDIV_MASK) >> MDIV_SHIFT;
|
||||
pdiv = (pll_div_ctl0 & PDIV_MASK) >> PDIV_SHIFT;
|
||||
sdiv = (pll_div_ctl0 & SDIV_MASK) >> SDIV_SHIFT;
|
||||
kdiv = pll_div_ctl1 & KDIV_MASK;
|
||||
u64 fvco = prate;
|
||||
|
||||
/* fvco = (m * 65536 + k) * Fin / (p * 65536) */
|
||||
fvco *= (mdiv * 65536 + kdiv);
|
||||
@@ -157,13 +115,160 @@ static unsigned long clk_pll1443x_recalc_rate(struct clk_hw *hw,
|
||||
return fvco;
|
||||
}
|
||||
|
||||
static long pll1443x_calc_kdiv(int mdiv, int pdiv, int sdiv,
|
||||
unsigned long rate, unsigned long prate)
|
||||
{
|
||||
long kdiv;
|
||||
|
||||
/* calc kdiv = round(rate * pdiv * 65536 * 2^sdiv / prate) - (mdiv * 65536) */
|
||||
kdiv = ((rate * ((pdiv * 65536) << sdiv) + prate / 2) / prate) - (mdiv * 65536);
|
||||
|
||||
return clamp_t(short, kdiv, KDIV_MIN, KDIV_MAX);
|
||||
}
|
||||
|
||||
static void imx_pll14xx_calc_settings(struct clk_pll14xx *pll, unsigned long rate,
|
||||
unsigned long prate, struct imx_pll14xx_rate_table *t)
|
||||
{
|
||||
u32 pll_div_ctl0, pll_div_ctl1;
|
||||
int mdiv, pdiv, sdiv, kdiv;
|
||||
long fvco, rate_min, rate_max, dist, best = LONG_MAX;
|
||||
const struct imx_pll14xx_rate_table *tt;
|
||||
|
||||
/*
|
||||
* Fractional PLL constrains:
|
||||
*
|
||||
* a) 6MHz <= prate <= 25MHz
|
||||
* b) 1 <= p <= 63 (1 <= p <= 4 prate = 24MHz)
|
||||
* c) 64 <= m <= 1023
|
||||
* d) 0 <= s <= 6
|
||||
* e) -32768 <= k <= 32767
|
||||
*
|
||||
* fvco = (m * 65536 + k) * prate / (p * 65536)
|
||||
*/
|
||||
|
||||
/* First try if we can get the desired rate from one of the static entries */
|
||||
tt = imx_get_pll_settings(pll, rate);
|
||||
if (tt) {
|
||||
pr_debug("%s: in=%ld, want=%ld, Using PLL setting from table\n",
|
||||
clk_hw_get_name(&pll->hw), prate, rate);
|
||||
t->rate = tt->rate;
|
||||
t->mdiv = tt->mdiv;
|
||||
t->pdiv = tt->pdiv;
|
||||
t->sdiv = tt->sdiv;
|
||||
t->kdiv = tt->kdiv;
|
||||
return;
|
||||
}
|
||||
|
||||
pll_div_ctl0 = readl_relaxed(pll->base + DIV_CTL0);
|
||||
mdiv = FIELD_GET(MDIV_MASK, pll_div_ctl0);
|
||||
pdiv = FIELD_GET(PDIV_MASK, pll_div_ctl0);
|
||||
sdiv = FIELD_GET(SDIV_MASK, pll_div_ctl0);
|
||||
pll_div_ctl1 = readl_relaxed(pll->base + DIV_CTL1);
|
||||
|
||||
/* Then see if we can get the desired rate by only adjusting kdiv (glitch free) */
|
||||
rate_min = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, KDIV_MIN, prate);
|
||||
rate_max = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, KDIV_MAX, prate);
|
||||
|
||||
if (rate >= rate_min && rate <= rate_max) {
|
||||
kdiv = pll1443x_calc_kdiv(mdiv, pdiv, sdiv, rate, prate);
|
||||
pr_debug("%s: in=%ld, want=%ld Only adjust kdiv %ld -> %d\n",
|
||||
clk_hw_get_name(&pll->hw), prate, rate,
|
||||
FIELD_GET(KDIV_MASK, pll_div_ctl1), kdiv);
|
||||
fvco = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, prate);
|
||||
t->rate = (unsigned int)fvco;
|
||||
t->mdiv = mdiv;
|
||||
t->pdiv = pdiv;
|
||||
t->sdiv = sdiv;
|
||||
t->kdiv = kdiv;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Finally calculate best values */
|
||||
for (pdiv = 1; pdiv <= 7; pdiv++) {
|
||||
for (sdiv = 0; sdiv <= 6; sdiv++) {
|
||||
/* calc mdiv = round(rate * pdiv * 2^sdiv) / prate) */
|
||||
mdiv = DIV_ROUND_CLOSEST(rate * (pdiv << sdiv), prate);
|
||||
mdiv = clamp(mdiv, 64, 1023);
|
||||
|
||||
kdiv = pll1443x_calc_kdiv(mdiv, pdiv, sdiv, rate, prate);
|
||||
fvco = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, prate);
|
||||
|
||||
/* best match */
|
||||
dist = abs((long)rate - (long)fvco);
|
||||
if (dist < best) {
|
||||
best = dist;
|
||||
t->rate = (unsigned int)fvco;
|
||||
t->mdiv = mdiv;
|
||||
t->pdiv = pdiv;
|
||||
t->sdiv = sdiv;
|
||||
t->kdiv = kdiv;
|
||||
|
||||
if (!dist)
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
}
|
||||
found:
|
||||
pr_debug("%s: in=%ld, want=%ld got=%d (pdiv=%d sdiv=%d mdiv=%d kdiv=%d)\n",
|
||||
clk_hw_get_name(&pll->hw), prate, rate, t->rate, t->pdiv, t->sdiv,
|
||||
t->mdiv, t->kdiv);
|
||||
}
|
||||
|
||||
static long clk_pll1416x_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
|
||||
const struct imx_pll14xx_rate_table *rate_table = pll->rate_table;
|
||||
int i;
|
||||
|
||||
/* Assuming rate_table is in descending order */
|
||||
for (i = 0; i < pll->rate_count; i++)
|
||||
if (rate >= rate_table[i].rate)
|
||||
return rate_table[i].rate;
|
||||
|
||||
/* return minimum supported value */
|
||||
return rate_table[pll->rate_count - 1].rate;
|
||||
}
|
||||
|
||||
static long clk_pll1443x_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
|
||||
struct imx_pll14xx_rate_table t;
|
||||
|
||||
imx_pll14xx_calc_settings(pll, rate, *prate, &t);
|
||||
|
||||
return t.rate;
|
||||
}
|
||||
|
||||
static unsigned long clk_pll14xx_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
|
||||
u32 mdiv, pdiv, sdiv, kdiv, pll_div_ctl0, pll_div_ctl1;
|
||||
|
||||
pll_div_ctl0 = readl_relaxed(pll->base + DIV_CTL0);
|
||||
mdiv = FIELD_GET(MDIV_MASK, pll_div_ctl0);
|
||||
pdiv = FIELD_GET(PDIV_MASK, pll_div_ctl0);
|
||||
sdiv = FIELD_GET(SDIV_MASK, pll_div_ctl0);
|
||||
|
||||
if (pll->type == PLL_1443X) {
|
||||
pll_div_ctl1 = readl_relaxed(pll->base + DIV_CTL1);
|
||||
kdiv = FIELD_GET(KDIV_MASK, pll_div_ctl1);
|
||||
} else {
|
||||
kdiv = 0;
|
||||
}
|
||||
|
||||
return pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, parent_rate);
|
||||
}
|
||||
|
||||
static inline bool clk_pll14xx_mp_change(const struct imx_pll14xx_rate_table *rate,
|
||||
u32 pll_div)
|
||||
{
|
||||
u32 old_mdiv, old_pdiv;
|
||||
|
||||
old_mdiv = (pll_div & MDIV_MASK) >> MDIV_SHIFT;
|
||||
old_pdiv = (pll_div & PDIV_MASK) >> PDIV_SHIFT;
|
||||
old_mdiv = FIELD_GET(MDIV_MASK, pll_div);
|
||||
old_pdiv = FIELD_GET(PDIV_MASK, pll_div);
|
||||
|
||||
return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv;
|
||||
}
|
||||
@@ -172,7 +277,7 @@ static int clk_pll14xx_wait_lock(struct clk_pll14xx *pll)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
return readl_poll_timeout(pll->base, val, val & LOCK_STATUS, 0,
|
||||
return readl_poll_timeout(pll->base + GNRL_CTL, val, val & LOCK_STATUS, 0,
|
||||
LOCK_TIMEOUT_US);
|
||||
}
|
||||
|
||||
@@ -186,37 +291,37 @@ static int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate,
|
||||
|
||||
rate = imx_get_pll_settings(pll, drate);
|
||||
if (!rate) {
|
||||
pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
|
||||
drate, clk_hw_get_name(hw));
|
||||
pr_err("Invalid rate %lu for pll clk %s\n", drate,
|
||||
clk_hw_get_name(hw));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tmp = readl_relaxed(pll->base + 4);
|
||||
tmp = readl_relaxed(pll->base + DIV_CTL0);
|
||||
|
||||
if (!clk_pll14xx_mp_change(rate, tmp)) {
|
||||
tmp &= ~(SDIV_MASK) << SDIV_SHIFT;
|
||||
tmp |= rate->sdiv << SDIV_SHIFT;
|
||||
writel_relaxed(tmp, pll->base + 4);
|
||||
tmp &= ~SDIV_MASK;
|
||||
tmp |= FIELD_PREP(SDIV_MASK, rate->sdiv);
|
||||
writel_relaxed(tmp, pll->base + DIV_CTL0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Bypass clock and set lock to pll output lock */
|
||||
tmp = readl_relaxed(pll->base);
|
||||
tmp = readl_relaxed(pll->base + GNRL_CTL);
|
||||
tmp |= LOCK_SEL_MASK;
|
||||
writel_relaxed(tmp, pll->base);
|
||||
writel_relaxed(tmp, pll->base + GNRL_CTL);
|
||||
|
||||
/* Enable RST */
|
||||
tmp &= ~RST_MASK;
|
||||
writel_relaxed(tmp, pll->base);
|
||||
writel_relaxed(tmp, pll->base + GNRL_CTL);
|
||||
|
||||
/* Enable BYPASS */
|
||||
tmp |= BYPASS_MASK;
|
||||
writel(tmp, pll->base);
|
||||
writel(tmp, pll->base + GNRL_CTL);
|
||||
|
||||
div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
|
||||
(rate->sdiv << SDIV_SHIFT);
|
||||
writel_relaxed(div_val, pll->base + 0x4);
|
||||
div_val = FIELD_PREP(MDIV_MASK, rate->mdiv) | FIELD_PREP(PDIV_MASK, rate->pdiv) |
|
||||
FIELD_PREP(SDIV_MASK, rate->sdiv);
|
||||
writel_relaxed(div_val, pll->base + DIV_CTL0);
|
||||
|
||||
/*
|
||||
* According to SPEC, t3 - t2 need to be greater than
|
||||
@@ -228,7 +333,7 @@ static int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate,
|
||||
|
||||
/* Disable RST */
|
||||
tmp |= RST_MASK;
|
||||
writel_relaxed(tmp, pll->base);
|
||||
writel_relaxed(tmp, pll->base + GNRL_CTL);
|
||||
|
||||
/* Wait Lock */
|
||||
ret = clk_pll14xx_wait_lock(pll);
|
||||
@@ -237,7 +342,7 @@ static int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate,
|
||||
|
||||
/* Bypass */
|
||||
tmp &= ~BYPASS_MASK;
|
||||
writel_relaxed(tmp, pll->base);
|
||||
writel_relaxed(tmp, pll->base + GNRL_CTL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -246,43 +351,41 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
|
||||
unsigned long prate)
|
||||
{
|
||||
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
|
||||
const struct imx_pll14xx_rate_table *rate;
|
||||
u32 tmp, div_val;
|
||||
struct imx_pll14xx_rate_table rate;
|
||||
u32 gnrl_ctl, div_ctl0;
|
||||
int ret;
|
||||
|
||||
rate = imx_get_pll_settings(pll, drate);
|
||||
if (!rate) {
|
||||
pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
|
||||
drate, clk_hw_get_name(hw));
|
||||
return -EINVAL;
|
||||
}
|
||||
imx_pll14xx_calc_settings(pll, drate, prate, &rate);
|
||||
|
||||
tmp = readl_relaxed(pll->base + 4);
|
||||
div_ctl0 = readl_relaxed(pll->base + DIV_CTL0);
|
||||
|
||||
if (!clk_pll14xx_mp_change(rate, tmp)) {
|
||||
tmp &= ~(SDIV_MASK) << SDIV_SHIFT;
|
||||
tmp |= rate->sdiv << SDIV_SHIFT;
|
||||
writel_relaxed(tmp, pll->base + 4);
|
||||
if (!clk_pll14xx_mp_change(&rate, div_ctl0)) {
|
||||
/* only sdiv and/or kdiv changed - no need to RESET PLL */
|
||||
div_ctl0 &= ~SDIV_MASK;
|
||||
div_ctl0 |= FIELD_PREP(SDIV_MASK, rate.sdiv);
|
||||
writel_relaxed(div_ctl0, pll->base + DIV_CTL0);
|
||||
|
||||
tmp = rate->kdiv << KDIV_SHIFT;
|
||||
writel_relaxed(tmp, pll->base + 8);
|
||||
writel_relaxed(FIELD_PREP(KDIV_MASK, rate.kdiv),
|
||||
pll->base + DIV_CTL1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Enable RST */
|
||||
tmp = readl_relaxed(pll->base);
|
||||
tmp &= ~RST_MASK;
|
||||
writel_relaxed(tmp, pll->base);
|
||||
gnrl_ctl = readl_relaxed(pll->base + GNRL_CTL);
|
||||
gnrl_ctl &= ~RST_MASK;
|
||||
writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL);
|
||||
|
||||
/* Enable BYPASS */
|
||||
tmp |= BYPASS_MASK;
|
||||
writel_relaxed(tmp, pll->base);
|
||||
gnrl_ctl |= BYPASS_MASK;
|
||||
writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL);
|
||||
|
||||
div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
|
||||
(rate->sdiv << SDIV_SHIFT);
|
||||
writel_relaxed(div_val, pll->base + 0x4);
|
||||
writel_relaxed(rate->kdiv << KDIV_SHIFT, pll->base + 0x8);
|
||||
div_ctl0 = FIELD_PREP(MDIV_MASK, rate.mdiv) |
|
||||
FIELD_PREP(PDIV_MASK, rate.pdiv) |
|
||||
FIELD_PREP(SDIV_MASK, rate.sdiv);
|
||||
writel_relaxed(div_ctl0, pll->base + DIV_CTL0);
|
||||
|
||||
writel_relaxed(FIELD_PREP(KDIV_MASK, rate.kdiv), pll->base + DIV_CTL1);
|
||||
|
||||
/*
|
||||
* According to SPEC, t3 - t2 need to be greater than
|
||||
@@ -293,8 +396,8 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
|
||||
udelay(3);
|
||||
|
||||
/* Disable RST */
|
||||
tmp |= RST_MASK;
|
||||
writel_relaxed(tmp, pll->base);
|
||||
gnrl_ctl |= RST_MASK;
|
||||
writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL);
|
||||
|
||||
/* Wait Lock*/
|
||||
ret = clk_pll14xx_wait_lock(pll);
|
||||
@@ -302,8 +405,8 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
|
||||
return ret;
|
||||
|
||||
/* Bypass */
|
||||
tmp &= ~BYPASS_MASK;
|
||||
writel_relaxed(tmp, pll->base);
|
||||
gnrl_ctl &= ~BYPASS_MASK;
|
||||
writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -364,21 +467,21 @@ static const struct clk_ops clk_pll1416x_ops = {
|
||||
.prepare = clk_pll14xx_prepare,
|
||||
.unprepare = clk_pll14xx_unprepare,
|
||||
.is_prepared = clk_pll14xx_is_prepared,
|
||||
.recalc_rate = clk_pll1416x_recalc_rate,
|
||||
.round_rate = clk_pll14xx_round_rate,
|
||||
.recalc_rate = clk_pll14xx_recalc_rate,
|
||||
.round_rate = clk_pll1416x_round_rate,
|
||||
.set_rate = clk_pll1416x_set_rate,
|
||||
};
|
||||
|
||||
static const struct clk_ops clk_pll1416x_min_ops = {
|
||||
.recalc_rate = clk_pll1416x_recalc_rate,
|
||||
.recalc_rate = clk_pll14xx_recalc_rate,
|
||||
};
|
||||
|
||||
static const struct clk_ops clk_pll1443x_ops = {
|
||||
.prepare = clk_pll14xx_prepare,
|
||||
.unprepare = clk_pll14xx_unprepare,
|
||||
.is_prepared = clk_pll14xx_is_prepared,
|
||||
.recalc_rate = clk_pll1443x_recalc_rate,
|
||||
.round_rate = clk_pll14xx_round_rate,
|
||||
.recalc_rate = clk_pll14xx_recalc_rate,
|
||||
.round_rate = clk_pll1443x_round_rate,
|
||||
.set_rate = clk_pll1443x_set_rate,
|
||||
};
|
||||
|
||||
@@ -412,8 +515,7 @@ struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
|
||||
init.ops = &clk_pll1443x_ops;
|
||||
break;
|
||||
default:
|
||||
pr_err("%s: Unknown pll type for pll clk %s\n",
|
||||
__func__, name);
|
||||
pr_err("Unknown pll type for pll clk %s\n", name);
|
||||
kfree(pll);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
@@ -432,8 +534,7 @@ struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
|
||||
|
||||
ret = clk_hw_register(dev, hw);
|
||||
if (ret) {
|
||||
pr_err("%s: failed to register pll %s %d\n",
|
||||
__func__, name, ret);
|
||||
pr_err("failed to register pll %s %d\n", name, ret);
|
||||
kfree(pll);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ struct imx_clk_scu_rsrc_table {
|
||||
|
||||
extern struct list_head imx_scu_clks[];
|
||||
extern const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops;
|
||||
extern const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8dxl;
|
||||
extern const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8qxp;
|
||||
extern const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8qm;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user