Commit f4a6365a 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:
 "There are a few changes to the core framework this time around, in
  addition to the normal collection of driver updates to support new
  SoCs, fix incorrect data, and convert various drivers to clk_hw based
  APIs.

  In the core, we allow clk_ops::init() to return an error code now so
  that we can fail clk registration if the callback does something like
  fail to allocate memory. We also add a new "terminate" clk_op so that
  things done in clk_ops::init() can be undone, e.g. free memory. We
  also spit out a warning now when critical clks fail to enable and we
  support changing clk rates and enable/disable state through debugfs
  when developers compile the kernel themselves.

  On the driver front, we get support for what seems like a lot of
  Qualcomm and NXP SoCs given that those vendors dominate the diffstat.
  There are a couple new drivers for Xilinx and Amlogic SoCs too. The
  updates are all small things like fixing the way glitch free muxes
  switch parents, avoiding div-by-zero problems, or fixing data like
  parent names. See the updates section below for more details.

  Finally, the "basic" clk types have been converted to support
  specifying parents with clk_hw pointers. This work includes an
  overhaul of the fixed-rate clk type to be more modern by using clk_hw
  APIs.

  Core:
   - Let clk_ops::init() return an error code
   - Add a clk_ops::terminate() callback to undo clk_ops::init()
   - Warn about critical clks that fail to enable or prepare
   - Support dangerous debugfs actions on clks with dead code

  New Drivers:
   - Support for Xilinx Versal platform clks
   - Display clk controller on qcom sc7180
   - Video clk controller on qcom sc7180
   - Graphics clk controller on qcom sc7180
   - CPU PLLs for qcom msm8916
   - Move qcom msm8974 gfx3d clk to RPM control
   - Display port clk support on qcom sdm845 SoCs
   - Global clk controller on qcom ipq6018
   - Add a driver for BCLK of Freescale SAI cores
   - Add cam, vpe and sgx clock support for TI dra7
   - Add aess clock support for TI omap5
   - Enable clks for CPUfreq on Allwinner A64 SoCs
   - Add Amlogic meson8b DDR clock controller
   - Add input clocks to Amlogic meson8b controllers
   - Add SPIBSC (SPI FLASH) clock on Renesas RZ/A2
   - i.MX8MP clk driver support

  Updates:
   - Convert gpio, fixed-factor, mux, gate, divider basic clks to hw
     based APIs
   - Detect more PRMCU variants in ux500 driver
   - Adjust the composite clk type to new way of describing clk parents
   - Fixes for clk controllers on qcom msm8998 SoCs
   - Fix gmac main clock for TI dra7
   - Move TI dra7-atl clock header to correct location
   - Fix hidden node name dependency on TI clkctrl clocks
   - Fix Amlogic meson8b mali clock update using the glitch free mux
   - Fix Amlogic pll driver division by zero at init
   - Prepare for split of Renesas R-Car H3 ES1.x and ES2.0+ config
     symbols
   - Switch more i.MX clk drivers to clk_hw based APIs
   - Disable non-functional divider between pll4_audio_div and
     pll4_post_div on imx6q
   - Fix watchdog2 clock name typo in imx7ulp clock driver
   - Set CLK_GET_RATE_NOCACHE flag for DRAM related clocks on i.MX8M
     SoCs
   - Suppress bind attrs for i.MX8M clock driver
   - Add a big comment in imx8qxp-lpcg driver to tell why
     devm_platform_ioremap_resource() shouldn't be used for the driver
   - A correction on i.MX8MN usb1_ctrl parent clock setting"

* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (140 commits)
  dt/bindings: clk: fsl,plldig: Drop 'bindings' from schema id
  clk: ls1028a: Fix warning on clamp() usage
  clk: qoriq: add ls1088a hwaccel clocks support
  clk: ls1028a: Add clock driver for Display output interface
  dt/bindings: clk: Add YAML schemas for LS1028A Display Clock bindings
  clk: fsl-sai: new driver
  dt-bindings: clock: document the fsl-sai driver
  clk: composite: add _register_composite_pdata() variants
  clk: qcom: rpmh: Sort OF match table
  dt-bindings: fix warnings in validation of qcom,gcc.yaml
  dt-binding: fix compilation error of the example in qcom,gcc.yaml
  clk: zynqmp: Add support for clock with CLK_DIVIDER_POWER_OF_TWO flag
  clk: zynqmp: Fix divider calculation
  clk: zynqmp: Add support for get max divider
  clk: zynqmp: Warn user if clock user are more than allowed
  clk: zynqmp: Extend driver for versal
  dt-bindings: clock: Add bindings for versal clock driver
  clk: ti: clkctrl: Fix hidden dependency to node name
  clk: ti: add clkctrl data dra7 sgx
  clk: ti: omap5: Add missing AESS clock
  ...
parents fe70da5a fc6a15c8
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/amlogic,meson8-ddr-clkc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic DDR Clock Controller Device Tree Bindings
maintainers:
- Martin Blumenstingl <martin.blumenstingl@googlemail.com>
properties:
compatible:
enum:
- amlogic,meson8-ddr-clkc
- amlogic,meson8b-ddr-clkc
reg:
maxItems: 1
clocks:
maxItems: 1
clock-names:
items:
- const: xtal
"#clock-cells":
const: 1
required:
- compatible
- reg
- clocks
- clock-names
- "#clock-cells"
additionalProperties: false
examples:
- |
ddr_clkc: clock-controller@400 {
compatible = "amlogic,meson8-ddr-clkc";
reg = <0x400 0x20>;
clocks = <&xtal>;
clock-names = "xtal";
#clock-cells = <1>;
};
...
...@@ -11,6 +11,11 @@ Required Properties: ...@@ -11,6 +11,11 @@ Required Properties:
- "amlogic,meson8m2-clkc" for Meson8m2 (S812) SoCs - "amlogic,meson8m2-clkc" for Meson8m2 (S812) SoCs
- #clock-cells: should be 1. - #clock-cells: should be 1.
- #reset-cells: should be 1. - #reset-cells: should be 1.
- clocks: list of clock phandles, one for each entry in clock-names
- clock-names: should contain the following:
* "xtal": the 24MHz system oscillator
* "ddr_pll": the DDR PLL clock
* "clk_32k": (if present) the 32kHz clock signal from GPIOAO_6 (CLK_32K_IN)
Parent node should have the following properties : Parent node should have the following properties :
- compatible: "amlogic,meson-hhi-sysctrl", "simple-mfd", "syscon" - compatible: "amlogic,meson-hhi-sysctrl", "simple-mfd", "syscon"
......
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/fsl,plldig.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP QorIQ Layerscape LS1028A Display PIXEL Clock Binding
maintainers:
- Wen He <wen.he_1@nxp.com>
description: |
NXP LS1028A has a clock domain PXLCLK0 used for the Display output
interface in the display core, as implemented in TSMC CLN28HPM PLL.
which generate and offers pixel clocks to Display.
properties:
compatible:
const: fsl,ls1028a-plldig
reg:
maxItems: 1
'#clock-cells':
const: 0
fsl,vco-hz:
description: Optional for VCO frequency of the PLL in Hertz.
The VCO frequency of this PLL cannot be changed during runtime
only at startup. Therefore, the output frequencies are very
limited and might not even closely match the requested frequency.
To work around this restriction the user may specify its own
desired VCO frequency for the PLL.
minimum: 650000000
maximum: 1300000000
default: 1188000000
required:
- compatible
- reg
- clocks
- '#clock-cells'
examples:
# Display PIXEL Clock node:
- |
dpclk: clock-display@f1f0000 {
compatible = "fsl,ls1028a-plldig";
reg = <0x0 0xf1f0000 0x0 0xffff>;
#clock-cells = <0>;
clocks = <&osc_27m>;
};
...
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/bindings/clock/fsl,sai-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale SAI bitclock-as-a-clock binding
maintainers:
- Michael Walle <michael@walle.cc>
description: |
It is possible to use the BCLK pin of a SAI module as a generic clock
output. Some SoC are very constrained in their pin multiplexer
configuration. Eg. pins can only be changed groups. For example, on the
LS1028A SoC you can only enable SAIs in pairs. If you use only one SAI,
the second pins are wasted. Using this binding it is possible to use the
clock of the second SAI as a MCLK clock for an audio codec, for example.
This is a composite of a gated clock and a divider clock.
properties:
compatible:
const: fsl,vf610-sai-clock
reg:
maxItems: 1
clocks:
maxItems: 1
'#clock-cells':
const: 0
required:
- compatible
- reg
- clocks
- '#clock-cells'
additionalProperties: false
examples:
- |
soc {
#address-cells = <2>;
#size-cells = <2>;
mclk: clock-mclk@f130080 {
compatible = "fsl,vf610-sai-clock";
reg = <0x0 0xf130080 0x0 0x80>;
#clock-cells = <0>;
clocks = <&parentclk>;
};
};
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/bindings/clock/imx8mp-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP i.MX8M Plus Clock Control Module Binding
maintainers:
- Anson Huang <Anson.Huang@nxp.com>
description:
NXP i.MX8M Plus clock control module is an integrated clock controller, which
generates and supplies to all modules.
properties:
compatible:
const: fsl,imx8mp-ccm
reg:
maxItems: 1
clocks:
items:
- description: 32k osc
- description: 24m osc
- description: ext1 clock input
- description: ext2 clock input
- description: ext3 clock input
- description: ext4 clock input
clock-names:
items:
- const: osc_32k
- const: osc_24m
- const: clk_ext1
- const: clk_ext2
- const: clk_ext3
- const: clk_ext4
'#clock-cells':
const: 1
description:
The clock consumer should specify the desired clock by having the clock
ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mp-clock.h
for the full list of i.MX8M Plus clock IDs.
required:
- compatible
- reg
- clocks
- clock-names
- '#clock-cells'
examples:
# Clock Control Module node:
- |
clk: clock-controller@30380000 {
compatible = "fsl,imx8mp-ccm";
reg = <0x30380000 0x10000>;
#clock-cells = <1>;
clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>,
<&clk_ext2>, <&clk_ext3>, <&clk_ext4>;
clock-names = "osc_32k", "osc_24m", "clk_ext1",
"clk_ext2", "clk_ext3", "clk_ext4";
};
...
Qualcomm Technologies, Inc. Display Clock Controller Binding
------------------------------------------------------------
Required properties :
- compatible : shall contain "qcom,sdm845-dispcc"
- reg : shall contain base register location and length.
- #clock-cells : from common clock binding, shall contain 1.
- #reset-cells : from common reset binding, shall contain 1.
- #power-domain-cells : from generic power domain binding, shall contain 1.
Example:
dispcc: clock-controller@af00000 {
compatible = "qcom,sdm845-dispcc";
reg = <0xaf00000 0x100000>;
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
};
# SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2
---
$id: http://devicetree.org/schemas/bindings/clock/qcom,dispcc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Display Clock & Reset Controller Binding
maintainers:
- Taniya Das <tdas@codeaurora.org>
description: |
Qualcomm display clock control module which supports the clocks, resets and
power domains.
properties:
compatible:
enum:
- qcom,sc7180-dispcc
- qcom,sdm845-dispcc
clocks:
minItems: 1
maxItems: 2
items:
- description: Board XO source
- description: GPLL0 source from GCC
clock-names:
items:
- const: xo
- const: gpll0
'#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'
examples:
# Example of DISPCC with clock node properties for SDM845:
- |
clock-controller@af00000 {
compatible = "qcom,sdm845-dispcc";
reg = <0xaf00000 0x10000>;
clocks = <&rpmhcc 0>, <&gcc 24>;
clock-names = "xo", "gpll0";
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
};
...
...@@ -19,8 +19,9 @@ properties: ...@@ -19,8 +19,9 @@ properties:
enum: enum:
- qcom,gcc-apq8064 - qcom,gcc-apq8064
- qcom,gcc-apq8084 - qcom,gcc-apq8084
- qcom,gcc-ipq8064
- qcom,gcc-ipq4019 - qcom,gcc-ipq4019
- qcom,gcc-ipq6018
- qcom,gcc-ipq8064
- qcom,gcc-ipq8074 - qcom,gcc-ipq8074
- qcom,gcc-msm8660 - qcom,gcc-msm8660
- qcom,gcc-msm8916 - qcom,gcc-msm8916
...@@ -40,20 +41,50 @@ properties: ...@@ -40,20 +41,50 @@ properties:
- qcom,gcc-sm8150 - qcom,gcc-sm8150
clocks: clocks:
minItems: 1 oneOf:
maxItems: 3 #qcom,gcc-sm8150
items: #qcom,gcc-sc7180
- description: Board XO source - items:
- description: Board active XO source - description: Board XO source
- description: Sleep clock source - description: Board active XO source
- description: Sleep clock source
#qcom,gcc-msm8996
- items:
- description: XO source
- description: Second XO source
- description: Sleep clock source
#qcom,gcc-msm8998
- items:
- description: Board XO source
- description: Sleep clock source
- description: USB 3.0 phy pipe clock
- description: UFS phy rx symbol clock for pipe 0
- description: UFS phy rx symbol clock for pipe 1
- description: UFS phy tx symbol clock
- description: PCIE phy pipe clock
clock-names: clock-names:
minItems: 1 oneOf:
maxItems: 3 #qcom,gcc-sm8150
items: #qcom,gcc-sc7180
- const: bi_tcxo - items:
- const: bi_tcxo_ao - const: bi_tcxo
- const: sleep_clk - const: bi_tcxo_ao
- const: sleep_clk
#qcom,gcc-msm8996
- items:
- const: cxo
- const: cxo2
- const: sleep_clk
#qcom,gcc-msm8998
- items:
- const: xo
- const: sleep_clk
- const: usb3_pipe
- const: ufs_rx_symbol0
- const: ufs_rx_symbol1
- const: ufs_tx_symbol0
- const: pcie0_pipe
'#clock-cells': '#clock-cells':
const: 1 const: 1
...@@ -118,6 +149,7 @@ else: ...@@ -118,6 +149,7 @@ else:
compatible: compatible:
contains: contains:
enum: enum:
- qcom,gcc-msm8998
- qcom,gcc-sm8150 - qcom,gcc-sm8150
- qcom,gcc-sc7180 - qcom,gcc-sc7180
then: then:
...@@ -179,10 +211,35 @@ examples: ...@@ -179,10 +211,35 @@ examples:
clock-controller@100000 { clock-controller@100000 {
compatible = "qcom,gcc-sc7180"; compatible = "qcom,gcc-sc7180";
reg = <0x100000 0x1f0000>; reg = <0x100000 0x1f0000>;
clocks = <&rpmhcc 0>, <&rpmhcc 1>; clocks = <&rpmhcc 0>, <&rpmhcc 1>, <0>;
clock-names = "bi_tcxo", "bi_tcxo_ao"; clock-names = "bi_tcxo", "bi_tcxo_ao", "sleep_clk";
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
};
# Example of MSM8998 GCC:
- |
#include <dt-bindings/clock/qcom,rpmcc.h>
clock-controller@100000 {
compatible = "qcom,gcc-msm8998";
#clock-cells = <1>; #clock-cells = <1>;
#reset-cells = <1>; #reset-cells = <1>;
#power-domain-cells = <1>; #power-domain-cells = <1>;
reg = <0x00100000 0xb0000>;
clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>,
<&sleep>,
<0>,
<0>,
<0>,
<0>,
<0>;
clock-names = "xo",
"sleep_clk",
"usb3_pipe",
"ufs_rx_symbol0",
"ufs_rx_symbol1",
"ufs_tx_symbol0",
"pcie0_pipe";
}; };
... ...
Qualcomm Graphics Clock & Reset Controller Binding
--------------------------------------------------
Required properties :
- compatible : shall contain "qcom,sdm845-gpucc" or "qcom,msm8998-gpucc"
- reg : shall contain base register location and length
- #clock-cells : from common clock binding, shall contain 1
- #reset-cells : from common reset binding, shall contain 1
- #power-domain-cells : from generic power domain binding, shall contain 1
- clocks : shall contain the XO clock
shall contain the gpll0 out main clock (msm8998)
- clock-names : shall be "xo"
shall be "gpll0" (msm8998)
Example:
gpucc: clock-controller@5090000 {
compatible = "qcom,sdm845-gpucc";
reg = <0x5090000 0x9000>;
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
clocks = <&rpmhcc RPMH_CXO_CLK>;
clock-names = "xo";
};
# SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2
---
$id: http://devicetree.org/schemas/bindings/clock/qcom,gpucc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Graphics Clock & Reset Controller Binding
maintainers:
- Taniya Das <tdas@codeaurora.org>
description: |
Qualcomm grpahics clock control module which supports the clocks, resets and
power domains.
properties:
compatible:
enum:
- qcom,msm8998-gpucc
- qcom,sc7180-gpucc
- qcom,sdm845-gpucc
clocks:
minItems: 1
maxItems: 3
items:
- description: Board XO source
- description: GPLL0 main branch source from GCC(gcc_gpu_gpll0_clk_src)
- description: GPLL0 div branch source from GCC(gcc_gpu_gpll0_div_clk_src)
clock-names:
minItems: 1
maxItems: 3
items:
- const: xo
- const: gpll0_main
- const: gpll0_div
'#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'
examples:
# Example of GPUCC with clock node properties for SDM845:
- |
clock-controller@5090000 {
compatible = "qcom,sdm845-gpucc";
reg = <0x5090000 0x9000>;
clocks = <&rpmhcc 0>, <&gcc 31>, <&gcc 32>;
clock-names = "xo", "gpll0_main", "gpll0_div";
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
};
...
Qualcomm Multimedia Clock & Reset Controller Binding
----------------------------------------------------
Required properties :
- compatible : shall contain only one of the following:
"qcom,mmcc-apq8064"
"qcom,mmcc-apq8084"
"qcom,mmcc-msm8660"
"qcom,mmcc-msm8960"
"qcom,mmcc-msm8974"
"qcom,mmcc-msm8996"
- reg : shall contain base register location and length
- #clock-cells : shall contain 1
- #reset-cells : shall contain 1
Optional properties :
- #power-domain-cells : shall contain 1
Example:
clock-controller@4000000 {
compatible = "qcom,mmcc-msm8960";
reg = <0x4000000 0x1000>;
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
};
# SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2
---
$id: http://devicetree.org/schemas/bindings/clock/qcom,mmcc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Multimedia Clock & Reset Controller Binding
maintainers:
- Jeffrey Hugo <jhugo@codeaurora.org>
- Taniya Das <tdas@codeaurora.org>
description: |
Qualcomm multimedia clock control module which supports the clocks, resets and
power domains.
properties:
compatible :
enum:
- qcom,mmcc-apq8064
- qcom,mmcc-apq8084
- qcom,mmcc-msm8660
- qcom,mmcc-msm8960
- qcom,mmcc-msm8974
- qcom,mmcc-msm8996
- qcom,mmcc-msm8998
clocks:
items:
- description: Board XO source
- description: Board sleep source
- description: Global PLL 0 clock
- description: DSI phy instance 0 dsi clock
- description: DSI phy instance 0 byte clock
- description: DSI phy instance 1 dsi clock
- description: DSI phy instance 1 byte clock
- description: HDMI phy PLL clock
- description: DisplayPort phy PLL vco clock
- description: DisplayPort phy PLL link clock
clock-names:
items:
- const: xo
- const: sleep
- const: gpll0
- const: dsi0dsi
- const: dsi0byte
- const: dsi1dsi
- const: dsi1byte
- const: hdmipll
- const: dpvco
- const: dplink
'#clock-cells':
const: 1
'#reset-cells':
const: 1
'#power-domain-cells':
const: 1
reg:
maxItems: 1
protected-clocks:
description:
Protected clock specifier list as per common clock binding
required:
- compatible
- reg
- '#clock-cells'
- '#reset-cells'
- '#power-domain-cells'
if:
properties:
compatible:
contains:
const: qcom,mmcc-msm8998
then:
required:
- clocks
- clock-names
examples:
# Example for MMCC for MSM8960:
- |
clock-controller@4000000 {
compatible = "qcom,mmcc-msm8960";
reg = <0x4000000 0x1000>;
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
};
...
Qualcomm Video Clock & Reset Controller Binding
-----------------------------------------------
Required properties :
- compatible : shall contain "qcom,sdm845-videocc"
- reg : shall contain base register location and length
- #clock-cells : from common clock binding, shall contain 1.
- #power-domain-cells : from generic power domain binding, shall contain 1.
- #reset-cells : from common reset binding, shall contain 1.
Example:
videocc: clock-controller@ab00000 {
compatible = "qcom,sdm845-videocc";
reg = <0xab00000 0x10000>;
#clock-cells = <1>;
#power-domain-cells = <1>;
#reset-cells = <1>;
};
# SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2
---
$id: http://devicetree.org/schemas/bindings/clock/qcom,videocc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Video Clock & Reset Controller Binding
maintainers:
- Taniya Das <tdas@codeaurora.org>
description: |
Qualcomm video clock control module which supports the clocks, resets and
power domains.
properties:
compatible:
enum:
- qcom,sc7180-videocc
- qcom,sdm845-videocc
clocks:
maxItems: 1
clock-names:
items:
- 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'
examples:
# Example of VIDEOCC with clock node properties for SDM845:
- |
clock-controller@ab00000 {
compatible = "qcom,sdm845-videocc";
reg = <0xab00000 0x10000>;
clocks = <&rpmhcc 0>;
clock-names = "xo";
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
};
...
...@@ -19,7 +19,7 @@ Required Properties: ...@@ -19,7 +19,7 @@ Required Properties:
- "renesas,r8a7745-cpg-mssr" for the r8a7745 SoC (RZ/G1E) - "renesas,r8a7745-cpg-mssr" for the r8a7745 SoC (RZ/G1E)
- "renesas,r8a77470-cpg-mssr" for the r8a77470 SoC (RZ/G1C) - "renesas,r8a77470-cpg-mssr" for the r8a77470 SoC (RZ/G1C)
- "renesas,r8a774a1-cpg-mssr" for the r8a774a1 SoC (RZ/G2M) - "renesas,r8a774a1-cpg-mssr" for the r8a774a1 SoC (RZ/G2M)
- "renesas,r8a774b1-cpg-mssr" for the r8a774a1 SoC (RZ/G2N) - "renesas,r8a774b1-cpg-mssr" for the r8a774b1 SoC (RZ/G2N)
- "renesas,r8a774c0-cpg-mssr" for the r8a774c0 SoC (RZ/G2E) - "renesas,r8a774c0-cpg-mssr" for the r8a774c0 SoC (RZ/G2E)
- "renesas,r8a7790-cpg-mssr" for the r8a7790 SoC (R-Car H2) - "renesas,r8a7790-cpg-mssr" for the r8a7790 SoC (R-Car H2)
- "renesas,r8a7791-cpg-mssr" for the r8a7791 SoC (R-Car M2-W) - "renesas,r8a7791-cpg-mssr" for the r8a7791 SoC (R-Car M2-W)
......
...@@ -16,18 +16,23 @@ For more information, please see the Linux clock framework binding at ...@@ -16,18 +16,23 @@ For more information, please see the Linux clock framework binding at
Documentation/devicetree/bindings/clock/clock-bindings.txt. Documentation/devicetree/bindings/clock/clock-bindings.txt.
Required properties : Required properties :
- compatible : shall be "ti,clkctrl" - compatible : shall be "ti,clkctrl" or a clock domain specific name:
"ti,clkctrl-l4-cfg"
"ti,clkctrl-l4-per"
"ti,clkctrl-l4-secure"
"ti,clkctrl-l4-wkup"
- #clock-cells : shall contain 2 with the first entry being the instance - #clock-cells : shall contain 2 with the first entry being the instance
offset from the clock domain base and the second being the offset from the clock domain base and the second being the
clock index clock index
- reg : clock registers
Example: Clock controller node on omap 4430: Example: Clock controller node on omap 4430:
&cm2 { &cm2 {
l4per: cm@1400 { l4per: cm@1400 {
cm_l4per@0 { cm_l4per@0 {
cm_l4per_clkctrl: clk@20 { cm_l4per_clkctrl: clock@20 {
compatible = "ti,clkctrl"; compatible = "ti,clkctrl-l4-per", "ti,clkctrl";
reg = <0x20 0x1b0>; reg = <0x20 0x1b0>;
#clock-cells = <2>; #clock-cells = <2>;
}; };
......
...@@ -43,7 +43,7 @@ Configuration of ATL instances: ...@@ -43,7 +43,7 @@ Configuration of ATL instances:
- aws : Audio word select signal selection - aws : Audio word select signal selection
}; };
For valid word select signals, see the dt-bindings/clk/ti-dra7-atl.h include For valid word select signals, see the dt-bindings/clock/ti-dra7-atl.h include
file. file.
Examples: Examples:
...@@ -83,7 +83,7 @@ atl: atl@4843c000 { ...@@ -83,7 +83,7 @@ atl: atl@4843c000 {
clock-names = "fck"; clock-names = "fck";
}; };
#include <dt-bindings/clk/ti-dra7-atl.h> #include <dt-bindings/clock/ti-dra7-atl.h>
&atl { &atl {
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/bindings/clock/xlnx,versal-clk.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Xilinx Versal clock controller
maintainers:
- Michal Simek <michal.simek@xilinx.com>
- Jolly Shah <jolly.shah@xilinx.com>
- Rajan Vaja <rajan.vaja@xilinx.com>
description: |
The clock controller is a hardware block of Xilinx versal clock tree. It
reads required input clock frequencies from the devicetree and acts as clock
provider for all clock consumers of PS clocks.
select: false
properties:
compatible:
const: xlnx,versal-clk
"#clock-cells":
const: 1
clocks:
description: List of clock specifiers which are external input
clocks to the given clock controller.
items:
- description: reference clock
- description: alternate reference clock
- description: alternate reference clock for programmable logic
clock-names:
items:
- const: ref
- const: alt_ref
- const: pl_alt_ref
required:
- compatible
- "#clock-cells"
- clocks
- clock-names
additionalProperties: false
examples:
- |
firmware {
zynqmp_firmware: zynqmp-firmware {
compatible = "xlnx,zynqmp-firmware";
method = "smc";
versal_clk: clock-controller {
#clock-cells = <1>;
compatible = "xlnx,versal-clk";
clocks = <&ref>, <&alt_ref>, <&pl_alt_ref>;
clock-names = "ref", "alt_ref", "pl_alt_ref";
};
};
};
...
...@@ -21,10 +21,11 @@ platforms. ...@@ -21,10 +21,11 @@ platforms.
Usage: required Usage: required
Value type: <prop-encoded-array> Value type: <prop-encoded-array>
Definition: must specify the base address and size of the global block Definition: must specify the base address and size of the global block
- clocks: - clocks:
Usage: required if #clocks-cells property is present Usage: required if #clock-names property is present
Value type: <phandle> Value type: <phandle array>
Definition: phandle to the input PLL, which feeds the APCS mux/divider Definition: phandles to the two parent clocks of the clock driver.
- #mbox-cells: - #mbox-cells:
Usage: required Usage: required
...@@ -36,6 +37,12 @@ platforms. ...@@ -36,6 +37,12 @@ platforms.
Value type: <u32> Value type: <u32>
Definition: as described in clock.txt, must be 0 Definition: as described in clock.txt, must be 0
- clock-names:
Usage: required if the platform data based clock driver needs to
retrieve the parent clock names from device tree.
This will requires two mandatory clocks to be defined.
Value type: <string-array>
Definition: must be "pll" and "aux"
= EXAMPLE = EXAMPLE
The following example describes the APCS HMSS found in MSM8996 and part of the The following example describes the APCS HMSS found in MSM8996 and part of the
...@@ -68,3 +75,14 @@ Below is another example of the APCS binding on MSM8916 platforms: ...@@ -68,3 +75,14 @@ Below is another example of the APCS binding on MSM8916 platforms:
clocks = <&a53pll>; clocks = <&a53pll>;
#clock-cells = <0>; #clock-cells = <0>;
}; };
Below is another example of the APCS binding on QCS404 platforms:
apcs_glb: mailbox@b011000 {
compatible = "qcom,qcs404-apcs-apps-global", "syscon";
reg = <0x0b011000 0x1000>;
#mbox-cells = <1>;
clocks = <&apcs_hfpll>, <&gcc GCC_GPLL0_AO_OUT_MAIN>;
clock-names = "pll", "aux";
#clock-cells = <0>;
};
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
*/ */
#include <dt-bindings/gpio/gpio.h> #include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/clk/ti-dra7-atl.h> #include <dt-bindings/clock/ti-dra7-atl.h>
#include <dt-bindings/input/input.h> #include <dt-bindings/input/input.h>
/ { / {
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
#include "dra72x.dtsi" #include "dra72x.dtsi"
#include <dt-bindings/gpio/gpio.h> #include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/clk/ti-dra7-atl.h> #include <dt-bindings/clock/ti-dra7-atl.h>
/ { / {
compatible = "ti,dra72-evm", "ti,dra722", "ti,dra72", "ti,dra7"; compatible = "ti,dra72-evm", "ti,dra722", "ti,dra72", "ti,dra7";
......
...@@ -1734,6 +1734,20 @@ dss_clkctrl: dss-clkctrl@20 { ...@@ -1734,6 +1734,20 @@ dss_clkctrl: dss-clkctrl@20 {
}; };
}; };
gpu_cm: gpu-cm@1200 {
compatible = "ti,omap4-cm";
reg = <0x1200 0x100>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x1200 0x100>;
gpu_clkctrl: gpu-clkctrl@20 {
compatible = "ti,clkctrl";
reg = <0x20 0x4>;
#clock-cells = <2>;
};
};
l3init_cm: l3init-cm@1300 { l3init_cm: l3init-cm@1300 {
compatible = "ti,omap4-cm"; compatible = "ti,omap4-cm";
reg = <0x1300 0x100>; reg = <0x1300 0x100>;
......
...@@ -27,7 +27,7 @@ config COMMON_CLK_WM831X ...@@ -27,7 +27,7 @@ config COMMON_CLK_WM831X
tristate "Clock driver for WM831x/2x PMICs" tristate "Clock driver for WM831x/2x PMICs"
depends on MFD_WM831X depends on MFD_WM831X
---help--- ---help---
Supports the clocking subsystem of the WM831x/2x series of Supports the clocking subsystem of the WM831x/2x series of
PMICs from Wolfson Microelectronics. PMICs from Wolfson Microelectronics.
source "drivers/clk/versatile/Kconfig" source "drivers/clk/versatile/Kconfig"
...@@ -174,6 +174,18 @@ config COMMON_CLK_CS2000_CP ...@@ -174,6 +174,18 @@ config COMMON_CLK_CS2000_CP
help help
If you say yes here you get support for the CS2000 clock multiplier. If you say yes here you get support for the CS2000 clock multiplier.
config COMMON_CLK_FSL_SAI
bool "Clock driver for BCLK of Freescale SAI cores"
depends on ARCH_LAYERSCAPE || COMPILE_TEST
help
This driver supports the Freescale SAI (Synchronous Audio Interface)
to be used as a generic clock output. Some SoCs have restrictions
regarding the possible pin multiplexer settings. Eg. on some SoCs
two SAI interfaces can only be enabled together. If just one is
needed, the BCLK pin of the second one can be used as general
purpose clock output. Ideally, it can be used to drive an audio
codec (sometimes known as MCLK).
config COMMON_CLK_GEMINI config COMMON_CLK_GEMINI
bool "Clock driver for Cortina Systems Gemini SoC" bool "Clock driver for Cortina Systems Gemini SoC"
depends on ARCH_GEMINI || COMPILE_TEST depends on ARCH_GEMINI || COMPILE_TEST
...@@ -225,6 +237,16 @@ config CLK_QORIQ ...@@ -225,6 +237,16 @@ config CLK_QORIQ
This adds the clock driver support for Freescale QorIQ platforms This adds the clock driver support for Freescale QorIQ platforms
using common clock framework. using common clock framework.
config CLK_LS1028A_PLLDIG
tristate "Clock driver for LS1028A Display output"
depends on ARCH_LAYERSCAPE || COMPILE_TEST
default ARCH_LAYERSCAPE
help
This driver support the Display output interfaces(LCD, DPHY) pixel clocks
of the QorIQ Layerscape LS1028A, as implemented TSMC CLN28HPM PLL. Not all
features of the PLL are currently supported by the driver. By default,
configured bypass mode with this PLL.
config COMMON_CLK_XGENE config COMMON_CLK_XGENE
bool "Clock driver for APM XGene SoC" bool "Clock driver for APM XGene SoC"
default ARCH_XGENE default ARCH_XGENE
......
...@@ -29,6 +29,7 @@ obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o ...@@ -29,6 +29,7 @@ obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o
obj-$(CONFIG_COMMON_CLK_FSL_SAI) += clk-fsl-sai.o
obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o
obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-aspeed.o obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-aspeed.o
obj-$(CONFIG_MACH_ASPEED_G6) += clk-ast2600.o obj-$(CONFIG_MACH_ASPEED_G6) += clk-ast2600.o
...@@ -44,6 +45,7 @@ obj-$(CONFIG_ARCH_NPCM7XX) += clk-npcm7xx.o ...@@ -44,6 +45,7 @@ obj-$(CONFIG_ARCH_NPCM7XX) += clk-npcm7xx.o
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
obj-$(CONFIG_COMMON_CLK_OXNAS) += clk-oxnas.o obj-$(CONFIG_COMMON_CLK_OXNAS) += clk-oxnas.o
obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o
obj-$(CONFIG_CLK_LS1028A_PLLDIG) += clk-plldig.o
obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o
obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o
obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o
......
...@@ -25,7 +25,8 @@ ...@@ -25,7 +25,8 @@
#define PMC_PLL_CTRL1_MUL_MSK GENMASK(30, 24) #define PMC_PLL_CTRL1_MUL_MSK GENMASK(30, 24)
#define PMC_PLL_ACR 0x18 #define PMC_PLL_ACR 0x18
#define PMC_PLL_ACR_DEFAULT 0x1b040010UL #define PMC_PLL_ACR_DEFAULT_UPLL 0x12020010UL
#define PMC_PLL_ACR_DEFAULT_PLLA 0x00020010UL
#define PMC_PLL_ACR_UTMIVR BIT(12) #define PMC_PLL_ACR_UTMIVR BIT(12)
#define PMC_PLL_ACR_UTMIBG BIT(13) #define PMC_PLL_ACR_UTMIBG BIT(13)
#define PMC_PLL_ACR_LOOP_FILTER_MSK GENMASK(31, 24) #define PMC_PLL_ACR_LOOP_FILTER_MSK GENMASK(31, 24)
...@@ -88,7 +89,10 @@ static int sam9x60_pll_prepare(struct clk_hw *hw) ...@@ -88,7 +89,10 @@ static int sam9x60_pll_prepare(struct clk_hw *hw)
} }
/* Recommended value for PMC_PLL_ACR */ /* Recommended value for PMC_PLL_ACR */
val = PMC_PLL_ACR_DEFAULT; if (pll->characteristics->upll)
val = PMC_PLL_ACR_DEFAULT_UPLL;
else
val = PMC_PLL_ACR_DEFAULT_PLLA;
regmap_write(regmap, PMC_PLL_ACR, val); regmap_write(regmap, PMC_PLL_ACR, val);
regmap_write(regmap, PMC_PLL_CTRL1, regmap_write(regmap, PMC_PLL_CTRL1,
......
...@@ -47,6 +47,7 @@ static const struct clk_programmable_layout sam9x60_programmable_layout = { ...@@ -47,6 +47,7 @@ static const struct clk_programmable_layout sam9x60_programmable_layout = {
.pres_shift = 8, .pres_shift = 8,
.css_mask = 0x1f, .css_mask = 0x1f,
.have_slck_mck = 0, .have_slck_mck = 0,
.is_pres_direct = 1,
}; };
static const struct clk_pcr_layout sam9x60_pcr_layout = { static const struct clk_pcr_layout sam9x60_pcr_layout = {
......
...@@ -260,7 +260,6 @@ static void __init asm9260_acc_init(struct device_node *np) ...@@ -260,7 +260,6 @@ static void __init asm9260_acc_init(struct device_node *np)
const char *ref_clk, *pll_clk = "pll"; const char *ref_clk, *pll_clk = "pll";
u32 rate; u32 rate;
int n; int n;
u32 accuracy = 0;
clk_data = kzalloc(struct_size(clk_data, hws, MAX_CLKS), GFP_KERNEL); clk_data = kzalloc(struct_size(clk_data, hws, MAX_CLKS), GFP_KERNEL);
if (!clk_data) if (!clk_data)
...@@ -275,10 +274,11 @@ static void __init asm9260_acc_init(struct device_node *np) ...@@ -275,10 +274,11 @@ static void __init asm9260_acc_init(struct device_node *np)
/* register pll */ /* register pll */
rate = (ioread32(base + HW_SYSPLLCTRL) & 0xffff) * 1000000; rate = (ioread32(base + HW_SYSPLLCTRL) & 0xffff) * 1000000;
/* TODO: Convert to DT parent scheme */
ref_clk = of_clk_get_parent_name(np, 0); ref_clk = of_clk_get_parent_name(np, 0);
accuracy = clk_get_accuracy(__clk_lookup(ref_clk)); hw = __clk_hw_register_fixed_rate_with_accuracy(NULL, NULL, pll_clk,
hw = clk_hw_register_fixed_rate_with_accuracy(NULL, pll_clk, ref_clk, NULL, NULL, 0, rate, 0,
ref_clk, 0, rate, accuracy); CLK_FIXED_RATE_PARENT_ACCURACY);
if (IS_ERR(hw)) if (IS_ERR(hw))
panic("%pOFn: can't register REFCLK. Check DT!", np); panic("%pOFn: can't register REFCLK. Check DT!", np);
......
...@@ -474,11 +474,10 @@ static struct bm1880_composite_clock bm1880_composite_clks[] = { ...@@ -474,11 +474,10 @@ static struct bm1880_composite_clock bm1880_composite_clks[] = {
static unsigned long bm1880_pll_rate_calc(u32 regval, unsigned long parent_rate) static unsigned long bm1880_pll_rate_calc(u32 regval, unsigned long parent_rate)
{ {
u64 numerator; u64 numerator;
u32 fbdiv, fref, refdiv; u32 fbdiv, refdiv;
u32 postdiv1, postdiv2, denominator; u32 postdiv1, postdiv2, denominator;
fbdiv = (regval >> 16) & 0xfff; fbdiv = (regval >> 16) & 0xfff;
fref = parent_rate;
refdiv = regval & 0x1f; refdiv = regval & 0x1f;
postdiv1 = (regval >> 8) & 0x7; postdiv1 = (regval >> 8) & 0x7;
postdiv2 = (regval >> 12) & 0x7; postdiv2 = (regval >> 12) & 0x7;
......
...@@ -199,8 +199,9 @@ static void clk_composite_disable(struct clk_hw *hw) ...@@ -199,8 +199,9 @@ static void clk_composite_disable(struct clk_hw *hw)
gate_ops->disable(gate_hw); gate_ops->disable(gate_hw);
} }
struct clk_hw *clk_hw_register_composite(struct device *dev, const char *name, static struct clk_hw *__clk_hw_register_composite(struct device *dev,
const char * const *parent_names, int num_parents, 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 *mux_hw, const struct clk_ops *mux_ops,
struct clk_hw *rate_hw, const struct clk_ops *rate_ops, struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
struct clk_hw *gate_hw, const struct clk_ops *gate_ops, struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
...@@ -218,7 +219,10 @@ struct clk_hw *clk_hw_register_composite(struct device *dev, const char *name, ...@@ -218,7 +219,10 @@ struct clk_hw *clk_hw_register_composite(struct device *dev, const char *name,
init.name = name; init.name = name;
init.flags = flags; init.flags = flags;
init.parent_names = parent_names; if (parent_names)
init.parent_names = parent_names;
else
init.parent_data = pdata;
init.num_parents = num_parents; init.num_parents = num_parents;
hw = &composite->hw; hw = &composite->hw;
...@@ -312,6 +316,34 @@ struct clk_hw *clk_hw_register_composite(struct device *dev, const char *name, ...@@ -312,6 +316,34 @@ struct clk_hw *clk_hw_register_composite(struct device *dev, const char *name,
return hw; return hw;
} }
struct clk_hw *clk_hw_register_composite(struct device *dev, const char *name,
const char * const *parent_names, 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 __clk_hw_register_composite(dev, name, parent_names, NULL,
num_parents, mux_hw, mux_ops,
rate_hw, rate_ops, gate_hw,
gate_ops, flags);
}
struct clk_hw *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 __clk_hw_register_composite(dev, name, NULL, parent_data,
num_parents, mux_hw, mux_ops,
rate_hw, rate_ops, gate_hw,
gate_ops, flags);
}
struct clk *clk_register_composite(struct device *dev, const char *name, struct clk *clk_register_composite(struct device *dev, const char *name,
const char * const *parent_names, int num_parents, const char * const *parent_names, int num_parents,
struct clk_hw *mux_hw, const struct clk_ops *mux_ops, struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
...@@ -329,6 +361,24 @@ struct clk *clk_register_composite(struct device *dev, const char *name, ...@@ -329,6 +361,24 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
return hw->clk; return hw->clk;
} }
struct clk *clk_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)
{
struct clk_hw *hw;
hw = clk_hw_register_composite_pdata(dev, name, parent_data,
num_parents, mux_hw, mux_ops, rate_hw, rate_ops,
gate_hw, gate_ops, flags);
if (IS_ERR(hw))
return ERR_CAST(hw);
return hw->clk;
}
void clk_unregister_composite(struct clk *clk) void clk_unregister_composite(struct clk *clk)
{ {
struct clk_composite *composite; struct clk_composite *composite;
......
...@@ -463,11 +463,12 @@ const struct clk_ops clk_divider_ro_ops = { ...@@ -463,11 +463,12 @@ const struct clk_ops clk_divider_ro_ops = {
}; };
EXPORT_SYMBOL_GPL(clk_divider_ro_ops); EXPORT_SYMBOL_GPL(clk_divider_ro_ops);
static struct clk_hw *_register_divider(struct device *dev, const char *name, struct clk_hw *__clk_hw_register_divider(struct device *dev,
const char *parent_name, unsigned long flags, struct device_node *np, const char *name,
void __iomem *reg, u8 shift, u8 width, const char *parent_name, const struct clk_hw *parent_hw,
u8 clk_divider_flags, const struct clk_div_table *table, const struct clk_parent_data *parent_data, unsigned long flags,
spinlock_t *lock) void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
const struct clk_div_table *table, spinlock_t *lock)
{ {
struct clk_divider *div; struct clk_divider *div;
struct clk_hw *hw; struct clk_hw *hw;
...@@ -514,55 +515,7 @@ static struct clk_hw *_register_divider(struct device *dev, const char *name, ...@@ -514,55 +515,7 @@ static struct clk_hw *_register_divider(struct device *dev, const char *name,
return hw; return hw;
} }
EXPORT_SYMBOL_GPL(__clk_hw_register_divider);
/**
* clk_register_divider - register a divider clock with the clock framework
* @dev: device registering this clock
* @name: name of this clock
* @parent_name: name of clock's parent
* @flags: framework-specific flags
* @reg: register address to adjust divider
* @shift: number of bits to shift the bitfield
* @width: width of the bitfield
* @clk_divider_flags: divider-specific flags for this clock
* @lock: shared register lock for this clock
*/
struct clk *clk_register_divider(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, spinlock_t *lock)
{
struct clk_hw *hw;
hw = _register_divider(dev, name, parent_name, flags, reg, shift,
width, clk_divider_flags, NULL, lock);
if (IS_ERR(hw))
return ERR_CAST(hw);
return hw->clk;
}
EXPORT_SYMBOL_GPL(clk_register_divider);
/**
* clk_hw_register_divider - register a divider clock with the clock framework
* @dev: device registering this clock
* @name: name of this clock
* @parent_name: name of clock's parent
* @flags: framework-specific flags
* @reg: register address to adjust divider
* @shift: number of bits to shift the bitfield
* @width: width of the bitfield
* @clk_divider_flags: divider-specific flags for this clock
* @lock: shared register lock for this clock
*/
struct clk_hw *clk_hw_register_divider(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, spinlock_t *lock)
{
return _register_divider(dev, name, parent_name, flags, reg, shift,
width, clk_divider_flags, NULL, lock);
}
EXPORT_SYMBOL_GPL(clk_hw_register_divider);
/** /**
* clk_register_divider_table - register a table based divider clock with * clk_register_divider_table - register a table based divider clock with
...@@ -586,39 +539,15 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name, ...@@ -586,39 +539,15 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
{ {
struct clk_hw *hw; struct clk_hw *hw;
hw = _register_divider(dev, name, parent_name, flags, reg, shift, hw = __clk_hw_register_divider(dev, NULL, name, parent_name, NULL,
width, clk_divider_flags, table, lock); NULL, flags, reg, shift, width, clk_divider_flags,
table, lock);
if (IS_ERR(hw)) if (IS_ERR(hw))
return ERR_CAST(hw); return ERR_CAST(hw);
return hw->clk; return hw->clk;
} }
EXPORT_SYMBOL_GPL(clk_register_divider_table); EXPORT_SYMBOL_GPL(clk_register_divider_table);
/**
* clk_hw_register_divider_table - register a table based divider clock with
* the clock framework
* @dev: device registering this clock
* @name: name of this clock
* @parent_name: name of clock's parent
* @flags: framework-specific flags
* @reg: register address to adjust divider
* @shift: number of bits to shift the bitfield
* @width: width of the bitfield
* @clk_divider_flags: divider-specific flags for this clock
* @table: array of divider/value pairs ending with a div set to 0
* @lock: shared register lock for this clock
*/
struct clk_hw *clk_hw_register_divider_table(struct device *dev,
const char *name, const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, const struct clk_div_table *table,
spinlock_t *lock)
{
return _register_divider(dev, name, parent_name, flags, reg, shift,
width, clk_divider_flags, table, lock);
}
EXPORT_SYMBOL_GPL(clk_hw_register_divider_table);
void clk_unregister_divider(struct clk *clk) void clk_unregister_divider(struct clk *clk)
{ {
struct clk_divider *div; struct clk_divider *div;
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
* parent - fixed parent. No clk_set_parent support * parent - fixed parent. No clk_set_parent support
*/ */
#define to_clk_fixed_rate(_hw) container_of(_hw, struct clk_fixed_rate, hw)
static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw, static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
...@@ -33,7 +35,12 @@ static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw, ...@@ -33,7 +35,12 @@ static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw,
static unsigned long clk_fixed_rate_recalc_accuracy(struct clk_hw *hw, static unsigned long clk_fixed_rate_recalc_accuracy(struct clk_hw *hw,
unsigned long parent_accuracy) unsigned long parent_accuracy)
{ {
return to_clk_fixed_rate(hw)->fixed_accuracy; struct clk_fixed_rate *fixed = to_clk_fixed_rate(hw);
if (fixed->flags & CLK_FIXED_RATE_PARENT_ACCURACY)
return parent_accuracy;
return fixed->fixed_accuracy;
} }
const struct clk_ops clk_fixed_rate_ops = { const struct clk_ops clk_fixed_rate_ops = {
...@@ -42,24 +49,17 @@ const struct clk_ops clk_fixed_rate_ops = { ...@@ -42,24 +49,17 @@ const struct clk_ops clk_fixed_rate_ops = {
}; };
EXPORT_SYMBOL_GPL(clk_fixed_rate_ops); EXPORT_SYMBOL_GPL(clk_fixed_rate_ops);
/** struct clk_hw *__clk_hw_register_fixed_rate(struct device *dev,
* clk_hw_register_fixed_rate_with_accuracy - register fixed-rate clock with struct device_node *np, const char *name,
* the clock framework const char *parent_name, const struct clk_hw *parent_hw,
* @dev: device that is registering this clock const struct clk_parent_data *parent_data, unsigned long flags,
* @name: name of this clock unsigned long fixed_rate, unsigned long fixed_accuracy,
* @parent_name: name of clock's parent unsigned long clk_fixed_flags)
* @flags: framework-specific flags
* @fixed_rate: non-adjustable clock rate
* @fixed_accuracy: non-adjustable clock rate
*/
struct clk_hw *clk_hw_register_fixed_rate_with_accuracy(struct device *dev,
const char *name, const char *parent_name, unsigned long flags,
unsigned long fixed_rate, unsigned long fixed_accuracy)
{ {
struct clk_fixed_rate *fixed; struct clk_fixed_rate *fixed;
struct clk_hw *hw; struct clk_hw *hw;
struct clk_init_data init = {}; struct clk_init_data init = {};
int ret; int ret = -EINVAL;
/* allocate fixed-rate clock */ /* allocate fixed-rate clock */
fixed = kzalloc(sizeof(*fixed), GFP_KERNEL); fixed = kzalloc(sizeof(*fixed), GFP_KERNEL);
...@@ -69,17 +69,26 @@ struct clk_hw *clk_hw_register_fixed_rate_with_accuracy(struct device *dev, ...@@ -69,17 +69,26 @@ struct clk_hw *clk_hw_register_fixed_rate_with_accuracy(struct device *dev,
init.name = name; init.name = name;
init.ops = &clk_fixed_rate_ops; init.ops = &clk_fixed_rate_ops;
init.flags = flags; init.flags = flags;
init.parent_names = (parent_name ? &parent_name: NULL); init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = (parent_name ? 1 : 0); init.parent_hws = parent_hw ? &parent_hw : NULL;
init.parent_data = parent_data;
if (parent_name || parent_hw || parent_data)
init.num_parents = 1;
else
init.num_parents = 0;
/* struct clk_fixed_rate assignments */ /* struct clk_fixed_rate assignments */
fixed->flags = clk_fixed_flags;
fixed->fixed_rate = fixed_rate; fixed->fixed_rate = fixed_rate;
fixed->fixed_accuracy = fixed_accuracy; fixed->fixed_accuracy = fixed_accuracy;
fixed->hw.init = &init; fixed->hw.init = &init;
/* register the clock */ /* register the clock */
hw = &fixed->hw; hw = &fixed->hw;
ret = clk_hw_register(dev, hw); if (dev || !np)
ret = clk_hw_register(dev, hw);
else if (np)
ret = of_clk_hw_register(np, hw);
if (ret) { if (ret) {
kfree(fixed); kfree(fixed);
hw = ERR_PTR(ret); hw = ERR_PTR(ret);
...@@ -87,47 +96,20 @@ struct clk_hw *clk_hw_register_fixed_rate_with_accuracy(struct device *dev, ...@@ -87,47 +96,20 @@ struct clk_hw *clk_hw_register_fixed_rate_with_accuracy(struct device *dev,
return hw; return hw;
} }
EXPORT_SYMBOL_GPL(clk_hw_register_fixed_rate_with_accuracy); EXPORT_SYMBOL_GPL(__clk_hw_register_fixed_rate);
struct clk *clk_register_fixed_rate_with_accuracy(struct device *dev, struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
const char *name, const char *parent_name, unsigned long flags, const char *parent_name, unsigned long flags,
unsigned long fixed_rate, unsigned long fixed_accuracy) unsigned long fixed_rate)
{ {
struct clk_hw *hw; struct clk_hw *hw;
hw = clk_hw_register_fixed_rate_with_accuracy(dev, name, parent_name, hw = clk_hw_register_fixed_rate_with_accuracy(dev, name, parent_name,
flags, fixed_rate, fixed_accuracy); flags, fixed_rate, 0);
if (IS_ERR(hw)) if (IS_ERR(hw))
return ERR_CAST(hw); return ERR_CAST(hw);
return hw->clk; return hw->clk;
} }
EXPORT_SYMBOL_GPL(clk_register_fixed_rate_with_accuracy);
/**
* clk_hw_register_fixed_rate - register fixed-rate clock with the clock
* framework
* @dev: device that is registering this clock
* @name: name of this clock
* @parent_name: name of clock's parent
* @flags: framework-specific flags
* @fixed_rate: non-adjustable clock rate
*/
struct clk_hw *clk_hw_register_fixed_rate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
unsigned long fixed_rate)
{
return clk_hw_register_fixed_rate_with_accuracy(dev, name, parent_name,
flags, fixed_rate, 0);
}
EXPORT_SYMBOL_GPL(clk_hw_register_fixed_rate);
struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
unsigned long fixed_rate)
{
return clk_register_fixed_rate_with_accuracy(dev, name, parent_name,
flags, fixed_rate, 0);
}
EXPORT_SYMBOL_GPL(clk_register_fixed_rate); EXPORT_SYMBOL_GPL(clk_register_fixed_rate);
void clk_unregister_fixed_rate(struct clk *clk) void clk_unregister_fixed_rate(struct clk *clk)
...@@ -155,9 +137,9 @@ void clk_hw_unregister_fixed_rate(struct clk_hw *hw) ...@@ -155,9 +137,9 @@ void clk_hw_unregister_fixed_rate(struct clk_hw *hw)
EXPORT_SYMBOL_GPL(clk_hw_unregister_fixed_rate); EXPORT_SYMBOL_GPL(clk_hw_unregister_fixed_rate);
#ifdef CONFIG_OF #ifdef CONFIG_OF
static struct clk *_of_fixed_clk_setup(struct device_node *node) static struct clk_hw *_of_fixed_clk_setup(struct device_node *node)
{ {
struct clk *clk; struct clk_hw *hw;
const char *clk_name = node->name; const char *clk_name = node->name;
u32 rate; u32 rate;
u32 accuracy = 0; u32 accuracy = 0;
...@@ -170,18 +152,18 @@ static struct clk *_of_fixed_clk_setup(struct device_node *node) ...@@ -170,18 +152,18 @@ static struct clk *_of_fixed_clk_setup(struct device_node *node)
of_property_read_string(node, "clock-output-names", &clk_name); of_property_read_string(node, "clock-output-names", &clk_name);
clk = clk_register_fixed_rate_with_accuracy(NULL, clk_name, NULL, hw = clk_hw_register_fixed_rate_with_accuracy(NULL, clk_name, NULL,
0, rate, accuracy); 0, rate, accuracy);
if (IS_ERR(clk)) if (IS_ERR(hw))
return clk; return hw;
ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
if (ret) { if (ret) {
clk_unregister(clk); clk_hw_unregister_fixed_rate(hw);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
return clk; return hw;
} }
/** /**
...@@ -195,27 +177,27 @@ CLK_OF_DECLARE(fixed_clk, "fixed-clock", of_fixed_clk_setup); ...@@ -195,27 +177,27 @@ CLK_OF_DECLARE(fixed_clk, "fixed-clock", of_fixed_clk_setup);
static int of_fixed_clk_remove(struct platform_device *pdev) static int of_fixed_clk_remove(struct platform_device *pdev)
{ {
struct clk *clk = platform_get_drvdata(pdev); struct clk_hw *hw = platform_get_drvdata(pdev);
of_clk_del_provider(pdev->dev.of_node); of_clk_del_provider(pdev->dev.of_node);
clk_unregister_fixed_rate(clk); clk_hw_unregister_fixed_rate(hw);
return 0; return 0;
} }
static int of_fixed_clk_probe(struct platform_device *pdev) static int of_fixed_clk_probe(struct platform_device *pdev)
{ {
struct clk *clk; struct clk_hw *hw;
/* /*
* This function is not executed when of_fixed_clk_setup * This function is not executed when of_fixed_clk_setup
* succeeded. * succeeded.
*/ */
clk = _of_fixed_clk_setup(pdev->dev.of_node); hw = _of_fixed_clk_setup(pdev->dev.of_node);
if (IS_ERR(clk)) if (IS_ERR(hw))
return PTR_ERR(clk); return PTR_ERR(hw);
platform_set_drvdata(pdev, clk); platform_set_drvdata(pdev, hw);
return 0; return 0;
} }
...@@ -224,7 +206,6 @@ static const struct of_device_id of_fixed_clk_ids[] = { ...@@ -224,7 +206,6 @@ static const struct of_device_id of_fixed_clk_ids[] = {
{ .compatible = "fixed-clock" }, { .compatible = "fixed-clock" },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, of_fixed_clk_ids);
static struct platform_driver of_fixed_clk_driver = { static struct platform_driver of_fixed_clk_driver = {
.driver = { .driver = {
......
// SPDX-License-Identifier: GPL-2.0
/*
* Freescale SAI BCLK as a generic clock driver
*
* Copyright 2020 Michael Walle <michael@walle.cc>
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/slab.h>
#define I2S_CSR 0x00
#define I2S_CR2 0x08
#define CSR_BCE_BIT 28
#define CR2_BCD BIT(24)
#define CR2_DIV_SHIFT 0
#define CR2_DIV_WIDTH 8
struct fsl_sai_clk {
struct clk_divider div;
struct clk_gate gate;
spinlock_t lock;
};
static int fsl_sai_clk_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct fsl_sai_clk *sai_clk;
struct clk_parent_data pdata = { .index = 0 };
void __iomem *base;
struct clk_hw *hw;
struct resource *res;
sai_clk = devm_kzalloc(dev, sizeof(*sai_clk), GFP_KERNEL);
if (!sai_clk)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
spin_lock_init(&sai_clk->lock);
sai_clk->gate.reg = base + I2S_CSR;
sai_clk->gate.bit_idx = CSR_BCE_BIT;
sai_clk->gate.lock = &sai_clk->lock;
sai_clk->div.reg = base + I2S_CR2;
sai_clk->div.shift = CR2_DIV_SHIFT;
sai_clk->div.width = CR2_DIV_WIDTH;
sai_clk->div.lock = &sai_clk->lock;
/* 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);
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 of_fsl_sai_clk_ids[] = {
{ .compatible = "fsl,vf610-sai-clock" },
{ }
};
MODULE_DEVICE_TABLE(of, of_fsl_sai_clk_ids);
static struct platform_driver fsl_sai_clk_driver = {
.probe = fsl_sai_clk_probe,
.driver = {
.name = "fsl-sai-clk",
.of_match_table = of_fsl_sai_clk_ids,
},
};
module_platform_driver(fsl_sai_clk_driver);
MODULE_DESCRIPTION("Freescale SAI bitclock-as-a-clock driver");
MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:fsl-sai-clk");
...@@ -123,26 +123,18 @@ const struct clk_ops clk_gate_ops = { ...@@ -123,26 +123,18 @@ const struct clk_ops clk_gate_ops = {
}; };
EXPORT_SYMBOL_GPL(clk_gate_ops); EXPORT_SYMBOL_GPL(clk_gate_ops);
/** struct clk_hw *__clk_hw_register_gate(struct device *dev,
* clk_hw_register_gate - register a gate clock with the clock framework struct device_node *np, const char *name,
* @dev: device that is registering this clock const char *parent_name, const struct clk_hw *parent_hw,
* @name: name of this clock const struct clk_parent_data *parent_data,
* @parent_name: name of this clock's parent unsigned long flags,
* @flags: framework-specific flags for this clock
* @reg: register address to control gating of this clock
* @bit_idx: which bit in the register controls gating of this clock
* @clk_gate_flags: gate-specific flags for this clock
* @lock: shared register lock for this clock
*/
struct clk_hw *clk_hw_register_gate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 bit_idx, void __iomem *reg, u8 bit_idx,
u8 clk_gate_flags, spinlock_t *lock) u8 clk_gate_flags, spinlock_t *lock)
{ {
struct clk_gate *gate; struct clk_gate *gate;
struct clk_hw *hw; struct clk_hw *hw;
struct clk_init_data init = {}; struct clk_init_data init = {};
int ret; int ret = -EINVAL;
if (clk_gate_flags & CLK_GATE_HIWORD_MASK) { if (clk_gate_flags & CLK_GATE_HIWORD_MASK) {
if (bit_idx > 15) { if (bit_idx > 15) {
...@@ -160,7 +152,12 @@ struct clk_hw *clk_hw_register_gate(struct device *dev, const char *name, ...@@ -160,7 +152,12 @@ struct clk_hw *clk_hw_register_gate(struct device *dev, const char *name,
init.ops = &clk_gate_ops; init.ops = &clk_gate_ops;
init.flags = flags; init.flags = flags;
init.parent_names = parent_name ? &parent_name : NULL; init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0; init.parent_hws = parent_hw ? &parent_hw : NULL;
init.parent_data = parent_data;
if (parent_name || parent_hw || parent_data)
init.num_parents = 1;
else
init.num_parents = 0;
/* struct clk_gate assignments */ /* struct clk_gate assignments */
gate->reg = reg; gate->reg = reg;
...@@ -170,15 +167,19 @@ struct clk_hw *clk_hw_register_gate(struct device *dev, const char *name, ...@@ -170,15 +167,19 @@ struct clk_hw *clk_hw_register_gate(struct device *dev, const char *name,
gate->hw.init = &init; gate->hw.init = &init;
hw = &gate->hw; hw = &gate->hw;
ret = clk_hw_register(dev, hw); if (dev || !np)
ret = clk_hw_register(dev, hw);
else if (np)
ret = of_clk_hw_register(np, hw);
if (ret) { if (ret) {
kfree(gate); kfree(gate);
hw = ERR_PTR(ret); hw = ERR_PTR(ret);
} }
return hw; return hw;
} }
EXPORT_SYMBOL_GPL(clk_hw_register_gate); EXPORT_SYMBOL_GPL(__clk_hw_register_gate);
struct clk *clk_register_gate(struct device *dev, const char *name, struct clk *clk_register_gate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags, const char *parent_name, unsigned long flags,
......
...@@ -28,6 +28,26 @@ ...@@ -28,6 +28,26 @@
* parent - fixed parent. No clk_set_parent support * parent - fixed parent. No clk_set_parent support
*/ */
/**
* struct clk_gpio - gpio gated clock
*
* @hw: handle between common and hardware-specific interfaces
* @gpiod: gpio descriptor
*
* Clock with a gpio control for enabling and disabling the parent clock
* or switching between two parents by asserting or deasserting the gpio.
*
* Implements .enable, .disable and .is_enabled or
* .get_parent, .set_parent and .determine_rate depending on which clk_ops
* is used.
*/
struct clk_gpio {
struct clk_hw hw;
struct gpio_desc *gpiod;
};
#define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw)
static int clk_gpio_gate_enable(struct clk_hw *hw) static int clk_gpio_gate_enable(struct clk_hw *hw)
{ {
struct clk_gpio *clk = to_clk_gpio(hw); struct clk_gpio *clk = to_clk_gpio(hw);
...@@ -51,12 +71,11 @@ static int clk_gpio_gate_is_enabled(struct clk_hw *hw) ...@@ -51,12 +71,11 @@ static int clk_gpio_gate_is_enabled(struct clk_hw *hw)
return gpiod_get_value(clk->gpiod); return gpiod_get_value(clk->gpiod);
} }
const struct clk_ops clk_gpio_gate_ops = { static const struct clk_ops clk_gpio_gate_ops = {
.enable = clk_gpio_gate_enable, .enable = clk_gpio_gate_enable,
.disable = clk_gpio_gate_disable, .disable = clk_gpio_gate_disable,
.is_enabled = clk_gpio_gate_is_enabled, .is_enabled = clk_gpio_gate_is_enabled,
}; };
EXPORT_SYMBOL_GPL(clk_gpio_gate_ops);
static int clk_sleeping_gpio_gate_prepare(struct clk_hw *hw) static int clk_sleeping_gpio_gate_prepare(struct clk_hw *hw)
{ {
...@@ -111,67 +130,49 @@ static int clk_gpio_mux_set_parent(struct clk_hw *hw, u8 index) ...@@ -111,67 +130,49 @@ static int clk_gpio_mux_set_parent(struct clk_hw *hw, u8 index)
return 0; return 0;
} }
const struct clk_ops clk_gpio_mux_ops = { static const struct clk_ops clk_gpio_mux_ops = {
.get_parent = clk_gpio_mux_get_parent, .get_parent = clk_gpio_mux_get_parent,
.set_parent = clk_gpio_mux_set_parent, .set_parent = clk_gpio_mux_set_parent,
.determine_rate = __clk_mux_determine_rate, .determine_rate = __clk_mux_determine_rate,
}; };
EXPORT_SYMBOL_GPL(clk_gpio_mux_ops);
static struct clk_hw *clk_register_gpio(struct device *dev, const char *name, static struct clk_hw *clk_register_gpio(struct device *dev, u8 num_parents,
const char * const *parent_names, u8 num_parents, struct gpio_desc *gpiod, struct gpio_desc *gpiod,
unsigned long flags, const struct clk_ops *clk_gpio_ops) const struct clk_ops *clk_gpio_ops)
{ {
struct clk_gpio *clk_gpio; struct clk_gpio *clk_gpio;
struct clk_hw *hw; struct clk_hw *hw;
struct clk_init_data init = {}; struct clk_init_data init = {};
int err; int err;
const struct clk_parent_data gpio_parent_data[] = {
{ .index = 0 },
{ .index = 1 },
};
if (dev) clk_gpio = devm_kzalloc(dev, sizeof(*clk_gpio), GFP_KERNEL);
clk_gpio = devm_kzalloc(dev, sizeof(*clk_gpio), GFP_KERNEL);
else
clk_gpio = kzalloc(sizeof(*clk_gpio), GFP_KERNEL);
if (!clk_gpio) if (!clk_gpio)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
init.name = name; init.name = dev->of_node->name;
init.ops = clk_gpio_ops; init.ops = clk_gpio_ops;
init.flags = flags; init.parent_data = gpio_parent_data;
init.parent_names = parent_names;
init.num_parents = num_parents; init.num_parents = num_parents;
init.flags = CLK_SET_RATE_PARENT;
clk_gpio->gpiod = gpiod; clk_gpio->gpiod = gpiod;
clk_gpio->hw.init = &init; clk_gpio->hw.init = &init;
hw = &clk_gpio->hw; hw = &clk_gpio->hw;
if (dev) err = devm_clk_hw_register(dev, hw);
err = devm_clk_hw_register(dev, hw); if (err)
else return ERR_PTR(err);
err = clk_hw_register(NULL, hw);
if (!err)
return hw;
if (!dev) {
kfree(clk_gpio);
}
return ERR_PTR(err); return hw;
} }
/** static struct clk_hw *clk_hw_register_gpio_gate(struct device *dev,
* clk_hw_register_gpio_gate - register a gpio clock gate with the clock int num_parents,
* framework struct gpio_desc *gpiod)
* @dev: device that is registering this clock
* @name: name of this clock
* @parent_name: name of this clock's parent
* @gpiod: gpio descriptor to gate this clock
* @flags: clock flags
*/
struct clk_hw *clk_hw_register_gpio_gate(struct device *dev, const char *name,
const char *parent_name, struct gpio_desc *gpiod,
unsigned long flags)
{ {
const struct clk_ops *ops; const struct clk_ops *ops;
...@@ -180,88 +181,36 @@ struct clk_hw *clk_hw_register_gpio_gate(struct device *dev, const char *name, ...@@ -180,88 +181,36 @@ struct clk_hw *clk_hw_register_gpio_gate(struct device *dev, const char *name,
else else
ops = &clk_gpio_gate_ops; ops = &clk_gpio_gate_ops;
return clk_register_gpio(dev, name, return clk_register_gpio(dev, num_parents, gpiod, ops);
(parent_name ? &parent_name : NULL),
(parent_name ? 1 : 0), gpiod, flags, ops);
} }
EXPORT_SYMBOL_GPL(clk_hw_register_gpio_gate);
struct clk *clk_register_gpio_gate(struct device *dev, const char *name, static struct clk_hw *clk_hw_register_gpio_mux(struct device *dev,
const char *parent_name, struct gpio_desc *gpiod, struct gpio_desc *gpiod)
unsigned long flags)
{ {
struct clk_hw *hw; return clk_register_gpio(dev, 2, gpiod, &clk_gpio_mux_ops);
hw = clk_hw_register_gpio_gate(dev, name, parent_name, gpiod, flags);
if (IS_ERR(hw))
return ERR_CAST(hw);
return hw->clk;
} }
EXPORT_SYMBOL_GPL(clk_register_gpio_gate);
/**
* clk_hw_register_gpio_mux - register a gpio clock mux with the clock framework
* @dev: device that is registering this clock
* @name: name of this clock
* @parent_names: names of this clock's parents
* @num_parents: number of parents listed in @parent_names
* @gpiod: gpio descriptor to gate this clock
* @flags: clock flags
*/
struct clk_hw *clk_hw_register_gpio_mux(struct device *dev, const char *name,
const char * const *parent_names, u8 num_parents, struct gpio_desc *gpiod,
unsigned long flags)
{
if (num_parents != 2) {
pr_err("mux-clock %s must have 2 parents\n", name);
return ERR_PTR(-EINVAL);
}
return clk_register_gpio(dev, name, parent_names, num_parents,
gpiod, flags, &clk_gpio_mux_ops);
}
EXPORT_SYMBOL_GPL(clk_hw_register_gpio_mux);
struct clk *clk_register_gpio_mux(struct device *dev, const char *name,
const char * const *parent_names, u8 num_parents, struct gpio_desc *gpiod,
unsigned long flags)
{
struct clk_hw *hw;
hw = clk_hw_register_gpio_mux(dev, name, parent_names, num_parents,
gpiod, flags);
if (IS_ERR(hw))
return ERR_CAST(hw);
return hw->clk;
}
EXPORT_SYMBOL_GPL(clk_register_gpio_mux);
static int gpio_clk_driver_probe(struct platform_device *pdev) static int gpio_clk_driver_probe(struct platform_device *pdev)
{ {
struct device_node *node = pdev->dev.of_node; struct device *dev = &pdev->dev;
const char **parent_names, *gpio_name; struct device_node *node = dev->of_node;
const char *gpio_name;
unsigned int num_parents; unsigned int num_parents;
struct gpio_desc *gpiod; struct gpio_desc *gpiod;
struct clk *clk; struct clk_hw *hw;
bool is_mux; bool is_mux;
int ret; int ret;
is_mux = of_device_is_compatible(node, "gpio-mux-clock");
num_parents = of_clk_get_parent_count(node); num_parents = of_clk_get_parent_count(node);
if (num_parents) { if (is_mux && num_parents != 2) {
parent_names = devm_kcalloc(&pdev->dev, num_parents, dev_err(dev, "mux-clock must have 2 parents\n");
sizeof(char *), GFP_KERNEL); return -EINVAL;
if (!parent_names)
return -ENOMEM;
of_clk_parent_fill(node, parent_names, num_parents);
} else {
parent_names = NULL;
} }
is_mux = of_device_is_compatible(node, "gpio-mux-clock");
gpio_name = is_mux ? "select" : "enable"; gpio_name = is_mux ? "select" : "enable";
gpiod = devm_gpiod_get(&pdev->dev, gpio_name, GPIOD_OUT_LOW); gpiod = devm_gpiod_get(dev, gpio_name, GPIOD_OUT_LOW);
if (IS_ERR(gpiod)) { if (IS_ERR(gpiod)) {
ret = PTR_ERR(gpiod); ret = PTR_ERR(gpiod);
if (ret == -EPROBE_DEFER) if (ret == -EPROBE_DEFER)
...@@ -275,16 +224,13 @@ static int gpio_clk_driver_probe(struct platform_device *pdev) ...@@ -275,16 +224,13 @@ static int gpio_clk_driver_probe(struct platform_device *pdev)
} }
if (is_mux) if (is_mux)
clk = clk_register_gpio_mux(&pdev->dev, node->name, hw = clk_hw_register_gpio_mux(dev, gpiod);
parent_names, num_parents, gpiod, 0);
else else
clk = clk_register_gpio_gate(&pdev->dev, node->name, hw = clk_hw_register_gpio_gate(dev, num_parents, gpiod);
parent_names ? parent_names[0] : NULL, gpiod, if (IS_ERR(hw))
CLK_SET_RATE_PARENT); return PTR_ERR(hw);
if (IS_ERR(clk))
return PTR_ERR(clk);
return of_clk_add_provider(node, of_clk_src_simple_get, clk); return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
} }
static const struct of_device_id gpio_clk_match_table[] = { static const struct of_device_id gpio_clk_match_table[] = {
......
...@@ -145,17 +145,19 @@ const struct clk_ops clk_mux_ro_ops = { ...@@ -145,17 +145,19 @@ const struct clk_ops clk_mux_ro_ops = {
}; };
EXPORT_SYMBOL_GPL(clk_mux_ro_ops); EXPORT_SYMBOL_GPL(clk_mux_ro_ops);
struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name, struct clk_hw *__clk_hw_register_mux(struct device *dev, struct device_node *np,
const char * const *parent_names, u8 num_parents, const char *name, u8 num_parents,
unsigned long flags, const char * const *parent_names,
void __iomem *reg, u8 shift, u32 mask, const struct clk_hw **parent_hws,
const struct clk_parent_data *parent_data,
unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
u8 clk_mux_flags, u32 *table, spinlock_t *lock) u8 clk_mux_flags, u32 *table, spinlock_t *lock)
{ {
struct clk_mux *mux; struct clk_mux *mux;
struct clk_hw *hw; struct clk_hw *hw;
struct clk_init_data init = {}; struct clk_init_data init = {};
u8 width = 0; u8 width = 0;
int ret; int ret = -EINVAL;
if (clk_mux_flags & CLK_MUX_HIWORD_MASK) { if (clk_mux_flags & CLK_MUX_HIWORD_MASK) {
width = fls(mask) - ffs(mask) + 1; width = fls(mask) - ffs(mask) + 1;
...@@ -177,6 +179,8 @@ struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name, ...@@ -177,6 +179,8 @@ struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name,
init.ops = &clk_mux_ops; init.ops = &clk_mux_ops;
init.flags = flags; init.flags = flags;
init.parent_names = parent_names; init.parent_names = parent_names;
init.parent_data = parent_data;
init.parent_hws = parent_hws;
init.num_parents = num_parents; init.num_parents = num_parents;
/* struct clk_mux assignments */ /* struct clk_mux assignments */
...@@ -189,7 +193,10 @@ struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name, ...@@ -189,7 +193,10 @@ struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name,
mux->hw.init = &init; mux->hw.init = &init;
hw = &mux->hw; hw = &mux->hw;
ret = clk_hw_register(dev, hw); if (dev || !np)
ret = clk_hw_register(dev, hw);
else if (np)
ret = of_clk_hw_register(np, hw);
if (ret) { if (ret) {
kfree(mux); kfree(mux);
hw = ERR_PTR(ret); hw = ERR_PTR(ret);
...@@ -197,53 +204,24 @@ struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name, ...@@ -197,53 +204,24 @@ struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name,
return hw; return hw;
} }
EXPORT_SYMBOL_GPL(clk_hw_register_mux_table); EXPORT_SYMBOL_GPL(__clk_hw_register_mux);
struct clk *clk_register_mux_table(struct device *dev, const char *name, struct clk *clk_register_mux_table(struct device *dev, const char *name,
const char * const *parent_names, u8 num_parents, const char * const *parent_names, u8 num_parents,
unsigned long flags, unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
void __iomem *reg, u8 shift, u32 mask,
u8 clk_mux_flags, u32 *table, spinlock_t *lock) u8 clk_mux_flags, u32 *table, spinlock_t *lock)
{ {
struct clk_hw *hw; struct clk_hw *hw;
hw = clk_hw_register_mux_table(dev, name, parent_names, num_parents, hw = clk_hw_register_mux_table(dev, name, parent_names,
flags, reg, shift, mask, clk_mux_flags, num_parents, flags, reg, shift, mask,
table, lock); clk_mux_flags, table, lock);
if (IS_ERR(hw)) if (IS_ERR(hw))
return ERR_CAST(hw); return ERR_CAST(hw);
return hw->clk; return hw->clk;
} }
EXPORT_SYMBOL_GPL(clk_register_mux_table); EXPORT_SYMBOL_GPL(clk_register_mux_table);
struct clk *clk_register_mux(struct device *dev, const char *name,
const char * const *parent_names, u8 num_parents,
unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_mux_flags, spinlock_t *lock)
{
u32 mask = BIT(width) - 1;
return clk_register_mux_table(dev, name, parent_names, num_parents,
flags, reg, shift, mask, clk_mux_flags,
NULL, lock);
}
EXPORT_SYMBOL_GPL(clk_register_mux);
struct clk_hw *clk_hw_register_mux(struct device *dev, const char *name,
const char * const *parent_names, u8 num_parents,
unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_mux_flags, spinlock_t *lock)
{
u32 mask = BIT(width) - 1;
return clk_hw_register_mux_table(dev, name, parent_names, num_parents,
flags, reg, shift, mask, clk_mux_flags,
NULL, lock);
}
EXPORT_SYMBOL_GPL(clk_hw_register_mux);
void clk_unregister_mux(struct clk *clk) void clk_unregister_mux(struct clk *clk)
{ {
struct clk_mux *mux; struct clk_mux *mux;
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2019 NXP
*
* Clock driver for LS1028A Display output interfaces(LCD, DPHY).
*/
#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/bitfield.h>
/* PLLDIG register offsets and bit masks */
#define PLLDIG_REG_PLLSR 0x24
#define PLLDIG_LOCK_MASK BIT(2)
#define PLLDIG_REG_PLLDV 0x28
#define PLLDIG_MFD_MASK GENMASK(7, 0)
#define PLLDIG_RFDPHI1_MASK GENMASK(30, 25)
#define PLLDIG_REG_PLLFM 0x2c
#define PLLDIG_SSCGBYP_ENABLE BIT(30)
#define PLLDIG_REG_PLLFD 0x30
#define PLLDIG_FDEN BIT(30)
#define PLLDIG_FRAC_MASK GENMASK(15, 0)
#define PLLDIG_REG_PLLCAL1 0x38
#define PLLDIG_REG_PLLCAL2 0x3c
/* Range of the VCO frequencies, in Hz */
#define PLLDIG_MIN_VCO_FREQ 650000000
#define PLLDIG_MAX_VCO_FREQ 1300000000
/* Range of the output frequencies, in Hz */
#define PHI1_MIN_FREQ 27000000UL
#define PHI1_MAX_FREQ 600000000UL
/* Maximum value of the reduced frequency divider */
#define MAX_RFDPHI1 63UL
/* Best value of multiplication factor divider */
#define PLLDIG_DEFAULT_MFD 44
/*
* Denominator part of the fractional part of the
* loop multiplication factor.
*/
#define MFDEN 20480
static const struct clk_parent_data parent_data[] = {
{ .index = 0 },
};
struct clk_plldig {
struct clk_hw hw;
void __iomem *regs;
unsigned int vco_freq;
};
#define to_clk_plldig(_hw) container_of(_hw, struct clk_plldig, hw)
static int plldig_enable(struct clk_hw *hw)
{
struct clk_plldig *data = to_clk_plldig(hw);
u32 val;
val = readl(data->regs + PLLDIG_REG_PLLFM);
/*
* Use Bypass mode with PLL off by default, the frequency overshoot
* detector output was disable. SSCG Bypass mode should be enable.
*/
val |= PLLDIG_SSCGBYP_ENABLE;
writel(val, data->regs + PLLDIG_REG_PLLFM);
return 0;
}
static void plldig_disable(struct clk_hw *hw)
{
struct clk_plldig *data = to_clk_plldig(hw);
u32 val;
val = readl(data->regs + PLLDIG_REG_PLLFM);
val &= ~PLLDIG_SSCGBYP_ENABLE;
val |= FIELD_PREP(PLLDIG_SSCGBYP_ENABLE, 0x0);
writel(val, data->regs + PLLDIG_REG_PLLFM);
}
static int plldig_is_enabled(struct clk_hw *hw)
{
struct clk_plldig *data = to_clk_plldig(hw);
return readl(data->regs + PLLDIG_REG_PLLFM) &
PLLDIG_SSCGBYP_ENABLE;
}
static unsigned long plldig_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_plldig *data = to_clk_plldig(hw);
u32 val, rfdphi1;
val = readl(data->regs + PLLDIG_REG_PLLDV);
/* Check if PLL is bypassed */
if (val & PLLDIG_SSCGBYP_ENABLE)
return parent_rate;
rfdphi1 = FIELD_GET(PLLDIG_RFDPHI1_MASK, val);
/*
* If RFDPHI1 has a value of 1 the VCO frequency is also divided by
* one.
*/
if (!rfdphi1)
rfdphi1 = 1;
return DIV_ROUND_UP(data->vco_freq, rfdphi1);
}
static unsigned long plldig_calc_target_div(unsigned long vco_freq,
unsigned long target_rate)
{
unsigned long div;
div = DIV_ROUND_CLOSEST(vco_freq, target_rate);
div = clamp(div, 1UL, MAX_RFDPHI1);
return div;
}
static int plldig_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct clk_plldig *data = to_clk_plldig(hw);
unsigned int div;
req->rate = clamp(req->rate, PHI1_MIN_FREQ, PHI1_MAX_FREQ);
div = plldig_calc_target_div(data->vco_freq, req->rate);
req->rate = DIV_ROUND_UP(data->vco_freq, div);
return 0;
}
static int plldig_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_plldig *data = to_clk_plldig(hw);
unsigned int val, cond;
unsigned int rfdphi1;
rate = clamp(rate, PHI1_MIN_FREQ, PHI1_MAX_FREQ);
rfdphi1 = plldig_calc_target_div(data->vco_freq, rate);
/* update the divider value */
val = readl(data->regs + PLLDIG_REG_PLLDV);
val &= ~PLLDIG_RFDPHI1_MASK;
val |= FIELD_PREP(PLLDIG_RFDPHI1_MASK, rfdphi1);
writel(val, data->regs + PLLDIG_REG_PLLDV);
/* waiting for old lock state to clear */
udelay(200);
/* Wait until PLL is locked or timeout */
return readl_poll_timeout_atomic(data->regs + PLLDIG_REG_PLLSR, cond,
cond & PLLDIG_LOCK_MASK, 0,
USEC_PER_MSEC);
}
static const struct clk_ops plldig_clk_ops = {
.enable = plldig_enable,
.disable = plldig_disable,
.is_enabled = plldig_is_enabled,
.recalc_rate = plldig_recalc_rate,
.determine_rate = plldig_determine_rate,
.set_rate = plldig_set_rate,
};
static int plldig_init(struct clk_hw *hw)
{
struct clk_plldig *data = to_clk_plldig(hw);
struct clk_hw *parent = clk_hw_get_parent(hw);
unsigned long parent_rate = clk_hw_get_rate(parent);
unsigned long val;
unsigned long long lltmp;
unsigned int mfd, fracdiv = 0;
if (!parent)
return -EINVAL;
if (data->vco_freq) {
mfd = data->vco_freq / parent_rate;
lltmp = data->vco_freq % parent_rate;
lltmp *= MFDEN;
do_div(lltmp, parent_rate);
fracdiv = lltmp;
} else {
mfd = PLLDIG_DEFAULT_MFD;
data->vco_freq = parent_rate * mfd;
}
val = FIELD_PREP(PLLDIG_MFD_MASK, mfd);
writel(val, data->regs + PLLDIG_REG_PLLDV);
/* Enable fractional divider */
if (fracdiv) {
val = FIELD_PREP(PLLDIG_FRAC_MASK, fracdiv);
val |= PLLDIG_FDEN;
writel(val, data->regs + PLLDIG_REG_PLLFD);
}
return 0;
}
static int plldig_clk_probe(struct platform_device *pdev)
{
struct clk_plldig *data;
struct device *dev = &pdev->dev;
int ret;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(data->regs))
return PTR_ERR(data->regs);
data->hw.init = CLK_HW_INIT_PARENTS_DATA("dpclk",
parent_data,
&plldig_clk_ops,
0);
ret = devm_clk_hw_register(dev, &data->hw);
if (ret) {
dev_err(dev, "failed to register %s clock\n",
dev->of_node->name);
return ret;
}
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
&data->hw);
if (ret) {
dev_err(dev, "unable to add clk provider\n");
return ret;
}
/*
* The frequency of the VCO cannot be changed during runtime.
* Therefore, let the user specify a desired frequency.
*/
if (!of_property_read_u32(dev->of_node, "fsl,vco-hz",
&data->vco_freq)) {
if (data->vco_freq < PLLDIG_MIN_VCO_FREQ ||
data->vco_freq > PLLDIG_MAX_VCO_FREQ)
return -EINVAL;
}
return plldig_init(&data->hw);
}
static const struct of_device_id plldig_clk_id[] = {
{ .compatible = "fsl,ls1028a-plldig" },
{ }
};
MODULE_DEVICE_TABLE(of, plldig_clk_id);
static struct platform_driver plldig_clk_driver = {
.driver = {
.name = "plldig-clock",
.of_match_table = plldig_clk_id,
},
.probe = plldig_clk_probe,
};
module_platform_driver(plldig_clk_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Wen He <wen.he_1@nxp.com>");
MODULE_DESCRIPTION("LS1028A Display output interface pixel clock driver");
...@@ -342,6 +342,32 @@ static const struct clockgen_muxinfo ls1046a_hwa2 = { ...@@ -342,6 +342,32 @@ static const struct clockgen_muxinfo ls1046a_hwa2 = {
}, },
}; };
static const struct clockgen_muxinfo ls1088a_hwa1 = {
{
{},
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV3 },
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV4 },
{},
{ CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
{ CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
},
};
static const struct clockgen_muxinfo ls1088a_hwa2 = {
{
{},
{ CLKSEL_VALID, CGA_PLL2, PLL_DIV1 },
{ CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
{ CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
{ CLKSEL_VALID, CGA_PLL2, PLL_DIV4 },
{},
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV3 },
},
};
static const struct clockgen_muxinfo ls1012a_cmux = { static const struct clockgen_muxinfo ls1012a_cmux = {
{ {
[0] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 }, [0] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
...@@ -607,6 +633,9 @@ static const struct clockgen_chipinfo chipinfo[] = { ...@@ -607,6 +633,9 @@ static const struct clockgen_chipinfo chipinfo[] = {
.cmux_groups = { .cmux_groups = {
&clockgen2_cmux_cga12 &clockgen2_cmux_cga12
}, },
.hwaccel = {
&ls1088a_hwa1, &ls1088a_hwa2
},
.cmux_to_group = { .cmux_to_group = {
0, 0, -1 0, 0, -1
}, },
......
...@@ -2996,6 +2996,41 @@ static int clk_dump_show(struct seq_file *s, void *data) ...@@ -2996,6 +2996,41 @@ static int clk_dump_show(struct seq_file *s, void *data)
} }
DEFINE_SHOW_ATTRIBUTE(clk_dump); DEFINE_SHOW_ATTRIBUTE(clk_dump);
#undef CLOCK_ALLOW_WRITE_DEBUGFS
#ifdef CLOCK_ALLOW_WRITE_DEBUGFS
/*
* This can be dangerous, therefore don't provide any real compile time
* configuration option for this feature.
* People who want to use this will need to modify the source code directly.
*/
static int clk_rate_set(void *data, u64 val)
{
struct clk_core *core = data;
int ret;
clk_prepare_lock();
ret = clk_core_set_rate_nolock(core, val);
clk_prepare_unlock();
return ret;
}
#define clk_rate_mode 0644
#else
#define clk_rate_set NULL
#define clk_rate_mode 0444
#endif
static int clk_rate_get(void *data, u64 *val)
{
struct clk_core *core = data;
*val = core->rate;
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(clk_rate_fops, clk_rate_get, clk_rate_set, "%llu\n");
static const struct { static const struct {
unsigned long flag; unsigned long flag;
const char *name; const char *name;
...@@ -3145,7 +3180,8 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) ...@@ -3145,7 +3180,8 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
root = debugfs_create_dir(core->name, pdentry); root = debugfs_create_dir(core->name, pdentry);
core->dentry = root; core->dentry = root;
debugfs_create_ulong("clk_rate", 0444, root, &core->rate); debugfs_create_file("clk_rate", clk_rate_mode, root, core,
&clk_rate_fops);
debugfs_create_file("clk_min_rate", 0444, root, core, &clk_min_rate_fops); debugfs_create_file("clk_min_rate", 0444, root, core, &clk_min_rate_fops);
debugfs_create_file("clk_max_rate", 0444, root, core, &clk_max_rate_fops); debugfs_create_file("clk_max_rate", 0444, root, core, &clk_max_rate_fops);
debugfs_create_ulong("clk_accuracy", 0444, root, &core->accuracy); debugfs_create_ulong("clk_accuracy", 0444, root, &core->accuracy);
...@@ -3338,6 +3374,26 @@ static int __clk_core_init(struct clk_core *core) ...@@ -3338,6 +3374,26 @@ static int __clk_core_init(struct clk_core *core)
goto out; goto out;
} }
/*
* optional platform-specific magic
*
* The .init callback is not used by any of the basic clock types, but
* exists for weird hardware that must perform initialization magic for
* CCF to get an accurate view of clock for any other callbacks. It may
* also be used needs to perform dynamic allocations. Such allocation
* must be freed in the terminate() callback.
* This callback shall not be used to initialize the parameters state,
* such as rate, parent, etc ...
*
* If it exist, this callback should called before any other callback of
* the clock
*/
if (core->ops->init) {
ret = core->ops->init(core->hw);
if (ret)
goto out;
}
core->parent = __clk_init_parent(core); core->parent = __clk_init_parent(core);
/* /*
...@@ -3362,17 +3418,6 @@ static int __clk_core_init(struct clk_core *core) ...@@ -3362,17 +3418,6 @@ static int __clk_core_init(struct clk_core *core)
core->orphan = true; core->orphan = true;
} }
/*
* optional platform-specific magic
*
* The .init callback is not used by any of the basic clock types, but
* exists for weird hardware that must perform initialization magic.
* Please consider other ways of solving initialization problems before
* using this callback, as its use is discouraged.
*/
if (core->ops->init)
core->ops->init(core->hw);
/* /*
* Set clk's accuracy. The preferred method is to use * Set clk's accuracy. The preferred method is to use
* .recalc_accuracy. For simple clocks and lazy developers the default * .recalc_accuracy. For simple clocks and lazy developers the default
...@@ -3427,13 +3472,18 @@ static int __clk_core_init(struct clk_core *core) ...@@ -3427,13 +3472,18 @@ static int __clk_core_init(struct clk_core *core)
unsigned long flags; unsigned long flags;
ret = clk_core_prepare(core); ret = clk_core_prepare(core);
if (ret) if (ret) {
pr_warn("%s: critical clk '%s' failed to prepare\n",
__func__, core->name);
goto out; goto out;
}
flags = clk_enable_lock(); flags = clk_enable_lock();
ret = clk_core_enable(core); ret = clk_core_enable(core);
clk_enable_unlock(flags); clk_enable_unlock(flags);
if (ret) { if (ret) {
pr_warn("%s: critical clk '%s' failed to enable\n",
__func__, core->name);
clk_core_unprepare(core); clk_core_unprepare(core);
goto out; goto out;
} }
...@@ -3732,6 +3782,28 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw) ...@@ -3732,6 +3782,28 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw)
return ERR_PTR(ret); return ERR_PTR(ret);
} }
/**
* dev_or_parent_of_node() - Get device node of @dev or @dev's parent
* @dev: Device to get device node of
*
* Return: device node pointer of @dev, or the device node pointer of
* @dev->parent if dev doesn't have a device node, or NULL if neither
* @dev or @dev->parent have a device node.
*/
static struct device_node *dev_or_parent_of_node(struct device *dev)
{
struct device_node *np;
if (!dev)
return NULL;
np = dev_of_node(dev);
if (!np)
np = dev_of_node(dev->parent);
return np;
}
/** /**
* clk_register - allocate a new clock, register it and return an opaque cookie * clk_register - allocate a new clock, register it and return an opaque cookie
* @dev: device that is registering this clock * @dev: device that is registering this clock
...@@ -3747,7 +3819,7 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw) ...@@ -3747,7 +3819,7 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw)
*/ */
struct clk *clk_register(struct device *dev, struct clk_hw *hw) struct clk *clk_register(struct device *dev, struct clk_hw *hw)
{ {
return __clk_register(dev, dev_of_node(dev), hw); return __clk_register(dev, dev_or_parent_of_node(dev), hw);
} }
EXPORT_SYMBOL_GPL(clk_register); EXPORT_SYMBOL_GPL(clk_register);
...@@ -3763,7 +3835,8 @@ EXPORT_SYMBOL_GPL(clk_register); ...@@ -3763,7 +3835,8 @@ EXPORT_SYMBOL_GPL(clk_register);
*/ */
int clk_hw_register(struct device *dev, struct clk_hw *hw) int clk_hw_register(struct device *dev, struct clk_hw *hw)
{ {
return PTR_ERR_OR_ZERO(__clk_register(dev, dev_of_node(dev), hw)); return PTR_ERR_OR_ZERO(__clk_register(dev, dev_or_parent_of_node(dev),
hw));
} }
EXPORT_SYMBOL_GPL(clk_hw_register); EXPORT_SYMBOL_GPL(clk_hw_register);
...@@ -3866,6 +3939,7 @@ static void clk_core_evict_parent_cache(struct clk_core *core) ...@@ -3866,6 +3939,7 @@ static void clk_core_evict_parent_cache(struct clk_core *core)
void clk_unregister(struct clk *clk) void clk_unregister(struct clk *clk)
{ {
unsigned long flags; unsigned long flags;
const struct clk_ops *ops;
if (!clk || WARN_ON_ONCE(IS_ERR(clk))) if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
return; return;
...@@ -3874,7 +3948,8 @@ void clk_unregister(struct clk *clk) ...@@ -3874,7 +3948,8 @@ void clk_unregister(struct clk *clk)
clk_prepare_lock(); clk_prepare_lock();
if (clk->core->ops == &clk_nodrv_ops) { ops = clk->core->ops;
if (ops == &clk_nodrv_ops) {
pr_err("%s: unregistered clock: %s\n", __func__, pr_err("%s: unregistered clock: %s\n", __func__,
clk->core->name); clk->core->name);
goto unlock; goto unlock;
...@@ -3887,6 +3962,9 @@ void clk_unregister(struct clk *clk) ...@@ -3887,6 +3962,9 @@ void clk_unregister(struct clk *clk)
clk->core->ops = &clk_nodrv_ops; clk->core->ops = &clk_nodrv_ops;
clk_enable_unlock(flags); clk_enable_unlock(flags);
if (ops->terminate)
ops->terminate(clk->core->hw);
if (!hlist_empty(&clk->core->children)) { if (!hlist_empty(&clk->core->children)) {
struct clk_core *child; struct clk_core *child;
struct hlist_node *t; struct hlist_node *t;
......
...@@ -20,6 +20,12 @@ config CLK_IMX8MN ...@@ -20,6 +20,12 @@ config CLK_IMX8MN
help help
Build the driver for i.MX8MN CCM Clock Driver Build the driver for i.MX8MN CCM Clock Driver
config CLK_IMX8MP
bool "IMX8MP CCM Clock Driver"
depends on ARCH_MXC && ARM64
help
Build the driver for i.MX8MP CCM Clock Driver
config CLK_IMX8MQ config CLK_IMX8MQ
bool "IMX8MQ CCM Clock Driver" bool "IMX8MQ CCM Clock Driver"
depends on ARCH_MXC && ARM64 depends on ARCH_MXC && ARM64
......
...@@ -18,7 +18,7 @@ obj-$(CONFIG_MXC_CLK) += \ ...@@ -18,7 +18,7 @@ obj-$(CONFIG_MXC_CLK) += \
clk-pllv2.o \ clk-pllv2.o \
clk-pllv3.o \ clk-pllv3.o \
clk-pllv4.o \ clk-pllv4.o \
clk-sccg-pll.o \ clk-sscg-pll.o \
clk-pll14xx.o clk-pll14xx.o
obj-$(CONFIG_MXC_CLK_SCU) += \ obj-$(CONFIG_MXC_CLK_SCU) += \
...@@ -27,6 +27,7 @@ obj-$(CONFIG_MXC_CLK_SCU) += \ ...@@ -27,6 +27,7 @@ obj-$(CONFIG_MXC_CLK_SCU) += \
obj-$(CONFIG_CLK_IMX8MM) += clk-imx8mm.o obj-$(CONFIG_CLK_IMX8MM) += clk-imx8mm.o
obj-$(CONFIG_CLK_IMX8MN) += clk-imx8mn.o obj-$(CONFIG_CLK_IMX8MN) += clk-imx8mn.o
obj-$(CONFIG_CLK_IMX8MP) += clk-imx8mp.o
obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o
obj-$(CONFIG_CLK_IMX8QXP) += clk-imx8qxp.o clk-imx8qxp-lpcg.o obj-$(CONFIG_CLK_IMX8QXP) += clk-imx8qxp.o clk-imx8qxp-lpcg.o
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#define PCG_PCD_WIDTH 3 #define PCG_PCD_WIDTH 3
#define PCG_PCD_MASK 0x7 #define PCG_PCD_MASK 0x7
struct clk_hw *imx7ulp_clk_composite(const char *name, struct clk_hw *imx7ulp_clk_hw_composite(const char *name,
const char * const *parent_names, const char * const *parent_names,
int num_parents, bool mux_present, int num_parents, bool mux_present,
bool rate_present, bool gate_present, bool rate_present, bool gate_present,
......
...@@ -123,7 +123,7 @@ static const struct clk_ops imx8m_clk_composite_divider_ops = { ...@@ -123,7 +123,7 @@ static const struct clk_ops imx8m_clk_composite_divider_ops = {
.set_rate = imx8m_clk_composite_divider_set_rate, .set_rate = imx8m_clk_composite_divider_set_rate,
}; };
struct clk *imx8m_clk_composite_flags(const char *name, struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
const char * const *parent_names, const char * const *parent_names,
int num_parents, void __iomem *reg, int num_parents, void __iomem *reg,
unsigned long flags) unsigned long flags)
...@@ -171,7 +171,7 @@ struct clk *imx8m_clk_composite_flags(const char *name, ...@@ -171,7 +171,7 @@ struct clk *imx8m_clk_composite_flags(const char *name,
if (IS_ERR(hw)) if (IS_ERR(hw))
goto fail; goto fail;
return hw->clk; return hw;
fail: fail:
kfree(gate); kfree(gate);
......
...@@ -43,7 +43,7 @@ static unsigned long clk_divider_gate_recalc_rate(struct clk_hw *hw, ...@@ -43,7 +43,7 @@ static unsigned long clk_divider_gate_recalc_rate(struct clk_hw *hw,
{ {
struct clk_divider_gate *div_gate = to_clk_divider_gate(hw); struct clk_divider_gate *div_gate = to_clk_divider_gate(hw);
struct clk_divider *div = to_clk_divider(hw); struct clk_divider *div = to_clk_divider(hw);
unsigned long flags = 0; unsigned long flags;
unsigned int val; unsigned int val;
spin_lock_irqsave(div->lock, flags); spin_lock_irqsave(div->lock, flags);
...@@ -75,7 +75,7 @@ static int clk_divider_gate_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -75,7 +75,7 @@ static int clk_divider_gate_set_rate(struct clk_hw *hw, unsigned long rate,
{ {
struct clk_divider_gate *div_gate = to_clk_divider_gate(hw); struct clk_divider_gate *div_gate = to_clk_divider_gate(hw);
struct clk_divider *div = to_clk_divider(hw); struct clk_divider *div = to_clk_divider(hw);
unsigned long flags = 0; unsigned long flags;
int value; int value;
u32 val; u32 val;
...@@ -104,7 +104,7 @@ static int clk_divider_enable(struct clk_hw *hw) ...@@ -104,7 +104,7 @@ static int clk_divider_enable(struct clk_hw *hw)
{ {
struct clk_divider_gate *div_gate = to_clk_divider_gate(hw); struct clk_divider_gate *div_gate = to_clk_divider_gate(hw);
struct clk_divider *div = to_clk_divider(hw); struct clk_divider *div = to_clk_divider(hw);
unsigned long flags = 0; unsigned long flags;
u32 val; u32 val;
if (!div_gate->cached_val) { if (!div_gate->cached_val) {
...@@ -127,7 +127,7 @@ static void clk_divider_disable(struct clk_hw *hw) ...@@ -127,7 +127,7 @@ static void clk_divider_disable(struct clk_hw *hw)
{ {
struct clk_divider_gate *div_gate = to_clk_divider_gate(hw); struct clk_divider_gate *div_gate = to_clk_divider_gate(hw);
struct clk_divider *div = to_clk_divider(hw); struct clk_divider *div = to_clk_divider(hw);
unsigned long flags = 0; unsigned long flags;
u32 val; u32 val;
spin_lock_irqsave(div->lock, flags); spin_lock_irqsave(div->lock, flags);
...@@ -167,13 +167,13 @@ static const struct clk_ops clk_divider_gate_ops = { ...@@ -167,13 +167,13 @@ static const struct clk_ops clk_divider_gate_ops = {
}; };
/* /*
* NOTE: In order to resue the most code from the common divider, * NOTE: In order to reuse the most code from the common divider,
* we also design our divider following the way that provids an extra * we also design our divider following the way that provids an extra
* clk_divider_flags, however it's fixed to CLK_DIVIDER_ONE_BASED by * clk_divider_flags, however it's fixed to CLK_DIVIDER_ONE_BASED by
* default as our HW is. Besides that it supports only CLK_DIVIDER_READ_ONLY * default as our HW is. Besides that it supports only CLK_DIVIDER_READ_ONLY
* flag which can be specified by user flexibly. * flag which can be specified by user flexibly.
*/ */
struct clk_hw *imx_clk_divider_gate(const char *name, const char *parent_name, struct clk_hw *imx_clk_hw_divider_gate(const char *name, const char *parent_name,
unsigned long flags, void __iomem *reg, unsigned long flags, void __iomem *reg,
u8 shift, u8 width, u8 clk_divider_flags, u8 shift, u8 width, u8 clk_divider_flags,
const struct clk_div_table *table, const struct clk_div_table *table,
......
...@@ -201,8 +201,9 @@ static const struct clk_ops clk_frac_pll_ops = { ...@@ -201,8 +201,9 @@ static const struct clk_ops clk_frac_pll_ops = {
.set_rate = clk_pll_set_rate, .set_rate = clk_pll_set_rate,
}; };
struct clk *imx_clk_frac_pll(const char *name, const char *parent_name, struct clk_hw *imx_clk_hw_frac_pll(const char *name,
void __iomem *base) const char *parent_name,
void __iomem *base)
{ {
struct clk_init_data init; struct clk_init_data init;
struct clk_frac_pll *pll; struct clk_frac_pll *pll;
...@@ -230,5 +231,5 @@ struct clk *imx_clk_frac_pll(const char *name, const char *parent_name, ...@@ -230,5 +231,5 @@ struct clk *imx_clk_frac_pll(const char *name, const char *parent_name,
return ERR_PTR(ret); return ERR_PTR(ret);
} }
return hw->clk; return hw;
} }
...@@ -598,7 +598,10 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) ...@@ -598,7 +598,10 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
} }
hws[IMX6QDL_CLK_PLL4_POST_DIV] = clk_hw_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock); hws[IMX6QDL_CLK_PLL4_POST_DIV] = clk_hw_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
hws[IMX6QDL_CLK_PLL4_AUDIO_DIV] = clk_hw_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock); if (clk_on_imx6q() || clk_on_imx6qp())
hws[IMX6QDL_CLK_PLL4_AUDIO_DIV] = imx_clk_hw_fixed_factor("pll4_audio_div", "pll4_post_div", 1, 1);
else
hws[IMX6QDL_CLK_PLL4_AUDIO_DIV] = clk_hw_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
hws[IMX6QDL_CLK_PLL5_POST_DIV] = clk_hw_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock); hws[IMX6QDL_CLK_PLL5_POST_DIV] = clk_hw_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
hws[IMX6QDL_CLK_PLL5_VIDEO_DIV] = clk_hw_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock); hws[IMX6QDL_CLK_PLL5_VIDEO_DIV] = clk_hw_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -173,6 +173,17 @@ static int imx8qxp_lpcg_clk_probe(struct platform_device *pdev) ...@@ -173,6 +173,17 @@ static int imx8qxp_lpcg_clk_probe(struct platform_device *pdev)
if (!ss_lpcg) if (!ss_lpcg)
return -ENODEV; return -ENODEV;
/*
* Please don't replace this with devm_platform_ioremap_resource.
*
* devm_platform_ioremap_resource calls devm_ioremap_resource which
* differs from devm_ioremap by also calling devm_request_mem_region
* and preventing other mappings in the same area.
*
* On imx8 the LPCG nodes map entire subsystems and overlap
* peripherals, this means that using devm_platform_ioremap_resource
* will cause many devices to fail to probe including serial ports.
*/
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) if (!res)
return -EINVAL; return -EINVAL;
......
...@@ -166,7 +166,7 @@ static const struct clk_ops clk_pfdv2_ops = { ...@@ -166,7 +166,7 @@ static const struct clk_ops clk_pfdv2_ops = {
.is_enabled = clk_pfdv2_is_enabled, .is_enabled = clk_pfdv2_is_enabled,
}; };
struct clk_hw *imx_clk_pfdv2(const char *name, const char *parent_name, struct clk_hw *imx_clk_hw_pfdv2(const char *name, const char *parent_name,
void __iomem *reg, u8 idx) void __iomem *reg, u8 idx)
{ {
struct clk_init_data init; struct clk_init_data init;
......
...@@ -67,6 +67,13 @@ struct imx_pll14xx_clk imx_1443x_pll = { ...@@ -67,6 +67,13 @@ struct imx_pll14xx_clk imx_1443x_pll = {
.rate_count = ARRAY_SIZE(imx_pll1443x_tbl), .rate_count = ARRAY_SIZE(imx_pll1443x_tbl),
}; };
struct imx_pll14xx_clk imx_1443x_dram_pll = {
.type = PLL_1443X,
.rate_table = imx_pll1443x_tbl,
.rate_count = ARRAY_SIZE(imx_pll1443x_tbl),
.flags = CLK_GET_RATE_NOCACHE,
};
struct imx_pll14xx_clk imx_1416x_pll = { struct imx_pll14xx_clk imx_1416x_pll = {
.type = PLL_1416X, .type = PLL_1416X,
.rate_table = imx_pll1416x_tbl, .rate_table = imx_pll1416x_tbl,
...@@ -369,13 +376,14 @@ static const struct clk_ops clk_pll1443x_ops = { ...@@ -369,13 +376,14 @@ static const struct clk_ops clk_pll1443x_ops = {
.set_rate = clk_pll1443x_set_rate, .set_rate = clk_pll1443x_set_rate,
}; };
struct clk *imx_clk_pll14xx(const char *name, const char *parent_name, struct clk_hw *imx_clk_hw_pll14xx(const char *name, const char *parent_name,
void __iomem *base, void __iomem *base,
const struct imx_pll14xx_clk *pll_clk) const struct imx_pll14xx_clk *pll_clk)
{ {
struct clk_pll14xx *pll; struct clk_pll14xx *pll;
struct clk *clk; struct clk_hw *hw;
struct clk_init_data init; struct clk_init_data init;
int ret;
u32 val; u32 val;
pll = kzalloc(sizeof(*pll), GFP_KERNEL); pll = kzalloc(sizeof(*pll), GFP_KERNEL);
...@@ -412,12 +420,15 @@ struct clk *imx_clk_pll14xx(const char *name, const char *parent_name, ...@@ -412,12 +420,15 @@ struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
val &= ~BYPASS_MASK; val &= ~BYPASS_MASK;
writel_relaxed(val, pll->base + GNRL_CTL); writel_relaxed(val, pll->base + GNRL_CTL);
clk = clk_register(NULL, &pll->hw); hw = &pll->hw;
if (IS_ERR(clk)) {
pr_err("%s: failed to register pll %s %lu\n", ret = clk_hw_register(NULL, hw);
__func__, name, PTR_ERR(clk)); if (ret) {
pr_err("%s: failed to register pll %s %d\n",
__func__, name, ret);
kfree(pll); kfree(pll);
return ERR_PTR(ret);
} }
return clk; return hw;
} }
...@@ -111,12 +111,13 @@ static const struct clk_ops clk_pllv1_ops = { ...@@ -111,12 +111,13 @@ static const struct clk_ops clk_pllv1_ops = {
.recalc_rate = clk_pllv1_recalc_rate, .recalc_rate = clk_pllv1_recalc_rate,
}; };
struct clk *imx_clk_pllv1(enum imx_pllv1_type type, const char *name, struct clk_hw *imx_clk_hw_pllv1(enum imx_pllv1_type type, const char *name,
const char *parent, void __iomem *base) const char *parent, void __iomem *base)
{ {
struct clk_pllv1 *pll; struct clk_pllv1 *pll;
struct clk *clk; struct clk_hw *hw;
struct clk_init_data init; struct clk_init_data init;
int ret;
pll = kmalloc(sizeof(*pll), GFP_KERNEL); pll = kmalloc(sizeof(*pll), GFP_KERNEL);
if (!pll) if (!pll)
...@@ -132,10 +133,13 @@ struct clk *imx_clk_pllv1(enum imx_pllv1_type type, const char *name, ...@@ -132,10 +133,13 @@ struct clk *imx_clk_pllv1(enum imx_pllv1_type type, const char *name,
init.num_parents = 1; init.num_parents = 1;
pll->hw.init = &init; pll->hw.init = &init;
hw = &pll->hw;
clk = clk_register(NULL, &pll->hw); ret = clk_hw_register(NULL, hw);
if (IS_ERR(clk)) if (ret) {
kfree(pll); kfree(pll);
return ERR_PTR(ret);
}
return clk; return hw;
} }
...@@ -239,12 +239,13 @@ static const struct clk_ops clk_pllv2_ops = { ...@@ -239,12 +239,13 @@ static const struct clk_ops clk_pllv2_ops = {
.set_rate = clk_pllv2_set_rate, .set_rate = clk_pllv2_set_rate,
}; };
struct clk *imx_clk_pllv2(const char *name, const char *parent, struct clk_hw *imx_clk_hw_pllv2(const char *name, const char *parent,
void __iomem *base) void __iomem *base)
{ {
struct clk_pllv2 *pll; struct clk_pllv2 *pll;
struct clk *clk; struct clk_hw *hw;
struct clk_init_data init; struct clk_init_data init;
int ret;
pll = kzalloc(sizeof(*pll), GFP_KERNEL); pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll) if (!pll)
...@@ -259,10 +260,13 @@ struct clk *imx_clk_pllv2(const char *name, const char *parent, ...@@ -259,10 +260,13 @@ struct clk *imx_clk_pllv2(const char *name, const char *parent,
init.num_parents = 1; init.num_parents = 1;
pll->hw.init = &init; pll->hw.init = &init;
hw = &pll->hw;
clk = clk_register(NULL, &pll->hw); ret = clk_hw_register(NULL, hw);
if (IS_ERR(clk)) if (ret) {
kfree(pll); kfree(pll);
return ERR_PTR(ret);
}
return clk; return hw;
} }
...@@ -206,7 +206,7 @@ static const struct clk_ops clk_pllv4_ops = { ...@@ -206,7 +206,7 @@ static const struct clk_ops clk_pllv4_ops = {
.is_enabled = clk_pllv4_is_enabled, .is_enabled = clk_pllv4_is_enabled,
}; };
struct clk_hw *imx_clk_pllv4(const char *name, const char *parent_name, struct clk_hw *imx_clk_hw_pllv4(const char *name, const char *parent_name,
void __iomem *base) void __iomem *base)
{ {
struct clk_pllv4 *pll; struct clk_pllv4 *pll;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -18,4 +18,4 @@ obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o ...@@ -18,4 +18,4 @@ obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o meson8-ddr.o
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -4692,6 +4692,7 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { ...@@ -4692,6 +4692,7 @@ static struct clk_regmap *const g12a_clk_regmaps[] = {
&g12a_bt656, &g12a_bt656,
&g12a_usb1_to_ddr, &g12a_usb1_to_ddr,
&g12a_mmc_pclk, &g12a_mmc_pclk,
&g12a_uart2,
&g12a_vpu_intr, &g12a_vpu_intr,
&g12a_gic, &g12a_gic,
&g12a_sd_emmc_a_clk0, &g12a_sd_emmc_a_clk0,
......
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.
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