mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 22:21:42 +00:00
Merge branch 'clk-next' into v3.19-rc7
This commit is contained in:
commit
54eea32f7e
@ -73,6 +73,8 @@ the operations defined in clk.h:
|
||||
unsigned long *parent_rate);
|
||||
long (*determine_rate)(struct clk_hw *hw,
|
||||
unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_clk);
|
||||
int (*set_parent)(struct clk_hw *hw, u8 index);
|
||||
|
@ -34,6 +34,8 @@ Required Properties for Clock Controller:
|
||||
- "samsung,exynos7-clock-peris"
|
||||
- "samsung,exynos7-clock-fsys0"
|
||||
- "samsung,exynos7-clock-fsys1"
|
||||
- "samsung,exynos7-clock-mscl"
|
||||
- "samsung,exynos7-clock-aud"
|
||||
|
||||
- reg: physical base address of the controller and the length of
|
||||
memory mapped region.
|
||||
@ -53,6 +55,7 @@ Input clocks for top0 clock controller:
|
||||
- dout_sclk_bus1_pll
|
||||
- dout_sclk_cc_pll
|
||||
- dout_sclk_mfc_pll
|
||||
- dout_sclk_aud_pll
|
||||
|
||||
Input clocks for top1 clock controller:
|
||||
- fin_pll
|
||||
@ -76,6 +79,14 @@ Input clocks for peric1 clock controller:
|
||||
- sclk_uart1
|
||||
- sclk_uart2
|
||||
- sclk_uart3
|
||||
- sclk_spi0
|
||||
- sclk_spi1
|
||||
- sclk_spi2
|
||||
- sclk_spi3
|
||||
- sclk_spi4
|
||||
- sclk_i2s1
|
||||
- sclk_pcm1
|
||||
- sclk_spdif
|
||||
|
||||
Input clocks for peris clock controller:
|
||||
- fin_pll
|
||||
@ -91,3 +102,7 @@ Input clocks for fsys1 clock controller:
|
||||
- dout_aclk_fsys1_200
|
||||
- dout_sclk_mmc0
|
||||
- dout_sclk_mmc1
|
||||
|
||||
Input clocks for aud clock controller:
|
||||
- fin_pll
|
||||
- fout_aud_pll
|
||||
|
21
Documentation/devicetree/bindings/clock/qcom,lcc.txt
Normal file
21
Documentation/devicetree/bindings/clock/qcom,lcc.txt
Normal file
@ -0,0 +1,21 @@
|
||||
Qualcomm LPASS Clock & Reset Controller Binding
|
||||
------------------------------------------------
|
||||
|
||||
Required properties :
|
||||
- compatible : shall contain only one of the following:
|
||||
|
||||
"qcom,lcc-msm8960"
|
||||
"qcom,lcc-apq8064"
|
||||
"qcom,lcc-ipq8064"
|
||||
|
||||
- reg : shall contain base register location and length
|
||||
- #clock-cells : shall contain 1
|
||||
- #reset-cells : shall contain 1
|
||||
|
||||
Example:
|
||||
clock-controller@28000000 {
|
||||
compatible = "qcom,lcc-ipq8064";
|
||||
reg = <0x28000000 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
@ -1,6 +1,6 @@
|
||||
* Clock Block on Freescale CoreNet Platforms
|
||||
* Clock Block on Freescale QorIQ Platforms
|
||||
|
||||
Freescale CoreNet chips take primary clocking input from the external
|
||||
Freescale qoriq chips take primary clocking input from the external
|
||||
SYSCLK signal. The SYSCLK input (frequency) is multiplied using
|
||||
multiple phase locked loops (PLL) to create a variety of frequencies
|
||||
which can then be passed to a variety of internal logic, including
|
||||
@ -29,6 +29,7 @@ Required properties:
|
||||
* "fsl,t4240-clockgen"
|
||||
* "fsl,b4420-clockgen"
|
||||
* "fsl,b4860-clockgen"
|
||||
* "fsl,ls1021a-clockgen"
|
||||
Chassis clock strings include:
|
||||
* "fsl,qoriq-clockgen-1.0": for chassis 1.0 clocks
|
||||
* "fsl,qoriq-clockgen-2.0": for chassis 2.0 clocks
|
||||
|
@ -11,6 +11,7 @@ Required Properties:
|
||||
|
||||
- compatible: Must be one of the following
|
||||
- "renesas,r7s72100-mstp-clocks" for R7S72100 (RZ) MSTP gate clocks
|
||||
- "renesas,r8a73a4-mstp-clocks" for R8A73A4 (R-Mobile APE6) MSTP gate clocks
|
||||
- "renesas,r8a7740-mstp-clocks" for R8A7740 (R-Mobile A1) MSTP gate clocks
|
||||
- "renesas,r8a7779-mstp-clocks" for R8A7779 (R-Car H1) MSTP gate clocks
|
||||
- "renesas,r8a7790-mstp-clocks" for R8A7790 (R-Car H2) MSTP gate clocks
|
||||
|
@ -0,0 +1,33 @@
|
||||
* Renesas R8A73A4 Clock Pulse Generator (CPG)
|
||||
|
||||
The CPG generates core clocks for the R8A73A4 SoC. It includes five PLLs
|
||||
and several fixed ratio dividers.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: Must be "renesas,r8a73a4-cpg-clocks"
|
||||
|
||||
- reg: Base address and length of the memory resource used by the CPG
|
||||
|
||||
- clocks: Reference to the parent clocks ("extal1" and "extal2")
|
||||
|
||||
- #clock-cells: Must be 1
|
||||
|
||||
- clock-output-names: The names of the clocks. Supported clocks are "main",
|
||||
"pll0", "pll1", "pll2", "pll2s", "pll2h", "z", "z2", "i", "m3", "b",
|
||||
"m1", "m2", "zx", "zs", and "hp".
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
cpg_clocks: cpg_clocks@e6150000 {
|
||||
compatible = "renesas,r8a73a4-cpg-clocks";
|
||||
reg = <0 0xe6150000 0 0x10000>;
|
||||
clocks = <&extal1_clk>, <&extal2_clk>;
|
||||
#clock-cells = <1>;
|
||||
clock-output-names = "main", "pll0", "pll1", "pll2",
|
||||
"pll2s", "pll2h", "z", "z2",
|
||||
"i", "m3", "b", "m1", "m2",
|
||||
"zx", "zs", "hp";
|
||||
};
|
@ -8,15 +8,18 @@ Required Properties:
|
||||
- compatible: Must be one of
|
||||
- "renesas,r8a7790-cpg-clocks" for the r8a7790 CPG
|
||||
- "renesas,r8a7791-cpg-clocks" for the r8a7791 CPG
|
||||
- "renesas,r8a7793-cpg-clocks" for the r8a7793 CPG
|
||||
- "renesas,r8a7794-cpg-clocks" for the r8a7794 CPG
|
||||
- "renesas,rcar-gen2-cpg-clocks" for the generic R-Car Gen2 CPG
|
||||
|
||||
- reg: Base address and length of the memory resource used by the CPG
|
||||
|
||||
- clocks: Reference to the parent clock
|
||||
- clocks: References to the parent clocks: first to the EXTAL clock, second
|
||||
to the USB_EXTAL clock
|
||||
- #clock-cells: Must be 1
|
||||
- clock-output-names: The names of the clocks. Supported clocks are "main",
|
||||
"pll0", "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "sd1" and "z"
|
||||
"pll0", "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "sd1", "z", "rcan", and
|
||||
"adsp"
|
||||
|
||||
|
||||
Example
|
||||
@ -26,8 +29,9 @@ Example
|
||||
compatible = "renesas,r8a7790-cpg-clocks",
|
||||
"renesas,rcar-gen2-cpg-clocks";
|
||||
reg = <0 0xe6150000 0 0x1000>;
|
||||
clocks = <&extal_clk>;
|
||||
clocks = <&extal_clk &usb_extal_clk>;
|
||||
#clock-cells = <1>;
|
||||
clock-output-names = "main", "pll0, "pll1", "pll3",
|
||||
"lb", "qspi", "sdh", "sd0", "sd1", "z";
|
||||
"lb", "qspi", "sdh", "sd0", "sd1", "z",
|
||||
"rcan", "adsp";
|
||||
};
|
||||
|
@ -26,7 +26,7 @@ Required properties:
|
||||
"allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s
|
||||
"allwinner,sun7i-a20-ahb-gates-clk" - for the AHB gates on A20
|
||||
"allwinner,sun6i-a31-ar100-clk" - for the AR100 on A31
|
||||
"allwinner,sun6i-a31-ahb1-mux-clk" - for the AHB1 multiplexer on A31
|
||||
"allwinner,sun6i-a31-ahb1-clk" - for the AHB1 clock on A31
|
||||
"allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
|
||||
"allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23
|
||||
"allwinner,sun9i-a80-ahb0-gates-clk" - for the AHB0 gates on A80
|
||||
@ -55,9 +55,11 @@ Required properties:
|
||||
"allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
|
||||
"allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
|
||||
"allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13
|
||||
"allwinner,sun4i-a10-mmc-output-clk" - for the MMC output clock on A10
|
||||
"allwinner,sun4i-a10-mmc-sample-clk" - for the MMC sample clock on A10
|
||||
"allwinner,sun4i-a10-mmc-clk" - for the MMC clock
|
||||
"allwinner,sun9i-a80-mmc-clk" - for mmc module clocks on A80
|
||||
"allwinner,sun9i-a80-mmc-config-clk" - for mmc gates + resets on A80
|
||||
"allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
|
||||
"allwinner,sun9i-a80-mod0-clk" - for module 0 (storage) clocks on A80
|
||||
"allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23
|
||||
"allwinner,sun7i-a20-out-clk" - for the external output clocks
|
||||
"allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
|
||||
@ -73,7 +75,9 @@ Required properties for all clocks:
|
||||
- #clock-cells : from common clock binding; shall be set to 0 except for
|
||||
the following compatibles where it shall be set to 1:
|
||||
"allwinner,*-gates-clk", "allwinner,sun4i-pll5-clk",
|
||||
"allwinner,sun4i-pll6-clk", "allwinner,sun6i-a31-pll6-clk"
|
||||
"allwinner,sun4i-pll6-clk", "allwinner,sun6i-a31-pll6-clk",
|
||||
"allwinner,*-usb-clk", "allwinner,*-mmc-clk",
|
||||
"allwinner,*-mmc-config-clk"
|
||||
- clock-output-names : shall be the corresponding names of the outputs.
|
||||
If the clock module only has one output, the name shall be the
|
||||
module name.
|
||||
@ -81,6 +85,10 @@ Required properties for all clocks:
|
||||
And "allwinner,*-usb-clk" clocks also require:
|
||||
- reset-cells : shall be set to 1
|
||||
|
||||
The "allwinner,sun9i-a80-mmc-config-clk" clock also requires:
|
||||
- #reset-cells : shall be set to 1
|
||||
- resets : shall be the reset control phandle for the mmc block.
|
||||
|
||||
For "allwinner,sun7i-a20-gmac-clk", the parent clocks shall be fixed rate
|
||||
dummy clocks at 25 MHz and 125 MHz, respectively. See example.
|
||||
|
||||
@ -95,6 +103,14 @@ For "allwinner,sun6i-a31-pll6-clk", there are 2 outputs. The first output
|
||||
is the normal PLL6 output, or "pll6". The second output is rate doubled
|
||||
PLL6, or "pll6x2".
|
||||
|
||||
The "allwinner,*-mmc-clk" clocks have three different outputs: the
|
||||
main clock, with the ID 0, and the output and sample clocks, with the
|
||||
IDs 1 and 2, respectively.
|
||||
|
||||
The "allwinner,sun9i-a80-mmc-config-clk" clock has one clock/reset output
|
||||
per mmc controller. The number of outputs is determined by the size of
|
||||
the address block, which is related to the overall mmc block.
|
||||
|
||||
For example:
|
||||
|
||||
osc24M: clk@01c20050 {
|
||||
@ -138,11 +154,11 @@ cpu: cpu@01c20054 {
|
||||
};
|
||||
|
||||
mmc0_clk: clk@01c20088 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c20088 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
|
||||
clock-output-names = "mmc0";
|
||||
clock-output-names = "mmc0", "mmc0_output", "mmc0_sample";
|
||||
};
|
||||
|
||||
mii_phy_tx_clk: clk@2 {
|
||||
@ -170,3 +186,16 @@ gmac_clk: clk@01c20164 {
|
||||
clocks = <&mii_phy_tx_clk>, <&gmac_int_tx_clk>;
|
||||
clock-output-names = "gmac";
|
||||
};
|
||||
|
||||
mmc_config_clk: clk@01c13000 {
|
||||
compatible = "allwinner,sun9i-a80-mmc-config-clk";
|
||||
reg = <0x01c13000 0x10>;
|
||||
clocks = <&ahb0_gates 8>;
|
||||
clock-names = "ahb";
|
||||
resets = <&ahb0_resets 8>;
|
||||
reset-names = "ahb";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
clock-output-names = "mmc0_config", "mmc1_config",
|
||||
"mmc2_config", "mmc3_config";
|
||||
};
|
||||
|
42
Documentation/devicetree/bindings/clock/ti,cdce706.txt
Normal file
42
Documentation/devicetree/bindings/clock/ti,cdce706.txt
Normal file
@ -0,0 +1,42 @@
|
||||
Bindings for Texas Instruments CDCE706 programmable 3-PLL clock
|
||||
synthesizer/multiplier/divider.
|
||||
|
||||
Reference: http://www.ti.com/lit/ds/symlink/cdce706.pdf
|
||||
|
||||
I2C device node required properties:
|
||||
- compatible: shall be "ti,cdce706".
|
||||
- reg: i2c device address, shall be in range [0x68...0x6b].
|
||||
- #clock-cells: from common clock binding; shall be set to 1.
|
||||
- clocks: from common clock binding; list of parent clock
|
||||
handles, shall be reference clock(s) connected to CLK_IN0
|
||||
and CLK_IN1 pins.
|
||||
- clock-names: shall be clk_in0 and/or clk_in1. Use clk_in0
|
||||
in case of crystal oscillator or differential signal input
|
||||
configuration. Use clk_in0 and clk_in1 in case of independent
|
||||
single-ended LVCMOS inputs configuration.
|
||||
|
||||
Example:
|
||||
|
||||
clocks {
|
||||
clk54: clk54 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <54000000>;
|
||||
};
|
||||
};
|
||||
...
|
||||
i2c0: i2c-master@0d090000 {
|
||||
...
|
||||
cdce706: clock-synth@69 {
|
||||
compatible = "ti,cdce706";
|
||||
#clock-cells = <1>;
|
||||
reg = <0x69>;
|
||||
clocks = <&clk54>;
|
||||
clock-names = "clk_in0";
|
||||
};
|
||||
};
|
||||
...
|
||||
simple-audio-card,codec {
|
||||
...
|
||||
clocks = <&cdce706 4>;
|
||||
};
|
33
Documentation/devicetree/bindings/clock/ti/fapll.txt
Normal file
33
Documentation/devicetree/bindings/clock/ti/fapll.txt
Normal file
@ -0,0 +1,33 @@
|
||||
Binding for Texas Instruments FAPLL clock.
|
||||
|
||||
Binding status: Unstable - ABI compatibility may be broken in the future
|
||||
|
||||
This binding uses the common clock binding[1]. It assumes a
|
||||
register-mapped FAPLL with usually two selectable input clocks
|
||||
(reference clock and bypass clock), and one or more child
|
||||
syntesizers.
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
Required properties:
|
||||
- compatible : shall be "ti,dm816-fapll-clock"
|
||||
- #clock-cells : from common clock binding; shall be set to 0.
|
||||
- clocks : link phandles of parent clocks (clk-ref and clk-bypass)
|
||||
- reg : address and length of the register set for controlling the FAPLL.
|
||||
|
||||
Examples:
|
||||
main_fapll: main_fapll {
|
||||
#clock-cells = <1>;
|
||||
compatible = "ti,dm816-fapll-clock";
|
||||
reg = <0x400 0x40>;
|
||||
clocks = <&sys_clkin_ck &sys_clkin_ck>;
|
||||
clock-indices = <1>, <2>, <3>, <4>, <5>,
|
||||
<6>, <7>;
|
||||
clock-output-names = "main_pll_clk1",
|
||||
"main_pll_clk2",
|
||||
"main_pll_clk3",
|
||||
"main_pll_clk4",
|
||||
"main_pll_clk5",
|
||||
"main_pll_clk6",
|
||||
"main_pll_clk7";
|
||||
};
|
@ -10,8 +10,8 @@ Absolute maximum transfer rate is 200MB/s
|
||||
Required properties:
|
||||
- compatible : "allwinner,sun4i-a10-mmc" or "allwinner,sun5i-a13-mmc"
|
||||
- reg : mmc controller base registers
|
||||
- clocks : a list with 2 phandle + clock specifier pairs
|
||||
- clock-names : must contain "ahb" and "mmc"
|
||||
- clocks : a list with 4 phandle + clock specifier pairs
|
||||
- clock-names : must contain "ahb", "mmc", "output" and "sample"
|
||||
- interrupts : mmc controller interrupt
|
||||
|
||||
Optional properties:
|
||||
@ -25,8 +25,8 @@ Examples:
|
||||
mmc0: mmc@01c0f000 {
|
||||
compatible = "allwinner,sun5i-a13-mmc";
|
||||
reg = <0x01c0f000 0x1000>;
|
||||
clocks = <&ahb_gates 8>, <&mmc0_clk>;
|
||||
clock-names = "ahb", "mod";
|
||||
clocks = <&ahb_gates 8>, <&mmc0_clk>, <&mmc0_output_clk>, <&mmc0_sample_clk>;
|
||||
clock-names = "ahb", "mod", "output", "sample";
|
||||
interrupts = <0 32 4>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
@ -9566,6 +9566,11 @@ L: linux-omap@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/thermal/ti-soc-thermal/
|
||||
|
||||
TI CDCE706 CLOCK DRIVER
|
||||
M: Max Filippov <jcmvbkbc@gmail.com>
|
||||
S: Maintained
|
||||
F: drivers/clk/clk-cdce706.c
|
||||
|
||||
TI CLOCK DRIVER
|
||||
M: Tero Kristo <t-kristo@ti.com>
|
||||
L: linux-omap@vger.kernel.org
|
||||
|
@ -226,35 +226,43 @@
|
||||
};
|
||||
|
||||
mmc0_clk: clk@01c20088 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c20088 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
|
||||
clock-output-names = "mmc0";
|
||||
clock-output-names = "mmc0",
|
||||
"mmc0_output",
|
||||
"mmc0_sample";
|
||||
};
|
||||
|
||||
mmc1_clk: clk@01c2008c {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c2008c 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
|
||||
clock-output-names = "mmc1";
|
||||
clock-output-names = "mmc1",
|
||||
"mmc1_output",
|
||||
"mmc1_sample";
|
||||
};
|
||||
|
||||
mmc2_clk: clk@01c20090 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c20090 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
|
||||
clock-output-names = "mmc2";
|
||||
clock-output-names = "mmc2",
|
||||
"mmc2_output",
|
||||
"mmc2_sample";
|
||||
};
|
||||
|
||||
mmc3_clk: clk@01c20094 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c20094 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
|
||||
clock-output-names = "mmc3";
|
||||
clock-output-names = "mmc3",
|
||||
"mmc3_output",
|
||||
"mmc3_sample";
|
||||
};
|
||||
|
||||
ts_clk: clk@01c20098 {
|
||||
@ -398,8 +406,14 @@
|
||||
mmc0: mmc@01c0f000 {
|
||||
compatible = "allwinner,sun4i-a10-mmc";
|
||||
reg = <0x01c0f000 0x1000>;
|
||||
clocks = <&ahb_gates 8>, <&mmc0_clk>;
|
||||
clock-names = "ahb", "mmc";
|
||||
clocks = <&ahb_gates 8>,
|
||||
<&mmc0_clk 0>,
|
||||
<&mmc0_clk 1>,
|
||||
<&mmc0_clk 2>;
|
||||
clock-names = "ahb",
|
||||
"mmc",
|
||||
"output",
|
||||
"sample";
|
||||
interrupts = <32>;
|
||||
status = "disabled";
|
||||
};
|
||||
@ -407,8 +421,14 @@
|
||||
mmc1: mmc@01c10000 {
|
||||
compatible = "allwinner,sun4i-a10-mmc";
|
||||
reg = <0x01c10000 0x1000>;
|
||||
clocks = <&ahb_gates 9>, <&mmc1_clk>;
|
||||
clock-names = "ahb", "mmc";
|
||||
clocks = <&ahb_gates 9>,
|
||||
<&mmc1_clk 0>,
|
||||
<&mmc1_clk 1>,
|
||||
<&mmc1_clk 2>;
|
||||
clock-names = "ahb",
|
||||
"mmc",
|
||||
"output",
|
||||
"sample";
|
||||
interrupts = <33>;
|
||||
status = "disabled";
|
||||
};
|
||||
@ -416,8 +436,14 @@
|
||||
mmc2: mmc@01c11000 {
|
||||
compatible = "allwinner,sun4i-a10-mmc";
|
||||
reg = <0x01c11000 0x1000>;
|
||||
clocks = <&ahb_gates 10>, <&mmc2_clk>;
|
||||
clock-names = "ahb", "mmc";
|
||||
clocks = <&ahb_gates 10>,
|
||||
<&mmc2_clk 0>,
|
||||
<&mmc2_clk 1>,
|
||||
<&mmc2_clk 2>;
|
||||
clock-names = "ahb",
|
||||
"mmc",
|
||||
"output",
|
||||
"sample";
|
||||
interrupts = <34>;
|
||||
status = "disabled";
|
||||
};
|
||||
@ -425,8 +451,14 @@
|
||||
mmc3: mmc@01c12000 {
|
||||
compatible = "allwinner,sun4i-a10-mmc";
|
||||
reg = <0x01c12000 0x1000>;
|
||||
clocks = <&ahb_gates 11>, <&mmc3_clk>;
|
||||
clock-names = "ahb", "mmc";
|
||||
clocks = <&ahb_gates 11>,
|
||||
<&mmc3_clk 0>,
|
||||
<&mmc3_clk 1>,
|
||||
<&mmc3_clk 2>;
|
||||
clock-names = "ahb",
|
||||
"mmc",
|
||||
"output",
|
||||
"sample";
|
||||
interrupts = <35>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
@ -207,27 +207,33 @@
|
||||
};
|
||||
|
||||
mmc0_clk: clk@01c20088 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c20088 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
|
||||
clock-output-names = "mmc0";
|
||||
clock-output-names = "mmc0",
|
||||
"mmc0_output",
|
||||
"mmc0_sample";
|
||||
};
|
||||
|
||||
mmc1_clk: clk@01c2008c {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c2008c 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
|
||||
clock-output-names = "mmc1";
|
||||
clock-output-names = "mmc1",
|
||||
"mmc1_output",
|
||||
"mmc1_sample";
|
||||
};
|
||||
|
||||
mmc2_clk: clk@01c20090 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c20090 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
|
||||
clock-output-names = "mmc2";
|
||||
clock-output-names = "mmc2",
|
||||
"mmc2_output",
|
||||
"mmc2_sample";
|
||||
};
|
||||
|
||||
ts_clk: clk@01c20098 {
|
||||
@ -355,8 +361,14 @@
|
||||
mmc0: mmc@01c0f000 {
|
||||
compatible = "allwinner,sun5i-a13-mmc";
|
||||
reg = <0x01c0f000 0x1000>;
|
||||
clocks = <&ahb_gates 8>, <&mmc0_clk>;
|
||||
clock-names = "ahb", "mmc";
|
||||
clocks = <&ahb_gates 8>,
|
||||
<&mmc0_clk 0>,
|
||||
<&mmc0_clk 1>,
|
||||
<&mmc0_clk 2>;
|
||||
clock-names = "ahb",
|
||||
"mmc",
|
||||
"output",
|
||||
"sample";
|
||||
interrupts = <32>;
|
||||
status = "disabled";
|
||||
};
|
||||
@ -364,8 +376,14 @@
|
||||
mmc1: mmc@01c10000 {
|
||||
compatible = "allwinner,sun5i-a13-mmc";
|
||||
reg = <0x01c10000 0x1000>;
|
||||
clocks = <&ahb_gates 9>, <&mmc1_clk>;
|
||||
clock-names = "ahb", "mmc";
|
||||
clocks = <&ahb_gates 9>,
|
||||
<&mmc1_clk 0>,
|
||||
<&mmc1_clk 1>,
|
||||
<&mmc1_clk 2>;
|
||||
clock-names = "ahb",
|
||||
"mmc",
|
||||
"output",
|
||||
"sample";
|
||||
interrupts = <33>;
|
||||
status = "disabled";
|
||||
};
|
||||
@ -373,8 +391,14 @@
|
||||
mmc2: mmc@01c11000 {
|
||||
compatible = "allwinner,sun5i-a13-mmc";
|
||||
reg = <0x01c11000 0x1000>;
|
||||
clocks = <&ahb_gates 10>, <&mmc2_clk>;
|
||||
clock-names = "ahb", "mmc";
|
||||
clocks = <&ahb_gates 10>,
|
||||
<&mmc2_clk 0>,
|
||||
<&mmc2_clk 1>,
|
||||
<&mmc2_clk 2>;
|
||||
clock-names = "ahb",
|
||||
"mmc",
|
||||
"output",
|
||||
"sample";
|
||||
interrupts = <34>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
@ -190,27 +190,33 @@
|
||||
};
|
||||
|
||||
mmc0_clk: clk@01c20088 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c20088 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
|
||||
clock-output-names = "mmc0";
|
||||
clock-output-names = "mmc0",
|
||||
"mmc0_output",
|
||||
"mmc0_sample";
|
||||
};
|
||||
|
||||
mmc1_clk: clk@01c2008c {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c2008c 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
|
||||
clock-output-names = "mmc1";
|
||||
clock-output-names = "mmc1",
|
||||
"mmc1_output",
|
||||
"mmc1_sample";
|
||||
};
|
||||
|
||||
mmc2_clk: clk@01c20090 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c20090 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
|
||||
clock-output-names = "mmc2";
|
||||
clock-output-names = "mmc2",
|
||||
"mmc2_output",
|
||||
"mmc2_sample";
|
||||
};
|
||||
|
||||
ts_clk: clk@01c20098 {
|
||||
@ -322,8 +328,14 @@
|
||||
mmc0: mmc@01c0f000 {
|
||||
compatible = "allwinner,sun5i-a13-mmc";
|
||||
reg = <0x01c0f000 0x1000>;
|
||||
clocks = <&ahb_gates 8>, <&mmc0_clk>;
|
||||
clock-names = "ahb", "mmc";
|
||||
clocks = <&ahb_gates 8>,
|
||||
<&mmc0_clk 0>,
|
||||
<&mmc0_clk 1>,
|
||||
<&mmc0_clk 2>;
|
||||
clock-names = "ahb",
|
||||
"mmc",
|
||||
"output",
|
||||
"sample";
|
||||
interrupts = <32>;
|
||||
status = "disabled";
|
||||
};
|
||||
@ -331,8 +343,14 @@
|
||||
mmc2: mmc@01c11000 {
|
||||
compatible = "allwinner,sun5i-a13-mmc";
|
||||
reg = <0x01c11000 0x1000>;
|
||||
clocks = <&ahb_gates 10>, <&mmc2_clk>;
|
||||
clock-names = "ahb", "mmc";
|
||||
clocks = <&ahb_gates 10>,
|
||||
<&mmc2_clk 0>,
|
||||
<&mmc2_clk 1>,
|
||||
<&mmc2_clk 2>;
|
||||
clock-names = "ahb",
|
||||
"mmc",
|
||||
"output",
|
||||
"sample";
|
||||
interrupts = <34>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
@ -168,19 +168,11 @@
|
||||
clock-output-names = "axi";
|
||||
};
|
||||
|
||||
ahb1_mux: ahb1_mux@01c20054 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun6i-a31-ahb1-mux-clk";
|
||||
reg = <0x01c20054 0x4>;
|
||||
clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6 0>;
|
||||
clock-output-names = "ahb1_mux";
|
||||
};
|
||||
|
||||
ahb1: ahb1@01c20054 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-ahb-clk";
|
||||
compatible = "allwinner,sun6i-a31-ahb1-clk";
|
||||
reg = <0x01c20054 0x4>;
|
||||
clocks = <&ahb1_mux>;
|
||||
clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6 0>;
|
||||
clock-output-names = "ahb1";
|
||||
};
|
||||
|
||||
@ -243,35 +235,43 @@
|
||||
};
|
||||
|
||||
mmc0_clk: clk@01c20088 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c20088 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 0>;
|
||||
clock-output-names = "mmc0";
|
||||
clock-output-names = "mmc0",
|
||||
"mmc0_output",
|
||||
"mmc0_sample";
|
||||
};
|
||||
|
||||
mmc1_clk: clk@01c2008c {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c2008c 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 0>;
|
||||
clock-output-names = "mmc1";
|
||||
clock-output-names = "mmc1",
|
||||
"mmc1_output",
|
||||
"mmc1_sample";
|
||||
};
|
||||
|
||||
mmc2_clk: clk@01c20090 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c20090 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 0>;
|
||||
clock-output-names = "mmc2";
|
||||
clock-output-names = "mmc2",
|
||||
"mmc2_output",
|
||||
"mmc2_sample";
|
||||
};
|
||||
|
||||
mmc3_clk: clk@01c20094 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c20094 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 0>;
|
||||
clock-output-names = "mmc3";
|
||||
clock-output-names = "mmc3",
|
||||
"mmc3_output",
|
||||
"mmc3_sample";
|
||||
};
|
||||
|
||||
spi0_clk: clk@01c200a0 {
|
||||
@ -361,15 +361,21 @@
|
||||
#dma-cells = <1>;
|
||||
|
||||
/* DMA controller requires AHB1 clocked from PLL6 */
|
||||
assigned-clocks = <&ahb1_mux>;
|
||||
assigned-clocks = <&ahb1>;
|
||||
assigned-clock-parents = <&pll6 0>;
|
||||
};
|
||||
|
||||
mmc0: mmc@01c0f000 {
|
||||
compatible = "allwinner,sun5i-a13-mmc";
|
||||
reg = <0x01c0f000 0x1000>;
|
||||
clocks = <&ahb1_gates 8>, <&mmc0_clk>;
|
||||
clock-names = "ahb", "mmc";
|
||||
clocks = <&ahb1_gates 8>,
|
||||
<&mmc0_clk 0>,
|
||||
<&mmc0_clk 1>,
|
||||
<&mmc0_clk 2>;
|
||||
clock-names = "ahb",
|
||||
"mmc",
|
||||
"output",
|
||||
"sample";
|
||||
resets = <&ahb1_rst 8>;
|
||||
reset-names = "ahb";
|
||||
interrupts = <0 60 4>;
|
||||
@ -379,8 +385,14 @@
|
||||
mmc1: mmc@01c10000 {
|
||||
compatible = "allwinner,sun5i-a13-mmc";
|
||||
reg = <0x01c10000 0x1000>;
|
||||
clocks = <&ahb1_gates 9>, <&mmc1_clk>;
|
||||
clock-names = "ahb", "mmc";
|
||||
clocks = <&ahb1_gates 9>,
|
||||
<&mmc1_clk 0>,
|
||||
<&mmc1_clk 1>,
|
||||
<&mmc1_clk 2>;
|
||||
clock-names = "ahb",
|
||||
"mmc",
|
||||
"output",
|
||||
"sample";
|
||||
resets = <&ahb1_rst 9>;
|
||||
reset-names = "ahb";
|
||||
interrupts = <0 61 4>;
|
||||
@ -390,8 +402,14 @@
|
||||
mmc2: mmc@01c11000 {
|
||||
compatible = "allwinner,sun5i-a13-mmc";
|
||||
reg = <0x01c11000 0x1000>;
|
||||
clocks = <&ahb1_gates 10>, <&mmc2_clk>;
|
||||
clock-names = "ahb", "mmc";
|
||||
clocks = <&ahb1_gates 10>,
|
||||
<&mmc2_clk 0>,
|
||||
<&mmc2_clk 1>,
|
||||
<&mmc2_clk 2>;
|
||||
clock-names = "ahb",
|
||||
"mmc",
|
||||
"output",
|
||||
"sample";
|
||||
resets = <&ahb1_rst 10>;
|
||||
reset-names = "ahb";
|
||||
interrupts = <0 62 4>;
|
||||
@ -401,8 +419,14 @@
|
||||
mmc3: mmc@01c12000 {
|
||||
compatible = "allwinner,sun5i-a13-mmc";
|
||||
reg = <0x01c12000 0x1000>;
|
||||
clocks = <&ahb1_gates 11>, <&mmc3_clk>;
|
||||
clock-names = "ahb", "mmc";
|
||||
clocks = <&ahb1_gates 11>,
|
||||
<&mmc3_clk 0>,
|
||||
<&mmc3_clk 1>,
|
||||
<&mmc3_clk 2>;
|
||||
clock-names = "ahb",
|
||||
"mmc",
|
||||
"output",
|
||||
"sample";
|
||||
resets = <&ahb1_rst 11>;
|
||||
reset-names = "ahb";
|
||||
interrupts = <0 63 4>;
|
||||
|
@ -266,35 +266,43 @@
|
||||
};
|
||||
|
||||
mmc0_clk: clk@01c20088 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c20088 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
|
||||
clock-output-names = "mmc0";
|
||||
clock-output-names = "mmc0",
|
||||
"mmc0_output",
|
||||
"mmc0_sample";
|
||||
};
|
||||
|
||||
mmc1_clk: clk@01c2008c {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c2008c 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
|
||||
clock-output-names = "mmc1";
|
||||
clock-output-names = "mmc1",
|
||||
"mmc1_output",
|
||||
"mmc1_sample";
|
||||
};
|
||||
|
||||
mmc2_clk: clk@01c20090 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c20090 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
|
||||
clock-output-names = "mmc2";
|
||||
clock-output-names = "mmc2",
|
||||
"mmc2_output",
|
||||
"mmc2_sample";
|
||||
};
|
||||
|
||||
mmc3_clk: clk@01c20094 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c20094 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
|
||||
clock-output-names = "mmc3";
|
||||
clock-output-names = "mmc3",
|
||||
"mmc3_output",
|
||||
"mmc3_sample";
|
||||
};
|
||||
|
||||
ts_clk: clk@01c20098 {
|
||||
@ -510,8 +518,14 @@
|
||||
mmc0: mmc@01c0f000 {
|
||||
compatible = "allwinner,sun5i-a13-mmc";
|
||||
reg = <0x01c0f000 0x1000>;
|
||||
clocks = <&ahb_gates 8>, <&mmc0_clk>;
|
||||
clock-names = "ahb", "mmc";
|
||||
clocks = <&ahb_gates 8>,
|
||||
<&mmc0_clk 0>,
|
||||
<&mmc0_clk 1>,
|
||||
<&mmc0_clk 2>;
|
||||
clock-names = "ahb",
|
||||
"mmc",
|
||||
"output",
|
||||
"sample";
|
||||
interrupts = <0 32 4>;
|
||||
status = "disabled";
|
||||
};
|
||||
@ -519,8 +533,14 @@
|
||||
mmc1: mmc@01c10000 {
|
||||
compatible = "allwinner,sun5i-a13-mmc";
|
||||
reg = <0x01c10000 0x1000>;
|
||||
clocks = <&ahb_gates 9>, <&mmc1_clk>;
|
||||
clock-names = "ahb", "mmc";
|
||||
clocks = <&ahb_gates 9>,
|
||||
<&mmc1_clk 0>,
|
||||
<&mmc1_clk 1>,
|
||||
<&mmc1_clk 2>;
|
||||
clock-names = "ahb",
|
||||
"mmc",
|
||||
"output",
|
||||
"sample";
|
||||
interrupts = <0 33 4>;
|
||||
status = "disabled";
|
||||
};
|
||||
@ -528,8 +548,14 @@
|
||||
mmc2: mmc@01c11000 {
|
||||
compatible = "allwinner,sun5i-a13-mmc";
|
||||
reg = <0x01c11000 0x1000>;
|
||||
clocks = <&ahb_gates 10>, <&mmc2_clk>;
|
||||
clock-names = "ahb", "mmc";
|
||||
clocks = <&ahb_gates 10>,
|
||||
<&mmc2_clk 0>,
|
||||
<&mmc2_clk 1>,
|
||||
<&mmc2_clk 2>;
|
||||
clock-names = "ahb",
|
||||
"mmc",
|
||||
"output",
|
||||
"sample";
|
||||
interrupts = <0 34 4>;
|
||||
status = "disabled";
|
||||
};
|
||||
@ -537,8 +563,14 @@
|
||||
mmc3: mmc@01c12000 {
|
||||
compatible = "allwinner,sun5i-a13-mmc";
|
||||
reg = <0x01c12000 0x1000>;
|
||||
clocks = <&ahb_gates 11>, <&mmc3_clk>;
|
||||
clock-names = "ahb", "mmc";
|
||||
clocks = <&ahb_gates 11>,
|
||||
<&mmc3_clk 0>,
|
||||
<&mmc3_clk 1>,
|
||||
<&mmc3_clk 2>;
|
||||
clock-names = "ahb",
|
||||
"mmc",
|
||||
"output",
|
||||
"sample";
|
||||
interrupts = <0 35 4>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
@ -101,11 +101,19 @@
|
||||
};
|
||||
|
||||
/* dummy clock until actually implemented */
|
||||
pll6: pll6_clk {
|
||||
pll5: pll5_clk {
|
||||
#clock-cells = <0>;
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <600000000>;
|
||||
clock-output-names = "pll6";
|
||||
clock-frequency = <0>;
|
||||
clock-output-names = "pll5";
|
||||
};
|
||||
|
||||
pll6: clk@01c20028 {
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun6i-a31-pll6-clk";
|
||||
reg = <0x01c20028 0x4>;
|
||||
clocks = <&osc24M>;
|
||||
clock-output-names = "pll6", "pll6x2";
|
||||
};
|
||||
|
||||
cpu: cpu_clk@01c20050 {
|
||||
@ -131,19 +139,11 @@
|
||||
clock-output-names = "axi";
|
||||
};
|
||||
|
||||
ahb1_mux: ahb1_mux_clk@01c20054 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun6i-a31-ahb1-mux-clk";
|
||||
reg = <0x01c20054 0x4>;
|
||||
clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6>;
|
||||
clock-output-names = "ahb1_mux";
|
||||
};
|
||||
|
||||
ahb1: ahb1_clk@01c20054 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-ahb-clk";
|
||||
compatible = "allwinner,sun6i-a31-ahb1-clk";
|
||||
reg = <0x01c20054 0x4>;
|
||||
clocks = <&ahb1_mux>;
|
||||
clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6 0>;
|
||||
clock-output-names = "ahb1";
|
||||
};
|
||||
|
||||
@ -184,7 +184,7 @@
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-apb1-clk";
|
||||
reg = <0x01c20058 0x4>;
|
||||
clocks = <&osc32k>, <&osc24M>, <&pll6>, <&pll6>;
|
||||
clocks = <&osc32k>, <&osc24M>, <&pll6 0>, <&pll6 0>;
|
||||
clock-output-names = "apb2";
|
||||
};
|
||||
|
||||
@ -200,27 +200,41 @@
|
||||
};
|
||||
|
||||
mmc0_clk: clk@01c20088 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c20088 0x4>;
|
||||
clocks = <&osc24M>, <&pll6>;
|
||||
clock-output-names = "mmc0";
|
||||
clocks = <&osc24M>, <&pll6 0>;
|
||||
clock-output-names = "mmc0",
|
||||
"mmc0_output",
|
||||
"mmc0_sample";
|
||||
};
|
||||
|
||||
mmc1_clk: clk@01c2008c {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c2008c 0x4>;
|
||||
clocks = <&osc24M>, <&pll6>;
|
||||
clock-output-names = "mmc1";
|
||||
clocks = <&osc24M>, <&pll6 0>;
|
||||
clock-output-names = "mmc1",
|
||||
"mmc1_output",
|
||||
"mmc1_sample";
|
||||
};
|
||||
|
||||
mmc2_clk: clk@01c20090 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-a10-mod0-clk";
|
||||
#clock-cells = <1>;
|
||||
compatible = "allwinner,sun4i-a10-mmc-clk";
|
||||
reg = <0x01c20090 0x4>;
|
||||
clocks = <&osc24M>, <&pll6>;
|
||||
clock-output-names = "mmc2";
|
||||
clocks = <&osc24M>, <&pll6 0>;
|
||||
clock-output-names = "mmc2",
|
||||
"mmc2_output",
|
||||
"mmc2_sample";
|
||||
};
|
||||
|
||||
mbus_clk: clk@01c2015c {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun8i-a23-mbus-clk";
|
||||
reg = <0x01c2015c 0x4>;
|
||||
clocks = <&osc24M>, <&pll6 1>, <&pll5>;
|
||||
clock-output-names = "mbus";
|
||||
};
|
||||
};
|
||||
|
||||
@ -242,8 +256,14 @@
|
||||
mmc0: mmc@01c0f000 {
|
||||
compatible = "allwinner,sun5i-a13-mmc";
|
||||
reg = <0x01c0f000 0x1000>;
|
||||
clocks = <&ahb1_gates 8>, <&mmc0_clk>;
|
||||
clock-names = "ahb", "mmc";
|
||||
clocks = <&ahb1_gates 8>,
|
||||
<&mmc0_clk 0>,
|
||||
<&mmc0_clk 1>,
|
||||
<&mmc0_clk 2>;
|
||||
clock-names = "ahb",
|
||||
"mmc",
|
||||
"output",
|
||||
"sample";
|
||||
resets = <&ahb1_rst 8>;
|
||||
reset-names = "ahb";
|
||||
interrupts = <0 60 4>;
|
||||
@ -253,8 +273,14 @@
|
||||
mmc1: mmc@01c10000 {
|
||||
compatible = "allwinner,sun5i-a13-mmc";
|
||||
reg = <0x01c10000 0x1000>;
|
||||
clocks = <&ahb1_gates 9>, <&mmc1_clk>;
|
||||
clock-names = "ahb", "mmc";
|
||||
clocks = <&ahb1_gates 9>,
|
||||
<&mmc1_clk 0>,
|
||||
<&mmc1_clk 1>,
|
||||
<&mmc1_clk 2>;
|
||||
clock-names = "ahb",
|
||||
"mmc",
|
||||
"output",
|
||||
"sample";
|
||||
resets = <&ahb1_rst 9>;
|
||||
reset-names = "ahb";
|
||||
interrupts = <0 61 4>;
|
||||
@ -264,8 +290,14 @@
|
||||
mmc2: mmc@01c11000 {
|
||||
compatible = "allwinner,sun5i-a13-mmc";
|
||||
reg = <0x01c11000 0x1000>;
|
||||
clocks = <&ahb1_gates 10>, <&mmc2_clk>;
|
||||
clock-names = "ahb", "mmc";
|
||||
clocks = <&ahb1_gates 10>,
|
||||
<&mmc2_clk 0>,
|
||||
<&mmc2_clk 1>,
|
||||
<&mmc2_clk 2>;
|
||||
clock-names = "ahb",
|
||||
"mmc",
|
||||
"output",
|
||||
"sample";
|
||||
resets = <&ahb1_rst 10>;
|
||||
reset-names = "ahb";
|
||||
interrupts = <0 62 4>;
|
||||
|
@ -187,7 +187,7 @@ obj-$(CONFIG_SOC_OMAP2430) += clock2430.o
|
||||
obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) clock3xxx.o
|
||||
obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o clkt34xx_dpll3m2.o
|
||||
obj-$(CONFIG_ARCH_OMAP3) += clock3517.o clock36xx.o
|
||||
obj-$(CONFIG_ARCH_OMAP3) += dpll3xxx.o cclock3xxx_data.o
|
||||
obj-$(CONFIG_ARCH_OMAP3) += dpll3xxx.o
|
||||
obj-$(CONFIG_ARCH_OMAP3) += clkt_iclk.o
|
||||
obj-$(CONFIG_ARCH_OMAP4) += $(clock-common)
|
||||
obj-$(CONFIG_ARCH_OMAP4) += dpll3xxx.o dpll44xx.o
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -23,7 +23,6 @@
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk-private.h>
|
||||
#include <asm/cpu.h>
|
||||
|
||||
#include <trace/events/power.h>
|
||||
@ -629,21 +628,6 @@ const struct clk_hw_omap_ops clkhwops_wait = {
|
||||
.find_companion = omap2_clk_dflt_find_companion,
|
||||
};
|
||||
|
||||
/**
|
||||
* omap_clocks_register - register an array of omap_clk
|
||||
* @ocs: pointer to an array of omap_clk to register
|
||||
*/
|
||||
void __init omap_clocks_register(struct omap_clk oclks[], int cnt)
|
||||
{
|
||||
struct omap_clk *c;
|
||||
|
||||
for (c = oclks; c < oclks + cnt; c++) {
|
||||
clkdev_add(&c->lk);
|
||||
if (!__clk_init(NULL, c->lk.clk))
|
||||
omap2_init_clk_hw_omap_clocks(c->lk.clk);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* omap2_clk_switch_mpurate_at_boot - switch ARM MPU rate by boot-time argument
|
||||
* @mpurate_ck_name: clk name of the clock to change rate
|
||||
|
@ -40,23 +40,29 @@ struct omap_clk {
|
||||
struct clockdomain;
|
||||
|
||||
#define DEFINE_STRUCT_CLK(_name, _parent_array_name, _clkops_name) \
|
||||
static struct clk _name = { \
|
||||
static struct clk_core _name##_core = { \
|
||||
.name = #_name, \
|
||||
.hw = &_name##_hw.hw, \
|
||||
.parent_names = _parent_array_name, \
|
||||
.num_parents = ARRAY_SIZE(_parent_array_name), \
|
||||
.ops = &_clkops_name, \
|
||||
}; \
|
||||
static struct clk _name = { \
|
||||
.core = &_name##_core, \
|
||||
};
|
||||
|
||||
#define DEFINE_STRUCT_CLK_FLAGS(_name, _parent_array_name, \
|
||||
_clkops_name, _flags) \
|
||||
static struct clk _name = { \
|
||||
static struct clk_core _name##_core = { \
|
||||
.name = #_name, \
|
||||
.hw = &_name##_hw.hw, \
|
||||
.parent_names = _parent_array_name, \
|
||||
.num_parents = ARRAY_SIZE(_parent_array_name), \
|
||||
.ops = &_clkops_name, \
|
||||
.flags = _flags, \
|
||||
}; \
|
||||
static struct clk _name = { \
|
||||
.core = &_name##_core, \
|
||||
};
|
||||
|
||||
#define DEFINE_STRUCT_CLK_HW_OMAP(_name, _clkdm_name) \
|
||||
@ -239,7 +245,6 @@ struct ti_clk_features {
|
||||
extern struct ti_clk_features ti_clk_features;
|
||||
|
||||
extern const struct clkops clkops_omap2_dflt_wait;
|
||||
extern const struct clkops clkops_dummy;
|
||||
extern const struct clkops clkops_omap2_dflt;
|
||||
|
||||
extern struct clk_functions omap2_clk_functions;
|
||||
@ -248,7 +253,6 @@ extern const struct clksel_rate gpt_32k_rates[];
|
||||
extern const struct clksel_rate gpt_sys_rates[];
|
||||
extern const struct clksel_rate gfx_l3_rates[];
|
||||
extern const struct clksel_rate dsp_ick_rates[];
|
||||
extern struct clk dummy_ck;
|
||||
|
||||
extern const struct clk_hw_omap_ops clkhwops_iclk_wait;
|
||||
extern const struct clk_hw_omap_ops clkhwops_wait;
|
||||
@ -273,7 +277,5 @@ extern void __iomem *clk_memmaps[];
|
||||
extern int omap2_clkops_enable_clkdm(struct clk_hw *hw);
|
||||
extern void omap2_clkops_disable_clkdm(struct clk_hw *hw);
|
||||
|
||||
extern void omap_clocks_register(struct omap_clk *oclks, int cnt);
|
||||
|
||||
void __init ti_clk_init_features(void);
|
||||
#endif
|
||||
|
@ -16,7 +16,6 @@
|
||||
* OMAP3xxx clock definition files.
|
||||
*/
|
||||
|
||||
#include <linux/clk-private.h>
|
||||
#include "clock.h"
|
||||
|
||||
/* clksel_rate data common to 24xx/343x */
|
||||
@ -114,13 +113,3 @@ const struct clksel_rate div31_1to31_rates[] = {
|
||||
{ .div = 31, .val = 31, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 0 },
|
||||
};
|
||||
|
||||
/* Clocks shared between various OMAP SoCs */
|
||||
|
||||
static struct clk_ops dummy_ck_ops = {};
|
||||
|
||||
struct clk dummy_ck = {
|
||||
.name = "dummy_clk",
|
||||
.ops = &dummy_ck_ops,
|
||||
.flags = CLK_IS_BASIC,
|
||||
};
|
||||
|
@ -410,7 +410,7 @@ int omap3_noncore_dpll_enable(struct clk_hw *hw)
|
||||
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
|
||||
int r;
|
||||
struct dpll_data *dd;
|
||||
struct clk *parent;
|
||||
struct clk_hw *parent;
|
||||
|
||||
dd = clk->dpll_data;
|
||||
if (!dd)
|
||||
@ -427,13 +427,13 @@ int omap3_noncore_dpll_enable(struct clk_hw *hw)
|
||||
}
|
||||
}
|
||||
|
||||
parent = __clk_get_parent(hw->clk);
|
||||
parent = __clk_get_hw(__clk_get_parent(hw->clk));
|
||||
|
||||
if (__clk_get_rate(hw->clk) == __clk_get_rate(dd->clk_bypass)) {
|
||||
WARN_ON(parent != dd->clk_bypass);
|
||||
WARN_ON(parent != __clk_get_hw(dd->clk_bypass));
|
||||
r = _omap3_noncore_dpll_bypass(clk);
|
||||
} else {
|
||||
WARN_ON(parent != dd->clk_ref);
|
||||
WARN_ON(parent != __clk_get_hw(dd->clk_ref));
|
||||
r = _omap3_noncore_dpll_lock(clk);
|
||||
}
|
||||
|
||||
@ -473,6 +473,8 @@ void omap3_noncore_dpll_disable(struct clk_hw *hw)
|
||||
* in failure.
|
||||
*/
|
||||
long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_clk)
|
||||
{
|
||||
@ -549,7 +551,8 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
if (!dd)
|
||||
return -EINVAL;
|
||||
|
||||
if (__clk_get_parent(hw->clk) != dd->clk_ref)
|
||||
if (__clk_get_hw(__clk_get_parent(hw->clk)) !=
|
||||
__clk_get_hw(dd->clk_ref))
|
||||
return -EINVAL;
|
||||
|
||||
if (dd->last_rounded_rate == 0)
|
||||
|
@ -222,6 +222,8 @@ out:
|
||||
* in failure.
|
||||
*/
|
||||
long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_clk)
|
||||
{
|
||||
|
@ -461,7 +461,17 @@ void __init omap3_init_early(void)
|
||||
omap3xxx_clockdomains_init();
|
||||
omap3xxx_hwmod_init();
|
||||
omap_hwmod_init_postsetup();
|
||||
omap_clk_soc_init = omap3xxx_clk_init;
|
||||
if (!of_have_populated_dt()) {
|
||||
omap3_prcm_legacy_iomaps_init();
|
||||
if (soc_is_am35xx())
|
||||
omap_clk_soc_init = am35xx_clk_legacy_init;
|
||||
else if (cpu_is_omap3630())
|
||||
omap_clk_soc_init = omap36xx_clk_legacy_init;
|
||||
else if (omap_rev() == OMAP3430_REV_ES1_0)
|
||||
omap_clk_soc_init = omap3430es1_clk_legacy_init;
|
||||
else
|
||||
omap_clk_soc_init = omap3430_clk_legacy_init;
|
||||
}
|
||||
}
|
||||
|
||||
void __init omap3430_init_early(void)
|
||||
@ -509,8 +519,6 @@ void __init ti81xx_init_early(void)
|
||||
omap_hwmod_init_postsetup();
|
||||
if (of_have_populated_dt())
|
||||
omap_clk_soc_init = ti81xx_dt_clk_init;
|
||||
else
|
||||
omap_clk_soc_init = omap3xxx_clk_init;
|
||||
}
|
||||
|
||||
void __init omap3_init_late(void)
|
||||
@ -731,15 +739,17 @@ int __init omap_clk_init(void)
|
||||
|
||||
ti_clk_init_features();
|
||||
|
||||
ret = of_prcm_init();
|
||||
if (ret)
|
||||
return ret;
|
||||
if (of_have_populated_dt()) {
|
||||
ret = of_prcm_init();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
of_clk_init(NULL);
|
||||
of_clk_init(NULL);
|
||||
|
||||
ti_dt_clk_init_retry_clks();
|
||||
ti_dt_clk_init_retry_clks();
|
||||
|
||||
ti_dt_clockdomains_setup();
|
||||
ti_dt_clockdomains_setup();
|
||||
}
|
||||
|
||||
ret = omap_clk_soc_init();
|
||||
|
||||
|
@ -20,6 +20,7 @@ extern void __iomem *prm_base;
|
||||
extern u16 prm_features;
|
||||
extern void omap2_set_globals_prm(void __iomem *prm);
|
||||
int of_prcm_init(void);
|
||||
void omap3_prcm_legacy_iomaps_init(void);
|
||||
# endif
|
||||
|
||||
/*
|
||||
|
@ -35,6 +35,8 @@
|
||||
#include "prm44xx.h"
|
||||
#include "common.h"
|
||||
#include "clock.h"
|
||||
#include "cm.h"
|
||||
#include "control.h"
|
||||
|
||||
/*
|
||||
* OMAP_PRCM_MAX_NR_PENDING_REG: maximum number of PRM_IRQ*_MPU regs
|
||||
@ -637,6 +639,15 @@ int __init of_prcm_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __init omap3_prcm_legacy_iomaps_init(void)
|
||||
{
|
||||
ti_clk_ll_ops = &omap_clk_ll_ops;
|
||||
|
||||
clk_memmaps[TI_CLKM_CM] = cm_base + OMAP3430_IVA2_MOD;
|
||||
clk_memmaps[TI_CLKM_PRM] = prm_base + OMAP3430_IVA2_MOD;
|
||||
clk_memmaps[TI_CLKM_SCRM] = omap_ctrl_base_get();
|
||||
}
|
||||
|
||||
static int __init prm_late_init(void)
|
||||
{
|
||||
if (prm_ll_data->late_init)
|
||||
|
@ -373,6 +373,8 @@ static long alchemy_calc_div(unsigned long rate, unsigned long prate,
|
||||
}
|
||||
|
||||
static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_clk,
|
||||
int scale, int maxdiv)
|
||||
@ -546,6 +548,8 @@ static unsigned long alchemy_clk_fgv1_recalc(struct clk_hw *hw,
|
||||
}
|
||||
|
||||
static long alchemy_clk_fgv1_detr(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_clk)
|
||||
{
|
||||
@ -678,6 +682,8 @@ static unsigned long alchemy_clk_fgv2_recalc(struct clk_hw *hw,
|
||||
}
|
||||
|
||||
static long alchemy_clk_fgv2_detr(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_clk)
|
||||
{
|
||||
@ -897,6 +903,8 @@ static int alchemy_clk_csrc_setr(struct clk_hw *hw, unsigned long rate,
|
||||
}
|
||||
|
||||
static long alchemy_clk_csrc_detr(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_clk)
|
||||
{
|
||||
|
@ -54,6 +54,7 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/irq_work.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <asm/trace.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
@ -943,6 +944,10 @@ void __init time_init(void)
|
||||
|
||||
init_decrementer_clockevent();
|
||||
tick_setup_hrtimer_broadcast();
|
||||
|
||||
#ifdef CONFIG_COMMON_CLK
|
||||
of_clk_init(NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -1168,6 +1168,11 @@ static void mpc5121_clk_provide_backwards_compat(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The "fixed-clock" nodes (which includes the oscillator node if the board's
|
||||
* DT provides one) has already been scanned by the of_clk_init() in
|
||||
* time_init().
|
||||
*/
|
||||
int __init mpc5121_clk_init(void)
|
||||
{
|
||||
struct device_node *clk_np;
|
||||
@ -1186,12 +1191,6 @@ int __init mpc5121_clk_init(void)
|
||||
/* invalidate all not yet registered clock slots */
|
||||
mpc512x_clk_preset_data();
|
||||
|
||||
/*
|
||||
* have the device tree scanned for "fixed-clock" nodes (which
|
||||
* includes the oscillator node if the board's DT provides one)
|
||||
*/
|
||||
of_clk_init(NULL);
|
||||
|
||||
/*
|
||||
* add a dummy clock for those situations where a clock spec is
|
||||
* required yet no real clock is involved
|
||||
|
@ -101,12 +101,12 @@ config COMMON_CLK_AXI_CLKGEN
|
||||
Support for the Analog Devices axi-clkgen pcore clock generator for Xilinx
|
||||
FPGAs. It is commonly used in Analog Devices' reference designs.
|
||||
|
||||
config CLK_PPC_CORENET
|
||||
bool "Clock driver for PowerPC corenet platforms"
|
||||
depends on PPC_E500MC && OF
|
||||
config CLK_QORIQ
|
||||
bool "Clock driver for Freescale QorIQ platforms"
|
||||
depends on (PPC_E500MC || ARM) && OF
|
||||
---help---
|
||||
This adds the clock driver support for Freescale PowerPC corenet
|
||||
platforms using common clock framework.
|
||||
This adds the clock driver support for Freescale QorIQ platforms
|
||||
using common clock framework.
|
||||
|
||||
config COMMON_CLK_XGENE
|
||||
bool "Clock driver for APM XGene SoC"
|
||||
@ -134,6 +134,14 @@ config COMMON_CLK_PXA
|
||||
---help---
|
||||
Sypport for the Marvell PXA SoC.
|
||||
|
||||
config COMMON_CLK_CDCE706
|
||||
tristate "Clock driver for TI CDCE706 clock synthesizer"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
select RATIONAL
|
||||
---help---
|
||||
This driver supports TI CDCE706 programmable 3-PLL clock synthesizer.
|
||||
|
||||
source "drivers/clk/qcom/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
@ -16,9 +16,11 @@ endif
|
||||
|
||||
# hardware specific clock types
|
||||
# please keep this section sorted lexicographically by file/directory path name
|
||||
obj-$(CONFIG_MACH_ASM9260) += clk-asm9260.o
|
||||
obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
|
||||
obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o
|
||||
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
|
||||
obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-cdce706.o
|
||||
obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
|
||||
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
|
||||
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
|
||||
@ -30,7 +32,7 @@ obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o
|
||||
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
|
||||
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
|
||||
obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o
|
||||
obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o
|
||||
obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o
|
||||
obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o
|
||||
obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
|
||||
obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
|
||||
|
@ -56,6 +56,8 @@ static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
|
||||
|
||||
static long clk_programmable_determine_rate(struct clk_hw *hw,
|
||||
unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_hw)
|
||||
{
|
||||
|
@ -1032,6 +1032,8 @@ static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
}
|
||||
|
||||
static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate, struct clk_hw **best_parent)
|
||||
{
|
||||
struct kona_clk *bcm_clk = to_kona_clk(hw);
|
||||
|
348
drivers/clk/clk-asm9260.c
Normal file
348
drivers/clk/clk-asm9260.c
Normal file
@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Oleksij Rempel <linux@rempel-privat.de>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <dt-bindings/clock/alphascale,asm9260.h>
|
||||
|
||||
#define HW_AHBCLKCTRL0 0x0020
|
||||
#define HW_AHBCLKCTRL1 0x0030
|
||||
#define HW_SYSPLLCTRL 0x0100
|
||||
#define HW_MAINCLKSEL 0x0120
|
||||
#define HW_MAINCLKUEN 0x0124
|
||||
#define HW_UARTCLKSEL 0x0128
|
||||
#define HW_UARTCLKUEN 0x012c
|
||||
#define HW_I2S0CLKSEL 0x0130
|
||||
#define HW_I2S0CLKUEN 0x0134
|
||||
#define HW_I2S1CLKSEL 0x0138
|
||||
#define HW_I2S1CLKUEN 0x013c
|
||||
#define HW_WDTCLKSEL 0x0160
|
||||
#define HW_WDTCLKUEN 0x0164
|
||||
#define HW_CLKOUTCLKSEL 0x0170
|
||||
#define HW_CLKOUTCLKUEN 0x0174
|
||||
#define HW_CPUCLKDIV 0x017c
|
||||
#define HW_SYSAHBCLKDIV 0x0180
|
||||
#define HW_I2S0MCLKDIV 0x0190
|
||||
#define HW_I2S0SCLKDIV 0x0194
|
||||
#define HW_I2S1MCLKDIV 0x0188
|
||||
#define HW_I2S1SCLKDIV 0x018c
|
||||
#define HW_UART0CLKDIV 0x0198
|
||||
#define HW_UART1CLKDIV 0x019c
|
||||
#define HW_UART2CLKDIV 0x01a0
|
||||
#define HW_UART3CLKDIV 0x01a4
|
||||
#define HW_UART4CLKDIV 0x01a8
|
||||
#define HW_UART5CLKDIV 0x01ac
|
||||
#define HW_UART6CLKDIV 0x01b0
|
||||
#define HW_UART7CLKDIV 0x01b4
|
||||
#define HW_UART8CLKDIV 0x01b8
|
||||
#define HW_UART9CLKDIV 0x01bc
|
||||
#define HW_SPI0CLKDIV 0x01c0
|
||||
#define HW_SPI1CLKDIV 0x01c4
|
||||
#define HW_QUADSPICLKDIV 0x01c8
|
||||
#define HW_SSP0CLKDIV 0x01d0
|
||||
#define HW_NANDCLKDIV 0x01d4
|
||||
#define HW_TRACECLKDIV 0x01e0
|
||||
#define HW_CAMMCLKDIV 0x01e8
|
||||
#define HW_WDTCLKDIV 0x01ec
|
||||
#define HW_CLKOUTCLKDIV 0x01f4
|
||||
#define HW_MACCLKDIV 0x01f8
|
||||
#define HW_LCDCLKDIV 0x01fc
|
||||
#define HW_ADCANACLKDIV 0x0200
|
||||
|
||||
static struct clk *clks[MAX_CLKS];
|
||||
static struct clk_onecell_data clk_data;
|
||||
static DEFINE_SPINLOCK(asm9260_clk_lock);
|
||||
|
||||
struct asm9260_div_clk {
|
||||
unsigned int idx;
|
||||
const char *name;
|
||||
const char *parent_name;
|
||||
u32 reg;
|
||||
};
|
||||
|
||||
struct asm9260_gate_data {
|
||||
unsigned int idx;
|
||||
const char *name;
|
||||
const char *parent_name;
|
||||
u32 reg;
|
||||
u8 bit_idx;
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
struct asm9260_mux_clock {
|
||||
u8 mask;
|
||||
u32 *table;
|
||||
const char *name;
|
||||
const char **parent_names;
|
||||
u8 num_parents;
|
||||
unsigned long offset;
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
static void __iomem *base;
|
||||
|
||||
static const struct asm9260_div_clk asm9260_div_clks[] __initconst = {
|
||||
{ CLKID_SYS_CPU, "cpu_div", "main_gate", HW_CPUCLKDIV },
|
||||
{ CLKID_SYS_AHB, "ahb_div", "cpu_div", HW_SYSAHBCLKDIV },
|
||||
|
||||
/* i2s has two deviders: one for only external mclk and internal
|
||||
* devider for all clks. */
|
||||
{ CLKID_SYS_I2S0M, "i2s0m_div", "i2s0_mclk", HW_I2S0MCLKDIV },
|
||||
{ CLKID_SYS_I2S1M, "i2s1m_div", "i2s1_mclk", HW_I2S1MCLKDIV },
|
||||
{ CLKID_SYS_I2S0S, "i2s0s_div", "i2s0_gate", HW_I2S0SCLKDIV },
|
||||
{ CLKID_SYS_I2S1S, "i2s1s_div", "i2s0_gate", HW_I2S1SCLKDIV },
|
||||
|
||||
{ CLKID_SYS_UART0, "uart0_div", "uart_gate", HW_UART0CLKDIV },
|
||||
{ CLKID_SYS_UART1, "uart1_div", "uart_gate", HW_UART1CLKDIV },
|
||||
{ CLKID_SYS_UART2, "uart2_div", "uart_gate", HW_UART2CLKDIV },
|
||||
{ CLKID_SYS_UART3, "uart3_div", "uart_gate", HW_UART3CLKDIV },
|
||||
{ CLKID_SYS_UART4, "uart4_div", "uart_gate", HW_UART4CLKDIV },
|
||||
{ CLKID_SYS_UART5, "uart5_div", "uart_gate", HW_UART5CLKDIV },
|
||||
{ CLKID_SYS_UART6, "uart6_div", "uart_gate", HW_UART6CLKDIV },
|
||||
{ CLKID_SYS_UART7, "uart7_div", "uart_gate", HW_UART7CLKDIV },
|
||||
{ CLKID_SYS_UART8, "uart8_div", "uart_gate", HW_UART8CLKDIV },
|
||||
{ CLKID_SYS_UART9, "uart9_div", "uart_gate", HW_UART9CLKDIV },
|
||||
|
||||
{ CLKID_SYS_SPI0, "spi0_div", "main_gate", HW_SPI0CLKDIV },
|
||||
{ CLKID_SYS_SPI1, "spi1_div", "main_gate", HW_SPI1CLKDIV },
|
||||
{ CLKID_SYS_QUADSPI, "quadspi_div", "main_gate", HW_QUADSPICLKDIV },
|
||||
{ CLKID_SYS_SSP0, "ssp0_div", "main_gate", HW_SSP0CLKDIV },
|
||||
{ CLKID_SYS_NAND, "nand_div", "main_gate", HW_NANDCLKDIV },
|
||||
{ CLKID_SYS_TRACE, "trace_div", "main_gate", HW_TRACECLKDIV },
|
||||
{ CLKID_SYS_CAMM, "camm_div", "main_gate", HW_CAMMCLKDIV },
|
||||
{ CLKID_SYS_MAC, "mac_div", "main_gate", HW_MACCLKDIV },
|
||||
{ CLKID_SYS_LCD, "lcd_div", "main_gate", HW_LCDCLKDIV },
|
||||
{ CLKID_SYS_ADCANA, "adcana_div", "main_gate", HW_ADCANACLKDIV },
|
||||
|
||||
{ CLKID_SYS_WDT, "wdt_div", "wdt_gate", HW_WDTCLKDIV },
|
||||
{ CLKID_SYS_CLKOUT, "clkout_div", "clkout_gate", HW_CLKOUTCLKDIV },
|
||||
};
|
||||
|
||||
static const struct asm9260_gate_data asm9260_mux_gates[] __initconst = {
|
||||
{ 0, "main_gate", "main_mux", HW_MAINCLKUEN, 0 },
|
||||
{ 0, "uart_gate", "uart_mux", HW_UARTCLKUEN, 0 },
|
||||
{ 0, "i2s0_gate", "i2s0_mux", HW_I2S0CLKUEN, 0 },
|
||||
{ 0, "i2s1_gate", "i2s1_mux", HW_I2S1CLKUEN, 0 },
|
||||
{ 0, "wdt_gate", "wdt_mux", HW_WDTCLKUEN, 0 },
|
||||
{ 0, "clkout_gate", "clkout_mux", HW_CLKOUTCLKUEN, 0 },
|
||||
};
|
||||
static const struct asm9260_gate_data asm9260_ahb_gates[] __initconst = {
|
||||
/* ahb gates */
|
||||
{ CLKID_AHB_ROM, "rom", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 1, CLK_IGNORE_UNUSED},
|
||||
{ CLKID_AHB_RAM, "ram", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 2, CLK_IGNORE_UNUSED},
|
||||
{ CLKID_AHB_GPIO, "gpio", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 4 },
|
||||
{ CLKID_AHB_MAC, "mac", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 5 },
|
||||
{ CLKID_AHB_EMI, "emi", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 6, CLK_IGNORE_UNUSED},
|
||||
{ CLKID_AHB_USB0, "usb0", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 7 },
|
||||
{ CLKID_AHB_USB1, "usb1", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 8 },
|
||||
{ CLKID_AHB_DMA0, "dma0", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 9 },
|
||||
{ CLKID_AHB_DMA1, "dma1", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 10 },
|
||||
{ CLKID_AHB_UART0, "uart0", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 11 },
|
||||
{ CLKID_AHB_UART1, "uart1", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 12 },
|
||||
{ CLKID_AHB_UART2, "uart2", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 13 },
|
||||
{ CLKID_AHB_UART3, "uart3", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 14 },
|
||||
{ CLKID_AHB_UART4, "uart4", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 15 },
|
||||
{ CLKID_AHB_UART5, "uart5", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 16 },
|
||||
{ CLKID_AHB_UART6, "uart6", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 17 },
|
||||
{ CLKID_AHB_UART7, "uart7", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 18 },
|
||||
{ CLKID_AHB_UART8, "uart8", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 19 },
|
||||
{ CLKID_AHB_UART9, "uart9", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 20 },
|
||||
{ CLKID_AHB_I2S0, "i2s0", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 21 },
|
||||
{ CLKID_AHB_I2C0, "i2c0", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 22 },
|
||||
{ CLKID_AHB_I2C1, "i2c1", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 23 },
|
||||
{ CLKID_AHB_SSP0, "ssp0", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 24 },
|
||||
{ CLKID_AHB_IOCONFIG, "ioconf", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 25 },
|
||||
{ CLKID_AHB_WDT, "wdt", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 26 },
|
||||
{ CLKID_AHB_CAN0, "can0", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 27 },
|
||||
{ CLKID_AHB_CAN1, "can1", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 28 },
|
||||
{ CLKID_AHB_MPWM, "mpwm", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 29 },
|
||||
{ CLKID_AHB_SPI0, "spi0", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 30 },
|
||||
{ CLKID_AHB_SPI1, "spi1", "ahb_div",
|
||||
HW_AHBCLKCTRL0, 31 },
|
||||
|
||||
{ CLKID_AHB_QEI, "qei", "ahb_div",
|
||||
HW_AHBCLKCTRL1, 0 },
|
||||
{ CLKID_AHB_QUADSPI0, "quadspi0", "ahb_div",
|
||||
HW_AHBCLKCTRL1, 1 },
|
||||
{ CLKID_AHB_CAMIF, "capmif", "ahb_div",
|
||||
HW_AHBCLKCTRL1, 2 },
|
||||
{ CLKID_AHB_LCDIF, "lcdif", "ahb_div",
|
||||
HW_AHBCLKCTRL1, 3 },
|
||||
{ CLKID_AHB_TIMER0, "timer0", "ahb_div",
|
||||
HW_AHBCLKCTRL1, 4 },
|
||||
{ CLKID_AHB_TIMER1, "timer1", "ahb_div",
|
||||
HW_AHBCLKCTRL1, 5 },
|
||||
{ CLKID_AHB_TIMER2, "timer2", "ahb_div",
|
||||
HW_AHBCLKCTRL1, 6 },
|
||||
{ CLKID_AHB_TIMER3, "timer3", "ahb_div",
|
||||
HW_AHBCLKCTRL1, 7 },
|
||||
{ CLKID_AHB_IRQ, "irq", "ahb_div",
|
||||
HW_AHBCLKCTRL1, 8, CLK_IGNORE_UNUSED},
|
||||
{ CLKID_AHB_RTC, "rtc", "ahb_div",
|
||||
HW_AHBCLKCTRL1, 9 },
|
||||
{ CLKID_AHB_NAND, "nand", "ahb_div",
|
||||
HW_AHBCLKCTRL1, 10 },
|
||||
{ CLKID_AHB_ADC0, "adc0", "ahb_div",
|
||||
HW_AHBCLKCTRL1, 11 },
|
||||
{ CLKID_AHB_LED, "led", "ahb_div",
|
||||
HW_AHBCLKCTRL1, 12 },
|
||||
{ CLKID_AHB_DAC0, "dac0", "ahb_div",
|
||||
HW_AHBCLKCTRL1, 13 },
|
||||
{ CLKID_AHB_LCD, "lcd", "ahb_div",
|
||||
HW_AHBCLKCTRL1, 14 },
|
||||
{ CLKID_AHB_I2S1, "i2s1", "ahb_div",
|
||||
HW_AHBCLKCTRL1, 15 },
|
||||
{ CLKID_AHB_MAC1, "mac1", "ahb_div",
|
||||
HW_AHBCLKCTRL1, 16 },
|
||||
};
|
||||
|
||||
static const char __initdata *main_mux_p[] = { NULL, NULL };
|
||||
static const char __initdata *i2s0_mux_p[] = { NULL, NULL, "i2s0m_div"};
|
||||
static const char __initdata *i2s1_mux_p[] = { NULL, NULL, "i2s1m_div"};
|
||||
static const char __initdata *clkout_mux_p[] = { NULL, NULL, "rtc"};
|
||||
static u32 three_mux_table[] = {0, 1, 3};
|
||||
|
||||
static struct asm9260_mux_clock asm9260_mux_clks[] __initdata = {
|
||||
{ 1, three_mux_table, "main_mux", main_mux_p,
|
||||
ARRAY_SIZE(main_mux_p), HW_MAINCLKSEL, },
|
||||
{ 1, three_mux_table, "uart_mux", main_mux_p,
|
||||
ARRAY_SIZE(main_mux_p), HW_UARTCLKSEL, },
|
||||
{ 1, three_mux_table, "wdt_mux", main_mux_p,
|
||||
ARRAY_SIZE(main_mux_p), HW_WDTCLKSEL, },
|
||||
{ 3, three_mux_table, "i2s0_mux", i2s0_mux_p,
|
||||
ARRAY_SIZE(i2s0_mux_p), HW_I2S0CLKSEL, },
|
||||
{ 3, three_mux_table, "i2s1_mux", i2s1_mux_p,
|
||||
ARRAY_SIZE(i2s1_mux_p), HW_I2S1CLKSEL, },
|
||||
{ 3, three_mux_table, "clkout_mux", clkout_mux_p,
|
||||
ARRAY_SIZE(clkout_mux_p), HW_CLKOUTCLKSEL, },
|
||||
};
|
||||
|
||||
static void __init asm9260_acc_init(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
const char *ref_clk, *pll_clk = "pll";
|
||||
u32 rate;
|
||||
int n;
|
||||
u32 accuracy = 0;
|
||||
|
||||
base = of_io_request_and_map(np, 0, np->name);
|
||||
if (!base)
|
||||
panic("%s: unable to map resource", np->name);
|
||||
|
||||
/* register pll */
|
||||
rate = (ioread32(base + HW_SYSPLLCTRL) & 0xffff) * 1000000;
|
||||
|
||||
ref_clk = of_clk_get_parent_name(np, 0);
|
||||
accuracy = clk_get_accuracy(__clk_lookup(ref_clk));
|
||||
clk = clk_register_fixed_rate_with_accuracy(NULL, pll_clk,
|
||||
ref_clk, 0, rate, accuracy);
|
||||
|
||||
if (IS_ERR(clk))
|
||||
panic("%s: can't register REFCLK. Check DT!", np->name);
|
||||
|
||||
for (n = 0; n < ARRAY_SIZE(asm9260_mux_clks); n++) {
|
||||
const struct asm9260_mux_clock *mc = &asm9260_mux_clks[n];
|
||||
|
||||
mc->parent_names[0] = ref_clk;
|
||||
mc->parent_names[1] = pll_clk;
|
||||
clk = clk_register_mux_table(NULL, mc->name, mc->parent_names,
|
||||
mc->num_parents, mc->flags, base + mc->offset,
|
||||
0, mc->mask, 0, mc->table, &asm9260_clk_lock);
|
||||
}
|
||||
|
||||
/* clock mux gate cells */
|
||||
for (n = 0; n < ARRAY_SIZE(asm9260_mux_gates); n++) {
|
||||
const struct asm9260_gate_data *gd = &asm9260_mux_gates[n];
|
||||
|
||||
clk = clk_register_gate(NULL, gd->name,
|
||||
gd->parent_name, gd->flags | CLK_SET_RATE_PARENT,
|
||||
base + gd->reg, gd->bit_idx, 0, &asm9260_clk_lock);
|
||||
}
|
||||
|
||||
/* clock div cells */
|
||||
for (n = 0; n < ARRAY_SIZE(asm9260_div_clks); n++) {
|
||||
const struct asm9260_div_clk *dc = &asm9260_div_clks[n];
|
||||
|
||||
clks[dc->idx] = clk_register_divider(NULL, dc->name,
|
||||
dc->parent_name, CLK_SET_RATE_PARENT,
|
||||
base + dc->reg, 0, 8, CLK_DIVIDER_ONE_BASED,
|
||||
&asm9260_clk_lock);
|
||||
}
|
||||
|
||||
/* clock ahb gate cells */
|
||||
for (n = 0; n < ARRAY_SIZE(asm9260_ahb_gates); n++) {
|
||||
const struct asm9260_gate_data *gd = &asm9260_ahb_gates[n];
|
||||
|
||||
clks[gd->idx] = clk_register_gate(NULL, gd->name,
|
||||
gd->parent_name, gd->flags, base + gd->reg,
|
||||
gd->bit_idx, 0, &asm9260_clk_lock);
|
||||
}
|
||||
|
||||
/* check for errors on leaf clocks */
|
||||
for (n = 0; n < MAX_CLKS; n++) {
|
||||
if (!IS_ERR(clks[n]))
|
||||
continue;
|
||||
|
||||
pr_err("%s: Unable to register leaf clock %d\n",
|
||||
np->full_name, n);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* register clk-provider */
|
||||
clk_data.clks = clks;
|
||||
clk_data.clk_num = MAX_CLKS;
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||
return;
|
||||
fail:
|
||||
iounmap(base);
|
||||
}
|
||||
CLK_OF_DECLARE(asm9260_acc, "alphascale,asm9260-clock-controller",
|
||||
asm9260_acc_init);
|
700
drivers/clk/clk-cdce706.c
Normal file
700
drivers/clk/clk-cdce706.c
Normal file
@ -0,0 +1,700 @@
|
||||
/*
|
||||
* TI CDCE706 programmable 3-PLL clock synthesizer driver
|
||||
*
|
||||
* Copyright (c) 2014 Cadence Design Systems Inc.
|
||||
*
|
||||
* Reference: http://www.ti.com/lit/ds/symlink/cdce706.pdf
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/rational.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define CDCE706_CLKIN_CLOCK 10
|
||||
#define CDCE706_CLKIN_SOURCE 11
|
||||
#define CDCE706_PLL_M_LOW(pll) (1 + 3 * (pll))
|
||||
#define CDCE706_PLL_N_LOW(pll) (2 + 3 * (pll))
|
||||
#define CDCE706_PLL_HI(pll) (3 + 3 * (pll))
|
||||
#define CDCE706_PLL_MUX 3
|
||||
#define CDCE706_PLL_FVCO 6
|
||||
#define CDCE706_DIVIDER(div) (13 + (div))
|
||||
#define CDCE706_CLKOUT(out) (19 + (out))
|
||||
|
||||
#define CDCE706_CLKIN_CLOCK_MASK 0x10
|
||||
#define CDCE706_CLKIN_SOURCE_SHIFT 6
|
||||
#define CDCE706_CLKIN_SOURCE_MASK 0xc0
|
||||
#define CDCE706_CLKIN_SOURCE_LVCMOS 0x40
|
||||
|
||||
#define CDCE706_PLL_MUX_MASK(pll) (0x80 >> (pll))
|
||||
#define CDCE706_PLL_LOW_M_MASK 0xff
|
||||
#define CDCE706_PLL_LOW_N_MASK 0xff
|
||||
#define CDCE706_PLL_HI_M_MASK 0x1
|
||||
#define CDCE706_PLL_HI_N_MASK 0x1e
|
||||
#define CDCE706_PLL_HI_N_SHIFT 1
|
||||
#define CDCE706_PLL_M_MAX 0x1ff
|
||||
#define CDCE706_PLL_N_MAX 0xfff
|
||||
#define CDCE706_PLL_FVCO_MASK(pll) (0x80 >> (pll))
|
||||
#define CDCE706_PLL_FREQ_MIN 80000000
|
||||
#define CDCE706_PLL_FREQ_MAX 300000000
|
||||
#define CDCE706_PLL_FREQ_HI 180000000
|
||||
|
||||
#define CDCE706_DIVIDER_PLL(div) (9 + (div) - ((div) > 2) - ((div) > 4))
|
||||
#define CDCE706_DIVIDER_PLL_SHIFT(div) ((div) < 2 ? 5 : 3 * ((div) & 1))
|
||||
#define CDCE706_DIVIDER_PLL_MASK(div) (0x7 << CDCE706_DIVIDER_PLL_SHIFT(div))
|
||||
#define CDCE706_DIVIDER_DIVIDER_MASK 0x7f
|
||||
#define CDCE706_DIVIDER_DIVIDER_MAX 0x7f
|
||||
|
||||
#define CDCE706_CLKOUT_DIVIDER_MASK 0x7
|
||||
#define CDCE706_CLKOUT_ENABLE_MASK 0x8
|
||||
|
||||
static struct regmap_config cdce706_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.val_format_endian = REGMAP_ENDIAN_NATIVE,
|
||||
};
|
||||
|
||||
#define to_hw_data(phw) (container_of((phw), struct cdce706_hw_data, hw))
|
||||
|
||||
struct cdce706_hw_data {
|
||||
struct cdce706_dev_data *dev_data;
|
||||
unsigned idx;
|
||||
unsigned parent;
|
||||
struct clk *clk;
|
||||
struct clk_hw hw;
|
||||
unsigned div;
|
||||
unsigned mul;
|
||||
unsigned mux;
|
||||
};
|
||||
|
||||
struct cdce706_dev_data {
|
||||
struct i2c_client *client;
|
||||
struct regmap *regmap;
|
||||
struct clk_onecell_data onecell;
|
||||
struct clk *clks[6];
|
||||
struct clk *clkin_clk[2];
|
||||
const char *clkin_name[2];
|
||||
struct cdce706_hw_data clkin[1];
|
||||
struct cdce706_hw_data pll[3];
|
||||
struct cdce706_hw_data divider[6];
|
||||
struct cdce706_hw_data clkout[6];
|
||||
};
|
||||
|
||||
static const char * const cdce706_source_name[] = {
|
||||
"clk_in0", "clk_in1",
|
||||
};
|
||||
|
||||
static const char *cdce706_clkin_name[] = {
|
||||
"clk_in",
|
||||
};
|
||||
|
||||
static const char * const cdce706_pll_name[] = {
|
||||
"pll1", "pll2", "pll3",
|
||||
};
|
||||
|
||||
static const char *cdce706_divider_parent_name[] = {
|
||||
"clk_in", "pll1", "pll2", "pll2", "pll3",
|
||||
};
|
||||
|
||||
static const char *cdce706_divider_name[] = {
|
||||
"p0", "p1", "p2", "p3", "p4", "p5",
|
||||
};
|
||||
|
||||
static const char * const cdce706_clkout_name[] = {
|
||||
"clk_out0", "clk_out1", "clk_out2", "clk_out3", "clk_out4", "clk_out5",
|
||||
};
|
||||
|
||||
static int cdce706_reg_read(struct cdce706_dev_data *dev_data, unsigned reg,
|
||||
unsigned *val)
|
||||
{
|
||||
int rc = regmap_read(dev_data->regmap, reg | 0x80, val);
|
||||
|
||||
if (rc < 0)
|
||||
dev_err(&dev_data->client->dev, "error reading reg %u", reg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cdce706_reg_write(struct cdce706_dev_data *dev_data, unsigned reg,
|
||||
unsigned val)
|
||||
{
|
||||
int rc = regmap_write(dev_data->regmap, reg | 0x80, val);
|
||||
|
||||
if (rc < 0)
|
||||
dev_err(&dev_data->client->dev, "error writing reg %u", reg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cdce706_reg_update(struct cdce706_dev_data *dev_data, unsigned reg,
|
||||
unsigned mask, unsigned val)
|
||||
{
|
||||
int rc = regmap_update_bits(dev_data->regmap, reg | 0x80, mask, val);
|
||||
|
||||
if (rc < 0)
|
||||
dev_err(&dev_data->client->dev, "error updating reg %u", reg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cdce706_clkin_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct cdce706_hw_data *hwd = to_hw_data(hw);
|
||||
|
||||
hwd->parent = index;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 cdce706_clkin_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct cdce706_hw_data *hwd = to_hw_data(hw);
|
||||
|
||||
return hwd->parent;
|
||||
}
|
||||
|
||||
static const struct clk_ops cdce706_clkin_ops = {
|
||||
.set_parent = cdce706_clkin_set_parent,
|
||||
.get_parent = cdce706_clkin_get_parent,
|
||||
};
|
||||
|
||||
static unsigned long cdce706_pll_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct cdce706_hw_data *hwd = to_hw_data(hw);
|
||||
|
||||
dev_dbg(&hwd->dev_data->client->dev,
|
||||
"%s, pll: %d, mux: %d, mul: %u, div: %u\n",
|
||||
__func__, hwd->idx, hwd->mux, hwd->mul, hwd->div);
|
||||
|
||||
if (!hwd->mux) {
|
||||
if (hwd->div && hwd->mul) {
|
||||
u64 res = (u64)parent_rate * hwd->mul;
|
||||
|
||||
do_div(res, hwd->div);
|
||||
return res;
|
||||
}
|
||||
} else {
|
||||
if (hwd->div)
|
||||
return parent_rate / hwd->div;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long cdce706_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct cdce706_hw_data *hwd = to_hw_data(hw);
|
||||
unsigned long mul, div;
|
||||
u64 res;
|
||||
|
||||
dev_dbg(&hwd->dev_data->client->dev,
|
||||
"%s, rate: %lu, parent_rate: %lu\n",
|
||||
__func__, rate, *parent_rate);
|
||||
|
||||
rational_best_approximation(rate, *parent_rate,
|
||||
CDCE706_PLL_N_MAX, CDCE706_PLL_M_MAX,
|
||||
&mul, &div);
|
||||
hwd->mul = mul;
|
||||
hwd->div = div;
|
||||
|
||||
dev_dbg(&hwd->dev_data->client->dev,
|
||||
"%s, pll: %d, mul: %lu, div: %lu\n",
|
||||
__func__, hwd->idx, mul, div);
|
||||
|
||||
res = (u64)*parent_rate * hwd->mul;
|
||||
do_div(res, hwd->div);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int cdce706_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct cdce706_hw_data *hwd = to_hw_data(hw);
|
||||
unsigned long mul = hwd->mul, div = hwd->div;
|
||||
int err;
|
||||
|
||||
dev_dbg(&hwd->dev_data->client->dev,
|
||||
"%s, pll: %d, mul: %lu, div: %lu\n",
|
||||
__func__, hwd->idx, mul, div);
|
||||
|
||||
err = cdce706_reg_update(hwd->dev_data,
|
||||
CDCE706_PLL_HI(hwd->idx),
|
||||
CDCE706_PLL_HI_M_MASK | CDCE706_PLL_HI_N_MASK,
|
||||
((div >> 8) & CDCE706_PLL_HI_M_MASK) |
|
||||
((mul >> (8 - CDCE706_PLL_HI_N_SHIFT)) &
|
||||
CDCE706_PLL_HI_N_MASK));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = cdce706_reg_write(hwd->dev_data,
|
||||
CDCE706_PLL_M_LOW(hwd->idx),
|
||||
div & CDCE706_PLL_LOW_M_MASK);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = cdce706_reg_write(hwd->dev_data,
|
||||
CDCE706_PLL_N_LOW(hwd->idx),
|
||||
mul & CDCE706_PLL_LOW_N_MASK);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = cdce706_reg_update(hwd->dev_data,
|
||||
CDCE706_PLL_FVCO,
|
||||
CDCE706_PLL_FVCO_MASK(hwd->idx),
|
||||
rate > CDCE706_PLL_FREQ_HI ?
|
||||
CDCE706_PLL_FVCO_MASK(hwd->idx) : 0);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct clk_ops cdce706_pll_ops = {
|
||||
.recalc_rate = cdce706_pll_recalc_rate,
|
||||
.round_rate = cdce706_pll_round_rate,
|
||||
.set_rate = cdce706_pll_set_rate,
|
||||
};
|
||||
|
||||
static int cdce706_divider_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct cdce706_hw_data *hwd = to_hw_data(hw);
|
||||
|
||||
if (hwd->parent == index)
|
||||
return 0;
|
||||
hwd->parent = index;
|
||||
return cdce706_reg_update(hwd->dev_data,
|
||||
CDCE706_DIVIDER_PLL(hwd->idx),
|
||||
CDCE706_DIVIDER_PLL_MASK(hwd->idx),
|
||||
index << CDCE706_DIVIDER_PLL_SHIFT(hwd->idx));
|
||||
}
|
||||
|
||||
static u8 cdce706_divider_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct cdce706_hw_data *hwd = to_hw_data(hw);
|
||||
|
||||
return hwd->parent;
|
||||
}
|
||||
|
||||
static unsigned long cdce706_divider_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct cdce706_hw_data *hwd = to_hw_data(hw);
|
||||
|
||||
dev_dbg(&hwd->dev_data->client->dev,
|
||||
"%s, divider: %d, div: %u\n",
|
||||
__func__, hwd->idx, hwd->div);
|
||||
if (hwd->div)
|
||||
return parent_rate / hwd->div;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long cdce706_divider_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct cdce706_hw_data *hwd = to_hw_data(hw);
|
||||
struct cdce706_dev_data *cdce = hwd->dev_data;
|
||||
unsigned long mul, div;
|
||||
|
||||
dev_dbg(&hwd->dev_data->client->dev,
|
||||
"%s, rate: %lu, parent_rate: %lu\n",
|
||||
__func__, rate, *parent_rate);
|
||||
|
||||
rational_best_approximation(rate, *parent_rate,
|
||||
1, CDCE706_DIVIDER_DIVIDER_MAX,
|
||||
&mul, &div);
|
||||
if (!mul)
|
||||
div = CDCE706_DIVIDER_DIVIDER_MAX;
|
||||
|
||||
if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
|
||||
unsigned long best_diff = rate;
|
||||
unsigned long best_div = 0;
|
||||
struct clk *gp_clk = cdce->clkin_clk[cdce->clkin[0].parent];
|
||||
unsigned long gp_rate = gp_clk ? clk_get_rate(gp_clk) : 0;
|
||||
|
||||
for (div = CDCE706_PLL_FREQ_MIN / rate; best_diff &&
|
||||
div <= CDCE706_PLL_FREQ_MAX / rate; ++div) {
|
||||
unsigned long n, m;
|
||||
unsigned long diff;
|
||||
unsigned long div_rate;
|
||||
u64 div_rate64;
|
||||
|
||||
if (rate * div < CDCE706_PLL_FREQ_MIN)
|
||||
continue;
|
||||
|
||||
rational_best_approximation(rate * div, gp_rate,
|
||||
CDCE706_PLL_N_MAX,
|
||||
CDCE706_PLL_M_MAX,
|
||||
&n, &m);
|
||||
div_rate64 = (u64)gp_rate * n;
|
||||
do_div(div_rate64, m);
|
||||
do_div(div_rate64, div);
|
||||
div_rate = div_rate64;
|
||||
diff = max(div_rate, rate) - min(div_rate, rate);
|
||||
|
||||
if (diff < best_diff) {
|
||||
best_diff = diff;
|
||||
best_div = div;
|
||||
dev_dbg(&hwd->dev_data->client->dev,
|
||||
"%s, %lu * %lu / %lu / %lu = %lu\n",
|
||||
__func__, gp_rate, n, m, div, div_rate);
|
||||
}
|
||||
}
|
||||
|
||||
div = best_div;
|
||||
|
||||
dev_dbg(&hwd->dev_data->client->dev,
|
||||
"%s, altering parent rate: %lu -> %lu\n",
|
||||
__func__, *parent_rate, rate * div);
|
||||
*parent_rate = rate * div;
|
||||
}
|
||||
hwd->div = div;
|
||||
|
||||
dev_dbg(&hwd->dev_data->client->dev,
|
||||
"%s, divider: %d, div: %lu\n",
|
||||
__func__, hwd->idx, div);
|
||||
|
||||
return *parent_rate / div;
|
||||
}
|
||||
|
||||
static int cdce706_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct cdce706_hw_data *hwd = to_hw_data(hw);
|
||||
|
||||
dev_dbg(&hwd->dev_data->client->dev,
|
||||
"%s, divider: %d, div: %u\n",
|
||||
__func__, hwd->idx, hwd->div);
|
||||
|
||||
return cdce706_reg_update(hwd->dev_data,
|
||||
CDCE706_DIVIDER(hwd->idx),
|
||||
CDCE706_DIVIDER_DIVIDER_MASK,
|
||||
hwd->div);
|
||||
}
|
||||
|
||||
static const struct clk_ops cdce706_divider_ops = {
|
||||
.set_parent = cdce706_divider_set_parent,
|
||||
.get_parent = cdce706_divider_get_parent,
|
||||
.recalc_rate = cdce706_divider_recalc_rate,
|
||||
.round_rate = cdce706_divider_round_rate,
|
||||
.set_rate = cdce706_divider_set_rate,
|
||||
};
|
||||
|
||||
static int cdce706_clkout_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct cdce706_hw_data *hwd = to_hw_data(hw);
|
||||
|
||||
return cdce706_reg_update(hwd->dev_data, CDCE706_CLKOUT(hwd->idx),
|
||||
CDCE706_CLKOUT_ENABLE_MASK,
|
||||
CDCE706_CLKOUT_ENABLE_MASK);
|
||||
}
|
||||
|
||||
static void cdce706_clkout_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct cdce706_hw_data *hwd = to_hw_data(hw);
|
||||
|
||||
cdce706_reg_update(hwd->dev_data, CDCE706_CLKOUT(hwd->idx),
|
||||
CDCE706_CLKOUT_ENABLE_MASK, 0);
|
||||
}
|
||||
|
||||
static int cdce706_clkout_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct cdce706_hw_data *hwd = to_hw_data(hw);
|
||||
|
||||
if (hwd->parent == index)
|
||||
return 0;
|
||||
hwd->parent = index;
|
||||
return cdce706_reg_update(hwd->dev_data,
|
||||
CDCE706_CLKOUT(hwd->idx),
|
||||
CDCE706_CLKOUT_ENABLE_MASK, index);
|
||||
}
|
||||
|
||||
static u8 cdce706_clkout_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct cdce706_hw_data *hwd = to_hw_data(hw);
|
||||
|
||||
return hwd->parent;
|
||||
}
|
||||
|
||||
static unsigned long cdce706_clkout_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return parent_rate;
|
||||
}
|
||||
|
||||
static long cdce706_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
*parent_rate = rate;
|
||||
return rate;
|
||||
}
|
||||
|
||||
static int cdce706_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops cdce706_clkout_ops = {
|
||||
.prepare = cdce706_clkout_prepare,
|
||||
.unprepare = cdce706_clkout_unprepare,
|
||||
.set_parent = cdce706_clkout_set_parent,
|
||||
.get_parent = cdce706_clkout_get_parent,
|
||||
.recalc_rate = cdce706_clkout_recalc_rate,
|
||||
.round_rate = cdce706_clkout_round_rate,
|
||||
.set_rate = cdce706_clkout_set_rate,
|
||||
};
|
||||
|
||||
static int cdce706_register_hw(struct cdce706_dev_data *cdce,
|
||||
struct cdce706_hw_data *hw, unsigned num_hw,
|
||||
const char * const *clk_names,
|
||||
struct clk_init_data *init)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < num_hw; ++i, ++hw) {
|
||||
init->name = clk_names[i];
|
||||
hw->dev_data = cdce;
|
||||
hw->idx = i;
|
||||
hw->hw.init = init;
|
||||
hw->clk = devm_clk_register(&cdce->client->dev,
|
||||
&hw->hw);
|
||||
if (IS_ERR(hw->clk)) {
|
||||
dev_err(&cdce->client->dev, "Failed to register %s\n",
|
||||
clk_names[i]);
|
||||
return PTR_ERR(hw->clk);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdce706_register_clkin(struct cdce706_dev_data *cdce)
|
||||
{
|
||||
struct clk_init_data init = {
|
||||
.ops = &cdce706_clkin_ops,
|
||||
.parent_names = cdce->clkin_name,
|
||||
.num_parents = ARRAY_SIZE(cdce->clkin_name),
|
||||
};
|
||||
unsigned i;
|
||||
int ret;
|
||||
unsigned clock, source;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cdce->clkin_name); ++i) {
|
||||
struct clk *parent = devm_clk_get(&cdce->client->dev,
|
||||
cdce706_source_name[i]);
|
||||
|
||||
if (IS_ERR(parent)) {
|
||||
cdce->clkin_name[i] = cdce706_source_name[i];
|
||||
} else {
|
||||
cdce->clkin_name[i] = __clk_get_name(parent);
|
||||
cdce->clkin_clk[i] = parent;
|
||||
}
|
||||
}
|
||||
|
||||
ret = cdce706_reg_read(cdce, CDCE706_CLKIN_SOURCE, &source);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if ((source & CDCE706_CLKIN_SOURCE_MASK) ==
|
||||
CDCE706_CLKIN_SOURCE_LVCMOS) {
|
||||
ret = cdce706_reg_read(cdce, CDCE706_CLKIN_CLOCK, &clock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
cdce->clkin[0].parent = !!(clock & CDCE706_CLKIN_CLOCK_MASK);
|
||||
}
|
||||
|
||||
ret = cdce706_register_hw(cdce, cdce->clkin,
|
||||
ARRAY_SIZE(cdce->clkin),
|
||||
cdce706_clkin_name, &init);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cdce706_register_plls(struct cdce706_dev_data *cdce)
|
||||
{
|
||||
struct clk_init_data init = {
|
||||
.ops = &cdce706_pll_ops,
|
||||
.parent_names = cdce706_clkin_name,
|
||||
.num_parents = ARRAY_SIZE(cdce706_clkin_name),
|
||||
};
|
||||
unsigned i;
|
||||
int ret;
|
||||
unsigned mux;
|
||||
|
||||
ret = cdce706_reg_read(cdce, CDCE706_PLL_MUX, &mux);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cdce->pll); ++i) {
|
||||
unsigned m, n, v;
|
||||
|
||||
ret = cdce706_reg_read(cdce, CDCE706_PLL_M_LOW(i), &m);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = cdce706_reg_read(cdce, CDCE706_PLL_N_LOW(i), &n);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = cdce706_reg_read(cdce, CDCE706_PLL_HI(i), &v);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
cdce->pll[i].div = m | ((v & CDCE706_PLL_HI_M_MASK) << 8);
|
||||
cdce->pll[i].mul = n | ((v & CDCE706_PLL_HI_N_MASK) <<
|
||||
(8 - CDCE706_PLL_HI_N_SHIFT));
|
||||
cdce->pll[i].mux = mux & CDCE706_PLL_MUX_MASK(i);
|
||||
dev_dbg(&cdce->client->dev,
|
||||
"%s: i: %u, div: %u, mul: %u, mux: %d\n", __func__, i,
|
||||
cdce->pll[i].div, cdce->pll[i].mul, cdce->pll[i].mux);
|
||||
}
|
||||
|
||||
ret = cdce706_register_hw(cdce, cdce->pll,
|
||||
ARRAY_SIZE(cdce->pll),
|
||||
cdce706_pll_name, &init);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cdce706_register_dividers(struct cdce706_dev_data *cdce)
|
||||
{
|
||||
struct clk_init_data init = {
|
||||
.ops = &cdce706_divider_ops,
|
||||
.parent_names = cdce706_divider_parent_name,
|
||||
.num_parents = ARRAY_SIZE(cdce706_divider_parent_name),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
};
|
||||
unsigned i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cdce->divider); ++i) {
|
||||
unsigned val;
|
||||
|
||||
ret = cdce706_reg_read(cdce, CDCE706_DIVIDER_PLL(i), &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
cdce->divider[i].parent =
|
||||
(val & CDCE706_DIVIDER_PLL_MASK(i)) >>
|
||||
CDCE706_DIVIDER_PLL_SHIFT(i);
|
||||
|
||||
ret = cdce706_reg_read(cdce, CDCE706_DIVIDER(i), &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
cdce->divider[i].div = val & CDCE706_DIVIDER_DIVIDER_MASK;
|
||||
dev_dbg(&cdce->client->dev,
|
||||
"%s: i: %u, parent: %u, div: %u\n", __func__, i,
|
||||
cdce->divider[i].parent, cdce->divider[i].div);
|
||||
}
|
||||
|
||||
ret = cdce706_register_hw(cdce, cdce->divider,
|
||||
ARRAY_SIZE(cdce->divider),
|
||||
cdce706_divider_name, &init);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cdce706_register_clkouts(struct cdce706_dev_data *cdce)
|
||||
{
|
||||
struct clk_init_data init = {
|
||||
.ops = &cdce706_clkout_ops,
|
||||
.parent_names = cdce706_divider_name,
|
||||
.num_parents = ARRAY_SIZE(cdce706_divider_name),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
};
|
||||
unsigned i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cdce->clkout); ++i) {
|
||||
unsigned val;
|
||||
|
||||
ret = cdce706_reg_read(cdce, CDCE706_CLKOUT(i), &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
cdce->clkout[i].parent = val & CDCE706_CLKOUT_DIVIDER_MASK;
|
||||
dev_dbg(&cdce->client->dev,
|
||||
"%s: i: %u, parent: %u\n", __func__, i,
|
||||
cdce->clkout[i].parent);
|
||||
}
|
||||
|
||||
ret = cdce706_register_hw(cdce, cdce->clkout,
|
||||
ARRAY_SIZE(cdce->clkout),
|
||||
cdce706_clkout_name, &init);
|
||||
for (i = 0; i < ARRAY_SIZE(cdce->clkout); ++i)
|
||||
cdce->clks[i] = cdce->clkout[i].clk;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cdce706_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
||||
struct cdce706_dev_data *cdce;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -EIO;
|
||||
|
||||
cdce = devm_kzalloc(&client->dev, sizeof(*cdce), GFP_KERNEL);
|
||||
if (!cdce)
|
||||
return -ENOMEM;
|
||||
|
||||
cdce->client = client;
|
||||
cdce->regmap = devm_regmap_init_i2c(client, &cdce706_regmap_config);
|
||||
if (IS_ERR(cdce->regmap)) {
|
||||
dev_err(&client->dev, "Failed to initialize regmap\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, cdce);
|
||||
|
||||
ret = cdce706_register_clkin(cdce);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = cdce706_register_plls(cdce);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = cdce706_register_dividers(cdce);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = cdce706_register_clkouts(cdce);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
cdce->onecell.clks = cdce->clks;
|
||||
cdce->onecell.clk_num = ARRAY_SIZE(cdce->clks);
|
||||
ret = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get,
|
||||
&cdce->onecell);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cdce706_remove(struct i2c_client *client)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id cdce706_dt_match[] = {
|
||||
{ .compatible = "ti,cdce706" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cdce706_dt_match);
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id cdce706_id[] = {
|
||||
{ "cdce706", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cdce706_id);
|
||||
|
||||
static struct i2c_driver cdce706_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "cdce706",
|
||||
.of_match_table = of_match_ptr(cdce706_dt_match),
|
||||
},
|
||||
.probe = cdce706_probe,
|
||||
.remove = cdce706_remove,
|
||||
.id_table = cdce706_id,
|
||||
};
|
||||
module_i2c_driver(cdce706_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>");
|
||||
MODULE_DESCRIPTION("TI CDCE 706 clock synthesizer driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -56,6 +56,8 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw,
|
||||
}
|
||||
|
||||
static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_p)
|
||||
{
|
||||
@ -73,7 +75,9 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
if (rate_hw && rate_ops && rate_ops->determine_rate) {
|
||||
rate_hw->clk = hw->clk;
|
||||
return rate_ops->determine_rate(rate_hw, rate, best_parent_rate,
|
||||
return rate_ops->determine_rate(rate_hw, rate, min_rate,
|
||||
max_rate,
|
||||
best_parent_rate,
|
||||
best_parent_p);
|
||||
} else if (rate_hw && rate_ops && rate_ops->round_rate &&
|
||||
mux_hw && mux_ops && mux_ops->set_parent) {
|
||||
@ -117,7 +121,8 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
return best_rate;
|
||||
} else if (mux_hw && mux_ops && mux_ops->determine_rate) {
|
||||
mux_hw->clk = hw->clk;
|
||||
return mux_ops->determine_rate(mux_hw, rate, best_parent_rate,
|
||||
return mux_ops->determine_rate(mux_hw, rate, min_rate,
|
||||
max_rate, best_parent_rate,
|
||||
best_parent_p);
|
||||
} else {
|
||||
pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n");
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
|
||||
|
||||
#define div_mask(d) ((1 << ((d)->width)) - 1)
|
||||
#define div_mask(width) ((1 << (width)) - 1)
|
||||
|
||||
static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
|
||||
{
|
||||
@ -54,15 +54,16 @@ static unsigned int _get_table_mindiv(const struct clk_div_table *table)
|
||||
return mindiv;
|
||||
}
|
||||
|
||||
static unsigned int _get_maxdiv(struct clk_divider *divider)
|
||||
static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width,
|
||||
unsigned long flags)
|
||||
{
|
||||
if (divider->flags & CLK_DIVIDER_ONE_BASED)
|
||||
return div_mask(divider);
|
||||
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
return 1 << div_mask(divider);
|
||||
if (divider->table)
|
||||
return _get_table_maxdiv(divider->table);
|
||||
return div_mask(divider) + 1;
|
||||
if (flags & CLK_DIVIDER_ONE_BASED)
|
||||
return div_mask(width);
|
||||
if (flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
return 1 << div_mask(width);
|
||||
if (table)
|
||||
return _get_table_maxdiv(table);
|
||||
return div_mask(width) + 1;
|
||||
}
|
||||
|
||||
static unsigned int _get_table_div(const struct clk_div_table *table,
|
||||
@ -76,14 +77,15 @@ static unsigned int _get_table_div(const struct clk_div_table *table,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int _get_div(struct clk_divider *divider, unsigned int val)
|
||||
static unsigned int _get_div(const struct clk_div_table *table,
|
||||
unsigned int val, unsigned long flags)
|
||||
{
|
||||
if (divider->flags & CLK_DIVIDER_ONE_BASED)
|
||||
if (flags & CLK_DIVIDER_ONE_BASED)
|
||||
return val;
|
||||
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
if (flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
return 1 << val;
|
||||
if (divider->table)
|
||||
return _get_table_div(divider->table, val);
|
||||
if (table)
|
||||
return _get_table_div(table, val);
|
||||
return val + 1;
|
||||
}
|
||||
|
||||
@ -98,29 +100,28 @@ static unsigned int _get_table_val(const struct clk_div_table *table,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int _get_val(struct clk_divider *divider, unsigned int div)
|
||||
static unsigned int _get_val(const struct clk_div_table *table,
|
||||
unsigned int div, unsigned long flags)
|
||||
{
|
||||
if (divider->flags & CLK_DIVIDER_ONE_BASED)
|
||||
if (flags & CLK_DIVIDER_ONE_BASED)
|
||||
return div;
|
||||
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
if (flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
return __ffs(div);
|
||||
if (divider->table)
|
||||
return _get_table_val(divider->table, div);
|
||||
if (table)
|
||||
return _get_table_val(table, div);
|
||||
return div - 1;
|
||||
}
|
||||
|
||||
static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate,
|
||||
unsigned int val,
|
||||
const struct clk_div_table *table,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct clk_divider *divider = to_clk_divider(hw);
|
||||
unsigned int div, val;
|
||||
unsigned int div;
|
||||
|
||||
val = clk_readl(divider->reg) >> divider->shift;
|
||||
val &= div_mask(divider);
|
||||
|
||||
div = _get_div(divider, val);
|
||||
div = _get_div(table, val, flags);
|
||||
if (!div) {
|
||||
WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO),
|
||||
WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO),
|
||||
"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
|
||||
__clk_get_name(hw->clk));
|
||||
return parent_rate;
|
||||
@ -128,6 +129,20 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
|
||||
|
||||
return DIV_ROUND_UP(parent_rate, div);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(divider_recalc_rate);
|
||||
|
||||
static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_divider *divider = to_clk_divider(hw);
|
||||
unsigned int val;
|
||||
|
||||
val = clk_readl(divider->reg) >> divider->shift;
|
||||
val &= div_mask(divider->width);
|
||||
|
||||
return divider_recalc_rate(hw, parent_rate, val, divider->table,
|
||||
divider->flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* The reverse of DIV_ROUND_UP: The maximum number which
|
||||
@ -146,12 +161,13 @@ static bool _is_valid_table_div(const struct clk_div_table *table,
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
|
||||
static bool _is_valid_div(const struct clk_div_table *table, unsigned int div,
|
||||
unsigned long flags)
|
||||
{
|
||||
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
if (flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
return is_power_of_2(div);
|
||||
if (divider->table)
|
||||
return _is_valid_table_div(divider->table, div);
|
||||
if (table)
|
||||
return _is_valid_table_div(table, div);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -191,71 +207,76 @@ static int _round_down_table(const struct clk_div_table *table, int div)
|
||||
return down;
|
||||
}
|
||||
|
||||
static int _div_round_up(struct clk_divider *divider,
|
||||
unsigned long parent_rate, unsigned long rate)
|
||||
static int _div_round_up(const struct clk_div_table *table,
|
||||
unsigned long parent_rate, unsigned long rate,
|
||||
unsigned long flags)
|
||||
{
|
||||
int div = DIV_ROUND_UP(parent_rate, rate);
|
||||
|
||||
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
if (flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
div = __roundup_pow_of_two(div);
|
||||
if (divider->table)
|
||||
div = _round_up_table(divider->table, div);
|
||||
if (table)
|
||||
div = _round_up_table(table, div);
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
static int _div_round_closest(struct clk_divider *divider,
|
||||
unsigned long parent_rate, unsigned long rate)
|
||||
static int _div_round_closest(const struct clk_div_table *table,
|
||||
unsigned long parent_rate, unsigned long rate,
|
||||
unsigned long flags)
|
||||
{
|
||||
int up, down, div;
|
||||
|
||||
up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate);
|
||||
|
||||
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) {
|
||||
if (flags & CLK_DIVIDER_POWER_OF_TWO) {
|
||||
up = __roundup_pow_of_two(div);
|
||||
down = __rounddown_pow_of_two(div);
|
||||
} else if (divider->table) {
|
||||
up = _round_up_table(divider->table, div);
|
||||
down = _round_down_table(divider->table, div);
|
||||
} else if (table) {
|
||||
up = _round_up_table(table, div);
|
||||
down = _round_down_table(table, div);
|
||||
}
|
||||
|
||||
return (up - div) <= (div - down) ? up : down;
|
||||
}
|
||||
|
||||
static int _div_round(struct clk_divider *divider, unsigned long parent_rate,
|
||||
unsigned long rate)
|
||||
static int _div_round(const struct clk_div_table *table,
|
||||
unsigned long parent_rate, unsigned long rate,
|
||||
unsigned long flags)
|
||||
{
|
||||
if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST)
|
||||
return _div_round_closest(divider, parent_rate, rate);
|
||||
if (flags & CLK_DIVIDER_ROUND_CLOSEST)
|
||||
return _div_round_closest(table, parent_rate, rate, flags);
|
||||
|
||||
return _div_round_up(divider, parent_rate, rate);
|
||||
return _div_round_up(table, parent_rate, rate, flags);
|
||||
}
|
||||
|
||||
static bool _is_best_div(struct clk_divider *divider,
|
||||
unsigned long rate, unsigned long now, unsigned long best)
|
||||
static bool _is_best_div(unsigned long rate, unsigned long now,
|
||||
unsigned long best, unsigned long flags)
|
||||
{
|
||||
if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST)
|
||||
if (flags & CLK_DIVIDER_ROUND_CLOSEST)
|
||||
return abs(rate - now) < abs(rate - best);
|
||||
|
||||
return now <= rate && now > best;
|
||||
}
|
||||
|
||||
static int _next_div(struct clk_divider *divider, int div)
|
||||
static int _next_div(const struct clk_div_table *table, int div,
|
||||
unsigned long flags)
|
||||
{
|
||||
div++;
|
||||
|
||||
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
if (flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
return __roundup_pow_of_two(div);
|
||||
if (divider->table)
|
||||
return _round_up_table(divider->table, div);
|
||||
if (table)
|
||||
return _round_up_table(table, div);
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *best_parent_rate)
|
||||
unsigned long *best_parent_rate,
|
||||
const struct clk_div_table *table, u8 width,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct clk_divider *divider = to_clk_divider(hw);
|
||||
int i, bestdiv = 0;
|
||||
unsigned long parent_rate, best = 0, now, maxdiv;
|
||||
unsigned long parent_rate_saved = *best_parent_rate;
|
||||
@ -263,19 +284,11 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
|
||||
if (!rate)
|
||||
rate = 1;
|
||||
|
||||
/* if read only, just return current value */
|
||||
if (divider->flags & CLK_DIVIDER_READ_ONLY) {
|
||||
bestdiv = readl(divider->reg) >> divider->shift;
|
||||
bestdiv &= div_mask(divider);
|
||||
bestdiv = _get_div(divider, bestdiv);
|
||||
return bestdiv;
|
||||
}
|
||||
|
||||
maxdiv = _get_maxdiv(divider);
|
||||
maxdiv = _get_maxdiv(table, width, flags);
|
||||
|
||||
if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
|
||||
parent_rate = *best_parent_rate;
|
||||
bestdiv = _div_round(divider, parent_rate, rate);
|
||||
bestdiv = _div_round(table, parent_rate, rate, flags);
|
||||
bestdiv = bestdiv == 0 ? 1 : bestdiv;
|
||||
bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
|
||||
return bestdiv;
|
||||
@ -287,8 +300,8 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
|
||||
*/
|
||||
maxdiv = min(ULONG_MAX / rate, maxdiv);
|
||||
|
||||
for (i = 1; i <= maxdiv; i = _next_div(divider, i)) {
|
||||
if (!_is_valid_div(divider, i))
|
||||
for (i = 1; i <= maxdiv; i = _next_div(table, i, flags)) {
|
||||
if (!_is_valid_div(table, i, flags))
|
||||
continue;
|
||||
if (rate * i == parent_rate_saved) {
|
||||
/*
|
||||
@ -302,7 +315,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
|
||||
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
|
||||
MULT_ROUND_UP(rate, i));
|
||||
now = DIV_ROUND_UP(parent_rate, i);
|
||||
if (_is_best_div(divider, rate, now, best)) {
|
||||
if (_is_best_div(rate, now, best, flags)) {
|
||||
bestdiv = i;
|
||||
best = now;
|
||||
*best_parent_rate = parent_rate;
|
||||
@ -310,48 +323,79 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
|
||||
}
|
||||
|
||||
if (!bestdiv) {
|
||||
bestdiv = _get_maxdiv(divider);
|
||||
bestdiv = _get_maxdiv(table, width, flags);
|
||||
*best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
|
||||
}
|
||||
|
||||
return bestdiv;
|
||||
}
|
||||
|
||||
static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
long divider_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate, const struct clk_div_table *table,
|
||||
u8 width, unsigned long flags)
|
||||
{
|
||||
int div;
|
||||
div = clk_divider_bestdiv(hw, rate, prate);
|
||||
|
||||
div = clk_divider_bestdiv(hw, rate, prate, table, width, flags);
|
||||
|
||||
return DIV_ROUND_UP(*prate, div);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(divider_round_rate);
|
||||
|
||||
static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct clk_divider *divider = to_clk_divider(hw);
|
||||
int bestdiv;
|
||||
|
||||
/* if read only, just return current value */
|
||||
if (divider->flags & CLK_DIVIDER_READ_ONLY) {
|
||||
bestdiv = readl(divider->reg) >> divider->shift;
|
||||
bestdiv &= div_mask(divider->width);
|
||||
bestdiv = _get_div(divider->table, bestdiv, divider->flags);
|
||||
return bestdiv;
|
||||
}
|
||||
|
||||
return divider_round_rate(hw, rate, prate, divider->table,
|
||||
divider->width, divider->flags);
|
||||
}
|
||||
|
||||
int divider_get_val(unsigned long rate, unsigned long parent_rate,
|
||||
const struct clk_div_table *table, u8 width,
|
||||
unsigned long flags)
|
||||
{
|
||||
unsigned int div, value;
|
||||
|
||||
div = DIV_ROUND_UP(parent_rate, rate);
|
||||
|
||||
if (!_is_valid_div(table, div, flags))
|
||||
return -EINVAL;
|
||||
|
||||
value = _get_val(table, div, flags);
|
||||
|
||||
return min_t(unsigned int, value, div_mask(width));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(divider_get_val);
|
||||
|
||||
static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_divider *divider = to_clk_divider(hw);
|
||||
unsigned int div, value;
|
||||
unsigned int value;
|
||||
unsigned long flags = 0;
|
||||
u32 val;
|
||||
|
||||
div = DIV_ROUND_UP(parent_rate, rate);
|
||||
|
||||
if (!_is_valid_div(divider, div))
|
||||
return -EINVAL;
|
||||
|
||||
value = _get_val(divider, div);
|
||||
|
||||
if (value > div_mask(divider))
|
||||
value = div_mask(divider);
|
||||
value = divider_get_val(rate, parent_rate, divider->table,
|
||||
divider->width, divider->flags);
|
||||
|
||||
if (divider->lock)
|
||||
spin_lock_irqsave(divider->lock, flags);
|
||||
|
||||
if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
|
||||
val = div_mask(divider) << (divider->shift + 16);
|
||||
val = div_mask(divider->width) << (divider->shift + 16);
|
||||
} else {
|
||||
val = clk_readl(divider->reg);
|
||||
val &= ~(div_mask(divider) << divider->shift);
|
||||
val &= ~(div_mask(divider->width) << divider->shift);
|
||||
}
|
||||
val |= value << divider->shift;
|
||||
clk_writel(val, divider->reg);
|
||||
@ -463,3 +507,19 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
|
||||
width, clk_divider_flags, table, lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_register_divider_table);
|
||||
|
||||
void clk_unregister_divider(struct clk *clk)
|
||||
{
|
||||
struct clk_divider *div;
|
||||
struct clk_hw *hw;
|
||||
|
||||
hw = __clk_get_hw(clk);
|
||||
if (!hw)
|
||||
return;
|
||||
|
||||
div = to_clk_divider(hw);
|
||||
|
||||
clk_unregister(clk);
|
||||
kfree(div);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_unregister_divider);
|
||||
|
@ -128,7 +128,7 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
|
||||
struct clk_init_data init;
|
||||
|
||||
if (clk_gate_flags & CLK_GATE_HIWORD_MASK) {
|
||||
if (bit_idx > 16) {
|
||||
if (bit_idx > 15) {
|
||||
pr_err("gate bit exceeds LOWORD field\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
@ -162,3 +162,19 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
|
||||
return clk;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_register_gate);
|
||||
|
||||
void clk_unregister_gate(struct clk *clk)
|
||||
{
|
||||
struct clk_gate *gate;
|
||||
struct clk_hw *hw;
|
||||
|
||||
hw = __clk_get_hw(clk);
|
||||
if (!hw)
|
||||
return;
|
||||
|
||||
gate = to_clk_gate(hw);
|
||||
|
||||
clk_unregister(clk);
|
||||
kfree(gate);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_unregister_gate);
|
||||
|
@ -177,3 +177,19 @@ struct clk *clk_register_mux(struct device *dev, const char *name,
|
||||
NULL, lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_register_mux);
|
||||
|
||||
void clk_unregister_mux(struct clk *clk)
|
||||
{
|
||||
struct clk_mux *mux;
|
||||
struct clk_hw *hw;
|
||||
|
||||
hw = __clk_get_hw(clk);
|
||||
if (!hw)
|
||||
return;
|
||||
|
||||
mux = to_clk_mux(hw);
|
||||
|
||||
clk_unregister(clk);
|
||||
kfree(mux);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_unregister_mux);
|
||||
|
@ -5,8 +5,11 @@
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* clock driver for Freescale PowerPC corenet SoCs.
|
||||
* clock driver for Freescale QorIQ SoCs.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
@ -19,6 +22,7 @@
|
||||
struct cmux_clk {
|
||||
struct clk_hw hw;
|
||||
void __iomem *reg;
|
||||
unsigned int clk_per_pll;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
@ -27,14 +31,12 @@ struct cmux_clk {
|
||||
#define CLKSEL_ADJUST BIT(0)
|
||||
#define to_cmux_clk(p) container_of(p, struct cmux_clk, hw)
|
||||
|
||||
static unsigned int clocks_per_pll;
|
||||
|
||||
static int cmux_set_parent(struct clk_hw *hw, u8 idx)
|
||||
{
|
||||
struct cmux_clk *clk = to_cmux_clk(hw);
|
||||
u32 clksel;
|
||||
|
||||
clksel = ((idx / clocks_per_pll) << 2) + idx % clocks_per_pll;
|
||||
clksel = ((idx / clk->clk_per_pll) << 2) + idx % clk->clk_per_pll;
|
||||
if (clk->flags & CLKSEL_ADJUST)
|
||||
clksel += 8;
|
||||
clksel = (clksel & 0xf) << CLKSEL_SHIFT;
|
||||
@ -52,12 +54,12 @@ static u8 cmux_get_parent(struct clk_hw *hw)
|
||||
clksel = (clksel >> CLKSEL_SHIFT) & 0xf;
|
||||
if (clk->flags & CLKSEL_ADJUST)
|
||||
clksel -= 8;
|
||||
clksel = (clksel >> 2) * clocks_per_pll + clksel % 4;
|
||||
clksel = (clksel >> 2) * clk->clk_per_pll + clksel % 4;
|
||||
|
||||
return clksel;
|
||||
}
|
||||
|
||||
const struct clk_ops cmux_ops = {
|
||||
static const struct clk_ops cmux_ops = {
|
||||
.get_parent = cmux_get_parent,
|
||||
.set_parent = cmux_set_parent,
|
||||
};
|
||||
@ -72,6 +74,7 @@ static void __init core_mux_init(struct device_node *np)
|
||||
u32 offset;
|
||||
const char *clk_name;
|
||||
const char **parent_names;
|
||||
struct of_phandle_args clkspec;
|
||||
|
||||
rc = of_property_read_u32(np, "reg", &offset);
|
||||
if (rc) {
|
||||
@ -85,32 +88,40 @@ static void __init core_mux_init(struct device_node *np)
|
||||
pr_err("%s: get clock count error\n", np->name);
|
||||
return;
|
||||
}
|
||||
parent_names = kzalloc((sizeof(char *) * count), GFP_KERNEL);
|
||||
if (!parent_names) {
|
||||
pr_err("%s: could not allocate parent_names\n", __func__);
|
||||
parent_names = kcalloc(count, sizeof(char *), GFP_KERNEL);
|
||||
if (!parent_names)
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
parent_names[i] = of_clk_get_parent_name(np, i);
|
||||
|
||||
cmux_clk = kzalloc(sizeof(struct cmux_clk), GFP_KERNEL);
|
||||
if (!cmux_clk) {
|
||||
pr_err("%s: could not allocate cmux_clk\n", __func__);
|
||||
cmux_clk = kzalloc(sizeof(*cmux_clk), GFP_KERNEL);
|
||||
if (!cmux_clk)
|
||||
goto err_name;
|
||||
}
|
||||
|
||||
cmux_clk->reg = of_iomap(np, 0);
|
||||
if (!cmux_clk->reg) {
|
||||
pr_err("%s: could not map register\n", __func__);
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", 0,
|
||||
&clkspec);
|
||||
if (rc) {
|
||||
pr_err("%s: parse clock node error\n", __func__);
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
cmux_clk->clk_per_pll = of_property_count_strings(clkspec.np,
|
||||
"clock-output-names");
|
||||
of_node_put(clkspec.np);
|
||||
|
||||
node = of_find_compatible_node(NULL, NULL, "fsl,p4080-clockgen");
|
||||
if (node && (offset >= 0x80))
|
||||
cmux_clk->flags = CLKSEL_ADJUST;
|
||||
|
||||
rc = of_property_read_string_index(np, "clock-output-names",
|
||||
0, &clk_name);
|
||||
0, &clk_name);
|
||||
if (rc) {
|
||||
pr_err("%s: read clock names error\n", np->name);
|
||||
goto err_clk;
|
||||
@ -132,7 +143,7 @@ static void __init core_mux_init(struct device_node *np)
|
||||
rc = of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
if (rc) {
|
||||
pr_err("Could not register clock provider for node:%s\n",
|
||||
np->name);
|
||||
np->name);
|
||||
goto err_clk;
|
||||
}
|
||||
goto err_name;
|
||||
@ -155,7 +166,7 @@ static void __init core_pll_init(struct device_node *np)
|
||||
|
||||
base = of_iomap(np, 0);
|
||||
if (!base) {
|
||||
pr_err("clk-ppc: iomap error\n");
|
||||
pr_err("iomap error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -181,24 +192,17 @@ static void __init core_pll_init(struct device_node *np)
|
||||
goto err_map;
|
||||
}
|
||||
|
||||
/* output clock number per PLL */
|
||||
clocks_per_pll = count;
|
||||
|
||||
subclks = kzalloc(sizeof(struct clk *) * count, GFP_KERNEL);
|
||||
if (!subclks) {
|
||||
pr_err("%s: could not allocate subclks\n", __func__);
|
||||
subclks = kcalloc(count, sizeof(struct clk *), GFP_KERNEL);
|
||||
if (!subclks)
|
||||
goto err_map;
|
||||
}
|
||||
|
||||
onecell_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
|
||||
if (!onecell_data) {
|
||||
pr_err("%s: could not allocate onecell_data\n", __func__);
|
||||
onecell_data = kmalloc(sizeof(*onecell_data), GFP_KERNEL);
|
||||
if (!onecell_data)
|
||||
goto err_clks;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
rc = of_property_read_string_index(np, "clock-output-names",
|
||||
i, &clk_name);
|
||||
i, &clk_name);
|
||||
if (rc) {
|
||||
pr_err("%s: could not get clock names\n", np->name);
|
||||
goto err_cell;
|
||||
@ -230,7 +234,7 @@ static void __init core_pll_init(struct device_node *np)
|
||||
rc = of_clk_add_provider(np, of_clk_src_onecell_get, onecell_data);
|
||||
if (rc) {
|
||||
pr_err("Could not register clk provider for node:%s\n",
|
||||
np->name);
|
||||
np->name);
|
||||
goto err_cell;
|
||||
}
|
||||
|
||||
@ -252,7 +256,7 @@ static void __init sysclk_init(struct device_node *node)
|
||||
u32 rate;
|
||||
|
||||
if (!np) {
|
||||
pr_err("ppc-clk: could not get parent node\n");
|
||||
pr_err("could not get parent node\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -267,40 +271,9 @@ static void __init sysclk_init(struct device_node *node)
|
||||
if (!IS_ERR(clk))
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
}
|
||||
|
||||
static const struct of_device_id clk_match[] __initconst = {
|
||||
{ .compatible = "fsl,qoriq-sysclk-1.0", .data = sysclk_init, },
|
||||
{ .compatible = "fsl,qoriq-sysclk-2.0", .data = sysclk_init, },
|
||||
{ .compatible = "fsl,qoriq-core-pll-1.0", .data = core_pll_init, },
|
||||
{ .compatible = "fsl,qoriq-core-pll-2.0", .data = core_pll_init, },
|
||||
{ .compatible = "fsl,qoriq-core-mux-1.0", .data = core_mux_init, },
|
||||
{ .compatible = "fsl,qoriq-core-mux-2.0", .data = core_mux_init, },
|
||||
{}
|
||||
};
|
||||
|
||||
static int __init ppc_corenet_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
of_clk_init(clk_match);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ppc_clk_ids[] __initconst = {
|
||||
{ .compatible = "fsl,qoriq-clockgen-1.0", },
|
||||
{ .compatible = "fsl,qoriq-clockgen-2.0", },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct platform_driver ppc_corenet_clk_driver = {
|
||||
.driver = {
|
||||
.name = "ppc_corenet_clock",
|
||||
.of_match_table = ppc_clk_ids,
|
||||
},
|
||||
.probe = ppc_corenet_clk_probe,
|
||||
};
|
||||
|
||||
static int __init ppc_corenet_clk_init(void)
|
||||
{
|
||||
return platform_driver_register(&ppc_corenet_clk_driver);
|
||||
}
|
||||
subsys_initcall(ppc_corenet_clk_init);
|
||||
CLK_OF_DECLARE(qoriq_sysclk_1, "fsl,qoriq-sysclk-1.0", sysclk_init);
|
||||
CLK_OF_DECLARE(qoriq_sysclk_2, "fsl,qoriq-sysclk-2.0", sysclk_init);
|
||||
CLK_OF_DECLARE(qoriq_core_pll_1, "fsl,qoriq-core-pll-1.0", core_pll_init);
|
||||
CLK_OF_DECLARE(qoriq_core_pll_2, "fsl,qoriq-core-pll-2.0", core_pll_init);
|
||||
CLK_OF_DECLARE(qoriq_core_mux_1, "fsl,qoriq-core-mux-1.0", core_mux_init);
|
||||
CLK_OF_DECLARE(qoriq_core_mux_2, "fsl,qoriq-core-mux-2.0", core_mux_init);
|
1000
drivers/clk/clk.c
1000
drivers/clk/clk.c
File diff suppressed because it is too large
Load Diff
@ -9,9 +9,14 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
struct clk_hw;
|
||||
|
||||
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
|
||||
struct clk *of_clk_get_by_clkspec(struct of_phandle_args *clkspec);
|
||||
struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec);
|
||||
void of_clk_lock(void);
|
||||
void of_clk_unlock(void);
|
||||
#endif
|
||||
|
||||
struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
|
||||
const char *con_id);
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include "clk.h"
|
||||
@ -53,7 +54,7 @@ struct clk *of_clk_get_by_clkspec(struct of_phandle_args *clkspec)
|
||||
return clk;
|
||||
}
|
||||
|
||||
struct clk *of_clk_get(struct device_node *np, int index)
|
||||
static struct clk *__of_clk_get(struct device_node *np, int index)
|
||||
{
|
||||
struct of_phandle_args clkspec;
|
||||
struct clk *clk;
|
||||
@ -69,20 +70,24 @@ struct clk *of_clk_get(struct device_node *np, int index)
|
||||
|
||||
clk = of_clk_get_by_clkspec(&clkspec);
|
||||
of_node_put(clkspec.np);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
struct clk *of_clk_get(struct device_node *np, int index)
|
||||
{
|
||||
struct clk *clk = __of_clk_get(np, index);
|
||||
|
||||
if (!IS_ERR(clk))
|
||||
clk = __clk_create_clk(__clk_get_hw(clk), np->full_name, NULL);
|
||||
|
||||
return clk;
|
||||
}
|
||||
EXPORT_SYMBOL(of_clk_get);
|
||||
|
||||
/**
|
||||
* of_clk_get_by_name() - Parse and lookup a clock referenced by a device node
|
||||
* @np: pointer to clock consumer node
|
||||
* @name: name of consumer's clock input, or NULL for the first clock reference
|
||||
*
|
||||
* This function parses the clocks and clock-names properties,
|
||||
* and uses them to look up the struct clk from the registered list of clock
|
||||
* providers.
|
||||
*/
|
||||
struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
|
||||
static struct clk *__of_clk_get_by_name(struct device_node *np,
|
||||
const char *dev_id,
|
||||
const char *name)
|
||||
{
|
||||
struct clk *clk = ERR_PTR(-ENOENT);
|
||||
|
||||
@ -97,9 +102,11 @@ struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
|
||||
*/
|
||||
if (name)
|
||||
index = of_property_match_string(np, "clock-names", name);
|
||||
clk = of_clk_get(np, index);
|
||||
if (!IS_ERR(clk))
|
||||
clk = __of_clk_get(np, index);
|
||||
if (!IS_ERR(clk)) {
|
||||
clk = __clk_create_clk(__clk_get_hw(clk), dev_id, name);
|
||||
break;
|
||||
}
|
||||
else if (name && index >= 0) {
|
||||
if (PTR_ERR(clk) != -EPROBE_DEFER)
|
||||
pr_err("ERROR: could not get clock %s:%s(%i)\n",
|
||||
@ -119,7 +126,33 @@ struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_clk_get_by_name() - Parse and lookup a clock referenced by a device node
|
||||
* @np: pointer to clock consumer node
|
||||
* @name: name of consumer's clock input, or NULL for the first clock reference
|
||||
*
|
||||
* This function parses the clocks and clock-names properties,
|
||||
* and uses them to look up the struct clk from the registered list of clock
|
||||
* providers.
|
||||
*/
|
||||
struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
|
||||
{
|
||||
if (!np)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
return __of_clk_get_by_name(np, np->full_name, name);
|
||||
}
|
||||
EXPORT_SYMBOL(of_clk_get_by_name);
|
||||
|
||||
#else /* defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) */
|
||||
|
||||
static struct clk *__of_clk_get_by_name(struct device_node *np,
|
||||
const char *dev_id,
|
||||
const char *name)
|
||||
{
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -168,14 +201,29 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
|
||||
struct clk *clk_get_sys(const char *dev_id, const char *con_id)
|
||||
{
|
||||
struct clk_lookup *cl;
|
||||
struct clk *clk = NULL;
|
||||
|
||||
mutex_lock(&clocks_mutex);
|
||||
|
||||
cl = clk_find(dev_id, con_id);
|
||||
if (cl && !__clk_get(cl->clk))
|
||||
if (!cl)
|
||||
goto out;
|
||||
|
||||
if (!__clk_get(cl->clk)) {
|
||||
cl = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_COMMON_CLK)
|
||||
clk = __clk_create_clk(__clk_get_hw(cl->clk), dev_id, con_id);
|
||||
#else
|
||||
clk = cl->clk;
|
||||
#endif
|
||||
|
||||
out:
|
||||
mutex_unlock(&clocks_mutex);
|
||||
|
||||
return cl ? cl->clk : ERR_PTR(-ENOENT);
|
||||
return cl ? clk : ERR_PTR(-ENOENT);
|
||||
}
|
||||
EXPORT_SYMBOL(clk_get_sys);
|
||||
|
||||
@ -185,10 +233,8 @@ struct clk *clk_get(struct device *dev, const char *con_id)
|
||||
struct clk *clk;
|
||||
|
||||
if (dev) {
|
||||
clk = of_clk_get_by_name(dev->of_node, con_id);
|
||||
if (!IS_ERR(clk))
|
||||
return clk;
|
||||
if (PTR_ERR(clk) == -EPROBE_DEFER)
|
||||
clk = __of_clk_get_by_name(dev->of_node, dev_id, con_id);
|
||||
if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER)
|
||||
return clk;
|
||||
}
|
||||
|
||||
@ -331,6 +377,7 @@ int clk_register_clkdev(struct clk *clk, const char *con_id,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_register_clkdev);
|
||||
|
||||
/**
|
||||
* clk_register_clkdevs - register a set of clk_lookup for a struct clk
|
||||
|
@ -295,6 +295,8 @@ static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw,
|
||||
}
|
||||
|
||||
static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_p)
|
||||
{
|
||||
|
@ -202,6 +202,8 @@ error:
|
||||
}
|
||||
|
||||
static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_clk)
|
||||
{
|
||||
|
@ -1,3 +1,4 @@
|
||||
obj-y += clk-pxa.o
|
||||
obj-$(CONFIG_PXA25x) += clk-pxa25x.o
|
||||
obj-$(CONFIG_PXA27x) += clk-pxa27x.o
|
||||
obj-$(CONFIG_PXA3xx) += clk-pxa3xx.o
|
||||
|
364
drivers/clk/pxa/clk-pxa3xx.c
Normal file
364
drivers/clk/pxa/clk-pxa3xx.c
Normal file
@ -0,0 +1,364 @@
|
||||
/*
|
||||
* Marvell PXA3xxx family clocks
|
||||
*
|
||||
* Copyright (C) 2014 Robert Jarzmik
|
||||
*
|
||||
* Heavily inspired from former arch/arm/mach-pxa/pxa3xx.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* For non-devicetree platforms. Once pxa is fully converted to devicetree, this
|
||||
* should go away.
|
||||
*/
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/of.h>
|
||||
#include <mach/smemc.h>
|
||||
#include <mach/pxa3xx-regs.h>
|
||||
|
||||
#include <dt-bindings/clock/pxa-clock.h>
|
||||
#include "clk-pxa.h"
|
||||
|
||||
#define KHz 1000
|
||||
#define MHz (1000 * 1000)
|
||||
|
||||
enum {
|
||||
PXA_CORE_60Mhz = 0,
|
||||
PXA_CORE_RUN,
|
||||
PXA_CORE_TURBO,
|
||||
};
|
||||
|
||||
enum {
|
||||
PXA_BUS_60Mhz = 0,
|
||||
PXA_BUS_HSS,
|
||||
};
|
||||
|
||||
/* crystal frequency to HSIO bus frequency multiplier (HSS) */
|
||||
static unsigned char hss_mult[4] = { 8, 12, 16, 24 };
|
||||
|
||||
/* crystal frequency to static memory controller multiplier (SMCFS) */
|
||||
static unsigned int smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, };
|
||||
static unsigned int df_clkdiv[4] = { 1, 2, 4, 1 };
|
||||
|
||||
static const char * const get_freq_khz[] = {
|
||||
"core", "ring_osc_60mhz", "run", "cpll", "system_bus"
|
||||
};
|
||||
|
||||
/*
|
||||
* Get the clock frequency as reflected by ACSR and the turbo flag.
|
||||
* We assume these values have been applied via a fcs.
|
||||
* If info is not 0 we also display the current settings.
|
||||
*/
|
||||
unsigned int pxa3xx_get_clk_frequency_khz(int info)
|
||||
{
|
||||
struct clk *clk;
|
||||
unsigned long clks[5];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
clk = clk_get(NULL, get_freq_khz[i]);
|
||||
if (IS_ERR(clk)) {
|
||||
clks[i] = 0;
|
||||
} else {
|
||||
clks[i] = clk_get_rate(clk);
|
||||
clk_put(clk);
|
||||
}
|
||||
}
|
||||
if (info) {
|
||||
pr_info("RO Mode clock: %ld.%02ldMHz\n",
|
||||
clks[1] / 1000000, (clks[0] % 1000000) / 10000);
|
||||
pr_info("Run Mode clock: %ld.%02ldMHz\n",
|
||||
clks[2] / 1000000, (clks[1] % 1000000) / 10000);
|
||||
pr_info("Turbo Mode clock: %ld.%02ldMHz\n",
|
||||
clks[3] / 1000000, (clks[2] % 1000000) / 10000);
|
||||
pr_info("System bus clock: %ld.%02ldMHz\n",
|
||||
clks[4] / 1000000, (clks[4] % 1000000) / 10000);
|
||||
}
|
||||
return (unsigned int)clks[0];
|
||||
}
|
||||
|
||||
static unsigned long clk_pxa3xx_ac97_get_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
unsigned long ac97_div, rate;
|
||||
|
||||
ac97_div = AC97_DIV;
|
||||
|
||||
/* This may loose precision for some rates but won't for the
|
||||
* standard 24.576MHz.
|
||||
*/
|
||||
rate = parent_rate / 2;
|
||||
rate /= ((ac97_div >> 12) & 0x7fff);
|
||||
rate *= (ac97_div & 0xfff);
|
||||
|
||||
return rate;
|
||||
}
|
||||
PARENTS(clk_pxa3xx_ac97) = { "spll_624mhz" };
|
||||
RATE_RO_OPS(clk_pxa3xx_ac97, "ac97");
|
||||
|
||||
static unsigned long clk_pxa3xx_smemc_get_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
unsigned long acsr = ACSR;
|
||||
unsigned long memclkcfg = __raw_readl(MEMCLKCFG);
|
||||
|
||||
return (parent_rate / 48) * smcfs_mult[(acsr >> 23) & 0x7] /
|
||||
df_clkdiv[(memclkcfg >> 16) & 0x3];
|
||||
}
|
||||
PARENTS(clk_pxa3xx_smemc) = { "spll_624mhz" };
|
||||
RATE_RO_OPS(clk_pxa3xx_smemc, "smemc");
|
||||
|
||||
static bool pxa3xx_is_ring_osc_forced(void)
|
||||
{
|
||||
unsigned long acsr = ACSR;
|
||||
|
||||
return acsr & ACCR_D0CS;
|
||||
}
|
||||
|
||||
PARENTS(pxa3xx_pbus) = { "ring_osc_60mhz", "spll_624mhz" };
|
||||
PARENTS(pxa3xx_32Khz_bus) = { "osc_32_768khz", "osc_32_768khz" };
|
||||
PARENTS(pxa3xx_13MHz_bus) = { "osc_13mhz", "osc_13mhz" };
|
||||
PARENTS(pxa3xx_ac97_bus) = { "ring_osc_60mhz", "ac97" };
|
||||
PARENTS(pxa3xx_sbus) = { "ring_osc_60mhz", "system_bus" };
|
||||
PARENTS(pxa3xx_smemcbus) = { "ring_osc_60mhz", "smemc" };
|
||||
|
||||
#define CKEN_AB(bit) ((CKEN_ ## bit > 31) ? &CKENA : &CKENB)
|
||||
#define PXA3XX_CKEN(dev_id, con_id, parents, mult_lp, div_lp, mult_hp, \
|
||||
div_hp, bit, is_lp, flags) \
|
||||
PXA_CKEN(dev_id, con_id, bit, parents, mult_lp, div_lp, \
|
||||
mult_hp, div_hp, is_lp, CKEN_AB(bit), \
|
||||
(CKEN_ ## bit % 32), flags)
|
||||
#define PXA3XX_PBUS_CKEN(dev_id, con_id, bit, mult_lp, div_lp, \
|
||||
mult_hp, div_hp, delay) \
|
||||
PXA3XX_CKEN(dev_id, con_id, pxa3xx_pbus_parents, mult_lp, \
|
||||
div_lp, mult_hp, div_hp, bit, pxa3xx_is_ring_osc_forced, 0)
|
||||
#define PXA3XX_CKEN_1RATE(dev_id, con_id, bit, parents) \
|
||||
PXA_CKEN_1RATE(dev_id, con_id, bit, parents, \
|
||||
CKEN_AB(bit), (CKEN_ ## bit % 32), 0)
|
||||
|
||||
static struct desc_clk_cken pxa3xx_clocks[] __initdata = {
|
||||
PXA3XX_PBUS_CKEN("pxa2xx-uart.0", NULL, FFUART, 1, 4, 1, 42, 1),
|
||||
PXA3XX_PBUS_CKEN("pxa2xx-uart.1", NULL, BTUART, 1, 4, 1, 42, 1),
|
||||
PXA3XX_PBUS_CKEN("pxa2xx-uart.2", NULL, STUART, 1, 4, 1, 42, 1),
|
||||
PXA3XX_PBUS_CKEN("pxa2xx-i2c.0", NULL, I2C, 2, 5, 1, 19, 0),
|
||||
PXA3XX_PBUS_CKEN("pxa27x-udc", NULL, UDC, 1, 4, 1, 13, 5),
|
||||
PXA3XX_PBUS_CKEN("pxa27x-ohci", NULL, USBH, 1, 4, 1, 13, 0),
|
||||
PXA3XX_PBUS_CKEN("pxa3xx-u2d", NULL, USB2, 1, 4, 1, 13, 0),
|
||||
PXA3XX_PBUS_CKEN("pxa27x-pwm.0", NULL, PWM0, 1, 6, 1, 48, 0),
|
||||
PXA3XX_PBUS_CKEN("pxa27x-pwm.1", NULL, PWM1, 1, 6, 1, 48, 0),
|
||||
PXA3XX_PBUS_CKEN("pxa2xx-mci.0", NULL, MMC1, 1, 4, 1, 24, 0),
|
||||
PXA3XX_PBUS_CKEN("pxa2xx-mci.1", NULL, MMC2, 1, 4, 1, 24, 0),
|
||||
PXA3XX_PBUS_CKEN("pxa2xx-mci.2", NULL, MMC3, 1, 4, 1, 24, 0),
|
||||
|
||||
PXA3XX_CKEN_1RATE("pxa27x-keypad", NULL, KEYPAD,
|
||||
pxa3xx_32Khz_bus_parents),
|
||||
PXA3XX_CKEN_1RATE("pxa3xx-ssp.0", NULL, SSP1, pxa3xx_13MHz_bus_parents),
|
||||
PXA3XX_CKEN_1RATE("pxa3xx-ssp.1", NULL, SSP2, pxa3xx_13MHz_bus_parents),
|
||||
PXA3XX_CKEN_1RATE("pxa3xx-ssp.2", NULL, SSP3, pxa3xx_13MHz_bus_parents),
|
||||
PXA3XX_CKEN_1RATE("pxa3xx-ssp.3", NULL, SSP4, pxa3xx_13MHz_bus_parents),
|
||||
|
||||
PXA3XX_CKEN(NULL, "AC97CLK", pxa3xx_ac97_bus_parents, 1, 4, 1, 1, AC97,
|
||||
pxa3xx_is_ring_osc_forced, 0),
|
||||
PXA3XX_CKEN(NULL, "CAMCLK", pxa3xx_sbus_parents, 1, 2, 1, 1, CAMERA,
|
||||
pxa3xx_is_ring_osc_forced, 0),
|
||||
PXA3XX_CKEN("pxa2xx-fb", NULL, pxa3xx_sbus_parents, 1, 1, 1, 1, LCD,
|
||||
pxa3xx_is_ring_osc_forced, 0),
|
||||
PXA3XX_CKEN("pxa2xx-pcmcia", NULL, pxa3xx_smemcbus_parents, 1, 4,
|
||||
1, 1, SMC, pxa3xx_is_ring_osc_forced, CLK_IGNORE_UNUSED),
|
||||
};
|
||||
|
||||
static struct desc_clk_cken pxa300_310_clocks[] __initdata = {
|
||||
|
||||
PXA3XX_PBUS_CKEN("pxa3xx-gcu", NULL, PXA300_GCU, 1, 1, 1, 1, 0),
|
||||
PXA3XX_PBUS_CKEN("pxa3xx-nand", NULL, NAND, 1, 2, 1, 4, 0),
|
||||
PXA3XX_CKEN_1RATE("pxa3xx-gpio", NULL, GPIO, pxa3xx_13MHz_bus_parents),
|
||||
};
|
||||
|
||||
static struct desc_clk_cken pxa320_clocks[] __initdata = {
|
||||
PXA3XX_PBUS_CKEN("pxa3xx-nand", NULL, NAND, 1, 2, 1, 6, 0),
|
||||
PXA3XX_PBUS_CKEN("pxa3xx-gcu", NULL, PXA320_GCU, 1, 1, 1, 1, 0),
|
||||
PXA3XX_CKEN_1RATE("pxa3xx-gpio", NULL, GPIO, pxa3xx_13MHz_bus_parents),
|
||||
};
|
||||
|
||||
static struct desc_clk_cken pxa93x_clocks[] __initdata = {
|
||||
|
||||
PXA3XX_PBUS_CKEN("pxa3xx-gcu", NULL, PXA300_GCU, 1, 1, 1, 1, 0),
|
||||
PXA3XX_PBUS_CKEN("pxa3xx-nand", NULL, NAND, 1, 2, 1, 4, 0),
|
||||
PXA3XX_CKEN_1RATE("pxa93x-gpio", NULL, GPIO, pxa3xx_13MHz_bus_parents),
|
||||
};
|
||||
|
||||
static unsigned long clk_pxa3xx_system_bus_get_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
unsigned long acsr = ACSR;
|
||||
unsigned int hss = (acsr >> 14) & 0x3;
|
||||
|
||||
if (pxa3xx_is_ring_osc_forced())
|
||||
return parent_rate;
|
||||
return parent_rate / 48 * hss_mult[hss];
|
||||
}
|
||||
|
||||
static u8 clk_pxa3xx_system_bus_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
if (pxa3xx_is_ring_osc_forced())
|
||||
return PXA_BUS_60Mhz;
|
||||
else
|
||||
return PXA_BUS_HSS;
|
||||
}
|
||||
|
||||
PARENTS(clk_pxa3xx_system_bus) = { "ring_osc_60mhz", "spll_624mhz" };
|
||||
MUX_RO_RATE_RO_OPS(clk_pxa3xx_system_bus, "system_bus");
|
||||
|
||||
static unsigned long clk_pxa3xx_core_get_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return parent_rate;
|
||||
}
|
||||
|
||||
static u8 clk_pxa3xx_core_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
unsigned long xclkcfg;
|
||||
unsigned int t;
|
||||
|
||||
if (pxa3xx_is_ring_osc_forced())
|
||||
return PXA_CORE_60Mhz;
|
||||
|
||||
/* Read XCLKCFG register turbo bit */
|
||||
__asm__ __volatile__("mrc\tp14, 0, %0, c6, c0, 0" : "=r"(xclkcfg));
|
||||
t = xclkcfg & 0x1;
|
||||
|
||||
if (t)
|
||||
return PXA_CORE_TURBO;
|
||||
return PXA_CORE_RUN;
|
||||
}
|
||||
PARENTS(clk_pxa3xx_core) = { "ring_osc_60mhz", "run", "cpll" };
|
||||
MUX_RO_RATE_RO_OPS(clk_pxa3xx_core, "core");
|
||||
|
||||
static unsigned long clk_pxa3xx_run_get_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
unsigned long acsr = ACSR;
|
||||
unsigned int xn = (acsr & ACCR_XN_MASK) >> 8;
|
||||
unsigned int t, xclkcfg;
|
||||
|
||||
/* Read XCLKCFG register turbo bit */
|
||||
__asm__ __volatile__("mrc\tp14, 0, %0, c6, c0, 0" : "=r"(xclkcfg));
|
||||
t = xclkcfg & 0x1;
|
||||
|
||||
return t ? (parent_rate / xn) * 2 : parent_rate;
|
||||
}
|
||||
PARENTS(clk_pxa3xx_run) = { "cpll" };
|
||||
RATE_RO_OPS(clk_pxa3xx_run, "run");
|
||||
|
||||
static unsigned long clk_pxa3xx_cpll_get_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
unsigned long acsr = ACSR;
|
||||
unsigned int xn = (acsr & ACCR_XN_MASK) >> 8;
|
||||
unsigned int xl = acsr & ACCR_XL_MASK;
|
||||
unsigned int t, xclkcfg;
|
||||
|
||||
/* Read XCLKCFG register turbo bit */
|
||||
__asm__ __volatile__("mrc\tp14, 0, %0, c6, c0, 0" : "=r"(xclkcfg));
|
||||
t = xclkcfg & 0x1;
|
||||
|
||||
pr_info("RJK: parent_rate=%lu, xl=%u, xn=%u\n", parent_rate, xl, xn);
|
||||
return t ? parent_rate * xl * xn : parent_rate * xl;
|
||||
}
|
||||
PARENTS(clk_pxa3xx_cpll) = { "osc_13mhz" };
|
||||
RATE_RO_OPS(clk_pxa3xx_cpll, "cpll");
|
||||
|
||||
static void __init pxa3xx_register_core(void)
|
||||
{
|
||||
clk_register_clk_pxa3xx_cpll();
|
||||
clk_register_clk_pxa3xx_run();
|
||||
|
||||
clkdev_pxa_register(CLK_CORE, "core", NULL,
|
||||
clk_register_clk_pxa3xx_core());
|
||||
}
|
||||
|
||||
static void __init pxa3xx_register_plls(void)
|
||||
{
|
||||
clk_register_fixed_rate(NULL, "osc_13mhz", NULL,
|
||||
CLK_GET_RATE_NOCACHE | CLK_IS_ROOT,
|
||||
13 * MHz);
|
||||
clk_register_fixed_rate(NULL, "osc_32_768khz", NULL,
|
||||
CLK_GET_RATE_NOCACHE | CLK_IS_ROOT,
|
||||
32768);
|
||||
clk_register_fixed_rate(NULL, "ring_osc_120mhz", NULL,
|
||||
CLK_GET_RATE_NOCACHE | CLK_IS_ROOT,
|
||||
120 * MHz);
|
||||
clk_register_fixed_rate(NULL, "clk_dummy", NULL, CLK_IS_ROOT, 0);
|
||||
clk_register_fixed_factor(NULL, "spll_624mhz", "osc_13mhz", 0, 48, 1);
|
||||
clk_register_fixed_factor(NULL, "ring_osc_60mhz", "ring_osc_120mhz",
|
||||
0, 1, 2);
|
||||
}
|
||||
|
||||
#define DUMMY_CLK(_con_id, _dev_id, _parent) \
|
||||
{ .con_id = _con_id, .dev_id = _dev_id, .parent = _parent }
|
||||
struct dummy_clk {
|
||||
const char *con_id;
|
||||
const char *dev_id;
|
||||
const char *parent;
|
||||
};
|
||||
static struct dummy_clk dummy_clks[] __initdata = {
|
||||
DUMMY_CLK(NULL, "pxa93x-gpio", "osc_13mhz"),
|
||||
DUMMY_CLK(NULL, "sa1100-rtc", "osc_32_768khz"),
|
||||
DUMMY_CLK("UARTCLK", "pxa2xx-ir", "STUART"),
|
||||
DUMMY_CLK(NULL, "pxa3xx-pwri2c.1", "osc_13mhz"),
|
||||
};
|
||||
|
||||
static void __init pxa3xx_dummy_clocks_init(void)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct dummy_clk *d;
|
||||
const char *name;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dummy_clks); i++) {
|
||||
d = &dummy_clks[i];
|
||||
name = d->dev_id ? d->dev_id : d->con_id;
|
||||
clk = clk_register_fixed_factor(NULL, name, d->parent, 0, 1, 1);
|
||||
clk_register_clkdev(clk, d->con_id, d->dev_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void __init pxa3xx_base_clocks_init(void)
|
||||
{
|
||||
pxa3xx_register_plls();
|
||||
pxa3xx_register_core();
|
||||
clk_register_clk_pxa3xx_system_bus();
|
||||
clk_register_clk_pxa3xx_ac97();
|
||||
clk_register_clk_pxa3xx_smemc();
|
||||
clk_register_gate(NULL, "CLK_POUT", "osc_13mhz", 0,
|
||||
(void __iomem *)&OSCC, 11, 0, NULL);
|
||||
}
|
||||
|
||||
int __init pxa3xx_clocks_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pxa3xx_base_clocks_init();
|
||||
pxa3xx_dummy_clocks_init();
|
||||
ret = clk_pxa_cken_init(pxa3xx_clocks, ARRAY_SIZE(pxa3xx_clocks));
|
||||
if (ret)
|
||||
return ret;
|
||||
if (cpu_is_pxa320())
|
||||
return clk_pxa_cken_init(pxa320_clocks,
|
||||
ARRAY_SIZE(pxa320_clocks));
|
||||
if (cpu_is_pxa300() || cpu_is_pxa310())
|
||||
return clk_pxa_cken_init(pxa300_310_clocks,
|
||||
ARRAY_SIZE(pxa300_310_clocks));
|
||||
return clk_pxa_cken_init(pxa93x_clocks, ARRAY_SIZE(pxa93x_clocks));
|
||||
}
|
||||
|
||||
static void __init pxa3xx_dt_clocks_init(struct device_node *np)
|
||||
{
|
||||
pxa3xx_clocks_init();
|
||||
clk_pxa_dt_common_init(np);
|
||||
}
|
||||
CLK_OF_DECLARE(pxa_clks, "marvell,pxa300-clocks", pxa3xx_dt_clocks_init);
|
@ -29,6 +29,15 @@ config IPQ_GCC_806X
|
||||
Say Y if you want to use peripheral devices such as UART, SPI,
|
||||
i2c, USB, SD/eMMC, etc.
|
||||
|
||||
config IPQ_LCC_806X
|
||||
tristate "IPQ806x LPASS Clock Controller"
|
||||
select IPQ_GCC_806X
|
||||
depends on COMMON_CLK_QCOM
|
||||
help
|
||||
Support for the LPASS clock controller on ipq806x devices.
|
||||
Say Y if you want to use audio devices such as i2s, pcm,
|
||||
S/PDIF, etc.
|
||||
|
||||
config MSM_GCC_8660
|
||||
tristate "MSM8660 Global Clock Controller"
|
||||
depends on COMMON_CLK_QCOM
|
||||
@ -45,6 +54,15 @@ config MSM_GCC_8960
|
||||
Say Y if you want to use peripheral devices such as UART, SPI,
|
||||
i2c, USB, SD/eMMC, SATA, PCIe, etc.
|
||||
|
||||
config MSM_LCC_8960
|
||||
tristate "APQ8064/MSM8960 LPASS Clock Controller"
|
||||
select MSM_GCC_8960
|
||||
depends on COMMON_CLK_QCOM
|
||||
help
|
||||
Support for the LPASS clock controller on apq8064/msm8960 devices.
|
||||
Say Y if you want to use audio devices such as i2s, pcm,
|
||||
SLIMBus, etc.
|
||||
|
||||
config MSM_MMCC_8960
|
||||
tristate "MSM8960 Multimedia Clock Controller"
|
||||
select MSM_GCC_8960
|
||||
|
@ -6,13 +6,17 @@ clk-qcom-y += clk-pll.o
|
||||
clk-qcom-y += clk-rcg.o
|
||||
clk-qcom-y += clk-rcg2.o
|
||||
clk-qcom-y += clk-branch.o
|
||||
clk-qcom-y += clk-regmap-divider.o
|
||||
clk-qcom-y += clk-regmap-mux.o
|
||||
clk-qcom-y += reset.o
|
||||
|
||||
obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
|
||||
obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o
|
||||
obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o
|
||||
obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o
|
||||
obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o
|
||||
obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o
|
||||
obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o
|
||||
obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o
|
||||
obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
|
||||
obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
|
||||
|
@ -141,6 +141,7 @@ struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate)
|
||||
|
||||
static long
|
||||
clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate, unsigned long max_rate,
|
||||
unsigned long *p_rate, struct clk_hw **p)
|
||||
{
|
||||
struct clk_pll *pll = to_clk_pll(hw);
|
||||
|
@ -368,6 +368,7 @@ clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
||||
|
||||
static long _freq_tbl_determine_rate(struct clk_hw *hw,
|
||||
const struct freq_tbl *f, unsigned long rate,
|
||||
unsigned long min_rate, unsigned long max_rate,
|
||||
unsigned long *p_rate, struct clk_hw **p_hw)
|
||||
{
|
||||
unsigned long clk_flags;
|
||||
@ -397,22 +398,27 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
|
||||
}
|
||||
|
||||
static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate, unsigned long max_rate,
|
||||
unsigned long *p_rate, struct clk_hw **p)
|
||||
{
|
||||
struct clk_rcg *rcg = to_clk_rcg(hw);
|
||||
|
||||
return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p);
|
||||
return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate,
|
||||
max_rate, p_rate, p);
|
||||
}
|
||||
|
||||
static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate, unsigned long max_rate,
|
||||
unsigned long *p_rate, struct clk_hw **p)
|
||||
{
|
||||
struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
|
||||
|
||||
return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p);
|
||||
return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate,
|
||||
max_rate, p_rate, p);
|
||||
}
|
||||
|
||||
static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate, unsigned long max_rate,
|
||||
unsigned long *p_rate, struct clk_hw **p_hw)
|
||||
{
|
||||
struct clk_rcg *rcg = to_clk_rcg(hw);
|
||||
|
@ -208,6 +208,7 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
|
||||
}
|
||||
|
||||
static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate, unsigned long max_rate,
|
||||
unsigned long *p_rate, struct clk_hw **p)
|
||||
{
|
||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||
@ -361,6 +362,8 @@ static int clk_edp_pixel_set_rate_and_parent(struct clk_hw *hw,
|
||||
}
|
||||
|
||||
static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *p_rate, struct clk_hw **p)
|
||||
{
|
||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||
@ -412,6 +415,7 @@ const struct clk_ops clk_edp_pixel_ops = {
|
||||
EXPORT_SYMBOL_GPL(clk_edp_pixel_ops);
|
||||
|
||||
static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate, unsigned long max_rate,
|
||||
unsigned long *p_rate, struct clk_hw **p_hw)
|
||||
{
|
||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||
@ -476,6 +480,8 @@ static const struct frac_entry frac_table_pixel[] = {
|
||||
};
|
||||
|
||||
static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *p_rate, struct clk_hw **p)
|
||||
{
|
||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||
|
70
drivers/clk/qcom/clk-regmap-divider.c
Normal file
70
drivers/clk/qcom/clk-regmap-divider.c
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include "clk-regmap-divider.h"
|
||||
|
||||
static inline struct clk_regmap_div *to_clk_regmap_div(struct clk_hw *hw)
|
||||
{
|
||||
return container_of(to_clk_regmap(hw), struct clk_regmap_div, clkr);
|
||||
}
|
||||
|
||||
static long div_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct clk_regmap_div *divider = to_clk_regmap_div(hw);
|
||||
|
||||
return divider_round_rate(hw, rate, prate, NULL, divider->width,
|
||||
CLK_DIVIDER_ROUND_CLOSEST);
|
||||
}
|
||||
|
||||
static int div_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_regmap_div *divider = to_clk_regmap_div(hw);
|
||||
struct clk_regmap *clkr = ÷r->clkr;
|
||||
u32 div;
|
||||
|
||||
div = divider_get_val(rate, parent_rate, NULL, divider->width,
|
||||
CLK_DIVIDER_ROUND_CLOSEST);
|
||||
|
||||
return regmap_update_bits(clkr->regmap, divider->reg,
|
||||
(BIT(divider->width) - 1) << divider->shift,
|
||||
div << divider->shift);
|
||||
}
|
||||
|
||||
static unsigned long div_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_regmap_div *divider = to_clk_regmap_div(hw);
|
||||
struct clk_regmap *clkr = ÷r->clkr;
|
||||
u32 div;
|
||||
|
||||
regmap_read(clkr->regmap, divider->reg, &div);
|
||||
div >>= divider->shift;
|
||||
div &= BIT(divider->width) - 1;
|
||||
|
||||
return divider_recalc_rate(hw, parent_rate, div, NULL,
|
||||
CLK_DIVIDER_ROUND_CLOSEST);
|
||||
}
|
||||
|
||||
const struct clk_ops clk_regmap_div_ops = {
|
||||
.round_rate = div_round_rate,
|
||||
.set_rate = div_set_rate,
|
||||
.recalc_rate = div_recalc_rate,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_regmap_div_ops);
|
29
drivers/clk/qcom/clk-regmap-divider.h
Normal file
29
drivers/clk/qcom/clk-regmap-divider.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __QCOM_CLK_REGMAP_DIVIDER_H__
|
||||
#define __QCOM_CLK_REGMAP_DIVIDER_H__
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include "clk-regmap.h"
|
||||
|
||||
struct clk_regmap_div {
|
||||
u32 reg;
|
||||
u32 shift;
|
||||
u32 width;
|
||||
struct clk_regmap clkr;
|
||||
};
|
||||
|
||||
extern const struct clk_ops clk_regmap_div_ops;
|
||||
|
||||
#endif
|
59
drivers/clk/qcom/clk-regmap-mux.c
Normal file
59
drivers/clk/qcom/clk-regmap-mux.c
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include "clk-regmap-mux.h"
|
||||
|
||||
static inline struct clk_regmap_mux *to_clk_regmap_mux(struct clk_hw *hw)
|
||||
{
|
||||
return container_of(to_clk_regmap(hw), struct clk_regmap_mux, clkr);
|
||||
}
|
||||
|
||||
static u8 mux_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_regmap_mux *mux = to_clk_regmap_mux(hw);
|
||||
struct clk_regmap *clkr = to_clk_regmap(hw);
|
||||
unsigned int mask = GENMASK(mux->width - 1, 0);
|
||||
unsigned int val;
|
||||
|
||||
regmap_read(clkr->regmap, mux->reg, &val);
|
||||
|
||||
val >>= mux->shift;
|
||||
val &= mask;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int mux_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct clk_regmap_mux *mux = to_clk_regmap_mux(hw);
|
||||
struct clk_regmap *clkr = to_clk_regmap(hw);
|
||||
unsigned int mask = GENMASK(mux->width + mux->shift - 1, mux->shift);
|
||||
unsigned int val;
|
||||
|
||||
val = index;
|
||||
val <<= mux->shift;
|
||||
|
||||
return regmap_update_bits(clkr->regmap, mux->reg, mask, val);
|
||||
}
|
||||
|
||||
const struct clk_ops clk_regmap_mux_closest_ops = {
|
||||
.get_parent = mux_get_parent,
|
||||
.set_parent = mux_set_parent,
|
||||
.determine_rate = __clk_mux_determine_rate_closest,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_regmap_mux_closest_ops);
|
29
drivers/clk/qcom/clk-regmap-mux.h
Normal file
29
drivers/clk/qcom/clk-regmap-mux.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __QCOM_CLK_REGMAP_MUX_H__
|
||||
#define __QCOM_CLK_REGMAP_MUX_H__
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include "clk-regmap.h"
|
||||
|
||||
struct clk_regmap_mux {
|
||||
u32 reg;
|
||||
u32 shift;
|
||||
u32 width;
|
||||
struct clk_regmap clkr;
|
||||
};
|
||||
|
||||
extern const struct clk_ops clk_regmap_mux_closest_ops;
|
||||
|
||||
#endif
|
@ -75,6 +75,17 @@ static struct clk_pll pll3 = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap pll4_vote = {
|
||||
.enable_reg = 0x34c0,
|
||||
.enable_mask = BIT(4),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "pll4_vote",
|
||||
.parent_names = (const char *[]){ "pll4" },
|
||||
.num_parents = 1,
|
||||
.ops = &clk_pll_vote_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_pll pll8 = {
|
||||
.l_reg = 0x3144,
|
||||
.m_reg = 0x3148,
|
||||
@ -2163,6 +2174,7 @@ static struct clk_regmap *gcc_ipq806x_clks[] = {
|
||||
[PLL0] = &pll0.clkr,
|
||||
[PLL0_VOTE] = &pll0_vote,
|
||||
[PLL3] = &pll3.clkr,
|
||||
[PLL4_VOTE] = &pll4_vote,
|
||||
[PLL8] = &pll8.clkr,
|
||||
[PLL8_VOTE] = &pll8_vote,
|
||||
[PLL14] = &pll14.clkr,
|
||||
|
473
drivers/clk/qcom/lcc-ipq806x.c
Normal file
473
drivers/clk/qcom/lcc-ipq806x.c
Normal file
@ -0,0 +1,473 @@
|
||||
/*
|
||||
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <dt-bindings/clock/qcom,lcc-ipq806x.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "clk-regmap.h"
|
||||
#include "clk-pll.h"
|
||||
#include "clk-rcg.h"
|
||||
#include "clk-branch.h"
|
||||
#include "clk-regmap-divider.h"
|
||||
#include "clk-regmap-mux.h"
|
||||
|
||||
static struct clk_pll pll4 = {
|
||||
.l_reg = 0x4,
|
||||
.m_reg = 0x8,
|
||||
.n_reg = 0xc,
|
||||
.config_reg = 0x14,
|
||||
.mode_reg = 0x0,
|
||||
.status_reg = 0x18,
|
||||
.status_bit = 16,
|
||||
.clkr.hw.init = &(struct clk_init_data){
|
||||
.name = "pll4",
|
||||
.parent_names = (const char *[]){ "pxo" },
|
||||
.num_parents = 1,
|
||||
.ops = &clk_pll_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct pll_config pll4_config = {
|
||||
.l = 0xf,
|
||||
.m = 0x91,
|
||||
.n = 0xc7,
|
||||
.vco_val = 0x0,
|
||||
.vco_mask = BIT(17) | BIT(16),
|
||||
.pre_div_val = 0x0,
|
||||
.pre_div_mask = BIT(19),
|
||||
.post_div_val = 0x0,
|
||||
.post_div_mask = BIT(21) | BIT(20),
|
||||
.mn_ena_mask = BIT(22),
|
||||
.main_output_mask = BIT(23),
|
||||
};
|
||||
|
||||
#define P_PXO 0
|
||||
#define P_PLL4 1
|
||||
|
||||
static const u8 lcc_pxo_pll4_map[] = {
|
||||
[P_PXO] = 0,
|
||||
[P_PLL4] = 2,
|
||||
};
|
||||
|
||||
static const char *lcc_pxo_pll4[] = {
|
||||
"pxo",
|
||||
"pll4_vote",
|
||||
};
|
||||
|
||||
static struct freq_tbl clk_tbl_aif_mi2s[] = {
|
||||
{ 1024000, P_PLL4, 4, 1, 96 },
|
||||
{ 1411200, P_PLL4, 4, 2, 139 },
|
||||
{ 1536000, P_PLL4, 4, 1, 64 },
|
||||
{ 2048000, P_PLL4, 4, 1, 48 },
|
||||
{ 2116800, P_PLL4, 4, 2, 93 },
|
||||
{ 2304000, P_PLL4, 4, 2, 85 },
|
||||
{ 2822400, P_PLL4, 4, 6, 209 },
|
||||
{ 3072000, P_PLL4, 4, 1, 32 },
|
||||
{ 3175200, P_PLL4, 4, 1, 31 },
|
||||
{ 4096000, P_PLL4, 4, 1, 24 },
|
||||
{ 4233600, P_PLL4, 4, 9, 209 },
|
||||
{ 4608000, P_PLL4, 4, 3, 64 },
|
||||
{ 5644800, P_PLL4, 4, 12, 209 },
|
||||
{ 6144000, P_PLL4, 4, 1, 16 },
|
||||
{ 6350400, P_PLL4, 4, 2, 31 },
|
||||
{ 8192000, P_PLL4, 4, 1, 12 },
|
||||
{ 8467200, P_PLL4, 4, 18, 209 },
|
||||
{ 9216000, P_PLL4, 4, 3, 32 },
|
||||
{ 11289600, P_PLL4, 4, 24, 209 },
|
||||
{ 12288000, P_PLL4, 4, 1, 8 },
|
||||
{ 12700800, P_PLL4, 4, 27, 209 },
|
||||
{ 13824000, P_PLL4, 4, 9, 64 },
|
||||
{ 16384000, P_PLL4, 4, 1, 6 },
|
||||
{ 16934400, P_PLL4, 4, 41, 238 },
|
||||
{ 18432000, P_PLL4, 4, 3, 16 },
|
||||
{ 22579200, P_PLL4, 2, 24, 209 },
|
||||
{ 24576000, P_PLL4, 4, 1, 4 },
|
||||
{ 27648000, P_PLL4, 4, 9, 32 },
|
||||
{ 33868800, P_PLL4, 4, 41, 119 },
|
||||
{ 36864000, P_PLL4, 4, 3, 8 },
|
||||
{ 45158400, P_PLL4, 1, 24, 209 },
|
||||
{ 49152000, P_PLL4, 4, 1, 2 },
|
||||
{ 50803200, P_PLL4, 1, 27, 209 },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct clk_rcg mi2s_osr_src = {
|
||||
.ns_reg = 0x48,
|
||||
.md_reg = 0x4c,
|
||||
.mn = {
|
||||
.mnctr_en_bit = 8,
|
||||
.mnctr_reset_bit = 7,
|
||||
.mnctr_mode_shift = 5,
|
||||
.n_val_shift = 24,
|
||||
.m_val_shift = 8,
|
||||
.width = 8,
|
||||
},
|
||||
.p = {
|
||||
.pre_div_shift = 3,
|
||||
.pre_div_width = 2,
|
||||
},
|
||||
.s = {
|
||||
.src_sel_shift = 0,
|
||||
.parent_map = lcc_pxo_pll4_map,
|
||||
},
|
||||
.freq_tbl = clk_tbl_aif_mi2s,
|
||||
.clkr = {
|
||||
.enable_reg = 0x48,
|
||||
.enable_mask = BIT(9),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mi2s_osr_src",
|
||||
.parent_names = lcc_pxo_pll4,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
.flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const char *lcc_mi2s_parents[] = {
|
||||
"mi2s_osr_src",
|
||||
};
|
||||
|
||||
static struct clk_branch mi2s_osr_clk = {
|
||||
.halt_reg = 0x50,
|
||||
.halt_bit = 1,
|
||||
.halt_check = BRANCH_HALT_ENABLE,
|
||||
.clkr = {
|
||||
.enable_reg = 0x48,
|
||||
.enable_mask = BIT(17),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mi2s_osr_clk",
|
||||
.parent_names = lcc_mi2s_parents,
|
||||
.num_parents = 1,
|
||||
.ops = &clk_branch_ops,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap_div mi2s_div_clk = {
|
||||
.reg = 0x48,
|
||||
.shift = 10,
|
||||
.width = 4,
|
||||
.clkr = {
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mi2s_div_clk",
|
||||
.parent_names = lcc_mi2s_parents,
|
||||
.num_parents = 1,
|
||||
.ops = &clk_regmap_div_ops,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_branch mi2s_bit_div_clk = {
|
||||
.halt_reg = 0x50,
|
||||
.halt_bit = 0,
|
||||
.halt_check = BRANCH_HALT_ENABLE,
|
||||
.clkr = {
|
||||
.enable_reg = 0x48,
|
||||
.enable_mask = BIT(15),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mi2s_bit_div_clk",
|
||||
.parent_names = (const char *[]){ "mi2s_div_clk" },
|
||||
.num_parents = 1,
|
||||
.ops = &clk_branch_ops,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
static struct clk_regmap_mux mi2s_bit_clk = {
|
||||
.reg = 0x48,
|
||||
.shift = 14,
|
||||
.width = 1,
|
||||
.clkr = {
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mi2s_bit_clk",
|
||||
.parent_names = (const char *[]){
|
||||
"mi2s_bit_div_clk",
|
||||
"mi2s_codec_clk",
|
||||
},
|
||||
.num_parents = 2,
|
||||
.ops = &clk_regmap_mux_closest_ops,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct freq_tbl clk_tbl_pcm[] = {
|
||||
{ 64000, P_PLL4, 4, 1, 1536 },
|
||||
{ 128000, P_PLL4, 4, 1, 768 },
|
||||
{ 256000, P_PLL4, 4, 1, 384 },
|
||||
{ 512000, P_PLL4, 4, 1, 192 },
|
||||
{ 1024000, P_PLL4, 4, 1, 96 },
|
||||
{ 2048000, P_PLL4, 4, 1, 48 },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct clk_rcg pcm_src = {
|
||||
.ns_reg = 0x54,
|
||||
.md_reg = 0x58,
|
||||
.mn = {
|
||||
.mnctr_en_bit = 8,
|
||||
.mnctr_reset_bit = 7,
|
||||
.mnctr_mode_shift = 5,
|
||||
.n_val_shift = 16,
|
||||
.m_val_shift = 16,
|
||||
.width = 16,
|
||||
},
|
||||
.p = {
|
||||
.pre_div_shift = 3,
|
||||
.pre_div_width = 2,
|
||||
},
|
||||
.s = {
|
||||
.src_sel_shift = 0,
|
||||
.parent_map = lcc_pxo_pll4_map,
|
||||
},
|
||||
.freq_tbl = clk_tbl_pcm,
|
||||
.clkr = {
|
||||
.enable_reg = 0x54,
|
||||
.enable_mask = BIT(9),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "pcm_src",
|
||||
.parent_names = lcc_pxo_pll4,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
.flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_branch pcm_clk_out = {
|
||||
.halt_reg = 0x5c,
|
||||
.halt_bit = 0,
|
||||
.halt_check = BRANCH_HALT_ENABLE,
|
||||
.clkr = {
|
||||
.enable_reg = 0x54,
|
||||
.enable_mask = BIT(11),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "pcm_clk_out",
|
||||
.parent_names = (const char *[]){ "pcm_src" },
|
||||
.num_parents = 1,
|
||||
.ops = &clk_branch_ops,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap_mux pcm_clk = {
|
||||
.reg = 0x54,
|
||||
.shift = 10,
|
||||
.width = 1,
|
||||
.clkr = {
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "pcm_clk",
|
||||
.parent_names = (const char *[]){
|
||||
"pcm_clk_out",
|
||||
"pcm_codec_clk",
|
||||
},
|
||||
.num_parents = 2,
|
||||
.ops = &clk_regmap_mux_closest_ops,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct freq_tbl clk_tbl_aif_osr[] = {
|
||||
{ 22050, P_PLL4, 1, 147, 20480 },
|
||||
{ 32000, P_PLL4, 1, 1, 96 },
|
||||
{ 44100, P_PLL4, 1, 147, 10240 },
|
||||
{ 48000, P_PLL4, 1, 1, 64 },
|
||||
{ 88200, P_PLL4, 1, 147, 5120 },
|
||||
{ 96000, P_PLL4, 1, 1, 32 },
|
||||
{ 176400, P_PLL4, 1, 147, 2560 },
|
||||
{ 192000, P_PLL4, 1, 1, 16 },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct clk_rcg spdif_src = {
|
||||
.ns_reg = 0xcc,
|
||||
.md_reg = 0xd0,
|
||||
.mn = {
|
||||
.mnctr_en_bit = 8,
|
||||
.mnctr_reset_bit = 7,
|
||||
.mnctr_mode_shift = 5,
|
||||
.n_val_shift = 16,
|
||||
.m_val_shift = 16,
|
||||
.width = 8,
|
||||
},
|
||||
.p = {
|
||||
.pre_div_shift = 3,
|
||||
.pre_div_width = 2,
|
||||
},
|
||||
.s = {
|
||||
.src_sel_shift = 0,
|
||||
.parent_map = lcc_pxo_pll4_map,
|
||||
},
|
||||
.freq_tbl = clk_tbl_aif_osr,
|
||||
.clkr = {
|
||||
.enable_reg = 0xcc,
|
||||
.enable_mask = BIT(9),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "spdif_src",
|
||||
.parent_names = lcc_pxo_pll4,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
.flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const char *lcc_spdif_parents[] = {
|
||||
"spdif_src",
|
||||
};
|
||||
|
||||
static struct clk_branch spdif_clk = {
|
||||
.halt_reg = 0xd4,
|
||||
.halt_bit = 1,
|
||||
.halt_check = BRANCH_HALT_ENABLE,
|
||||
.clkr = {
|
||||
.enable_reg = 0xcc,
|
||||
.enable_mask = BIT(12),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "spdif_clk",
|
||||
.parent_names = lcc_spdif_parents,
|
||||
.num_parents = 1,
|
||||
.ops = &clk_branch_ops,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct freq_tbl clk_tbl_ahbix[] = {
|
||||
{ 131072, P_PLL4, 1, 1, 3 },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct clk_rcg ahbix_clk = {
|
||||
.ns_reg = 0x38,
|
||||
.md_reg = 0x3c,
|
||||
.mn = {
|
||||
.mnctr_en_bit = 8,
|
||||
.mnctr_reset_bit = 7,
|
||||
.mnctr_mode_shift = 5,
|
||||
.n_val_shift = 24,
|
||||
.m_val_shift = 8,
|
||||
.width = 8,
|
||||
},
|
||||
.p = {
|
||||
.pre_div_shift = 3,
|
||||
.pre_div_width = 2,
|
||||
},
|
||||
.s = {
|
||||
.src_sel_shift = 0,
|
||||
.parent_map = lcc_pxo_pll4_map,
|
||||
},
|
||||
.freq_tbl = clk_tbl_ahbix,
|
||||
.clkr = {
|
||||
.enable_reg = 0x38,
|
||||
.enable_mask = BIT(10), /* toggle the gfmux to select mn/pxo */
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "ahbix",
|
||||
.parent_names = lcc_pxo_pll4,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
.flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap *lcc_ipq806x_clks[] = {
|
||||
[PLL4] = &pll4.clkr,
|
||||
[MI2S_OSR_SRC] = &mi2s_osr_src.clkr,
|
||||
[MI2S_OSR_CLK] = &mi2s_osr_clk.clkr,
|
||||
[MI2S_DIV_CLK] = &mi2s_div_clk.clkr,
|
||||
[MI2S_BIT_DIV_CLK] = &mi2s_bit_div_clk.clkr,
|
||||
[MI2S_BIT_CLK] = &mi2s_bit_clk.clkr,
|
||||
[PCM_SRC] = &pcm_src.clkr,
|
||||
[PCM_CLK_OUT] = &pcm_clk_out.clkr,
|
||||
[PCM_CLK] = &pcm_clk.clkr,
|
||||
[SPDIF_SRC] = &spdif_src.clkr,
|
||||
[SPDIF_CLK] = &spdif_clk.clkr,
|
||||
[AHBIX_CLK] = &ahbix_clk.clkr,
|
||||
};
|
||||
|
||||
static const struct regmap_config lcc_ipq806x_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.max_register = 0xfc,
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
static const struct qcom_cc_desc lcc_ipq806x_desc = {
|
||||
.config = &lcc_ipq806x_regmap_config,
|
||||
.clks = lcc_ipq806x_clks,
|
||||
.num_clks = ARRAY_SIZE(lcc_ipq806x_clks),
|
||||
};
|
||||
|
||||
static const struct of_device_id lcc_ipq806x_match_table[] = {
|
||||
{ .compatible = "qcom,lcc-ipq8064" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lcc_ipq806x_match_table);
|
||||
|
||||
static int lcc_ipq806x_probe(struct platform_device *pdev)
|
||||
{
|
||||
u32 val;
|
||||
struct regmap *regmap;
|
||||
|
||||
regmap = qcom_cc_map(pdev, &lcc_ipq806x_desc);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
/* Configure the rate of PLL4 if the bootloader hasn't already */
|
||||
val = regmap_read(regmap, 0x0, &val);
|
||||
if (!val)
|
||||
clk_pll_configure_sr(&pll4, regmap, &pll4_config, true);
|
||||
/* Enable PLL4 source on the LPASS Primary PLL Mux */
|
||||
regmap_write(regmap, 0xc4, 0x1);
|
||||
|
||||
return qcom_cc_really_probe(pdev, &lcc_ipq806x_desc, regmap);
|
||||
}
|
||||
|
||||
static int lcc_ipq806x_remove(struct platform_device *pdev)
|
||||
{
|
||||
qcom_cc_remove(pdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver lcc_ipq806x_driver = {
|
||||
.probe = lcc_ipq806x_probe,
|
||||
.remove = lcc_ipq806x_remove,
|
||||
.driver = {
|
||||
.name = "lcc-ipq806x",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = lcc_ipq806x_match_table,
|
||||
},
|
||||
};
|
||||
module_platform_driver(lcc_ipq806x_driver);
|
||||
|
||||
MODULE_DESCRIPTION("QCOM LCC IPQ806x Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:lcc-ipq806x");
|
585
drivers/clk/qcom/lcc-msm8960.c
Normal file
585
drivers/clk/qcom/lcc-msm8960.c
Normal file
@ -0,0 +1,585 @@
|
||||
/*
|
||||
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <dt-bindings/clock/qcom,lcc-msm8960.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "clk-regmap.h"
|
||||
#include "clk-pll.h"
|
||||
#include "clk-rcg.h"
|
||||
#include "clk-branch.h"
|
||||
#include "clk-regmap-divider.h"
|
||||
#include "clk-regmap-mux.h"
|
||||
|
||||
static struct clk_pll pll4 = {
|
||||
.l_reg = 0x4,
|
||||
.m_reg = 0x8,
|
||||
.n_reg = 0xc,
|
||||
.config_reg = 0x14,
|
||||
.mode_reg = 0x0,
|
||||
.status_reg = 0x18,
|
||||
.status_bit = 16,
|
||||
.clkr.hw.init = &(struct clk_init_data){
|
||||
.name = "pll4",
|
||||
.parent_names = (const char *[]){ "pxo" },
|
||||
.num_parents = 1,
|
||||
.ops = &clk_pll_ops,
|
||||
},
|
||||
};
|
||||
|
||||
#define P_PXO 0
|
||||
#define P_PLL4 1
|
||||
|
||||
static const u8 lcc_pxo_pll4_map[] = {
|
||||
[P_PXO] = 0,
|
||||
[P_PLL4] = 2,
|
||||
};
|
||||
|
||||
static const char *lcc_pxo_pll4[] = {
|
||||
"pxo",
|
||||
"pll4_vote",
|
||||
};
|
||||
|
||||
static struct freq_tbl clk_tbl_aif_osr_492[] = {
|
||||
{ 512000, P_PLL4, 4, 1, 240 },
|
||||
{ 768000, P_PLL4, 4, 1, 160 },
|
||||
{ 1024000, P_PLL4, 4, 1, 120 },
|
||||
{ 1536000, P_PLL4, 4, 1, 80 },
|
||||
{ 2048000, P_PLL4, 4, 1, 60 },
|
||||
{ 3072000, P_PLL4, 4, 1, 40 },
|
||||
{ 4096000, P_PLL4, 4, 1, 30 },
|
||||
{ 6144000, P_PLL4, 4, 1, 20 },
|
||||
{ 8192000, P_PLL4, 4, 1, 15 },
|
||||
{ 12288000, P_PLL4, 4, 1, 10 },
|
||||
{ 24576000, P_PLL4, 4, 1, 5 },
|
||||
{ 27000000, P_PXO, 1, 0, 0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct freq_tbl clk_tbl_aif_osr_393[] = {
|
||||
{ 512000, P_PLL4, 4, 1, 192 },
|
||||
{ 768000, P_PLL4, 4, 1, 128 },
|
||||
{ 1024000, P_PLL4, 4, 1, 96 },
|
||||
{ 1536000, P_PLL4, 4, 1, 64 },
|
||||
{ 2048000, P_PLL4, 4, 1, 48 },
|
||||
{ 3072000, P_PLL4, 4, 1, 32 },
|
||||
{ 4096000, P_PLL4, 4, 1, 24 },
|
||||
{ 6144000, P_PLL4, 4, 1, 16 },
|
||||
{ 8192000, P_PLL4, 4, 1, 12 },
|
||||
{ 12288000, P_PLL4, 4, 1, 8 },
|
||||
{ 24576000, P_PLL4, 4, 1, 4 },
|
||||
{ 27000000, P_PXO, 1, 0, 0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct clk_rcg mi2s_osr_src = {
|
||||
.ns_reg = 0x48,
|
||||
.md_reg = 0x4c,
|
||||
.mn = {
|
||||
.mnctr_en_bit = 8,
|
||||
.mnctr_reset_bit = 7,
|
||||
.mnctr_mode_shift = 5,
|
||||
.n_val_shift = 24,
|
||||
.m_val_shift = 8,
|
||||
.width = 8,
|
||||
},
|
||||
.p = {
|
||||
.pre_div_shift = 3,
|
||||
.pre_div_width = 2,
|
||||
},
|
||||
.s = {
|
||||
.src_sel_shift = 0,
|
||||
.parent_map = lcc_pxo_pll4_map,
|
||||
},
|
||||
.freq_tbl = clk_tbl_aif_osr_393,
|
||||
.clkr = {
|
||||
.enable_reg = 0x48,
|
||||
.enable_mask = BIT(9),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mi2s_osr_src",
|
||||
.parent_names = lcc_pxo_pll4,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
.flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const char *lcc_mi2s_parents[] = {
|
||||
"mi2s_osr_src",
|
||||
};
|
||||
|
||||
static struct clk_branch mi2s_osr_clk = {
|
||||
.halt_reg = 0x50,
|
||||
.halt_bit = 1,
|
||||
.halt_check = BRANCH_HALT_ENABLE,
|
||||
.clkr = {
|
||||
.enable_reg = 0x48,
|
||||
.enable_mask = BIT(17),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mi2s_osr_clk",
|
||||
.parent_names = lcc_mi2s_parents,
|
||||
.num_parents = 1,
|
||||
.ops = &clk_branch_ops,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap_div mi2s_div_clk = {
|
||||
.reg = 0x48,
|
||||
.shift = 10,
|
||||
.width = 4,
|
||||
.clkr = {
|
||||
.enable_reg = 0x48,
|
||||
.enable_mask = BIT(15),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mi2s_div_clk",
|
||||
.parent_names = lcc_mi2s_parents,
|
||||
.num_parents = 1,
|
||||
.ops = &clk_regmap_div_ops,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_branch mi2s_bit_div_clk = {
|
||||
.halt_reg = 0x50,
|
||||
.halt_bit = 0,
|
||||
.halt_check = BRANCH_HALT_ENABLE,
|
||||
.clkr = {
|
||||
.enable_reg = 0x48,
|
||||
.enable_mask = BIT(15),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mi2s_bit_div_clk",
|
||||
.parent_names = (const char *[]){ "mi2s_div_clk" },
|
||||
.num_parents = 1,
|
||||
.ops = &clk_branch_ops,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap_mux mi2s_bit_clk = {
|
||||
.reg = 0x48,
|
||||
.shift = 14,
|
||||
.width = 1,
|
||||
.clkr = {
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mi2s_bit_clk",
|
||||
.parent_names = (const char *[]){
|
||||
"mi2s_bit_div_clk",
|
||||
"mi2s_codec_clk",
|
||||
},
|
||||
.num_parents = 2,
|
||||
.ops = &clk_regmap_mux_closest_ops,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
#define CLK_AIF_OSR_DIV(prefix, _ns, _md, hr) \
|
||||
static struct clk_rcg prefix##_osr_src = { \
|
||||
.ns_reg = _ns, \
|
||||
.md_reg = _md, \
|
||||
.mn = { \
|
||||
.mnctr_en_bit = 8, \
|
||||
.mnctr_reset_bit = 7, \
|
||||
.mnctr_mode_shift = 5, \
|
||||
.n_val_shift = 24, \
|
||||
.m_val_shift = 8, \
|
||||
.width = 8, \
|
||||
}, \
|
||||
.p = { \
|
||||
.pre_div_shift = 3, \
|
||||
.pre_div_width = 2, \
|
||||
}, \
|
||||
.s = { \
|
||||
.src_sel_shift = 0, \
|
||||
.parent_map = lcc_pxo_pll4_map, \
|
||||
}, \
|
||||
.freq_tbl = clk_tbl_aif_osr_393, \
|
||||
.clkr = { \
|
||||
.enable_reg = _ns, \
|
||||
.enable_mask = BIT(9), \
|
||||
.hw.init = &(struct clk_init_data){ \
|
||||
.name = #prefix "_osr_src", \
|
||||
.parent_names = lcc_pxo_pll4, \
|
||||
.num_parents = 2, \
|
||||
.ops = &clk_rcg_ops, \
|
||||
.flags = CLK_SET_RATE_GATE, \
|
||||
}, \
|
||||
}, \
|
||||
}; \
|
||||
\
|
||||
static const char *lcc_##prefix##_parents[] = { \
|
||||
#prefix "_osr_src", \
|
||||
}; \
|
||||
\
|
||||
static struct clk_branch prefix##_osr_clk = { \
|
||||
.halt_reg = hr, \
|
||||
.halt_bit = 1, \
|
||||
.halt_check = BRANCH_HALT_ENABLE, \
|
||||
.clkr = { \
|
||||
.enable_reg = _ns, \
|
||||
.enable_mask = BIT(21), \
|
||||
.hw.init = &(struct clk_init_data){ \
|
||||
.name = #prefix "_osr_clk", \
|
||||
.parent_names = lcc_##prefix##_parents, \
|
||||
.num_parents = 1, \
|
||||
.ops = &clk_branch_ops, \
|
||||
.flags = CLK_SET_RATE_PARENT, \
|
||||
}, \
|
||||
}, \
|
||||
}; \
|
||||
\
|
||||
static struct clk_regmap_div prefix##_div_clk = { \
|
||||
.reg = _ns, \
|
||||
.shift = 10, \
|
||||
.width = 8, \
|
||||
.clkr = { \
|
||||
.hw.init = &(struct clk_init_data){ \
|
||||
.name = #prefix "_div_clk", \
|
||||
.parent_names = lcc_##prefix##_parents, \
|
||||
.num_parents = 1, \
|
||||
.ops = &clk_regmap_div_ops, \
|
||||
}, \
|
||||
}, \
|
||||
}; \
|
||||
\
|
||||
static struct clk_branch prefix##_bit_div_clk = { \
|
||||
.halt_reg = hr, \
|
||||
.halt_bit = 0, \
|
||||
.halt_check = BRANCH_HALT_ENABLE, \
|
||||
.clkr = { \
|
||||
.enable_reg = _ns, \
|
||||
.enable_mask = BIT(19), \
|
||||
.hw.init = &(struct clk_init_data){ \
|
||||
.name = #prefix "_bit_div_clk", \
|
||||
.parent_names = (const char *[]){ \
|
||||
#prefix "_div_clk" \
|
||||
}, \
|
||||
.num_parents = 1, \
|
||||
.ops = &clk_branch_ops, \
|
||||
.flags = CLK_SET_RATE_PARENT, \
|
||||
}, \
|
||||
}, \
|
||||
}; \
|
||||
\
|
||||
static struct clk_regmap_mux prefix##_bit_clk = { \
|
||||
.reg = _ns, \
|
||||
.shift = 18, \
|
||||
.width = 1, \
|
||||
.clkr = { \
|
||||
.hw.init = &(struct clk_init_data){ \
|
||||
.name = #prefix "_bit_clk", \
|
||||
.parent_names = (const char *[]){ \
|
||||
#prefix "_bit_div_clk", \
|
||||
#prefix "_codec_clk", \
|
||||
}, \
|
||||
.num_parents = 2, \
|
||||
.ops = &clk_regmap_mux_closest_ops, \
|
||||
.flags = CLK_SET_RATE_PARENT, \
|
||||
}, \
|
||||
}, \
|
||||
}
|
||||
|
||||
CLK_AIF_OSR_DIV(codec_i2s_mic, 0x60, 0x64, 0x68);
|
||||
CLK_AIF_OSR_DIV(spare_i2s_mic, 0x78, 0x7c, 0x80);
|
||||
CLK_AIF_OSR_DIV(codec_i2s_spkr, 0x6c, 0x70, 0x74);
|
||||
CLK_AIF_OSR_DIV(spare_i2s_spkr, 0x84, 0x88, 0x8c);
|
||||
|
||||
static struct freq_tbl clk_tbl_pcm_492[] = {
|
||||
{ 256000, P_PLL4, 4, 1, 480 },
|
||||
{ 512000, P_PLL4, 4, 1, 240 },
|
||||
{ 768000, P_PLL4, 4, 1, 160 },
|
||||
{ 1024000, P_PLL4, 4, 1, 120 },
|
||||
{ 1536000, P_PLL4, 4, 1, 80 },
|
||||
{ 2048000, P_PLL4, 4, 1, 60 },
|
||||
{ 3072000, P_PLL4, 4, 1, 40 },
|
||||
{ 4096000, P_PLL4, 4, 1, 30 },
|
||||
{ 6144000, P_PLL4, 4, 1, 20 },
|
||||
{ 8192000, P_PLL4, 4, 1, 15 },
|
||||
{ 12288000, P_PLL4, 4, 1, 10 },
|
||||
{ 24576000, P_PLL4, 4, 1, 5 },
|
||||
{ 27000000, P_PXO, 1, 0, 0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct freq_tbl clk_tbl_pcm_393[] = {
|
||||
{ 256000, P_PLL4, 4, 1, 384 },
|
||||
{ 512000, P_PLL4, 4, 1, 192 },
|
||||
{ 768000, P_PLL4, 4, 1, 128 },
|
||||
{ 1024000, P_PLL4, 4, 1, 96 },
|
||||
{ 1536000, P_PLL4, 4, 1, 64 },
|
||||
{ 2048000, P_PLL4, 4, 1, 48 },
|
||||
{ 3072000, P_PLL4, 4, 1, 32 },
|
||||
{ 4096000, P_PLL4, 4, 1, 24 },
|
||||
{ 6144000, P_PLL4, 4, 1, 16 },
|
||||
{ 8192000, P_PLL4, 4, 1, 12 },
|
||||
{ 12288000, P_PLL4, 4, 1, 8 },
|
||||
{ 24576000, P_PLL4, 4, 1, 4 },
|
||||
{ 27000000, P_PXO, 1, 0, 0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct clk_rcg pcm_src = {
|
||||
.ns_reg = 0x54,
|
||||
.md_reg = 0x58,
|
||||
.mn = {
|
||||
.mnctr_en_bit = 8,
|
||||
.mnctr_reset_bit = 7,
|
||||
.mnctr_mode_shift = 5,
|
||||
.n_val_shift = 16,
|
||||
.m_val_shift = 16,
|
||||
.width = 16,
|
||||
},
|
||||
.p = {
|
||||
.pre_div_shift = 3,
|
||||
.pre_div_width = 2,
|
||||
},
|
||||
.s = {
|
||||
.src_sel_shift = 0,
|
||||
.parent_map = lcc_pxo_pll4_map,
|
||||
},
|
||||
.freq_tbl = clk_tbl_pcm_393,
|
||||
.clkr = {
|
||||
.enable_reg = 0x54,
|
||||
.enable_mask = BIT(9),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "pcm_src",
|
||||
.parent_names = lcc_pxo_pll4,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
.flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_branch pcm_clk_out = {
|
||||
.halt_reg = 0x5c,
|
||||
.halt_bit = 0,
|
||||
.halt_check = BRANCH_HALT_ENABLE,
|
||||
.clkr = {
|
||||
.enable_reg = 0x54,
|
||||
.enable_mask = BIT(11),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "pcm_clk_out",
|
||||
.parent_names = (const char *[]){ "pcm_src" },
|
||||
.num_parents = 1,
|
||||
.ops = &clk_branch_ops,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap_mux pcm_clk = {
|
||||
.reg = 0x54,
|
||||
.shift = 10,
|
||||
.width = 1,
|
||||
.clkr = {
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "pcm_clk",
|
||||
.parent_names = (const char *[]){
|
||||
"pcm_clk_out",
|
||||
"pcm_codec_clk",
|
||||
},
|
||||
.num_parents = 2,
|
||||
.ops = &clk_regmap_mux_closest_ops,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_rcg slimbus_src = {
|
||||
.ns_reg = 0xcc,
|
||||
.md_reg = 0xd0,
|
||||
.mn = {
|
||||
.mnctr_en_bit = 8,
|
||||
.mnctr_reset_bit = 7,
|
||||
.mnctr_mode_shift = 5,
|
||||
.n_val_shift = 16,
|
||||
.m_val_shift = 16,
|
||||
.width = 8,
|
||||
},
|
||||
.p = {
|
||||
.pre_div_shift = 3,
|
||||
.pre_div_width = 2,
|
||||
},
|
||||
.s = {
|
||||
.src_sel_shift = 0,
|
||||
.parent_map = lcc_pxo_pll4_map,
|
||||
},
|
||||
.freq_tbl = clk_tbl_aif_osr_393,
|
||||
.clkr = {
|
||||
.enable_reg = 0xcc,
|
||||
.enable_mask = BIT(9),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "slimbus_src",
|
||||
.parent_names = lcc_pxo_pll4,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
.flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const char *lcc_slimbus_parents[] = {
|
||||
"slimbus_src",
|
||||
};
|
||||
|
||||
static struct clk_branch audio_slimbus_clk = {
|
||||
.halt_reg = 0xd4,
|
||||
.halt_bit = 0,
|
||||
.halt_check = BRANCH_HALT_ENABLE,
|
||||
.clkr = {
|
||||
.enable_reg = 0xcc,
|
||||
.enable_mask = BIT(10),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "audio_slimbus_clk",
|
||||
.parent_names = lcc_slimbus_parents,
|
||||
.num_parents = 1,
|
||||
.ops = &clk_branch_ops,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_branch sps_slimbus_clk = {
|
||||
.halt_reg = 0xd4,
|
||||
.halt_bit = 1,
|
||||
.halt_check = BRANCH_HALT_ENABLE,
|
||||
.clkr = {
|
||||
.enable_reg = 0xcc,
|
||||
.enable_mask = BIT(12),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "sps_slimbus_clk",
|
||||
.parent_names = lcc_slimbus_parents,
|
||||
.num_parents = 1,
|
||||
.ops = &clk_branch_ops,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap *lcc_msm8960_clks[] = {
|
||||
[PLL4] = &pll4.clkr,
|
||||
[MI2S_OSR_SRC] = &mi2s_osr_src.clkr,
|
||||
[MI2S_OSR_CLK] = &mi2s_osr_clk.clkr,
|
||||
[MI2S_DIV_CLK] = &mi2s_div_clk.clkr,
|
||||
[MI2S_BIT_DIV_CLK] = &mi2s_bit_div_clk.clkr,
|
||||
[MI2S_BIT_CLK] = &mi2s_bit_clk.clkr,
|
||||
[PCM_SRC] = &pcm_src.clkr,
|
||||
[PCM_CLK_OUT] = &pcm_clk_out.clkr,
|
||||
[PCM_CLK] = &pcm_clk.clkr,
|
||||
[SLIMBUS_SRC] = &slimbus_src.clkr,
|
||||
[AUDIO_SLIMBUS_CLK] = &audio_slimbus_clk.clkr,
|
||||
[SPS_SLIMBUS_CLK] = &sps_slimbus_clk.clkr,
|
||||
[CODEC_I2S_MIC_OSR_SRC] = &codec_i2s_mic_osr_src.clkr,
|
||||
[CODEC_I2S_MIC_OSR_CLK] = &codec_i2s_mic_osr_clk.clkr,
|
||||
[CODEC_I2S_MIC_DIV_CLK] = &codec_i2s_mic_div_clk.clkr,
|
||||
[CODEC_I2S_MIC_BIT_DIV_CLK] = &codec_i2s_mic_bit_div_clk.clkr,
|
||||
[CODEC_I2S_MIC_BIT_CLK] = &codec_i2s_mic_bit_clk.clkr,
|
||||
[SPARE_I2S_MIC_OSR_SRC] = &spare_i2s_mic_osr_src.clkr,
|
||||
[SPARE_I2S_MIC_OSR_CLK] = &spare_i2s_mic_osr_clk.clkr,
|
||||
[SPARE_I2S_MIC_DIV_CLK] = &spare_i2s_mic_div_clk.clkr,
|
||||
[SPARE_I2S_MIC_BIT_DIV_CLK] = &spare_i2s_mic_bit_div_clk.clkr,
|
||||
[SPARE_I2S_MIC_BIT_CLK] = &spare_i2s_mic_bit_clk.clkr,
|
||||
[CODEC_I2S_SPKR_OSR_SRC] = &codec_i2s_spkr_osr_src.clkr,
|
||||
[CODEC_I2S_SPKR_OSR_CLK] = &codec_i2s_spkr_osr_clk.clkr,
|
||||
[CODEC_I2S_SPKR_DIV_CLK] = &codec_i2s_spkr_div_clk.clkr,
|
||||
[CODEC_I2S_SPKR_BIT_DIV_CLK] = &codec_i2s_spkr_bit_div_clk.clkr,
|
||||
[CODEC_I2S_SPKR_BIT_CLK] = &codec_i2s_spkr_bit_clk.clkr,
|
||||
[SPARE_I2S_SPKR_OSR_SRC] = &spare_i2s_spkr_osr_src.clkr,
|
||||
[SPARE_I2S_SPKR_OSR_CLK] = &spare_i2s_spkr_osr_clk.clkr,
|
||||
[SPARE_I2S_SPKR_DIV_CLK] = &spare_i2s_spkr_div_clk.clkr,
|
||||
[SPARE_I2S_SPKR_BIT_DIV_CLK] = &spare_i2s_spkr_bit_div_clk.clkr,
|
||||
[SPARE_I2S_SPKR_BIT_CLK] = &spare_i2s_spkr_bit_clk.clkr,
|
||||
};
|
||||
|
||||
static const struct regmap_config lcc_msm8960_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.max_register = 0xfc,
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
static const struct qcom_cc_desc lcc_msm8960_desc = {
|
||||
.config = &lcc_msm8960_regmap_config,
|
||||
.clks = lcc_msm8960_clks,
|
||||
.num_clks = ARRAY_SIZE(lcc_msm8960_clks),
|
||||
};
|
||||
|
||||
static const struct of_device_id lcc_msm8960_match_table[] = {
|
||||
{ .compatible = "qcom,lcc-msm8960" },
|
||||
{ .compatible = "qcom,lcc-apq8064" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lcc_msm8960_match_table);
|
||||
|
||||
static int lcc_msm8960_probe(struct platform_device *pdev)
|
||||
{
|
||||
u32 val;
|
||||
struct regmap *regmap;
|
||||
|
||||
regmap = qcom_cc_map(pdev, &lcc_msm8960_desc);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
/* Use the correct frequency plan depending on speed of PLL4 */
|
||||
val = regmap_read(regmap, 0x4, &val);
|
||||
if (val == 0x12) {
|
||||
slimbus_src.freq_tbl = clk_tbl_aif_osr_492;
|
||||
mi2s_osr_src.freq_tbl = clk_tbl_aif_osr_492;
|
||||
codec_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492;
|
||||
spare_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492;
|
||||
codec_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492;
|
||||
spare_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492;
|
||||
pcm_src.freq_tbl = clk_tbl_pcm_492;
|
||||
}
|
||||
/* Enable PLL4 source on the LPASS Primary PLL Mux */
|
||||
regmap_write(regmap, 0xc4, 0x1);
|
||||
|
||||
return qcom_cc_really_probe(pdev, &lcc_msm8960_desc, regmap);
|
||||
}
|
||||
|
||||
static int lcc_msm8960_remove(struct platform_device *pdev)
|
||||
{
|
||||
qcom_cc_remove(pdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver lcc_msm8960_driver = {
|
||||
.probe = lcc_msm8960_probe,
|
||||
.remove = lcc_msm8960_remove,
|
||||
.driver = {
|
||||
.name = "lcc-msm8960",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = lcc_msm8960_match_table,
|
||||
},
|
||||
};
|
||||
module_platform_driver(lcc_msm8960_driver);
|
||||
|
||||
MODULE_DESCRIPTION("QCOM LCC MSM8960 Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:lcc-msm8960");
|
@ -535,44 +535,44 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
|
||||
COMPOSITE(0, "uart0_src", mux_pll_src_cpll_gll_usb_npll_p, 0,
|
||||
RK3288_CLKSEL_CON(13), 13, 2, MFLAGS, 0, 7, DFLAGS,
|
||||
RK3288_CLKGATE_CON(1), 8, GFLAGS),
|
||||
COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", 0,
|
||||
COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
|
||||
RK3288_CLKSEL_CON(17), 0,
|
||||
RK3288_CLKGATE_CON(1), 9, GFLAGS),
|
||||
MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, 0,
|
||||
MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
|
||||
RK3288_CLKSEL_CON(13), 8, 2, MFLAGS),
|
||||
MUX(0, "uart_src", mux_pll_src_cpll_gpll_p, 0,
|
||||
RK3288_CLKSEL_CON(13), 15, 1, MFLAGS),
|
||||
COMPOSITE_NOMUX(0, "uart1_src", "uart_src", 0,
|
||||
RK3288_CLKSEL_CON(14), 0, 7, DFLAGS,
|
||||
RK3288_CLKGATE_CON(1), 10, GFLAGS),
|
||||
COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", 0,
|
||||
COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
|
||||
RK3288_CLKSEL_CON(18), 0,
|
||||
RK3288_CLKGATE_CON(1), 11, GFLAGS),
|
||||
MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, 0,
|
||||
MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
|
||||
RK3288_CLKSEL_CON(14), 8, 2, MFLAGS),
|
||||
COMPOSITE_NOMUX(0, "uart2_src", "uart_src", 0,
|
||||
RK3288_CLKSEL_CON(15), 0, 7, DFLAGS,
|
||||
RK3288_CLKGATE_CON(1), 12, GFLAGS),
|
||||
COMPOSITE_FRAC(0, "uart2_frac", "uart2_src", 0,
|
||||
COMPOSITE_FRAC(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
|
||||
RK3288_CLKSEL_CON(19), 0,
|
||||
RK3288_CLKGATE_CON(1), 13, GFLAGS),
|
||||
MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, 0,
|
||||
MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
|
||||
RK3288_CLKSEL_CON(15), 8, 2, MFLAGS),
|
||||
COMPOSITE_NOMUX(0, "uart3_src", "uart_src", 0,
|
||||
RK3288_CLKSEL_CON(16), 0, 7, DFLAGS,
|
||||
RK3288_CLKGATE_CON(1), 14, GFLAGS),
|
||||
COMPOSITE_FRAC(0, "uart3_frac", "uart3_src", 0,
|
||||
COMPOSITE_FRAC(0, "uart3_frac", "uart3_src", CLK_SET_RATE_PARENT,
|
||||
RK3288_CLKSEL_CON(20), 0,
|
||||
RK3288_CLKGATE_CON(1), 15, GFLAGS),
|
||||
MUX(SCLK_UART3, "sclk_uart3", mux_uart3_p, 0,
|
||||
MUX(SCLK_UART3, "sclk_uart3", mux_uart3_p, CLK_SET_RATE_PARENT,
|
||||
RK3288_CLKSEL_CON(16), 8, 2, MFLAGS),
|
||||
COMPOSITE_NOMUX(0, "uart4_src", "uart_src", 0,
|
||||
RK3288_CLKSEL_CON(3), 0, 7, DFLAGS,
|
||||
RK3288_CLKGATE_CON(2), 12, GFLAGS),
|
||||
COMPOSITE_FRAC(0, "uart4_frac", "uart4_src", 0,
|
||||
COMPOSITE_FRAC(0, "uart4_frac", "uart4_src", CLK_SET_RATE_PARENT,
|
||||
RK3288_CLKSEL_CON(7), 0,
|
||||
RK3288_CLKGATE_CON(2), 13, GFLAGS),
|
||||
MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, 0,
|
||||
MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, CLK_SET_RATE_PARENT,
|
||||
RK3288_CLKSEL_CON(3), 8, 2, MFLAGS),
|
||||
|
||||
COMPOSITE(0, "mac_src", mux_pll_src_npll_cpll_gpll_p, 0,
|
||||
@ -598,7 +598,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
|
||||
GATE(0, "jtag", "ext_jtag", 0,
|
||||
RK3288_CLKGATE_CON(4), 14, GFLAGS),
|
||||
|
||||
COMPOSITE_NODIV(0, "usbphy480m_src", mux_usbphy480m_p, 0,
|
||||
COMPOSITE_NODIV(SCLK_USBPHY480M_SRC, "usbphy480m_src", mux_usbphy480m_p, 0,
|
||||
RK3288_CLKSEL_CON(13), 11, 2, MFLAGS,
|
||||
RK3288_CLKGATE_CON(5), 14, GFLAGS),
|
||||
COMPOSITE_NODIV(SCLK_HSICPHY480M, "sclk_hsicphy480m", mux_hsicphy480m_p, 0,
|
||||
@ -704,8 +704,8 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
|
||||
|
||||
GATE(SCLK_LCDC_PWM0, "sclk_lcdc_pwm0", "xin24m", 0, RK3288_CLKGATE_CON(13), 10, GFLAGS),
|
||||
GATE(SCLK_LCDC_PWM1, "sclk_lcdc_pwm1", "xin24m", 0, RK3288_CLKGATE_CON(13), 11, GFLAGS),
|
||||
GATE(0, "sclk_pvtm_core", "xin24m", 0, RK3288_CLKGATE_CON(5), 9, GFLAGS),
|
||||
GATE(0, "sclk_pvtm_gpu", "xin24m", 0, RK3288_CLKGATE_CON(5), 10, GFLAGS),
|
||||
GATE(SCLK_PVTM_CORE, "sclk_pvtm_core", "xin24m", 0, RK3288_CLKGATE_CON(5), 9, GFLAGS),
|
||||
GATE(SCLK_PVTM_GPU, "sclk_pvtm_gpu", "xin24m", 0, RK3288_CLKGATE_CON(5), 10, GFLAGS),
|
||||
GATE(0, "sclk_mipidsi_24m", "xin24m", 0, RK3288_CLKGATE_CON(5), 15, GFLAGS),
|
||||
|
||||
/* sclk_gpu gates */
|
||||
@ -805,6 +805,20 @@ static int rk3288_clk_suspend(void)
|
||||
rk3288_saved_cru_regs[i] =
|
||||
readl_relaxed(rk3288_cru_base + reg_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Switch PLLs other than DPLL (for SDRAM) to slow mode to
|
||||
* avoid crashes on resume. The Mask ROM on the system will
|
||||
* put APLL, CPLL, and GPLL into slow mode at resume time
|
||||
* anyway (which is why we restore them), but we might not
|
||||
* even make it to the Mask ROM if this isn't done at suspend
|
||||
* time.
|
||||
*
|
||||
* NOTE: only APLL truly matters here, but we'll do them all.
|
||||
*/
|
||||
|
||||
writel_relaxed(0xf3030000, rk3288_cru_base + RK3288_MODE_CON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -866,6 +880,14 @@ static void __init rk3288_clk_init(struct device_node *np)
|
||||
pr_warn("%s: could not register clock hclk_vcodec_pre: %ld\n",
|
||||
__func__, PTR_ERR(clk));
|
||||
|
||||
/* Watchdog pclk is controlled by RK3288_SGRF_SOC_CON0[1]. */
|
||||
clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_pd_alive", 0, 1, 1);
|
||||
if (IS_ERR(clk))
|
||||
pr_warn("%s: could not register clock pclk_wdt: %ld\n",
|
||||
__func__, PTR_ERR(clk));
|
||||
else
|
||||
rockchip_clk_add_lookup(clk, PCLK_WDT);
|
||||
|
||||
rockchip_clk_register_plls(rk3288_pll_clks,
|
||||
ARRAY_SIZE(rk3288_pll_clks),
|
||||
RK3288_GRF_SOC_STATUS1);
|
||||
|
@ -82,6 +82,26 @@ static const struct of_device_id exynos_audss_clk_of_match[] = {
|
||||
{},
|
||||
};
|
||||
|
||||
static void exynos_audss_clk_teardown(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = EXYNOS_MOUT_AUDSS; i < EXYNOS_DOUT_SRP; i++) {
|
||||
if (!IS_ERR(clk_table[i]))
|
||||
clk_unregister_mux(clk_table[i]);
|
||||
}
|
||||
|
||||
for (; i < EXYNOS_SRP_CLK; i++) {
|
||||
if (!IS_ERR(clk_table[i]))
|
||||
clk_unregister_divider(clk_table[i]);
|
||||
}
|
||||
|
||||
for (; i < clk_data.clk_num; i++) {
|
||||
if (!IS_ERR(clk_table[i]))
|
||||
clk_unregister_gate(clk_table[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* register exynos_audss clocks */
|
||||
static int exynos_audss_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
@ -219,10 +239,7 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
unregister:
|
||||
for (i = 0; i < clk_data.clk_num; i++) {
|
||||
if (!IS_ERR(clk_table[i]))
|
||||
clk_unregister(clk_table[i]);
|
||||
}
|
||||
exynos_audss_clk_teardown();
|
||||
|
||||
if (!IS_ERR(epll))
|
||||
clk_disable_unprepare(epll);
|
||||
@ -232,18 +249,13 @@ unregister:
|
||||
|
||||
static int exynos_audss_clk_remove(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
unregister_syscore_ops(&exynos_audss_clk_syscore_ops);
|
||||
#endif
|
||||
|
||||
of_clk_del_provider(pdev->dev.of_node);
|
||||
|
||||
for (i = 0; i < clk_data.clk_num; i++) {
|
||||
if (!IS_ERR(clk_table[i]))
|
||||
clk_unregister(clk_table[i]);
|
||||
}
|
||||
exynos_audss_clk_teardown();
|
||||
|
||||
if (!IS_ERR(epll))
|
||||
clk_disable_unprepare(epll);
|
||||
|
@ -104,27 +104,6 @@
|
||||
#define PWR_CTRL1_USE_CORE1_WFI (1 << 1)
|
||||
#define PWR_CTRL1_USE_CORE0_WFI (1 << 0)
|
||||
|
||||
/* list of PLLs to be registered */
|
||||
enum exynos3250_plls {
|
||||
apll, mpll, vpll, upll,
|
||||
nr_plls
|
||||
};
|
||||
|
||||
/* list of PLLs in DMC block to be registered */
|
||||
enum exynos3250_dmc_plls {
|
||||
bpll, epll,
|
||||
nr_dmc_plls
|
||||
};
|
||||
|
||||
static void __iomem *reg_base;
|
||||
static void __iomem *dmc_reg_base;
|
||||
|
||||
/*
|
||||
* Support for CMU save/restore across system suspends
|
||||
*/
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static struct samsung_clk_reg_dump *exynos3250_clk_regs;
|
||||
|
||||
static unsigned long exynos3250_cmu_clk_regs[] __initdata = {
|
||||
SRC_LEFTBUS,
|
||||
DIV_LEFTBUS,
|
||||
@ -195,43 +174,6 @@ static unsigned long exynos3250_cmu_clk_regs[] __initdata = {
|
||||
PWR_CTRL2,
|
||||
};
|
||||
|
||||
static int exynos3250_clk_suspend(void)
|
||||
{
|
||||
samsung_clk_save(reg_base, exynos3250_clk_regs,
|
||||
ARRAY_SIZE(exynos3250_cmu_clk_regs));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exynos3250_clk_resume(void)
|
||||
{
|
||||
samsung_clk_restore(reg_base, exynos3250_clk_regs,
|
||||
ARRAY_SIZE(exynos3250_cmu_clk_regs));
|
||||
}
|
||||
|
||||
static struct syscore_ops exynos3250_clk_syscore_ops = {
|
||||
.suspend = exynos3250_clk_suspend,
|
||||
.resume = exynos3250_clk_resume,
|
||||
};
|
||||
|
||||
static void exynos3250_clk_sleep_init(void)
|
||||
{
|
||||
exynos3250_clk_regs =
|
||||
samsung_clk_alloc_reg_dump(exynos3250_cmu_clk_regs,
|
||||
ARRAY_SIZE(exynos3250_cmu_clk_regs));
|
||||
if (!exynos3250_clk_regs) {
|
||||
pr_warn("%s: Failed to allocate sleep save data\n", __func__);
|
||||
goto err;
|
||||
}
|
||||
|
||||
register_syscore_ops(&exynos3250_clk_syscore_ops);
|
||||
return;
|
||||
err:
|
||||
kfree(exynos3250_clk_regs);
|
||||
}
|
||||
#else
|
||||
static inline void exynos3250_clk_sleep_init(void) { }
|
||||
#endif
|
||||
|
||||
/* list of all parent clock list */
|
||||
PNAME(mout_vpllsrc_p) = { "fin_pll", };
|
||||
|
||||
@ -782,18 +724,18 @@ static struct samsung_pll_rate_table exynos3250_vpll_rates[] = {
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct samsung_pll_clock exynos3250_plls[nr_plls] __initdata = {
|
||||
[apll] = PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll",
|
||||
APLL_LOCK, APLL_CON0, NULL),
|
||||
[mpll] = PLL(pll_35xx, CLK_FOUT_MPLL, "fout_mpll", "fin_pll",
|
||||
MPLL_LOCK, MPLL_CON0, NULL),
|
||||
[vpll] = PLL(pll_36xx, CLK_FOUT_VPLL, "fout_vpll", "fin_pll",
|
||||
VPLL_LOCK, VPLL_CON0, NULL),
|
||||
[upll] = PLL(pll_35xx, CLK_FOUT_UPLL, "fout_upll", "fin_pll",
|
||||
UPLL_LOCK, UPLL_CON0, NULL),
|
||||
static struct samsung_pll_clock exynos3250_plls[] __initdata = {
|
||||
PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll",
|
||||
APLL_LOCK, APLL_CON0, exynos3250_pll_rates),
|
||||
PLL(pll_35xx, CLK_FOUT_MPLL, "fout_mpll", "fin_pll",
|
||||
MPLL_LOCK, MPLL_CON0, exynos3250_pll_rates),
|
||||
PLL(pll_36xx, CLK_FOUT_VPLL, "fout_vpll", "fin_pll",
|
||||
VPLL_LOCK, VPLL_CON0, exynos3250_vpll_rates),
|
||||
PLL(pll_35xx, CLK_FOUT_UPLL, "fout_upll", "fin_pll",
|
||||
UPLL_LOCK, UPLL_CON0, exynos3250_pll_rates),
|
||||
};
|
||||
|
||||
static void __init exynos3_core_down_clock(void)
|
||||
static void __init exynos3_core_down_clock(void __iomem *reg_base)
|
||||
{
|
||||
unsigned int tmp;
|
||||
|
||||
@ -814,38 +756,31 @@ static void __init exynos3_core_down_clock(void)
|
||||
__raw_writel(0x0, reg_base + PWR_CTRL2);
|
||||
}
|
||||
|
||||
static struct samsung_cmu_info cmu_info __initdata = {
|
||||
.pll_clks = exynos3250_plls,
|
||||
.nr_pll_clks = ARRAY_SIZE(exynos3250_plls),
|
||||
.mux_clks = mux_clks,
|
||||
.nr_mux_clks = ARRAY_SIZE(mux_clks),
|
||||
.div_clks = div_clks,
|
||||
.nr_div_clks = ARRAY_SIZE(div_clks),
|
||||
.gate_clks = gate_clks,
|
||||
.nr_gate_clks = ARRAY_SIZE(gate_clks),
|
||||
.fixed_factor_clks = fixed_factor_clks,
|
||||
.nr_fixed_factor_clks = ARRAY_SIZE(fixed_factor_clks),
|
||||
.nr_clk_ids = CLK_NR_CLKS,
|
||||
.clk_regs = exynos3250_cmu_clk_regs,
|
||||
.nr_clk_regs = ARRAY_SIZE(exynos3250_cmu_clk_regs),
|
||||
};
|
||||
|
||||
static void __init exynos3250_cmu_init(struct device_node *np)
|
||||
{
|
||||
struct samsung_clk_provider *ctx;
|
||||
|
||||
reg_base = of_iomap(np, 0);
|
||||
if (!reg_base)
|
||||
panic("%s: failed to map registers\n", __func__);
|
||||
|
||||
ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS);
|
||||
ctx = samsung_cmu_register_one(np, &cmu_info);
|
||||
if (!ctx)
|
||||
panic("%s: unable to allocate context.\n", __func__);
|
||||
return;
|
||||
|
||||
samsung_clk_register_fixed_factor(ctx, fixed_factor_clks,
|
||||
ARRAY_SIZE(fixed_factor_clks));
|
||||
|
||||
exynos3250_plls[apll].rate_table = exynos3250_pll_rates;
|
||||
exynos3250_plls[mpll].rate_table = exynos3250_pll_rates;
|
||||
exynos3250_plls[vpll].rate_table = exynos3250_vpll_rates;
|
||||
exynos3250_plls[upll].rate_table = exynos3250_pll_rates;
|
||||
|
||||
samsung_clk_register_pll(ctx, exynos3250_plls,
|
||||
ARRAY_SIZE(exynos3250_plls), reg_base);
|
||||
|
||||
samsung_clk_register_mux(ctx, mux_clks, ARRAY_SIZE(mux_clks));
|
||||
samsung_clk_register_div(ctx, div_clks, ARRAY_SIZE(div_clks));
|
||||
samsung_clk_register_gate(ctx, gate_clks, ARRAY_SIZE(gate_clks));
|
||||
|
||||
exynos3_core_down_clock();
|
||||
|
||||
exynos3250_clk_sleep_init();
|
||||
|
||||
samsung_clk_of_add_provider(np, ctx);
|
||||
exynos3_core_down_clock(ctx->reg_base);
|
||||
}
|
||||
CLK_OF_DECLARE(exynos3250_cmu, "samsung,exynos3250-cmu", exynos3250_cmu_init);
|
||||
|
||||
@ -872,12 +807,6 @@ CLK_OF_DECLARE(exynos3250_cmu, "samsung,exynos3250-cmu", exynos3250_cmu_init);
|
||||
#define EPLL_CON2 0x111c
|
||||
#define SRC_EPLL 0x1120
|
||||
|
||||
/*
|
||||
* Support for CMU save/restore across system suspends
|
||||
*/
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static struct samsung_clk_reg_dump *exynos3250_dmc_clk_regs;
|
||||
|
||||
static unsigned long exynos3250_cmu_dmc_clk_regs[] __initdata = {
|
||||
BPLL_LOCK,
|
||||
BPLL_CON0,
|
||||
@ -899,43 +828,6 @@ static unsigned long exynos3250_cmu_dmc_clk_regs[] __initdata = {
|
||||
SRC_EPLL,
|
||||
};
|
||||
|
||||
static int exynos3250_dmc_clk_suspend(void)
|
||||
{
|
||||
samsung_clk_save(dmc_reg_base, exynos3250_dmc_clk_regs,
|
||||
ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exynos3250_dmc_clk_resume(void)
|
||||
{
|
||||
samsung_clk_restore(dmc_reg_base, exynos3250_dmc_clk_regs,
|
||||
ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs));
|
||||
}
|
||||
|
||||
static struct syscore_ops exynos3250_dmc_clk_syscore_ops = {
|
||||
.suspend = exynos3250_dmc_clk_suspend,
|
||||
.resume = exynos3250_dmc_clk_resume,
|
||||
};
|
||||
|
||||
static void exynos3250_dmc_clk_sleep_init(void)
|
||||
{
|
||||
exynos3250_dmc_clk_regs =
|
||||
samsung_clk_alloc_reg_dump(exynos3250_cmu_dmc_clk_regs,
|
||||
ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs));
|
||||
if (!exynos3250_dmc_clk_regs) {
|
||||
pr_warn("%s: Failed to allocate sleep save data\n", __func__);
|
||||
goto err;
|
||||
}
|
||||
|
||||
register_syscore_ops(&exynos3250_dmc_clk_syscore_ops);
|
||||
return;
|
||||
err:
|
||||
kfree(exynos3250_dmc_clk_regs);
|
||||
}
|
||||
#else
|
||||
static inline void exynos3250_dmc_clk_sleep_init(void) { }
|
||||
#endif
|
||||
|
||||
PNAME(mout_epll_p) = { "fin_pll", "fout_epll", };
|
||||
PNAME(mout_bpll_p) = { "fin_pll", "fout_bpll", };
|
||||
PNAME(mout_mpll_mif_p) = { "fin_pll", "sclk_mpll_mif", };
|
||||
@ -977,43 +869,28 @@ static struct samsung_div_clock dmc_div_clks[] __initdata = {
|
||||
DIV(CLK_DIV_DMCD, "div_dmcd", "div_dmc", DIV_DMC1, 11, 3),
|
||||
};
|
||||
|
||||
static struct samsung_pll_clock exynos3250_dmc_plls[nr_dmc_plls] __initdata = {
|
||||
[bpll] = PLL(pll_35xx, CLK_FOUT_BPLL, "fout_bpll", "fin_pll",
|
||||
BPLL_LOCK, BPLL_CON0, NULL),
|
||||
[epll] = PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll",
|
||||
EPLL_LOCK, EPLL_CON0, NULL),
|
||||
static struct samsung_pll_clock exynos3250_dmc_plls[] __initdata = {
|
||||
PLL(pll_35xx, CLK_FOUT_BPLL, "fout_bpll", "fin_pll",
|
||||
BPLL_LOCK, BPLL_CON0, exynos3250_pll_rates),
|
||||
PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll",
|
||||
EPLL_LOCK, EPLL_CON0, exynos3250_epll_rates),
|
||||
};
|
||||
|
||||
static struct samsung_cmu_info dmc_cmu_info __initdata = {
|
||||
.pll_clks = exynos3250_dmc_plls,
|
||||
.nr_pll_clks = ARRAY_SIZE(exynos3250_dmc_plls),
|
||||
.mux_clks = dmc_mux_clks,
|
||||
.nr_mux_clks = ARRAY_SIZE(dmc_mux_clks),
|
||||
.div_clks = dmc_div_clks,
|
||||
.nr_div_clks = ARRAY_SIZE(dmc_div_clks),
|
||||
.nr_clk_ids = NR_CLKS_DMC,
|
||||
.clk_regs = exynos3250_cmu_dmc_clk_regs,
|
||||
.nr_clk_regs = ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs),
|
||||
};
|
||||
|
||||
static void __init exynos3250_cmu_dmc_init(struct device_node *np)
|
||||
{
|
||||
struct samsung_clk_provider *ctx;
|
||||
|
||||
dmc_reg_base = of_iomap(np, 0);
|
||||
if (!dmc_reg_base)
|
||||
panic("%s: failed to map registers\n", __func__);
|
||||
|
||||
ctx = samsung_clk_init(np, dmc_reg_base, NR_CLKS_DMC);
|
||||
if (!ctx)
|
||||
panic("%s: unable to allocate context.\n", __func__);
|
||||
|
||||
exynos3250_dmc_plls[bpll].rate_table = exynos3250_pll_rates;
|
||||
exynos3250_dmc_plls[epll].rate_table = exynos3250_epll_rates;
|
||||
|
||||
pr_err("CLK registering epll bpll: %d, %d, %d, %d\n",
|
||||
exynos3250_dmc_plls[bpll].rate_table[0].rate,
|
||||
exynos3250_dmc_plls[bpll].rate_table[0].mdiv,
|
||||
exynos3250_dmc_plls[bpll].rate_table[0].pdiv,
|
||||
exynos3250_dmc_plls[bpll].rate_table[0].sdiv
|
||||
);
|
||||
samsung_clk_register_pll(ctx, exynos3250_dmc_plls,
|
||||
ARRAY_SIZE(exynos3250_dmc_plls), dmc_reg_base);
|
||||
|
||||
samsung_clk_register_mux(ctx, dmc_mux_clks, ARRAY_SIZE(dmc_mux_clks));
|
||||
samsung_clk_register_div(ctx, dmc_div_clks, ARRAY_SIZE(dmc_div_clks));
|
||||
|
||||
exynos3250_dmc_clk_sleep_init();
|
||||
|
||||
samsung_clk_of_add_provider(np, ctx);
|
||||
samsung_cmu_register_one(np, &dmc_cmu_info);
|
||||
}
|
||||
CLK_OF_DECLARE(exynos3250_cmu_dmc, "samsung,exynos3250-cmu-dmc",
|
||||
exynos3250_cmu_dmc_init);
|
||||
|
@ -703,12 +703,12 @@ static struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = {
|
||||
|
||||
/* list of divider clocks supported in all exynos4 soc's */
|
||||
static struct samsung_div_clock exynos4_div_clks[] __initdata = {
|
||||
DIV(0, "div_gdl", "mout_gdl", DIV_LEFTBUS, 0, 3),
|
||||
DIV(CLK_DIV_GDL, "div_gdl", "mout_gdl", DIV_LEFTBUS, 0, 3),
|
||||
DIV(0, "div_gpl", "div_gdl", DIV_LEFTBUS, 4, 3),
|
||||
DIV(0, "div_clkout_leftbus", "mout_clkout_leftbus",
|
||||
CLKOUT_CMU_LEFTBUS, 8, 6),
|
||||
|
||||
DIV(0, "div_gdr", "mout_gdr", DIV_RIGHTBUS, 0, 3),
|
||||
DIV(CLK_DIV_GDR, "div_gdr", "mout_gdr", DIV_RIGHTBUS, 0, 3),
|
||||
DIV(0, "div_gpr", "div_gdr", DIV_RIGHTBUS, 4, 3),
|
||||
DIV(0, "div_clkout_rightbus", "mout_clkout_rightbus",
|
||||
CLKOUT_CMU_RIGHTBUS, 8, 6),
|
||||
@ -781,10 +781,10 @@ static struct samsung_div_clock exynos4_div_clks[] __initdata = {
|
||||
CLK_SET_RATE_PARENT, 0),
|
||||
DIV(0, "div_clkout_top", "mout_clkout_top", CLKOUT_CMU_TOP, 8, 6),
|
||||
|
||||
DIV(0, "div_acp", "mout_dmc_bus", DIV_DMC0, 0, 3),
|
||||
DIV(CLK_DIV_ACP, "div_acp", "mout_dmc_bus", DIV_DMC0, 0, 3),
|
||||
DIV(0, "div_acp_pclk", "div_acp", DIV_DMC0, 4, 3),
|
||||
DIV(0, "div_dphy", "mout_dphy", DIV_DMC0, 8, 3),
|
||||
DIV(0, "div_dmc", "mout_dmc_bus", DIV_DMC0, 12, 3),
|
||||
DIV(CLK_DIV_DMC, "div_dmc", "mout_dmc_bus", DIV_DMC0, 12, 3),
|
||||
DIV(0, "div_dmcd", "div_dmc", DIV_DMC0, 16, 3),
|
||||
DIV(0, "div_dmcp", "div_dmcd", DIV_DMC0, 20, 3),
|
||||
DIV(0, "div_pwi", "mout_pwi", DIV_DMC1, 8, 4),
|
||||
@ -829,7 +829,7 @@ static struct samsung_div_clock exynos4x12_div_clks[] __initdata = {
|
||||
DIV_F(CLK_DIV_MCUISP1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1,
|
||||
8, 3, CLK_GET_RATE_NOCACHE, 0),
|
||||
DIV(CLK_SCLK_FIMG2D, "sclk_fimg2d", "mout_g2d", DIV_DMC1, 0, 4),
|
||||
DIV(0, "div_c2c", "mout_c2c", DIV_DMC1, 4, 3),
|
||||
DIV(CLK_DIV_C2C, "div_c2c", "mout_c2c", DIV_DMC1, 4, 3),
|
||||
DIV(0, "div_c2c_aclk", "div_c2c", DIV_DMC1, 12, 3),
|
||||
};
|
||||
|
||||
|
@ -113,19 +113,6 @@
|
||||
#define DIV_CPU0 0x14500
|
||||
#define DIV_CPU1 0x14504
|
||||
|
||||
enum exynos4415_plls {
|
||||
apll, epll, g3d_pll, isp_pll, disp_pll,
|
||||
nr_plls,
|
||||
};
|
||||
|
||||
static struct samsung_clk_provider *exynos4415_ctx;
|
||||
|
||||
/*
|
||||
* Support for CMU save/restore across system suspends
|
||||
*/
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static struct samsung_clk_reg_dump *exynos4415_clk_regs;
|
||||
|
||||
static unsigned long exynos4415_cmu_clk_regs[] __initdata = {
|
||||
SRC_LEFTBUS,
|
||||
DIV_LEFTBUS,
|
||||
@ -219,41 +206,6 @@ static unsigned long exynos4415_cmu_clk_regs[] __initdata = {
|
||||
DIV_CPU1,
|
||||
};
|
||||
|
||||
static int exynos4415_clk_suspend(void)
|
||||
{
|
||||
samsung_clk_save(exynos4415_ctx->reg_base, exynos4415_clk_regs,
|
||||
ARRAY_SIZE(exynos4415_cmu_clk_regs));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exynos4415_clk_resume(void)
|
||||
{
|
||||
samsung_clk_restore(exynos4415_ctx->reg_base, exynos4415_clk_regs,
|
||||
ARRAY_SIZE(exynos4415_cmu_clk_regs));
|
||||
}
|
||||
|
||||
static struct syscore_ops exynos4415_clk_syscore_ops = {
|
||||
.suspend = exynos4415_clk_suspend,
|
||||
.resume = exynos4415_clk_resume,
|
||||
};
|
||||
|
||||
static void exynos4415_clk_sleep_init(void)
|
||||
{
|
||||
exynos4415_clk_regs =
|
||||
samsung_clk_alloc_reg_dump(exynos4415_cmu_clk_regs,
|
||||
ARRAY_SIZE(exynos4415_cmu_clk_regs));
|
||||
if (!exynos4415_clk_regs) {
|
||||
pr_warn("%s: Failed to allocate sleep save data\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
register_syscore_ops(&exynos4415_clk_syscore_ops);
|
||||
}
|
||||
#else
|
||||
static inline void exynos4415_clk_sleep_init(void) { }
|
||||
#endif
|
||||
|
||||
/* list of all parent clock list */
|
||||
PNAME(mout_g3d_pllsrc_p) = { "fin_pll", };
|
||||
|
||||
@ -959,56 +911,40 @@ static struct samsung_pll_rate_table exynos4415_epll_rates[] = {
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct samsung_pll_clock exynos4415_plls[nr_plls] __initdata = {
|
||||
[apll] = PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll",
|
||||
APLL_LOCK, APLL_CON0, NULL),
|
||||
[epll] = PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll",
|
||||
EPLL_LOCK, EPLL_CON0, NULL),
|
||||
[g3d_pll] = PLL(pll_35xx, CLK_FOUT_G3D_PLL, "fout_g3d_pll",
|
||||
"mout_g3d_pllsrc", G3D_PLL_LOCK, G3D_PLL_CON0, NULL),
|
||||
[isp_pll] = PLL(pll_35xx, CLK_FOUT_ISP_PLL, "fout_isp_pll", "fin_pll",
|
||||
ISP_PLL_LOCK, ISP_PLL_CON0, NULL),
|
||||
[disp_pll] = PLL(pll_35xx, CLK_FOUT_DISP_PLL, "fout_disp_pll",
|
||||
"fin_pll", DISP_PLL_LOCK, DISP_PLL_CON0, NULL),
|
||||
static struct samsung_pll_clock exynos4415_plls[] __initdata = {
|
||||
PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll",
|
||||
APLL_LOCK, APLL_CON0, exynos4415_pll_rates),
|
||||
PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll",
|
||||
EPLL_LOCK, EPLL_CON0, exynos4415_epll_rates),
|
||||
PLL(pll_35xx, CLK_FOUT_G3D_PLL, "fout_g3d_pll", "mout_g3d_pllsrc",
|
||||
G3D_PLL_LOCK, G3D_PLL_CON0, exynos4415_pll_rates),
|
||||
PLL(pll_35xx, CLK_FOUT_ISP_PLL, "fout_isp_pll", "fin_pll",
|
||||
ISP_PLL_LOCK, ISP_PLL_CON0, exynos4415_pll_rates),
|
||||
PLL(pll_35xx, CLK_FOUT_DISP_PLL, "fout_disp_pll",
|
||||
"fin_pll", DISP_PLL_LOCK, DISP_PLL_CON0, exynos4415_pll_rates),
|
||||
};
|
||||
|
||||
static struct samsung_cmu_info cmu_info __initdata = {
|
||||
.pll_clks = exynos4415_plls,
|
||||
.nr_pll_clks = ARRAY_SIZE(exynos4415_plls),
|
||||
.mux_clks = exynos4415_mux_clks,
|
||||
.nr_mux_clks = ARRAY_SIZE(exynos4415_mux_clks),
|
||||
.div_clks = exynos4415_div_clks,
|
||||
.nr_div_clks = ARRAY_SIZE(exynos4415_div_clks),
|
||||
.gate_clks = exynos4415_gate_clks,
|
||||
.nr_gate_clks = ARRAY_SIZE(exynos4415_gate_clks),
|
||||
.fixed_clks = exynos4415_fixed_rate_clks,
|
||||
.nr_fixed_clks = ARRAY_SIZE(exynos4415_fixed_rate_clks),
|
||||
.fixed_factor_clks = exynos4415_fixed_factor_clks,
|
||||
.nr_fixed_factor_clks = ARRAY_SIZE(exynos4415_fixed_factor_clks),
|
||||
.nr_clk_ids = CLK_NR_CLKS,
|
||||
.clk_regs = exynos4415_cmu_clk_regs,
|
||||
.nr_clk_regs = ARRAY_SIZE(exynos4415_cmu_clk_regs),
|
||||
};
|
||||
|
||||
static void __init exynos4415_cmu_init(struct device_node *np)
|
||||
{
|
||||
void __iomem *reg_base;
|
||||
|
||||
reg_base = of_iomap(np, 0);
|
||||
if (!reg_base)
|
||||
panic("%s: failed to map registers\n", __func__);
|
||||
|
||||
exynos4415_ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS);
|
||||
if (!exynos4415_ctx)
|
||||
panic("%s: unable to allocate context.\n", __func__);
|
||||
|
||||
exynos4415_plls[apll].rate_table = exynos4415_pll_rates;
|
||||
exynos4415_plls[epll].rate_table = exynos4415_epll_rates;
|
||||
exynos4415_plls[g3d_pll].rate_table = exynos4415_pll_rates;
|
||||
exynos4415_plls[isp_pll].rate_table = exynos4415_pll_rates;
|
||||
exynos4415_plls[disp_pll].rate_table = exynos4415_pll_rates;
|
||||
|
||||
samsung_clk_register_fixed_factor(exynos4415_ctx,
|
||||
exynos4415_fixed_factor_clks,
|
||||
ARRAY_SIZE(exynos4415_fixed_factor_clks));
|
||||
samsung_clk_register_fixed_rate(exynos4415_ctx,
|
||||
exynos4415_fixed_rate_clks,
|
||||
ARRAY_SIZE(exynos4415_fixed_rate_clks));
|
||||
|
||||
samsung_clk_register_pll(exynos4415_ctx, exynos4415_plls,
|
||||
ARRAY_SIZE(exynos4415_plls), reg_base);
|
||||
samsung_clk_register_mux(exynos4415_ctx, exynos4415_mux_clks,
|
||||
ARRAY_SIZE(exynos4415_mux_clks));
|
||||
samsung_clk_register_div(exynos4415_ctx, exynos4415_div_clks,
|
||||
ARRAY_SIZE(exynos4415_div_clks));
|
||||
samsung_clk_register_gate(exynos4415_ctx, exynos4415_gate_clks,
|
||||
ARRAY_SIZE(exynos4415_gate_clks));
|
||||
|
||||
exynos4415_clk_sleep_init();
|
||||
|
||||
samsung_clk_of_add_provider(np, exynos4415_ctx);
|
||||
samsung_cmu_register_one(np, &cmu_info);
|
||||
}
|
||||
CLK_OF_DECLARE(exynos4415_cmu, "samsung,exynos4415-cmu", exynos4415_cmu_init);
|
||||
|
||||
@ -1027,16 +963,6 @@ CLK_OF_DECLARE(exynos4415_cmu, "samsung,exynos4415-cmu", exynos4415_cmu_init);
|
||||
#define SRC_DMC 0x300
|
||||
#define DIV_DMC1 0x504
|
||||
|
||||
enum exynos4415_dmc_plls {
|
||||
mpll, bpll,
|
||||
nr_dmc_plls,
|
||||
};
|
||||
|
||||
static struct samsung_clk_provider *exynos4415_dmc_ctx;
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static struct samsung_clk_reg_dump *exynos4415_dmc_clk_regs;
|
||||
|
||||
static unsigned long exynos4415_cmu_dmc_clk_regs[] __initdata = {
|
||||
MPLL_LOCK,
|
||||
MPLL_CON0,
|
||||
@ -1050,42 +976,6 @@ static unsigned long exynos4415_cmu_dmc_clk_regs[] __initdata = {
|
||||
DIV_DMC1,
|
||||
};
|
||||
|
||||
static int exynos4415_dmc_clk_suspend(void)
|
||||
{
|
||||
samsung_clk_save(exynos4415_dmc_ctx->reg_base,
|
||||
exynos4415_dmc_clk_regs,
|
||||
ARRAY_SIZE(exynos4415_cmu_dmc_clk_regs));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exynos4415_dmc_clk_resume(void)
|
||||
{
|
||||
samsung_clk_restore(exynos4415_dmc_ctx->reg_base,
|
||||
exynos4415_dmc_clk_regs,
|
||||
ARRAY_SIZE(exynos4415_cmu_dmc_clk_regs));
|
||||
}
|
||||
|
||||
static struct syscore_ops exynos4415_dmc_clk_syscore_ops = {
|
||||
.suspend = exynos4415_dmc_clk_suspend,
|
||||
.resume = exynos4415_dmc_clk_resume,
|
||||
};
|
||||
|
||||
static void exynos4415_dmc_clk_sleep_init(void)
|
||||
{
|
||||
exynos4415_dmc_clk_regs =
|
||||
samsung_clk_alloc_reg_dump(exynos4415_cmu_dmc_clk_regs,
|
||||
ARRAY_SIZE(exynos4415_cmu_dmc_clk_regs));
|
||||
if (!exynos4415_dmc_clk_regs) {
|
||||
pr_warn("%s: Failed to allocate sleep save data\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
register_syscore_ops(&exynos4415_dmc_clk_syscore_ops);
|
||||
}
|
||||
#else
|
||||
static inline void exynos4415_dmc_clk_sleep_init(void) { }
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
PNAME(mout_mpll_p) = { "fin_pll", "fout_mpll", };
|
||||
PNAME(mout_bpll_p) = { "fin_pll", "fout_bpll", };
|
||||
PNAME(mbpll_p) = { "mout_mpll", "mout_bpll", };
|
||||
@ -1107,38 +997,28 @@ static struct samsung_div_clock exynos4415_dmc_div_clks[] __initdata = {
|
||||
DIV(CLK_DMC_DIV_MPLL_PRE, "div_mpll_pre", "mout_mpll", DIV_DMC1, 8, 2),
|
||||
};
|
||||
|
||||
static struct samsung_pll_clock exynos4415_dmc_plls[nr_dmc_plls] __initdata = {
|
||||
[mpll] = PLL(pll_35xx, CLK_DMC_FOUT_MPLL, "fout_mpll", "fin_pll",
|
||||
MPLL_LOCK, MPLL_CON0, NULL),
|
||||
[bpll] = PLL(pll_35xx, CLK_DMC_FOUT_BPLL, "fout_bpll", "fin_pll",
|
||||
BPLL_LOCK, BPLL_CON0, NULL),
|
||||
static struct samsung_pll_clock exynos4415_dmc_plls[] __initdata = {
|
||||
PLL(pll_35xx, CLK_DMC_FOUT_MPLL, "fout_mpll", "fin_pll",
|
||||
MPLL_LOCK, MPLL_CON0, exynos4415_pll_rates),
|
||||
PLL(pll_35xx, CLK_DMC_FOUT_BPLL, "fout_bpll", "fin_pll",
|
||||
BPLL_LOCK, BPLL_CON0, exynos4415_pll_rates),
|
||||
};
|
||||
|
||||
static struct samsung_cmu_info cmu_dmc_info __initdata = {
|
||||
.pll_clks = exynos4415_dmc_plls,
|
||||
.nr_pll_clks = ARRAY_SIZE(exynos4415_dmc_plls),
|
||||
.mux_clks = exynos4415_dmc_mux_clks,
|
||||
.nr_mux_clks = ARRAY_SIZE(exynos4415_dmc_mux_clks),
|
||||
.div_clks = exynos4415_dmc_div_clks,
|
||||
.nr_div_clks = ARRAY_SIZE(exynos4415_dmc_div_clks),
|
||||
.nr_clk_ids = NR_CLKS_DMC,
|
||||
.clk_regs = exynos4415_cmu_dmc_clk_regs,
|
||||
.nr_clk_regs = ARRAY_SIZE(exynos4415_cmu_dmc_clk_regs),
|
||||
};
|
||||
|
||||
static void __init exynos4415_cmu_dmc_init(struct device_node *np)
|
||||
{
|
||||
void __iomem *reg_base;
|
||||
|
||||
reg_base = of_iomap(np, 0);
|
||||
if (!reg_base)
|
||||
panic("%s: failed to map registers\n", __func__);
|
||||
|
||||
exynos4415_dmc_ctx = samsung_clk_init(np, reg_base, NR_CLKS_DMC);
|
||||
if (!exynos4415_dmc_ctx)
|
||||
panic("%s: unable to allocate context.\n", __func__);
|
||||
|
||||
exynos4415_dmc_plls[mpll].rate_table = exynos4415_pll_rates;
|
||||
exynos4415_dmc_plls[bpll].rate_table = exynos4415_pll_rates;
|
||||
|
||||
samsung_clk_register_pll(exynos4415_dmc_ctx, exynos4415_dmc_plls,
|
||||
ARRAY_SIZE(exynos4415_dmc_plls), reg_base);
|
||||
samsung_clk_register_mux(exynos4415_dmc_ctx, exynos4415_dmc_mux_clks,
|
||||
ARRAY_SIZE(exynos4415_dmc_mux_clks));
|
||||
samsung_clk_register_div(exynos4415_dmc_ctx, exynos4415_dmc_div_clks,
|
||||
ARRAY_SIZE(exynos4415_dmc_div_clks));
|
||||
|
||||
exynos4415_dmc_clk_sleep_init();
|
||||
|
||||
samsung_clk_of_add_provider(np, exynos4415_dmc_ctx);
|
||||
samsung_cmu_register_one(np, &cmu_dmc_info);
|
||||
}
|
||||
CLK_OF_DECLARE(exynos4415_cmu_dmc, "samsung,exynos4415-cmu-dmc",
|
||||
exynos4415_cmu_dmc_init);
|
||||
|
@ -34,6 +34,7 @@
|
||||
#define DIV_TOPC0 0x0600
|
||||
#define DIV_TOPC1 0x0604
|
||||
#define DIV_TOPC3 0x060C
|
||||
#define ENABLE_ACLK_TOPC1 0x0804
|
||||
|
||||
static struct samsung_fixed_factor_clock topc_fixed_factor_clks[] __initdata = {
|
||||
FFACTOR(0, "ffac_topc_bus0_pll_div2", "mout_bus0_pll_ctrl", 1, 2, 0),
|
||||
@ -45,6 +46,7 @@ static struct samsung_fixed_factor_clock topc_fixed_factor_clks[] __initdata = {
|
||||
};
|
||||
|
||||
/* List of parent clocks for Muxes in CMU_TOPC */
|
||||
PNAME(mout_aud_pll_ctrl_p) = { "fin_pll", "fout_aud_pll" };
|
||||
PNAME(mout_bus0_pll_ctrl_p) = { "fin_pll", "fout_bus0_pll" };
|
||||
PNAME(mout_bus1_pll_ctrl_p) = { "fin_pll", "fout_bus1_pll" };
|
||||
PNAME(mout_cc_pll_ctrl_p) = { "fin_pll", "fout_cc_pll" };
|
||||
@ -104,9 +106,11 @@ static struct samsung_mux_clock topc_mux_clks[] __initdata = {
|
||||
|
||||
MUX(0, "mout_sclk_bus0_pll_out", mout_sclk_bus0_pll_out_p,
|
||||
MUX_SEL_TOPC1, 16, 1),
|
||||
MUX(0, "mout_aud_pll_ctrl", mout_aud_pll_ctrl_p, MUX_SEL_TOPC1, 0, 1),
|
||||
|
||||
MUX(0, "mout_aclk_ccore_133", mout_topc_group2, MUX_SEL_TOPC2, 4, 2),
|
||||
|
||||
MUX(0, "mout_aclk_mscl_532", mout_topc_group2, MUX_SEL_TOPC3, 20, 2),
|
||||
MUX(0, "mout_aclk_peris_66", mout_topc_group2, MUX_SEL_TOPC3, 24, 2),
|
||||
};
|
||||
|
||||
@ -114,6 +118,8 @@ static struct samsung_div_clock topc_div_clks[] __initdata = {
|
||||
DIV(DOUT_ACLK_CCORE_133, "dout_aclk_ccore_133", "mout_aclk_ccore_133",
|
||||
DIV_TOPC0, 4, 4),
|
||||
|
||||
DIV(DOUT_ACLK_MSCL_532, "dout_aclk_mscl_532", "mout_aclk_mscl_532",
|
||||
DIV_TOPC1, 20, 4),
|
||||
DIV(DOUT_ACLK_PERIS, "dout_aclk_peris_66", "mout_aclk_peris_66",
|
||||
DIV_TOPC1, 24, 4),
|
||||
|
||||
@ -125,6 +131,18 @@ static struct samsung_div_clock topc_div_clks[] __initdata = {
|
||||
DIV_TOPC3, 12, 3),
|
||||
DIV(DOUT_SCLK_MFC_PLL, "dout_sclk_mfc_pll", "mout_mfc_pll_ctrl",
|
||||
DIV_TOPC3, 16, 3),
|
||||
DIV(DOUT_SCLK_AUD_PLL, "dout_sclk_aud_pll", "mout_aud_pll_ctrl",
|
||||
DIV_TOPC3, 28, 3),
|
||||
};
|
||||
|
||||
static struct samsung_pll_rate_table pll1460x_24mhz_tbl[] __initdata = {
|
||||
PLL_36XX_RATE(491520000, 20, 1, 0, 31457),
|
||||
{},
|
||||
};
|
||||
|
||||
static struct samsung_gate_clock topc_gate_clks[] __initdata = {
|
||||
GATE(ACLK_MSCL_532, "aclk_mscl_532", "dout_aclk_mscl_532",
|
||||
ENABLE_ACLK_TOPC1, 20, 0, 0),
|
||||
};
|
||||
|
||||
static struct samsung_pll_clock topc_pll_clks[] __initdata = {
|
||||
@ -136,8 +154,8 @@ static struct samsung_pll_clock topc_pll_clks[] __initdata = {
|
||||
BUS1_DPLL_CON0, NULL),
|
||||
PLL(pll_1452x, 0, "fout_mfc_pll", "fin_pll", MFC_PLL_LOCK,
|
||||
MFC_PLL_CON0, NULL),
|
||||
PLL(pll_1460x, 0, "fout_aud_pll", "fin_pll", AUD_PLL_LOCK,
|
||||
AUD_PLL_CON0, NULL),
|
||||
PLL(pll_1460x, FOUT_AUD_PLL, "fout_aud_pll", "fin_pll", AUD_PLL_LOCK,
|
||||
AUD_PLL_CON0, pll1460x_24mhz_tbl),
|
||||
};
|
||||
|
||||
static struct samsung_cmu_info topc_cmu_info __initdata = {
|
||||
@ -147,6 +165,8 @@ static struct samsung_cmu_info topc_cmu_info __initdata = {
|
||||
.nr_mux_clks = ARRAY_SIZE(topc_mux_clks),
|
||||
.div_clks = topc_div_clks,
|
||||
.nr_div_clks = ARRAY_SIZE(topc_div_clks),
|
||||
.gate_clks = topc_gate_clks,
|
||||
.nr_gate_clks = ARRAY_SIZE(topc_gate_clks),
|
||||
.fixed_factor_clks = topc_fixed_factor_clks,
|
||||
.nr_fixed_factor_clks = ARRAY_SIZE(topc_fixed_factor_clks),
|
||||
.nr_clk_ids = TOPC_NR_CLK,
|
||||
@ -166,9 +186,18 @@ CLK_OF_DECLARE(exynos7_clk_topc, "samsung,exynos7-clock-topc",
|
||||
#define MUX_SEL_TOP00 0x0200
|
||||
#define MUX_SEL_TOP01 0x0204
|
||||
#define MUX_SEL_TOP03 0x020C
|
||||
#define MUX_SEL_TOP0_PERIC0 0x0230
|
||||
#define MUX_SEL_TOP0_PERIC1 0x0234
|
||||
#define MUX_SEL_TOP0_PERIC2 0x0238
|
||||
#define MUX_SEL_TOP0_PERIC3 0x023C
|
||||
#define DIV_TOP03 0x060C
|
||||
#define DIV_TOP0_PERIC0 0x0630
|
||||
#define DIV_TOP0_PERIC1 0x0634
|
||||
#define DIV_TOP0_PERIC2 0x0638
|
||||
#define DIV_TOP0_PERIC3 0x063C
|
||||
#define ENABLE_SCLK_TOP0_PERIC0 0x0A30
|
||||
#define ENABLE_SCLK_TOP0_PERIC1 0x0A34
|
||||
#define ENABLE_SCLK_TOP0_PERIC2 0x0A38
|
||||
#define ENABLE_SCLK_TOP0_PERIC3 0x0A3C
|
||||
|
||||
/* List of parent clocks for Muxes in CMU_TOP0 */
|
||||
@ -176,6 +205,7 @@ PNAME(mout_bus0_pll_p) = { "fin_pll", "dout_sclk_bus0_pll" };
|
||||
PNAME(mout_bus1_pll_p) = { "fin_pll", "dout_sclk_bus1_pll" };
|
||||
PNAME(mout_cc_pll_p) = { "fin_pll", "dout_sclk_cc_pll" };
|
||||
PNAME(mout_mfc_pll_p) = { "fin_pll", "dout_sclk_mfc_pll" };
|
||||
PNAME(mout_aud_pll_p) = { "fin_pll", "dout_sclk_aud_pll" };
|
||||
|
||||
PNAME(mout_top0_half_bus0_pll_p) = {"mout_top0_bus0_pll",
|
||||
"ffac_top0_bus0_pll_div2"};
|
||||
@ -189,18 +219,34 @@ PNAME(mout_top0_half_mfc_pll_p) = {"mout_top0_mfc_pll",
|
||||
PNAME(mout_top0_group1) = {"mout_top0_half_bus0_pll",
|
||||
"mout_top0_half_bus1_pll", "mout_top0_half_cc_pll",
|
||||
"mout_top0_half_mfc_pll"};
|
||||
PNAME(mout_top0_group3) = {"ioclk_audiocdclk0",
|
||||
"ioclk_audiocdclk1", "ioclk_spdif_extclk",
|
||||
"mout_top0_aud_pll", "mout_top0_half_bus0_pll",
|
||||
"mout_top0_half_bus1_pll"};
|
||||
PNAME(mout_top0_group4) = {"ioclk_audiocdclk1", "mout_top0_aud_pll",
|
||||
"mout_top0_half_bus0_pll", "mout_top0_half_bus1_pll"};
|
||||
|
||||
static unsigned long top0_clk_regs[] __initdata = {
|
||||
MUX_SEL_TOP00,
|
||||
MUX_SEL_TOP01,
|
||||
MUX_SEL_TOP03,
|
||||
MUX_SEL_TOP0_PERIC0,
|
||||
MUX_SEL_TOP0_PERIC1,
|
||||
MUX_SEL_TOP0_PERIC2,
|
||||
MUX_SEL_TOP0_PERIC3,
|
||||
DIV_TOP03,
|
||||
DIV_TOP0_PERIC0,
|
||||
DIV_TOP0_PERIC1,
|
||||
DIV_TOP0_PERIC2,
|
||||
DIV_TOP0_PERIC3,
|
||||
ENABLE_SCLK_TOP0_PERIC0,
|
||||
ENABLE_SCLK_TOP0_PERIC1,
|
||||
ENABLE_SCLK_TOP0_PERIC2,
|
||||
ENABLE_SCLK_TOP0_PERIC3,
|
||||
};
|
||||
|
||||
static struct samsung_mux_clock top0_mux_clks[] __initdata = {
|
||||
MUX(0, "mout_top0_aud_pll", mout_aud_pll_p, MUX_SEL_TOP00, 0, 1),
|
||||
MUX(0, "mout_top0_mfc_pll", mout_mfc_pll_p, MUX_SEL_TOP00, 4, 1),
|
||||
MUX(0, "mout_top0_cc_pll", mout_cc_pll_p, MUX_SEL_TOP00, 8, 1),
|
||||
MUX(0, "mout_top0_bus1_pll", mout_bus1_pll_p, MUX_SEL_TOP00, 12, 1),
|
||||
@ -218,10 +264,20 @@ static struct samsung_mux_clock top0_mux_clks[] __initdata = {
|
||||
MUX(0, "mout_aclk_peric1_66", mout_top0_group1, MUX_SEL_TOP03, 12, 2),
|
||||
MUX(0, "mout_aclk_peric0_66", mout_top0_group1, MUX_SEL_TOP03, 20, 2),
|
||||
|
||||
MUX(0, "mout_sclk_spdif", mout_top0_group3, MUX_SEL_TOP0_PERIC0, 4, 3),
|
||||
MUX(0, "mout_sclk_pcm1", mout_top0_group4, MUX_SEL_TOP0_PERIC0, 8, 2),
|
||||
MUX(0, "mout_sclk_i2s1", mout_top0_group4, MUX_SEL_TOP0_PERIC0, 20, 2),
|
||||
|
||||
MUX(0, "mout_sclk_spi1", mout_top0_group1, MUX_SEL_TOP0_PERIC1, 8, 2),
|
||||
MUX(0, "mout_sclk_spi0", mout_top0_group1, MUX_SEL_TOP0_PERIC1, 20, 2),
|
||||
|
||||
MUX(0, "mout_sclk_spi3", mout_top0_group1, MUX_SEL_TOP0_PERIC2, 8, 2),
|
||||
MUX(0, "mout_sclk_spi2", mout_top0_group1, MUX_SEL_TOP0_PERIC2, 20, 2),
|
||||
MUX(0, "mout_sclk_uart3", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 4, 2),
|
||||
MUX(0, "mout_sclk_uart2", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 8, 2),
|
||||
MUX(0, "mout_sclk_uart1", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 12, 2),
|
||||
MUX(0, "mout_sclk_uart0", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 16, 2),
|
||||
MUX(0, "mout_sclk_spi4", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 20, 2),
|
||||
};
|
||||
|
||||
static struct samsung_div_clock top0_div_clks[] __initdata = {
|
||||
@ -230,13 +286,40 @@ static struct samsung_div_clock top0_div_clks[] __initdata = {
|
||||
DIV(DOUT_ACLK_PERIC0, "dout_aclk_peric0_66", "mout_aclk_peric0_66",
|
||||
DIV_TOP03, 20, 6),
|
||||
|
||||
DIV(0, "dout_sclk_spdif", "mout_sclk_spdif", DIV_TOP0_PERIC0, 4, 4),
|
||||
DIV(0, "dout_sclk_pcm1", "mout_sclk_pcm1", DIV_TOP0_PERIC0, 8, 12),
|
||||
DIV(0, "dout_sclk_i2s1", "mout_sclk_i2s1", DIV_TOP0_PERIC0, 20, 10),
|
||||
|
||||
DIV(0, "dout_sclk_spi1", "mout_sclk_spi1", DIV_TOP0_PERIC1, 8, 12),
|
||||
DIV(0, "dout_sclk_spi0", "mout_sclk_spi0", DIV_TOP0_PERIC1, 20, 12),
|
||||
|
||||
DIV(0, "dout_sclk_spi3", "mout_sclk_spi3", DIV_TOP0_PERIC2, 8, 12),
|
||||
DIV(0, "dout_sclk_spi2", "mout_sclk_spi2", DIV_TOP0_PERIC2, 20, 12),
|
||||
|
||||
DIV(0, "dout_sclk_uart3", "mout_sclk_uart3", DIV_TOP0_PERIC3, 4, 4),
|
||||
DIV(0, "dout_sclk_uart2", "mout_sclk_uart2", DIV_TOP0_PERIC3, 8, 4),
|
||||
DIV(0, "dout_sclk_uart1", "mout_sclk_uart1", DIV_TOP0_PERIC3, 12, 4),
|
||||
DIV(0, "dout_sclk_uart0", "mout_sclk_uart0", DIV_TOP0_PERIC3, 16, 4),
|
||||
DIV(0, "dout_sclk_spi4", "mout_sclk_spi4", DIV_TOP0_PERIC3, 20, 12),
|
||||
};
|
||||
|
||||
static struct samsung_gate_clock top0_gate_clks[] __initdata = {
|
||||
GATE(CLK_SCLK_SPDIF, "sclk_spdif", "dout_sclk_spdif",
|
||||
ENABLE_SCLK_TOP0_PERIC0, 4, CLK_SET_RATE_PARENT, 0),
|
||||
GATE(CLK_SCLK_PCM1, "sclk_pcm1", "dout_sclk_pcm1",
|
||||
ENABLE_SCLK_TOP0_PERIC0, 8, CLK_SET_RATE_PARENT, 0),
|
||||
GATE(CLK_SCLK_I2S1, "sclk_i2s1", "dout_sclk_i2s1",
|
||||
ENABLE_SCLK_TOP0_PERIC0, 20, CLK_SET_RATE_PARENT, 0),
|
||||
|
||||
GATE(CLK_SCLK_SPI1, "sclk_spi1", "dout_sclk_spi1",
|
||||
ENABLE_SCLK_TOP0_PERIC1, 8, CLK_SET_RATE_PARENT, 0),
|
||||
GATE(CLK_SCLK_SPI0, "sclk_spi0", "dout_sclk_spi0",
|
||||
ENABLE_SCLK_TOP0_PERIC1, 20, CLK_SET_RATE_PARENT, 0),
|
||||
|
||||
GATE(CLK_SCLK_SPI3, "sclk_spi3", "dout_sclk_spi3",
|
||||
ENABLE_SCLK_TOP0_PERIC2, 8, CLK_SET_RATE_PARENT, 0),
|
||||
GATE(CLK_SCLK_SPI2, "sclk_spi2", "dout_sclk_spi2",
|
||||
ENABLE_SCLK_TOP0_PERIC2, 20, CLK_SET_RATE_PARENT, 0),
|
||||
GATE(CLK_SCLK_UART3, "sclk_uart3", "dout_sclk_uart3",
|
||||
ENABLE_SCLK_TOP0_PERIC3, 4, 0, 0),
|
||||
GATE(CLK_SCLK_UART2, "sclk_uart2", "dout_sclk_uart2",
|
||||
@ -245,6 +328,8 @@ static struct samsung_gate_clock top0_gate_clks[] __initdata = {
|
||||
ENABLE_SCLK_TOP0_PERIC3, 12, 0, 0),
|
||||
GATE(CLK_SCLK_UART0, "sclk_uart0", "dout_sclk_uart0",
|
||||
ENABLE_SCLK_TOP0_PERIC3, 16, 0, 0),
|
||||
GATE(CLK_SCLK_SPI4, "sclk_spi4", "dout_sclk_spi4",
|
||||
ENABLE_SCLK_TOP0_PERIC3, 20, CLK_SET_RATE_PARENT, 0),
|
||||
};
|
||||
|
||||
static struct samsung_fixed_factor_clock top0_fixed_factor_clks[] __initdata = {
|
||||
@ -343,6 +428,8 @@ static struct samsung_mux_clock top1_mux_clks[] __initdata = {
|
||||
MUX(0, "mout_aclk_fsys0_200", mout_top1_group1, MUX_SEL_TOP13, 28, 2),
|
||||
|
||||
MUX(0, "mout_sclk_mmc2", mout_top1_group1, MUX_SEL_TOP1_FSYS0, 24, 2),
|
||||
MUX(0, "mout_sclk_usbdrd300", mout_top1_group1,
|
||||
MUX_SEL_TOP1_FSYS0, 28, 2),
|
||||
|
||||
MUX(0, "mout_sclk_mmc1", mout_top1_group1, MUX_SEL_TOP1_FSYS1, 24, 2),
|
||||
MUX(0, "mout_sclk_mmc0", mout_top1_group1, MUX_SEL_TOP1_FSYS1, 28, 2),
|
||||
@ -356,6 +443,8 @@ static struct samsung_div_clock top1_div_clks[] __initdata = {
|
||||
|
||||
DIV(DOUT_SCLK_MMC2, "dout_sclk_mmc2", "mout_sclk_mmc2",
|
||||
DIV_TOP1_FSYS0, 24, 4),
|
||||
DIV(0, "dout_sclk_usbdrd300", "mout_sclk_usbdrd300",
|
||||
DIV_TOP1_FSYS0, 28, 4),
|
||||
|
||||
DIV(DOUT_SCLK_MMC1, "dout_sclk_mmc1", "mout_sclk_mmc1",
|
||||
DIV_TOP1_FSYS1, 24, 4),
|
||||
@ -366,6 +455,8 @@ static struct samsung_div_clock top1_div_clks[] __initdata = {
|
||||
static struct samsung_gate_clock top1_gate_clks[] __initdata = {
|
||||
GATE(CLK_SCLK_MMC2, "sclk_mmc2", "dout_sclk_mmc2",
|
||||
ENABLE_SCLK_TOP1_FSYS0, 24, CLK_SET_RATE_PARENT, 0),
|
||||
GATE(0, "sclk_usbdrd300", "dout_sclk_usbdrd300",
|
||||
ENABLE_SCLK_TOP1_FSYS0, 28, 0, 0),
|
||||
|
||||
GATE(CLK_SCLK_MMC1, "sclk_mmc1", "dout_sclk_mmc1",
|
||||
ENABLE_SCLK_TOP1_FSYS1, 24, CLK_SET_RATE_PARENT, 0),
|
||||
@ -514,6 +605,7 @@ static void __init exynos7_clk_peric0_init(struct device_node *np)
|
||||
/* Register Offset definitions for CMU_PERIC1 (0x14C80000) */
|
||||
#define MUX_SEL_PERIC10 0x0200
|
||||
#define MUX_SEL_PERIC11 0x0204
|
||||
#define MUX_SEL_PERIC12 0x0208
|
||||
#define ENABLE_PCLK_PERIC1 0x0900
|
||||
#define ENABLE_SCLK_PERIC10 0x0A00
|
||||
|
||||
@ -525,10 +617,16 @@ PNAME(mout_aclk_peric1_66_p) = { "fin_pll", "dout_aclk_peric1_66" };
|
||||
PNAME(mout_sclk_uart1_p) = { "fin_pll", "sclk_uart1" };
|
||||
PNAME(mout_sclk_uart2_p) = { "fin_pll", "sclk_uart2" };
|
||||
PNAME(mout_sclk_uart3_p) = { "fin_pll", "sclk_uart3" };
|
||||
PNAME(mout_sclk_spi0_p) = { "fin_pll", "sclk_spi0" };
|
||||
PNAME(mout_sclk_spi1_p) = { "fin_pll", "sclk_spi1" };
|
||||
PNAME(mout_sclk_spi2_p) = { "fin_pll", "sclk_spi2" };
|
||||
PNAME(mout_sclk_spi3_p) = { "fin_pll", "sclk_spi3" };
|
||||
PNAME(mout_sclk_spi4_p) = { "fin_pll", "sclk_spi4" };
|
||||
|
||||
static unsigned long peric1_clk_regs[] __initdata = {
|
||||
MUX_SEL_PERIC10,
|
||||
MUX_SEL_PERIC11,
|
||||
MUX_SEL_PERIC12,
|
||||
ENABLE_PCLK_PERIC1,
|
||||
ENABLE_SCLK_PERIC10,
|
||||
};
|
||||
@ -537,6 +635,16 @@ static struct samsung_mux_clock peric1_mux_clks[] __initdata = {
|
||||
MUX(0, "mout_aclk_peric1_66_user", mout_aclk_peric1_66_p,
|
||||
MUX_SEL_PERIC10, 0, 1),
|
||||
|
||||
MUX_F(0, "mout_sclk_spi0_user", mout_sclk_spi0_p,
|
||||
MUX_SEL_PERIC11, 0, 1, CLK_SET_RATE_PARENT, 0),
|
||||
MUX_F(0, "mout_sclk_spi1_user", mout_sclk_spi1_p,
|
||||
MUX_SEL_PERIC11, 4, 1, CLK_SET_RATE_PARENT, 0),
|
||||
MUX_F(0, "mout_sclk_spi2_user", mout_sclk_spi2_p,
|
||||
MUX_SEL_PERIC11, 8, 1, CLK_SET_RATE_PARENT, 0),
|
||||
MUX_F(0, "mout_sclk_spi3_user", mout_sclk_spi3_p,
|
||||
MUX_SEL_PERIC11, 12, 1, CLK_SET_RATE_PARENT, 0),
|
||||
MUX_F(0, "mout_sclk_spi4_user", mout_sclk_spi4_p,
|
||||
MUX_SEL_PERIC11, 16, 1, CLK_SET_RATE_PARENT, 0),
|
||||
MUX(0, "mout_sclk_uart1_user", mout_sclk_uart1_p,
|
||||
MUX_SEL_PERIC11, 20, 1),
|
||||
MUX(0, "mout_sclk_uart2_user", mout_sclk_uart2_p,
|
||||
@ -562,6 +670,22 @@ static struct samsung_gate_clock peric1_gate_clks[] __initdata = {
|
||||
ENABLE_PCLK_PERIC1, 10, 0, 0),
|
||||
GATE(PCLK_UART3, "pclk_uart3", "mout_aclk_peric1_66_user",
|
||||
ENABLE_PCLK_PERIC1, 11, 0, 0),
|
||||
GATE(PCLK_SPI0, "pclk_spi0", "mout_aclk_peric1_66_user",
|
||||
ENABLE_PCLK_PERIC1, 12, 0, 0),
|
||||
GATE(PCLK_SPI1, "pclk_spi1", "mout_aclk_peric1_66_user",
|
||||
ENABLE_PCLK_PERIC1, 13, 0, 0),
|
||||
GATE(PCLK_SPI2, "pclk_spi2", "mout_aclk_peric1_66_user",
|
||||
ENABLE_PCLK_PERIC1, 14, 0, 0),
|
||||
GATE(PCLK_SPI3, "pclk_spi3", "mout_aclk_peric1_66_user",
|
||||
ENABLE_PCLK_PERIC1, 15, 0, 0),
|
||||
GATE(PCLK_SPI4, "pclk_spi4", "mout_aclk_peric1_66_user",
|
||||
ENABLE_PCLK_PERIC1, 16, 0, 0),
|
||||
GATE(PCLK_I2S1, "pclk_i2s1", "mout_aclk_peric1_66_user",
|
||||
ENABLE_PCLK_PERIC1, 17, CLK_SET_RATE_PARENT, 0),
|
||||
GATE(PCLK_PCM1, "pclk_pcm1", "mout_aclk_peric1_66_user",
|
||||
ENABLE_PCLK_PERIC1, 18, 0, 0),
|
||||
GATE(PCLK_SPDIF, "pclk_spdif", "mout_aclk_peric1_66_user",
|
||||
ENABLE_PCLK_PERIC1, 19, 0, 0),
|
||||
|
||||
GATE(SCLK_UART1, "sclk_uart1_user", "mout_sclk_uart1_user",
|
||||
ENABLE_SCLK_PERIC10, 9, 0, 0),
|
||||
@ -569,6 +693,22 @@ static struct samsung_gate_clock peric1_gate_clks[] __initdata = {
|
||||
ENABLE_SCLK_PERIC10, 10, 0, 0),
|
||||
GATE(SCLK_UART3, "sclk_uart3_user", "mout_sclk_uart3_user",
|
||||
ENABLE_SCLK_PERIC10, 11, 0, 0),
|
||||
GATE(SCLK_SPI0, "sclk_spi0_user", "mout_sclk_spi0_user",
|
||||
ENABLE_SCLK_PERIC10, 12, CLK_SET_RATE_PARENT, 0),
|
||||
GATE(SCLK_SPI1, "sclk_spi1_user", "mout_sclk_spi1_user",
|
||||
ENABLE_SCLK_PERIC10, 13, CLK_SET_RATE_PARENT, 0),
|
||||
GATE(SCLK_SPI2, "sclk_spi2_user", "mout_sclk_spi2_user",
|
||||
ENABLE_SCLK_PERIC10, 14, CLK_SET_RATE_PARENT, 0),
|
||||
GATE(SCLK_SPI3, "sclk_spi3_user", "mout_sclk_spi3_user",
|
||||
ENABLE_SCLK_PERIC10, 15, CLK_SET_RATE_PARENT, 0),
|
||||
GATE(SCLK_SPI4, "sclk_spi4_user", "mout_sclk_spi4_user",
|
||||
ENABLE_SCLK_PERIC10, 16, CLK_SET_RATE_PARENT, 0),
|
||||
GATE(SCLK_I2S1, "sclk_i2s1_user", "sclk_i2s1",
|
||||
ENABLE_SCLK_PERIC10, 17, CLK_SET_RATE_PARENT, 0),
|
||||
GATE(SCLK_PCM1, "sclk_pcm1_user", "sclk_pcm1",
|
||||
ENABLE_SCLK_PERIC10, 18, CLK_SET_RATE_PARENT, 0),
|
||||
GATE(SCLK_SPDIF, "sclk_spdif_user", "sclk_spdif",
|
||||
ENABLE_SCLK_PERIC10, 19, CLK_SET_RATE_PARENT, 0),
|
||||
};
|
||||
|
||||
static struct samsung_cmu_info peric1_cmu_info __initdata = {
|
||||
@ -647,7 +787,12 @@ CLK_OF_DECLARE(exynos7_clk_peris, "samsung,exynos7-clock-peris",
|
||||
/* Register Offset definitions for CMU_FSYS0 (0x10E90000) */
|
||||
#define MUX_SEL_FSYS00 0x0200
|
||||
#define MUX_SEL_FSYS01 0x0204
|
||||
#define MUX_SEL_FSYS02 0x0208
|
||||
#define ENABLE_ACLK_FSYS00 0x0800
|
||||
#define ENABLE_ACLK_FSYS01 0x0804
|
||||
#define ENABLE_SCLK_FSYS01 0x0A04
|
||||
#define ENABLE_SCLK_FSYS02 0x0A08
|
||||
#define ENABLE_SCLK_FSYS04 0x0A10
|
||||
|
||||
/*
|
||||
* List of parent clocks for Muxes in CMU_FSYS0
|
||||
@ -655,10 +800,29 @@ CLK_OF_DECLARE(exynos7_clk_peris, "samsung,exynos7-clock-peris",
|
||||
PNAME(mout_aclk_fsys0_200_p) = { "fin_pll", "dout_aclk_fsys0_200" };
|
||||
PNAME(mout_sclk_mmc2_p) = { "fin_pll", "sclk_mmc2" };
|
||||
|
||||
PNAME(mout_sclk_usbdrd300_p) = { "fin_pll", "sclk_usbdrd300" };
|
||||
PNAME(mout_phyclk_usbdrd300_udrd30_phyclk_p) = { "fin_pll",
|
||||
"phyclk_usbdrd300_udrd30_phyclock" };
|
||||
PNAME(mout_phyclk_usbdrd300_udrd30_pipe_pclk_p) = { "fin_pll",
|
||||
"phyclk_usbdrd300_udrd30_pipe_pclk" };
|
||||
|
||||
/* fixed rate clocks used in the FSYS0 block */
|
||||
struct samsung_fixed_rate_clock fixed_rate_clks_fsys0[] __initdata = {
|
||||
FRATE(0, "phyclk_usbdrd300_udrd30_phyclock", NULL,
|
||||
CLK_IS_ROOT, 60000000),
|
||||
FRATE(0, "phyclk_usbdrd300_udrd30_pipe_pclk", NULL,
|
||||
CLK_IS_ROOT, 125000000),
|
||||
};
|
||||
|
||||
static unsigned long fsys0_clk_regs[] __initdata = {
|
||||
MUX_SEL_FSYS00,
|
||||
MUX_SEL_FSYS01,
|
||||
MUX_SEL_FSYS02,
|
||||
ENABLE_ACLK_FSYS00,
|
||||
ENABLE_ACLK_FSYS01,
|
||||
ENABLE_SCLK_FSYS01,
|
||||
ENABLE_SCLK_FSYS02,
|
||||
ENABLE_SCLK_FSYS04,
|
||||
};
|
||||
|
||||
static struct samsung_mux_clock fsys0_mux_clks[] __initdata = {
|
||||
@ -666,11 +830,49 @@ static struct samsung_mux_clock fsys0_mux_clks[] __initdata = {
|
||||
MUX_SEL_FSYS00, 24, 1),
|
||||
|
||||
MUX(0, "mout_sclk_mmc2_user", mout_sclk_mmc2_p, MUX_SEL_FSYS01, 24, 1),
|
||||
MUX(0, "mout_sclk_usbdrd300_user", mout_sclk_usbdrd300_p,
|
||||
MUX_SEL_FSYS01, 28, 1),
|
||||
|
||||
MUX(0, "mout_phyclk_usbdrd300_udrd30_pipe_pclk_user",
|
||||
mout_phyclk_usbdrd300_udrd30_pipe_pclk_p,
|
||||
MUX_SEL_FSYS02, 24, 1),
|
||||
MUX(0, "mout_phyclk_usbdrd300_udrd30_phyclk_user",
|
||||
mout_phyclk_usbdrd300_udrd30_phyclk_p,
|
||||
MUX_SEL_FSYS02, 28, 1),
|
||||
};
|
||||
|
||||
static struct samsung_gate_clock fsys0_gate_clks[] __initdata = {
|
||||
GATE(ACLK_AXIUS_USBDRD30X_FSYS0X, "aclk_axius_usbdrd30x_fsys0x",
|
||||
"mout_aclk_fsys0_200_user",
|
||||
ENABLE_ACLK_FSYS00, 19, 0, 0),
|
||||
GATE(ACLK_PDMA1, "aclk_pdma1", "mout_aclk_fsys0_200_user",
|
||||
ENABLE_ACLK_FSYS00, 3, 0, 0),
|
||||
GATE(ACLK_PDMA0, "aclk_pdma0", "mout_aclk_fsys0_200_user",
|
||||
ENABLE_ACLK_FSYS00, 4, 0, 0),
|
||||
|
||||
GATE(ACLK_USBDRD300, "aclk_usbdrd300", "mout_aclk_fsys0_200_user",
|
||||
ENABLE_ACLK_FSYS01, 29, 0, 0),
|
||||
GATE(ACLK_MMC2, "aclk_mmc2", "mout_aclk_fsys0_200_user",
|
||||
ENABLE_ACLK_FSYS01, 31, 0, 0),
|
||||
|
||||
GATE(SCLK_USBDRD300_SUSPENDCLK, "sclk_usbdrd300_suspendclk",
|
||||
"mout_sclk_usbdrd300_user",
|
||||
ENABLE_SCLK_FSYS01, 4, 0, 0),
|
||||
GATE(SCLK_USBDRD300_REFCLK, "sclk_usbdrd300_refclk", "fin_pll",
|
||||
ENABLE_SCLK_FSYS01, 8, 0, 0),
|
||||
|
||||
GATE(PHYCLK_USBDRD300_UDRD30_PIPE_PCLK_USER,
|
||||
"phyclk_usbdrd300_udrd30_pipe_pclk_user",
|
||||
"mout_phyclk_usbdrd300_udrd30_pipe_pclk_user",
|
||||
ENABLE_SCLK_FSYS02, 24, 0, 0),
|
||||
GATE(PHYCLK_USBDRD300_UDRD30_PHYCLK_USER,
|
||||
"phyclk_usbdrd300_udrd30_phyclk_user",
|
||||
"mout_phyclk_usbdrd300_udrd30_phyclk_user",
|
||||
ENABLE_SCLK_FSYS02, 28, 0, 0),
|
||||
|
||||
GATE(OSCCLK_PHY_CLKOUT_USB30_PHY, "oscclk_phy_clkout_usb30_phy",
|
||||
"fin_pll",
|
||||
ENABLE_SCLK_FSYS04, 28, 0, 0),
|
||||
};
|
||||
|
||||
static struct samsung_cmu_info fsys0_cmu_info __initdata = {
|
||||
@ -741,3 +943,205 @@ static void __init exynos7_clk_fsys1_init(struct device_node *np)
|
||||
|
||||
CLK_OF_DECLARE(exynos7_clk_fsys1, "samsung,exynos7-clock-fsys1",
|
||||
exynos7_clk_fsys1_init);
|
||||
|
||||
#define MUX_SEL_MSCL 0x0200
|
||||
#define DIV_MSCL 0x0600
|
||||
#define ENABLE_ACLK_MSCL 0x0800
|
||||
#define ENABLE_PCLK_MSCL 0x0900
|
||||
|
||||
/* List of parent clocks for Muxes in CMU_MSCL */
|
||||
PNAME(mout_aclk_mscl_532_user_p) = { "fin_pll", "aclk_mscl_532" };
|
||||
|
||||
static unsigned long mscl_clk_regs[] __initdata = {
|
||||
MUX_SEL_MSCL,
|
||||
DIV_MSCL,
|
||||
ENABLE_ACLK_MSCL,
|
||||
ENABLE_PCLK_MSCL,
|
||||
};
|
||||
|
||||
static struct samsung_mux_clock mscl_mux_clks[] __initdata = {
|
||||
MUX(USERMUX_ACLK_MSCL_532, "usermux_aclk_mscl_532",
|
||||
mout_aclk_mscl_532_user_p, MUX_SEL_MSCL, 0, 1),
|
||||
};
|
||||
static struct samsung_div_clock mscl_div_clks[] __initdata = {
|
||||
DIV(DOUT_PCLK_MSCL, "dout_pclk_mscl", "usermux_aclk_mscl_532",
|
||||
DIV_MSCL, 0, 3),
|
||||
};
|
||||
static struct samsung_gate_clock mscl_gate_clks[] __initdata = {
|
||||
|
||||
GATE(ACLK_MSCL_0, "aclk_mscl_0", "usermux_aclk_mscl_532",
|
||||
ENABLE_ACLK_MSCL, 31, 0, 0),
|
||||
GATE(ACLK_MSCL_1, "aclk_mscl_1", "usermux_aclk_mscl_532",
|
||||
ENABLE_ACLK_MSCL, 30, 0, 0),
|
||||
GATE(ACLK_JPEG, "aclk_jpeg", "usermux_aclk_mscl_532",
|
||||
ENABLE_ACLK_MSCL, 29, 0, 0),
|
||||
GATE(ACLK_G2D, "aclk_g2d", "usermux_aclk_mscl_532",
|
||||
ENABLE_ACLK_MSCL, 28, 0, 0),
|
||||
GATE(ACLK_LH_ASYNC_SI_MSCL_0, "aclk_lh_async_si_mscl_0",
|
||||
"usermux_aclk_mscl_532",
|
||||
ENABLE_ACLK_MSCL, 27, 0, 0),
|
||||
GATE(ACLK_LH_ASYNC_SI_MSCL_1, "aclk_lh_async_si_mscl_1",
|
||||
"usermux_aclk_mscl_532",
|
||||
ENABLE_ACLK_MSCL, 26, 0, 0),
|
||||
GATE(ACLK_XIU_MSCLX_0, "aclk_xiu_msclx_0", "usermux_aclk_mscl_532",
|
||||
ENABLE_ACLK_MSCL, 25, 0, 0),
|
||||
GATE(ACLK_XIU_MSCLX_1, "aclk_xiu_msclx_1", "usermux_aclk_mscl_532",
|
||||
ENABLE_ACLK_MSCL, 24, 0, 0),
|
||||
GATE(ACLK_AXI2ACEL_BRIDGE, "aclk_axi2acel_bridge",
|
||||
"usermux_aclk_mscl_532",
|
||||
ENABLE_ACLK_MSCL, 23, 0, 0),
|
||||
GATE(ACLK_QE_MSCL_0, "aclk_qe_mscl_0", "usermux_aclk_mscl_532",
|
||||
ENABLE_ACLK_MSCL, 22, 0, 0),
|
||||
GATE(ACLK_QE_MSCL_1, "aclk_qe_mscl_1", "usermux_aclk_mscl_532",
|
||||
ENABLE_ACLK_MSCL, 21, 0, 0),
|
||||
GATE(ACLK_QE_JPEG, "aclk_qe_jpeg", "usermux_aclk_mscl_532",
|
||||
ENABLE_ACLK_MSCL, 20, 0, 0),
|
||||
GATE(ACLK_QE_G2D, "aclk_qe_g2d", "usermux_aclk_mscl_532",
|
||||
ENABLE_ACLK_MSCL, 19, 0, 0),
|
||||
GATE(ACLK_PPMU_MSCL_0, "aclk_ppmu_mscl_0", "usermux_aclk_mscl_532",
|
||||
ENABLE_ACLK_MSCL, 18, 0, 0),
|
||||
GATE(ACLK_PPMU_MSCL_1, "aclk_ppmu_mscl_1", "usermux_aclk_mscl_532",
|
||||
ENABLE_ACLK_MSCL, 17, 0, 0),
|
||||
GATE(ACLK_MSCLNP_133, "aclk_msclnp_133", "usermux_aclk_mscl_532",
|
||||
ENABLE_ACLK_MSCL, 16, 0, 0),
|
||||
GATE(ACLK_AHB2APB_MSCL0P, "aclk_ahb2apb_mscl0p",
|
||||
"usermux_aclk_mscl_532",
|
||||
ENABLE_ACLK_MSCL, 15, 0, 0),
|
||||
GATE(ACLK_AHB2APB_MSCL1P, "aclk_ahb2apb_mscl1p",
|
||||
"usermux_aclk_mscl_532",
|
||||
ENABLE_ACLK_MSCL, 14, 0, 0),
|
||||
|
||||
GATE(PCLK_MSCL_0, "pclk_mscl_0", "dout_pclk_mscl",
|
||||
ENABLE_PCLK_MSCL, 31, 0, 0),
|
||||
GATE(PCLK_MSCL_1, "pclk_mscl_1", "dout_pclk_mscl",
|
||||
ENABLE_PCLK_MSCL, 30, 0, 0),
|
||||
GATE(PCLK_JPEG, "pclk_jpeg", "dout_pclk_mscl",
|
||||
ENABLE_PCLK_MSCL, 29, 0, 0),
|
||||
GATE(PCLK_G2D, "pclk_g2d", "dout_pclk_mscl",
|
||||
ENABLE_PCLK_MSCL, 28, 0, 0),
|
||||
GATE(PCLK_QE_MSCL_0, "pclk_qe_mscl_0", "dout_pclk_mscl",
|
||||
ENABLE_PCLK_MSCL, 27, 0, 0),
|
||||
GATE(PCLK_QE_MSCL_1, "pclk_qe_mscl_1", "dout_pclk_mscl",
|
||||
ENABLE_PCLK_MSCL, 26, 0, 0),
|
||||
GATE(PCLK_QE_JPEG, "pclk_qe_jpeg", "dout_pclk_mscl",
|
||||
ENABLE_PCLK_MSCL, 25, 0, 0),
|
||||
GATE(PCLK_QE_G2D, "pclk_qe_g2d", "dout_pclk_mscl",
|
||||
ENABLE_PCLK_MSCL, 24, 0, 0),
|
||||
GATE(PCLK_PPMU_MSCL_0, "pclk_ppmu_mscl_0", "dout_pclk_mscl",
|
||||
ENABLE_PCLK_MSCL, 23, 0, 0),
|
||||
GATE(PCLK_PPMU_MSCL_1, "pclk_ppmu_mscl_1", "dout_pclk_mscl",
|
||||
ENABLE_PCLK_MSCL, 22, 0, 0),
|
||||
GATE(PCLK_AXI2ACEL_BRIDGE, "pclk_axi2acel_bridge", "dout_pclk_mscl",
|
||||
ENABLE_PCLK_MSCL, 21, 0, 0),
|
||||
GATE(PCLK_PMU_MSCL, "pclk_pmu_mscl", "dout_pclk_mscl",
|
||||
ENABLE_PCLK_MSCL, 20, 0, 0),
|
||||
};
|
||||
|
||||
static struct samsung_cmu_info mscl_cmu_info __initdata = {
|
||||
.mux_clks = mscl_mux_clks,
|
||||
.nr_mux_clks = ARRAY_SIZE(mscl_mux_clks),
|
||||
.div_clks = mscl_div_clks,
|
||||
.nr_div_clks = ARRAY_SIZE(mscl_div_clks),
|
||||
.gate_clks = mscl_gate_clks,
|
||||
.nr_gate_clks = ARRAY_SIZE(mscl_gate_clks),
|
||||
.nr_clk_ids = MSCL_NR_CLK,
|
||||
.clk_regs = mscl_clk_regs,
|
||||
.nr_clk_regs = ARRAY_SIZE(mscl_clk_regs),
|
||||
};
|
||||
|
||||
static void __init exynos7_clk_mscl_init(struct device_node *np)
|
||||
{
|
||||
samsung_cmu_register_one(np, &mscl_cmu_info);
|
||||
}
|
||||
|
||||
CLK_OF_DECLARE(exynos7_clk_mscl, "samsung,exynos7-clock-mscl",
|
||||
exynos7_clk_mscl_init);
|
||||
|
||||
/* Register Offset definitions for CMU_AUD (0x114C0000) */
|
||||
#define MUX_SEL_AUD 0x0200
|
||||
#define DIV_AUD0 0x0600
|
||||
#define DIV_AUD1 0x0604
|
||||
#define ENABLE_ACLK_AUD 0x0800
|
||||
#define ENABLE_PCLK_AUD 0x0900
|
||||
#define ENABLE_SCLK_AUD 0x0A00
|
||||
|
||||
/*
|
||||
* List of parent clocks for Muxes in CMU_AUD
|
||||
*/
|
||||
PNAME(mout_aud_pll_user_p) = { "fin_pll", "fout_aud_pll" };
|
||||
PNAME(mout_aud_group_p) = { "dout_aud_cdclk", "ioclk_audiocdclk0" };
|
||||
|
||||
static unsigned long aud_clk_regs[] __initdata = {
|
||||
MUX_SEL_AUD,
|
||||
DIV_AUD0,
|
||||
DIV_AUD1,
|
||||
ENABLE_ACLK_AUD,
|
||||
ENABLE_PCLK_AUD,
|
||||
ENABLE_SCLK_AUD,
|
||||
};
|
||||
|
||||
static struct samsung_mux_clock aud_mux_clks[] __initdata = {
|
||||
MUX(0, "mout_sclk_i2s", mout_aud_group_p, MUX_SEL_AUD, 12, 1),
|
||||
MUX(0, "mout_sclk_pcm", mout_aud_group_p, MUX_SEL_AUD, 16, 1),
|
||||
MUX(0, "mout_aud_pll_user", mout_aud_pll_user_p, MUX_SEL_AUD, 20, 1),
|
||||
};
|
||||
|
||||
static struct samsung_div_clock aud_div_clks[] __initdata = {
|
||||
DIV(0, "dout_aud_ca5", "mout_aud_pll_user", DIV_AUD0, 0, 4),
|
||||
DIV(0, "dout_aclk_aud", "dout_aud_ca5", DIV_AUD0, 4, 4),
|
||||
DIV(0, "dout_aud_pclk_dbg", "dout_aud_ca5", DIV_AUD0, 8, 4),
|
||||
|
||||
DIV(0, "dout_sclk_i2s", "mout_sclk_i2s", DIV_AUD1, 0, 4),
|
||||
DIV(0, "dout_sclk_pcm", "mout_sclk_pcm", DIV_AUD1, 4, 8),
|
||||
DIV(0, "dout_sclk_uart", "dout_aud_cdclk", DIV_AUD1, 12, 4),
|
||||
DIV(0, "dout_sclk_slimbus", "dout_aud_cdclk", DIV_AUD1, 16, 5),
|
||||
DIV(0, "dout_aud_cdclk", "mout_aud_pll_user", DIV_AUD1, 24, 4),
|
||||
};
|
||||
|
||||
static struct samsung_gate_clock aud_gate_clks[] __initdata = {
|
||||
GATE(SCLK_PCM, "sclk_pcm", "dout_sclk_pcm",
|
||||
ENABLE_SCLK_AUD, 27, CLK_SET_RATE_PARENT, 0),
|
||||
GATE(SCLK_I2S, "sclk_i2s", "dout_sclk_i2s",
|
||||
ENABLE_SCLK_AUD, 28, CLK_SET_RATE_PARENT, 0),
|
||||
GATE(0, "sclk_uart", "dout_sclk_uart", ENABLE_SCLK_AUD, 29, 0, 0),
|
||||
GATE(0, "sclk_slimbus", "dout_sclk_slimbus",
|
||||
ENABLE_SCLK_AUD, 30, 0, 0),
|
||||
|
||||
GATE(0, "pclk_dbg_aud", "dout_aud_pclk_dbg", ENABLE_PCLK_AUD, 19, 0, 0),
|
||||
GATE(0, "pclk_gpio_aud", "dout_aclk_aud", ENABLE_PCLK_AUD, 20, 0, 0),
|
||||
GATE(0, "pclk_wdt1", "dout_aclk_aud", ENABLE_PCLK_AUD, 22, 0, 0),
|
||||
GATE(0, "pclk_wdt0", "dout_aclk_aud", ENABLE_PCLK_AUD, 23, 0, 0),
|
||||
GATE(0, "pclk_slimbus", "dout_aclk_aud", ENABLE_PCLK_AUD, 24, 0, 0),
|
||||
GATE(0, "pclk_uart", "dout_aclk_aud", ENABLE_PCLK_AUD, 25, 0, 0),
|
||||
GATE(PCLK_PCM, "pclk_pcm", "dout_aclk_aud",
|
||||
ENABLE_PCLK_AUD, 26, CLK_SET_RATE_PARENT, 0),
|
||||
GATE(PCLK_I2S, "pclk_i2s", "dout_aclk_aud",
|
||||
ENABLE_PCLK_AUD, 27, CLK_SET_RATE_PARENT, 0),
|
||||
GATE(0, "pclk_timer", "dout_aclk_aud", ENABLE_PCLK_AUD, 28, 0, 0),
|
||||
GATE(0, "pclk_smmu_aud", "dout_aclk_aud", ENABLE_PCLK_AUD, 31, 0, 0),
|
||||
|
||||
GATE(0, "aclk_smmu_aud", "dout_aclk_aud", ENABLE_ACLK_AUD, 27, 0, 0),
|
||||
GATE(0, "aclk_acel_lh_async_si_top", "dout_aclk_aud",
|
||||
ENABLE_ACLK_AUD, 28, 0, 0),
|
||||
GATE(ACLK_ADMA, "aclk_dmac", "dout_aclk_aud", ENABLE_ACLK_AUD, 31, 0, 0),
|
||||
};
|
||||
|
||||
static struct samsung_cmu_info aud_cmu_info __initdata = {
|
||||
.mux_clks = aud_mux_clks,
|
||||
.nr_mux_clks = ARRAY_SIZE(aud_mux_clks),
|
||||
.div_clks = aud_div_clks,
|
||||
.nr_div_clks = ARRAY_SIZE(aud_div_clks),
|
||||
.gate_clks = aud_gate_clks,
|
||||
.nr_gate_clks = ARRAY_SIZE(aud_gate_clks),
|
||||
.nr_clk_ids = AUD_NR_CLK,
|
||||
.clk_regs = aud_clk_regs,
|
||||
.nr_clk_regs = ARRAY_SIZE(aud_clk_regs),
|
||||
};
|
||||
|
||||
static void __init exynos7_clk_aud_init(struct device_node *np)
|
||||
{
|
||||
samsung_cmu_register_one(np, &aud_cmu_info);
|
||||
}
|
||||
|
||||
CLK_OF_DECLARE(exynos7_clk_aud, "samsung,exynos7-clock-aud",
|
||||
exynos7_clk_aud_init);
|
||||
|
@ -374,19 +374,24 @@ static void samsung_clk_sleep_init(void __iomem *reg_base,
|
||||
* Common function which registers plls, muxes, dividers and gates
|
||||
* for each CMU. It also add CMU register list to register cache.
|
||||
*/
|
||||
void __init samsung_cmu_register_one(struct device_node *np,
|
||||
struct samsung_clk_provider * __init samsung_cmu_register_one(
|
||||
struct device_node *np,
|
||||
struct samsung_cmu_info *cmu)
|
||||
{
|
||||
void __iomem *reg_base;
|
||||
struct samsung_clk_provider *ctx;
|
||||
|
||||
reg_base = of_iomap(np, 0);
|
||||
if (!reg_base)
|
||||
if (!reg_base) {
|
||||
panic("%s: failed to map registers\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx = samsung_clk_init(np, reg_base, cmu->nr_clk_ids);
|
||||
if (!ctx)
|
||||
if (!ctx) {
|
||||
panic("%s: unable to alllocate ctx\n", __func__);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
if (cmu->pll_clks)
|
||||
samsung_clk_register_pll(ctx, cmu->pll_clks, cmu->nr_pll_clks,
|
||||
@ -410,4 +415,6 @@ void __init samsung_cmu_register_one(struct device_node *np,
|
||||
cmu->nr_clk_regs);
|
||||
|
||||
samsung_clk_of_add_provider(np, ctx);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
@ -392,7 +392,8 @@ extern void __init samsung_clk_register_pll(struct samsung_clk_provider *ctx,
|
||||
struct samsung_pll_clock *pll_list,
|
||||
unsigned int nr_clk, void __iomem *base);
|
||||
|
||||
extern void __init samsung_cmu_register_one(struct device_node *,
|
||||
extern struct samsung_clk_provider __init *samsung_cmu_register_one(
|
||||
struct device_node *,
|
||||
struct samsung_cmu_info *);
|
||||
|
||||
extern unsigned long _get_rate(const char *clk_name);
|
||||
|
@ -1,9 +1,11 @@
|
||||
obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o
|
||||
obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o
|
||||
obj-$(CONFIG_ARCH_R8A73A4) += clk-r8a73a4.o
|
||||
obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o
|
||||
obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o
|
||||
obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o
|
||||
obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o
|
||||
obj-$(CONFIG_ARCH_R8A7793) += clk-rcar-gen2.o
|
||||
obj-$(CONFIG_ARCH_R8A7794) += clk-rcar-gen2.o
|
||||
obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o
|
||||
obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-mstp.o
|
||||
|
@ -54,12 +54,19 @@ static int cpg_div6_clock_enable(struct clk_hw *hw)
|
||||
static void cpg_div6_clock_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct div6_clock *clock = to_div6_clock(hw);
|
||||
u32 val;
|
||||
|
||||
/* DIV6 clocks require the divisor field to be non-zero when stopping
|
||||
* the clock.
|
||||
val = clk_readl(clock->reg);
|
||||
val |= CPG_DIV6_CKSTP;
|
||||
/*
|
||||
* DIV6 clocks require the divisor field to be non-zero when stopping
|
||||
* the clock. However, some clocks (e.g. ZB on sh73a0) fail to be
|
||||
* re-enabled later if the divisor field is changed when stopping the
|
||||
* clock
|
||||
*/
|
||||
clk_writel(clk_readl(clock->reg) | CPG_DIV6_CKSTP | CPG_DIV6_DIV_MASK,
|
||||
clock->reg);
|
||||
if (!(val & CPG_DIV6_DIV_MASK))
|
||||
val |= CPG_DIV6_DIV_MASK;
|
||||
clk_writel(val, clock->reg);
|
||||
}
|
||||
|
||||
static int cpg_div6_clock_is_enabled(struct clk_hw *hw)
|
||||
|
241
drivers/clk/shmobile/clk-r8a73a4.c
Normal file
241
drivers/clk/shmobile/clk-r8a73a4.c
Normal file
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* r8a73a4 Core CPG Clocks
|
||||
*
|
||||
* Copyright (C) 2014 Ulrich Hecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk/shmobile.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
struct r8a73a4_cpg {
|
||||
struct clk_onecell_data data;
|
||||
spinlock_t lock;
|
||||
void __iomem *reg;
|
||||
};
|
||||
|
||||
#define CPG_CKSCR 0xc0
|
||||
#define CPG_FRQCRA 0x00
|
||||
#define CPG_FRQCRB 0x04
|
||||
#define CPG_FRQCRC 0xe0
|
||||
#define CPG_PLL0CR 0xd8
|
||||
#define CPG_PLL1CR 0x28
|
||||
#define CPG_PLL2CR 0x2c
|
||||
#define CPG_PLL2HCR 0xe4
|
||||
#define CPG_PLL2SCR 0xf4
|
||||
|
||||
#define CLK_ENABLE_ON_INIT BIT(0)
|
||||
|
||||
struct div4_clk {
|
||||
const char *name;
|
||||
unsigned int reg;
|
||||
unsigned int shift;
|
||||
};
|
||||
|
||||
static struct div4_clk div4_clks[] = {
|
||||
{ "i", CPG_FRQCRA, 20 },
|
||||
{ "m3", CPG_FRQCRA, 12 },
|
||||
{ "b", CPG_FRQCRA, 8 },
|
||||
{ "m1", CPG_FRQCRA, 4 },
|
||||
{ "m2", CPG_FRQCRA, 0 },
|
||||
{ "zx", CPG_FRQCRB, 12 },
|
||||
{ "zs", CPG_FRQCRB, 8 },
|
||||
{ "hp", CPG_FRQCRB, 4 },
|
||||
{ NULL, 0, 0 },
|
||||
};
|
||||
|
||||
static const struct clk_div_table div4_div_table[] = {
|
||||
{ 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 }, { 5, 12 },
|
||||
{ 6, 16 }, { 7, 18 }, { 8, 24 }, { 10, 36 }, { 11, 48 },
|
||||
{ 12, 10 }, { 0, 0 }
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
r8a73a4_cpg_register_clock(struct device_node *np, struct r8a73a4_cpg *cpg,
|
||||
const char *name)
|
||||
{
|
||||
const struct clk_div_table *table = NULL;
|
||||
const char *parent_name;
|
||||
unsigned int shift, reg;
|
||||
unsigned int mult = 1;
|
||||
unsigned int div = 1;
|
||||
|
||||
|
||||
if (!strcmp(name, "main")) {
|
||||
u32 ckscr = clk_readl(cpg->reg + CPG_CKSCR);
|
||||
|
||||
switch ((ckscr >> 28) & 3) {
|
||||
case 0: /* extal1 */
|
||||
parent_name = of_clk_get_parent_name(np, 0);
|
||||
break;
|
||||
case 1: /* extal1 / 2 */
|
||||
parent_name = of_clk_get_parent_name(np, 0);
|
||||
div = 2;
|
||||
break;
|
||||
case 2: /* extal2 */
|
||||
parent_name = of_clk_get_parent_name(np, 1);
|
||||
break;
|
||||
case 3: /* extal2 / 2 */
|
||||
parent_name = of_clk_get_parent_name(np, 1);
|
||||
div = 2;
|
||||
break;
|
||||
}
|
||||
} else if (!strcmp(name, "pll0")) {
|
||||
/* PLL0/1 are configurable multiplier clocks. Register them as
|
||||
* fixed factor clocks for now as there's no generic multiplier
|
||||
* clock implementation and we currently have no need to change
|
||||
* the multiplier value.
|
||||
*/
|
||||
u32 value = clk_readl(cpg->reg + CPG_PLL0CR);
|
||||
|
||||
parent_name = "main";
|
||||
mult = ((value >> 24) & 0x7f) + 1;
|
||||
if (value & BIT(20))
|
||||
div = 2;
|
||||
} else if (!strcmp(name, "pll1")) {
|
||||
u32 value = clk_readl(cpg->reg + CPG_PLL1CR);
|
||||
|
||||
parent_name = "main";
|
||||
/* XXX: enable bit? */
|
||||
mult = ((value >> 24) & 0x7f) + 1;
|
||||
if (value & BIT(7))
|
||||
div = 2;
|
||||
} else if (!strncmp(name, "pll2", 4)) {
|
||||
u32 value, cr;
|
||||
|
||||
switch (name[4]) {
|
||||
case 0:
|
||||
cr = CPG_PLL2CR;
|
||||
break;
|
||||
case 's':
|
||||
cr = CPG_PLL2SCR;
|
||||
break;
|
||||
case 'h':
|
||||
cr = CPG_PLL2HCR;
|
||||
break;
|
||||
default:
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
value = clk_readl(cpg->reg + cr);
|
||||
switch ((value >> 5) & 7) {
|
||||
case 0:
|
||||
parent_name = "main";
|
||||
div = 2;
|
||||
break;
|
||||
case 1:
|
||||
parent_name = "extal2";
|
||||
div = 2;
|
||||
break;
|
||||
case 3:
|
||||
parent_name = "extal2";
|
||||
div = 4;
|
||||
break;
|
||||
case 4:
|
||||
parent_name = "main";
|
||||
break;
|
||||
case 5:
|
||||
parent_name = "extal2";
|
||||
break;
|
||||
default:
|
||||
pr_warn("%s: unexpected parent of %s\n", __func__,
|
||||
name);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
/* XXX: enable bit? */
|
||||
mult = ((value >> 24) & 0x7f) + 1;
|
||||
} else if (!strcmp(name, "z") || !strcmp(name, "z2")) {
|
||||
u32 shift = 8;
|
||||
|
||||
parent_name = "pll0";
|
||||
if (name[1] == '2') {
|
||||
div = 2;
|
||||
shift = 0;
|
||||
}
|
||||
div *= 32;
|
||||
mult = 0x20 - ((clk_readl(cpg->reg + CPG_FRQCRC) >> shift)
|
||||
& 0x1f);
|
||||
} else {
|
||||
struct div4_clk *c;
|
||||
|
||||
for (c = div4_clks; c->name; c++) {
|
||||
if (!strcmp(name, c->name))
|
||||
break;
|
||||
}
|
||||
if (!c->name)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
parent_name = "pll1";
|
||||
table = div4_div_table;
|
||||
reg = c->reg;
|
||||
shift = c->shift;
|
||||
}
|
||||
|
||||
if (!table) {
|
||||
return clk_register_fixed_factor(NULL, name, parent_name, 0,
|
||||
mult, div);
|
||||
} else {
|
||||
return clk_register_divider_table(NULL, name, parent_name, 0,
|
||||
cpg->reg + reg, shift, 4, 0,
|
||||
table, &cpg->lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void __init r8a73a4_cpg_clocks_init(struct device_node *np)
|
||||
{
|
||||
struct r8a73a4_cpg *cpg;
|
||||
struct clk **clks;
|
||||
unsigned int i;
|
||||
int num_clks;
|
||||
|
||||
num_clks = of_property_count_strings(np, "clock-output-names");
|
||||
if (num_clks < 0) {
|
||||
pr_err("%s: failed to count clocks\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
|
||||
clks = kcalloc(num_clks, sizeof(*clks), GFP_KERNEL);
|
||||
if (cpg == NULL || clks == NULL) {
|
||||
/* We're leaking memory on purpose, there's no point in cleaning
|
||||
* up as the system won't boot anyway.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_init(&cpg->lock);
|
||||
|
||||
cpg->data.clks = clks;
|
||||
cpg->data.clk_num = num_clks;
|
||||
|
||||
cpg->reg = of_iomap(np, 0);
|
||||
if (WARN_ON(cpg->reg == NULL))
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_clks; ++i) {
|
||||
const char *name;
|
||||
struct clk *clk;
|
||||
|
||||
of_property_read_string_index(np, "clock-output-names", i,
|
||||
&name);
|
||||
|
||||
clk = r8a73a4_cpg_register_clock(np, cpg, name);
|
||||
if (IS_ERR(clk))
|
||||
pr_err("%s: failed to register %s %s clock (%ld)\n",
|
||||
__func__, np->name, name, PTR_ERR(clk));
|
||||
else
|
||||
cpg->data.clks[i] = clk;
|
||||
}
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
|
||||
}
|
||||
CLK_OF_DECLARE(r8a73a4_cpg_clks, "renesas,r8a73a4-cpg-clocks",
|
||||
r8a73a4_cpg_clocks_init);
|
@ -33,6 +33,8 @@ struct rcar_gen2_cpg {
|
||||
#define CPG_FRQCRC 0x000000e0
|
||||
#define CPG_FRQCRC_ZFC_MASK (0x1f << 8)
|
||||
#define CPG_FRQCRC_ZFC_SHIFT 8
|
||||
#define CPG_ADSPCKCR 0x0000025c
|
||||
#define CPG_RCANCKCR 0x00000270
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Z Clock
|
||||
@ -161,6 +163,88 @@ static struct clk * __init cpg_z_clk_register(struct rcar_gen2_cpg *cpg)
|
||||
return clk;
|
||||
}
|
||||
|
||||
static struct clk * __init cpg_rcan_clk_register(struct rcar_gen2_cpg *cpg,
|
||||
struct device_node *np)
|
||||
{
|
||||
const char *parent_name = of_clk_get_parent_name(np, 1);
|
||||
struct clk_fixed_factor *fixed;
|
||||
struct clk_gate *gate;
|
||||
struct clk *clk;
|
||||
|
||||
fixed = kzalloc(sizeof(*fixed), GFP_KERNEL);
|
||||
if (!fixed)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
fixed->mult = 1;
|
||||
fixed->div = 6;
|
||||
|
||||
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
|
||||
if (!gate) {
|
||||
kfree(fixed);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
gate->reg = cpg->reg + CPG_RCANCKCR;
|
||||
gate->bit_idx = 8;
|
||||
gate->flags = CLK_GATE_SET_TO_DISABLE;
|
||||
gate->lock = &cpg->lock;
|
||||
|
||||
clk = clk_register_composite(NULL, "rcan", &parent_name, 1, NULL, NULL,
|
||||
&fixed->hw, &clk_fixed_factor_ops,
|
||||
&gate->hw, &clk_gate_ops, 0);
|
||||
if (IS_ERR(clk)) {
|
||||
kfree(gate);
|
||||
kfree(fixed);
|
||||
}
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
/* ADSP divisors */
|
||||
static const struct clk_div_table cpg_adsp_div_table[] = {
|
||||
{ 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 },
|
||||
{ 5, 12 }, { 6, 16 }, { 7, 18 }, { 8, 24 },
|
||||
{ 10, 36 }, { 11, 48 }, { 0, 0 },
|
||||
};
|
||||
|
||||
static struct clk * __init cpg_adsp_clk_register(struct rcar_gen2_cpg *cpg)
|
||||
{
|
||||
const char *parent_name = "pll1";
|
||||
struct clk_divider *div;
|
||||
struct clk_gate *gate;
|
||||
struct clk *clk;
|
||||
|
||||
div = kzalloc(sizeof(*div), GFP_KERNEL);
|
||||
if (!div)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
div->reg = cpg->reg + CPG_ADSPCKCR;
|
||||
div->width = 4;
|
||||
div->table = cpg_adsp_div_table;
|
||||
div->lock = &cpg->lock;
|
||||
|
||||
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
|
||||
if (!gate) {
|
||||
kfree(div);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
gate->reg = cpg->reg + CPG_ADSPCKCR;
|
||||
gate->bit_idx = 8;
|
||||
gate->flags = CLK_GATE_SET_TO_DISABLE;
|
||||
gate->lock = &cpg->lock;
|
||||
|
||||
clk = clk_register_composite(NULL, "adsp", &parent_name, 1, NULL, NULL,
|
||||
&div->hw, &clk_divider_ops,
|
||||
&gate->hw, &clk_gate_ops, 0);
|
||||
if (IS_ERR(clk)) {
|
||||
kfree(gate);
|
||||
kfree(div);
|
||||
}
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* CPG Clock Data
|
||||
*/
|
||||
@ -263,6 +347,10 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
|
||||
shift = 0;
|
||||
} else if (!strcmp(name, "z")) {
|
||||
return cpg_z_clk_register(cpg);
|
||||
} else if (!strcmp(name, "rcan")) {
|
||||
return cpg_rcan_clk_register(cpg, np);
|
||||
} else if (!strcmp(name, "adsp")) {
|
||||
return cpg_adsp_clk_register(cpg);
|
||||
} else {
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
@ -138,16 +138,27 @@ static int flexgen_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
struct flexgen *flexgen = to_flexgen(hw);
|
||||
struct clk_hw *pdiv_hw = &flexgen->pdiv.hw;
|
||||
struct clk_hw *fdiv_hw = &flexgen->fdiv.hw;
|
||||
unsigned long primary_div = 0;
|
||||
unsigned long div = 0;
|
||||
int ret = 0;
|
||||
|
||||
pdiv_hw->clk = hw->clk;
|
||||
fdiv_hw->clk = hw->clk;
|
||||
|
||||
primary_div = clk_best_div(parent_rate, rate);
|
||||
div = clk_best_div(parent_rate, rate);
|
||||
|
||||
clk_divider_ops.set_rate(fdiv_hw, parent_rate, parent_rate);
|
||||
ret = clk_divider_ops.set_rate(pdiv_hw, rate, rate * primary_div);
|
||||
/*
|
||||
* pdiv is mainly targeted for low freq results, while fdiv
|
||||
* should be used for div <= 64. The other way round can
|
||||
* lead to 'duty cycle' issues.
|
||||
*/
|
||||
|
||||
if (div <= 64) {
|
||||
clk_divider_ops.set_rate(pdiv_hw, parent_rate, parent_rate);
|
||||
ret = clk_divider_ops.set_rate(fdiv_hw, rate, rate * div);
|
||||
} else {
|
||||
clk_divider_ops.set_rate(fdiv_hw, parent_rate, parent_rate);
|
||||
ret = clk_divider_ops.set_rate(pdiv_hw, rate, rate * div);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ obj-y += clk-a20-gmac.o
|
||||
obj-y += clk-mod0.o
|
||||
obj-y += clk-sun8i-mbus.o
|
||||
obj-y += clk-sun9i-core.o
|
||||
obj-y += clk-sun9i-mmc.o
|
||||
|
||||
obj-$(CONFIG_MFD_SUN6I_PRCM) += \
|
||||
clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
|
||||
|
@ -80,6 +80,8 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
}
|
||||
|
||||
static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_p)
|
||||
{
|
||||
@ -156,9 +158,10 @@ static const struct clk_ops clk_factors_ops = {
|
||||
.set_rate = clk_factors_set_rate,
|
||||
};
|
||||
|
||||
struct clk * __init sunxi_factors_register(struct device_node *node,
|
||||
const struct factors_data *data,
|
||||
spinlock_t *lock)
|
||||
struct clk *sunxi_factors_register(struct device_node *node,
|
||||
const struct factors_data *data,
|
||||
spinlock_t *lock,
|
||||
void __iomem *reg)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_factors *factors;
|
||||
@ -168,11 +171,8 @@ struct clk * __init sunxi_factors_register(struct device_node *node,
|
||||
struct clk_hw *mux_hw = NULL;
|
||||
const char *clk_name = node->name;
|
||||
const char *parents[FACTORS_MAX_PARENTS];
|
||||
void __iomem *reg;
|
||||
int i = 0;
|
||||
|
||||
reg = of_iomap(node, 0);
|
||||
|
||||
/* if we have a mux, we will have >1 parents */
|
||||
while (i < FACTORS_MAX_PARENTS &&
|
||||
(parents[i] = of_clk_get_parent_name(node, i)) != NULL)
|
||||
|
@ -36,8 +36,9 @@ struct clk_factors {
|
||||
spinlock_t *lock;
|
||||
};
|
||||
|
||||
struct clk * __init sunxi_factors_register(struct device_node *node,
|
||||
const struct factors_data *data,
|
||||
spinlock_t *lock);
|
||||
struct clk *sunxi_factors_register(struct device_node *node,
|
||||
const struct factors_data *data,
|
||||
spinlock_t *lock,
|
||||
void __iomem *reg);
|
||||
|
||||
#endif
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "clk-factors.h"
|
||||
|
||||
@ -67,7 +68,7 @@ static struct clk_factors_config sun4i_a10_mod0_config = {
|
||||
.pwidth = 2,
|
||||
};
|
||||
|
||||
static const struct factors_data sun4i_a10_mod0_data __initconst = {
|
||||
static const struct factors_data sun4i_a10_mod0_data = {
|
||||
.enable = 31,
|
||||
.mux = 24,
|
||||
.muxmask = BIT(1) | BIT(0),
|
||||
@ -79,15 +80,95 @@ static DEFINE_SPINLOCK(sun4i_a10_mod0_lock);
|
||||
|
||||
static void __init sun4i_a10_mod0_setup(struct device_node *node)
|
||||
{
|
||||
sunxi_factors_register(node, &sun4i_a10_mod0_data, &sun4i_a10_mod0_lock);
|
||||
void __iomem *reg;
|
||||
|
||||
reg = of_iomap(node, 0);
|
||||
if (!reg) {
|
||||
/*
|
||||
* This happens with mod0 clk nodes instantiated through
|
||||
* mfd, as those do not have their resources assigned at
|
||||
* CLK_OF_DECLARE time yet, so do not print an error.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
sunxi_factors_register(node, &sun4i_a10_mod0_data,
|
||||
&sun4i_a10_mod0_lock, reg);
|
||||
}
|
||||
CLK_OF_DECLARE(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", sun4i_a10_mod0_setup);
|
||||
|
||||
static int sun4i_a10_mod0_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct resource *r;
|
||||
void __iomem *reg;
|
||||
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
reg = devm_ioremap_resource(&pdev->dev, r);
|
||||
if (IS_ERR(reg))
|
||||
return PTR_ERR(reg);
|
||||
|
||||
sunxi_factors_register(np, &sun4i_a10_mod0_data,
|
||||
&sun4i_a10_mod0_lock, reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id sun4i_a10_mod0_clk_dt_ids[] = {
|
||||
{ .compatible = "allwinner,sun4i-a10-mod0-clk" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct platform_driver sun4i_a10_mod0_clk_driver = {
|
||||
.driver = {
|
||||
.name = "sun4i-a10-mod0-clk",
|
||||
.of_match_table = sun4i_a10_mod0_clk_dt_ids,
|
||||
},
|
||||
.probe = sun4i_a10_mod0_clk_probe,
|
||||
};
|
||||
module_platform_driver(sun4i_a10_mod0_clk_driver);
|
||||
|
||||
static const struct factors_data sun9i_a80_mod0_data __initconst = {
|
||||
.enable = 31,
|
||||
.mux = 24,
|
||||
.muxmask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
|
||||
.table = &sun4i_a10_mod0_config,
|
||||
.getter = sun4i_a10_get_mod0_factors,
|
||||
};
|
||||
|
||||
static void __init sun9i_a80_mod0_setup(struct device_node *node)
|
||||
{
|
||||
void __iomem *reg;
|
||||
|
||||
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
|
||||
if (IS_ERR(reg)) {
|
||||
pr_err("Could not get registers for mod0-clk: %s\n",
|
||||
node->name);
|
||||
return;
|
||||
}
|
||||
|
||||
sunxi_factors_register(node, &sun9i_a80_mod0_data,
|
||||
&sun4i_a10_mod0_lock, reg);
|
||||
}
|
||||
CLK_OF_DECLARE(sun9i_a80_mod0, "allwinner,sun9i-a80-mod0-clk", sun9i_a80_mod0_setup);
|
||||
|
||||
static DEFINE_SPINLOCK(sun5i_a13_mbus_lock);
|
||||
|
||||
static void __init sun5i_a13_mbus_setup(struct device_node *node)
|
||||
{
|
||||
struct clk *mbus = sunxi_factors_register(node, &sun4i_a10_mod0_data, &sun5i_a13_mbus_lock);
|
||||
struct clk *mbus;
|
||||
void __iomem *reg;
|
||||
|
||||
reg = of_iomap(node, 0);
|
||||
if (!reg) {
|
||||
pr_err("Could not get registers for a13-mbus-clk\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mbus = sunxi_factors_register(node, &sun4i_a10_mod0_data,
|
||||
&sun5i_a13_mbus_lock, reg);
|
||||
|
||||
/* The MBUS clocks needs to be always enabled */
|
||||
__clk_get(mbus);
|
||||
@ -95,14 +176,10 @@ static void __init sun5i_a13_mbus_setup(struct device_node *node)
|
||||
}
|
||||
CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk", sun5i_a13_mbus_setup);
|
||||
|
||||
struct mmc_phase_data {
|
||||
u8 offset;
|
||||
};
|
||||
|
||||
struct mmc_phase {
|
||||
struct clk_hw hw;
|
||||
u8 offset;
|
||||
void __iomem *reg;
|
||||
struct mmc_phase_data *data;
|
||||
spinlock_t *lock;
|
||||
};
|
||||
|
||||
@ -118,7 +195,7 @@ static int mmc_get_phase(struct clk_hw *hw)
|
||||
u8 delay;
|
||||
|
||||
value = readl(phase->reg);
|
||||
delay = (value >> phase->data->offset) & 0x3;
|
||||
delay = (value >> phase->offset) & 0x3;
|
||||
|
||||
if (!delay)
|
||||
return 180;
|
||||
@ -206,8 +283,8 @@ static int mmc_set_phase(struct clk_hw *hw, int degrees)
|
||||
|
||||
spin_lock_irqsave(phase->lock, flags);
|
||||
value = readl(phase->reg);
|
||||
value &= ~GENMASK(phase->data->offset + 3, phase->data->offset);
|
||||
value |= delay << phase->data->offset;
|
||||
value &= ~GENMASK(phase->offset + 3, phase->offset);
|
||||
value |= delay << phase->offset;
|
||||
writel(value, phase->reg);
|
||||
spin_unlock_irqrestore(phase->lock, flags);
|
||||
|
||||
@ -219,66 +296,97 @@ static const struct clk_ops mmc_clk_ops = {
|
||||
.set_phase = mmc_set_phase,
|
||||
};
|
||||
|
||||
static void __init sun4i_a10_mmc_phase_setup(struct device_node *node,
|
||||
struct mmc_phase_data *data)
|
||||
/*
|
||||
* sunxi_mmc_setup - Common setup function for mmc module clocks
|
||||
*
|
||||
* The only difference between module clocks on different platforms is the
|
||||
* width of the mux register bits and the valid values, which are passed in
|
||||
* through struct factors_data. The phase clocks parts are identical.
|
||||
*/
|
||||
static void __init sunxi_mmc_setup(struct device_node *node,
|
||||
const struct factors_data *data,
|
||||
spinlock_t *lock)
|
||||
{
|
||||
const char *parent_names[1] = { of_clk_get_parent_name(node, 0) };
|
||||
struct clk_init_data init = {
|
||||
.num_parents = 1,
|
||||
.parent_names = parent_names,
|
||||
.ops = &mmc_clk_ops,
|
||||
};
|
||||
struct clk_onecell_data *clk_data;
|
||||
const char *parent;
|
||||
void __iomem *reg;
|
||||
int i;
|
||||
|
||||
struct mmc_phase *phase;
|
||||
struct clk *clk;
|
||||
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
|
||||
if (IS_ERR(reg)) {
|
||||
pr_err("Couldn't map the %s clock registers\n", node->name);
|
||||
return;
|
||||
}
|
||||
|
||||
phase = kmalloc(sizeof(*phase), GFP_KERNEL);
|
||||
if (!phase)
|
||||
clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
|
||||
if (!clk_data)
|
||||
return;
|
||||
|
||||
phase->hw.init = &init;
|
||||
clk_data->clks = kcalloc(3, sizeof(*clk_data->clks), GFP_KERNEL);
|
||||
if (!clk_data->clks)
|
||||
goto err_free_data;
|
||||
|
||||
phase->reg = of_iomap(node, 0);
|
||||
if (!phase->reg)
|
||||
goto err_free;
|
||||
clk_data->clk_num = 3;
|
||||
clk_data->clks[0] = sunxi_factors_register(node, data, lock, reg);
|
||||
if (!clk_data->clks[0])
|
||||
goto err_free_clks;
|
||||
|
||||
phase->data = data;
|
||||
phase->lock = &sun4i_a10_mod0_lock;
|
||||
parent = __clk_get_name(clk_data->clks[0]);
|
||||
|
||||
if (of_property_read_string(node, "clock-output-names", &init.name))
|
||||
init.name = node->name;
|
||||
for (i = 1; i < 3; i++) {
|
||||
struct clk_init_data init = {
|
||||
.num_parents = 1,
|
||||
.parent_names = &parent,
|
||||
.ops = &mmc_clk_ops,
|
||||
};
|
||||
struct mmc_phase *phase;
|
||||
|
||||
clk = clk_register(NULL, &phase->hw);
|
||||
if (IS_ERR(clk))
|
||||
goto err_unmap;
|
||||
phase = kmalloc(sizeof(*phase), GFP_KERNEL);
|
||||
if (!phase)
|
||||
continue;
|
||||
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
phase->hw.init = &init;
|
||||
phase->reg = reg;
|
||||
phase->lock = lock;
|
||||
|
||||
if (i == 1)
|
||||
phase->offset = 8;
|
||||
else
|
||||
phase->offset = 20;
|
||||
|
||||
if (of_property_read_string_index(node, "clock-output-names",
|
||||
i, &init.name))
|
||||
init.name = node->name;
|
||||
|
||||
clk_data->clks[i] = clk_register(NULL, &phase->hw);
|
||||
if (IS_ERR(clk_data->clks[i])) {
|
||||
kfree(phase);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
|
||||
|
||||
return;
|
||||
|
||||
err_unmap:
|
||||
iounmap(phase->reg);
|
||||
err_free:
|
||||
kfree(phase);
|
||||
err_free_clks:
|
||||
kfree(clk_data->clks);
|
||||
err_free_data:
|
||||
kfree(clk_data);
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(sun4i_a10_mmc_lock);
|
||||
|
||||
static struct mmc_phase_data mmc_output_clk = {
|
||||
.offset = 8,
|
||||
};
|
||||
|
||||
static struct mmc_phase_data mmc_sample_clk = {
|
||||
.offset = 20,
|
||||
};
|
||||
|
||||
static void __init sun4i_a10_mmc_output_setup(struct device_node *node)
|
||||
static void __init sun4i_a10_mmc_setup(struct device_node *node)
|
||||
{
|
||||
sun4i_a10_mmc_phase_setup(node, &mmc_output_clk);
|
||||
sunxi_mmc_setup(node, &sun4i_a10_mod0_data, &sun4i_a10_mmc_lock);
|
||||
}
|
||||
CLK_OF_DECLARE(sun4i_a10_mmc_output, "allwinner,sun4i-a10-mmc-output-clk", sun4i_a10_mmc_output_setup);
|
||||
CLK_OF_DECLARE(sun4i_a10_mmc, "allwinner,sun4i-a10-mmc-clk", sun4i_a10_mmc_setup);
|
||||
|
||||
static void __init sun4i_a10_mmc_sample_setup(struct device_node *node)
|
||||
static DEFINE_SPINLOCK(sun9i_a80_mmc_lock);
|
||||
|
||||
static void __init sun9i_a80_mmc_setup(struct device_node *node)
|
||||
{
|
||||
sun4i_a10_mmc_phase_setup(node, &mmc_sample_clk);
|
||||
sunxi_mmc_setup(node, &sun9i_a80_mod0_data, &sun9i_a80_mmc_lock);
|
||||
}
|
||||
CLK_OF_DECLARE(sun4i_a10_mmc_sample, "allwinner,sun4i-a10-mmc-sample-clk", sun4i_a10_mmc_sample_setup);
|
||||
CLK_OF_DECLARE(sun9i_a80_mmc, "allwinner,sun9i-a80-mmc-clk", sun9i_a80_mmc_setup);
|
||||
|
@ -45,6 +45,8 @@ static unsigned long ar100_recalc_rate(struct clk_hw *hw,
|
||||
}
|
||||
|
||||
static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_clk)
|
||||
{
|
||||
|
@ -69,8 +69,17 @@ static DEFINE_SPINLOCK(sun8i_a23_mbus_lock);
|
||||
|
||||
static void __init sun8i_a23_mbus_setup(struct device_node *node)
|
||||
{
|
||||
struct clk *mbus = sunxi_factors_register(node, &sun8i_a23_mbus_data,
|
||||
&sun8i_a23_mbus_lock);
|
||||
struct clk *mbus;
|
||||
void __iomem *reg;
|
||||
|
||||
reg = of_iomap(node, 0);
|
||||
if (!reg) {
|
||||
pr_err("Could not get registers for a23-mbus-clk\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mbus = sunxi_factors_register(node, &sun8i_a23_mbus_data,
|
||||
&sun8i_a23_mbus_lock, reg);
|
||||
|
||||
/* The MBUS clocks needs to be always enabled */
|
||||
__clk_get(mbus);
|
||||
|
@ -24,50 +24,51 @@
|
||||
|
||||
|
||||
/**
|
||||
* sun9i_a80_get_pll4_factors() - calculates n, p, m factors for PLL1
|
||||
* sun9i_a80_get_pll4_factors() - calculates n, p, m factors for PLL4
|
||||
* PLL4 rate is calculated as follows
|
||||
* rate = (parent_rate * n >> p) / (m + 1);
|
||||
* parent_rate is always 24Mhz
|
||||
* parent_rate is always 24MHz
|
||||
*
|
||||
* p and m are named div1 and div2 in Allwinner's SDK
|
||||
*/
|
||||
|
||||
static void sun9i_a80_get_pll4_factors(u32 *freq, u32 parent_rate,
|
||||
u8 *n, u8 *k, u8 *m, u8 *p)
|
||||
u8 *n_ret, u8 *k, u8 *m_ret, u8 *p_ret)
|
||||
{
|
||||
int div;
|
||||
int n;
|
||||
int m = 1;
|
||||
int p = 1;
|
||||
|
||||
/* Normalize value to a 6M multiple */
|
||||
div = DIV_ROUND_UP(*freq, 6000000);
|
||||
/* Normalize value to a 6 MHz multiple (24 MHz / 4) */
|
||||
n = DIV_ROUND_UP(*freq, 6000000);
|
||||
|
||||
/* divs above 256 cannot be odd */
|
||||
if (div > 256)
|
||||
div = round_up(div, 2);
|
||||
/* If n is too large switch to steps of 12 MHz */
|
||||
if (n > 255) {
|
||||
m = 0;
|
||||
n = (n + 1) / 2;
|
||||
}
|
||||
|
||||
/* divs above 512 must be a multiple of 4 */
|
||||
if (div > 512)
|
||||
div = round_up(div, 4);
|
||||
/* If n is still too large switch to steps of 24 MHz */
|
||||
if (n > 255) {
|
||||
p = 0;
|
||||
n = (n + 1) / 2;
|
||||
}
|
||||
|
||||
*freq = 6000000 * div;
|
||||
/* n must be between 12 and 255 */
|
||||
if (n > 255)
|
||||
n = 255;
|
||||
else if (n < 12)
|
||||
n = 12;
|
||||
|
||||
*freq = ((24000000 * n) >> p) / (m + 1);
|
||||
|
||||
/* we were called to round the frequency, we can now return */
|
||||
if (n == NULL)
|
||||
if (n_ret == NULL)
|
||||
return;
|
||||
|
||||
/* p will be 1 for divs under 512 */
|
||||
if (div < 512)
|
||||
*p = 1;
|
||||
else
|
||||
*p = 0;
|
||||
|
||||
/* m will be 1 if div is odd */
|
||||
if (div & 1)
|
||||
*m = 1;
|
||||
else
|
||||
*m = 0;
|
||||
|
||||
/* calculate a suitable n based on m and p */
|
||||
*n = div / (*p + 1) / (*m + 1);
|
||||
*n_ret = n;
|
||||
*m_ret = m;
|
||||
*p_ret = p;
|
||||
}
|
||||
|
||||
static struct clk_factors_config sun9i_a80_pll4_config = {
|
||||
@ -89,7 +90,17 @@ static DEFINE_SPINLOCK(sun9i_a80_pll4_lock);
|
||||
|
||||
static void __init sun9i_a80_pll4_setup(struct device_node *node)
|
||||
{
|
||||
sunxi_factors_register(node, &sun9i_a80_pll4_data, &sun9i_a80_pll4_lock);
|
||||
void __iomem *reg;
|
||||
|
||||
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
|
||||
if (!reg) {
|
||||
pr_err("Could not get registers for a80-pll4-clk: %s\n",
|
||||
node->name);
|
||||
return;
|
||||
}
|
||||
|
||||
sunxi_factors_register(node, &sun9i_a80_pll4_data,
|
||||
&sun9i_a80_pll4_lock, reg);
|
||||
}
|
||||
CLK_OF_DECLARE(sun9i_a80_pll4, "allwinner,sun9i-a80-pll4-clk", sun9i_a80_pll4_setup);
|
||||
|
||||
@ -139,8 +150,18 @@ static DEFINE_SPINLOCK(sun9i_a80_gt_lock);
|
||||
|
||||
static void __init sun9i_a80_gt_setup(struct device_node *node)
|
||||
{
|
||||
struct clk *gt = sunxi_factors_register(node, &sun9i_a80_gt_data,
|
||||
&sun9i_a80_gt_lock);
|
||||
void __iomem *reg;
|
||||
struct clk *gt;
|
||||
|
||||
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
|
||||
if (!reg) {
|
||||
pr_err("Could not get registers for a80-gt-clk: %s\n",
|
||||
node->name);
|
||||
return;
|
||||
}
|
||||
|
||||
gt = sunxi_factors_register(node, &sun9i_a80_gt_data,
|
||||
&sun9i_a80_gt_lock, reg);
|
||||
|
||||
/* The GT bus clock needs to be always enabled */
|
||||
__clk_get(gt);
|
||||
@ -194,7 +215,17 @@ static DEFINE_SPINLOCK(sun9i_a80_ahb_lock);
|
||||
|
||||
static void __init sun9i_a80_ahb_setup(struct device_node *node)
|
||||
{
|
||||
sunxi_factors_register(node, &sun9i_a80_ahb_data, &sun9i_a80_ahb_lock);
|
||||
void __iomem *reg;
|
||||
|
||||
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
|
||||
if (!reg) {
|
||||
pr_err("Could not get registers for a80-ahb-clk: %s\n",
|
||||
node->name);
|
||||
return;
|
||||
}
|
||||
|
||||
sunxi_factors_register(node, &sun9i_a80_ahb_data,
|
||||
&sun9i_a80_ahb_lock, reg);
|
||||
}
|
||||
CLK_OF_DECLARE(sun9i_a80_ahb, "allwinner,sun9i-a80-ahb-clk", sun9i_a80_ahb_setup);
|
||||
|
||||
@ -210,7 +241,17 @@ static DEFINE_SPINLOCK(sun9i_a80_apb0_lock);
|
||||
|
||||
static void __init sun9i_a80_apb0_setup(struct device_node *node)
|
||||
{
|
||||
sunxi_factors_register(node, &sun9i_a80_apb0_data, &sun9i_a80_apb0_lock);
|
||||
void __iomem *reg;
|
||||
|
||||
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
|
||||
if (!reg) {
|
||||
pr_err("Could not get registers for a80-apb0-clk: %s\n",
|
||||
node->name);
|
||||
return;
|
||||
}
|
||||
|
||||
sunxi_factors_register(node, &sun9i_a80_apb0_data,
|
||||
&sun9i_a80_apb0_lock, reg);
|
||||
}
|
||||
CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-clk", sun9i_a80_apb0_setup);
|
||||
|
||||
@ -266,6 +307,16 @@ static DEFINE_SPINLOCK(sun9i_a80_apb1_lock);
|
||||
|
||||
static void __init sun9i_a80_apb1_setup(struct device_node *node)
|
||||
{
|
||||
sunxi_factors_register(node, &sun9i_a80_apb1_data, &sun9i_a80_apb1_lock);
|
||||
void __iomem *reg;
|
||||
|
||||
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
|
||||
if (!reg) {
|
||||
pr_err("Could not get registers for a80-apb1-clk: %s\n",
|
||||
node->name);
|
||||
return;
|
||||
}
|
||||
|
||||
sunxi_factors_register(node, &sun9i_a80_apb1_data,
|
||||
&sun9i_a80_apb1_lock, reg);
|
||||
}
|
||||
CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-clk", sun9i_a80_apb1_setup);
|
||||
|
219
drivers/clk/sunxi/clk-sun9i-mmc.c
Normal file
219
drivers/clk/sunxi/clk-sun9i-mmc.c
Normal file
@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright 2015 Chen-Yu Tsai
|
||||
*
|
||||
* Chen-Yu Tsai <wens@csie.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define SUN9I_MMC_WIDTH 4
|
||||
|
||||
#define SUN9I_MMC_GATE_BIT 16
|
||||
#define SUN9I_MMC_RESET_BIT 18
|
||||
|
||||
struct sun9i_mmc_clk_data {
|
||||
spinlock_t lock;
|
||||
void __iomem *membase;
|
||||
struct clk *clk;
|
||||
struct reset_control *reset;
|
||||
struct clk_onecell_data clk_data;
|
||||
struct reset_controller_dev rcdev;
|
||||
};
|
||||
|
||||
static int sun9i_mmc_reset_assert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct sun9i_mmc_clk_data *data = container_of(rcdev,
|
||||
struct sun9i_mmc_clk_data,
|
||||
rcdev);
|
||||
unsigned long flags;
|
||||
void __iomem *reg = data->membase + SUN9I_MMC_WIDTH * id;
|
||||
u32 val;
|
||||
|
||||
clk_prepare_enable(data->clk);
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
|
||||
val = readl(reg);
|
||||
writel(val & ~BIT(SUN9I_MMC_RESET_BIT), reg);
|
||||
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
clk_disable_unprepare(data->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sun9i_mmc_reset_deassert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct sun9i_mmc_clk_data *data = container_of(rcdev,
|
||||
struct sun9i_mmc_clk_data,
|
||||
rcdev);
|
||||
unsigned long flags;
|
||||
void __iomem *reg = data->membase + SUN9I_MMC_WIDTH * id;
|
||||
u32 val;
|
||||
|
||||
clk_prepare_enable(data->clk);
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
|
||||
val = readl(reg);
|
||||
writel(val | BIT(SUN9I_MMC_RESET_BIT), reg);
|
||||
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
clk_disable_unprepare(data->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct reset_control_ops sun9i_mmc_reset_ops = {
|
||||
.assert = sun9i_mmc_reset_assert,
|
||||
.deassert = sun9i_mmc_reset_deassert,
|
||||
};
|
||||
|
||||
static int sun9i_a80_mmc_config_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct sun9i_mmc_clk_data *data;
|
||||
struct clk_onecell_data *clk_data;
|
||||
const char *clk_name = np->name;
|
||||
const char *clk_parent;
|
||||
struct resource *r;
|
||||
int count, i, ret;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&data->lock);
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
/* one clock/reset pair per word */
|
||||
count = DIV_ROUND_UP((r->end - r->start + 1), SUN9I_MMC_WIDTH);
|
||||
data->membase = devm_ioremap_resource(&pdev->dev, r);
|
||||
if (IS_ERR(data->membase))
|
||||
return PTR_ERR(data->membase);
|
||||
|
||||
clk_data = &data->clk_data;
|
||||
clk_data->clk_num = count;
|
||||
clk_data->clks = devm_kcalloc(&pdev->dev, count, sizeof(struct clk *),
|
||||
GFP_KERNEL);
|
||||
if (!clk_data->clks)
|
||||
return -ENOMEM;
|
||||
|
||||
data->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(data->clk)) {
|
||||
dev_err(&pdev->dev, "Could not get clock\n");
|
||||
return PTR_ERR(data->clk);
|
||||
}
|
||||
|
||||
data->reset = devm_reset_control_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(data->reset)) {
|
||||
dev_err(&pdev->dev, "Could not get reset control\n");
|
||||
return PTR_ERR(data->reset);
|
||||
}
|
||||
|
||||
ret = reset_control_deassert(data->reset);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Reset deassert err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
clk_parent = __clk_get_name(data->clk);
|
||||
for (i = 0; i < count; i++) {
|
||||
of_property_read_string_index(np, "clock-output-names",
|
||||
i, &clk_name);
|
||||
|
||||
clk_data->clks[i] = clk_register_gate(&pdev->dev, clk_name,
|
||||
clk_parent, 0,
|
||||
data->membase + SUN9I_MMC_WIDTH * i,
|
||||
SUN9I_MMC_GATE_BIT, 0,
|
||||
&data->lock);
|
||||
|
||||
if (IS_ERR(clk_data->clks[i])) {
|
||||
ret = PTR_ERR(clk_data->clks[i]);
|
||||
goto err_clk_register;
|
||||
}
|
||||
}
|
||||
|
||||
ret = of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
|
||||
if (ret)
|
||||
goto err_clk_provider;
|
||||
|
||||
data->rcdev.owner = THIS_MODULE;
|
||||
data->rcdev.nr_resets = count;
|
||||
data->rcdev.ops = &sun9i_mmc_reset_ops;
|
||||
data->rcdev.of_node = pdev->dev.of_node;
|
||||
|
||||
ret = reset_controller_register(&data->rcdev);
|
||||
if (ret)
|
||||
goto err_rc_reg;
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
return 0;
|
||||
|
||||
err_rc_reg:
|
||||
of_clk_del_provider(np);
|
||||
|
||||
err_clk_provider:
|
||||
for (i = 0; i < count; i++)
|
||||
clk_unregister(clk_data->clks[i]);
|
||||
|
||||
err_clk_register:
|
||||
reset_control_assert(data->reset);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sun9i_a80_mmc_config_clk_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct sun9i_mmc_clk_data *data = platform_get_drvdata(pdev);
|
||||
struct clk_onecell_data *clk_data = &data->clk_data;
|
||||
int i;
|
||||
|
||||
reset_controller_unregister(&data->rcdev);
|
||||
of_clk_del_provider(np);
|
||||
for (i = 0; i < clk_data->clk_num; i++)
|
||||
clk_unregister(clk_data->clks[i]);
|
||||
|
||||
reset_control_assert(data->reset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id sun9i_a80_mmc_config_clk_dt_ids[] = {
|
||||
{ .compatible = "allwinner,sun9i-a80-mmc-config-clk" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct platform_driver sun9i_a80_mmc_config_clk_driver = {
|
||||
.driver = {
|
||||
.name = "sun9i-a80-mmc-config-clk",
|
||||
.of_match_table = sun9i_a80_mmc_config_clk_dt_ids,
|
||||
},
|
||||
.probe = sun9i_a80_mmc_config_clk_probe,
|
||||
.remove = sun9i_a80_mmc_config_clk_remove,
|
||||
};
|
||||
module_platform_driver(sun9i_a80_mmc_config_clk_driver);
|
||||
|
||||
MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
|
||||
MODULE_DESCRIPTION("Allwinner A80 MMC clock/reset Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -20,11 +20,221 @@
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/log2.h>
|
||||
|
||||
#include "clk-factors.h"
|
||||
|
||||
static DEFINE_SPINLOCK(clk_lock);
|
||||
|
||||
/**
|
||||
* sun6i_a31_ahb1_clk_setup() - Setup function for a31 ahb1 composite clk
|
||||
*/
|
||||
|
||||
#define SUN6I_AHB1_MAX_PARENTS 4
|
||||
#define SUN6I_AHB1_MUX_PARENT_PLL6 3
|
||||
#define SUN6I_AHB1_MUX_SHIFT 12
|
||||
/* un-shifted mask is what mux_clk expects */
|
||||
#define SUN6I_AHB1_MUX_MASK 0x3
|
||||
#define SUN6I_AHB1_MUX_GET_PARENT(reg) ((reg >> SUN6I_AHB1_MUX_SHIFT) & \
|
||||
SUN6I_AHB1_MUX_MASK)
|
||||
|
||||
#define SUN6I_AHB1_DIV_SHIFT 4
|
||||
#define SUN6I_AHB1_DIV_MASK (0x3 << SUN6I_AHB1_DIV_SHIFT)
|
||||
#define SUN6I_AHB1_DIV_GET(reg) ((reg & SUN6I_AHB1_DIV_MASK) >> \
|
||||
SUN6I_AHB1_DIV_SHIFT)
|
||||
#define SUN6I_AHB1_DIV_SET(reg, div) ((reg & ~SUN6I_AHB1_DIV_MASK) | \
|
||||
(div << SUN6I_AHB1_DIV_SHIFT))
|
||||
#define SUN6I_AHB1_PLL6_DIV_SHIFT 6
|
||||
#define SUN6I_AHB1_PLL6_DIV_MASK (0x3 << SUN6I_AHB1_PLL6_DIV_SHIFT)
|
||||
#define SUN6I_AHB1_PLL6_DIV_GET(reg) ((reg & SUN6I_AHB1_PLL6_DIV_MASK) >> \
|
||||
SUN6I_AHB1_PLL6_DIV_SHIFT)
|
||||
#define SUN6I_AHB1_PLL6_DIV_SET(reg, div) ((reg & ~SUN6I_AHB1_PLL6_DIV_MASK) | \
|
||||
(div << SUN6I_AHB1_PLL6_DIV_SHIFT))
|
||||
|
||||
struct sun6i_ahb1_clk {
|
||||
struct clk_hw hw;
|
||||
void __iomem *reg;
|
||||
};
|
||||
|
||||
#define to_sun6i_ahb1_clk(_hw) container_of(_hw, struct sun6i_ahb1_clk, hw)
|
||||
|
||||
static unsigned long sun6i_ahb1_clk_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct sun6i_ahb1_clk *ahb1 = to_sun6i_ahb1_clk(hw);
|
||||
unsigned long rate;
|
||||
u32 reg;
|
||||
|
||||
/* Fetch the register value */
|
||||
reg = readl(ahb1->reg);
|
||||
|
||||
/* apply pre-divider first if parent is pll6 */
|
||||
if (SUN6I_AHB1_MUX_GET_PARENT(reg) == SUN6I_AHB1_MUX_PARENT_PLL6)
|
||||
parent_rate /= SUN6I_AHB1_PLL6_DIV_GET(reg) + 1;
|
||||
|
||||
/* clk divider */
|
||||
rate = parent_rate >> SUN6I_AHB1_DIV_GET(reg);
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static long sun6i_ahb1_clk_round(unsigned long rate, u8 *divp, u8 *pre_divp,
|
||||
u8 parent, unsigned long parent_rate)
|
||||
{
|
||||
u8 div, calcp, calcm = 1;
|
||||
|
||||
/*
|
||||
* clock can only divide, so we will never be able to achieve
|
||||
* frequencies higher than the parent frequency
|
||||
*/
|
||||
if (parent_rate && rate > parent_rate)
|
||||
rate = parent_rate;
|
||||
|
||||
div = DIV_ROUND_UP(parent_rate, rate);
|
||||
|
||||
/* calculate pre-divider if parent is pll6 */
|
||||
if (parent == SUN6I_AHB1_MUX_PARENT_PLL6) {
|
||||
if (div < 4)
|
||||
calcp = 0;
|
||||
else if (div / 2 < 4)
|
||||
calcp = 1;
|
||||
else if (div / 4 < 4)
|
||||
calcp = 2;
|
||||
else
|
||||
calcp = 3;
|
||||
|
||||
calcm = DIV_ROUND_UP(div, 1 << calcp);
|
||||
} else {
|
||||
calcp = __roundup_pow_of_two(div);
|
||||
calcp = calcp > 3 ? 3 : calcp;
|
||||
}
|
||||
|
||||
/* we were asked to pass back divider values */
|
||||
if (divp) {
|
||||
*divp = calcp;
|
||||
*pre_divp = calcm - 1;
|
||||
}
|
||||
|
||||
return (parent_rate / calcm) >> calcp;
|
||||
}
|
||||
|
||||
static long sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_clk)
|
||||
{
|
||||
struct clk *clk = hw->clk, *parent, *best_parent = NULL;
|
||||
int i, num_parents;
|
||||
unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
|
||||
|
||||
/* find the parent that can help provide the fastest rate <= rate */
|
||||
num_parents = __clk_get_num_parents(clk);
|
||||
for (i = 0; i < num_parents; i++) {
|
||||
parent = clk_get_parent_by_index(clk, i);
|
||||
if (!parent)
|
||||
continue;
|
||||
if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT)
|
||||
parent_rate = __clk_round_rate(parent, rate);
|
||||
else
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
|
||||
child_rate = sun6i_ahb1_clk_round(rate, NULL, NULL, i,
|
||||
parent_rate);
|
||||
|
||||
if (child_rate <= rate && child_rate > best_child_rate) {
|
||||
best_parent = parent;
|
||||
best = parent_rate;
|
||||
best_child_rate = child_rate;
|
||||
}
|
||||
}
|
||||
|
||||
if (best_parent)
|
||||
*best_parent_clk = __clk_get_hw(best_parent);
|
||||
*best_parent_rate = best;
|
||||
|
||||
return best_child_rate;
|
||||
}
|
||||
|
||||
static int sun6i_ahb1_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct sun6i_ahb1_clk *ahb1 = to_sun6i_ahb1_clk(hw);
|
||||
unsigned long flags;
|
||||
u8 div, pre_div, parent;
|
||||
u32 reg;
|
||||
|
||||
spin_lock_irqsave(&clk_lock, flags);
|
||||
|
||||
reg = readl(ahb1->reg);
|
||||
|
||||
/* need to know which parent is used to apply pre-divider */
|
||||
parent = SUN6I_AHB1_MUX_GET_PARENT(reg);
|
||||
sun6i_ahb1_clk_round(rate, &div, &pre_div, parent, parent_rate);
|
||||
|
||||
reg = SUN6I_AHB1_DIV_SET(reg, div);
|
||||
reg = SUN6I_AHB1_PLL6_DIV_SET(reg, pre_div);
|
||||
writel(reg, ahb1->reg);
|
||||
|
||||
spin_unlock_irqrestore(&clk_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops sun6i_ahb1_clk_ops = {
|
||||
.determine_rate = sun6i_ahb1_clk_determine_rate,
|
||||
.recalc_rate = sun6i_ahb1_clk_recalc_rate,
|
||||
.set_rate = sun6i_ahb1_clk_set_rate,
|
||||
};
|
||||
|
||||
static void __init sun6i_ahb1_clk_setup(struct device_node *node)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct sun6i_ahb1_clk *ahb1;
|
||||
struct clk_mux *mux;
|
||||
const char *clk_name = node->name;
|
||||
const char *parents[SUN6I_AHB1_MAX_PARENTS];
|
||||
void __iomem *reg;
|
||||
int i = 0;
|
||||
|
||||
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
|
||||
|
||||
/* we have a mux, we will have >1 parents */
|
||||
while (i < SUN6I_AHB1_MAX_PARENTS &&
|
||||
(parents[i] = of_clk_get_parent_name(node, i)) != NULL)
|
||||
i++;
|
||||
|
||||
of_property_read_string(node, "clock-output-names", &clk_name);
|
||||
|
||||
ahb1 = kzalloc(sizeof(struct sun6i_ahb1_clk), GFP_KERNEL);
|
||||
if (!ahb1)
|
||||
return;
|
||||
|
||||
mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
|
||||
if (!mux) {
|
||||
kfree(ahb1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* set up clock properties */
|
||||
mux->reg = reg;
|
||||
mux->shift = SUN6I_AHB1_MUX_SHIFT;
|
||||
mux->mask = SUN6I_AHB1_MUX_MASK;
|
||||
mux->lock = &clk_lock;
|
||||
ahb1->reg = reg;
|
||||
|
||||
clk = clk_register_composite(NULL, clk_name, parents, i,
|
||||
&mux->hw, &clk_mux_ops,
|
||||
&ahb1->hw, &sun6i_ahb1_clk_ops,
|
||||
NULL, NULL, 0);
|
||||
|
||||
if (!IS_ERR(clk)) {
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
clk_register_clkdev(clk, clk_name, NULL);
|
||||
}
|
||||
}
|
||||
CLK_OF_DECLARE(sun6i_a31_ahb1, "allwinner,sun6i-a31-ahb1-clk", sun6i_ahb1_clk_setup);
|
||||
|
||||
/* Maximum number of parents our clocks have */
|
||||
#define SUNXI_MAX_PARENTS 5
|
||||
|
||||
@ -354,43 +564,6 @@ static void sun7i_a20_get_out_factors(u32 *freq, u32 parent_rate,
|
||||
*p = calcp;
|
||||
}
|
||||
|
||||
/**
|
||||
* clk_sunxi_mmc_phase_control() - configures MMC clock phase control
|
||||
*/
|
||||
|
||||
void clk_sunxi_mmc_phase_control(struct clk *clk, u8 sample, u8 output)
|
||||
{
|
||||
#define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw)
|
||||
#define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw)
|
||||
|
||||
struct clk_hw *hw = __clk_get_hw(clk);
|
||||
struct clk_composite *composite = to_clk_composite(hw);
|
||||
struct clk_hw *rate_hw = composite->rate_hw;
|
||||
struct clk_factors *factors = to_clk_factors(rate_hw);
|
||||
unsigned long flags = 0;
|
||||
u32 reg;
|
||||
|
||||
if (factors->lock)
|
||||
spin_lock_irqsave(factors->lock, flags);
|
||||
|
||||
reg = readl(factors->reg);
|
||||
|
||||
/* set sample clock phase control */
|
||||
reg &= ~(0x7 << 20);
|
||||
reg |= ((sample & 0x7) << 20);
|
||||
|
||||
/* set output clock phase control */
|
||||
reg &= ~(0x7 << 8);
|
||||
reg |= ((output & 0x7) << 8);
|
||||
|
||||
writel(reg, factors->reg);
|
||||
|
||||
if (factors->lock)
|
||||
spin_unlock_irqrestore(factors->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(clk_sunxi_mmc_phase_control);
|
||||
|
||||
|
||||
/**
|
||||
* sunxi_factors_clk_setup() - Setup function for factor clocks
|
||||
*/
|
||||
@ -413,6 +586,7 @@ static struct clk_factors_config sun6i_a31_pll1_config = {
|
||||
.kwidth = 2,
|
||||
.mshift = 0,
|
||||
.mwidth = 2,
|
||||
.n_start = 1,
|
||||
};
|
||||
|
||||
static struct clk_factors_config sun8i_a23_pll1_config = {
|
||||
@ -520,7 +694,16 @@ static const struct factors_data sun7i_a20_out_data __initconst = {
|
||||
static struct clk * __init sunxi_factors_clk_setup(struct device_node *node,
|
||||
const struct factors_data *data)
|
||||
{
|
||||
return sunxi_factors_register(node, data, &clk_lock);
|
||||
void __iomem *reg;
|
||||
|
||||
reg = of_iomap(node, 0);
|
||||
if (!reg) {
|
||||
pr_err("Could not get registers for factors-clk: %s\n",
|
||||
node->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sunxi_factors_register(node, data, &clk_lock, reg);
|
||||
}
|
||||
|
||||
|
||||
@ -561,7 +744,7 @@ static void __init sunxi_mux_clk_setup(struct device_node *node,
|
||||
of_property_read_string(node, "clock-output-names", &clk_name);
|
||||
|
||||
clk = clk_register_mux(NULL, clk_name, parents, i,
|
||||
CLK_SET_RATE_NO_REPARENT, reg,
|
||||
CLK_SET_RATE_PARENT, reg,
|
||||
data->shift, SUNXI_MUX_GATE_WIDTH,
|
||||
0, &clk_lock);
|
||||
|
||||
@ -1217,7 +1400,6 @@ CLK_OF_DECLARE(sun7i_a20_clk_init, "allwinner,sun7i-a20", sun5i_init_clocks);
|
||||
|
||||
static const char *sun6i_critical_clocks[] __initdata = {
|
||||
"cpu",
|
||||
"ahb1_sdram",
|
||||
};
|
||||
|
||||
static void __init sun6i_init_clocks(struct device_node *node)
|
||||
|
@ -3,8 +3,10 @@ obj-y += clk.o autoidle.o clockdomain.o
|
||||
clk-common = dpll.o composite.o divider.o gate.o \
|
||||
fixed-factor.o mux.o apll.o
|
||||
obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o
|
||||
obj-$(CONFIG_SOC_TI81XX) += $(clk-common) fapll.o clk-816x.o
|
||||
obj-$(CONFIG_ARCH_OMAP2) += $(clk-common) interface.o clk-2xxx.o
|
||||
obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o clk-3xxx.o
|
||||
obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o \
|
||||
clk-3xxx.o clk-3xxx-legacy.o
|
||||
obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o
|
||||
obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o
|
||||
obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o \
|
||||
|
4653
drivers/clk/ti/clk-3xxx-legacy.c
Normal file
4653
drivers/clk/ti/clk-3xxx-legacy.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -327,7 +327,6 @@ enum {
|
||||
OMAP3_SOC_OMAP3430_ES1,
|
||||
OMAP3_SOC_OMAP3430_ES2_PLUS,
|
||||
OMAP3_SOC_OMAP3630,
|
||||
OMAP3_SOC_TI81XX,
|
||||
};
|
||||
|
||||
static int __init omap3xxx_dt_clk_init(int soc_type)
|
||||
@ -370,7 +369,7 @@ static int __init omap3xxx_dt_clk_init(int soc_type)
|
||||
(clk_get_rate(clk_get_sys(NULL, "core_ck")) / 1000000),
|
||||
(clk_get_rate(clk_get_sys(NULL, "arm_fck")) / 1000000));
|
||||
|
||||
if (soc_type != OMAP3_SOC_TI81XX && soc_type != OMAP3_SOC_OMAP3430_ES1)
|
||||
if (soc_type != OMAP3_SOC_OMAP3430_ES1)
|
||||
omap3_clk_lock_dpll5();
|
||||
|
||||
return 0;
|
||||
@ -390,8 +389,3 @@ int __init am35xx_dt_clk_init(void)
|
||||
{
|
||||
return omap3xxx_dt_clk_init(OMAP3_SOC_AM35XX);
|
||||
}
|
||||
|
||||
int __init ti81xx_dt_clk_init(void)
|
||||
{
|
||||
return omap3xxx_dt_clk_init(OMAP3_SOC_TI81XX);
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/clk-private.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk/ti.h>
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/clk-private.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk/ti.h>
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/clk-private.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk/ti.h>
|
||||
|
||||
|
53
drivers/clk/ti/clk-816x.c
Normal file
53
drivers/clk/ti/clk-816x.c
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk/ti.h>
|
||||
|
||||
static struct ti_dt_clk dm816x_clks[] = {
|
||||
DT_CLK(NULL, "sys_clkin", "sys_clkin_ck"),
|
||||
DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"),
|
||||
DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"),
|
||||
DT_CLK(NULL, "mpu_ck", "mpu_ck"),
|
||||
DT_CLK(NULL, "timer1_fck", "timer1_fck"),
|
||||
DT_CLK(NULL, "timer2_fck", "timer2_fck"),
|
||||
DT_CLK(NULL, "timer3_fck", "timer3_fck"),
|
||||
DT_CLK(NULL, "timer4_fck", "timer4_fck"),
|
||||
DT_CLK(NULL, "timer5_fck", "timer5_fck"),
|
||||
DT_CLK(NULL, "timer6_fck", "timer6_fck"),
|
||||
DT_CLK(NULL, "timer7_fck", "timer7_fck"),
|
||||
DT_CLK(NULL, "sysclk4_ck", "sysclk4_ck"),
|
||||
DT_CLK(NULL, "sysclk5_ck", "sysclk5_ck"),
|
||||
DT_CLK(NULL, "sysclk6_ck", "sysclk6_ck"),
|
||||
DT_CLK(NULL, "sysclk10_ck", "sysclk10_ck"),
|
||||
DT_CLK(NULL, "sysclk18_ck", "sysclk18_ck"),
|
||||
DT_CLK(NULL, "sysclk24_ck", "sysclk24_ck"),
|
||||
DT_CLK("4a100000.ethernet", "sysclk24_ck", "sysclk24_ck"),
|
||||
{ .node_name = NULL },
|
||||
};
|
||||
|
||||
static const char *enable_init_clks[] = {
|
||||
"ddr_pll_clk1",
|
||||
"ddr_pll_clk2",
|
||||
"ddr_pll_clk3",
|
||||
};
|
||||
|
||||
int __init ti81xx_dt_clk_init(void)
|
||||
{
|
||||
ti_dt_clocks_register(dm816x_clks);
|
||||
omap2_clk_disable_autoidle_all();
|
||||
omap2_clk_enable_init_clocks(enable_init_clks,
|
||||
ARRAY_SIZE(enable_init_clks));
|
||||
|
||||
return 0;
|
||||
}
|
@ -22,6 +22,8 @@
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "clock.h"
|
||||
|
||||
#undef pr_fmt
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
|
||||
@ -183,3 +185,126 @@ void ti_dt_clk_init_retry_clks(void)
|
||||
retries--;
|
||||
}
|
||||
}
|
||||
|
||||
void __init ti_clk_patch_legacy_clks(struct ti_clk **patch)
|
||||
{
|
||||
while (*patch) {
|
||||
memcpy((*patch)->patch, *patch, sizeof(**patch));
|
||||
patch++;
|
||||
}
|
||||
}
|
||||
|
||||
struct clk __init *ti_clk_register_clk(struct ti_clk *setup)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct ti_clk_fixed *fixed;
|
||||
struct ti_clk_fixed_factor *fixed_factor;
|
||||
struct clk_hw *clk_hw;
|
||||
|
||||
if (setup->clk)
|
||||
return setup->clk;
|
||||
|
||||
switch (setup->type) {
|
||||
case TI_CLK_FIXED:
|
||||
fixed = setup->data;
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, setup->name, NULL,
|
||||
CLK_IS_ROOT, fixed->frequency);
|
||||
break;
|
||||
case TI_CLK_MUX:
|
||||
clk = ti_clk_register_mux(setup);
|
||||
break;
|
||||
case TI_CLK_DIVIDER:
|
||||
clk = ti_clk_register_divider(setup);
|
||||
break;
|
||||
case TI_CLK_COMPOSITE:
|
||||
clk = ti_clk_register_composite(setup);
|
||||
break;
|
||||
case TI_CLK_FIXED_FACTOR:
|
||||
fixed_factor = setup->data;
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, setup->name,
|
||||
fixed_factor->parent,
|
||||
0, fixed_factor->mult,
|
||||
fixed_factor->div);
|
||||
break;
|
||||
case TI_CLK_GATE:
|
||||
clk = ti_clk_register_gate(setup);
|
||||
break;
|
||||
case TI_CLK_DPLL:
|
||||
clk = ti_clk_register_dpll(setup);
|
||||
break;
|
||||
default:
|
||||
pr_err("bad type for %s!\n", setup->name);
|
||||
clk = ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (!IS_ERR(clk)) {
|
||||
setup->clk = clk;
|
||||
if (setup->clkdm_name) {
|
||||
if (__clk_get_flags(clk) & CLK_IS_BASIC) {
|
||||
pr_warn("can't setup clkdm for basic clk %s\n",
|
||||
setup->name);
|
||||
} else {
|
||||
clk_hw = __clk_get_hw(clk);
|
||||
to_clk_hw_omap(clk_hw)->clkdm_name =
|
||||
setup->clkdm_name;
|
||||
omap2_init_clk_clkdm(clk_hw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
int __init ti_clk_register_legacy_clks(struct ti_clk_alias *clks)
|
||||
{
|
||||
struct clk *clk;
|
||||
bool retry;
|
||||
struct ti_clk_alias *retry_clk;
|
||||
struct ti_clk_alias *tmp;
|
||||
|
||||
while (clks->clk) {
|
||||
clk = ti_clk_register_clk(clks->clk);
|
||||
if (IS_ERR(clk)) {
|
||||
if (PTR_ERR(clk) == -EAGAIN) {
|
||||
list_add(&clks->link, &retry_list);
|
||||
} else {
|
||||
pr_err("register for %s failed: %ld\n",
|
||||
clks->clk->name, PTR_ERR(clk));
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
} else {
|
||||
clks->lk.clk = clk;
|
||||
clkdev_add(&clks->lk);
|
||||
}
|
||||
clks++;
|
||||
}
|
||||
|
||||
retry = true;
|
||||
|
||||
while (!list_empty(&retry_list) && retry) {
|
||||
retry = false;
|
||||
list_for_each_entry_safe(retry_clk, tmp, &retry_list, link) {
|
||||
pr_debug("retry-init: %s\n", retry_clk->clk->name);
|
||||
clk = ti_clk_register_clk(retry_clk->clk);
|
||||
if (IS_ERR(clk)) {
|
||||
if (PTR_ERR(clk) == -EAGAIN) {
|
||||
continue;
|
||||
} else {
|
||||
pr_err("register for %s failed: %ld\n",
|
||||
retry_clk->clk->name,
|
||||
PTR_ERR(clk));
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
} else {
|
||||
retry = true;
|
||||
retry_clk->lk.clk = clk;
|
||||
clkdev_add(&retry_clk->lk);
|
||||
list_del(&retry_clk->link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
172
drivers/clk/ti/clock.h
Normal file
172
drivers/clk/ti/clock.h
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* TI Clock driver internal definitions
|
||||
*
|
||||
* Copyright (C) 2014 Texas Instruments, Inc
|
||||
* Tero Kristo (t-kristo@ti.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#ifndef __DRIVERS_CLK_TI_CLOCK__
|
||||
#define __DRIVERS_CLK_TI_CLOCK__
|
||||
|
||||
enum {
|
||||
TI_CLK_FIXED,
|
||||
TI_CLK_MUX,
|
||||
TI_CLK_DIVIDER,
|
||||
TI_CLK_COMPOSITE,
|
||||
TI_CLK_FIXED_FACTOR,
|
||||
TI_CLK_GATE,
|
||||
TI_CLK_DPLL,
|
||||
};
|
||||
|
||||
/* Global flags */
|
||||
#define CLKF_INDEX_POWER_OF_TWO (1 << 0)
|
||||
#define CLKF_INDEX_STARTS_AT_ONE (1 << 1)
|
||||
#define CLKF_SET_RATE_PARENT (1 << 2)
|
||||
#define CLKF_OMAP3 (1 << 3)
|
||||
#define CLKF_AM35XX (1 << 4)
|
||||
|
||||
/* Gate flags */
|
||||
#define CLKF_SET_BIT_TO_DISABLE (1 << 5)
|
||||
#define CLKF_INTERFACE (1 << 6)
|
||||
#define CLKF_SSI (1 << 7)
|
||||
#define CLKF_DSS (1 << 8)
|
||||
#define CLKF_HSOTGUSB (1 << 9)
|
||||
#define CLKF_WAIT (1 << 10)
|
||||
#define CLKF_NO_WAIT (1 << 11)
|
||||
#define CLKF_HSDIV (1 << 12)
|
||||
#define CLKF_CLKDM (1 << 13)
|
||||
|
||||
/* DPLL flags */
|
||||
#define CLKF_LOW_POWER_STOP (1 << 5)
|
||||
#define CLKF_LOCK (1 << 6)
|
||||
#define CLKF_LOW_POWER_BYPASS (1 << 7)
|
||||
#define CLKF_PER (1 << 8)
|
||||
#define CLKF_CORE (1 << 9)
|
||||
#define CLKF_J_TYPE (1 << 10)
|
||||
|
||||
#define CLK(dev, con, ck) \
|
||||
{ \
|
||||
.lk = { \
|
||||
.dev_id = dev, \
|
||||
.con_id = con, \
|
||||
}, \
|
||||
.clk = ck, \
|
||||
}
|
||||
|
||||
struct ti_clk {
|
||||
const char *name;
|
||||
const char *clkdm_name;
|
||||
int type;
|
||||
void *data;
|
||||
struct ti_clk *patch;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
struct ti_clk_alias {
|
||||
struct ti_clk *clk;
|
||||
struct clk_lookup lk;
|
||||
struct list_head link;
|
||||
};
|
||||
|
||||
struct ti_clk_fixed {
|
||||
u32 frequency;
|
||||
u16 flags;
|
||||
};
|
||||
|
||||
struct ti_clk_mux {
|
||||
u8 bit_shift;
|
||||
int num_parents;
|
||||
u16 reg;
|
||||
u8 module;
|
||||
const char **parents;
|
||||
u16 flags;
|
||||
};
|
||||
|
||||
struct ti_clk_divider {
|
||||
const char *parent;
|
||||
u8 bit_shift;
|
||||
u16 max_div;
|
||||
u16 reg;
|
||||
u8 module;
|
||||
int *dividers;
|
||||
int num_dividers;
|
||||
u16 flags;
|
||||
};
|
||||
|
||||
struct ti_clk_fixed_factor {
|
||||
const char *parent;
|
||||
u16 div;
|
||||
u16 mult;
|
||||
u16 flags;
|
||||
};
|
||||
|
||||
struct ti_clk_gate {
|
||||
const char *parent;
|
||||
u8 bit_shift;
|
||||
u16 reg;
|
||||
u8 module;
|
||||
u16 flags;
|
||||
};
|
||||
|
||||
struct ti_clk_composite {
|
||||
struct ti_clk_divider *divider;
|
||||
struct ti_clk_mux *mux;
|
||||
struct ti_clk_gate *gate;
|
||||
u16 flags;
|
||||
};
|
||||
|
||||
struct ti_clk_clkdm_gate {
|
||||
const char *parent;
|
||||
u16 flags;
|
||||
};
|
||||
|
||||
struct ti_clk_dpll {
|
||||
int num_parents;
|
||||
u16 control_reg;
|
||||
u16 idlest_reg;
|
||||
u16 autoidle_reg;
|
||||
u16 mult_div1_reg;
|
||||
u8 module;
|
||||
const char **parents;
|
||||
u16 flags;
|
||||
u8 modes;
|
||||
u32 mult_mask;
|
||||
u32 div1_mask;
|
||||
u32 enable_mask;
|
||||
u32 autoidle_mask;
|
||||
u32 freqsel_mask;
|
||||
u32 idlest_mask;
|
||||
u32 dco_mask;
|
||||
u32 sddiv_mask;
|
||||
u16 max_multiplier;
|
||||
u16 max_divider;
|
||||
u8 min_divider;
|
||||
u8 auto_recal_bit;
|
||||
u8 recal_en_bit;
|
||||
u8 recal_st_bit;
|
||||
};
|
||||
|
||||
struct clk *ti_clk_register_gate(struct ti_clk *setup);
|
||||
struct clk *ti_clk_register_interface(struct ti_clk *setup);
|
||||
struct clk *ti_clk_register_mux(struct ti_clk *setup);
|
||||
struct clk *ti_clk_register_divider(struct ti_clk *setup);
|
||||
struct clk *ti_clk_register_composite(struct ti_clk *setup);
|
||||
struct clk *ti_clk_register_dpll(struct ti_clk *setup);
|
||||
|
||||
struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup);
|
||||
struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup);
|
||||
struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup);
|
||||
|
||||
void ti_clk_patch_legacy_clks(struct ti_clk **patch);
|
||||
struct clk *ti_clk_register_clk(struct ti_clk *setup);
|
||||
int ti_clk_register_legacy_clks(struct ti_clk_alias *clks);
|
||||
|
||||
#endif
|
@ -23,6 +23,8 @@
|
||||
#include <linux/clk/ti.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "clock.h"
|
||||
|
||||
#undef pr_fmt
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
|
||||
@ -116,8 +118,44 @@ static inline struct clk_hw *_get_hw(struct clk_hw_omap_comp *clk, int idx)
|
||||
|
||||
#define to_clk_hw_comp(_hw) container_of(_hw, struct clk_hw_omap_comp, hw)
|
||||
|
||||
static void __init ti_clk_register_composite(struct clk_hw *hw,
|
||||
struct device_node *node)
|
||||
struct clk *ti_clk_register_composite(struct ti_clk *setup)
|
||||
{
|
||||
struct ti_clk_composite *comp;
|
||||
struct clk_hw *gate;
|
||||
struct clk_hw *mux;
|
||||
struct clk_hw *div;
|
||||
int num_parents = 1;
|
||||
const char **parent_names = NULL;
|
||||
struct clk *clk;
|
||||
|
||||
comp = setup->data;
|
||||
|
||||
div = ti_clk_build_component_div(comp->divider);
|
||||
gate = ti_clk_build_component_gate(comp->gate);
|
||||
mux = ti_clk_build_component_mux(comp->mux);
|
||||
|
||||
if (div)
|
||||
parent_names = &comp->divider->parent;
|
||||
|
||||
if (gate)
|
||||
parent_names = &comp->gate->parent;
|
||||
|
||||
if (mux) {
|
||||
num_parents = comp->mux->num_parents;
|
||||
parent_names = comp->mux->parents;
|
||||
}
|
||||
|
||||
clk = clk_register_composite(NULL, setup->name,
|
||||
parent_names, num_parents, mux,
|
||||
&ti_clk_mux_ops, div,
|
||||
&ti_composite_divider_ops, gate,
|
||||
&ti_composite_gate_ops, 0);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
static void __init _register_composite(struct clk_hw *hw,
|
||||
struct device_node *node)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_hw_omap_comp *cclk = to_clk_hw_comp(hw);
|
||||
@ -136,7 +174,7 @@ static void __init ti_clk_register_composite(struct clk_hw *hw,
|
||||
pr_debug("component %s not ready for %s, retry\n",
|
||||
cclk->comp_nodes[i]->name, node->name);
|
||||
if (!ti_clk_retry_init(node, hw,
|
||||
ti_clk_register_composite))
|
||||
_register_composite))
|
||||
return;
|
||||
|
||||
goto cleanup;
|
||||
@ -216,7 +254,7 @@ static void __init of_ti_composite_clk_setup(struct device_node *node)
|
||||
for (i = 0; i < num_clks; i++)
|
||||
cclk->comp_nodes[i] = _get_component_node(node, i);
|
||||
|
||||
ti_clk_register_composite(&cclk->hw, node);
|
||||
_register_composite(&cclk->hw, node);
|
||||
}
|
||||
CLK_OF_DECLARE(ti_composite_clock, "ti,composite-clock",
|
||||
of_ti_composite_clk_setup);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/clk/ti.h>
|
||||
#include "clock.h"
|
||||
|
||||
#undef pr_fmt
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
@ -300,6 +301,134 @@ static struct clk *_register_divider(struct device *dev, const char *name,
|
||||
return clk;
|
||||
}
|
||||
|
||||
static struct clk_div_table *
|
||||
_get_div_table_from_setup(struct ti_clk_divider *setup, u8 *width)
|
||||
{
|
||||
int valid_div = 0;
|
||||
struct clk_div_table *table;
|
||||
int i;
|
||||
int div;
|
||||
u32 val;
|
||||
u8 flags;
|
||||
|
||||
if (!setup->num_dividers) {
|
||||
/* Clk divider table not provided, determine min/max divs */
|
||||
flags = setup->flags;
|
||||
|
||||
if (flags & CLKF_INDEX_STARTS_AT_ONE)
|
||||
val = 1;
|
||||
else
|
||||
val = 0;
|
||||
|
||||
div = 1;
|
||||
|
||||
while (div < setup->max_div) {
|
||||
if (flags & CLKF_INDEX_POWER_OF_TWO)
|
||||
div <<= 1;
|
||||
else
|
||||
div++;
|
||||
val++;
|
||||
}
|
||||
|
||||
*width = fls(val);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < setup->num_dividers; i++)
|
||||
if (setup->dividers[i])
|
||||
valid_div++;
|
||||
|
||||
table = kzalloc(sizeof(*table) * (valid_div + 1), GFP_KERNEL);
|
||||
if (!table)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
valid_div = 0;
|
||||
*width = 0;
|
||||
|
||||
for (i = 0; i < setup->num_dividers; i++)
|
||||
if (setup->dividers[i]) {
|
||||
table[valid_div].div = setup->dividers[i];
|
||||
table[valid_div].val = i;
|
||||
valid_div++;
|
||||
*width = i;
|
||||
}
|
||||
|
||||
*width = fls(*width);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup)
|
||||
{
|
||||
struct clk_divider *div;
|
||||
struct clk_omap_reg *reg;
|
||||
|
||||
if (!setup)
|
||||
return NULL;
|
||||
|
||||
div = kzalloc(sizeof(*div), GFP_KERNEL);
|
||||
if (!div)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
reg = (struct clk_omap_reg *)&div->reg;
|
||||
reg->index = setup->module;
|
||||
reg->offset = setup->reg;
|
||||
|
||||
if (setup->flags & CLKF_INDEX_STARTS_AT_ONE)
|
||||
div->flags |= CLK_DIVIDER_ONE_BASED;
|
||||
|
||||
if (setup->flags & CLKF_INDEX_POWER_OF_TWO)
|
||||
div->flags |= CLK_DIVIDER_POWER_OF_TWO;
|
||||
|
||||
div->table = _get_div_table_from_setup(setup, &div->width);
|
||||
|
||||
div->shift = setup->bit_shift;
|
||||
|
||||
return &div->hw;
|
||||
}
|
||||
|
||||
struct clk *ti_clk_register_divider(struct ti_clk *setup)
|
||||
{
|
||||
struct ti_clk_divider *div;
|
||||
struct clk_omap_reg *reg_setup;
|
||||
u32 reg;
|
||||
u8 width;
|
||||
u32 flags = 0;
|
||||
u8 div_flags = 0;
|
||||
struct clk_div_table *table;
|
||||
struct clk *clk;
|
||||
|
||||
div = setup->data;
|
||||
|
||||
reg_setup = (struct clk_omap_reg *)®
|
||||
|
||||
reg_setup->index = div->module;
|
||||
reg_setup->offset = div->reg;
|
||||
|
||||
if (div->flags & CLKF_INDEX_STARTS_AT_ONE)
|
||||
div_flags |= CLK_DIVIDER_ONE_BASED;
|
||||
|
||||
if (div->flags & CLKF_INDEX_POWER_OF_TWO)
|
||||
div_flags |= CLK_DIVIDER_POWER_OF_TWO;
|
||||
|
||||
if (div->flags & CLKF_SET_RATE_PARENT)
|
||||
flags |= CLK_SET_RATE_PARENT;
|
||||
|
||||
table = _get_div_table_from_setup(div, &width);
|
||||
if (IS_ERR(table))
|
||||
return (struct clk *)table;
|
||||
|
||||
clk = _register_divider(NULL, setup->name, div->parent,
|
||||
flags, (void __iomem *)reg, div->bit_shift,
|
||||
width, div_flags, table, NULL);
|
||||
|
||||
if (IS_ERR(clk))
|
||||
kfree(table);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
static struct clk_div_table *
|
||||
__init ti_clk_get_div_table(struct device_node *node)
|
||||
{
|
||||
@ -455,7 +584,8 @@ static void __init of_ti_divider_clk_setup(struct device_node *node)
|
||||
goto cleanup;
|
||||
|
||||
clk = _register_divider(NULL, node->name, parent_name, flags, reg,
|
||||
shift, width, clk_divider_flags, table, NULL);
|
||||
shift, width, clk_divider_flags, table,
|
||||
NULL);
|
||||
|
||||
if (!IS_ERR(clk)) {
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/clk/ti.h>
|
||||
#include "clock.h"
|
||||
|
||||
#undef pr_fmt
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
@ -130,7 +131,7 @@ static const struct clk_ops dpll_x2_ck_ops = {
|
||||
};
|
||||
|
||||
/**
|
||||
* ti_clk_register_dpll - low level registration of a DPLL clock
|
||||
* _register_dpll - low level registration of a DPLL clock
|
||||
* @hw: hardware clock definition for the clock
|
||||
* @node: device node for the clock
|
||||
*
|
||||
@ -138,8 +139,8 @@ static const struct clk_ops dpll_x2_ck_ops = {
|
||||
* clk-bypass is missing), the clock is added to retry list and
|
||||
* the initialization is retried on later stage.
|
||||
*/
|
||||
static void __init ti_clk_register_dpll(struct clk_hw *hw,
|
||||
struct device_node *node)
|
||||
static void __init _register_dpll(struct clk_hw *hw,
|
||||
struct device_node *node)
|
||||
{
|
||||
struct clk_hw_omap *clk_hw = to_clk_hw_omap(hw);
|
||||
struct dpll_data *dd = clk_hw->dpll_data;
|
||||
@ -151,7 +152,7 @@ static void __init ti_clk_register_dpll(struct clk_hw *hw,
|
||||
if (IS_ERR(dd->clk_ref) || IS_ERR(dd->clk_bypass)) {
|
||||
pr_debug("clk-ref or clk-bypass missing for %s, retry later\n",
|
||||
node->name);
|
||||
if (!ti_clk_retry_init(node, hw, ti_clk_register_dpll))
|
||||
if (!ti_clk_retry_init(node, hw, _register_dpll))
|
||||
return;
|
||||
|
||||
goto cleanup;
|
||||
@ -175,20 +176,116 @@ cleanup:
|
||||
kfree(clk_hw);
|
||||
}
|
||||
|
||||
void __iomem *_get_reg(u8 module, u16 offset)
|
||||
{
|
||||
u32 reg;
|
||||
struct clk_omap_reg *reg_setup;
|
||||
|
||||
reg_setup = (struct clk_omap_reg *)®
|
||||
|
||||
reg_setup->index = module;
|
||||
reg_setup->offset = offset;
|
||||
|
||||
return (void __iomem *)reg;
|
||||
}
|
||||
|
||||
struct clk *ti_clk_register_dpll(struct ti_clk *setup)
|
||||
{
|
||||
struct clk_hw_omap *clk_hw;
|
||||
struct clk_init_data init = { NULL };
|
||||
struct dpll_data *dd;
|
||||
struct clk *clk;
|
||||
struct ti_clk_dpll *dpll;
|
||||
const struct clk_ops *ops = &omap3_dpll_ck_ops;
|
||||
struct clk *clk_ref;
|
||||
struct clk *clk_bypass;
|
||||
|
||||
dpll = setup->data;
|
||||
|
||||
if (dpll->num_parents < 2)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
clk_ref = clk_get_sys(NULL, dpll->parents[0]);
|
||||
clk_bypass = clk_get_sys(NULL, dpll->parents[1]);
|
||||
|
||||
if (IS_ERR_OR_NULL(clk_ref) || IS_ERR_OR_NULL(clk_bypass))
|
||||
return ERR_PTR(-EAGAIN);
|
||||
|
||||
dd = kzalloc(sizeof(*dd), GFP_KERNEL);
|
||||
clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
|
||||
if (!dd || !clk_hw) {
|
||||
clk = ERR_PTR(-ENOMEM);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
clk_hw->dpll_data = dd;
|
||||
clk_hw->ops = &clkhwops_omap3_dpll;
|
||||
clk_hw->hw.init = &init;
|
||||
clk_hw->flags = MEMMAP_ADDRESSING;
|
||||
|
||||
init.name = setup->name;
|
||||
init.ops = ops;
|
||||
|
||||
init.num_parents = dpll->num_parents;
|
||||
init.parent_names = dpll->parents;
|
||||
|
||||
dd->control_reg = _get_reg(dpll->module, dpll->control_reg);
|
||||
dd->idlest_reg = _get_reg(dpll->module, dpll->idlest_reg);
|
||||
dd->mult_div1_reg = _get_reg(dpll->module, dpll->mult_div1_reg);
|
||||
dd->autoidle_reg = _get_reg(dpll->module, dpll->autoidle_reg);
|
||||
|
||||
dd->modes = dpll->modes;
|
||||
dd->div1_mask = dpll->div1_mask;
|
||||
dd->idlest_mask = dpll->idlest_mask;
|
||||
dd->mult_mask = dpll->mult_mask;
|
||||
dd->autoidle_mask = dpll->autoidle_mask;
|
||||
dd->enable_mask = dpll->enable_mask;
|
||||
dd->sddiv_mask = dpll->sddiv_mask;
|
||||
dd->dco_mask = dpll->dco_mask;
|
||||
dd->max_divider = dpll->max_divider;
|
||||
dd->min_divider = dpll->min_divider;
|
||||
dd->max_multiplier = dpll->max_multiplier;
|
||||
dd->auto_recal_bit = dpll->auto_recal_bit;
|
||||
dd->recal_en_bit = dpll->recal_en_bit;
|
||||
dd->recal_st_bit = dpll->recal_st_bit;
|
||||
|
||||
dd->clk_ref = clk_ref;
|
||||
dd->clk_bypass = clk_bypass;
|
||||
|
||||
if (dpll->flags & CLKF_CORE)
|
||||
ops = &omap3_dpll_core_ck_ops;
|
||||
|
||||
if (dpll->flags & CLKF_PER)
|
||||
ops = &omap3_dpll_per_ck_ops;
|
||||
|
||||
if (dpll->flags & CLKF_J_TYPE)
|
||||
dd->flags |= DPLL_J_TYPE;
|
||||
|
||||
clk = clk_register(NULL, &clk_hw->hw);
|
||||
|
||||
if (!IS_ERR(clk))
|
||||
return clk;
|
||||
|
||||
cleanup:
|
||||
kfree(dd);
|
||||
kfree(clk_hw);
|
||||
return clk;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \
|
||||
defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM33XX) || \
|
||||
defined(CONFIG_SOC_AM43XX)
|
||||
/**
|
||||
* ti_clk_register_dpll_x2 - Registers a DPLLx2 clock
|
||||
* _register_dpll_x2 - Registers a DPLLx2 clock
|
||||
* @node: device node for this clock
|
||||
* @ops: clk_ops for this clock
|
||||
* @hw_ops: clk_hw_ops for this clock
|
||||
*
|
||||
* Initializes a DPLL x 2 clock from device tree data.
|
||||
*/
|
||||
static void ti_clk_register_dpll_x2(struct device_node *node,
|
||||
const struct clk_ops *ops,
|
||||
const struct clk_hw_omap_ops *hw_ops)
|
||||
static void _register_dpll_x2(struct device_node *node,
|
||||
const struct clk_ops *ops,
|
||||
const struct clk_hw_omap_ops *hw_ops)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_init_data init = { NULL };
|
||||
@ -318,7 +415,7 @@ static void __init of_ti_dpll_setup(struct device_node *node,
|
||||
if (dpll_mode)
|
||||
dd->modes = dpll_mode;
|
||||
|
||||
ti_clk_register_dpll(&clk_hw->hw, node);
|
||||
_register_dpll(&clk_hw->hw, node);
|
||||
return;
|
||||
|
||||
cleanup:
|
||||
@ -332,7 +429,7 @@ cleanup:
|
||||
defined(CONFIG_SOC_DRA7XX)
|
||||
static void __init of_ti_omap4_dpll_x2_setup(struct device_node *node)
|
||||
{
|
||||
ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, &clkhwops_omap4_dpllmx);
|
||||
_register_dpll_x2(node, &dpll_x2_ck_ops, &clkhwops_omap4_dpllmx);
|
||||
}
|
||||
CLK_OF_DECLARE(ti_omap4_dpll_x2_clock, "ti,omap4-dpll-x2-clock",
|
||||
of_ti_omap4_dpll_x2_setup);
|
||||
@ -341,7 +438,7 @@ CLK_OF_DECLARE(ti_omap4_dpll_x2_clock, "ti,omap4-dpll-x2-clock",
|
||||
#if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX)
|
||||
static void __init of_ti_am3_dpll_x2_setup(struct device_node *node)
|
||||
{
|
||||
ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, NULL);
|
||||
_register_dpll_x2(node, &dpll_x2_ck_ops, NULL);
|
||||
}
|
||||
CLK_OF_DECLARE(ti_am3_dpll_x2_clock, "ti,am3-dpll-x2-clock",
|
||||
of_ti_am3_dpll_x2_setup);
|
||||
|
410
drivers/clk/ti/fapll.c
Normal file
410
drivers/clk/ti/fapll.c
Normal file
@ -0,0 +1,410 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/clk/ti.h>
|
||||
#include <asm/div64.h>
|
||||
|
||||
/* FAPLL Control Register PLL_CTRL */
|
||||
#define FAPLL_MAIN_LOCK BIT(7)
|
||||
#define FAPLL_MAIN_PLLEN BIT(3)
|
||||
#define FAPLL_MAIN_BP BIT(2)
|
||||
#define FAPLL_MAIN_LOC_CTL BIT(0)
|
||||
|
||||
/* FAPLL powerdown register PWD */
|
||||
#define FAPLL_PWD_OFFSET 4
|
||||
|
||||
#define MAX_FAPLL_OUTPUTS 7
|
||||
#define FAPLL_MAX_RETRIES 1000
|
||||
|
||||
#define to_fapll(_hw) container_of(_hw, struct fapll_data, hw)
|
||||
#define to_synth(_hw) container_of(_hw, struct fapll_synth, hw)
|
||||
|
||||
/* The bypass bit is inverted on the ddr_pll.. */
|
||||
#define fapll_is_ddr_pll(va) (((u32)(va) & 0xffff) == 0x0440)
|
||||
|
||||
/*
|
||||
* The audio_pll_clk1 input is hard wired to the 27MHz bypass clock,
|
||||
* and the audio_pll_clk1 synthesizer is hardwared to 32KiHz output.
|
||||
*/
|
||||
#define is_ddr_pll_clk1(va) (((u32)(va) & 0xffff) == 0x044c)
|
||||
#define is_audio_pll_clk1(va) (((u32)(va) & 0xffff) == 0x04a8)
|
||||
|
||||
/* Synthesizer divider register */
|
||||
#define SYNTH_LDMDIV1 BIT(8)
|
||||
|
||||
/* Synthesizer frequency register */
|
||||
#define SYNTH_LDFREQ BIT(31)
|
||||
|
||||
struct fapll_data {
|
||||
struct clk_hw hw;
|
||||
void __iomem *base;
|
||||
const char *name;
|
||||
struct clk *clk_ref;
|
||||
struct clk *clk_bypass;
|
||||
struct clk_onecell_data outputs;
|
||||
bool bypass_bit_inverted;
|
||||
};
|
||||
|
||||
struct fapll_synth {
|
||||
struct clk_hw hw;
|
||||
struct fapll_data *fd;
|
||||
int index;
|
||||
void __iomem *freq;
|
||||
void __iomem *div;
|
||||
const char *name;
|
||||
struct clk *clk_pll;
|
||||
};
|
||||
|
||||
static bool ti_fapll_clock_is_bypass(struct fapll_data *fd)
|
||||
{
|
||||
u32 v = readl_relaxed(fd->base);
|
||||
|
||||
if (fd->bypass_bit_inverted)
|
||||
return !(v & FAPLL_MAIN_BP);
|
||||
else
|
||||
return !!(v & FAPLL_MAIN_BP);
|
||||
}
|
||||
|
||||
static int ti_fapll_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct fapll_data *fd = to_fapll(hw);
|
||||
u32 v = readl_relaxed(fd->base);
|
||||
|
||||
v |= (1 << FAPLL_MAIN_PLLEN);
|
||||
writel_relaxed(v, fd->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ti_fapll_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct fapll_data *fd = to_fapll(hw);
|
||||
u32 v = readl_relaxed(fd->base);
|
||||
|
||||
v &= ~(1 << FAPLL_MAIN_PLLEN);
|
||||
writel_relaxed(v, fd->base);
|
||||
}
|
||||
|
||||
static int ti_fapll_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct fapll_data *fd = to_fapll(hw);
|
||||
u32 v = readl_relaxed(fd->base);
|
||||
|
||||
return v & (1 << FAPLL_MAIN_PLLEN);
|
||||
}
|
||||
|
||||
static unsigned long ti_fapll_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct fapll_data *fd = to_fapll(hw);
|
||||
u32 fapll_n, fapll_p, v;
|
||||
long long rate;
|
||||
|
||||
if (ti_fapll_clock_is_bypass(fd))
|
||||
return parent_rate;
|
||||
|
||||
rate = parent_rate;
|
||||
|
||||
/* PLL pre-divider is P and multiplier is N */
|
||||
v = readl_relaxed(fd->base);
|
||||
fapll_p = (v >> 8) & 0xff;
|
||||
if (fapll_p)
|
||||
do_div(rate, fapll_p);
|
||||
fapll_n = v >> 16;
|
||||
if (fapll_n)
|
||||
rate *= fapll_n;
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static u8 ti_fapll_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct fapll_data *fd = to_fapll(hw);
|
||||
|
||||
if (ti_fapll_clock_is_bypass(fd))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clk_ops ti_fapll_ops = {
|
||||
.enable = ti_fapll_enable,
|
||||
.disable = ti_fapll_disable,
|
||||
.is_enabled = ti_fapll_is_enabled,
|
||||
.recalc_rate = ti_fapll_recalc_rate,
|
||||
.get_parent = ti_fapll_get_parent,
|
||||
};
|
||||
|
||||
static int ti_fapll_synth_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct fapll_synth *synth = to_synth(hw);
|
||||
u32 v = readl_relaxed(synth->fd->base + FAPLL_PWD_OFFSET);
|
||||
|
||||
v &= ~(1 << synth->index);
|
||||
writel_relaxed(v, synth->fd->base + FAPLL_PWD_OFFSET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ti_fapll_synth_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct fapll_synth *synth = to_synth(hw);
|
||||
u32 v = readl_relaxed(synth->fd->base + FAPLL_PWD_OFFSET);
|
||||
|
||||
v |= 1 << synth->index;
|
||||
writel_relaxed(v, synth->fd->base + FAPLL_PWD_OFFSET);
|
||||
}
|
||||
|
||||
static int ti_fapll_synth_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct fapll_synth *synth = to_synth(hw);
|
||||
u32 v = readl_relaxed(synth->fd->base + FAPLL_PWD_OFFSET);
|
||||
|
||||
return !(v & (1 << synth->index));
|
||||
}
|
||||
|
||||
/*
|
||||
* See dm816x TRM chapter 1.10.3 Flying Adder PLL fore more info
|
||||
*/
|
||||
static unsigned long ti_fapll_synth_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct fapll_synth *synth = to_synth(hw);
|
||||
u32 synth_div_m;
|
||||
long long rate;
|
||||
|
||||
/* The audio_pll_clk1 is hardwired to produce 32.768KiHz clock */
|
||||
if (!synth->div)
|
||||
return 32768;
|
||||
|
||||
/*
|
||||
* PLL in bypass sets the synths in bypass mode too. The PLL rate
|
||||
* can be also be set to 27MHz, so we can't use parent_rate to
|
||||
* check for bypass mode.
|
||||
*/
|
||||
if (ti_fapll_clock_is_bypass(synth->fd))
|
||||
return parent_rate;
|
||||
|
||||
rate = parent_rate;
|
||||
|
||||
/*
|
||||
* Synth frequency integer and fractional divider.
|
||||
* Note that the phase output K is 8, so the result needs
|
||||
* to be multiplied by 8.
|
||||
*/
|
||||
if (synth->freq) {
|
||||
u32 v, synth_int_div, synth_frac_div, synth_div_freq;
|
||||
|
||||
v = readl_relaxed(synth->freq);
|
||||
synth_int_div = (v >> 24) & 0xf;
|
||||
synth_frac_div = v & 0xffffff;
|
||||
synth_div_freq = (synth_int_div * 10000000) + synth_frac_div;
|
||||
rate *= 10000000;
|
||||
do_div(rate, synth_div_freq);
|
||||
rate *= 8;
|
||||
}
|
||||
|
||||
/* Synth ost-divider M */
|
||||
synth_div_m = readl_relaxed(synth->div) & 0xff;
|
||||
do_div(rate, synth_div_m);
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static struct clk_ops ti_fapll_synt_ops = {
|
||||
.enable = ti_fapll_synth_enable,
|
||||
.disable = ti_fapll_synth_disable,
|
||||
.is_enabled = ti_fapll_synth_is_enabled,
|
||||
.recalc_rate = ti_fapll_synth_recalc_rate,
|
||||
};
|
||||
|
||||
static struct clk * __init ti_fapll_synth_setup(struct fapll_data *fd,
|
||||
void __iomem *freq,
|
||||
void __iomem *div,
|
||||
int index,
|
||||
const char *name,
|
||||
const char *parent,
|
||||
struct clk *pll_clk)
|
||||
{
|
||||
struct clk_init_data *init;
|
||||
struct fapll_synth *synth;
|
||||
|
||||
init = kzalloc(sizeof(*init), GFP_KERNEL);
|
||||
if (!init)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init->ops = &ti_fapll_synt_ops;
|
||||
init->name = name;
|
||||
init->parent_names = &parent;
|
||||
init->num_parents = 1;
|
||||
|
||||
synth = kzalloc(sizeof(*synth), GFP_KERNEL);
|
||||
if (!synth)
|
||||
goto free;
|
||||
|
||||
synth->fd = fd;
|
||||
synth->index = index;
|
||||
synth->freq = freq;
|
||||
synth->div = div;
|
||||
synth->name = name;
|
||||
synth->hw.init = init;
|
||||
synth->clk_pll = pll_clk;
|
||||
|
||||
return clk_register(NULL, &synth->hw);
|
||||
|
||||
free:
|
||||
kfree(synth);
|
||||
kfree(init);
|
||||
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
static void __init ti_fapll_setup(struct device_node *node)
|
||||
{
|
||||
struct fapll_data *fd;
|
||||
struct clk_init_data *init = NULL;
|
||||
const char *parent_name[2];
|
||||
struct clk *pll_clk;
|
||||
int i;
|
||||
|
||||
fd = kzalloc(sizeof(*fd), GFP_KERNEL);
|
||||
if (!fd)
|
||||
return;
|
||||
|
||||
fd->outputs.clks = kzalloc(sizeof(struct clk *) *
|
||||
MAX_FAPLL_OUTPUTS + 1,
|
||||
GFP_KERNEL);
|
||||
if (!fd->outputs.clks)
|
||||
goto free;
|
||||
|
||||
init = kzalloc(sizeof(*init), GFP_KERNEL);
|
||||
if (!init)
|
||||
goto free;
|
||||
|
||||
init->ops = &ti_fapll_ops;
|
||||
init->name = node->name;
|
||||
|
||||
init->num_parents = of_clk_get_parent_count(node);
|
||||
if (init->num_parents != 2) {
|
||||
pr_err("%s must have two parents\n", node->name);
|
||||
goto free;
|
||||
}
|
||||
|
||||
parent_name[0] = of_clk_get_parent_name(node, 0);
|
||||
parent_name[1] = of_clk_get_parent_name(node, 1);
|
||||
init->parent_names = parent_name;
|
||||
|
||||
fd->clk_ref = of_clk_get(node, 0);
|
||||
if (IS_ERR(fd->clk_ref)) {
|
||||
pr_err("%s could not get clk_ref\n", node->name);
|
||||
goto free;
|
||||
}
|
||||
|
||||
fd->clk_bypass = of_clk_get(node, 1);
|
||||
if (IS_ERR(fd->clk_bypass)) {
|
||||
pr_err("%s could not get clk_bypass\n", node->name);
|
||||
goto free;
|
||||
}
|
||||
|
||||
fd->base = of_iomap(node, 0);
|
||||
if (!fd->base) {
|
||||
pr_err("%s could not get IO base\n", node->name);
|
||||
goto free;
|
||||
}
|
||||
|
||||
if (fapll_is_ddr_pll(fd->base))
|
||||
fd->bypass_bit_inverted = true;
|
||||
|
||||
fd->name = node->name;
|
||||
fd->hw.init = init;
|
||||
|
||||
/* Register the parent PLL */
|
||||
pll_clk = clk_register(NULL, &fd->hw);
|
||||
if (IS_ERR(pll_clk))
|
||||
goto unmap;
|
||||
|
||||
fd->outputs.clks[0] = pll_clk;
|
||||
fd->outputs.clk_num++;
|
||||
|
||||
/*
|
||||
* Set up the child synthesizers starting at index 1 as the
|
||||
* PLL output is at index 0. We need to check the clock-indices
|
||||
* for numbering in case there are holes in the synth mapping,
|
||||
* and then probe the synth register to see if it has a FREQ
|
||||
* register available.
|
||||
*/
|
||||
for (i = 0; i < MAX_FAPLL_OUTPUTS; i++) {
|
||||
const char *output_name;
|
||||
void __iomem *freq, *div;
|
||||
struct clk *synth_clk;
|
||||
int output_instance;
|
||||
u32 v;
|
||||
|
||||
if (of_property_read_string_index(node, "clock-output-names",
|
||||
i, &output_name))
|
||||
continue;
|
||||
|
||||
if (of_property_read_u32_index(node, "clock-indices", i,
|
||||
&output_instance))
|
||||
output_instance = i;
|
||||
|
||||
freq = fd->base + (output_instance * 8);
|
||||
div = freq + 4;
|
||||
|
||||
/* Check for hardwired audio_pll_clk1 */
|
||||
if (is_audio_pll_clk1(freq)) {
|
||||
freq = 0;
|
||||
div = 0;
|
||||
} else {
|
||||
/* Does the synthesizer have a FREQ register? */
|
||||
v = readl_relaxed(freq);
|
||||
if (!v)
|
||||
freq = 0;
|
||||
}
|
||||
synth_clk = ti_fapll_synth_setup(fd, freq, div, output_instance,
|
||||
output_name, node->name,
|
||||
pll_clk);
|
||||
if (IS_ERR(synth_clk))
|
||||
continue;
|
||||
|
||||
fd->outputs.clks[output_instance] = synth_clk;
|
||||
fd->outputs.clk_num++;
|
||||
|
||||
clk_register_clkdev(synth_clk, output_name, NULL);
|
||||
}
|
||||
|
||||
/* Register the child synthesizers as the FAPLL outputs */
|
||||
of_clk_add_provider(node, of_clk_src_onecell_get, &fd->outputs);
|
||||
/* Add clock alias for the outputs */
|
||||
|
||||
kfree(init);
|
||||
|
||||
return;
|
||||
|
||||
unmap:
|
||||
iounmap(fd->base);
|
||||
free:
|
||||
if (fd->clk_bypass)
|
||||
clk_put(fd->clk_bypass);
|
||||
if (fd->clk_ref)
|
||||
clk_put(fd->clk_ref);
|
||||
kfree(fd->outputs.clks);
|
||||
kfree(fd);
|
||||
kfree(init);
|
||||
}
|
||||
|
||||
CLK_OF_DECLARE(ti_fapll_clock, "ti,dm816-fapll-clock", ti_fapll_setup);
|
@ -22,6 +22,8 @@
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/clk/ti.h>
|
||||
|
||||
#include "clock.h"
|
||||
|
||||
#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
|
||||
|
||||
#undef pr_fmt
|
||||
@ -90,63 +92,162 @@ static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *clk)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct clk *_register_gate(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
void __iomem *reg, u8 bit_idx,
|
||||
u8 clk_gate_flags, const struct clk_ops *ops,
|
||||
const struct clk_hw_omap_ops *hw_ops)
|
||||
{
|
||||
struct clk_init_data init = { NULL };
|
||||
struct clk_hw_omap *clk_hw;
|
||||
struct clk *clk;
|
||||
|
||||
clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
|
||||
if (!clk_hw)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
clk_hw->hw.init = &init;
|
||||
|
||||
init.name = name;
|
||||
init.ops = ops;
|
||||
|
||||
clk_hw->enable_reg = reg;
|
||||
clk_hw->enable_bit = bit_idx;
|
||||
clk_hw->ops = hw_ops;
|
||||
|
||||
clk_hw->flags = MEMMAP_ADDRESSING | clk_gate_flags;
|
||||
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
|
||||
init.flags = flags;
|
||||
|
||||
clk = clk_register(NULL, &clk_hw->hw);
|
||||
|
||||
if (IS_ERR(clk))
|
||||
kfree(clk_hw);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
struct clk *ti_clk_register_gate(struct ti_clk *setup)
|
||||
{
|
||||
const struct clk_ops *ops = &omap_gate_clk_ops;
|
||||
const struct clk_hw_omap_ops *hw_ops = NULL;
|
||||
u32 reg;
|
||||
struct clk_omap_reg *reg_setup;
|
||||
u32 flags = 0;
|
||||
u8 clk_gate_flags = 0;
|
||||
struct ti_clk_gate *gate;
|
||||
|
||||
gate = setup->data;
|
||||
|
||||
if (gate->flags & CLKF_INTERFACE)
|
||||
return ti_clk_register_interface(setup);
|
||||
|
||||
reg_setup = (struct clk_omap_reg *)®
|
||||
|
||||
if (gate->flags & CLKF_SET_RATE_PARENT)
|
||||
flags |= CLK_SET_RATE_PARENT;
|
||||
|
||||
if (gate->flags & CLKF_SET_BIT_TO_DISABLE)
|
||||
clk_gate_flags |= INVERT_ENABLE;
|
||||
|
||||
if (gate->flags & CLKF_HSDIV) {
|
||||
ops = &omap_gate_clk_hsdiv_restore_ops;
|
||||
hw_ops = &clkhwops_wait;
|
||||
}
|
||||
|
||||
if (gate->flags & CLKF_DSS)
|
||||
hw_ops = &clkhwops_omap3430es2_dss_usbhost_wait;
|
||||
|
||||
if (gate->flags & CLKF_WAIT)
|
||||
hw_ops = &clkhwops_wait;
|
||||
|
||||
if (gate->flags & CLKF_CLKDM)
|
||||
ops = &omap_gate_clkdm_clk_ops;
|
||||
|
||||
if (gate->flags & CLKF_AM35XX)
|
||||
hw_ops = &clkhwops_am35xx_ipss_module_wait;
|
||||
|
||||
reg_setup->index = gate->module;
|
||||
reg_setup->offset = gate->reg;
|
||||
|
||||
return _register_gate(NULL, setup->name, gate->parent, flags,
|
||||
(void __iomem *)reg, gate->bit_shift,
|
||||
clk_gate_flags, ops, hw_ops);
|
||||
}
|
||||
|
||||
struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup)
|
||||
{
|
||||
struct clk_hw_omap *gate;
|
||||
struct clk_omap_reg *reg;
|
||||
const struct clk_hw_omap_ops *ops = &clkhwops_wait;
|
||||
|
||||
if (!setup)
|
||||
return NULL;
|
||||
|
||||
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
|
||||
if (!gate)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
reg = (struct clk_omap_reg *)&gate->enable_reg;
|
||||
reg->index = setup->module;
|
||||
reg->offset = setup->reg;
|
||||
|
||||
gate->enable_bit = setup->bit_shift;
|
||||
|
||||
if (setup->flags & CLKF_NO_WAIT)
|
||||
ops = NULL;
|
||||
|
||||
if (setup->flags & CLKF_INTERFACE)
|
||||
ops = &clkhwops_iclk_wait;
|
||||
|
||||
gate->ops = ops;
|
||||
gate->flags = MEMMAP_ADDRESSING;
|
||||
|
||||
return &gate->hw;
|
||||
}
|
||||
|
||||
static void __init _of_ti_gate_clk_setup(struct device_node *node,
|
||||
const struct clk_ops *ops,
|
||||
const struct clk_hw_omap_ops *hw_ops)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_init_data init = { NULL };
|
||||
struct clk_hw_omap *clk_hw;
|
||||
const char *clk_name = node->name;
|
||||
const char *parent_name;
|
||||
void __iomem *reg = NULL;
|
||||
u8 enable_bit = 0;
|
||||
u32 val;
|
||||
|
||||
clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
|
||||
if (!clk_hw)
|
||||
return;
|
||||
|
||||
clk_hw->hw.init = &init;
|
||||
|
||||
init.name = clk_name;
|
||||
init.ops = ops;
|
||||
u32 flags = 0;
|
||||
u8 clk_gate_flags = 0;
|
||||
|
||||
if (ops != &omap_gate_clkdm_clk_ops) {
|
||||
clk_hw->enable_reg = ti_clk_get_reg_addr(node, 0);
|
||||
if (!clk_hw->enable_reg)
|
||||
goto cleanup;
|
||||
reg = ti_clk_get_reg_addr(node, 0);
|
||||
if (!reg)
|
||||
return;
|
||||
|
||||
if (!of_property_read_u32(node, "ti,bit-shift", &val))
|
||||
clk_hw->enable_bit = val;
|
||||
enable_bit = val;
|
||||
}
|
||||
|
||||
clk_hw->ops = hw_ops;
|
||||
|
||||
clk_hw->flags = MEMMAP_ADDRESSING;
|
||||
|
||||
if (of_clk_get_parent_count(node) != 1) {
|
||||
pr_err("%s must have 1 parent\n", clk_name);
|
||||
goto cleanup;
|
||||
pr_err("%s must have 1 parent\n", node->name);
|
||||
return;
|
||||
}
|
||||
|
||||
parent_name = of_clk_get_parent_name(node, 0);
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
|
||||
if (of_property_read_bool(node, "ti,set-rate-parent"))
|
||||
init.flags |= CLK_SET_RATE_PARENT;
|
||||
flags |= CLK_SET_RATE_PARENT;
|
||||
|
||||
if (of_property_read_bool(node, "ti,set-bit-to-disable"))
|
||||
clk_hw->flags |= INVERT_ENABLE;
|
||||
clk_gate_flags |= INVERT_ENABLE;
|
||||
|
||||
clk = clk_register(NULL, &clk_hw->hw);
|
||||
clk = _register_gate(NULL, node->name, parent_name, flags, reg,
|
||||
enable_bit, clk_gate_flags, ops, hw_ops);
|
||||
|
||||
if (!IS_ERR(clk)) {
|
||||
if (!IS_ERR(clk))
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
return;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
kfree(clk_hw);
|
||||
}
|
||||
|
||||
static void __init
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/clk/ti.h>
|
||||
#include "clock.h"
|
||||
|
||||
#undef pr_fmt
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
@ -31,53 +32,100 @@ static const struct clk_ops ti_interface_clk_ops = {
|
||||
.is_enabled = &omap2_dflt_clk_is_enabled,
|
||||
};
|
||||
|
||||
static void __init _of_ti_interface_clk_setup(struct device_node *node,
|
||||
const struct clk_hw_omap_ops *ops)
|
||||
static struct clk *_register_interface(struct device *dev, const char *name,
|
||||
const char *parent_name,
|
||||
void __iomem *reg, u8 bit_idx,
|
||||
const struct clk_hw_omap_ops *ops)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_init_data init = { NULL };
|
||||
struct clk_hw_omap *clk_hw;
|
||||
const char *parent_name;
|
||||
u32 val;
|
||||
struct clk *clk;
|
||||
|
||||
clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
|
||||
if (!clk_hw)
|
||||
return;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
clk_hw->hw.init = &init;
|
||||
clk_hw->ops = ops;
|
||||
clk_hw->flags = MEMMAP_ADDRESSING;
|
||||
clk_hw->enable_reg = reg;
|
||||
clk_hw->enable_bit = bit_idx;
|
||||
|
||||
clk_hw->enable_reg = ti_clk_get_reg_addr(node, 0);
|
||||
if (!clk_hw->enable_reg)
|
||||
goto cleanup;
|
||||
|
||||
if (!of_property_read_u32(node, "ti,bit-shift", &val))
|
||||
clk_hw->enable_bit = val;
|
||||
|
||||
init.name = node->name;
|
||||
init.name = name;
|
||||
init.ops = &ti_interface_clk_ops;
|
||||
init.flags = 0;
|
||||
|
||||
parent_name = of_clk_get_parent_name(node, 0);
|
||||
if (!parent_name) {
|
||||
pr_err("%s must have a parent\n", node->name);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
init.num_parents = 1;
|
||||
init.parent_names = &parent_name;
|
||||
|
||||
clk = clk_register(NULL, &clk_hw->hw);
|
||||
|
||||
if (!IS_ERR(clk)) {
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
if (IS_ERR(clk))
|
||||
kfree(clk_hw);
|
||||
else
|
||||
omap2_init_clk_hw_omap_clocks(clk);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
struct clk *ti_clk_register_interface(struct ti_clk *setup)
|
||||
{
|
||||
const struct clk_hw_omap_ops *ops = &clkhwops_iclk_wait;
|
||||
u32 reg;
|
||||
struct clk_omap_reg *reg_setup;
|
||||
struct ti_clk_gate *gate;
|
||||
|
||||
gate = setup->data;
|
||||
reg_setup = (struct clk_omap_reg *)®
|
||||
reg_setup->index = gate->module;
|
||||
reg_setup->offset = gate->reg;
|
||||
|
||||
if (gate->flags & CLKF_NO_WAIT)
|
||||
ops = &clkhwops_iclk;
|
||||
|
||||
if (gate->flags & CLKF_HSOTGUSB)
|
||||
ops = &clkhwops_omap3430es2_iclk_hsotgusb_wait;
|
||||
|
||||
if (gate->flags & CLKF_DSS)
|
||||
ops = &clkhwops_omap3430es2_iclk_dss_usbhost_wait;
|
||||
|
||||
if (gate->flags & CLKF_SSI)
|
||||
ops = &clkhwops_omap3430es2_iclk_ssi_wait;
|
||||
|
||||
if (gate->flags & CLKF_AM35XX)
|
||||
ops = &clkhwops_am35xx_ipss_wait;
|
||||
|
||||
return _register_interface(NULL, setup->name, gate->parent,
|
||||
(void __iomem *)reg, gate->bit_shift, ops);
|
||||
}
|
||||
|
||||
static void __init _of_ti_interface_clk_setup(struct device_node *node,
|
||||
const struct clk_hw_omap_ops *ops)
|
||||
{
|
||||
struct clk *clk;
|
||||
const char *parent_name;
|
||||
void __iomem *reg;
|
||||
u8 enable_bit = 0;
|
||||
u32 val;
|
||||
|
||||
reg = ti_clk_get_reg_addr(node, 0);
|
||||
if (!reg)
|
||||
return;
|
||||
|
||||
if (!of_property_read_u32(node, "ti,bit-shift", &val))
|
||||
enable_bit = val;
|
||||
|
||||
parent_name = of_clk_get_parent_name(node, 0);
|
||||
if (!parent_name) {
|
||||
pr_err("%s must have a parent\n", node->name);
|
||||
return;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
kfree(clk_hw);
|
||||
clk = _register_interface(NULL, node->name, parent_name, reg,
|
||||
enable_bit, ops);
|
||||
|
||||
if (!IS_ERR(clk))
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
}
|
||||
|
||||
static void __init of_ti_interface_clk_setup(struct device_node *node)
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/clk/ti.h>
|
||||
#include "clock.h"
|
||||
|
||||
#undef pr_fmt
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
@ -144,6 +145,39 @@ static struct clk *_register_mux(struct device *dev, const char *name,
|
||||
return clk;
|
||||
}
|
||||
|
||||
struct clk *ti_clk_register_mux(struct ti_clk *setup)
|
||||
{
|
||||
struct ti_clk_mux *mux;
|
||||
u32 flags;
|
||||
u8 mux_flags = 0;
|
||||
struct clk_omap_reg *reg_setup;
|
||||
u32 reg;
|
||||
u32 mask;
|
||||
|
||||
reg_setup = (struct clk_omap_reg *)®
|
||||
|
||||
mux = setup->data;
|
||||
flags = CLK_SET_RATE_NO_REPARENT;
|
||||
|
||||
mask = mux->num_parents;
|
||||
if (!(mux->flags & CLKF_INDEX_STARTS_AT_ONE))
|
||||
mask--;
|
||||
|
||||
mask = (1 << fls(mask)) - 1;
|
||||
reg_setup->index = mux->module;
|
||||
reg_setup->offset = mux->reg;
|
||||
|
||||
if (mux->flags & CLKF_INDEX_STARTS_AT_ONE)
|
||||
mux_flags |= CLK_MUX_INDEX_ONE;
|
||||
|
||||
if (mux->flags & CLKF_SET_RATE_PARENT)
|
||||
flags |= CLK_SET_RATE_PARENT;
|
||||
|
||||
return _register_mux(NULL, setup->name, mux->parents, mux->num_parents,
|
||||
flags, (void __iomem *)reg, mux->bit_shift, mask,
|
||||
mux_flags, NULL, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* of_mux_clk_setup - Setup function for simple mux rate clock
|
||||
* @node: DT node for the clock
|
||||
@ -194,8 +228,9 @@ static void of_mux_clk_setup(struct device_node *node)
|
||||
|
||||
mask = (1 << fls(mask)) - 1;
|
||||
|
||||
clk = _register_mux(NULL, node->name, parent_names, num_parents, flags,
|
||||
reg, shift, mask, clk_mux_flags, NULL, NULL);
|
||||
clk = _register_mux(NULL, node->name, parent_names, num_parents,
|
||||
flags, reg, shift, mask, clk_mux_flags, NULL,
|
||||
NULL);
|
||||
|
||||
if (!IS_ERR(clk))
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
@ -205,6 +240,37 @@ cleanup:
|
||||
}
|
||||
CLK_OF_DECLARE(mux_clk, "ti,mux-clock", of_mux_clk_setup);
|
||||
|
||||
struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup)
|
||||
{
|
||||
struct clk_mux *mux;
|
||||
struct clk_omap_reg *reg;
|
||||
int num_parents;
|
||||
|
||||
if (!setup)
|
||||
return NULL;
|
||||
|
||||
mux = kzalloc(sizeof(*mux), GFP_KERNEL);
|
||||
if (!mux)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
reg = (struct clk_omap_reg *)&mux->reg;
|
||||
|
||||
mux->shift = setup->bit_shift;
|
||||
|
||||
reg->index = setup->module;
|
||||
reg->offset = setup->reg;
|
||||
|
||||
if (setup->flags & CLKF_INDEX_STARTS_AT_ONE)
|
||||
mux->flags |= CLK_MUX_INDEX_ONE;
|
||||
|
||||
num_parents = setup->num_parents;
|
||||
|
||||
mux->mask = num_parents - 1;
|
||||
mux->mask = (1 << fls(mux->mask)) - 1;
|
||||
|
||||
return &mux->hw;
|
||||
}
|
||||
|
||||
static void __init of_ti_composite_mux_clk_setup(struct device_node *node)
|
||||
{
|
||||
struct clk_mux *mux;
|
||||
|
@ -8,7 +8,6 @@
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk-private.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user