Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 13 Sep 2017 18:04:14 +0000 (11:04 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 13 Sep 2017 18:04:14 +0000 (11:04 -0700)
Pull clk updates from Stephen Boyd:
 "The diff is dominated by the Allwinner A10/A20 SoCs getting converted
  to the sunxi-ng framework. Otherwise, the heavy hitters are various
  drivers for SoCs like AT91, Amlogic, Renesas, and Rockchip. There are
  some other new clk drivers in here too but overall this is just a
  bunch of clk drivers for various different pieces of hardware and a
  collection of non-critical fixes for clk drivers.

  New Drivers:
   - Allwinner R40 SoCs
   - Renesas R-Car Gen3 USB 2.0 clock selector PHY
   - Atmel AT91 audio PLL
   - Uniphier PXs3 SoCs
   - ARC HSDK Board PLLs
   - AXS10X Board PLLs
   - STMicroelectronics STM32H743 SoCs

  Removed Drivers:
   - Non-compiling mb86s7x support

  Updates:
   - Allwinner A10/A20 SoCs converted to sunxi-ng framework
   - Allwinner H3 CPU clk fixes
   - Renesas R-Car D3 SoC
   - Renesas V2H and M3-W modules
   - Samsung Exynos5420/5422/5800 audio fixes
   - Rockchip fractional clk approximation fixes
   - Rockchip rk3126 SoC support within the rk3128 driver
   - Amlogic gxbb CEC32 and sd_emmc clks
   - Amlogic meson8b reset controller support
   - IDT VersaClock 5P49V5925/5P49V6901 support
   - Qualcomm MSM8996 SMMU clks
   - Various 'const' applications for struct clk_ops
   - si5351 PLL reset bugfix
   - Uniphier audio on LD11/LD20 and ethernet support on LD11/LD20/Pro4/PXs2
   - Assorted Tegra clk driver fixes"

* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (120 commits)
  clk: si5351: fix PLL reset
  ASoC: atmel-classd: remove aclk clock
  ASoC: atmel-classd: remove aclk clock from DT binding
  clk: at91: clk-generated: make gclk determine audio_pll rate
  clk: at91: clk-generated: create function to find best_diff
  clk: at91: add audio pll clock drivers
  dt-bindings: clk: at91: add audio plls to the compatible list
  clk: at91: clk-generated: remove useless divisor loop
  clk: mb86s7x: Drop non-building driver
  clk: ti: check for null return in strrchr to avoid null dereferencing
  clk: Don't write error code into divider register
  clk: uniphier: add video input subsystem clock
  clk: uniphier: add audio system clock
  clk: stm32h7: Add stm32h743 clock driver
  clk: gate: expose clk_gate_ops::is_enabled
  clk: nxp: clk-lpc32xx: rename clk_gate_is_enabled()
  clk: uniphier: add PXs3 clock data
  clk: hi6220: change watchdog clock source
  clk: Kconfig: Name RK805 in Kconfig for COMMON_CLK_RK808
  clk: cs2000: Add cs2000_set_saved_rate
  ...

142 files changed:
Documentation/devicetree/bindings/clock/amlogic,gxbb-aoclkc.txt
Documentation/devicetree/bindings/clock/at91-clock.txt
Documentation/devicetree/bindings/clock/idt,versaclock5.txt
Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt
Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/rockchip,rk3128-cru.txt
Documentation/devicetree/bindings/clock/snps,hsdk-pll-clock.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/snps,pll-clock.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/st,stm32h7-rcc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/sunxi-ccu.txt
Documentation/devicetree/bindings/clock/uniphier-clock.txt
Documentation/devicetree/bindings/sound/atmel-classd.txt
MAINTAINERS
arch/arm/mach-at91/Kconfig
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/at91/Makefile
drivers/clk/at91/clk-audio-pll.c [new file with mode: 0644]
drivers/clk/at91/clk-generated.c
drivers/clk/axs10x/Makefile
drivers/clk/axs10x/pll_clock.c [new file with mode: 0644]
drivers/clk/berlin/bg2.c
drivers/clk/berlin/bg2q.c
drivers/clk/clk-asm9260.c
drivers/clk/clk-conf.c
drivers/clk/clk-cs2000-cp.c
drivers/clk/clk-divider.c
drivers/clk/clk-fractional-divider.c
drivers/clk/clk-gate.c
drivers/clk/clk-gemini.c
drivers/clk/clk-hsdk-pll.c [new file with mode: 0644]
drivers/clk/clk-mb86s7x.c [deleted file]
drivers/clk/clk-moxart.c
drivers/clk/clk-qoriq.c
drivers/clk/clk-si5351.c
drivers/clk/clk-stm32f4.c
drivers/clk/clk-stm32h7.c [new file with mode: 0644]
drivers/clk/clk-versaclock5.c
drivers/clk/clk-xgene.c
drivers/clk/clk.c
drivers/clk/clkdev.c
drivers/clk/hisilicon/clk-hi6220.c
drivers/clk/imx/clk-imx51-imx53.c
drivers/clk/imx/clk-imx6sl.c
drivers/clk/imx/clk-imx6sx.c
drivers/clk/imx/clk-imx6ul.c
drivers/clk/imx/clk-imx7d.c
drivers/clk/imx/clk-vf610.c
drivers/clk/mediatek/clk-cpumux.c
drivers/clk/mediatek/clk-mtk.c
drivers/clk/mediatek/reset.c
drivers/clk/meson/Kconfig
drivers/clk/meson/Makefile
drivers/clk/meson/gxbb-aoclk-32k.c [new file with mode: 0644]
drivers/clk/meson/gxbb-aoclk-regmap.c [new file with mode: 0644]
drivers/clk/meson/gxbb-aoclk.c
drivers/clk/meson/gxbb-aoclk.h [new file with mode: 0644]
drivers/clk/meson/gxbb.c
drivers/clk/meson/meson8b.c
drivers/clk/meson/meson8b.h
drivers/clk/mmp/clk.c
drivers/clk/nxp/clk-lpc32xx.c
drivers/clk/qcom/clk-smd-rpm.c
drivers/clk/qcom/gcc-msm8916.c
drivers/clk/qcom/gcc-msm8996.c
drivers/clk/renesas/Kconfig
drivers/clk/renesas/Makefile
drivers/clk/renesas/clk-div6.c
drivers/clk/renesas/clk-mstp.c
drivers/clk/renesas/clk-rcar-gen2.c
drivers/clk/renesas/r8a7792-cpg-mssr.c
drivers/clk/renesas/r8a7795-cpg-mssr.c
drivers/clk/renesas/r8a7796-cpg-mssr.c
drivers/clk/renesas/r8a77995-cpg-mssr.c [new file with mode: 0644]
drivers/clk/renesas/rcar-gen3-cpg.c
drivers/clk/renesas/rcar-gen3-cpg.h
drivers/clk/renesas/rcar-usb2-clock-sel.c [new file with mode: 0644]
drivers/clk/renesas/renesas-cpg-mssr.c
drivers/clk/renesas/renesas-cpg-mssr.h
drivers/clk/rockchip/clk-rk3128.c
drivers/clk/rockchip/clk-rk3228.c
drivers/clk/rockchip/clk-rv1108.c
drivers/clk/rockchip/clk.c
drivers/clk/samsung/clk-exynos-audss.c
drivers/clk/samsung/clk-exynos5420.c
drivers/clk/sunxi-ng/Kconfig
drivers/clk/sunxi-ng/Makefile
drivers/clk/sunxi-ng/ccu-sun4i-a10.c [new file with mode: 0644]
drivers/clk/sunxi-ng/ccu-sun4i-a10.h [new file with mode: 0644]
drivers/clk/sunxi-ng/ccu-sun5i.c
drivers/clk/sunxi-ng/ccu-sun6i-a31.c
drivers/clk/sunxi-ng/ccu-sun8i-a23.c
drivers/clk/sunxi-ng/ccu-sun8i-a33.c
drivers/clk/sunxi-ng/ccu-sun8i-h3.c
drivers/clk/sunxi-ng/ccu-sun8i-r.c
drivers/clk/sunxi-ng/ccu-sun8i-r.h
drivers/clk/sunxi-ng/ccu-sun8i-r40.c [new file with mode: 0644]
drivers/clk/sunxi-ng/ccu-sun8i-r40.h [new file with mode: 0644]
drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
drivers/clk/sunxi-ng/ccu_div.c
drivers/clk/sunxi-ng/ccu_div.h
drivers/clk/sunxi-ng/ccu_frac.c
drivers/clk/sunxi-ng/ccu_frac.h
drivers/clk/sunxi-ng/ccu_mult.c
drivers/clk/sunxi-ng/ccu_nkm.c
drivers/clk/sunxi-ng/ccu_nkm.h
drivers/clk/sunxi-ng/ccu_nm.c
drivers/clk/sunxi/clk-sun8i-bus-gates.c
drivers/clk/sunxi/clk-sunxi.c
drivers/clk/tegra/clk-emc.c
drivers/clk/tegra/clk-pll.c
drivers/clk/tegra/clk-tegra-periph.c
drivers/clk/tegra/clk-tegra-super-gen4.c
drivers/clk/tegra/clk-tegra210.c
drivers/clk/tegra/clk.h
drivers/clk/ti/adpll.c
drivers/clk/ti/apll.c
drivers/clk/ti/clockdomain.c
drivers/clk/ti/fapll.c
drivers/clk/uniphier/clk-uniphier-core.c
drivers/clk/uniphier/clk-uniphier-mio.c
drivers/clk/uniphier/clk-uniphier-sys.c
drivers/clk/uniphier/clk-uniphier.h
drivers/clk/ux500/clk-prcc.c
drivers/clk/ux500/clk-prcmu.c
drivers/clk/ux500/clk-sysctrl.c
drivers/clk/versatile/clk-vexpress-osc.c
drivers/clk/zte/clk-zx296718.c
include/dt-bindings/clock/qcom,gcc-msm8996.h
include/dt-bindings/clock/r8a77995-cpg-mssr.h [new file with mode: 0644]
include/dt-bindings/clock/rk3228-cru.h
include/dt-bindings/clock/rv1108-cru.h
include/dt-bindings/clock/stm32h7-clks.h [new file with mode: 0644]
include/dt-bindings/clock/sun4i-a10-ccu.h [new file with mode: 0644]
include/dt-bindings/clock/sun7i-a20-ccu.h [new file with mode: 0644]
include/dt-bindings/clock/sun8i-r40-ccu.h [new file with mode: 0644]
include/dt-bindings/mfd/stm32h7-rcc.h [new file with mode: 0644]
include/dt-bindings/reset/sun4i-a10-ccu.h [new file with mode: 0644]
include/dt-bindings/reset/sun8i-r40-ccu.h [new file with mode: 0644]
include/linux/clk-provider.h
include/linux/clk/at91_pmc.h
sound/soc/atmel/atmel-classd.c

index faa6d8ac583412557118a53c3bebb22ea0ab159a..786dc39ca904ddd02ede6af5b7617fb9ef2e7d32 100644 (file)
@@ -5,9 +5,11 @@ controllers within the Always-On part of the SoC.
 
 Required Properties:
 
-- compatible: should be "amlogic,gxbb-aoclkc"
-- reg: physical base address of the clock controller and length of memory
-       mapped region.
+- compatible: value should be different for each SoC family as :
+       - GXBB (S905) : "amlogic,meson-gxbb-aoclkc"
+       - GXL (S905X, S905D) : "amlogic,meson-gxl-aoclkc"
+       - GXM (S912) : "amlogic,meson-gxm-aoclkc"
+       followed by the common "amlogic,meson-gx-aoclkc"
 
 - #clock-cells: should be 1.
 
@@ -23,14 +25,22 @@ to specify the reset which they consume. All available resets are defined as
 preprocessor macros in the dt-bindings/reset/gxbb-aoclkc.h header and can be
 used in device tree sources.
 
+Parent node should have the following properties :
+- compatible: "amlogic,meson-gx-ao-sysctrl", "syscon", "simple-mfd"
+- reg: base address and size of the AO system control register space.
+
 Example: AO Clock controller node:
 
-       clkc_AO: clock-controller@040 {
-               compatible = "amlogic,gxbb-aoclkc";
-               reg = <0x0 0x040 0x0 0x4>;
+ao_sysctrl: sys-ctrl@0 {
+       compatible = "amlogic,meson-gx-ao-sysctrl", "syscon", "simple-mfd";
+       reg =  <0x0 0x0 0x0 0x100>;
+
+       clkc_AO: clock-controller {
+               compatible = "amlogic,meson-gxbb-aoclkc", "amlogic,meson-gx-aoclkc";
                #clock-cells = <1>;
                #reset-cells = <1>;
        };
+};
 
 Example: UART controller node that consumes the clock and reset generated
   by the clock controller:
index 5f3ad65daf69d48b8fc0f6cffc59e4f4210293cc..51c259a92d0294e31be12a2b4552e074b7d38e70 100644 (file)
@@ -81,6 +81,16 @@ Required properties:
        "atmel,sama5d2-clk-generated":
                at91 generated clock
 
+       "atmel,sama5d2-clk-audio-pll-frac":
+               at91 audio fractional pll
+
+       "atmel,sama5d2-clk-audio-pll-pad":
+               at91 audio pll CLK_AUDIO output pin
+
+       "atmel,sama5d2-clk-audio-pll-pmc"
+               at91 audio pll output on AUDIOPLLCLK that feeds the PMC
+               and can be used by peripheral clock or generic clock
+
 Required properties for SCKC node:
 - reg : defines the IO memory reserved for the SCKC.
 - #size-cells : shall be 0 (reg is used to encode clk id).
index 53d7e50ed875ae0db438af18f9f3354c2548c705..05a245c9df08fe48738a1d3e27e6bd45711b4a50 100644 (file)
@@ -1,24 +1,32 @@
-Binding for IDT VersaClock5 programmable i2c clock generator.
+Binding for IDT VersaClock 5,6 programmable i2c clock generators.
 
-The IDT VersaClock5 are programmable i2c clock generators providing
-from 3 to 12 output clocks.
+The IDT VersaClock 5 and VersaClock 6 are programmable i2c clock
+generators providing from 3 to 12 output clocks.
 
 ==I2C device node==
 
 Required properties:
-- compatible:  shall be one of "idt,5p49v5923" , "idt,5p49v5933" ,
-               "idt,5p49v5935".
+- compatible:  shall be one of
+               "idt,5p49v5923"
+               "idt,5p49v5925"
+               "idt,5p49v5933"
+               "idt,5p49v5935"
+               "idt,5p49v6901"
 - reg:         i2c device address, shall be 0x68 or 0x6a.
 - #clock-cells:        from common clock binding; shall be set to 1.
 - clocks:      from common clock binding; list of parent clock handles,
-               - 5p49v5923: (required) either or both of XTAL or CLKIN
+               - 5p49v5923 and
+                 5p49v5925 and
+                 5p49v6901: (required) either or both of XTAL or CLKIN
                                        reference clock.
                - 5p49v5933 and
                - 5p49v5935: (optional) property not present (internal
                                        Xtal used) or CLKIN reference
                                        clock.
 - clock-names: from common clock binding; clock input names, can be
-               - 5p49v5923: (required) either or both of "xin", "clkin".
+               - 5p49v5923 and
+                 5p49v5925 and
+                 5p49v6901: (required) either or both of "xin", "clkin".
                - 5p49v5933 and
                - 5p49v5935: (optional) property not present or "clkin".
 
@@ -37,6 +45,7 @@ clock specifier, the following mapping applies:
        1 -- OUT1
        2 -- OUT4
 
+5P49V5925 and
 5P49V5935:
        0 -- OUT0_SEL_I2CB
        1 -- OUT1
@@ -44,6 +53,13 @@ clock specifier, the following mapping applies:
        3 -- OUT3
        4 -- OUT4
 
+5P49V6901:
+       0 -- OUT0_SEL_I2CB
+       1 -- OUT1
+       2 -- OUT2
+       3 -- OUT3
+       4 -- OUT4
+
 ==Example==
 
 /* 25MHz reference crystal */
index 707a686d8d3e1341376b9f94de0296e43ba6c77b..316e136865688b7c4fe0c6f1d7b23934d66634d1 100644 (file)
@@ -22,6 +22,7 @@ Required Properties:
       - "renesas,r8a7794-cpg-mssr" for the r8a7794 SoC (R-Car E2)
       - "renesas,r8a7795-cpg-mssr" for the r8a7795 SoC (R-Car H3)
       - "renesas,r8a7796-cpg-mssr" for the r8a7796 SoC (R-Car M3-W)
+      - "renesas,r8a77995-cpg-mssr" for the r8a77995 SoC (R-Car D3)
 
   - reg: Base address and length of the memory resource used by the CPG/MSSR
     block
@@ -30,7 +31,7 @@ Required Properties:
     clock-names
   - clock-names: List of external parent clock names. Valid names are:
       - "extal" (r8a7743, r8a7745, r8a7790, r8a7791, r8a7792, r8a7793, r8a7794,
-                r8a7795, r8a7796)
+                r8a7795, r8a7796, r8a77995)
       - "extalr" (r8a7795, r8a7796)
       - "usb_extal" (r8a7743, r8a7745, r8a7790, r8a7791, r8a7793, r8a7794)
 
diff --git a/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt b/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt
new file mode 100644 (file)
index 0000000..e96e085
--- /dev/null
@@ -0,0 +1,55 @@
+* Renesas R-Car USB 2.0 clock selector
+
+This file provides information on what the device node for the R-Car USB 2.0
+clock selector.
+
+If you connect an external clock to the USB_EXTAL pin only, you should set
+the clock rate to "usb_extal" node only.
+If you connect an oscillator to both the USB_XTAL and USB_EXTAL, this module
+is not needed because this is default setting. (Of course, you can set the
+clock rates to both "usb_extal" and "usb_xtal" nodes.
+
+Case 1: An external clock connects to R-Car SoC
+       +----------+   +--- R-Car ---------------------+
+       |External  |---|USB_EXTAL ---> all usb channels|
+       |clock     |   |USB_XTAL                       |
+       +----------+   +-------------------------------+
+In this case, we need this driver with "usb_extal" clock.
+
+Case 2: An oscillator connects to R-Car SoC
+       +----------+   +--- R-Car ---------------------+
+       |Oscillator|---|USB_EXTAL -+-> all usb channels|
+       |          |---|USB_XTAL --+                   |
+       +----------+   +-------------------------------+
+In this case, we don't need this selector.
+
+Required properties:
+- compatible: "renesas,r8a7795-rcar-usb2-clock-sel" if the device is a part of
+             an R8A7795 SoC.
+             "renesas,r8a7796-rcar-usb2-clock-sel" if the device if a part of
+             an R8A7796 SoC.
+             "renesas,rcar-gen3-usb2-clock-sel" for a generic R-Car Gen3
+             compatible device.
+
+             When compatible with the generic version, nodes must list the
+             SoC-specific version corresponding to the platform first
+             followed by the generic version.
+
+- reg: offset and length of the USB 2.0 clock selector register block.
+- clocks: A list of phandles and specifier pairs.
+- clock-names: Name of the clocks.
+ - The functional clock must be "ehci_ohci"
+ - The USB_EXTAL clock pin must be "usb_extal"
+ - The USB_XTAL clock pin must be "usb_xtal"
+- #clock-cells: Must be 0
+
+Example (R-Car H3):
+
+       usb2_clksel: clock-controller@e6590630 {
+               compatible = "renesas,r8a77950-rcar-usb2-clock-sel",
+                            "renesas,rcar-gen3-usb2-clock-sel";
+               reg = <0 0xe6590630 0 0x02>;
+               clocks = <&cpg CPG_MOD 703>, <&usb_extal>, <&usb_xtal>;
+               clock-names = "ehci_ohci", "usb_extal", "usb_xtal";
+               #clock-cells = <0>;
+       };
index 455a9a00a623155dea4acd74e47b2153871b8904..6f8744fd301b23609f924873f325b9fc4e0c98a0 100644 (file)
@@ -1,12 +1,14 @@
-* Rockchip RK3128 Clock and Reset Unit
+* Rockchip RK3126/RK3128 Clock and Reset Unit
 
-The RK3128 clock controller generates and supplies clock to various
+The RK3126/RK3128 clock controller generates and supplies clock to various
 controllers within the SoC and also implements a reset controller for SoC
 peripherals.
 
 Required Properties:
 
-- compatible: should be "rockchip,rk3128-cru"
+- compatible: should be "rockchip,rk3126-cru" or "rockchip,rk3128-cru"
+  "rockchip,rk3126-cru" - controller compatible with RK3126 SoC.
+  "rockchip,rk3128-cru" - controller compatible with RK3128 SoC.
 - reg: physical base address of the controller and length of memory mapped
   region.
 - #clock-cells: should be 1.
diff --git a/Documentation/devicetree/bindings/clock/snps,hsdk-pll-clock.txt b/Documentation/devicetree/bindings/clock/snps,hsdk-pll-clock.txt
new file mode 100644 (file)
index 0000000..c56c755
--- /dev/null
@@ -0,0 +1,28 @@
+Binding for the HSDK Generic PLL clock
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible: should be "snps,hsdk-<name>-pll-clock"
+  "snps,hsdk-core-pll-clock"
+  "snps,hsdk-gp-pll-clock"
+  "snps,hsdk-hdmi-pll-clock"
+- reg : should contain base register location and length.
+- clocks: shall be the input parent clock phandle for the PLL.
+- #clock-cells: from common clock binding; Should always be set to 0.
+
+Example:
+       input_clk: input-clk {
+               clock-frequency = <33333333>;
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+       };
+
+       cpu_clk: cpu-clk@0 {
+               compatible = "snps,hsdk-core-pll-clock";
+               reg = <0x00 0x10>;
+               #clock-cells = <0>;
+               clocks = <&input_clk>;
+       };
diff --git a/Documentation/devicetree/bindings/clock/snps,pll-clock.txt b/Documentation/devicetree/bindings/clock/snps,pll-clock.txt
new file mode 100644 (file)
index 0000000..11fe487
--- /dev/null
@@ -0,0 +1,28 @@
+Binding for the AXS10X Generic PLL clock
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible: should be "snps,axs10x-<name>-pll-clock"
+  "snps,axs10x-arc-pll-clock"
+  "snps,axs10x-pgu-pll-clock"
+- reg: should always contain 2 pairs address - length: first for PLL config
+registers and second for corresponding LOCK CGU register.
+- clocks: shall be the input parent clock phandle for the PLL.
+- #clock-cells: from common clock binding; Should always be set to 0.
+
+Example:
+       input-clk: input-clk {
+               clock-frequency = <33333333>;
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+       };
+
+       core-clk: core-clk@80 {
+               compatible = "snps,axs10x-arc-pll-clock";
+               reg = <0x80 0x10>, <0x100 0x10>;
+               #clock-cells = <0>;
+               clocks = <&input-clk>;
+       };
diff --git a/Documentation/devicetree/bindings/clock/st,stm32h7-rcc.txt b/Documentation/devicetree/bindings/clock/st,stm32h7-rcc.txt
new file mode 100644 (file)
index 0000000..a135504
--- /dev/null
@@ -0,0 +1,71 @@
+STMicroelectronics STM32H7 Reset and Clock Controller
+=====================================================
+
+The RCC IP is both a reset and a clock controller.
+
+Please refer to clock-bindings.txt for common clock controller binding usage.
+Please also refer to reset.txt for common reset controller binding usage.
+
+Required properties:
+- compatible: Should be:
+  "st,stm32h743-rcc"
+
+- reg: should be register base and length as documented in the
+  datasheet
+
+- #reset-cells: 1, see below
+
+- #clock-cells : from common clock binding; shall be set to 1
+
+- clocks: External oscillator clock phandle
+  - high speed external clock signal (HSE)
+  - low speed external clock signal (LSE)
+  - external I2S clock (I2S_CKIN)
+
+Optional properties:
+- st,syscfg: phandle for pwrcfg, mandatory to disable/enable backup domain
+  write protection (RTC clock).
+
+Example:
+
+       rcc: reset-clock-controller@58024400 {
+               compatible = "st,stm32h743-rcc", "st,stm32-rcc";
+               reg = <0x58024400 0x400>;
+               #reset-cells = <1>;
+               #clock-cells = <2>;
+               clocks = <&clk_hse>, <&clk_lse>, <&clk_i2s_ckin>;
+
+               st,syscfg = <&pwrcfg>;
+};
+
+The peripheral clock consumer should specify the desired clock by
+having the clock ID in its "clocks" phandle cell.
+
+Example:
+
+               timer5: timer@40000c00 {
+                       compatible = "st,stm32-timer";
+                       reg = <0x40000c00 0x400>;
+                       interrupts = <50>;
+                       clocks = <&rcc TIM5_CK>;
+               };
+
+Specifying softreset control of devices
+=======================================
+
+Device nodes should specify the reset channel required in their "resets"
+property, containing a phandle to the reset device node and an index specifying
+which channel to use.
+The index is the bit number within the RCC registers bank, starting from RCC
+base address.
+It is calculated as: index = register_offset / 4 * 32 + bit_offset.
+Where bit_offset is the bit offset within the register.
+
+For example, for CRC reset:
+  crc = AHB4RSTR_offset / 4 * 32 + CRCRST_bit_offset = 0x88 / 4 * 32 + 19 = 1107
+
+Example:
+
+       timer2 {
+               resets  = <&rcc STM32H7_APB1L_RESET(TIM2)>;
+       };
index df9fad58facdc22b995e9066275cac3344724a6d..7eda08eb8a1e336cf0756baa62a91f21fd58bce6 100644 (file)
@@ -3,18 +3,24 @@ Allwinner Clock Control Unit Binding
 
 Required properties :
 - compatible: must contain one of the following compatibles:
+               - "allwinner,sun4i-a10-ccu"
+               - "allwinner,sun5i-a10s-ccu"
+               - "allwinner,sun5i-a13-ccu"
                - "allwinner,sun6i-a31-ccu"
+               - "allwinner,sun7i-a20-ccu"
                - "allwinner,sun8i-a23-ccu"
                - "allwinner,sun8i-a33-ccu"
                - "allwinner,sun8i-a83t-ccu"
                - "allwinner,sun8i-a83t-r-ccu"
                - "allwinner,sun8i-h3-ccu"
                - "allwinner,sun8i-h3-r-ccu"
++              - "allwinner,sun8i-r40-ccu"
                - "allwinner,sun8i-v3s-ccu"
                - "allwinner,sun9i-a80-ccu"
                - "allwinner,sun50i-a64-ccu"
                - "allwinner,sun50i-a64-r-ccu"
                - "allwinner,sun50i-h5-ccu"
+               - "nextthing,gr8-ccu"
 
 - reg: Must contain the registers base address and length
 - clocks: phandle to the oscillators feeding the CCU. Two are needed:
index 812163060fa3e4cb4e4f39fe22c9fbd2aeb41d9f..7b5f602765fe2fc318fef07c8c4ffc5168ddd5d8 100644 (file)
@@ -6,7 +6,6 @@ System clock
 
 Required properties:
 - compatible: should be one of the following:
-    "socionext,uniphier-sld3-clock" - for sLD3 SoC.
     "socionext,uniphier-ld4-clock"  - for LD4 SoC.
     "socionext,uniphier-pro4-clock" - for Pro4 SoC.
     "socionext,uniphier-sld8-clock" - for sLD8 SoC.
@@ -14,6 +13,7 @@ Required properties:
     "socionext,uniphier-pxs2-clock" - for PXs2/LD6b SoC.
     "socionext,uniphier-ld11-clock" - for LD11 SoC.
     "socionext,uniphier-ld20-clock" - for LD20 SoC.
+    "socionext,uniphier-pxs3-clock" - for PXs3 SoC
 - #clock-cells: should be 1.
 
 Example:
@@ -48,7 +48,6 @@ Media I/O (MIO) clock, SD clock
 
 Required properties:
 - compatible: should be one of the following:
-    "socionext,uniphier-sld3-mio-clock" - for sLD3 SoC.
     "socionext,uniphier-ld4-mio-clock"  - for LD4 SoC.
     "socionext,uniphier-pro4-mio-clock" - for Pro4 SoC.
     "socionext,uniphier-sld8-mio-clock" - for sLD8 SoC.
@@ -56,6 +55,7 @@ Required properties:
     "socionext,uniphier-pxs2-sd-clock"  - for PXs2/LD6b SoC.
     "socionext,uniphier-ld11-mio-clock" - for LD11 SoC.
     "socionext,uniphier-ld20-sd-clock"  - for LD20 SoC.
+    "socionext,uniphier-pxs3-sd-clock"  - for PXs3 SoC
 - #clock-cells: should be 1.
 
 Example:
@@ -82,11 +82,9 @@ Provided clocks:
  8: USB2 ch0 host
  9: USB2 ch1 host
 10: USB2 ch2 host
-11: USB2 ch3 host
 12: USB2 ch0 PHY
 13: USB2 ch1 PHY
 14: USB2 ch2 PHY
-15: USB2 ch3 PHY
 
 
 Peripheral clock
@@ -94,7 +92,6 @@ Peripheral clock
 
 Required properties:
 - compatible: should be one of the following:
-    "socionext,uniphier-sld3-peri-clock" - for sLD3 SoC.
     "socionext,uniphier-ld4-peri-clock"  - for LD4 SoC.
     "socionext,uniphier-pro4-peri-clock" - for Pro4 SoC.
     "socionext,uniphier-sld8-peri-clock" - for sLD8 SoC.
@@ -102,6 +99,7 @@ Required properties:
     "socionext,uniphier-pxs2-peri-clock" - for PXs2/LD6b SoC.
     "socionext,uniphier-ld11-peri-clock" - for LD11 SoC.
     "socionext,uniphier-ld20-peri-clock" - for LD20 SoC.
+    "socionext,uniphier-pxs3-peri-clock" - for PXs3 SoC
 - #clock-cells: should be 1.
 
 Example:
index 549e701cb7a1c58620863fc0a5e5b08c313ff4ef..898551076382abef7941b3772cbbc5511a8ac476 100644 (file)
@@ -13,13 +13,11 @@ Required properties:
        Must be "tx".
 - clock-names
        Tuple listing input clock names.
-       Required elements: "pclk", "gclk" and "aclk".
+       Required elements: "pclk" and "gclk".
 - clocks
        Please refer to clock-bindings.txt.
 - assigned-clocks
        Should be <&classd_gclk>.
-- assigned-clock-parents
-       Should be <&audio_pll_pmc>.
 
 Optional properties:
 - pinctrl-names, pinctrl-0
@@ -45,10 +43,9 @@ classd: classd@fc048000 {
                        (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
                        | AT91_XDMAC_DT_PERID(47))>;
                dma-names = "tx";
-               clocks = <&classd_clk>, <&classd_gclk>, <&audio_pll_pmc>;
-               clock-names = "pclk", "gclk", "aclk";
+               clocks = <&classd_clk>, <&classd_gclk>;
+               clock-names = "pclk", "gclk";
                assigned-clocks = <&classd_gclk>;
-               assigned-clock-parents = <&audio_pll_pmc>;
 
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_classd_default>;
index 048586a2a9be36c1f489b9ac6a489927e9ee56e3..7be4129ec9514bf17e1327a0a1f137c74772dfe1 100644 (file)
@@ -12842,6 +12842,18 @@ F:     drivers/clocksource/arc_timer.c
 F:     drivers/tty/serial/arc_uart.c
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc.git
 
+SYNOPSYS ARC HSDK SDP pll clock driver
+M:     Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
+S:     Supported
+F:     drivers/clk/clk-hsdk-pll.c
+F:     Documentation/devicetree/bindings/clock/snps,hsdk-pll-clock.txt
+
+SYNOPSYS ARC SDP clock driver
+M:     Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
+S:     Supported
+F:     drivers/clk/axs10x/*
+F:     Documentation/devicetree/bindings/clock/snps,pll-clock.txt
+
 SYNOPSYS ARC SDP platform support
 M:     Alexey Brodkin <abrodkin@synopsys.com>
 S:     Supported
index 195da38cb9a220f22c2f890c5bcb8fc1f2c7c621..6d870421a7a64d2e3aa615746307e4d4254058f8 100644 (file)
@@ -26,6 +26,7 @@ config SOC_SAMA5D2
        select HAVE_AT91_USB_CLK
        select HAVE_AT91_H32MX
        select HAVE_AT91_GENERATED_CLK
+       select HAVE_AT91_AUDIO_PLL
        select PINCTRL_AT91PIO4
        help
          Select this if ou are using one of Atmel's SAMA5D2 family SoC.
@@ -125,6 +126,9 @@ config HAVE_AT91_H32MX
 config HAVE_AT91_GENERATED_CLK
        bool
 
+config HAVE_AT91_AUDIO_PLL
+       bool
+
 config SOC_SAM_V4_V5
        bool
 
index 68ca2d9fcd73b3277fec4309996fbd5373b58bbd..1c4e1aa6767ee9f755dea6b1d115d7d1c0bce666 100644 (file)
@@ -31,6 +31,13 @@ config COMMON_CLK_WM831X
 
 source "drivers/clk/versatile/Kconfig"
 
+config CLK_HSDK
+       bool "PLL Driver for HSDK platform"
+       depends on OF || COMPILE_TEST
+       ---help---
+         This driver supports the HSDK core, system, ddr, tunnel and hdmi PLLs
+         control.
+
 config COMMON_CLK_MAX77686
        tristate "Clock driver for Maxim 77620/77686/77802 MFD"
        depends on MFD_MAX77686 || MFD_MAX77620 || COMPILE_TEST
@@ -39,10 +46,10 @@ config COMMON_CLK_MAX77686
          clock.
 
 config COMMON_CLK_RK808
-       tristate "Clock driver for RK808/RK818"
+       tristate "Clock driver for RK805/RK808/RK818"
        depends on MFD_RK808
        ---help---
-         This driver supports RK808 and RK818 crystal oscillator clock. These
+         This driver supports RK805, RK808 and RK818 crystal oscillator clock. These
          multi-function devices have two fixed-rate oscillators,
          clocked at 32KHz each. Clkout1 is always on, Clkout2 can off
          by control register.
@@ -210,14 +217,14 @@ config COMMON_CLK_OXNAS
          Support for the OXNAS SoC Family clocks.
 
 config COMMON_CLK_VC5
-       tristate "Clock driver for IDT VersaClock5 devices"
+       tristate "Clock driver for IDT VersaClock 5,6 devices"
        depends on I2C
        depends on OF
        select REGMAP_I2C
        help
        ---help---
-         This driver supports the IDT VersaClock5 programmable clock
-         generator.
+         This driver supports the IDT VersaClock 5 and VersaClock 6
+         programmable clock generators.
 
 source "drivers/clk/bcm/Kconfig"
 source "drivers/clk/hisilicon/Kconfig"
index cd376b3fb47adc2bd87c64dddb7ec775e51f8e21..c99f363826f02f683c6018ddf02a0d4d3a58033f 100644 (file)
@@ -27,8 +27,8 @@ obj-$(CONFIG_COMMON_CLK_CS2000_CP)    += clk-cs2000-cp.o
 obj-$(CONFIG_ARCH_EFM32)               += clk-efm32gg.o
 obj-$(CONFIG_COMMON_CLK_GEMINI)                += clk-gemini.o
 obj-$(CONFIG_ARCH_HIGHBANK)            += clk-highbank.o
+obj-$(CONFIG_CLK_HSDK)                 += clk-hsdk-pll.o
 obj-$(CONFIG_COMMON_CLK_MAX77686)      += clk-max77686.o
-obj-$(CONFIG_ARCH_MB86S7X)             += clk-mb86s7x.o
 obj-$(CONFIG_ARCH_MOXART)              += clk-moxart.o
 obj-$(CONFIG_ARCH_NOMADIK)             += clk-nomadik.o
 obj-$(CONFIG_ARCH_NSPIRE)              += clk-nspire.o
@@ -44,6 +44,7 @@ obj-$(CONFIG_COMMON_CLK_SI5351)               += clk-si5351.o
 obj-$(CONFIG_COMMON_CLK_SI514)         += clk-si514.o
 obj-$(CONFIG_COMMON_CLK_SI570)         += clk-si570.o
 obj-$(CONFIG_ARCH_STM32)               += clk-stm32f4.o
+obj-$(CONFIG_ARCH_STM32)               += clk-stm32h7.o
 obj-$(CONFIG_ARCH_TANGO)               += clk-tango4.o
 obj-$(CONFIG_CLK_TWL6040)              += clk-twl6040.o
 obj-$(CONFIG_ARCH_U300)                        += clk-u300.o
index 13e67bd35cff3c8c56eb86229a35a58f40bcf834..c68947b65a4c4a176f7f679459f97b60c57ea1e3 100644 (file)
@@ -6,6 +6,7 @@ obj-y += pmc.o sckc.o
 obj-y += clk-slow.o clk-main.o clk-pll.o clk-plldiv.o clk-master.o
 obj-y += clk-system.o clk-peripheral.o clk-programmable.o
 
+obj-$(CONFIG_HAVE_AT91_AUDIO_PLL)      += clk-audio-pll.o
 obj-$(CONFIG_HAVE_AT91_UTMI)           += clk-utmi.o
 obj-$(CONFIG_HAVE_AT91_USB_CLK)                += clk-usb.o
 obj-$(CONFIG_HAVE_AT91_SMD)            += clk-smd.o
diff --git a/drivers/clk/at91/clk-audio-pll.c b/drivers/clk/at91/clk-audio-pll.c
new file mode 100644 (file)
index 0000000..da7bafc
--- /dev/null
@@ -0,0 +1,536 @@
+/*
+ *  Copyright (C) 2016 Atmel Corporation,
+ *                    Songjun Wu <songjun.wu@atmel.com>,
+ *                     Nicolas Ferre <nicolas.ferre@atmel.com>
+ *  Copyright (C) 2017 Free Electrons,
+ *                    Quentin Schulz <quentin.schulz@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The Sama5d2 SoC has two audio PLLs (PMC and PAD) that shares the same parent
+ * (FRAC). FRAC can output between 620 and 700MHz and only multiply the rate of
+ * its own parent. PMC and PAD can then divide the FRAC rate to best match the
+ * asked rate.
+ *
+ * Traits of FRAC clock:
+ * enable - clk_enable writes nd, fracr parameters and enables PLL
+ * rate - rate is adjustable.
+ *        clk->rate = parent->rate * ((nd + 1) + (fracr / 2^22))
+ * parent - fixed parent.  No clk_set_parent support
+ *
+ * Traits of PMC clock:
+ * enable - clk_enable writes qdpmc, and enables PMC output
+ * rate - rate is adjustable.
+ *        clk->rate = parent->rate / (qdpmc + 1)
+ * parent - fixed parent.  No clk_set_parent support
+ *
+ * Traits of PAD clock:
+ * enable - clk_enable writes divisors and enables PAD output
+ * rate - rate is adjustable.
+ *        clk->rate = parent->rate / (qdaudio * div))
+ * parent - fixed parent.  No clk_set_parent support
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/of.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define AUDIO_PLL_DIV_FRAC     BIT(22)
+#define AUDIO_PLL_ND_MAX       (AT91_PMC_AUDIO_PLL_ND_MASK >> \
+                                       AT91_PMC_AUDIO_PLL_ND_OFFSET)
+
+#define AUDIO_PLL_QDPAD(qd, div)       ((AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV(qd) & \
+                                         AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MASK) | \
+                                        (AT91_PMC_AUDIO_PLL_QDPAD_DIV(div) & \
+                                         AT91_PMC_AUDIO_PLL_QDPAD_DIV_MASK))
+
+#define AUDIO_PLL_QDPMC_MAX            (AT91_PMC_AUDIO_PLL_QDPMC_MASK >> \
+                                               AT91_PMC_AUDIO_PLL_QDPMC_OFFSET)
+
+#define AUDIO_PLL_FOUT_MIN     620000000UL
+#define AUDIO_PLL_FOUT_MAX     700000000UL
+
+struct clk_audio_frac {
+       struct clk_hw hw;
+       struct regmap *regmap;
+       u32 fracr;
+       u8 nd;
+};
+
+struct clk_audio_pad {
+       struct clk_hw hw;
+       struct regmap *regmap;
+       u8 qdaudio;
+       u8 div;
+};
+
+struct clk_audio_pmc {
+       struct clk_hw hw;
+       struct regmap *regmap;
+       u8 qdpmc;
+};
+
+#define to_clk_audio_frac(hw) container_of(hw, struct clk_audio_frac, hw)
+#define to_clk_audio_pad(hw) container_of(hw, struct clk_audio_pad, hw)
+#define to_clk_audio_pmc(hw) container_of(hw, struct clk_audio_pmc, hw)
+
+static int clk_audio_pll_frac_enable(struct clk_hw *hw)
+{
+       struct clk_audio_frac *frac = to_clk_audio_frac(hw);
+
+       regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL0,
+                          AT91_PMC_AUDIO_PLL_RESETN, 0);
+       regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL0,
+                          AT91_PMC_AUDIO_PLL_RESETN,
+                          AT91_PMC_AUDIO_PLL_RESETN);
+       regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL1,
+                          AT91_PMC_AUDIO_PLL_FRACR_MASK, frac->fracr);
+
+       /*
+        * reset and enable have to be done in 2 separated writes
+        * for AT91_PMC_AUDIO_PLL0
+        */
+       regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL0,
+                          AT91_PMC_AUDIO_PLL_PLLEN |
+                          AT91_PMC_AUDIO_PLL_ND_MASK,
+                          AT91_PMC_AUDIO_PLL_PLLEN |
+                          AT91_PMC_AUDIO_PLL_ND(frac->nd));
+
+       return 0;
+}
+
+static int clk_audio_pll_pad_enable(struct clk_hw *hw)
+{
+       struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw);
+
+       regmap_update_bits(apad_ck->regmap, AT91_PMC_AUDIO_PLL1,
+                          AT91_PMC_AUDIO_PLL_QDPAD_MASK,
+                          AUDIO_PLL_QDPAD(apad_ck->qdaudio, apad_ck->div));
+       regmap_update_bits(apad_ck->regmap, AT91_PMC_AUDIO_PLL0,
+                          AT91_PMC_AUDIO_PLL_PADEN, AT91_PMC_AUDIO_PLL_PADEN);
+
+       return 0;
+}
+
+static int clk_audio_pll_pmc_enable(struct clk_hw *hw)
+{
+       struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw);
+
+       regmap_update_bits(apmc_ck->regmap, AT91_PMC_AUDIO_PLL0,
+                          AT91_PMC_AUDIO_PLL_PMCEN |
+                          AT91_PMC_AUDIO_PLL_QDPMC_MASK,
+                          AT91_PMC_AUDIO_PLL_PMCEN |
+                          AT91_PMC_AUDIO_PLL_QDPMC(apmc_ck->qdpmc));
+       return 0;
+}
+
+static void clk_audio_pll_frac_disable(struct clk_hw *hw)
+{
+       struct clk_audio_frac *frac = to_clk_audio_frac(hw);
+
+       regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL0,
+                          AT91_PMC_AUDIO_PLL_PLLEN, 0);
+       /* do it in 2 separated writes */
+       regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL0,
+                          AT91_PMC_AUDIO_PLL_RESETN, 0);
+}
+
+static void clk_audio_pll_pad_disable(struct clk_hw *hw)
+{
+       struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw);
+
+       regmap_update_bits(apad_ck->regmap, AT91_PMC_AUDIO_PLL0,
+                          AT91_PMC_AUDIO_PLL_PADEN, 0);
+}
+
+static void clk_audio_pll_pmc_disable(struct clk_hw *hw)
+{
+       struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw);
+
+       regmap_update_bits(apmc_ck->regmap, AT91_PMC_AUDIO_PLL0,
+                          AT91_PMC_AUDIO_PLL_PMCEN, 0);
+}
+
+static unsigned long clk_audio_pll_fout(unsigned long parent_rate,
+                                       unsigned long nd, unsigned long fracr)
+{
+       unsigned long long fr = (unsigned long long)parent_rate * fracr;
+
+       pr_debug("A PLL: %s, fr = %llu\n", __func__, fr);
+
+       fr = DIV_ROUND_CLOSEST_ULL(fr, AUDIO_PLL_DIV_FRAC);
+
+       pr_debug("A PLL: %s, fr = %llu\n", __func__, fr);
+
+       return parent_rate * (nd + 1) + fr;
+}
+
+static unsigned long clk_audio_pll_frac_recalc_rate(struct clk_hw *hw,
+                                                   unsigned long parent_rate)
+{
+       struct clk_audio_frac *frac = to_clk_audio_frac(hw);
+       unsigned long fout;
+
+       fout = clk_audio_pll_fout(parent_rate, frac->nd, frac->fracr);
+
+       pr_debug("A PLL: %s, fout = %lu (nd = %u, fracr = %lu)\n", __func__,
+                fout, frac->nd, (unsigned long)frac->fracr);
+
+       return fout;
+}
+
+static unsigned long clk_audio_pll_pad_recalc_rate(struct clk_hw *hw,
+                                                  unsigned long parent_rate)
+{
+       struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw);
+       unsigned long apad_rate = 0;
+
+       if (apad_ck->qdaudio && apad_ck->div)
+               apad_rate = parent_rate / (apad_ck->qdaudio * apad_ck->div);
+
+       pr_debug("A PLL/PAD: %s, apad_rate = %lu (div = %u, qdaudio = %u)\n",
+                __func__, apad_rate, apad_ck->div, apad_ck->qdaudio);
+
+       return apad_rate;
+}
+
+static unsigned long clk_audio_pll_pmc_recalc_rate(struct clk_hw *hw,
+                                                  unsigned long parent_rate)
+{
+       struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw);
+       unsigned long apmc_rate = 0;
+
+       apmc_rate = parent_rate / (apmc_ck->qdpmc + 1);
+
+       pr_debug("A PLL/PMC: %s, apmc_rate = %lu (qdpmc = %u)\n", __func__,
+                apmc_rate, apmc_ck->qdpmc);
+
+       return apmc_rate;
+}
+
+static int clk_audio_pll_frac_compute_frac(unsigned long rate,
+                                          unsigned long parent_rate,
+                                          unsigned long *nd,
+                                          unsigned long *fracr)
+{
+       unsigned long long tmp, rem;
+
+       if (!rate)
+               return -EINVAL;
+
+       tmp = rate;
+       rem = do_div(tmp, parent_rate);
+       if (!tmp || tmp >= AUDIO_PLL_ND_MAX)
+               return -EINVAL;
+
+       *nd = tmp - 1;
+
+       tmp = rem * AUDIO_PLL_DIV_FRAC;
+       tmp = DIV_ROUND_CLOSEST_ULL(tmp, parent_rate);
+       if (tmp > AT91_PMC_AUDIO_PLL_FRACR_MASK)
+               return -EINVAL;
+
+       /* we can cast here as we verified the bounds just above */
+       *fracr = (unsigned long)tmp;
+
+       return 0;
+}
+
+static int clk_audio_pll_frac_determine_rate(struct clk_hw *hw,
+                                            struct clk_rate_request *req)
+{
+       unsigned long fracr, nd;
+       int ret;
+
+       pr_debug("A PLL: %s, rate = %lu (parent_rate = %lu)\n", __func__,
+                req->rate, req->best_parent_rate);
+
+       req->rate = clamp(req->rate, AUDIO_PLL_FOUT_MIN, AUDIO_PLL_FOUT_MAX);
+
+       req->min_rate = max(req->min_rate, AUDIO_PLL_FOUT_MIN);
+       req->max_rate = min(req->max_rate, AUDIO_PLL_FOUT_MAX);
+
+       ret = clk_audio_pll_frac_compute_frac(req->rate, req->best_parent_rate,
+                                             &nd, &fracr);
+       if (ret)
+               return ret;
+
+       req->rate = clk_audio_pll_fout(req->best_parent_rate, nd, fracr);
+
+       req->best_parent_hw = clk_hw_get_parent(hw);
+
+       pr_debug("A PLL: %s, best_rate = %lu (nd = %lu, fracr = %lu)\n",
+                __func__, req->rate, nd, fracr);
+
+       return 0;
+}
+
+static long clk_audio_pll_pad_round_rate(struct clk_hw *hw, unsigned long rate,
+                                        unsigned long *parent_rate)
+{
+       struct clk_hw *pclk = clk_hw_get_parent(hw);
+       long best_rate = -EINVAL;
+       unsigned long best_parent_rate;
+       unsigned long tmp_qd;
+       u32 div;
+       long tmp_rate;
+       int tmp_diff;
+       int best_diff = -1;
+
+       pr_debug("A PLL/PAD: %s, rate = %lu (parent_rate = %lu)\n", __func__,
+                rate, *parent_rate);
+
+       /*
+        * Rate divisor is actually made of two different divisors, multiplied
+        * between themselves before dividing the rate.
+        * tmp_qd goes from 1 to 31 and div is either 2 or 3.
+        * In order to avoid testing twice the rate divisor (e.g. divisor 12 can
+        * be found with (tmp_qd, div) = (2, 6) or (3, 4)), we remove any loop
+        * for a rate divisor when div is 2 and tmp_qd is a multiple of 3.
+        * We cannot inverse it (condition div is 3 and tmp_qd is even) or we
+        * would miss some rate divisor that aren't reachable with div being 2
+        * (e.g. rate divisor 90 is made with div = 3 and tmp_qd = 30, thus
+        * tmp_qd is even so we skip it because we think div 2 could make this
+        * rate divisor which isn't possible since tmp_qd has to be <= 31).
+        */
+       for (tmp_qd = 1; tmp_qd < AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MAX; tmp_qd++)
+               for (div = 2; div <= 3; div++) {
+                       if (div == 2 && tmp_qd % 3 == 0)
+                               continue;
+
+                       best_parent_rate = clk_hw_round_rate(pclk,
+                                                       rate * tmp_qd * div);
+                       tmp_rate = best_parent_rate / (div * tmp_qd);
+                       tmp_diff = abs(rate - tmp_rate);
+
+                       if (best_diff < 0 || best_diff > tmp_diff) {
+                               *parent_rate = best_parent_rate;
+                               best_rate = tmp_rate;
+                               best_diff = tmp_diff;
+                       }
+               }
+
+       pr_debug("A PLL/PAD: %s, best_rate = %ld, best_parent_rate = %lu\n",
+                __func__, best_rate, best_parent_rate);
+
+       return best_rate;
+}
+
+static long clk_audio_pll_pmc_round_rate(struct clk_hw *hw, unsigned long rate,
+                                        unsigned long *parent_rate)
+{
+       struct clk_hw *pclk = clk_hw_get_parent(hw);
+       long best_rate = -EINVAL;
+       unsigned long best_parent_rate = 0;
+       u32 tmp_qd = 0, div;
+       long tmp_rate;
+       int tmp_diff;
+       int best_diff = -1;
+
+       pr_debug("A PLL/PMC: %s, rate = %lu (parent_rate = %lu)\n", __func__,
+                rate, *parent_rate);
+
+       for (div = 1; div <= AUDIO_PLL_QDPMC_MAX; div++) {
+               best_parent_rate = clk_round_rate(pclk->clk, rate * div);
+               tmp_rate = best_parent_rate / div;
+               tmp_diff = abs(rate - tmp_rate);
+
+               if (best_diff < 0 || best_diff > tmp_diff) {
+                       *parent_rate = best_parent_rate;
+                       best_rate = tmp_rate;
+                       best_diff = tmp_diff;
+                       tmp_qd = div;
+               }
+       }
+
+       pr_debug("A PLL/PMC: %s, best_rate = %ld, best_parent_rate = %lu (qd = %d)\n",
+                __func__, best_rate, *parent_rate, tmp_qd - 1);
+
+       return best_rate;
+}
+
+static int clk_audio_pll_frac_set_rate(struct clk_hw *hw, unsigned long rate,
+                                      unsigned long parent_rate)
+{
+       struct clk_audio_frac *frac = to_clk_audio_frac(hw);
+       unsigned long fracr, nd;
+       int ret;
+
+       pr_debug("A PLL: %s, rate = %lu (parent_rate = %lu)\n", __func__, rate,
+                parent_rate);
+
+       if (rate < AUDIO_PLL_FOUT_MIN || rate > AUDIO_PLL_FOUT_MAX)
+               return -EINVAL;
+
+       ret = clk_audio_pll_frac_compute_frac(rate, parent_rate, &nd, &fracr);
+       if (ret)
+               return ret;
+
+       frac->nd = nd;
+       frac->fracr = fracr;
+
+       return 0;
+}
+
+static int clk_audio_pll_pad_set_rate(struct clk_hw *hw, unsigned long rate,
+                                     unsigned long parent_rate)
+{
+       struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw);
+       u8 tmp_div;
+
+       pr_debug("A PLL/PAD: %s, rate = %lu (parent_rate = %lu)\n", __func__,
+                rate, parent_rate);
+
+       if (!rate)
+               return -EINVAL;
+
+       tmp_div = parent_rate / rate;
+       if (tmp_div % 3 == 0) {
+               apad_ck->qdaudio = tmp_div / 3;
+               apad_ck->div = 3;
+       } else {
+               apad_ck->qdaudio = tmp_div / 2;
+               apad_ck->div = 2;
+       }
+
+       return 0;
+}
+
+static int clk_audio_pll_pmc_set_rate(struct clk_hw *hw, unsigned long rate,
+                                     unsigned long parent_rate)
+{
+       struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw);
+
+       if (!rate)
+               return -EINVAL;
+
+       pr_debug("A PLL/PMC: %s, rate = %lu (parent_rate = %lu)\n", __func__,
+                rate, parent_rate);
+
+       apmc_ck->qdpmc = parent_rate / rate - 1;
+
+       return 0;
+}
+
+static const struct clk_ops audio_pll_frac_ops = {
+       .enable = clk_audio_pll_frac_enable,
+       .disable = clk_audio_pll_frac_disable,
+       .recalc_rate = clk_audio_pll_frac_recalc_rate,
+       .determine_rate = clk_audio_pll_frac_determine_rate,
+       .set_rate = clk_audio_pll_frac_set_rate,
+};
+
+static const struct clk_ops audio_pll_pad_ops = {
+       .enable = clk_audio_pll_pad_enable,
+       .disable = clk_audio_pll_pad_disable,
+       .recalc_rate = clk_audio_pll_pad_recalc_rate,
+       .round_rate = clk_audio_pll_pad_round_rate,
+       .set_rate = clk_audio_pll_pad_set_rate,
+};
+
+static const struct clk_ops audio_pll_pmc_ops = {
+       .enable = clk_audio_pll_pmc_enable,
+       .disable = clk_audio_pll_pmc_disable,
+       .recalc_rate = clk_audio_pll_pmc_recalc_rate,
+       .round_rate = clk_audio_pll_pmc_round_rate,
+       .set_rate = clk_audio_pll_pmc_set_rate,
+};
+
+static int of_sama5d2_clk_audio_pll_setup(struct device_node *np,
+                                         struct clk_init_data *init,
+                                         struct clk_hw *hw,
+                                         struct regmap **clk_audio_regmap)
+{
+       struct regmap *regmap;
+       const char *parent_names[1];
+       int ret;
+
+       regmap = syscon_node_to_regmap(of_get_parent(np));
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       init->name = np->name;
+       of_clk_parent_fill(np, parent_names, 1);
+       init->parent_names = parent_names;
+       init->num_parents = 1;
+
+       hw->init = init;
+       *clk_audio_regmap = regmap;
+
+       ret = clk_hw_register(NULL, hw);
+       if (ret)
+               return ret;
+
+       return of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+}
+
+static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np)
+{
+       struct clk_audio_frac *frac_ck;
+       struct clk_init_data init = {};
+
+       frac_ck = kzalloc(sizeof(*frac_ck), GFP_KERNEL);
+       if (!frac_ck)
+               return;
+
+       init.ops = &audio_pll_frac_ops;
+       init.flags = CLK_SET_RATE_GATE;
+
+       if (of_sama5d2_clk_audio_pll_setup(np, &init, &frac_ck->hw,
+                                          &frac_ck->regmap))
+               kfree(frac_ck);
+}
+
+static void __init of_sama5d2_clk_audio_pll_pad_setup(struct device_node *np)
+{
+       struct clk_audio_pad *apad_ck;
+       struct clk_init_data init = {};
+
+       apad_ck = kzalloc(sizeof(*apad_ck), GFP_KERNEL);
+       if (!apad_ck)
+               return;
+
+       init.ops = &audio_pll_pad_ops;
+       init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
+               CLK_SET_RATE_PARENT;
+
+       if (of_sama5d2_clk_audio_pll_setup(np, &init, &apad_ck->hw,
+                                          &apad_ck->regmap))
+               kfree(apad_ck);
+}
+
+static void __init of_sama5d2_clk_audio_pll_pmc_setup(struct device_node *np)
+{
+       struct clk_audio_pad *apmc_ck;
+       struct clk_init_data init = {};
+
+       apmc_ck = kzalloc(sizeof(*apmc_ck), GFP_KERNEL);
+       if (!apmc_ck)
+               return;
+
+       init.ops = &audio_pll_pmc_ops;
+       init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
+               CLK_SET_RATE_PARENT;
+
+       if (of_sama5d2_clk_audio_pll_setup(np, &init, &apmc_ck->hw,
+                                          &apmc_ck->regmap))
+               kfree(apmc_ck);
+}
+
+CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_frac_setup,
+              "atmel,sama5d2-clk-audio-pll-frac",
+              of_sama5d2_clk_audio_pll_frac_setup);
+CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pad_setup,
+              "atmel,sama5d2-clk-audio-pll-pad",
+              of_sama5d2_clk_audio_pll_pad_setup);
+CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup,
+              "atmel,sama5d2-clk-audio-pll-pmc",
+              of_sama5d2_clk_audio_pll_pmc_setup);
index f0b7ae904ce2c991d8a5f998734a77235de194ee..33481368740e7dc038fe1e32065e2659d8cec730 100644 (file)
 #define GENERATED_SOURCE_MAX   6
 #define GENERATED_MAX_DIV      255
 
+#define GCK_ID_SSC0            43
+#define GCK_ID_SSC1            44
+#define GCK_ID_I2S0            54
+#define GCK_ID_I2S1            55
+#define GCK_ID_CLASSD          59
+#define GCK_INDEX_DT_AUDIO_PLL 5
+
 struct clk_generated {
        struct clk_hw hw;
        struct regmap *regmap;
@@ -34,6 +41,7 @@ struct clk_generated {
        u32 id;
        u32 gckdiv;
        u8 parent_id;
+       bool audio_pll_allowed;
 };
 
 #define to_clk_generated(hw) \
@@ -99,21 +107,41 @@ clk_generated_recalc_rate(struct clk_hw *hw,
        return DIV_ROUND_CLOSEST(parent_rate, gck->gckdiv + 1);
 }
 
+static void clk_generated_best_diff(struct clk_rate_request *req,
+                                   struct clk_hw *parent,
+                                   unsigned long parent_rate, u32 div,
+                                   int *best_diff, long *best_rate)
+{
+       unsigned long tmp_rate;
+       int tmp_diff;
+
+       if (!div)
+               tmp_rate = parent_rate;
+       else
+               tmp_rate = parent_rate / div;
+       tmp_diff = abs(req->rate - tmp_rate);
+
+       if (*best_diff < 0 || *best_diff > tmp_diff) {
+               *best_rate = tmp_rate;
+               *best_diff = tmp_diff;
+               req->best_parent_rate = parent_rate;
+               req->best_parent_hw = parent;
+       }
+}
+
 static int clk_generated_determine_rate(struct clk_hw *hw,
                                        struct clk_rate_request *req)
 {
        struct clk_generated *gck = to_clk_generated(hw);
        struct clk_hw *parent = NULL;
+       struct clk_rate_request req_parent = *req;
        long best_rate = -EINVAL;
-       unsigned long tmp_rate, min_rate;
+       unsigned long min_rate, parent_rate;
        int best_diff = -1;
-       int tmp_diff;
        int i;
+       u32 div;
 
-       for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
-               u32 div;
-               unsigned long parent_rate;
-
+       for (i = 0; i < clk_hw_get_num_parents(hw) - 1; i++) {
                parent = clk_hw_get_parent_by_index(hw, i);
                if (!parent)
                        continue;
@@ -124,25 +152,43 @@ static int clk_generated_determine_rate(struct clk_hw *hw,
                    (gck->range.max && min_rate > gck->range.max))
                        continue;
 
-               for (div = 1; div < GENERATED_MAX_DIV + 2; div++) {
-                       tmp_rate = DIV_ROUND_CLOSEST(parent_rate, div);
-                       tmp_diff = abs(req->rate - tmp_rate);
+               div = DIV_ROUND_CLOSEST(parent_rate, req->rate);
 
-                       if (best_diff < 0 || best_diff > tmp_diff) {
-                               best_rate = tmp_rate;
-                               best_diff = tmp_diff;
-                               req->best_parent_rate = parent_rate;
-                               req->best_parent_hw = parent;
-                       }
+               clk_generated_best_diff(req, parent, parent_rate, div,
+                                       &best_diff, &best_rate);
 
-                       if (!best_diff || tmp_rate < req->rate)
-                               break;
-               }
+               if (!best_diff)
+                       break;
+       }
+
+       /*
+        * The audio_pll rate can be modified, unlike the five others clocks
+        * that should never be altered.
+        * The audio_pll can technically be used by multiple consumers. However,
+        * with the rate locking, the first consumer to enable to clock will be
+        * the one definitely setting the rate of the clock.
+        * Since audio IPs are most likely to request the same rate, we enforce
+        * that the only clks able to modify gck rate are those of audio IPs.
+        */
+
+       if (!gck->audio_pll_allowed)
+               goto end;
+
+       parent = clk_hw_get_parent_by_index(hw, GCK_INDEX_DT_AUDIO_PLL);
+       if (!parent)
+               goto end;
+
+       for (div = 1; div < GENERATED_MAX_DIV + 2; div++) {
+               req_parent.rate = req->rate * div;
+               __clk_determine_rate(parent, &req_parent);
+               clk_generated_best_diff(req, parent, req_parent.rate, div,
+                                       &best_diff, &best_rate);
 
                if (!best_diff)
                        break;
        }
 
+end:
        pr_debug("GCLK: %s, best_rate = %ld, parent clk: %s @ %ld\n",
                 __func__, best_rate,
                 __clk_get_name((req->best_parent_hw)->clk),
@@ -252,7 +298,8 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
        init.ops = &generated_ops;
        init.parent_names = parent_names;
        init.num_parents = num_parents;
-       init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
+       init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
+               CLK_SET_RATE_PARENT;
 
        gck->id = id;
        gck->hw.init = &init;
@@ -284,6 +331,7 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
        struct device_node *gcknp;
        struct clk_range range = CLK_RANGE(0, 0);
        struct regmap *regmap;
+       struct clk_generated *gck;
 
        num_parents = of_clk_get_parent_count(np);
        if (num_parents == 0 || num_parents > GENERATED_SOURCE_MAX)
@@ -315,6 +363,21 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
                hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,
                                                  parent_names, num_parents,
                                                  id, &range);
+
+               gck = to_clk_generated(hw);
+
+               if (of_device_is_compatible(np,
+                                           "atmel,sama5d2-clk-generated")) {
+                       if (gck->id == GCK_ID_SSC0 || gck->id == GCK_ID_SSC1 ||
+                           gck->id == GCK_ID_I2S0 || gck->id == GCK_ID_I2S1 ||
+                           gck->id == GCK_ID_CLASSD)
+                               gck->audio_pll_allowed = true;
+                       else
+                               gck->audio_pll_allowed = false;
+               } else {
+                       gck->audio_pll_allowed = false;
+               }
+
                if (IS_ERR(hw))
                        continue;
 
index 01996b871b06ed5a282f3fa65793d0f1804000c0..d747deafbf1e2e2014232c589d7869e4f96fa9b6 100644 (file)
@@ -1 +1,2 @@
 obj-y += i2s_pll_clock.o
+obj-y += pll_clock.o
diff --git a/drivers/clk/axs10x/pll_clock.c b/drivers/clk/axs10x/pll_clock.c
new file mode 100644 (file)
index 0000000..25d8c24
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * Synopsys AXS10X SDP Generic PLL clock driver
+ *
+ * Copyright (C) 2017 Synopsys
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+/* PLL registers addresses */
+#define PLL_REG_IDIV   0x0
+#define PLL_REG_FBDIV  0x4
+#define PLL_REG_ODIV   0x8
+
+/*
+ * Bit fields of the PLL IDIV/FBDIV/ODIV registers:
+ *  ________________________________________________________________________
+ * |31                15|    14    |   13   |  12  |11         6|5         0|
+ * |-------RESRVED------|-NOUPDATE-|-BYPASS-|-EDGE-|--HIGHTIME--|--LOWTIME--|
+ * |____________________|__________|________|______|____________|___________|
+ *
+ * Following macros determine the way of access to these registers
+ * They should be set up only using the macros.
+ * reg should be an u32 variable.
+ */
+
+#define PLL_REG_GET_LOW(reg)                   \
+       (((reg) & (0x3F << 0)) >> 0)
+#define PLL_REG_GET_HIGH(reg)                  \
+       (((reg) & (0x3F << 6)) >> 6)
+#define PLL_REG_GET_EDGE(reg)                  \
+       (((reg) & (BIT(12))) ? 1 : 0)
+#define PLL_REG_GET_BYPASS(reg)                        \
+       (((reg) & (BIT(13))) ? 1 : 0)
+#define PLL_REG_GET_NOUPD(reg)                 \
+       (((reg) & (BIT(14))) ? 1 : 0)
+#define PLL_REG_GET_PAD(reg)                   \
+       (((reg) & (0x1FFFF << 15)) >> 15)
+
+#define PLL_REG_SET_LOW(reg, value)            \
+       { reg |= (((value) & 0x3F) << 0); }
+#define PLL_REG_SET_HIGH(reg, value)           \
+       { reg |= (((value) & 0x3F) << 6); }
+#define PLL_REG_SET_EDGE(reg, value)           \
+       { reg |= (((value) & 0x01) << 12); }
+#define PLL_REG_SET_BYPASS(reg, value)         \
+       { reg |= (((value) & 0x01) << 13); }
+#define PLL_REG_SET_NOUPD(reg, value)          \
+       { reg |= (((value) & 0x01) << 14); }
+#define PLL_REG_SET_PAD(reg, value)            \
+       { reg |= (((value) & 0x1FFFF) << 15); }
+
+#define PLL_LOCK       BIT(0)
+#define PLL_ERROR      BIT(1)
+#define PLL_MAX_LOCK_TIME 100 /* 100 us */
+
+struct axs10x_pll_cfg {
+       u32 rate;
+       u32 idiv;
+       u32 fbdiv;
+       u32 odiv;
+};
+
+static const struct axs10x_pll_cfg arc_pll_cfg[] = {
+       { 33333333,  1, 1,  1 },
+       { 50000000,  1, 30, 20 },
+       { 75000000,  2, 45, 10 },
+       { 90000000,  2, 54, 10 },
+       { 100000000, 1, 30, 10 },
+       { 125000000, 2, 45, 6 },
+       {}
+};
+
+static const struct axs10x_pll_cfg pgu_pll_cfg[] = {
+       { 25200000, 1, 84, 90 },
+       { 50000000, 1, 100, 54 },
+       { 74250000, 1, 44, 16 },
+       {}
+};
+
+struct axs10x_pll_clk {
+       struct clk_hw hw;
+       void __iomem *base;
+       void __iomem *lock;
+       const struct axs10x_pll_cfg *pll_cfg;
+       struct device *dev;
+};
+
+static inline void axs10x_pll_write(struct axs10x_pll_clk *clk, u32 reg,
+                                   u32 val)
+{
+       iowrite32(val, clk->base + reg);
+}
+
+static inline u32 axs10x_pll_read(struct axs10x_pll_clk *clk, u32 reg)
+{
+       return ioread32(clk->base + reg);
+}
+
+static inline struct axs10x_pll_clk *to_axs10x_pll_clk(struct clk_hw *hw)
+{
+       return container_of(hw, struct axs10x_pll_clk, hw);
+}
+
+static inline u32 axs10x_div_get_value(u32 reg)
+{
+       if (PLL_REG_GET_BYPASS(reg))
+               return 1;
+
+       return PLL_REG_GET_HIGH(reg) + PLL_REG_GET_LOW(reg);
+}
+
+static inline u32 axs10x_encode_div(unsigned int id, int upd)
+{
+       u32 div = 0;
+
+       PLL_REG_SET_LOW(div, (id % 2 == 0) ? id >> 1 : (id >> 1) + 1);
+       PLL_REG_SET_HIGH(div, id >> 1);
+       PLL_REG_SET_EDGE(div, id % 2);
+       PLL_REG_SET_BYPASS(div, id == 1 ? 1 : 0);
+       PLL_REG_SET_NOUPD(div, upd == 0 ? 1 : 0);
+
+       return div;
+}
+
+static unsigned long axs10x_pll_recalc_rate(struct clk_hw *hw,
+                                           unsigned long parent_rate)
+{
+       u64 rate;
+       u32 idiv, fbdiv, odiv;
+       struct axs10x_pll_clk *clk = to_axs10x_pll_clk(hw);
+
+       idiv = axs10x_div_get_value(axs10x_pll_read(clk, PLL_REG_IDIV));
+       fbdiv = axs10x_div_get_value(axs10x_pll_read(clk, PLL_REG_FBDIV));
+       odiv = axs10x_div_get_value(axs10x_pll_read(clk, PLL_REG_ODIV));
+
+       rate = (u64)parent_rate * fbdiv;
+       do_div(rate, idiv * odiv);
+
+       return rate;
+}
+
+static long axs10x_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+                                 unsigned long *prate)
+{
+       int i;
+       long best_rate;
+       struct axs10x_pll_clk *clk = to_axs10x_pll_clk(hw);
+       const struct axs10x_pll_cfg *pll_cfg = clk->pll_cfg;
+
+       if (pll_cfg[0].rate == 0)
+               return -EINVAL;
+
+       best_rate = pll_cfg[0].rate;
+
+       for (i = 1; pll_cfg[i].rate != 0; i++) {
+               if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate))
+                       best_rate = pll_cfg[i].rate;
+       }
+
+       return best_rate;
+}
+
+static int axs10x_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+                              unsigned long parent_rate)
+{
+       int i;
+       struct axs10x_pll_clk *clk = to_axs10x_pll_clk(hw);
+       const struct axs10x_pll_cfg *pll_cfg = clk->pll_cfg;
+
+       for (i = 0; pll_cfg[i].rate != 0; i++) {
+               if (pll_cfg[i].rate == rate) {
+                       axs10x_pll_write(clk, PLL_REG_IDIV,
+                                        axs10x_encode_div(pll_cfg[i].idiv, 0));
+                       axs10x_pll_write(clk, PLL_REG_FBDIV,
+                                        axs10x_encode_div(pll_cfg[i].fbdiv, 0));
+                       axs10x_pll_write(clk, PLL_REG_ODIV,
+                                        axs10x_encode_div(pll_cfg[i].odiv, 1));
+
+                       /*
+                        * Wait until CGU relocks and check error status.
+                        * If after timeout CGU is unlocked yet return error
+                        */
+                       udelay(PLL_MAX_LOCK_TIME);
+                       if (!(ioread32(clk->lock) & PLL_LOCK))
+                               return -ETIMEDOUT;
+
+                       if (ioread32(clk->lock) & PLL_ERROR)
+                               return -EINVAL;
+
+                       return 0;
+               }
+       }
+
+       dev_err(clk->dev, "invalid rate=%ld, parent_rate=%ld\n", rate,
+                       parent_rate);
+       return -EINVAL;
+}
+
+static const struct clk_ops axs10x_pll_ops = {
+       .recalc_rate = axs10x_pll_recalc_rate,
+       .round_rate = axs10x_pll_round_rate,
+       .set_rate = axs10x_pll_set_rate,
+};
+
+static int axs10x_pll_clk_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       const char *parent_name;
+       struct axs10x_pll_clk *pll_clk;
+       struct resource *mem;
+       struct clk_init_data init = { };
+       int ret;
+
+       pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL);
+       if (!pll_clk)
+               return -ENOMEM;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       pll_clk->base = devm_ioremap_resource(dev, mem);
+       if (IS_ERR(pll_clk->base))
+               return PTR_ERR(pll_clk->base);
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       pll_clk->lock = devm_ioremap_resource(dev, mem);
+       if (IS_ERR(pll_clk->lock))
+               return PTR_ERR(pll_clk->lock);
+
+       init.name = dev->of_node->name;
+       init.ops = &axs10x_pll_ops;
+       parent_name = of_clk_get_parent_name(dev->of_node, 0);
+       init.parent_names = &parent_name;
+       init.num_parents = 1;
+       pll_clk->hw.init = &init;
+       pll_clk->dev = dev;
+       pll_clk->pll_cfg = of_device_get_match_data(dev);
+
+       if (!pll_clk->pll_cfg) {
+               dev_err(dev, "No OF match data provided\n");
+               return -EINVAL;
+       }
+
+       ret = devm_clk_hw_register(dev, &pll_clk->hw);
+       if (ret) {
+               dev_err(dev, "failed to register %s clock\n", init.name);
+               return ret;
+       }
+
+       return of_clk_add_hw_provider(dev->of_node, of_clk_hw_simple_get,
+                       &pll_clk->hw);
+}
+
+static int axs10x_pll_clk_remove(struct platform_device *pdev)
+{
+       of_clk_del_provider(pdev->dev.of_node);
+       return 0;
+}
+
+static void __init of_axs10x_pll_clk_setup(struct device_node *node)
+{
+       const char *parent_name;
+       struct axs10x_pll_clk *pll_clk;
+       struct clk_init_data init = { };
+       int ret;
+
+       pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
+       if (!pll_clk)
+               return;
+
+       pll_clk->base = of_iomap(node, 0);
+       if (!pll_clk->base) {
+               pr_err("failed to map pll div registers\n");
+               goto err_free_pll_clk;
+       }
+
+       pll_clk->lock = of_iomap(node, 1);
+       if (!pll_clk->lock) {
+               pr_err("failed to map pll lock register\n");
+               goto err_unmap_base;
+       }
+
+       init.name = node->name;
+       init.ops = &axs10x_pll_ops;
+       parent_name = of_clk_get_parent_name(node, 0);
+       init.parent_names = &parent_name;
+       init.num_parents = parent_name ? 1 : 0;
+       pll_clk->hw.init = &init;
+       pll_clk->pll_cfg = arc_pll_cfg;
+
+       ret = clk_hw_register(NULL, &pll_clk->hw);
+       if (ret) {
+               pr_err("failed to register %s clock\n", node->name);
+               goto err_unmap_lock;
+       }
+
+       ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &pll_clk->hw);
+       if (ret) {
+               pr_err("failed to add hw provider for %s clock\n", node->name);
+               goto err_unregister_clk;
+       }
+
+       return;
+
+err_unregister_clk:
+       clk_hw_unregister(&pll_clk->hw);
+err_unmap_lock:
+       iounmap(pll_clk->lock);
+err_unmap_base:
+       iounmap(pll_clk->base);
+err_free_pll_clk:
+       kfree(pll_clk);
+}
+CLK_OF_DECLARE(axs10x_pll_clock, "snps,axs10x-arc-pll-clock",
+              of_axs10x_pll_clk_setup);
+
+static const struct of_device_id axs10x_pll_clk_id[] = {
+       { .compatible = "snps,axs10x-pgu-pll-clock", .data = &pgu_pll_cfg},
+       { }
+};
+MODULE_DEVICE_TABLE(of, axs10x_pll_clk_id);
+
+static struct platform_driver axs10x_pll_clk_driver = {
+       .driver = {
+               .name = "axs10x-pll-clock",
+               .of_match_table = axs10x_pll_clk_id,
+       },
+       .probe = axs10x_pll_clk_probe,
+       .remove = axs10x_pll_clk_remove,
+};
+builtin_platform_driver(axs10x_pll_clk_driver);
+
+MODULE_AUTHOR("Vlad Zakharov <vzakhar@synopsys.com>");
+MODULE_DESCRIPTION("Synopsys AXS10X SDP Generic PLL Clock Driver");
+MODULE_LICENSE("GPL v2");
index 1d99292e2039ee5ff6e187e4e0cdbddf85d860e1..e7331ace0337cc564bb3b3114d4f21063f8a849f 100644 (file)
@@ -679,8 +679,7 @@ static void __init berlin2_clock_setup(struct device_node *np)
                if (!IS_ERR(hws[n]))
                        continue;
 
-               pr_err("%s: Unable to register leaf clock %d\n",
-                      np->full_name, n);
+               pr_err("%pOF: Unable to register leaf clock %d\n", np, n);
                goto bg2_fail;
        }
 
index 3b784b593afde7fea97650f938b03c55c79d8ac0..67c270b143f7280da78a8524c32619b7fdb1d73d 100644 (file)
@@ -304,14 +304,14 @@ static void __init berlin2q_clock_setup(struct device_node *np)
 
        gbase = of_iomap(parent_np, 0);
        if (!gbase) {
-               pr_err("%s: Unable to map global base\n", np->full_name);
+               pr_err("%pOF: Unable to map global base\n", np);
                return;
        }
 
        /* BG2Q CPU PLL is not part of global registers */
        cpupll_base = of_iomap(parent_np, 1);
        if (!cpupll_base) {
-               pr_err("%s: Unable to map cpupll base\n", np->full_name);
+               pr_err("%pOF: Unable to map cpupll base\n", np);
                iounmap(gbase);
                return;
        }
@@ -376,8 +376,7 @@ static void __init berlin2q_clock_setup(struct device_node *np)
                if (!IS_ERR(hws[n]))
                        continue;
 
-               pr_err("%s: Unable to register leaf clock %d\n",
-                      np->full_name, n);
+               pr_err("%pOF: Unable to register leaf clock %d\n", np, n);
                goto bg2q_fail;
        }
 
index ea8568536193ba3c59db95e904ceb8ad75e034d2..bf0582cbbf38e31aeaa6aca5a466d79db07adce2 100644 (file)
@@ -338,8 +338,8 @@ static void __init asm9260_acc_init(struct device_node *np)
                if (!IS_ERR(hws[n]))
                        continue;
 
-               pr_err("%s: Unable to register leaf clock %d\n",
-                               np->full_name, n);
+               pr_err("%pOF: Unable to register leaf clock %d\n",
+                               np, n);
                goto fail;
        }
 
index 7ec36722f8ab0f4cac82b18a91283696268c781f..49819b546134bfa4794d513ce0d6fb5d2e6e609d 100644 (file)
@@ -23,8 +23,8 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier)
        num_parents = of_count_phandle_with_args(node, "assigned-clock-parents",
                                                 "#clock-cells");
        if (num_parents == -EINVAL)
-               pr_err("clk: invalid value of clock-parents property at %s\n",
-                      node->full_name);
+               pr_err("clk: invalid value of clock-parents property at %pOF\n",
+                      node);
 
        for (index = 0; index < num_parents; index++) {
                rc = of_parse_phandle_with_args(node, "assigned-clock-parents",
@@ -41,8 +41,8 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier)
                pclk = of_clk_get_from_provider(&clkspec);
                if (IS_ERR(pclk)) {
                        if (PTR_ERR(pclk) != -EPROBE_DEFER)
-                               pr_warn("clk: couldn't get parent clock %d for %s\n",
-                                       index, node->full_name);
+                               pr_warn("clk: couldn't get parent clock %d for %pOF\n",
+                                       index, node);
                        return PTR_ERR(pclk);
                }
 
@@ -57,8 +57,8 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier)
                clk = of_clk_get_from_provider(&clkspec);
                if (IS_ERR(clk)) {
                        if (PTR_ERR(clk) != -EPROBE_DEFER)
-                               pr_warn("clk: couldn't get assigned clock %d for %s\n",
-                                       index, node->full_name);
+                               pr_warn("clk: couldn't get assigned clock %d for %pOF\n",
+                                       index, node);
                        rc = PTR_ERR(clk);
                        goto err;
                }
@@ -102,8 +102,8 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier)
                        clk = of_clk_get_from_provider(&clkspec);
                        if (IS_ERR(clk)) {
                                if (PTR_ERR(clk) != -EPROBE_DEFER)
-                                       pr_warn("clk: couldn't get clock %d for %s\n",
-                                               index, node->full_name);
+                                       pr_warn("clk: couldn't get clock %d for %pOF\n",
+                                               index, node);
                                return PTR_ERR(clk);
                        }
 
index c54baede4d68733ad2861b24e24c0f082aa5520e..e8ea81c30f0ccd290ea9fa7b66750b889c23a8df 100644 (file)
@@ -343,6 +343,15 @@ static int cs2000_set_rate(struct clk_hw *hw,
        return __cs2000_set_rate(priv, ch, rate, parent_rate);
 }
 
+static int cs2000_set_saved_rate(struct cs2000_priv *priv)
+{
+       int ch = 0; /* it uses ch0 only at this point */
+
+       return __cs2000_set_rate(priv, ch,
+                                priv->saved_rate,
+                                priv->saved_parent_rate);
+}
+
 static int cs2000_enable(struct clk_hw *hw)
 {
        struct cs2000_priv *priv = hw_to_priv(hw);
@@ -535,11 +544,8 @@ probe_err:
 static int cs2000_resume(struct device *dev)
 {
        struct cs2000_priv *priv = dev_get_drvdata(dev);
-       int ch = 0; /* it uses ch0 only at this point */
 
-       return __cs2000_set_rate(priv, ch,
-                                priv->saved_rate,
-                                priv->saved_parent_rate);
+       return cs2000_set_saved_rate(priv);
 }
 
 static const struct dev_pm_ops cs2000_pm_ops = {
index 9bb472cccca6e044e46bebc0ec57f4c74641b11b..4ed516cb72764a18a29f8cd77efcc81aa7087c47 100644 (file)
@@ -385,12 +385,14 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
                                unsigned long parent_rate)
 {
        struct clk_divider *divider = to_clk_divider(hw);
-       unsigned int value;
+       int value;
        unsigned long flags = 0;
        u32 val;
 
        value = divider_get_val(rate, parent_rate, divider->table,
                                divider->width, divider->flags);
+       if (value < 0)
+               return value;
 
        if (divider->lock)
                spin_lock_irqsave(divider->lock, flags);
@@ -403,7 +405,7 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
                val = clk_readl(divider->reg);
                val &= ~(div_mask(divider->width) << divider->shift);
        }
-       val |= value << divider->shift;
+       val |= (u32)value << divider->shift;
        clk_writel(val, divider->reg);
 
        if (divider->lock)
index aab904618eb636f9f926a6b7b46d7b03b780b10c..fdf625fb10faa03fc8c394555612fdcdf855ac09 100644 (file)
@@ -49,16 +49,12 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
        return ret;
 }
 
-static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
-                             unsigned long *parent_rate)
+static void clk_fd_general_approximation(struct clk_hw *hw, unsigned long rate,
+                                        unsigned long *parent_rate,
+                                        unsigned long *m, unsigned long *n)
 {
        struct clk_fractional_divider *fd = to_clk_fd(hw);
        unsigned long scale;
-       unsigned long m, n;
-       u64 ret;
-
-       if (!rate || rate >= *parent_rate)
-               return *parent_rate;
 
        /*
         * Get rate closer to *parent_rate to guarantee there is no overflow
@@ -71,7 +67,23 @@ static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
 
        rational_best_approximation(rate, *parent_rate,
                        GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
-                       &m, &n);
+                       m, n);
+}
+
+static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
+                             unsigned long *parent_rate)
+{
+       struct clk_fractional_divider *fd = to_clk_fd(hw);
+       unsigned long m, n;
+       u64 ret;
+
+       if (!rate || rate >= *parent_rate)
+               return *parent_rate;
+
+       if (fd->approximation)
+               fd->approximation(hw, rate, parent_rate, &m, &n);
+       else
+               clk_fd_general_approximation(hw, rate, parent_rate, &m, &n);
 
        ret = (u64)*parent_rate * m;
        do_div(ret, n);
index 4e0c054a787c07f93c287c4d38b306dffd3ee409..dd82485e09a1f9cac9d4652a4def98bb0eaa6110 100644 (file)
@@ -86,7 +86,7 @@ static void clk_gate_disable(struct clk_hw *hw)
        clk_gate_endisable(hw, 0);
 }
 
-static int clk_gate_is_enabled(struct clk_hw *hw)
+int clk_gate_is_enabled(struct clk_hw *hw)
 {
        u32 reg;
        struct clk_gate *gate = to_clk_gate(hw);
@@ -101,6 +101,7 @@ static int clk_gate_is_enabled(struct clk_hw *hw)
 
        return reg ? 1 : 0;
 }
+EXPORT_SYMBOL_GPL(clk_gate_is_enabled);
 
 const struct clk_ops clk_gate_ops = {
        .enable = clk_gate_enable,
index b4cf2f699a21024b727aabcb5a265fb0d613e817..f940e5af845b8d71eabe0bd2e20de20a1cb3f25e 100644 (file)
@@ -37,7 +37,6 @@ static DEFINE_SPINLOCK(gemini_clk_lock);
 
 #define GEMINI_GLOBAL_MISC_CONTROL     0x30
 #define PCI_CLK_66MHZ                  BIT(18)
-#define PCI_CLK_OE                     BIT(17)
 
 #define GEMINI_GLOBAL_CLOCK_CONTROL    0x34
 #define PCI_CLKRUN_EN                  BIT(16)
@@ -159,9 +158,6 @@ static int gemini_pci_enable(struct clk_hw *hw)
 
        regmap_update_bits(pciclk->map, GEMINI_GLOBAL_CLOCK_CONTROL,
                           0, PCI_CLKRUN_EN);
-       regmap_update_bits(pciclk->map,
-                          GEMINI_GLOBAL_MISC_CONTROL,
-                          0, PCI_CLK_OE);
        return 0;
 }
 
@@ -169,9 +165,6 @@ static void gemini_pci_disable(struct clk_hw *hw)
 {
        struct clk_gemini_pci *pciclk = to_pciclk(hw);
 
-       regmap_update_bits(pciclk->map,
-                          GEMINI_GLOBAL_MISC_CONTROL,
-                          PCI_CLK_OE, 0);
        regmap_update_bits(pciclk->map, GEMINI_GLOBAL_CLOCK_CONTROL,
                           PCI_CLKRUN_EN, 0);
 }
diff --git a/drivers/clk/clk-hsdk-pll.c b/drivers/clk/clk-hsdk-pll.c
new file mode 100644 (file)
index 0000000..bbf2371
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * Synopsys HSDK SDP Generic PLL clock driver
+ *
+ * Copyright (C) 2017 Synopsys
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define CGU_PLL_CTRL   0x000 /* ARC PLL control register */
+#define CGU_PLL_STATUS 0x004 /* ARC PLL status register */
+#define CGU_PLL_FMEAS  0x008 /* ARC PLL frequency measurement register */
+#define CGU_PLL_MON    0x00C /* ARC PLL monitor register */
+
+#define CGU_PLL_CTRL_ODIV_SHIFT                2
+#define CGU_PLL_CTRL_IDIV_SHIFT                4
+#define CGU_PLL_CTRL_FBDIV_SHIFT       9
+#define CGU_PLL_CTRL_BAND_SHIFT                20
+
+#define CGU_PLL_CTRL_ODIV_MASK         GENMASK(3, CGU_PLL_CTRL_ODIV_SHIFT)
+#define CGU_PLL_CTRL_IDIV_MASK         GENMASK(8, CGU_PLL_CTRL_IDIV_SHIFT)
+#define CGU_PLL_CTRL_FBDIV_MASK                GENMASK(15, CGU_PLL_CTRL_FBDIV_SHIFT)
+
+#define CGU_PLL_CTRL_PD                        BIT(0)
+#define CGU_PLL_CTRL_BYPASS            BIT(1)
+
+#define CGU_PLL_STATUS_LOCK            BIT(0)
+#define CGU_PLL_STATUS_ERR             BIT(1)
+
+#define HSDK_PLL_MAX_LOCK_TIME         100 /* 100 us */
+
+#define CGU_PLL_SOURCE_MAX             1
+
+#define CORE_IF_CLK_THRESHOLD_HZ       500000000
+#define CREG_CORE_IF_CLK_DIV_1         0x0
+#define CREG_CORE_IF_CLK_DIV_2         0x1
+
+struct hsdk_pll_cfg {
+       u32 rate;
+       u32 idiv;
+       u32 fbdiv;
+       u32 odiv;
+       u32 band;
+};
+
+static const struct hsdk_pll_cfg asdt_pll_cfg[] = {
+       { 100000000,  0, 11, 3, 0 },
+       { 133000000,  0, 15, 3, 0 },
+       { 200000000,  1, 47, 3, 0 },
+       { 233000000,  1, 27, 2, 0 },
+       { 300000000,  1, 35, 2, 0 },
+       { 333000000,  1, 39, 2, 0 },
+       { 400000000,  1, 47, 2, 0 },
+       { 500000000,  0, 14, 1, 0 },
+       { 600000000,  0, 17, 1, 0 },
+       { 700000000,  0, 20, 1, 0 },
+       { 800000000,  0, 23, 1, 0 },
+       { 900000000,  1, 26, 0, 0 },
+       { 1000000000, 1, 29, 0, 0 },
+       { 1100000000, 1, 32, 0, 0 },
+       { 1200000000, 1, 35, 0, 0 },
+       { 1300000000, 1, 38, 0, 0 },
+       { 1400000000, 1, 41, 0, 0 },
+       { 1500000000, 1, 44, 0, 0 },
+       { 1600000000, 1, 47, 0, 0 },
+       {}
+};
+
+static const struct hsdk_pll_cfg hdmi_pll_cfg[] = {
+       { 297000000,  0, 21, 2, 0 },
+       { 540000000,  0, 19, 1, 0 },
+       { 594000000,  0, 21, 1, 0 },
+       {}
+};
+
+struct hsdk_pll_clk {
+       struct clk_hw hw;
+       void __iomem *regs;
+       void __iomem *spec_regs;
+       const struct hsdk_pll_devdata *pll_devdata;
+       struct device *dev;
+};
+
+struct hsdk_pll_devdata {
+       const struct hsdk_pll_cfg *pll_cfg;
+       int (*update_rate)(struct hsdk_pll_clk *clk, unsigned long rate,
+                          const struct hsdk_pll_cfg *cfg);
+};
+
+static int hsdk_pll_core_update_rate(struct hsdk_pll_clk *, unsigned long,
+                                    const struct hsdk_pll_cfg *);
+static int hsdk_pll_comm_update_rate(struct hsdk_pll_clk *, unsigned long,
+                                    const struct hsdk_pll_cfg *);
+
+static const struct hsdk_pll_devdata core_pll_devdata = {
+       .pll_cfg = asdt_pll_cfg,
+       .update_rate = hsdk_pll_core_update_rate,
+};
+
+static const struct hsdk_pll_devdata sdt_pll_devdata = {
+       .pll_cfg = asdt_pll_cfg,
+       .update_rate = hsdk_pll_comm_update_rate,
+};
+
+static const struct hsdk_pll_devdata hdmi_pll_devdata = {
+       .pll_cfg = hdmi_pll_cfg,
+       .update_rate = hsdk_pll_comm_update_rate,
+};
+
+static inline void hsdk_pll_write(struct hsdk_pll_clk *clk, u32 reg, u32 val)
+{
+       iowrite32(val, clk->regs + reg);
+}
+
+static inline u32 hsdk_pll_read(struct hsdk_pll_clk *clk, u32 reg)
+{
+       return ioread32(clk->regs + reg);
+}
+
+static inline void hsdk_pll_set_cfg(struct hsdk_pll_clk *clk,
+                                   const struct hsdk_pll_cfg *cfg)
+{
+       u32 val = 0;
+
+       /* Powerdown and Bypass bits should be cleared */
+       val |= cfg->idiv << CGU_PLL_CTRL_IDIV_SHIFT;
+       val |= cfg->fbdiv << CGU_PLL_CTRL_FBDIV_SHIFT;
+       val |= cfg->odiv << CGU_PLL_CTRL_ODIV_SHIFT;
+       val |= cfg->band << CGU_PLL_CTRL_BAND_SHIFT;
+
+       dev_dbg(clk->dev, "write configurarion: %#x\n", val);
+
+       hsdk_pll_write(clk, CGU_PLL_CTRL, val);
+}
+
+static inline bool hsdk_pll_is_locked(struct hsdk_pll_clk *clk)
+{
+       return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_LOCK);
+}
+
+static inline bool hsdk_pll_is_err(struct hsdk_pll_clk *clk)
+{
+       return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_ERR);
+}
+
+static inline struct hsdk_pll_clk *to_hsdk_pll_clk(struct clk_hw *hw)
+{
+       return container_of(hw, struct hsdk_pll_clk, hw);
+}
+
+static unsigned long hsdk_pll_recalc_rate(struct clk_hw *hw,
+                                         unsigned long parent_rate)
+{
+       u32 val;
+       u64 rate;
+       u32 idiv, fbdiv, odiv;
+       struct hsdk_pll_clk *clk = to_hsdk_pll_clk(hw);
+
+       val = hsdk_pll_read(clk, CGU_PLL_CTRL);
+
+       dev_dbg(clk->dev, "current configurarion: %#x\n", val);
+
+       /* Check if PLL is disabled */
+       if (val & CGU_PLL_CTRL_PD)
+               return 0;
+
+       /* Check if PLL is bypassed */
+       if (val & CGU_PLL_CTRL_BYPASS)
+               return parent_rate;
+
+       /* input divider = reg.idiv + 1 */
+       idiv = 1 + ((val & CGU_PLL_CTRL_IDIV_MASK) >> CGU_PLL_CTRL_IDIV_SHIFT);
+       /* fb divider = 2*(reg.fbdiv + 1) */
+       fbdiv = 2 * (1 + ((val & CGU_PLL_CTRL_FBDIV_MASK) >> CGU_PLL_CTRL_FBDIV_SHIFT));
+       /* output divider = 2^(reg.odiv) */
+       odiv = 1 << ((val & CGU_PLL_CTRL_ODIV_MASK) >> CGU_PLL_CTRL_ODIV_SHIFT);
+
+       rate = (u64)parent_rate * fbdiv;
+       do_div(rate, idiv * odiv);
+
+       return rate;
+}
+
+static long hsdk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+                               unsigned long *prate)
+{
+       int i;
+       unsigned long best_rate;
+       struct hsdk_pll_clk *clk = to_hsdk_pll_clk(hw);
+       const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg;
+
+       if (pll_cfg[0].rate == 0)
+               return -EINVAL;
+
+       best_rate = pll_cfg[0].rate;
+
+       for (i = 1; pll_cfg[i].rate != 0; i++) {
+               if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate))
+                       best_rate = pll_cfg[i].rate;
+       }
+
+       dev_dbg(clk->dev, "chosen best rate: %lu\n", best_rate);
+
+       return best_rate;
+}
+
+static int hsdk_pll_comm_update_rate(struct hsdk_pll_clk *clk,
+                                    unsigned long rate,
+                                    const struct hsdk_pll_cfg *cfg)
+{
+       hsdk_pll_set_cfg(clk, cfg);
+
+       /*
+        * Wait until CGU relocks and check error status.
+        * If after timeout CGU is unlocked yet return error.
+        */
+       udelay(HSDK_PLL_MAX_LOCK_TIME);
+       if (!hsdk_pll_is_locked(clk))
+               return -ETIMEDOUT;
+
+       if (hsdk_pll_is_err(clk))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int hsdk_pll_core_update_rate(struct hsdk_pll_clk *clk,
+                                    unsigned long rate,
+                                    const struct hsdk_pll_cfg *cfg)
+{
+       /*
+        * When core clock exceeds 500MHz, the divider for the interface
+        * clock must be programmed to div-by-2.
+        */
+       if (rate > CORE_IF_CLK_THRESHOLD_HZ)
+               iowrite32(CREG_CORE_IF_CLK_DIV_2, clk->spec_regs);
+
+       hsdk_pll_set_cfg(clk, cfg);
+
+       /*
+        * Wait until CGU relocks and check error status.
+        * If after timeout CGU is unlocked yet return error.
+        */
+       udelay(HSDK_PLL_MAX_LOCK_TIME);
+       if (!hsdk_pll_is_locked(clk))
+               return -ETIMEDOUT;
+
+       if (hsdk_pll_is_err(clk))
+               return -EINVAL;
+
+       /*
+        * Program divider to div-by-1 if we succesfuly set core clock below
+        * 500MHz threshold.
+        */
+       if (rate <= CORE_IF_CLK_THRESHOLD_HZ)
+               iowrite32(CREG_CORE_IF_CLK_DIV_1, clk->spec_regs);
+
+       return 0;
+}
+
+static int hsdk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+                            unsigned long parent_rate)
+{
+       int i;
+       struct hsdk_pll_clk *clk = to_hsdk_pll_clk(hw);
+       const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg;
+
+       for (i = 0; pll_cfg[i].rate != 0; i++) {
+               if (pll_cfg[i].rate == rate) {
+                       return clk->pll_devdata->update_rate(clk, rate,
+                                                            &pll_cfg[i]);
+               }
+       }
+
+       dev_err(clk->dev, "invalid rate=%ld, parent_rate=%ld\n", rate,
+                       parent_rate);
+
+       return -EINVAL;
+}
+
+static const struct clk_ops hsdk_pll_ops = {
+       .recalc_rate = hsdk_pll_recalc_rate,
+       .round_rate = hsdk_pll_round_rate,
+       .set_rate = hsdk_pll_set_rate,
+};
+
+static int hsdk_pll_clk_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct resource *mem;
+       const char *parent_name;
+       unsigned int num_parents;
+       struct hsdk_pll_clk *pll_clk;
+       struct clk_init_data init = { };
+       struct device *dev = &pdev->dev;
+
+       pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL);
+       if (!pll_clk)
+               return -ENOMEM;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       pll_clk->regs = devm_ioremap_resource(dev, mem);
+       if (IS_ERR(pll_clk->regs))
+               return PTR_ERR(pll_clk->regs);
+
+       init.name = dev->of_node->name;
+       init.ops = &hsdk_pll_ops;
+       parent_name = of_clk_get_parent_name(dev->of_node, 0);
+       init.parent_names = &parent_name;
+       num_parents = of_clk_get_parent_count(dev->of_node);
+       if (num_parents == 0 || num_parents > CGU_PLL_SOURCE_MAX) {
+               dev_err(dev, "wrong clock parents number: %u\n", num_parents);
+               return -EINVAL;
+       }
+       init.num_parents = num_parents;
+
+       pll_clk->hw.init = &init;
+       pll_clk->dev = dev;
+       pll_clk->pll_devdata = of_device_get_match_data(dev);
+
+       if (!pll_clk->pll_devdata) {
+               dev_err(dev, "No OF match data provided\n");
+               return -EINVAL;
+       }
+
+       ret = devm_clk_hw_register(dev, &pll_clk->hw);
+       if (ret) {
+               dev_err(dev, "failed to register %s clock\n", init.name);
+               return ret;
+       }
+
+       return of_clk_add_hw_provider(dev->of_node, of_clk_hw_simple_get,
+                       &pll_clk->hw);
+}
+
+static int hsdk_pll_clk_remove(struct platform_device *pdev)
+{
+       of_clk_del_provider(pdev->dev.of_node);
+       return 0;
+}
+
+static void __init of_hsdk_pll_clk_setup(struct device_node *node)
+{
+       int ret;
+       const char *parent_name;
+       unsigned int num_parents;
+       struct hsdk_pll_clk *pll_clk;
+       struct clk_init_data init = { };
+
+       pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
+       if (!pll_clk)
+               return;
+
+       pll_clk->regs = of_iomap(node, 0);
+       if (!pll_clk->regs) {
+               pr_err("failed to map pll registers\n");
+               goto err_free_pll_clk;
+       }
+
+       pll_clk->spec_regs = of_iomap(node, 1);
+       if (!pll_clk->spec_regs) {
+               pr_err("failed to map pll registers\n");
+               goto err_unmap_comm_regs;
+       }
+
+       init.name = node->name;
+       init.ops = &hsdk_pll_ops;
+       parent_name = of_clk_get_parent_name(node, 0);
+       init.parent_names = &parent_name;
+       num_parents = of_clk_get_parent_count(node);
+       if (num_parents > CGU_PLL_SOURCE_MAX) {
+               pr_err("too much clock parents: %u\n", num_parents);
+               goto err_unmap_spec_regs;
+       }
+       init.num_parents = num_parents;
+
+       pll_clk->hw.init = &init;
+       pll_clk->pll_devdata = &core_pll_devdata;
+
+       ret = clk_hw_register(NULL, &pll_clk->hw);
+       if (ret) {
+               pr_err("failed to register %s clock\n", node->name);
+               goto err_unmap_spec_regs;
+       }
+
+       ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &pll_clk->hw);
+       if (ret) {
+               pr_err("failed to add hw provider for %s clock\n", node->name);
+               goto err_unmap_spec_regs;
+       }
+
+       return;
+
+err_unmap_spec_regs:
+       iounmap(pll_clk->spec_regs);
+err_unmap_comm_regs:
+       iounmap(pll_clk->regs);
+err_free_pll_clk:
+       kfree(pll_clk);
+}
+
+/* Core PLL needed early for ARC cpus timers */
+CLK_OF_DECLARE(hsdk_pll_clock, "snps,hsdk-core-pll-clock",
+of_hsdk_pll_clk_setup);
+
+static const struct of_device_id hsdk_pll_clk_id[] = {
+       { .compatible = "snps,hsdk-gp-pll-clock", .data = &sdt_pll_devdata},
+       { .compatible = "snps,hsdk-hdmi-pll-clock", .data = &hdmi_pll_devdata},
+       { }
+};
+
+static struct platform_driver hsdk_pll_clk_driver = {
+       .driver = {
+               .name = "hsdk-gp-pll-clock",
+               .of_match_table = hsdk_pll_clk_id,
+       },
+       .probe = hsdk_pll_clk_probe,
+       .remove = hsdk_pll_clk_remove,
+};
+builtin_platform_driver(hsdk_pll_clk_driver);
diff --git a/drivers/clk/clk-mb86s7x.c b/drivers/clk/clk-mb86s7x.c
deleted file mode 100644 (file)
index 2a83a3f..0000000
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * Copyright (C) 2013-2015 FUJITSU SEMICONDUCTOR LIMITED
- * Copyright (C) 2015 Linaro Ltd.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/clkdev.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/cpu.h>
-#include <linux/clk-provider.h>
-#include <linux/spinlock.h>
-#include <linux/module.h>
-#include <linux/topology.h>
-#include <linux/mailbox_client.h>
-#include <linux/platform_device.h>
-
-#include <soc/mb86s7x/scb_mhu.h>
-
-#define to_crg_clk(p) container_of(p, struct crg_clk, hw)
-#define to_clc_clk(p) container_of(p, struct cl_clk, hw)
-
-struct mb86s7x_peri_clk {
-       u32 payload_size;
-       u32 cntrlr;
-       u32 domain;
-       u32 port;
-       u32 en;
-       u64 frequency;
-} __packed __aligned(4);
-
-struct hack_rate {
-       unsigned clk_id;
-       unsigned long rate;
-       int gated;
-};
-
-struct crg_clk {
-       struct clk_hw hw;
-       u8 cntrlr, domain, port;
-};
-
-static int crg_gate_control(struct clk_hw *hw, int en)
-{
-       struct crg_clk *crgclk = to_crg_clk(hw);
-       struct mb86s7x_peri_clk cmd;
-       int ret;
-
-       cmd.payload_size = sizeof(cmd);
-       cmd.cntrlr = crgclk->cntrlr;
-       cmd.domain = crgclk->domain;
-       cmd.port = crgclk->port;
-       cmd.en = en;
-
-       /* Port is UngatedCLK */
-       if (cmd.port == 8)
-               return en ? 0 : -EINVAL;
-
-       pr_debug("%s:%d CMD Cntrlr-%u Dom-%u Port-%u En-%u}\n",
-                __func__, __LINE__, cmd.cntrlr,
-                cmd.domain, cmd.port, cmd.en);
-
-       ret = mb86s7x_send_packet(CMD_PERI_CLOCK_GATE_SET_REQ,
-                                 &cmd, sizeof(cmd));
-       if (ret < 0) {
-               pr_err("%s:%d failed!\n", __func__, __LINE__);
-               return ret;
-       }
-
-       pr_debug("%s:%d REP Cntrlr-%u Dom-%u Port-%u En-%u}\n",
-                __func__, __LINE__, cmd.cntrlr,
-                cmd.domain, cmd.port, cmd.en);
-
-       /* If the request was rejected */
-       if (cmd.en != en)
-               ret = -EINVAL;
-       else
-               ret = 0;
-
-       return ret;
-}
-
-static int crg_port_prepare(struct clk_hw *hw)
-{
-       return crg_gate_control(hw, 1);
-}
-
-static void crg_port_unprepare(struct clk_hw *hw)
-{
-       crg_gate_control(hw, 0);
-}
-
-static int
-crg_rate_control(struct clk_hw *hw, int set, unsigned long *rate)
-{
-       struct crg_clk *crgclk = to_crg_clk(hw);
-       struct mb86s7x_peri_clk cmd;
-       int code, ret;
-
-       cmd.payload_size = sizeof(cmd);
-       cmd.cntrlr = crgclk->cntrlr;
-       cmd.domain = crgclk->domain;
-       cmd.port = crgclk->port;
-       cmd.frequency = *rate;
-
-       if (set) {
-               code = CMD_PERI_CLOCK_RATE_SET_REQ;
-               pr_debug("%s:%d CMD Cntrlr-%u Dom-%u Port-%u Rate-SET %lluHz}\n",
-                        __func__, __LINE__, cmd.cntrlr,
-                        cmd.domain, cmd.port, cmd.frequency);
-       } else {
-               code = CMD_PERI_CLOCK_RATE_GET_REQ;
-               pr_debug("%s:%d CMD Cntrlr-%u Dom-%u Port-%u Rate-GET}\n",
-                        __func__, __LINE__, cmd.cntrlr,
-                        cmd.domain, cmd.port);
-       }
-
-       ret = mb86s7x_send_packet(code, &cmd, sizeof(cmd));
-       if (ret < 0) {
-               pr_err("%s:%d failed!\n", __func__, __LINE__);
-               return ret;
-       }
-
-       if (set)
-               pr_debug("%s:%d REP Cntrlr-%u Dom-%u Port-%u Rate-SET %lluHz}\n",
-                        __func__, __LINE__, cmd.cntrlr,
-                        cmd.domain, cmd.port, cmd.frequency);
-       else
-               pr_debug("%s:%d REP Cntrlr-%u Dom-%u Port-%u Rate-GOT %lluHz}\n",
-                        __func__, __LINE__, cmd.cntrlr,
-                        cmd.domain, cmd.port, cmd.frequency);
-
-       *rate = cmd.frequency;
-       return 0;
-}
-
-static unsigned long
-crg_port_recalc_rate(struct clk_hw *hw,        unsigned long parent_rate)
-{
-       unsigned long rate;
-
-       crg_rate_control(hw, 0, &rate);
-
-       return rate;
-}
-
-static long
-crg_port_round_rate(struct clk_hw *hw,
-                   unsigned long rate, unsigned long *pr)
-{
-       return rate;
-}
-
-static int
-crg_port_set_rate(struct clk_hw *hw,
-                 unsigned long rate, unsigned long parent_rate)
-{
-       return crg_rate_control(hw, 1, &rate);
-}
-
-const struct clk_ops crg_port_ops = {
-       .prepare = crg_port_prepare,
-       .unprepare = crg_port_unprepare,
-       .recalc_rate = crg_port_recalc_rate,
-       .round_rate = crg_port_round_rate,
-       .set_rate = crg_port_set_rate,
-};
-
-struct mb86s70_crg11 {
-       struct mutex lock; /* protects CLK populating and searching */
-};
-
-static struct clk *crg11_get(struct of_phandle_args *clkspec, void *data)
-{
-       struct mb86s70_crg11 *crg11 = data;
-       struct clk_init_data init;
-       u32 cntrlr, domain, port;
-       struct crg_clk *crgclk;
-       struct clk *clk;
-       char clkp[20];
-
-       if (clkspec->args_count != 3)
-               return ERR_PTR(-EINVAL);
-
-       cntrlr = clkspec->args[0];
-       domain = clkspec->args[1];
-       port = clkspec->args[2];
-
-       if (port > 7)
-               snprintf(clkp, 20, "UngatedCLK%d_%X", cntrlr, domain);
-       else
-               snprintf(clkp, 20, "CLK%d_%X_%d", cntrlr, domain, port);
-
-       mutex_lock(&crg11->lock);
-
-       clk = __clk_lookup(clkp);
-       if (clk) {
-               mutex_unlock(&crg11->lock);
-               return clk;
-       }
-
-       crgclk = kzalloc(sizeof(*crgclk), GFP_KERNEL);
-       if (!crgclk) {
-               mutex_unlock(&crg11->lock);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       init.name = clkp;
-       init.num_parents = 0;
-       init.ops = &crg_port_ops;
-       init.flags = 0;
-       crgclk->hw.init = &init;
-       crgclk->cntrlr = cntrlr;
-       crgclk->domain = domain;
-       crgclk->port = port;
-       clk = clk_register(NULL, &crgclk->hw);
-       if (IS_ERR(clk))
-               pr_err("%s:%d Error!\n", __func__, __LINE__);
-       else
-               pr_debug("Registered %s\n", clkp);
-
-       clk_register_clkdev(clk, clkp, NULL);
-       mutex_unlock(&crg11->lock);
-       return clk;
-}
-
-static void __init crg_port_init(struct device_node *node)
-{
-       struct mb86s70_crg11 *crg11;
-
-       crg11 = kzalloc(sizeof(*crg11), GFP_KERNEL);
-       if (!crg11)
-               return;
-
-       mutex_init(&crg11->lock);
-
-       of_clk_add_provider(node, crg11_get, crg11);
-}
-CLK_OF_DECLARE(crg11_gate, "fujitsu,mb86s70-crg11", crg_port_init);
-
-struct cl_clk {
-       struct clk_hw hw;
-       int cluster;
-};
-
-struct mb86s7x_cpu_freq {
-       u32 payload_size;
-       u32 cluster_class;
-       u32 cluster_id;
-       u32 cpu_id;
-       u64 frequency;
-};
-
-static void mhu_cluster_rate(struct clk_hw *hw, unsigned long *rate, int get)
-{
-       struct cl_clk *clc = to_clc_clk(hw);
-       struct mb86s7x_cpu_freq cmd;
-       int code, ret;
-
-       cmd.payload_size = sizeof(cmd);
-       cmd.cluster_class = 0;
-       cmd.cluster_id = clc->cluster;
-       cmd.cpu_id = 0;
-       cmd.frequency = *rate;
-
-       if (get)
-               code = CMD_CPU_CLOCK_RATE_GET_REQ;
-       else
-               code = CMD_CPU_CLOCK_RATE_SET_REQ;
-
-       pr_debug("%s:%d CMD Cl_Class-%u CL_ID-%u CPU_ID-%u Freq-%llu}\n",
-                __func__, __LINE__, cmd.cluster_class,
-                cmd.cluster_id, cmd.cpu_id, cmd.frequency);
-
-       ret = mb86s7x_send_packet(code, &cmd, sizeof(cmd));
-       if (ret < 0) {
-               pr_err("%s:%d failed!\n", __func__, __LINE__);
-               return;
-       }
-
-       pr_debug("%s:%d REP Cl_Class-%u CL_ID-%u CPU_ID-%u Freq-%llu}\n",
-                __func__, __LINE__, cmd.cluster_class,
-                cmd.cluster_id, cmd.cpu_id, cmd.frequency);
-
-       *rate = cmd.frequency;
-}
-
-static unsigned long
-clc_recalc_rate(struct clk_hw *hw, unsigned long unused)
-{
-       unsigned long rate;
-
-       mhu_cluster_rate(hw, &rate, 1);
-       return rate;
-}
-
-static long
-clc_round_rate(struct clk_hw *hw, unsigned long rate,
-              unsigned long *unused)
-{
-       return rate;
-}
-
-static int
-clc_set_rate(struct clk_hw *hw, unsigned long rate,
-            unsigned long unused)
-{
-       unsigned long res = rate;
-
-       mhu_cluster_rate(hw, &res, 0);
-
-       return (res == rate) ? 0 : -EINVAL;
-}
-
-static struct clk_ops clk_clc_ops = {
-       .recalc_rate = clc_recalc_rate,
-       .round_rate = clc_round_rate,
-       .set_rate = clc_set_rate,
-};
-
-static struct clk_hw *mb86s7x_clclk_register(struct device *cpu_dev)
-{
-       struct clk_init_data init;
-       struct cl_clk *clc;
-       int ret;
-
-       clc = kzalloc(sizeof(*clc), GFP_KERNEL);
-       if (!clc)
-               return ERR_PTR(-ENOMEM);
-
-       clc->hw.init = &init;
-       clc->cluster = topology_physical_package_id(cpu_dev->id);
-
-       init.name = dev_name(cpu_dev);
-       init.ops = &clk_clc_ops;
-       init.flags = CLK_GET_RATE_NOCACHE;
-       init.num_parents = 0;
-
-       ret = devm_clk_hw_register(cpu_dev, &clc->hw);
-       if (ret)
-               return ERR_PTR(ret);
-       return &clc->hw;
-}
-
-static int mb86s7x_clclk_of_init(void)
-{
-       int cpu, ret = -ENODEV;
-       struct device_node *np;
-       struct clk_hw *hw;
-
-       np = of_find_compatible_node(NULL, NULL, "fujitsu,mb86s70-scb-1.0");
-       if (!np || !of_device_is_available(np))
-               goto exit;
-
-       for_each_possible_cpu(cpu) {
-               struct device *cpu_dev = get_cpu_device(cpu);
-
-               if (!cpu_dev) {
-                       pr_err("failed to get cpu%d device\n", cpu);
-                       continue;
-               }
-
-               hw = mb86s7x_clclk_register(cpu_dev);
-               if (IS_ERR(hw)) {
-                       pr_err("failed to register cpu%d clock\n", cpu);
-                       continue;
-               }
-               if (clk_hw_register_clkdev(hw, NULL, dev_name(cpu_dev))) {
-                       pr_err("failed to register cpu%d clock lookup\n", cpu);
-                       continue;
-               }
-               pr_debug("registered clk for %s\n", dev_name(cpu_dev));
-       }
-       ret = 0;
-
-       platform_device_register_simple("arm-bL-cpufreq-dt", -1, NULL, 0);
-exit:
-       of_node_put(np);
-       return ret;
-}
-module_init(mb86s7x_clclk_of_init);
index b86dac851116a72e4b897900f63ce7c1ae960dd6..58428d0043fdc9aa10350ebd30460c2424750aca 100644 (file)
@@ -18,7 +18,7 @@
 
 static void __init moxart_of_pll_clk_init(struct device_node *node)
 {
-       static void __iomem *base;
+       void __iomem *base;
        struct clk_hw *hw;
        struct clk *ref_clk;
        unsigned int mul;
@@ -30,7 +30,7 @@ static void __init moxart_of_pll_clk_init(struct device_node *node)
 
        base = of_iomap(node, 0);
        if (!base) {
-               pr_err("%s: of_iomap failed\n", node->full_name);
+               pr_err("%pOF: of_iomap failed\n", node);
                return;
        }
 
@@ -39,13 +39,13 @@ static void __init moxart_of_pll_clk_init(struct device_node *node)
 
        ref_clk = of_clk_get(node, 0);
        if (IS_ERR(ref_clk)) {
-               pr_err("%s: of_clk_get failed\n", node->full_name);
+               pr_err("%pOF: of_clk_get failed\n", node);
                return;
        }
 
        hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, mul, 1);
        if (IS_ERR(hw)) {
-               pr_err("%s: failed to register clock\n", node->full_name);
+               pr_err("%pOF: failed to register clock\n", node);
                return;
        }
 
@@ -57,7 +57,7 @@ CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock",
 
 static void __init moxart_of_apb_clk_init(struct device_node *node)
 {
-       static void __iomem *base;
+       void __iomem *base;
        struct clk_hw *hw;
        struct clk *pll_clk;
        unsigned int div, val;
@@ -70,7 +70,7 @@ static void __init moxart_of_apb_clk_init(struct device_node *node)
 
        base = of_iomap(node, 0);
        if (!base) {
-               pr_err("%s: of_iomap failed\n", node->full_name);
+               pr_err("%pOF: of_iomap failed\n", node);
                return;
        }
 
@@ -83,13 +83,13 @@ static void __init moxart_of_apb_clk_init(struct device_node *node)
 
        pll_clk = of_clk_get(node, 0);
        if (IS_ERR(pll_clk)) {
-               pr_err("%s: of_clk_get failed\n", node->full_name);
+               pr_err("%pOF: of_clk_get failed\n", node);
                return;
        }
 
        hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, 1, div);
        if (IS_ERR(hw)) {
-               pr_err("%s: failed to register clock\n", node->full_name);
+               pr_err("%pOF: failed to register clock\n", node);
                return;
        }
 
index f3931e38fac0fb58a9bb6262e0fe7d9da33a6269..b0ea753b8709dafa7f4fdc886b0765de1ea1c248 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/clkdev.h>
 #include <linux/fsl/guts.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
@@ -536,6 +537,17 @@ static const struct clockgen_chipinfo chipinfo[] = {
                .pll_mask = 0x07,
                .flags = CG_PLL_8BIT,
        },
+       {
+               .compat = "fsl,ls1088a-clockgen",
+               .cmux_groups = {
+                       &clockgen2_cmux_cga12
+               },
+               .cmux_to_group = {
+                       0, 0, -1
+               },
+               .pll_mask = 0x07,
+               .flags = CG_VER3 | CG_LITTLE_ENDIAN,
+       },
        {
                .compat = "fsl,ls1012a-clockgen",
                .cmux_groups = {
@@ -1113,6 +1125,7 @@ static void __init create_one_pll(struct clockgen *cg, int idx)
 
        for (i = 0; i < ARRAY_SIZE(pll->div); i++) {
                struct clk *clk;
+               int ret;
 
                snprintf(pll->div[i].name, sizeof(pll->div[i].name),
                         "cg-pll%d-div%d", idx, i + 1);
@@ -1126,6 +1139,11 @@ static void __init create_one_pll(struct clockgen *cg, int idx)
                }
 
                pll->div[i].clk = clk;
+               ret = clk_register_clkdev(clk, pll->div[i].name, NULL);
+               if (ret != 0)
+                       pr_err("%s: %s: register to lookup table failed %ld\n",
+                              __func__, pll->div[i].name, PTR_ERR(clk));
+
        }
 }
 
@@ -1348,8 +1366,7 @@ static void __init clockgen_init(struct device_node *np)
        }
 
        if (i == ARRAY_SIZE(chipinfo)) {
-               pr_err("%s: unknown clockgen node %s\n", __func__,
-                      np->full_name);
+               pr_err("%s: unknown clockgen node %pOF\n", __func__, np);
                goto err;
        }
        clockgen.info = chipinfo[i];
@@ -1362,8 +1379,8 @@ static void __init clockgen_init(struct device_node *np)
                if (guts) {
                        clockgen.guts = of_iomap(guts, 0);
                        if (!clockgen.guts) {
-                               pr_err("%s: Couldn't map %s regs\n", __func__,
-                                      guts->full_name);
+                               pr_err("%s: Couldn't map %pOF regs\n", __func__,
+                                      guts);
                        }
                }
 
@@ -1398,6 +1415,7 @@ CLK_OF_DECLARE(qoriq_clockgen_ls1012a, "fsl,ls1012a-clockgen", clockgen_init);
 CLK_OF_DECLARE(qoriq_clockgen_ls1021a, "fsl,ls1021a-clockgen", clockgen_init);
 CLK_OF_DECLARE(qoriq_clockgen_ls1043a, "fsl,ls1043a-clockgen", clockgen_init);
 CLK_OF_DECLARE(qoriq_clockgen_ls1046a, "fsl,ls1046a-clockgen", clockgen_init);
+CLK_OF_DECLARE(qoriq_clockgen_ls1088a, "fsl,ls1088a-clockgen", clockgen_init);
 CLK_OF_DECLARE(qoriq_clockgen_ls2080a, "fsl,ls2080a-clockgen", clockgen_init);
 
 /* Legacy nodes */
index 2492442eea77aa0c5abcf540e9bedb81e36d62d3..20d90769cceda980a0e198919c226e1d86d80c9e 100644 (file)
@@ -519,6 +519,11 @@ static int si5351_pll_set_rate(struct clk_hw *hw, unsigned long rate,
                SI5351_CLK_INTEGER_MODE,
                (hwdata->params.p2 == 0) ? SI5351_CLK_INTEGER_MODE : 0);
 
+       /* Do a pll soft reset on the affected pll */
+       si5351_reg_write(hwdata->drvdata, SI5351_PLL_RESET,
+                        hwdata->num == 0 ? SI5351_PLL_RESET_A :
+                                           SI5351_PLL_RESET_B);
+
        dev_dbg(&hwdata->drvdata->client->dev,
                "%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, parent_rate = %lu, rate = %lu\n",
                __func__, clk_hw_get_name(hw),
@@ -1091,13 +1096,6 @@ static int si5351_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
        si5351_set_bits(hwdata->drvdata, SI5351_CLK0_CTRL + hwdata->num,
                        SI5351_CLK_POWERDOWN, 0);
 
-       /*
-        * Do a pll soft reset on both plls, needed in some cases to get
-        * all outputs running.
-        */
-       si5351_reg_write(hwdata->drvdata, SI5351_PLL_RESET,
-                        SI5351_PLL_RESET_A | SI5351_PLL_RESET_B);
-
        dev_dbg(&hwdata->drvdata->client->dev,
                "%s - %s: rdiv = %u, parent_rate = %lu, rate = %lu\n",
                __func__, clk_hw_get_name(hw), (1 << rdiv),
index 68e2a4e499f1d31ec490b29cb08eb16dcbf6d418..96c6b6bc8f0e475f9d03de0ffa5210a2f06acae2 100644 (file)
@@ -1541,8 +1541,8 @@ static void __init stm32f4_rcc_init(struct device_node *np)
                    base + gd->offset, gd->bit_idx, 0, &stm32f4_clk_lock);
 
                if (IS_ERR(clks[idx])) {
-                       pr_err("%s: Unable to register leaf clock %s\n",
-                              np->full_name, gd->name);
+                       pr_err("%pOF: Unable to register leaf clock %s\n",
+                              np, gd->name);
                        goto fail;
                }
        }
diff --git a/drivers/clk/clk-stm32h7.c b/drivers/clk/clk-stm32h7.c
new file mode 100644 (file)
index 0000000..a94c3f5
--- /dev/null
@@ -0,0 +1,1410 @@
+/*
+ * Copyright (C) Gabriel Fernandez 2017
+ * Author: Gabriel Fernandez <gabriel.fernandez@st.com>
+ *
+ * License terms: GPL V2.0.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/stm32h7-clks.h>
+
+/* Reset Clock Control Registers */
+#define RCC_CR         0x00
+#define RCC_CFGR       0x10
+#define RCC_D1CFGR     0x18
+#define RCC_D2CFGR     0x1C
+#define RCC_D3CFGR     0x20
+#define RCC_PLLCKSELR  0x28
+#define RCC_PLLCFGR    0x2C
+#define RCC_PLL1DIVR   0x30
+#define RCC_PLL1FRACR  0x34
+#define RCC_PLL2DIVR   0x38
+#define RCC_PLL2FRACR  0x3C
+#define RCC_PLL3DIVR   0x40
+#define RCC_PLL3FRACR  0x44
+#define RCC_D1CCIPR    0x4C
+#define RCC_D2CCIP1R   0x50
+#define RCC_D2CCIP2R   0x54
+#define RCC_D3CCIPR    0x58
+#define RCC_BDCR       0x70
+#define RCC_CSR                0x74
+#define RCC_AHB3ENR    0xD4
+#define RCC_AHB1ENR    0xD8
+#define RCC_AHB2ENR    0xDC
+#define RCC_AHB4ENR    0xE0
+#define RCC_APB3ENR    0xE4
+#define RCC_APB1LENR   0xE8
+#define RCC_APB1HENR   0xEC
+#define RCC_APB2ENR    0xF0
+#define RCC_APB4ENR    0xF4
+
+static DEFINE_SPINLOCK(stm32rcc_lock);
+
+static void __iomem *base;
+static struct clk_hw **hws;
+
+/* System clock parent */
+static const char * const sys_src[] = {
+       "hsi_ck", "csi_ck", "hse_ck", "pll1_p" };
+
+static const char * const tracein_src[] = {
+       "hsi_ck", "csi_ck", "hse_ck", "pll1_r" };
+
+static const char * const per_src[] = {
+       "hsi_ker", "csi_ker", "hse_ck", "disabled" };
+
+static const char * const pll_src[] = {
+       "hsi_ck", "csi_ck", "hse_ck", "no clock" };
+
+static const char * const sdmmc_src[] = { "pll1_q", "pll2_r" };
+
+static const char * const dsi_src[] = { "ck_dsi_phy", "pll2_q" };
+
+static const char * const qspi_src[] = {
+       "hclk", "pll1_q", "pll2_r", "per_ck" };
+
+static const char * const fmc_src[] = {
+       "hclk", "pll1_q", "pll2_r", "per_ck" };
+
+/* Kernel clock parent */
+static const char * const swp_src[] = {        "pclk1", "hsi_ker" };
+
+static const char * const fdcan_src[] = { "hse_ck", "pll1_q", "pll2_q" };
+
+static const char * const dfsdm1_src[] = { "pclk2", "sys_ck" };
+
+static const char * const spdifrx_src[] = {
+       "pll1_q", "pll2_r", "pll3_r", "hsi_ker" };
+
+static const char *spi_src1[5] = {
+       "pll1_q", "pll2_p", "pll3_p", NULL, "per_ck" };
+
+static const char * const spi_src2[] = {
+       "pclk2", "pll2_q", "pll3_q", "hsi_ker", "csi_ker", "hse_ck" };
+
+static const char * const spi_src3[] = {
+       "pclk4", "pll2_q", "pll3_q", "hsi_ker", "csi_ker", "hse_ck" };
+
+static const char * const lptim_src1[] = {
+       "pclk1", "pll2_p", "pll3_r", "lse_ck", "lsi_ck", "per_ck" };
+
+static const char * const lptim_src2[] = {
+       "pclk4", "pll2_p", "pll3_r", "lse_ck", "lsi_ck", "per_ck" };
+
+static const char * const cec_src[] = {"lse_ck", "lsi_ck", "csi_ker_div122" };
+
+static const char * const usbotg_src[] = {"pll1_q", "pll3_q", "rc48_ck" };
+
+/* i2c 1,2,3 src */
+static const char * const i2c_src1[] = {
+       "pclk1", "pll3_r", "hsi_ker", "csi_ker" };
+
+static const char * const i2c_src2[] = {
+       "pclk4", "pll3_r", "hsi_ker", "csi_ker" };
+
+static const char * const rng_src[] = {
+       "rc48_ck", "pll1_q", "lse_ck", "lsi_ck" };
+
+/* usart 1,6 src */
+static const char * const usart_src1[] = {
+       "pclk2", "pll2_q", "pll3_q", "hsi_ker", "csi_ker", "lse_ck" };
+
+/* usart 2,3,4,5,7,8 src */
+static const char * const usart_src2[] = {
+       "pclk1", "pll2_q", "pll3_q", "hsi_ker", "csi_ker", "lse_ck" };
+
+static const char *sai_src[5] = {
+       "pll1_q", "pll2_p", "pll3_p", NULL, "per_ck" };
+
+static const char * const adc_src[] = { "pll2_p", "pll3_r", "per_ck" };
+
+/* lptim 2,3,4,5 src */
+static const char * const lpuart1_src[] = {
+       "pclk3", "pll2_q", "pll3_q", "csi_ker", "lse_ck" };
+
+static const char * const hrtim_src[] = { "tim2_ker", "d1cpre" };
+
+/* RTC clock parent */
+static const char * const rtc_src[] = { "off", "lse_ck", "lsi_ck", "hse_1M" };
+
+/* Micro-controller output clock parent */
+static const char * const mco_src1[] = {
+       "hsi_ck", "lse_ck", "hse_ck", "pll1_q", "rc48_ck" };
+
+static const char * const mco_src2[] = {
+       "sys_ck", "pll2_p", "hse_ck", "pll1_p", "csi_ck", "lsi_ck" };
+
+/* LCD clock */
+static const char * const ltdc_src[] = {"pll3_r"};
+
+/* Gate clock with ready bit and backup domain management */
+struct stm32_ready_gate {
+       struct  clk_gate gate;
+       u8      bit_rdy;
+};
+
+#define to_ready_gate_clk(_rgate) container_of(_rgate, struct stm32_ready_gate,\
+               gate)
+
+#define RGATE_TIMEOUT 10000
+
+static int ready_gate_clk_enable(struct clk_hw *hw)
+{
+       struct clk_gate *gate = to_clk_gate(hw);
+       struct stm32_ready_gate *rgate = to_ready_gate_clk(gate);
+       int bit_status;
+       unsigned int timeout = RGATE_TIMEOUT;
+
+       if (clk_gate_ops.is_enabled(hw))
+               return 0;
+
+       clk_gate_ops.enable(hw);
+
+       /* We can't use readl_poll_timeout() because we can blocked if
+        * someone enables this clock before clocksource changes.
+        * Only jiffies counter is available. Jiffies are incremented by
+        * interruptions and enable op does not allow to be interrupted.
+        */
+       do {
+               bit_status = !(readl(gate->reg) & BIT(rgate->bit_rdy));
+
+               if (bit_status)
+                       udelay(100);
+
+       } while (bit_status && --timeout);
+
+       return bit_status;
+}
+
+static void ready_gate_clk_disable(struct clk_hw *hw)
+{
+       struct clk_gate *gate = to_clk_gate(hw);
+       struct stm32_ready_gate *rgate = to_ready_gate_clk(gate);
+       int bit_status;
+       unsigned int timeout = RGATE_TIMEOUT;
+
+       if (!clk_gate_ops.is_enabled(hw))
+               return;
+
+       clk_gate_ops.disable(hw);
+
+       do {
+               bit_status = !!(readl(gate->reg) & BIT(rgate->bit_rdy));
+
+               if (bit_status)
+                       udelay(100);
+
+       } while (bit_status && --timeout);
+}
+
+static const struct clk_ops ready_gate_clk_ops = {
+       .enable         = ready_gate_clk_enable,
+       .disable        = ready_gate_clk_disable,
+       .is_enabled     = clk_gate_is_enabled,
+};
+
+static struct clk_hw *clk_register_ready_gate(struct device *dev,
+               const char *name, const char *parent_name,
+               void __iomem *reg, u8 bit_idx, u8 bit_rdy,
+               unsigned long flags, spinlock_t *lock)
+{
+       struct stm32_ready_gate *rgate;
+       struct clk_init_data init = { NULL };
+       struct clk_hw *hw;
+       int ret;
+
+       rgate = kzalloc(sizeof(*rgate), GFP_KERNEL);
+       if (!rgate)
+               return ERR_PTR(-ENOMEM);
+
+       init.name = name;
+       init.ops = &ready_gate_clk_ops;
+       init.flags = flags;
+       init.parent_names = &parent_name;
+       init.num_parents = 1;
+
+       rgate->bit_rdy = bit_rdy;
+       rgate->gate.lock = lock;
+       rgate->gate.reg = reg;
+       rgate->gate.bit_idx = bit_idx;
+       rgate->gate.hw.init = &init;
+
+       hw = &rgate->gate.hw;
+       ret = clk_hw_register(dev, hw);
+       if (ret) {
+               kfree(rgate);
+               hw = ERR_PTR(ret);
+       }
+
+       return hw;
+}
+
+struct gate_cfg {
+       u32 offset;
+       u8  bit_idx;
+};
+
+struct muxdiv_cfg {
+       u32 offset;
+       u8 shift;
+       u8 width;
+};
+
+struct composite_clk_cfg {
+       struct gate_cfg *gate;
+       struct muxdiv_cfg *mux;
+       struct muxdiv_cfg *div;
+       const char *name;
+       const char * const *parent_name;
+       int num_parents;
+       u32 flags;
+};
+
+struct composite_clk_gcfg_t {
+       u8 flags;
+       const struct clk_ops *ops;
+};
+
+/*
+ * General config definition of a composite clock (only clock diviser for rate)
+ */
+struct composite_clk_gcfg {
+       struct composite_clk_gcfg_t *mux;
+       struct composite_clk_gcfg_t *div;
+       struct composite_clk_gcfg_t *gate;
+};
+
+#define M_CFG_MUX(_mux_ops, _mux_flags)\
+       .mux = &(struct composite_clk_gcfg_t) { _mux_flags, _mux_ops}
+
+#define M_CFG_DIV(_rate_ops, _rate_flags)\
+       .div = &(struct composite_clk_gcfg_t) {_rate_flags, _rate_ops}
+
+#define M_CFG_GATE(_gate_ops, _gate_flags)\
+       .gate = &(struct composite_clk_gcfg_t) { _gate_flags, _gate_ops}
+
+static struct clk_mux *_get_cmux(void __iomem *reg, u8 shift, u8 width,
+               u32 flags, spinlock_t *lock)
+{
+       struct clk_mux *mux;
+
+       mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+       if (!mux)
+               return ERR_PTR(-ENOMEM);
+
+       mux->reg        = reg;
+       mux->shift      = shift;
+       mux->mask       = (1 << width) - 1;
+       mux->flags      = flags;
+       mux->lock       = lock;
+
+       return mux;
+}
+
+static struct clk_divider *_get_cdiv(void __iomem *reg, u8 shift, u8 width,
+               u32 flags, spinlock_t *lock)
+{
+       struct clk_divider *div;
+
+       div = kzalloc(sizeof(*div), GFP_KERNEL);
+
+       if (!div)
+               return ERR_PTR(-ENOMEM);
+
+       div->reg   = reg;
+       div->shift = shift;
+       div->width = width;
+       div->flags = flags;
+       div->lock  = lock;
+
+       return div;
+}
+
+static struct clk_gate *_get_cgate(void __iomem *reg, u8 bit_idx, u32 flags,
+               spinlock_t *lock)
+{
+       struct clk_gate *gate;
+
+       gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+       if (!gate)
+               return ERR_PTR(-ENOMEM);
+
+       gate->reg       = reg;
+       gate->bit_idx   = bit_idx;
+       gate->flags     = flags;
+       gate->lock      = lock;
+
+       return gate;
+}
+
+struct composite_cfg {
+       struct clk_hw *mux_hw;
+       struct clk_hw *div_hw;
+       struct clk_hw *gate_hw;
+
+       const struct clk_ops *mux_ops;
+       const struct clk_ops *div_ops;
+       const struct clk_ops *gate_ops;
+};
+
+static void get_cfg_composite_div(const struct composite_clk_gcfg *gcfg,
+               const struct composite_clk_cfg *cfg,
+               struct composite_cfg *composite, spinlock_t *lock)
+{
+       struct clk_mux     *mux = NULL;
+       struct clk_divider *div = NULL;
+       struct clk_gate    *gate = NULL;
+       const struct clk_ops *mux_ops, *div_ops, *gate_ops;
+       struct clk_hw *mux_hw;
+       struct clk_hw *div_hw;
+       struct clk_hw *gate_hw;
+
+       mux_ops = div_ops = gate_ops = NULL;
+       mux_hw = div_hw = gate_hw = NULL;
+
+       if (gcfg->mux && gcfg->mux) {
+               mux = _get_cmux(base + cfg->mux->offset,
+                               cfg->mux->shift,
+                               cfg->mux->width,
+                               gcfg->mux->flags, lock);
+
+               if (!IS_ERR(mux)) {
+                       mux_hw = &mux->hw;
+                       mux_ops = gcfg->mux->ops ?
+                                 gcfg->mux->ops : &clk_mux_ops;
+               }
+       }
+
+       if (gcfg->div && cfg->div) {
+               div = _get_cdiv(base + cfg->div->offset,
+                               cfg->div->shift,
+                               cfg->div->width,
+                               gcfg->div->flags, lock);
+
+               if (!IS_ERR(div)) {
+                       div_hw = &div->hw;
+                       div_ops = gcfg->div->ops ?
+                                 gcfg->div->ops : &clk_divider_ops;
+               }
+       }
+
+       if (gcfg->gate && gcfg->gate) {
+               gate = _get_cgate(base + cfg->gate->offset,
+                               cfg->gate->bit_idx,
+                               gcfg->gate->flags, lock);
+
+               if (!IS_ERR(gate)) {
+                       gate_hw = &gate->hw;
+                       gate_ops = gcfg->gate->ops ?
+                                  gcfg->gate->ops : &clk_gate_ops;
+               }
+       }
+
+       composite->mux_hw = mux_hw;
+       composite->mux_ops = mux_ops;
+
+       composite->div_hw = div_hw;
+       composite->div_ops = div_ops;
+
+       composite->gate_hw = gate_hw;
+       composite->gate_ops = gate_ops;
+}
+
+/* Kernel Timer */
+struct timer_ker {
+       u8 dppre_shift;
+       struct clk_hw hw;
+       spinlock_t *lock;
+};
+
+#define to_timer_ker(_hw) container_of(_hw, struct timer_ker, hw)
+
+static unsigned long timer_ker_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct timer_ker *clk_elem = to_timer_ker(hw);
+       u32 timpre;
+       u32 dppre_shift = clk_elem->dppre_shift;
+       u32 prescaler;
+       u32 mul;
+
+       timpre = (readl(base + RCC_CFGR) >> 15) & 0x01;
+
+       prescaler = (readl(base + RCC_D2CFGR) >> dppre_shift) & 0x03;
+
+       mul = 2;
+
+       if (prescaler < 4)
+               mul = 1;
+
+       else if (timpre && prescaler > 4)
+               mul = 4;
+
+       return parent_rate * mul;
+}
+
+static const struct clk_ops timer_ker_ops = {
+       .recalc_rate = timer_ker_recalc_rate,
+};
+
+static struct clk_hw *clk_register_stm32_timer_ker(struct device *dev,
+               const char *name, const char *parent_name,
+               unsigned long flags,
+               u8 dppre_shift,
+               spinlock_t *lock)
+{
+       struct timer_ker *element;
+       struct clk_init_data init;
+       struct clk_hw *hw;
+       int err;
+
+       element = kzalloc(sizeof(*element), GFP_KERNEL);
+       if (!element)
+               return ERR_PTR(-ENOMEM);
+
+       init.name = name;
+       init.ops = &timer_ker_ops;
+       init.flags = flags;
+       init.parent_names = &parent_name;
+       init.num_parents = 1;
+
+       element->hw.init = &init;
+       element->lock = lock;
+       element->dppre_shift = dppre_shift;
+
+       hw = &element->hw;
+       err = clk_hw_register(dev, hw);
+
+       if (err) {
+               kfree(element);
+               return ERR_PTR(err);
+       }
+
+       return hw;
+}
+
+static const struct clk_div_table d1cpre_div_table[] = {
+       { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1},
+       { 4, 1 }, { 5, 1 }, { 6, 1 }, { 7, 1},
+       { 8, 2 }, { 9, 4 }, { 10, 8 }, { 11, 16 },
+       { 12, 64 }, { 13, 128 }, { 14, 256 },
+       { 15, 512 },
+       { 0 },
+};
+
+static const struct clk_div_table ppre_div_table[] = {
+       { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1},
+       { 4, 2 }, { 5, 4 }, { 6, 8 }, { 7, 16 },
+       { 0 },
+};
+
+static void register_core_and_bus_clocks(void)
+{
+       /* CORE AND BUS */
+       hws[SYS_D1CPRE] = clk_hw_register_divider_table(NULL, "d1cpre",
+                       "sys_ck", CLK_IGNORE_UNUSED, base + RCC_D1CFGR, 8, 4, 0,
+                       d1cpre_div_table, &stm32rcc_lock);
+
+       hws[HCLK] = clk_hw_register_divider_table(NULL, "hclk", "d1cpre",
+                       CLK_IGNORE_UNUSED, base + RCC_D1CFGR, 0, 4, 0,
+                       d1cpre_div_table, &stm32rcc_lock);
+
+       /* D1 DOMAIN */
+       /* * CPU Systick */
+       hws[CPU_SYSTICK] = clk_hw_register_fixed_factor(NULL, "systick",
+                       "d1cpre", 0, 1, 8);
+
+       /* * APB3 peripheral */
+       hws[PCLK3] = clk_hw_register_divider_table(NULL, "pclk3", "hclk", 0,
+                       base + RCC_D1CFGR, 4, 3, 0,
+                       ppre_div_table, &stm32rcc_lock);
+
+       /* D2 DOMAIN */
+       /* * APB1 peripheral */
+       hws[PCLK1] = clk_hw_register_divider_table(NULL, "pclk1", "hclk", 0,
+                       base + RCC_D2CFGR, 4, 3, 0,
+                       ppre_div_table, &stm32rcc_lock);
+
+       /* Timers prescaler clocks */
+       clk_register_stm32_timer_ker(NULL, "tim1_ker", "pclk1", 0,
+                       4, &stm32rcc_lock);
+
+       /* * APB2 peripheral */
+       hws[PCLK2] = clk_hw_register_divider_table(NULL, "pclk2", "hclk", 0,
+                       base + RCC_D2CFGR, 8, 3, 0, ppre_div_table,
+                       &stm32rcc_lock);
+
+       clk_register_stm32_timer_ker(NULL, "tim2_ker", "pclk2", 0, 8,
+                       &stm32rcc_lock);
+
+       /* D3 DOMAIN */
+       /* * APB4 peripheral */
+       hws[PCLK4] = clk_hw_register_divider_table(NULL, "pclk4", "hclk", 0,
+                       base + RCC_D3CFGR, 4, 3, 0,
+                       ppre_div_table, &stm32rcc_lock);
+}
+
+/* MUX clock configuration */
+struct stm32_mux_clk {
+       const char *name;
+       const char * const *parents;
+       u8 num_parents;
+       u32 offset;
+       u8 shift;
+       u8 width;
+       u32 flags;
+};
+
+#define M_MCLOCF(_name, _parents, _mux_offset, _mux_shift, _mux_width, _flags)\
+{\
+       .name           = _name,\
+       .parents        = _parents,\
+       .num_parents    = ARRAY_SIZE(_parents),\
+       .offset         = _mux_offset,\
+       .shift          = _mux_shift,\
+       .width          = _mux_width,\
+       .flags          = _flags,\
+}
+
+#define M_MCLOC(_name, _parents, _mux_offset, _mux_shift, _mux_width)\
+       M_MCLOCF(_name, _parents, _mux_offset, _mux_shift, _mux_width, 0)\
+
+static const struct stm32_mux_clk stm32_mclk[] __initconst = {
+       M_MCLOC("per_ck",       per_src,        RCC_D1CCIPR,    28, 3),
+       M_MCLOC("pllsrc",       pll_src,        RCC_PLLCKSELR,   0, 3),
+       M_MCLOC("sys_ck",       sys_src,        RCC_CFGR,        0, 3),
+       M_MCLOC("tracein_ck",   tracein_src,    RCC_CFGR,        0, 3),
+};
+
+/* Oscillary clock configuration */
+struct stm32_osc_clk {
+       const char *name;
+       const char *parent;
+       u32 gate_offset;
+       u8 bit_idx;
+       u8 bit_rdy;
+       u32 flags;
+};
+
+#define OSC_CLKF(_name, _parent, _gate_offset, _bit_idx, _bit_rdy, _flags)\
+{\
+       .name           = _name,\
+       .parent         = _parent,\
+       .gate_offset    = _gate_offset,\
+       .bit_idx        = _bit_idx,\
+       .bit_rdy        = _bit_rdy,\
+       .flags          = _flags,\
+}
+
+#define OSC_CLK(_name, _parent, _gate_offset, _bit_idx, _bit_rdy)\
+       OSC_CLKF(_name, _parent, _gate_offset, _bit_idx, _bit_rdy, 0)
+
+static const struct stm32_osc_clk stm32_oclk[] __initconst = {
+       OSC_CLKF("hsi_ck",  "hsidiv",   RCC_CR,   0,  2, CLK_IGNORE_UNUSED),
+       OSC_CLKF("hsi_ker", "hsidiv",   RCC_CR,   1,  2, CLK_IGNORE_UNUSED),
+       OSC_CLKF("csi_ck",  "clk-csi",  RCC_CR,   7,  8, CLK_IGNORE_UNUSED),
+       OSC_CLKF("csi_ker", "clk-csi",  RCC_CR,   9,  8, CLK_IGNORE_UNUSED),
+       OSC_CLKF("rc48_ck", "clk-rc48", RCC_CR,  12, 13, CLK_IGNORE_UNUSED),
+       OSC_CLKF("lsi_ck",  "clk-lsi",  RCC_CSR,  0,  1, CLK_IGNORE_UNUSED),
+};
+
+/* PLL configuration */
+struct st32h7_pll_cfg {
+       u8 bit_idx;
+       u32 offset_divr;
+       u8 bit_frac_en;
+       u32 offset_frac;
+       u8 divm;
+};
+
+struct stm32_pll_data {
+       const char *name;
+       const char *parent_name;
+       unsigned long flags;
+       const struct st32h7_pll_cfg *cfg;
+};
+
+static const struct st32h7_pll_cfg stm32h7_pll1 = {
+       .bit_idx = 24,
+       .offset_divr = RCC_PLL1DIVR,
+       .bit_frac_en = 0,
+       .offset_frac = RCC_PLL1FRACR,
+       .divm = 4,
+};
+
+static const struct st32h7_pll_cfg stm32h7_pll2 = {
+       .bit_idx = 26,
+       .offset_divr = RCC_PLL2DIVR,
+       .bit_frac_en = 4,
+       .offset_frac = RCC_PLL2FRACR,
+       .divm = 12,
+};
+
+static const struct st32h7_pll_cfg stm32h7_pll3 = {
+       .bit_idx = 28,
+       .offset_divr = RCC_PLL3DIVR,
+       .bit_frac_en = 8,
+       .offset_frac = RCC_PLL3FRACR,
+       .divm = 20,
+};
+
+static const struct stm32_pll_data stm32_pll[] = {
+       { "vco1", "pllsrc", CLK_IGNORE_UNUSED, &stm32h7_pll1 },
+       { "vco2", "pllsrc", 0, &stm32h7_pll2 },
+       { "vco3", "pllsrc", 0, &stm32h7_pll3 },
+};
+
+struct stm32_fractional_divider {
+       void __iomem    *mreg;
+       u8              mshift;
+       u8              mwidth;
+       u32             mmask;
+
+       void __iomem    *nreg;
+       u8              nshift;
+       u8              nwidth;
+
+       void __iomem    *freg_status;
+       u8              freg_bit;
+       void __iomem    *freg_value;
+       u8              fshift;
+       u8              fwidth;
+
+       u8              flags;
+       struct clk_hw   hw;
+       spinlock_t      *lock;
+};
+
+struct stm32_pll_obj {
+       spinlock_t *lock;
+       struct stm32_fractional_divider div;
+       struct stm32_ready_gate rgate;
+       struct clk_hw hw;
+};
+
+#define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw)
+
+static int pll_is_enabled(struct clk_hw *hw)
+{
+       struct stm32_pll_obj *clk_elem = to_pll(hw);
+       struct clk_hw *_hw = &clk_elem->rgate.gate.hw;
+
+       __clk_hw_set_clk(_hw, hw);
+
+       return ready_gate_clk_ops.is_enabled(_hw);
+}
+
+static int pll_enable(struct clk_hw *hw)
+{
+       struct stm32_pll_obj *clk_elem = to_pll(hw);
+       struct clk_hw *_hw = &clk_elem->rgate.gate.hw;
+
+       __clk_hw_set_clk(_hw, hw);
+
+       return ready_gate_clk_ops.enable(_hw);
+}
+
+static void pll_disable(struct clk_hw *hw)
+{
+       struct stm32_pll_obj *clk_elem = to_pll(hw);
+       struct clk_hw *_hw = &clk_elem->rgate.gate.hw;
+
+       __clk_hw_set_clk(_hw, hw);
+
+       ready_gate_clk_ops.disable(_hw);
+}
+
+static int pll_frac_is_enabled(struct clk_hw *hw)
+{
+       struct stm32_pll_obj *clk_elem = to_pll(hw);
+       struct stm32_fractional_divider *fd = &clk_elem->div;
+
+       return (readl(fd->freg_status) >> fd->freg_bit) & 0x01;
+}
+
+static unsigned long pll_read_frac(struct clk_hw *hw)
+{
+       struct stm32_pll_obj *clk_elem = to_pll(hw);
+       struct stm32_fractional_divider *fd = &clk_elem->div;
+
+       return (readl(fd->freg_value) >> fd->fshift) &
+               GENMASK(fd->fwidth - 1, 0);
+}
+
+static unsigned long pll_fd_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct stm32_pll_obj *clk_elem = to_pll(hw);
+       struct stm32_fractional_divider *fd = &clk_elem->div;
+       unsigned long m, n;
+       u32 val, mask;
+       u64 rate, rate1 = 0;
+
+       val = readl(fd->mreg);
+       mask = GENMASK(fd->mwidth - 1, 0) << fd->mshift;
+       m = (val & mask) >> fd->mshift;
+
+       val = readl(fd->nreg);
+       mask = GENMASK(fd->nwidth - 1, 0) << fd->nshift;
+       n = ((val & mask) >> fd->nshift) + 1;
+
+       if (!n || !m)
+               return parent_rate;
+
+       rate = (u64)parent_rate * n;
+       do_div(rate, m);
+
+       if (pll_frac_is_enabled(hw)) {
+               val = pll_read_frac(hw);
+               rate1 = (u64)parent_rate * (u64)val;
+               do_div(rate1, (m * 8191));
+       }
+
+       return rate + rate1;
+}
+
+static const struct clk_ops pll_ops = {
+       .enable         = pll_enable,
+       .disable        = pll_disable,
+       .is_enabled     = pll_is_enabled,
+       .recalc_rate    = pll_fd_recalc_rate,
+};
+
+static struct clk_hw *clk_register_stm32_pll(struct device *dev,
+               const char *name,
+               const char *parent,
+               unsigned long flags,
+               const struct st32h7_pll_cfg *cfg,
+               spinlock_t *lock)
+{
+       struct stm32_pll_obj *pll;
+       struct clk_init_data init = { NULL };
+       struct clk_hw *hw;
+       int ret;
+       struct stm32_fractional_divider *div = NULL;
+       struct stm32_ready_gate *rgate;
+
+       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+       if (!pll)
+               return ERR_PTR(-ENOMEM);
+
+       init.name = name;
+       init.ops = &pll_ops;
+       init.flags = flags;
+       init.parent_names = &parent;
+       init.num_parents = 1;
+       pll->hw.init = &init;
+
+       hw = &pll->hw;
+       rgate = &pll->rgate;
+
+       rgate->bit_rdy = cfg->bit_idx + 1;
+       rgate->gate.lock = lock;
+       rgate->gate.reg = base + RCC_CR;
+       rgate->gate.bit_idx = cfg->bit_idx;
+
+       div = &pll->div;
+       div->flags = 0;
+       div->mreg = base + RCC_PLLCKSELR;
+       div->mshift = cfg->divm;
+       div->mwidth = 6;
+       div->nreg = base +  cfg->offset_divr;
+       div->nshift = 0;
+       div->nwidth = 9;
+
+       div->freg_status = base + RCC_PLLCFGR;
+       div->freg_bit = cfg->bit_frac_en;
+       div->freg_value = base +  cfg->offset_frac;
+       div->fshift = 3;
+       div->fwidth = 13;
+
+       div->lock = lock;
+
+       ret = clk_hw_register(dev, hw);
+       if (ret) {
+               kfree(pll);
+               hw = ERR_PTR(ret);
+       }
+
+       return hw;
+}
+
+/* ODF CLOCKS */
+static unsigned long odf_divider_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       return clk_divider_ops.recalc_rate(hw, parent_rate);
+}
+
+static long odf_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *prate)
+{
+       return clk_divider_ops.round_rate(hw, rate, prate);
+}
+
+static int odf_divider_set_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long parent_rate)
+{
+       struct clk_hw *hwp;
+       int pll_status;
+       int ret;
+
+       hwp = clk_hw_get_parent(hw);
+
+       pll_status = pll_is_enabled(hwp);
+
+       if (pll_status)
+               pll_disable(hwp);
+
+       ret = clk_divider_ops.set_rate(hw, rate, parent_rate);
+
+       if (pll_status)
+               pll_enable(hwp);
+
+       return ret;
+}
+
+static const struct clk_ops odf_divider_ops = {
+       .recalc_rate    = odf_divider_recalc_rate,
+       .round_rate     = odf_divider_round_rate,
+       .set_rate       = odf_divider_set_rate,
+};
+
+static int odf_gate_enable(struct clk_hw *hw)
+{
+       struct clk_hw *hwp;
+       int pll_status;
+       int ret;
+
+       if (clk_gate_ops.is_enabled(hw))
+               return 0;
+
+       hwp = clk_hw_get_parent(hw);
+
+       pll_status = pll_is_enabled(hwp);
+
+       if (pll_status)
+               pll_disable(hwp);
+
+       ret = clk_gate_ops.enable(hw);
+
+       if (pll_status)
+               pll_enable(hwp);
+
+       return ret;
+}
+
+static void odf_gate_disable(struct clk_hw *hw)
+{
+       struct clk_hw *hwp;
+       int pll_status;
+
+       if (!clk_gate_ops.is_enabled(hw))
+               return;
+
+       hwp = clk_hw_get_parent(hw);
+
+       pll_status = pll_is_enabled(hwp);
+
+       if (pll_status)
+               pll_disable(hwp);
+
+       clk_gate_ops.disable(hw);
+
+       if (pll_status)
+               pll_enable(hwp);
+}
+
+static const struct clk_ops odf_gate_ops = {
+       .enable         = odf_gate_enable,
+       .disable        = odf_gate_disable,
+       .is_enabled     = clk_gate_is_enabled,
+};
+
+static struct composite_clk_gcfg odf_clk_gcfg = {
+       M_CFG_DIV(&odf_divider_ops, 0),
+       M_CFG_GATE(&odf_gate_ops, 0),
+};
+
+#define M_ODF_F(_name, _parent, _gate_offset,  _bit_idx, _rate_offset,\
+               _rate_shift, _rate_width, _flags)\
+{\
+       .mux = NULL,\
+       .div = &(struct muxdiv_cfg) {_rate_offset, _rate_shift, _rate_width},\
+       .gate = &(struct gate_cfg) {_gate_offset, _bit_idx },\
+       .name = _name,\
+       .parent_name = &(const char *) {_parent},\
+       .num_parents = 1,\
+       .flags = _flags,\
+}
+
+#define M_ODF(_name, _parent, _gate_offset,  _bit_idx, _rate_offset,\
+               _rate_shift, _rate_width)\
+M_ODF_F(_name, _parent, _gate_offset,  _bit_idx, _rate_offset,\
+               _rate_shift, _rate_width, 0)\
+
+static const struct composite_clk_cfg stm32_odf[3][3] = {
+       {
+               M_ODF_F("pll1_p", "vco1", RCC_PLLCFGR, 16, RCC_PLL1DIVR,  9, 7,
+                               CLK_IGNORE_UNUSED),
+               M_ODF_F("pll1_q", "vco1", RCC_PLLCFGR, 17, RCC_PLL1DIVR, 16, 7,
+                               CLK_IGNORE_UNUSED),
+               M_ODF_F("pll1_r", "vco1", RCC_PLLCFGR, 18, RCC_PLL1DIVR, 24, 7,
+                               CLK_IGNORE_UNUSED),
+       },
+
+       {
+               M_ODF("pll2_p", "vco2", RCC_PLLCFGR, 19, RCC_PLL2DIVR,  9, 7),
+               M_ODF("pll2_q", "vco2", RCC_PLLCFGR, 20, RCC_PLL2DIVR, 16, 7),
+               M_ODF("pll2_r", "vco2", RCC_PLLCFGR, 21, RCC_PLL2DIVR, 24, 7),
+       },
+       {
+               M_ODF("pll3_p", "vco3", RCC_PLLCFGR, 22, RCC_PLL3DIVR,  9, 7),
+               M_ODF("pll3_q", "vco3", RCC_PLLCFGR, 23, RCC_PLL3DIVR, 16, 7),
+               M_ODF("pll3_r", "vco3", RCC_PLLCFGR, 24, RCC_PLL3DIVR, 24, 7),
+       }
+};
+
+/* PERIF CLOCKS */
+struct pclk_t {
+       u32 gate_offset;
+       u8 bit_idx;
+       const char *name;
+       const char *parent;
+       u32 flags;
+};
+
+#define PER_CLKF(_gate_offset, _bit_idx, _name, _parent, _flags)\
+{\
+       .gate_offset    = _gate_offset,\
+       .bit_idx        = _bit_idx,\
+       .name           = _name,\
+       .parent         = _parent,\
+       .flags          = _flags,\
+}
+
+#define PER_CLK(_gate_offset, _bit_idx, _name, _parent)\
+       PER_CLKF(_gate_offset, _bit_idx, _name, _parent, 0)
+
+static const struct pclk_t pclk[] = {
+       PER_CLK(RCC_AHB3ENR, 31, "d1sram1", "hclk"),
+       PER_CLK(RCC_AHB3ENR, 30, "itcm", "hclk"),
+       PER_CLK(RCC_AHB3ENR, 29, "dtcm2", "hclk"),
+       PER_CLK(RCC_AHB3ENR, 28, "dtcm1", "hclk"),
+       PER_CLK(RCC_AHB3ENR, 8, "flitf", "hclk"),
+       PER_CLK(RCC_AHB3ENR, 5, "jpgdec", "hclk"),
+       PER_CLK(RCC_AHB3ENR, 4, "dma2d", "hclk"),
+       PER_CLK(RCC_AHB3ENR, 0, "mdma", "hclk"),
+       PER_CLK(RCC_AHB1ENR, 28, "usb2ulpi", "hclk"),
+       PER_CLK(RCC_AHB1ENR, 26, "usb1ulpi", "hclk"),
+       PER_CLK(RCC_AHB1ENR, 17, "eth1rx", "hclk"),
+       PER_CLK(RCC_AHB1ENR, 16, "eth1tx", "hclk"),
+       PER_CLK(RCC_AHB1ENR, 15, "eth1mac", "hclk"),
+       PER_CLK(RCC_AHB1ENR, 14, "art", "hclk"),
+       PER_CLK(RCC_AHB1ENR, 1, "dma2", "hclk"),
+       PER_CLK(RCC_AHB1ENR, 0, "dma1", "hclk"),
+       PER_CLK(RCC_AHB2ENR, 31, "d2sram3", "hclk"),
+       PER_CLK(RCC_AHB2ENR, 30, "d2sram2", "hclk"),
+       PER_CLK(RCC_AHB2ENR, 29, "d2sram1", "hclk"),
+       PER_CLK(RCC_AHB2ENR, 5, "hash", "hclk"),
+       PER_CLK(RCC_AHB2ENR, 4, "crypt", "hclk"),
+       PER_CLK(RCC_AHB2ENR, 0, "camitf", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 28, "bkpram", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 25, "hsem", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 21, "bdma", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 19, "crc", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 10, "gpiok", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 9, "gpioj", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 8, "gpioi", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 7, "gpioh", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 6, "gpiog", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 5, "gpiof", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 4, "gpioe", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 3, "gpiod", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 2, "gpioc", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 1, "gpiob", "hclk"),
+       PER_CLK(RCC_AHB4ENR, 0, "gpioa", "hclk"),
+       PER_CLK(RCC_APB3ENR, 6, "wwdg1", "pclk3"),
+       PER_CLK(RCC_APB1LENR, 29, "dac12", "pclk1"),
+       PER_CLK(RCC_APB1LENR, 11, "wwdg2", "pclk1"),
+       PER_CLK(RCC_APB1LENR, 8, "tim14", "tim1_ker"),
+       PER_CLK(RCC_APB1LENR, 7, "tim13", "tim1_ker"),
+       PER_CLK(RCC_APB1LENR, 6, "tim12", "tim1_ker"),
+       PER_CLK(RCC_APB1LENR, 5, "tim7", "tim1_ker"),
+       PER_CLK(RCC_APB1LENR, 4, "tim6", "tim1_ker"),
+       PER_CLK(RCC_APB1LENR, 3, "tim5", "tim1_ker"),
+       PER_CLK(RCC_APB1LENR, 2, "tim4", "tim1_ker"),
+       PER_CLK(RCC_APB1LENR, 1, "tim3", "tim1_ker"),
+       PER_CLK(RCC_APB1LENR, 0, "tim2", "tim1_ker"),
+       PER_CLK(RCC_APB1HENR, 5, "mdios", "pclk1"),
+       PER_CLK(RCC_APB1HENR, 4, "opamp", "pclk1"),
+       PER_CLK(RCC_APB1HENR, 1, "crs", "pclk1"),
+       PER_CLK(RCC_APB2ENR, 18, "tim17", "tim2_ker"),
+       PER_CLK(RCC_APB2ENR, 17, "tim16", "tim2_ker"),
+       PER_CLK(RCC_APB2ENR, 16, "tim15", "tim2_ker"),
+       PER_CLK(RCC_APB2ENR, 1, "tim8", "tim2_ker"),
+       PER_CLK(RCC_APB2ENR, 0, "tim1", "tim2_ker"),
+       PER_CLK(RCC_APB4ENR, 26, "tmpsens", "pclk4"),
+       PER_CLK(RCC_APB4ENR, 16, "rtcapb", "pclk4"),
+       PER_CLK(RCC_APB4ENR, 15, "vref", "pclk4"),
+       PER_CLK(RCC_APB4ENR, 14, "comp12", "pclk4"),
+       PER_CLK(RCC_APB4ENR, 1, "syscfg", "pclk4"),
+};
+
+/* KERNEL CLOCKS */
+#define KER_CLKF(_gate_offset, _bit_idx,\
+               _mux_offset, _mux_shift, _mux_width,\
+               _name, _parent_name,\
+               _flags) \
+{ \
+       .gate = &(struct gate_cfg) {_gate_offset, _bit_idx},\
+       .mux = &(struct muxdiv_cfg) {_mux_offset, _mux_shift, _mux_width },\
+       .name = _name, \
+       .parent_name = _parent_name, \
+       .num_parents = ARRAY_SIZE(_parent_name),\
+       .flags = _flags,\
+}
+
+#define KER_CLK(_gate_offset, _bit_idx, _mux_offset, _mux_shift, _mux_width,\
+               _name, _parent_name) \
+KER_CLKF(_gate_offset, _bit_idx, _mux_offset, _mux_shift, _mux_width,\
+               _name, _parent_name, 0)\
+
+#define KER_CLKF_NOMUX(_gate_offset, _bit_idx,\
+               _name, _parent_name,\
+               _flags) \
+{ \
+       .gate = &(struct gate_cfg) {_gate_offset, _bit_idx},\
+       .mux = NULL,\
+       .name = _name, \
+       .parent_name = _parent_name, \
+       .num_parents = 1,\
+       .flags = _flags,\
+}
+
+static const struct composite_clk_cfg kclk[] = {
+       KER_CLK(RCC_AHB3ENR,  16, RCC_D1CCIPR,  16, 1, "sdmmc1", sdmmc_src),
+       KER_CLKF(RCC_AHB3ENR, 14, RCC_D1CCIPR,   4, 2, "quadspi", qspi_src,
+                       CLK_IGNORE_UNUSED),
+       KER_CLKF(RCC_AHB3ENR, 12, RCC_D1CCIPR,   0, 2, "fmc", fmc_src,
+                       CLK_IGNORE_UNUSED),
+       KER_CLK(RCC_AHB1ENR,  27, RCC_D2CCIP2R, 20, 2, "usb2otg", usbotg_src),
+       KER_CLK(RCC_AHB1ENR,  25, RCC_D2CCIP2R, 20, 2, "usb1otg", usbotg_src),
+       KER_CLK(RCC_AHB1ENR,   5, RCC_D3CCIPR,  16, 2, "adc12", adc_src),
+       KER_CLK(RCC_AHB2ENR,   9, RCC_D1CCIPR,  16, 1, "sdmmc2", sdmmc_src),
+       KER_CLK(RCC_AHB2ENR,   6, RCC_D2CCIP2R,  8, 2, "rng", rng_src),
+       KER_CLK(RCC_AHB4ENR,  24, RCC_D3CCIPR,  16, 2, "adc3", adc_src),
+       KER_CLKF(RCC_APB3ENR,   4, RCC_D1CCIPR,  8, 1, "dsi", dsi_src,
+                       CLK_SET_RATE_PARENT),
+       KER_CLKF_NOMUX(RCC_APB3ENR, 3, "ltdc", ltdc_src, CLK_SET_RATE_PARENT),
+       KER_CLK(RCC_APB1LENR, 31, RCC_D2CCIP2R,  0, 3, "usart8", usart_src2),
+       KER_CLK(RCC_APB1LENR, 30, RCC_D2CCIP2R,  0, 3, "usart7", usart_src2),
+       KER_CLK(RCC_APB1LENR, 27, RCC_D2CCIP2R, 22, 2, "hdmicec", cec_src),
+       KER_CLK(RCC_APB1LENR, 23, RCC_D2CCIP2R, 12, 2, "i2c3", i2c_src1),
+       KER_CLK(RCC_APB1LENR, 22, RCC_D2CCIP2R, 12, 2, "i2c2", i2c_src1),
+       KER_CLK(RCC_APB1LENR, 21, RCC_D2CCIP2R, 12, 2, "i2c1", i2c_src1),
+       KER_CLK(RCC_APB1LENR, 20, RCC_D2CCIP2R,  0, 3, "uart5", usart_src2),
+       KER_CLK(RCC_APB1LENR, 19, RCC_D2CCIP2R,  0, 3, "uart4", usart_src2),
+       KER_CLK(RCC_APB1LENR, 18, RCC_D2CCIP2R,  0, 3, "usart3", usart_src2),
+       KER_CLK(RCC_APB1LENR, 17, RCC_D2CCIP2R,  0, 3, "usart2", usart_src2),
+       KER_CLK(RCC_APB1LENR, 16, RCC_D2CCIP1R, 20, 2, "spdifrx", spdifrx_src),
+       KER_CLK(RCC_APB1LENR, 15, RCC_D2CCIP1R, 16, 3, "spi3", spi_src1),
+       KER_CLK(RCC_APB1LENR, 14, RCC_D2CCIP1R, 16, 3, "spi2", spi_src1),
+       KER_CLK(RCC_APB1LENR,  9, RCC_D2CCIP2R, 28, 3, "lptim1", lptim_src1),
+       KER_CLK(RCC_APB1HENR,  8, RCC_D2CCIP1R, 28, 2, "fdcan", fdcan_src),
+       KER_CLK(RCC_APB1HENR,  2, RCC_D2CCIP1R, 31, 1, "swp", swp_src),
+       KER_CLK(RCC_APB2ENR,  29, RCC_CFGR,     14, 1, "hrtim", hrtim_src),
+       KER_CLK(RCC_APB2ENR,  28, RCC_D2CCIP1R, 24, 1, "dfsdm1", dfsdm1_src),
+       KER_CLKF(RCC_APB2ENR,  24, RCC_D2CCIP1R,  6, 3, "sai3", sai_src,
+                CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
+       KER_CLKF(RCC_APB2ENR,  23, RCC_D2CCIP1R,  6, 3, "sai2", sai_src,
+                CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
+       KER_CLKF(RCC_APB2ENR,  22, RCC_D2CCIP1R,  0, 3, "sai1", sai_src,
+                CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
+       KER_CLK(RCC_APB2ENR,  20, RCC_D2CCIP1R, 16, 3, "spi5", spi_src2),
+       KER_CLK(RCC_APB2ENR,  13, RCC_D2CCIP1R, 16, 3, "spi4", spi_src2),
+       KER_CLK(RCC_APB2ENR,  12, RCC_D2CCIP1R, 16, 3, "spi1", spi_src1),
+       KER_CLK(RCC_APB2ENR,   5, RCC_D2CCIP2R,  3, 3, "usart6", usart_src1),
+       KER_CLK(RCC_APB2ENR,   4, RCC_D2CCIP2R,  3, 3, "usart1", usart_src1),
+       KER_CLK(RCC_APB4ENR,  21, RCC_D3CCIPR,  24, 3, "sai4b", sai_src),
+       KER_CLK(RCC_APB4ENR,  21, RCC_D3CCIPR,  21, 3, "sai4a", sai_src),
+       KER_CLK(RCC_APB4ENR,  12, RCC_D3CCIPR,  13, 3, "lptim5", lptim_src2),
+       KER_CLK(RCC_APB4ENR,  11, RCC_D3CCIPR,  13, 3, "lptim4", lptim_src2),
+       KER_CLK(RCC_APB4ENR,  10, RCC_D3CCIPR,  13, 3, "lptim3", lptim_src2),
+       KER_CLK(RCC_APB4ENR,   9, RCC_D3CCIPR,  10, 3, "lptim2", lptim_src2),
+       KER_CLK(RCC_APB4ENR,   7, RCC_D3CCIPR,   8, 2, "i2c4", i2c_src2),
+       KER_CLK(RCC_APB4ENR,   5, RCC_D3CCIPR,  28, 3, "spi6", spi_src3),
+       KER_CLK(RCC_APB4ENR,   3, RCC_D3CCIPR,   0, 3, "lpuart1", lpuart1_src),
+};
+
+static struct composite_clk_gcfg kernel_clk_cfg = {
+       M_CFG_MUX(NULL, 0),
+       M_CFG_GATE(NULL, 0),
+};
+
+/* RTC clock */
+/*
+ * RTC & LSE registers are protected against parasitic write access.
+ * PWR_CR_DBP bit must be set to enable write access to RTC registers.
+ */
+/* STM32_PWR_CR */
+#define PWR_CR                         0x00
+/* STM32_PWR_CR bit field */
+#define PWR_CR_DBP                     BIT(8)
+
+static struct composite_clk_gcfg rtc_clk_cfg = {
+       M_CFG_MUX(NULL, 0),
+       M_CFG_GATE(NULL, 0),
+};
+
+static const struct composite_clk_cfg rtc_clk =
+       KER_CLK(RCC_BDCR, 15, RCC_BDCR, 8, 2, "rtc_ck", rtc_src);
+
+/* Micro-controller output clock */
+static struct composite_clk_gcfg mco_clk_cfg = {
+       M_CFG_MUX(NULL, 0),
+       M_CFG_DIV(NULL, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO),
+};
+
+#define M_MCO_F(_name, _parents, _mux_offset,  _mux_shift, _mux_width,\
+               _rate_offset, _rate_shift, _rate_width,\
+               _flags)\
+{\
+       .mux = &(struct muxdiv_cfg) {_mux_offset, _mux_shift, _mux_width },\
+       .div = &(struct muxdiv_cfg) {_rate_offset, _rate_shift, _rate_width},\
+       .gate = NULL,\
+       .name = _name,\
+       .parent_name = _parents,\
+       .num_parents = ARRAY_SIZE(_parents),\
+       .flags = _flags,\
+}
+
+static const struct composite_clk_cfg mco_clk[] = {
+       M_MCO_F("mco1", mco_src1, RCC_CFGR, 22, 4, RCC_CFGR, 18, 4, 0),
+       M_MCO_F("mco2", mco_src2, RCC_CFGR, 29, 3, RCC_CFGR, 25, 4, 0),
+};
+
+static void __init stm32h7_rcc_init(struct device_node *np)
+{
+       struct clk_hw_onecell_data *clk_data;
+       struct composite_cfg c_cfg;
+       int n;
+       const char *hse_clk, *lse_clk, *i2s_clk;
+       struct regmap *pdrm;
+
+       clk_data = kzalloc(sizeof(*clk_data) +
+                       sizeof(*clk_data->hws) * STM32H7_MAX_CLKS,
+                       GFP_KERNEL);
+       if (!clk_data)
+               return;
+
+       clk_data->num = STM32H7_MAX_CLKS;
+
+       hws = clk_data->hws;
+
+       for (n = 0; n < STM32H7_MAX_CLKS; n++)
+               hws[n] = ERR_PTR(-ENOENT);
+
+       /* get RCC base @ from DT */
+       base = of_iomap(np, 0);
+       if (!base) {
+               pr_err("%s: unable to map resource", np->name);
+               goto err_free_clks;
+       }
+
+       pdrm = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
+       if (IS_ERR(pdrm))
+               pr_warn("%s: Unable to get syscfg\n", __func__);
+       else
+               /* In any case disable backup domain write protection
+                * and will never be enabled.
+                * Needed by LSE & RTC clocks.
+                */
+               regmap_update_bits(pdrm, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);
+
+       /* Put parent names from DT */
+       hse_clk = of_clk_get_parent_name(np, 0);
+       lse_clk = of_clk_get_parent_name(np, 1);
+       i2s_clk = of_clk_get_parent_name(np, 2);
+
+       sai_src[3] = i2s_clk;
+       spi_src1[3] = i2s_clk;
+
+       /* Register Internal oscillators */
+       clk_hw_register_fixed_rate(NULL, "clk-hsi", NULL, 0, 64000000);
+       clk_hw_register_fixed_rate(NULL, "clk-csi", NULL, 0, 4000000);
+       clk_hw_register_fixed_rate(NULL, "clk-lsi", NULL, 0, 32000);
+       clk_hw_register_fixed_rate(NULL, "clk-rc48", NULL, 0, 48000);
+
+       /* This clock is coming from outside. Frequencies unknown */
+       hws[CK_DSI_PHY] = clk_hw_register_fixed_rate(NULL, "ck_dsi_phy", NULL,
+                       0, 0);
+
+       hws[HSI_DIV] = clk_hw_register_divider(NULL, "hsidiv", "clk-hsi", 0,
+                       base + RCC_CR, 3, 2, CLK_DIVIDER_POWER_OF_TWO,
+                       &stm32rcc_lock);
+
+       hws[HSE_1M] = clk_hw_register_divider(NULL, "hse_1M", "hse_ck", 0,
+                       base + RCC_CFGR, 8, 6, CLK_DIVIDER_ONE_BASED |
+                       CLK_DIVIDER_ALLOW_ZERO,
+                       &stm32rcc_lock);
+
+       /* Mux system clocks */
+       for (n = 0; n < ARRAY_SIZE(stm32_mclk); n++)
+               hws[MCLK_BANK + n] = clk_hw_register_mux(NULL,
+                               stm32_mclk[n].name,
+                               stm32_mclk[n].parents,
+                               stm32_mclk[n].num_parents,
+                               stm32_mclk[n].flags,
+                               stm32_mclk[n].offset + base,
+                               stm32_mclk[n].shift,
+                               stm32_mclk[n].width,
+                               0,
+                               &stm32rcc_lock);
+
+       register_core_and_bus_clocks();
+
+       /* Oscillary clocks */
+       for (n = 0; n < ARRAY_SIZE(stm32_oclk); n++)
+               hws[OSC_BANK + n] = clk_register_ready_gate(NULL,
+                               stm32_oclk[n].name,
+                               stm32_oclk[n].parent,
+                               stm32_oclk[n].gate_offset + base,
+                               stm32_oclk[n].bit_idx,
+                               stm32_oclk[n].bit_rdy,
+                               stm32_oclk[n].flags,
+                               &stm32rcc_lock);
+
+       hws[HSE_CK] = clk_register_ready_gate(NULL,
+                               "hse_ck",
+                               hse_clk,
+                               RCC_CR + base,
+                               16, 17,
+                               0,
+                               &stm32rcc_lock);
+
+       hws[LSE_CK] = clk_register_ready_gate(NULL,
+                               "lse_ck",
+                               lse_clk,
+                               RCC_BDCR + base,
+                               0, 1,
+                               0,
+                               &stm32rcc_lock);
+
+       hws[CSI_KER_DIV122 + n] = clk_hw_register_fixed_factor(NULL,
+                       "csi_ker_div122", "csi_ker", 0, 1, 122);
+
+       /* PLLs */
+       for (n = 0; n < ARRAY_SIZE(stm32_pll); n++) {
+               int odf;
+
+               /* Register the VCO */
+               clk_register_stm32_pll(NULL, stm32_pll[n].name,
+                               stm32_pll[n].parent_name, stm32_pll[n].flags,
+                               stm32_pll[n].cfg,
+                               &stm32rcc_lock);
+
+               /* Register the 3 output dividers */
+               for (odf = 0; odf < 3; odf++) {
+                       int idx = n * 3 + odf;
+
+                       get_cfg_composite_div(&odf_clk_gcfg, &stm32_odf[n][odf],
+                                       &c_cfg, &stm32rcc_lock);
+
+                       hws[ODF_BANK + idx] = clk_hw_register_composite(NULL,
+                                       stm32_odf[n][odf].name,
+                                       stm32_odf[n][odf].parent_name,
+                                       stm32_odf[n][odf].num_parents,
+                                       c_cfg.mux_hw, c_cfg.mux_ops,
+                                       c_cfg.div_hw, c_cfg.div_ops,
+                                       c_cfg.gate_hw, c_cfg.gate_ops,
+                                       stm32_odf[n][odf].flags);
+               }
+       }
+
+       /* Peripheral clocks */
+       for (n = 0; n < ARRAY_SIZE(pclk); n++)
+               hws[PERIF_BANK + n] = clk_hw_register_gate(NULL, pclk[n].name,
+                               pclk[n].parent,
+                               pclk[n].flags, base + pclk[n].gate_offset,
+                               pclk[n].bit_idx, pclk[n].flags, &stm32rcc_lock);
+
+       /* Kernel clocks */
+       for (n = 0; n < ARRAY_SIZE(kclk); n++) {
+               get_cfg_composite_div(&kernel_clk_cfg, &kclk[n], &c_cfg,
+                               &stm32rcc_lock);
+
+               hws[KERN_BANK + n] = clk_hw_register_composite(NULL,
+                               kclk[n].name,
+                               kclk[n].parent_name,
+                               kclk[n].num_parents,
+                               c_cfg.mux_hw, c_cfg.mux_ops,
+                               c_cfg.div_hw, c_cfg.div_ops,
+                               c_cfg.gate_hw, c_cfg.gate_ops,
+                               kclk[n].flags);
+       }
+
+       /* RTC clock (default state is off) */
+       clk_hw_register_fixed_rate(NULL, "off", NULL, 0, 0);
+
+       get_cfg_composite_div(&rtc_clk_cfg, &rtc_clk, &c_cfg, &stm32rcc_lock);
+
+       hws[RTC_CK] = clk_hw_register_composite(NULL,
+                       rtc_clk.name,
+                       rtc_clk.parent_name,
+                       rtc_clk.num_parents,
+                       c_cfg.mux_hw, c_cfg.mux_ops,
+                       c_cfg.div_hw, c_cfg.div_ops,
+                       c_cfg.gate_hw, c_cfg.gate_ops,
+                       rtc_clk.flags);
+
+       /* Micro-controller clocks */
+       for (n = 0; n < ARRAY_SIZE(mco_clk); n++) {
+               get_cfg_composite_div(&mco_clk_cfg, &mco_clk[n], &c_cfg,
+                               &stm32rcc_lock);
+
+               hws[MCO_BANK + n] = clk_hw_register_composite(NULL,
+                               mco_clk[n].name,
+                               mco_clk[n].parent_name,
+                               mco_clk[n].num_parents,
+                               c_cfg.mux_hw, c_cfg.mux_ops,
+                               c_cfg.div_hw, c_cfg.div_ops,
+                               c_cfg.gate_hw, c_cfg.gate_ops,
+                               mco_clk[n].flags);
+       }
+
+       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
+
+       return;
+
+err_free_clks:
+       kfree(clk_data);
+}
+
+/* The RCC node is a clock and reset controller, and these
+ * functionalities are supported by different drivers that
+ * matches the same compatible strings.
+ */
+CLK_OF_DECLARE_DRIVER(stm32h7_rcc, "st,stm32h743-rcc", stm32h7_rcc_init);
index ea7d552a2f2b11be9429574597ea3d7cf76249b0..decffb3826ece8be3206c8c9da2d535ddcbf5be1 100644 (file)
@@ -57,6 +57,7 @@
 #define VC5_PRIM_SRC_SHDN                      0x10
 #define VC5_PRIM_SRC_SHDN_EN_XTAL              BIT(7)
 #define VC5_PRIM_SRC_SHDN_EN_CLKIN             BIT(6)
+#define VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ  BIT(3)
 #define VC5_PRIM_SRC_SHDN_SP                   BIT(1)
 #define VC5_PRIM_SRC_SHDN_EN_GBL_SHDN          BIT(0)
 
 /* flags to describe chip features */
 /* chip has built-in oscilator */
 #define VC5_HAS_INTERNAL_XTAL  BIT(0)
+/* chip has PFD requency doubler */
+#define VC5_HAS_PFD_FREQ_DBL   BIT(1)
 
 /* Supported IDT VC5 models. */
 enum vc5_model {
        IDT_VC5_5P49V5923,
+       IDT_VC5_5P49V5925,
        IDT_VC5_5P49V5933,
        IDT_VC5_5P49V5935,
+       IDT_VC6_5P49V6901,
 };
 
 /* Structure to describe features of a particular VC5 model */
@@ -157,6 +162,8 @@ struct vc5_driver_data {
        struct clk              *pin_clkin;
        unsigned char           clk_mux_ins;
        struct clk_hw           clk_mux;
+       struct clk_hw           clk_mul;
+       struct clk_hw           clk_pfd;
        struct vc5_hw_data      clk_pll;
        struct vc5_hw_data      clk_fod[VC5_MAX_FOD_NUM];
        struct vc5_hw_data      clk_out[VC5_MAX_CLK_OUT_NUM];
@@ -166,6 +173,14 @@ static const char * const vc5_mux_names[] = {
        "mux"
 };
 
+static const char * const vc5_dbl_names[] = {
+       "dbl"
+};
+
+static const char * const vc5_pfd_names[] = {
+       "pfd"
+};
+
 static const char * const vc5_pll_names[] = {
        "pll"
 };
@@ -254,11 +269,64 @@ static int vc5_mux_set_parent(struct clk_hw *hw, u8 index)
        return regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN, mask, src);
 }
 
-static unsigned long vc5_mux_recalc_rate(struct clk_hw *hw,
+static const struct clk_ops vc5_mux_ops = {
+       .set_parent     = vc5_mux_set_parent,
+       .get_parent     = vc5_mux_get_parent,
+};
+
+static unsigned long vc5_dbl_recalc_rate(struct clk_hw *hw,
                                         unsigned long parent_rate)
 {
        struct vc5_driver_data *vc5 =
-               container_of(hw, struct vc5_driver_data, clk_mux);
+               container_of(hw, struct vc5_driver_data, clk_mul);
+       unsigned int premul;
+
+       regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &premul);
+       if (premul & VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ)
+               parent_rate *= 2;
+
+       return parent_rate;
+}
+
+static long vc5_dbl_round_rate(struct clk_hw *hw, unsigned long rate,
+                              unsigned long *parent_rate)
+{
+       if ((*parent_rate == rate) || ((*parent_rate * 2) == rate))
+               return rate;
+       else
+               return -EINVAL;
+}
+
+static int vc5_dbl_set_rate(struct clk_hw *hw, unsigned long rate,
+                           unsigned long parent_rate)
+{
+       struct vc5_driver_data *vc5 =
+               container_of(hw, struct vc5_driver_data, clk_mul);
+       u32 mask;
+
+       if ((parent_rate * 2) == rate)
+               mask = VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ;
+       else
+               mask = 0;
+
+       regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN,
+                          VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ,
+                          mask);
+
+       return 0;
+}
+
+static const struct clk_ops vc5_dbl_ops = {
+       .recalc_rate    = vc5_dbl_recalc_rate,
+       .round_rate     = vc5_dbl_round_rate,
+       .set_rate       = vc5_dbl_set_rate,
+};
+
+static unsigned long vc5_pfd_recalc_rate(struct clk_hw *hw,
+                                        unsigned long parent_rate)
+{
+       struct vc5_driver_data *vc5 =
+               container_of(hw, struct vc5_driver_data, clk_pfd);
        unsigned int prediv, div;
 
        regmap_read(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV, &prediv);
@@ -276,7 +344,7 @@ static unsigned long vc5_mux_recalc_rate(struct clk_hw *hw,
                return parent_rate / VC5_REF_DIVIDER_REF_DIV(div);
 }
 
-static long vc5_mux_round_rate(struct clk_hw *hw, unsigned long rate,
+static long vc5_pfd_round_rate(struct clk_hw *hw, unsigned long rate,
                               unsigned long *parent_rate)
 {
        unsigned long idiv;
@@ -296,11 +364,11 @@ static long vc5_mux_round_rate(struct clk_hw *hw, unsigned long rate,
        return *parent_rate / idiv;
 }
 
-static int vc5_mux_set_rate(struct clk_hw *hw, unsigned long rate,
+static int vc5_pfd_set_rate(struct clk_hw *hw, unsigned long rate,
                            unsigned long parent_rate)
 {
        struct vc5_driver_data *vc5 =
-               container_of(hw, struct vc5_driver_data, clk_mux);
+               container_of(hw, struct vc5_driver_data, clk_pfd);
        unsigned long idiv;
        u8 div;
 
@@ -328,12 +396,10 @@ static int vc5_mux_set_rate(struct clk_hw *hw, unsigned long rate,
        return 0;
 }
 
-static const struct clk_ops vc5_mux_ops = {
-       .set_parent     = vc5_mux_set_parent,
-       .get_parent     = vc5_mux_get_parent,
-       .recalc_rate    = vc5_mux_recalc_rate,
-       .round_rate     = vc5_mux_round_rate,
-       .set_rate       = vc5_mux_set_rate,
+static const struct clk_ops vc5_pfd_ops = {
+       .recalc_rate    = vc5_pfd_recalc_rate,
+       .round_rate     = vc5_pfd_round_rate,
+       .set_rate       = vc5_pfd_set_rate,
 };
 
 /*
@@ -426,6 +492,10 @@ static unsigned long vc5_fod_recalc_rate(struct clk_hw *hw,
        div_frc = (od_frc[0] << 22) | (od_frc[1] << 14) |
                  (od_frc[2] << 6) | (od_frc[3] >> 2);
 
+       /* Avoid division by zero if the output is not configured. */
+       if (div_int == 0 && div_frc == 0)
+               return 0;
+
        /* The PLL divider has 12 integer bits and 30 fractional bits */
        return div64_u64((u64)f_in << 24ULL, ((u64)div_int << 24ULL) + div_frc);
 }
@@ -503,6 +573,25 @@ static int vc5_clk_out_prepare(struct clk_hw *hw)
 {
        struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
        struct vc5_driver_data *vc5 = hwdata->vc5;
+       const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM |
+                       VC5_OUT_DIV_CONTROL_SEL_EXT |
+                       VC5_OUT_DIV_CONTROL_EN_FOD;
+       unsigned int src;
+       int ret;
+
+       /*
+        * If the input mux is disabled, enable it first and
+        * select source from matching FOD.
+        */
+       regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src);
+       if ((src & mask) == 0) {
+               src = VC5_OUT_DIV_CONTROL_RESET | VC5_OUT_DIV_CONTROL_EN_FOD;
+               ret = regmap_update_bits(vc5->regmap,
+                                        VC5_OUT_DIV_CONTROL(hwdata->num),
+                                        mask | VC5_OUT_DIV_CONTROL_RESET, src);
+               if (ret)
+                       return ret;
+       }
 
        /* Enable the clock buffer */
        regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
@@ -516,7 +605,7 @@ static void vc5_clk_out_unprepare(struct clk_hw *hw)
        struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
        struct vc5_driver_data *vc5 = hwdata->vc5;
 
-       /* Enable the clock buffer */
+       /* Disable the clock buffer */
        regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
                           VC5_CLK_OUTPUT_CFG1_EN_CLKBUF, 0);
 }
@@ -537,6 +626,9 @@ static unsigned char vc5_clk_out_get_parent(struct clk_hw *hw)
        regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src);
        src &= mask;
 
+       if (src == 0)   /* Input mux set to DISABLED */
+               return 0;
+
        if ((src & fodclkmask) == VC5_OUT_DIV_CONTROL_EN_FOD)
                return 0;
 
@@ -595,7 +687,9 @@ static int vc5_map_index_to_output(const enum vc5_model model,
        case IDT_VC5_5P49V5933:
                return (n == 0) ? 0 : 3;
        case IDT_VC5_5P49V5923:
+       case IDT_VC5_5P49V5925:
        case IDT_VC5_5P49V5935:
+       case IDT_VC6_5P49V6901:
        default:
                return n;
        }
@@ -672,12 +766,46 @@ static int vc5_probe(struct i2c_client *client,
                goto err_clk;
        }
 
+       if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) {
+               /* Register frequency doubler */
+               memset(&init, 0, sizeof(init));
+               init.name = vc5_dbl_names[0];
+               init.ops = &vc5_dbl_ops;
+               init.flags = CLK_SET_RATE_PARENT;
+               init.parent_names = vc5_mux_names;
+               init.num_parents = 1;
+               vc5->clk_mul.init = &init;
+               ret = devm_clk_hw_register(&client->dev, &vc5->clk_mul);
+               if (ret) {
+                       dev_err(&client->dev, "unable to register %s\n",
+                               init.name);
+                       goto err_clk;
+               }
+       }
+
+       /* Register PFD */
+       memset(&init, 0, sizeof(init));
+       init.name = vc5_pfd_names[0];
+       init.ops = &vc5_pfd_ops;
+       init.flags = CLK_SET_RATE_PARENT;
+       if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL)
+               init.parent_names = vc5_dbl_names;
+       else
+               init.parent_names = vc5_mux_names;
+       init.num_parents = 1;
+       vc5->clk_pfd.init = &init;
+       ret = devm_clk_hw_register(&client->dev, &vc5->clk_pfd);
+       if (ret) {
+               dev_err(&client->dev, "unable to register %s\n", init.name);
+               goto err_clk;
+       }
+
        /* Register PLL */
        memset(&init, 0, sizeof(init));
        init.name = vc5_pll_names[0];
        init.ops = &vc5_pll_ops;
        init.flags = CLK_SET_RATE_PARENT;
-       init.parent_names = vc5_mux_names;
+       init.parent_names = vc5_pfd_names;
        init.num_parents = 1;
        vc5->clk_pll.num = 0;
        vc5->clk_pll.vc5 = vc5;
@@ -785,6 +913,13 @@ static const struct vc5_chip_info idt_5p49v5923_info = {
        .flags = 0,
 };
 
+static const struct vc5_chip_info idt_5p49v5925_info = {
+       .model = IDT_VC5_5P49V5925,
+       .clk_fod_cnt = 4,
+       .clk_out_cnt = 5,
+       .flags = 0,
+};
+
 static const struct vc5_chip_info idt_5p49v5933_info = {
        .model = IDT_VC5_5P49V5933,
        .clk_fod_cnt = 2,
@@ -799,18 +934,29 @@ static const struct vc5_chip_info idt_5p49v5935_info = {
        .flags = VC5_HAS_INTERNAL_XTAL,
 };
 
+static const struct vc5_chip_info idt_5p49v6901_info = {
+       .model = IDT_VC6_5P49V6901,
+       .clk_fod_cnt = 4,
+       .clk_out_cnt = 5,
+       .flags = VC5_HAS_PFD_FREQ_DBL,
+};
+
 static const struct i2c_device_id vc5_id[] = {
        { "5p49v5923", .driver_data = IDT_VC5_5P49V5923 },
+       { "5p49v5925", .driver_data = IDT_VC5_5P49V5925 },
        { "5p49v5933", .driver_data = IDT_VC5_5P49V5933 },
        { "5p49v5935", .driver_data = IDT_VC5_5P49V5935 },
+       { "5p49v6901", .driver_data = IDT_VC6_5P49V6901 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, vc5_id);
 
 static const struct of_device_id clk_vc5_of_match[] = {
        { .compatible = "idt,5p49v5923", .data = &idt_5p49v5923_info },
+       { .compatible = "idt,5p49v5925", .data = &idt_5p49v5925_info },
        { .compatible = "idt,5p49v5933", .data = &idt_5p49v5933_info },
        { .compatible = "idt,5p49v5935", .data = &idt_5p49v5935_info },
+       { .compatible = "idt,5p49v6901", .data = &idt_5p49v6901_info },
        { },
 };
 MODULE_DEVICE_TABLE(of, clk_vc5_of_match);
index bc37030e38ba62833316302a383d86cdfd671921..4c75821a3933c26cd1c0582ce7ae13b145836f40 100644 (file)
@@ -192,7 +192,7 @@ static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_ty
 
        reg = of_iomap(np, 0);
        if (reg == NULL) {
-               pr_err("Unable to map CSR register for %s\n", np->full_name);
+               pr_err("Unable to map CSR register for %pOF\n", np);
                return;
        }
        of_property_read_string(np, "clock-output-names", &clk_name);
@@ -409,12 +409,12 @@ static void xgene_pmdclk_init(struct device_node *np)
        /* Parse the DTS register for resource */
        rc = of_address_to_resource(np, 0, &res);
        if (rc != 0) {
-               pr_err("no DTS register for %s\n", np->full_name);
+               pr_err("no DTS register for %pOF\n", np);
                return;
        }
        csr_reg = of_iomap(np, 0);
        if (!csr_reg) {
-               pr_err("Unable to map resource for %s\n", np->full_name);
+               pr_err("Unable to map resource for %pOF\n", np);
                return;
        }
        of_property_read_string(np, "clock-output-names", &clk_name);
@@ -703,16 +703,14 @@ static void __init xgene_devclk_init(struct device_node *np)
                rc = of_address_to_resource(np, i, &res);
                if (rc != 0) {
                        if (i == 0) {
-                               pr_err("no DTS register for %s\n",
-                                       np->full_name);
+                               pr_err("no DTS register for %pOF\n", np);
                                return;
                        }
                        break;
                }
                map_res = of_iomap(np, i);
                if (map_res == NULL) {
-                       pr_err("Unable to map resource %d for %s\n",
-                               i, np->full_name);
+                       pr_err("Unable to map resource %d for %pOF\n", i, np);
                        goto err;
                }
                if (strcmp(res.name, "div-reg") == 0)
@@ -747,8 +745,7 @@ static void __init xgene_devclk_init(struct device_node *np)
        pr_debug("Add %s clock\n", clk_name);
        rc = of_clk_add_provider(np, of_clk_src_simple_get, clk);
        if (rc != 0)
-               pr_err("%s: could register provider clk %s\n", __func__,
-                       np->full_name);
+               pr_err("%s: could register provider clk %pOF\n", __func__, np);
 
        return;
 
index fc58c52a26b4d1de4802be06950f45469d5b807d..c8d83acda0061977218d1fd084bc6faddff4091c 100644 (file)
@@ -3132,7 +3132,7 @@ int of_clk_add_provider(struct device_node *np,
        mutex_lock(&of_clk_mutex);
        list_add(&cp->link, &of_clk_providers);
        mutex_unlock(&of_clk_mutex);
-       pr_debug("Added clock from %s\n", np->full_name);
+       pr_debug("Added clock from %pOF\n", np);
 
        ret = of_clk_set_defaults(np, true);
        if (ret < 0)
@@ -3167,7 +3167,7 @@ int of_clk_add_hw_provider(struct device_node *np,
        mutex_lock(&of_clk_mutex);
        list_add(&cp->link, &of_clk_providers);
        mutex_unlock(&of_clk_mutex);
-       pr_debug("Added clk_hw provider from %s\n", np->full_name);
+       pr_debug("Added clk_hw provider from %pOF\n", np);
 
        ret = of_clk_set_defaults(np, true);
        if (ret < 0)
index bb8a77a5985f8627e6ea396298745c9b6c7eaf77..6b2f29df3f709feda0dd2dce53f1430152734d2c 100644 (file)
@@ -77,8 +77,8 @@ static struct clk *__of_clk_get_by_name(struct device_node *np,
                        break;
                } else if (name && index >= 0) {
                        if (PTR_ERR(clk) != -EPROBE_DEFER)
-                               pr_err("ERROR: could not get clock %s:%s(%i)\n",
-                                       np->full_name, name ? name : "", index);
+                               pr_err("ERROR: could not get clock %pOF:%s(%i)\n",
+                                       np, name ? name : "", index);
                        return clk;
                }
 
index 4181b68085456d9cc8f9f0ff0b8bbca5eb3fa7f5..e786d717f75dcf51383627988e22f5956fe74d6c 100644 (file)
@@ -55,9 +55,9 @@ static struct hisi_fixed_factor_clock hi6220_fixed_factor_clks[] __initdata = {
 };
 
 static struct hisi_gate_clock hi6220_separated_gate_clks_ao[] __initdata = {
-       { HI6220_WDT0_PCLK,   "wdt0_pclk",   "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 12, 0, },
-       { HI6220_WDT1_PCLK,   "wdt1_pclk",   "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 13, 0, },
-       { HI6220_WDT2_PCLK,   "wdt2_pclk",   "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 14, 0, },
+       { HI6220_WDT0_PCLK,   "wdt0_pclk",   "ref32k",   CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 12, 0, },
+       { HI6220_WDT1_PCLK,   "wdt1_pclk",   "ref32k",   CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 13, 0, },
+       { HI6220_WDT2_PCLK,   "wdt2_pclk",   "ref32k",   CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 14, 0, },
        { HI6220_TIMER0_PCLK, "timer0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 15, 0, },
        { HI6220_TIMER1_PCLK, "timer1_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 16, 0, },
        { HI6220_TIMER2_PCLK, "timer2_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 17, 0, },
index 1e3c9ea5f9dcf9e909e4412eaf5a2185659d9c84..7bcaf270db1175860832f3269cc7c03d1abdc68a 100644 (file)
@@ -416,10 +416,10 @@ static void __init mx51_clocks_init(struct device_node *np)
 
        clk[IMX5_CLK_LP_APM]            = imx_clk_mux("lp_apm", MXC_CCM_CCSR, 9, 1,
                                                lp_apm_sel, ARRAY_SIZE(lp_apm_sel));
-       clk[IMX5_CLK_IPU_DI0_SEL]       = imx_clk_mux("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3,
-                                               mx51_ipu_di0_sel, ARRAY_SIZE(mx51_ipu_di0_sel));
-       clk[IMX5_CLK_IPU_DI1_SEL]       = imx_clk_mux("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3,
-                                               mx51_ipu_di1_sel, ARRAY_SIZE(mx51_ipu_di1_sel));
+       clk[IMX5_CLK_IPU_DI0_SEL]       = imx_clk_mux_flags("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3,
+                                               mx51_ipu_di0_sel, ARRAY_SIZE(mx51_ipu_di0_sel), CLK_SET_RATE_PARENT);
+       clk[IMX5_CLK_IPU_DI1_SEL]       = imx_clk_mux_flags("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3,
+                                               mx51_ipu_di1_sel, ARRAY_SIZE(mx51_ipu_di1_sel), CLK_SET_RATE_PARENT);
        clk[IMX5_CLK_TVE_EXT_SEL]       = imx_clk_mux_flags("tve_ext_sel", MXC_CCM_CSCMR1, 6, 1,
                                                mx51_tve_ext_sel, ARRAY_SIZE(mx51_tve_ext_sel), CLK_SET_RATE_PARENT);
        clk[IMX5_CLK_TVE_SEL]           = imx_clk_mux("tve_sel", MXC_CCM_CSCMR1, 7, 1,
index 5fd4ddac1bf19cba71f16d95911e1a2e54218f0f..9642cdf0fb88e0e717e4cb7fdf9986f88fa02fd8 100644 (file)
@@ -71,7 +71,7 @@ static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
 static const char *pll6_bypass_sels[]  = { "pll6", "pll6_bypass_src", };
 static const char *pll7_bypass_sels[]  = { "pll7", "pll7_bypass_src", };
 
-static struct clk_div_table clk_enet_ref_table[] = {
+static const struct clk_div_table clk_enet_ref_table[] = {
        { .val = 0, .div = 20, },
        { .val = 1, .div = 10, },
        { .val = 2, .div = 5, },
@@ -79,14 +79,14 @@ static struct clk_div_table clk_enet_ref_table[] = {
        { }
 };
 
-static struct clk_div_table post_div_table[] = {
+static const struct clk_div_table post_div_table[] = {
        { .val = 2, .div = 1, },
        { .val = 1, .div = 2, },
        { .val = 0, .div = 4, },
        { }
 };
 
-static struct clk_div_table video_div_table[] = {
+static const struct clk_div_table video_div_table[] = {
        { .val = 0, .div = 1, },
        { .val = 1, .div = 2, },
        { .val = 2, .div = 1, },
index b5c96de41ccf957b5f556794756545714d0a3528..e6d389e333d7d15bdb30cde8d2db45abc1706f3b 100644 (file)
@@ -105,7 +105,7 @@ static int const clks_init_on[] __initconst = {
        IMX6SX_CLK_EPIT2,
 };
 
-static struct clk_div_table clk_enet_ref_table[] = {
+static const struct clk_div_table clk_enet_ref_table[] = {
        { .val = 0, .div = 20, },
        { .val = 1, .div = 10, },
        { .val = 2, .div = 5, },
@@ -113,14 +113,14 @@ static struct clk_div_table clk_enet_ref_table[] = {
        { }
 };
 
-static struct clk_div_table post_div_table[] = {
+static const struct clk_div_table post_div_table[] = {
        { .val = 2, .div = 1, },
        { .val = 1, .div = 2, },
        { .val = 0, .div = 4, },
        { }
 };
 
-static struct clk_div_table video_div_table[] = {
+static const struct clk_div_table video_div_table[] = {
        { .val = 0, .div = 1, },
        { .val = 1, .div = 2, },
        { .val = 2, .div = 1, },
index b4e0dff3c8c26b9c2a7eac10702b222e486bad96..5e8c18afce9ad35742dd378cded8042abe80c922 100644 (file)
@@ -78,7 +78,7 @@ static int const clks_init_on[] __initconst = {
        IMX6UL_CLK_MMDC_P0_FAST, IMX6UL_CLK_MMDC_P0_IPG,
 };
 
-static struct clk_div_table clk_enet_ref_table[] = {
+static const struct clk_div_table clk_enet_ref_table[] = {
        { .val = 0, .div = 20, },
        { .val = 1, .div = 10, },
        { .val = 2, .div = 5, },
@@ -86,14 +86,14 @@ static struct clk_div_table clk_enet_ref_table[] = {
        { }
 };
 
-static struct clk_div_table post_div_table[] = {
+static const struct clk_div_table post_div_table[] = {
        { .val = 2, .div = 1, },
        { .val = 1, .div = 2, },
        { .val = 0, .div = 4, },
        { }
 };
 
-static struct clk_div_table video_div_table[] = {
+static const struct clk_div_table video_div_table[] = {
        { .val = 0, .div = 1, },
        { .val = 1, .div = 2, },
        { .val = 2, .div = 1, },
index 3da121826b1baba4667858e01579dfb7d1acab12..2305699db46798441c7c32ef8910b5fe3354c64a 100644 (file)
@@ -27,7 +27,7 @@ static u32 share_count_sai2;
 static u32 share_count_sai3;
 static u32 share_count_nand;
 
-static struct clk_div_table test_div_table[] = {
+static const struct clk_div_table test_div_table[] = {
        { .val = 3, .div = 1, },
        { .val = 2, .div = 1, },
        { .val = 1, .div = 2, },
@@ -35,7 +35,7 @@ static struct clk_div_table test_div_table[] = {
        { }
 };
 
-static struct clk_div_table post_div_table[] = {
+static const struct clk_div_table post_div_table[] = {
        { .val = 3, .div = 4, },
        { .val = 2, .div = 1, },
        { .val = 1, .div = 2, },
index 59b1863deb88863fcf9e1b113ea14303dfcb5f04..6dae54325a91ddb32bb733b9d7d5cf48d0ecc023 100644 (file)
@@ -102,7 +102,7 @@ static const char *ftm_ext_sels[]   = {"sirc_128k", "sxosc", "fxosc_half", "audio_
 static const char *ftm_fix_sels[]      = { "sxosc", "ipg_bus", };
 
 
-static struct clk_div_table pll4_audio_div_table[] = {
+static const struct clk_div_table pll4_audio_div_table[] = {
        { .val = 0, .div = 1 },
        { .val = 1, .div = 2 },
        { .val = 2, .div = 6 },
index edd8e6918050f3bdaa0a9bc8989be19d617d7f7d..16e56772d280ba29d56ae18ec90e626a77c28906 100644 (file)
@@ -27,7 +27,6 @@ static inline struct mtk_clk_cpumux *to_mtk_clk_cpumux(struct clk_hw *_hw)
 static u8 clk_cpumux_get_parent(struct clk_hw *hw)
 {
        struct mtk_clk_cpumux *mux = to_mtk_clk_cpumux(hw);
-       int num_parents = clk_hw_get_num_parents(hw);
        unsigned int val;
 
        regmap_read(mux->regmap, mux->reg, &val);
@@ -35,9 +34,6 @@ static u8 clk_cpumux_get_parent(struct clk_hw *hw)
        val >>= mux->shift;
        val &= mux->mask;
 
-       if (val >= num_parents)
-               return -EINVAL;
-
        return val;
 }
 
@@ -98,7 +94,7 @@ int __init mtk_clk_register_cpumuxes(struct device_node *node,
 
        regmap = syscon_node_to_regmap(node);
        if (IS_ERR(regmap)) {
-               pr_err("Cannot find regmap for %s: %ld\n", node->full_name,
+               pr_err("Cannot find regmap for %pOF: %ld\n", node,
                       PTR_ERR(regmap));
                return PTR_ERR(regmap);
        }
index 0541df78141c7d8b0efe78d95d017a0a51263115..9c0ae4278a946bdb8dd18944fec6b09581c0ffa9 100644 (file)
@@ -114,7 +114,7 @@ int mtk_clk_register_gates(struct device_node *node,
 
        regmap = syscon_node_to_regmap(node);
        if (IS_ERR(regmap)) {
-               pr_err("Cannot find regmap for %s: %ld\n", node->full_name,
+               pr_err("Cannot find regmap for %pOF: %ld\n", node,
                                PTR_ERR(regmap));
                return PTR_ERR(regmap);
        }
index 309049d41f1ba04539fee6a7853a98d1f44e7874..d3551d5efef241e04aaabd6a8f372f22c486a5b1 100644 (file)
@@ -72,7 +72,7 @@ void mtk_register_reset_controller(struct device_node *np,
 
        regmap = syscon_node_to_regmap(np);
        if (IS_ERR(regmap)) {
-               pr_err("Cannot find regmap for %s: %ld\n", np->full_name,
+               pr_err("Cannot find regmap for %pOF: %ld\n", np,
                                PTR_ERR(regmap));
                return;
        }
index 5588f75a8414d5b7cefa9529cba44ec734d52b91..d2d0174a6ecabeb8f883f7328f7f6d8609144a57 100644 (file)
@@ -6,6 +6,7 @@ config COMMON_CLK_AMLOGIC
 config COMMON_CLK_MESON8B
        bool
        depends on COMMON_CLK_AMLOGIC
+       select RESET_CONTROLLER
        help
          Support for the clock controller on AmLogic S802 (Meson8),
          S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you
index 83b6d9d65aa1fd5914bbcc4ef4890f5409c6fa06..b139d41b25dac112e882adba4b57ea2cb27777a4 100644 (file)
@@ -4,4 +4,4 @@
 
 obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-cpu.o clk-mpll.o clk-audio-divider.o
 obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
-obj-$(CONFIG_COMMON_CLK_GXBB)   += gxbb.o gxbb-aoclk.o
+obj-$(CONFIG_COMMON_CLK_GXBB)   += gxbb.o gxbb-aoclk.o gxbb-aoclk-regmap.o gxbb-aoclk-32k.o
diff --git a/drivers/clk/meson/gxbb-aoclk-32k.c b/drivers/clk/meson/gxbb-aoclk-32k.c
new file mode 100644 (file)
index 0000000..491634d
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2017 BayLibre, SAS.
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/bitfield.h>
+#include <linux/regmap.h>
+#include "gxbb-aoclk.h"
+
+/*
+ * The AO Domain embeds a dual/divider to generate a more precise
+ * 32,768KHz clock for low-power suspend mode and CEC.
+ *                      ______   ______
+ *                     |      | |      |
+ *         ______      | Div1 |-| Cnt1 |       ______
+ *        |      |    /|______| |______|\     |      |
+ * Xtal-->| Gate |---|  ______   ______  X-X--| Gate |-->
+ *        |______| |  \|      | |      |/  |  |______|
+ *                 |   | Div2 |-| Cnt2 |   |
+ *                 |   |______| |______|   |
+ *                 |_______________________|
+ *
+ * The dividing can be switched to single or dual, with a counter
+ * for each divider to set when the switching is done.
+ * The entire dividing mechanism can be also bypassed.
+ */
+
+#define CLK_CNTL0_N1_MASK      GENMASK(11, 0)
+#define CLK_CNTL0_N2_MASK      GENMASK(23, 12)
+#define CLK_CNTL0_DUALDIV_EN   BIT(28)
+#define CLK_CNTL0_OUT_GATE_EN  BIT(30)
+#define CLK_CNTL0_IN_GATE_EN   BIT(31)
+
+#define CLK_CNTL1_M1_MASK      GENMASK(11, 0)
+#define CLK_CNTL1_M2_MASK      GENMASK(23, 12)
+#define CLK_CNTL1_BYPASS_EN    BIT(24)
+#define CLK_CNTL1_SELECT_OSC   BIT(27)
+
+#define PWR_CNTL_ALT_32K_SEL   GENMASK(13, 10)
+
+struct cec_32k_freq_table {
+       unsigned long parent_rate;
+       unsigned long target_rate;
+       bool dualdiv;
+       unsigned int n1;
+       unsigned int n2;
+       unsigned int m1;
+       unsigned int m2;
+};
+
+static const struct cec_32k_freq_table aoclk_cec_32k_table[] = {
+       [0] = {
+               .parent_rate = 24000000,
+               .target_rate = 32768,
+               .dualdiv = true,
+               .n1 = 733,
+               .n2 = 732,
+               .m1 = 8,
+               .m2 = 11,
+       },
+};
+
+/*
+ * If CLK_CNTL0_DUALDIV_EN == 0
+ *  - will use N1 divider only
+ * If CLK_CNTL0_DUALDIV_EN == 1
+ *  - hold M1 cycles of N1 divider then changes to N2
+ *  - hold M2 cycles of N2 divider then changes to N1
+ * Then we can get more accurate division.
+ */
+static unsigned long aoclk_cec_32k_recalc_rate(struct clk_hw *hw,
+                                              unsigned long parent_rate)
+{
+       struct aoclk_cec_32k *cec_32k = to_aoclk_cec_32k(hw);
+       unsigned long n1;
+       u32 reg0, reg1;
+
+       regmap_read(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, &reg0);
+       regmap_read(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL1, &reg1);
+
+       if (reg1 & CLK_CNTL1_BYPASS_EN)
+               return parent_rate;
+
+       if (reg0 & CLK_CNTL0_DUALDIV_EN) {
+               unsigned long n2, m1, m2, f1, f2, p1, p2;
+
+               n1 = FIELD_GET(CLK_CNTL0_N1_MASK, reg0) + 1;
+               n2 = FIELD_GET(CLK_CNTL0_N2_MASK, reg0) + 1;
+
+               m1 = FIELD_GET(CLK_CNTL1_M1_MASK, reg1) + 1;
+               m2 = FIELD_GET(CLK_CNTL1_M2_MASK, reg1) + 1;
+
+               f1 = DIV_ROUND_CLOSEST(parent_rate, n1);
+               f2 = DIV_ROUND_CLOSEST(parent_rate, n2);
+
+               p1 = DIV_ROUND_CLOSEST(100000000 * m1, f1 * (m1 + m2));
+               p2 = DIV_ROUND_CLOSEST(100000000 * m2, f2 * (m1 + m2));
+
+               return DIV_ROUND_UP(100000000, p1 + p2);
+       }
+
+       n1 = FIELD_GET(CLK_CNTL0_N1_MASK, reg0) + 1;
+
+       return DIV_ROUND_CLOSEST(parent_rate, n1);
+}
+
+static const struct cec_32k_freq_table *find_cec_32k_freq(unsigned long rate,
+                                                         unsigned long prate)
+{
+       int i;
+
+       for (i = 0 ; i < ARRAY_SIZE(aoclk_cec_32k_table) ; ++i)
+               if (aoclk_cec_32k_table[i].parent_rate == prate &&
+                   aoclk_cec_32k_table[i].target_rate == rate)
+                       return &aoclk_cec_32k_table[i];
+
+       return NULL;
+}
+
+static long aoclk_cec_32k_round_rate(struct clk_hw *hw, unsigned long rate,
+                                    unsigned long *prate)
+{
+       const struct cec_32k_freq_table *freq = find_cec_32k_freq(rate,
+                                                                 *prate);
+
+       /* If invalid return first one */
+       if (!freq)
+               return aoclk_cec_32k_table[0].target_rate;
+
+       return freq->target_rate;
+}
+
+/*
+ * From the Amlogic init procedure, the IN and OUT gates needs to be handled
+ * in the init procedure to avoid any glitches.
+ */
+
+static int aoclk_cec_32k_set_rate(struct clk_hw *hw, unsigned long rate,
+                                 unsigned long parent_rate)
+{
+       const struct cec_32k_freq_table *freq = find_cec_32k_freq(rate,
+                                                                 parent_rate);
+       struct aoclk_cec_32k *cec_32k = to_aoclk_cec_32k(hw);
+       u32 reg = 0;
+
+       if (!freq)
+               return -EINVAL;
+
+       /* Disable clock */
+       regmap_update_bits(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0,
+                          CLK_CNTL0_IN_GATE_EN | CLK_CNTL0_OUT_GATE_EN, 0);
+
+       reg = FIELD_PREP(CLK_CNTL0_N1_MASK, freq->n1 - 1);
+       if (freq->dualdiv)
+               reg |= CLK_CNTL0_DUALDIV_EN |
+                      FIELD_PREP(CLK_CNTL0_N2_MASK, freq->n2 - 1);
+
+       regmap_write(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, reg);
+
+       reg = FIELD_PREP(CLK_CNTL1_M1_MASK, freq->m1 - 1);
+       if (freq->dualdiv)
+               reg |= FIELD_PREP(CLK_CNTL1_M2_MASK, freq->m2 - 1);
+
+       regmap_write(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL1, reg);
+
+       /* Enable clock */
+       regmap_update_bits(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0,
+                          CLK_CNTL0_IN_GATE_EN, CLK_CNTL0_IN_GATE_EN);
+
+       udelay(200);
+
+       regmap_update_bits(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0,
+                          CLK_CNTL0_OUT_GATE_EN, CLK_CNTL0_OUT_GATE_EN);
+
+       regmap_update_bits(cec_32k->regmap, AO_CRT_CLK_CNTL1,
+                          CLK_CNTL1_SELECT_OSC, CLK_CNTL1_SELECT_OSC);
+
+       /* Select 32k from XTAL */
+       regmap_update_bits(cec_32k->regmap,
+                         AO_RTI_PWR_CNTL_REG0,
+                         PWR_CNTL_ALT_32K_SEL,
+                         FIELD_PREP(PWR_CNTL_ALT_32K_SEL, 4));
+
+       return 0;
+}
+
+const struct clk_ops meson_aoclk_cec_32k_ops = {
+       .recalc_rate = aoclk_cec_32k_recalc_rate,
+       .round_rate = aoclk_cec_32k_round_rate,
+       .set_rate = aoclk_cec_32k_set_rate,
+};
diff --git a/drivers/clk/meson/gxbb-aoclk-regmap.c b/drivers/clk/meson/gxbb-aoclk-regmap.c
new file mode 100644 (file)
index 0000000..2515fbf
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017 BayLibre, SAS.
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/bitfield.h>
+#include <linux/regmap.h>
+#include "gxbb-aoclk.h"
+
+static int aoclk_gate_regmap_enable(struct clk_hw *hw)
+{
+       struct aoclk_gate_regmap *gate = to_aoclk_gate_regmap(hw);
+
+       return regmap_update_bits(gate->regmap, AO_RTI_GEN_CNTL_REG0,
+                                 BIT(gate->bit_idx), BIT(gate->bit_idx));
+}
+
+static void aoclk_gate_regmap_disable(struct clk_hw *hw)
+{
+       struct aoclk_gate_regmap *gate = to_aoclk_gate_regmap(hw);
+
+       regmap_update_bits(gate->regmap, AO_RTI_GEN_CNTL_REG0,
+                          BIT(gate->bit_idx), 0);
+}
+
+static int aoclk_gate_regmap_is_enabled(struct clk_hw *hw)
+{
+       struct aoclk_gate_regmap *gate = to_aoclk_gate_regmap(hw);
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(gate->regmap, AO_RTI_GEN_CNTL_REG0, &val);
+       if (ret)
+               return ret;
+
+       return (val & BIT(gate->bit_idx)) != 0;
+}
+
+const struct clk_ops meson_aoclk_gate_regmap_ops = {
+       .enable = aoclk_gate_regmap_enable,
+       .disable = aoclk_gate_regmap_disable,
+       .is_enabled = aoclk_gate_regmap_is_enabled,
+};
index b45c5fba7e35bafd3f206a73c12ad260061dce62..6c161e0a8e59c248c2d8116f78904b1fd3a045ad 100644 (file)
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
 #include <linux/reset-controller.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 #include <dt-bindings/clock/gxbb-aoclkc.h>
 #include <dt-bindings/reset/gxbb-aoclkc.h>
+#include "gxbb-aoclk.h"
 
 static DEFINE_SPINLOCK(gxbb_aoclk_lock);
 
 struct gxbb_aoclk_reset_controller {
        struct reset_controller_dev reset;
        unsigned int *data;
-       void __iomem *base;
+       struct regmap *regmap;
 };
 
 static int gxbb_aoclk_do_reset(struct reset_controller_dev *rcdev,
@@ -74,9 +78,8 @@ static int gxbb_aoclk_do_reset(struct reset_controller_dev *rcdev,
        struct gxbb_aoclk_reset_controller *reset =
                container_of(rcdev, struct gxbb_aoclk_reset_controller, reset);
 
-       writel(BIT(reset->data[id]), reset->base);
-
-       return 0;
+       return regmap_write(reset->regmap, AO_RTI_GEN_CNTL_REG0,
+                           BIT(reset->data[id]));
 }
 
 static const struct reset_control_ops gxbb_aoclk_reset_ops = {
@@ -84,13 +87,12 @@ static const struct reset_control_ops gxbb_aoclk_reset_ops = {
 };
 
 #define GXBB_AO_GATE(_name, _bit)                                      \
-static struct clk_gate _name##_ao = {                                  \
-       .reg = (void __iomem *)0,                                       \
+static struct aoclk_gate_regmap _name##_ao = {                         \
        .bit_idx = (_bit),                                              \
        .lock = &gxbb_aoclk_lock,                                       \
        .hw.init = &(struct clk_init_data) {                            \
                .name = #_name "_ao",                                   \
-               .ops = &clk_gate_ops,                                   \
+               .ops = &meson_aoclk_gate_regmap_ops,                    \
                .parent_names = (const char *[]){ "clk81" },            \
                .num_parents = 1,                                       \
                .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED),     \
@@ -104,6 +106,17 @@ GXBB_AO_GATE(uart1, 3);
 GXBB_AO_GATE(uart2, 5);
 GXBB_AO_GATE(ir_blaster, 6);
 
+static struct aoclk_cec_32k cec_32k_ao = {
+       .lock = &gxbb_aoclk_lock,
+       .hw.init = &(struct clk_init_data) {
+               .name = "cec_32k_ao",
+               .ops = &meson_aoclk_cec_32k_ops,
+               .parent_names = (const char *[]){ "xtal" },
+               .num_parents = 1,
+               .flags = CLK_IGNORE_UNUSED,
+       },
+};
+
 static unsigned int gxbb_aoclk_reset[] = {
        [RESET_AO_REMOTE] = 16,
        [RESET_AO_I2C_MASTER] = 18,
@@ -113,7 +126,7 @@ static unsigned int gxbb_aoclk_reset[] = {
        [RESET_AO_IR_BLASTER] = 23,
 };
 
-static struct clk_gate *gxbb_aoclk_gate[] = {
+static struct aoclk_gate_regmap *gxbb_aoclk_gate[] = {
        [CLKID_AO_REMOTE] = &remote_ao,
        [CLKID_AO_I2C_MASTER] = &i2c_master_ao,
        [CLKID_AO_I2C_SLAVE] = &i2c_slave_ao,
@@ -130,30 +143,30 @@ static struct clk_hw_onecell_data gxbb_aoclk_onecell_data = {
                [CLKID_AO_UART1] = &uart1_ao.hw,
                [CLKID_AO_UART2] = &uart2_ao.hw,
                [CLKID_AO_IR_BLASTER] = &ir_blaster_ao.hw,
+               [CLKID_AO_CEC_32K] = &cec_32k_ao.hw,
        },
-       .num = ARRAY_SIZE(gxbb_aoclk_gate),
+       .num = 7,
 };
 
 static int gxbb_aoclkc_probe(struct platform_device *pdev)
 {
-       struct resource *res;
-       void __iomem *base;
-       int ret, clkid;
-       struct device *dev = &pdev->dev;
        struct gxbb_aoclk_reset_controller *rstc;
+       struct device *dev = &pdev->dev;
+       struct regmap *regmap;
+       int ret, clkid;
 
        rstc = devm_kzalloc(dev, sizeof(*rstc), GFP_KERNEL);
        if (!rstc)
                return -ENOMEM;
 
-       /* Generic clocks */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(base))
-               return PTR_ERR(base);
+       regmap = syscon_node_to_regmap(of_get_parent(dev->of_node));
+       if (IS_ERR(regmap)) {
+               dev_err(dev, "failed to get regmap\n");
+               return -ENODEV;
+       }
 
        /* Reset Controller */
-       rstc->base = base;
+       rstc->regmap = regmap;
        rstc->data = gxbb_aoclk_reset;
        rstc->reset.ops = &gxbb_aoclk_reset_ops;
        rstc->reset.nr_resets = ARRAY_SIZE(gxbb_aoclk_reset);
@@ -161,10 +174,10 @@ static int gxbb_aoclkc_probe(struct platform_device *pdev)
        ret = devm_reset_controller_register(dev, &rstc->reset);
 
        /*
-        * Populate base address and register all clks
+        * Populate regmap and register all clks
         */
-       for (clkid = 0; clkid < gxbb_aoclk_onecell_data.num; clkid++) {
-               gxbb_aoclk_gate[clkid]->reg = base;
+       for (clkid = 0; clkid < ARRAY_SIZE(gxbb_aoclk_gate); clkid++) {
+               gxbb_aoclk_gate[clkid]->regmap = regmap;
 
                ret = devm_clk_hw_register(dev,
                                        gxbb_aoclk_onecell_data.hws[clkid]);
@@ -172,12 +185,18 @@ static int gxbb_aoclkc_probe(struct platform_device *pdev)
                        return ret;
        }
 
+       /* Specific clocks */
+       cec_32k_ao.regmap = regmap;
+       ret = devm_clk_hw_register(dev, &cec_32k_ao.hw);
+       if (ret)
+               return ret;
+
        return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
                        &gxbb_aoclk_onecell_data);
 }
 
 static const struct of_device_id gxbb_aoclkc_match_table[] = {
-       { .compatible = "amlogic,gxbb-aoclkc" },
+       { .compatible = "amlogic,meson-gx-aoclkc" },
        { }
 };
 
diff --git a/drivers/clk/meson/gxbb-aoclk.h b/drivers/clk/meson/gxbb-aoclk.h
new file mode 100644 (file)
index 0000000..e8604c8
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __GXBB_AOCLKC_H
+#define __GXBB_AOCLKC_H
+
+/* AO Configuration Clock registers offsets */
+#define AO_RTI_PWR_CNTL_REG1   0x0c
+#define AO_RTI_PWR_CNTL_REG0   0x10
+#define AO_RTI_GEN_CNTL_REG0   0x40
+#define AO_OSCIN_CNTL          0x58
+#define AO_CRT_CLK_CNTL1       0x68
+#define AO_RTC_ALT_CLK_CNTL0   0x94
+#define AO_RTC_ALT_CLK_CNTL1   0x98
+
+struct aoclk_gate_regmap {
+       struct clk_hw hw;
+       unsigned bit_idx;
+       struct regmap *regmap;
+       spinlock_t *lock;
+};
+
+#define to_aoclk_gate_regmap(_hw) \
+       container_of(_hw, struct aoclk_gate_regmap, hw)
+
+extern const struct clk_ops meson_aoclk_gate_regmap_ops;
+
+struct aoclk_cec_32k {
+       struct clk_hw hw;
+       struct regmap *regmap;
+       spinlock_t *lock;
+};
+
+#define to_aoclk_cec_32k(_hw) container_of(_hw, struct aoclk_cec_32k, hw)
+
+extern const struct clk_ops meson_aoclk_cec_32k_ops;
+
+#endif /* __GXBB_AOCLKC_H */
index 964489b39f6a0ed6e1a98ed28f26c676db52d0d8..b2d1e8ed7152b75f11352f58ff40cad71a1dab57 100644 (file)
@@ -850,13 +850,14 @@ static struct meson_clk_audio_divider gxbb_cts_amclk_div = {
                .shift   = 0,
                .width   = 8,
        },
+       .flags = CLK_DIVIDER_ROUND_CLOSEST,
        .lock = &clk_lock,
        .hw.init = &(struct clk_init_data){
                .name = "cts_amclk_div",
                .ops = &meson_clk_audio_divider_ops,
                .parent_names = (const char *[]){ "cts_amclk_sel" },
                .num_parents = 1,
-               .flags = CLK_SET_RATE_PARENT | CLK_DIVIDER_ROUND_CLOSEST,
+               .flags = CLK_SET_RATE_PARENT,
        },
 };
 
@@ -880,7 +881,7 @@ static struct clk_mux gxbb_cts_mclk_i958_sel = {
        /* Default parent unknown (register reset value: 0) */
        .table = (u32[]){ 1, 2, 3 },
        .lock = &clk_lock,
-               .hw.init = &(struct clk_init_data){
+       .hw.init = &(struct clk_init_data) {
                .name = "cts_mclk_i958_sel",
                .ops = &clk_mux_ops,
                .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" },
@@ -894,12 +895,13 @@ static struct clk_divider gxbb_cts_mclk_i958_div = {
        .shift = 16,
        .width = 8,
        .lock = &clk_lock,
-       .hw.init = &(struct clk_init_data){
+       .flags = CLK_DIVIDER_ROUND_CLOSEST,
+       .hw.init = &(struct clk_init_data) {
                .name = "cts_mclk_i958_div",
                .ops = &clk_divider_ops,
                .parent_names = (const char *[]){ "cts_mclk_i958_sel" },
                .num_parents = 1,
-               .flags = CLK_SET_RATE_PARENT | CLK_DIVIDER_ROUND_CLOSEST,
+               .flags = CLK_SET_RATE_PARENT,
        },
 };
 
@@ -979,6 +981,156 @@ static struct clk_mux gxbb_32k_clk_sel = {
        },
 };
 
+static const char * const gxbb_sd_emmc_clk0_parent_names[] = {
+       "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7",
+
+       /*
+        * Following these parent clocks, we should also have had mpll2, mpll3
+        * and gp0_pll but these clocks are too precious to be used here. All
+        * the necessary rates for MMC and NAND operation can be acheived using
+        * xtal or fclk_div clocks
+        */
+};
+
+/* SDIO clock */
+static struct clk_mux gxbb_sd_emmc_a_clk0_sel = {
+       .reg = (void *)HHI_SD_EMMC_CLK_CNTL,
+       .mask = 0x7,
+       .shift = 9,
+       .lock = &clk_lock,
+       .hw.init = &(struct clk_init_data) {
+               .name = "sd_emmc_a_clk0_sel",
+               .ops = &clk_mux_ops,
+               .parent_names = gxbb_sd_emmc_clk0_parent_names,
+               .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names),
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_divider gxbb_sd_emmc_a_clk0_div = {
+       .reg = (void *)HHI_SD_EMMC_CLK_CNTL,
+       .shift = 0,
+       .width = 7,
+       .lock = &clk_lock,
+       .flags = CLK_DIVIDER_ROUND_CLOSEST,
+       .hw.init = &(struct clk_init_data) {
+               .name = "sd_emmc_a_clk0_div",
+               .ops = &clk_divider_ops,
+               .parent_names = (const char *[]){ "sd_emmc_a_clk0_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_gate gxbb_sd_emmc_a_clk0 = {
+       .reg = (void *)HHI_SD_EMMC_CLK_CNTL,
+       .bit_idx = 7,
+       .lock = &clk_lock,
+       .hw.init = &(struct clk_init_data){
+               .name = "sd_emmc_a_clk0",
+               .ops = &clk_gate_ops,
+               .parent_names = (const char *[]){ "sd_emmc_a_clk0_div" },
+               .num_parents = 1,
+
+               /*
+                * FIXME:
+                * We need CLK_IGNORE_UNUSED because mmc DT node point to xtal
+                * instead of this clock. CCF would gate this on boot, killing
+                * the mmc controller. Please remove this flag once DT properly
+                * point to this clock instead of xtal
+                *
+                * Same goes for emmc B and C clocks
+                */
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+/* SDcard clock */
+static struct clk_mux gxbb_sd_emmc_b_clk0_sel = {
+       .reg = (void *)HHI_SD_EMMC_CLK_CNTL,
+       .mask = 0x7,
+       .shift = 25,
+       .lock = &clk_lock,
+       .hw.init = &(struct clk_init_data) {
+               .name = "sd_emmc_b_clk0_sel",
+               .ops = &clk_mux_ops,
+               .parent_names = gxbb_sd_emmc_clk0_parent_names,
+               .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names),
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_divider gxbb_sd_emmc_b_clk0_div = {
+       .reg = (void *)HHI_SD_EMMC_CLK_CNTL,
+       .shift = 16,
+       .width = 7,
+       .lock = &clk_lock,
+       .flags = CLK_DIVIDER_ROUND_CLOSEST,
+       .hw.init = &(struct clk_init_data) {
+               .name = "sd_emmc_b_clk0_div",
+               .ops = &clk_divider_ops,
+               .parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_gate gxbb_sd_emmc_b_clk0 = {
+       .reg = (void *)HHI_SD_EMMC_CLK_CNTL,
+       .bit_idx = 23,
+       .lock = &clk_lock,
+       .hw.init = &(struct clk_init_data){
+               .name = "sd_emmc_b_clk0",
+               .ops = &clk_gate_ops,
+               .parent_names = (const char *[]){ "sd_emmc_b_clk0_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+/* EMMC/NAND clock */
+static struct clk_mux gxbb_sd_emmc_c_clk0_sel = {
+       .reg = (void *)HHI_NAND_CLK_CNTL,
+       .mask = 0x7,
+       .shift = 9,
+       .lock = &clk_lock,
+       .hw.init = &(struct clk_init_data) {
+               .name = "sd_emmc_c_clk0_sel",
+               .ops = &clk_mux_ops,
+               .parent_names = gxbb_sd_emmc_clk0_parent_names,
+               .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names),
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_divider gxbb_sd_emmc_c_clk0_div = {
+       .reg = (void *)HHI_NAND_CLK_CNTL,
+       .shift = 0,
+       .width = 7,
+       .lock = &clk_lock,
+       .flags = CLK_DIVIDER_ROUND_CLOSEST,
+       .hw.init = &(struct clk_init_data) {
+               .name = "sd_emmc_c_clk0_div",
+               .ops = &clk_divider_ops,
+               .parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_gate gxbb_sd_emmc_c_clk0 = {
+       .reg = (void *)HHI_NAND_CLK_CNTL,
+       .bit_idx = 7,
+       .lock = &clk_lock,
+       .hw.init = &(struct clk_init_data){
+               .name = "sd_emmc_c_clk0",
+               .ops = &clk_gate_ops,
+               .parent_names = (const char *[]){ "sd_emmc_c_clk0_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
 /* Everything Else (EE) domain gates */
 static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0);
 static MESON_GATE(gxbb_dos, HHI_GCLK_MPEG0, 1);
@@ -1188,6 +1340,15 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = {
                [CLKID_32K_CLK]             = &gxbb_32k_clk.hw,
                [CLKID_32K_CLK_SEL]         = &gxbb_32k_clk_sel.hw,
                [CLKID_32K_CLK_DIV]         = &gxbb_32k_clk_div.hw,
+               [CLKID_SD_EMMC_A_CLK0_SEL]  = &gxbb_sd_emmc_a_clk0_sel.hw,
+               [CLKID_SD_EMMC_A_CLK0_DIV]  = &gxbb_sd_emmc_a_clk0_div.hw,
+               [CLKID_SD_EMMC_A_CLK0]      = &gxbb_sd_emmc_a_clk0.hw,
+               [CLKID_SD_EMMC_B_CLK0_SEL]  = &gxbb_sd_emmc_b_clk0_sel.hw,
+               [CLKID_SD_EMMC_B_CLK0_DIV]  = &gxbb_sd_emmc_b_clk0_div.hw,
+               [CLKID_SD_EMMC_B_CLK0]      = &gxbb_sd_emmc_b_clk0.hw,
+               [CLKID_SD_EMMC_C_CLK0_SEL]  = &gxbb_sd_emmc_c_clk0_sel.hw,
+               [CLKID_SD_EMMC_C_CLK0_DIV]  = &gxbb_sd_emmc_c_clk0_div.hw,
+               [CLKID_SD_EMMC_C_CLK0]      = &gxbb_sd_emmc_c_clk0.hw,
                [NR_CLKS]                   = NULL,
        },
        .num = NR_CLKS,
@@ -1311,6 +1472,15 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = {
                [CLKID_32K_CLK]             = &gxbb_32k_clk.hw,
                [CLKID_32K_CLK_SEL]         = &gxbb_32k_clk_sel.hw,
                [CLKID_32K_CLK_DIV]         = &gxbb_32k_clk_div.hw,
+               [CLKID_SD_EMMC_A_CLK0_SEL]  = &gxbb_sd_emmc_a_clk0_sel.hw,
+               [CLKID_SD_EMMC_A_CLK0_DIV]  = &gxbb_sd_emmc_a_clk0_div.hw,
+               [CLKID_SD_EMMC_A_CLK0]      = &gxbb_sd_emmc_a_clk0.hw,
+               [CLKID_SD_EMMC_B_CLK0_SEL]  = &gxbb_sd_emmc_b_clk0_sel.hw,
+               [CLKID_SD_EMMC_B_CLK0_DIV]  = &gxbb_sd_emmc_b_clk0_div.hw,
+               [CLKID_SD_EMMC_B_CLK0]      = &gxbb_sd_emmc_b_clk0.hw,
+               [CLKID_SD_EMMC_C_CLK0_SEL]  = &gxbb_sd_emmc_c_clk0_sel.hw,
+               [CLKID_SD_EMMC_C_CLK0_DIV]  = &gxbb_sd_emmc_c_clk0_div.hw,
+               [CLKID_SD_EMMC_C_CLK0]      = &gxbb_sd_emmc_c_clk0.hw,
                [NR_CLKS]                   = NULL,
        },
        .num = NR_CLKS,
@@ -1427,6 +1597,9 @@ static struct clk_gate *const gxbb_clk_gates[] = {
        &gxbb_cts_amclk,
        &gxbb_cts_mclk_i958,
        &gxbb_32k_clk,
+       &gxbb_sd_emmc_a_clk0,
+       &gxbb_sd_emmc_b_clk0,
+       &gxbb_sd_emmc_c_clk0,
 };
 
 static struct clk_mux *const gxbb_clk_muxes[] = {
@@ -1439,6 +1612,9 @@ static struct clk_mux *const gxbb_clk_muxes[] = {
        &gxbb_cts_mclk_i958_sel,
        &gxbb_cts_i958,
        &gxbb_32k_clk_sel,
+       &gxbb_sd_emmc_a_clk0_sel,
+       &gxbb_sd_emmc_b_clk0_sel,
+       &gxbb_sd_emmc_c_clk0_sel,
 };
 
 static struct clk_divider *const gxbb_clk_dividers[] = {
@@ -1448,6 +1624,9 @@ static struct clk_divider *const gxbb_clk_dividers[] = {
        &gxbb_mali_1_div,
        &gxbb_cts_mclk_i958_div,
        &gxbb_32k_clk_div,
+       &gxbb_sd_emmc_a_clk0_div,
+       &gxbb_sd_emmc_b_clk0_div,
+       &gxbb_sd_emmc_c_clk0_div,
 };
 
 static struct meson_clk_audio_divider *const gxbb_audio_dividers[] = {
index cb60a516ca82bcf85d3b8334306696531ab6a597..20ab7190d3287b8ebb7fe6b49c9858038e4540f5 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/clk-provider.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
 #include <linux/init.h>
 
 #include "clkc.h"
 
 static DEFINE_SPINLOCK(clk_lock);
 
+static void __iomem *clk_base;
+
+struct meson8b_clk_reset {
+       struct reset_controller_dev reset;
+       void __iomem *base;
+};
+
 static const struct pll_rate_table sys_pll_rate_table[] = {
        PLL_RATE(312000000, 52, 1, 2),
        PLL_RATE(336000000, 56, 1, 2),
@@ -696,20 +705,114 @@ static struct clk_divider *const meson8b_clk_dividers[] = {
        &meson8b_mpeg_clk_div,
 };
 
+static const struct meson8b_clk_reset_line {
+       u32 reg;
+       u8 bit_idx;
+} meson8b_clk_reset_bits[] = {
+       [CLKC_RESET_L2_CACHE_SOFT_RESET] = {
+               .reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 30
+       },
+       [CLKC_RESET_AXI_64_TO_128_BRIDGE_A5_SOFT_RESET] = {
+               .reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 29
+       },
+       [CLKC_RESET_SCU_SOFT_RESET] = {
+               .reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 28
+       },
+       [CLKC_RESET_CPU3_SOFT_RESET] = {
+               .reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 27
+       },
+       [CLKC_RESET_CPU2_SOFT_RESET] = {
+               .reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 26
+       },
+       [CLKC_RESET_CPU1_SOFT_RESET] = {
+               .reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 25
+       },
+       [CLKC_RESET_CPU0_SOFT_RESET] = {
+               .reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 24
+       },
+       [CLKC_RESET_A5_GLOBAL_RESET] = {
+               .reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 18
+       },
+       [CLKC_RESET_A5_AXI_SOFT_RESET] = {
+               .reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 17
+       },
+       [CLKC_RESET_A5_ABP_SOFT_RESET] = {
+               .reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 16
+       },
+       [CLKC_RESET_AXI_64_TO_128_BRIDGE_MMC_SOFT_RESET] = {
+               .reg = HHI_SYS_CPU_CLK_CNTL1, .bit_idx = 30
+       },
+       [CLKC_RESET_VID_CLK_CNTL_SOFT_RESET] = {
+               .reg = HHI_VID_CLK_CNTL, .bit_idx = 15
+       },
+       [CLKC_RESET_VID_DIVIDER_CNTL_SOFT_RESET_POST] = {
+               .reg = HHI_VID_DIVIDER_CNTL, .bit_idx = 7
+       },
+       [CLKC_RESET_VID_DIVIDER_CNTL_SOFT_RESET_PRE] = {
+               .reg = HHI_VID_DIVIDER_CNTL, .bit_idx = 3
+       },
+       [CLKC_RESET_VID_DIVIDER_CNTL_RESET_N_POST] = {
+               .reg = HHI_VID_DIVIDER_CNTL, .bit_idx = 1
+       },
+       [CLKC_RESET_VID_DIVIDER_CNTL_RESET_N_PRE] = {
+               .reg = HHI_VID_DIVIDER_CNTL, .bit_idx = 0
+       },
+};
+
+static int meson8b_clk_reset_update(struct reset_controller_dev *rcdev,
+                                   unsigned long id, bool assert)
+{
+       struct meson8b_clk_reset *meson8b_clk_reset =
+               container_of(rcdev, struct meson8b_clk_reset, reset);
+       unsigned long flags;
+       const struct meson8b_clk_reset_line *reset;
+       u32 val;
+
+       if (id >= ARRAY_SIZE(meson8b_clk_reset_bits))
+               return -EINVAL;
+
+       reset = &meson8b_clk_reset_bits[id];
+
+       spin_lock_irqsave(&clk_lock, flags);
+
+       val = readl(meson8b_clk_reset->base + reset->reg);
+       if (assert)
+               val |= BIT(reset->bit_idx);
+       else
+               val &= ~BIT(reset->bit_idx);
+       writel(val, meson8b_clk_reset->base + reset->reg);
+
+       spin_unlock_irqrestore(&clk_lock, flags);
+
+       return 0;
+}
+
+static int meson8b_clk_reset_assert(struct reset_controller_dev *rcdev,
+                                    unsigned long id)
+{
+       return meson8b_clk_reset_update(rcdev, id, true);
+}
+
+static int meson8b_clk_reset_deassert(struct reset_controller_dev *rcdev,
+                                      unsigned long id)
+{
+       return meson8b_clk_reset_update(rcdev, id, false);
+}
+
+static const struct reset_control_ops meson8b_clk_reset_ops = {
+       .assert = meson8b_clk_reset_assert,
+       .deassert = meson8b_clk_reset_deassert,
+};
+
 static int meson8b_clkc_probe(struct platform_device *pdev)
 {
-       void __iomem *clk_base;
        int ret, clkid, i;
        struct clk_hw *parent_hw;
        struct clk *parent_clk;
        struct device *dev = &pdev->dev;
 
-       /*  Generic clocks and PLLs */
-       clk_base = of_iomap(dev->of_node, 1);
-       if (!clk_base) {
-               pr_err("%s: Unable to map clk base\n", __func__);
+       if (!clk_base)
                return -ENXIO;
-       }
 
        /* Populate base address for PLLs */
        for (i = 0; i < ARRAY_SIZE(meson8b_clk_plls); i++)
@@ -749,7 +852,7 @@ static int meson8b_clkc_probe(struct platform_device *pdev)
                /* FIXME convert to devm_clk_register */
                ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[clkid]);
                if (ret)
-                       goto iounmap;
+                       return ret;
        }
 
        /*
@@ -772,15 +875,11 @@ static int meson8b_clkc_probe(struct platform_device *pdev)
        if (ret) {
                pr_err("%s: failed to register clock notifier for cpu_clk\n",
                                __func__);
-               goto iounmap;
+               return ret;
        }
 
        return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
                        &meson8b_hw_onecell_data);
-
-iounmap:
-       iounmap(clk_base);
-       return ret;
 }
 
 static const struct of_device_id meson8b_clkc_match_table[] = {
@@ -799,3 +898,39 @@ static struct platform_driver meson8b_driver = {
 };
 
 builtin_platform_driver(meson8b_driver);
+
+static void __init meson8b_clkc_reset_init(struct device_node *np)
+{
+       struct meson8b_clk_reset *rstc;
+       int ret;
+
+       /* Generic clocks, PLLs and some of the reset-bits */
+       clk_base = of_iomap(np, 1);
+       if (!clk_base) {
+               pr_err("%s: Unable to map clk base\n", __func__);
+               return;
+       }
+
+       rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
+       if (!rstc)
+               return;
+
+       /* Reset Controller */
+       rstc->base = clk_base;
+       rstc->reset.ops = &meson8b_clk_reset_ops;
+       rstc->reset.nr_resets = ARRAY_SIZE(meson8b_clk_reset_bits);
+       rstc->reset.of_node = np;
+       ret = reset_controller_register(&rstc->reset);
+       if (ret) {
+               pr_err("%s: Failed to register clkc reset controller: %d\n",
+                      __func__, ret);
+               return;
+       }
+}
+
+CLK_OF_DECLARE_DRIVER(meson8_clkc, "amlogic,meson8-clkc",
+                     meson8b_clkc_reset_init);
+CLK_OF_DECLARE_DRIVER(meson8b_clkc, "amlogic,meson8b-clkc",
+                     meson8b_clkc_reset_init);
+CLK_OF_DECLARE_DRIVER(meson8m2_clkc, "amlogic,meson8m2-clkc",
+                     meson8b_clkc_reset_init);
index c139bb3273ca74a557605c987694e53980a5fb62..2eaf8a52e7dd84c15704f7dfbc5d99166140fce2 100644 (file)
@@ -37,6 +37,9 @@
 #define HHI_GCLK_AO                    0x154 /* 0x55 offset in data sheet */
 #define HHI_SYS_CPU_CLK_CNTL1          0x15c /* 0x57 offset in data sheet */
 #define HHI_MPEG_CLK_CNTL              0x174 /* 0x5d offset in data sheet */
+#define HHI_VID_CLK_CNTL               0x17c /* 0x5f offset in data sheet */
+#define HHI_VID_DIVIDER_CNTL           0x198 /* 0x66 offset in data sheet */
+#define HHI_SYS_CPU_CLK_CNTL0          0x19c /* 0x67 offset in data sheet */
 #define HHI_MPLL_CNTL                  0x280 /* 0xa0 offset in data sheet */
 #define HHI_SYS_PLL_CNTL               0x300 /* 0xc0 offset in data sheet */
 #define HHI_VID_PLL_CNTL               0x320 /* 0xc8 offset in data sheet */
 
 #define CLK_NR_CLKS            96
 
-/* include the CLKIDs that have been made part of the stable DT binding */
+/*
+ * include the CLKID and RESETID that have
+ * been made part of the stable DT binding
+ */
 #include <dt-bindings/clock/meson8b-clkc.h>
+#include <dt-bindings/reset/amlogic,meson8b-clkc-reset.h>
 
 #endif /* __MESON8B_H */
index 61893fe73251b41048ed1aebee177ca605c91cdc..089927e4cda2e2e331820fe76f4f4b8a947a23b5 100644 (file)
@@ -9,7 +9,7 @@
 void mmp_clk_init(struct device_node *np, struct mmp_clk_unit *unit,
                int nr_clks)
 {
-       static struct clk **clk_table;
+       struct clk **clk_table;
 
        clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL);
        if (!clk_table)
index 5b98ff9076f34fcdbc58283bd7410e2e56b546a9..7b359afd620ec0ad23bb6bf2e41da28d5fd4e05a 100644 (file)
@@ -885,7 +885,7 @@ static const struct clk_ops clk_usb_i2c_ops = {
        .recalc_rate = clk_usb_i2c_recalc_rate,
 };
 
-static int clk_gate_enable(struct clk_hw *hw)
+static int lpc32xx_clk_gate_enable(struct clk_hw *hw)
 {
        struct lpc32xx_clk_gate *clk = to_lpc32xx_gate(hw);
        u32 mask = BIT(clk->bit_idx);
@@ -894,7 +894,7 @@ static int clk_gate_enable(struct clk_hw *hw)
        return regmap_update_bits(clk_regmap, clk->reg, mask, val);
 }
 
-static void clk_gate_disable(struct clk_hw *hw)
+static void lpc32xx_clk_gate_disable(struct clk_hw *hw)
 {
        struct lpc32xx_clk_gate *clk = to_lpc32xx_gate(hw);
        u32 mask = BIT(clk->bit_idx);
@@ -903,7 +903,7 @@ static void clk_gate_disable(struct clk_hw *hw)
        regmap_update_bits(clk_regmap, clk->reg, mask, val);
 }
 
-static int clk_gate_is_enabled(struct clk_hw *hw)
+static int lpc32xx_clk_gate_is_enabled(struct clk_hw *hw)
 {
        struct lpc32xx_clk_gate *clk = to_lpc32xx_gate(hw);
        u32 val;
@@ -916,9 +916,9 @@ static int clk_gate_is_enabled(struct clk_hw *hw)
 }
 
 static const struct clk_ops lpc32xx_clk_gate_ops = {
-       .enable = clk_gate_enable,
-       .disable = clk_gate_disable,
-       .is_enabled = clk_gate_is_enabled,
+       .enable = lpc32xx_clk_gate_enable,
+       .disable = lpc32xx_clk_gate_disable,
+       .is_enabled = lpc32xx_clk_gate_is_enabled,
 };
 
 #define div_mask(width)        ((1 << (width)) - 1)
index d990fe44aef33986609fd4d0e7398b3732228b86..cc03d5508627b3ee11cf17eb8762b94f21740f16 100644 (file)
@@ -412,8 +412,6 @@ static const struct clk_ops clk_smd_rpm_ops = {
 static const struct clk_ops clk_smd_rpm_branch_ops = {
        .prepare        = clk_smd_rpm_prepare,
        .unprepare      = clk_smd_rpm_unprepare,
-       .round_rate     = clk_smd_rpm_round_rate,
-       .recalc_rate    = clk_smd_rpm_recalc_rate,
 };
 
 /* msm8916 */
index 2cfe7000fc60465028bc55567dedbfd540d0729e..3410ee68d4bc8dd52388483d43b61b124fd7367e 100644 (file)
@@ -1176,7 +1176,7 @@ static struct clk_rcg2 bimc_gpu_clk_src = {
                .parent_names = gcc_xo_gpll0_bimc,
                .num_parents = 3,
                .flags = CLK_GET_RATE_NOCACHE,
-               .ops = &clk_rcg2_shared_ops,
+               .ops = &clk_rcg2_ops,
        },
 };
 
index 8abc200d4fd36d7b6e87036c9ff6ec9aa908b4c8..7ddec886fcd35b05fed2d1a5e3920bcf302d4557 100644 (file)
@@ -2730,6 +2730,32 @@ static struct clk_fixed_factor ufs_rx_cfg_clk_src = {
        },
 };
 
+static struct clk_branch gcc_hlos1_vote_lpass_core_smmu_clk = {
+       .halt_reg = 0x7d010,
+       .halt_check = BRANCH_HALT_VOTED,
+       .clkr = {
+               .enable_reg = 0x7d010,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "hlos1_vote_lpass_core_smmu_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_hlos1_vote_lpass_adsp_smmu_clk = {
+       .halt_reg = 0x7d014,
+       .halt_check = BRANCH_HALT_VOTED,
+       .clkr = {
+               .enable_reg = 0x7d014,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "hlos1_vote_lpass_adsp_smmu_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
 static struct clk_branch gcc_ufs_rx_cfg_clk = {
        .halt_reg = 0x75014,
        .clkr = {
@@ -3307,6 +3333,8 @@ static struct clk_regmap *gcc_msm8996_clocks[] = {
        [GCC_UFS_AHB_CLK] = &gcc_ufs_ahb_clk.clkr,
        [GCC_UFS_TX_CFG_CLK] = &gcc_ufs_tx_cfg_clk.clkr,
        [GCC_UFS_RX_CFG_CLK] = &gcc_ufs_rx_cfg_clk.clkr,
+       [GCC_HLOS1_VOTE_LPASS_CORE_SMMU_CLK] = &gcc_hlos1_vote_lpass_core_smmu_clk.clkr,
+       [GCC_HLOS1_VOTE_LPASS_ADSP_SMMU_CLK] = &gcc_hlos1_vote_lpass_adsp_smmu_clk.clkr,
        [GCC_UFS_TX_SYMBOL_0_CLK] = &gcc_ufs_tx_symbol_0_clk.clkr,
        [GCC_UFS_RX_SYMBOL_0_CLK] = &gcc_ufs_rx_symbol_0_clk.clkr,
        [GCC_UFS_RX_SYMBOL_1_CLK] = &gcc_ufs_rx_symbol_1_clk.clkr,
index 78d1df9112ba3932fe993c5f9700f00bb830a786..acbb38151ba1c51aa57bdd3663ae31db23d1bab8 100644 (file)
@@ -15,6 +15,7 @@ config CLK_RENESAS
        select CLK_R8A7794 if ARCH_R8A7794
        select CLK_R8A7795 if ARCH_R8A7795
        select CLK_R8A7796 if ARCH_R8A7796
+       select CLK_R8A77995 if ARCH_R8A77995
        select CLK_SH73A0 if ARCH_SH73A0
 
 if CLK_RENESAS
@@ -34,94 +35,103 @@ config CLK_EMEV2
        bool "Emma Mobile EV2 clock support" if COMPILE_TEST
 
 config CLK_RZA1
-       bool
+       bool "RZ/A1H clock support" if COMPILE_TEST
        select CLK_RENESAS_CPG_MSTP
 
 config CLK_R8A73A4
-       bool
+       bool "R-Mobile APE6 clock support" if COMPILE_TEST
        select CLK_RENESAS_CPG_MSTP
        select CLK_RENESAS_DIV6
 
 config CLK_R8A7740
-       bool
+       bool "R-Mobile A1 clock support" if COMPILE_TEST
        select CLK_RENESAS_CPG_MSTP
        select CLK_RENESAS_DIV6
 
 config CLK_R8A7743
-       bool
+       bool "RZ/G1M clock support" if COMPILE_TEST
        select CLK_RCAR_GEN2_CPG
 
 config CLK_R8A7745
-       bool
+       bool "RZ/G1E clock support" if COMPILE_TEST
        select CLK_RCAR_GEN2_CPG
 
 config CLK_R8A7778
-       bool
+       bool "R-Car M1A clock support" if COMPILE_TEST
        select CLK_RENESAS_CPG_MSTP
 
 config CLK_R8A7779
-       bool
+       bool "R-Car H1 clock support" if COMPILE_TEST
        select CLK_RENESAS_CPG_MSTP
 
 config CLK_R8A7790
-       bool
+       bool "R-Car H2 clock support" if COMPILE_TEST
        select CLK_RCAR_GEN2 if CLK_RENESAS_LEGACY
        select CLK_RCAR_GEN2_CPG
        select CLK_RENESAS_DIV6
 
 config CLK_R8A7791
-       bool
+       bool "R-Car M2-W/N clock support" if COMPILE_TEST
        select CLK_RCAR_GEN2 if CLK_RENESAS_LEGACY
        select CLK_RCAR_GEN2_CPG
        select CLK_RENESAS_DIV6
 
 config CLK_R8A7792
-       bool
+       bool "R-Car V2H clock support" if COMPILE_TEST
        select CLK_RCAR_GEN2 if CLK_RENESAS_LEGACY
        select CLK_RCAR_GEN2_CPG
 
 config CLK_R8A7794
-       bool
+       bool "R-Car E2 clock support" if COMPILE_TEST
        select CLK_RCAR_GEN2 if CLK_RENESAS_LEGACY
        select CLK_RCAR_GEN2_CPG
        select CLK_RENESAS_DIV6
 
 config CLK_R8A7795
-       bool
+       bool "R-Car H3 clock support" if COMPILE_TEST
        select CLK_RCAR_GEN3_CPG
 
 config CLK_R8A7796
-       bool
+       bool "R-Car M3-W clock support" if COMPILE_TEST
+       select CLK_RCAR_GEN3_CPG
+
+config CLK_R8A77995
+       bool "R-Car D3 clock support" if COMPILE_TEST
        select CLK_RCAR_GEN3_CPG
 
 config CLK_SH73A0
-       bool
+       bool "SH-Mobile AG5 clock support" if COMPILE_TEST
        select CLK_RENESAS_CPG_MSTP
        select CLK_RENESAS_DIV6
 
 
 # Family
 config CLK_RCAR_GEN2
-       bool
+       bool "R-Car Gen2 legacy clock support" if COMPILE_TEST
        select CLK_RENESAS_CPG_MSTP
        select CLK_RENESAS_DIV6
 
 config CLK_RCAR_GEN2_CPG
-       bool
+       bool "R-Car Gen2 CPG clock support" if COMPILE_TEST
        select CLK_RENESAS_CPG_MSSR
 
 config CLK_RCAR_GEN3_CPG
-       bool
+       bool "R-Car Gen3 CPG clock support" if COMPILE_TEST
        select CLK_RENESAS_CPG_MSSR
 
+config CLK_RCAR_USB2_CLOCK_SEL
+       bool "Renesas R-Car USB2 clock selector support"
+       depends on ARCH_RENESAS || COMPILE_TEST
+       help
+         This is a driver for R-Car USB2 clock selector
 
 # Generic
 config CLK_RENESAS_CPG_MSSR
-       bool
+       bool "CPG/MSSR clock support" if COMPILE_TEST
        select CLK_RENESAS_DIV6
 
 config CLK_RENESAS_CPG_MSTP
-       bool
+       bool "MSTP clock support" if COMPILE_TEST
 
 config CLK_RENESAS_DIV6
        bool "DIV6 clock support" if COMPILE_TEST
index 02d04124371f717afee9ee21147144e38952586d..9bda3ec5b199561b6cd48d82093ef54d8b36e7e5 100644 (file)
@@ -13,12 +13,14 @@ obj-$(CONFIG_CLK_R8A7792)           += r8a7792-cpg-mssr.o
 obj-$(CONFIG_CLK_R8A7794)              += r8a7794-cpg-mssr.o
 obj-$(CONFIG_CLK_R8A7795)              += r8a7795-cpg-mssr.o
 obj-$(CONFIG_CLK_R8A7796)              += r8a7796-cpg-mssr.o
+obj-$(CONFIG_CLK_R8A77995)             += r8a77995-cpg-mssr.o
 obj-$(CONFIG_CLK_SH73A0)               += clk-sh73a0.o
 
 # Family
 obj-$(CONFIG_CLK_RCAR_GEN2)            += clk-rcar-gen2.o
 obj-$(CONFIG_CLK_RCAR_GEN2_CPG)                += rcar-gen2-cpg.o
 obj-$(CONFIG_CLK_RCAR_GEN3_CPG)                += rcar-gen3-cpg.o
+obj-$(CONFIG_CLK_RCAR_USB2_CLOCK_SEL)  += rcar-usb2-clock-sel.o
 
 # Generic
 obj-$(CONFIG_CLK_RENESAS_CPG_MSSR)     += renesas-cpg-mssr.o
index 0627860233cbf97e53af7f1be3edafb5fa5e95ce..3e0040c0ac87a14bdd0b6a44c6abeee3ef5a1c14 100644 (file)
@@ -29,6 +29,9 @@
  * @hw: handle between common and hardware-specific interfaces
  * @reg: IO-remapped register
  * @div: divisor value (1-64)
+ * @src_shift: Shift to access the register bits to select the parent clock
+ * @src_width: Number of register bits to select the parent clock (may be 0)
+ * @parents: Array to map from valid parent clocks indices to hardware indices
  */
 struct div6_clock {
        struct clk_hw hw;
index f1617dd044cbbe15bdd8c4722a9c7c2042d609b8..500a9e4e03c489579c5e056a0f27cd2100ec3e05 100644 (file)
@@ -335,7 +335,7 @@ void __init cpg_mstp_add_clk_domain(struct device_node *np)
        u32 ncells;
 
        if (of_property_read_u32(np, "#power-domain-cells", &ncells)) {
-               pr_warn("%s lacks #power-domain-cells\n", np->full_name);
+               pr_warn("%pOF lacks #power-domain-cells\n", np);
                return;
        }
 
index 51a2479ed5d7c817b719c299ef1875d6e3f72a61..0b2e56d0d94bb04c633cdebc1bef916e67d9d732 100644 (file)
@@ -407,8 +407,7 @@ static void __init rcar_gen2_cpg_clocks_init(struct device_node *np)
 
        if (rcar_rst_read_mode_pins(&cpg_mode)) {
                /* Backward-compatibility with old DT */
-               pr_warn("%s: failed to obtain mode pins from RST\n",
-                       np->full_name);
+               pr_warn("%pOF: failed to obtain mode pins from RST\n", np);
                cpg_mode = rcar_gen2_read_mode_pins();
        }
 
index a832b9b6f7b0dde86384d4757de9137cbe743ce9..7f85bbf20bf782b7098a2276a3e0a2eb62f3b24a 100644 (file)
@@ -118,6 +118,13 @@ static const struct mssr_mod_clk r8a7792_mod_clks[] __initconst = {
        DEF_MOD("vin1",                  810,   R8A7792_CLK_ZG),
        DEF_MOD("vin0",                  811,   R8A7792_CLK_ZG),
        DEF_MOD("etheravb",              812,   R8A7792_CLK_HP),
+       DEF_MOD("imr-lx3",               821,   R8A7792_CLK_ZG),
+       DEF_MOD("imr-lsx3-1",            822,   R8A7792_CLK_ZG),
+       DEF_MOD("imr-lsx3-0",            823,   R8A7792_CLK_ZG),
+       DEF_MOD("imr-lsx3-5",            825,   R8A7792_CLK_ZG),
+       DEF_MOD("imr-lsx3-4",            826,   R8A7792_CLK_ZG),
+       DEF_MOD("imr-lsx3-3",            827,   R8A7792_CLK_ZG),
+       DEF_MOD("imr-lsx3-2",            828,   R8A7792_CLK_ZG),
        DEF_MOD("gyro-adc",              901,   R8A7792_CLK_P),
        DEF_MOD("gpio7",                 904,   R8A7792_CLK_CP),
        DEF_MOD("gpio6",                 905,   R8A7792_CLK_CP),
index c091a8e024b88d32d09fa37be491016cbbf314a7..762b2f8824f118deb1a41e0f24ab5281b5179712 100644 (file)
@@ -305,23 +305,23 @@ static const unsigned int r8a7795_crit_mod_clks[] __initconst = {
                                         (((md) & BIT(17)) >> 17))
 
 static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[16] __initconst = {
-       /* EXTAL div    PLL1 mult       PLL3 mult */
-       { 1,            192,            192,    },
-       { 1,            192,            128,    },
-       { 0, /* Prohibited setting */           },
-       { 1,            192,            192,    },
-       { 1,            160,            160,    },
-       { 1,            160,            106,    },
-       { 0, /* Prohibited setting */           },
-       { 1,            160,            160,    },
-       { 1,            128,            128,    },
-       { 1,            128,            84,     },
-       { 0, /* Prohibited setting */           },
-       { 1,            128,            128,    },
-       { 2,            192,            192,    },
-       { 2,            192,            128,    },
-       { 0, /* Prohibited setting */           },
-       { 2,            192,            192,    },
+       /* EXTAL div    PLL1 mult/div   PLL3 mult/div */
+       { 1,            192,    1,      192,    1,      },
+       { 1,            192,    1,      128,    1,      },
+       { 0, /* Prohibited setting */                   },
+       { 1,            192,    1,      192,    1,      },
+       { 1,            160,    1,      160,    1,      },
+       { 1,            160,    1,      106,    1,      },
+       { 0, /* Prohibited setting */                   },
+       { 1,            160,    1,      160,    1,      },
+       { 1,            128,    1,      128,    1,      },
+       { 1,            128,    1,      84,     1,      },
+       { 0, /* Prohibited setting */                   },
+       { 1,            128,    1,      128,    1,      },
+       { 2,            192,    1,      192,    1,      },
+       { 2,            192,    1,      128,    1,      },
+       { 0, /* Prohibited setting */                   },
+       { 2,            192,    1,      192,    1,      },
 };
 
 static const struct soc_device_attribute r8a7795es1[] __initconst = {
index acc6d0f153e1b233b9bd9a6293648d4a50b0ba07..e5e7fb212288c3779dfa09ed0f001ee3f77b4408 100644 (file)
@@ -138,6 +138,7 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = {
        DEF_MOD("sdif0",                 314,   R8A7796_CLK_SD0),
        DEF_MOD("pcie1",                 318,   R8A7796_CLK_S3D1),
        DEF_MOD("pcie0",                 319,   R8A7796_CLK_S3D1),
+       DEF_MOD("usb3-if0",              328,   R8A7796_CLK_S3D1),
        DEF_MOD("usb-dmac0",             330,   R8A7796_CLK_S3D1),
        DEF_MOD("usb-dmac1",             331,   R8A7796_CLK_S3D1),
        DEF_MOD("rwdt",                  402,   R8A7796_CLK_R),
@@ -277,23 +278,23 @@ static const unsigned int r8a7796_crit_mod_clks[] __initconst = {
                                         (((md) & BIT(17)) >> 17))
 
 static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[16] __initconst = {
-       /* EXTAL div    PLL1 mult       PLL3 mult */
-       { 1,            192,            192,    },
-       { 1,            192,            128,    },
-       { 0, /* Prohibited setting */           },
-       { 1,            192,            192,    },
-       { 1,            160,            160,    },
-       { 1,            160,            106,    },
-       { 0, /* Prohibited setting */           },
-       { 1,            160,            160,    },
-       { 1,            128,            128,    },
-       { 1,            128,            84,     },
-       { 0, /* Prohibited setting */           },
-       { 1,            128,            128,    },
-       { 2,            192,            192,    },
-       { 2,            192,            128,    },
-       { 0, /* Prohibited setting */           },
-       { 2,            192,            192,    },
+       /* EXTAL div    PLL1 mult/div   PLL3 mult/div */
+       { 1,            192,    1,      192,    1,      },
+       { 1,            192,    1,      128,    1,      },
+       { 0, /* Prohibited setting */                   },
+       { 1,            192,    1,      192,    1,      },
+       { 1,            160,    1,      160,    1,      },
+       { 1,            160,    1,      106,    1,      },
+       { 0, /* Prohibited setting */                   },
+       { 1,            160,    1,      160,    1,      },
+       { 1,            128,    1,      128,    1,      },
+       { 1,            128,    1,      84,     1,      },
+       { 0, /* Prohibited setting */                   },
+       { 1,            128,    1,      128,    1,      },
+       { 2,            192,    1,      192,    1,      },
+       { 2,            192,    1,      128,    1,      },
+       { 0, /* Prohibited setting */                   },
+       { 2,            192,    1,      192,    1,      },
 };
 
 static int __init r8a7796_cpg_mssr_init(struct device *dev)
diff --git a/drivers/clk/renesas/r8a77995-cpg-mssr.c b/drivers/clk/renesas/r8a77995-cpg-mssr.c
new file mode 100644 (file)
index 0000000..e594cf8
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * r8a77995 Clock Pulse Generator / Module Standby and Software Reset
+ *
+ * Copyright (C) 2017 Glider bvba
+ *
+ * Based on r8a7795-cpg-mssr.c
+ *
+ * Copyright (C) 2015 Glider bvba
+ * Copyright (C) 2015 Renesas Electronics Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/soc/renesas/rcar-rst.h>
+
+#include <dt-bindings/clock/r8a77995-cpg-mssr.h>
+
+#include "renesas-cpg-mssr.h"
+#include "rcar-gen3-cpg.h"
+
+enum clk_ids {
+       /* Core Clock Outputs exported to DT */
+       LAST_DT_CORE_CLK = R8A77995_CLK_CP,
+
+       /* External Input Clocks */
+       CLK_EXTAL,
+
+       /* Internal Core Clocks */
+       CLK_MAIN,
+       CLK_PLL0,
+       CLK_PLL1,
+       CLK_PLL3,
+       CLK_PLL0D2,
+       CLK_PLL0D3,
+       CLK_PLL0D5,
+       CLK_PLL1D2,
+       CLK_PE,
+       CLK_S0,
+       CLK_S1,
+       CLK_S2,
+       CLK_S3,
+       CLK_SDSRC,
+       CLK_SSPSRC,
+
+       /* Module Clocks */
+       MOD_CLK_BASE
+};
+
+static const struct cpg_core_clk r8a77995_core_clks[] __initconst = {
+       /* External Clock Inputs */
+       DEF_INPUT("extal",     CLK_EXTAL),
+
+       /* Internal Core Clocks */
+       DEF_BASE(".main",      CLK_MAIN, CLK_TYPE_GEN3_MAIN,       CLK_EXTAL),
+       DEF_BASE(".pll1",      CLK_PLL1, CLK_TYPE_GEN3_PLL1,       CLK_MAIN),
+       DEF_BASE(".pll3",      CLK_PLL3, CLK_TYPE_GEN3_PLL3,       CLK_MAIN),
+
+       DEF_FIXED(".pll0",     CLK_PLL0,           CLK_MAIN,       4, 250),
+       DEF_FIXED(".pll0d2",   CLK_PLL0D2,         CLK_PLL0,       2, 1),
+       DEF_FIXED(".pll0d3",   CLK_PLL0D3,         CLK_PLL0,       3, 1),
+       DEF_FIXED(".pll0d5",   CLK_PLL0D5,         CLK_PLL0,       5, 1),
+       DEF_FIXED(".pll1d2",   CLK_PLL1D2,         CLK_PLL1,       2, 1),
+       DEF_FIXED(".pe",       CLK_PE,             CLK_PLL0D3,     4, 1),
+       DEF_FIXED(".s0",       CLK_S0,             CLK_PLL1,       2, 1),
+       DEF_FIXED(".s1",       CLK_S1,             CLK_PLL1,       3, 1),
+       DEF_FIXED(".s2",       CLK_S2,             CLK_PLL1,       4, 1),
+       DEF_FIXED(".s3",       CLK_S3,             CLK_PLL1,       6, 1),
+       DEF_FIXED(".sdsrc",    CLK_SDSRC,          CLK_PLL1,       2, 1),
+
+       /* Core Clock Outputs */
+       DEF_FIXED("z2",        R8A77995_CLK_Z2,    CLK_PLL0D3,     1, 1),
+       DEF_FIXED("ztr",       R8A77995_CLK_ZTR,   CLK_PLL1,       6, 1),
+       DEF_FIXED("zt",        R8A77995_CLK_ZT,    CLK_PLL1,       4, 1),
+       DEF_FIXED("zx",        R8A77995_CLK_ZX,    CLK_PLL1,       3, 1),
+       DEF_FIXED("s0d1",      R8A77995_CLK_S0D1,  CLK_S0,         1, 1),
+       DEF_FIXED("s1d1",      R8A77995_CLK_S1D1,  CLK_S1,         1, 1),
+       DEF_FIXED("s1d2",      R8A77995_CLK_S1D2,  CLK_S1,         2, 1),
+       DEF_FIXED("s1d4",      R8A77995_CLK_S1D4,  CLK_S1,         4, 1),
+       DEF_FIXED("s2d1",      R8A77995_CLK_S2D1,  CLK_S2,         1, 1),
+       DEF_FIXED("s2d2",      R8A77995_CLK_S2D2,  CLK_S2,         2, 1),
+       DEF_FIXED("s2d4",      R8A77995_CLK_S2D4,  CLK_S2,         4, 1),
+       DEF_FIXED("s3d1",      R8A77995_CLK_S3D1,  CLK_S3,         1, 1),
+       DEF_FIXED("s3d2",      R8A77995_CLK_S3D2,  CLK_S3,         2, 1),
+       DEF_FIXED("s3d4",      R8A77995_CLK_S3D4,  CLK_S3,         4, 1),
+
+       DEF_FIXED("cl",        R8A77995_CLK_CL,    CLK_PLL1,      48, 1),
+       DEF_FIXED("cp",        R8A77995_CLK_CP,    CLK_EXTAL,      2, 1),
+       DEF_FIXED("osc",       R8A77995_CLK_OSC,   CLK_EXTAL,    384, 1),
+       DEF_FIXED("r",         R8A77995_CLK_R,     CLK_EXTAL,   1536, 1),
+
+       DEF_GEN3_PE("s1d4c",   R8A77995_CLK_S1D4C, CLK_S1, 4, CLK_PE, 2),
+       DEF_GEN3_PE("s3d1c",   R8A77995_CLK_S3D1C, CLK_S3, 1, CLK_PE, 1),
+       DEF_GEN3_PE("s3d2c",   R8A77995_CLK_S3D2C, CLK_S3, 2, CLK_PE, 2),
+       DEF_GEN3_PE("s3d4c",   R8A77995_CLK_S3D4C, CLK_S3, 4, CLK_PE, 4),
+
+       DEF_GEN3_SD("sd0",     R8A77995_CLK_SD0,   CLK_SDSRC,     0x268),
+
+       DEF_DIV6P1("canfd",    R8A77995_CLK_CANFD, CLK_PLL0D3,    0x244),
+       DEF_DIV6P1("mso",      R8A77995_CLK_MSO,   CLK_PLL1D2,    0x014),
+};
+
+static const struct mssr_mod_clk r8a77995_mod_clks[] __initconst = {
+       DEF_MOD("scif5",                 202,   R8A77995_CLK_S3D4C),
+       DEF_MOD("scif4",                 203,   R8A77995_CLK_S3D4C),
+       DEF_MOD("scif3",                 204,   R8A77995_CLK_S3D4C),
+       DEF_MOD("scif1",                 206,   R8A77995_CLK_S3D4C),
+       DEF_MOD("scif0",                 207,   R8A77995_CLK_S3D4C),
+       DEF_MOD("msiof3",                208,   R8A77995_CLK_MSO),
+       DEF_MOD("msiof2",                209,   R8A77995_CLK_MSO),
+       DEF_MOD("msiof1",                210,   R8A77995_CLK_MSO),
+       DEF_MOD("msiof0",                211,   R8A77995_CLK_MSO),
+       DEF_MOD("sys-dmac2",             217,   R8A77995_CLK_S3D1),
+       DEF_MOD("sys-dmac1",             218,   R8A77995_CLK_S3D1),
+       DEF_MOD("sys-dmac0",             219,   R8A77995_CLK_S3D1),
+       DEF_MOD("cmt3",                  300,   R8A77995_CLK_R),
+       DEF_MOD("cmt2",                  301,   R8A77995_CLK_R),
+       DEF_MOD("cmt1",                  302,   R8A77995_CLK_R),
+       DEF_MOD("cmt0",                  303,   R8A77995_CLK_R),
+       DEF_MOD("scif2",                 310,   R8A77995_CLK_S3D4C),
+       DEF_MOD("emmc0",                 312,   R8A77995_CLK_SD0),
+       DEF_MOD("usb-dmac0",             330,   R8A77995_CLK_S3D1),
+       DEF_MOD("usb-dmac1",             331,   R8A77995_CLK_S3D1),
+       DEF_MOD("rwdt",                  402,   R8A77995_CLK_R),
+       DEF_MOD("intc-ex",               407,   R8A77995_CLK_CP),
+       DEF_MOD("intc-ap",               408,   R8A77995_CLK_S3D1),
+       DEF_MOD("audmac0",               502,   R8A77995_CLK_S3D1),
+       DEF_MOD("hscif3",                517,   R8A77995_CLK_S3D1C),
+       DEF_MOD("hscif0",                520,   R8A77995_CLK_S3D1C),
+       DEF_MOD("thermal",               522,   R8A77995_CLK_CP),
+       DEF_MOD("pwm",                   523,   R8A77995_CLK_S3D4C),
+       DEF_MOD("fcpvd1",                602,   R8A77995_CLK_S1D2),
+       DEF_MOD("fcpvd0",                603,   R8A77995_CLK_S1D2),
+       DEF_MOD("fcpvbs",                607,   R8A77995_CLK_S0D1),
+       DEF_MOD("vspd1",                 622,   R8A77995_CLK_S1D2),
+       DEF_MOD("vspd0",                 623,   R8A77995_CLK_S1D2),
+       DEF_MOD("vspbs",                 627,   R8A77995_CLK_S0D1),
+       DEF_MOD("ehci0",                 703,   R8A77995_CLK_S3D2),
+       DEF_MOD("hsusb",                 704,   R8A77995_CLK_S3D2),
+       DEF_MOD("du1",                   723,   R8A77995_CLK_S2D1),
+       DEF_MOD("du0",                   724,   R8A77995_CLK_S2D1),
+       DEF_MOD("lvds",                  727,   R8A77995_CLK_S2D1),
+       DEF_MOD("vin7",                  804,   R8A77995_CLK_S1D2),
+       DEF_MOD("vin6",                  805,   R8A77995_CLK_S1D2),
+       DEF_MOD("vin5",                  806,   R8A77995_CLK_S1D2),
+       DEF_MOD("vin4",                  807,   R8A77995_CLK_S1D2),
+       DEF_MOD("etheravb",              812,   R8A77995_CLK_S3D2),
+       DEF_MOD("imr0",                  823,   R8A77995_CLK_S1D2),
+       DEF_MOD("gpio6",                 906,   R8A77995_CLK_S3D4),
+       DEF_MOD("gpio5",                 907,   R8A77995_CLK_S3D4),
+       DEF_MOD("gpio4",                 908,   R8A77995_CLK_S3D4),
+       DEF_MOD("gpio3",                 909,   R8A77995_CLK_S3D4),
+       DEF_MOD("gpio2",                 910,   R8A77995_CLK_S3D4),
+       DEF_MOD("gpio1",                 911,   R8A77995_CLK_S3D4),
+       DEF_MOD("gpio0",                 912,   R8A77995_CLK_S3D4),
+       DEF_MOD("can-fd",                914,   R8A77995_CLK_S3D2),
+       DEF_MOD("can-if1",               915,   R8A77995_CLK_S3D4),
+       DEF_MOD("can-if0",               916,   R8A77995_CLK_S3D4),
+       DEF_MOD("i2c3",                  928,   R8A77995_CLK_S3D2),
+       DEF_MOD("i2c2",                  929,   R8A77995_CLK_S3D2),
+       DEF_MOD("i2c1",                  930,   R8A77995_CLK_S3D2),
+       DEF_MOD("i2c0",                  931,   R8A77995_CLK_S3D2),
+       DEF_MOD("ssi-all",              1005,   R8A77995_CLK_S3D4),
+       DEF_MOD("ssi4",                 1011,   MOD_CLK_ID(1005)),
+       DEF_MOD("ssi3",                 1012,   MOD_CLK_ID(1005)),
+       DEF_MOD("scu-all",              1017,   R8A77995_CLK_S3D4),
+       DEF_MOD("scu-dvc1",             1018,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-dvc0",             1019,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-ctu1-mix1",        1020,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-ctu0-mix0",        1021,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src6",             1025,   MOD_CLK_ID(1017)),
+       DEF_MOD("scu-src5",             1026,   MOD_CLK_ID(1017)),
+};
+
+static const unsigned int r8a77995_crit_mod_clks[] __initconst = {
+       MOD_CLK_ID(408),        /* INTC-AP (GIC) */
+};
+
+
+/*
+ * CPG Clock Data
+ */
+
+/*
+ * MD19                EXTAL (MHz)     PLL0            PLL1            PLL3
+ *--------------------------------------------------------------------
+ * 0           48 x 1          x250/4          x100/3          x100/3
+ * 1           48 x 1          x250/4          x100/3          x116/6
+ */
+#define CPG_PLL_CONFIG_INDEX(md)       (((md) & BIT(19)) >> 19)
+
+static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[2] __initconst = {
+       /* EXTAL div    PLL1 mult/div   PLL3 mult/div */
+       { 1,            100,    3,      100,    3,      },
+       { 1,            100,    3,      116,    6,      },
+};
+
+static int __init r8a77995_cpg_mssr_init(struct device *dev)
+{
+       const struct rcar_gen3_cpg_pll_config *cpg_pll_config;
+       u32 cpg_mode;
+       int error;
+
+       error = rcar_rst_read_mode_pins(&cpg_mode);
+       if (error)
+               return error;
+
+       cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
+
+       return rcar_gen3_cpg_init(cpg_pll_config, 0, cpg_mode);
+}
+
+const struct cpg_mssr_info r8a77995_cpg_mssr_info __initconst = {
+       /* Core Clocks */
+       .core_clks = r8a77995_core_clks,
+       .num_core_clks = ARRAY_SIZE(r8a77995_core_clks),
+       .last_dt_core_clk = LAST_DT_CORE_CLK,
+       .num_total_core_clks = MOD_CLK_BASE,
+
+       /* Module Clocks */
+       .mod_clks = r8a77995_mod_clks,
+       .num_mod_clks = ARRAY_SIZE(r8a77995_mod_clks),
+       .num_hw_mod_clks = 12 * 32,
+
+       /* Critical Module Clocks */
+       .crit_mod_clks = r8a77995_crit_mod_clks,
+       .num_crit_mod_clks = ARRAY_SIZE(r8a77995_crit_mod_clks),
+
+       /* Callbacks */
+       .init = r8a77995_cpg_mssr_init,
+       .cpg_clk_register = rcar_gen3_cpg_clk_register,
+};
index 3dee900522b703bd650c5265b2314c1d3c522741..9511058165475dd7c8563aaa1409d1dd5ada5cc1 100644 (file)
@@ -60,6 +60,7 @@ struct sd_clock {
        unsigned int div_num;
        unsigned int div_min;
        unsigned int div_max;
+       unsigned int cur_div_idx;
 };
 
 /* SDn divider
@@ -96,21 +97,10 @@ static const struct sd_div_table cpg_sd_div_table[] = {
 static int cpg_sd_clock_enable(struct clk_hw *hw)
 {
        struct sd_clock *clock = to_sd_clock(hw);
-       u32 val, sd_fc;
-       unsigned int i;
-
-       val = readl(clock->reg);
-
-       sd_fc = val & CPG_SD_FC_MASK;
-       for (i = 0; i < clock->div_num; i++)
-               if (sd_fc == (clock->div_table[i].val & CPG_SD_FC_MASK))
-                       break;
-
-       if (i >= clock->div_num)
-               return -EINVAL;
+       u32 val = readl(clock->reg);
 
        val &= ~(CPG_SD_STP_MASK);
-       val |= clock->div_table[i].val & CPG_SD_STP_MASK;
+       val |= clock->div_table[clock->cur_div_idx].val & CPG_SD_STP_MASK;
 
        writel(val, clock->reg);
 
@@ -135,21 +125,9 @@ static unsigned long cpg_sd_clock_recalc_rate(struct clk_hw *hw,
                                                unsigned long parent_rate)
 {
        struct sd_clock *clock = to_sd_clock(hw);
-       unsigned long rate = parent_rate;
-       u32 val, sd_fc;
-       unsigned int i;
 
-       val = readl(clock->reg);
-
-       sd_fc = val & CPG_SD_FC_MASK;
-      &n