mirror of
https://github.com/torvalds/linux.git
synced 2025-11-30 23:16:01 +07:00
Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
Pull clk updates from Stephen Boyd: "There's a bunch of patches here across drivers/clk/ to migrate drivers to use struct clk_ops::determine_rate() instead of the round_rate() one so that we can remove the round_rate clk_op entirely. Brian has taken up that task which nobody else has wanted to do for close to a decade. Thanks Brian! This is all prerequisite work to get to the real task of improving the clk rate setting process. Once we have determine_rate() used everywhere, we'll be able to do things like chain the rate request structs in linked lists to order the rate setting operations or add more parameters without having to change every clk driver in existence. It's also nice to not have multiple ways to do something which just causes confusion for clk driver authors. Overall I'm glad this is getting done. Beyond this change we also have a tweak to the clk_lookup() function in the core framework to use hashing on the clk name instead of a clk tree walk with string comparisons. We _still_ rely on the clk name to be unique, because historically we've used globally unique strings to describe the clk tree topology. This tree walk becomes increasingly slow as more clks are added to the system. Searching from the roots for a duplicate is simple but pretty dumb and it wastes boot time so we're using a hash table as an improvement. Ideally we wouldn't rely on the strings to be unique at all, relegating them to simply debug information, but that is future work that will likely require some sort of Kconfig knob indicating strings aren't used for topology description. Outside of the core framework changes we have the usual new SoC support and fixes to clk drivers for things that were discovered once the clks were used by consumer drivers. Nothing in particular is jumping out at me in the "misc" pile, except maybe the Amlogic driver that has gone through a refactoring. That series got a fix from testing in -next though so it seems likely that things have been getting good test coverage for a couple weeks already" * tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (299 commits) clk: microchip: core: remove duplicate roclk_determine_rate() reset: aspeed: register AST2700 reset auxiliary bus device dt-bindings: clock: ast2700: modify soc0/1 clock define clk: tegra: do not overallocate memory for bpmp clocks clk: ep93xx: Use int type to store negative error codes clk: nxp: Fix pll0 rate check condition in LPC18xx CGU driver clk: loongson2: Add clock definitions for Loongson-2K0300 SoC clk: loongson2: Avoid hardcoding firmware name of the reference clock clk: loongson2: Allow zero divisors for dividers clk: loongson2: Support scale clocks with an alternative mode clk: loongson2: Allow specifying clock flags for gate clock dt-bindings: clock: loongson2: Add Loongson-2K0300 compatible clk: clocking-wizard: Fix output clock register offset for Versal platforms clk: xilinx: Optimize divisor search in clk_wzrd_get_divisors_ver() clk: mmp: pxa1908: Instantiate power driver through auxiliary bus clk: s2mps11: add support for S2MPG10 PMIC clock dt-bindings: clock: samsung,s2mps11: add s2mpg10 dt-bindings: stm32: cosmetic fixes for STM32MP25 clock and reset bindings clk: stm32: introduce clocks for STM32MP21 platform dt-bindings: stm32: add STM32MP21 clocks and reset bindings ...
This commit is contained in:
@@ -42,6 +42,9 @@ properties:
|
||||
- const: clkin2
|
||||
- const: s_axi_aclk
|
||||
|
||||
clock-output-names:
|
||||
maxItems: 1
|
||||
|
||||
'#clock-cells':
|
||||
const: 0
|
||||
|
||||
@@ -65,4 +68,5 @@ examples:
|
||||
reg = <0xff000000 0x1000>;
|
||||
clocks = <&osc 1>, <&clkc 15>;
|
||||
clock-names = "clkin1", "s_axi_aclk";
|
||||
clock-output-names = "spi_sclk";
|
||||
};
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
Fujitsu CRG11 clock driver bindings
|
||||
-----------------------------------
|
||||
|
||||
Required properties :
|
||||
- compatible : Shall contain "fujitsu,mb86s70-crg11"
|
||||
- #clock-cells : Shall be 3 {cntrlr domain port}
|
||||
|
||||
The consumer specifies the desired clock pointing to its phandle.
|
||||
|
||||
Example:
|
||||
|
||||
clock: crg11 {
|
||||
compatible = "fujitsu,mb86s70-crg11";
|
||||
#clock-cells = <3>;
|
||||
};
|
||||
|
||||
mhu: mhu0@2b1f0000 {
|
||||
#mbox-cells = <1>;
|
||||
compatible = "arm,mhu";
|
||||
reg = <0 0x2B1F0000 0x1000>;
|
||||
interrupts = <0 36 4>, /* LP Non-Sec */
|
||||
<0 35 4>, /* HP Non-Sec */
|
||||
<0 37 4>; /* Secure */
|
||||
clocks = <&clock 0 2 1>; /* Cntrlr:0 Domain:2 Port:1 */
|
||||
clock-names = "clk";
|
||||
};
|
||||
@@ -16,6 +16,7 @@ description: |
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- loongson,ls2k0300-clk
|
||||
- loongson,ls2k0500-clk
|
||||
- loongson,ls2k-clk # This is for Loongson-2K1000
|
||||
- loongson,ls2k2000-clk
|
||||
@@ -24,8 +25,7 @@ properties:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: 100m ref
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
@@ -38,11 +38,23 @@ properties:
|
||||
ID in its "clocks" phandle cell. See include/dt-bindings/clock/loongson,ls2k-clk.h
|
||||
for the full list of Loongson-2 SoC clock IDs.
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: loongson,ls2k0300-clk
|
||||
then:
|
||||
properties:
|
||||
clock-names: false
|
||||
else:
|
||||
required:
|
||||
- clock-names
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#clock-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/mediatek,mt8196-clock.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MediaTek Functional Clock Controller for MT8196
|
||||
|
||||
maintainers:
|
||||
- Guangjie Song <guangjie.song@mediatek.com>
|
||||
- Laura Nao <laura.nao@collabora.com>
|
||||
|
||||
description: |
|
||||
The clock architecture in MediaTek SoCs is structured like below:
|
||||
PLLs -->
|
||||
dividers -->
|
||||
muxes
|
||||
-->
|
||||
clock gate
|
||||
|
||||
The device nodes provide clock gate control in different IP blocks.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- mediatek,mt8196-imp-iic-wrap-c
|
||||
- mediatek,mt8196-imp-iic-wrap-e
|
||||
- mediatek,mt8196-imp-iic-wrap-n
|
||||
- mediatek,mt8196-imp-iic-wrap-w
|
||||
- mediatek,mt8196-mdpsys0
|
||||
- mediatek,mt8196-mdpsys1
|
||||
- mediatek,mt8196-pericfg-ao
|
||||
- mediatek,mt8196-pextp0cfg-ao
|
||||
- mediatek,mt8196-pextp1cfg-ao
|
||||
- mediatek,mt8196-ufscfg-ao
|
||||
- mediatek,mt8196-vencsys
|
||||
- mediatek,mt8196-vencsys-c1
|
||||
- mediatek,mt8196-vencsys-c2
|
||||
- mediatek,mt8196-vdecsys
|
||||
- mediatek,mt8196-vdecsys-soc
|
||||
- mediatek,mt8196-vdisp-ao
|
||||
- const: syscon
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
description:
|
||||
Reset lines for PEXTP0/1 and UFS blocks.
|
||||
|
||||
mediatek,hardware-voter:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: |
|
||||
Phandle to the "Hardware Voter" (HWV), as named in the vendor
|
||||
documentation for MT8196/MT6991.
|
||||
|
||||
The HWV is a SoC-internal fixed-function MCU used to collect votes from
|
||||
both the Application Processor and other remote processors within the SoC.
|
||||
It is intended to transparently enable or disable hardware resources (such
|
||||
as power domains or clocks) based on internal vote aggregation handled by
|
||||
the MCU's internal state machine.
|
||||
|
||||
However, in practice, this design is incomplete. While the HWV performs
|
||||
some internal vote aggregation,software is still required to
|
||||
- Manually enable power supplies externally, if present and if required
|
||||
- Manually enable parent clocks via direct MMIO writes to clock controllers
|
||||
- Enable the FENC after the clock has been ungated via direct MMIO
|
||||
writes to clock controllers
|
||||
|
||||
As such, the HWV behaves more like a hardware-managed clock reference
|
||||
counter than a true voter. Furthermore, it is not a separate
|
||||
controller. It merely serves as an alternative interface to the same
|
||||
underlying clock or power controller. Actual control still requires
|
||||
direct access to the controller's own MMIO register space, in
|
||||
addition to writing to the HWV's MMIO region.
|
||||
|
||||
For this reason, a custom phandle is used here - drivers need to directly
|
||||
access the HWV MMIO region in a syscon-like fashion, due to how the
|
||||
hardware is wired. This differs from true hardware voting systems, which
|
||||
typically do not require custom phandles and rely instead on generic APIs
|
||||
(clocks, power domains, interconnects).
|
||||
|
||||
The name "hardware-voter" is retained to match vendor documentation, but
|
||||
this should not be reused or misunderstood as a proper voting mechanism.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
pericfg_ao: clock-controller@16640000 {
|
||||
compatible = "mediatek,mt8196-pericfg-ao", "syscon";
|
||||
reg = <0x16640000 0x1000>;
|
||||
mediatek,hardware-voter = <&scp_hwv>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
- |
|
||||
pextp0cfg_ao: clock-controller@169b0000 {
|
||||
compatible = "mediatek,mt8196-pextp0cfg-ao", "syscon";
|
||||
reg = <0x169b0000 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
@@ -0,0 +1,107 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/mediatek,mt8196-sys-clock.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MediaTek System Clock Controller for MT8196
|
||||
|
||||
maintainers:
|
||||
- Guangjie Song <guangjie.song@mediatek.com>
|
||||
- Laura Nao <laura.nao@collabora.com>
|
||||
|
||||
description: |
|
||||
The clock architecture in MediaTek SoCs is structured like below:
|
||||
PLLs -->
|
||||
dividers -->
|
||||
muxes
|
||||
-->
|
||||
clock gate
|
||||
|
||||
The apmixedsys, apmixedsys_gp2, vlpckgen, armpll, ccipll, mfgpll and ptppll
|
||||
provide most of the PLLs which are generated from the SoC's 26MHZ crystal oscillator.
|
||||
The topckgen, topckgen_gp2 and vlpckgen provide dividers and muxes which
|
||||
provide the clock source to other IP blocks.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- mediatek,mt8196-apmixedsys
|
||||
- mediatek,mt8196-armpll-b-pll-ctrl
|
||||
- mediatek,mt8196-armpll-bl-pll-ctrl
|
||||
- mediatek,mt8196-armpll-ll-pll-ctrl
|
||||
- mediatek,mt8196-apmixedsys-gp2
|
||||
- mediatek,mt8196-ccipll-pll-ctrl
|
||||
- mediatek,mt8196-mfgpll-pll-ctrl
|
||||
- mediatek,mt8196-mfgpll-sc0-pll-ctrl
|
||||
- mediatek,mt8196-mfgpll-sc1-pll-ctrl
|
||||
- mediatek,mt8196-ptppll-pll-ctrl
|
||||
- mediatek,mt8196-topckgen
|
||||
- mediatek,mt8196-topckgen-gp2
|
||||
- mediatek,mt8196-vlpckgen
|
||||
- const: syscon
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
mediatek,hardware-voter:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: |
|
||||
Phandle to the "Hardware Voter" (HWV), as named in the vendor
|
||||
documentation for MT8196/MT6991.
|
||||
|
||||
The HWV is a SoC-internal fixed-function MCU used to collect votes from
|
||||
both the Application Processor and other remote processors within the SoC.
|
||||
It is intended to transparently enable or disable hardware resources (such
|
||||
as power domains or clocks) based on internal vote aggregation handled by
|
||||
the MCU's internal state machine.
|
||||
|
||||
However, in practice, this design is incomplete. While the HWV performs
|
||||
some internal vote aggregation,software is still required to
|
||||
- Manually enable power supplies externally, if present and if required
|
||||
- Manually enable parent clocks via direct MMIO writes to clock controllers
|
||||
- Enable the FENC after the clock has been ungated via direct MMIO
|
||||
writes to clock controllers
|
||||
|
||||
As such, the HWV behaves more like a hardware-managed clock reference
|
||||
counter than a true voter. Furthermore, it is not a separate
|
||||
controller. It merely serves as an alternative interface to the same
|
||||
underlying clock or power controller. Actual control still requires
|
||||
direct access to the controller's own MMIO register space, in
|
||||
addition to writing to the HWV's MMIO region.
|
||||
|
||||
For this reason, a custom phandle is used here - drivers need to directly
|
||||
access the HWV MMIO region in a syscon-like fashion, due to how the
|
||||
hardware is wired. This differs from true hardware voting systems, which
|
||||
typically do not require custom phandles and rely instead on generic APIs
|
||||
(clocks, power domains, interconnects).
|
||||
|
||||
The name "hardware-voter" is retained to match vendor documentation, but
|
||||
this should not be reused or misunderstood as a proper voting mechanism.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
apmixedsys_clk: syscon@10000800 {
|
||||
compatible = "mediatek,mt8196-apmixedsys", "syscon";
|
||||
reg = <0x10000800 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
- |
|
||||
topckgen: syscon@10000000 {
|
||||
compatible = "mediatek,mt8196-topckgen", "syscon";
|
||||
reg = <0x10000000 0x800>;
|
||||
mediatek,hardware-voter = <&scp_hwv>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
@@ -76,6 +76,9 @@ properties:
|
||||
- const: mediatek,mt2701-vdecsys
|
||||
- const: syscon
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -86,6 +89,18 @@ required:
|
||||
- compatible
|
||||
- '#clock-cells'
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: mediatek,mt8183-mfgcfg
|
||||
then:
|
||||
properties:
|
||||
power-domains: true
|
||||
else:
|
||||
properties:
|
||||
power-domains: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
||||
@@ -9,16 +9,21 @@ title: Qualcomm Global Clock & Reset Controller on MSM8953
|
||||
maintainers:
|
||||
- Adam Skladowski <a_skl39@protonmail.com>
|
||||
- Sireesh Kodali <sireeshkodali@protonmail.com>
|
||||
- Barnabas Czeman <barnabas.czeman@mainlining.org>
|
||||
|
||||
description: |
|
||||
Qualcomm global clock control module provides the clocks, resets and power
|
||||
domains on MSM8953.
|
||||
domains on MSM8937 or MSM8953.
|
||||
|
||||
See also: include/dt-bindings/clock/qcom,gcc-msm8953.h
|
||||
See also::
|
||||
include/dt-bindings/clock/qcom,gcc-msm8917.h
|
||||
include/dt-bindings/clock/qcom,gcc-msm8953.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,gcc-msm8953
|
||||
enum:
|
||||
- qcom,gcc-msm8937
|
||||
- qcom,gcc-msm8953
|
||||
|
||||
clocks:
|
||||
items:
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,glymur-dispcc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Display Clock & Reset Controller on GLYMUR
|
||||
|
||||
maintainers:
|
||||
- Taniya Das <taniya.das@oss.qualcomm.com>
|
||||
|
||||
description: |
|
||||
Qualcomm display clock control module which supports the clocks, resets and
|
||||
power domains for the MDSS instances on GLYMUR SoC.
|
||||
|
||||
See also:
|
||||
include/dt-bindings/clock/qcom,dispcc-glymur.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,glymur-dispcc
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Board CXO clock
|
||||
- description: Board sleep clock
|
||||
- description: DisplayPort 0 link clock
|
||||
- description: DisplayPort 0 VCO div clock
|
||||
- description: DisplayPort 1 link clock
|
||||
- description: DisplayPort 1 VCO div clock
|
||||
- description: DisplayPort 2 link clock
|
||||
- description: DisplayPort 2 VCO div clock
|
||||
- description: DisplayPort 3 link clock
|
||||
- description: DisplayPort 3 VCO div clock
|
||||
- description: DSI 0 PLL byte clock
|
||||
- description: DSI 0 PLL DSI clock
|
||||
- description: DSI 1 PLL byte clock
|
||||
- description: DSI 1 PLL DSI clock
|
||||
- description: Standalone PHY 0 PLL link clock
|
||||
- description: Standalone PHY 0 VCO div clock
|
||||
- description: Standalone PHY 1 PLL link clock
|
||||
- description: Standalone PHY 1 VCO div clock
|
||||
|
||||
power-domains:
|
||||
description:
|
||||
A phandle and PM domain specifier for the MMCX power domain.
|
||||
maxItems: 1
|
||||
|
||||
required-opps:
|
||||
description:
|
||||
A phandle to an OPP node describing required MMCX performance point.
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- power-domains
|
||||
- '#power-domain-cells'
|
||||
|
||||
allOf:
|
||||
- $ref: qcom,gcc.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
#include <dt-bindings/power/qcom,rpmhpd.h>
|
||||
|
||||
clock-controller@af00000 {
|
||||
compatible = "qcom,glymur-dispcc";
|
||||
reg = <0x0af00000 0x20000>;
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>,
|
||||
<&sleep_clk>,
|
||||
<&mdss_dp_phy0 0>,
|
||||
<&mdss_dp_phy0 1>,
|
||||
<&mdss_dp_phy1 0>,
|
||||
<&mdss_dp_phy1 1>,
|
||||
<&mdss_dp_phy2 0>,
|
||||
<&mdss_dp_phy2 1>,
|
||||
<&mdss_dp_phy3 0>,
|
||||
<&mdss_dp_phy3 1>,
|
||||
<&mdss_dsi0_phy 0>,
|
||||
<&mdss_dsi0_phy 1>,
|
||||
<&mdss_dsi1_phy 0>,
|
||||
<&mdss_dsi1_phy 1>,
|
||||
<&mdss_phy0_link 0>,
|
||||
<&mdss_phy0_vco_div 0>,
|
||||
<&mdss_phy1_link 1>,
|
||||
<&mdss_phy1_vco_div 1>;
|
||||
power-domains = <&rpmhpd RPMHPD_MMCX>;
|
||||
required-opps = <&rpmhpd_opp_low_svs>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
...
|
||||
121
Documentation/devicetree/bindings/clock/qcom,glymur-gcc.yaml
Normal file
121
Documentation/devicetree/bindings/clock/qcom,glymur-gcc.yaml
Normal file
@@ -0,0 +1,121 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,glymur-gcc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Global Clock & Reset Controller on Glymur SoC
|
||||
|
||||
maintainers:
|
||||
- Taniya Das <taniya.das@oss.qualcomm.com>
|
||||
|
||||
description: |
|
||||
Qualcomm global clock control module provides the clocks, resets and power
|
||||
domains on Glymur SoC.
|
||||
|
||||
See also: include/dt-bindings/clock/qcom,glymur-gcc.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,glymur-gcc
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Board XO source
|
||||
- description: Board XO_A source
|
||||
- description: Sleep clock source
|
||||
- description: USB 0 Phy DP0 GMUX clock source
|
||||
- description: USB 0 Phy DP1 GMUX clock source
|
||||
- description: USB 0 Phy PCIE PIPEGMUX clock source
|
||||
- description: USB 0 Phy PIPEGMUX clock source
|
||||
- description: USB 0 Phy SYS PCIE PIPEGMUX clock source
|
||||
- description: USB 1 Phy DP0 GMUX 2 clock source
|
||||
- description: USB 1 Phy DP1 GMUX 2 clock source
|
||||
- description: USB 1 Phy PCIE PIPEGMUX clock source
|
||||
- description: USB 1 Phy PIPEGMUX clock source
|
||||
- description: USB 1 Phy SYS PCIE PIPEGMUX clock source
|
||||
- description: USB 2 Phy DP0 GMUX 2 clock source
|
||||
- description: USB 2 Phy DP1 GMUX 2 clock source
|
||||
- description: USB 2 Phy PCIE PIPEGMUX clock source
|
||||
- description: USB 2 Phy PIPEGMUX clock source
|
||||
- description: USB 2 Phy SYS PCIE PIPEGMUX clock source
|
||||
- description: PCIe 3a pipe clock
|
||||
- description: PCIe 3b pipe clock
|
||||
- description: PCIe 4 pipe clock
|
||||
- description: PCIe 5 pipe clock
|
||||
- description: PCIe 6 pipe clock
|
||||
- description: QUSB4 0 PHY RX 0 clock source
|
||||
- description: QUSB4 0 PHY RX 1 clock source
|
||||
- description: QUSB4 1 PHY RX 0 clock source
|
||||
- description: QUSB4 1 PHY RX 1 clock source
|
||||
- description: QUSB4 2 PHY RX 0 clock source
|
||||
- description: QUSB4 2 PHY RX 1 clock source
|
||||
- description: UFS PHY RX Symbol 0 clock source
|
||||
- description: UFS PHY RX Symbol 1 clock source
|
||||
- description: UFS PHY TX Symbol 0 clock source
|
||||
- description: USB3 PHY 0 pipe clock source
|
||||
- description: USB3 PHY 1 pipe clock source
|
||||
- description: USB3 PHY 2 pipe clock source
|
||||
- description: USB3 UNI PHY pipe 0 clock source
|
||||
- description: USB3 UNI PHY pipe 1 clock source
|
||||
- description: USB4 PHY 0 pcie pipe clock source
|
||||
- description: USB4 PHY 0 Max pipe clock source
|
||||
- description: USB4 PHY 1 pcie pipe clock source
|
||||
- description: USB4 PHY 1 Max pipe clock source
|
||||
- description: USB4 PHY 2 pcie pipe clock source
|
||||
- description: USB4 PHY 2 Max pipe clock source
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- '#power-domain-cells'
|
||||
|
||||
allOf:
|
||||
- $ref: qcom,gcc.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
clock-controller@100000 {
|
||||
compatible = "qcom,glymur-gcc";
|
||||
reg = <0x100000 0x1f9000>;
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>,
|
||||
<&rpmhcc RPMH_CXO_CLK_A>,
|
||||
<&sleep_clk>,
|
||||
<&usb_0_phy_dp0_gmux>,
|
||||
<&usb_0_phy_dp1_gmux>,
|
||||
<&usb_0_phy_pcie_pipegmux>,
|
||||
<&usb_0_phy_pipegmux>,
|
||||
<&usb_0_phy_sys_pcie_pipegmux>,
|
||||
<&usb_1_phy_dp0_gmux_2>,
|
||||
<&usb_1_phy_dp1_gmux_2>,
|
||||
<&usb_1_phy_pcie_pipegmux>,
|
||||
<&usb_1_phy_pipegmux>,
|
||||
<&usb_1_phy_sys_pcie_pipegmux>,
|
||||
<&usb_2_phy_dp0_gmux 2>,
|
||||
<&usb_2_phy_dp1_gmux 2>,
|
||||
<&usb_2_phy_pcie_pipegmux>,
|
||||
<&usb_2_phy_pipegmux>,
|
||||
<&usb_2_phy_sys_pcie_pipegmux>,
|
||||
<&pcie_3a_pipe>, <&pcie_3b_pipe>,
|
||||
<&pcie_4_pipe>, <&pcie_5_pipe>,
|
||||
<&pcie_6_pipe>,
|
||||
<&qusb4_0_phy_rx_0>, <&qusb4_0_phy_rx_1>,
|
||||
<&qusb4_1_phy_rx_0>, <&qusb4_1_phy_rx_1>,
|
||||
<&qusb4_2_phy_rx_0>, <&qusb4_2_phy_rx_1>,
|
||||
<&ufs_phy_rx_symbol_0>, <&ufs_phy_rx_symbol_1>,
|
||||
<&ufs_phy_tx_symbol_0>,
|
||||
<&usb3_phy_0_pipe>, <&usb3_phy_1_pipe>,
|
||||
<&usb3_phy_2_pipe>,
|
||||
<&usb3_uni_phy_pipe_0>, <&usb3_uni_phy_pipe_1>,
|
||||
<&usb4_phy_0_pcie_pipe>, <&usb4_phy_0_max_pipe>,
|
||||
<&usb4_phy_1_pcie_pipe>, <&usb4_phy_1_max_pipe>,
|
||||
<&usb4_phy_2_pcie_pipe>, <&usb4_phy_2_max_pipe>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
|
||||
...
|
||||
@@ -17,6 +17,7 @@ description: |
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,glymur-rpmh-clk
|
||||
- qcom,milos-rpmh-clk
|
||||
- qcom,qcs615-rpmh-clk
|
||||
- qcom,qdu1000-rpmh-clk
|
||||
|
||||
@@ -8,12 +8,14 @@ title: Qualcomm TCSR Clock Controller on SM8550
|
||||
|
||||
maintainers:
|
||||
- Bjorn Andersson <andersson@kernel.org>
|
||||
- Taniya Das <taniya.das@oss.qualcomm.com>
|
||||
|
||||
description: |
|
||||
Qualcomm TCSR clock control module provides the clocks, resets and
|
||||
power domains on SM8550
|
||||
|
||||
See also:
|
||||
- include/dt-bindings/clock/qcom,glymur-tcsr.h
|
||||
- include/dt-bindings/clock/qcom,sm8550-tcsr.h
|
||||
- include/dt-bindings/clock/qcom,sm8650-tcsr.h
|
||||
- include/dt-bindings/clock/qcom,sm8750-tcsr.h
|
||||
@@ -22,6 +24,7 @@ properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- qcom,glymur-tcsr
|
||||
- qcom,milos-tcsr
|
||||
- qcom,sar2130p-tcsr
|
||||
- qcom,sm8550-tcsr
|
||||
|
||||
@@ -23,13 +23,17 @@ description: |
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,sc7180-videocc
|
||||
- qcom,sc7280-videocc
|
||||
- qcom,sdm845-videocc
|
||||
- qcom,sm6350-videocc
|
||||
- qcom,sm8150-videocc
|
||||
- qcom,sm8250-videocc
|
||||
oneOf:
|
||||
- enum:
|
||||
- qcom,sc7180-videocc
|
||||
- qcom,sc7280-videocc
|
||||
- qcom,sdm845-videocc
|
||||
- qcom,sm6350-videocc
|
||||
- qcom,sm8150-videocc
|
||||
- qcom,sm8250-videocc
|
||||
- items:
|
||||
- const: qcom,sc8180x-videocc
|
||||
- const: qcom,sm8150-videocc
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
@@ -110,8 +114,9 @@ allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,sm8150-videocc
|
||||
contains:
|
||||
enum:
|
||||
- qcom,sm8150-videocc
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
|
||||
@@ -30,6 +30,8 @@ description: |
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- samsung,exynos990-cmu-peric1
|
||||
- samsung,exynos990-cmu-peric0
|
||||
- samsung,exynos990-cmu-hsi0
|
||||
- samsung,exynos990-cmu-peris
|
||||
- samsung,exynos990-cmu-top
|
||||
@@ -56,6 +58,28 @@ required:
|
||||
- reg
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- samsung,exynos990-cmu-peric1
|
||||
- samsung,exynos990-cmu-peric0
|
||||
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: External reference clock (26 MHz)
|
||||
- description: Connectivity Peripheral 0/1 bus clock (from CMU_TOP)
|
||||
- description: Connectivity Peripheral 0/1 IP clock (from CMU_TOP)
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: oscclk
|
||||
- const: bus
|
||||
- const: ip
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
||||
@@ -25,6 +25,7 @@ description: |
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- samsung,s2mpg10-clk
|
||||
- samsung,s2mps11-clk
|
||||
- samsung,s2mps13-clk # S2MPS13 and S2MPS15
|
||||
- samsung,s2mps14-clk
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
Binding for Silicon Labs 514 programmable I2C clock generator.
|
||||
|
||||
Reference
|
||||
This binding uses the common clock binding[1]. Details about the device can be
|
||||
found in the datasheet[2].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
[2] Si514 datasheet
|
||||
https://www.silabs.com/Support%20Documents/TechnicalDocs/si514.pdf
|
||||
|
||||
Required properties:
|
||||
- compatible: Shall be "silabs,si514"
|
||||
- reg: I2C device address.
|
||||
- #clock-cells: From common clock bindings: Shall be 0.
|
||||
|
||||
Optional properties:
|
||||
- clock-output-names: From common clock bindings. Recommended to be "si514".
|
||||
|
||||
Example:
|
||||
si514: clock-generator@55 {
|
||||
reg = <0x55>;
|
||||
#clock-cells = <0>;
|
||||
compatible = "silabs,si514";
|
||||
};
|
||||
@@ -1,175 +0,0 @@
|
||||
Binding for Silicon Labs Si5340, Si5341 Si5342, Si5344 and Si5345 programmable
|
||||
i2c clock generator.
|
||||
|
||||
Reference
|
||||
[1] Si5341 Data Sheet
|
||||
https://www.silabs.com/documents/public/data-sheets/Si5341-40-D-DataSheet.pdf
|
||||
[2] Si5341 Reference Manual
|
||||
https://www.silabs.com/documents/public/reference-manuals/Si5341-40-D-RM.pdf
|
||||
[3] Si5345 Reference Manual
|
||||
https://www.silabs.com/documents/public/reference-manuals/Si5345-44-42-D-RM.pdf
|
||||
|
||||
The Si5341 and Si5340 are programmable i2c clock generators with up to 10 output
|
||||
clocks. The chip contains a PLL that sources 5 (or 4) multisynth clocks, which
|
||||
in turn can be directed to any of the 10 (or 4) outputs through a divider.
|
||||
The internal structure of the clock generators can be found in [2].
|
||||
The Si5345 is similar to the Si5341 with the addition of fractional input
|
||||
dividers and automatic input selection, as described in [3].
|
||||
The Si5342 and Si5344 are smaller versions of the Si5345, with 2 or 4 outputs.
|
||||
|
||||
The driver can be used in "as is" mode, reading the current settings from the
|
||||
chip at boot, in case you have a (pre-)programmed device. If the PLL is not
|
||||
configured when the driver probes, it assumes the driver must fully initialize
|
||||
it.
|
||||
|
||||
The device type, speed grade and revision are determined runtime by probing.
|
||||
|
||||
The driver currently does not support any fancy input configurations. They can
|
||||
still be programmed into the chip and the driver will leave them "as is".
|
||||
|
||||
==I2C device node==
|
||||
|
||||
Required properties:
|
||||
- compatible: shall be one of the following:
|
||||
"silabs,si5340" - Si5340 A/B/C/D
|
||||
"silabs,si5341" - Si5341 A/B/C/D
|
||||
"silabs,si5342" - Si5342 A/B/C/D
|
||||
"silabs,si5344" - Si5344 A/B/C/D
|
||||
"silabs,si5345" - Si5345 A/B/C/D
|
||||
- reg: i2c device address, usually 0x74
|
||||
- #clock-cells: from common clock binding; shall be set to 2.
|
||||
The first value is "0" for outputs, "1" for synthesizers.
|
||||
The second value is the output or synthesizer index.
|
||||
- clocks: from common clock binding; list of parent clock handles,
|
||||
corresponding to inputs. Use a fixed clock for the "xtal" input.
|
||||
At least one must be present.
|
||||
- clock-names: One of: "xtal", "in0", "in1", "in2"
|
||||
|
||||
Optional properties:
|
||||
- vdd-supply: Regulator node for VDD
|
||||
- vdda-supply: Regulator node for VDDA
|
||||
- vdds-supply: Regulator node for VDDS
|
||||
- silabs,pll-m-num, silabs,pll-m-den: Numerator and denominator for PLL
|
||||
feedback divider. Must be such that the PLL output is in the valid range. For
|
||||
example, to create 14GHz from a 48MHz xtal, use m-num=14000 and m-den=48. Only
|
||||
the fraction matters, using 3500 and 12 will deliver the exact same result.
|
||||
If these are not specified, and the PLL is not yet programmed when the driver
|
||||
probes, the PLL will be set to 14GHz.
|
||||
- silabs,reprogram: When present, the driver will always assume the device must
|
||||
be initialized, and always performs the soft-reset routine. Since this will
|
||||
temporarily stop all output clocks, don't do this if the chip is generating
|
||||
the CPU clock for example.
|
||||
- silabs,xaxb-ext-clk: When present, indicates that the XA/XB pins are used
|
||||
in EXTCLK (external reference clock) rather than XTAL (crystal) mode.
|
||||
- interrupts: Interrupt for INTRb pin.
|
||||
- silabs,iovdd-33: When present, indicates that the I2C lines are using 3.3V
|
||||
rather than 1.8V thresholds.
|
||||
- vddoX-supply (where X is an output index): Regulator node for VDDO for the
|
||||
specified output. The driver selects the output VDD_SEL setting based on this
|
||||
voltage.
|
||||
- #address-cells: shall be set to 1.
|
||||
- #size-cells: shall be set to 0.
|
||||
|
||||
|
||||
== Child nodes: Outputs ==
|
||||
|
||||
The child nodes list the output clocks.
|
||||
|
||||
Each of the clock outputs can be overwritten individually by using a child node.
|
||||
If a child node for a clock output is not set, the configuration remains
|
||||
unchanged.
|
||||
|
||||
Required child node properties:
|
||||
- reg: number of clock output.
|
||||
|
||||
Optional child node properties:
|
||||
- silabs,format: Output format, one of:
|
||||
1 = differential (defaults to LVDS levels)
|
||||
2 = low-power (defaults to HCSL levels)
|
||||
4 = LVCMOS
|
||||
- silabs,common-mode: Manually override output common mode, see [2] for values
|
||||
- silabs,amplitude: Manually override output amplitude, see [2] for values
|
||||
- silabs,synth-master: boolean. If present, this output is allowed to change the
|
||||
multisynth frequency dynamically.
|
||||
- silabs,silabs,disable-high: boolean. If set, the clock output is driven HIGH
|
||||
when disabled, otherwise it's driven LOW.
|
||||
|
||||
==Example==
|
||||
|
||||
/* 48MHz reference crystal */
|
||||
ref48: ref48M {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <48000000>;
|
||||
};
|
||||
|
||||
i2c-master-node {
|
||||
/* Programmable clock (for logic) */
|
||||
si5341: clock-generator@74 {
|
||||
reg = <0x74>;
|
||||
compatible = "silabs,si5341";
|
||||
#clock-cells = <2>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&ref48>;
|
||||
clock-names = "xtal";
|
||||
|
||||
silabs,pll-m-num = <14000>; /* PLL at 14.0 GHz */
|
||||
silabs,pll-m-den = <48>;
|
||||
silabs,reprogram; /* Chips are not programmed, always reset */
|
||||
|
||||
out@0 {
|
||||
reg = <0>;
|
||||
silabs,format = <1>; /* LVDS 3v3 */
|
||||
silabs,common-mode = <3>;
|
||||
silabs,amplitude = <3>;
|
||||
silabs,synth-master;
|
||||
};
|
||||
|
||||
/*
|
||||
* Output 6 configuration:
|
||||
* LVDS 1v8
|
||||
*/
|
||||
out@6 {
|
||||
reg = <6>;
|
||||
silabs,format = <1>; /* LVDS 1v8 */
|
||||
silabs,common-mode = <13>;
|
||||
silabs,amplitude = <3>;
|
||||
};
|
||||
|
||||
/*
|
||||
* Output 8 configuration:
|
||||
* HCSL 3v3
|
||||
*/
|
||||
out@8 {
|
||||
reg = <8>;
|
||||
silabs,format = <2>;
|
||||
silabs,common-mode = <11>;
|
||||
silabs,amplitude = <3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
some-video-node {
|
||||
/* Standard clock bindings */
|
||||
clock-names = "pixel";
|
||||
clocks = <&si5341 0 7>; /* Output 7 */
|
||||
|
||||
/* Set output 7 to use syntesizer 3 as its parent */
|
||||
assigned-clocks = <&si5341 0 7>, <&si5341 1 3>;
|
||||
assigned-clock-parents = <&si5341 1 3>;
|
||||
/* Set output 7 to 148.5 MHz using a synth frequency of 594 MHz */
|
||||
assigned-clock-rates = <148500000>, <594000000>;
|
||||
};
|
||||
|
||||
some-audio-node {
|
||||
clock-names = "i2s-clk";
|
||||
clocks = <&si5341 0 0>;
|
||||
/*
|
||||
* since output 0 is a synth-master, the synth will be automatically set
|
||||
* to an appropriate frequency when the audio driver requests another
|
||||
* frequency. We give control over synth 2 to this output here.
|
||||
*/
|
||||
assigned-clocks = <&si5341 0 0>;
|
||||
assigned-clock-parents = <&si5341 1 2>;
|
||||
};
|
||||
223
Documentation/devicetree/bindings/clock/silabs,si5341.yaml
Normal file
223
Documentation/devicetree/bindings/clock/silabs,si5341.yaml
Normal file
@@ -0,0 +1,223 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/silabs,si5341.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Silicon Labs Si5340/1/2/4/5 programmable i2c clock generator
|
||||
|
||||
maintainers:
|
||||
- Mike Looijmans <mike.looijmans@topic.nl>
|
||||
|
||||
description: >
|
||||
Silicon Labs Si5340, Si5341 Si5342, Si5344 and Si5345 programmable i2c clock
|
||||
generator.
|
||||
|
||||
Reference
|
||||
[1] Si5341 Data Sheet
|
||||
https://www.silabs.com/documents/public/data-sheets/Si5341-40-D-DataSheet.pdf
|
||||
[2] Si5341 Reference Manual
|
||||
https://www.silabs.com/documents/public/reference-manuals/Si5341-40-D-RM.pdf
|
||||
[3] Si5345 Reference Manual
|
||||
https://www.silabs.com/documents/public/reference-manuals/Si5345-44-42-D-RM.pdf
|
||||
|
||||
The Si5341 and Si5340 are programmable i2c clock generators with up to 10 output
|
||||
clocks. The chip contains a PLL that sources 5 (or 4) multisynth clocks, which
|
||||
in turn can be directed to any of the 10 (or 4) outputs through a divider.
|
||||
The internal structure of the clock generators can be found in [2].
|
||||
The Si5345 is similar to the Si5341 with the addition of fractional input
|
||||
dividers and automatic input selection, as described in [3].
|
||||
The Si5342 and Si5344 are smaller versions of the Si5345, with 2 or 4 outputs.
|
||||
|
||||
The driver can be used in "as is" mode, reading the current settings from the
|
||||
chip at boot, in case you have a (pre-)programmed device. If the PLL is not
|
||||
configured when the driver probes, it assumes the driver must fully initialize
|
||||
it.
|
||||
|
||||
The device type, speed grade and revision are determined runtime by probing.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- silabs,si5340
|
||||
- silabs,si5341
|
||||
- silabs,si5342
|
||||
- silabs,si5344
|
||||
- silabs,si5345
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#clock-cells":
|
||||
const: 2
|
||||
description: >
|
||||
The first value is "0" for outputs, "1" for synthesizers.
|
||||
|
||||
The second value is the output or synthesizer index.
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
items:
|
||||
- const: xtal
|
||||
- const: in0
|
||||
- const: in1
|
||||
- const: in2
|
||||
|
||||
clock-output-names: true
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
description: Interrupt for INTRb pin
|
||||
|
||||
vdd-supply:
|
||||
description: Regulator node for VDD
|
||||
|
||||
vdda-supply:
|
||||
description: Regulator node for VDDA
|
||||
|
||||
vdds-supply:
|
||||
description: Regulator node for VDDS
|
||||
|
||||
silabs,pll-m-num:
|
||||
description:
|
||||
Numerator for PLL feedback divider. Must be such that the PLL output is in
|
||||
the valid range. For example, to create 14GHz from a 48MHz xtal, use
|
||||
m-num=14000 and m-den=48. Only the fraction matters, using 3500 and 12
|
||||
will deliver the exact same result. If these are not specified, and the
|
||||
PLL is not yet programmed when the driver probes, the PLL will be set to
|
||||
14GHz.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
silabs,pll-m-den:
|
||||
description: Denominator for PLL feedback divider
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
silabs,reprogram:
|
||||
description: Always perform soft-reset and reinitialize PLL
|
||||
type: boolean
|
||||
|
||||
silabs,xaxb-ext-clk:
|
||||
description: Use XA/XB pins as external reference clock
|
||||
type: boolean
|
||||
|
||||
silabs,iovdd-33:
|
||||
description: I2C lines use 3.3V thresholds
|
||||
type: boolean
|
||||
|
||||
patternProperties:
|
||||
"^vddo[0-9]-supply$": true
|
||||
|
||||
"^out@[0-9]$":
|
||||
description: >
|
||||
Output-specific override nodes
|
||||
|
||||
Each of the clock outputs can be overwritten individually by using a child
|
||||
node. If a child node for a clock output is not set, the configuration
|
||||
remains unchanged.
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description: Number of clock output
|
||||
maximum: 9
|
||||
|
||||
always-on:
|
||||
description: Set to keep the clock output always running
|
||||
type: boolean
|
||||
|
||||
silabs,format:
|
||||
description: Output format
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [1, 2, 4]
|
||||
|
||||
silabs,common-mode:
|
||||
description: Override output common mode
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
silabs,amplitude:
|
||||
description: Override output amplitude
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
silabs,synth-master:
|
||||
description: Allow dynamic multisynth rate control
|
||||
type: boolean
|
||||
|
||||
silabs,disable-high:
|
||||
description: Drive output HIGH when disabled
|
||||
type: boolean
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#clock-cells"
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clock-generator@74 {
|
||||
reg = <0x74>;
|
||||
compatible = "silabs,si5341";
|
||||
#clock-cells = <2>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&ref48>;
|
||||
clock-names = "xtal";
|
||||
|
||||
silabs,pll-m-num = <14000>; /* PLL at 14.0 GHz */
|
||||
silabs,pll-m-den = <48>;
|
||||
silabs,reprogram; /* Chips are not programmed, always reset */
|
||||
|
||||
out@0 {
|
||||
reg = <0>;
|
||||
silabs,format = <1>; /* LVDS 3v3 */
|
||||
silabs,common-mode = <3>;
|
||||
silabs,amplitude = <3>;
|
||||
silabs,synth-master;
|
||||
};
|
||||
|
||||
/*
|
||||
* Output 6 configuration:
|
||||
* LVDS 1v8
|
||||
*/
|
||||
out@6 {
|
||||
reg = <6>;
|
||||
silabs,format = <1>; /* LVDS 1v8 */
|
||||
silabs,common-mode = <13>;
|
||||
silabs,amplitude = <3>;
|
||||
};
|
||||
|
||||
/*
|
||||
* Output 8 configuration:
|
||||
* HCSL 3v3
|
||||
*/
|
||||
out@8 {
|
||||
reg = <8>;
|
||||
silabs,format = <2>;
|
||||
silabs,common-mode = <11>;
|
||||
silabs,amplitude = <3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -1,25 +0,0 @@
|
||||
Binding for Silicon Labs 544 programmable I2C clock generator.
|
||||
|
||||
Reference
|
||||
This binding uses the common clock binding[1]. Details about the device can be
|
||||
found in the datasheet[2].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
[2] Si544 datasheet
|
||||
https://www.silabs.com/documents/public/data-sheets/si544-datasheet.pdf
|
||||
|
||||
Required properties:
|
||||
- compatible: One of "silabs,si514a", "silabs,si514b" "silabs,si514c" according
|
||||
to the speed grade of the chip.
|
||||
- reg: I2C device address.
|
||||
- #clock-cells: From common clock bindings: Shall be 0.
|
||||
|
||||
Optional properties:
|
||||
- clock-output-names: From common clock bindings. Recommended to be "si544".
|
||||
|
||||
Example:
|
||||
si544: clock-controller@55 {
|
||||
reg = <0x55>;
|
||||
#clock-cells = <0>;
|
||||
compatible = "silabs,si544b";
|
||||
};
|
||||
54
Documentation/devicetree/bindings/clock/silabs,si544.yaml
Normal file
54
Documentation/devicetree/bindings/clock/silabs,si544.yaml
Normal file
@@ -0,0 +1,54 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/silabs,si544.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Silicon Labs SI514/SI544 clock generator
|
||||
|
||||
maintainers:
|
||||
- Mike Looijmans <mike.looijmans@topic.nl>
|
||||
|
||||
description: >
|
||||
Silicon Labs 514/544 programmable I2C clock generator. Details about the device
|
||||
can be found in the datasheet:
|
||||
|
||||
https://www.silabs.com/Support%20Documents/TechnicalDocs/si514.pdf
|
||||
https://www.silabs.com/documents/public/data-sheets/si544-datasheet.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- silabs,si514
|
||||
- silabs,si544a
|
||||
- silabs,si544b
|
||||
- silabs,si544c
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#clock-cells":
|
||||
const: 0
|
||||
|
||||
clock-output-names:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#clock-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clock-controller@55 {
|
||||
reg = <0x55>;
|
||||
#clock-cells = <0>;
|
||||
compatible = "silabs,si544b";
|
||||
};
|
||||
};
|
||||
@@ -1,41 +0,0 @@
|
||||
Binding for Silicon Labs 570, 571, 598 and 599 programmable
|
||||
I2C clock generators.
|
||||
|
||||
Reference
|
||||
This binding uses the common clock binding[1]. Details about the devices can be
|
||||
found in the data sheets[2][3].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
[2] Si570/571 Data Sheet
|
||||
https://www.silabs.com/Support%20Documents/TechnicalDocs/si570.pdf
|
||||
[3] Si598/599 Data Sheet
|
||||
https://www.silabs.com/Support%20Documents/TechnicalDocs/si598-99.pdf
|
||||
|
||||
Required properties:
|
||||
- compatible: Shall be one of "silabs,si570", "silabs,si571",
|
||||
"silabs,si598", "silabs,si599"
|
||||
- reg: I2C device address.
|
||||
- #clock-cells: From common clock bindings: Shall be 0.
|
||||
- factory-fout: Factory set default frequency. This frequency is part specific.
|
||||
The correct frequency for the part used has to be provided in
|
||||
order to generate the correct output frequencies. For more
|
||||
details, please refer to the data sheet.
|
||||
- temperature-stability: Temperature stability of the device in PPM. Should be
|
||||
one of: 7, 20, 50 or 100.
|
||||
|
||||
Optional properties:
|
||||
- clock-output-names: From common clock bindings. Recommended to be "si570".
|
||||
- clock-frequency: Output frequency to generate. This defines the output
|
||||
frequency set during boot. It can be reprogrammed during
|
||||
runtime through the common clock framework.
|
||||
- silabs,skip-recall: Do not perform NVM->RAM recall operation. It will rely
|
||||
on hardware loading of RAM from NVM at power on.
|
||||
|
||||
Example:
|
||||
si570: clock-generator@5d {
|
||||
#clock-cells = <0>;
|
||||
compatible = "silabs,si570";
|
||||
temperature-stability = <50>;
|
||||
reg = <0x5d>;
|
||||
factory-fout = <156250000>;
|
||||
};
|
||||
80
Documentation/devicetree/bindings/clock/silabs,si570.yaml
Normal file
80
Documentation/devicetree/bindings/clock/silabs,si570.yaml
Normal file
@@ -0,0 +1,80 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/silabs,si570.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Silicon Labs Si570/Si571/Si598/Si599 programmable I2C clock generator
|
||||
|
||||
maintainers:
|
||||
- Soren Brinkmann <soren.brinkmann@xilinx.com>
|
||||
|
||||
description: >
|
||||
Silicon Labs 570, 571, 598 and 599 programmable I2C clock generators. Details
|
||||
about the devices can be found in the data sheets[1][2].
|
||||
|
||||
[1] Si570/571 Data Sheet
|
||||
https://www.silabs.com/Support%20Documents/TechnicalDocs/si570.pdf
|
||||
[2] Si598/599 Data Sheet
|
||||
https://www.silabs.com/Support%20Documents/TechnicalDocs/si598-99.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- silabs,si570
|
||||
- silabs,si571
|
||||
- silabs,si598
|
||||
- silabs,si599
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#clock-cells':
|
||||
const: 0
|
||||
|
||||
factory-fout:
|
||||
description: Factory-set default frequency in Hz.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
temperature-stability:
|
||||
description: Temperature stability of the device in PPM.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum:
|
||||
- 7
|
||||
- 20
|
||||
- 50
|
||||
- 100
|
||||
|
||||
clock-output-names:
|
||||
maxItems: 1
|
||||
|
||||
clock-frequency:
|
||||
description: Output frequency to generate at boot; can be reprogrammed at runtime.
|
||||
|
||||
silabs,skip-recall:
|
||||
description: Skip the NVM-to-RAM recall operation during boot.
|
||||
type: boolean
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
- factory-fout
|
||||
- temperature-stability
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clock-generator@5d {
|
||||
compatible = "silabs,si570";
|
||||
reg = <0x5d>;
|
||||
#clock-cells = <0>;
|
||||
temperature-stability = <50>;
|
||||
factory-fout = <156250000>;
|
||||
};
|
||||
};
|
||||
199
Documentation/devicetree/bindings/clock/st,stm32mp21-rcc.yaml
Normal file
199
Documentation/devicetree/bindings/clock/st,stm32mp21-rcc.yaml
Normal file
@@ -0,0 +1,199 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/st,stm32mp21-rcc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: STM32MP21 Reset Clock Controller
|
||||
|
||||
maintainers:
|
||||
- Gabriel Fernandez <gabriel.fernandez@foss.st.com>
|
||||
|
||||
description: |
|
||||
The RCC hardware block is both a reset and a clock controller.
|
||||
RCC makes also power management (resume/suspend).
|
||||
|
||||
See also:
|
||||
include/dt-bindings/clock/st,stm32mp21-rcc.h
|
||||
include/dt-bindings/reset/st,stm32mp21-rcc.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- st,stm32mp21-rcc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: CK_SCMI_HSE High Speed External oscillator (8 to 48 MHz)
|
||||
- description: CK_SCMI_HSI High Speed Internal oscillator (~ 64 MHz)
|
||||
- description: CK_SCMI_MSI Low Power Internal oscillator (~ 4 MHz or ~ 16 MHz)
|
||||
- description: CK_SCMI_LSE Low Speed External oscillator (32 KHz)
|
||||
- description: CK_SCMI_LSI Low Speed Internal oscillator (~ 32 KHz)
|
||||
- description: CK_SCMI_HSE_DIV2 CK_SCMI_HSE divided by 2 (could be gated)
|
||||
- description: CK_SCMI_ICN_HS_MCU High Speed interconnect bus clock
|
||||
- description: CK_SCMI_ICN_LS_MCU Low Speed interconnect bus clock
|
||||
- description: CK_SCMI_ICN_SDMMC SDMMC interconnect bus clock
|
||||
- description: CK_SCMI_ICN_DDR DDR interconnect bus clock
|
||||
- description: CK_SCMI_ICN_DISPLAY Display interconnect bus clock
|
||||
- description: CK_SCMI_ICN_HSL HSL interconnect bus clock
|
||||
- description: CK_SCMI_ICN_NIC NIC interconnect bus clock
|
||||
- description: CK_SCMI_FLEXGEN_07 flexgen clock 7
|
||||
- description: CK_SCMI_FLEXGEN_08 flexgen clock 8
|
||||
- description: CK_SCMI_FLEXGEN_09 flexgen clock 9
|
||||
- description: CK_SCMI_FLEXGEN_10 flexgen clock 10
|
||||
- description: CK_SCMI_FLEXGEN_11 flexgen clock 11
|
||||
- description: CK_SCMI_FLEXGEN_12 flexgen clock 12
|
||||
- description: CK_SCMI_FLEXGEN_13 flexgen clock 13
|
||||
- description: CK_SCMI_FLEXGEN_14 flexgen clock 14
|
||||
- description: CK_SCMI_FLEXGEN_16 flexgen clock 16
|
||||
- description: CK_SCMI_FLEXGEN_17 flexgen clock 17
|
||||
- description: CK_SCMI_FLEXGEN_18 flexgen clock 18
|
||||
- description: CK_SCMI_FLEXGEN_19 flexgen clock 19
|
||||
- description: CK_SCMI_FLEXGEN_20 flexgen clock 20
|
||||
- description: CK_SCMI_FLEXGEN_21 flexgen clock 21
|
||||
- description: CK_SCMI_FLEXGEN_22 flexgen clock 22
|
||||
- description: CK_SCMI_FLEXGEN_23 flexgen clock 23
|
||||
- description: CK_SCMI_FLEXGEN_24 flexgen clock 24
|
||||
- description: CK_SCMI_FLEXGEN_25 flexgen clock 25
|
||||
- description: CK_SCMI_FLEXGEN_26 flexgen clock 26
|
||||
- description: CK_SCMI_FLEXGEN_27 flexgen clock 27
|
||||
- description: CK_SCMI_FLEXGEN_29 flexgen clock 29
|
||||
- description: CK_SCMI_FLEXGEN_30 flexgen clock 30
|
||||
- description: CK_SCMI_FLEXGEN_31 flexgen clock 31
|
||||
- description: CK_SCMI_FLEXGEN_33 flexgen clock 33
|
||||
- description: CK_SCMI_FLEXGEN_36 flexgen clock 36
|
||||
- description: CK_SCMI_FLEXGEN_37 flexgen clock 37
|
||||
- description: CK_SCMI_FLEXGEN_38 flexgen clock 38
|
||||
- description: CK_SCMI_FLEXGEN_39 flexgen clock 39
|
||||
- description: CK_SCMI_FLEXGEN_40 flexgen clock 40
|
||||
- description: CK_SCMI_FLEXGEN_41 flexgen clock 41
|
||||
- description: CK_SCMI_FLEXGEN_42 flexgen clock 42
|
||||
- description: CK_SCMI_FLEXGEN_43 flexgen clock 43
|
||||
- description: CK_SCMI_FLEXGEN_44 flexgen clock 44
|
||||
- description: CK_SCMI_FLEXGEN_45 flexgen clock 45
|
||||
- description: CK_SCMI_FLEXGEN_46 flexgen clock 46
|
||||
- description: CK_SCMI_FLEXGEN_47 flexgen clock 47
|
||||
- description: CK_SCMI_FLEXGEN_48 flexgen clock 48
|
||||
- description: CK_SCMI_FLEXGEN_50 flexgen clock 50
|
||||
- description: CK_SCMI_FLEXGEN_51 flexgen clock 51
|
||||
- description: CK_SCMI_FLEXGEN_52 flexgen clock 52
|
||||
- description: CK_SCMI_FLEXGEN_53 flexgen clock 53
|
||||
- description: CK_SCMI_FLEXGEN_54 flexgen clock 54
|
||||
- description: CK_SCMI_FLEXGEN_55 flexgen clock 55
|
||||
- description: CK_SCMI_FLEXGEN_56 flexgen clock 56
|
||||
- description: CK_SCMI_FLEXGEN_57 flexgen clock 57
|
||||
- description: CK_SCMI_FLEXGEN_58 flexgen clock 58
|
||||
- description: CK_SCMI_FLEXGEN_61 flexgen clock 61
|
||||
- description: CK_SCMI_FLEXGEN_62 flexgen clock 62
|
||||
- description: CK_SCMI_FLEXGEN_63 flexgen clock 63
|
||||
- description: CK_SCMI_ICN_APB1 Peripheral bridge 1
|
||||
- description: CK_SCMI_ICN_APB2 Peripheral bridge 2
|
||||
- description: CK_SCMI_ICN_APB3 Peripheral bridge 3
|
||||
- description: CK_SCMI_ICN_APB4 Peripheral bridge 4
|
||||
- description: CK_SCMI_ICN_APB5 Peripheral bridge 5
|
||||
- description: CK_SCMI_ICN_APBDBG Peripheral bridge for debug
|
||||
- description: CK_SCMI_TIMG1 Peripheral bridge for timer1
|
||||
- description: CK_SCMI_TIMG2 Peripheral bridge for timer2
|
||||
|
||||
access-controllers:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/st,stm32mp21-rcc.h>
|
||||
|
||||
clock-controller@44200000 {
|
||||
compatible = "st,stm32mp21-rcc";
|
||||
reg = <0x44200000 0x10000>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
clocks = <&scmi_clk CK_SCMI_HSE>,
|
||||
<&scmi_clk CK_SCMI_HSI>,
|
||||
<&scmi_clk CK_SCMI_MSI>,
|
||||
<&scmi_clk CK_SCMI_LSE>,
|
||||
<&scmi_clk CK_SCMI_LSI>,
|
||||
<&scmi_clk CK_SCMI_HSE_DIV2>,
|
||||
<&scmi_clk CK_SCMI_ICN_HS_MCU>,
|
||||
<&scmi_clk CK_SCMI_ICN_LS_MCU>,
|
||||
<&scmi_clk CK_SCMI_ICN_SDMMC>,
|
||||
<&scmi_clk CK_SCMI_ICN_DDR>,
|
||||
<&scmi_clk CK_SCMI_ICN_DISPLAY>,
|
||||
<&scmi_clk CK_SCMI_ICN_HSL>,
|
||||
<&scmi_clk CK_SCMI_ICN_NIC>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_07>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_08>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_09>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_10>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_11>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_12>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_13>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_14>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_16>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_17>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_18>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_19>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_20>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_21>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_22>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_23>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_24>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_25>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_26>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_27>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_29>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_30>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_31>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_33>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_36>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_37>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_38>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_39>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_40>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_41>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_42>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_43>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_44>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_45>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_46>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_47>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_48>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_50>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_51>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_52>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_53>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_54>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_55>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_56>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_57>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_58>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_61>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_62>,
|
||||
<&scmi_clk CK_SCMI_FLEXGEN_63>,
|
||||
<&scmi_clk CK_SCMI_ICN_APB1>,
|
||||
<&scmi_clk CK_SCMI_ICN_APB2>,
|
||||
<&scmi_clk CK_SCMI_ICN_APB3>,
|
||||
<&scmi_clk CK_SCMI_ICN_APB4>,
|
||||
<&scmi_clk CK_SCMI_ICN_APB5>,
|
||||
<&scmi_clk CK_SCMI_ICN_APBDBG>,
|
||||
<&scmi_clk CK_SCMI_TIMG1>,
|
||||
<&scmi_clk CK_SCMI_TIMG2>;
|
||||
};
|
||||
...
|
||||
@@ -11,9 +11,9 @@ maintainers:
|
||||
|
||||
description: |
|
||||
The RCC hardware block is both a reset and a clock controller.
|
||||
RCC makes also power management (resume/supend).
|
||||
RCC makes also power management (resume/suspend).
|
||||
|
||||
See also::
|
||||
See also:
|
||||
include/dt-bindings/clock/st,stm32mp25-rcc.h
|
||||
include/dt-bindings/reset/st,stm32mp25-rcc.h
|
||||
|
||||
@@ -38,7 +38,7 @@ properties:
|
||||
- description: CK_SCMI_MSI Low Power Internal oscillator (~ 4 MHz or ~ 16 MHz)
|
||||
- description: CK_SCMI_LSE Low Speed External oscillator (32 KHz)
|
||||
- description: CK_SCMI_LSI Low Speed Internal oscillator (~ 32 KHz)
|
||||
- description: CK_SCMI_HSE_DIV2 CK_SCMI_HSE divided by 2 (coud be gated)
|
||||
- description: CK_SCMI_HSE_DIV2 CK_SCMI_HSE divided by 2 (could be gated)
|
||||
- description: CK_SCMI_ICN_HS_MCU High Speed interconnect bus clock
|
||||
- description: CK_SCMI_ICN_LS_MCU Low Speed interconnect bus clock
|
||||
- description: CK_SCMI_ICN_SDMMC SDMMC interconnect bus clock
|
||||
@@ -108,15 +108,14 @@ properties:
|
||||
- description: CK_SCMI_ICN_APB2 Peripheral bridge 2
|
||||
- description: CK_SCMI_ICN_APB3 Peripheral bridge 3
|
||||
- description: CK_SCMI_ICN_APB4 Peripheral bridge 4
|
||||
- description: CK_SCMI_ICN_APBDBG Peripheral bridge for degub
|
||||
- description: CK_SCMI_ICN_APBDBG Peripheral bridge for debug
|
||||
- description: CK_SCMI_TIMG1 Peripheral bridge for timer1
|
||||
- description: CK_SCMI_TIMG2 Peripheral bridge for timer2
|
||||
- description: CK_SCMI_PLL3 PLL3 clock
|
||||
- description: clk_dsi_txbyte DSI byte clock
|
||||
|
||||
access-controllers:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
@@ -131,7 +130,7 @@ examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/st,stm32mp25-rcc.h>
|
||||
|
||||
rcc: clock-controller@44200000 {
|
||||
clock-controller@44200000 {
|
||||
compatible = "st,stm32mp25-rcc";
|
||||
reg = <0x44200000 0x10000>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
@@ -64,12 +64,9 @@ Required properties:
|
||||
audio use case)
|
||||
"st,flexgen-video", "st,flexgen" (enable clock propagation on parent
|
||||
and activate synchronous mode)
|
||||
"st,flexgen-stih407-a0"
|
||||
"st,flexgen-stih410-a0"
|
||||
"st,flexgen-stih407-c0"
|
||||
"st,flexgen-stih410-c0"
|
||||
"st,flexgen-stih418-c0"
|
||||
"st,flexgen-stih407-d0"
|
||||
"st,flexgen-stih410-d0"
|
||||
"st,flexgen-stih407-d2"
|
||||
"st,flexgen-stih418-d2"
|
||||
|
||||
@@ -2906,7 +2906,9 @@ ARM/Marvell PXA1908 SOC support
|
||||
M: Duje Mihanović <duje@dujemihanovic.xyz>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/clock/marvell,pxa1908.yaml
|
||||
F: arch/arm64/boot/dts/marvell/mmp/
|
||||
F: drivers/clk/mmp/Kconfig
|
||||
F: drivers/clk/mmp/clk-pxa1908*.c
|
||||
F: drivers/pmdomain/marvell/
|
||||
F: include/dt-bindings/clock/marvell,pxa1908.h
|
||||
|
||||
@@ -364,6 +364,7 @@ config COMMON_CLK_LOCHNAGAR
|
||||
config COMMON_CLK_NPCM8XX
|
||||
tristate "Clock driver for the NPCM8XX SoC Family"
|
||||
depends on ARCH_NPCM || COMPILE_TEST
|
||||
select AUXILIARY_BUS
|
||||
help
|
||||
This driver supports the clocks on the Nuvoton BMC NPCM8XX SoC Family,
|
||||
all the clocks are initialized by the bootloader, so this driver
|
||||
@@ -520,6 +521,7 @@ source "drivers/clk/imx/Kconfig"
|
||||
source "drivers/clk/ingenic/Kconfig"
|
||||
source "drivers/clk/keystone/Kconfig"
|
||||
source "drivers/clk/mediatek/Kconfig"
|
||||
source "drivers/clk/mmp/Kconfig"
|
||||
source "drivers/clk/meson/Kconfig"
|
||||
source "drivers/clk/mstar/Kconfig"
|
||||
source "drivers/clk/microchip/Kconfig"
|
||||
|
||||
@@ -18,7 +18,6 @@ static const struct regmap_config owl_regmap_config = {
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.max_register = 0x00cc,
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
static void owl_clk_set_regmap(const struct owl_clk_desc *desc,
|
||||
|
||||
@@ -122,13 +122,13 @@ static int owl_comp_fact_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
rate, parent_rate);
|
||||
}
|
||||
|
||||
static long owl_comp_fix_fact_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int owl_comp_fix_fact_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct owl_composite *comp = hw_to_owl_comp(hw);
|
||||
struct clk_fixed_factor *fix_fact_hw = &comp->rate.fix_fact_hw;
|
||||
|
||||
return comp->fix_fact_ops->round_rate(&fix_fact_hw->hw, rate, parent_rate);
|
||||
return comp->fix_fact_ops->determine_rate(&fix_fact_hw->hw, req);
|
||||
}
|
||||
|
||||
static unsigned long owl_comp_fix_fact_recalc_rate(struct clk_hw *hw,
|
||||
@@ -193,7 +193,7 @@ const struct clk_ops owl_comp_fix_fact_ops = {
|
||||
.is_enabled = owl_comp_is_enabled,
|
||||
|
||||
/* fix_fact_ops */
|
||||
.round_rate = owl_comp_fix_fact_round_rate,
|
||||
.determine_rate = owl_comp_fix_fact_determine_rate,
|
||||
.recalc_rate = owl_comp_fix_fact_recalc_rate,
|
||||
.set_rate = owl_comp_fix_fact_set_rate,
|
||||
};
|
||||
|
||||
@@ -23,13 +23,16 @@ long owl_divider_helper_round_rate(struct owl_clk_common *common,
|
||||
div_hw->div_flags);
|
||||
}
|
||||
|
||||
static long owl_divider_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int owl_divider_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct owl_divider *div = hw_to_owl_divider(hw);
|
||||
|
||||
return owl_divider_helper_round_rate(&div->common, &div->div_hw,
|
||||
rate, parent_rate);
|
||||
req->rate = owl_divider_helper_round_rate(&div->common, &div->div_hw,
|
||||
req->rate,
|
||||
&req->best_parent_rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long owl_divider_helper_recalc_rate(struct owl_clk_common *common,
|
||||
@@ -89,6 +92,6 @@ static int owl_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
const struct clk_ops owl_divider_ops = {
|
||||
.recalc_rate = owl_divider_recalc_rate,
|
||||
.round_rate = owl_divider_round_rate,
|
||||
.determine_rate = owl_divider_determine_rate,
|
||||
.set_rate = owl_divider_set_rate,
|
||||
};
|
||||
|
||||
@@ -130,14 +130,16 @@ long owl_factor_helper_round_rate(struct owl_clk_common *common,
|
||||
return *parent_rate * mul / div;
|
||||
}
|
||||
|
||||
static long owl_factor_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int owl_factor_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct owl_factor *factor = hw_to_owl_factor(hw);
|
||||
struct owl_factor_hw *factor_hw = &factor->factor_hw;
|
||||
|
||||
return owl_factor_helper_round_rate(&factor->common, factor_hw,
|
||||
rate, parent_rate);
|
||||
req->rate = owl_factor_helper_round_rate(&factor->common, factor_hw,
|
||||
req->rate, &req->best_parent_rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long owl_factor_helper_recalc_rate(struct owl_clk_common *common,
|
||||
@@ -214,7 +216,7 @@ static int owl_factor_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
}
|
||||
|
||||
const struct clk_ops owl_factor_ops = {
|
||||
.round_rate = owl_factor_round_rate,
|
||||
.determine_rate = owl_factor_determine_rate,
|
||||
.recalc_rate = owl_factor_recalc_rate,
|
||||
.set_rate = owl_factor_set_rate,
|
||||
};
|
||||
|
||||
@@ -56,8 +56,8 @@ static const struct clk_pll_table *_get_pll_table(
|
||||
return table;
|
||||
}
|
||||
|
||||
static long owl_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int owl_pll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct owl_pll *pll = hw_to_owl_pll(hw);
|
||||
struct owl_pll_hw *pll_hw = &pll->pll_hw;
|
||||
@@ -65,17 +65,24 @@ static long owl_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
u32 mul;
|
||||
|
||||
if (pll_hw->table) {
|
||||
clkt = _get_pll_table(pll_hw->table, rate);
|
||||
return clkt->rate;
|
||||
clkt = _get_pll_table(pll_hw->table, req->rate);
|
||||
req->rate = clkt->rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fixed frequency */
|
||||
if (pll_hw->width == 0)
|
||||
return pll_hw->bfreq;
|
||||
if (pll_hw->width == 0) {
|
||||
req->rate = pll_hw->bfreq;
|
||||
|
||||
mul = owl_pll_calculate_mul(pll_hw, rate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pll_hw->bfreq * mul;
|
||||
mul = owl_pll_calculate_mul(pll_hw, req->rate);
|
||||
|
||||
req->rate = pll_hw->bfreq * mul;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long owl_pll_recalc_rate(struct clk_hw *hw,
|
||||
@@ -188,7 +195,7 @@ const struct clk_ops owl_pll_ops = {
|
||||
.enable = owl_pll_enable,
|
||||
.disable = owl_pll_disable,
|
||||
.is_enabled = owl_pll_is_enabled,
|
||||
.round_rate = owl_pll_round_rate,
|
||||
.determine_rate = owl_pll_determine_rate,
|
||||
.recalc_rate = owl_pll_recalc_rate,
|
||||
.set_rate = owl_pll_set_rate,
|
||||
};
|
||||
|
||||
@@ -270,8 +270,8 @@ static int clk_audio_pll_frac_determine_rate(struct clk_hw *hw,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long clk_audio_pll_pad_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int clk_audio_pll_pad_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_hw *pclk = clk_hw_get_parent(hw);
|
||||
long best_rate = -EINVAL;
|
||||
@@ -283,7 +283,7 @@ static long clk_audio_pll_pad_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
int best_diff = -1;
|
||||
|
||||
pr_debug("A PLL/PAD: %s, rate = %lu (parent_rate = %lu)\n", __func__,
|
||||
rate, *parent_rate);
|
||||
req->rate, req->best_parent_rate);
|
||||
|
||||
/*
|
||||
* Rate divisor is actually made of two different divisors, multiplied
|
||||
@@ -304,12 +304,12 @@ static long clk_audio_pll_pad_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
continue;
|
||||
|
||||
best_parent_rate = clk_hw_round_rate(pclk,
|
||||
rate * tmp_qd * div);
|
||||
req->rate * tmp_qd * div);
|
||||
tmp_rate = best_parent_rate / (div * tmp_qd);
|
||||
tmp_diff = abs(rate - tmp_rate);
|
||||
tmp_diff = abs(req->rate - tmp_rate);
|
||||
|
||||
if (best_diff < 0 || best_diff > tmp_diff) {
|
||||
*parent_rate = best_parent_rate;
|
||||
req->best_parent_rate = best_parent_rate;
|
||||
best_rate = tmp_rate;
|
||||
best_diff = tmp_diff;
|
||||
}
|
||||
@@ -318,11 +318,13 @@ static long clk_audio_pll_pad_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
pr_debug("A PLL/PAD: %s, best_rate = %ld, best_parent_rate = %lu\n",
|
||||
__func__, best_rate, best_parent_rate);
|
||||
|
||||
return best_rate;
|
||||
req->rate = best_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long clk_audio_pll_pmc_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int clk_audio_pll_pmc_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_hw *pclk = clk_hw_get_parent(hw);
|
||||
long best_rate = -EINVAL;
|
||||
@@ -333,20 +335,20 @@ static long clk_audio_pll_pmc_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
int best_diff = -1;
|
||||
|
||||
pr_debug("A PLL/PMC: %s, rate = %lu (parent_rate = %lu)\n", __func__,
|
||||
rate, *parent_rate);
|
||||
req->rate, req->best_parent_rate);
|
||||
|
||||
if (!rate)
|
||||
if (!req->rate)
|
||||
return 0;
|
||||
|
||||
best_parent_rate = clk_round_rate(pclk->clk, 1);
|
||||
div = max(best_parent_rate / rate, 1UL);
|
||||
div = max(best_parent_rate / req->rate, 1UL);
|
||||
for (; div <= AUDIO_PLL_QDPMC_MAX; div++) {
|
||||
best_parent_rate = clk_round_rate(pclk->clk, rate * div);
|
||||
best_parent_rate = clk_round_rate(pclk->clk, req->rate * div);
|
||||
tmp_rate = best_parent_rate / div;
|
||||
tmp_diff = abs(rate - tmp_rate);
|
||||
tmp_diff = abs(req->rate - tmp_rate);
|
||||
|
||||
if (best_diff < 0 || best_diff > tmp_diff) {
|
||||
*parent_rate = best_parent_rate;
|
||||
req->best_parent_rate = best_parent_rate;
|
||||
best_rate = tmp_rate;
|
||||
best_diff = tmp_diff;
|
||||
tmp_qd = div;
|
||||
@@ -356,9 +358,11 @@ static long clk_audio_pll_pmc_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
}
|
||||
|
||||
pr_debug("A PLL/PMC: %s, best_rate = %ld, best_parent_rate = %lu (qd = %d)\n",
|
||||
__func__, best_rate, *parent_rate, tmp_qd - 1);
|
||||
__func__, best_rate, req->best_parent_rate, tmp_qd - 1);
|
||||
|
||||
return best_rate;
|
||||
req->rate = best_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_audio_pll_frac_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -436,7 +440,7 @@ static const struct clk_ops audio_pll_pad_ops = {
|
||||
.enable = clk_audio_pll_pad_enable,
|
||||
.disable = clk_audio_pll_pad_disable,
|
||||
.recalc_rate = clk_audio_pll_pad_recalc_rate,
|
||||
.round_rate = clk_audio_pll_pad_round_rate,
|
||||
.determine_rate = clk_audio_pll_pad_determine_rate,
|
||||
.set_rate = clk_audio_pll_pad_set_rate,
|
||||
};
|
||||
|
||||
@@ -444,7 +448,7 @@ static const struct clk_ops audio_pll_pmc_ops = {
|
||||
.enable = clk_audio_pll_pmc_enable,
|
||||
.disable = clk_audio_pll_pmc_disable,
|
||||
.recalc_rate = clk_audio_pll_pmc_recalc_rate,
|
||||
.round_rate = clk_audio_pll_pmc_round_rate,
|
||||
.determine_rate = clk_audio_pll_pmc_determine_rate,
|
||||
.set_rate = clk_audio_pll_pmc_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -40,21 +40,32 @@ static unsigned long clk_sama5d4_h32mx_recalc_rate(struct clk_hw *hw,
|
||||
return parent_rate;
|
||||
}
|
||||
|
||||
static long clk_sama5d4_h32mx_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int clk_sama5d4_h32mx_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
unsigned long div;
|
||||
|
||||
if (rate > *parent_rate)
|
||||
return *parent_rate;
|
||||
div = *parent_rate / 2;
|
||||
if (rate < div)
|
||||
return div;
|
||||
if (req->rate > req->best_parent_rate) {
|
||||
req->rate = req->best_parent_rate;
|
||||
|
||||
if (rate - div < *parent_rate - rate)
|
||||
return div;
|
||||
return 0;
|
||||
}
|
||||
div = req->best_parent_rate / 2;
|
||||
if (req->rate < div) {
|
||||
req->rate = div;
|
||||
|
||||
return *parent_rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (req->rate - div < req->best_parent_rate - req->rate) {
|
||||
req->rate = div;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
req->rate = req->best_parent_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_sama5d4_h32mx_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -77,7 +88,7 @@ static int clk_sama5d4_h32mx_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops h32mx_ops = {
|
||||
.recalc_rate = clk_sama5d4_h32mx_recalc_rate,
|
||||
.round_rate = clk_sama5d4_h32mx_round_rate,
|
||||
.determine_rate = clk_sama5d4_h32mx_determine_rate,
|
||||
.set_rate = clk_sama5d4_h32mx_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -580,6 +580,9 @@ clk_sama7g5_master_recalc_rate(struct clk_hw *hw,
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
|
||||
if (master->div == MASTER_PRES_MAX)
|
||||
return DIV_ROUND_CLOSEST_ULL(parent_rate, 3);
|
||||
|
||||
return DIV_ROUND_CLOSEST_ULL(parent_rate, (1 << master->div));
|
||||
}
|
||||
|
||||
|
||||
@@ -279,8 +279,11 @@ static int clk_sam9x5_peripheral_determine_rate(struct clk_hw *hw,
|
||||
long best_diff = LONG_MIN;
|
||||
u32 shift;
|
||||
|
||||
if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max)
|
||||
return parent_rate;
|
||||
if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) {
|
||||
req->rate = parent_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Fist step: check the available dividers. */
|
||||
for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
|
||||
@@ -332,50 +335,57 @@ end:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long clk_sam9x5_peripheral_round_rate(struct clk_hw *hw,
|
||||
unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int clk_sam9x5_peripheral_no_parent_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
int shift = 0;
|
||||
unsigned long best_rate;
|
||||
unsigned long best_diff;
|
||||
unsigned long cur_rate = *parent_rate;
|
||||
unsigned long cur_rate = req->best_parent_rate;
|
||||
unsigned long cur_diff;
|
||||
struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
|
||||
|
||||
if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max)
|
||||
return *parent_rate;
|
||||
if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) {
|
||||
req->rate = req->best_parent_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (periph->range.max) {
|
||||
for (; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
|
||||
cur_rate = *parent_rate >> shift;
|
||||
cur_rate = req->best_parent_rate >> shift;
|
||||
if (cur_rate <= periph->range.max)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rate >= cur_rate)
|
||||
return cur_rate;
|
||||
if (req->rate >= cur_rate) {
|
||||
req->rate = cur_rate;
|
||||
|
||||
best_diff = cur_rate - rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
best_diff = cur_rate - req->rate;
|
||||
best_rate = cur_rate;
|
||||
for (; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
|
||||
cur_rate = *parent_rate >> shift;
|
||||
if (cur_rate < rate)
|
||||
cur_diff = rate - cur_rate;
|
||||
cur_rate = req->best_parent_rate >> shift;
|
||||
if (cur_rate < req->rate)
|
||||
cur_diff = req->rate - cur_rate;
|
||||
else
|
||||
cur_diff = cur_rate - rate;
|
||||
cur_diff = cur_rate - req->rate;
|
||||
|
||||
if (cur_diff < best_diff) {
|
||||
best_diff = cur_diff;
|
||||
best_rate = cur_rate;
|
||||
}
|
||||
|
||||
if (!best_diff || cur_rate < rate)
|
||||
if (!best_diff || cur_rate < req->rate)
|
||||
break;
|
||||
}
|
||||
|
||||
return best_rate;
|
||||
req->rate = best_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_sam9x5_peripheral_set_rate(struct clk_hw *hw,
|
||||
@@ -427,7 +437,7 @@ static const struct clk_ops sam9x5_peripheral_ops = {
|
||||
.disable = clk_sam9x5_peripheral_disable,
|
||||
.is_enabled = clk_sam9x5_peripheral_is_enabled,
|
||||
.recalc_rate = clk_sam9x5_peripheral_recalc_rate,
|
||||
.round_rate = clk_sam9x5_peripheral_round_rate,
|
||||
.determine_rate = clk_sam9x5_peripheral_no_parent_determine_rate,
|
||||
.set_rate = clk_sam9x5_peripheral_set_rate,
|
||||
.save_context = clk_sam9x5_peripheral_save_context,
|
||||
.restore_context = clk_sam9x5_peripheral_restore_context,
|
||||
|
||||
@@ -231,13 +231,15 @@ static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate,
|
||||
return bestrate;
|
||||
}
|
||||
|
||||
static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int clk_pll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_pll *pll = to_clk_pll(hw);
|
||||
|
||||
return clk_pll_get_best_div_mul(pll, rate, *parent_rate,
|
||||
NULL, NULL, NULL);
|
||||
req->rate = clk_pll_get_best_div_mul(pll, req->rate, req->best_parent_rate,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -302,7 +304,7 @@ static const struct clk_ops pll_ops = {
|
||||
.unprepare = clk_pll_unprepare,
|
||||
.is_prepared = clk_pll_is_prepared,
|
||||
.recalc_rate = clk_pll_recalc_rate,
|
||||
.round_rate = clk_pll_round_rate,
|
||||
.determine_rate = clk_pll_determine_rate,
|
||||
.set_rate = clk_pll_set_rate,
|
||||
.save_context = clk_pll_save_context,
|
||||
.restore_context = clk_pll_restore_context,
|
||||
|
||||
@@ -33,21 +33,33 @@ static unsigned long clk_plldiv_recalc_rate(struct clk_hw *hw,
|
||||
return parent_rate;
|
||||
}
|
||||
|
||||
static long clk_plldiv_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int clk_plldiv_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
unsigned long div;
|
||||
|
||||
if (rate > *parent_rate)
|
||||
return *parent_rate;
|
||||
div = *parent_rate / 2;
|
||||
if (rate < div)
|
||||
return div;
|
||||
if (req->rate > req->best_parent_rate) {
|
||||
req->rate = req->best_parent_rate;
|
||||
|
||||
if (rate - div < *parent_rate - rate)
|
||||
return div;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return *parent_rate;
|
||||
div = req->best_parent_rate / 2;
|
||||
if (req->rate < div) {
|
||||
req->rate = div;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (req->rate - div < req->best_parent_rate - req->rate) {
|
||||
req->rate = div;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
req->rate = req->best_parent_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_plldiv_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -66,7 +78,7 @@ static int clk_plldiv_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops plldiv_ops = {
|
||||
.recalc_rate = clk_plldiv_recalc_rate,
|
||||
.round_rate = clk_plldiv_round_rate,
|
||||
.determine_rate = clk_plldiv_determine_rate,
|
||||
.set_rate = clk_plldiv_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -93,8 +93,8 @@ static int sam9x60_frac_pll_set(struct sam9x60_pll_core *core)
|
||||
|
||||
spin_lock_irqsave(core->lock, flags);
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_ID_MSK, core->id);
|
||||
regmap_write_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_ID_MSK, core->id);
|
||||
regmap_read(regmap, AT91_PMC_PLL_CTRL1, &val);
|
||||
cmul = (val & core->layout->mul_mask) >> core->layout->mul_shift;
|
||||
cfrac = (val & core->layout->frac_mask) >> core->layout->frac_shift;
|
||||
@@ -103,11 +103,8 @@ static int sam9x60_frac_pll_set(struct sam9x60_pll_core *core)
|
||||
(cmul == frac->mul && cfrac == frac->frac))
|
||||
goto unlock;
|
||||
|
||||
/* Recommended value for PMC_PLL_ACR */
|
||||
if (core->characteristics->upll)
|
||||
val = AT91_PMC_PLL_ACR_DEFAULT_UPLL;
|
||||
else
|
||||
val = AT91_PMC_PLL_ACR_DEFAULT_PLLA;
|
||||
/* Load recommended value for PMC_PLL_ACR */
|
||||
val = core->characteristics->acr;
|
||||
regmap_write(regmap, AT91_PMC_PLL_ACR, val);
|
||||
|
||||
regmap_write(regmap, AT91_PMC_PLL_CTRL1,
|
||||
@@ -128,17 +125,17 @@ static int sam9x60_frac_pll_set(struct sam9x60_pll_core *core)
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | core->id);
|
||||
regmap_write_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | core->id);
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,
|
||||
AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL,
|
||||
AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL);
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | core->id);
|
||||
regmap_write_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | core->id);
|
||||
|
||||
while (!sam9x60_pll_ready(regmap, core->id))
|
||||
cpu_relax();
|
||||
@@ -164,8 +161,8 @@ static void sam9x60_frac_pll_unprepare(struct clk_hw *hw)
|
||||
|
||||
spin_lock_irqsave(core->lock, flags);
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_ID_MSK, core->id);
|
||||
regmap_write_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_ID_MSK, core->id);
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0, AT91_PMC_PLL_CTRL0_ENPLL, 0);
|
||||
|
||||
@@ -173,9 +170,9 @@ static void sam9x60_frac_pll_unprepare(struct clk_hw *hw)
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_ACR,
|
||||
AT91_PMC_PLL_ACR_UTMIBG | AT91_PMC_PLL_ACR_UTMIVR, 0);
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | core->id);
|
||||
regmap_write_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | core->id);
|
||||
|
||||
spin_unlock_irqrestore(core->lock, flags);
|
||||
}
|
||||
@@ -230,12 +227,16 @@ static long sam9x60_frac_pll_compute_mul_frac(struct sam9x60_pll_core *core,
|
||||
return tmprate;
|
||||
}
|
||||
|
||||
static long sam9x60_frac_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int sam9x60_frac_pll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
|
||||
|
||||
return sam9x60_frac_pll_compute_mul_frac(core, rate, *parent_rate, false);
|
||||
req->rate = sam9x60_frac_pll_compute_mul_frac(core, req->rate,
|
||||
req->best_parent_rate,
|
||||
false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sam9x60_frac_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -262,8 +263,8 @@ static int sam9x60_frac_pll_set_rate_chg(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
spin_lock_irqsave(core->lock, irqflags);
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
core->id);
|
||||
regmap_write_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
core->id);
|
||||
regmap_read(regmap, AT91_PMC_PLL_CTRL1, &val);
|
||||
cmul = (val & core->layout->mul_mask) >> core->layout->mul_shift;
|
||||
cfrac = (val & core->layout->frac_mask) >> core->layout->frac_shift;
|
||||
@@ -275,18 +276,18 @@ static int sam9x60_frac_pll_set_rate_chg(struct clk_hw *hw, unsigned long rate,
|
||||
(frac->mul << core->layout->mul_shift) |
|
||||
(frac->frac << core->layout->frac_shift));
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | core->id);
|
||||
regmap_write_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | core->id);
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,
|
||||
AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL,
|
||||
AT91_PMC_PLL_CTRL0_ENLOCK |
|
||||
AT91_PMC_PLL_CTRL0_ENPLL);
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | core->id);
|
||||
regmap_write_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | core->id);
|
||||
|
||||
while (!sam9x60_pll_ready(regmap, core->id))
|
||||
cpu_relax();
|
||||
@@ -321,7 +322,7 @@ static const struct clk_ops sam9x60_frac_pll_ops = {
|
||||
.unprepare = sam9x60_frac_pll_unprepare,
|
||||
.is_prepared = sam9x60_frac_pll_is_prepared,
|
||||
.recalc_rate = sam9x60_frac_pll_recalc_rate,
|
||||
.round_rate = sam9x60_frac_pll_round_rate,
|
||||
.determine_rate = sam9x60_frac_pll_determine_rate,
|
||||
.set_rate = sam9x60_frac_pll_set_rate,
|
||||
.save_context = sam9x60_frac_pll_save_context,
|
||||
.restore_context = sam9x60_frac_pll_restore_context,
|
||||
@@ -332,13 +333,16 @@ static const struct clk_ops sam9x60_frac_pll_ops_chg = {
|
||||
.unprepare = sam9x60_frac_pll_unprepare,
|
||||
.is_prepared = sam9x60_frac_pll_is_prepared,
|
||||
.recalc_rate = sam9x60_frac_pll_recalc_rate,
|
||||
.round_rate = sam9x60_frac_pll_round_rate,
|
||||
.determine_rate = sam9x60_frac_pll_determine_rate,
|
||||
.set_rate = sam9x60_frac_pll_set_rate_chg,
|
||||
.save_context = sam9x60_frac_pll_save_context,
|
||||
.restore_context = sam9x60_frac_pll_restore_context,
|
||||
};
|
||||
|
||||
/* This function should be called with spinlock acquired. */
|
||||
/* This function should be called with spinlock acquired.
|
||||
* Warning: this function must be called only if the same PLL ID was set in
|
||||
* PLL_UPDT register previously.
|
||||
*/
|
||||
static void sam9x60_div_pll_set_div(struct sam9x60_pll_core *core, u32 div,
|
||||
bool enable)
|
||||
{
|
||||
@@ -350,9 +354,9 @@ static void sam9x60_div_pll_set_div(struct sam9x60_pll_core *core, u32 div,
|
||||
core->layout->div_mask | ena_msk,
|
||||
(div << core->layout->div_shift) | ena_val);
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | core->id);
|
||||
regmap_write_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | core->id);
|
||||
|
||||
while (!sam9x60_pll_ready(regmap, core->id))
|
||||
cpu_relax();
|
||||
@@ -366,8 +370,8 @@ static int sam9x60_div_pll_set(struct sam9x60_pll_core *core)
|
||||
unsigned int val, cdiv;
|
||||
|
||||
spin_lock_irqsave(core->lock, flags);
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_ID_MSK, core->id);
|
||||
regmap_write_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_ID_MSK, core->id);
|
||||
regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);
|
||||
cdiv = (val & core->layout->div_mask) >> core->layout->div_shift;
|
||||
|
||||
@@ -398,15 +402,15 @@ static void sam9x60_div_pll_unprepare(struct clk_hw *hw)
|
||||
|
||||
spin_lock_irqsave(core->lock, flags);
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_ID_MSK, core->id);
|
||||
regmap_write_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_ID_MSK, core->id);
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,
|
||||
core->layout->endiv_mask, 0);
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | core->id);
|
||||
regmap_write_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
AT91_PMC_PLL_UPDT_UPDATE | core->id);
|
||||
|
||||
spin_unlock_irqrestore(core->lock, flags);
|
||||
}
|
||||
@@ -487,12 +491,15 @@ static long sam9x60_div_pll_compute_div(struct sam9x60_pll_core *core,
|
||||
return best_rate;
|
||||
}
|
||||
|
||||
static long sam9x60_div_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int sam9x60_div_pll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
|
||||
|
||||
return sam9x60_div_pll_compute_div(core, parent_rate, rate);
|
||||
req->rate = sam9x60_div_pll_compute_div(core, &req->best_parent_rate,
|
||||
req->rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sam9x60_div_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -518,8 +525,8 @@ static int sam9x60_div_pll_set_rate_chg(struct clk_hw *hw, unsigned long rate,
|
||||
div->div = DIV_ROUND_CLOSEST(parent_rate, rate) - 1;
|
||||
|
||||
spin_lock_irqsave(core->lock, irqflags);
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
core->id);
|
||||
regmap_write_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
core->id);
|
||||
regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);
|
||||
cdiv = (val & core->layout->div_mask) >> core->layout->div_shift;
|
||||
|
||||
@@ -574,8 +581,8 @@ static int sam9x60_div_pll_notifier_fn(struct notifier_block *notifier,
|
||||
div->div = div->safe_div;
|
||||
|
||||
spin_lock_irqsave(core.lock, irqflags);
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
core.id);
|
||||
regmap_write_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
|
||||
core.id);
|
||||
regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);
|
||||
cdiv = (val & core.layout->div_mask) >> core.layout->div_shift;
|
||||
|
||||
@@ -601,7 +608,7 @@ static const struct clk_ops sam9x60_div_pll_ops = {
|
||||
.unprepare = sam9x60_div_pll_unprepare,
|
||||
.is_prepared = sam9x60_div_pll_is_prepared,
|
||||
.recalc_rate = sam9x60_div_pll_recalc_rate,
|
||||
.round_rate = sam9x60_div_pll_round_rate,
|
||||
.determine_rate = sam9x60_div_pll_determine_rate,
|
||||
.set_rate = sam9x60_div_pll_set_rate,
|
||||
.save_context = sam9x60_div_pll_save_context,
|
||||
.restore_context = sam9x60_div_pll_restore_context,
|
||||
@@ -612,7 +619,7 @@ static const struct clk_ops sam9x60_div_pll_ops_chg = {
|
||||
.unprepare = sam9x60_div_pll_unprepare,
|
||||
.is_prepared = sam9x60_div_pll_is_prepared,
|
||||
.recalc_rate = sam9x60_div_pll_recalc_rate,
|
||||
.round_rate = sam9x60_div_pll_round_rate,
|
||||
.determine_rate = sam9x60_div_pll_determine_rate,
|
||||
.set_rate = sam9x60_div_pll_set_rate_chg,
|
||||
.save_context = sam9x60_div_pll_save_context,
|
||||
.restore_context = sam9x60_div_pll_restore_context,
|
||||
@@ -623,7 +630,7 @@ static const struct clk_ops sam9x60_fixed_div_pll_ops = {
|
||||
.unprepare = sam9x60_div_pll_unprepare,
|
||||
.is_prepared = sam9x60_div_pll_is_prepared,
|
||||
.recalc_rate = sam9x60_fixed_div_pll_recalc_rate,
|
||||
.round_rate = sam9x60_div_pll_round_rate,
|
||||
.determine_rate = sam9x60_div_pll_determine_rate,
|
||||
.save_context = sam9x60_div_pll_save_context,
|
||||
.restore_context = sam9x60_div_pll_restore_context,
|
||||
};
|
||||
|
||||
@@ -319,8 +319,8 @@ static unsigned long at91rm9200_clk_usb_recalc_rate(struct clk_hw *hw,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int at91rm9200_clk_usb_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
|
||||
struct clk_hw *parent = clk_hw_get_parent(hw);
|
||||
@@ -336,25 +336,27 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
if (!usb->divisors[i])
|
||||
continue;
|
||||
|
||||
tmp_parent_rate = rate * usb->divisors[i];
|
||||
tmp_parent_rate = req->rate * usb->divisors[i];
|
||||
tmp_parent_rate = clk_hw_round_rate(parent, tmp_parent_rate);
|
||||
tmprate = DIV_ROUND_CLOSEST(tmp_parent_rate, usb->divisors[i]);
|
||||
if (tmprate < rate)
|
||||
tmpdiff = rate - tmprate;
|
||||
if (tmprate < req->rate)
|
||||
tmpdiff = req->rate - tmprate;
|
||||
else
|
||||
tmpdiff = tmprate - rate;
|
||||
tmpdiff = tmprate - req->rate;
|
||||
|
||||
if (bestdiff < 0 || bestdiff > tmpdiff) {
|
||||
bestrate = tmprate;
|
||||
bestdiff = tmpdiff;
|
||||
*parent_rate = tmp_parent_rate;
|
||||
req->best_parent_rate = tmp_parent_rate;
|
||||
}
|
||||
|
||||
if (!bestdiff)
|
||||
break;
|
||||
}
|
||||
|
||||
return bestrate;
|
||||
req->rate = bestrate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -384,7 +386,7 @@ static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops at91rm9200_usb_ops = {
|
||||
.recalc_rate = at91rm9200_clk_usb_recalc_rate,
|
||||
.round_rate = at91rm9200_clk_usb_round_rate,
|
||||
.determine_rate = at91rm9200_clk_usb_determine_rate,
|
||||
.set_rate = at91rm9200_clk_usb_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ struct clk_pll_characteristics {
|
||||
u16 *icpll;
|
||||
u8 *out;
|
||||
u8 upll : 1;
|
||||
u32 acr;
|
||||
};
|
||||
|
||||
struct clk_programmable_layout {
|
||||
|
||||
@@ -36,6 +36,7 @@ static const struct clk_pll_characteristics plla_characteristics = {
|
||||
.num_output = ARRAY_SIZE(plla_outputs),
|
||||
.output = plla_outputs,
|
||||
.core_output = core_outputs,
|
||||
.acr = UL(0x00020010),
|
||||
};
|
||||
|
||||
static const struct clk_range upll_outputs[] = {
|
||||
@@ -48,6 +49,7 @@ static const struct clk_pll_characteristics upll_characteristics = {
|
||||
.output = upll_outputs,
|
||||
.core_output = core_outputs,
|
||||
.upll = true,
|
||||
.acr = UL(0x12023010), /* fIN = [18 MHz, 32 MHz]*/
|
||||
};
|
||||
|
||||
static const struct clk_pll_layout pll_frac_layout = {
|
||||
|
||||
@@ -107,6 +107,7 @@ static const struct clk_pll_characteristics plla_characteristics = {
|
||||
.num_output = ARRAY_SIZE(plla_outputs),
|
||||
.output = plla_outputs,
|
||||
.core_output = plla_core_outputs,
|
||||
.acr = UL(0x00020010), /* Old ACR_DEFAULT_PLLA value */
|
||||
};
|
||||
|
||||
static const struct clk_pll_characteristics upll_characteristics = {
|
||||
@@ -115,6 +116,7 @@ static const struct clk_pll_characteristics upll_characteristics = {
|
||||
.output = upll_outputs,
|
||||
.core_output = upll_core_outputs,
|
||||
.upll = true,
|
||||
.acr = UL(0x12023010), /* fIN=[20 MHz, 32 MHz] */
|
||||
};
|
||||
|
||||
static const struct clk_pll_characteristics lvdspll_characteristics = {
|
||||
@@ -122,6 +124,7 @@ static const struct clk_pll_characteristics lvdspll_characteristics = {
|
||||
.num_output = ARRAY_SIZE(lvdspll_outputs),
|
||||
.output = lvdspll_outputs,
|
||||
.core_output = lvdspll_core_outputs,
|
||||
.acr = UL(0x12023010), /* fIN=[20 MHz, 32 MHz] */
|
||||
};
|
||||
|
||||
static const struct clk_pll_characteristics audiopll_characteristics = {
|
||||
@@ -129,6 +132,7 @@ static const struct clk_pll_characteristics audiopll_characteristics = {
|
||||
.num_output = ARRAY_SIZE(audiopll_outputs),
|
||||
.output = audiopll_outputs,
|
||||
.core_output = audiopll_core_outputs,
|
||||
.acr = UL(0x12023010), /* fIN=[20 MHz, 32 MHz] */
|
||||
};
|
||||
|
||||
static const struct clk_pll_characteristics plladiv2_characteristics = {
|
||||
@@ -136,6 +140,7 @@ static const struct clk_pll_characteristics plladiv2_characteristics = {
|
||||
.num_output = ARRAY_SIZE(plladiv2_outputs),
|
||||
.output = plladiv2_outputs,
|
||||
.core_output = plladiv2_core_outputs,
|
||||
.acr = UL(0x00020010), /* Old ACR_DEFAULT_PLLA value */
|
||||
};
|
||||
|
||||
/* Layout for fractional PLL ID PLLA. */
|
||||
@@ -403,6 +408,7 @@ static const struct {
|
||||
{ .n = "pioD_clk", .id = 44, },
|
||||
{ .n = "tcb1_clk", .id = 45, },
|
||||
{ .n = "dbgu_clk", .id = 47, },
|
||||
{ .n = "pmecc_clk", .id = 48, },
|
||||
/*
|
||||
* mpddr_clk feeds DDR controller and is enabled by bootloader thus we
|
||||
* need to keep it enabled in case there is no Linux consumer for it.
|
||||
|
||||
@@ -138,6 +138,7 @@ static const struct clk_pll_characteristics cpu_pll_characteristics = {
|
||||
.num_output = ARRAY_SIZE(cpu_pll_outputs),
|
||||
.output = cpu_pll_outputs,
|
||||
.core_output = core_outputs,
|
||||
.acr = UL(0x00070010),
|
||||
};
|
||||
|
||||
/* PLL characteristics. */
|
||||
@@ -146,6 +147,7 @@ static const struct clk_pll_characteristics pll_characteristics = {
|
||||
.num_output = ARRAY_SIZE(pll_outputs),
|
||||
.output = pll_outputs,
|
||||
.core_output = core_outputs,
|
||||
.acr = UL(0x00070010),
|
||||
};
|
||||
|
||||
static const struct clk_pll_characteristics lvdspll_characteristics = {
|
||||
@@ -153,6 +155,7 @@ static const struct clk_pll_characteristics lvdspll_characteristics = {
|
||||
.num_output = ARRAY_SIZE(lvdspll_outputs),
|
||||
.output = lvdspll_outputs,
|
||||
.core_output = lvdspll_core_outputs,
|
||||
.acr = UL(0x00070010),
|
||||
};
|
||||
|
||||
static const struct clk_pll_characteristics upll_characteristics = {
|
||||
@@ -160,6 +163,7 @@ static const struct clk_pll_characteristics upll_characteristics = {
|
||||
.num_output = ARRAY_SIZE(upll_outputs),
|
||||
.output = upll_outputs,
|
||||
.core_output = upll_core_outputs,
|
||||
.acr = UL(0x12020010),
|
||||
.upll = true,
|
||||
};
|
||||
|
||||
|
||||
@@ -113,6 +113,7 @@ static const struct clk_pll_characteristics cpu_pll_characteristics = {
|
||||
.num_output = ARRAY_SIZE(cpu_pll_outputs),
|
||||
.output = cpu_pll_outputs,
|
||||
.core_output = core_outputs,
|
||||
.acr = UL(0x00070010),
|
||||
};
|
||||
|
||||
/* PLL characteristics. */
|
||||
@@ -121,6 +122,7 @@ static const struct clk_pll_characteristics pll_characteristics = {
|
||||
.num_output = ARRAY_SIZE(pll_outputs),
|
||||
.output = pll_outputs,
|
||||
.core_output = core_outputs,
|
||||
.acr = UL(0x00070010),
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -108,21 +108,21 @@ static unsigned long i2s_pll_recalc_rate(struct clk_hw *hw,
|
||||
return ((parent_rate / idiv) * fbdiv) / odiv;
|
||||
}
|
||||
|
||||
static long i2s_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static int i2s_pll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct i2s_pll_clk *clk = to_i2s_pll_clk(hw);
|
||||
const struct i2s_pll_cfg *pll_cfg = i2s_pll_get_cfg(*prate);
|
||||
const struct i2s_pll_cfg *pll_cfg = i2s_pll_get_cfg(req->best_parent_rate);
|
||||
int i;
|
||||
|
||||
if (!pll_cfg) {
|
||||
dev_err(clk->dev, "invalid parent rate=%ld\n", *prate);
|
||||
dev_err(clk->dev, "invalid parent rate=%ld\n", req->best_parent_rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; pll_cfg[i].rate != 0; i++)
|
||||
if (pll_cfg[i].rate == rate)
|
||||
return rate;
|
||||
if (pll_cfg[i].rate == req->rate)
|
||||
return 0;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -156,7 +156,7 @@ static int i2s_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops i2s_pll_ops = {
|
||||
.recalc_rate = i2s_pll_recalc_rate,
|
||||
.round_rate = i2s_pll_round_rate,
|
||||
.determine_rate = i2s_pll_determine_rate,
|
||||
.set_rate = i2s_pll_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -149,8 +149,8 @@ static unsigned long axs10x_pll_recalc_rate(struct clk_hw *hw,
|
||||
return rate;
|
||||
}
|
||||
|
||||
static long axs10x_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static int axs10x_pll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
int i;
|
||||
long best_rate;
|
||||
@@ -163,11 +163,13 @@ static long axs10x_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
best_rate = pll_cfg[0].rate;
|
||||
|
||||
for (i = 1; pll_cfg[i].rate != 0; i++) {
|
||||
if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate))
|
||||
if (abs(req->rate - pll_cfg[i].rate) < abs(req->rate - best_rate))
|
||||
best_rate = pll_cfg[i].rate;
|
||||
}
|
||||
|
||||
return best_rate;
|
||||
req->rate = best_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int axs10x_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -208,7 +210,7 @@ static int axs10x_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops axs10x_pll_ops = {
|
||||
.recalc_rate = axs10x_pll_recalc_rate,
|
||||
.round_rate = axs10x_pll_round_rate,
|
||||
.determine_rate = axs10x_pll_determine_rate,
|
||||
.set_rate = axs10x_pll_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -228,15 +228,18 @@ static inline unsigned long ccu_div_var_calc_divider(unsigned long rate,
|
||||
CCU_DIV_CLKDIV_MAX(mask));
|
||||
}
|
||||
|
||||
static long ccu_div_var_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int ccu_div_var_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct ccu_div *div = to_ccu_div(hw);
|
||||
unsigned long divider;
|
||||
|
||||
divider = ccu_div_var_calc_divider(rate, *parent_rate, div->mask);
|
||||
divider = ccu_div_var_calc_divider(req->rate, req->best_parent_rate,
|
||||
div->mask);
|
||||
|
||||
return ccu_div_calc_freq(*parent_rate, divider);
|
||||
req->rate = ccu_div_calc_freq(req->best_parent_rate, divider);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -308,12 +311,14 @@ static unsigned long ccu_div_fixed_recalc_rate(struct clk_hw *hw,
|
||||
return ccu_div_calc_freq(parent_rate, div->divider);
|
||||
}
|
||||
|
||||
static long ccu_div_fixed_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int ccu_div_fixed_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct ccu_div *div = to_ccu_div(hw);
|
||||
|
||||
return ccu_div_calc_freq(*parent_rate, div->divider);
|
||||
req->rate = ccu_div_calc_freq(req->best_parent_rate, div->divider);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ccu_div_fixed_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -534,14 +539,14 @@ static const struct clk_ops ccu_div_var_gate_to_set_ops = {
|
||||
.disable = ccu_div_gate_disable,
|
||||
.is_enabled = ccu_div_gate_is_enabled,
|
||||
.recalc_rate = ccu_div_var_recalc_rate,
|
||||
.round_rate = ccu_div_var_round_rate,
|
||||
.determine_rate = ccu_div_var_determine_rate,
|
||||
.set_rate = ccu_div_var_set_rate_fast,
|
||||
.debug_init = ccu_div_var_debug_init
|
||||
};
|
||||
|
||||
static const struct clk_ops ccu_div_var_nogate_ops = {
|
||||
.recalc_rate = ccu_div_var_recalc_rate,
|
||||
.round_rate = ccu_div_var_round_rate,
|
||||
.determine_rate = ccu_div_var_determine_rate,
|
||||
.set_rate = ccu_div_var_set_rate_slow,
|
||||
.debug_init = ccu_div_var_debug_init
|
||||
};
|
||||
@@ -551,7 +556,7 @@ static const struct clk_ops ccu_div_gate_ops = {
|
||||
.disable = ccu_div_gate_disable,
|
||||
.is_enabled = ccu_div_gate_is_enabled,
|
||||
.recalc_rate = ccu_div_fixed_recalc_rate,
|
||||
.round_rate = ccu_div_fixed_round_rate,
|
||||
.determine_rate = ccu_div_fixed_determine_rate,
|
||||
.set_rate = ccu_div_fixed_set_rate,
|
||||
.debug_init = ccu_div_gate_debug_init
|
||||
};
|
||||
@@ -565,7 +570,7 @@ static const struct clk_ops ccu_div_buf_ops = {
|
||||
|
||||
static const struct clk_ops ccu_div_fixed_ops = {
|
||||
.recalc_rate = ccu_div_fixed_recalc_rate,
|
||||
.round_rate = ccu_div_fixed_round_rate,
|
||||
.determine_rate = ccu_div_fixed_determine_rate,
|
||||
.set_rate = ccu_div_fixed_set_rate,
|
||||
.debug_init = ccu_div_fixed_debug_init
|
||||
};
|
||||
|
||||
@@ -228,14 +228,16 @@ static void ccu_pll_calc_factors(unsigned long rate, unsigned long parent_rate,
|
||||
}
|
||||
}
|
||||
|
||||
static long ccu_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int ccu_pll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
unsigned long nr = 1, nf = 1, od = 1;
|
||||
|
||||
ccu_pll_calc_factors(rate, *parent_rate, &nr, &nf, &od);
|
||||
ccu_pll_calc_factors(req->rate, req->best_parent_rate, &nr, &nf, &od);
|
||||
|
||||
return ccu_pll_calc_freq(*parent_rate, nr, nf, od);
|
||||
req->rate = ccu_pll_calc_freq(req->best_parent_rate, nr, nf, od);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -481,7 +483,7 @@ static const struct clk_ops ccu_pll_gate_to_set_ops = {
|
||||
.disable = ccu_pll_disable,
|
||||
.is_enabled = ccu_pll_is_enabled,
|
||||
.recalc_rate = ccu_pll_recalc_rate,
|
||||
.round_rate = ccu_pll_round_rate,
|
||||
.determine_rate = ccu_pll_determine_rate,
|
||||
.set_rate = ccu_pll_set_rate_norst,
|
||||
.debug_init = ccu_pll_debug_init
|
||||
};
|
||||
@@ -491,7 +493,7 @@ static const struct clk_ops ccu_pll_straight_set_ops = {
|
||||
.disable = ccu_pll_disable,
|
||||
.is_enabled = ccu_pll_is_enabled,
|
||||
.recalc_rate = ccu_pll_recalc_rate,
|
||||
.round_rate = ccu_pll_round_rate,
|
||||
.determine_rate = ccu_pll_determine_rate,
|
||||
.set_rate = ccu_pll_set_rate_reset,
|
||||
.debug_init = ccu_pll_debug_init
|
||||
};
|
||||
|
||||
@@ -98,22 +98,27 @@ static unsigned long iproc_asiu_clk_recalc_rate(struct clk_hw *hw,
|
||||
return clk->rate;
|
||||
}
|
||||
|
||||
static long iproc_asiu_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int iproc_asiu_clk_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
unsigned int div;
|
||||
|
||||
if (rate == 0 || *parent_rate == 0)
|
||||
if (req->rate == 0 || req->best_parent_rate == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (rate == *parent_rate)
|
||||
return *parent_rate;
|
||||
if (req->rate == req->best_parent_rate)
|
||||
return 0;
|
||||
|
||||
div = DIV_ROUND_CLOSEST(*parent_rate, rate);
|
||||
if (div < 2)
|
||||
return *parent_rate;
|
||||
div = DIV_ROUND_CLOSEST(req->best_parent_rate, req->rate);
|
||||
if (div < 2) {
|
||||
req->rate = req->best_parent_rate;
|
||||
|
||||
return *parent_rate / div;
|
||||
return 0;
|
||||
}
|
||||
|
||||
req->rate = req->best_parent_rate / div;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iproc_asiu_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -168,7 +173,7 @@ static const struct clk_ops iproc_asiu_ops = {
|
||||
.enable = iproc_asiu_clk_enable,
|
||||
.disable = iproc_asiu_clk_disable,
|
||||
.recalc_rate = iproc_asiu_clk_recalc_rate,
|
||||
.round_rate = iproc_asiu_clk_round_rate,
|
||||
.determine_rate = iproc_asiu_clk_determine_rate,
|
||||
.set_rate = iproc_asiu_clk_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -68,6 +68,8 @@ struct raspberrypi_clk_variant {
|
||||
char *clkdev;
|
||||
unsigned long min_rate;
|
||||
bool minimize;
|
||||
bool maximize;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
static struct raspberrypi_clk_variant
|
||||
@@ -75,6 +77,7 @@ raspberrypi_clk_variants[RPI_FIRMWARE_NUM_CLK_ID] = {
|
||||
[RPI_FIRMWARE_ARM_CLK_ID] = {
|
||||
.export = true,
|
||||
.clkdev = "cpu0",
|
||||
.flags = CLK_IS_CRITICAL,
|
||||
},
|
||||
[RPI_FIRMWARE_CORE_CLK_ID] = {
|
||||
.export = true,
|
||||
@@ -90,6 +93,12 @@ raspberrypi_clk_variants[RPI_FIRMWARE_NUM_CLK_ID] = {
|
||||
* always use the minimum the drivers will let us.
|
||||
*/
|
||||
.minimize = true,
|
||||
|
||||
/*
|
||||
* It should never be disabled as it drives the bus for
|
||||
* everything else.
|
||||
*/
|
||||
.flags = CLK_IS_CRITICAL,
|
||||
},
|
||||
[RPI_FIRMWARE_M2MC_CLK_ID] = {
|
||||
.export = true,
|
||||
@@ -115,18 +124,29 @@ raspberrypi_clk_variants[RPI_FIRMWARE_NUM_CLK_ID] = {
|
||||
* drivers will let us.
|
||||
*/
|
||||
.minimize = true,
|
||||
|
||||
/*
|
||||
* As mentioned above, this clock is disabled during boot,
|
||||
* the firmware will skip the HSM initialization, resulting
|
||||
* in a bus lockup. Therefore, make sure it's enabled
|
||||
* during boot, but after it, it can be enabled/disabled
|
||||
* by the driver.
|
||||
*/
|
||||
.flags = CLK_IGNORE_UNUSED,
|
||||
},
|
||||
[RPI_FIRMWARE_V3D_CLK_ID] = {
|
||||
.export = true,
|
||||
.minimize = true,
|
||||
.maximize = true,
|
||||
},
|
||||
[RPI_FIRMWARE_PIXEL_CLK_ID] = {
|
||||
.export = true,
|
||||
.minimize = true,
|
||||
.flags = CLK_IS_CRITICAL,
|
||||
},
|
||||
[RPI_FIRMWARE_HEVC_CLK_ID] = {
|
||||
.export = true,
|
||||
.minimize = true,
|
||||
.flags = CLK_IS_CRITICAL,
|
||||
},
|
||||
[RPI_FIRMWARE_ISP_CLK_ID] = {
|
||||
.export = true,
|
||||
@@ -135,6 +155,7 @@ raspberrypi_clk_variants[RPI_FIRMWARE_NUM_CLK_ID] = {
|
||||
[RPI_FIRMWARE_PIXEL_BVB_CLK_ID] = {
|
||||
.export = true,
|
||||
.minimize = true,
|
||||
.flags = CLK_IS_CRITICAL,
|
||||
},
|
||||
[RPI_FIRMWARE_VEC_CLK_ID] = {
|
||||
.export = true,
|
||||
@@ -194,8 +215,11 @@ static int raspberrypi_fw_is_prepared(struct clk_hw *hw)
|
||||
|
||||
ret = raspberrypi_clock_property(rpi->firmware, data,
|
||||
RPI_FIRMWARE_GET_CLOCK_STATE, &val);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
dev_err_ratelimited(rpi->dev, "Failed to get %s state: %d\n",
|
||||
clk_hw_get_name(hw), ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return !!(val & RPI_FIRMWARE_STATE_ENABLE_BIT);
|
||||
}
|
||||
@@ -211,8 +235,11 @@ static unsigned long raspberrypi_fw_get_rate(struct clk_hw *hw,
|
||||
|
||||
ret = raspberrypi_clock_property(rpi->firmware, data,
|
||||
RPI_FIRMWARE_GET_CLOCK_RATE, &val);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
dev_err_ratelimited(rpi->dev, "Failed to get %s frequency: %d\n",
|
||||
clk_hw_get_name(hw), ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
@@ -259,7 +286,41 @@ static int raspberrypi_fw_dumb_determine_rate(struct clk_hw *hw,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raspberrypi_fw_prepare(struct clk_hw *hw)
|
||||
{
|
||||
const struct raspberrypi_clk_data *data = clk_hw_to_data(hw);
|
||||
struct raspberrypi_clk *rpi = data->rpi;
|
||||
u32 state = RPI_FIRMWARE_STATE_ENABLE_BIT;
|
||||
int ret;
|
||||
|
||||
ret = raspberrypi_clock_property(rpi->firmware, data,
|
||||
RPI_FIRMWARE_SET_CLOCK_STATE, &state);
|
||||
if (ret)
|
||||
dev_err_ratelimited(rpi->dev,
|
||||
"Failed to set clock %s state to on: %d\n",
|
||||
clk_hw_get_name(hw), ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void raspberrypi_fw_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
const struct raspberrypi_clk_data *data = clk_hw_to_data(hw);
|
||||
struct raspberrypi_clk *rpi = data->rpi;
|
||||
u32 state = 0;
|
||||
int ret;
|
||||
|
||||
ret = raspberrypi_clock_property(rpi->firmware, data,
|
||||
RPI_FIRMWARE_SET_CLOCK_STATE, &state);
|
||||
if (ret)
|
||||
dev_err_ratelimited(rpi->dev,
|
||||
"Failed to set clock %s state to off: %d\n",
|
||||
clk_hw_get_name(hw), ret);
|
||||
}
|
||||
|
||||
static const struct clk_ops raspberrypi_firmware_clk_ops = {
|
||||
.prepare = raspberrypi_fw_prepare,
|
||||
.unprepare = raspberrypi_fw_unprepare,
|
||||
.is_prepared = raspberrypi_fw_is_prepared,
|
||||
.recalc_rate = raspberrypi_fw_get_rate,
|
||||
.determine_rate = raspberrypi_fw_dumb_determine_rate,
|
||||
@@ -289,7 +350,7 @@ static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi,
|
||||
if (!init.name)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
init.ops = &raspberrypi_firmware_clk_ops;
|
||||
init.flags = CLK_GET_RATE_NOCACHE;
|
||||
init.flags = variant->flags | CLK_GET_RATE_NOCACHE;
|
||||
|
||||
data->hw.init = &init;
|
||||
|
||||
@@ -326,6 +387,9 @@ static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi,
|
||||
}
|
||||
}
|
||||
|
||||
if (variant->maximize)
|
||||
variant->min_rate = max_rate;
|
||||
|
||||
if (variant->min_rate) {
|
||||
unsigned long rate;
|
||||
|
||||
|
||||
@@ -212,13 +212,15 @@ static unsigned long applnco_recalc_rate(struct clk_hw *hw,
|
||||
((u64) div) * incbase + inc1);
|
||||
}
|
||||
|
||||
static long applnco_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int applnco_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
unsigned long lo = *parent_rate / (COARSE_DIV_OFFSET + LFSR_TBLSIZE) + 1;
|
||||
unsigned long hi = *parent_rate / COARSE_DIV_OFFSET;
|
||||
unsigned long lo = req->best_parent_rate / (COARSE_DIV_OFFSET + LFSR_TBLSIZE) + 1;
|
||||
unsigned long hi = req->best_parent_rate / COARSE_DIV_OFFSET;
|
||||
|
||||
return clamp(rate, lo, hi);
|
||||
req->rate = clamp(req->rate, lo, hi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applnco_enable(struct clk_hw *hw)
|
||||
@@ -246,7 +248,7 @@ static void applnco_disable(struct clk_hw *hw)
|
||||
static const struct clk_ops applnco_ops = {
|
||||
.set_rate = applnco_set_rate,
|
||||
.recalc_rate = applnco_recalc_rate,
|
||||
.round_rate = applnco_round_rate,
|
||||
.determine_rate = applnco_determine_rate,
|
||||
.enable = applnco_enable,
|
||||
.disable = applnco_disable,
|
||||
.is_enabled = applnco_is_enabled,
|
||||
|
||||
@@ -540,7 +540,7 @@ static int axi_clkgen_setup_limits(struct axi_clkgen *axi_clkgen,
|
||||
default:
|
||||
return dev_err_probe(dev, -ENODEV, "Unknown speed grade %d\n",
|
||||
speed_grade);
|
||||
};
|
||||
}
|
||||
|
||||
/* Overwrite vco limits for ultrascale+ */
|
||||
if (tech == ADI_AXI_FPGA_TECH_ULTRASCALE_PLUS) {
|
||||
|
||||
@@ -529,7 +529,6 @@ static const struct regmap_config axmclk_regmap_config = {
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.max_register = 0x1fffc,
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id axmclk_match_table[] = {
|
||||
|
||||
@@ -608,8 +608,8 @@ static unsigned long bm1880_clk_div_recalc_rate(struct clk_hw *hw,
|
||||
return rate;
|
||||
}
|
||||
|
||||
static long bm1880_clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static int bm1880_clk_div_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw);
|
||||
struct bm1880_div_clock *div = &div_hw->div;
|
||||
@@ -621,13 +621,18 @@ static long bm1880_clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
val = readl(reg_addr) >> div->shift;
|
||||
val &= clk_div_mask(div->width);
|
||||
|
||||
return divider_ro_round_rate(hw, rate, prate, div->table,
|
||||
div->width, div->flags,
|
||||
val);
|
||||
req->rate = divider_ro_round_rate(hw, req->rate,
|
||||
&req->best_parent_rate,
|
||||
div->table,
|
||||
div->width, div->flags, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return divider_round_rate(hw, rate, prate, div->table,
|
||||
div->width, div->flags);
|
||||
req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate,
|
||||
div->table, div->width, div->flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bm1880_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -665,7 +670,7 @@ static int bm1880_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops bm1880_clk_div_ops = {
|
||||
.recalc_rate = bm1880_clk_div_recalc_rate,
|
||||
.round_rate = bm1880_clk_div_round_rate,
|
||||
.determine_rate = bm1880_clk_div_determine_rate,
|
||||
.set_rate = bm1880_clk_div_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -183,8 +183,8 @@ static unsigned long cdce706_pll_recalc_rate(struct clk_hw *hw,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long cdce706_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int cdce706_pll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct cdce706_hw_data *hwd = to_hw_data(hw);
|
||||
unsigned long mul, div;
|
||||
@@ -192,9 +192,9 @@ static long cdce706_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
dev_dbg(&hwd->dev_data->client->dev,
|
||||
"%s, rate: %lu, parent_rate: %lu\n",
|
||||
__func__, rate, *parent_rate);
|
||||
__func__, req->rate, req->best_parent_rate);
|
||||
|
||||
rational_best_approximation(rate, *parent_rate,
|
||||
rational_best_approximation(req->rate, req->best_parent_rate,
|
||||
CDCE706_PLL_N_MAX, CDCE706_PLL_M_MAX,
|
||||
&mul, &div);
|
||||
hwd->mul = mul;
|
||||
@@ -204,9 +204,11 @@ static long cdce706_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
"%s, pll: %d, mul: %lu, div: %lu\n",
|
||||
__func__, hwd->idx, mul, div);
|
||||
|
||||
res = (u64)*parent_rate * hwd->mul;
|
||||
res = (u64)req->best_parent_rate * hwd->mul;
|
||||
do_div(res, hwd->div);
|
||||
return res;
|
||||
req->rate = res;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdce706_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -251,7 +253,7 @@ static int cdce706_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops cdce706_pll_ops = {
|
||||
.recalc_rate = cdce706_pll_recalc_rate,
|
||||
.round_rate = cdce706_pll_round_rate,
|
||||
.determine_rate = cdce706_pll_determine_rate,
|
||||
.set_rate = cdce706_pll_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -128,13 +128,15 @@ static void cdce925_pll_find_rate(unsigned long rate,
|
||||
}
|
||||
}
|
||||
|
||||
static long cdce925_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int cdce925_pll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
u16 n, m;
|
||||
|
||||
cdce925_pll_find_rate(rate, *parent_rate, &n, &m);
|
||||
return (long)cdce925_pll_calculate_rate(*parent_rate, n, m);
|
||||
cdce925_pll_find_rate(req->rate, req->best_parent_rate, &n, &m);
|
||||
req->rate = (long)cdce925_pll_calculate_rate(req->best_parent_rate, n, m);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdce925_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -266,7 +268,7 @@ static const struct clk_ops cdce925_pll_ops = {
|
||||
.prepare = cdce925_pll_prepare,
|
||||
.unprepare = cdce925_pll_unprepare,
|
||||
.recalc_rate = cdce925_pll_recalc_rate,
|
||||
.round_rate = cdce925_pll_round_rate,
|
||||
.determine_rate = cdce925_pll_determine_rate,
|
||||
.set_rate = cdce925_pll_set_rate,
|
||||
};
|
||||
|
||||
@@ -420,20 +422,23 @@ static unsigned long cdce925_clk_best_parent_rate(
|
||||
return rate * pdiv_best;
|
||||
}
|
||||
|
||||
static long cdce925_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int cdce925_clk_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
unsigned long l_parent_rate = *parent_rate;
|
||||
u16 divider = cdce925_calc_divider(rate, l_parent_rate);
|
||||
unsigned long l_parent_rate = req->best_parent_rate;
|
||||
u16 divider = cdce925_calc_divider(req->rate, l_parent_rate);
|
||||
|
||||
if (l_parent_rate / divider != rate) {
|
||||
l_parent_rate = cdce925_clk_best_parent_rate(hw, rate);
|
||||
divider = cdce925_calc_divider(rate, l_parent_rate);
|
||||
*parent_rate = l_parent_rate;
|
||||
if (l_parent_rate / divider != req->rate) {
|
||||
l_parent_rate = cdce925_clk_best_parent_rate(hw, req->rate);
|
||||
divider = cdce925_calc_divider(req->rate, l_parent_rate);
|
||||
req->best_parent_rate = l_parent_rate;
|
||||
}
|
||||
|
||||
if (divider)
|
||||
return (long)(l_parent_rate / divider);
|
||||
req->rate = (long)(l_parent_rate / divider);
|
||||
else
|
||||
req->rate = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -451,7 +456,7 @@ static const struct clk_ops cdce925_clk_ops = {
|
||||
.prepare = cdce925_clk_prepare,
|
||||
.unprepare = cdce925_clk_unprepare,
|
||||
.recalc_rate = cdce925_clk_recalc_rate,
|
||||
.round_rate = cdce925_clk_round_rate,
|
||||
.determine_rate = cdce925_clk_determine_rate,
|
||||
.set_rate = cdce925_clk_set_rate,
|
||||
};
|
||||
|
||||
@@ -473,14 +478,17 @@ static u16 cdce925_y1_calc_divider(unsigned long rate,
|
||||
return (u16)divider;
|
||||
}
|
||||
|
||||
static long cdce925_clk_y1_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int cdce925_clk_y1_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
unsigned long l_parent_rate = *parent_rate;
|
||||
u16 divider = cdce925_y1_calc_divider(rate, l_parent_rate);
|
||||
unsigned long l_parent_rate = req->best_parent_rate;
|
||||
u16 divider = cdce925_y1_calc_divider(req->rate, l_parent_rate);
|
||||
|
||||
if (divider)
|
||||
return (long)(l_parent_rate / divider);
|
||||
req->rate = (long)(l_parent_rate / divider);
|
||||
else
|
||||
req->rate = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -498,7 +506,7 @@ static const struct clk_ops cdce925_clk_y1_ops = {
|
||||
.prepare = cdce925_clk_prepare,
|
||||
.unprepare = cdce925_clk_unprepare,
|
||||
.recalc_rate = cdce925_clk_recalc_rate,
|
||||
.round_rate = cdce925_clk_y1_round_rate,
|
||||
.determine_rate = cdce925_clk_y1_determine_rate,
|
||||
.set_rate = cdce925_clk_y1_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -305,15 +305,19 @@ static unsigned long cs2000_recalc_rate(struct clk_hw *hw,
|
||||
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)
|
||||
static int cs2000_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct cs2000_priv *priv = hw_to_priv(hw);
|
||||
u32 ratio;
|
||||
|
||||
ratio = cs2000_rate_to_ratio(*parent_rate, rate, priv->lf_ratio);
|
||||
ratio = cs2000_rate_to_ratio(req->best_parent_rate, req->rate,
|
||||
priv->lf_ratio);
|
||||
|
||||
return cs2000_ratio_to_rate(ratio, *parent_rate, priv->lf_ratio);
|
||||
req->rate = cs2000_ratio_to_rate(ratio, req->best_parent_rate,
|
||||
priv->lf_ratio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs2000_select_ratio_mode(struct cs2000_priv *priv,
|
||||
@@ -430,7 +434,7 @@ static u8 cs2000_get_parent(struct clk_hw *hw)
|
||||
static const struct clk_ops cs2000_ops = {
|
||||
.get_parent = cs2000_get_parent,
|
||||
.recalc_rate = cs2000_recalc_rate,
|
||||
.round_rate = cs2000_round_rate,
|
||||
.determine_rate = cs2000_determine_rate,
|
||||
.set_rate = cs2000_set_rate,
|
||||
.prepare = cs2000_enable,
|
||||
.unprepare = cs2000_disable,
|
||||
|
||||
@@ -431,27 +431,6 @@ long divider_ro_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(divider_ro_round_rate_parent);
|
||||
|
||||
static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct clk_divider *divider = to_clk_divider(hw);
|
||||
|
||||
/* if read only, just return current value */
|
||||
if (divider->flags & CLK_DIVIDER_READ_ONLY) {
|
||||
u32 val;
|
||||
|
||||
val = clk_div_readl(divider) >> divider->shift;
|
||||
val &= clk_div_mask(divider->width);
|
||||
|
||||
return divider_ro_round_rate(hw, rate, prate, divider->table,
|
||||
divider->width, divider->flags,
|
||||
val);
|
||||
}
|
||||
|
||||
return divider_round_rate(hw, rate, prate, divider->table,
|
||||
divider->width, divider->flags);
|
||||
}
|
||||
|
||||
static int clk_divider_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
@@ -527,7 +506,6 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
const struct clk_ops clk_divider_ops = {
|
||||
.recalc_rate = clk_divider_recalc_rate,
|
||||
.round_rate = clk_divider_round_rate,
|
||||
.determine_rate = clk_divider_determine_rate,
|
||||
.set_rate = clk_divider_set_rate,
|
||||
};
|
||||
@@ -535,7 +513,6 @@ EXPORT_SYMBOL_GPL(clk_divider_ops);
|
||||
|
||||
const struct clk_ops clk_divider_ro_ops = {
|
||||
.recalc_rate = clk_divider_recalc_rate,
|
||||
.round_rate = clk_divider_round_rate,
|
||||
.determine_rate = clk_divider_determine_rate,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_divider_ro_ops);
|
||||
|
||||
@@ -389,23 +389,25 @@ static unsigned long ep93xx_div_recalc_rate(struct clk_hw *hw,
|
||||
return DIV_ROUND_CLOSEST(parent_rate, clk->div[index]);
|
||||
}
|
||||
|
||||
static long ep93xx_div_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int ep93xx_div_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct ep93xx_clk *clk = ep93xx_clk_from(hw);
|
||||
unsigned long best = 0, now;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < clk->num_div; i++) {
|
||||
if ((rate * clk->div[i]) == *parent_rate)
|
||||
return rate;
|
||||
if (req->rate * clk->div[i] == req->best_parent_rate)
|
||||
return 0;
|
||||
|
||||
now = DIV_ROUND_CLOSEST(*parent_rate, clk->div[i]);
|
||||
if (!best || is_best(rate, now, best))
|
||||
now = DIV_ROUND_CLOSEST(req->best_parent_rate, clk->div[i]);
|
||||
if (!best || is_best(req->rate, now, best))
|
||||
best = now;
|
||||
}
|
||||
|
||||
return best;
|
||||
req->rate = best;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ep93xx_div_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -437,7 +439,7 @@ static const struct clk_ops ep93xx_div_ops = {
|
||||
.disable = ep93xx_clk_disable,
|
||||
.is_enabled = ep93xx_clk_is_enabled,
|
||||
.recalc_rate = ep93xx_div_recalc_rate,
|
||||
.round_rate = ep93xx_div_round_rate,
|
||||
.determine_rate = ep93xx_div_determine_rate,
|
||||
.set_rate = ep93xx_div_set_rate,
|
||||
};
|
||||
|
||||
@@ -486,9 +488,10 @@ static const struct ep93xx_gate ep93xx_uarts[] = {
|
||||
static int ep93xx_uart_clock_init(struct ep93xx_clk_priv *priv)
|
||||
{
|
||||
struct clk_parent_data parent_data = { };
|
||||
unsigned int i, idx, ret, clk_uart_div;
|
||||
unsigned int i, idx, clk_uart_div;
|
||||
struct ep93xx_clk *clk;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
regmap_read(priv->map, EP93XX_SYSCON_PWRCNT, &val);
|
||||
if (val & EP93XX_SYSCON_PWRCNT_UARTBAUD)
|
||||
|
||||
@@ -30,19 +30,21 @@ static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
|
||||
return (unsigned long)rate;
|
||||
}
|
||||
|
||||
static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static int clk_factor_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
|
||||
|
||||
if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
|
||||
unsigned long best_parent;
|
||||
|
||||
best_parent = (rate / fix->mult) * fix->div;
|
||||
*prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
|
||||
best_parent = (req->rate / fix->mult) * fix->div;
|
||||
req->best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
|
||||
}
|
||||
|
||||
return (*prate / fix->div) * fix->mult;
|
||||
req->rate = (req->best_parent_rate / fix->div) * fix->mult;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_factor_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -50,7 +52,7 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
{
|
||||
/*
|
||||
* We must report success but we can do so unconditionally because
|
||||
* clk_factor_round_rate returns values that ensure this call is a
|
||||
* clk_factor_determine_rate returns values that ensure this call is a
|
||||
* nop.
|
||||
*/
|
||||
|
||||
@@ -69,7 +71,7 @@ static unsigned long clk_factor_recalc_accuracy(struct clk_hw *hw,
|
||||
}
|
||||
|
||||
const struct clk_ops clk_fixed_factor_ops = {
|
||||
.round_rate = clk_factor_round_rate,
|
||||
.determine_rate = clk_factor_determine_rate,
|
||||
.set_rate = clk_factor_set_rate,
|
||||
.recalc_rate = clk_factor_recalc_rate,
|
||||
.recalc_accuracy = clk_factor_recalc_accuracy,
|
||||
|
||||
@@ -151,25 +151,32 @@ void clk_fractional_divider_general_approximation(struct clk_hw *hw,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_fractional_divider_general_approximation);
|
||||
|
||||
static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int clk_fd_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_fractional_divider *fd = to_clk_fd(hw);
|
||||
unsigned long m, n;
|
||||
u64 ret;
|
||||
|
||||
if (!rate || (!clk_hw_can_set_rate_parent(hw) && rate >= *parent_rate))
|
||||
return *parent_rate;
|
||||
if (!req->rate || (!clk_hw_can_set_rate_parent(hw) && req->rate >= req->best_parent_rate)) {
|
||||
req->rate = req->best_parent_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fd->approximation)
|
||||
fd->approximation(hw, rate, parent_rate, &m, &n);
|
||||
fd->approximation(hw, req->rate, &req->best_parent_rate, &m, &n);
|
||||
else
|
||||
clk_fractional_divider_general_approximation(hw, rate, parent_rate, &m, &n);
|
||||
clk_fractional_divider_general_approximation(hw, req->rate,
|
||||
&req->best_parent_rate,
|
||||
&m, &n);
|
||||
|
||||
ret = (u64)*parent_rate * m;
|
||||
ret = (u64)req->best_parent_rate * m;
|
||||
do_div(ret, n);
|
||||
|
||||
return ret;
|
||||
req->rate = ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -250,7 +257,7 @@ static void clk_fd_debug_init(struct clk_hw *hw, struct dentry *dentry)
|
||||
|
||||
const struct clk_ops clk_fractional_divider_ops = {
|
||||
.recalc_rate = clk_fd_recalc_rate,
|
||||
.round_rate = clk_fd_round_rate,
|
||||
.determine_rate = clk_fd_determine_rate,
|
||||
.set_rate = clk_fd_set_rate,
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
.debug_init = clk_fd_debug_init,
|
||||
|
||||
@@ -126,13 +126,16 @@ static unsigned long gemini_pci_recalc_rate(struct clk_hw *hw,
|
||||
return 33000000;
|
||||
}
|
||||
|
||||
static long gemini_pci_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static int gemini_pci_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
/* We support 33 and 66 MHz */
|
||||
if (rate < 48000000)
|
||||
return 33000000;
|
||||
return 66000000;
|
||||
if (req->rate < 48000000)
|
||||
req->rate = 33000000;
|
||||
else
|
||||
req->rate = 66000000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gemini_pci_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -179,7 +182,7 @@ static int gemini_pci_is_enabled(struct clk_hw *hw)
|
||||
|
||||
static const struct clk_ops gemini_pci_clk_ops = {
|
||||
.recalc_rate = gemini_pci_recalc_rate,
|
||||
.round_rate = gemini_pci_round_rate,
|
||||
.determine_rate = gemini_pci_determine_rate,
|
||||
.set_rate = gemini_pci_set_rate,
|
||||
.enable = gemini_pci_enable,
|
||||
.disable = gemini_pci_disable,
|
||||
|
||||
@@ -130,15 +130,17 @@ static void clk_pll_calc(unsigned long rate, unsigned long ref_freq,
|
||||
*pdivf = divf;
|
||||
}
|
||||
|
||||
static long clk_pll_round_rate(struct clk_hw *hwclk, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int clk_pll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
u32 divq, divf;
|
||||
unsigned long ref_freq = *parent_rate;
|
||||
unsigned long ref_freq = req->best_parent_rate;
|
||||
|
||||
clk_pll_calc(rate, ref_freq, &divq, &divf);
|
||||
clk_pll_calc(req->rate, ref_freq, &divq, &divf);
|
||||
|
||||
return (ref_freq * (divf + 1)) / (1 << divq);
|
||||
req->rate = (ref_freq * (divf + 1)) / (1 << divq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
|
||||
@@ -185,7 +187,7 @@ static const struct clk_ops clk_pll_ops = {
|
||||
.enable = clk_pll_enable,
|
||||
.disable = clk_pll_disable,
|
||||
.recalc_rate = clk_pll_recalc_rate,
|
||||
.round_rate = clk_pll_round_rate,
|
||||
.determine_rate = clk_pll_determine_rate,
|
||||
.set_rate = clk_pll_set_rate,
|
||||
};
|
||||
|
||||
@@ -227,16 +229,18 @@ static unsigned long clk_periclk_recalc_rate(struct clk_hw *hwclk,
|
||||
return parent_rate / div;
|
||||
}
|
||||
|
||||
static long clk_periclk_round_rate(struct clk_hw *hwclk, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int clk_periclk_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
u32 div;
|
||||
|
||||
div = *parent_rate / rate;
|
||||
div = req->best_parent_rate / req->rate;
|
||||
div++;
|
||||
div &= ~0x1;
|
||||
|
||||
return *parent_rate / div;
|
||||
req->rate = req->best_parent_rate / div;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_periclk_set_rate(struct clk_hw *hwclk, unsigned long rate,
|
||||
@@ -255,7 +259,7 @@ static int clk_periclk_set_rate(struct clk_hw *hwclk, unsigned long rate,
|
||||
|
||||
static const struct clk_ops periclk_ops = {
|
||||
.recalc_rate = clk_periclk_recalc_rate,
|
||||
.round_rate = clk_periclk_round_rate,
|
||||
.determine_rate = clk_periclk_determine_rate,
|
||||
.set_rate = clk_periclk_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -197,8 +197,8 @@ static unsigned long hsdk_pll_recalc_rate(struct clk_hw *hw,
|
||||
return rate;
|
||||
}
|
||||
|
||||
static long hsdk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static int hsdk_pll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
int i;
|
||||
unsigned long best_rate;
|
||||
@@ -211,13 +211,15 @@ static long hsdk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
best_rate = pll_cfg[0].rate;
|
||||
|
||||
for (i = 1; pll_cfg[i].rate != 0; i++) {
|
||||
if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate))
|
||||
if (abs(req->rate - pll_cfg[i].rate) < abs(req->rate - best_rate))
|
||||
best_rate = pll_cfg[i].rate;
|
||||
}
|
||||
|
||||
dev_dbg(clk->dev, "chosen best rate: %lu\n", best_rate);
|
||||
|
||||
return best_rate;
|
||||
req->rate = best_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hsdk_pll_comm_update_rate(struct hsdk_pll_clk *clk,
|
||||
@@ -296,7 +298,7 @@ static int hsdk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops hsdk_pll_ops = {
|
||||
.recalc_rate = hsdk_pll_recalc_rate,
|
||||
.round_rate = hsdk_pll_round_rate,
|
||||
.determine_rate = hsdk_pll_determine_rate,
|
||||
.set_rate = hsdk_pll_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -491,28 +491,33 @@ static long lmk04832_calc_pll2_params(unsigned long prate, unsigned long rate,
|
||||
return DIV_ROUND_CLOSEST(prate * 2 * pll2_p * pll2_n, pll2_r);
|
||||
}
|
||||
|
||||
static long lmk04832_vco_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static int lmk04832_vco_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct lmk04832 *lmk = container_of(hw, struct lmk04832, vco);
|
||||
unsigned int n, p, r;
|
||||
long vco_rate;
|
||||
int ret;
|
||||
|
||||
ret = lmk04832_check_vco_ranges(lmk, rate);
|
||||
ret = lmk04832_check_vco_ranges(lmk, req->rate);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
vco_rate = lmk04832_calc_pll2_params(*prate, rate, &n, &p, &r);
|
||||
vco_rate = lmk04832_calc_pll2_params(req->best_parent_rate, req->rate,
|
||||
&n, &p, &r);
|
||||
if (vco_rate < 0) {
|
||||
dev_err(lmk->dev, "PLL2 parameters out of range\n");
|
||||
return vco_rate;
|
||||
req->rate = vco_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rate != vco_rate)
|
||||
if (req->rate != vco_rate)
|
||||
return -EINVAL;
|
||||
|
||||
return vco_rate;
|
||||
req->rate = vco_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lmk04832_vco_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -579,7 +584,7 @@ static const struct clk_ops lmk04832_vco_ops = {
|
||||
.prepare = lmk04832_vco_prepare,
|
||||
.unprepare = lmk04832_vco_unprepare,
|
||||
.recalc_rate = lmk04832_vco_recalc_rate,
|
||||
.round_rate = lmk04832_vco_round_rate,
|
||||
.determine_rate = lmk04832_vco_determine_rate,
|
||||
.set_rate = lmk04832_vco_set_rate,
|
||||
};
|
||||
|
||||
@@ -888,25 +893,27 @@ static unsigned long lmk04832_sclk_recalc_rate(struct clk_hw *hw,
|
||||
return DIV_ROUND_CLOSEST(prate, sysref_div);
|
||||
}
|
||||
|
||||
static long lmk04832_sclk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static int lmk04832_sclk_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct lmk04832 *lmk = container_of(hw, struct lmk04832, sclk);
|
||||
unsigned long sclk_rate;
|
||||
unsigned int sysref_div;
|
||||
|
||||
sysref_div = DIV_ROUND_CLOSEST(*prate, rate);
|
||||
sclk_rate = DIV_ROUND_CLOSEST(*prate, sysref_div);
|
||||
sysref_div = DIV_ROUND_CLOSEST(req->best_parent_rate, req->rate);
|
||||
sclk_rate = DIV_ROUND_CLOSEST(req->best_parent_rate, sysref_div);
|
||||
|
||||
if (sysref_div < 0x07 || sysref_div > 0x1fff) {
|
||||
dev_err(lmk->dev, "SYSREF divider out of range\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (rate != sclk_rate)
|
||||
if (req->rate != sclk_rate)
|
||||
return -EINVAL;
|
||||
|
||||
return sclk_rate;
|
||||
req->rate = sclk_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lmk04832_sclk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -945,7 +952,7 @@ static const struct clk_ops lmk04832_sclk_ops = {
|
||||
.prepare = lmk04832_sclk_prepare,
|
||||
.unprepare = lmk04832_sclk_unprepare,
|
||||
.recalc_rate = lmk04832_sclk_recalc_rate,
|
||||
.round_rate = lmk04832_sclk_round_rate,
|
||||
.determine_rate = lmk04832_sclk_determine_rate,
|
||||
.set_rate = lmk04832_sclk_set_rate,
|
||||
};
|
||||
|
||||
@@ -1069,26 +1076,28 @@ static unsigned long lmk04832_dclk_recalc_rate(struct clk_hw *hw,
|
||||
return rate;
|
||||
}
|
||||
|
||||
static long lmk04832_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static int lmk04832_dclk_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct lmk_dclk *dclk = container_of(hw, struct lmk_dclk, hw);
|
||||
struct lmk04832 *lmk = dclk->lmk;
|
||||
unsigned long dclk_rate;
|
||||
unsigned int dclk_div;
|
||||
|
||||
dclk_div = DIV_ROUND_CLOSEST(*prate, rate);
|
||||
dclk_rate = DIV_ROUND_CLOSEST(*prate, dclk_div);
|
||||
dclk_div = DIV_ROUND_CLOSEST(req->best_parent_rate, req->rate);
|
||||
dclk_rate = DIV_ROUND_CLOSEST(req->best_parent_rate, dclk_div);
|
||||
|
||||
if (dclk_div < 1 || dclk_div > 0x3ff) {
|
||||
dev_err(lmk->dev, "%s_div out of range\n", clk_hw_get_name(hw));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (rate != dclk_rate)
|
||||
if (req->rate != dclk_rate)
|
||||
return -EINVAL;
|
||||
|
||||
return dclk_rate;
|
||||
req->rate = dclk_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lmk04832_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -1158,7 +1167,7 @@ static const struct clk_ops lmk04832_dclk_ops = {
|
||||
.prepare = lmk04832_dclk_prepare,
|
||||
.unprepare = lmk04832_dclk_unprepare,
|
||||
.recalc_rate = lmk04832_dclk_recalc_rate,
|
||||
.round_rate = lmk04832_dclk_round_rate,
|
||||
.determine_rate = lmk04832_dclk_determine_rate,
|
||||
.set_rate = lmk04832_dclk_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -93,14 +93,16 @@ static unsigned long ls1x_divider_recalc_rate(struct clk_hw *hw,
|
||||
d->flags, d->width);
|
||||
}
|
||||
|
||||
static long ls1x_divider_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static int ls1x_divider_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct ls1x_clk *ls1x_clk = to_ls1x_clk(hw);
|
||||
const struct ls1x_clk_div_data *d = ls1x_clk->data;
|
||||
|
||||
return divider_round_rate(hw, rate, prate, d->table,
|
||||
d->width, d->flags);
|
||||
req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate,
|
||||
d->table, d->width, d->flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ls1x_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -146,7 +148,7 @@ static int ls1x_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops ls1x_clk_divider_ops = {
|
||||
.recalc_rate = ls1x_divider_recalc_rate,
|
||||
.round_rate = ls1x_divider_round_rate,
|
||||
.determine_rate = ls1x_divider_determine_rate,
|
||||
.set_rate = ls1x_divider_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -13,10 +13,6 @@
|
||||
#include <linux/io-64-nonatomic-lo-hi.h>
|
||||
#include <dt-bindings/clock/loongson,ls2k-clk.h>
|
||||
|
||||
static const struct clk_parent_data pdata[] = {
|
||||
{ .fw_name = "ref_100m", },
|
||||
};
|
||||
|
||||
enum loongson2_clk_type {
|
||||
CLK_TYPE_PLL,
|
||||
CLK_TYPE_SCALE,
|
||||
@@ -42,6 +38,7 @@ struct loongson2_clk_data {
|
||||
u8 div_width;
|
||||
u8 mult_shift;
|
||||
u8 mult_width;
|
||||
u8 bit_idx;
|
||||
};
|
||||
|
||||
struct loongson2_clk_board_info {
|
||||
@@ -50,6 +47,7 @@ struct loongson2_clk_board_info {
|
||||
const char *name;
|
||||
const char *parent_name;
|
||||
unsigned long fixed_rate;
|
||||
unsigned long flags;
|
||||
u8 reg_offset;
|
||||
u8 div_shift;
|
||||
u8 div_width;
|
||||
@@ -95,6 +93,19 @@ struct loongson2_clk_board_info {
|
||||
.div_width = _dwidth, \
|
||||
}
|
||||
|
||||
#define CLK_SCALE_MODE(_id, _name, _pname, _offset, \
|
||||
_dshift, _dwidth, _midx) \
|
||||
{ \
|
||||
.id = _id, \
|
||||
.type = CLK_TYPE_SCALE, \
|
||||
.name = _name, \
|
||||
.parent_name = _pname, \
|
||||
.reg_offset = _offset, \
|
||||
.div_shift = _dshift, \
|
||||
.div_width = _dwidth, \
|
||||
.bit_idx = _midx + 1, \
|
||||
}
|
||||
|
||||
#define CLK_GATE(_id, _name, _pname, _offset, _bidx) \
|
||||
{ \
|
||||
.id = _id, \
|
||||
@@ -105,6 +116,18 @@ struct loongson2_clk_board_info {
|
||||
.bit_idx = _bidx, \
|
||||
}
|
||||
|
||||
#define CLK_GATE_FLAGS(_id, _name, _pname, _offset, _bidx, \
|
||||
_flags) \
|
||||
{ \
|
||||
.id = _id, \
|
||||
.type = CLK_TYPE_GATE, \
|
||||
.name = _name, \
|
||||
.parent_name = _pname, \
|
||||
.reg_offset = _offset, \
|
||||
.bit_idx = _bidx, \
|
||||
.flags = _flags \
|
||||
}
|
||||
|
||||
#define CLK_FIXED(_id, _name, _pname, _rate) \
|
||||
{ \
|
||||
.id = _id, \
|
||||
@@ -114,6 +137,51 @@ struct loongson2_clk_board_info {
|
||||
.fixed_rate = _rate, \
|
||||
}
|
||||
|
||||
static const struct loongson2_clk_board_info ls2k0300_clks[] = {
|
||||
/* Reference Clock */
|
||||
CLK_PLL(LS2K0300_NODE_PLL, "pll_node", 0x00, 15, 9, 8, 7),
|
||||
CLK_PLL(LS2K0300_DDR_PLL, "pll_ddr", 0x08, 15, 9, 8, 7),
|
||||
CLK_PLL(LS2K0300_PIX_PLL, "pll_pix", 0x10, 15, 9, 8, 7),
|
||||
CLK_FIXED(LS2K0300_CLK_STABLE, "clk_stable", NULL, 100000000),
|
||||
CLK_FIXED(LS2K0300_CLK_THSENS, "clk_thsens", NULL, 10000000),
|
||||
/* Node PLL */
|
||||
CLK_DIV(LS2K0300_CLK_NODE_DIV, "clk_node_div", "pll_node", 0x00, 24, 7),
|
||||
CLK_DIV(LS2K0300_CLK_GMAC_DIV, "clk_gmac_div", "pll_node", 0x04, 0, 7),
|
||||
CLK_DIV(LS2K0300_CLK_I2S_DIV, "clk_i2s_div", "pll_node", 0x04, 8, 7),
|
||||
CLK_GATE(LS2K0300_CLK_NODE_PLL_GATE, "clk_node_pll_gate", "clk_node_div", 0x00, 0),
|
||||
CLK_GATE(LS2K0300_CLK_GMAC_GATE, "clk_gmac_gate", "clk_gmac_div", 0x00, 1),
|
||||
CLK_GATE(LS2K0300_CLK_I2S_GATE, "clk_i2s_gate", "clk_i2s_div", 0x00, 2),
|
||||
CLK_GATE_FLAGS(LS2K0300_CLK_NODE_GATE, "clk_node_gate", "clk_node_scale", 0x24, 0,
|
||||
CLK_IS_CRITICAL),
|
||||
CLK_SCALE_MODE(LS2K0300_CLK_NODE_SCALE, "clk_node_scale", "clk_node_pll_gate", 0x20, 0, 3,
|
||||
3),
|
||||
/* DDR PLL */
|
||||
CLK_DIV(LS2K0300_CLK_DDR_DIV, "clk_ddr_div", "pll_ddr", 0x08, 24, 7),
|
||||
CLK_DIV(LS2K0300_CLK_NET_DIV, "clk_net_div", "pll_ddr", 0x0c, 0, 7),
|
||||
CLK_DIV(LS2K0300_CLK_DEV_DIV, "clk_dev_div", "pll_ddr", 0x0c, 8, 7),
|
||||
CLK_GATE(LS2K0300_CLK_NET_GATE, "clk_net_gate", "clk_net_div", 0x08, 1),
|
||||
CLK_GATE(LS2K0300_CLK_DEV_GATE, "clk_dev_gate", "clk_dev_div", 0x08, 2),
|
||||
CLK_GATE_FLAGS(LS2K0300_CLK_DDR_GATE, "clk_ddr_gate", "clk_ddr_div", 0x08, 0,
|
||||
CLK_IS_CRITICAL),
|
||||
/* PIX PLL */
|
||||
CLK_DIV(LS2K0300_CLK_PIX_DIV, "clk_pix_div", "pll_pix", 0x10, 24, 7),
|
||||
CLK_DIV(LS2K0300_CLK_GMACBP_DIV, "clk_gmacbp_div", "pll_pix", 0x14, 0, 7),
|
||||
CLK_GATE(LS2K0300_CLK_PIX_PLL_GATE, "clk_pix_pll_gate", "clk_pix_div", 0x10, 0),
|
||||
CLK_GATE(LS2K0300_CLK_PIX_GATE, "clk_pix_gate", "clk_pix_scale", 0x24, 6),
|
||||
CLK_GATE(LS2K0300_CLK_GMACBP_GATE, "clk_gmacbp_gate", "clk_gmacbp_div", 0x10, 1),
|
||||
CLK_SCALE_MODE(LS2K0300_CLK_PIX_SCALE, "clk_pix_scale", "clk_pix_pll_gate", 0x20, 4, 3, 7),
|
||||
/* clk_dev_gate */
|
||||
CLK_DIV(LS2K0300_CLK_SDIO_SCALE, "clk_sdio_scale", "clk_dev_gate", 0x20, 24, 4),
|
||||
CLK_GATE(LS2K0300_CLK_USB_GATE, "clk_usb_gate", "clk_usb_scale", 0x24, 2),
|
||||
CLK_GATE(LS2K0300_CLK_SDIO_GATE, "clk_sdio_gate", "clk_sdio_scale", 0x24, 4),
|
||||
CLK_GATE(LS2K0300_CLK_APB_GATE, "clk_apb_gate", "clk_apb_scale", 0x24, 3),
|
||||
CLK_GATE_FLAGS(LS2K0300_CLK_BOOT_GATE, "clk_boot_gate", "clk_boot_scale", 0x24, 1,
|
||||
CLK_IS_CRITICAL),
|
||||
CLK_SCALE_MODE(LS2K0300_CLK_USB_SCALE, "clk_usb_scale", "clk_dev_gate", 0x20, 12, 3, 15),
|
||||
CLK_SCALE_MODE(LS2K0300_CLK_APB_SCALE, "clk_apb_scale", "clk_dev_gate", 0x20, 16, 3, 19),
|
||||
CLK_SCALE_MODE(LS2K0300_CLK_BOOT_SCALE, "clk_boot_scale", "clk_dev_gate", 0x20, 8, 3, 11),
|
||||
};
|
||||
|
||||
static const struct loongson2_clk_board_info ls2k0500_clks[] = {
|
||||
CLK_PLL(LOONGSON2_NODE_PLL, "pll_node", 0, 16, 8, 8, 6),
|
||||
CLK_PLL(LOONGSON2_DDR_PLL, "pll_ddr", 0x8, 16, 8, 8, 6),
|
||||
@@ -230,20 +298,26 @@ static const struct clk_ops loongson2_pll_recalc_ops = {
|
||||
static unsigned long loongson2_freqscale_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u64 val, mult;
|
||||
u64 val, scale;
|
||||
u32 mode = 0;
|
||||
struct loongson2_clk_data *clk = to_loongson2_clk(hw);
|
||||
|
||||
val = readq(clk->reg);
|
||||
mult = loongson2_rate_part(val, clk->div_shift, clk->div_width) + 1;
|
||||
scale = loongson2_rate_part(val, clk->div_shift, clk->div_width) + 1;
|
||||
|
||||
return div_u64((u64)parent_rate * mult, 8);
|
||||
if (clk->bit_idx)
|
||||
mode = val & BIT(clk->bit_idx - 1);
|
||||
|
||||
return mode == 0 ? div_u64((u64)parent_rate * scale, 8) :
|
||||
div_u64((u64)parent_rate, scale);
|
||||
}
|
||||
|
||||
static const struct clk_ops loongson2_freqscale_recalc_ops = {
|
||||
.recalc_rate = loongson2_freqscale_recalc_rate,
|
||||
};
|
||||
|
||||
static struct clk_hw *loongson2_clk_register(struct loongson2_clk_provider *clp,
|
||||
static struct clk_hw *loongson2_clk_register(const char *parent,
|
||||
struct loongson2_clk_provider *clp,
|
||||
const struct loongson2_clk_board_info *cld,
|
||||
const struct clk_ops *ops)
|
||||
{
|
||||
@@ -260,17 +334,14 @@ static struct clk_hw *loongson2_clk_register(struct loongson2_clk_provider *clp,
|
||||
init.ops = ops;
|
||||
init.flags = 0;
|
||||
init.num_parents = 1;
|
||||
|
||||
if (!cld->parent_name)
|
||||
init.parent_data = pdata;
|
||||
else
|
||||
init.parent_names = &cld->parent_name;
|
||||
init.parent_names = &parent;
|
||||
|
||||
clk->reg = clp->base + cld->reg_offset;
|
||||
clk->div_shift = cld->div_shift;
|
||||
clk->div_width = cld->div_width;
|
||||
clk->mult_shift = cld->mult_shift;
|
||||
clk->mult_width = cld->mult_width;
|
||||
clk->bit_idx = cld->bit_idx;
|
||||
clk->hw.init = &init;
|
||||
|
||||
hw = &clk->hw;
|
||||
@@ -288,11 +359,17 @@ static int loongson2_clk_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct loongson2_clk_provider *clp;
|
||||
const struct loongson2_clk_board_info *p, *data;
|
||||
const char *refclk_name, *parent_name;
|
||||
|
||||
data = device_get_match_data(dev);
|
||||
if (!data)
|
||||
return -EINVAL;
|
||||
|
||||
refclk_name = of_clk_get_parent_name(dev->of_node, 0);
|
||||
if (IS_ERR(refclk_name))
|
||||
return dev_err_probe(dev, PTR_ERR(refclk_name),
|
||||
"failed to get refclk name\n");
|
||||
|
||||
for (p = data; p->name; p++)
|
||||
clks_num = max(clks_num, p->id + 1);
|
||||
|
||||
@@ -314,32 +391,36 @@ static int loongson2_clk_probe(struct platform_device *pdev)
|
||||
|
||||
for (i = 0; i < clks_num; i++) {
|
||||
p = &data[i];
|
||||
parent_name = p->parent_name ? p->parent_name : refclk_name;
|
||||
|
||||
switch (p->type) {
|
||||
case CLK_TYPE_PLL:
|
||||
hw = loongson2_clk_register(clp, p,
|
||||
hw = loongson2_clk_register(parent_name, clp, p,
|
||||
&loongson2_pll_recalc_ops);
|
||||
break;
|
||||
case CLK_TYPE_SCALE:
|
||||
hw = loongson2_clk_register(clp, p,
|
||||
hw = loongson2_clk_register(parent_name, clp, p,
|
||||
&loongson2_freqscale_recalc_ops);
|
||||
break;
|
||||
case CLK_TYPE_DIVIDER:
|
||||
hw = devm_clk_hw_register_divider(dev, p->name,
|
||||
p->parent_name, 0,
|
||||
parent_name, 0,
|
||||
clp->base + p->reg_offset,
|
||||
p->div_shift, p->div_width,
|
||||
CLK_DIVIDER_ONE_BASED,
|
||||
CLK_DIVIDER_ONE_BASED |
|
||||
CLK_DIVIDER_ALLOW_ZERO,
|
||||
&clp->clk_lock);
|
||||
break;
|
||||
case CLK_TYPE_GATE:
|
||||
hw = devm_clk_hw_register_gate(dev, p->name, p->parent_name, 0,
|
||||
hw = devm_clk_hw_register_gate(dev, p->name, parent_name,
|
||||
p->flags,
|
||||
clp->base + p->reg_offset,
|
||||
p->bit_idx, 0,
|
||||
&clp->clk_lock);
|
||||
break;
|
||||
case CLK_TYPE_FIXED:
|
||||
hw = devm_clk_hw_register_fixed_rate_parent_data(dev, p->name, pdata,
|
||||
0, p->fixed_rate);
|
||||
hw = devm_clk_hw_register_fixed_rate(dev, p->name, parent_name,
|
||||
0, p->fixed_rate);
|
||||
break;
|
||||
default:
|
||||
return dev_err_probe(dev, -EINVAL, "Invalid clk type\n");
|
||||
@@ -357,6 +438,7 @@ static int loongson2_clk_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct of_device_id loongson2_clk_match_table[] = {
|
||||
{ .compatible = "loongson,ls2k0300-clk", .data = &ls2k0300_clks },
|
||||
{ .compatible = "loongson,ls2k0500-clk", .data = &ls2k0500_clks },
|
||||
{ .compatible = "loongson,ls2k-clk", .data = &ls2k1000_clks },
|
||||
{ .compatible = "loongson,ls2k2000-clk", .data = &ls2k2000_clks },
|
||||
|
||||
@@ -159,29 +159,32 @@ static unsigned long max9485_clkout_recalc_rate(struct clk_hw *hw,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long max9485_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int max9485_clkout_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
const struct max9485_rate *curr, *prev = NULL;
|
||||
|
||||
for (curr = max9485_rates; curr->out != 0; curr++) {
|
||||
/* Exact matches */
|
||||
if (curr->out == rate)
|
||||
return rate;
|
||||
if (curr->out == req->rate)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Find the first entry that has a frequency higher than the
|
||||
* requested one.
|
||||
*/
|
||||
if (curr->out > rate) {
|
||||
if (curr->out > req->rate) {
|
||||
unsigned int mid;
|
||||
|
||||
/*
|
||||
* If this is the first entry, clamp the value to the
|
||||
* lowest possible frequency.
|
||||
*/
|
||||
if (!prev)
|
||||
return curr->out;
|
||||
if (!prev) {
|
||||
req->rate = curr->out;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise, determine whether the previous entry or
|
||||
@@ -189,14 +192,18 @@ static long max9485_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
*/
|
||||
mid = prev->out + ((curr->out - prev->out) / 2);
|
||||
|
||||
return (mid > rate) ? prev->out : curr->out;
|
||||
req->rate = mid > req->rate ? prev->out : curr->out;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
prev = curr;
|
||||
}
|
||||
|
||||
/* If the last entry was still too high, clamp the value */
|
||||
return prev->out;
|
||||
req->rate = prev->out;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct max9485_clk {
|
||||
@@ -221,7 +228,7 @@ static const struct max9485_clk max9485_clks[MAX9485_NUM_CLKS] = {
|
||||
.parent_index = -1,
|
||||
.ops = {
|
||||
.set_rate = max9485_clkout_set_rate,
|
||||
.round_rate = max9485_clkout_round_rate,
|
||||
.determine_rate = max9485_clkout_determine_rate,
|
||||
.recalc_rate = max9485_clkout_recalc_rate,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -386,8 +386,8 @@ static unsigned long m10v_clk_divider_recalc_rate(struct clk_hw *hw,
|
||||
divider->flags, divider->width);
|
||||
}
|
||||
|
||||
static long m10v_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static int m10v_clk_divider_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct m10v_clk_divider *divider = to_m10v_div(hw);
|
||||
|
||||
@@ -398,13 +398,19 @@ static long m10v_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
val = readl(divider->reg) >> divider->shift;
|
||||
val &= clk_div_mask(divider->width);
|
||||
|
||||
return divider_ro_round_rate(hw, rate, prate, divider->table,
|
||||
divider->width, divider->flags,
|
||||
val);
|
||||
req->rate = divider_ro_round_rate(hw, req->rate,
|
||||
&req->best_parent_rate,
|
||||
divider->table,
|
||||
divider->width,
|
||||
divider->flags, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return divider_round_rate(hw, rate, prate, divider->table,
|
||||
divider->width, divider->flags);
|
||||
req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate,
|
||||
divider->table, divider->width, divider->flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int m10v_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -450,7 +456,7 @@ static int m10v_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops m10v_clk_divider_ops = {
|
||||
.recalc_rate = m10v_clk_divider_recalc_rate,
|
||||
.round_rate = m10v_clk_divider_round_rate,
|
||||
.determine_rate = m10v_clk_divider_determine_rate,
|
||||
.set_rate = m10v_clk_divider_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -112,14 +112,16 @@ static unsigned long __bestmult(struct clk_hw *hw, unsigned long rate,
|
||||
return bestmult;
|
||||
}
|
||||
|
||||
static long clk_multiplier_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int clk_multiplier_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_multiplier *mult = to_clk_multiplier(hw);
|
||||
unsigned long factor = __bestmult(hw, rate, parent_rate,
|
||||
unsigned long factor = __bestmult(hw, req->rate, &req->best_parent_rate,
|
||||
mult->width, mult->flags);
|
||||
|
||||
return *parent_rate * factor;
|
||||
req->rate = req->best_parent_rate * factor;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_multiplier_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -150,7 +152,7 @@ static int clk_multiplier_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
const struct clk_ops clk_multiplier_ops = {
|
||||
.recalc_rate = clk_multiplier_recalc_rate,
|
||||
.round_rate = clk_multiplier_round_rate,
|
||||
.determine_rate = clk_multiplier_determine_rate,
|
||||
.set_rate = clk_multiplier_set_rate,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_multiplier_ops);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/samsung/s2mpg10.h>
|
||||
#include <linux/mfd/samsung/s2mps11.h>
|
||||
#include <linux/mfd/samsung/s2mps13.h>
|
||||
#include <linux/mfd/samsung/s2mps14.h>
|
||||
@@ -140,6 +141,9 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
|
||||
clk_data->num = S2MPS11_CLKS_NUM;
|
||||
|
||||
switch (hwid) {
|
||||
case S2MPG10:
|
||||
s2mps11_reg = S2MPG10_PMIC_RTCBUF;
|
||||
break;
|
||||
case S2MPS11X:
|
||||
s2mps11_reg = S2MPS11_REG_RTC_CTRL;
|
||||
break;
|
||||
@@ -221,6 +225,7 @@ static void s2mps11_clk_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct platform_device_id s2mps11_clk_id[] = {
|
||||
{ "s2mpg10-clk", S2MPG10},
|
||||
{ "s2mps11-clk", S2MPS11X},
|
||||
{ "s2mps13-clk", S2MPS13X},
|
||||
{ "s2mps14-clk", S2MPS14X},
|
||||
@@ -241,6 +246,9 @@ MODULE_DEVICE_TABLE(platform, s2mps11_clk_id);
|
||||
*/
|
||||
static const struct of_device_id s2mps11_dt_match[] __used = {
|
||||
{
|
||||
.compatible = "samsung,s2mpg10-clk",
|
||||
.data = (void *)S2MPG10,
|
||||
}, {
|
||||
.compatible = "samsung,s2mps11-clk",
|
||||
.data = (void *)S2MPS11X,
|
||||
}, {
|
||||
|
||||
@@ -54,8 +54,8 @@ static unsigned long scmi_clk_recalc_rate(struct clk_hw *hw,
|
||||
return rate;
|
||||
}
|
||||
|
||||
static long scmi_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int scmi_clk_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
u64 fmin, fmax, ftmp;
|
||||
struct scmi_clk *clk = to_scmi_clk(hw);
|
||||
@@ -67,20 +67,27 @@ static long scmi_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
* running at then.
|
||||
*/
|
||||
if (clk->info->rate_discrete)
|
||||
return rate;
|
||||
return 0;
|
||||
|
||||
fmin = clk->info->range.min_rate;
|
||||
fmax = clk->info->range.max_rate;
|
||||
if (rate <= fmin)
|
||||
return fmin;
|
||||
else if (rate >= fmax)
|
||||
return fmax;
|
||||
if (req->rate <= fmin) {
|
||||
req->rate = fmin;
|
||||
|
||||
ftmp = rate - fmin;
|
||||
return 0;
|
||||
} else if (req->rate >= fmax) {
|
||||
req->rate = fmax;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ftmp = req->rate - fmin;
|
||||
ftmp += clk->info->range.step_size - 1; /* to round up */
|
||||
do_div(ftmp, clk->info->range.step_size);
|
||||
|
||||
return ftmp * clk->info->range.step_size + fmin;
|
||||
req->rate = ftmp * clk->info->range.step_size + fmin;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scmi_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -119,15 +126,6 @@ static u8 scmi_clk_get_parent(struct clk_hw *hw)
|
||||
return p_idx;
|
||||
}
|
||||
|
||||
static int scmi_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
|
||||
{
|
||||
/*
|
||||
* Suppose all the requested rates are supported, and let firmware
|
||||
* to handle the left work.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scmi_clk_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct scmi_clk *clk = to_scmi_clk(hw);
|
||||
@@ -300,7 +298,6 @@ scmi_clk_ops_alloc(struct device *dev, unsigned long feats_key)
|
||||
|
||||
/* Rate ops */
|
||||
ops->recalc_rate = scmi_clk_recalc_rate;
|
||||
ops->round_rate = scmi_clk_round_rate;
|
||||
ops->determine_rate = scmi_clk_determine_rate;
|
||||
if (feats_key & BIT(SCMI_CLK_RATE_CTRL_SUPPORTED))
|
||||
ops->set_rate = scmi_clk_set_rate;
|
||||
@@ -349,6 +346,8 @@ scmi_clk_ops_select(struct scmi_clk *sclk, bool atomic_capable,
|
||||
unsigned int atomic_threshold_us,
|
||||
const struct clk_ops **clk_ops_db, size_t db_size)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
const struct scmi_clock_info *ci = sclk->info;
|
||||
unsigned int feats_key = 0;
|
||||
const struct clk_ops *ops;
|
||||
@@ -370,8 +369,13 @@ scmi_clk_ops_select(struct scmi_clk *sclk, bool atomic_capable,
|
||||
if (!ci->parent_ctrl_forbidden)
|
||||
feats_key |= BIT(SCMI_CLK_PARENT_CTRL_SUPPORTED);
|
||||
|
||||
if (ci->extended_config)
|
||||
feats_key |= BIT(SCMI_CLK_DUTY_CYCLE_SUPPORTED);
|
||||
if (ci->extended_config) {
|
||||
ret = scmi_proto_clk_ops->config_oem_get(sclk->ph, sclk->id,
|
||||
SCMI_CLOCK_CFG_DUTY_CYCLE,
|
||||
&val, NULL, false);
|
||||
if (!ret)
|
||||
feats_key |= BIT(SCMI_CLK_DUTY_CYCLE_SUPPORTED);
|
||||
}
|
||||
|
||||
if (WARN_ON(feats_key >= db_size))
|
||||
return NULL;
|
||||
|
||||
@@ -32,8 +32,8 @@ static unsigned long scpi_clk_recalc_rate(struct clk_hw *hw,
|
||||
return clk->scpi_ops->clk_get_val(clk->id);
|
||||
}
|
||||
|
||||
static long scpi_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int scpi_clk_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
/*
|
||||
* We can't figure out what rate it will be, so just return the
|
||||
@@ -41,7 +41,7 @@ static long scpi_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
* after the rate is set and we'll know what rate the clock is
|
||||
* running at then.
|
||||
*/
|
||||
return rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scpi_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -54,7 +54,7 @@ static int scpi_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops scpi_clk_ops = {
|
||||
.recalc_rate = scpi_clk_recalc_rate,
|
||||
.round_rate = scpi_clk_round_rate,
|
||||
.determine_rate = scpi_clk_determine_rate,
|
||||
.set_rate = scpi_clk_set_rate,
|
||||
};
|
||||
|
||||
@@ -92,12 +92,14 @@ static unsigned long scpi_dvfs_recalc_rate(struct clk_hw *hw,
|
||||
return opp->freq;
|
||||
}
|
||||
|
||||
static long scpi_dvfs_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int scpi_dvfs_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct scpi_clk *clk = to_scpi_clk(hw);
|
||||
|
||||
return __scpi_dvfs_round_rate(clk, rate);
|
||||
req->rate = __scpi_dvfs_round_rate(clk, req->rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __scpi_find_dvfs_index(struct scpi_clk *clk, unsigned long rate)
|
||||
@@ -124,7 +126,7 @@ static int scpi_dvfs_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops scpi_dvfs_ops = {
|
||||
.recalc_rate = scpi_dvfs_recalc_rate,
|
||||
.round_rate = scpi_dvfs_round_rate,
|
||||
.determine_rate = scpi_dvfs_determine_rate,
|
||||
.set_rate = scpi_dvfs_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -227,20 +227,28 @@ static unsigned long si514_recalc_rate(struct clk_hw *hw,
|
||||
return si514_calc_rate(&settings);
|
||||
}
|
||||
|
||||
static long si514_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int si514_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_si514_muldiv settings;
|
||||
int err;
|
||||
|
||||
if (!rate)
|
||||
if (!req->rate) {
|
||||
req->rate = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = si514_calc_muldiv(&settings, rate);
|
||||
if (err)
|
||||
return err;
|
||||
err = si514_calc_muldiv(&settings, req->rate);
|
||||
if (err) {
|
||||
req->rate = err;
|
||||
|
||||
return si514_calc_rate(&settings);
|
||||
return 0;
|
||||
}
|
||||
|
||||
req->rate = si514_calc_rate(&settings);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -289,7 +297,7 @@ static const struct clk_ops si514_clk_ops = {
|
||||
.unprepare = si514_unprepare,
|
||||
.is_prepared = si514_is_prepared,
|
||||
.recalc_rate = si514_recalc_rate,
|
||||
.round_rate = si514_round_rate,
|
||||
.determine_rate = si514_determine_rate,
|
||||
.set_rate = si514_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -164,15 +164,17 @@ static unsigned long si521xx_diff_recalc_rate(struct clk_hw *hw,
|
||||
return (unsigned long)rate;
|
||||
}
|
||||
|
||||
static long si521xx_diff_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static int si521xx_diff_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
unsigned long best_parent;
|
||||
|
||||
best_parent = (rate / SI521XX_DIFF_MULT) * SI521XX_DIFF_DIV;
|
||||
*prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
|
||||
best_parent = (req->rate / SI521XX_DIFF_MULT) * SI521XX_DIFF_DIV;
|
||||
req->best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
|
||||
|
||||
return (*prate / SI521XX_DIFF_DIV) * SI521XX_DIFF_MULT;
|
||||
req->rate = (req->best_parent_rate / SI521XX_DIFF_DIV) * SI521XX_DIFF_MULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int si521xx_diff_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -208,7 +210,7 @@ static void si521xx_diff_unprepare(struct clk_hw *hw)
|
||||
}
|
||||
|
||||
static const struct clk_ops si521xx_diff_clk_ops = {
|
||||
.round_rate = si521xx_diff_round_rate,
|
||||
.determine_rate = si521xx_diff_determine_rate,
|
||||
.set_rate = si521xx_diff_set_rate,
|
||||
.recalc_rate = si521xx_diff_recalc_rate,
|
||||
.prepare = si521xx_diff_prepare,
|
||||
|
||||
@@ -663,8 +663,8 @@ static unsigned long si5341_synth_clk_recalc_rate(struct clk_hw *hw,
|
||||
return f;
|
||||
}
|
||||
|
||||
static long si5341_synth_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int si5341_synth_clk_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
|
||||
u64 f;
|
||||
@@ -672,15 +672,21 @@ static long si5341_synth_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
/* The synthesizer accuracy is such that anything in range will work */
|
||||
f = synth->data->freq_vco;
|
||||
do_div(f, SI5341_SYNTH_N_MAX);
|
||||
if (rate < f)
|
||||
return f;
|
||||
if (req->rate < f) {
|
||||
req->rate = f;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
f = synth->data->freq_vco;
|
||||
do_div(f, SI5341_SYNTH_N_MIN);
|
||||
if (rate > f)
|
||||
return f;
|
||||
if (req->rate > f) {
|
||||
req->rate = f;
|
||||
|
||||
return rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int si5341_synth_program(struct clk_si5341_synth *synth,
|
||||
@@ -741,7 +747,7 @@ static const struct clk_ops si5341_synth_clk_ops = {
|
||||
.prepare = si5341_synth_clk_prepare,
|
||||
.unprepare = si5341_synth_clk_unprepare,
|
||||
.recalc_rate = si5341_synth_clk_recalc_rate,
|
||||
.round_rate = si5341_synth_clk_round_rate,
|
||||
.determine_rate = si5341_synth_clk_determine_rate,
|
||||
.set_rate = si5341_synth_clk_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -307,16 +307,16 @@ static unsigned long si544_recalc_rate(struct clk_hw *hw,
|
||||
return si544_calc_rate(&settings);
|
||||
}
|
||||
|
||||
static long si544_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int si544_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_si544 *data = to_clk_si544(hw);
|
||||
|
||||
if (!is_valid_frequency(data, rate))
|
||||
if (!is_valid_frequency(data, req->rate))
|
||||
return -EINVAL;
|
||||
|
||||
/* The accuracy is less than 1 Hz, so any rate is possible */
|
||||
return rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calculates the maximum "small" change, 950 * rate / 1000000 */
|
||||
@@ -408,7 +408,7 @@ static const struct clk_ops si544_clk_ops = {
|
||||
.unprepare = si544_unprepare,
|
||||
.is_prepared = si544_is_prepared,
|
||||
.recalc_rate = si544_recalc_rate,
|
||||
.round_rate = si544_round_rate,
|
||||
.determine_rate = si544_determine_rate,
|
||||
.set_rate = si544_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -246,34 +246,40 @@ static unsigned long si570_recalc_rate(struct clk_hw *hw,
|
||||
return rate;
|
||||
}
|
||||
|
||||
static long si570_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int si570_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
int err;
|
||||
u64 rfreq;
|
||||
unsigned int n1, hs_div;
|
||||
struct clk_si570 *data = to_clk_si570(hw);
|
||||
|
||||
if (!rate)
|
||||
return 0;
|
||||
if (!req->rate) {
|
||||
req->rate = 0;
|
||||
|
||||
if (div64_u64(abs(rate - data->frequency) * 10000LL,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (div64_u64(abs(req->rate - data->frequency) * 10000LL,
|
||||
data->frequency) < 35) {
|
||||
rfreq = div64_u64((data->rfreq * rate) +
|
||||
div64_u64(data->frequency, 2), data->frequency);
|
||||
rfreq = div64_u64((data->rfreq * req->rate) +
|
||||
div64_u64(data->frequency, 2),
|
||||
data->frequency);
|
||||
n1 = data->n1;
|
||||
hs_div = data->hs_div;
|
||||
|
||||
} else {
|
||||
err = si570_calc_divs(rate, data, &rfreq, &n1, &hs_div);
|
||||
err = si570_calc_divs(req->rate, data, &rfreq, &n1, &hs_div);
|
||||
if (err) {
|
||||
dev_err(&data->i2c_client->dev,
|
||||
"unable to round rate\n");
|
||||
req->rate = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -368,7 +374,7 @@ static int si570_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops si570_clk_ops = {
|
||||
.recalc_rate = si570_recalc_rate,
|
||||
.round_rate = si570_round_rate,
|
||||
.determine_rate = si570_determine_rate,
|
||||
.set_rate = si570_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -406,25 +406,27 @@ static long sp_pll_calc_div(struct sp_pll *clk, unsigned long rate)
|
||||
return fbdiv;
|
||||
}
|
||||
|
||||
static long sp_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static int sp_pll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct sp_pll *clk = to_sp_pll(hw);
|
||||
long ret;
|
||||
|
||||
if (rate == *prate) {
|
||||
ret = *prate; /* bypass */
|
||||
if (req->rate == req->best_parent_rate) {
|
||||
ret = req->best_parent_rate; /* bypass */
|
||||
} else if (clk->div_width == DIV_A) {
|
||||
ret = plla_round_rate(clk, rate);
|
||||
ret = plla_round_rate(clk, req->rate);
|
||||
} else if (clk->div_width == DIV_TV) {
|
||||
ret = plltv_div(clk, rate);
|
||||
ret = plltv_div(clk, req->rate);
|
||||
if (ret < 0)
|
||||
ret = *prate;
|
||||
ret = req->best_parent_rate;
|
||||
} else {
|
||||
ret = sp_pll_calc_div(clk, rate) * clk->brate;
|
||||
ret = sp_pll_calc_div(clk, req->rate) * clk->brate;
|
||||
}
|
||||
|
||||
return ret;
|
||||
req->rate = ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long sp_pll_recalc_rate(struct clk_hw *hw,
|
||||
@@ -529,7 +531,7 @@ static const struct clk_ops sp_pll_ops = {
|
||||
.enable = sp_pll_enable,
|
||||
.disable = sp_pll_disable,
|
||||
.is_enabled = sp_pll_is_enabled,
|
||||
.round_rate = sp_pll_round_rate,
|
||||
.determine_rate = sp_pll_determine_rate,
|
||||
.recalc_rate = sp_pll_recalc_rate,
|
||||
.set_rate = sp_pll_set_rate
|
||||
};
|
||||
|
||||
@@ -213,19 +213,21 @@ static unsigned long s5_pll_recalc_rate(struct clk_hw *hw,
|
||||
return conf.freq;
|
||||
}
|
||||
|
||||
static long s5_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int s5_pll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct s5_pll_conf conf;
|
||||
|
||||
return s5_calc_params(rate, *parent_rate, &conf);
|
||||
req->rate = s5_calc_params(req->rate, req->best_parent_rate, &conf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops s5_pll_ops = {
|
||||
.enable = s5_pll_enable,
|
||||
.disable = s5_pll_disable,
|
||||
.set_rate = s5_pll_set_rate,
|
||||
.round_rate = s5_pll_round_rate,
|
||||
.determine_rate = s5_pll_determine_rate,
|
||||
.recalc_rate = s5_pll_recalc_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -443,8 +443,8 @@ static unsigned long clk_apb_mul_recalc_rate(struct clk_hw *hw,
|
||||
return parent_rate;
|
||||
}
|
||||
|
||||
static long clk_apb_mul_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static int clk_apb_mul_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_apb_mul *am = to_clk_apb_mul(hw);
|
||||
unsigned long mult = 1;
|
||||
@@ -453,12 +453,14 @@ static long clk_apb_mul_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
mult = 2;
|
||||
|
||||
if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
|
||||
unsigned long best_parent = rate / mult;
|
||||
unsigned long best_parent = req->rate / mult;
|
||||
|
||||
*prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
|
||||
req->best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
|
||||
}
|
||||
|
||||
return *prate * mult;
|
||||
req->rate = req->best_parent_rate * mult;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_apb_mul_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -474,7 +476,7 @@ static int clk_apb_mul_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_apb_mul_factor_ops = {
|
||||
.round_rate = clk_apb_mul_round_rate,
|
||||
.determine_rate = clk_apb_mul_determine_rate,
|
||||
.set_rate = clk_apb_mul_set_rate,
|
||||
.recalc_rate = clk_apb_mul_recalc_rate,
|
||||
};
|
||||
@@ -670,21 +672,23 @@ static unsigned long stm32f4_pll_recalc(struct clk_hw *hw,
|
||||
return parent_rate * n;
|
||||
}
|
||||
|
||||
static long stm32f4_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static int stm32f4_pll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_gate *gate = to_clk_gate(hw);
|
||||
struct stm32f4_pll *pll = to_stm32f4_pll(gate);
|
||||
unsigned long n;
|
||||
|
||||
n = rate / *prate;
|
||||
n = req->rate / req->best_parent_rate;
|
||||
|
||||
if (n < pll->n_start)
|
||||
n = pll->n_start;
|
||||
else if (n > 432)
|
||||
n = 432;
|
||||
|
||||
return *prate * n;
|
||||
req->rate = req->best_parent_rate * n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stm32f4_pll_set_ssc(struct clk_hw *hw, unsigned long parent_rate,
|
||||
@@ -749,7 +753,7 @@ static const struct clk_ops stm32f4_pll_gate_ops = {
|
||||
.disable = stm32f4_pll_disable,
|
||||
.is_enabled = stm32f4_pll_is_enabled,
|
||||
.recalc_rate = stm32f4_pll_recalc,
|
||||
.round_rate = stm32f4_pll_round_rate,
|
||||
.determine_rate = stm32f4_pll_determine_rate,
|
||||
.set_rate = stm32f4_pll_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -146,12 +146,14 @@ static unsigned int tps68470_clk_cfg_lookup(unsigned long rate)
|
||||
return best_idx;
|
||||
}
|
||||
|
||||
static long tps68470_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int tps68470_clk_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
unsigned int idx = tps68470_clk_cfg_lookup(rate);
|
||||
unsigned int idx = tps68470_clk_cfg_lookup(req->rate);
|
||||
|
||||
return clk_freqs[idx].freq;
|
||||
req->rate = clk_freqs[idx].freq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps68470_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -186,7 +188,7 @@ static const struct clk_ops tps68470_clk_ops = {
|
||||
.prepare = tps68470_clk_prepare,
|
||||
.unprepare = tps68470_clk_unprepare,
|
||||
.recalc_rate = tps68470_clk_recalc_rate,
|
||||
.round_rate = tps68470_clk_round_rate,
|
||||
.determine_rate = tps68470_clk_determine_rate,
|
||||
.set_rate = tps68470_clk_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -289,22 +289,25 @@ static unsigned long vc3_pfd_recalc_rate(struct clk_hw *hw,
|
||||
return rate;
|
||||
}
|
||||
|
||||
static long vc3_pfd_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int vc3_pfd_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
|
||||
const struct vc3_pfd_data *pfd = vc3->data;
|
||||
unsigned long idiv;
|
||||
|
||||
/* PLL cannot operate with input clock above 50 MHz. */
|
||||
if (rate > 50000000)
|
||||
if (req->rate > 50000000)
|
||||
return -EINVAL;
|
||||
|
||||
/* CLKIN within range of PLL input, feed directly to PLL. */
|
||||
if (*parent_rate <= 50000000)
|
||||
return *parent_rate;
|
||||
if (req->best_parent_rate <= 50000000) {
|
||||
req->rate = req->best_parent_rate;
|
||||
|
||||
idiv = DIV_ROUND_UP(*parent_rate, rate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
idiv = DIV_ROUND_UP(req->best_parent_rate, req->rate);
|
||||
if (pfd->num == VC3_PFD1 || pfd->num == VC3_PFD3) {
|
||||
if (idiv > 63)
|
||||
return -EINVAL;
|
||||
@@ -313,7 +316,9 @@ static long vc3_pfd_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return *parent_rate / idiv;
|
||||
req->rate = req->best_parent_rate / idiv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vc3_pfd_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -354,7 +359,7 @@ static int vc3_pfd_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops vc3_pfd_ops = {
|
||||
.recalc_rate = vc3_pfd_recalc_rate,
|
||||
.round_rate = vc3_pfd_round_rate,
|
||||
.determine_rate = vc3_pfd_determine_rate,
|
||||
.set_rate = vc3_pfd_set_rate,
|
||||
};
|
||||
|
||||
@@ -385,36 +390,38 @@ static unsigned long vc3_pll_recalc_rate(struct clk_hw *hw,
|
||||
return rate;
|
||||
}
|
||||
|
||||
static long vc3_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int vc3_pll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
|
||||
const struct vc3_pll_data *pll = vc3->data;
|
||||
u64 div_frc;
|
||||
|
||||
if (rate < pll->vco.min)
|
||||
rate = pll->vco.min;
|
||||
if (rate > pll->vco.max)
|
||||
rate = pll->vco.max;
|
||||
if (req->rate < pll->vco.min)
|
||||
req->rate = pll->vco.min;
|
||||
if (req->rate > pll->vco.max)
|
||||
req->rate = pll->vco.max;
|
||||
|
||||
vc3->div_int = rate / *parent_rate;
|
||||
vc3->div_int = req->rate / req->best_parent_rate;
|
||||
|
||||
if (pll->num == VC3_PLL2) {
|
||||
if (vc3->div_int > 0x7ff)
|
||||
rate = *parent_rate * 0x7ff;
|
||||
req->rate = req->best_parent_rate * 0x7ff;
|
||||
|
||||
/* Determine best fractional part, which is 16 bit wide */
|
||||
div_frc = rate % *parent_rate;
|
||||
div_frc = req->rate % req->best_parent_rate;
|
||||
div_frc *= BIT(16) - 1;
|
||||
|
||||
vc3->div_frc = min_t(u64, div64_ul(div_frc, *parent_rate), U16_MAX);
|
||||
rate = (*parent_rate *
|
||||
(vc3->div_int * VC3_2_POW_16 + vc3->div_frc) / VC3_2_POW_16);
|
||||
vc3->div_frc = min_t(u64,
|
||||
div64_ul(div_frc, req->best_parent_rate),
|
||||
U16_MAX);
|
||||
req->rate = (req->best_parent_rate *
|
||||
(vc3->div_int * VC3_2_POW_16 + vc3->div_frc) / VC3_2_POW_16);
|
||||
} else {
|
||||
rate = *parent_rate * vc3->div_int;
|
||||
req->rate = req->best_parent_rate * vc3->div_int;
|
||||
}
|
||||
|
||||
return rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vc3_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -441,7 +448,7 @@ static int vc3_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops vc3_pll_ops = {
|
||||
.recalc_rate = vc3_pll_recalc_rate,
|
||||
.round_rate = vc3_pll_round_rate,
|
||||
.determine_rate = vc3_pll_determine_rate,
|
||||
.set_rate = vc3_pll_set_rate,
|
||||
};
|
||||
|
||||
@@ -498,8 +505,8 @@ static unsigned long vc3_div_recalc_rate(struct clk_hw *hw,
|
||||
div_data->flags, div_data->width);
|
||||
}
|
||||
|
||||
static long vc3_div_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int vc3_div_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
|
||||
const struct vc3_div_data *div_data = vc3->data;
|
||||
@@ -511,11 +518,16 @@ static long vc3_div_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
bestdiv >>= div_data->shift;
|
||||
bestdiv &= VC3_DIV_MASK(div_data->width);
|
||||
bestdiv = vc3_get_div(div_data->table, bestdiv, div_data->flags);
|
||||
return DIV_ROUND_UP(*parent_rate, bestdiv);
|
||||
req->rate = DIV_ROUND_UP(req->best_parent_rate, bestdiv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return divider_round_rate(hw, rate, parent_rate, div_data->table,
|
||||
div_data->width, div_data->flags);
|
||||
req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate,
|
||||
div_data->table,
|
||||
div_data->width, div_data->flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vc3_div_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -534,7 +546,7 @@ static int vc3_div_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops vc3_div_ops = {
|
||||
.recalc_rate = vc3_div_recalc_rate,
|
||||
.round_rate = vc3_div_round_rate,
|
||||
.determine_rate = vc3_div_determine_rate,
|
||||
.set_rate = vc3_div_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -304,11 +304,11 @@ static unsigned long vc5_dbl_recalc_rate(struct clk_hw *hw,
|
||||
return parent_rate;
|
||||
}
|
||||
|
||||
static long vc5_dbl_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int vc5_dbl_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
if ((*parent_rate == rate) || ((*parent_rate * 2) == rate))
|
||||
return rate;
|
||||
if ((req->best_parent_rate == req->rate) || ((req->best_parent_rate * 2) == req->rate))
|
||||
return 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -332,7 +332,7 @@ static int vc5_dbl_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops vc5_dbl_ops = {
|
||||
.recalc_rate = vc5_dbl_recalc_rate,
|
||||
.round_rate = vc5_dbl_round_rate,
|
||||
.determine_rate = vc5_dbl_determine_rate,
|
||||
.set_rate = vc5_dbl_set_rate,
|
||||
};
|
||||
|
||||
@@ -363,24 +363,29 @@ static unsigned long vc5_pfd_recalc_rate(struct clk_hw *hw,
|
||||
return parent_rate / VC5_REF_DIVIDER_REF_DIV(div);
|
||||
}
|
||||
|
||||
static long vc5_pfd_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int vc5_pfd_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
unsigned long idiv;
|
||||
|
||||
/* PLL cannot operate with input clock above 50 MHz. */
|
||||
if (rate > 50000000)
|
||||
if (req->rate > 50000000)
|
||||
return -EINVAL;
|
||||
|
||||
/* CLKIN within range of PLL input, feed directly to PLL. */
|
||||
if (*parent_rate <= 50000000)
|
||||
return *parent_rate;
|
||||
if (req->best_parent_rate <= 50000000) {
|
||||
req->rate = req->best_parent_rate;
|
||||
|
||||
idiv = DIV_ROUND_UP(*parent_rate, rate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
idiv = DIV_ROUND_UP(req->best_parent_rate, req->rate);
|
||||
if (idiv > 127)
|
||||
return -EINVAL;
|
||||
|
||||
return *parent_rate / idiv;
|
||||
req->rate = req->best_parent_rate / idiv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vc5_pfd_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -420,7 +425,7 @@ static int vc5_pfd_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops vc5_pfd_ops = {
|
||||
.recalc_rate = vc5_pfd_recalc_rate,
|
||||
.round_rate = vc5_pfd_round_rate,
|
||||
.determine_rate = vc5_pfd_determine_rate,
|
||||
.set_rate = vc5_pfd_set_rate,
|
||||
};
|
||||
|
||||
@@ -444,30 +449,32 @@ static unsigned long vc5_pll_recalc_rate(struct clk_hw *hw,
|
||||
return (parent_rate * div_int) + ((parent_rate * div_frc) >> 24);
|
||||
}
|
||||
|
||||
static long vc5_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int vc5_pll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
|
||||
struct vc5_driver_data *vc5 = hwdata->vc5;
|
||||
u32 div_int;
|
||||
u64 div_frc;
|
||||
|
||||
rate = clamp(rate, VC5_PLL_VCO_MIN, vc5->chip_info->vco_max);
|
||||
req->rate = clamp(req->rate, VC5_PLL_VCO_MIN, vc5->chip_info->vco_max);
|
||||
|
||||
/* Determine integer part, which is 12 bit wide */
|
||||
div_int = rate / *parent_rate;
|
||||
div_int = req->rate / req->best_parent_rate;
|
||||
if (div_int > 0xfff)
|
||||
rate = *parent_rate * 0xfff;
|
||||
req->rate = req->best_parent_rate * 0xfff;
|
||||
|
||||
/* Determine best fractional part, which is 24 bit wide */
|
||||
div_frc = rate % *parent_rate;
|
||||
div_frc = req->rate % req->best_parent_rate;
|
||||
div_frc *= BIT(24) - 1;
|
||||
do_div(div_frc, *parent_rate);
|
||||
do_div(div_frc, req->best_parent_rate);
|
||||
|
||||
hwdata->div_int = div_int;
|
||||
hwdata->div_frc = (u32)div_frc;
|
||||
|
||||
return (*parent_rate * div_int) + ((*parent_rate * div_frc) >> 24);
|
||||
req->rate = (req->best_parent_rate * div_int) + ((req->best_parent_rate * div_frc) >> 24);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vc5_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -488,7 +495,7 @@ static int vc5_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops vc5_pll_ops = {
|
||||
.recalc_rate = vc5_pll_recalc_rate,
|
||||
.round_rate = vc5_pll_round_rate,
|
||||
.determine_rate = vc5_pll_determine_rate,
|
||||
.set_rate = vc5_pll_set_rate,
|
||||
};
|
||||
|
||||
@@ -520,17 +527,17 @@ static unsigned long vc5_fod_recalc_rate(struct clk_hw *hw,
|
||||
return div64_u64((u64)f_in << 24ULL, ((u64)div_int << 24ULL) + div_frc);
|
||||
}
|
||||
|
||||
static long vc5_fod_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int vc5_fod_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
|
||||
/* VCO frequency is divided by two before entering FOD */
|
||||
u32 f_in = *parent_rate / 2;
|
||||
u32 f_in = req->best_parent_rate / 2;
|
||||
u32 div_int;
|
||||
u64 div_frc;
|
||||
|
||||
/* Determine integer part, which is 12 bit wide */
|
||||
div_int = f_in / rate;
|
||||
div_int = f_in / req->rate;
|
||||
/*
|
||||
* WARNING: The clock chip does not output signal if the integer part
|
||||
* of the divider is 0xfff and fractional part is non-zero.
|
||||
@@ -538,18 +545,20 @@ static long vc5_fod_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
*/
|
||||
if (div_int > 0xffe) {
|
||||
div_int = 0xffe;
|
||||
rate = f_in / div_int;
|
||||
req->rate = f_in / div_int;
|
||||
}
|
||||
|
||||
/* Determine best fractional part, which is 30 bit wide */
|
||||
div_frc = f_in % rate;
|
||||
div_frc = f_in % req->rate;
|
||||
div_frc <<= 24;
|
||||
do_div(div_frc, rate);
|
||||
do_div(div_frc, req->rate);
|
||||
|
||||
hwdata->div_int = div_int;
|
||||
hwdata->div_frc = (u32)div_frc;
|
||||
|
||||
return div64_u64((u64)f_in << 24ULL, ((u64)div_int << 24ULL) + div_frc);
|
||||
req->rate = div64_u64((u64)f_in << 24ULL, ((u64)div_int << 24ULL) + div_frc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vc5_fod_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -589,7 +598,7 @@ static int vc5_fod_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops vc5_fod_ops = {
|
||||
.recalc_rate = vc5_fod_recalc_rate,
|
||||
.round_rate = vc5_fod_round_rate,
|
||||
.determine_rate = vc5_fod_determine_rate,
|
||||
.set_rate = vc5_fod_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -900,17 +900,18 @@ static unsigned long vc7_fod_recalc_rate(struct clk_hw *hw, unsigned long parent
|
||||
return fod_rate;
|
||||
}
|
||||
|
||||
static long vc7_fod_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate)
|
||||
static int vc7_fod_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct vc7_fod_data *fod = container_of(hw, struct vc7_fod_data, hw);
|
||||
unsigned long fod_rate;
|
||||
|
||||
pr_debug("%s - %s: requested rate: %lu, parent_rate: %lu\n",
|
||||
__func__, clk_hw_get_name(hw), rate, *parent_rate);
|
||||
__func__, clk_hw_get_name(hw), req->rate, req->best_parent_rate);
|
||||
|
||||
vc7_calc_fod_divider(rate, *parent_rate,
|
||||
vc7_calc_fod_divider(req->rate, req->best_parent_rate,
|
||||
&fod->fod_1st_int, &fod->fod_2nd_int, &fod->fod_frac);
|
||||
fod_rate = vc7_calc_fod_2nd_stage_rate(*parent_rate, fod->fod_1st_int,
|
||||
fod_rate = vc7_calc_fod_2nd_stage_rate(req->best_parent_rate, fod->fod_1st_int,
|
||||
fod->fod_2nd_int, fod->fod_frac);
|
||||
|
||||
pr_debug("%s - %s: fod_1st_int: %u, fod_2nd_int: %u, fod_frac: %llu\n",
|
||||
@@ -918,7 +919,9 @@ static long vc7_fod_round_rate(struct clk_hw *hw, unsigned long rate, unsigned l
|
||||
fod->fod_1st_int, fod->fod_2nd_int, fod->fod_frac);
|
||||
pr_debug("%s - %s rate: %lu\n", __func__, clk_hw_get_name(hw), fod_rate);
|
||||
|
||||
return fod_rate;
|
||||
req->rate = fod_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vc7_fod_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
|
||||
@@ -952,7 +955,7 @@ static int vc7_fod_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long
|
||||
|
||||
static const struct clk_ops vc7_fod_ops = {
|
||||
.recalc_rate = vc7_fod_recalc_rate,
|
||||
.round_rate = vc7_fod_round_rate,
|
||||
.determine_rate = vc7_fod_determine_rate,
|
||||
.set_rate = vc7_fod_set_rate,
|
||||
};
|
||||
|
||||
@@ -978,21 +981,24 @@ static unsigned long vc7_iod_recalc_rate(struct clk_hw *hw, unsigned long parent
|
||||
return iod_rate;
|
||||
}
|
||||
|
||||
static long vc7_iod_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate)
|
||||
static int vc7_iod_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct vc7_iod_data *iod = container_of(hw, struct vc7_iod_data, hw);
|
||||
unsigned long iod_rate;
|
||||
|
||||
pr_debug("%s - %s: requested rate: %lu, parent_rate: %lu\n",
|
||||
__func__, clk_hw_get_name(hw), rate, *parent_rate);
|
||||
__func__, clk_hw_get_name(hw), req->rate, req->best_parent_rate);
|
||||
|
||||
vc7_calc_iod_divider(rate, *parent_rate, &iod->iod_int);
|
||||
iod_rate = div64_u64(*parent_rate, iod->iod_int);
|
||||
vc7_calc_iod_divider(req->rate, req->best_parent_rate, &iod->iod_int);
|
||||
iod_rate = div64_u64(req->best_parent_rate, iod->iod_int);
|
||||
|
||||
pr_debug("%s - %s: iod_int: %u\n", __func__, clk_hw_get_name(hw), iod->iod_int);
|
||||
pr_debug("%s - %s rate: %ld\n", __func__, clk_hw_get_name(hw), iod_rate);
|
||||
|
||||
return iod_rate;
|
||||
req->rate = iod_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vc7_iod_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
|
||||
@@ -1023,7 +1029,7 @@ static int vc7_iod_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long
|
||||
|
||||
static const struct clk_ops vc7_iod_ops = {
|
||||
.recalc_rate = vc7_iod_recalc_rate,
|
||||
.round_rate = vc7_iod_round_rate,
|
||||
.determine_rate = vc7_iod_determine_rate,
|
||||
.set_rate = vc7_iod_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -128,30 +128,31 @@ static unsigned long vt8500_dclk_recalc_rate(struct clk_hw *hw,
|
||||
return parent_rate / div;
|
||||
}
|
||||
|
||||
static long vt8500_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static int vt8500_dclk_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_device *cdev = to_clk_device(hw);
|
||||
u32 divisor;
|
||||
|
||||
if (rate == 0)
|
||||
if (req->rate == 0)
|
||||
return 0;
|
||||
|
||||
divisor = *prate / rate;
|
||||
divisor = req->best_parent_rate / req->rate;
|
||||
|
||||
/* If prate / rate would be decimal, incr the divisor */
|
||||
if (rate * divisor < *prate)
|
||||
if (req->rate * divisor < req->best_parent_rate)
|
||||
divisor++;
|
||||
|
||||
/*
|
||||
* If this is a request for SDMMC we have to adjust the divisor
|
||||
* when >31 to use the fixed predivisor
|
||||
*/
|
||||
if ((cdev->div_mask == 0x3F) && (divisor > 31)) {
|
||||
if ((cdev->div_mask == 0x3F) && (divisor > 31))
|
||||
divisor = 64 * ((divisor / 64) + 1);
|
||||
}
|
||||
|
||||
return *prate / divisor;
|
||||
req->rate = req->best_parent_rate / divisor;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vt8500_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -202,7 +203,7 @@ static const struct clk_ops vt8500_gated_clk_ops = {
|
||||
};
|
||||
|
||||
static const struct clk_ops vt8500_divisor_clk_ops = {
|
||||
.round_rate = vt8500_dclk_round_rate,
|
||||
.determine_rate = vt8500_dclk_determine_rate,
|
||||
.set_rate = vt8500_dclk_set_rate,
|
||||
.recalc_rate = vt8500_dclk_recalc_rate,
|
||||
};
|
||||
@@ -211,7 +212,7 @@ static const struct clk_ops vt8500_gated_divisor_clk_ops = {
|
||||
.enable = vt8500_dclk_enable,
|
||||
.disable = vt8500_dclk_disable,
|
||||
.is_enabled = vt8500_dclk_is_enabled,
|
||||
.round_rate = vt8500_dclk_round_rate,
|
||||
.determine_rate = vt8500_dclk_determine_rate,
|
||||
.set_rate = vt8500_dclk_set_rate,
|
||||
.recalc_rate = vt8500_dclk_recalc_rate,
|
||||
};
|
||||
@@ -594,8 +595,8 @@ static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static int vtwm_pll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_pll *pll = to_clk_pll(hw);
|
||||
u32 filter, mul, div1, div2;
|
||||
@@ -604,33 +605,43 @@ static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
switch (pll->type) {
|
||||
case PLL_TYPE_VT8500:
|
||||
ret = vt8500_find_pll_bits(rate, *prate, &mul, &div1);
|
||||
ret = vt8500_find_pll_bits(req->rate, req->best_parent_rate,
|
||||
&mul, &div1);
|
||||
if (!ret)
|
||||
round_rate = VT8500_BITS_TO_FREQ(*prate, mul, div1);
|
||||
round_rate = VT8500_BITS_TO_FREQ(req->best_parent_rate,
|
||||
mul, div1);
|
||||
break;
|
||||
case PLL_TYPE_WM8650:
|
||||
ret = wm8650_find_pll_bits(rate, *prate, &mul, &div1, &div2);
|
||||
ret = wm8650_find_pll_bits(req->rate, req->best_parent_rate,
|
||||
&mul, &div1, &div2);
|
||||
if (!ret)
|
||||
round_rate = WM8650_BITS_TO_FREQ(*prate, mul, div1, div2);
|
||||
round_rate = WM8650_BITS_TO_FREQ(req->best_parent_rate,
|
||||
mul, div1, div2);
|
||||
break;
|
||||
case PLL_TYPE_WM8750:
|
||||
ret = wm8750_find_pll_bits(rate, *prate, &filter, &mul, &div1, &div2);
|
||||
ret = wm8750_find_pll_bits(req->rate, req->best_parent_rate,
|
||||
&filter, &mul, &div1, &div2);
|
||||
if (!ret)
|
||||
round_rate = WM8750_BITS_TO_FREQ(*prate, mul, div1, div2);
|
||||
round_rate = WM8750_BITS_TO_FREQ(req->best_parent_rate,
|
||||
mul, div1, div2);
|
||||
break;
|
||||
case PLL_TYPE_WM8850:
|
||||
ret = wm8850_find_pll_bits(rate, *prate, &mul, &div1, &div2);
|
||||
ret = wm8850_find_pll_bits(req->rate, req->best_parent_rate,
|
||||
&mul, &div1, &div2);
|
||||
if (!ret)
|
||||
round_rate = WM8850_BITS_TO_FREQ(*prate, mul, div1, div2);
|
||||
round_rate = WM8850_BITS_TO_FREQ(req->best_parent_rate,
|
||||
mul, div1, div2);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
req->rate = ret;
|
||||
else
|
||||
req->rate = round_rate;
|
||||
|
||||
return round_rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long vtwm_pll_recalc_rate(struct clk_hw *hw,
|
||||
@@ -665,7 +676,7 @@ static unsigned long vtwm_pll_recalc_rate(struct clk_hw *hw,
|
||||
}
|
||||
|
||||
static const struct clk_ops vtwm_pll_ops = {
|
||||
.round_rate = vtwm_pll_round_rate,
|
||||
.determine_rate = vtwm_pll_determine_rate,
|
||||
.set_rate = vtwm_pll_set_rate,
|
||||
.recalc_rate = vtwm_pll_recalc_rate,
|
||||
};
|
||||
|
||||
@@ -133,18 +133,20 @@ static unsigned long wm831x_fll_recalc_rate(struct clk_hw *hw,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long wm831x_fll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *unused)
|
||||
static int wm831x_fll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
int best = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wm831x_fll_auto_rates); i++)
|
||||
if (abs(wm831x_fll_auto_rates[i] - rate) <
|
||||
abs(wm831x_fll_auto_rates[best] - rate))
|
||||
if (abs(wm831x_fll_auto_rates[i] - req->rate) <
|
||||
abs(wm831x_fll_auto_rates[best] - req->rate))
|
||||
best = i;
|
||||
|
||||
return wm831x_fll_auto_rates[best];
|
||||
req->rate = wm831x_fll_auto_rates[best];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm831x_fll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -214,7 +216,7 @@ static const struct clk_ops wm831x_fll_ops = {
|
||||
.is_prepared = wm831x_fll_is_prepared,
|
||||
.prepare = wm831x_fll_prepare,
|
||||
.unprepare = wm831x_fll_unprepare,
|
||||
.round_rate = wm831x_fll_round_rate,
|
||||
.determine_rate = wm831x_fll_determine_rate,
|
||||
.recalc_rate = wm831x_fll_recalc_rate,
|
||||
.set_rate = wm831x_fll_set_rate,
|
||||
.get_parent = wm831x_fll_get_parent,
|
||||
|
||||
@@ -271,23 +271,28 @@ static unsigned long xgene_clk_pmd_recalc_rate(struct clk_hw *hw,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long xgene_clk_pmd_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int xgene_clk_pmd_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct xgene_clk_pmd *fd = to_xgene_clk_pmd(hw);
|
||||
u64 ret, scale;
|
||||
|
||||
if (!rate || rate >= *parent_rate)
|
||||
return *parent_rate;
|
||||
if (!req->rate || req->rate >= req->best_parent_rate) {
|
||||
req->rate = req->best_parent_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* freq = parent_rate * scaler / denom */
|
||||
ret = rate * fd->denom;
|
||||
scale = DIV_ROUND_UP_ULL(ret, *parent_rate);
|
||||
ret = req->rate * fd->denom;
|
||||
scale = DIV_ROUND_UP_ULL(ret, req->best_parent_rate);
|
||||
|
||||
ret = (u64)*parent_rate * scale;
|
||||
ret = (u64)req->best_parent_rate * scale;
|
||||
do_div(ret, fd->denom);
|
||||
|
||||
return ret;
|
||||
req->rate = ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xgene_clk_pmd_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -333,7 +338,7 @@ static int xgene_clk_pmd_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops xgene_clk_pmd_ops = {
|
||||
.recalc_rate = xgene_clk_pmd_recalc_rate,
|
||||
.round_rate = xgene_clk_pmd_round_rate,
|
||||
.determine_rate = xgene_clk_pmd_determine_rate,
|
||||
.set_rate = xgene_clk_pmd_set_rate,
|
||||
};
|
||||
|
||||
@@ -593,23 +598,25 @@ static int xgene_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
return parent_rate / divider_save;
|
||||
}
|
||||
|
||||
static long xgene_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static int xgene_clk_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct xgene_clk *pclk = to_xgene_clk(hw);
|
||||
unsigned long parent_rate = *prate;
|
||||
unsigned long parent_rate = req->best_parent_rate;
|
||||
u32 divider;
|
||||
|
||||
if (pclk->param.divider_reg) {
|
||||
/* Let's compute the divider */
|
||||
if (rate > parent_rate)
|
||||
rate = parent_rate;
|
||||
divider = parent_rate / rate; /* Rounded down */
|
||||
if (req->rate > parent_rate)
|
||||
req->rate = parent_rate;
|
||||
divider = parent_rate / req->rate; /* Rounded down */
|
||||
} else {
|
||||
divider = 1;
|
||||
}
|
||||
|
||||
return parent_rate / divider;
|
||||
req->rate = parent_rate / divider;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops xgene_clk_ops = {
|
||||
@@ -618,7 +625,7 @@ static const struct clk_ops xgene_clk_ops = {
|
||||
.is_enabled = xgene_clk_is_enabled,
|
||||
.recalc_rate = xgene_clk_recalc_rate,
|
||||
.set_rate = xgene_clk_set_rate,
|
||||
.round_rate = xgene_clk_round_rate,
|
||||
.determine_rate = xgene_clk_determine_rate,
|
||||
};
|
||||
|
||||
static struct clk *xgene_register_clk(struct device *dev,
|
||||
|
||||
@@ -6,21 +6,24 @@
|
||||
* Standard functionality for the common clock API. See Documentation/driver-api/clk.rst
|
||||
*/
|
||||
|
||||
#include <linux/clk/clk-conf.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk/clk-conf.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/hashtable.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/stringhash.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
@@ -33,6 +36,9 @@ static struct task_struct *enable_owner;
|
||||
static int prepare_refcnt;
|
||||
static int enable_refcnt;
|
||||
|
||||
#define CLK_HASH_BITS 9
|
||||
static DEFINE_HASHTABLE(clk_hashtable, CLK_HASH_BITS);
|
||||
|
||||
static HLIST_HEAD(clk_root_list);
|
||||
static HLIST_HEAD(clk_orphan_list);
|
||||
static LIST_HEAD(clk_notifier_list);
|
||||
@@ -87,6 +93,7 @@ struct clk_core {
|
||||
struct clk_duty duty;
|
||||
struct hlist_head children;
|
||||
struct hlist_node child_node;
|
||||
struct hlist_node hashtable_node;
|
||||
struct hlist_head clks;
|
||||
unsigned int notifier_count;
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
@@ -395,45 +402,20 @@ struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_hw_get_parent);
|
||||
|
||||
static struct clk_core *__clk_lookup_subtree(const char *name,
|
||||
struct clk_core *core)
|
||||
{
|
||||
struct clk_core *child;
|
||||
struct clk_core *ret;
|
||||
|
||||
if (!strcmp(core->name, name))
|
||||
return core;
|
||||
|
||||
hlist_for_each_entry(child, &core->children, child_node) {
|
||||
ret = __clk_lookup_subtree(name, child);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct clk_core *clk_core_lookup(const char *name)
|
||||
{
|
||||
struct clk_core *root_clk;
|
||||
struct clk_core *ret;
|
||||
struct clk_core *core;
|
||||
u32 hash;
|
||||
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
/* search the 'proper' clk tree first */
|
||||
hlist_for_each_entry(root_clk, &clk_root_list, child_node) {
|
||||
ret = __clk_lookup_subtree(name, root_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
hash = full_name_hash(NULL, name, strlen(name));
|
||||
|
||||
/* if not found, then search the orphan tree */
|
||||
hlist_for_each_entry(root_clk, &clk_orphan_list, child_node) {
|
||||
ret = __clk_lookup_subtree(name, root_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
/* search the hashtable */
|
||||
hash_for_each_possible(clk_hashtable, core, hashtable_node, hash)
|
||||
if (!strcmp(core->name, name))
|
||||
return core;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -4013,6 +3995,8 @@ static int __clk_core_init(struct clk_core *core)
|
||||
hlist_add_head(&core->child_node, &clk_orphan_list);
|
||||
core->orphan = true;
|
||||
}
|
||||
hash_add(clk_hashtable, &core->hashtable_node,
|
||||
full_name_hash(NULL, core->name, strlen(core->name)));
|
||||
|
||||
/*
|
||||
* Set clk's accuracy. The preferred method is to use
|
||||
@@ -4089,6 +4073,7 @@ out:
|
||||
clk_pm_runtime_put(core);
|
||||
unlock:
|
||||
if (ret) {
|
||||
hash_del(&core->hashtable_node);
|
||||
hlist_del_init(&core->child_node);
|
||||
core->hw->core = NULL;
|
||||
}
|
||||
@@ -4610,6 +4595,7 @@ void clk_unregister(struct clk *clk)
|
||||
|
||||
clk_core_evict_parent_cache(clk->core);
|
||||
|
||||
hash_del(&clk->core->hashtable_node);
|
||||
hlist_del_init(&clk->core->child_node);
|
||||
|
||||
if (clk->core->prepare_count)
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
.num_parents = 0, \
|
||||
.flags = CLK_GET_RATE_NOCACHE, \
|
||||
}, \
|
||||
},
|
||||
}
|
||||
|
||||
#define to_stub_clk(_hw) container_of(_hw, struct hi3660_stub_clk, hw)
|
||||
|
||||
@@ -67,14 +67,14 @@ static unsigned long hi3660_stub_clk_recalc_rate(struct clk_hw *hw,
|
||||
return stub_clk->rate;
|
||||
}
|
||||
|
||||
static long hi3660_stub_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static int hi3660_stub_clk_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
/*
|
||||
* LPM3 handles rate rounding so just return whatever
|
||||
* rate is requested.
|
||||
*/
|
||||
return rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hi3660_stub_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -97,15 +97,15 @@ static int hi3660_stub_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops hi3660_stub_clk_ops = {
|
||||
.recalc_rate = hi3660_stub_clk_recalc_rate,
|
||||
.round_rate = hi3660_stub_clk_round_rate,
|
||||
.determine_rate = hi3660_stub_clk_determine_rate,
|
||||
.set_rate = hi3660_stub_clk_set_rate,
|
||||
};
|
||||
|
||||
static struct hi3660_stub_clk hi3660_stub_clks[HI3660_CLK_STUB_NUM] = {
|
||||
DEFINE_CLK_STUB(HI3660_CLK_STUB_CLUSTER0, 0x0001030A, "cpu-cluster.0")
|
||||
DEFINE_CLK_STUB(HI3660_CLK_STUB_CLUSTER1, 0x0002030A, "cpu-cluster.1")
|
||||
DEFINE_CLK_STUB(HI3660_CLK_STUB_GPU, 0x0003030A, "clk-g3d")
|
||||
DEFINE_CLK_STUB(HI3660_CLK_STUB_DDR, 0x00040309, "clk-ddrc")
|
||||
DEFINE_CLK_STUB(HI3660_CLK_STUB_CLUSTER0, 0x0001030A, "cpu-cluster.0"),
|
||||
DEFINE_CLK_STUB(HI3660_CLK_STUB_CLUSTER1, 0x0002030A, "cpu-cluster.1"),
|
||||
DEFINE_CLK_STUB(HI3660_CLK_STUB_GPU, 0x0003030A, "clk-g3d"),
|
||||
DEFINE_CLK_STUB(HI3660_CLK_STUB_DDR, 0x00040309, "clk-ddrc"),
|
||||
};
|
||||
|
||||
static struct clk_hw *hi3660_stub_clk_hw_get(struct of_phandle_args *clkspec,
|
||||
|
||||
@@ -161,11 +161,11 @@ static int hi6220_stub_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long hi6220_stub_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static int hi6220_stub_clk_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct hi6220_stub_clk *stub_clk = to_stub_clk(hw);
|
||||
unsigned long new_rate = rate / 1000; /* kHz */
|
||||
unsigned long new_rate = req->rate / 1000; /* kHz */
|
||||
|
||||
switch (stub_clk->id) {
|
||||
case HI6220_STUB_ACPU0:
|
||||
@@ -181,12 +181,14 @@ static long hi6220_stub_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
break;
|
||||
}
|
||||
|
||||
return new_rate;
|
||||
req->rate = new_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops hi6220_stub_clk_ops = {
|
||||
.recalc_rate = hi6220_stub_clk_recalc_rate,
|
||||
.round_rate = hi6220_stub_clk_round_rate,
|
||||
.determine_rate = hi6220_stub_clk_determine_rate,
|
||||
.set_rate = hi6220_stub_clk_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -55,13 +55,15 @@ static unsigned long hi6220_clkdiv_recalc_rate(struct clk_hw *hw,
|
||||
CLK_DIVIDER_ROUND_CLOSEST, dclk->width);
|
||||
}
|
||||
|
||||
static long hi6220_clkdiv_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
static int hi6220_clkdiv_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw);
|
||||
|
||||
return divider_round_rate(hw, rate, prate, dclk->table,
|
||||
dclk->width, CLK_DIVIDER_ROUND_CLOSEST);
|
||||
req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, dclk->table,
|
||||
dclk->width, CLK_DIVIDER_ROUND_CLOSEST);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hi6220_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -93,7 +95,7 @@ static int hi6220_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops hi6220_clkdiv_ops = {
|
||||
.recalc_rate = hi6220_clkdiv_recalc_rate,
|
||||
.round_rate = hi6220_clkdiv_round_rate,
|
||||
.determine_rate = hi6220_clkdiv_determine_rate,
|
||||
.set_rate = hi6220_clkdiv_set_rate,
|
||||
};
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ struct imx95_blk_ctl {
|
||||
void __iomem *base;
|
||||
/* clock gate register */
|
||||
u32 clk_reg_restore;
|
||||
const struct imx95_blk_ctl_dev_data *pdata;
|
||||
};
|
||||
|
||||
struct imx95_blk_ctl_clk_dev_data {
|
||||
@@ -349,7 +350,6 @@ static const struct imx95_blk_ctl_dev_data imx94_dispmix_csr_dev_data = {
|
||||
static int imx95_bc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct imx95_blk_ctl_dev_data *bc_data;
|
||||
struct imx95_blk_ctl *bc;
|
||||
struct clk_hw_onecell_data *clk_hw_data;
|
||||
struct clk_hw **hws;
|
||||
@@ -379,25 +379,25 @@ static int imx95_bc_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
bc_data = of_device_get_match_data(dev);
|
||||
if (!bc_data)
|
||||
bc->pdata = of_device_get_match_data(dev);
|
||||
if (!bc->pdata)
|
||||
return devm_of_platform_populate(dev);
|
||||
|
||||
clk_hw_data = devm_kzalloc(dev, struct_size(clk_hw_data, hws, bc_data->num_clks),
|
||||
clk_hw_data = devm_kzalloc(dev, struct_size(clk_hw_data, hws, bc->pdata->num_clks),
|
||||
GFP_KERNEL);
|
||||
if (!clk_hw_data)
|
||||
return -ENOMEM;
|
||||
|
||||
if (bc_data->rpm_enabled) {
|
||||
if (bc->pdata->rpm_enabled) {
|
||||
devm_pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_resume_and_get(&pdev->dev);
|
||||
}
|
||||
|
||||
clk_hw_data->num = bc_data->num_clks;
|
||||
clk_hw_data->num = bc->pdata->num_clks;
|
||||
hws = clk_hw_data->hws;
|
||||
|
||||
for (i = 0; i < bc_data->num_clks; i++) {
|
||||
const struct imx95_blk_ctl_clk_dev_data *data = &bc_data->clk_dev_data[i];
|
||||
for (i = 0; i < bc->pdata->num_clks; i++) {
|
||||
const struct imx95_blk_ctl_clk_dev_data *data = &bc->pdata->clk_dev_data[i];
|
||||
void __iomem *reg = base + data->reg;
|
||||
|
||||
if (data->type == CLK_MUX) {
|
||||
@@ -439,7 +439,7 @@ static int imx95_bc_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
for (i = 0; i < bc_data->num_clks; i++) {
|
||||
for (i = 0; i < bc->pdata->num_clks; i++) {
|
||||
if (IS_ERR_OR_NULL(hws[i]))
|
||||
continue;
|
||||
clk_hw_unregister(hws[i]);
|
||||
@@ -453,15 +453,24 @@ static int imx95_bc_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct imx95_blk_ctl *bc = dev_get_drvdata(dev);
|
||||
|
||||
bc->clk_reg_restore = readl(bc->base + bc->pdata->clk_reg_offset);
|
||||
clk_disable_unprepare(bc->clk_apb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx95_bc_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct imx95_blk_ctl *bc = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
return clk_prepare_enable(bc->clk_apb);
|
||||
ret = clk_prepare_enable(bc->clk_apb);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
writel(bc->clk_reg_restore, bc->base + bc->pdata->clk_reg_offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -469,22 +478,12 @@ static int imx95_bc_runtime_resume(struct device *dev)
|
||||
static int imx95_bc_suspend(struct device *dev)
|
||||
{
|
||||
struct imx95_blk_ctl *bc = dev_get_drvdata(dev);
|
||||
const struct imx95_blk_ctl_dev_data *bc_data;
|
||||
int ret;
|
||||
|
||||
bc_data = of_device_get_match_data(dev);
|
||||
if (!bc_data)
|
||||
if (pm_runtime_suspended(dev))
|
||||
return 0;
|
||||
|
||||
if (bc_data->rpm_enabled) {
|
||||
ret = pm_runtime_get_sync(bc->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(bc->dev);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
bc->clk_reg_restore = readl(bc->base + bc_data->clk_reg_offset);
|
||||
bc->clk_reg_restore = readl(bc->base + bc->pdata->clk_reg_offset);
|
||||
clk_disable_unprepare(bc->clk_apb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -492,16 +491,16 @@ static int imx95_bc_suspend(struct device *dev)
|
||||
static int imx95_bc_resume(struct device *dev)
|
||||
{
|
||||
struct imx95_blk_ctl *bc = dev_get_drvdata(dev);
|
||||
const struct imx95_blk_ctl_dev_data *bc_data;
|
||||
int ret;
|
||||
|
||||
bc_data = of_device_get_match_data(dev);
|
||||
if (!bc_data)
|
||||
if (pm_runtime_suspended(dev))
|
||||
return 0;
|
||||
|
||||
writel(bc->clk_reg_restore, bc->base + bc_data->clk_reg_offset);
|
||||
ret = clk_prepare_enable(bc->clk_apb);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (bc_data->rpm_enabled)
|
||||
pm_runtime_put(bc->dev);
|
||||
writel(bc->clk_reg_restore, bc->base + bc->pdata->clk_reg_offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -174,14 +174,16 @@ ingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info,
|
||||
n * od);
|
||||
}
|
||||
|
||||
static long
|
||||
ingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate,
|
||||
unsigned long *prate)
|
||||
static int ingenic_pll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
|
||||
const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
|
||||
|
||||
return ingenic_pll_calc(clk_info, req_rate, *prate, NULL, NULL, NULL);
|
||||
req->rate = ingenic_pll_calc(clk_info, req->rate, req->best_parent_rate,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ingenic_pll_check_stable(struct ingenic_cgu *cgu,
|
||||
@@ -317,7 +319,7 @@ static int ingenic_pll_is_enabled(struct clk_hw *hw)
|
||||
|
||||
static const struct clk_ops ingenic_pll_ops = {
|
||||
.recalc_rate = ingenic_pll_recalc_rate,
|
||||
.round_rate = ingenic_pll_round_rate,
|
||||
.determine_rate = ingenic_pll_determine_rate,
|
||||
.set_rate = ingenic_pll_set_rate,
|
||||
|
||||
.enable = ingenic_pll_enable,
|
||||
|
||||
@@ -128,19 +128,19 @@ static unsigned long jz4780_otg_phy_recalc_rate(struct clk_hw *hw,
|
||||
return parent_rate;
|
||||
}
|
||||
|
||||
static long jz4780_otg_phy_round_rate(struct clk_hw *hw, unsigned long req_rate,
|
||||
unsigned long *parent_rate)
|
||||
static int jz4780_otg_phy_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
if (req_rate < 15600000)
|
||||
return 12000000;
|
||||
if (req->rate < 15600000)
|
||||
req->rate = 12000000;
|
||||
else if (req->rate < 21600000)
|
||||
req->rate = 19200000;
|
||||
else if (req->rate < 36000000)
|
||||
req->rate = 24000000;
|
||||
else
|
||||
req->rate = 48000000;
|
||||
|
||||
if (req_rate < 21600000)
|
||||
return 19200000;
|
||||
|
||||
if (req_rate < 36000000)
|
||||
return 24000000;
|
||||
|
||||
return 48000000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jz4780_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate,
|
||||
@@ -212,7 +212,7 @@ static int jz4780_otg_phy_is_enabled(struct clk_hw *hw)
|
||||
|
||||
static const struct clk_ops jz4780_otg_phy_ops = {
|
||||
.recalc_rate = jz4780_otg_phy_recalc_rate,
|
||||
.round_rate = jz4780_otg_phy_round_rate,
|
||||
.determine_rate = jz4780_otg_phy_determine_rate,
|
||||
.set_rate = jz4780_otg_phy_set_rate,
|
||||
|
||||
.enable = jz4780_otg_phy_enable,
|
||||
|
||||
@@ -84,16 +84,17 @@ static unsigned long x1000_otg_phy_recalc_rate(struct clk_hw *hw,
|
||||
return parent_rate;
|
||||
}
|
||||
|
||||
static long x1000_otg_phy_round_rate(struct clk_hw *hw, unsigned long req_rate,
|
||||
unsigned long *parent_rate)
|
||||
static int x1000_otg_phy_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
if (req_rate < 18000000)
|
||||
return 12000000;
|
||||
if (req->rate < 18000000)
|
||||
req->rate = 12000000;
|
||||
else if (req->rate < 36000000)
|
||||
req->rate = 24000000;
|
||||
else
|
||||
req->rate = 48000000;
|
||||
|
||||
if (req_rate < 36000000)
|
||||
return 24000000;
|
||||
|
||||
return 48000000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int x1000_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate,
|
||||
@@ -161,7 +162,7 @@ static int x1000_usb_phy_is_enabled(struct clk_hw *hw)
|
||||
|
||||
static const struct clk_ops x1000_otg_phy_ops = {
|
||||
.recalc_rate = x1000_otg_phy_recalc_rate,
|
||||
.round_rate = x1000_otg_phy_round_rate,
|
||||
.determine_rate = x1000_otg_phy_determine_rate,
|
||||
.set_rate = x1000_otg_phy_set_rate,
|
||||
|
||||
.enable = x1000_usb_phy_enable,
|
||||
|
||||
@@ -480,13 +480,10 @@ static int ti_sci_scan_clocks_from_fw(struct sci_clk_provider *provider)
|
||||
num_clks++;
|
||||
}
|
||||
|
||||
provider->clocks = devm_kmalloc_array(dev, num_clks, sizeof(sci_clk),
|
||||
GFP_KERNEL);
|
||||
provider->clocks = devm_kmemdup_array(dev, clks, num_clks, sizeof(sci_clk), GFP_KERNEL);
|
||||
if (!provider->clocks)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(provider->clocks, clks, num_clks * sizeof(sci_clk));
|
||||
|
||||
provider->num_clocks = num_clks;
|
||||
|
||||
devm_kfree(dev, clks);
|
||||
|
||||
@@ -1002,6 +1002,77 @@ config COMMON_CLK_MT8195_VENCSYS
|
||||
help
|
||||
This driver supports MediaTek MT8195 vencsys clocks.
|
||||
|
||||
config COMMON_CLK_MT8196
|
||||
tristate "Clock driver for MediaTek MT8196"
|
||||
depends on ARM64 || COMPILE_TEST
|
||||
select COMMON_CLK_MEDIATEK
|
||||
default ARCH_MEDIATEK
|
||||
help
|
||||
This driver supports MediaTek MT8196 basic clocks.
|
||||
|
||||
config COMMON_CLK_MT8196_IMP_IIC_WRAP
|
||||
tristate "Clock driver for MediaTek MT8196 imp_iic_wrap"
|
||||
depends on COMMON_CLK_MT8196
|
||||
default COMMON_CLK_MT8196
|
||||
help
|
||||
This driver supports MediaTek MT8196 i2c clocks.
|
||||
|
||||
config COMMON_CLK_MT8196_MCUSYS
|
||||
tristate "Clock driver for MediaTek MT8196 mcusys"
|
||||
depends on COMMON_CLK_MT8196
|
||||
default COMMON_CLK_MT8196
|
||||
help
|
||||
This driver supports MediaTek MT8196 mcusys clocks.
|
||||
|
||||
config COMMON_CLK_MT8196_MDPSYS
|
||||
tristate "Clock driver for MediaTek MT8196 mdpsys"
|
||||
depends on COMMON_CLK_MT8196
|
||||
default COMMON_CLK_MT8196
|
||||
help
|
||||
This driver supports MediaTek MT8196 mdpsys clocks.
|
||||
|
||||
config COMMON_CLK_MT8196_MFGCFG
|
||||
tristate "Clock driver for MediaTek MT8196 mfgcfg"
|
||||
depends on COMMON_CLK_MT8196
|
||||
default m
|
||||
help
|
||||
This driver supports MediaTek MT8196 mfgcfg clocks.
|
||||
|
||||
config COMMON_CLK_MT8196_MMSYS
|
||||
tristate "Clock driver for MediaTek MT8196 mmsys"
|
||||
depends on COMMON_CLK_MT8196
|
||||
default m
|
||||
help
|
||||
This driver supports MediaTek MT8196 mmsys clocks.
|
||||
|
||||
config COMMON_CLK_MT8196_PEXTPSYS
|
||||
tristate "Clock driver for MediaTek MT8196 pextpsys"
|
||||
depends on COMMON_CLK_MT8196
|
||||
default COMMON_CLK_MT8196
|
||||
help
|
||||
This driver supports MediaTek MT8196 pextpsys clocks.
|
||||
|
||||
config COMMON_CLK_MT8196_UFSSYS
|
||||
tristate "Clock driver for MediaTek MT8196 ufssys"
|
||||
depends on COMMON_CLK_MT8196
|
||||
default COMMON_CLK_MT8196
|
||||
help
|
||||
This driver supports MediaTek MT8196 ufssys clocks.
|
||||
|
||||
config COMMON_CLK_MT8196_VDECSYS
|
||||
tristate "Clock driver for MediaTek MT8196 vdecsys"
|
||||
depends on COMMON_CLK_MT8196
|
||||
default m
|
||||
help
|
||||
This driver supports MediaTek MT8196 vdecsys clocks.
|
||||
|
||||
config COMMON_CLK_MT8196_VENCSYS
|
||||
tristate "Clock driver for MediaTek MT8196 vencsys"
|
||||
depends on COMMON_CLK_MT8196
|
||||
default m
|
||||
help
|
||||
This driver supports MediaTek MT8196 vencsys clocks.
|
||||
|
||||
config COMMON_CLK_MT8365
|
||||
tristate "Clock driver for MediaTek MT8365"
|
||||
depends on ARCH_MEDIATEK || COMPILE_TEST
|
||||
|
||||
@@ -150,6 +150,19 @@ obj-$(CONFIG_COMMON_CLK_MT8195_VDOSYS) += clk-mt8195-vdo0.o clk-mt8195-vdo1.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT8195_VENCSYS) += clk-mt8195-venc.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT8195_VPPSYS) += clk-mt8195-vpp0.o clk-mt8195-vpp1.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT8195_WPESYS) += clk-mt8195-wpe.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT8196) += clk-mt8196-apmixedsys.o clk-mt8196-topckgen.o \
|
||||
clk-mt8196-topckgen2.o clk-mt8196-vlpckgen.o \
|
||||
clk-mt8196-peri_ao.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT8196_IMP_IIC_WRAP) += clk-mt8196-imp_iic_wrap.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT8196_MCUSYS) += clk-mt8196-mcu.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT8196_MDPSYS) += clk-mt8196-mdpsys.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT8196_MFGCFG) += clk-mt8196-mfg.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT8196_MMSYS) += clk-mt8196-disp0.o clk-mt8196-disp1.o clk-mt8196-vdisp_ao.o \
|
||||
clk-mt8196-ovl0.o clk-mt8196-ovl1.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT8196_PEXTPSYS) += clk-mt8196-pextp.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT8196_UFSSYS) += clk-mt8196-ufs_ao.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT8196_VDECSYS) += clk-mt8196-vdec.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT8196_VENCSYS) += clk-mt8196-venc.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT8365_APU) += clk-mt8365-apu.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT8365_CAM) += clk-mt8365-cam.o
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/printk.h>
|
||||
@@ -12,15 +13,14 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "clk-mtk.h"
|
||||
#include "clk-gate.h"
|
||||
|
||||
struct mtk_clk_gate {
|
||||
struct clk_hw hw;
|
||||
struct regmap *regmap;
|
||||
int set_ofs;
|
||||
int clr_ofs;
|
||||
int sta_ofs;
|
||||
u8 bit;
|
||||
struct regmap *regmap_hwv;
|
||||
const struct mtk_gate *gate;
|
||||
};
|
||||
|
||||
static inline struct mtk_clk_gate *to_mtk_clk_gate(struct clk_hw *hw)
|
||||
@@ -33,9 +33,9 @@ static u32 mtk_get_clockgating(struct clk_hw *hw)
|
||||
struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
|
||||
u32 val;
|
||||
|
||||
regmap_read(cg->regmap, cg->sta_ofs, &val);
|
||||
regmap_read(cg->regmap, cg->gate->regs->sta_ofs, &val);
|
||||
|
||||
return val & BIT(cg->bit);
|
||||
return val & BIT(cg->gate->shift);
|
||||
}
|
||||
|
||||
static int mtk_cg_bit_is_cleared(struct clk_hw *hw)
|
||||
@@ -52,28 +52,30 @@ static void mtk_cg_set_bit(struct clk_hw *hw)
|
||||
{
|
||||
struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
|
||||
|
||||
regmap_write(cg->regmap, cg->set_ofs, BIT(cg->bit));
|
||||
regmap_write(cg->regmap, cg->gate->regs->set_ofs, BIT(cg->gate->shift));
|
||||
}
|
||||
|
||||
static void mtk_cg_clr_bit(struct clk_hw *hw)
|
||||
{
|
||||
struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
|
||||
|
||||
regmap_write(cg->regmap, cg->clr_ofs, BIT(cg->bit));
|
||||
regmap_write(cg->regmap, cg->gate->regs->clr_ofs, BIT(cg->gate->shift));
|
||||
}
|
||||
|
||||
static void mtk_cg_set_bit_no_setclr(struct clk_hw *hw)
|
||||
{
|
||||
struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
|
||||
|
||||
regmap_set_bits(cg->regmap, cg->sta_ofs, BIT(cg->bit));
|
||||
regmap_set_bits(cg->regmap, cg->gate->regs->sta_ofs,
|
||||
BIT(cg->gate->shift));
|
||||
}
|
||||
|
||||
static void mtk_cg_clr_bit_no_setclr(struct clk_hw *hw)
|
||||
{
|
||||
struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
|
||||
|
||||
regmap_clear_bits(cg->regmap, cg->sta_ofs, BIT(cg->bit));
|
||||
regmap_clear_bits(cg->regmap, cg->gate->regs->sta_ofs,
|
||||
BIT(cg->gate->shift));
|
||||
}
|
||||
|
||||
static int mtk_cg_enable(struct clk_hw *hw)
|
||||
@@ -100,6 +102,32 @@ static void mtk_cg_disable_inv(struct clk_hw *hw)
|
||||
mtk_cg_clr_bit(hw);
|
||||
}
|
||||
|
||||
static int mtk_cg_hwv_set_en(struct clk_hw *hw, bool enable)
|
||||
{
|
||||
struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
|
||||
u32 val;
|
||||
|
||||
regmap_write(cg->regmap_hwv,
|
||||
enable ? cg->gate->hwv_regs->set_ofs :
|
||||
cg->gate->hwv_regs->clr_ofs,
|
||||
BIT(cg->gate->shift));
|
||||
|
||||
return regmap_read_poll_timeout_atomic(cg->regmap_hwv,
|
||||
cg->gate->hwv_regs->sta_ofs, val,
|
||||
val & BIT(cg->gate->shift), 0,
|
||||
MTK_WAIT_HWV_DONE_US);
|
||||
}
|
||||
|
||||
static int mtk_cg_hwv_enable(struct clk_hw *hw)
|
||||
{
|
||||
return mtk_cg_hwv_set_en(hw, true);
|
||||
}
|
||||
|
||||
static void mtk_cg_hwv_disable(struct clk_hw *hw)
|
||||
{
|
||||
mtk_cg_hwv_set_en(hw, false);
|
||||
}
|
||||
|
||||
static int mtk_cg_enable_no_setclr(struct clk_hw *hw)
|
||||
{
|
||||
mtk_cg_clr_bit_no_setclr(hw);
|
||||
@@ -124,6 +152,15 @@ static void mtk_cg_disable_inv_no_setclr(struct clk_hw *hw)
|
||||
mtk_cg_clr_bit_no_setclr(hw);
|
||||
}
|
||||
|
||||
static bool mtk_cg_uses_hwv(const struct clk_ops *ops)
|
||||
{
|
||||
if (ops == &mtk_clk_gate_hwv_ops_setclr ||
|
||||
ops == &mtk_clk_gate_hwv_ops_setclr_inv)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const struct clk_ops mtk_clk_gate_ops_setclr = {
|
||||
.is_enabled = mtk_cg_bit_is_cleared,
|
||||
.enable = mtk_cg_enable,
|
||||
@@ -138,6 +175,20 @@ const struct clk_ops mtk_clk_gate_ops_setclr_inv = {
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_setclr_inv);
|
||||
|
||||
const struct clk_ops mtk_clk_gate_hwv_ops_setclr = {
|
||||
.is_enabled = mtk_cg_bit_is_cleared,
|
||||
.enable = mtk_cg_hwv_enable,
|
||||
.disable = mtk_cg_hwv_disable,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(mtk_clk_gate_hwv_ops_setclr);
|
||||
|
||||
const struct clk_ops mtk_clk_gate_hwv_ops_setclr_inv = {
|
||||
.is_enabled = mtk_cg_bit_is_set,
|
||||
.enable = mtk_cg_hwv_enable,
|
||||
.disable = mtk_cg_hwv_disable,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(mtk_clk_gate_hwv_ops_setclr_inv);
|
||||
|
||||
const struct clk_ops mtk_clk_gate_ops_no_setclr = {
|
||||
.is_enabled = mtk_cg_bit_is_cleared,
|
||||
.enable = mtk_cg_enable_no_setclr,
|
||||
@@ -152,12 +203,10 @@ const struct clk_ops mtk_clk_gate_ops_no_setclr_inv = {
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_no_setclr_inv);
|
||||
|
||||
static struct clk_hw *mtk_clk_register_gate(struct device *dev, const char *name,
|
||||
const char *parent_name,
|
||||
struct regmap *regmap, int set_ofs,
|
||||
int clr_ofs, int sta_ofs, u8 bit,
|
||||
const struct clk_ops *ops,
|
||||
unsigned long flags)
|
||||
static struct clk_hw *mtk_clk_register_gate(struct device *dev,
|
||||
const struct mtk_gate *gate,
|
||||
struct regmap *regmap,
|
||||
struct regmap *regmap_hwv)
|
||||
{
|
||||
struct mtk_clk_gate *cg;
|
||||
int ret;
|
||||
@@ -167,18 +216,19 @@ static struct clk_hw *mtk_clk_register_gate(struct device *dev, const char *name
|
||||
if (!cg)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.flags = flags | CLK_SET_RATE_PARENT;
|
||||
init.parent_names = parent_name ? &parent_name : NULL;
|
||||
init.num_parents = parent_name ? 1 : 0;
|
||||
init.ops = ops;
|
||||
init.name = gate->name;
|
||||
init.flags = gate->flags | CLK_SET_RATE_PARENT;
|
||||
init.parent_names = gate->parent_name ? &gate->parent_name : NULL;
|
||||
init.num_parents = gate->parent_name ? 1 : 0;
|
||||
init.ops = gate->ops;
|
||||
if (mtk_cg_uses_hwv(init.ops) && !regmap_hwv)
|
||||
return dev_err_ptr_probe(
|
||||
dev, -ENXIO,
|
||||
"regmap not found for hardware voter clocks\n");
|
||||
|
||||
cg->regmap = regmap;
|
||||
cg->set_ofs = set_ofs;
|
||||
cg->clr_ofs = clr_ofs;
|
||||
cg->sta_ofs = sta_ofs;
|
||||
cg->bit = bit;
|
||||
|
||||
cg->regmap_hwv = regmap_hwv;
|
||||
cg->gate = gate;
|
||||
cg->hw.init = &init;
|
||||
|
||||
ret = clk_hw_register(dev, &cg->hw);
|
||||
@@ -209,6 +259,7 @@ int mtk_clk_register_gates(struct device *dev, struct device_node *node,
|
||||
int i;
|
||||
struct clk_hw *hw;
|
||||
struct regmap *regmap;
|
||||
struct regmap *regmap_hwv;
|
||||
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
@@ -219,6 +270,12 @@ int mtk_clk_register_gates(struct device *dev, struct device_node *node,
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
regmap_hwv = mtk_clk_get_hwv_regmap(node);
|
||||
if (IS_ERR(regmap_hwv))
|
||||
return dev_err_probe(
|
||||
dev, PTR_ERR(regmap_hwv),
|
||||
"Cannot find hardware voter regmap for %pOF\n", node);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
const struct mtk_gate *gate = &clks[i];
|
||||
|
||||
@@ -228,13 +285,7 @@ int mtk_clk_register_gates(struct device *dev, struct device_node *node,
|
||||
continue;
|
||||
}
|
||||
|
||||
hw = mtk_clk_register_gate(dev, gate->name, gate->parent_name,
|
||||
regmap,
|
||||
gate->regs->set_ofs,
|
||||
gate->regs->clr_ofs,
|
||||
gate->regs->sta_ofs,
|
||||
gate->shift, gate->ops,
|
||||
gate->flags);
|
||||
hw = mtk_clk_register_gate(dev, gate, regmap, regmap_hwv);
|
||||
|
||||
if (IS_ERR(hw)) {
|
||||
pr_err("Failed to register clk %s: %pe\n", gate->name,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user