The common clock framework changes for 3.10 include many fixes for
existing platforms, as well as adoption of the framework by new platforms and devices. Some long-needed fixes to the core framework are here as well as new features such as improved initialization of clocks from DT as well as framework reentrancy for nested clock operations. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJRfqtLAAoJEDqPOy9afJhJsxwP/RLvfeeMIU3804ahVNK2C59h ehJ06ZP+b0u0A7+YSC7CX1pHXIFW+UoZgYLJiLdV2kEdpOIKMELZyUcEVB97u1Of TVlsmHfTLv2zVAq/LYRVSKFYeMUd/6RRoq7Cm6hoj638IVeXG7C+8pei2aVZe++t 1ENmb4UGFJ7NLfpE5zQ3fEuIfHfuWA8Od6SmPaV/YG5Io8HgkDGF3/tCJURJGII6 xLN2Rh8qbFktJLVvKe6yLyvUEZiWh8A6HNPyNiFYYGX11wU76zK2wMN3BW6Nn/kW 3PubzISoKRaoCZvuVK+CoLWnhFl2LteFVVmL1TBc/jxJe6q+rLX33sXl1q9K+SLt POnHf/7nDyO3zbZWgfRR1r3FdeZqdLYw8HVsLcOKFcv9n1UligzuUNml5PklKwNh BDMmSo5ytS1QPV1e9ZtVrk6IyvDyrenwfDW1Mw43ST6D23FVrivywB4X9ur6WljI d1/CBvQXQZ11Hd4OAvqRL8QYFJvc5WlERjSd1j6I6XS6xioKOTKMkUC/KpRcCid9 avA6mJ5k/a1jTojvh2wl37paI//OzY0VDlxRSeMZIu9Dsn29DnPlE5CLg535Ovu+ mn9OtLFEDNnlgWCMQYUehGd7ITgtwrB/fxxNeBbMYjDz4AIirR2BIvMR7I8CMTQz M0rHu8NpwKH6eqC6kAup =+LO3 -----END PGP SIGNATURE----- Merge tag 'clk-for-linus-3.10' of git://git.linaro.org/people/mturquette/linux Pull clock framework update from Michael Turquette: "The common clock framework changes for 3.10 include many fixes for existing platforms, as well as adoption of the framework by new platforms and devices. Some long-needed fixes to the core framework are here as well as new features such as improved initialization of clocks from DT as well as framework reentrancy for nested clock operations." * tag 'clk-for-linus-3.10' of git://git.linaro.org/people/mturquette/linux: (44 commits) clk: add clk_ignore_unused option to keep boot clocks on clk: ux500: fix mismatched types clk: vexpress: Add separate SP810 driver clk: si5351: make clk-si5351 depend on CONFIG_OF clk: export __clk_get_flags for modular clock providers clk: vt8500: Missing breaks in vtwm_pll_round_rate/_set_rate. clk: sunxi: Unify oscillator clock clk: composite: allow fixed rates & fixed dividers clk: composite: rename 'div' references to 'rate' clk: add si5351 i2c common clock driver clk: add device tree fixed-factor-clock binding support clk: Properly handle notifier return values clk: ux500: abx500: Define clock tree for ab850x clk: ux500: Add support for sysctrl clocks clk: mvebu: Fix valid value range checking for cpu_freq_select clk: Fixup locking issues for clk_set_parent clk: Fixup errorhandling for clk_set_parent clk: Restructure code for __clk_reparent clk: sunxi: drop an unnecesary kmalloc clk: sunxi: drop CLK_IGNORE_UNUSED ...
This commit is contained in:
		
				commit
				
					
						362ed48dee
					
				
			
		
					 48 changed files with 4520 additions and 306 deletions
				
			
		
							
								
								
									
										56
									
								
								Documentation/arm/sunxi/clocks.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								Documentation/arm/sunxi/clocks.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,56 @@
 | 
			
		|||
Frequently asked questions about the sunxi clock system
 | 
			
		||||
=======================================================
 | 
			
		||||
 | 
			
		||||
This document contains useful bits of information that people tend to ask
 | 
			
		||||
about the sunxi clock system, as well as accompanying ASCII art when adequate.
 | 
			
		||||
 | 
			
		||||
Q: Why is the main 24MHz oscillator gatable? Wouldn't that break the
 | 
			
		||||
   system?
 | 
			
		||||
 | 
			
		||||
A: The 24MHz oscillator allows gating to save power. Indeed, if gated
 | 
			
		||||
   carelessly the system would stop functioning, but with the right
 | 
			
		||||
   steps, one can gate it and keep the system running. Consider this
 | 
			
		||||
   simplified suspend example:
 | 
			
		||||
 | 
			
		||||
   While the system is operational, you would see something like
 | 
			
		||||
 | 
			
		||||
      24MHz         32kHz
 | 
			
		||||
       |
 | 
			
		||||
      PLL1
 | 
			
		||||
       \
 | 
			
		||||
        \_ CPU Mux
 | 
			
		||||
             |
 | 
			
		||||
           [CPU]
 | 
			
		||||
 | 
			
		||||
   When you are about to suspend, you switch the CPU Mux to the 32kHz
 | 
			
		||||
   oscillator:
 | 
			
		||||
 | 
			
		||||
      24Mhz         32kHz
 | 
			
		||||
       |              |
 | 
			
		||||
      PLL1            |
 | 
			
		||||
                     /
 | 
			
		||||
           CPU Mux _/
 | 
			
		||||
             |
 | 
			
		||||
           [CPU]
 | 
			
		||||
 | 
			
		||||
    Finally you can gate the main oscillator
 | 
			
		||||
 | 
			
		||||
                    32kHz
 | 
			
		||||
                      |
 | 
			
		||||
                      |
 | 
			
		||||
                     /
 | 
			
		||||
           CPU Mux _/
 | 
			
		||||
             |
 | 
			
		||||
           [CPU]
 | 
			
		||||
 | 
			
		||||
Q: Were can I learn more about the sunxi clocks?
 | 
			
		||||
 | 
			
		||||
A: The linux-sunxi wiki contains a page documenting the clock registers,
 | 
			
		||||
   you can find it at
 | 
			
		||||
 | 
			
		||||
        http://linux-sunxi.org/A10/CCM
 | 
			
		||||
 | 
			
		||||
   The authoritative source for information at this time is the ccmu driver
 | 
			
		||||
   released by Allwinner, you can find it at
 | 
			
		||||
 | 
			
		||||
        https://github.com/linux-sunxi/linux-sunxi/tree/sunxi-3.0/arch/arm/mach-sun4i/clock/ccmu
 | 
			
		||||
| 
						 | 
				
			
			@ -174,9 +174,9 @@ int clk_foo_enable(struct clk_hw *hw)
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
Below is a matrix detailing which clk_ops are mandatory based upon the
 | 
			
		||||
hardware capbilities of that clock.  A cell marked as "y" means
 | 
			
		||||
hardware capabilities of that clock.  A cell marked as "y" means
 | 
			
		||||
mandatory, a cell marked as "n" implies that either including that
 | 
			
		||||
callback is invalid or otherwise uneccesary.  Empty cells are either
 | 
			
		||||
callback is invalid or otherwise unnecessary.  Empty cells are either
 | 
			
		||||
optional or must be evaluated on a case-by-case basis.
 | 
			
		||||
 | 
			
		||||
                           clock hardware characteristics
 | 
			
		||||
| 
						 | 
				
			
			@ -231,3 +231,14 @@ To better enforce this policy, always follow this simple rule: any
 | 
			
		|||
statically initialized clock data MUST be defined in a separate file
 | 
			
		||||
from the logic that implements its ops.  Basically separate the logic
 | 
			
		||||
from the data and all is well.
 | 
			
		||||
 | 
			
		||||
	Part 6 - Disabling clock gating of unused clocks
 | 
			
		||||
 | 
			
		||||
Sometimes during development it can be useful to be able to bypass the
 | 
			
		||||
default disabling of unused clocks. For example, if drivers aren't enabling
 | 
			
		||||
clocks properly but rely on them being on from the bootloader, bypassing
 | 
			
		||||
the disabling means that the driver will remain functional while the issues
 | 
			
		||||
are sorted out.
 | 
			
		||||
 | 
			
		||||
To bypass this disabling, include "clk_ignore_unused" in the bootargs to the
 | 
			
		||||
kernel.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										22
									
								
								Documentation/devicetree/bindings/clock/axi-clkgen.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								Documentation/devicetree/bindings/clock/axi-clkgen.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
Binding for the axi-clkgen clock generator
 | 
			
		||||
 | 
			
		||||
This binding uses the common clock binding[1].
 | 
			
		||||
 | 
			
		||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
 | 
			
		||||
 | 
			
		||||
Required properties:
 | 
			
		||||
- compatible : shall be "adi,axi-clkgen".
 | 
			
		||||
- #clock-cells : from common clock binding; Should always be set to 0.
 | 
			
		||||
- reg : Address and length of the axi-clkgen register set.
 | 
			
		||||
- clocks : Phandle and clock specifier for the parent clock.
 | 
			
		||||
 | 
			
		||||
Optional properties:
 | 
			
		||||
- clock-output-names : From common clock binding.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
	clock@0xff000000 {
 | 
			
		||||
		compatible = "adi,axi-clkgen";
 | 
			
		||||
		#clock-cells = <0>;
 | 
			
		||||
		reg = <0xff000000 0x1000>;
 | 
			
		||||
		clocks = <&osc 1>;
 | 
			
		||||
	};
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
Binding for simple fixed factor rate clock sources.
 | 
			
		||||
 | 
			
		||||
This binding uses the common clock binding[1].
 | 
			
		||||
 | 
			
		||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
 | 
			
		||||
 | 
			
		||||
Required properties:
 | 
			
		||||
- compatible : shall be "fixed-factor-clock".
 | 
			
		||||
- #clock-cells : from common clock binding; shall be set to 0.
 | 
			
		||||
- clock-div: fixed divider.
 | 
			
		||||
- clock-mult: fixed multiplier.
 | 
			
		||||
- clocks: parent clock.
 | 
			
		||||
 | 
			
		||||
Optional properties:
 | 
			
		||||
- clock-output-names : From common clock binding.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
	clock {
 | 
			
		||||
		compatible = "fixed-factor-clock";
 | 
			
		||||
		clocks = <&parentclk>;
 | 
			
		||||
		#clock-cells = <0>;
 | 
			
		||||
		div = <2>;
 | 
			
		||||
		mult = <1>;
 | 
			
		||||
	};
 | 
			
		||||
							
								
								
									
										114
									
								
								Documentation/devicetree/bindings/clock/silabs,si5351.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								Documentation/devicetree/bindings/clock/silabs,si5351.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,114 @@
 | 
			
		|||
Binding for Silicon Labs Si5351a/b/c programmable i2c clock generator.
 | 
			
		||||
 | 
			
		||||
Reference
 | 
			
		||||
[1] Si5351A/B/C Data Sheet
 | 
			
		||||
    http://www.silabs.com/Support%20Documents/TechnicalDocs/Si5351.pdf
 | 
			
		||||
 | 
			
		||||
The Si5351a/b/c are programmable i2c clock generators with upto 8 output
 | 
			
		||||
clocks. Si5351a also has a reduced pin-count package (MSOP10) where only
 | 
			
		||||
3 output clocks are accessible. The internal structure of the clock
 | 
			
		||||
generators can be found in [1].
 | 
			
		||||
 | 
			
		||||
==I2C device node==
 | 
			
		||||
 | 
			
		||||
Required properties:
 | 
			
		||||
- compatible: shall be one of "silabs,si5351{a,a-msop,b,c}".
 | 
			
		||||
- reg: i2c device address, shall be 0x60 or 0x61.
 | 
			
		||||
- #clock-cells: from common clock binding; shall be set to 1.
 | 
			
		||||
- clocks: from common clock binding; list of parent clock
 | 
			
		||||
  handles, shall be xtal reference clock or xtal and clkin for
 | 
			
		||||
  si5351c only.
 | 
			
		||||
- #address-cells: shall be set to 1.
 | 
			
		||||
- #size-cells: shall be set to 0.
 | 
			
		||||
 | 
			
		||||
Optional properties:
 | 
			
		||||
- silabs,pll-source: pair of (number, source) for each pll. Allows
 | 
			
		||||
  to overwrite clock source of pll A (number=0) or B (number=1).
 | 
			
		||||
 | 
			
		||||
==Child nodes==
 | 
			
		||||
 | 
			
		||||
Each of the clock outputs can be overwritten individually by
 | 
			
		||||
using a child node to the I2C device node. If a child node for a clock
 | 
			
		||||
output is not set, the eeprom configuration is not overwritten.
 | 
			
		||||
 | 
			
		||||
Required child node properties:
 | 
			
		||||
- reg: number of clock output.
 | 
			
		||||
 | 
			
		||||
Optional child node properties:
 | 
			
		||||
- silabs,clock-source: source clock of the output divider stage N, shall be
 | 
			
		||||
  0 = multisynth N
 | 
			
		||||
  1 = multisynth 0 for output clocks 0-3, else multisynth4
 | 
			
		||||
  2 = xtal
 | 
			
		||||
  3 = clkin (si5351c only)
 | 
			
		||||
- silabs,drive-strength: output drive strength in mA, shall be one of {2,4,6,8}.
 | 
			
		||||
- silabs,multisynth-source: source pll A(0) or B(1) of corresponding multisynth
 | 
			
		||||
  divider.
 | 
			
		||||
- silabs,pll-master: boolean, multisynth can change pll frequency.
 | 
			
		||||
 | 
			
		||||
==Example==
 | 
			
		||||
 | 
			
		||||
/* 25MHz reference crystal */
 | 
			
		||||
ref25: ref25M {
 | 
			
		||||
	compatible = "fixed-clock";
 | 
			
		||||
	#clock-cells = <0>;
 | 
			
		||||
	clock-frequency = <25000000>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
i2c-master-node {
 | 
			
		||||
 | 
			
		||||
	/* Si5351a msop10 i2c clock generator */
 | 
			
		||||
	si5351a: clock-generator@60 {
 | 
			
		||||
		compatible = "silabs,si5351a-msop";
 | 
			
		||||
		reg = <0x60>;
 | 
			
		||||
		#address-cells = <1>;
 | 
			
		||||
		#size-cells = <0>;
 | 
			
		||||
		#clock-cells = <1>;
 | 
			
		||||
 | 
			
		||||
		/* connect xtal input to 25MHz reference */
 | 
			
		||||
		clocks = <&ref25>;
 | 
			
		||||
 | 
			
		||||
		/* connect xtal input as source of pll0 and pll1 */
 | 
			
		||||
		silabs,pll-source = <0 0>, <1 0>;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * overwrite clkout0 configuration with:
 | 
			
		||||
		 * - 8mA output drive strength
 | 
			
		||||
		 * - pll0 as clock source of multisynth0
 | 
			
		||||
		 * - multisynth0 as clock source of output divider
 | 
			
		||||
		 * - multisynth0 can change pll0
 | 
			
		||||
		 * - set initial clock frequency of 74.25MHz
 | 
			
		||||
		 */
 | 
			
		||||
		clkout0 {
 | 
			
		||||
			reg = <0>;
 | 
			
		||||
			silabs,drive-strength = <8>;
 | 
			
		||||
			silabs,multisynth-source = <0>;
 | 
			
		||||
			silabs,clock-source = <0>;
 | 
			
		||||
			silabs,pll-master;
 | 
			
		||||
			clock-frequency = <74250000>;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * overwrite clkout1 configuration with:
 | 
			
		||||
		 * - 4mA output drive strength
 | 
			
		||||
		 * - pll1 as clock source of multisynth1
 | 
			
		||||
		 * - multisynth1 as clock source of output divider
 | 
			
		||||
		 * - multisynth1 can change pll1
 | 
			
		||||
		 */
 | 
			
		||||
		clkout1 {
 | 
			
		||||
			reg = <1>;
 | 
			
		||||
			silabs,drive-strength = <4>;
 | 
			
		||||
			silabs,multisynth-source = <1>;
 | 
			
		||||
			silabs,clock-source = <0>;
 | 
			
		||||
			pll-master;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * overwrite clkout2 configuration with:
 | 
			
		||||
		 * - xtal as clock source of output divider
 | 
			
		||||
		 */
 | 
			
		||||
		clkout2 {
 | 
			
		||||
			reg = <2>;
 | 
			
		||||
			silabs,clock-source = <2>;
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										151
									
								
								Documentation/devicetree/bindings/clock/sunxi.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								Documentation/devicetree/bindings/clock/sunxi.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,151 @@
 | 
			
		|||
Device Tree Clock bindings for arch-sunxi
 | 
			
		||||
 | 
			
		||||
This binding uses the common clock binding[1].
 | 
			
		||||
 | 
			
		||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
 | 
			
		||||
 | 
			
		||||
Required properties:
 | 
			
		||||
- compatible : shall be one of the following:
 | 
			
		||||
	"allwinner,sun4i-osc-clk" - for a gatable oscillator
 | 
			
		||||
	"allwinner,sun4i-pll1-clk" - for the main PLL clock
 | 
			
		||||
	"allwinner,sun4i-cpu-clk" - for the CPU multiplexer clock
 | 
			
		||||
	"allwinner,sun4i-axi-clk" - for the AXI clock
 | 
			
		||||
	"allwinner,sun4i-axi-gates-clk" - for the AXI gates
 | 
			
		||||
	"allwinner,sun4i-ahb-clk" - for the AHB clock
 | 
			
		||||
	"allwinner,sun4i-ahb-gates-clk" - for the AHB gates
 | 
			
		||||
	"allwinner,sun4i-apb0-clk" - for the APB0 clock
 | 
			
		||||
	"allwinner,sun4i-apb0-gates-clk" - for the APB0 gates
 | 
			
		||||
	"allwinner,sun4i-apb1-clk" - for the APB1 clock
 | 
			
		||||
	"allwinner,sun4i-apb1-mux-clk" - for the APB1 clock muxing
 | 
			
		||||
	"allwinner,sun4i-apb1-gates-clk" - for the APB1 gates
 | 
			
		||||
 | 
			
		||||
Required properties for all clocks:
 | 
			
		||||
- reg : shall be the control register address for the clock.
 | 
			
		||||
- clocks : shall be the input parent clock(s) phandle for the clock
 | 
			
		||||
- #clock-cells : from common clock binding; shall be set to 0 except for
 | 
			
		||||
	"allwinner,sun4i-*-gates-clk" where it shall be set to 1
 | 
			
		||||
 | 
			
		||||
Additionally, "allwinner,sun4i-*-gates-clk" clocks require:
 | 
			
		||||
- clock-output-names : the corresponding gate names that the clock controls
 | 
			
		||||
 | 
			
		||||
For example:
 | 
			
		||||
 | 
			
		||||
osc24M: osc24M@01c20050 {
 | 
			
		||||
	#clock-cells = <0>;
 | 
			
		||||
	compatible = "allwinner,sun4i-osc-clk";
 | 
			
		||||
	reg = <0x01c20050 0x4>;
 | 
			
		||||
	clocks = <&osc24M_fixed>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pll1: pll1@01c20000 {
 | 
			
		||||
	#clock-cells = <0>;
 | 
			
		||||
	compatible = "allwinner,sun4i-pll1-clk";
 | 
			
		||||
	reg = <0x01c20000 0x4>;
 | 
			
		||||
	clocks = <&osc24M>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
cpu: cpu@01c20054 {
 | 
			
		||||
	#clock-cells = <0>;
 | 
			
		||||
	compatible = "allwinner,sun4i-cpu-clk";
 | 
			
		||||
	reg = <0x01c20054 0x4>;
 | 
			
		||||
	clocks = <&osc32k>, <&osc24M>, <&pll1>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Gate clock outputs
 | 
			
		||||
 | 
			
		||||
The "allwinner,sun4i-*-gates-clk" clocks provide several gatable outputs;
 | 
			
		||||
their corresponding offsets as present on sun4i are listed below. Note that
 | 
			
		||||
some of these gates are not present on sun5i.
 | 
			
		||||
 | 
			
		||||
  * AXI gates ("allwinner,sun4i-axi-gates-clk")
 | 
			
		||||
 | 
			
		||||
    DRAM                                                                0
 | 
			
		||||
 | 
			
		||||
  * AHB gates ("allwinner,sun4i-ahb-gates-clk")
 | 
			
		||||
 | 
			
		||||
    USB0                                                                0
 | 
			
		||||
    EHCI0                                                               1
 | 
			
		||||
    OHCI0                                                               2*
 | 
			
		||||
    EHCI1                                                               3
 | 
			
		||||
    OHCI1                                                               4*
 | 
			
		||||
    SS                                                                  5
 | 
			
		||||
    DMA                                                                 6
 | 
			
		||||
    BIST                                                                7
 | 
			
		||||
    MMC0                                                                8
 | 
			
		||||
    MMC1                                                                9
 | 
			
		||||
    MMC2                                                                10
 | 
			
		||||
    MMC3                                                                11
 | 
			
		||||
    MS                                                                  12**
 | 
			
		||||
    NAND                                                                13
 | 
			
		||||
    SDRAM                                                               14
 | 
			
		||||
 | 
			
		||||
    ACE                                                                 16
 | 
			
		||||
    EMAC                                                                17
 | 
			
		||||
    TS                                                                  18
 | 
			
		||||
 | 
			
		||||
    SPI0                                                                20
 | 
			
		||||
    SPI1                                                                21
 | 
			
		||||
    SPI2                                                                22
 | 
			
		||||
    SPI3                                                                23
 | 
			
		||||
    PATA                                                                24
 | 
			
		||||
    SATA                                                                25**
 | 
			
		||||
    GPS                                                                 26*
 | 
			
		||||
 | 
			
		||||
    VE                                                                  32
 | 
			
		||||
    TVD                                                                 33
 | 
			
		||||
    TVE0                                                                34
 | 
			
		||||
    TVE1                                                                35
 | 
			
		||||
    LCD0                                                                36
 | 
			
		||||
    LCD1                                                                37
 | 
			
		||||
 | 
			
		||||
    CSI0                                                                40
 | 
			
		||||
    CSI1                                                                41
 | 
			
		||||
 | 
			
		||||
    HDMI                                                                43
 | 
			
		||||
    DE_BE0                                                              44
 | 
			
		||||
    DE_BE1                                                              45
 | 
			
		||||
    DE_FE0                                                              46
 | 
			
		||||
    DE_FE1                                                              47
 | 
			
		||||
 | 
			
		||||
    MP                                                                  50
 | 
			
		||||
 | 
			
		||||
    MALI400                                                             52
 | 
			
		||||
 | 
			
		||||
  * APB0 gates ("allwinner,sun4i-apb0-gates-clk")
 | 
			
		||||
 | 
			
		||||
    CODEC                                                               0
 | 
			
		||||
    SPDIF                                                               1*
 | 
			
		||||
    AC97                                                                2
 | 
			
		||||
    IIS                                                                 3
 | 
			
		||||
 | 
			
		||||
    PIO                                                                 5
 | 
			
		||||
    IR0                                                                 6
 | 
			
		||||
    IR1                                                                 7
 | 
			
		||||
 | 
			
		||||
    KEYPAD                                                              10
 | 
			
		||||
 | 
			
		||||
  * APB1 gates ("allwinner,sun4i-apb1-gates-clk")
 | 
			
		||||
 | 
			
		||||
    I2C0                                                                0
 | 
			
		||||
    I2C1                                                                1
 | 
			
		||||
    I2C2                                                                2
 | 
			
		||||
 | 
			
		||||
    CAN                                                                 4
 | 
			
		||||
    SCR                                                                 5
 | 
			
		||||
    PS20                                                                6
 | 
			
		||||
    PS21                                                                7
 | 
			
		||||
 | 
			
		||||
    UART0                                                               16
 | 
			
		||||
    UART1                                                               17
 | 
			
		||||
    UART2                                                               18
 | 
			
		||||
    UART3                                                               19
 | 
			
		||||
    UART4                                                               20
 | 
			
		||||
    UART5                                                               21
 | 
			
		||||
    UART6                                                               22
 | 
			
		||||
    UART7                                                               23
 | 
			
		||||
 | 
			
		||||
Notation:
 | 
			
		||||
 [*]:  The datasheet didn't mention these, but they are present on AW code
 | 
			
		||||
 [**]: The datasheet had this marked as "NC" but they are used on AW code
 | 
			
		||||
| 
						 | 
				
			
			@ -49,6 +49,7 @@ samsung	Samsung Semiconductor
 | 
			
		|||
sbs	Smart Battery System
 | 
			
		||||
schindler	Schindler
 | 
			
		||||
sil	Silicon Image
 | 
			
		||||
silabs	Silicon Laboratories
 | 
			
		||||
simtek
 | 
			
		||||
sirf	SiRF Technology, Inc.
 | 
			
		||||
snps 	Synopsys, Inc.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,6 +44,7 @@ parameter is applicable:
 | 
			
		|||
	AVR32	AVR32 architecture is enabled.
 | 
			
		||||
	AX25	Appropriate AX.25 support is enabled.
 | 
			
		||||
	BLACKFIN Blackfin architecture is enabled.
 | 
			
		||||
	CLK	Common clock infrastructure is enabled.
 | 
			
		||||
	DRM	Direct Rendering Management support is enabled.
 | 
			
		||||
	DYNAMIC_DEBUG Build in debug messages and enable them at runtime
 | 
			
		||||
	EDD	BIOS Enhanced Disk Drive Services (EDD) is enabled
 | 
			
		||||
| 
						 | 
				
			
			@ -472,6 +473,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 | 
			
		|||
 | 
			
		||||
	cio_ignore=	[S390]
 | 
			
		||||
			See Documentation/s390/CommonIO for details.
 | 
			
		||||
	clk_ignore_unused
 | 
			
		||||
			[CLK]
 | 
			
		||||
			Keep all clocks already enabled by bootloader on,
 | 
			
		||||
			even if no driver has claimed them. This is useful
 | 
			
		||||
			for debug and development, but should not be
 | 
			
		||||
			needed on a platform with proper driver support.
 | 
			
		||||
			For more information, see Documentation/clk.txt.
 | 
			
		||||
 | 
			
		||||
	clock=		[BUGS=X86-32, HW] gettimeofday clocksource override.
 | 
			
		||||
			[Deprecated]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -169,7 +169,7 @@ struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
 | 
			
		|||
 | 
			
		||||
	busy->mux.reg = reg;
 | 
			
		||||
	busy->mux.shift = shift;
 | 
			
		||||
	busy->mux.width = width;
 | 
			
		||||
	busy->mux.mask = BIT(width) - 1;
 | 
			
		||||
	busy->mux.lock = &imx_ccm_lock;
 | 
			
		||||
	busy->mux_ops = &clk_mux_ops;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,6 +21,8 @@
 | 
			
		|||
#include <linux/regulator/fixed.h>
 | 
			
		||||
#include <linux/regulator/machine.h>
 | 
			
		||||
#include <linux/vexpress.h>
 | 
			
		||||
#include <linux/clk-provider.h>
 | 
			
		||||
#include <linux/clkdev.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/arch_timer.h>
 | 
			
		||||
#include <asm/mach-types.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -433,7 +435,7 @@ static void __init v2m_dt_timer_init(void)
 | 
			
		|||
{
 | 
			
		||||
	struct device_node *node = NULL;
 | 
			
		||||
 | 
			
		||||
	vexpress_clk_of_init();
 | 
			
		||||
	of_clk_init(NULL);
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		node = of_find_compatible_node(node, NULL, "arm,sp804");
 | 
			
		||||
| 
						 | 
				
			
			@ -441,6 +443,10 @@ static void __init v2m_dt_timer_init(void)
 | 
			
		|||
	if (node) {
 | 
			
		||||
		pr_info("Using SP804 '%s' as a clock & events source\n",
 | 
			
		||||
				node->full_name);
 | 
			
		||||
		WARN_ON(clk_register_clkdev(of_clk_get_by_name(node,
 | 
			
		||||
				"timclken1"), "v2m-timer0", "sp804"));
 | 
			
		||||
		WARN_ON(clk_register_clkdev(of_clk_get_by_name(node,
 | 
			
		||||
				"timclken2"), "v2m-timer1", "sp804"));
 | 
			
		||||
		v2m_sp804_init(of_iomap(node, 0),
 | 
			
		||||
				irq_of_parse_and_map(node, 0));
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,6 +55,16 @@ config COMMON_CLK_MAX77686
 | 
			
		|||
	---help---
 | 
			
		||||
	  This driver supports Maxim 77686 crystal oscillator clock. 
 | 
			
		||||
 | 
			
		||||
config COMMON_CLK_SI5351
 | 
			
		||||
	tristate "Clock driver for SiLabs 5351A/B/C"
 | 
			
		||||
	depends on I2C
 | 
			
		||||
	depends on OF
 | 
			
		||||
	select REGMAP_I2C
 | 
			
		||||
	select RATIONAL
 | 
			
		||||
	---help---
 | 
			
		||||
	  This driver supports Silicon Labs 5351A/B/C programmable clock
 | 
			
		||||
	  generators.
 | 
			
		||||
 | 
			
		||||
config CLK_TWL6040
 | 
			
		||||
	tristate "External McPDM functional clock from twl6040"
 | 
			
		||||
	depends on TWL6040_CORE
 | 
			
		||||
| 
						 | 
				
			
			@ -63,6 +73,14 @@ config CLK_TWL6040
 | 
			
		|||
	  McPDM. McPDM module is using the external bit clock on the McPDM bus
 | 
			
		||||
	  as functional clock.
 | 
			
		||||
 | 
			
		||||
config COMMON_CLK_AXI_CLKGEN
 | 
			
		||||
	tristate "AXI clkgen driver"
 | 
			
		||||
	depends on ARCH_ZYNQ || MICROBLAZE
 | 
			
		||||
	help
 | 
			
		||||
	---help---
 | 
			
		||||
	  Support for the Analog Devices axi-clkgen pcore clock generator for Xilinx
 | 
			
		||||
	  FPGAs. It is commonly used in Analog Devices' reference designs.
 | 
			
		||||
 | 
			
		||||
endmenu
 | 
			
		||||
 | 
			
		||||
source "drivers/clk/mvebu/Kconfig"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@ obj-$(CONFIG_COMMON_CLK)	+= clk-fixed-factor.o
 | 
			
		|||
obj-$(CONFIG_COMMON_CLK)	+= clk-fixed-rate.o
 | 
			
		||||
obj-$(CONFIG_COMMON_CLK)	+= clk-gate.o
 | 
			
		||||
obj-$(CONFIG_COMMON_CLK)	+= clk-mux.o
 | 
			
		||||
obj-$(CONFIG_COMMON_CLK)	+= clk-composite.o
 | 
			
		||||
 | 
			
		||||
# SoCs specific
 | 
			
		||||
obj-$(CONFIG_ARCH_BCM2835)	+= clk-bcm2835.o
 | 
			
		||||
| 
						 | 
				
			
			@ -23,6 +24,7 @@ ifeq ($(CONFIG_COMMON_CLK), y)
 | 
			
		|||
obj-$(CONFIG_ARCH_MMP)		+= mmp/
 | 
			
		||||
endif
 | 
			
		||||
obj-$(CONFIG_MACH_LOONGSON1)	+= clk-ls1x.o
 | 
			
		||||
obj-$(CONFIG_ARCH_SUNXI)	+= sunxi/
 | 
			
		||||
obj-$(CONFIG_ARCH_U8500)	+= ux500/
 | 
			
		||||
obj-$(CONFIG_ARCH_VT8500)	+= clk-vt8500.o
 | 
			
		||||
obj-$(CONFIG_ARCH_ZYNQ)		+= clk-zynq.o
 | 
			
		||||
| 
						 | 
				
			
			@ -31,6 +33,8 @@ obj-$(CONFIG_ARCH_TEGRA)	+= tegra/
 | 
			
		|||
obj-$(CONFIG_X86)		+= x86/
 | 
			
		||||
 | 
			
		||||
# Chip specific
 | 
			
		||||
obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
 | 
			
		||||
obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
 | 
			
		||||
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
 | 
			
		||||
obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
 | 
			
		||||
obj-$(CONFIG_CLK_TWL6040)	+= clk-twl6040.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										331
									
								
								drivers/clk/clk-axi-clkgen.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										331
									
								
								drivers/clk/clk-axi-clkgen.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,331 @@
 | 
			
		|||
/*
 | 
			
		||||
 * AXI clkgen driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright 2012-2013 Analog Devices Inc.
 | 
			
		||||
 *  Author: Lars-Peter Clausen <lars@metafoo.de>
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the GPL-2.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/clk-provider.h>
 | 
			
		||||
#include <linux/clk.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/io.h>
 | 
			
		||||
#include <linux/of.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/err.h>
 | 
			
		||||
 | 
			
		||||
#define AXI_CLKGEN_REG_UPDATE_ENABLE	0x04
 | 
			
		||||
#define AXI_CLKGEN_REG_CLK_OUT1		0x08
 | 
			
		||||
#define AXI_CLKGEN_REG_CLK_OUT2		0x0c
 | 
			
		||||
#define AXI_CLKGEN_REG_CLK_DIV		0x10
 | 
			
		||||
#define AXI_CLKGEN_REG_CLK_FB1		0x14
 | 
			
		||||
#define AXI_CLKGEN_REG_CLK_FB2		0x18
 | 
			
		||||
#define AXI_CLKGEN_REG_LOCK1		0x1c
 | 
			
		||||
#define AXI_CLKGEN_REG_LOCK2		0x20
 | 
			
		||||
#define AXI_CLKGEN_REG_LOCK3		0x24
 | 
			
		||||
#define AXI_CLKGEN_REG_FILTER1		0x28
 | 
			
		||||
#define AXI_CLKGEN_REG_FILTER2		0x2c
 | 
			
		||||
 | 
			
		||||
struct axi_clkgen {
 | 
			
		||||
	void __iomem *base;
 | 
			
		||||
	struct clk_hw clk_hw;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static uint32_t axi_clkgen_lookup_filter(unsigned int m)
 | 
			
		||||
{
 | 
			
		||||
	switch (m) {
 | 
			
		||||
	case 0:
 | 
			
		||||
		return 0x01001990;
 | 
			
		||||
	case 1:
 | 
			
		||||
		return 0x01001190;
 | 
			
		||||
	case 2:
 | 
			
		||||
		return 0x01009890;
 | 
			
		||||
	case 3:
 | 
			
		||||
		return 0x01001890;
 | 
			
		||||
	case 4:
 | 
			
		||||
		return 0x01008890;
 | 
			
		||||
	case 5 ... 8:
 | 
			
		||||
		return 0x01009090;
 | 
			
		||||
	case 9 ... 11:
 | 
			
		||||
		return 0x01000890;
 | 
			
		||||
	case 12:
 | 
			
		||||
		return 0x08009090;
 | 
			
		||||
	case 13 ... 22:
 | 
			
		||||
		return 0x01001090;
 | 
			
		||||
	case 23 ... 36:
 | 
			
		||||
		return 0x01008090;
 | 
			
		||||
	case 37 ... 46:
 | 
			
		||||
		return 0x08001090;
 | 
			
		||||
	default:
 | 
			
		||||
		return 0x08008090;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const uint32_t axi_clkgen_lock_table[] = {
 | 
			
		||||
	0x060603e8, 0x060603e8, 0x080803e8, 0x0b0b03e8,
 | 
			
		||||
	0x0e0e03e8, 0x111103e8, 0x131303e8, 0x161603e8,
 | 
			
		||||
	0x191903e8, 0x1c1c03e8, 0x1f1f0384, 0x1f1f0339,
 | 
			
		||||
	0x1f1f02ee, 0x1f1f02bc, 0x1f1f028a, 0x1f1f0271,
 | 
			
		||||
	0x1f1f023f, 0x1f1f0226, 0x1f1f020d, 0x1f1f01f4,
 | 
			
		||||
	0x1f1f01db, 0x1f1f01c2, 0x1f1f01a9, 0x1f1f0190,
 | 
			
		||||
	0x1f1f0190, 0x1f1f0177, 0x1f1f015e, 0x1f1f015e,
 | 
			
		||||
	0x1f1f0145, 0x1f1f0145, 0x1f1f012c, 0x1f1f012c,
 | 
			
		||||
	0x1f1f012c, 0x1f1f0113, 0x1f1f0113, 0x1f1f0113,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static uint32_t axi_clkgen_lookup_lock(unsigned int m)
 | 
			
		||||
{
 | 
			
		||||
	if (m < ARRAY_SIZE(axi_clkgen_lock_table))
 | 
			
		||||
		return axi_clkgen_lock_table[m];
 | 
			
		||||
	return 0x1f1f00fa;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const unsigned int fpfd_min = 10000;
 | 
			
		||||
static const unsigned int fpfd_max = 300000;
 | 
			
		||||
static const unsigned int fvco_min = 600000;
 | 
			
		||||
static const unsigned int fvco_max = 1200000;
 | 
			
		||||
 | 
			
		||||
static void axi_clkgen_calc_params(unsigned long fin, unsigned long fout,
 | 
			
		||||
	unsigned int *best_d, unsigned int *best_m, unsigned int *best_dout)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long d, d_min, d_max, _d_min, _d_max;
 | 
			
		||||
	unsigned long m, m_min, m_max;
 | 
			
		||||
	unsigned long f, dout, best_f, fvco;
 | 
			
		||||
 | 
			
		||||
	fin /= 1000;
 | 
			
		||||
	fout /= 1000;
 | 
			
		||||
 | 
			
		||||
	best_f = ULONG_MAX;
 | 
			
		||||
	*best_d = 0;
 | 
			
		||||
	*best_m = 0;
 | 
			
		||||
	*best_dout = 0;
 | 
			
		||||
 | 
			
		||||
	d_min = max_t(unsigned long, DIV_ROUND_UP(fin, fpfd_max), 1);
 | 
			
		||||
	d_max = min_t(unsigned long, fin / fpfd_min, 80);
 | 
			
		||||
 | 
			
		||||
	m_min = max_t(unsigned long, DIV_ROUND_UP(fvco_min, fin) * d_min, 1);
 | 
			
		||||
	m_max = min_t(unsigned long, fvco_max * d_max / fin, 64);
 | 
			
		||||
 | 
			
		||||
	for (m = m_min; m <= m_max; m++) {
 | 
			
		||||
		_d_min = max(d_min, DIV_ROUND_UP(fin * m, fvco_max));
 | 
			
		||||
		_d_max = min(d_max, fin * m / fvco_min);
 | 
			
		||||
 | 
			
		||||
		for (d = _d_min; d <= _d_max; d++) {
 | 
			
		||||
			fvco = fin * m / d;
 | 
			
		||||
 | 
			
		||||
			dout = DIV_ROUND_CLOSEST(fvco, fout);
 | 
			
		||||
			dout = clamp_t(unsigned long, dout, 1, 128);
 | 
			
		||||
			f = fvco / dout;
 | 
			
		||||
			if (abs(f - fout) < abs(best_f - fout)) {
 | 
			
		||||
				best_f = f;
 | 
			
		||||
				*best_d = d;
 | 
			
		||||
				*best_m = m;
 | 
			
		||||
				*best_dout = dout;
 | 
			
		||||
				if (best_f == fout)
 | 
			
		||||
					return;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void axi_clkgen_calc_clk_params(unsigned int divider, unsigned int *low,
 | 
			
		||||
	unsigned int *high, unsigned int *edge, unsigned int *nocount)
 | 
			
		||||
{
 | 
			
		||||
	if (divider == 1)
 | 
			
		||||
		*nocount = 1;
 | 
			
		||||
	else
 | 
			
		||||
		*nocount = 0;
 | 
			
		||||
 | 
			
		||||
	*high = divider / 2;
 | 
			
		||||
	*edge = divider % 2;
 | 
			
		||||
	*low = divider - *high;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void axi_clkgen_write(struct axi_clkgen *axi_clkgen,
 | 
			
		||||
	unsigned int reg, unsigned int val)
 | 
			
		||||
{
 | 
			
		||||
	writel(val, axi_clkgen->base + reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void axi_clkgen_read(struct axi_clkgen *axi_clkgen,
 | 
			
		||||
	unsigned int reg, unsigned int *val)
 | 
			
		||||
{
 | 
			
		||||
	*val = readl(axi_clkgen->base + reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct axi_clkgen *clk_hw_to_axi_clkgen(struct clk_hw *clk_hw)
 | 
			
		||||
{
 | 
			
		||||
	return container_of(clk_hw, struct axi_clkgen, clk_hw);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int axi_clkgen_set_rate(struct clk_hw *clk_hw,
 | 
			
		||||
	unsigned long rate, unsigned long parent_rate)
 | 
			
		||||
{
 | 
			
		||||
	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
 | 
			
		||||
	unsigned int d, m, dout;
 | 
			
		||||
	unsigned int nocount;
 | 
			
		||||
	unsigned int high;
 | 
			
		||||
	unsigned int edge;
 | 
			
		||||
	unsigned int low;
 | 
			
		||||
	uint32_t filter;
 | 
			
		||||
	uint32_t lock;
 | 
			
		||||
 | 
			
		||||
	if (parent_rate == 0 || rate == 0)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	axi_clkgen_calc_params(parent_rate, rate, &d, &m, &dout);
 | 
			
		||||
 | 
			
		||||
	if (d == 0 || dout == 0 || m == 0)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	filter = axi_clkgen_lookup_filter(m - 1);
 | 
			
		||||
	lock = axi_clkgen_lookup_lock(m - 1);
 | 
			
		||||
 | 
			
		||||
	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_UPDATE_ENABLE, 0);
 | 
			
		||||
 | 
			
		||||
	axi_clkgen_calc_clk_params(dout, &low, &high, &edge, &nocount);
 | 
			
		||||
	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT1,
 | 
			
		||||
		(high << 6) | low);
 | 
			
		||||
	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT2,
 | 
			
		||||
		(edge << 7) | (nocount << 6));
 | 
			
		||||
 | 
			
		||||
	axi_clkgen_calc_clk_params(d, &low, &high, &edge, &nocount);
 | 
			
		||||
	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_DIV,
 | 
			
		||||
		(edge << 13) | (nocount << 12) | (high << 6) | low);
 | 
			
		||||
 | 
			
		||||
	axi_clkgen_calc_clk_params(m, &low, &high, &edge, &nocount);
 | 
			
		||||
	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_FB1,
 | 
			
		||||
		(high << 6) | low);
 | 
			
		||||
	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_FB2,
 | 
			
		||||
		(edge << 7) | (nocount << 6));
 | 
			
		||||
 | 
			
		||||
	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK1, lock & 0x3ff);
 | 
			
		||||
	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK2,
 | 
			
		||||
		(((lock >> 16) & 0x1f) << 10) | 0x1);
 | 
			
		||||
	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK3,
 | 
			
		||||
		(((lock >> 24) & 0x1f) << 10) | 0x3e9);
 | 
			
		||||
	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_FILTER1, filter >> 16);
 | 
			
		||||
	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_FILTER2, filter);
 | 
			
		||||
 | 
			
		||||
	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_UPDATE_ENABLE, 1);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static long axi_clkgen_round_rate(struct clk_hw *hw, unsigned long rate,
 | 
			
		||||
	unsigned long *parent_rate)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int d, m, dout;
 | 
			
		||||
 | 
			
		||||
	axi_clkgen_calc_params(*parent_rate, rate, &d, &m, &dout);
 | 
			
		||||
 | 
			
		||||
	if (d == 0 || dout == 0 || m == 0)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	return *parent_rate / d * m / dout;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw,
 | 
			
		||||
	unsigned long parent_rate)
 | 
			
		||||
{
 | 
			
		||||
	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
 | 
			
		||||
	unsigned int d, m, dout;
 | 
			
		||||
	unsigned int reg;
 | 
			
		||||
	unsigned long long tmp;
 | 
			
		||||
 | 
			
		||||
	axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT1, ®);
 | 
			
		||||
	dout = (reg & 0x3f) + ((reg >> 6) & 0x3f);
 | 
			
		||||
	axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_DIV, ®);
 | 
			
		||||
	d = (reg & 0x3f) + ((reg >> 6) & 0x3f);
 | 
			
		||||
	axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_FB1, ®);
 | 
			
		||||
	m = (reg & 0x3f) + ((reg >> 6) & 0x3f);
 | 
			
		||||
 | 
			
		||||
	if (d == 0 || dout == 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	tmp = (unsigned long long)(parent_rate / d) * m;
 | 
			
		||||
	do_div(tmp, dout);
 | 
			
		||||
 | 
			
		||||
	if (tmp > ULONG_MAX)
 | 
			
		||||
		return ULONG_MAX;
 | 
			
		||||
 | 
			
		||||
	return tmp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct clk_ops axi_clkgen_ops = {
 | 
			
		||||
	.recalc_rate = axi_clkgen_recalc_rate,
 | 
			
		||||
	.round_rate = axi_clkgen_round_rate,
 | 
			
		||||
	.set_rate = axi_clkgen_set_rate,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int axi_clkgen_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct axi_clkgen *axi_clkgen;
 | 
			
		||||
	struct clk_init_data init;
 | 
			
		||||
	const char *parent_name;
 | 
			
		||||
	const char *clk_name;
 | 
			
		||||
	struct resource *mem;
 | 
			
		||||
	struct clk *clk;
 | 
			
		||||
 | 
			
		||||
	axi_clkgen = devm_kzalloc(&pdev->dev, sizeof(*axi_clkgen), GFP_KERNEL);
 | 
			
		||||
	if (!axi_clkgen)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | 
			
		||||
	axi_clkgen->base = devm_ioremap_resource(&pdev->dev, mem);
 | 
			
		||||
	if (IS_ERR(axi_clkgen->base))
 | 
			
		||||
		return PTR_ERR(axi_clkgen->base);
 | 
			
		||||
 | 
			
		||||
	parent_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
 | 
			
		||||
	if (!parent_name)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	clk_name = pdev->dev.of_node->name;
 | 
			
		||||
	of_property_read_string(pdev->dev.of_node, "clock-output-names",
 | 
			
		||||
		&clk_name);
 | 
			
		||||
 | 
			
		||||
	init.name = clk_name;
 | 
			
		||||
	init.ops = &axi_clkgen_ops;
 | 
			
		||||
	init.flags = 0;
 | 
			
		||||
	init.parent_names = &parent_name;
 | 
			
		||||
	init.num_parents = 1;
 | 
			
		||||
 | 
			
		||||
	axi_clkgen->clk_hw.init = &init;
 | 
			
		||||
	clk = devm_clk_register(&pdev->dev, &axi_clkgen->clk_hw);
 | 
			
		||||
	if (IS_ERR(clk))
 | 
			
		||||
		return PTR_ERR(clk);
 | 
			
		||||
 | 
			
		||||
	return of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get,
 | 
			
		||||
				    clk);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int axi_clkgen_remove(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	of_clk_del_provider(pdev->dev.of_node);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct of_device_id axi_clkgen_ids[] = {
 | 
			
		||||
	{ .compatible = "adi,axi-clkgen-1.00.a" },
 | 
			
		||||
	{ },
 | 
			
		||||
};
 | 
			
		||||
MODULE_DEVICE_TABLE(of, axi_clkgen_ids);
 | 
			
		||||
 | 
			
		||||
static struct platform_driver axi_clkgen_driver = {
 | 
			
		||||
	.driver = {
 | 
			
		||||
		.name = "adi-axi-clkgen",
 | 
			
		||||
		.owner = THIS_MODULE,
 | 
			
		||||
		.of_match_table = axi_clkgen_ids,
 | 
			
		||||
	},
 | 
			
		||||
	.probe = axi_clkgen_probe,
 | 
			
		||||
	.remove = axi_clkgen_remove,
 | 
			
		||||
};
 | 
			
		||||
module_platform_driver(axi_clkgen_driver);
 | 
			
		||||
 | 
			
		||||
MODULE_LICENSE("GPL v2");
 | 
			
		||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 | 
			
		||||
MODULE_DESCRIPTION("Driver for the Analog Devices' AXI clkgen pcore clock generator");
 | 
			
		||||
							
								
								
									
										210
									
								
								drivers/clk/clk-composite.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								drivers/clk/clk-composite.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,210 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2013 NVIDIA CORPORATION.  All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify it
 | 
			
		||||
 * under the terms and conditions of the GNU General Public License,
 | 
			
		||||
 * version 2, as published by the Free Software Foundation.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope it will be useful, but WITHOUT
 | 
			
		||||
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 | 
			
		||||
 * more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/clk.h>
 | 
			
		||||
#include <linux/clk-provider.h>
 | 
			
		||||
#include <linux/err.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
 | 
			
		||||
#define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw)
 | 
			
		||||
 | 
			
		||||
static u8 clk_composite_get_parent(struct clk_hw *hw)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_composite *composite = to_clk_composite(hw);
 | 
			
		||||
	const struct clk_ops *mux_ops = composite->mux_ops;
 | 
			
		||||
	struct clk_hw *mux_hw = composite->mux_hw;
 | 
			
		||||
 | 
			
		||||
	mux_hw->clk = hw->clk;
 | 
			
		||||
 | 
			
		||||
	return mux_ops->get_parent(mux_hw);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int clk_composite_set_parent(struct clk_hw *hw, u8 index)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_composite *composite = to_clk_composite(hw);
 | 
			
		||||
	const struct clk_ops *mux_ops = composite->mux_ops;
 | 
			
		||||
	struct clk_hw *mux_hw = composite->mux_hw;
 | 
			
		||||
 | 
			
		||||
	mux_hw->clk = hw->clk;
 | 
			
		||||
 | 
			
		||||
	return mux_ops->set_parent(mux_hw, index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned long clk_composite_recalc_rate(struct clk_hw *hw,
 | 
			
		||||
					    unsigned long parent_rate)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_composite *composite = to_clk_composite(hw);
 | 
			
		||||
	const struct clk_ops *rate_ops = composite->rate_ops;
 | 
			
		||||
	struct clk_hw *rate_hw = composite->rate_hw;
 | 
			
		||||
 | 
			
		||||
	rate_hw->clk = hw->clk;
 | 
			
		||||
 | 
			
		||||
	return rate_ops->recalc_rate(rate_hw, parent_rate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static long clk_composite_round_rate(struct clk_hw *hw, unsigned long rate,
 | 
			
		||||
				  unsigned long *prate)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_composite *composite = to_clk_composite(hw);
 | 
			
		||||
	const struct clk_ops *rate_ops = composite->rate_ops;
 | 
			
		||||
	struct clk_hw *rate_hw = composite->rate_hw;
 | 
			
		||||
 | 
			
		||||
	rate_hw->clk = hw->clk;
 | 
			
		||||
 | 
			
		||||
	return rate_ops->round_rate(rate_hw, rate, prate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int clk_composite_set_rate(struct clk_hw *hw, unsigned long rate,
 | 
			
		||||
			       unsigned long parent_rate)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_composite *composite = to_clk_composite(hw);
 | 
			
		||||
	const struct clk_ops *rate_ops = composite->rate_ops;
 | 
			
		||||
	struct clk_hw *rate_hw = composite->rate_hw;
 | 
			
		||||
 | 
			
		||||
	rate_hw->clk = hw->clk;
 | 
			
		||||
 | 
			
		||||
	return rate_ops->set_rate(rate_hw, rate, parent_rate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int clk_composite_is_enabled(struct clk_hw *hw)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_composite *composite = to_clk_composite(hw);
 | 
			
		||||
	const struct clk_ops *gate_ops = composite->gate_ops;
 | 
			
		||||
	struct clk_hw *gate_hw = composite->gate_hw;
 | 
			
		||||
 | 
			
		||||
	gate_hw->clk = hw->clk;
 | 
			
		||||
 | 
			
		||||
	return gate_ops->is_enabled(gate_hw);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int clk_composite_enable(struct clk_hw *hw)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_composite *composite = to_clk_composite(hw);
 | 
			
		||||
	const struct clk_ops *gate_ops = composite->gate_ops;
 | 
			
		||||
	struct clk_hw *gate_hw = composite->gate_hw;
 | 
			
		||||
 | 
			
		||||
	gate_hw->clk = hw->clk;
 | 
			
		||||
 | 
			
		||||
	return gate_ops->enable(gate_hw);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void clk_composite_disable(struct clk_hw *hw)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_composite *composite = to_clk_composite(hw);
 | 
			
		||||
	const struct clk_ops *gate_ops = composite->gate_ops;
 | 
			
		||||
	struct clk_hw *gate_hw = composite->gate_hw;
 | 
			
		||||
 | 
			
		||||
	gate_hw->clk = hw->clk;
 | 
			
		||||
 | 
			
		||||
	gate_ops->disable(gate_hw);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct clk *clk_register_composite(struct device *dev, const char *name,
 | 
			
		||||
			const char **parent_names, int num_parents,
 | 
			
		||||
			struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
 | 
			
		||||
			struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
 | 
			
		||||
			struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
 | 
			
		||||
			unsigned long flags)
 | 
			
		||||
{
 | 
			
		||||
	struct clk *clk;
 | 
			
		||||
	struct clk_init_data init;
 | 
			
		||||
	struct clk_composite *composite;
 | 
			
		||||
	struct clk_ops *clk_composite_ops;
 | 
			
		||||
 | 
			
		||||
	composite = kzalloc(sizeof(*composite), GFP_KERNEL);
 | 
			
		||||
	if (!composite) {
 | 
			
		||||
		pr_err("%s: could not allocate composite clk\n", __func__);
 | 
			
		||||
		return ERR_PTR(-ENOMEM);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	init.name = name;
 | 
			
		||||
	init.flags = flags | CLK_IS_BASIC;
 | 
			
		||||
	init.parent_names = parent_names;
 | 
			
		||||
	init.num_parents = num_parents;
 | 
			
		||||
 | 
			
		||||
	clk_composite_ops = &composite->ops;
 | 
			
		||||
 | 
			
		||||
	if (mux_hw && mux_ops) {
 | 
			
		||||
		if (!mux_ops->get_parent || !mux_ops->set_parent) {
 | 
			
		||||
			clk = ERR_PTR(-EINVAL);
 | 
			
		||||
			goto err;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		composite->mux_hw = mux_hw;
 | 
			
		||||
		composite->mux_ops = mux_ops;
 | 
			
		||||
		clk_composite_ops->get_parent = clk_composite_get_parent;
 | 
			
		||||
		clk_composite_ops->set_parent = clk_composite_set_parent;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (rate_hw && rate_ops) {
 | 
			
		||||
		if (!rate_ops->recalc_rate) {
 | 
			
		||||
			clk = ERR_PTR(-EINVAL);
 | 
			
		||||
			goto err;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* .round_rate is a prerequisite for .set_rate */
 | 
			
		||||
		if (rate_ops->round_rate) {
 | 
			
		||||
			clk_composite_ops->round_rate = clk_composite_round_rate;
 | 
			
		||||
			if (rate_ops->set_rate) {
 | 
			
		||||
				clk_composite_ops->set_rate = clk_composite_set_rate;
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			WARN(rate_ops->set_rate,
 | 
			
		||||
				"%s: missing round_rate op is required\n",
 | 
			
		||||
				__func__);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		composite->rate_hw = rate_hw;
 | 
			
		||||
		composite->rate_ops = rate_ops;
 | 
			
		||||
		clk_composite_ops->recalc_rate = clk_composite_recalc_rate;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (gate_hw && gate_ops) {
 | 
			
		||||
		if (!gate_ops->is_enabled || !gate_ops->enable ||
 | 
			
		||||
		    !gate_ops->disable) {
 | 
			
		||||
			clk = ERR_PTR(-EINVAL);
 | 
			
		||||
			goto err;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		composite->gate_hw = gate_hw;
 | 
			
		||||
		composite->gate_ops = gate_ops;
 | 
			
		||||
		clk_composite_ops->is_enabled = clk_composite_is_enabled;
 | 
			
		||||
		clk_composite_ops->enable = clk_composite_enable;
 | 
			
		||||
		clk_composite_ops->disable = clk_composite_disable;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	init.ops = clk_composite_ops;
 | 
			
		||||
	composite->hw.init = &init;
 | 
			
		||||
 | 
			
		||||
	clk = clk_register(dev, &composite->hw);
 | 
			
		||||
	if (IS_ERR(clk))
 | 
			
		||||
		goto err;
 | 
			
		||||
 | 
			
		||||
	if (composite->mux_hw)
 | 
			
		||||
		composite->mux_hw->clk = clk;
 | 
			
		||||
 | 
			
		||||
	if (composite->rate_hw)
 | 
			
		||||
		composite->rate_hw->clk = clk;
 | 
			
		||||
 | 
			
		||||
	if (composite->gate_hw)
 | 
			
		||||
		composite->gate_hw->clk = clk;
 | 
			
		||||
 | 
			
		||||
	return clk;
 | 
			
		||||
 | 
			
		||||
err:
 | 
			
		||||
	kfree(composite);
 | 
			
		||||
	return clk;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -109,8 +109,9 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
 | 
			
		|||
 | 
			
		||||
	div = _get_div(divider, val);
 | 
			
		||||
	if (!div) {
 | 
			
		||||
		WARN(1, "%s: Invalid divisor for clock %s\n", __func__,
 | 
			
		||||
						__clk_get_name(hw->clk));
 | 
			
		||||
		WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO),
 | 
			
		||||
			"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
 | 
			
		||||
			__clk_get_name(hw->clk));
 | 
			
		||||
		return parent_rate;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,7 @@
 | 
			
		|||
#include <linux/clk-provider.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/err.h>
 | 
			
		||||
#include <linux/of.h>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * DOC: basic fixed multiplier and divider clock that cannot gate
 | 
			
		||||
| 
						 | 
				
			
			@ -96,3 +97,38 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
 | 
			
		|||
 | 
			
		||||
	return clk;
 | 
			
		||||
}
 | 
			
		||||
#ifdef CONFIG_OF
 | 
			
		||||
/**
 | 
			
		||||
 * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock
 | 
			
		||||
 */
 | 
			
		||||
void __init of_fixed_factor_clk_setup(struct device_node *node)
 | 
			
		||||
{
 | 
			
		||||
	struct clk *clk;
 | 
			
		||||
	const char *clk_name = node->name;
 | 
			
		||||
	const char *parent_name;
 | 
			
		||||
	u32 div, mult;
 | 
			
		||||
 | 
			
		||||
	if (of_property_read_u32(node, "clock-div", &div)) {
 | 
			
		||||
		pr_err("%s Fixed factor clock <%s> must have a clock-div property\n",
 | 
			
		||||
			__func__, node->name);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (of_property_read_u32(node, "clock-mult", &mult)) {
 | 
			
		||||
		pr_err("%s Fixed factor clock <%s> must have a clokc-mult property\n",
 | 
			
		||||
			__func__, node->name);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	of_property_read_string(node, "clock-output-names", &clk_name);
 | 
			
		||||
	parent_name = of_clk_get_parent_name(node, 0);
 | 
			
		||||
 | 
			
		||||
	clk = clk_register_fixed_factor(NULL, clk_name, parent_name, 0,
 | 
			
		||||
					mult, div);
 | 
			
		||||
	if (!IS_ERR(clk))
 | 
			
		||||
		of_clk_add_provider(node, of_clk_src_simple_get, clk);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(of_fixed_factor_clk_setup);
 | 
			
		||||
CLK_OF_DECLARE(fixed_factor_clk, "fixed-factor-clock",
 | 
			
		||||
		of_fixed_factor_clk_setup);
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,6 +32,7 @@
 | 
			
		|||
static u8 clk_mux_get_parent(struct clk_hw *hw)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_mux *mux = to_clk_mux(hw);
 | 
			
		||||
	int num_parents = __clk_get_num_parents(hw->clk);
 | 
			
		||||
	u32 val;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			@ -42,7 +43,16 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
 | 
			
		|||
	 * val = 0x4 really means "bit 2, index starts at bit 0"
 | 
			
		||||
	 */
 | 
			
		||||
	val = readl(mux->reg) >> mux->shift;
 | 
			
		||||
	val &= (1 << mux->width) - 1;
 | 
			
		||||
	val &= mux->mask;
 | 
			
		||||
 | 
			
		||||
	if (mux->table) {
 | 
			
		||||
		int i;
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < num_parents; i++)
 | 
			
		||||
			if (mux->table[i] == val)
 | 
			
		||||
				return i;
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (val && (mux->flags & CLK_MUX_INDEX_BIT))
 | 
			
		||||
		val = ffs(val) - 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +60,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
 | 
			
		|||
	if (val && (mux->flags & CLK_MUX_INDEX_ONE))
 | 
			
		||||
		val--;
 | 
			
		||||
 | 
			
		||||
	if (val >= __clk_get_num_parents(hw->clk))
 | 
			
		||||
	if (val >= num_parents)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	return val;
 | 
			
		||||
| 
						 | 
				
			
			@ -62,17 +72,22 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
 | 
			
		|||
	u32 val;
 | 
			
		||||
	unsigned long flags = 0;
 | 
			
		||||
 | 
			
		||||
	if (mux->flags & CLK_MUX_INDEX_BIT)
 | 
			
		||||
		index = (1 << ffs(index));
 | 
			
		||||
	if (mux->table)
 | 
			
		||||
		index = mux->table[index];
 | 
			
		||||
 | 
			
		||||
	if (mux->flags & CLK_MUX_INDEX_ONE)
 | 
			
		||||
		index++;
 | 
			
		||||
	else {
 | 
			
		||||
		if (mux->flags & CLK_MUX_INDEX_BIT)
 | 
			
		||||
			index = (1 << ffs(index));
 | 
			
		||||
 | 
			
		||||
		if (mux->flags & CLK_MUX_INDEX_ONE)
 | 
			
		||||
			index++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mux->lock)
 | 
			
		||||
		spin_lock_irqsave(mux->lock, flags);
 | 
			
		||||
 | 
			
		||||
	val = readl(mux->reg);
 | 
			
		||||
	val &= ~(((1 << mux->width) - 1) << mux->shift);
 | 
			
		||||
	val &= ~(mux->mask << mux->shift);
 | 
			
		||||
	val |= index << mux->shift;
 | 
			
		||||
	writel(val, mux->reg);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -88,10 +103,10 @@ const struct clk_ops clk_mux_ops = {
 | 
			
		|||
};
 | 
			
		||||
EXPORT_SYMBOL_GPL(clk_mux_ops);
 | 
			
		||||
 | 
			
		||||
struct clk *clk_register_mux(struct device *dev, const char *name,
 | 
			
		||||
struct clk *clk_register_mux_table(struct device *dev, const char *name,
 | 
			
		||||
		const char **parent_names, u8 num_parents, unsigned long flags,
 | 
			
		||||
		void __iomem *reg, u8 shift, u8 width,
 | 
			
		||||
		u8 clk_mux_flags, spinlock_t *lock)
 | 
			
		||||
		void __iomem *reg, u8 shift, u32 mask,
 | 
			
		||||
		u8 clk_mux_flags, u32 *table, spinlock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_mux *mux;
 | 
			
		||||
	struct clk *clk;
 | 
			
		||||
| 
						 | 
				
			
			@ -113,9 +128,10 @@ struct clk *clk_register_mux(struct device *dev, const char *name,
 | 
			
		|||
	/* struct clk_mux assignments */
 | 
			
		||||
	mux->reg = reg;
 | 
			
		||||
	mux->shift = shift;
 | 
			
		||||
	mux->width = width;
 | 
			
		||||
	mux->mask = mask;
 | 
			
		||||
	mux->flags = clk_mux_flags;
 | 
			
		||||
	mux->lock = lock;
 | 
			
		||||
	mux->table = table;
 | 
			
		||||
	mux->hw.init = &init;
 | 
			
		||||
 | 
			
		||||
	clk = clk_register(dev, &mux->hw);
 | 
			
		||||
| 
						 | 
				
			
			@ -125,3 +141,15 @@ struct clk *clk_register_mux(struct device *dev, const char *name,
 | 
			
		|||
 | 
			
		||||
	return clk;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct clk *clk_register_mux(struct device *dev, const char *name,
 | 
			
		||||
		const char **parent_names, u8 num_parents, unsigned long flags,
 | 
			
		||||
		void __iomem *reg, u8 shift, u8 width,
 | 
			
		||||
		u8 clk_mux_flags, spinlock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
	u32 mask = BIT(width) - 1;
 | 
			
		||||
 | 
			
		||||
	return clk_register_mux_table(dev, name, parent_names, num_parents,
 | 
			
		||||
				      flags, reg, shift, mask, clk_mux_flags,
 | 
			
		||||
				      NULL, lock);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1113,7 +1113,7 @@ void __init sirfsoc_of_clk_init(void)
 | 
			
		|||
 | 
			
		||||
	for (i = pll1; i < maxclk; i++) {
 | 
			
		||||
		prima2_clks[i] = clk_register(NULL, prima2_clk_hw_array[i]);
 | 
			
		||||
		BUG_ON(!prima2_clks[i]);
 | 
			
		||||
		BUG_ON(IS_ERR(prima2_clks[i]));
 | 
			
		||||
	}
 | 
			
		||||
	clk_register_clkdev(prima2_clks[cpu], NULL, "cpu");
 | 
			
		||||
	clk_register_clkdev(prima2_clks[io],  NULL, "io");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1510
									
								
								drivers/clk/clk-si5351.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1510
									
								
								drivers/clk/clk-si5351.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										155
									
								
								drivers/clk/clk-si5351.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								drivers/clk/clk-si5351.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,155 @@
 | 
			
		|||
/*
 | 
			
		||||
 * clk-si5351.h: Silicon Laboratories Si5351A/B/C I2C Clock Generator
 | 
			
		||||
 *
 | 
			
		||||
 * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
 | 
			
		||||
 * Rabeeh Khoury <rabeeh@solid-run.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute  it and/or modify it
 | 
			
		||||
 * under  the terms of  the GNU General  Public License as published by the
 | 
			
		||||
 * Free Software Foundation;  either version 2 of the  License, or (at your
 | 
			
		||||
 * option) any later version.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _CLK_SI5351_H_
 | 
			
		||||
#define _CLK_SI5351_H_
 | 
			
		||||
 | 
			
		||||
#define SI5351_BUS_BASE_ADDR			0x60
 | 
			
		||||
 | 
			
		||||
#define SI5351_PLL_VCO_MIN			600000000
 | 
			
		||||
#define SI5351_PLL_VCO_MAX			900000000
 | 
			
		||||
#define SI5351_MULTISYNTH_MIN_FREQ		1000000
 | 
			
		||||
#define SI5351_MULTISYNTH_DIVBY4_FREQ		150000000
 | 
			
		||||
#define SI5351_MULTISYNTH_MAX_FREQ		160000000
 | 
			
		||||
#define SI5351_MULTISYNTH67_MAX_FREQ		SI5351_MULTISYNTH_DIVBY4_FREQ
 | 
			
		||||
#define SI5351_CLKOUT_MIN_FREQ			8000
 | 
			
		||||
#define SI5351_CLKOUT_MAX_FREQ			SI5351_MULTISYNTH_MAX_FREQ
 | 
			
		||||
#define SI5351_CLKOUT67_MAX_FREQ		SI5351_MULTISYNTH67_MAX_FREQ
 | 
			
		||||
 | 
			
		||||
#define SI5351_PLL_A_MIN			15
 | 
			
		||||
#define SI5351_PLL_A_MAX			90
 | 
			
		||||
#define SI5351_PLL_B_MAX			(SI5351_PLL_C_MAX-1)
 | 
			
		||||
#define SI5351_PLL_C_MAX			1048575
 | 
			
		||||
#define SI5351_MULTISYNTH_A_MIN			6
 | 
			
		||||
#define SI5351_MULTISYNTH_A_MAX			1800
 | 
			
		||||
#define SI5351_MULTISYNTH67_A_MAX		254
 | 
			
		||||
#define SI5351_MULTISYNTH_B_MAX			(SI5351_MULTISYNTH_C_MAX-1)
 | 
			
		||||
#define SI5351_MULTISYNTH_C_MAX			1048575
 | 
			
		||||
#define SI5351_MULTISYNTH_P1_MAX		((1<<18)-1)
 | 
			
		||||
#define SI5351_MULTISYNTH_P2_MAX		((1<<20)-1)
 | 
			
		||||
#define SI5351_MULTISYNTH_P3_MAX		((1<<20)-1)
 | 
			
		||||
 | 
			
		||||
#define SI5351_DEVICE_STATUS			0
 | 
			
		||||
#define SI5351_INTERRUPT_STATUS			1
 | 
			
		||||
#define SI5351_INTERRUPT_MASK			2
 | 
			
		||||
#define  SI5351_STATUS_SYS_INIT			(1<<7)
 | 
			
		||||
#define  SI5351_STATUS_LOL_B			(1<<6)
 | 
			
		||||
#define  SI5351_STATUS_LOL_A			(1<<5)
 | 
			
		||||
#define  SI5351_STATUS_LOS			(1<<4)
 | 
			
		||||
#define SI5351_OUTPUT_ENABLE_CTRL		3
 | 
			
		||||
#define SI5351_OEB_PIN_ENABLE_CTRL		9
 | 
			
		||||
#define SI5351_PLL_INPUT_SOURCE			15
 | 
			
		||||
#define  SI5351_CLKIN_DIV_MASK			(3<<6)
 | 
			
		||||
#define  SI5351_CLKIN_DIV_1			(0<<6)
 | 
			
		||||
#define  SI5351_CLKIN_DIV_2			(1<<6)
 | 
			
		||||
#define  SI5351_CLKIN_DIV_4			(2<<6)
 | 
			
		||||
#define  SI5351_CLKIN_DIV_8			(3<<6)
 | 
			
		||||
#define  SI5351_PLLB_SOURCE			(1<<3)
 | 
			
		||||
#define  SI5351_PLLA_SOURCE			(1<<2)
 | 
			
		||||
 | 
			
		||||
#define SI5351_CLK0_CTRL			16
 | 
			
		||||
#define SI5351_CLK1_CTRL			17
 | 
			
		||||
#define SI5351_CLK2_CTRL			18
 | 
			
		||||
#define SI5351_CLK3_CTRL			19
 | 
			
		||||
#define SI5351_CLK4_CTRL			20
 | 
			
		||||
#define SI5351_CLK5_CTRL			21
 | 
			
		||||
#define SI5351_CLK6_CTRL			22
 | 
			
		||||
#define SI5351_CLK7_CTRL			23
 | 
			
		||||
#define  SI5351_CLK_POWERDOWN			(1<<7)
 | 
			
		||||
#define  SI5351_CLK_INTEGER_MODE		(1<<6)
 | 
			
		||||
#define  SI5351_CLK_PLL_SELECT			(1<<5)
 | 
			
		||||
#define  SI5351_CLK_INVERT			(1<<4)
 | 
			
		||||
#define  SI5351_CLK_INPUT_MASK			(3<<2)
 | 
			
		||||
#define  SI5351_CLK_INPUT_XTAL			(0<<2)
 | 
			
		||||
#define  SI5351_CLK_INPUT_CLKIN			(1<<2)
 | 
			
		||||
#define  SI5351_CLK_INPUT_MULTISYNTH_0_4	(2<<2)
 | 
			
		||||
#define  SI5351_CLK_INPUT_MULTISYNTH_N		(3<<2)
 | 
			
		||||
#define  SI5351_CLK_DRIVE_STRENGTH_MASK		(3<<0)
 | 
			
		||||
#define  SI5351_CLK_DRIVE_STRENGTH_2MA		(0<<0)
 | 
			
		||||
#define  SI5351_CLK_DRIVE_STRENGTH_4MA		(1<<0)
 | 
			
		||||
#define  SI5351_CLK_DRIVE_STRENGTH_6MA		(2<<0)
 | 
			
		||||
#define  SI5351_CLK_DRIVE_STRENGTH_8MA		(3<<0)
 | 
			
		||||
 | 
			
		||||
#define SI5351_CLK3_0_DISABLE_STATE		24
 | 
			
		||||
#define SI5351_CLK7_4_DISABLE_STATE		25
 | 
			
		||||
#define  SI5351_CLK_DISABLE_STATE_LOW		0
 | 
			
		||||
#define  SI5351_CLK_DISABLE_STATE_HIGH		1
 | 
			
		||||
#define  SI5351_CLK_DISABLE_STATE_FLOAT		2
 | 
			
		||||
#define  SI5351_CLK_DISABLE_STATE_NEVER		3
 | 
			
		||||
 | 
			
		||||
#define SI5351_PARAMETERS_LENGTH		8
 | 
			
		||||
#define SI5351_PLLA_PARAMETERS			26
 | 
			
		||||
#define SI5351_PLLB_PARAMETERS			34
 | 
			
		||||
#define SI5351_CLK0_PARAMETERS			42
 | 
			
		||||
#define SI5351_CLK1_PARAMETERS			50
 | 
			
		||||
#define SI5351_CLK2_PARAMETERS			58
 | 
			
		||||
#define SI5351_CLK3_PARAMETERS			66
 | 
			
		||||
#define SI5351_CLK4_PARAMETERS			74
 | 
			
		||||
#define SI5351_CLK5_PARAMETERS			82
 | 
			
		||||
#define SI5351_CLK6_PARAMETERS			90
 | 
			
		||||
#define SI5351_CLK7_PARAMETERS			91
 | 
			
		||||
#define SI5351_CLK6_7_OUTPUT_DIVIDER		92
 | 
			
		||||
#define  SI5351_OUTPUT_CLK_DIV_MASK		(7 << 4)
 | 
			
		||||
#define  SI5351_OUTPUT_CLK6_DIV_MASK		(7 << 0)
 | 
			
		||||
#define  SI5351_OUTPUT_CLK_DIV_SHIFT		4
 | 
			
		||||
#define  SI5351_OUTPUT_CLK_DIV6_SHIFT		0
 | 
			
		||||
#define  SI5351_OUTPUT_CLK_DIV_1		0
 | 
			
		||||
#define  SI5351_OUTPUT_CLK_DIV_2		1
 | 
			
		||||
#define  SI5351_OUTPUT_CLK_DIV_4		2
 | 
			
		||||
#define  SI5351_OUTPUT_CLK_DIV_8		3
 | 
			
		||||
#define  SI5351_OUTPUT_CLK_DIV_16		4
 | 
			
		||||
#define  SI5351_OUTPUT_CLK_DIV_32		5
 | 
			
		||||
#define  SI5351_OUTPUT_CLK_DIV_64		6
 | 
			
		||||
#define  SI5351_OUTPUT_CLK_DIV_128		7
 | 
			
		||||
#define  SI5351_OUTPUT_CLK_DIVBY4		(3<<2)
 | 
			
		||||
 | 
			
		||||
#define SI5351_SSC_PARAM0			149
 | 
			
		||||
#define SI5351_SSC_PARAM1			150
 | 
			
		||||
#define SI5351_SSC_PARAM2			151
 | 
			
		||||
#define SI5351_SSC_PARAM3			152
 | 
			
		||||
#define SI5351_SSC_PARAM4			153
 | 
			
		||||
#define SI5351_SSC_PARAM5			154
 | 
			
		||||
#define SI5351_SSC_PARAM6			155
 | 
			
		||||
#define SI5351_SSC_PARAM7			156
 | 
			
		||||
#define SI5351_SSC_PARAM8			157
 | 
			
		||||
#define SI5351_SSC_PARAM9			158
 | 
			
		||||
#define SI5351_SSC_PARAM10			159
 | 
			
		||||
#define SI5351_SSC_PARAM11			160
 | 
			
		||||
#define SI5351_SSC_PARAM12			161
 | 
			
		||||
 | 
			
		||||
#define SI5351_VXCO_PARAMETERS_LOW		162
 | 
			
		||||
#define SI5351_VXCO_PARAMETERS_MID		163
 | 
			
		||||
#define SI5351_VXCO_PARAMETERS_HIGH		164
 | 
			
		||||
 | 
			
		||||
#define SI5351_CLK0_PHASE_OFFSET		165
 | 
			
		||||
#define SI5351_CLK1_PHASE_OFFSET		166
 | 
			
		||||
#define SI5351_CLK2_PHASE_OFFSET		167
 | 
			
		||||
#define SI5351_CLK3_PHASE_OFFSET		168
 | 
			
		||||
#define SI5351_CLK4_PHASE_OFFSET		169
 | 
			
		||||
#define SI5351_CLK5_PHASE_OFFSET		170
 | 
			
		||||
 | 
			
		||||
#define SI5351_PLL_RESET			177
 | 
			
		||||
#define  SI5351_PLL_RESET_B			(1<<7)
 | 
			
		||||
#define  SI5351_PLL_RESET_A			(1<<5)
 | 
			
		||||
 | 
			
		||||
#define SI5351_CRYSTAL_LOAD			183
 | 
			
		||||
#define  SI5351_CRYSTAL_LOAD_MASK		(3<<6)
 | 
			
		||||
#define  SI5351_CRYSTAL_LOAD_6PF		(1<<6)
 | 
			
		||||
#define  SI5351_CRYSTAL_LOAD_8PF		(2<<6)
 | 
			
		||||
#define  SI5351_CRYSTAL_LOAD_10PF		(3<<6)
 | 
			
		||||
 | 
			
		||||
#define SI5351_FANOUT_ENABLE			187
 | 
			
		||||
#define  SI5351_CLKIN_ENABLE			(1<<7)
 | 
			
		||||
#define  SI5351_XTAL_ENABLE			(1<<6)
 | 
			
		||||
#define  SI5351_MULTISYNTH_ENABLE		(1<<4)
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -488,6 +488,7 @@ static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate,
 | 
			
		|||
	case PLL_TYPE_WM8750:
 | 
			
		||||
		wm8750_find_pll_bits(rate, parent_rate, &filter, &mul, &div1, &div2);
 | 
			
		||||
		pll_val = WM8750_BITS_TO_VAL(filter, mul, div1, div2);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		pr_err("%s: invalid pll type\n", __func__);
 | 
			
		||||
		return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -523,6 +524,7 @@ static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate,
 | 
			
		|||
	case PLL_TYPE_WM8750:
 | 
			
		||||
		wm8750_find_pll_bits(rate, *prate, &filter, &mul, &div1, &div2);
 | 
			
		||||
		round_rate = WM8750_BITS_TO_FREQ(*prate, mul, div1, div2);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		round_rate = 0;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,7 @@
 | 
			
		|||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/kernel.h>
 | 
			
		||||
#include <linux/clk-provider.h>
 | 
			
		||||
#include <linux/clk/zynq.h>
 | 
			
		||||
 | 
			
		||||
static void __iomem *slcr_base;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,14 +19,77 @@
 | 
			
		|||
#include <linux/of.h>
 | 
			
		||||
#include <linux/device.h>
 | 
			
		||||
#include <linux/init.h>
 | 
			
		||||
#include <linux/sched.h>
 | 
			
		||||
 | 
			
		||||
static DEFINE_SPINLOCK(enable_lock);
 | 
			
		||||
static DEFINE_MUTEX(prepare_lock);
 | 
			
		||||
 | 
			
		||||
static struct task_struct *prepare_owner;
 | 
			
		||||
static struct task_struct *enable_owner;
 | 
			
		||||
 | 
			
		||||
static int prepare_refcnt;
 | 
			
		||||
static int enable_refcnt;
 | 
			
		||||
 | 
			
		||||
static HLIST_HEAD(clk_root_list);
 | 
			
		||||
static HLIST_HEAD(clk_orphan_list);
 | 
			
		||||
static LIST_HEAD(clk_notifier_list);
 | 
			
		||||
 | 
			
		||||
/***           locking             ***/
 | 
			
		||||
static void clk_prepare_lock(void)
 | 
			
		||||
{
 | 
			
		||||
	if (!mutex_trylock(&prepare_lock)) {
 | 
			
		||||
		if (prepare_owner == current) {
 | 
			
		||||
			prepare_refcnt++;
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		mutex_lock(&prepare_lock);
 | 
			
		||||
	}
 | 
			
		||||
	WARN_ON_ONCE(prepare_owner != NULL);
 | 
			
		||||
	WARN_ON_ONCE(prepare_refcnt != 0);
 | 
			
		||||
	prepare_owner = current;
 | 
			
		||||
	prepare_refcnt = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void clk_prepare_unlock(void)
 | 
			
		||||
{
 | 
			
		||||
	WARN_ON_ONCE(prepare_owner != current);
 | 
			
		||||
	WARN_ON_ONCE(prepare_refcnt == 0);
 | 
			
		||||
 | 
			
		||||
	if (--prepare_refcnt)
 | 
			
		||||
		return;
 | 
			
		||||
	prepare_owner = NULL;
 | 
			
		||||
	mutex_unlock(&prepare_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned long clk_enable_lock(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	if (!spin_trylock_irqsave(&enable_lock, flags)) {
 | 
			
		||||
		if (enable_owner == current) {
 | 
			
		||||
			enable_refcnt++;
 | 
			
		||||
			return flags;
 | 
			
		||||
		}
 | 
			
		||||
		spin_lock_irqsave(&enable_lock, flags);
 | 
			
		||||
	}
 | 
			
		||||
	WARN_ON_ONCE(enable_owner != NULL);
 | 
			
		||||
	WARN_ON_ONCE(enable_refcnt != 0);
 | 
			
		||||
	enable_owner = current;
 | 
			
		||||
	enable_refcnt = 1;
 | 
			
		||||
	return flags;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void clk_enable_unlock(unsigned long flags)
 | 
			
		||||
{
 | 
			
		||||
	WARN_ON_ONCE(enable_owner != current);
 | 
			
		||||
	WARN_ON_ONCE(enable_refcnt == 0);
 | 
			
		||||
 | 
			
		||||
	if (--enable_refcnt)
 | 
			
		||||
		return;
 | 
			
		||||
	enable_owner = NULL;
 | 
			
		||||
	spin_unlock_irqrestore(&enable_lock, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/***        debugfs support        ***/
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_COMMON_CLK_DEBUG
 | 
			
		||||
| 
						 | 
				
			
			@ -69,7 +132,7 @@ static int clk_summary_show(struct seq_file *s, void *data)
 | 
			
		|||
	seq_printf(s, "   clock                        enable_cnt  prepare_cnt  rate\n");
 | 
			
		||||
	seq_printf(s, "---------------------------------------------------------------------\n");
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&prepare_lock);
 | 
			
		||||
	clk_prepare_lock();
 | 
			
		||||
 | 
			
		||||
	hlist_for_each_entry(c, &clk_root_list, child_node)
 | 
			
		||||
		clk_summary_show_subtree(s, c, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -77,7 +140,7 @@ static int clk_summary_show(struct seq_file *s, void *data)
 | 
			
		|||
	hlist_for_each_entry(c, &clk_orphan_list, child_node)
 | 
			
		||||
		clk_summary_show_subtree(s, c, 0);
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&prepare_lock);
 | 
			
		||||
	clk_prepare_unlock();
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -130,7 +193,7 @@ static int clk_dump(struct seq_file *s, void *data)
 | 
			
		|||
 | 
			
		||||
	seq_printf(s, "{");
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&prepare_lock);
 | 
			
		||||
	clk_prepare_lock();
 | 
			
		||||
 | 
			
		||||
	hlist_for_each_entry(c, &clk_root_list, child_node) {
 | 
			
		||||
		if (!first_node)
 | 
			
		||||
| 
						 | 
				
			
			@ -144,7 +207,7 @@ static int clk_dump(struct seq_file *s, void *data)
 | 
			
		|||
		clk_dump_subtree(s, c, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&prepare_lock);
 | 
			
		||||
	clk_prepare_unlock();
 | 
			
		||||
 | 
			
		||||
	seq_printf(s, "}");
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -279,6 +342,39 @@ out:
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * clk_debug_reparent - reparent clk node in the debugfs clk tree
 | 
			
		||||
 * @clk: the clk being reparented
 | 
			
		||||
 * @new_parent: the new clk parent, may be NULL
 | 
			
		||||
 *
 | 
			
		||||
 * Rename clk entry in the debugfs clk tree if debugfs has been
 | 
			
		||||
 * initialized.  Otherwise it bails out early since the debugfs clk tree
 | 
			
		||||
 * will be created lazily by clk_debug_init as part of a late_initcall.
 | 
			
		||||
 *
 | 
			
		||||
 * Caller must hold prepare_lock.
 | 
			
		||||
 */
 | 
			
		||||
static void clk_debug_reparent(struct clk *clk, struct clk *new_parent)
 | 
			
		||||
{
 | 
			
		||||
	struct dentry *d;
 | 
			
		||||
	struct dentry *new_parent_d;
 | 
			
		||||
 | 
			
		||||
	if (!inited)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (new_parent)
 | 
			
		||||
		new_parent_d = new_parent->dentry;
 | 
			
		||||
	else
 | 
			
		||||
		new_parent_d = orphandir;
 | 
			
		||||
 | 
			
		||||
	d = debugfs_rename(clk->dentry->d_parent, clk->dentry,
 | 
			
		||||
			new_parent_d, clk->name);
 | 
			
		||||
	if (d)
 | 
			
		||||
		clk->dentry = d;
 | 
			
		||||
	else
 | 
			
		||||
		pr_debug("%s: failed to rename debugfs entry for %s\n",
 | 
			
		||||
				__func__, clk->name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * clk_debug_init - lazily create the debugfs clk tree visualization
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -316,7 +412,7 @@ static int __init clk_debug_init(void)
 | 
			
		|||
	if (!orphandir)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&prepare_lock);
 | 
			
		||||
	clk_prepare_lock();
 | 
			
		||||
 | 
			
		||||
	hlist_for_each_entry(clk, &clk_root_list, child_node)
 | 
			
		||||
		clk_debug_create_subtree(clk, rootdir);
 | 
			
		||||
| 
						 | 
				
			
			@ -326,15 +422,44 @@ static int __init clk_debug_init(void)
 | 
			
		|||
 | 
			
		||||
	inited = 1;
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&prepare_lock);
 | 
			
		||||
	clk_prepare_unlock();
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
late_initcall(clk_debug_init);
 | 
			
		||||
#else
 | 
			
		||||
static inline int clk_debug_register(struct clk *clk) { return 0; }
 | 
			
		||||
static inline void clk_debug_reparent(struct clk *clk, struct clk *new_parent)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* caller must hold prepare_lock */
 | 
			
		||||
static void clk_unprepare_unused_subtree(struct clk *clk)
 | 
			
		||||
{
 | 
			
		||||
	struct clk *child;
 | 
			
		||||
 | 
			
		||||
	if (!clk)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	hlist_for_each_entry(child, &clk->children, child_node)
 | 
			
		||||
		clk_unprepare_unused_subtree(child);
 | 
			
		||||
 | 
			
		||||
	if (clk->prepare_count)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (clk->flags & CLK_IGNORE_UNUSED)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (__clk_is_prepared(clk)) {
 | 
			
		||||
		if (clk->ops->unprepare_unused)
 | 
			
		||||
			clk->ops->unprepare_unused(clk->hw);
 | 
			
		||||
		else if (clk->ops->unprepare)
 | 
			
		||||
			clk->ops->unprepare(clk->hw);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(__clk_get_flags);
 | 
			
		||||
 | 
			
		||||
/* caller must hold prepare_lock */
 | 
			
		||||
static void clk_disable_unused_subtree(struct clk *clk)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -347,7 +472,7 @@ static void clk_disable_unused_subtree(struct clk *clk)
 | 
			
		|||
	hlist_for_each_entry(child, &clk->children, child_node)
 | 
			
		||||
		clk_disable_unused_subtree(child);
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&enable_lock, flags);
 | 
			
		||||
	flags = clk_enable_lock();
 | 
			
		||||
 | 
			
		||||
	if (clk->enable_count)
 | 
			
		||||
		goto unlock_out;
 | 
			
		||||
| 
						 | 
				
			
			@ -368,17 +493,30 @@ static void clk_disable_unused_subtree(struct clk *clk)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
unlock_out:
 | 
			
		||||
	spin_unlock_irqrestore(&enable_lock, flags);
 | 
			
		||||
	clk_enable_unlock(flags);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool clk_ignore_unused;
 | 
			
		||||
static int __init clk_ignore_unused_setup(char *__unused)
 | 
			
		||||
{
 | 
			
		||||
	clk_ignore_unused = true;
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
__setup("clk_ignore_unused", clk_ignore_unused_setup);
 | 
			
		||||
 | 
			
		||||
static int clk_disable_unused(void)
 | 
			
		||||
{
 | 
			
		||||
	struct clk *clk;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&prepare_lock);
 | 
			
		||||
	if (clk_ignore_unused) {
 | 
			
		||||
		pr_warn("clk: Not disabling unused clocks\n");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	clk_prepare_lock();
 | 
			
		||||
 | 
			
		||||
	hlist_for_each_entry(clk, &clk_root_list, child_node)
 | 
			
		||||
		clk_disable_unused_subtree(clk);
 | 
			
		||||
| 
						 | 
				
			
			@ -386,7 +524,13 @@ static int clk_disable_unused(void)
 | 
			
		|||
	hlist_for_each_entry(clk, &clk_orphan_list, child_node)
 | 
			
		||||
		clk_disable_unused_subtree(clk);
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&prepare_lock);
 | 
			
		||||
	hlist_for_each_entry(clk, &clk_root_list, child_node)
 | 
			
		||||
		clk_unprepare_unused_subtree(clk);
 | 
			
		||||
 | 
			
		||||
	hlist_for_each_entry(clk, &clk_orphan_list, child_node)
 | 
			
		||||
		clk_unprepare_unused_subtree(clk);
 | 
			
		||||
 | 
			
		||||
	clk_prepare_unlock();
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -451,6 +595,27 @@ unsigned long __clk_get_flags(struct clk *clk)
 | 
			
		|||
	return !clk ? 0 : clk->flags;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool __clk_is_prepared(struct clk *clk)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!clk)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * .is_prepared is optional for clocks that can prepare
 | 
			
		||||
	 * fall back to software usage counter if it is missing
 | 
			
		||||
	 */
 | 
			
		||||
	if (!clk->ops->is_prepared) {
 | 
			
		||||
		ret = clk->prepare_count ? 1 : 0;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = clk->ops->is_prepared(clk->hw);
 | 
			
		||||
out:
 | 
			
		||||
	return !!ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool __clk_is_enabled(struct clk *clk)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -548,9 +713,9 @@ void __clk_unprepare(struct clk *clk)
 | 
			
		|||
 */
 | 
			
		||||
void clk_unprepare(struct clk *clk)
 | 
			
		||||
{
 | 
			
		||||
	mutex_lock(&prepare_lock);
 | 
			
		||||
	clk_prepare_lock();
 | 
			
		||||
	__clk_unprepare(clk);
 | 
			
		||||
	mutex_unlock(&prepare_lock);
 | 
			
		||||
	clk_prepare_unlock();
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(clk_unprepare);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -596,9 +761,9 @@ int clk_prepare(struct clk *clk)
 | 
			
		|||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&prepare_lock);
 | 
			
		||||
	clk_prepare_lock();
 | 
			
		||||
	ret = __clk_prepare(clk);
 | 
			
		||||
	mutex_unlock(&prepare_lock);
 | 
			
		||||
	clk_prepare_unlock();
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -640,9 +805,9 @@ void clk_disable(struct clk *clk)
 | 
			
		|||
{
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&enable_lock, flags);
 | 
			
		||||
	flags = clk_enable_lock();
 | 
			
		||||
	__clk_disable(clk);
 | 
			
		||||
	spin_unlock_irqrestore(&enable_lock, flags);
 | 
			
		||||
	clk_enable_unlock(flags);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(clk_disable);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -693,9 +858,9 @@ int clk_enable(struct clk *clk)
 | 
			
		|||
	unsigned long flags;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&enable_lock, flags);
 | 
			
		||||
	flags = clk_enable_lock();
 | 
			
		||||
	ret = __clk_enable(clk);
 | 
			
		||||
	spin_unlock_irqrestore(&enable_lock, flags);
 | 
			
		||||
	clk_enable_unlock(flags);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -740,9 +905,9 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
 | 
			
		|||
{
 | 
			
		||||
	unsigned long ret;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&prepare_lock);
 | 
			
		||||
	clk_prepare_lock();
 | 
			
		||||
	ret = __clk_round_rate(clk, rate);
 | 
			
		||||
	mutex_unlock(&prepare_lock);
 | 
			
		||||
	clk_prepare_unlock();
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -837,13 +1002,13 @@ unsigned long clk_get_rate(struct clk *clk)
 | 
			
		|||
{
 | 
			
		||||
	unsigned long rate;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&prepare_lock);
 | 
			
		||||
	clk_prepare_lock();
 | 
			
		||||
 | 
			
		||||
	if (clk && (clk->flags & CLK_GET_RATE_NOCACHE))
 | 
			
		||||
		__clk_recalc_rates(clk, 0);
 | 
			
		||||
 | 
			
		||||
	rate = __clk_get_rate(clk);
 | 
			
		||||
	mutex_unlock(&prepare_lock);
 | 
			
		||||
	clk_prepare_unlock();
 | 
			
		||||
 | 
			
		||||
	return rate;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -876,16 +1041,16 @@ static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate)
 | 
			
		|||
	else
 | 
			
		||||
		new_rate = parent_rate;
 | 
			
		||||
 | 
			
		||||
	/* abort the rate change if a driver returns NOTIFY_BAD */
 | 
			
		||||
	/* abort rate change if a driver returns NOTIFY_BAD or NOTIFY_STOP */
 | 
			
		||||
	if (clk->notifier_count)
 | 
			
		||||
		ret = __clk_notify(clk, PRE_RATE_CHANGE, clk->rate, new_rate);
 | 
			
		||||
 | 
			
		||||
	if (ret == NOTIFY_BAD)
 | 
			
		||||
	if (ret & NOTIFY_STOP_MASK)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	hlist_for_each_entry(child, &clk->children, child_node) {
 | 
			
		||||
		ret = __clk_speculate_rates(child, new_rate);
 | 
			
		||||
		if (ret == NOTIFY_BAD)
 | 
			
		||||
		if (ret & NOTIFY_STOP_MASK)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -974,11 +1139,11 @@ static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long even
 | 
			
		|||
	int ret = NOTIFY_DONE;
 | 
			
		||||
 | 
			
		||||
	if (clk->rate == clk->new_rate)
 | 
			
		||||
		return 0;
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	if (clk->notifier_count) {
 | 
			
		||||
		ret = __clk_notify(clk, event, clk->rate, clk->new_rate);
 | 
			
		||||
		if (ret == NOTIFY_BAD)
 | 
			
		||||
		if (ret & NOTIFY_STOP_MASK)
 | 
			
		||||
			fail_clk = clk;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1048,7 +1213,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
 | 
			
		|||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	/* prevent racing with updates to the clock topology */
 | 
			
		||||
	mutex_lock(&prepare_lock);
 | 
			
		||||
	clk_prepare_lock();
 | 
			
		||||
 | 
			
		||||
	/* bail early if nothing to do */
 | 
			
		||||
	if (rate == clk->rate)
 | 
			
		||||
| 
						 | 
				
			
			@ -1080,7 +1245,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
 | 
			
		|||
	clk_change_rate(top);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	mutex_unlock(&prepare_lock);
 | 
			
		||||
	clk_prepare_unlock();
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1096,9 +1261,9 @@ struct clk *clk_get_parent(struct clk *clk)
 | 
			
		|||
{
 | 
			
		||||
	struct clk *parent;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&prepare_lock);
 | 
			
		||||
	clk_prepare_lock();
 | 
			
		||||
	parent = __clk_get_parent(clk);
 | 
			
		||||
	mutex_unlock(&prepare_lock);
 | 
			
		||||
	clk_prepare_unlock();
 | 
			
		||||
 | 
			
		||||
	return parent;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1162,16 +1327,8 @@ out:
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __clk_reparent(struct clk *clk, struct clk *new_parent)
 | 
			
		||||
static void clk_reparent(struct clk *clk, struct clk *new_parent)
 | 
			
		||||
{
 | 
			
		||||
#ifdef CONFIG_COMMON_CLK_DEBUG
 | 
			
		||||
	struct dentry *d;
 | 
			
		||||
	struct dentry *new_parent_d;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (!clk || !new_parent)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	hlist_del(&clk->child_node);
 | 
			
		||||
 | 
			
		||||
	if (new_parent)
 | 
			
		||||
| 
						 | 
				
			
			@ -1179,39 +1336,20 @@ void __clk_reparent(struct clk *clk, struct clk *new_parent)
 | 
			
		|||
	else
 | 
			
		||||
		hlist_add_head(&clk->child_node, &clk_orphan_list);
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_COMMON_CLK_DEBUG
 | 
			
		||||
	if (!inited)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	if (new_parent)
 | 
			
		||||
		new_parent_d = new_parent->dentry;
 | 
			
		||||
	else
 | 
			
		||||
		new_parent_d = orphandir;
 | 
			
		||||
 | 
			
		||||
	d = debugfs_rename(clk->dentry->d_parent, clk->dentry,
 | 
			
		||||
			new_parent_d, clk->name);
 | 
			
		||||
	if (d)
 | 
			
		||||
		clk->dentry = d;
 | 
			
		||||
	else
 | 
			
		||||
		pr_debug("%s: failed to rename debugfs entry for %s\n",
 | 
			
		||||
				__func__, clk->name);
 | 
			
		||||
out:
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	clk->parent = new_parent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __clk_reparent(struct clk *clk, struct clk *new_parent)
 | 
			
		||||
{
 | 
			
		||||
	clk_reparent(clk, new_parent);
 | 
			
		||||
	clk_debug_reparent(clk, new_parent);
 | 
			
		||||
	__clk_recalc_rates(clk, POST_RATE_CHANGE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int __clk_set_parent(struct clk *clk, struct clk *parent)
 | 
			
		||||
static u8 clk_fetch_parent_index(struct clk *clk, struct clk *parent)
 | 
			
		||||
{
 | 
			
		||||
	struct clk *old_parent;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	int ret = -EINVAL;
 | 
			
		||||
	u8 i;
 | 
			
		||||
 | 
			
		||||
	old_parent = clk->parent;
 | 
			
		||||
 | 
			
		||||
	if (!clk->parents)
 | 
			
		||||
		clk->parents = kzalloc((sizeof(struct clk*) * clk->num_parents),
 | 
			
		||||
								GFP_KERNEL);
 | 
			
		||||
| 
						 | 
				
			
			@ -1231,36 +1369,79 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent)
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (i == clk->num_parents) {
 | 
			
		||||
		pr_debug("%s: clock %s is not a possible parent of clock %s\n",
 | 
			
		||||
				__func__, parent->name, clk->name);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	return i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	/* migrate prepare and enable */
 | 
			
		||||
static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
	struct clk *old_parent = clk->parent;
 | 
			
		||||
	bool migrated_enable = false;
 | 
			
		||||
 | 
			
		||||
	/* migrate prepare */
 | 
			
		||||
	if (clk->prepare_count)
 | 
			
		||||
		__clk_prepare(parent);
 | 
			
		||||
 | 
			
		||||
	/* FIXME replace with clk_is_enabled(clk) someday */
 | 
			
		||||
	spin_lock_irqsave(&enable_lock, flags);
 | 
			
		||||
	if (clk->enable_count)
 | 
			
		||||
	flags = clk_enable_lock();
 | 
			
		||||
 | 
			
		||||
	/* migrate enable */
 | 
			
		||||
	if (clk->enable_count) {
 | 
			
		||||
		__clk_enable(parent);
 | 
			
		||||
	spin_unlock_irqrestore(&enable_lock, flags);
 | 
			
		||||
		migrated_enable = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* update the clk tree topology */
 | 
			
		||||
	clk_reparent(clk, parent);
 | 
			
		||||
 | 
			
		||||
	clk_enable_unlock(flags);
 | 
			
		||||
 | 
			
		||||
	/* change clock input source */
 | 
			
		||||
	ret = clk->ops->set_parent(clk->hw, i);
 | 
			
		||||
	if (parent && clk->ops->set_parent)
 | 
			
		||||
		ret = clk->ops->set_parent(clk->hw, p_index);
 | 
			
		||||
 | 
			
		||||
	/* clean up old prepare and enable */
 | 
			
		||||
	spin_lock_irqsave(&enable_lock, flags);
 | 
			
		||||
	if (clk->enable_count)
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * The error handling is tricky due to that we need to release
 | 
			
		||||
		 * the spinlock while issuing the .set_parent callback. This
 | 
			
		||||
		 * means the new parent might have been enabled/disabled in
 | 
			
		||||
		 * between, which must be considered when doing rollback.
 | 
			
		||||
		 */
 | 
			
		||||
		flags = clk_enable_lock();
 | 
			
		||||
 | 
			
		||||
		clk_reparent(clk, old_parent);
 | 
			
		||||
 | 
			
		||||
		if (migrated_enable && clk->enable_count) {
 | 
			
		||||
			__clk_disable(parent);
 | 
			
		||||
		} else if (migrated_enable && (clk->enable_count == 0)) {
 | 
			
		||||
			__clk_disable(old_parent);
 | 
			
		||||
		} else if (!migrated_enable && clk->enable_count) {
 | 
			
		||||
			__clk_disable(parent);
 | 
			
		||||
			__clk_enable(old_parent);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		clk_enable_unlock(flags);
 | 
			
		||||
 | 
			
		||||
		if (clk->prepare_count)
 | 
			
		||||
			__clk_unprepare(parent);
 | 
			
		||||
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* clean up enable for old parent if migration was done */
 | 
			
		||||
	if (migrated_enable) {
 | 
			
		||||
		flags = clk_enable_lock();
 | 
			
		||||
		__clk_disable(old_parent);
 | 
			
		||||
	spin_unlock_irqrestore(&enable_lock, flags);
 | 
			
		||||
		clk_enable_unlock(flags);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* clean up prepare for old parent if migration was done */
 | 
			
		||||
	if (clk->prepare_count)
 | 
			
		||||
		__clk_unprepare(old_parent);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	return ret;
 | 
			
		||||
	/* update debugfs with new clk tree topology */
 | 
			
		||||
	clk_debug_reparent(clk, parent);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -1278,44 +1459,59 @@ out:
 | 
			
		|||
int clk_set_parent(struct clk *clk, struct clk *parent)
 | 
			
		||||
{
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
	u8 p_index = 0;
 | 
			
		||||
	unsigned long p_rate = 0;
 | 
			
		||||
 | 
			
		||||
	if (!clk || !clk->ops)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (!clk->ops->set_parent)
 | 
			
		||||
	/* verify ops for for multi-parent clks */
 | 
			
		||||
	if ((clk->num_parents > 1) && (!clk->ops->set_parent))
 | 
			
		||||
		return -ENOSYS;
 | 
			
		||||
 | 
			
		||||
	/* prevent racing with updates to the clock topology */
 | 
			
		||||
	mutex_lock(&prepare_lock);
 | 
			
		||||
	clk_prepare_lock();
 | 
			
		||||
 | 
			
		||||
	if (clk->parent == parent)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	/* propagate PRE_RATE_CHANGE notifications */
 | 
			
		||||
	if (clk->notifier_count)
 | 
			
		||||
		ret = __clk_speculate_rates(clk, parent->rate);
 | 
			
		||||
 | 
			
		||||
	/* abort if a driver objects */
 | 
			
		||||
	if (ret == NOTIFY_STOP)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	/* only re-parent if the clock is not in use */
 | 
			
		||||
	if ((clk->flags & CLK_SET_PARENT_GATE) && clk->prepare_count)
 | 
			
		||||
	/* check that we are allowed to re-parent if the clock is in use */
 | 
			
		||||
	if ((clk->flags & CLK_SET_PARENT_GATE) && clk->prepare_count) {
 | 
			
		||||
		ret = -EBUSY;
 | 
			
		||||
	else
 | 
			
		||||
		ret = __clk_set_parent(clk, parent);
 | 
			
		||||
 | 
			
		||||
	/* propagate ABORT_RATE_CHANGE if .set_parent failed */
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		__clk_recalc_rates(clk, ABORT_RATE_CHANGE);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* propagate rate recalculation downstream */
 | 
			
		||||
	__clk_reparent(clk, parent);
 | 
			
		||||
	/* try finding the new parent index */
 | 
			
		||||
	if (parent) {
 | 
			
		||||
		p_index = clk_fetch_parent_index(clk, parent);
 | 
			
		||||
		p_rate = parent->rate;
 | 
			
		||||
		if (p_index == clk->num_parents) {
 | 
			
		||||
			pr_debug("%s: clk %s can not be parent of clk %s\n",
 | 
			
		||||
					__func__, parent->name, clk->name);
 | 
			
		||||
			ret = -EINVAL;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* propagate PRE_RATE_CHANGE notifications */
 | 
			
		||||
	if (clk->notifier_count)
 | 
			
		||||
		ret = __clk_speculate_rates(clk, p_rate);
 | 
			
		||||
 | 
			
		||||
	/* abort if a driver objects */
 | 
			
		||||
	if (ret & NOTIFY_STOP_MASK)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	/* do the re-parent */
 | 
			
		||||
	ret = __clk_set_parent(clk, parent, p_index);
 | 
			
		||||
 | 
			
		||||
	/* propagate rate recalculation accordingly */
 | 
			
		||||
	if (ret)
 | 
			
		||||
		__clk_recalc_rates(clk, ABORT_RATE_CHANGE);
 | 
			
		||||
	else
 | 
			
		||||
		__clk_recalc_rates(clk, POST_RATE_CHANGE);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	mutex_unlock(&prepare_lock);
 | 
			
		||||
	clk_prepare_unlock();
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1338,7 +1534,7 @@ int __clk_init(struct device *dev, struct clk *clk)
 | 
			
		|||
	if (!clk)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&prepare_lock);
 | 
			
		||||
	clk_prepare_lock();
 | 
			
		||||
 | 
			
		||||
	/* check to see if a clock with this name is already registered */
 | 
			
		||||
	if (__clk_lookup(clk->name)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1462,7 +1658,7 @@ int __clk_init(struct device *dev, struct clk *clk)
 | 
			
		|||
	clk_debug_register(clk);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	mutex_unlock(&prepare_lock);
 | 
			
		||||
	clk_prepare_unlock();
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1696,7 +1892,7 @@ int clk_notifier_register(struct clk *clk, struct notifier_block *nb)
 | 
			
		|||
	if (!clk || !nb)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&prepare_lock);
 | 
			
		||||
	clk_prepare_lock();
 | 
			
		||||
 | 
			
		||||
	/* search the list of notifiers for this clk */
 | 
			
		||||
	list_for_each_entry(cn, &clk_notifier_list, node)
 | 
			
		||||
| 
						 | 
				
			
			@ -1720,7 +1916,7 @@ int clk_notifier_register(struct clk *clk, struct notifier_block *nb)
 | 
			
		|||
	clk->notifier_count++;
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	mutex_unlock(&prepare_lock);
 | 
			
		||||
	clk_prepare_unlock();
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1745,7 +1941,7 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
 | 
			
		|||
	if (!clk || !nb)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&prepare_lock);
 | 
			
		||||
	clk_prepare_lock();
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(cn, &clk_notifier_list, node)
 | 
			
		||||
		if (cn->clk == clk)
 | 
			
		||||
| 
						 | 
				
			
			@ -1766,7 +1962,7 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
 | 
			
		|||
		ret = -ENOENT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&prepare_lock);
 | 
			
		||||
	clk_prepare_unlock();
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -156,7 +156,7 @@ static u32 __init armada_370_get_cpu_freq(void __iomem *sar)
 | 
			
		|||
 | 
			
		||||
	cpu_freq_select = ((readl(sar) >> SARL_A370_PCLK_FREQ_OPT) &
 | 
			
		||||
			   SARL_A370_PCLK_FREQ_OPT_MASK);
 | 
			
		||||
	if (cpu_freq_select > ARRAY_SIZE(armada_370_cpu_frequencies)) {
 | 
			
		||||
	if (cpu_freq_select >= ARRAY_SIZE(armada_370_cpu_frequencies)) {
 | 
			
		||||
		pr_err("CPU freq select unsuported %d\n", cpu_freq_select);
 | 
			
		||||
		cpu_freq = 0;
 | 
			
		||||
	} else
 | 
			
		||||
| 
						 | 
				
			
			@ -278,7 +278,7 @@ static u32 __init armada_xp_get_cpu_freq(void __iomem *sar)
 | 
			
		|||
	cpu_freq_select |= (((readl(sar+4) >> SARH_AXP_PCLK_FREQ_OPT) &
 | 
			
		||||
			     SARH_AXP_PCLK_FREQ_OPT_MASK)
 | 
			
		||||
			    << SARH_AXP_PCLK_FREQ_OPT_SHIFT);
 | 
			
		||||
	if (cpu_freq_select > ARRAY_SIZE(armada_xp_cpu_frequencies)) {
 | 
			
		||||
	if (cpu_freq_select >= ARRAY_SIZE(armada_xp_cpu_frequencies)) {
 | 
			
		||||
		pr_err("CPU freq select unsuported: %d\n", cpu_freq_select);
 | 
			
		||||
		cpu_freq = 0;
 | 
			
		||||
	} else
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,6 @@
 | 
			
		|||
#include <linux/io.h>
 | 
			
		||||
#include <linux/of.h>
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include "clk-cpu.h"
 | 
			
		||||
 | 
			
		||||
#define SYS_CTRL_CLK_DIVIDER_CTRL_OFFSET    0x0
 | 
			
		||||
#define SYS_CTRL_CLK_DIVIDER_VALUE_OFFSET   0xC
 | 
			
		||||
| 
						 | 
				
			
			@ -173,17 +172,5 @@ clks_out:
 | 
			
		|||
	kfree(cpuclk);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const __initconst struct of_device_id clk_cpu_match[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.compatible = "marvell,armada-xp-cpu-clock",
 | 
			
		||||
		.data = of_cpu_clk_setup,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		/* sentinel */
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void __init mvebu_cpu_clk_init(void)
 | 
			
		||||
{
 | 
			
		||||
	of_clk_init(clk_cpu_match);
 | 
			
		||||
}
 | 
			
		||||
CLK_OF_DECLARE(armada_xp_cpu_clock, "marvell,armada-xp-cpu-clock",
 | 
			
		||||
					 of_cpu_clk_setup);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,22 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Marvell MVEBU CPU clock handling.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2012 Marvell
 | 
			
		||||
 *
 | 
			
		||||
 * Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This file is licensed under the terms of the GNU General Public
 | 
			
		||||
 * License version 2.  This program is licensed "as is" without any
 | 
			
		||||
 * warranty of any kind, whether express or implied.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __MVEBU_CLK_CPU_H
 | 
			
		||||
#define __MVEBU_CLK_CPU_H
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MVEBU_CLK_CPU
 | 
			
		||||
void __init mvebu_cpu_clk_init(void);
 | 
			
		||||
#else
 | 
			
		||||
static inline void mvebu_cpu_clk_init(void) {}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -10,18 +10,14 @@
 | 
			
		|||
 * warranty of any kind, whether express or implied.
 | 
			
		||||
 */
 | 
			
		||||
#include <linux/kernel.h>
 | 
			
		||||
#include <linux/clk.h>
 | 
			
		||||
#include <linux/clk-provider.h>
 | 
			
		||||
#include <linux/of_address.h>
 | 
			
		||||
#include <linux/clk/mvebu.h>
 | 
			
		||||
#include <linux/of.h>
 | 
			
		||||
#include "clk-core.h"
 | 
			
		||||
#include "clk-cpu.h"
 | 
			
		||||
#include "clk-gating-ctrl.h"
 | 
			
		||||
 | 
			
		||||
void __init mvebu_clocks_init(void)
 | 
			
		||||
{
 | 
			
		||||
	mvebu_core_clk_init();
 | 
			
		||||
	mvebu_gating_clk_init();
 | 
			
		||||
	mvebu_cpu_clk_init();
 | 
			
		||||
	of_clk_init(NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,7 @@
 | 
			
		|||
#include <linux/io.h>
 | 
			
		||||
#include <linux/jiffies.h>
 | 
			
		||||
#include <linux/spinlock.h>
 | 
			
		||||
#include "clk.h"
 | 
			
		||||
 | 
			
		||||
DEFINE_SPINLOCK(mxs_lock);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -960,47 +960,47 @@ void __init spear1340_clk_init(void)
 | 
			
		|||
			SPEAR1340_SPDIF_IN_CLK_ENB, 0, &_lock);
 | 
			
		||||
	clk_register_clkdev(clk, NULL, "d0100000.spdif-in");
 | 
			
		||||
 | 
			
		||||
	clk = clk_register_gate(NULL, "acp_clk", "acp_mclk", 0,
 | 
			
		||||
	clk = clk_register_gate(NULL, "acp_clk", "ahb_clk", 0,
 | 
			
		||||
			SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_ACP_CLK_ENB, 0,
 | 
			
		||||
			&_lock);
 | 
			
		||||
	clk_register_clkdev(clk, NULL, "acp_clk");
 | 
			
		||||
 | 
			
		||||
	clk = clk_register_gate(NULL, "plgpio_clk", "plgpio_mclk", 0,
 | 
			
		||||
	clk = clk_register_gate(NULL, "plgpio_clk", "ahb_clk", 0,
 | 
			
		||||
			SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_PLGPIO_CLK_ENB, 0,
 | 
			
		||||
			&_lock);
 | 
			
		||||
	clk_register_clkdev(clk, NULL, "e2800000.gpio");
 | 
			
		||||
 | 
			
		||||
	clk = clk_register_gate(NULL, "video_dec_clk", "video_dec_mclk", 0,
 | 
			
		||||
	clk = clk_register_gate(NULL, "video_dec_clk", "ahb_clk", 0,
 | 
			
		||||
			SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_DEC_CLK_ENB,
 | 
			
		||||
			0, &_lock);
 | 
			
		||||
	clk_register_clkdev(clk, NULL, "video_dec");
 | 
			
		||||
 | 
			
		||||
	clk = clk_register_gate(NULL, "video_enc_clk", "video_enc_mclk", 0,
 | 
			
		||||
	clk = clk_register_gate(NULL, "video_enc_clk", "ahb_clk", 0,
 | 
			
		||||
			SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_ENC_CLK_ENB,
 | 
			
		||||
			0, &_lock);
 | 
			
		||||
	clk_register_clkdev(clk, NULL, "video_enc");
 | 
			
		||||
 | 
			
		||||
	clk = clk_register_gate(NULL, "video_in_clk", "video_in_mclk", 0,
 | 
			
		||||
	clk = clk_register_gate(NULL, "video_in_clk", "ahb_clk", 0,
 | 
			
		||||
			SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_IN_CLK_ENB, 0,
 | 
			
		||||
			&_lock);
 | 
			
		||||
	clk_register_clkdev(clk, NULL, "spear_vip");
 | 
			
		||||
 | 
			
		||||
	clk = clk_register_gate(NULL, "cam0_clk", "cam0_mclk", 0,
 | 
			
		||||
	clk = clk_register_gate(NULL, "cam0_clk", "ahb_clk", 0,
 | 
			
		||||
			SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM0_CLK_ENB, 0,
 | 
			
		||||
			&_lock);
 | 
			
		||||
	clk_register_clkdev(clk, NULL, "d0200000.cam0");
 | 
			
		||||
 | 
			
		||||
	clk = clk_register_gate(NULL, "cam1_clk", "cam1_mclk", 0,
 | 
			
		||||
	clk = clk_register_gate(NULL, "cam1_clk", "ahb_clk", 0,
 | 
			
		||||
			SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM1_CLK_ENB, 0,
 | 
			
		||||
			&_lock);
 | 
			
		||||
	clk_register_clkdev(clk, NULL, "d0300000.cam1");
 | 
			
		||||
 | 
			
		||||
	clk = clk_register_gate(NULL, "cam2_clk", "cam2_mclk", 0,
 | 
			
		||||
	clk = clk_register_gate(NULL, "cam2_clk", "ahb_clk", 0,
 | 
			
		||||
			SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM2_CLK_ENB, 0,
 | 
			
		||||
			&_lock);
 | 
			
		||||
	clk_register_clkdev(clk, NULL, "d0400000.cam2");
 | 
			
		||||
 | 
			
		||||
	clk = clk_register_gate(NULL, "cam3_clk", "cam3_mclk", 0,
 | 
			
		||||
	clk = clk_register_gate(NULL, "cam3_clk", "ahb_clk", 0,
 | 
			
		||||
			SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM3_CLK_ENB, 0,
 | 
			
		||||
			&_lock);
 | 
			
		||||
	clk_register_clkdev(clk, NULL, "d0500000.cam3");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										5
									
								
								drivers/clk/sunxi/Makefile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								drivers/clk/sunxi/Makefile
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
#
 | 
			
		||||
# Makefile for sunxi specific clk
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
obj-y += clk-sunxi.o clk-factors.o
 | 
			
		||||
							
								
								
									
										180
									
								
								drivers/clk/sunxi/clk-factors.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								drivers/clk/sunxi/clk-factors.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,180 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (C) 2013 Emilio López <emilio@elopez.com.ar>
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Adjustable factor-based clock implementation
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/clk-provider.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/io.h>
 | 
			
		||||
#include <linux/err.h>
 | 
			
		||||
#include <linux/string.h>
 | 
			
		||||
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
 | 
			
		||||
#include "clk-factors.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * DOC: basic adjustable factor-based clock that cannot gate
 | 
			
		||||
 *
 | 
			
		||||
 * Traits of this clock:
 | 
			
		||||
 * prepare - clk_prepare only ensures that parents are prepared
 | 
			
		||||
 * enable - clk_enable only ensures that parents are enabled
 | 
			
		||||
 * rate - rate is adjustable.
 | 
			
		||||
 *        clk->rate = (parent->rate * N * (K + 1) >> P) / (M + 1)
 | 
			
		||||
 * parent - fixed parent.  No clk_set_parent support
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct clk_factors {
 | 
			
		||||
	struct clk_hw hw;
 | 
			
		||||
	void __iomem *reg;
 | 
			
		||||
	struct clk_factors_config *config;
 | 
			
		||||
	void (*get_factors) (u32 *rate, u32 parent, u8 *n, u8 *k, u8 *m, u8 *p);
 | 
			
		||||
	spinlock_t *lock;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw)
 | 
			
		||||
 | 
			
		||||
#define SETMASK(len, pos)		(((-1U) >> (31-len))  << (pos))
 | 
			
		||||
#define CLRMASK(len, pos)		(~(SETMASK(len, pos)))
 | 
			
		||||
#define FACTOR_GET(bit, len, reg)	(((reg) & SETMASK(len, bit)) >> (bit))
 | 
			
		||||
 | 
			
		||||
#define FACTOR_SET(bit, len, reg, val) \
 | 
			
		||||
	(((reg) & CLRMASK(len, bit)) | (val << (bit)))
 | 
			
		||||
 | 
			
		||||
static unsigned long clk_factors_recalc_rate(struct clk_hw *hw,
 | 
			
		||||
					     unsigned long parent_rate)
 | 
			
		||||
{
 | 
			
		||||
	u8 n = 1, k = 0, p = 0, m = 0;
 | 
			
		||||
	u32 reg;
 | 
			
		||||
	unsigned long rate;
 | 
			
		||||
	struct clk_factors *factors = to_clk_factors(hw);
 | 
			
		||||
	struct clk_factors_config *config = factors->config;
 | 
			
		||||
 | 
			
		||||
	/* Fetch the register value */
 | 
			
		||||
	reg = readl(factors->reg);
 | 
			
		||||
 | 
			
		||||
	/* Get each individual factor if applicable */
 | 
			
		||||
	if (config->nwidth != SUNXI_FACTORS_NOT_APPLICABLE)
 | 
			
		||||
		n = FACTOR_GET(config->nshift, config->nwidth, reg);
 | 
			
		||||
	if (config->kwidth != SUNXI_FACTORS_NOT_APPLICABLE)
 | 
			
		||||
		k = FACTOR_GET(config->kshift, config->kwidth, reg);
 | 
			
		||||
	if (config->mwidth != SUNXI_FACTORS_NOT_APPLICABLE)
 | 
			
		||||
		m = FACTOR_GET(config->mshift, config->mwidth, reg);
 | 
			
		||||
	if (config->pwidth != SUNXI_FACTORS_NOT_APPLICABLE)
 | 
			
		||||
		p = FACTOR_GET(config->pshift, config->pwidth, reg);
 | 
			
		||||
 | 
			
		||||
	/* Calculate the rate */
 | 
			
		||||
	rate = (parent_rate * n * (k + 1) >> p) / (m + 1);
 | 
			
		||||
 | 
			
		||||
	return rate;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate,
 | 
			
		||||
				   unsigned long *parent_rate)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_factors *factors = to_clk_factors(hw);
 | 
			
		||||
	factors->get_factors((u32 *)&rate, (u32)*parent_rate,
 | 
			
		||||
			     NULL, NULL, NULL, NULL);
 | 
			
		||||
 | 
			
		||||
	return rate;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
 | 
			
		||||
				unsigned long parent_rate)
 | 
			
		||||
{
 | 
			
		||||
	u8 n, k, m, p;
 | 
			
		||||
	u32 reg;
 | 
			
		||||
	struct clk_factors *factors = to_clk_factors(hw);
 | 
			
		||||
	struct clk_factors_config *config = factors->config;
 | 
			
		||||
	unsigned long flags = 0;
 | 
			
		||||
 | 
			
		||||
	factors->get_factors((u32 *)&rate, (u32)parent_rate, &n, &k, &m, &p);
 | 
			
		||||
 | 
			
		||||
	if (factors->lock)
 | 
			
		||||
		spin_lock_irqsave(factors->lock, flags);
 | 
			
		||||
 | 
			
		||||
	/* Fetch the register value */
 | 
			
		||||
	reg = readl(factors->reg);
 | 
			
		||||
 | 
			
		||||
	/* Set up the new factors - macros do not do anything if width is 0 */
 | 
			
		||||
	reg = FACTOR_SET(config->nshift, config->nwidth, reg, n);
 | 
			
		||||
	reg = FACTOR_SET(config->kshift, config->kwidth, reg, k);
 | 
			
		||||
	reg = FACTOR_SET(config->mshift, config->mwidth, reg, m);
 | 
			
		||||
	reg = FACTOR_SET(config->pshift, config->pwidth, reg, p);
 | 
			
		||||
 | 
			
		||||
	/* Apply them now */
 | 
			
		||||
	writel(reg, factors->reg);
 | 
			
		||||
 | 
			
		||||
	/* delay 500us so pll stabilizes */
 | 
			
		||||
	__delay((rate >> 20) * 500 / 2);
 | 
			
		||||
 | 
			
		||||
	if (factors->lock)
 | 
			
		||||
		spin_unlock_irqrestore(factors->lock, flags);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct clk_ops clk_factors_ops = {
 | 
			
		||||
	.recalc_rate = clk_factors_recalc_rate,
 | 
			
		||||
	.round_rate = clk_factors_round_rate,
 | 
			
		||||
	.set_rate = clk_factors_set_rate,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * clk_register_factors - register a factors clock with
 | 
			
		||||
 * the clock framework
 | 
			
		||||
 * @dev: device registering this clock
 | 
			
		||||
 * @name: name of this clock
 | 
			
		||||
 * @parent_name: name of clock's parent
 | 
			
		||||
 * @flags: framework-specific flags
 | 
			
		||||
 * @reg: register address to adjust factors
 | 
			
		||||
 * @config: shift and width of factors n, k, m and p
 | 
			
		||||
 * @get_factors: function to calculate the factors for a given frequency
 | 
			
		||||
 * @lock: shared register lock for this clock
 | 
			
		||||
 */
 | 
			
		||||
struct clk *clk_register_factors(struct device *dev, const char *name,
 | 
			
		||||
				 const char *parent_name,
 | 
			
		||||
				 unsigned long flags, void __iomem *reg,
 | 
			
		||||
				 struct clk_factors_config *config,
 | 
			
		||||
				 void (*get_factors)(u32 *rate, u32 parent,
 | 
			
		||||
						     u8 *n, u8 *k, u8 *m, u8 *p),
 | 
			
		||||
				 spinlock_t *lock)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_factors *factors;
 | 
			
		||||
	struct clk *clk;
 | 
			
		||||
	struct clk_init_data init;
 | 
			
		||||
 | 
			
		||||
	/* allocate the factors */
 | 
			
		||||
	factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL);
 | 
			
		||||
	if (!factors) {
 | 
			
		||||
		pr_err("%s: could not allocate factors clk\n", __func__);
 | 
			
		||||
		return ERR_PTR(-ENOMEM);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	init.name = name;
 | 
			
		||||
	init.ops = &clk_factors_ops;
 | 
			
		||||
	init.flags = flags;
 | 
			
		||||
	init.parent_names = (parent_name ? &parent_name : NULL);
 | 
			
		||||
	init.num_parents = (parent_name ? 1 : 0);
 | 
			
		||||
 | 
			
		||||
	/* struct clk_factors assignments */
 | 
			
		||||
	factors->reg = reg;
 | 
			
		||||
	factors->config = config;
 | 
			
		||||
	factors->lock = lock;
 | 
			
		||||
	factors->hw.init = &init;
 | 
			
		||||
	factors->get_factors = get_factors;
 | 
			
		||||
 | 
			
		||||
	/* register the clock */
 | 
			
		||||
	clk = clk_register(dev, &factors->hw);
 | 
			
		||||
 | 
			
		||||
	if (IS_ERR(clk))
 | 
			
		||||
		kfree(factors);
 | 
			
		||||
 | 
			
		||||
	return clk;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								drivers/clk/sunxi/clk-factors.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								drivers/clk/sunxi/clk-factors.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
#ifndef __MACH_SUNXI_CLK_FACTORS_H
 | 
			
		||||
#define __MACH_SUNXI_CLK_FACTORS_H
 | 
			
		||||
 | 
			
		||||
#include <linux/clk-provider.h>
 | 
			
		||||
#include <linux/clkdev.h>
 | 
			
		||||
 | 
			
		||||
#define SUNXI_FACTORS_NOT_APPLICABLE	(0)
 | 
			
		||||
 | 
			
		||||
struct clk_factors_config {
 | 
			
		||||
	u8 nshift;
 | 
			
		||||
	u8 nwidth;
 | 
			
		||||
	u8 kshift;
 | 
			
		||||
	u8 kwidth;
 | 
			
		||||
	u8 mshift;
 | 
			
		||||
	u8 mwidth;
 | 
			
		||||
	u8 pshift;
 | 
			
		||||
	u8 pwidth;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct clk *clk_register_factors(struct device *dev, const char *name,
 | 
			
		||||
				 const char *parent_name,
 | 
			
		||||
				 unsigned long flags, void __iomem *reg,
 | 
			
		||||
				 struct clk_factors_config *config,
 | 
			
		||||
				 void (*get_factors) (u32 *rate, u32 parent_rate,
 | 
			
		||||
						      u8 *n, u8 *k, u8 *m, u8 *p),
 | 
			
		||||
				 spinlock_t *lock);
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										469
									
								
								drivers/clk/sunxi/clk-sunxi.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										469
									
								
								drivers/clk/sunxi/clk-sunxi.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,469 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2013 Emilio López
 | 
			
		||||
 *
 | 
			
		||||
 * Emilio López <emilio@elopez.com.ar>
 | 
			
		||||
 *
 | 
			
		||||
 * 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/clk/sunxi.h>
 | 
			
		||||
#include <linux/of.h>
 | 
			
		||||
#include <linux/of_address.h>
 | 
			
		||||
 | 
			
		||||
#include "clk-factors.h"
 | 
			
		||||
 | 
			
		||||
static DEFINE_SPINLOCK(clk_lock);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * sunxi_osc_clk_setup() - Setup function for gatable oscillator
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define SUNXI_OSC24M_GATE	0
 | 
			
		||||
 | 
			
		||||
static void __init sunxi_osc_clk_setup(struct device_node *node)
 | 
			
		||||
{
 | 
			
		||||
	struct clk *clk;
 | 
			
		||||
	struct clk_fixed_rate *fixed;
 | 
			
		||||
	struct clk_gate *gate;
 | 
			
		||||
	const char *clk_name = node->name;
 | 
			
		||||
	u32 rate;
 | 
			
		||||
 | 
			
		||||
	/* allocate fixed-rate and gate clock structs */
 | 
			
		||||
	fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL);
 | 
			
		||||
	if (!fixed)
 | 
			
		||||
		return;
 | 
			
		||||
	gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
 | 
			
		||||
	if (!gate) {
 | 
			
		||||
		kfree(fixed);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (of_property_read_u32(node, "clock-frequency", &rate))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* set up gate and fixed rate properties */
 | 
			
		||||
	gate->reg = of_iomap(node, 0);
 | 
			
		||||
	gate->bit_idx = SUNXI_OSC24M_GATE;
 | 
			
		||||
	gate->lock = &clk_lock;
 | 
			
		||||
	fixed->fixed_rate = rate;
 | 
			
		||||
 | 
			
		||||
	clk = clk_register_composite(NULL, clk_name,
 | 
			
		||||
			NULL, 0,
 | 
			
		||||
			NULL, NULL,
 | 
			
		||||
			&fixed->hw, &clk_fixed_rate_ops,
 | 
			
		||||
			&gate->hw, &clk_gate_ops,
 | 
			
		||||
			CLK_IS_ROOT);
 | 
			
		||||
 | 
			
		||||
	if (clk) {
 | 
			
		||||
		of_clk_add_provider(node, of_clk_src_simple_get, clk);
 | 
			
		||||
		clk_register_clkdev(clk, clk_name, NULL);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * sunxi_get_pll1_factors() - calculates n, k, m, p factors for PLL1
 | 
			
		||||
 * PLL1 rate is calculated as follows
 | 
			
		||||
 * rate = (parent_rate * n * (k + 1) >> p) / (m + 1);
 | 
			
		||||
 * parent_rate is always 24Mhz
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static void sunxi_get_pll1_factors(u32 *freq, u32 parent_rate,
 | 
			
		||||
				   u8 *n, u8 *k, u8 *m, u8 *p)
 | 
			
		||||
{
 | 
			
		||||
	u8 div;
 | 
			
		||||
 | 
			
		||||
	/* Normalize value to a 6M multiple */
 | 
			
		||||
	div = *freq / 6000000;
 | 
			
		||||
	*freq = 6000000 * div;
 | 
			
		||||
 | 
			
		||||
	/* we were called to round the frequency, we can now return */
 | 
			
		||||
	if (n == NULL)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* m is always zero for pll1 */
 | 
			
		||||
	*m = 0;
 | 
			
		||||
 | 
			
		||||
	/* k is 1 only on these cases */
 | 
			
		||||
	if (*freq >= 768000000 || *freq == 42000000 || *freq == 54000000)
 | 
			
		||||
		*k = 1;
 | 
			
		||||
	else
 | 
			
		||||
		*k = 0;
 | 
			
		||||
 | 
			
		||||
	/* p will be 3 for divs under 10 */
 | 
			
		||||
	if (div < 10)
 | 
			
		||||
		*p = 3;
 | 
			
		||||
 | 
			
		||||
	/* p will be 2 for divs between 10 - 20 and odd divs under 32 */
 | 
			
		||||
	else if (div < 20 || (div < 32 && (div & 1)))
 | 
			
		||||
		*p = 2;
 | 
			
		||||
 | 
			
		||||
	/* p will be 1 for even divs under 32, divs under 40 and odd pairs
 | 
			
		||||
	 * of divs between 40-62 */
 | 
			
		||||
	else if (div < 40 || (div < 64 && (div & 2)))
 | 
			
		||||
		*p = 1;
 | 
			
		||||
 | 
			
		||||
	/* any other entries have p = 0 */
 | 
			
		||||
	else
 | 
			
		||||
		*p = 0;
 | 
			
		||||
 | 
			
		||||
	/* calculate a suitable n based on k and p */
 | 
			
		||||
	div <<= *p;
 | 
			
		||||
	div /= (*k + 1);
 | 
			
		||||
	*n = div / 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * sunxi_get_apb1_factors() - calculates m, p factors for APB1
 | 
			
		||||
 * APB1 rate is calculated as follows
 | 
			
		||||
 * rate = (parent_rate >> p) / (m + 1);
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static void sunxi_get_apb1_factors(u32 *freq, u32 parent_rate,
 | 
			
		||||
				   u8 *n, u8 *k, u8 *m, u8 *p)
 | 
			
		||||
{
 | 
			
		||||
	u8 calcm, calcp;
 | 
			
		||||
 | 
			
		||||
	if (parent_rate < *freq)
 | 
			
		||||
		*freq = parent_rate;
 | 
			
		||||
 | 
			
		||||
	parent_rate = (parent_rate + (*freq - 1)) / *freq;
 | 
			
		||||
 | 
			
		||||
	/* Invalid rate! */
 | 
			
		||||
	if (parent_rate > 32)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (parent_rate <= 4)
 | 
			
		||||
		calcp = 0;
 | 
			
		||||
	else if (parent_rate <= 8)
 | 
			
		||||
		calcp = 1;
 | 
			
		||||
	else if (parent_rate <= 16)
 | 
			
		||||
		calcp = 2;
 | 
			
		||||
	else
 | 
			
		||||
		calcp = 3;
 | 
			
		||||
 | 
			
		||||
	calcm = (parent_rate >> calcp) - 1;
 | 
			
		||||
 | 
			
		||||
	*freq = (parent_rate >> calcp) / (calcm + 1);
 | 
			
		||||
 | 
			
		||||
	/* we were called to round the frequency, we can now return */
 | 
			
		||||
	if (n == NULL)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	*m = calcm;
 | 
			
		||||
	*p = calcp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * sunxi_factors_clk_setup() - Setup function for factor clocks
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct factors_data {
 | 
			
		||||
	struct clk_factors_config *table;
 | 
			
		||||
	void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct clk_factors_config pll1_config = {
 | 
			
		||||
	.nshift = 8,
 | 
			
		||||
	.nwidth = 5,
 | 
			
		||||
	.kshift = 4,
 | 
			
		||||
	.kwidth = 2,
 | 
			
		||||
	.mshift = 0,
 | 
			
		||||
	.mwidth = 2,
 | 
			
		||||
	.pshift = 16,
 | 
			
		||||
	.pwidth = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct clk_factors_config apb1_config = {
 | 
			
		||||
	.mshift = 0,
 | 
			
		||||
	.mwidth = 5,
 | 
			
		||||
	.pshift = 16,
 | 
			
		||||
	.pwidth = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const __initconst struct factors_data pll1_data = {
 | 
			
		||||
	.table = &pll1_config,
 | 
			
		||||
	.getter = sunxi_get_pll1_factors,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const __initconst struct factors_data apb1_data = {
 | 
			
		||||
	.table = &apb1_config,
 | 
			
		||||
	.getter = sunxi_get_apb1_factors,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void __init sunxi_factors_clk_setup(struct device_node *node,
 | 
			
		||||
					   struct factors_data *data)
 | 
			
		||||
{
 | 
			
		||||
	struct clk *clk;
 | 
			
		||||
	const char *clk_name = node->name;
 | 
			
		||||
	const char *parent;
 | 
			
		||||
	void *reg;
 | 
			
		||||
 | 
			
		||||
	reg = of_iomap(node, 0);
 | 
			
		||||
 | 
			
		||||
	parent = of_clk_get_parent_name(node, 0);
 | 
			
		||||
 | 
			
		||||
	clk = clk_register_factors(NULL, clk_name, parent, 0, reg,
 | 
			
		||||
				   data->table, data->getter, &clk_lock);
 | 
			
		||||
 | 
			
		||||
	if (clk) {
 | 
			
		||||
		of_clk_add_provider(node, of_clk_src_simple_get, clk);
 | 
			
		||||
		clk_register_clkdev(clk, clk_name, NULL);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * sunxi_mux_clk_setup() - Setup function for muxes
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define SUNXI_MUX_GATE_WIDTH	2
 | 
			
		||||
 | 
			
		||||
struct mux_data {
 | 
			
		||||
	u8 shift;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const __initconst struct mux_data cpu_data = {
 | 
			
		||||
	.shift = 16,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const __initconst struct mux_data apb1_mux_data = {
 | 
			
		||||
	.shift = 24,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void __init sunxi_mux_clk_setup(struct device_node *node,
 | 
			
		||||
				       struct mux_data *data)
 | 
			
		||||
{
 | 
			
		||||
	struct clk *clk;
 | 
			
		||||
	const char *clk_name = node->name;
 | 
			
		||||
	const char *parents[5];
 | 
			
		||||
	void *reg;
 | 
			
		||||
	int i = 0;
 | 
			
		||||
 | 
			
		||||
	reg = of_iomap(node, 0);
 | 
			
		||||
 | 
			
		||||
	while (i < 5 && (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
 | 
			
		||||
		i++;
 | 
			
		||||
 | 
			
		||||
	clk = clk_register_mux(NULL, clk_name, parents, i, 0, reg,
 | 
			
		||||
			       data->shift, SUNXI_MUX_GATE_WIDTH,
 | 
			
		||||
			       0, &clk_lock);
 | 
			
		||||
 | 
			
		||||
	if (clk) {
 | 
			
		||||
		of_clk_add_provider(node, of_clk_src_simple_get, clk);
 | 
			
		||||
		clk_register_clkdev(clk, clk_name, NULL);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * sunxi_divider_clk_setup() - Setup function for simple divider clocks
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define SUNXI_DIVISOR_WIDTH	2
 | 
			
		||||
 | 
			
		||||
struct div_data {
 | 
			
		||||
	u8 shift;
 | 
			
		||||
	u8 pow;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const __initconst struct div_data axi_data = {
 | 
			
		||||
	.shift = 0,
 | 
			
		||||
	.pow = 0,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const __initconst struct div_data ahb_data = {
 | 
			
		||||
	.shift = 4,
 | 
			
		||||
	.pow = 1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const __initconst struct div_data apb0_data = {
 | 
			
		||||
	.shift = 8,
 | 
			
		||||
	.pow = 1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void __init sunxi_divider_clk_setup(struct device_node *node,
 | 
			
		||||
					   struct div_data *data)
 | 
			
		||||
{
 | 
			
		||||
	struct clk *clk;
 | 
			
		||||
	const char *clk_name = node->name;
 | 
			
		||||
	const char *clk_parent;
 | 
			
		||||
	void *reg;
 | 
			
		||||
 | 
			
		||||
	reg = of_iomap(node, 0);
 | 
			
		||||
 | 
			
		||||
	clk_parent = of_clk_get_parent_name(node, 0);
 | 
			
		||||
 | 
			
		||||
	clk = clk_register_divider(NULL, clk_name, clk_parent, 0,
 | 
			
		||||
				   reg, data->shift, SUNXI_DIVISOR_WIDTH,
 | 
			
		||||
				   data->pow ? CLK_DIVIDER_POWER_OF_TWO : 0,
 | 
			
		||||
				   &clk_lock);
 | 
			
		||||
	if (clk) {
 | 
			
		||||
		of_clk_add_provider(node, of_clk_src_simple_get, clk);
 | 
			
		||||
		clk_register_clkdev(clk, clk_name, NULL);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * sunxi_gates_clk_setup() - Setup function for leaf gates on clocks
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define SUNXI_GATES_MAX_SIZE	64
 | 
			
		||||
 | 
			
		||||
struct gates_data {
 | 
			
		||||
	DECLARE_BITMAP(mask, SUNXI_GATES_MAX_SIZE);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const __initconst struct gates_data axi_gates_data = {
 | 
			
		||||
	.mask = {1},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const __initconst struct gates_data ahb_gates_data = {
 | 
			
		||||
	.mask = {0x7F77FFF, 0x14FB3F},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const __initconst struct gates_data apb0_gates_data = {
 | 
			
		||||
	.mask = {0x4EF},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const __initconst struct gates_data apb1_gates_data = {
 | 
			
		||||
	.mask = {0xFF00F7},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void __init sunxi_gates_clk_setup(struct device_node *node,
 | 
			
		||||
					 struct gates_data *data)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_onecell_data *clk_data;
 | 
			
		||||
	const char *clk_parent;
 | 
			
		||||
	const char *clk_name;
 | 
			
		||||
	void *reg;
 | 
			
		||||
	int qty;
 | 
			
		||||
	int i = 0;
 | 
			
		||||
	int j = 0;
 | 
			
		||||
	int ignore;
 | 
			
		||||
 | 
			
		||||
	reg = of_iomap(node, 0);
 | 
			
		||||
 | 
			
		||||
	clk_parent = of_clk_get_parent_name(node, 0);
 | 
			
		||||
 | 
			
		||||
	/* Worst-case size approximation and memory allocation */
 | 
			
		||||
	qty = find_last_bit(data->mask, SUNXI_GATES_MAX_SIZE);
 | 
			
		||||
	clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
 | 
			
		||||
	if (!clk_data)
 | 
			
		||||
		return;
 | 
			
		||||
	clk_data->clks = kzalloc((qty+1) * sizeof(struct clk *), GFP_KERNEL);
 | 
			
		||||
	if (!clk_data->clks) {
 | 
			
		||||
		kfree(clk_data);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for_each_set_bit(i, data->mask, SUNXI_GATES_MAX_SIZE) {
 | 
			
		||||
		of_property_read_string_index(node, "clock-output-names",
 | 
			
		||||
					      j, &clk_name);
 | 
			
		||||
 | 
			
		||||
		/* No driver claims this clock, but it should remain gated */
 | 
			
		||||
		ignore = !strcmp("ahb_sdram", clk_name) ? CLK_IGNORE_UNUSED : 0;
 | 
			
		||||
 | 
			
		||||
		clk_data->clks[i] = clk_register_gate(NULL, clk_name,
 | 
			
		||||
						      clk_parent, ignore,
 | 
			
		||||
						      reg + 4 * (i/32), i % 32,
 | 
			
		||||
						      0, &clk_lock);
 | 
			
		||||
		WARN_ON(IS_ERR(clk_data->clks[i]));
 | 
			
		||||
 | 
			
		||||
		j++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Adjust to the real max */
 | 
			
		||||
	clk_data->clk_num = i;
 | 
			
		||||
 | 
			
		||||
	of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Matches for of_clk_init */
 | 
			
		||||
static const __initconst struct of_device_id clk_match[] = {
 | 
			
		||||
	{.compatible = "allwinner,sun4i-osc-clk", .data = sunxi_osc_clk_setup,},
 | 
			
		||||
	{}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Matches for factors clocks */
 | 
			
		||||
static const __initconst struct of_device_id clk_factors_match[] = {
 | 
			
		||||
	{.compatible = "allwinner,sun4i-pll1-clk", .data = &pll1_data,},
 | 
			
		||||
	{.compatible = "allwinner,sun4i-apb1-clk", .data = &apb1_data,},
 | 
			
		||||
	{}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Matches for divider clocks */
 | 
			
		||||
static const __initconst struct of_device_id clk_div_match[] = {
 | 
			
		||||
	{.compatible = "allwinner,sun4i-axi-clk", .data = &axi_data,},
 | 
			
		||||
	{.compatible = "allwinner,sun4i-ahb-clk", .data = &ahb_data,},
 | 
			
		||||
	{.compatible = "allwinner,sun4i-apb0-clk", .data = &apb0_data,},
 | 
			
		||||
	{}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Matches for mux clocks */
 | 
			
		||||
static const __initconst struct of_device_id clk_mux_match[] = {
 | 
			
		||||
	{.compatible = "allwinner,sun4i-cpu-clk", .data = &cpu_data,},
 | 
			
		||||
	{.compatible = "allwinner,sun4i-apb1-mux-clk", .data = &apb1_mux_data,},
 | 
			
		||||
	{}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Matches for gate clocks */
 | 
			
		||||
static const __initconst struct of_device_id clk_gates_match[] = {
 | 
			
		||||
	{.compatible = "allwinner,sun4i-axi-gates-clk", .data = &axi_gates_data,},
 | 
			
		||||
	{.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &ahb_gates_data,},
 | 
			
		||||
	{.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &apb0_gates_data,},
 | 
			
		||||
	{.compatible = "allwinner,sun4i-apb1-gates-clk", .data = &apb1_gates_data,},
 | 
			
		||||
	{}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void __init of_sunxi_table_clock_setup(const struct of_device_id *clk_match,
 | 
			
		||||
					      void *function)
 | 
			
		||||
{
 | 
			
		||||
	struct device_node *np;
 | 
			
		||||
	const struct div_data *data;
 | 
			
		||||
	const struct of_device_id *match;
 | 
			
		||||
	void (*setup_function)(struct device_node *, const void *) = function;
 | 
			
		||||
 | 
			
		||||
	for_each_matching_node(np, clk_match) {
 | 
			
		||||
		match = of_match_node(clk_match, np);
 | 
			
		||||
		data = match->data;
 | 
			
		||||
		setup_function(np, data);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __init sunxi_init_clocks(void)
 | 
			
		||||
{
 | 
			
		||||
	/* Register all the simple sunxi clocks on DT */
 | 
			
		||||
	of_clk_init(clk_match);
 | 
			
		||||
 | 
			
		||||
	/* Register factor clocks */
 | 
			
		||||
	of_sunxi_table_clock_setup(clk_factors_match, sunxi_factors_clk_setup);
 | 
			
		||||
 | 
			
		||||
	/* Register divider clocks */
 | 
			
		||||
	of_sunxi_table_clock_setup(clk_div_match, sunxi_divider_clk_setup);
 | 
			
		||||
 | 
			
		||||
	/* Register mux clocks */
 | 
			
		||||
	of_sunxi_table_clock_setup(clk_mux_match, sunxi_mux_clk_setup);
 | 
			
		||||
 | 
			
		||||
	/* Register gate clocks */
 | 
			
		||||
	of_sunxi_table_clock_setup(clk_gates_match, sunxi_gates_clk_setup);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -355,15 +355,16 @@ struct clk *tegra_clk_register_periph_nodiv(const char *name,
 | 
			
		|||
		struct tegra_clk_periph *periph, void __iomem *clk_base,
 | 
			
		||||
		u32 offset);
 | 
			
		||||
 | 
			
		||||
#define TEGRA_CLK_PERIPH(_mux_shift, _mux_width, _mux_flags,		\
 | 
			
		||||
#define TEGRA_CLK_PERIPH(_mux_shift, _mux_mask, _mux_flags,		\
 | 
			
		||||
			 _div_shift, _div_width, _div_frac_width,	\
 | 
			
		||||
			 _div_flags, _clk_num, _enb_refcnt, _regs,	\
 | 
			
		||||
			 _gate_flags)					\
 | 
			
		||||
			 _gate_flags, _table)				\
 | 
			
		||||
	{								\
 | 
			
		||||
		.mux = {						\
 | 
			
		||||
			.flags = _mux_flags,				\
 | 
			
		||||
			.shift = _mux_shift,				\
 | 
			
		||||
			.width = _mux_width,				\
 | 
			
		||||
			.mask = _mux_mask,				\
 | 
			
		||||
			.table = _table,				\
 | 
			
		||||
		},							\
 | 
			
		||||
		.divider = {						\
 | 
			
		||||
			.flags = _div_flags,				\
 | 
			
		||||
| 
						 | 
				
			
			@ -393,26 +394,36 @@ struct tegra_periph_init_data {
 | 
			
		|||
	const char *dev_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parent_names, _offset, \
 | 
			
		||||
			_mux_shift, _mux_width, _mux_flags, _div_shift,	\
 | 
			
		||||
#define TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parent_names, _offset,\
 | 
			
		||||
			_mux_shift, _mux_mask, _mux_flags, _div_shift,	\
 | 
			
		||||
			_div_width, _div_frac_width, _div_flags, _regs,	\
 | 
			
		||||
			_clk_num, _enb_refcnt, _gate_flags, _clk_id)	\
 | 
			
		||||
			_clk_num, _enb_refcnt, _gate_flags, _clk_id, _table) \
 | 
			
		||||
	{								\
 | 
			
		||||
		.name = _name,						\
 | 
			
		||||
		.clk_id = _clk_id,					\
 | 
			
		||||
		.parent_names = _parent_names,				\
 | 
			
		||||
		.num_parents = ARRAY_SIZE(_parent_names),		\
 | 
			
		||||
		.periph = TEGRA_CLK_PERIPH(_mux_shift, _mux_width,	\
 | 
			
		||||
		.periph = TEGRA_CLK_PERIPH(_mux_shift, _mux_mask,	\
 | 
			
		||||
					   _mux_flags, _div_shift,	\
 | 
			
		||||
					   _div_width, _div_frac_width,	\
 | 
			
		||||
					   _div_flags, _clk_num,	\
 | 
			
		||||
					   _enb_refcnt, _regs,		\
 | 
			
		||||
					   _gate_flags),		\
 | 
			
		||||
					   _gate_flags, _table),	\
 | 
			
		||||
		.offset = _offset,					\
 | 
			
		||||
		.con_id = _con_id,					\
 | 
			
		||||
		.dev_id = _dev_id,					\
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#define TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parent_names, _offset,\
 | 
			
		||||
			_mux_shift, _mux_width, _mux_flags, _div_shift,	\
 | 
			
		||||
			_div_width, _div_frac_width, _div_flags, _regs,	\
 | 
			
		||||
			_clk_num, _enb_refcnt, _gate_flags, _clk_id)	\
 | 
			
		||||
	TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parent_names, _offset,\
 | 
			
		||||
			_mux_shift, BIT(_mux_width) - 1, _mux_flags,	\
 | 
			
		||||
			_div_shift, _div_width, _div_frac_width, _div_flags, \
 | 
			
		||||
			_regs, _clk_num, _enb_refcnt, _gate_flags, _clk_id,\
 | 
			
		||||
			NULL)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct clk_super_mux - super clock
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@
 | 
			
		|||
# Clock types
 | 
			
		||||
obj-y += clk-prcc.o
 | 
			
		||||
obj-y += clk-prcmu.o
 | 
			
		||||
obj-y += clk-sysctrl.o
 | 
			
		||||
 | 
			
		||||
# Clock definitions
 | 
			
		||||
obj-y += u8500_clk.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,13 +12,78 @@
 | 
			
		|||
#include <linux/device.h>
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/mfd/abx500/ab8500.h>
 | 
			
		||||
 | 
			
		||||
/* TODO: Add clock implementations here */
 | 
			
		||||
 | 
			
		||||
#include <linux/mfd/abx500/ab8500-sysctrl.h>
 | 
			
		||||
#include <linux/clk.h>
 | 
			
		||||
#include <linux/clkdev.h>
 | 
			
		||||
#include <linux/clk-provider.h>
 | 
			
		||||
#include <linux/mfd/dbx500-prcmu.h>
 | 
			
		||||
#include "clk.h"
 | 
			
		||||
 | 
			
		||||
/* Clock definitions for ab8500 */
 | 
			
		||||
static int ab8500_reg_clks(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct clk *clk;
 | 
			
		||||
 | 
			
		||||
	const char *intclk_parents[] = {"ab8500_sysclk", "ulpclk"};
 | 
			
		||||
	u16 intclk_reg_sel[] = {0 , AB8500_SYSULPCLKCTRL1};
 | 
			
		||||
	u8 intclk_reg_mask[] = {0 , AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_MASK};
 | 
			
		||||
	u8 intclk_reg_bits[] = {
 | 
			
		||||
		0 ,
 | 
			
		||||
		(1 << AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_SHIFT)
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	dev_info(dev, "register clocks for ab850x\n");
 | 
			
		||||
 | 
			
		||||
	/* Enable SWAT */
 | 
			
		||||
	ret = ab8500_sysctrl_set(AB8500_SWATCTRL, AB8500_SWATCTRL_SWATENABLE);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	/* ab8500_sysclk */
 | 
			
		||||
	clk = clk_reg_prcmu_gate("ab8500_sysclk", NULL, PRCMU_SYSCLK,
 | 
			
		||||
				CLK_IS_ROOT);
 | 
			
		||||
	clk_register_clkdev(clk, "sysclk", "ab8500-usb.0");
 | 
			
		||||
	clk_register_clkdev(clk, "sysclk", "ab-iddet.0");
 | 
			
		||||
	clk_register_clkdev(clk, "sysclk", "ab85xx-codec.0");
 | 
			
		||||
	clk_register_clkdev(clk, "sysclk", "shrm_bus");
 | 
			
		||||
 | 
			
		||||
	/* ab8500_sysclk2 */
 | 
			
		||||
	clk = clk_reg_sysctrl_gate(dev , "ab8500_sysclk2", "ab8500_sysclk",
 | 
			
		||||
		AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ,
 | 
			
		||||
		AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ, 0, 0);
 | 
			
		||||
	clk_register_clkdev(clk, "sysclk", "0-0070");
 | 
			
		||||
 | 
			
		||||
	/* ab8500_sysclk3 */
 | 
			
		||||
	clk = clk_reg_sysctrl_gate(dev , "ab8500_sysclk3", "ab8500_sysclk",
 | 
			
		||||
		AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ,
 | 
			
		||||
		AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ, 0, 0);
 | 
			
		||||
	clk_register_clkdev(clk, "sysclk", "cg1960_core.0");
 | 
			
		||||
 | 
			
		||||
	/* ab8500_sysclk4 */
 | 
			
		||||
	clk = clk_reg_sysctrl_gate(dev , "ab8500_sysclk4", "ab8500_sysclk",
 | 
			
		||||
		AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ,
 | 
			
		||||
		AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ, 0, 0);
 | 
			
		||||
 | 
			
		||||
	/* ab_ulpclk */
 | 
			
		||||
	clk = clk_reg_sysctrl_gate_fixed_rate(dev, "ulpclk", NULL,
 | 
			
		||||
		AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_ULPCLKREQ,
 | 
			
		||||
		AB8500_SYSULPCLKCTRL1_ULPCLKREQ,
 | 
			
		||||
		38400000, 9000, CLK_IS_ROOT);
 | 
			
		||||
	clk_register_clkdev(clk, "ulpclk", "ab85xx-codec.0");
 | 
			
		||||
 | 
			
		||||
	/* ab8500_intclk */
 | 
			
		||||
	clk = clk_reg_sysctrl_set_parent(dev , "intclk", intclk_parents, 2,
 | 
			
		||||
		intclk_reg_sel, intclk_reg_mask, intclk_reg_bits, 0);
 | 
			
		||||
	clk_register_clkdev(clk, "intclk", "ab85xx-codec.0");
 | 
			
		||||
	clk_register_clkdev(clk, NULL, "ab8500-pwm.1");
 | 
			
		||||
 | 
			
		||||
	/* ab8500_audioclk */
 | 
			
		||||
	clk = clk_reg_sysctrl_gate(dev , "audioclk", "intclk",
 | 
			
		||||
		AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_AUDIOCLKENA,
 | 
			
		||||
		AB8500_SYSULPCLKCTRL1_AUDIOCLKENA, 0, 0);
 | 
			
		||||
	clk_register_clkdev(clk, "audioclk", "ab85xx-codec.0");
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,15 +20,23 @@
 | 
			
		|||
struct clk_prcmu {
 | 
			
		||||
	struct clk_hw hw;
 | 
			
		||||
	u8 cg_sel;
 | 
			
		||||
	int is_prepared;
 | 
			
		||||
	int is_enabled;
 | 
			
		||||
	int opp_requested;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* PRCMU clock operations. */
 | 
			
		||||
 | 
			
		||||
static int clk_prcmu_prepare(struct clk_hw *hw)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct clk_prcmu *clk = to_clk_prcmu(hw);
 | 
			
		||||
	return prcmu_request_clock(clk->cg_sel, true);
 | 
			
		||||
 | 
			
		||||
	ret = prcmu_request_clock(clk->cg_sel, true);
 | 
			
		||||
	if (!ret)
 | 
			
		||||
		clk->is_prepared = 1;
 | 
			
		||||
 | 
			
		||||
	return ret;;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void clk_prcmu_unprepare(struct clk_hw *hw)
 | 
			
		||||
| 
						 | 
				
			
			@ -36,7 +44,15 @@ static void clk_prcmu_unprepare(struct clk_hw *hw)
 | 
			
		|||
	struct clk_prcmu *clk = to_clk_prcmu(hw);
 | 
			
		||||
	if (prcmu_request_clock(clk->cg_sel, false))
 | 
			
		||||
		pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
 | 
			
		||||
			hw->init->name);
 | 
			
		||||
			__clk_get_name(hw->clk));
 | 
			
		||||
	else
 | 
			
		||||
		clk->is_prepared = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int clk_prcmu_is_prepared(struct clk_hw *hw)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_prcmu *clk = to_clk_prcmu(hw);
 | 
			
		||||
	return clk->is_prepared;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int clk_prcmu_enable(struct clk_hw *hw)
 | 
			
		||||
| 
						 | 
				
			
			@ -79,58 +95,52 @@ static int clk_prcmu_set_rate(struct clk_hw *hw, unsigned long rate,
 | 
			
		|||
	return prcmu_set_clock_rate(clk->cg_sel, rate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int request_ape_opp100(bool enable)
 | 
			
		||||
{
 | 
			
		||||
	static int reqs;
 | 
			
		||||
	int err = 0;
 | 
			
		||||
 | 
			
		||||
	if (enable) {
 | 
			
		||||
		if (!reqs)
 | 
			
		||||
			err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP,
 | 
			
		||||
							"clock", 100);
 | 
			
		||||
		if (!err)
 | 
			
		||||
			reqs++;
 | 
			
		||||
	} else {
 | 
			
		||||
		reqs--;
 | 
			
		||||
		if (!reqs)
 | 
			
		||||
			prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
 | 
			
		||||
						"clock");
 | 
			
		||||
	}
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int clk_prcmu_opp_prepare(struct clk_hw *hw)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	struct clk_prcmu *clk = to_clk_prcmu(hw);
 | 
			
		||||
 | 
			
		||||
	err = request_ape_opp100(true);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		pr_err("clk_prcmu: %s failed to request APE OPP100 for %s.\n",
 | 
			
		||||
			__func__, hw->init->name);
 | 
			
		||||
		return err;
 | 
			
		||||
	if (!clk->opp_requested) {
 | 
			
		||||
		err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP,
 | 
			
		||||
						(char *)__clk_get_name(hw->clk),
 | 
			
		||||
						100);
 | 
			
		||||
		if (err) {
 | 
			
		||||
			pr_err("clk_prcmu: %s fail req APE OPP for %s.\n",
 | 
			
		||||
				__func__, __clk_get_name(hw->clk));
 | 
			
		||||
			return err;
 | 
			
		||||
		}
 | 
			
		||||
		clk->opp_requested = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = prcmu_request_clock(clk->cg_sel, true);
 | 
			
		||||
	if (err)
 | 
			
		||||
		request_ape_opp100(false);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
 | 
			
		||||
					(char *)__clk_get_name(hw->clk));
 | 
			
		||||
		clk->opp_requested = 0;
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
	clk->is_prepared = 1;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void clk_prcmu_opp_unprepare(struct clk_hw *hw)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_prcmu *clk = to_clk_prcmu(hw);
 | 
			
		||||
 | 
			
		||||
	if (prcmu_request_clock(clk->cg_sel, false))
 | 
			
		||||
		goto out_error;
 | 
			
		||||
	if (request_ape_opp100(false))
 | 
			
		||||
		goto out_error;
 | 
			
		||||
	return;
 | 
			
		||||
	if (prcmu_request_clock(clk->cg_sel, false)) {
 | 
			
		||||
		pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
 | 
			
		||||
			__clk_get_name(hw->clk));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
out_error:
 | 
			
		||||
	pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
 | 
			
		||||
		hw->init->name);
 | 
			
		||||
	if (clk->opp_requested) {
 | 
			
		||||
		prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
 | 
			
		||||
					(char *)__clk_get_name(hw->clk));
 | 
			
		||||
		clk->opp_requested = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	clk->is_prepared = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw)
 | 
			
		||||
| 
						 | 
				
			
			@ -138,38 +148,49 @@ static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw)
 | 
			
		|||
	int err;
 | 
			
		||||
	struct clk_prcmu *clk = to_clk_prcmu(hw);
 | 
			
		||||
 | 
			
		||||
	err = prcmu_request_ape_opp_100_voltage(true);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		pr_err("clk_prcmu: %s failed to request APE OPP VOLT for %s.\n",
 | 
			
		||||
			__func__, hw->init->name);
 | 
			
		||||
		return err;
 | 
			
		||||
	if (!clk->opp_requested) {
 | 
			
		||||
		err = prcmu_request_ape_opp_100_voltage(true);
 | 
			
		||||
		if (err) {
 | 
			
		||||
			pr_err("clk_prcmu: %s fail req APE OPP VOLT for %s.\n",
 | 
			
		||||
				__func__, __clk_get_name(hw->clk));
 | 
			
		||||
			return err;
 | 
			
		||||
		}
 | 
			
		||||
		clk->opp_requested = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = prcmu_request_clock(clk->cg_sel, true);
 | 
			
		||||
	if (err)
 | 
			
		||||
	if (err) {
 | 
			
		||||
		prcmu_request_ape_opp_100_voltage(false);
 | 
			
		||||
		clk->opp_requested = 0;
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
	clk->is_prepared = 1;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void clk_prcmu_opp_volt_unprepare(struct clk_hw *hw)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_prcmu *clk = to_clk_prcmu(hw);
 | 
			
		||||
 | 
			
		||||
	if (prcmu_request_clock(clk->cg_sel, false))
 | 
			
		||||
		goto out_error;
 | 
			
		||||
	if (prcmu_request_ape_opp_100_voltage(false))
 | 
			
		||||
		goto out_error;
 | 
			
		||||
	return;
 | 
			
		||||
	if (prcmu_request_clock(clk->cg_sel, false)) {
 | 
			
		||||
		pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
 | 
			
		||||
			__clk_get_name(hw->clk));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
out_error:
 | 
			
		||||
	pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
 | 
			
		||||
		hw->init->name);
 | 
			
		||||
	if (clk->opp_requested) {
 | 
			
		||||
		prcmu_request_ape_opp_100_voltage(false);
 | 
			
		||||
		clk->opp_requested = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	clk->is_prepared = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct clk_ops clk_prcmu_scalable_ops = {
 | 
			
		||||
	.prepare = clk_prcmu_prepare,
 | 
			
		||||
	.unprepare = clk_prcmu_unprepare,
 | 
			
		||||
	.is_prepared = clk_prcmu_is_prepared,
 | 
			
		||||
	.enable = clk_prcmu_enable,
 | 
			
		||||
	.disable = clk_prcmu_disable,
 | 
			
		||||
	.is_enabled = clk_prcmu_is_enabled,
 | 
			
		||||
| 
						 | 
				
			
			@ -181,6 +202,7 @@ static struct clk_ops clk_prcmu_scalable_ops = {
 | 
			
		|||
static struct clk_ops clk_prcmu_gate_ops = {
 | 
			
		||||
	.prepare = clk_prcmu_prepare,
 | 
			
		||||
	.unprepare = clk_prcmu_unprepare,
 | 
			
		||||
	.is_prepared = clk_prcmu_is_prepared,
 | 
			
		||||
	.enable = clk_prcmu_enable,
 | 
			
		||||
	.disable = clk_prcmu_disable,
 | 
			
		||||
	.is_enabled = clk_prcmu_is_enabled,
 | 
			
		||||
| 
						 | 
				
			
			@ -202,6 +224,7 @@ static struct clk_ops clk_prcmu_rate_ops = {
 | 
			
		|||
static struct clk_ops clk_prcmu_opp_gate_ops = {
 | 
			
		||||
	.prepare = clk_prcmu_opp_prepare,
 | 
			
		||||
	.unprepare = clk_prcmu_opp_unprepare,
 | 
			
		||||
	.is_prepared = clk_prcmu_is_prepared,
 | 
			
		||||
	.enable = clk_prcmu_enable,
 | 
			
		||||
	.disable = clk_prcmu_disable,
 | 
			
		||||
	.is_enabled = clk_prcmu_is_enabled,
 | 
			
		||||
| 
						 | 
				
			
			@ -211,6 +234,7 @@ static struct clk_ops clk_prcmu_opp_gate_ops = {
 | 
			
		|||
static struct clk_ops clk_prcmu_opp_volt_scalable_ops = {
 | 
			
		||||
	.prepare = clk_prcmu_opp_volt_prepare,
 | 
			
		||||
	.unprepare = clk_prcmu_opp_volt_unprepare,
 | 
			
		||||
	.is_prepared = clk_prcmu_is_prepared,
 | 
			
		||||
	.enable = clk_prcmu_enable,
 | 
			
		||||
	.disable = clk_prcmu_disable,
 | 
			
		||||
	.is_enabled = clk_prcmu_is_enabled,
 | 
			
		||||
| 
						 | 
				
			
			@ -242,7 +266,9 @@ static struct clk *clk_reg_prcmu(const char *name,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	clk->cg_sel = cg_sel;
 | 
			
		||||
	clk->is_prepared = 1;
 | 
			
		||||
	clk->is_enabled = 1;
 | 
			
		||||
	clk->opp_requested = 0;
 | 
			
		||||
	/* "rate" can be used for changing the initial frequency */
 | 
			
		||||
	if (rate)
 | 
			
		||||
		prcmu_set_clock_rate(cg_sel, rate);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										221
									
								
								drivers/clk/ux500/clk-sysctrl.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										221
									
								
								drivers/clk/ux500/clk-sysctrl.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,221 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Sysctrl clock implementation for ux500 platform.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2013 ST-Ericsson SA
 | 
			
		||||
 * Author: Ulf Hansson <ulf.hansson@linaro.org>
 | 
			
		||||
 *
 | 
			
		||||
 * License terms: GNU General Public License (GPL) version 2
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/clk-provider.h>
 | 
			
		||||
#include <linux/mfd/abx500/ab8500-sysctrl.h>
 | 
			
		||||
#include <linux/device.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include <linux/io.h>
 | 
			
		||||
#include <linux/err.h>
 | 
			
		||||
#include "clk.h"
 | 
			
		||||
 | 
			
		||||
#define SYSCTRL_MAX_NUM_PARENTS 4
 | 
			
		||||
 | 
			
		||||
#define to_clk_sysctrl(_hw) container_of(_hw, struct clk_sysctrl, hw)
 | 
			
		||||
 | 
			
		||||
struct clk_sysctrl {
 | 
			
		||||
	struct clk_hw hw;
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
	u8 parent_index;
 | 
			
		||||
	u16 reg_sel[SYSCTRL_MAX_NUM_PARENTS];
 | 
			
		||||
	u8 reg_mask[SYSCTRL_MAX_NUM_PARENTS];
 | 
			
		||||
	u8 reg_bits[SYSCTRL_MAX_NUM_PARENTS];
 | 
			
		||||
	unsigned long rate;
 | 
			
		||||
	unsigned long enable_delay_us;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Sysctrl clock operations. */
 | 
			
		||||
 | 
			
		||||
static int clk_sysctrl_prepare(struct clk_hw *hw)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct clk_sysctrl *clk = to_clk_sysctrl(hw);
 | 
			
		||||
 | 
			
		||||
	ret = ab8500_sysctrl_write(clk->reg_sel[0], clk->reg_mask[0],
 | 
			
		||||
				clk->reg_bits[0]);
 | 
			
		||||
 | 
			
		||||
	if (!ret && clk->enable_delay_us)
 | 
			
		||||
		usleep_range(clk->enable_delay_us, clk->enable_delay_us);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void clk_sysctrl_unprepare(struct clk_hw *hw)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_sysctrl *clk = to_clk_sysctrl(hw);
 | 
			
		||||
	if (ab8500_sysctrl_clear(clk->reg_sel[0], clk->reg_mask[0]))
 | 
			
		||||
		dev_err(clk->dev, "clk_sysctrl: %s fail to clear %s.\n",
 | 
			
		||||
			__func__, __clk_get_name(hw->clk));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned long clk_sysctrl_recalc_rate(struct clk_hw *hw,
 | 
			
		||||
					unsigned long parent_rate)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_sysctrl *clk = to_clk_sysctrl(hw);
 | 
			
		||||
	return clk->rate;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int clk_sysctrl_set_parent(struct clk_hw *hw, u8 index)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_sysctrl *clk = to_clk_sysctrl(hw);
 | 
			
		||||
	u8 old_index = clk->parent_index;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	if (clk->reg_sel[old_index]) {
 | 
			
		||||
		ret = ab8500_sysctrl_clear(clk->reg_sel[old_index],
 | 
			
		||||
					clk->reg_mask[old_index]);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (clk->reg_sel[index]) {
 | 
			
		||||
		ret = ab8500_sysctrl_write(clk->reg_sel[index],
 | 
			
		||||
					clk->reg_mask[index],
 | 
			
		||||
					clk->reg_bits[index]);
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			if (clk->reg_sel[old_index])
 | 
			
		||||
				ab8500_sysctrl_write(clk->reg_sel[old_index],
 | 
			
		||||
						clk->reg_mask[old_index],
 | 
			
		||||
						clk->reg_bits[old_index]);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	clk->parent_index = index;
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static u8 clk_sysctrl_get_parent(struct clk_hw *hw)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_sysctrl *clk = to_clk_sysctrl(hw);
 | 
			
		||||
	return clk->parent_index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct clk_ops clk_sysctrl_gate_ops = {
 | 
			
		||||
	.prepare = clk_sysctrl_prepare,
 | 
			
		||||
	.unprepare = clk_sysctrl_unprepare,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct clk_ops clk_sysctrl_gate_fixed_rate_ops = {
 | 
			
		||||
	.prepare = clk_sysctrl_prepare,
 | 
			
		||||
	.unprepare = clk_sysctrl_unprepare,
 | 
			
		||||
	.recalc_rate = clk_sysctrl_recalc_rate,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct clk_ops clk_sysctrl_set_parent_ops = {
 | 
			
		||||
	.set_parent = clk_sysctrl_set_parent,
 | 
			
		||||
	.get_parent = clk_sysctrl_get_parent,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct clk *clk_reg_sysctrl(struct device *dev,
 | 
			
		||||
				const char *name,
 | 
			
		||||
				const char **parent_names,
 | 
			
		||||
				u8 num_parents,
 | 
			
		||||
				u16 *reg_sel,
 | 
			
		||||
				u8 *reg_mask,
 | 
			
		||||
				u8 *reg_bits,
 | 
			
		||||
				unsigned long rate,
 | 
			
		||||
				unsigned long enable_delay_us,
 | 
			
		||||
				unsigned long flags,
 | 
			
		||||
				struct clk_ops *clk_sysctrl_ops)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_sysctrl *clk;
 | 
			
		||||
	struct clk_init_data clk_sysctrl_init;
 | 
			
		||||
	struct clk *clk_reg;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (!dev)
 | 
			
		||||
		return ERR_PTR(-EINVAL);
 | 
			
		||||
 | 
			
		||||
	if (!name || (num_parents > SYSCTRL_MAX_NUM_PARENTS)) {
 | 
			
		||||
		dev_err(dev, "clk_sysctrl: invalid arguments passed\n");
 | 
			
		||||
		return ERR_PTR(-EINVAL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	clk = devm_kzalloc(dev, sizeof(struct clk_sysctrl), GFP_KERNEL);
 | 
			
		||||
	if (!clk) {
 | 
			
		||||
		dev_err(dev, "clk_sysctrl: could not allocate clk\n");
 | 
			
		||||
		return ERR_PTR(-ENOMEM);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_parents; i++) {
 | 
			
		||||
		clk->reg_sel[i] = reg_sel[i];
 | 
			
		||||
		clk->reg_bits[i] = reg_bits[i];
 | 
			
		||||
		clk->reg_mask[i] = reg_mask[i];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	clk->parent_index = 0;
 | 
			
		||||
	clk->rate = rate;
 | 
			
		||||
	clk->enable_delay_us = enable_delay_us;
 | 
			
		||||
	clk->dev = dev;
 | 
			
		||||
 | 
			
		||||
	clk_sysctrl_init.name = name;
 | 
			
		||||
	clk_sysctrl_init.ops = clk_sysctrl_ops;
 | 
			
		||||
	clk_sysctrl_init.flags = flags;
 | 
			
		||||
	clk_sysctrl_init.parent_names = parent_names;
 | 
			
		||||
	clk_sysctrl_init.num_parents = num_parents;
 | 
			
		||||
	clk->hw.init = &clk_sysctrl_init;
 | 
			
		||||
 | 
			
		||||
	clk_reg = devm_clk_register(clk->dev, &clk->hw);
 | 
			
		||||
	if (IS_ERR(clk_reg))
 | 
			
		||||
		dev_err(dev, "clk_sysctrl: clk_register failed\n");
 | 
			
		||||
 | 
			
		||||
	return clk_reg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct clk *clk_reg_sysctrl_gate(struct device *dev,
 | 
			
		||||
				const char *name,
 | 
			
		||||
				const char *parent_name,
 | 
			
		||||
				u16 reg_sel,
 | 
			
		||||
				u8 reg_mask,
 | 
			
		||||
				u8 reg_bits,
 | 
			
		||||
				unsigned long enable_delay_us,
 | 
			
		||||
				unsigned long flags)
 | 
			
		||||
{
 | 
			
		||||
	const char **parent_names = (parent_name ? &parent_name : NULL);
 | 
			
		||||
	u8 num_parents = (parent_name ? 1 : 0);
 | 
			
		||||
 | 
			
		||||
	return clk_reg_sysctrl(dev, name, parent_names, num_parents,
 | 
			
		||||
			®_sel, ®_mask, ®_bits, 0, enable_delay_us,
 | 
			
		||||
			flags, &clk_sysctrl_gate_ops);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct clk *clk_reg_sysctrl_gate_fixed_rate(struct device *dev,
 | 
			
		||||
					const char *name,
 | 
			
		||||
					const char *parent_name,
 | 
			
		||||
					u16 reg_sel,
 | 
			
		||||
					u8 reg_mask,
 | 
			
		||||
					u8 reg_bits,
 | 
			
		||||
					unsigned long rate,
 | 
			
		||||
					unsigned long enable_delay_us,
 | 
			
		||||
					unsigned long flags)
 | 
			
		||||
{
 | 
			
		||||
	const char **parent_names = (parent_name ? &parent_name : NULL);
 | 
			
		||||
	u8 num_parents = (parent_name ? 1 : 0);
 | 
			
		||||
 | 
			
		||||
	return clk_reg_sysctrl(dev, name, parent_names, num_parents,
 | 
			
		||||
			®_sel, ®_mask, ®_bits,
 | 
			
		||||
			rate, enable_delay_us, flags,
 | 
			
		||||
			&clk_sysctrl_gate_fixed_rate_ops);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct clk *clk_reg_sysctrl_set_parent(struct device *dev,
 | 
			
		||||
				const char *name,
 | 
			
		||||
				const char **parent_names,
 | 
			
		||||
				u8 num_parents,
 | 
			
		||||
				u16 *reg_sel,
 | 
			
		||||
				u8 *reg_mask,
 | 
			
		||||
				u8 *reg_bits,
 | 
			
		||||
				unsigned long flags)
 | 
			
		||||
{
 | 
			
		||||
	return clk_reg_sysctrl(dev, name, parent_names, num_parents,
 | 
			
		||||
			reg_sel, reg_mask, reg_bits, 0, 0, flags,
 | 
			
		||||
			&clk_sysctrl_set_parent_ops);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -11,16 +11,18 @@
 | 
			
		|||
#define __UX500_CLK_H
 | 
			
		||||
 | 
			
		||||
#include <linux/clk.h>
 | 
			
		||||
#include <linux/device.h>
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
 | 
			
		||||
struct clk *clk_reg_prcc_pclk(const char *name,
 | 
			
		||||
			      const char *parent_name,
 | 
			
		||||
			      unsigned int phy_base,
 | 
			
		||||
			      resource_size_t phy_base,
 | 
			
		||||
			      u32 cg_sel,
 | 
			
		||||
			      unsigned long flags);
 | 
			
		||||
 | 
			
		||||
struct clk *clk_reg_prcc_kclk(const char *name,
 | 
			
		||||
			      const char *parent_name,
 | 
			
		||||
			      unsigned int phy_base,
 | 
			
		||||
			      resource_size_t phy_base,
 | 
			
		||||
			      u32 cg_sel,
 | 
			
		||||
			      unsigned long flags);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -57,4 +59,32 @@ struct clk *clk_reg_prcmu_opp_volt_scalable(const char *name,
 | 
			
		|||
					    unsigned long rate,
 | 
			
		||||
					    unsigned long flags);
 | 
			
		||||
 | 
			
		||||
struct clk *clk_reg_sysctrl_gate(struct device *dev,
 | 
			
		||||
				 const char *name,
 | 
			
		||||
				 const char *parent_name,
 | 
			
		||||
				 u16 reg_sel,
 | 
			
		||||
				 u8 reg_mask,
 | 
			
		||||
				 u8 reg_bits,
 | 
			
		||||
				 unsigned long enable_delay_us,
 | 
			
		||||
				 unsigned long flags);
 | 
			
		||||
 | 
			
		||||
struct clk *clk_reg_sysctrl_gate_fixed_rate(struct device *dev,
 | 
			
		||||
					    const char *name,
 | 
			
		||||
					    const char *parent_name,
 | 
			
		||||
					    u16 reg_sel,
 | 
			
		||||
					    u8 reg_mask,
 | 
			
		||||
					    u8 reg_bits,
 | 
			
		||||
					    unsigned long rate,
 | 
			
		||||
					    unsigned long enable_delay_us,
 | 
			
		||||
					    unsigned long flags);
 | 
			
		||||
 | 
			
		||||
struct clk *clk_reg_sysctrl_set_parent(struct device *dev,
 | 
			
		||||
				       const char *name,
 | 
			
		||||
				       const char **parent_names,
 | 
			
		||||
				       u8 num_parents,
 | 
			
		||||
				       u16 *reg_sel,
 | 
			
		||||
				       u8 *reg_mask,
 | 
			
		||||
				       u8 *reg_bits,
 | 
			
		||||
				       unsigned long flags);
 | 
			
		||||
 | 
			
		||||
#endif /* __UX500_CLK_H */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,5 +3,5 @@ obj-$(CONFIG_ICST)		+= clk-icst.o
 | 
			
		|||
obj-$(CONFIG_ARCH_INTEGRATOR)	+= clk-integrator.o
 | 
			
		||||
obj-$(CONFIG_INTEGRATOR_IMPD1)	+= clk-impd1.o
 | 
			
		||||
obj-$(CONFIG_ARCH_REALVIEW)	+= clk-realview.o
 | 
			
		||||
obj-$(CONFIG_ARCH_VEXPRESS)	+= clk-vexpress.o
 | 
			
		||||
obj-$(CONFIG_ARCH_VEXPRESS)	+= clk-vexpress.o clk-sp810.o
 | 
			
		||||
obj-$(CONFIG_VEXPRESS_CONFIG)	+= clk-vexpress-osc.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										188
									
								
								drivers/clk/versatile/clk-sp810.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								drivers/clk/versatile/clk-sp810.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,188 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2013 ARM Limited
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/amba/sp810.h>
 | 
			
		||||
#include <linux/clkdev.h>
 | 
			
		||||
#include <linux/clk-provider.h>
 | 
			
		||||
#include <linux/err.h>
 | 
			
		||||
#include <linux/of.h>
 | 
			
		||||
#include <linux/of_address.h>
 | 
			
		||||
 | 
			
		||||
#define to_clk_sp810_timerclken(_hw) \
 | 
			
		||||
		container_of(_hw, struct clk_sp810_timerclken, hw)
 | 
			
		||||
 | 
			
		||||
struct clk_sp810;
 | 
			
		||||
 | 
			
		||||
struct clk_sp810_timerclken {
 | 
			
		||||
	struct clk_hw hw;
 | 
			
		||||
	struct clk *clk;
 | 
			
		||||
	struct clk_sp810 *sp810;
 | 
			
		||||
	int channel;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct clk_sp810 {
 | 
			
		||||
	struct device_node *node;
 | 
			
		||||
	int refclk_index, timclk_index;
 | 
			
		||||
	void __iomem *base;
 | 
			
		||||
	spinlock_t lock;
 | 
			
		||||
	struct clk_sp810_timerclken timerclken[4];
 | 
			
		||||
	struct clk *refclk;
 | 
			
		||||
	struct clk *timclk;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static u8 clk_sp810_timerclken_get_parent(struct clk_hw *hw)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw);
 | 
			
		||||
	u32 val = readl(timerclken->sp810->base + SCCTRL);
 | 
			
		||||
 | 
			
		||||
	return !!(val & (1 << SCCTRL_TIMERENnSEL_SHIFT(timerclken->channel)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int clk_sp810_timerclken_set_parent(struct clk_hw *hw, u8 index)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw);
 | 
			
		||||
	struct clk_sp810 *sp810 = timerclken->sp810;
 | 
			
		||||
	u32 val, shift = SCCTRL_TIMERENnSEL_SHIFT(timerclken->channel);
 | 
			
		||||
	unsigned long flags = 0;
 | 
			
		||||
 | 
			
		||||
	if (WARN_ON(index > 1))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&sp810->lock, flags);
 | 
			
		||||
 | 
			
		||||
	val = readl(sp810->base + SCCTRL);
 | 
			
		||||
	val &= ~(1 << shift);
 | 
			
		||||
	val |= index << shift;
 | 
			
		||||
	writel(val, sp810->base + SCCTRL);
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&sp810->lock, flags);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * FIXME - setting the parent every time .prepare is invoked is inefficient.
 | 
			
		||||
 * This is better handled by a dedicated clock tree configuration mechanism at
 | 
			
		||||
 * init-time.  Revisit this later when such a mechanism exists
 | 
			
		||||
 */
 | 
			
		||||
static int clk_sp810_timerclken_prepare(struct clk_hw *hw)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw);
 | 
			
		||||
	struct clk_sp810 *sp810 = timerclken->sp810;
 | 
			
		||||
	struct clk *old_parent = __clk_get_parent(hw->clk);
 | 
			
		||||
	struct clk *new_parent;
 | 
			
		||||
 | 
			
		||||
	if (!sp810->refclk)
 | 
			
		||||
		sp810->refclk = of_clk_get(sp810->node, sp810->refclk_index);
 | 
			
		||||
 | 
			
		||||
	if (!sp810->timclk)
 | 
			
		||||
		sp810->timclk = of_clk_get(sp810->node, sp810->timclk_index);
 | 
			
		||||
 | 
			
		||||
	if (WARN_ON(IS_ERR(sp810->refclk) || IS_ERR(sp810->timclk)))
 | 
			
		||||
		return -ENOENT;
 | 
			
		||||
 | 
			
		||||
	/* Select fastest parent */
 | 
			
		||||
	if (clk_get_rate(sp810->refclk) > clk_get_rate(sp810->timclk))
 | 
			
		||||
		new_parent = sp810->refclk;
 | 
			
		||||
	else
 | 
			
		||||
		new_parent = sp810->timclk;
 | 
			
		||||
 | 
			
		||||
	/* Switch the parent if necessary */
 | 
			
		||||
	if (old_parent != new_parent) {
 | 
			
		||||
		clk_prepare(new_parent);
 | 
			
		||||
		clk_set_parent(hw->clk, new_parent);
 | 
			
		||||
		clk_unprepare(old_parent);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void clk_sp810_timerclken_unprepare(struct clk_hw *hw)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw);
 | 
			
		||||
	struct clk_sp810 *sp810 = timerclken->sp810;
 | 
			
		||||
 | 
			
		||||
	clk_put(sp810->timclk);
 | 
			
		||||
	clk_put(sp810->refclk);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct clk_ops clk_sp810_timerclken_ops = {
 | 
			
		||||
	.prepare = clk_sp810_timerclken_prepare,
 | 
			
		||||
	.unprepare = clk_sp810_timerclken_unprepare,
 | 
			
		||||
	.get_parent = clk_sp810_timerclken_get_parent,
 | 
			
		||||
	.set_parent = clk_sp810_timerclken_set_parent,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct clk *clk_sp810_timerclken_of_get(struct of_phandle_args *clkspec,
 | 
			
		||||
		void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_sp810 *sp810 = data;
 | 
			
		||||
 | 
			
		||||
	if (WARN_ON(clkspec->args_count != 1 || clkspec->args[0] >
 | 
			
		||||
			ARRAY_SIZE(sp810->timerclken)))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	return sp810->timerclken[clkspec->args[0]].clk;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __init clk_sp810_of_setup(struct device_node *node)
 | 
			
		||||
{
 | 
			
		||||
	struct clk_sp810 *sp810 = kzalloc(sizeof(*sp810), GFP_KERNEL);
 | 
			
		||||
	const char *parent_names[2];
 | 
			
		||||
	char name[12];
 | 
			
		||||
	struct clk_init_data init;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (!sp810) {
 | 
			
		||||
		pr_err("Failed to allocate memory for SP810!\n");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sp810->refclk_index = of_property_match_string(node, "clock-names",
 | 
			
		||||
			"refclk");
 | 
			
		||||
	parent_names[0] = of_clk_get_parent_name(node, sp810->refclk_index);
 | 
			
		||||
 | 
			
		||||
	sp810->timclk_index = of_property_match_string(node, "clock-names",
 | 
			
		||||
			"timclk");
 | 
			
		||||
	parent_names[1] = of_clk_get_parent_name(node, sp810->timclk_index);
 | 
			
		||||
 | 
			
		||||
	if (parent_names[0] <= 0 || parent_names[1] <= 0) {
 | 
			
		||||
		pr_warn("Failed to obtain parent clocks for SP810!\n");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sp810->node = node;
 | 
			
		||||
	sp810->base = of_iomap(node, 0);
 | 
			
		||||
	spin_lock_init(&sp810->lock);
 | 
			
		||||
 | 
			
		||||
	init.name = name;
 | 
			
		||||
	init.ops = &clk_sp810_timerclken_ops;
 | 
			
		||||
	init.flags = CLK_IS_BASIC;
 | 
			
		||||
	init.parent_names = parent_names;
 | 
			
		||||
	init.num_parents = ARRAY_SIZE(parent_names);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(sp810->timerclken); i++) {
 | 
			
		||||
		snprintf(name, ARRAY_SIZE(name), "timerclken%d", i);
 | 
			
		||||
 | 
			
		||||
		sp810->timerclken[i].sp810 = sp810;
 | 
			
		||||
		sp810->timerclken[i].channel = i;
 | 
			
		||||
		sp810->timerclken[i].hw.init = &init;
 | 
			
		||||
 | 
			
		||||
		sp810->timerclken[i].clk = clk_register(NULL,
 | 
			
		||||
				&sp810->timerclken[i].hw);
 | 
			
		||||
		WARN_ON(IS_ERR(sp810->timerclken[i].clk));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	of_clk_add_provider(node, clk_sp810_timerclken_of_get, sp810);
 | 
			
		||||
}
 | 
			
		||||
CLK_OF_DECLARE(sp810, "arm,sp810", clk_sp810_of_setup);
 | 
			
		||||
| 
						 | 
				
			
			@ -15,8 +15,6 @@
 | 
			
		|||
#include <linux/clkdev.h>
 | 
			
		||||
#include <linux/clk-provider.h>
 | 
			
		||||
#include <linux/err.h>
 | 
			
		||||
#include <linux/of.h>
 | 
			
		||||
#include <linux/of_address.h>
 | 
			
		||||
#include <linux/vexpress.h>
 | 
			
		||||
 | 
			
		||||
static struct clk *vexpress_sp810_timerclken[4];
 | 
			
		||||
| 
						 | 
				
			
			@ -86,50 +84,3 @@ void __init vexpress_clk_init(void __iomem *sp810_base)
 | 
			
		|||
	WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[1],
 | 
			
		||||
				"v2m-timer1", "sp804"));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined(CONFIG_OF)
 | 
			
		||||
 | 
			
		||||
struct clk *vexpress_sp810_of_get(struct of_phandle_args *clkspec, void *data)
 | 
			
		||||
{
 | 
			
		||||
	if (WARN_ON(clkspec->args_count != 1 || clkspec->args[0] >
 | 
			
		||||
			ARRAY_SIZE(vexpress_sp810_timerclken)))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	return vexpress_sp810_timerclken[clkspec->args[0]];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __init vexpress_clk_of_init(void)
 | 
			
		||||
{
 | 
			
		||||
	struct device_node *node;
 | 
			
		||||
	struct clk *clk;
 | 
			
		||||
	struct clk *refclk, *timclk;
 | 
			
		||||
 | 
			
		||||
	of_clk_init(NULL);
 | 
			
		||||
 | 
			
		||||
	node = of_find_compatible_node(NULL, NULL, "arm,sp810");
 | 
			
		||||
	vexpress_sp810_init(of_iomap(node, 0));
 | 
			
		||||
	of_clk_add_provider(node, vexpress_sp810_of_get, NULL);
 | 
			
		||||
 | 
			
		||||
	/* Select "better" (faster) parent for SP804 timers */
 | 
			
		||||
	refclk = of_clk_get_by_name(node, "refclk");
 | 
			
		||||
	timclk = of_clk_get_by_name(node, "timclk");
 | 
			
		||||
	if (!WARN_ON(IS_ERR(refclk) || IS_ERR(timclk))) {
 | 
			
		||||
		int i = 0;
 | 
			
		||||
 | 
			
		||||
		if (clk_get_rate(refclk) > clk_get_rate(timclk))
 | 
			
		||||
			clk = refclk;
 | 
			
		||||
		else
 | 
			
		||||
			clk = timclk;
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++)
 | 
			
		||||
			WARN_ON(clk_set_parent(vexpress_sp810_timerclken[i],
 | 
			
		||||
					clk));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[0],
 | 
			
		||||
				"v2m-timer0", "sp804"));
 | 
			
		||||
	WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[1],
 | 
			
		||||
				"v2m-timer1", "sp804"));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@
 | 
			
		|||
#include <linux/of_address.h>
 | 
			
		||||
#include <linux/of_irq.h>
 | 
			
		||||
#include <linux/sunxi_timer.h>
 | 
			
		||||
#include <linux/clk-provider.h>
 | 
			
		||||
#include <linux/clk/sunxi.h>
 | 
			
		||||
 | 
			
		||||
#define TIMER_CTL_REG		0x00
 | 
			
		||||
#define TIMER_CTL_ENABLE		(1 << 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -123,7 +123,7 @@ void __init sunxi_timer_init(void)
 | 
			
		|||
	if (irq <= 0)
 | 
			
		||||
		panic("Can't parse IRQ");
 | 
			
		||||
 | 
			
		||||
	of_clk_init(NULL);
 | 
			
		||||
	sunxi_init_clocks();
 | 
			
		||||
 | 
			
		||||
	clk = of_clk_get(node, 0);
 | 
			
		||||
	if (IS_ERR(clk))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -152,7 +152,7 @@ struct clk {
 | 
			
		|||
		},						\
 | 
			
		||||
		.reg = _reg,					\
 | 
			
		||||
		.shift = _shift,				\
 | 
			
		||||
		.width = _width,				\
 | 
			
		||||
		.mask = BIT(_width) - 1,			\
 | 
			
		||||
		.flags = _mux_flags,				\
 | 
			
		||||
		.lock = _lock,					\
 | 
			
		||||
	};							\
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,6 +45,14 @@ struct clk_hw;
 | 
			
		|||
 * 		undo any work done in the @prepare callback. Called with
 | 
			
		||||
 * 		prepare_lock held.
 | 
			
		||||
 *
 | 
			
		||||
 * @is_prepared: Queries the hardware to determine if the clock is prepared.
 | 
			
		||||
 *		This function is allowed to sleep. Optional, if this op is not
 | 
			
		||||
 *		set then the prepare count will be used.
 | 
			
		||||
 *
 | 
			
		||||
 * @unprepare_unused: Unprepare the clock atomically.  Only called from
 | 
			
		||||
 *		clk_disable_unused for prepare clocks with special needs.
 | 
			
		||||
 *		Called with prepare mutex held. This function may sleep.
 | 
			
		||||
 *
 | 
			
		||||
 * @enable:	Enable the clock atomically. This must not return until the
 | 
			
		||||
 * 		clock is generating a valid clock signal, usable by consumer
 | 
			
		||||
 * 		devices. Called with enable_lock held. This function must not
 | 
			
		||||
| 
						 | 
				
			
			@ -108,6 +116,8 @@ struct clk_hw;
 | 
			
		|||
struct clk_ops {
 | 
			
		||||
	int		(*prepare)(struct clk_hw *hw);
 | 
			
		||||
	void		(*unprepare)(struct clk_hw *hw);
 | 
			
		||||
	int		(*is_prepared)(struct clk_hw *hw);
 | 
			
		||||
	void		(*unprepare_unused)(struct clk_hw *hw);
 | 
			
		||||
	int		(*enable)(struct clk_hw *hw);
 | 
			
		||||
	void		(*disable)(struct clk_hw *hw);
 | 
			
		||||
	int		(*is_enabled)(struct clk_hw *hw);
 | 
			
		||||
| 
						 | 
				
			
			@ -239,9 +249,14 @@ struct clk_div_table {
 | 
			
		|||
 * CLK_DIVIDER_ONE_BASED - by default the divisor is the value read from the
 | 
			
		||||
 * 	register plus one.  If CLK_DIVIDER_ONE_BASED is set then the divider is
 | 
			
		||||
 * 	the raw value read from the register, with the value of zero considered
 | 
			
		||||
 * 	invalid
 | 
			
		||||
 *	invalid, unless CLK_DIVIDER_ALLOW_ZERO is set.
 | 
			
		||||
 * CLK_DIVIDER_POWER_OF_TWO - clock divisor is 2 raised to the value read from
 | 
			
		||||
 * 	the hardware register
 | 
			
		||||
 * CLK_DIVIDER_ALLOW_ZERO - Allow zero divisors.  For dividers which have
 | 
			
		||||
 *	CLK_DIVIDER_ONE_BASED set, it is possible to end up with a zero divisor.
 | 
			
		||||
 *	Some hardware implementations gracefully handle this case and allow a
 | 
			
		||||
 *	zero divisor by not modifying their input clock
 | 
			
		||||
 *	(divide by one / bypass).
 | 
			
		||||
 */
 | 
			
		||||
struct clk_divider {
 | 
			
		||||
	struct clk_hw	hw;
 | 
			
		||||
| 
						 | 
				
			
			@ -255,6 +270,7 @@ struct clk_divider {
 | 
			
		|||
 | 
			
		||||
#define CLK_DIVIDER_ONE_BASED		BIT(0)
 | 
			
		||||
#define CLK_DIVIDER_POWER_OF_TWO	BIT(1)
 | 
			
		||||
#define CLK_DIVIDER_ALLOW_ZERO		BIT(2)
 | 
			
		||||
 | 
			
		||||
extern const struct clk_ops clk_divider_ops;
 | 
			
		||||
struct clk *clk_register_divider(struct device *dev, const char *name,
 | 
			
		||||
| 
						 | 
				
			
			@ -274,7 +290,7 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
 | 
			
		|||
 * @reg:	register controlling multiplexer
 | 
			
		||||
 * @shift:	shift to multiplexer bit field
 | 
			
		||||
 * @width:	width of mutliplexer bit field
 | 
			
		||||
 * @num_clks:	number of parent clocks
 | 
			
		||||
 * @flags:	hardware-specific flags
 | 
			
		||||
 * @lock:	register lock
 | 
			
		||||
 *
 | 
			
		||||
 * Clock with multiple selectable parents.  Implements .get_parent, .set_parent
 | 
			
		||||
| 
						 | 
				
			
			@ -287,8 +303,9 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
 | 
			
		|||
struct clk_mux {
 | 
			
		||||
	struct clk_hw	hw;
 | 
			
		||||
	void __iomem	*reg;
 | 
			
		||||
	u32		*table;
 | 
			
		||||
	u32		mask;
 | 
			
		||||
	u8		shift;
 | 
			
		||||
	u8		width;
 | 
			
		||||
	u8		flags;
 | 
			
		||||
	spinlock_t	*lock;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -297,11 +314,19 @@ struct clk_mux {
 | 
			
		|||
#define CLK_MUX_INDEX_BIT		BIT(1)
 | 
			
		||||
 | 
			
		||||
extern const struct clk_ops clk_mux_ops;
 | 
			
		||||
 | 
			
		||||
struct clk *clk_register_mux(struct device *dev, const char *name,
 | 
			
		||||
		const char **parent_names, u8 num_parents, unsigned long flags,
 | 
			
		||||
		void __iomem *reg, u8 shift, u8 width,
 | 
			
		||||
		u8 clk_mux_flags, spinlock_t *lock);
 | 
			
		||||
 | 
			
		||||
struct clk *clk_register_mux_table(struct device *dev, const char *name,
 | 
			
		||||
		const char **parent_names, u8 num_parents, unsigned long flags,
 | 
			
		||||
		void __iomem *reg, u8 shift, u32 mask,
 | 
			
		||||
		u8 clk_mux_flags, u32 *table, spinlock_t *lock);
 | 
			
		||||
 | 
			
		||||
void of_fixed_factor_clk_setup(struct device_node *node);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct clk_fixed_factor - fixed multiplier and divider clock
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -325,6 +350,37 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
 | 
			
		|||
		const char *parent_name, unsigned long flags,
 | 
			
		||||
		unsigned int mult, unsigned int div);
 | 
			
		||||
 | 
			
		||||
/***
 | 
			
		||||
 * struct clk_composite - aggregate clock of mux, divider and gate clocks
 | 
			
		||||
 *
 | 
			
		||||
 * @hw:		handle between common and hardware-specific interfaces
 | 
			
		||||
 * @mux_hw:	handle between composite and hardware-specific mux clock
 | 
			
		||||
 * @rate_hw:	handle between composite and hardware-specific rate clock
 | 
			
		||||
 * @gate_hw:	handle between composite and hardware-specific gate clock
 | 
			
		||||
 * @mux_ops:	clock ops for mux
 | 
			
		||||
 * @rate_ops:	clock ops for rate
 | 
			
		||||
 * @gate_ops:	clock ops for gate
 | 
			
		||||
 */
 | 
			
		||||
struct clk_composite {
 | 
			
		||||
	struct clk_hw	hw;
 | 
			
		||||
	struct clk_ops	ops;
 | 
			
		||||
 | 
			
		||||
	struct clk_hw	*mux_hw;
 | 
			
		||||
	struct clk_hw	*rate_hw;
 | 
			
		||||
	struct clk_hw	*gate_hw;
 | 
			
		||||
 | 
			
		||||
	const struct clk_ops	*mux_ops;
 | 
			
		||||
	const struct clk_ops	*rate_ops;
 | 
			
		||||
	const struct clk_ops	*gate_ops;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct clk *clk_register_composite(struct device *dev, const char *name,
 | 
			
		||||
		const char **parent_names, int num_parents,
 | 
			
		||||
		struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
 | 
			
		||||
		struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
 | 
			
		||||
		struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
 | 
			
		||||
		unsigned long flags);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * clk_register - allocate a new clock, register it and return an opaque cookie
 | 
			
		||||
 * @dev: device that is registering this clock
 | 
			
		||||
| 
						 | 
				
			
			@ -351,6 +407,7 @@ unsigned int __clk_get_enable_count(struct clk *clk);
 | 
			
		|||
unsigned int __clk_get_prepare_count(struct clk *clk);
 | 
			
		||||
unsigned long __clk_get_rate(struct clk *clk);
 | 
			
		||||
unsigned long __clk_get_flags(struct clk *clk);
 | 
			
		||||
bool __clk_is_prepared(struct clk *clk);
 | 
			
		||||
bool __clk_is_enabled(struct clk *clk);
 | 
			
		||||
struct clk *__clk_lookup(const char *name);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,16 +28,16 @@ struct clk;
 | 
			
		|||
 * PRE_RATE_CHANGE - called immediately before the clk rate is changed,
 | 
			
		||||
 *     to indicate that the rate change will proceed.  Drivers must
 | 
			
		||||
 *     immediately terminate any operations that will be affected by the
 | 
			
		||||
 *     rate change.  Callbacks may either return NOTIFY_DONE or
 | 
			
		||||
 *     NOTIFY_STOP.
 | 
			
		||||
 *     rate change.  Callbacks may either return NOTIFY_DONE, NOTIFY_OK,
 | 
			
		||||
 *     NOTIFY_STOP or NOTIFY_BAD.
 | 
			
		||||
 *
 | 
			
		||||
 * ABORT_RATE_CHANGE: called if the rate change failed for some reason
 | 
			
		||||
 *     after PRE_RATE_CHANGE.  In this case, all registered notifiers on
 | 
			
		||||
 *     the clk will be called with ABORT_RATE_CHANGE. Callbacks must
 | 
			
		||||
 *     always return NOTIFY_DONE.
 | 
			
		||||
 *     always return NOTIFY_DONE or NOTIFY_OK.
 | 
			
		||||
 *
 | 
			
		||||
 * POST_RATE_CHANGE - called after the clk rate change has successfully
 | 
			
		||||
 *     completed.  Callbacks must always return NOTIFY_DONE.
 | 
			
		||||
 *     completed.  Callbacks must always return NOTIFY_DONE or NOTIFY_OK.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
#define PRE_RATE_CHANGE			BIT(0)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										22
									
								
								include/linux/clk/sunxi.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								include/linux/clk/sunxi.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2012 Maxime Ripard
 | 
			
		||||
 *
 | 
			
		||||
 * Maxime Ripard <maxime.ripard@free-electrons.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 __LINUX_CLK_SUNXI_H_
 | 
			
		||||
#define __LINUX_CLK_SUNXI_H_
 | 
			
		||||
 | 
			
		||||
void __init sunxi_init_clocks(void);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										114
									
								
								include/linux/platform_data/si5351.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								include/linux/platform_data/si5351.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,114 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Si5351A/B/C programmable clock generator platform_data.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __LINUX_PLATFORM_DATA_SI5351_H__
 | 
			
		||||
#define __LINUX_PLATFORM_DATA_SI5351_H__
 | 
			
		||||
 | 
			
		||||
struct clk;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * enum si5351_variant - SiLabs Si5351 chip variant
 | 
			
		||||
 * @SI5351_VARIANT_A: Si5351A (8 output clocks, XTAL input)
 | 
			
		||||
 * @SI5351_VARIANT_A3: Si5351A MSOP10 (3 output clocks, XTAL input)
 | 
			
		||||
 * @SI5351_VARIANT_B: Si5351B (8 output clocks, XTAL/VXCO input)
 | 
			
		||||
 * @SI5351_VARIANT_C: Si5351C (8 output clocks, XTAL/CLKIN input)
 | 
			
		||||
 */
 | 
			
		||||
enum si5351_variant {
 | 
			
		||||
	SI5351_VARIANT_A = 1,
 | 
			
		||||
	SI5351_VARIANT_A3 = 2,
 | 
			
		||||
	SI5351_VARIANT_B = 3,
 | 
			
		||||
	SI5351_VARIANT_C = 4,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * enum si5351_pll_src - Si5351 pll clock source
 | 
			
		||||
 * @SI5351_PLL_SRC_DEFAULT: default, do not change eeprom config
 | 
			
		||||
 * @SI5351_PLL_SRC_XTAL: pll source clock is XTAL input
 | 
			
		||||
 * @SI5351_PLL_SRC_CLKIN: pll source clock is CLKIN input (Si5351C only)
 | 
			
		||||
 */
 | 
			
		||||
enum si5351_pll_src {
 | 
			
		||||
	SI5351_PLL_SRC_DEFAULT = 0,
 | 
			
		||||
	SI5351_PLL_SRC_XTAL = 1,
 | 
			
		||||
	SI5351_PLL_SRC_CLKIN = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * enum si5351_multisynth_src - Si5351 multisynth clock source
 | 
			
		||||
 * @SI5351_MULTISYNTH_SRC_DEFAULT: default, do not change eeprom config
 | 
			
		||||
 * @SI5351_MULTISYNTH_SRC_VCO0: multisynth source clock is VCO0
 | 
			
		||||
 * @SI5351_MULTISYNTH_SRC_VCO1: multisynth source clock is VCO1/VXCO
 | 
			
		||||
 */
 | 
			
		||||
enum si5351_multisynth_src {
 | 
			
		||||
	SI5351_MULTISYNTH_SRC_DEFAULT = 0,
 | 
			
		||||
	SI5351_MULTISYNTH_SRC_VCO0 = 1,
 | 
			
		||||
	SI5351_MULTISYNTH_SRC_VCO1 = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * enum si5351_clkout_src - Si5351 clock output clock source
 | 
			
		||||
 * @SI5351_CLKOUT_SRC_DEFAULT: default, do not change eeprom config
 | 
			
		||||
 * @SI5351_CLKOUT_SRC_MSYNTH_N: clkout N source clock is multisynth N
 | 
			
		||||
 * @SI5351_CLKOUT_SRC_MSYNTH_0_4: clkout N source clock is multisynth 0 (N<4)
 | 
			
		||||
 *                                or 4 (N>=4)
 | 
			
		||||
 * @SI5351_CLKOUT_SRC_XTAL: clkout N source clock is XTAL
 | 
			
		||||
 * @SI5351_CLKOUT_SRC_CLKIN: clkout N source clock is CLKIN (Si5351C only)
 | 
			
		||||
 */
 | 
			
		||||
enum si5351_clkout_src {
 | 
			
		||||
	SI5351_CLKOUT_SRC_DEFAULT = 0,
 | 
			
		||||
	SI5351_CLKOUT_SRC_MSYNTH_N = 1,
 | 
			
		||||
	SI5351_CLKOUT_SRC_MSYNTH_0_4 = 2,
 | 
			
		||||
	SI5351_CLKOUT_SRC_XTAL = 3,
 | 
			
		||||
	SI5351_CLKOUT_SRC_CLKIN = 4,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * enum si5351_drive_strength - Si5351 clock output drive strength
 | 
			
		||||
 * @SI5351_DRIVE_DEFAULT: default, do not change eeprom config
 | 
			
		||||
 * @SI5351_DRIVE_2MA: 2mA clock output drive strength
 | 
			
		||||
 * @SI5351_DRIVE_4MA: 4mA clock output drive strength
 | 
			
		||||
 * @SI5351_DRIVE_6MA: 6mA clock output drive strength
 | 
			
		||||
 * @SI5351_DRIVE_8MA: 8mA clock output drive strength
 | 
			
		||||
 */
 | 
			
		||||
enum si5351_drive_strength {
 | 
			
		||||
	SI5351_DRIVE_DEFAULT = 0,
 | 
			
		||||
	SI5351_DRIVE_2MA = 2,
 | 
			
		||||
	SI5351_DRIVE_4MA = 4,
 | 
			
		||||
	SI5351_DRIVE_6MA = 6,
 | 
			
		||||
	SI5351_DRIVE_8MA = 8,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct si5351_clkout_config - Si5351 clock output configuration
 | 
			
		||||
 * @clkout: clkout number
 | 
			
		||||
 * @multisynth_src: multisynth source clock
 | 
			
		||||
 * @clkout_src: clkout source clock
 | 
			
		||||
 * @pll_master: if true, clkout can also change pll rate
 | 
			
		||||
 * @drive: output drive strength
 | 
			
		||||
 * @rate: initial clkout rate, or default if 0
 | 
			
		||||
 */
 | 
			
		||||
struct si5351_clkout_config {
 | 
			
		||||
	enum si5351_multisynth_src multisynth_src;
 | 
			
		||||
	enum si5351_clkout_src clkout_src;
 | 
			
		||||
	enum si5351_drive_strength drive;
 | 
			
		||||
	bool pll_master;
 | 
			
		||||
	unsigned long rate;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct si5351_platform_data - Platform data for the Si5351 clock driver
 | 
			
		||||
 * @variant: Si5351 chip variant
 | 
			
		||||
 * @clk_xtal: xtal input clock
 | 
			
		||||
 * @clk_clkin: clkin input clock
 | 
			
		||||
 * @pll_src: array of pll source clock setting
 | 
			
		||||
 * @clkout: array of clkout configuration
 | 
			
		||||
 */
 | 
			
		||||
struct si5351_platform_data {
 | 
			
		||||
	enum si5351_variant variant;
 | 
			
		||||
	struct clk *clk_xtal;
 | 
			
		||||
	struct clk *clk_clkin;
 | 
			
		||||
	enum si5351_pll_src pll_src[2];
 | 
			
		||||
	struct si5351_clkout_config clkout[8];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue