Merge branch 'clk-fixes' into clk-next
diff --git a/Documentation/clk.txt b/Documentation/clk.txt
index c9c399a..1fee72f 100644
--- a/Documentation/clk.txt
+++ b/Documentation/clk.txt
@@ -68,21 +68,27 @@
int (*is_enabled)(struct clk_hw *hw);
unsigned long (*recalc_rate)(struct clk_hw *hw,
unsigned long parent_rate);
- long (*round_rate)(struct clk_hw *hw, unsigned long,
- unsigned long *);
+ long (*round_rate)(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long *parent_rate);
long (*determine_rate)(struct clk_hw *hw,
unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_clk);
int (*set_parent)(struct clk_hw *hw, u8 index);
u8 (*get_parent)(struct clk_hw *hw);
- int (*set_rate)(struct clk_hw *hw, unsigned long);
+ int (*set_rate)(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate);
int (*set_rate_and_parent)(struct clk_hw *hw,
unsigned long rate,
- unsigned long parent_rate, u8 index);
+ unsigned long parent_rate,
+ u8 index);
unsigned long (*recalc_accuracy)(struct clk_hw *hw,
- unsigned long parent_accuracy);
+ unsigned long parent_accuracy);
void (*init)(struct clk_hw *hw);
+ int (*debug_init)(struct clk_hw *hw,
+ struct dentry *dentry);
};
Part 3 - hardware clk implementations
diff --git a/Documentation/devicetree/bindings/clock/bcm-kona-clock.txt b/Documentation/devicetree/bindings/clock/bcm-kona-clock.txt
index 56d1f49..5286e26 100644
--- a/Documentation/devicetree/bindings/clock/bcm-kona-clock.txt
+++ b/Documentation/devicetree/bindings/clock/bcm-kona-clock.txt
@@ -10,12 +10,12 @@
Required properties:
- compatible
- Shall have one of the following values:
- - "brcm,bcm11351-root-ccu"
- - "brcm,bcm11351-aon-ccu"
- - "brcm,bcm11351-hub-ccu"
- - "brcm,bcm11351-master-ccu"
- - "brcm,bcm11351-slave-ccu"
+ Shall have a value of the form "brcm,<model>-<which>-ccu",
+ where <model> is a Broadcom SoC model number and <which> is
+ the name of a defined CCU. For example:
+ "brcm,bcm11351-root-ccu"
+ The compatible strings used for each supported SoC family
+ are defined below.
- reg
Shall define the base and range of the address space
containing clock control registers
@@ -26,12 +26,48 @@
Shall be an ordered list of strings defining the names of
the clocks provided by the CCU.
+Device tree example:
-BCM281XX family SoCs use Kona CCUs. The following table defines
-the set of CCUs and clock specifiers for BCM281XX clocks. When
-a clock consumer references a clocks, its symbolic specifier
-(rather than its numeric index value) should be used. These
-specifiers are defined in "include/dt-bindings/clock/bcm281xx.h".
+ slave_ccu: slave_ccu {
+ compatible = "brcm,bcm11351-slave-ccu";
+ reg = <0x3e011000 0x0f00>;
+ #clock-cells = <1>;
+ clock-output-names = "uartb",
+ "uartb2",
+ "uartb3",
+ "uartb4";
+ };
+
+ ref_crystal_clk: ref_crystal {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <26000000>;
+ };
+
+ uart@3e002000 {
+ compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart";
+ status = "disabled";
+ reg = <0x3e002000 0x1000>;
+ clocks = <&slave_ccu BCM281XX_SLAVE_CCU_UARTB3>;
+ interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ };
+
+BCM281XX family
+---------------
+CCU compatible string values for SoCs in the BCM281XX family are:
+ "brcm,bcm11351-root-ccu"
+ "brcm,bcm11351-aon-ccu"
+ "brcm,bcm11351-hub-ccu"
+ "brcm,bcm11351-master-ccu"
+ "brcm,bcm11351-slave-ccu"
+
+The following table defines the set of CCUs and clock specifiers for
+BCM281XX family clocks. When a clock consumer references a clocks,
+its symbolic specifier (rather than its numeric index value) should
+be used. These specifiers are defined in:
+ "include/dt-bindings/clock/bcm281xx.h"
CCU Clock Type Index Specifier
--- ----- ---- ----- ---------
@@ -64,30 +100,40 @@
slave pwm peri 9 BCM281XX_SLAVE_CCU_PWM
-Device tree example:
+BCM21664 family
+---------------
+CCU compatible string values for SoCs in the BCM21664 family are:
+ "brcm,bcm21664-root-ccu"
+ "brcm,bcm21664-aon-ccu"
+ "brcm,bcm21664-master-ccu"
+ "brcm,bcm21664-slave-ccu"
- slave_ccu: slave_ccu {
- compatible = "brcm,bcm11351-slave-ccu";
- reg = <0x3e011000 0x0f00>;
- #clock-cells = <1>;
- clock-output-names = "uartb",
- "uartb2",
- "uartb3",
- "uartb4";
- };
+The following table defines the set of CCUs and clock specifiers for
+BCM21664 family clocks. When a clock consumer references a clocks,
+its symbolic specifier (rather than its numeric index value) should
+be used. These specifiers are defined in:
+ "include/dt-bindings/clock/bcm21664.h"
- ref_crystal_clk: ref_crystal {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <26000000>;
- };
+ CCU Clock Type Index Specifier
+ --- ----- ---- ----- ---------
+ root frac_1m peri 0 BCM21664_ROOT_CCU_FRAC_1M
- uart@3e002000 {
- compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart";
- status = "disabled";
- reg = <0x3e002000 0x1000>;
- clocks = <&slave_ccu BCM281XX_SLAVE_CCU_UARTB3>;
- interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
- reg-shift = <2>;
- reg-io-width = <4>;
- };
+ aon hub_timer peri 0 BCM21664_AON_CCU_HUB_TIMER
+
+ master sdio1 peri 0 BCM21664_MASTER_CCU_SDIO1
+ master sdio2 peri 1 BCM21664_MASTER_CCU_SDIO2
+ master sdio3 peri 2 BCM21664_MASTER_CCU_SDIO3
+ master sdio4 peri 3 BCM21664_MASTER_CCU_SDIO4
+ master sdio1_sleep peri 4 BCM21664_MASTER_CCU_SDIO1_SLEEP
+ master sdio2_sleep peri 5 BCM21664_MASTER_CCU_SDIO2_SLEEP
+ master sdio3_sleep peri 6 BCM21664_MASTER_CCU_SDIO3_SLEEP
+ master sdio4_sleep peri 7 BCM21664_MASTER_CCU_SDIO4_SLEEP
+
+ slave uartb peri 0 BCM21664_SLAVE_CCU_UARTB
+ slave uartb2 peri 1 BCM21664_SLAVE_CCU_UARTB2
+ slave uartb3 peri 2 BCM21664_SLAVE_CCU_UARTB3
+ slave uartb4 peri 3 BCM21664_SLAVE_CCU_UARTB4
+ slave bsc1 peri 4 BCM21664_SLAVE_CCU_BSC1
+ slave bsc2 peri 5 BCM21664_SLAVE_CCU_BSC2
+ slave bsc3 peri 6 BCM21664_SLAVE_CCU_BSC3
+ slave bsc4 peri 7 BCM21664_SLAVE_CCU_BSC4
diff --git a/Documentation/devicetree/bindings/clock/clock-bindings.txt b/Documentation/devicetree/bindings/clock/clock-bindings.txt
index 700e7aa..f157878 100644
--- a/Documentation/devicetree/bindings/clock/clock-bindings.txt
+++ b/Documentation/devicetree/bindings/clock/clock-bindings.txt
@@ -44,10 +44,9 @@
clocks by index. The names should reflect the clock output signal
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.
+clock-indices: If the identifying number for the clocks in the node
+ is not linear from zero, then this allows the mapping of
+ identifiers into the clock-output-names array.
For example, if we have two clocks <&oscillator 1> and <&oscillator 3>:
@@ -58,7 +57,7 @@
clock-output-names = "clka", "clkb";
}
- This ensures we do not have any empty nodes in clock-output-names
+ This ensures we do not have any empty strings in clock-output-names
==Clock consumers==
diff --git a/Documentation/devicetree/bindings/clock/fixed-clock.txt b/Documentation/devicetree/bindings/clock/fixed-clock.txt
index 48ea0ad..0641a663 100644
--- a/Documentation/devicetree/bindings/clock/fixed-clock.txt
+++ b/Documentation/devicetree/bindings/clock/fixed-clock.txt
@@ -12,7 +12,6 @@
Optional properties:
- clock-accuracy : accuracy of clock in ppb (parts per billion).
Should be a single cell.
-- gpios : From common gpio binding; gpio connection to clock enable pin.
- clock-output-names : From common clock binding.
Example:
diff --git a/Documentation/devicetree/bindings/clock/hix5hd2-clock.txt b/Documentation/devicetree/bindings/clock/hix5hd2-clock.txt
new file mode 100644
index 0000000..7894a64
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/hix5hd2-clock.txt
@@ -0,0 +1,31 @@
+* Hisilicon Hix5hd2 Clock Controller
+
+The hix5hd2 clock controller generates and supplies clock to various
+controllers within the hix5hd2 SoC.
+
+Required Properties:
+
+- compatible: should be "hisilicon,hix5hd2-clock"
+- reg: Address and length of the register set
+- #clock-cells: Should be <1>
+
+Each clock is assigned an identifier and client nodes use this identifier
+to specify the clock which they consume.
+
+All these identifier could be found in <dt-bindings/clock/hix5hd2-clock.h>.
+
+Examples:
+ clock: clock@f8a22000 {
+ compatible = "hisilicon,hix5hd2-clock";
+ reg = <0xf8a22000 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ uart0: uart@f8b00000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0xf8b00000 0x1000>;
+ interrupts = <0 49 4>;
+ clocks = <&clock HIX5HD2_FIXED_83M>;
+ clock-names = "apb_pclk";
+ status = "disabled";
+ };
diff --git a/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
index 307a503..dc5ea5b 100644
--- a/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
+++ b/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
@@ -29,6 +29,11 @@
2 = l2clk (L2 Cache clock derived from CPU0 clock)
3 = ddrclk (DDR controller clock derived from CPU0 clock)
+The following is a list of provided IDs and clock names on Orion5x:
+ 0 = tclk (Internal Bus clock)
+ 1 = cpuclk (CPU0 clock)
+ 2 = ddrclk (DDR controller clock derived from CPU0 clock)
+
Required properties:
- compatible : shall be one of the following:
"marvell,armada-370-core-clock" - For Armada 370 SoC core clocks
@@ -38,6 +43,9 @@
"marvell,dove-core-clock" - for Dove SoC core clocks
"marvell,kirkwood-core-clock" - for Kirkwood SoC (except mv88f6180)
"marvell,mv88f6180-core-clock" - for Kirkwood MV88f6180 SoC
+ "marvell,mv88f5182-core-clock" - for Orion MV88F5182 SoC
+ "marvell,mv88f5281-core-clock" - for Orion MV88F5281 SoC
+ "marvell,mv88f6183-core-clock" - for Orion MV88F6183 SoC
- reg : shall be the register address of the Sample-At-Reset (SAR) register
- #clock-cells : from common clock binding; shall be set to 1
diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
index 767401f..7b7104e 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
@@ -4,6 +4,7 @@
Required properties :
- compatible : shall contain only one of the following:
+ "qcom,gcc-apq8064"
"qcom,gcc-msm8660"
"qcom,gcc-msm8960"
"qcom,gcc-msm8974"
diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
index 02a25d9..30df825 100644
--- a/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
+++ b/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
@@ -10,6 +10,7 @@
Required Properties:
- compatible: Must be one of the following
+ - "renesas,r8a7779-mstp-clocks" for R8A7779 (R-Car H1) MSTP gate clocks
- "renesas,r8a7790-mstp-clocks" for R8A7790 (R-Car H2) MSTP gate clocks
- "renesas,r8a7791-mstp-clocks" for R8A7791 (R-Car M2) MSTP gate clocks
- "renesas,cpg-mstp-clock" for generic MSTP gate clocks
diff --git a/Documentation/devicetree/bindings/clock/renesas,r8a7779-cpg-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,r8a7779-cpg-clocks.txt
new file mode 100644
index 0000000..ed3c8cb
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/renesas,r8a7779-cpg-clocks.txt
@@ -0,0 +1,27 @@
+* Renesas R8A7779 Clock Pulse Generator (CPG)
+
+The CPG generates core clocks for the R8A7779. It includes one PLL and
+several fixed ratio dividers
+
+Required Properties:
+
+ - compatible: Must be "renesas,r8a7779-cpg-clocks"
+ - reg: Base address and length of the memory resource used by the CPG
+
+ - clocks: Reference to the parent clock
+ - #clock-cells: Must be 1
+ - clock-output-names: The names of the clocks. Supported clocks are "plla",
+ "z", "zs", "s", "s1", "p", "b", "out".
+
+
+Example
+-------
+
+ cpg_clocks: cpg_clocks@ffc80000 {
+ compatible = "renesas,r8a7779-cpg-clocks";
+ reg = <0 0xffc80000 0 0x30>;
+ clocks = <&extal_clk>;
+ #clock-cells = <1>;
+ clock-output-names = "plla", "z", "zs", "s", "s1", "p",
+ "b", "out";
+ };
diff --git a/arch/arm/boot/dts/bcm21664.dtsi b/arch/arm/boot/dts/bcm21664.dtsi
index 08a44d4..8b36682 100644
--- a/arch/arm/boot/dts/bcm21664.dtsi
+++ b/arch/arm/boot/dts/bcm21664.dtsi
@@ -14,6 +14,8 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
+#include "dt-bindings/clock/bcm21664.h"
+
#include "skeleton.dtsi"
/ {
@@ -43,7 +45,7 @@
compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart";
status = "disabled";
reg = <0x3e000000 0x118>;
- clocks = <&uartb_clk>;
+ clocks = <&slave_ccu BCM21664_SLAVE_CCU_UARTB>;
interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
@@ -53,7 +55,7 @@
compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart";
status = "disabled";
reg = <0x3e001000 0x118>;
- clocks = <&uartb2_clk>;
+ clocks = <&slave_ccu BCM21664_SLAVE_CCU_UARTB2>;
interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
@@ -63,7 +65,7 @@
compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart";
status = "disabled";
reg = <0x3e002000 0x118>;
- clocks = <&uartb3_clk>;
+ clocks = <&slave_ccu BCM21664_SLAVE_CCU_UARTB3>;
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
@@ -85,7 +87,7 @@
compatible = "brcm,kona-timer";
reg = <0x35006000 0x1c>;
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&hub_timer_clk>;
+ clocks = <&aon_ccu BCM21664_AON_CCU_HUB_TIMER>;
};
gpio: gpio@35003000 {
@@ -106,7 +108,7 @@
compatible = "brcm,kona-sdhci";
reg = <0x3f180000 0x801c>;
interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&sdio1_clk>;
+ clocks = <&master_ccu BCM21664_MASTER_CCU_SDIO1>;
status = "disabled";
};
@@ -114,7 +116,7 @@
compatible = "brcm,kona-sdhci";
reg = <0x3f190000 0x801c>;
interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&sdio2_clk>;
+ clocks = <&master_ccu BCM21664_MASTER_CCU_SDIO2>;
status = "disabled";
};
@@ -122,7 +124,7 @@
compatible = "brcm,kona-sdhci";
reg = <0x3f1a0000 0x801c>;
interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&sdio3_clk>;
+ clocks = <&master_ccu BCM21664_MASTER_CCU_SDIO3>;
status = "disabled";
};
@@ -130,7 +132,7 @@
compatible = "brcm,kona-sdhci";
reg = <0x3f1b0000 0x801c>;
interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&sdio4_clk>;
+ clocks = <&master_ccu BCM21664_MASTER_CCU_SDIO4>;
status = "disabled";
};
@@ -140,7 +142,7 @@
interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
- clocks = <&bsc1_clk>;
+ clocks = <&slave_ccu BCM21664_SLAVE_CCU_BSC1>;
status = "disabled";
};
@@ -150,7 +152,7 @@
interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
- clocks = <&bsc2_clk>;
+ clocks = <&slave_ccu BCM21664_SLAVE_CCU_BSC2>;
status = "disabled";
};
@@ -160,7 +162,7 @@
interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
- clocks = <&bsc3_clk>;
+ clocks = <&slave_ccu BCM21664_SLAVE_CCU_BSC3>;
status = "disabled";
};
@@ -170,105 +172,149 @@
interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
- clocks = <&bsc4_clk>;
+ clocks = <&slave_ccu BCM21664_SLAVE_CCU_BSC4>;
status = "disabled";
};
clocks {
- bsc1_clk: bsc1 {
- compatible = "fixed-clock";
- clock-frequency = <13000000>;
- #clock-cells = <0>;
- };
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
- bsc2_clk: bsc2 {
- compatible = "fixed-clock";
- clock-frequency = <13000000>;
- #clock-cells = <0>;
- };
+ /*
+ * Fixed clocks are defined before CCUs whose
+ * clocks may depend on them.
+ */
- bsc3_clk: bsc3 {
- compatible = "fixed-clock";
- clock-frequency = <13000000>;
+ ref_32k_clk: ref_32k {
#clock-cells = <0>;
- };
-
- bsc4_clk: bsc4 {
- compatible = "fixed-clock";
- clock-frequency = <13000000>;
- #clock-cells = <0>;
- };
-
- pmu_bsc_clk: pmu_bsc {
- compatible = "fixed-clock";
- clock-frequency = <13000000>;
- #clock-cells = <0>;
- };
-
- hub_timer_clk: hub_timer {
compatible = "fixed-clock";
clock-frequency = <32768>;
- #clock-cells = <0>;
};
- pwm_clk: pwm {
+ bbl_32k_clk: bbl_32k {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ };
+
+ ref_13m_clk: ref_13m {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <13000000>;
+ };
+
+ var_13m_clk: var_13m {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <13000000>;
+ };
+
+ dft_19_5m_clk: dft_19_5m {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <19500000>;
+ };
+
+ ref_crystal_clk: ref_crystal {
+ #clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <26000000>;
- #clock-cells = <0>;
};
- sdio1_clk: sdio1 {
- compatible = "fixed-clock";
- clock-frequency = <48000000>;
+ ref_52m_clk: ref_52m {
#clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <52000000>;
};
- sdio2_clk: sdio2 {
- compatible = "fixed-clock";
- clock-frequency = <48000000>;
+ var_52m_clk: var_52m {
#clock-cells = <0>;
- };
-
- sdio3_clk: sdio3 {
compatible = "fixed-clock";
- clock-frequency = <48000000>;
- #clock-cells = <0>;
- };
-
- sdio4_clk: sdio4 {
- compatible = "fixed-clock";
- clock-frequency = <48000000>;
- #clock-cells = <0>;
- };
-
- tmon_1m_clk: tmon_1m {
- compatible = "fixed-clock";
- clock-frequency = <1000000>;
- #clock-cells = <0>;
- };
-
- uartb_clk: uartb {
- compatible = "fixed-clock";
- clock-frequency = <13000000>;
- #clock-cells = <0>;
- };
-
- uartb2_clk: uartb2 {
- compatible = "fixed-clock";
- clock-frequency = <13000000>;
- #clock-cells = <0>;
- };
-
- uartb3_clk: uartb3 {
- compatible = "fixed-clock";
- clock-frequency = <13000000>;
- #clock-cells = <0>;
+ clock-frequency = <52000000>;
};
usb_otg_ahb_clk: usb_otg_ahb {
+ #clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <52000000>;
+ };
+
+ ref_96m_clk: ref_96m {
#clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <96000000>;
+ };
+
+ var_96m_clk: var_96m {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <96000000>;
+ };
+
+ ref_104m_clk: ref_104m {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <104000000>;
+ };
+
+ var_104m_clk: var_104m {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <104000000>;
+ };
+
+ ref_156m_clk: ref_156m {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <156000000>;
+ };
+
+ var_156m_clk: var_156m {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <156000000>;
+ };
+
+ root_ccu: root_ccu {
+ compatible = BCM21664_DT_ROOT_CCU_COMPAT;
+ reg = <0x35001000 0x0f00>;
+ #clock-cells = <1>;
+ clock-output-names = "frac_1m";
+ };
+
+ aon_ccu: aon_ccu {
+ compatible = BCM21664_DT_AON_CCU_COMPAT;
+ reg = <0x35002000 0x0f00>;
+ #clock-cells = <1>;
+ clock-output-names = "hub_timer";
+ };
+
+ master_ccu: master_ccu {
+ compatible = BCM21664_DT_MASTER_CCU_COMPAT;
+ reg = <0x3f001000 0x0f00>;
+ #clock-cells = <1>;
+ clock-output-names = "sdio1",
+ "sdio2",
+ "sdio3",
+ "sdio4",
+ "sdio1_sleep",
+ "sdio2_sleep",
+ "sdio3_sleep",
+ "sdio4_sleep";
+ };
+
+ slave_ccu: slave_ccu {
+ compatible = BCM21664_DT_SLAVE_CCU_COMPAT;
+ reg = <0x3e011000 0x0f00>;
+ #clock-cells = <1>;
+ clock-output-names = "uartb",
+ "uartb2",
+ "uartb3",
+ "bsc1",
+ "bsc2",
+ "bsc3",
+ "bsc4";
};
};
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 5f8a287..3e6e577 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -33,6 +33,7 @@
obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/
obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
obj-$(CONFIG_ARCH_HIP04) += hisilicon/
+obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/
obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/
diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig
index a7262fb..75506e5 100644
--- a/drivers/clk/bcm/Kconfig
+++ b/drivers/clk/bcm/Kconfig
@@ -6,4 +6,4 @@
help
Enable common clock framework support for Broadcom SoCs
using "Kona" style clock control units, including those
- in the BCM281xx family.
+ in the BCM281xx and BCM21664 families.
diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile
index cf93359..6297d05 100644
--- a/drivers/clk/bcm/Makefile
+++ b/drivers/clk/bcm/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o
+obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
diff --git a/drivers/clk/bcm/clk-bcm21664.c b/drivers/clk/bcm/clk-bcm21664.c
new file mode 100644
index 0000000..eeae4ca
--- /dev/null
+++ b/drivers/clk/bcm/clk-bcm21664.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2014 Broadcom Corporation
+ * Copyright 2014 Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "clk-kona.h"
+#include "dt-bindings/clock/bcm21664.h"
+
+#define BCM21664_CCU_COMMON(_name, _capname) \
+ KONA_CCU_COMMON(BCM21664, _name, _capname)
+
+/* Root CCU */
+
+static struct peri_clk_data frac_1m_data = {
+ .gate = HW_SW_GATE(0x214, 16, 0, 1),
+ .clocks = CLOCKS("ref_crystal"),
+};
+
+static struct ccu_data root_ccu_data = {
+ BCM21664_CCU_COMMON(root, ROOT),
+ /* no policy control */
+ .kona_clks = {
+ [BCM21664_ROOT_CCU_FRAC_1M] =
+ KONA_CLK(root, frac_1m, peri),
+ [BCM21664_ROOT_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
+};
+
+/* AON CCU */
+
+static struct peri_clk_data hub_timer_data = {
+ .gate = HW_SW_GATE(0x0414, 16, 0, 1),
+ .hyst = HYST(0x0414, 8, 9),
+ .clocks = CLOCKS("bbl_32k",
+ "frac_1m",
+ "dft_19_5m"),
+ .sel = SELECTOR(0x0a10, 0, 2),
+ .trig = TRIGGER(0x0a40, 4),
+};
+
+static struct ccu_data aon_ccu_data = {
+ BCM21664_CCU_COMMON(aon, AON),
+ .policy = {
+ .enable = CCU_LVM_EN(0x0034, 0),
+ .control = CCU_POLICY_CTL(0x000c, 0, 1, 2),
+ },
+ .kona_clks = {
+ [BCM21664_AON_CCU_HUB_TIMER] =
+ KONA_CLK(aon, hub_timer, peri),
+ [BCM21664_AON_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
+};
+
+/* Master CCU */
+
+static struct peri_clk_data sdio1_data = {
+ .gate = HW_SW_GATE(0x0358, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_52m",
+ "ref_52m",
+ "var_96m",
+ "ref_96m"),
+ .sel = SELECTOR(0x0a28, 0, 3),
+ .div = DIVIDER(0x0a28, 4, 14),
+ .trig = TRIGGER(0x0afc, 9),
+};
+
+static struct peri_clk_data sdio2_data = {
+ .gate = HW_SW_GATE(0x035c, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_52m",
+ "ref_52m",
+ "var_96m",
+ "ref_96m"),
+ .sel = SELECTOR(0x0a2c, 0, 3),
+ .div = DIVIDER(0x0a2c, 4, 14),
+ .trig = TRIGGER(0x0afc, 10),
+};
+
+static struct peri_clk_data sdio3_data = {
+ .gate = HW_SW_GATE(0x0364, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_52m",
+ "ref_52m",
+ "var_96m",
+ "ref_96m"),
+ .sel = SELECTOR(0x0a34, 0, 3),
+ .div = DIVIDER(0x0a34, 4, 14),
+ .trig = TRIGGER(0x0afc, 12),
+};
+
+static struct peri_clk_data sdio4_data = {
+ .gate = HW_SW_GATE(0x0360, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_52m",
+ "ref_52m",
+ "var_96m",
+ "ref_96m"),
+ .sel = SELECTOR(0x0a30, 0, 3),
+ .div = DIVIDER(0x0a30, 4, 14),
+ .trig = TRIGGER(0x0afc, 11),
+};
+
+static struct peri_clk_data sdio1_sleep_data = {
+ .clocks = CLOCKS("ref_32k"), /* Verify */
+ .gate = HW_SW_GATE(0x0358, 18, 2, 3),
+};
+
+static struct peri_clk_data sdio2_sleep_data = {
+ .clocks = CLOCKS("ref_32k"), /* Verify */
+ .gate = HW_SW_GATE(0x035c, 18, 2, 3),
+};
+
+static struct peri_clk_data sdio3_sleep_data = {
+ .clocks = CLOCKS("ref_32k"), /* Verify */
+ .gate = HW_SW_GATE(0x0364, 18, 2, 3),
+};
+
+static struct peri_clk_data sdio4_sleep_data = {
+ .clocks = CLOCKS("ref_32k"), /* Verify */
+ .gate = HW_SW_GATE(0x0360, 18, 2, 3),
+};
+
+static struct ccu_data master_ccu_data = {
+ BCM21664_CCU_COMMON(master, MASTER),
+ .policy = {
+ .enable = CCU_LVM_EN(0x0034, 0),
+ .control = CCU_POLICY_CTL(0x000c, 0, 1, 2),
+ },
+ .kona_clks = {
+ [BCM21664_MASTER_CCU_SDIO1] =
+ KONA_CLK(master, sdio1, peri),
+ [BCM21664_MASTER_CCU_SDIO2] =
+ KONA_CLK(master, sdio2, peri),
+ [BCM21664_MASTER_CCU_SDIO3] =
+ KONA_CLK(master, sdio3, peri),
+ [BCM21664_MASTER_CCU_SDIO4] =
+ KONA_CLK(master, sdio4, peri),
+ [BCM21664_MASTER_CCU_SDIO1_SLEEP] =
+ KONA_CLK(master, sdio1_sleep, peri),
+ [BCM21664_MASTER_CCU_SDIO2_SLEEP] =
+ KONA_CLK(master, sdio2_sleep, peri),
+ [BCM21664_MASTER_CCU_SDIO3_SLEEP] =
+ KONA_CLK(master, sdio3_sleep, peri),
+ [BCM21664_MASTER_CCU_SDIO4_SLEEP] =
+ KONA_CLK(master, sdio4_sleep, peri),
+ [BCM21664_MASTER_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
+};
+
+/* Slave CCU */
+
+static struct peri_clk_data uartb_data = {
+ .gate = HW_SW_GATE(0x0400, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_156m",
+ "ref_156m"),
+ .sel = SELECTOR(0x0a10, 0, 2),
+ .div = FRAC_DIVIDER(0x0a10, 4, 12, 8),
+ .trig = TRIGGER(0x0afc, 2),
+};
+
+static struct peri_clk_data uartb2_data = {
+ .gate = HW_SW_GATE(0x0404, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_156m",
+ "ref_156m"),
+ .sel = SELECTOR(0x0a14, 0, 2),
+ .div = FRAC_DIVIDER(0x0a14, 4, 12, 8),
+ .trig = TRIGGER(0x0afc, 3),
+};
+
+static struct peri_clk_data uartb3_data = {
+ .gate = HW_SW_GATE(0x0408, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_156m",
+ "ref_156m"),
+ .sel = SELECTOR(0x0a18, 0, 2),
+ .div = FRAC_DIVIDER(0x0a18, 4, 12, 8),
+ .trig = TRIGGER(0x0afc, 4),
+};
+
+static struct peri_clk_data bsc1_data = {
+ .gate = HW_SW_GATE(0x0458, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_104m",
+ "ref_104m",
+ "var_13m",
+ "ref_13m"),
+ .sel = SELECTOR(0x0a64, 0, 3),
+ .trig = TRIGGER(0x0afc, 23),
+};
+
+static struct peri_clk_data bsc2_data = {
+ .gate = HW_SW_GATE(0x045c, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_104m",
+ "ref_104m",
+ "var_13m",
+ "ref_13m"),
+ .sel = SELECTOR(0x0a68, 0, 3),
+ .trig = TRIGGER(0x0afc, 24),
+};
+
+static struct peri_clk_data bsc3_data = {
+ .gate = HW_SW_GATE(0x0470, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_104m",
+ "ref_104m",
+ "var_13m",
+ "ref_13m"),
+ .sel = SELECTOR(0x0a7c, 0, 3),
+ .trig = TRIGGER(0x0afc, 18),
+};
+
+static struct peri_clk_data bsc4_data = {
+ .gate = HW_SW_GATE(0x0474, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_104m",
+ "ref_104m",
+ "var_13m",
+ "ref_13m"),
+ .sel = SELECTOR(0x0a80, 0, 3),
+ .trig = TRIGGER(0x0afc, 19),
+};
+
+static struct ccu_data slave_ccu_data = {
+ BCM21664_CCU_COMMON(slave, SLAVE),
+ .policy = {
+ .enable = CCU_LVM_EN(0x0034, 0),
+ .control = CCU_POLICY_CTL(0x000c, 0, 1, 2),
+ },
+ .kona_clks = {
+ [BCM21664_SLAVE_CCU_UARTB] =
+ KONA_CLK(slave, uartb, peri),
+ [BCM21664_SLAVE_CCU_UARTB2] =
+ KONA_CLK(slave, uartb2, peri),
+ [BCM21664_SLAVE_CCU_UARTB3] =
+ KONA_CLK(slave, uartb3, peri),
+ [BCM21664_SLAVE_CCU_BSC1] =
+ KONA_CLK(slave, bsc1, peri),
+ [BCM21664_SLAVE_CCU_BSC2] =
+ KONA_CLK(slave, bsc2, peri),
+ [BCM21664_SLAVE_CCU_BSC3] =
+ KONA_CLK(slave, bsc3, peri),
+ [BCM21664_SLAVE_CCU_BSC4] =
+ KONA_CLK(slave, bsc4, peri),
+ [BCM21664_SLAVE_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
+};
+
+/* Device tree match table callback functions */
+
+static void __init kona_dt_root_ccu_setup(struct device_node *node)
+{
+ kona_dt_ccu_setup(&root_ccu_data, node);
+}
+
+static void __init kona_dt_aon_ccu_setup(struct device_node *node)
+{
+ kona_dt_ccu_setup(&aon_ccu_data, node);
+}
+
+static void __init kona_dt_master_ccu_setup(struct device_node *node)
+{
+ kona_dt_ccu_setup(&master_ccu_data, node);
+}
+
+static void __init kona_dt_slave_ccu_setup(struct device_node *node)
+{
+ kona_dt_ccu_setup(&slave_ccu_data, node);
+}
+
+CLK_OF_DECLARE(bcm21664_root_ccu, BCM21664_DT_ROOT_CCU_COMPAT,
+ kona_dt_root_ccu_setup);
+CLK_OF_DECLARE(bcm21664_aon_ccu, BCM21664_DT_AON_CCU_COMPAT,
+ kona_dt_aon_ccu_setup);
+CLK_OF_DECLARE(bcm21664_master_ccu, BCM21664_DT_MASTER_CCU_COMPAT,
+ kona_dt_master_ccu_setup);
+CLK_OF_DECLARE(bcm21664_slave_ccu, BCM21664_DT_SLAVE_CCU_COMPAT,
+ kona_dt_slave_ccu_setup);
diff --git a/drivers/clk/bcm/clk-bcm281xx.c b/drivers/clk/bcm/clk-bcm281xx.c
index 3c66de6..502a487 100644
--- a/drivers/clk/bcm/clk-bcm281xx.c
+++ b/drivers/clk/bcm/clk-bcm281xx.c
@@ -15,14 +15,10 @@
#include "clk-kona.h"
#include "dt-bindings/clock/bcm281xx.h"
-/* bcm11351 CCU device tree "compatible" strings */
-#define BCM11351_DT_ROOT_CCU_COMPAT "brcm,bcm11351-root-ccu"
-#define BCM11351_DT_AON_CCU_COMPAT "brcm,bcm11351-aon-ccu"
-#define BCM11351_DT_HUB_CCU_COMPAT "brcm,bcm11351-hub-ccu"
-#define BCM11351_DT_MASTER_CCU_COMPAT "brcm,bcm11351-master-ccu"
-#define BCM11351_DT_SLAVE_CCU_COMPAT "brcm,bcm11351-slave-ccu"
+#define BCM281XX_CCU_COMMON(_name, _ucase_name) \
+ KONA_CCU_COMMON(BCM281XX, _name, _ucase_name)
-/* Root CCU clocks */
+/* Root CCU */
static struct peri_clk_data frac_1m_data = {
.gate = HW_SW_GATE(0x214, 16, 0, 1),
@@ -31,7 +27,16 @@
.clocks = CLOCKS("ref_crystal"),
};
-/* AON CCU clocks */
+static struct ccu_data root_ccu_data = {
+ BCM281XX_CCU_COMMON(root, ROOT),
+ .kona_clks = {
+ [BCM281XX_ROOT_CCU_FRAC_1M] =
+ KONA_CLK(root, frac_1m, peri),
+ [BCM281XX_ROOT_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
+};
+
+/* AON CCU */
static struct peri_clk_data hub_timer_data = {
.gate = HW_SW_GATE(0x0414, 16, 0, 1),
@@ -60,7 +65,20 @@
.trig = TRIGGER(0x0a40, 2),
};
-/* Hub CCU clocks */
+static struct ccu_data aon_ccu_data = {
+ BCM281XX_CCU_COMMON(aon, AON),
+ .kona_clks = {
+ [BCM281XX_AON_CCU_HUB_TIMER] =
+ KONA_CLK(aon, hub_timer, peri),
+ [BCM281XX_AON_CCU_PMU_BSC] =
+ KONA_CLK(aon, pmu_bsc, peri),
+ [BCM281XX_AON_CCU_PMU_BSC_VAR] =
+ KONA_CLK(aon, pmu_bsc_var, peri),
+ [BCM281XX_AON_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
+};
+
+/* Hub CCU */
static struct peri_clk_data tmon_1m_data = {
.gate = HW_SW_GATE(0x04a4, 18, 2, 3),
@@ -70,7 +88,16 @@
.trig = TRIGGER(0x0e84, 1),
};
-/* Master CCU clocks */
+static struct ccu_data hub_ccu_data = {
+ BCM281XX_CCU_COMMON(hub, HUB),
+ .kona_clks = {
+ [BCM281XX_HUB_CCU_TMON_1M] =
+ KONA_CLK(hub, tmon_1m, peri),
+ [BCM281XX_HUB_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
+};
+
+/* Master CCU */
static struct peri_clk_data sdio1_data = {
.gate = HW_SW_GATE(0x0358, 18, 2, 3),
@@ -153,7 +180,28 @@
.trig = TRIGGER(0x0afc, 5),
};
-/* Slave CCU clocks */
+static struct ccu_data master_ccu_data = {
+ BCM281XX_CCU_COMMON(master, MASTER),
+ .kona_clks = {
+ [BCM281XX_MASTER_CCU_SDIO1] =
+ KONA_CLK(master, sdio1, peri),
+ [BCM281XX_MASTER_CCU_SDIO2] =
+ KONA_CLK(master, sdio2, peri),
+ [BCM281XX_MASTER_CCU_SDIO3] =
+ KONA_CLK(master, sdio3, peri),
+ [BCM281XX_MASTER_CCU_SDIO4] =
+ KONA_CLK(master, sdio4, peri),
+ [BCM281XX_MASTER_CCU_USB_IC] =
+ KONA_CLK(master, usb_ic, peri),
+ [BCM281XX_MASTER_CCU_HSIC2_48M] =
+ KONA_CLK(master, hsic2_48m, peri),
+ [BCM281XX_MASTER_CCU_HSIC2_12M] =
+ KONA_CLK(master, hsic2_12m, peri),
+ [BCM281XX_MASTER_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
+};
+
+/* Slave CCU */
static struct peri_clk_data uartb_data = {
.gate = HW_SW_GATE(0x0400, 18, 2, 3),
@@ -261,156 +309,67 @@
.trig = TRIGGER(0x0afc, 15),
};
-/*
- * CCU setup routines
- *
- * These are called from kona_dt_ccu_setup() to initialize the array
- * of clocks provided by the CCU. Once allocated, the entries in
- * the array are initialized by calling kona_clk_setup() with the
- * initialization data for each clock. They return 0 if successful
- * or an error code otherwise.
- */
-static int __init bcm281xx_root_ccu_clks_setup(struct ccu_data *ccu)
-{
- struct clk **clks;
- size_t count = BCM281XX_ROOT_CCU_CLOCK_COUNT;
-
- clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
- if (!clks) {
- pr_err("%s: failed to allocate root clocks\n", __func__);
- return -ENOMEM;
- }
- ccu->data.clks = clks;
- ccu->data.clk_num = count;
-
- PERI_CLK_SETUP(clks, ccu, BCM281XX_ROOT_CCU_FRAC_1M, frac_1m);
-
- return 0;
-}
-
-static int __init bcm281xx_aon_ccu_clks_setup(struct ccu_data *ccu)
-{
- struct clk **clks;
- size_t count = BCM281XX_AON_CCU_CLOCK_COUNT;
-
- clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
- if (!clks) {
- pr_err("%s: failed to allocate aon clocks\n", __func__);
- return -ENOMEM;
- }
- ccu->data.clks = clks;
- ccu->data.clk_num = count;
-
- PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_HUB_TIMER, hub_timer);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_PMU_BSC, pmu_bsc);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_PMU_BSC_VAR, pmu_bsc_var);
-
- return 0;
-}
-
-static int __init bcm281xx_hub_ccu_clks_setup(struct ccu_data *ccu)
-{
- struct clk **clks;
- size_t count = BCM281XX_HUB_CCU_CLOCK_COUNT;
-
- clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
- if (!clks) {
- pr_err("%s: failed to allocate hub clocks\n", __func__);
- return -ENOMEM;
- }
- ccu->data.clks = clks;
- ccu->data.clk_num = count;
-
- PERI_CLK_SETUP(clks, ccu, BCM281XX_HUB_CCU_TMON_1M, tmon_1m);
-
- return 0;
-}
-
-static int __init bcm281xx_master_ccu_clks_setup(struct ccu_data *ccu)
-{
- struct clk **clks;
- size_t count = BCM281XX_MASTER_CCU_CLOCK_COUNT;
-
- clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
- if (!clks) {
- pr_err("%s: failed to allocate master clocks\n", __func__);
- return -ENOMEM;
- }
- ccu->data.clks = clks;
- ccu->data.clk_num = count;
-
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO1, sdio1);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO2, sdio2);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO3, sdio3);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO4, sdio4);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_USB_IC, usb_ic);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_HSIC2_48M, hsic2_48m);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_HSIC2_12M, hsic2_12m);
-
- return 0;
-}
-
-static int __init bcm281xx_slave_ccu_clks_setup(struct ccu_data *ccu)
-{
- struct clk **clks;
- size_t count = BCM281XX_SLAVE_CCU_CLOCK_COUNT;
-
- clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
- if (!clks) {
- pr_err("%s: failed to allocate slave clocks\n", __func__);
- return -ENOMEM;
- }
- ccu->data.clks = clks;
- ccu->data.clk_num = count;
-
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB, uartb);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB2, uartb2);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB3, uartb3);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB4, uartb4);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_SSP0, ssp0);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_SSP2, ssp2);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC1, bsc1);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC2, bsc2);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC3, bsc3);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_PWM, pwm);
-
- return 0;
-}
+static struct ccu_data slave_ccu_data = {
+ BCM281XX_CCU_COMMON(slave, SLAVE),
+ .kona_clks = {
+ [BCM281XX_SLAVE_CCU_UARTB] =
+ KONA_CLK(slave, uartb, peri),
+ [BCM281XX_SLAVE_CCU_UARTB2] =
+ KONA_CLK(slave, uartb2, peri),
+ [BCM281XX_SLAVE_CCU_UARTB3] =
+ KONA_CLK(slave, uartb3, peri),
+ [BCM281XX_SLAVE_CCU_UARTB4] =
+ KONA_CLK(slave, uartb4, peri),
+ [BCM281XX_SLAVE_CCU_SSP0] =
+ KONA_CLK(slave, ssp0, peri),
+ [BCM281XX_SLAVE_CCU_SSP2] =
+ KONA_CLK(slave, ssp2, peri),
+ [BCM281XX_SLAVE_CCU_BSC1] =
+ KONA_CLK(slave, bsc1, peri),
+ [BCM281XX_SLAVE_CCU_BSC2] =
+ KONA_CLK(slave, bsc2, peri),
+ [BCM281XX_SLAVE_CCU_BSC3] =
+ KONA_CLK(slave, bsc3, peri),
+ [BCM281XX_SLAVE_CCU_PWM] =
+ KONA_CLK(slave, pwm, peri),
+ [BCM281XX_SLAVE_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
+};
/* Device tree match table callback functions */
static void __init kona_dt_root_ccu_setup(struct device_node *node)
{
- kona_dt_ccu_setup(node, bcm281xx_root_ccu_clks_setup);
+ kona_dt_ccu_setup(&root_ccu_data, node);
}
static void __init kona_dt_aon_ccu_setup(struct device_node *node)
{
- kona_dt_ccu_setup(node, bcm281xx_aon_ccu_clks_setup);
+ kona_dt_ccu_setup(&aon_ccu_data, node);
}
static void __init kona_dt_hub_ccu_setup(struct device_node *node)
{
- kona_dt_ccu_setup(node, bcm281xx_hub_ccu_clks_setup);
+ kona_dt_ccu_setup(&hub_ccu_data, node);
}
static void __init kona_dt_master_ccu_setup(struct device_node *node)
{
- kona_dt_ccu_setup(node, bcm281xx_master_ccu_clks_setup);
+ kona_dt_ccu_setup(&master_ccu_data, node);
}
static void __init kona_dt_slave_ccu_setup(struct device_node *node)
{
- kona_dt_ccu_setup(node, bcm281xx_slave_ccu_clks_setup);
+ kona_dt_ccu_setup(&slave_ccu_data, node);
}
-CLK_OF_DECLARE(bcm11351_root_ccu, BCM11351_DT_ROOT_CCU_COMPAT,
+CLK_OF_DECLARE(bcm281xx_root_ccu, BCM281XX_DT_ROOT_CCU_COMPAT,
kona_dt_root_ccu_setup);
-CLK_OF_DECLARE(bcm11351_aon_ccu, BCM11351_DT_AON_CCU_COMPAT,
+CLK_OF_DECLARE(bcm281xx_aon_ccu, BCM281XX_DT_AON_CCU_COMPAT,
kona_dt_aon_ccu_setup);
-CLK_OF_DECLARE(bcm11351_hub_ccu, BCM11351_DT_HUB_CCU_COMPAT,
+CLK_OF_DECLARE(bcm281xx_hub_ccu, BCM281XX_DT_HUB_CCU_COMPAT,
kona_dt_hub_ccu_setup);
-CLK_OF_DECLARE(bcm11351_master_ccu, BCM11351_DT_MASTER_CCU_COMPAT,
+CLK_OF_DECLARE(bcm281xx_master_ccu, BCM281XX_DT_MASTER_CCU_COMPAT,
kona_dt_master_ccu_setup);
-CLK_OF_DECLARE(bcm11351_slave_ccu, BCM11351_DT_SLAVE_CCU_COMPAT,
+CLK_OF_DECLARE(bcm281xx_slave_ccu, BCM281XX_DT_SLAVE_CCU_COMPAT,
kona_dt_slave_ccu_setup);
diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c
index 54a0652..e5aeded 100644
--- a/drivers/clk/bcm/clk-kona-setup.c
+++ b/drivers/clk/bcm/clk-kona-setup.c
@@ -25,6 +25,31 @@
/* Validity checking */
+static bool ccu_data_offsets_valid(struct ccu_data *ccu)
+{
+ struct ccu_policy *ccu_policy = &ccu->policy;
+ u32 limit;
+
+ limit = ccu->range - sizeof(u32);
+ limit = round_down(limit, sizeof(u32));
+ if (ccu_policy_exists(ccu_policy)) {
+ if (ccu_policy->enable.offset > limit) {
+ pr_err("%s: bad policy enable offset for %s "
+ "(%u > %u)\n", __func__,
+ ccu->name, ccu_policy->enable.offset, limit);
+ return false;
+ }
+ if (ccu_policy->control.offset > limit) {
+ pr_err("%s: bad policy control offset for %s "
+ "(%u > %u)\n", __func__,
+ ccu->name, ccu_policy->control.offset, limit);
+ return false;
+ }
+ }
+
+ return true;
+}
+
static bool clk_requires_trigger(struct kona_clk *bcm_clk)
{
struct peri_clk_data *peri = bcm_clk->u.peri;
@@ -54,7 +79,9 @@
static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk)
{
struct peri_clk_data *peri;
+ struct bcm_clk_policy *policy;
struct bcm_clk_gate *gate;
+ struct bcm_clk_hyst *hyst;
struct bcm_clk_div *div;
struct bcm_clk_sel *sel;
struct bcm_clk_trig *trig;
@@ -64,19 +91,41 @@
BUG_ON(bcm_clk->type != bcm_clk_peri);
peri = bcm_clk->u.peri;
- name = bcm_clk->name;
+ name = bcm_clk->init_data.name;
range = bcm_clk->ccu->range;
limit = range - sizeof(u32);
limit = round_down(limit, sizeof(u32));
+ policy = &peri->policy;
+ if (policy_exists(policy)) {
+ if (policy->offset > limit) {
+ pr_err("%s: bad policy offset for %s (%u > %u)\n",
+ __func__, name, policy->offset, limit);
+ return false;
+ }
+ }
+
gate = &peri->gate;
+ hyst = &peri->hyst;
if (gate_exists(gate)) {
if (gate->offset > limit) {
pr_err("%s: bad gate offset for %s (%u > %u)\n",
__func__, name, gate->offset, limit);
return false;
}
+
+ if (hyst_exists(hyst)) {
+ if (hyst->offset > limit) {
+ pr_err("%s: bad hysteresis offset for %s "
+ "(%u > %u)\n", __func__,
+ name, hyst->offset, limit);
+ return false;
+ }
+ }
+ } else if (hyst_exists(hyst)) {
+ pr_err("%s: hysteresis but no gate for %s\n", __func__, name);
+ return false;
}
div = &peri->div;
@@ -167,6 +216,36 @@
return true;
}
+static bool
+ccu_policy_valid(struct ccu_policy *ccu_policy, const char *ccu_name)
+{
+ struct bcm_lvm_en *enable = &ccu_policy->enable;
+ struct bcm_policy_ctl *control;
+
+ if (!bit_posn_valid(enable->bit, "policy enable", ccu_name))
+ return false;
+
+ control = &ccu_policy->control;
+ if (!bit_posn_valid(control->go_bit, "policy control GO", ccu_name))
+ return false;
+
+ if (!bit_posn_valid(control->atl_bit, "policy control ATL", ccu_name))
+ return false;
+
+ if (!bit_posn_valid(control->ac_bit, "policy control AC", ccu_name))
+ return false;
+
+ return true;
+}
+
+static bool policy_valid(struct bcm_clk_policy *policy, const char *clock_name)
+{
+ if (!bit_posn_valid(policy->bit, "policy", clock_name))
+ return false;
+
+ return true;
+}
+
/*
* All gates, if defined, have a status bit, and for hardware-only
* gates, that's it. Gates that can be software controlled also
@@ -196,6 +275,17 @@
return true;
}
+static bool hyst_valid(struct bcm_clk_hyst *hyst, const char *clock_name)
+{
+ if (!bit_posn_valid(hyst->en_bit, "hysteresis enable", clock_name))
+ return false;
+
+ if (!bit_posn_valid(hyst->val_bit, "hysteresis value", clock_name))
+ return false;
+
+ return true;
+}
+
/*
* A selector bitfield must be valid. Its parent_sel array must
* also be reasonable for the field.
@@ -312,7 +402,9 @@
peri_clk_data_valid(struct kona_clk *bcm_clk)
{
struct peri_clk_data *peri;
+ struct bcm_clk_policy *policy;
struct bcm_clk_gate *gate;
+ struct bcm_clk_hyst *hyst;
struct bcm_clk_sel *sel;
struct bcm_clk_div *div;
struct bcm_clk_div *pre_div;
@@ -330,11 +422,20 @@
return false;
peri = bcm_clk->u.peri;
- name = bcm_clk->name;
+ name = bcm_clk->init_data.name;
+
+ policy = &peri->policy;
+ if (policy_exists(policy) && !policy_valid(policy, name))
+ return false;
+
gate = &peri->gate;
if (gate_exists(gate) && !gate_valid(gate, "gate", name))
return false;
+ hyst = &peri->hyst;
+ if (hyst_exists(hyst) && !hyst_valid(hyst, name))
+ return false;
+
sel = &peri->sel;
if (selector_exists(sel)) {
if (!sel_valid(sel, "selector", name))
@@ -567,7 +668,6 @@
struct clk_init_data *init_data)
{
clk_sel_teardown(&data->sel, init_data);
- init_data->ops = NULL;
}
/*
@@ -576,10 +676,9 @@
* that can be assigned if the clock has one or more parent clocks
* associated with it.
*/
-static int peri_clk_setup(struct ccu_data *ccu, struct peri_clk_data *data,
- struct clk_init_data *init_data)
+static int
+peri_clk_setup(struct peri_clk_data *data, struct clk_init_data *init_data)
{
- init_data->ops = &kona_peri_clk_ops;
init_data->flags = CLK_IGNORE_UNUSED;
return clk_sel_setup(data->clocks, &data->sel, init_data);
@@ -617,39 +716,26 @@
bcm_clk_teardown(bcm_clk);
}
-struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name,
- enum bcm_clk_type type, void *data)
+struct clk *kona_clk_setup(struct kona_clk *bcm_clk)
{
- struct kona_clk *bcm_clk;
- struct clk_init_data *init_data;
+ struct clk_init_data *init_data = &bcm_clk->init_data;
struct clk *clk = NULL;
- bcm_clk = kzalloc(sizeof(*bcm_clk), GFP_KERNEL);
- if (!bcm_clk) {
- pr_err("%s: failed to allocate bcm_clk for %s\n", __func__,
- name);
- return NULL;
- }
- bcm_clk->ccu = ccu;
- bcm_clk->name = name;
-
- init_data = &bcm_clk->init_data;
- init_data->name = name;
- switch (type) {
+ switch (bcm_clk->type) {
case bcm_clk_peri:
- if (peri_clk_setup(ccu, data, init_data))
- goto out_free;
+ if (peri_clk_setup(bcm_clk->u.data, init_data))
+ return NULL;
break;
default:
- data = NULL;
- break;
+ pr_err("%s: clock type %d invalid for %s\n", __func__,
+ (int)bcm_clk->type, init_data->name);
+ return NULL;
}
- bcm_clk->type = type;
- bcm_clk->u.data = data;
/* Make sure everything makes sense before we set it up */
if (!kona_clk_valid(bcm_clk)) {
- pr_err("%s: clock data invalid for %s\n", __func__, name);
+ pr_err("%s: clock data invalid for %s\n", __func__,
+ init_data->name);
goto out_teardown;
}
@@ -657,7 +743,7 @@
clk = clk_register(NULL, &bcm_clk->hw);
if (IS_ERR(clk)) {
pr_err("%s: error registering clock %s (%ld)\n", __func__,
- name, PTR_ERR(clk));
+ init_data->name, PTR_ERR(clk));
goto out_teardown;
}
BUG_ON(!clk);
@@ -665,8 +751,6 @@
return clk;
out_teardown:
bcm_clk_teardown(bcm_clk);
-out_free:
- kfree(bcm_clk);
return NULL;
}
@@ -675,50 +759,64 @@
{
u32 i;
- for (i = 0; i < ccu->data.clk_num; i++)
- kona_clk_teardown(ccu->data.clks[i]);
- kfree(ccu->data.clks);
+ for (i = 0; i < ccu->clk_data.clk_num; i++)
+ kona_clk_teardown(ccu->clk_data.clks[i]);
+ kfree(ccu->clk_data.clks);
}
static void kona_ccu_teardown(struct ccu_data *ccu)
{
- if (!ccu)
- return;
-
+ kfree(ccu->clk_data.clks);
+ ccu->clk_data.clks = NULL;
if (!ccu->base)
- goto done;
+ return;
of_clk_del_provider(ccu->node); /* safe if never added */
ccu_clks_teardown(ccu);
list_del(&ccu->links);
of_node_put(ccu->node);
+ ccu->node = NULL;
iounmap(ccu->base);
-done:
- kfree(ccu->name);
- kfree(ccu);
+ ccu->base = NULL;
+}
+
+static bool ccu_data_valid(struct ccu_data *ccu)
+{
+ struct ccu_policy *ccu_policy;
+
+ if (!ccu_data_offsets_valid(ccu))
+ return false;
+
+ ccu_policy = &ccu->policy;
+ if (ccu_policy_exists(ccu_policy))
+ if (!ccu_policy_valid(ccu_policy, ccu->name))
+ return false;
+
+ return true;
}
/*
* Set up a CCU. Call the provided ccu_clks_setup callback to
* initialize the array of clocks provided by the CCU.
*/
-void __init kona_dt_ccu_setup(struct device_node *node,
- int (*ccu_clks_setup)(struct ccu_data *))
+void __init kona_dt_ccu_setup(struct ccu_data *ccu,
+ struct device_node *node)
{
- struct ccu_data *ccu;
struct resource res = { 0 };
resource_size_t range;
+ unsigned int i;
int ret;
- ccu = kzalloc(sizeof(*ccu), GFP_KERNEL);
- if (ccu)
- ccu->name = kstrdup(node->name, GFP_KERNEL);
- if (!ccu || !ccu->name) {
- pr_err("%s: unable to allocate CCU struct for %s\n",
- __func__, node->name);
- kfree(ccu);
+ if (ccu->clk_data.clk_num) {
+ size_t size;
- return;
+ size = ccu->clk_data.clk_num * sizeof(*ccu->clk_data.clks);
+ ccu->clk_data.clks = kzalloc(size, GFP_KERNEL);
+ if (!ccu->clk_data.clks) {
+ pr_err("%s: unable to allocate %u clocks for %s\n",
+ __func__, ccu->clk_data.clk_num, node->name);
+ return;
+ }
}
ret = of_address_to_resource(node, 0, &res);
@@ -736,24 +834,33 @@
}
ccu->range = (u32)range;
+
+ if (!ccu_data_valid(ccu)) {
+ pr_err("%s: ccu data not valid for %s\n", __func__, node->name);
+ goto out_err;
+ }
+
ccu->base = ioremap(res.start, ccu->range);
if (!ccu->base) {
pr_err("%s: unable to map CCU registers for %s\n", __func__,
node->name);
goto out_err;
}
-
- spin_lock_init(&ccu->lock);
- INIT_LIST_HEAD(&ccu->links);
ccu->node = of_node_get(node);
-
list_add_tail(&ccu->links, &ccu_list);
- /* Set up clocks array (in ccu->data) */
- if (ccu_clks_setup(ccu))
- goto out_err;
+ /*
+ * Set up each defined kona clock and save the result in
+ * the clock framework clock array (in ccu->data). Then
+ * register as a provider for these clocks.
+ */
+ for (i = 0; i < ccu->clk_data.clk_num; i++) {
+ if (!ccu->kona_clks[i].ccu)
+ continue;
+ ccu->clk_data.clks[i] = kona_clk_setup(&ccu->kona_clks[i]);
+ }
- ret = of_clk_add_provider(node, of_clk_src_onecell_get, &ccu->data);
+ ret = of_clk_add_provider(node, of_clk_src_onecell_get, &ccu->clk_data);
if (ret) {
pr_err("%s: error adding ccu %s as provider (%d)\n", __func__,
node->name, ret);
diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c
index db11a87..d603c4e 100644
--- a/drivers/clk/bcm/clk-kona.c
+++ b/drivers/clk/bcm/clk-kona.c
@@ -16,6 +16,14 @@
#include <linux/delay.h>
+/*
+ * "Policies" affect the frequencies of bus clocks provided by a
+ * CCU. (I believe these polices are named "Deep Sleep", "Economy",
+ * "Normal", and "Turbo".) A lower policy number has lower power
+ * consumption, and policy 2 is the default.
+ */
+#define CCU_POLICY_COUNT 4
+
#define CCU_ACCESS_PASSWORD 0xA5A500
#define CLK_GATE_DELAY_LOOP 2000
@@ -207,9 +215,154 @@
return true;
udelay(1);
}
+ pr_warn("%s: %s/0x%04x bit %u was never %s\n", __func__,
+ ccu->name, reg_offset, bit, want ? "set" : "clear");
+
return false;
}
+/* Policy operations */
+
+static bool __ccu_policy_engine_start(struct ccu_data *ccu, bool sync)
+{
+ struct bcm_policy_ctl *control = &ccu->policy.control;
+ u32 offset;
+ u32 go_bit;
+ u32 mask;
+ bool ret;
+
+ /* If we don't need to control policy for this CCU, we're done. */
+ if (!policy_ctl_exists(control))
+ return true;
+
+ offset = control->offset;
+ go_bit = control->go_bit;
+
+ /* Ensure we're not busy before we start */
+ ret = __ccu_wait_bit(ccu, offset, go_bit, false);
+ if (!ret) {
+ pr_err("%s: ccu %s policy engine wouldn't go idle\n",
+ __func__, ccu->name);
+ return false;
+ }
+
+ /*
+ * If it's a synchronous request, we'll wait for the voltage
+ * and frequency of the active load to stabilize before
+ * returning. To do this we select the active load by
+ * setting the ATL bit.
+ *
+ * An asynchronous request instead ramps the voltage in the
+ * background, and when that process stabilizes, the target
+ * load is copied to the active load and the CCU frequency
+ * is switched. We do this by selecting the target load
+ * (ATL bit clear) and setting the request auto-copy (AC bit
+ * set).
+ *
+ * Note, we do NOT read-modify-write this register.
+ */
+ mask = (u32)1 << go_bit;
+ if (sync)
+ mask |= 1 << control->atl_bit;
+ else
+ mask |= 1 << control->ac_bit;
+ __ccu_write(ccu, offset, mask);
+
+ /* Wait for indication that operation is complete. */
+ ret = __ccu_wait_bit(ccu, offset, go_bit, false);
+ if (!ret)
+ pr_err("%s: ccu %s policy engine never started\n",
+ __func__, ccu->name);
+
+ return ret;
+}
+
+static bool __ccu_policy_engine_stop(struct ccu_data *ccu)
+{
+ struct bcm_lvm_en *enable = &ccu->policy.enable;
+ u32 offset;
+ u32 enable_bit;
+ bool ret;
+
+ /* If we don't need to control policy for this CCU, we're done. */
+ if (!policy_lvm_en_exists(enable))
+ return true;
+
+ /* Ensure we're not busy before we start */
+ offset = enable->offset;
+ enable_bit = enable->bit;
+ ret = __ccu_wait_bit(ccu, offset, enable_bit, false);
+ if (!ret) {
+ pr_err("%s: ccu %s policy engine already stopped\n",
+ __func__, ccu->name);
+ return false;
+ }
+
+ /* Now set the bit to stop the engine (NO read-modify-write) */
+ __ccu_write(ccu, offset, (u32)1 << enable_bit);
+
+ /* Wait for indication that it has stopped. */
+ ret = __ccu_wait_bit(ccu, offset, enable_bit, false);
+ if (!ret)
+ pr_err("%s: ccu %s policy engine never stopped\n",
+ __func__, ccu->name);
+
+ return ret;
+}
+
+/*
+ * A CCU has four operating conditions ("policies"), and some clocks
+ * can be disabled or enabled based on which policy is currently in
+ * effect. Such clocks have a bit in a "policy mask" register for
+ * each policy indicating whether the clock is enabled for that
+ * policy or not. The bit position for a clock is the same for all
+ * four registers, and the 32-bit registers are at consecutive
+ * addresses.
+ */
+static bool policy_init(struct ccu_data *ccu, struct bcm_clk_policy *policy)
+{
+ u32 offset;
+ u32 mask;
+ int i;
+ bool ret;
+
+ if (!policy_exists(policy))
+ return true;
+
+ /*
+ * We need to stop the CCU policy engine to allow update
+ * of our policy bits.
+ */
+ if (!__ccu_policy_engine_stop(ccu)) {
+ pr_err("%s: unable to stop CCU %s policy engine\n",
+ __func__, ccu->name);
+ return false;
+ }
+
+ /*
+ * For now, if a clock defines its policy bit we just mark
+ * it "enabled" for all four policies.
+ */
+ offset = policy->offset;
+ mask = (u32)1 << policy->bit;
+ for (i = 0; i < CCU_POLICY_COUNT; i++) {
+ u32 reg_val;
+
+ reg_val = __ccu_read(ccu, offset);
+ reg_val |= mask;
+ __ccu_write(ccu, offset, reg_val);
+ offset += sizeof(u32);
+ }
+
+ /* We're done updating; fire up the policy engine again. */
+ ret = __ccu_policy_engine_start(ccu, true);
+ if (!ret)
+ pr_err("%s: unable to restart CCU %s policy engine\n",
+ __func__, ccu->name);
+
+ return ret;
+}
+
/* Gate operations */
/* Determine whether a clock is gated. CCU lock must be held. */
@@ -374,6 +527,35 @@
return -EIO;
}
+/* Hysteresis operations */
+
+/*
+ * If a clock gate requires a turn-off delay it will have
+ * "hysteresis" register bits defined. The first, if set, enables
+ * the delay; and if enabled, the second bit determines whether the
+ * delay is "low" or "high" (1 means high). For now, if it's
+ * defined for a clock, we set it.
+ */
+static bool hyst_init(struct ccu_data *ccu, struct bcm_clk_hyst *hyst)
+{
+ u32 offset;
+ u32 reg_val;
+ u32 mask;
+
+ if (!hyst_exists(hyst))
+ return true;
+
+ offset = hyst->offset;
+ mask = (u32)1 << hyst->en_bit;
+ mask |= (u32)1 << hyst->val_bit;
+
+ reg_val = __ccu_read(ccu, offset);
+ reg_val |= mask;
+ __ccu_write(ccu, offset, reg_val);
+
+ return true;
+}
+
/* Trigger operations */
/*
@@ -806,7 +988,7 @@
struct kona_clk *bcm_clk = to_kona_clk(hw);
struct bcm_clk_gate *gate = &bcm_clk->u.peri->gate;
- return clk_gate(bcm_clk->ccu, bcm_clk->name, gate, true);
+ return clk_gate(bcm_clk->ccu, bcm_clk->init_data.name, gate, true);
}
static void kona_peri_clk_disable(struct clk_hw *hw)
@@ -814,7 +996,7 @@
struct kona_clk *bcm_clk = to_kona_clk(hw);
struct bcm_clk_gate *gate = &bcm_clk->u.peri->gate;
- (void)clk_gate(bcm_clk->ccu, bcm_clk->name, gate, false);
+ (void)clk_gate(bcm_clk->ccu, bcm_clk->init_data.name, gate, false);
}
static int kona_peri_clk_is_enabled(struct clk_hw *hw)
@@ -872,12 +1054,13 @@
ret = selector_write(bcm_clk->ccu, &data->gate, sel, trig, index);
if (ret == -ENXIO) {
- pr_err("%s: gating failure for %s\n", __func__, bcm_clk->name);
+ pr_err("%s: gating failure for %s\n", __func__,
+ bcm_clk->init_data.name);
ret = -EIO; /* Don't proliferate weird errors */
} else if (ret == -EIO) {
pr_err("%s: %strigger failed for %s\n", __func__,
trig == &data->pre_trig ? "pre-" : "",
- bcm_clk->name);
+ bcm_clk->init_data.name);
}
return ret;
@@ -936,10 +1119,12 @@
ret = divider_write(bcm_clk->ccu, &data->gate, &data->div,
&data->trig, scaled_div);
if (ret == -ENXIO) {
- pr_err("%s: gating failure for %s\n", __func__, bcm_clk->name);
+ pr_err("%s: gating failure for %s\n", __func__,
+ bcm_clk->init_data.name);
ret = -EIO; /* Don't proliferate weird errors */
} else if (ret == -EIO) {
- pr_err("%s: trigger failed for %s\n", __func__, bcm_clk->name);
+ pr_err("%s: trigger failed for %s\n", __func__,
+ bcm_clk->init_data.name);
}
return ret;
@@ -961,15 +1146,24 @@
{
struct ccu_data *ccu = bcm_clk->ccu;
struct peri_clk_data *peri = bcm_clk->u.peri;
- const char *name = bcm_clk->name;
+ const char *name = bcm_clk->init_data.name;
struct bcm_clk_trig *trig;
BUG_ON(bcm_clk->type != bcm_clk_peri);
+ if (!policy_init(ccu, &peri->policy)) {
+ pr_err("%s: error initializing policy for %s\n",
+ __func__, name);
+ return false;
+ }
if (!gate_init(ccu, &peri->gate)) {
pr_err("%s: error initializing gate for %s\n", __func__, name);
return false;
}
+ if (!hyst_init(ccu, &peri->hyst)) {
+ pr_err("%s: error initializing hyst for %s\n", __func__, name);
+ return false;
+ }
if (!div_init(ccu, &peri->gate, &peri->div, &peri->trig)) {
pr_err("%s: error initializing divider for %s\n", __func__,
name);
@@ -1014,13 +1208,13 @@
{
unsigned long flags;
unsigned int which;
- struct clk **clks = ccu->data.clks;
+ struct clk **clks = ccu->clk_data.clks;
bool success = true;
flags = ccu_lock(ccu);
__ccu_write_enable(ccu);
- for (which = 0; which < ccu->data.clk_num; which++) {
+ for (which = 0; which < ccu->clk_data.clk_num; which++) {
struct kona_clk *bcm_clk;
if (!clks[which])
diff --git a/drivers/clk/bcm/clk-kona.h b/drivers/clk/bcm/clk-kona.h
index dee6909..2537b30 100644
--- a/drivers/clk/bcm/clk-kona.h
+++ b/drivers/clk/bcm/clk-kona.h
@@ -43,8 +43,14 @@
#define FLAG_FLIP(obj, type, flag) ((obj)->flags ^= FLAG(type, flag))
#define FLAG_TEST(obj, type, flag) (!!((obj)->flags & FLAG(type, flag)))
+/* CCU field state tests */
+
+#define ccu_policy_exists(ccu_policy) ((ccu_policy)->enable.offset != 0)
+
/* Clock field state tests */
+#define policy_exists(policy) ((policy)->offset != 0)
+
#define gate_exists(gate) FLAG_TEST(gate, GATE, EXISTS)
#define gate_is_enabled(gate) FLAG_TEST(gate, GATE, ENABLED)
#define gate_is_hw_controllable(gate) FLAG_TEST(gate, GATE, HW)
@@ -54,6 +60,8 @@
#define gate_flip_enabled(gate) FLAG_FLIP(gate, GATE, ENABLED)
+#define hyst_exists(hyst) ((hyst)->offset != 0)
+
#define divider_exists(div) FLAG_TEST(div, DIV, EXISTS)
#define divider_is_fixed(div) FLAG_TEST(div, DIV, FIXED)
#define divider_has_fraction(div) (!divider_is_fixed(div) && \
@@ -62,6 +70,9 @@
#define selector_exists(sel) ((sel)->width != 0)
#define trigger_exists(trig) FLAG_TEST(trig, TRIG, EXISTS)
+#define policy_lvm_en_exists(enable) ((enable)->offset != 0)
+#define policy_ctl_exists(control) ((control)->offset != 0)
+
/* Clock type, used to tell common block what it's part of */
enum bcm_clk_type {
bcm_clk_none, /* undefined clock type */
@@ -71,25 +82,26 @@
};
/*
- * Each CCU defines a mapped area of memory containing registers
- * used to manage clocks implemented by the CCU. Access to memory
- * within the CCU's space is serialized by a spinlock. Before any
- * (other) address can be written, a special access "password" value
- * must be written to its WR_ACCESS register (located at the base
- * address of the range). We keep track of the name of each CCU as
- * it is set up, and maintain them in a list.
+ * CCU policy control for clocks. Clocks can be enabled or disabled
+ * based on the CCU policy in effect. One bit in each policy mask
+ * register (one per CCU policy) represents whether the clock is
+ * enabled when that policy is effect or not. The CCU policy engine
+ * must be stopped to update these bits, and must be restarted again
+ * afterward.
*/
-struct ccu_data {
- void __iomem *base; /* base of mapped address space */
- spinlock_t lock; /* serialization lock */
- bool write_enabled; /* write access is currently enabled */
- struct list_head links; /* for ccu_list */
- struct device_node *node;
- struct clk_onecell_data data;
- const char *name;
- u32 range; /* byte range of address space */
+struct bcm_clk_policy {
+ u32 offset; /* first policy mask register offset */
+ u32 bit; /* bit used in all mask registers */
};
+/* Policy initialization macro */
+
+#define POLICY(_offset, _bit) \
+ { \
+ .offset = (_offset), \
+ .bit = (_bit), \
+ }
+
/*
* Gating control and status is managed by a 32-bit gate register.
*
@@ -195,6 +207,22 @@
.flags = FLAG(GATE, HW)|FLAG(GATE, EXISTS), \
}
+/* Gate hysteresis for clocks */
+struct bcm_clk_hyst {
+ u32 offset; /* hyst register offset (normally CLKGATE) */
+ u32 en_bit; /* bit used to enable hysteresis */
+ u32 val_bit; /* if enabled: 0 = low delay; 1 = high delay */
+};
+
+/* Hysteresis initialization macro */
+
+#define HYST(_offset, _en_bit, _val_bit) \
+ { \
+ .offset = (_offset), \
+ .en_bit = (_en_bit), \
+ .val_bit = (_val_bit), \
+ }
+
/*
* Each clock can have zero, one, or two dividers which change the
* output rate of the clock. Each divider can be either fixed or
@@ -360,7 +388,9 @@
}
struct peri_clk_data {
+ struct bcm_clk_policy policy;
struct bcm_clk_gate gate;
+ struct bcm_clk_hyst hyst;
struct bcm_clk_trig pre_trig;
struct bcm_clk_div pre_div;
struct bcm_clk_trig trig;
@@ -373,8 +403,7 @@
struct kona_clk {
struct clk_hw hw;
- struct clk_init_data init_data;
- const char *name; /* name of this clock */
+ struct clk_init_data init_data; /* includes name of this clock */
struct ccu_data *ccu; /* ccu this clock is associated with */
enum bcm_clk_type type;
union {
@@ -385,15 +414,93 @@
#define to_kona_clk(_hw) \
container_of(_hw, struct kona_clk, hw)
+/* Initialization macro for an entry in a CCU's kona_clks[] array. */
+#define KONA_CLK(_ccu_name, _clk_name, _type) \
+ { \
+ .init_data = { \
+ .name = #_clk_name, \
+ .ops = &kona_ ## _type ## _clk_ops, \
+ }, \
+ .ccu = &_ccu_name ## _ccu_data, \
+ .type = bcm_clk_ ## _type, \
+ .u.data = &_clk_name ## _data, \
+ }
+#define LAST_KONA_CLK { .type = bcm_clk_none }
+
+/*
+ * CCU policy control. To enable software update of the policy
+ * tables the CCU policy engine must be stopped by setting the
+ * software update enable bit (LVM_EN). After an update the engine
+ * is restarted using the GO bit and either the GO_ATL or GO_AC bit.
+ */
+struct bcm_lvm_en {
+ u32 offset; /* LVM_EN register offset */
+ u32 bit; /* POLICY_CONFIG_EN bit in register */
+};
+
+/* Policy enable initialization macro */
+#define CCU_LVM_EN(_offset, _bit) \
+ { \
+ .offset = (_offset), \
+ .bit = (_bit), \
+ }
+
+struct bcm_policy_ctl {
+ u32 offset; /* POLICY_CTL register offset */
+ u32 go_bit;
+ u32 atl_bit; /* GO, GO_ATL, and GO_AC bits */
+ u32 ac_bit;
+};
+
+/* Policy control initialization macro */
+#define CCU_POLICY_CTL(_offset, _go_bit, _ac_bit, _atl_bit) \
+ { \
+ .offset = (_offset), \
+ .go_bit = (_go_bit), \
+ .ac_bit = (_ac_bit), \
+ .atl_bit = (_atl_bit), \
+ }
+
+struct ccu_policy {
+ struct bcm_lvm_en enable;
+ struct bcm_policy_ctl control;
+};
+
+/*
+ * Each CCU defines a mapped area of memory containing registers
+ * used to manage clocks implemented by the CCU. Access to memory
+ * within the CCU's space is serialized by a spinlock. Before any
+ * (other) address can be written, a special access "password" value
+ * must be written to its WR_ACCESS register (located at the base
+ * address of the range). We keep track of the name of each CCU as
+ * it is set up, and maintain them in a list.
+ */
+struct ccu_data {
+ void __iomem *base; /* base of mapped address space */
+ spinlock_t lock; /* serialization lock */
+ bool write_enabled; /* write access is currently enabled */
+ struct ccu_policy policy;
+ struct list_head links; /* for ccu_list */
+ struct device_node *node;
+ struct clk_onecell_data clk_data;
+ const char *name;
+ u32 range; /* byte range of address space */
+ struct kona_clk kona_clks[]; /* must be last */
+};
+
+/* Initialization for common fields in a Kona ccu_data structure */
+#define KONA_CCU_COMMON(_prefix, _name, _ccuname) \
+ .name = #_name "_ccu", \
+ .lock = __SPIN_LOCK_UNLOCKED(_name ## _ccu_data.lock), \
+ .links = LIST_HEAD_INIT(_name ## _ccu_data.links), \
+ .clk_data = { \
+ .clk_num = _prefix ## _ ## _ccuname ## _CCU_CLOCK_COUNT, \
+ }
+
/* Exported globals */
extern struct clk_ops kona_peri_clk_ops;
-/* Help functions */
-
-#define PERI_CLK_SETUP(clks, ccu, id, name) \
- clks[id] = kona_clk_setup(ccu, #name, bcm_clk_peri, &name ## _data)
-
/* Externally visible functions */
extern u64 do_div_round_closest(u64 dividend, unsigned long divisor);
@@ -401,10 +508,9 @@
extern u64 scaled_div_build(struct bcm_clk_div *div, u32 div_value,
u32 billionths);
-extern struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name,
- enum bcm_clk_type type, void *data);
-extern void __init kona_dt_ccu_setup(struct device_node *node,
- int (*ccu_clks_setup)(struct ccu_data *));
+extern struct clk *kona_clk_setup(struct kona_clk *bcm_clk);
+extern void __init kona_dt_ccu_setup(struct ccu_data *ccu,
+ struct device_node *node);
extern bool __init kona_ccu_init(struct ccu_data *ccu);
#endif /* _CLK_KONA_H */
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 4637697..b3c8396 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -43,6 +43,17 @@
return maxdiv;
}
+static unsigned int _get_table_mindiv(const struct clk_div_table *table)
+{
+ unsigned int mindiv = UINT_MAX;
+ const struct clk_div_table *clkt;
+
+ for (clkt = table; clkt->div; clkt++)
+ if (clkt->div < mindiv)
+ mindiv = clkt->div;
+ return mindiv;
+}
+
static unsigned int _get_maxdiv(struct clk_divider *divider)
{
if (divider->flags & CLK_DIVIDER_ONE_BASED)
@@ -162,6 +173,24 @@
return up;
}
+static int _round_down_table(const struct clk_div_table *table, int div)
+{
+ const struct clk_div_table *clkt;
+ int down = _get_table_mindiv(table);
+
+ for (clkt = table; clkt->div; clkt++) {
+ if (clkt->div == div)
+ return clkt->div;
+ else if (clkt->div > div)
+ continue;
+
+ if ((div - clkt->div) < (div - down))
+ down = clkt->div;
+ }
+
+ return down;
+}
+
static int _div_round_up(struct clk_divider *divider,
unsigned long parent_rate, unsigned long rate)
{
@@ -175,6 +204,54 @@
return div;
}
+static int _div_round_closest(struct clk_divider *divider,
+ unsigned long parent_rate, unsigned long rate)
+{
+ int up, down, div;
+
+ up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate);
+
+ if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) {
+ up = __roundup_pow_of_two(div);
+ down = __rounddown_pow_of_two(div);
+ } else if (divider->table) {
+ up = _round_up_table(divider->table, div);
+ down = _round_down_table(divider->table, div);
+ }
+
+ return (up - div) <= (div - down) ? up : down;
+}
+
+static int _div_round(struct clk_divider *divider, unsigned long parent_rate,
+ unsigned long rate)
+{
+ if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST)
+ return _div_round_closest(divider, parent_rate, rate);
+
+ return _div_round_up(divider, parent_rate, rate);
+}
+
+static bool _is_best_div(struct clk_divider *divider,
+ int rate, int now, int best)
+{
+ if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST)
+ return abs(rate - now) < abs(rate - best);
+
+ return now <= rate && now > best;
+}
+
+static int _next_div(struct clk_divider *divider, int div)
+{
+ div++;
+
+ if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+ return __roundup_pow_of_two(div);
+ if (divider->table)
+ return _round_up_table(divider->table, div);
+
+ return div;
+}
+
static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate)
{
@@ -190,7 +267,7 @@
if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
parent_rate = *best_parent_rate;
- bestdiv = _div_round_up(divider, parent_rate, rate);
+ bestdiv = _div_round(divider, parent_rate, rate);
bestdiv = bestdiv == 0 ? 1 : bestdiv;
bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
return bestdiv;
@@ -202,7 +279,7 @@
*/
maxdiv = min(ULONG_MAX / rate, maxdiv);
- for (i = 1; i <= maxdiv; i++) {
+ for (i = 1; i <= maxdiv; i = _next_div(divider, i)) {
if (!_is_valid_div(divider, i))
continue;
if (rate * i == parent_rate_saved) {
@@ -217,7 +294,7 @@
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
MULT_ROUND_UP(rate, i));
now = DIV_ROUND_UP(parent_rate, i);
- if (now <= rate && now > best) {
+ if (_is_best_div(divider, rate, now, best)) {
bestdiv = i;
best = now;
*best_parent_rate = parent_rate;
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 7cf2c09..4d56220 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -822,6 +822,9 @@
*/
void clk_unprepare(struct clk *clk)
{
+ if (IS_ERR_OR_NULL(clk))
+ return;
+
clk_prepare_lock();
__clk_unprepare(clk);
clk_prepare_unlock();
@@ -883,9 +886,6 @@
if (!clk)
return;
- if (WARN_ON(IS_ERR(clk)))
- return;
-
if (WARN_ON(clk->enable_count == 0))
return;
@@ -914,6 +914,9 @@
{
unsigned long flags;
+ if (IS_ERR_OR_NULL(clk))
+ return;
+
flags = clk_enable_lock();
__clk_disable(clk);
clk_enable_unlock(flags);
@@ -1115,6 +1118,13 @@
}
EXPORT_SYMBOL_GPL(clk_get_accuracy);
+static unsigned long clk_recalc(struct clk *clk, unsigned long parent_rate)
+{
+ if (clk->ops->recalc_rate)
+ return clk->ops->recalc_rate(clk->hw, parent_rate);
+ return parent_rate;
+}
+
/**
* __clk_recalc_rates
* @clk: first clk in the subtree
@@ -1140,10 +1150,7 @@
if (clk->parent)
parent_rate = clk->parent->rate;
- if (clk->ops->recalc_rate)
- clk->rate = clk->ops->recalc_rate(clk->hw, parent_rate);
- else
- clk->rate = parent_rate;
+ clk->rate = clk_recalc(clk, parent_rate);
/*
* ignore NOTIFY_STOP and NOTIFY_BAD return values for POST_RATE_CHANGE
@@ -1334,10 +1341,7 @@
unsigned long new_rate;
int ret = NOTIFY_DONE;
- if (clk->ops->recalc_rate)
- new_rate = clk->ops->recalc_rate(clk->hw, parent_rate);
- else
- new_rate = parent_rate;
+ new_rate = clk_recalc(clk, parent_rate);
/* abort rate change if a driver returns NOTIFY_BAD or NOTIFY_STOP */
if (clk->notifier_count)
@@ -1373,10 +1377,7 @@
new_parent->new_child = clk;
hlist_for_each_entry(child, &clk->children, child_node) {
- if (child->ops->recalc_rate)
- child->new_rate = child->ops->recalc_rate(child->hw, new_rate);
- else
- child->new_rate = new_rate;
+ child->new_rate = clk_recalc(child, new_rate);
clk_calc_subtree(child, child->new_rate, NULL, 0);
}
}
@@ -1524,10 +1525,7 @@
if (!skip_set_rate && clk->ops->set_rate)
clk->ops->set_rate(clk->hw, clk->new_rate, best_parent_rate);
- if (clk->ops->recalc_rate)
- clk->rate = clk->ops->recalc_rate(clk->hw, best_parent_rate);
- else
- clk->rate = best_parent_rate;
+ clk->rate = clk_recalc(clk, best_parent_rate);
if (clk->notifier_count && old_rate != clk->rate)
__clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
@@ -1716,9 +1714,6 @@
if (!clk)
return 0;
- if (!clk->ops)
- return -EINVAL;
-
/* verify ops for for multi-parent clks */
if ((clk->num_parents > 1) && (!clk->ops->set_parent))
return -ENOSYS;
diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile
index 40b33c6..038c02f 100644
--- a/drivers/clk/hisilicon/Makefile
+++ b/drivers/clk/hisilicon/Makefile
@@ -6,3 +6,4 @@
obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o
obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o
+obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o
diff --git a/drivers/clk/hisilicon/clk-hix5hd2.c b/drivers/clk/hisilicon/clk-hix5hd2.c
new file mode 100644
index 0000000..e5fcfb4
--- /dev/null
+++ b/drivers/clk/hisilicon/clk-hix5hd2.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2014 Linaro Ltd.
+ * Copyright (c) 2014 Hisilicon Limited.
+ *
+ * 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.
+ */
+
+#include <linux/of_address.h>
+#include <dt-bindings/clock/hix5hd2-clock.h>
+#include "clk.h"
+
+static struct hisi_fixed_rate_clock hix5hd2_fixed_rate_clks[] __initdata = {
+ { HIX5HD2_FIXED_1200M, "1200m", NULL, CLK_IS_ROOT, 1200000000, },
+ { HIX5HD2_FIXED_400M, "400m", NULL, CLK_IS_ROOT, 400000000, },
+ { HIX5HD2_FIXED_48M, "48m", NULL, CLK_IS_ROOT, 48000000, },
+ { HIX5HD2_FIXED_24M, "24m", NULL, CLK_IS_ROOT, 24000000, },
+ { HIX5HD2_FIXED_600M, "600m", NULL, CLK_IS_ROOT, 600000000, },
+ { HIX5HD2_FIXED_300M, "300m", NULL, CLK_IS_ROOT, 300000000, },
+ { HIX5HD2_FIXED_75M, "75m", NULL, CLK_IS_ROOT, 75000000, },
+ { HIX5HD2_FIXED_200M, "200m", NULL, CLK_IS_ROOT, 200000000, },
+ { HIX5HD2_FIXED_100M, "100m", NULL, CLK_IS_ROOT, 100000000, },
+ { HIX5HD2_FIXED_40M, "40m", NULL, CLK_IS_ROOT, 40000000, },
+ { HIX5HD2_FIXED_150M, "150m", NULL, CLK_IS_ROOT, 150000000, },
+ { HIX5HD2_FIXED_1728M, "1728m", NULL, CLK_IS_ROOT, 1728000000, },
+ { HIX5HD2_FIXED_28P8M, "28p8m", NULL, CLK_IS_ROOT, 28000000, },
+ { HIX5HD2_FIXED_432M, "432m", NULL, CLK_IS_ROOT, 432000000, },
+ { HIX5HD2_FIXED_345P6M, "345p6m", NULL, CLK_IS_ROOT, 345000000, },
+ { HIX5HD2_FIXED_288M, "288m", NULL, CLK_IS_ROOT, 288000000, },
+ { HIX5HD2_FIXED_60M, "60m", NULL, CLK_IS_ROOT, 60000000, },
+ { HIX5HD2_FIXED_750M, "750m", NULL, CLK_IS_ROOT, 750000000, },
+ { HIX5HD2_FIXED_500M, "500m", NULL, CLK_IS_ROOT, 500000000, },
+ { HIX5HD2_FIXED_54M, "54m", NULL, CLK_IS_ROOT, 54000000, },
+ { HIX5HD2_FIXED_27M, "27m", NULL, CLK_IS_ROOT, 27000000, },
+ { HIX5HD2_FIXED_1500M, "1500m", NULL, CLK_IS_ROOT, 1500000000, },
+ { HIX5HD2_FIXED_375M, "375m", NULL, CLK_IS_ROOT, 375000000, },
+ { HIX5HD2_FIXED_187M, "187m", NULL, CLK_IS_ROOT, 187000000, },
+ { HIX5HD2_FIXED_250M, "250m", NULL, CLK_IS_ROOT, 250000000, },
+ { HIX5HD2_FIXED_125M, "125m", NULL, CLK_IS_ROOT, 125000000, },
+ { HIX5HD2_FIXED_2P02M, "2m", NULL, CLK_IS_ROOT, 2000000, },
+ { HIX5HD2_FIXED_50M, "50m", NULL, CLK_IS_ROOT, 50000000, },
+ { HIX5HD2_FIXED_25M, "25m", NULL, CLK_IS_ROOT, 25000000, },
+ { HIX5HD2_FIXED_83M, "83m", NULL, CLK_IS_ROOT, 83333333, },
+};
+
+static const char *sfc_mux_p[] __initconst = {
+ "24m", "150m", "200m", "100m", "75m", };
+static u32 sfc_mux_table[] = {0, 4, 5, 6, 7};
+
+static const char *sdio1_mux_p[] __initconst = {
+ "75m", "100m", "50m", "15m", };
+static u32 sdio1_mux_table[] = {0, 1, 2, 3};
+
+static const char *fephy_mux_p[] __initconst = { "25m", "125m"};
+static u32 fephy_mux_table[] = {0, 1};
+
+
+static struct hisi_mux_clock hix5hd2_mux_clks[] __initdata = {
+ { HIX5HD2_SFC_MUX, "sfc_mux", sfc_mux_p, ARRAY_SIZE(sfc_mux_p),
+ CLK_SET_RATE_PARENT, 0x5c, 8, 3, 0, sfc_mux_table, },
+ { HIX5HD2_MMC_MUX, "mmc_mux", sdio1_mux_p, ARRAY_SIZE(sdio1_mux_p),
+ CLK_SET_RATE_PARENT, 0xa0, 8, 2, 0, sdio1_mux_table, },
+ { HIX5HD2_FEPHY_MUX, "fephy_mux",
+ fephy_mux_p, ARRAY_SIZE(fephy_mux_p),
+ CLK_SET_RATE_PARENT, 0x120, 8, 2, 0, fephy_mux_table, },
+};
+
+static struct hisi_gate_clock hix5hd2_gate_clks[] __initdata = {
+ /*sfc*/
+ { HIX5HD2_SFC_CLK, "clk_sfc", "sfc_mux",
+ CLK_SET_RATE_PARENT, 0x5c, 0, 0, },
+ { HIX5HD2_SFC_RST, "rst_sfc", "clk_sfc",
+ CLK_SET_RATE_PARENT, 0x5c, 4, CLK_GATE_SET_TO_DISABLE, },
+ /*sdio1*/
+ { HIX5HD2_MMC_BIU_CLK, "clk_mmc_biu", "200m",
+ CLK_SET_RATE_PARENT, 0xa0, 0, 0, },
+ { HIX5HD2_MMC_CIU_CLK, "clk_mmc_ciu", "mmc_mux",
+ CLK_SET_RATE_PARENT, 0xa0, 1, 0, },
+ { HIX5HD2_MMC_CIU_RST, "rst_mmc_ciu", "clk_mmc_ciu",
+ CLK_SET_RATE_PARENT, 0xa0, 4, CLK_GATE_SET_TO_DISABLE, },
+};
+
+static void __init hix5hd2_clk_init(struct device_node *np)
+{
+ struct hisi_clock_data *clk_data;
+
+ clk_data = hisi_clk_init(np, HIX5HD2_NR_CLKS);
+ if (!clk_data)
+ return;
+
+ hisi_clk_register_fixed_rate(hix5hd2_fixed_rate_clks,
+ ARRAY_SIZE(hix5hd2_fixed_rate_clks),
+ clk_data);
+ hisi_clk_register_mux(hix5hd2_mux_clks, ARRAY_SIZE(hix5hd2_mux_clks),
+ clk_data);
+ hisi_clk_register_gate(hix5hd2_gate_clks,
+ ARRAY_SIZE(hix5hd2_gate_clks), clk_data);
+}
+
+CLK_OF_DECLARE(hix5hd2_clk, "hisilicon,hix5hd2-clock", hix5hd2_clk_init);
diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c
index 276f672..a078e84 100644
--- a/drivers/clk/hisilicon/clk.c
+++ b/drivers/clk/hisilicon/clk.c
@@ -127,11 +127,14 @@
int i;
for (i = 0; i < nums; i++) {
- clk = clk_register_mux(NULL, clks[i].name, clks[i].parent_names,
- clks[i].num_parents, clks[i].flags,
- base + clks[i].offset, clks[i].shift,
- clks[i].width, clks[i].mux_flags,
- &hisi_clk_lock);
+ u32 mask = BIT(clks[i].width) - 1;
+
+ clk = clk_register_mux_table(NULL, clks[i].name,
+ clks[i].parent_names,
+ clks[i].num_parents, clks[i].flags,
+ base + clks[i].offset, clks[i].shift,
+ mask, clks[i].mux_flags,
+ clks[i].table, &hisi_clk_lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
@@ -174,6 +177,34 @@
}
}
+void __init hisi_clk_register_gate(struct hisi_gate_clock *clks,
+ int nums, struct hisi_clock_data *data)
+{
+ struct clk *clk;
+ void __iomem *base = data->base;
+ int i;
+
+ for (i = 0; i < nums; i++) {
+ clk = clk_register_gate(NULL, clks[i].name,
+ clks[i].parent_name,
+ clks[i].flags,
+ base + clks[i].offset,
+ clks[i].bit_idx,
+ clks[i].gate_flags,
+ &hisi_clk_lock);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register clock %s\n",
+ __func__, clks[i].name);
+ continue;
+ }
+
+ if (clks[i].alias)
+ clk_register_clkdev(clk, clks[i].alias, NULL);
+
+ data->clk_data.clks[clks[i].id] = clk;
+ }
+}
+
void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks,
int nums, struct hisi_clock_data *data)
{
diff --git a/drivers/clk/hisilicon/clk.h b/drivers/clk/hisilicon/clk.h
index 43fa5da..31083ff 100644
--- a/drivers/clk/hisilicon/clk.h
+++ b/drivers/clk/hisilicon/clk.h
@@ -62,6 +62,7 @@
u8 shift;
u8 width;
u8 mux_flags;
+ u32 *table;
const char *alias;
};
@@ -103,6 +104,8 @@
struct hisi_clock_data *);
void __init hisi_clk_register_divider(struct hisi_divider_clock *,
int, struct hisi_clock_data *);
+void __init hisi_clk_register_gate(struct hisi_gate_clock *,
+ int, struct hisi_clock_data *);
void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *,
int, struct hisi_clock_data *);
#endif /* __HISI_CLK_H */
diff --git a/drivers/clk/mvebu/Kconfig b/drivers/clk/mvebu/Kconfig
index 693f7be..3b34dba 100644
--- a/drivers/clk/mvebu/Kconfig
+++ b/drivers/clk/mvebu/Kconfig
@@ -34,3 +34,7 @@
config KIRKWOOD_CLK
bool
select MVEBU_CLK_COMMON
+
+config ORION_CLK
+ bool
+ select MVEBU_CLK_COMMON
diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile
index 4c66162..a9a56fc 100644
--- a/drivers/clk/mvebu/Makefile
+++ b/drivers/clk/mvebu/Makefile
@@ -8,3 +8,4 @@
obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o
obj-$(CONFIG_DOVE_CLK) += dove.o
obj-$(CONFIG_KIRKWOOD_CLK) += kirkwood.o
+obj-$(CONFIG_ORION_CLK) += orion.o
diff --git a/drivers/clk/mvebu/orion.c b/drivers/clk/mvebu/orion.c
new file mode 100644
index 0000000..fd12956
--- /dev/null
+++ b/drivers/clk/mvebu/orion.c
@@ -0,0 +1,210 @@
+/*
+ * Marvell Orion SoC clocks
+ *
+ * Copyright (C) 2014 Thomas Petazzoni
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include "common.h"
+
+static const struct coreclk_ratio orion_coreclk_ratios[] __initconst = {
+ { .id = 0, .name = "ddrclk", }
+};
+
+/*
+ * Orion 5182
+ */
+
+#define SAR_MV88F5182_TCLK_FREQ 8
+#define SAR_MV88F5182_TCLK_FREQ_MASK 0x3
+
+static u32 __init mv88f5182_get_tclk_freq(void __iomem *sar)
+{
+ u32 opt = (readl(sar) >> SAR_MV88F5182_TCLK_FREQ) &
+ SAR_MV88F5182_TCLK_FREQ_MASK;
+ if (opt == 1)
+ return 150000000;
+ else if (opt == 2)
+ return 166666667;
+ else
+ return 0;
+}
+
+#define SAR_MV88F5182_CPU_FREQ 4
+#define SAR_MV88F5182_CPU_FREQ_MASK 0xf
+
+static u32 __init mv88f5182_get_cpu_freq(void __iomem *sar)
+{
+ u32 opt = (readl(sar) >> SAR_MV88F5182_CPU_FREQ) &
+ SAR_MV88F5182_CPU_FREQ_MASK;
+ if (opt == 0)
+ return 333333333;
+ else if (opt == 1 || opt == 2)
+ return 400000000;
+ else if (opt == 3)
+ return 500000000;
+ else
+ return 0;
+}
+
+static void __init mv88f5182_get_clk_ratio(void __iomem *sar, int id,
+ int *mult, int *div)
+{
+ u32 opt = (readl(sar) >> SAR_MV88F5182_CPU_FREQ) &
+ SAR_MV88F5182_CPU_FREQ_MASK;
+ if (opt == 0 || opt == 1) {
+ *mult = 1;
+ *div = 2;
+ } else if (opt == 2 || opt == 3) {
+ *mult = 1;
+ *div = 3;
+ } else {
+ *mult = 0;
+ *div = 1;
+ }
+}
+
+static const struct coreclk_soc_desc mv88f5182_coreclks = {
+ .get_tclk_freq = mv88f5182_get_tclk_freq,
+ .get_cpu_freq = mv88f5182_get_cpu_freq,
+ .get_clk_ratio = mv88f5182_get_clk_ratio,
+ .ratios = orion_coreclk_ratios,
+ .num_ratios = ARRAY_SIZE(orion_coreclk_ratios),
+};
+
+static void __init mv88f5182_clk_init(struct device_node *np)
+{
+ return mvebu_coreclk_setup(np, &mv88f5182_coreclks);
+}
+
+CLK_OF_DECLARE(mv88f5182_clk, "marvell,mv88f5182-core-clock", mv88f5182_clk_init);
+
+/*
+ * Orion 5281
+ */
+
+static u32 __init mv88f5281_get_tclk_freq(void __iomem *sar)
+{
+ /* On 5281, tclk is always 166 Mhz */
+ return 166666667;
+}
+
+#define SAR_MV88F5281_CPU_FREQ 4
+#define SAR_MV88F5281_CPU_FREQ_MASK 0xf
+
+static u32 __init mv88f5281_get_cpu_freq(void __iomem *sar)
+{
+ u32 opt = (readl(sar) >> SAR_MV88F5281_CPU_FREQ) &
+ SAR_MV88F5281_CPU_FREQ_MASK;
+ if (opt == 1 || opt == 2)
+ return 400000000;
+ else if (opt == 3)
+ return 500000000;
+ else
+ return 0;
+}
+
+static void __init mv88f5281_get_clk_ratio(void __iomem *sar, int id,
+ int *mult, int *div)
+{
+ u32 opt = (readl(sar) >> SAR_MV88F5281_CPU_FREQ) &
+ SAR_MV88F5281_CPU_FREQ_MASK;
+ if (opt == 1) {
+ *mult = 1;
+ *div = 2;
+ } else if (opt == 2 || opt == 3) {
+ *mult = 1;
+ *div = 3;
+ } else {
+ *mult = 0;
+ *div = 1;
+ }
+}
+
+static const struct coreclk_soc_desc mv88f5281_coreclks = {
+ .get_tclk_freq = mv88f5281_get_tclk_freq,
+ .get_cpu_freq = mv88f5281_get_cpu_freq,
+ .get_clk_ratio = mv88f5281_get_clk_ratio,
+ .ratios = orion_coreclk_ratios,
+ .num_ratios = ARRAY_SIZE(orion_coreclk_ratios),
+};
+
+static void __init mv88f5281_clk_init(struct device_node *np)
+{
+ return mvebu_coreclk_setup(np, &mv88f5281_coreclks);
+}
+
+CLK_OF_DECLARE(mv88f5281_clk, "marvell,mv88f5281-core-clock", mv88f5281_clk_init);
+
+/*
+ * Orion 6183
+ */
+
+#define SAR_MV88F6183_TCLK_FREQ 9
+#define SAR_MV88F6183_TCLK_FREQ_MASK 0x1
+
+static u32 __init mv88f6183_get_tclk_freq(void __iomem *sar)
+{
+ u32 opt = (readl(sar) >> SAR_MV88F6183_TCLK_FREQ) &
+ SAR_MV88F6183_TCLK_FREQ_MASK;
+ if (opt == 0)
+ return 133333333;
+ else if (opt == 1)
+ return 166666667;
+ else
+ return 0;
+}
+
+#define SAR_MV88F6183_CPU_FREQ 1
+#define SAR_MV88F6183_CPU_FREQ_MASK 0x3f
+
+static u32 __init mv88f6183_get_cpu_freq(void __iomem *sar)
+{
+ u32 opt = (readl(sar) >> SAR_MV88F6183_CPU_FREQ) &
+ SAR_MV88F6183_CPU_FREQ_MASK;
+ if (opt == 9)
+ return 333333333;
+ else if (opt == 17)
+ return 400000000;
+ else
+ return 0;
+}
+
+static void __init mv88f6183_get_clk_ratio(void __iomem *sar, int id,
+ int *mult, int *div)
+{
+ u32 opt = (readl(sar) >> SAR_MV88F6183_CPU_FREQ) &
+ SAR_MV88F6183_CPU_FREQ_MASK;
+ if (opt == 9 || opt == 17) {
+ *mult = 1;
+ *div = 2;
+ } else {
+ *mult = 0;
+ *div = 1;
+ }
+}
+
+static const struct coreclk_soc_desc mv88f6183_coreclks = {
+ .get_tclk_freq = mv88f6183_get_tclk_freq,
+ .get_cpu_freq = mv88f6183_get_cpu_freq,
+ .get_clk_ratio = mv88f6183_get_clk_ratio,
+ .ratios = orion_coreclk_ratios,
+ .num_ratios = ARRAY_SIZE(orion_coreclk_ratios),
+};
+
+
+static void __init mv88f6183_clk_init(struct device_node *np)
+{
+ return mvebu_coreclk_setup(np, &mv88f6183_coreclks);
+}
+
+CLK_OF_DECLARE(mv88f6183_clk, "marvell,mv88f6183-core-clock", mv88f6183_clk_init);
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 995bcfa..7f696b7 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -13,10 +13,10 @@
i2c, USB, SD/eMMC, etc.
config MSM_GCC_8960
- tristate "MSM8960 Global Clock Controller"
+ tristate "APQ8064/MSM8960 Global Clock Controller"
depends on COMMON_CLK_QCOM
help
- Support for the global clock controller on msm8960 devices.
+ Support for the global clock controller on apq8064/msm8960 devices.
Say Y if you want to use peripheral devices such as UART, SPI,
i2c, USB, SD/eMMC, SATA, PCIe, etc.
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index f60db2e..689e05b 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -1,5 +1,6 @@
obj-$(CONFIG_COMMON_CLK_QCOM) += clk-qcom.o
+clk-qcom-y += common.o
clk-qcom-y += clk-regmap.o
clk-qcom-y += clk-pll.o
clk-qcom-y += clk-rcg.o
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
new file mode 100644
index 0000000..86b45fb
--- /dev/null
+++ b/drivers/clk/qcom/common.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/export.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/clk-provider.h>
+#include <linux/reset-controller.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "reset.h"
+
+struct qcom_cc {
+ struct qcom_reset_controller reset;
+ struct clk_onecell_data data;
+ struct clk *clks[];
+};
+
+int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc)
+{
+ void __iomem *base;
+ struct resource *res;
+ int i, ret;
+ struct device *dev = &pdev->dev;
+ struct clk *clk;
+ struct clk_onecell_data *data;
+ struct clk **clks;
+ struct regmap *regmap;
+ struct qcom_reset_controller *reset;
+ struct qcom_cc *cc;
+ size_t num_clks = desc->num_clks;
+ struct clk_regmap **rclks = desc->clks;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ regmap = devm_regmap_init_mmio(dev, base, desc->config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks,
+ GFP_KERNEL);
+ if (!cc)
+ return -ENOMEM;
+
+ clks = cc->clks;
+ data = &cc->data;
+ data->clks = clks;
+ data->clk_num = num_clks;
+
+ for (i = 0; i < num_clks; i++) {
+ if (!rclks[i])
+ continue;
+ clk = devm_clk_register_regmap(dev, rclks[i]);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ clks[i] = clk;
+ }
+
+ ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
+ if (ret)
+ return ret;
+
+ reset = &cc->reset;
+ reset->rcdev.of_node = dev->of_node;
+ reset->rcdev.ops = &qcom_reset_ops;
+ reset->rcdev.owner = dev->driver->owner;
+ reset->rcdev.nr_resets = desc->num_resets;
+ reset->regmap = regmap;
+ reset->reset_map = desc->resets;
+ platform_set_drvdata(pdev, &reset->rcdev);
+
+ ret = reset_controller_register(&reset->rcdev);
+ if (ret)
+ of_clk_del_provider(dev->of_node);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_cc_probe);
+
+void qcom_cc_remove(struct platform_device *pdev)
+{
+ of_clk_del_provider(pdev->dev.of_node);
+ reset_controller_unregister(platform_get_drvdata(pdev));
+}
+EXPORT_SYMBOL_GPL(qcom_cc_remove);
diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
new file mode 100644
index 0000000..2c3cfc8
--- /dev/null
+++ b/drivers/clk/qcom/common.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __QCOM_CLK_COMMON_H__
+#define __QCOM_CLK_COMMON_H__
+
+struct platform_device;
+struct regmap_config;
+struct clk_regmap;
+struct qcom_reset_map;
+
+struct qcom_cc_desc {
+ const struct regmap_config *config;
+ struct clk_regmap **clks;
+ size_t num_clks;
+ const struct qcom_reset_map *resets;
+ size_t num_resets;
+};
+
+extern int qcom_cc_probe(struct platform_device *pdev,
+ const struct qcom_cc_desc *desc);
+
+extern void qcom_cc_remove(struct platform_device *pdev);
+
+#endif
diff --git a/drivers/clk/qcom/gcc-msm8660.c b/drivers/clk/qcom/gcc-msm8660.c
index bc0b7f1..44bc6fa 100644
--- a/drivers/clk/qcom/gcc-msm8660.c
+++ b/drivers/clk/qcom/gcc-msm8660.c
@@ -25,6 +25,7 @@
#include <dt-bindings/clock/qcom,gcc-msm8660.h>
#include <dt-bindings/reset/qcom,gcc-msm8660.h>
+#include "common.h"
#include "clk-regmap.h"
#include "clk-pll.h"
#include "clk-rcg.h"
@@ -2701,94 +2702,28 @@
.fast_io = true,
};
+static const struct qcom_cc_desc gcc_msm8660_desc = {
+ .config = &gcc_msm8660_regmap_config,
+ .clks = gcc_msm8660_clks,
+ .num_clks = ARRAY_SIZE(gcc_msm8660_clks),
+ .resets = gcc_msm8660_resets,
+ .num_resets = ARRAY_SIZE(gcc_msm8660_resets),
+};
+
static const struct of_device_id gcc_msm8660_match_table[] = {
{ .compatible = "qcom,gcc-msm8660" },
{ }
};
MODULE_DEVICE_TABLE(of, gcc_msm8660_match_table);
-struct qcom_cc {
- struct qcom_reset_controller reset;
- struct clk_onecell_data data;
- struct clk *clks[];
-};
-
static int gcc_msm8660_probe(struct platform_device *pdev)
{
- void __iomem *base;
- struct resource *res;
- int i, ret;
- struct device *dev = &pdev->dev;
- struct clk *clk;
- struct clk_onecell_data *data;
- struct clk **clks;
- struct regmap *regmap;
- size_t num_clks;
- struct qcom_reset_controller *reset;
- struct qcom_cc *cc;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- regmap = devm_regmap_init_mmio(dev, base, &gcc_msm8660_regmap_config);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- num_clks = ARRAY_SIZE(gcc_msm8660_clks);
- cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks,
- GFP_KERNEL);
- if (!cc)
- return -ENOMEM;
-
- clks = cc->clks;
- data = &cc->data;
- data->clks = clks;
- data->clk_num = num_clks;
-
- /* Temporary until RPM clocks supported */
- clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
-
- clk = clk_register_fixed_rate(dev, "pxo", NULL, CLK_IS_ROOT, 27000000);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
-
- for (i = 0; i < num_clks; i++) {
- if (!gcc_msm8660_clks[i])
- continue;
- clk = devm_clk_register_regmap(dev, gcc_msm8660_clks[i]);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
- clks[i] = clk;
- }
-
- ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
- if (ret)
- return ret;
-
- reset = &cc->reset;
- reset->rcdev.of_node = dev->of_node;
- reset->rcdev.ops = &qcom_reset_ops,
- reset->rcdev.owner = THIS_MODULE,
- reset->rcdev.nr_resets = ARRAY_SIZE(gcc_msm8660_resets),
- reset->regmap = regmap;
- reset->reset_map = gcc_msm8660_resets,
- platform_set_drvdata(pdev, &reset->rcdev);
-
- ret = reset_controller_register(&reset->rcdev);
- if (ret)
- of_clk_del_provider(dev->of_node);
-
- return ret;
+ return qcom_cc_probe(pdev, &gcc_msm8660_desc);
}
static int gcc_msm8660_remove(struct platform_device *pdev)
{
- of_clk_del_provider(pdev->dev.of_node);
- reset_controller_unregister(platform_get_drvdata(pdev));
+ qcom_cc_remove(pdev);
return 0;
}
diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c
index fd446ab..f4ffd91 100644
--- a/drivers/clk/qcom/gcc-msm8960.c
+++ b/drivers/clk/qcom/gcc-msm8960.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -25,6 +25,7 @@
#include <dt-bindings/clock/qcom,gcc-msm8960.h>
#include <dt-bindings/reset/qcom,gcc-msm8960.h>
+#include "common.h"
#include "clk-regmap.h"
#include "clk-pll.h"
#include "clk-rcg.h"
@@ -2809,7 +2810,7 @@
[PPSS_PROC_RESET] = { 0x2594, 1 },
[PPSS_RESET] = { 0x2594},
[DMA_BAM_RESET] = { 0x25c0, 7 },
- [SIC_TIC_RESET] = { 0x2600, 7 },
+ [SPS_TIC_H_RESET] = { 0x2600, 7 },
[SLIMBUS_H_RESET] = { 0x2620, 7 },
[SFAB_CFPB_M_RESET] = { 0x2680, 7 },
[SFAB_CFPB_S_RESET] = { 0x26c0, 7 },
@@ -2822,7 +2823,7 @@
[SFAB_SFPB_M_RESET] = { 0x2780, 7 },
[SFAB_SFPB_S_RESET] = { 0x27a0, 7 },
[RPM_PROC_RESET] = { 0x27c0, 7 },
- [PMIC_SSBI2_RESET] = { 0x270c, 12 },
+ [PMIC_SSBI2_RESET] = { 0x280c, 12 },
[SDC1_RESET] = { 0x2830 },
[SDC2_RESET] = { 0x2850 },
[SDC3_RESET] = { 0x2870 },
@@ -2867,6 +2868,16 @@
[RIVA_RESET] = { 0x35e0 },
};
+static struct clk_regmap *gcc_apq8064_clks[] = {
+ [PLL8] = &pll8.clkr,
+ [PLL8_VOTE] = &pll8_vote,
+ [GSBI7_UART_SRC] = &gsbi7_uart_src.clkr,
+ [GSBI7_UART_CLK] = &gsbi7_uart_clk.clkr,
+ [GSBI7_QUP_SRC] = &gsbi7_qup_src.clkr,
+ [GSBI7_QUP_CLK] = &gsbi7_qup_clk.clkr,
+ [GSBI7_H_CLK] = &gsbi7_h_clk.clkr,
+};
+
static const struct regmap_config gcc_msm8960_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -2875,51 +2886,38 @@
.fast_io = true,
};
+static const struct qcom_cc_desc gcc_msm8960_desc = {
+ .config = &gcc_msm8960_regmap_config,
+ .clks = gcc_msm8960_clks,
+ .num_clks = ARRAY_SIZE(gcc_msm8960_clks),
+ .resets = gcc_msm8960_resets,
+ .num_resets = ARRAY_SIZE(gcc_msm8960_resets),
+};
+
+static const struct qcom_cc_desc gcc_apq8064_desc = {
+ .config = &gcc_msm8960_regmap_config,
+ .clks = gcc_apq8064_clks,
+ .num_clks = ARRAY_SIZE(gcc_apq8064_clks),
+ .resets = gcc_msm8960_resets,
+ .num_resets = ARRAY_SIZE(gcc_msm8960_resets),
+};
+
static const struct of_device_id gcc_msm8960_match_table[] = {
- { .compatible = "qcom,gcc-msm8960" },
+ { .compatible = "qcom,gcc-msm8960", .data = &gcc_msm8960_desc },
+ { .compatible = "qcom,gcc-apq8064", .data = &gcc_apq8064_desc },
{ }
};
MODULE_DEVICE_TABLE(of, gcc_msm8960_match_table);
-struct qcom_cc {
- struct qcom_reset_controller reset;
- struct clk_onecell_data data;
- struct clk *clks[];
-};
-
static int gcc_msm8960_probe(struct platform_device *pdev)
{
- void __iomem *base;
- struct resource *res;
- int i, ret;
- struct device *dev = &pdev->dev;
struct clk *clk;
- struct clk_onecell_data *data;
- struct clk **clks;
- struct regmap *regmap;
- size_t num_clks;
- struct qcom_reset_controller *reset;
- struct qcom_cc *cc;
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *match;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- regmap = devm_regmap_init_mmio(dev, base, &gcc_msm8960_regmap_config);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- num_clks = ARRAY_SIZE(gcc_msm8960_clks);
- cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks,
- GFP_KERNEL);
- if (!cc)
- return -ENOMEM;
-
- clks = cc->clks;
- data = &cc->data;
- data->clks = clks;
- data->clk_num = num_clks;
+ match = of_match_device(gcc_msm8960_match_table, &pdev->dev);
+ if (!match)
+ return -EINVAL;
/* Temporary until RPM clocks supported */
clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000);
@@ -2930,39 +2928,12 @@
if (IS_ERR(clk))
return PTR_ERR(clk);
- for (i = 0; i < num_clks; i++) {
- if (!gcc_msm8960_clks[i])
- continue;
- clk = devm_clk_register_regmap(dev, gcc_msm8960_clks[i]);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
- clks[i] = clk;
- }
-
- ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
- if (ret)
- return ret;
-
- reset = &cc->reset;
- reset->rcdev.of_node = dev->of_node;
- reset->rcdev.ops = &qcom_reset_ops,
- reset->rcdev.owner = THIS_MODULE,
- reset->rcdev.nr_resets = ARRAY_SIZE(gcc_msm8960_resets),
- reset->regmap = regmap;
- reset->reset_map = gcc_msm8960_resets,
- platform_set_drvdata(pdev, &reset->rcdev);
-
- ret = reset_controller_register(&reset->rcdev);
- if (ret)
- of_clk_del_provider(dev->of_node);
-
- return ret;
+ return qcom_cc_probe(pdev, match->data);
}
static int gcc_msm8960_remove(struct platform_device *pdev)
{
- of_clk_del_provider(pdev->dev.of_node);
- reset_controller_unregister(platform_get_drvdata(pdev));
+ qcom_cc_remove(pdev);
return 0;
}
diff --git a/drivers/clk/qcom/gcc-msm8974.c b/drivers/clk/qcom/gcc-msm8974.c
index 51d457e..0d1edc1 100644
--- a/drivers/clk/qcom/gcc-msm8974.c
+++ b/drivers/clk/qcom/gcc-msm8974.c
@@ -25,6 +25,7 @@
#include <dt-bindings/clock/qcom,gcc-msm8974.h>
#include <dt-bindings/reset/qcom,gcc-msm8974.h>
+#include "common.h"
#include "clk-regmap.h"
#include "clk-pll.h"
#include "clk-rcg.h"
@@ -2574,51 +2575,24 @@
.fast_io = true,
};
+static const struct qcom_cc_desc gcc_msm8974_desc = {
+ .config = &gcc_msm8974_regmap_config,
+ .clks = gcc_msm8974_clocks,
+ .num_clks = ARRAY_SIZE(gcc_msm8974_clocks),
+ .resets = gcc_msm8974_resets,
+ .num_resets = ARRAY_SIZE(gcc_msm8974_resets),
+};
+
static const struct of_device_id gcc_msm8974_match_table[] = {
{ .compatible = "qcom,gcc-msm8974" },
{ }
};
MODULE_DEVICE_TABLE(of, gcc_msm8974_match_table);
-struct qcom_cc {
- struct qcom_reset_controller reset;
- struct clk_onecell_data data;
- struct clk *clks[];
-};
-
static int gcc_msm8974_probe(struct platform_device *pdev)
{
- void __iomem *base;
- struct resource *res;
- int i, ret;
- struct device *dev = &pdev->dev;
struct clk *clk;
- struct clk_onecell_data *data;
- struct clk **clks;
- struct regmap *regmap;
- size_t num_clks;
- struct qcom_reset_controller *reset;
- struct qcom_cc *cc;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- regmap = devm_regmap_init_mmio(dev, base, &gcc_msm8974_regmap_config);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- num_clks = ARRAY_SIZE(gcc_msm8974_clocks);
- cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks,
- GFP_KERNEL);
- if (!cc)
- return -ENOMEM;
-
- clks = cc->clks;
- data = &cc->data;
- data->clks = clks;
- data->clk_num = num_clks;
+ struct device *dev = &pdev->dev;
/* Temporary until RPM clocks supported */
clk = clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 19200000);
@@ -2631,39 +2605,12 @@
if (IS_ERR(clk))
return PTR_ERR(clk);
- for (i = 0; i < num_clks; i++) {
- if (!gcc_msm8974_clocks[i])
- continue;
- clk = devm_clk_register_regmap(dev, gcc_msm8974_clocks[i]);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
- clks[i] = clk;
- }
-
- ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
- if (ret)
- return ret;
-
- reset = &cc->reset;
- reset->rcdev.of_node = dev->of_node;
- reset->rcdev.ops = &qcom_reset_ops,
- reset->rcdev.owner = THIS_MODULE,
- reset->rcdev.nr_resets = ARRAY_SIZE(gcc_msm8974_resets),
- reset->regmap = regmap;
- reset->reset_map = gcc_msm8974_resets,
- platform_set_drvdata(pdev, &reset->rcdev);
-
- ret = reset_controller_register(&reset->rcdev);
- if (ret)
- of_clk_del_provider(dev->of_node);
-
- return ret;
+ return qcom_cc_probe(pdev, &gcc_msm8974_desc);
}
static int gcc_msm8974_remove(struct platform_device *pdev)
{
- of_clk_del_provider(pdev->dev.of_node);
- reset_controller_unregister(platform_get_drvdata(pdev));
+ qcom_cc_remove(pdev);
return 0;
}
diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c
index f9b59c7..12f3c0b 100644
--- a/drivers/clk/qcom/mmcc-msm8960.c
+++ b/drivers/clk/qcom/mmcc-msm8960.c
@@ -26,6 +26,7 @@
#include <dt-bindings/clock/qcom,mmcc-msm8960.h>
#include <dt-bindings/reset/qcom,mmcc-msm8960.h>
+#include "common.h"
#include "clk-regmap.h"
#include "clk-pll.h"
#include "clk-rcg.h"
@@ -2222,85 +2223,28 @@
.fast_io = true,
};
+static const struct qcom_cc_desc mmcc_msm8960_desc = {
+ .config = &mmcc_msm8960_regmap_config,
+ .clks = mmcc_msm8960_clks,
+ .num_clks = ARRAY_SIZE(mmcc_msm8960_clks),
+ .resets = mmcc_msm8960_resets,
+ .num_resets = ARRAY_SIZE(mmcc_msm8960_resets),
+};
+
static const struct of_device_id mmcc_msm8960_match_table[] = {
{ .compatible = "qcom,mmcc-msm8960" },
{ }
};
MODULE_DEVICE_TABLE(of, mmcc_msm8960_match_table);
-struct qcom_cc {
- struct qcom_reset_controller reset;
- struct clk_onecell_data data;
- struct clk *clks[];
-};
-
static int mmcc_msm8960_probe(struct platform_device *pdev)
{
- void __iomem *base;
- struct resource *res;
- int i, ret;
- struct device *dev = &pdev->dev;
- struct clk *clk;
- struct clk_onecell_data *data;
- struct clk **clks;
- struct regmap *regmap;
- size_t num_clks;
- struct qcom_reset_controller *reset;
- struct qcom_cc *cc;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- regmap = devm_regmap_init_mmio(dev, base, &mmcc_msm8960_regmap_config);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- num_clks = ARRAY_SIZE(mmcc_msm8960_clks);
- cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks,
- GFP_KERNEL);
- if (!cc)
- return -ENOMEM;
-
- clks = cc->clks;
- data = &cc->data;
- data->clks = clks;
- data->clk_num = num_clks;
-
- for (i = 0; i < num_clks; i++) {
- if (!mmcc_msm8960_clks[i])
- continue;
- clk = devm_clk_register_regmap(dev, mmcc_msm8960_clks[i]);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
- clks[i] = clk;
- }
-
- ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
- if (ret)
- return ret;
-
- reset = &cc->reset;
- reset->rcdev.of_node = dev->of_node;
- reset->rcdev.ops = &qcom_reset_ops,
- reset->rcdev.owner = THIS_MODULE,
- reset->rcdev.nr_resets = ARRAY_SIZE(mmcc_msm8960_resets),
- reset->regmap = regmap;
- reset->reset_map = mmcc_msm8960_resets,
- platform_set_drvdata(pdev, &reset->rcdev);
-
- ret = reset_controller_register(&reset->rcdev);
- if (ret)
- of_clk_del_provider(dev->of_node);
-
- return ret;
+ return qcom_cc_probe(pdev, &mmcc_msm8960_desc);
}
static int mmcc_msm8960_remove(struct platform_device *pdev)
{
- of_clk_del_provider(pdev->dev.of_node);
- reset_controller_unregister(platform_get_drvdata(pdev));
+ qcom_cc_remove(pdev);
return 0;
}
diff --git a/drivers/clk/qcom/mmcc-msm8974.c b/drivers/clk/qcom/mmcc-msm8974.c
index c957745..60b7c24 100644
--- a/drivers/clk/qcom/mmcc-msm8974.c
+++ b/drivers/clk/qcom/mmcc-msm8974.c
@@ -25,6 +25,7 @@
#include <dt-bindings/clock/qcom,mmcc-msm8974.h>
#include <dt-bindings/reset/qcom,mmcc-msm8974.h>
+#include "common.h"
#include "clk-regmap.h"
#include "clk-pll.h"
#include "clk-rcg.h"
@@ -2524,88 +2525,39 @@
.fast_io = true,
};
+static const struct qcom_cc_desc mmcc_msm8974_desc = {
+ .config = &mmcc_msm8974_regmap_config,
+ .clks = mmcc_msm8974_clocks,
+ .num_clks = ARRAY_SIZE(mmcc_msm8974_clocks),
+ .resets = mmcc_msm8974_resets,
+ .num_resets = ARRAY_SIZE(mmcc_msm8974_resets),
+};
+
static const struct of_device_id mmcc_msm8974_match_table[] = {
{ .compatible = "qcom,mmcc-msm8974" },
{ }
};
MODULE_DEVICE_TABLE(of, mmcc_msm8974_match_table);
-struct qcom_cc {
- struct qcom_reset_controller reset;
- struct clk_onecell_data data;
- struct clk *clks[];
-};
-
static int mmcc_msm8974_probe(struct platform_device *pdev)
{
- void __iomem *base;
- struct resource *res;
- int i, ret;
- struct device *dev = &pdev->dev;
- struct clk *clk;
- struct clk_onecell_data *data;
- struct clk **clks;
+ int ret;
struct regmap *regmap;
- size_t num_clks;
- struct qcom_reset_controller *reset;
- struct qcom_cc *cc;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- regmap = devm_regmap_init_mmio(dev, base, &mmcc_msm8974_regmap_config);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- num_clks = ARRAY_SIZE(mmcc_msm8974_clocks);
- cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks,
- GFP_KERNEL);
- if (!cc)
- return -ENOMEM;
-
- clks = cc->clks;
- data = &cc->data;
- data->clks = clks;
- data->clk_num = num_clks;
-
- clk_pll_configure_sr_hpm_lp(&mmpll1, regmap, &mmpll1_config, true);
- clk_pll_configure_sr_hpm_lp(&mmpll3, regmap, &mmpll3_config, false);
-
- for (i = 0; i < num_clks; i++) {
- if (!mmcc_msm8974_clocks[i])
- continue;
- clk = devm_clk_register_regmap(dev, mmcc_msm8974_clocks[i]);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
- clks[i] = clk;
- }
-
- ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
+ ret = qcom_cc_probe(pdev, &mmcc_msm8974_desc);
if (ret)
return ret;
- reset = &cc->reset;
- reset->rcdev.of_node = dev->of_node;
- reset->rcdev.ops = &qcom_reset_ops,
- reset->rcdev.owner = THIS_MODULE,
- reset->rcdev.nr_resets = ARRAY_SIZE(mmcc_msm8974_resets),
- reset->regmap = regmap;
- reset->reset_map = mmcc_msm8974_resets,
- platform_set_drvdata(pdev, &reset->rcdev);
+ regmap = dev_get_regmap(&pdev->dev, NULL);
+ clk_pll_configure_sr_hpm_lp(&mmpll1, regmap, &mmpll1_config, true);
+ clk_pll_configure_sr_hpm_lp(&mmpll3, regmap, &mmpll3_config, false);
- ret = reset_controller_register(&reset->rcdev);
- if (ret)
- of_clk_del_provider(dev->of_node);
-
- return ret;
+ return 0;
}
static int mmcc_msm8974_remove(struct platform_device *pdev)
{
- of_clk_del_provider(pdev->dev.of_node);
- reset_controller_unregister(platform_get_drvdata(pdev));
+ qcom_cc_remove(pdev);
return 0;
}
diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile
index 5404cb9..bdf342d 100644
--- a/drivers/clk/shmobile/Makefile
+++ b/drivers/clk/shmobile/Makefile
@@ -1,5 +1,6 @@
obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o
obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o
+obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o
obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o
diff --git a/drivers/clk/shmobile/clk-r8a7779.c b/drivers/clk/shmobile/clk-r8a7779.c
new file mode 100644
index 0000000..652ecac
--- /dev/null
+++ b/drivers/clk/shmobile/clk-r8a7779.c
@@ -0,0 +1,180 @@
+/*
+ * r8a7779 Core CPG Clocks
+ *
+ * Copyright (C) 2013, 2014 Horms Solutions Ltd.
+ *
+ * Contact: Simon Horman <horms@verge.net.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/shmobile.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/spinlock.h>
+
+#include <dt-bindings/clock/r8a7779-clock.h>
+
+#define CPG_NUM_CLOCKS (R8A7779_CLK_OUT + 1)
+
+struct r8a7779_cpg {
+ struct clk_onecell_data data;
+ spinlock_t lock;
+ void __iomem *reg;
+};
+
+/* -----------------------------------------------------------------------------
+ * CPG Clock Data
+ */
+
+/*
+ * MD1 = 1 MD1 = 0
+ * (PLLA = 1500) (PLLA = 1600)
+ * (MHz) (MHz)
+ *------------------------------------------------+--------------------
+ * clkz 1000 (2/3) 800 (1/2)
+ * clkzs 250 (1/6) 200 (1/8)
+ * clki 750 (1/2) 800 (1/2)
+ * clks 250 (1/6) 200 (1/8)
+ * clks1 125 (1/12) 100 (1/16)
+ * clks3 187.5 (1/8) 200 (1/8)
+ * clks4 93.7 (1/16) 100 (1/16)
+ * clkp 62.5 (1/24) 50 (1/32)
+ * clkg 62.5 (1/24) 66.6 (1/24)
+ * clkb, CLKOUT
+ * (MD2 = 0) 62.5 (1/24) 66.6 (1/24)
+ * (MD2 = 1) 41.6 (1/36) 50 (1/32)
+ */
+
+#define CPG_CLK_CONFIG_INDEX(md) (((md) & (BIT(2)|BIT(1))) >> 1)
+
+struct cpg_clk_config {
+ unsigned int z_mult;
+ unsigned int z_div;
+ unsigned int zs_and_s_div;
+ unsigned int s1_div;
+ unsigned int p_div;
+ unsigned int b_and_out_div;
+};
+
+static const struct cpg_clk_config cpg_clk_configs[4] __initconst = {
+ { 1, 2, 8, 16, 32, 24 },
+ { 2, 3, 6, 12, 24, 24 },
+ { 1, 2, 8, 16, 32, 32 },
+ { 2, 3, 6, 12, 24, 36 },
+};
+
+/*
+ * MD PLLA Ratio
+ * 12 11
+ *------------------------
+ * 0 0 x42
+ * 0 1 x48
+ * 1 0 x56
+ * 1 1 x64
+ */
+
+#define CPG_PLLA_MULT_INDEX(md) (((md) & (BIT(12)|BIT(11))) >> 11)
+
+static const unsigned int cpg_plla_mult[4] __initconst = { 42, 48, 56, 64 };
+
+/* -----------------------------------------------------------------------------
+ * Initialization
+ */
+
+static u32 cpg_mode __initdata;
+
+static struct clk * __init
+r8a7779_cpg_register_clock(struct device_node *np, struct r8a7779_cpg *cpg,
+ const struct cpg_clk_config *config,
+ unsigned int plla_mult, const char *name)
+{
+ const char *parent_name = "plla";
+ unsigned int mult = 1;
+ unsigned int div = 1;
+
+ if (!strcmp(name, "plla")) {
+ parent_name = of_clk_get_parent_name(np, 0);
+ mult = plla_mult;
+ } else if (!strcmp(name, "z")) {
+ div = config->z_div;
+ mult = config->z_mult;
+ } else if (!strcmp(name, "zs") || !strcmp(name, "s")) {
+ div = config->zs_and_s_div;
+ } else if (!strcmp(name, "s1")) {
+ div = config->s1_div;
+ } else if (!strcmp(name, "p")) {
+ div = config->p_div;
+ } else if (!strcmp(name, "b") || !strcmp(name, "out")) {
+ div = config->b_and_out_div;
+ } else {
+ return ERR_PTR(-EINVAL);
+ }
+
+ return clk_register_fixed_factor(NULL, name, parent_name, 0, mult, div);
+}
+
+static void __init r8a7779_cpg_clocks_init(struct device_node *np)
+{
+ const struct cpg_clk_config *config;
+ struct r8a7779_cpg *cpg;
+ struct clk **clks;
+ unsigned int i, plla_mult;
+ int num_clks;
+
+ num_clks = of_property_count_strings(np, "clock-output-names");
+ if (num_clks < 0) {
+ pr_err("%s: failed to count clocks\n", __func__);
+ return;
+ }
+
+ cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
+ clks = kzalloc(CPG_NUM_CLOCKS * sizeof(*clks), GFP_KERNEL);
+ if (cpg == NULL || clks == NULL) {
+ /* We're leaking memory on purpose, there's no point in cleaning
+ * up as the system won't boot anyway.
+ */
+ return;
+ }
+
+ spin_lock_init(&cpg->lock);
+
+ cpg->data.clks = clks;
+ cpg->data.clk_num = num_clks;
+
+ config = &cpg_clk_configs[CPG_CLK_CONFIG_INDEX(cpg_mode)];
+ plla_mult = cpg_plla_mult[CPG_PLLA_MULT_INDEX(cpg_mode)];
+
+ 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 = r8a7779_cpg_register_clock(np, cpg, config,
+ plla_mult, 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(r8a7779_cpg_clks, "renesas,r8a7779-cpg-clocks",
+ r8a7779_cpg_clocks_init);
+
+void __init r8a7779_clocks_init(u32 mode)
+{
+ cpg_mode = mode;
+
+ of_clk_init(NULL);
+}
diff --git a/drivers/clk/socfpga/clk-gate.c b/drivers/clk/socfpga/clk-gate.c
index 501d513..dd3a78c 100644
--- a/drivers/clk/socfpga/clk-gate.c
+++ b/drivers/clk/socfpga/clk-gate.c
@@ -32,7 +32,6 @@
#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)
diff --git a/drivers/clk/socfpga/clk-periph.c b/drivers/clk/socfpga/clk-periph.c
index 81623a3..46531c3 100644
--- a/drivers/clk/socfpga/clk-periph.c
+++ b/drivers/clk/socfpga/clk-periph.c
@@ -29,12 +29,18 @@
unsigned long parent_rate)
{
struct socfpga_periph_clk *socfpgaclk = to_socfpga_periph_clk(hwclk);
- u32 div;
+ u32 div, val;
- if (socfpgaclk->fixed_div)
+ if (socfpgaclk->fixed_div) {
div = socfpgaclk->fixed_div;
- else
+ } else {
+ if (socfpgaclk->div_reg) {
+ val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
+ val &= div_mask(socfpgaclk->width);
+ parent_rate /= (val + 1);
+ }
div = ((readl(socfpgaclk->hw.reg) & 0x1ff) + 1);
+ }
return parent_rate / div;
}
@@ -54,6 +60,7 @@
struct clk_init_data init;
int rc;
u32 fixed_div;
+ u32 div_reg[3];
of_property_read_u32(node, "reg", ®);
@@ -63,6 +70,15 @@
periph_clk->hw.reg = clk_mgr_base_addr + reg;
+ rc = of_property_read_u32_array(node, "div-reg", div_reg, 3);
+ if (!rc) {
+ periph_clk->div_reg = clk_mgr_base_addr + div_reg[0];
+ periph_clk->shift = div_reg[1];
+ periph_clk->width = div_reg[2];
+ } else {
+ periph_clk->div_reg = 0;
+ }
+
rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
if (rc)
periph_clk->fixed_div = 0;
diff --git a/drivers/clk/socfpga/clk.h b/drivers/clk/socfpga/clk.h
index d2e5401..d291f60 100644
--- a/drivers/clk/socfpga/clk.h
+++ b/drivers/clk/socfpga/clk.h
@@ -27,6 +27,7 @@
#define CLKMGR_PERPLL_SRC 0xAC
#define SOCFPGA_MAX_PARENTS 3
+#define div_mask(width) ((1 << (width)) - 1)
extern void __iomem *clk_mgr_base_addr;
@@ -52,6 +53,9 @@
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 */
};
#endif /* SOCFPGA_CLK_H */
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c
index 9e232644..3806d97 100644
--- a/drivers/clk/sunxi/clk-factors.c
+++ b/drivers/clk/sunxi/clk-factors.c
@@ -77,6 +77,41 @@
return rate;
}
+static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *best_parent_rate,
+ struct clk **best_parent_p)
+{
+ struct clk *clk = hw->clk, *parent, *best_parent = NULL;
+ int i, num_parents;
+ unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
+
+ /* find the parent that can help provide the fastest rate <= rate */
+ num_parents = __clk_get_num_parents(clk);
+ for (i = 0; i < num_parents; i++) {
+ parent = clk_get_parent_by_index(clk, i);
+ if (!parent)
+ continue;
+ if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT)
+ parent_rate = __clk_round_rate(parent, rate);
+ else
+ parent_rate = __clk_get_rate(parent);
+
+ child_rate = clk_factors_round_rate(hw, rate, &parent_rate);
+
+ if (child_rate <= rate && child_rate > best_child_rate) {
+ best_parent = parent;
+ best = parent_rate;
+ best_child_rate = child_rate;
+ }
+ }
+
+ if (best_parent)
+ *best_parent_p = best_parent;
+ *best_parent_rate = best;
+
+ return best_child_rate;
+}
+
static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
@@ -113,6 +148,7 @@
}
const struct clk_ops clk_factors_ops = {
+ .determine_rate = clk_factors_determine_rate,
.recalc_rate = clk_factors_recalc_rate,
.round_rate = clk_factors_round_rate,
.set_rate = clk_factors_set_rate,
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index bd7dc73..4cc2b2a 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -507,6 +507,43 @@
/**
+ * clk_sunxi_mmc_phase_control() - configures MMC clock phase control
+ */
+
+void clk_sunxi_mmc_phase_control(struct clk *clk, u8 sample, u8 output)
+{
+ #define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw)
+ #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw)
+
+ struct clk_hw *hw = __clk_get_hw(clk);
+ struct clk_composite *composite = to_clk_composite(hw);
+ struct clk_hw *rate_hw = composite->rate_hw;
+ struct clk_factors *factors = to_clk_factors(rate_hw);
+ unsigned long flags = 0;
+ u32 reg;
+
+ if (factors->lock)
+ spin_lock_irqsave(factors->lock, flags);
+
+ reg = readl(factors->reg);
+
+ /* set sample clock phase control */
+ reg &= ~(0x7 << 20);
+ reg |= ((sample & 0x7) << 20);
+
+ /* set output clock phase control */
+ reg &= ~(0x7 << 8);
+ reg |= ((output & 0x7) << 8);
+
+ writel(reg, factors->reg);
+
+ if (factors->lock)
+ spin_unlock_irqrestore(factors->lock, flags);
+}
+EXPORT_SYMBOL(clk_sunxi_mmc_phase_control);
+
+
+/**
* sunxi_factors_clk_setup() - Setup function for factor clocks
*/
diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c
index a820b0cf..7f3868a 100644
--- a/drivers/clk/versatile/clk-icst.c
+++ b/drivers/clk/versatile/clk-icst.c
@@ -160,3 +160,4 @@
return clk;
}
+EXPORT_SYMBOL_GPL(icst_clk_register);
diff --git a/drivers/clk/versatile/clk-impd1.c b/drivers/clk/versatile/clk-impd1.c
index 31b44f0..264d8d5 100644
--- a/drivers/clk/versatile/clk-impd1.c
+++ b/drivers/clk/versatile/clk-impd1.c
@@ -133,6 +133,7 @@
for (i = 0; i < ARRAY_SIZE(imc->clks); i++)
clkdev_add(imc->clks[i]);
}
+EXPORT_SYMBOL_GPL(integrator_impd1_clk_init);
void integrator_impd1_clk_exit(unsigned int id)
{
@@ -155,3 +156,4 @@
kfree(imc->vco2name);
kfree(imc->vco1name);
}
+EXPORT_SYMBOL_GPL(integrator_impd1_clk_exit);
diff --git a/include/dt-bindings/clock/bcm21664.h b/include/dt-bindings/clock/bcm21664.h
new file mode 100644
index 0000000..5a7f0e4
--- /dev/null
+++ b/include/dt-bindings/clock/bcm21664.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2013 Broadcom Corporation
+ * Copyright 2013 Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CLOCK_BCM21664_H
+#define _CLOCK_BCM21664_H
+
+/*
+ * This file defines the values used to specify clocks provided by
+ * the clock control units (CCUs) on Broadcom BCM21664 family SoCs.
+ */
+
+/* bcm21664 CCU device tree "compatible" strings */
+#define BCM21664_DT_ROOT_CCU_COMPAT "brcm,bcm21664-root-ccu"
+#define BCM21664_DT_AON_CCU_COMPAT "brcm,bcm21664-aon-ccu"
+#define BCM21664_DT_MASTER_CCU_COMPAT "brcm,bcm21664-master-ccu"
+#define BCM21664_DT_SLAVE_CCU_COMPAT "brcm,bcm21664-slave-ccu"
+
+/* root CCU clock ids */
+
+#define BCM21664_ROOT_CCU_FRAC_1M 0
+#define BCM21664_ROOT_CCU_CLOCK_COUNT 1
+
+/* aon CCU clock ids */
+
+#define BCM21664_AON_CCU_HUB_TIMER 0
+#define BCM21664_AON_CCU_CLOCK_COUNT 1
+
+/* master CCU clock ids */
+
+#define BCM21664_MASTER_CCU_SDIO1 0
+#define BCM21664_MASTER_CCU_SDIO2 1
+#define BCM21664_MASTER_CCU_SDIO3 2
+#define BCM21664_MASTER_CCU_SDIO4 3
+#define BCM21664_MASTER_CCU_SDIO1_SLEEP 4
+#define BCM21664_MASTER_CCU_SDIO2_SLEEP 5
+#define BCM21664_MASTER_CCU_SDIO3_SLEEP 6
+#define BCM21664_MASTER_CCU_SDIO4_SLEEP 7
+#define BCM21664_MASTER_CCU_CLOCK_COUNT 8
+
+/* slave CCU clock ids */
+
+#define BCM21664_SLAVE_CCU_UARTB 0
+#define BCM21664_SLAVE_CCU_UARTB2 1
+#define BCM21664_SLAVE_CCU_UARTB3 2
+#define BCM21664_SLAVE_CCU_BSC1 3
+#define BCM21664_SLAVE_CCU_BSC2 4
+#define BCM21664_SLAVE_CCU_BSC3 5
+#define BCM21664_SLAVE_CCU_BSC4 6
+#define BCM21664_SLAVE_CCU_CLOCK_COUNT 7
+
+#endif /* _CLOCK_BCM21664_H */
diff --git a/include/dt-bindings/clock/bcm281xx.h b/include/dt-bindings/clock/bcm281xx.h
index e009694..a763460 100644
--- a/include/dt-bindings/clock/bcm281xx.h
+++ b/include/dt-bindings/clock/bcm281xx.h
@@ -20,6 +20,18 @@
* the clock control units (CCUs) on Broadcom BCM281XX family SoCs.
*/
+/*
+ * These are the bcm281xx CCU device tree "compatible" strings.
+ * We're stuck with using "bcm11351" in the string because wild
+ * cards aren't allowed, and that name was the first one defined
+ * in this family of devices.
+ */
+#define BCM281XX_DT_ROOT_CCU_COMPAT "brcm,bcm11351-root-ccu"
+#define BCM281XX_DT_AON_CCU_COMPAT "brcm,bcm11351-aon-ccu"
+#define BCM281XX_DT_HUB_CCU_COMPAT "brcm,bcm11351-hub-ccu"
+#define BCM281XX_DT_MASTER_CCU_COMPAT "brcm,bcm11351-master-ccu"
+#define BCM281XX_DT_SLAVE_CCU_COMPAT "brcm,bcm11351-slave-ccu"
+
/* root CCU clock ids */
#define BCM281XX_ROOT_CCU_FRAC_1M 0
diff --git a/include/dt-bindings/clock/hix5hd2-clock.h b/include/dt-bindings/clock/hix5hd2-clock.h
new file mode 100644
index 0000000..aad579a
--- /dev/null
+++ b/include/dt-bindings/clock/hix5hd2-clock.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014 Linaro Ltd.
+ * Copyright (c) 2014 Hisilicon Limited.
+ *
+ * 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.
+ */
+
+#ifndef __DTS_HIX5HD2_CLOCK_H
+#define __DTS_HIX5HD2_CLOCK_H
+
+/* fixed rate */
+#define HIX5HD2_FIXED_1200M 1
+#define HIX5HD2_FIXED_400M 2
+#define HIX5HD2_FIXED_48M 3
+#define HIX5HD2_FIXED_24M 4
+#define HIX5HD2_FIXED_600M 5
+#define HIX5HD2_FIXED_300M 6
+#define HIX5HD2_FIXED_75M 7
+#define HIX5HD2_FIXED_200M 8
+#define HIX5HD2_FIXED_100M 9
+#define HIX5HD2_FIXED_40M 10
+#define HIX5HD2_FIXED_150M 11
+#define HIX5HD2_FIXED_1728M 12
+#define HIX5HD2_FIXED_28P8M 13
+#define HIX5HD2_FIXED_432M 14
+#define HIX5HD2_FIXED_345P6M 15
+#define HIX5HD2_FIXED_288M 16
+#define HIX5HD2_FIXED_60M 17
+#define HIX5HD2_FIXED_750M 18
+#define HIX5HD2_FIXED_500M 19
+#define HIX5HD2_FIXED_54M 20
+#define HIX5HD2_FIXED_27M 21
+#define HIX5HD2_FIXED_1500M 22
+#define HIX5HD2_FIXED_375M 23
+#define HIX5HD2_FIXED_187M 24
+#define HIX5HD2_FIXED_250M 25
+#define HIX5HD2_FIXED_125M 26
+#define HIX5HD2_FIXED_2P02M 27
+#define HIX5HD2_FIXED_50M 28
+#define HIX5HD2_FIXED_25M 29
+#define HIX5HD2_FIXED_83M 30
+
+/* mux clocks */
+#define HIX5HD2_SFC_MUX 64
+#define HIX5HD2_MMC_MUX 65
+#define HIX5HD2_FEPHY_MUX 66
+
+/* gate clocks */
+#define HIX5HD2_SFC_RST 128
+#define HIX5HD2_SFC_CLK 129
+#define HIX5HD2_MMC_CIU_CLK 130
+#define HIX5HD2_MMC_BIU_CLK 131
+#define HIX5HD2_MMC_CIU_RST 132
+
+#define HIX5HD2_NR_CLKS 256
+#endif /* __DTS_HIX5HD2_CLOCK_H */
diff --git a/include/dt-bindings/clock/qcom,gcc-msm8960.h b/include/dt-bindings/clock/qcom,gcc-msm8960.h
index 03bbf49..f9f5471 100644
--- a/include/dt-bindings/clock/qcom,gcc-msm8960.h
+++ b/include/dt-bindings/clock/qcom,gcc-msm8960.h
@@ -51,7 +51,7 @@
#define QDSS_TSCTR_CLK 34
#define SFAB_ADM0_M0_A_CLK 35
#define SFAB_ADM0_M1_A_CLK 36
-#define SFAB_ADM0_M2_A_CLK 37
+#define SFAB_ADM0_M2_H_CLK 37
#define ADM0_CLK 38
#define ADM0_PBUS_CLK 39
#define MSS_XPU_CLK 40
@@ -99,7 +99,7 @@
#define CFPB2_H_CLK 82
#define SFAB_CFPB_M_H_CLK 83
#define CFPB_MASTER_H_CLK 84
-#define SFAB_CFPB_S_HCLK 85
+#define SFAB_CFPB_S_H_CLK 85
#define CFPB_SPLITTER_H_CLK 86
#define TSIF_H_CLK 87
#define TSIF_INACTIVITY_TIMERS_CLK 88
@@ -110,7 +110,6 @@
#define CE1_SLEEP_CLK 93
#define CE2_H_CLK 94
#define CE2_CORE_CLK 95
-#define CE2_SLEEP_CLK 96
#define SFPB_H_CLK_SRC 97
#define SFPB_H_CLK 98
#define SFAB_SFPB_M_H_CLK 99
@@ -252,7 +251,7 @@
#define MSS_S_H_CLK 235
#define MSS_CXO_SRC_CLK 236
#define SATA_H_CLK 237
-#define SATA_SRC_CLK 238
+#define SATA_CLK_SRC 238
#define SATA_RXOOB_CLK 239
#define SATA_PMALIVE_CLK 240
#define SATA_PHY_REF_CLK 241
diff --git a/include/dt-bindings/reset/qcom,gcc-msm8960.h b/include/dt-bindings/reset/qcom,gcc-msm8960.h
index a840e68..07edd0e 100644
--- a/include/dt-bindings/reset/qcom,gcc-msm8960.h
+++ b/include/dt-bindings/reset/qcom,gcc-msm8960.h
@@ -58,7 +58,7 @@
#define PPSS_PROC_RESET 41
#define PPSS_RESET 42
#define DMA_BAM_RESET 43
-#define SIC_TIC_RESET 44
+#define SPS_TIC_H_RESET 44
#define SLIMBUS_H_RESET 45
#define SFAB_CFPB_M_RESET 46
#define SFAB_CFPB_S_RESET 47
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 5119174..4080943 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -40,14 +40,14 @@
* through the clk_* api.
*
* @prepare: Prepare the clock for enabling. This must not return until
- * the clock is fully prepared, and it's safe to call clk_enable.
- * This callback is intended to allow clock implementations to
- * do any initialisation that may sleep. Called with
- * prepare_lock held.
+ * the clock is fully prepared, and it's safe to call clk_enable.
+ * This callback is intended to allow clock implementations to
+ * do any initialisation that may sleep. Called with
+ * prepare_lock held.
*
* @unprepare: Release the clock from its prepared state. This will typically
- * undo any work done in the @prepare callback. Called with
- * prepare_lock held.
+ * undo any work done in the @prepare callback. Called with
+ * prepare_lock held.
*
* @is_prepared: Queries the hardware to determine if the clock is prepared.
* This function is allowed to sleep. Optional, if this op is not
@@ -58,16 +58,16 @@
* Called with prepare mutex held. This function may sleep.
*
* @enable: Enable the clock atomically. This must not return until the
- * clock is generating a valid clock signal, usable by consumer
- * devices. Called with enable_lock held. This function must not
- * sleep.
+ * clock is generating a valid clock signal, usable by consumer
+ * devices. Called with enable_lock held. This function must not
+ * sleep.
*
* @disable: Disable the clock atomically. Called with enable_lock held.
- * This function must not sleep.
+ * This function must not sleep.
*
* @is_enabled: Queries the hardware to determine if the clock is enabled.
- * This function must not sleep. Optional, if this op is not
- * set then the enable count will be used.
+ * This function must not sleep. Optional, if this op is not
+ * set then the enable count will be used.
*
* @disable_unused: Disable the clock atomically. Only called from
* clk_disable_unused for gate clocks with special needs.
@@ -75,34 +75,35 @@
* sleep.
*
* @recalc_rate Recalculate the rate of this clock, by querying hardware. The
- * parent rate is an input parameter. It is up to the caller to
- * ensure that the prepare_mutex is held across this call.
- * Returns the calculated rate. Optional, but recommended - if
- * this op is not set then clock rate will be initialized to 0.
+ * parent rate is an input parameter. It is up to the caller to
+ * ensure that the prepare_mutex is held across this call.
+ * Returns the calculated rate. Optional, but recommended - if
+ * this op is not set then clock rate will be initialized to 0.
*
* @round_rate: Given a target rate as input, returns the closest rate actually
- * supported by the clock.
+ * supported by the clock. The parent rate is an input/output
+ * parameter.
*
* @determine_rate: Given a target rate as input, returns the closest rate
* actually supported by the clock, and optionally the parent clock
* that should be used to provide the clock rate.
*
- * @get_parent: Queries the hardware to determine the parent of a clock. The
- * return value is a u8 which specifies the index corresponding to
- * the parent clock. This index can be applied to either the
- * .parent_names or .parents arrays. In short, this function
- * translates the parent value read from hardware into an array
- * index. Currently only called when the clock is initialized by
- * __clk_init. This callback is mandatory for clocks with
- * multiple parents. It is optional (and unnecessary) for clocks
- * with 0 or 1 parents.
- *
* @set_parent: Change the input source of this clock; for clocks with multiple
- * possible parents specify a new parent by passing in the index
- * as a u8 corresponding to the parent in either the .parent_names
- * or .parents arrays. This function in affect translates an
- * array index into the value programmed into the hardware.
- * Returns 0 on success, -EERROR otherwise.
+ * possible parents specify a new parent by passing in the index
+ * as a u8 corresponding to the parent in either the .parent_names
+ * or .parents arrays. This function in affect translates an
+ * array index into the value programmed into the hardware.
+ * Returns 0 on success, -EERROR otherwise.
+ *
+ * @get_parent: Queries the hardware to determine the parent of a clock. The
+ * return value is a u8 which specifies the index corresponding to
+ * the parent clock. This index can be applied to either the
+ * .parent_names or .parents arrays. In short, this function
+ * translates the parent value read from hardware into an array
+ * index. Currently only called when the clock is initialized by
+ * __clk_init. This callback is mandatory for clocks with
+ * multiple parents. It is optional (and unnecessary) for clocks
+ * with 0 or 1 parents.
*
* @set_rate: Change the rate of this clock. The requested rate is specified
* by the second argument, which should typically be the return
@@ -110,13 +111,6 @@
* which is likely helpful for most .set_rate implementation.
* Returns 0 on success, -EERROR otherwise.
*
- * @recalc_accuracy: Recalculate the accuracy of this clock. The clock accuracy
- * is expressed in ppb (parts per billion). The parent accuracy is
- * an input parameter.
- * Returns the calculated accuracy. Optional - if this op is not
- * set then clock accuracy will be initialized to parent accuracy
- * or 0 (perfect clock) if clock has no parent.
- *
* @set_rate_and_parent: Change the rate and the parent of this clock. The
* requested rate is specified by the second argument, which
* should typically be the return of .round_rate call. The
@@ -128,6 +122,18 @@
* separately via calls to .set_parent and .set_rate.
* Returns 0 on success, -EERROR otherwise.
*
+ * @recalc_accuracy: Recalculate the accuracy of this clock. The clock accuracy
+ * is expressed in ppb (parts per billion). The parent accuracy is
+ * an input parameter.
+ * Returns the calculated accuracy. Optional - if this op is not
+ * set then clock accuracy will be initialized to parent accuracy
+ * or 0 (perfect clock) if clock has no parent.
+ *
+ * @init: Perform platform-specific initialization magic.
+ * This is not not used by any of the basic clock types.
+ * Please consider other ways of solving initialization problems
+ * before using this callback, as its use is discouraged.
+ *
* @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
@@ -157,15 +163,15 @@
void (*disable_unused)(struct clk_hw *hw);
unsigned long (*recalc_rate)(struct clk_hw *hw,
unsigned long parent_rate);
- long (*round_rate)(struct clk_hw *hw, unsigned long,
- unsigned long *);
+ long (*round_rate)(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate);
long (*determine_rate)(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_clk);
int (*set_parent)(struct clk_hw *hw, u8 index);
u8 (*get_parent)(struct clk_hw *hw);
- int (*set_rate)(struct clk_hw *hw, unsigned long,
- unsigned long);
+ int (*set_rate)(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate);
int (*set_rate_and_parent)(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate, u8 index);
@@ -254,12 +260,12 @@
*
* Flags:
* CLK_GATE_SET_TO_DISABLE - by default this clock sets the bit at bit_idx to
- * enable the clock. Setting this flag does the opposite: setting the bit
- * disable the clock and clearing it enables the clock
+ * enable the clock. Setting this flag does the opposite: setting the bit
+ * disable the clock and clearing it enables the clock
* CLK_GATE_HIWORD_MASK - The gate settings are only in lower 16-bit
- * of this register, and mask of gate bits are in higher 16-bit of this
- * register. While setting the gate bits, higher 16-bit should also be
- * updated to indicate changing gate bits.
+ * of this register, and mask of gate bits are in higher 16-bit of this
+ * register. While setting the gate bits, higher 16-bit should also be
+ * updated to indicate changing gate bits.
*/
struct clk_gate {
struct clk_hw hw;
@@ -298,20 +304,22 @@
*
* Flags:
* CLK_DIVIDER_ONE_BASED - by default the divisor is the value read from the
- * register plus one. If CLK_DIVIDER_ONE_BASED is set then the divider is
- * the raw value read from the register, with the value of zero considered
+ * register plus one. If CLK_DIVIDER_ONE_BASED is set then the divider is
+ * the raw value read from the register, with the value of zero considered
* invalid, unless CLK_DIVIDER_ALLOW_ZERO is set.
* CLK_DIVIDER_POWER_OF_TWO - clock divisor is 2 raised to the value read from
- * the hardware register
+ * the hardware register
* CLK_DIVIDER_ALLOW_ZERO - Allow zero divisors. For dividers which have
* CLK_DIVIDER_ONE_BASED set, it is possible to end up with a zero divisor.
* Some hardware implementations gracefully handle this case and allow a
* zero divisor by not modifying their input clock
* (divide by one / bypass).
* CLK_DIVIDER_HIWORD_MASK - The divider settings are only in lower 16-bit
- * of this register, and mask of divider bits are in higher 16-bit of this
- * register. While setting the divider bits, higher 16-bit should also be
- * updated to indicate changing divider bits.
+ * of this register, and mask of divider bits are in higher 16-bit of this
+ * register. While setting the divider bits, higher 16-bit should also be
+ * updated to indicate changing divider bits.
+ * CLK_DIVIDER_ROUND_CLOSEST - Makes the best calculated divider to be rounded
+ * to the closest integer instead of the up one.
*/
struct clk_divider {
struct clk_hw hw;
@@ -327,6 +335,7 @@
#define CLK_DIVIDER_POWER_OF_TWO BIT(1)
#define CLK_DIVIDER_ALLOW_ZERO BIT(2)
#define CLK_DIVIDER_HIWORD_MASK BIT(3)
+#define CLK_DIVIDER_ROUND_CLOSEST BIT(4)
extern const struct clk_ops clk_divider_ops;
struct clk *clk_register_divider(struct device *dev, const char *name,
@@ -356,9 +365,9 @@
* CLK_MUX_INDEX_ONE - register index starts at 1, not 0
* CLK_MUX_INDEX_BIT - register index is a single bit (power of two)
* CLK_MUX_HIWORD_MASK - The mux settings are only in lower 16-bit of this
- * register, and mask of mux bits are in higher 16-bit of this register.
- * While setting the mux bits, higher 16-bit should also be updated to
- * indicate changing mux bits.
+ * register, and mask of mux bits are in higher 16-bit of this register.
+ * While setting the mux bits, higher 16-bit should also be updated to
+ * indicate changing mux bits.
*/
struct clk_mux {
struct clk_hw hw;
diff --git a/include/linux/clk/shmobile.h b/include/linux/clk/shmobile.h
index f9bf080..9f8a140 100644
--- a/include/linux/clk/shmobile.h
+++ b/include/linux/clk/shmobile.h
@@ -1,7 +1,9 @@
/*
* Copyright 2013 Ideas On Board SPRL
+ * Copyright 2013, 2014 Horms Solutions Ltd.
*
* Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Contact: Simon Horman <horms@verge.net.au>
*
* 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
@@ -14,6 +16,7 @@
#include <linux/types.h>
+void r8a7779_clocks_init(u32 mode);
void rcar_gen2_clocks_init(u32 mode);
#endif
diff --git a/include/linux/clk/sunxi.h b/include/linux/clk/sunxi.h
new file mode 100644
index 0000000..aed28c4
--- /dev/null
+++ b/include/linux/clk/sunxi.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2013 - Hans de Goede <hdegoede@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_CLK_SUNXI_H_
+#define __LINUX_CLK_SUNXI_H_
+
+#include <linux/clk.h>
+
+void clk_sunxi_mmc_phase_control(struct clk *clk, u8 sample, u8 output);
+
+#endif