diff options
101 files changed, 4134 insertions, 798 deletions
diff --git a/Documentation/devicetree/bindings/clock/exynos3250-clock.txt b/Documentation/devicetree/bindings/clock/exynos3250-clock.txt index aadc9c59e2d1..f57d9dd9ea85 100644 --- a/Documentation/devicetree/bindings/clock/exynos3250-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos3250-clock.txt | |||
| @@ -7,6 +7,8 @@ Required Properties: | |||
| 7 | 7 | ||
| 8 | - compatible: should be one of the following. | 8 | - compatible: should be one of the following. |
| 9 | - "samsung,exynos3250-cmu" - controller compatible with Exynos3250 SoC. | 9 | - "samsung,exynos3250-cmu" - controller compatible with Exynos3250 SoC. |
| 10 | - "samsung,exynos3250-cmu-dmc" - controller compatible with | ||
| 11 | Exynos3250 SoC for Dynamic Memory Controller domain. | ||
| 10 | 12 | ||
| 11 | - reg: physical base address of the controller and length of memory mapped | 13 | - reg: physical base address of the controller and length of memory mapped |
| 12 | region. | 14 | region. |
| @@ -20,7 +22,7 @@ All available clocks are defined as preprocessor macros in | |||
| 20 | dt-bindings/clock/exynos3250.h header and can be used in device | 22 | dt-bindings/clock/exynos3250.h header and can be used in device |
| 21 | tree sources. | 23 | tree sources. |
| 22 | 24 | ||
| 23 | Example 1: An example of a clock controller node is listed below. | 25 | Example 1: Examples of clock controller nodes are listed below. |
| 24 | 26 | ||
| 25 | cmu: clock-controller@10030000 { | 27 | cmu: clock-controller@10030000 { |
| 26 | compatible = "samsung,exynos3250-cmu"; | 28 | compatible = "samsung,exynos3250-cmu"; |
| @@ -28,6 +30,12 @@ Example 1: An example of a clock controller node is listed below. | |||
| 28 | #clock-cells = <1>; | 30 | #clock-cells = <1>; |
| 29 | }; | 31 | }; |
| 30 | 32 | ||
| 33 | cmu_dmc: clock-controller@105C0000 { | ||
| 34 | compatible = "samsung,exynos3250-cmu-dmc"; | ||
| 35 | reg = <0x105C0000 0x2000>; | ||
| 36 | #clock-cells = <1>; | ||
| 37 | }; | ||
| 38 | |||
| 31 | Example 2: UART controller node that consumes the clock generated by the clock | 39 | Example 2: UART controller node that consumes the clock generated by the clock |
| 32 | controller. Refer to the standard clock bindings for information | 40 | controller. Refer to the standard clock bindings for information |
| 33 | about 'clocks' and 'clock-names' property. | 41 | about 'clocks' and 'clock-names' property. |
diff --git a/Documentation/devicetree/bindings/clock/gpio-gate-clock.txt b/Documentation/devicetree/bindings/clock/gpio-gate-clock.txt new file mode 100644 index 000000000000..d3379ff9b84b --- /dev/null +++ b/Documentation/devicetree/bindings/clock/gpio-gate-clock.txt | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | Binding for simple gpio gated clock. | ||
| 2 | |||
| 3 | This binding uses the common clock binding[1]. | ||
| 4 | |||
| 5 | [1] Documentation/devicetree/bindings/clock/clock-bindings.txt | ||
| 6 | |||
| 7 | Required properties: | ||
| 8 | - compatible : shall be "gpio-gate-clock". | ||
| 9 | - #clock-cells : from common clock binding; shall be set to 0. | ||
| 10 | - enable-gpios : GPIO reference for enabling and disabling the clock. | ||
| 11 | |||
| 12 | Optional properties: | ||
| 13 | - clocks: Maximum of one parent clock is supported. | ||
| 14 | |||
| 15 | Example: | ||
| 16 | clock { | ||
| 17 | compatible = "gpio-gate-clock"; | ||
| 18 | clocks = <&parentclk>; | ||
| 19 | #clock-cells = <0>; | ||
| 20 | enable-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>; | ||
| 21 | }; | ||
diff --git a/Documentation/devicetree/bindings/clock/maxim,max77686.txt b/Documentation/devicetree/bindings/clock/maxim,max77686.txt index 96ce71bbd745..9c40739a661a 100644 --- a/Documentation/devicetree/bindings/clock/maxim,max77686.txt +++ b/Documentation/devicetree/bindings/clock/maxim,max77686.txt | |||
| @@ -9,13 +9,21 @@ The MAX77686 contains three 32.768khz clock outputs that can be controlled | |||
| 9 | Following properties should be presend in main device node of the MFD chip. | 9 | Following properties should be presend in main device node of the MFD chip. |
| 10 | 10 | ||
| 11 | Required properties: | 11 | Required properties: |
| 12 | - #clock-cells: simple one-cell clock specifier format is used, where the | 12 | |
| 13 | only cell is used as an index of the clock inside the provider. Following | 13 | - #clock-cells: from common clock binding; shall be set to 1. |
| 14 | indices are allowed: | 14 | |
| 15 | Optional properties: | ||
| 16 | - clock-output-names: From common clock binding. | ||
| 17 | |||
| 18 | Each clock is assigned an identifier and client nodes can use this identifier | ||
| 19 | to specify the clock which they consume. Following indices are allowed: | ||
| 15 | - 0: 32khz_ap clock, | 20 | - 0: 32khz_ap clock, |
| 16 | - 1: 32khz_cp clock, | 21 | - 1: 32khz_cp clock, |
| 17 | - 2: 32khz_pmic clock. | 22 | - 2: 32khz_pmic clock. |
| 18 | 23 | ||
| 24 | Clocks are defined as preprocessor macros in dt-bindings/clock/maxim,max77686.h | ||
| 25 | header and can be used in device tree sources. | ||
| 26 | |||
| 19 | Example: Node of the MFD chip | 27 | Example: Node of the MFD chip |
| 20 | 28 | ||
| 21 | max77686: max77686@09 { | 29 | max77686: max77686@09 { |
| @@ -34,5 +42,5 @@ Example: Clock consumer node | |||
| 34 | compatible = "bar,foo"; | 42 | compatible = "bar,foo"; |
| 35 | /* ... */ | 43 | /* ... */ |
| 36 | clock-names = "my-clock"; | 44 | clock-names = "my-clock"; |
| 37 | clocks = <&max77686 2>; | 45 | clocks = <&max77686 MAX77686_CLK_PMIC>; |
| 38 | }; | 46 | }; |
diff --git a/Documentation/devicetree/bindings/clock/maxim,max77802.txt b/Documentation/devicetree/bindings/clock/maxim,max77802.txt new file mode 100644 index 000000000000..c6dc7835f06c --- /dev/null +++ b/Documentation/devicetree/bindings/clock/maxim,max77802.txt | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | Binding for Maxim MAX77802 32k clock generator block | ||
| 2 | |||
| 3 | This is a part of device tree bindings of MAX77802 multi-function device. | ||
| 4 | More information can be found in bindings/mfd/max77802.txt file. | ||
| 5 | |||
| 6 | The MAX77802 contains two 32.768khz clock outputs that can be controlled | ||
| 7 | (gated/ungated) over I2C. | ||
| 8 | |||
| 9 | Following properties should be present in main device node of the MFD chip. | ||
| 10 | |||
| 11 | Required properties: | ||
| 12 | - #clock-cells: From common clock binding; shall be set to 1. | ||
| 13 | |||
| 14 | Optional properties: | ||
| 15 | - clock-output-names: From common clock binding. | ||
| 16 | |||
| 17 | Each clock is assigned an identifier and client nodes can use this identifier | ||
| 18 | to specify the clock which they consume. Following indices are allowed: | ||
| 19 | - 0: 32khz_ap clock, | ||
| 20 | - 1: 32khz_cp clock. | ||
| 21 | |||
| 22 | Clocks are defined as preprocessor macros in dt-bindings/clock/maxim,max77802.h | ||
| 23 | header and can be used in device tree sources. | ||
| 24 | |||
| 25 | Example: Node of the MFD chip | ||
| 26 | |||
| 27 | max77802: max77802@09 { | ||
| 28 | compatible = "maxim,max77802"; | ||
| 29 | interrupt-parent = <&wakeup_eint>; | ||
| 30 | interrupts = <26 0>; | ||
| 31 | reg = <0x09>; | ||
| 32 | #clock-cells = <1>; | ||
| 33 | |||
| 34 | /* ... */ | ||
| 35 | }; | ||
| 36 | |||
| 37 | Example: Clock consumer node | ||
| 38 | |||
| 39 | foo@0 { | ||
| 40 | compatible = "bar,foo"; | ||
| 41 | /* ... */ | ||
| 42 | clock-names = "my-clock"; | ||
| 43 | clocks = <&max77802 MAX77802_CLK_32K_AP>; | ||
| 44 | }; | ||
diff --git a/Documentation/devicetree/bindings/clock/pxa-clock.txt b/Documentation/devicetree/bindings/clock/pxa-clock.txt new file mode 100644 index 000000000000..4b4a9024bd99 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/pxa-clock.txt | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | * Clock bindings for Marvell PXA chips | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: Should be "marvell,pxa-clocks" | ||
| 5 | - #clock-cells: Should be <1> | ||
| 6 | |||
| 7 | The clock consumer should specify the desired clock by having the clock | ||
| 8 | ID in its "clocks" phandle cell (see include/.../pxa-clock.h). | ||
| 9 | |||
| 10 | Examples: | ||
| 11 | |||
| 12 | pxa2xx_clks: pxa2xx_clks@41300004 { | ||
| 13 | compatible = "marvell,pxa-clocks"; | ||
| 14 | #clock-cells = <1>; | ||
| 15 | status = "okay"; | ||
| 16 | }; | ||
diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt index 8f1424f0fa43..a5f52238c80d 100644 --- a/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt +++ b/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt | |||
| @@ -15,6 +15,7 @@ Required Properties: | |||
| 15 | - "renesas,r8a7779-mstp-clocks" for R8A7779 (R-Car H1) MSTP gate clocks | 15 | - "renesas,r8a7779-mstp-clocks" for R8A7779 (R-Car H1) MSTP gate clocks |
| 16 | - "renesas,r8a7790-mstp-clocks" for R8A7790 (R-Car H2) MSTP gate clocks | 16 | - "renesas,r8a7790-mstp-clocks" for R8A7790 (R-Car H2) MSTP gate clocks |
| 17 | - "renesas,r8a7791-mstp-clocks" for R8A7791 (R-Car M2) MSTP gate clocks | 17 | - "renesas,r8a7791-mstp-clocks" for R8A7791 (R-Car M2) MSTP gate clocks |
| 18 | - "renesas,r8a7794-mstp-clocks" for R8A7794 (R-Car E2) MSTP gate clocks | ||
| 18 | - "renesas,sh73a0-mstp-clocks" for SH73A0 (SH-MobileAG5) MSTP gate clocks | 19 | - "renesas,sh73a0-mstp-clocks" for SH73A0 (SH-MobileAG5) MSTP gate clocks |
| 19 | - "renesas,cpg-mstp-clock" for generic MSTP gate clocks | 20 | - "renesas,cpg-mstp-clock" for generic MSTP gate clocks |
| 20 | - reg: Base address and length of the I/O mapped registers used by the MSTP | 21 | - reg: Base address and length of the I/O mapped registers used by the MSTP |
diff --git a/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt index 7b41c2fe54db..e6ad35b894f9 100644 --- a/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt +++ b/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt | |||
| @@ -8,6 +8,7 @@ Required Properties: | |||
| 8 | - compatible: Must be one of | 8 | - compatible: Must be one of |
| 9 | - "renesas,r8a7790-cpg-clocks" for the r8a7790 CPG | 9 | - "renesas,r8a7790-cpg-clocks" for the r8a7790 CPG |
| 10 | - "renesas,r8a7791-cpg-clocks" for the r8a7791 CPG | 10 | - "renesas,r8a7791-cpg-clocks" for the r8a7791 CPG |
| 11 | - "renesas,r8a7794-cpg-clocks" for the r8a7794 CPG | ||
| 11 | - "renesas,rcar-gen2-cpg-clocks" for the generic R-Car Gen2 CPG | 12 | - "renesas,rcar-gen2-cpg-clocks" for the generic R-Car Gen2 CPG |
| 12 | 13 | ||
| 13 | - reg: Base address and length of the memory resource used by the CPG | 14 | - reg: Base address and length of the memory resource used by the CPG |
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt index d3a5c3c6d677..ed116df9c3e7 100644 --- a/Documentation/devicetree/bindings/clock/sunxi.txt +++ b/Documentation/devicetree/bindings/clock/sunxi.txt | |||
| @@ -46,7 +46,11 @@ Required properties: | |||
| 46 | "allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31 | 46 | "allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31 |
| 47 | "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 | 47 | "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 |
| 48 | "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23 | 48 | "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23 |
| 49 | "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13 | ||
| 50 | "allwinner,sun4i-a10-mmc-output-clk" - for the MMC output clock on A10 | ||
| 51 | "allwinner,sun4i-a10-mmc-sample-clk" - for the MMC sample clock on A10 | ||
| 49 | "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks | 52 | "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks |
| 53 | "allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23 | ||
| 50 | "allwinner,sun7i-a20-out-clk" - for the external output clocks | 54 | "allwinner,sun7i-a20-out-clk" - for the external output clocks |
| 51 | "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31 | 55 | "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31 |
| 52 | "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20 | 56 | "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20 |
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 04e9f5505faa..b62bdcb1eb39 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
| @@ -605,11 +605,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
| 605 | See Documentation/s390/CommonIO for details. | 605 | See Documentation/s390/CommonIO for details. |
| 606 | clk_ignore_unused | 606 | clk_ignore_unused |
| 607 | [CLK] | 607 | [CLK] |
| 608 | Keep all clocks already enabled by bootloader on, | 608 | Prevents the clock framework from automatically gating |
| 609 | even if no driver has claimed them. This is useful | 609 | clocks that have not been explicitly enabled by a Linux |
| 610 | for debug and development, but should not be | 610 | device driver but are enabled in hardware at reset or |
| 611 | needed on a platform with proper driver support. | 611 | by the bootloader/firmware. Note that this does not |
| 612 | For more information, see Documentation/clk.txt. | 612 | force such clocks to be always-on nor does it reserve |
| 613 | those clocks in any way. This parameter is useful for | ||
| 614 | debug and development, but should not be needed on a | ||
| 615 | platform with proper driver support. For more | ||
| 616 | information, see Documentation/clk.txt. | ||
| 613 | 617 | ||
| 614 | clock= [BUGS=X86-32, HW] gettimeofday clocksource override. | 618 | clock= [BUGS=X86-32, HW] gettimeofday clocksource override. |
| 615 | [Deprecated] | 619 | [Deprecated] |
diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi index 8831c48c2bc9..693a3275606f 100644 --- a/arch/arm/boot/dts/exynos3250.dtsi +++ b/arch/arm/boot/dts/exynos3250.dtsi | |||
| @@ -169,6 +169,12 @@ | |||
| 169 | #clock-cells = <1>; | 169 | #clock-cells = <1>; |
| 170 | }; | 170 | }; |
| 171 | 171 | ||
| 172 | cmu_dmc: clock-controller@105C0000 { | ||
| 173 | compatible = "samsung,exynos3250-cmu-dmc"; | ||
| 174 | reg = <0x105C0000 0x2000>; | ||
| 175 | #clock-cells = <1>; | ||
| 176 | }; | ||
| 177 | |||
| 172 | rtc: rtc@10070000 { | 178 | rtc: rtc@10070000 { |
| 173 | compatible = "samsung,exynos3250-rtc"; | 179 | compatible = "samsung,exynos3250-rtc"; |
| 174 | reg = <0x10070000 0x100>; | 180 | reg = <0x10070000 0x100>; |
diff --git a/arch/arm/boot/dts/pxa27x.dtsi b/arch/arm/boot/dts/pxa27x.dtsi index a70546945985..80fc5d7e9ef9 100644 --- a/arch/arm/boot/dts/pxa27x.dtsi +++ b/arch/arm/boot/dts/pxa27x.dtsi | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* The pxa3xx skeleton simply augments the 2xx version */ | 1 | /* The pxa3xx skeleton simply augments the 2xx version */ |
| 2 | /include/ "pxa2xx.dtsi" | 2 | #include "pxa2xx.dtsi" |
| 3 | #include "dt-bindings/clock/pxa2xx-clock.h" | ||
| 3 | 4 | ||
| 4 | / { | 5 | / { |
| 5 | model = "Marvell PXA27x familiy SoC"; | 6 | model = "Marvell PXA27x familiy SoC"; |
| @@ -35,4 +36,21 @@ | |||
| 35 | #pwm-cells = <1>; | 36 | #pwm-cells = <1>; |
| 36 | }; | 37 | }; |
| 37 | }; | 38 | }; |
| 39 | |||
| 40 | clocks { | ||
| 41 | /* | ||
| 42 | * The muxing of external clocks/internal dividers for osc* clock | ||
| 43 | * sources has been hidden under the carpet by now. | ||
| 44 | */ | ||
| 45 | #address-cells = <1>; | ||
| 46 | #size-cells = <1>; | ||
| 47 | ranges; | ||
| 48 | |||
| 49 | pxa2xx_clks: pxa2xx_clks@41300004 { | ||
| 50 | compatible = "marvell,pxa-clocks"; | ||
| 51 | #clock-cells = <1>; | ||
| 52 | status = "okay"; | ||
| 53 | }; | ||
| 54 | }; | ||
| 55 | |||
| 38 | }; | 56 | }; |
diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi index d73a2287b37a..531272c0e526 100644 --- a/arch/arm/boot/dts/sun5i-a10s.dtsi +++ b/arch/arm/boot/dts/sun5i-a10s.dtsi | |||
| @@ -287,7 +287,7 @@ | |||
| 287 | 287 | ||
| 288 | mbus_clk: clk@01c2015c { | 288 | mbus_clk: clk@01c2015c { |
| 289 | #clock-cells = <0>; | 289 | #clock-cells = <0>; |
| 290 | compatible = "allwinner,sun4i-a10-mod0-clk"; | 290 | compatible = "allwinner,sun5i-a13-mbus-clk"; |
| 291 | reg = <0x01c2015c 0x4>; | 291 | reg = <0x01c2015c 0x4>; |
| 292 | clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; | 292 | clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; |
| 293 | clock-output-names = "mbus"; | 293 | clock-output-names = "mbus"; |
diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi index c4b5d7825b9f..b131068f4f35 100644 --- a/arch/arm/boot/dts/sun5i-a13.dtsi +++ b/arch/arm/boot/dts/sun5i-a13.dtsi | |||
| @@ -285,7 +285,7 @@ | |||
| 285 | 285 | ||
| 286 | mbus_clk: clk@01c2015c { | 286 | mbus_clk: clk@01c2015c { |
| 287 | #clock-cells = <0>; | 287 | #clock-cells = <0>; |
| 288 | compatible = "allwinner,sun4i-a10-mod0-clk"; | 288 | compatible = "allwinner,sun5i-a13-mbus-clk"; |
| 289 | reg = <0x01c2015c 0x4>; | 289 | reg = <0x01c2015c 0x4>; |
| 290 | clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; | 290 | clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; |
| 291 | clock-output-names = "mbus"; | 291 | clock-output-names = "mbus"; |
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index a96b99465069..82097c905c48 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi | |||
| @@ -382,7 +382,7 @@ | |||
| 382 | 382 | ||
| 383 | mbus_clk: clk@01c2015c { | 383 | mbus_clk: clk@01c2015c { |
| 384 | #clock-cells = <0>; | 384 | #clock-cells = <0>; |
| 385 | compatible = "allwinner,sun4i-a10-mod0-clk"; | 385 | compatible = "allwinner,sun5i-a13-mbus-clk"; |
| 386 | reg = <0x01c2015c 0x4>; | 386 | reg = <0x01c2015c 0x4>; |
| 387 | clocks = <&osc24M>, <&pll6 2>, <&pll5 1>; | 387 | clocks = <&osc24M>, <&pll6 2>, <&pll5 1>; |
| 388 | clock-output-names = "mbus"; | 388 | clock-output-names = "mbus"; |
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index b8ad045bcb8d..03cbb16898a3 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c | |||
| @@ -723,8 +723,16 @@ int __init omap_clk_init(void) | |||
| 723 | ti_clk_init_features(); | 723 | ti_clk_init_features(); |
| 724 | 724 | ||
| 725 | ret = of_prcm_init(); | 725 | ret = of_prcm_init(); |
| 726 | if (!ret) | 726 | if (ret) |
| 727 | ret = omap_clk_soc_init(); | 727 | return ret; |
| 728 | |||
| 729 | of_clk_init(NULL); | ||
| 730 | |||
| 731 | ti_dt_clk_init_retry_clks(); | ||
| 732 | |||
| 733 | ti_dt_clockdomains_setup(); | ||
| 734 | |||
| 735 | ret = omap_clk_soc_init(); | ||
| 728 | 736 | ||
| 729 | return ret; | 737 | return ret; |
| 730 | } | 738 | } |
diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c index 74054b813600..ee2b5222eac0 100644 --- a/arch/arm/mach-omap2/prm_common.c +++ b/arch/arm/mach-omap2/prm_common.c | |||
| @@ -525,8 +525,6 @@ int __init of_prcm_init(void) | |||
| 525 | memmap_index++; | 525 | memmap_index++; |
| 526 | } | 526 | } |
| 527 | 527 | ||
| 528 | ti_dt_clockdomains_setup(); | ||
| 529 | |||
| 530 | return 0; | 528 | return 0; |
| 531 | } | 529 | } |
| 532 | 530 | ||
diff --git a/arch/arm/mach-pxa/include/mach/pxa2xx-regs.h b/arch/arm/mach-pxa/include/mach/pxa2xx-regs.h index ee6ced1cea7f..f1dd62946b36 100644 --- a/arch/arm/mach-pxa/include/mach/pxa2xx-regs.h +++ b/arch/arm/mach-pxa/include/mach/pxa2xx-regs.h | |||
| @@ -143,6 +143,16 @@ | |||
| 143 | #define CCCR_M_MASK 0x0060 /* Memory Frequency to Run Mode Frequency Multiplier */ | 143 | #define CCCR_M_MASK 0x0060 /* Memory Frequency to Run Mode Frequency Multiplier */ |
| 144 | #define CCCR_L_MASK 0x001f /* Crystal Frequency to Memory Frequency Multiplier */ | 144 | #define CCCR_L_MASK 0x001f /* Crystal Frequency to Memory Frequency Multiplier */ |
| 145 | 145 | ||
| 146 | #define CCCR_CPDIS_BIT (31) | ||
| 147 | #define CCCR_PPDIS_BIT (30) | ||
| 148 | #define CCCR_LCD_26_BIT (27) | ||
| 149 | #define CCCR_A_BIT (25) | ||
| 150 | |||
| 151 | #define CCSR_N2_MASK CCCR_N_MASK | ||
| 152 | #define CCSR_M_MASK CCCR_M_MASK | ||
| 153 | #define CCSR_L_MASK CCCR_L_MASK | ||
| 154 | #define CCSR_N2_SHIFT 7 | ||
| 155 | |||
| 146 | #define CKEN_AC97CONF (31) /* AC97 Controller Configuration */ | 156 | #define CKEN_AC97CONF (31) /* AC97 Controller Configuration */ |
| 147 | #define CKEN_CAMERA (24) /* Camera Interface Clock Enable */ | 157 | #define CKEN_CAMERA (24) /* Camera Interface Clock Enable */ |
| 148 | #define CKEN_SSP1 (23) /* SSP1 Unit Clock Enable */ | 158 | #define CKEN_SSP1 (23) /* SSP1 Unit Clock Enable */ |
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 84e0590e31dc..455fd17d938e 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig | |||
| @@ -32,12 +32,23 @@ config COMMON_CLK_WM831X | |||
| 32 | 32 | ||
| 33 | source "drivers/clk/versatile/Kconfig" | 33 | source "drivers/clk/versatile/Kconfig" |
| 34 | 34 | ||
| 35 | config COMMON_CLK_MAX_GEN | ||
| 36 | bool | ||
| 37 | |||
| 35 | config COMMON_CLK_MAX77686 | 38 | config COMMON_CLK_MAX77686 |
| 36 | tristate "Clock driver for Maxim 77686 MFD" | 39 | tristate "Clock driver for Maxim 77686 MFD" |
| 37 | depends on MFD_MAX77686 | 40 | depends on MFD_MAX77686 |
| 41 | select COMMON_CLK_MAX_GEN | ||
| 38 | ---help--- | 42 | ---help--- |
| 39 | This driver supports Maxim 77686 crystal oscillator clock. | 43 | This driver supports Maxim 77686 crystal oscillator clock. |
| 40 | 44 | ||
| 45 | config COMMON_CLK_MAX77802 | ||
| 46 | tristate "Clock driver for Maxim 77802 PMIC" | ||
| 47 | depends on MFD_MAX77686 | ||
| 48 | select COMMON_CLK_MAX_GEN | ||
| 49 | ---help--- | ||
| 50 | This driver supports Maxim 77802 crystal oscillator clock. | ||
| 51 | |||
| 41 | config COMMON_CLK_RK808 | 52 | config COMMON_CLK_RK808 |
| 42 | tristate "Clock driver for RK808" | 53 | tristate "Clock driver for RK808" |
| 43 | depends on MFD_RK808 | 54 | depends on MFD_RK808 |
| @@ -118,6 +129,11 @@ config COMMON_CLK_PALMAS | |||
| 118 | This driver supports TI Palmas devices 32KHz output KG and KG_AUDIO | 129 | This driver supports TI Palmas devices 32KHz output KG and KG_AUDIO |
| 119 | using common clock framework. | 130 | using common clock framework. |
| 120 | 131 | ||
| 132 | config COMMON_CLK_PXA | ||
| 133 | def_bool COMMON_CLK && ARCH_PXA | ||
| 134 | ---help--- | ||
| 135 | Sypport for the Marvell PXA SoC. | ||
| 136 | |||
| 121 | source "drivers/clk/qcom/Kconfig" | 137 | source "drivers/clk/qcom/Kconfig" |
| 122 | 138 | ||
| 123 | endmenu | 139 | endmenu |
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 99f53d5f8766..d5fba5bc6e1b 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile | |||
| @@ -9,6 +9,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-gate.o | |||
| 9 | obj-$(CONFIG_COMMON_CLK) += clk-mux.o | 9 | obj-$(CONFIG_COMMON_CLK) += clk-mux.o |
| 10 | obj-$(CONFIG_COMMON_CLK) += clk-composite.o | 10 | obj-$(CONFIG_COMMON_CLK) += clk-composite.o |
| 11 | obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o | 11 | obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o |
| 12 | obj-$(CONFIG_COMMON_CLK) += clk-gpio-gate.o | ||
| 12 | ifeq ($(CONFIG_OF), y) | 13 | ifeq ($(CONFIG_OF), y) |
| 13 | obj-$(CONFIG_COMMON_CLK) += clk-conf.o | 14 | obj-$(CONFIG_COMMON_CLK) += clk-conf.o |
| 14 | endif | 15 | endif |
| @@ -22,7 +23,9 @@ obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o | |||
| 22 | obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o | 23 | obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o |
| 23 | obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o | 24 | obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o |
| 24 | obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o | 25 | obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o |
| 26 | obj-$(CONFIG_COMMON_CLK_MAX_GEN) += clk-max-gen.o | ||
| 25 | obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o | 27 | obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o |
| 28 | obj-$(CONFIG_COMMON_CLK_MAX77802) += clk-max77802.o | ||
| 26 | obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o | 29 | obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o |
| 27 | obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o | 30 | obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o |
| 28 | obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o | 31 | obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o |
| @@ -49,6 +52,7 @@ obj-$(CONFIG_ARCH_MMP) += mmp/ | |||
| 49 | endif | 52 | endif |
| 50 | obj-$(CONFIG_PLAT_ORION) += mvebu/ | 53 | obj-$(CONFIG_PLAT_ORION) += mvebu/ |
| 51 | obj-$(CONFIG_ARCH_MXS) += mxs/ | 54 | obj-$(CONFIG_ARCH_MXS) += mxs/ |
| 55 | obj-$(CONFIG_COMMON_CLK_PXA) += pxa/ | ||
| 52 | obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ | 56 | obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ |
| 53 | obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ | 57 | obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ |
| 54 | obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ | 58 | obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ |
diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c index cf6ed023504c..6ec79dbc0840 100644 --- a/drivers/clk/at91/clk-pll.c +++ b/drivers/clk/at91/clk-pll.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/of_address.h> | 15 | #include <linux/of_address.h> |
| 16 | #include <linux/of_irq.h> | 16 | #include <linux/of_irq.h> |
| 17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
| 18 | #include <linux/kernel.h> | ||
| 18 | #include <linux/wait.h> | 19 | #include <linux/wait.h> |
| 19 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
| 20 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
| @@ -29,9 +30,12 @@ | |||
| 29 | #define PLL_DIV(reg) ((reg) & PLL_DIV_MASK) | 30 | #define PLL_DIV(reg) ((reg) & PLL_DIV_MASK) |
| 30 | #define PLL_MUL(reg, layout) (((reg) >> (layout)->mul_shift) & \ | 31 | #define PLL_MUL(reg, layout) (((reg) >> (layout)->mul_shift) & \ |
| 31 | (layout)->mul_mask) | 32 | (layout)->mul_mask) |
| 33 | #define PLL_MUL_MIN 2 | ||
| 34 | #define PLL_MUL_MASK(layout) ((layout)->mul_mask) | ||
| 35 | #define PLL_MUL_MAX(layout) (PLL_MUL_MASK(layout) + 1) | ||
| 32 | #define PLL_ICPR_SHIFT(id) ((id) * 16) | 36 | #define PLL_ICPR_SHIFT(id) ((id) * 16) |
| 33 | #define PLL_ICPR_MASK(id) (0xffff << PLL_ICPR_SHIFT(id)) | 37 | #define PLL_ICPR_MASK(id) (0xffff << PLL_ICPR_SHIFT(id)) |
| 34 | #define PLL_MAX_COUNT 0x3ff | 38 | #define PLL_MAX_COUNT 0x3f |
| 35 | #define PLL_COUNT_SHIFT 8 | 39 | #define PLL_COUNT_SHIFT 8 |
| 36 | #define PLL_OUT_SHIFT 14 | 40 | #define PLL_OUT_SHIFT 14 |
| 37 | #define PLL_MAX_ID 1 | 41 | #define PLL_MAX_ID 1 |
| @@ -147,115 +151,113 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, | |||
| 147 | unsigned long parent_rate) | 151 | unsigned long parent_rate) |
| 148 | { | 152 | { |
| 149 | struct clk_pll *pll = to_clk_pll(hw); | 153 | struct clk_pll *pll = to_clk_pll(hw); |
| 150 | const struct clk_pll_layout *layout = pll->layout; | 154 | |
| 151 | struct at91_pmc *pmc = pll->pmc; | 155 | if (!pll->div || !pll->mul) |
| 152 | int offset = PLL_REG(pll->id); | ||
| 153 | u32 tmp = pmc_read(pmc, offset) & layout->pllr_mask; | ||
| 154 | u8 div = PLL_DIV(tmp); | ||
| 155 | u16 mul = PLL_MUL(tmp, layout); | ||
| 156 | if (!div || !mul) | ||
| 157 | return 0; | 156 | return 0; |
| 158 | 157 | ||
| 159 | return (parent_rate * (mul + 1)) / div; | 158 | return (parent_rate / pll->div) * (pll->mul + 1); |
| 160 | } | 159 | } |
| 161 | 160 | ||
| 162 | static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate, | 161 | static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate, |
| 163 | unsigned long parent_rate, | 162 | unsigned long parent_rate, |
| 164 | u32 *div, u32 *mul, | 163 | u32 *div, u32 *mul, |
| 165 | u32 *index) { | 164 | u32 *index) { |
| 166 | unsigned long maxrate; | ||
| 167 | unsigned long minrate; | ||
| 168 | unsigned long divrate; | ||
| 169 | unsigned long bestdiv = 1; | ||
| 170 | unsigned long bestmul; | ||
| 171 | unsigned long tmpdiv; | ||
| 172 | unsigned long roundup; | ||
| 173 | unsigned long rounddown; | ||
| 174 | unsigned long remainder; | ||
| 175 | unsigned long bestremainder; | ||
| 176 | unsigned long maxmul; | ||
| 177 | unsigned long maxdiv; | ||
| 178 | unsigned long mindiv; | ||
| 179 | int i = 0; | ||
| 180 | const struct clk_pll_layout *layout = pll->layout; | 165 | const struct clk_pll_layout *layout = pll->layout; |
| 181 | const struct clk_pll_characteristics *characteristics = | 166 | const struct clk_pll_characteristics *characteristics = |
| 182 | pll->characteristics; | 167 | pll->characteristics; |
| 168 | unsigned long bestremainder = ULONG_MAX; | ||
| 169 | unsigned long maxdiv, mindiv, tmpdiv; | ||
| 170 | long bestrate = -ERANGE; | ||
| 171 | unsigned long bestdiv; | ||
| 172 | unsigned long bestmul; | ||
| 173 | int i = 0; | ||
| 183 | 174 | ||
| 184 | /* Minimum divider = 1 */ | 175 | /* Check if parent_rate is a valid input rate */ |
| 185 | /* Maximum multiplier = max_mul */ | ||
| 186 | maxmul = layout->mul_mask + 1; | ||
| 187 | maxrate = (parent_rate * maxmul) / 1; | ||
| 188 | |||
| 189 | /* Maximum divider = max_div */ | ||
| 190 | /* Minimum multiplier = 2 */ | ||
| 191 | maxdiv = PLL_DIV_MAX; | ||
| 192 | minrate = (parent_rate * 2) / maxdiv; | ||
| 193 | |||
| 194 | if (parent_rate < characteristics->input.min || | 176 | if (parent_rate < characteristics->input.min || |
| 195 | parent_rate < characteristics->input.max) | 177 | parent_rate > characteristics->input.max) |
| 196 | return -ERANGE; | ||
| 197 | |||
| 198 | if (parent_rate < minrate || parent_rate > maxrate) | ||
| 199 | return -ERANGE; | 178 | return -ERANGE; |
| 200 | 179 | ||
| 201 | for (i = 0; i < characteristics->num_output; i++) { | 180 | /* |
| 202 | if (parent_rate >= characteristics->output[i].min && | 181 | * Calculate minimum divider based on the minimum multiplier, the |
| 203 | parent_rate <= characteristics->output[i].max) | 182 | * parent_rate and the requested rate. |
| 204 | break; | 183 | * Should always be 2 according to the input and output characteristics |
| 205 | } | 184 | * of the PLL blocks. |
| 206 | 185 | */ | |
| 207 | if (i >= characteristics->num_output) | 186 | mindiv = (parent_rate * PLL_MUL_MIN) / rate; |
| 208 | return -ERANGE; | 187 | if (!mindiv) |
| 209 | 188 | mindiv = 1; | |
| 210 | bestmul = rate / parent_rate; | 189 | |
| 211 | rounddown = parent_rate % rate; | 190 | /* |
| 212 | roundup = rate - rounddown; | 191 | * Calculate the maximum divider which is limited by PLL register |
| 213 | bestremainder = roundup < rounddown ? roundup : rounddown; | 192 | * layout (limited by the MUL or DIV field size). |
| 214 | 193 | */ | |
| 215 | if (!bestremainder) { | 194 | maxdiv = DIV_ROUND_UP(parent_rate * PLL_MUL_MAX(layout), rate); |
| 216 | if (div) | 195 | if (maxdiv > PLL_DIV_MAX) |
| 217 | *div = bestdiv; | 196 | maxdiv = PLL_DIV_MAX; |
| 218 | if (mul) | 197 | |
| 219 | *mul = bestmul; | 198 | /* |
| 220 | if (index) | 199 | * Iterate over the acceptable divider values to find the best |
| 221 | *index = i; | 200 | * divider/multiplier pair (the one that generates the closest |
| 222 | return rate; | 201 | * rate to the requested one). |
| 223 | } | 202 | */ |
| 224 | 203 | for (tmpdiv = mindiv; tmpdiv <= maxdiv; tmpdiv++) { | |
| 225 | maxdiv = 255 / (bestmul + 1); | 204 | unsigned long remainder; |
| 226 | if (parent_rate / maxdiv < characteristics->input.min) | 205 | unsigned long tmprate; |
| 227 | maxdiv = parent_rate / characteristics->input.min; | 206 | unsigned long tmpmul; |
| 228 | mindiv = parent_rate / characteristics->input.max; | 207 | |
| 229 | if (parent_rate % characteristics->input.max) | 208 | /* |
| 230 | mindiv++; | 209 | * Calculate the multiplier associated with the current |
| 231 | 210 | * divider that provide the closest rate to the requested one. | |
| 232 | for (tmpdiv = mindiv; tmpdiv < maxdiv; tmpdiv++) { | 211 | */ |
| 233 | divrate = parent_rate / tmpdiv; | 212 | tmpmul = DIV_ROUND_CLOSEST(rate, parent_rate / tmpdiv); |
| 234 | 213 | tmprate = (parent_rate / tmpdiv) * tmpmul; | |
| 235 | rounddown = rate % divrate; | 214 | if (tmprate > rate) |
| 236 | roundup = divrate - rounddown; | 215 | remainder = tmprate - rate; |
| 237 | remainder = roundup < rounddown ? roundup : rounddown; | 216 | else |
| 238 | 217 | remainder = rate - tmprate; | |
| 218 | |||
| 219 | /* | ||
| 220 | * Compare the remainder with the best remainder found until | ||
| 221 | * now and elect a new best multiplier/divider pair if the | ||
| 222 | * current remainder is smaller than the best one. | ||
| 223 | */ | ||
| 239 | if (remainder < bestremainder) { | 224 | if (remainder < bestremainder) { |
| 240 | bestremainder = remainder; | 225 | bestremainder = remainder; |
| 241 | bestmul = rate / divrate; | ||
| 242 | bestdiv = tmpdiv; | 226 | bestdiv = tmpdiv; |
| 227 | bestmul = tmpmul; | ||
| 228 | bestrate = tmprate; | ||
| 243 | } | 229 | } |
| 244 | 230 | ||
| 231 | /* | ||
| 232 | * We've found a perfect match! | ||
| 233 | * Stop searching now and use this multiplier/divider pair. | ||
| 234 | */ | ||
| 245 | if (!remainder) | 235 | if (!remainder) |
| 246 | break; | 236 | break; |
| 247 | } | 237 | } |
| 248 | 238 | ||
| 249 | rate = (parent_rate / bestdiv) * bestmul; | 239 | /* We haven't found any multiplier/divider pair => return -ERANGE */ |
| 240 | if (bestrate < 0) | ||
| 241 | return bestrate; | ||
| 242 | |||
| 243 | /* Check if bestrate is a valid output rate */ | ||
| 244 | for (i = 0; i < characteristics->num_output; i++) { | ||
| 245 | if (bestrate >= characteristics->output[i].min && | ||
| 246 | bestrate <= characteristics->output[i].max) | ||
| 247 | break; | ||
| 248 | } | ||
| 249 | |||
| 250 | if (i >= characteristics->num_output) | ||
| 251 | return -ERANGE; | ||
| 250 | 252 | ||
| 251 | if (div) | 253 | if (div) |
| 252 | *div = bestdiv; | 254 | *div = bestdiv; |
| 253 | if (mul) | 255 | if (mul) |
| 254 | *mul = bestmul; | 256 | *mul = bestmul - 1; |
| 255 | if (index) | 257 | if (index) |
| 256 | *index = i; | 258 | *index = i; |
| 257 | 259 | ||
| 258 | return rate; | 260 | return bestrate; |
| 259 | } | 261 | } |
| 260 | 262 | ||
| 261 | static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, | 263 | static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, |
diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index 7d1d26a4bd04..24b5b020753a 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c | |||
| @@ -238,16 +238,22 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, | |||
| 238 | unsigned long *parent_rate) | 238 | unsigned long *parent_rate) |
| 239 | { | 239 | { |
| 240 | struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); | 240 | struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); |
| 241 | struct clk *parent = __clk_get_parent(hw->clk); | ||
| 241 | unsigned long bestrate = 0; | 242 | unsigned long bestrate = 0; |
| 242 | int bestdiff = -1; | 243 | int bestdiff = -1; |
| 243 | unsigned long tmprate; | 244 | unsigned long tmprate; |
| 244 | int tmpdiff; | 245 | int tmpdiff; |
| 245 | int i = 0; | 246 | int i = 0; |
| 246 | 247 | ||
| 247 | for (i = 0; i < 4; i++) { | 248 | for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) { |
| 249 | unsigned long tmp_parent_rate; | ||
| 250 | |||
| 248 | if (!usb->divisors[i]) | 251 | if (!usb->divisors[i]) |
| 249 | continue; | 252 | continue; |
| 250 | tmprate = *parent_rate / usb->divisors[i]; | 253 | |
| 254 | tmp_parent_rate = rate * usb->divisors[i]; | ||
| 255 | tmp_parent_rate = __clk_round_rate(parent, tmp_parent_rate); | ||
| 256 | tmprate = tmp_parent_rate / usb->divisors[i]; | ||
| 251 | if (tmprate < rate) | 257 | if (tmprate < rate) |
| 252 | tmpdiff = rate - tmprate; | 258 | tmpdiff = rate - tmprate; |
| 253 | else | 259 | else |
| @@ -256,6 +262,7 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, | |||
| 256 | if (bestdiff < 0 || bestdiff > tmpdiff) { | 262 | if (bestdiff < 0 || bestdiff > tmpdiff) { |
| 257 | bestrate = tmprate; | 263 | bestrate = tmprate; |
| 258 | bestdiff = tmpdiff; | 264 | bestdiff = tmpdiff; |
| 265 | *parent_rate = tmp_parent_rate; | ||
| 259 | } | 266 | } |
| 260 | 267 | ||
| 261 | if (!bestdiff) | 268 | if (!bestdiff) |
| @@ -272,10 +279,13 @@ static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, | |||
| 272 | int i; | 279 | int i; |
| 273 | struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); | 280 | struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); |
| 274 | struct at91_pmc *pmc = usb->pmc; | 281 | struct at91_pmc *pmc = usb->pmc; |
| 275 | unsigned long div = parent_rate / rate; | 282 | unsigned long div; |
| 276 | 283 | ||
| 277 | if (parent_rate % rate) | 284 | if (!rate || parent_rate % rate) |
| 278 | return -EINVAL; | 285 | return -EINVAL; |
| 286 | |||
| 287 | div = parent_rate / rate; | ||
| 288 | |||
| 279 | for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) { | 289 | for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) { |
| 280 | if (usb->divisors[i] == div) { | 290 | if (usb->divisors[i] == div) { |
| 281 | tmp = pmc_read(pmc, AT91_CKGR_PLLBR) & | 291 | tmp = pmc_read(pmc, AT91_CKGR_PLLBR) & |
| @@ -311,7 +321,7 @@ at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name, | |||
| 311 | init.ops = &at91rm9200_usb_ops; | 321 | init.ops = &at91rm9200_usb_ops; |
| 312 | init.parent_names = &parent_name; | 322 | init.parent_names = &parent_name; |
| 313 | init.num_parents = 1; | 323 | init.num_parents = 1; |
| 314 | init.flags = 0; | 324 | init.flags = CLK_SET_RATE_PARENT; |
| 315 | 325 | ||
| 316 | usb->hw.init = &init; | 326 | usb->hw.init = &init; |
| 317 | usb->pmc = pmc; | 327 | usb->pmc = pmc; |
diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c index 1127ee46b802..e619285c6def 100644 --- a/drivers/clk/clk-axi-clkgen.c +++ b/drivers/clk/clk-axi-clkgen.c | |||
| @@ -544,7 +544,6 @@ static int axi_clkgen_remove(struct platform_device *pdev) | |||
| 544 | static struct platform_driver axi_clkgen_driver = { | 544 | static struct platform_driver axi_clkgen_driver = { |
| 545 | .driver = { | 545 | .driver = { |
| 546 | .name = "adi-axi-clkgen", | 546 | .name = "adi-axi-clkgen", |
| 547 | .owner = THIS_MODULE, | ||
| 548 | .of_match_table = axi_clkgen_ids, | 547 | .of_match_table = axi_clkgen_ids, |
| 549 | }, | 548 | }, |
| 550 | .probe = axi_clkgen_probe, | 549 | .probe = axi_clkgen_probe, |
diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index ede685ca0d20..82a59d0086cc 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c | |||
| @@ -36,7 +36,7 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw, | |||
| 36 | m = (val & fd->mmask) >> fd->mshift; | 36 | m = (val & fd->mmask) >> fd->mshift; |
| 37 | n = (val & fd->nmask) >> fd->nshift; | 37 | n = (val & fd->nmask) >> fd->nshift; |
| 38 | 38 | ||
| 39 | ret = parent_rate * m; | 39 | ret = (u64)parent_rate * m; |
| 40 | do_div(ret, n); | 40 | do_div(ret, n); |
| 41 | 41 | ||
| 42 | return ret; | 42 | return ret; |
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c index 4a58c55255bd..51fd87fb7ba6 100644 --- a/drivers/clk/clk-gate.c +++ b/drivers/clk/clk-gate.c | |||
| @@ -45,7 +45,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable) | |||
| 45 | { | 45 | { |
| 46 | struct clk_gate *gate = to_clk_gate(hw); | 46 | struct clk_gate *gate = to_clk_gate(hw); |
| 47 | int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0; | 47 | int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0; |
| 48 | unsigned long flags = 0; | 48 | unsigned long uninitialized_var(flags); |
| 49 | u32 reg; | 49 | u32 reg; |
| 50 | 50 | ||
| 51 | set ^= enable; | 51 | set ^= enable; |
diff --git a/drivers/clk/clk-gpio-gate.c b/drivers/clk/clk-gpio-gate.c new file mode 100644 index 000000000000..08e43224fd52 --- /dev/null +++ b/drivers/clk/clk-gpio-gate.c | |||
| @@ -0,0 +1,205 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2013 - 2014 Texas Instruments Incorporated - http://www.ti.com | ||
| 3 | * Author: Jyri Sarha <jsarha@ti.com> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License version 2 as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * Gpio gated clock implementation | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/clk-provider.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/slab.h> | ||
| 15 | #include <linux/gpio.h> | ||
| 16 | #include <linux/gpio/consumer.h> | ||
| 17 | #include <linux/of_gpio.h> | ||
| 18 | #include <linux/err.h> | ||
| 19 | #include <linux/device.h> | ||
| 20 | |||
| 21 | /** | ||
| 22 | * DOC: basic gpio gated clock which can be enabled and disabled | ||
| 23 | * with gpio output | ||
| 24 | * Traits of this clock: | ||
| 25 | * prepare - clk_(un)prepare only ensures parent is (un)prepared | ||
| 26 | * enable - clk_enable and clk_disable are functional & control gpio | ||
| 27 | * rate - inherits rate from parent. No clk_set_rate support | ||
| 28 | * parent - fixed parent. No clk_set_parent support | ||
| 29 | */ | ||
| 30 | |||
| 31 | #define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw) | ||
| 32 | |||
| 33 | static int clk_gpio_gate_enable(struct clk_hw *hw) | ||
| 34 | { | ||
| 35 | struct clk_gpio *clk = to_clk_gpio(hw); | ||
| 36 | |||
| 37 | gpiod_set_value(clk->gpiod, 1); | ||
| 38 | |||
| 39 | return 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | static void clk_gpio_gate_disable(struct clk_hw *hw) | ||
| 43 | { | ||
| 44 | struct clk_gpio *clk = to_clk_gpio(hw); | ||
| 45 | |||
| 46 | gpiod_set_value(clk->gpiod, 0); | ||
| 47 | } | ||
| 48 | |||
| 49 | static int clk_gpio_gate_is_enabled(struct clk_hw *hw) | ||
| 50 | { | ||
| 51 | struct clk_gpio *clk = to_clk_gpio(hw); | ||
| 52 | |||
| 53 | return gpiod_get_value(clk->gpiod); | ||
| 54 | } | ||
| 55 | |||
| 56 | const struct clk_ops clk_gpio_gate_ops = { | ||
| 57 | .enable = clk_gpio_gate_enable, | ||
| 58 | .disable = clk_gpio_gate_disable, | ||
| 59 | .is_enabled = clk_gpio_gate_is_enabled, | ||
| 60 | }; | ||
| 61 | EXPORT_SYMBOL_GPL(clk_gpio_gate_ops); | ||
| 62 | |||
| 63 | /** | ||
| 64 | * clk_register_gpio - register a gpip clock with the clock framework | ||
| 65 | * @dev: device that is registering this clock | ||
| 66 | * @name: name of this clock | ||
| 67 | * @parent_name: name of this clock's parent | ||
| 68 | * @gpiod: gpio descriptor to gate this clock | ||
| 69 | */ | ||
| 70 | struct clk *clk_register_gpio_gate(struct device *dev, const char *name, | ||
| 71 | const char *parent_name, struct gpio_desc *gpiod, | ||
| 72 | unsigned long flags) | ||
| 73 | { | ||
| 74 | struct clk_gpio *clk_gpio = NULL; | ||
| 75 | struct clk *clk = ERR_PTR(-EINVAL); | ||
| 76 | struct clk_init_data init = { NULL }; | ||
| 77 | unsigned long gpio_flags; | ||
| 78 | int err; | ||
| 79 | |||
| 80 | if (gpiod_is_active_low(gpiod)) | ||
| 81 | gpio_flags = GPIOF_OUT_INIT_HIGH; | ||
| 82 | else | ||
| 83 | gpio_flags = GPIOF_OUT_INIT_LOW; | ||
| 84 | |||
| 85 | if (dev) | ||
| 86 | err = devm_gpio_request_one(dev, desc_to_gpio(gpiod), | ||
| 87 | gpio_flags, name); | ||
| 88 | else | ||
| 89 | err = gpio_request_one(desc_to_gpio(gpiod), gpio_flags, name); | ||
| 90 | |||
| 91 | if (err) { | ||
| 92 | pr_err("%s: %s: Error requesting clock control gpio %u\n", | ||
| 93 | __func__, name, desc_to_gpio(gpiod)); | ||
| 94 | return ERR_PTR(err); | ||
| 95 | } | ||
| 96 | |||
| 97 | if (dev) | ||
| 98 | clk_gpio = devm_kzalloc(dev, sizeof(struct clk_gpio), | ||
| 99 | GFP_KERNEL); | ||
| 100 | else | ||
| 101 | clk_gpio = kzalloc(sizeof(struct clk_gpio), GFP_KERNEL); | ||
| 102 | |||
| 103 | if (!clk_gpio) { | ||
| 104 | clk = ERR_PTR(-ENOMEM); | ||
| 105 | goto clk_register_gpio_gate_err; | ||
| 106 | } | ||
| 107 | |||
| 108 | init.name = name; | ||
| 109 | init.ops = &clk_gpio_gate_ops; | ||
| 110 | init.flags = flags | CLK_IS_BASIC; | ||
| 111 | init.parent_names = (parent_name ? &parent_name : NULL); | ||
| 112 | init.num_parents = (parent_name ? 1 : 0); | ||
| 113 | |||
| 114 | clk_gpio->gpiod = gpiod; | ||
| 115 | clk_gpio->hw.init = &init; | ||
| 116 | |||
| 117 | clk = clk_register(dev, &clk_gpio->hw); | ||
| 118 | |||
| 119 | if (!IS_ERR(clk)) | ||
| 120 | return clk; | ||
| 121 | |||
| 122 | if (!dev) | ||
| 123 | kfree(clk_gpio); | ||
| 124 | |||
| 125 | clk_register_gpio_gate_err: | ||
| 126 | gpiod_put(gpiod); | ||
| 127 | |||
| 128 | return clk; | ||
| 129 | } | ||
| 130 | EXPORT_SYMBOL_GPL(clk_register_gpio_gate); | ||
| 131 | |||
| 132 | #ifdef CONFIG_OF | ||
| 133 | /** | ||
| 134 | * The clk_register_gpio_gate has to be delayed, because the EPROBE_DEFER | ||
| 135 | * can not be handled properly at of_clk_init() call time. | ||
| 136 | */ | ||
| 137 | |||
| 138 | struct clk_gpio_gate_delayed_register_data { | ||
| 139 | struct device_node *node; | ||
| 140 | struct mutex lock; | ||
| 141 | struct clk *clk; | ||
| 142 | }; | ||
| 143 | |||
| 144 | static struct clk *of_clk_gpio_gate_delayed_register_get( | ||
| 145 | struct of_phandle_args *clkspec, | ||
| 146 | void *_data) | ||
| 147 | { | ||
| 148 | struct clk_gpio_gate_delayed_register_data *data = _data; | ||
| 149 | struct clk *clk; | ||
| 150 | const char *clk_name = data->node->name; | ||
| 151 | const char *parent_name; | ||
| 152 | struct gpio_desc *gpiod; | ||
| 153 | int gpio; | ||
| 154 | |||
| 155 | mutex_lock(&data->lock); | ||
| 156 | |||
| 157 | if (data->clk) { | ||
| 158 | mutex_unlock(&data->lock); | ||
| 159 | return data->clk; | ||
| 160 | } | ||
| 161 | |||
| 162 | gpio = of_get_named_gpio_flags(data->node, "enable-gpios", 0, NULL); | ||
| 163 | if (gpio < 0) { | ||
| 164 | mutex_unlock(&data->lock); | ||
| 165 | if (gpio != -EPROBE_DEFER) | ||
| 166 | pr_err("%s: %s: Can't get 'enable-gpios' DT property\n", | ||
| 167 | __func__, clk_name); | ||
| 168 | return ERR_PTR(gpio); | ||
| 169 | } | ||
| 170 | gpiod = gpio_to_desc(gpio); | ||
| 171 | |||
| 172 | parent_name = of_clk_get_parent_name(data->node, 0); | ||
| 173 | |||
| 174 | clk = clk_register_gpio_gate(NULL, clk_name, parent_name, gpiod, 0); | ||
| 175 | if (IS_ERR(clk)) { | ||
| 176 | mutex_unlock(&data->lock); | ||
| 177 | return clk; | ||
| 178 | } | ||
| 179 | |||
| 180 | data->clk = clk; | ||
| 181 | mutex_unlock(&data->lock); | ||
| 182 | |||
| 183 | return clk; | ||
| 184 | } | ||
| 185 | |||
| 186 | /** | ||
| 187 | * of_gpio_gate_clk_setup() - Setup function for gpio controlled clock | ||
| 188 | */ | ||
| 189 | void __init of_gpio_gate_clk_setup(struct device_node *node) | ||
| 190 | { | ||
| 191 | struct clk_gpio_gate_delayed_register_data *data; | ||
| 192 | |||
| 193 | data = kzalloc(sizeof(struct clk_gpio_gate_delayed_register_data), | ||
| 194 | GFP_KERNEL); | ||
| 195 | if (!data) | ||
| 196 | return; | ||
| 197 | |||
| 198 | data->node = node; | ||
| 199 | mutex_init(&data->lock); | ||
| 200 | |||
| 201 | of_clk_add_provider(node, of_clk_gpio_gate_delayed_register_get, data); | ||
| 202 | } | ||
| 203 | EXPORT_SYMBOL_GPL(of_gpio_gate_clk_setup); | ||
| 204 | CLK_OF_DECLARE(gpio_gate_clk, "gpio-gate-clock", of_gpio_gate_clk_setup); | ||
| 205 | #endif | ||
diff --git a/drivers/clk/clk-max-gen.c b/drivers/clk/clk-max-gen.c new file mode 100644 index 000000000000..6505049d50f1 --- /dev/null +++ b/drivers/clk/clk-max-gen.c | |||
| @@ -0,0 +1,192 @@ | |||
| 1 | /* | ||
| 2 | * clk-max-gen.c - Generic clock driver for Maxim PMICs clocks | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Google, Inc | ||
| 5 | * | ||
| 6 | * Copyright (C) 2012 Samsung Electornics | ||
| 7 | * Jonghwa Lee <jonghwa3.lee@samsung.com> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify it | ||
| 10 | * under the terms of the GNU General Public License as published by the | ||
| 11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 12 | * option) any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * This driver is based on clk-max77686.c | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/kernel.h> | ||
| 24 | #include <linux/slab.h> | ||
| 25 | #include <linux/err.h> | ||
| 26 | #include <linux/regmap.h> | ||
| 27 | #include <linux/platform_device.h> | ||
| 28 | #include <linux/clk-provider.h> | ||
| 29 | #include <linux/mutex.h> | ||
| 30 | #include <linux/clkdev.h> | ||
| 31 | #include <linux/of.h> | ||
| 32 | #include <linux/export.h> | ||
| 33 | |||
| 34 | struct max_gen_clk { | ||
| 35 | struct regmap *regmap; | ||
| 36 | u32 mask; | ||
| 37 | u32 reg; | ||
| 38 | struct clk_hw hw; | ||
| 39 | }; | ||
| 40 | |||
| 41 | static struct max_gen_clk *to_max_gen_clk(struct clk_hw *hw) | ||
| 42 | { | ||
| 43 | return container_of(hw, struct max_gen_clk, hw); | ||
| 44 | } | ||
| 45 | |||
| 46 | static int max_gen_clk_prepare(struct clk_hw *hw) | ||
| 47 | { | ||
| 48 | struct max_gen_clk *max_gen = to_max_gen_clk(hw); | ||
| 49 | |||
| 50 | return regmap_update_bits(max_gen->regmap, max_gen->reg, | ||
| 51 | max_gen->mask, max_gen->mask); | ||
| 52 | } | ||
| 53 | |||
| 54 | static void max_gen_clk_unprepare(struct clk_hw *hw) | ||
| 55 | { | ||
| 56 | struct max_gen_clk *max_gen = to_max_gen_clk(hw); | ||
| 57 | |||
| 58 | regmap_update_bits(max_gen->regmap, max_gen->reg, | ||
| 59 | max_gen->mask, ~max_gen->mask); | ||
| 60 | } | ||
| 61 | |||
| 62 | static int max_gen_clk_is_prepared(struct clk_hw *hw) | ||
| 63 | { | ||
| 64 | struct max_gen_clk *max_gen = to_max_gen_clk(hw); | ||
| 65 | int ret; | ||
| 66 | u32 val; | ||
| 67 | |||
| 68 | ret = regmap_read(max_gen->regmap, max_gen->reg, &val); | ||
| 69 | |||
| 70 | if (ret < 0) | ||
| 71 | return -EINVAL; | ||
| 72 | |||
| 73 | return val & max_gen->mask; | ||
| 74 | } | ||
| 75 | |||
| 76 | static unsigned long max_gen_recalc_rate(struct clk_hw *hw, | ||
| 77 | unsigned long parent_rate) | ||
| 78 | { | ||
| 79 | return 32768; | ||
| 80 | } | ||
| 81 | |||
| 82 | struct clk_ops max_gen_clk_ops = { | ||
| 83 | .prepare = max_gen_clk_prepare, | ||
| 84 | .unprepare = max_gen_clk_unprepare, | ||
| 85 | .is_prepared = max_gen_clk_is_prepared, | ||
| 86 | .recalc_rate = max_gen_recalc_rate, | ||
| 87 | }; | ||
| 88 | EXPORT_SYMBOL_GPL(max_gen_clk_ops); | ||
| 89 | |||
| 90 | static struct clk *max_gen_clk_register(struct device *dev, | ||
| 91 | struct max_gen_clk *max_gen) | ||
| 92 | { | ||
| 93 | struct clk *clk; | ||
| 94 | struct clk_hw *hw = &max_gen->hw; | ||
| 95 | int ret; | ||
| 96 | |||
| 97 | clk = devm_clk_register(dev, hw); | ||
| 98 | if (IS_ERR(clk)) | ||
| 99 | return clk; | ||
| 100 | |||
| 101 | ret = clk_register_clkdev(clk, hw->init->name, NULL); | ||
| 102 | |||
| 103 | if (ret) | ||
| 104 | return ERR_PTR(ret); | ||
| 105 | |||
| 106 | return clk; | ||
| 107 | } | ||
| 108 | |||
| 109 | int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap, | ||
| 110 | u32 reg, struct clk_init_data *clks_init, int num_init) | ||
| 111 | { | ||
| 112 | int i, ret; | ||
| 113 | struct max_gen_clk *max_gen_clks; | ||
| 114 | struct clk **clocks; | ||
| 115 | struct device *dev = pdev->dev.parent; | ||
| 116 | const char *clk_name; | ||
| 117 | struct clk_init_data *init; | ||
| 118 | |||
| 119 | clocks = devm_kzalloc(dev, sizeof(struct clk *) * num_init, GFP_KERNEL); | ||
| 120 | if (!clocks) | ||
| 121 | return -ENOMEM; | ||
| 122 | |||
| 123 | max_gen_clks = devm_kzalloc(dev, sizeof(struct max_gen_clk) | ||
| 124 | * num_init, GFP_KERNEL); | ||
| 125 | if (!max_gen_clks) | ||
| 126 | return -ENOMEM; | ||
| 127 | |||
| 128 | for (i = 0; i < num_init; i++) { | ||
| 129 | max_gen_clks[i].regmap = regmap; | ||
| 130 | max_gen_clks[i].mask = 1 << i; | ||
| 131 | max_gen_clks[i].reg = reg; | ||
| 132 | |||
| 133 | init = devm_kzalloc(dev, sizeof(*init), GFP_KERNEL); | ||
| 134 | if (!init) | ||
| 135 | return -ENOMEM; | ||
| 136 | |||
| 137 | if (dev->of_node && | ||
| 138 | !of_property_read_string_index(dev->of_node, | ||
| 139 | "clock-output-names", | ||
| 140 | i, &clk_name)) | ||
| 141 | init->name = clk_name; | ||
| 142 | else | ||
| 143 | init->name = clks_init[i].name; | ||
| 144 | |||
| 145 | init->ops = clks_init[i].ops; | ||
| 146 | init->flags = clks_init[i].flags; | ||
| 147 | |||
| 148 | max_gen_clks[i].hw.init = init; | ||
| 149 | |||
| 150 | clocks[i] = max_gen_clk_register(dev, &max_gen_clks[i]); | ||
| 151 | if (IS_ERR(clocks[i])) { | ||
| 152 | ret = PTR_ERR(clocks[i]); | ||
| 153 | dev_err(dev, "failed to register %s\n", | ||
| 154 | max_gen_clks[i].hw.init->name); | ||
| 155 | return ret; | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | platform_set_drvdata(pdev, clocks); | ||
| 160 | |||
| 161 | if (dev->of_node) { | ||
| 162 | struct clk_onecell_data *of_data; | ||
| 163 | |||
| 164 | of_data = devm_kzalloc(dev, sizeof(*of_data), GFP_KERNEL); | ||
| 165 | if (!of_data) | ||
| 166 | return -ENOMEM; | ||
| 167 | |||
| 168 | of_data->clks = clocks; | ||
| 169 | of_data->clk_num = num_init; | ||
| 170 | ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, | ||
| 171 | of_data); | ||
| 172 | |||
| 173 | if (ret) { | ||
| 174 | dev_err(dev, "failed to register OF clock provider\n"); | ||
| 175 | return ret; | ||
| 176 | } | ||
| 177 | } | ||
| 178 | |||
| 179 | return 0; | ||
| 180 | } | ||
| 181 | EXPORT_SYMBOL_GPL(max_gen_clk_probe); | ||
| 182 | |||
| 183 | int max_gen_clk_remove(struct platform_device *pdev, int num_init) | ||
| 184 | { | ||
| 185 | struct device *dev = pdev->dev.parent; | ||
| 186 | |||
| 187 | if (dev->of_node) | ||
| 188 | of_clk_del_provider(dev->of_node); | ||
| 189 | |||
| 190 | return 0; | ||
| 191 | } | ||
| 192 | EXPORT_SYMBOL_GPL(max_gen_clk_remove); | ||
diff --git a/drivers/clk/clk-max-gen.h b/drivers/clk/clk-max-gen.h new file mode 100644 index 000000000000..997e86fc3f4d --- /dev/null +++ b/drivers/clk/clk-max-gen.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | /* | ||
| 2 | * clk-max-gen.h - Generic clock driver for Maxim PMICs clocks | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Google, Inc | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms of the GNU General Public License as published by the | ||
| 8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 9 | * option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #ifndef __CLK_MAX_GEN_H__ | ||
| 19 | #define __CLK_MAX_GEN_H__ | ||
| 20 | |||
| 21 | #include <linux/types.h> | ||
| 22 | #include <linux/device.h> | ||
| 23 | #include <linux/clkdev.h> | ||
| 24 | #include <linux/regmap.h> | ||
| 25 | #include <linux/platform_device.h> | ||
| 26 | |||
| 27 | int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap, | ||
| 28 | u32 reg, struct clk_init_data *clks_init, int num_init); | ||
| 29 | int max_gen_clk_remove(struct platform_device *pdev, int num_init); | ||
| 30 | extern struct clk_ops max_gen_clk_ops; | ||
| 31 | |||
| 32 | #endif /* __CLK_MAX_GEN_H__ */ | ||
diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c index 3d7e8dd8fd58..86cdb3a28629 100644 --- a/drivers/clk/clk-max77686.c +++ b/drivers/clk/clk-max77686.c | |||
| @@ -30,193 +30,38 @@ | |||
| 30 | #include <linux/mutex.h> | 30 | #include <linux/mutex.h> |
| 31 | #include <linux/clkdev.h> | 31 | #include <linux/clkdev.h> |
| 32 | 32 | ||
| 33 | enum { | 33 | #include <dt-bindings/clock/maxim,max77686.h> |
| 34 | MAX77686_CLK_AP = 0, | 34 | #include "clk-max-gen.h" |
| 35 | MAX77686_CLK_CP, | ||
| 36 | MAX77686_CLK_PMIC, | ||
| 37 | MAX77686_CLKS_NUM, | ||
| 38 | }; | ||
| 39 | |||
| 40 | struct max77686_clk { | ||
| 41 | struct max77686_dev *iodev; | ||
| 42 | u32 mask; | ||
| 43 | struct clk_hw hw; | ||
| 44 | struct clk_lookup *lookup; | ||
| 45 | }; | ||
| 46 | |||
| 47 | static struct max77686_clk *to_max77686_clk(struct clk_hw *hw) | ||
| 48 | { | ||
| 49 | return container_of(hw, struct max77686_clk, hw); | ||
| 50 | } | ||
| 51 | |||
| 52 | static int max77686_clk_prepare(struct clk_hw *hw) | ||
| 53 | { | ||
| 54 | struct max77686_clk *max77686 = to_max77686_clk(hw); | ||
| 55 | |||
| 56 | return regmap_update_bits(max77686->iodev->regmap, | ||
| 57 | MAX77686_REG_32KHZ, max77686->mask, | ||
| 58 | max77686->mask); | ||
| 59 | } | ||
| 60 | |||
| 61 | static void max77686_clk_unprepare(struct clk_hw *hw) | ||
| 62 | { | ||
| 63 | struct max77686_clk *max77686 = to_max77686_clk(hw); | ||
| 64 | |||
| 65 | regmap_update_bits(max77686->iodev->regmap, | ||
| 66 | MAX77686_REG_32KHZ, max77686->mask, ~max77686->mask); | ||
| 67 | } | ||
| 68 | |||
| 69 | static int max77686_clk_is_prepared(struct clk_hw *hw) | ||
| 70 | { | ||
| 71 | struct max77686_clk *max77686 = to_max77686_clk(hw); | ||
| 72 | int ret; | ||
| 73 | u32 val; | ||
| 74 | |||
| 75 | ret = regmap_read(max77686->iodev->regmap, | ||
| 76 | MAX77686_REG_32KHZ, &val); | ||
| 77 | |||
| 78 | if (ret < 0) | ||
| 79 | return -EINVAL; | ||
| 80 | |||
| 81 | return val & max77686->mask; | ||
| 82 | } | ||
| 83 | |||
| 84 | static unsigned long max77686_recalc_rate(struct clk_hw *hw, | ||
| 85 | unsigned long parent_rate) | ||
| 86 | { | ||
| 87 | return 32768; | ||
| 88 | } | ||
| 89 | |||
| 90 | static struct clk_ops max77686_clk_ops = { | ||
| 91 | .prepare = max77686_clk_prepare, | ||
| 92 | .unprepare = max77686_clk_unprepare, | ||
| 93 | .is_prepared = max77686_clk_is_prepared, | ||
| 94 | .recalc_rate = max77686_recalc_rate, | ||
| 95 | }; | ||
| 96 | 35 | ||
| 97 | static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = { | 36 | static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = { |
| 98 | [MAX77686_CLK_AP] = { | 37 | [MAX77686_CLK_AP] = { |
| 99 | .name = "32khz_ap", | 38 | .name = "32khz_ap", |
| 100 | .ops = &max77686_clk_ops, | 39 | .ops = &max_gen_clk_ops, |
| 101 | .flags = CLK_IS_ROOT, | 40 | .flags = CLK_IS_ROOT, |
| 102 | }, | 41 | }, |
| 103 | [MAX77686_CLK_CP] = { | 42 | [MAX77686_CLK_CP] = { |
| 104 | .name = "32khz_cp", | 43 | .name = "32khz_cp", |
| 105 | .ops = &max77686_clk_ops, | 44 | .ops = &max_gen_clk_ops, |
| 106 | .flags = CLK_IS_ROOT, | 45 | .flags = CLK_IS_ROOT, |
| 107 | }, | 46 | }, |
| 108 | [MAX77686_CLK_PMIC] = { | 47 | [MAX77686_CLK_PMIC] = { |
| 109 | .name = "32khz_pmic", | 48 | .name = "32khz_pmic", |
| 110 | .ops = &max77686_clk_ops, | 49 | .ops = &max_gen_clk_ops, |
| 111 | .flags = CLK_IS_ROOT, | 50 | .flags = CLK_IS_ROOT, |
| 112 | }, | 51 | }, |
| 113 | }; | 52 | }; |
| 114 | 53 | ||
| 115 | static struct clk *max77686_clk_register(struct device *dev, | ||
| 116 | struct max77686_clk *max77686) | ||
| 117 | { | ||
| 118 | struct clk *clk; | ||
| 119 | struct clk_hw *hw = &max77686->hw; | ||
| 120 | |||
| 121 | clk = clk_register(dev, hw); | ||
| 122 | if (IS_ERR(clk)) | ||
| 123 | return clk; | ||
| 124 | |||
| 125 | max77686->lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL); | ||
| 126 | if (!max77686->lookup) | ||
| 127 | return ERR_PTR(-ENOMEM); | ||
| 128 | |||
| 129 | max77686->lookup->con_id = hw->init->name; | ||
| 130 | max77686->lookup->clk = clk; | ||
| 131 | |||
| 132 | clkdev_add(max77686->lookup); | ||
| 133 | |||
| 134 | return clk; | ||
| 135 | } | ||
| 136 | |||
| 137 | static int max77686_clk_probe(struct platform_device *pdev) | 54 | static int max77686_clk_probe(struct platform_device *pdev) |
| 138 | { | 55 | { |
| 139 | struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); | 56 | struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); |
| 140 | struct max77686_clk *max77686_clks[MAX77686_CLKS_NUM]; | ||
| 141 | struct clk **clocks; | ||
| 142 | int i, ret; | ||
| 143 | |||
| 144 | clocks = devm_kzalloc(&pdev->dev, sizeof(struct clk *) | ||
| 145 | * MAX77686_CLKS_NUM, GFP_KERNEL); | ||
| 146 | if (!clocks) | ||
| 147 | return -ENOMEM; | ||
| 148 | |||
| 149 | for (i = 0; i < MAX77686_CLKS_NUM; i++) { | ||
| 150 | max77686_clks[i] = devm_kzalloc(&pdev->dev, | ||
| 151 | sizeof(struct max77686_clk), GFP_KERNEL); | ||
| 152 | if (!max77686_clks[i]) | ||
| 153 | return -ENOMEM; | ||
| 154 | } | ||
| 155 | |||
| 156 | for (i = 0; i < MAX77686_CLKS_NUM; i++) { | ||
| 157 | max77686_clks[i]->iodev = iodev; | ||
| 158 | max77686_clks[i]->mask = 1 << i; | ||
| 159 | max77686_clks[i]->hw.init = &max77686_clks_init[i]; | ||
| 160 | |||
| 161 | clocks[i] = max77686_clk_register(&pdev->dev, max77686_clks[i]); | ||
| 162 | if (IS_ERR(clocks[i])) { | ||
| 163 | ret = PTR_ERR(clocks[i]); | ||
| 164 | dev_err(&pdev->dev, "failed to register %s\n", | ||
| 165 | max77686_clks[i]->hw.init->name); | ||
| 166 | goto err_clocks; | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | platform_set_drvdata(pdev, clocks); | ||
| 171 | |||
| 172 | if (iodev->dev->of_node) { | ||
| 173 | struct clk_onecell_data *of_data; | ||
| 174 | 57 | ||
| 175 | of_data = devm_kzalloc(&pdev->dev, | 58 | return max_gen_clk_probe(pdev, iodev->regmap, MAX77686_REG_32KHZ, |
| 176 | sizeof(*of_data), GFP_KERNEL); | 59 | max77686_clks_init, MAX77686_CLKS_NUM); |
| 177 | if (!of_data) { | ||
| 178 | ret = -ENOMEM; | ||
| 179 | goto err_clocks; | ||
| 180 | } | ||
| 181 | |||
| 182 | of_data->clks = clocks; | ||
| 183 | of_data->clk_num = MAX77686_CLKS_NUM; | ||
| 184 | ret = of_clk_add_provider(iodev->dev->of_node, | ||
| 185 | of_clk_src_onecell_get, of_data); | ||
| 186 | if (ret) { | ||
| 187 | dev_err(&pdev->dev, "failed to register OF clock provider\n"); | ||
| 188 | goto err_clocks; | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | return 0; | ||
| 193 | |||
| 194 | err_clocks: | ||
| 195 | for (--i; i >= 0; --i) { | ||
| 196 | clkdev_drop(max77686_clks[i]->lookup); | ||
| 197 | clk_unregister(max77686_clks[i]->hw.clk); | ||
| 198 | } | ||
| 199 | |||
| 200 | return ret; | ||
| 201 | } | 60 | } |
| 202 | 61 | ||
| 203 | static int max77686_clk_remove(struct platform_device *pdev) | 62 | static int max77686_clk_remove(struct platform_device *pdev) |
| 204 | { | 63 | { |
| 205 | struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); | 64 | return max_gen_clk_remove(pdev, MAX77686_CLKS_NUM); |
| 206 | struct clk **clocks = platform_get_drvdata(pdev); | ||
| 207 | int i; | ||
| 208 | |||
| 209 | if (iodev->dev->of_node) | ||
| 210 | of_clk_del_provider(iodev->dev->of_node); | ||
| 211 | |||
| 212 | for (i = 0; i < MAX77686_CLKS_NUM; i++) { | ||
| 213 | struct clk_hw *hw = __clk_get_hw(clocks[i]); | ||
| 214 | struct max77686_clk *max77686 = to_max77686_clk(hw); | ||
| 215 | |||
| 216 | clkdev_drop(max77686->lookup); | ||
| 217 | clk_unregister(clocks[i]); | ||
| 218 | } | ||
| 219 | return 0; | ||
| 220 | } | 65 | } |
| 221 | 66 | ||
| 222 | static const struct platform_device_id max77686_clk_id[] = { | 67 | static const struct platform_device_id max77686_clk_id[] = { |
| @@ -228,24 +73,13 @@ MODULE_DEVICE_TABLE(platform, max77686_clk_id); | |||
| 228 | static struct platform_driver max77686_clk_driver = { | 73 | static struct platform_driver max77686_clk_driver = { |
| 229 | .driver = { | 74 | .driver = { |
| 230 | .name = "max77686-clk", | 75 | .name = "max77686-clk", |
| 231 | .owner = THIS_MODULE, | ||
| 232 | }, | 76 | }, |
| 233 | .probe = max77686_clk_probe, | 77 | .probe = max77686_clk_probe, |
| 234 | .remove = max77686_clk_remove, | 78 | .remove = max77686_clk_remove, |
| 235 | .id_table = max77686_clk_id, | 79 | .id_table = max77686_clk_id, |
| 236 | }; | 80 | }; |
| 237 | 81 | ||
| 238 | static int __init max77686_clk_init(void) | 82 | module_platform_driver(max77686_clk_driver); |
| 239 | { | ||
| 240 | return platform_driver_register(&max77686_clk_driver); | ||
| 241 | } | ||
| 242 | subsys_initcall(max77686_clk_init); | ||
| 243 | |||
| 244 | static void __init max77686_clk_cleanup(void) | ||
| 245 | { | ||
| 246 | platform_driver_unregister(&max77686_clk_driver); | ||
| 247 | } | ||
| 248 | module_exit(max77686_clk_cleanup); | ||
| 249 | 83 | ||
| 250 | MODULE_DESCRIPTION("MAXIM 77686 Clock Driver"); | 84 | MODULE_DESCRIPTION("MAXIM 77686 Clock Driver"); |
| 251 | MODULE_AUTHOR("Jonghwa Lee <jonghwa3.lee@samsung.com>"); | 85 | MODULE_AUTHOR("Jonghwa Lee <jonghwa3.lee@samsung.com>"); |
diff --git a/drivers/clk/clk-max77802.c b/drivers/clk/clk-max77802.c new file mode 100644 index 000000000000..0729dc723a8f --- /dev/null +++ b/drivers/clk/clk-max77802.c | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | /* | ||
| 2 | * clk-max77802.c - Clock driver for Maxim 77802 | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Google, Inc | ||
| 5 | * | ||
| 6 | * Copyright (C) 2012 Samsung Electornics | ||
| 7 | * Jonghwa Lee <jonghwa3.lee@samsung.com> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify it | ||
| 10 | * under the terms of the GNU General Public License as published by the | ||
| 11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 12 | * option) any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * This driver is based on clk-max77686.c | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <linux/kernel.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | #include <linux/err.h> | ||
| 25 | #include <linux/platform_device.h> | ||
| 26 | #include <linux/mfd/max77686-private.h> | ||
| 27 | #include <linux/clk-provider.h> | ||
| 28 | #include <linux/mutex.h> | ||
| 29 | #include <linux/clkdev.h> | ||
| 30 | |||
| 31 | #include <dt-bindings/clock/maxim,max77802.h> | ||
| 32 | #include "clk-max-gen.h" | ||
| 33 | |||
| 34 | #define MAX77802_CLOCK_OPMODE_MASK 0x1 | ||
| 35 | #define MAX77802_CLOCK_LOW_JITTER_SHIFT 0x3 | ||
| 36 | |||
| 37 | static struct clk_init_data max77802_clks_init[MAX77802_CLKS_NUM] = { | ||
| 38 | [MAX77802_CLK_32K_AP] = { | ||
| 39 | .name = "32khz_ap", | ||
| 40 | .ops = &max_gen_clk_ops, | ||
| 41 | .flags = CLK_IS_ROOT, | ||
| 42 | }, | ||
| 43 | [MAX77802_CLK_32K_CP] = { | ||
| 44 | .name = "32khz_cp", | ||
| 45 | .ops = &max_gen_clk_ops, | ||
| 46 | .flags = CLK_IS_ROOT, | ||
| 47 | }, | ||
| 48 | }; | ||
| 49 | |||
| 50 | static int max77802_clk_probe(struct platform_device *pdev) | ||
| 51 | { | ||
| 52 | struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); | ||
| 53 | int ret; | ||
| 54 | |||
| 55 | ret = max_gen_clk_probe(pdev, iodev->regmap, MAX77802_REG_32KHZ, | ||
| 56 | max77802_clks_init, MAX77802_CLKS_NUM); | ||
| 57 | |||
| 58 | if (ret) { | ||
| 59 | dev_err(&pdev->dev, "generic probe failed %d\n", ret); | ||
| 60 | return ret; | ||
| 61 | } | ||
| 62 | |||
| 63 | /* Enable low-jitter mode on the 32khz clocks. */ | ||
| 64 | ret = regmap_update_bits(iodev->regmap, MAX77802_REG_32KHZ, | ||
| 65 | 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT, | ||
| 66 | 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT); | ||
| 67 | if (ret < 0) | ||
| 68 | dev_err(&pdev->dev, "failed to enable low-jitter mode\n"); | ||
| 69 | |||
| 70 | return ret; | ||
| 71 | } | ||
| 72 | |||
| 73 | static int max77802_clk_remove(struct platform_device *pdev) | ||
| 74 | { | ||
| 75 | return max_gen_clk_remove(pdev, MAX77802_CLKS_NUM); | ||
| 76 | } | ||
| 77 | |||
| 78 | static const struct platform_device_id max77802_clk_id[] = { | ||
| 79 | { "max77802-clk", 0}, | ||
| 80 | { }, | ||
| 81 | }; | ||
| 82 | MODULE_DEVICE_TABLE(platform, max77802_clk_id); | ||
| 83 | |||
| 84 | static struct platform_driver max77802_clk_driver = { | ||
| 85 | .driver = { | ||
| 86 | .name = "max77802-clk", | ||
| 87 | }, | ||
| 88 | .probe = max77802_clk_probe, | ||
| 89 | .remove = max77802_clk_remove, | ||
| 90 | .id_table = max77802_clk_id, | ||
| 91 | }; | ||
| 92 | |||
| 93 | module_platform_driver(max77802_clk_driver); | ||
| 94 | |||
| 95 | MODULE_DESCRIPTION("MAXIM 77802 Clock Driver"); | ||
| 96 | MODULE_AUTHOR("Javier Martinez Canillas <javier.martinez@collabora.co.uk>"); | ||
| 97 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/clk/clk-palmas.c b/drivers/clk/clk-palmas.c index 781630e1372b..8d459923a15f 100644 --- a/drivers/clk/clk-palmas.c +++ b/drivers/clk/clk-palmas.c | |||
| @@ -292,7 +292,6 @@ static int palmas_clks_remove(struct platform_device *pdev) | |||
| 292 | static struct platform_driver palmas_clks_driver = { | 292 | static struct platform_driver palmas_clks_driver = { |
| 293 | .driver = { | 293 | .driver = { |
| 294 | .name = "palmas-clk", | 294 | .name = "palmas-clk", |
| 295 | .owner = THIS_MODULE, | ||
| 296 | .of_match_table = palmas_clks_of_match, | 295 | .of_match_table = palmas_clks_of_match, |
| 297 | }, | 296 | }, |
| 298 | .probe = palmas_clks_probe, | 297 | .probe = palmas_clks_probe, |
diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c index 1ada79a28052..4a755135bcd3 100644 --- a/drivers/clk/clk-twl6040.c +++ b/drivers/clk/clk-twl6040.c | |||
| @@ -112,7 +112,6 @@ static int twl6040_clk_remove(struct platform_device *pdev) | |||
| 112 | static struct platform_driver twl6040_clk_driver = { | 112 | static struct platform_driver twl6040_clk_driver = { |
| 113 | .driver = { | 113 | .driver = { |
| 114 | .name = "twl6040-clk", | 114 | .name = "twl6040-clk", |
| 115 | .owner = THIS_MODULE, | ||
| 116 | }, | 115 | }, |
| 117 | .probe = twl6040_clk_probe, | 116 | .probe = twl6040_clk_probe, |
| 118 | .remove = twl6040_clk_remove, | 117 | .remove = twl6040_clk_remove, |
diff --git a/drivers/clk/clk-wm831x.c b/drivers/clk/clk-wm831x.c index b131041c8f48..ef67719f4e52 100644 --- a/drivers/clk/clk-wm831x.c +++ b/drivers/clk/clk-wm831x.c | |||
| @@ -395,7 +395,6 @@ static struct platform_driver wm831x_clk_driver = { | |||
| 395 | .probe = wm831x_clk_probe, | 395 | .probe = wm831x_clk_probe, |
| 396 | .driver = { | 396 | .driver = { |
| 397 | .name = "wm831x-clk", | 397 | .name = "wm831x-clk", |
| 398 | .owner = THIS_MODULE, | ||
| 399 | }, | 398 | }, |
| 400 | }; | 399 | }; |
| 401 | 400 | ||
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index bacc06ff939b..4896ae9e23da 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c | |||
| @@ -100,6 +100,8 @@ static void clk_enable_unlock(unsigned long flags) | |||
| 100 | 100 | ||
| 101 | static struct dentry *rootdir; | 101 | static struct dentry *rootdir; |
| 102 | static int inited = 0; | 102 | static int inited = 0; |
| 103 | static DEFINE_MUTEX(clk_debug_lock); | ||
| 104 | static HLIST_HEAD(clk_debug_list); | ||
| 103 | 105 | ||
| 104 | static struct hlist_head *all_lists[] = { | 106 | static struct hlist_head *all_lists[] = { |
| 105 | &clk_root_list, | 107 | &clk_root_list, |
| @@ -117,11 +119,11 @@ static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level) | |||
| 117 | if (!c) | 119 | if (!c) |
| 118 | return; | 120 | return; |
| 119 | 121 | ||
| 120 | seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu\n", | 122 | seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu %-3d\n", |
| 121 | level * 3 + 1, "", | 123 | level * 3 + 1, "", |
| 122 | 30 - level * 3, c->name, | 124 | 30 - level * 3, c->name, |
| 123 | c->enable_count, c->prepare_count, clk_get_rate(c), | 125 | c->enable_count, c->prepare_count, clk_get_rate(c), |
| 124 | clk_get_accuracy(c)); | 126 | clk_get_accuracy(c), clk_get_phase(c)); |
| 125 | } | 127 | } |
| 126 | 128 | ||
| 127 | static void clk_summary_show_subtree(struct seq_file *s, struct clk *c, | 129 | static void clk_summary_show_subtree(struct seq_file *s, struct clk *c, |
| @@ -143,8 +145,8 @@ static int clk_summary_show(struct seq_file *s, void *data) | |||
| 143 | struct clk *c; | 145 | struct clk *c; |
| 144 | struct hlist_head **lists = (struct hlist_head **)s->private; | 146 | struct hlist_head **lists = (struct hlist_head **)s->private; |
| 145 | 147 | ||
| 146 | seq_puts(s, " clock enable_cnt prepare_cnt rate accuracy\n"); | 148 | seq_puts(s, " clock enable_cnt prepare_cnt rate accuracy phase\n"); |
| 147 | seq_puts(s, "--------------------------------------------------------------------------------\n"); | 149 | seq_puts(s, "----------------------------------------------------------------------------------------\n"); |
| 148 | 150 | ||
| 149 | clk_prepare_lock(); | 151 | clk_prepare_lock(); |
| 150 | 152 | ||
| @@ -180,6 +182,7 @@ static void clk_dump_one(struct seq_file *s, struct clk *c, int level) | |||
| 180 | seq_printf(s, "\"prepare_count\": %d,", c->prepare_count); | 182 | seq_printf(s, "\"prepare_count\": %d,", c->prepare_count); |
| 181 | seq_printf(s, "\"rate\": %lu", clk_get_rate(c)); | 183 | seq_printf(s, "\"rate\": %lu", clk_get_rate(c)); |
| 182 | seq_printf(s, "\"accuracy\": %lu", clk_get_accuracy(c)); | 184 | seq_printf(s, "\"accuracy\": %lu", clk_get_accuracy(c)); |
| 185 | seq_printf(s, "\"phase\": %d", clk_get_phase(c)); | ||
| 183 | } | 186 | } |
| 184 | 187 | ||
| 185 | static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level) | 188 | static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level) |
| @@ -264,6 +267,11 @@ static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry) | |||
| 264 | if (!d) | 267 | if (!d) |
| 265 | goto err_out; | 268 | goto err_out; |
| 266 | 269 | ||
| 270 | d = debugfs_create_u32("clk_phase", S_IRUGO, clk->dentry, | ||
| 271 | (u32 *)&clk->phase); | ||
| 272 | if (!d) | ||
| 273 | goto err_out; | ||
| 274 | |||
| 267 | d = debugfs_create_x32("clk_flags", S_IRUGO, clk->dentry, | 275 | d = debugfs_create_x32("clk_flags", S_IRUGO, clk->dentry, |
| 268 | (u32 *)&clk->flags); | 276 | (u32 *)&clk->flags); |
| 269 | if (!d) | 277 | if (!d) |
| @@ -300,28 +308,6 @@ out: | |||
| 300 | return ret; | 308 | return ret; |
| 301 | } | 309 | } |
| 302 | 310 | ||
| 303 | /* caller must hold prepare_lock */ | ||
| 304 | static int clk_debug_create_subtree(struct clk *clk, struct dentry *pdentry) | ||
| 305 | { | ||
| 306 | struct clk *child; | ||
| 307 | int ret = -EINVAL;; | ||
| 308 | |||
| 309 | if (!clk || !pdentry) | ||
| 310 | goto out; | ||
| 311 | |||
| 312 | ret = clk_debug_create_one(clk, pdentry); | ||
| 313 | |||
| 314 | if (ret) | ||
| 315 | goto out; | ||
| 316 | |||
| 317 | hlist_for_each_entry(child, &clk->children, child_node) | ||
| 318 | clk_debug_create_subtree(child, pdentry); | ||
| 319 | |||
| 320 | ret = 0; | ||
| 321 | out: | ||
| 322 | return ret; | ||
| 323 | } | ||
| 324 | |||
| 325 | /** | 311 | /** |
| 326 | * clk_debug_register - add a clk node to the debugfs clk tree | 312 | * clk_debug_register - add a clk node to the debugfs clk tree |
| 327 | * @clk: the clk being added to the debugfs clk tree | 313 | * @clk: the clk being added to the debugfs clk tree |
| @@ -329,20 +315,21 @@ out: | |||
| 329 | * Dynamically adds a clk to the debugfs clk tree if debugfs has been | 315 | * Dynamically adds a clk to the debugfs clk tree if debugfs has been |
| 330 | * initialized. Otherwise it bails out early since the debugfs clk tree | 316 | * initialized. Otherwise it bails out early since the debugfs clk tree |
| 331 | * will be created lazily by clk_debug_init as part of a late_initcall. | 317 | * will be created lazily by clk_debug_init as part of a late_initcall. |
| 332 | * | ||
| 333 | * Caller must hold prepare_lock. Only clk_init calls this function (so | ||
| 334 | * far) so this is taken care. | ||
| 335 | */ | 318 | */ |
| 336 | static int clk_debug_register(struct clk *clk) | 319 | static int clk_debug_register(struct clk *clk) |
| 337 | { | 320 | { |
| 338 | int ret = 0; | 321 | int ret = 0; |
| 339 | 322 | ||
| 323 | mutex_lock(&clk_debug_lock); | ||
| 324 | hlist_add_head(&clk->debug_node, &clk_debug_list); | ||
| 325 | |||
| 340 | if (!inited) | 326 | if (!inited) |
| 341 | goto out; | 327 | goto unlock; |
| 342 | 328 | ||
| 343 | ret = clk_debug_create_subtree(clk, rootdir); | 329 | ret = clk_debug_create_one(clk, rootdir); |
| 330 | unlock: | ||
| 331 | mutex_unlock(&clk_debug_lock); | ||
| 344 | 332 | ||
| 345 | out: | ||
| 346 | return ret; | 333 | return ret; |
| 347 | } | 334 | } |
| 348 | 335 | ||
| @@ -353,12 +340,18 @@ out: | |||
| 353 | * Dynamically removes a clk and all it's children clk nodes from the | 340 | * Dynamically removes a clk and all it's children clk nodes from the |
| 354 | * debugfs clk tree if clk->dentry points to debugfs created by | 341 | * debugfs clk tree if clk->dentry points to debugfs created by |
| 355 | * clk_debug_register in __clk_init. | 342 | * clk_debug_register in __clk_init. |
| 356 | * | ||
| 357 | * Caller must hold prepare_lock. | ||
| 358 | */ | 343 | */ |
| 359 | static void clk_debug_unregister(struct clk *clk) | 344 | static void clk_debug_unregister(struct clk *clk) |
| 360 | { | 345 | { |
| 346 | mutex_lock(&clk_debug_lock); | ||
| 347 | if (!clk->dentry) | ||
| 348 | goto out; | ||
| 349 | |||
| 350 | hlist_del_init(&clk->debug_node); | ||
| 361 | debugfs_remove_recursive(clk->dentry); | 351 | debugfs_remove_recursive(clk->dentry); |
| 352 | clk->dentry = NULL; | ||
| 353 | out: | ||
| 354 | mutex_unlock(&clk_debug_lock); | ||
| 362 | } | 355 | } |
| 363 | 356 | ||
| 364 | struct dentry *clk_debugfs_add_file(struct clk *clk, char *name, umode_t mode, | 357 | struct dentry *clk_debugfs_add_file(struct clk *clk, char *name, umode_t mode, |
| @@ -415,17 +408,12 @@ static int __init clk_debug_init(void) | |||
| 415 | if (!d) | 408 | if (!d) |
| 416 | return -ENOMEM; | 409 | return -ENOMEM; |
| 417 | 410 | ||
| 418 | clk_prepare_lock(); | 411 | mutex_lock(&clk_debug_lock); |
| 419 | 412 | hlist_for_each_entry(clk, &clk_debug_list, debug_node) | |
| 420 | hlist_for_each_entry(clk, &clk_root_list, child_node) | 413 | clk_debug_create_one(clk, rootdir); |
| 421 | clk_debug_create_subtree(clk, rootdir); | ||
| 422 | |||
| 423 | hlist_for_each_entry(clk, &clk_orphan_list, child_node) | ||
| 424 | clk_debug_create_subtree(clk, rootdir); | ||
| 425 | 414 | ||
| 426 | inited = 1; | 415 | inited = 1; |
| 427 | 416 | mutex_unlock(&clk_debug_lock); | |
| 428 | clk_prepare_unlock(); | ||
| 429 | 417 | ||
| 430 | return 0; | 418 | return 0; |
| 431 | } | 419 | } |
| @@ -1744,6 +1732,77 @@ out: | |||
| 1744 | EXPORT_SYMBOL_GPL(clk_set_parent); | 1732 | EXPORT_SYMBOL_GPL(clk_set_parent); |
| 1745 | 1733 | ||
| 1746 | /** | 1734 | /** |
| 1735 | * clk_set_phase - adjust the phase shift of a clock signal | ||
| 1736 | * @clk: clock signal source | ||
| 1737 | * @degrees: number of degrees the signal is shifted | ||
| 1738 | * | ||
| 1739 | * Shifts the phase of a clock signal by the specified | ||
| 1740 | * degrees. Returns 0 on success, -EERROR otherwise. | ||
| 1741 | * | ||
| 1742 | * This function makes no distinction about the input or reference | ||
| 1743 | * signal that we adjust the clock signal phase against. For example | ||
| 1744 | * phase locked-loop clock signal generators we may shift phase with | ||
| 1745 | * respect to feedback clock signal input, but for other cases the | ||
| 1746 | * clock phase may be shifted with respect to some other, unspecified | ||
| 1747 | * signal. | ||
| 1748 | * | ||
| 1749 | * Additionally the concept of phase shift does not propagate through | ||
| 1750 | * the clock tree hierarchy, which sets it apart from clock rates and | ||
| 1751 | * clock accuracy. A parent clock phase attribute does not have an | ||
| 1752 | * impact on the phase attribute of a child clock. | ||
| 1753 | */ | ||
| 1754 | int clk_set_phase(struct clk *clk, int degrees) | ||
| 1755 | { | ||
| 1756 | int ret = 0; | ||
| 1757 | |||
| 1758 | if (!clk) | ||
| 1759 | goto out; | ||
| 1760 | |||
| 1761 | /* sanity check degrees */ | ||
| 1762 | degrees %= 360; | ||
| 1763 | if (degrees < 0) | ||
| 1764 | degrees += 360; | ||
| 1765 | |||
| 1766 | clk_prepare_lock(); | ||
| 1767 | |||
| 1768 | if (!clk->ops->set_phase) | ||
| 1769 | goto out_unlock; | ||
| 1770 | |||
| 1771 | ret = clk->ops->set_phase(clk->hw, degrees); | ||
| 1772 | |||
| 1773 | if (!ret) | ||
| 1774 | clk->phase = degrees; | ||
| 1775 | |||
| 1776 | out_unlock: | ||
| 1777 | clk_prepare_unlock(); | ||
| 1778 | |||
| 1779 | out: | ||
| 1780 | return ret; | ||
| 1781 | } | ||
| 1782 | |||
| 1783 | /** | ||
| 1784 | * clk_get_phase - return the phase shift of a clock signal | ||
| 1785 | * @clk: clock signal source | ||
| 1786 | * | ||
| 1787 | * Returns the phase shift of a clock node in degrees, otherwise returns | ||
| 1788 | * -EERROR. | ||
| 1789 | */ | ||
| 1790 | int clk_get_phase(struct clk *clk) | ||
| 1791 | { | ||
| 1792 | int ret = 0; | ||
| 1793 | |||
| 1794 | if (!clk) | ||
| 1795 | goto out; | ||
| 1796 | |||
| 1797 | clk_prepare_lock(); | ||
| 1798 | ret = clk->phase; | ||
| 1799 | clk_prepare_unlock(); | ||
| 1800 | |||
| 1801 | out: | ||
| 1802 | return ret; | ||
| 1803 | } | ||
| 1804 | |||
| 1805 | /** | ||
| 1747 | * __clk_init - initialize the data structures in a struct clk | 1806 | * __clk_init - initialize the data structures in a struct clk |
| 1748 | * @dev: device initializing this clk, placeholder for now | 1807 | * @dev: device initializing this clk, placeholder for now |
| 1749 | * @clk: clk being initialized | 1808 | * @clk: clk being initialized |
| @@ -1862,6 +1921,16 @@ int __clk_init(struct device *dev, struct clk *clk) | |||
| 1862 | clk->accuracy = 0; | 1921 | clk->accuracy = 0; |
| 1863 | 1922 | ||
| 1864 | /* | 1923 | /* |
| 1924 | * Set clk's phase. | ||
| 1925 | * Since a phase is by definition relative to its parent, just | ||
| 1926 | * query the current clock phase, or just assume it's in phase. | ||
| 1927 | */ | ||
| 1928 | if (clk->ops->get_phase) | ||
| 1929 | clk->phase = clk->ops->get_phase(clk->hw); | ||
| 1930 | else | ||
| 1931 | clk->phase = 0; | ||
| 1932 | |||
| 1933 | /* | ||
| 1865 | * Set clk's rate. The preferred method is to use .recalc_rate. For | 1934 | * Set clk's rate. The preferred method is to use .recalc_rate. For |
| 1866 | * simple clocks and lazy developers the default fallback is to use the | 1935 | * simple clocks and lazy developers the default fallback is to use the |
| 1867 | * parent's rate. If a clock doesn't have a parent (or is orphaned) | 1936 | * parent's rate. If a clock doesn't have a parent (or is orphaned) |
| @@ -2092,14 +2161,16 @@ void clk_unregister(struct clk *clk) | |||
| 2092 | { | 2161 | { |
| 2093 | unsigned long flags; | 2162 | unsigned long flags; |
| 2094 | 2163 | ||
| 2095 | if (!clk || WARN_ON_ONCE(IS_ERR(clk))) | 2164 | if (!clk || WARN_ON_ONCE(IS_ERR(clk))) |
| 2096 | return; | 2165 | return; |
| 2166 | |||
| 2167 | clk_debug_unregister(clk); | ||
| 2097 | 2168 | ||
| 2098 | clk_prepare_lock(); | 2169 | clk_prepare_lock(); |
| 2099 | 2170 | ||
| 2100 | if (clk->ops == &clk_nodrv_ops) { | 2171 | if (clk->ops == &clk_nodrv_ops) { |
| 2101 | pr_err("%s: unregistered clock: %s\n", __func__, clk->name); | 2172 | pr_err("%s: unregistered clock: %s\n", __func__, clk->name); |
| 2102 | goto out; | 2173 | return; |
| 2103 | } | 2174 | } |
| 2104 | /* | 2175 | /* |
| 2105 | * Assign empty clock ops for consumers that might still hold | 2176 | * Assign empty clock ops for consumers that might still hold |
| @@ -2118,16 +2189,13 @@ void clk_unregister(struct clk *clk) | |||
| 2118 | clk_set_parent(child, NULL); | 2189 | clk_set_parent(child, NULL); |
| 2119 | } | 2190 | } |
| 2120 | 2191 | ||
| 2121 | clk_debug_unregister(clk); | ||
| 2122 | |||
| 2123 | hlist_del_init(&clk->child_node); | 2192 | hlist_del_init(&clk->child_node); |
| 2124 | 2193 | ||
| 2125 | if (clk->prepare_count) | 2194 | if (clk->prepare_count) |
| 2126 | pr_warn("%s: unregistering prepared clock: %s\n", | 2195 | pr_warn("%s: unregistering prepared clock: %s\n", |
| 2127 | __func__, clk->name); | 2196 | __func__, clk->name); |
| 2128 | |||
| 2129 | kref_put(&clk->ref, __clk_release); | 2197 | kref_put(&clk->ref, __clk_release); |
| 2130 | out: | 2198 | |
| 2131 | clk_prepare_unlock(); | 2199 | clk_prepare_unlock(); |
| 2132 | } | 2200 | } |
| 2133 | EXPORT_SYMBOL_GPL(clk_unregister); | 2201 | EXPORT_SYMBOL_GPL(clk_unregister); |
diff --git a/drivers/clk/hisilicon/clk-hix5hd2.c b/drivers/clk/hisilicon/clk-hix5hd2.c index e5fcfb4e32ef..3f369c60fe56 100644 --- a/drivers/clk/hisilicon/clk-hix5hd2.c +++ b/drivers/clk/hisilicon/clk-hix5hd2.c | |||
| @@ -9,6 +9,8 @@ | |||
| 9 | 9 | ||
| 10 | #include <linux/of_address.h> | 10 | #include <linux/of_address.h> |
| 11 | #include <dt-bindings/clock/hix5hd2-clock.h> | 11 | #include <dt-bindings/clock/hix5hd2-clock.h> |
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/delay.h> | ||
| 12 | #include "clk.h" | 14 | #include "clk.h" |
| 13 | 15 | ||
| 14 | static struct hisi_fixed_rate_clock hix5hd2_fixed_rate_clks[] __initdata = { | 16 | static struct hisi_fixed_rate_clock hix5hd2_fixed_rate_clks[] __initdata = { |
| @@ -48,9 +50,9 @@ static const char *sfc_mux_p[] __initconst = { | |||
| 48 | "24m", "150m", "200m", "100m", "75m", }; | 50 | "24m", "150m", "200m", "100m", "75m", }; |
| 49 | static u32 sfc_mux_table[] = {0, 4, 5, 6, 7}; | 51 | static u32 sfc_mux_table[] = {0, 4, 5, 6, 7}; |
| 50 | 52 | ||
| 51 | static const char *sdio1_mux_p[] __initconst = { | 53 | static const char *sdio_mux_p[] __initconst = { |
| 52 | "75m", "100m", "50m", "15m", }; | 54 | "75m", "100m", "50m", "15m", }; |
| 53 | static u32 sdio1_mux_table[] = {0, 1, 2, 3}; | 55 | static u32 sdio_mux_table[] = {0, 1, 2, 3}; |
| 54 | 56 | ||
| 55 | static const char *fephy_mux_p[] __initconst = { "25m", "125m"}; | 57 | static const char *fephy_mux_p[] __initconst = { "25m", "125m"}; |
| 56 | static u32 fephy_mux_table[] = {0, 1}; | 58 | static u32 fephy_mux_table[] = {0, 1}; |
| @@ -59,28 +61,243 @@ static u32 fephy_mux_table[] = {0, 1}; | |||
| 59 | static struct hisi_mux_clock hix5hd2_mux_clks[] __initdata = { | 61 | static struct hisi_mux_clock hix5hd2_mux_clks[] __initdata = { |
| 60 | { HIX5HD2_SFC_MUX, "sfc_mux", sfc_mux_p, ARRAY_SIZE(sfc_mux_p), | 62 | { HIX5HD2_SFC_MUX, "sfc_mux", sfc_mux_p, ARRAY_SIZE(sfc_mux_p), |
| 61 | CLK_SET_RATE_PARENT, 0x5c, 8, 3, 0, sfc_mux_table, }, | 63 | CLK_SET_RATE_PARENT, 0x5c, 8, 3, 0, sfc_mux_table, }, |
| 62 | { HIX5HD2_MMC_MUX, "mmc_mux", sdio1_mux_p, ARRAY_SIZE(sdio1_mux_p), | 64 | { HIX5HD2_MMC_MUX, "mmc_mux", sdio_mux_p, ARRAY_SIZE(sdio_mux_p), |
| 63 | CLK_SET_RATE_PARENT, 0xa0, 8, 2, 0, sdio1_mux_table, }, | 65 | CLK_SET_RATE_PARENT, 0xa0, 8, 2, 0, sdio_mux_table, }, |
| 66 | { HIX5HD2_SD_MUX, "sd_mux", sdio_mux_p, ARRAY_SIZE(sdio_mux_p), | ||
| 67 | CLK_SET_RATE_PARENT, 0x9c, 8, 2, 0, sdio_mux_table, }, | ||
| 64 | { HIX5HD2_FEPHY_MUX, "fephy_mux", | 68 | { HIX5HD2_FEPHY_MUX, "fephy_mux", |
| 65 | fephy_mux_p, ARRAY_SIZE(fephy_mux_p), | 69 | fephy_mux_p, ARRAY_SIZE(fephy_mux_p), |
| 66 | CLK_SET_RATE_PARENT, 0x120, 8, 2, 0, fephy_mux_table, }, | 70 | CLK_SET_RATE_PARENT, 0x120, 8, 2, 0, fephy_mux_table, }, |
| 67 | }; | 71 | }; |
| 68 | 72 | ||
| 69 | static struct hisi_gate_clock hix5hd2_gate_clks[] __initdata = { | 73 | static struct hisi_gate_clock hix5hd2_gate_clks[] __initdata = { |
| 70 | /*sfc*/ | 74 | /* sfc */ |
| 71 | { HIX5HD2_SFC_CLK, "clk_sfc", "sfc_mux", | 75 | { HIX5HD2_SFC_CLK, "clk_sfc", "sfc_mux", |
| 72 | CLK_SET_RATE_PARENT, 0x5c, 0, 0, }, | 76 | CLK_SET_RATE_PARENT, 0x5c, 0, 0, }, |
| 73 | { HIX5HD2_SFC_RST, "rst_sfc", "clk_sfc", | 77 | { HIX5HD2_SFC_RST, "rst_sfc", "clk_sfc", |
| 74 | CLK_SET_RATE_PARENT, 0x5c, 4, CLK_GATE_SET_TO_DISABLE, }, | 78 | CLK_SET_RATE_PARENT, 0x5c, 4, CLK_GATE_SET_TO_DISABLE, }, |
| 75 | /*sdio1*/ | 79 | /* sdio0 */ |
| 80 | { HIX5HD2_SD_BIU_CLK, "clk_sd_biu", "200m", | ||
| 81 | CLK_SET_RATE_PARENT, 0x9c, 0, 0, }, | ||
| 82 | { HIX5HD2_SD_CIU_CLK, "clk_sd_ciu", "sd_mux", | ||
| 83 | CLK_SET_RATE_PARENT, 0x9c, 1, 0, }, | ||
| 84 | { HIX5HD2_SD_CIU_RST, "rst_sd_ciu", "clk_sd_ciu", | ||
| 85 | CLK_SET_RATE_PARENT, 0x9c, 4, CLK_GATE_SET_TO_DISABLE, }, | ||
| 86 | /* sdio1 */ | ||
| 76 | { HIX5HD2_MMC_BIU_CLK, "clk_mmc_biu", "200m", | 87 | { HIX5HD2_MMC_BIU_CLK, "clk_mmc_biu", "200m", |
| 77 | CLK_SET_RATE_PARENT, 0xa0, 0, 0, }, | 88 | CLK_SET_RATE_PARENT, 0xa0, 0, 0, }, |
| 78 | { HIX5HD2_MMC_CIU_CLK, "clk_mmc_ciu", "mmc_mux", | 89 | { HIX5HD2_MMC_CIU_CLK, "clk_mmc_ciu", "mmc_mux", |
| 79 | CLK_SET_RATE_PARENT, 0xa0, 1, 0, }, | 90 | CLK_SET_RATE_PARENT, 0xa0, 1, 0, }, |
| 80 | { HIX5HD2_MMC_CIU_RST, "rst_mmc_ciu", "clk_mmc_ciu", | 91 | { HIX5HD2_MMC_CIU_RST, "rst_mmc_ciu", "clk_mmc_ciu", |
| 81 | CLK_SET_RATE_PARENT, 0xa0, 4, CLK_GATE_SET_TO_DISABLE, }, | 92 | CLK_SET_RATE_PARENT, 0xa0, 4, CLK_GATE_SET_TO_DISABLE, }, |
| 93 | /* gsf */ | ||
| 94 | { HIX5HD2_FWD_BUS_CLK, "clk_fwd_bus", NULL, 0, 0xcc, 0, 0, }, | ||
| 95 | { HIX5HD2_FWD_SYS_CLK, "clk_fwd_sys", "clk_fwd_bus", 0, 0xcc, 5, 0, }, | ||
| 96 | { HIX5HD2_MAC0_PHY_CLK, "clk_fephy", "clk_fwd_sys", | ||
| 97 | CLK_SET_RATE_PARENT, 0x120, 0, 0, }, | ||
| 98 | /* wdg0 */ | ||
| 99 | { HIX5HD2_WDG0_CLK, "clk_wdg0", "24m", | ||
| 100 | CLK_SET_RATE_PARENT, 0x178, 0, 0, }, | ||
| 101 | { HIX5HD2_WDG0_RST, "rst_wdg0", "clk_wdg0", | ||
| 102 | CLK_SET_RATE_PARENT, 0x178, 4, CLK_GATE_SET_TO_DISABLE, }, | ||
| 103 | /* I2C */ | ||
| 104 | {HIX5HD2_I2C0_CLK, "clk_i2c0", "100m", | ||
| 105 | CLK_SET_RATE_PARENT, 0x06c, 4, 0, }, | ||
| 106 | {HIX5HD2_I2C0_RST, "rst_i2c0", "clk_i2c0", | ||
| 107 | CLK_SET_RATE_PARENT, 0x06c, 5, CLK_GATE_SET_TO_DISABLE, }, | ||
| 108 | {HIX5HD2_I2C1_CLK, "clk_i2c1", "100m", | ||
| 109 | CLK_SET_RATE_PARENT, 0x06c, 8, 0, }, | ||
| 110 | {HIX5HD2_I2C1_RST, "rst_i2c1", "clk_i2c1", | ||
| 111 | CLK_SET_RATE_PARENT, 0x06c, 9, CLK_GATE_SET_TO_DISABLE, }, | ||
| 112 | {HIX5HD2_I2C2_CLK, "clk_i2c2", "100m", | ||
| 113 | CLK_SET_RATE_PARENT, 0x06c, 12, 0, }, | ||
| 114 | {HIX5HD2_I2C2_RST, "rst_i2c2", "clk_i2c2", | ||
| 115 | CLK_SET_RATE_PARENT, 0x06c, 13, CLK_GATE_SET_TO_DISABLE, }, | ||
| 116 | {HIX5HD2_I2C3_CLK, "clk_i2c3", "100m", | ||
| 117 | CLK_SET_RATE_PARENT, 0x06c, 16, 0, }, | ||
| 118 | {HIX5HD2_I2C3_RST, "rst_i2c3", "clk_i2c3", | ||
| 119 | CLK_SET_RATE_PARENT, 0x06c, 17, CLK_GATE_SET_TO_DISABLE, }, | ||
| 120 | {HIX5HD2_I2C4_CLK, "clk_i2c4", "100m", | ||
| 121 | CLK_SET_RATE_PARENT, 0x06c, 20, 0, }, | ||
| 122 | {HIX5HD2_I2C4_RST, "rst_i2c4", "clk_i2c4", | ||
| 123 | CLK_SET_RATE_PARENT, 0x06c, 21, CLK_GATE_SET_TO_DISABLE, }, | ||
| 124 | {HIX5HD2_I2C5_CLK, "clk_i2c5", "100m", | ||
| 125 | CLK_SET_RATE_PARENT, 0x06c, 0, 0, }, | ||
| 126 | {HIX5HD2_I2C5_RST, "rst_i2c5", "clk_i2c5", | ||
| 127 | CLK_SET_RATE_PARENT, 0x06c, 1, CLK_GATE_SET_TO_DISABLE, }, | ||
| 82 | }; | 128 | }; |
| 83 | 129 | ||
| 130 | enum hix5hd2_clk_type { | ||
| 131 | TYPE_COMPLEX, | ||
| 132 | TYPE_ETHER, | ||
| 133 | }; | ||
| 134 | |||
| 135 | struct hix5hd2_complex_clock { | ||
| 136 | const char *name; | ||
| 137 | const char *parent_name; | ||
| 138 | u32 id; | ||
| 139 | u32 ctrl_reg; | ||
| 140 | u32 ctrl_clk_mask; | ||
| 141 | u32 ctrl_rst_mask; | ||
| 142 | u32 phy_reg; | ||
| 143 | u32 phy_clk_mask; | ||
| 144 | u32 phy_rst_mask; | ||
| 145 | enum hix5hd2_clk_type type; | ||
| 146 | }; | ||
| 147 | |||
| 148 | struct hix5hd2_clk_complex { | ||
| 149 | struct clk_hw hw; | ||
| 150 | u32 id; | ||
| 151 | void __iomem *ctrl_reg; | ||
| 152 | u32 ctrl_clk_mask; | ||
| 153 | u32 ctrl_rst_mask; | ||
| 154 | void __iomem *phy_reg; | ||
| 155 | u32 phy_clk_mask; | ||
| 156 | u32 phy_rst_mask; | ||
| 157 | }; | ||
| 158 | |||
| 159 | static struct hix5hd2_complex_clock hix5hd2_complex_clks[] __initdata = { | ||
| 160 | {"clk_mac0", "clk_fephy", HIX5HD2_MAC0_CLK, | ||
| 161 | 0xcc, 0xa, 0x500, 0x120, 0, 0x10, TYPE_ETHER}, | ||
| 162 | {"clk_mac1", "clk_fwd_sys", HIX5HD2_MAC1_CLK, | ||
| 163 | 0xcc, 0x14, 0xa00, 0x168, 0x2, 0, TYPE_ETHER}, | ||
| 164 | {"clk_sata", NULL, HIX5HD2_SATA_CLK, | ||
| 165 | 0xa8, 0x1f, 0x300, 0xac, 0x1, 0x0, TYPE_COMPLEX}, | ||
| 166 | {"clk_usb", NULL, HIX5HD2_USB_CLK, | ||
| 167 | 0xb8, 0xff, 0x3f000, 0xbc, 0x7, 0x3f00, TYPE_COMPLEX}, | ||
| 168 | }; | ||
| 169 | |||
| 170 | #define to_complex_clk(_hw) container_of(_hw, struct hix5hd2_clk_complex, hw) | ||
| 171 | |||
| 172 | static int clk_ether_prepare(struct clk_hw *hw) | ||
| 173 | { | ||
| 174 | struct hix5hd2_clk_complex *clk = to_complex_clk(hw); | ||
| 175 | u32 val; | ||
| 176 | |||
| 177 | val = readl_relaxed(clk->ctrl_reg); | ||
| 178 | val |= clk->ctrl_clk_mask | clk->ctrl_rst_mask; | ||
| 179 | writel_relaxed(val, clk->ctrl_reg); | ||
| 180 | val &= ~(clk->ctrl_rst_mask); | ||
| 181 | writel_relaxed(val, clk->ctrl_reg); | ||
| 182 | |||
| 183 | val = readl_relaxed(clk->phy_reg); | ||
| 184 | val |= clk->phy_clk_mask; | ||
| 185 | val &= ~(clk->phy_rst_mask); | ||
| 186 | writel_relaxed(val, clk->phy_reg); | ||
| 187 | mdelay(10); | ||
| 188 | |||
| 189 | val &= ~(clk->phy_clk_mask); | ||
| 190 | val |= clk->phy_rst_mask; | ||
| 191 | writel_relaxed(val, clk->phy_reg); | ||
| 192 | mdelay(10); | ||
| 193 | |||
| 194 | val |= clk->phy_clk_mask; | ||
| 195 | val &= ~(clk->phy_rst_mask); | ||
| 196 | writel_relaxed(val, clk->phy_reg); | ||
| 197 | mdelay(30); | ||
| 198 | return 0; | ||
| 199 | } | ||
| 200 | |||
| 201 | static void clk_ether_unprepare(struct clk_hw *hw) | ||
| 202 | { | ||
| 203 | struct hix5hd2_clk_complex *clk = to_complex_clk(hw); | ||
| 204 | u32 val; | ||
| 205 | |||
| 206 | val = readl_relaxed(clk->ctrl_reg); | ||
| 207 | val &= ~(clk->ctrl_clk_mask); | ||
| 208 | writel_relaxed(val, clk->ctrl_reg); | ||
| 209 | } | ||
| 210 | |||
| 211 | static struct clk_ops clk_ether_ops = { | ||
| 212 | .prepare = clk_ether_prepare, | ||
| 213 | .unprepare = clk_ether_unprepare, | ||
| 214 | }; | ||
| 215 | |||
| 216 | static int clk_complex_enable(struct clk_hw *hw) | ||
| 217 | { | ||
| 218 | struct hix5hd2_clk_complex *clk = to_complex_clk(hw); | ||
| 219 | u32 val; | ||
| 220 | |||
| 221 | val = readl_relaxed(clk->ctrl_reg); | ||
| 222 | val |= clk->ctrl_clk_mask; | ||
| 223 | val &= ~(clk->ctrl_rst_mask); | ||
| 224 | writel_relaxed(val, clk->ctrl_reg); | ||
| 225 | |||
| 226 | val = readl_relaxed(clk->phy_reg); | ||
| 227 | val |= clk->phy_clk_mask; | ||
| 228 | val &= ~(clk->phy_rst_mask); | ||
| 229 | writel_relaxed(val, clk->phy_reg); | ||
| 230 | |||
| 231 | return 0; | ||
| 232 | } | ||
| 233 | |||
| 234 | static void clk_complex_disable(struct clk_hw *hw) | ||
| 235 | { | ||
| 236 | struct hix5hd2_clk_complex *clk = to_complex_clk(hw); | ||
| 237 | u32 val; | ||
| 238 | |||
| 239 | val = readl_relaxed(clk->ctrl_reg); | ||
| 240 | val |= clk->ctrl_rst_mask; | ||
| 241 | val &= ~(clk->ctrl_clk_mask); | ||
| 242 | writel_relaxed(val, clk->ctrl_reg); | ||
| 243 | |||
| 244 | val = readl_relaxed(clk->phy_reg); | ||
| 245 | val |= clk->phy_rst_mask; | ||
| 246 | val &= ~(clk->phy_clk_mask); | ||
| 247 | writel_relaxed(val, clk->phy_reg); | ||
| 248 | } | ||
| 249 | |||
| 250 | static struct clk_ops clk_complex_ops = { | ||
| 251 | .enable = clk_complex_enable, | ||
| 252 | .disable = clk_complex_disable, | ||
| 253 | }; | ||
| 254 | |||
| 255 | void __init hix5hd2_clk_register_complex(struct hix5hd2_complex_clock *clks, | ||
| 256 | int nums, struct hisi_clock_data *data) | ||
| 257 | { | ||
| 258 | void __iomem *base = data->base; | ||
| 259 | int i; | ||
| 260 | |||
| 261 | for (i = 0; i < nums; i++) { | ||
| 262 | struct hix5hd2_clk_complex *p_clk; | ||
| 263 | struct clk *clk; | ||
| 264 | struct clk_init_data init; | ||
| 265 | |||
| 266 | p_clk = kzalloc(sizeof(*p_clk), GFP_KERNEL); | ||
| 267 | if (!p_clk) | ||
| 268 | return; | ||
| 269 | |||
| 270 | init.name = clks[i].name; | ||
| 271 | if (clks[i].type == TYPE_ETHER) | ||
| 272 | init.ops = &clk_ether_ops; | ||
| 273 | else | ||
| 274 | init.ops = &clk_complex_ops; | ||
| 275 | |||
| 276 | init.flags = CLK_IS_BASIC; | ||
| 277 | init.parent_names = | ||
| 278 | (clks[i].parent_name ? &clks[i].parent_name : NULL); | ||
| 279 | init.num_parents = (clks[i].parent_name ? 1 : 0); | ||
| 280 | |||
| 281 | p_clk->ctrl_reg = base + clks[i].ctrl_reg; | ||
| 282 | p_clk->ctrl_clk_mask = clks[i].ctrl_clk_mask; | ||
| 283 | p_clk->ctrl_rst_mask = clks[i].ctrl_rst_mask; | ||
| 284 | p_clk->phy_reg = base + clks[i].phy_reg; | ||
| 285 | p_clk->phy_clk_mask = clks[i].phy_clk_mask; | ||
| 286 | p_clk->phy_rst_mask = clks[i].phy_rst_mask; | ||
| 287 | p_clk->hw.init = &init; | ||
| 288 | |||
| 289 | clk = clk_register(NULL, &p_clk->hw); | ||
| 290 | if (IS_ERR(clk)) { | ||
| 291 | kfree(p_clk); | ||
| 292 | pr_err("%s: failed to register clock %s\n", | ||
| 293 | __func__, clks[i].name); | ||
| 294 | continue; | ||
| 295 | } | ||
| 296 | |||
| 297 | data->clk_data.clks[clks[i].id] = clk; | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 84 | static void __init hix5hd2_clk_init(struct device_node *np) | 301 | static void __init hix5hd2_clk_init(struct device_node *np) |
| 85 | { | 302 | { |
| 86 | struct hisi_clock_data *clk_data; | 303 | struct hisi_clock_data *clk_data; |
| @@ -96,6 +313,9 @@ static void __init hix5hd2_clk_init(struct device_node *np) | |||
| 96 | clk_data); | 313 | clk_data); |
| 97 | hisi_clk_register_gate(hix5hd2_gate_clks, | 314 | hisi_clk_register_gate(hix5hd2_gate_clks, |
| 98 | ARRAY_SIZE(hix5hd2_gate_clks), clk_data); | 315 | ARRAY_SIZE(hix5hd2_gate_clks), clk_data); |
| 316 | hix5hd2_clk_register_complex(hix5hd2_complex_clks, | ||
| 317 | ARRAY_SIZE(hix5hd2_complex_clks), | ||
| 318 | clk_data); | ||
| 99 | } | 319 | } |
| 100 | 320 | ||
| 101 | CLK_OF_DECLARE(hix5hd2_clk, "hisilicon,hix5hd2-clock", hix5hd2_clk_init); | 321 | CLK_OF_DECLARE(hix5hd2_clk, "hisilicon,hix5hd2-clock", hix5hd2_clk_init); |
diff --git a/drivers/clk/mvebu/armada-370.c b/drivers/clk/mvebu/armada-370.c index bef198a83863..756f0f39d6a3 100644 --- a/drivers/clk/mvebu/armada-370.c +++ b/drivers/clk/mvebu/armada-370.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | #define SARL 0 /* Low part [0:31] */ | 25 | #define SARL 0 /* Low part [0:31] */ |
| 26 | #define SARL_A370_SSCG_ENABLE BIT(10) | ||
| 26 | #define SARL_A370_PCLK_FREQ_OPT 11 | 27 | #define SARL_A370_PCLK_FREQ_OPT 11 |
| 27 | #define SARL_A370_PCLK_FREQ_OPT_MASK 0xF | 28 | #define SARL_A370_PCLK_FREQ_OPT_MASK 0xF |
| 28 | #define SARL_A370_FAB_FREQ_OPT 15 | 29 | #define SARL_A370_FAB_FREQ_OPT 15 |
| @@ -133,10 +134,17 @@ static void __init a370_get_clk_ratio( | |||
| 133 | } | 134 | } |
| 134 | } | 135 | } |
| 135 | 136 | ||
| 137 | static bool a370_is_sscg_enabled(void __iomem *sar) | ||
| 138 | { | ||
| 139 | return !(readl(sar) & SARL_A370_SSCG_ENABLE); | ||
| 140 | } | ||
| 141 | |||
| 136 | static const struct coreclk_soc_desc a370_coreclks = { | 142 | static const struct coreclk_soc_desc a370_coreclks = { |
| 137 | .get_tclk_freq = a370_get_tclk_freq, | 143 | .get_tclk_freq = a370_get_tclk_freq, |
| 138 | .get_cpu_freq = a370_get_cpu_freq, | 144 | .get_cpu_freq = a370_get_cpu_freq, |
| 139 | .get_clk_ratio = a370_get_clk_ratio, | 145 | .get_clk_ratio = a370_get_clk_ratio, |
| 146 | .is_sscg_enabled = a370_is_sscg_enabled, | ||
| 147 | .fix_sscg_deviation = kirkwood_fix_sscg_deviation, | ||
| 140 | .ratios = a370_coreclk_ratios, | 148 | .ratios = a370_coreclk_ratios, |
| 141 | .num_ratios = ARRAY_SIZE(a370_coreclk_ratios), | 149 | .num_ratios = ARRAY_SIZE(a370_coreclk_ratios), |
| 142 | }; | 150 | }; |
diff --git a/drivers/clk/mvebu/armada-375.c b/drivers/clk/mvebu/armada-375.c index c991a4d95e10..c7af2242b796 100644 --- a/drivers/clk/mvebu/armada-375.c +++ b/drivers/clk/mvebu/armada-375.c | |||
| @@ -27,14 +27,14 @@ | |||
| 27 | * all modified at the same time, and not separately as for the Armada | 27 | * all modified at the same time, and not separately as for the Armada |
| 28 | * 370 or the Armada XP SoCs. | 28 | * 370 or the Armada XP SoCs. |
| 29 | * | 29 | * |
| 30 | * SAR0[21:17] : CPU frequency DDR frequency L2 frequency | 30 | * SAR1[21:17] : CPU frequency DDR frequency L2 frequency |
| 31 | * 6 = 400 MHz 400 MHz 200 MHz | 31 | * 6 = 400 MHz 400 MHz 200 MHz |
| 32 | * 15 = 600 MHz 600 MHz 300 MHz | 32 | * 15 = 600 MHz 600 MHz 300 MHz |
| 33 | * 21 = 800 MHz 534 MHz 400 MHz | 33 | * 21 = 800 MHz 534 MHz 400 MHz |
| 34 | * 25 = 1000 MHz 500 MHz 500 MHz | 34 | * 25 = 1000 MHz 500 MHz 500 MHz |
| 35 | * others reserved. | 35 | * others reserved. |
| 36 | * | 36 | * |
| 37 | * SAR0[22] : TCLK frequency | 37 | * SAR1[22] : TCLK frequency |
| 38 | * 0 = 166 MHz | 38 | * 0 = 166 MHz |
| 39 | * 1 = 200 MHz | 39 | * 1 = 200 MHz |
| 40 | */ | 40 | */ |
diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c index 25ceccf939ad..b7fcb469c87a 100644 --- a/drivers/clk/mvebu/common.c +++ b/drivers/clk/mvebu/common.c | |||
| @@ -26,8 +26,85 @@ | |||
| 26 | * Core Clocks | 26 | * Core Clocks |
| 27 | */ | 27 | */ |
| 28 | 28 | ||
| 29 | #define SSCG_CONF_MODE(reg) (((reg) >> 16) & 0x3) | ||
| 30 | #define SSCG_SPREAD_DOWN 0x0 | ||
| 31 | #define SSCG_SPREAD_UP 0x1 | ||
| 32 | #define SSCG_SPREAD_CENTRAL 0x2 | ||
| 33 | #define SSCG_CONF_LOW(reg) (((reg) >> 8) & 0xFF) | ||
| 34 | #define SSCG_CONF_HIGH(reg) ((reg) & 0xFF) | ||
| 35 | |||
| 29 | static struct clk_onecell_data clk_data; | 36 | static struct clk_onecell_data clk_data; |
| 30 | 37 | ||
| 38 | /* | ||
| 39 | * This function can be used by the Kirkwood, the Armada 370, the | ||
| 40 | * Armada XP and the Armada 375 SoC. The name of the function was | ||
| 41 | * chosen following the dt convention: using the first known SoC | ||
| 42 | * compatible with it. | ||
| 43 | */ | ||
| 44 | u32 kirkwood_fix_sscg_deviation(u32 system_clk) | ||
| 45 | { | ||
| 46 | struct device_node *sscg_np = NULL; | ||
| 47 | void __iomem *sscg_map; | ||
| 48 | u32 sscg_reg; | ||
| 49 | s32 low_bound, high_bound; | ||
| 50 | u64 freq_swing_half; | ||
| 51 | |||
| 52 | sscg_np = of_find_node_by_name(NULL, "sscg"); | ||
| 53 | if (sscg_np == NULL) { | ||
| 54 | pr_err("cannot get SSCG register node\n"); | ||
| 55 | return system_clk; | ||
| 56 | } | ||
| 57 | |||
| 58 | sscg_map = of_iomap(sscg_np, 0); | ||
| 59 | if (sscg_map == NULL) { | ||
| 60 | pr_err("cannot map SSCG register\n"); | ||
| 61 | goto out; | ||
| 62 | } | ||
| 63 | |||
| 64 | sscg_reg = readl(sscg_map); | ||
| 65 | high_bound = SSCG_CONF_HIGH(sscg_reg); | ||
| 66 | low_bound = SSCG_CONF_LOW(sscg_reg); | ||
| 67 | |||
| 68 | if ((high_bound - low_bound) <= 0) | ||
| 69 | goto out; | ||
| 70 | /* | ||
| 71 | * From Marvell engineer we got the following formula (when | ||
| 72 | * this code was written, the datasheet was erroneous) | ||
| 73 | * Spread percentage = 1/96 * (H - L) / H | ||
| 74 | * H = SSCG_High_Boundary | ||
| 75 | * L = SSCG_Low_Boundary | ||
| 76 | * | ||
| 77 | * As the deviation is half of spread then it lead to the | ||
| 78 | * following formula in the code. | ||
| 79 | * | ||
| 80 | * To avoid an overflow and not lose any significant digit in | ||
| 81 | * the same time we have to use a 64 bit integer. | ||
| 82 | */ | ||
| 83 | |||
| 84 | freq_swing_half = (((u64)high_bound - (u64)low_bound) | ||
| 85 | * (u64)system_clk); | ||
| 86 | do_div(freq_swing_half, (2 * 96 * high_bound)); | ||
| 87 | |||
| 88 | switch (SSCG_CONF_MODE(sscg_reg)) { | ||
| 89 | case SSCG_SPREAD_DOWN: | ||
| 90 | system_clk -= freq_swing_half; | ||
| 91 | break; | ||
| 92 | case SSCG_SPREAD_UP: | ||
| 93 | system_clk += freq_swing_half; | ||
| 94 | break; | ||
| 95 | case SSCG_SPREAD_CENTRAL: | ||
| 96 | default: | ||
| 97 | break; | ||
| 98 | } | ||
| 99 | |||
| 100 | iounmap(sscg_map); | ||
| 101 | |||
| 102 | out: | ||
| 103 | of_node_put(sscg_np); | ||
| 104 | |||
| 105 | return system_clk; | ||
| 106 | } | ||
| 107 | |||
| 31 | void __init mvebu_coreclk_setup(struct device_node *np, | 108 | void __init mvebu_coreclk_setup(struct device_node *np, |
| 32 | const struct coreclk_soc_desc *desc) | 109 | const struct coreclk_soc_desc *desc) |
| 33 | { | 110 | { |
| @@ -62,6 +139,11 @@ void __init mvebu_coreclk_setup(struct device_node *np, | |||
| 62 | of_property_read_string_index(np, "clock-output-names", 1, | 139 | of_property_read_string_index(np, "clock-output-names", 1, |
| 63 | &cpuclk_name); | 140 | &cpuclk_name); |
| 64 | rate = desc->get_cpu_freq(base); | 141 | rate = desc->get_cpu_freq(base); |
| 142 | |||
| 143 | if (desc->is_sscg_enabled && desc->fix_sscg_deviation | ||
| 144 | && desc->is_sscg_enabled(base)) | ||
| 145 | rate = desc->fix_sscg_deviation(rate); | ||
| 146 | |||
| 65 | clk_data.clks[1] = clk_register_fixed_rate(NULL, cpuclk_name, NULL, | 147 | clk_data.clks[1] = clk_register_fixed_rate(NULL, cpuclk_name, NULL, |
| 66 | CLK_IS_ROOT, rate); | 148 | CLK_IS_ROOT, rate); |
| 67 | WARN_ON(IS_ERR(clk_data.clks[1])); | 149 | WARN_ON(IS_ERR(clk_data.clks[1])); |
| @@ -89,8 +171,10 @@ void __init mvebu_coreclk_setup(struct device_node *np, | |||
| 89 | * Clock Gating Control | 171 | * Clock Gating Control |
| 90 | */ | 172 | */ |
| 91 | 173 | ||
| 174 | DEFINE_SPINLOCK(ctrl_gating_lock); | ||
| 175 | |||
| 92 | struct clk_gating_ctrl { | 176 | struct clk_gating_ctrl { |
| 93 | spinlock_t lock; | 177 | spinlock_t *lock; |
| 94 | struct clk **gates; | 178 | struct clk **gates; |
| 95 | int num_gates; | 179 | int num_gates; |
| 96 | }; | 180 | }; |
| @@ -138,7 +222,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np, | |||
| 138 | if (WARN_ON(!ctrl)) | 222 | if (WARN_ON(!ctrl)) |
| 139 | goto ctrl_out; | 223 | goto ctrl_out; |
| 140 | 224 | ||
| 141 | spin_lock_init(&ctrl->lock); | 225 | /* lock must already be initialized */ |
| 226 | ctrl->lock = &ctrl_gating_lock; | ||
| 142 | 227 | ||
| 143 | /* Count, allocate, and register clock gates */ | 228 | /* Count, allocate, and register clock gates */ |
| 144 | for (n = 0; desc[n].name;) | 229 | for (n = 0; desc[n].name;) |
| @@ -155,7 +240,7 @@ void __init mvebu_clk_gating_setup(struct device_node *np, | |||
| 155 | (desc[n].parent) ? desc[n].parent : default_parent; | 240 | (desc[n].parent) ? desc[n].parent : default_parent; |
| 156 | ctrl->gates[n] = clk_register_gate(NULL, desc[n].name, parent, | 241 | ctrl->gates[n] = clk_register_gate(NULL, desc[n].name, parent, |
| 157 | desc[n].flags, base, desc[n].bit_idx, | 242 | desc[n].flags, base, desc[n].bit_idx, |
| 158 | 0, &ctrl->lock); | 243 | 0, ctrl->lock); |
| 159 | WARN_ON(IS_ERR(ctrl->gates[n])); | 244 | WARN_ON(IS_ERR(ctrl->gates[n])); |
| 160 | } | 245 | } |
| 161 | 246 | ||
diff --git a/drivers/clk/mvebu/common.h b/drivers/clk/mvebu/common.h index f968b4d9df92..783b5631a453 100644 --- a/drivers/clk/mvebu/common.h +++ b/drivers/clk/mvebu/common.h | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | 17 | ||
| 18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
| 19 | 19 | ||
| 20 | extern spinlock_t ctrl_gating_lock; | ||
| 21 | |||
| 20 | struct device_node; | 22 | struct device_node; |
| 21 | 23 | ||
| 22 | struct coreclk_ratio { | 24 | struct coreclk_ratio { |
| @@ -28,6 +30,8 @@ struct coreclk_soc_desc { | |||
| 28 | u32 (*get_tclk_freq)(void __iomem *sar); | 30 | u32 (*get_tclk_freq)(void __iomem *sar); |
| 29 | u32 (*get_cpu_freq)(void __iomem *sar); | 31 | u32 (*get_cpu_freq)(void __iomem *sar); |
| 30 | void (*get_clk_ratio)(void __iomem *sar, int id, int *mult, int *div); | 32 | void (*get_clk_ratio)(void __iomem *sar, int id, int *mult, int *div); |
| 33 | bool (*is_sscg_enabled)(void __iomem *sar); | ||
| 34 | u32 (*fix_sscg_deviation)(u32 system_clk); | ||
| 31 | const struct coreclk_ratio *ratios; | 35 | const struct coreclk_ratio *ratios; |
| 32 | int num_ratios; | 36 | int num_ratios; |
| 33 | }; | 37 | }; |
| @@ -45,4 +49,9 @@ void __init mvebu_coreclk_setup(struct device_node *np, | |||
| 45 | void __init mvebu_clk_gating_setup(struct device_node *np, | 49 | void __init mvebu_clk_gating_setup(struct device_node *np, |
| 46 | const struct clk_gating_soc_desc *desc); | 50 | const struct clk_gating_soc_desc *desc); |
| 47 | 51 | ||
| 52 | /* | ||
| 53 | * This function is shared among the Kirkwood, Armada 370, Armada XP | ||
| 54 | * and Armada 375 SoC | ||
| 55 | */ | ||
| 56 | u32 kirkwood_fix_sscg_deviation(u32 system_clk); | ||
| 48 | #endif | 57 | #endif |
diff --git a/drivers/clk/mvebu/kirkwood.c b/drivers/clk/mvebu/kirkwood.c index ddb666a86500..99550f25975e 100644 --- a/drivers/clk/mvebu/kirkwood.c +++ b/drivers/clk/mvebu/kirkwood.c | |||
| @@ -13,9 +13,11 @@ | |||
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 16 | #include <linux/slab.h> | ||
| 16 | #include <linux/clk-provider.h> | 17 | #include <linux/clk-provider.h> |
| 17 | #include <linux/io.h> | 18 | #include <linux/io.h> |
| 18 | #include <linux/of.h> | 19 | #include <linux/of.h> |
| 20 | #include <linux/of_address.h> | ||
| 19 | #include "common.h" | 21 | #include "common.h" |
| 20 | 22 | ||
| 21 | /* | 23 | /* |
| @@ -214,7 +216,6 @@ static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = { | |||
| 214 | { "runit", NULL, 7, 0 }, | 216 | { "runit", NULL, 7, 0 }, |
| 215 | { "xor0", NULL, 8, 0 }, | 217 | { "xor0", NULL, 8, 0 }, |
| 216 | { "audio", NULL, 9, 0 }, | 218 | { "audio", NULL, 9, 0 }, |
| 217 | { "powersave", "cpuclk", 11, 0 }, | ||
| 218 | { "sata0", NULL, 14, 0 }, | 219 | { "sata0", NULL, 14, 0 }, |
| 219 | { "sata1", NULL, 15, 0 }, | 220 | { "sata1", NULL, 15, 0 }, |
| 220 | { "xor1", NULL, 16, 0 }, | 221 | { "xor1", NULL, 16, 0 }, |
| @@ -225,6 +226,101 @@ static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = { | |||
| 225 | { } | 226 | { } |
| 226 | }; | 227 | }; |
| 227 | 228 | ||
| 229 | |||
| 230 | /* | ||
| 231 | * Clock Muxing Control | ||
| 232 | */ | ||
| 233 | |||
| 234 | struct clk_muxing_soc_desc { | ||
| 235 | const char *name; | ||
| 236 | const char **parents; | ||
| 237 | int num_parents; | ||
| 238 | int shift; | ||
| 239 | int width; | ||
| 240 | unsigned long flags; | ||
| 241 | }; | ||
| 242 | |||
| 243 | struct clk_muxing_ctrl { | ||
| 244 | spinlock_t *lock; | ||
| 245 | struct clk **muxes; | ||
| 246 | int num_muxes; | ||
| 247 | }; | ||
| 248 | |||
| 249 | static const char *powersave_parents[] = { | ||
| 250 | "cpuclk", | ||
| 251 | "ddrclk", | ||
| 252 | }; | ||
| 253 | |||
| 254 | static const struct clk_muxing_soc_desc kirkwood_mux_desc[] __initconst = { | ||
| 255 | { "powersave", powersave_parents, ARRAY_SIZE(powersave_parents), | ||
| 256 | 11, 1, 0 }, | ||
| 257 | }; | ||
| 258 | |||
| 259 | #define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw) | ||
| 260 | |||
| 261 | static struct clk *clk_muxing_get_src( | ||
| 262 | struct of_phandle_args *clkspec, void *data) | ||
| 263 | { | ||
| 264 | struct clk_muxing_ctrl *ctrl = (struct clk_muxing_ctrl *)data; | ||
| 265 | int n; | ||
| 266 | |||
| 267 | if (clkspec->args_count < 1) | ||
| 268 | return ERR_PTR(-EINVAL); | ||
| 269 | |||
| 270 | for (n = 0; n < ctrl->num_muxes; n++) { | ||
| 271 | struct clk_mux *mux = | ||
| 272 | to_clk_mux(__clk_get_hw(ctrl->muxes[n])); | ||
| 273 | if (clkspec->args[0] == mux->shift) | ||
| 274 | return ctrl->muxes[n]; | ||
| 275 | } | ||
| 276 | return ERR_PTR(-ENODEV); | ||
| 277 | } | ||
| 278 | |||
| 279 | static void __init kirkwood_clk_muxing_setup(struct device_node *np, | ||
| 280 | const struct clk_muxing_soc_desc *desc) | ||
| 281 | { | ||
| 282 | struct clk_muxing_ctrl *ctrl; | ||
| 283 | void __iomem *base; | ||
| 284 | int n; | ||
| 285 | |||
| 286 | base = of_iomap(np, 0); | ||
| 287 | if (WARN_ON(!base)) | ||
| 288 | return; | ||
| 289 | |||
| 290 | ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); | ||
| 291 | if (WARN_ON(!ctrl)) | ||
| 292 | goto ctrl_out; | ||
| 293 | |||
| 294 | /* lock must already be initialized */ | ||
| 295 | ctrl->lock = &ctrl_gating_lock; | ||
| 296 | |||
| 297 | /* Count, allocate, and register clock muxes */ | ||
| 298 | for (n = 0; desc[n].name;) | ||
| 299 | n++; | ||
| 300 | |||
| 301 | ctrl->num_muxes = n; | ||
| 302 | ctrl->muxes = kcalloc(ctrl->num_muxes, sizeof(struct clk *), | ||
| 303 | GFP_KERNEL); | ||
| 304 | if (WARN_ON(!ctrl->muxes)) | ||
| 305 | goto muxes_out; | ||
| 306 | |||
| 307 | for (n = 0; n < ctrl->num_muxes; n++) { | ||
| 308 | ctrl->muxes[n] = clk_register_mux(NULL, desc[n].name, | ||
| 309 | desc[n].parents, desc[n].num_parents, | ||
| 310 | desc[n].flags, base, desc[n].shift, | ||
| 311 | desc[n].width, desc[n].flags, ctrl->lock); | ||
| 312 | WARN_ON(IS_ERR(ctrl->muxes[n])); | ||
| 313 | } | ||
| 314 | |||
| 315 | of_clk_add_provider(np, clk_muxing_get_src, ctrl); | ||
| 316 | |||
| 317 | return; | ||
| 318 | muxes_out: | ||
| 319 | kfree(ctrl); | ||
| 320 | ctrl_out: | ||
| 321 | iounmap(base); | ||
| 322 | } | ||
| 323 | |||
| 228 | static void __init kirkwood_clk_init(struct device_node *np) | 324 | static void __init kirkwood_clk_init(struct device_node *np) |
| 229 | { | 325 | { |
| 230 | struct device_node *cgnp = | 326 | struct device_node *cgnp = |
| @@ -236,8 +332,10 @@ static void __init kirkwood_clk_init(struct device_node *np) | |||
| 236 | else | 332 | else |
| 237 | mvebu_coreclk_setup(np, &kirkwood_coreclks); | 333 | mvebu_coreclk_setup(np, &kirkwood_coreclks); |
| 238 | 334 | ||
| 239 | if (cgnp) | 335 | if (cgnp) { |
| 240 | mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc); | 336 | mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc); |
| 337 | kirkwood_clk_muxing_setup(cgnp, kirkwood_mux_desc); | ||
| 338 | } | ||
| 241 | } | 339 | } |
| 242 | CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock", | 340 | CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock", |
| 243 | kirkwood_clk_init); | 341 | kirkwood_clk_init); |
diff --git a/drivers/clk/pxa/Makefile b/drivers/clk/pxa/Makefile new file mode 100644 index 000000000000..4ff2abcd500b --- /dev/null +++ b/drivers/clk/pxa/Makefile | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | obj-y += clk-pxa.o | ||
| 2 | obj-$(CONFIG_PXA27x) += clk-pxa27x.o | ||
diff --git a/drivers/clk/pxa/clk-pxa.c b/drivers/clk/pxa/clk-pxa.c new file mode 100644 index 000000000000..ef3c05389c0a --- /dev/null +++ b/drivers/clk/pxa/clk-pxa.c | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | /* | ||
| 2 | * Marvell PXA family clocks | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Robert Jarzmik | ||
| 5 | * | ||
| 6 | * Common clock code for PXA clocks ("CKEN" type clocks + DT) | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; version 2 of the License. | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | #include <linux/clk.h> | ||
| 14 | #include <linux/clk-provider.h> | ||
| 15 | #include <linux/clkdev.h> | ||
| 16 | #include <linux/of.h> | ||
| 17 | |||
| 18 | #include <dt-bindings/clock/pxa-clock.h> | ||
| 19 | #include "clk-pxa.h" | ||
| 20 | |||
| 21 | DEFINE_SPINLOCK(lock); | ||
| 22 | |||
| 23 | static struct clk *pxa_clocks[CLK_MAX]; | ||
| 24 | static struct clk_onecell_data onecell_data = { | ||
| 25 | .clks = pxa_clocks, | ||
| 26 | .clk_num = CLK_MAX, | ||
| 27 | }; | ||
| 28 | |||
| 29 | #define to_pxa_clk(_hw) container_of(_hw, struct pxa_clk_cken, hw) | ||
| 30 | |||
| 31 | static unsigned long cken_recalc_rate(struct clk_hw *hw, | ||
| 32 | unsigned long parent_rate) | ||
| 33 | { | ||
| 34 | struct pxa_clk_cken *pclk = to_pxa_clk(hw); | ||
| 35 | struct clk_fixed_factor *fix; | ||
| 36 | |||
| 37 | if (!pclk->is_in_low_power || pclk->is_in_low_power()) | ||
| 38 | fix = &pclk->lp; | ||
| 39 | else | ||
| 40 | fix = &pclk->hp; | ||
| 41 | fix->hw.clk = hw->clk; | ||
| 42 | return clk_fixed_factor_ops.recalc_rate(&fix->hw, parent_rate); | ||
| 43 | } | ||
| 44 | |||
| 45 | static struct clk_ops cken_rate_ops = { | ||
| 46 | .recalc_rate = cken_recalc_rate, | ||
| 47 | }; | ||
| 48 | |||
| 49 | static u8 cken_get_parent(struct clk_hw *hw) | ||
| 50 | { | ||
| 51 | struct pxa_clk_cken *pclk = to_pxa_clk(hw); | ||
| 52 | |||
| 53 | if (!pclk->is_in_low_power) | ||
| 54 | return 0; | ||
| 55 | return pclk->is_in_low_power() ? 0 : 1; | ||
| 56 | } | ||
| 57 | |||
| 58 | static struct clk_ops cken_mux_ops = { | ||
| 59 | .get_parent = cken_get_parent, | ||
| 60 | .set_parent = dummy_clk_set_parent, | ||
| 61 | }; | ||
| 62 | |||
| 63 | void __init clkdev_pxa_register(int ckid, const char *con_id, | ||
| 64 | const char *dev_id, struct clk *clk) | ||
| 65 | { | ||
| 66 | if (!IS_ERR(clk) && (ckid != CLK_NONE)) | ||
| 67 | pxa_clocks[ckid] = clk; | ||
| 68 | if (!IS_ERR(clk)) | ||
| 69 | clk_register_clkdev(clk, con_id, dev_id); | ||
| 70 | } | ||
| 71 | |||
| 72 | int __init clk_pxa_cken_init(struct pxa_clk_cken *clks, int nb_clks) | ||
| 73 | { | ||
| 74 | int i; | ||
| 75 | struct pxa_clk_cken *pclk; | ||
| 76 | struct clk *clk; | ||
| 77 | |||
| 78 | for (i = 0; i < nb_clks; i++) { | ||
| 79 | pclk = clks + i; | ||
| 80 | pclk->gate.lock = &lock; | ||
| 81 | clk = clk_register_composite(NULL, pclk->name, | ||
| 82 | pclk->parent_names, 2, | ||
| 83 | &pclk->hw, &cken_mux_ops, | ||
| 84 | &pclk->hw, &cken_rate_ops, | ||
| 85 | &pclk->gate.hw, &clk_gate_ops, | ||
| 86 | pclk->flags); | ||
| 87 | clkdev_pxa_register(pclk->ckid, pclk->con_id, pclk->dev_id, | ||
| 88 | clk); | ||
| 89 | } | ||
| 90 | return 0; | ||
| 91 | } | ||
| 92 | |||
| 93 | static void __init pxa_dt_clocks_init(struct device_node *np) | ||
| 94 | { | ||
| 95 | of_clk_add_provider(np, of_clk_src_onecell_get, &onecell_data); | ||
| 96 | } | ||
| 97 | CLK_OF_DECLARE(pxa_clks, "marvell,pxa-clocks", pxa_dt_clocks_init); | ||
diff --git a/drivers/clk/pxa/clk-pxa.h b/drivers/clk/pxa/clk-pxa.h new file mode 100644 index 000000000000..5fe219d06b49 --- /dev/null +++ b/drivers/clk/pxa/clk-pxa.h | |||
| @@ -0,0 +1,107 @@ | |||
| 1 | /* | ||
| 2 | * Marvell PXA family clocks | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Robert Jarzmik | ||
| 5 | * | ||
| 6 | * Common clock code for PXA clocks ("CKEN" type clocks + DT) | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; version 2 of the License. | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | #ifndef _CLK_PXA_ | ||
| 14 | #define _CLK_PXA_ | ||
| 15 | |||
| 16 | #define PARENTS(name) \ | ||
| 17 | static const char *name ## _parents[] __initconst | ||
| 18 | #define MUX_RO_RATE_RO_OPS(name, clk_name) \ | ||
| 19 | static struct clk_hw name ## _mux_hw; \ | ||
| 20 | static struct clk_hw name ## _rate_hw; \ | ||
| 21 | static struct clk_ops name ## _mux_ops = { \ | ||
| 22 | .get_parent = name ## _get_parent, \ | ||
| 23 | .set_parent = dummy_clk_set_parent, \ | ||
| 24 | }; \ | ||
| 25 | static struct clk_ops name ## _rate_ops = { \ | ||
| 26 | .recalc_rate = name ## _get_rate, \ | ||
| 27 | }; \ | ||
| 28 | static struct clk *clk_register_ ## name(void) \ | ||
| 29 | { \ | ||
| 30 | return clk_register_composite(NULL, clk_name, \ | ||
| 31 | name ## _parents, \ | ||
| 32 | ARRAY_SIZE(name ## _parents), \ | ||
| 33 | &name ## _mux_hw, &name ## _mux_ops, \ | ||
| 34 | &name ## _rate_hw, &name ## _rate_ops, \ | ||
| 35 | NULL, NULL, CLK_GET_RATE_NOCACHE); \ | ||
| 36 | } | ||
| 37 | |||
| 38 | #define RATE_RO_OPS(name, clk_name) \ | ||
| 39 | static struct clk_hw name ## _rate_hw; \ | ||
| 40 | static struct clk_ops name ## _rate_ops = { \ | ||
| 41 | .recalc_rate = name ## _get_rate, \ | ||
| 42 | }; \ | ||
| 43 | static struct clk *clk_register_ ## name(void) \ | ||
| 44 | { \ | ||
| 45 | return clk_register_composite(NULL, clk_name, \ | ||
| 46 | name ## _parents, \ | ||
| 47 | ARRAY_SIZE(name ## _parents), \ | ||
| 48 | NULL, NULL, \ | ||
| 49 | &name ## _rate_hw, &name ## _rate_ops, \ | ||
| 50 | NULL, NULL, CLK_GET_RATE_NOCACHE); \ | ||
| 51 | } | ||
| 52 | |||
| 53 | /* | ||
| 54 | * CKEN clock type | ||
| 55 | * This clock takes it source from 2 possible parents : | ||
| 56 | * - a low power parent | ||
| 57 | * - a normal parent | ||
| 58 | * | ||
| 59 | * +------------+ +-----------+ | ||
| 60 | * | Low Power | --- | x mult_lp | | ||
| 61 | * | Clock | | / div_lp |\ | ||
| 62 | * +------------+ +-----------+ \+-----+ +-----------+ | ||
| 63 | * | Mux |---| CKEN gate | | ||
| 64 | * +------------+ +-----------+ /+-----+ +-----------+ | ||
| 65 | * | High Power | | x mult_hp |/ | ||
| 66 | * | Clock | --- | / div_hp | | ||
| 67 | * +------------+ +-----------+ | ||
| 68 | */ | ||
| 69 | struct pxa_clk_cken { | ||
| 70 | struct clk_hw hw; | ||
| 71 | int ckid; | ||
| 72 | const char *name; | ||
| 73 | const char *dev_id; | ||
| 74 | const char *con_id; | ||
| 75 | const char **parent_names; | ||
| 76 | struct clk_fixed_factor lp; | ||
| 77 | struct clk_fixed_factor hp; | ||
| 78 | struct clk_gate gate; | ||
| 79 | bool (*is_in_low_power)(void); | ||
| 80 | const unsigned long flags; | ||
| 81 | }; | ||
| 82 | |||
| 83 | #define PXA_CKEN(_dev_id, _con_id, _name, parents, _mult_lp, _div_lp, \ | ||
| 84 | _mult_hp, _div_hp, is_lp, _cken_reg, _cken_bit, flag) \ | ||
| 85 | { .ckid = CLK_ ## _name, .name = #_name, \ | ||
| 86 | .dev_id = _dev_id, .con_id = _con_id, .parent_names = parents,\ | ||
| 87 | .lp = { .mult = _mult_lp, .div = _div_lp }, \ | ||
| 88 | .hp = { .mult = _mult_hp, .div = _div_hp }, \ | ||
| 89 | .is_in_low_power = is_lp, \ | ||
| 90 | .gate = { .reg = (void __iomem *)_cken_reg, .bit_idx = _cken_bit }, \ | ||
| 91 | .flags = flag, \ | ||
| 92 | } | ||
| 93 | #define PXA_CKEN_1RATE(dev_id, con_id, name, parents, cken_reg, \ | ||
| 94 | cken_bit, flag) \ | ||
| 95 | PXA_CKEN(dev_id, con_id, name, parents, 1, 1, 1, 1, \ | ||
| 96 | NULL, cken_reg, cken_bit, flag) | ||
| 97 | |||
| 98 | static int dummy_clk_set_parent(struct clk_hw *hw, u8 index) | ||
| 99 | { | ||
| 100 | return 0; | ||
| 101 | } | ||
| 102 | |||
| 103 | extern void clkdev_pxa_register(int ckid, const char *con_id, | ||
| 104 | const char *dev_id, struct clk *clk); | ||
| 105 | extern int clk_pxa_cken_init(struct pxa_clk_cken *clks, int nb_clks); | ||
| 106 | |||
| 107 | #endif | ||
diff --git a/drivers/clk/pxa/clk-pxa27x.c b/drivers/clk/pxa/clk-pxa27x.c new file mode 100644 index 000000000000..b345cc791e5d --- /dev/null +++ b/drivers/clk/pxa/clk-pxa27x.c | |||
| @@ -0,0 +1,370 @@ | |||
| 1 | /* | ||
| 2 | * Marvell PXA27x family clocks | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Robert Jarzmik | ||
| 5 | * | ||
| 6 | * Heavily inspired from former arch/arm/mach-pxa/clock.c. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; version 2 of the License. | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | #include <linux/clk-provider.h> | ||
| 14 | #include <mach/pxa2xx-regs.h> | ||
| 15 | #include <linux/io.h> | ||
| 16 | #include <linux/clk.h> | ||
| 17 | #include <linux/clkdev.h> | ||
| 18 | #include <linux/of.h> | ||
| 19 | |||
| 20 | #include <dt-bindings/clock/pxa-clock.h> | ||
| 21 | #include "clk-pxa.h" | ||
| 22 | |||
| 23 | #define KHz 1000 | ||
| 24 | #define MHz (1000 * 1000) | ||
| 25 | |||
| 26 | enum { | ||
| 27 | PXA_CORE_13Mhz = 0, | ||
| 28 | PXA_CORE_RUN, | ||
| 29 | PXA_CORE_TURBO, | ||
| 30 | }; | ||
| 31 | |||
| 32 | enum { | ||
| 33 | PXA_BUS_13Mhz = 0, | ||
| 34 | PXA_BUS_RUN, | ||
| 35 | }; | ||
| 36 | |||
| 37 | enum { | ||
| 38 | PXA_LCD_13Mhz = 0, | ||
| 39 | PXA_LCD_RUN, | ||
| 40 | }; | ||
| 41 | |||
| 42 | enum { | ||
| 43 | PXA_MEM_13Mhz = 0, | ||
| 44 | PXA_MEM_SYSTEM_BUS, | ||
| 45 | PXA_MEM_RUN, | ||
| 46 | }; | ||
| 47 | |||
| 48 | static const char * const get_freq_khz[] = { | ||
| 49 | "core", "run", "cpll", "memory", | ||
| 50 | "system_bus" | ||
| 51 | }; | ||
| 52 | |||
| 53 | /* | ||
| 54 | * Get the clock frequency as reflected by CCSR and the turbo flag. | ||
| 55 | * We assume these values have been applied via a fcs. | ||
| 56 | * If info is not 0 we also display the current settings. | ||
| 57 | */ | ||
| 58 | unsigned int pxa27x_get_clk_frequency_khz(int info) | ||
| 59 | { | ||
| 60 | struct clk *clk; | ||
| 61 | unsigned long clks[5]; | ||
| 62 | int i; | ||
| 63 | |||
| 64 | for (i = 0; i < 5; i++) { | ||
| 65 | clk = clk_get(NULL, get_freq_khz[i]); | ||
| 66 | if (IS_ERR(clk)) { | ||
| 67 | clks[i] = 0; | ||
| 68 | } else { | ||
| 69 | clks[i] = clk_get_rate(clk); | ||
| 70 | clk_put(clk); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | if (info) { | ||
| 74 | pr_info("Run Mode clock: %ld.%02ldMHz\n", | ||
| 75 | clks[1] / 1000000, (clks[1] % 1000000) / 10000); | ||
| 76 | pr_info("Turbo Mode clock: %ld.%02ldMHz\n", | ||
| 77 | clks[2] / 1000000, (clks[2] % 1000000) / 10000); | ||
| 78 | pr_info("Memory clock: %ld.%02ldMHz\n", | ||
| 79 | clks[3] / 1000000, (clks[3] % 1000000) / 10000); | ||
| 80 | pr_info("System bus clock: %ld.%02ldMHz\n", | ||
| 81 | clks[4] / 1000000, (clks[4] % 1000000) / 10000); | ||
| 82 | } | ||
| 83 | return (unsigned int)clks[0]; | ||
| 84 | } | ||
| 85 | |||
| 86 | bool pxa27x_is_ppll_disabled(void) | ||
| 87 | { | ||
| 88 | unsigned long ccsr = CCSR; | ||
| 89 | |||
| 90 | return ccsr & (1 << CCCR_PPDIS_BIT); | ||
| 91 | } | ||
| 92 | |||
| 93 | #define PXA27X_CKEN(dev_id, con_id, parents, mult_hp, div_hp, \ | ||
| 94 | bit, is_lp, flags) \ | ||
| 95 | PXA_CKEN(dev_id, con_id, bit, parents, 1, 1, mult_hp, div_hp, \ | ||
| 96 | is_lp, &CKEN, CKEN_ ## bit, flags) | ||
| 97 | #define PXA27X_PBUS_CKEN(dev_id, con_id, bit, mult_hp, div_hp, delay) \ | ||
| 98 | PXA27X_CKEN(dev_id, con_id, pxa27x_pbus_parents, mult_hp, \ | ||
| 99 | div_hp, bit, pxa27x_is_ppll_disabled, 0) | ||
| 100 | |||
| 101 | PARENTS(pxa27x_pbus) = { "osc_13mhz", "ppll_312mhz" }; | ||
| 102 | PARENTS(pxa27x_sbus) = { "system_bus", "system_bus" }; | ||
| 103 | PARENTS(pxa27x_32Mhz_bus) = { "osc_32_768khz", "osc_32_768khz" }; | ||
| 104 | PARENTS(pxa27x_lcd_bus) = { "lcd_base", "lcd_base" }; | ||
| 105 | PARENTS(pxa27x_membus) = { "lcd_base", "lcd_base" }; | ||
| 106 | |||
| 107 | #define PXA27X_CKEN_1RATE(dev_id, con_id, bit, parents, delay) \ | ||
| 108 | PXA_CKEN_1RATE(dev_id, con_id, bit, parents, \ | ||
| 109 | &CKEN, CKEN_ ## bit, 0) | ||
| 110 | #define PXA27X_CKEN_1RATE_AO(dev_id, con_id, bit, parents, delay) \ | ||
| 111 | PXA_CKEN_1RATE(dev_id, con_id, bit, parents, \ | ||
| 112 | &CKEN, CKEN_ ## bit, CLK_IGNORE_UNUSED) | ||
| 113 | |||
| 114 | static struct pxa_clk_cken pxa27x_clocks[] = { | ||
| 115 | PXA27X_PBUS_CKEN("pxa2xx-uart.0", NULL, FFUART, 2, 42, 1), | ||
| 116 | PXA27X_PBUS_CKEN("pxa2xx-uart.1", NULL, BTUART, 2, 42, 1), | ||
| 117 | PXA27X_PBUS_CKEN("pxa2xx-uart.2", NULL, STUART, 2, 42, 1), | ||
| 118 | PXA27X_PBUS_CKEN("pxa2xx-i2s", NULL, I2S, 2, 51, 0), | ||
| 119 | PXA27X_PBUS_CKEN("pxa2xx-i2c.0", NULL, I2C, 2, 19, 0), | ||
| 120 | PXA27X_PBUS_CKEN("pxa27x-udc", NULL, USB, 2, 13, 5), | ||
| 121 | PXA27X_PBUS_CKEN("pxa2xx-mci.0", NULL, MMC, 2, 32, 0), | ||
| 122 | PXA27X_PBUS_CKEN("pxa2xx-ir", "FICPCLK", FICP, 2, 13, 0), | ||
| 123 | PXA27X_PBUS_CKEN("pxa27x-ohci", NULL, USBHOST, 2, 13, 0), | ||
| 124 | PXA27X_PBUS_CKEN("pxa2xx-i2c.1", NULL, PWRI2C, 1, 24, 0), | ||
| 125 | PXA27X_PBUS_CKEN("pxa27x-ssp.0", NULL, SSP1, 1, 24, 0), | ||
| 126 | PXA27X_PBUS_CKEN("pxa27x-ssp.1", NULL, SSP2, 1, 24, 0), | ||
| 127 | PXA27X_PBUS_CKEN("pxa27x-ssp.2", NULL, SSP3, 1, 24, 0), | ||
| 128 | PXA27X_PBUS_CKEN("pxa27x-pwm.0", NULL, PWM0, 1, 24, 0), | ||
| 129 | PXA27X_PBUS_CKEN("pxa27x-pwm.1", NULL, PWM1, 1, 24, 0), | ||
| 130 | PXA27X_PBUS_CKEN(NULL, "MSLCLK", MSL, 2, 13, 0), | ||
| 131 | PXA27X_PBUS_CKEN(NULL, "USIMCLK", USIM, 2, 13, 0), | ||
| 132 | PXA27X_PBUS_CKEN(NULL, "MSTKCLK", MEMSTK, 2, 32, 0), | ||
| 133 | PXA27X_PBUS_CKEN(NULL, "AC97CLK", AC97, 1, 1, 0), | ||
| 134 | PXA27X_PBUS_CKEN(NULL, "AC97CONFCLK", AC97CONF, 1, 1, 0), | ||
| 135 | PXA27X_PBUS_CKEN(NULL, "OSTIMER0", OSTIMER, 1, 96, 0), | ||
| 136 | |||
| 137 | PXA27X_CKEN_1RATE("pxa27x-keypad", NULL, KEYPAD, | ||
| 138 | pxa27x_32Mhz_bus_parents, 0), | ||
| 139 | PXA27X_CKEN_1RATE(NULL, "IMCLK", IM, pxa27x_sbus_parents, 0), | ||
| 140 | PXA27X_CKEN_1RATE("pxa2xx-fb", NULL, LCD, pxa27x_lcd_bus_parents, 0), | ||
| 141 | PXA27X_CKEN_1RATE("pxa27x-camera.0", NULL, CAMERA, | ||
| 142 | pxa27x_lcd_bus_parents, 0), | ||
| 143 | PXA27X_CKEN_1RATE_AO("pxa2xx-pcmcia", NULL, MEMC, | ||
| 144 | pxa27x_membus_parents, 0), | ||
| 145 | |||
| 146 | }; | ||
| 147 | |||
| 148 | static unsigned long clk_pxa27x_cpll_get_rate(struct clk_hw *hw, | ||
| 149 | unsigned long parent_rate) | ||
| 150 | { | ||
| 151 | unsigned long clkcfg; | ||
| 152 | unsigned int t, ht; | ||
| 153 | unsigned int l, L, n2, N; | ||
| 154 | unsigned long ccsr = CCSR; | ||
| 155 | |||
| 156 | asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); | ||
| 157 | t = clkcfg & (1 << 0); | ||
| 158 | ht = clkcfg & (1 << 2); | ||
| 159 | |||
| 160 | l = ccsr & CCSR_L_MASK; | ||
| 161 | n2 = (ccsr & CCSR_N2_MASK) >> CCSR_N2_SHIFT; | ||
| 162 | L = l * parent_rate; | ||
| 163 | N = (L * n2) / 2; | ||
| 164 | |||
| 165 | return t ? N : L; | ||
| 166 | } | ||
| 167 | PARENTS(clk_pxa27x_cpll) = { "osc_13mhz" }; | ||
| 168 | RATE_RO_OPS(clk_pxa27x_cpll, "cpll"); | ||
| 169 | |||
| 170 | static unsigned long clk_pxa27x_lcd_base_get_rate(struct clk_hw *hw, | ||
| 171 | unsigned long parent_rate) | ||
| 172 | { | ||
| 173 | unsigned int l, osc_forced; | ||
| 174 | unsigned long ccsr = CCSR; | ||
| 175 | unsigned long cccr = CCCR; | ||
| 176 | |||
| 177 | l = ccsr & CCSR_L_MASK; | ||
| 178 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
| 179 | if (osc_forced) { | ||
| 180 | if (cccr & (1 << CCCR_LCD_26_BIT)) | ||
| 181 | return parent_rate * 2; | ||
| 182 | else | ||
| 183 | return parent_rate; | ||
| 184 | } | ||
| 185 | |||
| 186 | if (l <= 7) | ||
| 187 | return parent_rate; | ||
| 188 | if (l <= 16) | ||
| 189 | return parent_rate / 2; | ||
| 190 | return parent_rate / 4; | ||
| 191 | } | ||
| 192 | |||
| 193 | static u8 clk_pxa27x_lcd_base_get_parent(struct clk_hw *hw) | ||
| 194 | { | ||
| 195 | unsigned int osc_forced; | ||
| 196 | unsigned long ccsr = CCSR; | ||
| 197 | |||
| 198 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
| 199 | if (osc_forced) | ||
| 200 | return PXA_LCD_13Mhz; | ||
| 201 | else | ||
| 202 | return PXA_LCD_RUN; | ||
| 203 | } | ||
| 204 | |||
| 205 | PARENTS(clk_pxa27x_lcd_base) = { "osc_13mhz", "run" }; | ||
| 206 | MUX_RO_RATE_RO_OPS(clk_pxa27x_lcd_base, "lcd_base"); | ||
| 207 | |||
| 208 | static void __init pxa27x_register_plls(void) | ||
| 209 | { | ||
| 210 | clk_register_fixed_rate(NULL, "osc_13mhz", NULL, | ||
| 211 | CLK_GET_RATE_NOCACHE | CLK_IS_ROOT, | ||
| 212 | 13 * MHz); | ||
| 213 | clk_register_fixed_rate(NULL, "osc_32_768khz", NULL, | ||
| 214 | CLK_GET_RATE_NOCACHE | CLK_IS_ROOT, | ||
| 215 | 32768 * KHz); | ||
| 216 | clk_register_fixed_rate(NULL, "clk_dummy", NULL, CLK_IS_ROOT, 0); | ||
| 217 | clk_register_fixed_factor(NULL, "ppll_312mhz", "osc_13mhz", 0, 24, 1); | ||
| 218 | } | ||
| 219 | |||
| 220 | static unsigned long clk_pxa27x_core_get_rate(struct clk_hw *hw, | ||
| 221 | unsigned long parent_rate) | ||
| 222 | { | ||
| 223 | unsigned long clkcfg; | ||
| 224 | unsigned int t, ht, b, osc_forced; | ||
| 225 | unsigned long ccsr = CCSR; | ||
| 226 | |||
| 227 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
| 228 | asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); | ||
| 229 | t = clkcfg & (1 << 0); | ||
| 230 | ht = clkcfg & (1 << 2); | ||
| 231 | b = clkcfg & (1 << 3); | ||
| 232 | |||
| 233 | if (osc_forced) | ||
| 234 | return parent_rate; | ||
| 235 | if (ht) | ||
| 236 | return parent_rate / 2; | ||
| 237 | else | ||
| 238 | return parent_rate; | ||
| 239 | } | ||
| 240 | |||
| 241 | static u8 clk_pxa27x_core_get_parent(struct clk_hw *hw) | ||
| 242 | { | ||
| 243 | unsigned long clkcfg; | ||
| 244 | unsigned int t, ht, b, osc_forced; | ||
| 245 | unsigned long ccsr = CCSR; | ||
| 246 | |||
| 247 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
| 248 | if (osc_forced) | ||
| 249 | return PXA_CORE_13Mhz; | ||
| 250 | |||
| 251 | asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); | ||
| 252 | t = clkcfg & (1 << 0); | ||
| 253 | ht = clkcfg & (1 << 2); | ||
| 254 | b = clkcfg & (1 << 3); | ||
| 255 | |||
| 256 | if (ht || t) | ||
| 257 | return PXA_CORE_TURBO; | ||
| 258 | return PXA_CORE_RUN; | ||
| 259 | } | ||
| 260 | PARENTS(clk_pxa27x_core) = { "osc_13mhz", "run", "cpll" }; | ||
| 261 | MUX_RO_RATE_RO_OPS(clk_pxa27x_core, "core"); | ||
| 262 | |||
| 263 | static unsigned long clk_pxa27x_run_get_rate(struct clk_hw *hw, | ||
| 264 | unsigned long parent_rate) | ||
| 265 | { | ||
| 266 | unsigned long ccsr = CCSR; | ||
| 267 | unsigned int n2 = (ccsr & CCSR_N2_MASK) >> CCSR_N2_SHIFT; | ||
| 268 | |||
| 269 | return (parent_rate / n2) * 2; | ||
| 270 | } | ||
| 271 | PARENTS(clk_pxa27x_run) = { "cpll" }; | ||
| 272 | RATE_RO_OPS(clk_pxa27x_run, "run"); | ||
| 273 | |||
| 274 | static void __init pxa27x_register_core(void) | ||
| 275 | { | ||
| 276 | clk_register_clk_pxa27x_cpll(); | ||
| 277 | clk_register_clk_pxa27x_run(); | ||
| 278 | |||
| 279 | clkdev_pxa_register(CLK_CORE, "core", NULL, | ||
| 280 | clk_register_clk_pxa27x_core()); | ||
| 281 | } | ||
| 282 | |||
| 283 | static unsigned long clk_pxa27x_system_bus_get_rate(struct clk_hw *hw, | ||
| 284 | unsigned long parent_rate) | ||
| 285 | { | ||
| 286 | unsigned long clkcfg; | ||
| 287 | unsigned int b, osc_forced; | ||
| 288 | unsigned long ccsr = CCSR; | ||
| 289 | |||
| 290 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
| 291 | asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); | ||
| 292 | b = clkcfg & (1 << 3); | ||
| 293 | |||
| 294 | if (osc_forced) | ||
| 295 | return parent_rate; | ||
| 296 | if (b) | ||
| 297 | return parent_rate / 2; | ||
| 298 | else | ||
| 299 | return parent_rate; | ||
| 300 | } | ||
| 301 | |||
| 302 | static u8 clk_pxa27x_system_bus_get_parent(struct clk_hw *hw) | ||
| 303 | { | ||
| 304 | unsigned int osc_forced; | ||
| 305 | unsigned long ccsr = CCSR; | ||
| 306 | |||
| 307 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
| 308 | if (osc_forced) | ||
| 309 | return PXA_BUS_13Mhz; | ||
| 310 | else | ||
| 311 | return PXA_BUS_RUN; | ||
| 312 | } | ||
| 313 | |||
| 314 | PARENTS(clk_pxa27x_system_bus) = { "osc_13mhz", "run" }; | ||
| 315 | MUX_RO_RATE_RO_OPS(clk_pxa27x_system_bus, "system_bus"); | ||
| 316 | |||
| 317 | static unsigned long clk_pxa27x_memory_get_rate(struct clk_hw *hw, | ||
| 318 | unsigned long parent_rate) | ||
| 319 | { | ||
| 320 | unsigned int a, l, osc_forced; | ||
| 321 | unsigned long cccr = CCCR; | ||
| 322 | unsigned long ccsr = CCSR; | ||
| 323 | |||
| 324 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
| 325 | a = cccr & CCCR_A_BIT; | ||
| 326 | l = ccsr & CCSR_L_MASK; | ||
| 327 | |||
| 328 | if (osc_forced || a) | ||
| 329 | return parent_rate; | ||
| 330 | if (l <= 10) | ||
| 331 | return parent_rate; | ||
| 332 | if (l <= 20) | ||
| 333 | return parent_rate / 2; | ||
| 334 | return parent_rate / 4; | ||
| 335 | } | ||
| 336 | |||
| 337 | static u8 clk_pxa27x_memory_get_parent(struct clk_hw *hw) | ||
| 338 | { | ||
| 339 | unsigned int osc_forced, a; | ||
| 340 | unsigned long cccr = CCCR; | ||
| 341 | unsigned long ccsr = CCSR; | ||
| 342 | |||
| 343 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
| 344 | a = cccr & CCCR_A_BIT; | ||
| 345 | if (osc_forced) | ||
| 346 | return PXA_MEM_13Mhz; | ||
| 347 | if (a) | ||
| 348 | return PXA_MEM_SYSTEM_BUS; | ||
| 349 | else | ||
| 350 | return PXA_MEM_RUN; | ||
| 351 | } | ||
| 352 | |||
| 353 | PARENTS(clk_pxa27x_memory) = { "osc_13mhz", "system_bus", "run" }; | ||
| 354 | MUX_RO_RATE_RO_OPS(clk_pxa27x_memory, "memory"); | ||
| 355 | |||
| 356 | static void __init pxa27x_base_clocks_init(void) | ||
| 357 | { | ||
| 358 | pxa27x_register_plls(); | ||
| 359 | pxa27x_register_core(); | ||
| 360 | clk_register_clk_pxa27x_system_bus(); | ||
| 361 | clk_register_clk_pxa27x_memory(); | ||
| 362 | clk_register_clk_pxa27x_lcd_base(); | ||
| 363 | } | ||
| 364 | |||
| 365 | static int __init pxa27x_clocks_init(void) | ||
| 366 | { | ||
| 367 | pxa27x_base_clocks_init(); | ||
| 368 | return clk_pxa_cken_init(pxa27x_clocks, ARRAY_SIZE(pxa27x_clocks)); | ||
| 369 | } | ||
| 370 | postcore_initcall(pxa27x_clocks_init); | ||
diff --git a/drivers/clk/qcom/clk-pll.c b/drivers/clk/qcom/clk-pll.c index 9db03d3b1657..b823bc3b6250 100644 --- a/drivers/clk/qcom/clk-pll.c +++ b/drivers/clk/qcom/clk-pll.c | |||
| @@ -97,7 +97,7 @@ static unsigned long | |||
| 97 | clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | 97 | clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) |
| 98 | { | 98 | { |
| 99 | struct clk_pll *pll = to_clk_pll(hw); | 99 | struct clk_pll *pll = to_clk_pll(hw); |
| 100 | u32 l, m, n; | 100 | u32 l, m, n, config; |
| 101 | unsigned long rate; | 101 | unsigned long rate; |
| 102 | u64 tmp; | 102 | u64 tmp; |
| 103 | 103 | ||
| @@ -116,13 +116,79 @@ clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | |||
| 116 | do_div(tmp, n); | 116 | do_div(tmp, n); |
| 117 | rate += tmp; | 117 | rate += tmp; |
| 118 | } | 118 | } |
| 119 | if (pll->post_div_width) { | ||
| 120 | regmap_read(pll->clkr.regmap, pll->config_reg, &config); | ||
| 121 | config >>= pll->post_div_shift; | ||
| 122 | config &= BIT(pll->post_div_width) - 1; | ||
| 123 | rate /= config + 1; | ||
| 124 | } | ||
| 125 | |||
| 119 | return rate; | 126 | return rate; |
| 120 | } | 127 | } |
| 121 | 128 | ||
| 129 | static const | ||
| 130 | struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate) | ||
| 131 | { | ||
| 132 | if (!f) | ||
| 133 | return NULL; | ||
| 134 | |||
| 135 | for (; f->freq; f++) | ||
| 136 | if (rate <= f->freq) | ||
| 137 | return f; | ||
| 138 | |||
| 139 | return NULL; | ||
| 140 | } | ||
| 141 | |||
| 142 | static long | ||
| 143 | clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate, | ||
| 144 | unsigned long *p_rate, struct clk **p) | ||
| 145 | { | ||
| 146 | struct clk_pll *pll = to_clk_pll(hw); | ||
| 147 | const struct pll_freq_tbl *f; | ||
| 148 | |||
| 149 | f = find_freq(pll->freq_tbl, rate); | ||
| 150 | if (!f) | ||
| 151 | return clk_pll_recalc_rate(hw, *p_rate); | ||
| 152 | |||
| 153 | return f->freq; | ||
| 154 | } | ||
| 155 | |||
| 156 | static int | ||
| 157 | clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long p_rate) | ||
| 158 | { | ||
| 159 | struct clk_pll *pll = to_clk_pll(hw); | ||
| 160 | const struct pll_freq_tbl *f; | ||
| 161 | bool enabled; | ||
| 162 | u32 mode; | ||
| 163 | u32 enable_mask = PLL_OUTCTRL | PLL_BYPASSNL | PLL_RESET_N; | ||
| 164 | |||
| 165 | f = find_freq(pll->freq_tbl, rate); | ||
| 166 | if (!f) | ||
| 167 | return -EINVAL; | ||
| 168 | |||
| 169 | regmap_read(pll->clkr.regmap, pll->mode_reg, &mode); | ||
| 170 | enabled = (mode & enable_mask) == enable_mask; | ||
| 171 | |||
| 172 | if (enabled) | ||
| 173 | clk_pll_disable(hw); | ||
| 174 | |||
| 175 | regmap_update_bits(pll->clkr.regmap, pll->l_reg, 0x3ff, f->l); | ||
| 176 | regmap_update_bits(pll->clkr.regmap, pll->m_reg, 0x7ffff, f->m); | ||
| 177 | regmap_update_bits(pll->clkr.regmap, pll->n_reg, 0x7ffff, f->n); | ||
| 178 | regmap_write(pll->clkr.regmap, pll->config_reg, f->ibits); | ||
| 179 | |||
| 180 | if (enabled) | ||
| 181 | clk_pll_enable(hw); | ||
| 182 | |||
| 183 | return 0; | ||
| 184 | } | ||
| 185 | |||
| 122 | const struct clk_ops clk_pll_ops = { | 186 | const struct clk_ops clk_pll_ops = { |
| 123 | .enable = clk_pll_enable, | 187 | .enable = clk_pll_enable, |
| 124 | .disable = clk_pll_disable, | 188 | .disable = clk_pll_disable, |
| 125 | .recalc_rate = clk_pll_recalc_rate, | 189 | .recalc_rate = clk_pll_recalc_rate, |
| 190 | .determine_rate = clk_pll_determine_rate, | ||
| 191 | .set_rate = clk_pll_set_rate, | ||
| 126 | }; | 192 | }; |
| 127 | EXPORT_SYMBOL_GPL(clk_pll_ops); | 193 | EXPORT_SYMBOL_GPL(clk_pll_ops); |
| 128 | 194 | ||
diff --git a/drivers/clk/qcom/clk-pll.h b/drivers/clk/qcom/clk-pll.h index 3003e9962472..c9c0cda306d0 100644 --- a/drivers/clk/qcom/clk-pll.h +++ b/drivers/clk/qcom/clk-pll.h | |||
| @@ -18,6 +18,21 @@ | |||
| 18 | #include "clk-regmap.h" | 18 | #include "clk-regmap.h" |
| 19 | 19 | ||
| 20 | /** | 20 | /** |
| 21 | * struct pll_freq_tbl - PLL frequency table | ||
| 22 | * @l: L value | ||
| 23 | * @m: M value | ||
| 24 | * @n: N value | ||
| 25 | * @ibits: internal values | ||
| 26 | */ | ||
| 27 | struct pll_freq_tbl { | ||
| 28 | unsigned long freq; | ||
| 29 | u16 l; | ||
| 30 | u16 m; | ||
| 31 | u16 n; | ||
| 32 | u32 ibits; | ||
| 33 | }; | ||
| 34 | |||
| 35 | /** | ||
| 21 | * struct clk_pll - phase locked loop (PLL) | 36 | * struct clk_pll - phase locked loop (PLL) |
| 22 | * @l_reg: L register | 37 | * @l_reg: L register |
| 23 | * @m_reg: M register | 38 | * @m_reg: M register |
| @@ -26,6 +41,7 @@ | |||
| 26 | * @mode_reg: mode register | 41 | * @mode_reg: mode register |
| 27 | * @status_reg: status register | 42 | * @status_reg: status register |
| 28 | * @status_bit: ANDed with @status_reg to determine if PLL is enabled | 43 | * @status_bit: ANDed with @status_reg to determine if PLL is enabled |
| 44 | * @freq_tbl: PLL frequency table | ||
| 29 | * @hw: handle between common and hardware-specific interfaces | 45 | * @hw: handle between common and hardware-specific interfaces |
| 30 | */ | 46 | */ |
| 31 | struct clk_pll { | 47 | struct clk_pll { |
| @@ -36,6 +52,10 @@ struct clk_pll { | |||
| 36 | u32 mode_reg; | 52 | u32 mode_reg; |
| 37 | u32 status_reg; | 53 | u32 status_reg; |
| 38 | u8 status_bit; | 54 | u8 status_bit; |
| 55 | u8 post_div_width; | ||
| 56 | u8 post_div_shift; | ||
| 57 | |||
| 58 | const struct pll_freq_tbl *freq_tbl; | ||
| 39 | 59 | ||
| 40 | struct clk_regmap clkr; | 60 | struct clk_regmap clkr; |
| 41 | }; | 61 | }; |
diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c index b638c5846dbf..b6e6959e89aa 100644 --- a/drivers/clk/qcom/clk-rcg.c +++ b/drivers/clk/qcom/clk-rcg.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <asm/div64.h> | 21 | #include <asm/div64.h> |
| 22 | 22 | ||
| 23 | #include "clk-rcg.h" | 23 | #include "clk-rcg.h" |
| 24 | #include "common.h" | ||
| 24 | 25 | ||
| 25 | static u32 ns_to_src(struct src_sel *s, u32 ns) | 26 | static u32 ns_to_src(struct src_sel *s, u32 ns) |
| 26 | { | 27 | { |
| @@ -67,16 +68,16 @@ static u8 clk_dyn_rcg_get_parent(struct clk_hw *hw) | |||
| 67 | { | 68 | { |
| 68 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); | 69 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); |
| 69 | int num_parents = __clk_get_num_parents(hw->clk); | 70 | int num_parents = __clk_get_num_parents(hw->clk); |
| 70 | u32 ns, ctl; | 71 | u32 ns, reg; |
| 71 | int bank; | 72 | int bank; |
| 72 | int i; | 73 | int i; |
| 73 | struct src_sel *s; | 74 | struct src_sel *s; |
| 74 | 75 | ||
| 75 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &ctl); | 76 | regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); |
| 76 | bank = reg_to_bank(rcg, ctl); | 77 | bank = reg_to_bank(rcg, reg); |
| 77 | s = &rcg->s[bank]; | 78 | s = &rcg->s[bank]; |
| 78 | 79 | ||
| 79 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | 80 | regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns); |
| 80 | ns = ns_to_src(s, ns); | 81 | ns = ns_to_src(s, ns); |
| 81 | 82 | ||
| 82 | for (i = 0; i < num_parents; i++) | 83 | for (i = 0; i < num_parents; i++) |
| @@ -192,90 +193,93 @@ static u32 mn_to_reg(struct mn *mn, u32 m, u32 n, u32 val) | |||
| 192 | 193 | ||
| 193 | static void configure_bank(struct clk_dyn_rcg *rcg, const struct freq_tbl *f) | 194 | static void configure_bank(struct clk_dyn_rcg *rcg, const struct freq_tbl *f) |
| 194 | { | 195 | { |
| 195 | u32 ns, md, ctl, *regp; | 196 | u32 ns, md, reg; |
| 196 | int bank, new_bank; | 197 | int bank, new_bank; |
| 197 | struct mn *mn; | 198 | struct mn *mn; |
| 198 | struct pre_div *p; | 199 | struct pre_div *p; |
| 199 | struct src_sel *s; | 200 | struct src_sel *s; |
| 200 | bool enabled; | 201 | bool enabled; |
| 201 | u32 md_reg; | 202 | u32 md_reg, ns_reg; |
| 202 | u32 bank_reg; | ||
| 203 | bool banked_mn = !!rcg->mn[1].width; | 203 | bool banked_mn = !!rcg->mn[1].width; |
| 204 | bool banked_p = !!rcg->p[1].pre_div_width; | ||
| 204 | struct clk_hw *hw = &rcg->clkr.hw; | 205 | struct clk_hw *hw = &rcg->clkr.hw; |
| 205 | 206 | ||
| 206 | enabled = __clk_is_enabled(hw->clk); | 207 | enabled = __clk_is_enabled(hw->clk); |
| 207 | 208 | ||
| 208 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | 209 | regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); |
| 209 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &ctl); | 210 | bank = reg_to_bank(rcg, reg); |
| 210 | |||
| 211 | if (banked_mn) { | ||
| 212 | regp = &ctl; | ||
| 213 | bank_reg = rcg->clkr.enable_reg; | ||
| 214 | } else { | ||
| 215 | regp = &ns; | ||
| 216 | bank_reg = rcg->ns_reg; | ||
| 217 | } | ||
| 218 | |||
| 219 | bank = reg_to_bank(rcg, *regp); | ||
| 220 | new_bank = enabled ? !bank : bank; | 211 | new_bank = enabled ? !bank : bank; |
| 221 | 212 | ||
| 213 | ns_reg = rcg->ns_reg[new_bank]; | ||
| 214 | regmap_read(rcg->clkr.regmap, ns_reg, &ns); | ||
| 215 | |||
| 222 | if (banked_mn) { | 216 | if (banked_mn) { |
| 223 | mn = &rcg->mn[new_bank]; | 217 | mn = &rcg->mn[new_bank]; |
| 224 | md_reg = rcg->md_reg[new_bank]; | 218 | md_reg = rcg->md_reg[new_bank]; |
| 225 | 219 | ||
| 226 | ns |= BIT(mn->mnctr_reset_bit); | 220 | ns |= BIT(mn->mnctr_reset_bit); |
| 227 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | 221 | regmap_write(rcg->clkr.regmap, ns_reg, ns); |
| 228 | 222 | ||
| 229 | regmap_read(rcg->clkr.regmap, md_reg, &md); | 223 | regmap_read(rcg->clkr.regmap, md_reg, &md); |
| 230 | md = mn_to_md(mn, f->m, f->n, md); | 224 | md = mn_to_md(mn, f->m, f->n, md); |
| 231 | regmap_write(rcg->clkr.regmap, md_reg, md); | 225 | regmap_write(rcg->clkr.regmap, md_reg, md); |
| 232 | 226 | ||
| 233 | ns = mn_to_ns(mn, f->m, f->n, ns); | 227 | ns = mn_to_ns(mn, f->m, f->n, ns); |
| 234 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | 228 | regmap_write(rcg->clkr.regmap, ns_reg, ns); |
| 235 | 229 | ||
| 236 | ctl = mn_to_reg(mn, f->m, f->n, ctl); | 230 | /* Two NS registers means mode control is in NS register */ |
| 237 | regmap_write(rcg->clkr.regmap, rcg->clkr.enable_reg, ctl); | 231 | if (rcg->ns_reg[0] != rcg->ns_reg[1]) { |
| 232 | ns = mn_to_reg(mn, f->m, f->n, ns); | ||
| 233 | regmap_write(rcg->clkr.regmap, ns_reg, ns); | ||
| 234 | } else { | ||
| 235 | reg = mn_to_reg(mn, f->m, f->n, reg); | ||
| 236 | regmap_write(rcg->clkr.regmap, rcg->bank_reg, reg); | ||
| 237 | } | ||
| 238 | 238 | ||
| 239 | ns &= ~BIT(mn->mnctr_reset_bit); | 239 | ns &= ~BIT(mn->mnctr_reset_bit); |
| 240 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | 240 | regmap_write(rcg->clkr.regmap, ns_reg, ns); |
| 241 | } else { | 241 | } |
| 242 | |||
| 243 | if (banked_p) { | ||
| 242 | p = &rcg->p[new_bank]; | 244 | p = &rcg->p[new_bank]; |
| 243 | ns = pre_div_to_ns(p, f->pre_div - 1, ns); | 245 | ns = pre_div_to_ns(p, f->pre_div - 1, ns); |
| 244 | } | 246 | } |
| 245 | 247 | ||
| 246 | s = &rcg->s[new_bank]; | 248 | s = &rcg->s[new_bank]; |
| 247 | ns = src_to_ns(s, s->parent_map[f->src], ns); | 249 | ns = src_to_ns(s, s->parent_map[f->src], ns); |
| 248 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | 250 | regmap_write(rcg->clkr.regmap, ns_reg, ns); |
| 249 | 251 | ||
| 250 | if (enabled) { | 252 | if (enabled) { |
| 251 | *regp ^= BIT(rcg->mux_sel_bit); | 253 | regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); |
| 252 | regmap_write(rcg->clkr.regmap, bank_reg, *regp); | 254 | reg ^= BIT(rcg->mux_sel_bit); |
| 255 | regmap_write(rcg->clkr.regmap, rcg->bank_reg, reg); | ||
| 253 | } | 256 | } |
| 254 | } | 257 | } |
| 255 | 258 | ||
| 256 | static int clk_dyn_rcg_set_parent(struct clk_hw *hw, u8 index) | 259 | static int clk_dyn_rcg_set_parent(struct clk_hw *hw, u8 index) |
| 257 | { | 260 | { |
| 258 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); | 261 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); |
| 259 | u32 ns, ctl, md, reg; | 262 | u32 ns, md, reg; |
| 260 | int bank; | 263 | int bank; |
| 261 | struct freq_tbl f = { 0 }; | 264 | struct freq_tbl f = { 0 }; |
| 262 | bool banked_mn = !!rcg->mn[1].width; | 265 | bool banked_mn = !!rcg->mn[1].width; |
| 266 | bool banked_p = !!rcg->p[1].pre_div_width; | ||
| 263 | 267 | ||
| 264 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | 268 | regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); |
| 265 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &ctl); | ||
| 266 | reg = banked_mn ? ctl : ns; | ||
| 267 | |||
| 268 | bank = reg_to_bank(rcg, reg); | 269 | bank = reg_to_bank(rcg, reg); |
| 269 | 270 | ||
| 271 | regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns); | ||
| 272 | |||
| 270 | if (banked_mn) { | 273 | if (banked_mn) { |
| 271 | regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md); | 274 | regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md); |
| 272 | f.m = md_to_m(&rcg->mn[bank], md); | 275 | f.m = md_to_m(&rcg->mn[bank], md); |
| 273 | f.n = ns_m_to_n(&rcg->mn[bank], ns, f.m); | 276 | f.n = ns_m_to_n(&rcg->mn[bank], ns, f.m); |
| 274 | } else { | ||
| 275 | f.pre_div = ns_to_pre_div(&rcg->p[bank], ns) + 1; | ||
| 276 | } | 277 | } |
| 277 | f.src = index; | ||
| 278 | 278 | ||
| 279 | if (banked_p) | ||
| 280 | f.pre_div = ns_to_pre_div(&rcg->p[bank], ns) + 1; | ||
| 281 | |||
| 282 | f.src = index; | ||
| 279 | configure_bank(rcg, &f); | 283 | configure_bank(rcg, &f); |
| 280 | 284 | ||
| 281 | return 0; | 285 | return 0; |
| @@ -336,41 +340,30 @@ clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | |||
| 336 | u32 m, n, pre_div, ns, md, mode, reg; | 340 | u32 m, n, pre_div, ns, md, mode, reg; |
| 337 | int bank; | 341 | int bank; |
| 338 | struct mn *mn; | 342 | struct mn *mn; |
| 343 | bool banked_p = !!rcg->p[1].pre_div_width; | ||
| 339 | bool banked_mn = !!rcg->mn[1].width; | 344 | bool banked_mn = !!rcg->mn[1].width; |
| 340 | 345 | ||
| 341 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | 346 | regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); |
| 342 | |||
| 343 | if (banked_mn) | ||
| 344 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, ®); | ||
| 345 | else | ||
| 346 | reg = ns; | ||
| 347 | |||
| 348 | bank = reg_to_bank(rcg, reg); | 347 | bank = reg_to_bank(rcg, reg); |
| 349 | 348 | ||
| 349 | regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns); | ||
| 350 | m = n = pre_div = mode = 0; | ||
| 351 | |||
| 350 | if (banked_mn) { | 352 | if (banked_mn) { |
| 351 | mn = &rcg->mn[bank]; | 353 | mn = &rcg->mn[bank]; |
| 352 | regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md); | 354 | regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md); |
| 353 | m = md_to_m(mn, md); | 355 | m = md_to_m(mn, md); |
| 354 | n = ns_m_to_n(mn, ns, m); | 356 | n = ns_m_to_n(mn, ns, m); |
| 357 | /* Two NS registers means mode control is in NS register */ | ||
| 358 | if (rcg->ns_reg[0] != rcg->ns_reg[1]) | ||
| 359 | reg = ns; | ||
| 355 | mode = reg_to_mnctr_mode(mn, reg); | 360 | mode = reg_to_mnctr_mode(mn, reg); |
| 356 | return calc_rate(parent_rate, m, n, mode, 0); | ||
| 357 | } else { | ||
| 358 | pre_div = ns_to_pre_div(&rcg->p[bank], ns); | ||
| 359 | return calc_rate(parent_rate, 0, 0, 0, pre_div); | ||
| 360 | } | 361 | } |
| 361 | } | ||
| 362 | 362 | ||
| 363 | static const | 363 | if (banked_p) |
| 364 | struct freq_tbl *find_freq(const struct freq_tbl *f, unsigned long rate) | 364 | pre_div = ns_to_pre_div(&rcg->p[bank], ns); |
| 365 | { | ||
| 366 | if (!f) | ||
| 367 | return NULL; | ||
| 368 | |||
| 369 | for (; f->freq; f++) | ||
| 370 | if (rate <= f->freq) | ||
| 371 | return f; | ||
| 372 | 365 | ||
| 373 | return NULL; | 366 | return calc_rate(parent_rate, m, n, mode, pre_div); |
| 374 | } | 367 | } |
| 375 | 368 | ||
| 376 | static long _freq_tbl_determine_rate(struct clk_hw *hw, | 369 | static long _freq_tbl_determine_rate(struct clk_hw *hw, |
| @@ -379,7 +372,7 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw, | |||
| 379 | { | 372 | { |
| 380 | unsigned long clk_flags; | 373 | unsigned long clk_flags; |
| 381 | 374 | ||
| 382 | f = find_freq(f, rate); | 375 | f = qcom_find_freq(f, rate); |
| 383 | if (!f) | 376 | if (!f) |
| 384 | return -EINVAL; | 377 | return -EINVAL; |
| 385 | 378 | ||
| @@ -477,7 +470,7 @@ static int clk_rcg_set_rate(struct clk_hw *hw, unsigned long rate, | |||
| 477 | struct clk_rcg *rcg = to_clk_rcg(hw); | 470 | struct clk_rcg *rcg = to_clk_rcg(hw); |
| 478 | const struct freq_tbl *f; | 471 | const struct freq_tbl *f; |
| 479 | 472 | ||
| 480 | f = find_freq(rcg->freq_tbl, rate); | 473 | f = qcom_find_freq(rcg->freq_tbl, rate); |
| 481 | if (!f) | 474 | if (!f) |
| 482 | return -EINVAL; | 475 | return -EINVAL; |
| 483 | 476 | ||
| @@ -497,7 +490,7 @@ static int __clk_dyn_rcg_set_rate(struct clk_hw *hw, unsigned long rate) | |||
| 497 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); | 490 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); |
| 498 | const struct freq_tbl *f; | 491 | const struct freq_tbl *f; |
| 499 | 492 | ||
| 500 | f = find_freq(rcg->freq_tbl, rate); | 493 | f = qcom_find_freq(rcg->freq_tbl, rate); |
| 501 | if (!f) | 494 | if (!f) |
| 502 | return -EINVAL; | 495 | return -EINVAL; |
| 503 | 496 | ||
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index ba0523cefd2e..687e41f91d7c 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h | |||
| @@ -103,8 +103,9 @@ extern const struct clk_ops clk_rcg_bypass_ops; | |||
| 103 | * struct clk_dyn_rcg - root clock generator with glitch free mux | 103 | * struct clk_dyn_rcg - root clock generator with glitch free mux |
| 104 | * | 104 | * |
| 105 | * @mux_sel_bit: bit to switch glitch free mux | 105 | * @mux_sel_bit: bit to switch glitch free mux |
| 106 | * @ns_reg: NS register | 106 | * @ns_reg: NS0 and NS1 register |
| 107 | * @md_reg: MD0 and MD1 register | 107 | * @md_reg: MD0 and MD1 register |
| 108 | * @bank_reg: register to XOR @mux_sel_bit into to switch glitch free mux | ||
| 108 | * @mn: mn counter (banked) | 109 | * @mn: mn counter (banked) |
| 109 | * @s: source selector (banked) | 110 | * @s: source selector (banked) |
| 110 | * @freq_tbl: frequency table | 111 | * @freq_tbl: frequency table |
| @@ -113,8 +114,9 @@ extern const struct clk_ops clk_rcg_bypass_ops; | |||
| 113 | * | 114 | * |
| 114 | */ | 115 | */ |
| 115 | struct clk_dyn_rcg { | 116 | struct clk_dyn_rcg { |
| 116 | u32 ns_reg; | 117 | u32 ns_reg[2]; |
| 117 | u32 md_reg[2]; | 118 | u32 md_reg[2]; |
| 119 | u32 bank_reg; | ||
| 118 | 120 | ||
| 119 | u8 mux_sel_bit; | 121 | u8 mux_sel_bit; |
| 120 | 122 | ||
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index cd185d5cc67a..cfa9eb4fe9ca 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <asm/div64.h> | 24 | #include <asm/div64.h> |
| 25 | 25 | ||
| 26 | #include "clk-rcg.h" | 26 | #include "clk-rcg.h" |
| 27 | #include "common.h" | ||
| 27 | 28 | ||
| 28 | #define CMD_REG 0x0 | 29 | #define CMD_REG 0x0 |
| 29 | #define CMD_UPDATE BIT(0) | 30 | #define CMD_UPDATE BIT(0) |
| @@ -172,27 +173,13 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | |||
| 172 | return calc_rate(parent_rate, m, n, mode, hid_div); | 173 | return calc_rate(parent_rate, m, n, mode, hid_div); |
| 173 | } | 174 | } |
| 174 | 175 | ||
| 175 | static const | ||
| 176 | struct freq_tbl *find_freq(const struct freq_tbl *f, unsigned long rate) | ||
| 177 | { | ||
| 178 | if (!f) | ||
| 179 | return NULL; | ||
| 180 | |||
| 181 | for (; f->freq; f++) | ||
| 182 | if (rate <= f->freq) | ||
| 183 | return f; | ||
| 184 | |||
| 185 | /* Default to our fastest rate */ | ||
| 186 | return f - 1; | ||
| 187 | } | ||
| 188 | |||
| 189 | static long _freq_tbl_determine_rate(struct clk_hw *hw, | 176 | static long _freq_tbl_determine_rate(struct clk_hw *hw, |
| 190 | const struct freq_tbl *f, unsigned long rate, | 177 | const struct freq_tbl *f, unsigned long rate, |
| 191 | unsigned long *p_rate, struct clk **p) | 178 | unsigned long *p_rate, struct clk **p) |
| 192 | { | 179 | { |
| 193 | unsigned long clk_flags; | 180 | unsigned long clk_flags; |
| 194 | 181 | ||
| 195 | f = find_freq(f, rate); | 182 | f = qcom_find_freq(f, rate); |
| 196 | if (!f) | 183 | if (!f) |
| 197 | return -EINVAL; | 184 | return -EINVAL; |
| 198 | 185 | ||
| @@ -268,7 +255,7 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate) | |||
| 268 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | 255 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); |
| 269 | const struct freq_tbl *f; | 256 | const struct freq_tbl *f; |
| 270 | 257 | ||
| 271 | f = find_freq(rcg->freq_tbl, rate); | 258 | f = qcom_find_freq(rcg->freq_tbl, rate); |
| 272 | if (!f) | 259 | if (!f) |
| 273 | return -EINVAL; | 260 | return -EINVAL; |
| 274 | 261 | ||
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index eeb3eea01f4c..e20d947db3e5 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <linux/reset-controller.h> | 18 | #include <linux/reset-controller.h> |
| 19 | 19 | ||
| 20 | #include "common.h" | 20 | #include "common.h" |
| 21 | #include "clk-rcg.h" | ||
| 21 | #include "clk-regmap.h" | 22 | #include "clk-regmap.h" |
| 22 | #include "reset.h" | 23 | #include "reset.h" |
| 23 | 24 | ||
| @@ -27,6 +28,21 @@ struct qcom_cc { | |||
| 27 | struct clk *clks[]; | 28 | struct clk *clks[]; |
| 28 | }; | 29 | }; |
| 29 | 30 | ||
| 31 | const | ||
| 32 | struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, unsigned long rate) | ||
| 33 | { | ||
| 34 | if (!f) | ||
| 35 | return NULL; | ||
| 36 | |||
| 37 | for (; f->freq; f++) | ||
| 38 | if (rate <= f->freq) | ||
| 39 | return f; | ||
| 40 | |||
| 41 | /* Default to our fastest rate */ | ||
| 42 | return f - 1; | ||
| 43 | } | ||
| 44 | EXPORT_SYMBOL_GPL(qcom_find_freq); | ||
| 45 | |||
| 30 | struct regmap * | 46 | struct regmap * |
| 31 | qcom_cc_map(struct platform_device *pdev, const struct qcom_cc_desc *desc) | 47 | qcom_cc_map(struct platform_device *pdev, const struct qcom_cc_desc *desc) |
| 32 | { | 48 | { |
diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h index 2765e9d3da97..f519322acdf3 100644 --- a/drivers/clk/qcom/common.h +++ b/drivers/clk/qcom/common.h | |||
| @@ -18,6 +18,7 @@ struct regmap_config; | |||
| 18 | struct clk_regmap; | 18 | struct clk_regmap; |
| 19 | struct qcom_reset_map; | 19 | struct qcom_reset_map; |
| 20 | struct regmap; | 20 | struct regmap; |
| 21 | struct freq_tbl; | ||
| 21 | 22 | ||
| 22 | struct qcom_cc_desc { | 23 | struct qcom_cc_desc { |
| 23 | const struct regmap_config *config; | 24 | const struct regmap_config *config; |
| @@ -27,6 +28,9 @@ struct qcom_cc_desc { | |||
| 27 | size_t num_resets; | 28 | size_t num_resets; |
| 28 | }; | 29 | }; |
| 29 | 30 | ||
| 31 | extern const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, | ||
| 32 | unsigned long rate); | ||
| 33 | |||
| 30 | extern struct regmap *qcom_cc_map(struct platform_device *pdev, | 34 | extern struct regmap *qcom_cc_map(struct platform_device *pdev, |
| 31 | const struct qcom_cc_desc *desc); | 35 | const struct qcom_cc_desc *desc); |
| 32 | extern int qcom_cc_really_probe(struct platform_device *pdev, | 36 | extern int qcom_cc_really_probe(struct platform_device *pdev, |
diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c index 3b83b7dd78c7..5cd62a709ac7 100644 --- a/drivers/clk/qcom/gcc-ipq806x.c +++ b/drivers/clk/qcom/gcc-ipq806x.c | |||
| @@ -32,6 +32,33 @@ | |||
| 32 | #include "clk-branch.h" | 32 | #include "clk-branch.h" |
| 33 | #include "reset.h" | 33 | #include "reset.h" |
| 34 | 34 | ||
| 35 | static struct clk_pll pll0 = { | ||
| 36 | .l_reg = 0x30c4, | ||
| 37 | .m_reg = 0x30c8, | ||
| 38 | .n_reg = 0x30cc, | ||
| 39 | .config_reg = 0x30d4, | ||
| 40 | .mode_reg = 0x30c0, | ||
| 41 | .status_reg = 0x30d8, | ||
| 42 | .status_bit = 16, | ||
| 43 | .clkr.hw.init = &(struct clk_init_data){ | ||
| 44 | .name = "pll0", | ||
| 45 | .parent_names = (const char *[]){ "pxo" }, | ||
| 46 | .num_parents = 1, | ||
| 47 | .ops = &clk_pll_ops, | ||
| 48 | }, | ||
| 49 | }; | ||
| 50 | |||
| 51 | static struct clk_regmap pll0_vote = { | ||
| 52 | .enable_reg = 0x34c0, | ||
| 53 | .enable_mask = BIT(0), | ||
| 54 | .hw.init = &(struct clk_init_data){ | ||
| 55 | .name = "pll0_vote", | ||
| 56 | .parent_names = (const char *[]){ "pll0" }, | ||
| 57 | .num_parents = 1, | ||
| 58 | .ops = &clk_pll_vote_ops, | ||
| 59 | }, | ||
| 60 | }; | ||
| 61 | |||
| 35 | static struct clk_pll pll3 = { | 62 | static struct clk_pll pll3 = { |
| 36 | .l_reg = 0x3164, | 63 | .l_reg = 0x3164, |
| 37 | .m_reg = 0x3168, | 64 | .m_reg = 0x3168, |
| @@ -154,7 +181,7 @@ static const u8 gcc_pxo_pll8_pll0[] = { | |||
| 154 | static const char *gcc_pxo_pll8_pll0_map[] = { | 181 | static const char *gcc_pxo_pll8_pll0_map[] = { |
| 155 | "pxo", | 182 | "pxo", |
| 156 | "pll8_vote", | 183 | "pll8_vote", |
| 157 | "pll0", | 184 | "pll0_vote", |
| 158 | }; | 185 | }; |
| 159 | 186 | ||
| 160 | static struct freq_tbl clk_tbl_gsbi_uart[] = { | 187 | static struct freq_tbl clk_tbl_gsbi_uart[] = { |
| @@ -2133,6 +2160,8 @@ static struct clk_branch usb_fs1_h_clk = { | |||
| 2133 | }; | 2160 | }; |
| 2134 | 2161 | ||
| 2135 | static struct clk_regmap *gcc_ipq806x_clks[] = { | 2162 | static struct clk_regmap *gcc_ipq806x_clks[] = { |
| 2163 | [PLL0] = &pll0.clkr, | ||
| 2164 | [PLL0_VOTE] = &pll0_vote, | ||
| 2136 | [PLL3] = &pll3.clkr, | 2165 | [PLL3] = &pll3.clkr, |
| 2137 | [PLL8] = &pll8.clkr, | 2166 | [PLL8] = &pll8.clkr, |
| 2138 | [PLL8_VOTE] = &pll8_vote, | 2167 | [PLL8_VOTE] = &pll8_vote, |
diff --git a/drivers/clk/qcom/mmcc-apq8084.c b/drivers/clk/qcom/mmcc-apq8084.c index 751eea376a2b..dab988ab8cf1 100644 --- a/drivers/clk/qcom/mmcc-apq8084.c +++ b/drivers/clk/qcom/mmcc-apq8084.c | |||
| @@ -3341,7 +3341,6 @@ static struct platform_driver mmcc_apq8084_driver = { | |||
| 3341 | .remove = mmcc_apq8084_remove, | 3341 | .remove = mmcc_apq8084_remove, |
| 3342 | .driver = { | 3342 | .driver = { |
| 3343 | .name = "mmcc-apq8084", | 3343 | .name = "mmcc-apq8084", |
| 3344 | .owner = THIS_MODULE, | ||
| 3345 | .of_match_table = mmcc_apq8084_match_table, | 3344 | .of_match_table = mmcc_apq8084_match_table, |
| 3346 | }, | 3345 | }, |
| 3347 | }; | 3346 | }; |
diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c index 2e80a219b8ea..e8b33bbc362f 100644 --- a/drivers/clk/qcom/mmcc-msm8960.c +++ b/drivers/clk/qcom/mmcc-msm8960.c | |||
| @@ -773,9 +773,11 @@ static struct freq_tbl clk_tbl_gfx2d[] = { | |||
| 773 | }; | 773 | }; |
| 774 | 774 | ||
| 775 | static struct clk_dyn_rcg gfx2d0_src = { | 775 | static struct clk_dyn_rcg gfx2d0_src = { |
| 776 | .ns_reg = 0x0070, | 776 | .ns_reg[0] = 0x0070, |
| 777 | .ns_reg[1] = 0x0070, | ||
| 777 | .md_reg[0] = 0x0064, | 778 | .md_reg[0] = 0x0064, |
| 778 | .md_reg[1] = 0x0068, | 779 | .md_reg[1] = 0x0068, |
| 780 | .bank_reg = 0x0060, | ||
| 779 | .mn[0] = { | 781 | .mn[0] = { |
| 780 | .mnctr_en_bit = 8, | 782 | .mnctr_en_bit = 8, |
| 781 | .mnctr_reset_bit = 25, | 783 | .mnctr_reset_bit = 25, |
| @@ -831,9 +833,11 @@ static struct clk_branch gfx2d0_clk = { | |||
| 831 | }; | 833 | }; |
| 832 | 834 | ||
| 833 | static struct clk_dyn_rcg gfx2d1_src = { | 835 | static struct clk_dyn_rcg gfx2d1_src = { |
| 834 | .ns_reg = 0x007c, | 836 | .ns_reg[0] = 0x007c, |
| 837 | .ns_reg[1] = 0x007c, | ||
| 835 | .md_reg[0] = 0x0078, | 838 | .md_reg[0] = 0x0078, |
| 836 | .md_reg[1] = 0x006c, | 839 | .md_reg[1] = 0x006c, |
| 840 | .bank_reg = 0x0074, | ||
| 837 | .mn[0] = { | 841 | .mn[0] = { |
| 838 | .mnctr_en_bit = 8, | 842 | .mnctr_en_bit = 8, |
| 839 | .mnctr_reset_bit = 25, | 843 | .mnctr_reset_bit = 25, |
| @@ -930,9 +934,11 @@ static struct freq_tbl clk_tbl_gfx3d_8064[] = { | |||
| 930 | }; | 934 | }; |
| 931 | 935 | ||
| 932 | static struct clk_dyn_rcg gfx3d_src = { | 936 | static struct clk_dyn_rcg gfx3d_src = { |
| 933 | .ns_reg = 0x008c, | 937 | .ns_reg[0] = 0x008c, |
| 938 | .ns_reg[1] = 0x008c, | ||
| 934 | .md_reg[0] = 0x0084, | 939 | .md_reg[0] = 0x0084, |
| 935 | .md_reg[1] = 0x0088, | 940 | .md_reg[1] = 0x0088, |
| 941 | .bank_reg = 0x0080, | ||
| 936 | .mn[0] = { | 942 | .mn[0] = { |
| 937 | .mnctr_en_bit = 8, | 943 | .mnctr_en_bit = 8, |
| 938 | .mnctr_reset_bit = 25, | 944 | .mnctr_reset_bit = 25, |
| @@ -1006,9 +1012,11 @@ static struct freq_tbl clk_tbl_vcap[] = { | |||
| 1006 | }; | 1012 | }; |
| 1007 | 1013 | ||
| 1008 | static struct clk_dyn_rcg vcap_src = { | 1014 | static struct clk_dyn_rcg vcap_src = { |
| 1009 | .ns_reg = 0x021c, | 1015 | .ns_reg[0] = 0x021c, |
| 1016 | .ns_reg[1] = 0x021c, | ||
| 1010 | .md_reg[0] = 0x01ec, | 1017 | .md_reg[0] = 0x01ec, |
| 1011 | .md_reg[1] = 0x0218, | 1018 | .md_reg[1] = 0x0218, |
| 1019 | .bank_reg = 0x0178, | ||
| 1012 | .mn[0] = { | 1020 | .mn[0] = { |
| 1013 | .mnctr_en_bit = 8, | 1021 | .mnctr_en_bit = 8, |
| 1014 | .mnctr_reset_bit = 23, | 1022 | .mnctr_reset_bit = 23, |
| @@ -1211,9 +1219,11 @@ static struct freq_tbl clk_tbl_mdp[] = { | |||
| 1211 | }; | 1219 | }; |
| 1212 | 1220 | ||
| 1213 | static struct clk_dyn_rcg mdp_src = { | 1221 | static struct clk_dyn_rcg mdp_src = { |
| 1214 | .ns_reg = 0x00d0, | 1222 | .ns_reg[0] = 0x00d0, |
| 1223 | .ns_reg[1] = 0x00d0, | ||
| 1215 | .md_reg[0] = 0x00c4, | 1224 | .md_reg[0] = 0x00c4, |
| 1216 | .md_reg[1] = 0x00c8, | 1225 | .md_reg[1] = 0x00c8, |
| 1226 | .bank_reg = 0x00c0, | ||
| 1217 | .mn[0] = { | 1227 | .mn[0] = { |
| 1218 | .mnctr_en_bit = 8, | 1228 | .mnctr_en_bit = 8, |
| 1219 | .mnctr_reset_bit = 31, | 1229 | .mnctr_reset_bit = 31, |
| @@ -1318,7 +1328,9 @@ static struct freq_tbl clk_tbl_rot[] = { | |||
| 1318 | }; | 1328 | }; |
| 1319 | 1329 | ||
| 1320 | static struct clk_dyn_rcg rot_src = { | 1330 | static struct clk_dyn_rcg rot_src = { |
| 1321 | .ns_reg = 0x00e8, | 1331 | .ns_reg[0] = 0x00e8, |
| 1332 | .ns_reg[1] = 0x00e8, | ||
| 1333 | .bank_reg = 0x00e8, | ||
| 1322 | .p[0] = { | 1334 | .p[0] = { |
| 1323 | .pre_div_shift = 22, | 1335 | .pre_div_shift = 22, |
| 1324 | .pre_div_width = 4, | 1336 | .pre_div_width = 4, |
| @@ -1542,9 +1554,11 @@ static struct freq_tbl clk_tbl_vcodec[] = { | |||
| 1542 | }; | 1554 | }; |
| 1543 | 1555 | ||
| 1544 | static struct clk_dyn_rcg vcodec_src = { | 1556 | static struct clk_dyn_rcg vcodec_src = { |
| 1545 | .ns_reg = 0x0100, | 1557 | .ns_reg[0] = 0x0100, |
| 1558 | .ns_reg[1] = 0x0100, | ||
| 1546 | .md_reg[0] = 0x00fc, | 1559 | .md_reg[0] = 0x00fc, |
| 1547 | .md_reg[1] = 0x0128, | 1560 | .md_reg[1] = 0x0128, |
| 1561 | .bank_reg = 0x00f8, | ||
| 1548 | .mn[0] = { | 1562 | .mn[0] = { |
| 1549 | .mnctr_en_bit = 5, | 1563 | .mnctr_en_bit = 5, |
| 1550 | .mnctr_reset_bit = 31, | 1564 | .mnctr_reset_bit = 31, |
| @@ -2679,7 +2693,6 @@ static struct platform_driver mmcc_msm8960_driver = { | |||
| 2679 | .remove = mmcc_msm8960_remove, | 2693 | .remove = mmcc_msm8960_remove, |
| 2680 | .driver = { | 2694 | .driver = { |
| 2681 | .name = "mmcc-msm8960", | 2695 | .name = "mmcc-msm8960", |
| 2682 | .owner = THIS_MODULE, | ||
| 2683 | .of_match_table = mmcc_msm8960_match_table, | 2696 | .of_match_table = mmcc_msm8960_match_table, |
| 2684 | }, | 2697 | }, |
| 2685 | }; | 2698 | }; |
diff --git a/drivers/clk/qcom/mmcc-msm8974.c b/drivers/clk/qcom/mmcc-msm8974.c index bc8f519c47aa..be94c54a9a4f 100644 --- a/drivers/clk/qcom/mmcc-msm8974.c +++ b/drivers/clk/qcom/mmcc-msm8974.c | |||
| @@ -2570,7 +2570,6 @@ static struct platform_driver mmcc_msm8974_driver = { | |||
| 2570 | .remove = mmcc_msm8974_remove, | 2570 | .remove = mmcc_msm8974_remove, |
| 2571 | .driver = { | 2571 | .driver = { |
| 2572 | .name = "mmcc-msm8974", | 2572 | .name = "mmcc-msm8974", |
| 2573 | .owner = THIS_MODULE, | ||
| 2574 | .of_match_table = mmcc_msm8974_match_table, | 2573 | .of_match_table = mmcc_msm8974_match_table, |
| 2575 | }, | 2574 | }, |
| 2576 | }; | 2575 | }; |
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index ee6b077381e1..bd8514d63634 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | obj-y += clk-rockchip.o | 5 | obj-y += clk-rockchip.o |
| 6 | obj-y += clk.o | 6 | obj-y += clk.o |
| 7 | obj-y += clk-pll.o | 7 | obj-y += clk-pll.o |
| 8 | obj-y += clk-cpu.o | ||
| 8 | obj-$(CONFIG_RESET_CONTROLLER) += softrst.o | 9 | obj-$(CONFIG_RESET_CONTROLLER) += softrst.o |
| 9 | 10 | ||
| 10 | obj-y += clk-rk3188.o | 11 | obj-y += clk-rk3188.o |
diff --git a/drivers/clk/rockchip/clk-cpu.c b/drivers/clk/rockchip/clk-cpu.c new file mode 100644 index 000000000000..75c8c45ef728 --- /dev/null +++ b/drivers/clk/rockchip/clk-cpu.c | |||
| @@ -0,0 +1,329 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014 MundoReader S.L. | ||
| 3 | * Author: Heiko Stuebner <heiko@sntech.de> | ||
| 4 | * | ||
| 5 | * based on clk/samsung/clk-cpu.c | ||
| 6 | * Copyright (c) 2014 Samsung Electronics Co., Ltd. | ||
| 7 | * Author: Thomas Abraham <thomas.ab@samsung.com> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | * | ||
| 13 | * A CPU clock is defined as a clock supplied to a CPU or a group of CPUs. | ||
| 14 | * The CPU clock is typically derived from a hierarchy of clock | ||
| 15 | * blocks which includes mux and divider blocks. There are a number of other | ||
| 16 | * auxiliary clocks supplied to the CPU domain such as the debug blocks and AXI | ||
| 17 | * clock for CPU domain. The rates of these auxiliary clocks are related to the | ||
| 18 | * CPU clock rate and this relation is usually specified in the hardware manual | ||
| 19 | * of the SoC or supplied after the SoC characterization. | ||
| 20 | * | ||
| 21 | * The below implementation of the CPU clock allows the rate changes of the CPU | ||
| 22 | * clock and the corresponding rate changes of the auxillary clocks of the CPU | ||
| 23 | * domain. The platform clock driver provides a clock register configuration | ||
| 24 | * for each configurable rate which is then used to program the clock hardware | ||
| 25 | * registers to acheive a fast co-oridinated rate change for all the CPU domain | ||
| 26 | * clocks. | ||
| 27 | * | ||
| 28 | * On a rate change request for the CPU clock, the rate change is propagated | ||
| 29 | * upto the PLL supplying the clock to the CPU domain clock blocks. While the | ||
| 30 | * CPU domain PLL is reconfigured, the CPU domain clocks are driven using an | ||
| 31 | * alternate clock source. If required, the alternate clock source is divided | ||
| 32 | * down in order to keep the output clock rate within the previous OPP limits. | ||
| 33 | */ | ||
| 34 | |||
| 35 | #include <linux/of.h> | ||
| 36 | #include <linux/slab.h> | ||
| 37 | #include <linux/io.h> | ||
| 38 | #include <linux/clk-provider.h> | ||
| 39 | #include "clk.h" | ||
| 40 | |||
| 41 | /** | ||
| 42 | * struct rockchip_cpuclk: information about clock supplied to a CPU core. | ||
| 43 | * @hw: handle between ccf and cpu clock. | ||
| 44 | * @alt_parent: alternate parent clock to use when switching the speed | ||
| 45 | * of the primary parent clock. | ||
| 46 | * @reg_base: base register for cpu-clock values. | ||
| 47 | * @clk_nb: clock notifier registered for changes in clock speed of the | ||
| 48 | * primary parent clock. | ||
| 49 | * @rate_count: number of rates in the rate_table | ||
| 50 | * @rate_table: pll-rates and their associated dividers | ||
| 51 | * @reg_data: cpu-specific register settings | ||
| 52 | * @lock: clock lock | ||
| 53 | */ | ||
| 54 | struct rockchip_cpuclk { | ||
| 55 | struct clk_hw hw; | ||
| 56 | |||
| 57 | struct clk_mux cpu_mux; | ||
| 58 | const struct clk_ops *cpu_mux_ops; | ||
| 59 | |||
| 60 | struct clk *alt_parent; | ||
| 61 | void __iomem *reg_base; | ||
| 62 | struct notifier_block clk_nb; | ||
| 63 | unsigned int rate_count; | ||
| 64 | struct rockchip_cpuclk_rate_table *rate_table; | ||
| 65 | const struct rockchip_cpuclk_reg_data *reg_data; | ||
| 66 | spinlock_t *lock; | ||
| 67 | }; | ||
| 68 | |||
| 69 | #define to_rockchip_cpuclk_hw(hw) container_of(hw, struct rockchip_cpuclk, hw) | ||
| 70 | #define to_rockchip_cpuclk_nb(nb) \ | ||
| 71 | container_of(nb, struct rockchip_cpuclk, clk_nb) | ||
| 72 | |||
| 73 | static const struct rockchip_cpuclk_rate_table *rockchip_get_cpuclk_settings( | ||
| 74 | struct rockchip_cpuclk *cpuclk, unsigned long rate) | ||
| 75 | { | ||
| 76 | const struct rockchip_cpuclk_rate_table *rate_table = | ||
| 77 | cpuclk->rate_table; | ||
| 78 | int i; | ||
| 79 | |||
| 80 | for (i = 0; i < cpuclk->rate_count; i++) { | ||
| 81 | if (rate == rate_table[i].prate) | ||
| 82 | return &rate_table[i]; | ||
| 83 | } | ||
| 84 | |||
| 85 | return NULL; | ||
| 86 | } | ||
| 87 | |||
| 88 | static unsigned long rockchip_cpuclk_recalc_rate(struct clk_hw *hw, | ||
| 89 | unsigned long parent_rate) | ||
| 90 | { | ||
| 91 | struct rockchip_cpuclk *cpuclk = to_rockchip_cpuclk_hw(hw); | ||
| 92 | const struct rockchip_cpuclk_reg_data *reg_data = cpuclk->reg_data; | ||
| 93 | u32 clksel0 = readl_relaxed(cpuclk->reg_base + reg_data->core_reg); | ||
| 94 | |||
| 95 | clksel0 >>= reg_data->div_core_shift; | ||
| 96 | clksel0 &= reg_data->div_core_mask; | ||
| 97 | return parent_rate / (clksel0 + 1); | ||
| 98 | } | ||
| 99 | |||
| 100 | static const struct clk_ops rockchip_cpuclk_ops = { | ||
| 101 | .recalc_rate = rockchip_cpuclk_recalc_rate, | ||
| 102 | }; | ||
| 103 | |||
| 104 | static void rockchip_cpuclk_set_dividers(struct rockchip_cpuclk *cpuclk, | ||
| 105 | const struct rockchip_cpuclk_rate_table *rate) | ||
| 106 | { | ||
| 107 | int i; | ||
| 108 | |||
| 109 | /* alternate parent is active now. set the dividers */ | ||
| 110 | for (i = 0; i < ARRAY_SIZE(rate->divs); i++) { | ||
| 111 | const struct rockchip_cpuclk_clksel *clksel = &rate->divs[i]; | ||
| 112 | |||
| 113 | if (!clksel->reg) | ||
| 114 | continue; | ||
| 115 | |||
| 116 | pr_debug("%s: setting reg 0x%x to 0x%x\n", | ||
| 117 | __func__, clksel->reg, clksel->val); | ||
| 118 | writel(clksel->val , cpuclk->reg_base + clksel->reg); | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | static int rockchip_cpuclk_pre_rate_change(struct rockchip_cpuclk *cpuclk, | ||
| 123 | struct clk_notifier_data *ndata) | ||
| 124 | { | ||
| 125 | const struct rockchip_cpuclk_reg_data *reg_data = cpuclk->reg_data; | ||
| 126 | unsigned long alt_prate, alt_div; | ||
| 127 | |||
| 128 | alt_prate = clk_get_rate(cpuclk->alt_parent); | ||
| 129 | |||
| 130 | spin_lock(cpuclk->lock); | ||
| 131 | |||
| 132 | /* | ||
| 133 | * If the old parent clock speed is less than the clock speed | ||
| 134 | * of the alternate parent, then it should be ensured that at no point | ||
| 135 | * the armclk speed is more than the old_rate until the dividers are | ||
| 136 | * set. | ||
| 137 | */ | ||
| 138 | if (alt_prate > ndata->old_rate) { | ||
| 139 | /* calculate dividers */ | ||
| 140 | alt_div = DIV_ROUND_UP(alt_prate, ndata->old_rate) - 1; | ||
| 141 | if (alt_div > reg_data->div_core_mask) { | ||
| 142 | pr_warn("%s: limiting alt-divider %lu to %d\n", | ||
| 143 | __func__, alt_div, reg_data->div_core_mask); | ||
| 144 | alt_div = reg_data->div_core_mask; | ||
| 145 | } | ||
| 146 | |||
| 147 | /* | ||
| 148 | * Change parents and add dividers in a single transaction. | ||
| 149 | * | ||
| 150 | * NOTE: we do this in a single transaction so we're never | ||
| 151 | * dividing the primary parent by the extra dividers that were | ||
| 152 | * needed for the alt. | ||
| 153 | */ | ||
| 154 | pr_debug("%s: setting div %lu as alt-rate %lu > old-rate %lu\n", | ||
| 155 | __func__, alt_div, alt_prate, ndata->old_rate); | ||
| 156 | |||
| 157 | writel(HIWORD_UPDATE(alt_div, reg_data->div_core_mask, | ||
| 158 | reg_data->div_core_shift) | | ||
| 159 | HIWORD_UPDATE(1, 1, reg_data->mux_core_shift), | ||
| 160 | cpuclk->reg_base + reg_data->core_reg); | ||
| 161 | } else { | ||
| 162 | /* select alternate parent */ | ||
| 163 | writel(HIWORD_UPDATE(1, 1, reg_data->mux_core_shift), | ||
| 164 | cpuclk->reg_base + reg_data->core_reg); | ||
| 165 | } | ||
| 166 | |||
| 167 | spin_unlock(cpuclk->lock); | ||
| 168 | return 0; | ||
| 169 | } | ||
| 170 | |||
| 171 | static int rockchip_cpuclk_post_rate_change(struct rockchip_cpuclk *cpuclk, | ||
| 172 | struct clk_notifier_data *ndata) | ||
| 173 | { | ||
| 174 | const struct rockchip_cpuclk_reg_data *reg_data = cpuclk->reg_data; | ||
| 175 | const struct rockchip_cpuclk_rate_table *rate; | ||
| 176 | |||
| 177 | rate = rockchip_get_cpuclk_settings(cpuclk, ndata->new_rate); | ||
| 178 | if (!rate) { | ||
| 179 | pr_err("%s: Invalid rate : %lu for cpuclk\n", | ||
| 180 | __func__, ndata->new_rate); | ||
| 181 | return -EINVAL; | ||
| 182 | } | ||
| 183 | |||
| 184 | spin_lock(cpuclk->lock); | ||
| 185 | |||
| 186 | if (ndata->old_rate < ndata->new_rate) | ||
| 187 | rockchip_cpuclk_set_dividers(cpuclk, rate); | ||
| 188 | |||
| 189 | /* | ||
| 190 | * post-rate change event, re-mux to primary parent and remove dividers. | ||
| 191 | * | ||
| 192 | * NOTE: we do this in a single transaction so we're never dividing the | ||
| 193 | * primary parent by the extra dividers that were needed for the alt. | ||
| 194 | */ | ||
| 195 | |||
| 196 | writel(HIWORD_UPDATE(0, reg_data->div_core_mask, | ||
| 197 | reg_data->div_core_shift) | | ||
| 198 | HIWORD_UPDATE(0, 1, reg_data->mux_core_shift), | ||
| 199 | cpuclk->reg_base + reg_data->core_reg); | ||
| 200 | |||
| 201 | if (ndata->old_rate > ndata->new_rate) | ||
| 202 | rockchip_cpuclk_set_dividers(cpuclk, rate); | ||
| 203 | |||
| 204 | spin_unlock(cpuclk->lock); | ||
| 205 | return 0; | ||
| 206 | } | ||
| 207 | |||
| 208 | /* | ||
| 209 | * This clock notifier is called when the frequency of the parent clock | ||
| 210 | * of cpuclk is to be changed. This notifier handles the setting up all | ||
| 211 | * the divider clocks, remux to temporary parent and handling the safe | ||
| 212 | * frequency levels when using temporary parent. | ||
| 213 | */ | ||
| 214 | static int rockchip_cpuclk_notifier_cb(struct notifier_block *nb, | ||
| 215 | unsigned long event, void *data) | ||
| 216 | { | ||
| 217 | struct clk_notifier_data *ndata = data; | ||
| 218 | struct rockchip_cpuclk *cpuclk = to_rockchip_cpuclk_nb(nb); | ||
| 219 | int ret = 0; | ||
| 220 | |||
| 221 | pr_debug("%s: event %lu, old_rate %lu, new_rate: %lu\n", | ||
| 222 | __func__, event, ndata->old_rate, ndata->new_rate); | ||
| 223 | if (event == PRE_RATE_CHANGE) | ||
| 224 | ret = rockchip_cpuclk_pre_rate_change(cpuclk, ndata); | ||
| 225 | else if (event == POST_RATE_CHANGE) | ||
| 226 | ret = rockchip_cpuclk_post_rate_change(cpuclk, ndata); | ||
| 227 | |||
| 228 | return notifier_from_errno(ret); | ||
| 229 | } | ||
| 230 | |||
| 231 | struct clk *rockchip_clk_register_cpuclk(const char *name, | ||
| 232 | const char **parent_names, u8 num_parents, | ||
| 233 | const struct rockchip_cpuclk_reg_data *reg_data, | ||
| 234 | const struct rockchip_cpuclk_rate_table *rates, | ||
| 235 | int nrates, void __iomem *reg_base, spinlock_t *lock) | ||
| 236 | { | ||
| 237 | struct rockchip_cpuclk *cpuclk; | ||
| 238 | struct clk_init_data init; | ||
| 239 | struct clk *clk, *cclk; | ||
| 240 | int ret; | ||
| 241 | |||
| 242 | if (num_parents != 2) { | ||
| 243 | pr_err("%s: needs two parent clocks\n", __func__); | ||
| 244 | return ERR_PTR(-EINVAL); | ||
| 245 | } | ||
| 246 | |||
| 247 | cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL); | ||
| 248 | if (!cpuclk) | ||
| 249 | return ERR_PTR(-ENOMEM); | ||
| 250 | |||
| 251 | init.name = name; | ||
| 252 | init.parent_names = &parent_names[0]; | ||
| 253 | init.num_parents = 1; | ||
| 254 | init.ops = &rockchip_cpuclk_ops; | ||
| 255 | |||
| 256 | /* only allow rate changes when we have a rate table */ | ||
| 257 | init.flags = (nrates > 0) ? CLK_SET_RATE_PARENT : 0; | ||
| 258 | |||
| 259 | /* disallow automatic parent changes by ccf */ | ||
| 260 | init.flags |= CLK_SET_RATE_NO_REPARENT; | ||
| 261 | |||
| 262 | init.flags |= CLK_GET_RATE_NOCACHE; | ||
| 263 | |||
| 264 | cpuclk->reg_base = reg_base; | ||
| 265 | cpuclk->lock = lock; | ||
| 266 | cpuclk->reg_data = reg_data; | ||
| 267 | cpuclk->clk_nb.notifier_call = rockchip_cpuclk_notifier_cb; | ||
| 268 | cpuclk->hw.init = &init; | ||
| 269 | |||
| 270 | cpuclk->alt_parent = __clk_lookup(parent_names[1]); | ||
| 271 | if (!cpuclk->alt_parent) { | ||
| 272 | pr_err("%s: could not lookup alternate parent\n", | ||
| 273 | __func__); | ||
| 274 | ret = -EINVAL; | ||
| 275 | goto free_cpuclk; | ||
| 276 | } | ||
| 277 | |||
| 278 | ret = clk_prepare_enable(cpuclk->alt_parent); | ||
| 279 | if (ret) { | ||
| 280 | pr_err("%s: could not enable alternate parent\n", | ||
| 281 | __func__); | ||
| 282 | goto free_cpuclk; | ||
| 283 | } | ||
| 284 | |||
| 285 | clk = __clk_lookup(parent_names[0]); | ||
| 286 | if (!clk) { | ||
| 287 | pr_err("%s: could not lookup parent clock %s\n", | ||
| 288 | __func__, parent_names[0]); | ||
| 289 | ret = -EINVAL; | ||
| 290 | goto free_cpuclk; | ||
| 291 | } | ||
| 292 | |||
| 293 | ret = clk_notifier_register(clk, &cpuclk->clk_nb); | ||
| 294 | if (ret) { | ||
| 295 | pr_err("%s: failed to register clock notifier for %s\n", | ||
| 296 | __func__, name); | ||
| 297 | goto free_cpuclk; | ||
| 298 | } | ||
| 299 | |||
| 300 | if (nrates > 0) { | ||
| 301 | cpuclk->rate_count = nrates; | ||
| 302 | cpuclk->rate_table = kmemdup(rates, | ||
| 303 | sizeof(*rates) * nrates, | ||
| 304 | GFP_KERNEL); | ||
| 305 | if (!cpuclk->rate_table) { | ||
| 306 | pr_err("%s: could not allocate memory for cpuclk rates\n", | ||
| 307 | __func__); | ||
| 308 | ret = -ENOMEM; | ||
| 309 | goto unregister_notifier; | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | cclk = clk_register(NULL, &cpuclk->hw); | ||
| 314 | if (IS_ERR(clk)) { | ||
| 315 | pr_err("%s: could not register cpuclk %s\n", __func__, name); | ||
| 316 | ret = PTR_ERR(clk); | ||
| 317 | goto free_rate_table; | ||
| 318 | } | ||
| 319 | |||
| 320 | return cclk; | ||
| 321 | |||
| 322 | free_rate_table: | ||
| 323 | kfree(cpuclk->rate_table); | ||
| 324 | unregister_notifier: | ||
| 325 | clk_notifier_unregister(clk, &cpuclk->clk_nb); | ||
| 326 | free_cpuclk: | ||
| 327 | kfree(cpuclk); | ||
| 328 | return ERR_PTR(ret); | ||
| 329 | } | ||
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index f2a1c7abf4d9..a3e886a38480 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c | |||
| @@ -34,7 +34,6 @@ struct rockchip_clk_pll { | |||
| 34 | const struct clk_ops *pll_mux_ops; | 34 | const struct clk_ops *pll_mux_ops; |
| 35 | 35 | ||
| 36 | struct notifier_block clk_nb; | 36 | struct notifier_block clk_nb; |
| 37 | bool rate_change_remuxed; | ||
| 38 | 37 | ||
| 39 | void __iomem *reg_base; | 38 | void __iomem *reg_base; |
| 40 | int lock_offset; | 39 | int lock_offset; |
| @@ -109,38 +108,6 @@ static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll) | |||
| 109 | } | 108 | } |
| 110 | 109 | ||
| 111 | /** | 110 | /** |
| 112 | * Set pll mux when changing the pll rate. | ||
| 113 | * This makes sure to move the pll mux away from the actual pll before | ||
| 114 | * changing its rate and back to the original parent after the change. | ||
| 115 | */ | ||
| 116 | static int rockchip_pll_notifier_cb(struct notifier_block *nb, | ||
| 117 | unsigned long event, void *data) | ||
| 118 | { | ||
| 119 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll_nb(nb); | ||
| 120 | struct clk_mux *pll_mux = &pll->pll_mux; | ||
| 121 | const struct clk_ops *pll_mux_ops = pll->pll_mux_ops; | ||
| 122 | int cur_parent; | ||
| 123 | |||
| 124 | switch (event) { | ||
| 125 | case PRE_RATE_CHANGE: | ||
| 126 | cur_parent = pll_mux_ops->get_parent(&pll_mux->hw); | ||
| 127 | if (cur_parent == PLL_MODE_NORM) { | ||
| 128 | pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW); | ||
| 129 | pll->rate_change_remuxed = 1; | ||
| 130 | } | ||
| 131 | break; | ||
| 132 | case POST_RATE_CHANGE: | ||
| 133 | if (pll->rate_change_remuxed) { | ||
| 134 | pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM); | ||
| 135 | pll->rate_change_remuxed = 0; | ||
| 136 | } | ||
| 137 | break; | ||
| 138 | } | ||
| 139 | |||
| 140 | return NOTIFY_OK; | ||
| 141 | } | ||
| 142 | |||
| 143 | /** | ||
| 144 | * PLL used in RK3066, RK3188 and RK3288 | 111 | * PLL used in RK3066, RK3188 and RK3288 |
| 145 | */ | 112 | */ |
| 146 | 113 | ||
| @@ -194,6 +161,10 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate, | |||
| 194 | const struct rockchip_pll_rate_table *rate; | 161 | const struct rockchip_pll_rate_table *rate; |
| 195 | unsigned long old_rate = rockchip_rk3066_pll_recalc_rate(hw, prate); | 162 | unsigned long old_rate = rockchip_rk3066_pll_recalc_rate(hw, prate); |
| 196 | struct regmap *grf = rockchip_clk_get_grf(); | 163 | struct regmap *grf = rockchip_clk_get_grf(); |
| 164 | struct clk_mux *pll_mux = &pll->pll_mux; | ||
| 165 | const struct clk_ops *pll_mux_ops = pll->pll_mux_ops; | ||
| 166 | int rate_change_remuxed = 0; | ||
| 167 | int cur_parent; | ||
| 197 | int ret; | 168 | int ret; |
| 198 | 169 | ||
| 199 | if (IS_ERR(grf)) { | 170 | if (IS_ERR(grf)) { |
| @@ -216,6 +187,12 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate, | |||
| 216 | pr_debug("%s: rate settings for %lu (nr, no, nf): (%d, %d, %d)\n", | 187 | pr_debug("%s: rate settings for %lu (nr, no, nf): (%d, %d, %d)\n", |
| 217 | __func__, rate->rate, rate->nr, rate->no, rate->nf); | 188 | __func__, rate->rate, rate->nr, rate->no, rate->nf); |
| 218 | 189 | ||
| 190 | cur_parent = pll_mux_ops->get_parent(&pll_mux->hw); | ||
| 191 | if (cur_parent == PLL_MODE_NORM) { | ||
| 192 | pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW); | ||
| 193 | rate_change_remuxed = 1; | ||
| 194 | } | ||
| 195 | |||
| 219 | /* enter reset mode */ | 196 | /* enter reset mode */ |
| 220 | writel(HIWORD_UPDATE(RK3066_PLLCON3_RESET, RK3066_PLLCON3_RESET, 0), | 197 | writel(HIWORD_UPDATE(RK3066_PLLCON3_RESET, RK3066_PLLCON3_RESET, 0), |
| 221 | pll->reg_base + RK3066_PLLCON(3)); | 198 | pll->reg_base + RK3066_PLLCON(3)); |
| @@ -247,6 +224,9 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate, | |||
| 247 | rockchip_rk3066_pll_set_rate(hw, old_rate, prate); | 224 | rockchip_rk3066_pll_set_rate(hw, old_rate, prate); |
| 248 | } | 225 | } |
| 249 | 226 | ||
| 227 | if (rate_change_remuxed) | ||
| 228 | pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM); | ||
| 229 | |||
| 250 | return ret; | 230 | return ret; |
| 251 | } | 231 | } |
| 252 | 232 | ||
| @@ -310,7 +290,6 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, | |||
| 310 | struct clk_mux *pll_mux; | 290 | struct clk_mux *pll_mux; |
| 311 | struct clk *pll_clk, *mux_clk; | 291 | struct clk *pll_clk, *mux_clk; |
| 312 | char pll_name[20]; | 292 | char pll_name[20]; |
| 313 | int ret; | ||
| 314 | 293 | ||
| 315 | if (num_parents != 2) { | 294 | if (num_parents != 2) { |
| 316 | pr_err("%s: needs two parent clocks\n", __func__); | 295 | pr_err("%s: needs two parent clocks\n", __func__); |
| @@ -367,7 +346,6 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, | |||
| 367 | pll->lock_offset = grf_lock_offset; | 346 | pll->lock_offset = grf_lock_offset; |
| 368 | pll->lock_shift = lock_shift; | 347 | pll->lock_shift = lock_shift; |
| 369 | pll->lock = lock; | 348 | pll->lock = lock; |
| 370 | pll->clk_nb.notifier_call = rockchip_pll_notifier_cb; | ||
| 371 | 349 | ||
| 372 | pll_clk = clk_register(NULL, &pll->hw); | 350 | pll_clk = clk_register(NULL, &pll->hw); |
| 373 | if (IS_ERR(pll_clk)) { | 351 | if (IS_ERR(pll_clk)) { |
| @@ -377,14 +355,6 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, | |||
| 377 | goto err_pll; | 355 | goto err_pll; |
| 378 | } | 356 | } |
| 379 | 357 | ||
| 380 | ret = clk_notifier_register(pll_clk, &pll->clk_nb); | ||
| 381 | if (ret) { | ||
| 382 | pr_err("%s: failed to register clock notifier for %s : %d\n", | ||
| 383 | __func__, name, ret); | ||
| 384 | mux_clk = ERR_PTR(ret); | ||
| 385 | goto err_pll_notifier; | ||
| 386 | } | ||
| 387 | |||
| 388 | /* create the mux on top of the real pll */ | 358 | /* create the mux on top of the real pll */ |
| 389 | pll->pll_mux_ops = &clk_mux_ops; | 359 | pll->pll_mux_ops = &clk_mux_ops; |
| 390 | pll_mux = &pll->pll_mux; | 360 | pll_mux = &pll->pll_mux; |
| @@ -417,13 +387,6 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, | |||
| 417 | return mux_clk; | 387 | return mux_clk; |
| 418 | 388 | ||
| 419 | err_mux: | 389 | err_mux: |
| 420 | ret = clk_notifier_unregister(pll_clk, &pll->clk_nb); | ||
| 421 | if (ret) { | ||
| 422 | pr_err("%s: could not unregister clock notifier in error path : %d\n", | ||
| 423 | __func__, ret); | ||
| 424 | return mux_clk; | ||
| 425 | } | ||
| 426 | err_pll_notifier: | ||
| 427 | clk_unregister(pll_clk); | 390 | clk_unregister(pll_clk); |
| 428 | err_pll: | 391 | err_pll: |
| 429 | kfree(pll); | 392 | kfree(pll); |
diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index a83a6d8d0fb6..beed49c79126 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <dt-bindings/clock/rk3188-cru-common.h> | 19 | #include <dt-bindings/clock/rk3188-cru-common.h> |
| 20 | #include "clk.h" | 20 | #include "clk.h" |
| 21 | 21 | ||
| 22 | #define RK3066_GRF_SOC_STATUS 0x15c | ||
| 22 | #define RK3188_GRF_SOC_STATUS 0xac | 23 | #define RK3188_GRF_SOC_STATUS 0xac |
| 23 | 24 | ||
| 24 | enum rk3188_plls { | 25 | enum rk3188_plls { |
| @@ -100,6 +101,98 @@ struct rockchip_pll_rate_table rk3188_pll_rates[] = { | |||
| 100 | { /* sentinel */ }, | 101 | { /* sentinel */ }, |
| 101 | }; | 102 | }; |
| 102 | 103 | ||
| 104 | #define RK3066_DIV_CORE_PERIPH_MASK 0x3 | ||
| 105 | #define RK3066_DIV_CORE_PERIPH_SHIFT 6 | ||
| 106 | #define RK3066_DIV_ACLK_CORE_MASK 0x7 | ||
| 107 | #define RK3066_DIV_ACLK_CORE_SHIFT 0 | ||
| 108 | #define RK3066_DIV_ACLK_HCLK_MASK 0x3 | ||
| 109 | #define RK3066_DIV_ACLK_HCLK_SHIFT 8 | ||
| 110 | #define RK3066_DIV_ACLK_PCLK_MASK 0x3 | ||
| 111 | #define RK3066_DIV_ACLK_PCLK_SHIFT 12 | ||
| 112 | #define RK3066_DIV_AHB2APB_MASK 0x3 | ||
| 113 | #define RK3066_DIV_AHB2APB_SHIFT 14 | ||
| 114 | |||
| 115 | #define RK3066_CLKSEL0(_core_peri) \ | ||
| 116 | { \ | ||
| 117 | .reg = RK2928_CLKSEL_CON(0), \ | ||
| 118 | .val = HIWORD_UPDATE(_core_peri, RK3066_DIV_CORE_PERIPH_MASK, \ | ||
| 119 | RK3066_DIV_CORE_PERIPH_SHIFT) \ | ||
| 120 | } | ||
| 121 | #define RK3066_CLKSEL1(_aclk_core, _aclk_hclk, _aclk_pclk, _ahb2apb) \ | ||
| 122 | { \ | ||
| 123 | .reg = RK2928_CLKSEL_CON(1), \ | ||
| 124 | .val = HIWORD_UPDATE(_aclk_core, RK3066_DIV_ACLK_CORE_MASK, \ | ||
| 125 | RK3066_DIV_ACLK_CORE_SHIFT) | \ | ||
| 126 | HIWORD_UPDATE(_aclk_hclk, RK3066_DIV_ACLK_HCLK_MASK, \ | ||
| 127 | RK3066_DIV_ACLK_HCLK_SHIFT) | \ | ||
| 128 | HIWORD_UPDATE(_aclk_pclk, RK3066_DIV_ACLK_PCLK_MASK, \ | ||
| 129 | RK3066_DIV_ACLK_PCLK_SHIFT) | \ | ||
| 130 | HIWORD_UPDATE(_ahb2apb, RK3066_DIV_AHB2APB_MASK, \ | ||
| 131 | RK3066_DIV_AHB2APB_SHIFT), \ | ||
| 132 | } | ||
| 133 | |||
| 134 | #define RK3066_CPUCLK_RATE(_prate, _core_peri, _acore, _ahclk, _apclk, _h2p) \ | ||
| 135 | { \ | ||
| 136 | .prate = _prate, \ | ||
| 137 | .divs = { \ | ||
| 138 | RK3066_CLKSEL0(_core_peri), \ | ||
| 139 | RK3066_CLKSEL1(_acore, _ahclk, _apclk, _h2p), \ | ||
| 140 | }, \ | ||
| 141 | } | ||
| 142 | |||
| 143 | static struct rockchip_cpuclk_rate_table rk3066_cpuclk_rates[] __initdata = { | ||
| 144 | RK3066_CPUCLK_RATE(1416000000, 2, 3, 1, 2, 1), | ||
| 145 | RK3066_CPUCLK_RATE(1200000000, 2, 3, 1, 2, 1), | ||
| 146 | RK3066_CPUCLK_RATE(1008000000, 2, 2, 1, 2, 1), | ||
| 147 | RK3066_CPUCLK_RATE( 816000000, 2, 2, 1, 2, 1), | ||
| 148 | RK3066_CPUCLK_RATE( 600000000, 1, 2, 1, 2, 1), | ||
| 149 | RK3066_CPUCLK_RATE( 504000000, 1, 1, 1, 2, 1), | ||
| 150 | RK3066_CPUCLK_RATE( 312000000, 0, 1, 1, 1, 0), | ||
| 151 | }; | ||
| 152 | |||
| 153 | static const struct rockchip_cpuclk_reg_data rk3066_cpuclk_data = { | ||
| 154 | .core_reg = RK2928_CLKSEL_CON(0), | ||
| 155 | .div_core_shift = 0, | ||
| 156 | .div_core_mask = 0x1f, | ||
| 157 | .mux_core_shift = 8, | ||
| 158 | }; | ||
| 159 | |||
| 160 | #define RK3188_DIV_ACLK_CORE_MASK 0x7 | ||
| 161 | #define RK3188_DIV_ACLK_CORE_SHIFT 3 | ||
| 162 | |||
| 163 | #define RK3188_CLKSEL1(_aclk_core) \ | ||
| 164 | { \ | ||
| 165 | .reg = RK2928_CLKSEL_CON(1), \ | ||
| 166 | .val = HIWORD_UPDATE(_aclk_core, RK3188_DIV_ACLK_CORE_MASK,\ | ||
| 167 | RK3188_DIV_ACLK_CORE_SHIFT) \ | ||
| 168 | } | ||
| 169 | #define RK3188_CPUCLK_RATE(_prate, _core_peri, _aclk_core) \ | ||
| 170 | { \ | ||
| 171 | .prate = _prate, \ | ||
| 172 | .divs = { \ | ||
| 173 | RK3066_CLKSEL0(_core_peri), \ | ||
| 174 | RK3188_CLKSEL1(_aclk_core), \ | ||
| 175 | }, \ | ||
| 176 | } | ||
| 177 | |||
| 178 | static struct rockchip_cpuclk_rate_table rk3188_cpuclk_rates[] __initdata = { | ||
| 179 | RK3188_CPUCLK_RATE(1608000000, 2, 3), | ||
| 180 | RK3188_CPUCLK_RATE(1416000000, 2, 3), | ||
| 181 | RK3188_CPUCLK_RATE(1200000000, 2, 3), | ||
| 182 | RK3188_CPUCLK_RATE(1008000000, 2, 3), | ||
| 183 | RK3188_CPUCLK_RATE( 816000000, 2, 3), | ||
| 184 | RK3188_CPUCLK_RATE( 600000000, 1, 3), | ||
| 185 | RK3188_CPUCLK_RATE( 504000000, 1, 3), | ||
| 186 | RK3188_CPUCLK_RATE( 312000000, 0, 1), | ||
| 187 | }; | ||
| 188 | |||
| 189 | static const struct rockchip_cpuclk_reg_data rk3188_cpuclk_data = { | ||
| 190 | .core_reg = RK2928_CLKSEL_CON(0), | ||
| 191 | .div_core_shift = 9, | ||
| 192 | .div_core_mask = 0x1f, | ||
| 193 | .mux_core_shift = 8, | ||
| 194 | }; | ||
| 195 | |||
| 103 | PNAME(mux_pll_p) = { "xin24m", "xin32k" }; | 196 | PNAME(mux_pll_p) = { "xin24m", "xin32k" }; |
| 104 | PNAME(mux_armclk_p) = { "apll", "gpll_armclk" }; | 197 | PNAME(mux_armclk_p) = { "apll", "gpll_armclk" }; |
| 105 | PNAME(mux_ddrphy_p) = { "dpll", "gpll_ddr" }; | 198 | PNAME(mux_ddrphy_p) = { "dpll", "gpll_ddr" }; |
| @@ -173,17 +266,10 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { | |||
| 173 | GATE(0, "aclk_cpu", "aclk_cpu_pre", 0, | 266 | GATE(0, "aclk_cpu", "aclk_cpu_pre", 0, |
| 174 | RK2928_CLKGATE_CON(0), 3, GFLAGS), | 267 | RK2928_CLKGATE_CON(0), 3, GFLAGS), |
| 175 | 268 | ||
| 176 | DIV(0, "pclk_cpu_pre", "aclk_cpu_pre", 0, | ||
| 177 | RK2928_CLKSEL_CON(1), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), | ||
| 178 | GATE(0, "atclk_cpu", "pclk_cpu_pre", 0, | 269 | GATE(0, "atclk_cpu", "pclk_cpu_pre", 0, |
| 179 | RK2928_CLKGATE_CON(0), 6, GFLAGS), | 270 | RK2928_CLKGATE_CON(0), 6, GFLAGS), |
| 180 | GATE(0, "pclk_cpu", "pclk_cpu_pre", 0, | 271 | GATE(0, "pclk_cpu", "pclk_cpu_pre", 0, |
| 181 | RK2928_CLKGATE_CON(0), 5, GFLAGS), | 272 | RK2928_CLKGATE_CON(0), 5, GFLAGS), |
| 182 | DIV(0, "hclk_cpu_pre", "aclk_cpu_pre", 0, | ||
| 183 | RK2928_CLKSEL_CON(1), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), | ||
| 184 | COMPOSITE_NOMUX(0, "hclk_ahb2apb", "hclk_cpu_pre", 0, | ||
| 185 | RK2928_CLKSEL_CON(1), 14, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, | ||
| 186 | RK2928_CLKGATE_CON(4), 9, GFLAGS), | ||
| 187 | GATE(0, "hclk_cpu", "hclk_cpu_pre", 0, | 273 | GATE(0, "hclk_cpu", "hclk_cpu_pre", 0, |
| 188 | RK2928_CLKGATE_CON(0), 4, GFLAGS), | 274 | RK2928_CLKGATE_CON(0), 4, GFLAGS), |
| 189 | 275 | ||
| @@ -412,10 +498,18 @@ static struct clk_div_table div_aclk_cpu_t[] = { | |||
| 412 | }; | 498 | }; |
| 413 | 499 | ||
| 414 | static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = { | 500 | static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = { |
| 415 | COMPOSITE_NOGATE(0, "armclk", mux_armclk_p, 0, | ||
| 416 | RK2928_CLKSEL_CON(0), 8, 1, MFLAGS, 0, 5, DFLAGS), | ||
| 417 | DIVTBL(0, "aclk_cpu_pre", "armclk", 0, | 501 | DIVTBL(0, "aclk_cpu_pre", "armclk", 0, |
| 418 | RK2928_CLKSEL_CON(1), 0, 3, DFLAGS, div_aclk_cpu_t), | 502 | RK2928_CLKSEL_CON(1), 0, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, div_aclk_cpu_t), |
| 503 | DIV(0, "pclk_cpu_pre", "aclk_cpu_pre", 0, | ||
| 504 | RK2928_CLKSEL_CON(1), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO | ||
| 505 | | CLK_DIVIDER_READ_ONLY), | ||
| 506 | DIV(0, "hclk_cpu_pre", "aclk_cpu_pre", 0, | ||
| 507 | RK2928_CLKSEL_CON(1), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO | ||
| 508 | | CLK_DIVIDER_READ_ONLY), | ||
| 509 | COMPOSITE_NOMUX(0, "hclk_ahb2apb", "hclk_cpu_pre", 0, | ||
| 510 | RK2928_CLKSEL_CON(1), 14, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO | ||
| 511 | | CLK_DIVIDER_READ_ONLY, | ||
| 512 | RK2928_CLKGATE_CON(4), 9, GFLAGS), | ||
| 419 | 513 | ||
| 420 | GATE(CORE_L2C, "core_l2c", "aclk_cpu", 0, | 514 | GATE(CORE_L2C, "core_l2c", "aclk_cpu", 0, |
| 421 | RK2928_CLKGATE_CON(9), 4, GFLAGS), | 515 | RK2928_CLKGATE_CON(9), 4, GFLAGS), |
| @@ -524,8 +618,6 @@ PNAME(mux_hsicphy_p) = { "sclk_otgphy0", "sclk_otgphy1", | |||
| 524 | "gpll", "cpll" }; | 618 | "gpll", "cpll" }; |
| 525 | 619 | ||
| 526 | static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { | 620 | static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { |
| 527 | COMPOSITE_NOGATE(0, "armclk", mux_armclk_p, 0, | ||
| 528 | RK2928_CLKSEL_CON(0), 8, 1, MFLAGS, 9, 5, DFLAGS), | ||
| 529 | COMPOSITE_NOMUX_DIVTBL(0, "aclk_core", "armclk", 0, | 621 | COMPOSITE_NOMUX_DIVTBL(0, "aclk_core", "armclk", 0, |
| 530 | RK2928_CLKSEL_CON(1), 3, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, | 622 | RK2928_CLKSEL_CON(1), 3, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, |
| 531 | div_rk3188_aclk_core_t, RK2928_CLKGATE_CON(0), 7, GFLAGS), | 623 | div_rk3188_aclk_core_t, RK2928_CLKGATE_CON(0), 7, GFLAGS), |
| @@ -533,6 +625,13 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { | |||
| 533 | /* do not source aclk_cpu_pre from the apll, to keep complexity down */ | 625 | /* do not source aclk_cpu_pre from the apll, to keep complexity down */ |
| 534 | COMPOSITE_NOGATE(0, "aclk_cpu_pre", mux_aclk_cpu_p, CLK_SET_RATE_NO_REPARENT, | 626 | COMPOSITE_NOGATE(0, "aclk_cpu_pre", mux_aclk_cpu_p, CLK_SET_RATE_NO_REPARENT, |
| 535 | RK2928_CLKSEL_CON(0), 5, 1, MFLAGS, 0, 5, DFLAGS), | 627 | RK2928_CLKSEL_CON(0), 5, 1, MFLAGS, 0, 5, DFLAGS), |
| 628 | DIV(0, "pclk_cpu_pre", "aclk_cpu_pre", 0, | ||
| 629 | RK2928_CLKSEL_CON(1), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), | ||
| 630 | DIV(0, "hclk_cpu_pre", "aclk_cpu_pre", 0, | ||
| 631 | RK2928_CLKSEL_CON(1), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), | ||
| 632 | COMPOSITE_NOMUX(0, "hclk_ahb2apb", "hclk_cpu_pre", 0, | ||
| 633 | RK2928_CLKSEL_CON(1), 14, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, | ||
| 634 | RK2928_CLKGATE_CON(4), 9, GFLAGS), | ||
| 536 | 635 | ||
| 537 | GATE(CORE_L2C, "core_l2c", "armclk", 0, | 636 | GATE(CORE_L2C, "core_l2c", "armclk", 0, |
| 538 | RK2928_CLKGATE_CON(9), 4, GFLAGS), | 637 | RK2928_CLKGATE_CON(9), 4, GFLAGS), |
| @@ -599,6 +698,12 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { | |||
| 599 | GATE(ACLK_GPS, "aclk_gps", "aclk_peri", 0, RK2928_CLKGATE_CON(8), 13, GFLAGS), | 698 | GATE(ACLK_GPS, "aclk_gps", "aclk_peri", 0, RK2928_CLKGATE_CON(8), 13, GFLAGS), |
| 600 | }; | 699 | }; |
| 601 | 700 | ||
| 701 | static const char *rk3188_critical_clocks[] __initconst = { | ||
| 702 | "aclk_cpu", | ||
| 703 | "aclk_peri", | ||
| 704 | "hclk_peri", | ||
| 705 | }; | ||
| 706 | |||
| 602 | static void __init rk3188_common_clk_init(struct device_node *np) | 707 | static void __init rk3188_common_clk_init(struct device_node *np) |
| 603 | { | 708 | { |
| 604 | void __iomem *reg_base; | 709 | void __iomem *reg_base; |
| @@ -623,29 +728,65 @@ static void __init rk3188_common_clk_init(struct device_node *np) | |||
| 623 | pr_warn("%s: could not register clock usb480m: %ld\n", | 728 | pr_warn("%s: could not register clock usb480m: %ld\n", |
| 624 | __func__, PTR_ERR(clk)); | 729 | __func__, PTR_ERR(clk)); |
| 625 | 730 | ||
| 626 | rockchip_clk_register_plls(rk3188_pll_clks, | ||
| 627 | ARRAY_SIZE(rk3188_pll_clks), | ||
| 628 | RK3188_GRF_SOC_STATUS); | ||
| 629 | rockchip_clk_register_branches(common_clk_branches, | 731 | rockchip_clk_register_branches(common_clk_branches, |
| 630 | ARRAY_SIZE(common_clk_branches)); | 732 | ARRAY_SIZE(common_clk_branches)); |
| 733 | rockchip_clk_protect_critical(rk3188_critical_clocks, | ||
| 734 | ARRAY_SIZE(rk3188_critical_clocks)); | ||
| 631 | 735 | ||
| 632 | rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0), | 736 | rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0), |
| 633 | ROCKCHIP_SOFTRST_HIWORD_MASK); | 737 | ROCKCHIP_SOFTRST_HIWORD_MASK); |
| 738 | |||
| 739 | rockchip_register_restart_notifier(RK2928_GLB_SRST_FST); | ||
| 634 | } | 740 | } |
| 635 | 741 | ||
| 636 | static void __init rk3066a_clk_init(struct device_node *np) | 742 | static void __init rk3066a_clk_init(struct device_node *np) |
| 637 | { | 743 | { |
| 638 | rk3188_common_clk_init(np); | 744 | rk3188_common_clk_init(np); |
| 745 | rockchip_clk_register_plls(rk3188_pll_clks, | ||
| 746 | ARRAY_SIZE(rk3188_pll_clks), | ||
| 747 | RK3066_GRF_SOC_STATUS); | ||
| 639 | rockchip_clk_register_branches(rk3066a_clk_branches, | 748 | rockchip_clk_register_branches(rk3066a_clk_branches, |
| 640 | ARRAY_SIZE(rk3066a_clk_branches)); | 749 | ARRAY_SIZE(rk3066a_clk_branches)); |
| 750 | rockchip_clk_register_armclk(ARMCLK, "armclk", | ||
| 751 | mux_armclk_p, ARRAY_SIZE(mux_armclk_p), | ||
| 752 | &rk3066_cpuclk_data, rk3066_cpuclk_rates, | ||
| 753 | ARRAY_SIZE(rk3066_cpuclk_rates)); | ||
| 641 | } | 754 | } |
| 642 | CLK_OF_DECLARE(rk3066a_cru, "rockchip,rk3066a-cru", rk3066a_clk_init); | 755 | CLK_OF_DECLARE(rk3066a_cru, "rockchip,rk3066a-cru", rk3066a_clk_init); |
| 643 | 756 | ||
| 644 | static void __init rk3188a_clk_init(struct device_node *np) | 757 | static void __init rk3188a_clk_init(struct device_node *np) |
| 645 | { | 758 | { |
| 759 | struct clk *clk1, *clk2; | ||
| 760 | unsigned long rate; | ||
| 761 | int ret; | ||
| 762 | |||
| 646 | rk3188_common_clk_init(np); | 763 | rk3188_common_clk_init(np); |
| 764 | rockchip_clk_register_plls(rk3188_pll_clks, | ||
| 765 | ARRAY_SIZE(rk3188_pll_clks), | ||
| 766 | RK3188_GRF_SOC_STATUS); | ||
| 647 | rockchip_clk_register_branches(rk3188_clk_branches, | 767 | rockchip_clk_register_branches(rk3188_clk_branches, |
| 648 | ARRAY_SIZE(rk3188_clk_branches)); | 768 | ARRAY_SIZE(rk3188_clk_branches)); |
| 769 | rockchip_clk_register_armclk(ARMCLK, "armclk", | ||
| 770 | mux_armclk_p, ARRAY_SIZE(mux_armclk_p), | ||
| 771 | &rk3188_cpuclk_data, rk3188_cpuclk_rates, | ||
| 772 | ARRAY_SIZE(rk3188_cpuclk_rates)); | ||
| 773 | |||
| 774 | /* reparent aclk_cpu_pre from apll */ | ||
| 775 | clk1 = __clk_lookup("aclk_cpu_pre"); | ||
| 776 | clk2 = __clk_lookup("gpll"); | ||
| 777 | if (clk1 && clk2) { | ||
| 778 | rate = clk_get_rate(clk1); | ||
| 779 | |||
| 780 | ret = clk_set_parent(clk1, clk2); | ||
| 781 | if (ret < 0) | ||
| 782 | pr_warn("%s: could not reparent aclk_cpu_pre to gpll\n", | ||
| 783 | __func__); | ||
| 784 | |||
| 785 | clk_set_rate(clk1, rate); | ||
| 786 | } else { | ||
| 787 | pr_warn("%s: missing clocks to reparent aclk_cpu_pre to gpll\n", | ||
| 788 | __func__); | ||
| 789 | } | ||
| 649 | } | 790 | } |
| 650 | CLK_OF_DECLARE(rk3188a_cru, "rockchip,rk3188a-cru", rk3188a_clk_init); | 791 | CLK_OF_DECLARE(rk3188a_cru, "rockchip,rk3188a-cru", rk3188a_clk_init); |
| 651 | 792 | ||
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index b22a2d2f21e9..23278291da44 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c | |||
| @@ -20,7 +20,7 @@ | |||
| 20 | #include "clk.h" | 20 | #include "clk.h" |
| 21 | 21 | ||
| 22 | #define RK3288_GRF_SOC_CON(x) (0x244 + x * 4) | 22 | #define RK3288_GRF_SOC_CON(x) (0x244 + x * 4) |
| 23 | #define RK3288_GRF_SOC_STATUS 0x280 | 23 | #define RK3288_GRF_SOC_STATUS1 0x284 |
| 24 | 24 | ||
| 25 | enum rk3288_plls { | 25 | enum rk3288_plls { |
| 26 | apll, dpll, cpll, gpll, npll, | 26 | apll, dpll, cpll, gpll, npll, |
| @@ -101,6 +101,70 @@ struct rockchip_pll_rate_table rk3288_pll_rates[] = { | |||
| 101 | { /* sentinel */ }, | 101 | { /* sentinel */ }, |
| 102 | }; | 102 | }; |
| 103 | 103 | ||
| 104 | #define RK3288_DIV_ACLK_CORE_M0_MASK 0xf | ||
| 105 | #define RK3288_DIV_ACLK_CORE_M0_SHIFT 0 | ||
| 106 | #define RK3288_DIV_ACLK_CORE_MP_MASK 0xf | ||
| 107 | #define RK3288_DIV_ACLK_CORE_MP_SHIFT 4 | ||
| 108 | #define RK3288_DIV_L2RAM_MASK 0x7 | ||
| 109 | #define RK3288_DIV_L2RAM_SHIFT 0 | ||
| 110 | #define RK3288_DIV_ATCLK_MASK 0x1f | ||
| 111 | #define RK3288_DIV_ATCLK_SHIFT 4 | ||
| 112 | #define RK3288_DIV_PCLK_DBGPRE_MASK 0x1f | ||
| 113 | #define RK3288_DIV_PCLK_DBGPRE_SHIFT 9 | ||
| 114 | |||
| 115 | #define RK3288_CLKSEL0(_core_m0, _core_mp) \ | ||
| 116 | { \ | ||
| 117 | .reg = RK3288_CLKSEL_CON(0), \ | ||
| 118 | .val = HIWORD_UPDATE(_core_m0, RK3288_DIV_ACLK_CORE_M0_MASK, \ | ||
| 119 | RK3288_DIV_ACLK_CORE_M0_SHIFT) | \ | ||
| 120 | HIWORD_UPDATE(_core_mp, RK3288_DIV_ACLK_CORE_MP_MASK, \ | ||
| 121 | RK3288_DIV_ACLK_CORE_MP_SHIFT), \ | ||
| 122 | } | ||
| 123 | #define RK3288_CLKSEL37(_l2ram, _atclk, _pclk_dbg_pre) \ | ||
| 124 | { \ | ||
| 125 | .reg = RK3288_CLKSEL_CON(37), \ | ||
| 126 | .val = HIWORD_UPDATE(_l2ram, RK3288_DIV_L2RAM_MASK, \ | ||
| 127 | RK3288_DIV_L2RAM_SHIFT) | \ | ||
| 128 | HIWORD_UPDATE(_atclk, RK3288_DIV_ATCLK_MASK, \ | ||
| 129 | RK3288_DIV_ATCLK_SHIFT) | \ | ||
| 130 | HIWORD_UPDATE(_pclk_dbg_pre, \ | ||
| 131 | RK3288_DIV_PCLK_DBGPRE_MASK, \ | ||
| 132 | RK3288_DIV_PCLK_DBGPRE_SHIFT), \ | ||
| 133 | } | ||
| 134 | |||
| 135 | #define RK3288_CPUCLK_RATE(_prate, _core_m0, _core_mp, _l2ram, _atclk, _pdbg) \ | ||
| 136 | { \ | ||
| 137 | .prate = _prate, \ | ||
| 138 | .divs = { \ | ||
| 139 | RK3288_CLKSEL0(_core_m0, _core_mp), \ | ||
| 140 | RK3288_CLKSEL37(_l2ram, _atclk, _pdbg), \ | ||
| 141 | }, \ | ||
| 142 | } | ||
| 143 | |||
| 144 | static struct rockchip_cpuclk_rate_table rk3288_cpuclk_rates[] __initdata = { | ||
| 145 | RK3288_CPUCLK_RATE(1800000000, 2, 4, 2, 4, 4), | ||
| 146 | RK3288_CPUCLK_RATE(1704000000, 2, 4, 2, 4, 4), | ||
| 147 | RK3288_CPUCLK_RATE(1608000000, 2, 4, 2, 4, 4), | ||
| 148 | RK3288_CPUCLK_RATE(1512000000, 2, 4, 2, 4, 4), | ||
| 149 | RK3288_CPUCLK_RATE(1416000000, 2, 4, 2, 4, 4), | ||
| 150 | RK3288_CPUCLK_RATE(1200000000, 2, 4, 2, 4, 4), | ||
| 151 | RK3288_CPUCLK_RATE(1008000000, 2, 4, 2, 4, 4), | ||
| 152 | RK3288_CPUCLK_RATE( 816000000, 2, 4, 2, 4, 4), | ||
| 153 | RK3288_CPUCLK_RATE( 696000000, 2, 4, 2, 4, 4), | ||
| 154 | RK3288_CPUCLK_RATE( 600000000, 2, 4, 2, 4, 4), | ||
| 155 | RK3288_CPUCLK_RATE( 408000000, 2, 4, 2, 4, 4), | ||
| 156 | RK3288_CPUCLK_RATE( 312000000, 2, 4, 2, 4, 4), | ||
| 157 | RK3288_CPUCLK_RATE( 216000000, 2, 4, 2, 4, 4), | ||
| 158 | RK3288_CPUCLK_RATE( 126000000, 2, 4, 2, 4, 4), | ||
| 159 | }; | ||
| 160 | |||
| 161 | static const struct rockchip_cpuclk_reg_data rk3288_cpuclk_data = { | ||
| 162 | .core_reg = RK3288_CLKSEL_CON(0), | ||
| 163 | .div_core_shift = 8, | ||
| 164 | .div_core_mask = 0x1f, | ||
| 165 | .mux_core_shift = 15, | ||
| 166 | }; | ||
| 167 | |||
| 104 | PNAME(mux_pll_p) = { "xin24m", "xin32k" }; | 168 | PNAME(mux_pll_p) = { "xin24m", "xin32k" }; |
| 105 | PNAME(mux_armclk_p) = { "apll_core", "gpll_core" }; | 169 | PNAME(mux_armclk_p) = { "apll_core", "gpll_core" }; |
| 106 | PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr" }; | 170 | PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr" }; |
| @@ -143,7 +207,7 @@ static struct rockchip_pll_clock rk3288_pll_clks[] __initdata = { | |||
| 143 | [gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3288_PLL_CON(12), | 207 | [gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3288_PLL_CON(12), |
| 144 | RK3288_MODE_CON, 12, 8, rk3288_pll_rates), | 208 | RK3288_MODE_CON, 12, 8, rk3288_pll_rates), |
| 145 | [npll] = PLL(pll_rk3066, PLL_NPLL, "npll", mux_pll_p, 0, RK3288_PLL_CON(16), | 209 | [npll] = PLL(pll_rk3066, PLL_NPLL, "npll", mux_pll_p, 0, RK3288_PLL_CON(16), |
| 146 | RK3288_MODE_CON, 14, 9, NULL), | 210 | RK3288_MODE_CON, 14, 9, rk3288_pll_rates), |
| 147 | }; | 211 | }; |
| 148 | 212 | ||
| 149 | static struct clk_div_table div_hclk_cpu_t[] = { | 213 | static struct clk_div_table div_hclk_cpu_t[] = { |
| @@ -166,35 +230,33 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { | |||
| 166 | RK3288_CLKGATE_CON(0), 1, GFLAGS), | 230 | RK3288_CLKGATE_CON(0), 1, GFLAGS), |
| 167 | GATE(0, "gpll_core", "gpll", 0, | 231 | GATE(0, "gpll_core", "gpll", 0, |
| 168 | RK3288_CLKGATE_CON(0), 2, GFLAGS), | 232 | RK3288_CLKGATE_CON(0), 2, GFLAGS), |
| 169 | COMPOSITE_NOGATE(0, "armclk", mux_armclk_p, 0, | ||
| 170 | RK3288_CLKSEL_CON(0), 15, 1, MFLAGS, 8, 5, DFLAGS), | ||
| 171 | 233 | ||
| 172 | COMPOSITE_NOMUX(0, "armcore0", "armclk", 0, | 234 | COMPOSITE_NOMUX(0, "armcore0", "armclk", 0, |
| 173 | RK3288_CLKSEL_CON(36), 0, 3, DFLAGS, | 235 | RK3288_CLKSEL_CON(36), 0, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, |
| 174 | RK3288_CLKGATE_CON(12), 0, GFLAGS), | 236 | RK3288_CLKGATE_CON(12), 0, GFLAGS), |
| 175 | COMPOSITE_NOMUX(0, "armcore1", "armclk", 0, | 237 | COMPOSITE_NOMUX(0, "armcore1", "armclk", 0, |
| 176 | RK3288_CLKSEL_CON(36), 4, 3, DFLAGS, | 238 | RK3288_CLKSEL_CON(36), 4, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, |
| 177 | RK3288_CLKGATE_CON(12), 1, GFLAGS), | 239 | RK3288_CLKGATE_CON(12), 1, GFLAGS), |
| 178 | COMPOSITE_NOMUX(0, "armcore2", "armclk", 0, | 240 | COMPOSITE_NOMUX(0, "armcore2", "armclk", 0, |
| 179 | RK3288_CLKSEL_CON(36), 8, 3, DFLAGS, | 241 | RK3288_CLKSEL_CON(36), 8, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, |
| 180 | RK3288_CLKGATE_CON(12), 2, GFLAGS), | 242 | RK3288_CLKGATE_CON(12), 2, GFLAGS), |
| 181 | COMPOSITE_NOMUX(0, "armcore3", "armclk", 0, | 243 | COMPOSITE_NOMUX(0, "armcore3", "armclk", 0, |
| 182 | RK3288_CLKSEL_CON(36), 12, 3, DFLAGS, | 244 | RK3288_CLKSEL_CON(36), 12, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, |
| 183 | RK3288_CLKGATE_CON(12), 3, GFLAGS), | 245 | RK3288_CLKGATE_CON(12), 3, GFLAGS), |
| 184 | COMPOSITE_NOMUX(0, "l2ram", "armclk", 0, | 246 | COMPOSITE_NOMUX(0, "l2ram", "armclk", 0, |
| 185 | RK3288_CLKSEL_CON(37), 0, 3, DFLAGS, | 247 | RK3288_CLKSEL_CON(37), 0, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, |
| 186 | RK3288_CLKGATE_CON(12), 4, GFLAGS), | 248 | RK3288_CLKGATE_CON(12), 4, GFLAGS), |
| 187 | COMPOSITE_NOMUX(0, "aclk_core_m0", "armclk", 0, | 249 | COMPOSITE_NOMUX(0, "aclk_core_m0", "armclk", 0, |
| 188 | RK3288_CLKSEL_CON(0), 0, 4, DFLAGS, | 250 | RK3288_CLKSEL_CON(0), 0, 4, DFLAGS | CLK_DIVIDER_READ_ONLY, |
| 189 | RK3288_CLKGATE_CON(12), 5, GFLAGS), | 251 | RK3288_CLKGATE_CON(12), 5, GFLAGS), |
| 190 | COMPOSITE_NOMUX(0, "aclk_core_mp", "armclk", 0, | 252 | COMPOSITE_NOMUX(0, "aclk_core_mp", "armclk", 0, |
| 191 | RK3288_CLKSEL_CON(0), 4, 4, DFLAGS, | 253 | RK3288_CLKSEL_CON(0), 4, 4, DFLAGS | CLK_DIVIDER_READ_ONLY, |
| 192 | RK3288_CLKGATE_CON(12), 6, GFLAGS), | 254 | RK3288_CLKGATE_CON(12), 6, GFLAGS), |
| 193 | COMPOSITE_NOMUX(0, "atclk", "armclk", 0, | 255 | COMPOSITE_NOMUX(0, "atclk", "armclk", 0, |
| 194 | RK3288_CLKSEL_CON(37), 4, 5, DFLAGS, | 256 | RK3288_CLKSEL_CON(37), 4, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, |
| 195 | RK3288_CLKGATE_CON(12), 7, GFLAGS), | 257 | RK3288_CLKGATE_CON(12), 7, GFLAGS), |
| 196 | COMPOSITE_NOMUX(0, "pclk_dbg_pre", "armclk", 0, | 258 | COMPOSITE_NOMUX(0, "pclk_dbg_pre", "armclk", 0, |
| 197 | RK3288_CLKSEL_CON(37), 9, 5, DFLAGS, | 259 | RK3288_CLKSEL_CON(37), 9, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, |
| 198 | RK3288_CLKGATE_CON(12), 8, GFLAGS), | 260 | RK3288_CLKGATE_CON(12), 8, GFLAGS), |
| 199 | GATE(0, "pclk_dbg", "pclk_dbg_pre", 0, | 261 | GATE(0, "pclk_dbg", "pclk_dbg_pre", 0, |
| 200 | RK3288_CLKGATE_CON(12), 9, GFLAGS), | 262 | RK3288_CLKGATE_CON(12), 9, GFLAGS), |
| @@ -219,12 +281,12 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { | |||
| 219 | RK3288_CLKSEL_CON(1), 15, 1, MFLAGS, 3, 5, DFLAGS), | 281 | RK3288_CLKSEL_CON(1), 15, 1, MFLAGS, 3, 5, DFLAGS), |
| 220 | DIV(0, "aclk_cpu_pre", "aclk_cpu_src", 0, | 282 | DIV(0, "aclk_cpu_pre", "aclk_cpu_src", 0, |
| 221 | RK3288_CLKSEL_CON(1), 0, 3, DFLAGS), | 283 | RK3288_CLKSEL_CON(1), 0, 3, DFLAGS), |
| 222 | GATE(0, "aclk_cpu", "aclk_cpu_pre", 0, | 284 | GATE(ACLK_CPU, "aclk_cpu", "aclk_cpu_pre", 0, |
| 223 | RK3288_CLKGATE_CON(0), 3, GFLAGS), | 285 | RK3288_CLKGATE_CON(0), 3, GFLAGS), |
| 224 | COMPOSITE_NOMUX(0, "pclk_cpu", "aclk_cpu_pre", 0, | 286 | COMPOSITE_NOMUX(PCLK_CPU, "pclk_cpu", "aclk_cpu_pre", 0, |
| 225 | RK3288_CLKSEL_CON(1), 12, 3, DFLAGS, | 287 | RK3288_CLKSEL_CON(1), 12, 3, DFLAGS, |
| 226 | RK3288_CLKGATE_CON(0), 5, GFLAGS), | 288 | RK3288_CLKGATE_CON(0), 5, GFLAGS), |
| 227 | COMPOSITE_NOMUX_DIVTBL(0, "hclk_cpu", "aclk_cpu_pre", 0, | 289 | COMPOSITE_NOMUX_DIVTBL(HCLK_CPU, "hclk_cpu", "aclk_cpu_pre", 0, |
| 228 | RK3288_CLKSEL_CON(1), 8, 2, DFLAGS, div_hclk_cpu_t, | 290 | RK3288_CLKSEL_CON(1), 8, 2, DFLAGS, div_hclk_cpu_t, |
| 229 | RK3288_CLKGATE_CON(0), 4, GFLAGS), | 291 | RK3288_CLKGATE_CON(0), 4, GFLAGS), |
| 230 | GATE(0, "c2c_host", "aclk_cpu_src", 0, | 292 | GATE(0, "c2c_host", "aclk_cpu_src", 0, |
| @@ -238,15 +300,15 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { | |||
| 238 | COMPOSITE(0, "i2s_src", mux_pll_src_cpll_gpll_p, 0, | 300 | COMPOSITE(0, "i2s_src", mux_pll_src_cpll_gpll_p, 0, |
| 239 | RK3288_CLKSEL_CON(4), 15, 1, MFLAGS, 0, 7, DFLAGS, | 301 | RK3288_CLKSEL_CON(4), 15, 1, MFLAGS, 0, 7, DFLAGS, |
| 240 | RK3288_CLKGATE_CON(4), 1, GFLAGS), | 302 | RK3288_CLKGATE_CON(4), 1, GFLAGS), |
| 241 | COMPOSITE_FRAC(0, "i2s_frac", "i2s_src", 0, | 303 | COMPOSITE_FRAC(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT, |
| 242 | RK3288_CLKSEL_CON(8), 0, | 304 | RK3288_CLKSEL_CON(8), 0, |
| 243 | RK3288_CLKGATE_CON(4), 2, GFLAGS), | 305 | RK3288_CLKGATE_CON(4), 2, GFLAGS), |
| 244 | MUX(0, "i2s_pre", mux_i2s_pre_p, 0, | 306 | MUX(0, "i2s_pre", mux_i2s_pre_p, CLK_SET_RATE_PARENT, |
| 245 | RK3288_CLKSEL_CON(4), 8, 2, MFLAGS), | 307 | RK3288_CLKSEL_CON(4), 8, 2, MFLAGS), |
| 246 | COMPOSITE_NODIV(0, "i2s0_clkout", mux_i2s_clkout_p, 0, | 308 | COMPOSITE_NODIV(0, "i2s0_clkout", mux_i2s_clkout_p, CLK_SET_RATE_PARENT, |
| 247 | RK3288_CLKSEL_CON(4), 12, 1, MFLAGS, | 309 | RK3288_CLKSEL_CON(4), 12, 1, MFLAGS, |
| 248 | RK3288_CLKGATE_CON(4), 0, GFLAGS), | 310 | RK3288_CLKGATE_CON(4), 0, GFLAGS), |
| 249 | GATE(SCLK_I2S0, "sclk_i2s0", "i2s_pre", 0, | 311 | GATE(SCLK_I2S0, "sclk_i2s0", "i2s_pre", CLK_SET_RATE_PARENT, |
| 250 | RK3288_CLKGATE_CON(4), 3, GFLAGS), | 312 | RK3288_CLKGATE_CON(4), 3, GFLAGS), |
| 251 | 313 | ||
| 252 | MUX(0, "spdif_src", mux_pll_src_cpll_gpll_p, 0, | 314 | MUX(0, "spdif_src", mux_pll_src_cpll_gpll_p, 0, |
| @@ -296,6 +358,20 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { | |||
| 296 | COMPOSITE(0, "aclk_vdpu", mux_pll_src_cpll_gpll_usb480m_p, 0, | 358 | COMPOSITE(0, "aclk_vdpu", mux_pll_src_cpll_gpll_usb480m_p, 0, |
| 297 | RK3288_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS, | 359 | RK3288_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS, |
| 298 | RK3288_CLKGATE_CON(3), 11, GFLAGS), | 360 | RK3288_CLKGATE_CON(3), 11, GFLAGS), |
| 361 | /* | ||
| 362 | * We use aclk_vdpu by default GRF_SOC_CON0[7] setting in system, | ||
| 363 | * so we ignore the mux and make clocks nodes as following, | ||
| 364 | */ | ||
| 365 | GATE(ACLK_VCODEC, "aclk_vcodec", "aclk_vdpu", 0, | ||
| 366 | RK3288_CLKGATE_CON(9), 0, GFLAGS), | ||
| 367 | /* | ||
| 368 | * We introduce a virtul node of hclk_vodec_pre_v to split one clock | ||
| 369 | * struct with a gate and a fix divider into two node in software. | ||
| 370 | */ | ||
| 371 | GATE(0, "hclk_vcodec_pre_v", "aclk_vdpu", 0, | ||
| 372 | RK3288_CLKGATE_CON(3), 10, GFLAGS), | ||
| 373 | GATE(HCLK_VCODEC, "hclk_vcodec", "hclk_vcodec_pre", 0, | ||
| 374 | RK3288_CLKGATE_CON(9), 1, GFLAGS), | ||
| 299 | 375 | ||
| 300 | COMPOSITE(0, "aclk_vio0", mux_pll_src_cpll_gpll_usb480m_p, 0, | 376 | COMPOSITE(0, "aclk_vio0", mux_pll_src_cpll_gpll_usb480m_p, 0, |
| 301 | RK3288_CLKSEL_CON(31), 6, 2, MFLAGS, 0, 5, DFLAGS, | 377 | RK3288_CLKSEL_CON(31), 6, 2, MFLAGS, 0, 5, DFLAGS, |
| @@ -309,7 +385,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { | |||
| 309 | COMPOSITE(0, "aclk_rga_pre", mux_pll_src_cpll_gpll_usb480m_p, 0, | 385 | COMPOSITE(0, "aclk_rga_pre", mux_pll_src_cpll_gpll_usb480m_p, 0, |
| 310 | RK3288_CLKSEL_CON(30), 6, 2, MFLAGS, 0, 5, DFLAGS, | 386 | RK3288_CLKSEL_CON(30), 6, 2, MFLAGS, 0, 5, DFLAGS, |
| 311 | RK3288_CLKGATE_CON(3), 5, GFLAGS), | 387 | RK3288_CLKGATE_CON(3), 5, GFLAGS), |
| 312 | COMPOSITE(0, "sclk_rga", mux_pll_src_cpll_gpll_usb480m_p, 0, | 388 | COMPOSITE(SCLK_RGA, "sclk_rga", mux_pll_src_cpll_gpll_usb480m_p, 0, |
| 313 | RK3288_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS, | 389 | RK3288_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS, |
| 314 | RK3288_CLKGATE_CON(3), 4, GFLAGS), | 390 | RK3288_CLKGATE_CON(3), 4, GFLAGS), |
| 315 | 391 | ||
| @@ -320,35 +396,35 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { | |||
| 320 | RK3288_CLKSEL_CON(29), 6, 2, MFLAGS, 8, 8, DFLAGS, | 396 | RK3288_CLKSEL_CON(29), 6, 2, MFLAGS, 8, 8, DFLAGS, |
| 321 | RK3288_CLKGATE_CON(3), 3, GFLAGS), | 397 | RK3288_CLKGATE_CON(3), 3, GFLAGS), |
| 322 | 398 | ||
| 323 | COMPOSITE_NODIV(0, "sclk_edp_24m", mux_edp_24m_p, 0, | 399 | COMPOSITE_NODIV(SCLK_EDP_24M, "sclk_edp_24m", mux_edp_24m_p, 0, |
| 324 | RK3288_CLKSEL_CON(28), 15, 1, MFLAGS, | 400 | RK3288_CLKSEL_CON(28), 15, 1, MFLAGS, |
| 325 | RK3288_CLKGATE_CON(3), 12, GFLAGS), | 401 | RK3288_CLKGATE_CON(3), 12, GFLAGS), |
| 326 | COMPOSITE(0, "sclk_edp", mux_pll_src_cpll_gpll_npll_p, 0, | 402 | COMPOSITE(SCLK_EDP, "sclk_edp", mux_pll_src_cpll_gpll_npll_p, 0, |
| 327 | RK3288_CLKSEL_CON(28), 6, 2, MFLAGS, 0, 6, DFLAGS, | 403 | RK3288_CLKSEL_CON(28), 6, 2, MFLAGS, 0, 6, DFLAGS, |
| 328 | RK3288_CLKGATE_CON(3), 13, GFLAGS), | 404 | RK3288_CLKGATE_CON(3), 13, GFLAGS), |
| 329 | 405 | ||
| 330 | COMPOSITE(0, "sclk_isp", mux_pll_src_cpll_gpll_npll_p, 0, | 406 | COMPOSITE(SCLK_ISP, "sclk_isp", mux_pll_src_cpll_gpll_npll_p, 0, |
| 331 | RK3288_CLKSEL_CON(6), 6, 2, MFLAGS, 0, 6, DFLAGS, | 407 | RK3288_CLKSEL_CON(6), 6, 2, MFLAGS, 0, 6, DFLAGS, |
| 332 | RK3288_CLKGATE_CON(3), 14, GFLAGS), | 408 | RK3288_CLKGATE_CON(3), 14, GFLAGS), |
| 333 | COMPOSITE(0, "sclk_isp_jpe", mux_pll_src_cpll_gpll_npll_p, 0, | 409 | COMPOSITE(SCLK_ISP_JPE, "sclk_isp_jpe", mux_pll_src_cpll_gpll_npll_p, 0, |
| 334 | RK3288_CLKSEL_CON(6), 14, 2, MFLAGS, 8, 6, DFLAGS, | 410 | RK3288_CLKSEL_CON(6), 14, 2, MFLAGS, 8, 6, DFLAGS, |
| 335 | RK3288_CLKGATE_CON(3), 15, GFLAGS), | 411 | RK3288_CLKGATE_CON(3), 15, GFLAGS), |
| 336 | 412 | ||
| 337 | GATE(0, "sclk_hdmi_hdcp", "xin24m", 0, | 413 | GATE(SCLK_HDMI_HDCP, "sclk_hdmi_hdcp", "xin24m", 0, |
| 338 | RK3288_CLKGATE_CON(5), 12, GFLAGS), | 414 | RK3288_CLKGATE_CON(5), 12, GFLAGS), |
| 339 | GATE(0, "sclk_hdmi_cec", "xin32k", 0, | 415 | GATE(SCLK_HDMI_CEC, "sclk_hdmi_cec", "xin32k", 0, |
| 340 | RK3288_CLKGATE_CON(5), 11, GFLAGS), | 416 | RK3288_CLKGATE_CON(5), 11, GFLAGS), |
| 341 | 417 | ||
| 342 | COMPOSITE(0, "aclk_hevc", mux_pll_src_cpll_gpll_npll_p, 0, | 418 | COMPOSITE(ACLK_HEVC, "aclk_hevc", mux_pll_src_cpll_gpll_npll_p, 0, |
| 343 | RK3288_CLKSEL_CON(39), 14, 2, MFLAGS, 8, 5, DFLAGS, | 419 | RK3288_CLKSEL_CON(39), 14, 2, MFLAGS, 8, 5, DFLAGS, |
| 344 | RK3288_CLKGATE_CON(13), 13, GFLAGS), | 420 | RK3288_CLKGATE_CON(13), 13, GFLAGS), |
| 345 | DIV(0, "hclk_hevc", "aclk_hevc", 0, | 421 | DIV(HCLK_HEVC, "hclk_hevc", "aclk_hevc", 0, |
| 346 | RK3288_CLKSEL_CON(40), 12, 2, DFLAGS), | 422 | RK3288_CLKSEL_CON(40), 12, 2, DFLAGS), |
| 347 | 423 | ||
| 348 | COMPOSITE(0, "sclk_hevc_cabac", mux_pll_src_cpll_gpll_npll_p, 0, | 424 | COMPOSITE(SCLK_HEVC_CABAC, "sclk_hevc_cabac", mux_pll_src_cpll_gpll_npll_p, 0, |
| 349 | RK3288_CLKSEL_CON(42), 6, 2, MFLAGS, 0, 5, DFLAGS, | 425 | RK3288_CLKSEL_CON(42), 6, 2, MFLAGS, 0, 5, DFLAGS, |
| 350 | RK3288_CLKGATE_CON(13), 14, GFLAGS), | 426 | RK3288_CLKGATE_CON(13), 14, GFLAGS), |
| 351 | COMPOSITE(0, "sclk_hevc_core", mux_pll_src_cpll_gpll_npll_p, 0, | 427 | COMPOSITE(SCLK_HEVC_CORE, "sclk_hevc_core", mux_pll_src_cpll_gpll_npll_p, 0, |
| 352 | RK3288_CLKSEL_CON(42), 14, 2, MFLAGS, 8, 5, DFLAGS, | 428 | RK3288_CLKSEL_CON(42), 14, 2, MFLAGS, 8, 5, DFLAGS, |
| 353 | RK3288_CLKGATE_CON(13), 15, GFLAGS), | 429 | RK3288_CLKGATE_CON(13), 15, GFLAGS), |
| 354 | 430 | ||
| @@ -371,13 +447,13 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { | |||
| 371 | COMPOSITE(0, "aclk_peri_src", mux_pll_src_cpll_gpll_p, 0, | 447 | COMPOSITE(0, "aclk_peri_src", mux_pll_src_cpll_gpll_p, 0, |
| 372 | RK3288_CLKSEL_CON(10), 15, 1, MFLAGS, 0, 5, DFLAGS, | 448 | RK3288_CLKSEL_CON(10), 15, 1, MFLAGS, 0, 5, DFLAGS, |
| 373 | RK3288_CLKGATE_CON(2), 0, GFLAGS), | 449 | RK3288_CLKGATE_CON(2), 0, GFLAGS), |
| 374 | COMPOSITE_NOMUX(0, "pclk_peri", "aclk_peri_src", 0, | 450 | COMPOSITE_NOMUX(PCLK_PERI, "pclk_peri", "aclk_peri_src", 0, |
| 375 | RK3288_CLKSEL_CON(10), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, | 451 | RK3288_CLKSEL_CON(10), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, |
| 376 | RK3288_CLKGATE_CON(2), 3, GFLAGS), | 452 | RK3288_CLKGATE_CON(2), 3, GFLAGS), |
| 377 | COMPOSITE_NOMUX(0, "hclk_peri", "aclk_peri_src", 0, | 453 | COMPOSITE_NOMUX(HCLK_PERI, "hclk_peri", "aclk_peri_src", 0, |
| 378 | RK3288_CLKSEL_CON(10), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, | 454 | RK3288_CLKSEL_CON(10), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, |
| 379 | RK3288_CLKGATE_CON(2), 2, GFLAGS), | 455 | RK3288_CLKGATE_CON(2), 2, GFLAGS), |
| 380 | GATE(0, "aclk_peri", "aclk_peri_src", 0, | 456 | GATE(ACLK_PERI, "aclk_peri", "aclk_peri_src", 0, |
| 381 | RK3288_CLKGATE_CON(2), 1, GFLAGS), | 457 | RK3288_CLKGATE_CON(2), 1, GFLAGS), |
| 382 | 458 | ||
| 383 | /* | 459 | /* |
| @@ -643,34 +719,34 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { | |||
| 643 | GATE(HCLK_RGA, "hclk_rga", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 1, GFLAGS), | 719 | GATE(HCLK_RGA, "hclk_rga", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 1, GFLAGS), |
| 644 | GATE(HCLK_VOP0, "hclk_vop0", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 6, GFLAGS), | 720 | GATE(HCLK_VOP0, "hclk_vop0", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 6, GFLAGS), |
| 645 | GATE(HCLK_VOP1, "hclk_vop1", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 8, GFLAGS), | 721 | GATE(HCLK_VOP1, "hclk_vop1", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 8, GFLAGS), |
| 646 | GATE(0, "hclk_vio_ahb_arbi", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 9, GFLAGS), | 722 | GATE(HCLK_VIO_AHB_ARBI, "hclk_vio_ahb_arbi", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 9, GFLAGS), |
| 647 | GATE(0, "hclk_vio_niu", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 10, GFLAGS), | 723 | GATE(HCLK_VIO_NIU, "hclk_vio_niu", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 10, GFLAGS), |
| 648 | GATE(0, "hclk_vip", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 15, GFLAGS), | 724 | GATE(HCLK_VIP, "hclk_vip", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 15, GFLAGS), |
| 649 | GATE(HCLK_IEP, "hclk_iep", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 3, GFLAGS), | 725 | GATE(HCLK_IEP, "hclk_iep", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 3, GFLAGS), |
| 650 | GATE(HCLK_ISP, "hclk_isp", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 1, GFLAGS), | 726 | GATE(HCLK_ISP, "hclk_isp", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 1, GFLAGS), |
| 651 | GATE(0, "hclk_vio2_h2p", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 10, GFLAGS), | 727 | GATE(HCLK_VIO2_H2P, "hclk_vio2_h2p", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 10, GFLAGS), |
| 652 | GATE(0, "pclk_mipi_dsi0", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 4, GFLAGS), | 728 | GATE(PCLK_MIPI_DSI0, "pclk_mipi_dsi0", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 4, GFLAGS), |
| 653 | GATE(0, "pclk_mipi_dsi1", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 5, GFLAGS), | 729 | GATE(PCLK_MIPI_DSI1, "pclk_mipi_dsi1", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 5, GFLAGS), |
| 654 | GATE(0, "pclk_mipi_csi", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 6, GFLAGS), | 730 | GATE(PCLK_MIPI_CSI, "pclk_mipi_csi", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 6, GFLAGS), |
| 655 | GATE(0, "pclk_lvds_phy", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 7, GFLAGS), | 731 | GATE(PCLK_LVDS_PHY, "pclk_lvds_phy", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 7, GFLAGS), |
| 656 | GATE(0, "pclk_edp_ctrl", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 8, GFLAGS), | 732 | GATE(PCLK_EDP_CTRL, "pclk_edp_ctrl", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 8, GFLAGS), |
| 657 | GATE(0, "pclk_hdmi_ctrl", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 9, GFLAGS), | 733 | GATE(PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 9, GFLAGS), |
| 658 | GATE(0, "pclk_vio2_h2p", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 11, GFLAGS), | 734 | GATE(PCLK_VIO2_H2P, "pclk_vio2_h2p", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 11, GFLAGS), |
| 659 | 735 | ||
| 660 | /* aclk_vio0 gates */ | 736 | /* aclk_vio0 gates */ |
| 661 | GATE(ACLK_VOP0, "aclk_vop0", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 5, GFLAGS), | 737 | GATE(ACLK_VOP0, "aclk_vop0", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 5, GFLAGS), |
| 662 | GATE(0, "aclk_iep", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 2, GFLAGS), | 738 | GATE(ACLK_IEP, "aclk_iep", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 2, GFLAGS), |
| 663 | GATE(0, "aclk_vio0_niu", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 11, GFLAGS), | 739 | GATE(ACLK_VIO0_NIU, "aclk_vio0_niu", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 11, GFLAGS), |
| 664 | GATE(0, "aclk_vip", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 14, GFLAGS), | 740 | GATE(ACLK_VIP, "aclk_vip", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 14, GFLAGS), |
| 665 | 741 | ||
| 666 | /* aclk_vio1 gates */ | 742 | /* aclk_vio1 gates */ |
| 667 | GATE(ACLK_VOP1, "aclk_vop1", "aclk_vio1", 0, RK3288_CLKGATE_CON(15), 7, GFLAGS), | 743 | GATE(ACLK_VOP1, "aclk_vop1", "aclk_vio1", 0, RK3288_CLKGATE_CON(15), 7, GFLAGS), |
| 668 | GATE(0, "aclk_isp", "aclk_vio1", 0, RK3288_CLKGATE_CON(16), 2, GFLAGS), | 744 | GATE(ACLK_ISP, "aclk_isp", "aclk_vio1", 0, RK3288_CLKGATE_CON(16), 2, GFLAGS), |
| 669 | GATE(0, "aclk_vio1_niu", "aclk_vio1", 0, RK3288_CLKGATE_CON(15), 12, GFLAGS), | 745 | GATE(ACLK_VIO1_NIU, "aclk_vio1_niu", "aclk_vio1", 0, RK3288_CLKGATE_CON(15), 12, GFLAGS), |
| 670 | 746 | ||
| 671 | /* aclk_rga_pre gates */ | 747 | /* aclk_rga_pre gates */ |
| 672 | GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0, RK3288_CLKGATE_CON(15), 0, GFLAGS), | 748 | GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0, RK3288_CLKGATE_CON(15), 0, GFLAGS), |
| 673 | GATE(0, "aclk_rga_niu", "aclk_rga_pre", 0, RK3288_CLKGATE_CON(15), 13, GFLAGS), | 749 | GATE(ACLK_RGA_NIU, "aclk_rga_niu", "aclk_rga_pre", 0, RK3288_CLKGATE_CON(15), 13, GFLAGS), |
| 674 | 750 | ||
| 675 | /* | 751 | /* |
| 676 | * Other ungrouped clocks. | 752 | * Other ungrouped clocks. |
| @@ -680,6 +756,12 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { | |||
| 680 | GATE(0, "pclk_isp_in", "ext_isp", 0, RK3288_CLKGATE_CON(16), 3, GFLAGS), | 756 | GATE(0, "pclk_isp_in", "ext_isp", 0, RK3288_CLKGATE_CON(16), 3, GFLAGS), |
| 681 | }; | 757 | }; |
| 682 | 758 | ||
| 759 | static const char *rk3288_critical_clocks[] __initconst = { | ||
| 760 | "aclk_cpu", | ||
| 761 | "aclk_peri", | ||
| 762 | "hclk_peri", | ||
| 763 | }; | ||
| 764 | |||
| 683 | static void __init rk3288_clk_init(struct device_node *np) | 765 | static void __init rk3288_clk_init(struct device_node *np) |
| 684 | { | 766 | { |
| 685 | void __iomem *reg_base; | 767 | void __iomem *reg_base; |
| @@ -705,13 +787,28 @@ static void __init rk3288_clk_init(struct device_node *np) | |||
| 705 | pr_warn("%s: could not register clock usb480m: %ld\n", | 787 | pr_warn("%s: could not register clock usb480m: %ld\n", |
| 706 | __func__, PTR_ERR(clk)); | 788 | __func__, PTR_ERR(clk)); |
| 707 | 789 | ||
| 790 | clk = clk_register_fixed_factor(NULL, "hclk_vcodec_pre", | ||
| 791 | "hclk_vcodec_pre_v", 0, 1, 4); | ||
| 792 | if (IS_ERR(clk)) | ||
| 793 | pr_warn("%s: could not register clock hclk_vcodec_pre: %ld\n", | ||
| 794 | __func__, PTR_ERR(clk)); | ||
| 795 | |||
| 708 | rockchip_clk_register_plls(rk3288_pll_clks, | 796 | rockchip_clk_register_plls(rk3288_pll_clks, |
| 709 | ARRAY_SIZE(rk3288_pll_clks), | 797 | ARRAY_SIZE(rk3288_pll_clks), |
| 710 | RK3288_GRF_SOC_STATUS); | 798 | RK3288_GRF_SOC_STATUS1); |
| 711 | rockchip_clk_register_branches(rk3288_clk_branches, | 799 | rockchip_clk_register_branches(rk3288_clk_branches, |
| 712 | ARRAY_SIZE(rk3288_clk_branches)); | 800 | ARRAY_SIZE(rk3288_clk_branches)); |
| 801 | rockchip_clk_protect_critical(rk3288_critical_clocks, | ||
| 802 | ARRAY_SIZE(rk3288_critical_clocks)); | ||
| 713 | 803 | ||
| 714 | rockchip_register_softrst(np, 9, reg_base + RK3288_SOFTRST_CON(0), | 804 | rockchip_clk_register_armclk(ARMCLK, "armclk", |
| 805 | mux_armclk_p, ARRAY_SIZE(mux_armclk_p), | ||
| 806 | &rk3288_cpuclk_data, rk3288_cpuclk_rates, | ||
| 807 | ARRAY_SIZE(rk3288_cpuclk_rates)); | ||
| 808 | |||
| 809 | rockchip_register_softrst(np, 12, reg_base + RK3288_SOFTRST_CON(0), | ||
| 715 | ROCKCHIP_SOFTRST_HIWORD_MASK); | 810 | ROCKCHIP_SOFTRST_HIWORD_MASK); |
| 811 | |||
| 812 | rockchip_register_restart_notifier(RK3288_GLB_SRST_FST); | ||
| 716 | } | 813 | } |
| 717 | CLK_OF_DECLARE(rk3288_cru, "rockchip,rk3288-cru", rk3288_clk_init); | 814 | CLK_OF_DECLARE(rk3288_cru, "rockchip,rk3288-cru", rk3288_clk_init); |
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index 278cf9dd1e23..1e68bff481b8 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/clk-provider.h> | 25 | #include <linux/clk-provider.h> |
| 26 | #include <linux/mfd/syscon.h> | 26 | #include <linux/mfd/syscon.h> |
| 27 | #include <linux/regmap.h> | 27 | #include <linux/regmap.h> |
| 28 | #include <linux/reboot.h> | ||
| 28 | #include "clk.h" | 29 | #include "clk.h" |
| 29 | 30 | ||
| 30 | /** | 31 | /** |
| @@ -37,7 +38,7 @@ | |||
| 37 | * | 38 | * |
| 38 | * sometimes without one of those components. | 39 | * sometimes without one of those components. |
| 39 | */ | 40 | */ |
| 40 | struct clk *rockchip_clk_register_branch(const char *name, | 41 | static struct clk *rockchip_clk_register_branch(const char *name, |
| 41 | const char **parent_names, u8 num_parents, void __iomem *base, | 42 | const char **parent_names, u8 num_parents, void __iomem *base, |
| 42 | int muxdiv_offset, u8 mux_shift, u8 mux_width, u8 mux_flags, | 43 | int muxdiv_offset, u8 mux_shift, u8 mux_width, u8 mux_flags, |
| 43 | u8 div_shift, u8 div_width, u8 div_flags, | 44 | u8 div_shift, u8 div_width, u8 div_flags, |
| @@ -103,6 +104,54 @@ struct clk *rockchip_clk_register_branch(const char *name, | |||
| 103 | return clk; | 104 | return clk; |
| 104 | } | 105 | } |
| 105 | 106 | ||
| 107 | static struct clk *rockchip_clk_register_frac_branch(const char *name, | ||
| 108 | const char **parent_names, u8 num_parents, void __iomem *base, | ||
| 109 | int muxdiv_offset, u8 div_flags, | ||
| 110 | int gate_offset, u8 gate_shift, u8 gate_flags, | ||
| 111 | unsigned long flags, spinlock_t *lock) | ||
| 112 | { | ||
| 113 | struct clk *clk; | ||
| 114 | struct clk_gate *gate = NULL; | ||
| 115 | struct clk_fractional_divider *div = NULL; | ||
| 116 | const struct clk_ops *div_ops = NULL, *gate_ops = NULL; | ||
| 117 | |||
| 118 | if (gate_offset >= 0) { | ||
| 119 | gate = kzalloc(sizeof(*gate), GFP_KERNEL); | ||
| 120 | if (!gate) | ||
| 121 | return ERR_PTR(-ENOMEM); | ||
| 122 | |||
| 123 | gate->flags = gate_flags; | ||
| 124 | gate->reg = base + gate_offset; | ||
| 125 | gate->bit_idx = gate_shift; | ||
| 126 | gate->lock = lock; | ||
| 127 | gate_ops = &clk_gate_ops; | ||
| 128 | } | ||
| 129 | |||
| 130 | if (muxdiv_offset < 0) | ||
| 131 | return ERR_PTR(-EINVAL); | ||
| 132 | |||
| 133 | div = kzalloc(sizeof(*div), GFP_KERNEL); | ||
| 134 | if (!div) | ||
| 135 | return ERR_PTR(-ENOMEM); | ||
| 136 | |||
| 137 | div->flags = div_flags; | ||
| 138 | div->reg = base + muxdiv_offset; | ||
| 139 | div->mshift = 16; | ||
| 140 | div->mmask = 0xffff0000; | ||
| 141 | div->nshift = 0; | ||
| 142 | div->nmask = 0xffff; | ||
| 143 | div->lock = lock; | ||
| 144 | div_ops = &clk_fractional_divider_ops; | ||
| 145 | |||
| 146 | clk = clk_register_composite(NULL, name, parent_names, num_parents, | ||
| 147 | NULL, NULL, | ||
| 148 | &div->hw, div_ops, | ||
| 149 | gate ? &gate->hw : NULL, gate_ops, | ||
| 150 | flags); | ||
| 151 | |||
| 152 | return clk; | ||
| 153 | } | ||
| 154 | |||
| 106 | static DEFINE_SPINLOCK(clk_lock); | 155 | static DEFINE_SPINLOCK(clk_lock); |
| 107 | static struct clk **clk_table; | 156 | static struct clk **clk_table; |
| 108 | static void __iomem *reg_base; | 157 | static void __iomem *reg_base; |
| @@ -197,8 +246,14 @@ void __init rockchip_clk_register_branches( | |||
| 197 | list->div_flags, &clk_lock); | 246 | list->div_flags, &clk_lock); |
| 198 | break; | 247 | break; |
| 199 | case branch_fraction_divider: | 248 | case branch_fraction_divider: |
| 200 | /* unimplemented */ | 249 | /* keep all gates untouched for now */ |
| 201 | continue; | 250 | flags |= CLK_IGNORE_UNUSED; |
| 251 | |||
| 252 | clk = rockchip_clk_register_frac_branch(list->name, | ||
| 253 | list->parent_names, list->num_parents, | ||
| 254 | reg_base, list->muxdiv_offset, list->div_flags, | ||
| 255 | list->gate_offset, list->gate_shift, | ||
| 256 | list->gate_flags, flags, &clk_lock); | ||
| 202 | break; | 257 | break; |
| 203 | case branch_gate: | 258 | case branch_gate: |
| 204 | flags |= CLK_SET_RATE_PARENT; | 259 | flags |= CLK_SET_RATE_PARENT; |
| @@ -242,3 +297,61 @@ void __init rockchip_clk_register_branches( | |||
| 242 | rockchip_clk_add_lookup(clk, list->id); | 297 | rockchip_clk_add_lookup(clk, list->id); |
| 243 | } | 298 | } |
| 244 | } | 299 | } |
| 300 | |||
| 301 | void __init rockchip_clk_register_armclk(unsigned int lookup_id, | ||
| 302 | const char *name, const char **parent_names, | ||
| 303 | u8 num_parents, | ||
| 304 | const struct rockchip_cpuclk_reg_data *reg_data, | ||
| 305 | const struct rockchip_cpuclk_rate_table *rates, | ||
| 306 | int nrates) | ||
| 307 | { | ||
| 308 | struct clk *clk; | ||
| 309 | |||
| 310 | clk = rockchip_clk_register_cpuclk(name, parent_names, num_parents, | ||
| 311 | reg_data, rates, nrates, reg_base, | ||
| 312 | &clk_lock); | ||
| 313 | if (IS_ERR(clk)) { | ||
| 314 | pr_err("%s: failed to register clock %s: %ld\n", | ||
| 315 | __func__, name, PTR_ERR(clk)); | ||
| 316 | return; | ||
| 317 | } | ||
| 318 | |||
| 319 | rockchip_clk_add_lookup(clk, lookup_id); | ||
| 320 | } | ||
| 321 | |||
| 322 | void __init rockchip_clk_protect_critical(const char *clocks[], int nclocks) | ||
| 323 | { | ||
| 324 | int i; | ||
| 325 | |||
| 326 | /* Protect the clocks that needs to stay on */ | ||
| 327 | for (i = 0; i < nclocks; i++) { | ||
| 328 | struct clk *clk = __clk_lookup(clocks[i]); | ||
| 329 | |||
| 330 | if (clk) | ||
| 331 | clk_prepare_enable(clk); | ||
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 335 | static unsigned int reg_restart; | ||
| 336 | static int rockchip_restart_notify(struct notifier_block *this, | ||
| 337 | unsigned long mode, void *cmd) | ||
| 338 | { | ||
| 339 | writel(0xfdb9, reg_base + reg_restart); | ||
| 340 | return NOTIFY_DONE; | ||
| 341 | } | ||
| 342 | |||
| 343 | static struct notifier_block rockchip_restart_handler = { | ||
| 344 | .notifier_call = rockchip_restart_notify, | ||
| 345 | .priority = 128, | ||
| 346 | }; | ||
| 347 | |||
| 348 | void __init rockchip_register_restart_notifier(unsigned int reg) | ||
| 349 | { | ||
| 350 | int ret; | ||
| 351 | |||
| 352 | reg_restart = reg; | ||
| 353 | ret = register_restart_handler(&rockchip_restart_handler); | ||
| 354 | if (ret) | ||
| 355 | pr_err("%s: cannot register restart handler, %d\n", | ||
| 356 | __func__, ret); | ||
| 357 | } | ||
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 887cbdeca2aa..ca009ab0a33a 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h | |||
| @@ -120,6 +120,38 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, | |||
| 120 | struct rockchip_pll_rate_table *rate_table, | 120 | struct rockchip_pll_rate_table *rate_table, |
| 121 | spinlock_t *lock); | 121 | spinlock_t *lock); |
| 122 | 122 | ||
| 123 | struct rockchip_cpuclk_clksel { | ||
| 124 | int reg; | ||
| 125 | u32 val; | ||
| 126 | }; | ||
| 127 | |||
| 128 | #define ROCKCHIP_CPUCLK_NUM_DIVIDERS 2 | ||
| 129 | struct rockchip_cpuclk_rate_table { | ||
| 130 | unsigned long prate; | ||
| 131 | struct rockchip_cpuclk_clksel divs[ROCKCHIP_CPUCLK_NUM_DIVIDERS]; | ||
| 132 | }; | ||
| 133 | |||
| 134 | /** | ||
| 135 | * struct rockchip_cpuclk_reg_data: describes register offsets and masks of the cpuclock | ||
| 136 | * @core_reg: register offset of the core settings register | ||
| 137 | * @div_core_shift: core divider offset used to divide the pll value | ||
| 138 | * @div_core_mask: core divider mask | ||
| 139 | * @mux_core_shift: offset of the core multiplexer | ||
| 140 | */ | ||
| 141 | struct rockchip_cpuclk_reg_data { | ||
| 142 | int core_reg; | ||
| 143 | u8 div_core_shift; | ||
| 144 | u32 div_core_mask; | ||
| 145 | int mux_core_reg; | ||
| 146 | u8 mux_core_shift; | ||
| 147 | }; | ||
| 148 | |||
| 149 | struct clk *rockchip_clk_register_cpuclk(const char *name, | ||
| 150 | const char **parent_names, u8 num_parents, | ||
| 151 | const struct rockchip_cpuclk_reg_data *reg_data, | ||
| 152 | const struct rockchip_cpuclk_rate_table *rates, | ||
| 153 | int nrates, void __iomem *reg_base, spinlock_t *lock); | ||
| 154 | |||
| 123 | #define PNAME(x) static const char *x[] __initconst | 155 | #define PNAME(x) static const char *x[] __initconst |
| 124 | 156 | ||
| 125 | enum rockchip_clk_branch_type { | 157 | enum rockchip_clk_branch_type { |
| @@ -329,6 +361,13 @@ void rockchip_clk_register_branches(struct rockchip_clk_branch *clk_list, | |||
| 329 | unsigned int nr_clk); | 361 | unsigned int nr_clk); |
| 330 | void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list, | 362 | void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list, |
| 331 | unsigned int nr_pll, int grf_lock_offset); | 363 | unsigned int nr_pll, int grf_lock_offset); |
| 364 | void rockchip_clk_register_armclk(unsigned int lookup_id, const char *name, | ||
| 365 | const char **parent_names, u8 num_parents, | ||
| 366 | const struct rockchip_cpuclk_reg_data *reg_data, | ||
| 367 | const struct rockchip_cpuclk_rate_table *rates, | ||
| 368 | int nrates); | ||
| 369 | void rockchip_clk_protect_critical(const char *clocks[], int nclocks); | ||
| 370 | void rockchip_register_restart_notifier(unsigned int reg); | ||
| 332 | 371 | ||
| 333 | #define ROCKCHIP_SOFTRST_HIWORD_MASK BIT(0) | 372 | #define ROCKCHIP_SOFTRST_HIWORD_MASK BIT(0) |
| 334 | 373 | ||
diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c index dc85f8e7a2d7..6e6cca392082 100644 --- a/drivers/clk/samsung/clk-exynos3250.c +++ b/drivers/clk/samsung/clk-exynos3250.c | |||
| @@ -110,7 +110,14 @@ enum exynos3250_plls { | |||
| 110 | nr_plls | 110 | nr_plls |
| 111 | }; | 111 | }; |
| 112 | 112 | ||
| 113 | /* list of PLLs in DMC block to be registered */ | ||
| 114 | enum exynos3250_dmc_plls { | ||
| 115 | bpll, epll, | ||
| 116 | nr_dmc_plls | ||
| 117 | }; | ||
| 118 | |||
| 113 | static void __iomem *reg_base; | 119 | static void __iomem *reg_base; |
| 120 | static void __iomem *dmc_reg_base; | ||
| 114 | 121 | ||
| 115 | /* | 122 | /* |
| 116 | * Support for CMU save/restore across system suspends | 123 | * Support for CMU save/restore across system suspends |
| @@ -266,6 +273,7 @@ PNAME(group_sclk_cam_blk_p) = { "xxti", "xusbxti", | |||
| 266 | "none", "none", "none", | 273 | "none", "none", "none", |
| 267 | "none", "div_mpll_pre", | 274 | "none", "div_mpll_pre", |
| 268 | "mout_epll_user", "mout_vpll", | 275 | "mout_epll_user", "mout_vpll", |
| 276 | "none", "none", "none", | ||
| 269 | "div_cam_blk_320", }; | 277 | "div_cam_blk_320", }; |
| 270 | PNAME(group_sclk_fimd0_p) = { "xxti", "xusbxti", | 278 | PNAME(group_sclk_fimd0_p) = { "xxti", "xusbxti", |
| 271 | "m_bitclkhsdiv4_2l", "none", | 279 | "m_bitclkhsdiv4_2l", "none", |
| @@ -353,8 +361,8 @@ static struct samsung_mux_clock mux_clks[] __initdata = { | |||
| 353 | 361 | ||
| 354 | /* SRC_FSYS */ | 362 | /* SRC_FSYS */ |
| 355 | MUX(CLK_MOUT_TSADC, "mout_tsadc", group_sclk_p, SRC_FSYS, 28, 4), | 363 | MUX(CLK_MOUT_TSADC, "mout_tsadc", group_sclk_p, SRC_FSYS, 28, 4), |
| 356 | MUX(CLK_MOUT_MMC1, "mout_mmc1", group_sclk_p, SRC_FSYS, 4, 3), | 364 | MUX(CLK_MOUT_MMC1, "mout_mmc1", group_sclk_p, SRC_FSYS, 4, 4), |
| 357 | MUX(CLK_MOUT_MMC0, "mout_mmc0", group_sclk_p, SRC_FSYS, 0, 3), | 365 | MUX(CLK_MOUT_MMC0, "mout_mmc0", group_sclk_p, SRC_FSYS, 0, 4), |
| 358 | 366 | ||
| 359 | /* SRC_PERIL0 */ | 367 | /* SRC_PERIL0 */ |
| 360 | MUX(CLK_MOUT_UART1, "mout_uart1", group_sclk_p, SRC_PERIL0, 4, 4), | 368 | MUX(CLK_MOUT_UART1, "mout_uart1", group_sclk_p, SRC_PERIL0, 4, 4), |
| @@ -423,7 +431,7 @@ static struct samsung_div_clock div_clks[] __initdata = { | |||
| 423 | DIV(CLK_DIV_SPI1_ISP, "div_spi1_isp", "mout_spi1_isp", DIV_ISP, 16, 4), | 431 | DIV(CLK_DIV_SPI1_ISP, "div_spi1_isp", "mout_spi1_isp", DIV_ISP, 16, 4), |
| 424 | DIV_F(CLK_DIV_SPI0_ISP_PRE, "div_spi0_isp_pre", "div_spi0_isp", | 432 | DIV_F(CLK_DIV_SPI0_ISP_PRE, "div_spi0_isp_pre", "div_spi0_isp", |
| 425 | DIV_ISP, 8, 8, CLK_SET_RATE_PARENT, 0), | 433 | DIV_ISP, 8, 8, CLK_SET_RATE_PARENT, 0), |
| 426 | DIV(CLK_DIV_SPI0_ISP, "div_spi0_isp", "mout_spi0_isp", DIV_ISP, 0, 4), | 434 | DIV(CLK_DIV_SPI0_ISP, "div_spi0_isp", "mout_spi0_isp", DIV_ISP, 4, 4), |
| 427 | 435 | ||
| 428 | /* DIV_FSYS0 */ | 436 | /* DIV_FSYS0 */ |
| 429 | DIV_F(CLK_DIV_TSADC_PRE, "div_tsadc_pre", "div_tsadc", DIV_FSYS0, 8, 8, | 437 | DIV_F(CLK_DIV_TSADC_PRE, "div_tsadc_pre", "div_tsadc", DIV_FSYS0, 8, 8, |
| @@ -724,6 +732,25 @@ static struct samsung_pll_rate_table exynos3250_pll_rates[] = { | |||
| 724 | { /* sentinel */ } | 732 | { /* sentinel */ } |
| 725 | }; | 733 | }; |
| 726 | 734 | ||
| 735 | /* EPLL */ | ||
| 736 | static struct samsung_pll_rate_table exynos3250_epll_rates[] = { | ||
| 737 | PLL_36XX_RATE(800000000, 200, 3, 1, 0), | ||
| 738 | PLL_36XX_RATE(288000000, 96, 2, 2, 0), | ||
| 739 | PLL_36XX_RATE(192000000, 128, 2, 3, 0), | ||
| 740 | PLL_36XX_RATE(144000000, 96, 2, 3, 0), | ||
| 741 | PLL_36XX_RATE( 96000000, 128, 2, 4, 0), | ||
| 742 | PLL_36XX_RATE( 84000000, 112, 2, 4, 0), | ||
| 743 | PLL_36XX_RATE( 80000004, 106, 2, 4, 43691), | ||
| 744 | PLL_36XX_RATE( 73728000, 98, 2, 4, 19923), | ||
| 745 | PLL_36XX_RATE( 67737598, 270, 3, 5, 62285), | ||
| 746 | PLL_36XX_RATE( 65535999, 174, 2, 5, 49982), | ||
| 747 | PLL_36XX_RATE( 50000000, 200, 3, 5, 0), | ||
| 748 | PLL_36XX_RATE( 49152002, 131, 2, 5, 4719), | ||
| 749 | PLL_36XX_RATE( 48000000, 128, 2, 5, 0), | ||
| 750 | PLL_36XX_RATE( 45158401, 180, 3, 5, 41524), | ||
| 751 | { /* sentinel */ } | ||
| 752 | }; | ||
| 753 | |||
| 727 | /* VPLL */ | 754 | /* VPLL */ |
| 728 | static struct samsung_pll_rate_table exynos3250_vpll_rates[] = { | 755 | static struct samsung_pll_rate_table exynos3250_vpll_rates[] = { |
| 729 | PLL_36XX_RATE(600000000, 100, 2, 1, 0), | 756 | PLL_36XX_RATE(600000000, 100, 2, 1, 0), |
| @@ -821,3 +848,172 @@ static void __init exynos3250_cmu_init(struct device_node *np) | |||
| 821 | samsung_clk_of_add_provider(np, ctx); | 848 | samsung_clk_of_add_provider(np, ctx); |
| 822 | } | 849 | } |
| 823 | CLK_OF_DECLARE(exynos3250_cmu, "samsung,exynos3250-cmu", exynos3250_cmu_init); | 850 | CLK_OF_DECLARE(exynos3250_cmu, "samsung,exynos3250-cmu", exynos3250_cmu_init); |
| 851 | |||
| 852 | /* | ||
| 853 | * CMU DMC | ||
| 854 | */ | ||
| 855 | |||
| 856 | #define BPLL_LOCK 0x0118 | ||
| 857 | #define BPLL_CON0 0x0218 | ||
| 858 | #define BPLL_CON1 0x021c | ||
| 859 | #define BPLL_CON2 0x0220 | ||
| 860 | #define SRC_DMC 0x0300 | ||
| 861 | #define DIV_DMC1 0x0504 | ||
| 862 | #define GATE_BUS_DMC0 0x0700 | ||
| 863 | #define GATE_BUS_DMC1 0x0704 | ||
| 864 | #define GATE_BUS_DMC2 0x0708 | ||
| 865 | #define GATE_BUS_DMC3 0x070c | ||
| 866 | #define GATE_SCLK_DMC 0x0800 | ||
| 867 | #define GATE_IP_DMC0 0x0900 | ||
| 868 | #define GATE_IP_DMC1 0x0904 | ||
| 869 | #define EPLL_LOCK 0x1110 | ||
| 870 | #define EPLL_CON0 0x1114 | ||
| 871 | #define EPLL_CON1 0x1118 | ||
| 872 | #define EPLL_CON2 0x111c | ||
| 873 | #define SRC_EPLL 0x1120 | ||
| 874 | |||
| 875 | /* | ||
| 876 | * Support for CMU save/restore across system suspends | ||
| 877 | */ | ||
| 878 | #ifdef CONFIG_PM_SLEEP | ||
| 879 | static struct samsung_clk_reg_dump *exynos3250_dmc_clk_regs; | ||
| 880 | |||
| 881 | static unsigned long exynos3250_cmu_dmc_clk_regs[] __initdata = { | ||
| 882 | BPLL_LOCK, | ||
| 883 | BPLL_CON0, | ||
| 884 | BPLL_CON1, | ||
| 885 | BPLL_CON2, | ||
| 886 | SRC_DMC, | ||
| 887 | DIV_DMC1, | ||
| 888 | GATE_BUS_DMC0, | ||
| 889 | GATE_BUS_DMC1, | ||
| 890 | GATE_BUS_DMC2, | ||
| 891 | GATE_BUS_DMC3, | ||
| 892 | GATE_SCLK_DMC, | ||
| 893 | GATE_IP_DMC0, | ||
| 894 | GATE_IP_DMC1, | ||
| 895 | EPLL_LOCK, | ||
| 896 | EPLL_CON0, | ||
| 897 | EPLL_CON1, | ||
| 898 | EPLL_CON2, | ||
| 899 | SRC_EPLL, | ||
| 900 | }; | ||
| 901 | |||
| 902 | static int exynos3250_dmc_clk_suspend(void) | ||
| 903 | { | ||
| 904 | samsung_clk_save(dmc_reg_base, exynos3250_dmc_clk_regs, | ||
| 905 | ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs)); | ||
| 906 | return 0; | ||
| 907 | } | ||
| 908 | |||
| 909 | static void exynos3250_dmc_clk_resume(void) | ||
| 910 | { | ||
| 911 | samsung_clk_restore(dmc_reg_base, exynos3250_dmc_clk_regs, | ||
| 912 | ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs)); | ||
| 913 | } | ||
| 914 | |||
| 915 | static struct syscore_ops exynos3250_dmc_clk_syscore_ops = { | ||
| 916 | .suspend = exynos3250_dmc_clk_suspend, | ||
| 917 | .resume = exynos3250_dmc_clk_resume, | ||
| 918 | }; | ||
| 919 | |||
| 920 | static void exynos3250_dmc_clk_sleep_init(void) | ||
| 921 | { | ||
| 922 | exynos3250_dmc_clk_regs = | ||
| 923 | samsung_clk_alloc_reg_dump(exynos3250_cmu_dmc_clk_regs, | ||
| 924 | ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs)); | ||
| 925 | if (!exynos3250_dmc_clk_regs) { | ||
| 926 | pr_warn("%s: Failed to allocate sleep save data\n", __func__); | ||
| 927 | goto err; | ||
| 928 | } | ||
| 929 | |||
| 930 | register_syscore_ops(&exynos3250_dmc_clk_syscore_ops); | ||
| 931 | return; | ||
| 932 | err: | ||
| 933 | kfree(exynos3250_dmc_clk_regs); | ||
| 934 | } | ||
| 935 | #else | ||
| 936 | static inline void exynos3250_dmc_clk_sleep_init(void) { } | ||
| 937 | #endif | ||
| 938 | |||
| 939 | PNAME(mout_epll_p) = { "fin_pll", "fout_epll", }; | ||
| 940 | PNAME(mout_bpll_p) = { "fin_pll", "fout_bpll", }; | ||
| 941 | PNAME(mout_mpll_mif_p) = { "fin_pll", "sclk_mpll_mif", }; | ||
| 942 | PNAME(mout_dphy_p) = { "mout_mpll_mif", "mout_bpll", }; | ||
| 943 | |||
| 944 | static struct samsung_mux_clock dmc_mux_clks[] __initdata = { | ||
| 945 | /* | ||
| 946 | * NOTE: Following table is sorted by register address in ascending | ||
| 947 | * order and then bitfield shift in descending order, as it is done | ||
| 948 | * in the User's Manual. When adding new entries, please make sure | ||
| 949 | * that the order is preserved, to avoid merge conflicts and make | ||
| 950 | * further work with defined data easier. | ||
| 951 | */ | ||
| 952 | |||
| 953 | /* SRC_DMC */ | ||
| 954 | MUX(CLK_MOUT_MPLL_MIF, "mout_mpll_mif", mout_mpll_mif_p, SRC_DMC, 12, 1), | ||
| 955 | MUX(CLK_MOUT_BPLL, "mout_bpll", mout_bpll_p, SRC_DMC, 10, 1), | ||
| 956 | MUX(CLK_MOUT_DPHY, "mout_dphy", mout_dphy_p, SRC_DMC, 8, 1), | ||
| 957 | MUX(CLK_MOUT_DMC_BUS, "mout_dmc_bus", mout_dphy_p, SRC_DMC, 4, 1), | ||
| 958 | |||
| 959 | /* SRC_EPLL */ | ||
| 960 | MUX(CLK_MOUT_EPLL, "mout_epll", mout_epll_p, SRC_EPLL, 4, 1), | ||
| 961 | }; | ||
| 962 | |||
| 963 | static struct samsung_div_clock dmc_div_clks[] __initdata = { | ||
| 964 | /* | ||
| 965 | * NOTE: Following table is sorted by register address in ascending | ||
| 966 | * order and then bitfield shift in descending order, as it is done | ||
| 967 | * in the User's Manual. When adding new entries, please make sure | ||
| 968 | * that the order is preserved, to avoid merge conflicts and make | ||
| 969 | * further work with defined data easier. | ||
| 970 | */ | ||
| 971 | |||
| 972 | /* DIV_DMC1 */ | ||
| 973 | DIV(CLK_DIV_DMC, "div_dmc", "div_dmc_pre", DIV_DMC1, 27, 3), | ||
| 974 | DIV(CLK_DIV_DPHY, "div_dphy", "mout_dphy", DIV_DMC1, 23, 3), | ||
| 975 | DIV(CLK_DIV_DMC_PRE, "div_dmc_pre", "mout_dmc_bus", DIV_DMC1, 19, 2), | ||
| 976 | DIV(CLK_DIV_DMCP, "div_dmcp", "div_dmcd", DIV_DMC1, 15, 3), | ||
| 977 | DIV(CLK_DIV_DMCD, "div_dmcd", "div_dmc", DIV_DMC1, 11, 3), | ||
| 978 | }; | ||
| 979 | |||
| 980 | static struct samsung_pll_clock exynos3250_dmc_plls[nr_dmc_plls] __initdata = { | ||
| 981 | [bpll] = PLL(pll_35xx, CLK_FOUT_BPLL, "fout_bpll", "fin_pll", | ||
| 982 | BPLL_LOCK, BPLL_CON0, NULL), | ||
| 983 | [epll] = PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll", | ||
| 984 | EPLL_LOCK, EPLL_CON0, NULL), | ||
| 985 | }; | ||
| 986 | |||
| 987 | static void __init exynos3250_cmu_dmc_init(struct device_node *np) | ||
| 988 | { | ||
| 989 | struct samsung_clk_provider *ctx; | ||
| 990 | |||
| 991 | dmc_reg_base = of_iomap(np, 0); | ||
| 992 | if (!dmc_reg_base) | ||
| 993 | panic("%s: failed to map registers\n", __func__); | ||
| 994 | |||
| 995 | ctx = samsung_clk_init(np, dmc_reg_base, NR_CLKS_DMC); | ||
| 996 | if (!ctx) | ||
| 997 | panic("%s: unable to allocate context.\n", __func__); | ||
| 998 | |||
| 999 | exynos3250_dmc_plls[bpll].rate_table = exynos3250_pll_rates; | ||
| 1000 | exynos3250_dmc_plls[epll].rate_table = exynos3250_epll_rates; | ||
| 1001 | |||
| 1002 | pr_err("CLK registering epll bpll: %d, %d, %d, %d\n", | ||
| 1003 | exynos3250_dmc_plls[bpll].rate_table[0].rate, | ||
| 1004 | exynos3250_dmc_plls[bpll].rate_table[0].mdiv, | ||
| 1005 | exynos3250_dmc_plls[bpll].rate_table[0].pdiv, | ||
| 1006 | exynos3250_dmc_plls[bpll].rate_table[0].sdiv | ||
| 1007 | ); | ||
| 1008 | samsung_clk_register_pll(ctx, exynos3250_dmc_plls, | ||
| 1009 | ARRAY_SIZE(exynos3250_dmc_plls), dmc_reg_base); | ||
| 1010 | |||
| 1011 | samsung_clk_register_mux(ctx, dmc_mux_clks, ARRAY_SIZE(dmc_mux_clks)); | ||
| 1012 | samsung_clk_register_div(ctx, dmc_div_clks, ARRAY_SIZE(dmc_div_clks)); | ||
| 1013 | |||
| 1014 | exynos3250_dmc_clk_sleep_init(); | ||
| 1015 | |||
| 1016 | samsung_clk_of_add_provider(np, ctx); | ||
| 1017 | } | ||
| 1018 | CLK_OF_DECLARE(exynos3250_cmu_dmc, "samsung,exynos3250-cmu-dmc", | ||
| 1019 | exynos3250_cmu_dmc_init); | ||
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index ac163d7f5bc3..940f02837b82 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c | |||
| @@ -517,7 +517,7 @@ static struct samsung_fixed_factor_clock exynos4_fixed_factor_clks[] __initdata | |||
| 517 | FFACTOR(0, "sclk_apll_div_2", "sclk_apll", 1, 2, 0), | 517 | FFACTOR(0, "sclk_apll_div_2", "sclk_apll", 1, 2, 0), |
| 518 | FFACTOR(0, "fout_mpll_div_2", "fout_mpll", 1, 2, 0), | 518 | FFACTOR(0, "fout_mpll_div_2", "fout_mpll", 1, 2, 0), |
| 519 | FFACTOR(0, "fout_apll_div_2", "fout_apll", 1, 2, 0), | 519 | FFACTOR(0, "fout_apll_div_2", "fout_apll", 1, 2, 0), |
| 520 | FFACTOR(0, "arm_clk_div_2", "arm_clk", 1, 2, 0), | 520 | FFACTOR(0, "arm_clk_div_2", "div_core2", 1, 2, 0), |
| 521 | }; | 521 | }; |
| 522 | 522 | ||
| 523 | static struct samsung_fixed_factor_clock exynos4210_fixed_factor_clks[] __initdata = { | 523 | static struct samsung_fixed_factor_clock exynos4210_fixed_factor_clks[] __initdata = { |
| @@ -535,7 +535,7 @@ static struct samsung_fixed_factor_clock exynos4x12_fixed_factor_clks[] __initda | |||
| 535 | static struct samsung_mux_clock exynos4_mux_clks[] __initdata = { | 535 | static struct samsung_mux_clock exynos4_mux_clks[] __initdata = { |
| 536 | MUX_FA(CLK_MOUT_APLL, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, | 536 | MUX_FA(CLK_MOUT_APLL, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, |
| 537 | CLK_SET_RATE_PARENT, 0, "mout_apll"), | 537 | CLK_SET_RATE_PARENT, 0, "mout_apll"), |
| 538 | MUX(0, "mout_hdmi", mout_hdmi_p, SRC_TV, 0, 1), | 538 | MUX(CLK_MOUT_HDMI, "mout_hdmi", mout_hdmi_p, SRC_TV, 0, 1), |
| 539 | MUX(0, "mout_mfc1", sclk_evpll_p, SRC_MFC, 4, 1), | 539 | MUX(0, "mout_mfc1", sclk_evpll_p, SRC_MFC, 4, 1), |
| 540 | MUX(0, "mout_mfc", mout_mfc_p, SRC_MFC, 8, 1), | 540 | MUX(0, "mout_mfc", mout_mfc_p, SRC_MFC, 8, 1), |
| 541 | MUX_F(CLK_MOUT_G3D1, "mout_g3d1", sclk_evpll_p, SRC_G3D, 4, 1, | 541 | MUX_F(CLK_MOUT_G3D1, "mout_g3d1", sclk_evpll_p, SRC_G3D, 4, 1, |
| @@ -569,7 +569,7 @@ static struct samsung_mux_clock exynos4210_mux_clks[] __initdata = { | |||
| 569 | MUX(0, "mout_aclk100", sclk_ampll_p4210, SRC_TOP0, 16, 1), | 569 | MUX(0, "mout_aclk100", sclk_ampll_p4210, SRC_TOP0, 16, 1), |
| 570 | MUX(0, "mout_aclk160", sclk_ampll_p4210, SRC_TOP0, 20, 1), | 570 | MUX(0, "mout_aclk160", sclk_ampll_p4210, SRC_TOP0, 20, 1), |
| 571 | MUX(0, "mout_aclk133", sclk_ampll_p4210, SRC_TOP0, 24, 1), | 571 | MUX(0, "mout_aclk133", sclk_ampll_p4210, SRC_TOP0, 24, 1), |
| 572 | MUX(0, "mout_mixer", mout_mixer_p4210, SRC_TV, 4, 1), | 572 | MUX(CLK_MOUT_MIXER, "mout_mixer", mout_mixer_p4210, SRC_TV, 4, 1), |
| 573 | MUX(0, "mout_dac", mout_dac_p4210, SRC_TV, 8, 1), | 573 | MUX(0, "mout_dac", mout_dac_p4210, SRC_TV, 8, 1), |
| 574 | MUX(0, "mout_g2d0", sclk_ampll_p4210, E4210_SRC_IMAGE, 0, 1), | 574 | MUX(0, "mout_g2d0", sclk_ampll_p4210, E4210_SRC_IMAGE, 0, 1), |
| 575 | MUX(0, "mout_g2d1", sclk_evpll_p, E4210_SRC_IMAGE, 4, 1), | 575 | MUX(0, "mout_g2d1", sclk_evpll_p, E4210_SRC_IMAGE, 4, 1), |
| @@ -719,7 +719,7 @@ static struct samsung_div_clock exynos4_div_clks[] __initdata = { | |||
| 719 | DIV(0, "div_periph", "div_core2", DIV_CPU0, 12, 3), | 719 | DIV(0, "div_periph", "div_core2", DIV_CPU0, 12, 3), |
| 720 | DIV(0, "div_atb", "mout_core", DIV_CPU0, 16, 3), | 720 | DIV(0, "div_atb", "mout_core", DIV_CPU0, 16, 3), |
| 721 | DIV(0, "div_pclk_dbg", "div_atb", DIV_CPU0, 20, 3), | 721 | DIV(0, "div_pclk_dbg", "div_atb", DIV_CPU0, 20, 3), |
| 722 | DIV(0, "div_core2", "div_core", DIV_CPU0, 28, 3), | 722 | DIV(CLK_ARM_CLK, "div_core2", "div_core", DIV_CPU0, 28, 3), |
| 723 | DIV(0, "div_copy", "mout_hpm", DIV_CPU1, 0, 3), | 723 | DIV(0, "div_copy", "mout_hpm", DIV_CPU1, 0, 3), |
| 724 | DIV(0, "div_hpm", "div_copy", DIV_CPU1, 4, 3), | 724 | DIV(0, "div_hpm", "div_copy", DIV_CPU1, 4, 3), |
| 725 | DIV(0, "div_clkout_cpu", "mout_clkout_cpu", CLKOUT_CMU_CPU, 8, 6), | 725 | DIV(0, "div_clkout_cpu", "mout_clkout_cpu", CLKOUT_CMU_CPU, 8, 6), |
| @@ -733,8 +733,7 @@ static struct samsung_div_clock exynos4_div_clks[] __initdata = { | |||
| 733 | DIV(0, "div_csis0", "mout_csis0", DIV_CAM, 24, 4), | 733 | DIV(0, "div_csis0", "mout_csis0", DIV_CAM, 24, 4), |
| 734 | DIV(0, "div_csis1", "mout_csis1", DIV_CAM, 28, 4), | 734 | DIV(0, "div_csis1", "mout_csis1", DIV_CAM, 28, 4), |
| 735 | DIV(CLK_SCLK_MFC, "sclk_mfc", "mout_mfc", DIV_MFC, 0, 4), | 735 | DIV(CLK_SCLK_MFC, "sclk_mfc", "mout_mfc", DIV_MFC, 0, 4), |
| 736 | DIV_F(0, "div_g3d", "mout_g3d", DIV_G3D, 0, 4, | 736 | DIV(CLK_SCLK_G3D, "sclk_g3d", "mout_g3d", DIV_G3D, 0, 4), |
| 737 | CLK_SET_RATE_PARENT, 0), | ||
| 738 | DIV(0, "div_fimd0", "mout_fimd0", DIV_LCD0, 0, 4), | 737 | DIV(0, "div_fimd0", "mout_fimd0", DIV_LCD0, 0, 4), |
| 739 | DIV(0, "div_mipi0", "mout_mipi0", DIV_LCD0, 16, 4), | 738 | DIV(0, "div_mipi0", "mout_mipi0", DIV_LCD0, 16, 4), |
| 740 | DIV(0, "div_audio0", "mout_audio0", DIV_MAUDIO, 0, 4), | 739 | DIV(0, "div_audio0", "mout_audio0", DIV_MAUDIO, 0, 4), |
| @@ -769,7 +768,6 @@ static struct samsung_div_clock exynos4_div_clks[] __initdata = { | |||
| 769 | DIV(0, "div_spi_pre2", "div_spi2", DIV_PERIL2, 8, 8), | 768 | DIV(0, "div_spi_pre2", "div_spi2", DIV_PERIL2, 8, 8), |
| 770 | DIV(0, "div_audio1", "mout_audio1", DIV_PERIL4, 0, 4), | 769 | DIV(0, "div_audio1", "mout_audio1", DIV_PERIL4, 0, 4), |
| 771 | DIV(0, "div_audio2", "mout_audio2", DIV_PERIL4, 16, 4), | 770 | DIV(0, "div_audio2", "mout_audio2", DIV_PERIL4, 16, 4), |
| 772 | DIV(CLK_ARM_CLK, "arm_clk", "div_core2", DIV_CPU0, 28, 3), | ||
| 773 | DIV(CLK_SCLK_APLL, "sclk_apll", "mout_apll", DIV_CPU0, 24, 3), | 771 | DIV(CLK_SCLK_APLL, "sclk_apll", "mout_apll", DIV_CPU0, 24, 3), |
| 774 | DIV_F(0, "div_mipi_pre0", "div_mipi0", DIV_LCD0, 20, 4, | 772 | DIV_F(0, "div_mipi_pre0", "div_mipi0", DIV_LCD0, 20, 4, |
| 775 | CLK_SET_RATE_PARENT, 0), | 773 | CLK_SET_RATE_PARENT, 0), |
| @@ -857,8 +855,7 @@ static struct samsung_gate_clock exynos4_gate_clks[] __initdata = { | |||
| 857 | 0), | 855 | 0), |
| 858 | GATE(CLK_TSI, "tsi", "aclk133", GATE_IP_FSYS, 4, 0, 0), | 856 | GATE(CLK_TSI, "tsi", "aclk133", GATE_IP_FSYS, 4, 0, 0), |
| 859 | GATE(CLK_SROMC, "sromc", "aclk133", GATE_IP_FSYS, 11, 0, 0), | 857 | GATE(CLK_SROMC, "sromc", "aclk133", GATE_IP_FSYS, 11, 0, 0), |
| 860 | GATE(CLK_SCLK_G3D, "sclk_g3d", "div_g3d", GATE_IP_G3D, 0, | 858 | GATE(CLK_G3D, "g3d", "aclk200", GATE_IP_G3D, 0, 0, 0), |
| 861 | CLK_SET_RATE_PARENT, 0), | ||
| 862 | GATE(CLK_PPMUG3D, "ppmug3d", "aclk200", GATE_IP_G3D, 1, 0, 0), | 859 | GATE(CLK_PPMUG3D, "ppmug3d", "aclk200", GATE_IP_G3D, 1, 0, 0), |
| 863 | GATE(CLK_USB_DEVICE, "usb_device", "aclk133", GATE_IP_FSYS, 13, 0, 0), | 860 | GATE(CLK_USB_DEVICE, "usb_device", "aclk133", GATE_IP_FSYS, 13, 0, 0), |
| 864 | GATE(CLK_ONENAND, "onenand", "aclk133", GATE_IP_FSYS, 15, 0, 0), | 861 | GATE(CLK_ONENAND, "onenand", "aclk133", GATE_IP_FSYS, 15, 0, 0), |
| @@ -1183,6 +1180,7 @@ static struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = { | |||
| 1183 | GATE(CLK_SPI1_ISP, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13, | 1180 | GATE(CLK_SPI1_ISP, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13, |
| 1184 | CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), | 1181 | CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), |
| 1185 | GATE(CLK_G2D, "g2d", "aclk200", GATE_IP_DMC, 23, 0, 0), | 1182 | GATE(CLK_G2D, "g2d", "aclk200", GATE_IP_DMC, 23, 0, 0), |
| 1183 | GATE(CLK_SMMU_G2D, "smmu_g2d", "aclk200", GATE_IP_DMC, 24, 0, 0), | ||
| 1186 | GATE(CLK_TMU_APBIF, "tmu_apbif", "aclk100", E4X12_GATE_IP_PERIR, 17, 0, | 1184 | GATE(CLK_TMU_APBIF, "tmu_apbif", "aclk100", E4X12_GATE_IP_PERIR, 17, 0, |
| 1187 | 0), | 1185 | 0), |
| 1188 | }; | 1186 | }; |
| @@ -1486,7 +1484,7 @@ static void __init exynos4_clk_init(struct device_node *np, | |||
| 1486 | exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12", | 1484 | exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12", |
| 1487 | _get_rate("sclk_apll"), _get_rate("sclk_mpll"), | 1485 | _get_rate("sclk_apll"), _get_rate("sclk_mpll"), |
| 1488 | _get_rate("sclk_epll"), _get_rate("sclk_vpll"), | 1486 | _get_rate("sclk_epll"), _get_rate("sclk_vpll"), |
| 1489 | _get_rate("arm_clk")); | 1487 | _get_rate("div_core2")); |
| 1490 | } | 1488 | } |
| 1491 | 1489 | ||
| 1492 | 1490 | ||
diff --git a/drivers/clk/samsung/clk-exynos5260.c b/drivers/clk/samsung/clk-exynos5260.c index ce3de97e5f11..2527e39aadcf 100644 --- a/drivers/clk/samsung/clk-exynos5260.c +++ b/drivers/clk/samsung/clk-exynos5260.c | |||
| @@ -1581,7 +1581,7 @@ struct samsung_fixed_rate_clock fixed_rate_clks[] __initdata = { | |||
| 1581 | FRATE(PHYCLK_HDMI_LINK_O_TMDS_CLKHI, "phyclk_hdmi_link_o_tmds_clkhi", | 1581 | FRATE(PHYCLK_HDMI_LINK_O_TMDS_CLKHI, "phyclk_hdmi_link_o_tmds_clkhi", |
| 1582 | NULL, CLK_IS_ROOT, 125000000), | 1582 | NULL, CLK_IS_ROOT, 125000000), |
| 1583 | FRATE(PHYCLK_MIPI_DPHY_4L_M_TXBYTECLKHS, | 1583 | FRATE(PHYCLK_MIPI_DPHY_4L_M_TXBYTECLKHS, |
| 1584 | "phyclk_mipi_dphy_4l_m_txbyteclkhs" , NULL, | 1584 | "phyclk_mipi_dphy_4l_m_txbyte_clkhs" , NULL, |
| 1585 | CLK_IS_ROOT, 187500000), | 1585 | CLK_IS_ROOT, 187500000), |
| 1586 | FRATE(PHYCLK_DPTX_PHY_O_REF_CLK_24M, "phyclk_dptx_phy_o_ref_clk_24m", | 1586 | FRATE(PHYCLK_DPTX_PHY_O_REF_CLK_24M, "phyclk_dptx_phy_o_ref_clk_24m", |
| 1587 | NULL, CLK_IS_ROOT, 24000000), | 1587 | NULL, CLK_IS_ROOT, 24000000), |
diff --git a/drivers/clk/samsung/clk-s3c2410-dclk.c b/drivers/clk/samsung/clk-s3c2410-dclk.c index 0449cc0458ed..f4f29ed6bd25 100644 --- a/drivers/clk/samsung/clk-s3c2410-dclk.c +++ b/drivers/clk/samsung/clk-s3c2410-dclk.c | |||
| @@ -426,7 +426,6 @@ MODULE_DEVICE_TABLE(platform, s3c24xx_dclk_driver_ids); | |||
| 426 | static struct platform_driver s3c24xx_dclk_driver = { | 426 | static struct platform_driver s3c24xx_dclk_driver = { |
| 427 | .driver = { | 427 | .driver = { |
| 428 | .name = "s3c24xx-dclk", | 428 | .name = "s3c24xx-dclk", |
| 429 | .owner = THIS_MODULE, | ||
| 430 | .pm = &s3c24xx_dclk_pm_ops, | 429 | .pm = &s3c24xx_dclk_pm_ops, |
| 431 | }, | 430 | }, |
| 432 | .probe = s3c24xx_dclk_probe, | 431 | .probe = s3c24xx_dclk_probe, |
diff --git a/drivers/clk/samsung/clk-s3c2412.c b/drivers/clk/samsung/clk-s3c2412.c index 34af09f6a155..2ceedaf8ce18 100644 --- a/drivers/clk/samsung/clk-s3c2412.c +++ b/drivers/clk/samsung/clk-s3c2412.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <linux/of.h> | 14 | #include <linux/of.h> |
| 15 | #include <linux/of_address.h> | 15 | #include <linux/of_address.h> |
| 16 | #include <linux/syscore_ops.h> | 16 | #include <linux/syscore_ops.h> |
| 17 | #include <linux/reboot.h> | ||
| 17 | 18 | ||
| 18 | #include <dt-bindings/clock/s3c2412.h> | 19 | #include <dt-bindings/clock/s3c2412.h> |
| 19 | 20 | ||
| @@ -26,6 +27,7 @@ | |||
| 26 | #define CLKCON 0x0c | 27 | #define CLKCON 0x0c |
| 27 | #define CLKDIVN 0x14 | 28 | #define CLKDIVN 0x14 |
| 28 | #define CLKSRC 0x1c | 29 | #define CLKSRC 0x1c |
| 30 | #define SWRST 0x30 | ||
| 29 | 31 | ||
| 30 | /* list of PLLs to be registered */ | 32 | /* list of PLLs to be registered */ |
| 31 | enum s3c2412_plls { | 33 | enum s3c2412_plls { |
| @@ -204,6 +206,28 @@ struct samsung_clock_alias s3c2412_aliases[] __initdata = { | |||
| 204 | ALIAS(MSYSCLK, NULL, "fclk"), | 206 | ALIAS(MSYSCLK, NULL, "fclk"), |
| 205 | }; | 207 | }; |
| 206 | 208 | ||
| 209 | static int s3c2412_restart(struct notifier_block *this, | ||
| 210 | unsigned long mode, void *cmd) | ||
| 211 | { | ||
| 212 | /* errata "Watch-dog/Software Reset Problem" specifies that | ||
| 213 | * this reset must be done with the SYSCLK sourced from | ||
| 214 | * EXTCLK instead of FOUT to avoid a glitch in the reset | ||
| 215 | * mechanism. | ||
| 216 | * | ||
| 217 | * See the watchdog section of the S3C2412 manual for more | ||
| 218 | * information on this fix. | ||
| 219 | */ | ||
| 220 | |||
| 221 | __raw_writel(0x00, reg_base + CLKSRC); | ||
| 222 | __raw_writel(0x533C2412, reg_base + SWRST); | ||
| 223 | return NOTIFY_DONE; | ||
| 224 | } | ||
| 225 | |||
| 226 | static struct notifier_block s3c2412_restart_handler = { | ||
| 227 | .notifier_call = s3c2412_restart, | ||
| 228 | .priority = 129, | ||
| 229 | }; | ||
| 230 | |||
| 207 | /* | 231 | /* |
| 208 | * fixed rate clocks generated outside the soc | 232 | * fixed rate clocks generated outside the soc |
| 209 | * Only necessary until the devicetree-move is complete | 233 | * Only necessary until the devicetree-move is complete |
| @@ -233,6 +257,7 @@ void __init s3c2412_common_clk_init(struct device_node *np, unsigned long xti_f, | |||
| 233 | unsigned long ext_f, void __iomem *base) | 257 | unsigned long ext_f, void __iomem *base) |
| 234 | { | 258 | { |
| 235 | struct samsung_clk_provider *ctx; | 259 | struct samsung_clk_provider *ctx; |
| 260 | int ret; | ||
| 236 | reg_base = base; | 261 | reg_base = base; |
| 237 | 262 | ||
| 238 | if (np) { | 263 | if (np) { |
| @@ -267,6 +292,10 @@ void __init s3c2412_common_clk_init(struct device_node *np, unsigned long xti_f, | |||
| 267 | s3c2412_clk_sleep_init(); | 292 | s3c2412_clk_sleep_init(); |
| 268 | 293 | ||
| 269 | samsung_clk_of_add_provider(np, ctx); | 294 | samsung_clk_of_add_provider(np, ctx); |
| 295 | |||
| 296 | ret = register_restart_handler(&s3c2412_restart_handler); | ||
| 297 | if (ret) | ||
| 298 | pr_warn("cannot register restart handler, %d\n", ret); | ||
| 270 | } | 299 | } |
| 271 | 300 | ||
| 272 | static void __init s3c2412_clk_init(struct device_node *np) | 301 | static void __init s3c2412_clk_init(struct device_node *np) |
diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c index c92f853fca9f..0c3c182b902a 100644 --- a/drivers/clk/samsung/clk-s3c2443.c +++ b/drivers/clk/samsung/clk-s3c2443.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <linux/of.h> | 14 | #include <linux/of.h> |
| 15 | #include <linux/of_address.h> | 15 | #include <linux/of_address.h> |
| 16 | #include <linux/syscore_ops.h> | 16 | #include <linux/syscore_ops.h> |
| 17 | #include <linux/reboot.h> | ||
| 17 | 18 | ||
| 18 | #include <dt-bindings/clock/s3c2443.h> | 19 | #include <dt-bindings/clock/s3c2443.h> |
| 19 | 20 | ||
| @@ -33,6 +34,7 @@ | |||
| 33 | #define HCLKCON 0x30 | 34 | #define HCLKCON 0x30 |
| 34 | #define PCLKCON 0x34 | 35 | #define PCLKCON 0x34 |
| 35 | #define SCLKCON 0x38 | 36 | #define SCLKCON 0x38 |
| 37 | #define SWRST 0x44 | ||
| 36 | 38 | ||
| 37 | /* the soc types */ | 39 | /* the soc types */ |
| 38 | enum supported_socs { | 40 | enum supported_socs { |
| @@ -354,6 +356,18 @@ struct samsung_clock_alias s3c2450_aliases[] __initdata = { | |||
| 354 | ALIAS(PCLK_I2C1, "s3c2410-i2c.1", "i2c"), | 356 | ALIAS(PCLK_I2C1, "s3c2410-i2c.1", "i2c"), |
| 355 | }; | 357 | }; |
| 356 | 358 | ||
| 359 | static int s3c2443_restart(struct notifier_block *this, | ||
| 360 | unsigned long mode, void *cmd) | ||
| 361 | { | ||
| 362 | __raw_writel(0x533c2443, reg_base + SWRST); | ||
| 363 | return NOTIFY_DONE; | ||
| 364 | } | ||
| 365 | |||
| 366 | static struct notifier_block s3c2443_restart_handler = { | ||
| 367 | .notifier_call = s3c2443_restart, | ||
| 368 | .priority = 129, | ||
| 369 | }; | ||
| 370 | |||
| 357 | /* | 371 | /* |
| 358 | * fixed rate clocks generated outside the soc | 372 | * fixed rate clocks generated outside the soc |
| 359 | * Only necessary until the devicetree-move is complete | 373 | * Only necessary until the devicetree-move is complete |
| @@ -378,6 +392,7 @@ void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f, | |||
| 378 | void __iomem *base) | 392 | void __iomem *base) |
| 379 | { | 393 | { |
| 380 | struct samsung_clk_provider *ctx; | 394 | struct samsung_clk_provider *ctx; |
| 395 | int ret; | ||
| 381 | reg_base = base; | 396 | reg_base = base; |
| 382 | 397 | ||
| 383 | if (np) { | 398 | if (np) { |
| @@ -447,6 +462,10 @@ void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f, | |||
| 447 | s3c2443_clk_sleep_init(); | 462 | s3c2443_clk_sleep_init(); |
| 448 | 463 | ||
| 449 | samsung_clk_of_add_provider(np, ctx); | 464 | samsung_clk_of_add_provider(np, ctx); |
| 465 | |||
| 466 | ret = register_restart_handler(&s3c2443_restart_handler); | ||
| 467 | if (ret) | ||
| 468 | pr_warn("cannot register restart handler, %d\n", ret); | ||
| 450 | } | 469 | } |
| 451 | 470 | ||
| 452 | static void __init s3c2416_clk_init(struct device_node *np) | 471 | static void __init s3c2416_clk_init(struct device_node *np) |
diff --git a/drivers/clk/shmobile/clk-rcar-gen2.c b/drivers/clk/shmobile/clk-rcar-gen2.c index dff7f79a19b9..e996425d06a9 100644 --- a/drivers/clk/shmobile/clk-rcar-gen2.c +++ b/drivers/clk/shmobile/clk-rcar-gen2.c | |||
| @@ -202,6 +202,7 @@ static const struct clk_div_table cpg_sdh_div_table[] = { | |||
| 202 | }; | 202 | }; |
| 203 | 203 | ||
| 204 | static const struct clk_div_table cpg_sd01_div_table[] = { | 204 | static const struct clk_div_table cpg_sd01_div_table[] = { |
| 205 | { 4, 8 }, | ||
| 205 | { 5, 12 }, { 6, 16 }, { 7, 18 }, { 8, 24 }, | 206 | { 5, 12 }, { 6, 16 }, { 7, 18 }, { 8, 24 }, |
| 206 | { 10, 36 }, { 11, 48 }, { 12, 10 }, { 0, 0 }, | 207 | { 10, 36 }, { 11, 48 }, { 12, 10 }, { 0, 0 }, |
| 207 | }; | 208 | }; |
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index 6850cba35871..7ddc2b553846 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile | |||
| @@ -5,6 +5,8 @@ | |||
| 5 | obj-y += clk-sunxi.o clk-factors.o | 5 | obj-y += clk-sunxi.o clk-factors.o |
| 6 | obj-y += clk-a10-hosc.o | 6 | obj-y += clk-a10-hosc.o |
| 7 | obj-y += clk-a20-gmac.o | 7 | obj-y += clk-a20-gmac.o |
| 8 | obj-y += clk-mod0.o | ||
| 9 | obj-y += clk-sun8i-mbus.o | ||
| 8 | 10 | ||
| 9 | obj-$(CONFIG_MFD_SUN6I_PRCM) += \ | 11 | obj-$(CONFIG_MFD_SUN6I_PRCM) += \ |
| 10 | clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \ | 12 | clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \ |
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c index 2057c8ac648f..f83ba097126c 100644 --- a/drivers/clk/sunxi/clk-factors.c +++ b/drivers/clk/sunxi/clk-factors.c | |||
| @@ -9,18 +9,18 @@ | |||
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <linux/clk-provider.h> | 11 | #include <linux/clk-provider.h> |
| 12 | #include <linux/delay.h> | ||
| 13 | #include <linux/err.h> | ||
| 14 | #include <linux/io.h> | ||
| 12 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 16 | #include <linux/of_address.h> | ||
| 13 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
| 14 | #include <linux/io.h> | ||
| 15 | #include <linux/err.h> | ||
| 16 | #include <linux/string.h> | 18 | #include <linux/string.h> |
| 17 | 19 | ||
| 18 | #include <linux/delay.h> | ||
| 19 | |||
| 20 | #include "clk-factors.h" | 20 | #include "clk-factors.h" |
| 21 | 21 | ||
| 22 | /* | 22 | /* |
| 23 | * DOC: basic adjustable factor-based clock that cannot gate | 23 | * DOC: basic adjustable factor-based clock |
| 24 | * | 24 | * |
| 25 | * Traits of this clock: | 25 | * Traits of this clock: |
| 26 | * prepare - clk_prepare only ensures that parents are prepared | 26 | * prepare - clk_prepare only ensures that parents are prepared |
| @@ -32,6 +32,8 @@ | |||
| 32 | 32 | ||
| 33 | #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw) | 33 | #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw) |
| 34 | 34 | ||
| 35 | #define FACTORS_MAX_PARENTS 5 | ||
| 36 | |||
| 35 | #define SETMASK(len, pos) (((1U << (len)) - 1) << (pos)) | 37 | #define SETMASK(len, pos) (((1U << (len)) - 1) << (pos)) |
| 36 | #define CLRMASK(len, pos) (~(SETMASK(len, pos))) | 38 | #define CLRMASK(len, pos) (~(SETMASK(len, pos))) |
| 37 | #define FACTOR_GET(bit, len, reg) (((reg) & SETMASK(len, bit)) >> (bit)) | 39 | #define FACTOR_GET(bit, len, reg) (((reg) & SETMASK(len, bit)) >> (bit)) |
| @@ -147,9 +149,96 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, | |||
| 147 | return 0; | 149 | return 0; |
| 148 | } | 150 | } |
| 149 | 151 | ||
| 150 | const struct clk_ops clk_factors_ops = { | 152 | static const struct clk_ops clk_factors_ops = { |
| 151 | .determine_rate = clk_factors_determine_rate, | 153 | .determine_rate = clk_factors_determine_rate, |
| 152 | .recalc_rate = clk_factors_recalc_rate, | 154 | .recalc_rate = clk_factors_recalc_rate, |
| 153 | .round_rate = clk_factors_round_rate, | 155 | .round_rate = clk_factors_round_rate, |
| 154 | .set_rate = clk_factors_set_rate, | 156 | .set_rate = clk_factors_set_rate, |
| 155 | }; | 157 | }; |
| 158 | |||
| 159 | struct clk * __init sunxi_factors_register(struct device_node *node, | ||
| 160 | const struct factors_data *data, | ||
| 161 | spinlock_t *lock) | ||
| 162 | { | ||
| 163 | struct clk *clk; | ||
| 164 | struct clk_factors *factors; | ||
| 165 | struct clk_gate *gate = NULL; | ||
| 166 | struct clk_mux *mux = NULL; | ||
| 167 | struct clk_hw *gate_hw = NULL; | ||
| 168 | struct clk_hw *mux_hw = NULL; | ||
| 169 | const char *clk_name = node->name; | ||
| 170 | const char *parents[FACTORS_MAX_PARENTS]; | ||
| 171 | void __iomem *reg; | ||
| 172 | int i = 0; | ||
| 173 | |||
| 174 | reg = of_iomap(node, 0); | ||
| 175 | |||
| 176 | /* if we have a mux, we will have >1 parents */ | ||
| 177 | while (i < FACTORS_MAX_PARENTS && | ||
| 178 | (parents[i] = of_clk_get_parent_name(node, i)) != NULL) | ||
| 179 | i++; | ||
| 180 | |||
| 181 | /* | ||
| 182 | * some factor clocks, such as pll5 and pll6, may have multiple | ||
| 183 | * outputs, and have their name designated in factors_data | ||
| 184 | */ | ||
| 185 | if (data->name) | ||
| 186 | clk_name = data->name; | ||
| 187 | else | ||
| 188 | of_property_read_string(node, "clock-output-names", &clk_name); | ||
| 189 | |||
| 190 | factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL); | ||
| 191 | if (!factors) | ||
| 192 | return NULL; | ||
| 193 | |||
| 194 | /* set up factors properties */ | ||
| 195 | factors->reg = reg; | ||
| 196 | factors->config = data->table; | ||
| 197 | factors->get_factors = data->getter; | ||
| 198 | factors->lock = lock; | ||
| 199 | |||
| 200 | /* Add a gate if this factor clock can be gated */ | ||
| 201 | if (data->enable) { | ||
| 202 | gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); | ||
| 203 | if (!gate) { | ||
| 204 | kfree(factors); | ||
| 205 | return NULL; | ||
| 206 | } | ||
| 207 | |||
| 208 | /* set up gate properties */ | ||
| 209 | gate->reg = reg; | ||
| 210 | gate->bit_idx = data->enable; | ||
| 211 | gate->lock = factors->lock; | ||
| 212 | gate_hw = &gate->hw; | ||
| 213 | } | ||
| 214 | |||
| 215 | /* Add a mux if this factor clock can be muxed */ | ||
| 216 | if (data->mux) { | ||
| 217 | mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); | ||
| 218 | if (!mux) { | ||
| 219 | kfree(factors); | ||
| 220 | kfree(gate); | ||
| 221 | return NULL; | ||
| 222 | } | ||
| 223 | |||
| 224 | /* set up gate properties */ | ||
| 225 | mux->reg = reg; | ||
| 226 | mux->shift = data->mux; | ||
| 227 | mux->mask = SUNXI_FACTORS_MUX_MASK; | ||
| 228 | mux->lock = factors->lock; | ||
| 229 | mux_hw = &mux->hw; | ||
| 230 | } | ||
| 231 | |||
| 232 | clk = clk_register_composite(NULL, clk_name, | ||
| 233 | parents, i, | ||
| 234 | mux_hw, &clk_mux_ops, | ||
| 235 | &factors->hw, &clk_factors_ops, | ||
| 236 | gate_hw, &clk_gate_ops, 0); | ||
| 237 | |||
| 238 | if (!IS_ERR(clk)) { | ||
| 239 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | ||
| 240 | clk_register_clkdev(clk, clk_name, NULL); | ||
| 241 | } | ||
| 242 | |||
| 243 | return clk; | ||
| 244 | } | ||
diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h index d2d0efa39379..9913840018d3 100644 --- a/drivers/clk/sunxi/clk-factors.h +++ b/drivers/clk/sunxi/clk-factors.h | |||
| @@ -3,9 +3,12 @@ | |||
| 3 | 3 | ||
| 4 | #include <linux/clk-provider.h> | 4 | #include <linux/clk-provider.h> |
| 5 | #include <linux/clkdev.h> | 5 | #include <linux/clkdev.h> |
| 6 | #include <linux/spinlock.h> | ||
| 6 | 7 | ||
| 7 | #define SUNXI_FACTORS_NOT_APPLICABLE (0) | 8 | #define SUNXI_FACTORS_NOT_APPLICABLE (0) |
| 8 | 9 | ||
| 10 | #define SUNXI_FACTORS_MUX_MASK 0x3 | ||
| 11 | |||
| 9 | struct clk_factors_config { | 12 | struct clk_factors_config { |
| 10 | u8 nshift; | 13 | u8 nshift; |
| 11 | u8 nwidth; | 14 | u8 nwidth; |
| @@ -18,6 +21,14 @@ struct clk_factors_config { | |||
| 18 | u8 n_start; | 21 | u8 n_start; |
| 19 | }; | 22 | }; |
| 20 | 23 | ||
| 24 | struct factors_data { | ||
| 25 | int enable; | ||
| 26 | int mux; | ||
| 27 | struct clk_factors_config *table; | ||
| 28 | void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p); | ||
| 29 | const char *name; | ||
| 30 | }; | ||
| 31 | |||
| 21 | struct clk_factors { | 32 | struct clk_factors { |
| 22 | struct clk_hw hw; | 33 | struct clk_hw hw; |
| 23 | void __iomem *reg; | 34 | void __iomem *reg; |
| @@ -26,5 +37,8 @@ struct clk_factors { | |||
| 26 | spinlock_t *lock; | 37 | spinlock_t *lock; |
| 27 | }; | 38 | }; |
| 28 | 39 | ||
| 29 | extern const struct clk_ops clk_factors_ops; | 40 | struct clk * __init sunxi_factors_register(struct device_node *node, |
| 41 | const struct factors_data *data, | ||
| 42 | spinlock_t *lock); | ||
| 43 | |||
| 30 | #endif | 44 | #endif |
diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c new file mode 100644 index 000000000000..4a563850ee6e --- /dev/null +++ b/drivers/clk/sunxi/clk-mod0.c | |||
| @@ -0,0 +1,283 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2013 Emilio López | ||
| 3 | * | ||
| 4 | * Emilio López <emilio@elopez.com.ar> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/clk-provider.h> | ||
| 18 | #include <linux/clkdev.h> | ||
| 19 | #include <linux/of_address.h> | ||
| 20 | |||
| 21 | #include "clk-factors.h" | ||
| 22 | |||
| 23 | /** | ||
| 24 | * sun4i_get_mod0_factors() - calculates m, n factors for MOD0-style clocks | ||
| 25 | * MOD0 rate is calculated as follows | ||
| 26 | * rate = (parent_rate >> p) / (m + 1); | ||
| 27 | */ | ||
| 28 | |||
| 29 | static void sun4i_a10_get_mod0_factors(u32 *freq, u32 parent_rate, | ||
| 30 | u8 *n, u8 *k, u8 *m, u8 *p) | ||
| 31 | { | ||
| 32 | u8 div, calcm, calcp; | ||
| 33 | |||
| 34 | /* These clocks can only divide, so we will never be able to achieve | ||
| 35 | * frequencies higher than the parent frequency */ | ||
| 36 | if (*freq > parent_rate) | ||
| 37 | *freq = parent_rate; | ||
| 38 | |||
| 39 | div = DIV_ROUND_UP(parent_rate, *freq); | ||
| 40 | |||
| 41 | if (div < 16) | ||
| 42 | calcp = 0; | ||
| 43 | else if (div / 2 < 16) | ||
| 44 | calcp = 1; | ||
| 45 | else if (div / 4 < 16) | ||
| 46 | calcp = 2; | ||
| 47 | else | ||
| 48 | calcp = 3; | ||
| 49 | |||
| 50 | calcm = DIV_ROUND_UP(div, 1 << calcp); | ||
| 51 | |||
| 52 | *freq = (parent_rate >> calcp) / calcm; | ||
| 53 | |||
| 54 | /* we were called to round the frequency, we can now return */ | ||
| 55 | if (n == NULL) | ||
| 56 | return; | ||
| 57 | |||
| 58 | *m = calcm - 1; | ||
| 59 | *p = calcp; | ||
| 60 | } | ||
| 61 | |||
| 62 | /* user manual says "n" but it's really "p" */ | ||
| 63 | static struct clk_factors_config sun4i_a10_mod0_config = { | ||
| 64 | .mshift = 0, | ||
| 65 | .mwidth = 4, | ||
| 66 | .pshift = 16, | ||
| 67 | .pwidth = 2, | ||
| 68 | }; | ||
| 69 | |||
| 70 | static const struct factors_data sun4i_a10_mod0_data __initconst = { | ||
| 71 | .enable = 31, | ||
| 72 | .mux = 24, | ||
| 73 | .table = &sun4i_a10_mod0_config, | ||
| 74 | .getter = sun4i_a10_get_mod0_factors, | ||
| 75 | }; | ||
| 76 | |||
| 77 | static DEFINE_SPINLOCK(sun4i_a10_mod0_lock); | ||
| 78 | |||
| 79 | static void __init sun4i_a10_mod0_setup(struct device_node *node) | ||
| 80 | { | ||
| 81 | sunxi_factors_register(node, &sun4i_a10_mod0_data, &sun4i_a10_mod0_lock); | ||
| 82 | } | ||
| 83 | CLK_OF_DECLARE(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", sun4i_a10_mod0_setup); | ||
| 84 | |||
| 85 | static DEFINE_SPINLOCK(sun5i_a13_mbus_lock); | ||
| 86 | |||
| 87 | static void __init sun5i_a13_mbus_setup(struct device_node *node) | ||
| 88 | { | ||
| 89 | struct clk *mbus = sunxi_factors_register(node, &sun4i_a10_mod0_data, &sun5i_a13_mbus_lock); | ||
| 90 | |||
| 91 | /* The MBUS clocks needs to be always enabled */ | ||
| 92 | __clk_get(mbus); | ||
| 93 | clk_prepare_enable(mbus); | ||
| 94 | } | ||
| 95 | CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk", sun5i_a13_mbus_setup); | ||
| 96 | |||
| 97 | struct mmc_phase_data { | ||
| 98 | u8 offset; | ||
| 99 | }; | ||
| 100 | |||
| 101 | struct mmc_phase { | ||
| 102 | struct clk_hw hw; | ||
| 103 | void __iomem *reg; | ||
| 104 | struct mmc_phase_data *data; | ||
| 105 | spinlock_t *lock; | ||
| 106 | }; | ||
| 107 | |||
| 108 | #define to_mmc_phase(_hw) container_of(_hw, struct mmc_phase, hw) | ||
| 109 | |||
| 110 | static int mmc_get_phase(struct clk_hw *hw) | ||
| 111 | { | ||
| 112 | struct clk *mmc, *mmc_parent, *clk = hw->clk; | ||
| 113 | struct mmc_phase *phase = to_mmc_phase(hw); | ||
| 114 | unsigned int mmc_rate, mmc_parent_rate; | ||
| 115 | u16 step, mmc_div; | ||
| 116 | u32 value; | ||
| 117 | u8 delay; | ||
| 118 | |||
| 119 | value = readl(phase->reg); | ||
| 120 | delay = (value >> phase->data->offset) & 0x3; | ||
| 121 | |||
| 122 | if (!delay) | ||
| 123 | return 180; | ||
| 124 | |||
| 125 | /* Get the main MMC clock */ | ||
| 126 | mmc = clk_get_parent(clk); | ||
| 127 | if (!mmc) | ||
| 128 | return -EINVAL; | ||
| 129 | |||
| 130 | /* And its rate */ | ||
| 131 | mmc_rate = clk_get_rate(mmc); | ||
| 132 | if (!mmc_rate) | ||
| 133 | return -EINVAL; | ||
| 134 | |||
| 135 | /* Now, get the MMC parent (most likely some PLL) */ | ||
| 136 | mmc_parent = clk_get_parent(mmc); | ||
| 137 | if (!mmc_parent) | ||
| 138 | return -EINVAL; | ||
| 139 | |||
| 140 | /* And its rate */ | ||
| 141 | mmc_parent_rate = clk_get_rate(mmc_parent); | ||
| 142 | if (!mmc_parent_rate) | ||
| 143 | return -EINVAL; | ||
| 144 | |||
| 145 | /* Get MMC clock divider */ | ||
| 146 | mmc_div = mmc_parent_rate / mmc_rate; | ||
| 147 | |||
| 148 | step = DIV_ROUND_CLOSEST(360, mmc_div); | ||
| 149 | return delay * step; | ||
| 150 | } | ||
| 151 | |||
| 152 | static int mmc_set_phase(struct clk_hw *hw, int degrees) | ||
| 153 | { | ||
| 154 | struct clk *mmc, *mmc_parent, *clk = hw->clk; | ||
| 155 | struct mmc_phase *phase = to_mmc_phase(hw); | ||
| 156 | unsigned int mmc_rate, mmc_parent_rate; | ||
| 157 | unsigned long flags; | ||
| 158 | u32 value; | ||
| 159 | u8 delay; | ||
| 160 | |||
| 161 | /* Get the main MMC clock */ | ||
| 162 | mmc = clk_get_parent(clk); | ||
| 163 | if (!mmc) | ||
| 164 | return -EINVAL; | ||
| 165 | |||
| 166 | /* And its rate */ | ||
| 167 | mmc_rate = clk_get_rate(mmc); | ||
| 168 | if (!mmc_rate) | ||
| 169 | return -EINVAL; | ||
| 170 | |||
| 171 | /* Now, get the MMC parent (most likely some PLL) */ | ||
| 172 | mmc_parent = clk_get_parent(mmc); | ||
| 173 | if (!mmc_parent) | ||
| 174 | return -EINVAL; | ||
| 175 | |||
| 176 | /* And its rate */ | ||
| 177 | mmc_parent_rate = clk_get_rate(mmc_parent); | ||
| 178 | if (!mmc_parent_rate) | ||
| 179 | return -EINVAL; | ||
| 180 | |||
| 181 | if (degrees != 180) { | ||
| 182 | u16 step, mmc_div; | ||
| 183 | |||
| 184 | /* Get MMC clock divider */ | ||
| 185 | mmc_div = mmc_parent_rate / mmc_rate; | ||
| 186 | |||
| 187 | /* | ||
| 188 | * We can only outphase the clocks by multiple of the | ||
| 189 | * PLL's period. | ||
| 190 | * | ||
| 191 | * Since the MMC clock in only a divider, and the | ||
| 192 | * formula to get the outphasing in degrees is deg = | ||
| 193 | * 360 * delta / period | ||
| 194 | * | ||
| 195 | * If we simplify this formula, we can see that the | ||
| 196 | * only thing that we're concerned about is the number | ||
| 197 | * of period we want to outphase our clock from, and | ||
| 198 | * the divider set by the MMC clock. | ||
| 199 | */ | ||
| 200 | step = DIV_ROUND_CLOSEST(360, mmc_div); | ||
| 201 | delay = DIV_ROUND_CLOSEST(degrees, step); | ||
| 202 | } else { | ||
| 203 | delay = 0; | ||
| 204 | } | ||
| 205 | |||
| 206 | spin_lock_irqsave(phase->lock, flags); | ||
| 207 | value = readl(phase->reg); | ||
| 208 | value &= ~GENMASK(phase->data->offset + 3, phase->data->offset); | ||
| 209 | value |= delay << phase->data->offset; | ||
| 210 | writel(value, phase->reg); | ||
| 211 | spin_unlock_irqrestore(phase->lock, flags); | ||
| 212 | |||
| 213 | return 0; | ||
| 214 | } | ||
| 215 | |||
| 216 | static const struct clk_ops mmc_clk_ops = { | ||
| 217 | .get_phase = mmc_get_phase, | ||
| 218 | .set_phase = mmc_set_phase, | ||
| 219 | }; | ||
| 220 | |||
| 221 | static void __init sun4i_a10_mmc_phase_setup(struct device_node *node, | ||
| 222 | struct mmc_phase_data *data) | ||
| 223 | { | ||
| 224 | const char *parent_names[1] = { of_clk_get_parent_name(node, 0) }; | ||
| 225 | struct clk_init_data init = { | ||
| 226 | .num_parents = 1, | ||
| 227 | .parent_names = parent_names, | ||
| 228 | .ops = &mmc_clk_ops, | ||
| 229 | }; | ||
| 230 | |||
| 231 | struct mmc_phase *phase; | ||
| 232 | struct clk *clk; | ||
| 233 | |||
| 234 | phase = kmalloc(sizeof(*phase), GFP_KERNEL); | ||
| 235 | if (!phase) | ||
| 236 | return; | ||
| 237 | |||
| 238 | phase->hw.init = &init; | ||
| 239 | |||
| 240 | phase->reg = of_iomap(node, 0); | ||
| 241 | if (!phase->reg) | ||
| 242 | goto err_free; | ||
| 243 | |||
| 244 | phase->data = data; | ||
| 245 | phase->lock = &sun4i_a10_mod0_lock; | ||
| 246 | |||
| 247 | if (of_property_read_string(node, "clock-output-names", &init.name)) | ||
| 248 | init.name = node->name; | ||
| 249 | |||
| 250 | clk = clk_register(NULL, &phase->hw); | ||
| 251 | if (IS_ERR(clk)) | ||
| 252 | goto err_unmap; | ||
| 253 | |||
| 254 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | ||
| 255 | |||
| 256 | return; | ||
| 257 | |||
| 258 | err_unmap: | ||
| 259 | iounmap(phase->reg); | ||
| 260 | err_free: | ||
| 261 | kfree(phase); | ||
| 262 | } | ||
| 263 | |||
| 264 | |||
| 265 | static struct mmc_phase_data mmc_output_clk = { | ||
| 266 | .offset = 8, | ||
| 267 | }; | ||
| 268 | |||
| 269 | static struct mmc_phase_data mmc_sample_clk = { | ||
| 270 | .offset = 20, | ||
| 271 | }; | ||
| 272 | |||
| 273 | static void __init sun4i_a10_mmc_output_setup(struct device_node *node) | ||
| 274 | { | ||
| 275 | sun4i_a10_mmc_phase_setup(node, &mmc_output_clk); | ||
| 276 | } | ||
| 277 | CLK_OF_DECLARE(sun4i_a10_mmc_output, "allwinner,sun4i-a10-mmc-output-clk", sun4i_a10_mmc_output_setup); | ||
| 278 | |||
| 279 | static void __init sun4i_a10_mmc_sample_setup(struct device_node *node) | ||
| 280 | { | ||
| 281 | sun4i_a10_mmc_phase_setup(node, &mmc_sample_clk); | ||
| 282 | } | ||
| 283 | CLK_OF_DECLARE(sun4i_a10_mmc_sample, "allwinner,sun4i-a10-mmc-sample-clk", sun4i_a10_mmc_sample_setup); | ||
diff --git a/drivers/clk/sunxi/clk-sun6i-apb0-gates.c b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c index e10d0521ec76..64f3e46d383c 100644 --- a/drivers/clk/sunxi/clk-sun6i-apb0-gates.c +++ b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c | |||
| @@ -99,7 +99,6 @@ static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev) | |||
| 99 | static struct platform_driver sun6i_a31_apb0_gates_clk_driver = { | 99 | static struct platform_driver sun6i_a31_apb0_gates_clk_driver = { |
| 100 | .driver = { | 100 | .driver = { |
| 101 | .name = "sun6i-a31-apb0-gates-clk", | 101 | .name = "sun6i-a31-apb0-gates-clk", |
| 102 | .owner = THIS_MODULE, | ||
| 103 | .of_match_table = sun6i_a31_apb0_gates_clk_dt_ids, | 102 | .of_match_table = sun6i_a31_apb0_gates_clk_dt_ids, |
| 104 | }, | 103 | }, |
| 105 | .probe = sun6i_a31_apb0_gates_clk_probe, | 104 | .probe = sun6i_a31_apb0_gates_clk_probe, |
diff --git a/drivers/clk/sunxi/clk-sun6i-apb0.c b/drivers/clk/sunxi/clk-sun6i-apb0.c index 1fa23371c8c6..70763600aeae 100644 --- a/drivers/clk/sunxi/clk-sun6i-apb0.c +++ b/drivers/clk/sunxi/clk-sun6i-apb0.c | |||
| @@ -65,7 +65,6 @@ static const struct of_device_id sun6i_a31_apb0_clk_dt_ids[] = { | |||
| 65 | static struct platform_driver sun6i_a31_apb0_clk_driver = { | 65 | static struct platform_driver sun6i_a31_apb0_clk_driver = { |
| 66 | .driver = { | 66 | .driver = { |
| 67 | .name = "sun6i-a31-apb0-clk", | 67 | .name = "sun6i-a31-apb0-clk", |
| 68 | .owner = THIS_MODULE, | ||
| 69 | .of_match_table = sun6i_a31_apb0_clk_dt_ids, | 68 | .of_match_table = sun6i_a31_apb0_clk_dt_ids, |
| 70 | }, | 69 | }, |
| 71 | .probe = sun6i_a31_apb0_clk_probe, | 70 | .probe = sun6i_a31_apb0_clk_probe, |
diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c index eca8ca025b6a..acca53290be2 100644 --- a/drivers/clk/sunxi/clk-sun6i-ar100.c +++ b/drivers/clk/sunxi/clk-sun6i-ar100.c | |||
| @@ -221,7 +221,6 @@ static const struct of_device_id sun6i_a31_ar100_clk_dt_ids[] = { | |||
| 221 | static struct platform_driver sun6i_a31_ar100_clk_driver = { | 221 | static struct platform_driver sun6i_a31_ar100_clk_driver = { |
| 222 | .driver = { | 222 | .driver = { |
| 223 | .name = "sun6i-a31-ar100-clk", | 223 | .name = "sun6i-a31-ar100-clk", |
| 224 | .owner = THIS_MODULE, | ||
| 225 | .of_match_table = sun6i_a31_ar100_clk_dt_ids, | 224 | .of_match_table = sun6i_a31_ar100_clk_dt_ids, |
| 226 | }, | 225 | }, |
| 227 | .probe = sun6i_a31_ar100_clk_probe, | 226 | .probe = sun6i_a31_ar100_clk_probe, |
diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c index 1f5ba9b4b8cd..155d0022194f 100644 --- a/drivers/clk/sunxi/clk-sun8i-apb0.c +++ b/drivers/clk/sunxi/clk-sun8i-apb0.c | |||
| @@ -56,7 +56,6 @@ static const struct of_device_id sun8i_a23_apb0_clk_dt_ids[] = { | |||
| 56 | static struct platform_driver sun8i_a23_apb0_clk_driver = { | 56 | static struct platform_driver sun8i_a23_apb0_clk_driver = { |
| 57 | .driver = { | 57 | .driver = { |
| 58 | .name = "sun8i-a23-apb0-clk", | 58 | .name = "sun8i-a23-apb0-clk", |
| 59 | .owner = THIS_MODULE, | ||
| 60 | .of_match_table = sun8i_a23_apb0_clk_dt_ids, | 59 | .of_match_table = sun8i_a23_apb0_clk_dt_ids, |
| 61 | }, | 60 | }, |
| 62 | .probe = sun8i_a23_apb0_clk_probe, | 61 | .probe = sun8i_a23_apb0_clk_probe, |
diff --git a/drivers/clk/sunxi/clk-sun8i-mbus.c b/drivers/clk/sunxi/clk-sun8i-mbus.c new file mode 100644 index 000000000000..8e49b44cee41 --- /dev/null +++ b/drivers/clk/sunxi/clk-sun8i-mbus.c | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2014 Chen-Yu Tsai | ||
| 3 | * | ||
| 4 | * Chen-Yu Tsai <wens@csie.org> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/clk-provider.h> | ||
| 18 | #include <linux/clkdev.h> | ||
| 19 | #include <linux/of_address.h> | ||
| 20 | |||
| 21 | #include "clk-factors.h" | ||
| 22 | |||
| 23 | /** | ||
| 24 | * sun8i_a23_get_mbus_factors() - calculates m factor for MBUS clocks | ||
| 25 | * MBUS rate is calculated as follows | ||
| 26 | * rate = parent_rate / (m + 1); | ||
| 27 | */ | ||
| 28 | |||
| 29 | static void sun8i_a23_get_mbus_factors(u32 *freq, u32 parent_rate, | ||
| 30 | u8 *n, u8 *k, u8 *m, u8 *p) | ||
| 31 | { | ||
| 32 | u8 div; | ||
| 33 | |||
| 34 | /* | ||
| 35 | * These clocks can only divide, so we will never be able to | ||
| 36 | * achieve frequencies higher than the parent frequency | ||
| 37 | */ | ||
| 38 | if (*freq > parent_rate) | ||
| 39 | *freq = parent_rate; | ||
| 40 | |||
| 41 | div = DIV_ROUND_UP(parent_rate, *freq); | ||
| 42 | |||
| 43 | if (div > 8) | ||
| 44 | div = 8; | ||
| 45 | |||
| 46 | *freq = parent_rate / div; | ||
| 47 | |||
| 48 | /* we were called to round the frequency, we can now return */ | ||
| 49 | if (m == NULL) | ||
| 50 | return; | ||
| 51 | |||
| 52 | *m = div - 1; | ||
| 53 | } | ||
| 54 | |||
| 55 | static struct clk_factors_config sun8i_a23_mbus_config = { | ||
| 56 | .mshift = 0, | ||
| 57 | .mwidth = 3, | ||
| 58 | }; | ||
| 59 | |||
| 60 | static const struct factors_data sun8i_a23_mbus_data __initconst = { | ||
| 61 | .enable = 31, | ||
| 62 | .mux = 24, | ||
| 63 | .table = &sun8i_a23_mbus_config, | ||
| 64 | .getter = sun8i_a23_get_mbus_factors, | ||
| 65 | }; | ||
| 66 | |||
| 67 | static DEFINE_SPINLOCK(sun8i_a23_mbus_lock); | ||
| 68 | |||
| 69 | static void __init sun8i_a23_mbus_setup(struct device_node *node) | ||
| 70 | { | ||
| 71 | struct clk *mbus = sunxi_factors_register(node, &sun8i_a23_mbus_data, | ||
| 72 | &sun8i_a23_mbus_lock); | ||
| 73 | |||
| 74 | /* The MBUS clocks needs to be always enabled */ | ||
| 75 | __clk_get(mbus); | ||
| 76 | clk_prepare_enable(mbus); | ||
| 77 | } | ||
| 78 | CLK_OF_DECLARE(sun8i_a23_mbus, "allwinner,sun8i-a23-mbus-clk", sun8i_a23_mbus_setup); | ||
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index b654b7b1d137..d5dc951264ca 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/of.h> | 19 | #include <linux/of.h> |
| 20 | #include <linux/of_address.h> | 20 | #include <linux/of_address.h> |
| 21 | #include <linux/reset-controller.h> | 21 | #include <linux/reset-controller.h> |
| 22 | #include <linux/spinlock.h> | ||
| 22 | 23 | ||
| 23 | #include "clk-factors.h" | 24 | #include "clk-factors.h" |
| 24 | 25 | ||
| @@ -319,46 +320,6 @@ static void sun4i_get_apb1_factors(u32 *freq, u32 parent_rate, | |||
| 319 | 320 | ||
| 320 | 321 | ||
| 321 | 322 | ||
| 322 | /** | ||
| 323 | * sun4i_get_mod0_factors() - calculates m, n factors for MOD0-style clocks | ||
| 324 | * MOD0 rate is calculated as follows | ||
| 325 | * rate = (parent_rate >> p) / (m + 1); | ||
| 326 | */ | ||
| 327 | |||
| 328 | static void sun4i_get_mod0_factors(u32 *freq, u32 parent_rate, | ||
| 329 | u8 *n, u8 *k, u8 *m, u8 *p) | ||
| 330 | { | ||
| 331 | u8 div, calcm, calcp; | ||
| 332 | |||
| 333 | /* These clocks can only divide, so we will never be able to achieve | ||
| 334 | * frequencies higher than the parent frequency */ | ||
| 335 | if (*freq > parent_rate) | ||
| 336 | *freq = parent_rate; | ||
| 337 | |||
| 338 | div = DIV_ROUND_UP(parent_rate, *freq); | ||
| 339 | |||
| 340 | if (div < 16) | ||
| 341 | calcp = 0; | ||
| 342 | else if (div / 2 < 16) | ||
| 343 | calcp = 1; | ||
| 344 | else if (div / 4 < 16) | ||
| 345 | calcp = 2; | ||
| 346 | else | ||
| 347 | calcp = 3; | ||
| 348 | |||
| 349 | calcm = DIV_ROUND_UP(div, 1 << calcp); | ||
| 350 | |||
| 351 | *freq = (parent_rate >> calcp) / calcm; | ||
| 352 | |||
| 353 | /* we were called to round the frequency, we can now return */ | ||
| 354 | if (n == NULL) | ||
| 355 | return; | ||
| 356 | |||
| 357 | *m = calcm - 1; | ||
| 358 | *p = calcp; | ||
| 359 | } | ||
| 360 | |||
| 361 | |||
| 362 | 323 | ||
| 363 | /** | 324 | /** |
| 364 | * sun7i_a20_get_out_factors() - calculates m, p factors for CLK_OUT_A/B | 325 | * sun7i_a20_get_out_factors() - calculates m, p factors for CLK_OUT_A/B |
| @@ -440,16 +401,6 @@ EXPORT_SYMBOL(clk_sunxi_mmc_phase_control); | |||
| 440 | * sunxi_factors_clk_setup() - Setup function for factor clocks | 401 | * sunxi_factors_clk_setup() - Setup function for factor clocks |
| 441 | */ | 402 | */ |
| 442 | 403 | ||
| 443 | #define SUNXI_FACTORS_MUX_MASK 0x3 | ||
| 444 | |||
| 445 | struct factors_data { | ||
| 446 | int enable; | ||
| 447 | int mux; | ||
| 448 | struct clk_factors_config *table; | ||
| 449 | void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p); | ||
| 450 | const char *name; | ||
| 451 | }; | ||
| 452 | |||
| 453 | static struct clk_factors_config sun4i_pll1_config = { | 404 | static struct clk_factors_config sun4i_pll1_config = { |
| 454 | .nshift = 8, | 405 | .nshift = 8, |
| 455 | .nwidth = 5, | 406 | .nwidth = 5, |
| @@ -504,14 +455,6 @@ static struct clk_factors_config sun4i_apb1_config = { | |||
| 504 | }; | 455 | }; |
| 505 | 456 | ||
| 506 | /* user manual says "n" but it's really "p" */ | 457 | /* user manual says "n" but it's really "p" */ |
| 507 | static struct clk_factors_config sun4i_mod0_config = { | ||
| 508 | .mshift = 0, | ||
| 509 | .mwidth = 4, | ||
| 510 | .pshift = 16, | ||
| 511 | .pwidth = 2, | ||
| 512 | }; | ||
| 513 | |||
| 514 | /* user manual says "n" but it's really "p" */ | ||
| 515 | static struct clk_factors_config sun7i_a20_out_config = { | 458 | static struct clk_factors_config sun7i_a20_out_config = { |
| 516 | .mshift = 8, | 459 | .mshift = 8, |
| 517 | .mwidth = 5, | 460 | .mwidth = 5, |
| @@ -568,13 +511,6 @@ static const struct factors_data sun4i_apb1_data __initconst = { | |||
| 568 | .getter = sun4i_get_apb1_factors, | 511 | .getter = sun4i_get_apb1_factors, |
| 569 | }; | 512 | }; |
| 570 | 513 | ||
| 571 | static const struct factors_data sun4i_mod0_data __initconst = { | ||
| 572 | .enable = 31, | ||
| 573 | .mux = 24, | ||
| 574 | .table = &sun4i_mod0_config, | ||
| 575 | .getter = sun4i_get_mod0_factors, | ||
| 576 | }; | ||
| 577 | |||
| 578 | static const struct factors_data sun7i_a20_out_data __initconst = { | 514 | static const struct factors_data sun7i_a20_out_data __initconst = { |
| 579 | .enable = 31, | 515 | .enable = 31, |
| 580 | .mux = 24, | 516 | .mux = 24, |
| @@ -583,89 +519,9 @@ static const struct factors_data sun7i_a20_out_data __initconst = { | |||
| 583 | }; | 519 | }; |
| 584 | 520 | ||
| 585 | static struct clk * __init sunxi_factors_clk_setup(struct device_node *node, | 521 | static struct clk * __init sunxi_factors_clk_setup(struct device_node *node, |
| 586 | const struct factors_data *data) | 522 | const struct factors_data *data) |
| 587 | { | 523 | { |
| 588 | struct clk *clk; | 524 | return sunxi_factors_register(node, data, &clk_lock); |
| 589 | struct clk_factors *factors; | ||
| 590 | struct clk_gate *gate = NULL; | ||
| 591 | struct clk_mux *mux = NULL; | ||
| 592 | struct clk_hw *gate_hw = NULL; | ||
| 593 | struct clk_hw *mux_hw = NULL; | ||
| 594 | const char *clk_name = node->name; | ||
| 595 | const char *parents[SUNXI_MAX_PARENTS]; | ||
| 596 | void __iomem *reg; | ||
| 597 | int i = 0; | ||
| 598 | |||
| 599 | reg = of_iomap(node, 0); | ||
| 600 | |||
| 601 | /* if we have a mux, we will have >1 parents */ | ||
| 602 | while (i < SUNXI_MAX_PARENTS && | ||
| 603 | (parents[i] = of_clk_get_parent_name(node, i)) != NULL) | ||
| 604 | i++; | ||
| 605 | |||
| 606 | /* | ||
| 607 | * some factor clocks, such as pll5 and pll6, may have multiple | ||
| 608 | * outputs, and have their name designated in factors_data | ||
| 609 | */ | ||
| 610 | if (data->name) | ||
| 611 | clk_name = data->name; | ||
| 612 | else | ||
| 613 | of_property_read_string(node, "clock-output-names", &clk_name); | ||
| 614 | |||
| 615 | factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL); | ||
| 616 | if (!factors) | ||
| 617 | return NULL; | ||
| 618 | |||
| 619 | /* Add a gate if this factor clock can be gated */ | ||
| 620 | if (data->enable) { | ||
| 621 | gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); | ||
| 622 | if (!gate) { | ||
| 623 | kfree(factors); | ||
| 624 | return NULL; | ||
| 625 | } | ||
| 626 | |||
| 627 | /* set up gate properties */ | ||
| 628 | gate->reg = reg; | ||
| 629 | gate->bit_idx = data->enable; | ||
| 630 | gate->lock = &clk_lock; | ||
| 631 | gate_hw = &gate->hw; | ||
| 632 | } | ||
| 633 | |||
| 634 | /* Add a mux if this factor clock can be muxed */ | ||
| 635 | if (data->mux) { | ||
| 636 | mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); | ||
| 637 | if (!mux) { | ||
| 638 | kfree(factors); | ||
| 639 | kfree(gate); | ||
| 640 | return NULL; | ||
| 641 | } | ||
| 642 | |||
| 643 | /* set up gate properties */ | ||
| 644 | mux->reg = reg; | ||
| 645 | mux->shift = data->mux; | ||
| 646 | mux->mask = SUNXI_FACTORS_MUX_MASK; | ||
| 647 | mux->lock = &clk_lock; | ||
| 648 | mux_hw = &mux->hw; | ||
| 649 | } | ||
| 650 | |||
| 651 | /* set up factors properties */ | ||
| 652 | factors->reg = reg; | ||
| 653 | factors->config = data->table; | ||
| 654 | factors->get_factors = data->getter; | ||
| 655 | factors->lock = &clk_lock; | ||
| 656 | |||
| 657 | clk = clk_register_composite(NULL, clk_name, | ||
| 658 | parents, i, | ||
| 659 | mux_hw, &clk_mux_ops, | ||
| 660 | &factors->hw, &clk_factors_ops, | ||
| 661 | gate_hw, &clk_gate_ops, 0); | ||
| 662 | |||
| 663 | if (!IS_ERR(clk)) { | ||
| 664 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | ||
| 665 | clk_register_clkdev(clk, clk_name, NULL); | ||
| 666 | } | ||
| 667 | |||
| 668 | return clk; | ||
| 669 | } | 525 | } |
| 670 | 526 | ||
| 671 | 527 | ||
| @@ -762,10 +618,19 @@ static const struct div_data sun4i_ahb_data __initconst = { | |||
| 762 | .width = 2, | 618 | .width = 2, |
| 763 | }; | 619 | }; |
| 764 | 620 | ||
| 621 | static const struct clk_div_table sun4i_apb0_table[] __initconst = { | ||
| 622 | { .val = 0, .div = 2 }, | ||
| 623 | { .val = 1, .div = 2 }, | ||
| 624 | { .val = 2, .div = 4 }, | ||
| 625 | { .val = 3, .div = 8 }, | ||
| 626 | { } /* sentinel */ | ||
| 627 | }; | ||
| 628 | |||
| 765 | static const struct div_data sun4i_apb0_data __initconst = { | 629 | static const struct div_data sun4i_apb0_data __initconst = { |
| 766 | .shift = 8, | 630 | .shift = 8, |
| 767 | .pow = 1, | 631 | .pow = 1, |
| 768 | .width = 2, | 632 | .width = 2, |
| 633 | .table = sun4i_apb0_table, | ||
| 769 | }; | 634 | }; |
| 770 | 635 | ||
| 771 | static const struct div_data sun6i_a31_apb2_div_data __initconst = { | 636 | static const struct div_data sun6i_a31_apb2_div_data __initconst = { |
| @@ -1199,7 +1064,6 @@ static const struct of_device_id clk_factors_match[] __initconst = { | |||
| 1199 | {.compatible = "allwinner,sun7i-a20-pll4-clk", .data = &sun7i_a20_pll4_data,}, | 1064 | {.compatible = "allwinner,sun7i-a20-pll4-clk", .data = &sun7i_a20_pll4_data,}, |
| 1200 | {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,}, | 1065 | {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,}, |
| 1201 | {.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,}, | 1066 | {.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,}, |
| 1202 | {.compatible = "allwinner,sun4i-a10-mod0-clk", .data = &sun4i_mod0_data,}, | ||
| 1203 | {.compatible = "allwinner,sun7i-a20-out-clk", .data = &sun7i_a20_out_data,}, | 1067 | {.compatible = "allwinner,sun7i-a20-out-clk", .data = &sun7i_a20_out_data,}, |
| 1204 | {} | 1068 | {} |
| 1205 | }; | 1069 | }; |
| @@ -1311,7 +1175,6 @@ static void __init sun4i_a10_init_clocks(struct device_node *node) | |||
| 1311 | CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sun4i_a10_init_clocks); | 1175 | CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sun4i_a10_init_clocks); |
| 1312 | 1176 | ||
| 1313 | static const char *sun5i_critical_clocks[] __initdata = { | 1177 | static const char *sun5i_critical_clocks[] __initdata = { |
| 1314 | "mbus", | ||
| 1315 | "pll5_ddr", | 1178 | "pll5_ddr", |
| 1316 | "ahb_sdram", | 1179 | "ahb_sdram", |
| 1317 | }; | 1180 | }; |
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index 9525c684d149..e3a85842ce0c 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c | |||
| @@ -1166,6 +1166,12 @@ static void __init tegra124_pll_init(void __iomem *clk_base, | |||
| 1166 | clk_register_clkdev(clk, "pll_c_out1", NULL); | 1166 | clk_register_clkdev(clk, "pll_c_out1", NULL); |
| 1167 | clks[TEGRA124_CLK_PLL_C_OUT1] = clk; | 1167 | clks[TEGRA124_CLK_PLL_C_OUT1] = clk; |
| 1168 | 1168 | ||
| 1169 | /* PLLC_UD */ | ||
| 1170 | clk = clk_register_fixed_factor(NULL, "pll_c_ud", "pll_c", | ||
| 1171 | CLK_SET_RATE_PARENT, 1, 1); | ||
| 1172 | clk_register_clkdev(clk, "pll_c_ud", NULL); | ||
| 1173 | clks[TEGRA124_CLK_PLL_C_UD] = clk; | ||
| 1174 | |||
| 1169 | /* PLLC2 */ | 1175 | /* PLLC2 */ |
| 1170 | clk = tegra_clk_register_pllc("pll_c2", "pll_ref", clk_base, pmc, 0, | 1176 | clk = tegra_clk_register_pllc("pll_c2", "pll_ref", clk_base, pmc, 0, |
| 1171 | &pll_c2_params, NULL); | 1177 | &pll_c2_params, NULL); |
| @@ -1198,6 +1204,8 @@ static void __init tegra124_pll_init(void __iomem *clk_base, | |||
| 1198 | /* PLLM_UD */ | 1204 | /* PLLM_UD */ |
| 1199 | clk = clk_register_fixed_factor(NULL, "pll_m_ud", "pll_m", | 1205 | clk = clk_register_fixed_factor(NULL, "pll_m_ud", "pll_m", |
| 1200 | CLK_SET_RATE_PARENT, 1, 1); | 1206 | CLK_SET_RATE_PARENT, 1, 1); |
| 1207 | clk_register_clkdev(clk, "pll_m_ud", NULL); | ||
| 1208 | clks[TEGRA124_CLK_PLL_M_UD] = clk; | ||
| 1201 | 1209 | ||
| 1202 | /* PLLU */ | 1210 | /* PLLU */ |
| 1203 | val = readl(clk_base + pll_u_params.base_reg); | 1211 | val = readl(clk_base + pll_u_params.base_reg); |
diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c index f87c609e8f72..97dc8595c3cd 100644 --- a/drivers/clk/tegra/clk.c +++ b/drivers/clk/tegra/clk.c | |||
| @@ -207,8 +207,13 @@ void __init tegra_init_from_table(struct tegra_clk_init_table *tbl, | |||
| 207 | 207 | ||
| 208 | for (; tbl->clk_id < clk_max; tbl++) { | 208 | for (; tbl->clk_id < clk_max; tbl++) { |
| 209 | clk = clks[tbl->clk_id]; | 209 | clk = clks[tbl->clk_id]; |
| 210 | if (IS_ERR_OR_NULL(clk)) | 210 | if (IS_ERR_OR_NULL(clk)) { |
| 211 | return; | 211 | pr_err("%s: invalid entry %ld in clks array for id %d\n", |
| 212 | __func__, PTR_ERR(clk), tbl->clk_id); | ||
| 213 | WARN_ON(1); | ||
| 214 | |||
| 215 | continue; | ||
| 216 | } | ||
| 212 | 217 | ||
| 213 | if (tbl->parent_id < clk_max) { | 218 | if (tbl->parent_id < clk_max) { |
| 214 | struct clk *parent = clks[tbl->parent_id]; | 219 | struct clk *parent = clks[tbl->parent_id]; |
diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c index af29359677da..59bb4b39d12e 100644 --- a/drivers/clk/ti/clk-dra7-atl.c +++ b/drivers/clk/ti/clk-dra7-atl.c | |||
| @@ -203,6 +203,7 @@ static void __init of_dra7_atl_clock_setup(struct device_node *node) | |||
| 203 | 203 | ||
| 204 | if (!IS_ERR(clk)) { | 204 | if (!IS_ERR(clk)) { |
| 205 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | 205 | of_clk_add_provider(node, of_clk_src_simple_get, clk); |
| 206 | kfree(parent_names); | ||
| 206 | return; | 207 | return; |
| 207 | } | 208 | } |
| 208 | cleanup: | 209 | cleanup: |
| @@ -228,6 +229,7 @@ static int of_dra7_atl_clk_probe(struct platform_device *pdev) | |||
| 228 | cinfo->iobase = of_iomap(node, 0); | 229 | cinfo->iobase = of_iomap(node, 0); |
| 229 | cinfo->dev = &pdev->dev; | 230 | cinfo->dev = &pdev->dev; |
| 230 | pm_runtime_enable(cinfo->dev); | 231 | pm_runtime_enable(cinfo->dev); |
| 232 | pm_runtime_irq_safe(cinfo->dev); | ||
| 231 | 233 | ||
| 232 | pm_runtime_get_sync(cinfo->dev); | 234 | pm_runtime_get_sync(cinfo->dev); |
| 233 | atl_write(cinfo, DRA7_ATL_PCLKMUX_REG(0), DRA7_ATL_PCLKMUX); | 235 | atl_write(cinfo, DRA7_ATL_PCLKMUX_REG(0), DRA7_ATL_PCLKMUX); |
| @@ -301,7 +303,6 @@ MODULE_DEVICE_TABLE(of, of_dra7_atl_clk_match_tbl); | |||
| 301 | static struct platform_driver dra7_atl_clk_driver = { | 303 | static struct platform_driver dra7_atl_clk_driver = { |
| 302 | .driver = { | 304 | .driver = { |
| 303 | .name = "dra7-atl", | 305 | .name = "dra7-atl", |
| 304 | .owner = THIS_MODULE, | ||
| 305 | .of_match_table = of_dra7_atl_clk_match_tbl, | 306 | .of_match_table = of_dra7_atl_clk_match_tbl, |
| 306 | }, | 307 | }, |
| 307 | .probe = of_dra7_atl_clk_probe, | 308 | .probe = of_dra7_atl_clk_probe, |
diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index b1a6f7144f3f..337abe5909e1 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c | |||
| @@ -25,8 +25,8 @@ | |||
| 25 | #undef pr_fmt | 25 | #undef pr_fmt |
| 26 | #define pr_fmt(fmt) "%s: " fmt, __func__ | 26 | #define pr_fmt(fmt) "%s: " fmt, __func__ |
| 27 | 27 | ||
| 28 | static int ti_dt_clk_memmap_index; | ||
| 29 | struct ti_clk_ll_ops *ti_clk_ll_ops; | 28 | struct ti_clk_ll_ops *ti_clk_ll_ops; |
| 29 | static struct device_node *clocks_node_ptr[CLK_MAX_MEMMAPS]; | ||
| 30 | 30 | ||
| 31 | /** | 31 | /** |
| 32 | * ti_dt_clocks_register - register DT alias clocks during boot | 32 | * ti_dt_clocks_register - register DT alias clocks during boot |
| @@ -108,9 +108,21 @@ void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index) | |||
| 108 | struct clk_omap_reg *reg; | 108 | struct clk_omap_reg *reg; |
| 109 | u32 val; | 109 | u32 val; |
| 110 | u32 tmp; | 110 | u32 tmp; |
| 111 | int i; | ||
| 111 | 112 | ||
| 112 | reg = (struct clk_omap_reg *)&tmp; | 113 | reg = (struct clk_omap_reg *)&tmp; |
| 113 | reg->index = ti_dt_clk_memmap_index; | 114 | |
| 115 | for (i = 0; i < CLK_MAX_MEMMAPS; i++) { | ||
| 116 | if (clocks_node_ptr[i] == node->parent) | ||
| 117 | break; | ||
| 118 | } | ||
| 119 | |||
| 120 | if (i == CLK_MAX_MEMMAPS) { | ||
| 121 | pr_err("clk-provider not found for %s!\n", node->name); | ||
| 122 | return NULL; | ||
| 123 | } | ||
| 124 | |||
| 125 | reg->index = i; | ||
| 114 | 126 | ||
| 115 | if (of_property_read_u32_index(node, "reg", index, &val)) { | 127 | if (of_property_read_u32_index(node, "reg", index, &val)) { |
| 116 | pr_err("%s must have reg[%d]!\n", node->name, index); | 128 | pr_err("%s must have reg[%d]!\n", node->name, index); |
| @@ -127,20 +139,14 @@ void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index) | |||
| 127 | * @parent: master node | 139 | * @parent: master node |
| 128 | * @index: internal index for clk_reg_ops | 140 | * @index: internal index for clk_reg_ops |
| 129 | * | 141 | * |
| 130 | * Initializes a master clock IP block and its child clock nodes. | 142 | * Initializes a master clock IP block. This basically sets up the |
| 131 | * Regmap is provided for accessing the register space for the | 143 | * mapping from clocks node to the memory map index. All the clocks |
| 132 | * IP block and all the clocks under it. | 144 | * are then initialized through the common of_clk_init call, and the |
| 145 | * clocks will access their memory maps based on the node layout. | ||
| 133 | */ | 146 | */ |
| 134 | void ti_dt_clk_init_provider(struct device_node *parent, int index) | 147 | void ti_dt_clk_init_provider(struct device_node *parent, int index) |
| 135 | { | 148 | { |
| 136 | const struct of_device_id *match; | ||
| 137 | struct device_node *np; | ||
| 138 | struct device_node *clocks; | 149 | struct device_node *clocks; |
| 139 | of_clk_init_cb_t clk_init_cb; | ||
| 140 | struct clk_init_item *retry; | ||
| 141 | struct clk_init_item *tmp; | ||
| 142 | |||
| 143 | ti_dt_clk_memmap_index = index; | ||
| 144 | 150 | ||
| 145 | /* get clocks for this parent */ | 151 | /* get clocks for this parent */ |
| 146 | clocks = of_get_child_by_name(parent, "clocks"); | 152 | clocks = of_get_child_by_name(parent, "clocks"); |
| @@ -149,19 +155,31 @@ void ti_dt_clk_init_provider(struct device_node *parent, int index) | |||
| 149 | return; | 155 | return; |
| 150 | } | 156 | } |
| 151 | 157 | ||
| 152 | for_each_child_of_node(clocks, np) { | 158 | /* add clocks node info */ |
| 153 | match = of_match_node(&__clk_of_table, np); | 159 | clocks_node_ptr[index] = clocks; |
| 154 | if (!match) | 160 | } |
| 155 | continue; | ||
| 156 | clk_init_cb = (of_clk_init_cb_t)match->data; | ||
| 157 | pr_debug("%s: initializing: %s\n", __func__, np->name); | ||
| 158 | clk_init_cb(np); | ||
| 159 | } | ||
| 160 | 161 | ||
| 161 | list_for_each_entry_safe(retry, tmp, &retry_list, link) { | 162 | /** |
| 162 | pr_debug("retry-init: %s\n", retry->node->name); | 163 | * ti_dt_clk_init_retry_clks - init clocks from the retry list |
| 163 | retry->func(retry->hw, retry->node); | 164 | * |
| 164 | list_del(&retry->link); | 165 | * Initializes any clocks that have failed to initialize before, |
| 165 | kfree(retry); | 166 | * reasons being missing parent node(s) during earlier init. This |
| 167 | * typically happens only for DPLLs which need to have both of their | ||
| 168 | * parent clocks ready during init. | ||
| 169 | */ | ||
| 170 | void ti_dt_clk_init_retry_clks(void) | ||
| 171 | { | ||
| 172 | struct clk_init_item *retry; | ||
| 173 | struct clk_init_item *tmp; | ||
| 174 | int retries = 5; | ||
| 175 | |||
| 176 | while (!list_empty(&retry_list) && retries) { | ||
| 177 | list_for_each_entry_safe(retry, tmp, &retry_list, link) { | ||
| 178 | pr_debug("retry-init: %s\n", retry->node->name); | ||
| 179 | retry->func(retry->hw, retry->node); | ||
| 180 | list_del(&retry->link); | ||
| 181 | kfree(retry); | ||
| 182 | } | ||
| 183 | retries--; | ||
| 166 | } | 184 | } |
| 167 | } | 185 | } |
diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c index f1e0038d76ac..b4c5faccaece 100644 --- a/drivers/clk/ti/clockdomain.c +++ b/drivers/clk/ti/clockdomain.c | |||
| @@ -36,6 +36,11 @@ static void __init of_ti_clockdomain_setup(struct device_node *node) | |||
| 36 | 36 | ||
| 37 | for (i = 0; i < num_clks; i++) { | 37 | for (i = 0; i < num_clks; i++) { |
| 38 | clk = of_clk_get(node, i); | 38 | clk = of_clk_get(node, i); |
| 39 | if (IS_ERR(clk)) { | ||
| 40 | pr_err("%s: Failed get %s' clock nr %d (%ld)\n", | ||
| 41 | __func__, node->full_name, i, PTR_ERR(clk)); | ||
| 42 | continue; | ||
| 43 | } | ||
| 39 | if (__clk_get_flags(clk) & CLK_IS_BASIC) { | 44 | if (__clk_get_flags(clk) & CLK_IS_BASIC) { |
| 40 | pr_warn("can't setup clkdm for basic clk %s\n", | 45 | pr_warn("can't setup clkdm for basic clk %s\n", |
| 41 | __clk_get_name(clk)); | 46 | __clk_get_name(clk)); |
diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c index a837f703be65..bff2b5b8ff59 100644 --- a/drivers/clk/ti/divider.c +++ b/drivers/clk/ti/divider.c | |||
| @@ -300,8 +300,8 @@ static struct clk *_register_divider(struct device *dev, const char *name, | |||
| 300 | return clk; | 300 | return clk; |
| 301 | } | 301 | } |
| 302 | 302 | ||
| 303 | static struct clk_div_table | 303 | static struct clk_div_table * |
| 304 | __init *ti_clk_get_div_table(struct device_node *node) | 304 | __init ti_clk_get_div_table(struct device_node *node) |
| 305 | { | 305 | { |
| 306 | struct clk_div_table *table; | 306 | struct clk_div_table *table; |
| 307 | const __be32 *divspec; | 307 | const __be32 *divspec; |
diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c index 246cf1226eaa..9037bebd69f7 100644 --- a/drivers/clk/zynq/clkc.c +++ b/drivers/clk/zynq/clkc.c | |||
| @@ -85,24 +85,22 @@ static DEFINE_SPINLOCK(canmioclk_lock); | |||
| 85 | static DEFINE_SPINLOCK(dbgclk_lock); | 85 | static DEFINE_SPINLOCK(dbgclk_lock); |
| 86 | static DEFINE_SPINLOCK(aperclk_lock); | 86 | static DEFINE_SPINLOCK(aperclk_lock); |
| 87 | 87 | ||
| 88 | static const char dummy_nm[] __initconst = "dummy_name"; | 88 | static const char *armpll_parents[] __initconst = {"armpll_int", "ps_clk"}; |
| 89 | 89 | static const char *ddrpll_parents[] __initconst = {"ddrpll_int", "ps_clk"}; | |
| 90 | static const char *armpll_parents[] __initdata = {"armpll_int", "ps_clk"}; | 90 | static const char *iopll_parents[] __initconst = {"iopll_int", "ps_clk"}; |
| 91 | static const char *ddrpll_parents[] __initdata = {"ddrpll_int", "ps_clk"}; | 91 | static const char *gem0_mux_parents[] __initconst = {"gem0_div1", "dummy_name"}; |
| 92 | static const char *iopll_parents[] __initdata = {"iopll_int", "ps_clk"}; | 92 | static const char *gem1_mux_parents[] __initconst = {"gem1_div1", "dummy_name"}; |
| 93 | static const char *gem0_mux_parents[] __initdata = {"gem0_div1", dummy_nm}; | 93 | static const char *can0_mio_mux2_parents[] __initconst = {"can0_gate", |
| 94 | static const char *gem1_mux_parents[] __initdata = {"gem1_div1", dummy_nm}; | ||
| 95 | static const char *can0_mio_mux2_parents[] __initdata = {"can0_gate", | ||
| 96 | "can0_mio_mux"}; | 94 | "can0_mio_mux"}; |
| 97 | static const char *can1_mio_mux2_parents[] __initdata = {"can1_gate", | 95 | static const char *can1_mio_mux2_parents[] __initconst = {"can1_gate", |
| 98 | "can1_mio_mux"}; | 96 | "can1_mio_mux"}; |
| 99 | static const char *dbg_emio_mux_parents[] __initdata = {"dbg_div", | 97 | static const char *dbg_emio_mux_parents[] __initconst = {"dbg_div", |
| 100 | dummy_nm}; | 98 | "dummy_name"}; |
| 101 | 99 | ||
| 102 | static const char *dbgtrc_emio_input_names[] __initdata = {"trace_emio_clk"}; | 100 | static const char *dbgtrc_emio_input_names[] __initconst = {"trace_emio_clk"}; |
| 103 | static const char *gem0_emio_input_names[] __initdata = {"gem0_emio_clk"}; | 101 | static const char *gem0_emio_input_names[] __initconst = {"gem0_emio_clk"}; |
| 104 | static const char *gem1_emio_input_names[] __initdata = {"gem1_emio_clk"}; | 102 | static const char *gem1_emio_input_names[] __initconst = {"gem1_emio_clk"}; |
| 105 | static const char *swdt_ext_clk_input_names[] __initdata = {"swdt_ext_clk"}; | 103 | static const char *swdt_ext_clk_input_names[] __initconst = {"swdt_ext_clk"}; |
| 106 | 104 | ||
| 107 | static void __init zynq_clk_register_fclk(enum zynq_clk fclk, | 105 | static void __init zynq_clk_register_fclk(enum zynq_clk fclk, |
| 108 | const char *clk_name, void __iomem *fclk_ctrl_reg, | 106 | const char *clk_name, void __iomem *fclk_ctrl_reg, |
| @@ -230,6 +228,7 @@ static void __init zynq_clk_setup(struct device_node *np) | |||
| 230 | const char *periph_parents[4]; | 228 | const char *periph_parents[4]; |
| 231 | const char *swdt_ext_clk_mux_parents[2]; | 229 | const char *swdt_ext_clk_mux_parents[2]; |
| 232 | const char *can_mio_mux_parents[NUM_MIO_PINS]; | 230 | const char *can_mio_mux_parents[NUM_MIO_PINS]; |
| 231 | const char *dummy_nm = "dummy_name"; | ||
| 233 | 232 | ||
| 234 | pr_info("Zynq clock init\n"); | 233 | pr_info("Zynq clock init\n"); |
| 235 | 234 | ||
| @@ -619,5 +618,4 @@ void __init zynq_clock_init(void) | |||
| 619 | np_err: | 618 | np_err: |
| 620 | of_node_put(np); | 619 | of_node_put(np); |
| 621 | BUG(); | 620 | BUG(); |
| 622 | return; | ||
| 623 | } | 621 | } |
diff --git a/drivers/clk/zynq/pll.c b/drivers/clk/zynq/pll.c index cec97596fe65..00d72fb5c036 100644 --- a/drivers/clk/zynq/pll.c +++ b/drivers/clk/zynq/pll.c | |||
| @@ -211,10 +211,8 @@ struct clk *clk_register_zynq_pll(const char *name, const char *parent, | |||
| 211 | }; | 211 | }; |
| 212 | 212 | ||
| 213 | pll = kmalloc(sizeof(*pll), GFP_KERNEL); | 213 | pll = kmalloc(sizeof(*pll), GFP_KERNEL); |
| 214 | if (!pll) { | 214 | if (!pll) |
| 215 | pr_err("%s: Could not allocate Zynq PLL clk.\n", __func__); | ||
| 216 | return ERR_PTR(-ENOMEM); | 215 | return ERR_PTR(-ENOMEM); |
| 217 | } | ||
| 218 | 216 | ||
| 219 | /* Populate the struct */ | 217 | /* Populate the struct */ |
| 220 | pll->hw.init = &initd; | 218 | pll->hw.init = &initd; |
diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c index 37a480680cd0..7906d4acfe40 100644 --- a/drivers/cpufreq/kirkwood-cpufreq.c +++ b/drivers/cpufreq/kirkwood-cpufreq.c | |||
| @@ -12,7 +12,6 @@ | |||
| 12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| 13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 14 | #include <linux/clk.h> | 14 | #include <linux/clk.h> |
| 15 | #include <linux/clk-provider.h> | ||
| 16 | #include <linux/cpufreq.h> | 15 | #include <linux/cpufreq.h> |
| 17 | #include <linux/of_device.h> | 16 | #include <linux/of_device.h> |
| 18 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
| @@ -39,8 +38,7 @@ static struct priv | |||
| 39 | * - cpu clk | 38 | * - cpu clk |
| 40 | * - ddr clk | 39 | * - ddr clk |
| 41 | * | 40 | * |
| 42 | * The frequencies are set at runtime before registering this * | 41 | * The frequencies are set at runtime before registering this table. |
| 43 | * table. | ||
| 44 | */ | 42 | */ |
| 45 | static struct cpufreq_frequency_table kirkwood_freq_table[] = { | 43 | static struct cpufreq_frequency_table kirkwood_freq_table[] = { |
| 46 | {0, STATE_CPU_FREQ, 0}, /* CPU uses cpuclk */ | 44 | {0, STATE_CPU_FREQ, 0}, /* CPU uses cpuclk */ |
| @@ -50,9 +48,7 @@ static struct cpufreq_frequency_table kirkwood_freq_table[] = { | |||
| 50 | 48 | ||
| 51 | static unsigned int kirkwood_cpufreq_get_cpu_frequency(unsigned int cpu) | 49 | static unsigned int kirkwood_cpufreq_get_cpu_frequency(unsigned int cpu) |
| 52 | { | 50 | { |
| 53 | if (__clk_is_enabled(priv.powersave_clk)) | 51 | return clk_get_rate(priv.powersave_clk) / 1000; |
| 54 | return kirkwood_freq_table[1].frequency; | ||
| 55 | return kirkwood_freq_table[0].frequency; | ||
| 56 | } | 52 | } |
| 57 | 53 | ||
| 58 | static int kirkwood_cpufreq_target(struct cpufreq_policy *policy, | 54 | static int kirkwood_cpufreq_target(struct cpufreq_policy *policy, |
| @@ -70,10 +66,10 @@ static int kirkwood_cpufreq_target(struct cpufreq_policy *policy, | |||
| 70 | 66 | ||
| 71 | switch (state) { | 67 | switch (state) { |
| 72 | case STATE_CPU_FREQ: | 68 | case STATE_CPU_FREQ: |
| 73 | clk_disable(priv.powersave_clk); | 69 | clk_set_parent(priv.powersave_clk, priv.cpu_clk); |
| 74 | break; | 70 | break; |
| 75 | case STATE_DDR_FREQ: | 71 | case STATE_DDR_FREQ: |
| 76 | clk_enable(priv.powersave_clk); | 72 | clk_set_parent(priv.powersave_clk, priv.ddr_clk); |
| 77 | break; | 73 | break; |
| 78 | } | 74 | } |
| 79 | 75 | ||
| @@ -150,7 +146,7 @@ static int kirkwood_cpufreq_probe(struct platform_device *pdev) | |||
| 150 | err = PTR_ERR(priv.powersave_clk); | 146 | err = PTR_ERR(priv.powersave_clk); |
| 151 | goto out_ddr; | 147 | goto out_ddr; |
| 152 | } | 148 | } |
| 153 | clk_prepare(priv.powersave_clk); | 149 | clk_prepare_enable(priv.powersave_clk); |
| 154 | 150 | ||
| 155 | of_node_put(np); | 151 | of_node_put(np); |
| 156 | np = NULL; | 152 | np = NULL; |
diff --git a/include/asm-generic/clkdev.h b/include/asm-generic/clkdev.h index 90a32a61dd21..4ff334749ed5 100644 --- a/include/asm-generic/clkdev.h +++ b/include/asm-generic/clkdev.h | |||
| @@ -15,10 +15,12 @@ | |||
| 15 | 15 | ||
| 16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
| 17 | 17 | ||
| 18 | #ifndef CONFIG_COMMON_CLK | ||
| 18 | struct clk; | 19 | struct clk; |
| 19 | 20 | ||
| 20 | static inline int __clk_get(struct clk *clk) { return 1; } | 21 | static inline int __clk_get(struct clk *clk) { return 1; } |
| 21 | static inline void __clk_put(struct clk *clk) { } | 22 | static inline void __clk_put(struct clk *clk) { } |
| 23 | #endif | ||
| 22 | 24 | ||
| 23 | static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) | 25 | static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) |
| 24 | { | 26 | { |
diff --git a/include/dt-bindings/clock/exynos3250.h b/include/dt-bindings/clock/exynos3250.h index b535e9da7de6..961b9c130ea9 100644 --- a/include/dt-bindings/clock/exynos3250.h +++ b/include/dt-bindings/clock/exynos3250.h | |||
| @@ -255,4 +255,31 @@ | |||
| 255 | */ | 255 | */ |
| 256 | #define CLK_NR_CLKS 248 | 256 | #define CLK_NR_CLKS 248 |
| 257 | 257 | ||
| 258 | /* | ||
| 259 | * CMU DMC | ||
| 260 | */ | ||
| 261 | |||
| 262 | #define CLK_FOUT_BPLL 1 | ||
| 263 | #define CLK_FOUT_EPLL 2 | ||
| 264 | |||
| 265 | /* Muxes */ | ||
| 266 | #define CLK_MOUT_MPLL_MIF 8 | ||
| 267 | #define CLK_MOUT_BPLL 9 | ||
| 268 | #define CLK_MOUT_DPHY 10 | ||
| 269 | #define CLK_MOUT_DMC_BUS 11 | ||
| 270 | #define CLK_MOUT_EPLL 12 | ||
| 271 | |||
| 272 | /* Dividers */ | ||
| 273 | #define CLK_DIV_DMC 16 | ||
| 274 | #define CLK_DIV_DPHY 17 | ||
| 275 | #define CLK_DIV_DMC_PRE 18 | ||
| 276 | #define CLK_DIV_DMCP 19 | ||
| 277 | #define CLK_DIV_DMCD 20 | ||
| 278 | |||
| 279 | /* | ||
| 280 | * Total number of clocks of main CMU. | ||
| 281 | * NOTE: Must be equal to last clock ID increased by one. | ||
| 282 | */ | ||
| 283 | #define NR_CLKS_DMC 21 | ||
| 284 | |||
| 258 | #endif /* _DT_BINDINGS_CLOCK_SAMSUNG_EXYNOS3250_CLOCK_H */ | 285 | #endif /* _DT_BINDINGS_CLOCK_SAMSUNG_EXYNOS3250_CLOCK_H */ |
diff --git a/include/dt-bindings/clock/exynos4.h b/include/dt-bindings/clock/exynos4.h index 459bd2bd411f..34fe28c622d0 100644 --- a/include/dt-bindings/clock/exynos4.h +++ b/include/dt-bindings/clock/exynos4.h | |||
| @@ -115,11 +115,11 @@ | |||
| 115 | #define CLK_SMMU_MFCR 275 | 115 | #define CLK_SMMU_MFCR 275 |
| 116 | #define CLK_G3D 276 | 116 | #define CLK_G3D 276 |
| 117 | #define CLK_G2D 277 | 117 | #define CLK_G2D 277 |
| 118 | #define CLK_ROTATOR 278 /* Exynos4210 only */ | 118 | #define CLK_ROTATOR 278 |
| 119 | #define CLK_MDMA 279 /* Exynos4210 only */ | 119 | #define CLK_MDMA 279 |
| 120 | #define CLK_SMMU_G2D 280 /* Exynos4210 only */ | 120 | #define CLK_SMMU_G2D 280 |
| 121 | #define CLK_SMMU_ROTATOR 281 /* Exynos4210 only */ | 121 | #define CLK_SMMU_ROTATOR 281 |
| 122 | #define CLK_SMMU_MDMA 282 /* Exynos4210 only */ | 122 | #define CLK_SMMU_MDMA 282 |
| 123 | #define CLK_FIMD0 283 | 123 | #define CLK_FIMD0 283 |
| 124 | #define CLK_MIE0 284 | 124 | #define CLK_MIE0 284 |
| 125 | #define CLK_MDNIE0 285 /* Exynos4412 only */ | 125 | #define CLK_MDNIE0 285 /* Exynos4412 only */ |
| @@ -234,6 +234,8 @@ | |||
| 234 | #define CLK_MOUT_G3D1 393 | 234 | #define CLK_MOUT_G3D1 393 |
| 235 | #define CLK_MOUT_G3D 394 | 235 | #define CLK_MOUT_G3D 394 |
| 236 | #define CLK_ACLK400_MCUISP 395 /* Exynos4x12 only */ | 236 | #define CLK_ACLK400_MCUISP 395 /* Exynos4x12 only */ |
| 237 | #define CLK_MOUT_HDMI 396 | ||
| 238 | #define CLK_MOUT_MIXER 397 | ||
| 237 | 239 | ||
| 238 | /* gate clocks - ppmu */ | 240 | /* gate clocks - ppmu */ |
| 239 | #define CLK_PPMULEFT 400 | 241 | #define CLK_PPMULEFT 400 |
diff --git a/include/dt-bindings/clock/hix5hd2-clock.h b/include/dt-bindings/clock/hix5hd2-clock.h index aad579a75802..fd29c174ba63 100644 --- a/include/dt-bindings/clock/hix5hd2-clock.h +++ b/include/dt-bindings/clock/hix5hd2-clock.h | |||
| @@ -46,6 +46,7 @@ | |||
| 46 | #define HIX5HD2_SFC_MUX 64 | 46 | #define HIX5HD2_SFC_MUX 64 |
| 47 | #define HIX5HD2_MMC_MUX 65 | 47 | #define HIX5HD2_MMC_MUX 65 |
| 48 | #define HIX5HD2_FEPHY_MUX 66 | 48 | #define HIX5HD2_FEPHY_MUX 66 |
| 49 | #define HIX5HD2_SD_MUX 67 | ||
| 49 | 50 | ||
| 50 | /* gate clocks */ | 51 | /* gate clocks */ |
| 51 | #define HIX5HD2_SFC_RST 128 | 52 | #define HIX5HD2_SFC_RST 128 |
| @@ -53,6 +54,32 @@ | |||
| 53 | #define HIX5HD2_MMC_CIU_CLK 130 | 54 | #define HIX5HD2_MMC_CIU_CLK 130 |
| 54 | #define HIX5HD2_MMC_BIU_CLK 131 | 55 | #define HIX5HD2_MMC_BIU_CLK 131 |
| 55 | #define HIX5HD2_MMC_CIU_RST 132 | 56 | #define HIX5HD2_MMC_CIU_RST 132 |
| 57 | #define HIX5HD2_FWD_BUS_CLK 133 | ||
| 58 | #define HIX5HD2_FWD_SYS_CLK 134 | ||
| 59 | #define HIX5HD2_MAC0_PHY_CLK 135 | ||
| 60 | #define HIX5HD2_SD_CIU_CLK 136 | ||
| 61 | #define HIX5HD2_SD_BIU_CLK 137 | ||
| 62 | #define HIX5HD2_SD_CIU_RST 138 | ||
| 63 | #define HIX5HD2_WDG0_CLK 139 | ||
| 64 | #define HIX5HD2_WDG0_RST 140 | ||
| 65 | #define HIX5HD2_I2C0_CLK 141 | ||
| 66 | #define HIX5HD2_I2C0_RST 142 | ||
| 67 | #define HIX5HD2_I2C1_CLK 143 | ||
| 68 | #define HIX5HD2_I2C1_RST 144 | ||
| 69 | #define HIX5HD2_I2C2_CLK 145 | ||
| 70 | #define HIX5HD2_I2C2_RST 146 | ||
| 71 | #define HIX5HD2_I2C3_CLK 147 | ||
| 72 | #define HIX5HD2_I2C3_RST 148 | ||
| 73 | #define HIX5HD2_I2C4_CLK 149 | ||
| 74 | #define HIX5HD2_I2C4_RST 150 | ||
| 75 | #define HIX5HD2_I2C5_CLK 151 | ||
| 76 | #define HIX5HD2_I2C5_RST 152 | ||
| 77 | |||
| 78 | /* complex */ | ||
| 79 | #define HIX5HD2_MAC0_CLK 192 | ||
| 80 | #define HIX5HD2_MAC1_CLK 193 | ||
| 81 | #define HIX5HD2_SATA_CLK 194 | ||
| 82 | #define HIX5HD2_USB_CLK 195 | ||
| 56 | 83 | ||
| 57 | #define HIX5HD2_NR_CLKS 256 | 84 | #define HIX5HD2_NR_CLKS 256 |
| 58 | #endif /* __DTS_HIX5HD2_CLOCK_H */ | 85 | #endif /* __DTS_HIX5HD2_CLOCK_H */ |
diff --git a/include/dt-bindings/clock/maxim,max77686.h b/include/dt-bindings/clock/maxim,max77686.h new file mode 100644 index 000000000000..7b28b0905869 --- /dev/null +++ b/include/dt-bindings/clock/maxim,max77686.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2014 Google, Inc | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * Device Tree binding constants clocks for the Maxim 77686 PMIC. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef _DT_BINDINGS_CLOCK_MAXIM_MAX77686_CLOCK_H | ||
| 12 | #define _DT_BINDINGS_CLOCK_MAXIM_MAX77686_CLOCK_H | ||
| 13 | |||
| 14 | /* Fixed rate clocks. */ | ||
| 15 | |||
| 16 | #define MAX77686_CLK_AP 0 | ||
| 17 | #define MAX77686_CLK_CP 1 | ||
| 18 | #define MAX77686_CLK_PMIC 2 | ||
| 19 | |||
| 20 | /* Total number of clocks. */ | ||
| 21 | #define MAX77686_CLKS_NUM (MAX77686_CLK_PMIC + 1) | ||
| 22 | |||
| 23 | #endif /* _DT_BINDINGS_CLOCK_MAXIM_MAX77686_CLOCK_H */ | ||
diff --git a/include/dt-bindings/clock/maxim,max77802.h b/include/dt-bindings/clock/maxim,max77802.h new file mode 100644 index 000000000000..997312edcbb5 --- /dev/null +++ b/include/dt-bindings/clock/maxim,max77802.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2014 Google, Inc | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * Device Tree binding constants clocks for the Maxim 77802 PMIC. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H | ||
| 12 | #define _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H | ||
| 13 | |||
| 14 | /* Fixed rate clocks. */ | ||
| 15 | |||
| 16 | #define MAX77802_CLK_32K_AP 0 | ||
| 17 | #define MAX77802_CLK_32K_CP 1 | ||
| 18 | |||
| 19 | /* Total number of clocks. */ | ||
| 20 | #define MAX77802_CLKS_NUM (MAX77802_CLK_32K_CP + 1) | ||
| 21 | |||
| 22 | #endif /* _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H */ | ||
diff --git a/include/dt-bindings/clock/pxa-clock.h b/include/dt-bindings/clock/pxa-clock.h new file mode 100644 index 000000000000..e65803b1dc7e --- /dev/null +++ b/include/dt-bindings/clock/pxa-clock.h | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | /* | ||
| 2 | * Inspired by original work from pxa2xx-regs.h by Nicolas Pitre | ||
| 3 | * Copyright (C) 2014 Robert Jarzmik | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef __DT_BINDINGS_CLOCK_PXA2XX_H__ | ||
| 12 | #define __DT_BINDINGS_CLOCK_PXA2XX_H__ | ||
| 13 | |||
| 14 | #define CLK_NONE 0 | ||
| 15 | #define CLK_1WIRE 1 | ||
| 16 | #define CLK_AC97 2 | ||
| 17 | #define CLK_AC97CONF 3 | ||
| 18 | #define CLK_ASSP 4 | ||
| 19 | #define CLK_BOOT 5 | ||
| 20 | #define CLK_BTUART 6 | ||
| 21 | #define CLK_CAMERA 7 | ||
| 22 | #define CLK_CIR 8 | ||
| 23 | #define CLK_CORE 9 | ||
| 24 | #define CLK_DMC 10 | ||
| 25 | #define CLK_FFUART 11 | ||
| 26 | #define CLK_FICP 12 | ||
| 27 | #define CLK_GPIO 13 | ||
| 28 | #define CLK_HSIO2 14 | ||
| 29 | #define CLK_HWUART 15 | ||
| 30 | #define CLK_I2C 16 | ||
| 31 | #define CLK_I2S 17 | ||
| 32 | #define CLK_IM 18 | ||
| 33 | #define CLK_INC 19 | ||
| 34 | #define CLK_ISC 20 | ||
| 35 | #define CLK_KEYPAD 21 | ||
| 36 | #define CLK_LCD 22 | ||
| 37 | #define CLK_MEMC 23 | ||
| 38 | #define CLK_MEMSTK 24 | ||
| 39 | #define CLK_MINI_IM 25 | ||
| 40 | #define CLK_MINI_LCD 26 | ||
| 41 | #define CLK_MMC 27 | ||
| 42 | #define CLK_MMC1 28 | ||
| 43 | #define CLK_MMC2 29 | ||
| 44 | #define CLK_MMC3 30 | ||
| 45 | #define CLK_MSL 31 | ||
| 46 | #define CLK_MSL0 32 | ||
| 47 | #define CLK_MVED 33 | ||
| 48 | #define CLK_NAND 34 | ||
| 49 | #define CLK_NSSP 35 | ||
| 50 | #define CLK_OSTIMER 36 | ||
| 51 | #define CLK_PWM0 37 | ||
| 52 | #define CLK_PWM1 38 | ||
| 53 | #define CLK_PWM2 39 | ||
| 54 | #define CLK_PWM3 40 | ||
| 55 | #define CLK_PWRI2C 41 | ||
| 56 | #define CLK_PXA300_GCU 42 | ||
| 57 | #define CLK_PXA320_GCU 43 | ||
| 58 | #define CLK_SMC 44 | ||
| 59 | #define CLK_SSP 45 | ||
| 60 | #define CLK_SSP1 46 | ||
| 61 | #define CLK_SSP2 47 | ||
| 62 | #define CLK_SSP3 48 | ||
| 63 | #define CLK_SSP4 49 | ||
| 64 | #define CLK_STUART 50 | ||
| 65 | #define CLK_TOUCH 51 | ||
| 66 | #define CLK_TPM 52 | ||
| 67 | #define CLK_UDC 53 | ||
| 68 | #define CLK_USB 54 | ||
| 69 | #define CLK_USB2 55 | ||
| 70 | #define CLK_USBH 56 | ||
| 71 | #define CLK_USBHOST 57 | ||
| 72 | #define CLK_USIM 58 | ||
| 73 | #define CLK_USIM1 59 | ||
| 74 | #define CLK_USMI0 60 | ||
| 75 | #define CLK_MAX 61 | ||
| 76 | |||
| 77 | #endif | ||
diff --git a/include/dt-bindings/clock/rk3188-cru-common.h b/include/dt-bindings/clock/rk3188-cru-common.h index 750ee60e75fb..6a370503c954 100644 --- a/include/dt-bindings/clock/rk3188-cru-common.h +++ b/include/dt-bindings/clock/rk3188-cru-common.h | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #define PLL_GPLL 4 | 20 | #define PLL_GPLL 4 |
| 21 | #define CORE_PERI 5 | 21 | #define CORE_PERI 5 |
| 22 | #define CORE_L2C 6 | 22 | #define CORE_L2C 6 |
| 23 | #define ARMCLK 7 | ||
| 23 | 24 | ||
| 24 | /* sclk gates (special clocks) */ | 25 | /* sclk gates (special clocks) */ |
| 25 | #define SCLK_UART0 64 | 26 | #define SCLK_UART0 64 |
diff --git a/include/dt-bindings/clock/rk3288-cru.h b/include/dt-bindings/clock/rk3288-cru.h index ebcb460ea4ad..100a08c47692 100644 --- a/include/dt-bindings/clock/rk3288-cru.h +++ b/include/dt-bindings/clock/rk3288-cru.h | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #define PLL_CPLL 3 | 19 | #define PLL_CPLL 3 |
| 20 | #define PLL_GPLL 4 | 20 | #define PLL_GPLL 4 |
| 21 | #define PLL_NPLL 5 | 21 | #define PLL_NPLL 5 |
| 22 | #define ARMCLK 6 | ||
| 22 | 23 | ||
| 23 | /* sclk gates (special clocks) */ | 24 | /* sclk gates (special clocks) */ |
| 24 | #define SCLK_GPU 64 | 25 | #define SCLK_GPU 64 |
| @@ -61,6 +62,15 @@ | |||
| 61 | #define SCLK_LCDC_PWM1 101 | 62 | #define SCLK_LCDC_PWM1 101 |
| 62 | #define SCLK_MAC_RX 102 | 63 | #define SCLK_MAC_RX 102 |
| 63 | #define SCLK_MAC_TX 103 | 64 | #define SCLK_MAC_TX 103 |
| 65 | #define SCLK_EDP_24M 104 | ||
| 66 | #define SCLK_EDP 105 | ||
| 67 | #define SCLK_RGA 106 | ||
| 68 | #define SCLK_ISP 107 | ||
| 69 | #define SCLK_ISP_JPE 108 | ||
| 70 | #define SCLK_HDMI_HDCP 109 | ||
| 71 | #define SCLK_HDMI_CEC 110 | ||
| 72 | #define SCLK_HEVC_CABAC 111 | ||
| 73 | #define SCLK_HEVC_CORE 112 | ||
| 64 | 74 | ||
| 65 | #define DCLK_VOP0 190 | 75 | #define DCLK_VOP0 190 |
| 66 | #define DCLK_VOP1 191 | 76 | #define DCLK_VOP1 191 |
| @@ -75,6 +85,16 @@ | |||
| 75 | #define ACLK_VOP1 198 | 85 | #define ACLK_VOP1 198 |
| 76 | #define ACLK_CRYPTO 199 | 86 | #define ACLK_CRYPTO 199 |
| 77 | #define ACLK_RGA 200 | 87 | #define ACLK_RGA 200 |
| 88 | #define ACLK_RGA_NIU 201 | ||
| 89 | #define ACLK_IEP 202 | ||
| 90 | #define ACLK_VIO0_NIU 203 | ||
| 91 | #define ACLK_VIP 204 | ||
| 92 | #define ACLK_ISP 205 | ||
| 93 | #define ACLK_VIO1_NIU 206 | ||
| 94 | #define ACLK_HEVC 207 | ||
| 95 | #define ACLK_VCODEC 208 | ||
| 96 | #define ACLK_CPU 209 | ||
| 97 | #define ACLK_PERI 210 | ||
| 78 | 98 | ||
| 79 | /* pclk gates */ | 99 | /* pclk gates */ |
| 80 | #define PCLK_GPIO0 320 | 100 | #define PCLK_GPIO0 320 |
| @@ -112,6 +132,15 @@ | |||
| 112 | #define PCLK_PS2C 352 | 132 | #define PCLK_PS2C 352 |
| 113 | #define PCLK_TIMER 353 | 133 | #define PCLK_TIMER 353 |
| 114 | #define PCLK_TZPC 354 | 134 | #define PCLK_TZPC 354 |
| 135 | #define PCLK_EDP_CTRL 355 | ||
| 136 | #define PCLK_MIPI_DSI0 356 | ||
| 137 | #define PCLK_MIPI_DSI1 357 | ||
| 138 | #define PCLK_MIPI_CSI 358 | ||
| 139 | #define PCLK_LVDS_PHY 359 | ||
| 140 | #define PCLK_HDMI_CTRL 360 | ||
| 141 | #define PCLK_VIO2_H2P 361 | ||
| 142 | #define PCLK_CPU 362 | ||
| 143 | #define PCLK_PERI 363 | ||
| 115 | 144 | ||
| 116 | /* hclk gates */ | 145 | /* hclk gates */ |
| 117 | #define HCLK_GPS 448 | 146 | #define HCLK_GPS 448 |
| @@ -137,8 +166,16 @@ | |||
| 137 | #define HCLK_IEP 468 | 166 | #define HCLK_IEP 468 |
| 138 | #define HCLK_ISP 469 | 167 | #define HCLK_ISP 469 |
| 139 | #define HCLK_RGA 470 | 168 | #define HCLK_RGA 470 |
| 169 | #define HCLK_VIO_AHB_ARBI 471 | ||
| 170 | #define HCLK_VIO_NIU 472 | ||
| 171 | #define HCLK_VIP 473 | ||
| 172 | #define HCLK_VIO2_H2P 474 | ||
| 173 | #define HCLK_HEVC 475 | ||
| 174 | #define HCLK_VCODEC 476 | ||
| 175 | #define HCLK_CPU 477 | ||
| 176 | #define HCLK_PERI 478 | ||
| 140 | 177 | ||
| 141 | #define CLK_NR_CLKS (HCLK_RGA + 1) | 178 | #define CLK_NR_CLKS (HCLK_PERI + 1) |
| 142 | 179 | ||
| 143 | /* soft-reset indices */ | 180 | /* soft-reset indices */ |
| 144 | #define SRST_CORE0 0 | 181 | #define SRST_CORE0 0 |
| @@ -276,3 +313,46 @@ | |||
| 276 | #define SRST_USBHOST1_CON 140 | 313 | #define SRST_USBHOST1_CON 140 |
| 277 | #define SRST_USB_ADP 141 | 314 | #define SRST_USB_ADP 141 |
| 278 | #define SRST_ACC_EFUSE 142 | 315 | #define SRST_ACC_EFUSE 142 |
| 316 | |||
| 317 | #define SRST_CORESIGHT 144 | ||
| 318 | #define SRST_PD_CORE_AHB_NOC 145 | ||
| 319 | #define SRST_PD_CORE_APB_NOC 146 | ||
| 320 | #define SRST_PD_CORE_MP_AXI 147 | ||
| 321 | #define SRST_GIC 148 | ||
| 322 | #define SRST_LCDC_PWM0 149 | ||
| 323 | #define SRST_LCDC_PWM1 150 | ||
| 324 | #define SRST_VIO0_H2P_BRG 151 | ||
| 325 | #define SRST_VIO1_H2P_BRG 152 | ||
| 326 | #define SRST_RGA_H2P_BRG 153 | ||
| 327 | #define SRST_HEVC 154 | ||
| 328 | #define SRST_TSADC 159 | ||
| 329 | |||
| 330 | #define SRST_DDRPHY0 160 | ||
| 331 | #define SRST_DDRPHY0_APB 161 | ||
| 332 | #define SRST_DDRCTRL0 162 | ||
| 333 | #define SRST_DDRCTRL0_APB 163 | ||
| 334 | #define SRST_DDRPHY0_CTRL 164 | ||
| 335 | #define SRST_DDRPHY1 165 | ||
| 336 | #define SRST_DDRPHY1_APB 166 | ||
| 337 | #define SRST_DDRCTRL1 167 | ||
| 338 | #define SRST_DDRCTRL1_APB 168 | ||
| 339 | #define SRST_DDRPHY1_CTRL 169 | ||
| 340 | #define SRST_DDRMSCH0 170 | ||
| 341 | #define SRST_DDRMSCH1 171 | ||
| 342 | #define SRST_CRYPTO 174 | ||
| 343 | #define SRST_C2C_HOST 175 | ||
| 344 | |||
| 345 | #define SRST_LCDC1_AXI 176 | ||
| 346 | #define SRST_LCDC1_AHB 177 | ||
| 347 | #define SRST_LCDC1_DCLK 178 | ||
| 348 | #define SRST_UART0 179 | ||
| 349 | #define SRST_UART1 180 | ||
| 350 | #define SRST_UART2 181 | ||
| 351 | #define SRST_UART3 182 | ||
| 352 | #define SRST_UART4 183 | ||
| 353 | #define SRST_SIMC 186 | ||
| 354 | #define SRST_PS2C 187 | ||
| 355 | #define SRST_TSP 188 | ||
| 356 | #define SRST_TSP_CLKIN0 189 | ||
| 357 | #define SRST_TSP_CLKIN1 190 | ||
| 358 | #define SRST_TSP_27M 191 | ||
diff --git a/include/dt-bindings/clock/tegra124-car.h b/include/dt-bindings/clock/tegra124-car.h index 8a4c5892890f..6bac637fd635 100644 --- a/include/dt-bindings/clock/tegra124-car.h +++ b/include/dt-bindings/clock/tegra124-car.h | |||
| @@ -337,6 +337,10 @@ | |||
| 337 | #define TEGRA124_CLK_DSIB_MUX 310 | 337 | #define TEGRA124_CLK_DSIB_MUX 310 |
| 338 | #define TEGRA124_CLK_SOR0_LVDS 311 | 338 | #define TEGRA124_CLK_SOR0_LVDS 311 |
| 339 | #define TEGRA124_CLK_XUSB_SS_DIV2 312 | 339 | #define TEGRA124_CLK_XUSB_SS_DIV2 312 |
| 340 | #define TEGRA124_CLK_CLK_MAX 313 | 340 | |
| 341 | #define TEGRA124_CLK_PLL_M_UD 313 | ||
| 342 | #define TEGRA124_CLK_PLL_C_UD 314 | ||
| 343 | |||
| 344 | #define TEGRA124_CLK_CLK_MAX 315 | ||
| 341 | 345 | ||
| 342 | #endif /* _DT_BINDINGS_CLOCK_TEGRA124_CAR_H */ | 346 | #endif /* _DT_BINDINGS_CLOCK_TEGRA124_CAR_H */ |
diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index efbf70b9fd84..0ca5f6046920 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h | |||
| @@ -46,8 +46,10 @@ struct clk { | |||
| 46 | unsigned int enable_count; | 46 | unsigned int enable_count; |
| 47 | unsigned int prepare_count; | 47 | unsigned int prepare_count; |
| 48 | unsigned long accuracy; | 48 | unsigned long accuracy; |
| 49 | int phase; | ||
| 49 | struct hlist_head children; | 50 | struct hlist_head children; |
| 50 | struct hlist_node child_node; | 51 | struct hlist_node child_node; |
| 52 | struct hlist_node debug_node; | ||
| 51 | unsigned int notifier_count; | 53 | unsigned int notifier_count; |
| 52 | #ifdef CONFIG_DEBUG_FS | 54 | #ifdef CONFIG_DEBUG_FS |
| 53 | struct dentry *dentry; | 55 | struct dentry *dentry; |
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 411dd7eb2653..be21af149f11 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | #include <linux/clk.h> | 14 | #include <linux/clk.h> |
| 15 | #include <linux/io.h> | 15 | #include <linux/io.h> |
| 16 | #include <linux/of.h> | ||
| 16 | 17 | ||
| 17 | #ifdef CONFIG_COMMON_CLK | 18 | #ifdef CONFIG_COMMON_CLK |
| 18 | 19 | ||
| @@ -129,6 +130,14 @@ struct dentry; | |||
| 129 | * set then clock accuracy will be initialized to parent accuracy | 130 | * set then clock accuracy will be initialized to parent accuracy |
| 130 | * or 0 (perfect clock) if clock has no parent. | 131 | * or 0 (perfect clock) if clock has no parent. |
| 131 | * | 132 | * |
| 133 | * @get_phase: Queries the hardware to get the current phase of a clock. | ||
| 134 | * Returned values are 0-359 degrees on success, negative | ||
| 135 | * error codes on failure. | ||
| 136 | * | ||
| 137 | * @set_phase: Shift the phase this clock signal in degrees specified | ||
| 138 | * by the second argument. Valid values for degrees are | ||
| 139 | * 0-359. Return 0 on success, otherwise -EERROR. | ||
| 140 | * | ||
| 132 | * @init: Perform platform-specific initialization magic. | 141 | * @init: Perform platform-specific initialization magic. |
| 133 | * This is not not used by any of the basic clock types. | 142 | * This is not not used by any of the basic clock types. |
| 134 | * Please consider other ways of solving initialization problems | 143 | * Please consider other ways of solving initialization problems |
| @@ -177,6 +186,8 @@ struct clk_ops { | |||
| 177 | unsigned long parent_rate, u8 index); | 186 | unsigned long parent_rate, u8 index); |
| 178 | unsigned long (*recalc_accuracy)(struct clk_hw *hw, | 187 | unsigned long (*recalc_accuracy)(struct clk_hw *hw, |
| 179 | unsigned long parent_accuracy); | 188 | unsigned long parent_accuracy); |
| 189 | int (*get_phase)(struct clk_hw *hw); | ||
| 190 | int (*set_phase)(struct clk_hw *hw, int degrees); | ||
| 180 | void (*init)(struct clk_hw *hw); | 191 | void (*init)(struct clk_hw *hw); |
| 181 | int (*debug_init)(struct clk_hw *hw, struct dentry *dentry); | 192 | int (*debug_init)(struct clk_hw *hw, struct dentry *dentry); |
| 182 | }; | 193 | }; |
| @@ -488,6 +499,28 @@ struct clk *clk_register_composite(struct device *dev, const char *name, | |||
| 488 | struct clk_hw *gate_hw, const struct clk_ops *gate_ops, | 499 | struct clk_hw *gate_hw, const struct clk_ops *gate_ops, |
| 489 | unsigned long flags); | 500 | unsigned long flags); |
| 490 | 501 | ||
| 502 | /*** | ||
| 503 | * struct clk_gpio_gate - gpio gated clock | ||
| 504 | * | ||
| 505 | * @hw: handle between common and hardware-specific interfaces | ||
| 506 | * @gpiod: gpio descriptor | ||
| 507 | * | ||
| 508 | * Clock with a gpio control for enabling and disabling the parent clock. | ||
| 509 | * Implements .enable, .disable and .is_enabled | ||
| 510 | */ | ||
| 511 | |||
| 512 | struct clk_gpio { | ||
| 513 | struct clk_hw hw; | ||
| 514 | struct gpio_desc *gpiod; | ||
| 515 | }; | ||
| 516 | |||
| 517 | extern const struct clk_ops clk_gpio_gate_ops; | ||
| 518 | struct clk *clk_register_gpio_gate(struct device *dev, const char *name, | ||
| 519 | const char *parent_name, struct gpio_desc *gpio, | ||
| 520 | unsigned long flags); | ||
| 521 | |||
| 522 | void of_gpio_clk_gate_setup(struct device_node *node); | ||
| 523 | |||
| 491 | /** | 524 | /** |
| 492 | * clk_register - allocate a new clock, register it and return an opaque cookie | 525 | * clk_register - allocate a new clock, register it and return an opaque cookie |
| 493 | * @dev: device that is registering this clock | 526 | * @dev: device that is registering this clock |
diff --git a/include/linux/clk.h b/include/linux/clk.h index afb44bfaf8d1..c7f258a81761 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h | |||
| @@ -106,6 +106,25 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb); | |||
| 106 | */ | 106 | */ |
| 107 | long clk_get_accuracy(struct clk *clk); | 107 | long clk_get_accuracy(struct clk *clk); |
| 108 | 108 | ||
| 109 | /** | ||
| 110 | * clk_set_phase - adjust the phase shift of a clock signal | ||
| 111 | * @clk: clock signal source | ||
| 112 | * @degrees: number of degrees the signal is shifted | ||
| 113 | * | ||
| 114 | * Shifts the phase of a clock signal by the specified degrees. Returns 0 on | ||
| 115 | * success, -EERROR otherwise. | ||
| 116 | */ | ||
| 117 | int clk_set_phase(struct clk *clk, int degrees); | ||
| 118 | |||
| 119 | /** | ||
| 120 | * clk_get_phase - return the phase shift of a clock signal | ||
| 121 | * @clk: clock signal source | ||
| 122 | * | ||
| 123 | * Returns the phase shift of a clock node in degrees, otherwise returns | ||
| 124 | * -EERROR. | ||
| 125 | */ | ||
| 126 | int clk_get_phase(struct clk *clk); | ||
| 127 | |||
| 109 | #else | 128 | #else |
| 110 | 129 | ||
| 111 | static inline long clk_get_accuracy(struct clk *clk) | 130 | static inline long clk_get_accuracy(struct clk *clk) |
| @@ -113,6 +132,16 @@ static inline long clk_get_accuracy(struct clk *clk) | |||
| 113 | return -ENOTSUPP; | 132 | return -ENOTSUPP; |
| 114 | } | 133 | } |
| 115 | 134 | ||
| 135 | static inline long clk_set_phase(struct clk *clk, int phase) | ||
| 136 | { | ||
| 137 | return -ENOTSUPP; | ||
| 138 | } | ||
| 139 | |||
| 140 | static inline long clk_get_phase(struct clk *clk) | ||
| 141 | { | ||
| 142 | return -ENOTSUPP; | ||
| 143 | } | ||
| 144 | |||
| 116 | #endif | 145 | #endif |
| 117 | 146 | ||
| 118 | /** | 147 | /** |
diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index e8d8a35034a5..f75acbf70e96 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h | |||
| @@ -292,6 +292,7 @@ void omap2xxx_clkt_vps_init(void); | |||
| 292 | void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index); | 292 | void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index); |
| 293 | void ti_dt_clocks_register(struct ti_dt_clk *oclks); | 293 | void ti_dt_clocks_register(struct ti_dt_clk *oclks); |
| 294 | void ti_dt_clk_init_provider(struct device_node *np, int index); | 294 | void ti_dt_clk_init_provider(struct device_node *np, int index); |
| 295 | void ti_dt_clk_init_retry_clks(void); | ||
| 295 | void ti_dt_clockdomains_setup(void); | 296 | void ti_dt_clockdomains_setup(void); |
| 296 | int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, | 297 | int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, |
| 297 | ti_of_clk_init_cb_t func); | 298 | ti_of_clk_init_cb_t func); |
