The core framework got some nice improvements this time around. We gained the
ability to get struct clk pointers from a struct clk_hw so that clk providers can consume the clks they provide, if they need to do something like that. This has been a long missing part of the clk provider API that will help us move away from exposing a struct clk pointer in the struct clk_hw. Tracepoints are added for the clk_set_rate() "range" functions, similar to the tracepoints we already have for clk_set_rate() and we added a column to debugfs to help developers understand the hardware enable state of clks in case firmware or bootloader state is different than what is expected. Overall the core changes are mostly improving the clk driver writing experience. At the driver level, we have the usual collection of driver updates and new drivers for new SoCs. This time around the Qualcomm folks introduced a good handful of clk drivers for various parts of three or four SoCs. The SiFive folks added a new clk driver for their FU740 SoCs, coming in second on the diffstat and then Atmel AT91 and Amlogic SoCs had lots of work done after that for various new features. One last thing to note in the driver area is that the i.MX driver has gained a new binding to support SCU clks after being on the list for many months. It uses a two cell binding which is sort of rare in clk DT bindings. Beyond that we have the usual set of driver fixes and tweaks that come from more testing and finding out that some configuration was wrong or that a driver could support being built as a module. Core: - Add some trace points for clk_set_rate() "range" functions - Add hardware enable information to clk_summary debugfs - Replace clk-provider.h with of_clk.h when possible - Add devm variant of clk_notifier_register() - Add clk_hw_get_clk() to generate a struct clk from a struct clk_hw New Drivers: - Bindings for Canaan K210 SoC clks - Support for SiFive FU740 PRCI - Camera clks on Qualcomm SC7180 SoCs - GCC and RPMh clks on Qualcomm SDX55 SoCs - RPMh clks on Qualcomm SM8350 SoCs - LPASS clks on Qualcomm SM8250 SoCs Updates: - DVFS support for AT91 clk driver - Update git repo branch for Renesas clock drivers - Add camera (CSI) and video-in (VIN) clocks on Renesas R-Car V3U - Add RPC (QSPI/HyperFLASH) clocks on Renesas RZ/G2M, RZ/G2N, and RZ/G2E - Stop using __raw_*() I/O accessors in Renesas clk drivers - One more conversion of DT bindings to json-schema - Make i.MX clk-gate2 driver more flexible - New two cell binding for i.MX SCU clks - Drop of_match_ptr() in i.MX8 clk drivers - Add arch dependencies for Rockchip clk drivers - Fix i2s on Rockchip rk3066 - Add MIPI DSI clks on Amlogic axg and g12 SoCs - Support modular builds of Amlogic clk drivers - Fix an Amlogic Video PLL clock dependency - Samsung Kconfig dependencies updates for better compile test coverage - Refactoring of the Samsung PLL clocks driver - Small Tegra driver cleanups - Minor fixes to Ingenic and VC5 clk drivers - Cleanup patches to remove unused variables and plug memory leaks -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEE9L57QeeUxqYDyoaDrQKIl8bklSUFAl/f/ycRHHNib3lkQGtl cm5lbC5vcmcACgkQrQKIl8bklSXjxg/7BJMFphpZmQb3iy/lZMYfgPh2yxZvrrBj zJ2i1mMru/C3BkXTx29HCJvj6/VC2HgGLL6fzfwe7oY3XVRT1Vxlsvka9vNZSNc2 UYNa8GUwR0mSXDzp5KnzoAQfLwvSqWUIeT8WB+Z+CJ7WIAGWnXgBlqsf/d/mr9hg JoAh+ROpbksL6hs61WJSm+7/Yu6efS0Yj0zzLZOINFWvDIOJ+Rp4g1u+qGH9tZyO I2Bik75Sc8hqvLUP5SVzI/1H4yLB0On+ADgVRwjvrKPVX56alYquOUMsU+sy4SeY ONQBki3vV5gtJHG1qvkwTC5/Yw20eUsrmrc7PNECvb1zo5Tp4QuOAR5nHCb4fg8u n7RRd1MktTAUAQxTzBaNYtix3Q19fjSR44C/1B6lKk6xkN+w4uYLi2GHrADy9rXa SwQVTKTGc8LjGywDaAOXdAyx2FMAtt1OvkTxZ238+aoHw5nQDHWKxu5TwYK6b5jG aEFzTCIEYlzRLqcZyGONSD0WXmQWyoNiPwJ3B7RDRfpg7dPESyKIB4MzGWiX9eDy lri/SoVH08c1sRf8AzIoi+CUNi8geTNAHHlJfiGznrv81ttVf3FioWyWLjr+SmBV rNxn35WxeDWoCZqtrLJlg5skVgmD8BRXLZTI9udPG8u6D7OdWdJBuMZ6EelO+OZg /n4w8tdo3cE= =Wt9O -----END PGP SIGNATURE----- Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux Pull clk updates from Stephen Boyd: "The core framework got some nice improvements this time around. We gained the ability to get struct clk pointers from a struct clk_hw so that clk providers can consume the clks they provide, if they need to do something like that. This has been a long missing part of the clk provider API that will help us move away from exposing a struct clk pointer in the struct clk_hw. Tracepoints are added for the clk_set_rate() "range" functions, similar to the tracepoints we already have for clk_set_rate() and we added a column to debugfs to help developers understand the hardware enable state of clks in case firmware or bootloader state is different than what is expected. Overall the core changes are mostly improving the clk driver writing experience. At the driver level, we have the usual collection of driver updates and new drivers for new SoCs. This time around the Qualcomm folks introduced a good handful of clk drivers for various parts of three or four SoCs. The SiFive folks added a new clk driver for their FU740 SoCs, coming in second on the diffstat and then Atmel AT91 and Amlogic SoCs had lots of work done after that for various new features. One last thing to note in the driver area is that the i.MX driver has gained a new binding to support SCU clks after being on the list for many months. It uses a two cell binding which is sort of rare in clk DT bindings. Beyond that we have the usual set of driver fixes and tweaks that come from more testing and finding out that some configuration was wrong or that a driver could support being built as a module. Summary: Core: - Add some trace points for clk_set_rate() "range" functions - Add hardware enable information to clk_summary debugfs - Replace clk-provider.h with of_clk.h when possible - Add devm variant of clk_notifier_register() - Add clk_hw_get_clk() to generate a struct clk from a struct clk_hw New Drivers: - Bindings for Canaan K210 SoC clks - Support for SiFive FU740 PRCI - Camera clks on Qualcomm SC7180 SoCs - GCC and RPMh clks on Qualcomm SDX55 SoCs - RPMh clks on Qualcomm SM8350 SoCs - LPASS clks on Qualcomm SM8250 SoCs Updates: - DVFS support for AT91 clk driver - Update git repo branch for Renesas clock drivers - Add camera (CSI) and video-in (VIN) clocks on Renesas R-Car V3U - Add RPC (QSPI/HyperFLASH) clocks on Renesas RZ/G2M, RZ/G2N, and RZ/G2E - Stop using __raw_*() I/O accessors in Renesas clk drivers - One more conversion of DT bindings to json-schema - Make i.MX clk-gate2 driver more flexible - New two cell binding for i.MX SCU clks - Drop of_match_ptr() in i.MX8 clk drivers - Add arch dependencies for Rockchip clk drivers - Fix i2s on Rockchip rk3066 - Add MIPI DSI clks on Amlogic axg and g12 SoCs - Support modular builds of Amlogic clk drivers - Fix an Amlogic Video PLL clock dependency - Samsung Kconfig dependencies updates for better compile test coverage - Refactoring of the Samsung PLL clocks driver - Small Tegra driver cleanups - Minor fixes to Ingenic and VC5 clk drivers - Cleanup patches to remove unused variables and plug memory leaks" * tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (134 commits) dt-binding: clock: Document canaan,k210-clk bindings dt-bindings: Add Canaan vendor prefix clk: vc5: Use "idt,voltage-microvolt" instead of "idt,voltage-microvolts" clk: ingenic: Fix divider calculation with div tables clk: sunxi-ng: Make sure divider tables have sentinel clk: s2mps11: Fix a resource leak in error handling paths in the probe function clk: mvebu: a3700: fix the XTAL MODE pin to MPP1_9 clk: si5351: Wait for bit clear after PLL reset clk: at91: sam9x60: remove atmel,osc-bypass support clk: at91: sama7g5: register cpu clock clk: at91: clk-master: re-factor master clock clk: at91: sama7g5: do not allow cpu pll to go higher than 1GHz clk: at91: sama7g5: decrease lower limit for MCK0 rate clk: at91: sama7g5: remove mck0 from parent list of other clocks clk: at91: clk-sam9x60-pll: allow runtime changes for pll clk: at91: sama7g5: add 5th divisor for mck0 layout and characteristics clk: at91: clk-master: add 5th divisor for mck master clk: at91: sama7g5: allow SYS and CPU PLLs to be exported and referenced in DT dt-bindings: clock: at91: add sama7g5 pll defines clk: at91: sama7g5: fix compilation error ...
This commit is contained in:
commit
8653b778e4
|
@ -0,0 +1,53 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/adi,axi-clkgen.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Binding for Analog Devices AXI clkgen pcore clock generator
|
||||
|
||||
maintainers:
|
||||
- Lars-Peter Clausen <lars@metafoo.de>
|
||||
- Michael Hennerich <michael.hennerich@analog.com>
|
||||
|
||||
description: |
|
||||
The axi_clkgen IP core is a software programmable clock generator,
|
||||
that can be synthesized on various FPGA platforms.
|
||||
|
||||
Link: https://wiki.analog.com/resources/fpga/docs/axi_clkgen
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,axi-clkgen-2.00.a
|
||||
|
||||
clocks:
|
||||
description:
|
||||
Specifies the reference clock(s) from which the output frequency is
|
||||
derived. This must either reference one clock if only the first clock
|
||||
input is connected or two if both clock inputs are connected.
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
'#clock-cells':
|
||||
const: 0
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- '#clock-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
clock-controller@ff000000 {
|
||||
compatible = "adi,axi-clkgen-2.00.a";
|
||||
#clock-cells = <0>;
|
||||
reg = <0xff000000 0x1000>;
|
||||
clocks = <&osc 1>;
|
||||
};
|
|
@ -1,25 +0,0 @@
|
|||
Binding for the axi-clkgen clock generator
|
||||
|
||||
This binding uses the common clock binding[1].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
Required properties:
|
||||
- compatible : shall be "adi,axi-clkgen-1.00.a" or "adi,axi-clkgen-2.00.a".
|
||||
- #clock-cells : from common clock binding; Should always be set to 0.
|
||||
- reg : Address and length of the axi-clkgen register set.
|
||||
- clocks : Phandle and clock specifier for the parent clock(s). This must
|
||||
either reference one clock if only the first clock input is connected or two
|
||||
if both clock inputs are connected. For the later case the clock connected
|
||||
to the first input must be specified first.
|
||||
|
||||
Optional properties:
|
||||
- clock-output-names : From common clock binding.
|
||||
|
||||
Example:
|
||||
clock@ff000000 {
|
||||
compatible = "adi,axi-clkgen";
|
||||
#clock-cells = <0>;
|
||||
reg = <0xff000000 0x1000>;
|
||||
clocks = <&osc 1>;
|
||||
};
|
|
@ -0,0 +1,54 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/canaan,k210-clk.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Canaan Kendryte K210 Clock Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Damien Le Moal <damien.lemoal@wdc.com>
|
||||
|
||||
description: |
|
||||
Canaan Kendryte K210 SoC clocks driver bindings. The clock
|
||||
controller node must be defined as a child node of the K210
|
||||
system controller node.
|
||||
|
||||
See also:
|
||||
- dt-bindings/clock/k210-clk.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: canaan,k210-clk
|
||||
|
||||
clocks:
|
||||
description:
|
||||
Phandle of the SoC 26MHz fixed-rate oscillator clock.
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- '#clock-cells'
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/k210-clk.h>
|
||||
clocks {
|
||||
in0: oscillator {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <26000000>;
|
||||
};
|
||||
};
|
||||
|
||||
/* ... */
|
||||
sysclk: clock-controller {
|
||||
#clock-cells = <1>;
|
||||
compatible = "canaan,k210-clk";
|
||||
clocks = <&in0>;
|
||||
};
|
|
@ -0,0 +1,55 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/fsl,flexspi-clock.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Freescale FlexSPI clock driver for Layerscape SoCs
|
||||
|
||||
maintainers:
|
||||
- Michael Walle <michael@walle.cc>
|
||||
|
||||
description:
|
||||
The Freescale Layerscape SoCs have a special FlexSPI clock which is
|
||||
derived from the platform PLL.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,ls1028a-flexspi-clk
|
||||
- fsl,lx2160a-flexspi-clk
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
'#clock-cells':
|
||||
const: 0
|
||||
|
||||
clock-output-names:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- '#clock-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
dcfg {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
fspi_clk: clock-controller@900 {
|
||||
compatible = "fsl,ls1028a-flexspi-clk";
|
||||
reg = <0x900 0x4>;
|
||||
#clock-cells = <0>;
|
||||
clocks = <&parentclk>;
|
||||
clock-output-names = "fspi_clk";
|
||||
};
|
||||
};
|
|
@ -0,0 +1,58 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,aoncc-sm8250.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Clock bindings for LPASS Always ON Clock Controller on SM8250 SoCs
|
||||
|
||||
maintainers:
|
||||
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
|
||||
|
||||
description: |
|
||||
The clock consumer should specify the desired clock by having the clock
|
||||
ID in its "clocks" phandle cell.
|
||||
See include/dt-bindings/clock/qcom,sm8250-lpass-aoncc.h for the full list
|
||||
of Audio Clock controller clock IDs.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,sm8250-lpass-aon
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: LPASS Core voting clock
|
||||
- description: Glitch Free Mux register clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: core
|
||||
- const: bus
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,sm8250-lpass-aoncc.h>
|
||||
#include <dt-bindings/sound/qcom,q6afe.h>
|
||||
clock-controller@3800000 {
|
||||
#clock-cells = <1>;
|
||||
compatible = "qcom,sm8250-lpass-aon";
|
||||
reg = <0x03380000 0x40000>;
|
||||
clocks = <&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
|
||||
<&q6afecc LPASS_CLK_ID_TX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
|
||||
clock-names = "core", "bus";
|
||||
};
|
|
@ -0,0 +1,58 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,audiocc-sm8250.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Clock bindings for LPASS Audio Clock Controller on SM8250 SoCs
|
||||
|
||||
maintainers:
|
||||
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
|
||||
|
||||
description: |
|
||||
The clock consumer should specify the desired clock by having the clock
|
||||
ID in its "clocks" phandle cell.
|
||||
See include/dt-bindings/clock/qcom,sm8250-lpass-audiocc.h for the full list
|
||||
of Audio Clock controller clock IDs.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,sm8250-lpass-audiocc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: LPASS Core voting clock
|
||||
- description: Glitch Free Mux register clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: core
|
||||
- const: bus
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,sm8250-lpass-audiocc.h>
|
||||
#include <dt-bindings/sound/qcom,q6afe.h>
|
||||
clock-controller@3300000 {
|
||||
#clock-cells = <1>;
|
||||
compatible = "qcom,sm8250-lpass-audiocc";
|
||||
reg = <0x03300000 0x30000>;
|
||||
clocks = <&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
|
||||
<&q6afecc LPASS_CLK_ID_TX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
|
||||
clock-names = "core", "bus";
|
||||
};
|
|
@ -0,0 +1,77 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,gcc-sdx55.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Global Clock & Reset Controller Binding for SDX55
|
||||
|
||||
maintainers:
|
||||
- Vinod Koul <vkoul@kernel.org>
|
||||
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
description: |
|
||||
Qualcomm global clock control module which supports the clocks, resets and
|
||||
power domains on SDX55
|
||||
|
||||
See also:
|
||||
- dt-bindings/clock/qcom,gcc-sdx55.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,gcc-sdx55
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Board XO source
|
||||
- description: Sleep clock source
|
||||
- description: PLL test clock source (Optional clock)
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: bi_tcxo
|
||||
- const: sleep_clk
|
||||
- const: core_bi_pll_test_se # Optional clock
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- clock-names
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- '#power-domain-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
clock-controller@100000 {
|
||||
compatible = "qcom,gcc-sdx55";
|
||||
reg = <0x00100000 0x1f0000>;
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>,
|
||||
<&sleep_clk>, <&pll_test_clk>;
|
||||
clock-names = "bi_tcxo", "sleep_clk", "core_bi_pll_test_se";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
|
||||
...
|
|
@ -19,8 +19,10 @@ properties:
|
|||
enum:
|
||||
- qcom,sc7180-rpmh-clk
|
||||
- qcom,sdm845-rpmh-clk
|
||||
- qcom,sdx55-rpmh-clk
|
||||
- qcom,sm8150-rpmh-clk
|
||||
- qcom,sm8250-rpmh-clk
|
||||
- qcom,sm8350-rpmh-clk
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,sc7180-camcc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Camera Clock & Reset Controller Binding for SC7180
|
||||
|
||||
maintainers:
|
||||
- Taniya Das <tdas@codeaurora.org>
|
||||
|
||||
description: |
|
||||
Qualcomm camera clock control module which supports the clocks, resets and
|
||||
power domains on SC7180.
|
||||
|
||||
See also:
|
||||
- dt-bindings/clock/qcom,camcc-sc7180.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,sc7180-camcc
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Board XO source
|
||||
- description: Camera_ahb clock from GCC
|
||||
- description: Camera XO clock from GCC
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: bi_tcxo
|
||||
- const: iface
|
||||
- const: xo
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- '#power-domain-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,gcc-sc7180.h>
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
clock-controller@ad00000 {
|
||||
compatible = "qcom,sc7180-camcc";
|
||||
reg = <0x0ad00000 0x10000>;
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>,
|
||||
<&gcc GCC_CAMERA_AHB_CLK>,
|
||||
<&gcc GCC_CAMERA_XO_CLK>;
|
||||
clock-names = "bi_tcxo", "iface", "xo";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
...
|
|
@ -1,68 +0,0 @@
|
|||
* Renesas R-Car USB 2.0 clock selector
|
||||
|
||||
This file provides information on what the device node for the R-Car USB 2.0
|
||||
clock selector.
|
||||
|
||||
If you connect an external clock to the USB_EXTAL pin only, you should set
|
||||
the clock rate to "usb_extal" node only.
|
||||
If you connect an oscillator to both the USB_XTAL and USB_EXTAL, this module
|
||||
is not needed because this is default setting. (Of course, you can set the
|
||||
clock rates to both "usb_extal" and "usb_xtal" nodes.
|
||||
|
||||
Case 1: An external clock connects to R-Car SoC
|
||||
+----------+ +--- R-Car ---------------------+
|
||||
|External |---|USB_EXTAL ---> all usb channels|
|
||||
|clock | |USB_XTAL |
|
||||
+----------+ +-------------------------------+
|
||||
In this case, we need this driver with "usb_extal" clock.
|
||||
|
||||
Case 2: An oscillator connects to R-Car SoC
|
||||
+----------+ +--- R-Car ---------------------+
|
||||
|Oscillator|---|USB_EXTAL -+-> all usb channels|
|
||||
| |---|USB_XTAL --+ |
|
||||
+----------+ +-------------------------------+
|
||||
In this case, we don't need this selector.
|
||||
|
||||
Required properties:
|
||||
- compatible: "renesas,r8a7795-rcar-usb2-clock-sel" if the device is a part of
|
||||
an R8A7795 SoC.
|
||||
"renesas,r8a7796-rcar-usb2-clock-sel" if the device if a part of
|
||||
an R8A77960 SoC.
|
||||
"renesas,r8a77961-rcar-usb2-clock-sel" if the device if a part of
|
||||
an R8A77961 SoC.
|
||||
"renesas,rcar-gen3-usb2-clock-sel" for a generic R-Car Gen3
|
||||
compatible device.
|
||||
|
||||
When compatible with the generic version, nodes must list the
|
||||
SoC-specific version corresponding to the platform first
|
||||
followed by the generic version.
|
||||
|
||||
- reg: offset and length of the USB 2.0 clock selector register block.
|
||||
- clocks: A list of phandles and specifier pairs.
|
||||
- clock-names: Name of the clocks.
|
||||
- The functional clock of USB 2.0 host side must be "ehci_ohci"
|
||||
- The functional clock of HS-USB side must be "hs-usb-if"
|
||||
- The USB_EXTAL clock pin must be "usb_extal"
|
||||
- The USB_XTAL clock pin must be "usb_xtal"
|
||||
- #clock-cells: Must be 0
|
||||
- power-domains: A phandle and symbolic PM domain specifier.
|
||||
See power/renesas,rcar-sysc.yaml.
|
||||
- resets: A list of phandles and specifier pairs.
|
||||
- reset-names: Name of the resets.
|
||||
- The reset of USB 2.0 host side must be "ehci_ohci"
|
||||
- The reset of HS-USB side must be "hs-usb-if"
|
||||
|
||||
Example (R-Car H3):
|
||||
|
||||
usb2_clksel: clock-controller@e6590630 {
|
||||
compatible = "renesas,r8a7795-rcar-usb2-clock-sel",
|
||||
"renesas,rcar-gen3-usb2-clock-sel";
|
||||
reg = <0 0xe6590630 0 0x02>;
|
||||
clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>,
|
||||
<&usb_extal>, <&usb_xtal>;
|
||||
clock-names = "ehci_ohci", "hs-usb-if", "usb_extal", "usb_xtal";
|
||||
#clock-cells = <0>;
|
||||
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 703>, <&cpg 704>;
|
||||
reset-names = "ehci_ohci", "hs-usb-if";
|
||||
};
|
|
@ -0,0 +1,100 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/clock/renesas,rcar-usb2-clock-sel.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: Renesas R-Car USB 2.0 clock selector
|
||||
|
||||
maintainers:
|
||||
- Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
||||
|
||||
description: |
|
||||
If you connect an external clock to the USB_EXTAL pin only, you should set
|
||||
the clock rate to "usb_extal" node only.
|
||||
If you connect an oscillator to both the USB_XTAL and USB_EXTAL, this module
|
||||
is not needed because this is default setting. (Of course, you can set the
|
||||
clock rates to both "usb_extal" and "usb_xtal" nodes.
|
||||
|
||||
Case 1: An external clock connects to R-Car SoC
|
||||
+----------+ +--- R-Car ---------------------+
|
||||
|External |---|USB_EXTAL ---> all usb channels|
|
||||
|clock | |USB_XTAL |
|
||||
+----------+ +-------------------------------+
|
||||
|
||||
In this case, we need this driver with "usb_extal" clock.
|
||||
|
||||
Case 2: An oscillator connects to R-Car SoC
|
||||
+----------+ +--- R-Car ---------------------+
|
||||
|Oscillator|---|USB_EXTAL -+-> all usb channels|
|
||||
| |---|USB_XTAL --+ |
|
||||
+----------+ +-------------------------------+
|
||||
In this case, we don't need this selector.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- renesas,r8a7795-rcar-usb2-clock-sel # R-Car H3
|
||||
- renesas,r8a7796-rcar-usb2-clock-sel # R-Car M3-W
|
||||
- renesas,r8a77961-rcar-usb2-clock-sel # R-Car M3-W+
|
||||
- const: renesas,rcar-gen3-usb2-clock-sel
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ehci_ohci
|
||||
- const: hs-usb-if
|
||||
- const: usb_extal
|
||||
- const: usb_xtal
|
||||
|
||||
'#clock-cells':
|
||||
const: 0
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: ehci_ohci
|
||||
- const: hs-usb-if
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#clock-cells'
|
||||
- power-domains
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r8a7795-cpg-mssr.h>
|
||||
#include <dt-bindings/power/r8a7795-sysc.h>
|
||||
|
||||
usb2_clksel: clock-controller@e6590630 {
|
||||
compatible = "renesas,r8a7795-rcar-usb2-clock-sel",
|
||||
"renesas,rcar-gen3-usb2-clock-sel";
|
||||
reg = <0xe6590630 0x02>;
|
||||
clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>,
|
||||
<&usb_extal>, <&usb_xtal>;
|
||||
clock-names = "ehci_ohci", "hs-usb-if", "usb_extal", "usb_xtal";
|
||||
#clock-cells = <0>;
|
||||
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 703>, <&cpg 704>;
|
||||
reset-names = "ehci_ohci", "hs-usb-if";
|
||||
};
|
|
@ -0,0 +1,60 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) 2020 SiFive, Inc.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/sifive/fu740-prci.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: SiFive FU740 Power Reset Clock Interrupt Controller (PRCI)
|
||||
|
||||
maintainers:
|
||||
- Zong Li <zong.li@sifive.com>
|
||||
- Paul Walmsley <paul.walmsley@sifive.com>
|
||||
|
||||
description:
|
||||
On the FU740 family of SoCs, most system-wide clock and reset integration
|
||||
is via the PRCI IP block.
|
||||
The clock consumer should specify the desired clock via the clock ID
|
||||
macros defined in include/dt-bindings/clock/sifive-fu740-prci.h.
|
||||
These macros begin with PRCI_CLK_.
|
||||
|
||||
The hfclk and rtcclk nodes are required, and represent physical
|
||||
crystals or resonators located on the PCB. These nodes should be present
|
||||
underneath /, rather than /soc.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: sifive,fu740-c000-prci
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: high frequency clock.
|
||||
- description: RTL clock.
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: hfclk
|
||||
- const: rtcclk
|
||||
|
||||
"#clock-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- "#clock-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
prci: clock-controller@10000000 {
|
||||
compatible = "sifive,fu740-c000-prci";
|
||||
reg = <0x10000000 0x1000>;
|
||||
clocks = <&hfclk>, <&rtcclk>;
|
||||
#clock-cells = <1>;
|
||||
};
|
|
@ -187,6 +187,8 @@ patternProperties:
|
|||
description: CALAO Systems SAS
|
||||
"^calxeda,.*":
|
||||
description: Calxeda
|
||||
"^canaan,.*":
|
||||
description: Canaan, Inc.
|
||||
"^caninos,.*":
|
||||
description: Caninos Loucos Program
|
||||
"^capella,.*":
|
||||
|
|
|
@ -15108,7 +15108,7 @@ RENESAS CLOCK DRIVERS
|
|||
M: Geert Uytterhoeven <geert+renesas@glider.be>
|
||||
L: linux-renesas-soc@vger.kernel.org
|
||||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git clk-renesas
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git renesas-clk
|
||||
F: Documentation/devicetree/bindings/clock/renesas,*
|
||||
F: drivers/clk/renesas/
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ config SOC_SIFIVE
|
|||
select SERIAL_SIFIVE if TTY
|
||||
select SERIAL_SIFIVE_CONSOLE if TTY
|
||||
select CLK_SIFIVE
|
||||
select CLK_SIFIVE_FU540_PRCI
|
||||
select CLK_SIFIVE_PRCI
|
||||
select SIFIVE_PLIC
|
||||
help
|
||||
This enables support for SiFive SoC platform hardware.
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
*/
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_clk.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <asm/machvec.h>
|
||||
#include <asm/rtc.h>
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of_clk.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/time.h>
|
||||
|
|
|
@ -188,6 +188,14 @@ config COMMON_CLK_CS2000_CP
|
|||
help
|
||||
If you say yes here you get support for the CS2000 clock multiplier.
|
||||
|
||||
config COMMON_CLK_FSL_FLEXSPI
|
||||
tristate "Clock driver for FlexSPI on Layerscape SoCs"
|
||||
depends on ARCH_LAYERSCAPE || COMPILE_TEST
|
||||
default ARCH_LAYERSCAPE && SPI_NXP_FLEXSPI
|
||||
help
|
||||
On Layerscape SoCs there is a special clock for the FlexSPI
|
||||
interface.
|
||||
|
||||
config COMMON_CLK_FSL_SAI
|
||||
bool "Clock driver for BCLK of Freescale SAI cores"
|
||||
depends on ARCH_LAYERSCAPE || COMPILE_TEST
|
||||
|
@ -246,7 +254,8 @@ config COMMON_CLK_AXI_CLKGEN
|
|||
|
||||
config CLK_QORIQ
|
||||
bool "Clock driver for Freescale QorIQ platforms"
|
||||
depends on (PPC_E500MC || ARM || ARM64 || COMPILE_TEST) && OF
|
||||
depends on OF
|
||||
depends on PPC_E500MC || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST
|
||||
help
|
||||
This adds the clock driver support for Freescale QorIQ platforms
|
||||
using common clock framework.
|
||||
|
|
|
@ -30,6 +30,7 @@ obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
|
|||
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
|
||||
obj-$(CONFIG_ARCH_SPARX5) += clk-sparx5.o
|
||||
obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o
|
||||
obj-$(CONFIG_COMMON_CLK_FSL_FLEXSPI) += clk-fsl-flexspi.o
|
||||
obj-$(CONFIG_COMMON_CLK_FSL_SAI) += clk-fsl-sai.o
|
||||
obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o
|
||||
obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-aspeed.o
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "pmc.h"
|
||||
|
||||
static DEFINE_SPINLOCK(rm9200_mck_lock);
|
||||
|
||||
struct sck {
|
||||
char *n;
|
||||
char *p;
|
||||
|
@ -137,9 +139,20 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "pllack";
|
||||
parent_names[3] = "pllbck";
|
||||
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
|
||||
&at91rm9200_master_layout,
|
||||
&rm9200_mck_characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91rm9200_master_layout,
|
||||
&rm9200_mck_characteristics,
|
||||
&rm9200_mck_lock, CLK_SET_RATE_GATE,
|
||||
INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "masterck_div",
|
||||
"masterck_pres",
|
||||
&at91rm9200_master_layout,
|
||||
&rm9200_mck_characteristics,
|
||||
&rm9200_mck_lock, CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -181,7 +194,7 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
|
|||
for (i = 0; i < ARRAY_SIZE(at91rm9200_periphck); i++) {
|
||||
hw = at91_clk_register_peripheral(regmap,
|
||||
at91rm9200_periphck[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
at91rm9200_periphck[i].id);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
|
|
@ -32,6 +32,8 @@ struct at91sam926x_data {
|
|||
bool has_slck;
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(at91sam9260_mck_lock);
|
||||
|
||||
static const struct clk_master_characteristics sam9260_mck_characteristics = {
|
||||
.output = { .min = 0, .max = 105000000 },
|
||||
.divisors = { 1, 2, 4, 0 },
|
||||
|
@ -218,8 +220,8 @@ static const struct sck at91sam9261_systemck[] = {
|
|||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
{ .n = "pck2", .p = "prog2", .id = 10 },
|
||||
{ .n = "pck3", .p = "prog3", .id = 11 },
|
||||
{ .n = "hclk0", .p = "masterck", .id = 16 },
|
||||
{ .n = "hclk1", .p = "masterck", .id = 17 },
|
||||
{ .n = "hclk0", .p = "masterck_div", .id = 16 },
|
||||
{ .n = "hclk1", .p = "masterck_div", .id = 17 },
|
||||
};
|
||||
|
||||
static const struct pck at91sam9261_periphck[] = {
|
||||
|
@ -413,9 +415,21 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "pllack";
|
||||
parent_names[3] = "pllbck";
|
||||
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
|
||||
&at91rm9200_master_layout,
|
||||
data->mck_characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91rm9200_master_layout,
|
||||
data->mck_characteristics,
|
||||
&at91sam9260_mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "masterck_div",
|
||||
"masterck_pres",
|
||||
&at91rm9200_master_layout,
|
||||
data->mck_characteristics,
|
||||
&at91sam9260_mck_lock,
|
||||
CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -457,7 +471,7 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
|
|||
for (i = 0; i < data->num_pck; i++) {
|
||||
hw = at91_clk_register_peripheral(regmap,
|
||||
data->pck[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
data->pck[i].id);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "pmc.h"
|
||||
|
||||
static DEFINE_SPINLOCK(at91sam9g45_mck_lock);
|
||||
|
||||
static const struct clk_master_characteristics mck_characteristics = {
|
||||
.output = { .min = 0, .max = 133333333 },
|
||||
.divisors = { 1, 2, 4, 3 },
|
||||
|
@ -40,10 +42,10 @@ static const struct {
|
|||
char *p;
|
||||
u8 id;
|
||||
} at91sam9g45_systemck[] = {
|
||||
{ .n = "ddrck", .p = "masterck", .id = 2 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
{ .n = "ddrck", .p = "masterck_div", .id = 2 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
};
|
||||
|
||||
struct pck {
|
||||
|
@ -148,9 +150,21 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
|
||||
&at91rm9200_master_layout,
|
||||
&mck_characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91rm9200_master_layout,
|
||||
&mck_characteristics,
|
||||
&at91sam9g45_mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "masterck_div",
|
||||
"masterck_pres",
|
||||
&at91rm9200_master_layout,
|
||||
&mck_characteristics,
|
||||
&at91sam9g45_mck_lock,
|
||||
CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -166,7 +180,7 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
parent_names[4] = "masterck";
|
||||
parent_names[4] = "masterck_div";
|
||||
for (i = 0; i < 2; i++) {
|
||||
char name[6];
|
||||
|
||||
|
@ -195,7 +209,7 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
|
|||
for (i = 0; i < ARRAY_SIZE(at91sam9g45_periphck); i++) {
|
||||
hw = at91_clk_register_peripheral(regmap,
|
||||
at91sam9g45_periphck[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
at91sam9g45_periphck[i].id);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "pmc.h"
|
||||
|
||||
static DEFINE_SPINLOCK(at91sam9n12_mck_lock);
|
||||
|
||||
static const struct clk_master_characteristics mck_characteristics = {
|
||||
.output = { .min = 0, .max = 133333333 },
|
||||
.divisors = { 1, 2, 4, 3 },
|
||||
|
@ -54,12 +56,12 @@ static const struct {
|
|||
char *p;
|
||||
u8 id;
|
||||
} at91sam9n12_systemck[] = {
|
||||
{ .n = "ddrck", .p = "masterck", .id = 2 },
|
||||
{ .n = "lcdck", .p = "masterck", .id = 3 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "udpck", .p = "usbck", .id = 7 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
{ .n = "ddrck", .p = "masterck_div", .id = 2 },
|
||||
{ .n = "lcdck", .p = "masterck_div", .id = 3 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "udpck", .p = "usbck", .id = 7 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
};
|
||||
|
||||
static const struct clk_pcr_layout at91sam9n12_pcr_layout = {
|
||||
|
@ -175,9 +177,21 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "pllbck";
|
||||
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics,
|
||||
&at91sam9n12_mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "masterck_div",
|
||||
"masterck_pres",
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics,
|
||||
&at91sam9n12_mck_lock,
|
||||
CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -191,7 +205,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "pllbck";
|
||||
parent_names[4] = "masterck";
|
||||
parent_names[4] = "masterck_div";
|
||||
for (i = 0; i < 2; i++) {
|
||||
char name[6];
|
||||
|
||||
|
@ -221,7 +235,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
|
|||
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
|
||||
&at91sam9n12_pcr_layout,
|
||||
at91sam9n12_periphck[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
at91sam9n12_periphck[i].id,
|
||||
&range, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "pmc.h"
|
||||
|
||||
static DEFINE_SPINLOCK(sam9rl_mck_lock);
|
||||
|
||||
static const struct clk_master_characteristics sam9rl_mck_characteristics = {
|
||||
.output = { .min = 0, .max = 94000000 },
|
||||
.divisors = { 1, 2, 4, 0 },
|
||||
|
@ -117,9 +119,20 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "pllack";
|
||||
parent_names[3] = "utmick";
|
||||
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
|
||||
&at91rm9200_master_layout,
|
||||
&sam9rl_mck_characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91rm9200_master_layout,
|
||||
&sam9rl_mck_characteristics,
|
||||
&sam9rl_mck_lock, CLK_SET_RATE_GATE,
|
||||
INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "masterck_div",
|
||||
"masterck_pres",
|
||||
&at91rm9200_master_layout,
|
||||
&sam9rl_mck_characteristics,
|
||||
&sam9rl_mck_lock, CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -129,7 +142,7 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "pllack";
|
||||
parent_names[3] = "utmick";
|
||||
parent_names[4] = "masterck";
|
||||
parent_names[4] = "masterck_div";
|
||||
for (i = 0; i < 2; i++) {
|
||||
char name[6];
|
||||
|
||||
|
@ -158,7 +171,7 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
|
|||
for (i = 0; i < ARRAY_SIZE(at91sam9rl_periphck); i++) {
|
||||
hw = at91_clk_register_peripheral(regmap,
|
||||
at91sam9rl_periphck[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
at91sam9rl_periphck[i].id);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "pmc.h"
|
||||
|
||||
static DEFINE_SPINLOCK(mck_lock);
|
||||
|
||||
static const struct clk_master_characteristics mck_characteristics = {
|
||||
.output = { .min = 0, .max = 133333333 },
|
||||
.divisors = { 1, 2, 4, 3 },
|
||||
|
@ -41,7 +43,7 @@ static const struct {
|
|||
char *p;
|
||||
u8 id;
|
||||
} at91sam9x5_systemck[] = {
|
||||
{ .n = "ddrck", .p = "masterck", .id = 2 },
|
||||
{ .n = "ddrck", .p = "masterck_div", .id = 2 },
|
||||
{ .n = "smdck", .p = "smdclk", .id = 4 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "udpck", .p = "usbck", .id = 7 },
|
||||
|
@ -196,9 +198,19 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "masterck_div",
|
||||
"masterck_pres",
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -218,7 +230,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
parent_names[4] = "masterck";
|
||||
parent_names[4] = "masterck_div";
|
||||
for (i = 0; i < 2; i++) {
|
||||
char name[6];
|
||||
|
||||
|
@ -245,7 +257,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
|
|||
}
|
||||
|
||||
if (has_lcdck) {
|
||||
hw = at91_clk_register_system(regmap, "lcdck", "masterck", 3);
|
||||
hw = at91_clk_register_system(regmap, "lcdck", "masterck_div", 3);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -256,7 +268,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
|
|||
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
|
||||
&at91sam9x5_pcr_layout,
|
||||
at91sam9x5_periphck[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
at91sam9x5_periphck[i].id,
|
||||
&range, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
|
@ -269,7 +281,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
|
|||
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
|
||||
&at91sam9x5_pcr_layout,
|
||||
extra_pcks[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
extra_pcks[i].id,
|
||||
&range, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#define MASTER_PRES_MASK 0x7
|
||||
#define MASTER_PRES_MAX MASTER_PRES_MASK
|
||||
#define MASTER_DIV_SHIFT 8
|
||||
#define MASTER_DIV_MASK 0x3
|
||||
#define MASTER_DIV_MASK 0x7
|
||||
|
||||
#define PMC_MCR 0x30
|
||||
#define PMC_MCR_ID_MSK GENMASK(3, 0)
|
||||
|
@ -58,119 +58,153 @@ static inline bool clk_master_ready(struct clk_master *master)
|
|||
static int clk_master_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(master->lock, flags);
|
||||
|
||||
while (!clk_master_ready(master))
|
||||
cpu_relax();
|
||||
|
||||
spin_unlock_irqrestore(master->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_master_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
unsigned long flags;
|
||||
bool status;
|
||||
|
||||
return clk_master_ready(master);
|
||||
spin_lock_irqsave(master->lock, flags);
|
||||
status = clk_master_ready(master);
|
||||
spin_unlock_irqrestore(master->lock, flags);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static unsigned long clk_master_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
static unsigned long clk_master_div_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u8 pres;
|
||||
u8 div;
|
||||
unsigned long rate = parent_rate;
|
||||
unsigned long flags, rate = parent_rate;
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
const struct clk_master_layout *layout = master->layout;
|
||||
const struct clk_master_characteristics *characteristics =
|
||||
master->characteristics;
|
||||
unsigned int mckr;
|
||||
|
||||
spin_lock_irqsave(master->lock, flags);
|
||||
regmap_read(master->regmap, master->layout->offset, &mckr);
|
||||
spin_unlock_irqrestore(master->lock, flags);
|
||||
|
||||
mckr &= layout->mask;
|
||||
|
||||
pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK;
|
||||
div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
|
||||
|
||||
if (characteristics->have_div3_pres && pres == MASTER_PRES_MAX)
|
||||
rate /= 3;
|
||||
else
|
||||
rate >>= pres;
|
||||
|
||||
rate /= characteristics->divisors[div];
|
||||
|
||||
if (rate < characteristics->output.min)
|
||||
pr_warn("master clk is underclocked");
|
||||
pr_warn("master clk div is underclocked");
|
||||
else if (rate > characteristics->output.max)
|
||||
pr_warn("master clk is overclocked");
|
||||
pr_warn("master clk div is overclocked");
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static u8 clk_master_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
unsigned int mckr;
|
||||
|
||||
regmap_read(master->regmap, master->layout->offset, &mckr);
|
||||
|
||||
return mckr & AT91_PMC_CSS;
|
||||
}
|
||||
|
||||
static const struct clk_ops master_ops = {
|
||||
static const struct clk_ops master_div_ops = {
|
||||
.prepare = clk_master_prepare,
|
||||
.is_prepared = clk_master_is_prepared,
|
||||
.recalc_rate = clk_master_recalc_rate,
|
||||
.get_parent = clk_master_get_parent,
|
||||
.recalc_rate = clk_master_div_recalc_rate,
|
||||
};
|
||||
|
||||
struct clk_hw * __init
|
||||
at91_clk_register_master(struct regmap *regmap,
|
||||
const char *name, int num_parents,
|
||||
const char **parent_names,
|
||||
const struct clk_master_layout *layout,
|
||||
const struct clk_master_characteristics *characteristics)
|
||||
{
|
||||
struct clk_master *master;
|
||||
struct clk_init_data init;
|
||||
struct clk_hw *hw;
|
||||
int ret;
|
||||
|
||||
if (!name || !num_parents || !parent_names)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
master = kzalloc(sizeof(*master), GFP_KERNEL);
|
||||
if (!master)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &master_ops;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
init.flags = 0;
|
||||
|
||||
master->hw.init = &init;
|
||||
master->layout = layout;
|
||||
master->characteristics = characteristics;
|
||||
master->regmap = regmap;
|
||||
|
||||
hw = &master->hw;
|
||||
ret = clk_hw_register(NULL, &master->hw);
|
||||
if (ret) {
|
||||
kfree(master);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
clk_sama7g5_master_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
static int clk_master_div_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
const struct clk_master_characteristics *characteristics =
|
||||
master->characteristics;
|
||||
unsigned long flags;
|
||||
int div, i;
|
||||
|
||||
return DIV_ROUND_CLOSEST_ULL(parent_rate, (1 << master->div));
|
||||
div = DIV_ROUND_CLOSEST(parent_rate, rate);
|
||||
if (div > ARRAY_SIZE(characteristics->divisors))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(characteristics->divisors); i++) {
|
||||
if (!characteristics->divisors[i])
|
||||
break;
|
||||
|
||||
if (div == characteristics->divisors[i]) {
|
||||
div = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(characteristics->divisors))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(master->lock, flags);
|
||||
regmap_update_bits(master->regmap, master->layout->offset,
|
||||
(MASTER_DIV_MASK << MASTER_DIV_SHIFT),
|
||||
(div << MASTER_DIV_SHIFT));
|
||||
while (!clk_master_ready(master))
|
||||
cpu_relax();
|
||||
spin_unlock_irqrestore(master->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_master_div_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
const struct clk_master_characteristics *characteristics =
|
||||
master->characteristics;
|
||||
struct clk_hw *parent;
|
||||
unsigned long parent_rate, tmp_rate, best_rate = 0;
|
||||
int i, best_diff = INT_MIN, tmp_diff;
|
||||
|
||||
parent = clk_hw_get_parent(hw);
|
||||
if (!parent)
|
||||
return -EINVAL;
|
||||
|
||||
parent_rate = clk_hw_get_rate(parent);
|
||||
if (!parent_rate)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(characteristics->divisors); i++) {
|
||||
if (!characteristics->divisors[i])
|
||||
break;
|
||||
|
||||
tmp_rate = DIV_ROUND_CLOSEST_ULL(parent_rate,
|
||||
characteristics->divisors[i]);
|
||||
tmp_diff = abs(tmp_rate - req->rate);
|
||||
|
||||
if (!best_rate || best_diff > tmp_diff) {
|
||||
best_diff = tmp_diff;
|
||||
best_rate = tmp_rate;
|
||||
}
|
||||
|
||||
if (!best_diff)
|
||||
break;
|
||||
}
|
||||
|
||||
req->best_parent_rate = best_rate;
|
||||
req->best_parent_hw = parent;
|
||||
req->rate = best_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops master_div_ops_chg = {
|
||||
.prepare = clk_master_prepare,
|
||||
.is_prepared = clk_master_is_prepared,
|
||||
.recalc_rate = clk_master_div_recalc_rate,
|
||||
.determine_rate = clk_master_div_determine_rate,
|
||||
.set_rate = clk_master_div_set_rate,
|
||||
};
|
||||
|
||||
static void clk_sama7g5_master_best_diff(struct clk_rate_request *req,
|
||||
struct clk_hw *parent,
|
||||
unsigned long parent_rate,
|
||||
|
@ -195,6 +229,217 @@ static void clk_sama7g5_master_best_diff(struct clk_rate_request *req,
|
|||
}
|
||||
}
|
||||
|
||||
static int clk_master_pres_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
struct clk_rate_request req_parent = *req;
|
||||
const struct clk_master_characteristics *characteristics =
|
||||
master->characteristics;
|
||||
struct clk_hw *parent;
|
||||
long best_rate = LONG_MIN, best_diff = LONG_MIN;
|
||||
u32 pres;
|
||||
int i;
|
||||
|
||||
if (master->chg_pid < 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
parent = clk_hw_get_parent_by_index(hw, master->chg_pid);
|
||||
if (!parent)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
for (i = 0; i <= MASTER_PRES_MAX; i++) {
|
||||
if (characteristics->have_div3_pres && i == MASTER_PRES_MAX)
|
||||
pres = 3;
|
||||
else
|
||||
pres = 1 << i;
|
||||
|
||||
req_parent.rate = req->rate * pres;
|
||||
if (__clk_determine_rate(parent, &req_parent))
|
||||
continue;
|
||||
|
||||
clk_sama7g5_master_best_diff(req, parent, req_parent.rate,
|
||||
&best_diff, &best_rate, pres);
|
||||
if (!best_diff)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_master_pres_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
unsigned long flags;
|
||||
unsigned int pres;
|
||||
|
||||
pres = DIV_ROUND_CLOSEST(parent_rate, rate);
|
||||
if (pres > MASTER_PRES_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
else if (pres == 3)
|
||||
pres = MASTER_PRES_MAX;
|
||||
else
|
||||
pres = ffs(pres) - 1;
|
||||
|
||||
spin_lock_irqsave(master->lock, flags);
|
||||
regmap_update_bits(master->regmap, master->layout->offset,
|
||||
(MASTER_PRES_MASK << master->layout->pres_shift),
|
||||
(pres << master->layout->pres_shift));
|
||||
|
||||
while (!clk_master_ready(master))
|
||||
cpu_relax();
|
||||
spin_unlock_irqrestore(master->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long clk_master_pres_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
const struct clk_master_characteristics *characteristics =
|
||||
master->characteristics;
|
||||
unsigned long flags;
|
||||
unsigned int val, pres;
|
||||
|
||||
spin_lock_irqsave(master->lock, flags);
|
||||
regmap_read(master->regmap, master->layout->offset, &val);
|
||||
spin_unlock_irqrestore(master->lock, flags);
|
||||
|
||||
pres = (val >> master->layout->pres_shift) & MASTER_PRES_MASK;
|
||||
if (pres == 3 && characteristics->have_div3_pres)
|
||||
pres = 3;
|
||||
else
|
||||
pres = (1 << pres);
|
||||
|
||||
return DIV_ROUND_CLOSEST_ULL(parent_rate, pres);
|
||||
}
|
||||
|
||||
static u8 clk_master_pres_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
unsigned long flags;
|
||||
unsigned int mckr;
|
||||
|
||||
spin_lock_irqsave(master->lock, flags);
|
||||
regmap_read(master->regmap, master->layout->offset, &mckr);
|
||||
spin_unlock_irqrestore(master->lock, flags);
|
||||
|
||||
return mckr & AT91_PMC_CSS;
|
||||
}
|
||||
|
||||
static const struct clk_ops master_pres_ops = {
|
||||
.prepare = clk_master_prepare,
|
||||
.is_prepared = clk_master_is_prepared,
|
||||
.recalc_rate = clk_master_pres_recalc_rate,
|
||||
.get_parent = clk_master_pres_get_parent,
|
||||
};
|
||||
|
||||
static const struct clk_ops master_pres_ops_chg = {
|
||||
.prepare = clk_master_prepare,
|
||||
.is_prepared = clk_master_is_prepared,
|
||||
.determine_rate = clk_master_pres_determine_rate,
|
||||
.recalc_rate = clk_master_pres_recalc_rate,
|
||||
.get_parent = clk_master_pres_get_parent,
|
||||
.set_rate = clk_master_pres_set_rate,
|
||||
};
|
||||
|
||||
static struct clk_hw * __init
|
||||
at91_clk_register_master_internal(struct regmap *regmap,
|
||||
const char *name, int num_parents,
|
||||
const char **parent_names,
|
||||
const struct clk_master_layout *layout,
|
||||
const struct clk_master_characteristics *characteristics,
|
||||
const struct clk_ops *ops, spinlock_t *lock, u32 flags,
|
||||
int chg_pid)
|
||||
{
|
||||
struct clk_master *master;
|
||||
struct clk_init_data init;
|
||||
struct clk_hw *hw;
|
||||
int ret;
|
||||
|
||||
if (!name || !num_parents || !parent_names || !lock)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
master = kzalloc(sizeof(*master), GFP_KERNEL);
|
||||
if (!master)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = ops;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
init.flags = flags;
|
||||
|
||||
master->hw.init = &init;
|
||||
master->layout = layout;
|
||||
master->characteristics = characteristics;
|
||||
master->regmap = regmap;
|
||||
master->chg_pid = chg_pid;
|
||||
master->lock = lock;
|
||||
|
||||
hw = &master->hw;
|
||||
ret = clk_hw_register(NULL, &master->hw);
|
||||
if (ret) {
|
||||
kfree(master);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
struct clk_hw * __init
|
||||
at91_clk_register_master_pres(struct regmap *regmap,
|
||||
const char *name, int num_parents,
|
||||
const char **parent_names,
|
||||
const struct clk_master_layout *layout,
|
||||
const struct clk_master_characteristics *characteristics,
|
||||
spinlock_t *lock, u32 flags, int chg_pid)
|
||||
{
|
||||
const struct clk_ops *ops;
|
||||
|
||||
if (flags & CLK_SET_RATE_GATE)
|
||||
ops = &master_pres_ops;
|
||||
else
|
||||
ops = &master_pres_ops_chg;
|
||||
|
||||
return at91_clk_register_master_internal(regmap, name, num_parents,
|
||||
parent_names, layout,
|
||||
characteristics, ops,
|
||||
lock, flags, chg_pid);
|
||||
}
|
||||
|
||||
struct clk_hw * __init
|
||||
at91_clk_register_master_div(struct regmap *regmap,
|
||||
const char *name, const char *parent_name,
|
||||
const struct clk_master_layout *layout,
|
||||
const struct clk_master_characteristics *characteristics,
|
||||
spinlock_t *lock, u32 flags)
|
||||
{
|
||||
const struct clk_ops *ops;
|
||||
|
||||
if (flags & CLK_SET_RATE_GATE)
|
||||
ops = &master_div_ops;
|
||||
else
|
||||
ops = &master_div_ops_chg;
|
||||
|
||||
return at91_clk_register_master_internal(regmap, name, 1,
|
||||
&parent_name, layout,
|
||||
characteristics, ops,
|
||||
lock, flags, -EINVAL);
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
clk_sama7g5_master_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_master *master = to_clk_master(hw);
|
||||
|
||||
return DIV_ROUND_CLOSEST_ULL(parent_rate, (1 << master->div));
|
||||
}
|
||||
|
||||
static int clk_sama7g5_master_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
|
|
|
@ -229,6 +229,57 @@ static int sam9x60_frac_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
return sam9x60_frac_pll_compute_mul_frac(core, rate, parent_rate, true);
|
||||
}
|
||||
|
||||
static int sam9x60_frac_pll_set_rate_chg(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
|
||||
struct sam9x60_frac *frac = to_sam9x60_frac(core);
|
||||
struct regmap *regmap = core->regmap;
|
||||
unsigned long irqflags;
|
||||
unsigned int val, cfrac, cmul;
|
||||
long ret;
|
||||
|
||||
ret = sam9x60_frac_pll_compute_mul_frac(core, rate, parent_rate, true);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
spin_lock_irqsave(core->lock, irqflags);
|
||||
|
||||
regmap_update_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;
|
||||
|
||||
if (cmul == frac->mul && cfrac == frac->frac)
|
||||
goto unlock;
|
||||
|
||||
regmap_write(regmap, AT91_PMC_PLL_CTRL1,
|
||||
(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_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);
|
||||
|
||||
while (!sam9x60_pll_ready(regmap, core->id))
|
||||
cpu_relax();
|
||||
|
||||
unlock:
|
||||
spin_unlock_irqrestore(core->lock, irqflags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct clk_ops sam9x60_frac_pll_ops = {
|
||||
.prepare = sam9x60_frac_pll_prepare,
|
||||
.unprepare = sam9x60_frac_pll_unprepare,
|
||||
|
@ -238,6 +289,15 @@ static const struct clk_ops sam9x60_frac_pll_ops = {
|
|||
.set_rate = sam9x60_frac_pll_set_rate,
|
||||
};
|
||||
|
||||
static const struct clk_ops sam9x60_frac_pll_ops_chg = {
|
||||
.prepare = sam9x60_frac_pll_prepare,
|
||||
.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,
|
||||
.set_rate = sam9x60_frac_pll_set_rate_chg,
|
||||
};
|
||||
|
||||
static int sam9x60_div_pll_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
|
||||
|
@ -384,6 +444,44 @@ static int sam9x60_div_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sam9x60_div_pll_set_rate_chg(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
|
||||
struct sam9x60_div *div = to_sam9x60_div(core);
|
||||
struct regmap *regmap = core->regmap;
|
||||
unsigned long irqflags;
|
||||
unsigned int val, cdiv;
|
||||
|
||||
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_read(regmap, AT91_PMC_PLL_CTRL0, &val);
|
||||
cdiv = (val & core->layout->div_mask) >> core->layout->div_shift;
|
||||
|
||||
/* Stop if nothing changed. */
|
||||
if (cdiv == div->div)
|
||||
goto unlock;
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,
|
||||
core->layout->div_mask,
|
||||
(div->div << core->layout->div_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);
|
||||
|
||||
while (!sam9x60_pll_ready(regmap, core->id))
|
||||
cpu_relax();
|
||||
|
||||
unlock:
|
||||
spin_unlock_irqrestore(core->lock, irqflags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops sam9x60_div_pll_ops = {
|
||||
.prepare = sam9x60_div_pll_prepare,
|
||||
.unprepare = sam9x60_div_pll_unprepare,
|
||||
|
@ -393,17 +491,26 @@ static const struct clk_ops sam9x60_div_pll_ops = {
|
|||
.set_rate = sam9x60_div_pll_set_rate,
|
||||
};
|
||||
|
||||
static const struct clk_ops sam9x60_div_pll_ops_chg = {
|
||||
.prepare = sam9x60_div_pll_prepare,
|
||||
.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,
|
||||
.set_rate = sam9x60_div_pll_set_rate_chg,
|
||||
};
|
||||
|
||||
struct clk_hw * __init
|
||||
sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
|
||||
const char *name, const char *parent_name,
|
||||
struct clk_hw *parent_hw, u8 id,
|
||||
const struct clk_pll_characteristics *characteristics,
|
||||
const struct clk_pll_layout *layout, bool critical)
|
||||
const struct clk_pll_layout *layout, u32 flags)
|
||||
{
|
||||
struct sam9x60_frac *frac;
|
||||
struct clk_hw *hw;
|
||||
struct clk_init_data init;
|
||||
unsigned long parent_rate, flags;
|
||||
unsigned long parent_rate, irqflags;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
|
@ -417,10 +524,12 @@ sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
|
|||
init.name = name;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
init.ops = &sam9x60_frac_pll_ops;
|
||||
init.flags = CLK_SET_RATE_GATE;
|
||||
if (critical)
|
||||
init.flags |= CLK_IS_CRITICAL;
|
||||
if (flags & CLK_SET_RATE_GATE)
|
||||
init.ops = &sam9x60_frac_pll_ops;
|
||||
else
|
||||
init.ops = &sam9x60_frac_pll_ops_chg;
|
||||
|
||||
init.flags = flags;
|
||||
|
||||
frac->core.id = id;
|
||||
frac->core.hw.init = &init;
|
||||
|
@ -429,7 +538,7 @@ sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
|
|||
frac->core.regmap = regmap;
|
||||
frac->core.lock = lock;
|
||||
|
||||
spin_lock_irqsave(frac->core.lock, flags);
|
||||
spin_lock_irqsave(frac->core.lock, irqflags);
|
||||
if (sam9x60_pll_ready(regmap, id)) {
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_ID_MSK, id);
|
||||
|
@ -457,7 +566,7 @@ sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
|
|||
goto free;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(frac->core.lock, flags);
|
||||
spin_unlock_irqrestore(frac->core.lock, irqflags);
|
||||
|
||||
hw = &frac->core.hw;
|
||||
ret = clk_hw_register(NULL, hw);
|
||||
|
@ -469,7 +578,7 @@ sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
|
|||
return hw;
|
||||
|
||||
free:
|
||||
spin_unlock_irqrestore(frac->core.lock, flags);
|
||||
spin_unlock_irqrestore(frac->core.lock, irqflags);
|
||||
kfree(frac);
|
||||
return hw;
|
||||
}
|
||||
|
@ -478,12 +587,12 @@ struct clk_hw * __init
|
|||
sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock,
|
||||
const char *name, const char *parent_name, u8 id,
|
||||
const struct clk_pll_characteristics *characteristics,
|
||||
const struct clk_pll_layout *layout, bool critical)
|
||||
const struct clk_pll_layout *layout, u32 flags)
|
||||
{
|
||||
struct sam9x60_div *div;
|
||||
struct clk_hw *hw;
|
||||
struct clk_init_data init;
|
||||
unsigned long flags;
|
||||
unsigned long irqflags;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
|
@ -497,11 +606,11 @@ sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock,
|
|||
init.name = name;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
init.ops = &sam9x60_div_pll_ops;
|
||||
init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
|
||||
CLK_SET_RATE_PARENT;
|
||||
if (critical)
|
||||
init.flags |= CLK_IS_CRITICAL;
|
||||
if (flags & CLK_SET_RATE_GATE)
|
||||
init.ops = &sam9x60_div_pll_ops;
|
||||
else
|
||||
init.ops = &sam9x60_div_pll_ops_chg;
|
||||
init.flags = flags;
|
||||
|
||||
div->core.id = id;
|
||||
div->core.hw.init = &init;
|
||||
|
@ -510,14 +619,14 @@ sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock,
|
|||
div->core.regmap = regmap;
|
||||
div->core.lock = lock;
|
||||
|
||||
spin_lock_irqsave(div->core.lock, flags);
|
||||
spin_lock_irqsave(div->core.lock, irqflags);
|
||||
|
||||
regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
|
||||
AT91_PMC_PLL_UPDT_ID_MSK, id);
|
||||
regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);
|
||||
div->div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, val);
|
||||
|
||||
spin_unlock_irqrestore(div->core.lock, flags);
|
||||
spin_unlock_irqrestore(div->core.lock, irqflags);
|
||||
|
||||
hw = &div->core.hw;
|
||||
ret = clk_hw_register(NULL, hw);
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
#define GCK_INDEX_DT_AUDIO_PLL 5
|
||||
|
||||
static DEFINE_SPINLOCK(mck_lock);
|
||||
|
||||
#ifdef CONFIG_HAVE_AT91_AUDIO_PLL
|
||||
static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np)
|
||||
{
|
||||
|
@ -388,9 +390,16 @@ of_at91_clk_master_setup(struct device_node *np,
|
|||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
hw = at91_clk_register_master(regmap, name, num_parents,
|
||||
parent_names, layout,
|
||||
characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", num_parents,
|
||||
parent_names, layout,
|
||||
characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto out_free_characteristics;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, name, "masterck_pres",
|
||||
layout, characteristics,
|
||||
&mck_lock, CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto out_free_characteristics;
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ extern const struct clk_master_layout at91sam9x5_master_layout;
|
|||
|
||||
struct clk_master_characteristics {
|
||||
struct clk_range output;
|
||||
u32 divisors[4];
|
||||
u32 divisors[5];
|
||||
u8 have_div3_pres;
|
||||
};
|
||||
|
||||
|
@ -155,10 +155,18 @@ at91_clk_register_sam9x5_main(struct regmap *regmap, const char *name,
|
|||
const char **parent_names, int num_parents);
|
||||
|
||||
struct clk_hw * __init
|
||||
at91_clk_register_master(struct regmap *regmap, const char *name,
|
||||
int num_parents, const char **parent_names,
|
||||
const struct clk_master_layout *layout,
|
||||
const struct clk_master_characteristics *characteristics);
|
||||
at91_clk_register_master_pres(struct regmap *regmap, const char *name,
|
||||
int num_parents, const char **parent_names,
|
||||
const struct clk_master_layout *layout,
|
||||
const struct clk_master_characteristics *characteristics,
|
||||
spinlock_t *lock, u32 flags, int chg_pid);
|
||||
|
||||
struct clk_hw * __init
|
||||
at91_clk_register_master_div(struct regmap *regmap, const char *name,
|
||||
const char *parent_names,
|
||||
const struct clk_master_layout *layout,
|
||||
const struct clk_master_characteristics *characteristics,
|
||||
spinlock_t *lock, u32 flags);
|
||||
|
||||
struct clk_hw * __init
|
||||
at91_clk_sama7g5_register_master(struct regmap *regmap,
|
||||
|
@ -190,14 +198,14 @@ struct clk_hw * __init
|
|||
sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock,
|
||||
const char *name, const char *parent_name, u8 id,
|
||||
const struct clk_pll_characteristics *characteristics,
|
||||
const struct clk_pll_layout *layout, bool critical);
|
||||
const struct clk_pll_layout *layout, u32 flags);
|
||||
|
||||
struct clk_hw * __init
|
||||
sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
|
||||
const char *name, const char *parent_name,
|
||||
struct clk_hw *parent_hw, u8 id,
|
||||
const struct clk_pll_characteristics *characteristics,
|
||||
const struct clk_pll_layout *layout, bool critical);
|
||||
const struct clk_pll_layout *layout, u32 flags);
|
||||
|
||||
struct clk_hw * __init
|
||||
at91_clk_register_programmable(struct regmap *regmap, const char *name,
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "pmc.h"
|
||||
|
||||
static DEFINE_SPINLOCK(pmc_pll_lock);
|
||||
static DEFINE_SPINLOCK(mck_lock);
|
||||
|
||||
static const struct clk_master_characteristics mck_characteristics = {
|
||||
.output = { .min = 140000000, .max = 200000000 },
|
||||
|
@ -76,11 +77,11 @@ static const struct {
|
|||
char *p;
|
||||
u8 id;
|
||||
} sam9x60_systemck[] = {
|
||||
{ .n = "ddrck", .p = "masterck", .id = 2 },
|
||||
{ .n = "ddrck", .p = "masterck_div", .id = 2 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
{ .n = "qspick", .p = "masterck", .id = 19 },
|
||||
{ .n = "qspick", .p = "masterck_div", .id = 19 },
|
||||
};
|
||||
|
||||
static const struct {
|
||||
|
@ -174,7 +175,6 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
|
|||
struct regmap *regmap;
|
||||
struct clk_hw *hw;
|
||||
int i;
|
||||
bool bypass;
|
||||
|
||||
i = of_property_match_string(np, "clock-names", "td_slck");
|
||||
if (i < 0)
|
||||
|
@ -209,10 +209,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
|
|||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
bypass = of_property_read_bool(np, "atmel,osc-bypass");
|
||||
|
||||
hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
|
||||
bypass);
|
||||
hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, 0);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
main_osc_hw = hw;
|
||||
|
@ -228,13 +225,24 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
|
|||
hw = sam9x60_clk_register_frac_pll(regmap, &pmc_pll_lock, "pllack_fracck",
|
||||
"mainck", sam9x60_pmc->chws[PMC_MAIN],
|
||||
0, &plla_characteristics,
|
||||
&pll_frac_layout, true);
|
||||
&pll_frac_layout,
|
||||
/*
|
||||
* This feeds pllack_divck which
|
||||
* feeds CPU. It should not be
|
||||
* disabled.
|
||||
*/
|
||||
CLK_IS_CRITICAL | CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = sam9x60_clk_register_div_pll(regmap, &pmc_pll_lock, "pllack_divck",
|
||||
"pllack_fracck", 0, &plla_characteristics,
|
||||
&pll_div_layout, true);
|
||||
&pll_div_layout,
|
||||
/*
|
||||
* This feeds CPU. It should not
|
||||
* be disabled.
|
||||
*/
|
||||
CLK_IS_CRITICAL | CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -243,13 +251,16 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
|
|||
hw = sam9x60_clk_register_frac_pll(regmap, &pmc_pll_lock, "upllck_fracck",
|
||||
"main_osc", main_osc_hw, 1,
|
||||
&upll_characteristics,
|
||||
&pll_frac_layout, false);
|
||||
&pll_frac_layout, CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = sam9x60_clk_register_div_pll(regmap, &pmc_pll_lock, "upllck_divck",
|
||||
"upllck_fracck", 1, &upll_characteristics,
|
||||
&pll_div_layout, false);
|
||||
&pll_div_layout,
|
||||
CLK_SET_RATE_GATE |
|
||||
CLK_SET_PARENT_GATE |
|
||||
CLK_SET_RATE_PARENT);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -258,9 +269,17 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
|
|||
parent_names[0] = md_slck_name;
|
||||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "pllack_divck";
|
||||
hw = at91_clk_register_master(regmap, "masterck", 3, parent_names,
|
||||
&sam9x60_master_layout,
|
||||
&mck_characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 3,
|
||||
parent_names, &sam9x60_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "masterck_div",
|
||||
"masterck_pres", &sam9x60_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -276,7 +295,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
|
|||
parent_names[0] = md_slck_name;
|
||||
parent_names[1] = td_slck_name;
|
||||
parent_names[2] = "mainck";
|
||||
parent_names[3] = "masterck";
|
||||
parent_names[3] = "masterck_div";
|
||||
parent_names[4] = "pllack_divck";
|
||||
parent_names[5] = "upllck_divck";
|
||||
for (i = 0; i < 2; i++) {
|
||||
|
@ -308,7 +327,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
|
|||
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
|
||||
&sam9x60_pcr_layout,
|
||||
sam9x60_periphck[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
sam9x60_periphck[i].id,
|
||||
&range, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "pmc.h"
|
||||
|
||||
static DEFINE_SPINLOCK(mck_lock);
|
||||
|
||||
static const struct clk_master_characteristics mck_characteristics = {
|
||||
.output = { .min = 124000000, .max = 166000000 },
|
||||
.divisors = { 1, 2, 4, 3 },
|
||||
|
@ -40,14 +42,14 @@ static const struct {
|
|||
char *p;
|
||||
u8 id;
|
||||
} sama5d2_systemck[] = {
|
||||
{ .n = "ddrck", .p = "masterck", .id = 2 },
|
||||
{ .n = "lcdck", .p = "masterck", .id = 3 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "udpck", .p = "usbck", .id = 7 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
{ .n = "pck2", .p = "prog2", .id = 10 },
|
||||
{ .n = "iscck", .p = "masterck", .id = 18 },
|
||||
{ .n = "ddrck", .p = "masterck_div", .id = 2 },
|
||||
{ .n = "lcdck", .p = "masterck_div", .id = 3 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "udpck", .p = "usbck", .id = 7 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
{ .n = "pck2", .p = "prog2", .id = 10 },
|
||||
{ .n = "iscck", .p = "masterck_div", .id = 18 },
|
||||
};
|
||||
|
||||
static const struct {
|
||||
|
@ -235,15 +237,25 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "masterck_div",
|
||||
"masterck_pres",
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
sama5d2_pmc->chws[PMC_MCK] = hw;
|
||||
|
||||
hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck");
|
||||
hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck_div");
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -259,7 +271,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
parent_names[4] = "masterck";
|
||||
parent_names[4] = "masterck_div";
|
||||
parent_names[5] = "audiopll_pmcck";
|
||||
for (i = 0; i < 3; i++) {
|
||||
char name[6];
|
||||
|
@ -290,7 +302,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
|
|||
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
|
||||
&sama5d2_pcr_layout,
|
||||
sama5d2_periphck[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
sama5d2_periphck[i].id,
|
||||
&range, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
|
@ -317,7 +329,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
parent_names[4] = "masterck";
|
||||
parent_names[4] = "masterck_div";
|
||||
parent_names[5] = "audiopll_pmcck";
|
||||
for (i = 0; i < ARRAY_SIZE(sama5d2_gck); i++) {
|
||||
hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "pmc.h"
|
||||
|
||||
static DEFINE_SPINLOCK(mck_lock);
|
||||
|
||||
static const struct clk_master_characteristics mck_characteristics = {
|
||||
.output = { .min = 0, .max = 166000000 },
|
||||
.divisors = { 1, 2, 4, 3 },
|
||||
|
@ -40,14 +42,14 @@ static const struct {
|
|||
char *p;
|
||||
u8 id;
|
||||
} sama5d3_systemck[] = {
|
||||
{ .n = "ddrck", .p = "masterck", .id = 2 },
|
||||
{ .n = "lcdck", .p = "masterck", .id = 3 },
|
||||
{ .n = "smdck", .p = "smdclk", .id = 4 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "udpck", .p = "usbck", .id = 7 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
{ .n = "pck2", .p = "prog2", .id = 10 },
|
||||
{ .n = "ddrck", .p = "masterck_div", .id = 2 },
|
||||
{ .n = "lcdck", .p = "masterck_div", .id = 3 },
|
||||
{ .n = "smdck", .p = "smdclk", .id = 4 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "udpck", .p = "usbck", .id = 7 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
{ .n = "pck2", .p = "prog2", .id = 10 },
|
||||
};
|
||||
|
||||
static const struct {
|
||||
|
@ -170,9 +172,19 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "masterck_div",
|
||||
"masterck_pres",
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -192,7 +204,7 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
parent_names[4] = "masterck";
|
||||
parent_names[4] = "masterck_div";
|
||||
for (i = 0; i < 3; i++) {
|
||||
char name[6];
|
||||
|
||||
|
@ -222,7 +234,7 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
|
|||
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
|
||||
&sama5d3_pcr_layout,
|
||||
sama5d3_periphck[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
sama5d3_periphck[i].id,
|
||||
&sama5d3_periphck[i].r,
|
||||
INT_MIN);
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "pmc.h"
|
||||
|
||||
static DEFINE_SPINLOCK(mck_lock);
|
||||
|
||||
static const struct clk_master_characteristics mck_characteristics = {
|
||||
.output = { .min = 125000000, .max = 200000000 },
|
||||
.divisors = { 1, 2, 4, 3 },
|
||||
|
@ -39,14 +41,14 @@ static const struct {
|
|||
char *p;
|
||||
u8 id;
|
||||
} sama5d4_systemck[] = {
|
||||
{ .n = "ddrck", .p = "masterck", .id = 2 },
|
||||
{ .n = "lcdck", .p = "masterck", .id = 3 },
|
||||
{ .n = "smdck", .p = "smdclk", .id = 4 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "udpck", .p = "usbck", .id = 7 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
{ .n = "pck2", .p = "prog2", .id = 10 },
|
||||
{ .n = "ddrck", .p = "masterck_div", .id = 2 },
|
||||
{ .n = "lcdck", .p = "masterck_div", .id = 3 },
|
||||
{ .n = "smdck", .p = "smdclk", .id = 4 },
|
||||
{ .n = "uhpck", .p = "usbck", .id = 6 },
|
||||
{ .n = "udpck", .p = "usbck", .id = 7 },
|
||||
{ .n = "pck0", .p = "prog0", .id = 8 },
|
||||
{ .n = "pck1", .p = "prog1", .id = 9 },
|
||||
{ .n = "pck2", .p = "prog2", .id = 10 },
|
||||
};
|
||||
|
||||
static const struct {
|
||||
|
@ -185,15 +187,25 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics);
|
||||
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
|
||||
parent_names,
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "masterck_div",
|
||||
"masterck_pres",
|
||||
&at91sam9x5_master_layout,
|
||||
&mck_characteristics, &mck_lock,
|
||||
CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
sama5d4_pmc->chws[PMC_MCK] = hw;
|
||||
|
||||
hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck");
|
||||
hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck_div");
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -215,7 +227,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
|
|||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "plladivck";
|
||||
parent_names[3] = "utmick";
|
||||
parent_names[4] = "masterck";
|
||||
parent_names[4] = "masterck_div";
|
||||
for (i = 0; i < 3; i++) {
|
||||
char name[6];
|
||||
|
||||
|
@ -245,7 +257,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
|
|||
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
|
||||
&sama5d4_pcr_layout,
|
||||
sama5d4_periphck[i].n,
|
||||
"masterck",
|
||||
"masterck_div",
|
||||
sama5d4_periphck[i].id,
|
||||
&range, INT_MIN);
|
||||
if (IS_ERR(hw))
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
} while (0)
|
||||
|
||||
static DEFINE_SPINLOCK(pmc_pll_lock);
|
||||
static DEFINE_SPINLOCK(pmc_mck0_lock);
|
||||
static DEFINE_SPINLOCK(pmc_mckX_lock);
|
||||
|
||||
/**
|
||||
|
@ -89,118 +90,198 @@ static const struct clk_pll_layout pll_layout_divio = {
|
|||
.endiv_shift = 30,
|
||||
};
|
||||
|
||||
/*
|
||||
* CPU PLL output range.
|
||||
* Notice: The upper limit has been setup to 1000000002 due to hardware
|
||||
* block which cannot output exactly 1GHz.
|
||||
*/
|
||||
static const struct clk_range cpu_pll_outputs[] = {
|
||||
{ .min = 2343750, .max = 1000000002 },
|
||||
};
|
||||
|
||||
/* PLL output range. */
|
||||
static const struct clk_range pll_outputs[] = {
|
||||
{ .min = 2343750, .max = 1200000000 },
|
||||
};
|
||||
|
||||
/* CPU PLL characteristics. */
|
||||
static const struct clk_pll_characteristics cpu_pll_characteristics = {
|
||||
.input = { .min = 12000000, .max = 50000000 },
|
||||
.num_output = ARRAY_SIZE(cpu_pll_outputs),
|
||||
.output = cpu_pll_outputs,
|
||||
};
|
||||
|
||||
/* PLL characteristics. */
|
||||
static const struct clk_pll_characteristics pll_characteristics = {
|
||||
.input = { .min = 12000000, .max = 50000000 },
|
||||
.num_output = ARRAY_SIZE(pll_outputs),
|
||||
.output = pll_outputs,
|
||||
};
|
||||
|
||||
/**
|
||||
* PLL clocks description
|
||||
* @n: clock name
|
||||
* @p: clock parent
|
||||
* @l: clock layout
|
||||
* @c: clock characteristics
|
||||
* @t: clock type
|
||||
* @f: true if clock is critical and cannot be disabled
|
||||
* @f: clock flags
|
||||
* @eid: export index in sama7g5->chws[] array
|
||||
*/
|
||||
static const struct {
|
||||
const char *n;
|
||||
const char *p;
|
||||
const struct clk_pll_layout *l;
|
||||
const struct clk_pll_characteristics *c;
|
||||
unsigned long f;
|
||||
u8 t;
|
||||
u8 c;
|
||||
u8 eid;
|
||||
} sama7g5_plls[][PLL_ID_MAX] = {
|
||||
[PLL_ID_CPU] = {
|
||||
{ .n = "cpupll_fracck",
|
||||
.p = "mainck",
|
||||
.l = &pll_layout_frac,
|
||||
.c = &cpu_pll_characteristics,
|
||||
.t = PLL_TYPE_FRAC,
|
||||
.c = 1, },
|
||||
/*
|
||||
* This feeds cpupll_divpmcck which feeds CPU. It should
|
||||
* not be disabled.
|
||||
*/
|
||||
.f = CLK_IS_CRITICAL, },
|
||||
|
||||
{ .n = "cpupll_divpmcck",
|
||||
.p = "cpupll_fracck",
|
||||
.l = &pll_layout_divpmc,
|
||||
.c = &cpu_pll_characteristics,
|
||||
.t = PLL_TYPE_DIV,
|
||||
.c = 1, },
|
||||
/* This feeds CPU. It should not be disabled. */
|
||||
.f = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT,
|
||||
.eid = PMC_CPUPLL, },
|
||||
},
|
||||
|
||||
[PLL_ID_SYS] = {
|
||||
{ .n = "syspll_fracck",
|
||||
.p = "mainck",
|
||||
.l = &pll_layout_frac,
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_FRAC,
|
||||
.c = 1, },
|
||||
/*
|
||||
* This feeds syspll_divpmcck which may feed critial parts
|
||||
* of the systems like timers. Therefore it should not be
|
||||
* disabled.
|
||||
*/
|
||||
.f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE, },
|
||||
|
||||
{ .n = "syspll_divpmcck",
|
||||
.p = "syspll_fracck",
|
||||
.l = &pll_layout_divpmc,
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_DIV,
|
||||
.c = 1, },
|
||||
/*
|
||||
* This may feed critial parts of the systems like timers.
|
||||
* Therefore it should not be disabled.
|
||||
*/
|
||||
.f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE,
|
||||
.eid = PMC_SYSPLL, },
|
||||
},
|
||||
|
||||
[PLL_ID_DDR] = {
|
||||
{ .n = "ddrpll_fracck",
|
||||
.p = "mainck",
|
||||
.l = &pll_layout_frac,
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_FRAC,
|
||||
.c = 1, },
|
||||
/*
|
||||
* This feeds ddrpll_divpmcck which feeds DDR. It should not
|
||||
* be disabled.
|
||||
*/
|
||||
.f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE, },
|
||||
|
||||
{ .n = "ddrpll_divpmcck",
|
||||
.p = "ddrpll_fracck",
|
||||
.l = &pll_layout_divpmc,
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_DIV,
|
||||
.c = 1, },
|
||||
/* This feeds DDR. It should not be disabled. */
|
||||
.f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE, },
|
||||
},
|
||||
|
||||
[PLL_ID_IMG] = {
|
||||
{ .n = "imgpll_fracck",
|
||||
.p = "mainck",
|
||||
.l = &pll_layout_frac,
|
||||
.t = PLL_TYPE_FRAC, },
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_FRAC,
|
||||
.f = CLK_SET_RATE_GATE, },
|
||||
|
||||
{ .n = "imgpll_divpmcck",
|
||||
.p = "imgpll_fracck",
|
||||
.l = &pll_layout_divpmc,
|
||||
.t = PLL_TYPE_DIV, },
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_DIV,
|
||||
.f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
|
||||
CLK_SET_RATE_PARENT, },
|
||||
},
|
||||
|
||||
[PLL_ID_BAUD] = {
|
||||
{ .n = "baudpll_fracck",
|
||||
.p = "mainck",
|
||||
.l = &pll_layout_frac,
|
||||
.t = PLL_TYPE_FRAC, },
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_FRAC,
|
||||
.f = CLK_SET_RATE_GATE, },
|
||||
|
||||
{ .n = "baudpll_divpmcck",
|
||||
.p = "baudpll_fracck",
|
||||
.l = &pll_layout_divpmc,
|
||||
.t = PLL_TYPE_DIV, },
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_DIV,
|
||||
.f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
|
||||
CLK_SET_RATE_PARENT, },
|
||||
},
|
||||
|
||||
[PLL_ID_AUDIO] = {
|
||||
{ .n = "audiopll_fracck",
|
||||
.p = "main_xtal",
|
||||
.l = &pll_layout_frac,
|
||||
.t = PLL_TYPE_FRAC, },
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_FRAC,
|
||||
.f = CLK_SET_RATE_GATE, },
|
||||
|
||||
{ .n = "audiopll_divpmcck",
|
||||
.p = "audiopll_fracck",
|
||||
.l = &pll_layout_divpmc,
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_DIV,
|
||||
.eid = PMC_I2S0_MUX, },
|
||||
.f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
|
||||
CLK_SET_RATE_PARENT,
|
||||
.eid = PMC_AUDIOPMCPLL, },
|
||||
|
||||
{ .n = "audiopll_diviock",
|
||||
.p = "audiopll_fracck",
|
||||
.l = &pll_layout_divio,
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_DIV,
|
||||
.eid = PMC_I2S1_MUX, },
|
||||
.f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
|
||||
CLK_SET_RATE_PARENT,
|
||||
.eid = PMC_AUDIOIOPLL, },
|
||||
},
|
||||
|
||||
[PLL_ID_ETH] = {
|
||||
{ .n = "ethpll_fracck",
|
||||
.p = "main_xtal",
|
||||
.l = &pll_layout_frac,
|
||||
.t = PLL_TYPE_FRAC, },
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_FRAC,
|
||||
.f = CLK_SET_RATE_GATE, },
|
||||
|
||||
{ .n = "ethpll_divpmcck",
|
||||
.p = "ethpll_fracck",
|
||||
.l = &pll_layout_divpmc,
|
||||
.t = PLL_TYPE_DIV, },
|
||||
.c = &pll_characteristics,
|
||||
.t = PLL_TYPE_DIV,
|
||||
.f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
|
||||
CLK_SET_RATE_PARENT, },
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -245,7 +326,7 @@ static const struct {
|
|||
.ep = { "syspll_divpmcck", "ddrpll_divpmcck", "imgpll_divpmcck", },
|
||||
.ep_mux_table = { 5, 6, 7, },
|
||||
.ep_count = 3,
|
||||
.ep_chg_id = 6, },
|
||||
.ep_chg_id = 5, },
|
||||
|
||||
{ .n = "mck4",
|
||||
.id = 4,
|
||||
|
@ -278,7 +359,7 @@ static const struct {
|
|||
};
|
||||
|
||||
/* Mux table for programmable clocks. */
|
||||
static u32 sama7g5_prog_mux_table[] = { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, };
|
||||
static u32 sama7g5_prog_mux_table[] = { 0, 1, 2, 5, 6, 7, 8, 9, 10, };
|
||||
|
||||
/**
|
||||
* Peripheral clock description
|
||||
|
@ -401,7 +482,7 @@ static const struct {
|
|||
.pp = { "audiopll_divpmcck", },
|
||||
.pp_mux_table = { 9, },
|
||||
.pp_count = 1,
|
||||
.pp_chg_id = 4, },
|
||||
.pp_chg_id = 3, },
|
||||
|
||||
{ .n = "csi_gclk",
|
||||
.id = 33,
|
||||
|
@ -513,7 +594,7 @@ static const struct {
|
|||
.pp = { "ethpll_divpmcck", },
|
||||
.pp_mux_table = { 10, },
|
||||
.pp_count = 1,
|
||||
.pp_chg_id = 4, },
|
||||
.pp_chg_id = 3, },
|
||||
|
||||
{ .n = "gmac1_gclk",
|
||||
.id = 52,
|
||||
|
@ -545,7 +626,7 @@ static const struct {
|
|||
.pp = { "syspll_divpmcck", "audiopll_divpmcck", },
|
||||
.pp_mux_table = { 5, 9, },
|
||||
.pp_count = 2,
|
||||
.pp_chg_id = 5, },
|
||||
.pp_chg_id = 4, },
|
||||
|
||||
{ .n = "i2smcc1_gclk",
|
||||
.id = 58,
|
||||
|
@ -553,7 +634,7 @@ static const struct {
|
|||
.pp = { "syspll_divpmcck", "audiopll_divpmcck", },
|
||||
.pp_mux_table = { 5, 9, },
|
||||
.pp_count = 2,
|
||||
.pp_chg_id = 5, },
|
||||
.pp_chg_id = 4, },
|
||||
|
||||
{ .n = "mcan0_gclk",
|
||||
.id = 61,
|
||||
|
@ -695,7 +776,7 @@ static const struct {
|
|||
.pp = { "syspll_divpmcck", "baudpll_divpmcck", },
|
||||
.pp_mux_table = { 5, 8, },
|
||||
.pp_count = 2,
|
||||
.pp_chg_id = 5, },
|
||||
.pp_chg_id = 4, },
|
||||
|
||||
{ .n = "sdmmc1_gclk",
|
||||
.id = 81,
|
||||
|
@ -703,7 +784,7 @@ static const struct {
|
|||
.pp = { "syspll_divpmcck", "baudpll_divpmcck", },
|
||||
.pp_mux_table = { 5, 8, },
|
||||
.pp_count = 2,
|
||||
.pp_chg_id = 5, },
|
||||
.pp_chg_id = 4, },
|
||||
|
||||
{ .n = "sdmmc2_gclk",
|
||||
.id = 82,
|
||||
|
@ -711,7 +792,7 @@ static const struct {
|
|||
.pp = { "syspll_divpmcck", "baudpll_divpmcck", },
|
||||
.pp_mux_table = { 5, 8, },
|
||||
.pp_count = 2,
|
||||
.pp_chg_id = 5, },
|
||||
.pp_chg_id = 4, },
|
||||
|
||||
{ .n = "spdifrx_gclk",
|
||||
.id = 84,
|
||||
|
@ -719,7 +800,7 @@ static const struct {
|
|||
.pp = { "syspll_divpmcck", "audiopll_divpmcck", },
|
||||
.pp_mux_table = { 5, 9, },
|
||||
.pp_count = 2,
|
||||
.pp_chg_id = 5, },
|
||||
.pp_chg_id = 4, },
|
||||
|
||||
{ .n = "spdiftx_gclk",
|
||||
.id = 85,
|
||||
|
@ -727,7 +808,7 @@ static const struct {
|
|||
.pp = { "syspll_divpmcck", "audiopll_divpmcck", },
|
||||
.pp_mux_table = { 5, 9, },
|
||||
.pp_count = 2,
|
||||
.pp_chg_id = 5, },
|
||||
.pp_chg_id = 4, },
|
||||
|
||||
{ .n = "tcb0_ch0_gclk",
|
||||
.id = 88,
|
||||
|
@ -758,28 +839,16 @@ static const struct {
|
|||
.pp_chg_id = INT_MIN, },
|
||||
};
|
||||
|
||||
/* PLL output range. */
|
||||
static const struct clk_range pll_outputs[] = {
|
||||
{ .min = 2343750, .max = 1200000000 },
|
||||
};
|
||||
|
||||
/* PLL characteristics. */
|
||||
static const struct clk_pll_characteristics pll_characteristics = {
|
||||
.input = { .min = 12000000, .max = 50000000 },
|
||||
.num_output = ARRAY_SIZE(pll_outputs),
|
||||
.output = pll_outputs,
|
||||
};
|
||||
|
||||
/* MCK0 characteristics. */
|
||||
static const struct clk_master_characteristics mck0_characteristics = {
|
||||
.output = { .min = 140000000, .max = 200000000 },
|
||||
.divisors = { 1, 2, 4, 3 },
|
||||
.output = { .min = 50000000, .max = 200000000 },
|
||||
.divisors = { 1, 2, 4, 3, 5 },
|
||||
.have_div3_pres = 1,
|
||||
};
|
||||
|
||||
/* MCK0 layout. */
|
||||
static const struct clk_master_layout mck0_layout = {
|
||||
.mask = 0x373,
|
||||
.mask = 0x773,
|
||||
.pres_shift = 4,
|
||||
.offset = 0x28,
|
||||
};
|
||||
|
@ -835,10 +904,10 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
|
|||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
sama7g5_pmc = pmc_data_allocate(PMC_I2S1_MUX + 1,
|
||||
sama7g5_pmc = pmc_data_allocate(PMC_CPU + 1,
|
||||
nck(sama7g5_systemck),
|
||||
nck(sama7g5_periphck),
|
||||
nck(sama7g5_gck));
|
||||
nck(sama7g5_gck), 8);
|
||||
if (!sama7g5_pmc)
|
||||
return;
|
||||
|
||||
|
@ -886,18 +955,18 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
|
|||
hw = sam9x60_clk_register_frac_pll(regmap,
|
||||
&pmc_pll_lock, sama7g5_plls[i][j].n,
|
||||
sama7g5_plls[i][j].p, parent_hw, i,
|
||||
&pll_characteristics,
|
||||
sama7g5_plls[i][j].c,
|
||||
sama7g5_plls[i][j].l,
|
||||
sama7g5_plls[i][j].c);
|
||||
sama7g5_plls[i][j].f);
|
||||
break;
|
||||
|
||||
case PLL_TYPE_DIV:
|
||||
hw = sam9x60_clk_register_div_pll(regmap,
|
||||
&pmc_pll_lock, sama7g5_plls[i][j].n,
|
||||
sama7g5_plls[i][j].p, i,
|
||||
&pll_characteristics,
|
||||
sama7g5_plls[i][j].c,
|
||||
sama7g5_plls[i][j].l,
|
||||
sama7g5_plls[i][j].c);
|
||||
sama7g5_plls[i][j].f);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -912,12 +981,19 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
|
|||
}
|
||||
}
|
||||
|
||||
parent_names[0] = md_slck_name;
|
||||
parent_names[1] = "mainck";
|
||||
parent_names[2] = "cpupll_divpmcck";
|
||||
parent_names[3] = "syspll_divpmcck";
|
||||
hw = at91_clk_register_master(regmap, "mck0", 4, parent_names,
|
||||
&mck0_layout, &mck0_characteristics);
|
||||
parent_names[0] = "cpupll_divpmcck";
|
||||
hw = at91_clk_register_master_pres(regmap, "cpuck", 1, parent_names,
|
||||
&mck0_layout, &mck0_characteristics,
|
||||
&pmc_mck0_lock,
|
||||
CLK_SET_RATE_PARENT, 0);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
sama7g5_pmc->chws[PMC_CPU] = hw;
|
||||
|
||||
hw = at91_clk_register_master_div(regmap, "mck0", "cpuck",
|
||||
&mck0_layout, &mck0_characteristics,
|
||||
&pmc_mck0_lock, 0);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
|
@ -926,9 +1002,8 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
|
|||
parent_names[0] = md_slck_name;
|
||||
parent_names[1] = td_slck_name;
|
||||
parent_names[2] = "mainck";
|
||||
parent_names[3] = "mck0";
|
||||
for (i = 0; i < ARRAY_SIZE(sama7g5_mckx); i++) {
|
||||
u8 num_parents = 4 + sama7g5_mckx[i].ep_count;
|
||||
u8 num_parents = 3 + sama7g5_mckx[i].ep_count;
|
||||
u32 *mux_table;
|
||||
|
||||
mux_table = kmalloc_array(num_parents, sizeof(*mux_table),
|
||||
|
@ -936,10 +1011,10 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
|
|||
if (!mux_table)
|
||||
goto err_free;
|
||||
|
||||
SAMA7G5_INIT_TABLE(mux_table, 4);
|
||||
SAMA7G5_FILL_TABLE(&mux_table[4], sama7g5_mckx[i].ep_mux_table,
|
||||
SAMA7G5_INIT_TABLE(mux_table, 3);
|
||||
SAMA7G5_FILL_TABLE(&mux_table[3], sama7g5_mckx[i].ep_mux_table,
|
||||
sama7g5_mckx[i].ep_count);
|
||||
SAMA7G5_FILL_TABLE(&parent_names[4], sama7g5_mckx[i].ep,
|
||||
SAMA7G5_FILL_TABLE(&parent_names[3], sama7g5_mckx[i].ep,
|
||||
sama7g5_mckx[i].ep_count);
|
||||
|
||||
hw = at91_clk_sama7g5_register_master(regmap, sama7g5_mckx[i].n,
|
||||
|
@ -962,24 +1037,25 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
|
|||
parent_names[0] = md_slck_name;
|
||||
parent_names[1] = td_slck_name;
|
||||
parent_names[2] = "mainck";
|
||||
parent_names[3] = "mck0";
|
||||
parent_names[4] = "syspll_divpmcck";
|
||||
parent_names[5] = "ddrpll_divpmcck";
|
||||
parent_names[6] = "imgpll_divpmcck";
|
||||
parent_names[7] = "baudpll_divpmcck";
|
||||
parent_names[8] = "audiopll_divpmcck";
|
||||
parent_names[9] = "ethpll_divpmcck";
|
||||
parent_names[3] = "syspll_divpmcck";
|
||||
parent_names[4] = "ddrpll_divpmcck";
|
||||
parent_names[5] = "imgpll_divpmcck";
|
||||
parent_names[6] = "baudpll_divpmcck";
|
||||
parent_names[7] = "audiopll_divpmcck";
|
||||
parent_names[8] = "ethpll_divpmcck";
|
||||
for (i = 0; i < 8; i++) {
|
||||
char name[6];
|
||||
|
||||
snprintf(name, sizeof(name), "prog%d", i);
|
||||
|
||||
hw = at91_clk_register_programmable(regmap, name, parent_names,
|
||||
10, i,
|
||||
9, i,
|
||||
&programmable_layout,
|
||||
sama7g5_prog_mux_table);
|
||||
if (IS_ERR(hw))
|
||||
goto err_free;
|
||||
|
||||
sama7g5_pmc->pchws[i] = hw;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sama7g5_systemck); i++) {
|
||||
|
@ -1010,9 +1086,8 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
|
|||
parent_names[0] = md_slck_name;
|
||||
parent_names[1] = td_slck_name;
|
||||
parent_names[2] = "mainck";
|
||||
parent_names[3] = "mck0";
|
||||
for (i = 0; i < ARRAY_SIZE(sama7g5_gck); i++) {
|
||||
u8 num_parents = 4 + sama7g5_gck[i].pp_count;
|
||||
u8 num_parents = 3 + sama7g5_gck[i].pp_count;
|
||||
u32 *mux_table;
|
||||
|
||||
mux_table = kmalloc_array(num_parents, sizeof(*mux_table),
|
||||
|
@ -1020,10 +1095,10 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
|
|||
if (!mux_table)
|
||||
goto err_free;
|
||||
|
||||
SAMA7G5_INIT_TABLE(mux_table, 4);
|
||||
SAMA7G5_FILL_TABLE(&mux_table[4], sama7g5_gck[i].pp_mux_table,
|
||||
SAMA7G5_INIT_TABLE(mux_table, 3);
|
||||
SAMA7G5_FILL_TABLE(&mux_table[3], sama7g5_gck[i].pp_mux_table,
|
||||
sama7g5_gck[i].pp_count);
|
||||
SAMA7G5_FILL_TABLE(&parent_names[4], sama7g5_gck[i].pp,
|
||||
SAMA7G5_FILL_TABLE(&parent_names[3], sama7g5_gck[i].pp,
|
||||
sama7g5_gck[i].pp_count);
|
||||
|
||||
hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
|
||||
|
@ -1052,7 +1127,7 @@ err_free:
|
|||
kfree(alloc_mem);
|
||||
}
|
||||
|
||||
pmc_data_free(sama7g5_pmc);
|
||||
kfree(sama7g5_pmc);
|
||||
}
|
||||
|
||||
/* Some clks are used for a clocksource */
|
||||
|
|
|
@ -25,7 +25,6 @@ static const struct clk_parent_data clk_dvp_parent = {
|
|||
static int clk_dvp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct clk_hw_onecell_data *data;
|
||||
struct resource *res;
|
||||
struct clk_dvp *dvp;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
|
@ -42,7 +41,7 @@ static int clk_dvp_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
data = dvp->data;
|
||||
|
||||
base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
|
@ -108,6 +107,7 @@ static const struct of_device_id clk_dvp_dt_ids[] = {
|
|||
{ .compatible = "brcm,brcm2711-dvp", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, clk_dvp_dt_ids);
|
||||
|
||||
static struct platform_driver clk_dvp_driver = {
|
||||
.probe = clk_dvp_probe,
|
||||
|
|
|
@ -46,9 +46,17 @@
|
|||
#define MMCM_CLK_DIV_DIVIDE BIT(11)
|
||||
#define MMCM_CLK_DIV_NOCOUNT BIT(12)
|
||||
|
||||
struct axi_clkgen_limits {
|
||||
unsigned int fpfd_min;
|
||||
unsigned int fpfd_max;
|
||||
unsigned int fvco_min;
|
||||
unsigned int fvco_max;
|
||||
};
|
||||
|
||||
struct axi_clkgen {
|
||||
void __iomem *base;
|
||||
struct clk_hw clk_hw;
|
||||
struct axi_clkgen_limits limits;
|
||||
};
|
||||
|
||||
static uint32_t axi_clkgen_lookup_filter(unsigned int m)
|
||||
|
@ -100,12 +108,15 @@ static uint32_t axi_clkgen_lookup_lock(unsigned int m)
|
|||
return 0x1f1f00fa;
|
||||
}
|
||||
|
||||
static const unsigned int fpfd_min = 10000;
|
||||
static const unsigned int fpfd_max = 300000;
|
||||
static const unsigned int fvco_min = 600000;
|
||||
static const unsigned int fvco_max = 1200000;
|
||||
static const struct axi_clkgen_limits axi_clkgen_zynq_default_limits = {
|
||||
.fpfd_min = 10000,
|
||||
.fpfd_max = 300000,
|
||||
.fvco_min = 600000,
|
||||
.fvco_max = 1200000,
|
||||
};
|
||||
|
||||
static void axi_clkgen_calc_params(unsigned long fin, unsigned long fout,
|
||||
static void axi_clkgen_calc_params(const struct axi_clkgen_limits *limits,
|
||||
unsigned long fin, unsigned long fout,
|
||||
unsigned int *best_d, unsigned int *best_m, unsigned int *best_dout)
|
||||
{
|
||||
unsigned long d, d_min, d_max, _d_min, _d_max;
|
||||
|
@ -122,12 +133,12 @@ static void axi_clkgen_calc_params(unsigned long fin, unsigned long fout,
|
|||
*best_m = 0;
|
||||
*best_dout = 0;
|
||||
|
||||
d_min = max_t(unsigned long, DIV_ROUND_UP(fin, fpfd_max), 1);
|
||||
d_max = min_t(unsigned long, fin / fpfd_min, 80);
|
||||
d_min = max_t(unsigned long, DIV_ROUND_UP(fin, limits->fpfd_max), 1);
|
||||
d_max = min_t(unsigned long, fin / limits->fpfd_min, 80);
|
||||
|
||||
again:
|
||||
fvco_min_fract = fvco_min << fract_shift;
|
||||
fvco_max_fract = fvco_max << fract_shift;
|
||||
fvco_min_fract = limits->fvco_min << fract_shift;
|
||||
fvco_max_fract = limits->fvco_max << fract_shift;
|
||||
|
||||
m_min = max_t(unsigned long, DIV_ROUND_UP(fvco_min_fract, fin) * d_min, 1);
|
||||
m_max = min_t(unsigned long, fvco_max_fract * d_max / fin, 64 << fract_shift);
|
||||
|
@ -319,6 +330,7 @@ static int axi_clkgen_set_rate(struct clk_hw *clk_hw,
|
|||
unsigned long rate, unsigned long parent_rate)
|
||||
{
|
||||
struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
|
||||
const struct axi_clkgen_limits *limits = &axi_clkgen->limits;
|
||||
unsigned int d, m, dout;
|
||||
struct axi_clkgen_div_params params;
|
||||
uint32_t power = 0;
|
||||
|
@ -328,7 +340,7 @@ static int axi_clkgen_set_rate(struct clk_hw *clk_hw,
|
|||
if (parent_rate == 0 || rate == 0)
|
||||
return -EINVAL;
|
||||
|
||||
axi_clkgen_calc_params(parent_rate, rate, &d, &m, &dout);
|
||||
axi_clkgen_calc_params(limits, parent_rate, rate, &d, &m, &dout);
|
||||
|
||||
if (d == 0 || dout == 0 || m == 0)
|
||||
return -EINVAL;
|
||||
|
@ -368,10 +380,12 @@ static int axi_clkgen_set_rate(struct clk_hw *clk_hw,
|
|||
static long axi_clkgen_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(hw);
|
||||
const struct axi_clkgen_limits *limits = &axi_clkgen->limits;
|
||||
unsigned int d, m, dout;
|
||||
unsigned long long tmp;
|
||||
|
||||
axi_clkgen_calc_params(*parent_rate, rate, &d, &m, &dout);
|
||||
axi_clkgen_calc_params(limits, *parent_rate, rate, &d, &m, &dout);
|
||||
|
||||
if (d == 0 || dout == 0 || m == 0)
|
||||
return -EINVAL;
|
||||
|
@ -482,17 +496,9 @@ static const struct clk_ops axi_clkgen_ops = {
|
|||
.get_parent = axi_clkgen_get_parent,
|
||||
};
|
||||
|
||||
static const struct of_device_id axi_clkgen_ids[] = {
|
||||
{
|
||||
.compatible = "adi,axi-clkgen-2.00.a",
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, axi_clkgen_ids);
|
||||
|
||||
static int axi_clkgen_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *id;
|
||||
const struct axi_clkgen_limits *dflt_limits;
|
||||
struct axi_clkgen *axi_clkgen;
|
||||
struct clk_init_data init;
|
||||
const char *parent_names[2];
|
||||
|
@ -501,11 +507,8 @@ static int axi_clkgen_probe(struct platform_device *pdev)
|
|||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (!pdev->dev.of_node)
|
||||
return -ENODEV;
|
||||
|
||||
id = of_match_node(axi_clkgen_ids, pdev->dev.of_node);
|
||||
if (!id)
|
||||
dflt_limits = device_get_match_data(&pdev->dev);
|
||||
if (!dflt_limits)
|
||||
return -ENODEV;
|
||||
|
||||
axi_clkgen = devm_kzalloc(&pdev->dev, sizeof(*axi_clkgen), GFP_KERNEL);
|
||||
|
@ -527,6 +530,8 @@ static int axi_clkgen_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(&axi_clkgen->limits, dflt_limits, sizeof(axi_clkgen->limits));
|
||||
|
||||
clk_name = pdev->dev.of_node->name;
|
||||
of_property_read_string(pdev->dev.of_node, "clock-output-names",
|
||||
&clk_name);
|
||||
|
@ -554,6 +559,15 @@ static int axi_clkgen_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id axi_clkgen_ids[] = {
|
||||
{
|
||||
.compatible = "adi,axi-clkgen-2.00.a",
|
||||
.data = &axi_clkgen_zynq_default_limits,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, axi_clkgen_ids);
|
||||
|
||||
static struct platform_driver axi_clkgen_driver = {
|
||||
.driver = {
|
||||
.name = "adi-axi-clkgen",
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
@ -405,3 +406,52 @@ void clk_hw_unregister_composite(struct clk_hw *hw)
|
|||
kfree(composite);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_hw_unregister_composite);
|
||||
|
||||
static void devm_clk_hw_release_composite(struct device *dev, void *res)
|
||||
{
|
||||
clk_hw_unregister_composite(*(struct clk_hw **)res);
|
||||
}
|
||||
|
||||
static struct clk_hw *__devm_clk_hw_register_composite(struct device *dev,
|
||||
const char *name, const char * const *parent_names,
|
||||
const struct clk_parent_data *pdata, int num_parents,
|
||||
struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
|
||||
struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
|
||||
struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct clk_hw **ptr, *hw;
|
||||
|
||||
ptr = devres_alloc(devm_clk_hw_release_composite, sizeof(*ptr),
|
||||
GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
hw = __clk_hw_register_composite(dev, name, parent_names, pdata,
|
||||
num_parents, mux_hw, mux_ops, rate_hw,
|
||||
rate_ops, gate_hw, gate_ops, flags);
|
||||
|
||||
if (!IS_ERR(hw)) {
|
||||
*ptr = hw;
|
||||
devres_add(dev, ptr);
|
||||
} else {
|
||||
devres_free(ptr);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
struct clk_hw *devm_clk_hw_register_composite_pdata(struct device *dev,
|
||||
const char *name,
|
||||
const struct clk_parent_data *parent_data,
|
||||
int num_parents,
|
||||
struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
|
||||
struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
|
||||
struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
|
||||
unsigned long flags)
|
||||
{
|
||||
return __devm_clk_hw_register_composite(dev, name, NULL, parent_data,
|
||||
num_parents, mux_hw, mux_ops,
|
||||
rate_hw, rate_ops, gate_hw,
|
||||
gate_ops, flags);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
|
@ -578,3 +579,36 @@ void clk_hw_unregister_divider(struct clk_hw *hw)
|
|||
kfree(div);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_hw_unregister_divider);
|
||||
|
||||
static void devm_clk_hw_release_divider(struct device *dev, void *res)
|
||||
{
|
||||
clk_hw_unregister_divider(*(struct clk_hw **)res);
|
||||
}
|
||||
|
||||
struct clk_hw *__devm_clk_hw_register_divider(struct device *dev,
|
||||
struct device_node *np, const char *name,
|
||||
const char *parent_name, const struct clk_hw *parent_hw,
|
||||
const struct clk_parent_data *parent_data, unsigned long flags,
|
||||
void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
|
||||
const struct clk_div_table *table, spinlock_t *lock)
|
||||
{
|
||||
struct clk_hw **ptr, *hw;
|
||||
|
||||
ptr = devres_alloc(devm_clk_hw_release_divider, sizeof(*ptr), GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
hw = __clk_hw_register_divider(dev, np, name, parent_name, parent_hw,
|
||||
parent_data, flags, reg, shift, width,
|
||||
clk_divider_flags, table, lock);
|
||||
|
||||
if (!IS_ERR(hw)) {
|
||||
*ptr = hw;
|
||||
devres_add(dev, ptr);
|
||||
} else {
|
||||
devres_free(ptr);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__devm_clk_hw_register_divider);
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Layerscape FlexSPI clock driver
|
||||
*
|
||||
* Copyright 2020 Michael Walle <michael@walle.cc>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
static const struct clk_div_table ls1028a_flexspi_divs[] = {
|
||||
{ .val = 0, .div = 1, },
|
||||
{ .val = 1, .div = 2, },
|
||||
{ .val = 2, .div = 3, },
|
||||
{ .val = 3, .div = 4, },
|
||||
{ .val = 4, .div = 5, },
|
||||
{ .val = 5, .div = 6, },
|
||||
{ .val = 6, .div = 7, },
|
||||
{ .val = 7, .div = 8, },
|
||||
{ .val = 11, .div = 12, },
|
||||
{ .val = 15, .div = 16, },
|
||||
{ .val = 16, .div = 20, },
|
||||
{ .val = 17, .div = 24, },
|
||||
{ .val = 18, .div = 28, },
|
||||
{ .val = 19, .div = 32, },
|
||||
{ .val = 20, .div = 80, },
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct clk_div_table lx2160a_flexspi_divs[] = {
|
||||
{ .val = 1, .div = 2, },
|
||||
{ .val = 3, .div = 4, },
|
||||
{ .val = 5, .div = 6, },
|
||||
{ .val = 7, .div = 8, },
|
||||
{ .val = 11, .div = 12, },
|
||||
{ .val = 15, .div = 16, },
|
||||
{ .val = 16, .div = 20, },
|
||||
{ .val = 17, .div = 24, },
|
||||
{ .val = 18, .div = 28, },
|
||||
{ .val = 19, .div = 32, },
|
||||
{ .val = 20, .div = 80, },
|
||||
{}
|
||||
};
|
||||
|
||||
static int fsl_flexspi_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
const char *clk_name = np->name;
|
||||
const char *clk_parent;
|
||||
struct resource *res;
|
||||
void __iomem *reg;
|
||||
struct clk_hw *hw;
|
||||
const struct clk_div_table *divs;
|
||||
|
||||
divs = device_get_match_data(dev);
|
||||
if (!divs)
|
||||
return -ENOENT;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENOENT;
|
||||
|
||||
/*
|
||||
* Can't use devm_ioremap_resource() or devm_of_iomap() because the
|
||||
* resource might already be taken by the parent device.
|
||||
*/
|
||||
reg = devm_ioremap(dev, res->start, resource_size(res));
|
||||
if (!reg)
|
||||
return -ENOMEM;
|
||||
|
||||
clk_parent = of_clk_get_parent_name(np, 0);
|
||||
if (!clk_parent)
|
||||
return -EINVAL;
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &clk_name);
|
||||
|
||||
hw = devm_clk_hw_register_divider_table(dev, clk_name, clk_parent, 0,
|
||||
reg, 0, 5, 0, divs, NULL);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
|
||||
return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
|
||||
static const struct of_device_id fsl_flexspi_clk_dt_ids[] = {
|
||||
{ .compatible = "fsl,ls1028a-flexspi-clk", .data = &ls1028a_flexspi_divs },
|
||||
{ .compatible = "fsl,lx2160a-flexspi-clk", .data = &lx2160a_flexspi_divs },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, fsl_flexspi_clk_dt_ids);
|
||||
|
||||
static struct platform_driver fsl_flexspi_clk_driver = {
|
||||
.driver = {
|
||||
.name = "fsl-flexspi-clk",
|
||||
.of_match_table = fsl_flexspi_clk_dt_ids,
|
||||
},
|
||||
.probe = fsl_flexspi_clk_probe,
|
||||
};
|
||||
module_platform_driver(fsl_flexspi_clk_driver);
|
||||
|
||||
MODULE_DESCRIPTION("FlexSPI clock driver for Layerscape SoCs");
|
||||
MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -58,13 +58,13 @@ static int fsl_sai_clk_probe(struct platform_device *pdev)
|
|||
/* set clock direction, we are the BCLK master */
|
||||
writel(CR2_BCD, base + I2S_CR2);
|
||||
|
||||
hw = clk_hw_register_composite_pdata(dev, dev->of_node->name,
|
||||
&pdata, 1, NULL, NULL,
|
||||
&sai_clk->div.hw,
|
||||
&clk_divider_ops,
|
||||
&sai_clk->gate.hw,
|
||||
&clk_gate_ops,
|
||||
CLK_SET_RATE_GATE);
|
||||
hw = devm_clk_hw_register_composite_pdata(dev, dev->of_node->name,
|
||||
&pdata, 1, NULL, NULL,
|
||||
&sai_clk->div.hw,
|
||||
&clk_divider_ops,
|
||||
&sai_clk->gate.hw,
|
||||
&clk_gate_ops,
|
||||
CLK_SET_RATE_GATE);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
|
||||
|
|
|
@ -147,7 +147,7 @@ static struct platform_driver clk_pwm_driver = {
|
|||
.remove = clk_pwm_remove,
|
||||
.driver = {
|
||||
.name = "pwm-clock",
|
||||
.of_match_table = of_match_ptr(clk_pwm_dt_ids),
|
||||
.of_match_table = clk_pwm_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <dt-bindings/clock/fsl,qoriq-clockgen.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
|
@ -1368,33 +1369,33 @@ static struct clk *clockgen_clk_get(struct of_phandle_args *clkspec, void *data)
|
|||
idx = clkspec->args[1];
|
||||
|
||||
switch (type) {
|
||||
case 0:
|
||||
case QORIQ_CLK_SYSCLK:
|
||||
if (idx != 0)
|
||||
goto bad_args;
|
||||
clk = cg->sysclk;
|
||||
break;
|
||||
case 1:
|
||||
case QORIQ_CLK_CMUX:
|
||||
if (idx >= ARRAY_SIZE(cg->cmux))
|
||||
goto bad_args;
|
||||
clk = cg->cmux[idx];
|
||||
break;
|
||||
case 2:
|
||||
case QORIQ_CLK_HWACCEL:
|
||||
if (idx >= ARRAY_SIZE(cg->hwaccel))
|
||||
goto bad_args;
|
||||
clk = cg->hwaccel[idx];
|
||||
break;
|
||||
case 3:
|
||||
case QORIQ_CLK_FMAN:
|
||||
if (idx >= ARRAY_SIZE(cg->fman))
|
||||
goto bad_args;
|
||||
clk = cg->fman[idx];
|
||||
break;
|
||||
case 4:
|
||||
case QORIQ_CLK_PLATFORM_PLL:
|
||||
pll = &cg->pll[PLATFORM_PLL];
|
||||
if (idx >= ARRAY_SIZE(pll->div))
|
||||
goto bad_args;
|
||||
clk = pll->div[idx].clk;
|
||||
break;
|
||||
case 5:
|
||||
case QORIQ_CLK_CORECLK:
|
||||
if (idx != 0)
|
||||
goto bad_args;
|
||||
clk = cg->coreclk;
|
||||
|
|
|
@ -195,6 +195,7 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
|
||||
err_reg:
|
||||
of_node_put(s2mps11_clks[0].clk_np);
|
||||
while (--i >= 0)
|
||||
clkdev_drop(s2mps11_clks[i].lookup);
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ static const struct clk_ops scpi_dvfs_ops = {
|
|||
.set_rate = scpi_dvfs_set_rate,
|
||||
};
|
||||
|
||||
static const struct of_device_id scpi_clk_match[] = {
|
||||
static const struct of_device_id scpi_clk_match[] __maybe_unused = {
|
||||
{ .compatible = "arm,scpi-dvfs-clocks", .data = &scpi_dvfs_ops, },
|
||||
{ .compatible = "arm,scpi-variable-clocks", .data = &scpi_clk_ops, },
|
||||
{}
|
||||
|
|
|
@ -902,6 +902,10 @@ static int _si5351_clkout_set_disable_state(
|
|||
static void _si5351_clkout_reset_pll(struct si5351_driver_data *drvdata, int num)
|
||||
{
|
||||
u8 val = si5351_reg_read(drvdata, SI5351_CLK0_CTRL + num);
|
||||
u8 mask = val & SI5351_CLK_PLL_SELECT ? SI5351_PLL_RESET_B :
|
||||
SI5351_PLL_RESET_A;
|
||||
unsigned int v;
|
||||
int err;
|
||||
|
||||
switch (val & SI5351_CLK_INPUT_MASK) {
|
||||
case SI5351_CLK_INPUT_XTAL:
|
||||
|
@ -909,9 +913,12 @@ static void _si5351_clkout_reset_pll(struct si5351_driver_data *drvdata, int num
|
|||
return; /* pll not used, no need to reset */
|
||||
}
|
||||
|
||||
si5351_reg_write(drvdata, SI5351_PLL_RESET,
|
||||
val & SI5351_CLK_PLL_SELECT ? SI5351_PLL_RESET_B :
|
||||
SI5351_PLL_RESET_A);
|
||||
si5351_reg_write(drvdata, SI5351_PLL_RESET, mask);
|
||||
|
||||
err = regmap_read_poll_timeout(drvdata->regmap, SI5351_PLL_RESET, v,
|
||||
!(v & mask), 0, 20000);
|
||||
if (err < 0)
|
||||
dev_err(&drvdata->client->dev, "Reset bit didn't clear\n");
|
||||
|
||||
dev_dbg(&drvdata->client->dev, "%s - %s: pll = %d\n",
|
||||
__func__, clk_hw_get_name(&drvdata->clkout[num].hw),
|
||||
|
|
|
@ -739,8 +739,8 @@ static int vc5_update_power(struct device_node *np_output,
|
|||
{
|
||||
u32 value;
|
||||
|
||||
if (!of_property_read_u32(np_output,
|
||||
"idt,voltage-microvolts", &value)) {
|
||||
if (!of_property_read_u32(np_output, "idt,voltage-microvolt",
|
||||
&value)) {
|
||||
clk_out->clk_output_cfg0_mask |= VC5_CLK_OUTPUT_CFG0_PWR_MASK;
|
||||
switch (value) {
|
||||
case 1800000:
|
||||
|
|
|
@ -420,7 +420,7 @@ static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index)
|
|||
static void clk_core_fill_parent_index(struct clk_core *core, u8 index)
|
||||
{
|
||||
struct clk_parent_map *entry = &core->parents[index];
|
||||
struct clk_core *parent = ERR_PTR(-ENOENT);
|
||||
struct clk_core *parent;
|
||||
|
||||
if (entry->hw) {
|
||||
parent = entry->hw->core;
|
||||
|
@ -2314,6 +2314,8 @@ int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)
|
|||
if (!clk)
|
||||
return 0;
|
||||
|
||||
trace_clk_set_rate_range(clk->core, min, max);
|
||||
|
||||
if (min > max) {
|
||||
pr_err("%s: clk %s dev %s con %s: invalid range [%lu, %lu]\n",
|
||||
__func__, clk->core->name, clk->dev_id, clk->con_id,
|
||||
|
@ -2381,6 +2383,8 @@ int clk_set_min_rate(struct clk *clk, unsigned long rate)
|
|||
if (!clk)
|
||||
return 0;
|
||||
|
||||
trace_clk_set_min_rate(clk->core, rate);
|
||||
|
||||
return clk_set_rate_range(clk, rate, clk->max_rate);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_set_min_rate);
|
||||
|
@ -2397,6 +2401,8 @@ int clk_set_max_rate(struct clk *clk, unsigned long rate)
|
|||
if (!clk)
|
||||
return 0;
|
||||
|
||||
trace_clk_set_max_rate(clk->core, rate);
|
||||
|
||||
return clk_set_rate_range(clk, clk->min_rate, rate);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_set_max_rate);
|
||||
|
@ -2931,7 +2937,14 @@ static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
|
|||
else
|
||||
seq_puts(s, "-----");
|
||||
|
||||
seq_printf(s, " %6d\n", clk_core_get_scaled_duty_cycle(c, 100000));
|
||||
seq_printf(s, " %6d", clk_core_get_scaled_duty_cycle(c, 100000));
|
||||
|
||||
if (c->ops->is_enabled)
|
||||
seq_printf(s, " %9c\n", clk_core_is_enabled(c) ? 'Y' : 'N');
|
||||
else if (!c->ops->enable)
|
||||
seq_printf(s, " %9c\n", 'Y');
|
||||
else
|
||||
seq_printf(s, " %9c\n", '?');
|
||||
}
|
||||
|
||||
static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
|
||||
|
@ -2950,9 +2963,9 @@ static int clk_summary_show(struct seq_file *s, void *data)
|
|||
struct clk_core *c;
|
||||
struct hlist_head **lists = (struct hlist_head **)s->private;
|
||||
|
||||
seq_puts(s, " enable prepare protect duty\n");
|
||||
seq_puts(s, " clock count count count rate accuracy phase cycle\n");
|
||||
seq_puts(s, "---------------------------------------------------------------------------------------------\n");
|
||||
seq_puts(s, " enable prepare protect duty hardware\n");
|
||||
seq_puts(s, " clock count count count rate accuracy phase cycle enable\n");
|
||||
seq_puts(s, "-------------------------------------------------------------------------------------------------------\n");
|
||||
|
||||
clk_prepare_lock();
|
||||
|
||||
|
@ -3667,6 +3680,24 @@ struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw,
|
|||
return clk;
|
||||
}
|
||||
|
||||
/**
|
||||
* clk_hw_get_clk - get clk consumer given an clk_hw
|
||||
* @hw: clk_hw associated with the clk being consumed
|
||||
* @con_id: connection ID string on device
|
||||
*
|
||||
* Returns: new clk consumer
|
||||
* This is the function to be used by providers which need
|
||||
* to get a consumer clk and act on the clock element
|
||||
* Calls to this function must be balanced with calls clk_put()
|
||||
*/
|
||||
struct clk *clk_hw_get_clk(struct clk_hw *hw, const char *con_id)
|
||||
{
|
||||
struct device *dev = hw->core->dev;
|
||||
|
||||
return clk_hw_create_clk(dev, hw, dev_name(dev), con_id);
|
||||
}
|
||||
EXPORT_SYMBOL(clk_hw_get_clk);
|
||||
|
||||
static int clk_cpy_name(const char **dst_p, const char *src, bool must_exist)
|
||||
{
|
||||
const char *dst;
|
||||
|
@ -4068,12 +4099,12 @@ void clk_hw_unregister(struct clk_hw *hw)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(clk_hw_unregister);
|
||||
|
||||
static void devm_clk_release(struct device *dev, void *res)
|
||||
static void devm_clk_unregister_cb(struct device *dev, void *res)
|
||||
{
|
||||
clk_unregister(*(struct clk **)res);
|
||||
}
|
||||
|
||||
static void devm_clk_hw_release(struct device *dev, void *res)
|
||||
static void devm_clk_hw_unregister_cb(struct device *dev, void *res)
|
||||
{
|
||||
clk_hw_unregister(*(struct clk_hw **)res);
|
||||
}
|
||||
|
@ -4093,7 +4124,7 @@ struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw)
|
|||
struct clk *clk;
|
||||
struct clk **clkp;
|
||||
|
||||
clkp = devres_alloc(devm_clk_release, sizeof(*clkp), GFP_KERNEL);
|
||||
clkp = devres_alloc(devm_clk_unregister_cb, sizeof(*clkp), GFP_KERNEL);
|
||||
if (!clkp)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
@ -4123,7 +4154,7 @@ int devm_clk_hw_register(struct device *dev, struct clk_hw *hw)
|
|||
struct clk_hw **hwp;
|
||||
int ret;
|
||||
|
||||
hwp = devres_alloc(devm_clk_hw_release, sizeof(*hwp), GFP_KERNEL);
|
||||
hwp = devres_alloc(devm_clk_hw_unregister_cb, sizeof(*hwp), GFP_KERNEL);
|
||||
if (!hwp)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -4167,7 +4198,7 @@ static int devm_clk_hw_match(struct device *dev, void *res, void *data)
|
|||
*/
|
||||
void devm_clk_unregister(struct device *dev, struct clk *clk)
|
||||
{
|
||||
WARN_ON(devres_release(dev, devm_clk_release, devm_clk_match, clk));
|
||||
WARN_ON(devres_release(dev, devm_clk_unregister_cb, devm_clk_match, clk));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_clk_unregister);
|
||||
|
||||
|
@ -4182,11 +4213,54 @@ EXPORT_SYMBOL_GPL(devm_clk_unregister);
|
|||
*/
|
||||
void devm_clk_hw_unregister(struct device *dev, struct clk_hw *hw)
|
||||
{
|
||||
WARN_ON(devres_release(dev, devm_clk_hw_release, devm_clk_hw_match,
|
||||
WARN_ON(devres_release(dev, devm_clk_hw_unregister_cb, devm_clk_hw_match,
|
||||
hw));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_clk_hw_unregister);
|
||||
|
||||
static void devm_clk_release(struct device *dev, void *res)
|
||||
{
|
||||
clk_put(*(struct clk **)res);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_clk_hw_get_clk - resource managed clk_hw_get_clk()
|
||||
* @dev: device that is registering this clock
|
||||
* @hw: clk_hw associated with the clk being consumed
|
||||
* @con_id: connection ID string on device
|
||||
*
|
||||
* Managed clk_hw_get_clk(). Clocks got with this function are
|
||||
* automatically clk_put() on driver detach. See clk_put()
|
||||
* for more information.
|
||||
*/
|
||||
struct clk *devm_clk_hw_get_clk(struct device *dev, struct clk_hw *hw,
|
||||
const char *con_id)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk **clkp;
|
||||
|
||||
/* This should not happen because it would mean we have drivers
|
||||
* passing around clk_hw pointers instead of having the caller use
|
||||
* proper clk_get() style APIs
|
||||
*/
|
||||
WARN_ON_ONCE(dev != hw->core->dev);
|
||||
|
||||
clkp = devres_alloc(devm_clk_release, sizeof(*clkp), GFP_KERNEL);
|
||||
if (!clkp)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
clk = clk_hw_get_clk(hw, con_id);
|
||||
if (!IS_ERR(clk)) {
|
||||
*clkp = clk;
|
||||
devres_add(dev, clkp);
|
||||
} else {
|
||||
devres_free(clkp);
|
||||
}
|
||||
|
||||
return clk;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_clk_hw_get_clk);
|
||||
|
||||
/*
|
||||
* clkdev helpers
|
||||
*/
|
||||
|
@ -4334,6 +4408,42 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(clk_notifier_unregister);
|
||||
|
||||
struct clk_notifier_devres {
|
||||
struct clk *clk;
|
||||
struct notifier_block *nb;
|
||||
};
|
||||
|
||||
static void devm_clk_notifier_release(struct device *dev, void *res)
|
||||
{
|
||||
struct clk_notifier_devres *devres = res;
|
||||
|
||||
clk_notifier_unregister(devres->clk, devres->nb);
|
||||
}
|
||||
|
||||
int devm_clk_notifier_register(struct device *dev, struct clk *clk,
|
||||
struct notifier_block *nb)
|
||||
{
|
||||
struct clk_notifier_devres *devres;
|
||||
int ret;
|
||||
|
||||
devres = devres_alloc(devm_clk_notifier_release,
|
||||
sizeof(*devres), GFP_KERNEL);
|
||||
|
||||
if (!devres)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = clk_notifier_register(clk, nb);
|
||||
if (!ret) {
|
||||
devres->clk = clk;
|
||||
devres->nb = nb;
|
||||
} else {
|
||||
devres_free(devres);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_clk_notifier_register);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static void clk_core_reparent_orphans(void)
|
||||
{
|
||||
|
|
|
@ -30,6 +30,7 @@ struct clk_gate2 {
|
|||
void __iomem *reg;
|
||||
u8 bit_idx;
|
||||
u8 cgr_val;
|
||||
u8 cgr_mask;
|
||||
u8 flags;
|
||||
spinlock_t *lock;
|
||||
unsigned int *share_count;
|
||||
|
@ -37,37 +38,38 @@ struct clk_gate2 {
|
|||
|
||||
#define to_clk_gate2(_hw) container_of(_hw, struct clk_gate2, hw)
|
||||
|
||||
static int clk_gate2_enable(struct clk_hw *hw)
|
||||
static void clk_gate2_do_shared_clks(struct clk_hw *hw, bool enable)
|
||||
{
|
||||
struct clk_gate2 *gate = to_clk_gate2(hw);
|
||||
u32 reg;
|
||||
|
||||
reg = readl(gate->reg);
|
||||
reg &= ~(gate->cgr_mask << gate->bit_idx);
|
||||
if (enable)
|
||||
reg |= (gate->cgr_val & gate->cgr_mask) << gate->bit_idx;
|
||||
writel(reg, gate->reg);
|
||||
}
|
||||
|
||||
static int clk_gate2_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gate2 *gate = to_clk_gate2(hw);
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(gate->lock, flags);
|
||||
|
||||
if (gate->share_count && (*gate->share_count)++ > 0)
|
||||
goto out;
|
||||
|
||||
if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT) {
|
||||
ret = clk_gate_ops.enable(hw);
|
||||
} else {
|
||||
reg = readl(gate->reg);
|
||||
reg &= ~(3 << gate->bit_idx);
|
||||
reg |= gate->cgr_val << gate->bit_idx;
|
||||
writel(reg, gate->reg);
|
||||
}
|
||||
|
||||
clk_gate2_do_shared_clks(hw, true);
|
||||
out:
|
||||
spin_unlock_irqrestore(gate->lock, flags);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_gate2_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gate2 *gate = to_clk_gate2(hw);
|
||||
u32 reg;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(gate->lock, flags);
|
||||
|
@ -79,23 +81,17 @@ static void clk_gate2_disable(struct clk_hw *hw)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT) {
|
||||
clk_gate_ops.disable(hw);
|
||||
} else {
|
||||
reg = readl(gate->reg);
|
||||
reg &= ~(3 << gate->bit_idx);
|
||||
writel(reg, gate->reg);
|
||||
}
|
||||
|
||||
clk_gate2_do_shared_clks(hw, false);
|
||||
out:
|
||||
spin_unlock_irqrestore(gate->lock, flags);
|
||||
}
|
||||
|
||||
static int clk_gate2_reg_is_enabled(void __iomem *reg, u8 bit_idx)
|
||||
static int clk_gate2_reg_is_enabled(void __iomem *reg, u8 bit_idx,
|
||||
u8 cgr_val, u8 cgr_mask)
|
||||
{
|
||||
u32 val = readl(reg);
|
||||
|
||||
if (((val >> bit_idx) & 1) == 1)
|
||||
if (((val >> bit_idx) & cgr_mask) == cgr_val)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
|
@ -104,29 +100,28 @@ static int clk_gate2_reg_is_enabled(void __iomem *reg, u8 bit_idx)
|
|||
static int clk_gate2_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gate2 *gate = to_clk_gate2(hw);
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT)
|
||||
return clk_gate_ops.is_enabled(hw);
|
||||
spin_lock_irqsave(gate->lock, flags);
|
||||
|
||||
return clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx);
|
||||
ret = clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx,
|
||||
gate->cgr_val, gate->cgr_mask);
|
||||
|
||||
spin_unlock_irqrestore(gate->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void clk_gate2_disable_unused(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gate2 *gate = to_clk_gate2(hw);
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
|
||||
if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(gate->lock, flags);
|
||||
|
||||
if (!gate->share_count || *gate->share_count == 0) {
|
||||
reg = readl(gate->reg);
|
||||
reg &= ~(3 << gate->bit_idx);
|
||||
writel(reg, gate->reg);
|
||||
}
|
||||
if (!gate->share_count || *gate->share_count == 0)
|
||||
clk_gate2_do_shared_clks(hw, false);
|
||||
|
||||
spin_unlock_irqrestore(gate->lock, flags);
|
||||
}
|
||||
|
@ -140,7 +135,7 @@ static const struct clk_ops clk_gate2_ops = {
|
|||
|
||||
struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
void __iomem *reg, u8 bit_idx, u8 cgr_val,
|
||||
void __iomem *reg, u8 bit_idx, u8 cgr_val, u8 cgr_mask,
|
||||
u8 clk_gate2_flags, spinlock_t *lock,
|
||||
unsigned int *share_count)
|
||||
{
|
||||
|
@ -157,6 +152,7 @@ struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name,
|
|||
gate->reg = reg;
|
||||
gate->bit_idx = bit_idx;
|
||||
gate->cgr_val = cgr_val;
|
||||
gate->cgr_mask = cgr_mask;
|
||||
gate->flags = clk_gate2_flags;
|
||||
gate->lock = lock;
|
||||
gate->share_count = share_count;
|
||||
|
|
|
@ -653,7 +653,7 @@ static struct platform_driver imx8mm_clk_driver = {
|
|||
* reloading the driver will crash or break devices.
|
||||
*/
|
||||
.suppress_bind_attrs = true,
|
||||
.of_match_table = of_match_ptr(imx8mm_clk_of_match),
|
||||
.of_match_table = imx8mm_clk_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(imx8mm_clk_driver);
|
||||
|
|
|
@ -604,7 +604,7 @@ static struct platform_driver imx8mn_clk_driver = {
|
|||
* reloading the driver will crash or break devices.
|
||||
*/
|
||||
.suppress_bind_attrs = true,
|
||||
.of_match_table = of_match_ptr(imx8mn_clk_of_match),
|
||||
.of_match_table = imx8mn_clk_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(imx8mn_clk_driver);
|
||||
|
|
|
@ -425,7 +425,7 @@ static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1];
|
|||
static int imx8mp_clocks_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct device_node *np;
|
||||
void __iomem *anatop_base, *ccm_base;
|
||||
int i;
|
||||
|
||||
|
@ -763,7 +763,7 @@ static struct platform_driver imx8mp_clk_driver = {
|
|||
* reloading the driver will crash or break devices.
|
||||
*/
|
||||
.suppress_bind_attrs = true,
|
||||
.of_match_table = of_match_ptr(imx8mp_clk_of_match),
|
||||
.of_match_table = imx8mp_clk_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(imx8mp_clk_driver);
|
||||
|
|
|
@ -639,7 +639,7 @@ static struct platform_driver imx8mq_clk_driver = {
|
|||
* reloading the driver will crash or break devices.
|
||||
*/
|
||||
.suppress_bind_attrs = true,
|
||||
.of_match_table = of_match_ptr(imx8mq_clk_of_match),
|
||||
.of_match_table = imx8mq_clk_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(imx8mq_clk_driver);
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "clk-scu.h"
|
||||
|
@ -157,6 +159,135 @@ static const struct imx8qxp_ss_lpcg imx8qxp_ss_lsio = {
|
|||
.num_max = IMX_LSIO_LPCG_CLK_END,
|
||||
};
|
||||
|
||||
#define IMX_LPCG_MAX_CLKS 8
|
||||
|
||||
static struct clk_hw *imx_lpcg_of_clk_src_get(struct of_phandle_args *clkspec,
|
||||
void *data)
|
||||
{
|
||||
struct clk_hw_onecell_data *hw_data = data;
|
||||
unsigned int idx = clkspec->args[0] / 4;
|
||||
|
||||
if (idx >= hw_data->num) {
|
||||
pr_err("%s: invalid index %u\n", __func__, idx);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return hw_data->hws[idx];
|
||||
}
|
||||
|
||||
static int imx_lpcg_parse_clks_from_dt(struct platform_device *pdev,
|
||||
struct device_node *np)
|
||||
{
|
||||
const char *output_names[IMX_LPCG_MAX_CLKS];
|
||||
const char *parent_names[IMX_LPCG_MAX_CLKS];
|
||||
unsigned int bit_offset[IMX_LPCG_MAX_CLKS];
|
||||
struct clk_hw_onecell_data *clk_data;
|
||||
struct clk_hw **clk_hws;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
int count;
|
||||
int idx;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (!of_device_is_compatible(np, "fsl,imx8qxp-lpcg"))
|
||||
return -EINVAL;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
count = of_property_count_u32_elems(np, "clock-indices");
|
||||
if (count < 0) {
|
||||
dev_err(&pdev->dev, "failed to count clocks\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* A trick here is that we set the num of clks to the MAX instead
|
||||
* of the count from clock-indices because one LPCG supports up to
|
||||
* 8 clock outputs which each of them is fixed to 4 bits. Then we can
|
||||
* easily get the clock by clk-indices (bit-offset) / 4.
|
||||
* And the cost is very limited few pointers.
|
||||
*/
|
||||
|
||||
clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hws,
|
||||
IMX_LPCG_MAX_CLKS), GFP_KERNEL);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
clk_data->num = IMX_LPCG_MAX_CLKS;
|
||||
clk_hws = clk_data->hws;
|
||||
|
||||
ret = of_property_read_u32_array(np, "clock-indices", bit_offset,
|
||||
count);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to read clock-indices\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = of_clk_parent_fill(np, parent_names, count);
|
||||
if (ret != count) {
|
||||
dev_err(&pdev->dev, "failed to get clock parent names\n");
|
||||
return count;
|
||||
}
|
||||
|
||||
ret = of_property_read_string_array(np, "clock-output-names",
|
||||
output_names, count);
|
||||
if (ret != count) {
|
||||
dev_err(&pdev->dev, "failed to read clock-output-names\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pm_runtime_get_noresume(&pdev->dev);
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
idx = bit_offset[i] / 4;
|
||||
if (idx > IMX_LPCG_MAX_CLKS) {
|
||||
dev_warn(&pdev->dev, "invalid bit offset of clock %d\n",
|
||||
i);
|
||||
ret = -EINVAL;
|
||||
goto unreg;
|
||||
}
|
||||
|
||||
clk_hws[idx] = imx_clk_lpcg_scu_dev(&pdev->dev, output_names[i],
|
||||
parent_names[i], 0, base,
|
||||
bit_offset[i], false);
|
||||
if (IS_ERR(clk_hws[idx])) {
|
||||
dev_warn(&pdev->dev, "failed to register clock %d\n",
|
||||
idx);
|
||||
ret = PTR_ERR(clk_hws[idx]);
|
||||
goto unreg;
|
||||
}
|
||||
}
|
||||
|
||||
ret = devm_of_clk_add_hw_provider(&pdev->dev, imx_lpcg_of_clk_src_get,
|
||||
clk_data);
|
||||
if (ret)
|
||||
goto unreg;
|
||||
|
||||
pm_runtime_mark_last_busy(&pdev->dev);
|
||||
pm_runtime_put_autosuspend(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
unreg:
|
||||
while (--i >= 0) {
|
||||
idx = bit_offset[i] / 4;
|
||||
if (clk_hws[idx])
|
||||
imx_clk_lpcg_scu_unregister(clk_hws[idx]);
|
||||
}
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx8qxp_lpcg_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
@ -167,8 +298,14 @@ static int imx8qxp_lpcg_clk_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
struct clk_hw **clks;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/* try new binding to parse clocks from device tree first */
|
||||
ret = imx_lpcg_parse_clks_from_dt(pdev, np);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
ss_lpcg = of_device_get_match_data(dev);
|
||||
if (!ss_lpcg)
|
||||
return -ENODEV;
|
||||
|
@ -219,6 +356,7 @@ static const struct of_device_id imx8qxp_lpcg_match[] = {
|
|||
{ .compatible = "fsl,imx8qxp-lpcg-adma", &imx8qxp_ss_adma, },
|
||||
{ .compatible = "fsl,imx8qxp-lpcg-conn", &imx8qxp_ss_conn, },
|
||||
{ .compatible = "fsl,imx8qxp-lpcg-lsio", &imx8qxp_ss_lsio, },
|
||||
{ .compatible = "fsl,imx8qxp-lpcg", NULL },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
|
@ -226,6 +364,7 @@ static struct platform_driver imx8qxp_lpcg_clk_driver = {
|
|||
.driver = {
|
||||
.name = "imx8qxp-lpcg-clk",
|
||||
.of_match_table = imx8qxp_lpcg_match,
|
||||
.pm = &imx_clk_lpcg_scu_pm_ops,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.probe = imx8qxp_lpcg_clk_probe,
|
||||
|
|
|
@ -22,9 +22,10 @@ static int imx8qxp_clk_probe(struct platform_device *pdev)
|
|||
struct device_node *ccm_node = pdev->dev.of_node;
|
||||
struct clk_hw_onecell_data *clk_data;
|
||||
struct clk_hw **clks;
|
||||
u32 clk_cells;
|
||||
int ret, i;
|
||||
|
||||
ret = imx_clk_scu_init();
|
||||
ret = imx_clk_scu_init(ccm_node);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -33,6 +34,9 @@ static int imx8qxp_clk_probe(struct platform_device *pdev)
|
|||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
if (of_property_read_u32(ccm_node, "#clock-cells", &clk_cells))
|
||||
return -EINVAL;
|
||||
|
||||
clk_data->num = IMX_SCU_CLK_END;
|
||||
clks = clk_data->hws;
|
||||
|
||||
|
@ -55,78 +59,78 @@ static int imx8qxp_clk_probe(struct platform_device *pdev)
|
|||
clks[IMX_LSIO_BUS_CLK] = clk_hw_register_fixed_rate(NULL, "lsio_bus_clk_root", NULL, 0, 100000000);
|
||||
|
||||
/* ARM core */
|
||||
clks[IMX_A35_CLK] = imx_clk_scu("a35_clk", IMX_SC_R_A35, IMX_SC_PM_CLK_CPU);
|
||||
clks[IMX_A35_CLK] = imx_clk_scu("a35_clk", IMX_SC_R_A35, IMX_SC_PM_CLK_CPU, clk_cells);
|
||||
|
||||
/* LSIO SS */
|
||||
clks[IMX_LSIO_PWM0_CLK] = imx_clk_scu("pwm0_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_LSIO_PWM1_CLK] = imx_clk_scu("pwm1_clk", IMX_SC_R_PWM_1, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_LSIO_PWM2_CLK] = imx_clk_scu("pwm2_clk", IMX_SC_R_PWM_2, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_LSIO_PWM3_CLK] = imx_clk_scu("pwm3_clk", IMX_SC_R_PWM_3, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_LSIO_PWM4_CLK] = imx_clk_scu("pwm4_clk", IMX_SC_R_PWM_4, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_LSIO_PWM5_CLK] = imx_clk_scu("pwm5_clk", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_LSIO_PWM6_CLK] = imx_clk_scu("pwm6_clk", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_LSIO_PWM7_CLK] = imx_clk_scu("pwm7_clk", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_LSIO_GPT0_CLK] = imx_clk_scu("gpt0_clk", IMX_SC_R_GPT_0, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_LSIO_GPT1_CLK] = imx_clk_scu("gpt1_clk", IMX_SC_R_GPT_1, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_LSIO_GPT2_CLK] = imx_clk_scu("gpt2_clk", IMX_SC_R_GPT_2, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_LSIO_GPT3_CLK] = imx_clk_scu("gpt3_clk", IMX_SC_R_GPT_3, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_LSIO_GPT4_CLK] = imx_clk_scu("gpt4_clk", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_LSIO_FSPI0_CLK] = imx_clk_scu("fspi0_clk", IMX_SC_R_FSPI_0, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_LSIO_FSPI1_CLK] = imx_clk_scu("fspi1_clk", IMX_SC_R_FSPI_1, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_LSIO_PWM0_CLK] = imx_clk_scu("pwm0_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_LSIO_PWM1_CLK] = imx_clk_scu("pwm1_clk", IMX_SC_R_PWM_1, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_LSIO_PWM2_CLK] = imx_clk_scu("pwm2_clk", IMX_SC_R_PWM_2, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_LSIO_PWM3_CLK] = imx_clk_scu("pwm3_clk", IMX_SC_R_PWM_3, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_LSIO_PWM4_CLK] = imx_clk_scu("pwm4_clk", IMX_SC_R_PWM_4, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_LSIO_PWM5_CLK] = imx_clk_scu("pwm5_clk", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_LSIO_PWM6_CLK] = imx_clk_scu("pwm6_clk", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_LSIO_PWM7_CLK] = imx_clk_scu("pwm7_clk", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_LSIO_GPT0_CLK] = imx_clk_scu("gpt0_clk", IMX_SC_R_GPT_0, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_LSIO_GPT1_CLK] = imx_clk_scu("gpt1_clk", IMX_SC_R_GPT_1, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_LSIO_GPT2_CLK] = imx_clk_scu("gpt2_clk", IMX_SC_R_GPT_2, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_LSIO_GPT3_CLK] = imx_clk_scu("gpt3_clk", IMX_SC_R_GPT_3, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_LSIO_GPT4_CLK] = imx_clk_scu("gpt4_clk", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_LSIO_FSPI0_CLK] = imx_clk_scu("fspi0_clk", IMX_SC_R_FSPI_0, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_LSIO_FSPI1_CLK] = imx_clk_scu("fspi1_clk", IMX_SC_R_FSPI_1, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
|
||||
/* ADMA SS */
|
||||
clks[IMX_ADMA_UART0_CLK] = imx_clk_scu("uart0_clk", IMX_SC_R_UART_0, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_ADMA_UART1_CLK] = imx_clk_scu("uart1_clk", IMX_SC_R_UART_1, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_ADMA_UART2_CLK] = imx_clk_scu("uart2_clk", IMX_SC_R_UART_2, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_ADMA_UART3_CLK] = imx_clk_scu("uart3_clk", IMX_SC_R_UART_3, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_ADMA_SPI0_CLK] = imx_clk_scu("spi0_clk", IMX_SC_R_SPI_0, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_ADMA_SPI1_CLK] = imx_clk_scu("spi1_clk", IMX_SC_R_SPI_1, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_ADMA_SPI2_CLK] = imx_clk_scu("spi2_clk", IMX_SC_R_SPI_2, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_ADMA_SPI3_CLK] = imx_clk_scu("spi3_clk", IMX_SC_R_SPI_3, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_ADMA_CAN0_CLK] = imx_clk_scu("can0_clk", IMX_SC_R_CAN_0, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_ADMA_I2C0_CLK] = imx_clk_scu("i2c0_clk", IMX_SC_R_I2C_0, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_ADMA_I2C1_CLK] = imx_clk_scu("i2c1_clk", IMX_SC_R_I2C_1, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_ADMA_I2C2_CLK] = imx_clk_scu("i2c2_clk", IMX_SC_R_I2C_2, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_ADMA_I2C3_CLK] = imx_clk_scu("i2c3_clk", IMX_SC_R_I2C_3, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_ADMA_FTM0_CLK] = imx_clk_scu("ftm0_clk", IMX_SC_R_FTM_0, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_ADMA_FTM1_CLK] = imx_clk_scu("ftm1_clk", IMX_SC_R_FTM_1, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_ADMA_ADC0_CLK] = imx_clk_scu("adc0_clk", IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_ADMA_PWM_CLK] = imx_clk_scu("pwm_clk", IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_ADMA_LCD_CLK] = imx_clk_scu("lcd_clk", IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_ADMA_UART0_CLK] = imx_clk_scu("uart0_clk", IMX_SC_R_UART_0, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_ADMA_UART1_CLK] = imx_clk_scu("uart1_clk", IMX_SC_R_UART_1, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_ADMA_UART2_CLK] = imx_clk_scu("uart2_clk", IMX_SC_R_UART_2, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_ADMA_UART3_CLK] = imx_clk_scu("uart3_clk", IMX_SC_R_UART_3, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_ADMA_SPI0_CLK] = imx_clk_scu("spi0_clk", IMX_SC_R_SPI_0, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_ADMA_SPI1_CLK] = imx_clk_scu("spi1_clk", IMX_SC_R_SPI_1, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_ADMA_SPI2_CLK] = imx_clk_scu("spi2_clk", IMX_SC_R_SPI_2, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_ADMA_SPI3_CLK] = imx_clk_scu("spi3_clk", IMX_SC_R_SPI_3, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_ADMA_CAN0_CLK] = imx_clk_scu("can0_clk", IMX_SC_R_CAN_0, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_ADMA_I2C0_CLK] = imx_clk_scu("i2c0_clk", IMX_SC_R_I2C_0, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_ADMA_I2C1_CLK] = imx_clk_scu("i2c1_clk", IMX_SC_R_I2C_1, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_ADMA_I2C2_CLK] = imx_clk_scu("i2c2_clk", IMX_SC_R_I2C_2, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_ADMA_I2C3_CLK] = imx_clk_scu("i2c3_clk", IMX_SC_R_I2C_3, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_ADMA_FTM0_CLK] = imx_clk_scu("ftm0_clk", IMX_SC_R_FTM_0, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_ADMA_FTM1_CLK] = imx_clk_scu("ftm1_clk", IMX_SC_R_FTM_1, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_ADMA_ADC0_CLK] = imx_clk_scu("adc0_clk", IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_ADMA_PWM_CLK] = imx_clk_scu("pwm_clk", IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_ADMA_LCD_CLK] = imx_clk_scu("lcd_clk", IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
|
||||
/* Connectivity */
|
||||
clks[IMX_CONN_SDHC0_CLK] = imx_clk_scu("sdhc0_clk", IMX_SC_R_SDHC_0, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_CONN_SDHC1_CLK] = imx_clk_scu("sdhc1_clk", IMX_SC_R_SDHC_1, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_CONN_SDHC2_CLK] = imx_clk_scu("sdhc2_clk", IMX_SC_R_SDHC_2, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_CONN_ENET0_ROOT_CLK] = imx_clk_scu("enet0_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_CONN_ENET0_BYPASS_CLK] = imx_clk_scu("enet0_bypass_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_BYPASS);
|
||||
clks[IMX_CONN_ENET0_RGMII_CLK] = imx_clk_scu("enet0_rgmii_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0);
|
||||
clks[IMX_CONN_ENET1_ROOT_CLK] = imx_clk_scu("enet1_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_CONN_ENET1_BYPASS_CLK] = imx_clk_scu("enet1_bypass_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_BYPASS);
|
||||
clks[IMX_CONN_ENET1_RGMII_CLK] = imx_clk_scu("enet1_rgmii_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0);
|
||||
clks[IMX_CONN_GPMI_BCH_IO_CLK] = imx_clk_scu("gpmi_io_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_MST_BUS);
|
||||
clks[IMX_CONN_GPMI_BCH_CLK] = imx_clk_scu("gpmi_bch_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_CONN_USB2_ACLK] = imx_clk_scu("usb3_aclk_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_CONN_USB2_BUS_CLK] = imx_clk_scu("usb3_bus_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MST_BUS);
|
||||
clks[IMX_CONN_USB2_LPM_CLK] = imx_clk_scu("usb3_lpm_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MISC);
|
||||
clks[IMX_CONN_SDHC0_CLK] = imx_clk_scu("sdhc0_clk", IMX_SC_R_SDHC_0, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_CONN_SDHC1_CLK] = imx_clk_scu("sdhc1_clk", IMX_SC_R_SDHC_1, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_CONN_SDHC2_CLK] = imx_clk_scu("sdhc2_clk", IMX_SC_R_SDHC_2, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_CONN_ENET0_ROOT_CLK] = imx_clk_scu("enet0_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_CONN_ENET0_BYPASS_CLK] = imx_clk_scu("enet0_bypass_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_BYPASS, clk_cells);
|
||||
clks[IMX_CONN_ENET0_RGMII_CLK] = imx_clk_scu("enet0_rgmii_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0, clk_cells);
|
||||
clks[IMX_CONN_ENET1_ROOT_CLK] = imx_clk_scu("enet1_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_CONN_ENET1_BYPASS_CLK] = imx_clk_scu("enet1_bypass_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_BYPASS, clk_cells);
|
||||
clks[IMX_CONN_ENET1_RGMII_CLK] = imx_clk_scu("enet1_rgmii_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0, clk_cells);
|
||||
clks[IMX_CONN_GPMI_BCH_IO_CLK] = imx_clk_scu("gpmi_io_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_MST_BUS, clk_cells);
|
||||
clks[IMX_CONN_GPMI_BCH_CLK] = imx_clk_scu("gpmi_bch_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_CONN_USB2_ACLK] = imx_clk_scu("usb3_aclk_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_CONN_USB2_BUS_CLK] = imx_clk_scu("usb3_bus_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MST_BUS, clk_cells);
|
||||
clks[IMX_CONN_USB2_LPM_CLK] = imx_clk_scu("usb3_lpm_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MISC, clk_cells);
|
||||
|
||||
/* Display controller SS */
|
||||
clks[IMX_DC0_DISP0_CLK] = imx_clk_scu("dc0_disp0_clk", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC0);
|
||||
clks[IMX_DC0_DISP1_CLK] = imx_clk_scu("dc0_disp1_clk", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC1);
|
||||
clks[IMX_DC0_DISP0_CLK] = imx_clk_scu("dc0_disp0_clk", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC0, clk_cells);
|
||||
clks[IMX_DC0_DISP1_CLK] = imx_clk_scu("dc0_disp1_clk", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC1, clk_cells);
|
||||
|
||||
/* MIPI-LVDS SS */
|
||||
clks[IMX_MIPI0_I2C0_CLK] = imx_clk_scu("mipi0_i2c0_clk", IMX_SC_R_MIPI_0_I2C_0, IMX_SC_PM_CLK_MISC2);
|
||||
clks[IMX_MIPI0_I2C1_CLK] = imx_clk_scu("mipi0_i2c1_clk", IMX_SC_R_MIPI_0_I2C_1, IMX_SC_PM_CLK_MISC2);
|
||||
clks[IMX_MIPI0_I2C0_CLK] = imx_clk_scu("mipi0_i2c0_clk", IMX_SC_R_MIPI_0_I2C_0, IMX_SC_PM_CLK_MISC2, clk_cells);
|
||||
clks[IMX_MIPI0_I2C1_CLK] = imx_clk_scu("mipi0_i2c1_clk", IMX_SC_R_MIPI_0_I2C_1, IMX_SC_PM_CLK_MISC2, clk_cells);
|
||||
|
||||
/* MIPI CSI SS */
|
||||
clks[IMX_CSI0_CORE_CLK] = imx_clk_scu("mipi_csi0_core_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_CSI0_ESC_CLK] = imx_clk_scu("mipi_csi0_esc_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_MISC);
|
||||
clks[IMX_CSI0_I2C0_CLK] = imx_clk_scu("mipi_csi0_i2c0_clk", IMX_SC_R_CSI_0_I2C_0, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_CSI0_PWM0_CLK] = imx_clk_scu("mipi_csi0_pwm0_clk", IMX_SC_R_CSI_0_PWM_0, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_CSI0_CORE_CLK] = imx_clk_scu("mipi_csi0_core_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_CSI0_ESC_CLK] = imx_clk_scu("mipi_csi0_esc_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_MISC, clk_cells);
|
||||
clks[IMX_CSI0_I2C0_CLK] = imx_clk_scu("mipi_csi0_i2c0_clk", IMX_SC_R_CSI_0_I2C_0, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_CSI0_PWM0_CLK] = imx_clk_scu("mipi_csi0_pwm0_clk", IMX_SC_R_CSI_0_PWM_0, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
|
||||
/* GPU SS */
|
||||
clks[IMX_GPU0_CORE_CLK] = imx_clk_scu("gpu_core0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_PER);
|
||||
clks[IMX_GPU0_SHADER_CLK] = imx_clk_scu("gpu_shader0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_MISC);
|
||||
clks[IMX_GPU0_CORE_CLK] = imx_clk_scu("gpu_core0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_PER, clk_cells);
|
||||
clks[IMX_GPU0_SHADER_CLK] = imx_clk_scu("gpu_shader0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_MISC, clk_cells);
|
||||
|
||||
for (i = 0; i < clk_data->num; i++) {
|
||||
if (IS_ERR(clks[i]))
|
||||
|
@ -134,7 +138,19 @@ static int imx8qxp_clk_probe(struct platform_device *pdev)
|
|||
i, PTR_ERR(clks[i]));
|
||||
}
|
||||
|
||||
return of_clk_add_hw_provider(ccm_node, of_clk_hw_onecell_get, clk_data);
|
||||
if (clk_cells == 2) {
|
||||
ret = of_clk_add_hw_provider(ccm_node, imx_scu_of_clk_src_get, imx_scu_clks);
|
||||
if (ret)
|
||||
imx_clk_scu_unregister();
|
||||
} else {
|
||||
/*
|
||||
* legacy binding code path doesn't unregister here because
|
||||
* it will be removed later.
|
||||
*/
|
||||
ret = of_clk_add_hw_provider(ccm_node, of_clk_hw_onecell_get, clk_data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id imx8qxp_match[] = {
|
||||
|
|
|
@ -34,6 +34,9 @@ struct clk_lpcg_scu {
|
|||
void __iomem *reg;
|
||||
u8 bit_idx;
|
||||
bool hw_gate;
|
||||
|
||||
/* for state save&restore */
|
||||
u32 state;
|
||||
};
|
||||
|
||||
#define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw)
|
||||
|
@ -81,9 +84,9 @@ static const struct clk_ops clk_lpcg_scu_ops = {
|
|||
.disable = clk_lpcg_scu_disable,
|
||||
};
|
||||
|
||||
struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name,
|
||||
unsigned long flags, void __iomem *reg,
|
||||
u8 bit_idx, bool hw_gate)
|
||||
struct clk_hw *__imx_clk_lpcg_scu(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
void __iomem *reg, u8 bit_idx, bool hw_gate)
|
||||
{
|
||||
struct clk_lpcg_scu *clk;
|
||||
struct clk_init_data init;
|
||||
|
@ -107,11 +110,53 @@ struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name,
|
|||
clk->hw.init = &init;
|
||||
|
||||
hw = &clk->hw;
|
||||
ret = clk_hw_register(NULL, hw);
|
||||
ret = clk_hw_register(dev, hw);
|
||||
if (ret) {
|
||||
kfree(clk);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
if (dev)
|
||||
dev_set_drvdata(dev, clk);
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
void imx_clk_lpcg_scu_unregister(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
|
||||
|
||||
clk_hw_unregister(&clk->hw);
|
||||
kfree(clk);
|
||||
}
|
||||
|
||||
static int __maybe_unused imx_clk_lpcg_scu_suspend(struct device *dev)
|
||||
{
|
||||
struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
|
||||
|
||||
clk->state = readl_relaxed(clk->reg);
|
||||
dev_dbg(dev, "save lpcg state 0x%x\n", clk->state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev)
|
||||
{
|
||||
struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
|
||||
|
||||
/*
|
||||
* FIXME: Sometimes writes don't work unless the CPU issues
|
||||
* them twice
|
||||
*/
|
||||
|
||||
writel(clk->state, clk->reg);
|
||||
writel(clk->state, clk->reg);
|
||||
dev_dbg(dev, "restore lpcg state 0x%x\n", clk->state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops = {
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_clk_lpcg_scu_suspend,
|
||||
imx_clk_lpcg_scu_resume)
|
||||
};
|
||||
|
|
|
@ -416,7 +416,7 @@ struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
|
|||
__func__, name);
|
||||
kfree(pll);
|
||||
return ERR_PTR(-EINVAL);
|
||||
};
|
||||
}
|
||||
|
||||
pll->base = base;
|
||||
pll->hw.init = &init;
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
#include <linux/arm-smccc.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "clk-scu.h"
|
||||
|
@ -16,6 +20,21 @@
|
|||
#define IMX_SIP_SET_CPUFREQ 0x00
|
||||
|
||||
static struct imx_sc_ipc *ccm_ipc_handle;
|
||||
static struct device_node *pd_np;
|
||||
static struct platform_driver imx_clk_scu_driver;
|
||||
|
||||
struct imx_scu_clk_node {
|
||||
const char *name;
|
||||
u32 rsrc;
|
||||
u8 clk_type;
|
||||
const char * const *parents;
|
||||
int num_parents;
|
||||
|
||||
struct clk_hw *hw;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
struct list_head imx_scu_clks[IMX_SC_R_LAST];
|
||||
|
||||
/*
|
||||
* struct clk_scu - Description of one SCU clock
|
||||
|
@ -27,6 +46,10 @@ struct clk_scu {
|
|||
struct clk_hw hw;
|
||||
u16 rsrc_id;
|
||||
u8 clk_type;
|
||||
|
||||
/* for state save&restore */
|
||||
bool is_enabled;
|
||||
u32 rate;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -128,9 +151,28 @@ static inline struct clk_scu *to_clk_scu(struct clk_hw *hw)
|
|||
return container_of(hw, struct clk_scu, hw);
|
||||
}
|
||||
|
||||
int imx_clk_scu_init(void)
|
||||
int imx_clk_scu_init(struct device_node *np)
|
||||
{
|
||||
return imx_scu_get_handle(&ccm_ipc_handle);
|
||||
u32 clk_cells;
|
||||
int ret, i;
|
||||
|
||||
ret = imx_scu_get_handle(&ccm_ipc_handle);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
of_property_read_u32(np, "#clock-cells", &clk_cells);
|
||||
|
||||
if (clk_cells == 2) {
|
||||
for (i = 0; i < IMX_SC_R_LAST; i++)
|
||||
INIT_LIST_HEAD(&imx_scu_clks[i]);
|
||||
|
||||
/* pd_np will be used to attach power domains later */
|
||||
pd_np = of_find_compatible_node(NULL, NULL, "fsl,scu-pd");
|
||||
if (!pd_np)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return platform_driver_register(&imx_clk_scu_driver);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -344,8 +386,9 @@ static const struct clk_ops clk_scu_cpu_ops = {
|
|||
.unprepare = clk_scu_unprepare,
|
||||
};
|
||||
|
||||
struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
|
||||
int num_parents, u32 rsrc_id, u8 clk_type)
|
||||
struct clk_hw *__imx_clk_scu(struct device *dev, const char *name,
|
||||
const char * const *parents, int num_parents,
|
||||
u32 rsrc_id, u8 clk_type)
|
||||
{
|
||||
struct clk_init_data init;
|
||||
struct clk_scu *clk;
|
||||
|
@ -379,11 +422,185 @@ struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
|
|||
clk->hw.init = &init;
|
||||
|
||||
hw = &clk->hw;
|
||||
ret = clk_hw_register(NULL, hw);
|
||||
ret = clk_hw_register(dev, hw);
|
||||
if (ret) {
|
||||
kfree(clk);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
if (dev)
|
||||
dev_set_drvdata(dev, clk);
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
struct clk_hw *imx_scu_of_clk_src_get(struct of_phandle_args *clkspec,
|
||||
void *data)
|
||||
{
|
||||
unsigned int rsrc = clkspec->args[0];
|
||||
unsigned int idx = clkspec->args[1];
|
||||
struct list_head *scu_clks = data;
|
||||
struct imx_scu_clk_node *clk;
|
||||
|
||||
list_for_each_entry(clk, &scu_clks[rsrc], node) {
|
||||
if (clk->clk_type == idx)
|
||||
return clk->hw;
|
||||
}
|
||||
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static int imx_clk_scu_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct imx_scu_clk_node *clk = dev_get_platdata(dev);
|
||||
struct clk_hw *hw;
|
||||
int ret;
|
||||
|
||||
pm_runtime_set_suspended(dev);
|
||||
pm_runtime_set_autosuspend_delay(dev, 50);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret) {
|
||||
pm_runtime_disable(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
hw = __imx_clk_scu(dev, clk->name, clk->parents, clk->num_parents,
|
||||
clk->rsrc, clk->clk_type);
|
||||
if (IS_ERR(hw)) {
|
||||
pm_runtime_disable(dev);
|
||||
return PTR_ERR(hw);
|
||||
}
|
||||
|
||||
clk->hw = hw;
|
||||
list_add_tail(&clk->node, &imx_scu_clks[clk->rsrc]);
|
||||
|
||||
pm_runtime_mark_last_busy(&pdev->dev);
|
||||
pm_runtime_put_autosuspend(&pdev->dev);
|
||||
|
||||
dev_dbg(dev, "register SCU clock rsrc:%d type:%d\n", clk->rsrc,
|
||||
clk->clk_type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused imx_clk_scu_suspend(struct device *dev)
|
||||
{
|
||||
struct clk_scu *clk = dev_get_drvdata(dev);
|
||||
|
||||
clk->rate = clk_hw_get_rate(&clk->hw);
|
||||
clk->is_enabled = clk_hw_is_enabled(&clk->hw);
|
||||
|
||||
if (clk->rate)
|
||||
dev_dbg(dev, "save rate %d\n", clk->rate);
|
||||
|
||||
if (clk->is_enabled)
|
||||
dev_dbg(dev, "save enabled state\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused imx_clk_scu_resume(struct device *dev)
|
||||
{
|
||||
struct clk_scu *clk = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
|
||||
if (clk->rate) {
|
||||
ret = clk_scu_set_rate(&clk->hw, clk->rate, 0);
|
||||
dev_dbg(dev, "restore rate %d %s\n", clk->rate,
|
||||
!ret ? "success" : "failed");
|
||||
}
|
||||
|
||||
if (clk->is_enabled) {
|
||||
ret = clk_scu_prepare(&clk->hw);
|
||||
dev_dbg(dev, "restore enabled state %s\n",
|
||||
!ret ? "success" : "failed");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops imx_clk_scu_pm_ops = {
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_clk_scu_suspend,
|
||||
imx_clk_scu_resume)
|
||||
};
|
||||
|
||||
static struct platform_driver imx_clk_scu_driver = {
|
||||
.driver = {
|
||||
.name = "imx-scu-clk",
|
||||
.suppress_bind_attrs = true,
|
||||
.pm = &imx_clk_scu_pm_ops,
|
||||
},
|
||||
.probe = imx_clk_scu_probe,
|
||||
};
|
||||
|
||||
static int imx_clk_scu_attach_pd(struct device *dev, u32 rsrc_id)
|
||||
{
|
||||
struct of_phandle_args genpdspec = {
|
||||
.np = pd_np,
|
||||
.args_count = 1,
|
||||
.args[0] = rsrc_id,
|
||||
};
|
||||
|
||||
if (rsrc_id == IMX_SC_R_A35 || rsrc_id == IMX_SC_R_A53 ||
|
||||
rsrc_id == IMX_SC_R_A72)
|
||||
return 0;
|
||||
|
||||
return of_genpd_add_device(&genpdspec, dev);
|
||||
}
|
||||
|
||||
struct clk_hw *imx_clk_scu_alloc_dev(const char *name,
|
||||
const char * const *parents,
|
||||
int num_parents, u32 rsrc_id, u8 clk_type)
|
||||
{
|
||||
struct imx_scu_clk_node clk = {
|
||||
.name = name,
|
||||
.rsrc = rsrc_id,
|
||||
.clk_type = clk_type,
|
||||
.parents = parents,
|
||||
.num_parents = num_parents,
|
||||
};
|
||||
struct platform_device *pdev;
|
||||
int ret;
|
||||
|
||||
pdev = platform_device_alloc(name, PLATFORM_DEVID_NONE);
|
||||
if (!pdev) {
|
||||
pr_err("%s: failed to allocate scu clk dev rsrc %d type %d\n",
|
||||
name, rsrc_id, clk_type);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
ret = platform_device_add_data(pdev, &clk, sizeof(clk));
|
||||
if (ret) {
|
||||
platform_device_put(pdev);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
pdev->driver_override = "imx-scu-clk";
|
||||
|
||||
ret = imx_clk_scu_attach_pd(&pdev->dev, rsrc_id);
|
||||
if (ret)
|
||||
pr_warn("%s: failed to attached the power domain %d\n",
|
||||
name, ret);
|
||||
|
||||
platform_device_add(pdev);
|
||||
|
||||
/* For API backwards compatiblilty, simply return NULL for success */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void imx_clk_scu_unregister(void)
|
||||
{
|
||||
struct imx_scu_clk_node *clk;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IMX_SC_R_LAST; i++) {
|
||||
list_for_each_entry(clk, &imx_scu_clks[i], node) {
|
||||
clk_hw_unregister(clk->hw);
|
||||
kfree(clk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,25 +8,61 @@
|
|||
#define __IMX_CLK_SCU_H
|
||||
|
||||
#include <linux/firmware/imx/sci.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
int imx_clk_scu_init(void);
|
||||
extern struct list_head imx_scu_clks[];
|
||||
extern const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops;
|
||||
|
||||
struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
|
||||
int num_parents, u32 rsrc_id, u8 clk_type);
|
||||
int imx_clk_scu_init(struct device_node *np);
|
||||
struct clk_hw *imx_scu_of_clk_src_get(struct of_phandle_args *clkspec,
|
||||
void *data);
|
||||
struct clk_hw *imx_clk_scu_alloc_dev(const char *name,
|
||||
const char * const *parents,
|
||||
int num_parents, u32 rsrc_id, u8 clk_type);
|
||||
|
||||
struct clk_hw *__imx_clk_scu(struct device *dev, const char *name,
|
||||
const char * const *parents, int num_parents,
|
||||
u32 rsrc_id, u8 clk_type);
|
||||
|
||||
void imx_clk_scu_unregister(void);
|
||||
|
||||
struct clk_hw *__imx_clk_lpcg_scu(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
void __iomem *reg, u8 bit_idx, bool hw_gate);
|
||||
void imx_clk_lpcg_scu_unregister(struct clk_hw *hw);
|
||||
|
||||
static inline struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id,
|
||||
u8 clk_type)
|
||||
u8 clk_type, u8 clk_cells)
|
||||
{
|
||||
return __imx_clk_scu(name, NULL, 0, rsrc_id, clk_type);
|
||||
if (clk_cells == 2)
|
||||
return imx_clk_scu_alloc_dev(name, NULL, 0, rsrc_id, clk_type);
|
||||
else
|
||||
return __imx_clk_scu(NULL, name, NULL, 0, rsrc_id, clk_type);
|
||||
}
|
||||
|
||||
static inline struct clk_hw *imx_clk_scu2(const char *name, const char * const *parents,
|
||||
int num_parents, u32 rsrc_id, u8 clk_type)
|
||||
int num_parents, u32 rsrc_id, u8 clk_type,
|
||||
u8 clk_cells)
|
||||
{
|
||||
return __imx_clk_scu(name, parents, num_parents, rsrc_id, clk_type);
|
||||
if (clk_cells == 2)
|
||||
return imx_clk_scu_alloc_dev(name, parents, num_parents, rsrc_id, clk_type);
|
||||
else
|
||||
return __imx_clk_scu(NULL, name, parents, num_parents, rsrc_id, clk_type);
|
||||
}
|
||||
|
||||
struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name,
|
||||
unsigned long flags, void __iomem *reg,
|
||||
u8 bit_idx, bool hw_gate);
|
||||
static inline struct clk_hw *imx_clk_lpcg_scu_dev(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
void __iomem *reg, u8 bit_idx, bool hw_gate)
|
||||
{
|
||||
return __imx_clk_lpcg_scu(dev, name, parent_name, flags, reg,
|
||||
bit_idx, hw_gate);
|
||||
}
|
||||
|
||||
static inline struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name,
|
||||
unsigned long flags, void __iomem *reg,
|
||||
u8 bit_idx, bool hw_gate)
|
||||
{
|
||||
return __imx_clk_lpcg_scu(NULL, name, parent_name, flags, reg,
|
||||
bit_idx, hw_gate);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
#define IMX_CLK_GATE2_SINGLE_BIT 1
|
||||
|
||||
extern spinlock_t imx_ccm_lock;
|
||||
|
||||
void imx_check_clocks(struct clk *clks[], unsigned int count);
|
||||
|
@ -68,9 +66,9 @@ extern struct imx_pll14xx_clk imx_1443x_dram_pll;
|
|||
to_clk(imx_clk_hw_cpu(name, parent_name, div, mux, pll, step))
|
||||
|
||||
#define clk_register_gate2(dev, name, parent_name, flags, reg, bit_idx, \
|
||||
cgr_val, clk_gate_flags, lock, share_count) \
|
||||
cgr_val, cgr_mask, clk_gate_flags, lock, share_count) \
|
||||
to_clk(clk_hw_register_gate2(dev, name, parent_name, flags, reg, bit_idx, \
|
||||
cgr_val, clk_gate_flags, lock, share_count))
|
||||
cgr_val, cgr_mask, clk_gate_flags, lock, share_count))
|
||||
|
||||
#define imx_clk_pllv3(type, name, parent_name, base, div_mask) \
|
||||
to_clk(imx_clk_hw_pllv3(type, name, parent_name, base, div_mask))
|
||||
|
@ -198,7 +196,7 @@ struct clk_hw *imx_clk_hw_pllv4(const char *name, const char *parent_name,
|
|||
|
||||
struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
void __iomem *reg, u8 bit_idx, u8 cgr_val,
|
||||
void __iomem *reg, u8 bit_idx, u8 cgr_val, u8 cgr_mask,
|
||||
u8 clk_gate_flags, spinlock_t *lock,
|
||||
unsigned int *share_count);
|
||||
|
||||
|
@ -351,14 +349,14 @@ static inline struct clk_hw *imx_clk_hw_gate2(const char *name, const char *pare
|
|||
void __iomem *reg, u8 shift)
|
||||
{
|
||||
return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
|
||||
shift, 0x3, 0, &imx_ccm_lock, NULL);
|
||||
shift, 0x3, 0x3, 0, &imx_ccm_lock, NULL);
|
||||
}
|
||||
|
||||
static inline struct clk_hw *imx_clk_hw_gate2_flags(const char *name, const char *parent,
|
||||
void __iomem *reg, u8 shift, unsigned long flags)
|
||||
{
|
||||
return clk_hw_register_gate2(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
|
||||
shift, 0x3, 0, &imx_ccm_lock, NULL);
|
||||
shift, 0x3, 0x3, 0, &imx_ccm_lock, NULL);
|
||||
}
|
||||
|
||||
static inline struct clk_hw *imx_clk_hw_gate2_shared(const char *name,
|
||||
|
@ -366,7 +364,7 @@ static inline struct clk_hw *imx_clk_hw_gate2_shared(const char *name,
|
|||
unsigned int *share_count)
|
||||
{
|
||||
return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
|
||||
shift, 0x3, 0, &imx_ccm_lock, share_count);
|
||||
shift, 0x3, 0x3, 0, &imx_ccm_lock, share_count);
|
||||
}
|
||||
|
||||
static inline struct clk_hw *imx_clk_hw_gate2_shared2(const char *name,
|
||||
|
@ -374,7 +372,7 @@ static inline struct clk_hw *imx_clk_hw_gate2_shared2(const char *name,
|
|||
unsigned int *share_count)
|
||||
{
|
||||
return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT |
|
||||
CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0,
|
||||
CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0x3, 0,
|
||||
&imx_ccm_lock, share_count);
|
||||
}
|
||||
|
||||
|
@ -384,16 +382,15 @@ static inline struct clk_hw *imx_dev_clk_hw_gate_shared(struct device *dev,
|
|||
unsigned int *share_count)
|
||||
{
|
||||
return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT |
|
||||
CLK_OPS_PARENT_ENABLE, reg, shift, 0x3,
|
||||
IMX_CLK_GATE2_SINGLE_BIT,
|
||||
&imx_ccm_lock, share_count);
|
||||
CLK_OPS_PARENT_ENABLE, reg, shift, 0x1,
|
||||
0x1, 0, &imx_ccm_lock, share_count);
|
||||
}
|
||||
|
||||
static inline struct clk *imx_clk_gate2_cgr(const char *name,
|
||||
const char *parent, void __iomem *reg, u8 shift, u8 cgr_val)
|
||||
{
|
||||
return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
|
||||
shift, cgr_val, 0, &imx_ccm_lock, NULL);
|
||||
shift, cgr_val, 0x3, 0, &imx_ccm_lock, NULL);
|
||||
}
|
||||
|
||||
static inline struct clk_hw *imx_clk_hw_gate3(const char *name, const char *parent,
|
||||
|
@ -421,7 +418,7 @@ static inline struct clk_hw *imx_clk_hw_gate4(const char *name, const char *pare
|
|||
{
|
||||
return clk_hw_register_gate2(NULL, name, parent,
|
||||
CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
|
||||
reg, shift, 0x3, 0, &imx_ccm_lock, NULL);
|
||||
reg, shift, 0x3, 0x3, 0, &imx_ccm_lock, NULL);
|
||||
}
|
||||
|
||||
static inline struct clk_hw *imx_clk_hw_gate4_flags(const char *name,
|
||||
|
@ -430,7 +427,7 @@ static inline struct clk_hw *imx_clk_hw_gate4_flags(const char *name,
|
|||
{
|
||||
return clk_hw_register_gate2(NULL, name, parent,
|
||||
flags | CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
|
||||
reg, shift, 0x3, 0, &imx_ccm_lock, NULL);
|
||||
reg, shift, 0x3, 0x3, 0, &imx_ccm_lock, NULL);
|
||||
}
|
||||
|
||||
#define imx_clk_gate4_flags(name, parent, reg, shift, flags) \
|
||||
|
|
|
@ -392,15 +392,21 @@ static unsigned int
|
|||
ingenic_clk_calc_hw_div(const struct ingenic_cgu_clk_info *clk_info,
|
||||
unsigned int div)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int i, best_i = 0, best = (unsigned int)-1;
|
||||
|
||||
for (i = 0; i < (1 << clk_info->div.bits)
|
||||
&& clk_info->div.div_table[i]; i++) {
|
||||
if (clk_info->div.div_table[i] >= div)
|
||||
return i;
|
||||
if (clk_info->div.div_table[i] >= div &&
|
||||
clk_info->div.div_table[i] < best) {
|
||||
best = clk_info->div.div_table[i];
|
||||
best_i = i;
|
||||
|
||||
if (div == best)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return i - 1;
|
||||
return best_i;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
|
|
|
@ -155,7 +155,7 @@ const struct clk_ops mtk_mux_gate_clr_set_upd_ops = {
|
|||
.set_parent = mtk_clk_mux_set_parent_setclr_lock,
|
||||
};
|
||||
|
||||
struct clk *mtk_clk_register_mux(const struct mtk_mux *mux,
|
||||
static struct clk *mtk_clk_register_mux(const struct mtk_mux *mux,
|
||||
struct regmap *regmap,
|
||||
spinlock_t *lock)
|
||||
{
|
||||
|
|
|
@ -77,10 +77,6 @@ extern const struct clk_ops mtk_mux_gate_clr_set_upd_ops;
|
|||
_width, _gate, _upd_ofs, _upd, \
|
||||
CLK_SET_RATE_PARENT)
|
||||
|
||||
struct clk *mtk_clk_register_mux(const struct mtk_mux *mux,
|
||||
struct regmap *regmap,
|
||||
spinlock_t *lock);
|
||||
|
||||
int mtk_clk_register_muxes(const struct mtk_mux *muxes,
|
||||
int num, struct device_node *node,
|
||||
spinlock_t *lock,
|
||||
|
|
|
@ -58,7 +58,7 @@ config COMMON_CLK_MESON8B
|
|||
want peripherals and CPU frequency scaling to work.
|
||||
|
||||
config COMMON_CLK_GXBB
|
||||
bool "GXBB and GXL SoC clock controllers support"
|
||||
tristate "GXBB and GXL SoC clock controllers support"
|
||||
depends on ARM64
|
||||
default y
|
||||
select COMMON_CLK_MESON_REGMAP
|
||||
|
@ -74,7 +74,7 @@ config COMMON_CLK_GXBB
|
|||
Say Y if you want peripherals and CPU frequency scaling to work.
|
||||
|
||||
config COMMON_CLK_AXG
|
||||
bool "AXG SoC clock controllers support"
|
||||
tristate "AXG SoC clock controllers support"
|
||||
depends on ARM64
|
||||
default y
|
||||
select COMMON_CLK_MESON_REGMAP
|
||||
|
@ -100,7 +100,7 @@ config COMMON_CLK_AXG_AUDIO
|
|||
aka axg, Say Y if you want audio subsystem to work.
|
||||
|
||||
config COMMON_CLK_G12A
|
||||
bool "G12 and SM1 SoC clock controllers support"
|
||||
tristate "G12 and SM1 SoC clock controllers support"
|
||||
depends on ARM64
|
||||
default y
|
||||
select COMMON_CLK_MESON_REGMAP
|
||||
|
@ -110,6 +110,7 @@ config COMMON_CLK_G12A
|
|||
select COMMON_CLK_MESON_AO_CLKC
|
||||
select COMMON_CLK_MESON_EE_CLKC
|
||||
select COMMON_CLK_MESON_CPU_DYNDIV
|
||||
select COMMON_CLK_MESON_VID_PLL_DIV
|
||||
select MFD_SYSCON
|
||||
help
|
||||
Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include "meson-aoclk.h"
|
||||
#include "axg-aoclk.h"
|
||||
|
||||
|
@ -326,6 +327,7 @@ static const struct of_device_id axg_aoclkc_match_table[] = {
|
|||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, axg_aoclkc_match_table);
|
||||
|
||||
static struct platform_driver axg_aoclkc_driver = {
|
||||
.probe = meson_aoclkc_probe,
|
||||
|
@ -335,4 +337,5 @@ static struct platform_driver axg_aoclkc_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
builtin_platform_driver(axg_aoclkc_driver);
|
||||
module_platform_driver(axg_aoclkc_driver);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "clk-regmap.h"
|
||||
#include "clk-pll.h"
|
||||
|
@ -1026,6 +1027,743 @@ static struct clk_regmap axg_sd_emmc_c_clk0 = {
|
|||
},
|
||||
};
|
||||
|
||||
/* VPU Clock */
|
||||
|
||||
static const struct clk_hw *axg_vpu_parent_hws[] = {
|
||||
&axg_fclk_div4.hw,
|
||||
&axg_fclk_div3.hw,
|
||||
&axg_fclk_div5.hw,
|
||||
&axg_fclk_div7.hw,
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vpu_0_sel = {
|
||||
.data = &(struct clk_regmap_mux_data){
|
||||
.offset = HHI_VPU_CLK_CNTL,
|
||||
.mask = 0x3,
|
||||
.shift = 9,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vpu_0_sel",
|
||||
.ops = &clk_regmap_mux_ops,
|
||||
.parent_hws = axg_vpu_parent_hws,
|
||||
.num_parents = ARRAY_SIZE(axg_vpu_parent_hws),
|
||||
/* We need a specific parent for VPU clock source, let it be set in DT */
|
||||
.flags = CLK_SET_RATE_NO_REPARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vpu_0_div = {
|
||||
.data = &(struct clk_regmap_div_data){
|
||||
.offset = HHI_VPU_CLK_CNTL,
|
||||
.shift = 0,
|
||||
.width = 7,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vpu_0_div",
|
||||
.ops = &clk_regmap_divider_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &axg_vpu_0_sel.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vpu_0 = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VPU_CLK_CNTL,
|
||||
.bit_idx = 8,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vpu_0",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &axg_vpu_0_div.hw },
|
||||
.num_parents = 1,
|
||||
/*
|
||||
* We want to avoid CCF to disable the VPU clock if
|
||||
* display has been set by Bootloader
|
||||
*/
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vpu_1_sel = {
|
||||
.data = &(struct clk_regmap_mux_data){
|
||||
.offset = HHI_VPU_CLK_CNTL,
|
||||
.mask = 0x3,
|
||||
.shift = 25,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vpu_1_sel",
|
||||
.ops = &clk_regmap_mux_ops,
|
||||
.parent_hws = axg_vpu_parent_hws,
|
||||
.num_parents = ARRAY_SIZE(axg_vpu_parent_hws),
|
||||
/* We need a specific parent for VPU clock source, let it be set in DT */
|
||||
.flags = CLK_SET_RATE_NO_REPARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vpu_1_div = {
|
||||
.data = &(struct clk_regmap_div_data){
|
||||
.offset = HHI_VPU_CLK_CNTL,
|
||||
.shift = 16,
|
||||
.width = 7,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vpu_1_div",
|
||||
.ops = &clk_regmap_divider_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &axg_vpu_1_sel.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vpu_1 = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VPU_CLK_CNTL,
|
||||
.bit_idx = 24,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vpu_1",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &axg_vpu_1_div.hw },
|
||||
.num_parents = 1,
|
||||
/*
|
||||
* We want to avoid CCF to disable the VPU clock if
|
||||
* display has been set by Bootloader
|
||||
*/
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vpu = {
|
||||
.data = &(struct clk_regmap_mux_data){
|
||||
.offset = HHI_VPU_CLK_CNTL,
|
||||
.mask = 1,
|
||||
.shift = 31,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vpu",
|
||||
.ops = &clk_regmap_mux_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&axg_vpu_0.hw,
|
||||
&axg_vpu_1.hw
|
||||
},
|
||||
.num_parents = 2,
|
||||
.flags = CLK_SET_RATE_NO_REPARENT,
|
||||
},
|
||||
};
|
||||
|
||||
/* VAPB Clock */
|
||||
|
||||
static struct clk_regmap axg_vapb_0_sel = {
|
||||
.data = &(struct clk_regmap_mux_data){
|
||||
.offset = HHI_VAPBCLK_CNTL,
|
||||
.mask = 0x3,
|
||||
.shift = 9,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vapb_0_sel",
|
||||
.ops = &clk_regmap_mux_ops,
|
||||
.parent_hws = axg_vpu_parent_hws,
|
||||
.num_parents = ARRAY_SIZE(axg_vpu_parent_hws),
|
||||
.flags = CLK_SET_RATE_NO_REPARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vapb_0_div = {
|
||||
.data = &(struct clk_regmap_div_data){
|
||||
.offset = HHI_VAPBCLK_CNTL,
|
||||
.shift = 0,
|
||||
.width = 7,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vapb_0_div",
|
||||
.ops = &clk_regmap_divider_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&axg_vapb_0_sel.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vapb_0 = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VAPBCLK_CNTL,
|
||||
.bit_idx = 8,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vapb_0",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&axg_vapb_0_div.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vapb_1_sel = {
|
||||
.data = &(struct clk_regmap_mux_data){
|
||||
.offset = HHI_VAPBCLK_CNTL,
|
||||
.mask = 0x3,
|
||||
.shift = 25,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vapb_1_sel",
|
||||
.ops = &clk_regmap_mux_ops,
|
||||
.parent_hws = axg_vpu_parent_hws,
|
||||
.num_parents = ARRAY_SIZE(axg_vpu_parent_hws),
|
||||
.flags = CLK_SET_RATE_NO_REPARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vapb_1_div = {
|
||||
.data = &(struct clk_regmap_div_data){
|
||||
.offset = HHI_VAPBCLK_CNTL,
|
||||
.shift = 16,
|
||||
.width = 7,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vapb_1_div",
|
||||
.ops = &clk_regmap_divider_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&axg_vapb_1_sel.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vapb_1 = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VAPBCLK_CNTL,
|
||||
.bit_idx = 24,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vapb_1",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&axg_vapb_1_div.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vapb_sel = {
|
||||
.data = &(struct clk_regmap_mux_data){
|
||||
.offset = HHI_VAPBCLK_CNTL,
|
||||
.mask = 1,
|
||||
.shift = 31,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vapb_sel",
|
||||
.ops = &clk_regmap_mux_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&axg_vapb_0.hw,
|
||||
&axg_vapb_1.hw
|
||||
},
|
||||
.num_parents = 2,
|
||||
.flags = CLK_SET_RATE_NO_REPARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vapb = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VAPBCLK_CNTL,
|
||||
.bit_idx = 30,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vapb",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &axg_vapb_sel.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
/* Video Clocks */
|
||||
|
||||
static const struct clk_hw *axg_vclk_parent_hws[] = {
|
||||
&axg_gp0_pll.hw,
|
||||
&axg_fclk_div4.hw,
|
||||
&axg_fclk_div3.hw,
|
||||
&axg_fclk_div5.hw,
|
||||
&axg_fclk_div2.hw,
|
||||
&axg_fclk_div7.hw,
|
||||
&axg_mpll1.hw,
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vclk_sel = {
|
||||
.data = &(struct clk_regmap_mux_data){
|
||||
.offset = HHI_VID_CLK_CNTL,
|
||||
.mask = 0x7,
|
||||
.shift = 16,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vclk_sel",
|
||||
.ops = &clk_regmap_mux_ops,
|
||||
.parent_hws = axg_vclk_parent_hws,
|
||||
.num_parents = ARRAY_SIZE(axg_vclk_parent_hws),
|
||||
.flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vclk2_sel = {
|
||||
.data = &(struct clk_regmap_mux_data){
|
||||
.offset = HHI_VIID_CLK_CNTL,
|
||||
.mask = 0x7,
|
||||
.shift = 16,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vclk2_sel",
|
||||
.ops = &clk_regmap_mux_ops,
|
||||
.parent_hws = axg_vclk_parent_hws,
|
||||
.num_parents = ARRAY_SIZE(axg_vclk_parent_hws),
|
||||
.flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vclk_input = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VID_CLK_DIV,
|
||||
.bit_idx = 16,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vclk_input",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &axg_vclk_sel.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vclk2_input = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VIID_CLK_DIV,
|
||||
.bit_idx = 16,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vclk2_input",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &axg_vclk2_sel.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vclk_div = {
|
||||
.data = &(struct clk_regmap_div_data){
|
||||
.offset = HHI_VID_CLK_DIV,
|
||||
.shift = 0,
|
||||
.width = 8,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vclk_div",
|
||||
.ops = &clk_regmap_divider_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&axg_vclk_input.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
.flags = CLK_GET_RATE_NOCACHE,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vclk2_div = {
|
||||
.data = &(struct clk_regmap_div_data){
|
||||
.offset = HHI_VIID_CLK_DIV,
|
||||
.shift = 0,
|
||||
.width = 8,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vclk2_div",
|
||||
.ops = &clk_regmap_divider_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&axg_vclk2_input.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
.flags = CLK_GET_RATE_NOCACHE,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vclk = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VID_CLK_CNTL,
|
||||
.bit_idx = 19,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vclk",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &axg_vclk_div.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vclk2 = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VIID_CLK_CNTL,
|
||||
.bit_idx = 19,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vclk2",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &axg_vclk2_div.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vclk_div1 = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VID_CLK_CNTL,
|
||||
.bit_idx = 0,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vclk_div1",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &axg_vclk.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vclk_div2_en = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VID_CLK_CNTL,
|
||||
.bit_idx = 1,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vclk_div2_en",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &axg_vclk.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vclk_div4_en = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VID_CLK_CNTL,
|
||||
.bit_idx = 2,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vclk_div4_en",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &axg_vclk.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vclk_div6_en = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VID_CLK_CNTL,
|
||||
.bit_idx = 3,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vclk_div6_en",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &axg_vclk.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vclk_div12_en = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VID_CLK_CNTL,
|
||||
.bit_idx = 4,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vclk_div12_en",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &axg_vclk.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vclk2_div1 = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VIID_CLK_CNTL,
|
||||
.bit_idx = 0,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vclk2_div1",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &axg_vclk2.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vclk2_div2_en = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VIID_CLK_CNTL,
|
||||
.bit_idx = 1,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vclk2_div2_en",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &axg_vclk2.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vclk2_div4_en = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VIID_CLK_CNTL,
|
||||
.bit_idx = 2,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vclk2_div4_en",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &axg_vclk2.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vclk2_div6_en = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VIID_CLK_CNTL,
|
||||
.bit_idx = 3,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vclk2_div6_en",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &axg_vclk2.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vclk2_div12_en = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VIID_CLK_CNTL,
|
||||
.bit_idx = 4,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vclk2_div12_en",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &axg_vclk2.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_fixed_factor axg_vclk_div2 = {
|
||||
.mult = 1,
|
||||
.div = 2,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vclk_div2",
|
||||
.ops = &clk_fixed_factor_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&axg_vclk_div2_en.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_fixed_factor axg_vclk_div4 = {
|
||||
.mult = 1,
|
||||
.div = 4,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vclk_div4",
|
||||
.ops = &clk_fixed_factor_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&axg_vclk_div4_en.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_fixed_factor axg_vclk_div6 = {
|
||||
.mult = 1,
|
||||
.div = 6,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vclk_div6",
|
||||
.ops = &clk_fixed_factor_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&axg_vclk_div6_en.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_fixed_factor axg_vclk_div12 = {
|
||||
.mult = 1,
|
||||
.div = 12,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vclk_div12",
|
||||
.ops = &clk_fixed_factor_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&axg_vclk_div12_en.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_fixed_factor axg_vclk2_div2 = {
|
||||
.mult = 1,
|
||||
.div = 2,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vclk2_div2",
|
||||
.ops = &clk_fixed_factor_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&axg_vclk2_div2_en.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_fixed_factor axg_vclk2_div4 = {
|
||||
.mult = 1,
|
||||
.div = 4,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vclk2_div4",
|
||||
.ops = &clk_fixed_factor_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&axg_vclk2_div4_en.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_fixed_factor axg_vclk2_div6 = {
|
||||
.mult = 1,
|
||||
.div = 6,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vclk2_div6",
|
||||
.ops = &clk_fixed_factor_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&axg_vclk2_div6_en.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_fixed_factor axg_vclk2_div12 = {
|
||||
.mult = 1,
|
||||
.div = 12,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vclk2_div12",
|
||||
.ops = &clk_fixed_factor_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&axg_vclk2_div12_en.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static u32 mux_table_cts_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 };
|
||||
static const struct clk_hw *axg_cts_parent_hws[] = {
|
||||
&axg_vclk_div1.hw,
|
||||
&axg_vclk_div2.hw,
|
||||
&axg_vclk_div4.hw,
|
||||
&axg_vclk_div6.hw,
|
||||
&axg_vclk_div12.hw,
|
||||
&axg_vclk2_div1.hw,
|
||||
&axg_vclk2_div2.hw,
|
||||
&axg_vclk2_div4.hw,
|
||||
&axg_vclk2_div6.hw,
|
||||
&axg_vclk2_div12.hw,
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_cts_encl_sel = {
|
||||
.data = &(struct clk_regmap_mux_data){
|
||||
.offset = HHI_VIID_CLK_DIV,
|
||||
.mask = 0xf,
|
||||
.shift = 12,
|
||||
.table = mux_table_cts_sel,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "cts_encl_sel",
|
||||
.ops = &clk_regmap_mux_ops,
|
||||
.parent_hws = axg_cts_parent_hws,
|
||||
.num_parents = ARRAY_SIZE(axg_cts_parent_hws),
|
||||
.flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_cts_encl = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VID_CLK_CNTL2,
|
||||
.bit_idx = 3,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "cts_encl",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&axg_cts_encl_sel.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
/* MIPI DSI Host Clock */
|
||||
|
||||
static u32 mux_table_axg_vdin_meas[] = { 0, 1, 2, 3, 6, 7 };
|
||||
static const struct clk_parent_data axg_vdin_meas_parent_data[] = {
|
||||
{ .fw_name = "xtal", },
|
||||
{ .hw = &axg_fclk_div4.hw },
|
||||
{ .hw = &axg_fclk_div3.hw },
|
||||
{ .hw = &axg_fclk_div5.hw },
|
||||
{ .hw = &axg_fclk_div2.hw },
|
||||
{ .hw = &axg_fclk_div7.hw },
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vdin_meas_sel = {
|
||||
.data = &(struct clk_regmap_mux_data){
|
||||
.offset = HHI_VDIN_MEAS_CLK_CNTL,
|
||||
.mask = 0x7,
|
||||
.shift = 21,
|
||||
.flags = CLK_MUX_ROUND_CLOSEST,
|
||||
.table = mux_table_axg_vdin_meas,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vdin_meas_sel",
|
||||
.ops = &clk_regmap_mux_ops,
|
||||
.parent_data = axg_vdin_meas_parent_data,
|
||||
.num_parents = ARRAY_SIZE(axg_vdin_meas_parent_data),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vdin_meas_div = {
|
||||
.data = &(struct clk_regmap_div_data){
|
||||
.offset = HHI_VDIN_MEAS_CLK_CNTL,
|
||||
.shift = 12,
|
||||
.width = 7,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vdin_meas_div",
|
||||
.ops = &clk_regmap_divider_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&axg_vdin_meas_sel.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_vdin_meas = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VDIN_MEAS_CLK_CNTL,
|
||||
.bit_idx = 20,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vdin_meas",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&axg_vdin_meas_div.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8,
|
||||
9, 10, 11, 13, 14, };
|
||||
static const struct clk_parent_data gen_clk_parent_data[] = {
|
||||
|
@ -1246,6 +1984,52 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = {
|
|||
[CLKID_HIFI_PLL_DCO] = &axg_hifi_pll_dco.hw,
|
||||
[CLKID_PCIE_PLL_DCO] = &axg_pcie_pll_dco.hw,
|
||||
[CLKID_PCIE_PLL_OD] = &axg_pcie_pll_od.hw,
|
||||
[CLKID_VPU_0_DIV] = &axg_vpu_0_div.hw,
|
||||
[CLKID_VPU_0_SEL] = &axg_vpu_0_sel.hw,
|
||||
[CLKID_VPU_0] = &axg_vpu_0.hw,
|
||||
[CLKID_VPU_1_DIV] = &axg_vpu_1_div.hw,
|
||||
[CLKID_VPU_1_SEL] = &axg_vpu_1_sel.hw,
|
||||
[CLKID_VPU_1] = &axg_vpu_1.hw,
|
||||
[CLKID_VPU] = &axg_vpu.hw,
|
||||
[CLKID_VAPB_0_DIV] = &axg_vapb_0_div.hw,
|
||||
[CLKID_VAPB_0_SEL] = &axg_vapb_0_sel.hw,
|
||||
[CLKID_VAPB_0] = &axg_vapb_0.hw,
|
||||
[CLKID_VAPB_1_DIV] = &axg_vapb_1_div.hw,
|
||||
[CLKID_VAPB_1_SEL] = &axg_vapb_1_sel.hw,
|
||||
[CLKID_VAPB_1] = &axg_vapb_1.hw,
|
||||
[CLKID_VAPB_SEL] = &axg_vapb_sel.hw,
|
||||
[CLKID_VAPB] = &axg_vapb.hw,
|
||||
[CLKID_VCLK] = &axg_vclk.hw,
|
||||
[CLKID_VCLK2] = &axg_vclk2.hw,
|
||||
[CLKID_VCLK_SEL] = &axg_vclk_sel.hw,
|
||||
[CLKID_VCLK2_SEL] = &axg_vclk2_sel.hw,
|
||||
[CLKID_VCLK_INPUT] = &axg_vclk_input.hw,
|
||||
[CLKID_VCLK2_INPUT] = &axg_vclk2_input.hw,
|
||||
[CLKID_VCLK_DIV] = &axg_vclk_div.hw,
|
||||
[CLKID_VCLK2_DIV] = &axg_vclk2_div.hw,
|
||||
[CLKID_VCLK_DIV2_EN] = &axg_vclk_div2_en.hw,
|
||||
[CLKID_VCLK_DIV4_EN] = &axg_vclk_div4_en.hw,
|
||||
[CLKID_VCLK_DIV6_EN] = &axg_vclk_div6_en.hw,
|
||||
[CLKID_VCLK_DIV12_EN] = &axg_vclk_div12_en.hw,
|
||||
[CLKID_VCLK2_DIV2_EN] = &axg_vclk2_div2_en.hw,
|
||||
[CLKID_VCLK2_DIV4_EN] = &axg_vclk2_div4_en.hw,
|
||||
[CLKID_VCLK2_DIV6_EN] = &axg_vclk2_div6_en.hw,
|
||||
[CLKID_VCLK2_DIV12_EN] = &axg_vclk2_div12_en.hw,
|
||||
[CLKID_VCLK_DIV1] = &axg_vclk_div1.hw,
|
||||
[CLKID_VCLK_DIV2] = &axg_vclk_div2.hw,
|
||||
[CLKID_VCLK_DIV4] = &axg_vclk_div4.hw,
|
||||
[CLKID_VCLK_DIV6] = &axg_vclk_div6.hw,
|
||||
[CLKID_VCLK_DIV12] = &axg_vclk_div12.hw,
|
||||
[CLKID_VCLK2_DIV1] = &axg_vclk2_div1.hw,
|
||||
[CLKID_VCLK2_DIV2] = &axg_vclk2_div2.hw,
|
||||
[CLKID_VCLK2_DIV4] = &axg_vclk2_div4.hw,
|
||||
[CLKID_VCLK2_DIV6] = &axg_vclk2_div6.hw,
|
||||
[CLKID_VCLK2_DIV12] = &axg_vclk2_div12.hw,
|
||||
[CLKID_CTS_ENCL_SEL] = &axg_cts_encl_sel.hw,
|
||||
[CLKID_CTS_ENCL] = &axg_cts_encl.hw,
|
||||
[CLKID_VDIN_MEAS_SEL] = &axg_vdin_meas_sel.hw,
|
||||
[CLKID_VDIN_MEAS_DIV] = &axg_vdin_meas_div.hw,
|
||||
[CLKID_VDIN_MEAS] = &axg_vdin_meas.hw,
|
||||
[NR_CLKS] = NULL,
|
||||
},
|
||||
.num = NR_CLKS,
|
||||
|
@ -1341,6 +2125,42 @@ static struct clk_regmap *const axg_clk_regmaps[] = {
|
|||
&axg_hifi_pll_dco,
|
||||
&axg_pcie_pll_dco,
|
||||
&axg_pcie_pll_od,
|
||||
&axg_vpu_0_div,
|
||||
&axg_vpu_0_sel,
|
||||
&axg_vpu_0,
|
||||
&axg_vpu_1_div,
|
||||
&axg_vpu_1_sel,
|
||||
&axg_vpu_1,
|
||||
&axg_vpu,
|
||||
&axg_vapb_0_div,
|
||||
&axg_vapb_0_sel,
|
||||
&axg_vapb_0,
|
||||
&axg_vapb_1_div,
|
||||
&axg_vapb_1_sel,
|
||||
&axg_vapb_1,
|
||||
&axg_vapb_sel,
|
||||
&axg_vapb,
|
||||
&axg_vclk,
|
||||
&axg_vclk2,
|
||||
&axg_vclk_sel,
|
||||
&axg_vclk2_sel,
|
||||
&axg_vclk_input,
|
||||
&axg_vclk2_input,
|
||||
&axg_vclk_div,
|
||||
&axg_vclk2_div,
|
||||
&axg_vclk_div2_en,
|
||||
&axg_vclk_div4_en,
|
||||
&axg_vclk_div6_en,
|
||||
&axg_vclk_div12_en,
|
||||
&axg_vclk2_div2_en,
|
||||
&axg_vclk2_div4_en,
|
||||
&axg_vclk2_div6_en,
|
||||
&axg_vclk2_div12_en,
|
||||
&axg_cts_encl_sel,
|
||||
&axg_cts_encl,
|
||||
&axg_vdin_meas_sel,
|
||||
&axg_vdin_meas_div,
|
||||
&axg_vdin_meas,
|
||||
};
|
||||
|
||||
static const struct meson_eeclkc_data axg_clkc_data = {
|
||||
|
@ -1354,6 +2174,7 @@ static const struct of_device_id clkc_match_table[] = {
|
|||
{ .compatible = "amlogic,axg-clkc", .data = &axg_clkc_data },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, clkc_match_table);
|
||||
|
||||
static struct platform_driver axg_driver = {
|
||||
.probe = meson_eeclkc_probe,
|
||||
|
@ -1363,4 +2184,5 @@ static struct platform_driver axg_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
builtin_platform_driver(axg_driver);
|
||||
module_platform_driver(axg_driver);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -139,8 +139,29 @@
|
|||
#define CLKID_HIFI_PLL_DCO 88
|
||||
#define CLKID_PCIE_PLL_DCO 89
|
||||
#define CLKID_PCIE_PLL_OD 90
|
||||
#define CLKID_VPU_0_DIV 91
|
||||
#define CLKID_VPU_1_DIV 94
|
||||
#define CLKID_VAPB_0_DIV 98
|
||||
#define CLKID_VAPB_1_DIV 101
|
||||
#define CLKID_VCLK_SEL 108
|
||||
#define CLKID_VCLK2_SEL 109
|
||||
#define CLKID_VCLK_INPUT 110
|
||||
#define CLKID_VCLK2_INPUT 111
|
||||
#define CLKID_VCLK_DIV 112
|
||||
#define CLKID_VCLK2_DIV 113
|
||||
#define CLKID_VCLK_DIV2_EN 114
|
||||
#define CLKID_VCLK_DIV4_EN 115
|
||||
#define CLKID_VCLK_DIV6_EN 116
|
||||
#define CLKID_VCLK_DIV12_EN 117
|
||||
#define CLKID_VCLK2_DIV2_EN 118
|
||||
#define CLKID_VCLK2_DIV4_EN 119
|
||||
#define CLKID_VCLK2_DIV6_EN 120
|
||||
#define CLKID_VCLK2_DIV12_EN 121
|
||||
#define CLKID_CTS_ENCL_SEL 132
|
||||
#define CLKID_VDIN_MEAS_SEL 134
|
||||
#define CLKID_VDIN_MEAS_DIV 135
|
||||
|
||||
#define NR_CLKS 91
|
||||
#define NR_CLKS 137
|
||||
|
||||
/* include the CLKIDs that have been made part of the DT binding */
|
||||
#include <dt-bindings/clock/axg-clkc.h>
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include "meson-aoclk.h"
|
||||
#include "g12a-aoclk.h"
|
||||
|
||||
|
@ -461,6 +462,7 @@ static const struct of_device_id g12a_aoclkc_match_table[] = {
|
|||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, g12a_aoclkc_match_table);
|
||||
|
||||
static struct platform_driver g12a_aoclkc_driver = {
|
||||
.probe = meson_aoclkc_probe,
|
||||
|
@ -470,4 +472,5 @@ static struct platform_driver g12a_aoclkc_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
builtin_platform_driver(g12a_aoclkc_driver);
|
||||
module_platform_driver(g12a_aoclkc_driver);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "clk-mpll.h"
|
||||
#include "clk-pll.h"
|
||||
|
@ -3657,6 +3658,68 @@ static struct clk_regmap g12a_hdmi_tx = {
|
|||
},
|
||||
};
|
||||
|
||||
/* MIPI DSI Host Clocks */
|
||||
|
||||
static const struct clk_hw *g12a_mipi_dsi_pxclk_parent_hws[] = {
|
||||
&g12a_vid_pll.hw,
|
||||
&g12a_gp0_pll.hw,
|
||||
&g12a_hifi_pll.hw,
|
||||
&g12a_mpll1.hw,
|
||||
&g12a_fclk_div2.hw,
|
||||
&g12a_fclk_div2p5.hw,
|
||||
&g12a_fclk_div3.hw,
|
||||
&g12a_fclk_div7.hw,
|
||||
};
|
||||
|
||||
static struct clk_regmap g12a_mipi_dsi_pxclk_sel = {
|
||||
.data = &(struct clk_regmap_mux_data){
|
||||
.offset = HHI_MIPIDSI_PHY_CLK_CNTL,
|
||||
.mask = 0x7,
|
||||
.shift = 12,
|
||||
.flags = CLK_MUX_ROUND_CLOSEST,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mipi_dsi_pxclk_sel",
|
||||
.ops = &clk_regmap_mux_ops,
|
||||
.parent_hws = g12a_mipi_dsi_pxclk_parent_hws,
|
||||
.num_parents = ARRAY_SIZE(g12a_mipi_dsi_pxclk_parent_hws),
|
||||
.flags = CLK_SET_RATE_NO_REPARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap g12a_mipi_dsi_pxclk_div = {
|
||||
.data = &(struct clk_regmap_div_data){
|
||||
.offset = HHI_MIPIDSI_PHY_CLK_CNTL,
|
||||
.shift = 0,
|
||||
.width = 7,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mipi_dsi_pxclk_div",
|
||||
.ops = &clk_regmap_divider_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&g12a_mipi_dsi_pxclk_sel.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap g12a_mipi_dsi_pxclk = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_MIPIDSI_PHY_CLK_CNTL,
|
||||
.bit_idx = 8,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "mipi_dsi_pxclk",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&g12a_mipi_dsi_pxclk_div.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
/* HDMI Clocks */
|
||||
|
||||
static const struct clk_parent_data g12a_hdmi_parent_data[] = {
|
||||
|
@ -4402,6 +4465,9 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = {
|
|||
[CLKID_SPICC1_SCLK_SEL] = &g12a_spicc1_sclk_sel.hw,
|
||||
[CLKID_SPICC1_SCLK_DIV] = &g12a_spicc1_sclk_div.hw,
|
||||
[CLKID_SPICC1_SCLK] = &g12a_spicc1_sclk.hw,
|
||||
[CLKID_MIPI_DSI_PXCLK_SEL] = &g12a_mipi_dsi_pxclk_sel.hw,
|
||||
[CLKID_MIPI_DSI_PXCLK_DIV] = &g12a_mipi_dsi_pxclk_div.hw,
|
||||
[CLKID_MIPI_DSI_PXCLK] = &g12a_mipi_dsi_pxclk.hw,
|
||||
[NR_CLKS] = NULL,
|
||||
},
|
||||
.num = NR_CLKS,
|
||||
|
@ -4657,6 +4723,9 @@ static struct clk_hw_onecell_data g12b_hw_onecell_data = {
|
|||
[CLKID_SPICC1_SCLK_SEL] = &g12a_spicc1_sclk_sel.hw,
|
||||
[CLKID_SPICC1_SCLK_DIV] = &g12a_spicc1_sclk_div.hw,
|
||||
[CLKID_SPICC1_SCLK] = &g12a_spicc1_sclk.hw,
|
||||
[CLKID_MIPI_DSI_PXCLK_SEL] = &g12a_mipi_dsi_pxclk_sel.hw,
|
||||
[CLKID_MIPI_DSI_PXCLK_DIV] = &g12a_mipi_dsi_pxclk_div.hw,
|
||||
[CLKID_MIPI_DSI_PXCLK] = &g12a_mipi_dsi_pxclk.hw,
|
||||
[NR_CLKS] = NULL,
|
||||
},
|
||||
.num = NR_CLKS,
|
||||
|
@ -4903,6 +4972,9 @@ static struct clk_hw_onecell_data sm1_hw_onecell_data = {
|
|||
[CLKID_NNA_CORE_CLK_SEL] = &sm1_nna_core_clk_sel.hw,
|
||||
[CLKID_NNA_CORE_CLK_DIV] = &sm1_nna_core_clk_div.hw,
|
||||
[CLKID_NNA_CORE_CLK] = &sm1_nna_core_clk.hw,
|
||||
[CLKID_MIPI_DSI_PXCLK_SEL] = &g12a_mipi_dsi_pxclk_sel.hw,
|
||||
[CLKID_MIPI_DSI_PXCLK_DIV] = &g12a_mipi_dsi_pxclk_div.hw,
|
||||
[CLKID_MIPI_DSI_PXCLK] = &g12a_mipi_dsi_pxclk.hw,
|
||||
[NR_CLKS] = NULL,
|
||||
},
|
||||
.num = NR_CLKS,
|
||||
|
@ -5150,16 +5222,20 @@ static struct clk_regmap *const g12a_clk_regmaps[] = {
|
|||
&sm1_nna_core_clk_sel,
|
||||
&sm1_nna_core_clk_div,
|
||||
&sm1_nna_core_clk,
|
||||
&g12a_mipi_dsi_pxclk_sel,
|
||||
&g12a_mipi_dsi_pxclk_div,
|
||||
&g12a_mipi_dsi_pxclk,
|
||||
};
|
||||
|
||||
static const struct reg_sequence g12a_init_regs[] = {
|
||||
{ .reg = HHI_MPLL_CNTL0, .def = 0x00000543 },
|
||||
};
|
||||
|
||||
static int meson_g12a_dvfs_setup_common(struct platform_device *pdev,
|
||||
#define DVFS_CON_ID "dvfs"
|
||||
|
||||
static int meson_g12a_dvfs_setup_common(struct device *dev,
|
||||
struct clk_hw **hws)
|
||||
{
|
||||
const char *notifier_clk_name;
|
||||
struct clk *notifier_clk;
|
||||
struct clk_hw *xtal;
|
||||
int ret;
|
||||
|
@ -5168,21 +5244,22 @@ static int meson_g12a_dvfs_setup_common(struct platform_device *pdev,
|
|||
|
||||
/* Setup clock notifier for cpu_clk_postmux0 */
|
||||
g12a_cpu_clk_postmux0_nb_data.xtal = xtal;
|
||||
notifier_clk_name = clk_hw_get_name(&g12a_cpu_clk_postmux0.hw);
|
||||
notifier_clk = __clk_lookup(notifier_clk_name);
|
||||
ret = clk_notifier_register(notifier_clk,
|
||||
&g12a_cpu_clk_postmux0_nb_data.nb);
|
||||
notifier_clk = devm_clk_hw_get_clk(dev, &g12a_cpu_clk_postmux0.hw,
|
||||
DVFS_CON_ID);
|
||||
ret = devm_clk_notifier_register(dev, notifier_clk,
|
||||
&g12a_cpu_clk_postmux0_nb_data.nb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register the cpu_clk_postmux0 notifier\n");
|
||||
dev_err(dev, "failed to register the cpu_clk_postmux0 notifier\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Setup clock notifier for cpu_clk_dyn mux */
|
||||
notifier_clk_name = clk_hw_get_name(&g12a_cpu_clk_dyn.hw);
|
||||
notifier_clk = __clk_lookup(notifier_clk_name);
|
||||
ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb);
|
||||
notifier_clk = devm_clk_hw_get_clk(dev, &g12a_cpu_clk_dyn.hw,
|
||||
DVFS_CON_ID);
|
||||
ret = devm_clk_notifier_register(dev, notifier_clk,
|
||||
&g12a_cpu_clk_mux_nb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register the cpu_clk_dyn notifier\n");
|
||||
dev_err(dev, "failed to register the cpu_clk_dyn notifier\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -5192,33 +5269,34 @@ static int meson_g12a_dvfs_setup_common(struct platform_device *pdev,
|
|||
static int meson_g12b_dvfs_setup(struct platform_device *pdev)
|
||||
{
|
||||
struct clk_hw **hws = g12b_hw_onecell_data.hws;
|
||||
const char *notifier_clk_name;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct clk *notifier_clk;
|
||||
struct clk_hw *xtal;
|
||||
int ret;
|
||||
|
||||
ret = meson_g12a_dvfs_setup_common(pdev, hws);
|
||||
ret = meson_g12a_dvfs_setup_common(dev, hws);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
xtal = clk_hw_get_parent_by_index(hws[CLKID_CPU_CLK_DYN1_SEL], 0);
|
||||
|
||||
/* Setup clock notifier for cpu_clk mux */
|
||||
notifier_clk_name = clk_hw_get_name(&g12b_cpu_clk.hw);
|
||||
notifier_clk = __clk_lookup(notifier_clk_name);
|
||||
ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb);
|
||||
notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpu_clk.hw,
|
||||
DVFS_CON_ID);
|
||||
ret = devm_clk_notifier_register(dev, notifier_clk,
|
||||
&g12a_cpu_clk_mux_nb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register the cpu_clk notifier\n");
|
||||
dev_err(dev, "failed to register the cpu_clk notifier\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Setup clock notifier for sys1_pll */
|
||||
notifier_clk_name = clk_hw_get_name(&g12b_sys1_pll.hw);
|
||||
notifier_clk = __clk_lookup(notifier_clk_name);
|
||||
ret = clk_notifier_register(notifier_clk,
|
||||
&g12b_cpu_clk_sys1_pll_nb_data.nb);
|
||||
notifier_clk = devm_clk_hw_get_clk(dev, &g12b_sys1_pll.hw,
|
||||
DVFS_CON_ID);
|
||||
ret = devm_clk_notifier_register(dev, notifier_clk,
|
||||
&g12b_cpu_clk_sys1_pll_nb_data.nb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register the sys1_pll notifier\n");
|
||||
dev_err(dev, "failed to register the sys1_pll notifier\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -5226,40 +5304,39 @@ static int meson_g12b_dvfs_setup(struct platform_device *pdev)
|
|||
|
||||
/* Setup clock notifier for cpub_clk_postmux0 */
|
||||
g12b_cpub_clk_postmux0_nb_data.xtal = xtal;
|
||||
notifier_clk_name = clk_hw_get_name(&g12b_cpub_clk_postmux0.hw);
|
||||
notifier_clk = __clk_lookup(notifier_clk_name);
|
||||
ret = clk_notifier_register(notifier_clk,
|
||||
&g12b_cpub_clk_postmux0_nb_data.nb);
|
||||
notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpub_clk_postmux0.hw,
|
||||
DVFS_CON_ID);
|
||||
ret = devm_clk_notifier_register(dev, notifier_clk,
|
||||
&g12b_cpub_clk_postmux0_nb_data.nb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register the cpub_clk_postmux0 notifier\n");
|
||||
dev_err(dev, "failed to register the cpub_clk_postmux0 notifier\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Setup clock notifier for cpub_clk_dyn mux */
|
||||
notifier_clk_name = clk_hw_get_name(&g12b_cpub_clk_dyn.hw);
|
||||
notifier_clk = __clk_lookup(notifier_clk_name);
|
||||
ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb);
|
||||
notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpub_clk_dyn.hw, "dvfs");
|
||||
ret = devm_clk_notifier_register(dev, notifier_clk,
|
||||
&g12a_cpu_clk_mux_nb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register the cpub_clk_dyn notifier\n");
|
||||
dev_err(dev, "failed to register the cpub_clk_dyn notifier\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Setup clock notifier for cpub_clk mux */
|
||||
notifier_clk_name = clk_hw_get_name(&g12b_cpub_clk.hw);
|
||||
notifier_clk = __clk_lookup(notifier_clk_name);
|
||||
ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb);
|
||||
notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpub_clk.hw, DVFS_CON_ID);
|
||||
ret = devm_clk_notifier_register(dev, notifier_clk,
|
||||
&g12a_cpu_clk_mux_nb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register the cpub_clk notifier\n");
|
||||
dev_err(dev, "failed to register the cpub_clk notifier\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Setup clock notifier for sys_pll */
|
||||
notifier_clk_name = clk_hw_get_name(&g12a_sys_pll.hw);
|
||||
notifier_clk = __clk_lookup(notifier_clk_name);
|
||||
ret = clk_notifier_register(notifier_clk,
|
||||
&g12b_cpub_clk_sys_pll_nb_data.nb);
|
||||
notifier_clk = devm_clk_hw_get_clk(dev, &g12a_sys_pll.hw, DVFS_CON_ID);
|
||||
ret = devm_clk_notifier_register(dev, notifier_clk,
|
||||
&g12b_cpub_clk_sys_pll_nb_data.nb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register the sys_pll notifier\n");
|
||||
dev_err(dev, "failed to register the sys_pll notifier\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -5269,29 +5346,29 @@ static int meson_g12b_dvfs_setup(struct platform_device *pdev)
|
|||
static int meson_g12a_dvfs_setup(struct platform_device *pdev)
|
||||
{
|
||||
struct clk_hw **hws = g12a_hw_onecell_data.hws;
|
||||
const char *notifier_clk_name;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct clk *notifier_clk;
|
||||
int ret;
|
||||
|
||||
ret = meson_g12a_dvfs_setup_common(pdev, hws);
|
||||
ret = meson_g12a_dvfs_setup_common(dev, hws);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Setup clock notifier for cpu_clk mux */
|
||||
notifier_clk_name = clk_hw_get_name(&g12a_cpu_clk.hw);
|
||||
notifier_clk = __clk_lookup(notifier_clk_name);
|
||||
ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb);
|
||||
notifier_clk = devm_clk_hw_get_clk(dev, &g12a_cpu_clk.hw, DVFS_CON_ID);
|
||||
ret = devm_clk_notifier_register(dev, notifier_clk,
|
||||
&g12a_cpu_clk_mux_nb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register the cpu_clk notifier\n");
|
||||
dev_err(dev, "failed to register the cpu_clk notifier\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Setup clock notifier for sys_pll */
|
||||
notifier_clk_name = clk_hw_get_name(&g12a_sys_pll.hw);
|
||||
notifier_clk = __clk_lookup(notifier_clk_name);
|
||||
ret = clk_notifier_register(notifier_clk, &g12a_sys_pll_nb_data.nb);
|
||||
notifier_clk = devm_clk_hw_get_clk(dev, &g12a_sys_pll.hw, DVFS_CON_ID);
|
||||
ret = devm_clk_notifier_register(dev, notifier_clk,
|
||||
&g12a_sys_pll_nb_data.nb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register the sys_pll notifier\n");
|
||||
dev_err(dev, "failed to register the sys_pll notifier\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -5370,6 +5447,7 @@ static const struct of_device_id clkc_match_table[] = {
|
|||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, clkc_match_table);
|
||||
|
||||
static struct platform_driver g12a_driver = {
|
||||
.probe = meson_g12a_probe,
|
||||
|
@ -5379,4 +5457,5 @@ static struct platform_driver g12a_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
builtin_platform_driver(g12a_driver);
|
||||
module_platform_driver(g12a_driver);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -264,8 +264,9 @@
|
|||
#define CLKID_NNA_AXI_CLK_DIV 263
|
||||
#define CLKID_NNA_CORE_CLK_SEL 265
|
||||
#define CLKID_NNA_CORE_CLK_DIV 266
|
||||
#define CLKID_MIPI_DSI_PXCLK_DIV 268
|
||||
|
||||
#define NR_CLKS 268
|
||||
#define NR_CLKS 271
|
||||
|
||||
/* include the CLKIDs that have been made part of the DT binding */
|
||||
#include <dt-bindings/clock/g12a-clkc.h>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include "meson-aoclk.h"
|
||||
#include "gxbb-aoclk.h"
|
||||
|
||||
|
@ -287,6 +288,7 @@ static const struct of_device_id gxbb_aoclkc_match_table[] = {
|
|||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, gxbb_aoclkc_match_table);
|
||||
|
||||
static struct platform_driver gxbb_aoclkc_driver = {
|
||||
.probe = meson_aoclkc_probe,
|
||||
|
@ -295,4 +297,5 @@ static struct platform_driver gxbb_aoclkc_driver = {
|
|||
.of_match_table = gxbb_aoclkc_match_table,
|
||||
},
|
||||
};
|
||||
builtin_platform_driver(gxbb_aoclkc_driver);
|
||||
module_platform_driver(gxbb_aoclkc_driver);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "gxbb.h"
|
||||
#include "clk-regmap.h"
|
||||
|
@ -3519,6 +3520,7 @@ static const struct of_device_id clkc_match_table[] = {
|
|||
{ .compatible = "amlogic,gxl-clkc", .data = &gxl_clkc_data },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, clkc_match_table);
|
||||
|
||||
static struct platform_driver gxbb_driver = {
|
||||
.probe = meson_eeclkc_probe,
|
||||
|
@ -3528,4 +3530,5 @@ static struct platform_driver gxbb_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
builtin_platform_driver(gxbb_driver);
|
||||
module_platform_driver(gxbb_driver);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include <linux/reset-controller.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include "meson-aoclk.h"
|
||||
|
||||
|
@ -84,3 +86,5 @@ int meson_aoclkc_probe(struct platform_device *pdev)
|
|||
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
|
||||
(void *) data->hw_data);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(meson_aoclkc_probe);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "clk-regmap.h"
|
||||
#include "meson-eeclk.h"
|
||||
|
@ -54,3 +55,5 @@ int meson_eeclkc_probe(struct platform_device *pdev)
|
|||
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
|
||||
data->hw_onecell_data);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(meson_eeclkc_probe);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define NB_GPIO1_LATCH 0xC
|
||||
#define XTAL_MODE BIT(31)
|
||||
#define NB_GPIO1_LATCH 0x8
|
||||
#define XTAL_MODE BIT(9)
|
||||
|
||||
static int armada_3700_xtal_clock_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
|
|
@ -44,7 +44,7 @@ config QCOM_CLK_APCC_MSM8996
|
|||
help
|
||||
Support for the CPU clock controller on msm8996 devices.
|
||||
Say Y if you want to support CPU clock scaling using CPUfreq
|
||||
drivers for dyanmic power management.
|
||||
drivers for dynamic power management.
|
||||
|
||||
config QCOM_CLK_RPM
|
||||
tristate "RPM based Clock Controller"
|
||||
|
@ -290,6 +290,15 @@ config QCS_GCC_404
|
|||
Say Y if you want to use multimedia devices or peripheral
|
||||
devices such as UART, SPI, I2C, USB, SD/eMMC, PCIe etc.
|
||||
|
||||
config SC_CAMCC_7180
|
||||
tristate "SC7180 Camera Clock Controller"
|
||||
select SC_GCC_7180
|
||||
help
|
||||
Support for the camera clock controller on Qualcomm Technologies, Inc
|
||||
SC7180 devices.
|
||||
Say Y if you want to support camera devices and functionality such as
|
||||
capturing pictures.
|
||||
|
||||
config SC_DISPCC_7180
|
||||
tristate "SC7180 Display Clock Controller"
|
||||
select SC_GCC_7180
|
||||
|
@ -413,6 +422,14 @@ config SDM_LPASSCC_845
|
|||
Say Y if you want to use the LPASS branch clocks of the LPASS clock
|
||||
controller to reset the LPASS subsystem.
|
||||
|
||||
config SDX_GCC_55
|
||||
tristate "SDX55 Global Clock Controller"
|
||||
select QCOM_GDSC
|
||||
help
|
||||
Support for the global clock controller on SDX55 devices.
|
||||
Say Y if you want to use peripheral devices such as UART,
|
||||
SPI, I2C, USB, SD/UFS, PCIe etc.
|
||||
|
||||
config SM_DISPCC_8250
|
||||
tristate "SM8150 and SM8250 Display Clock Controller"
|
||||
depends on SM_GCC_8150 || SM_GCC_8250
|
||||
|
@ -502,4 +519,10 @@ config KRAITCC
|
|||
Support for the Krait CPU clocks on Qualcomm devices.
|
||||
Say Y if you want to support CPU frequency scaling.
|
||||
|
||||
config CLK_GFM_LPASS_SM8250
|
||||
tristate "SM8250 GFM LPASS Clocks"
|
||||
help
|
||||
Support for the Glitch Free Mux (GFM) Low power audio
|
||||
subsystem (LPASS) clocks found on SM8250 SoCs.
|
||||
|
||||
endif
|
||||
|
|
|
@ -19,6 +19,7 @@ clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
|
|||
# Keep alphabetically sorted by config
|
||||
obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
|
||||
obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o
|
||||
obj-$(CONFIG_CLK_GFM_LPASS_SM8250) += lpass-gfm-sm8250.o
|
||||
obj-$(CONFIG_IPQ_APSS_PLL) += apss-ipq-pll.o
|
||||
obj-$(CONFIG_IPQ_APSS_6018) += apss-ipq6018.o
|
||||
obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o
|
||||
|
@ -51,6 +52,7 @@ obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
|
|||
obj-$(CONFIG_QCS_GCC_404) += gcc-qcs404.o
|
||||
obj-$(CONFIG_QCS_Q6SSTOP_404) += q6sstop-qcs404.o
|
||||
obj-$(CONFIG_QCS_TURING_404) += turingcc-qcs404.o
|
||||
obj-$(CONFIG_SC_CAMCC_7180) += camcc-sc7180.o
|
||||
obj-$(CONFIG_SC_DISPCC_7180) += dispcc-sc7180.o
|
||||
obj-$(CONFIG_SC_GCC_7180) += gcc-sc7180.o
|
||||
obj-$(CONFIG_SC_GPUCC_7180) += gpucc-sc7180.o
|
||||
|
@ -64,6 +66,7 @@ obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o
|
|||
obj-$(CONFIG_SDM_GPUCC_845) += gpucc-sdm845.o
|
||||
obj-$(CONFIG_SDM_LPASSCC_845) += lpasscc-sdm845.o
|
||||
obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
|
||||
obj-$(CONFIG_SDX_GCC_55) += gcc-sdx55.o
|
||||
obj-$(CONFIG_SM_DISPCC_8250) += dispcc-sm8250.o
|
||||
obj-$(CONFIG_SM_GCC_8150) += gcc-sm8150.o
|
||||
obj-$(CONFIG_SM_GCC_8250) += gcc-sm8250.o
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -116,6 +116,16 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = {
|
|||
[PLL_OFF_OPMODE] = 0x38,
|
||||
[PLL_OFF_ALPHA_VAL] = 0x40,
|
||||
},
|
||||
[CLK_ALPHA_PLL_TYPE_AGERA] = {
|
||||
[PLL_OFF_L_VAL] = 0x04,
|
||||
[PLL_OFF_ALPHA_VAL] = 0x08,
|
||||
[PLL_OFF_USER_CTL] = 0x0c,
|
||||
[PLL_OFF_CONFIG_CTL] = 0x10,
|
||||
[PLL_OFF_CONFIG_CTL_U] = 0x14,
|
||||
[PLL_OFF_TEST_CTL] = 0x18,
|
||||
[PLL_OFF_TEST_CTL_U] = 0x1c,
|
||||
[PLL_OFF_STATUS] = 0x2c,
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_alpha_pll_regs);
|
||||
|
||||
|
@ -207,6 +217,13 @@ static int wait_for_pll(struct clk_alpha_pll *pll, u32 mask, bool inverse,
|
|||
#define wait_for_pll_update_ack_clear(pll) \
|
||||
wait_for_pll(pll, ALPHA_PLL_ACK_LATCH, 1, "update_ack_clear")
|
||||
|
||||
static void clk_alpha_pll_write_config(struct regmap *regmap, unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
if (val)
|
||||
regmap_write(regmap, reg, val);
|
||||
}
|
||||
|
||||
void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
|
||||
const struct alpha_pll_config *config)
|
||||
{
|
||||
|
@ -1004,33 +1021,19 @@ void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
|
|||
{
|
||||
u32 val, mask;
|
||||
|
||||
if (config->l)
|
||||
regmap_write(regmap, PLL_L_VAL(pll), config->l);
|
||||
|
||||
if (config->alpha)
|
||||
regmap_write(regmap, PLL_FRAC(pll), config->alpha);
|
||||
|
||||
if (config->config_ctl_val)
|
||||
regmap_write(regmap, PLL_CONFIG_CTL(pll),
|
||||
clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), config->l);
|
||||
clk_alpha_pll_write_config(regmap, PLL_FRAC(pll), config->alpha);
|
||||
clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL(pll),
|
||||
config->config_ctl_val);
|
||||
|
||||
if (config->config_ctl_hi_val)
|
||||
regmap_write(regmap, PLL_CONFIG_CTL_U(pll),
|
||||
clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U(pll),
|
||||
config->config_ctl_hi_val);
|
||||
|
||||
if (config->user_ctl_val)
|
||||
regmap_write(regmap, PLL_USER_CTL(pll), config->user_ctl_val);
|
||||
|
||||
if (config->user_ctl_hi_val)
|
||||
regmap_write(regmap, PLL_USER_CTL_U(pll),
|
||||
clk_alpha_pll_write_config(regmap, PLL_USER_CTL(pll),
|
||||
config->user_ctl_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_USER_CTL_U(pll),
|
||||
config->user_ctl_hi_val);
|
||||
|
||||
if (config->test_ctl_val)
|
||||
regmap_write(regmap, PLL_TEST_CTL(pll),
|
||||
clk_alpha_pll_write_config(regmap, PLL_TEST_CTL(pll),
|
||||
config->test_ctl_val);
|
||||
|
||||
if (config->test_ctl_hi_val)
|
||||
regmap_write(regmap, PLL_TEST_CTL_U(pll),
|
||||
clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U(pll),
|
||||
config->test_ctl_hi_val);
|
||||
|
||||
if (config->post_div_mask) {
|
||||
|
@ -1145,25 +1148,38 @@ static unsigned long alpha_pll_fabia_recalc_rate(struct clk_hw *hw,
|
|||
return alpha_pll_calc_rate(parent_rate, l, frac, alpha_width);
|
||||
}
|
||||
|
||||
/*
|
||||
* Due to limited number of bits for fractional rate programming, the
|
||||
* rounded up rate could be marginally higher than the requested rate.
|
||||
*/
|
||||
static int alpha_pll_check_rate_margin(struct clk_hw *hw,
|
||||
unsigned long rrate, unsigned long rate)
|
||||
{
|
||||
unsigned long rate_margin = rate + PLL_RATE_MARGIN;
|
||||
|
||||
if (rrate > rate_margin || rrate < rate) {
|
||||
pr_err("%s: Rounded rate %lu not within range [%lu, %lu)\n",
|
||||
clk_hw_get_name(hw), rrate, rate, rate_margin);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alpha_pll_fabia_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long prate)
|
||||
{
|
||||
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
|
||||
u32 l, alpha_width = pll_alpha_width(pll);
|
||||
unsigned long rrate;
|
||||
int ret;
|
||||
u64 a;
|
||||
unsigned long rrate, max = rate + PLL_RATE_MARGIN;
|
||||
|
||||
rrate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width);
|
||||
|
||||
/*
|
||||
* Due to limited number of bits for fractional rate programming, the
|
||||
* rounded up rate could be marginally higher than the requested rate.
|
||||
*/
|
||||
if (rrate > (rate + PLL_RATE_MARGIN) || rrate < rate) {
|
||||
pr_err("%s: Rounded rate %lu not within range [%lu, %lu)\n",
|
||||
clk_hw_get_name(hw), rrate, rate, max);
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = alpha_pll_check_rate_margin(hw, rrate, rate);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l);
|
||||
regmap_write(pll->clkr.regmap, PLL_FRAC(pll), a);
|
||||
|
@ -1206,12 +1222,10 @@ static int alpha_pll_fabia_prepare(struct clk_hw *hw)
|
|||
|
||||
rrate = alpha_pll_round_rate(cal_freq, clk_hw_get_rate(parent_hw),
|
||||
&cal_l, &a, alpha_width);
|
||||
/*
|
||||
* Due to a limited number of bits for fractional rate programming, the
|
||||
* rounded up rate could be marginally higher than the requested rate.
|
||||
*/
|
||||
if (rrate > (cal_freq + PLL_RATE_MARGIN) || rrate < cal_freq)
|
||||
return -EINVAL;
|
||||
|
||||
ret = alpha_pll_check_rate_margin(hw, rrate, cal_freq);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Setup PLL for calibration frequency */
|
||||
regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), cal_l);
|
||||
|
@ -1388,49 +1402,27 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_fabia_ops);
|
|||
void clk_trion_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
|
||||
const struct alpha_pll_config *config)
|
||||
{
|
||||
if (config->l)
|
||||
regmap_write(regmap, PLL_L_VAL(pll), config->l);
|
||||
|
||||
clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), config->l);
|
||||
regmap_write(regmap, PLL_CAL_L_VAL(pll), TRION_PLL_CAL_VAL);
|
||||
|
||||
if (config->alpha)
|
||||
regmap_write(regmap, PLL_ALPHA_VAL(pll), config->alpha);
|
||||
|
||||
if (config->config_ctl_val)
|
||||
regmap_write(regmap, PLL_CONFIG_CTL(pll),
|
||||
config->config_ctl_val);
|
||||
|
||||
if (config->config_ctl_hi_val)
|
||||
regmap_write(regmap, PLL_CONFIG_CTL_U(pll),
|
||||
config->config_ctl_hi_val);
|
||||
|
||||
if (config->config_ctl_hi1_val)
|
||||
regmap_write(regmap, PLL_CONFIG_CTL_U1(pll),
|
||||
config->config_ctl_hi1_val);
|
||||
|
||||
if (config->user_ctl_val)
|
||||
regmap_write(regmap, PLL_USER_CTL(pll),
|
||||
config->user_ctl_val);
|
||||
|
||||
if (config->user_ctl_hi_val)
|
||||
regmap_write(regmap, PLL_USER_CTL_U(pll),
|
||||
config->user_ctl_hi_val);
|
||||
|
||||
if (config->user_ctl_hi1_val)
|
||||
regmap_write(regmap, PLL_USER_CTL_U1(pll),
|
||||
config->user_ctl_hi1_val);
|
||||
|
||||
if (config->test_ctl_val)
|
||||
regmap_write(regmap, PLL_TEST_CTL(pll),
|
||||
config->test_ctl_val);
|
||||
|
||||
if (config->test_ctl_hi_val)
|
||||
regmap_write(regmap, PLL_TEST_CTL_U(pll),
|
||||
config->test_ctl_hi_val);
|
||||
|
||||
if (config->test_ctl_hi1_val)
|
||||
regmap_write(regmap, PLL_TEST_CTL_U1(pll),
|
||||
config->test_ctl_hi1_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_ALPHA_VAL(pll), config->alpha);
|
||||
clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL(pll),
|
||||
config->config_ctl_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U(pll),
|
||||
config->config_ctl_hi_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U1(pll),
|
||||
config->config_ctl_hi1_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_USER_CTL(pll),
|
||||
config->user_ctl_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_USER_CTL_U(pll),
|
||||
config->user_ctl_hi_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_USER_CTL_U1(pll),
|
||||
config->user_ctl_hi1_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_TEST_CTL(pll),
|
||||
config->test_ctl_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U(pll),
|
||||
config->test_ctl_hi_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U1(pll),
|
||||
config->test_ctl_hi1_val);
|
||||
|
||||
regmap_update_bits(regmap, PLL_MODE(pll), PLL_UPDATE_BYPASS,
|
||||
PLL_UPDATE_BYPASS);
|
||||
|
@ -1490,14 +1482,9 @@ static int alpha_pll_trion_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
rrate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width);
|
||||
|
||||
/*
|
||||
* Due to a limited number of bits for fractional rate programming, the
|
||||
* rounded up rate could be marginally higher than the requested rate.
|
||||
*/
|
||||
if (rrate > (rate + PLL_RATE_MARGIN) || rrate < rate) {
|
||||
pr_err("Call set rate on the PLL with rounded rates!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = alpha_pll_check_rate_margin(hw, rrate, rate);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l);
|
||||
regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a);
|
||||
|
@ -1561,3 +1548,55 @@ const struct clk_ops clk_alpha_pll_postdiv_lucid_ops = {
|
|||
.set_rate = clk_alpha_pll_postdiv_fabia_set_rate,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_lucid_ops);
|
||||
|
||||
void clk_agera_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
|
||||
const struct alpha_pll_config *config)
|
||||
{
|
||||
clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), config->l);
|
||||
clk_alpha_pll_write_config(regmap, PLL_ALPHA_VAL(pll), config->alpha);
|
||||
clk_alpha_pll_write_config(regmap, PLL_USER_CTL(pll),
|
||||
config->user_ctl_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL(pll),
|
||||
config->config_ctl_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U(pll),
|
||||
config->config_ctl_hi_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_TEST_CTL(pll),
|
||||
config->test_ctl_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U(pll),
|
||||
config->test_ctl_hi_val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_agera_pll_configure);
|
||||
|
||||
static int clk_alpha_pll_agera_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long prate)
|
||||
{
|
||||
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
|
||||
u32 l, alpha_width = pll_alpha_width(pll);
|
||||
int ret;
|
||||
unsigned long rrate;
|
||||
u64 a;
|
||||
|
||||
rrate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width);
|
||||
ret = alpha_pll_check_rate_margin(hw, rrate, rate);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* change L_VAL without having to go through the power on sequence */
|
||||
regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l);
|
||||
regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a);
|
||||
|
||||
if (clk_hw_is_enabled(hw))
|
||||
return wait_for_pll_enable_lock(pll);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct clk_ops clk_alpha_pll_agera_ops = {
|
||||
.enable = clk_alpha_pll_enable,
|
||||
.disable = clk_alpha_pll_disable,
|
||||
.is_enabled = clk_alpha_pll_is_enabled,
|
||||
.recalc_rate = alpha_pll_fabia_recalc_rate,
|
||||
.round_rate = clk_alpha_pll_round_rate,
|
||||
.set_rate = clk_alpha_pll_agera_set_rate,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_alpha_pll_agera_ops);
|
||||
|
|
|
@ -15,6 +15,7 @@ enum {
|
|||
CLK_ALPHA_PLL_TYPE_FABIA,
|
||||
CLK_ALPHA_PLL_TYPE_TRION,
|
||||
CLK_ALPHA_PLL_TYPE_LUCID = CLK_ALPHA_PLL_TYPE_TRION,
|
||||
CLK_ALPHA_PLL_TYPE_AGERA,
|
||||
CLK_ALPHA_PLL_TYPE_MAX,
|
||||
};
|
||||
|
||||
|
@ -141,6 +142,7 @@ extern const struct clk_ops clk_alpha_pll_postdiv_trion_ops;
|
|||
extern const struct clk_ops clk_alpha_pll_lucid_ops;
|
||||
#define clk_alpha_pll_fixed_lucid_ops clk_alpha_pll_fixed_trion_ops
|
||||
extern const struct clk_ops clk_alpha_pll_postdiv_lucid_ops;
|
||||
extern const struct clk_ops clk_alpha_pll_agera_ops;
|
||||
|
||||
void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
|
||||
const struct alpha_pll_config *config);
|
||||
|
@ -148,6 +150,8 @@ void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
|
|||
const struct alpha_pll_config *config);
|
||||
void clk_trion_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
|
||||
const struct alpha_pll_config *config);
|
||||
void clk_agera_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
|
||||
const struct alpha_pll_config *config);
|
||||
#define clk_lucid_pll_configure(pll, regmap, config) \
|
||||
clk_trion_pll_configure(pll, regmap, config)
|
||||
|
||||
|
|
|
@ -349,6 +349,7 @@ DEFINE_CLK_RPMH_VRM(sdm845, rf_clk2, rf_clk2_ao, "rfclka2", 1);
|
|||
DEFINE_CLK_RPMH_VRM(sdm845, rf_clk3, rf_clk3_ao, "rfclka3", 1);
|
||||
DEFINE_CLK_RPMH_VRM(sm8150, rf_clk3, rf_clk3_ao, "rfclka3", 1);
|
||||
DEFINE_CLK_RPMH_BCM(sdm845, ipa, "IP0");
|
||||
DEFINE_CLK_RPMH_BCM(sdm845, ce, "CE0");
|
||||
|
||||
static struct clk_hw *sdm845_rpmh_clocks[] = {
|
||||
[RPMH_CXO_CLK] = &sdm845_bi_tcxo.hw,
|
||||
|
@ -364,6 +365,7 @@ static struct clk_hw *sdm845_rpmh_clocks[] = {
|
|||
[RPMH_RF_CLK3] = &sdm845_rf_clk3.hw,
|
||||
[RPMH_RF_CLK3_A] = &sdm845_rf_clk3_ao.hw,
|
||||
[RPMH_IPA_CLK] = &sdm845_ipa.hw,
|
||||
[RPMH_CE_CLK] = &sdm845_ce.hw,
|
||||
};
|
||||
|
||||
static const struct clk_rpmh_desc clk_rpmh_sdm845 = {
|
||||
|
@ -371,6 +373,25 @@ static const struct clk_rpmh_desc clk_rpmh_sdm845 = {
|
|||
.num_clks = ARRAY_SIZE(sdm845_rpmh_clocks),
|
||||
};
|
||||
|
||||
DEFINE_CLK_RPMH_VRM(sdx55, rf_clk1, rf_clk1_ao, "rfclkd1", 1);
|
||||
DEFINE_CLK_RPMH_VRM(sdx55, rf_clk2, rf_clk2_ao, "rfclkd2", 1);
|
||||
DEFINE_CLK_RPMH_BCM(sdx55, qpic_clk, "QP0");
|
||||
|
||||
static struct clk_hw *sdx55_rpmh_clocks[] = {
|
||||
[RPMH_CXO_CLK] = &sdm845_bi_tcxo.hw,
|
||||
[RPMH_CXO_CLK_A] = &sdm845_bi_tcxo_ao.hw,
|
||||
[RPMH_RF_CLK1] = &sdx55_rf_clk1.hw,
|
||||
[RPMH_RF_CLK1_A] = &sdx55_rf_clk1_ao.hw,
|
||||
[RPMH_RF_CLK2] = &sdx55_rf_clk2.hw,
|
||||
[RPMH_RF_CLK2_A] = &sdx55_rf_clk2_ao.hw,
|
||||
[RPMH_QPIC_CLK] = &sdx55_qpic_clk.hw,
|
||||
};
|
||||
|
||||
static const struct clk_rpmh_desc clk_rpmh_sdx55 = {
|
||||
.clks = sdx55_rpmh_clocks,
|
||||
.num_clks = ARRAY_SIZE(sdx55_rpmh_clocks),
|
||||
};
|
||||
|
||||
static struct clk_hw *sm8150_rpmh_clocks[] = {
|
||||
[RPMH_CXO_CLK] = &sdm845_bi_tcxo.hw,
|
||||
[RPMH_CXO_CLK_A] = &sdm845_bi_tcxo_ao.hw,
|
||||
|
@ -432,6 +453,39 @@ static const struct clk_rpmh_desc clk_rpmh_sm8250 = {
|
|||
.num_clks = ARRAY_SIZE(sm8250_rpmh_clocks),
|
||||
};
|
||||
|
||||
DEFINE_CLK_RPMH_VRM(sm8350, div_clk1, div_clk1_ao, "divclka1", 2);
|
||||
DEFINE_CLK_RPMH_VRM(sm8350, rf_clk4, rf_clk4_ao, "rfclka4", 1);
|
||||
DEFINE_CLK_RPMH_VRM(sm8350, rf_clk5, rf_clk5_ao, "rfclka5", 1);
|
||||
DEFINE_CLK_RPMH_BCM(sm8350, pka, "PKA0");
|
||||
DEFINE_CLK_RPMH_BCM(sm8350, hwkm, "HK0");
|
||||
|
||||
static struct clk_hw *sm8350_rpmh_clocks[] = {
|
||||
[RPMH_CXO_CLK] = &sdm845_bi_tcxo.hw,
|
||||
[RPMH_CXO_CLK_A] = &sdm845_bi_tcxo_ao.hw,
|
||||
[RPMH_DIV_CLK1] = &sm8350_div_clk1.hw,
|
||||
[RPMH_DIV_CLK1_A] = &sm8350_div_clk1_ao.hw,
|
||||
[RPMH_LN_BB_CLK1] = &sm8250_ln_bb_clk1.hw,
|
||||
[RPMH_LN_BB_CLK1_A] = &sm8250_ln_bb_clk1_ao.hw,
|
||||
[RPMH_LN_BB_CLK2] = &sdm845_ln_bb_clk2.hw,
|
||||
[RPMH_LN_BB_CLK2_A] = &sdm845_ln_bb_clk2_ao.hw,
|
||||
[RPMH_RF_CLK1] = &sdm845_rf_clk1.hw,
|
||||
[RPMH_RF_CLK1_A] = &sdm845_rf_clk1_ao.hw,
|
||||
[RPMH_RF_CLK3] = &sdm845_rf_clk3.hw,
|
||||
[RPMH_RF_CLK3_A] = &sdm845_rf_clk3_ao.hw,
|
||||
[RPMH_RF_CLK4] = &sm8350_rf_clk4.hw,
|
||||
[RPMH_RF_CLK4_A] = &sm8350_rf_clk4_ao.hw,
|
||||
[RPMH_RF_CLK5] = &sm8350_rf_clk5.hw,
|
||||
[RPMH_RF_CLK5_A] = &sm8350_rf_clk5_ao.hw,
|
||||
[RPMH_IPA_CLK] = &sdm845_ipa.hw,
|
||||
[RPMH_PKA_CLK] = &sm8350_pka.hw,
|
||||
[RPMH_HWKM_CLK] = &sm8350_hwkm.hw,
|
||||
};
|
||||
|
||||
static const struct clk_rpmh_desc clk_rpmh_sm8350 = {
|
||||
.clks = sm8350_rpmh_clocks,
|
||||
.num_clks = ARRAY_SIZE(sm8350_rpmh_clocks),
|
||||
};
|
||||
|
||||
static struct clk_hw *of_clk_rpmh_hw_get(struct of_phandle_args *clkspec,
|
||||
void *data)
|
||||
{
|
||||
|
@ -517,8 +571,10 @@ static int clk_rpmh_probe(struct platform_device *pdev)
|
|||
static const struct of_device_id clk_rpmh_match_table[] = {
|
||||
{ .compatible = "qcom,sc7180-rpmh-clk", .data = &clk_rpmh_sc7180},
|
||||
{ .compatible = "qcom,sdm845-rpmh-clk", .data = &clk_rpmh_sdm845},
|
||||
{ .compatible = "qcom,sdx55-rpmh-clk", .data = &clk_rpmh_sdx55},
|
||||
{ .compatible = "qcom,sm8150-rpmh-clk", .data = &clk_rpmh_sm8150},
|
||||
{ .compatible = "qcom,sm8250-rpmh-clk", .data = &clk_rpmh_sm8250},
|
||||
{ .compatible = "qcom,sm8350-rpmh-clk", .data = &clk_rpmh_sm8350},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, clk_rpmh_match_table);
|
||||
|
|
|
@ -963,6 +963,7 @@ static struct gdsc mdss_gdsc = {
|
|||
},
|
||||
.pwrsts = PWRSTS_OFF_ON,
|
||||
.flags = HW_CTRL,
|
||||
.supply = "mmcx",
|
||||
};
|
||||
|
||||
static struct clk_regmap *disp_cc_sm8250_clocks[] = {
|
||||
|
|
|
@ -642,7 +642,7 @@ static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = {
|
|||
.name = "gcc_sdcc1_ice_core_clk_src",
|
||||
.parent_data = gcc_parent_data_0,
|
||||
.num_parents = 4,
|
||||
.ops = &clk_rcg2_ops,
|
||||
.ops = &clk_rcg2_floor_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -651,6 +651,7 @@ static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
|
|||
F(9600000, P_BI_TCXO, 2, 0, 0),
|
||||
F(19200000, P_BI_TCXO, 1, 0, 0),
|
||||
F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0),
|
||||
F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0),
|
||||
F(100000000, P_GPLL0_OUT_EVEN, 3, 0, 0),
|
||||
F(202000000, P_GPLL7_OUT_MAIN, 4, 0, 0),
|
||||
{ }
|
||||
|
@ -666,7 +667,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = {
|
|||
.name = "gcc_sdcc2_apps_clk_src",
|
||||
.parent_data = gcc_parent_data_5,
|
||||
.num_parents = 5,
|
||||
.ops = &clk_rcg2_ops,
|
||||
.ops = &clk_rcg2_floor_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,320 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* LPASS Audio CC and Always ON CC Glitch Free Mux clock driver
|
||||
*
|
||||
* Copyright (c) 2020 Linaro Ltd.
|
||||
* Author: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/pm_clock.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <dt-bindings/clock/qcom,sm8250-lpass-audiocc.h>
|
||||
#include <dt-bindings/clock/qcom,sm8250-lpass-aoncc.h>
|
||||
|
||||
struct lpass_gfm {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
struct clk_gfm {
|
||||
unsigned int mux_reg;
|
||||
unsigned int mux_mask;
|
||||
struct clk_hw hw;
|
||||
struct lpass_gfm *priv;
|
||||
void __iomem *gfm_mux;
|
||||
};
|
||||
|
||||
#define GFM_MASK BIT(1)
|
||||
#define to_clk_gfm(_hw) container_of(_hw, struct clk_gfm, hw)
|
||||
|
||||
static u8 clk_gfm_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gfm *clk = to_clk_gfm(hw);
|
||||
|
||||
return readl(clk->gfm_mux) & GFM_MASK;
|
||||
}
|
||||
|
||||
static int clk_gfm_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct clk_gfm *clk = to_clk_gfm(hw);
|
||||
unsigned int val;
|
||||
|
||||
val = readl(clk->gfm_mux);
|
||||
|
||||
if (index)
|
||||
val |= GFM_MASK;
|
||||
else
|
||||
val &= ~GFM_MASK;
|
||||
|
||||
writel(val, clk->gfm_mux);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_gfm_ops = {
|
||||
.get_parent = clk_gfm_get_parent,
|
||||
.set_parent = clk_gfm_set_parent,
|
||||
.determine_rate = __clk_mux_determine_rate,
|
||||
};
|
||||
|
||||
static struct clk_gfm lpass_gfm_va_mclk = {
|
||||
.mux_reg = 0x20000,
|
||||
.mux_mask = BIT(0),
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "VA_MCLK",
|
||||
.ops = &clk_gfm_ops,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
|
||||
.num_parents = 2,
|
||||
.parent_data = (const struct clk_parent_data[]){
|
||||
{
|
||||
.index = 0,
|
||||
.fw_name = "LPASS_CLK_ID_TX_CORE_MCLK",
|
||||
}, {
|
||||
.index = 1,
|
||||
.fw_name = "LPASS_CLK_ID_VA_CORE_MCLK",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_gfm lpass_gfm_tx_npl = {
|
||||
.mux_reg = 0x20000,
|
||||
.mux_mask = BIT(0),
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "TX_NPL",
|
||||
.ops = &clk_gfm_ops,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
|
||||
.parent_data = (const struct clk_parent_data[]){
|
||||
{
|
||||
.index = 0,
|
||||
.fw_name = "LPASS_CLK_ID_TX_CORE_NPL_MCLK",
|
||||
}, {
|
||||
.index = 1,
|
||||
.fw_name = "LPASS_CLK_ID_VA_CORE_2X_MCLK",
|
||||
},
|
||||
},
|
||||
.num_parents = 2,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_gfm lpass_gfm_wsa_mclk = {
|
||||
.mux_reg = 0x220d8,
|
||||
.mux_mask = BIT(0),
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "WSA_MCLK",
|
||||
.ops = &clk_gfm_ops,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
|
||||
.parent_data = (const struct clk_parent_data[]){
|
||||
{
|
||||
.index = 0,
|
||||
.fw_name = "LPASS_CLK_ID_TX_CORE_MCLK",
|
||||
}, {
|
||||
.index = 1,
|
||||
.fw_name = "LPASS_CLK_ID_WSA_CORE_MCLK",
|
||||
},
|
||||
},
|
||||
.num_parents = 2,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_gfm lpass_gfm_wsa_npl = {
|
||||
.mux_reg = 0x220d8,
|
||||
.mux_mask = BIT(0),
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "WSA_NPL",
|
||||
.ops = &clk_gfm_ops,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
|
||||
.parent_data = (const struct clk_parent_data[]){
|
||||
{
|
||||
.index = 0,
|
||||
.fw_name = "LPASS_CLK_ID_TX_CORE_NPL_MCLK",
|
||||
}, {
|
||||
.index = 1,
|
||||
.fw_name = "LPASS_CLK_ID_WSA_CORE_NPL_MCLK",
|
||||
},
|
||||
},
|
||||
.num_parents = 2,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_gfm lpass_gfm_rx_mclk_mclk2 = {
|
||||
.mux_reg = 0x240d8,
|
||||
.mux_mask = BIT(0),
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "RX_MCLK_MCLK2",
|
||||
.ops = &clk_gfm_ops,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
|
||||
.parent_data = (const struct clk_parent_data[]){
|
||||
{
|
||||
.index = 0,
|
||||
.fw_name = "LPASS_CLK_ID_TX_CORE_MCLK",
|
||||
}, {
|
||||
.index = 1,
|
||||
.fw_name = "LPASS_CLK_ID_RX_CORE_MCLK",
|
||||
},
|
||||
},
|
||||
.num_parents = 2,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_gfm lpass_gfm_rx_npl = {
|
||||
.mux_reg = 0x240d8,
|
||||
.mux_mask = BIT(0),
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "RX_NPL",
|
||||
.ops = &clk_gfm_ops,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
|
||||
.parent_data = (const struct clk_parent_data[]){
|
||||
{
|
||||
.index = 0,
|
||||
.fw_name = "LPASS_CLK_ID_TX_CORE_NPL_MCLK",
|
||||
}, {
|
||||
.index = 1,
|
||||
.fw_name = "LPASS_CLK_ID_RX_CORE_NPL_MCLK",
|
||||
},
|
||||
},
|
||||
.num_parents = 2,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_gfm *aoncc_gfm_clks[] = {
|
||||
[LPASS_CDC_VA_MCLK] = &lpass_gfm_va_mclk,
|
||||
[LPASS_CDC_TX_NPL] = &lpass_gfm_tx_npl,
|
||||
};
|
||||
|
||||
static struct clk_hw_onecell_data aoncc_hw_onecell_data = {
|
||||
.hws = {
|
||||
[LPASS_CDC_VA_MCLK] = &lpass_gfm_va_mclk.hw,
|
||||
[LPASS_CDC_TX_NPL] = &lpass_gfm_tx_npl.hw,
|
||||
},
|
||||
.num = ARRAY_SIZE(aoncc_gfm_clks),
|
||||
};
|
||||
|
||||
static struct clk_gfm *audiocc_gfm_clks[] = {
|
||||
[LPASS_CDC_WSA_NPL] = &lpass_gfm_wsa_npl,
|
||||
[LPASS_CDC_WSA_MCLK] = &lpass_gfm_wsa_mclk,
|
||||
[LPASS_CDC_RX_NPL] = &lpass_gfm_rx_npl,
|
||||
[LPASS_CDC_RX_MCLK_MCLK2] = &lpass_gfm_rx_mclk_mclk2,
|
||||
};
|
||||
|
||||
static struct clk_hw_onecell_data audiocc_hw_onecell_data = {
|
||||
.hws = {
|
||||
[LPASS_CDC_WSA_NPL] = &lpass_gfm_wsa_npl.hw,
|
||||
[LPASS_CDC_WSA_MCLK] = &lpass_gfm_wsa_mclk.hw,
|
||||
[LPASS_CDC_RX_NPL] = &lpass_gfm_rx_npl.hw,
|
||||
[LPASS_CDC_RX_MCLK_MCLK2] = &lpass_gfm_rx_mclk_mclk2.hw,
|
||||
},
|
||||
.num = ARRAY_SIZE(audiocc_gfm_clks),
|
||||
};
|
||||
|
||||
struct lpass_gfm_data {
|
||||
struct clk_hw_onecell_data *onecell_data;
|
||||
struct clk_gfm **gfm_clks;
|
||||
};
|
||||
|
||||
static struct lpass_gfm_data audiocc_data = {
|
||||
.onecell_data = &audiocc_hw_onecell_data,
|
||||
.gfm_clks = audiocc_gfm_clks,
|
||||
};
|
||||
|
||||
static struct lpass_gfm_data aoncc_data = {
|
||||
.onecell_data = &aoncc_hw_onecell_data,
|
||||
.gfm_clks = aoncc_gfm_clks,
|
||||
};
|
||||
|
||||
static int lpass_gfm_clk_driver_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct lpass_gfm_data *data;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct clk_gfm *gfm;
|
||||
struct lpass_gfm *cc;
|
||||
int err, i;
|
||||
|
||||
data = of_device_get_match_data(dev);
|
||||
if (!data)
|
||||
return -EINVAL;
|
||||
|
||||
cc = devm_kzalloc(dev, sizeof(*cc), GFP_KERNEL);
|
||||
if (!cc)
|
||||
return -ENOMEM;
|
||||
|
||||
cc->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(cc->base))
|
||||
return PTR_ERR(cc->base);
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
err = pm_clk_create(dev);
|
||||
if (err)
|
||||
goto pm_clk_err;
|
||||
|
||||
err = of_pm_clk_add_clks(dev);
|
||||
if (err < 0) {
|
||||
dev_dbg(dev, "Failed to get lpass core voting clocks\n");
|
||||
goto clk_reg_err;
|
||||
}
|
||||
|
||||
for (i = 0; i < data->onecell_data->num; i++) {
|
||||
if (!data->gfm_clks[i])
|
||||
continue;
|
||||
|
||||
gfm = data->gfm_clks[i];
|
||||
gfm->priv = cc;
|
||||
gfm->gfm_mux = cc->base;
|
||||
gfm->gfm_mux = gfm->gfm_mux + data->gfm_clks[i]->mux_reg;
|
||||
|
||||
err = devm_clk_hw_register(dev, &data->gfm_clks[i]->hw);
|
||||
if (err)
|
||||
goto clk_reg_err;
|
||||
|
||||
}
|
||||
|
||||
err = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
|
||||
data->onecell_data);
|
||||
if (err)
|
||||
goto clk_reg_err;
|
||||
|
||||
return 0;
|
||||
|
||||
clk_reg_err:
|
||||
pm_clk_destroy(dev);
|
||||
pm_clk_err:
|
||||
pm_runtime_disable(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct of_device_id lpass_gfm_clk_match_table[] = {
|
||||
{
|
||||
.compatible = "qcom,sm8250-lpass-aoncc",
|
||||
.data = &aoncc_data,
|
||||
},
|
||||
{
|
||||
.compatible = "qcom,sm8250-lpass-audiocc",
|
||||
.data = &audiocc_data,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lpass_gfm_clk_match_table);
|
||||
|
||||
static const struct dev_pm_ops lpass_gfm_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver lpass_gfm_clk_driver = {
|
||||
.probe = lpass_gfm_clk_driver_probe,
|
||||
.driver = {
|
||||
.name = "lpass-gfm-clk",
|
||||
.of_match_table = lpass_gfm_clk_match_table,
|
||||
.pm = &lpass_gfm_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(lpass_gfm_clk_driver);
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -356,12 +356,52 @@ static const struct qcom_cc_desc lpass_audio_hm_sc7180_desc = {
|
|||
.num_gdscs = ARRAY_SIZE(lpass_audio_hm_sc7180_gdscs),
|
||||
};
|
||||
|
||||
static void lpass_pm_runtime_disable(void *data)
|
||||
{
|
||||
pm_runtime_disable(data);
|
||||
}
|
||||
|
||||
static void lpass_pm_clk_destroy(void *data)
|
||||
{
|
||||
pm_clk_destroy(data);
|
||||
}
|
||||
|
||||
static int lpass_create_pm_clks(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
ret = devm_add_action_or_reset(&pdev->dev, lpass_pm_runtime_disable, &pdev->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pm_clk_create(&pdev->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = devm_add_action_or_reset(&pdev->dev, lpass_pm_clk_destroy, &pdev->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pm_clk_add(&pdev->dev, "iface");
|
||||
if (ret < 0)
|
||||
dev_err(&pdev->dev, "failed to acquire iface clock\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lpass_core_cc_sc7180_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct qcom_cc_desc *desc;
|
||||
struct regmap *regmap;
|
||||
int ret;
|
||||
|
||||
ret = lpass_create_pm_clks(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
lpass_core_cc_sc7180_regmap_config.name = "lpass_audio_cc";
|
||||
desc = &lpass_audio_hm_sc7180_desc;
|
||||
ret = qcom_cc_probe_by_index(pdev, 1, desc);
|
||||
|
@ -386,12 +426,22 @@ static int lpass_core_cc_sc7180_probe(struct platform_device *pdev)
|
|||
clk_fabia_pll_configure(&lpass_lpaaudio_dig_pll, regmap,
|
||||
&lpass_lpaaudio_dig_pll_config);
|
||||
|
||||
return qcom_cc_really_probe(pdev, &lpass_core_cc_sc7180_desc, regmap);
|
||||
ret = qcom_cc_really_probe(pdev, &lpass_core_cc_sc7180_desc, regmap);
|
||||
|
||||
pm_runtime_mark_last_busy(&pdev->dev);
|
||||
pm_runtime_put_autosuspend(&pdev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lpass_hm_core_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct qcom_cc_desc *desc;
|
||||
int ret;
|
||||
|
||||
ret = lpass_create_pm_clks(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
lpass_core_cc_sc7180_regmap_config.name = "lpass_hm_core";
|
||||
desc = &lpass_core_hm_sc7180_desc;
|
||||
|
@ -399,61 +449,28 @@ static int lpass_hm_core_probe(struct platform_device *pdev)
|
|||
return qcom_cc_probe_by_index(pdev, 0, desc);
|
||||
}
|
||||
|
||||
static const struct of_device_id lpass_core_cc_sc7180_match_table[] = {
|
||||
static const struct of_device_id lpass_hm_sc7180_match_table[] = {
|
||||
{
|
||||
.compatible = "qcom,sc7180-lpasshm",
|
||||
.data = lpass_hm_core_probe,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lpass_hm_sc7180_match_table);
|
||||
|
||||
static const struct of_device_id lpass_core_cc_sc7180_match_table[] = {
|
||||
{
|
||||
.compatible = "qcom,sc7180-lpasscorecc",
|
||||
.data = lpass_core_cc_sc7180_probe,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lpass_core_cc_sc7180_match_table);
|
||||
|
||||
static int lpass_core_sc7180_probe(struct platform_device *pdev)
|
||||
{
|
||||
int (*clk_probe)(struct platform_device *p);
|
||||
int ret;
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
ret = pm_clk_create(&pdev->dev);
|
||||
if (ret)
|
||||
goto disable_pm_runtime;
|
||||
|
||||
ret = pm_clk_add(&pdev->dev, "iface");
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to acquire iface clock\n");
|
||||
goto destroy_pm_clk;
|
||||
}
|
||||
|
||||
ret = -EINVAL;
|
||||
clk_probe = of_device_get_match_data(&pdev->dev);
|
||||
if (!clk_probe)
|
||||
goto destroy_pm_clk;
|
||||
|
||||
ret = clk_probe(pdev);
|
||||
if (ret)
|
||||
goto destroy_pm_clk;
|
||||
|
||||
return 0;
|
||||
|
||||
destroy_pm_clk:
|
||||
pm_clk_destroy(&pdev->dev);
|
||||
|
||||
disable_pm_runtime:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops lpass_core_cc_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver lpass_core_cc_sc7180_driver = {
|
||||
.probe = lpass_core_sc7180_probe,
|
||||
.probe = lpass_core_cc_sc7180_probe,
|
||||
.driver = {
|
||||
.name = "lpass_core_cc-sc7180",
|
||||
.of_match_table = lpass_core_cc_sc7180_match_table,
|
||||
|
@ -461,17 +478,43 @@ static struct platform_driver lpass_core_cc_sc7180_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
static int __init lpass_core_cc_sc7180_init(void)
|
||||
{
|
||||
return platform_driver_register(&lpass_core_cc_sc7180_driver);
|
||||
}
|
||||
subsys_initcall(lpass_core_cc_sc7180_init);
|
||||
static const struct dev_pm_ops lpass_hm_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL)
|
||||
};
|
||||
|
||||
static void __exit lpass_core_cc_sc7180_exit(void)
|
||||
static struct platform_driver lpass_hm_sc7180_driver = {
|
||||
.probe = lpass_hm_core_probe,
|
||||
.driver = {
|
||||
.name = "lpass_hm-sc7180",
|
||||
.of_match_table = lpass_hm_sc7180_match_table,
|
||||
.pm = &lpass_hm_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init lpass_sc7180_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&lpass_core_cc_sc7180_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = platform_driver_register(&lpass_hm_sc7180_driver);
|
||||
if (ret) {
|
||||
platform_driver_unregister(&lpass_core_cc_sc7180_driver);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
subsys_initcall(lpass_sc7180_init);
|
||||
|
||||
static void __exit lpass_sc7180_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&lpass_hm_sc7180_driver);
|
||||
platform_driver_unregister(&lpass_core_cc_sc7180_driver);
|
||||
}
|
||||
module_exit(lpass_core_cc_sc7180_exit);
|
||||
module_exit(lpass_sc7180_exit);
|
||||
|
||||
MODULE_DESCRIPTION("QTI LPASS_CORE_CC SC7180 Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -121,7 +121,7 @@ sh73a0_cpg_register_clock(struct device_node *np, struct sh73a0_cpg *cpg,
|
|||
(phy_no ? CPG_DSI1PHYCR : CPG_DSI0PHYCR);
|
||||
|
||||
parent_name = phy_no ? "dsi1pck" : "dsi0pck";
|
||||
mult = __raw_readl(dsi_reg);
|
||||
mult = readl(dsi_reg);
|
||||
if (!(mult & 0x8000))
|
||||
mult = 1;
|
||||
else
|
||||
|
|
|
@ -41,6 +41,7 @@ enum clk_ids {
|
|||
CLK_S2,
|
||||
CLK_S3,
|
||||
CLK_SDSRC,
|
||||
CLK_RPCSRC,
|
||||
CLK_RINT,
|
||||
|
||||
/* Module Clocks */
|
||||
|
@ -67,6 +68,12 @@ static const struct cpg_core_clk r8a774a1_core_clks[] __initconst = {
|
|||
DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1),
|
||||
DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1),
|
||||
DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1),
|
||||
DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1),
|
||||
|
||||
DEF_BASE("rpc", R8A774A1_CLK_RPC, CLK_TYPE_GEN3_RPC,
|
||||
CLK_RPCSRC),
|
||||
DEF_BASE("rpcd2", R8A774A1_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2,
|
||||
R8A774A1_CLK_RPC),
|
||||
|
||||
DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32),
|
||||
|
||||
|
@ -200,6 +207,7 @@ static const struct mssr_mod_clk r8a774a1_mod_clks[] __initconst = {
|
|||
DEF_MOD("can-fd", 914, R8A774A1_CLK_S3D2),
|
||||
DEF_MOD("can-if1", 915, R8A774A1_CLK_S3D4),
|
||||
DEF_MOD("can-if0", 916, R8A774A1_CLK_S3D4),
|
||||
DEF_MOD("rpc-if", 917, R8A774A1_CLK_RPCD2),
|
||||
DEF_MOD("i2c6", 918, R8A774A1_CLK_S0D6),
|
||||
DEF_MOD("i2c5", 919, R8A774A1_CLK_S0D6),
|
||||
DEF_MOD("i2c-dvfs", 926, R8A774A1_CLK_CP),
|
||||
|
|
|
@ -40,6 +40,7 @@ enum clk_ids {
|
|||
CLK_S2,
|
||||
CLK_S3,
|
||||
CLK_SDSRC,
|
||||
CLK_RPCSRC,
|
||||
CLK_RINT,
|
||||
|
||||
/* Module Clocks */
|
||||
|
@ -65,6 +66,12 @@ static const struct cpg_core_clk r8a774b1_core_clks[] __initconst = {
|
|||
DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1),
|
||||
DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1),
|
||||
DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1),
|
||||
DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1),
|
||||
|
||||
DEF_BASE("rpc", R8A774B1_CLK_RPC, CLK_TYPE_GEN3_RPC,
|
||||
CLK_RPCSRC),
|
||||
DEF_BASE("rpcd2", R8A774B1_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2,
|
||||
R8A774B1_CLK_RPC),
|
||||
|
||||
DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32),
|
||||
|
||||
|
@ -196,6 +203,7 @@ static const struct mssr_mod_clk r8a774b1_mod_clks[] __initconst = {
|
|||
DEF_MOD("can-fd", 914, R8A774B1_CLK_S3D2),
|
||||
DEF_MOD("can-if1", 915, R8A774B1_CLK_S3D4),
|
||||
DEF_MOD("can-if0", 916, R8A774B1_CLK_S3D4),
|
||||
DEF_MOD("rpc-if", 917, R8A774B1_CLK_RPCD2),
|
||||
DEF_MOD("i2c6", 918, R8A774B1_CLK_S0D6),
|
||||
DEF_MOD("i2c5", 919, R8A774B1_CLK_S0D6),
|
||||
DEF_MOD("i2c-dvfs", 926, R8A774B1_CLK_CP),
|
||||
|
|
|
@ -44,6 +44,7 @@ enum clk_ids {
|
|||
CLK_S2,
|
||||
CLK_S3,
|
||||
CLK_SDSRC,
|
||||
CLK_RPCSRC,
|
||||
CLK_RINT,
|
||||
CLK_OCO,
|
||||
|
||||
|
@ -74,6 +75,13 @@ static const struct cpg_core_clk r8a774c0_core_clks[] __initconst = {
|
|||
DEF_FIXED(".s3", CLK_S3, CLK_PLL1, 6, 1),
|
||||
DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1, 2, 1),
|
||||
|
||||
DEF_FIXED_RPCSRC_E3(".rpcsrc", CLK_RPCSRC, CLK_PLL0, CLK_PLL1),
|
||||
|
||||
DEF_BASE("rpc", R8A774C0_CLK_RPC, CLK_TYPE_GEN3_RPC,
|
||||
CLK_RPCSRC),
|
||||
DEF_BASE("rpcd2", R8A774C0_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2,
|
||||
R8A774C0_CLK_RPC),
|
||||
|
||||
DEF_DIV6_RO(".r", CLK_RINT, CLK_EXTAL, CPG_RCKCR, 32),
|
||||
|
||||
DEF_RATE(".oco", CLK_OCO, 8 * 1000 * 1000),
|
||||
|
@ -199,6 +207,7 @@ static const struct mssr_mod_clk r8a774c0_mod_clks[] __initconst = {
|
|||
DEF_MOD("can-fd", 914, R8A774C0_CLK_S3D2),
|
||||
DEF_MOD("can-if1", 915, R8A774C0_CLK_S3D4),
|
||||
DEF_MOD("can-if0", 916, R8A774C0_CLK_S3D4),
|
||||
DEF_MOD("rpc-if", 917, R8A774C0_CLK_RPCD2),
|
||||
DEF_MOD("i2c6", 918, R8A774C0_CLK_S3D2),
|
||||
DEF_MOD("i2c5", 919, R8A774C0_CLK_S3D2),
|
||||
DEF_MOD("i2c-dvfs", 926, R8A774C0_CLK_CP),
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include <dt-bindings/clock/r8a779a0-cpg-mssr.h>
|
||||
|
||||
#include "renesas-cpg-mssr.h"
|
||||
#include "rcar-gen3-cpg.h"
|
||||
|
||||
enum rcar_r8a779a0_clk_types {
|
||||
CLK_TYPE_R8A779A0_MAIN = CLK_TYPE_CUSTOM,
|
||||
|
@ -84,6 +83,14 @@ enum clk_ids {
|
|||
DEF_BASE(_name, _id, CLK_TYPE_R8A779A0_PLL2X_3X, CLK_MAIN, \
|
||||
.offset = _offset)
|
||||
|
||||
#define DEF_MDSEL(_name, _id, _md, _parent0, _div0, _parent1, _div1) \
|
||||
DEF_BASE(_name, _id, CLK_TYPE_R8A779A0_MDSEL, \
|
||||
(_parent0) << 16 | (_parent1), \
|
||||
.div = (_div0) << 16 | (_div1), .offset = _md)
|
||||
|
||||
#define DEF_OSC(_name, _id, _parent, _div) \
|
||||
DEF_BASE(_name, _id, CLK_TYPE_R8A779A0_OSC, _parent, .div = _div)
|
||||
|
||||
static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = {
|
||||
/* External Clock Inputs */
|
||||
DEF_INPUT("extal", CLK_EXTAL),
|
||||
|
@ -136,15 +143,51 @@ static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = {
|
|||
DEF_DIV6P1("canfd", R8A779A0_CLK_CANFD, CLK_PLL5_DIV4, 0x878),
|
||||
DEF_DIV6P1("csi0", R8A779A0_CLK_CSI0, CLK_PLL5_DIV4, 0x880),
|
||||
|
||||
DEF_GEN3_OSC("osc", R8A779A0_CLK_OSC, CLK_EXTAL, 8),
|
||||
DEF_GEN3_MDSEL("r", R8A779A0_CLK_R, 29, CLK_EXTALR, 1, CLK_OCO, 1),
|
||||
DEF_OSC("osc", R8A779A0_CLK_OSC, CLK_EXTAL, 8),
|
||||
DEF_MDSEL("r", R8A779A0_CLK_R, 29, CLK_EXTALR, 1, CLK_OCO, 1),
|
||||
};
|
||||
|
||||
static const struct mssr_mod_clk r8a779a0_mod_clks[] __initconst = {
|
||||
DEF_MOD("csi40", 331, R8A779A0_CLK_CSI0),
|
||||
DEF_MOD("csi41", 400, R8A779A0_CLK_CSI0),
|
||||
DEF_MOD("csi42", 401, R8A779A0_CLK_CSI0),
|
||||
DEF_MOD("csi43", 402, R8A779A0_CLK_CSI0),
|
||||
DEF_MOD("scif0", 702, R8A779A0_CLK_S1D8),
|
||||
DEF_MOD("scif1", 703, R8A779A0_CLK_S1D8),
|
||||
DEF_MOD("scif3", 704, R8A779A0_CLK_S1D8),
|
||||
DEF_MOD("scif4", 705, R8A779A0_CLK_S1D8),
|
||||
DEF_MOD("vin00", 730, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin01", 731, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin02", 800, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin03", 801, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin04", 802, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin05", 803, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin06", 804, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin07", 805, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin10", 806, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin11", 807, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin12", 808, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin13", 809, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin14", 810, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin15", 811, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin16", 812, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin17", 813, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin20", 814, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin21", 815, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin22", 816, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin23", 817, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin24", 818, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin25", 819, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin26", 820, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin27", 821, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin30", 822, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin31", 823, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin32", 824, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin33", 825, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin34", 826, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin35", 827, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin36", 828, R8A779A0_CLK_S1D1),
|
||||
DEF_MOD("vin37", 829, R8A779A0_CLK_S1D1),
|
||||
};
|
||||
|
||||
static spinlock_t cpg_lock;
|
||||
|
@ -153,7 +196,7 @@ static const struct rcar_r8a779a0_cpg_pll_config *cpg_pll_config __initdata;
|
|||
static unsigned int cpg_clk_extalr __initdata;
|
||||
static u32 cpg_mode __initdata;
|
||||
|
||||
struct clk * __init rcar_r8a779a0_cpg_clk_register(struct device *dev,
|
||||
static struct clk * __init rcar_r8a779a0_cpg_clk_register(struct device *dev,
|
||||
const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
|
||||
struct clk **clks, void __iomem *base,
|
||||
struct raw_notifier_head *notifiers)
|
||||
|
|
|
@ -224,10 +224,9 @@ static struct clk * __init cpg_z_clk_register(const char *name,
|
|||
#define CPG_SD_STP_MASK (CPG_SD_STP_HCK | CPG_SD_STP_CK)
|
||||
#define CPG_SD_FC_MASK (0x7 << 2 | 0x3 << 0)
|
||||
|
||||
#define CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) \
|
||||
#define CPG_SD_DIV_TABLE_DATA(stp_hck, sd_srcfc, sd_fc, sd_div) \
|
||||
{ \
|
||||
.val = ((stp_hck) ? CPG_SD_STP_HCK : 0) | \
|
||||
((stp_ck) ? CPG_SD_STP_CK : 0) | \
|
||||
((sd_srcfc) << 2) | \
|
||||
((sd_fc) << 0), \
|
||||
.div = (sd_div), \
|
||||
|
@ -247,36 +246,36 @@ struct sd_clock {
|
|||
};
|
||||
|
||||
/* SDn divider
|
||||
* sd_srcfc sd_fc div
|
||||
* stp_hck stp_ck (div) (div) = sd_srcfc x sd_fc
|
||||
*-------------------------------------------------------------------
|
||||
* 0 0 0 (1) 1 (4) 4 : SDR104 / HS200 / HS400 (8 TAP)
|
||||
* 0 0 1 (2) 1 (4) 8 : SDR50
|
||||
* 1 0 2 (4) 1 (4) 16 : HS / SDR25
|
||||
* 1 0 3 (8) 1 (4) 32 : NS / SDR12
|
||||
* 1 0 4 (16) 1 (4) 64
|
||||
* 0 0 0 (1) 0 (2) 2
|
||||
* 0 0 1 (2) 0 (2) 4 : SDR104 / HS200 / HS400 (4 TAP)
|
||||
* 1 0 2 (4) 0 (2) 8
|
||||
* 1 0 3 (8) 0 (2) 16
|
||||
* 1 0 4 (16) 0 (2) 32
|
||||
* sd_srcfc sd_fc div
|
||||
* stp_hck (div) (div) = sd_srcfc x sd_fc
|
||||
*---------------------------------------------------------
|
||||
* 0 0 (1) 1 (4) 4 : SDR104 / HS200 / HS400 (8 TAP)
|
||||
* 0 1 (2) 1 (4) 8 : SDR50
|
||||
* 1 2 (4) 1 (4) 16 : HS / SDR25
|
||||
* 1 3 (8) 1 (4) 32 : NS / SDR12
|
||||
* 1 4 (16) 1 (4) 64
|
||||
* 0 0 (1) 0 (2) 2
|
||||
* 0 1 (2) 0 (2) 4 : SDR104 / HS200 / HS400 (4 TAP)
|
||||
* 1 2 (4) 0 (2) 8
|
||||
* 1 3 (8) 0 (2) 16
|
||||
* 1 4 (16) 0 (2) 32
|
||||
*
|
||||
* NOTE: There is a quirk option to ignore the first row of the dividers
|
||||
* table when searching for suitable settings. This is because HS400 on
|
||||
* early ES versions of H3 and M3-W requires a specific setting to work.
|
||||
*/
|
||||
static const struct sd_div_table cpg_sd_div_table[] = {
|
||||
/* CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) */
|
||||
CPG_SD_DIV_TABLE_DATA(0, 0, 0, 1, 4),
|
||||
CPG_SD_DIV_TABLE_DATA(0, 0, 1, 1, 8),
|
||||
CPG_SD_DIV_TABLE_DATA(1, 0, 2, 1, 16),
|
||||
CPG_SD_DIV_TABLE_DATA(1, 0, 3, 1, 32),
|
||||
CPG_SD_DIV_TABLE_DATA(1, 0, 4, 1, 64),
|
||||
CPG_SD_DIV_TABLE_DATA(0, 0, 0, 0, 2),
|
||||
CPG_SD_DIV_TABLE_DATA(0, 0, 1, 0, 4),
|
||||
CPG_SD_DIV_TABLE_DATA(1, 0, 2, 0, 8),
|
||||
CPG_SD_DIV_TABLE_DATA(1, 0, 3, 0, 16),
|
||||
CPG_SD_DIV_TABLE_DATA(1, 0, 4, 0, 32),
|
||||
/* CPG_SD_DIV_TABLE_DATA(stp_hck, sd_srcfc, sd_fc, sd_div) */
|
||||
CPG_SD_DIV_TABLE_DATA(0, 0, 1, 4),
|
||||
CPG_SD_DIV_TABLE_DATA(0, 1, 1, 8),
|
||||
CPG_SD_DIV_TABLE_DATA(1, 2, 1, 16),
|
||||
CPG_SD_DIV_TABLE_DATA(1, 3, 1, 32),
|
||||
CPG_SD_DIV_TABLE_DATA(1, 4, 1, 64),
|
||||
CPG_SD_DIV_TABLE_DATA(0, 0, 0, 2),
|
||||
CPG_SD_DIV_TABLE_DATA(0, 1, 0, 4),
|
||||
CPG_SD_DIV_TABLE_DATA(1, 2, 0, 8),
|
||||
CPG_SD_DIV_TABLE_DATA(1, 3, 0, 16),
|
||||
CPG_SD_DIV_TABLE_DATA(1, 4, 0, 32),
|
||||
};
|
||||
|
||||
#define to_sd_clock(_hw) container_of(_hw, struct sd_clock, hw)
|
||||
|
@ -696,6 +695,34 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
|
|||
cpg_rpcsrc_div_table,
|
||||
&cpg_lock);
|
||||
|
||||
case CLK_TYPE_GEN3_E3_RPCSRC:
|
||||
/*
|
||||
* Register RPCSRC as fixed factor clock based on the
|
||||
* MD[4:1] pins and CPG_RPCCKCR[4:3] register value for
|
||||
* which has been set prior to booting the kernel.
|
||||
*/
|
||||
value = (readl(base + CPG_RPCCKCR) & GENMASK(4, 3)) >> 3;
|
||||
|
||||
switch (value) {
|
||||
case 0:
|
||||
div = 5;
|
||||
break;
|
||||
case 1:
|
||||
div = 3;
|
||||
break;
|
||||
case 2:
|
||||
parent = clks[core->parent >> 16];
|
||||
if (IS_ERR(parent))
|
||||
return ERR_CAST(parent);
|
||||
div = core->div;
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
div = 2;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case CLK_TYPE_GEN3_RPC:
|
||||
return cpg_rpc_clk_register(core->name, base,
|
||||
__clk_get_name(parent), notifiers);
|
||||
|
|
|
@ -24,6 +24,7 @@ enum rcar_gen3_clk_types {
|
|||
CLK_TYPE_GEN3_OSC, /* OSC EXTAL predivider and fixed divider */
|
||||
CLK_TYPE_GEN3_RCKSEL, /* Select parent/divider using RCKCR.CKSEL */
|
||||
CLK_TYPE_GEN3_RPCSRC,
|
||||
CLK_TYPE_GEN3_E3_RPCSRC,
|
||||
CLK_TYPE_GEN3_RPC,
|
||||
CLK_TYPE_GEN3_RPCD2,
|
||||
|
||||
|
@ -54,6 +55,10 @@ enum rcar_gen3_clk_types {
|
|||
#define DEF_GEN3_Z(_name, _id, _type, _parent, _div, _offset) \
|
||||
DEF_BASE(_name, _id, _type, _parent, .div = _div, .offset = _offset)
|
||||
|
||||
#define DEF_FIXED_RPCSRC_E3(_name, _id, _parent0, _parent1) \
|
||||
DEF_BASE(_name, _id, CLK_TYPE_GEN3_E3_RPCSRC, \
|
||||
(_parent0) << 16 | (_parent1), .div = 8)
|
||||
|
||||
struct rcar_gen3_cpg_pll_config {
|
||||
u8 extal_div;
|
||||
u8 pll1_mult;
|
||||
|
|
|
@ -160,7 +160,7 @@ static int rcar_usb2_clock_sel_probe(struct platform_device *pdev)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
priv->rsts = devm_reset_control_array_get(dev, true, false);
|
||||
priv->rsts = devm_reset_control_array_get_shared(dev);
|
||||
if (IS_ERR(priv->rsts))
|
||||
return PTR_ERR(priv->rsts);
|
||||
|
||||
|
|
|
@ -119,7 +119,8 @@ static const u16 srstclr_for_v3u[] = {
|
|||
};
|
||||
|
||||
/**
|
||||
* Clock Pulse Generator / Module Standby and Software Reset Private Data
|
||||
* struct cpg_mssr_priv - Clock Pulse Generator / Module Standby
|
||||
* and Software Reset Private Data
|
||||
*
|
||||
* @rcdev: Optional reset controller entity
|
||||
* @dev: CPG/MSSR device
|
||||
|
|
|
@ -11,67 +11,77 @@ config COMMON_CLK_ROCKCHIP
|
|||
if COMMON_CLK_ROCKCHIP
|
||||
config CLK_PX30
|
||||
bool "Rockchip PX30 clock controller support"
|
||||
depends on (ARM64 || COMPILE_TEST)
|
||||
default y
|
||||
help
|
||||
Build the driver for PX30 Clock Driver.
|
||||
|
||||
config CLK_RV110X
|
||||
bool "Rockchip RV110x clock controller support"
|
||||
depends on (ARM || COMPILE_TEST)
|
||||
default y
|
||||
help
|
||||
Build the driver for RV110x Clock Driver.
|
||||
|
||||
config CLK_RK3036
|
||||
bool "Rockchip RK3036 clock controller support"
|
||||
depends on (ARM || COMPILE_TEST)
|
||||
default y
|
||||
help
|
||||
Build the driver for RK3036 Clock Driver.
|
||||
|
||||
config CLK_RK312X
|
||||
bool "Rockchip RK312x clock controller support"
|
||||
depends on (ARM || COMPILE_TEST)
|
||||
default y
|
||||
help
|
||||
Build the driver for RK312x Clock Driver.
|
||||
|
||||
config CLK_RK3188
|
||||
bool "Rockchip RK3188 clock controller support"
|
||||
depends on (ARM || COMPILE_TEST)
|
||||
default y
|
||||
help
|
||||
Build the driver for RK3188 Clock Driver.
|
||||
|
||||
config CLK_RK322X
|
||||
bool "Rockchip RK322x clock controller support"
|
||||
depends on (ARM || COMPILE_TEST)
|
||||
default y
|
||||
help
|
||||
Build the driver for RK322x Clock Driver.
|
||||
|
||||
config CLK_RK3288
|
||||
bool "Rockchip RK3288 clock controller support"
|
||||
depends on ARM
|
||||
depends on (ARM || COMPILE_TEST)
|
||||
default y
|
||||
help
|
||||
Build the driver for RK3288 Clock Driver.
|
||||
|
||||
config CLK_RK3308
|
||||
bool "Rockchip RK3308 clock controller support"
|
||||
depends on (ARM64 || COMPILE_TEST)
|
||||
default y
|
||||
help
|
||||
Build the driver for RK3308 Clock Driver.
|
||||
|
||||
config CLK_RK3328
|
||||
bool "Rockchip RK3328 clock controller support"
|
||||
depends on (ARM64 || COMPILE_TEST)
|
||||
default y
|
||||
help
|
||||
Build the driver for RK3328 Clock Driver.
|
||||
|
||||
config CLK_RK3368
|
||||
bool "Rockchip RK3368 clock controller support"
|
||||
depends on (ARM64 || COMPILE_TEST)
|
||||
default y
|
||||
help
|
||||
Build the driver for RK3368 Clock Driver.
|
||||
|
||||
config CLK_RK3399
|
||||
tristate "Rockchip RK3399 clock controller support"
|
||||
depends on (ARM64 || COMPILE_TEST)
|
||||
default y
|
||||
help
|
||||
Build the driver for RK3399 Clock Driver.
|
||||
|
|
|
@ -255,19 +255,19 @@ static struct rockchip_clk_branch common_spdif_fracmux __initdata =
|
|||
RK2928_CLKSEL_CON(5), 8, 2, MFLAGS);
|
||||
|
||||
static struct rockchip_clk_branch common_uart0_fracmux __initdata =
|
||||
MUX(SCLK_UART0, "sclk_uart0", mux_sclk_uart0_p, 0,
|
||||
MUX(SCLK_UART0, "sclk_uart0", mux_sclk_uart0_p, CLK_SET_RATE_PARENT,
|
||||
RK2928_CLKSEL_CON(13), 8, 2, MFLAGS);
|
||||
|
||||
static struct rockchip_clk_branch common_uart1_fracmux __initdata =
|
||||
MUX(SCLK_UART1, "sclk_uart1", mux_sclk_uart1_p, 0,
|
||||
MUX(SCLK_UART1, "sclk_uart1", mux_sclk_uart1_p, CLK_SET_RATE_PARENT,
|
||||
RK2928_CLKSEL_CON(14), 8, 2, MFLAGS);
|
||||
|
||||
static struct rockchip_clk_branch common_uart2_fracmux __initdata =
|
||||
MUX(SCLK_UART2, "sclk_uart2", mux_sclk_uart2_p, 0,
|
||||
MUX(SCLK_UART2, "sclk_uart2", mux_sclk_uart2_p, CLK_SET_RATE_PARENT,
|
||||
RK2928_CLKSEL_CON(15), 8, 2, MFLAGS);
|
||||
|
||||
static struct rockchip_clk_branch common_uart3_fracmux __initdata =
|
||||
MUX(SCLK_UART3, "sclk_uart3", mux_sclk_uart3_p, 0,
|
||||
MUX(SCLK_UART3, "sclk_uart3", mux_sclk_uart3_p, CLK_SET_RATE_PARENT,
|
||||
RK2928_CLKSEL_CON(16), 8, 2, MFLAGS);
|
||||
|
||||
static struct rockchip_clk_branch common_clk_branches[] __initdata = {
|
||||
|
@ -408,28 +408,28 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
|
|||
COMPOSITE_NOMUX(0, "uart0_pre", "uart_src", 0,
|
||||
RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
|
||||
RK2928_CLKGATE_CON(1), 8, GFLAGS),
|
||||
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_pre", 0,
|
||||
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_pre", CLK_SET_RATE_PARENT,
|
||||
RK2928_CLKSEL_CON(17), 0,
|
||||
RK2928_CLKGATE_CON(1), 9, GFLAGS,
|
||||
&common_uart0_fracmux),
|
||||
COMPOSITE_NOMUX(0, "uart1_pre", "uart_src", 0,
|
||||
RK2928_CLKSEL_CON(14), 0, 7, DFLAGS,
|
||||
RK2928_CLKGATE_CON(1), 10, GFLAGS),
|
||||
COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_pre", 0,
|
||||
COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_pre", CLK_SET_RATE_PARENT,
|
||||
RK2928_CLKSEL_CON(18), 0,
|
||||
RK2928_CLKGATE_CON(1), 11, GFLAGS,
|
||||
&common_uart1_fracmux),
|
||||
COMPOSITE_NOMUX(0, "uart2_pre", "uart_src", 0,
|
||||
RK2928_CLKSEL_CON(15), 0, 7, DFLAGS,
|
||||
RK2928_CLKGATE_CON(1), 12, GFLAGS),
|
||||
COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_pre", 0,
|
||||
COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_pre", CLK_SET_RATE_PARENT,
|
||||
RK2928_CLKSEL_CON(19), 0,
|
||||
RK2928_CLKGATE_CON(1), 13, GFLAGS,
|
||||
&common_uart2_fracmux),
|
||||
COMPOSITE_NOMUX(0, "uart3_pre", "uart_src", 0,
|
||||
RK2928_CLKSEL_CON(16), 0, 7, DFLAGS,
|
||||
RK2928_CLKGATE_CON(1), 14, GFLAGS),
|
||||
COMPOSITE_FRACMUX(0, "uart3_frac", "uart3_pre", 0,
|
||||
COMPOSITE_FRACMUX(0, "uart3_frac", "uart3_pre", CLK_SET_RATE_PARENT,
|
||||
RK2928_CLKSEL_CON(20), 0,
|
||||
RK2928_CLKGATE_CON(1), 15, GFLAGS,
|
||||
&common_uart3_fracmux),
|
||||
|
@ -449,7 +449,6 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
|
|||
|
||||
/* hclk_cpu gates */
|
||||
GATE(HCLK_ROM, "hclk_rom", "hclk_cpu", 0, RK2928_CLKGATE_CON(5), 6, GFLAGS),
|
||||
GATE(HCLK_I2S0, "hclk_i2s0", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS),
|
||||
GATE(HCLK_SPDIF, "hclk_spdif", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 1, GFLAGS),
|
||||
GATE(0, "hclk_cpubus", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 8, GFLAGS),
|
||||
/* hclk_ahb2apb is part of a clk branch */
|
||||
|
@ -543,15 +542,15 @@ static struct clk_div_table div_aclk_cpu_t[] = {
|
|||
};
|
||||
|
||||
static struct rockchip_clk_branch rk3066a_i2s0_fracmux __initdata =
|
||||
MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0,
|
||||
MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, CLK_SET_RATE_PARENT,
|
||||
RK2928_CLKSEL_CON(2), 8, 2, MFLAGS);
|
||||
|
||||
static struct rockchip_clk_branch rk3066a_i2s1_fracmux __initdata =
|
||||
MUX(SCLK_I2S1, "sclk_i2s1", mux_sclk_i2s1_p, 0,
|
||||
MUX(SCLK_I2S1, "sclk_i2s1", mux_sclk_i2s1_p, CLK_SET_RATE_PARENT,
|
||||
RK2928_CLKSEL_CON(3), 8, 2, MFLAGS);
|
||||
|
||||
static struct rockchip_clk_branch rk3066a_i2s2_fracmux __initdata =
|
||||
MUX(SCLK_I2S2, "sclk_i2s2", mux_sclk_i2s2_p, 0,
|
||||
MUX(SCLK_I2S2, "sclk_i2s2", mux_sclk_i2s2_p, CLK_SET_RATE_PARENT,
|
||||
RK2928_CLKSEL_CON(4), 8, 2, MFLAGS);
|
||||
|
||||
static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = {
|
||||
|
@ -615,27 +614,28 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = {
|
|||
COMPOSITE_NOMUX(0, "i2s0_pre", "i2s_src", 0,
|
||||
RK2928_CLKSEL_CON(2), 0, 7, DFLAGS,
|
||||
RK2928_CLKGATE_CON(0), 7, GFLAGS),
|
||||
COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", 0,
|
||||
COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", CLK_SET_RATE_PARENT,
|
||||
RK2928_CLKSEL_CON(6), 0,
|
||||
RK2928_CLKGATE_CON(0), 8, GFLAGS,
|
||||
&rk3066a_i2s0_fracmux),
|
||||
COMPOSITE_NOMUX(0, "i2s1_pre", "i2s_src", 0,
|
||||
RK2928_CLKSEL_CON(3), 0, 7, DFLAGS,
|
||||
RK2928_CLKGATE_CON(0), 9, GFLAGS),
|
||||
COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_pre", 0,
|
||||
COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_pre", CLK_SET_RATE_PARENT,
|
||||
RK2928_CLKSEL_CON(7), 0,
|
||||
RK2928_CLKGATE_CON(0), 10, GFLAGS,
|
||||
&rk3066a_i2s1_fracmux),
|
||||
COMPOSITE_NOMUX(0, "i2s2_pre", "i2s_src", 0,
|
||||
RK2928_CLKSEL_CON(4), 0, 7, DFLAGS,
|
||||
RK2928_CLKGATE_CON(0), 11, GFLAGS),
|
||||
COMPOSITE_FRACMUX(0, "i2s2_frac", "i2s2_pre", 0,
|
||||
COMPOSITE_FRACMUX(0, "i2s2_frac", "i2s2_pre", CLK_SET_RATE_PARENT,
|
||||
RK2928_CLKSEL_CON(8), 0,
|
||||
RK2928_CLKGATE_CON(0), 12, GFLAGS,
|
||||
&rk3066a_i2s2_fracmux),
|
||||
|
||||
GATE(HCLK_I2S1, "hclk_i2s1", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS),
|
||||
GATE(HCLK_I2S2, "hclk_i2s2", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS),
|
||||
GATE(HCLK_I2S0, "hclk_i2s0", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS),
|
||||
GATE(HCLK_I2S1, "hclk_i2s1", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS),
|
||||
GATE(HCLK_I2S2, "hclk_i2s2", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS),
|
||||
GATE(HCLK_CIF1, "hclk_cif1", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 6, GFLAGS),
|
||||
GATE(HCLK_HDMI, "hclk_hdmi", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS),
|
||||
|
||||
|
@ -728,6 +728,7 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = {
|
|||
RK2928_CLKGATE_CON(0), 10, GFLAGS,
|
||||
&rk3188_i2s0_fracmux),
|
||||
|
||||
GATE(HCLK_I2S0, "hclk_i2s0", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS),
|
||||
GATE(0, "hclk_imem0", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS),
|
||||
GATE(0, "hclk_imem1", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 15, GFLAGS),
|
||||
|
||||
|
|
|
@ -603,8 +603,7 @@ void rockchip_clk_protect_critical(const char *const clocks[],
|
|||
for (i = 0; i < nclocks; i++) {
|
||||
struct clk *clk = __clk_lookup(clocks[i]);
|
||||
|
||||
if (clk)
|
||||
clk_prepare_enable(clk);
|
||||
clk_prepare_enable(clk);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_clk_protect_critical);
|
||||
|
|
|
@ -2,10 +2,73 @@
|
|||
# Recent Exynos platforms should just select COMMON_CLK_SAMSUNG:
|
||||
config COMMON_CLK_SAMSUNG
|
||||
bool "Samsung Exynos clock controller support" if COMPILE_TEST
|
||||
# Clocks on ARM64 SoCs (e.g. Exynos5433, Exynos7) are chosen by
|
||||
# EXYNOS_ARM64_COMMON_CLK to avoid building them on ARMv7:
|
||||
select S3C64XX_COMMON_CLK if ARM && ARCH_S3C64XX
|
||||
select S5PV210_COMMON_CLK if ARM && ARCH_S5PV210
|
||||
select EXYNOS_3250_COMMON_CLK if ARM && SOC_EXYNOS3250
|
||||
select EXYNOS_4_COMMON_CLK if ARM && ARCH_EXYNOS4
|
||||
select EXYNOS_5250_COMMON_CLK if ARM && SOC_EXYNOS5250
|
||||
select EXYNOS_5260_COMMON_CLK if ARM && SOC_EXYNOS5260
|
||||
select EXYNOS_5410_COMMON_CLK if ARM && SOC_EXYNOS5410
|
||||
select EXYNOS_5420_COMMON_CLK if ARM && SOC_EXYNOS5420
|
||||
select EXYNOS_ARM64_COMMON_CLK if ARM64 && ARCH_EXYNOS
|
||||
|
||||
config S3C64XX_COMMON_CLK
|
||||
bool "Samsung S3C64xx clock controller support" if COMPILE_TEST
|
||||
depends on COMMON_CLK_SAMSUNG
|
||||
help
|
||||
Support for the clock controller present on the Samsung S3C64xx SoCs.
|
||||
Choose Y here only if you build for this SoC.
|
||||
|
||||
config S5PV210_COMMON_CLK
|
||||
bool "Samsung S5Pv210 clock controller support" if COMPILE_TEST
|
||||
depends on COMMON_CLK_SAMSUNG
|
||||
help
|
||||
Support for the clock controller present on the Samsung S5Pv210 SoCs.
|
||||
Choose Y here only if you build for this SoC.
|
||||
|
||||
config EXYNOS_3250_COMMON_CLK
|
||||
bool "Samsung Exynos3250 clock controller support" if COMPILE_TEST
|
||||
depends on COMMON_CLK_SAMSUNG
|
||||
help
|
||||
Support for the clock controller present on the Samsung
|
||||
Exynos3250 SoCs. Choose Y here only if you build for this SoC.
|
||||
|
||||
config EXYNOS_4_COMMON_CLK
|
||||
bool "Samsung Exynos4 clock controller support" if COMPILE_TEST
|
||||
depends on COMMON_CLK_SAMSUNG
|
||||
help
|
||||
Support for the clock controller present on the Samsung
|
||||
Exynos4212 and Exynos4412 SoCs. Choose Y here only if you build for
|
||||
this SoC.
|
||||
|
||||
config EXYNOS_5250_COMMON_CLK
|
||||
bool "Samsung Exynos5250 clock controller support" if COMPILE_TEST
|
||||
depends on COMMON_CLK_SAMSUNG
|
||||
help
|
||||
Support for the clock controller present on the Samsung
|
||||
Exynos5250 SoCs. Choose Y here only if you build for this SoC.
|
||||
|
||||
config EXYNOS_5260_COMMON_CLK
|
||||
bool "Samsung Exynos5260 clock controller support" if COMPILE_TEST
|
||||
depends on COMMON_CLK_SAMSUNG
|
||||
help
|
||||
Support for the clock controller present on the Samsung
|
||||
Exynos5260 SoCs. Choose Y here only if you build for this SoC.
|
||||
|
||||
config EXYNOS_5410_COMMON_CLK
|
||||
bool "Samsung Exynos5410 clock controller support" if COMPILE_TEST
|
||||
depends on COMMON_CLK_SAMSUNG
|
||||
help
|
||||
Support for the clock controller present on the Samsung
|
||||
Exynos5410 SoCs. Choose Y here only if you build for this SoC.
|
||||
|
||||
config EXYNOS_5420_COMMON_CLK
|
||||
bool "Samsung Exynos5420 clock controller support" if COMPILE_TEST
|
||||
depends on COMMON_CLK_SAMSUNG
|
||||
help
|
||||
Support for the clock controller present on the Samsung
|
||||
Exynos5420 SoCs. Choose Y here only if you build for this SoC.
|
||||
|
||||
config EXYNOS_ARM64_COMMON_CLK
|
||||
bool "Samsung Exynos ARMv8-family clock controller support" if COMPILE_TEST
|
||||
depends on COMMON_CLK_SAMSUNG
|
||||
|
|
|
@ -4,15 +4,15 @@
|
|||
#
|
||||
|
||||
obj-$(CONFIG_COMMON_CLK) += clk.o clk-pll.o clk-cpu.o
|
||||
obj-$(CONFIG_SOC_EXYNOS3250) += clk-exynos3250.o
|
||||
obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4.o
|
||||
obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4412-isp.o
|
||||
obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o
|
||||
obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5-subcmu.o
|
||||
obj-$(CONFIG_SOC_EXYNOS5260) += clk-exynos5260.o
|
||||
obj-$(CONFIG_SOC_EXYNOS5410) += clk-exynos5410.o
|
||||
obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o
|
||||
obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5-subcmu.o
|
||||
obj-$(CONFIG_EXYNOS_3250_COMMON_CLK) += clk-exynos3250.o
|
||||
obj-$(CONFIG_EXYNOS_4_COMMON_CLK) += clk-exynos4.o
|
||||
obj-$(CONFIG_EXYNOS_4_COMMON_CLK) += clk-exynos4412-isp.o
|
||||
obj-$(CONFIG_EXYNOS_5250_COMMON_CLK) += clk-exynos5250.o
|
||||
obj-$(CONFIG_EXYNOS_5250_COMMON_CLK) += clk-exynos5-subcmu.o
|
||||
obj-$(CONFIG_EXYNOS_5260_COMMON_CLK) += clk-exynos5260.o
|
||||
obj-$(CONFIG_EXYNOS_5410_COMMON_CLK) += clk-exynos5410.o
|
||||
obj-$(CONFIG_EXYNOS_5420_COMMON_CLK) += clk-exynos5420.o
|
||||
obj-$(CONFIG_EXYNOS_5420_COMMON_CLK) += clk-exynos5-subcmu.o
|
||||
obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos5433.o
|
||||
obj-$(CONFIG_EXYNOS_AUDSS_CLK_CON) += clk-exynos-audss.o
|
||||
obj-$(CONFIG_EXYNOS_CLKOUT) += clk-exynos-clkout.o
|
||||
|
@ -21,5 +21,5 @@ obj-$(CONFIG_S3C2410_COMMON_CLK)+= clk-s3c2410.o
|
|||
obj-$(CONFIG_S3C2410_COMMON_DCLK)+= clk-s3c2410-dclk.o
|
||||
obj-$(CONFIG_S3C2412_COMMON_CLK)+= clk-s3c2412.o
|
||||
obj-$(CONFIG_S3C2443_COMMON_CLK)+= clk-s3c2443.o
|
||||
obj-$(CONFIG_ARCH_S3C64XX) += clk-s3c64xx.o
|
||||
obj-$(CONFIG_ARCH_S5PV210) += clk-s5pv210.o clk-s5pv210-audss.o
|
||||
obj-$(CONFIG_S3C64XX_COMMON_CLK) += clk-s3c64xx.o
|
||||
obj-$(CONFIG_S5PV210_COMMON_CLK) += clk-s5pv210.o clk-s5pv210-audss.o
|
||||
|
|
|
@ -8,14 +8,17 @@
|
|||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timekeeping.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include "clk.h"
|
||||
#include "clk-pll.h"
|
||||
|
||||
#define PLL_TIMEOUT_MS 10
|
||||
#define PLL_TIMEOUT_US 20000U
|
||||
#define PLL_TIMEOUT_LOOPS 1000000U
|
||||
|
||||
struct samsung_clk_pll {
|
||||
struct clk_hw hw;
|
||||
|
@ -63,6 +66,53 @@ static long samsung_pll_round_rate(struct clk_hw *hw,
|
|||
return rate_table[i - 1].rate;
|
||||
}
|
||||
|
||||
static bool pll_early_timeout = true;
|
||||
|
||||
static int __init samsung_pll_disable_early_timeout(void)
|
||||
{
|
||||
pll_early_timeout = false;
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(samsung_pll_disable_early_timeout);
|
||||
|
||||
/* Wait until the PLL is locked */
|
||||
static int samsung_pll_lock_wait(struct samsung_clk_pll *pll,
|
||||
unsigned int reg_mask)
|
||||
{
|
||||
int i, ret;
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
* This function might be called when the timekeeping API can't be used
|
||||
* to detect timeouts. One situation is when the clocksource is not yet
|
||||
* initialized, another when the timekeeping is suspended. udelay() also
|
||||
* cannot be used when the clocksource is not running on arm64, since
|
||||
* the current timer is used as cycle counter. So a simple busy loop
|
||||
* is used here in that special cases. The limit of iterations has been
|
||||
* derived from experimental measurements of various PLLs on multiple
|
||||
* Exynos SoC variants. Single register read time was usually in range
|
||||
* 0.4...1.5 us, never less than 0.4 us.
|
||||
*/
|
||||
if (pll_early_timeout || timekeeping_suspended) {
|
||||
i = PLL_TIMEOUT_LOOPS;
|
||||
while (i-- > 0) {
|
||||
if (readl_relaxed(pll->con_reg) & reg_mask)
|
||||
return 0;
|
||||
|
||||
cpu_relax();
|
||||
}
|
||||
ret = -ETIMEDOUT;
|
||||
} else {
|
||||
ret = readl_relaxed_poll_timeout_atomic(pll->con_reg, val,
|
||||
val & reg_mask, 0, PLL_TIMEOUT_US);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
pr_err("Could not lock PLL %s\n", clk_hw_get_name(&pll->hw));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int samsung_pll3xxx_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct samsung_clk_pll *pll = to_clk_pll(hw);
|
||||
|
@ -72,13 +122,7 @@ static int samsung_pll3xxx_enable(struct clk_hw *hw)
|
|||
tmp |= BIT(pll->enable_offs);
|
||||
writel_relaxed(tmp, pll->con_reg);
|
||||
|
||||
/* wait lock time */
|
||||
do {
|
||||
cpu_relax();
|
||||
tmp = readl_relaxed(pll->con_reg);
|
||||
} while (!(tmp & BIT(pll->lock_offs)));
|
||||
|
||||
return 0;
|
||||
return samsung_pll_lock_wait(pll, BIT(pll->lock_offs));
|
||||
}
|
||||
|
||||
static void samsung_pll3xxx_disable(struct clk_hw *hw)
|
||||
|
@ -240,13 +284,10 @@ static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate,
|
|||
(rate->sdiv << PLL35XX_SDIV_SHIFT);
|
||||
writel_relaxed(tmp, pll->con_reg);
|
||||
|
||||
/* Wait until the PLL is locked if it is enabled. */
|
||||
if (tmp & BIT(pll->enable_offs)) {
|
||||
do {
|
||||
cpu_relax();
|
||||
tmp = readl_relaxed(pll->con_reg);
|
||||
} while (!(tmp & BIT(pll->lock_offs)));
|
||||
}
|
||||
/* Wait for PLL lock if the PLL is enabled */
|
||||
if (tmp & BIT(pll->enable_offs))
|
||||
return samsung_pll_lock_wait(pll, BIT(pll->lock_offs));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -318,7 +359,7 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate,
|
|||
unsigned long parent_rate)
|
||||
{
|
||||
struct samsung_clk_pll *pll = to_clk_pll(hw);
|
||||
u32 tmp, pll_con0, pll_con1;
|
||||
u32 pll_con0, pll_con1;
|
||||
const struct samsung_pll_rate_table *rate;
|
||||
|
||||
rate = samsung_get_pll_settings(pll, drate);
|
||||
|
@ -356,13 +397,8 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate,
|
|||
pll_con1 |= rate->kdiv << PLL36XX_KDIV_SHIFT;
|
||||
writel_relaxed(pll_con1, pll->con_reg + 4);
|
||||
|
||||
/* wait_lock_time */
|
||||
if (pll_con0 & BIT(pll->enable_offs)) {
|
||||
do {
|
||||
cpu_relax();
|
||||
tmp = readl_relaxed(pll->con_reg);
|
||||
} while (!(tmp & BIT(pll->lock_offs)));
|
||||
}
|
||||
if (pll_con0 & BIT(pll->enable_offs))
|
||||
return samsung_pll_lock_wait(pll, BIT(pll->lock_offs));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -437,7 +473,6 @@ static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate,
|
|||
struct samsung_clk_pll *pll = to_clk_pll(hw);
|
||||
const struct samsung_pll_rate_table *rate;
|
||||
u32 con0, con1;
|
||||
ktime_t start;
|
||||
|
||||
/* Get required rate settings from table */
|
||||
rate = samsung_get_pll_settings(pll, drate);
|
||||
|
@ -488,21 +523,8 @@ static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate,
|
|||
writel_relaxed(con1, pll->con_reg + 0x4);
|
||||
writel_relaxed(con0, pll->con_reg);
|
||||
|
||||
/* Wait for locking. */
|
||||
start = ktime_get();
|
||||
while (!(readl_relaxed(pll->con_reg) & PLL45XX_LOCKED)) {
|
||||
ktime_t delta = ktime_sub(ktime_get(), start);
|
||||
|
||||
if (ktime_to_ms(delta) > PLL_TIMEOUT_MS) {
|
||||
pr_err("%s: could not lock PLL %s\n",
|
||||
__func__, clk_hw_get_name(hw));
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* Wait for PLL lock */
|
||||
return samsung_pll_lock_wait(pll, PLL45XX_LOCKED);
|
||||
}
|
||||
|
||||
static const struct clk_ops samsung_pll45xx_clk_ops = {
|
||||
|
@ -588,7 +610,6 @@ static int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate,
|
|||
struct samsung_clk_pll *pll = to_clk_pll(hw);
|
||||
const struct samsung_pll_rate_table *rate;
|
||||
u32 con0, con1, lock;
|
||||
ktime_t start;
|
||||
|
||||
/* Get required rate settings from table */
|
||||
rate = samsung_get_pll_settings(pll, drate);
|
||||
|
@ -647,21 +668,8 @@ static int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate,
|
|||
writel_relaxed(con0, pll->con_reg);
|
||||
writel_relaxed(con1, pll->con_reg + 0x4);
|
||||
|
||||
/* Wait for locking. */
|
||||
start = ktime_get();
|
||||
while (!(readl_relaxed(pll->con_reg) & PLL46XX_LOCKED)) {
|
||||
ktime_t delta = ktime_sub(ktime_get(), start);
|
||||
|
||||
if (ktime_to_ms(delta) > PLL_TIMEOUT_MS) {
|
||||
pr_err("%s: could not lock PLL %s\n",
|
||||
__func__, clk_hw_get_name(hw));
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* Wait for PLL lock */
|
||||
return samsung_pll_lock_wait(pll, PLL46XX_LOCKED);
|
||||
}
|
||||
|
||||
static const struct clk_ops samsung_pll46xx_clk_ops = {
|
||||
|
@ -1035,14 +1043,9 @@ static int samsung_pll2550xx_set_rate(struct clk_hw *hw, unsigned long drate,
|
|||
(rate->sdiv << PLL2550XX_S_SHIFT);
|
||||
writel_relaxed(tmp, pll->con_reg);
|
||||
|
||||
/* wait_lock_time */
|
||||
do {
|
||||
cpu_relax();
|
||||
tmp = readl_relaxed(pll->con_reg);
|
||||
} while (!(tmp & (PLL2550XX_LOCK_STAT_MASK
|
||||
<< PLL2550XX_LOCK_STAT_SHIFT)));
|
||||
|
||||
return 0;
|
||||
/* Wait for PLL lock */
|
||||
return samsung_pll_lock_wait(pll,
|
||||
PLL2550XX_LOCK_STAT_MASK << PLL2550XX_LOCK_STAT_SHIFT);
|
||||
}
|
||||
|
||||
static const struct clk_ops samsung_pll2550xx_clk_ops = {
|
||||
|
@ -1132,13 +1135,9 @@ static int samsung_pll2650x_set_rate(struct clk_hw *hw, unsigned long drate,
|
|||
con1 |= ((rate->kdiv & PLL2650X_K_MASK) << PLL2650X_K_SHIFT);
|
||||
writel_relaxed(con1, pll->con_reg + 4);
|
||||
|
||||
do {
|
||||
cpu_relax();
|
||||
con0 = readl_relaxed(pll->con_reg);
|
||||
} while (!(con0 & (PLL2650X_LOCK_STAT_MASK
|
||||
<< PLL2650X_LOCK_STAT_SHIFT)));
|
||||
|
||||
return 0;
|
||||
/* Wait for PLL lock */
|
||||
return samsung_pll_lock_wait(pll,
|
||||
PLL2650X_LOCK_STAT_MASK << PLL2650X_LOCK_STAT_SHIFT);
|
||||
}
|
||||
|
||||
static const struct clk_ops samsung_pll2650x_clk_ops = {
|
||||
|
@ -1196,7 +1195,7 @@ static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate,
|
|||
unsigned long parent_rate)
|
||||
{
|
||||
struct samsung_clk_pll *pll = to_clk_pll(hw);
|
||||
u32 tmp, pll_con0, pll_con2;
|
||||
u32 pll_con0, pll_con2;
|
||||
const struct samsung_pll_rate_table *rate;
|
||||
|
||||
rate = samsung_get_pll_settings(pll, drate);
|
||||
|
@ -1229,11 +1228,7 @@ static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate,
|
|||
writel_relaxed(pll_con0, pll->con_reg);
|
||||
writel_relaxed(pll_con2, pll->con_reg + 8);
|
||||
|
||||
do {
|
||||
tmp = readl_relaxed(pll->con_reg);
|
||||
} while (!(tmp & (0x1 << PLL2650XX_PLL_LOCKTIME_SHIFT)));
|
||||
|
||||
return 0;
|
||||
return samsung_pll_lock_wait(pll, 0x1 << PLL2650XX_PLL_LOCKTIME_SHIFT);
|
||||
}
|
||||
|
||||
static const struct clk_ops samsung_pll2650xx_clk_ops = {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue