Commit 8653b778 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 8552d28e abe7e32f
# 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>;
};
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>;
};
# 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>;
};
# 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";
};
};
# 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";
};
# 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";
};
# 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
......
# 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>;
};
...
* 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";
};
# 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";
};
# 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))
......
This diff is collapsed.
......@@ -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))
......
This diff is collapsed.
......@@ -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);
// 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;
spin_lock_irqsave(gate->lock, flags);
if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT)
return clk_gate_ops.is_enabled(hw);
ret = clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx,
gate->cgr_val, gate->cgr_mask);
return clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx);
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,
......
This diff is collapsed.
......@@ -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)
{
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);
}
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_scu(name, parents, num_parents, rsrc_id, clk_type);
return __imx_clk_lpcg_scu(dev, name, parent_name, flags, reg,
bit_idx, hw_gate);
}
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(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");
This diff is collapsed.
......@@ -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");
This diff is collapsed.
......@@ -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)
{
......
This diff is collapsed.
......@@ -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
......
This diff is collapsed.
This diff is collapsed.
......@@ -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)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment