Commit 19bc2eec authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'clk-for-linus-3.15' of git://git.linaro.org/people/mike.turquette/linux

Pull clock framework changes from Mike Turquette:
 "The clock framework changes for 3.15 look similar to past pull
  requests.  Mostly clock driver updates, more Device Tree support in
  the form of common functions useful across platforms and a handful of
  features and fixes to the framework core"

* tag 'clk-for-linus-3.15' of git://git.linaro.org/people/mike.turquette/linux: (86 commits)
  clk: shmobile: fix setting paretn clock rate
  clk: shmobile: rcar-gen2: fix lb/sd0/sd1/sdh clock parent to pll1
  clk: Fix minor errors in of_clk_init() function comments
  clk: reverse default clk provider initialization order in of_clk_init()
  clk: sirf: update copyright years to 2014
  clk: mmp: try to use closer one when do round rate
  clk: mmp: fix the wrong calculation formula
  clk: mmp: fix wrong mask when calculate denominator
  clk: st: Adds quadfs clock binding
  clk: st: Adds clockgen-vcc and clockgen-mux clock binding
  clk: st: Adds clockgen clock binding
  clk: st: Adds divmux and prediv clock binding
  clk: st: Support for A9 MUX clocks
  clk: st: Support for ClockGenA9/DDR/GPU
  clk: st: Support for QUADFS inside ClockGenB/C/D/E/F
  clk: st: Support for VCC-mux and MUX clocks
  clk: st: Support for PLLs inside ClockGenA(s)
  clk: st: Support for DIVMUX and PreDiv Clocks
  clk: support hardware-specific debugfs entries
  clk: s2mps11: Use of_get_child_by_name
  ...
parents 9712d3c3 e44df332
...@@ -255,3 +255,37 @@ are sorted out. ...@@ -255,3 +255,37 @@ are sorted out.
To bypass this disabling, include "clk_ignore_unused" in the bootargs to the To bypass this disabling, include "clk_ignore_unused" in the bootargs to the
kernel. kernel.
Part 7 - Locking
The common clock framework uses two global locks, the prepare lock and the
enable lock.
The enable lock is a spinlock and is held across calls to the .enable,
.disable and .is_enabled operations. Those operations are thus not allowed to
sleep, and calls to the clk_enable(), clk_disable() and clk_is_enabled() API
functions are allowed in atomic context.
The prepare lock is a mutex and is held across calls to all other operations.
All those operations are allowed to sleep, and calls to the corresponding API
functions are not allowed in atomic context.
This effectively divides operations in two groups from a locking perspective.
Drivers don't need to manually protect resources shared between the operations
of one group, regardless of whether those resources are shared by multiple
clocks or not. However, access to resources that are shared between operations
of the two groups needs to be protected by the drivers. An example of such a
resource would be a register that controls both the clock rate and the clock
enable/disable state.
The clock framework is reentrant, in that a driver is allowed to call clock
framework functions from within its implementation of clock operations. This
can for instance cause a .set_rate operation of one clock being called from
within the .set_rate operation of another clock. This case must be considered
in the driver implementations, but the code flow is usually controlled by the
driver in that case.
Note that locking must also be considered when code outside of the common
clock framework needs to access resources used by the clock operations. This
is considered out of scope of this document.
...@@ -30,3 +30,17 @@ Example: ...@@ -30,3 +30,17 @@ Example:
resume-offset = <0x308>; resume-offset = <0x308>;
reboot-offset = <0x4>; reboot-offset = <0x4>;
}; };
PCTRL: Peripheral misc control register
Required Properties:
- compatible: "hisilicon,pctrl"
- reg: Address and size of pctrl.
Example:
/* for Hi3620 */
pctrl: pctrl@fca09000 {
compatible = "hisilicon,pctrl";
reg = <0xfca09000 0x1000>;
};
...@@ -23,3 +23,8 @@ Optional properties: ...@@ -23,3 +23,8 @@ Optional properties:
and the bit index. and the bit index.
- div-reg : For "socfpga-gate-clk", div-reg contains the divider register, bit shift, - div-reg : For "socfpga-gate-clk", div-reg contains the divider register, bit shift,
and width. and width.
- clk-phase : For the sdmmc_clk, contains the value of the clock phase that controls
the SDMMC CIU clock. The first value is the clk_sample(smpsel), and the second
value is the cclk_in_drv(drvsel). The clk-phase is used to enable the correct
hold/delay times that is needed for the SD/MMC CIU clock. The values of both
can be 0-315 degrees, in 45 degree increments.
...@@ -5,7 +5,7 @@ This binding uses the common clock binding[1]. ...@@ -5,7 +5,7 @@ This binding uses the common clock binding[1].
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt [1] Documentation/devicetree/bindings/clock/clock-bindings.txt
Required properties: Required properties:
- compatible : shall be "adi,axi-clkgen". - compatible : shall be "adi,axi-clkgen-1.00.a" or "adi,axi-clkgen-2.00.a".
- #clock-cells : from common clock binding; Should always be set to 0. - #clock-cells : from common clock binding; Should always be set to 0.
- reg : Address and length of the axi-clkgen register set. - reg : Address and length of the axi-clkgen register set.
- clocks : Phandle and clock specifier for the parent clock. - clocks : Phandle and clock specifier for the parent clock.
......
...@@ -44,6 +44,23 @@ For example: ...@@ -44,6 +44,23 @@ For example:
clocks by index. The names should reflect the clock output signal clocks by index. The names should reflect the clock output signal
names for the device. names for the device.
clock-indices: If the identifyng number for the clocks in the node
is not linear from zero, then the this mapping allows
the mapping of identifiers into the clock-output-names
array.
For example, if we have two clocks <&oscillator 1> and <&oscillator 3>:
oscillator {
compatible = "myclocktype";
#clock-cells = <1>;
clock-indices = <1>, <3>;
clock-output-names = "clka", "clkb";
}
This ensures we do not have any empty nodes in clock-output-names
==Clock consumers== ==Clock consumers==
Required properties: Required properties:
......
...@@ -7,6 +7,7 @@ Required Properties: ...@@ -7,6 +7,7 @@ Required Properties:
- compatible: should be one of the following. - compatible: should be one of the following.
- "hisilicon,hi3620-clock" - controller compatible with Hi3620 SoC. - "hisilicon,hi3620-clock" - controller compatible with Hi3620 SoC.
- "hisilicon,hi3620-mmc-clock" - controller specific for Hi3620 mmc.
- reg: physical base address of the controller and length of memory mapped - reg: physical base address of the controller and length of memory mapped
region. region.
......
Device Tree Clock bindings for arch-moxart
This binding uses the common clock binding[1].
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
MOXA ART SoCs allow to determine PLL output and APB frequencies
by reading registers holding multiplier and divisor information.
PLL:
Required properties:
- compatible : Must be "moxa,moxart-pll-clock"
- #clock-cells : Should be 0
- reg : Should contain registers location and length
- clocks : Should contain phandle + clock-specifier for the parent clock
Optional properties:
- clock-output-names : Should contain clock name
APB:
Required properties:
- compatible : Must be "moxa,moxart-apb-clock"
- #clock-cells : Should be 0
- reg : Should contain registers location and length
- clocks : Should contain phandle + clock-specifier for the parent clock
Optional properties:
- clock-output-names : Should contain clock name
For example:
clk_pll: clk_pll@98100000 {
compatible = "moxa,moxart-pll-clock";
#clock-cells = <0>;
reg = <0x98100000 0x34>;
};
clk_apb: clk_apb@98100000 {
compatible = "moxa,moxart-apb-clock";
#clock-cells = <0>;
reg = <0x98100000 0x34>;
clocks = <&clk_pll>;
};
...@@ -11,6 +11,18 @@ The following is a list of provided IDs and clock names on Armada 370/XP: ...@@ -11,6 +11,18 @@ The following is a list of provided IDs and clock names on Armada 370/XP:
3 = hclk (DRAM control clock) 3 = hclk (DRAM control clock)
4 = dramclk (DDR clock) 4 = dramclk (DDR clock)
The following is a list of provided IDs and clock names on Armada 375:
0 = tclk (Internal Bus clock)
1 = cpuclk (CPU clock)
2 = l2clk (L2 Cache clock)
3 = ddrclk (DDR clock)
The following is a list of provided IDs and clock names on Armada 380/385:
0 = tclk (Internal Bus clock)
1 = cpuclk (CPU clock)
2 = l2clk (L2 Cache clock)
3 = ddrclk (DDR clock)
The following is a list of provided IDs and clock names on Kirkwood and Dove: The following is a list of provided IDs and clock names on Kirkwood and Dove:
0 = tclk (Internal Bus clock) 0 = tclk (Internal Bus clock)
1 = cpuclk (CPU0 clock) 1 = cpuclk (CPU0 clock)
...@@ -20,6 +32,8 @@ The following is a list of provided IDs and clock names on Kirkwood and Dove: ...@@ -20,6 +32,8 @@ The following is a list of provided IDs and clock names on Kirkwood and Dove:
Required properties: Required properties:
- compatible : shall be one of the following: - compatible : shall be one of the following:
"marvell,armada-370-core-clock" - For Armada 370 SoC core clocks "marvell,armada-370-core-clock" - For Armada 370 SoC core clocks
"marvell,armada-375-core-clock" - For Armada 375 SoC core clocks
"marvell,armada-380-core-clock" - For Armada 380/385 SoC core clocks
"marvell,armada-xp-core-clock" - For Armada XP SoC core clocks "marvell,armada-xp-core-clock" - For Armada XP SoC core clocks
"marvell,dove-core-clock" - for Dove SoC core clocks "marvell,dove-core-clock" - for Dove SoC core clocks
"marvell,kirkwood-core-clock" - for Kirkwood SoC (except mv88f6180) "marvell,kirkwood-core-clock" - for Kirkwood SoC (except mv88f6180)
......
...@@ -4,7 +4,10 @@ The following is a list of provided IDs and clock names on Armada 370/XP: ...@@ -4,7 +4,10 @@ The following is a list of provided IDs and clock names on Armada 370/XP:
0 = nand (NAND clock) 0 = nand (NAND clock)
Required properties: Required properties:
- compatible : must be "marvell,armada-370-corediv-clock" - compatible : must be "marvell,armada-370-corediv-clock",
"marvell,armada-375-corediv-clock",
"marvell,armada-380-corediv-clock",
- reg : must be the register address of Core Divider control register - reg : must be the register address of Core Divider control register
- #clock-cells : from common clock binding; shall be set to 1 - #clock-cells : from common clock binding; shall be set to 1
- clocks : must be set to the parent's phandle - clocks : must be set to the parent's phandle
......
* Gated Clock bindings for Marvell EBU SoCs * Gated Clock bindings for Marvell EBU SoCs
Marvell Armada 370/XP, Dove and Kirkwood allow some peripheral clocks to be Marvell Armada 370/375/380/385/XP, Dove and Kirkwood allow some
gated to save some power. The clock consumer should specify the desired clock peripheral clocks to be gated to save some power. The clock consumer
by having the clock ID in its "clocks" phandle cell. The clock ID is directly should specify the desired clock by having the clock ID in its
mapped to the corresponding clock gating control bit in HW to ease manual clock "clocks" phandle cell. The clock ID is directly mapped to the
corresponding clock gating control bit in HW to ease manual clock
lookup in datasheet. lookup in datasheet.
The following is a list of provided IDs for Armada 370: The following is a list of provided IDs for Armada 370:
...@@ -22,6 +23,60 @@ ID Clock Peripheral ...@@ -22,6 +23,60 @@ ID Clock Peripheral
28 ddr DDR Cntrl 28 ddr DDR Cntrl
30 sata1 SATA Host 0 30 sata1 SATA Host 0
The following is a list of provided IDs for Armada 375:
ID Clock Peripheral
-----------------------------------
2 mu Management Unit
3 pp Packet Processor
4 ptp PTP
5 pex0 PCIe 0 Clock out
6 pex1 PCIe 1 Clock out
8 audio Audio Cntrl
11 nd_clk Nand Flash Cntrl
14 sata0_link SATA 0 Link
15 sata0_core SATA 0 Core
16 usb3 USB3 Host
17 sdio SDHCI Host
18 usb USB Host
19 gop Gigabit Ethernet MAC
20 sata1_link SATA 1 Link
21 sata1_core SATA 1 Core
22 xor0 XOR DMA 0
23 xor1 XOR DMA 0
24 copro Coprocessor
25 tdm Time Division Mplx
28 crypto0_enc Cryptographic Unit Port 0 Encryption
29 crypto0_core Cryptographic Unit Port 0 Core
30 crypto1_enc Cryptographic Unit Port 1 Encryption
31 crypto1_core Cryptographic Unit Port 1 Core
The following is a list of provided IDs for Armada 380/385:
ID Clock Peripheral
-----------------------------------
0 audio Audio
2 ge2 Gigabit Ethernet 2
3 ge1 Gigabit Ethernet 1
4 ge0 Gigabit Ethernet 0
5 pex1 PCIe 1
6 pex2 PCIe 2
7 pex3 PCIe 3
8 pex0 PCIe 0
9 usb3h0 USB3 Host 0
10 usb3h1 USB3 Host 1
11 usb3d USB3 Device
13 bm Buffer Management
14 crypto0z Cryptographic 0 Z
15 sata0 SATA 0
16 crypto1z Cryptographic 1 Z
17 sdio SDIO
18 usb2 USB 2
21 crypto1 Cryptographic 1
22 xor0 XOR 0
23 crypto0 Cryptographic 0
25 tdm Time Division Multiplexing
28 xor1 XOR 1
30 sata1 SATA 1
The following is a list of provided IDs for Armada XP: The following is a list of provided IDs for Armada XP:
ID Clock Peripheral ID Clock Peripheral
----------------------------------- -----------------------------------
...@@ -95,6 +150,8 @@ ID Clock Peripheral ...@@ -95,6 +150,8 @@ ID Clock Peripheral
Required properties: Required properties:
- compatible : shall be one of the following: - compatible : shall be one of the following:
"marvell,armada-370-gating-clock" - for Armada 370 SoC clock gating "marvell,armada-370-gating-clock" - for Armada 370 SoC clock gating
"marvell,armada-375-gating-clock" - for Armada 375 SoC clock gating
"marvell,armada-380-gating-clock" - for Armada 380/385 SoC clock gating
"marvell,armada-xp-gating-clock" - for Armada XP SoC clock gating "marvell,armada-xp-gating-clock" - for Armada XP SoC clock gating
"marvell,dove-gating-clock" - for Dove SoC clock gating "marvell,dove-gating-clock" - for Dove SoC clock gating
"marvell,kirkwood-gating-clock" - for Kirkwood SoC clock gating "marvell,kirkwood-gating-clock" - for Kirkwood SoC clock gating
......
* Renesas RZ Clock Pulse Generator (CPG)
The CPG generates core clocks for the RZ SoCs. It includes the PLL, variable
CPU and GPU clocks, and several fixed ratio dividers.
Required Properties:
- compatible: Must be one of
- "renesas,r7s72100-cpg-clocks" for the r7s72100 CPG
- "renesas,rz-cpg-clocks" for the generic RZ CPG
- reg: Base address and length of the memory resource used by the CPG
- clocks: References to possible parent clocks. Order must match clock modes
in the datasheet. For the r7s72100, this is extal, usb_x1.
- #clock-cells: Must be 1
- clock-output-names: The names of the clocks. Supported clocks are "pll",
"i", and "g"
Example
-------
cpg_clocks: cpg_clocks@fcfe0000 {
#clock-cells = <1>;
compatible = "renesas,r7s72100-cpg-clocks",
"renesas,rz-cpg-clocks";
reg = <0xfcfe0000 0x18>;
clocks = <&extal_clk>, <&usb_x1_clk>;
clock-output-names = "pll", "i", "g";
};
Binding for a ST divider and multiplexer clock driver.
This binding uses the common clock binding[1].
Base address is located to the parent node. See clock binding[2]
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
[2] Documentation/devicetree/bindings/clock/st/st,clkgen.txt
Required properties:
- compatible : shall be:
"st,clkgena-divmux-c65-hs", "st,clkgena-divmux"
"st,clkgena-divmux-c65-ls", "st,clkgena-divmux"
"st,clkgena-divmux-c32-odf0", "st,clkgena-divmux"
"st,clkgena-divmux-c32-odf1", "st,clkgena-divmux"
"st,clkgena-divmux-c32-odf2", "st,clkgena-divmux"
"st,clkgena-divmux-c32-odf3", "st,clkgena-divmux"
- #clock-cells : From common clock binding; shall be set to 1.
- clocks : From common clock binding
- clock-output-names : From common clock binding.
Example:
clockgenA@fd345000 {
reg = <0xfd345000 0xb50>;
CLK_M_A1_DIV1: CLK_M_A1_DIV1 {
#clock-cells = <1>;
compatible = "st,clkgena-divmux-c32-odf1",
"st,clkgena-divmux";
clocks = <&CLK_M_A1_OSC_PREDIV>,
<&CLK_M_A1_PLL0 1>, /* PLL0 PHI1 */
<&CLK_M_A1_PLL1 1>; /* PLL1 PHI1 */
clock-output-names = "CLK_M_RX_ICN_TS",
"CLK_M_RX_ICN_VDP_0",
"", /* Unused */
"CLK_M_PRV_T1_BUS",
"CLK_M_ICN_REG_12",
"CLK_M_ICN_REG_10",
"", /* Unused */
"CLK_M_ICN_ST231";
};
};
Binding for a ST multiplexed clock driver.
This binding supports only simple indexed multiplexers, it does not
support table based parent index to hardware value translations.
This binding uses the common clock binding[1].
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
Required properties:
- compatible : shall be:
"st,stih416-clkgenc-vcc-hd", "st,clkgen-mux"
"st,stih416-clkgenf-vcc-fvdp", "st,clkgen-mux"
"st,stih416-clkgenf-vcc-hva", "st,clkgen-mux"
"st,stih416-clkgenf-vcc-hd", "st,clkgen-mux"
"st,stih416-clkgenf-vcc-sd", "st,clkgen-mux"
"st,stih415-clkgen-a9-mux", "st,clkgen-mux"
"st,stih416-clkgen-a9-mux", "st,clkgen-mux"
- #clock-cells : from common clock binding; shall be set to 0.
- reg : A Base address and length of the register set.
- clocks : from common clock binding
Example:
CLK_M_HVA: CLK_M_HVA {
#clock-cells = <0>;
compatible = "st,stih416-clkgenf-vcc-hva", "st,clkgen-mux";
reg = <0xfd690868 4>;
clocks = <&CLOCKGEN_F 1>, <&CLK_M_A1_DIV0 3>;
};
Binding for a ST pll clock driver.
This binding uses the common clock binding[1].
Base address is located to the parent node. See clock binding[2]
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
[2] Documentation/devicetree/bindings/clock/st/st,clkgen.txt
Required properties:
- compatible : shall be:
"st,clkgena-prediv-c65", "st,clkgena-prediv"
"st,clkgena-prediv-c32", "st,clkgena-prediv"
"st,clkgena-plls-c65"
"st,plls-c32-a1x-0", "st,clkgen-plls-c32"
"st,plls-c32-a1x-1", "st,clkgen-plls-c32"
"st,stih415-plls-c32-a9", "st,clkgen-plls-c32"
"st,stih415-plls-c32-ddr", "st,clkgen-plls-c32"
"st,stih416-plls-c32-a9", "st,clkgen-plls-c32"
"st,stih416-plls-c32-ddr", "st,clkgen-plls-c32"
"st,stih415-gpu-pll-c32", "st,clkgengpu-pll-c32"
"st,stih416-gpu-pll-c32", "st,clkgengpu-pll-c32"
- #clock-cells : From common clock binding; shall be set to 1.
- clocks : From common clock binding
- clock-output-names : From common clock binding.
Example:
clockgenA@fee62000 {
reg = <0xfee62000 0xb48>;
CLK_S_A0_PLL: CLK_S_A0_PLL {
#clock-cells = <1>;
compatible = "st,clkgena-plls-c65";
clocks = <&CLK_SYSIN>;
clock-output-names = "CLK_S_A0_PLL0_HS",
"CLK_S_A0_PLL0_LS",
"CLK_S_A0_PLL1";
};
};
Binding for a ST pre-divider clock driver.
This binding uses the common clock binding[1].
Base address is located to the parent node. See clock binding[2]
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
[2] Documentation/devicetree/bindings/clock/st/st,clkgen.txt
Required properties:
- compatible : shall be:
"st,clkgena-prediv-c65", "st,clkgena-prediv"
"st,clkgena-prediv-c32", "st,clkgena-prediv"
- #clock-cells : From common clock binding; shall be set to 0.
- clocks : From common clock binding
- clock-output-names : From common clock binding.
Example:
clockgenA@fd345000 {
reg = <0xfd345000 0xb50>;
CLK_M_A2_OSC_PREDIV: CLK_M_A2_OSC_PREDIV {
#clock-cells = <0>;
compatible = "st,clkgena-prediv-c32",
"st,clkgena-prediv";
clocks = <&CLK_SYSIN>;
clock-output-names = "CLK_M_A2_OSC_PREDIV";
};
};
Binding for a type of STMicroelectronics clock crossbar (VCC).
The crossbar can take up to 4 input clocks and control up to 16
output clocks. Not all inputs or outputs have to be in use in a
particular instantiation. Each output can be individually enabled,
select any of the input clocks and apply a divide (by 1,2,4 or 8) to
that selected clock.
This binding uses the common clock binding[1].
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
Required properties:
- compatible : shall be:
"st,stih416-clkgenc", "st,vcc"
"st,stih416-clkgenf", "st,vcc"
- #clock-cells : from common clock binding; shall be set to 1.
- reg : A Base address and length of the register set.
- clocks : from common clock binding
- clock-output-names : From common clock binding. The block has 16
clock outputs but not all of them in a specific instance
have to be used in the SoC. If a clock name is left as
an empty string then no clock will be created for the
output associated with that string index. If fewer than
16 strings are provided then no clocks will be created
for the remaining outputs.
Example:
CLOCKGEN_C_VCC: CLOCKGEN_C_VCC {
#clock-cells = <1>;
compatible = "st,stih416-clkgenc", "st,clkgen-vcc";
reg = <0xfe8308ac 12>;
clocks = <&CLK_S_VCC_HD>, <&CLOCKGEN_C 1>,
<&CLK_S_TMDS_FROMPHY>, <&CLOCKGEN_C 2>;
clock-output-names =
"CLK_S_PIX_HDMI", "CLK_S_PIX_DVO",
"CLK_S_OUT_DVO", "CLK_S_PIX_HD",
"CLK_S_HDDAC", "CLK_S_DENC",
"CLK_S_SDDAC", "CLK_S_PIX_MAIN",
"CLK_S_PIX_AUX", "CLK_S_STFE_FRC_0",
"CLK_S_REF_MCRU", "CLK_S_SLAVE_MCRU",
"CLK_S_TMDS_HDMI", "CLK_S_HDMI_REJECT_PLL",
"CLK_S_THSENS";
};
Binding for a Clockgen hardware block found on
certain STMicroelectronics consumer electronics SoC devices.
A Clockgen node can contain pll, diviser or multiplexer nodes.
We will find only the base address of the Clockgen, this base
address is common of all subnode.
clockgen_node {
reg = <>;
pll_node {
...
};
prediv_node {
...
};
divmux_node {
...
};
quadfs_node {
...
};
...
};
This binding uses the common clock binding[1].
Each subnode should use the binding discribe in [2]..[4]
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
[2] Documentation/devicetree/bindings/clock/st,quadfs.txt
[3] Documentation/devicetree/bindings/clock/st,quadfs.txt
[4] Documentation/devicetree/bindings/clock/st,quadfs.txt
Required properties:
- reg : A Base address and length of the register set.
Example:
clockgenA@fee62000 {
reg = <0xfee62000 0xb48>;
CLK_S_A0_PLL: CLK_S_A0_PLL {
#clock-cells = <1>;
compatible = "st,clkgena-plls-c65";
clocks = <&CLK_SYSIN>;
clock-output-names = "CLK_S_A0_PLL0_HS",
"CLK_S_A0_PLL0_LS",
"CLK_S_A0_PLL1";
};
CLK_S_A0_OSC_PREDIV: CLK_S_A0_OSC_PREDIV {
#clock-cells = <0>;
compatible = "st,clkgena-prediv-c65",
"st,clkgena-prediv";
clocks = <&CLK_SYSIN>;
clock-output-names = "CLK_S_A0_OSC_PREDIV";
};
CLK_S_A0_HS: CLK_S_A0_HS {
#clock-cells = <1>;
compatible = "st,clkgena-divmux-c65-hs",
"st,clkgena-divmux";
clocks = <&CLK_S_A0_OSC_PREDIV>,
<&CLK_S_A0_PLL 0>, /* PLL0 HS */
<&CLK_S_A0_PLL 2>; /* PLL1 */
clock-output-names = "CLK_S_FDMA_0",
"CLK_S_FDMA_1",
""; /* CLK_S_JIT_SENSE */
/* Fourth output unused */
};
};
Binding for a type of quad channel digital frequency synthesizer found on
certain STMicroelectronics consumer electronics SoC devices.
This version contains a programmable PLL which can generate up to 216, 432
or 660MHz (from a 30MHz oscillator input) as the input to the digital
synthesizers.
This binding uses the common clock binding[1].
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
Required properties:
- compatible : shall be:
"st,stih416-quadfs216", "st,quadfs"
"st,stih416-quadfs432", "st,quadfs"
"st,stih416-quadfs660-E", "st,quadfs"
"st,stih416-quadfs660-F", "st,quadfs"
- #clock-cells : from common clock binding; shall be set to 1.
- reg : A Base address and length of the register set.
- clocks : from common clock binding
- clock-output-names : From common clock binding. The block has 4
clock outputs but not all of them in a specific instance
have to be used in the SoC. If a clock name is left as
an empty string then no clock will be created for the
output associated with that string index. If fewer than
4 strings are provided then no clocks will be created
for the remaining outputs.
Example:
CLOCKGEN_E: CLOCKGEN_E {
#clock-cells = <1>;
compatible = "st,stih416-quadfs660-E", "st,quadfs";
reg = <0xfd3208bc 0xB0>;
clocks = <&CLK_SYSIN>;
clock-output-names = "CLK_M_PIX_MDTP_0",
"CLK_M_PIX_MDTP_1",
"CLK_M_PIX_MDTP_2",
"CLK_M_MPELPC";
};
...@@ -6,37 +6,41 @@ This binding uses the common clock binding[1]. ...@@ -6,37 +6,41 @@ This binding uses the common clock binding[1].
Required properties: Required properties:
- compatible : shall be one of the following: - compatible : shall be one of the following:
"allwinner,sun4i-osc-clk" - for a gatable oscillator "allwinner,sun4i-a10-osc-clk" - for a gatable oscillator
"allwinner,sun4i-pll1-clk" - for the main PLL clock and PLL4 "allwinner,sun4i-a10-pll1-clk" - for the main PLL clock and PLL4
"allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31 "allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31
"allwinner,sun4i-pll5-clk" - for the PLL5 clock "allwinner,sun4i-a10-pll5-clk" - for the PLL5 clock
"allwinner,sun4i-pll6-clk" - for the PLL6 clock "allwinner,sun4i-a10-pll6-clk" - for the PLL6 clock
"allwinner,sun4i-cpu-clk" - for the CPU multiplexer clock "allwinner,sun6i-a31-pll6-clk" - for the PLL6 clock on A31
"allwinner,sun4i-axi-clk" - for the AXI clock "allwinner,sun4i-a10-cpu-clk" - for the CPU multiplexer clock
"allwinner,sun4i-axi-gates-clk" - for the AXI gates "allwinner,sun4i-a10-axi-clk" - for the AXI clock
"allwinner,sun4i-ahb-clk" - for the AHB clock "allwinner,sun4i-a10-axi-gates-clk" - for the AXI gates
"allwinner,sun4i-ahb-gates-clk" - for the AHB gates on A10 "allwinner,sun4i-a10-ahb-clk" - for the AHB clock
"allwinner,sun4i-a10-ahb-gates-clk" - for the AHB gates on A10
"allwinner,sun5i-a13-ahb-gates-clk" - for the AHB gates on A13 "allwinner,sun5i-a13-ahb-gates-clk" - for the AHB gates on A13
"allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s "allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s
"allwinner,sun7i-a20-ahb-gates-clk" - for the AHB gates on A20 "allwinner,sun7i-a20-ahb-gates-clk" - for the AHB gates on A20
"allwinner,sun6i-a31-ahb1-mux-clk" - for the AHB1 multiplexer on A31 "allwinner,sun6i-a31-ahb1-mux-clk" - for the AHB1 multiplexer on A31
"allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31 "allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
"allwinner,sun4i-apb0-clk" - for the APB0 clock "allwinner,sun4i-a10-apb0-clk" - for the APB0 clock
"allwinner,sun4i-apb0-gates-clk" - for the APB0 gates on A10 "allwinner,sun4i-a10-apb0-gates-clk" - for the APB0 gates on A10
"allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13 "allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13
"allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s "allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s
"allwinner,sun7i-a20-apb0-gates-clk" - for the APB0 gates on A20 "allwinner,sun7i-a20-apb0-gates-clk" - for the APB0 gates on A20
"allwinner,sun4i-apb1-clk" - for the APB1 clock "allwinner,sun4i-a10-apb1-clk" - for the APB1 clock
"allwinner,sun4i-apb1-mux-clk" - for the APB1 clock muxing "allwinner,sun4i-a10-apb1-mux-clk" - for the APB1 clock muxing
"allwinner,sun4i-apb1-gates-clk" - for the APB1 gates on A10 "allwinner,sun4i-a10-apb1-gates-clk" - for the APB1 gates on A10
"allwinner,sun5i-a13-apb1-gates-clk" - for the APB1 gates on A13 "allwinner,sun5i-a13-apb1-gates-clk" - for the APB1 gates on A13
"allwinner,sun5i-a10s-apb1-gates-clk" - for the APB1 gates on A10s "allwinner,sun5i-a10s-apb1-gates-clk" - for the APB1 gates on A10s
"allwinner,sun6i-a31-apb1-gates-clk" - for the APB1 gates on A31 "allwinner,sun6i-a31-apb1-gates-clk" - for the APB1 gates on A31
"allwinner,sun7i-a20-apb1-gates-clk" - for the APB1 gates on A20 "allwinner,sun7i-a20-apb1-gates-clk" - for the APB1 gates on A20
"allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31 "allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31
"allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
"allwinner,sun4i-mod0-clk" - for the module 0 family of clocks "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
"allwinner,sun7i-a20-out-clk" - for the external output clocks "allwinner,sun7i-a20-out-clk" - for the external output clocks
"allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
"allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
"allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
Required properties for all clocks: Required properties for all clocks:
- reg : shall be the control register address for the clock. - reg : shall be the control register address for the clock.
...@@ -44,10 +48,17 @@ Required properties for all clocks: ...@@ -44,10 +48,17 @@ Required properties for all clocks:
multiplexed clocks, the list order must match the hardware multiplexed clocks, the list order must match the hardware
programming order. programming order.
- #clock-cells : from common clock binding; shall be set to 0 except for - #clock-cells : from common clock binding; shall be set to 0 except for
"allwinner,*-gates-clk" where it shall be set to 1 "allwinner,*-gates-clk", "allwinner,sun4i-pll5-clk" and
"allwinner,sun4i-pll6-clk" where it shall be set to 1
- clock-output-names : shall be the corresponding names of the outputs.
If the clock module only has one output, the name shall be the
module name.
Additionally, "allwinner,*-gates-clk" clocks require: And "allwinner,*-usb-clk" clocks also require:
- clock-output-names : the corresponding gate names that the clock controls - reset-cells : shall be set to 1
For "allwinner,sun7i-a20-gmac-clk", the parent clocks shall be fixed rate
dummy clocks at 25 MHz and 125 MHz, respectively. See example.
Clock consumers should specify the desired clocks they use with a Clock consumers should specify the desired clocks they use with a
"clocks" phandle cell. Consumers that are using a gated clock should "clocks" phandle cell. Consumers that are using a gated clock should
...@@ -56,23 +67,68 @@ offset of the bit controlling this particular gate in the register. ...@@ -56,23 +67,68 @@ offset of the bit controlling this particular gate in the register.
For example: For example:
osc24M: osc24M@01c20050 { osc24M: clk@01c20050 {
#clock-cells = <0>; #clock-cells = <0>;
compatible = "allwinner,sun4i-osc-clk"; compatible = "allwinner,sun4i-a10-osc-clk";
reg = <0x01c20050 0x4>; reg = <0x01c20050 0x4>;
clocks = <&osc24M_fixed>; clocks = <&osc24M_fixed>;
clock-output-names = "osc24M";
}; };
pll1: pll1@01c20000 { pll1: clk@01c20000 {
#clock-cells = <0>; #clock-cells = <0>;
compatible = "allwinner,sun4i-pll1-clk"; compatible = "allwinner,sun4i-a10-pll1-clk";
reg = <0x01c20000 0x4>; reg = <0x01c20000 0x4>;
clocks = <&osc24M>; clocks = <&osc24M>;
clock-output-names = "pll1";
};
pll5: clk@01c20020 {
#clock-cells = <1>;
compatible = "allwinner,sun4i-pll5-clk";
reg = <0x01c20020 0x4>;
clocks = <&osc24M>;
clock-output-names = "pll5_ddr", "pll5_other";
}; };
cpu: cpu@01c20054 { cpu: cpu@01c20054 {
#clock-cells = <0>; #clock-cells = <0>;
compatible = "allwinner,sun4i-cpu-clk"; compatible = "allwinner,sun4i-a10-cpu-clk";
reg = <0x01c20054 0x4>; reg = <0x01c20054 0x4>;
clocks = <&osc32k>, <&osc24M>, <&pll1>; clocks = <&osc32k>, <&osc24M>, <&pll1>;
clock-output-names = "cpu";
};
mmc0_clk: clk@01c20088 {
#clock-cells = <0>;
compatible = "allwinner,sun4i-mod0-clk";
reg = <0x01c20088 0x4>;
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
clock-output-names = "mmc0";
};
mii_phy_tx_clk: clk@2 {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <25000000>;
clock-output-names = "mii_phy_tx";
};
gmac_int_tx_clk: clk@3 {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <125000000>;
clock-output-names = "gmac_int_tx";
};
gmac_clk: clk@01c20164 {
#clock-cells = <0>;
compatible = "allwinner,sun7i-a20-gmac-clk";
reg = <0x01c20164 0x4>;
/*
* The first clock must be fixed at 25MHz;
* the second clock must be fixed at 125MHz
*/
clocks = <&mii_phy_tx_clk>, <&gmac_int_tx_clk>;
clock-output-names = "gmac";
}; };
...@@ -2318,7 +2318,7 @@ F: include/uapi/linux/coda*.h ...@@ -2318,7 +2318,7 @@ F: include/uapi/linux/coda*.h
COMMON CLK FRAMEWORK COMMON CLK FRAMEWORK
M: Mike Turquette <mturquette@linaro.org> M: Mike Turquette <mturquette@linaro.org>
L: linux-arm-kernel@lists.infradead.org (same as CLK API & CLKDEV) L: linux-kernel@vger.kernel.org
T: git git://git.linaro.org/people/mturquette/linux.git T: git git://git.linaro.org/people/mturquette/linux.git
S: Maintained S: Maintained
F: drivers/clk/ F: drivers/clk/
......
...@@ -424,6 +424,7 @@ sdmmc_clk: sdmmc_clk { ...@@ -424,6 +424,7 @@ sdmmc_clk: sdmmc_clk {
compatible = "altr,socfpga-gate-clk"; compatible = "altr,socfpga-gate-clk";
clocks = <&f2s_periph_ref_clk>, <&main_nand_sdmmc_clk>, <&per_nand_mmc_clk>; clocks = <&f2s_periph_ref_clk>, <&main_nand_sdmmc_clk>, <&per_nand_mmc_clk>;
clk-gate = <0xa0 8>; clk-gate = <0xa0 8>;
clk-phase = <0 135>;
}; };
nand_x_clk: nand_x_clk { nand_x_clk: nand_x_clk {
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
void __iomem *socfpga_scu_base_addr = ((void __iomem *)(SOCFPGA_SCU_VIRT_BASE)); void __iomem *socfpga_scu_base_addr = ((void __iomem *)(SOCFPGA_SCU_VIRT_BASE));
void __iomem *sys_manager_base_addr; void __iomem *sys_manager_base_addr;
void __iomem *rst_manager_base_addr; void __iomem *rst_manager_base_addr;
void __iomem *clk_mgr_base_addr;
unsigned long cpu1start_addr; unsigned long cpu1start_addr;
static struct map_desc scu_io_desc __initdata = { static struct map_desc scu_io_desc __initdata = {
...@@ -78,9 +77,6 @@ void __init socfpga_sysmgr_init(void) ...@@ -78,9 +77,6 @@ void __init socfpga_sysmgr_init(void)
np = of_find_compatible_node(NULL, NULL, "altr,rst-mgr"); np = of_find_compatible_node(NULL, NULL, "altr,rst-mgr");
rst_manager_base_addr = of_iomap(np, 0); rst_manager_base_addr = of_iomap(np, 0);
np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr");
clk_mgr_base_addr = of_iomap(np, 0);
} }
static void __init socfpga_init_irq(void) static void __init socfpga_init_irq(void)
...@@ -106,7 +102,6 @@ static void __init socfpga_cyclone5_init(void) ...@@ -106,7 +102,6 @@ static void __init socfpga_cyclone5_init(void)
{ {
l2x0_of_init(0, ~0UL); l2x0_of_init(0, ~0UL);
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
socfpga_init_clocks();
} }
static const char *altera_dt_match[] = { static const char *altera_dt_match[] = {
......
...@@ -65,10 +65,12 @@ config COMMON_CLK_SI570 ...@@ -65,10 +65,12 @@ config COMMON_CLK_SI570
clock generators. clock generators.
config COMMON_CLK_S2MPS11 config COMMON_CLK_S2MPS11
tristate "Clock driver for S2MPS11 MFD" tristate "Clock driver for S2MPS11/S5M8767 MFD"
depends on MFD_SEC_CORE depends on MFD_SEC_CORE
---help--- ---help---
This driver supports S2MPS11 crystal oscillator clock. This driver supports S2MPS11/S5M8767 crystal oscillator clock. These
multi-function devices have 3 fixed-rate oscillators, clocked at
32KHz each.
config CLK_TWL6040 config CLK_TWL6040
tristate "External McPDM functional clock from twl6040" tristate "External McPDM functional clock from twl6040"
......
...@@ -17,6 +17,7 @@ obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o ...@@ -17,6 +17,7 @@ obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o
...@@ -31,6 +32,7 @@ obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o ...@@ -31,6 +32,7 @@ obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o
obj-$(CONFIG_COMMON_CLK_AT91) += at91/ obj-$(CONFIG_COMMON_CLK_AT91) += at91/
obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/ obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/
obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
obj-$(CONFIG_ARCH_HIP04) += hisilicon/
obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
ifeq ($(CONFIG_COMMON_CLK), y) ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/ obj-$(CONFIG_ARCH_MMP) += mmp/
...@@ -44,6 +46,7 @@ obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += shmobile/ ...@@ -44,6 +46,7 @@ obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += shmobile/
obj-$(CONFIG_ARCH_SIRF) += sirf/ obj-$(CONFIG_ARCH_SIRF) += sirf/
obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
obj-$(CONFIG_PLAT_SPEAR) += spear/ obj-$(CONFIG_PLAT_SPEAR) += spear/
obj-$(CONFIG_ARCH_STI) += st/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_ARCH_OMAP2PLUS) += ti/ obj-$(CONFIG_ARCH_OMAP2PLUS) += ti/
......
...@@ -13,12 +13,9 @@ ...@@ -13,12 +13,9 @@
#include <linux/clk/at91_pmc.h> #include <linux/clk/at91_pmc.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include "pmc.h" #include "pmc.h"
...@@ -38,104 +35,59 @@ struct clk_programmable_layout { ...@@ -38,104 +35,59 @@ struct clk_programmable_layout {
struct clk_programmable { struct clk_programmable {
struct clk_hw hw; struct clk_hw hw;
struct at91_pmc *pmc; struct at91_pmc *pmc;
unsigned int irq;
wait_queue_head_t wait;
u8 id; u8 id;
u8 css;
u8 pres;
u8 slckmck;
const struct clk_programmable_layout *layout; const struct clk_programmable_layout *layout;
}; };
#define to_clk_programmable(hw) container_of(hw, struct clk_programmable, hw) #define to_clk_programmable(hw) container_of(hw, struct clk_programmable, hw)
static irqreturn_t clk_programmable_irq_handler(int irq, void *dev_id)
{
struct clk_programmable *prog = (struct clk_programmable *)dev_id;
wake_up(&prog->wait);
return IRQ_HANDLED;
}
static int clk_programmable_prepare(struct clk_hw *hw)
{
u32 tmp;
struct clk_programmable *prog = to_clk_programmable(hw);
struct at91_pmc *pmc = prog->pmc;
const struct clk_programmable_layout *layout = prog->layout;
u8 id = prog->id;
u32 mask = PROG_STATUS_MASK(id);
tmp = prog->css | (prog->pres << layout->pres_shift);
if (layout->have_slck_mck && prog->slckmck)
tmp |= AT91_PMC_CSSMCK_MCK;
pmc_write(pmc, AT91_PMC_PCKR(id), tmp);
while (!(pmc_read(pmc, AT91_PMC_SR) & mask))
wait_event(prog->wait, pmc_read(pmc, AT91_PMC_SR) & mask);
return 0;
}
static int clk_programmable_is_ready(struct clk_hw *hw)
{
struct clk_programmable *prog = to_clk_programmable(hw);
struct at91_pmc *pmc = prog->pmc;
return !!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_PCKR(prog->id));
}
static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw, static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
u32 tmp; u32 pres;
struct clk_programmable *prog = to_clk_programmable(hw); struct clk_programmable *prog = to_clk_programmable(hw);
struct at91_pmc *pmc = prog->pmc; struct at91_pmc *pmc = prog->pmc;
const struct clk_programmable_layout *layout = prog->layout; const struct clk_programmable_layout *layout = prog->layout;
tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id)); pres = (pmc_read(pmc, AT91_PMC_PCKR(prog->id)) >> layout->pres_shift) &
prog->pres = (tmp >> layout->pres_shift) & PROG_PRES_MASK; PROG_PRES_MASK;
return parent_rate >> pres;
return parent_rate >> prog->pres;
} }
static long clk_programmable_round_rate(struct clk_hw *hw, unsigned long rate, static long clk_programmable_determine_rate(struct clk_hw *hw,
unsigned long *parent_rate) unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_clk)
{ {
unsigned long best_rate = *parent_rate; struct clk *parent = NULL;
unsigned long best_diff; long best_rate = -EINVAL;
unsigned long new_diff; unsigned long parent_rate;
unsigned long cur_rate; unsigned long tmp_rate;
int shift = shift; int shift;
int i;
if (rate > *parent_rate)
return *parent_rate;
else
best_diff = *parent_rate - rate;
if (!best_diff)
return best_rate;
for (shift = 1; shift < PROG_PRES_MASK; shift++) { for (i = 0; i < __clk_get_num_parents(hw->clk); i++) {
cur_rate = *parent_rate >> shift; parent = clk_get_parent_by_index(hw->clk, i);
if (!parent)
continue;
if (cur_rate > rate) parent_rate = __clk_get_rate(parent);
new_diff = cur_rate - rate; for (shift = 0; shift < PROG_PRES_MASK; shift++) {
else tmp_rate = parent_rate >> shift;
new_diff = rate - cur_rate; if (tmp_rate <= rate)
break;
}
if (!new_diff) if (tmp_rate > rate)
return cur_rate; continue;
if (new_diff < best_diff) { if (best_rate < 0 || (rate - tmp_rate) < (rate - best_rate)) {
best_diff = new_diff; best_rate = tmp_rate;
best_rate = cur_rate; *best_parent_rate = parent_rate;
*best_parent_clk = parent;
} }
if (rate > cur_rate) if (!best_rate)
break; break;
} }
...@@ -146,17 +98,22 @@ static int clk_programmable_set_parent(struct clk_hw *hw, u8 index) ...@@ -146,17 +98,22 @@ static int clk_programmable_set_parent(struct clk_hw *hw, u8 index)
{ {
struct clk_programmable *prog = to_clk_programmable(hw); struct clk_programmable *prog = to_clk_programmable(hw);
const struct clk_programmable_layout *layout = prog->layout; const struct clk_programmable_layout *layout = prog->layout;
struct at91_pmc *pmc = prog->pmc;
u32 tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id)) & ~layout->css_mask;
if (layout->have_slck_mck)
tmp &= AT91_PMC_CSSMCK_MCK;
if (index > layout->css_mask) { if (index > layout->css_mask) {
if (index > PROG_MAX_RM9200_CSS && layout->have_slck_mck) { if (index > PROG_MAX_RM9200_CSS && layout->have_slck_mck) {
prog->css = 0; tmp |= AT91_PMC_CSSMCK_MCK;
prog->slckmck = 1;
return 0; return 0;
} else { } else {
return -EINVAL; return -EINVAL;
} }
} }
prog->css = index; pmc_write(pmc, AT91_PMC_PCKR(prog->id), tmp | index);
return 0; return 0;
} }
...@@ -169,13 +126,9 @@ static u8 clk_programmable_get_parent(struct clk_hw *hw) ...@@ -169,13 +126,9 @@ static u8 clk_programmable_get_parent(struct clk_hw *hw)
const struct clk_programmable_layout *layout = prog->layout; const struct clk_programmable_layout *layout = prog->layout;
tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id)); tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id));
prog->css = tmp & layout->css_mask; ret = tmp & layout->css_mask;
ret = prog->css; if (layout->have_slck_mck && (tmp & AT91_PMC_CSSMCK_MCK) && !ret)
if (layout->have_slck_mck) {
prog->slckmck = !!(tmp & AT91_PMC_CSSMCK_MCK);
if (prog->slckmck && !ret)
ret = PROG_MAX_RM9200_CSS + 1; ret = PROG_MAX_RM9200_CSS + 1;
}
return ret; return ret;
} }
...@@ -184,67 +137,47 @@ static int clk_programmable_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -184,67 +137,47 @@ static int clk_programmable_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct clk_programmable *prog = to_clk_programmable(hw); struct clk_programmable *prog = to_clk_programmable(hw);
unsigned long best_rate = parent_rate; struct at91_pmc *pmc = prog->pmc;
unsigned long best_diff; const struct clk_programmable_layout *layout = prog->layout;
unsigned long new_diff; unsigned long div = parent_rate / rate;
unsigned long cur_rate;
int shift = 0; int shift = 0;
u32 tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id)) &
~(PROG_PRES_MASK << layout->pres_shift);
if (rate > parent_rate) if (!div)
return parent_rate; return -EINVAL;
else
best_diff = parent_rate - rate;
if (!best_diff) {
prog->pres = shift;
return 0;
}
for (shift = 1; shift < PROG_PRES_MASK; shift++) {
cur_rate = parent_rate >> shift;
if (cur_rate > rate) shift = fls(div) - 1;
new_diff = cur_rate - rate;
else
new_diff = rate - cur_rate;
if (!new_diff) if (div != (1<<shift))
break; return -EINVAL;
if (new_diff < best_diff) { if (shift >= PROG_PRES_MASK)
best_diff = new_diff; return -EINVAL;
best_rate = cur_rate;
}
if (rate > cur_rate) pmc_write(pmc, AT91_PMC_PCKR(prog->id),
break; tmp | (shift << layout->pres_shift));
}
prog->pres = shift;
return 0; return 0;
} }
static const struct clk_ops programmable_ops = { static const struct clk_ops programmable_ops = {
.prepare = clk_programmable_prepare,
.is_prepared = clk_programmable_is_ready,
.recalc_rate = clk_programmable_recalc_rate, .recalc_rate = clk_programmable_recalc_rate,
.round_rate = clk_programmable_round_rate, .determine_rate = clk_programmable_determine_rate,
.get_parent = clk_programmable_get_parent, .get_parent = clk_programmable_get_parent,
.set_parent = clk_programmable_set_parent, .set_parent = clk_programmable_set_parent,
.set_rate = clk_programmable_set_rate, .set_rate = clk_programmable_set_rate,
}; };
static struct clk * __init static struct clk * __init
at91_clk_register_programmable(struct at91_pmc *pmc, unsigned int irq, at91_clk_register_programmable(struct at91_pmc *pmc,
const char *name, const char **parent_names, const char *name, const char **parent_names,
u8 num_parents, u8 id, u8 num_parents, u8 id,
const struct clk_programmable_layout *layout) const struct clk_programmable_layout *layout)
{ {
int ret;
struct clk_programmable *prog; struct clk_programmable *prog;
struct clk *clk = NULL; struct clk *clk = NULL;
struct clk_init_data init; struct clk_init_data init;
char irq_name[11];
if (id > PROG_ID_MAX) if (id > PROG_ID_MAX)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -263,14 +196,6 @@ at91_clk_register_programmable(struct at91_pmc *pmc, unsigned int irq, ...@@ -263,14 +196,6 @@ at91_clk_register_programmable(struct at91_pmc *pmc, unsigned int irq,
prog->layout = layout; prog->layout = layout;
prog->hw.init = &init; prog->hw.init = &init;
prog->pmc = pmc; prog->pmc = pmc;
prog->irq = irq;
init_waitqueue_head(&prog->wait);
irq_set_status_flags(prog->irq, IRQ_NOAUTOEN);
snprintf(irq_name, sizeof(irq_name), "clk-prog%d", id);
ret = request_irq(prog->irq, clk_programmable_irq_handler,
IRQF_TRIGGER_HIGH, irq_name, prog);
if (ret)
return ERR_PTR(ret);
clk = clk_register(NULL, &prog->hw); clk = clk_register(NULL, &prog->hw);
if (IS_ERR(clk)) if (IS_ERR(clk))
...@@ -304,7 +229,6 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc, ...@@ -304,7 +229,6 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
int num; int num;
u32 id; u32 id;
int i; int i;
unsigned int irq;
struct clk *clk; struct clk *clk;
int num_parents; int num_parents;
const char *parent_names[PROG_SOURCE_MAX]; const char *parent_names[PROG_SOURCE_MAX];
...@@ -332,11 +256,7 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc, ...@@ -332,11 +256,7 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
if (of_property_read_string(np, "clock-output-names", &name)) if (of_property_read_string(np, "clock-output-names", &name))
name = progclknp->name; name = progclknp->name;
irq = irq_of_parse_and_map(progclknp, 0); clk = at91_clk_register_programmable(pmc, name,
if (!irq)
continue;
clk = at91_clk_register_programmable(pmc, irq, name,
parent_names, num_parents, parent_names, num_parents,
id, layout); id, layout);
if (IS_ERR(clk)) if (IS_ERR(clk))
......
...@@ -14,6 +14,11 @@ ...@@ -14,6 +14,11 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/irq.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include "pmc.h" #include "pmc.h"
...@@ -25,19 +30,48 @@ ...@@ -25,19 +30,48 @@
struct clk_system { struct clk_system {
struct clk_hw hw; struct clk_hw hw;
struct at91_pmc *pmc; struct at91_pmc *pmc;
unsigned int irq;
wait_queue_head_t wait;
u8 id; u8 id;
}; };
static int clk_system_enable(struct clk_hw *hw) static inline int is_pck(int id)
{
return (id >= 8) && (id <= 15);
}
static irqreturn_t clk_system_irq_handler(int irq, void *dev_id)
{
struct clk_system *sys = (struct clk_system *)dev_id;
wake_up(&sys->wait);
disable_irq_nosync(sys->irq);
return IRQ_HANDLED;
}
static int clk_system_prepare(struct clk_hw *hw)
{ {
struct clk_system *sys = to_clk_system(hw); struct clk_system *sys = to_clk_system(hw);
struct at91_pmc *pmc = sys->pmc; struct at91_pmc *pmc = sys->pmc;
u32 mask = 1 << sys->id;
pmc_write(pmc, AT91_PMC_SCER, mask);
pmc_write(pmc, AT91_PMC_SCER, 1 << sys->id); if (!is_pck(sys->id))
return 0;
while (!(pmc_read(pmc, AT91_PMC_SR) & mask)) {
if (sys->irq) {
enable_irq(sys->irq);
wait_event(sys->wait,
pmc_read(pmc, AT91_PMC_SR) & mask);
} else
cpu_relax();
}
return 0; return 0;
} }
static void clk_system_disable(struct clk_hw *hw) static void clk_system_unprepare(struct clk_hw *hw)
{ {
struct clk_system *sys = to_clk_system(hw); struct clk_system *sys = to_clk_system(hw);
struct at91_pmc *pmc = sys->pmc; struct at91_pmc *pmc = sys->pmc;
...@@ -45,27 +79,34 @@ static void clk_system_disable(struct clk_hw *hw) ...@@ -45,27 +79,34 @@ static void clk_system_disable(struct clk_hw *hw)
pmc_write(pmc, AT91_PMC_SCDR, 1 << sys->id); pmc_write(pmc, AT91_PMC_SCDR, 1 << sys->id);
} }
static int clk_system_is_enabled(struct clk_hw *hw) static int clk_system_is_prepared(struct clk_hw *hw)
{ {
struct clk_system *sys = to_clk_system(hw); struct clk_system *sys = to_clk_system(hw);
struct at91_pmc *pmc = sys->pmc; struct at91_pmc *pmc = sys->pmc;
return !!(pmc_read(pmc, AT91_PMC_SCSR) & (1 << sys->id)); if (!(pmc_read(pmc, AT91_PMC_SCSR) & (1 << sys->id)))
return 0;
if (!is_pck(sys->id))
return 1;
return !!(pmc_read(pmc, AT91_PMC_SR) & (1 << sys->id));
} }
static const struct clk_ops system_ops = { static const struct clk_ops system_ops = {
.enable = clk_system_enable, .prepare = clk_system_prepare,
.disable = clk_system_disable, .unprepare = clk_system_unprepare,
.is_enabled = clk_system_is_enabled, .is_prepared = clk_system_is_prepared,
}; };
static struct clk * __init static struct clk * __init
at91_clk_register_system(struct at91_pmc *pmc, const char *name, at91_clk_register_system(struct at91_pmc *pmc, const char *name,
const char *parent_name, u8 id) const char *parent_name, u8 id, int irq)
{ {
struct clk_system *sys; struct clk_system *sys;
struct clk *clk = NULL; struct clk *clk = NULL;
struct clk_init_data init; struct clk_init_data init;
int ret;
if (!parent_name || id > SYSTEM_MAX_ID) if (!parent_name || id > SYSTEM_MAX_ID)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -84,11 +125,20 @@ at91_clk_register_system(struct at91_pmc *pmc, const char *name, ...@@ -84,11 +125,20 @@ at91_clk_register_system(struct at91_pmc *pmc, const char *name,
* (see drivers/memory) which would request and enable the ddrck clock. * (see drivers/memory) which would request and enable the ddrck clock.
* When this is done we will be able to remove CLK_IGNORE_UNUSED flag. * When this is done we will be able to remove CLK_IGNORE_UNUSED flag.
*/ */
init.flags = CLK_IGNORE_UNUSED; init.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED;
sys->id = id; sys->id = id;
sys->hw.init = &init; sys->hw.init = &init;
sys->pmc = pmc; sys->pmc = pmc;
sys->irq = irq;
if (irq) {
init_waitqueue_head(&sys->wait);
irq_set_status_flags(sys->irq, IRQ_NOAUTOEN);
ret = request_irq(sys->irq, clk_system_irq_handler,
IRQF_TRIGGER_HIGH, name, sys);
if (ret)
return ERR_PTR(ret);
}
clk = clk_register(NULL, &sys->hw); clk = clk_register(NULL, &sys->hw);
if (IS_ERR(clk)) if (IS_ERR(clk))
...@@ -101,6 +151,7 @@ static void __init ...@@ -101,6 +151,7 @@ static void __init
of_at91_clk_sys_setup(struct device_node *np, struct at91_pmc *pmc) of_at91_clk_sys_setup(struct device_node *np, struct at91_pmc *pmc)
{ {
int num; int num;
int irq = 0;
u32 id; u32 id;
struct clk *clk; struct clk *clk;
const char *name; const char *name;
...@@ -118,9 +169,12 @@ of_at91_clk_sys_setup(struct device_node *np, struct at91_pmc *pmc) ...@@ -118,9 +169,12 @@ of_at91_clk_sys_setup(struct device_node *np, struct at91_pmc *pmc)
if (of_property_read_string(np, "clock-output-names", &name)) if (of_property_read_string(np, "clock-output-names", &name))
name = sysclknp->name; name = sysclknp->name;
if (is_pck(id))
irq = irq_of_parse_and_map(sysclknp, 0);
parent_name = of_clk_get_parent_name(sysclknp, 0); parent_name = of_clk_get_parent_name(sysclknp, 0);
clk = at91_clk_register_system(pmc, name, parent_name, id); clk = at91_clk_register_system(pmc, name, parent_name, id, irq);
if (IS_ERR(clk)) if (IS_ERR(clk))
continue; continue;
......
This diff is collapsed.
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
* Traits of this clock: * Traits of this clock:
* prepare - clk_prepare only ensures that parents are prepared * prepare - clk_prepare only ensures that parents are prepared
* enable - clk_enable only ensures that parents are enabled * enable - clk_enable only ensures that parents are enabled
* rate - rate is adjustable. clk->rate = parent->rate / divisor * rate - rate is adjustable. clk->rate = DIV_ROUND_UP(parent->rate / divisor)
* parent - fixed parent. No clk_set_parent support * parent - fixed parent. No clk_set_parent support
*/ */
...@@ -115,7 +115,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, ...@@ -115,7 +115,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
return parent_rate; return parent_rate;
} }
return parent_rate / div; return DIV_ROUND_UP(parent_rate, div);
} }
/* /*
...@@ -185,7 +185,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, ...@@ -185,7 +185,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
} }
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
MULT_ROUND_UP(rate, i)); MULT_ROUND_UP(rate, i));
now = parent_rate / i; now = DIV_ROUND_UP(parent_rate, i);
if (now <= rate && now > best) { if (now <= rate && now > best) {
bestdiv = i; bestdiv = i;
best = now; best = now;
...@@ -207,7 +207,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -207,7 +207,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
int div; int div;
div = clk_divider_bestdiv(hw, rate, prate); div = clk_divider_bestdiv(hw, rate, prate);
return *prate / div; return DIV_ROUND_UP(*prate, div);
} }
static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
...@@ -218,7 +218,7 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -218,7 +218,7 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long flags = 0; unsigned long flags = 0;
u32 val; u32 val;
div = parent_rate / rate; div = DIV_ROUND_UP(parent_rate, rate);
value = _get_val(divider, div); value = _get_val(divider, div);
if (value > div_mask(divider)) if (value > div_mask(divider))
......
/*
* MOXA ART SoCs clock driver.
*
* Copyright (C) 2013 Jonas Jensen
*
* Jonas Jensen <jonas.jensen@gmail.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.
*/
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/clkdev.h>
void __init moxart_of_pll_clk_init(struct device_node *node)
{
static void __iomem *base;
struct clk *clk, *ref_clk;
unsigned int mul;
const char *name = node->name;
const char *parent_name;
of_property_read_string(node, "clock-output-names", &name);
parent_name = of_clk_get_parent_name(node, 0);
base = of_iomap(node, 0);
if (!base) {
pr_err("%s: of_iomap failed\n", node->full_name);
return;
}
mul = readl(base + 0x30) >> 3 & 0x3f;
iounmap(base);
ref_clk = of_clk_get(node, 0);
if (IS_ERR(ref_clk)) {
pr_err("%s: of_clk_get failed\n", node->full_name);
return;
}
clk = clk_register_fixed_factor(NULL, name, parent_name, 0, mul, 1);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock\n", node->full_name);
return;
}
clk_register_clkdev(clk, NULL, name);
of_clk_add_provider(node, of_clk_src_simple_get, clk);
}
CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock",
moxart_of_pll_clk_init);
void __init moxart_of_apb_clk_init(struct device_node *node)
{
static void __iomem *base;
struct clk *clk, *pll_clk;
unsigned int div, val;
unsigned int div_idx[] = { 2, 3, 4, 6, 8};
const char *name = node->name;
const char *parent_name;
of_property_read_string(node, "clock-output-names", &name);
parent_name = of_clk_get_parent_name(node, 0);
base = of_iomap(node, 0);
if (!base) {
pr_err("%s: of_iomap failed\n", node->full_name);
return;
}
val = readl(base + 0xc) >> 4 & 0x7;
iounmap(base);
if (val > 4)
val = 0;
div = div_idx[val] * 2;
pll_clk = of_clk_get(node, 0);
if (IS_ERR(pll_clk)) {
pr_err("%s: of_clk_get failed\n", node->full_name);
return;
}
clk = clk_register_fixed_factor(NULL, name, parent_name, 0, 1, div);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock\n", node->full_name);
return;
}
clk_register_clkdev(clk, NULL, name);
of_clk_add_provider(node, of_clk_src_simple_get, clk);
}
CLK_OF_DECLARE(moxart_apb_clock, "moxa,moxart-apb-clock",
moxart_of_apb_clk_init);
...@@ -27,7 +27,6 @@ struct cmux_clk { ...@@ -27,7 +27,6 @@ struct cmux_clk {
#define CLKSEL_ADJUST BIT(0) #define CLKSEL_ADJUST BIT(0)
#define to_cmux_clk(p) container_of(p, struct cmux_clk, hw) #define to_cmux_clk(p) container_of(p, struct cmux_clk, hw)
static void __iomem *base;
static unsigned int clocks_per_pll; static unsigned int clocks_per_pll;
static int cmux_set_parent(struct clk_hw *hw, u8 idx) static int cmux_set_parent(struct clk_hw *hw, u8 idx)
...@@ -100,7 +99,11 @@ static void __init core_mux_init(struct device_node *np) ...@@ -100,7 +99,11 @@ static void __init core_mux_init(struct device_node *np)
pr_err("%s: could not allocate cmux_clk\n", __func__); pr_err("%s: could not allocate cmux_clk\n", __func__);
goto err_name; goto err_name;
} }
cmux_clk->reg = base + offset; cmux_clk->reg = of_iomap(np, 0);
if (!cmux_clk->reg) {
pr_err("%s: could not map register\n", __func__);
goto err_clk;
}
node = of_find_compatible_node(NULL, NULL, "fsl,p4080-clockgen"); node = of_find_compatible_node(NULL, NULL, "fsl,p4080-clockgen");
if (node && (offset >= 0x80)) if (node && (offset >= 0x80))
...@@ -143,38 +146,39 @@ static void __init core_mux_init(struct device_node *np) ...@@ -143,38 +146,39 @@ static void __init core_mux_init(struct device_node *np)
static void __init core_pll_init(struct device_node *np) static void __init core_pll_init(struct device_node *np)
{ {
u32 offset, mult; u32 mult;
int i, rc, count; int i, rc, count;
const char *clk_name, *parent_name; const char *clk_name, *parent_name;
struct clk_onecell_data *onecell_data; struct clk_onecell_data *onecell_data;
struct clk **subclks; struct clk **subclks;
void __iomem *base;
rc = of_property_read_u32(np, "reg", &offset); base = of_iomap(np, 0);
if (rc) { if (!base) {
pr_err("%s: could not get reg property\n", np->name); pr_err("clk-ppc: iomap error\n");
return; return;
} }
/* get the multiple of PLL */ /* get the multiple of PLL */
mult = ioread32be(base + offset); mult = ioread32be(base);
/* check if this PLL is disabled */ /* check if this PLL is disabled */
if (mult & PLL_KILL) { if (mult & PLL_KILL) {
pr_debug("PLL:%s is disabled\n", np->name); pr_debug("PLL:%s is disabled\n", np->name);
return; goto err_map;
} }
mult = (mult >> 1) & 0x3f; mult = (mult >> 1) & 0x3f;
parent_name = of_clk_get_parent_name(np, 0); parent_name = of_clk_get_parent_name(np, 0);
if (!parent_name) { if (!parent_name) {
pr_err("PLL: %s must have a parent\n", np->name); pr_err("PLL: %s must have a parent\n", np->name);
return; goto err_map;
} }
count = of_property_count_strings(np, "clock-output-names"); count = of_property_count_strings(np, "clock-output-names");
if (count < 0 || count > 4) { if (count < 0 || count > 4) {
pr_err("%s: clock is not supported\n", np->name); pr_err("%s: clock is not supported\n", np->name);
return; goto err_map;
} }
/* output clock number per PLL */ /* output clock number per PLL */
...@@ -183,7 +187,7 @@ static void __init core_pll_init(struct device_node *np) ...@@ -183,7 +187,7 @@ static void __init core_pll_init(struct device_node *np)
subclks = kzalloc(sizeof(struct clk *) * count, GFP_KERNEL); subclks = kzalloc(sizeof(struct clk *) * count, GFP_KERNEL);
if (!subclks) { if (!subclks) {
pr_err("%s: could not allocate subclks\n", __func__); pr_err("%s: could not allocate subclks\n", __func__);
return; goto err_map;
} }
onecell_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL); onecell_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
...@@ -230,30 +234,52 @@ static void __init core_pll_init(struct device_node *np) ...@@ -230,30 +234,52 @@ static void __init core_pll_init(struct device_node *np)
goto err_cell; goto err_cell;
} }
iounmap(base);
return; return;
err_cell: err_cell:
kfree(onecell_data); kfree(onecell_data);
err_clks: err_clks:
kfree(subclks); kfree(subclks);
err_map:
iounmap(base);
}
static void __init sysclk_init(struct device_node *node)
{
struct clk *clk;
const char *clk_name = node->name;
struct device_node *np = of_get_parent(node);
u32 rate;
if (!np) {
pr_err("ppc-clk: could not get parent node\n");
return;
}
if (of_property_read_u32(np, "clock-frequency", &rate)) {
of_node_put(node);
return;
}
of_property_read_string(np, "clock-output-names", &clk_name);
clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT, rate);
if (!IS_ERR(clk))
of_clk_add_provider(np, of_clk_src_simple_get, clk);
} }
static const struct of_device_id clk_match[] __initconst = { static const struct of_device_id clk_match[] __initconst = {
{ .compatible = "fixed-clock", .data = of_fixed_clk_setup, }, { .compatible = "fsl,qoriq-sysclk-1.0", .data = sysclk_init, },
{ .compatible = "fsl,core-pll-clock", .data = core_pll_init, }, { .compatible = "fsl,qoriq-sysclk-2.0", .data = sysclk_init, },
{ .compatible = "fsl,core-mux-clock", .data = core_mux_init, }, { .compatible = "fsl,qoriq-core-pll-1.0", .data = core_pll_init, },
{ .compatible = "fsl,qoriq-core-pll-2.0", .data = core_pll_init, },
{ .compatible = "fsl,qoriq-core-mux-1.0", .data = core_mux_init, },
{ .compatible = "fsl,qoriq-core-mux-2.0", .data = core_mux_init, },
{} {}
}; };
static int __init ppc_corenet_clk_probe(struct platform_device *pdev) static int __init ppc_corenet_clk_probe(struct platform_device *pdev)
{ {
struct device_node *np;
np = pdev->dev.of_node;
base = of_iomap(np, 0);
if (!base) {
dev_err(&pdev->dev, "iomap error\n");
return -ENOMEM;
}
of_clk_init(clk_match); of_clk_init(clk_match);
return 0; return 0;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mfd/samsung/s2mps11.h> #include <linux/mfd/samsung/s2mps11.h>
#include <linux/mfd/samsung/s5m8767.h>
#include <linux/mfd/samsung/core.h> #include <linux/mfd/samsung/core.h>
#define s2mps11_name(a) (a->hw.init->name) #define s2mps11_name(a) (a->hw.init->name)
...@@ -48,6 +49,7 @@ struct s2mps11_clk { ...@@ -48,6 +49,7 @@ struct s2mps11_clk {
struct clk_lookup *lookup; struct clk_lookup *lookup;
u32 mask; u32 mask;
bool enabled; bool enabled;
unsigned int reg;
}; };
static struct s2mps11_clk *to_s2mps11_clk(struct clk_hw *hw) static struct s2mps11_clk *to_s2mps11_clk(struct clk_hw *hw)
...@@ -61,7 +63,7 @@ static int s2mps11_clk_prepare(struct clk_hw *hw) ...@@ -61,7 +63,7 @@ static int s2mps11_clk_prepare(struct clk_hw *hw)
int ret; int ret;
ret = regmap_update_bits(s2mps11->iodev->regmap_pmic, ret = regmap_update_bits(s2mps11->iodev->regmap_pmic,
S2MPS11_REG_RTC_CTRL, s2mps11->reg,
s2mps11->mask, s2mps11->mask); s2mps11->mask, s2mps11->mask);
if (!ret) if (!ret)
s2mps11->enabled = true; s2mps11->enabled = true;
...@@ -74,7 +76,7 @@ static void s2mps11_clk_unprepare(struct clk_hw *hw) ...@@ -74,7 +76,7 @@ static void s2mps11_clk_unprepare(struct clk_hw *hw)
struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw); struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
int ret; int ret;
ret = regmap_update_bits(s2mps11->iodev->regmap_pmic, S2MPS11_REG_RTC_CTRL, ret = regmap_update_bits(s2mps11->iodev->regmap_pmic, s2mps11->reg,
s2mps11->mask, ~s2mps11->mask); s2mps11->mask, ~s2mps11->mask);
if (!ret) if (!ret)
...@@ -130,9 +132,9 @@ static struct device_node *s2mps11_clk_parse_dt(struct platform_device *pdev) ...@@ -130,9 +132,9 @@ static struct device_node *s2mps11_clk_parse_dt(struct platform_device *pdev)
int i; int i;
if (!iodev->dev->of_node) if (!iodev->dev->of_node)
return NULL; return ERR_PTR(-EINVAL);
clk_np = of_find_node_by_name(iodev->dev->of_node, "clocks"); clk_np = of_get_child_by_name(iodev->dev->of_node, "clocks");
if (!clk_np) { if (!clk_np) {
dev_err(&pdev->dev, "could not find clock sub-node\n"); dev_err(&pdev->dev, "could not find clock sub-node\n");
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -155,6 +157,7 @@ static int s2mps11_clk_probe(struct platform_device *pdev) ...@@ -155,6 +157,7 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct s2mps11_clk *s2mps11_clks, *s2mps11_clk; struct s2mps11_clk *s2mps11_clks, *s2mps11_clk;
struct device_node *clk_np = NULL; struct device_node *clk_np = NULL;
unsigned int s2mps11_reg;
int i, ret = 0; int i, ret = 0;
u32 val; u32 val;
...@@ -169,13 +172,26 @@ static int s2mps11_clk_probe(struct platform_device *pdev) ...@@ -169,13 +172,26 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
if (IS_ERR(clk_np)) if (IS_ERR(clk_np))
return PTR_ERR(clk_np); return PTR_ERR(clk_np);
switch(platform_get_device_id(pdev)->driver_data) {
case S2MPS11X:
s2mps11_reg = S2MPS11_REG_RTC_CTRL;
break;
case S5M8767X:
s2mps11_reg = S5M8767_REG_CTRL1;
break;
default:
dev_err(&pdev->dev, "Invalid device type\n");
return -EINVAL;
};
for (i = 0; i < S2MPS11_CLKS_NUM; i++, s2mps11_clk++) { for (i = 0; i < S2MPS11_CLKS_NUM; i++, s2mps11_clk++) {
s2mps11_clk->iodev = iodev; s2mps11_clk->iodev = iodev;
s2mps11_clk->hw.init = &s2mps11_clks_init[i]; s2mps11_clk->hw.init = &s2mps11_clks_init[i];
s2mps11_clk->mask = 1 << i; s2mps11_clk->mask = 1 << i;
s2mps11_clk->reg = s2mps11_reg;
ret = regmap_read(s2mps11_clk->iodev->regmap_pmic, ret = regmap_read(s2mps11_clk->iodev->regmap_pmic,
S2MPS11_REG_RTC_CTRL, &val); s2mps11_clk->reg, &val);
if (ret < 0) if (ret < 0)
goto err_reg; goto err_reg;
...@@ -241,7 +257,8 @@ static int s2mps11_clk_remove(struct platform_device *pdev) ...@@ -241,7 +257,8 @@ static int s2mps11_clk_remove(struct platform_device *pdev)
} }
static const struct platform_device_id s2mps11_clk_id[] = { static const struct platform_device_id s2mps11_clk_id[] = {
{ "s2mps11-clk", 0}, { "s2mps11-clk", S2MPS11X},
{ "s5m8767-clk", S5M8767X},
{ }, { },
}; };
MODULE_DEVICE_TABLE(platform, s2mps11_clk_id); MODULE_DEVICE_TABLE(platform, s2mps11_clk_id);
......
...@@ -277,6 +277,10 @@ static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry) ...@@ -277,6 +277,10 @@ static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
if (!d) if (!d)
goto err_out; goto err_out;
if (clk->ops->debug_init)
if (clk->ops->debug_init(clk->hw, clk->dentry))
goto err_out;
ret = 0; ret = 0;
goto out; goto out;
...@@ -1339,8 +1343,11 @@ static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate) ...@@ -1339,8 +1343,11 @@ static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate)
if (clk->notifier_count) if (clk->notifier_count)
ret = __clk_notify(clk, PRE_RATE_CHANGE, clk->rate, new_rate); ret = __clk_notify(clk, PRE_RATE_CHANGE, clk->rate, new_rate);
if (ret & NOTIFY_STOP_MASK) if (ret & NOTIFY_STOP_MASK) {
pr_debug("%s: clk notifier callback for clock %s aborted with error %d\n",
__func__, clk->name, ret);
goto out; goto out;
}
hlist_for_each_entry(child, &clk->children, child_node) { hlist_for_each_entry(child, &clk->children, child_node) {
ret = __clk_speculate_rates(child, new_rate); ret = __clk_speculate_rates(child, new_rate);
...@@ -1588,7 +1595,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate) ...@@ -1588,7 +1595,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
/* notify that we are about to change rates */ /* notify that we are about to change rates */
fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE); fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
if (fail_clk) { if (fail_clk) {
pr_warn("%s: failed to set %s rate\n", __func__, pr_debug("%s: failed to set %s rate\n", __func__,
fail_clk->name); fail_clk->name);
clk_propagate_rate_change(top, ABORT_RATE_CHANGE); clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
ret = -EBUSY; ret = -EBUSY;
...@@ -2260,20 +2267,11 @@ void __clk_put(struct clk *clk) ...@@ -2260,20 +2267,11 @@ void __clk_put(struct clk *clk)
* re-enter into the clk framework by calling any top-level clk APIs; * re-enter into the clk framework by calling any top-level clk APIs;
* this will cause a nested prepare_lock mutex. * this will cause a nested prepare_lock mutex.
* *
* Pre-change notifier callbacks will be passed the current, pre-change * In all notification cases cases (pre, post and abort rate change) the
* rate of the clk via struct clk_notifier_data.old_rate. The new, * original clock rate is passed to the callback via struct
* post-change rate of the clk is passed via struct * clk_notifier_data.old_rate and the new frequency is passed via struct
* clk_notifier_data.new_rate.
*
* Post-change notifiers will pass the now-current, post-change rate of
* the clk in both struct clk_notifier_data.old_rate and struct
* clk_notifier_data.new_rate. * clk_notifier_data.new_rate.
* *
* Abort-change notifiers are effectively the opposite of pre-change
* notifiers: the original pre-change clk rate is passed in via struct
* clk_notifier_data.new_rate and the failed post-change rate is passed
* in via struct clk_notifier_data.old_rate.
*
* clk_notifier_register() must be called from non-atomic context. * clk_notifier_register() must be called from non-atomic context.
* Returns -EINVAL if called with null arguments, -ENOMEM upon * Returns -EINVAL if called with null arguments, -ENOMEM upon
* allocation failure; otherwise, passes along the return value of * allocation failure; otherwise, passes along the return value of
...@@ -2473,7 +2471,7 @@ EXPORT_SYMBOL_GPL(of_clk_del_provider); ...@@ -2473,7 +2471,7 @@ EXPORT_SYMBOL_GPL(of_clk_del_provider);
struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec) struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec)
{ {
struct of_clk_provider *provider; struct of_clk_provider *provider;
struct clk *clk = ERR_PTR(-ENOENT); struct clk *clk = ERR_PTR(-EPROBE_DEFER);
/* Check if we have such a provider in our array */ /* Check if we have such a provider in our array */
list_for_each_entry(provider, &of_clk_providers, link) { list_for_each_entry(provider, &of_clk_providers, link) {
...@@ -2506,8 +2504,12 @@ EXPORT_SYMBOL_GPL(of_clk_get_parent_count); ...@@ -2506,8 +2504,12 @@ EXPORT_SYMBOL_GPL(of_clk_get_parent_count);
const char *of_clk_get_parent_name(struct device_node *np, int index) const char *of_clk_get_parent_name(struct device_node *np, int index)
{ {
struct of_phandle_args clkspec; struct of_phandle_args clkspec;
struct property *prop;
const char *clk_name; const char *clk_name;
const __be32 *vp;
u32 pv;
int rc; int rc;
int count;
if (index < 0) if (index < 0)
return NULL; return NULL;
...@@ -2517,8 +2519,22 @@ const char *of_clk_get_parent_name(struct device_node *np, int index) ...@@ -2517,8 +2519,22 @@ const char *of_clk_get_parent_name(struct device_node *np, int index)
if (rc) if (rc)
return NULL; return NULL;
index = clkspec.args_count ? clkspec.args[0] : 0;
count = 0;
/* if there is an indices property, use it to transfer the index
* specified into an array offset for the clock-output-names property.
*/
of_property_for_each_u32(clkspec.np, "clock-indices", prop, vp, pv) {
if (index == pv) {
index = count;
break;
}
count++;
}
if (of_property_read_string_index(clkspec.np, "clock-output-names", if (of_property_read_string_index(clkspec.np, "clock-output-names",
clkspec.args_count ? clkspec.args[0] : 0, index,
&clk_name) < 0) &clk_name) < 0)
clk_name = clkspec.np->name; clk_name = clkspec.np->name;
...@@ -2527,24 +2543,99 @@ const char *of_clk_get_parent_name(struct device_node *np, int index) ...@@ -2527,24 +2543,99 @@ const char *of_clk_get_parent_name(struct device_node *np, int index)
} }
EXPORT_SYMBOL_GPL(of_clk_get_parent_name); EXPORT_SYMBOL_GPL(of_clk_get_parent_name);
struct clock_provider {
of_clk_init_cb_t clk_init_cb;
struct device_node *np;
struct list_head node;
};
static LIST_HEAD(clk_provider_list);
/*
* This function looks for a parent clock. If there is one, then it
* checks that the provider for this parent clock was initialized, in
* this case the parent clock will be ready.
*/
static int parent_ready(struct device_node *np)
{
int i = 0;
while (true) {
struct clk *clk = of_clk_get(np, i);
/* this parent is ready we can check the next one */
if (!IS_ERR(clk)) {
clk_put(clk);
i++;
continue;
}
/* at least one parent is not ready, we exit now */
if (PTR_ERR(clk) == -EPROBE_DEFER)
return 0;
/*
* Here we make assumption that the device tree is
* written correctly. So an error means that there is
* no more parent. As we didn't exit yet, then the
* previous parent are ready. If there is no clock
* parent, no need to wait for them, then we can
* consider their absence as being ready
*/
return 1;
}
}
/** /**
* of_clk_init() - Scan and init clock providers from the DT * of_clk_init() - Scan and init clock providers from the DT
* @matches: array of compatible values and init functions for providers. * @matches: array of compatible values and init functions for providers.
* *
* This function scans the device tree for matching clock providers and * This function scans the device tree for matching clock providers
* calls their initialization functions * and calls their initialization functions. It also does it by trying
* to follow the dependencies.
*/ */
void __init of_clk_init(const struct of_device_id *matches) void __init of_clk_init(const struct of_device_id *matches)
{ {
const struct of_device_id *match; const struct of_device_id *match;
struct device_node *np; struct device_node *np;
struct clock_provider *clk_provider, *next;
bool is_init_done;
bool force = false;
if (!matches) if (!matches)
matches = &__clk_of_table; matches = &__clk_of_table;
/* First prepare the list of the clocks providers */
for_each_matching_node_and_match(np, matches, &match) { for_each_matching_node_and_match(np, matches, &match) {
of_clk_init_cb_t clk_init_cb = match->data; struct clock_provider *parent =
clk_init_cb(np); kzalloc(sizeof(struct clock_provider), GFP_KERNEL);
parent->clk_init_cb = match->data;
parent->np = np;
list_add_tail(&parent->node, &clk_provider_list);
}
while (!list_empty(&clk_provider_list)) {
is_init_done = false;
list_for_each_entry_safe(clk_provider, next,
&clk_provider_list, node) {
if (force || parent_ready(clk_provider->np)) {
clk_provider->clk_init_cb(clk_provider->np);
list_del(&clk_provider->node);
kfree(clk_provider);
is_init_done = true;
}
}
/*
* We didn't manage to initialize any of the
* remaining providers during the last loop, so now we
* initialize all the remaining ones unconditionally
* in case the clock parent was not mandatory
*/
if (!is_init_done)
force = true;
} }
} }
#endif #endif
...@@ -167,6 +167,8 @@ struct clk *clk_get(struct device *dev, const char *con_id) ...@@ -167,6 +167,8 @@ struct clk *clk_get(struct device *dev, const char *con_id)
clk = of_clk_get_by_name(dev->of_node, con_id); clk = of_clk_get_by_name(dev->of_node, con_id);
if (!IS_ERR(clk)) if (!IS_ERR(clk))
return clk; return clk;
if (PTR_ERR(clk) == -EPROBE_DEFER)
return clk;
} }
return clk_get_sys(dev_id, con_id); return clk_get_sys(dev_id, con_id);
......
...@@ -2,4 +2,7 @@ ...@@ -2,4 +2,7 @@
# Hisilicon Clock specific Makefile # Hisilicon Clock specific Makefile
# #
obj-y += clk.o clkgate-separated.o clk-hi3620.o obj-y += clk.o clkgate-separated.o
obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o
obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o
...@@ -210,33 +210,297 @@ static struct hisi_gate_clock hi3620_seperated_gate_clks[] __initdata = { ...@@ -210,33 +210,297 @@ static struct hisi_gate_clock hi3620_seperated_gate_clks[] __initdata = {
static void __init hi3620_clk_init(struct device_node *np) static void __init hi3620_clk_init(struct device_node *np)
{ {
void __iomem *base; struct hisi_clock_data *clk_data;
if (np) { clk_data = hisi_clk_init(np, HI3620_NR_CLKS);
base = of_iomap(np, 0); if (!clk_data)
if (!base) {
pr_err("failed to map Hi3620 clock registers\n");
return;
}
} else {
pr_err("failed to find Hi3620 clock node in DTS\n");
return; return;
}
hisi_clk_init(np, HI3620_NR_CLKS);
hisi_clk_register_fixed_rate(hi3620_fixed_rate_clks, hisi_clk_register_fixed_rate(hi3620_fixed_rate_clks,
ARRAY_SIZE(hi3620_fixed_rate_clks), ARRAY_SIZE(hi3620_fixed_rate_clks),
base); clk_data);
hisi_clk_register_fixed_factor(hi3620_fixed_factor_clks, hisi_clk_register_fixed_factor(hi3620_fixed_factor_clks,
ARRAY_SIZE(hi3620_fixed_factor_clks), ARRAY_SIZE(hi3620_fixed_factor_clks),
base); clk_data);
hisi_clk_register_mux(hi3620_mux_clks, ARRAY_SIZE(hi3620_mux_clks), hisi_clk_register_mux(hi3620_mux_clks, ARRAY_SIZE(hi3620_mux_clks),
base); clk_data);
hisi_clk_register_divider(hi3620_div_clks, ARRAY_SIZE(hi3620_div_clks), hisi_clk_register_divider(hi3620_div_clks, ARRAY_SIZE(hi3620_div_clks),
base); clk_data);
hisi_clk_register_gate_sep(hi3620_seperated_gate_clks, hisi_clk_register_gate_sep(hi3620_seperated_gate_clks,
ARRAY_SIZE(hi3620_seperated_gate_clks), ARRAY_SIZE(hi3620_seperated_gate_clks),
base); clk_data);
} }
CLK_OF_DECLARE(hi3620_clk, "hisilicon,hi3620-clock", hi3620_clk_init); CLK_OF_DECLARE(hi3620_clk, "hisilicon,hi3620-clock", hi3620_clk_init);
struct hisi_mmc_clock {
unsigned int id;
const char *name;
const char *parent_name;
unsigned long flags;
u32 clken_reg;
u32 clken_bit;
u32 div_reg;
u32 div_off;
u32 div_bits;
u32 drv_reg;
u32 drv_off;
u32 drv_bits;
u32 sam_reg;
u32 sam_off;
u32 sam_bits;
};
struct clk_mmc {
struct clk_hw hw;
u32 id;
void __iomem *clken_reg;
u32 clken_bit;
void __iomem *div_reg;
u32 div_off;
u32 div_bits;
void __iomem *drv_reg;
u32 drv_off;
u32 drv_bits;
void __iomem *sam_reg;
u32 sam_off;
u32 sam_bits;
};
#define to_mmc(_hw) container_of(_hw, struct clk_mmc, hw)
static struct hisi_mmc_clock hi3620_mmc_clks[] __initdata = {
{ HI3620_SD_CIUCLK, "sd_bclk1", "sd_clk", CLK_SET_RATE_PARENT, 0x1f8, 0, 0x1f8, 1, 3, 0x1f8, 4, 4, 0x1f8, 8, 4},
{ HI3620_MMC_CIUCLK1, "mmc_bclk1", "mmc_clk1", CLK_SET_RATE_PARENT, 0x1f8, 12, 0x1f8, 13, 3, 0x1f8, 16, 4, 0x1f8, 20, 4},
{ HI3620_MMC_CIUCLK2, "mmc_bclk2", "mmc_clk2", CLK_SET_RATE_PARENT, 0x1f8, 24, 0x1f8, 25, 3, 0x1f8, 28, 4, 0x1fc, 0, 4},
{ HI3620_MMC_CIUCLK3, "mmc_bclk3", "mmc_clk3", CLK_SET_RATE_PARENT, 0x1fc, 4, 0x1fc, 5, 3, 0x1fc, 8, 4, 0x1fc, 12, 4},
};
static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
switch (parent_rate) {
case 26000000:
return 13000000;
case 180000000:
return 25000000;
case 360000000:
return 50000000;
case 720000000:
return 100000000;
case 1440000000:
return 180000000;
default:
return parent_rate;
}
}
static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_p)
{
struct clk_mmc *mclk = to_mmc(hw);
unsigned long best = 0;
if ((rate <= 13000000) && (mclk->id == HI3620_MMC_CIUCLK1)) {
rate = 13000000;
best = 26000000;
} else if (rate <= 26000000) {
rate = 25000000;
best = 180000000;
} else if (rate <= 52000000) {
rate = 50000000;
best = 360000000;
} else if (rate <= 100000000) {
rate = 100000000;
best = 720000000;
} else {
/* max is 180M */
rate = 180000000;
best = 1440000000;
}
*best_parent_rate = best;
return rate;
}
static u32 mmc_clk_delay(u32 val, u32 para, u32 off, u32 len)
{
u32 i;
for (i = 0; i < len; i++) {
if (para % 2)
val |= 1 << (off + i);
else
val &= ~(1 << (off + i));
para = para >> 1;
}
return val;
}
static int mmc_clk_set_timing(struct clk_hw *hw, unsigned long rate)
{
struct clk_mmc *mclk = to_mmc(hw);
unsigned long flags;
u32 sam, drv, div, val;
static DEFINE_SPINLOCK(mmc_clk_lock);
switch (rate) {
case 13000000:
sam = 3;
drv = 1;
div = 1;
break;
case 25000000:
sam = 13;
drv = 6;
div = 6;
break;
case 50000000:
sam = 3;
drv = 6;
div = 6;
break;
case 100000000:
sam = 6;
drv = 4;
div = 6;
break;
case 180000000:
sam = 6;
drv = 4;
div = 7;
break;
default:
return -EINVAL;
}
spin_lock_irqsave(&mmc_clk_lock, flags);
val = readl_relaxed(mclk->clken_reg);
val &= ~(1 << mclk->clken_bit);
writel_relaxed(val, mclk->clken_reg);
val = readl_relaxed(mclk->sam_reg);
val = mmc_clk_delay(val, sam, mclk->sam_off, mclk->sam_bits);
writel_relaxed(val, mclk->sam_reg);
val = readl_relaxed(mclk->drv_reg);
val = mmc_clk_delay(val, drv, mclk->drv_off, mclk->drv_bits);
writel_relaxed(val, mclk->drv_reg);
val = readl_relaxed(mclk->div_reg);
val = mmc_clk_delay(val, div, mclk->div_off, mclk->div_bits);
writel_relaxed(val, mclk->div_reg);
val = readl_relaxed(mclk->clken_reg);
val |= 1 << mclk->clken_bit;
writel_relaxed(val, mclk->clken_reg);
spin_unlock_irqrestore(&mmc_clk_lock, flags);
return 0;
}
static int mmc_clk_prepare(struct clk_hw *hw)
{
struct clk_mmc *mclk = to_mmc(hw);
unsigned long rate;
if (mclk->id == HI3620_MMC_CIUCLK1)
rate = 13000000;
else
rate = 25000000;
return mmc_clk_set_timing(hw, rate);
}
static int mmc_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
return mmc_clk_set_timing(hw, rate);
}
static struct clk_ops clk_mmc_ops = {
.prepare = mmc_clk_prepare,
.determine_rate = mmc_clk_determine_rate,
.set_rate = mmc_clk_set_rate,
.recalc_rate = mmc_clk_recalc_rate,
};
static struct clk *hisi_register_clk_mmc(struct hisi_mmc_clock *mmc_clk,
void __iomem *base, struct device_node *np)
{
struct clk_mmc *mclk;
struct clk *clk;
struct clk_init_data init;
mclk = kzalloc(sizeof(*mclk), GFP_KERNEL);
if (!mclk) {
pr_err("%s: fail to allocate mmc clk\n", __func__);
return ERR_PTR(-ENOMEM);
}
init.name = mmc_clk->name;
init.ops = &clk_mmc_ops;
init.flags = mmc_clk->flags | CLK_IS_BASIC;
init.parent_names = (mmc_clk->parent_name ? &mmc_clk->parent_name : NULL);
init.num_parents = (mmc_clk->parent_name ? 1 : 0);
mclk->hw.init = &init;
mclk->id = mmc_clk->id;
mclk->clken_reg = base + mmc_clk->clken_reg;
mclk->clken_bit = mmc_clk->clken_bit;
mclk->div_reg = base + mmc_clk->div_reg;
mclk->div_off = mmc_clk->div_off;
mclk->div_bits = mmc_clk->div_bits;
mclk->drv_reg = base + mmc_clk->drv_reg;
mclk->drv_off = mmc_clk->drv_off;
mclk->drv_bits = mmc_clk->drv_bits;
mclk->sam_reg = base + mmc_clk->sam_reg;
mclk->sam_off = mmc_clk->sam_off;
mclk->sam_bits = mmc_clk->sam_bits;
clk = clk_register(NULL, &mclk->hw);
if (WARN_ON(IS_ERR(clk)))
kfree(mclk);
return clk;
}
static void __init hi3620_mmc_clk_init(struct device_node *node)
{
void __iomem *base;
int i, num = ARRAY_SIZE(hi3620_mmc_clks);
struct clk_onecell_data *clk_data;
if (!node) {
pr_err("failed to find pctrl node in DTS\n");
return;
}
base = of_iomap(node, 0);
if (!base) {
pr_err("failed to map pctrl\n");
return;
}
clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
if (WARN_ON(!clk_data))
return;
clk_data->clks = kzalloc(sizeof(struct clk *) * num, GFP_KERNEL);
if (!clk_data->clks) {
pr_err("%s: fail to allocate mmc clk\n", __func__);
return;
}
for (i = 0; i < num; i++) {
struct hisi_mmc_clock *mmc_clk = &hi3620_mmc_clks[i];
clk_data->clks[mmc_clk->id] =
hisi_register_clk_mmc(mmc_clk, base, node);
}
clk_data->clk_num = num;
of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
}
CLK_OF_DECLARE(hi3620_mmc_clk, "hisilicon,hi3620-mmc-clock", hi3620_mmc_clk_init);
/*
* Hisilicon HiP04 clock driver
*
* Copyright (c) 2013-2014 Hisilicon Limited.
* Copyright (c) 2013-2014 Linaro Limited.
*
* Author: Haojian Zhuang <haojian.zhuang@linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <linux/kernel.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <dt-bindings/clock/hip04-clock.h>
#include "clk.h"
/* fixed rate clocks */
static struct hisi_fixed_rate_clock hip04_fixed_rate_clks[] __initdata = {
{ HIP04_OSC50M, "osc50m", NULL, CLK_IS_ROOT, 50000000, },
{ HIP04_CLK_50M, "clk50m", NULL, CLK_IS_ROOT, 50000000, },
{ HIP04_CLK_168M, "clk168m", NULL, CLK_IS_ROOT, 168750000, },
};
static void __init hip04_clk_init(struct device_node *np)
{
struct hisi_clock_data *clk_data;
clk_data = hisi_clk_init(np, HIP04_NR_CLKS);
if (!clk_data)
return;
hisi_clk_register_fixed_rate(hip04_fixed_rate_clks,
ARRAY_SIZE(hip04_fixed_rate_clks),
clk_data);
}
CLK_OF_DECLARE(hip04_clk, "hisilicon,hip04-clock", hip04_clk_init);
...@@ -37,23 +37,49 @@ ...@@ -37,23 +37,49 @@
#include "clk.h" #include "clk.h"
static DEFINE_SPINLOCK(hisi_clk_lock); static DEFINE_SPINLOCK(hisi_clk_lock);
static struct clk **clk_table;
static struct clk_onecell_data clk_data;
void __init hisi_clk_init(struct device_node *np, int nr_clks) struct hisi_clock_data __init *hisi_clk_init(struct device_node *np,
int nr_clks)
{ {
struct hisi_clock_data *clk_data;
struct clk **clk_table;
void __iomem *base;
if (np) {
base = of_iomap(np, 0);
if (!base) {
pr_err("failed to map Hisilicon clock registers\n");
goto err;
}
} else {
pr_err("failed to find Hisilicon clock node in DTS\n");
goto err;
}
clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
if (!clk_data) {
pr_err("%s: could not allocate clock data\n", __func__);
goto err;
}
clk_data->base = base;
clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL); clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
if (!clk_table) { if (!clk_table) {
pr_err("%s: could not allocate clock lookup table\n", __func__); pr_err("%s: could not allocate clock lookup table\n", __func__);
return; goto err_data;
} }
clk_data.clks = clk_table; clk_data->clk_data.clks = clk_table;
clk_data.clk_num = nr_clks; clk_data->clk_data.clk_num = nr_clks;
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data);
return clk_data;
err_data:
kfree(clk_data);
err:
return NULL;
} }
void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *clks, void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *clks,
int nums, void __iomem *base) int nums, struct hisi_clock_data *data)
{ {
struct clk *clk; struct clk *clk;
int i; int i;
...@@ -68,11 +94,13 @@ void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *clks, ...@@ -68,11 +94,13 @@ void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *clks,
__func__, clks[i].name); __func__, clks[i].name);
continue; continue;
} }
data->clk_data.clks[clks[i].id] = clk;
} }
} }
void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *clks, void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *clks,
int nums, void __iomem *base) int nums,
struct hisi_clock_data *data)
{ {
struct clk *clk; struct clk *clk;
int i; int i;
...@@ -87,13 +115,15 @@ void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *clks, ...@@ -87,13 +115,15 @@ void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *clks,
__func__, clks[i].name); __func__, clks[i].name);
continue; continue;
} }
data->clk_data.clks[clks[i].id] = clk;
} }
} }
void __init hisi_clk_register_mux(struct hisi_mux_clock *clks, void __init hisi_clk_register_mux(struct hisi_mux_clock *clks,
int nums, void __iomem *base) int nums, struct hisi_clock_data *data)
{ {
struct clk *clk; struct clk *clk;
void __iomem *base = data->base;
int i; int i;
for (i = 0; i < nums; i++) { for (i = 0; i < nums; i++) {
...@@ -111,14 +141,15 @@ void __init hisi_clk_register_mux(struct hisi_mux_clock *clks, ...@@ -111,14 +141,15 @@ void __init hisi_clk_register_mux(struct hisi_mux_clock *clks,
if (clks[i].alias) if (clks[i].alias)
clk_register_clkdev(clk, clks[i].alias, NULL); clk_register_clkdev(clk, clks[i].alias, NULL);
clk_table[clks[i].id] = clk; data->clk_data.clks[clks[i].id] = clk;
} }
} }
void __init hisi_clk_register_divider(struct hisi_divider_clock *clks, void __init hisi_clk_register_divider(struct hisi_divider_clock *clks,
int nums, void __iomem *base) int nums, struct hisi_clock_data *data)
{ {
struct clk *clk; struct clk *clk;
void __iomem *base = data->base;
int i; int i;
for (i = 0; i < nums; i++) { for (i = 0; i < nums; i++) {
...@@ -139,14 +170,15 @@ void __init hisi_clk_register_divider(struct hisi_divider_clock *clks, ...@@ -139,14 +170,15 @@ void __init hisi_clk_register_divider(struct hisi_divider_clock *clks,
if (clks[i].alias) if (clks[i].alias)
clk_register_clkdev(clk, clks[i].alias, NULL); clk_register_clkdev(clk, clks[i].alias, NULL);
clk_table[clks[i].id] = clk; data->clk_data.clks[clks[i].id] = clk;
} }
} }
void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks, void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks,
int nums, void __iomem *base) int nums, struct hisi_clock_data *data)
{ {
struct clk *clk; struct clk *clk;
void __iomem *base = data->base;
int i; int i;
for (i = 0; i < nums; i++) { for (i = 0; i < nums; i++) {
...@@ -166,6 +198,6 @@ void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks, ...@@ -166,6 +198,6 @@ void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks,
if (clks[i].alias) if (clks[i].alias)
clk_register_clkdev(clk, clks[i].alias, NULL); clk_register_clkdev(clk, clks[i].alias, NULL);
clk_table[clks[i].id] = clk; data->clk_data.clks[clks[i].id] = clk;
} }
} }
...@@ -30,6 +30,11 @@ ...@@ -30,6 +30,11 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
struct hisi_clock_data {
struct clk_onecell_data clk_data;
void __iomem *base;
};
struct hisi_fixed_rate_clock { struct hisi_fixed_rate_clock {
unsigned int id; unsigned int id;
char *name; char *name;
...@@ -89,15 +94,15 @@ struct clk *hisi_register_clkgate_sep(struct device *, const char *, ...@@ -89,15 +94,15 @@ struct clk *hisi_register_clkgate_sep(struct device *, const char *,
void __iomem *, u8, void __iomem *, u8,
u8, spinlock_t *); u8, spinlock_t *);
void __init hisi_clk_init(struct device_node *, int); struct hisi_clock_data __init *hisi_clk_init(struct device_node *, int);
void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *, void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *,
int, void __iomem *); int, struct hisi_clock_data *);
void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *, void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *,
int, void __iomem *); int, struct hisi_clock_data *);
void __init hisi_clk_register_mux(struct hisi_mux_clock *, int, void __init hisi_clk_register_mux(struct hisi_mux_clock *, int,
void __iomem *); struct hisi_clock_data *);
void __init hisi_clk_register_divider(struct hisi_divider_clock *, void __init hisi_clk_register_divider(struct hisi_divider_clock *,
int, void __iomem *); int, struct hisi_clock_data *);
void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *, void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *,
int, void __iomem *); int, struct hisi_clock_data *);
#endif /* __HISI_CLK_H */ #endif /* __HISI_CLK_H */
...@@ -40,15 +40,19 @@ static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate, ...@@ -40,15 +40,19 @@ static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate,
for (i = 0; i < factor->ftbl_cnt; i++) { for (i = 0; i < factor->ftbl_cnt; i++) {
prev_rate = rate; prev_rate = rate;
rate = (((*prate / 10000) * factor->ftbl[i].num) / rate = (((*prate / 10000) * factor->ftbl[i].den) /
(factor->ftbl[i].den * factor->masks->factor)) * 10000; (factor->ftbl[i].num * factor->masks->factor)) * 10000;
if (rate > drate) if (rate > drate)
break; break;
} }
if (i == 0) if ((i == 0) || (i == factor->ftbl_cnt)) {
return rate;
} else {
if ((drate - prev_rate) > (rate - drate))
return rate; return rate;
else else
return prev_rate; return prev_rate;
}
} }
static unsigned long clk_factor_recalc_rate(struct clk_hw *hw, static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
...@@ -64,7 +68,7 @@ static unsigned long clk_factor_recalc_rate(struct clk_hw *hw, ...@@ -64,7 +68,7 @@ static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
num = (val >> masks->num_shift) & masks->num_mask; num = (val >> masks->num_shift) & masks->num_mask;
/* calculate denominator */ /* calculate denominator */
den = (val >> masks->den_shift) & masks->num_mask; den = (val >> masks->den_shift) & masks->den_mask;
if (!den) if (!den)
return 0; return 0;
...@@ -85,8 +89,8 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate, ...@@ -85,8 +89,8 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate,
for (i = 0; i < factor->ftbl_cnt; i++) { for (i = 0; i < factor->ftbl_cnt; i++) {
prev_rate = rate; prev_rate = rate;
rate = (((prate / 10000) * factor->ftbl[i].num) / rate = (((prate / 10000) * factor->ftbl[i].den) /
(factor->ftbl[i].den * factor->masks->factor)) * 10000; (factor->ftbl[i].num * factor->masks->factor)) * 10000;
if (rate > drate) if (rate > drate)
break; break;
} }
......
...@@ -13,6 +13,14 @@ config ARMADA_370_CLK ...@@ -13,6 +13,14 @@ config ARMADA_370_CLK
select MVEBU_CLK_CPU select MVEBU_CLK_CPU
select MVEBU_CLK_COREDIV select MVEBU_CLK_COREDIV
config ARMADA_375_CLK
bool
select MVEBU_CLK_COMMON
config ARMADA_38X_CLK
bool
select MVEBU_CLK_COMMON
config ARMADA_XP_CLK config ARMADA_XP_CLK
bool bool
select MVEBU_CLK_COMMON select MVEBU_CLK_COMMON
......
...@@ -3,6 +3,8 @@ obj-$(CONFIG_MVEBU_CLK_CPU) += clk-cpu.o ...@@ -3,6 +3,8 @@ obj-$(CONFIG_MVEBU_CLK_CPU) += clk-cpu.o
obj-$(CONFIG_MVEBU_CLK_COREDIV) += clk-corediv.o obj-$(CONFIG_MVEBU_CLK_COREDIV) += clk-corediv.o
obj-$(CONFIG_ARMADA_370_CLK) += armada-370.o obj-$(CONFIG_ARMADA_370_CLK) += armada-370.o
obj-$(CONFIG_ARMADA_375_CLK) += armada-375.o
obj-$(CONFIG_ARMADA_38X_CLK) += armada-38x.o
obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o
obj-$(CONFIG_DOVE_CLK) += dove.o obj-$(CONFIG_DOVE_CLK) += dove.o
obj-$(CONFIG_KIRKWOOD_CLK) += kirkwood.o obj-$(CONFIG_KIRKWOOD_CLK) += kirkwood.o
/*
* Marvell Armada 375 SoC clocks
*
* Copyright (C) 2014 Marvell
*
* Gregory CLEMENT <gregory.clement@free-electrons.com>
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Andrew Lunn <andrew@lunn.ch>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of.h>
#include "common.h"
/*
* Core Clocks
*/
/*
* For the Armada 375 SoCs, the CPU, DDR and L2 clocks frequencies are
* all modified at the same time, and not separately as for the Armada
* 370 or the Armada XP SoCs.
*
* SAR0[21:17] : CPU frequency DDR frequency L2 frequency
* 6 = 400 MHz 400 MHz 200 MHz
* 15 = 600 MHz 600 MHz 300 MHz
* 21 = 800 MHz 534 MHz 400 MHz
* 25 = 1000 MHz 500 MHz 500 MHz
* others reserved.
*
* SAR0[22] : TCLK frequency
* 0 = 166 MHz
* 1 = 200 MHz
*/
#define SAR1_A375_TCLK_FREQ_OPT 22
#define SAR1_A375_TCLK_FREQ_OPT_MASK 0x1
#define SAR1_A375_CPU_DDR_L2_FREQ_OPT 17
#define SAR1_A375_CPU_DDR_L2_FREQ_OPT_MASK 0x1F
static const u32 armada_375_tclk_frequencies[] __initconst = {
166000000,
200000000,
};
static u32 __init armada_375_get_tclk_freq(void __iomem *sar)
{
u8 tclk_freq_select;
tclk_freq_select = ((readl(sar) >> SAR1_A375_TCLK_FREQ_OPT) &
SAR1_A375_TCLK_FREQ_OPT_MASK);
return armada_375_tclk_frequencies[tclk_freq_select];
}
static const u32 armada_375_cpu_frequencies[] __initconst = {
0, 0, 0, 0, 0, 0,
400000000,
0, 0, 0, 0, 0, 0, 0, 0,
600000000,
0, 0, 0, 0, 0,
800000000,
0, 0, 0,
1000000000,
};
static u32 __init armada_375_get_cpu_freq(void __iomem *sar)
{
u8 cpu_freq_select;
cpu_freq_select = ((readl(sar) >> SAR1_A375_CPU_DDR_L2_FREQ_OPT) &
SAR1_A375_CPU_DDR_L2_FREQ_OPT_MASK);
if (cpu_freq_select >= ARRAY_SIZE(armada_375_cpu_frequencies)) {
pr_err("Selected CPU frequency (%d) unsupported\n",
cpu_freq_select);
return 0;
} else
return armada_375_cpu_frequencies[cpu_freq_select];
}
enum { A375_CPU_TO_DDR, A375_CPU_TO_L2 };
static const struct coreclk_ratio armada_375_coreclk_ratios[] __initconst = {
{ .id = A375_CPU_TO_L2, .name = "l2clk" },
{ .id = A375_CPU_TO_DDR, .name = "ddrclk" },
};
static const int armada_375_cpu_l2_ratios[32][2] __initconst = {
{0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {1, 2}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {1, 2},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {1, 2}, {0, 1}, {0, 1},
{0, 1}, {1, 2}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
};
static const int armada_375_cpu_ddr_ratios[32][2] __initconst = {
{0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {1, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {2, 3},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {2, 3}, {0, 1}, {0, 1},
{0, 1}, {1, 2}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
};
static void __init armada_375_get_clk_ratio(
void __iomem *sar, int id, int *mult, int *div)
{
u32 opt = ((readl(sar) >> SAR1_A375_CPU_DDR_L2_FREQ_OPT) &
SAR1_A375_CPU_DDR_L2_FREQ_OPT_MASK);
switch (id) {
case A375_CPU_TO_L2:
*mult = armada_375_cpu_l2_ratios[opt][0];
*div = armada_375_cpu_l2_ratios[opt][1];
break;
case A375_CPU_TO_DDR:
*mult = armada_375_cpu_ddr_ratios[opt][0];
*div = armada_375_cpu_ddr_ratios[opt][1];
break;
}
}
static const struct coreclk_soc_desc armada_375_coreclks = {
.get_tclk_freq = armada_375_get_tclk_freq,
.get_cpu_freq = armada_375_get_cpu_freq,
.get_clk_ratio = armada_375_get_clk_ratio,
.ratios = armada_375_coreclk_ratios,
.num_ratios = ARRAY_SIZE(armada_375_coreclk_ratios),
};
static void __init armada_375_coreclk_init(struct device_node *np)
{
mvebu_coreclk_setup(np, &armada_375_coreclks);
}
CLK_OF_DECLARE(armada_375_core_clk, "marvell,armada-375-core-clock",
armada_375_coreclk_init);
/*
* Clock Gating Control
*/
static const struct clk_gating_soc_desc armada_375_gating_desc[] __initconst = {
{ "mu", NULL, 2 },
{ "pp", NULL, 3 },
{ "ptp", NULL, 4 },
{ "pex0", NULL, 5 },
{ "pex1", NULL, 6 },
{ "audio", NULL, 8 },
{ "nd_clk", "nand", 11 },
{ "sata0_link", "sata0_core", 14 },
{ "sata0_core", NULL, 15 },
{ "usb3", NULL, 16 },
{ "sdio", NULL, 17 },
{ "usb", NULL, 18 },
{ "gop", NULL, 19 },
{ "sata1_link", "sata1_core", 20 },
{ "sata1_core", NULL, 21 },
{ "xor0", NULL, 22 },
{ "xor1", NULL, 23 },
{ "copro", NULL, 24 },
{ "tdm", NULL, 25 },
{ "crypto0_enc", NULL, 28 },
{ "crypto0_core", NULL, 29 },
{ "crypto1_enc", NULL, 30 },
{ "crypto1_core", NULL, 31 },
{ }
};
static void __init armada_375_clk_gating_init(struct device_node *np)
{
mvebu_clk_gating_setup(np, armada_375_gating_desc);
}
CLK_OF_DECLARE(armada_375_clk_gating, "marvell,armada-375-gating-clock",
armada_375_clk_gating_init);
/*
* Marvell Armada 380/385 SoC clocks
*
* Copyright (C) 2014 Marvell
*
* Gregory CLEMENT <gregory.clement@free-electrons.com>
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Andrew Lunn <andrew@lunn.ch>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of.h>
#include "common.h"
/*
* SAR[14:10] : Ratios between PCLK0, NBCLK, HCLK and DRAM clocks
*
* SAR[15] : TCLK frequency
* 0 = 250 MHz
* 1 = 200 MHz
*/
#define SAR_A380_TCLK_FREQ_OPT 15
#define SAR_A380_TCLK_FREQ_OPT_MASK 0x1
#define SAR_A380_CPU_DDR_L2_FREQ_OPT 10
#define SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK 0x1F
static const u32 armada_38x_tclk_frequencies[] __initconst = {
250000000,
200000000,
};
static u32 __init armada_38x_get_tclk_freq(void __iomem *sar)
{
u8 tclk_freq_select;
tclk_freq_select = ((readl(sar) >> SAR_A380_TCLK_FREQ_OPT) &
SAR_A380_TCLK_FREQ_OPT_MASK);
return armada_38x_tclk_frequencies[tclk_freq_select];
}
static const u32 armada_38x_cpu_frequencies[] __initconst = {
0, 0, 0, 0,
1066 * 1000 * 1000, 0, 0, 0,
1332 * 1000 * 1000, 0, 0, 0,
1600 * 1000 * 1000,
};
static u32 __init armada_38x_get_cpu_freq(void __iomem *sar)
{
u8 cpu_freq_select;
cpu_freq_select = ((readl(sar) >> SAR_A380_CPU_DDR_L2_FREQ_OPT) &
SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK);
if (cpu_freq_select >= ARRAY_SIZE(armada_38x_cpu_frequencies)) {
pr_err("Selected CPU frequency (%d) unsupported\n",
cpu_freq_select);
return 0;
}
return armada_38x_cpu_frequencies[cpu_freq_select];
}
enum { A380_CPU_TO_DDR, A380_CPU_TO_L2 };
static const struct coreclk_ratio armada_38x_coreclk_ratios[] __initconst = {
{ .id = A380_CPU_TO_L2, .name = "l2clk" },
{ .id = A380_CPU_TO_DDR, .name = "ddrclk" },
};
static const int armada_38x_cpu_l2_ratios[32][2] __initconst = {
{0, 1}, {0, 1}, {0, 1}, {0, 1},
{1, 2}, {0, 1}, {0, 1}, {0, 1},
{1, 2}, {0, 1}, {0, 1}, {0, 1},
{1, 2}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
};
static const int armada_38x_cpu_ddr_ratios[32][2] __initconst = {
{0, 1}, {0, 1}, {0, 1}, {0, 1},
{1, 2}, {0, 1}, {0, 1}, {0, 1},
{1, 2}, {0, 1}, {0, 1}, {0, 1},
{1, 2}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
};
static void __init armada_38x_get_clk_ratio(
void __iomem *sar, int id, int *mult, int *div)
{
u32 opt = ((readl(sar) >> SAR_A380_CPU_DDR_L2_FREQ_OPT) &
SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK);
switch (id) {
case A380_CPU_TO_L2:
*mult = armada_38x_cpu_l2_ratios[opt][0];
*div = armada_38x_cpu_l2_ratios[opt][1];
break;
case A380_CPU_TO_DDR:
*mult = armada_38x_cpu_ddr_ratios[opt][0];
*div = armada_38x_cpu_ddr_ratios[opt][1];
break;
}
}
static const struct coreclk_soc_desc armada_38x_coreclks = {
.get_tclk_freq = armada_38x_get_tclk_freq,
.get_cpu_freq = armada_38x_get_cpu_freq,
.get_clk_ratio = armada_38x_get_clk_ratio,
.ratios = armada_38x_coreclk_ratios,
.num_ratios = ARRAY_SIZE(armada_38x_coreclk_ratios),
};
static void __init armada_38x_coreclk_init(struct device_node *np)
{
mvebu_coreclk_setup(np, &armada_38x_coreclks);
}
CLK_OF_DECLARE(armada_38x_core_clk, "marvell,armada-380-core-clock",
armada_38x_coreclk_init);
/*
* Clock Gating Control
*/
static const struct clk_gating_soc_desc armada_38x_gating_desc[] __initconst = {
{ "audio", NULL, 0 },
{ "ge2", NULL, 2 },
{ "ge1", NULL, 3 },
{ "ge0", NULL, 4 },
{ "pex1", NULL, 5 },
{ "pex2", NULL, 6 },
{ "pex3", NULL, 7 },
{ "pex0", NULL, 8 },
{ "usb3h0", NULL, 9 },
{ "usb3h1", NULL, 10 },
{ "usb3d", NULL, 11 },
{ "bm", NULL, 13 },
{ "crypto0z", NULL, 14 },
{ "sata0", NULL, 15 },
{ "crypto1z", NULL, 16 },
{ "sdio", NULL, 17 },
{ "usb2", NULL, 18 },
{ "crypto1", NULL, 21 },
{ "xor0", NULL, 22 },
{ "crypto0", NULL, 23 },
{ "tdm", NULL, 25 },
{ "xor1", NULL, 28 },
{ "sata1", NULL, 30 },
{ }
};
static void __init armada_38x_clk_gating_init(struct device_node *np)
{
mvebu_clk_gating_setup(np, armada_38x_gating_desc);
}
CLK_OF_DECLARE(armada_38x_clk_gating, "marvell,armada-380-gating-clock",
armada_38x_clk_gating_init);
...@@ -18,26 +18,56 @@ ...@@ -18,26 +18,56 @@
#include "common.h" #include "common.h"
#define CORE_CLK_DIV_RATIO_MASK 0xff #define CORE_CLK_DIV_RATIO_MASK 0xff
#define CORE_CLK_DIV_RATIO_RELOAD BIT(8)
#define CORE_CLK_DIV_ENABLE_OFFSET 24
#define CORE_CLK_DIV_RATIO_OFFSET 0x8
/*
* This structure describes the hardware details (bit offset and mask)
* to configure one particular core divider clock. Those hardware
* details may differ from one SoC to another. This structure is
* therefore typically instantiated statically to describe the
* hardware details.
*/
struct clk_corediv_desc { struct clk_corediv_desc {
unsigned int mask; unsigned int mask;
unsigned int offset; unsigned int offset;
unsigned int fieldbit; unsigned int fieldbit;
}; };
/*
* This structure describes the hardware details to configure the core
* divider clocks on a given SoC. Amongst others, it points to the
* array of core divider clock descriptors for this SoC, as well as
* the corresponding operations to manipulate them.
*/
struct clk_corediv_soc_desc {
const struct clk_corediv_desc *descs;
unsigned int ndescs;
const struct clk_ops ops;
u32 ratio_reload;
u32 enable_bit_offset;
u32 ratio_offset;
};
/*
* This structure represents one core divider clock for the clock
* framework, and is dynamically allocated for each core divider clock
* existing in the current SoC.
*/
struct clk_corediv { struct clk_corediv {
struct clk_hw hw; struct clk_hw hw;
void __iomem *reg; void __iomem *reg;
struct clk_corediv_desc desc; const struct clk_corediv_desc *desc;
const struct clk_corediv_soc_desc *soc_desc;
spinlock_t lock; spinlock_t lock;
}; };
static struct clk_onecell_data clk_data; static struct clk_onecell_data clk_data;
static const struct clk_corediv_desc mvebu_corediv_desc[] __initconst = { /*
* Description of the core divider clocks available. For now, we
* support only NAND, and it is available at the same register
* locations regardless of the SoC.
*/
static const struct clk_corediv_desc mvebu_corediv_desc[] = {
{ .mask = 0x3f, .offset = 8, .fieldbit = 1 }, /* NAND clock */ { .mask = 0x3f, .offset = 8, .fieldbit = 1 }, /* NAND clock */
}; };
...@@ -46,8 +76,9 @@ static const struct clk_corediv_desc mvebu_corediv_desc[] __initconst = { ...@@ -46,8 +76,9 @@ static const struct clk_corediv_desc mvebu_corediv_desc[] __initconst = {
static int clk_corediv_is_enabled(struct clk_hw *hwclk) static int clk_corediv_is_enabled(struct clk_hw *hwclk)
{ {
struct clk_corediv *corediv = to_corediv_clk(hwclk); struct clk_corediv *corediv = to_corediv_clk(hwclk);
struct clk_corediv_desc *desc = &corediv->desc; const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
u32 enable_mask = BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET; const struct clk_corediv_desc *desc = corediv->desc;
u32 enable_mask = BIT(desc->fieldbit) << soc_desc->enable_bit_offset;
return !!(readl(corediv->reg) & enable_mask); return !!(readl(corediv->reg) & enable_mask);
} }
...@@ -55,14 +86,15 @@ static int clk_corediv_is_enabled(struct clk_hw *hwclk) ...@@ -55,14 +86,15 @@ static int clk_corediv_is_enabled(struct clk_hw *hwclk)
static int clk_corediv_enable(struct clk_hw *hwclk) static int clk_corediv_enable(struct clk_hw *hwclk)
{ {
struct clk_corediv *corediv = to_corediv_clk(hwclk); struct clk_corediv *corediv = to_corediv_clk(hwclk);
struct clk_corediv_desc *desc = &corediv->desc; const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
const struct clk_corediv_desc *desc = corediv->desc;
unsigned long flags = 0; unsigned long flags = 0;
u32 reg; u32 reg;
spin_lock_irqsave(&corediv->lock, flags); spin_lock_irqsave(&corediv->lock, flags);
reg = readl(corediv->reg); reg = readl(corediv->reg);
reg |= (BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET); reg |= (BIT(desc->fieldbit) << soc_desc->enable_bit_offset);
writel(reg, corediv->reg); writel(reg, corediv->reg);
spin_unlock_irqrestore(&corediv->lock, flags); spin_unlock_irqrestore(&corediv->lock, flags);
...@@ -73,14 +105,15 @@ static int clk_corediv_enable(struct clk_hw *hwclk) ...@@ -73,14 +105,15 @@ static int clk_corediv_enable(struct clk_hw *hwclk)
static void clk_corediv_disable(struct clk_hw *hwclk) static void clk_corediv_disable(struct clk_hw *hwclk)
{ {
struct clk_corediv *corediv = to_corediv_clk(hwclk); struct clk_corediv *corediv = to_corediv_clk(hwclk);
struct clk_corediv_desc *desc = &corediv->desc; const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
const struct clk_corediv_desc *desc = corediv->desc;
unsigned long flags = 0; unsigned long flags = 0;
u32 reg; u32 reg;
spin_lock_irqsave(&corediv->lock, flags); spin_lock_irqsave(&corediv->lock, flags);
reg = readl(corediv->reg); reg = readl(corediv->reg);
reg &= ~(BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET); reg &= ~(BIT(desc->fieldbit) << soc_desc->enable_bit_offset);
writel(reg, corediv->reg); writel(reg, corediv->reg);
spin_unlock_irqrestore(&corediv->lock, flags); spin_unlock_irqrestore(&corediv->lock, flags);
...@@ -90,10 +123,11 @@ static unsigned long clk_corediv_recalc_rate(struct clk_hw *hwclk, ...@@ -90,10 +123,11 @@ static unsigned long clk_corediv_recalc_rate(struct clk_hw *hwclk,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct clk_corediv *corediv = to_corediv_clk(hwclk); struct clk_corediv *corediv = to_corediv_clk(hwclk);
struct clk_corediv_desc *desc = &corediv->desc; const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
const struct clk_corediv_desc *desc = corediv->desc;
u32 reg, div; u32 reg, div;
reg = readl(corediv->reg + CORE_CLK_DIV_RATIO_OFFSET); reg = readl(corediv->reg + soc_desc->ratio_offset);
div = (reg >> desc->offset) & desc->mask; div = (reg >> desc->offset) & desc->mask;
return parent_rate / div; return parent_rate / div;
} }
...@@ -117,7 +151,8 @@ static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate, ...@@ -117,7 +151,8 @@ static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct clk_corediv *corediv = to_corediv_clk(hwclk); struct clk_corediv *corediv = to_corediv_clk(hwclk);
struct clk_corediv_desc *desc = &corediv->desc; const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
const struct clk_corediv_desc *desc = corediv->desc;
unsigned long flags = 0; unsigned long flags = 0;
u32 reg, div; u32 reg, div;
...@@ -126,17 +161,17 @@ static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate, ...@@ -126,17 +161,17 @@ static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate,
spin_lock_irqsave(&corediv->lock, flags); spin_lock_irqsave(&corediv->lock, flags);
/* Write new divider to the divider ratio register */ /* Write new divider to the divider ratio register */
reg = readl(corediv->reg + CORE_CLK_DIV_RATIO_OFFSET); reg = readl(corediv->reg + soc_desc->ratio_offset);
reg &= ~(desc->mask << desc->offset); reg &= ~(desc->mask << desc->offset);
reg |= (div & desc->mask) << desc->offset; reg |= (div & desc->mask) << desc->offset;
writel(reg, corediv->reg + CORE_CLK_DIV_RATIO_OFFSET); writel(reg, corediv->reg + soc_desc->ratio_offset);
/* Set reload-force for this clock */ /* Set reload-force for this clock */
reg = readl(corediv->reg) | BIT(desc->fieldbit); reg = readl(corediv->reg) | BIT(desc->fieldbit);
writel(reg, corediv->reg); writel(reg, corediv->reg);
/* Now trigger the clock update */ /* Now trigger the clock update */
reg = readl(corediv->reg) | CORE_CLK_DIV_RATIO_RELOAD; reg = readl(corediv->reg) | soc_desc->ratio_reload;
writel(reg, corediv->reg); writel(reg, corediv->reg);
/* /*
...@@ -144,7 +179,7 @@ static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate, ...@@ -144,7 +179,7 @@ static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate,
* ratios request and the reload request. * ratios request and the reload request.
*/ */
udelay(1000); udelay(1000);
reg &= ~(CORE_CLK_DIV_RATIO_MASK | CORE_CLK_DIV_RATIO_RELOAD); reg &= ~(CORE_CLK_DIV_RATIO_MASK | soc_desc->ratio_reload);
writel(reg, corediv->reg); writel(reg, corediv->reg);
udelay(1000); udelay(1000);
...@@ -153,16 +188,53 @@ static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate, ...@@ -153,16 +188,53 @@ static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate,
return 0; return 0;
} }
static const struct clk_ops corediv_ops = { static const struct clk_corediv_soc_desc armada370_corediv_soc = {
.descs = mvebu_corediv_desc,
.ndescs = ARRAY_SIZE(mvebu_corediv_desc),
.ops = {
.enable = clk_corediv_enable,
.disable = clk_corediv_disable,
.is_enabled = clk_corediv_is_enabled,
.recalc_rate = clk_corediv_recalc_rate,
.round_rate = clk_corediv_round_rate,
.set_rate = clk_corediv_set_rate,
},
.ratio_reload = BIT(8),
.enable_bit_offset = 24,
.ratio_offset = 0x8,
};
static const struct clk_corediv_soc_desc armada380_corediv_soc = {
.descs = mvebu_corediv_desc,
.ndescs = ARRAY_SIZE(mvebu_corediv_desc),
.ops = {
.enable = clk_corediv_enable, .enable = clk_corediv_enable,
.disable = clk_corediv_disable, .disable = clk_corediv_disable,
.is_enabled = clk_corediv_is_enabled, .is_enabled = clk_corediv_is_enabled,
.recalc_rate = clk_corediv_recalc_rate, .recalc_rate = clk_corediv_recalc_rate,
.round_rate = clk_corediv_round_rate, .round_rate = clk_corediv_round_rate,
.set_rate = clk_corediv_set_rate, .set_rate = clk_corediv_set_rate,
},
.ratio_reload = BIT(8),
.enable_bit_offset = 16,
.ratio_offset = 0x4,
};
static const struct clk_corediv_soc_desc armada375_corediv_soc = {
.descs = mvebu_corediv_desc,
.ndescs = ARRAY_SIZE(mvebu_corediv_desc),
.ops = {
.recalc_rate = clk_corediv_recalc_rate,
.round_rate = clk_corediv_round_rate,
.set_rate = clk_corediv_set_rate,
},
.ratio_reload = BIT(8),
.ratio_offset = 0x4,
}; };
static void __init mvebu_corediv_clk_init(struct device_node *node) static void __init
mvebu_corediv_clk_init(struct device_node *node,
const struct clk_corediv_soc_desc *soc_desc)
{ {
struct clk_init_data init; struct clk_init_data init;
struct clk_corediv *corediv; struct clk_corediv *corediv;
...@@ -178,7 +250,7 @@ static void __init mvebu_corediv_clk_init(struct device_node *node) ...@@ -178,7 +250,7 @@ static void __init mvebu_corediv_clk_init(struct device_node *node)
parent_name = of_clk_get_parent_name(node, 0); parent_name = of_clk_get_parent_name(node, 0);
clk_data.clk_num = ARRAY_SIZE(mvebu_corediv_desc); clk_data.clk_num = soc_desc->ndescs;
/* clks holds the clock array */ /* clks holds the clock array */
clks = kcalloc(clk_data.clk_num, sizeof(struct clk *), clks = kcalloc(clk_data.clk_num, sizeof(struct clk *),
...@@ -199,10 +271,11 @@ static void __init mvebu_corediv_clk_init(struct device_node *node) ...@@ -199,10 +271,11 @@ static void __init mvebu_corediv_clk_init(struct device_node *node)
init.num_parents = 1; init.num_parents = 1;
init.parent_names = &parent_name; init.parent_names = &parent_name;
init.name = clk_name; init.name = clk_name;
init.ops = &corediv_ops; init.ops = &soc_desc->ops;
init.flags = 0; init.flags = 0;
corediv[i].desc = mvebu_corediv_desc[i]; corediv[i].soc_desc = soc_desc;
corediv[i].desc = soc_desc->descs + i;
corediv[i].reg = base; corediv[i].reg = base;
corediv[i].hw.init = &init; corediv[i].hw.init = &init;
...@@ -219,5 +292,24 @@ static void __init mvebu_corediv_clk_init(struct device_node *node) ...@@ -219,5 +292,24 @@ static void __init mvebu_corediv_clk_init(struct device_node *node)
err_unmap: err_unmap:
iounmap(base); iounmap(base);
} }
CLK_OF_DECLARE(mvebu_corediv_clk, "marvell,armada-370-corediv-clock",
mvebu_corediv_clk_init); static void __init armada370_corediv_clk_init(struct device_node *node)
{
return mvebu_corediv_clk_init(node, &armada370_corediv_soc);
}
CLK_OF_DECLARE(armada370_corediv_clk, "marvell,armada-370-corediv-clock",
armada370_corediv_clk_init);
static void __init armada375_corediv_clk_init(struct device_node *node)
{
return mvebu_corediv_clk_init(node, &armada375_corediv_soc);
}
CLK_OF_DECLARE(armada375_corediv_clk, "marvell,armada-375-corediv-clock",
armada375_corediv_clk_init);
static void __init armada380_corediv_clk_init(struct device_node *node)
{
return mvebu_corediv_clk_init(node, &armada380_corediv_soc);
}
CLK_OF_DECLARE(armada380_corediv_clk, "marvell,armada-380-corediv-clock",
armada380_corediv_clk_init);
obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o
obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o
obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#define CPG_DIV6_DIV_MASK 0x3f #define CPG_DIV6_DIV_MASK 0x3f
/** /**
* struct div6_clock - MSTP gating clock * struct div6_clock - CPG 6 bit divider clock
* @hw: handle between common and hardware-specific interfaces * @hw: handle between common and hardware-specific interfaces
* @reg: IO-remapped register * @reg: IO-remapped register
* @div: divisor value (1-64) * @div: divisor value (1-64)
......
...@@ -137,7 +137,7 @@ cpg_mstp_clock_register(const char *name, const char *parent_name, ...@@ -137,7 +137,7 @@ cpg_mstp_clock_register(const char *name, const char *parent_name,
init.name = name; init.name = name;
init.ops = &cpg_mstp_clock_ops; init.ops = &cpg_mstp_clock_ops;
init.flags = CLK_IS_BASIC; init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
init.parent_names = &parent_name; init.parent_names = &parent_name;
init.num_parents = 1; init.num_parents = 1;
......
...@@ -242,22 +242,22 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg, ...@@ -242,22 +242,22 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
parent_name = "main"; parent_name = "main";
mult = config->pll3_mult; mult = config->pll3_mult;
} else if (!strcmp(name, "lb")) { } else if (!strcmp(name, "lb")) {
parent_name = "pll1_div2"; parent_name = "pll1";
div = cpg_mode & BIT(18) ? 36 : 24; div = cpg_mode & BIT(18) ? 36 : 24;
} else if (!strcmp(name, "qspi")) { } else if (!strcmp(name, "qspi")) {
parent_name = "pll1_div2"; parent_name = "pll1_div2";
div = (cpg_mode & (BIT(3) | BIT(2) | BIT(1))) == BIT(2) div = (cpg_mode & (BIT(3) | BIT(2) | BIT(1))) == BIT(2)
? 8 : 10; ? 8 : 10;
} else if (!strcmp(name, "sdh")) { } else if (!strcmp(name, "sdh")) {
parent_name = "pll1_div2"; parent_name = "pll1";
table = cpg_sdh_div_table; table = cpg_sdh_div_table;
shift = 8; shift = 8;
} else if (!strcmp(name, "sd0")) { } else if (!strcmp(name, "sd0")) {
parent_name = "pll1_div2"; parent_name = "pll1";
table = cpg_sd01_div_table; table = cpg_sd01_div_table;
shift = 4; shift = 4;
} else if (!strcmp(name, "sd1")) { } else if (!strcmp(name, "sd1")) {
parent_name = "pll1_div2"; parent_name = "pll1";
table = cpg_sd01_div_table; table = cpg_sd01_div_table;
shift = 0; shift = 0;
} else if (!strcmp(name, "z")) { } else if (!strcmp(name, "z")) {
......
/*
* rz Core CPG Clocks
*
* Copyright (C) 2013 Ideas On Board SPRL
* Copyright (C) 2014 Wolfram Sang, Sang Engineering <wsa@sang-engineering.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*/
#include <linux/clk-provider.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/slab.h>
struct rz_cpg {
struct clk_onecell_data data;
void __iomem *reg;
};
#define CPG_FRQCR 0x10
#define CPG_FRQCR2 0x14
/* -----------------------------------------------------------------------------
* Initialization
*/
static struct clk * __init
rz_cpg_register_clock(struct device_node *np, struct rz_cpg *cpg, const char *name)
{
u32 val;
unsigned mult;
static const unsigned frqcr_tab[4] = { 3, 2, 0, 1 };
if (strcmp(name, "pll") == 0) {
/* FIXME: cpg_mode should be read from GPIO. But no GPIO support yet */
unsigned cpg_mode = 0; /* hardcoded to EXTAL for now */
const char *parent_name = of_clk_get_parent_name(np, cpg_mode);
mult = cpg_mode ? (32 / 4) : 30;
return clk_register_fixed_factor(NULL, name, parent_name, 0, mult, 1);
}
/* If mapping regs failed, skip non-pll clocks. System will boot anyhow */
if (!cpg->reg)
return ERR_PTR(-ENXIO);
/* FIXME:"i" and "g" are variable clocks with non-integer dividers (e.g. 2/3)
* and the constraint that always g <= i. To get the rz platform started,
* let them run at fixed current speed and implement the details later.
*/
if (strcmp(name, "i") == 0)
val = (clk_readl(cpg->reg + CPG_FRQCR) >> 8) & 3;
else if (strcmp(name, "g") == 0)
val = clk_readl(cpg->reg + CPG_FRQCR2) & 3;
else
return ERR_PTR(-EINVAL);
mult = frqcr_tab[val];
return clk_register_fixed_factor(NULL, name, "pll", 0, mult, 3);
}
static void __init rz_cpg_clocks_init(struct device_node *np)
{
struct rz_cpg *cpg;
struct clk **clks;
unsigned i;
int num_clks;
num_clks = of_property_count_strings(np, "clock-output-names");
if (WARN(num_clks <= 0, "can't count CPG clocks\n"))
return;
cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL);
BUG_ON(!cpg || !clks);
cpg->data.clks = clks;
cpg->data.clk_num = num_clks;
cpg->reg = of_iomap(np, 0);
for (i = 0; i < num_clks; ++i) {
const char *name;
struct clk *clk;
of_property_read_string_index(np, "clock-output-names", i, &name);
clk = rz_cpg_register_clock(np, cpg, name);
if (IS_ERR(clk))
pr_err("%s: failed to register %s %s clock (%ld)\n",
__func__, np->name, name, PTR_ERR(clk));
else
cpg->data.clks[i] = clk;
}
of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
}
CLK_OF_DECLARE(rz_cpg_clks, "renesas,rz-cpg-clocks", rz_cpg_clocks_init);
/* /*
* Clock tree for CSR SiRFatlasVI * Clock tree for CSR SiRFatlasVI
* *
* Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. * Copyright (c) 2011 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
* company.
* *
* Licensed under GPLv2 or later. * Licensed under GPLv2 or later.
*/ */
......
/* /*
* common clks module for all SiRF SoCs * common clks module for all SiRF SoCs
* *
* Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. * Copyright (c) 2011 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
* company.
* *
* Licensed under GPLv2 or later. * Licensed under GPLv2 or later.
*/ */
......
/* /*
* Clock tree for CSR SiRFprimaII * Clock tree for CSR SiRFprimaII
* *
* Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. * Copyright (c) 2011 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
* company.
* *
* Licensed under GPLv2 or later. * Licensed under GPLv2 or later.
*/ */
......
obj-y += clk.o obj-y += clk.o
obj-y += clk-gate.o
obj-y += clk-pll.o
obj-y += clk-periph.o
/*
* Copyright 2011-2012 Calxeda, Inc.
* Copyright (C) 2012-2013 Altera Corporation <www.altera.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.
*
* Based from clk-highbank.c
*
*/
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include "clk.h"
#define SOCFPGA_L4_MP_CLK "l4_mp_clk"
#define SOCFPGA_L4_SP_CLK "l4_sp_clk"
#define SOCFPGA_NAND_CLK "nand_clk"
#define SOCFPGA_NAND_X_CLK "nand_x_clk"
#define SOCFPGA_MMC_CLK "sdmmc_clk"
#define SOCFPGA_GPIO_DB_CLK_OFFSET 0xA8
#define div_mask(width) ((1 << (width)) - 1)
#define streq(a, b) (strcmp((a), (b)) == 0)
#define to_socfpga_gate_clk(p) container_of(p, struct socfpga_gate_clk, hw.hw)
/* SDMMC Group for System Manager defines */
#define SYSMGR_SDMMCGRP_CTRL_OFFSET 0x108
#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel) \
((((smplsel) & 0x7) << 3) | (((drvsel) & 0x7) << 0))
static u8 socfpga_clk_get_parent(struct clk_hw *hwclk)
{
u32 l4_src;
u32 perpll_src;
if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK)) {
l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
return l4_src &= 0x1;
}
if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK)) {
l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
return !!(l4_src & 2);
}
perpll_src = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
if (streq(hwclk->init->name, SOCFPGA_MMC_CLK))
return perpll_src &= 0x3;
if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) ||
streq(hwclk->init->name, SOCFPGA_NAND_X_CLK))
return (perpll_src >> 2) & 3;
/* QSPI clock */
return (perpll_src >> 4) & 3;
}
static int socfpga_clk_set_parent(struct clk_hw *hwclk, u8 parent)
{
u32 src_reg;
if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK)) {
src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
src_reg &= ~0x1;
src_reg |= parent;
writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC);
} else if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK)) {
src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
src_reg &= ~0x2;
src_reg |= (parent << 1);
writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC);
} else {
src_reg = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
if (streq(hwclk->init->name, SOCFPGA_MMC_CLK)) {
src_reg &= ~0x3;
src_reg |= parent;
} else if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) ||
streq(hwclk->init->name, SOCFPGA_NAND_X_CLK)) {
src_reg &= ~0xC;
src_reg |= (parent << 2);
} else {/* QSPI clock */
src_reg &= ~0x30;
src_reg |= (parent << 4);
}
writel(src_reg, clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
}
return 0;
}
static unsigned long socfpga_clk_recalc_rate(struct clk_hw *hwclk,
unsigned long parent_rate)
{
struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
u32 div = 1, val;
if (socfpgaclk->fixed_div)
div = socfpgaclk->fixed_div;
else if (socfpgaclk->div_reg) {
val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
val &= div_mask(socfpgaclk->width);
/* Check for GPIO_DB_CLK by its offset */
if ((int) socfpgaclk->div_reg & SOCFPGA_GPIO_DB_CLK_OFFSET)
div = val + 1;
else
div = (1 << val);
}
return parent_rate / div;
}
static int socfpga_clk_prepare(struct clk_hw *hwclk)
{
struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
struct regmap *sys_mgr_base_addr;
int i;
u32 hs_timing;
u32 clk_phase[2];
if (socfpgaclk->clk_phase[0] || socfpgaclk->clk_phase[1]) {
sys_mgr_base_addr = syscon_regmap_lookup_by_compatible("altr,sys-mgr");
if (IS_ERR(sys_mgr_base_addr)) {
pr_err("%s: failed to find altr,sys-mgr regmap!\n", __func__);
return -EINVAL;
}
for (i = 0; i < 2; i++) {
switch (socfpgaclk->clk_phase[i]) {
case 0:
clk_phase[i] = 0;
break;
case 45:
clk_phase[i] = 1;
break;
case 90:
clk_phase[i] = 2;
break;
case 135:
clk_phase[i] = 3;
break;
case 180:
clk_phase[i] = 4;
break;
case 225:
clk_phase[i] = 5;
break;
case 270:
clk_phase[i] = 6;
break;
case 315:
clk_phase[i] = 7;
break;
default:
clk_phase[i] = 0;
break;
}
}
hs_timing = SYSMGR_SDMMC_CTRL_SET(clk_phase[0], clk_phase[1]);
regmap_write(sys_mgr_base_addr, SYSMGR_SDMMCGRP_CTRL_OFFSET,
hs_timing);
}
return 0;
}
static struct clk_ops gateclk_ops = {
.prepare = socfpga_clk_prepare,
.recalc_rate = socfpga_clk_recalc_rate,
.get_parent = socfpga_clk_get_parent,
.set_parent = socfpga_clk_set_parent,
};
static void __init __socfpga_gate_init(struct device_node *node,
const struct clk_ops *ops)
{
u32 clk_gate[2];
u32 div_reg[3];
u32 clk_phase[2];
u32 fixed_div;
struct clk *clk;
struct socfpga_gate_clk *socfpga_clk;
const char *clk_name = node->name;
const char *parent_name[SOCFPGA_MAX_PARENTS];
struct clk_init_data init;
int rc;
int i = 0;
socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
if (WARN_ON(!socfpga_clk))
return;
rc = of_property_read_u32_array(node, "clk-gate", clk_gate, 2);
if (rc)
clk_gate[0] = 0;
if (clk_gate[0]) {
socfpga_clk->hw.reg = clk_mgr_base_addr + clk_gate[0];
socfpga_clk->hw.bit_idx = clk_gate[1];
gateclk_ops.enable = clk_gate_ops.enable;
gateclk_ops.disable = clk_gate_ops.disable;
}
rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
if (rc)
socfpga_clk->fixed_div = 0;
else
socfpga_clk->fixed_div = fixed_div;
rc = of_property_read_u32_array(node, "div-reg", div_reg, 3);
if (!rc) {
socfpga_clk->div_reg = clk_mgr_base_addr + div_reg[0];
socfpga_clk->shift = div_reg[1];
socfpga_clk->width = div_reg[2];
} else {
socfpga_clk->div_reg = 0;
}
rc = of_property_read_u32_array(node, "clk-phase", clk_phase, 2);
if (!rc) {
socfpga_clk->clk_phase[0] = clk_phase[0];
socfpga_clk->clk_phase[1] = clk_phase[1];
}
of_property_read_string(node, "clock-output-names", &clk_name);
init.name = clk_name;
init.ops = ops;
init.flags = 0;
while (i < SOCFPGA_MAX_PARENTS && (parent_name[i] =
of_clk_get_parent_name(node, i)) != NULL)
i++;
init.parent_names = parent_name;
init.num_parents = i;
socfpga_clk->hw.hw.init = &init;
clk = clk_register(NULL, &socfpga_clk->hw.hw);
if (WARN_ON(IS_ERR(clk))) {
kfree(socfpga_clk);
return;
}
rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
if (WARN_ON(rc))
return;
}
void __init socfpga_gate_init(struct device_node *node)
{
__socfpga_gate_init(node, &gateclk_ops);
}
/*
* Copyright 2011-2012 Calxeda, Inc.
* Copyright (C) 2012-2013 Altera Corporation <www.altera.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.
*
* Based from clk-highbank.c
*
*/
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of.h>
#include "clk.h"
#define to_socfpga_periph_clk(p) container_of(p, struct socfpga_periph_clk, hw.hw)
static unsigned long clk_periclk_recalc_rate(struct clk_hw *hwclk,
unsigned long parent_rate)
{
struct socfpga_periph_clk *socfpgaclk = to_socfpga_periph_clk(hwclk);
u32 div;
if (socfpgaclk->fixed_div)
div = socfpgaclk->fixed_div;
else
div = ((readl(socfpgaclk->hw.reg) & 0x1ff) + 1);
return parent_rate / div;
}
static const struct clk_ops periclk_ops = {
.recalc_rate = clk_periclk_recalc_rate,
};
static __init void __socfpga_periph_init(struct device_node *node,
const struct clk_ops *ops)
{
u32 reg;
struct clk *clk;
struct socfpga_periph_clk *periph_clk;
const char *clk_name = node->name;
const char *parent_name;
struct clk_init_data init;
int rc;
u32 fixed_div;
of_property_read_u32(node, "reg", &reg);
periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
if (WARN_ON(!periph_clk))
return;
periph_clk->hw.reg = clk_mgr_base_addr + reg;
rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
if (rc)
periph_clk->fixed_div = 0;
else
periph_clk->fixed_div = fixed_div;
of_property_read_string(node, "clock-output-names", &clk_name);
init.name = clk_name;
init.ops = ops;
init.flags = 0;
parent_name = of_clk_get_parent_name(node, 0);
init.parent_names = &parent_name;
init.num_parents = 1;
periph_clk->hw.hw.init = &init;
clk = clk_register(NULL, &periph_clk->hw.hw);
if (WARN_ON(IS_ERR(clk))) {
kfree(periph_clk);
return;
}
rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
}
void __init socfpga_periph_init(struct device_node *node)
{
__socfpga_periph_init(node, &periclk_ops);
}
/*
* Copyright 2011-2012 Calxeda, Inc.
* Copyright (C) 2012-2013 Altera Corporation <www.altera.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.
*
* Based from clk-highbank.c
*
*/
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of.h>
#include "clk.h"
/* Clock bypass bits */
#define MAINPLL_BYPASS (1<<0)
#define SDRAMPLL_BYPASS (1<<1)
#define SDRAMPLL_SRC_BYPASS (1<<2)
#define PERPLL_BYPASS (1<<3)
#define PERPLL_SRC_BYPASS (1<<4)
#define SOCFPGA_PLL_BG_PWRDWN 0
#define SOCFPGA_PLL_EXT_ENA 1
#define SOCFPGA_PLL_PWR_DOWN 2
#define SOCFPGA_PLL_DIVF_MASK 0x0000FFF8
#define SOCFPGA_PLL_DIVF_SHIFT 3
#define SOCFPGA_PLL_DIVQ_MASK 0x003F0000
#define SOCFPGA_PLL_DIVQ_SHIFT 16
#define CLK_MGR_PLL_CLK_SRC_SHIFT 22
#define CLK_MGR_PLL_CLK_SRC_MASK 0x3
#define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw)
static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk,
unsigned long parent_rate)
{
struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
unsigned long divf, divq, reg;
unsigned long long vco_freq;
unsigned long bypass;
reg = readl(socfpgaclk->hw.reg);
bypass = readl(clk_mgr_base_addr + CLKMGR_BYPASS);
if (bypass & MAINPLL_BYPASS)
return parent_rate;
divf = (reg & SOCFPGA_PLL_DIVF_MASK) >> SOCFPGA_PLL_DIVF_SHIFT;
divq = (reg & SOCFPGA_PLL_DIVQ_MASK) >> SOCFPGA_PLL_DIVQ_SHIFT;
vco_freq = (unsigned long long)parent_rate * (divf + 1);
do_div(vco_freq, (1 + divq));
return (unsigned long)vco_freq;
}
static u8 clk_pll_get_parent(struct clk_hw *hwclk)
{
u32 pll_src;
struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
pll_src = readl(socfpgaclk->hw.reg);
return (pll_src >> CLK_MGR_PLL_CLK_SRC_SHIFT) &
CLK_MGR_PLL_CLK_SRC_MASK;
}
static struct clk_ops clk_pll_ops = {
.recalc_rate = clk_pll_recalc_rate,
.get_parent = clk_pll_get_parent,
};
static __init struct clk *__socfpga_pll_init(struct device_node *node,
const struct clk_ops *ops)
{
u32 reg;
struct clk *clk;
struct socfpga_pll *pll_clk;
const char *clk_name = node->name;
const char *parent_name[SOCFPGA_MAX_PARENTS];
struct clk_init_data init;
int rc;
int i = 0;
of_property_read_u32(node, "reg", &reg);
pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
if (WARN_ON(!pll_clk))
return NULL;
pll_clk->hw.reg = clk_mgr_base_addr + reg;
of_property_read_string(node, "clock-output-names", &clk_name);
init.name = clk_name;
init.ops = ops;
init.flags = 0;
while (i < SOCFPGA_MAX_PARENTS && (parent_name[i] =
of_clk_get_parent_name(node, i)) != NULL)
i++;
init.num_parents = i;
init.parent_names = parent_name;
pll_clk->hw.hw.init = &init;
pll_clk->hw.bit_idx = SOCFPGA_PLL_EXT_ENA;
clk_pll_ops.enable = clk_gate_ops.enable;
clk_pll_ops.disable = clk_gate_ops.disable;
clk = clk_register(NULL, &pll_clk->hw.hw);
if (WARN_ON(IS_ERR(clk))) {
kfree(pll_clk);
return NULL;
}
rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
return clk;
}
void __init socfpga_pll_init(struct device_node *node)
{
__socfpga_pll_init(node, &clk_pll_ops);
}
...@@ -22,325 +22,23 @@ ...@@ -22,325 +22,23 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h>
/* Clock Manager offsets */ #include "clk.h"
#define CLKMGR_CTRL 0x0
#define CLKMGR_BYPASS 0x4
#define CLKMGR_L4SRC 0x70
#define CLKMGR_PERPLL_SRC 0xAC
/* Clock bypass bits */ void __iomem *clk_mgr_base_addr;
#define MAINPLL_BYPASS (1<<0)
#define SDRAMPLL_BYPASS (1<<1)
#define SDRAMPLL_SRC_BYPASS (1<<2)
#define PERPLL_BYPASS (1<<3)
#define PERPLL_SRC_BYPASS (1<<4)
#define SOCFPGA_PLL_BG_PWRDWN 0 static const struct of_device_id socfpga_child_clocks[] __initconst = {
#define SOCFPGA_PLL_EXT_ENA 1 { .compatible = "altr,socfpga-pll-clock", socfpga_pll_init, },
#define SOCFPGA_PLL_PWR_DOWN 2 { .compatible = "altr,socfpga-perip-clk", socfpga_periph_init, },
#define SOCFPGA_PLL_DIVF_MASK 0x0000FFF8 { .compatible = "altr,socfpga-gate-clk", socfpga_gate_init, },
#define SOCFPGA_PLL_DIVF_SHIFT 3 {},
#define SOCFPGA_PLL_DIVQ_MASK 0x003F0000
#define SOCFPGA_PLL_DIVQ_SHIFT 16
#define SOCFGPA_MAX_PARENTS 3
#define SOCFPGA_L4_MP_CLK "l4_mp_clk"
#define SOCFPGA_L4_SP_CLK "l4_sp_clk"
#define SOCFPGA_NAND_CLK "nand_clk"
#define SOCFPGA_NAND_X_CLK "nand_x_clk"
#define SOCFPGA_MMC_CLK "sdmmc_clk"
#define SOCFPGA_DB_CLK "gpio_db_clk"
#define div_mask(width) ((1 << (width)) - 1)
#define streq(a, b) (strcmp((a), (b)) == 0)
extern void __iomem *clk_mgr_base_addr;
struct socfpga_clk {
struct clk_gate hw;
char *parent_name;
char *clk_name;
u32 fixed_div;
void __iomem *div_reg;
u32 width; /* only valid if div_reg != 0 */
u32 shift; /* only valid if div_reg != 0 */
};
#define to_socfpga_clk(p) container_of(p, struct socfpga_clk, hw.hw)
static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk,
unsigned long parent_rate)
{
struct socfpga_clk *socfpgaclk = to_socfpga_clk(hwclk);
unsigned long divf, divq, vco_freq, reg;
unsigned long bypass;
reg = readl(socfpgaclk->hw.reg);
bypass = readl(clk_mgr_base_addr + CLKMGR_BYPASS);
if (bypass & MAINPLL_BYPASS)
return parent_rate;
divf = (reg & SOCFPGA_PLL_DIVF_MASK) >> SOCFPGA_PLL_DIVF_SHIFT;
divq = (reg & SOCFPGA_PLL_DIVQ_MASK) >> SOCFPGA_PLL_DIVQ_SHIFT;
vco_freq = parent_rate * (divf + 1);
return vco_freq / (1 + divq);
}
static struct clk_ops clk_pll_ops = {
.recalc_rate = clk_pll_recalc_rate,
};
static unsigned long clk_periclk_recalc_rate(struct clk_hw *hwclk,
unsigned long parent_rate)
{
struct socfpga_clk *socfpgaclk = to_socfpga_clk(hwclk);
u32 div;
if (socfpgaclk->fixed_div)
div = socfpgaclk->fixed_div;
else
div = ((readl(socfpgaclk->hw.reg) & 0x1ff) + 1);
return parent_rate / div;
}
static const struct clk_ops periclk_ops = {
.recalc_rate = clk_periclk_recalc_rate,
};
static __init struct clk *socfpga_clk_init(struct device_node *node,
const struct clk_ops *ops)
{
u32 reg;
struct clk *clk;
struct socfpga_clk *socfpga_clk;
const char *clk_name = node->name;
const char *parent_name;
struct clk_init_data init;
int rc;
u32 fixed_div;
of_property_read_u32(node, "reg", &reg);
socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
if (WARN_ON(!socfpga_clk))
return NULL;
socfpga_clk->hw.reg = clk_mgr_base_addr + reg;
rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
if (rc)
socfpga_clk->fixed_div = 0;
else
socfpga_clk->fixed_div = fixed_div;
of_property_read_string(node, "clock-output-names", &clk_name);
init.name = clk_name;
init.ops = ops;
init.flags = 0;
parent_name = of_clk_get_parent_name(node, 0);
init.parent_names = &parent_name;
init.num_parents = 1;
socfpga_clk->hw.hw.init = &init;
if (streq(clk_name, "main_pll") ||
streq(clk_name, "periph_pll") ||
streq(clk_name, "sdram_pll")) {
socfpga_clk->hw.bit_idx = SOCFPGA_PLL_EXT_ENA;
clk_pll_ops.enable = clk_gate_ops.enable;
clk_pll_ops.disable = clk_gate_ops.disable;
}
clk = clk_register(NULL, &socfpga_clk->hw.hw);
if (WARN_ON(IS_ERR(clk))) {
kfree(socfpga_clk);
return NULL;
}
rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
return clk;
}
static u8 socfpga_clk_get_parent(struct clk_hw *hwclk)
{
u32 l4_src;
u32 perpll_src;
if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK)) {
l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
return l4_src &= 0x1;
}
if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK)) {
l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
return !!(l4_src & 2);
}
perpll_src = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
if (streq(hwclk->init->name, SOCFPGA_MMC_CLK))
return perpll_src &= 0x3;
if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) ||
streq(hwclk->init->name, SOCFPGA_NAND_X_CLK))
return (perpll_src >> 2) & 3;
/* QSPI clock */
return (perpll_src >> 4) & 3;
}
static int socfpga_clk_set_parent(struct clk_hw *hwclk, u8 parent)
{
u32 src_reg;
if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK)) {
src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
src_reg &= ~0x1;
src_reg |= parent;
writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC);
} else if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK)) {
src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
src_reg &= ~0x2;
src_reg |= (parent << 1);
writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC);
} else {
src_reg = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
if (streq(hwclk->init->name, SOCFPGA_MMC_CLK)) {
src_reg &= ~0x3;
src_reg |= parent;
} else if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) ||
streq(hwclk->init->name, SOCFPGA_NAND_X_CLK)) {
src_reg &= ~0xC;
src_reg |= (parent << 2);
} else {/* QSPI clock */
src_reg &= ~0x30;
src_reg |= (parent << 4);
}
writel(src_reg, clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
}
return 0;
}
static unsigned long socfpga_clk_recalc_rate(struct clk_hw *hwclk,
unsigned long parent_rate)
{
struct socfpga_clk *socfpgaclk = to_socfpga_clk(hwclk);
u32 div = 1, val;
if (socfpgaclk->fixed_div)
div = socfpgaclk->fixed_div;
else if (socfpgaclk->div_reg) {
val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
val &= div_mask(socfpgaclk->width);
if (streq(hwclk->init->name, SOCFPGA_DB_CLK))
div = val + 1;
else
div = (1 << val);
}
return parent_rate / div;
}
static struct clk_ops gateclk_ops = {
.recalc_rate = socfpga_clk_recalc_rate,
.get_parent = socfpga_clk_get_parent,
.set_parent = socfpga_clk_set_parent,
}; };
static void __init socfpga_gate_clk_init(struct device_node *node, static void __init socfpga_clkmgr_init(struct device_node *node)
const struct clk_ops *ops)
{
u32 clk_gate[2];
u32 div_reg[3];
u32 fixed_div;
struct clk *clk;
struct socfpga_clk *socfpga_clk;
const char *clk_name = node->name;
const char *parent_name[SOCFGPA_MAX_PARENTS];
struct clk_init_data init;
int rc;
int i = 0;
socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
if (WARN_ON(!socfpga_clk))
return;
rc = of_property_read_u32_array(node, "clk-gate", clk_gate, 2);
if (rc)
clk_gate[0] = 0;
if (clk_gate[0]) {
socfpga_clk->hw.reg = clk_mgr_base_addr + clk_gate[0];
socfpga_clk->hw.bit_idx = clk_gate[1];
gateclk_ops.enable = clk_gate_ops.enable;
gateclk_ops.disable = clk_gate_ops.disable;
}
rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
if (rc)
socfpga_clk->fixed_div = 0;
else
socfpga_clk->fixed_div = fixed_div;
rc = of_property_read_u32_array(node, "div-reg", div_reg, 3);
if (!rc) {
socfpga_clk->div_reg = clk_mgr_base_addr + div_reg[0];
socfpga_clk->shift = div_reg[1];
socfpga_clk->width = div_reg[2];
} else {
socfpga_clk->div_reg = NULL;
}
of_property_read_string(node, "clock-output-names", &clk_name);
init.name = clk_name;
init.ops = ops;
init.flags = 0;
while (i < SOCFGPA_MAX_PARENTS && (parent_name[i] =
of_clk_get_parent_name(node, i)) != NULL)
i++;
init.parent_names = parent_name;
init.num_parents = i;
socfpga_clk->hw.hw.init = &init;
clk = clk_register(NULL, &socfpga_clk->hw.hw);
if (WARN_ON(IS_ERR(clk))) {
kfree(socfpga_clk);
return;
}
rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
if (WARN_ON(rc))
return;
}
static void __init socfpga_pll_init(struct device_node *node)
{ {
socfpga_clk_init(node, &clk_pll_ops); clk_mgr_base_addr = of_iomap(node, 0);
of_clk_init(socfpga_child_clocks);
} }
CLK_OF_DECLARE(socfpga_pll, "altr,socfpga-pll-clock", socfpga_pll_init); CLK_OF_DECLARE(socfpga_mgr, "altr,clk-mgr", socfpga_clkmgr_init);
static void __init socfpga_periph_init(struct device_node *node)
{
socfpga_clk_init(node, &periclk_ops);
}
CLK_OF_DECLARE(socfpga_periph, "altr,socfpga-perip-clk", socfpga_periph_init);
static void __init socfpga_gate_init(struct device_node *node)
{
socfpga_gate_clk_init(node, &gateclk_ops);
}
CLK_OF_DECLARE(socfpga_gate, "altr,socfpga-gate-clk", socfpga_gate_init);
void __init socfpga_init_clocks(void)
{
struct clk *clk;
int ret;
clk = clk_register_fixed_factor(NULL, "smp_twd", "mpuclk", 0, 1, 4);
ret = clk_register_clkdev(clk, NULL, "smp_twd");
if (ret)
pr_err("smp_twd alias not registered\n");
}
/*
* Copyright (c) 2013, Steffen Trumtrar <s.trumtrar@pengutronix.de>
*
* based on drivers/clk/tegra/clk.h
*
* 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.
*
*/
#ifndef __SOCFPGA_CLK_H
#define __SOCFPGA_CLK_H
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
/* Clock Manager offsets */
#define CLKMGR_CTRL 0x0
#define CLKMGR_BYPASS 0x4
#define CLKMGR_L4SRC 0x70
#define CLKMGR_PERPLL_SRC 0xAC
#define SOCFPGA_MAX_PARENTS 3
extern void __iomem *clk_mgr_base_addr;
void __init socfpga_pll_init(struct device_node *node);
void __init socfpga_periph_init(struct device_node *node);
void __init socfpga_gate_init(struct device_node *node);
struct socfpga_pll {
struct clk_gate hw;
};
struct socfpga_gate_clk {
struct clk_gate hw;
char *parent_name;
u32 fixed_div;
void __iomem *div_reg;
u32 width; /* only valid if div_reg != 0 */
u32 shift; /* only valid if div_reg != 0 */
u32 clk_phase[2];
};
struct socfpga_periph_clk {
struct clk_gate hw;
char *parent_name;
u32 fixed_div;
};
#endif /* SOCFPGA_CLK_H */
obj-y += clkgen-mux.o clkgen-pll.o clkgen-fsyn.o
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/************************************************************************
File : Clock H/w specific Information
Author: Pankaj Dev <pankaj.dev@st.com>
Copyright (C) 2014 STMicroelectronics
************************************************************************/
#ifndef __CLKGEN_INFO_H
#define __CLKGEN_INFO_H
struct clkgen_field {
unsigned int offset;
unsigned int mask;
unsigned int shift;
};
static inline unsigned long clkgen_read(void __iomem *base,
struct clkgen_field *field)
{
return (readl(base + field->offset) >> field->shift) & field->mask;
}
static inline void clkgen_write(void __iomem *base, struct clkgen_field *field,
unsigned long val)
{
writel((readl(base + field->offset) &
~(field->mask << field->shift)) | (val << field->shift),
base + field->offset);
return;
}
#define CLKGEN_FIELD(_offset, _mask, _shift) { \
.offset = _offset, \
.mask = _mask, \
.shift = _shift, \
}
#define CLKGEN_READ(pll, field) clkgen_read(pll->regs_base, \
&pll->data->field)
#define CLKGEN_WRITE(pll, field, val) clkgen_write(pll->regs_base, \
&pll->data->field, val)
#endif /*__CLKGEN_INFO_H*/
This diff is collapsed.
...@@ -130,7 +130,7 @@ static const struct clk_ops tegra_clk_periph_nodiv_ops = { ...@@ -130,7 +130,7 @@ static const struct clk_ops tegra_clk_periph_nodiv_ops = {
.disable = clk_periph_disable, .disable = clk_periph_disable,
}; };
const struct clk_ops tegra_clk_periph_no_gate_ops = { static const struct clk_ops tegra_clk_periph_no_gate_ops = {
.get_parent = clk_periph_get_parent, .get_parent = clk_periph_get_parent,
.set_parent = clk_periph_set_parent, .set_parent = clk_periph_set_parent,
.recalc_rate = clk_periph_recalc_rate, .recalc_rate = clk_periph_recalc_rate,
......
...@@ -34,7 +34,6 @@ static struct ti_dt_clk am33xx_clks[] = { ...@@ -34,7 +34,6 @@ static struct ti_dt_clk am33xx_clks[] = {
DT_CLK(NULL, "dpll_core_m5_ck", "dpll_core_m5_ck"), DT_CLK(NULL, "dpll_core_m5_ck", "dpll_core_m5_ck"),
DT_CLK(NULL, "dpll_core_m6_ck", "dpll_core_m6_ck"), DT_CLK(NULL, "dpll_core_m6_ck", "dpll_core_m6_ck"),
DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"), DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"),
DT_CLK("cpu0", NULL, "dpll_mpu_ck"),
DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"), DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"),
DT_CLK(NULL, "dpll_ddr_ck", "dpll_ddr_ck"), DT_CLK(NULL, "dpll_ddr_ck", "dpll_ddr_ck"),
DT_CLK(NULL, "dpll_ddr_m2_ck", "dpll_ddr_m2_ck"), DT_CLK(NULL, "dpll_ddr_m2_ck", "dpll_ddr_m2_ck"),
......
...@@ -112,7 +112,7 @@ static unsigned long ti_clk_divider_recalc_rate(struct clk_hw *hw, ...@@ -112,7 +112,7 @@ static unsigned long ti_clk_divider_recalc_rate(struct clk_hw *hw,
return parent_rate; return parent_rate;
} }
return parent_rate / div; return DIV_ROUND_UP(parent_rate, div);
} }
/* /*
...@@ -182,7 +182,7 @@ static int ti_clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, ...@@ -182,7 +182,7 @@ static int ti_clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
} }
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
MULT_ROUND_UP(rate, i)); MULT_ROUND_UP(rate, i));
now = parent_rate / i; now = DIV_ROUND_UP(parent_rate, i);
if (now <= rate && now > best) { if (now <= rate && now > best) {
bestdiv = i; bestdiv = i;
best = now; best = now;
...@@ -205,7 +205,7 @@ static long ti_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -205,7 +205,7 @@ static long ti_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
int div; int div;
div = ti_clk_divider_bestdiv(hw, rate, prate); div = ti_clk_divider_bestdiv(hw, rate, prate);
return *prate / div; return DIV_ROUND_UP(*prate, div);
} }
static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
...@@ -216,7 +216,7 @@ static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -216,7 +216,7 @@ static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long flags = 0; unsigned long flags = 0;
u32 val; u32 val;
div = parent_rate / rate; div = DIV_ROUND_UP(parent_rate, rate);
value = _get_val(divider, div); value = _get_val(divider, div);
if (value > div_mask(divider)) if (value > div_mask(divider))
......
...@@ -29,7 +29,8 @@ static struct clk *prcc_kclk[(PRCC_NUM_PERIPH_CLUSTERS + 1) * PRCC_PERIPHS_PER_C ...@@ -29,7 +29,8 @@ static struct clk *prcc_kclk[(PRCC_NUM_PERIPH_CLUSTERS + 1) * PRCC_PERIPHS_PER_C
#define PRCC_KCLK_STORE(clk, base, bit) \ #define PRCC_KCLK_STORE(clk, base, bit) \
prcc_kclk[(base * PRCC_PERIPHS_PER_CLUSTER) + bit] = clk prcc_kclk[(base * PRCC_PERIPHS_PER_CLUSTER) + bit] = clk
struct clk *ux500_twocell_get(struct of_phandle_args *clkspec, void *data) static struct clk *ux500_twocell_get(struct of_phandle_args *clkspec,
void *data)
{ {
struct clk **clk_data = data; struct clk **clk_data = data;
unsigned int base, bit; unsigned int base, bit;
......
...@@ -149,7 +149,7 @@ static void __init zynq_clk_register_fclk(enum zynq_clk fclk, ...@@ -149,7 +149,7 @@ static void __init zynq_clk_register_fclk(enum zynq_clk fclk,
clks[fclk] = clk_register_gate(NULL, clk_name, clks[fclk] = clk_register_gate(NULL, clk_name,
div1_name, CLK_SET_RATE_PARENT, fclk_gate_reg, div1_name, CLK_SET_RATE_PARENT, fclk_gate_reg,
0, CLK_GATE_SET_TO_DISABLE, fclk_gate_lock); 0, CLK_GATE_SET_TO_DISABLE, fclk_gate_lock);
enable_reg = readl(fclk_gate_reg) & 1; enable_reg = clk_readl(fclk_gate_reg) & 1;
if (enable && !enable_reg) { if (enable && !enable_reg) {
if (clk_prepare_enable(clks[fclk])) if (clk_prepare_enable(clks[fclk]))
pr_warn("%s: FCLK%u enable failed\n", __func__, pr_warn("%s: FCLK%u enable failed\n", __func__,
...@@ -278,7 +278,7 @@ static void __init zynq_clk_setup(struct device_node *np) ...@@ -278,7 +278,7 @@ static void __init zynq_clk_setup(struct device_node *np)
SLCR_IOPLL_CTRL, 4, 1, 0, &iopll_lock); SLCR_IOPLL_CTRL, 4, 1, 0, &iopll_lock);
/* CPU clocks */ /* CPU clocks */
tmp = readl(SLCR_621_TRUE) & 1; tmp = clk_readl(SLCR_621_TRUE) & 1;
clk = clk_register_mux(NULL, "cpu_mux", cpu_parents, 4, clk = clk_register_mux(NULL, "cpu_mux", cpu_parents, 4,
CLK_SET_RATE_NO_REPARENT, SLCR_ARM_CLK_CTRL, 4, 2, 0, CLK_SET_RATE_NO_REPARENT, SLCR_ARM_CLK_CTRL, 4, 2, 0,
&armclk_lock); &armclk_lock);
......
...@@ -90,7 +90,7 @@ static unsigned long zynq_pll_recalc_rate(struct clk_hw *hw, ...@@ -90,7 +90,7 @@ static unsigned long zynq_pll_recalc_rate(struct clk_hw *hw,
* makes probably sense to redundantly save fbdiv in the struct * makes probably sense to redundantly save fbdiv in the struct
* zynq_pll to save the IO access. * zynq_pll to save the IO access.
*/ */
fbdiv = (readl(clk->pll_ctrl) & PLLCTRL_FBDIV_MASK) >> fbdiv = (clk_readl(clk->pll_ctrl) & PLLCTRL_FBDIV_MASK) >>
PLLCTRL_FBDIV_SHIFT; PLLCTRL_FBDIV_SHIFT;
return parent_rate * fbdiv; return parent_rate * fbdiv;
...@@ -112,7 +112,7 @@ static int zynq_pll_is_enabled(struct clk_hw *hw) ...@@ -112,7 +112,7 @@ static int zynq_pll_is_enabled(struct clk_hw *hw)
spin_lock_irqsave(clk->lock, flags); spin_lock_irqsave(clk->lock, flags);
reg = readl(clk->pll_ctrl); reg = clk_readl(clk->pll_ctrl);
spin_unlock_irqrestore(clk->lock, flags); spin_unlock_irqrestore(clk->lock, flags);
...@@ -138,10 +138,10 @@ static int zynq_pll_enable(struct clk_hw *hw) ...@@ -138,10 +138,10 @@ static int zynq_pll_enable(struct clk_hw *hw)
/* Power up PLL and wait for lock */ /* Power up PLL and wait for lock */
spin_lock_irqsave(clk->lock, flags); spin_lock_irqsave(clk->lock, flags);
reg = readl(clk->pll_ctrl); reg = clk_readl(clk->pll_ctrl);
reg &= ~(PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK); reg &= ~(PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK);
writel(reg, clk->pll_ctrl); clk_writel(reg, clk->pll_ctrl);
while (!(readl(clk->pll_status) & (1 << clk->lockbit))) while (!(clk_readl(clk->pll_status) & (1 << clk->lockbit)))
; ;
spin_unlock_irqrestore(clk->lock, flags); spin_unlock_irqrestore(clk->lock, flags);
...@@ -168,9 +168,9 @@ static void zynq_pll_disable(struct clk_hw *hw) ...@@ -168,9 +168,9 @@ static void zynq_pll_disable(struct clk_hw *hw)
/* shut down PLL */ /* shut down PLL */
spin_lock_irqsave(clk->lock, flags); spin_lock_irqsave(clk->lock, flags);
reg = readl(clk->pll_ctrl); reg = clk_readl(clk->pll_ctrl);
reg |= PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK; reg |= PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK;
writel(reg, clk->pll_ctrl); clk_writel(reg, clk->pll_ctrl);
spin_unlock_irqrestore(clk->lock, flags); spin_unlock_irqrestore(clk->lock, flags);
} }
...@@ -225,9 +225,9 @@ struct clk *clk_register_zynq_pll(const char *name, const char *parent, ...@@ -225,9 +225,9 @@ struct clk *clk_register_zynq_pll(const char *name, const char *parent,
spin_lock_irqsave(pll->lock, flags); spin_lock_irqsave(pll->lock, flags);
reg = readl(pll->pll_ctrl); reg = clk_readl(pll->pll_ctrl);
reg &= ~PLLCTRL_BPQUAL_MASK; reg &= ~PLLCTRL_BPQUAL_MASK;
writel(reg, pll->pll_ctrl); clk_writel(reg, pll->pll_ctrl);
spin_unlock_irqrestore(pll->lock, flags); spin_unlock_irqrestore(pll->lock, flags);
......
...@@ -147,6 +147,11 @@ ...@@ -147,6 +147,11 @@
#define HI3620_MMC_CLK3 217 #define HI3620_MMC_CLK3 217
#define HI3620_MCU_CLK 218 #define HI3620_MCU_CLK 218
#define HI3620_SD_CIUCLK 0
#define HI3620_MMC_CIUCLK1 1
#define HI3620_MMC_CIUCLK2 2
#define HI3620_MMC_CIUCLK3 3
#define HI3620_NR_CLKS 219 #define HI3620_NR_CLKS 219
#endif /* __DTS_HI3620_CLOCK_H */ #endif /* __DTS_HI3620_CLOCK_H */
/*
* Copyright (c) 2013-2014 Hisilicon Limited.
* Copyright (c) 2013-2014 Linaro Limited.
*
* Author: Haojian Zhuang <haojian.zhuang@linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef __DTS_HIP04_CLOCK_H
#define __DTS_HIP04_CLOCK_H
#define HIP04_NONE_CLOCK 0
/* fixed rate & fixed factor clocks */
#define HIP04_OSC50M 1
#define HIP04_CLK_50M 2
#define HIP04_CLK_168M 3
#define HIP04_NR_CLKS 64
#endif /* __DTS_HIP04_CLOCK_H */
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */ #define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */
struct clk_hw; struct clk_hw;
struct dentry;
/** /**
* struct clk_ops - Callback operations for hardware clocks; these are to * struct clk_ops - Callback operations for hardware clocks; these are to
...@@ -127,6 +128,12 @@ struct clk_hw; ...@@ -127,6 +128,12 @@ struct clk_hw;
* separately via calls to .set_parent and .set_rate. * separately via calls to .set_parent and .set_rate.
* Returns 0 on success, -EERROR otherwise. * Returns 0 on success, -EERROR otherwise.
* *
* @debug_init: Set up type-specific debugfs entries for this clock. This
* is called once, after the debugfs directory entry for this
* clock has been created. The dentry pointer representing that
* directory is provided as an argument. Called with
* prepare_lock held. Returns 0 on success, -EERROR otherwise.
*
* *
* The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
* implementations to split any work between atomic (enable) and sleepable * implementations to split any work between atomic (enable) and sleepable
...@@ -165,6 +172,7 @@ struct clk_ops { ...@@ -165,6 +172,7 @@ struct clk_ops {
unsigned long (*recalc_accuracy)(struct clk_hw *hw, unsigned long (*recalc_accuracy)(struct clk_hw *hw,
unsigned long parent_accuracy); unsigned long parent_accuracy);
void (*init)(struct clk_hw *hw); void (*init)(struct clk_hw *hw);
int (*debug_init)(struct clk_hw *hw, struct dentry *dentry);
}; };
/** /**
......
...@@ -78,8 +78,22 @@ struct clk_notifier_data { ...@@ -78,8 +78,22 @@ struct clk_notifier_data {
unsigned long new_rate; unsigned long new_rate;
}; };
/**
* clk_notifier_register: register a clock rate-change notifier callback
* @clk: clock whose rate we are interested in
* @nb: notifier block with callback function pointer
*
* ProTip: debugging across notifier chains can be frustrating. Make sure that
* your notifier callback function prints a nice big warning in case of
* failure.
*/
int clk_notifier_register(struct clk *clk, struct notifier_block *nb); int clk_notifier_register(struct clk *clk, struct notifier_block *nb);
/**
* clk_notifier_unregister: unregister a clock rate-change notifier callback
* @clk: clock whose rate we are no longer interested in
* @nb: notifier block which will be unregistered
*/
int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb); int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment