diff options
93 files changed, 7218 insertions, 925 deletions
diff --git a/Documentation/clk.txt b/Documentation/clk.txt index c9c399af7c08..1fee72f4d331 100644 --- a/Documentation/clk.txt +++ b/Documentation/clk.txt | |||
| @@ -68,21 +68,27 @@ the operations defined in clk.h: | |||
| 68 | int (*is_enabled)(struct clk_hw *hw); | 68 | int (*is_enabled)(struct clk_hw *hw); |
| 69 | unsigned long (*recalc_rate)(struct clk_hw *hw, | 69 | unsigned long (*recalc_rate)(struct clk_hw *hw, |
| 70 | unsigned long parent_rate); | 70 | unsigned long parent_rate); |
| 71 | long (*round_rate)(struct clk_hw *hw, unsigned long, | 71 | long (*round_rate)(struct clk_hw *hw, |
| 72 | unsigned long *); | 72 | unsigned long rate, |
| 73 | unsigned long *parent_rate); | ||
| 73 | long (*determine_rate)(struct clk_hw *hw, | 74 | long (*determine_rate)(struct clk_hw *hw, |
| 74 | unsigned long rate, | 75 | unsigned long rate, |
| 75 | unsigned long *best_parent_rate, | 76 | unsigned long *best_parent_rate, |
| 76 | struct clk **best_parent_clk); | 77 | struct clk **best_parent_clk); |
| 77 | int (*set_parent)(struct clk_hw *hw, u8 index); | 78 | int (*set_parent)(struct clk_hw *hw, u8 index); |
| 78 | u8 (*get_parent)(struct clk_hw *hw); | 79 | u8 (*get_parent)(struct clk_hw *hw); |
| 79 | int (*set_rate)(struct clk_hw *hw, unsigned long); | 80 | int (*set_rate)(struct clk_hw *hw, |
| 81 | unsigned long rate, | ||
| 82 | unsigned long parent_rate); | ||
| 80 | int (*set_rate_and_parent)(struct clk_hw *hw, | 83 | int (*set_rate_and_parent)(struct clk_hw *hw, |
| 81 | unsigned long rate, | 84 | unsigned long rate, |
| 82 | unsigned long parent_rate, u8 index); | 85 | unsigned long parent_rate, |
| 86 | u8 index); | ||
| 83 | unsigned long (*recalc_accuracy)(struct clk_hw *hw, | 87 | unsigned long (*recalc_accuracy)(struct clk_hw *hw, |
| 84 | unsigned long parent_accuracy); | 88 | unsigned long parent_accuracy); |
| 85 | void (*init)(struct clk_hw *hw); | 89 | void (*init)(struct clk_hw *hw); |
| 90 | int (*debug_init)(struct clk_hw *hw, | ||
| 91 | struct dentry *dentry); | ||
| 86 | }; | 92 | }; |
| 87 | 93 | ||
| 88 | Part 3 - hardware clk implementations | 94 | 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 56d1f4961075..5286e260fcae 100644 --- a/Documentation/devicetree/bindings/clock/bcm-kona-clock.txt +++ b/Documentation/devicetree/bindings/clock/bcm-kona-clock.txt | |||
| @@ -10,12 +10,12 @@ This binding uses the common clock binding: | |||
| 10 | 10 | ||
| 11 | Required properties: | 11 | Required properties: |
| 12 | - compatible | 12 | - compatible |
| 13 | Shall have one of the following values: | 13 | Shall have a value of the form "brcm,<model>-<which>-ccu", |
| 14 | - "brcm,bcm11351-root-ccu" | 14 | where <model> is a Broadcom SoC model number and <which> is |
| 15 | - "brcm,bcm11351-aon-ccu" | 15 | the name of a defined CCU. For example: |
| 16 | - "brcm,bcm11351-hub-ccu" | 16 | "brcm,bcm11351-root-ccu" |
| 17 | - "brcm,bcm11351-master-ccu" | 17 | The compatible strings used for each supported SoC family |
| 18 | - "brcm,bcm11351-slave-ccu" | 18 | are defined below. |
| 19 | - reg | 19 | - reg |
| 20 | Shall define the base and range of the address space | 20 | Shall define the base and range of the address space |
| 21 | containing clock control registers | 21 | containing clock control registers |
| @@ -26,12 +26,48 @@ Required properties: | |||
| 26 | Shall be an ordered list of strings defining the names of | 26 | Shall be an ordered list of strings defining the names of |
| 27 | the clocks provided by the CCU. | 27 | the clocks provided by the CCU. |
| 28 | 28 | ||
| 29 | Device tree example: | ||
| 30 | |||
| 31 | slave_ccu: slave_ccu { | ||
| 32 | compatible = "brcm,bcm11351-slave-ccu"; | ||
| 33 | reg = <0x3e011000 0x0f00>; | ||
| 34 | #clock-cells = <1>; | ||
| 35 | clock-output-names = "uartb", | ||
| 36 | "uartb2", | ||
| 37 | "uartb3", | ||
| 38 | "uartb4"; | ||
| 39 | }; | ||
| 40 | |||
| 41 | ref_crystal_clk: ref_crystal { | ||
| 42 | #clock-cells = <0>; | ||
| 43 | compatible = "fixed-clock"; | ||
| 44 | clock-frequency = <26000000>; | ||
| 45 | }; | ||
| 46 | |||
| 47 | uart@3e002000 { | ||
| 48 | compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart"; | ||
| 49 | status = "disabled"; | ||
| 50 | reg = <0x3e002000 0x1000>; | ||
| 51 | clocks = <&slave_ccu BCM281XX_SLAVE_CCU_UARTB3>; | ||
| 52 | interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; | ||
| 53 | reg-shift = <2>; | ||
| 54 | reg-io-width = <4>; | ||
| 55 | }; | ||
| 56 | |||
| 57 | BCM281XX family | ||
| 58 | --------------- | ||
| 59 | CCU compatible string values for SoCs in the BCM281XX family are: | ||
| 60 | "brcm,bcm11351-root-ccu" | ||
| 61 | "brcm,bcm11351-aon-ccu" | ||
| 62 | "brcm,bcm11351-hub-ccu" | ||
| 63 | "brcm,bcm11351-master-ccu" | ||
| 64 | "brcm,bcm11351-slave-ccu" | ||
| 29 | 65 | ||
| 30 | BCM281XX family SoCs use Kona CCUs. The following table defines | 66 | The following table defines the set of CCUs and clock specifiers for |
| 31 | the set of CCUs and clock specifiers for BCM281XX clocks. When | 67 | BCM281XX family clocks. When a clock consumer references a clocks, |
| 32 | a clock consumer references a clocks, its symbolic specifier | 68 | its symbolic specifier (rather than its numeric index value) should |
| 33 | (rather than its numeric index value) should be used. These | 69 | be used. These specifiers are defined in: |
| 34 | specifiers are defined in "include/dt-bindings/clock/bcm281xx.h". | 70 | "include/dt-bindings/clock/bcm281xx.h" |
| 35 | 71 | ||
| 36 | CCU Clock Type Index Specifier | 72 | CCU Clock Type Index Specifier |
| 37 | --- ----- ---- ----- --------- | 73 | --- ----- ---- ----- --------- |
| @@ -64,30 +100,40 @@ specifiers are defined in "include/dt-bindings/clock/bcm281xx.h". | |||
| 64 | slave pwm peri 9 BCM281XX_SLAVE_CCU_PWM | 100 | slave pwm peri 9 BCM281XX_SLAVE_CCU_PWM |
| 65 | 101 | ||
| 66 | 102 | ||
| 67 | Device tree example: | 103 | BCM21664 family |
| 104 | --------------- | ||
| 105 | CCU compatible string values for SoCs in the BCM21664 family are: | ||
| 106 | "brcm,bcm21664-root-ccu" | ||
| 107 | "brcm,bcm21664-aon-ccu" | ||
| 108 | "brcm,bcm21664-master-ccu" | ||
| 109 | "brcm,bcm21664-slave-ccu" | ||
| 68 | 110 | ||
| 69 | slave_ccu: slave_ccu { | 111 | The following table defines the set of CCUs and clock specifiers for |
| 70 | compatible = "brcm,bcm11351-slave-ccu"; | 112 | BCM21664 family clocks. When a clock consumer references a clocks, |
| 71 | reg = <0x3e011000 0x0f00>; | 113 | its symbolic specifier (rather than its numeric index value) should |
| 72 | #clock-cells = <1>; | 114 | be used. These specifiers are defined in: |
| 73 | clock-output-names = "uartb", | 115 | "include/dt-bindings/clock/bcm21664.h" |
| 74 | "uartb2", | ||
| 75 | "uartb3", | ||
| 76 | "uartb4"; | ||
| 77 | }; | ||
| 78 | 116 | ||
| 79 | ref_crystal_clk: ref_crystal { | 117 | CCU Clock Type Index Specifier |
| 80 | #clock-cells = <0>; | 118 | --- ----- ---- ----- --------- |
| 81 | compatible = "fixed-clock"; | 119 | root frac_1m peri 0 BCM21664_ROOT_CCU_FRAC_1M |
| 82 | clock-frequency = <26000000>; | ||
| 83 | }; | ||
| 84 | 120 | ||
| 85 | uart@3e002000 { | 121 | aon hub_timer peri 0 BCM21664_AON_CCU_HUB_TIMER |
| 86 | compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart"; | 122 | |
| 87 | status = "disabled"; | 123 | master sdio1 peri 0 BCM21664_MASTER_CCU_SDIO1 |
| 88 | reg = <0x3e002000 0x1000>; | 124 | master sdio2 peri 1 BCM21664_MASTER_CCU_SDIO2 |
| 89 | clocks = <&slave_ccu BCM281XX_SLAVE_CCU_UARTB3>; | 125 | master sdio3 peri 2 BCM21664_MASTER_CCU_SDIO3 |
| 90 | interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; | 126 | master sdio4 peri 3 BCM21664_MASTER_CCU_SDIO4 |
| 91 | reg-shift = <2>; | 127 | master sdio1_sleep peri 4 BCM21664_MASTER_CCU_SDIO1_SLEEP |
| 92 | reg-io-width = <4>; | 128 | master sdio2_sleep peri 5 BCM21664_MASTER_CCU_SDIO2_SLEEP |
| 93 | }; | 129 | master sdio3_sleep peri 6 BCM21664_MASTER_CCU_SDIO3_SLEEP |
| 130 | master sdio4_sleep peri 7 BCM21664_MASTER_CCU_SDIO4_SLEEP | ||
| 131 | |||
| 132 | slave uartb peri 0 BCM21664_SLAVE_CCU_UARTB | ||
| 133 | slave uartb2 peri 1 BCM21664_SLAVE_CCU_UARTB2 | ||
| 134 | slave uartb3 peri 2 BCM21664_SLAVE_CCU_UARTB3 | ||
| 135 | slave uartb4 peri 3 BCM21664_SLAVE_CCU_UARTB4 | ||
| 136 | slave bsc1 peri 4 BCM21664_SLAVE_CCU_BSC1 | ||
| 137 | slave bsc2 peri 5 BCM21664_SLAVE_CCU_BSC2 | ||
| 138 | slave bsc3 peri 6 BCM21664_SLAVE_CCU_BSC3 | ||
| 139 | 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 700e7aac3717..f15787817d6b 100644 --- a/Documentation/devicetree/bindings/clock/clock-bindings.txt +++ b/Documentation/devicetree/bindings/clock/clock-bindings.txt | |||
| @@ -44,10 +44,9 @@ For example: | |||
| 44 | clocks by index. The names should reflect the clock output signal | 44 | clocks by index. The names should reflect the clock output signal |
| 45 | names for the device. | 45 | names for the device. |
| 46 | 46 | ||
| 47 | clock-indices: If the identifyng number for the clocks in the node | 47 | clock-indices: If the identifying number for the clocks in the node |
| 48 | is not linear from zero, then the this mapping allows | 48 | is not linear from zero, then this allows the mapping of |
| 49 | the mapping of identifiers into the clock-output-names | 49 | identifiers into the clock-output-names array. |
| 50 | array. | ||
| 51 | 50 | ||
| 52 | For example, if we have two clocks <&oscillator 1> and <&oscillator 3>: | 51 | For example, if we have two clocks <&oscillator 1> and <&oscillator 3>: |
| 53 | 52 | ||
| @@ -58,7 +57,7 @@ For example, if we have two clocks <&oscillator 1> and <&oscillator 3>: | |||
| 58 | clock-output-names = "clka", "clkb"; | 57 | clock-output-names = "clka", "clkb"; |
| 59 | } | 58 | } |
| 60 | 59 | ||
| 61 | This ensures we do not have any empty nodes in clock-output-names | 60 | This ensures we do not have any empty strings in clock-output-names |
| 62 | 61 | ||
| 63 | 62 | ||
| 64 | ==Clock consumers== | 63 | ==Clock consumers== |
diff --git a/Documentation/devicetree/bindings/clock/fixed-clock.txt b/Documentation/devicetree/bindings/clock/fixed-clock.txt index 48ea0ad8ad46..0641a663ad69 100644 --- a/Documentation/devicetree/bindings/clock/fixed-clock.txt +++ b/Documentation/devicetree/bindings/clock/fixed-clock.txt | |||
| @@ -12,7 +12,6 @@ Required properties: | |||
| 12 | Optional properties: | 12 | Optional properties: |
| 13 | - clock-accuracy : accuracy of clock in ppb (parts per billion). | 13 | - clock-accuracy : accuracy of clock in ppb (parts per billion). |
| 14 | Should be a single cell. | 14 | Should be a single cell. |
| 15 | - gpios : From common gpio binding; gpio connection to clock enable pin. | ||
| 16 | - clock-output-names : From common clock binding. | 15 | - clock-output-names : From common clock binding. |
| 17 | 16 | ||
| 18 | Example: | 17 | Example: |
diff --git a/Documentation/devicetree/bindings/clock/hix5hd2-clock.txt b/Documentation/devicetree/bindings/clock/hix5hd2-clock.txt new file mode 100644 index 000000000000..7894a64887cb --- /dev/null +++ b/Documentation/devicetree/bindings/clock/hix5hd2-clock.txt | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | * Hisilicon Hix5hd2 Clock Controller | ||
| 2 | |||
| 3 | The hix5hd2 clock controller generates and supplies clock to various | ||
| 4 | controllers within the hix5hd2 SoC. | ||
| 5 | |||
| 6 | Required Properties: | ||
| 7 | |||
| 8 | - compatible: should be "hisilicon,hix5hd2-clock" | ||
| 9 | - reg: Address and length of the register set | ||
| 10 | - #clock-cells: Should be <1> | ||
| 11 | |||
| 12 | Each clock is assigned an identifier and client nodes use this identifier | ||
| 13 | to specify the clock which they consume. | ||
| 14 | |||
| 15 | All these identifier could be found in <dt-bindings/clock/hix5hd2-clock.h>. | ||
| 16 | |||
| 17 | Examples: | ||
| 18 | clock: clock@f8a22000 { | ||
| 19 | compatible = "hisilicon,hix5hd2-clock"; | ||
| 20 | reg = <0xf8a22000 0x1000>; | ||
| 21 | #clock-cells = <1>; | ||
| 22 | }; | ||
| 23 | |||
| 24 | uart0: uart@f8b00000 { | ||
| 25 | compatible = "arm,pl011", "arm,primecell"; | ||
| 26 | reg = <0xf8b00000 0x1000>; | ||
| 27 | interrupts = <0 49 4>; | ||
| 28 | clocks = <&clock HIX5HD2_FIXED_83M>; | ||
| 29 | clock-names = "apb_pclk"; | ||
| 30 | status = "disabled"; | ||
| 31 | }; | ||
diff --git a/Documentation/devicetree/bindings/clock/lsi,axm5516-clks.txt b/Documentation/devicetree/bindings/clock/lsi,axm5516-clks.txt new file mode 100644 index 000000000000..3ce97cfe999b --- /dev/null +++ b/Documentation/devicetree/bindings/clock/lsi,axm5516-clks.txt | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | AXM5516 clock driver bindings | ||
| 2 | ----------------------------- | ||
| 3 | |||
| 4 | Required properties : | ||
| 5 | - compatible : shall contain "lsi,axm5516-clks" | ||
| 6 | - reg : shall contain base register location and length | ||
| 7 | - #clock-cells : shall contain 1 | ||
| 8 | |||
| 9 | The consumer specifies the desired clock by having the clock ID in its "clocks" | ||
| 10 | phandle cell. See <dt-bindings/clock/lsi,axxia-clock.h> for the list of | ||
| 11 | supported clock IDs. | ||
| 12 | |||
| 13 | Example: | ||
| 14 | |||
| 15 | clks: clock-controller@2010020000 { | ||
| 16 | compatible = "lsi,axm5516-clks"; | ||
| 17 | #clock-cells = <1>; | ||
| 18 | reg = <0x20 0x10020000 0 0x20000>; | ||
| 19 | }; | ||
| 20 | |||
| 21 | serial0: uart@2010080000 { | ||
| 22 | compatible = "arm,pl011", "arm,primecell"; | ||
| 23 | reg = <0x20 0x10080000 0 0x1000>; | ||
| 24 | interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>; | ||
| 25 | clocks = <&clks AXXIA_CLK_PER>; | ||
| 26 | clock-names = "apb_pclk"; | ||
| 27 | }; | ||
| 28 | }; | ||
| 29 | |||
diff --git a/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt index 307a503c5db8..dc5ea5b22da9 100644 --- a/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt +++ b/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt | |||
| @@ -29,6 +29,11 @@ The following is a list of provided IDs and clock names on Kirkwood and Dove: | |||
| 29 | 2 = l2clk (L2 Cache clock derived from CPU0 clock) | 29 | 2 = l2clk (L2 Cache clock derived from CPU0 clock) |
| 30 | 3 = ddrclk (DDR controller clock derived from CPU0 clock) | 30 | 3 = ddrclk (DDR controller clock derived from CPU0 clock) |
| 31 | 31 | ||
| 32 | The following is a list of provided IDs and clock names on Orion5x: | ||
| 33 | 0 = tclk (Internal Bus clock) | ||
| 34 | 1 = cpuclk (CPU0 clock) | ||
| 35 | 2 = ddrclk (DDR controller clock derived from CPU0 clock) | ||
| 36 | |||
| 32 | Required properties: | 37 | Required properties: |
| 33 | - compatible : shall be one of the following: | 38 | - compatible : shall be one of the following: |
| 34 | "marvell,armada-370-core-clock" - For Armada 370 SoC core clocks | 39 | "marvell,armada-370-core-clock" - For Armada 370 SoC core clocks |
| @@ -38,6 +43,9 @@ Required properties: | |||
| 38 | "marvell,dove-core-clock" - for Dove SoC core clocks | 43 | "marvell,dove-core-clock" - for Dove SoC core clocks |
| 39 | "marvell,kirkwood-core-clock" - for Kirkwood SoC (except mv88f6180) | 44 | "marvell,kirkwood-core-clock" - for Kirkwood SoC (except mv88f6180) |
| 40 | "marvell,mv88f6180-core-clock" - for Kirkwood MV88f6180 SoC | 45 | "marvell,mv88f6180-core-clock" - for Kirkwood MV88f6180 SoC |
| 46 | "marvell,mv88f5182-core-clock" - for Orion MV88F5182 SoC | ||
| 47 | "marvell,mv88f5281-core-clock" - for Orion MV88F5281 SoC | ||
| 48 | "marvell,mv88f6183-core-clock" - for Orion MV88F6183 SoC | ||
| 41 | - reg : shall be the register address of the Sample-At-Reset (SAR) register | 49 | - reg : shall be the register address of the Sample-At-Reset (SAR) register |
| 42 | - #clock-cells : from common clock binding; shall be set to 1 | 50 | - #clock-cells : from common clock binding; shall be set to 1 |
| 43 | 51 | ||
diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt index 767401f42871..9cfcb4f2bc97 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt | |||
| @@ -4,9 +4,12 @@ Qualcomm Global Clock & Reset Controller Binding | |||
| 4 | Required properties : | 4 | Required properties : |
| 5 | - compatible : shall contain only one of the following: | 5 | - compatible : shall contain only one of the following: |
| 6 | 6 | ||
| 7 | "qcom,gcc-apq8064" | ||
| 7 | "qcom,gcc-msm8660" | 8 | "qcom,gcc-msm8660" |
| 8 | "qcom,gcc-msm8960" | 9 | "qcom,gcc-msm8960" |
| 9 | "qcom,gcc-msm8974" | 10 | "qcom,gcc-msm8974" |
| 11 | "qcom,gcc-msm8974pro" | ||
| 12 | "qcom,gcc-msm8974pro-ac" | ||
| 10 | 13 | ||
| 11 | - reg : shall contain base register location and length | 14 | - reg : shall contain base register location and length |
| 12 | - #clock-cells : shall contain 1 | 15 | - #clock-cells : shall contain 1 |
diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt index 6c3c0847e4fd..8a92b5fb3540 100644 --- a/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt +++ b/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt | |||
| @@ -11,6 +11,7 @@ Required Properties: | |||
| 11 | 11 | ||
| 12 | - compatible: Must be one of the following | 12 | - compatible: Must be one of the following |
| 13 | - "renesas,r7s72100-mstp-clocks" for R7S72100 (RZ) MSTP gate clocks | 13 | - "renesas,r7s72100-mstp-clocks" for R7S72100 (RZ) MSTP gate clocks |
| 14 | - "renesas,r8a7779-mstp-clocks" for R8A7779 (R-Car H1) MSTP gate clocks | ||
| 14 | - "renesas,r8a7790-mstp-clocks" for R8A7790 (R-Car H2) MSTP gate clocks | 15 | - "renesas,r8a7790-mstp-clocks" for R8A7790 (R-Car H2) MSTP gate clocks |
| 15 | - "renesas,r8a7791-mstp-clocks" for R8A7791 (R-Car M2) MSTP gate clocks | 16 | - "renesas,r8a7791-mstp-clocks" for R8A7791 (R-Car M2) MSTP gate clocks |
| 16 | - "renesas,cpg-mstp-clock" for generic MSTP gate clocks | 17 | - "renesas,cpg-mstp-clock" for generic MSTP gate clocks |
diff --git a/Documentation/devicetree/bindings/clock/renesas,r8a7740-cpg-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,r8a7740-cpg-clocks.txt new file mode 100644 index 000000000000..2c03302f86ed --- /dev/null +++ b/Documentation/devicetree/bindings/clock/renesas,r8a7740-cpg-clocks.txt | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | These bindings should be considered EXPERIMENTAL for now. | ||
| 2 | |||
| 3 | * Renesas R8A7740 Clock Pulse Generator (CPG) | ||
| 4 | |||
| 5 | The CPG generates core clocks for the R8A7740 SoC. It includes three PLLs | ||
| 6 | and several fixed ratio and variable ratio dividers. | ||
| 7 | |||
| 8 | Required Properties: | ||
| 9 | |||
| 10 | - compatible: Must be "renesas,r8a7740-cpg-clocks" | ||
| 11 | |||
| 12 | - reg: Base address and length of the memory resource used by the CPG | ||
| 13 | |||
| 14 | - clocks: Reference to the three parent clocks | ||
| 15 | - #clock-cells: Must be 1 | ||
| 16 | - clock-output-names: The names of the clocks. Supported clocks are | ||
| 17 | "system", "pllc0", "pllc1", "pllc2", "r", "usb24s", "i", "zg", "b", | ||
| 18 | "m1", "hp", "hpp", "usbp", "s", "zb", "m3", and "cp". | ||
| 19 | |||
| 20 | - renesas,mode: board-specific settings of the MD_CK* bits | ||
| 21 | |||
| 22 | |||
| 23 | Example | ||
| 24 | ------- | ||
| 25 | |||
| 26 | cpg_clocks: cpg_clocks@e6150000 { | ||
| 27 | compatible = "renesas,r8a7740-cpg-clocks"; | ||
| 28 | reg = <0xe6150000 0x10000>; | ||
| 29 | clocks = <&extal1_clk>, <&extal2_clk>, <&extalr_clk>; | ||
| 30 | #clock-cells = <1>; | ||
| 31 | clock-output-names = "system", "pllc0", "pllc1", | ||
| 32 | "pllc2", "r", | ||
| 33 | "usb24s", | ||
| 34 | "i", "zg", "b", "m1", "hp", | ||
| 35 | "hpp", "usbp", "s", "zb", "m3", | ||
| 36 | "cp"; | ||
| 37 | }; | ||
| 38 | |||
| 39 | &cpg_clocks { | ||
| 40 | renesas,mode = <0x05>; | ||
| 41 | }; | ||
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 000000000000..ed3c8cb12f4e --- /dev/null +++ b/Documentation/devicetree/bindings/clock/renesas,r8a7779-cpg-clocks.txt | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | * Renesas R8A7779 Clock Pulse Generator (CPG) | ||
| 2 | |||
| 3 | The CPG generates core clocks for the R8A7779. It includes one PLL and | ||
| 4 | several fixed ratio dividers | ||
| 5 | |||
| 6 | Required Properties: | ||
| 7 | |||
| 8 | - compatible: Must be "renesas,r8a7779-cpg-clocks" | ||
| 9 | - reg: Base address and length of the memory resource used by the CPG | ||
| 10 | |||
| 11 | - clocks: Reference to the parent clock | ||
| 12 | - #clock-cells: Must be 1 | ||
| 13 | - clock-output-names: The names of the clocks. Supported clocks are "plla", | ||
| 14 | "z", "zs", "s", "s1", "p", "b", "out". | ||
| 15 | |||
| 16 | |||
| 17 | Example | ||
| 18 | ------- | ||
| 19 | |||
| 20 | cpg_clocks: cpg_clocks@ffc80000 { | ||
| 21 | compatible = "renesas,r8a7779-cpg-clocks"; | ||
| 22 | reg = <0 0xffc80000 0 0x30>; | ||
| 23 | clocks = <&extal_clk>; | ||
| 24 | #clock-cells = <1>; | ||
| 25 | clock-output-names = "plla", "z", "zs", "s", "s1", "p", | ||
| 26 | "b", "out"; | ||
| 27 | }; | ||
diff --git a/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt b/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt new file mode 100644 index 000000000000..91b3a3467150 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | * Allwinner sunxi MMC controller | ||
| 2 | |||
| 3 | The highspeed MMC host controller on Allwinner SoCs provides an interface | ||
| 4 | for MMC, SD and SDIO types of memory cards. | ||
| 5 | |||
| 6 | Supported maximum speeds are the ones of the eMMC standard 4.5 as well | ||
| 7 | as the speed of SD standard 3.0. | ||
| 8 | Absolute maximum transfer rate is 200MB/s | ||
| 9 | |||
| 10 | Required properties: | ||
| 11 | - compatible : "allwinner,sun4i-a10-mmc" or "allwinner,sun5i-a13-mmc" | ||
| 12 | - reg : mmc controller base registers | ||
| 13 | - clocks : a list with 2 phandle + clock specifier pairs | ||
| 14 | - clock-names : must contain "ahb" and "mmc" | ||
| 15 | - interrupts : mmc controller interrupt | ||
| 16 | |||
| 17 | Optional properties: | ||
| 18 | - resets : phandle + reset specifier pair | ||
| 19 | - reset-names : must contain "ahb" | ||
| 20 | - for cd, bus-width and additional generic mmc parameters | ||
| 21 | please refer to mmc.txt within this directory | ||
| 22 | |||
| 23 | Examples: | ||
| 24 | - Within .dtsi: | ||
| 25 | mmc0: mmc@01c0f000 { | ||
| 26 | compatible = "allwinner,sun5i-a13-mmc"; | ||
| 27 | reg = <0x01c0f000 0x1000>; | ||
| 28 | clocks = <&ahb_gates 8>, <&mmc0_clk>; | ||
| 29 | clock-names = "ahb", "mod"; | ||
| 30 | interrupts = <0 32 4>; | ||
| 31 | status = "disabled"; | ||
| 32 | }; | ||
| 33 | |||
| 34 | - Within dts: | ||
| 35 | mmc0: mmc@01c0f000 { | ||
| 36 | pinctrl-names = "default", "default"; | ||
| 37 | pinctrl-0 = <&mmc0_pins_a>; | ||
| 38 | pinctrl-1 = <&mmc0_cd_pin_reference_design>; | ||
| 39 | bus-width = <4>; | ||
| 40 | cd-gpios = <&pio 7 1 0>; /* PH1 */ | ||
| 41 | cd-inverted; | ||
| 42 | status = "okay"; | ||
| 43 | }; | ||
diff --git a/MAINTAINERS b/MAINTAINERS index f98da9025d7d..7ca9e1918bad 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -815,6 +815,11 @@ F: arch/arm/boot/dts/at91*.dtsi | |||
| 815 | F: arch/arm/boot/dts/sama*.dts | 815 | F: arch/arm/boot/dts/sama*.dts |
| 816 | F: arch/arm/boot/dts/sama*.dtsi | 816 | F: arch/arm/boot/dts/sama*.dtsi |
| 817 | 817 | ||
| 818 | ARM/ATMEL AT91 Clock Support | ||
| 819 | M: Boris Brezillon <boris.brezillon@free-electrons.com> | ||
| 820 | S: Maintained | ||
| 821 | F: drivers/clk/at91 | ||
| 822 | |||
| 818 | ARM/CALXEDA HIGHBANK ARCHITECTURE | 823 | ARM/CALXEDA HIGHBANK ARCHITECTURE |
| 819 | M: Rob Herring <robh@kernel.org> | 824 | M: Rob Herring <robh@kernel.org> |
| 820 | L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) | 825 | L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) |
diff --git a/arch/arm/boot/dts/bcm21664.dtsi b/arch/arm/boot/dts/bcm21664.dtsi index 08a44d41b672..8b366822bb43 100644 --- a/arch/arm/boot/dts/bcm21664.dtsi +++ b/arch/arm/boot/dts/bcm21664.dtsi | |||
| @@ -14,6 +14,8 @@ | |||
| 14 | #include <dt-bindings/interrupt-controller/arm-gic.h> | 14 | #include <dt-bindings/interrupt-controller/arm-gic.h> |
| 15 | #include <dt-bindings/interrupt-controller/irq.h> | 15 | #include <dt-bindings/interrupt-controller/irq.h> |
| 16 | 16 | ||
| 17 | #include "dt-bindings/clock/bcm21664.h" | ||
| 18 | |||
| 17 | #include "skeleton.dtsi" | 19 | #include "skeleton.dtsi" |
| 18 | 20 | ||
| 19 | / { | 21 | / { |
| @@ -43,7 +45,7 @@ | |||
| 43 | compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart"; | 45 | compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart"; |
| 44 | status = "disabled"; | 46 | status = "disabled"; |
| 45 | reg = <0x3e000000 0x118>; | 47 | reg = <0x3e000000 0x118>; |
| 46 | clocks = <&uartb_clk>; | 48 | clocks = <&slave_ccu BCM21664_SLAVE_CCU_UARTB>; |
| 47 | interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; | 49 | interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; |
| 48 | reg-shift = <2>; | 50 | reg-shift = <2>; |
| 49 | reg-io-width = <4>; | 51 | reg-io-width = <4>; |
| @@ -53,7 +55,7 @@ | |||
| 53 | compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart"; | 55 | compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart"; |
| 54 | status = "disabled"; | 56 | status = "disabled"; |
| 55 | reg = <0x3e001000 0x118>; | 57 | reg = <0x3e001000 0x118>; |
| 56 | clocks = <&uartb2_clk>; | 58 | clocks = <&slave_ccu BCM21664_SLAVE_CCU_UARTB2>; |
| 57 | interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>; | 59 | interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>; |
| 58 | reg-shift = <2>; | 60 | reg-shift = <2>; |
| 59 | reg-io-width = <4>; | 61 | reg-io-width = <4>; |
| @@ -63,7 +65,7 @@ | |||
| 63 | compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart"; | 65 | compatible = "brcm,bcm21664-dw-apb-uart", "snps,dw-apb-uart"; |
| 64 | status = "disabled"; | 66 | status = "disabled"; |
| 65 | reg = <0x3e002000 0x118>; | 67 | reg = <0x3e002000 0x118>; |
| 66 | clocks = <&uartb3_clk>; | 68 | clocks = <&slave_ccu BCM21664_SLAVE_CCU_UARTB3>; |
| 67 | interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; | 69 | interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; |
| 68 | reg-shift = <2>; | 70 | reg-shift = <2>; |
| 69 | reg-io-width = <4>; | 71 | reg-io-width = <4>; |
| @@ -85,7 +87,7 @@ | |||
| 85 | compatible = "brcm,kona-timer"; | 87 | compatible = "brcm,kona-timer"; |
| 86 | reg = <0x35006000 0x1c>; | 88 | reg = <0x35006000 0x1c>; |
| 87 | interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; | 89 | interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; |
| 88 | clocks = <&hub_timer_clk>; | 90 | clocks = <&aon_ccu BCM21664_AON_CCU_HUB_TIMER>; |
| 89 | }; | 91 | }; |
| 90 | 92 | ||
| 91 | gpio: gpio@35003000 { | 93 | gpio: gpio@35003000 { |
| @@ -106,7 +108,7 @@ | |||
| 106 | compatible = "brcm,kona-sdhci"; | 108 | compatible = "brcm,kona-sdhci"; |
| 107 | reg = <0x3f180000 0x801c>; | 109 | reg = <0x3f180000 0x801c>; |
| 108 | interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>; | 110 | interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>; |
| 109 | clocks = <&sdio1_clk>; | 111 | clocks = <&master_ccu BCM21664_MASTER_CCU_SDIO1>; |
| 110 | status = "disabled"; | 112 | status = "disabled"; |
| 111 | }; | 113 | }; |
| 112 | 114 | ||
| @@ -114,7 +116,7 @@ | |||
| 114 | compatible = "brcm,kona-sdhci"; | 116 | compatible = "brcm,kona-sdhci"; |
| 115 | reg = <0x3f190000 0x801c>; | 117 | reg = <0x3f190000 0x801c>; |
| 116 | interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>; | 118 | interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>; |
| 117 | clocks = <&sdio2_clk>; | 119 | clocks = <&master_ccu BCM21664_MASTER_CCU_SDIO2>; |
| 118 | status = "disabled"; | 120 | status = "disabled"; |
| 119 | }; | 121 | }; |
| 120 | 122 | ||
| @@ -122,7 +124,7 @@ | |||
| 122 | compatible = "brcm,kona-sdhci"; | 124 | compatible = "brcm,kona-sdhci"; |
| 123 | reg = <0x3f1a0000 0x801c>; | 125 | reg = <0x3f1a0000 0x801c>; |
| 124 | interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; | 126 | interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; |
| 125 | clocks = <&sdio3_clk>; | 127 | clocks = <&master_ccu BCM21664_MASTER_CCU_SDIO3>; |
| 126 | status = "disabled"; | 128 | status = "disabled"; |
| 127 | }; | 129 | }; |
| 128 | 130 | ||
| @@ -130,7 +132,7 @@ | |||
| 130 | compatible = "brcm,kona-sdhci"; | 132 | compatible = "brcm,kona-sdhci"; |
| 131 | reg = <0x3f1b0000 0x801c>; | 133 | reg = <0x3f1b0000 0x801c>; |
| 132 | interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; | 134 | interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; |
| 133 | clocks = <&sdio4_clk>; | 135 | clocks = <&master_ccu BCM21664_MASTER_CCU_SDIO4>; |
| 134 | status = "disabled"; | 136 | status = "disabled"; |
| 135 | }; | 137 | }; |
| 136 | 138 | ||
| @@ -140,7 +142,7 @@ | |||
| 140 | interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>; | 142 | interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>; |
| 141 | #address-cells = <1>; | 143 | #address-cells = <1>; |
| 142 | #size-cells = <0>; | 144 | #size-cells = <0>; |
| 143 | clocks = <&bsc1_clk>; | 145 | clocks = <&slave_ccu BCM21664_SLAVE_CCU_BSC1>; |
| 144 | status = "disabled"; | 146 | status = "disabled"; |
| 145 | }; | 147 | }; |
| 146 | 148 | ||
| @@ -150,7 +152,7 @@ | |||
| 150 | interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>; | 152 | interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>; |
| 151 | #address-cells = <1>; | 153 | #address-cells = <1>; |
| 152 | #size-cells = <0>; | 154 | #size-cells = <0>; |
| 153 | clocks = <&bsc2_clk>; | 155 | clocks = <&slave_ccu BCM21664_SLAVE_CCU_BSC2>; |
| 154 | status = "disabled"; | 156 | status = "disabled"; |
| 155 | }; | 157 | }; |
| 156 | 158 | ||
| @@ -160,7 +162,7 @@ | |||
| 160 | interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>; | 162 | interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>; |
| 161 | #address-cells = <1>; | 163 | #address-cells = <1>; |
| 162 | #size-cells = <0>; | 164 | #size-cells = <0>; |
| 163 | clocks = <&bsc3_clk>; | 165 | clocks = <&slave_ccu BCM21664_SLAVE_CCU_BSC3>; |
| 164 | status = "disabled"; | 166 | status = "disabled"; |
| 165 | }; | 167 | }; |
| 166 | 168 | ||
| @@ -170,105 +172,149 @@ | |||
| 170 | interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>; | 172 | interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>; |
| 171 | #address-cells = <1>; | 173 | #address-cells = <1>; |
| 172 | #size-cells = <0>; | 174 | #size-cells = <0>; |
| 173 | clocks = <&bsc4_clk>; | 175 | clocks = <&slave_ccu BCM21664_SLAVE_CCU_BSC4>; |
| 174 | status = "disabled"; | 176 | status = "disabled"; |
| 175 | }; | 177 | }; |
| 176 | 178 | ||
| 177 | clocks { | 179 | clocks { |
| 178 | bsc1_clk: bsc1 { | 180 | #address-cells = <1>; |
| 179 | compatible = "fixed-clock"; | 181 | #size-cells = <1>; |
| 180 | clock-frequency = <13000000>; | 182 | ranges; |
| 181 | #clock-cells = <0>; | ||
| 182 | }; | ||
| 183 | 183 | ||
| 184 | bsc2_clk: bsc2 { | 184 | /* |
| 185 | compatible = "fixed-clock"; | 185 | * Fixed clocks are defined before CCUs whose |
| 186 | clock-frequency = <13000000>; | 186 | * clocks may depend on them. |
| 187 | */ | ||
| 188 | |||
| 189 | ref_32k_clk: ref_32k { | ||
| 187 | #clock-cells = <0>; | 190 | #clock-cells = <0>; |
| 191 | compatible = "fixed-clock"; | ||
| 192 | clock-frequency = <32768>; | ||
| 188 | }; | 193 | }; |
| 189 | 194 | ||
| 190 | bsc3_clk: bsc3 { | 195 | bbl_32k_clk: bbl_32k { |
| 191 | compatible = "fixed-clock"; | ||
| 192 | clock-frequency = <13000000>; | ||
| 193 | #clock-cells = <0>; | 196 | #clock-cells = <0>; |
| 197 | compatible = "fixed-clock"; | ||
| 198 | clock-frequency = <32768>; | ||
| 194 | }; | 199 | }; |
| 195 | 200 | ||
| 196 | bsc4_clk: bsc4 { | 201 | ref_13m_clk: ref_13m { |
| 202 | #clock-cells = <0>; | ||
| 197 | compatible = "fixed-clock"; | 203 | compatible = "fixed-clock"; |
| 198 | clock-frequency = <13000000>; | 204 | clock-frequency = <13000000>; |
| 199 | #clock-cells = <0>; | ||
| 200 | }; | 205 | }; |
| 201 | 206 | ||
| 202 | pmu_bsc_clk: pmu_bsc { | 207 | var_13m_clk: var_13m { |
| 208 | #clock-cells = <0>; | ||
| 203 | compatible = "fixed-clock"; | 209 | compatible = "fixed-clock"; |
| 204 | clock-frequency = <13000000>; | 210 | clock-frequency = <13000000>; |
| 205 | #clock-cells = <0>; | ||
| 206 | }; | 211 | }; |
| 207 | 212 | ||
| 208 | hub_timer_clk: hub_timer { | 213 | dft_19_5m_clk: dft_19_5m { |
| 209 | compatible = "fixed-clock"; | ||
| 210 | clock-frequency = <32768>; | ||
| 211 | #clock-cells = <0>; | 214 | #clock-cells = <0>; |
| 215 | compatible = "fixed-clock"; | ||
| 216 | clock-frequency = <19500000>; | ||
| 212 | }; | 217 | }; |
| 213 | 218 | ||
| 214 | pwm_clk: pwm { | 219 | ref_crystal_clk: ref_crystal { |
| 220 | #clock-cells = <0>; | ||
| 215 | compatible = "fixed-clock"; | 221 | compatible = "fixed-clock"; |
| 216 | clock-frequency = <26000000>; | 222 | clock-frequency = <26000000>; |
| 217 | #clock-cells = <0>; | ||
| 218 | }; | 223 | }; |
| 219 | 224 | ||
| 220 | sdio1_clk: sdio1 { | 225 | ref_52m_clk: ref_52m { |
| 221 | compatible = "fixed-clock"; | ||
| 222 | clock-frequency = <48000000>; | ||
| 223 | #clock-cells = <0>; | 226 | #clock-cells = <0>; |
| 227 | compatible = "fixed-clock"; | ||
| 228 | clock-frequency = <52000000>; | ||
| 224 | }; | 229 | }; |
| 225 | 230 | ||
| 226 | sdio2_clk: sdio2 { | 231 | var_52m_clk: var_52m { |
| 227 | compatible = "fixed-clock"; | ||
| 228 | clock-frequency = <48000000>; | ||
| 229 | #clock-cells = <0>; | 232 | #clock-cells = <0>; |
| 233 | compatible = "fixed-clock"; | ||
| 234 | clock-frequency = <52000000>; | ||
| 230 | }; | 235 | }; |
| 231 | 236 | ||
| 232 | sdio3_clk: sdio3 { | 237 | usb_otg_ahb_clk: usb_otg_ahb { |
| 233 | compatible = "fixed-clock"; | ||
| 234 | clock-frequency = <48000000>; | ||
| 235 | #clock-cells = <0>; | 238 | #clock-cells = <0>; |
| 239 | compatible = "fixed-clock"; | ||
| 240 | clock-frequency = <52000000>; | ||
| 236 | }; | 241 | }; |
| 237 | 242 | ||
| 238 | sdio4_clk: sdio4 { | 243 | ref_96m_clk: ref_96m { |
| 239 | compatible = "fixed-clock"; | ||
| 240 | clock-frequency = <48000000>; | ||
| 241 | #clock-cells = <0>; | 244 | #clock-cells = <0>; |
| 245 | compatible = "fixed-clock"; | ||
| 246 | clock-frequency = <96000000>; | ||
| 242 | }; | 247 | }; |
| 243 | 248 | ||
| 244 | tmon_1m_clk: tmon_1m { | 249 | var_96m_clk: var_96m { |
| 245 | compatible = "fixed-clock"; | ||
| 246 | clock-frequency = <1000000>; | ||
| 247 | #clock-cells = <0>; | 250 | #clock-cells = <0>; |
| 251 | compatible = "fixed-clock"; | ||
| 252 | clock-frequency = <96000000>; | ||
| 248 | }; | 253 | }; |
| 249 | 254 | ||
| 250 | uartb_clk: uartb { | 255 | ref_104m_clk: ref_104m { |
| 251 | compatible = "fixed-clock"; | ||
| 252 | clock-frequency = <13000000>; | ||
| 253 | #clock-cells = <0>; | 256 | #clock-cells = <0>; |
| 257 | compatible = "fixed-clock"; | ||
| 258 | clock-frequency = <104000000>; | ||
| 254 | }; | 259 | }; |
| 255 | 260 | ||
| 256 | uartb2_clk: uartb2 { | 261 | var_104m_clk: var_104m { |
| 257 | compatible = "fixed-clock"; | ||
| 258 | clock-frequency = <13000000>; | ||
| 259 | #clock-cells = <0>; | 262 | #clock-cells = <0>; |
| 263 | compatible = "fixed-clock"; | ||
| 264 | clock-frequency = <104000000>; | ||
| 260 | }; | 265 | }; |
| 261 | 266 | ||
| 262 | uartb3_clk: uartb3 { | 267 | ref_156m_clk: ref_156m { |
| 263 | compatible = "fixed-clock"; | ||
| 264 | clock-frequency = <13000000>; | ||
| 265 | #clock-cells = <0>; | 268 | #clock-cells = <0>; |
| 269 | compatible = "fixed-clock"; | ||
| 270 | clock-frequency = <156000000>; | ||
| 266 | }; | 271 | }; |
| 267 | 272 | ||
| 268 | usb_otg_ahb_clk: usb_otg_ahb { | 273 | var_156m_clk: var_156m { |
| 269 | compatible = "fixed-clock"; | ||
| 270 | clock-frequency = <52000000>; | ||
| 271 | #clock-cells = <0>; | 274 | #clock-cells = <0>; |
| 275 | compatible = "fixed-clock"; | ||
| 276 | clock-frequency = <156000000>; | ||
| 277 | }; | ||
| 278 | |||
| 279 | root_ccu: root_ccu { | ||
| 280 | compatible = BCM21664_DT_ROOT_CCU_COMPAT; | ||
| 281 | reg = <0x35001000 0x0f00>; | ||
| 282 | #clock-cells = <1>; | ||
| 283 | clock-output-names = "frac_1m"; | ||
| 284 | }; | ||
| 285 | |||
| 286 | aon_ccu: aon_ccu { | ||
| 287 | compatible = BCM21664_DT_AON_CCU_COMPAT; | ||
| 288 | reg = <0x35002000 0x0f00>; | ||
| 289 | #clock-cells = <1>; | ||
| 290 | clock-output-names = "hub_timer"; | ||
| 291 | }; | ||
| 292 | |||
| 293 | master_ccu: master_ccu { | ||
| 294 | compatible = BCM21664_DT_MASTER_CCU_COMPAT; | ||
| 295 | reg = <0x3f001000 0x0f00>; | ||
| 296 | #clock-cells = <1>; | ||
| 297 | clock-output-names = "sdio1", | ||
| 298 | "sdio2", | ||
| 299 | "sdio3", | ||
| 300 | "sdio4", | ||
| 301 | "sdio1_sleep", | ||
| 302 | "sdio2_sleep", | ||
| 303 | "sdio3_sleep", | ||
| 304 | "sdio4_sleep"; | ||
| 305 | }; | ||
| 306 | |||
| 307 | slave_ccu: slave_ccu { | ||
| 308 | compatible = BCM21664_DT_SLAVE_CCU_COMPAT; | ||
| 309 | reg = <0x3e011000 0x0f00>; | ||
| 310 | #clock-cells = <1>; | ||
| 311 | clock-output-names = "uartb", | ||
| 312 | "uartb2", | ||
| 313 | "uartb3", | ||
| 314 | "bsc1", | ||
| 315 | "bsc2", | ||
| 316 | "bsc3", | ||
| 317 | "bsc4"; | ||
| 272 | }; | 318 | }; |
| 273 | }; | 319 | }; |
| 274 | 320 | ||
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 3a2196481b11..9f9c5ae5359b 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig | |||
| @@ -58,12 +58,12 @@ config COMMON_CLK_SI570 | |||
| 58 | clock generators. | 58 | clock generators. |
| 59 | 59 | ||
| 60 | config COMMON_CLK_S2MPS11 | 60 | config COMMON_CLK_S2MPS11 |
| 61 | tristate "Clock driver for S2MPS11/S5M8767 MFD" | 61 | tristate "Clock driver for S2MPS1X/S5M8767 MFD" |
| 62 | depends on MFD_SEC_CORE | 62 | depends on MFD_SEC_CORE |
| 63 | ---help--- | 63 | ---help--- |
| 64 | This driver supports S2MPS11/S5M8767 crystal oscillator clock. These | 64 | This driver supports S2MPS11/S2MPS14/S5M8767 crystal oscillator |
| 65 | multi-function devices have 3 fixed-rate oscillators, clocked at | 65 | clock. These multi-function devices have two (S2MPS14) or three |
| 66 | 32KHz each. | 66 | (S2MPS11, S5M8767) fixed-rate oscillators, clocked at 32KHz each. |
| 67 | 67 | ||
| 68 | config CLK_TWL6040 | 68 | config CLK_TWL6040 |
| 69 | tristate "External McPDM functional clock from twl6040" | 69 | tristate "External McPDM functional clock from twl6040" |
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 50b2a7ebd747..567f10259029 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile | |||
| @@ -13,6 +13,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o | |||
| 13 | # hardware specific clock types | 13 | # hardware specific clock types |
| 14 | # please keep this section sorted lexicographically by file/directory path name | 14 | # please keep this section sorted lexicographically by file/directory path name |
| 15 | obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o | 15 | obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o |
| 16 | obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o | ||
| 16 | obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o | 17 | obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o |
| 17 | obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o | 18 | obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o |
| 18 | obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o | 19 | obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o |
| @@ -32,8 +33,10 @@ obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o | |||
| 32 | obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o | 33 | obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o |
| 33 | obj-$(CONFIG_COMMON_CLK_AT91) += at91/ | 34 | obj-$(CONFIG_COMMON_CLK_AT91) += at91/ |
| 34 | obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/ | 35 | obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/ |
| 36 | obj-$(CONFIG_ARCH_BERLIN) += berlin/ | ||
| 35 | obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ | 37 | obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ |
| 36 | obj-$(CONFIG_ARCH_HIP04) += hisilicon/ | 38 | obj-$(CONFIG_ARCH_HIP04) += hisilicon/ |
| 39 | obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/ | ||
| 37 | obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ | 40 | obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ |
| 38 | ifeq ($(CONFIG_COMMON_CLK), y) | 41 | ifeq ($(CONFIG_COMMON_CLK), y) |
| 39 | obj-$(CONFIG_ARCH_MMP) += mmp/ | 42 | obj-$(CONFIG_ARCH_MMP) += mmp/ |
diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig index a7262fb8ce55..75506e53075b 100644 --- a/drivers/clk/bcm/Kconfig +++ b/drivers/clk/bcm/Kconfig | |||
| @@ -6,4 +6,4 @@ config CLK_BCM_KONA | |||
| 6 | help | 6 | help |
| 7 | Enable common clock framework support for Broadcom SoCs | 7 | Enable common clock framework support for Broadcom SoCs |
| 8 | using "Kona" style clock control units, including those | 8 | using "Kona" style clock control units, including those |
| 9 | in the BCM281xx family. | 9 | in the BCM281xx and BCM21664 families. |
diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile index cf93359aa862..6297d05a9a10 100644 --- a/drivers/clk/bcm/Makefile +++ b/drivers/clk/bcm/Makefile | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o | 1 | obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o |
| 2 | obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o | 2 | obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o |
| 3 | obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o | 3 | obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o |
| 4 | 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 000000000000..eeae4cad2281 --- /dev/null +++ b/drivers/clk/bcm/clk-bcm21664.c | |||
| @@ -0,0 +1,290 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2014 Broadcom Corporation | ||
| 3 | * Copyright 2014 Linaro Limited | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License as | ||
| 7 | * published by the Free Software Foundation version 2. | ||
| 8 | * | ||
| 9 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
| 10 | * kind, whether express or implied; without even the implied warranty | ||
| 11 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include "clk-kona.h" | ||
| 16 | #include "dt-bindings/clock/bcm21664.h" | ||
| 17 | |||
| 18 | #define BCM21664_CCU_COMMON(_name, _capname) \ | ||
| 19 | KONA_CCU_COMMON(BCM21664, _name, _capname) | ||
| 20 | |||
| 21 | /* Root CCU */ | ||
| 22 | |||
| 23 | static struct peri_clk_data frac_1m_data = { | ||
| 24 | .gate = HW_SW_GATE(0x214, 16, 0, 1), | ||
| 25 | .clocks = CLOCKS("ref_crystal"), | ||
| 26 | }; | ||
| 27 | |||
| 28 | static struct ccu_data root_ccu_data = { | ||
| 29 | BCM21664_CCU_COMMON(root, ROOT), | ||
| 30 | /* no policy control */ | ||
| 31 | .kona_clks = { | ||
| 32 | [BCM21664_ROOT_CCU_FRAC_1M] = | ||
| 33 | KONA_CLK(root, frac_1m, peri), | ||
| 34 | [BCM21664_ROOT_CCU_CLOCK_COUNT] = LAST_KONA_CLK, | ||
| 35 | }, | ||
| 36 | }; | ||
| 37 | |||
| 38 | /* AON CCU */ | ||
| 39 | |||
| 40 | static struct peri_clk_data hub_timer_data = { | ||
| 41 | .gate = HW_SW_GATE(0x0414, 16, 0, 1), | ||
| 42 | .hyst = HYST(0x0414, 8, 9), | ||
| 43 | .clocks = CLOCKS("bbl_32k", | ||
| 44 | "frac_1m", | ||
| 45 | "dft_19_5m"), | ||
| 46 | .sel = SELECTOR(0x0a10, 0, 2), | ||
| 47 | .trig = TRIGGER(0x0a40, 4), | ||
| 48 | }; | ||
| 49 | |||
| 50 | static struct ccu_data aon_ccu_data = { | ||
| 51 | BCM21664_CCU_COMMON(aon, AON), | ||
| 52 | .policy = { | ||
| 53 | .enable = CCU_LVM_EN(0x0034, 0), | ||
| 54 | .control = CCU_POLICY_CTL(0x000c, 0, 1, 2), | ||
| 55 | }, | ||
| 56 | .kona_clks = { | ||
| 57 | [BCM21664_AON_CCU_HUB_TIMER] = | ||
| 58 | KONA_CLK(aon, hub_timer, peri), | ||
| 59 | [BCM21664_AON_CCU_CLOCK_COUNT] = LAST_KONA_CLK, | ||
| 60 | }, | ||
| 61 | }; | ||
| 62 | |||
| 63 | /* Master CCU */ | ||
| 64 | |||
| 65 | static struct peri_clk_data sdio1_data = { | ||
| 66 | .gate = HW_SW_GATE(0x0358, 18, 2, 3), | ||
| 67 | .clocks = CLOCKS("ref_crystal", | ||
| 68 | "var_52m", | ||
| 69 | "ref_52m", | ||
| 70 | "var_96m", | ||
| 71 | "ref_96m"), | ||
| 72 | .sel = SELECTOR(0x0a28, 0, 3), | ||
| 73 | .div = DIVIDER(0x0a28, 4, 14), | ||
| 74 | .trig = TRIGGER(0x0afc, 9), | ||
| 75 | }; | ||
| 76 | |||
| 77 | static struct peri_clk_data sdio2_data = { | ||
| 78 | .gate = HW_SW_GATE(0x035c, 18, 2, 3), | ||
| 79 | .clocks = CLOCKS("ref_crystal", | ||
| 80 | "var_52m", | ||
| 81 | "ref_52m", | ||
| 82 | "var_96m", | ||
| 83 | "ref_96m"), | ||
| 84 | .sel = SELECTOR(0x0a2c, 0, 3), | ||
| 85 | .div = DIVIDER(0x0a2c, 4, 14), | ||
| 86 | .trig = TRIGGER(0x0afc, 10), | ||
| 87 | }; | ||
| 88 | |||
| 89 | static struct peri_clk_data sdio3_data = { | ||
| 90 | .gate = HW_SW_GATE(0x0364, 18, 2, 3), | ||
| 91 | .clocks = CLOCKS("ref_crystal", | ||
| 92 | "var_52m", | ||
| 93 | "ref_52m", | ||
| 94 | "var_96m", | ||
| 95 | "ref_96m"), | ||
| 96 | .sel = SELECTOR(0x0a34, 0, 3), | ||
| 97 | .div = DIVIDER(0x0a34, 4, 14), | ||
| 98 | .trig = TRIGGER(0x0afc, 12), | ||
| 99 | }; | ||
| 100 | |||
| 101 | static struct peri_clk_data sdio4_data = { | ||
| 102 | .gate = HW_SW_GATE(0x0360, 18, 2, 3), | ||
| 103 | .clocks = CLOCKS("ref_crystal", | ||
| 104 | "var_52m", | ||
| 105 | "ref_52m", | ||
| 106 | "var_96m", | ||
| 107 | "ref_96m"), | ||
| 108 | .sel = SELECTOR(0x0a30, 0, 3), | ||
| 109 | .div = DIVIDER(0x0a30, 4, 14), | ||
| 110 | .trig = TRIGGER(0x0afc, 11), | ||
| 111 | }; | ||
| 112 | |||
| 113 | static struct peri_clk_data sdio1_sleep_data = { | ||
| 114 | .clocks = CLOCKS("ref_32k"), /* Verify */ | ||
| 115 | .gate = HW_SW_GATE(0x0358, 18, 2, 3), | ||
| 116 | }; | ||
| 117 | |||
| 118 | static struct peri_clk_data sdio2_sleep_data = { | ||
| 119 | .clocks = CLOCKS("ref_32k"), /* Verify */ | ||
| 120 | .gate = HW_SW_GATE(0x035c, 18, 2, 3), | ||
| 121 | }; | ||
| 122 | |||
| 123 | static struct peri_clk_data sdio3_sleep_data = { | ||
| 124 | .clocks = CLOCKS("ref_32k"), /* Verify */ | ||
| 125 | .gate = HW_SW_GATE(0x0364, 18, 2, 3), | ||
| 126 | }; | ||
| 127 | |||
| 128 | static struct peri_clk_data sdio4_sleep_data = { | ||
| 129 | .clocks = CLOCKS("ref_32k"), /* Verify */ | ||
| 130 | .gate = HW_SW_GATE(0x0360, 18, 2, 3), | ||
| 131 | }; | ||
| 132 | |||
| 133 | static struct ccu_data master_ccu_data = { | ||
| 134 | BCM21664_CCU_COMMON(master, MASTER), | ||
| 135 | .policy = { | ||
| 136 | .enable = CCU_LVM_EN(0x0034, 0), | ||
| 137 | .control = CCU_POLICY_CTL(0x000c, 0, 1, 2), | ||
| 138 | }, | ||
| 139 | .kona_clks = { | ||
| 140 | [BCM21664_MASTER_CCU_SDIO1] = | ||
| 141 | KONA_CLK(master, sdio1, peri), | ||
| 142 | [BCM21664_MASTER_CCU_SDIO2] = | ||
| 143 | KONA_CLK(master, sdio2, peri), | ||
| 144 | [BCM21664_MASTER_CCU_SDIO3] = | ||
| 145 | KONA_CLK(master, sdio3, peri), | ||
| 146 | [BCM21664_MASTER_CCU_SDIO4] = | ||
| 147 | KONA_CLK(master, sdio4, peri), | ||
| 148 | [BCM21664_MASTER_CCU_SDIO1_SLEEP] = | ||
| 149 | KONA_CLK(master, sdio1_sleep, peri), | ||
| 150 | [BCM21664_MASTER_CCU_SDIO2_SLEEP] = | ||
| 151 | KONA_CLK(master, sdio2_sleep, peri), | ||
| 152 | [BCM21664_MASTER_CCU_SDIO3_SLEEP] = | ||
| 153 | KONA_CLK(master, sdio3_sleep, peri), | ||
| 154 | [BCM21664_MASTER_CCU_SDIO4_SLEEP] = | ||
| 155 | KONA_CLK(master, sdio4_sleep, peri), | ||
| 156 | [BCM21664_MASTER_CCU_CLOCK_COUNT] = LAST_KONA_CLK, | ||
| 157 | }, | ||
| 158 | }; | ||
| 159 | |||
| 160 | /* Slave CCU */ | ||
| 161 | |||
| 162 | static struct peri_clk_data uartb_data = { | ||
| 163 | .gate = HW_SW_GATE(0x0400, 18, 2, 3), | ||
| 164 | .clocks = CLOCKS("ref_crystal", | ||
| 165 | "var_156m", | ||
| 166 | "ref_156m"), | ||
| 167 | .sel = SELECTOR(0x0a10, 0, 2), | ||
| 168 | .div = FRAC_DIVIDER(0x0a10, 4, 12, 8), | ||
| 169 | .trig = TRIGGER(0x0afc, 2), | ||
| 170 | }; | ||
| 171 | |||
| 172 | static struct peri_clk_data uartb2_data = { | ||
| 173 | .gate = HW_SW_GATE(0x0404, 18, 2, 3), | ||
| 174 | .clocks = CLOCKS("ref_crystal", | ||
| 175 | "var_156m", | ||
| 176 | "ref_156m"), | ||
| 177 | .sel = SELECTOR(0x0a14, 0, 2), | ||
| 178 | .div = FRAC_DIVIDER(0x0a14, 4, 12, 8), | ||
| 179 | .trig = TRIGGER(0x0afc, 3), | ||
| 180 | }; | ||
| 181 | |||
| 182 | static struct peri_clk_data uartb3_data = { | ||
| 183 | .gate = HW_SW_GATE(0x0408, 18, 2, 3), | ||
| 184 | .clocks = CLOCKS("ref_crystal", | ||
| 185 | "var_156m", | ||
| 186 | "ref_156m"), | ||
| 187 | .sel = SELECTOR(0x0a18, 0, 2), | ||
| 188 | .div = FRAC_DIVIDER(0x0a18, 4, 12, 8), | ||
| 189 | .trig = TRIGGER(0x0afc, 4), | ||
| 190 | }; | ||
| 191 | |||
| 192 | static struct peri_clk_data bsc1_data = { | ||
| 193 | .gate = HW_SW_GATE(0x0458, 18, 2, 3), | ||
| 194 | .clocks = CLOCKS("ref_crystal", | ||
| 195 | "var_104m", | ||
| 196 | "ref_104m", | ||
| 197 | "var_13m", | ||
| 198 | "ref_13m"), | ||
| 199 | .sel = SELECTOR(0x0a64, 0, 3), | ||
| 200 | .trig = TRIGGER(0x0afc, 23), | ||
| 201 | }; | ||
| 202 | |||
| 203 | static struct peri_clk_data bsc2_data = { | ||
| 204 | .gate = HW_SW_GATE(0x045c, 18, 2, 3), | ||
| 205 | .clocks = CLOCKS("ref_crystal", | ||
| 206 | "var_104m", | ||
| 207 | "ref_104m", | ||
| 208 | "var_13m", | ||
| 209 | "ref_13m"), | ||
| 210 | .sel = SELECTOR(0x0a68, 0, 3), | ||
| 211 | .trig = TRIGGER(0x0afc, 24), | ||
| 212 | }; | ||
| 213 | |||
| 214 | static struct peri_clk_data bsc3_data = { | ||
| 215 | .gate = HW_SW_GATE(0x0470, 18, 2, 3), | ||
| 216 | .clocks = CLOCKS("ref_crystal", | ||
| 217 | "var_104m", | ||
| 218 | "ref_104m", | ||
| 219 | "var_13m", | ||
| 220 | "ref_13m"), | ||
| 221 | .sel = SELECTOR(0x0a7c, 0, 3), | ||
| 222 | .trig = TRIGGER(0x0afc, 18), | ||
| 223 | }; | ||
| 224 | |||
| 225 | static struct peri_clk_data bsc4_data = { | ||
| 226 | .gate = HW_SW_GATE(0x0474, 18, 2, 3), | ||
| 227 | .clocks = CLOCKS("ref_crystal", | ||
| 228 | "var_104m", | ||
| 229 | "ref_104m", | ||
| 230 | "var_13m", | ||
| 231 | "ref_13m"), | ||
| 232 | .sel = SELECTOR(0x0a80, 0, 3), | ||
| 233 | .trig = TRIGGER(0x0afc, 19), | ||
| 234 | }; | ||
| 235 | |||
| 236 | static struct ccu_data slave_ccu_data = { | ||
| 237 | BCM21664_CCU_COMMON(slave, SLAVE), | ||
| 238 | .policy = { | ||
| 239 | .enable = CCU_LVM_EN(0x0034, 0), | ||
| 240 | .control = CCU_POLICY_CTL(0x000c, 0, 1, 2), | ||
| 241 | }, | ||
| 242 | .kona_clks = { | ||
| 243 | [BCM21664_SLAVE_CCU_UARTB] = | ||
| 244 | KONA_CLK(slave, uartb, peri), | ||
| 245 | [BCM21664_SLAVE_CCU_UARTB2] = | ||
| 246 | KONA_CLK(slave, uartb2, peri), | ||
| 247 | [BCM21664_SLAVE_CCU_UARTB3] = | ||
| 248 | KONA_CLK(slave, uartb3, peri), | ||
| 249 | [BCM21664_SLAVE_CCU_BSC1] = | ||
| 250 | KONA_CLK(slave, bsc1, peri), | ||
| 251 | [BCM21664_SLAVE_CCU_BSC2] = | ||
| 252 | KONA_CLK(slave, bsc2, peri), | ||
| 253 | [BCM21664_SLAVE_CCU_BSC3] = | ||
| 254 | KONA_CLK(slave, bsc3, peri), | ||
| 255 | [BCM21664_SLAVE_CCU_BSC4] = | ||
| 256 | KONA_CLK(slave, bsc4, peri), | ||
| 257 | [BCM21664_SLAVE_CCU_CLOCK_COUNT] = LAST_KONA_CLK, | ||
| 258 | }, | ||
| 259 | }; | ||
| 260 | |||
| 261 | /* Device tree match table callback functions */ | ||
| 262 | |||
| 263 | static void __init kona_dt_root_ccu_setup(struct device_node *node) | ||
| 264 | { | ||
| 265 | kona_dt_ccu_setup(&root_ccu_data, node); | ||
| 266 | } | ||
| 267 | |||
| 268 | static void __init kona_dt_aon_ccu_setup(struct device_node *node) | ||
| 269 | { | ||
| 270 | kona_dt_ccu_setup(&aon_ccu_data, node); | ||
| 271 | } | ||
| 272 | |||
| 273 | static void __init kona_dt_master_ccu_setup(struct device_node *node) | ||
| 274 | { | ||
| 275 | kona_dt_ccu_setup(&master_ccu_data, node); | ||
| 276 | } | ||
| 277 | |||
| 278 | static void __init kona_dt_slave_ccu_setup(struct device_node *node) | ||
| 279 | { | ||
| 280 | kona_dt_ccu_setup(&slave_ccu_data, node); | ||
| 281 | } | ||
| 282 | |||
| 283 | CLK_OF_DECLARE(bcm21664_root_ccu, BCM21664_DT_ROOT_CCU_COMPAT, | ||
| 284 | kona_dt_root_ccu_setup); | ||
| 285 | CLK_OF_DECLARE(bcm21664_aon_ccu, BCM21664_DT_AON_CCU_COMPAT, | ||
| 286 | kona_dt_aon_ccu_setup); | ||
| 287 | CLK_OF_DECLARE(bcm21664_master_ccu, BCM21664_DT_MASTER_CCU_COMPAT, | ||
| 288 | kona_dt_master_ccu_setup); | ||
| 289 | CLK_OF_DECLARE(bcm21664_slave_ccu, BCM21664_DT_SLAVE_CCU_COMPAT, | ||
| 290 | kona_dt_slave_ccu_setup); | ||
diff --git a/drivers/clk/bcm/clk-bcm281xx.c b/drivers/clk/bcm/clk-bcm281xx.c index 3c66de696aeb..502a487d62c5 100644 --- a/drivers/clk/bcm/clk-bcm281xx.c +++ b/drivers/clk/bcm/clk-bcm281xx.c | |||
| @@ -15,14 +15,10 @@ | |||
| 15 | #include "clk-kona.h" | 15 | #include "clk-kona.h" |
| 16 | #include "dt-bindings/clock/bcm281xx.h" | 16 | #include "dt-bindings/clock/bcm281xx.h" |
| 17 | 17 | ||
| 18 | /* bcm11351 CCU device tree "compatible" strings */ | 18 | #define BCM281XX_CCU_COMMON(_name, _ucase_name) \ |
| 19 | #define BCM11351_DT_ROOT_CCU_COMPAT "brcm,bcm11351-root-ccu" | 19 | KONA_CCU_COMMON(BCM281XX, _name, _ucase_name) |
| 20 | #define BCM11351_DT_AON_CCU_COMPAT "brcm,bcm11351-aon-ccu" | ||
| 21 | #define BCM11351_DT_HUB_CCU_COMPAT "brcm,bcm11351-hub-ccu" | ||
| 22 | #define BCM11351_DT_MASTER_CCU_COMPAT "brcm,bcm11351-master-ccu" | ||
| 23 | #define BCM11351_DT_SLAVE_CCU_COMPAT "brcm,bcm11351-slave-ccu" | ||
| 24 | 20 | ||
| 25 | /* Root CCU clocks */ | 21 | /* Root CCU */ |
| 26 | 22 | ||
| 27 | static struct peri_clk_data frac_1m_data = { | 23 | static struct peri_clk_data frac_1m_data = { |
| 28 | .gate = HW_SW_GATE(0x214, 16, 0, 1), | 24 | .gate = HW_SW_GATE(0x214, 16, 0, 1), |
| @@ -31,7 +27,16 @@ static struct peri_clk_data frac_1m_data = { | |||
| 31 | .clocks = CLOCKS("ref_crystal"), | 27 | .clocks = CLOCKS("ref_crystal"), |
| 32 | }; | 28 | }; |
| 33 | 29 | ||
| 34 | /* AON CCU clocks */ | 30 | static struct ccu_data root_ccu_data = { |
| 31 | BCM281XX_CCU_COMMON(root, ROOT), | ||
| 32 | .kona_clks = { | ||
| 33 | [BCM281XX_ROOT_CCU_FRAC_1M] = | ||
| 34 | KONA_CLK(root, frac_1m, peri), | ||
| 35 | [BCM281XX_ROOT_CCU_CLOCK_COUNT] = LAST_KONA_CLK, | ||
| 36 | }, | ||
| 37 | }; | ||
| 38 | |||
| 39 | /* AON CCU */ | ||
| 35 | 40 | ||
| 36 | static struct peri_clk_data hub_timer_data = { | 41 | static struct peri_clk_data hub_timer_data = { |
| 37 | .gate = HW_SW_GATE(0x0414, 16, 0, 1), | 42 | .gate = HW_SW_GATE(0x0414, 16, 0, 1), |
| @@ -60,7 +65,20 @@ static struct peri_clk_data pmu_bsc_var_data = { | |||
| 60 | .trig = TRIGGER(0x0a40, 2), | 65 | .trig = TRIGGER(0x0a40, 2), |
| 61 | }; | 66 | }; |
| 62 | 67 | ||
| 63 | /* Hub CCU clocks */ | 68 | static struct ccu_data aon_ccu_data = { |
| 69 | BCM281XX_CCU_COMMON(aon, AON), | ||
| 70 | .kona_clks = { | ||
| 71 | [BCM281XX_AON_CCU_HUB_TIMER] = | ||
| 72 | KONA_CLK(aon, hub_timer, peri), | ||
| 73 | [BCM281XX_AON_CCU_PMU_BSC] = | ||
| 74 | KONA_CLK(aon, pmu_bsc, peri), | ||
| 75 | [BCM281XX_AON_CCU_PMU_BSC_VAR] = | ||
| 76 | KONA_CLK(aon, pmu_bsc_var, peri), | ||
| 77 | [BCM281XX_AON_CCU_CLOCK_COUNT] = LAST_KONA_CLK, | ||
| 78 | }, | ||
| 79 | }; | ||
| 80 | |||
| 81 | /* Hub CCU */ | ||
| 64 | 82 | ||
| 65 | static struct peri_clk_data tmon_1m_data = { | 83 | static struct peri_clk_data tmon_1m_data = { |
| 66 | .gate = HW_SW_GATE(0x04a4, 18, 2, 3), | 84 | .gate = HW_SW_GATE(0x04a4, 18, 2, 3), |
| @@ -70,7 +88,16 @@ static struct peri_clk_data tmon_1m_data = { | |||
| 70 | .trig = TRIGGER(0x0e84, 1), | 88 | .trig = TRIGGER(0x0e84, 1), |
| 71 | }; | 89 | }; |
| 72 | 90 | ||
| 73 | /* Master CCU clocks */ | 91 | static struct ccu_data hub_ccu_data = { |
| 92 | BCM281XX_CCU_COMMON(hub, HUB), | ||
| 93 | .kona_clks = { | ||
| 94 | [BCM281XX_HUB_CCU_TMON_1M] = | ||
| 95 | KONA_CLK(hub, tmon_1m, peri), | ||
| 96 | [BCM281XX_HUB_CCU_CLOCK_COUNT] = LAST_KONA_CLK, | ||
| 97 | }, | ||
| 98 | }; | ||
| 99 | |||
| 100 | /* Master CCU */ | ||
| 74 | 101 | ||
| 75 | static struct peri_clk_data sdio1_data = { | 102 | static struct peri_clk_data sdio1_data = { |
| 76 | .gate = HW_SW_GATE(0x0358, 18, 2, 3), | 103 | .gate = HW_SW_GATE(0x0358, 18, 2, 3), |
| @@ -153,7 +180,28 @@ static struct peri_clk_data hsic2_12m_data = { | |||
| 153 | .trig = TRIGGER(0x0afc, 5), | 180 | .trig = TRIGGER(0x0afc, 5), |
| 154 | }; | 181 | }; |
| 155 | 182 | ||
| 156 | /* Slave CCU clocks */ | 183 | static struct ccu_data master_ccu_data = { |
| 184 | BCM281XX_CCU_COMMON(master, MASTER), | ||
| 185 | .kona_clks = { | ||
| 186 | [BCM281XX_MASTER_CCU_SDIO1] = | ||
| 187 | KONA_CLK(master, sdio1, peri), | ||
| 188 | [BCM281XX_MASTER_CCU_SDIO2] = | ||
| 189 | KONA_CLK(master, sdio2, peri), | ||
| 190 | [BCM281XX_MASTER_CCU_SDIO3] = | ||
| 191 | KONA_CLK(master, sdio3, peri), | ||
| 192 | [BCM281XX_MASTER_CCU_SDIO4] = | ||
| 193 | KONA_CLK(master, sdio4, peri), | ||
| 194 | [BCM281XX_MASTER_CCU_USB_IC] = | ||
| 195 | KONA_CLK(master, usb_ic, peri), | ||
| 196 | [BCM281XX_MASTER_CCU_HSIC2_48M] = | ||
| 197 | KONA_CLK(master, hsic2_48m, peri), | ||
| 198 | [BCM281XX_MASTER_CCU_HSIC2_12M] = | ||
| 199 | KONA_CLK(master, hsic2_12m, peri), | ||
| 200 | [BCM281XX_MASTER_CCU_CLOCK_COUNT] = LAST_KONA_CLK, | ||
| 201 | }, | ||
| 202 | }; | ||
| 203 | |||
| 204 | /* Slave CCU */ | ||
| 157 | 205 | ||
| 158 | static struct peri_clk_data uartb_data = { | 206 | static struct peri_clk_data uartb_data = { |
| 159 | .gate = HW_SW_GATE(0x0400, 18, 2, 3), | 207 | .gate = HW_SW_GATE(0x0400, 18, 2, 3), |
| @@ -261,156 +309,67 @@ static struct peri_clk_data pwm_data = { | |||
| 261 | .trig = TRIGGER(0x0afc, 15), | 309 | .trig = TRIGGER(0x0afc, 15), |
| 262 | }; | 310 | }; |
| 263 | 311 | ||
| 264 | /* | 312 | static struct ccu_data slave_ccu_data = { |
| 265 | * CCU setup routines | 313 | BCM281XX_CCU_COMMON(slave, SLAVE), |
| 266 | * | 314 | .kona_clks = { |
| 267 | * These are called from kona_dt_ccu_setup() to initialize the array | 315 | [BCM281XX_SLAVE_CCU_UARTB] = |
| 268 | * of clocks provided by the CCU. Once allocated, the entries in | 316 | KONA_CLK(slave, uartb, peri), |
| 269 | * the array are initialized by calling kona_clk_setup() with the | 317 | [BCM281XX_SLAVE_CCU_UARTB2] = |
| 270 | * initialization data for each clock. They return 0 if successful | 318 | KONA_CLK(slave, uartb2, peri), |
| 271 | * or an error code otherwise. | 319 | [BCM281XX_SLAVE_CCU_UARTB3] = |
| 272 | */ | 320 | KONA_CLK(slave, uartb3, peri), |
| 273 | static int __init bcm281xx_root_ccu_clks_setup(struct ccu_data *ccu) | 321 | [BCM281XX_SLAVE_CCU_UARTB4] = |
| 274 | { | 322 | KONA_CLK(slave, uartb4, peri), |
| 275 | struct clk **clks; | 323 | [BCM281XX_SLAVE_CCU_SSP0] = |
| 276 | size_t count = BCM281XX_ROOT_CCU_CLOCK_COUNT; | 324 | KONA_CLK(slave, ssp0, peri), |
| 277 | 325 | [BCM281XX_SLAVE_CCU_SSP2] = | |
| 278 | clks = kzalloc(count * sizeof(*clks), GFP_KERNEL); | 326 | KONA_CLK(slave, ssp2, peri), |
| 279 | if (!clks) { | 327 | [BCM281XX_SLAVE_CCU_BSC1] = |
| 280 | pr_err("%s: failed to allocate root clocks\n", __func__); | 328 | KONA_CLK(slave, bsc1, peri), |
| 281 | return -ENOMEM; | 329 | [BCM281XX_SLAVE_CCU_BSC2] = |
| 282 | } | 330 | KONA_CLK(slave, bsc2, peri), |
| 283 | ccu->data.clks = clks; | 331 | [BCM281XX_SLAVE_CCU_BSC3] = |
| 284 | ccu->data.clk_num = count; | 332 | KONA_CLK(slave, bsc3, peri), |
| 285 | 333 | [BCM281XX_SLAVE_CCU_PWM] = | |
| 286 | PERI_CLK_SETUP(clks, ccu, BCM281XX_ROOT_CCU_FRAC_1M, frac_1m); | 334 | KONA_CLK(slave, pwm, peri), |
| 287 | 335 | [BCM281XX_SLAVE_CCU_CLOCK_COUNT] = LAST_KONA_CLK, | |
| 288 | return 0; | 336 | }, |
| 289 | } | 337 | }; |
| 290 | |||
| 291 | static int __init bcm281xx_aon_ccu_clks_setup(struct ccu_data *ccu) | ||
| 292 | { | ||
| 293 | struct clk **clks; | ||
| 294 | size_t count = BCM281XX_AON_CCU_CLOCK_COUNT; | ||
| 295 | |||
| 296 | clks = kzalloc(count * sizeof(*clks), GFP_KERNEL); | ||
| 297 | if (!clks) { | ||
| 298 | pr_err("%s: failed to allocate aon clocks\n", __func__); | ||
| 299 | return -ENOMEM; | ||
| 300 | } | ||
| 301 | ccu->data.clks = clks; | ||
| 302 | ccu->data.clk_num = count; | ||
| 303 | |||
| 304 | PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_HUB_TIMER, hub_timer); | ||
| 305 | PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_PMU_BSC, pmu_bsc); | ||
| 306 | PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_PMU_BSC_VAR, pmu_bsc_var); | ||
| 307 | |||
| 308 | return 0; | ||
| 309 | } | ||
| 310 | |||
| 311 | static int __init bcm281xx_hub_ccu_clks_setup(struct ccu_data *ccu) | ||
| 312 | { | ||
| 313 | struct clk **clks; | ||
| 314 | size_t count = BCM281XX_HUB_CCU_CLOCK_COUNT; | ||
| 315 | |||
| 316 | clks = kzalloc(count * sizeof(*clks), GFP_KERNEL); | ||
| 317 | if (!clks) { | ||
| 318 | pr_err("%s: failed to allocate hub clocks\n", __func__); | ||
| 319 | return -ENOMEM; | ||
| 320 | } | ||
| 321 | ccu->data.clks = clks; | ||
| 322 | ccu->data.clk_num = count; | ||
| 323 | |||
| 324 | PERI_CLK_SETUP(clks, ccu, BCM281XX_HUB_CCU_TMON_1M, tmon_1m); | ||
| 325 | |||
| 326 | return 0; | ||
| 327 | } | ||
| 328 | |||
| 329 | static int __init bcm281xx_master_ccu_clks_setup(struct ccu_data *ccu) | ||
| 330 | { | ||
| 331 | struct clk **clks; | ||
| 332 | size_t count = BCM281XX_MASTER_CCU_CLOCK_COUNT; | ||
| 333 | |||
| 334 | clks = kzalloc(count * sizeof(*clks), GFP_KERNEL); | ||
| 335 | if (!clks) { | ||
| 336 | pr_err("%s: failed to allocate master clocks\n", __func__); | ||
| 337 | return -ENOMEM; | ||
| 338 | } | ||
| 339 | ccu->data.clks = clks; | ||
| 340 | ccu->data.clk_num = count; | ||
| 341 | |||
| 342 | PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO1, sdio1); | ||
| 343 | PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO2, sdio2); | ||
| 344 | PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO3, sdio3); | ||
| 345 | PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO4, sdio4); | ||
| 346 | PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_USB_IC, usb_ic); | ||
| 347 | PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_HSIC2_48M, hsic2_48m); | ||
| 348 | PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_HSIC2_12M, hsic2_12m); | ||
| 349 | |||
| 350 | return 0; | ||
| 351 | } | ||
| 352 | |||
| 353 | static int __init bcm281xx_slave_ccu_clks_setup(struct ccu_data *ccu) | ||
| 354 | { | ||
| 355 | struct clk **clks; | ||
| 356 | size_t count = BCM281XX_SLAVE_CCU_CLOCK_COUNT; | ||
| 357 | |||
| 358 | clks = kzalloc(count * sizeof(*clks), GFP_KERNEL); | ||
| 359 | if (!clks) { | ||
| 360 | pr_err("%s: failed to allocate slave clocks\n", __func__); | ||
| 361 | return -ENOMEM; | ||
| 362 | } | ||
| 363 | ccu->data.clks = clks; | ||
| 364 | ccu->data.clk_num = count; | ||
| 365 | |||
| 366 | PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB, uartb); | ||
| 367 | PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB2, uartb2); | ||
| 368 | PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB3, uartb3); | ||
| 369 | PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB4, uartb4); | ||
| 370 | PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_SSP0, ssp0); | ||
| 371 | PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_SSP2, ssp2); | ||
| 372 | PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC1, bsc1); | ||
| 373 | PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC2, bsc2); | ||
| 374 | PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC3, bsc3); | ||
| 375 | PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_PWM, pwm); | ||
| 376 | |||
| 377 | return 0; | ||
| 378 | } | ||
| 379 | 338 | ||
| 380 | /* Device tree match table callback functions */ | 339 | /* Device tree match table callback functions */ |
| 381 | 340 | ||
| 382 | static void __init kona_dt_root_ccu_setup(struct device_node *node) | 341 | static void __init kona_dt_root_ccu_setup(struct device_node *node) |
| 383 | { | 342 | { |
| 384 | kona_dt_ccu_setup(node, bcm281xx_root_ccu_clks_setup); | 343 | kona_dt_ccu_setup(&root_ccu_data, node); |
| 385 | } | 344 | } |
| 386 | 345 | ||
| 387 | static void __init kona_dt_aon_ccu_setup(struct device_node *node) | 346 | static void __init kona_dt_aon_ccu_setup(struct device_node *node) |
| 388 | { | 347 | { |
| 389 | kona_dt_ccu_setup(node, bcm281xx_aon_ccu_clks_setup); | 348 | kona_dt_ccu_setup(&aon_ccu_data, node); |
| 390 | } | 349 | } |
| 391 | 350 | ||
| 392 | static void __init kona_dt_hub_ccu_setup(struct device_node *node) | 351 | static void __init kona_dt_hub_ccu_setup(struct device_node *node) |
| 393 | { | 352 | { |
| 394 | kona_dt_ccu_setup(node, bcm281xx_hub_ccu_clks_setup); | 353 | kona_dt_ccu_setup(&hub_ccu_data, node); |
| 395 | } | 354 | } |
| 396 | 355 | ||
| 397 | static void __init kona_dt_master_ccu_setup(struct device_node *node) | 356 | static void __init kona_dt_master_ccu_setup(struct device_node *node) |
| 398 | { | 357 | { |
| 399 | kona_dt_ccu_setup(node, bcm281xx_master_ccu_clks_setup); | 358 | kona_dt_ccu_setup(&master_ccu_data, node); |
| 400 | } | 359 | } |
| 401 | 360 | ||
| 402 | static void __init kona_dt_slave_ccu_setup(struct device_node *node) | 361 | static void __init kona_dt_slave_ccu_setup(struct device_node *node) |
| 403 | { | 362 | { |
| 404 | kona_dt_ccu_setup(node, bcm281xx_slave_ccu_clks_setup); | 363 | kona_dt_ccu_setup(&slave_ccu_data, node); |
| 405 | } | 364 | } |
| 406 | 365 | ||
| 407 | CLK_OF_DECLARE(bcm11351_root_ccu, BCM11351_DT_ROOT_CCU_COMPAT, | 366 | CLK_OF_DECLARE(bcm281xx_root_ccu, BCM281XX_DT_ROOT_CCU_COMPAT, |
| 408 | kona_dt_root_ccu_setup); | 367 | kona_dt_root_ccu_setup); |
| 409 | CLK_OF_DECLARE(bcm11351_aon_ccu, BCM11351_DT_AON_CCU_COMPAT, | 368 | CLK_OF_DECLARE(bcm281xx_aon_ccu, BCM281XX_DT_AON_CCU_COMPAT, |
| 410 | kona_dt_aon_ccu_setup); | 369 | kona_dt_aon_ccu_setup); |
| 411 | CLK_OF_DECLARE(bcm11351_hub_ccu, BCM11351_DT_HUB_CCU_COMPAT, | 370 | CLK_OF_DECLARE(bcm281xx_hub_ccu, BCM281XX_DT_HUB_CCU_COMPAT, |
| 412 | kona_dt_hub_ccu_setup); | 371 | kona_dt_hub_ccu_setup); |
| 413 | CLK_OF_DECLARE(bcm11351_master_ccu, BCM11351_DT_MASTER_CCU_COMPAT, | 372 | CLK_OF_DECLARE(bcm281xx_master_ccu, BCM281XX_DT_MASTER_CCU_COMPAT, |
| 414 | kona_dt_master_ccu_setup); | 373 | kona_dt_master_ccu_setup); |
| 415 | CLK_OF_DECLARE(bcm11351_slave_ccu, BCM11351_DT_SLAVE_CCU_COMPAT, | 374 | CLK_OF_DECLARE(bcm281xx_slave_ccu, BCM281XX_DT_SLAVE_CCU_COMPAT, |
| 416 | kona_dt_slave_ccu_setup); | 375 | kona_dt_slave_ccu_setup); |
diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c index 54a06526f64f..e5aededdd322 100644 --- a/drivers/clk/bcm/clk-kona-setup.c +++ b/drivers/clk/bcm/clk-kona-setup.c | |||
| @@ -25,6 +25,31 @@ LIST_HEAD(ccu_list); /* The list of set up CCUs */ | |||
| 25 | 25 | ||
| 26 | /* Validity checking */ | 26 | /* Validity checking */ |
| 27 | 27 | ||
| 28 | static bool ccu_data_offsets_valid(struct ccu_data *ccu) | ||
| 29 | { | ||
| 30 | struct ccu_policy *ccu_policy = &ccu->policy; | ||
| 31 | u32 limit; | ||
| 32 | |||
| 33 | limit = ccu->range - sizeof(u32); | ||
| 34 | limit = round_down(limit, sizeof(u32)); | ||
| 35 | if (ccu_policy_exists(ccu_policy)) { | ||
| 36 | if (ccu_policy->enable.offset > limit) { | ||
| 37 | pr_err("%s: bad policy enable offset for %s " | ||
| 38 | "(%u > %u)\n", __func__, | ||
| 39 | ccu->name, ccu_policy->enable.offset, limit); | ||
| 40 | return false; | ||
| 41 | } | ||
| 42 | if (ccu_policy->control.offset > limit) { | ||
| 43 | pr_err("%s: bad policy control offset for %s " | ||
| 44 | "(%u > %u)\n", __func__, | ||
| 45 | ccu->name, ccu_policy->control.offset, limit); | ||
| 46 | return false; | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | return true; | ||
| 51 | } | ||
| 52 | |||
| 28 | static bool clk_requires_trigger(struct kona_clk *bcm_clk) | 53 | static bool clk_requires_trigger(struct kona_clk *bcm_clk) |
| 29 | { | 54 | { |
| 30 | struct peri_clk_data *peri = bcm_clk->u.peri; | 55 | struct peri_clk_data *peri = bcm_clk->u.peri; |
| @@ -54,7 +79,9 @@ static bool clk_requires_trigger(struct kona_clk *bcm_clk) | |||
| 54 | static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk) | 79 | static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk) |
| 55 | { | 80 | { |
| 56 | struct peri_clk_data *peri; | 81 | struct peri_clk_data *peri; |
| 82 | struct bcm_clk_policy *policy; | ||
| 57 | struct bcm_clk_gate *gate; | 83 | struct bcm_clk_gate *gate; |
| 84 | struct bcm_clk_hyst *hyst; | ||
| 58 | struct bcm_clk_div *div; | 85 | struct bcm_clk_div *div; |
| 59 | struct bcm_clk_sel *sel; | 86 | struct bcm_clk_sel *sel; |
| 60 | struct bcm_clk_trig *trig; | 87 | struct bcm_clk_trig *trig; |
| @@ -64,19 +91,41 @@ static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk) | |||
| 64 | 91 | ||
| 65 | BUG_ON(bcm_clk->type != bcm_clk_peri); | 92 | BUG_ON(bcm_clk->type != bcm_clk_peri); |
| 66 | peri = bcm_clk->u.peri; | 93 | peri = bcm_clk->u.peri; |
| 67 | name = bcm_clk->name; | 94 | name = bcm_clk->init_data.name; |
| 68 | range = bcm_clk->ccu->range; | 95 | range = bcm_clk->ccu->range; |
| 69 | 96 | ||
| 70 | limit = range - sizeof(u32); | 97 | limit = range - sizeof(u32); |
| 71 | limit = round_down(limit, sizeof(u32)); | 98 | limit = round_down(limit, sizeof(u32)); |
| 72 | 99 | ||
| 100 | policy = &peri->policy; | ||
| 101 | if (policy_exists(policy)) { | ||
| 102 | if (policy->offset > limit) { | ||
| 103 | pr_err("%s: bad policy offset for %s (%u > %u)\n", | ||
| 104 | __func__, name, policy->offset, limit); | ||
| 105 | return false; | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 73 | gate = &peri->gate; | 109 | gate = &peri->gate; |
| 110 | hyst = &peri->hyst; | ||
| 74 | if (gate_exists(gate)) { | 111 | if (gate_exists(gate)) { |
| 75 | if (gate->offset > limit) { | 112 | if (gate->offset > limit) { |
| 76 | pr_err("%s: bad gate offset for %s (%u > %u)\n", | 113 | pr_err("%s: bad gate offset for %s (%u > %u)\n", |
| 77 | __func__, name, gate->offset, limit); | 114 | __func__, name, gate->offset, limit); |
| 78 | return false; | 115 | return false; |
| 79 | } | 116 | } |
| 117 | |||
| 118 | if (hyst_exists(hyst)) { | ||
| 119 | if (hyst->offset > limit) { | ||
| 120 | pr_err("%s: bad hysteresis offset for %s " | ||
| 121 | "(%u > %u)\n", __func__, | ||
| 122 | name, hyst->offset, limit); | ||
| 123 | return false; | ||
| 124 | } | ||
| 125 | } | ||
| 126 | } else if (hyst_exists(hyst)) { | ||
| 127 | pr_err("%s: hysteresis but no gate for %s\n", __func__, name); | ||
| 128 | return false; | ||
| 80 | } | 129 | } |
| 81 | 130 | ||
| 82 | div = &peri->div; | 131 | div = &peri->div; |
| @@ -167,6 +216,36 @@ static bool bitfield_valid(u32 shift, u32 width, const char *field_name, | |||
| 167 | return true; | 216 | return true; |
| 168 | } | 217 | } |
| 169 | 218 | ||
| 219 | static bool | ||
| 220 | ccu_policy_valid(struct ccu_policy *ccu_policy, const char *ccu_name) | ||
| 221 | { | ||
| 222 | struct bcm_lvm_en *enable = &ccu_policy->enable; | ||
| 223 | struct bcm_policy_ctl *control; | ||
| 224 | |||
| 225 | if (!bit_posn_valid(enable->bit, "policy enable", ccu_name)) | ||
| 226 | return false; | ||
| 227 | |||
| 228 | control = &ccu_policy->control; | ||
| 229 | if (!bit_posn_valid(control->go_bit, "policy control GO", ccu_name)) | ||
| 230 | return false; | ||
| 231 | |||
| 232 | if (!bit_posn_valid(control->atl_bit, "policy control ATL", ccu_name)) | ||
| 233 | return false; | ||
| 234 | |||
| 235 | if (!bit_posn_valid(control->ac_bit, "policy control AC", ccu_name)) | ||
| 236 | return false; | ||
| 237 | |||
| 238 | return true; | ||
| 239 | } | ||
| 240 | |||
| 241 | static bool policy_valid(struct bcm_clk_policy *policy, const char *clock_name) | ||
| 242 | { | ||
| 243 | if (!bit_posn_valid(policy->bit, "policy", clock_name)) | ||
| 244 | return false; | ||
| 245 | |||
| 246 | return true; | ||
| 247 | } | ||
| 248 | |||
| 170 | /* | 249 | /* |
| 171 | * All gates, if defined, have a status bit, and for hardware-only | 250 | * All gates, if defined, have a status bit, and for hardware-only |
| 172 | * gates, that's it. Gates that can be software controlled also | 251 | * gates, that's it. Gates that can be software controlled also |
| @@ -196,6 +275,17 @@ static bool gate_valid(struct bcm_clk_gate *gate, const char *field_name, | |||
| 196 | return true; | 275 | return true; |
| 197 | } | 276 | } |
| 198 | 277 | ||
| 278 | static bool hyst_valid(struct bcm_clk_hyst *hyst, const char *clock_name) | ||
| 279 | { | ||
| 280 | if (!bit_posn_valid(hyst->en_bit, "hysteresis enable", clock_name)) | ||
| 281 | return false; | ||
| 282 | |||
| 283 | if (!bit_posn_valid(hyst->val_bit, "hysteresis value", clock_name)) | ||
| 284 | return false; | ||
| 285 | |||
| 286 | return true; | ||
| 287 | } | ||
| 288 | |||
| 199 | /* | 289 | /* |
| 200 | * A selector bitfield must be valid. Its parent_sel array must | 290 | * A selector bitfield must be valid. Its parent_sel array must |
| 201 | * also be reasonable for the field. | 291 | * also be reasonable for the field. |
| @@ -312,7 +402,9 @@ static bool | |||
| 312 | peri_clk_data_valid(struct kona_clk *bcm_clk) | 402 | peri_clk_data_valid(struct kona_clk *bcm_clk) |
| 313 | { | 403 | { |
| 314 | struct peri_clk_data *peri; | 404 | struct peri_clk_data *peri; |
| 405 | struct bcm_clk_policy *policy; | ||
| 315 | struct bcm_clk_gate *gate; | 406 | struct bcm_clk_gate *gate; |
| 407 | struct bcm_clk_hyst *hyst; | ||
| 316 | struct bcm_clk_sel *sel; | 408 | struct bcm_clk_sel *sel; |
| 317 | struct bcm_clk_div *div; | 409 | struct bcm_clk_div *div; |
| 318 | struct bcm_clk_div *pre_div; | 410 | struct bcm_clk_div *pre_div; |
| @@ -330,11 +422,20 @@ peri_clk_data_valid(struct kona_clk *bcm_clk) | |||
| 330 | return false; | 422 | return false; |
| 331 | 423 | ||
| 332 | peri = bcm_clk->u.peri; | 424 | peri = bcm_clk->u.peri; |
| 333 | name = bcm_clk->name; | 425 | name = bcm_clk->init_data.name; |
| 426 | |||
| 427 | policy = &peri->policy; | ||
| 428 | if (policy_exists(policy) && !policy_valid(policy, name)) | ||
| 429 | return false; | ||
| 430 | |||
| 334 | gate = &peri->gate; | 431 | gate = &peri->gate; |
| 335 | if (gate_exists(gate) && !gate_valid(gate, "gate", name)) | 432 | if (gate_exists(gate) && !gate_valid(gate, "gate", name)) |
| 336 | return false; | 433 | return false; |
| 337 | 434 | ||
| 435 | hyst = &peri->hyst; | ||
| 436 | if (hyst_exists(hyst) && !hyst_valid(hyst, name)) | ||
| 437 | return false; | ||
| 438 | |||
| 338 | sel = &peri->sel; | 439 | sel = &peri->sel; |
| 339 | if (selector_exists(sel)) { | 440 | if (selector_exists(sel)) { |
| 340 | if (!sel_valid(sel, "selector", name)) | 441 | if (!sel_valid(sel, "selector", name)) |
| @@ -567,7 +668,6 @@ static void peri_clk_teardown(struct peri_clk_data *data, | |||
| 567 | struct clk_init_data *init_data) | 668 | struct clk_init_data *init_data) |
| 568 | { | 669 | { |
| 569 | clk_sel_teardown(&data->sel, init_data); | 670 | clk_sel_teardown(&data->sel, init_data); |
| 570 | init_data->ops = NULL; | ||
| 571 | } | 671 | } |
| 572 | 672 | ||
| 573 | /* | 673 | /* |
| @@ -576,10 +676,9 @@ static void peri_clk_teardown(struct peri_clk_data *data, | |||
| 576 | * that can be assigned if the clock has one or more parent clocks | 676 | * that can be assigned if the clock has one or more parent clocks |
| 577 | * associated with it. | 677 | * associated with it. |
| 578 | */ | 678 | */ |
| 579 | static int peri_clk_setup(struct ccu_data *ccu, struct peri_clk_data *data, | 679 | static int |
| 580 | struct clk_init_data *init_data) | 680 | peri_clk_setup(struct peri_clk_data *data, struct clk_init_data *init_data) |
| 581 | { | 681 | { |
| 582 | init_data->ops = &kona_peri_clk_ops; | ||
| 583 | init_data->flags = CLK_IGNORE_UNUSED; | 682 | init_data->flags = CLK_IGNORE_UNUSED; |
| 584 | 683 | ||
| 585 | return clk_sel_setup(data->clocks, &data->sel, init_data); | 684 | return clk_sel_setup(data->clocks, &data->sel, init_data); |
| @@ -617,39 +716,26 @@ static void kona_clk_teardown(struct clk *clk) | |||
| 617 | bcm_clk_teardown(bcm_clk); | 716 | bcm_clk_teardown(bcm_clk); |
| 618 | } | 717 | } |
| 619 | 718 | ||
| 620 | struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name, | 719 | struct clk *kona_clk_setup(struct kona_clk *bcm_clk) |
| 621 | enum bcm_clk_type type, void *data) | ||
| 622 | { | 720 | { |
| 623 | struct kona_clk *bcm_clk; | 721 | struct clk_init_data *init_data = &bcm_clk->init_data; |
| 624 | struct clk_init_data *init_data; | ||
| 625 | struct clk *clk = NULL; | 722 | struct clk *clk = NULL; |
| 626 | 723 | ||
| 627 | bcm_clk = kzalloc(sizeof(*bcm_clk), GFP_KERNEL); | 724 | switch (bcm_clk->type) { |
| 628 | if (!bcm_clk) { | ||
| 629 | pr_err("%s: failed to allocate bcm_clk for %s\n", __func__, | ||
| 630 | name); | ||
| 631 | return NULL; | ||
| 632 | } | ||
| 633 | bcm_clk->ccu = ccu; | ||
| 634 | bcm_clk->name = name; | ||
| 635 | |||
| 636 | init_data = &bcm_clk->init_data; | ||
| 637 | init_data->name = name; | ||
| 638 | switch (type) { | ||
| 639 | case bcm_clk_peri: | 725 | case bcm_clk_peri: |
| 640 | if (peri_clk_setup(ccu, data, init_data)) | 726 | if (peri_clk_setup(bcm_clk->u.data, init_data)) |
| 641 | goto out_free; | 727 | return NULL; |
| 642 | break; | 728 | break; |
| 643 | default: | 729 | default: |
| 644 | data = NULL; | 730 | pr_err("%s: clock type %d invalid for %s\n", __func__, |
| 645 | break; | 731 | (int)bcm_clk->type, init_data->name); |
| 732 | return NULL; | ||
| 646 | } | 733 | } |
| 647 | bcm_clk->type = type; | ||
| 648 | bcm_clk->u.data = data; | ||
| 649 | 734 | ||
| 650 | /* Make sure everything makes sense before we set it up */ | 735 | /* Make sure everything makes sense before we set it up */ |
| 651 | if (!kona_clk_valid(bcm_clk)) { | 736 | if (!kona_clk_valid(bcm_clk)) { |
| 652 | pr_err("%s: clock data invalid for %s\n", __func__, name); | 737 | pr_err("%s: clock data invalid for %s\n", __func__, |
| 738 | init_data->name); | ||
| 653 | goto out_teardown; | 739 | goto out_teardown; |
| 654 | } | 740 | } |
| 655 | 741 | ||
| @@ -657,7 +743,7 @@ struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name, | |||
| 657 | clk = clk_register(NULL, &bcm_clk->hw); | 743 | clk = clk_register(NULL, &bcm_clk->hw); |
| 658 | if (IS_ERR(clk)) { | 744 | if (IS_ERR(clk)) { |
| 659 | pr_err("%s: error registering clock %s (%ld)\n", __func__, | 745 | pr_err("%s: error registering clock %s (%ld)\n", __func__, |
| 660 | name, PTR_ERR(clk)); | 746 | init_data->name, PTR_ERR(clk)); |
| 661 | goto out_teardown; | 747 | goto out_teardown; |
| 662 | } | 748 | } |
| 663 | BUG_ON(!clk); | 749 | BUG_ON(!clk); |
| @@ -665,8 +751,6 @@ struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name, | |||
| 665 | return clk; | 751 | return clk; |
| 666 | out_teardown: | 752 | out_teardown: |
| 667 | bcm_clk_teardown(bcm_clk); | 753 | bcm_clk_teardown(bcm_clk); |
| 668 | out_free: | ||
| 669 | kfree(bcm_clk); | ||
| 670 | 754 | ||
| 671 | return NULL; | 755 | return NULL; |
| 672 | } | 756 | } |
| @@ -675,50 +759,64 @@ static void ccu_clks_teardown(struct ccu_data *ccu) | |||
| 675 | { | 759 | { |
| 676 | u32 i; | 760 | u32 i; |
| 677 | 761 | ||
| 678 | for (i = 0; i < ccu->data.clk_num; i++) | 762 | for (i = 0; i < ccu->clk_data.clk_num; i++) |
| 679 | kona_clk_teardown(ccu->data.clks[i]); | 763 | kona_clk_teardown(ccu->clk_data.clks[i]); |
| 680 | kfree(ccu->data.clks); | 764 | kfree(ccu->clk_data.clks); |
| 681 | } | 765 | } |
| 682 | 766 | ||
| 683 | static void kona_ccu_teardown(struct ccu_data *ccu) | 767 | static void kona_ccu_teardown(struct ccu_data *ccu) |
| 684 | { | 768 | { |
| 685 | if (!ccu) | 769 | kfree(ccu->clk_data.clks); |
| 686 | return; | 770 | ccu->clk_data.clks = NULL; |
| 687 | |||
| 688 | if (!ccu->base) | 771 | if (!ccu->base) |
| 689 | goto done; | 772 | return; |
| 690 | 773 | ||
| 691 | of_clk_del_provider(ccu->node); /* safe if never added */ | 774 | of_clk_del_provider(ccu->node); /* safe if never added */ |
| 692 | ccu_clks_teardown(ccu); | 775 | ccu_clks_teardown(ccu); |
| 693 | list_del(&ccu->links); | 776 | list_del(&ccu->links); |
| 694 | of_node_put(ccu->node); | 777 | of_node_put(ccu->node); |
| 778 | ccu->node = NULL; | ||
| 695 | iounmap(ccu->base); | 779 | iounmap(ccu->base); |
| 696 | done: | 780 | ccu->base = NULL; |
| 697 | kfree(ccu->name); | 781 | } |
| 698 | kfree(ccu); | 782 | |
| 783 | static bool ccu_data_valid(struct ccu_data *ccu) | ||
| 784 | { | ||
| 785 | struct ccu_policy *ccu_policy; | ||
| 786 | |||
| 787 | if (!ccu_data_offsets_valid(ccu)) | ||
| 788 | return false; | ||
| 789 | |||
| 790 | ccu_policy = &ccu->policy; | ||
| 791 | if (ccu_policy_exists(ccu_policy)) | ||
| 792 | if (!ccu_policy_valid(ccu_policy, ccu->name)) | ||
| 793 | return false; | ||
| 794 | |||
| 795 | return true; | ||
| 699 | } | 796 | } |
| 700 | 797 | ||
| 701 | /* | 798 | /* |
| 702 | * Set up a CCU. Call the provided ccu_clks_setup callback to | 799 | * Set up a CCU. Call the provided ccu_clks_setup callback to |
| 703 | * initialize the array of clocks provided by the CCU. | 800 | * initialize the array of clocks provided by the CCU. |
| 704 | */ | 801 | */ |
| 705 | void __init kona_dt_ccu_setup(struct device_node *node, | 802 | void __init kona_dt_ccu_setup(struct ccu_data *ccu, |
| 706 | int (*ccu_clks_setup)(struct ccu_data *)) | 803 | struct device_node *node) |
| 707 | { | 804 | { |
| 708 | struct ccu_data *ccu; | ||
| 709 | struct resource res = { 0 }; | 805 | struct resource res = { 0 }; |
| 710 | resource_size_t range; | 806 | resource_size_t range; |
| 807 | unsigned int i; | ||
| 711 | int ret; | 808 | int ret; |
| 712 | 809 | ||
| 713 | ccu = kzalloc(sizeof(*ccu), GFP_KERNEL); | 810 | if (ccu->clk_data.clk_num) { |
| 714 | if (ccu) | 811 | size_t size; |
| 715 | ccu->name = kstrdup(node->name, GFP_KERNEL); | ||
| 716 | if (!ccu || !ccu->name) { | ||
| 717 | pr_err("%s: unable to allocate CCU struct for %s\n", | ||
| 718 | __func__, node->name); | ||
| 719 | kfree(ccu); | ||
| 720 | 812 | ||
| 721 | return; | 813 | size = ccu->clk_data.clk_num * sizeof(*ccu->clk_data.clks); |
| 814 | ccu->clk_data.clks = kzalloc(size, GFP_KERNEL); | ||
| 815 | if (!ccu->clk_data.clks) { | ||
| 816 | pr_err("%s: unable to allocate %u clocks for %s\n", | ||
| 817 | __func__, ccu->clk_data.clk_num, node->name); | ||
| 818 | return; | ||
| 819 | } | ||
| 722 | } | 820 | } |
| 723 | 821 | ||
| 724 | ret = of_address_to_resource(node, 0, &res); | 822 | ret = of_address_to_resource(node, 0, &res); |
| @@ -736,24 +834,33 @@ void __init kona_dt_ccu_setup(struct device_node *node, | |||
| 736 | } | 834 | } |
| 737 | 835 | ||
| 738 | ccu->range = (u32)range; | 836 | ccu->range = (u32)range; |
| 837 | |||
| 838 | if (!ccu_data_valid(ccu)) { | ||
| 839 | pr_err("%s: ccu data not valid for %s\n", __func__, node->name); | ||
| 840 | goto out_err; | ||
| 841 | } | ||
| 842 | |||
| 739 | ccu->base = ioremap(res.start, ccu->range); | 843 | ccu->base = ioremap(res.start, ccu->range); |
| 740 | if (!ccu->base) { | 844 | if (!ccu->base) { |
| 741 | pr_err("%s: unable to map CCU registers for %s\n", __func__, | 845 | pr_err("%s: unable to map CCU registers for %s\n", __func__, |
| 742 | node->name); | 846 | node->name); |
| 743 | goto out_err; | 847 | goto out_err; |
| 744 | } | 848 | } |
| 745 | |||
| 746 | spin_lock_init(&ccu->lock); | ||
| 747 | INIT_LIST_HEAD(&ccu->links); | ||
| 748 | ccu->node = of_node_get(node); | 849 | ccu->node = of_node_get(node); |
| 749 | |||
| 750 | list_add_tail(&ccu->links, &ccu_list); | 850 | list_add_tail(&ccu->links, &ccu_list); |
| 751 | 851 | ||
| 752 | /* Set up clocks array (in ccu->data) */ | 852 | /* |
| 753 | if (ccu_clks_setup(ccu)) | 853 | * Set up each defined kona clock and save the result in |
| 754 | goto out_err; | 854 | * the clock framework clock array (in ccu->data). Then |
| 855 | * register as a provider for these clocks. | ||
| 856 | */ | ||
| 857 | for (i = 0; i < ccu->clk_data.clk_num; i++) { | ||
| 858 | if (!ccu->kona_clks[i].ccu) | ||
| 859 | continue; | ||
| 860 | ccu->clk_data.clks[i] = kona_clk_setup(&ccu->kona_clks[i]); | ||
| 861 | } | ||
| 755 | 862 | ||
| 756 | ret = of_clk_add_provider(node, of_clk_src_onecell_get, &ccu->data); | 863 | ret = of_clk_add_provider(node, of_clk_src_onecell_get, &ccu->clk_data); |
| 757 | if (ret) { | 864 | if (ret) { |
| 758 | pr_err("%s: error adding ccu %s as provider (%d)\n", __func__, | 865 | pr_err("%s: error adding ccu %s as provider (%d)\n", __func__, |
| 759 | node->name, ret); | 866 | node->name, ret); |
diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c index db11a87449f2..95af2e665dd3 100644 --- a/drivers/clk/bcm/clk-kona.c +++ b/drivers/clk/bcm/clk-kona.c | |||
| @@ -16,6 +16,14 @@ | |||
| 16 | 16 | ||
| 17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
| 18 | 18 | ||
| 19 | /* | ||
| 20 | * "Policies" affect the frequencies of bus clocks provided by a | ||
| 21 | * CCU. (I believe these polices are named "Deep Sleep", "Economy", | ||
| 22 | * "Normal", and "Turbo".) A lower policy number has lower power | ||
| 23 | * consumption, and policy 2 is the default. | ||
| 24 | */ | ||
| 25 | #define CCU_POLICY_COUNT 4 | ||
| 26 | |||
| 19 | #define CCU_ACCESS_PASSWORD 0xA5A500 | 27 | #define CCU_ACCESS_PASSWORD 0xA5A500 |
| 20 | #define CLK_GATE_DELAY_LOOP 2000 | 28 | #define CLK_GATE_DELAY_LOOP 2000 |
| 21 | 29 | ||
| @@ -207,9 +215,154 @@ __ccu_wait_bit(struct ccu_data *ccu, u32 reg_offset, u32 bit, bool want) | |||
| 207 | return true; | 215 | return true; |
| 208 | udelay(1); | 216 | udelay(1); |
| 209 | } | 217 | } |
| 218 | pr_warn("%s: %s/0x%04x bit %u was never %s\n", __func__, | ||
| 219 | ccu->name, reg_offset, bit, want ? "set" : "clear"); | ||
| 220 | |||
| 210 | return false; | 221 | return false; |
| 211 | } | 222 | } |
| 212 | 223 | ||
| 224 | /* Policy operations */ | ||
| 225 | |||
| 226 | static bool __ccu_policy_engine_start(struct ccu_data *ccu, bool sync) | ||
| 227 | { | ||
| 228 | struct bcm_policy_ctl *control = &ccu->policy.control; | ||
| 229 | u32 offset; | ||
| 230 | u32 go_bit; | ||
| 231 | u32 mask; | ||
| 232 | bool ret; | ||
| 233 | |||
| 234 | /* If we don't need to control policy for this CCU, we're done. */ | ||
| 235 | if (!policy_ctl_exists(control)) | ||
| 236 | return true; | ||
| 237 | |||
| 238 | offset = control->offset; | ||
| 239 | go_bit = control->go_bit; | ||
| 240 | |||
| 241 | /* Ensure we're not busy before we start */ | ||
| 242 | ret = __ccu_wait_bit(ccu, offset, go_bit, false); | ||
| 243 | if (!ret) { | ||
| 244 | pr_err("%s: ccu %s policy engine wouldn't go idle\n", | ||
| 245 | __func__, ccu->name); | ||
| 246 | return false; | ||
| 247 | } | ||
| 248 | |||
| 249 | /* | ||
| 250 | * If it's a synchronous request, we'll wait for the voltage | ||
| 251 | * and frequency of the active load to stabilize before | ||
| 252 | * returning. To do this we select the active load by | ||
| 253 | * setting the ATL bit. | ||
| 254 | * | ||
| 255 | * An asynchronous request instead ramps the voltage in the | ||
| 256 | * background, and when that process stabilizes, the target | ||
| 257 | * load is copied to the active load and the CCU frequency | ||
| 258 | * is switched. We do this by selecting the target load | ||
| 259 | * (ATL bit clear) and setting the request auto-copy (AC bit | ||
| 260 | * set). | ||
| 261 | * | ||
| 262 | * Note, we do NOT read-modify-write this register. | ||
| 263 | */ | ||
| 264 | mask = (u32)1 << go_bit; | ||
| 265 | if (sync) | ||
| 266 | mask |= 1 << control->atl_bit; | ||
| 267 | else | ||
| 268 | mask |= 1 << control->ac_bit; | ||
| 269 | __ccu_write(ccu, offset, mask); | ||
| 270 | |||
| 271 | /* Wait for indication that operation is complete. */ | ||
| 272 | ret = __ccu_wait_bit(ccu, offset, go_bit, false); | ||
| 273 | if (!ret) | ||
| 274 | pr_err("%s: ccu %s policy engine never started\n", | ||
| 275 | __func__, ccu->name); | ||
| 276 | |||
| 277 | return ret; | ||
| 278 | } | ||
| 279 | |||
| 280 | static bool __ccu_policy_engine_stop(struct ccu_data *ccu) | ||
| 281 | { | ||
| 282 | struct bcm_lvm_en *enable = &ccu->policy.enable; | ||
| 283 | u32 offset; | ||
| 284 | u32 enable_bit; | ||
| 285 | bool ret; | ||
| 286 | |||
| 287 | /* If we don't need to control policy for this CCU, we're done. */ | ||
| 288 | if (!policy_lvm_en_exists(enable)) | ||
| 289 | return true; | ||
| 290 | |||
| 291 | /* Ensure we're not busy before we start */ | ||
| 292 | offset = enable->offset; | ||
| 293 | enable_bit = enable->bit; | ||
| 294 | ret = __ccu_wait_bit(ccu, offset, enable_bit, false); | ||
| 295 | if (!ret) { | ||
| 296 | pr_err("%s: ccu %s policy engine already stopped\n", | ||
| 297 | __func__, ccu->name); | ||
| 298 | return false; | ||
| 299 | } | ||
| 300 | |||
| 301 | /* Now set the bit to stop the engine (NO read-modify-write) */ | ||
| 302 | __ccu_write(ccu, offset, (u32)1 << enable_bit); | ||
| 303 | |||
| 304 | /* Wait for indication that it has stopped. */ | ||
| 305 | ret = __ccu_wait_bit(ccu, offset, enable_bit, false); | ||
| 306 | if (!ret) | ||
| 307 | pr_err("%s: ccu %s policy engine never stopped\n", | ||
| 308 | __func__, ccu->name); | ||
| 309 | |||
| 310 | return ret; | ||
| 311 | } | ||
| 312 | |||
| 313 | /* | ||
| 314 | * A CCU has four operating conditions ("policies"), and some clocks | ||
| 315 | * can be disabled or enabled based on which policy is currently in | ||
| 316 | * effect. Such clocks have a bit in a "policy mask" register for | ||
| 317 | * each policy indicating whether the clock is enabled for that | ||
| 318 | * policy or not. The bit position for a clock is the same for all | ||
| 319 | * four registers, and the 32-bit registers are at consecutive | ||
| 320 | * addresses. | ||
| 321 | */ | ||
| 322 | static bool policy_init(struct ccu_data *ccu, struct bcm_clk_policy *policy) | ||
| 323 | { | ||
| 324 | u32 offset; | ||
| 325 | u32 mask; | ||
| 326 | int i; | ||
| 327 | bool ret; | ||
| 328 | |||
| 329 | if (!policy_exists(policy)) | ||
| 330 | return true; | ||
| 331 | |||
| 332 | /* | ||
| 333 | * We need to stop the CCU policy engine to allow update | ||
| 334 | * of our policy bits. | ||
| 335 | */ | ||
| 336 | if (!__ccu_policy_engine_stop(ccu)) { | ||
| 337 | pr_err("%s: unable to stop CCU %s policy engine\n", | ||
| 338 | __func__, ccu->name); | ||
| 339 | return false; | ||
| 340 | } | ||
| 341 | |||
| 342 | /* | ||
| 343 | * For now, if a clock defines its policy bit we just mark | ||
| 344 | * it "enabled" for all four policies. | ||
| 345 | */ | ||
| 346 | offset = policy->offset; | ||
| 347 | mask = (u32)1 << policy->bit; | ||
| 348 | for (i = 0; i < CCU_POLICY_COUNT; i++) { | ||
| 349 | u32 reg_val; | ||
| 350 | |||
| 351 | reg_val = __ccu_read(ccu, offset); | ||
| 352 | reg_val |= mask; | ||
| 353 | __ccu_write(ccu, offset, reg_val); | ||
| 354 | offset += sizeof(u32); | ||
| 355 | } | ||
| 356 | |||
| 357 | /* We're done updating; fire up the policy engine again. */ | ||
| 358 | ret = __ccu_policy_engine_start(ccu, true); | ||
| 359 | if (!ret) | ||
| 360 | pr_err("%s: unable to restart CCU %s policy engine\n", | ||
| 361 | __func__, ccu->name); | ||
| 362 | |||
| 363 | return ret; | ||
| 364 | } | ||
| 365 | |||
| 213 | /* Gate operations */ | 366 | /* Gate operations */ |
| 214 | 367 | ||
| 215 | /* Determine whether a clock is gated. CCU lock must be held. */ | 368 | /* Determine whether a clock is gated. CCU lock must be held. */ |
| @@ -374,6 +527,35 @@ static int clk_gate(struct ccu_data *ccu, const char *name, | |||
| 374 | return -EIO; | 527 | return -EIO; |
| 375 | } | 528 | } |
| 376 | 529 | ||
| 530 | /* Hysteresis operations */ | ||
| 531 | |||
| 532 | /* | ||
| 533 | * If a clock gate requires a turn-off delay it will have | ||
| 534 | * "hysteresis" register bits defined. The first, if set, enables | ||
| 535 | * the delay; and if enabled, the second bit determines whether the | ||
| 536 | * delay is "low" or "high" (1 means high). For now, if it's | ||
| 537 | * defined for a clock, we set it. | ||
| 538 | */ | ||
| 539 | static bool hyst_init(struct ccu_data *ccu, struct bcm_clk_hyst *hyst) | ||
| 540 | { | ||
| 541 | u32 offset; | ||
| 542 | u32 reg_val; | ||
| 543 | u32 mask; | ||
| 544 | |||
| 545 | if (!hyst_exists(hyst)) | ||
| 546 | return true; | ||
| 547 | |||
| 548 | offset = hyst->offset; | ||
| 549 | mask = (u32)1 << hyst->en_bit; | ||
| 550 | mask |= (u32)1 << hyst->val_bit; | ||
| 551 | |||
| 552 | reg_val = __ccu_read(ccu, offset); | ||
| 553 | reg_val |= mask; | ||
| 554 | __ccu_write(ccu, offset, reg_val); | ||
| 555 | |||
| 556 | return true; | ||
| 557 | } | ||
| 558 | |||
| 377 | /* Trigger operations */ | 559 | /* Trigger operations */ |
| 378 | 560 | ||
| 379 | /* | 561 | /* |
| @@ -806,7 +988,7 @@ static int kona_peri_clk_enable(struct clk_hw *hw) | |||
| 806 | struct kona_clk *bcm_clk = to_kona_clk(hw); | 988 | struct kona_clk *bcm_clk = to_kona_clk(hw); |
| 807 | struct bcm_clk_gate *gate = &bcm_clk->u.peri->gate; | 989 | struct bcm_clk_gate *gate = &bcm_clk->u.peri->gate; |
| 808 | 990 | ||
| 809 | return clk_gate(bcm_clk->ccu, bcm_clk->name, gate, true); | 991 | return clk_gate(bcm_clk->ccu, bcm_clk->init_data.name, gate, true); |
| 810 | } | 992 | } |
| 811 | 993 | ||
| 812 | static void kona_peri_clk_disable(struct clk_hw *hw) | 994 | static void kona_peri_clk_disable(struct clk_hw *hw) |
| @@ -814,7 +996,7 @@ static void kona_peri_clk_disable(struct clk_hw *hw) | |||
| 814 | struct kona_clk *bcm_clk = to_kona_clk(hw); | 996 | struct kona_clk *bcm_clk = to_kona_clk(hw); |
| 815 | struct bcm_clk_gate *gate = &bcm_clk->u.peri->gate; | 997 | struct bcm_clk_gate *gate = &bcm_clk->u.peri->gate; |
| 816 | 998 | ||
| 817 | (void)clk_gate(bcm_clk->ccu, bcm_clk->name, gate, false); | 999 | (void)clk_gate(bcm_clk->ccu, bcm_clk->init_data.name, gate, false); |
| 818 | } | 1000 | } |
| 819 | 1001 | ||
| 820 | static int kona_peri_clk_is_enabled(struct clk_hw *hw) | 1002 | static int kona_peri_clk_is_enabled(struct clk_hw *hw) |
| @@ -849,6 +1031,58 @@ static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate, | |||
| 849 | rate ? rate : 1, *parent_rate, NULL); | 1031 | rate ? rate : 1, *parent_rate, NULL); |
| 850 | } | 1032 | } |
| 851 | 1033 | ||
| 1034 | static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate, | ||
| 1035 | unsigned long *best_parent_rate, struct clk **best_parent) | ||
| 1036 | { | ||
| 1037 | struct kona_clk *bcm_clk = to_kona_clk(hw); | ||
| 1038 | struct clk *clk = hw->clk; | ||
| 1039 | struct clk *current_parent; | ||
| 1040 | unsigned long parent_rate; | ||
| 1041 | unsigned long best_delta; | ||
| 1042 | unsigned long best_rate; | ||
| 1043 | u32 parent_count; | ||
| 1044 | u32 which; | ||
| 1045 | |||
| 1046 | /* | ||
| 1047 | * If there is no other parent to choose, use the current one. | ||
| 1048 | * Note: We don't honor (or use) CLK_SET_RATE_NO_REPARENT. | ||
| 1049 | */ | ||
| 1050 | WARN_ON_ONCE(bcm_clk->init_data.flags & CLK_SET_RATE_NO_REPARENT); | ||
| 1051 | parent_count = (u32)bcm_clk->init_data.num_parents; | ||
| 1052 | if (parent_count < 2) | ||
| 1053 | return kona_peri_clk_round_rate(hw, rate, best_parent_rate); | ||
| 1054 | |||
| 1055 | /* Unless we can do better, stick with current parent */ | ||
| 1056 | current_parent = clk_get_parent(clk); | ||
| 1057 | parent_rate = __clk_get_rate(current_parent); | ||
| 1058 | best_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate); | ||
| 1059 | best_delta = abs(best_rate - rate); | ||
| 1060 | |||
| 1061 | /* Check whether any other parent clock can produce a better result */ | ||
| 1062 | for (which = 0; which < parent_count; which++) { | ||
| 1063 | struct clk *parent = clk_get_parent_by_index(clk, which); | ||
| 1064 | unsigned long delta; | ||
| 1065 | unsigned long other_rate; | ||
| 1066 | |||
| 1067 | BUG_ON(!parent); | ||
| 1068 | if (parent == current_parent) | ||
| 1069 | continue; | ||
| 1070 | |||
| 1071 | /* We don't support CLK_SET_RATE_PARENT */ | ||
| 1072 | parent_rate = __clk_get_rate(parent); | ||
| 1073 | other_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate); | ||
| 1074 | delta = abs(other_rate - rate); | ||
| 1075 | if (delta < best_delta) { | ||
| 1076 | best_delta = delta; | ||
| 1077 | best_rate = other_rate; | ||
| 1078 | *best_parent = parent; | ||
| 1079 | *best_parent_rate = parent_rate; | ||
| 1080 | } | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | return best_rate; | ||
| 1084 | } | ||
| 1085 | |||
| 852 | static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index) | 1086 | static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index) |
| 853 | { | 1087 | { |
| 854 | struct kona_clk *bcm_clk = to_kona_clk(hw); | 1088 | struct kona_clk *bcm_clk = to_kona_clk(hw); |
| @@ -872,12 +1106,13 @@ static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index) | |||
| 872 | 1106 | ||
| 873 | ret = selector_write(bcm_clk->ccu, &data->gate, sel, trig, index); | 1107 | ret = selector_write(bcm_clk->ccu, &data->gate, sel, trig, index); |
| 874 | if (ret == -ENXIO) { | 1108 | if (ret == -ENXIO) { |
| 875 | pr_err("%s: gating failure for %s\n", __func__, bcm_clk->name); | 1109 | pr_err("%s: gating failure for %s\n", __func__, |
| 1110 | bcm_clk->init_data.name); | ||
| 876 | ret = -EIO; /* Don't proliferate weird errors */ | 1111 | ret = -EIO; /* Don't proliferate weird errors */ |
| 877 | } else if (ret == -EIO) { | 1112 | } else if (ret == -EIO) { |
| 878 | pr_err("%s: %strigger failed for %s\n", __func__, | 1113 | pr_err("%s: %strigger failed for %s\n", __func__, |
| 879 | trig == &data->pre_trig ? "pre-" : "", | 1114 | trig == &data->pre_trig ? "pre-" : "", |
| 880 | bcm_clk->name); | 1115 | bcm_clk->init_data.name); |
| 881 | } | 1116 | } |
| 882 | 1117 | ||
| 883 | return ret; | 1118 | return ret; |
| @@ -936,10 +1171,12 @@ static int kona_peri_clk_set_rate(struct clk_hw *hw, unsigned long rate, | |||
| 936 | ret = divider_write(bcm_clk->ccu, &data->gate, &data->div, | 1171 | ret = divider_write(bcm_clk->ccu, &data->gate, &data->div, |
| 937 | &data->trig, scaled_div); | 1172 | &data->trig, scaled_div); |
| 938 | if (ret == -ENXIO) { | 1173 | if (ret == -ENXIO) { |
| 939 | pr_err("%s: gating failure for %s\n", __func__, bcm_clk->name); | 1174 | pr_err("%s: gating failure for %s\n", __func__, |
| 1175 | bcm_clk->init_data.name); | ||
| 940 | ret = -EIO; /* Don't proliferate weird errors */ | 1176 | ret = -EIO; /* Don't proliferate weird errors */ |
| 941 | } else if (ret == -EIO) { | 1177 | } else if (ret == -EIO) { |
| 942 | pr_err("%s: trigger failed for %s\n", __func__, bcm_clk->name); | 1178 | pr_err("%s: trigger failed for %s\n", __func__, |
| 1179 | bcm_clk->init_data.name); | ||
| 943 | } | 1180 | } |
| 944 | 1181 | ||
| 945 | return ret; | 1182 | return ret; |
| @@ -950,7 +1187,7 @@ struct clk_ops kona_peri_clk_ops = { | |||
| 950 | .disable = kona_peri_clk_disable, | 1187 | .disable = kona_peri_clk_disable, |
| 951 | .is_enabled = kona_peri_clk_is_enabled, | 1188 | .is_enabled = kona_peri_clk_is_enabled, |
| 952 | .recalc_rate = kona_peri_clk_recalc_rate, | 1189 | .recalc_rate = kona_peri_clk_recalc_rate, |
| 953 | .round_rate = kona_peri_clk_round_rate, | 1190 | .determine_rate = kona_peri_clk_determine_rate, |
| 954 | .set_parent = kona_peri_clk_set_parent, | 1191 | .set_parent = kona_peri_clk_set_parent, |
| 955 | .get_parent = kona_peri_clk_get_parent, | 1192 | .get_parent = kona_peri_clk_get_parent, |
| 956 | .set_rate = kona_peri_clk_set_rate, | 1193 | .set_rate = kona_peri_clk_set_rate, |
| @@ -961,15 +1198,24 @@ static bool __peri_clk_init(struct kona_clk *bcm_clk) | |||
| 961 | { | 1198 | { |
| 962 | struct ccu_data *ccu = bcm_clk->ccu; | 1199 | struct ccu_data *ccu = bcm_clk->ccu; |
| 963 | struct peri_clk_data *peri = bcm_clk->u.peri; | 1200 | struct peri_clk_data *peri = bcm_clk->u.peri; |
| 964 | const char *name = bcm_clk->name; | 1201 | const char *name = bcm_clk->init_data.name; |
| 965 | struct bcm_clk_trig *trig; | 1202 | struct bcm_clk_trig *trig; |
| 966 | 1203 | ||
| 967 | BUG_ON(bcm_clk->type != bcm_clk_peri); | 1204 | BUG_ON(bcm_clk->type != bcm_clk_peri); |
| 968 | 1205 | ||
| 1206 | if (!policy_init(ccu, &peri->policy)) { | ||
| 1207 | pr_err("%s: error initializing policy for %s\n", | ||
| 1208 | __func__, name); | ||
| 1209 | return false; | ||
| 1210 | } | ||
| 969 | if (!gate_init(ccu, &peri->gate)) { | 1211 | if (!gate_init(ccu, &peri->gate)) { |
| 970 | pr_err("%s: error initializing gate for %s\n", __func__, name); | 1212 | pr_err("%s: error initializing gate for %s\n", __func__, name); |
| 971 | return false; | 1213 | return false; |
| 972 | } | 1214 | } |
| 1215 | if (!hyst_init(ccu, &peri->hyst)) { | ||
| 1216 | pr_err("%s: error initializing hyst for %s\n", __func__, name); | ||
| 1217 | return false; | ||
| 1218 | } | ||
| 973 | if (!div_init(ccu, &peri->gate, &peri->div, &peri->trig)) { | 1219 | if (!div_init(ccu, &peri->gate, &peri->div, &peri->trig)) { |
| 974 | pr_err("%s: error initializing divider for %s\n", __func__, | 1220 | pr_err("%s: error initializing divider for %s\n", __func__, |
| 975 | name); | 1221 | name); |
| @@ -1014,13 +1260,13 @@ bool __init kona_ccu_init(struct ccu_data *ccu) | |||
| 1014 | { | 1260 | { |
| 1015 | unsigned long flags; | 1261 | unsigned long flags; |
| 1016 | unsigned int which; | 1262 | unsigned int which; |
| 1017 | struct clk **clks = ccu->data.clks; | 1263 | struct clk **clks = ccu->clk_data.clks; |
| 1018 | bool success = true; | 1264 | bool success = true; |
| 1019 | 1265 | ||
| 1020 | flags = ccu_lock(ccu); | 1266 | flags = ccu_lock(ccu); |
| 1021 | __ccu_write_enable(ccu); | 1267 | __ccu_write_enable(ccu); |
| 1022 | 1268 | ||
| 1023 | for (which = 0; which < ccu->data.clk_num; which++) { | 1269 | for (which = 0; which < ccu->clk_data.clk_num; which++) { |
| 1024 | struct kona_clk *bcm_clk; | 1270 | struct kona_clk *bcm_clk; |
| 1025 | 1271 | ||
| 1026 | if (!clks[which]) | 1272 | if (!clks[which]) |
diff --git a/drivers/clk/bcm/clk-kona.h b/drivers/clk/bcm/clk-kona.h index dee690951bb6..2537b3072910 100644 --- a/drivers/clk/bcm/clk-kona.h +++ b/drivers/clk/bcm/clk-kona.h | |||
| @@ -43,8 +43,14 @@ | |||
| 43 | #define FLAG_FLIP(obj, type, flag) ((obj)->flags ^= FLAG(type, flag)) | 43 | #define FLAG_FLIP(obj, type, flag) ((obj)->flags ^= FLAG(type, flag)) |
| 44 | #define FLAG_TEST(obj, type, flag) (!!((obj)->flags & FLAG(type, flag))) | 44 | #define FLAG_TEST(obj, type, flag) (!!((obj)->flags & FLAG(type, flag))) |
| 45 | 45 | ||
| 46 | /* CCU field state tests */ | ||
| 47 | |||
| 48 | #define ccu_policy_exists(ccu_policy) ((ccu_policy)->enable.offset != 0) | ||
| 49 | |||
| 46 | /* Clock field state tests */ | 50 | /* Clock field state tests */ |
| 47 | 51 | ||
| 52 | #define policy_exists(policy) ((policy)->offset != 0) | ||
| 53 | |||
| 48 | #define gate_exists(gate) FLAG_TEST(gate, GATE, EXISTS) | 54 | #define gate_exists(gate) FLAG_TEST(gate, GATE, EXISTS) |
| 49 | #define gate_is_enabled(gate) FLAG_TEST(gate, GATE, ENABLED) | 55 | #define gate_is_enabled(gate) FLAG_TEST(gate, GATE, ENABLED) |
| 50 | #define gate_is_hw_controllable(gate) FLAG_TEST(gate, GATE, HW) | 56 | #define gate_is_hw_controllable(gate) FLAG_TEST(gate, GATE, HW) |
| @@ -54,6 +60,8 @@ | |||
| 54 | 60 | ||
| 55 | #define gate_flip_enabled(gate) FLAG_FLIP(gate, GATE, ENABLED) | 61 | #define gate_flip_enabled(gate) FLAG_FLIP(gate, GATE, ENABLED) |
| 56 | 62 | ||
| 63 | #define hyst_exists(hyst) ((hyst)->offset != 0) | ||
| 64 | |||
| 57 | #define divider_exists(div) FLAG_TEST(div, DIV, EXISTS) | 65 | #define divider_exists(div) FLAG_TEST(div, DIV, EXISTS) |
| 58 | #define divider_is_fixed(div) FLAG_TEST(div, DIV, FIXED) | 66 | #define divider_is_fixed(div) FLAG_TEST(div, DIV, FIXED) |
| 59 | #define divider_has_fraction(div) (!divider_is_fixed(div) && \ | 67 | #define divider_has_fraction(div) (!divider_is_fixed(div) && \ |
| @@ -62,6 +70,9 @@ | |||
| 62 | #define selector_exists(sel) ((sel)->width != 0) | 70 | #define selector_exists(sel) ((sel)->width != 0) |
| 63 | #define trigger_exists(trig) FLAG_TEST(trig, TRIG, EXISTS) | 71 | #define trigger_exists(trig) FLAG_TEST(trig, TRIG, EXISTS) |
| 64 | 72 | ||
| 73 | #define policy_lvm_en_exists(enable) ((enable)->offset != 0) | ||
| 74 | #define policy_ctl_exists(control) ((control)->offset != 0) | ||
| 75 | |||
| 65 | /* Clock type, used to tell common block what it's part of */ | 76 | /* Clock type, used to tell common block what it's part of */ |
| 66 | enum bcm_clk_type { | 77 | enum bcm_clk_type { |
| 67 | bcm_clk_none, /* undefined clock type */ | 78 | bcm_clk_none, /* undefined clock type */ |
| @@ -71,25 +82,26 @@ enum bcm_clk_type { | |||
| 71 | }; | 82 | }; |
| 72 | 83 | ||
| 73 | /* | 84 | /* |
| 74 | * Each CCU defines a mapped area of memory containing registers | 85 | * CCU policy control for clocks. Clocks can be enabled or disabled |
| 75 | * used to manage clocks implemented by the CCU. Access to memory | 86 | * based on the CCU policy in effect. One bit in each policy mask |
| 76 | * within the CCU's space is serialized by a spinlock. Before any | 87 | * register (one per CCU policy) represents whether the clock is |
| 77 | * (other) address can be written, a special access "password" value | 88 | * enabled when that policy is effect or not. The CCU policy engine |
| 78 | * must be written to its WR_ACCESS register (located at the base | 89 | * must be stopped to update these bits, and must be restarted again |
| 79 | * address of the range). We keep track of the name of each CCU as | 90 | * afterward. |
| 80 | * it is set up, and maintain them in a list. | ||
| 81 | */ | 91 | */ |
| 82 | struct ccu_data { | 92 | struct bcm_clk_policy { |
| 83 | void __iomem *base; /* base of mapped address space */ | 93 | u32 offset; /* first policy mask register offset */ |
| 84 | spinlock_t lock; /* serialization lock */ | 94 | u32 bit; /* bit used in all mask registers */ |
| 85 | bool write_enabled; /* write access is currently enabled */ | ||
| 86 | struct list_head links; /* for ccu_list */ | ||
| 87 | struct device_node *node; | ||
| 88 | struct clk_onecell_data data; | ||
| 89 | const char *name; | ||
| 90 | u32 range; /* byte range of address space */ | ||
| 91 | }; | 95 | }; |
| 92 | 96 | ||
| 97 | /* Policy initialization macro */ | ||
| 98 | |||
| 99 | #define POLICY(_offset, _bit) \ | ||
| 100 | { \ | ||
| 101 | .offset = (_offset), \ | ||
| 102 | .bit = (_bit), \ | ||
| 103 | } | ||
| 104 | |||
| 93 | /* | 105 | /* |
| 94 | * Gating control and status is managed by a 32-bit gate register. | 106 | * Gating control and status is managed by a 32-bit gate register. |
| 95 | * | 107 | * |
| @@ -195,6 +207,22 @@ struct bcm_clk_gate { | |||
| 195 | .flags = FLAG(GATE, HW)|FLAG(GATE, EXISTS), \ | 207 | .flags = FLAG(GATE, HW)|FLAG(GATE, EXISTS), \ |
| 196 | } | 208 | } |
| 197 | 209 | ||
| 210 | /* Gate hysteresis for clocks */ | ||
| 211 | struct bcm_clk_hyst { | ||
| 212 | u32 offset; /* hyst register offset (normally CLKGATE) */ | ||
| 213 | u32 en_bit; /* bit used to enable hysteresis */ | ||
| 214 | u32 val_bit; /* if enabled: 0 = low delay; 1 = high delay */ | ||
| 215 | }; | ||
| 216 | |||
| 217 | /* Hysteresis initialization macro */ | ||
| 218 | |||
| 219 | #define HYST(_offset, _en_bit, _val_bit) \ | ||
| 220 | { \ | ||
| 221 | .offset = (_offset), \ | ||
| 222 | .en_bit = (_en_bit), \ | ||
| 223 | .val_bit = (_val_bit), \ | ||
| 224 | } | ||
| 225 | |||
| 198 | /* | 226 | /* |
| 199 | * Each clock can have zero, one, or two dividers which change the | 227 | * Each clock can have zero, one, or two dividers which change the |
| 200 | * output rate of the clock. Each divider can be either fixed or | 228 | * output rate of the clock. Each divider can be either fixed or |
| @@ -360,7 +388,9 @@ struct bcm_clk_trig { | |||
| 360 | } | 388 | } |
| 361 | 389 | ||
| 362 | struct peri_clk_data { | 390 | struct peri_clk_data { |
| 391 | struct bcm_clk_policy policy; | ||
| 363 | struct bcm_clk_gate gate; | 392 | struct bcm_clk_gate gate; |
| 393 | struct bcm_clk_hyst hyst; | ||
| 364 | struct bcm_clk_trig pre_trig; | 394 | struct bcm_clk_trig pre_trig; |
| 365 | struct bcm_clk_div pre_div; | 395 | struct bcm_clk_div pre_div; |
| 366 | struct bcm_clk_trig trig; | 396 | struct bcm_clk_trig trig; |
| @@ -373,8 +403,7 @@ struct peri_clk_data { | |||
| 373 | 403 | ||
| 374 | struct kona_clk { | 404 | struct kona_clk { |
| 375 | struct clk_hw hw; | 405 | struct clk_hw hw; |
| 376 | struct clk_init_data init_data; | 406 | struct clk_init_data init_data; /* includes name of this clock */ |
| 377 | const char *name; /* name of this clock */ | ||
| 378 | struct ccu_data *ccu; /* ccu this clock is associated with */ | 407 | struct ccu_data *ccu; /* ccu this clock is associated with */ |
| 379 | enum bcm_clk_type type; | 408 | enum bcm_clk_type type; |
| 380 | union { | 409 | union { |
| @@ -385,14 +414,92 @@ struct kona_clk { | |||
| 385 | #define to_kona_clk(_hw) \ | 414 | #define to_kona_clk(_hw) \ |
| 386 | container_of(_hw, struct kona_clk, hw) | 415 | container_of(_hw, struct kona_clk, hw) |
| 387 | 416 | ||
| 388 | /* Exported globals */ | 417 | /* Initialization macro for an entry in a CCU's kona_clks[] array. */ |
| 418 | #define KONA_CLK(_ccu_name, _clk_name, _type) \ | ||
| 419 | { \ | ||
| 420 | .init_data = { \ | ||
| 421 | .name = #_clk_name, \ | ||
| 422 | .ops = &kona_ ## _type ## _clk_ops, \ | ||
| 423 | }, \ | ||
| 424 | .ccu = &_ccu_name ## _ccu_data, \ | ||
| 425 | .type = bcm_clk_ ## _type, \ | ||
| 426 | .u.data = &_clk_name ## _data, \ | ||
| 427 | } | ||
| 428 | #define LAST_KONA_CLK { .type = bcm_clk_none } | ||
| 389 | 429 | ||
| 390 | extern struct clk_ops kona_peri_clk_ops; | 430 | /* |
| 431 | * CCU policy control. To enable software update of the policy | ||
| 432 | * tables the CCU policy engine must be stopped by setting the | ||
| 433 | * software update enable bit (LVM_EN). After an update the engine | ||
| 434 | * is restarted using the GO bit and either the GO_ATL or GO_AC bit. | ||
| 435 | */ | ||
| 436 | struct bcm_lvm_en { | ||
| 437 | u32 offset; /* LVM_EN register offset */ | ||
| 438 | u32 bit; /* POLICY_CONFIG_EN bit in register */ | ||
| 439 | }; | ||
| 440 | |||
| 441 | /* Policy enable initialization macro */ | ||
| 442 | #define CCU_LVM_EN(_offset, _bit) \ | ||
| 443 | { \ | ||
| 444 | .offset = (_offset), \ | ||
| 445 | .bit = (_bit), \ | ||
| 446 | } | ||
| 447 | |||
| 448 | struct bcm_policy_ctl { | ||
| 449 | u32 offset; /* POLICY_CTL register offset */ | ||
| 450 | u32 go_bit; | ||
| 451 | u32 atl_bit; /* GO, GO_ATL, and GO_AC bits */ | ||
| 452 | u32 ac_bit; | ||
| 453 | }; | ||
| 454 | |||
| 455 | /* Policy control initialization macro */ | ||
| 456 | #define CCU_POLICY_CTL(_offset, _go_bit, _ac_bit, _atl_bit) \ | ||
| 457 | { \ | ||
| 458 | .offset = (_offset), \ | ||
| 459 | .go_bit = (_go_bit), \ | ||
| 460 | .ac_bit = (_ac_bit), \ | ||
| 461 | .atl_bit = (_atl_bit), \ | ||
| 462 | } | ||
| 463 | |||
| 464 | struct ccu_policy { | ||
| 465 | struct bcm_lvm_en enable; | ||
| 466 | struct bcm_policy_ctl control; | ||
| 467 | }; | ||
| 468 | |||
| 469 | /* | ||
| 470 | * Each CCU defines a mapped area of memory containing registers | ||
| 471 | * used to manage clocks implemented by the CCU. Access to memory | ||
| 472 | * within the CCU's space is serialized by a spinlock. Before any | ||
| 473 | * (other) address can be written, a special access "password" value | ||
| 474 | * must be written to its WR_ACCESS register (located at the base | ||
| 475 | * address of the range). We keep track of the name of each CCU as | ||
| 476 | * it is set up, and maintain them in a list. | ||
| 477 | */ | ||
| 478 | struct ccu_data { | ||
| 479 | void __iomem *base; /* base of mapped address space */ | ||
| 480 | spinlock_t lock; /* serialization lock */ | ||
| 481 | bool write_enabled; /* write access is currently enabled */ | ||
| 482 | struct ccu_policy policy; | ||
| 483 | struct list_head links; /* for ccu_list */ | ||
| 484 | struct device_node *node; | ||
| 485 | struct clk_onecell_data clk_data; | ||
| 486 | const char *name; | ||
| 487 | u32 range; /* byte range of address space */ | ||
| 488 | struct kona_clk kona_clks[]; /* must be last */ | ||
| 489 | }; | ||
| 391 | 490 | ||
| 392 | /* Help functions */ | 491 | /* Initialization for common fields in a Kona ccu_data structure */ |
| 492 | #define KONA_CCU_COMMON(_prefix, _name, _ccuname) \ | ||
| 493 | .name = #_name "_ccu", \ | ||
| 494 | .lock = __SPIN_LOCK_UNLOCKED(_name ## _ccu_data.lock), \ | ||
| 495 | .links = LIST_HEAD_INIT(_name ## _ccu_data.links), \ | ||
| 496 | .clk_data = { \ | ||
| 497 | .clk_num = _prefix ## _ ## _ccuname ## _CCU_CLOCK_COUNT, \ | ||
| 498 | } | ||
| 499 | |||
| 500 | /* Exported globals */ | ||
| 393 | 501 | ||
| 394 | #define PERI_CLK_SETUP(clks, ccu, id, name) \ | 502 | extern struct clk_ops kona_peri_clk_ops; |
| 395 | clks[id] = kona_clk_setup(ccu, #name, bcm_clk_peri, &name ## _data) | ||
| 396 | 503 | ||
| 397 | /* Externally visible functions */ | 504 | /* Externally visible functions */ |
| 398 | 505 | ||
| @@ -401,10 +508,9 @@ extern u64 scaled_div_max(struct bcm_clk_div *div); | |||
| 401 | extern u64 scaled_div_build(struct bcm_clk_div *div, u32 div_value, | 508 | extern u64 scaled_div_build(struct bcm_clk_div *div, u32 div_value, |
| 402 | u32 billionths); | 509 | u32 billionths); |
| 403 | 510 | ||
| 404 | extern struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name, | 511 | extern struct clk *kona_clk_setup(struct kona_clk *bcm_clk); |
| 405 | enum bcm_clk_type type, void *data); | 512 | extern void __init kona_dt_ccu_setup(struct ccu_data *ccu, |
| 406 | extern void __init kona_dt_ccu_setup(struct device_node *node, | 513 | struct device_node *node); |
| 407 | int (*ccu_clks_setup)(struct ccu_data *)); | ||
| 408 | extern bool __init kona_ccu_init(struct ccu_data *ccu); | 514 | extern bool __init kona_ccu_init(struct ccu_data *ccu); |
| 409 | 515 | ||
| 410 | #endif /* _CLK_KONA_H */ | 516 | #endif /* _CLK_KONA_H */ |
diff --git a/drivers/clk/berlin/Makefile b/drivers/clk/berlin/Makefile new file mode 100644 index 000000000000..2a36ab710a07 --- /dev/null +++ b/drivers/clk/berlin/Makefile | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | obj-y += berlin2-avpll.o berlin2-pll.o berlin2-div.o | ||
| 2 | obj-$(CONFIG_MACH_BERLIN_BG2) += bg2.o | ||
| 3 | obj-$(CONFIG_MACH_BERLIN_BG2CD) += bg2.o | ||
| 4 | obj-$(CONFIG_MACH_BERLIN_BG2Q) += bg2q.o | ||
diff --git a/drivers/clk/berlin/berlin2-avpll.c b/drivers/clk/berlin/berlin2-avpll.c new file mode 100644 index 000000000000..fd0f26c38465 --- /dev/null +++ b/drivers/clk/berlin/berlin2-avpll.c | |||
| @@ -0,0 +1,393 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014 Marvell Technology Group Ltd. | ||
| 3 | * | ||
| 4 | * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | ||
| 5 | * Alexandre Belloni <alexandre.belloni@free-electrons.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms and conditions of the GNU General Public License, | ||
| 9 | * version 2, as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 14 | * more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License along with | ||
| 17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #include <linux/clk-provider.h> | ||
| 20 | #include <linux/io.h> | ||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/of.h> | ||
| 23 | #include <linux/of_address.h> | ||
| 24 | #include <linux/slab.h> | ||
| 25 | |||
| 26 | #include "berlin2-avpll.h" | ||
| 27 | |||
| 28 | /* | ||
| 29 | * Berlin2 SoCs comprise up to two PLLs called AVPLL built upon a | ||
| 30 | * VCO with 8 channels each, channel 8 is the odd-one-out and does | ||
| 31 | * not provide mul/div. | ||
| 32 | * | ||
| 33 | * Unfortunately, its registers are not named but just numbered. To | ||
| 34 | * get in at least some kind of structure, we split each AVPLL into | ||
| 35 | * the VCOs and each channel into separate clock drivers. | ||
| 36 | * | ||
| 37 | * Also, here and there the VCO registers are a bit different with | ||
| 38 | * respect to bit shifts. Make sure to add a comment for those. | ||
| 39 | */ | ||
| 40 | #define NUM_CHANNELS 8 | ||
| 41 | |||
| 42 | #define AVPLL_CTRL(x) ((x) * 0x4) | ||
| 43 | |||
| 44 | #define VCO_CTRL0 AVPLL_CTRL(0) | ||
| 45 | /* BG2/BG2CDs VCO_B has an additional shift of 4 for its VCO_CTRL0 reg */ | ||
| 46 | #define VCO_RESET BIT(0) | ||
| 47 | #define VCO_POWERUP BIT(1) | ||
| 48 | #define VCO_INTERPOL_SHIFT 2 | ||
| 49 | #define VCO_INTERPOL_MASK (0xf << VCO_INTERPOL_SHIFT) | ||
| 50 | #define VCO_REG1V45_SEL_SHIFT 6 | ||
| 51 | #define VCO_REG1V45_SEL(x) ((x) << VCO_REG1V45_SEL_SHIFT) | ||
| 52 | #define VCO_REG1V45_SEL_1V40 VCO_REG1V45_SEL(0) | ||
| 53 | #define VCO_REG1V45_SEL_1V45 VCO_REG1V45_SEL(1) | ||
| 54 | #define VCO_REG1V45_SEL_1V50 VCO_REG1V45_SEL(2) | ||
| 55 | #define VCO_REG1V45_SEL_1V55 VCO_REG1V45_SEL(3) | ||
| 56 | #define VCO_REG1V45_SEL_MASK VCO_REG1V45_SEL(3) | ||
| 57 | #define VCO_REG0V9_SEL_SHIFT 8 | ||
| 58 | #define VCO_REG0V9_SEL_MASK (0xf << VCO_REG0V9_SEL_SHIFT) | ||
| 59 | #define VCO_VTHCAL_SHIFT 12 | ||
| 60 | #define VCO_VTHCAL(x) ((x) << VCO_VTHCAL_SHIFT) | ||
| 61 | #define VCO_VTHCAL_0V90 VCO_VTHCAL(0) | ||
| 62 | #define VCO_VTHCAL_0V95 VCO_VTHCAL(1) | ||
| 63 | #define VCO_VTHCAL_1V00 VCO_VTHCAL(2) | ||
| 64 | #define VCO_VTHCAL_1V05 VCO_VTHCAL(3) | ||
| 65 | #define VCO_VTHCAL_MASK VCO_VTHCAL(3) | ||
| 66 | #define VCO_KVCOEXT_SHIFT 14 | ||
| 67 | #define VCO_KVCOEXT_MASK (0x3 << VCO_KVCOEXT_SHIFT) | ||
| 68 | #define VCO_KVCOEXT_ENABLE BIT(17) | ||
| 69 | #define VCO_V2IEXT_SHIFT 18 | ||
| 70 | #define VCO_V2IEXT_MASK (0xf << VCO_V2IEXT_SHIFT) | ||
| 71 | #define VCO_V2IEXT_ENABLE BIT(22) | ||
| 72 | #define VCO_SPEED_SHIFT 23 | ||
| 73 | #define VCO_SPEED(x) ((x) << VCO_SPEED_SHIFT) | ||
| 74 | #define VCO_SPEED_1G08_1G21 VCO_SPEED(0) | ||
| 75 | #define VCO_SPEED_1G21_1G40 VCO_SPEED(1) | ||
| 76 | #define VCO_SPEED_1G40_1G61 VCO_SPEED(2) | ||
| 77 | #define VCO_SPEED_1G61_1G86 VCO_SPEED(3) | ||
| 78 | #define VCO_SPEED_1G86_2G00 VCO_SPEED(4) | ||
| 79 | #define VCO_SPEED_2G00_2G22 VCO_SPEED(5) | ||
| 80 | #define VCO_SPEED_2G22 VCO_SPEED(6) | ||
| 81 | #define VCO_SPEED_MASK VCO_SPEED(0x7) | ||
| 82 | #define VCO_CLKDET_ENABLE BIT(26) | ||
| 83 | #define VCO_CTRL1 AVPLL_CTRL(1) | ||
| 84 | #define VCO_REFDIV_SHIFT 0 | ||
| 85 | #define VCO_REFDIV(x) ((x) << VCO_REFDIV_SHIFT) | ||
| 86 | #define VCO_REFDIV_1 VCO_REFDIV(0) | ||
| 87 | #define VCO_REFDIV_2 VCO_REFDIV(1) | ||
| 88 | #define VCO_REFDIV_4 VCO_REFDIV(2) | ||
| 89 | #define VCO_REFDIV_3 VCO_REFDIV(3) | ||
| 90 | #define VCO_REFDIV_MASK VCO_REFDIV(0x3f) | ||
| 91 | #define VCO_FBDIV_SHIFT 6 | ||
| 92 | #define VCO_FBDIV(x) ((x) << VCO_FBDIV_SHIFT) | ||
| 93 | #define VCO_FBDIV_MASK VCO_FBDIV(0xff) | ||
| 94 | #define VCO_ICP_SHIFT 14 | ||
| 95 | /* PLL Charge Pump Current = 10uA * (x + 1) */ | ||
| 96 | #define VCO_ICP(x) ((x) << VCO_ICP_SHIFT) | ||
| 97 | #define VCO_ICP_MASK VCO_ICP(0xf) | ||
| 98 | #define VCO_LOAD_CAP BIT(18) | ||
| 99 | #define VCO_CALIBRATION_START BIT(19) | ||
| 100 | #define VCO_FREQOFFSETn(x) AVPLL_CTRL(3 + (x)) | ||
| 101 | #define VCO_FREQOFFSET_MASK 0x7ffff | ||
| 102 | #define VCO_CTRL10 AVPLL_CTRL(10) | ||
| 103 | #define VCO_POWERUP_CH1 BIT(20) | ||
| 104 | #define VCO_CTRL11 AVPLL_CTRL(11) | ||
| 105 | #define VCO_CTRL12 AVPLL_CTRL(12) | ||
| 106 | #define VCO_CTRL13 AVPLL_CTRL(13) | ||
| 107 | #define VCO_CTRL14 AVPLL_CTRL(14) | ||
| 108 | #define VCO_CTRL15 AVPLL_CTRL(15) | ||
| 109 | #define VCO_SYNC1n(x) AVPLL_CTRL(15 + (x)) | ||
| 110 | #define VCO_SYNC1_MASK 0x1ffff | ||
| 111 | #define VCO_SYNC2n(x) AVPLL_CTRL(23 + (x)) | ||
| 112 | #define VCO_SYNC2_MASK 0x1ffff | ||
| 113 | #define VCO_CTRL30 AVPLL_CTRL(30) | ||
| 114 | #define VCO_DPLL_CH1_ENABLE BIT(17) | ||
| 115 | |||
| 116 | struct berlin2_avpll_vco { | ||
| 117 | struct clk_hw hw; | ||
| 118 | void __iomem *base; | ||
| 119 | u8 flags; | ||
| 120 | }; | ||
| 121 | |||
| 122 | #define to_avpll_vco(hw) container_of(hw, struct berlin2_avpll_vco, hw) | ||
| 123 | |||
| 124 | static int berlin2_avpll_vco_is_enabled(struct clk_hw *hw) | ||
| 125 | { | ||
| 126 | struct berlin2_avpll_vco *vco = to_avpll_vco(hw); | ||
| 127 | u32 reg; | ||
| 128 | |||
| 129 | reg = readl_relaxed(vco->base + VCO_CTRL0); | ||
| 130 | if (vco->flags & BERLIN2_AVPLL_BIT_QUIRK) | ||
| 131 | reg >>= 4; | ||
| 132 | |||
| 133 | return !!(reg & VCO_POWERUP); | ||
| 134 | } | ||
| 135 | |||
| 136 | static int berlin2_avpll_vco_enable(struct clk_hw *hw) | ||
| 137 | { | ||
| 138 | struct berlin2_avpll_vco *vco = to_avpll_vco(hw); | ||
| 139 | u32 reg; | ||
| 140 | |||
| 141 | reg = readl_relaxed(vco->base + VCO_CTRL0); | ||
| 142 | if (vco->flags & BERLIN2_AVPLL_BIT_QUIRK) | ||
| 143 | reg |= VCO_POWERUP << 4; | ||
| 144 | else | ||
| 145 | reg |= VCO_POWERUP; | ||
| 146 | writel_relaxed(reg, vco->base + VCO_CTRL0); | ||
| 147 | |||
| 148 | return 0; | ||
| 149 | } | ||
| 150 | |||
| 151 | static void berlin2_avpll_vco_disable(struct clk_hw *hw) | ||
| 152 | { | ||
| 153 | struct berlin2_avpll_vco *vco = to_avpll_vco(hw); | ||
| 154 | u32 reg; | ||
| 155 | |||
| 156 | reg = readl_relaxed(vco->base + VCO_CTRL0); | ||
| 157 | if (vco->flags & BERLIN2_AVPLL_BIT_QUIRK) | ||
| 158 | reg &= ~(VCO_POWERUP << 4); | ||
| 159 | else | ||
| 160 | reg &= ~VCO_POWERUP; | ||
| 161 | writel_relaxed(reg, vco->base + VCO_CTRL0); | ||
| 162 | } | ||
| 163 | |||
| 164 | static u8 vco_refdiv[] = { 1, 2, 4, 3 }; | ||
| 165 | |||
| 166 | static unsigned long | ||
| 167 | berlin2_avpll_vco_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | ||
| 168 | { | ||
| 169 | struct berlin2_avpll_vco *vco = to_avpll_vco(hw); | ||
| 170 | u32 reg, refdiv, fbdiv; | ||
| 171 | u64 freq = parent_rate; | ||
| 172 | |||
| 173 | /* AVPLL VCO frequency: Fvco = (Fref / refdiv) * fbdiv */ | ||
| 174 | reg = readl_relaxed(vco->base + VCO_CTRL1); | ||
| 175 | refdiv = (reg & VCO_REFDIV_MASK) >> VCO_REFDIV_SHIFT; | ||
| 176 | refdiv = vco_refdiv[refdiv]; | ||
| 177 | fbdiv = (reg & VCO_FBDIV_MASK) >> VCO_FBDIV_SHIFT; | ||
| 178 | freq *= fbdiv; | ||
| 179 | do_div(freq, refdiv); | ||
| 180 | |||
| 181 | return (unsigned long)freq; | ||
| 182 | } | ||
| 183 | |||
| 184 | static const struct clk_ops berlin2_avpll_vco_ops = { | ||
| 185 | .is_enabled = berlin2_avpll_vco_is_enabled, | ||
| 186 | .enable = berlin2_avpll_vco_enable, | ||
| 187 | .disable = berlin2_avpll_vco_disable, | ||
| 188 | .recalc_rate = berlin2_avpll_vco_recalc_rate, | ||
| 189 | }; | ||
| 190 | |||
| 191 | struct clk * __init berlin2_avpll_vco_register(void __iomem *base, | ||
| 192 | const char *name, const char *parent_name, | ||
| 193 | u8 vco_flags, unsigned long flags) | ||
| 194 | { | ||
| 195 | struct berlin2_avpll_vco *vco; | ||
| 196 | struct clk_init_data init; | ||
| 197 | |||
| 198 | vco = kzalloc(sizeof(*vco), GFP_KERNEL); | ||
| 199 | if (!vco) | ||
| 200 | return ERR_PTR(-ENOMEM); | ||
| 201 | |||
| 202 | vco->base = base; | ||
| 203 | vco->flags = vco_flags; | ||
| 204 | vco->hw.init = &init; | ||
| 205 | init.name = name; | ||
| 206 | init.ops = &berlin2_avpll_vco_ops; | ||
| 207 | init.parent_names = &parent_name; | ||
| 208 | init.num_parents = 1; | ||
| 209 | init.flags = flags; | ||
| 210 | |||
| 211 | return clk_register(NULL, &vco->hw); | ||
| 212 | } | ||
| 213 | |||
| 214 | struct berlin2_avpll_channel { | ||
| 215 | struct clk_hw hw; | ||
| 216 | void __iomem *base; | ||
| 217 | u8 flags; | ||
| 218 | u8 index; | ||
| 219 | }; | ||
| 220 | |||
| 221 | #define to_avpll_channel(hw) container_of(hw, struct berlin2_avpll_channel, hw) | ||
| 222 | |||
| 223 | static int berlin2_avpll_channel_is_enabled(struct clk_hw *hw) | ||
| 224 | { | ||
| 225 | struct berlin2_avpll_channel *ch = to_avpll_channel(hw); | ||
| 226 | u32 reg; | ||
| 227 | |||
| 228 | if (ch->index == 7) | ||
| 229 | return 1; | ||
| 230 | |||
| 231 | reg = readl_relaxed(ch->base + VCO_CTRL10); | ||
| 232 | reg &= VCO_POWERUP_CH1 << ch->index; | ||
| 233 | |||
| 234 | return !!reg; | ||
| 235 | } | ||
| 236 | |||
| 237 | static int berlin2_avpll_channel_enable(struct clk_hw *hw) | ||
| 238 | { | ||
| 239 | struct berlin2_avpll_channel *ch = to_avpll_channel(hw); | ||
| 240 | u32 reg; | ||
| 241 | |||
| 242 | reg = readl_relaxed(ch->base + VCO_CTRL10); | ||
| 243 | reg |= VCO_POWERUP_CH1 << ch->index; | ||
| 244 | writel_relaxed(reg, ch->base + VCO_CTRL10); | ||
| 245 | |||
| 246 | return 0; | ||
| 247 | } | ||
| 248 | |||
| 249 | static void berlin2_avpll_channel_disable(struct clk_hw *hw) | ||
| 250 | { | ||
| 251 | struct berlin2_avpll_channel *ch = to_avpll_channel(hw); | ||
| 252 | u32 reg; | ||
| 253 | |||
| 254 | reg = readl_relaxed(ch->base + VCO_CTRL10); | ||
| 255 | reg &= ~(VCO_POWERUP_CH1 << ch->index); | ||
| 256 | writel_relaxed(reg, ch->base + VCO_CTRL10); | ||
| 257 | } | ||
| 258 | |||
| 259 | static const u8 div_hdmi[] = { 1, 2, 4, 6 }; | ||
| 260 | static const u8 div_av1[] = { 1, 2, 5, 5 }; | ||
| 261 | |||
| 262 | static unsigned long | ||
| 263 | berlin2_avpll_channel_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | ||
| 264 | { | ||
| 265 | struct berlin2_avpll_channel *ch = to_avpll_channel(hw); | ||
| 266 | u32 reg, div_av2, div_av3, divider = 1; | ||
| 267 | u64 freq = parent_rate; | ||
| 268 | |||
| 269 | reg = readl_relaxed(ch->base + VCO_CTRL30); | ||
| 270 | if ((reg & (VCO_DPLL_CH1_ENABLE << ch->index)) == 0) | ||
| 271 | goto skip_div; | ||
| 272 | |||
| 273 | /* | ||
| 274 | * Fch = (Fref * sync2) / | ||
| 275 | * (sync1 * div_hdmi * div_av1 * div_av2 * div_av3) | ||
| 276 | */ | ||
| 277 | |||
| 278 | reg = readl_relaxed(ch->base + VCO_SYNC1n(ch->index)); | ||
| 279 | /* BG2/BG2CDs SYNC1 reg on AVPLL_B channel 1 is shifted by 4 */ | ||
| 280 | if (ch->flags & BERLIN2_AVPLL_BIT_QUIRK && ch->index == 0) | ||
| 281 | reg >>= 4; | ||
| 282 | divider = reg & VCO_SYNC1_MASK; | ||
| 283 | |||
| 284 | reg = readl_relaxed(ch->base + VCO_SYNC2n(ch->index)); | ||
| 285 | freq *= reg & VCO_SYNC2_MASK; | ||
| 286 | |||
| 287 | /* Channel 8 has no dividers */ | ||
| 288 | if (ch->index == 7) | ||
| 289 | goto skip_div; | ||
| 290 | |||
| 291 | /* | ||
| 292 | * HDMI divider start at VCO_CTRL11, bit 7; MSB is enable, lower 2 bit | ||
| 293 | * determine divider. | ||
| 294 | */ | ||
| 295 | reg = readl_relaxed(ch->base + VCO_CTRL11) >> 7; | ||
| 296 | reg = (reg >> (ch->index * 3)); | ||
| 297 | if (reg & BIT(2)) | ||
| 298 | divider *= div_hdmi[reg & 0x3]; | ||
| 299 | |||
| 300 | /* | ||
| 301 | * AV1 divider start at VCO_CTRL11, bit 28; MSB is enable, lower 2 bit | ||
| 302 | * determine divider. | ||
| 303 | */ | ||
| 304 | if (ch->index == 0) { | ||
| 305 | reg = readl_relaxed(ch->base + VCO_CTRL11); | ||
| 306 | reg >>= 28; | ||
| 307 | } else { | ||
| 308 | reg = readl_relaxed(ch->base + VCO_CTRL12); | ||
| 309 | reg >>= (ch->index-1) * 3; | ||
| 310 | } | ||
| 311 | if (reg & BIT(2)) | ||
| 312 | divider *= div_av1[reg & 0x3]; | ||
| 313 | |||
| 314 | /* | ||
| 315 | * AV2 divider start at VCO_CTRL12, bit 18; each 7 bits wide, | ||
| 316 | * zero is not a valid value. | ||
| 317 | */ | ||
| 318 | if (ch->index < 2) { | ||
| 319 | reg = readl_relaxed(ch->base + VCO_CTRL12); | ||
| 320 | reg >>= 18 + (ch->index * 7); | ||
| 321 | } else if (ch->index < 7) { | ||
| 322 | reg = readl_relaxed(ch->base + VCO_CTRL13); | ||
| 323 | reg >>= (ch->index - 2) * 7; | ||
| 324 | } else { | ||
| 325 | reg = readl_relaxed(ch->base + VCO_CTRL14); | ||
| 326 | } | ||
| 327 | div_av2 = reg & 0x7f; | ||
| 328 | if (div_av2) | ||
| 329 | divider *= div_av2; | ||
| 330 | |||
| 331 | /* | ||
| 332 | * AV3 divider start at VCO_CTRL14, bit 7; each 4 bits wide. | ||
| 333 | * AV2/AV3 form a fractional divider, where only specfic values for AV3 | ||
| 334 | * are allowed. AV3 != 0 divides by AV2/2, AV3=0 is bypass. | ||
| 335 | */ | ||
| 336 | if (ch->index < 6) { | ||
| 337 | reg = readl_relaxed(ch->base + VCO_CTRL14); | ||
| 338 | reg >>= 7 + (ch->index * 4); | ||
| 339 | } else { | ||
| 340 | reg = readl_relaxed(ch->base + VCO_CTRL15); | ||
| 341 | } | ||
| 342 | div_av3 = reg & 0xf; | ||
| 343 | if (div_av2 && div_av3) | ||
| 344 | freq *= 2; | ||
| 345 | |||
| 346 | skip_div: | ||
| 347 | do_div(freq, divider); | ||
| 348 | return (unsigned long)freq; | ||
| 349 | } | ||
| 350 | |||
| 351 | static const struct clk_ops berlin2_avpll_channel_ops = { | ||
| 352 | .is_enabled = berlin2_avpll_channel_is_enabled, | ||
| 353 | .enable = berlin2_avpll_channel_enable, | ||
| 354 | .disable = berlin2_avpll_channel_disable, | ||
| 355 | .recalc_rate = berlin2_avpll_channel_recalc_rate, | ||
| 356 | }; | ||
| 357 | |||
| 358 | /* | ||
| 359 | * Another nice quirk: | ||
| 360 | * On some production SoCs, AVPLL channels are scrambled with respect | ||
| 361 | * to the channel numbering in the registers but still referenced by | ||
| 362 | * their original channel numbers. We deal with it by having a flag | ||
| 363 | * and a translation table for the index. | ||
| 364 | */ | ||
| 365 | static const u8 quirk_index[] __initconst = { 0, 6, 5, 4, 3, 2, 1, 7 }; | ||
| 366 | |||
| 367 | struct clk * __init berlin2_avpll_channel_register(void __iomem *base, | ||
| 368 | const char *name, u8 index, const char *parent_name, | ||
| 369 | u8 ch_flags, unsigned long flags) | ||
| 370 | { | ||
| 371 | struct berlin2_avpll_channel *ch; | ||
| 372 | struct clk_init_data init; | ||
| 373 | |||
| 374 | ch = kzalloc(sizeof(*ch), GFP_KERNEL); | ||
| 375 | if (!ch) | ||
| 376 | return ERR_PTR(-ENOMEM); | ||
| 377 | |||
| 378 | ch->base = base; | ||
| 379 | if (ch_flags & BERLIN2_AVPLL_SCRAMBLE_QUIRK) | ||
| 380 | ch->index = quirk_index[index]; | ||
| 381 | else | ||
| 382 | ch->index = index; | ||
| 383 | |||
| 384 | ch->flags = ch_flags; | ||
| 385 | ch->hw.init = &init; | ||
| 386 | init.name = name; | ||
| 387 | init.ops = &berlin2_avpll_channel_ops; | ||
| 388 | init.parent_names = &parent_name; | ||
| 389 | init.num_parents = 1; | ||
| 390 | init.flags = flags; | ||
| 391 | |||
| 392 | return clk_register(NULL, &ch->hw); | ||
| 393 | } | ||
diff --git a/drivers/clk/berlin/berlin2-avpll.h b/drivers/clk/berlin/berlin2-avpll.h new file mode 100644 index 000000000000..a37f5068d299 --- /dev/null +++ b/drivers/clk/berlin/berlin2-avpll.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014 Marvell Technology Group Ltd. | ||
| 3 | * | ||
| 4 | * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | ||
| 5 | * Alexandre Belloni <alexandre.belloni@free-electrons.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms and conditions of the GNU General Public License, | ||
| 9 | * version 2, as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 14 | * more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License along with | ||
| 17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #ifndef __BERLIN2_AVPLL_H | ||
| 20 | #define __BERLIN2_AVPLL_H | ||
| 21 | |||
| 22 | struct clk; | ||
| 23 | |||
| 24 | #define BERLIN2_AVPLL_BIT_QUIRK BIT(0) | ||
| 25 | #define BERLIN2_AVPLL_SCRAMBLE_QUIRK BIT(1) | ||
| 26 | |||
| 27 | struct clk * __init | ||
| 28 | berlin2_avpll_vco_register(void __iomem *base, const char *name, | ||
| 29 | const char *parent_name, u8 vco_flags, unsigned long flags); | ||
| 30 | |||
| 31 | struct clk * __init | ||
| 32 | berlin2_avpll_channel_register(void __iomem *base, const char *name, | ||
| 33 | u8 index, const char *parent_name, u8 ch_flags, | ||
| 34 | unsigned long flags); | ||
| 35 | |||
| 36 | #endif /* __BERLIN2_AVPLL_H */ | ||
diff --git a/drivers/clk/berlin/berlin2-div.c b/drivers/clk/berlin/berlin2-div.c new file mode 100644 index 000000000000..81ff97f8aa0b --- /dev/null +++ b/drivers/clk/berlin/berlin2-div.c | |||
| @@ -0,0 +1,265 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014 Marvell Technology Group Ltd. | ||
| 3 | * | ||
| 4 | * Alexandre Belloni <alexandre.belloni@free-electrons.com> | ||
| 5 | * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms and conditions of the GNU General Public License, | ||
| 9 | * version 2, as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 14 | * more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License along with | ||
| 17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #include <linux/bitops.h> | ||
| 20 | #include <linux/clk-provider.h> | ||
| 21 | #include <linux/of.h> | ||
| 22 | #include <linux/of_address.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | #include <linux/spinlock.h> | ||
| 25 | |||
| 26 | #include "berlin2-div.h" | ||
| 27 | |||
| 28 | /* | ||
| 29 | * Clock dividers in Berlin2 SoCs comprise a complex cell to select | ||
| 30 | * input pll and divider. The virtual structure as it is used in Marvell | ||
| 31 | * BSP code can be seen as: | ||
| 32 | * | ||
| 33 | * +---+ | ||
| 34 | * pll0 --------------->| 0 | +---+ | ||
| 35 | * +---+ |(B)|--+--------------->| 0 | +---+ | ||
| 36 | * pll1.0 -->| 0 | +-->| 1 | | +--------+ |(E)|----->| 0 | +---+ | ||
| 37 | * pll1.1 -->| 1 | | +---+ +-->|(C) 1:M |-->| 1 | |(F)|-->|(G)|-> | ||
| 38 | * ... -->|(A)|--+ | +--------+ +---+ +-->| 1 | +---+ | ||
| 39 | * ... -->| | +-->|(D) 1:3 |----------+ +---+ | ||
| 40 | * pll1.N -->| N | +--------- | ||
| 41 | * +---+ | ||
| 42 | * | ||
| 43 | * (A) input pll clock mux controlled by <PllSelect[1:n]> | ||
| 44 | * (B) input pll bypass mux controlled by <PllSwitch> | ||
| 45 | * (C) programmable clock divider controlled by <Select[1:n]> | ||
| 46 | * (D) constant div-by-3 clock divider | ||
| 47 | * (E) programmable clock divider bypass controlled by <Switch> | ||
| 48 | * (F) constant div-by-3 clock mux controlled by <D3Switch> | ||
| 49 | * (G) clock gate controlled by <Enable> | ||
| 50 | * | ||
| 51 | * For whatever reason, above control signals come in two flavors: | ||
| 52 | * - single register dividers with all bits in one register | ||
| 53 | * - shared register dividers with bits spread over multiple registers | ||
| 54 | * (including signals for the same cell spread over consecutive registers) | ||
| 55 | * | ||
| 56 | * Also, clock gate and pll mux is not available on every div cell, so | ||
| 57 | * we have to deal with those, too. We reuse common clock composite driver | ||
| 58 | * for it. | ||
| 59 | */ | ||
| 60 | |||
| 61 | #define PLL_SELECT_MASK 0x7 | ||
| 62 | #define DIV_SELECT_MASK 0x7 | ||
| 63 | |||
| 64 | struct berlin2_div { | ||
| 65 | struct clk_hw hw; | ||
| 66 | void __iomem *base; | ||
| 67 | struct berlin2_div_map map; | ||
| 68 | spinlock_t *lock; | ||
| 69 | }; | ||
| 70 | |||
| 71 | #define to_berlin2_div(hw) container_of(hw, struct berlin2_div, hw) | ||
| 72 | |||
| 73 | static u8 clk_div[] = { 1, 2, 4, 6, 8, 12, 1, 1 }; | ||
| 74 | |||
| 75 | static int berlin2_div_is_enabled(struct clk_hw *hw) | ||
| 76 | { | ||
| 77 | struct berlin2_div *div = to_berlin2_div(hw); | ||
| 78 | struct berlin2_div_map *map = &div->map; | ||
| 79 | u32 reg; | ||
| 80 | |||
| 81 | if (div->lock) | ||
| 82 | spin_lock(div->lock); | ||
| 83 | |||
| 84 | reg = readl_relaxed(div->base + map->gate_offs); | ||
| 85 | reg >>= map->gate_shift; | ||
| 86 | |||
| 87 | if (div->lock) | ||
| 88 | spin_unlock(div->lock); | ||
| 89 | |||
| 90 | return (reg & 0x1); | ||
| 91 | } | ||
| 92 | |||
| 93 | static int berlin2_div_enable(struct clk_hw *hw) | ||
| 94 | { | ||
| 95 | struct berlin2_div *div = to_berlin2_div(hw); | ||
| 96 | struct berlin2_div_map *map = &div->map; | ||
| 97 | u32 reg; | ||
| 98 | |||
| 99 | if (div->lock) | ||
| 100 | spin_lock(div->lock); | ||
| 101 | |||
| 102 | reg = readl_relaxed(div->base + map->gate_offs); | ||
| 103 | reg |= BIT(map->gate_shift); | ||
| 104 | writel_relaxed(reg, div->base + map->gate_offs); | ||
| 105 | |||
| 106 | if (div->lock) | ||
| 107 | spin_unlock(div->lock); | ||
| 108 | |||
| 109 | return 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | static void berlin2_div_disable(struct clk_hw *hw) | ||
| 113 | { | ||
| 114 | struct berlin2_div *div = to_berlin2_div(hw); | ||
| 115 | struct berlin2_div_map *map = &div->map; | ||
| 116 | u32 reg; | ||
| 117 | |||
| 118 | if (div->lock) | ||
| 119 | spin_lock(div->lock); | ||
| 120 | |||
| 121 | reg = readl_relaxed(div->base + map->gate_offs); | ||
| 122 | reg &= ~BIT(map->gate_shift); | ||
| 123 | writel_relaxed(reg, div->base + map->gate_offs); | ||
| 124 | |||
| 125 | if (div->lock) | ||
| 126 | spin_unlock(div->lock); | ||
| 127 | } | ||
| 128 | |||
| 129 | static int berlin2_div_set_parent(struct clk_hw *hw, u8 index) | ||
| 130 | { | ||
| 131 | struct berlin2_div *div = to_berlin2_div(hw); | ||
| 132 | struct berlin2_div_map *map = &div->map; | ||
| 133 | u32 reg; | ||
| 134 | |||
| 135 | if (div->lock) | ||
| 136 | spin_lock(div->lock); | ||
| 137 | |||
| 138 | /* index == 0 is PLL_SWITCH */ | ||
| 139 | reg = readl_relaxed(div->base + map->pll_switch_offs); | ||
| 140 | if (index == 0) | ||
| 141 | reg &= ~BIT(map->pll_switch_shift); | ||
| 142 | else | ||
| 143 | reg |= BIT(map->pll_switch_shift); | ||
| 144 | writel_relaxed(reg, div->base + map->pll_switch_offs); | ||
| 145 | |||
| 146 | /* index > 0 is PLL_SELECT */ | ||
| 147 | if (index > 0) { | ||
| 148 | reg = readl_relaxed(div->base + map->pll_select_offs); | ||
| 149 | reg &= ~(PLL_SELECT_MASK << map->pll_select_shift); | ||
| 150 | reg |= (index - 1) << map->pll_select_shift; | ||
| 151 | writel_relaxed(reg, div->base + map->pll_select_offs); | ||
| 152 | } | ||
| 153 | |||
| 154 | if (div->lock) | ||
| 155 | spin_unlock(div->lock); | ||
| 156 | |||
| 157 | return 0; | ||
| 158 | } | ||
| 159 | |||
| 160 | static u8 berlin2_div_get_parent(struct clk_hw *hw) | ||
| 161 | { | ||
| 162 | struct berlin2_div *div = to_berlin2_div(hw); | ||
| 163 | struct berlin2_div_map *map = &div->map; | ||
| 164 | u32 reg; | ||
| 165 | u8 index = 0; | ||
| 166 | |||
| 167 | if (div->lock) | ||
| 168 | spin_lock(div->lock); | ||
| 169 | |||
| 170 | /* PLL_SWITCH == 0 is index 0 */ | ||
| 171 | reg = readl_relaxed(div->base + map->pll_switch_offs); | ||
| 172 | reg &= BIT(map->pll_switch_shift); | ||
| 173 | if (reg) { | ||
| 174 | reg = readl_relaxed(div->base + map->pll_select_offs); | ||
| 175 | reg >>= map->pll_select_shift; | ||
| 176 | reg &= PLL_SELECT_MASK; | ||
| 177 | index = 1 + reg; | ||
| 178 | } | ||
| 179 | |||
| 180 | if (div->lock) | ||
| 181 | spin_unlock(div->lock); | ||
| 182 | |||
| 183 | return index; | ||
| 184 | } | ||
| 185 | |||
| 186 | static unsigned long berlin2_div_recalc_rate(struct clk_hw *hw, | ||
| 187 | unsigned long parent_rate) | ||
| 188 | { | ||
| 189 | struct berlin2_div *div = to_berlin2_div(hw); | ||
| 190 | struct berlin2_div_map *map = &div->map; | ||
| 191 | u32 divsw, div3sw, divider = 1; | ||
| 192 | |||
| 193 | if (div->lock) | ||
| 194 | spin_lock(div->lock); | ||
| 195 | |||
| 196 | divsw = readl_relaxed(div->base + map->div_switch_offs) & | ||
| 197 | (1 << map->div_switch_shift); | ||
| 198 | div3sw = readl_relaxed(div->base + map->div3_switch_offs) & | ||
| 199 | (1 << map->div3_switch_shift); | ||
| 200 | |||
| 201 | /* constant divide-by-3 (dominant) */ | ||
| 202 | if (div3sw != 0) { | ||
| 203 | divider = 3; | ||
| 204 | /* divider can be bypassed with DIV_SWITCH == 0 */ | ||
| 205 | } else if (divsw == 0) { | ||
| 206 | divider = 1; | ||
| 207 | /* clock divider determined by DIV_SELECT */ | ||
| 208 | } else { | ||
| 209 | u32 reg; | ||
| 210 | reg = readl_relaxed(div->base + map->div_select_offs); | ||
| 211 | reg >>= map->div_select_shift; | ||
| 212 | reg &= DIV_SELECT_MASK; | ||
| 213 | divider = clk_div[reg]; | ||
| 214 | } | ||
| 215 | |||
| 216 | if (div->lock) | ||
| 217 | spin_unlock(div->lock); | ||
| 218 | |||
| 219 | return parent_rate / divider; | ||
| 220 | } | ||
| 221 | |||
| 222 | static const struct clk_ops berlin2_div_rate_ops = { | ||
| 223 | .recalc_rate = berlin2_div_recalc_rate, | ||
| 224 | }; | ||
| 225 | |||
| 226 | static const struct clk_ops berlin2_div_gate_ops = { | ||
| 227 | .is_enabled = berlin2_div_is_enabled, | ||
| 228 | .enable = berlin2_div_enable, | ||
| 229 | .disable = berlin2_div_disable, | ||
| 230 | }; | ||
| 231 | |||
| 232 | static const struct clk_ops berlin2_div_mux_ops = { | ||
| 233 | .set_parent = berlin2_div_set_parent, | ||
| 234 | .get_parent = berlin2_div_get_parent, | ||
| 235 | }; | ||
| 236 | |||
| 237 | struct clk * __init | ||
| 238 | berlin2_div_register(const struct berlin2_div_map *map, | ||
| 239 | void __iomem *base, const char *name, u8 div_flags, | ||
| 240 | const char **parent_names, int num_parents, | ||
| 241 | unsigned long flags, spinlock_t *lock) | ||
| 242 | { | ||
| 243 | const struct clk_ops *mux_ops = &berlin2_div_mux_ops; | ||
| 244 | const struct clk_ops *rate_ops = &berlin2_div_rate_ops; | ||
| 245 | const struct clk_ops *gate_ops = &berlin2_div_gate_ops; | ||
| 246 | struct berlin2_div *div; | ||
| 247 | |||
| 248 | div = kzalloc(sizeof(*div), GFP_KERNEL); | ||
| 249 | if (!div) | ||
| 250 | return ERR_PTR(-ENOMEM); | ||
| 251 | |||
| 252 | /* copy div_map to allow __initconst */ | ||
| 253 | memcpy(&div->map, map, sizeof(*map)); | ||
| 254 | div->base = base; | ||
| 255 | div->lock = lock; | ||
| 256 | |||
| 257 | if ((div_flags & BERLIN2_DIV_HAS_GATE) == 0) | ||
| 258 | gate_ops = NULL; | ||
| 259 | if ((div_flags & BERLIN2_DIV_HAS_MUX) == 0) | ||
| 260 | mux_ops = NULL; | ||
| 261 | |||
| 262 | return clk_register_composite(NULL, name, parent_names, num_parents, | ||
| 263 | &div->hw, mux_ops, &div->hw, rate_ops, | ||
| 264 | &div->hw, gate_ops, flags); | ||
| 265 | } | ||
diff --git a/drivers/clk/berlin/berlin2-div.h b/drivers/clk/berlin/berlin2-div.h new file mode 100644 index 000000000000..15e3384f3116 --- /dev/null +++ b/drivers/clk/berlin/berlin2-div.h | |||
| @@ -0,0 +1,89 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014 Marvell Technology Group Ltd. | ||
| 3 | * | ||
| 4 | * Alexandre Belloni <alexandre.belloni@free-electrons.com> | ||
| 5 | * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms and conditions of the GNU General Public License, | ||
| 9 | * version 2, as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 14 | * more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License along with | ||
| 17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #ifndef __BERLIN2_DIV_H | ||
| 20 | #define __BERLIN2_DIV_H | ||
| 21 | |||
| 22 | struct clk; | ||
| 23 | |||
| 24 | #define BERLIN2_DIV_HAS_GATE BIT(0) | ||
| 25 | #define BERLIN2_DIV_HAS_MUX BIT(1) | ||
| 26 | |||
| 27 | #define BERLIN2_PLL_SELECT(_off, _sh) \ | ||
| 28 | .pll_select_offs = _off, \ | ||
| 29 | .pll_select_shift = _sh | ||
| 30 | |||
| 31 | #define BERLIN2_PLL_SWITCH(_off, _sh) \ | ||
| 32 | .pll_switch_offs = _off, \ | ||
| 33 | .pll_switch_shift = _sh | ||
| 34 | |||
| 35 | #define BERLIN2_DIV_SELECT(_off, _sh) \ | ||
| 36 | .div_select_offs = _off, \ | ||
| 37 | .div_select_shift = _sh | ||
| 38 | |||
| 39 | #define BERLIN2_DIV_SWITCH(_off, _sh) \ | ||
| 40 | .div_switch_offs = _off, \ | ||
| 41 | .div_switch_shift = _sh | ||
| 42 | |||
| 43 | #define BERLIN2_DIV_D3SWITCH(_off, _sh) \ | ||
| 44 | .div3_switch_offs = _off, \ | ||
| 45 | .div3_switch_shift = _sh | ||
| 46 | |||
| 47 | #define BERLIN2_DIV_GATE(_off, _sh) \ | ||
| 48 | .gate_offs = _off, \ | ||
| 49 | .gate_shift = _sh | ||
| 50 | |||
| 51 | #define BERLIN2_SINGLE_DIV(_off) \ | ||
| 52 | BERLIN2_DIV_GATE(_off, 0), \ | ||
| 53 | BERLIN2_PLL_SELECT(_off, 1), \ | ||
| 54 | BERLIN2_PLL_SWITCH(_off, 4), \ | ||
| 55 | BERLIN2_DIV_SWITCH(_off, 5), \ | ||
| 56 | BERLIN2_DIV_D3SWITCH(_off, 6), \ | ||
| 57 | BERLIN2_DIV_SELECT(_off, 7) | ||
| 58 | |||
| 59 | struct berlin2_div_map { | ||
| 60 | u16 pll_select_offs; | ||
| 61 | u16 pll_switch_offs; | ||
| 62 | u16 div_select_offs; | ||
| 63 | u16 div_switch_offs; | ||
| 64 | u16 div3_switch_offs; | ||
| 65 | u16 gate_offs; | ||
| 66 | u8 pll_select_shift; | ||
| 67 | u8 pll_switch_shift; | ||
| 68 | u8 div_select_shift; | ||
| 69 | u8 div_switch_shift; | ||
| 70 | u8 div3_switch_shift; | ||
| 71 | u8 gate_shift; | ||
| 72 | }; | ||
| 73 | |||
| 74 | struct berlin2_div_data { | ||
| 75 | const char *name; | ||
| 76 | const u8 *parent_ids; | ||
| 77 | int num_parents; | ||
| 78 | unsigned long flags; | ||
| 79 | struct berlin2_div_map map; | ||
| 80 | u8 div_flags; | ||
| 81 | }; | ||
| 82 | |||
| 83 | struct clk * __init | ||
| 84 | berlin2_div_register(const struct berlin2_div_map *map, | ||
| 85 | void __iomem *base, const char *name, u8 div_flags, | ||
| 86 | const char **parent_names, int num_parents, | ||
| 87 | unsigned long flags, spinlock_t *lock); | ||
| 88 | |||
| 89 | #endif /* __BERLIN2_DIV_H */ | ||
diff --git a/drivers/clk/berlin/berlin2-pll.c b/drivers/clk/berlin/berlin2-pll.c new file mode 100644 index 000000000000..bdc506b03824 --- /dev/null +++ b/drivers/clk/berlin/berlin2-pll.c | |||
| @@ -0,0 +1,117 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014 Marvell Technology Group Ltd. | ||
| 3 | * | ||
| 4 | * Alexandre Belloni <alexandre.belloni@free-electrons.com> | ||
| 5 | * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms and conditions of the GNU General Public License, | ||
| 9 | * version 2, as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 14 | * more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License along with | ||
| 17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #include <linux/clk-provider.h> | ||
| 20 | #include <linux/io.h> | ||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/of.h> | ||
| 23 | #include <linux/of_address.h> | ||
| 24 | #include <linux/slab.h> | ||
| 25 | #include <asm/div64.h> | ||
| 26 | |||
| 27 | #include "berlin2-div.h" | ||
| 28 | |||
| 29 | struct berlin2_pll_map { | ||
| 30 | const u8 vcodiv[16]; | ||
| 31 | u8 mult; | ||
| 32 | u8 fbdiv_shift; | ||
| 33 | u8 rfdiv_shift; | ||
| 34 | u8 divsel_shift; | ||
| 35 | }; | ||
| 36 | |||
| 37 | struct berlin2_pll { | ||
| 38 | struct clk_hw hw; | ||
| 39 | void __iomem *base; | ||
| 40 | struct berlin2_pll_map map; | ||
| 41 | }; | ||
| 42 | |||
| 43 | #define to_berlin2_pll(hw) container_of(hw, struct berlin2_pll, hw) | ||
| 44 | |||
| 45 | #define SPLL_CTRL0 0x00 | ||
| 46 | #define SPLL_CTRL1 0x04 | ||
| 47 | #define SPLL_CTRL2 0x08 | ||
| 48 | #define SPLL_CTRL3 0x0c | ||
| 49 | #define SPLL_CTRL4 0x10 | ||
| 50 | |||
| 51 | #define FBDIV_MASK 0x1ff | ||
| 52 | #define RFDIV_MASK 0x1f | ||
| 53 | #define DIVSEL_MASK 0xf | ||
| 54 | |||
| 55 | /* | ||
| 56 | * The output frequency formula for the pll is: | ||
| 57 | * clkout = fbdiv / refdiv * parent / vcodiv | ||
| 58 | */ | ||
| 59 | static unsigned long | ||
| 60 | berlin2_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | ||
| 61 | { | ||
| 62 | struct berlin2_pll *pll = to_berlin2_pll(hw); | ||
| 63 | struct berlin2_pll_map *map = &pll->map; | ||
| 64 | u32 val, fbdiv, rfdiv, vcodivsel, vcodiv; | ||
| 65 | u64 rate = parent_rate; | ||
| 66 | |||
| 67 | val = readl_relaxed(pll->base + SPLL_CTRL0); | ||
| 68 | fbdiv = (val >> map->fbdiv_shift) & FBDIV_MASK; | ||
| 69 | rfdiv = (val >> map->rfdiv_shift) & RFDIV_MASK; | ||
| 70 | if (rfdiv == 0) { | ||
| 71 | pr_warn("%s has zero rfdiv\n", __clk_get_name(hw->clk)); | ||
| 72 | rfdiv = 1; | ||
| 73 | } | ||
| 74 | |||
| 75 | val = readl_relaxed(pll->base + SPLL_CTRL1); | ||
| 76 | vcodivsel = (val >> map->divsel_shift) & DIVSEL_MASK; | ||
| 77 | vcodiv = map->vcodiv[vcodivsel]; | ||
| 78 | if (vcodiv == 0) { | ||
| 79 | pr_warn("%s has zero vcodiv (index %d)\n", | ||
| 80 | __clk_get_name(hw->clk), vcodivsel); | ||
| 81 | vcodiv = 1; | ||
| 82 | } | ||
| 83 | |||
| 84 | rate *= fbdiv * map->mult; | ||
| 85 | do_div(rate, rfdiv * vcodiv); | ||
| 86 | |||
| 87 | return (unsigned long)rate; | ||
| 88 | } | ||
| 89 | |||
| 90 | static const struct clk_ops berlin2_pll_ops = { | ||
| 91 | .recalc_rate = berlin2_pll_recalc_rate, | ||
| 92 | }; | ||
| 93 | |||
| 94 | struct clk * __init | ||
| 95 | berlin2_pll_register(const struct berlin2_pll_map *map, | ||
| 96 | void __iomem *base, const char *name, | ||
| 97 | const char *parent_name, unsigned long flags) | ||
| 98 | { | ||
| 99 | struct clk_init_data init; | ||
| 100 | struct berlin2_pll *pll; | ||
| 101 | |||
| 102 | pll = kzalloc(sizeof(*pll), GFP_KERNEL); | ||
| 103 | if (!pll) | ||
| 104 | return ERR_PTR(-ENOMEM); | ||
| 105 | |||
| 106 | /* copy pll_map to allow __initconst */ | ||
| 107 | memcpy(&pll->map, map, sizeof(*map)); | ||
| 108 | pll->base = base; | ||
| 109 | pll->hw.init = &init; | ||
| 110 | init.name = name; | ||
| 111 | init.ops = &berlin2_pll_ops; | ||
| 112 | init.parent_names = &parent_name; | ||
| 113 | init.num_parents = 1; | ||
| 114 | init.flags = flags; | ||
| 115 | |||
| 116 | return clk_register(NULL, &pll->hw); | ||
| 117 | } | ||
diff --git a/drivers/clk/berlin/berlin2-pll.h b/drivers/clk/berlin/berlin2-pll.h new file mode 100644 index 000000000000..8831ce27ac1e --- /dev/null +++ b/drivers/clk/berlin/berlin2-pll.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014 Marvell Technology Group Ltd. | ||
| 3 | * | ||
| 4 | * Alexandre Belloni <alexandre.belloni@free-electrons.com> | ||
| 5 | * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms and conditions of the GNU General Public License, | ||
| 9 | * version 2, as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 14 | * more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License along with | ||
| 17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #ifndef __BERLIN2_PLL_H | ||
| 20 | #define __BERLIN2_PLL_H | ||
| 21 | |||
| 22 | struct clk; | ||
| 23 | |||
| 24 | struct berlin2_pll_map { | ||
| 25 | const u8 vcodiv[16]; | ||
| 26 | u8 mult; | ||
| 27 | u8 fbdiv_shift; | ||
| 28 | u8 rfdiv_shift; | ||
| 29 | u8 divsel_shift; | ||
| 30 | }; | ||
| 31 | |||
| 32 | struct clk * __init | ||
| 33 | berlin2_pll_register(const struct berlin2_pll_map *map, | ||
| 34 | void __iomem *base, const char *name, | ||
| 35 | const char *parent_name, unsigned long flags); | ||
| 36 | |||
| 37 | #endif /* __BERLIN2_PLL_H */ | ||
diff --git a/drivers/clk/berlin/bg2.c b/drivers/clk/berlin/bg2.c new file mode 100644 index 000000000000..515fb133495c --- /dev/null +++ b/drivers/clk/berlin/bg2.c | |||
| @@ -0,0 +1,691 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014 Marvell Technology Group Ltd. | ||
| 3 | * | ||
| 4 | * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | ||
| 5 | * Alexandre Belloni <alexandre.belloni@free-electrons.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms and conditions of the GNU General Public License, | ||
| 9 | * version 2, as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 14 | * more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License along with | ||
| 17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/clk.h> | ||
| 21 | #include <linux/clk-provider.h> | ||
| 22 | #include <linux/kernel.h> | ||
| 23 | #include <linux/of.h> | ||
| 24 | #include <linux/of_address.h> | ||
| 25 | #include <linux/slab.h> | ||
| 26 | |||
| 27 | #include <dt-bindings/clock/berlin2.h> | ||
| 28 | |||
| 29 | #include "berlin2-avpll.h" | ||
| 30 | #include "berlin2-div.h" | ||
| 31 | #include "berlin2-pll.h" | ||
| 32 | #include "common.h" | ||
| 33 | |||
| 34 | #define REG_PINMUX0 0x0000 | ||
| 35 | #define REG_PINMUX1 0x0004 | ||
| 36 | #define REG_SYSPLLCTL0 0x0014 | ||
| 37 | #define REG_SYSPLLCTL4 0x0024 | ||
| 38 | #define REG_MEMPLLCTL0 0x0028 | ||
| 39 | #define REG_MEMPLLCTL4 0x0038 | ||
| 40 | #define REG_CPUPLLCTL0 0x003c | ||
| 41 | #define REG_CPUPLLCTL4 0x004c | ||
| 42 | #define REG_AVPLLCTL0 0x0050 | ||
| 43 | #define REG_AVPLLCTL31 0x00cc | ||
| 44 | #define REG_AVPLLCTL62 0x0148 | ||
| 45 | #define REG_PLLSTATUS 0x014c | ||
| 46 | #define REG_CLKENABLE 0x0150 | ||
| 47 | #define REG_CLKSELECT0 0x0154 | ||
| 48 | #define REG_CLKSELECT1 0x0158 | ||
| 49 | #define REG_CLKSELECT2 0x015c | ||
| 50 | #define REG_CLKSELECT3 0x0160 | ||
| 51 | #define REG_CLKSWITCH0 0x0164 | ||
| 52 | #define REG_CLKSWITCH1 0x0168 | ||
| 53 | #define REG_RESET_TRIGGER 0x0178 | ||
| 54 | #define REG_RESET_STATUS0 0x017c | ||
| 55 | #define REG_RESET_STATUS1 0x0180 | ||
| 56 | #define REG_SW_GENERIC0 0x0184 | ||
| 57 | #define REG_SW_GENERIC3 0x0190 | ||
| 58 | #define REG_PRODUCTID 0x01cc | ||
| 59 | #define REG_PRODUCTID_EXT 0x01d0 | ||
| 60 | #define REG_GFX3DCORE_CLKCTL 0x022c | ||
| 61 | #define REG_GFX3DSYS_CLKCTL 0x0230 | ||
| 62 | #define REG_ARC_CLKCTL 0x0234 | ||
| 63 | #define REG_VIP_CLKCTL 0x0238 | ||
| 64 | #define REG_SDIO0XIN_CLKCTL 0x023c | ||
| 65 | #define REG_SDIO1XIN_CLKCTL 0x0240 | ||
| 66 | #define REG_GFX3DEXTRA_CLKCTL 0x0244 | ||
| 67 | #define REG_GFX3D_RESET 0x0248 | ||
| 68 | #define REG_GC360_CLKCTL 0x024c | ||
| 69 | #define REG_SDIO_DLLMST_CLKCTL 0x0250 | ||
| 70 | |||
| 71 | /* | ||
| 72 | * BG2/BG2CD SoCs have the following audio/video I/O units: | ||
| 73 | * | ||
| 74 | * audiohd: HDMI TX audio | ||
| 75 | * audio0: 7.1ch TX | ||
| 76 | * audio1: 2ch TX | ||
| 77 | * audio2: 2ch RX | ||
| 78 | * audio3: SPDIF TX | ||
| 79 | * video0: HDMI video | ||
| 80 | * video1: Secondary video | ||
| 81 | * video2: SD auxiliary video | ||
| 82 | * | ||
| 83 | * There are no external audio clocks (ACLKI0, ACLKI1) and | ||
| 84 | * only one external video clock (VCLKI0). | ||
| 85 | * | ||
| 86 | * Currently missing bits and pieces: | ||
| 87 | * - audio_fast_pll is unknown | ||
| 88 | * - audiohd_pll is unknown | ||
| 89 | * - video0_pll is unknown | ||
| 90 | * - audio[023], audiohd parent pll is assumed to be audio_fast_pll | ||
| 91 | * | ||
| 92 | */ | ||
| 93 | |||
| 94 | #define MAX_CLKS 41 | ||
| 95 | static struct clk *clks[MAX_CLKS]; | ||
| 96 | static struct clk_onecell_data clk_data; | ||
| 97 | static DEFINE_SPINLOCK(lock); | ||
| 98 | static void __iomem *gbase; | ||
| 99 | |||
| 100 | enum { | ||
| 101 | REFCLK, VIDEO_EXT0, | ||
| 102 | SYSPLL, MEMPLL, CPUPLL, | ||
| 103 | AVPLL_A1, AVPLL_A2, AVPLL_A3, AVPLL_A4, | ||
| 104 | AVPLL_A5, AVPLL_A6, AVPLL_A7, AVPLL_A8, | ||
| 105 | AVPLL_B1, AVPLL_B2, AVPLL_B3, AVPLL_B4, | ||
| 106 | AVPLL_B5, AVPLL_B6, AVPLL_B7, AVPLL_B8, | ||
| 107 | AUDIO1_PLL, AUDIO_FAST_PLL, | ||
| 108 | VIDEO0_PLL, VIDEO0_IN, | ||
| 109 | VIDEO1_PLL, VIDEO1_IN, | ||
| 110 | VIDEO2_PLL, VIDEO2_IN, | ||
| 111 | }; | ||
| 112 | |||
| 113 | static const char *clk_names[] = { | ||
| 114 | [REFCLK] = "refclk", | ||
| 115 | [VIDEO_EXT0] = "video_ext0", | ||
| 116 | [SYSPLL] = "syspll", | ||
| 117 | [MEMPLL] = "mempll", | ||
| 118 | [CPUPLL] = "cpupll", | ||
| 119 | [AVPLL_A1] = "avpll_a1", | ||
| 120 | [AVPLL_A2] = "avpll_a2", | ||
| 121 | [AVPLL_A3] = "avpll_a3", | ||
| 122 | [AVPLL_A4] = "avpll_a4", | ||
| 123 | [AVPLL_A5] = "avpll_a5", | ||
| 124 | [AVPLL_A6] = "avpll_a6", | ||
| 125 | [AVPLL_A7] = "avpll_a7", | ||
| 126 | [AVPLL_A8] = "avpll_a8", | ||
| 127 | [AVPLL_B1] = "avpll_b1", | ||
| 128 | [AVPLL_B2] = "avpll_b2", | ||
| 129 | [AVPLL_B3] = "avpll_b3", | ||
| 130 | [AVPLL_B4] = "avpll_b4", | ||
| 131 | [AVPLL_B5] = "avpll_b5", | ||
| 132 | [AVPLL_B6] = "avpll_b6", | ||
| 133 | [AVPLL_B7] = "avpll_b7", | ||
| 134 | [AVPLL_B8] = "avpll_b8", | ||
| 135 | [AUDIO1_PLL] = "audio1_pll", | ||
| 136 | [AUDIO_FAST_PLL] = "audio_fast_pll", | ||
| 137 | [VIDEO0_PLL] = "video0_pll", | ||
| 138 | [VIDEO0_IN] = "video0_in", | ||
| 139 | [VIDEO1_PLL] = "video1_pll", | ||
| 140 | [VIDEO1_IN] = "video1_in", | ||
| 141 | [VIDEO2_PLL] = "video2_pll", | ||
| 142 | [VIDEO2_IN] = "video2_in", | ||
| 143 | }; | ||
| 144 | |||
| 145 | static const struct berlin2_pll_map bg2_pll_map __initconst = { | ||
| 146 | .vcodiv = {10, 15, 20, 25, 30, 40, 50, 60, 80}, | ||
| 147 | .mult = 10, | ||
| 148 | .fbdiv_shift = 6, | ||
| 149 | .rfdiv_shift = 1, | ||
| 150 | .divsel_shift = 7, | ||
| 151 | }; | ||
| 152 | |||
| 153 | static const u8 default_parent_ids[] = { | ||
| 154 | SYSPLL, AVPLL_B4, AVPLL_A5, AVPLL_B6, AVPLL_B7, SYSPLL | ||
| 155 | }; | ||
| 156 | |||
| 157 | static const struct berlin2_div_data bg2_divs[] __initconst = { | ||
| 158 | { | ||
| 159 | .name = "sys", | ||
| 160 | .parent_ids = (const u8 []){ | ||
| 161 | SYSPLL, AVPLL_B4, AVPLL_B5, AVPLL_B6, AVPLL_B7, SYSPLL | ||
| 162 | }, | ||
| 163 | .num_parents = 6, | ||
| 164 | .map = { | ||
| 165 | BERLIN2_DIV_GATE(REG_CLKENABLE, 0), | ||
| 166 | BERLIN2_PLL_SELECT(REG_CLKSELECT0, 0), | ||
| 167 | BERLIN2_DIV_SELECT(REG_CLKSELECT0, 3), | ||
| 168 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 3), | ||
| 169 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 4), | ||
| 170 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 5), | ||
| 171 | }, | ||
| 172 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 173 | .flags = CLK_IGNORE_UNUSED, | ||
| 174 | }, | ||
| 175 | { | ||
| 176 | .name = "cpu", | ||
| 177 | .parent_ids = (const u8 []){ | ||
| 178 | CPUPLL, MEMPLL, MEMPLL, MEMPLL, MEMPLL | ||
| 179 | }, | ||
| 180 | .num_parents = 5, | ||
| 181 | .map = { | ||
| 182 | BERLIN2_PLL_SELECT(REG_CLKSELECT0, 6), | ||
| 183 | BERLIN2_DIV_SELECT(REG_CLKSELECT0, 9), | ||
| 184 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 6), | ||
| 185 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 7), | ||
| 186 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 8), | ||
| 187 | }, | ||
| 188 | .div_flags = BERLIN2_DIV_HAS_MUX, | ||
| 189 | .flags = 0, | ||
| 190 | }, | ||
| 191 | { | ||
| 192 | .name = "drmfigo", | ||
| 193 | .parent_ids = default_parent_ids, | ||
| 194 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 195 | .map = { | ||
| 196 | BERLIN2_DIV_GATE(REG_CLKENABLE, 16), | ||
| 197 | BERLIN2_PLL_SELECT(REG_CLKSELECT0, 17), | ||
| 198 | BERLIN2_DIV_SELECT(REG_CLKSELECT0, 20), | ||
| 199 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 12), | ||
| 200 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 13), | ||
| 201 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 14), | ||
| 202 | }, | ||
| 203 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 204 | .flags = 0, | ||
| 205 | }, | ||
| 206 | { | ||
| 207 | .name = "cfg", | ||
| 208 | .parent_ids = default_parent_ids, | ||
| 209 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 210 | .map = { | ||
| 211 | BERLIN2_DIV_GATE(REG_CLKENABLE, 1), | ||
| 212 | BERLIN2_PLL_SELECT(REG_CLKSELECT0, 23), | ||
| 213 | BERLIN2_DIV_SELECT(REG_CLKSELECT0, 26), | ||
| 214 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 15), | ||
| 215 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 16), | ||
| 216 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 17), | ||
| 217 | }, | ||
| 218 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 219 | .flags = 0, | ||
| 220 | }, | ||
| 221 | { | ||
| 222 | .name = "gfx", | ||
| 223 | .parent_ids = default_parent_ids, | ||
| 224 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 225 | .map = { | ||
| 226 | BERLIN2_DIV_GATE(REG_CLKENABLE, 4), | ||
| 227 | BERLIN2_PLL_SELECT(REG_CLKSELECT0, 29), | ||
| 228 | BERLIN2_DIV_SELECT(REG_CLKSELECT1, 0), | ||
| 229 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 18), | ||
| 230 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 19), | ||
| 231 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 20), | ||
| 232 | }, | ||
| 233 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 234 | .flags = 0, | ||
| 235 | }, | ||
| 236 | { | ||
| 237 | .name = "zsp", | ||
| 238 | .parent_ids = default_parent_ids, | ||
| 239 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 240 | .map = { | ||
| 241 | BERLIN2_DIV_GATE(REG_CLKENABLE, 5), | ||
| 242 | BERLIN2_PLL_SELECT(REG_CLKSELECT1, 3), | ||
| 243 | BERLIN2_DIV_SELECT(REG_CLKSELECT1, 6), | ||
| 244 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 21), | ||
| 245 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 22), | ||
| 246 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 23), | ||
| 247 | }, | ||
| 248 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 249 | .flags = 0, | ||
| 250 | }, | ||
| 251 | { | ||
| 252 | .name = "perif", | ||
| 253 | .parent_ids = default_parent_ids, | ||
| 254 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 255 | .map = { | ||
| 256 | BERLIN2_DIV_GATE(REG_CLKENABLE, 6), | ||
| 257 | BERLIN2_PLL_SELECT(REG_CLKSELECT1, 9), | ||
| 258 | BERLIN2_DIV_SELECT(REG_CLKSELECT1, 12), | ||
| 259 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 24), | ||
| 260 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 25), | ||
| 261 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 26), | ||
| 262 | }, | ||
| 263 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 264 | .flags = CLK_IGNORE_UNUSED, | ||
| 265 | }, | ||
| 266 | { | ||
| 267 | .name = "pcube", | ||
| 268 | .parent_ids = default_parent_ids, | ||
| 269 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 270 | .map = { | ||
| 271 | BERLIN2_DIV_GATE(REG_CLKENABLE, 2), | ||
| 272 | BERLIN2_PLL_SELECT(REG_CLKSELECT1, 15), | ||
| 273 | BERLIN2_DIV_SELECT(REG_CLKSELECT1, 18), | ||
| 274 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 27), | ||
| 275 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 28), | ||
| 276 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 29), | ||
| 277 | }, | ||
| 278 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 279 | .flags = 0, | ||
| 280 | }, | ||
| 281 | { | ||
| 282 | .name = "vscope", | ||
| 283 | .parent_ids = default_parent_ids, | ||
| 284 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 285 | .map = { | ||
| 286 | BERLIN2_DIV_GATE(REG_CLKENABLE, 3), | ||
| 287 | BERLIN2_PLL_SELECT(REG_CLKSELECT1, 21), | ||
| 288 | BERLIN2_DIV_SELECT(REG_CLKSELECT1, 24), | ||
| 289 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 30), | ||
| 290 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 31), | ||
| 291 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 0), | ||
| 292 | }, | ||
| 293 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 294 | .flags = 0, | ||
| 295 | }, | ||
| 296 | { | ||
| 297 | .name = "nfc_ecc", | ||
| 298 | .parent_ids = default_parent_ids, | ||
| 299 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 300 | .map = { | ||
| 301 | BERLIN2_DIV_GATE(REG_CLKENABLE, 18), | ||
| 302 | BERLIN2_PLL_SELECT(REG_CLKSELECT1, 27), | ||
| 303 | BERLIN2_DIV_SELECT(REG_CLKSELECT2, 0), | ||
| 304 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 1), | ||
| 305 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 2), | ||
| 306 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 3), | ||
| 307 | }, | ||
| 308 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 309 | .flags = 0, | ||
| 310 | }, | ||
| 311 | { | ||
| 312 | .name = "vpp", | ||
| 313 | .parent_ids = default_parent_ids, | ||
| 314 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 315 | .map = { | ||
| 316 | BERLIN2_DIV_GATE(REG_CLKENABLE, 21), | ||
| 317 | BERLIN2_PLL_SELECT(REG_CLKSELECT2, 3), | ||
| 318 | BERLIN2_DIV_SELECT(REG_CLKSELECT2, 6), | ||
| 319 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 4), | ||
| 320 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 5), | ||
| 321 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 6), | ||
| 322 | }, | ||
| 323 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 324 | .flags = 0, | ||
| 325 | }, | ||
| 326 | { | ||
| 327 | .name = "app", | ||
| 328 | .parent_ids = default_parent_ids, | ||
| 329 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 330 | .map = { | ||
| 331 | BERLIN2_DIV_GATE(REG_CLKENABLE, 20), | ||
| 332 | BERLIN2_PLL_SELECT(REG_CLKSELECT2, 9), | ||
| 333 | BERLIN2_DIV_SELECT(REG_CLKSELECT2, 12), | ||
| 334 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 7), | ||
| 335 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 8), | ||
| 336 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 9), | ||
| 337 | }, | ||
| 338 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 339 | .flags = 0, | ||
| 340 | }, | ||
| 341 | { | ||
| 342 | .name = "audio0", | ||
| 343 | .parent_ids = (const u8 []){ AUDIO_FAST_PLL }, | ||
| 344 | .num_parents = 1, | ||
| 345 | .map = { | ||
| 346 | BERLIN2_DIV_GATE(REG_CLKENABLE, 22), | ||
| 347 | BERLIN2_DIV_SELECT(REG_CLKSELECT2, 17), | ||
| 348 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 10), | ||
| 349 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 11), | ||
| 350 | }, | ||
| 351 | .div_flags = BERLIN2_DIV_HAS_GATE, | ||
| 352 | .flags = 0, | ||
| 353 | }, | ||
| 354 | { | ||
| 355 | .name = "audio2", | ||
| 356 | .parent_ids = (const u8 []){ AUDIO_FAST_PLL }, | ||
| 357 | .num_parents = 1, | ||
| 358 | .map = { | ||
| 359 | BERLIN2_DIV_GATE(REG_CLKENABLE, 24), | ||
| 360 | BERLIN2_DIV_SELECT(REG_CLKSELECT2, 20), | ||
| 361 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 14), | ||
| 362 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 15), | ||
| 363 | }, | ||
| 364 | .div_flags = BERLIN2_DIV_HAS_GATE, | ||
| 365 | .flags = 0, | ||
| 366 | }, | ||
| 367 | { | ||
| 368 | .name = "audio3", | ||
| 369 | .parent_ids = (const u8 []){ AUDIO_FAST_PLL }, | ||
| 370 | .num_parents = 1, | ||
| 371 | .map = { | ||
| 372 | BERLIN2_DIV_GATE(REG_CLKENABLE, 25), | ||
| 373 | BERLIN2_DIV_SELECT(REG_CLKSELECT2, 23), | ||
| 374 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 16), | ||
| 375 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 17), | ||
| 376 | }, | ||
| 377 | .div_flags = BERLIN2_DIV_HAS_GATE, | ||
| 378 | .flags = 0, | ||
| 379 | }, | ||
| 380 | { | ||
| 381 | .name = "audio1", | ||
| 382 | .parent_ids = (const u8 []){ AUDIO1_PLL }, | ||
| 383 | .num_parents = 1, | ||
| 384 | .map = { | ||
| 385 | BERLIN2_DIV_GATE(REG_CLKENABLE, 23), | ||
| 386 | BERLIN2_DIV_SELECT(REG_CLKSELECT3, 0), | ||
| 387 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 12), | ||
| 388 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 13), | ||
| 389 | }, | ||
| 390 | .div_flags = BERLIN2_DIV_HAS_GATE, | ||
| 391 | .flags = 0, | ||
| 392 | }, | ||
| 393 | { | ||
| 394 | .name = "gfx3d_core", | ||
| 395 | .parent_ids = default_parent_ids, | ||
| 396 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 397 | .map = { | ||
| 398 | BERLIN2_SINGLE_DIV(REG_GFX3DCORE_CLKCTL), | ||
| 399 | }, | ||
| 400 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 401 | .flags = 0, | ||
| 402 | }, | ||
| 403 | { | ||
| 404 | .name = "gfx3d_sys", | ||
| 405 | .parent_ids = default_parent_ids, | ||
| 406 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 407 | .map = { | ||
| 408 | BERLIN2_SINGLE_DIV(REG_GFX3DSYS_CLKCTL), | ||
| 409 | }, | ||
| 410 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 411 | .flags = 0, | ||
| 412 | }, | ||
| 413 | { | ||
| 414 | .name = "arc", | ||
| 415 | .parent_ids = default_parent_ids, | ||
| 416 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 417 | .map = { | ||
| 418 | BERLIN2_SINGLE_DIV(REG_ARC_CLKCTL), | ||
| 419 | }, | ||
| 420 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 421 | .flags = 0, | ||
| 422 | }, | ||
| 423 | { | ||
| 424 | .name = "vip", | ||
| 425 | .parent_ids = default_parent_ids, | ||
| 426 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 427 | .map = { | ||
| 428 | BERLIN2_SINGLE_DIV(REG_VIP_CLKCTL), | ||
| 429 | }, | ||
| 430 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 431 | .flags = 0, | ||
| 432 | }, | ||
| 433 | { | ||
| 434 | .name = "sdio0xin", | ||
| 435 | .parent_ids = default_parent_ids, | ||
| 436 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 437 | .map = { | ||
| 438 | BERLIN2_SINGLE_DIV(REG_SDIO0XIN_CLKCTL), | ||
| 439 | }, | ||
| 440 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 441 | .flags = 0, | ||
| 442 | }, | ||
| 443 | { | ||
| 444 | .name = "sdio1xin", | ||
| 445 | .parent_ids = default_parent_ids, | ||
| 446 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 447 | .map = { | ||
| 448 | BERLIN2_SINGLE_DIV(REG_SDIO1XIN_CLKCTL), | ||
| 449 | }, | ||
| 450 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 451 | .flags = 0, | ||
| 452 | }, | ||
| 453 | { | ||
| 454 | .name = "gfx3d_extra", | ||
| 455 | .parent_ids = default_parent_ids, | ||
| 456 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 457 | .map = { | ||
| 458 | BERLIN2_SINGLE_DIV(REG_GFX3DEXTRA_CLKCTL), | ||
| 459 | }, | ||
| 460 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 461 | .flags = 0, | ||
| 462 | }, | ||
| 463 | { | ||
| 464 | .name = "gc360", | ||
| 465 | .parent_ids = default_parent_ids, | ||
| 466 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 467 | .map = { | ||
| 468 | BERLIN2_SINGLE_DIV(REG_GC360_CLKCTL), | ||
| 469 | }, | ||
| 470 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 471 | .flags = 0, | ||
| 472 | }, | ||
| 473 | { | ||
| 474 | .name = "sdio_dllmst", | ||
| 475 | .parent_ids = default_parent_ids, | ||
| 476 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 477 | .map = { | ||
| 478 | BERLIN2_SINGLE_DIV(REG_SDIO_DLLMST_CLKCTL), | ||
| 479 | }, | ||
| 480 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 481 | .flags = 0, | ||
| 482 | }, | ||
| 483 | }; | ||
| 484 | |||
| 485 | static const struct berlin2_gate_data bg2_gates[] __initconst = { | ||
| 486 | { "geth0", "perif", 7 }, | ||
| 487 | { "geth1", "perif", 8 }, | ||
| 488 | { "sata", "perif", 9 }, | ||
| 489 | { "ahbapb", "perif", 10, CLK_IGNORE_UNUSED }, | ||
| 490 | { "usb0", "perif", 11 }, | ||
| 491 | { "usb1", "perif", 12 }, | ||
| 492 | { "pbridge", "perif", 13, CLK_IGNORE_UNUSED }, | ||
| 493 | { "sdio0", "perif", 14, CLK_IGNORE_UNUSED }, | ||
| 494 | { "sdio1", "perif", 15, CLK_IGNORE_UNUSED }, | ||
| 495 | { "nfc", "perif", 17 }, | ||
| 496 | { "smemc", "perif", 19 }, | ||
| 497 | { "audiohd", "audiohd_pll", 26 }, | ||
| 498 | { "video0", "video0_in", 27 }, | ||
| 499 | { "video1", "video1_in", 28 }, | ||
| 500 | { "video2", "video2_in", 29 }, | ||
| 501 | }; | ||
| 502 | |||
| 503 | static void __init berlin2_clock_setup(struct device_node *np) | ||
| 504 | { | ||
| 505 | const char *parent_names[9]; | ||
| 506 | struct clk *clk; | ||
| 507 | u8 avpll_flags = 0; | ||
| 508 | int n; | ||
| 509 | |||
| 510 | gbase = of_iomap(np, 0); | ||
| 511 | if (!gbase) | ||
| 512 | return; | ||
| 513 | |||
| 514 | /* overwrite default clock names with DT provided ones */ | ||
| 515 | clk = of_clk_get_by_name(np, clk_names[REFCLK]); | ||
| 516 | if (!IS_ERR(clk)) { | ||
| 517 | clk_names[REFCLK] = __clk_get_name(clk); | ||
| 518 | clk_put(clk); | ||
| 519 | } | ||
| 520 | |||
| 521 | clk = of_clk_get_by_name(np, clk_names[VIDEO_EXT0]); | ||
| 522 | if (!IS_ERR(clk)) { | ||
| 523 | clk_names[VIDEO_EXT0] = __clk_get_name(clk); | ||
| 524 | clk_put(clk); | ||
| 525 | } | ||
| 526 | |||
| 527 | /* simple register PLLs */ | ||
| 528 | clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_SYSPLLCTL0, | ||
| 529 | clk_names[SYSPLL], clk_names[REFCLK], 0); | ||
| 530 | if (IS_ERR(clk)) | ||
| 531 | goto bg2_fail; | ||
| 532 | |||
| 533 | clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_MEMPLLCTL0, | ||
| 534 | clk_names[MEMPLL], clk_names[REFCLK], 0); | ||
| 535 | if (IS_ERR(clk)) | ||
| 536 | goto bg2_fail; | ||
| 537 | |||
| 538 | clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_CPUPLLCTL0, | ||
| 539 | clk_names[CPUPLL], clk_names[REFCLK], 0); | ||
| 540 | if (IS_ERR(clk)) | ||
| 541 | goto bg2_fail; | ||
| 542 | |||
| 543 | if (of_device_is_compatible(np, "marvell,berlin2-global-register")) | ||
| 544 | avpll_flags |= BERLIN2_AVPLL_SCRAMBLE_QUIRK; | ||
| 545 | |||
| 546 | /* audio/video VCOs */ | ||
| 547 | clk = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL0, "avpll_vcoA", | ||
| 548 | clk_names[REFCLK], avpll_flags, 0); | ||
| 549 | if (IS_ERR(clk)) | ||
| 550 | goto bg2_fail; | ||
| 551 | |||
| 552 | for (n = 0; n < 8; n++) { | ||
| 553 | clk = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL0, | ||
| 554 | clk_names[AVPLL_A1 + n], n, "avpll_vcoA", | ||
| 555 | avpll_flags, 0); | ||
| 556 | if (IS_ERR(clk)) | ||
| 557 | goto bg2_fail; | ||
| 558 | } | ||
| 559 | |||
| 560 | clk = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL31, "avpll_vcoB", | ||
| 561 | clk_names[REFCLK], BERLIN2_AVPLL_BIT_QUIRK | | ||
| 562 | avpll_flags, 0); | ||
| 563 | if (IS_ERR(clk)) | ||
| 564 | goto bg2_fail; | ||
| 565 | |||
| 566 | for (n = 0; n < 8; n++) { | ||
| 567 | clk = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL31, | ||
| 568 | clk_names[AVPLL_B1 + n], n, "avpll_vcoB", | ||
| 569 | BERLIN2_AVPLL_BIT_QUIRK | avpll_flags, 0); | ||
| 570 | if (IS_ERR(clk)) | ||
| 571 | goto bg2_fail; | ||
| 572 | } | ||
| 573 | |||
| 574 | /* reference clock bypass switches */ | ||
| 575 | parent_names[0] = clk_names[SYSPLL]; | ||
| 576 | parent_names[1] = clk_names[REFCLK]; | ||
| 577 | clk = clk_register_mux(NULL, "syspll_byp", parent_names, 2, | ||
| 578 | 0, gbase + REG_CLKSWITCH0, 0, 1, 0, &lock); | ||
| 579 | if (IS_ERR(clk)) | ||
| 580 | goto bg2_fail; | ||
| 581 | clk_names[SYSPLL] = __clk_get_name(clk); | ||
| 582 | |||
| 583 | parent_names[0] = clk_names[MEMPLL]; | ||
| 584 | parent_names[1] = clk_names[REFCLK]; | ||
| 585 | clk = clk_register_mux(NULL, "mempll_byp", parent_names, 2, | ||
| 586 | 0, gbase + REG_CLKSWITCH0, 1, 1, 0, &lock); | ||
| 587 | if (IS_ERR(clk)) | ||
| 588 | goto bg2_fail; | ||
| 589 | clk_names[MEMPLL] = __clk_get_name(clk); | ||
| 590 | |||
| 591 | parent_names[0] = clk_names[CPUPLL]; | ||
| 592 | parent_names[1] = clk_names[REFCLK]; | ||
| 593 | clk = clk_register_mux(NULL, "cpupll_byp", parent_names, 2, | ||
| 594 | 0, gbase + REG_CLKSWITCH0, 2, 1, 0, &lock); | ||
| 595 | if (IS_ERR(clk)) | ||
| 596 | goto bg2_fail; | ||
| 597 | clk_names[CPUPLL] = __clk_get_name(clk); | ||
| 598 | |||
| 599 | /* clock muxes */ | ||
| 600 | parent_names[0] = clk_names[AVPLL_B3]; | ||
| 601 | parent_names[1] = clk_names[AVPLL_A3]; | ||
| 602 | clk = clk_register_mux(NULL, clk_names[AUDIO1_PLL], parent_names, 2, | ||
| 603 | 0, gbase + REG_CLKSELECT2, 29, 1, 0, &lock); | ||
| 604 | if (IS_ERR(clk)) | ||
| 605 | goto bg2_fail; | ||
| 606 | |||
| 607 | parent_names[0] = clk_names[VIDEO0_PLL]; | ||
| 608 | parent_names[1] = clk_names[VIDEO_EXT0]; | ||
| 609 | clk = clk_register_mux(NULL, clk_names[VIDEO0_IN], parent_names, 2, | ||
| 610 | 0, gbase + REG_CLKSELECT3, 4, 1, 0, &lock); | ||
| 611 | if (IS_ERR(clk)) | ||
| 612 | goto bg2_fail; | ||
| 613 | |||
| 614 | parent_names[0] = clk_names[VIDEO1_PLL]; | ||
| 615 | parent_names[1] = clk_names[VIDEO_EXT0]; | ||
| 616 | clk = clk_register_mux(NULL, clk_names[VIDEO1_IN], parent_names, 2, | ||
| 617 | 0, gbase + REG_CLKSELECT3, 6, 1, 0, &lock); | ||
| 618 | if (IS_ERR(clk)) | ||
| 619 | goto bg2_fail; | ||
| 620 | |||
| 621 | parent_names[0] = clk_names[AVPLL_A2]; | ||
| 622 | parent_names[1] = clk_names[AVPLL_B2]; | ||
| 623 | clk = clk_register_mux(NULL, clk_names[VIDEO1_PLL], parent_names, 2, | ||
| 624 | 0, gbase + REG_CLKSELECT3, 7, 1, 0, &lock); | ||
| 625 | if (IS_ERR(clk)) | ||
| 626 | goto bg2_fail; | ||
| 627 | |||
| 628 | parent_names[0] = clk_names[VIDEO2_PLL]; | ||
| 629 | parent_names[1] = clk_names[VIDEO_EXT0]; | ||
| 630 | clk = clk_register_mux(NULL, clk_names[VIDEO2_IN], parent_names, 2, | ||
| 631 | 0, gbase + REG_CLKSELECT3, 9, 1, 0, &lock); | ||
| 632 | if (IS_ERR(clk)) | ||
| 633 | goto bg2_fail; | ||
| 634 | |||
| 635 | parent_names[0] = clk_names[AVPLL_B1]; | ||
| 636 | parent_names[1] = clk_names[AVPLL_A5]; | ||
| 637 | clk = clk_register_mux(NULL, clk_names[VIDEO2_PLL], parent_names, 2, | ||
| 638 | 0, gbase + REG_CLKSELECT3, 10, 1, 0, &lock); | ||
| 639 | if (IS_ERR(clk)) | ||
| 640 | goto bg2_fail; | ||
| 641 | |||
| 642 | /* clock divider cells */ | ||
| 643 | for (n = 0; n < ARRAY_SIZE(bg2_divs); n++) { | ||
| 644 | const struct berlin2_div_data *dd = &bg2_divs[n]; | ||
| 645 | int k; | ||
| 646 | |||
| 647 | for (k = 0; k < dd->num_parents; k++) | ||
| 648 | parent_names[k] = clk_names[dd->parent_ids[k]]; | ||
| 649 | |||
| 650 | clks[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase, | ||
| 651 | dd->name, dd->div_flags, parent_names, | ||
| 652 | dd->num_parents, dd->flags, &lock); | ||
| 653 | } | ||
| 654 | |||
| 655 | /* clock gate cells */ | ||
| 656 | for (n = 0; n < ARRAY_SIZE(bg2_gates); n++) { | ||
| 657 | const struct berlin2_gate_data *gd = &bg2_gates[n]; | ||
| 658 | |||
| 659 | clks[CLKID_GETH0 + n] = clk_register_gate(NULL, gd->name, | ||
| 660 | gd->parent_name, gd->flags, gbase + REG_CLKENABLE, | ||
| 661 | gd->bit_idx, 0, &lock); | ||
| 662 | } | ||
| 663 | |||
| 664 | /* twdclk is derived from cpu/3 */ | ||
| 665 | clks[CLKID_TWD] = | ||
| 666 | clk_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3); | ||
| 667 | |||
| 668 | /* check for errors on leaf clocks */ | ||
| 669 | for (n = 0; n < MAX_CLKS; n++) { | ||
| 670 | if (!IS_ERR(clks[n])) | ||
| 671 | continue; | ||
| 672 | |||
| 673 | pr_err("%s: Unable to register leaf clock %d\n", | ||
| 674 | np->full_name, n); | ||
| 675 | goto bg2_fail; | ||
| 676 | } | ||
| 677 | |||
| 678 | /* register clk-provider */ | ||
| 679 | clk_data.clks = clks; | ||
| 680 | clk_data.clk_num = MAX_CLKS; | ||
| 681 | of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); | ||
| 682 | |||
| 683 | return; | ||
| 684 | |||
| 685 | bg2_fail: | ||
| 686 | iounmap(gbase); | ||
| 687 | } | ||
| 688 | CLK_OF_DECLARE(berlin2_clock, "marvell,berlin2-chip-ctrl", | ||
| 689 | berlin2_clock_setup); | ||
| 690 | CLK_OF_DECLARE(berlin2cd_clock, "marvell,berlin2cd-chip-ctrl", | ||
| 691 | berlin2_clock_setup); | ||
diff --git a/drivers/clk/berlin/bg2q.c b/drivers/clk/berlin/bg2q.c new file mode 100644 index 000000000000..21784e4eb3f0 --- /dev/null +++ b/drivers/clk/berlin/bg2q.c | |||
| @@ -0,0 +1,389 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014 Marvell Technology Group Ltd. | ||
| 3 | * | ||
| 4 | * Alexandre Belloni <alexandre.belloni@free-electrons.com> | ||
| 5 | * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms and conditions of the GNU General Public License, | ||
| 9 | * version 2, as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 14 | * more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License along with | ||
| 17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/clk.h> | ||
| 21 | #include <linux/clk-provider.h> | ||
| 22 | #include <linux/kernel.h> | ||
| 23 | #include <linux/of.h> | ||
| 24 | #include <linux/of_address.h> | ||
| 25 | #include <linux/slab.h> | ||
| 26 | |||
| 27 | #include <dt-bindings/clock/berlin2q.h> | ||
| 28 | |||
| 29 | #include "berlin2-div.h" | ||
| 30 | #include "berlin2-pll.h" | ||
| 31 | #include "common.h" | ||
| 32 | |||
| 33 | #define REG_PINMUX0 0x0018 | ||
| 34 | #define REG_PINMUX5 0x002c | ||
| 35 | #define REG_SYSPLLCTL0 0x0030 | ||
| 36 | #define REG_SYSPLLCTL4 0x0040 | ||
| 37 | #define REG_CLKENABLE 0x00e8 | ||
| 38 | #define REG_CLKSELECT0 0x00ec | ||
| 39 | #define REG_CLKSELECT1 0x00f0 | ||
| 40 | #define REG_CLKSELECT2 0x00f4 | ||
| 41 | #define REG_CLKSWITCH0 0x00f8 | ||
| 42 | #define REG_CLKSWITCH1 0x00fc | ||
| 43 | #define REG_SW_GENERIC0 0x0110 | ||
| 44 | #define REG_SW_GENERIC3 0x011c | ||
| 45 | #define REG_SDIO0XIN_CLKCTL 0x0158 | ||
| 46 | #define REG_SDIO1XIN_CLKCTL 0x015c | ||
| 47 | |||
| 48 | #define MAX_CLKS 27 | ||
| 49 | static struct clk *clks[MAX_CLKS]; | ||
| 50 | static struct clk_onecell_data clk_data; | ||
| 51 | static DEFINE_SPINLOCK(lock); | ||
| 52 | static void __iomem *gbase; | ||
| 53 | static void __iomem *cpupll_base; | ||
| 54 | |||
| 55 | enum { | ||
| 56 | REFCLK, | ||
| 57 | SYSPLL, CPUPLL, | ||
| 58 | AVPLL_B1, AVPLL_B2, AVPLL_B3, AVPLL_B4, | ||
| 59 | AVPLL_B5, AVPLL_B6, AVPLL_B7, AVPLL_B8, | ||
| 60 | }; | ||
| 61 | |||
| 62 | static const char *clk_names[] = { | ||
| 63 | [REFCLK] = "refclk", | ||
| 64 | [SYSPLL] = "syspll", | ||
| 65 | [CPUPLL] = "cpupll", | ||
| 66 | [AVPLL_B1] = "avpll_b1", | ||
| 67 | [AVPLL_B2] = "avpll_b2", | ||
| 68 | [AVPLL_B3] = "avpll_b3", | ||
| 69 | [AVPLL_B4] = "avpll_b4", | ||
| 70 | [AVPLL_B5] = "avpll_b5", | ||
| 71 | [AVPLL_B6] = "avpll_b6", | ||
| 72 | [AVPLL_B7] = "avpll_b7", | ||
| 73 | [AVPLL_B8] = "avpll_b8", | ||
| 74 | }; | ||
| 75 | |||
| 76 | static const struct berlin2_pll_map bg2q_pll_map __initconst = { | ||
| 77 | .vcodiv = {1, 0, 2, 0, 3, 4, 0, 6, 8}, | ||
| 78 | .mult = 1, | ||
| 79 | .fbdiv_shift = 7, | ||
| 80 | .rfdiv_shift = 2, | ||
| 81 | .divsel_shift = 9, | ||
| 82 | }; | ||
| 83 | |||
| 84 | static const u8 default_parent_ids[] = { | ||
| 85 | SYSPLL, AVPLL_B4, AVPLL_B5, AVPLL_B6, AVPLL_B7, SYSPLL | ||
| 86 | }; | ||
| 87 | |||
| 88 | static const struct berlin2_div_data bg2q_divs[] __initconst = { | ||
| 89 | { | ||
| 90 | .name = "sys", | ||
| 91 | .parent_ids = default_parent_ids, | ||
| 92 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 93 | .map = { | ||
| 94 | BERLIN2_DIV_GATE(REG_CLKENABLE, 0), | ||
| 95 | BERLIN2_PLL_SELECT(REG_CLKSELECT0, 0), | ||
| 96 | BERLIN2_DIV_SELECT(REG_CLKSELECT0, 3), | ||
| 97 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 3), | ||
| 98 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 4), | ||
| 99 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 5), | ||
| 100 | }, | ||
| 101 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 102 | .flags = CLK_IGNORE_UNUSED, | ||
| 103 | }, | ||
| 104 | { | ||
| 105 | .name = "drmfigo", | ||
| 106 | .parent_ids = default_parent_ids, | ||
| 107 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 108 | .map = { | ||
| 109 | BERLIN2_DIV_GATE(REG_CLKENABLE, 17), | ||
| 110 | BERLIN2_PLL_SELECT(REG_CLKSELECT0, 6), | ||
| 111 | BERLIN2_DIV_SELECT(REG_CLKSELECT0, 9), | ||
| 112 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 6), | ||
| 113 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 7), | ||
| 114 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 8), | ||
| 115 | }, | ||
| 116 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 117 | .flags = 0, | ||
| 118 | }, | ||
| 119 | { | ||
| 120 | .name = "cfg", | ||
| 121 | .parent_ids = default_parent_ids, | ||
| 122 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 123 | .map = { | ||
| 124 | BERLIN2_DIV_GATE(REG_CLKENABLE, 1), | ||
| 125 | BERLIN2_PLL_SELECT(REG_CLKSELECT0, 12), | ||
| 126 | BERLIN2_DIV_SELECT(REG_CLKSELECT0, 15), | ||
| 127 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 9), | ||
| 128 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 10), | ||
| 129 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 11), | ||
| 130 | }, | ||
| 131 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 132 | .flags = 0, | ||
| 133 | }, | ||
| 134 | { | ||
| 135 | .name = "gfx2d", | ||
| 136 | .parent_ids = default_parent_ids, | ||
| 137 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 138 | .map = { | ||
| 139 | BERLIN2_DIV_GATE(REG_CLKENABLE, 4), | ||
| 140 | BERLIN2_PLL_SELECT(REG_CLKSELECT0, 18), | ||
| 141 | BERLIN2_DIV_SELECT(REG_CLKSELECT0, 21), | ||
| 142 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 12), | ||
| 143 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 13), | ||
| 144 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 14), | ||
| 145 | }, | ||
| 146 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 147 | .flags = 0, | ||
| 148 | }, | ||
| 149 | { | ||
| 150 | .name = "zsp", | ||
| 151 | .parent_ids = default_parent_ids, | ||
| 152 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 153 | .map = { | ||
| 154 | BERLIN2_DIV_GATE(REG_CLKENABLE, 6), | ||
| 155 | BERLIN2_PLL_SELECT(REG_CLKSELECT0, 24), | ||
| 156 | BERLIN2_DIV_SELECT(REG_CLKSELECT0, 27), | ||
| 157 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 15), | ||
| 158 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 16), | ||
| 159 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 17), | ||
| 160 | }, | ||
| 161 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 162 | .flags = 0, | ||
| 163 | }, | ||
| 164 | { | ||
| 165 | .name = "perif", | ||
| 166 | .parent_ids = default_parent_ids, | ||
| 167 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 168 | .map = { | ||
| 169 | BERLIN2_DIV_GATE(REG_CLKENABLE, 7), | ||
| 170 | BERLIN2_PLL_SELECT(REG_CLKSELECT1, 0), | ||
| 171 | BERLIN2_DIV_SELECT(REG_CLKSELECT1, 3), | ||
| 172 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 18), | ||
| 173 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 19), | ||
| 174 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 20), | ||
| 175 | }, | ||
| 176 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 177 | .flags = CLK_IGNORE_UNUSED, | ||
| 178 | }, | ||
| 179 | { | ||
| 180 | .name = "pcube", | ||
| 181 | .parent_ids = default_parent_ids, | ||
| 182 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 183 | .map = { | ||
| 184 | BERLIN2_DIV_GATE(REG_CLKENABLE, 2), | ||
| 185 | BERLIN2_PLL_SELECT(REG_CLKSELECT1, 6), | ||
| 186 | BERLIN2_DIV_SELECT(REG_CLKSELECT1, 9), | ||
| 187 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 21), | ||
| 188 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 22), | ||
| 189 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 23), | ||
| 190 | }, | ||
| 191 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 192 | .flags = 0, | ||
| 193 | }, | ||
| 194 | { | ||
| 195 | .name = "vscope", | ||
| 196 | .parent_ids = default_parent_ids, | ||
| 197 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 198 | .map = { | ||
| 199 | BERLIN2_DIV_GATE(REG_CLKENABLE, 3), | ||
| 200 | BERLIN2_PLL_SELECT(REG_CLKSELECT1, 12), | ||
| 201 | BERLIN2_DIV_SELECT(REG_CLKSELECT1, 15), | ||
| 202 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 24), | ||
| 203 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 25), | ||
| 204 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 26), | ||
| 205 | }, | ||
| 206 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 207 | .flags = 0, | ||
| 208 | }, | ||
| 209 | { | ||
| 210 | .name = "nfc_ecc", | ||
| 211 | .parent_ids = default_parent_ids, | ||
| 212 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 213 | .map = { | ||
| 214 | BERLIN2_DIV_GATE(REG_CLKENABLE, 19), | ||
| 215 | BERLIN2_PLL_SELECT(REG_CLKSELECT1, 18), | ||
| 216 | BERLIN2_DIV_SELECT(REG_CLKSELECT1, 21), | ||
| 217 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 27), | ||
| 218 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 28), | ||
| 219 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 29), | ||
| 220 | }, | ||
| 221 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 222 | .flags = 0, | ||
| 223 | }, | ||
| 224 | { | ||
| 225 | .name = "vpp", | ||
| 226 | .parent_ids = default_parent_ids, | ||
| 227 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 228 | .map = { | ||
| 229 | BERLIN2_DIV_GATE(REG_CLKENABLE, 21), | ||
| 230 | BERLIN2_PLL_SELECT(REG_CLKSELECT1, 24), | ||
| 231 | BERLIN2_DIV_SELECT(REG_CLKSELECT1, 27), | ||
| 232 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 30), | ||
| 233 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 31), | ||
| 234 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 0), | ||
| 235 | }, | ||
| 236 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 237 | .flags = 0, | ||
| 238 | }, | ||
| 239 | { | ||
| 240 | .name = "app", | ||
| 241 | .parent_ids = default_parent_ids, | ||
| 242 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 243 | .map = { | ||
| 244 | BERLIN2_DIV_GATE(REG_CLKENABLE, 20), | ||
| 245 | BERLIN2_PLL_SELECT(REG_CLKSELECT2, 0), | ||
| 246 | BERLIN2_DIV_SELECT(REG_CLKSELECT2, 3), | ||
| 247 | BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 1), | ||
| 248 | BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 2), | ||
| 249 | BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 3), | ||
| 250 | }, | ||
| 251 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 252 | .flags = 0, | ||
| 253 | }, | ||
| 254 | { | ||
| 255 | .name = "sdio0xin", | ||
| 256 | .parent_ids = default_parent_ids, | ||
| 257 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 258 | .map = { | ||
| 259 | BERLIN2_SINGLE_DIV(REG_SDIO0XIN_CLKCTL), | ||
| 260 | }, | ||
| 261 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 262 | .flags = 0, | ||
| 263 | }, | ||
| 264 | { | ||
| 265 | .name = "sdio1xin", | ||
| 266 | .parent_ids = default_parent_ids, | ||
| 267 | .num_parents = ARRAY_SIZE(default_parent_ids), | ||
| 268 | .map = { | ||
| 269 | BERLIN2_SINGLE_DIV(REG_SDIO1XIN_CLKCTL), | ||
| 270 | }, | ||
| 271 | .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX, | ||
| 272 | .flags = 0, | ||
| 273 | }, | ||
| 274 | }; | ||
| 275 | |||
| 276 | static const struct berlin2_gate_data bg2q_gates[] __initconst = { | ||
| 277 | { "gfx2daxi", "perif", 5 }, | ||
| 278 | { "geth0", "perif", 8 }, | ||
| 279 | { "sata", "perif", 9 }, | ||
| 280 | { "ahbapb", "perif", 10, CLK_IGNORE_UNUSED }, | ||
| 281 | { "usb0", "perif", 11 }, | ||
| 282 | { "usb1", "perif", 12 }, | ||
| 283 | { "usb2", "perif", 13 }, | ||
| 284 | { "usb3", "perif", 14 }, | ||
| 285 | { "pbridge", "perif", 15, CLK_IGNORE_UNUSED }, | ||
| 286 | { "sdio", "perif", 16, CLK_IGNORE_UNUSED }, | ||
| 287 | { "nfc", "perif", 18 }, | ||
| 288 | { "smemc", "perif", 19 }, | ||
| 289 | { "pcie", "perif", 22 }, | ||
| 290 | }; | ||
| 291 | |||
| 292 | static void __init berlin2q_clock_setup(struct device_node *np) | ||
| 293 | { | ||
| 294 | const char *parent_names[9]; | ||
| 295 | struct clk *clk; | ||
| 296 | int n; | ||
| 297 | |||
| 298 | gbase = of_iomap(np, 0); | ||
| 299 | if (!gbase) { | ||
| 300 | pr_err("%s: Unable to map global base\n", np->full_name); | ||
| 301 | return; | ||
| 302 | } | ||
| 303 | |||
| 304 | /* BG2Q CPU PLL is not part of global registers */ | ||
| 305 | cpupll_base = of_iomap(np, 1); | ||
| 306 | if (!cpupll_base) { | ||
| 307 | pr_err("%s: Unable to map cpupll base\n", np->full_name); | ||
| 308 | iounmap(gbase); | ||
| 309 | return; | ||
| 310 | } | ||
| 311 | |||
| 312 | /* overwrite default clock names with DT provided ones */ | ||
| 313 | clk = of_clk_get_by_name(np, clk_names[REFCLK]); | ||
| 314 | if (!IS_ERR(clk)) { | ||
| 315 | clk_names[REFCLK] = __clk_get_name(clk); | ||
| 316 | clk_put(clk); | ||
| 317 | } | ||
| 318 | |||
| 319 | /* simple register PLLs */ | ||
| 320 | clk = berlin2_pll_register(&bg2q_pll_map, gbase + REG_SYSPLLCTL0, | ||
| 321 | clk_names[SYSPLL], clk_names[REFCLK], 0); | ||
| 322 | if (IS_ERR(clk)) | ||
| 323 | goto bg2q_fail; | ||
| 324 | |||
| 325 | clk = berlin2_pll_register(&bg2q_pll_map, cpupll_base, | ||
| 326 | clk_names[CPUPLL], clk_names[REFCLK], 0); | ||
| 327 | if (IS_ERR(clk)) | ||
| 328 | goto bg2q_fail; | ||
| 329 | |||
| 330 | /* TODO: add BG2Q AVPLL */ | ||
| 331 | |||
| 332 | /* | ||
| 333 | * TODO: add reference clock bypass switches: | ||
| 334 | * memPLLSWBypass, cpuPLLSWBypass, and sysPLLSWBypass | ||
| 335 | */ | ||
| 336 | |||
| 337 | /* clock divider cells */ | ||
| 338 | for (n = 0; n < ARRAY_SIZE(bg2q_divs); n++) { | ||
| 339 | const struct berlin2_div_data *dd = &bg2q_divs[n]; | ||
| 340 | int k; | ||
| 341 | |||
| 342 | for (k = 0; k < dd->num_parents; k++) | ||
| 343 | parent_names[k] = clk_names[dd->parent_ids[k]]; | ||
| 344 | |||
| 345 | clks[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase, | ||
| 346 | dd->name, dd->div_flags, parent_names, | ||
| 347 | dd->num_parents, dd->flags, &lock); | ||
| 348 | } | ||
| 349 | |||
| 350 | /* clock gate cells */ | ||
| 351 | for (n = 0; n < ARRAY_SIZE(bg2q_gates); n++) { | ||
| 352 | const struct berlin2_gate_data *gd = &bg2q_gates[n]; | ||
| 353 | |||
| 354 | clks[CLKID_GFX2DAXI + n] = clk_register_gate(NULL, gd->name, | ||
| 355 | gd->parent_name, gd->flags, gbase + REG_CLKENABLE, | ||
| 356 | gd->bit_idx, 0, &lock); | ||
| 357 | } | ||
| 358 | |||
| 359 | /* | ||
| 360 | * twdclk is derived from cpu/3 | ||
| 361 | * TODO: use cpupll until cpuclk is not available | ||
| 362 | */ | ||
| 363 | clks[CLKID_TWD] = | ||
| 364 | clk_register_fixed_factor(NULL, "twd", clk_names[CPUPLL], | ||
| 365 | 0, 1, 3); | ||
| 366 | |||
| 367 | /* check for errors on leaf clocks */ | ||
| 368 | for (n = 0; n < MAX_CLKS; n++) { | ||
| 369 | if (!IS_ERR(clks[n])) | ||
| 370 | continue; | ||
| 371 | |||
| 372 | pr_err("%s: Unable to register leaf clock %d\n", | ||
| 373 | np->full_name, n); | ||
| 374 | goto bg2q_fail; | ||
| 375 | } | ||
| 376 | |||
| 377 | /* register clk-provider */ | ||
| 378 | clk_data.clks = clks; | ||
| 379 | clk_data.clk_num = MAX_CLKS; | ||
| 380 | of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); | ||
| 381 | |||
| 382 | return; | ||
| 383 | |||
| 384 | bg2q_fail: | ||
| 385 | iounmap(cpupll_base); | ||
| 386 | iounmap(gbase); | ||
| 387 | } | ||
| 388 | CLK_OF_DECLARE(berlin2q_clock, "marvell,berlin2q-chip-ctrl", | ||
| 389 | berlin2q_clock_setup); | ||
diff --git a/drivers/clk/berlin/common.h b/drivers/clk/berlin/common.h new file mode 100644 index 000000000000..bc68a14c4550 --- /dev/null +++ b/drivers/clk/berlin/common.h | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014 Marvell Technology Group Ltd. | ||
| 3 | * | ||
| 4 | * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | ||
| 5 | * Alexandre Belloni <alexandre.belloni@free-electrons.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms and conditions of the GNU General Public License, | ||
| 9 | * version 2, as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 14 | * more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License along with | ||
| 17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #ifndef __BERLIN2_COMMON_H | ||
| 20 | #define __BERLIN2_COMMON_H | ||
| 21 | |||
| 22 | struct berlin2_gate_data { | ||
| 23 | const char *name; | ||
| 24 | const char *parent_name; | ||
| 25 | u8 bit_idx; | ||
| 26 | unsigned long flags; | ||
| 27 | }; | ||
| 28 | |||
| 29 | #endif /* BERLIN2_COMMON_H */ | ||
diff --git a/drivers/clk/clk-axm5516.c b/drivers/clk/clk-axm5516.c new file mode 100644 index 000000000000..d2f1e119b450 --- /dev/null +++ b/drivers/clk/clk-axm5516.c | |||
| @@ -0,0 +1,615 @@ | |||
| 1 | /* | ||
| 2 | * drivers/clk/clk-axm5516.c | ||
| 3 | * | ||
| 4 | * Provides clock implementations for three different types of clock devices on | ||
| 5 | * the Axxia device: PLL clock, a clock divider and a clock mux. | ||
| 6 | * | ||
| 7 | * Copyright (C) 2014 LSI Corporation | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify it | ||
| 10 | * under the terms of the GNU General Public License version 2 as published by | ||
| 11 | * the Free Software Foundation. | ||
| 12 | */ | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/platform_device.h> | ||
| 17 | #include <linux/of.h> | ||
| 18 | #include <linux/of_address.h> | ||
| 19 | #include <linux/clk-provider.h> | ||
| 20 | #include <linux/regmap.h> | ||
| 21 | #include <dt-bindings/clock/lsi,axm5516-clks.h> | ||
| 22 | |||
| 23 | |||
| 24 | /** | ||
| 25 | * struct axxia_clk - Common struct to all Axxia clocks. | ||
| 26 | * @hw: clk_hw for the common clk framework | ||
| 27 | * @regmap: Regmap for the clock control registers | ||
| 28 | */ | ||
| 29 | struct axxia_clk { | ||
| 30 | struct clk_hw hw; | ||
| 31 | struct regmap *regmap; | ||
| 32 | }; | ||
| 33 | #define to_axxia_clk(_hw) container_of(_hw, struct axxia_clk, hw) | ||
| 34 | |||
| 35 | /** | ||
| 36 | * struct axxia_pllclk - Axxia PLL generated clock. | ||
| 37 | * @aclk: Common struct | ||
| 38 | * @reg: Offset into regmap for PLL control register | ||
| 39 | */ | ||
| 40 | struct axxia_pllclk { | ||
| 41 | struct axxia_clk aclk; | ||
| 42 | u32 reg; | ||
| 43 | }; | ||
| 44 | #define to_axxia_pllclk(_aclk) container_of(_aclk, struct axxia_pllclk, aclk) | ||
| 45 | |||
| 46 | /** | ||
| 47 | * axxia_pllclk_recalc - Calculate the PLL generated clock rate given the | ||
| 48 | * parent clock rate. | ||
| 49 | */ | ||
| 50 | static unsigned long | ||
| 51 | axxia_pllclk_recalc(struct clk_hw *hw, unsigned long parent_rate) | ||
| 52 | { | ||
| 53 | struct axxia_clk *aclk = to_axxia_clk(hw); | ||
| 54 | struct axxia_pllclk *pll = to_axxia_pllclk(aclk); | ||
| 55 | unsigned long rate, fbdiv, refdiv, postdiv; | ||
| 56 | u32 control; | ||
| 57 | |||
| 58 | regmap_read(aclk->regmap, pll->reg, &control); | ||
| 59 | postdiv = ((control >> 0) & 0xf) + 1; | ||
| 60 | fbdiv = ((control >> 4) & 0xfff) + 3; | ||
| 61 | refdiv = ((control >> 16) & 0x1f) + 1; | ||
| 62 | rate = (parent_rate / (refdiv * postdiv)) * fbdiv; | ||
| 63 | |||
| 64 | return rate; | ||
| 65 | } | ||
| 66 | |||
| 67 | static const struct clk_ops axxia_pllclk_ops = { | ||
| 68 | .recalc_rate = axxia_pllclk_recalc, | ||
| 69 | }; | ||
| 70 | |||
| 71 | /** | ||
| 72 | * struct axxia_divclk - Axxia clock divider | ||
| 73 | * @aclk: Common struct | ||
| 74 | * @reg: Offset into regmap for PLL control register | ||
| 75 | * @shift: Bit position for divider value | ||
| 76 | * @width: Number of bits in divider value | ||
| 77 | */ | ||
| 78 | struct axxia_divclk { | ||
| 79 | struct axxia_clk aclk; | ||
| 80 | u32 reg; | ||
| 81 | u32 shift; | ||
| 82 | u32 width; | ||
| 83 | }; | ||
| 84 | #define to_axxia_divclk(_aclk) container_of(_aclk, struct axxia_divclk, aclk) | ||
| 85 | |||
| 86 | /** | ||
| 87 | * axxia_divclk_recalc_rate - Calculate clock divider output rage | ||
| 88 | */ | ||
| 89 | static unsigned long | ||
| 90 | axxia_divclk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | ||
| 91 | { | ||
| 92 | struct axxia_clk *aclk = to_axxia_clk(hw); | ||
| 93 | struct axxia_divclk *divclk = to_axxia_divclk(aclk); | ||
| 94 | u32 ctrl, div; | ||
| 95 | |||
| 96 | regmap_read(aclk->regmap, divclk->reg, &ctrl); | ||
| 97 | div = 1 + ((ctrl >> divclk->shift) & ((1 << divclk->width)-1)); | ||
| 98 | |||
| 99 | return parent_rate / div; | ||
| 100 | } | ||
| 101 | |||
| 102 | static const struct clk_ops axxia_divclk_ops = { | ||
| 103 | .recalc_rate = axxia_divclk_recalc_rate, | ||
| 104 | }; | ||
| 105 | |||
| 106 | /** | ||
| 107 | * struct axxia_clkmux - Axxia clock mux | ||
| 108 | * @aclk: Common struct | ||
| 109 | * @reg: Offset into regmap for PLL control register | ||
| 110 | * @shift: Bit position for selection value | ||
| 111 | * @width: Number of bits in selection value | ||
| 112 | */ | ||
| 113 | struct axxia_clkmux { | ||
| 114 | struct axxia_clk aclk; | ||
| 115 | u32 reg; | ||
| 116 | u32 shift; | ||
| 117 | u32 width; | ||
| 118 | }; | ||
| 119 | #define to_axxia_clkmux(_aclk) container_of(_aclk, struct axxia_clkmux, aclk) | ||
| 120 | |||
| 121 | /** | ||
| 122 | * axxia_clkmux_get_parent - Return the index of selected parent clock | ||
| 123 | */ | ||
| 124 | static u8 axxia_clkmux_get_parent(struct clk_hw *hw) | ||
| 125 | { | ||
| 126 | struct axxia_clk *aclk = to_axxia_clk(hw); | ||
| 127 | struct axxia_clkmux *mux = to_axxia_clkmux(aclk); | ||
| 128 | u32 ctrl, parent; | ||
| 129 | |||
| 130 | regmap_read(aclk->regmap, mux->reg, &ctrl); | ||
| 131 | parent = (ctrl >> mux->shift) & ((1 << mux->width) - 1); | ||
| 132 | |||
| 133 | return (u8) parent; | ||
| 134 | } | ||
| 135 | |||
| 136 | static const struct clk_ops axxia_clkmux_ops = { | ||
| 137 | .get_parent = axxia_clkmux_get_parent, | ||
| 138 | }; | ||
| 139 | |||
| 140 | |||
| 141 | /* | ||
| 142 | * PLLs | ||
| 143 | */ | ||
| 144 | |||
| 145 | static struct axxia_pllclk clk_fab_pll = { | ||
| 146 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 147 | .name = "clk_fab_pll", | ||
| 148 | .parent_names = (const char *[]){ | ||
| 149 | "clk_ref0" | ||
| 150 | }, | ||
| 151 | .num_parents = 1, | ||
| 152 | .ops = &axxia_pllclk_ops, | ||
| 153 | }, | ||
| 154 | .reg = 0x01800, | ||
| 155 | }; | ||
| 156 | |||
| 157 | static struct axxia_pllclk clk_cpu_pll = { | ||
| 158 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 159 | .name = "clk_cpu_pll", | ||
| 160 | .parent_names = (const char *[]){ | ||
| 161 | "clk_ref0" | ||
| 162 | }, | ||
| 163 | .num_parents = 1, | ||
| 164 | .ops = &axxia_pllclk_ops, | ||
| 165 | }, | ||
| 166 | .reg = 0x02000, | ||
| 167 | }; | ||
| 168 | |||
| 169 | static struct axxia_pllclk clk_sys_pll = { | ||
| 170 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 171 | .name = "clk_sys_pll", | ||
| 172 | .parent_names = (const char *[]){ | ||
| 173 | "clk_ref0" | ||
| 174 | }, | ||
| 175 | .num_parents = 1, | ||
| 176 | .ops = &axxia_pllclk_ops, | ||
| 177 | }, | ||
| 178 | .reg = 0x02800, | ||
| 179 | }; | ||
| 180 | |||
| 181 | static struct axxia_pllclk clk_sm0_pll = { | ||
| 182 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 183 | .name = "clk_sm0_pll", | ||
| 184 | .parent_names = (const char *[]){ | ||
| 185 | "clk_ref2" | ||
| 186 | }, | ||
| 187 | .num_parents = 1, | ||
| 188 | .ops = &axxia_pllclk_ops, | ||
| 189 | }, | ||
| 190 | .reg = 0x03000, | ||
| 191 | }; | ||
| 192 | |||
| 193 | static struct axxia_pllclk clk_sm1_pll = { | ||
| 194 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 195 | .name = "clk_sm1_pll", | ||
| 196 | .parent_names = (const char *[]){ | ||
| 197 | "clk_ref1" | ||
| 198 | }, | ||
| 199 | .num_parents = 1, | ||
| 200 | .ops = &axxia_pllclk_ops, | ||
| 201 | }, | ||
| 202 | .reg = 0x03800, | ||
| 203 | }; | ||
| 204 | |||
| 205 | /* | ||
| 206 | * Clock dividers | ||
| 207 | */ | ||
| 208 | |||
| 209 | static struct axxia_divclk clk_cpu0_div = { | ||
| 210 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 211 | .name = "clk_cpu0_div", | ||
| 212 | .parent_names = (const char *[]){ | ||
| 213 | "clk_cpu_pll" | ||
| 214 | }, | ||
| 215 | .num_parents = 1, | ||
| 216 | .ops = &axxia_divclk_ops, | ||
| 217 | }, | ||
| 218 | .reg = 0x10008, | ||
| 219 | .shift = 0, | ||
| 220 | .width = 4, | ||
| 221 | }; | ||
| 222 | |||
| 223 | static struct axxia_divclk clk_cpu1_div = { | ||
| 224 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 225 | .name = "clk_cpu1_div", | ||
| 226 | .parent_names = (const char *[]){ | ||
| 227 | "clk_cpu_pll" | ||
| 228 | }, | ||
| 229 | .num_parents = 1, | ||
| 230 | .ops = &axxia_divclk_ops, | ||
| 231 | }, | ||
| 232 | .reg = 0x10008, | ||
| 233 | .shift = 4, | ||
| 234 | .width = 4, | ||
| 235 | }; | ||
| 236 | |||
| 237 | static struct axxia_divclk clk_cpu2_div = { | ||
| 238 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 239 | .name = "clk_cpu2_div", | ||
| 240 | .parent_names = (const char *[]){ | ||
| 241 | "clk_cpu_pll" | ||
| 242 | }, | ||
| 243 | .num_parents = 1, | ||
| 244 | .ops = &axxia_divclk_ops, | ||
| 245 | }, | ||
| 246 | .reg = 0x10008, | ||
| 247 | .shift = 8, | ||
| 248 | .width = 4, | ||
| 249 | }; | ||
| 250 | |||
| 251 | static struct axxia_divclk clk_cpu3_div = { | ||
| 252 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 253 | .name = "clk_cpu3_div", | ||
| 254 | .parent_names = (const char *[]){ | ||
| 255 | "clk_cpu_pll" | ||
| 256 | }, | ||
| 257 | .num_parents = 1, | ||
| 258 | .ops = &axxia_divclk_ops, | ||
| 259 | }, | ||
| 260 | .reg = 0x10008, | ||
| 261 | .shift = 12, | ||
| 262 | .width = 4, | ||
| 263 | }; | ||
| 264 | |||
| 265 | static struct axxia_divclk clk_nrcp_div = { | ||
| 266 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 267 | .name = "clk_nrcp_div", | ||
| 268 | .parent_names = (const char *[]){ | ||
| 269 | "clk_sys_pll" | ||
| 270 | }, | ||
| 271 | .num_parents = 1, | ||
| 272 | .ops = &axxia_divclk_ops, | ||
| 273 | }, | ||
| 274 | .reg = 0x1000c, | ||
| 275 | .shift = 0, | ||
| 276 | .width = 4, | ||
| 277 | }; | ||
| 278 | |||
| 279 | static struct axxia_divclk clk_sys_div = { | ||
| 280 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 281 | .name = "clk_sys_div", | ||
| 282 | .parent_names = (const char *[]){ | ||
| 283 | "clk_sys_pll" | ||
| 284 | }, | ||
| 285 | .num_parents = 1, | ||
| 286 | .ops = &axxia_divclk_ops, | ||
| 287 | }, | ||
| 288 | .reg = 0x1000c, | ||
| 289 | .shift = 4, | ||
| 290 | .width = 4, | ||
| 291 | }; | ||
| 292 | |||
| 293 | static struct axxia_divclk clk_fab_div = { | ||
| 294 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 295 | .name = "clk_fab_div", | ||
| 296 | .parent_names = (const char *[]){ | ||
| 297 | "clk_fab_pll" | ||
| 298 | }, | ||
| 299 | .num_parents = 1, | ||
| 300 | .ops = &axxia_divclk_ops, | ||
| 301 | }, | ||
| 302 | .reg = 0x1000c, | ||
| 303 | .shift = 8, | ||
| 304 | .width = 4, | ||
| 305 | }; | ||
| 306 | |||
| 307 | static struct axxia_divclk clk_per_div = { | ||
| 308 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 309 | .name = "clk_per_div", | ||
| 310 | .parent_names = (const char *[]){ | ||
| 311 | "clk_sm1_pll" | ||
| 312 | }, | ||
| 313 | .num_parents = 1, | ||
| 314 | .flags = CLK_IS_BASIC, | ||
| 315 | .ops = &axxia_divclk_ops, | ||
| 316 | }, | ||
| 317 | .reg = 0x1000c, | ||
| 318 | .shift = 12, | ||
| 319 | .width = 4, | ||
| 320 | }; | ||
| 321 | |||
| 322 | static struct axxia_divclk clk_mmc_div = { | ||
| 323 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 324 | .name = "clk_mmc_div", | ||
| 325 | .parent_names = (const char *[]){ | ||
| 326 | "clk_sm1_pll" | ||
| 327 | }, | ||
| 328 | .num_parents = 1, | ||
| 329 | .flags = CLK_IS_BASIC, | ||
| 330 | .ops = &axxia_divclk_ops, | ||
| 331 | }, | ||
| 332 | .reg = 0x1000c, | ||
| 333 | .shift = 16, | ||
| 334 | .width = 4, | ||
| 335 | }; | ||
| 336 | |||
| 337 | /* | ||
| 338 | * Clock MUXes | ||
| 339 | */ | ||
| 340 | |||
| 341 | static struct axxia_clkmux clk_cpu0_mux = { | ||
| 342 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 343 | .name = "clk_cpu0", | ||
| 344 | .parent_names = (const char *[]){ | ||
| 345 | "clk_ref0", | ||
| 346 | "clk_cpu_pll", | ||
| 347 | "clk_cpu0_div", | ||
| 348 | "clk_cpu0_div" | ||
| 349 | }, | ||
| 350 | .num_parents = 4, | ||
| 351 | .ops = &axxia_clkmux_ops, | ||
| 352 | }, | ||
| 353 | .reg = 0x10000, | ||
| 354 | .shift = 0, | ||
| 355 | .width = 2, | ||
| 356 | }; | ||
| 357 | |||
| 358 | static struct axxia_clkmux clk_cpu1_mux = { | ||
| 359 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 360 | .name = "clk_cpu1", | ||
| 361 | .parent_names = (const char *[]){ | ||
| 362 | "clk_ref0", | ||
| 363 | "clk_cpu_pll", | ||
| 364 | "clk_cpu1_div", | ||
| 365 | "clk_cpu1_div" | ||
| 366 | }, | ||
| 367 | .num_parents = 4, | ||
| 368 | .ops = &axxia_clkmux_ops, | ||
| 369 | }, | ||
| 370 | .reg = 0x10000, | ||
| 371 | .shift = 2, | ||
| 372 | .width = 2, | ||
| 373 | }; | ||
| 374 | |||
| 375 | static struct axxia_clkmux clk_cpu2_mux = { | ||
| 376 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 377 | .name = "clk_cpu2", | ||
| 378 | .parent_names = (const char *[]){ | ||
| 379 | "clk_ref0", | ||
| 380 | "clk_cpu_pll", | ||
| 381 | "clk_cpu2_div", | ||
| 382 | "clk_cpu2_div" | ||
| 383 | }, | ||
| 384 | .num_parents = 4, | ||
| 385 | .ops = &axxia_clkmux_ops, | ||
| 386 | }, | ||
| 387 | .reg = 0x10000, | ||
| 388 | .shift = 4, | ||
| 389 | .width = 2, | ||
| 390 | }; | ||
| 391 | |||
| 392 | static struct axxia_clkmux clk_cpu3_mux = { | ||
| 393 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 394 | .name = "clk_cpu3", | ||
| 395 | .parent_names = (const char *[]){ | ||
| 396 | "clk_ref0", | ||
| 397 | "clk_cpu_pll", | ||
| 398 | "clk_cpu3_div", | ||
| 399 | "clk_cpu3_div" | ||
| 400 | }, | ||
| 401 | .num_parents = 4, | ||
| 402 | .ops = &axxia_clkmux_ops, | ||
| 403 | }, | ||
| 404 | .reg = 0x10000, | ||
| 405 | .shift = 6, | ||
| 406 | .width = 2, | ||
| 407 | }; | ||
| 408 | |||
| 409 | static struct axxia_clkmux clk_nrcp_mux = { | ||
| 410 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 411 | .name = "clk_nrcp", | ||
| 412 | .parent_names = (const char *[]){ | ||
| 413 | "clk_ref0", | ||
| 414 | "clk_sys_pll", | ||
| 415 | "clk_nrcp_div", | ||
| 416 | "clk_nrcp_div" | ||
| 417 | }, | ||
| 418 | .num_parents = 4, | ||
| 419 | .ops = &axxia_clkmux_ops, | ||
| 420 | }, | ||
| 421 | .reg = 0x10004, | ||
| 422 | .shift = 0, | ||
| 423 | .width = 2, | ||
| 424 | }; | ||
| 425 | |||
| 426 | static struct axxia_clkmux clk_sys_mux = { | ||
| 427 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 428 | .name = "clk_sys", | ||
| 429 | .parent_names = (const char *[]){ | ||
| 430 | "clk_ref0", | ||
| 431 | "clk_sys_pll", | ||
| 432 | "clk_sys_div", | ||
| 433 | "clk_sys_div" | ||
| 434 | }, | ||
| 435 | .num_parents = 4, | ||
| 436 | .ops = &axxia_clkmux_ops, | ||
| 437 | }, | ||
| 438 | .reg = 0x10004, | ||
| 439 | .shift = 2, | ||
| 440 | .width = 2, | ||
| 441 | }; | ||
| 442 | |||
| 443 | static struct axxia_clkmux clk_fab_mux = { | ||
| 444 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 445 | .name = "clk_fab", | ||
| 446 | .parent_names = (const char *[]){ | ||
| 447 | "clk_ref0", | ||
| 448 | "clk_fab_pll", | ||
| 449 | "clk_fab_div", | ||
| 450 | "clk_fab_div" | ||
| 451 | }, | ||
| 452 | .num_parents = 4, | ||
| 453 | .ops = &axxia_clkmux_ops, | ||
| 454 | }, | ||
| 455 | .reg = 0x10004, | ||
| 456 | .shift = 4, | ||
| 457 | .width = 2, | ||
| 458 | }; | ||
| 459 | |||
| 460 | static struct axxia_clkmux clk_per_mux = { | ||
| 461 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 462 | .name = "clk_per", | ||
| 463 | .parent_names = (const char *[]){ | ||
| 464 | "clk_ref1", | ||
| 465 | "clk_per_div" | ||
| 466 | }, | ||
| 467 | .num_parents = 2, | ||
| 468 | .ops = &axxia_clkmux_ops, | ||
| 469 | }, | ||
| 470 | .reg = 0x10004, | ||
| 471 | .shift = 6, | ||
| 472 | .width = 1, | ||
| 473 | }; | ||
| 474 | |||
| 475 | static struct axxia_clkmux clk_mmc_mux = { | ||
| 476 | .aclk.hw.init = &(struct clk_init_data){ | ||
| 477 | .name = "clk_mmc", | ||
| 478 | .parent_names = (const char *[]){ | ||
| 479 | "clk_ref1", | ||
| 480 | "clk_mmc_div" | ||
| 481 | }, | ||
| 482 | .num_parents = 2, | ||
| 483 | .ops = &axxia_clkmux_ops, | ||
| 484 | }, | ||
| 485 | .reg = 0x10004, | ||
| 486 | .shift = 9, | ||
| 487 | .width = 1, | ||
| 488 | }; | ||
| 489 | |||
| 490 | /* Table of all supported clocks indexed by the clock identifiers from the | ||
| 491 | * device tree binding | ||
| 492 | */ | ||
| 493 | static struct axxia_clk *axmclk_clocks[] = { | ||
| 494 | [AXXIA_CLK_FAB_PLL] = &clk_fab_pll.aclk, | ||
| 495 | [AXXIA_CLK_CPU_PLL] = &clk_cpu_pll.aclk, | ||
| 496 | [AXXIA_CLK_SYS_PLL] = &clk_sys_pll.aclk, | ||
| 497 | [AXXIA_CLK_SM0_PLL] = &clk_sm0_pll.aclk, | ||
| 498 | [AXXIA_CLK_SM1_PLL] = &clk_sm1_pll.aclk, | ||
| 499 | [AXXIA_CLK_FAB_DIV] = &clk_fab_div.aclk, | ||
| 500 | [AXXIA_CLK_SYS_DIV] = &clk_sys_div.aclk, | ||
| 501 | [AXXIA_CLK_NRCP_DIV] = &clk_nrcp_div.aclk, | ||
| 502 | [AXXIA_CLK_CPU0_DIV] = &clk_cpu0_div.aclk, | ||
| 503 | [AXXIA_CLK_CPU1_DIV] = &clk_cpu1_div.aclk, | ||
| 504 | [AXXIA_CLK_CPU2_DIV] = &clk_cpu2_div.aclk, | ||
| 505 | [AXXIA_CLK_CPU3_DIV] = &clk_cpu3_div.aclk, | ||
| 506 | [AXXIA_CLK_PER_DIV] = &clk_per_div.aclk, | ||
| 507 | [AXXIA_CLK_MMC_DIV] = &clk_mmc_div.aclk, | ||
| 508 | [AXXIA_CLK_FAB] = &clk_fab_mux.aclk, | ||
| 509 | [AXXIA_CLK_SYS] = &clk_sys_mux.aclk, | ||
| 510 | [AXXIA_CLK_NRCP] = &clk_nrcp_mux.aclk, | ||
| 511 | [AXXIA_CLK_CPU0] = &clk_cpu0_mux.aclk, | ||
| 512 | [AXXIA_CLK_CPU1] = &clk_cpu1_mux.aclk, | ||
| 513 | [AXXIA_CLK_CPU2] = &clk_cpu2_mux.aclk, | ||
| 514 | [AXXIA_CLK_CPU3] = &clk_cpu3_mux.aclk, | ||
| 515 | [AXXIA_CLK_PER] = &clk_per_mux.aclk, | ||
| 516 | [AXXIA_CLK_MMC] = &clk_mmc_mux.aclk, | ||
| 517 | }; | ||
| 518 | |||
| 519 | static const struct regmap_config axmclk_regmap_config = { | ||
| 520 | .reg_bits = 32, | ||
| 521 | .reg_stride = 4, | ||
| 522 | .val_bits = 32, | ||
| 523 | .max_register = 0x1fffc, | ||
| 524 | .fast_io = true, | ||
| 525 | }; | ||
| 526 | |||
| 527 | static const struct of_device_id axmclk_match_table[] = { | ||
| 528 | { .compatible = "lsi,axm5516-clks" }, | ||
| 529 | { } | ||
| 530 | }; | ||
| 531 | MODULE_DEVICE_TABLE(of, axmclk_match_table); | ||
| 532 | |||
| 533 | struct axmclk_priv { | ||
| 534 | struct clk_onecell_data onecell; | ||
| 535 | struct clk *clks[]; | ||
| 536 | }; | ||
| 537 | |||
| 538 | static int axmclk_probe(struct platform_device *pdev) | ||
| 539 | { | ||
| 540 | void __iomem *base; | ||
| 541 | struct resource *res; | ||
| 542 | int i, ret; | ||
| 543 | struct device *dev = &pdev->dev; | ||
| 544 | struct clk *clk; | ||
| 545 | struct regmap *regmap; | ||
| 546 | size_t num_clks; | ||
| 547 | struct axmclk_priv *priv; | ||
| 548 | |||
| 549 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 550 | base = devm_ioremap_resource(dev, res); | ||
| 551 | if (IS_ERR(base)) | ||
| 552 | return PTR_ERR(base); | ||
| 553 | |||
| 554 | regmap = devm_regmap_init_mmio(dev, base, &axmclk_regmap_config); | ||
| 555 | if (IS_ERR(regmap)) | ||
| 556 | return PTR_ERR(regmap); | ||
| 557 | |||
| 558 | num_clks = ARRAY_SIZE(axmclk_clocks); | ||
| 559 | pr_info("axmclk: supporting %u clocks\n", num_clks); | ||
| 560 | priv = devm_kzalloc(dev, sizeof(*priv) + sizeof(*priv->clks) * num_clks, | ||
| 561 | GFP_KERNEL); | ||
| 562 | if (!priv) | ||
| 563 | return -ENOMEM; | ||
| 564 | |||
| 565 | priv->onecell.clks = priv->clks; | ||
| 566 | priv->onecell.clk_num = num_clks; | ||
| 567 | |||
| 568 | /* Update each entry with the allocated regmap and register the clock | ||
| 569 | * with the common clock framework | ||
| 570 | */ | ||
| 571 | for (i = 0; i < num_clks; i++) { | ||
| 572 | axmclk_clocks[i]->regmap = regmap; | ||
| 573 | clk = devm_clk_register(dev, &axmclk_clocks[i]->hw); | ||
| 574 | if (IS_ERR(clk)) | ||
| 575 | return PTR_ERR(clk); | ||
| 576 | priv->clks[i] = clk; | ||
| 577 | } | ||
| 578 | |||
| 579 | ret = of_clk_add_provider(dev->of_node, | ||
| 580 | of_clk_src_onecell_get, &priv->onecell); | ||
| 581 | |||
| 582 | return ret; | ||
| 583 | } | ||
| 584 | |||
| 585 | static int axmclk_remove(struct platform_device *pdev) | ||
| 586 | { | ||
| 587 | of_clk_del_provider(pdev->dev.of_node); | ||
| 588 | return 0; | ||
| 589 | } | ||
| 590 | |||
| 591 | static struct platform_driver axmclk_driver = { | ||
| 592 | .probe = axmclk_probe, | ||
| 593 | .remove = axmclk_remove, | ||
| 594 | .driver = { | ||
| 595 | .name = "clk-axm5516", | ||
| 596 | .owner = THIS_MODULE, | ||
| 597 | .of_match_table = axmclk_match_table, | ||
| 598 | }, | ||
| 599 | }; | ||
| 600 | |||
| 601 | static int __init axmclk_init(void) | ||
| 602 | { | ||
| 603 | return platform_driver_register(&axmclk_driver); | ||
| 604 | } | ||
| 605 | core_initcall(axmclk_init); | ||
| 606 | |||
| 607 | static void __exit axmclk_exit(void) | ||
| 608 | { | ||
| 609 | platform_driver_unregister(&axmclk_driver); | ||
| 610 | } | ||
| 611 | module_exit(axmclk_exit); | ||
| 612 | |||
| 613 | MODULE_DESCRIPTION("AXM5516 clock driver"); | ||
| 614 | MODULE_LICENSE("GPL v2"); | ||
| 615 | MODULE_ALIAS("platform:clk-axm5516"); | ||
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 3fbee4540228..18a9de29df0e 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c | |||
| @@ -43,6 +43,17 @@ static unsigned int _get_table_maxdiv(const struct clk_div_table *table) | |||
| 43 | return maxdiv; | 43 | return maxdiv; |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | static unsigned int _get_table_mindiv(const struct clk_div_table *table) | ||
| 47 | { | ||
| 48 | unsigned int mindiv = UINT_MAX; | ||
| 49 | const struct clk_div_table *clkt; | ||
| 50 | |||
| 51 | for (clkt = table; clkt->div; clkt++) | ||
| 52 | if (clkt->div < mindiv) | ||
| 53 | mindiv = clkt->div; | ||
| 54 | return mindiv; | ||
| 55 | } | ||
| 56 | |||
| 46 | static unsigned int _get_maxdiv(struct clk_divider *divider) | 57 | static unsigned int _get_maxdiv(struct clk_divider *divider) |
| 47 | { | 58 | { |
| 48 | if (divider->flags & CLK_DIVIDER_ONE_BASED) | 59 | if (divider->flags & CLK_DIVIDER_ONE_BASED) |
| @@ -162,6 +173,24 @@ static int _round_up_table(const struct clk_div_table *table, int div) | |||
| 162 | return up; | 173 | return up; |
| 163 | } | 174 | } |
| 164 | 175 | ||
| 176 | static int _round_down_table(const struct clk_div_table *table, int div) | ||
| 177 | { | ||
| 178 | const struct clk_div_table *clkt; | ||
| 179 | int down = _get_table_mindiv(table); | ||
| 180 | |||
| 181 | for (clkt = table; clkt->div; clkt++) { | ||
| 182 | if (clkt->div == div) | ||
| 183 | return clkt->div; | ||
| 184 | else if (clkt->div > div) | ||
| 185 | continue; | ||
| 186 | |||
| 187 | if ((div - clkt->div) < (div - down)) | ||
| 188 | down = clkt->div; | ||
| 189 | } | ||
| 190 | |||
| 191 | return down; | ||
| 192 | } | ||
| 193 | |||
| 165 | static int _div_round_up(struct clk_divider *divider, | 194 | static int _div_round_up(struct clk_divider *divider, |
| 166 | unsigned long parent_rate, unsigned long rate) | 195 | unsigned long parent_rate, unsigned long rate) |
| 167 | { | 196 | { |
| @@ -175,6 +204,54 @@ static int _div_round_up(struct clk_divider *divider, | |||
| 175 | return div; | 204 | return div; |
| 176 | } | 205 | } |
| 177 | 206 | ||
| 207 | static int _div_round_closest(struct clk_divider *divider, | ||
| 208 | unsigned long parent_rate, unsigned long rate) | ||
| 209 | { | ||
| 210 | int up, down, div; | ||
| 211 | |||
| 212 | up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate); | ||
| 213 | |||
| 214 | if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) { | ||
| 215 | up = __roundup_pow_of_two(div); | ||
| 216 | down = __rounddown_pow_of_two(div); | ||
| 217 | } else if (divider->table) { | ||
| 218 | up = _round_up_table(divider->table, div); | ||
| 219 | down = _round_down_table(divider->table, div); | ||
| 220 | } | ||
| 221 | |||
| 222 | return (up - div) <= (div - down) ? up : down; | ||
| 223 | } | ||
| 224 | |||
| 225 | static int _div_round(struct clk_divider *divider, unsigned long parent_rate, | ||
| 226 | unsigned long rate) | ||
| 227 | { | ||
| 228 | if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST) | ||
| 229 | return _div_round_closest(divider, parent_rate, rate); | ||
| 230 | |||
| 231 | return _div_round_up(divider, parent_rate, rate); | ||
| 232 | } | ||
| 233 | |||
| 234 | static bool _is_best_div(struct clk_divider *divider, | ||
| 235 | unsigned long rate, unsigned long now, unsigned long best) | ||
| 236 | { | ||
| 237 | if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST) | ||
| 238 | return abs(rate - now) < abs(rate - best); | ||
| 239 | |||
| 240 | return now <= rate && now > best; | ||
| 241 | } | ||
| 242 | |||
| 243 | static int _next_div(struct clk_divider *divider, int div) | ||
| 244 | { | ||
| 245 | div++; | ||
| 246 | |||
| 247 | if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) | ||
| 248 | return __roundup_pow_of_two(div); | ||
| 249 | if (divider->table) | ||
| 250 | return _round_up_table(divider->table, div); | ||
| 251 | |||
| 252 | return div; | ||
| 253 | } | ||
| 254 | |||
| 178 | static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, | 255 | static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, |
| 179 | unsigned long *best_parent_rate) | 256 | unsigned long *best_parent_rate) |
| 180 | { | 257 | { |
| @@ -190,7 +267,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, | |||
| 190 | 267 | ||
| 191 | if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { | 268 | if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { |
| 192 | parent_rate = *best_parent_rate; | 269 | parent_rate = *best_parent_rate; |
| 193 | bestdiv = _div_round_up(divider, parent_rate, rate); | 270 | bestdiv = _div_round(divider, parent_rate, rate); |
| 194 | bestdiv = bestdiv == 0 ? 1 : bestdiv; | 271 | bestdiv = bestdiv == 0 ? 1 : bestdiv; |
| 195 | bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; | 272 | bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; |
| 196 | return bestdiv; | 273 | return bestdiv; |
| @@ -202,7 +279,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, | |||
| 202 | */ | 279 | */ |
| 203 | maxdiv = min(ULONG_MAX / rate, maxdiv); | 280 | maxdiv = min(ULONG_MAX / rate, maxdiv); |
| 204 | 281 | ||
| 205 | for (i = 1; i <= maxdiv; i++) { | 282 | for (i = 1; i <= maxdiv; i = _next_div(divider, i)) { |
| 206 | if (!_is_valid_div(divider, i)) | 283 | if (!_is_valid_div(divider, i)) |
| 207 | continue; | 284 | continue; |
| 208 | if (rate * i == parent_rate_saved) { | 285 | if (rate * i == parent_rate_saved) { |
| @@ -217,7 +294,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, | |||
| 217 | parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), | 294 | parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), |
| 218 | MULT_ROUND_UP(rate, i)); | 295 | MULT_ROUND_UP(rate, i)); |
| 219 | now = DIV_ROUND_UP(parent_rate, i); | 296 | now = DIV_ROUND_UP(parent_rate, i); |
| 220 | if (now <= rate && now > best) { | 297 | if (_is_best_div(divider, rate, now, best)) { |
| 221 | bestdiv = i; | 298 | bestdiv = i; |
| 222 | best = now; | 299 | best = now; |
| 223 | *best_parent_rate = parent_rate; | 300 | *best_parent_rate = parent_rate; |
| @@ -284,6 +361,11 @@ const struct clk_ops clk_divider_ops = { | |||
| 284 | }; | 361 | }; |
| 285 | EXPORT_SYMBOL_GPL(clk_divider_ops); | 362 | EXPORT_SYMBOL_GPL(clk_divider_ops); |
| 286 | 363 | ||
| 364 | const struct clk_ops clk_divider_ro_ops = { | ||
| 365 | .recalc_rate = clk_divider_recalc_rate, | ||
| 366 | }; | ||
| 367 | EXPORT_SYMBOL_GPL(clk_divider_ro_ops); | ||
| 368 | |||
| 287 | static struct clk *_register_divider(struct device *dev, const char *name, | 369 | static struct clk *_register_divider(struct device *dev, const char *name, |
| 288 | const char *parent_name, unsigned long flags, | 370 | const char *parent_name, unsigned long flags, |
| 289 | void __iomem *reg, u8 shift, u8 width, | 371 | void __iomem *reg, u8 shift, u8 width, |
| @@ -309,7 +391,10 @@ static struct clk *_register_divider(struct device *dev, const char *name, | |||
| 309 | } | 391 | } |
| 310 | 392 | ||
| 311 | init.name = name; | 393 | init.name = name; |
| 312 | init.ops = &clk_divider_ops; | 394 | if (clk_divider_flags & CLK_DIVIDER_READ_ONLY) |
| 395 | init.ops = &clk_divider_ro_ops; | ||
| 396 | else | ||
| 397 | init.ops = &clk_divider_ops; | ||
| 313 | init.flags = flags | CLK_IS_BASIC; | 398 | init.flags = flags | CLK_IS_BASIC; |
| 314 | init.parent_names = (parent_name ? &parent_name: NULL); | 399 | init.parent_names = (parent_name ? &parent_name: NULL); |
| 315 | init.num_parents = (parent_name ? 1 : 0); | 400 | init.num_parents = (parent_name ? 1 : 0); |
diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c index f2f62a1bf61a..9b7b5859a420 100644 --- a/drivers/clk/clk-s2mps11.c +++ b/drivers/clk/clk-s2mps11.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * clk-s2mps11.c - Clock driver for S2MPS11. | 2 | * clk-s2mps11.c - Clock driver for S2MPS11. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2013 Samsung Electornics | 4 | * Copyright (C) 2013,2014 Samsung Electornics |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
| 7 | * under the terms of the GNU General Public License as published by the | 7 | * under the terms of the GNU General Public License as published by the |
| @@ -13,10 +13,6 @@ | |||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. |
| 15 | * | 15 | * |
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | * | ||
| 20 | */ | 16 | */ |
| 21 | 17 | ||
| 22 | #include <linux/module.h> | 18 | #include <linux/module.h> |
| @@ -27,6 +23,7 @@ | |||
| 27 | #include <linux/clk-provider.h> | 23 | #include <linux/clk-provider.h> |
| 28 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
| 29 | #include <linux/mfd/samsung/s2mps11.h> | 25 | #include <linux/mfd/samsung/s2mps11.h> |
| 26 | #include <linux/mfd/samsung/s2mps14.h> | ||
| 30 | #include <linux/mfd/samsung/s5m8767.h> | 27 | #include <linux/mfd/samsung/s5m8767.h> |
| 31 | #include <linux/mfd/samsung/core.h> | 28 | #include <linux/mfd/samsung/core.h> |
| 32 | 29 | ||
| @@ -44,6 +41,7 @@ enum { | |||
| 44 | 41 | ||
| 45 | struct s2mps11_clk { | 42 | struct s2mps11_clk { |
| 46 | struct sec_pmic_dev *iodev; | 43 | struct sec_pmic_dev *iodev; |
| 44 | struct device_node *clk_np; | ||
| 47 | struct clk_hw hw; | 45 | struct clk_hw hw; |
| 48 | struct clk *clk; | 46 | struct clk *clk; |
| 49 | struct clk_lookup *lookup; | 47 | struct clk_lookup *lookup; |
| @@ -125,7 +123,21 @@ static struct clk_init_data s2mps11_clks_init[S2MPS11_CLKS_NUM] = { | |||
| 125 | }, | 123 | }, |
| 126 | }; | 124 | }; |
| 127 | 125 | ||
| 128 | static struct device_node *s2mps11_clk_parse_dt(struct platform_device *pdev) | 126 | static struct clk_init_data s2mps14_clks_init[S2MPS11_CLKS_NUM] = { |
| 127 | [S2MPS11_CLK_AP] = { | ||
| 128 | .name = "s2mps14_ap", | ||
| 129 | .ops = &s2mps11_clk_ops, | ||
| 130 | .flags = CLK_IS_ROOT, | ||
| 131 | }, | ||
| 132 | [S2MPS11_CLK_BT] = { | ||
| 133 | .name = "s2mps14_bt", | ||
| 134 | .ops = &s2mps11_clk_ops, | ||
| 135 | .flags = CLK_IS_ROOT, | ||
| 136 | }, | ||
| 137 | }; | ||
| 138 | |||
| 139 | static struct device_node *s2mps11_clk_parse_dt(struct platform_device *pdev, | ||
| 140 | struct clk_init_data *clks_init) | ||
| 129 | { | 141 | { |
| 130 | struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); | 142 | struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); |
| 131 | struct device_node *clk_np; | 143 | struct device_node *clk_np; |
| @@ -140,14 +152,12 @@ static struct device_node *s2mps11_clk_parse_dt(struct platform_device *pdev) | |||
| 140 | return ERR_PTR(-EINVAL); | 152 | return ERR_PTR(-EINVAL); |
| 141 | } | 153 | } |
| 142 | 154 | ||
| 143 | clk_table = devm_kzalloc(&pdev->dev, sizeof(struct clk *) * | 155 | for (i = 0; i < S2MPS11_CLKS_NUM; i++) { |
| 144 | S2MPS11_CLKS_NUM, GFP_KERNEL); | 156 | if (!clks_init[i].name) |
| 145 | if (!clk_table) | 157 | continue; /* Skip clocks not present in some devices */ |
| 146 | return ERR_PTR(-ENOMEM); | ||
| 147 | |||
| 148 | for (i = 0; i < S2MPS11_CLKS_NUM; i++) | ||
| 149 | of_property_read_string_index(clk_np, "clock-output-names", i, | 158 | of_property_read_string_index(clk_np, "clock-output-names", i, |
| 150 | &s2mps11_clks_init[i].name); | 159 | &clks_init[i].name); |
| 160 | } | ||
| 151 | 161 | ||
| 152 | return clk_np; | 162 | return clk_np; |
| 153 | } | 163 | } |
| @@ -156,8 +166,8 @@ static int s2mps11_clk_probe(struct platform_device *pdev) | |||
| 156 | { | 166 | { |
| 157 | struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); | 167 | struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); |
| 158 | struct s2mps11_clk *s2mps11_clks, *s2mps11_clk; | 168 | struct s2mps11_clk *s2mps11_clks, *s2mps11_clk; |
| 159 | struct device_node *clk_np = NULL; | ||
| 160 | unsigned int s2mps11_reg; | 169 | unsigned int s2mps11_reg; |
| 170 | struct clk_init_data *clks_init; | ||
| 161 | int i, ret = 0; | 171 | int i, ret = 0; |
| 162 | u32 val; | 172 | u32 val; |
| 163 | 173 | ||
| @@ -168,25 +178,39 @@ static int s2mps11_clk_probe(struct platform_device *pdev) | |||
| 168 | 178 | ||
| 169 | s2mps11_clk = s2mps11_clks; | 179 | s2mps11_clk = s2mps11_clks; |
| 170 | 180 | ||
| 171 | clk_np = s2mps11_clk_parse_dt(pdev); | 181 | clk_table = devm_kzalloc(&pdev->dev, sizeof(struct clk *) * |
| 172 | if (IS_ERR(clk_np)) | 182 | S2MPS11_CLKS_NUM, GFP_KERNEL); |
| 173 | return PTR_ERR(clk_np); | 183 | if (!clk_table) |
| 184 | return -ENOMEM; | ||
| 174 | 185 | ||
| 175 | switch(platform_get_device_id(pdev)->driver_data) { | 186 | switch(platform_get_device_id(pdev)->driver_data) { |
| 176 | case S2MPS11X: | 187 | case S2MPS11X: |
| 177 | s2mps11_reg = S2MPS11_REG_RTC_CTRL; | 188 | s2mps11_reg = S2MPS11_REG_RTC_CTRL; |
| 189 | clks_init = s2mps11_clks_init; | ||
| 190 | break; | ||
| 191 | case S2MPS14X: | ||
| 192 | s2mps11_reg = S2MPS14_REG_RTCCTRL; | ||
| 193 | clks_init = s2mps14_clks_init; | ||
| 178 | break; | 194 | break; |
| 179 | case S5M8767X: | 195 | case S5M8767X: |
| 180 | s2mps11_reg = S5M8767_REG_CTRL1; | 196 | s2mps11_reg = S5M8767_REG_CTRL1; |
| 197 | clks_init = s2mps11_clks_init; | ||
| 181 | break; | 198 | break; |
| 182 | default: | 199 | default: |
| 183 | dev_err(&pdev->dev, "Invalid device type\n"); | 200 | dev_err(&pdev->dev, "Invalid device type\n"); |
| 184 | return -EINVAL; | 201 | return -EINVAL; |
| 185 | }; | 202 | }; |
| 186 | 203 | ||
| 204 | /* Store clocks of_node in first element of s2mps11_clks array */ | ||
| 205 | s2mps11_clks->clk_np = s2mps11_clk_parse_dt(pdev, clks_init); | ||
| 206 | if (IS_ERR(s2mps11_clks->clk_np)) | ||
| 207 | return PTR_ERR(s2mps11_clks->clk_np); | ||
| 208 | |||
| 187 | for (i = 0; i < S2MPS11_CLKS_NUM; i++, s2mps11_clk++) { | 209 | for (i = 0; i < S2MPS11_CLKS_NUM; i++, s2mps11_clk++) { |
| 210 | if (!clks_init[i].name) | ||
| 211 | continue; /* Skip clocks not present in some devices */ | ||
| 188 | s2mps11_clk->iodev = iodev; | 212 | s2mps11_clk->iodev = iodev; |
| 189 | s2mps11_clk->hw.init = &s2mps11_clks_init[i]; | 213 | s2mps11_clk->hw.init = &clks_init[i]; |
| 190 | s2mps11_clk->mask = 1 << i; | 214 | s2mps11_clk->mask = 1 << i; |
| 191 | s2mps11_clk->reg = s2mps11_reg; | 215 | s2mps11_clk->reg = s2mps11_reg; |
| 192 | 216 | ||
| @@ -219,15 +243,18 @@ static int s2mps11_clk_probe(struct platform_device *pdev) | |||
| 219 | clkdev_add(s2mps11_clk->lookup); | 243 | clkdev_add(s2mps11_clk->lookup); |
| 220 | } | 244 | } |
| 221 | 245 | ||
| 222 | if (clk_table) { | 246 | for (i = 0; i < S2MPS11_CLKS_NUM; i++) { |
| 223 | for (i = 0; i < S2MPS11_CLKS_NUM; i++) | 247 | /* Skip clocks not present on S2MPS14 */ |
| 224 | clk_table[i] = s2mps11_clks[i].clk; | 248 | if (!clks_init[i].name) |
| 225 | 249 | continue; | |
| 226 | clk_data.clks = clk_table; | 250 | clk_table[i] = s2mps11_clks[i].clk; |
| 227 | clk_data.clk_num = S2MPS11_CLKS_NUM; | ||
| 228 | of_clk_add_provider(clk_np, of_clk_src_onecell_get, &clk_data); | ||
| 229 | } | 251 | } |
| 230 | 252 | ||
| 253 | clk_data.clks = clk_table; | ||
| 254 | clk_data.clk_num = S2MPS11_CLKS_NUM; | ||
| 255 | of_clk_add_provider(s2mps11_clks->clk_np, of_clk_src_onecell_get, | ||
| 256 | &clk_data); | ||
| 257 | |||
| 231 | platform_set_drvdata(pdev, s2mps11_clks); | 258 | platform_set_drvdata(pdev, s2mps11_clks); |
| 232 | 259 | ||
| 233 | return ret; | 260 | return ret; |
| @@ -250,14 +277,23 @@ static int s2mps11_clk_remove(struct platform_device *pdev) | |||
| 250 | struct s2mps11_clk *s2mps11_clks = platform_get_drvdata(pdev); | 277 | struct s2mps11_clk *s2mps11_clks = platform_get_drvdata(pdev); |
| 251 | int i; | 278 | int i; |
| 252 | 279 | ||
| 253 | for (i = 0; i < S2MPS11_CLKS_NUM; i++) | 280 | of_clk_del_provider(s2mps11_clks[0].clk_np); |
| 281 | /* Drop the reference obtained in s2mps11_clk_parse_dt */ | ||
| 282 | of_node_put(s2mps11_clks[0].clk_np); | ||
| 283 | |||
| 284 | for (i = 0; i < S2MPS11_CLKS_NUM; i++) { | ||
| 285 | /* Skip clocks not present on S2MPS14 */ | ||
| 286 | if (!s2mps11_clks[i].lookup) | ||
| 287 | continue; | ||
| 254 | clkdev_drop(s2mps11_clks[i].lookup); | 288 | clkdev_drop(s2mps11_clks[i].lookup); |
| 289 | } | ||
| 255 | 290 | ||
| 256 | return 0; | 291 | return 0; |
| 257 | } | 292 | } |
| 258 | 293 | ||
| 259 | static const struct platform_device_id s2mps11_clk_id[] = { | 294 | static const struct platform_device_id s2mps11_clk_id[] = { |
| 260 | { "s2mps11-clk", S2MPS11X}, | 295 | { "s2mps11-clk", S2MPS11X}, |
| 296 | { "s2mps14-clk", S2MPS14X}, | ||
| 261 | { "s5m8767-clk", S5M8767X}, | 297 | { "s5m8767-clk", S5M8767X}, |
| 262 | { }, | 298 | { }, |
| 263 | }; | 299 | }; |
diff --git a/drivers/clk/clk-si570.c b/drivers/clk/clk-si570.c index 4bbbe32585ec..fc167b3f8919 100644 --- a/drivers/clk/clk-si570.c +++ b/drivers/clk/clk-si570.c | |||
| @@ -526,6 +526,6 @@ static struct i2c_driver si570_driver = { | |||
| 526 | module_i2c_driver(si570_driver); | 526 | module_i2c_driver(si570_driver); |
| 527 | 527 | ||
| 528 | MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>"); | 528 | MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>"); |
| 529 | MODULE_AUTHOR("Soeren Brinkmann <soren.brinkmann@xilinx.com"); | 529 | MODULE_AUTHOR("Soeren Brinkmann <soren.brinkmann@xilinx.com>"); |
| 530 | MODULE_DESCRIPTION("Si570 driver"); | 530 | MODULE_DESCRIPTION("Si570 driver"); |
| 531 | MODULE_LICENSE("GPL"); | 531 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/clk/clk-u300.c b/drivers/clk/clk-u300.c index 3efbdd078d14..406bfc1375b2 100644 --- a/drivers/clk/clk-u300.c +++ b/drivers/clk/clk-u300.c | |||
| @@ -1168,6 +1168,7 @@ static const struct of_device_id u300_clk_match[] __initconst = { | |||
| 1168 | .compatible = "stericsson,u300-syscon-mclk", | 1168 | .compatible = "stericsson,u300-syscon-mclk", |
| 1169 | .data = of_u300_syscon_mclk_init, | 1169 | .data = of_u300_syscon_mclk_init, |
| 1170 | }, | 1170 | }, |
| 1171 | {} | ||
| 1171 | }; | 1172 | }; |
| 1172 | 1173 | ||
| 1173 | 1174 | ||
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 7cf2c093cc54..8b73edef151d 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c | |||
| @@ -106,12 +106,11 @@ static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level) | |||
| 106 | if (!c) | 106 | if (!c) |
| 107 | return; | 107 | return; |
| 108 | 108 | ||
| 109 | seq_printf(s, "%*s%-*s %-11d %-12d %-10lu %-11lu", | 109 | seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu\n", |
| 110 | level * 3 + 1, "", | 110 | level * 3 + 1, "", |
| 111 | 30 - level * 3, c->name, | 111 | 30 - level * 3, c->name, |
| 112 | c->enable_count, c->prepare_count, clk_get_rate(c), | 112 | c->enable_count, c->prepare_count, clk_get_rate(c), |
| 113 | clk_get_accuracy(c)); | 113 | clk_get_accuracy(c)); |
| 114 | seq_printf(s, "\n"); | ||
| 115 | } | 114 | } |
| 116 | 115 | ||
| 117 | static void clk_summary_show_subtree(struct seq_file *s, struct clk *c, | 116 | static void clk_summary_show_subtree(struct seq_file *s, struct clk *c, |
| @@ -132,8 +131,8 @@ static int clk_summary_show(struct seq_file *s, void *data) | |||
| 132 | { | 131 | { |
| 133 | struct clk *c; | 132 | struct clk *c; |
| 134 | 133 | ||
| 135 | seq_printf(s, " clock enable_cnt prepare_cnt rate accuracy\n"); | 134 | seq_puts(s, " clock enable_cnt prepare_cnt rate accuracy\n"); |
| 136 | seq_printf(s, "---------------------------------------------------------------------------------\n"); | 135 | seq_puts(s, "--------------------------------------------------------------------------------\n"); |
| 137 | 136 | ||
| 138 | clk_prepare_lock(); | 137 | clk_prepare_lock(); |
| 139 | 138 | ||
| @@ -822,6 +821,9 @@ void __clk_unprepare(struct clk *clk) | |||
| 822 | */ | 821 | */ |
| 823 | void clk_unprepare(struct clk *clk) | 822 | void clk_unprepare(struct clk *clk) |
| 824 | { | 823 | { |
| 824 | if (IS_ERR_OR_NULL(clk)) | ||
| 825 | return; | ||
| 826 | |||
| 825 | clk_prepare_lock(); | 827 | clk_prepare_lock(); |
| 826 | __clk_unprepare(clk); | 828 | __clk_unprepare(clk); |
| 827 | clk_prepare_unlock(); | 829 | clk_prepare_unlock(); |
| @@ -883,9 +885,6 @@ static void __clk_disable(struct clk *clk) | |||
| 883 | if (!clk) | 885 | if (!clk) |
| 884 | return; | 886 | return; |
| 885 | 887 | ||
| 886 | if (WARN_ON(IS_ERR(clk))) | ||
| 887 | return; | ||
| 888 | |||
| 889 | if (WARN_ON(clk->enable_count == 0)) | 888 | if (WARN_ON(clk->enable_count == 0)) |
| 890 | return; | 889 | return; |
| 891 | 890 | ||
| @@ -914,6 +913,9 @@ void clk_disable(struct clk *clk) | |||
| 914 | { | 913 | { |
| 915 | unsigned long flags; | 914 | unsigned long flags; |
| 916 | 915 | ||
| 916 | if (IS_ERR_OR_NULL(clk)) | ||
| 917 | return; | ||
| 918 | |||
| 917 | flags = clk_enable_lock(); | 919 | flags = clk_enable_lock(); |
| 918 | __clk_disable(clk); | 920 | __clk_disable(clk); |
| 919 | clk_enable_unlock(flags); | 921 | clk_enable_unlock(flags); |
| @@ -1004,6 +1006,7 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) | |||
| 1004 | else | 1006 | else |
| 1005 | return clk->rate; | 1007 | return clk->rate; |
| 1006 | } | 1008 | } |
| 1009 | EXPORT_SYMBOL_GPL(__clk_round_rate); | ||
| 1007 | 1010 | ||
| 1008 | /** | 1011 | /** |
| 1009 | * clk_round_rate - round the given rate for a clk | 1012 | * clk_round_rate - round the given rate for a clk |
| @@ -1115,6 +1118,13 @@ long clk_get_accuracy(struct clk *clk) | |||
| 1115 | } | 1118 | } |
| 1116 | EXPORT_SYMBOL_GPL(clk_get_accuracy); | 1119 | EXPORT_SYMBOL_GPL(clk_get_accuracy); |
| 1117 | 1120 | ||
| 1121 | static unsigned long clk_recalc(struct clk *clk, unsigned long parent_rate) | ||
| 1122 | { | ||
| 1123 | if (clk->ops->recalc_rate) | ||
| 1124 | return clk->ops->recalc_rate(clk->hw, parent_rate); | ||
| 1125 | return parent_rate; | ||
| 1126 | } | ||
| 1127 | |||
| 1118 | /** | 1128 | /** |
| 1119 | * __clk_recalc_rates | 1129 | * __clk_recalc_rates |
| 1120 | * @clk: first clk in the subtree | 1130 | * @clk: first clk in the subtree |
| @@ -1140,10 +1150,7 @@ static void __clk_recalc_rates(struct clk *clk, unsigned long msg) | |||
| 1140 | if (clk->parent) | 1150 | if (clk->parent) |
| 1141 | parent_rate = clk->parent->rate; | 1151 | parent_rate = clk->parent->rate; |
| 1142 | 1152 | ||
| 1143 | if (clk->ops->recalc_rate) | 1153 | clk->rate = clk_recalc(clk, parent_rate); |
| 1144 | clk->rate = clk->ops->recalc_rate(clk->hw, parent_rate); | ||
| 1145 | else | ||
| 1146 | clk->rate = parent_rate; | ||
| 1147 | 1154 | ||
| 1148 | /* | 1155 | /* |
| 1149 | * ignore NOTIFY_STOP and NOTIFY_BAD return values for POST_RATE_CHANGE | 1156 | * ignore NOTIFY_STOP and NOTIFY_BAD return values for POST_RATE_CHANGE |
| @@ -1334,10 +1341,7 @@ static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate) | |||
| 1334 | unsigned long new_rate; | 1341 | unsigned long new_rate; |
| 1335 | int ret = NOTIFY_DONE; | 1342 | int ret = NOTIFY_DONE; |
| 1336 | 1343 | ||
| 1337 | if (clk->ops->recalc_rate) | 1344 | new_rate = clk_recalc(clk, parent_rate); |
| 1338 | new_rate = clk->ops->recalc_rate(clk->hw, parent_rate); | ||
| 1339 | else | ||
| 1340 | new_rate = parent_rate; | ||
| 1341 | 1345 | ||
| 1342 | /* abort rate change if a driver returns NOTIFY_BAD or NOTIFY_STOP */ | 1346 | /* abort rate change if a driver returns NOTIFY_BAD or NOTIFY_STOP */ |
| 1343 | if (clk->notifier_count) | 1347 | if (clk->notifier_count) |
| @@ -1373,10 +1377,7 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate, | |||
| 1373 | new_parent->new_child = clk; | 1377 | new_parent->new_child = clk; |
| 1374 | 1378 | ||
| 1375 | hlist_for_each_entry(child, &clk->children, child_node) { | 1379 | hlist_for_each_entry(child, &clk->children, child_node) { |
| 1376 | if (child->ops->recalc_rate) | 1380 | child->new_rate = clk_recalc(child, new_rate); |
| 1377 | child->new_rate = child->ops->recalc_rate(child->hw, new_rate); | ||
| 1378 | else | ||
| 1379 | child->new_rate = new_rate; | ||
| 1380 | clk_calc_subtree(child, child->new_rate, NULL, 0); | 1381 | clk_calc_subtree(child, child->new_rate, NULL, 0); |
| 1381 | } | 1382 | } |
| 1382 | } | 1383 | } |
| @@ -1524,10 +1525,7 @@ static void clk_change_rate(struct clk *clk) | |||
| 1524 | if (!skip_set_rate && clk->ops->set_rate) | 1525 | if (!skip_set_rate && clk->ops->set_rate) |
| 1525 | clk->ops->set_rate(clk->hw, clk->new_rate, best_parent_rate); | 1526 | clk->ops->set_rate(clk->hw, clk->new_rate, best_parent_rate); |
| 1526 | 1527 | ||
| 1527 | if (clk->ops->recalc_rate) | 1528 | clk->rate = clk_recalc(clk, best_parent_rate); |
| 1528 | clk->rate = clk->ops->recalc_rate(clk->hw, best_parent_rate); | ||
| 1529 | else | ||
| 1530 | clk->rate = best_parent_rate; | ||
| 1531 | 1529 | ||
| 1532 | if (clk->notifier_count && old_rate != clk->rate) | 1530 | if (clk->notifier_count && old_rate != clk->rate) |
| 1533 | __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate); | 1531 | __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate); |
| @@ -1716,9 +1714,6 @@ int clk_set_parent(struct clk *clk, struct clk *parent) | |||
| 1716 | if (!clk) | 1714 | if (!clk) |
| 1717 | return 0; | 1715 | return 0; |
| 1718 | 1716 | ||
| 1719 | if (!clk->ops) | ||
| 1720 | return -EINVAL; | ||
| 1721 | |||
| 1722 | /* verify ops for for multi-parent clks */ | 1717 | /* verify ops for for multi-parent clks */ |
| 1723 | if ((clk->num_parents > 1) && (!clk->ops->set_parent)) | 1718 | if ((clk->num_parents > 1) && (!clk->ops->set_parent)) |
| 1724 | return -ENOSYS; | 1719 | return -ENOSYS; |
diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h index 795cc9f0dac0..c798138f023f 100644 --- a/drivers/clk/clk.h +++ b/drivers/clk/clk.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) | 12 | #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) |
| 13 | struct clk *of_clk_get_by_clkspec(struct of_phandle_args *clkspec); | ||
| 13 | struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec); | 14 | struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec); |
| 14 | void of_clk_lock(void); | 15 | void of_clk_lock(void); |
| 15 | void of_clk_unlock(void); | 16 | void of_clk_unlock(void); |
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index a360b2eca5cb..f890b901c6bc 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c | |||
| @@ -27,6 +27,32 @@ static LIST_HEAD(clocks); | |||
| 27 | static DEFINE_MUTEX(clocks_mutex); | 27 | static DEFINE_MUTEX(clocks_mutex); |
| 28 | 28 | ||
| 29 | #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) | 29 | #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) |
| 30 | |||
| 31 | /** | ||
| 32 | * of_clk_get_by_clkspec() - Lookup a clock form a clock provider | ||
| 33 | * @clkspec: pointer to a clock specifier data structure | ||
| 34 | * | ||
| 35 | * This function looks up a struct clk from the registered list of clock | ||
| 36 | * providers, an input is a clock specifier data structure as returned | ||
| 37 | * from the of_parse_phandle_with_args() function call. | ||
| 38 | */ | ||
| 39 | struct clk *of_clk_get_by_clkspec(struct of_phandle_args *clkspec) | ||
| 40 | { | ||
| 41 | struct clk *clk; | ||
| 42 | |||
| 43 | if (!clkspec) | ||
| 44 | return ERR_PTR(-EINVAL); | ||
| 45 | |||
| 46 | of_clk_lock(); | ||
| 47 | clk = __of_clk_get_from_provider(clkspec); | ||
| 48 | |||
| 49 | if (!IS_ERR(clk) && !__clk_get(clk)) | ||
| 50 | clk = ERR_PTR(-ENOENT); | ||
| 51 | |||
| 52 | of_clk_unlock(); | ||
| 53 | return clk; | ||
| 54 | } | ||
| 55 | |||
| 30 | struct clk *of_clk_get(struct device_node *np, int index) | 56 | struct clk *of_clk_get(struct device_node *np, int index) |
| 31 | { | 57 | { |
| 32 | struct of_phandle_args clkspec; | 58 | struct of_phandle_args clkspec; |
| @@ -41,13 +67,7 @@ struct clk *of_clk_get(struct device_node *np, int index) | |||
| 41 | if (rc) | 67 | if (rc) |
| 42 | return ERR_PTR(rc); | 68 | return ERR_PTR(rc); |
| 43 | 69 | ||
| 44 | of_clk_lock(); | 70 | clk = of_clk_get_by_clkspec(&clkspec); |
| 45 | clk = __of_clk_get_from_provider(&clkspec); | ||
| 46 | |||
| 47 | if (!IS_ERR(clk) && !__clk_get(clk)) | ||
| 48 | clk = ERR_PTR(-ENOENT); | ||
| 49 | |||
| 50 | of_clk_unlock(); | ||
| 51 | of_node_put(clkspec.np); | 71 | of_node_put(clkspec.np); |
| 52 | return clk; | 72 | return clk; |
| 53 | } | 73 | } |
diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile index 40b33c6a8257..038c02f4d0e7 100644 --- a/drivers/clk/hisilicon/Makefile +++ b/drivers/clk/hisilicon/Makefile | |||
| @@ -6,3 +6,4 @@ obj-y += clk.o clkgate-separated.o | |||
| 6 | 6 | ||
| 7 | obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o | 7 | obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o |
| 8 | obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o | 8 | obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o |
| 9 | 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 000000000000..e5fcfb4e32ef --- /dev/null +++ b/drivers/clk/hisilicon/clk-hix5hd2.c | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014 Linaro Ltd. | ||
| 3 | * Copyright (c) 2014 Hisilicon Limited. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms and conditions of the GNU General Public License, | ||
| 7 | * version 2, as published by the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/of_address.h> | ||
| 11 | #include <dt-bindings/clock/hix5hd2-clock.h> | ||
| 12 | #include "clk.h" | ||
| 13 | |||
| 14 | static struct hisi_fixed_rate_clock hix5hd2_fixed_rate_clks[] __initdata = { | ||
| 15 | { HIX5HD2_FIXED_1200M, "1200m", NULL, CLK_IS_ROOT, 1200000000, }, | ||
| 16 | { HIX5HD2_FIXED_400M, "400m", NULL, CLK_IS_ROOT, 400000000, }, | ||
| 17 | { HIX5HD2_FIXED_48M, "48m", NULL, CLK_IS_ROOT, 48000000, }, | ||
| 18 | { HIX5HD2_FIXED_24M, "24m", NULL, CLK_IS_ROOT, 24000000, }, | ||
| 19 | { HIX5HD2_FIXED_600M, "600m", NULL, CLK_IS_ROOT, 600000000, }, | ||
| 20 | { HIX5HD2_FIXED_300M, "300m", NULL, CLK_IS_ROOT, 300000000, }, | ||
| 21 | { HIX5HD2_FIXED_75M, "75m", NULL, CLK_IS_ROOT, 75000000, }, | ||
| 22 | { HIX5HD2_FIXED_200M, "200m", NULL, CLK_IS_ROOT, 200000000, }, | ||
| 23 | { HIX5HD2_FIXED_100M, "100m", NULL, CLK_IS_ROOT, 100000000, }, | ||
| 24 | { HIX5HD2_FIXED_40M, "40m", NULL, CLK_IS_ROOT, 40000000, }, | ||
| 25 | { HIX5HD2_FIXED_150M, "150m", NULL, CLK_IS_ROOT, 150000000, }, | ||
| 26 | { HIX5HD2_FIXED_1728M, "1728m", NULL, CLK_IS_ROOT, 1728000000, }, | ||
| 27 | { HIX5HD2_FIXED_28P8M, "28p8m", NULL, CLK_IS_ROOT, 28000000, }, | ||
| 28 | { HIX5HD2_FIXED_432M, "432m", NULL, CLK_IS_ROOT, 432000000, }, | ||
| 29 | { HIX5HD2_FIXED_345P6M, "345p6m", NULL, CLK_IS_ROOT, 345000000, }, | ||
| 30 | { HIX5HD2_FIXED_288M, "288m", NULL, CLK_IS_ROOT, 288000000, }, | ||
| 31 | { HIX5HD2_FIXED_60M, "60m", NULL, CLK_IS_ROOT, 60000000, }, | ||
| 32 | { HIX5HD2_FIXED_750M, "750m", NULL, CLK_IS_ROOT, 750000000, }, | ||
| 33 | { HIX5HD2_FIXED_500M, "500m", NULL, CLK_IS_ROOT, 500000000, }, | ||
| 34 | { HIX5HD2_FIXED_54M, "54m", NULL, CLK_IS_ROOT, 54000000, }, | ||
| 35 | { HIX5HD2_FIXED_27M, "27m", NULL, CLK_IS_ROOT, 27000000, }, | ||
| 36 | { HIX5HD2_FIXED_1500M, "1500m", NULL, CLK_IS_ROOT, 1500000000, }, | ||
| 37 | { HIX5HD2_FIXED_375M, "375m", NULL, CLK_IS_ROOT, 375000000, }, | ||
| 38 | { HIX5HD2_FIXED_187M, "187m", NULL, CLK_IS_ROOT, 187000000, }, | ||
| 39 | { HIX5HD2_FIXED_250M, "250m", NULL, CLK_IS_ROOT, 250000000, }, | ||
| 40 | { HIX5HD2_FIXED_125M, "125m", NULL, CLK_IS_ROOT, 125000000, }, | ||
| 41 | { HIX5HD2_FIXED_2P02M, "2m", NULL, CLK_IS_ROOT, 2000000, }, | ||
| 42 | { HIX5HD2_FIXED_50M, "50m", NULL, CLK_IS_ROOT, 50000000, }, | ||
| 43 | { HIX5HD2_FIXED_25M, "25m", NULL, CLK_IS_ROOT, 25000000, }, | ||
| 44 | { HIX5HD2_FIXED_83M, "83m", NULL, CLK_IS_ROOT, 83333333, }, | ||
| 45 | }; | ||
| 46 | |||
| 47 | static const char *sfc_mux_p[] __initconst = { | ||
| 48 | "24m", "150m", "200m", "100m", "75m", }; | ||
| 49 | static u32 sfc_mux_table[] = {0, 4, 5, 6, 7}; | ||
| 50 | |||
| 51 | static const char *sdio1_mux_p[] __initconst = { | ||
| 52 | "75m", "100m", "50m", "15m", }; | ||
| 53 | static u32 sdio1_mux_table[] = {0, 1, 2, 3}; | ||
| 54 | |||
| 55 | static const char *fephy_mux_p[] __initconst = { "25m", "125m"}; | ||
| 56 | static u32 fephy_mux_table[] = {0, 1}; | ||
| 57 | |||
| 58 | |||
| 59 | static struct hisi_mux_clock hix5hd2_mux_clks[] __initdata = { | ||
| 60 | { HIX5HD2_SFC_MUX, "sfc_mux", sfc_mux_p, ARRAY_SIZE(sfc_mux_p), | ||
| 61 | CLK_SET_RATE_PARENT, 0x5c, 8, 3, 0, sfc_mux_table, }, | ||
| 62 | { HIX5HD2_MMC_MUX, "mmc_mux", sdio1_mux_p, ARRAY_SIZE(sdio1_mux_p), | ||
| 63 | CLK_SET_RATE_PARENT, 0xa0, 8, 2, 0, sdio1_mux_table, }, | ||
| 64 | { HIX5HD2_FEPHY_MUX, "fephy_mux", | ||
| 65 | fephy_mux_p, ARRAY_SIZE(fephy_mux_p), | ||
| 66 | CLK_SET_RATE_PARENT, 0x120, 8, 2, 0, fephy_mux_table, }, | ||
| 67 | }; | ||
| 68 | |||
| 69 | static struct hisi_gate_clock hix5hd2_gate_clks[] __initdata = { | ||
| 70 | /*sfc*/ | ||
| 71 | { HIX5HD2_SFC_CLK, "clk_sfc", "sfc_mux", | ||
| 72 | CLK_SET_RATE_PARENT, 0x5c, 0, 0, }, | ||
| 73 | { HIX5HD2_SFC_RST, "rst_sfc", "clk_sfc", | ||
| 74 | CLK_SET_RATE_PARENT, 0x5c, 4, CLK_GATE_SET_TO_DISABLE, }, | ||
| 75 | /*sdio1*/ | ||
| 76 | { HIX5HD2_MMC_BIU_CLK, "clk_mmc_biu", "200m", | ||
| 77 | CLK_SET_RATE_PARENT, 0xa0, 0, 0, }, | ||
| 78 | { HIX5HD2_MMC_CIU_CLK, "clk_mmc_ciu", "mmc_mux", | ||
| 79 | CLK_SET_RATE_PARENT, 0xa0, 1, 0, }, | ||
| 80 | { HIX5HD2_MMC_CIU_RST, "rst_mmc_ciu", "clk_mmc_ciu", | ||
| 81 | CLK_SET_RATE_PARENT, 0xa0, 4, CLK_GATE_SET_TO_DISABLE, }, | ||
| 82 | }; | ||
| 83 | |||
| 84 | static void __init hix5hd2_clk_init(struct device_node *np) | ||
| 85 | { | ||
| 86 | struct hisi_clock_data *clk_data; | ||
| 87 | |||
| 88 | clk_data = hisi_clk_init(np, HIX5HD2_NR_CLKS); | ||
| 89 | if (!clk_data) | ||
| 90 | return; | ||
| 91 | |||
| 92 | hisi_clk_register_fixed_rate(hix5hd2_fixed_rate_clks, | ||
| 93 | ARRAY_SIZE(hix5hd2_fixed_rate_clks), | ||
| 94 | clk_data); | ||
| 95 | hisi_clk_register_mux(hix5hd2_mux_clks, ARRAY_SIZE(hix5hd2_mux_clks), | ||
| 96 | clk_data); | ||
| 97 | hisi_clk_register_gate(hix5hd2_gate_clks, | ||
| 98 | ARRAY_SIZE(hix5hd2_gate_clks), clk_data); | ||
| 99 | } | ||
| 100 | |||
| 101 | 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 276f672e7b1a..a078e84f7b05 100644 --- a/drivers/clk/hisilicon/clk.c +++ b/drivers/clk/hisilicon/clk.c | |||
| @@ -127,11 +127,14 @@ void __init hisi_clk_register_mux(struct hisi_mux_clock *clks, | |||
| 127 | int i; | 127 | int i; |
| 128 | 128 | ||
| 129 | for (i = 0; i < nums; i++) { | 129 | for (i = 0; i < nums; i++) { |
| 130 | clk = clk_register_mux(NULL, clks[i].name, clks[i].parent_names, | 130 | u32 mask = BIT(clks[i].width) - 1; |
| 131 | clks[i].num_parents, clks[i].flags, | 131 | |
| 132 | base + clks[i].offset, clks[i].shift, | 132 | clk = clk_register_mux_table(NULL, clks[i].name, |
| 133 | clks[i].width, clks[i].mux_flags, | 133 | clks[i].parent_names, |
| 134 | &hisi_clk_lock); | 134 | clks[i].num_parents, clks[i].flags, |
| 135 | base + clks[i].offset, clks[i].shift, | ||
| 136 | mask, clks[i].mux_flags, | ||
| 137 | clks[i].table, &hisi_clk_lock); | ||
| 135 | if (IS_ERR(clk)) { | 138 | if (IS_ERR(clk)) { |
| 136 | pr_err("%s: failed to register clock %s\n", | 139 | pr_err("%s: failed to register clock %s\n", |
| 137 | __func__, clks[i].name); | 140 | __func__, clks[i].name); |
| @@ -174,6 +177,34 @@ void __init hisi_clk_register_divider(struct hisi_divider_clock *clks, | |||
| 174 | } | 177 | } |
| 175 | } | 178 | } |
| 176 | 179 | ||
| 180 | void __init hisi_clk_register_gate(struct hisi_gate_clock *clks, | ||
| 181 | int nums, struct hisi_clock_data *data) | ||
| 182 | { | ||
| 183 | struct clk *clk; | ||
| 184 | void __iomem *base = data->base; | ||
| 185 | int i; | ||
| 186 | |||
| 187 | for (i = 0; i < nums; i++) { | ||
| 188 | clk = clk_register_gate(NULL, clks[i].name, | ||
| 189 | clks[i].parent_name, | ||
| 190 | clks[i].flags, | ||
| 191 | base + clks[i].offset, | ||
| 192 | clks[i].bit_idx, | ||
| 193 | clks[i].gate_flags, | ||
| 194 | &hisi_clk_lock); | ||
| 195 | if (IS_ERR(clk)) { | ||
| 196 | pr_err("%s: failed to register clock %s\n", | ||
| 197 | __func__, clks[i].name); | ||
| 198 | continue; | ||
| 199 | } | ||
| 200 | |||
| 201 | if (clks[i].alias) | ||
| 202 | clk_register_clkdev(clk, clks[i].alias, NULL); | ||
| 203 | |||
| 204 | data->clk_data.clks[clks[i].id] = clk; | ||
| 205 | } | ||
| 206 | } | ||
| 207 | |||
| 177 | void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks, | 208 | void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks, |
| 178 | int nums, struct hisi_clock_data *data) | 209 | int nums, struct hisi_clock_data *data) |
| 179 | { | 210 | { |
diff --git a/drivers/clk/hisilicon/clk.h b/drivers/clk/hisilicon/clk.h index 43fa5da88f02..31083ffc0650 100644 --- a/drivers/clk/hisilicon/clk.h +++ b/drivers/clk/hisilicon/clk.h | |||
| @@ -62,6 +62,7 @@ struct hisi_mux_clock { | |||
| 62 | u8 shift; | 62 | u8 shift; |
| 63 | u8 width; | 63 | u8 width; |
| 64 | u8 mux_flags; | 64 | u8 mux_flags; |
| 65 | u32 *table; | ||
| 65 | const char *alias; | 66 | const char *alias; |
| 66 | }; | 67 | }; |
| 67 | 68 | ||
| @@ -103,6 +104,8 @@ void __init hisi_clk_register_mux(struct hisi_mux_clock *, int, | |||
| 103 | struct hisi_clock_data *); | 104 | struct hisi_clock_data *); |
| 104 | void __init hisi_clk_register_divider(struct hisi_divider_clock *, | 105 | void __init hisi_clk_register_divider(struct hisi_divider_clock *, |
| 105 | int, struct hisi_clock_data *); | 106 | int, struct hisi_clock_data *); |
| 107 | void __init hisi_clk_register_gate(struct hisi_gate_clock *, | ||
| 108 | int, struct hisi_clock_data *); | ||
| 106 | void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *, | 109 | void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *, |
| 107 | int, struct hisi_clock_data *); | 110 | int, struct hisi_clock_data *); |
| 108 | #endif /* __HISI_CLK_H */ | 111 | #endif /* __HISI_CLK_H */ |
diff --git a/drivers/clk/mvebu/Kconfig b/drivers/clk/mvebu/Kconfig index 693f7be129f1..3b34dba9178d 100644 --- a/drivers/clk/mvebu/Kconfig +++ b/drivers/clk/mvebu/Kconfig | |||
| @@ -34,3 +34,7 @@ config DOVE_CLK | |||
| 34 | config KIRKWOOD_CLK | 34 | config KIRKWOOD_CLK |
| 35 | bool | 35 | bool |
| 36 | select MVEBU_CLK_COMMON | 36 | select MVEBU_CLK_COMMON |
| 37 | |||
| 38 | config ORION_CLK | ||
| 39 | bool | ||
| 40 | select MVEBU_CLK_COMMON | ||
diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile index 4c66162fb0b4..a9a56fc01901 100644 --- a/drivers/clk/mvebu/Makefile +++ b/drivers/clk/mvebu/Makefile | |||
| @@ -8,3 +8,4 @@ obj-$(CONFIG_ARMADA_38X_CLK) += armada-38x.o | |||
| 8 | obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o | 8 | obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o |
| 9 | obj-$(CONFIG_DOVE_CLK) += dove.o | 9 | obj-$(CONFIG_DOVE_CLK) += dove.o |
| 10 | obj-$(CONFIG_KIRKWOOD_CLK) += kirkwood.o | 10 | obj-$(CONFIG_KIRKWOOD_CLK) += kirkwood.o |
| 11 | 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 000000000000..fd129566c1ce --- /dev/null +++ b/drivers/clk/mvebu/orion.c | |||
| @@ -0,0 +1,210 @@ | |||
| 1 | /* | ||
| 2 | * Marvell Orion SoC clocks | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Thomas Petazzoni | ||
| 5 | * | ||
| 6 | * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> | ||
| 7 | * | ||
| 8 | * This file is licensed under the terms of the GNU General Public | ||
| 9 | * License version 2. This program is licensed "as is" without any | ||
| 10 | * warranty of any kind, whether express or implied. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/clk-provider.h> | ||
| 15 | #include <linux/io.h> | ||
| 16 | #include <linux/of.h> | ||
| 17 | #include "common.h" | ||
| 18 | |||
| 19 | static const struct coreclk_ratio orion_coreclk_ratios[] __initconst = { | ||
| 20 | { .id = 0, .name = "ddrclk", } | ||
| 21 | }; | ||
| 22 | |||
| 23 | /* | ||
| 24 | * Orion 5182 | ||
| 25 | */ | ||
| 26 | |||
| 27 | #define SAR_MV88F5182_TCLK_FREQ 8 | ||
| 28 | #define SAR_MV88F5182_TCLK_FREQ_MASK 0x3 | ||
| 29 | |||
| 30 | static u32 __init mv88f5182_get_tclk_freq(void __iomem *sar) | ||
| 31 | { | ||
| 32 | u32 opt = (readl(sar) >> SAR_MV88F5182_TCLK_FREQ) & | ||
| 33 | SAR_MV88F5182_TCLK_FREQ_MASK; | ||
| 34 | if (opt == 1) | ||
| 35 | return 150000000; | ||
| 36 | else if (opt == 2) | ||
| 37 | return 166666667; | ||
| 38 | else | ||
| 39 | return 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | #define SAR_MV88F5182_CPU_FREQ 4 | ||
| 43 | #define SAR_MV88F5182_CPU_FREQ_MASK 0xf | ||
| 44 | |||
| 45 | static u32 __init mv88f5182_get_cpu_freq(void __iomem *sar) | ||
| 46 | { | ||
| 47 | u32 opt = (readl(sar) >> SAR_MV88F5182_CPU_FREQ) & | ||
| 48 | SAR_MV88F5182_CPU_FREQ_MASK; | ||
| 49 | if (opt == 0) | ||
| 50 | return 333333333; | ||
| 51 | else if (opt == 1 || opt == 2) | ||
| 52 | return 400000000; | ||
| 53 | else if (opt == 3) | ||
| 54 | return 500000000; | ||
| 55 | else | ||
| 56 | return 0; | ||
| 57 | } | ||
| 58 | |||
| 59 | static void __init mv88f5182_get_clk_ratio(void __iomem *sar, int id, | ||
| 60 | int *mult, int *div) | ||
| 61 | { | ||
| 62 | u32 opt = (readl(sar) >> SAR_MV88F5182_CPU_FREQ) & | ||
| 63 | SAR_MV88F5182_CPU_FREQ_MASK; | ||
| 64 | if (opt == 0 || opt == 1) { | ||
| 65 | *mult = 1; | ||
| 66 | *div = 2; | ||
| 67 | } else if (opt == 2 || opt == 3) { | ||
| 68 | *mult = 1; | ||
| 69 | *div = 3; | ||
| 70 | } else { | ||
| 71 | *mult = 0; | ||
| 72 | *div = 1; | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | static const struct coreclk_soc_desc mv88f5182_coreclks = { | ||
| 77 | .get_tclk_freq = mv88f5182_get_tclk_freq, | ||
| 78 | .get_cpu_freq = mv88f5182_get_cpu_freq, | ||
| 79 | .get_clk_ratio = mv88f5182_get_clk_ratio, | ||
| 80 | .ratios = orion_coreclk_ratios, | ||
| 81 | .num_ratios = ARRAY_SIZE(orion_coreclk_ratios), | ||
| 82 | }; | ||
| 83 | |||
| 84 | static void __init mv88f5182_clk_init(struct device_node *np) | ||
| 85 | { | ||
| 86 | return mvebu_coreclk_setup(np, &mv88f5182_coreclks); | ||
| 87 | } | ||
| 88 | |||
| 89 | CLK_OF_DECLARE(mv88f5182_clk, "marvell,mv88f5182-core-clock", mv88f5182_clk_init); | ||
| 90 | |||
| 91 | /* | ||
| 92 | * Orion 5281 | ||
| 93 | */ | ||
| 94 | |||
| 95 | static u32 __init mv88f5281_get_tclk_freq(void __iomem *sar) | ||
| 96 | { | ||
| 97 | /* On 5281, tclk is always 166 Mhz */ | ||
| 98 | return 166666667; | ||
| 99 | } | ||
| 100 | |||
| 101 | #define SAR_MV88F5281_CPU_FREQ 4 | ||
| 102 | #define SAR_MV88F5281_CPU_FREQ_MASK 0xf | ||
| 103 | |||
| 104 | static u32 __init mv88f5281_get_cpu_freq(void __iomem *sar) | ||
| 105 | { | ||
| 106 | u32 opt = (readl(sar) >> SAR_MV88F5281_CPU_FREQ) & | ||
| 107 | SAR_MV88F5281_CPU_FREQ_MASK; | ||
| 108 | if (opt == 1 || opt == 2) | ||
| 109 | return 400000000; | ||
| 110 | else if (opt == 3) | ||
| 111 | return 500000000; | ||
| 112 | else | ||
| 113 | return 0; | ||
| 114 | } | ||
| 115 | |||
| 116 | static void __init mv88f5281_get_clk_ratio(void __iomem *sar, int id, | ||
| 117 | int *mult, int *div) | ||
| 118 | { | ||
| 119 | u32 opt = (readl(sar) >> SAR_MV88F5281_CPU_FREQ) & | ||
| 120 | SAR_MV88F5281_CPU_FREQ_MASK; | ||
| 121 | if (opt == 1) { | ||
| 122 | *mult = 1; | ||
| 123 | *div = 2; | ||
| 124 | } else if (opt == 2 || opt == 3) { | ||
| 125 | *mult = 1; | ||
| 126 | *div = 3; | ||
| 127 | } else { | ||
| 128 | *mult = 0; | ||
| 129 | *div = 1; | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | static const struct coreclk_soc_desc mv88f5281_coreclks = { | ||
| 134 | .get_tclk_freq = mv88f5281_get_tclk_freq, | ||
| 135 | .get_cpu_freq = mv88f5281_get_cpu_freq, | ||
| 136 | .get_clk_ratio = mv88f5281_get_clk_ratio, | ||
| 137 | .ratios = orion_coreclk_ratios, | ||
| 138 | .num_ratios = ARRAY_SIZE(orion_coreclk_ratios), | ||
| 139 | }; | ||
| 140 | |||
| 141 | static void __init mv88f5281_clk_init(struct device_node *np) | ||
| 142 | { | ||
| 143 | return mvebu_coreclk_setup(np, &mv88f5281_coreclks); | ||
| 144 | } | ||
| 145 | |||
| 146 | CLK_OF_DECLARE(mv88f5281_clk, "marvell,mv88f5281-core-clock", mv88f5281_clk_init); | ||
| 147 | |||
| 148 | /* | ||
| 149 | * Orion 6183 | ||
| 150 | */ | ||
| 151 | |||
| 152 | #define SAR_MV88F6183_TCLK_FREQ 9 | ||
| 153 | #define SAR_MV88F6183_TCLK_FREQ_MASK 0x1 | ||
| 154 | |||
| 155 | static u32 __init mv88f6183_get_tclk_freq(void __iomem *sar) | ||
| 156 | { | ||
| 157 | u32 opt = (readl(sar) >> SAR_MV88F6183_TCLK_FREQ) & | ||
| 158 | SAR_MV88F6183_TCLK_FREQ_MASK; | ||
| 159 | if (opt == 0) | ||
| 160 | return 133333333; | ||
| 161 | else if (opt == 1) | ||
| 162 | return 166666667; | ||
| 163 | else | ||
| 164 | return 0; | ||
| 165 | } | ||
| 166 | |||
| 167 | #define SAR_MV88F6183_CPU_FREQ 1 | ||
| 168 | #define SAR_MV88F6183_CPU_FREQ_MASK 0x3f | ||
| 169 | |||
| 170 | static u32 __init mv88f6183_get_cpu_freq(void __iomem *sar) | ||
| 171 | { | ||
| 172 | u32 opt = (readl(sar) >> SAR_MV88F6183_CPU_FREQ) & | ||
| 173 | SAR_MV88F6183_CPU_FREQ_MASK; | ||
| 174 | if (opt == 9) | ||
| 175 | return 333333333; | ||
| 176 | else if (opt == 17) | ||
| 177 | return 400000000; | ||
| 178 | else | ||
| 179 | return 0; | ||
| 180 | } | ||
| 181 | |||
| 182 | static void __init mv88f6183_get_clk_ratio(void __iomem *sar, int id, | ||
| 183 | int *mult, int *div) | ||
| 184 | { | ||
| 185 | u32 opt = (readl(sar) >> SAR_MV88F6183_CPU_FREQ) & | ||
| 186 | SAR_MV88F6183_CPU_FREQ_MASK; | ||
| 187 | if (opt == 9 || opt == 17) { | ||
| 188 | *mult = 1; | ||
| 189 | *div = 2; | ||
| 190 | } else { | ||
| 191 | *mult = 0; | ||
| 192 | *div = 1; | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | static const struct coreclk_soc_desc mv88f6183_coreclks = { | ||
| 197 | .get_tclk_freq = mv88f6183_get_tclk_freq, | ||
| 198 | .get_cpu_freq = mv88f6183_get_cpu_freq, | ||
| 199 | .get_clk_ratio = mv88f6183_get_clk_ratio, | ||
| 200 | .ratios = orion_coreclk_ratios, | ||
| 201 | .num_ratios = ARRAY_SIZE(orion_coreclk_ratios), | ||
| 202 | }; | ||
| 203 | |||
| 204 | |||
| 205 | static void __init mv88f6183_clk_init(struct device_node *np) | ||
| 206 | { | ||
| 207 | return mvebu_coreclk_setup(np, &mv88f6183_coreclks); | ||
| 208 | } | ||
| 209 | |||
| 210 | 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 995bcfa021a4..7f696b7d4422 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig | |||
| @@ -13,10 +13,10 @@ config MSM_GCC_8660 | |||
| 13 | i2c, USB, SD/eMMC, etc. | 13 | i2c, USB, SD/eMMC, etc. |
| 14 | 14 | ||
| 15 | config MSM_GCC_8960 | 15 | config MSM_GCC_8960 |
| 16 | tristate "MSM8960 Global Clock Controller" | 16 | tristate "APQ8064/MSM8960 Global Clock Controller" |
| 17 | depends on COMMON_CLK_QCOM | 17 | depends on COMMON_CLK_QCOM |
| 18 | help | 18 | help |
| 19 | Support for the global clock controller on msm8960 devices. | 19 | Support for the global clock controller on apq8064/msm8960 devices. |
| 20 | Say Y if you want to use peripheral devices such as UART, SPI, | 20 | Say Y if you want to use peripheral devices such as UART, SPI, |
| 21 | i2c, USB, SD/eMMC, SATA, PCIe, etc. | 21 | i2c, USB, SD/eMMC, SATA, PCIe, etc. |
| 22 | 22 | ||
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index f60db2ef1aee..689e05bf4f95 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | obj-$(CONFIG_COMMON_CLK_QCOM) += clk-qcom.o | 1 | obj-$(CONFIG_COMMON_CLK_QCOM) += clk-qcom.o |
| 2 | 2 | ||
| 3 | clk-qcom-y += common.o | ||
| 3 | clk-qcom-y += clk-regmap.o | 4 | clk-qcom-y += clk-regmap.o |
| 4 | clk-qcom-y += clk-pll.o | 5 | clk-qcom-y += clk-pll.o |
| 5 | clk-qcom-y += clk-rcg.o | 6 | clk-qcom-y += clk-rcg.o |
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index 1d6b6dece328..b9ec11dfd1b4 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h | |||
| @@ -155,5 +155,8 @@ struct clk_rcg2 { | |||
| 155 | #define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr) | 155 | #define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr) |
| 156 | 156 | ||
| 157 | extern const struct clk_ops clk_rcg2_ops; | 157 | extern const struct clk_ops clk_rcg2_ops; |
| 158 | extern const struct clk_ops clk_edp_pixel_ops; | ||
| 159 | extern const struct clk_ops clk_byte_ops; | ||
| 160 | extern const struct clk_ops clk_pixel_ops; | ||
| 158 | 161 | ||
| 159 | #endif | 162 | #endif |
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 00f878a04d3f..cd185d5cc67a 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/clk-provider.h> | 19 | #include <linux/clk-provider.h> |
| 20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
| 21 | #include <linux/regmap.h> | 21 | #include <linux/regmap.h> |
| 22 | #include <linux/math64.h> | ||
| 22 | 23 | ||
| 23 | #include <asm/div64.h> | 24 | #include <asm/div64.h> |
| 24 | 25 | ||
| @@ -55,7 +56,7 @@ static int clk_rcg2_is_enabled(struct clk_hw *hw) | |||
| 55 | if (ret) | 56 | if (ret) |
| 56 | return ret; | 57 | return ret; |
| 57 | 58 | ||
| 58 | return (cmd & CMD_ROOT_OFF) != 0; | 59 | return (cmd & CMD_ROOT_OFF) == 0; |
| 59 | } | 60 | } |
| 60 | 61 | ||
| 61 | static u8 clk_rcg2_get_parent(struct clk_hw *hw) | 62 | static u8 clk_rcg2_get_parent(struct clk_hw *hw) |
| @@ -181,7 +182,8 @@ struct freq_tbl *find_freq(const struct freq_tbl *f, unsigned long rate) | |||
| 181 | if (rate <= f->freq) | 182 | if (rate <= f->freq) |
| 182 | return f; | 183 | return f; |
| 183 | 184 | ||
| 184 | return NULL; | 185 | /* Default to our fastest rate */ |
| 186 | return f - 1; | ||
| 185 | } | 187 | } |
| 186 | 188 | ||
| 187 | static long _freq_tbl_determine_rate(struct clk_hw *hw, | 189 | static long _freq_tbl_determine_rate(struct clk_hw *hw, |
| @@ -224,31 +226,25 @@ static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate, | |||
| 224 | return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p); | 226 | return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p); |
| 225 | } | 227 | } |
| 226 | 228 | ||
| 227 | static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate) | 229 | static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f) |
| 228 | { | 230 | { |
| 229 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
| 230 | const struct freq_tbl *f; | ||
| 231 | u32 cfg, mask; | 231 | u32 cfg, mask; |
| 232 | int ret; | 232 | int ret; |
| 233 | 233 | ||
| 234 | f = find_freq(rcg->freq_tbl, rate); | ||
| 235 | if (!f) | ||
| 236 | return -EINVAL; | ||
| 237 | |||
| 238 | if (rcg->mnd_width && f->n) { | 234 | if (rcg->mnd_width && f->n) { |
| 239 | mask = BIT(rcg->mnd_width) - 1; | 235 | mask = BIT(rcg->mnd_width) - 1; |
| 240 | ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + M_REG, | 236 | ret = regmap_update_bits(rcg->clkr.regmap, |
| 241 | mask, f->m); | 237 | rcg->cmd_rcgr + M_REG, mask, f->m); |
| 242 | if (ret) | 238 | if (ret) |
| 243 | return ret; | 239 | return ret; |
| 244 | 240 | ||
| 245 | ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + N_REG, | 241 | ret = regmap_update_bits(rcg->clkr.regmap, |
| 246 | mask, ~(f->n - f->m)); | 242 | rcg->cmd_rcgr + N_REG, mask, ~(f->n - f->m)); |
| 247 | if (ret) | 243 | if (ret) |
| 248 | return ret; | 244 | return ret; |
| 249 | 245 | ||
| 250 | ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + D_REG, | 246 | ret = regmap_update_bits(rcg->clkr.regmap, |
| 251 | mask, ~f->n); | 247 | rcg->cmd_rcgr + D_REG, mask, ~f->n); |
| 252 | if (ret) | 248 | if (ret) |
| 253 | return ret; | 249 | return ret; |
| 254 | } | 250 | } |
| @@ -259,14 +255,26 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate) | |||
| 259 | cfg |= rcg->parent_map[f->src] << CFG_SRC_SEL_SHIFT; | 255 | cfg |= rcg->parent_map[f->src] << CFG_SRC_SEL_SHIFT; |
| 260 | if (rcg->mnd_width && f->n) | 256 | if (rcg->mnd_width && f->n) |
| 261 | cfg |= CFG_MODE_DUAL_EDGE; | 257 | cfg |= CFG_MODE_DUAL_EDGE; |
| 262 | ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, mask, | 258 | ret = regmap_update_bits(rcg->clkr.regmap, |
| 263 | cfg); | 259 | rcg->cmd_rcgr + CFG_REG, mask, cfg); |
| 264 | if (ret) | 260 | if (ret) |
| 265 | return ret; | 261 | return ret; |
| 266 | 262 | ||
| 267 | return update_config(rcg); | 263 | return update_config(rcg); |
| 268 | } | 264 | } |
| 269 | 265 | ||
| 266 | static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate) | ||
| 267 | { | ||
| 268 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
| 269 | const struct freq_tbl *f; | ||
| 270 | |||
| 271 | f = find_freq(rcg->freq_tbl, rate); | ||
| 272 | if (!f) | ||
| 273 | return -EINVAL; | ||
| 274 | |||
| 275 | return clk_rcg2_configure(rcg, f); | ||
| 276 | } | ||
| 277 | |||
| 270 | static int clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, | 278 | static int clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, |
| 271 | unsigned long parent_rate) | 279 | unsigned long parent_rate) |
| 272 | { | 280 | { |
| @@ -289,3 +297,265 @@ const struct clk_ops clk_rcg2_ops = { | |||
| 289 | .set_rate_and_parent = clk_rcg2_set_rate_and_parent, | 297 | .set_rate_and_parent = clk_rcg2_set_rate_and_parent, |
| 290 | }; | 298 | }; |
| 291 | EXPORT_SYMBOL_GPL(clk_rcg2_ops); | 299 | EXPORT_SYMBOL_GPL(clk_rcg2_ops); |
| 300 | |||
| 301 | struct frac_entry { | ||
| 302 | int num; | ||
| 303 | int den; | ||
| 304 | }; | ||
| 305 | |||
| 306 | static const struct frac_entry frac_table_675m[] = { /* link rate of 270M */ | ||
| 307 | { 52, 295 }, /* 119 M */ | ||
| 308 | { 11, 57 }, /* 130.25 M */ | ||
| 309 | { 63, 307 }, /* 138.50 M */ | ||
| 310 | { 11, 50 }, /* 148.50 M */ | ||
| 311 | { 47, 206 }, /* 154 M */ | ||
| 312 | { 31, 100 }, /* 205.25 M */ | ||
| 313 | { 107, 269 }, /* 268.50 M */ | ||
| 314 | { }, | ||
| 315 | }; | ||
| 316 | |||
| 317 | static struct frac_entry frac_table_810m[] = { /* Link rate of 162M */ | ||
| 318 | { 31, 211 }, /* 119 M */ | ||
| 319 | { 32, 199 }, /* 130.25 M */ | ||
| 320 | { 63, 307 }, /* 138.50 M */ | ||
| 321 | { 11, 60 }, /* 148.50 M */ | ||
| 322 | { 50, 263 }, /* 154 M */ | ||
| 323 | { 31, 120 }, /* 205.25 M */ | ||
| 324 | { 119, 359 }, /* 268.50 M */ | ||
| 325 | { }, | ||
| 326 | }; | ||
| 327 | |||
| 328 | static int clk_edp_pixel_set_rate(struct clk_hw *hw, unsigned long rate, | ||
| 329 | unsigned long parent_rate) | ||
| 330 | { | ||
| 331 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
| 332 | struct freq_tbl f = *rcg->freq_tbl; | ||
| 333 | const struct frac_entry *frac; | ||
| 334 | int delta = 100000; | ||
| 335 | s64 src_rate = parent_rate; | ||
| 336 | s64 request; | ||
| 337 | u32 mask = BIT(rcg->hid_width) - 1; | ||
| 338 | u32 hid_div; | ||
| 339 | |||
| 340 | if (src_rate == 810000000) | ||
| 341 | frac = frac_table_810m; | ||
| 342 | else | ||
| 343 | frac = frac_table_675m; | ||
| 344 | |||
| 345 | for (; frac->num; frac++) { | ||
| 346 | request = rate; | ||
| 347 | request *= frac->den; | ||
| 348 | request = div_s64(request, frac->num); | ||
| 349 | if ((src_rate < (request - delta)) || | ||
| 350 | (src_rate > (request + delta))) | ||
| 351 | continue; | ||
| 352 | |||
| 353 | regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, | ||
| 354 | &hid_div); | ||
| 355 | f.pre_div = hid_div; | ||
| 356 | f.pre_div >>= CFG_SRC_DIV_SHIFT; | ||
| 357 | f.pre_div &= mask; | ||
| 358 | f.m = frac->num; | ||
| 359 | f.n = frac->den; | ||
| 360 | |||
| 361 | return clk_rcg2_configure(rcg, &f); | ||
| 362 | } | ||
| 363 | |||
| 364 | return -EINVAL; | ||
| 365 | } | ||
| 366 | |||
| 367 | static int clk_edp_pixel_set_rate_and_parent(struct clk_hw *hw, | ||
| 368 | unsigned long rate, unsigned long parent_rate, u8 index) | ||
| 369 | { | ||
| 370 | /* Parent index is set statically in frequency table */ | ||
| 371 | return clk_edp_pixel_set_rate(hw, rate, parent_rate); | ||
| 372 | } | ||
| 373 | |||
| 374 | static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, | ||
| 375 | unsigned long *p_rate, struct clk **p) | ||
| 376 | { | ||
| 377 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
| 378 | const struct freq_tbl *f = rcg->freq_tbl; | ||
| 379 | const struct frac_entry *frac; | ||
| 380 | int delta = 100000; | ||
| 381 | s64 src_rate = *p_rate; | ||
| 382 | s64 request; | ||
| 383 | u32 mask = BIT(rcg->hid_width) - 1; | ||
| 384 | u32 hid_div; | ||
| 385 | |||
| 386 | /* Force the correct parent */ | ||
| 387 | *p = clk_get_parent_by_index(hw->clk, f->src); | ||
| 388 | |||
| 389 | if (src_rate == 810000000) | ||
| 390 | frac = frac_table_810m; | ||
| 391 | else | ||
| 392 | frac = frac_table_675m; | ||
| 393 | |||
| 394 | for (; frac->num; frac++) { | ||
| 395 | request = rate; | ||
| 396 | request *= frac->den; | ||
| 397 | request = div_s64(request, frac->num); | ||
| 398 | if ((src_rate < (request - delta)) || | ||
| 399 | (src_rate > (request + delta))) | ||
| 400 | continue; | ||
| 401 | |||
| 402 | regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, | ||
| 403 | &hid_div); | ||
| 404 | hid_div >>= CFG_SRC_DIV_SHIFT; | ||
| 405 | hid_div &= mask; | ||
| 406 | |||
| 407 | return calc_rate(src_rate, frac->num, frac->den, !!frac->den, | ||
| 408 | hid_div); | ||
| 409 | } | ||
| 410 | |||
| 411 | return -EINVAL; | ||
| 412 | } | ||
| 413 | |||
| 414 | const struct clk_ops clk_edp_pixel_ops = { | ||
| 415 | .is_enabled = clk_rcg2_is_enabled, | ||
| 416 | .get_parent = clk_rcg2_get_parent, | ||
| 417 | .set_parent = clk_rcg2_set_parent, | ||
| 418 | .recalc_rate = clk_rcg2_recalc_rate, | ||
| 419 | .set_rate = clk_edp_pixel_set_rate, | ||
| 420 | .set_rate_and_parent = clk_edp_pixel_set_rate_and_parent, | ||
| 421 | .determine_rate = clk_edp_pixel_determine_rate, | ||
| 422 | }; | ||
| 423 | EXPORT_SYMBOL_GPL(clk_edp_pixel_ops); | ||
| 424 | |||
| 425 | static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate, | ||
| 426 | unsigned long *p_rate, struct clk **p) | ||
| 427 | { | ||
| 428 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
| 429 | const struct freq_tbl *f = rcg->freq_tbl; | ||
| 430 | unsigned long parent_rate, div; | ||
| 431 | u32 mask = BIT(rcg->hid_width) - 1; | ||
| 432 | |||
| 433 | if (rate == 0) | ||
| 434 | return -EINVAL; | ||
| 435 | |||
| 436 | *p = clk_get_parent_by_index(hw->clk, f->src); | ||
| 437 | *p_rate = parent_rate = __clk_round_rate(*p, rate); | ||
| 438 | |||
| 439 | div = DIV_ROUND_UP((2 * parent_rate), rate) - 1; | ||
| 440 | div = min_t(u32, div, mask); | ||
| 441 | |||
| 442 | return calc_rate(parent_rate, 0, 0, 0, div); | ||
| 443 | } | ||
| 444 | |||
| 445 | static int clk_byte_set_rate(struct clk_hw *hw, unsigned long rate, | ||
| 446 | unsigned long parent_rate) | ||
| 447 | { | ||
| 448 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
| 449 | struct freq_tbl f = *rcg->freq_tbl; | ||
| 450 | unsigned long div; | ||
| 451 | u32 mask = BIT(rcg->hid_width) - 1; | ||
| 452 | |||
| 453 | div = DIV_ROUND_UP((2 * parent_rate), rate) - 1; | ||
| 454 | div = min_t(u32, div, mask); | ||
| 455 | |||
| 456 | f.pre_div = div; | ||
| 457 | |||
| 458 | return clk_rcg2_configure(rcg, &f); | ||
| 459 | } | ||
| 460 | |||
| 461 | static int clk_byte_set_rate_and_parent(struct clk_hw *hw, | ||
| 462 | unsigned long rate, unsigned long parent_rate, u8 index) | ||
| 463 | { | ||
| 464 | /* Parent index is set statically in frequency table */ | ||
| 465 | return clk_byte_set_rate(hw, rate, parent_rate); | ||
| 466 | } | ||
| 467 | |||
| 468 | const struct clk_ops clk_byte_ops = { | ||
| 469 | .is_enabled = clk_rcg2_is_enabled, | ||
| 470 | .get_parent = clk_rcg2_get_parent, | ||
| 471 | .set_parent = clk_rcg2_set_parent, | ||
| 472 | .recalc_rate = clk_rcg2_recalc_rate, | ||
| 473 | .set_rate = clk_byte_set_rate, | ||
| 474 | .set_rate_and_parent = clk_byte_set_rate_and_parent, | ||
| 475 | .determine_rate = clk_byte_determine_rate, | ||
| 476 | }; | ||
| 477 | EXPORT_SYMBOL_GPL(clk_byte_ops); | ||
| 478 | |||
| 479 | static const struct frac_entry frac_table_pixel[] = { | ||
| 480 | { 3, 8 }, | ||
| 481 | { 2, 9 }, | ||
| 482 | { 4, 9 }, | ||
| 483 | { 1, 1 }, | ||
| 484 | { } | ||
| 485 | }; | ||
| 486 | |||
| 487 | static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, | ||
| 488 | unsigned long *p_rate, struct clk **p) | ||
| 489 | { | ||
| 490 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
| 491 | unsigned long request, src_rate; | ||
| 492 | int delta = 100000; | ||
| 493 | const struct freq_tbl *f = rcg->freq_tbl; | ||
| 494 | const struct frac_entry *frac = frac_table_pixel; | ||
| 495 | struct clk *parent = *p = clk_get_parent_by_index(hw->clk, f->src); | ||
| 496 | |||
| 497 | for (; frac->num; frac++) { | ||
| 498 | request = (rate * frac->den) / frac->num; | ||
| 499 | |||
| 500 | src_rate = __clk_round_rate(parent, request); | ||
| 501 | if ((src_rate < (request - delta)) || | ||
| 502 | (src_rate > (request + delta))) | ||
| 503 | continue; | ||
| 504 | |||
| 505 | *p_rate = src_rate; | ||
| 506 | return (src_rate * frac->num) / frac->den; | ||
| 507 | } | ||
| 508 | |||
| 509 | return -EINVAL; | ||
| 510 | } | ||
| 511 | |||
| 512 | static int clk_pixel_set_rate(struct clk_hw *hw, unsigned long rate, | ||
| 513 | unsigned long parent_rate) | ||
| 514 | { | ||
| 515 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | ||
| 516 | struct freq_tbl f = *rcg->freq_tbl; | ||
| 517 | const struct frac_entry *frac = frac_table_pixel; | ||
| 518 | unsigned long request, src_rate; | ||
| 519 | int delta = 100000; | ||
| 520 | u32 mask = BIT(rcg->hid_width) - 1; | ||
| 521 | u32 hid_div; | ||
| 522 | struct clk *parent = clk_get_parent_by_index(hw->clk, f.src); | ||
| 523 | |||
| 524 | for (; frac->num; frac++) { | ||
| 525 | request = (rate * frac->den) / frac->num; | ||
| 526 | |||
| 527 | src_rate = __clk_round_rate(parent, request); | ||
| 528 | if ((src_rate < (request - delta)) || | ||
| 529 | (src_rate > (request + delta))) | ||
| 530 | continue; | ||
| 531 | |||
| 532 | regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, | ||
| 533 | &hid_div); | ||
| 534 | f.pre_div = hid_div; | ||
| 535 | f.pre_div >>= CFG_SRC_DIV_SHIFT; | ||
| 536 | f.pre_div &= mask; | ||
| 537 | f.m = frac->num; | ||
| 538 | f.n = frac->den; | ||
| 539 | |||
| 540 | return clk_rcg2_configure(rcg, &f); | ||
| 541 | } | ||
| 542 | return -EINVAL; | ||
| 543 | } | ||
| 544 | |||
| 545 | static int clk_pixel_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, | ||
| 546 | unsigned long parent_rate, u8 index) | ||
| 547 | { | ||
| 548 | /* Parent index is set statically in frequency table */ | ||
| 549 | return clk_pixel_set_rate(hw, rate, parent_rate); | ||
| 550 | } | ||
| 551 | |||
| 552 | const struct clk_ops clk_pixel_ops = { | ||
| 553 | .is_enabled = clk_rcg2_is_enabled, | ||
| 554 | .get_parent = clk_rcg2_get_parent, | ||
| 555 | .set_parent = clk_rcg2_set_parent, | ||
| 556 | .recalc_rate = clk_rcg2_recalc_rate, | ||
| 557 | .set_rate = clk_pixel_set_rate, | ||
| 558 | .set_rate_and_parent = clk_pixel_set_rate_and_parent, | ||
| 559 | .determine_rate = clk_pixel_determine_rate, | ||
| 560 | }; | ||
| 561 | EXPORT_SYMBOL_GPL(clk_pixel_ops); | ||
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c new file mode 100644 index 000000000000..9b5a1cfc6b91 --- /dev/null +++ b/drivers/clk/qcom/common.c | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. | ||
| 3 | * | ||
| 4 | * This software is licensed under the terms of the GNU General Public | ||
| 5 | * License version 2, as published by the Free Software Foundation, and | ||
| 6 | * may be copied, distributed, and modified under those terms. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/export.h> | ||
| 15 | #include <linux/regmap.h> | ||
| 16 | #include <linux/platform_device.h> | ||
| 17 | #include <linux/clk-provider.h> | ||
| 18 | #include <linux/reset-controller.h> | ||
| 19 | |||
| 20 | #include "common.h" | ||
| 21 | #include "clk-regmap.h" | ||
| 22 | #include "reset.h" | ||
| 23 | |||
| 24 | struct qcom_cc { | ||
| 25 | struct qcom_reset_controller reset; | ||
| 26 | struct clk_onecell_data data; | ||
| 27 | struct clk *clks[]; | ||
| 28 | }; | ||
| 29 | |||
| 30 | int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc) | ||
| 31 | { | ||
| 32 | void __iomem *base; | ||
| 33 | struct resource *res; | ||
| 34 | int i, ret; | ||
| 35 | struct device *dev = &pdev->dev; | ||
| 36 | struct clk *clk; | ||
| 37 | struct clk_onecell_data *data; | ||
| 38 | struct clk **clks; | ||
| 39 | struct regmap *regmap; | ||
| 40 | struct qcom_reset_controller *reset; | ||
| 41 | struct qcom_cc *cc; | ||
| 42 | size_t num_clks = desc->num_clks; | ||
| 43 | struct clk_regmap **rclks = desc->clks; | ||
| 44 | |||
| 45 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 46 | base = devm_ioremap_resource(dev, res); | ||
| 47 | if (IS_ERR(base)) | ||
| 48 | return PTR_ERR(base); | ||
| 49 | |||
| 50 | regmap = devm_regmap_init_mmio(dev, base, desc->config); | ||
| 51 | if (IS_ERR(regmap)) | ||
| 52 | return PTR_ERR(regmap); | ||
| 53 | |||
| 54 | cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, | ||
| 55 | GFP_KERNEL); | ||
| 56 | if (!cc) | ||
| 57 | return -ENOMEM; | ||
| 58 | |||
| 59 | clks = cc->clks; | ||
| 60 | data = &cc->data; | ||
| 61 | data->clks = clks; | ||
| 62 | data->clk_num = num_clks; | ||
| 63 | |||
| 64 | for (i = 0; i < num_clks; i++) { | ||
| 65 | if (!rclks[i]) { | ||
| 66 | clks[i] = ERR_PTR(-ENOENT); | ||
| 67 | continue; | ||
| 68 | } | ||
| 69 | clk = devm_clk_register_regmap(dev, rclks[i]); | ||
| 70 | if (IS_ERR(clk)) | ||
| 71 | return PTR_ERR(clk); | ||
| 72 | clks[i] = clk; | ||
| 73 | } | ||
| 74 | |||
| 75 | ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); | ||
| 76 | if (ret) | ||
| 77 | return ret; | ||
| 78 | |||
| 79 | reset = &cc->reset; | ||
| 80 | reset->rcdev.of_node = dev->of_node; | ||
| 81 | reset->rcdev.ops = &qcom_reset_ops; | ||
| 82 | reset->rcdev.owner = dev->driver->owner; | ||
| 83 | reset->rcdev.nr_resets = desc->num_resets; | ||
| 84 | reset->regmap = regmap; | ||
| 85 | reset->reset_map = desc->resets; | ||
| 86 | platform_set_drvdata(pdev, &reset->rcdev); | ||
| 87 | |||
| 88 | ret = reset_controller_register(&reset->rcdev); | ||
| 89 | if (ret) | ||
| 90 | of_clk_del_provider(dev->of_node); | ||
| 91 | |||
| 92 | return ret; | ||
| 93 | } | ||
| 94 | EXPORT_SYMBOL_GPL(qcom_cc_probe); | ||
| 95 | |||
| 96 | void qcom_cc_remove(struct platform_device *pdev) | ||
| 97 | { | ||
| 98 | of_clk_del_provider(pdev->dev.of_node); | ||
| 99 | reset_controller_unregister(platform_get_drvdata(pdev)); | ||
| 100 | } | ||
| 101 | 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 000000000000..2c3cfc860348 --- /dev/null +++ b/drivers/clk/qcom/common.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014, The Linux Foundation. All rights reserved. | ||
| 3 | * | ||
| 4 | * This software is licensed under the terms of the GNU General Public | ||
| 5 | * License version 2, as published by the Free Software Foundation, and | ||
| 6 | * may be copied, distributed, and modified under those terms. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | */ | ||
| 13 | #ifndef __QCOM_CLK_COMMON_H__ | ||
| 14 | #define __QCOM_CLK_COMMON_H__ | ||
| 15 | |||
| 16 | struct platform_device; | ||
| 17 | struct regmap_config; | ||
| 18 | struct clk_regmap; | ||
| 19 | struct qcom_reset_map; | ||
| 20 | |||
| 21 | struct qcom_cc_desc { | ||
| 22 | const struct regmap_config *config; | ||
| 23 | struct clk_regmap **clks; | ||
| 24 | size_t num_clks; | ||
| 25 | const struct qcom_reset_map *resets; | ||
| 26 | size_t num_resets; | ||
| 27 | }; | ||
| 28 | |||
| 29 | extern int qcom_cc_probe(struct platform_device *pdev, | ||
| 30 | const struct qcom_cc_desc *desc); | ||
| 31 | |||
| 32 | extern void qcom_cc_remove(struct platform_device *pdev); | ||
| 33 | |||
| 34 | #endif | ||
diff --git a/drivers/clk/qcom/gcc-msm8660.c b/drivers/clk/qcom/gcc-msm8660.c index bc0b7f1fcfbe..0c4b727ae429 100644 --- a/drivers/clk/qcom/gcc-msm8660.c +++ b/drivers/clk/qcom/gcc-msm8660.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <dt-bindings/clock/qcom,gcc-msm8660.h> | 25 | #include <dt-bindings/clock/qcom,gcc-msm8660.h> |
| 26 | #include <dt-bindings/reset/qcom,gcc-msm8660.h> | 26 | #include <dt-bindings/reset/qcom,gcc-msm8660.h> |
| 27 | 27 | ||
| 28 | #include "common.h" | ||
| 28 | #include "clk-regmap.h" | 29 | #include "clk-regmap.h" |
| 29 | #include "clk-pll.h" | 30 | #include "clk-pll.h" |
| 30 | #include "clk-rcg.h" | 31 | #include "clk-rcg.h" |
| @@ -2701,51 +2702,24 @@ static const struct regmap_config gcc_msm8660_regmap_config = { | |||
| 2701 | .fast_io = true, | 2702 | .fast_io = true, |
| 2702 | }; | 2703 | }; |
| 2703 | 2704 | ||
| 2705 | static const struct qcom_cc_desc gcc_msm8660_desc = { | ||
| 2706 | .config = &gcc_msm8660_regmap_config, | ||
| 2707 | .clks = gcc_msm8660_clks, | ||
| 2708 | .num_clks = ARRAY_SIZE(gcc_msm8660_clks), | ||
| 2709 | .resets = gcc_msm8660_resets, | ||
| 2710 | .num_resets = ARRAY_SIZE(gcc_msm8660_resets), | ||
| 2711 | }; | ||
| 2712 | |||
| 2704 | static const struct of_device_id gcc_msm8660_match_table[] = { | 2713 | static const struct of_device_id gcc_msm8660_match_table[] = { |
| 2705 | { .compatible = "qcom,gcc-msm8660" }, | 2714 | { .compatible = "qcom,gcc-msm8660" }, |
| 2706 | { } | 2715 | { } |
| 2707 | }; | 2716 | }; |
| 2708 | MODULE_DEVICE_TABLE(of, gcc_msm8660_match_table); | 2717 | MODULE_DEVICE_TABLE(of, gcc_msm8660_match_table); |
| 2709 | 2718 | ||
| 2710 | struct qcom_cc { | ||
| 2711 | struct qcom_reset_controller reset; | ||
| 2712 | struct clk_onecell_data data; | ||
| 2713 | struct clk *clks[]; | ||
| 2714 | }; | ||
| 2715 | |||
| 2716 | static int gcc_msm8660_probe(struct platform_device *pdev) | 2719 | static int gcc_msm8660_probe(struct platform_device *pdev) |
| 2717 | { | 2720 | { |
| 2718 | void __iomem *base; | ||
| 2719 | struct resource *res; | ||
| 2720 | int i, ret; | ||
| 2721 | struct device *dev = &pdev->dev; | ||
| 2722 | struct clk *clk; | 2721 | struct clk *clk; |
| 2723 | struct clk_onecell_data *data; | 2722 | struct device *dev = &pdev->dev; |
| 2724 | struct clk **clks; | ||
| 2725 | struct regmap *regmap; | ||
| 2726 | size_t num_clks; | ||
| 2727 | struct qcom_reset_controller *reset; | ||
| 2728 | struct qcom_cc *cc; | ||
| 2729 | |||
| 2730 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 2731 | base = devm_ioremap_resource(dev, res); | ||
| 2732 | if (IS_ERR(base)) | ||
| 2733 | return PTR_ERR(base); | ||
| 2734 | |||
| 2735 | regmap = devm_regmap_init_mmio(dev, base, &gcc_msm8660_regmap_config); | ||
| 2736 | if (IS_ERR(regmap)) | ||
| 2737 | return PTR_ERR(regmap); | ||
| 2738 | |||
| 2739 | num_clks = ARRAY_SIZE(gcc_msm8660_clks); | ||
| 2740 | cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, | ||
| 2741 | GFP_KERNEL); | ||
| 2742 | if (!cc) | ||
| 2743 | return -ENOMEM; | ||
| 2744 | |||
| 2745 | clks = cc->clks; | ||
| 2746 | data = &cc->data; | ||
| 2747 | data->clks = clks; | ||
| 2748 | data->clk_num = num_clks; | ||
| 2749 | 2723 | ||
| 2750 | /* Temporary until RPM clocks supported */ | 2724 | /* Temporary until RPM clocks supported */ |
| 2751 | clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000); | 2725 | clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000); |
| @@ -2756,39 +2730,12 @@ static int gcc_msm8660_probe(struct platform_device *pdev) | |||
| 2756 | if (IS_ERR(clk)) | 2730 | if (IS_ERR(clk)) |
| 2757 | return PTR_ERR(clk); | 2731 | return PTR_ERR(clk); |
| 2758 | 2732 | ||
| 2759 | for (i = 0; i < num_clks; i++) { | 2733 | return qcom_cc_probe(pdev, &gcc_msm8660_desc); |
| 2760 | if (!gcc_msm8660_clks[i]) | ||
| 2761 | continue; | ||
| 2762 | clk = devm_clk_register_regmap(dev, gcc_msm8660_clks[i]); | ||
| 2763 | if (IS_ERR(clk)) | ||
| 2764 | return PTR_ERR(clk); | ||
| 2765 | clks[i] = clk; | ||
| 2766 | } | ||
| 2767 | |||
| 2768 | ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); | ||
| 2769 | if (ret) | ||
| 2770 | return ret; | ||
| 2771 | |||
| 2772 | reset = &cc->reset; | ||
| 2773 | reset->rcdev.of_node = dev->of_node; | ||
| 2774 | reset->rcdev.ops = &qcom_reset_ops, | ||
| 2775 | reset->rcdev.owner = THIS_MODULE, | ||
| 2776 | reset->rcdev.nr_resets = ARRAY_SIZE(gcc_msm8660_resets), | ||
| 2777 | reset->regmap = regmap; | ||
| 2778 | reset->reset_map = gcc_msm8660_resets, | ||
| 2779 | platform_set_drvdata(pdev, &reset->rcdev); | ||
| 2780 | |||
| 2781 | ret = reset_controller_register(&reset->rcdev); | ||
| 2782 | if (ret) | ||
| 2783 | of_clk_del_provider(dev->of_node); | ||
| 2784 | |||
| 2785 | return ret; | ||
| 2786 | } | 2734 | } |
| 2787 | 2735 | ||
| 2788 | static int gcc_msm8660_remove(struct platform_device *pdev) | 2736 | static int gcc_msm8660_remove(struct platform_device *pdev) |
| 2789 | { | 2737 | { |
| 2790 | of_clk_del_provider(pdev->dev.of_node); | 2738 | qcom_cc_remove(pdev); |
| 2791 | reset_controller_unregister(platform_get_drvdata(pdev)); | ||
| 2792 | return 0; | 2739 | return 0; |
| 2793 | } | 2740 | } |
| 2794 | 2741 | ||
diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c index fd446ab2fd98..f4ffd91901f8 100644 --- a/drivers/clk/qcom/gcc-msm8960.c +++ b/drivers/clk/qcom/gcc-msm8960.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2013, The Linux Foundation. All rights reserved. | 2 | * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. |
| 3 | * | 3 | * |
| 4 | * This software is licensed under the terms of the GNU General Public | 4 | * This software is licensed under the terms of the GNU General Public |
| 5 | * License version 2, as published by the Free Software Foundation, and | 5 | * License version 2, as published by the Free Software Foundation, and |
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <dt-bindings/clock/qcom,gcc-msm8960.h> | 25 | #include <dt-bindings/clock/qcom,gcc-msm8960.h> |
| 26 | #include <dt-bindings/reset/qcom,gcc-msm8960.h> | 26 | #include <dt-bindings/reset/qcom,gcc-msm8960.h> |
| 27 | 27 | ||
| 28 | #include "common.h" | ||
| 28 | #include "clk-regmap.h" | 29 | #include "clk-regmap.h" |
| 29 | #include "clk-pll.h" | 30 | #include "clk-pll.h" |
| 30 | #include "clk-rcg.h" | 31 | #include "clk-rcg.h" |
| @@ -2809,7 +2810,7 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = { | |||
| 2809 | [PPSS_PROC_RESET] = { 0x2594, 1 }, | 2810 | [PPSS_PROC_RESET] = { 0x2594, 1 }, |
| 2810 | [PPSS_RESET] = { 0x2594}, | 2811 | [PPSS_RESET] = { 0x2594}, |
| 2811 | [DMA_BAM_RESET] = { 0x25c0, 7 }, | 2812 | [DMA_BAM_RESET] = { 0x25c0, 7 }, |
| 2812 | [SIC_TIC_RESET] = { 0x2600, 7 }, | 2813 | [SPS_TIC_H_RESET] = { 0x2600, 7 }, |
| 2813 | [SLIMBUS_H_RESET] = { 0x2620, 7 }, | 2814 | [SLIMBUS_H_RESET] = { 0x2620, 7 }, |
| 2814 | [SFAB_CFPB_M_RESET] = { 0x2680, 7 }, | 2815 | [SFAB_CFPB_M_RESET] = { 0x2680, 7 }, |
| 2815 | [SFAB_CFPB_S_RESET] = { 0x26c0, 7 }, | 2816 | [SFAB_CFPB_S_RESET] = { 0x26c0, 7 }, |
| @@ -2822,7 +2823,7 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = { | |||
| 2822 | [SFAB_SFPB_M_RESET] = { 0x2780, 7 }, | 2823 | [SFAB_SFPB_M_RESET] = { 0x2780, 7 }, |
| 2823 | [SFAB_SFPB_S_RESET] = { 0x27a0, 7 }, | 2824 | [SFAB_SFPB_S_RESET] = { 0x27a0, 7 }, |
| 2824 | [RPM_PROC_RESET] = { 0x27c0, 7 }, | 2825 | [RPM_PROC_RESET] = { 0x27c0, 7 }, |
| 2825 | [PMIC_SSBI2_RESET] = { 0x270c, 12 }, | 2826 | [PMIC_SSBI2_RESET] = { 0x280c, 12 }, |
| 2826 | [SDC1_RESET] = { 0x2830 }, | 2827 | [SDC1_RESET] = { 0x2830 }, |
| 2827 | [SDC2_RESET] = { 0x2850 }, | 2828 | [SDC2_RESET] = { 0x2850 }, |
| 2828 | [SDC3_RESET] = { 0x2870 }, | 2829 | [SDC3_RESET] = { 0x2870 }, |
| @@ -2867,6 +2868,16 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = { | |||
| 2867 | [RIVA_RESET] = { 0x35e0 }, | 2868 | [RIVA_RESET] = { 0x35e0 }, |
| 2868 | }; | 2869 | }; |
| 2869 | 2870 | ||
| 2871 | static struct clk_regmap *gcc_apq8064_clks[] = { | ||
| 2872 | [PLL8] = &pll8.clkr, | ||
| 2873 | [PLL8_VOTE] = &pll8_vote, | ||
| 2874 | [GSBI7_UART_SRC] = &gsbi7_uart_src.clkr, | ||
| 2875 | [GSBI7_UART_CLK] = &gsbi7_uart_clk.clkr, | ||
| 2876 | [GSBI7_QUP_SRC] = &gsbi7_qup_src.clkr, | ||
| 2877 | [GSBI7_QUP_CLK] = &gsbi7_qup_clk.clkr, | ||
| 2878 | [GSBI7_H_CLK] = &gsbi7_h_clk.clkr, | ||
| 2879 | }; | ||
| 2880 | |||
| 2870 | static const struct regmap_config gcc_msm8960_regmap_config = { | 2881 | static const struct regmap_config gcc_msm8960_regmap_config = { |
| 2871 | .reg_bits = 32, | 2882 | .reg_bits = 32, |
| 2872 | .reg_stride = 4, | 2883 | .reg_stride = 4, |
| @@ -2875,51 +2886,38 @@ static const struct regmap_config gcc_msm8960_regmap_config = { | |||
| 2875 | .fast_io = true, | 2886 | .fast_io = true, |
| 2876 | }; | 2887 | }; |
| 2877 | 2888 | ||
| 2889 | static const struct qcom_cc_desc gcc_msm8960_desc = { | ||
| 2890 | .config = &gcc_msm8960_regmap_config, | ||
| 2891 | .clks = gcc_msm8960_clks, | ||
| 2892 | .num_clks = ARRAY_SIZE(gcc_msm8960_clks), | ||
| 2893 | .resets = gcc_msm8960_resets, | ||
| 2894 | .num_resets = ARRAY_SIZE(gcc_msm8960_resets), | ||
| 2895 | }; | ||
| 2896 | |||
| 2897 | static const struct qcom_cc_desc gcc_apq8064_desc = { | ||
| 2898 | .config = &gcc_msm8960_regmap_config, | ||
| 2899 | .clks = gcc_apq8064_clks, | ||
| 2900 | .num_clks = ARRAY_SIZE(gcc_apq8064_clks), | ||
| 2901 | .resets = gcc_msm8960_resets, | ||
| 2902 | .num_resets = ARRAY_SIZE(gcc_msm8960_resets), | ||
| 2903 | }; | ||
| 2904 | |||
| 2878 | static const struct of_device_id gcc_msm8960_match_table[] = { | 2905 | static const struct of_device_id gcc_msm8960_match_table[] = { |
| 2879 | { .compatible = "qcom,gcc-msm8960" }, | 2906 | { .compatible = "qcom,gcc-msm8960", .data = &gcc_msm8960_desc }, |
| 2907 | { .compatible = "qcom,gcc-apq8064", .data = &gcc_apq8064_desc }, | ||
| 2880 | { } | 2908 | { } |
| 2881 | }; | 2909 | }; |
| 2882 | MODULE_DEVICE_TABLE(of, gcc_msm8960_match_table); | 2910 | MODULE_DEVICE_TABLE(of, gcc_msm8960_match_table); |
| 2883 | 2911 | ||
| 2884 | struct qcom_cc { | ||
| 2885 | struct qcom_reset_controller reset; | ||
| 2886 | struct clk_onecell_data data; | ||
| 2887 | struct clk *clks[]; | ||
| 2888 | }; | ||
| 2889 | |||
| 2890 | static int gcc_msm8960_probe(struct platform_device *pdev) | 2912 | static int gcc_msm8960_probe(struct platform_device *pdev) |
| 2891 | { | 2913 | { |
| 2892 | void __iomem *base; | ||
| 2893 | struct resource *res; | ||
| 2894 | int i, ret; | ||
| 2895 | struct device *dev = &pdev->dev; | ||
| 2896 | struct clk *clk; | 2914 | struct clk *clk; |
| 2897 | struct clk_onecell_data *data; | 2915 | struct device *dev = &pdev->dev; |
| 2898 | struct clk **clks; | 2916 | const struct of_device_id *match; |
| 2899 | struct regmap *regmap; | 2917 | |
| 2900 | size_t num_clks; | 2918 | match = of_match_device(gcc_msm8960_match_table, &pdev->dev); |
| 2901 | struct qcom_reset_controller *reset; | 2919 | if (!match) |
| 2902 | struct qcom_cc *cc; | 2920 | return -EINVAL; |
| 2903 | |||
| 2904 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 2905 | base = devm_ioremap_resource(dev, res); | ||
| 2906 | if (IS_ERR(base)) | ||
| 2907 | return PTR_ERR(base); | ||
| 2908 | |||
| 2909 | regmap = devm_regmap_init_mmio(dev, base, &gcc_msm8960_regmap_config); | ||
| 2910 | if (IS_ERR(regmap)) | ||
| 2911 | return PTR_ERR(regmap); | ||
| 2912 | |||
| 2913 | num_clks = ARRAY_SIZE(gcc_msm8960_clks); | ||
| 2914 | cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, | ||
| 2915 | GFP_KERNEL); | ||
| 2916 | if (!cc) | ||
| 2917 | return -ENOMEM; | ||
| 2918 | |||
| 2919 | clks = cc->clks; | ||
| 2920 | data = &cc->data; | ||
| 2921 | data->clks = clks; | ||
| 2922 | data->clk_num = num_clks; | ||
| 2923 | 2921 | ||
| 2924 | /* Temporary until RPM clocks supported */ | 2922 | /* Temporary until RPM clocks supported */ |
| 2925 | clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000); | 2923 | clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000); |
| @@ -2930,39 +2928,12 @@ static int gcc_msm8960_probe(struct platform_device *pdev) | |||
| 2930 | if (IS_ERR(clk)) | 2928 | if (IS_ERR(clk)) |
| 2931 | return PTR_ERR(clk); | 2929 | return PTR_ERR(clk); |
| 2932 | 2930 | ||
| 2933 | for (i = 0; i < num_clks; i++) { | 2931 | return qcom_cc_probe(pdev, match->data); |
| 2934 | if (!gcc_msm8960_clks[i]) | ||
| 2935 | continue; | ||
| 2936 | clk = devm_clk_register_regmap(dev, gcc_msm8960_clks[i]); | ||
| 2937 | if (IS_ERR(clk)) | ||
| 2938 | return PTR_ERR(clk); | ||
| 2939 | clks[i] = clk; | ||
| 2940 | } | ||
| 2941 | |||
| 2942 | ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); | ||
| 2943 | if (ret) | ||
| 2944 | return ret; | ||
| 2945 | |||
| 2946 | reset = &cc->reset; | ||
| 2947 | reset->rcdev.of_node = dev->of_node; | ||
| 2948 | reset->rcdev.ops = &qcom_reset_ops, | ||
| 2949 | reset->rcdev.owner = THIS_MODULE, | ||
| 2950 | reset->rcdev.nr_resets = ARRAY_SIZE(gcc_msm8960_resets), | ||
| 2951 | reset->regmap = regmap; | ||
| 2952 | reset->reset_map = gcc_msm8960_resets, | ||
| 2953 | platform_set_drvdata(pdev, &reset->rcdev); | ||
| 2954 | |||
| 2955 | ret = reset_controller_register(&reset->rcdev); | ||
| 2956 | if (ret) | ||
| 2957 | of_clk_del_provider(dev->of_node); | ||
| 2958 | |||
| 2959 | return ret; | ||
| 2960 | } | 2932 | } |
| 2961 | 2933 | ||
| 2962 | static int gcc_msm8960_remove(struct platform_device *pdev) | 2934 | static int gcc_msm8960_remove(struct platform_device *pdev) |
| 2963 | { | 2935 | { |
| 2964 | of_clk_del_provider(pdev->dev.of_node); | 2936 | qcom_cc_remove(pdev); |
| 2965 | reset_controller_unregister(platform_get_drvdata(pdev)); | ||
| 2966 | return 0; | 2937 | return 0; |
| 2967 | } | 2938 | } |
| 2968 | 2939 | ||
diff --git a/drivers/clk/qcom/gcc-msm8974.c b/drivers/clk/qcom/gcc-msm8974.c index 51d457e2b959..7af7c18d2144 100644 --- a/drivers/clk/qcom/gcc-msm8974.c +++ b/drivers/clk/qcom/gcc-msm8974.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <dt-bindings/clock/qcom,gcc-msm8974.h> | 25 | #include <dt-bindings/clock/qcom,gcc-msm8974.h> |
| 26 | #include <dt-bindings/reset/qcom,gcc-msm8974.h> | 26 | #include <dt-bindings/reset/qcom,gcc-msm8974.h> |
| 27 | 27 | ||
| 28 | #include "common.h" | ||
| 28 | #include "clk-regmap.h" | 29 | #include "clk-regmap.h" |
| 29 | #include "clk-pll.h" | 30 | #include "clk-pll.h" |
| 30 | #include "clk-rcg.h" | 31 | #include "clk-rcg.h" |
| @@ -34,6 +35,7 @@ | |||
| 34 | #define P_XO 0 | 35 | #define P_XO 0 |
| 35 | #define P_GPLL0 1 | 36 | #define P_GPLL0 1 |
| 36 | #define P_GPLL1 1 | 37 | #define P_GPLL1 1 |
| 38 | #define P_GPLL4 2 | ||
| 37 | 39 | ||
| 38 | static const u8 gcc_xo_gpll0_map[] = { | 40 | static const u8 gcc_xo_gpll0_map[] = { |
| 39 | [P_XO] = 0, | 41 | [P_XO] = 0, |
| @@ -45,6 +47,18 @@ static const char *gcc_xo_gpll0[] = { | |||
| 45 | "gpll0_vote", | 47 | "gpll0_vote", |
| 46 | }; | 48 | }; |
| 47 | 49 | ||
| 50 | static const u8 gcc_xo_gpll0_gpll4_map[] = { | ||
| 51 | [P_XO] = 0, | ||
| 52 | [P_GPLL0] = 1, | ||
| 53 | [P_GPLL4] = 5, | ||
| 54 | }; | ||
| 55 | |||
| 56 | static const char *gcc_xo_gpll0_gpll4[] = { | ||
| 57 | "xo", | ||
| 58 | "gpll0_vote", | ||
| 59 | "gpll4_vote", | ||
| 60 | }; | ||
| 61 | |||
| 48 | #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } | 62 | #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } |
| 49 | 63 | ||
| 50 | static struct clk_pll gpll0 = { | 64 | static struct clk_pll gpll0 = { |
| @@ -137,6 +151,33 @@ static struct clk_regmap gpll1_vote = { | |||
| 137 | }, | 151 | }, |
| 138 | }; | 152 | }; |
| 139 | 153 | ||
| 154 | static struct clk_pll gpll4 = { | ||
| 155 | .l_reg = 0x1dc4, | ||
| 156 | .m_reg = 0x1dc8, | ||
| 157 | .n_reg = 0x1dcc, | ||
| 158 | .config_reg = 0x1dd4, | ||
| 159 | .mode_reg = 0x1dc0, | ||
| 160 | .status_reg = 0x1ddc, | ||
| 161 | .status_bit = 17, | ||
| 162 | .clkr.hw.init = &(struct clk_init_data){ | ||
| 163 | .name = "gpll4", | ||
| 164 | .parent_names = (const char *[]){ "xo" }, | ||
| 165 | .num_parents = 1, | ||
| 166 | .ops = &clk_pll_ops, | ||
| 167 | }, | ||
| 168 | }; | ||
| 169 | |||
| 170 | static struct clk_regmap gpll4_vote = { | ||
| 171 | .enable_reg = 0x1480, | ||
| 172 | .enable_mask = BIT(4), | ||
| 173 | .hw.init = &(struct clk_init_data){ | ||
| 174 | .name = "gpll4_vote", | ||
| 175 | .parent_names = (const char *[]){ "gpll4" }, | ||
| 176 | .num_parents = 1, | ||
| 177 | .ops = &clk_pll_vote_ops, | ||
| 178 | }, | ||
| 179 | }; | ||
| 180 | |||
| 140 | static const struct freq_tbl ftbl_gcc_usb30_master_clk[] = { | 181 | static const struct freq_tbl ftbl_gcc_usb30_master_clk[] = { |
| 141 | F(125000000, P_GPLL0, 1, 5, 24), | 182 | F(125000000, P_GPLL0, 1, 5, 24), |
| 142 | { } | 183 | { } |
| @@ -811,18 +852,33 @@ static const struct freq_tbl ftbl_gcc_sdcc1_4_apps_clk[] = { | |||
| 811 | { } | 852 | { } |
| 812 | }; | 853 | }; |
| 813 | 854 | ||
| 855 | static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_pro[] = { | ||
| 856 | F(144000, P_XO, 16, 3, 25), | ||
| 857 | F(400000, P_XO, 12, 1, 4), | ||
| 858 | F(20000000, P_GPLL0, 15, 1, 2), | ||
| 859 | F(25000000, P_GPLL0, 12, 1, 2), | ||
| 860 | F(50000000, P_GPLL0, 12, 0, 0), | ||
| 861 | F(100000000, P_GPLL0, 6, 0, 0), | ||
| 862 | F(192000000, P_GPLL4, 4, 0, 0), | ||
| 863 | F(200000000, P_GPLL0, 3, 0, 0), | ||
| 864 | F(384000000, P_GPLL4, 2, 0, 0), | ||
| 865 | { } | ||
| 866 | }; | ||
| 867 | |||
| 868 | static struct clk_init_data sdcc1_apps_clk_src_init = { | ||
| 869 | .name = "sdcc1_apps_clk_src", | ||
| 870 | .parent_names = gcc_xo_gpll0, | ||
| 871 | .num_parents = 2, | ||
| 872 | .ops = &clk_rcg2_ops, | ||
| 873 | }; | ||
| 874 | |||
| 814 | static struct clk_rcg2 sdcc1_apps_clk_src = { | 875 | static struct clk_rcg2 sdcc1_apps_clk_src = { |
| 815 | .cmd_rcgr = 0x04d0, | 876 | .cmd_rcgr = 0x04d0, |
| 816 | .mnd_width = 8, | 877 | .mnd_width = 8, |
| 817 | .hid_width = 5, | 878 | .hid_width = 5, |
| 818 | .parent_map = gcc_xo_gpll0_map, | 879 | .parent_map = gcc_xo_gpll0_map, |
| 819 | .freq_tbl = ftbl_gcc_sdcc1_4_apps_clk, | 880 | .freq_tbl = ftbl_gcc_sdcc1_4_apps_clk, |
| 820 | .clkr.hw.init = &(struct clk_init_data){ | 881 | .clkr.hw.init = &sdcc1_apps_clk_src_init, |
| 821 | .name = "sdcc1_apps_clk_src", | ||
| 822 | .parent_names = gcc_xo_gpll0, | ||
| 823 | .num_parents = 2, | ||
| 824 | .ops = &clk_rcg2_ops, | ||
| 825 | }, | ||
| 826 | }; | 882 | }; |
| 827 | 883 | ||
| 828 | static struct clk_rcg2 sdcc2_apps_clk_src = { | 884 | static struct clk_rcg2 sdcc2_apps_clk_src = { |
| @@ -1340,7 +1396,7 @@ static struct clk_branch gcc_blsp1_uart6_apps_clk = { | |||
| 1340 | }; | 1396 | }; |
| 1341 | 1397 | ||
| 1342 | static struct clk_branch gcc_blsp2_ahb_clk = { | 1398 | static struct clk_branch gcc_blsp2_ahb_clk = { |
| 1343 | .halt_reg = 0x05c4, | 1399 | .halt_reg = 0x0944, |
| 1344 | .halt_check = BRANCH_HALT_VOTED, | 1400 | .halt_check = BRANCH_HALT_VOTED, |
| 1345 | .clkr = { | 1401 | .clkr = { |
| 1346 | .enable_reg = 0x1484, | 1402 | .enable_reg = 0x1484, |
| @@ -1994,6 +2050,38 @@ static struct clk_branch gcc_sdcc1_apps_clk = { | |||
| 1994 | }, | 2050 | }, |
| 1995 | }; | 2051 | }; |
| 1996 | 2052 | ||
| 2053 | static struct clk_branch gcc_sdcc1_cdccal_ff_clk = { | ||
| 2054 | .halt_reg = 0x04e8, | ||
| 2055 | .clkr = { | ||
| 2056 | .enable_reg = 0x04e8, | ||
| 2057 | .enable_mask = BIT(0), | ||
| 2058 | .hw.init = &(struct clk_init_data){ | ||
| 2059 | .name = "gcc_sdcc1_cdccal_ff_clk", | ||
| 2060 | .parent_names = (const char *[]){ | ||
| 2061 | "xo" | ||
| 2062 | }, | ||
| 2063 | .num_parents = 1, | ||
| 2064 | .ops = &clk_branch2_ops, | ||
| 2065 | }, | ||
| 2066 | }, | ||
| 2067 | }; | ||
| 2068 | |||
| 2069 | static struct clk_branch gcc_sdcc1_cdccal_sleep_clk = { | ||
| 2070 | .halt_reg = 0x04e4, | ||
| 2071 | .clkr = { | ||
| 2072 | .enable_reg = 0x04e4, | ||
| 2073 | .enable_mask = BIT(0), | ||
| 2074 | .hw.init = &(struct clk_init_data){ | ||
| 2075 | .name = "gcc_sdcc1_cdccal_sleep_clk", | ||
| 2076 | .parent_names = (const char *[]){ | ||
| 2077 | "sleep_clk_src" | ||
| 2078 | }, | ||
| 2079 | .num_parents = 1, | ||
| 2080 | .ops = &clk_branch2_ops, | ||
| 2081 | }, | ||
| 2082 | }, | ||
| 2083 | }; | ||
| 2084 | |||
| 1997 | static struct clk_branch gcc_sdcc2_ahb_clk = { | 2085 | static struct clk_branch gcc_sdcc2_ahb_clk = { |
| 1998 | .halt_reg = 0x0508, | 2086 | .halt_reg = 0x0508, |
| 1999 | .clkr = { | 2087 | .clkr = { |
| @@ -2483,6 +2571,10 @@ static struct clk_regmap *gcc_msm8974_clocks[] = { | |||
| 2483 | [GCC_USB_HSIC_IO_CAL_SLEEP_CLK] = &gcc_usb_hsic_io_cal_sleep_clk.clkr, | 2571 | [GCC_USB_HSIC_IO_CAL_SLEEP_CLK] = &gcc_usb_hsic_io_cal_sleep_clk.clkr, |
| 2484 | [GCC_USB_HSIC_SYSTEM_CLK] = &gcc_usb_hsic_system_clk.clkr, | 2572 | [GCC_USB_HSIC_SYSTEM_CLK] = &gcc_usb_hsic_system_clk.clkr, |
| 2485 | [GCC_MMSS_GPLL0_CLK_SRC] = &gcc_mmss_gpll0_clk_src, | 2573 | [GCC_MMSS_GPLL0_CLK_SRC] = &gcc_mmss_gpll0_clk_src, |
| 2574 | [GPLL4] = NULL, | ||
| 2575 | [GPLL4_VOTE] = NULL, | ||
| 2576 | [GCC_SDCC1_CDCCAL_SLEEP_CLK] = NULL, | ||
| 2577 | [GCC_SDCC1_CDCCAL_FF_CLK] = NULL, | ||
| 2486 | }; | 2578 | }; |
| 2487 | 2579 | ||
| 2488 | static const struct qcom_reset_map gcc_msm8974_resets[] = { | 2580 | static const struct qcom_reset_map gcc_msm8974_resets[] = { |
| @@ -2574,51 +2666,51 @@ static const struct regmap_config gcc_msm8974_regmap_config = { | |||
| 2574 | .fast_io = true, | 2666 | .fast_io = true, |
| 2575 | }; | 2667 | }; |
| 2576 | 2668 | ||
| 2669 | static const struct qcom_cc_desc gcc_msm8974_desc = { | ||
| 2670 | .config = &gcc_msm8974_regmap_config, | ||
| 2671 | .clks = gcc_msm8974_clocks, | ||
| 2672 | .num_clks = ARRAY_SIZE(gcc_msm8974_clocks), | ||
| 2673 | .resets = gcc_msm8974_resets, | ||
| 2674 | .num_resets = ARRAY_SIZE(gcc_msm8974_resets), | ||
| 2675 | }; | ||
| 2676 | |||
| 2577 | static const struct of_device_id gcc_msm8974_match_table[] = { | 2677 | static const struct of_device_id gcc_msm8974_match_table[] = { |
| 2578 | { .compatible = "qcom,gcc-msm8974" }, | 2678 | { .compatible = "qcom,gcc-msm8974" }, |
| 2679 | { .compatible = "qcom,gcc-msm8974pro" , .data = (void *)1UL }, | ||
| 2680 | { .compatible = "qcom,gcc-msm8974pro-ac", .data = (void *)1UL }, | ||
| 2579 | { } | 2681 | { } |
| 2580 | }; | 2682 | }; |
| 2581 | MODULE_DEVICE_TABLE(of, gcc_msm8974_match_table); | 2683 | MODULE_DEVICE_TABLE(of, gcc_msm8974_match_table); |
| 2582 | 2684 | ||
| 2583 | struct qcom_cc { | 2685 | static void msm8974_pro_clock_override(void) |
| 2584 | struct qcom_reset_controller reset; | 2686 | { |
| 2585 | struct clk_onecell_data data; | 2687 | sdcc1_apps_clk_src_init.parent_names = gcc_xo_gpll0_gpll4; |
| 2586 | struct clk *clks[]; | 2688 | sdcc1_apps_clk_src_init.num_parents = 3; |
| 2587 | }; | 2689 | sdcc1_apps_clk_src.freq_tbl = ftbl_gcc_sdcc1_apps_clk_pro; |
| 2690 | sdcc1_apps_clk_src.parent_map = gcc_xo_gpll0_gpll4_map; | ||
| 2691 | |||
| 2692 | gcc_msm8974_clocks[GPLL4] = &gpll4.clkr; | ||
| 2693 | gcc_msm8974_clocks[GPLL4_VOTE] = &gpll4_vote; | ||
| 2694 | gcc_msm8974_clocks[GCC_SDCC1_CDCCAL_SLEEP_CLK] = | ||
| 2695 | &gcc_sdcc1_cdccal_sleep_clk.clkr; | ||
| 2696 | gcc_msm8974_clocks[GCC_SDCC1_CDCCAL_FF_CLK] = | ||
| 2697 | &gcc_sdcc1_cdccal_ff_clk.clkr; | ||
| 2698 | } | ||
| 2588 | 2699 | ||
| 2589 | static int gcc_msm8974_probe(struct platform_device *pdev) | 2700 | static int gcc_msm8974_probe(struct platform_device *pdev) |
| 2590 | { | 2701 | { |
| 2591 | void __iomem *base; | ||
| 2592 | struct resource *res; | ||
| 2593 | int i, ret; | ||
| 2594 | struct device *dev = &pdev->dev; | ||
| 2595 | struct clk *clk; | 2702 | struct clk *clk; |
| 2596 | struct clk_onecell_data *data; | 2703 | struct device *dev = &pdev->dev; |
| 2597 | struct clk **clks; | 2704 | bool pro; |
| 2598 | struct regmap *regmap; | 2705 | const struct of_device_id *id; |
| 2599 | size_t num_clks; | 2706 | |
| 2600 | struct qcom_reset_controller *reset; | 2707 | id = of_match_device(gcc_msm8974_match_table, dev); |
| 2601 | struct qcom_cc *cc; | 2708 | if (!id) |
| 2602 | 2709 | return -ENODEV; | |
| 2603 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 2710 | pro = !!(id->data); |
| 2604 | base = devm_ioremap_resource(dev, res); | 2711 | |
| 2605 | if (IS_ERR(base)) | 2712 | if (pro) |
| 2606 | return PTR_ERR(base); | 2713 | msm8974_pro_clock_override(); |
| 2607 | |||
| 2608 | regmap = devm_regmap_init_mmio(dev, base, &gcc_msm8974_regmap_config); | ||
| 2609 | if (IS_ERR(regmap)) | ||
| 2610 | return PTR_ERR(regmap); | ||
| 2611 | |||
| 2612 | num_clks = ARRAY_SIZE(gcc_msm8974_clocks); | ||
| 2613 | cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, | ||
| 2614 | GFP_KERNEL); | ||
| 2615 | if (!cc) | ||
| 2616 | return -ENOMEM; | ||
| 2617 | |||
| 2618 | clks = cc->clks; | ||
| 2619 | data = &cc->data; | ||
| 2620 | data->clks = clks; | ||
| 2621 | data->clk_num = num_clks; | ||
| 2622 | 2714 | ||
| 2623 | /* Temporary until RPM clocks supported */ | 2715 | /* Temporary until RPM clocks supported */ |
| 2624 | clk = clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 19200000); | 2716 | clk = clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 19200000); |
| @@ -2631,39 +2723,12 @@ static int gcc_msm8974_probe(struct platform_device *pdev) | |||
| 2631 | if (IS_ERR(clk)) | 2723 | if (IS_ERR(clk)) |
| 2632 | return PTR_ERR(clk); | 2724 | return PTR_ERR(clk); |
| 2633 | 2725 | ||
| 2634 | for (i = 0; i < num_clks; i++) { | 2726 | return qcom_cc_probe(pdev, &gcc_msm8974_desc); |
| 2635 | if (!gcc_msm8974_clocks[i]) | ||
| 2636 | continue; | ||
| 2637 | clk = devm_clk_register_regmap(dev, gcc_msm8974_clocks[i]); | ||
| 2638 | if (IS_ERR(clk)) | ||
| 2639 | return PTR_ERR(clk); | ||
| 2640 | clks[i] = clk; | ||
| 2641 | } | ||
| 2642 | |||
| 2643 | ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); | ||
| 2644 | if (ret) | ||
| 2645 | return ret; | ||
| 2646 | |||
| 2647 | reset = &cc->reset; | ||
| 2648 | reset->rcdev.of_node = dev->of_node; | ||
| 2649 | reset->rcdev.ops = &qcom_reset_ops, | ||
| 2650 | reset->rcdev.owner = THIS_MODULE, | ||
| 2651 | reset->rcdev.nr_resets = ARRAY_SIZE(gcc_msm8974_resets), | ||
| 2652 | reset->regmap = regmap; | ||
| 2653 | reset->reset_map = gcc_msm8974_resets, | ||
| 2654 | platform_set_drvdata(pdev, &reset->rcdev); | ||
| 2655 | |||
| 2656 | ret = reset_controller_register(&reset->rcdev); | ||
| 2657 | if (ret) | ||
| 2658 | of_clk_del_provider(dev->of_node); | ||
| 2659 | |||
| 2660 | return ret; | ||
| 2661 | } | 2727 | } |
| 2662 | 2728 | ||
| 2663 | static int gcc_msm8974_remove(struct platform_device *pdev) | 2729 | static int gcc_msm8974_remove(struct platform_device *pdev) |
| 2664 | { | 2730 | { |
| 2665 | of_clk_del_provider(pdev->dev.of_node); | 2731 | qcom_cc_remove(pdev); |
| 2666 | reset_controller_unregister(platform_get_drvdata(pdev)); | ||
| 2667 | return 0; | 2732 | return 0; |
| 2668 | } | 2733 | } |
| 2669 | 2734 | ||
diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c index f9b59c7e48e9..12f3c0b64fcd 100644 --- a/drivers/clk/qcom/mmcc-msm8960.c +++ b/drivers/clk/qcom/mmcc-msm8960.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <dt-bindings/clock/qcom,mmcc-msm8960.h> | 26 | #include <dt-bindings/clock/qcom,mmcc-msm8960.h> |
| 27 | #include <dt-bindings/reset/qcom,mmcc-msm8960.h> | 27 | #include <dt-bindings/reset/qcom,mmcc-msm8960.h> |
| 28 | 28 | ||
| 29 | #include "common.h" | ||
| 29 | #include "clk-regmap.h" | 30 | #include "clk-regmap.h" |
| 30 | #include "clk-pll.h" | 31 | #include "clk-pll.h" |
| 31 | #include "clk-rcg.h" | 32 | #include "clk-rcg.h" |
| @@ -2222,85 +2223,28 @@ static const struct regmap_config mmcc_msm8960_regmap_config = { | |||
| 2222 | .fast_io = true, | 2223 | .fast_io = true, |
| 2223 | }; | 2224 | }; |
| 2224 | 2225 | ||
| 2226 | static const struct qcom_cc_desc mmcc_msm8960_desc = { | ||
| 2227 | .config = &mmcc_msm8960_regmap_config, | ||
| 2228 | .clks = mmcc_msm8960_clks, | ||
| 2229 | .num_clks = ARRAY_SIZE(mmcc_msm8960_clks), | ||
| 2230 | .resets = mmcc_msm8960_resets, | ||
| 2231 | .num_resets = ARRAY_SIZE(mmcc_msm8960_resets), | ||
| 2232 | }; | ||
| 2233 | |||
| 2225 | static const struct of_device_id mmcc_msm8960_match_table[] = { | 2234 | static const struct of_device_id mmcc_msm8960_match_table[] = { |
| 2226 | { .compatible = "qcom,mmcc-msm8960" }, | 2235 | { .compatible = "qcom,mmcc-msm8960" }, |
| 2227 | { } | 2236 | { } |
| 2228 | }; | 2237 | }; |
| 2229 | MODULE_DEVICE_TABLE(of, mmcc_msm8960_match_table); | 2238 | MODULE_DEVICE_TABLE(of, mmcc_msm8960_match_table); |
| 2230 | 2239 | ||
| 2231 | struct qcom_cc { | ||
| 2232 | struct qcom_reset_controller reset; | ||
| 2233 | struct clk_onecell_data data; | ||
| 2234 | struct clk *clks[]; | ||
| 2235 | }; | ||
| 2236 | |||
| 2237 | static int mmcc_msm8960_probe(struct platform_device *pdev) | 2240 | static int mmcc_msm8960_probe(struct platform_device *pdev) |
| 2238 | { | 2241 | { |
| 2239 | void __iomem *base; | 2242 | return qcom_cc_probe(pdev, &mmcc_msm8960_desc); |
| 2240 | struct resource *res; | ||
| 2241 | int i, ret; | ||
| 2242 | struct device *dev = &pdev->dev; | ||
| 2243 | struct clk *clk; | ||
| 2244 | struct clk_onecell_data *data; | ||
| 2245 | struct clk **clks; | ||
| 2246 | struct regmap *regmap; | ||
| 2247 | size_t num_clks; | ||
| 2248 | struct qcom_reset_controller *reset; | ||
| 2249 | struct qcom_cc *cc; | ||
| 2250 | |||
| 2251 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 2252 | base = devm_ioremap_resource(dev, res); | ||
| 2253 | if (IS_ERR(base)) | ||
| 2254 | return PTR_ERR(base); | ||
| 2255 | |||
| 2256 | regmap = devm_regmap_init_mmio(dev, base, &mmcc_msm8960_regmap_config); | ||
| 2257 | if (IS_ERR(regmap)) | ||
| 2258 | return PTR_ERR(regmap); | ||
| 2259 | |||
| 2260 | num_clks = ARRAY_SIZE(mmcc_msm8960_clks); | ||
| 2261 | cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, | ||
| 2262 | GFP_KERNEL); | ||
| 2263 | if (!cc) | ||
| 2264 | return -ENOMEM; | ||
| 2265 | |||
| 2266 | clks = cc->clks; | ||
| 2267 | data = &cc->data; | ||
| 2268 | data->clks = clks; | ||
| 2269 | data->clk_num = num_clks; | ||
| 2270 | |||
| 2271 | for (i = 0; i < num_clks; i++) { | ||
| 2272 | if (!mmcc_msm8960_clks[i]) | ||
| 2273 | continue; | ||
| 2274 | clk = devm_clk_register_regmap(dev, mmcc_msm8960_clks[i]); | ||
| 2275 | if (IS_ERR(clk)) | ||
| 2276 | return PTR_ERR(clk); | ||
| 2277 | clks[i] = clk; | ||
| 2278 | } | ||
| 2279 | |||
| 2280 | ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); | ||
| 2281 | if (ret) | ||
| 2282 | return ret; | ||
| 2283 | |||
| 2284 | reset = &cc->reset; | ||
| 2285 | reset->rcdev.of_node = dev->of_node; | ||
| 2286 | reset->rcdev.ops = &qcom_reset_ops, | ||
| 2287 | reset->rcdev.owner = THIS_MODULE, | ||
| 2288 | reset->rcdev.nr_resets = ARRAY_SIZE(mmcc_msm8960_resets), | ||
| 2289 | reset->regmap = regmap; | ||
| 2290 | reset->reset_map = mmcc_msm8960_resets, | ||
| 2291 | platform_set_drvdata(pdev, &reset->rcdev); | ||
| 2292 | |||
| 2293 | ret = reset_controller_register(&reset->rcdev); | ||
| 2294 | if (ret) | ||
| 2295 | of_clk_del_provider(dev->of_node); | ||
| 2296 | |||
| 2297 | return ret; | ||
| 2298 | } | 2243 | } |
| 2299 | 2244 | ||
| 2300 | static int mmcc_msm8960_remove(struct platform_device *pdev) | 2245 | static int mmcc_msm8960_remove(struct platform_device *pdev) |
| 2301 | { | 2246 | { |
| 2302 | of_clk_del_provider(pdev->dev.of_node); | 2247 | qcom_cc_remove(pdev); |
| 2303 | reset_controller_unregister(platform_get_drvdata(pdev)); | ||
| 2304 | return 0; | 2248 | return 0; |
| 2305 | } | 2249 | } |
| 2306 | 2250 | ||
diff --git a/drivers/clk/qcom/mmcc-msm8974.c b/drivers/clk/qcom/mmcc-msm8974.c index c95774514b81..c65b90515872 100644 --- a/drivers/clk/qcom/mmcc-msm8974.c +++ b/drivers/clk/qcom/mmcc-msm8974.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <dt-bindings/clock/qcom,mmcc-msm8974.h> | 25 | #include <dt-bindings/clock/qcom,mmcc-msm8974.h> |
| 26 | #include <dt-bindings/reset/qcom,mmcc-msm8974.h> | 26 | #include <dt-bindings/reset/qcom,mmcc-msm8974.h> |
| 27 | 27 | ||
| 28 | #include "common.h" | ||
| 28 | #include "clk-regmap.h" | 29 | #include "clk-regmap.h" |
| 29 | #include "clk-pll.h" | 30 | #include "clk-pll.h" |
| 30 | #include "clk-rcg.h" | 31 | #include "clk-rcg.h" |
| @@ -40,9 +41,11 @@ | |||
| 40 | #define P_EDPVCO 3 | 41 | #define P_EDPVCO 3 |
| 41 | #define P_GPLL1 4 | 42 | #define P_GPLL1 4 |
| 42 | #define P_DSI0PLL 4 | 43 | #define P_DSI0PLL 4 |
| 44 | #define P_DSI0PLL_BYTE 4 | ||
| 43 | #define P_MMPLL2 4 | 45 | #define P_MMPLL2 4 |
| 44 | #define P_MMPLL3 4 | 46 | #define P_MMPLL3 4 |
| 45 | #define P_DSI1PLL 5 | 47 | #define P_DSI1PLL 5 |
| 48 | #define P_DSI1PLL_BYTE 5 | ||
| 46 | 49 | ||
| 47 | static const u8 mmcc_xo_mmpll0_mmpll1_gpll0_map[] = { | 50 | static const u8 mmcc_xo_mmpll0_mmpll1_gpll0_map[] = { |
| 48 | [P_XO] = 0, | 51 | [P_XO] = 0, |
| @@ -160,6 +163,24 @@ static const char *mmcc_xo_dsi_hdmi_edp_gpll0[] = { | |||
| 160 | "dsi1pll", | 163 | "dsi1pll", |
| 161 | }; | 164 | }; |
| 162 | 165 | ||
| 166 | static const u8 mmcc_xo_dsibyte_hdmi_edp_gpll0_map[] = { | ||
| 167 | [P_XO] = 0, | ||
| 168 | [P_EDPLINK] = 4, | ||
| 169 | [P_HDMIPLL] = 3, | ||
| 170 | [P_GPLL0] = 5, | ||
| 171 | [P_DSI0PLL_BYTE] = 1, | ||
| 172 | [P_DSI1PLL_BYTE] = 2, | ||
| 173 | }; | ||
| 174 | |||
| 175 | static const char *mmcc_xo_dsibyte_hdmi_edp_gpll0[] = { | ||
| 176 | "xo", | ||
| 177 | "edp_link_clk", | ||
| 178 | "hdmipll", | ||
| 179 | "gpll0_vote", | ||
| 180 | "dsi0pllbyte", | ||
| 181 | "dsi1pllbyte", | ||
| 182 | }; | ||
| 183 | |||
| 163 | #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } | 184 | #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } |
| 164 | 185 | ||
| 165 | static struct clk_pll mmpll0 = { | 186 | static struct clk_pll mmpll0 = { |
| @@ -169,6 +190,7 @@ static struct clk_pll mmpll0 = { | |||
| 169 | .config_reg = 0x0014, | 190 | .config_reg = 0x0014, |
| 170 | .mode_reg = 0x0000, | 191 | .mode_reg = 0x0000, |
| 171 | .status_reg = 0x001c, | 192 | .status_reg = 0x001c, |
| 193 | .status_bit = 17, | ||
| 172 | .clkr.hw.init = &(struct clk_init_data){ | 194 | .clkr.hw.init = &(struct clk_init_data){ |
| 173 | .name = "mmpll0", | 195 | .name = "mmpll0", |
| 174 | .parent_names = (const char *[]){ "xo" }, | 196 | .parent_names = (const char *[]){ "xo" }, |
| @@ -192,9 +214,10 @@ static struct clk_pll mmpll1 = { | |||
| 192 | .l_reg = 0x0044, | 214 | .l_reg = 0x0044, |
| 193 | .m_reg = 0x0048, | 215 | .m_reg = 0x0048, |
| 194 | .n_reg = 0x004c, | 216 | .n_reg = 0x004c, |
| 195 | .config_reg = 0x0054, | 217 | .config_reg = 0x0050, |
| 196 | .mode_reg = 0x0040, | 218 | .mode_reg = 0x0040, |
| 197 | .status_reg = 0x005c, | 219 | .status_reg = 0x005c, |
| 220 | .status_bit = 17, | ||
| 198 | .clkr.hw.init = &(struct clk_init_data){ | 221 | .clkr.hw.init = &(struct clk_init_data){ |
| 199 | .name = "mmpll1", | 222 | .name = "mmpll1", |
| 200 | .parent_names = (const char *[]){ "xo" }, | 223 | .parent_names = (const char *[]){ "xo" }, |
| @@ -218,7 +241,7 @@ static struct clk_pll mmpll2 = { | |||
| 218 | .l_reg = 0x4104, | 241 | .l_reg = 0x4104, |
| 219 | .m_reg = 0x4108, | 242 | .m_reg = 0x4108, |
| 220 | .n_reg = 0x410c, | 243 | .n_reg = 0x410c, |
| 221 | .config_reg = 0x4114, | 244 | .config_reg = 0x4110, |
| 222 | .mode_reg = 0x4100, | 245 | .mode_reg = 0x4100, |
| 223 | .status_reg = 0x411c, | 246 | .status_reg = 0x411c, |
| 224 | .clkr.hw.init = &(struct clk_init_data){ | 247 | .clkr.hw.init = &(struct clk_init_data){ |
| @@ -233,9 +256,10 @@ static struct clk_pll mmpll3 = { | |||
| 233 | .l_reg = 0x0084, | 256 | .l_reg = 0x0084, |
| 234 | .m_reg = 0x0088, | 257 | .m_reg = 0x0088, |
| 235 | .n_reg = 0x008c, | 258 | .n_reg = 0x008c, |
| 236 | .config_reg = 0x0094, | 259 | .config_reg = 0x0090, |
| 237 | .mode_reg = 0x0080, | 260 | .mode_reg = 0x0080, |
| 238 | .status_reg = 0x009c, | 261 | .status_reg = 0x009c, |
| 262 | .status_bit = 17, | ||
| 239 | .clkr.hw.init = &(struct clk_init_data){ | 263 | .clkr.hw.init = &(struct clk_init_data){ |
| 240 | .name = "mmpll3", | 264 | .name = "mmpll3", |
| 241 | .parent_names = (const char *[]){ "xo" }, | 265 | .parent_names = (const char *[]){ "xo" }, |
| @@ -496,15 +520,8 @@ static struct clk_rcg2 jpeg2_clk_src = { | |||
| 496 | }, | 520 | }, |
| 497 | }; | 521 | }; |
| 498 | 522 | ||
| 499 | static struct freq_tbl ftbl_mdss_pclk0_clk[] = { | 523 | static struct freq_tbl pixel_freq_tbl[] = { |
| 500 | F(125000000, P_DSI0PLL, 2, 0, 0), | 524 | { .src = P_DSI0PLL }, |
| 501 | F(250000000, P_DSI0PLL, 1, 0, 0), | ||
| 502 | { } | ||
| 503 | }; | ||
| 504 | |||
| 505 | static struct freq_tbl ftbl_mdss_pclk1_clk[] = { | ||
| 506 | F(125000000, P_DSI1PLL, 2, 0, 0), | ||
| 507 | F(250000000, P_DSI1PLL, 1, 0, 0), | ||
| 508 | { } | 525 | { } |
| 509 | }; | 526 | }; |
| 510 | 527 | ||
| @@ -513,12 +530,13 @@ static struct clk_rcg2 pclk0_clk_src = { | |||
| 513 | .mnd_width = 8, | 530 | .mnd_width = 8, |
| 514 | .hid_width = 5, | 531 | .hid_width = 5, |
| 515 | .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map, | 532 | .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map, |
| 516 | .freq_tbl = ftbl_mdss_pclk0_clk, | 533 | .freq_tbl = pixel_freq_tbl, |
| 517 | .clkr.hw.init = &(struct clk_init_data){ | 534 | .clkr.hw.init = &(struct clk_init_data){ |
| 518 | .name = "pclk0_clk_src", | 535 | .name = "pclk0_clk_src", |
| 519 | .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, | 536 | .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, |
| 520 | .num_parents = 6, | 537 | .num_parents = 6, |
| 521 | .ops = &clk_rcg2_ops, | 538 | .ops = &clk_pixel_ops, |
| 539 | .flags = CLK_SET_RATE_PARENT, | ||
| 522 | }, | 540 | }, |
| 523 | }; | 541 | }; |
| 524 | 542 | ||
| @@ -527,12 +545,13 @@ static struct clk_rcg2 pclk1_clk_src = { | |||
| 527 | .mnd_width = 8, | 545 | .mnd_width = 8, |
| 528 | .hid_width = 5, | 546 | .hid_width = 5, |
| 529 | .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map, | 547 | .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map, |
| 530 | .freq_tbl = ftbl_mdss_pclk1_clk, | 548 | .freq_tbl = pixel_freq_tbl, |
| 531 | .clkr.hw.init = &(struct clk_init_data){ | 549 | .clkr.hw.init = &(struct clk_init_data){ |
| 532 | .name = "pclk1_clk_src", | 550 | .name = "pclk1_clk_src", |
| 533 | .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, | 551 | .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, |
| 534 | .num_parents = 6, | 552 | .num_parents = 6, |
| 535 | .ops = &clk_rcg2_ops, | 553 | .ops = &clk_pixel_ops, |
| 554 | .flags = CLK_SET_RATE_PARENT, | ||
| 536 | }, | 555 | }, |
| 537 | }; | 556 | }; |
| 538 | 557 | ||
| @@ -750,41 +769,36 @@ static struct clk_rcg2 cpp_clk_src = { | |||
| 750 | }, | 769 | }, |
| 751 | }; | 770 | }; |
| 752 | 771 | ||
| 753 | static struct freq_tbl ftbl_mdss_byte0_clk[] = { | 772 | static struct freq_tbl byte_freq_tbl[] = { |
| 754 | F(93750000, P_DSI0PLL, 8, 0, 0), | 773 | { .src = P_DSI0PLL_BYTE }, |
| 755 | F(187500000, P_DSI0PLL, 4, 0, 0), | ||
| 756 | { } | ||
| 757 | }; | ||
| 758 | |||
| 759 | static struct freq_tbl ftbl_mdss_byte1_clk[] = { | ||
| 760 | F(93750000, P_DSI1PLL, 8, 0, 0), | ||
| 761 | F(187500000, P_DSI1PLL, 4, 0, 0), | ||
| 762 | { } | 774 | { } |
| 763 | }; | 775 | }; |
| 764 | 776 | ||
| 765 | static struct clk_rcg2 byte0_clk_src = { | 777 | static struct clk_rcg2 byte0_clk_src = { |
| 766 | .cmd_rcgr = 0x2120, | 778 | .cmd_rcgr = 0x2120, |
| 767 | .hid_width = 5, | 779 | .hid_width = 5, |
| 768 | .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map, | 780 | .parent_map = mmcc_xo_dsibyte_hdmi_edp_gpll0_map, |
| 769 | .freq_tbl = ftbl_mdss_byte0_clk, | 781 | .freq_tbl = byte_freq_tbl, |
| 770 | .clkr.hw.init = &(struct clk_init_data){ | 782 | .clkr.hw.init = &(struct clk_init_data){ |
| 771 | .name = "byte0_clk_src", | 783 | .name = "byte0_clk_src", |
| 772 | .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, | 784 | .parent_names = mmcc_xo_dsibyte_hdmi_edp_gpll0, |
| 773 | .num_parents = 6, | 785 | .num_parents = 6, |
| 774 | .ops = &clk_rcg2_ops, | 786 | .ops = &clk_byte_ops, |
| 787 | .flags = CLK_SET_RATE_PARENT, | ||
| 775 | }, | 788 | }, |
| 776 | }; | 789 | }; |
| 777 | 790 | ||
| 778 | static struct clk_rcg2 byte1_clk_src = { | 791 | static struct clk_rcg2 byte1_clk_src = { |
| 779 | .cmd_rcgr = 0x2140, | 792 | .cmd_rcgr = 0x2140, |
| 780 | .hid_width = 5, | 793 | .hid_width = 5, |
| 781 | .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map, | 794 | .parent_map = mmcc_xo_dsibyte_hdmi_edp_gpll0_map, |
| 782 | .freq_tbl = ftbl_mdss_byte1_clk, | 795 | .freq_tbl = byte_freq_tbl, |
| 783 | .clkr.hw.init = &(struct clk_init_data){ | 796 | .clkr.hw.init = &(struct clk_init_data){ |
| 784 | .name = "byte1_clk_src", | 797 | .name = "byte1_clk_src", |
| 785 | .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, | 798 | .parent_names = mmcc_xo_dsibyte_hdmi_edp_gpll0, |
| 786 | .num_parents = 6, | 799 | .num_parents = 6, |
| 787 | .ops = &clk_rcg2_ops, | 800 | .ops = &clk_byte_ops, |
| 801 | .flags = CLK_SET_RATE_PARENT, | ||
| 788 | }, | 802 | }, |
| 789 | }; | 803 | }; |
| 790 | 804 | ||
| @@ -822,12 +836,12 @@ static struct clk_rcg2 edplink_clk_src = { | |||
| 822 | .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, | 836 | .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, |
| 823 | .num_parents = 6, | 837 | .num_parents = 6, |
| 824 | .ops = &clk_rcg2_ops, | 838 | .ops = &clk_rcg2_ops, |
| 839 | .flags = CLK_SET_RATE_PARENT, | ||
| 825 | }, | 840 | }, |
| 826 | }; | 841 | }; |
| 827 | 842 | ||
| 828 | static struct freq_tbl ftbl_mdss_edppixel_clk[] = { | 843 | static struct freq_tbl edp_pixel_freq_tbl[] = { |
| 829 | F(175000000, P_EDPVCO, 2, 0, 0), | 844 | { .src = P_EDPVCO }, |
| 830 | F(350000000, P_EDPVCO, 11, 0, 0), | ||
| 831 | { } | 845 | { } |
| 832 | }; | 846 | }; |
| 833 | 847 | ||
| @@ -836,12 +850,12 @@ static struct clk_rcg2 edppixel_clk_src = { | |||
| 836 | .mnd_width = 8, | 850 | .mnd_width = 8, |
| 837 | .hid_width = 5, | 851 | .hid_width = 5, |
| 838 | .parent_map = mmcc_xo_dsi_hdmi_edp_map, | 852 | .parent_map = mmcc_xo_dsi_hdmi_edp_map, |
| 839 | .freq_tbl = ftbl_mdss_edppixel_clk, | 853 | .freq_tbl = edp_pixel_freq_tbl, |
| 840 | .clkr.hw.init = &(struct clk_init_data){ | 854 | .clkr.hw.init = &(struct clk_init_data){ |
| 841 | .name = "edppixel_clk_src", | 855 | .name = "edppixel_clk_src", |
| 842 | .parent_names = mmcc_xo_dsi_hdmi_edp, | 856 | .parent_names = mmcc_xo_dsi_hdmi_edp, |
| 843 | .num_parents = 6, | 857 | .num_parents = 6, |
| 844 | .ops = &clk_rcg2_ops, | 858 | .ops = &clk_edp_pixel_ops, |
| 845 | }, | 859 | }, |
| 846 | }; | 860 | }; |
| 847 | 861 | ||
| @@ -853,11 +867,11 @@ static struct freq_tbl ftbl_mdss_esc0_1_clk[] = { | |||
| 853 | static struct clk_rcg2 esc0_clk_src = { | 867 | static struct clk_rcg2 esc0_clk_src = { |
| 854 | .cmd_rcgr = 0x2160, | 868 | .cmd_rcgr = 0x2160, |
| 855 | .hid_width = 5, | 869 | .hid_width = 5, |
| 856 | .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map, | 870 | .parent_map = mmcc_xo_dsibyte_hdmi_edp_gpll0_map, |
| 857 | .freq_tbl = ftbl_mdss_esc0_1_clk, | 871 | .freq_tbl = ftbl_mdss_esc0_1_clk, |
| 858 | .clkr.hw.init = &(struct clk_init_data){ | 872 | .clkr.hw.init = &(struct clk_init_data){ |
| 859 | .name = "esc0_clk_src", | 873 | .name = "esc0_clk_src", |
| 860 | .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, | 874 | .parent_names = mmcc_xo_dsibyte_hdmi_edp_gpll0, |
| 861 | .num_parents = 6, | 875 | .num_parents = 6, |
| 862 | .ops = &clk_rcg2_ops, | 876 | .ops = &clk_rcg2_ops, |
| 863 | }, | 877 | }, |
| @@ -866,26 +880,18 @@ static struct clk_rcg2 esc0_clk_src = { | |||
| 866 | static struct clk_rcg2 esc1_clk_src = { | 880 | static struct clk_rcg2 esc1_clk_src = { |
| 867 | .cmd_rcgr = 0x2180, | 881 | .cmd_rcgr = 0x2180, |
| 868 | .hid_width = 5, | 882 | .hid_width = 5, |
| 869 | .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map, | 883 | .parent_map = mmcc_xo_dsibyte_hdmi_edp_gpll0_map, |
| 870 | .freq_tbl = ftbl_mdss_esc0_1_clk, | 884 | .freq_tbl = ftbl_mdss_esc0_1_clk, |
| 871 | .clkr.hw.init = &(struct clk_init_data){ | 885 | .clkr.hw.init = &(struct clk_init_data){ |
| 872 | .name = "esc1_clk_src", | 886 | .name = "esc1_clk_src", |
| 873 | .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, | 887 | .parent_names = mmcc_xo_dsibyte_hdmi_edp_gpll0, |
| 874 | .num_parents = 6, | 888 | .num_parents = 6, |
| 875 | .ops = &clk_rcg2_ops, | 889 | .ops = &clk_rcg2_ops, |
| 876 | }, | 890 | }, |
| 877 | }; | 891 | }; |
| 878 | 892 | ||
| 879 | static struct freq_tbl ftbl_mdss_extpclk_clk[] = { | 893 | static struct freq_tbl extpclk_freq_tbl[] = { |
| 880 | F(25200000, P_HDMIPLL, 1, 0, 0), | 894 | { .src = P_HDMIPLL }, |
| 881 | F(27000000, P_HDMIPLL, 1, 0, 0), | ||
| 882 | F(27030000, P_HDMIPLL, 1, 0, 0), | ||
| 883 | F(65000000, P_HDMIPLL, 1, 0, 0), | ||
| 884 | F(74250000, P_HDMIPLL, 1, 0, 0), | ||
| 885 | F(108000000, P_HDMIPLL, 1, 0, 0), | ||
| 886 | F(148500000, P_HDMIPLL, 1, 0, 0), | ||
| 887 | F(268500000, P_HDMIPLL, 1, 0, 0), | ||
| 888 | F(297000000, P_HDMIPLL, 1, 0, 0), | ||
| 889 | { } | 895 | { } |
| 890 | }; | 896 | }; |
| 891 | 897 | ||
| @@ -893,12 +899,13 @@ static struct clk_rcg2 extpclk_clk_src = { | |||
| 893 | .cmd_rcgr = 0x2060, | 899 | .cmd_rcgr = 0x2060, |
| 894 | .hid_width = 5, | 900 | .hid_width = 5, |
| 895 | .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map, | 901 | .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map, |
| 896 | .freq_tbl = ftbl_mdss_extpclk_clk, | 902 | .freq_tbl = extpclk_freq_tbl, |
| 897 | .clkr.hw.init = &(struct clk_init_data){ | 903 | .clkr.hw.init = &(struct clk_init_data){ |
| 898 | .name = "extpclk_clk_src", | 904 | .name = "extpclk_clk_src", |
| 899 | .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, | 905 | .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, |
| 900 | .num_parents = 6, | 906 | .num_parents = 6, |
| 901 | .ops = &clk_rcg2_ops, | 907 | .ops = &clk_byte_ops, |
| 908 | .flags = CLK_SET_RATE_PARENT, | ||
| 902 | }, | 909 | }, |
| 903 | }; | 910 | }; |
| 904 | 911 | ||
| @@ -2318,7 +2325,7 @@ static const struct pll_config mmpll1_config = { | |||
| 2318 | .vco_val = 0x0, | 2325 | .vco_val = 0x0, |
| 2319 | .vco_mask = 0x3 << 20, | 2326 | .vco_mask = 0x3 << 20, |
| 2320 | .pre_div_val = 0x0, | 2327 | .pre_div_val = 0x0, |
| 2321 | .pre_div_mask = 0x3 << 12, | 2328 | .pre_div_mask = 0x7 << 12, |
| 2322 | .post_div_val = 0x0, | 2329 | .post_div_val = 0x0, |
| 2323 | .post_div_mask = 0x3 << 8, | 2330 | .post_div_mask = 0x3 << 8, |
| 2324 | .mn_ena_mask = BIT(24), | 2331 | .mn_ena_mask = BIT(24), |
| @@ -2332,7 +2339,7 @@ static struct pll_config mmpll3_config = { | |||
| 2332 | .vco_val = 0x0, | 2339 | .vco_val = 0x0, |
| 2333 | .vco_mask = 0x3 << 20, | 2340 | .vco_mask = 0x3 << 20, |
| 2334 | .pre_div_val = 0x0, | 2341 | .pre_div_val = 0x0, |
| 2335 | .pre_div_mask = 0x3 << 12, | 2342 | .pre_div_mask = 0x7 << 12, |
| 2336 | .post_div_val = 0x0, | 2343 | .post_div_val = 0x0, |
| 2337 | .post_div_mask = 0x3 << 8, | 2344 | .post_div_mask = 0x3 << 8, |
| 2338 | .mn_ena_mask = BIT(24), | 2345 | .mn_ena_mask = BIT(24), |
| @@ -2524,88 +2531,39 @@ static const struct regmap_config mmcc_msm8974_regmap_config = { | |||
| 2524 | .fast_io = true, | 2531 | .fast_io = true, |
| 2525 | }; | 2532 | }; |
| 2526 | 2533 | ||
| 2534 | static const struct qcom_cc_desc mmcc_msm8974_desc = { | ||
| 2535 | .config = &mmcc_msm8974_regmap_config, | ||
| 2536 | .clks = mmcc_msm8974_clocks, | ||
| 2537 | .num_clks = ARRAY_SIZE(mmcc_msm8974_clocks), | ||
| 2538 | .resets = mmcc_msm8974_resets, | ||
| 2539 | .num_resets = ARRAY_SIZE(mmcc_msm8974_resets), | ||
| 2540 | }; | ||
| 2541 | |||
| 2527 | static const struct of_device_id mmcc_msm8974_match_table[] = { | 2542 | static const struct of_device_id mmcc_msm8974_match_table[] = { |
| 2528 | { .compatible = "qcom,mmcc-msm8974" }, | 2543 | { .compatible = "qcom,mmcc-msm8974" }, |
| 2529 | { } | 2544 | { } |
| 2530 | }; | 2545 | }; |
| 2531 | MODULE_DEVICE_TABLE(of, mmcc_msm8974_match_table); | 2546 | MODULE_DEVICE_TABLE(of, mmcc_msm8974_match_table); |
| 2532 | 2547 | ||
| 2533 | struct qcom_cc { | ||
| 2534 | struct qcom_reset_controller reset; | ||
| 2535 | struct clk_onecell_data data; | ||
| 2536 | struct clk *clks[]; | ||
| 2537 | }; | ||
| 2538 | |||
| 2539 | static int mmcc_msm8974_probe(struct platform_device *pdev) | 2548 | static int mmcc_msm8974_probe(struct platform_device *pdev) |
| 2540 | { | 2549 | { |
| 2541 | void __iomem *base; | 2550 | int ret; |
| 2542 | struct resource *res; | ||
| 2543 | int i, ret; | ||
| 2544 | struct device *dev = &pdev->dev; | ||
| 2545 | struct clk *clk; | ||
| 2546 | struct clk_onecell_data *data; | ||
| 2547 | struct clk **clks; | ||
| 2548 | struct regmap *regmap; | 2551 | struct regmap *regmap; |
| 2549 | size_t num_clks; | ||
| 2550 | struct qcom_reset_controller *reset; | ||
| 2551 | struct qcom_cc *cc; | ||
| 2552 | |||
| 2553 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 2554 | base = devm_ioremap_resource(dev, res); | ||
| 2555 | if (IS_ERR(base)) | ||
| 2556 | return PTR_ERR(base); | ||
| 2557 | |||
| 2558 | regmap = devm_regmap_init_mmio(dev, base, &mmcc_msm8974_regmap_config); | ||
| 2559 | if (IS_ERR(regmap)) | ||
| 2560 | return PTR_ERR(regmap); | ||
| 2561 | |||
| 2562 | num_clks = ARRAY_SIZE(mmcc_msm8974_clocks); | ||
| 2563 | cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, | ||
| 2564 | GFP_KERNEL); | ||
| 2565 | if (!cc) | ||
| 2566 | return -ENOMEM; | ||
| 2567 | |||
| 2568 | clks = cc->clks; | ||
| 2569 | data = &cc->data; | ||
| 2570 | data->clks = clks; | ||
| 2571 | data->clk_num = num_clks; | ||
| 2572 | |||
| 2573 | clk_pll_configure_sr_hpm_lp(&mmpll1, regmap, &mmpll1_config, true); | ||
| 2574 | clk_pll_configure_sr_hpm_lp(&mmpll3, regmap, &mmpll3_config, false); | ||
| 2575 | |||
| 2576 | for (i = 0; i < num_clks; i++) { | ||
| 2577 | if (!mmcc_msm8974_clocks[i]) | ||
| 2578 | continue; | ||
| 2579 | clk = devm_clk_register_regmap(dev, mmcc_msm8974_clocks[i]); | ||
| 2580 | if (IS_ERR(clk)) | ||
| 2581 | return PTR_ERR(clk); | ||
| 2582 | clks[i] = clk; | ||
| 2583 | } | ||
| 2584 | 2552 | ||
| 2585 | ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); | 2553 | ret = qcom_cc_probe(pdev, &mmcc_msm8974_desc); |
| 2586 | if (ret) | 2554 | if (ret) |
| 2587 | return ret; | 2555 | return ret; |
| 2588 | 2556 | ||
| 2589 | reset = &cc->reset; | 2557 | regmap = dev_get_regmap(&pdev->dev, NULL); |
| 2590 | reset->rcdev.of_node = dev->of_node; | 2558 | clk_pll_configure_sr_hpm_lp(&mmpll1, regmap, &mmpll1_config, true); |
| 2591 | reset->rcdev.ops = &qcom_reset_ops, | 2559 | clk_pll_configure_sr_hpm_lp(&mmpll3, regmap, &mmpll3_config, false); |
| 2592 | reset->rcdev.owner = THIS_MODULE, | ||
| 2593 | reset->rcdev.nr_resets = ARRAY_SIZE(mmcc_msm8974_resets), | ||
| 2594 | reset->regmap = regmap; | ||
| 2595 | reset->reset_map = mmcc_msm8974_resets, | ||
| 2596 | platform_set_drvdata(pdev, &reset->rcdev); | ||
| 2597 | |||
| 2598 | ret = reset_controller_register(&reset->rcdev); | ||
| 2599 | if (ret) | ||
| 2600 | of_clk_del_provider(dev->of_node); | ||
| 2601 | 2560 | ||
| 2602 | return ret; | 2561 | return 0; |
| 2603 | } | 2562 | } |
| 2604 | 2563 | ||
| 2605 | static int mmcc_msm8974_remove(struct platform_device *pdev) | 2564 | static int mmcc_msm8974_remove(struct platform_device *pdev) |
| 2606 | { | 2565 | { |
| 2607 | of_clk_del_provider(pdev->dev.of_node); | 2566 | qcom_cc_remove(pdev); |
| 2608 | reset_controller_unregister(platform_get_drvdata(pdev)); | ||
| 2609 | return 0; | 2567 | return 0; |
| 2610 | } | 2568 | } |
| 2611 | 2569 | ||
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index c4df294bb7fb..4f150c9dd38c 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c | |||
| @@ -324,7 +324,7 @@ static struct syscore_ops exynos4_clk_syscore_ops = { | |||
| 324 | .resume = exynos4_clk_resume, | 324 | .resume = exynos4_clk_resume, |
| 325 | }; | 325 | }; |
| 326 | 326 | ||
| 327 | static void exynos4_clk_sleep_init(void) | 327 | static void __init exynos4_clk_sleep_init(void) |
| 328 | { | 328 | { |
| 329 | exynos4_save_common = samsung_clk_alloc_reg_dump(exynos4_clk_regs, | 329 | exynos4_save_common = samsung_clk_alloc_reg_dump(exynos4_clk_regs, |
| 330 | ARRAY_SIZE(exynos4_clk_regs)); | 330 | ARRAY_SIZE(exynos4_clk_regs)); |
| @@ -359,7 +359,7 @@ err_warn: | |||
| 359 | __func__); | 359 | __func__); |
| 360 | } | 360 | } |
| 361 | #else | 361 | #else |
| 362 | static void exynos4_clk_sleep_init(void) {} | 362 | static void __init exynos4_clk_sleep_init(void) {} |
| 363 | #endif | 363 | #endif |
| 364 | 364 | ||
| 365 | /* list of all parent clock list */ | 365 | /* list of all parent clock list */ |
diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile index 5404cb931ebf..e0029237827a 100644 --- a/drivers/clk/shmobile/Makefile +++ b/drivers/clk/shmobile/Makefile | |||
| @@ -1,5 +1,7 @@ | |||
| 1 | obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o | 1 | obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o |
| 2 | obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o | 2 | obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o |
| 3 | obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o | ||
| 4 | obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o | ||
| 3 | obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o | 5 | obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o |
| 4 | obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o | 6 | obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o |
| 5 | obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o | 7 | obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o |
diff --git a/drivers/clk/shmobile/clk-mstp.c b/drivers/clk/shmobile/clk-mstp.c index 1f6324e29a80..2d2fe773ac81 100644 --- a/drivers/clk/shmobile/clk-mstp.c +++ b/drivers/clk/shmobile/clk-mstp.c | |||
| @@ -112,7 +112,7 @@ static int cpg_mstp_clock_is_enabled(struct clk_hw *hw) | |||
| 112 | else | 112 | else |
| 113 | value = clk_readl(group->smstpcr); | 113 | value = clk_readl(group->smstpcr); |
| 114 | 114 | ||
| 115 | return !!(value & BIT(clock->bit_index)); | 115 | return !(value & BIT(clock->bit_index)); |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | static const struct clk_ops cpg_mstp_clock_ops = { | 118 | static const struct clk_ops cpg_mstp_clock_ops = { |
diff --git a/drivers/clk/shmobile/clk-r8a7740.c b/drivers/clk/shmobile/clk-r8a7740.c new file mode 100644 index 000000000000..1e2eaae21e01 --- /dev/null +++ b/drivers/clk/shmobile/clk-r8a7740.c | |||
| @@ -0,0 +1,199 @@ | |||
| 1 | /* | ||
| 2 | * r8a7740 Core CPG Clocks | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Ulrich Hecht | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; version 2 of the License. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/clk-provider.h> | ||
| 12 | #include <linux/clkdev.h> | ||
| 13 | #include <linux/clk/shmobile.h> | ||
| 14 | #include <linux/init.h> | ||
| 15 | #include <linux/kernel.h> | ||
| 16 | #include <linux/of.h> | ||
| 17 | #include <linux/of_address.h> | ||
| 18 | #include <linux/spinlock.h> | ||
| 19 | |||
| 20 | struct r8a7740_cpg { | ||
| 21 | struct clk_onecell_data data; | ||
| 22 | spinlock_t lock; | ||
| 23 | void __iomem *reg; | ||
| 24 | }; | ||
| 25 | |||
| 26 | #define CPG_FRQCRA 0x00 | ||
| 27 | #define CPG_FRQCRB 0x04 | ||
| 28 | #define CPG_PLLC2CR 0x2c | ||
| 29 | #define CPG_USBCKCR 0x8c | ||
| 30 | #define CPG_FRQCRC 0xe0 | ||
| 31 | |||
| 32 | #define CLK_ENABLE_ON_INIT BIT(0) | ||
| 33 | |||
| 34 | struct div4_clk { | ||
| 35 | const char *name; | ||
| 36 | unsigned int reg; | ||
| 37 | unsigned int shift; | ||
| 38 | int flags; | ||
| 39 | }; | ||
| 40 | |||
| 41 | static struct div4_clk div4_clks[] = { | ||
| 42 | { "i", CPG_FRQCRA, 20, CLK_ENABLE_ON_INIT }, | ||
| 43 | { "zg", CPG_FRQCRA, 16, CLK_ENABLE_ON_INIT }, | ||
| 44 | { "b", CPG_FRQCRA, 8, CLK_ENABLE_ON_INIT }, | ||
| 45 | { "m1", CPG_FRQCRA, 4, CLK_ENABLE_ON_INIT }, | ||
| 46 | { "hp", CPG_FRQCRB, 4, 0 }, | ||
| 47 | { "hpp", CPG_FRQCRC, 20, 0 }, | ||
| 48 | { "usbp", CPG_FRQCRC, 16, 0 }, | ||
| 49 | { "s", CPG_FRQCRC, 12, 0 }, | ||
| 50 | { "zb", CPG_FRQCRC, 8, 0 }, | ||
| 51 | { "m3", CPG_FRQCRC, 4, 0 }, | ||
| 52 | { "cp", CPG_FRQCRC, 0, 0 }, | ||
| 53 | { NULL, 0, 0, 0 }, | ||
| 54 | }; | ||
| 55 | |||
| 56 | static const struct clk_div_table div4_div_table[] = { | ||
| 57 | { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 }, { 5, 12 }, | ||
| 58 | { 6, 16 }, { 7, 18 }, { 8, 24 }, { 9, 32 }, { 10, 36 }, { 11, 48 }, | ||
| 59 | { 13, 72 }, { 14, 96 }, { 0, 0 } | ||
| 60 | }; | ||
| 61 | |||
| 62 | static u32 cpg_mode __initdata; | ||
| 63 | |||
| 64 | static struct clk * __init | ||
| 65 | r8a7740_cpg_register_clock(struct device_node *np, struct r8a7740_cpg *cpg, | ||
| 66 | const char *name) | ||
| 67 | { | ||
| 68 | const struct clk_div_table *table = NULL; | ||
| 69 | const char *parent_name; | ||
| 70 | unsigned int shift, reg; | ||
| 71 | unsigned int mult = 1; | ||
| 72 | unsigned int div = 1; | ||
| 73 | |||
| 74 | if (!strcmp(name, "r")) { | ||
| 75 | switch (cpg_mode & (BIT(2) | BIT(1))) { | ||
| 76 | case BIT(1) | BIT(2): | ||
| 77 | /* extal1 */ | ||
| 78 | parent_name = of_clk_get_parent_name(np, 0); | ||
| 79 | div = 2048; | ||
| 80 | break; | ||
| 81 | case BIT(2): | ||
| 82 | /* extal1 */ | ||
| 83 | parent_name = of_clk_get_parent_name(np, 0); | ||
| 84 | div = 1024; | ||
| 85 | break; | ||
| 86 | default: | ||
| 87 | /* extalr */ | ||
| 88 | parent_name = of_clk_get_parent_name(np, 2); | ||
| 89 | break; | ||
| 90 | } | ||
| 91 | } else if (!strcmp(name, "system")) { | ||
| 92 | parent_name = of_clk_get_parent_name(np, 0); | ||
| 93 | if (cpg_mode & BIT(1)) | ||
| 94 | div = 2; | ||
| 95 | } else if (!strcmp(name, "pllc0")) { | ||
| 96 | /* PLLC0/1 are configurable multiplier clocks. Register them as | ||
| 97 | * fixed factor clocks for now as there's no generic multiplier | ||
| 98 | * clock implementation and we currently have no need to change | ||
| 99 | * the multiplier value. | ||
| 100 | */ | ||
| 101 | u32 value = clk_readl(cpg->reg + CPG_FRQCRC); | ||
| 102 | parent_name = "system"; | ||
| 103 | mult = ((value >> 24) & 0x7f) + 1; | ||
| 104 | } else if (!strcmp(name, "pllc1")) { | ||
| 105 | u32 value = clk_readl(cpg->reg + CPG_FRQCRA); | ||
| 106 | parent_name = "system"; | ||
| 107 | mult = ((value >> 24) & 0x7f) + 1; | ||
| 108 | div = 2; | ||
| 109 | } else if (!strcmp(name, "pllc2")) { | ||
| 110 | u32 value = clk_readl(cpg->reg + CPG_PLLC2CR); | ||
| 111 | parent_name = "system"; | ||
| 112 | mult = ((value >> 24) & 0x3f) + 1; | ||
| 113 | } else if (!strcmp(name, "usb24s")) { | ||
| 114 | u32 value = clk_readl(cpg->reg + CPG_USBCKCR); | ||
| 115 | if (value & BIT(7)) | ||
| 116 | /* extal2 */ | ||
| 117 | parent_name = of_clk_get_parent_name(np, 1); | ||
| 118 | else | ||
| 119 | parent_name = "system"; | ||
| 120 | if (!(value & BIT(6))) | ||
| 121 | div = 2; | ||
| 122 | } else { | ||
| 123 | struct div4_clk *c; | ||
| 124 | for (c = div4_clks; c->name; c++) { | ||
| 125 | if (!strcmp(name, c->name)) { | ||
| 126 | parent_name = "pllc1"; | ||
| 127 | table = div4_div_table; | ||
| 128 | reg = c->reg; | ||
| 129 | shift = c->shift; | ||
| 130 | break; | ||
| 131 | } | ||
| 132 | } | ||
| 133 | if (!c->name) | ||
| 134 | return ERR_PTR(-EINVAL); | ||
| 135 | } | ||
| 136 | |||
| 137 | if (!table) { | ||
| 138 | return clk_register_fixed_factor(NULL, name, parent_name, 0, | ||
| 139 | mult, div); | ||
| 140 | } else { | ||
| 141 | return clk_register_divider_table(NULL, name, parent_name, 0, | ||
| 142 | cpg->reg + reg, shift, 4, 0, | ||
| 143 | table, &cpg->lock); | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | static void __init r8a7740_cpg_clocks_init(struct device_node *np) | ||
| 148 | { | ||
| 149 | struct r8a7740_cpg *cpg; | ||
| 150 | struct clk **clks; | ||
| 151 | unsigned int i; | ||
| 152 | int num_clks; | ||
| 153 | |||
| 154 | if (of_property_read_u32(np, "renesas,mode", &cpg_mode)) | ||
| 155 | pr_warn("%s: missing renesas,mode property\n", __func__); | ||
| 156 | |||
| 157 | num_clks = of_property_count_strings(np, "clock-output-names"); | ||
| 158 | if (num_clks < 0) { | ||
| 159 | pr_err("%s: failed to count clocks\n", __func__); | ||
| 160 | return; | ||
| 161 | } | ||
| 162 | |||
| 163 | cpg = kzalloc(sizeof(*cpg), GFP_KERNEL); | ||
| 164 | clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL); | ||
| 165 | if (cpg == NULL || clks == NULL) { | ||
| 166 | /* We're leaking memory on purpose, there's no point in cleaning | ||
| 167 | * up as the system won't boot anyway. | ||
| 168 | */ | ||
| 169 | return; | ||
| 170 | } | ||
| 171 | |||
| 172 | spin_lock_init(&cpg->lock); | ||
| 173 | |||
| 174 | cpg->data.clks = clks; | ||
| 175 | cpg->data.clk_num = num_clks; | ||
| 176 | |||
| 177 | cpg->reg = of_iomap(np, 0); | ||
| 178 | if (WARN_ON(cpg->reg == NULL)) | ||
| 179 | return; | ||
| 180 | |||
| 181 | for (i = 0; i < num_clks; ++i) { | ||
| 182 | const char *name; | ||
| 183 | struct clk *clk; | ||
| 184 | |||
| 185 | of_property_read_string_index(np, "clock-output-names", i, | ||
| 186 | &name); | ||
| 187 | |||
| 188 | clk = r8a7740_cpg_register_clock(np, cpg, name); | ||
| 189 | if (IS_ERR(clk)) | ||
| 190 | pr_err("%s: failed to register %s %s clock (%ld)\n", | ||
| 191 | __func__, np->name, name, PTR_ERR(clk)); | ||
| 192 | else | ||
| 193 | cpg->data.clks[i] = clk; | ||
| 194 | } | ||
| 195 | |||
| 196 | of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data); | ||
| 197 | } | ||
| 198 | CLK_OF_DECLARE(r8a7740_cpg_clks, "renesas,r8a7740-cpg-clocks", | ||
| 199 | r8a7740_cpg_clocks_init); | ||
diff --git a/drivers/clk/shmobile/clk-r8a7779.c b/drivers/clk/shmobile/clk-r8a7779.c new file mode 100644 index 000000000000..652ecacb6daf --- /dev/null +++ b/drivers/clk/shmobile/clk-r8a7779.c | |||
| @@ -0,0 +1,180 @@ | |||
| 1 | /* | ||
| 2 | * r8a7779 Core CPG Clocks | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013, 2014 Horms Solutions Ltd. | ||
| 5 | * | ||
| 6 | * Contact: Simon Horman <horms@verge.net.au> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; version 2 of the License. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/clk-provider.h> | ||
| 14 | #include <linux/clkdev.h> | ||
| 15 | #include <linux/clk/shmobile.h> | ||
| 16 | #include <linux/init.h> | ||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/of.h> | ||
| 19 | #include <linux/of_address.h> | ||
| 20 | #include <linux/spinlock.h> | ||
| 21 | |||
| 22 | #include <dt-bindings/clock/r8a7779-clock.h> | ||
| 23 | |||
| 24 | #define CPG_NUM_CLOCKS (R8A7779_CLK_OUT + 1) | ||
| 25 | |||
| 26 | struct r8a7779_cpg { | ||
| 27 | struct clk_onecell_data data; | ||
| 28 | spinlock_t lock; | ||
| 29 | void __iomem *reg; | ||
| 30 | }; | ||
| 31 | |||
| 32 | /* ----------------------------------------------------------------------------- | ||
| 33 | * CPG Clock Data | ||
| 34 | */ | ||
| 35 | |||
| 36 | /* | ||
| 37 | * MD1 = 1 MD1 = 0 | ||
| 38 | * (PLLA = 1500) (PLLA = 1600) | ||
| 39 | * (MHz) (MHz) | ||
| 40 | *------------------------------------------------+-------------------- | ||
| 41 | * clkz 1000 (2/3) 800 (1/2) | ||
| 42 | * clkzs 250 (1/6) 200 (1/8) | ||
| 43 | * clki 750 (1/2) 800 (1/2) | ||
| 44 | * clks 250 (1/6) 200 (1/8) | ||
| 45 | * clks1 125 (1/12) 100 (1/16) | ||
| 46 | * clks3 187.5 (1/8) 200 (1/8) | ||
| 47 | * clks4 93.7 (1/16) 100 (1/16) | ||
| 48 | * clkp 62.5 (1/24) 50 (1/32) | ||
| 49 | * clkg 62.5 (1/24) 66.6 (1/24) | ||
| 50 | * clkb, CLKOUT | ||
| 51 | * (MD2 = 0) 62.5 (1/24) 66.6 (1/24) | ||
| 52 | * (MD2 = 1) 41.6 (1/36) 50 (1/32) | ||
| 53 | */ | ||
| 54 | |||
| 55 | #define CPG_CLK_CONFIG_INDEX(md) (((md) & (BIT(2)|BIT(1))) >> 1) | ||
| 56 | |||
| 57 | struct cpg_clk_config { | ||
| 58 | unsigned int z_mult; | ||
| 59 | unsigned int z_div; | ||
| 60 | unsigned int zs_and_s_div; | ||
| 61 | unsigned int s1_div; | ||
| 62 | unsigned int p_div; | ||
| 63 | unsigned int b_and_out_div; | ||
| 64 | }; | ||
| 65 | |||
| 66 | static const struct cpg_clk_config cpg_clk_configs[4] __initconst = { | ||
| 67 | { 1, 2, 8, 16, 32, 24 }, | ||
| 68 | { 2, 3, 6, 12, 24, 24 }, | ||
| 69 | { 1, 2, 8, 16, 32, 32 }, | ||
| 70 | { 2, 3, 6, 12, 24, 36 }, | ||
| 71 | }; | ||
| 72 | |||
| 73 | /* | ||
| 74 | * MD PLLA Ratio | ||
| 75 | * 12 11 | ||
| 76 | *------------------------ | ||
| 77 | * 0 0 x42 | ||
| 78 | * 0 1 x48 | ||
| 79 | * 1 0 x56 | ||
| 80 | * 1 1 x64 | ||
| 81 | */ | ||
| 82 | |||
| 83 | #define CPG_PLLA_MULT_INDEX(md) (((md) & (BIT(12)|BIT(11))) >> 11) | ||
| 84 | |||
| 85 | static const unsigned int cpg_plla_mult[4] __initconst = { 42, 48, 56, 64 }; | ||
| 86 | |||
| 87 | /* ----------------------------------------------------------------------------- | ||
| 88 | * Initialization | ||
| 89 | */ | ||
| 90 | |||
| 91 | static u32 cpg_mode __initdata; | ||
| 92 | |||
| 93 | static struct clk * __init | ||
| 94 | r8a7779_cpg_register_clock(struct device_node *np, struct r8a7779_cpg *cpg, | ||
| 95 | const struct cpg_clk_config *config, | ||
| 96 | unsigned int plla_mult, const char *name) | ||
| 97 | { | ||
| 98 | const char *parent_name = "plla"; | ||
| 99 | unsigned int mult = 1; | ||
| 100 | unsigned int div = 1; | ||
| 101 | |||
| 102 | if (!strcmp(name, "plla")) { | ||
| 103 | parent_name = of_clk_get_parent_name(np, 0); | ||
| 104 | mult = plla_mult; | ||
| 105 | } else if (!strcmp(name, "z")) { | ||
| 106 | div = config->z_div; | ||
| 107 | mult = config->z_mult; | ||
| 108 | } else if (!strcmp(name, "zs") || !strcmp(name, "s")) { | ||
| 109 | div = config->zs_and_s_div; | ||
| 110 | } else if (!strcmp(name, "s1")) { | ||
| 111 | div = config->s1_div; | ||
| 112 | } else if (!strcmp(name, "p")) { | ||
| 113 | div = config->p_div; | ||
| 114 | } else if (!strcmp(name, "b") || !strcmp(name, "out")) { | ||
| 115 | div = config->b_and_out_div; | ||
| 116 | } else { | ||
| 117 | return ERR_PTR(-EINVAL); | ||
| 118 | } | ||
| 119 | |||
| 120 | return clk_register_fixed_factor(NULL, name, parent_name, 0, mult, div); | ||
| 121 | } | ||
| 122 | |||
| 123 | static void __init r8a7779_cpg_clocks_init(struct device_node *np) | ||
| 124 | { | ||
| 125 | const struct cpg_clk_config *config; | ||
| 126 | struct r8a7779_cpg *cpg; | ||
| 127 | struct clk **clks; | ||
| 128 | unsigned int i, plla_mult; | ||
| 129 | int num_clks; | ||
| 130 | |||
| 131 | num_clks = of_property_count_strings(np, "clock-output-names"); | ||
| 132 | if (num_clks < 0) { | ||
| 133 | pr_err("%s: failed to count clocks\n", __func__); | ||
| 134 | return; | ||
| 135 | } | ||
| 136 | |||
| 137 | cpg = kzalloc(sizeof(*cpg), GFP_KERNEL); | ||
| 138 | clks = kzalloc(CPG_NUM_CLOCKS * sizeof(*clks), GFP_KERNEL); | ||
| 139 | if (cpg == NULL || clks == NULL) { | ||
| 140 | /* We're leaking memory on purpose, there's no point in cleaning | ||
| 141 | * up as the system won't boot anyway. | ||
| 142 | */ | ||
| 143 | return; | ||
| 144 | } | ||
| 145 | |||
| 146 | spin_lock_init(&cpg->lock); | ||
| 147 | |||
| 148 | cpg->data.clks = clks; | ||
| 149 | cpg->data.clk_num = num_clks; | ||
| 150 | |||
| 151 | config = &cpg_clk_configs[CPG_CLK_CONFIG_INDEX(cpg_mode)]; | ||
| 152 | plla_mult = cpg_plla_mult[CPG_PLLA_MULT_INDEX(cpg_mode)]; | ||
| 153 | |||
| 154 | for (i = 0; i < num_clks; ++i) { | ||
| 155 | const char *name; | ||
| 156 | struct clk *clk; | ||
| 157 | |||
| 158 | of_property_read_string_index(np, "clock-output-names", i, | ||
| 159 | &name); | ||
| 160 | |||
| 161 | clk = r8a7779_cpg_register_clock(np, cpg, config, | ||
| 162 | plla_mult, name); | ||
| 163 | if (IS_ERR(clk)) | ||
| 164 | pr_err("%s: failed to register %s %s clock (%ld)\n", | ||
| 165 | __func__, np->name, name, PTR_ERR(clk)); | ||
| 166 | else | ||
| 167 | cpg->data.clks[i] = clk; | ||
| 168 | } | ||
| 169 | |||
| 170 | of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data); | ||
| 171 | } | ||
| 172 | CLK_OF_DECLARE(r8a7779_cpg_clks, "renesas,r8a7779-cpg-clocks", | ||
| 173 | r8a7779_cpg_clocks_init); | ||
| 174 | |||
| 175 | void __init r8a7779_clocks_init(u32 mode) | ||
| 176 | { | ||
| 177 | cpg_mode = mode; | ||
| 178 | |||
| 179 | of_clk_init(NULL); | ||
| 180 | } | ||
diff --git a/drivers/clk/socfpga/clk-gate.c b/drivers/clk/socfpga/clk-gate.c index 501d513bf890..dd3a78c64795 100644 --- a/drivers/clk/socfpga/clk-gate.c +++ b/drivers/clk/socfpga/clk-gate.c | |||
| @@ -32,7 +32,6 @@ | |||
| 32 | #define SOCFPGA_MMC_CLK "sdmmc_clk" | 32 | #define SOCFPGA_MMC_CLK "sdmmc_clk" |
| 33 | #define SOCFPGA_GPIO_DB_CLK_OFFSET 0xA8 | 33 | #define SOCFPGA_GPIO_DB_CLK_OFFSET 0xA8 |
| 34 | 34 | ||
| 35 | #define div_mask(width) ((1 << (width)) - 1) | ||
| 36 | #define streq(a, b) (strcmp((a), (b)) == 0) | 35 | #define streq(a, b) (strcmp((a), (b)) == 0) |
| 37 | 36 | ||
| 38 | #define to_socfpga_gate_clk(p) container_of(p, struct socfpga_gate_clk, hw.hw) | 37 | #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 81623a3736f9..46531c34ec9b 100644 --- a/drivers/clk/socfpga/clk-periph.c +++ b/drivers/clk/socfpga/clk-periph.c | |||
| @@ -29,12 +29,18 @@ static unsigned long clk_periclk_recalc_rate(struct clk_hw *hwclk, | |||
| 29 | unsigned long parent_rate) | 29 | unsigned long parent_rate) |
| 30 | { | 30 | { |
| 31 | struct socfpga_periph_clk *socfpgaclk = to_socfpga_periph_clk(hwclk); | 31 | struct socfpga_periph_clk *socfpgaclk = to_socfpga_periph_clk(hwclk); |
| 32 | u32 div; | 32 | u32 div, val; |
| 33 | 33 | ||
| 34 | if (socfpgaclk->fixed_div) | 34 | if (socfpgaclk->fixed_div) { |
| 35 | div = socfpgaclk->fixed_div; | 35 | div = socfpgaclk->fixed_div; |
| 36 | else | 36 | } else { |
| 37 | if (socfpgaclk->div_reg) { | ||
| 38 | val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift; | ||
| 39 | val &= div_mask(socfpgaclk->width); | ||
| 40 | parent_rate /= (val + 1); | ||
| 41 | } | ||
| 37 | div = ((readl(socfpgaclk->hw.reg) & 0x1ff) + 1); | 42 | div = ((readl(socfpgaclk->hw.reg) & 0x1ff) + 1); |
| 43 | } | ||
| 38 | 44 | ||
| 39 | return parent_rate / div; | 45 | return parent_rate / div; |
| 40 | } | 46 | } |
| @@ -54,6 +60,7 @@ static __init void __socfpga_periph_init(struct device_node *node, | |||
| 54 | struct clk_init_data init; | 60 | struct clk_init_data init; |
| 55 | int rc; | 61 | int rc; |
| 56 | u32 fixed_div; | 62 | u32 fixed_div; |
| 63 | u32 div_reg[3]; | ||
| 57 | 64 | ||
| 58 | of_property_read_u32(node, "reg", ®); | 65 | of_property_read_u32(node, "reg", ®); |
| 59 | 66 | ||
| @@ -63,6 +70,15 @@ static __init void __socfpga_periph_init(struct device_node *node, | |||
| 63 | 70 | ||
| 64 | periph_clk->hw.reg = clk_mgr_base_addr + reg; | 71 | periph_clk->hw.reg = clk_mgr_base_addr + reg; |
| 65 | 72 | ||
| 73 | rc = of_property_read_u32_array(node, "div-reg", div_reg, 3); | ||
| 74 | if (!rc) { | ||
| 75 | periph_clk->div_reg = clk_mgr_base_addr + div_reg[0]; | ||
| 76 | periph_clk->shift = div_reg[1]; | ||
| 77 | periph_clk->width = div_reg[2]; | ||
| 78 | } else { | ||
| 79 | periph_clk->div_reg = 0; | ||
| 80 | } | ||
| 81 | |||
| 66 | rc = of_property_read_u32(node, "fixed-divider", &fixed_div); | 82 | rc = of_property_read_u32(node, "fixed-divider", &fixed_div); |
| 67 | if (rc) | 83 | if (rc) |
| 68 | periph_clk->fixed_div = 0; | 84 | periph_clk->fixed_div = 0; |
diff --git a/drivers/clk/socfpga/clk.h b/drivers/clk/socfpga/clk.h index d2e54019c94f..d291f60c46e1 100644 --- a/drivers/clk/socfpga/clk.h +++ b/drivers/clk/socfpga/clk.h | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #define CLKMGR_PERPLL_SRC 0xAC | 27 | #define CLKMGR_PERPLL_SRC 0xAC |
| 28 | 28 | ||
| 29 | #define SOCFPGA_MAX_PARENTS 3 | 29 | #define SOCFPGA_MAX_PARENTS 3 |
| 30 | #define div_mask(width) ((1 << (width)) - 1) | ||
| 30 | 31 | ||
| 31 | extern void __iomem *clk_mgr_base_addr; | 32 | extern void __iomem *clk_mgr_base_addr; |
| 32 | 33 | ||
| @@ -52,6 +53,9 @@ struct socfpga_periph_clk { | |||
| 52 | struct clk_gate hw; | 53 | struct clk_gate hw; |
| 53 | char *parent_name; | 54 | char *parent_name; |
| 54 | u32 fixed_div; | 55 | u32 fixed_div; |
| 56 | void __iomem *div_reg; | ||
| 57 | u32 width; /* only valid if div_reg != 0 */ | ||
| 58 | u32 shift; /* only valid if div_reg != 0 */ | ||
| 55 | }; | 59 | }; |
| 56 | 60 | ||
| 57 | #endif /* SOCFPGA_CLK_H */ | 61 | #endif /* SOCFPGA_CLK_H */ |
diff --git a/drivers/clk/st/clkgen-pll.c b/drivers/clk/st/clkgen-pll.c index a886702f7c8b..d8b9b1a2aeda 100644 --- a/drivers/clk/st/clkgen-pll.c +++ b/drivers/clk/st/clkgen-pll.c | |||
| @@ -655,6 +655,7 @@ static struct of_device_id c32_gpu_pll_of_match[] = { | |||
| 655 | .compatible = "st,stih416-gpu-pll-c32", | 655 | .compatible = "st,stih416-gpu-pll-c32", |
| 656 | .data = &st_pll1200c32_gpu_416, | 656 | .data = &st_pll1200c32_gpu_416, |
| 657 | }, | 657 | }, |
| 658 | {} | ||
| 658 | }; | 659 | }; |
| 659 | 660 | ||
| 660 | static void __init clkgengpu_c32_pll_setup(struct device_node *np) | 661 | static void __init clkgengpu_c32_pll_setup(struct device_node *np) |
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c index 9e232644f07e..3806d97e529b 100644 --- a/drivers/clk/sunxi/clk-factors.c +++ b/drivers/clk/sunxi/clk-factors.c | |||
| @@ -77,6 +77,41 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate, | |||
| 77 | return rate; | 77 | return rate; |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate, | ||
| 81 | unsigned long *best_parent_rate, | ||
| 82 | struct clk **best_parent_p) | ||
| 83 | { | ||
| 84 | struct clk *clk = hw->clk, *parent, *best_parent = NULL; | ||
| 85 | int i, num_parents; | ||
| 86 | unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0; | ||
| 87 | |||
| 88 | /* find the parent that can help provide the fastest rate <= rate */ | ||
| 89 | num_parents = __clk_get_num_parents(clk); | ||
| 90 | for (i = 0; i < num_parents; i++) { | ||
| 91 | parent = clk_get_parent_by_index(clk, i); | ||
| 92 | if (!parent) | ||
| 93 | continue; | ||
| 94 | if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT) | ||
| 95 | parent_rate = __clk_round_rate(parent, rate); | ||
| 96 | else | ||
| 97 | parent_rate = __clk_get_rate(parent); | ||
| 98 | |||
| 99 | child_rate = clk_factors_round_rate(hw, rate, &parent_rate); | ||
| 100 | |||
| 101 | if (child_rate <= rate && child_rate > best_child_rate) { | ||
| 102 | best_parent = parent; | ||
| 103 | best = parent_rate; | ||
| 104 | best_child_rate = child_rate; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | if (best_parent) | ||
| 109 | *best_parent_p = best_parent; | ||
| 110 | *best_parent_rate = best; | ||
| 111 | |||
| 112 | return best_child_rate; | ||
| 113 | } | ||
| 114 | |||
| 80 | static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, | 115 | static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, |
| 81 | unsigned long parent_rate) | 116 | unsigned long parent_rate) |
| 82 | { | 117 | { |
| @@ -113,6 +148,7 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, | |||
| 113 | } | 148 | } |
| 114 | 149 | ||
| 115 | const struct clk_ops clk_factors_ops = { | 150 | const struct clk_ops clk_factors_ops = { |
| 151 | .determine_rate = clk_factors_determine_rate, | ||
| 116 | .recalc_rate = clk_factors_recalc_rate, | 152 | .recalc_rate = clk_factors_recalc_rate, |
| 117 | .round_rate = clk_factors_round_rate, | 153 | .round_rate = clk_factors_round_rate, |
| 118 | .set_rate = clk_factors_set_rate, | 154 | .set_rate = clk_factors_set_rate, |
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 9eddf22d56a4..426483422d3d 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c | |||
| @@ -507,6 +507,43 @@ CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk", | |||
| 507 | 507 | ||
| 508 | 508 | ||
| 509 | /** | 509 | /** |
| 510 | * clk_sunxi_mmc_phase_control() - configures MMC clock phase control | ||
| 511 | */ | ||
| 512 | |||
| 513 | void clk_sunxi_mmc_phase_control(struct clk *clk, u8 sample, u8 output) | ||
| 514 | { | ||
| 515 | #define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw) | ||
| 516 | #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw) | ||
| 517 | |||
| 518 | struct clk_hw *hw = __clk_get_hw(clk); | ||
| 519 | struct clk_composite *composite = to_clk_composite(hw); | ||
| 520 | struct clk_hw *rate_hw = composite->rate_hw; | ||
| 521 | struct clk_factors *factors = to_clk_factors(rate_hw); | ||
| 522 | unsigned long flags = 0; | ||
| 523 | u32 reg; | ||
| 524 | |||
| 525 | if (factors->lock) | ||
| 526 | spin_lock_irqsave(factors->lock, flags); | ||
| 527 | |||
| 528 | reg = readl(factors->reg); | ||
| 529 | |||
| 530 | /* set sample clock phase control */ | ||
| 531 | reg &= ~(0x7 << 20); | ||
| 532 | reg |= ((sample & 0x7) << 20); | ||
| 533 | |||
| 534 | /* set output clock phase control */ | ||
| 535 | reg &= ~(0x7 << 8); | ||
| 536 | reg |= ((output & 0x7) << 8); | ||
| 537 | |||
| 538 | writel(reg, factors->reg); | ||
| 539 | |||
| 540 | if (factors->lock) | ||
| 541 | spin_unlock_irqrestore(factors->lock, flags); | ||
| 542 | } | ||
| 543 | EXPORT_SYMBOL(clk_sunxi_mmc_phase_control); | ||
| 544 | |||
| 545 | |||
| 546 | /** | ||
| 510 | * sunxi_factors_clk_setup() - Setup function for factor clocks | 547 | * sunxi_factors_clk_setup() - Setup function for factor clocks |
| 511 | */ | 548 | */ |
| 512 | 549 | ||
diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h index c39613c519af..0011d547a9f7 100644 --- a/drivers/clk/tegra/clk-id.h +++ b/drivers/clk/tegra/clk-id.h | |||
| @@ -233,6 +233,7 @@ enum clk_id { | |||
| 233 | tegra_clk_xusb_hs_src, | 233 | tegra_clk_xusb_hs_src, |
| 234 | tegra_clk_xusb_ss, | 234 | tegra_clk_xusb_ss, |
| 235 | tegra_clk_xusb_ss_src, | 235 | tegra_clk_xusb_ss_src, |
| 236 | tegra_clk_xusb_ss_div2, | ||
| 236 | tegra_clk_max, | 237 | tegra_clk_max, |
| 237 | }; | 238 | }; |
| 238 | 239 | ||
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 6aad8abc69a2..637b62ccc91e 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c | |||
| @@ -96,10 +96,20 @@ | |||
| 96 | (PLLE_SS_MAX_VAL | PLLE_SS_INC_VAL | PLLE_SS_INCINTRV_VAL) | 96 | (PLLE_SS_MAX_VAL | PLLE_SS_INC_VAL | PLLE_SS_INCINTRV_VAL) |
| 97 | 97 | ||
| 98 | #define PLLE_AUX_PLLP_SEL BIT(2) | 98 | #define PLLE_AUX_PLLP_SEL BIT(2) |
| 99 | #define PLLE_AUX_USE_LOCKDET BIT(3) | ||
| 99 | #define PLLE_AUX_ENABLE_SWCTL BIT(4) | 100 | #define PLLE_AUX_ENABLE_SWCTL BIT(4) |
| 101 | #define PLLE_AUX_SS_SWCTL BIT(6) | ||
| 100 | #define PLLE_AUX_SEQ_ENABLE BIT(24) | 102 | #define PLLE_AUX_SEQ_ENABLE BIT(24) |
| 103 | #define PLLE_AUX_SEQ_START_STATE BIT(25) | ||
| 101 | #define PLLE_AUX_PLLRE_SEL BIT(28) | 104 | #define PLLE_AUX_PLLRE_SEL BIT(28) |
| 102 | 105 | ||
| 106 | #define XUSBIO_PLL_CFG0 0x51c | ||
| 107 | #define XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL BIT(0) | ||
| 108 | #define XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL BIT(2) | ||
| 109 | #define XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET BIT(6) | ||
| 110 | #define XUSBIO_PLL_CFG0_SEQ_ENABLE BIT(24) | ||
| 111 | #define XUSBIO_PLL_CFG0_SEQ_START_STATE BIT(25) | ||
| 112 | |||
| 103 | #define PLLE_MISC_PLLE_PTS BIT(8) | 113 | #define PLLE_MISC_PLLE_PTS BIT(8) |
| 104 | #define PLLE_MISC_IDDQ_SW_VALUE BIT(13) | 114 | #define PLLE_MISC_IDDQ_SW_VALUE BIT(13) |
| 105 | #define PLLE_MISC_IDDQ_SW_CTRL BIT(14) | 115 | #define PLLE_MISC_IDDQ_SW_CTRL BIT(14) |
| @@ -1328,7 +1338,28 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw) | |||
| 1328 | pll_writel(val, PLLE_SS_CTRL, pll); | 1338 | pll_writel(val, PLLE_SS_CTRL, pll); |
| 1329 | udelay(1); | 1339 | udelay(1); |
| 1330 | 1340 | ||
| 1331 | /* TODO: enable hw control of xusb brick pll */ | 1341 | /* Enable hw control of xusb brick pll */ |
| 1342 | val = pll_readl_misc(pll); | ||
| 1343 | val &= ~PLLE_MISC_IDDQ_SW_CTRL; | ||
| 1344 | pll_writel_misc(val, pll); | ||
| 1345 | |||
| 1346 | val = pll_readl(pll->params->aux_reg, pll); | ||
| 1347 | val |= (PLLE_AUX_USE_LOCKDET | PLLE_AUX_SEQ_START_STATE); | ||
| 1348 | val &= ~(PLLE_AUX_ENABLE_SWCTL | PLLE_AUX_SS_SWCTL); | ||
| 1349 | pll_writel(val, pll->params->aux_reg, pll); | ||
| 1350 | udelay(1); | ||
| 1351 | val |= PLLE_AUX_SEQ_ENABLE; | ||
| 1352 | pll_writel(val, pll->params->aux_reg, pll); | ||
| 1353 | |||
| 1354 | val = pll_readl(XUSBIO_PLL_CFG0, pll); | ||
| 1355 | val |= (XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET | | ||
| 1356 | XUSBIO_PLL_CFG0_SEQ_START_STATE); | ||
| 1357 | val &= ~(XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL | | ||
| 1358 | XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL); | ||
| 1359 | pll_writel(val, XUSBIO_PLL_CFG0, pll); | ||
| 1360 | udelay(1); | ||
| 1361 | val |= XUSBIO_PLL_CFG0_SEQ_ENABLE; | ||
| 1362 | pll_writel(val, XUSBIO_PLL_CFG0, pll); | ||
| 1332 | 1363 | ||
| 1333 | out: | 1364 | out: |
| 1334 | if (pll->lock) | 1365 | if (pll->lock) |
diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index 1fa5c3f33b20..adf6b814b5bc 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c | |||
| @@ -329,7 +329,9 @@ static u32 mux_clkm_pllp_pllc_pllre_idx[] = { | |||
| 329 | static const char *mux_clkm_48M_pllp_480M[] = { | 329 | static const char *mux_clkm_48M_pllp_480M[] = { |
| 330 | "clk_m", "pll_u_48M", "pll_p", "pll_u_480M" | 330 | "clk_m", "pll_u_48M", "pll_p", "pll_u_480M" |
| 331 | }; | 331 | }; |
| 332 | #define mux_clkm_48M_pllp_480M_idx NULL | 332 | static u32 mux_clkm_48M_pllp_480M_idx[] = { |
| 333 | [0] = 0, [1] = 2, [2] = 4, [3] = 6, | ||
| 334 | }; | ||
| 333 | 335 | ||
| 334 | static const char *mux_clkm_pllre_clk32_480M_pllc_ref[] = { | 336 | static const char *mux_clkm_pllre_clk32_480M_pllc_ref[] = { |
| 335 | "clk_m", "pll_re_out", "clk_32k", "pll_u_480M", "pll_c", "pll_ref" | 337 | "clk_m", "pll_re_out", "clk_32k", "pll_u_480M", "pll_c", "pll_ref" |
| @@ -338,6 +340,11 @@ static u32 mux_clkm_pllre_clk32_480M_pllc_ref_idx[] = { | |||
| 338 | [0] = 0, [1] = 1, [2] = 3, [3] = 3, [4] = 4, [5] = 7, | 340 | [0] = 0, [1] = 1, [2] = 3, [3] = 3, [4] = 4, [5] = 7, |
| 339 | }; | 341 | }; |
| 340 | 342 | ||
| 343 | static const char *mux_ss_60M[] = { | ||
| 344 | "xusb_ss_div2", "pll_u_60M" | ||
| 345 | }; | ||
| 346 | #define mux_ss_60M_idx NULL | ||
| 347 | |||
| 341 | static const char *mux_d_audio_clk[] = { | 348 | static const char *mux_d_audio_clk[] = { |
| 342 | "pll_a_out0", "pll_p", "clk_m", "spdif_in_sync", "i2s0_sync", | 349 | "pll_a_out0", "pll_p", "clk_m", "spdif_in_sync", "i2s0_sync", |
| 343 | "i2s1_sync", "i2s2_sync", "i2s3_sync", "i2s4_sync", "vimclk_sync", | 350 | "i2s1_sync", "i2s2_sync", "i2s3_sync", "i2s4_sync", "vimclk_sync", |
| @@ -499,6 +506,7 @@ static struct tegra_periph_init_data periph_clks[] = { | |||
| 499 | XUSB("xusb_falcon_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src), | 506 | XUSB("xusb_falcon_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src), |
| 500 | XUSB("xusb_fs_src", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_fs_src), | 507 | XUSB("xusb_fs_src", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_fs_src), |
| 501 | XUSB("xusb_ss_src", mux_clkm_pllre_clk32_480M_pllc_ref, CLK_SOURCE_XUSB_SS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_ss_src), | 508 | XUSB("xusb_ss_src", mux_clkm_pllre_clk32_480M_pllc_ref, CLK_SOURCE_XUSB_SS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_ss_src), |
| 509 | NODIV("xusb_hs_src", mux_ss_60M, CLK_SOURCE_XUSB_SS_SRC, 25, MASK(1), 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_hs_src, NULL), | ||
| 502 | XUSB("xusb_dev_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src), | 510 | XUSB("xusb_dev_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src), |
| 503 | }; | 511 | }; |
| 504 | 512 | ||
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index 80431f0fb268..b9c8ba258ef0 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c | |||
| @@ -142,7 +142,6 @@ | |||
| 142 | #define UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL BIT(0) | 142 | #define UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL BIT(0) |
| 143 | 143 | ||
| 144 | #define CLK_SOURCE_CSITE 0x1d4 | 144 | #define CLK_SOURCE_CSITE 0x1d4 |
| 145 | #define CLK_SOURCE_XUSB_SS_SRC 0x610 | ||
| 146 | #define CLK_SOURCE_EMC 0x19c | 145 | #define CLK_SOURCE_EMC 0x19c |
| 147 | 146 | ||
| 148 | /* PLLM override registers */ | 147 | /* PLLM override registers */ |
| @@ -834,6 +833,7 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = { | |||
| 834 | [tegra_clk_xusb_falcon_src] = { .dt_id = TEGRA114_CLK_XUSB_FALCON_SRC, .present = true }, | 833 | [tegra_clk_xusb_falcon_src] = { .dt_id = TEGRA114_CLK_XUSB_FALCON_SRC, .present = true }, |
| 835 | [tegra_clk_xusb_fs_src] = { .dt_id = TEGRA114_CLK_XUSB_FS_SRC, .present = true }, | 834 | [tegra_clk_xusb_fs_src] = { .dt_id = TEGRA114_CLK_XUSB_FS_SRC, .present = true }, |
| 836 | [tegra_clk_xusb_ss_src] = { .dt_id = TEGRA114_CLK_XUSB_SS_SRC, .present = true }, | 835 | [tegra_clk_xusb_ss_src] = { .dt_id = TEGRA114_CLK_XUSB_SS_SRC, .present = true }, |
| 836 | [tegra_clk_xusb_ss_div2] = { .dt_id = TEGRA114_CLK_XUSB_SS_DIV2, .present = true}, | ||
| 837 | [tegra_clk_xusb_dev_src] = { .dt_id = TEGRA114_CLK_XUSB_DEV_SRC, .present = true }, | 837 | [tegra_clk_xusb_dev_src] = { .dt_id = TEGRA114_CLK_XUSB_DEV_SRC, .present = true }, |
| 838 | [tegra_clk_xusb_dev] = { .dt_id = TEGRA114_CLK_XUSB_DEV, .present = true }, | 838 | [tegra_clk_xusb_dev] = { .dt_id = TEGRA114_CLK_XUSB_DEV, .present = true }, |
| 839 | [tegra_clk_xusb_hs_src] = { .dt_id = TEGRA114_CLK_XUSB_HS_SRC, .present = true }, | 839 | [tegra_clk_xusb_hs_src] = { .dt_id = TEGRA114_CLK_XUSB_HS_SRC, .present = true }, |
| @@ -1182,16 +1182,11 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base, | |||
| 1182 | void __iomem *pmc_base) | 1182 | void __iomem *pmc_base) |
| 1183 | { | 1183 | { |
| 1184 | struct clk *clk; | 1184 | struct clk *clk; |
| 1185 | u32 val; | ||
| 1186 | |||
| 1187 | /* xusb_hs_src */ | ||
| 1188 | val = readl(clk_base + CLK_SOURCE_XUSB_SS_SRC); | ||
| 1189 | val |= BIT(25); /* always select PLLU_60M */ | ||
| 1190 | writel(val, clk_base + CLK_SOURCE_XUSB_SS_SRC); | ||
| 1191 | 1185 | ||
| 1192 | clk = clk_register_fixed_factor(NULL, "xusb_hs_src", "pll_u_60M", 0, | 1186 | /* xusb_ss_div2 */ |
| 1193 | 1, 1); | 1187 | clk = clk_register_fixed_factor(NULL, "xusb_ss_div2", "xusb_ss_src", 0, |
| 1194 | clks[TEGRA114_CLK_XUSB_HS_SRC] = clk; | 1188 | 1, 2); |
| 1189 | clks[TEGRA114_CLK_XUSB_SS_DIV2] = clk; | ||
| 1195 | 1190 | ||
| 1196 | /* dsia mux */ | 1191 | /* dsia mux */ |
| 1197 | clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0, | 1192 | clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0, |
| @@ -1301,7 +1296,12 @@ static struct tegra_clk_init_table init_table[] __initdata = { | |||
| 1301 | {TEGRA114_CLK_GR3D, TEGRA114_CLK_PLL_C2, 300000000, 0}, | 1296 | {TEGRA114_CLK_GR3D, TEGRA114_CLK_PLL_C2, 300000000, 0}, |
| 1302 | {TEGRA114_CLK_DSIALP, TEGRA114_CLK_PLL_P, 68000000, 0}, | 1297 | {TEGRA114_CLK_DSIALP, TEGRA114_CLK_PLL_P, 68000000, 0}, |
| 1303 | {TEGRA114_CLK_DSIBLP, TEGRA114_CLK_PLL_P, 68000000, 0}, | 1298 | {TEGRA114_CLK_DSIBLP, TEGRA114_CLK_PLL_P, 68000000, 0}, |
| 1304 | 1299 | {TEGRA114_CLK_PLL_RE_VCO, TEGRA114_CLK_CLK_MAX, 612000000, 0}, | |
| 1300 | {TEGRA114_CLK_XUSB_SS_SRC, TEGRA114_CLK_PLL_RE_OUT, 122400000, 0}, | ||
| 1301 | {TEGRA114_CLK_XUSB_FS_SRC, TEGRA114_CLK_PLL_U_48M, 48000000, 0}, | ||
| 1302 | {TEGRA114_CLK_XUSB_HS_SRC, TEGRA114_CLK_XUSB_SS_DIV2, 61200000, 0}, | ||
| 1303 | {TEGRA114_CLK_XUSB_FALCON_SRC, TEGRA114_CLK_PLL_P, 204000000, 0}, | ||
| 1304 | {TEGRA114_CLK_XUSB_HOST_SRC, TEGRA114_CLK_PLL_P, 102000000, 0}, | ||
| 1305 | /* This MUST be the last entry. */ | 1305 | /* This MUST be the last entry. */ |
| 1306 | {TEGRA114_CLK_CLK_MAX, TEGRA114_CLK_CLK_MAX, 0, 0}, | 1306 | {TEGRA114_CLK_CLK_MAX, TEGRA114_CLK_CLK_MAX, 0, 0}, |
| 1307 | }; | 1307 | }; |
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index cc37c342c4cb..80efe51fdcdf 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c | |||
| @@ -30,7 +30,6 @@ | |||
| 30 | 30 | ||
| 31 | #define CLK_SOURCE_CSITE 0x1d4 | 31 | #define CLK_SOURCE_CSITE 0x1d4 |
| 32 | #define CLK_SOURCE_EMC 0x19c | 32 | #define CLK_SOURCE_EMC 0x19c |
| 33 | #define CLK_SOURCE_XUSB_SS_SRC 0x610 | ||
| 34 | 33 | ||
| 35 | #define PLLC_BASE 0x80 | 34 | #define PLLC_BASE 0x80 |
| 36 | #define PLLC_OUT 0x84 | 35 | #define PLLC_OUT 0x84 |
| @@ -925,6 +924,7 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = { | |||
| 925 | [tegra_clk_xusb_falcon_src] = { .dt_id = TEGRA124_CLK_XUSB_FALCON_SRC, .present = true }, | 924 | [tegra_clk_xusb_falcon_src] = { .dt_id = TEGRA124_CLK_XUSB_FALCON_SRC, .present = true }, |
| 926 | [tegra_clk_xusb_fs_src] = { .dt_id = TEGRA124_CLK_XUSB_FS_SRC, .present = true }, | 925 | [tegra_clk_xusb_fs_src] = { .dt_id = TEGRA124_CLK_XUSB_FS_SRC, .present = true }, |
| 927 | [tegra_clk_xusb_ss_src] = { .dt_id = TEGRA124_CLK_XUSB_SS_SRC, .present = true }, | 926 | [tegra_clk_xusb_ss_src] = { .dt_id = TEGRA124_CLK_XUSB_SS_SRC, .present = true }, |
| 927 | [tegra_clk_xusb_ss_div2] = { .dt_id = TEGRA124_CLK_XUSB_SS_DIV2, .present = true }, | ||
| 928 | [tegra_clk_xusb_dev_src] = { .dt_id = TEGRA124_CLK_XUSB_DEV_SRC, .present = true }, | 928 | [tegra_clk_xusb_dev_src] = { .dt_id = TEGRA124_CLK_XUSB_DEV_SRC, .present = true }, |
| 929 | [tegra_clk_xusb_dev] = { .dt_id = TEGRA124_CLK_XUSB_DEV, .present = true }, | 929 | [tegra_clk_xusb_dev] = { .dt_id = TEGRA124_CLK_XUSB_DEV, .present = true }, |
| 930 | [tegra_clk_xusb_hs_src] = { .dt_id = TEGRA124_CLK_XUSB_HS_SRC, .present = true }, | 930 | [tegra_clk_xusb_hs_src] = { .dt_id = TEGRA124_CLK_XUSB_HS_SRC, .present = true }, |
| @@ -1105,16 +1105,11 @@ static __init void tegra124_periph_clk_init(void __iomem *clk_base, | |||
| 1105 | void __iomem *pmc_base) | 1105 | void __iomem *pmc_base) |
| 1106 | { | 1106 | { |
| 1107 | struct clk *clk; | 1107 | struct clk *clk; |
| 1108 | u32 val; | ||
| 1109 | |||
| 1110 | /* xusb_hs_src */ | ||
| 1111 | val = readl(clk_base + CLK_SOURCE_XUSB_SS_SRC); | ||
| 1112 | val |= BIT(25); /* always select PLLU_60M */ | ||
| 1113 | writel(val, clk_base + CLK_SOURCE_XUSB_SS_SRC); | ||
| 1114 | 1108 | ||
| 1115 | clk = clk_register_fixed_factor(NULL, "xusb_hs_src", "pll_u_60M", 0, | 1109 | /* xusb_ss_div2 */ |
| 1116 | 1, 1); | 1110 | clk = clk_register_fixed_factor(NULL, "xusb_ss_div2", "xusb_ss_src", 0, |
| 1117 | clks[TEGRA124_CLK_XUSB_HS_SRC] = clk; | 1111 | 1, 2); |
| 1112 | clks[TEGRA124_CLK_XUSB_SS_DIV2] = clk; | ||
| 1118 | 1113 | ||
| 1119 | /* dsia mux */ | 1114 | /* dsia mux */ |
| 1120 | clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0, | 1115 | clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0, |
| @@ -1368,6 +1363,12 @@ static struct tegra_clk_init_table init_table[] __initdata = { | |||
| 1368 | {TEGRA124_CLK_SBC4, TEGRA124_CLK_PLL_P, 12000000, 1}, | 1363 | {TEGRA124_CLK_SBC4, TEGRA124_CLK_PLL_P, 12000000, 1}, |
| 1369 | {TEGRA124_CLK_TSEC, TEGRA124_CLK_PLL_C3, 0, 0}, | 1364 | {TEGRA124_CLK_TSEC, TEGRA124_CLK_PLL_C3, 0, 0}, |
| 1370 | {TEGRA124_CLK_MSENC, TEGRA124_CLK_PLL_C3, 0, 0}, | 1365 | {TEGRA124_CLK_MSENC, TEGRA124_CLK_PLL_C3, 0, 0}, |
| 1366 | {TEGRA124_CLK_PLL_RE_VCO, TEGRA124_CLK_CLK_MAX, 672000000, 0}, | ||
| 1367 | {TEGRA124_CLK_XUSB_SS_SRC, TEGRA124_CLK_PLL_U_480M, 120000000, 0}, | ||
| 1368 | {TEGRA124_CLK_XUSB_FS_SRC, TEGRA124_CLK_PLL_U_48M, 48000000, 0}, | ||
| 1369 | {TEGRA124_CLK_XUSB_HS_SRC, TEGRA124_CLK_PLL_U_60M, 60000000, 0}, | ||
| 1370 | {TEGRA124_CLK_XUSB_FALCON_SRC, TEGRA124_CLK_PLL_RE_OUT, 224000000, 0}, | ||
| 1371 | {TEGRA124_CLK_XUSB_HOST_SRC, TEGRA124_CLK_PLL_RE_OUT, 112000000, 0}, | ||
| 1371 | /* This MUST be the last entry. */ | 1372 | /* This MUST be the last entry. */ |
| 1372 | {TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0}, | 1373 | {TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0}, |
| 1373 | }; | 1374 | }; |
diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c index a820b0cfcf57..bc96f103bd7c 100644 --- a/drivers/clk/versatile/clk-icst.c +++ b/drivers/clk/versatile/clk-icst.c | |||
| @@ -140,6 +140,7 @@ struct clk *icst_clk_register(struct device *dev, | |||
| 140 | 140 | ||
| 141 | pclone = kmemdup(desc->params, sizeof(*pclone), GFP_KERNEL); | 141 | pclone = kmemdup(desc->params, sizeof(*pclone), GFP_KERNEL); |
| 142 | if (!pclone) { | 142 | if (!pclone) { |
| 143 | kfree(icst); | ||
| 143 | pr_err("could not clone ICST params\n"); | 144 | pr_err("could not clone ICST params\n"); |
| 144 | return ERR_PTR(-ENOMEM); | 145 | return ERR_PTR(-ENOMEM); |
| 145 | } | 146 | } |
| @@ -160,3 +161,4 @@ struct clk *icst_clk_register(struct device *dev, | |||
| 160 | 161 | ||
| 161 | return clk; | 162 | return clk; |
| 162 | } | 163 | } |
| 164 | EXPORT_SYMBOL_GPL(icst_clk_register); | ||
diff --git a/drivers/clk/versatile/clk-impd1.c b/drivers/clk/versatile/clk-impd1.c index 31b44f025f9e..1cc1330dc570 100644 --- a/drivers/clk/versatile/clk-impd1.c +++ b/drivers/clk/versatile/clk-impd1.c | |||
| @@ -20,6 +20,8 @@ | |||
| 20 | #define IMPD1_LOCK 0x08 | 20 | #define IMPD1_LOCK 0x08 |
| 21 | 21 | ||
| 22 | struct impd1_clk { | 22 | struct impd1_clk { |
| 23 | char *pclkname; | ||
| 24 | struct clk *pclk; | ||
| 23 | char *vco1name; | 25 | char *vco1name; |
| 24 | struct clk *vco1clk; | 26 | struct clk *vco1clk; |
| 25 | char *vco2name; | 27 | char *vco2name; |
| @@ -31,7 +33,7 @@ struct impd1_clk { | |||
| 31 | struct clk *spiclk; | 33 | struct clk *spiclk; |
| 32 | char *scname; | 34 | char *scname; |
| 33 | struct clk *scclk; | 35 | struct clk *scclk; |
| 34 | struct clk_lookup *clks[6]; | 36 | struct clk_lookup *clks[15]; |
| 35 | }; | 37 | }; |
| 36 | 38 | ||
| 37 | /* One entry for each connected IM-PD1 LM */ | 39 | /* One entry for each connected IM-PD1 LM */ |
| @@ -86,6 +88,7 @@ void integrator_impd1_clk_init(void __iomem *base, unsigned int id) | |||
| 86 | { | 88 | { |
| 87 | struct impd1_clk *imc; | 89 | struct impd1_clk *imc; |
| 88 | struct clk *clk; | 90 | struct clk *clk; |
| 91 | struct clk *pclk; | ||
| 89 | int i; | 92 | int i; |
| 90 | 93 | ||
| 91 | if (id > 3) { | 94 | if (id > 3) { |
| @@ -94,11 +97,18 @@ void integrator_impd1_clk_init(void __iomem *base, unsigned int id) | |||
| 94 | } | 97 | } |
| 95 | imc = &impd1_clks[id]; | 98 | imc = &impd1_clks[id]; |
| 96 | 99 | ||
| 100 | /* Register the fixed rate PCLK */ | ||
| 101 | imc->pclkname = kasprintf(GFP_KERNEL, "lm%x-pclk", id); | ||
| 102 | pclk = clk_register_fixed_rate(NULL, imc->pclkname, NULL, | ||
| 103 | CLK_IS_ROOT, 0); | ||
| 104 | imc->pclk = pclk; | ||
| 105 | |||
| 97 | imc->vco1name = kasprintf(GFP_KERNEL, "lm%x-vco1", id); | 106 | imc->vco1name = kasprintf(GFP_KERNEL, "lm%x-vco1", id); |
| 98 | clk = icst_clk_register(NULL, &impd1_icst1_desc, imc->vco1name, NULL, | 107 | clk = icst_clk_register(NULL, &impd1_icst1_desc, imc->vco1name, NULL, |
| 99 | base); | 108 | base); |
| 100 | imc->vco1clk = clk; | 109 | imc->vco1clk = clk; |
| 101 | imc->clks[0] = clkdev_alloc(clk, NULL, "lm%x:01000", id); | 110 | imc->clks[0] = clkdev_alloc(pclk, "apb_pclk", "lm%x:01000", id); |
| 111 | imc->clks[1] = clkdev_alloc(clk, NULL, "lm%x:01000", id); | ||
| 102 | 112 | ||
| 103 | /* VCO2 is also called "CLK2" */ | 113 | /* VCO2 is also called "CLK2" */ |
| 104 | imc->vco2name = kasprintf(GFP_KERNEL, "lm%x-vco2", id); | 114 | imc->vco2name = kasprintf(GFP_KERNEL, "lm%x-vco2", id); |
| @@ -107,32 +117,43 @@ void integrator_impd1_clk_init(void __iomem *base, unsigned int id) | |||
| 107 | imc->vco2clk = clk; | 117 | imc->vco2clk = clk; |
| 108 | 118 | ||
| 109 | /* MMCI uses CLK2 right off */ | 119 | /* MMCI uses CLK2 right off */ |
| 110 | imc->clks[1] = clkdev_alloc(clk, NULL, "lm%x:00700", id); | 120 | imc->clks[2] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00700", id); |
| 121 | imc->clks[3] = clkdev_alloc(clk, NULL, "lm%x:00700", id); | ||
| 111 | 122 | ||
| 112 | /* UART reference clock divides CLK2 by a fixed factor 4 */ | 123 | /* UART reference clock divides CLK2 by a fixed factor 4 */ |
| 113 | imc->uartname = kasprintf(GFP_KERNEL, "lm%x-uartclk", id); | 124 | imc->uartname = kasprintf(GFP_KERNEL, "lm%x-uartclk", id); |
| 114 | clk = clk_register_fixed_factor(NULL, imc->uartname, imc->vco2name, | 125 | clk = clk_register_fixed_factor(NULL, imc->uartname, imc->vco2name, |
| 115 | CLK_IGNORE_UNUSED, 1, 4); | 126 | CLK_IGNORE_UNUSED, 1, 4); |
| 116 | imc->uartclk = clk; | 127 | imc->uartclk = clk; |
| 117 | imc->clks[2] = clkdev_alloc(clk, NULL, "lm%x:00100", id); | 128 | imc->clks[4] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00100", id); |
| 118 | imc->clks[3] = clkdev_alloc(clk, NULL, "lm%x:00200", id); | 129 | imc->clks[5] = clkdev_alloc(clk, NULL, "lm%x:00100", id); |
| 130 | imc->clks[6] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00200", id); | ||
| 131 | imc->clks[7] = clkdev_alloc(clk, NULL, "lm%x:00200", id); | ||
| 119 | 132 | ||
| 120 | /* SPI PL022 clock divides CLK2 by a fixed factor 64 */ | 133 | /* SPI PL022 clock divides CLK2 by a fixed factor 64 */ |
| 121 | imc->spiname = kasprintf(GFP_KERNEL, "lm%x-spiclk", id); | 134 | imc->spiname = kasprintf(GFP_KERNEL, "lm%x-spiclk", id); |
| 122 | clk = clk_register_fixed_factor(NULL, imc->spiname, imc->vco2name, | 135 | clk = clk_register_fixed_factor(NULL, imc->spiname, imc->vco2name, |
| 123 | CLK_IGNORE_UNUSED, 1, 64); | 136 | CLK_IGNORE_UNUSED, 1, 64); |
| 124 | imc->clks[4] = clkdev_alloc(clk, NULL, "lm%x:00300", id); | 137 | imc->clks[8] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00300", id); |
| 138 | imc->clks[9] = clkdev_alloc(clk, NULL, "lm%x:00300", id); | ||
| 139 | |||
| 140 | /* The GPIO blocks and AACI have only PCLK */ | ||
| 141 | imc->clks[10] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00400", id); | ||
| 142 | imc->clks[11] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00500", id); | ||
| 143 | imc->clks[12] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00800", id); | ||
| 125 | 144 | ||
| 126 | /* Smart Card clock divides CLK2 by a fixed factor 4 */ | 145 | /* Smart Card clock divides CLK2 by a fixed factor 4 */ |
| 127 | imc->scname = kasprintf(GFP_KERNEL, "lm%x-scclk", id); | 146 | imc->scname = kasprintf(GFP_KERNEL, "lm%x-scclk", id); |
| 128 | clk = clk_register_fixed_factor(NULL, imc->scname, imc->vco2name, | 147 | clk = clk_register_fixed_factor(NULL, imc->scname, imc->vco2name, |
| 129 | CLK_IGNORE_UNUSED, 1, 4); | 148 | CLK_IGNORE_UNUSED, 1, 4); |
| 130 | imc->scclk = clk; | 149 | imc->scclk = clk; |
| 131 | imc->clks[5] = clkdev_alloc(clk, NULL, "lm%x:00600", id); | 150 | imc->clks[13] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00600", id); |
| 151 | imc->clks[14] = clkdev_alloc(clk, NULL, "lm%x:00600", id); | ||
| 132 | 152 | ||
| 133 | for (i = 0; i < ARRAY_SIZE(imc->clks); i++) | 153 | for (i = 0; i < ARRAY_SIZE(imc->clks); i++) |
| 134 | clkdev_add(imc->clks[i]); | 154 | clkdev_add(imc->clks[i]); |
| 135 | } | 155 | } |
| 156 | EXPORT_SYMBOL_GPL(integrator_impd1_clk_init); | ||
| 136 | 157 | ||
| 137 | void integrator_impd1_clk_exit(unsigned int id) | 158 | void integrator_impd1_clk_exit(unsigned int id) |
| 138 | { | 159 | { |
| @@ -149,9 +170,12 @@ void integrator_impd1_clk_exit(unsigned int id) | |||
| 149 | clk_unregister(imc->uartclk); | 170 | clk_unregister(imc->uartclk); |
| 150 | clk_unregister(imc->vco2clk); | 171 | clk_unregister(imc->vco2clk); |
| 151 | clk_unregister(imc->vco1clk); | 172 | clk_unregister(imc->vco1clk); |
| 173 | clk_unregister(imc->pclk); | ||
| 152 | kfree(imc->scname); | 174 | kfree(imc->scname); |
| 153 | kfree(imc->spiname); | 175 | kfree(imc->spiname); |
| 154 | kfree(imc->uartname); | 176 | kfree(imc->uartname); |
| 155 | kfree(imc->vco2name); | 177 | kfree(imc->vco2name); |
| 156 | kfree(imc->vco1name); | 178 | kfree(imc->vco1name); |
| 179 | kfree(imc->pclkname); | ||
| 157 | } | 180 | } |
| 181 | EXPORT_SYMBOL_GPL(integrator_impd1_clk_exit); | ||
diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c index 52c09afdcfb7..246cf1226eaa 100644 --- a/drivers/clk/zynq/clkc.c +++ b/drivers/clk/zynq/clkc.c | |||
| @@ -53,6 +53,9 @@ static void __iomem *zynq_clkc_base; | |||
| 53 | 53 | ||
| 54 | #define NUM_MIO_PINS 54 | 54 | #define NUM_MIO_PINS 54 |
| 55 | 55 | ||
| 56 | #define DBG_CLK_CTRL_CLKACT_TRC BIT(0) | ||
| 57 | #define DBG_CLK_CTRL_CPU_1XCLKACT BIT(1) | ||
| 58 | |||
| 56 | enum zynq_clk { | 59 | enum zynq_clk { |
| 57 | armpll, ddrpll, iopll, | 60 | armpll, ddrpll, iopll, |
| 58 | cpu_6or4x, cpu_3or2x, cpu_2x, cpu_1x, | 61 | cpu_6or4x, cpu_3or2x, cpu_2x, cpu_1x, |
| @@ -499,6 +502,15 @@ static void __init zynq_clk_setup(struct device_node *np) | |||
| 499 | clk_output_name[cpu_1x], 0, SLCR_DBG_CLK_CTRL, 1, 0, | 502 | clk_output_name[cpu_1x], 0, SLCR_DBG_CLK_CTRL, 1, 0, |
| 500 | &dbgclk_lock); | 503 | &dbgclk_lock); |
| 501 | 504 | ||
| 505 | /* leave debug clocks in the state the bootloader set them up to */ | ||
| 506 | tmp = clk_readl(SLCR_DBG_CLK_CTRL); | ||
| 507 | if (tmp & DBG_CLK_CTRL_CLKACT_TRC) | ||
| 508 | if (clk_prepare_enable(clks[dbg_trc])) | ||
| 509 | pr_warn("%s: trace clk enable failed\n", __func__); | ||
| 510 | if (tmp & DBG_CLK_CTRL_CPU_1XCLKACT) | ||
| 511 | if (clk_prepare_enable(clks[dbg_apb])) | ||
| 512 | pr_warn("%s: debug APB clk enable failed\n", __func__); | ||
| 513 | |||
| 502 | /* One gated clock for all APER clocks. */ | 514 | /* One gated clock for all APER clocks. */ |
| 503 | clks[dma] = clk_register_gate(NULL, clk_output_name[dma], | 515 | clks[dma] = clk_register_gate(NULL, clk_output_name[dma], |
| 504 | clk_output_name[cpu_2x], 0, SLCR_APER_CLK_CTRL, 0, 0, | 516 | clk_output_name[cpu_2x], 0, SLCR_APER_CLK_CTRL, 0, 0, |
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index b675882307e4..779368b683d0 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig | |||
| @@ -701,3 +701,10 @@ config MMC_REALTEK_USB | |||
| 701 | help | 701 | help |
| 702 | Say Y here to include driver code to support SD/MMC card interface | 702 | Say Y here to include driver code to support SD/MMC card interface |
| 703 | of Realtek RTS5129/39 series card reader | 703 | of Realtek RTS5129/39 series card reader |
| 704 | |||
| 705 | config MMC_SUNXI | ||
| 706 | tristate "Allwinner sunxi SD/MMC Host Controller support" | ||
| 707 | depends on ARCH_SUNXI | ||
| 708 | help | ||
| 709 | This selects support for the SD/MMC Host Controller on | ||
| 710 | Allwinner sunxi SoCs. | ||
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 3eb48b656f25..61cbc241935b 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile | |||
| @@ -50,6 +50,7 @@ obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o | |||
| 50 | obj-$(CONFIG_MMC_VUB300) += vub300.o | 50 | obj-$(CONFIG_MMC_VUB300) += vub300.o |
| 51 | obj-$(CONFIG_MMC_USHC) += ushc.o | 51 | obj-$(CONFIG_MMC_USHC) += ushc.o |
| 52 | obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o | 52 | obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o |
| 53 | obj-$(CONFIG_MMC_SUNXI) += sunxi-mmc.o | ||
| 53 | 54 | ||
| 54 | obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o | 55 | obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o |
| 55 | obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o | 56 | obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o |
diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c new file mode 100644 index 000000000000..024f67c98cdc --- /dev/null +++ b/drivers/mmc/host/sunxi-mmc.c | |||
| @@ -0,0 +1,1049 @@ | |||
| 1 | /* | ||
| 2 | * Driver for sunxi SD/MMC host controllers | ||
| 3 | * (C) Copyright 2007-2011 Reuuimlla Technology Co., Ltd. | ||
| 4 | * (C) Copyright 2007-2011 Aaron Maoye <leafy.myeh@reuuimllatech.com> | ||
| 5 | * (C) Copyright 2013-2014 O2S GmbH <www.o2s.ch> | ||
| 6 | * (C) Copyright 2013-2014 David Lanzend�rfer <david.lanzendoerfer@o2s.ch> | ||
| 7 | * (C) Copyright 2013-2014 Hans de Goede <hdegoede@redhat.com> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or | ||
| 10 | * modify it under the terms of the GNU General Public License as | ||
| 11 | * published by the Free Software Foundation; either version 2 of | ||
| 12 | * the License, or (at your option) any later version. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/kernel.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/io.h> | ||
| 18 | #include <linux/device.h> | ||
| 19 | #include <linux/interrupt.h> | ||
| 20 | #include <linux/delay.h> | ||
| 21 | #include <linux/err.h> | ||
| 22 | |||
| 23 | #include <linux/clk.h> | ||
| 24 | #include <linux/clk-private.h> | ||
| 25 | #include <linux/clk/sunxi.h> | ||
| 26 | |||
| 27 | #include <linux/gpio.h> | ||
| 28 | #include <linux/platform_device.h> | ||
| 29 | #include <linux/spinlock.h> | ||
| 30 | #include <linux/scatterlist.h> | ||
| 31 | #include <linux/dma-mapping.h> | ||
| 32 | #include <linux/slab.h> | ||
| 33 | #include <linux/reset.h> | ||
| 34 | |||
| 35 | #include <linux/of_address.h> | ||
| 36 | #include <linux/of_gpio.h> | ||
| 37 | #include <linux/of_platform.h> | ||
| 38 | |||
| 39 | #include <linux/mmc/host.h> | ||
| 40 | #include <linux/mmc/sd.h> | ||
| 41 | #include <linux/mmc/sdio.h> | ||
| 42 | #include <linux/mmc/mmc.h> | ||
| 43 | #include <linux/mmc/core.h> | ||
| 44 | #include <linux/mmc/card.h> | ||
| 45 | #include <linux/mmc/slot-gpio.h> | ||
| 46 | |||
| 47 | /* register offset definitions */ | ||
| 48 | #define SDXC_REG_GCTRL (0x00) /* SMC Global Control Register */ | ||
| 49 | #define SDXC_REG_CLKCR (0x04) /* SMC Clock Control Register */ | ||
| 50 | #define SDXC_REG_TMOUT (0x08) /* SMC Time Out Register */ | ||
| 51 | #define SDXC_REG_WIDTH (0x0C) /* SMC Bus Width Register */ | ||
| 52 | #define SDXC_REG_BLKSZ (0x10) /* SMC Block Size Register */ | ||
| 53 | #define SDXC_REG_BCNTR (0x14) /* SMC Byte Count Register */ | ||
| 54 | #define SDXC_REG_CMDR (0x18) /* SMC Command Register */ | ||
| 55 | #define SDXC_REG_CARG (0x1C) /* SMC Argument Register */ | ||
| 56 | #define SDXC_REG_RESP0 (0x20) /* SMC Response Register 0 */ | ||
| 57 | #define SDXC_REG_RESP1 (0x24) /* SMC Response Register 1 */ | ||
| 58 | #define SDXC_REG_RESP2 (0x28) /* SMC Response Register 2 */ | ||
| 59 | #define SDXC_REG_RESP3 (0x2C) /* SMC Response Register 3 */ | ||
| 60 | #define SDXC_REG_IMASK (0x30) /* SMC Interrupt Mask Register */ | ||
| 61 | #define SDXC_REG_MISTA (0x34) /* SMC Masked Interrupt Status Register */ | ||
| 62 | #define SDXC_REG_RINTR (0x38) /* SMC Raw Interrupt Status Register */ | ||
| 63 | #define SDXC_REG_STAS (0x3C) /* SMC Status Register */ | ||
| 64 | #define SDXC_REG_FTRGL (0x40) /* SMC FIFO Threshold Watermark Registe */ | ||
| 65 | #define SDXC_REG_FUNS (0x44) /* SMC Function Select Register */ | ||
| 66 | #define SDXC_REG_CBCR (0x48) /* SMC CIU Byte Count Register */ | ||
| 67 | #define SDXC_REG_BBCR (0x4C) /* SMC BIU Byte Count Register */ | ||
| 68 | #define SDXC_REG_DBGC (0x50) /* SMC Debug Enable Register */ | ||
| 69 | #define SDXC_REG_HWRST (0x78) /* SMC Card Hardware Reset for Register */ | ||
| 70 | #define SDXC_REG_DMAC (0x80) /* SMC IDMAC Control Register */ | ||
| 71 | #define SDXC_REG_DLBA (0x84) /* SMC IDMAC Descriptor List Base Addre */ | ||
| 72 | #define SDXC_REG_IDST (0x88) /* SMC IDMAC Status Register */ | ||
| 73 | #define SDXC_REG_IDIE (0x8C) /* SMC IDMAC Interrupt Enable Register */ | ||
| 74 | #define SDXC_REG_CHDA (0x90) | ||
| 75 | #define SDXC_REG_CBDA (0x94) | ||
| 76 | |||
| 77 | #define mmc_readl(host, reg) \ | ||
| 78 | readl((host)->reg_base + SDXC_##reg) | ||
| 79 | #define mmc_writel(host, reg, value) \ | ||
| 80 | writel((value), (host)->reg_base + SDXC_##reg) | ||
| 81 | |||
| 82 | /* global control register bits */ | ||
| 83 | #define SDXC_SOFT_RESET BIT(0) | ||
| 84 | #define SDXC_FIFO_RESET BIT(1) | ||
| 85 | #define SDXC_DMA_RESET BIT(2) | ||
| 86 | #define SDXC_INTERRUPT_ENABLE_BIT BIT(4) | ||
| 87 | #define SDXC_DMA_ENABLE_BIT BIT(5) | ||
| 88 | #define SDXC_DEBOUNCE_ENABLE_BIT BIT(8) | ||
| 89 | #define SDXC_POSEDGE_LATCH_DATA BIT(9) | ||
| 90 | #define SDXC_DDR_MODE BIT(10) | ||
| 91 | #define SDXC_MEMORY_ACCESS_DONE BIT(29) | ||
| 92 | #define SDXC_ACCESS_DONE_DIRECT BIT(30) | ||
| 93 | #define SDXC_ACCESS_BY_AHB BIT(31) | ||
| 94 | #define SDXC_ACCESS_BY_DMA (0 << 31) | ||
| 95 | #define SDXC_HARDWARE_RESET \ | ||
| 96 | (SDXC_SOFT_RESET | SDXC_FIFO_RESET | SDXC_DMA_RESET) | ||
| 97 | |||
| 98 | /* clock control bits */ | ||
| 99 | #define SDXC_CARD_CLOCK_ON BIT(16) | ||
| 100 | #define SDXC_LOW_POWER_ON BIT(17) | ||
| 101 | |||
| 102 | /* bus width */ | ||
| 103 | #define SDXC_WIDTH1 0 | ||
| 104 | #define SDXC_WIDTH4 1 | ||
| 105 | #define SDXC_WIDTH8 2 | ||
| 106 | |||
| 107 | /* smc command bits */ | ||
| 108 | #define SDXC_RESP_EXPIRE BIT(6) | ||
| 109 | #define SDXC_LONG_RESPONSE BIT(7) | ||
| 110 | #define SDXC_CHECK_RESPONSE_CRC BIT(8) | ||
| 111 | #define SDXC_DATA_EXPIRE BIT(9) | ||
| 112 | #define SDXC_WRITE BIT(10) | ||
| 113 | #define SDXC_SEQUENCE_MODE BIT(11) | ||
| 114 | #define SDXC_SEND_AUTO_STOP BIT(12) | ||
| 115 | #define SDXC_WAIT_PRE_OVER BIT(13) | ||
| 116 | #define SDXC_STOP_ABORT_CMD BIT(14) | ||
| 117 | #define SDXC_SEND_INIT_SEQUENCE BIT(15) | ||
| 118 | #define SDXC_UPCLK_ONLY BIT(21) | ||
| 119 | #define SDXC_READ_CEATA_DEV BIT(22) | ||
| 120 | #define SDXC_CCS_EXPIRE BIT(23) | ||
| 121 | #define SDXC_ENABLE_BIT_BOOT BIT(24) | ||
| 122 | #define SDXC_ALT_BOOT_OPTIONS BIT(25) | ||
| 123 | #define SDXC_BOOT_ACK_EXPIRE BIT(26) | ||
| 124 | #define SDXC_BOOT_ABORT BIT(27) | ||
| 125 | #define SDXC_VOLTAGE_SWITCH BIT(28) | ||
| 126 | #define SDXC_USE_HOLD_REGISTER BIT(29) | ||
| 127 | #define SDXC_START BIT(31) | ||
| 128 | |||
| 129 | /* interrupt bits */ | ||
| 130 | #define SDXC_RESP_ERROR BIT(1) | ||
| 131 | #define SDXC_COMMAND_DONE BIT(2) | ||
| 132 | #define SDXC_DATA_OVER BIT(3) | ||
| 133 | #define SDXC_TX_DATA_REQUEST BIT(4) | ||
| 134 | #define SDXC_RX_DATA_REQUEST BIT(5) | ||
| 135 | #define SDXC_RESP_CRC_ERROR BIT(6) | ||
| 136 | #define SDXC_DATA_CRC_ERROR BIT(7) | ||
| 137 | #define SDXC_RESP_TIMEOUT BIT(8) | ||
| 138 | #define SDXC_DATA_TIMEOUT BIT(9) | ||
| 139 | #define SDXC_VOLTAGE_CHANGE_DONE BIT(10) | ||
| 140 | #define SDXC_FIFO_RUN_ERROR BIT(11) | ||
| 141 | #define SDXC_HARD_WARE_LOCKED BIT(12) | ||
| 142 | #define SDXC_START_BIT_ERROR BIT(13) | ||
| 143 | #define SDXC_AUTO_COMMAND_DONE BIT(14) | ||
| 144 | #define SDXC_END_BIT_ERROR BIT(15) | ||
| 145 | #define SDXC_SDIO_INTERRUPT BIT(16) | ||
| 146 | #define SDXC_CARD_INSERT BIT(30) | ||
| 147 | #define SDXC_CARD_REMOVE BIT(31) | ||
| 148 | #define SDXC_INTERRUPT_ERROR_BIT \ | ||
| 149 | (SDXC_RESP_ERROR | SDXC_RESP_CRC_ERROR | SDXC_DATA_CRC_ERROR | \ | ||
| 150 | SDXC_RESP_TIMEOUT | SDXC_DATA_TIMEOUT | SDXC_FIFO_RUN_ERROR | \ | ||
| 151 | SDXC_HARD_WARE_LOCKED | SDXC_START_BIT_ERROR | SDXC_END_BIT_ERROR) | ||
| 152 | #define SDXC_INTERRUPT_DONE_BIT \ | ||
| 153 | (SDXC_AUTO_COMMAND_DONE | SDXC_DATA_OVER | \ | ||
| 154 | SDXC_COMMAND_DONE | SDXC_VOLTAGE_CHANGE_DONE) | ||
| 155 | |||
| 156 | /* status */ | ||
| 157 | #define SDXC_RXWL_FLAG BIT(0) | ||
| 158 | #define SDXC_TXWL_FLAG BIT(1) | ||
| 159 | #define SDXC_FIFO_EMPTY BIT(2) | ||
| 160 | #define SDXC_FIFO_FULL BIT(3) | ||
| 161 | #define SDXC_CARD_PRESENT BIT(8) | ||
| 162 | #define SDXC_CARD_DATA_BUSY BIT(9) | ||
| 163 | #define SDXC_DATA_FSM_BUSY BIT(10) | ||
| 164 | #define SDXC_DMA_REQUEST BIT(31) | ||
| 165 | #define SDXC_FIFO_SIZE 16 | ||
| 166 | |||
| 167 | /* Function select */ | ||
| 168 | #define SDXC_CEATA_ON (0xceaa << 16) | ||
| 169 | #define SDXC_SEND_IRQ_RESPONSE BIT(0) | ||
| 170 | #define SDXC_SDIO_READ_WAIT BIT(1) | ||
| 171 | #define SDXC_ABORT_READ_DATA BIT(2) | ||
| 172 | #define SDXC_SEND_CCSD BIT(8) | ||
| 173 | #define SDXC_SEND_AUTO_STOPCCSD BIT(9) | ||
| 174 | #define SDXC_CEATA_DEV_IRQ_ENABLE BIT(10) | ||
| 175 | |||
| 176 | /* IDMA controller bus mod bit field */ | ||
| 177 | #define SDXC_IDMAC_SOFT_RESET BIT(0) | ||
| 178 | #define SDXC_IDMAC_FIX_BURST BIT(1) | ||
| 179 | #define SDXC_IDMAC_IDMA_ON BIT(7) | ||
| 180 | #define SDXC_IDMAC_REFETCH_DES BIT(31) | ||
| 181 | |||
| 182 | /* IDMA status bit field */ | ||
| 183 | #define SDXC_IDMAC_TRANSMIT_INTERRUPT BIT(0) | ||
| 184 | #define SDXC_IDMAC_RECEIVE_INTERRUPT BIT(1) | ||
| 185 | #define SDXC_IDMAC_FATAL_BUS_ERROR BIT(2) | ||
| 186 | #define SDXC_IDMAC_DESTINATION_INVALID BIT(4) | ||
| 187 | #define SDXC_IDMAC_CARD_ERROR_SUM BIT(5) | ||
| 188 | #define SDXC_IDMAC_NORMAL_INTERRUPT_SUM BIT(8) | ||
| 189 | #define SDXC_IDMAC_ABNORMAL_INTERRUPT_SUM BIT(9) | ||
| 190 | #define SDXC_IDMAC_HOST_ABORT_INTERRUPT BIT(10) | ||
| 191 | #define SDXC_IDMAC_IDLE (0 << 13) | ||
| 192 | #define SDXC_IDMAC_SUSPEND (1 << 13) | ||
| 193 | #define SDXC_IDMAC_DESC_READ (2 << 13) | ||
| 194 | #define SDXC_IDMAC_DESC_CHECK (3 << 13) | ||
| 195 | #define SDXC_IDMAC_READ_REQUEST_WAIT (4 << 13) | ||
| 196 | #define SDXC_IDMAC_WRITE_REQUEST_WAIT (5 << 13) | ||
| 197 | #define SDXC_IDMAC_READ (6 << 13) | ||
| 198 | #define SDXC_IDMAC_WRITE (7 << 13) | ||
| 199 | #define SDXC_IDMAC_DESC_CLOSE (8 << 13) | ||
| 200 | |||
| 201 | /* | ||
| 202 | * If the idma-des-size-bits of property is ie 13, bufsize bits are: | ||
| 203 | * Bits 0-12: buf1 size | ||
| 204 | * Bits 13-25: buf2 size | ||
| 205 | * Bits 26-31: not used | ||
| 206 | * Since we only ever set buf1 size, we can simply store it directly. | ||
| 207 | */ | ||
| 208 | #define SDXC_IDMAC_DES0_DIC BIT(1) /* disable interrupt on completion */ | ||
| 209 | #define SDXC_IDMAC_DES0_LD BIT(2) /* last descriptor */ | ||
| 210 | #define SDXC_IDMAC_DES0_FD BIT(3) /* first descriptor */ | ||
| 211 | #define SDXC_IDMAC_DES0_CH BIT(4) /* chain mode */ | ||
| 212 | #define SDXC_IDMAC_DES0_ER BIT(5) /* end of ring */ | ||
| 213 | #define SDXC_IDMAC_DES0_CES BIT(30) /* card error summary */ | ||
| 214 | #define SDXC_IDMAC_DES0_OWN BIT(31) /* 1-idma owns it, 0-host owns it */ | ||
| 215 | |||
| 216 | struct sunxi_idma_des { | ||
| 217 | u32 config; | ||
| 218 | u32 buf_size; | ||
| 219 | u32 buf_addr_ptr1; | ||
| 220 | u32 buf_addr_ptr2; | ||
| 221 | }; | ||
| 222 | |||
| 223 | struct sunxi_mmc_host { | ||
| 224 | struct mmc_host *mmc; | ||
| 225 | struct reset_control *reset; | ||
| 226 | |||
| 227 | /* IO mapping base */ | ||
| 228 | void __iomem *reg_base; | ||
| 229 | |||
| 230 | /* clock management */ | ||
| 231 | struct clk *clk_ahb; | ||
| 232 | struct clk *clk_mmc; | ||
| 233 | |||
| 234 | /* irq */ | ||
| 235 | spinlock_t lock; | ||
| 236 | int irq; | ||
| 237 | u32 int_sum; | ||
| 238 | u32 sdio_imask; | ||
| 239 | |||
| 240 | /* dma */ | ||
| 241 | u32 idma_des_size_bits; | ||
| 242 | dma_addr_t sg_dma; | ||
| 243 | void *sg_cpu; | ||
| 244 | bool wait_dma; | ||
| 245 | |||
| 246 | struct mmc_request *mrq; | ||
| 247 | struct mmc_request *manual_stop_mrq; | ||
| 248 | int ferror; | ||
| 249 | }; | ||
| 250 | |||
| 251 | static int sunxi_mmc_reset_host(struct sunxi_mmc_host *host) | ||
| 252 | { | ||
| 253 | unsigned long expire = jiffies + msecs_to_jiffies(250); | ||
| 254 | u32 rval; | ||
| 255 | |||
| 256 | mmc_writel(host, REG_CMDR, SDXC_HARDWARE_RESET); | ||
| 257 | do { | ||
| 258 | rval = mmc_readl(host, REG_GCTRL); | ||
| 259 | } while (time_before(jiffies, expire) && (rval & SDXC_HARDWARE_RESET)); | ||
| 260 | |||
| 261 | if (rval & SDXC_HARDWARE_RESET) { | ||
| 262 | dev_err(mmc_dev(host->mmc), "fatal err reset timeout\n"); | ||
| 263 | return -EIO; | ||
| 264 | } | ||
| 265 | |||
| 266 | return 0; | ||
| 267 | } | ||
| 268 | |||
| 269 | static int sunxi_mmc_init_host(struct mmc_host *mmc) | ||
| 270 | { | ||
| 271 | u32 rval; | ||
| 272 | struct sunxi_mmc_host *host = mmc_priv(mmc); | ||
| 273 | |||
| 274 | if (sunxi_mmc_reset_host(host)) | ||
| 275 | return -EIO; | ||
| 276 | |||
| 277 | mmc_writel(host, REG_FTRGL, 0x20070008); | ||
| 278 | mmc_writel(host, REG_TMOUT, 0xffffffff); | ||
| 279 | mmc_writel(host, REG_IMASK, host->sdio_imask); | ||
| 280 | mmc_writel(host, REG_RINTR, 0xffffffff); | ||
| 281 | mmc_writel(host, REG_DBGC, 0xdeb); | ||
| 282 | mmc_writel(host, REG_FUNS, SDXC_CEATA_ON); | ||
| 283 | mmc_writel(host, REG_DLBA, host->sg_dma); | ||
| 284 | |||
| 285 | rval = mmc_readl(host, REG_GCTRL); | ||
| 286 | rval |= SDXC_INTERRUPT_ENABLE_BIT; | ||
| 287 | rval &= ~SDXC_ACCESS_DONE_DIRECT; | ||
| 288 | mmc_writel(host, REG_GCTRL, rval); | ||
| 289 | |||
| 290 | return 0; | ||
| 291 | } | ||
| 292 | |||
| 293 | static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host, | ||
| 294 | struct mmc_data *data) | ||
| 295 | { | ||
| 296 | struct sunxi_idma_des *pdes = (struct sunxi_idma_des *)host->sg_cpu; | ||
| 297 | struct sunxi_idma_des *pdes_pa = (struct sunxi_idma_des *)host->sg_dma; | ||
| 298 | int i, max_len = (1 << host->idma_des_size_bits); | ||
| 299 | |||
| 300 | for (i = 0; i < data->sg_len; i++) { | ||
| 301 | pdes[i].config = SDXC_IDMAC_DES0_CH | SDXC_IDMAC_DES0_OWN | | ||
| 302 | SDXC_IDMAC_DES0_DIC; | ||
| 303 | |||
| 304 | if (data->sg[i].length == max_len) | ||
| 305 | pdes[i].buf_size = 0; /* 0 == max_len */ | ||
| 306 | else | ||
| 307 | pdes[i].buf_size = data->sg[i].length; | ||
| 308 | |||
| 309 | pdes[i].buf_addr_ptr1 = sg_dma_address(&data->sg[i]); | ||
| 310 | pdes[i].buf_addr_ptr2 = (u32)&pdes_pa[i + 1]; | ||
| 311 | } | ||
| 312 | |||
| 313 | pdes[0].config |= SDXC_IDMAC_DES0_FD; | ||
| 314 | pdes[i - 1].config = SDXC_IDMAC_DES0_OWN | SDXC_IDMAC_DES0_LD; | ||
| 315 | |||
| 316 | /* | ||
| 317 | * Avoid the io-store starting the idmac hitting io-mem before the | ||
| 318 | * descriptors hit the main-mem. | ||
| 319 | */ | ||
| 320 | wmb(); | ||
| 321 | } | ||
| 322 | |||
| 323 | static enum dma_data_direction sunxi_mmc_get_dma_dir(struct mmc_data *data) | ||
| 324 | { | ||
| 325 | if (data->flags & MMC_DATA_WRITE) | ||
| 326 | return DMA_TO_DEVICE; | ||
| 327 | else | ||
| 328 | return DMA_FROM_DEVICE; | ||
| 329 | } | ||
| 330 | |||
| 331 | static int sunxi_mmc_map_dma(struct sunxi_mmc_host *host, | ||
| 332 | struct mmc_data *data) | ||
| 333 | { | ||
| 334 | u32 i, dma_len; | ||
| 335 | struct scatterlist *sg; | ||
| 336 | |||
| 337 | dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, | ||
| 338 | sunxi_mmc_get_dma_dir(data)); | ||
| 339 | if (dma_len == 0) { | ||
| 340 | dev_err(mmc_dev(host->mmc), "dma_map_sg failed\n"); | ||
| 341 | return -ENOMEM; | ||
| 342 | } | ||
| 343 | |||
| 344 | for_each_sg(data->sg, sg, data->sg_len, i) { | ||
| 345 | if (sg->offset & 3 || sg->length & 3) { | ||
| 346 | dev_err(mmc_dev(host->mmc), | ||
| 347 | "unaligned scatterlist: os %x length %d\n", | ||
| 348 | sg->offset, sg->length); | ||
| 349 | return -EINVAL; | ||
| 350 | } | ||
| 351 | } | ||
| 352 | |||
| 353 | return 0; | ||
| 354 | } | ||
| 355 | |||
| 356 | static void sunxi_mmc_start_dma(struct sunxi_mmc_host *host, | ||
| 357 | struct mmc_data *data) | ||
| 358 | { | ||
| 359 | u32 rval; | ||
| 360 | |||
| 361 | sunxi_mmc_init_idma_des(host, data); | ||
| 362 | |||
| 363 | rval = mmc_readl(host, REG_GCTRL); | ||
| 364 | rval |= SDXC_DMA_ENABLE_BIT; | ||
| 365 | mmc_writel(host, REG_GCTRL, rval); | ||
| 366 | rval |= SDXC_DMA_RESET; | ||
| 367 | mmc_writel(host, REG_GCTRL, rval); | ||
| 368 | |||
| 369 | mmc_writel(host, REG_DMAC, SDXC_IDMAC_SOFT_RESET); | ||
| 370 | |||
| 371 | if (!(data->flags & MMC_DATA_WRITE)) | ||
| 372 | mmc_writel(host, REG_IDIE, SDXC_IDMAC_RECEIVE_INTERRUPT); | ||
| 373 | |||
| 374 | mmc_writel(host, REG_DMAC, | ||
| 375 | SDXC_IDMAC_FIX_BURST | SDXC_IDMAC_IDMA_ON); | ||
| 376 | } | ||
| 377 | |||
| 378 | static void sunxi_mmc_send_manual_stop(struct sunxi_mmc_host *host, | ||
| 379 | struct mmc_request *req) | ||
| 380 | { | ||
| 381 | u32 arg, cmd_val, ri; | ||
| 382 | unsigned long expire = jiffies + msecs_to_jiffies(1000); | ||
| 383 | |||
| 384 | cmd_val = SDXC_START | SDXC_RESP_EXPIRE | | ||
| 385 | SDXC_STOP_ABORT_CMD | SDXC_CHECK_RESPONSE_CRC; | ||
| 386 | |||
| 387 | if (req->cmd->opcode == SD_IO_RW_EXTENDED) { | ||
| 388 | cmd_val |= SD_IO_RW_DIRECT; | ||
| 389 | arg = (1 << 31) | (0 << 28) | (SDIO_CCCR_ABORT << 9) | | ||
| 390 | ((req->cmd->arg >> 28) & 0x7); | ||
| 391 | } else { | ||
| 392 | cmd_val |= MMC_STOP_TRANSMISSION; | ||
| 393 | arg = 0; | ||
| 394 | } | ||
| 395 | |||
| 396 | mmc_writel(host, REG_CARG, arg); | ||
| 397 | mmc_writel(host, REG_CMDR, cmd_val); | ||
| 398 | |||
| 399 | do { | ||
| 400 | ri = mmc_readl(host, REG_RINTR); | ||
| 401 | } while (!(ri & (SDXC_COMMAND_DONE | SDXC_INTERRUPT_ERROR_BIT)) && | ||
| 402 | time_before(jiffies, expire)); | ||
| 403 | |||
| 404 | if (!(ri & SDXC_COMMAND_DONE) || (ri & SDXC_INTERRUPT_ERROR_BIT)) { | ||
| 405 | dev_err(mmc_dev(host->mmc), "send stop command failed\n"); | ||
| 406 | if (req->stop) | ||
| 407 | req->stop->resp[0] = -ETIMEDOUT; | ||
| 408 | } else { | ||
| 409 | if (req->stop) | ||
| 410 | req->stop->resp[0] = mmc_readl(host, REG_RESP0); | ||
| 411 | } | ||
| 412 | |||
| 413 | mmc_writel(host, REG_RINTR, 0xffff); | ||
| 414 | } | ||
| 415 | |||
| 416 | static void sunxi_mmc_dump_errinfo(struct sunxi_mmc_host *host) | ||
| 417 | { | ||
| 418 | struct mmc_command *cmd = host->mrq->cmd; | ||
| 419 | struct mmc_data *data = host->mrq->data; | ||
| 420 | |||
| 421 | /* For some cmds timeout is normal with sd/mmc cards */ | ||
| 422 | if ((host->int_sum & SDXC_INTERRUPT_ERROR_BIT) == | ||
| 423 | SDXC_RESP_TIMEOUT && (cmd->opcode == SD_IO_SEND_OP_COND || | ||
| 424 | cmd->opcode == SD_IO_RW_DIRECT)) | ||
| 425 | return; | ||
| 426 | |||
| 427 | dev_err(mmc_dev(host->mmc), | ||
| 428 | "smc %d err, cmd %d,%s%s%s%s%s%s%s%s%s%s !!\n", | ||
| 429 | host->mmc->index, cmd->opcode, | ||
| 430 | data ? (data->flags & MMC_DATA_WRITE ? " WR" : " RD") : "", | ||
| 431 | host->int_sum & SDXC_RESP_ERROR ? " RE" : "", | ||
| 432 | host->int_sum & SDXC_RESP_CRC_ERROR ? " RCE" : "", | ||
| 433 | host->int_sum & SDXC_DATA_CRC_ERROR ? " DCE" : "", | ||
| 434 | host->int_sum & SDXC_RESP_TIMEOUT ? " RTO" : "", | ||
| 435 | host->int_sum & SDXC_DATA_TIMEOUT ? " DTO" : "", | ||
| 436 | host->int_sum & SDXC_FIFO_RUN_ERROR ? " FE" : "", | ||
| 437 | host->int_sum & SDXC_HARD_WARE_LOCKED ? " HL" : "", | ||
| 438 | host->int_sum & SDXC_START_BIT_ERROR ? " SBE" : "", | ||
| 439 | host->int_sum & SDXC_END_BIT_ERROR ? " EBE" : "" | ||
| 440 | ); | ||
| 441 | } | ||
| 442 | |||
| 443 | /* Called in interrupt context! */ | ||
| 444 | static irqreturn_t sunxi_mmc_finalize_request(struct sunxi_mmc_host *host) | ||
| 445 | { | ||
| 446 | struct mmc_request *mrq = host->mrq; | ||
| 447 | struct mmc_data *data = mrq->data; | ||
| 448 | u32 rval; | ||
| 449 | |||
| 450 | mmc_writel(host, REG_IMASK, host->sdio_imask); | ||
| 451 | mmc_writel(host, REG_IDIE, 0); | ||
| 452 | |||
| 453 | if (host->int_sum & SDXC_INTERRUPT_ERROR_BIT) { | ||
| 454 | sunxi_mmc_dump_errinfo(host); | ||
| 455 | mrq->cmd->error = -ETIMEDOUT; | ||
| 456 | |||
| 457 | if (data) { | ||
| 458 | data->error = -ETIMEDOUT; | ||
| 459 | host->manual_stop_mrq = mrq; | ||
| 460 | } | ||
| 461 | |||
| 462 | if (mrq->stop) | ||
| 463 | mrq->stop->error = -ETIMEDOUT; | ||
| 464 | } else { | ||
| 465 | if (mrq->cmd->flags & MMC_RSP_136) { | ||
| 466 | mrq->cmd->resp[0] = mmc_readl(host, REG_RESP3); | ||
| 467 | mrq->cmd->resp[1] = mmc_readl(host, REG_RESP2); | ||
| 468 | mrq->cmd->resp[2] = mmc_readl(host, REG_RESP1); | ||
| 469 | mrq->cmd->resp[3] = mmc_readl(host, REG_RESP0); | ||
| 470 | } else { | ||
| 471 | mrq->cmd->resp[0] = mmc_readl(host, REG_RESP0); | ||
| 472 | } | ||
| 473 | |||
| 474 | if (data) | ||
| 475 | data->bytes_xfered = data->blocks * data->blksz; | ||
| 476 | } | ||
| 477 | |||
| 478 | if (data) { | ||
| 479 | mmc_writel(host, REG_IDST, 0x337); | ||
| 480 | mmc_writel(host, REG_DMAC, 0); | ||
| 481 | rval = mmc_readl(host, REG_GCTRL); | ||
| 482 | rval |= SDXC_DMA_RESET; | ||
| 483 | mmc_writel(host, REG_GCTRL, rval); | ||
| 484 | rval &= ~SDXC_DMA_ENABLE_BIT; | ||
| 485 | mmc_writel(host, REG_GCTRL, rval); | ||
| 486 | rval |= SDXC_FIFO_RESET; | ||
| 487 | mmc_writel(host, REG_GCTRL, rval); | ||
| 488 | dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, | ||
| 489 | sunxi_mmc_get_dma_dir(data)); | ||
| 490 | } | ||
| 491 | |||
| 492 | mmc_writel(host, REG_RINTR, 0xffff); | ||
| 493 | |||
| 494 | host->mrq = NULL; | ||
| 495 | host->int_sum = 0; | ||
| 496 | host->wait_dma = false; | ||
| 497 | |||
| 498 | return host->manual_stop_mrq ? IRQ_WAKE_THREAD : IRQ_HANDLED; | ||
| 499 | } | ||
| 500 | |||
| 501 | static irqreturn_t sunxi_mmc_irq(int irq, void *dev_id) | ||
| 502 | { | ||
| 503 | struct sunxi_mmc_host *host = dev_id; | ||
| 504 | struct mmc_request *mrq; | ||
| 505 | u32 msk_int, idma_int; | ||
| 506 | bool finalize = false; | ||
| 507 | bool sdio_int = false; | ||
| 508 | irqreturn_t ret = IRQ_HANDLED; | ||
| 509 | |||
| 510 | spin_lock(&host->lock); | ||
| 511 | |||
| 512 | idma_int = mmc_readl(host, REG_IDST); | ||
| 513 | msk_int = mmc_readl(host, REG_MISTA); | ||
| 514 | |||
| 515 | dev_dbg(mmc_dev(host->mmc), "irq: rq %p mi %08x idi %08x\n", | ||
| 516 | host->mrq, msk_int, idma_int); | ||
| 517 | |||
| 518 | mrq = host->mrq; | ||
| 519 | if (mrq) { | ||
| 520 | if (idma_int & SDXC_IDMAC_RECEIVE_INTERRUPT) | ||
| 521 | host->wait_dma = false; | ||
| 522 | |||
| 523 | host->int_sum |= msk_int; | ||
| 524 | |||
| 525 | /* Wait for COMMAND_DONE on RESPONSE_TIMEOUT before finalize */ | ||
| 526 | if ((host->int_sum & SDXC_RESP_TIMEOUT) && | ||
| 527 | !(host->int_sum & SDXC_COMMAND_DONE)) | ||
| 528 | mmc_writel(host, REG_IMASK, | ||
| 529 | host->sdio_imask | SDXC_COMMAND_DONE); | ||
| 530 | /* Don't wait for dma on error */ | ||
| 531 | else if (host->int_sum & SDXC_INTERRUPT_ERROR_BIT) | ||
| 532 | finalize = true; | ||
| 533 | else if ((host->int_sum & SDXC_INTERRUPT_DONE_BIT) && | ||
| 534 | !host->wait_dma) | ||
| 535 | finalize = true; | ||
| 536 | } | ||
| 537 | |||
| 538 | if (msk_int & SDXC_SDIO_INTERRUPT) | ||
| 539 | sdio_int = true; | ||
| 540 | |||
| 541 | mmc_writel(host, REG_RINTR, msk_int); | ||
| 542 | mmc_writel(host, REG_IDST, idma_int); | ||
| 543 | |||
| 544 | if (finalize) | ||
| 545 | ret = sunxi_mmc_finalize_request(host); | ||
| 546 | |||
| 547 | spin_unlock(&host->lock); | ||
| 548 | |||
| 549 | if (finalize && ret == IRQ_HANDLED) | ||
| 550 | mmc_request_done(host->mmc, mrq); | ||
| 551 | |||
| 552 | if (sdio_int) | ||
| 553 | mmc_signal_sdio_irq(host->mmc); | ||
| 554 | |||
| 555 | return ret; | ||
| 556 | } | ||
| 557 | |||
| 558 | static irqreturn_t sunxi_mmc_handle_manual_stop(int irq, void *dev_id) | ||
| 559 | { | ||
| 560 | struct sunxi_mmc_host *host = dev_id; | ||
| 561 | struct mmc_request *mrq; | ||
| 562 | unsigned long iflags; | ||
| 563 | |||
| 564 | spin_lock_irqsave(&host->lock, iflags); | ||
| 565 | mrq = host->manual_stop_mrq; | ||
| 566 | spin_unlock_irqrestore(&host->lock, iflags); | ||
| 567 | |||
| 568 | if (!mrq) { | ||
| 569 | dev_err(mmc_dev(host->mmc), "no request for manual stop\n"); | ||
| 570 | return IRQ_HANDLED; | ||
| 571 | } | ||
| 572 | |||
| 573 | dev_err(mmc_dev(host->mmc), "data error, sending stop command\n"); | ||
| 574 | sunxi_mmc_send_manual_stop(host, mrq); | ||
| 575 | |||
| 576 | spin_lock_irqsave(&host->lock, iflags); | ||
| 577 | host->manual_stop_mrq = NULL; | ||
| 578 | spin_unlock_irqrestore(&host->lock, iflags); | ||
| 579 | |||
| 580 | mmc_request_done(host->mmc, mrq); | ||
| 581 | |||
| 582 | return IRQ_HANDLED; | ||
| 583 | } | ||
| 584 | |||
| 585 | static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en) | ||
| 586 | { | ||
| 587 | unsigned long expire = jiffies + msecs_to_jiffies(250); | ||
| 588 | u32 rval; | ||
| 589 | |||
| 590 | rval = mmc_readl(host, REG_CLKCR); | ||
| 591 | rval &= ~(SDXC_CARD_CLOCK_ON | SDXC_LOW_POWER_ON); | ||
| 592 | |||
| 593 | if (oclk_en) | ||
| 594 | rval |= SDXC_CARD_CLOCK_ON; | ||
| 595 | |||
| 596 | mmc_writel(host, REG_CLKCR, rval); | ||
| 597 | |||
| 598 | rval = SDXC_START | SDXC_UPCLK_ONLY | SDXC_WAIT_PRE_OVER; | ||
| 599 | mmc_writel(host, REG_CMDR, rval); | ||
| 600 | |||
| 601 | do { | ||
| 602 | rval = mmc_readl(host, REG_CMDR); | ||
| 603 | } while (time_before(jiffies, expire) && (rval & SDXC_START)); | ||
| 604 | |||
| 605 | /* clear irq status bits set by the command */ | ||
| 606 | mmc_writel(host, REG_RINTR, | ||
| 607 | mmc_readl(host, REG_RINTR) & ~SDXC_SDIO_INTERRUPT); | ||
| 608 | |||
| 609 | if (rval & SDXC_START) { | ||
| 610 | dev_err(mmc_dev(host->mmc), "fatal err update clk timeout\n"); | ||
| 611 | return -EIO; | ||
| 612 | } | ||
| 613 | |||
| 614 | return 0; | ||
| 615 | } | ||
| 616 | |||
| 617 | static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, | ||
| 618 | struct mmc_ios *ios) | ||
| 619 | { | ||
| 620 | u32 rate, oclk_dly, rval, sclk_dly, src_clk; | ||
| 621 | int ret; | ||
| 622 | |||
| 623 | rate = clk_round_rate(host->clk_mmc, ios->clock); | ||
| 624 | dev_dbg(mmc_dev(host->mmc), "setting clk to %d, rounded %d\n", | ||
| 625 | ios->clock, rate); | ||
| 626 | |||
| 627 | /* setting clock rate */ | ||
| 628 | ret = clk_set_rate(host->clk_mmc, rate); | ||
| 629 | if (ret) { | ||
| 630 | dev_err(mmc_dev(host->mmc), "error setting clk to %d: %d\n", | ||
| 631 | rate, ret); | ||
| 632 | return ret; | ||
| 633 | } | ||
| 634 | |||
| 635 | ret = sunxi_mmc_oclk_onoff(host, 0); | ||
| 636 | if (ret) | ||
| 637 | return ret; | ||
| 638 | |||
| 639 | /* clear internal divider */ | ||
| 640 | rval = mmc_readl(host, REG_CLKCR); | ||
| 641 | rval &= ~0xff; | ||
| 642 | mmc_writel(host, REG_CLKCR, rval); | ||
| 643 | |||
| 644 | /* determine delays */ | ||
| 645 | if (rate <= 400000) { | ||
| 646 | oclk_dly = 0; | ||
| 647 | sclk_dly = 7; | ||
| 648 | } else if (rate <= 25000000) { | ||
| 649 | oclk_dly = 0; | ||
| 650 | sclk_dly = 5; | ||
| 651 | } else if (rate <= 50000000) { | ||
| 652 | if (ios->timing == MMC_TIMING_UHS_DDR50) { | ||
| 653 | oclk_dly = 2; | ||
| 654 | sclk_dly = 4; | ||
| 655 | } else { | ||
| 656 | oclk_dly = 3; | ||
| 657 | sclk_dly = 5; | ||
| 658 | } | ||
| 659 | } else { | ||
| 660 | /* rate > 50000000 */ | ||
| 661 | oclk_dly = 2; | ||
| 662 | sclk_dly = 4; | ||
| 663 | } | ||
| 664 | |||
| 665 | src_clk = clk_get_rate(clk_get_parent(host->clk_mmc)); | ||
| 666 | if (src_clk >= 300000000 && src_clk <= 400000000) { | ||
| 667 | if (oclk_dly) | ||
| 668 | oclk_dly--; | ||
| 669 | if (sclk_dly) | ||
| 670 | sclk_dly--; | ||
| 671 | } | ||
| 672 | |||
| 673 | clk_sunxi_mmc_phase_control(host->clk_mmc, sclk_dly, oclk_dly); | ||
| 674 | |||
| 675 | return sunxi_mmc_oclk_onoff(host, 1); | ||
| 676 | } | ||
| 677 | |||
| 678 | static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | ||
| 679 | { | ||
| 680 | struct sunxi_mmc_host *host = mmc_priv(mmc); | ||
| 681 | u32 rval; | ||
| 682 | |||
| 683 | /* Set the power state */ | ||
| 684 | switch (ios->power_mode) { | ||
| 685 | case MMC_POWER_ON: | ||
| 686 | break; | ||
| 687 | |||
| 688 | case MMC_POWER_UP: | ||
| 689 | mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); | ||
| 690 | |||
| 691 | host->ferror = sunxi_mmc_init_host(mmc); | ||
| 692 | if (host->ferror) | ||
| 693 | return; | ||
| 694 | |||
| 695 | dev_dbg(mmc_dev(mmc), "power on!\n"); | ||
| 696 | break; | ||
| 697 | |||
| 698 | case MMC_POWER_OFF: | ||
| 699 | dev_dbg(mmc_dev(mmc), "power off!\n"); | ||
| 700 | sunxi_mmc_reset_host(host); | ||
| 701 | mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); | ||
| 702 | break; | ||
| 703 | } | ||
| 704 | |||
| 705 | /* set bus width */ | ||
| 706 | switch (ios->bus_width) { | ||
| 707 | case MMC_BUS_WIDTH_1: | ||
| 708 | mmc_writel(host, REG_WIDTH, SDXC_WIDTH1); | ||
| 709 | break; | ||
| 710 | case MMC_BUS_WIDTH_4: | ||
| 711 | mmc_writel(host, REG_WIDTH, SDXC_WIDTH4); | ||
| 712 | break; | ||
| 713 | case MMC_BUS_WIDTH_8: | ||
| 714 | mmc_writel(host, REG_WIDTH, SDXC_WIDTH8); | ||
| 715 | break; | ||
| 716 | } | ||
| 717 | |||
| 718 | /* set ddr mode */ | ||
| 719 | rval = mmc_readl(host, REG_GCTRL); | ||
| 720 | if (ios->timing == MMC_TIMING_UHS_DDR50) | ||
| 721 | rval |= SDXC_DDR_MODE; | ||
| 722 | else | ||
| 723 | rval &= ~SDXC_DDR_MODE; | ||
| 724 | mmc_writel(host, REG_GCTRL, rval); | ||
| 725 | |||
| 726 | /* set up clock */ | ||
| 727 | if (ios->clock && ios->power_mode) { | ||
| 728 | host->ferror = sunxi_mmc_clk_set_rate(host, ios); | ||
| 729 | /* Android code had a usleep_range(50000, 55000); here */ | ||
| 730 | } | ||
| 731 | } | ||
| 732 | |||
| 733 | static void sunxi_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) | ||
| 734 | { | ||
| 735 | struct sunxi_mmc_host *host = mmc_priv(mmc); | ||
| 736 | unsigned long flags; | ||
| 737 | u32 imask; | ||
| 738 | |||
| 739 | spin_lock_irqsave(&host->lock, flags); | ||
| 740 | |||
| 741 | imask = mmc_readl(host, REG_IMASK); | ||
| 742 | if (enable) { | ||
| 743 | host->sdio_imask = SDXC_SDIO_INTERRUPT; | ||
| 744 | imask |= SDXC_SDIO_INTERRUPT; | ||
| 745 | } else { | ||
| 746 | host->sdio_imask = 0; | ||
| 747 | imask &= ~SDXC_SDIO_INTERRUPT; | ||
| 748 | } | ||
| 749 | mmc_writel(host, REG_IMASK, imask); | ||
| 750 | spin_unlock_irqrestore(&host->lock, flags); | ||
| 751 | } | ||
| 752 | |||
| 753 | static void sunxi_mmc_hw_reset(struct mmc_host *mmc) | ||
| 754 | { | ||
| 755 | struct sunxi_mmc_host *host = mmc_priv(mmc); | ||
| 756 | mmc_writel(host, REG_HWRST, 0); | ||
| 757 | udelay(10); | ||
| 758 | mmc_writel(host, REG_HWRST, 1); | ||
| 759 | udelay(300); | ||
| 760 | } | ||
| 761 | |||
| 762 | static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) | ||
| 763 | { | ||
| 764 | struct sunxi_mmc_host *host = mmc_priv(mmc); | ||
| 765 | struct mmc_command *cmd = mrq->cmd; | ||
| 766 | struct mmc_data *data = mrq->data; | ||
| 767 | unsigned long iflags; | ||
| 768 | u32 imask = SDXC_INTERRUPT_ERROR_BIT; | ||
| 769 | u32 cmd_val = SDXC_START | (cmd->opcode & 0x3f); | ||
| 770 | int ret; | ||
| 771 | |||
| 772 | /* Check for set_ios errors (should never happen) */ | ||
| 773 | if (host->ferror) { | ||
| 774 | mrq->cmd->error = host->ferror; | ||
| 775 | mmc_request_done(mmc, mrq); | ||
| 776 | return; | ||
| 777 | } | ||
| 778 | |||
| 779 | if (data) { | ||
| 780 | ret = sunxi_mmc_map_dma(host, data); | ||
| 781 | if (ret < 0) { | ||
| 782 | dev_err(mmc_dev(mmc), "map DMA failed\n"); | ||
| 783 | cmd->error = ret; | ||
| 784 | data->error = ret; | ||
| 785 | mmc_request_done(mmc, mrq); | ||
| 786 | return; | ||
| 787 | } | ||
| 788 | } | ||
| 789 | |||
| 790 | if (cmd->opcode == MMC_GO_IDLE_STATE) { | ||
| 791 | cmd_val |= SDXC_SEND_INIT_SEQUENCE; | ||
| 792 | imask |= SDXC_COMMAND_DONE; | ||
| 793 | } | ||
| 794 | |||
| 795 | if (cmd->flags & MMC_RSP_PRESENT) { | ||
| 796 | cmd_val |= SDXC_RESP_EXPIRE; | ||
| 797 | if (cmd->flags & MMC_RSP_136) | ||
| 798 | cmd_val |= SDXC_LONG_RESPONSE; | ||
| 799 | if (cmd->flags & MMC_RSP_CRC) | ||
| 800 | cmd_val |= SDXC_CHECK_RESPONSE_CRC; | ||
| 801 | |||
| 802 | if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC) { | ||
| 803 | cmd_val |= SDXC_DATA_EXPIRE | SDXC_WAIT_PRE_OVER; | ||
| 804 | if (cmd->data->flags & MMC_DATA_STREAM) { | ||
| 805 | imask |= SDXC_AUTO_COMMAND_DONE; | ||
| 806 | cmd_val |= SDXC_SEQUENCE_MODE | | ||
| 807 | SDXC_SEND_AUTO_STOP; | ||
| 808 | } | ||
| 809 | |||
| 810 | if (cmd->data->stop) { | ||
| 811 | imask |= SDXC_AUTO_COMMAND_DONE; | ||
| 812 | cmd_val |= SDXC_SEND_AUTO_STOP; | ||
| 813 | } else { | ||
| 814 | imask |= SDXC_DATA_OVER; | ||
| 815 | } | ||
| 816 | |||
| 817 | if (cmd->data->flags & MMC_DATA_WRITE) | ||
| 818 | cmd_val |= SDXC_WRITE; | ||
| 819 | else | ||
| 820 | host->wait_dma = true; | ||
| 821 | } else { | ||
| 822 | imask |= SDXC_COMMAND_DONE; | ||
| 823 | } | ||
| 824 | } else { | ||
| 825 | imask |= SDXC_COMMAND_DONE; | ||
| 826 | } | ||
| 827 | |||
| 828 | dev_dbg(mmc_dev(mmc), "cmd %d(%08x) arg %x ie 0x%08x len %d\n", | ||
| 829 | cmd_val & 0x3f, cmd_val, cmd->arg, imask, | ||
| 830 | mrq->data ? mrq->data->blksz * mrq->data->blocks : 0); | ||
| 831 | |||
| 832 | spin_lock_irqsave(&host->lock, iflags); | ||
| 833 | |||
| 834 | if (host->mrq || host->manual_stop_mrq) { | ||
| 835 | spin_unlock_irqrestore(&host->lock, iflags); | ||
| 836 | |||
| 837 | if (data) | ||
| 838 | dma_unmap_sg(mmc_dev(mmc), data->sg, data->sg_len, | ||
| 839 | sunxi_mmc_get_dma_dir(data)); | ||
| 840 | |||
| 841 | dev_err(mmc_dev(mmc), "request already pending\n"); | ||
| 842 | mrq->cmd->error = -EBUSY; | ||
| 843 | mmc_request_done(mmc, mrq); | ||
| 844 | return; | ||
| 845 | } | ||
| 846 | |||
| 847 | if (data) { | ||
| 848 | mmc_writel(host, REG_BLKSZ, data->blksz); | ||
| 849 | mmc_writel(host, REG_BCNTR, data->blksz * data->blocks); | ||
| 850 | sunxi_mmc_start_dma(host, data); | ||
| 851 | } | ||
| 852 | |||
| 853 | host->mrq = mrq; | ||
| 854 | mmc_writel(host, REG_IMASK, host->sdio_imask | imask); | ||
| 855 | mmc_writel(host, REG_CARG, cmd->arg); | ||
| 856 | mmc_writel(host, REG_CMDR, cmd_val); | ||
| 857 | |||
| 858 | spin_unlock_irqrestore(&host->lock, iflags); | ||
| 859 | } | ||
| 860 | |||
| 861 | static const struct of_device_id sunxi_mmc_of_match[] = { | ||
| 862 | { .compatible = "allwinner,sun4i-a10-mmc", }, | ||
| 863 | { .compatible = "allwinner,sun5i-a13-mmc", }, | ||
| 864 | { /* sentinel */ } | ||
| 865 | }; | ||
| 866 | MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match); | ||
| 867 | |||
| 868 | static struct mmc_host_ops sunxi_mmc_ops = { | ||
| 869 | .request = sunxi_mmc_request, | ||
| 870 | .set_ios = sunxi_mmc_set_ios, | ||
| 871 | .get_ro = mmc_gpio_get_ro, | ||
| 872 | .get_cd = mmc_gpio_get_cd, | ||
| 873 | .enable_sdio_irq = sunxi_mmc_enable_sdio_irq, | ||
| 874 | .hw_reset = sunxi_mmc_hw_reset, | ||
| 875 | }; | ||
| 876 | |||
| 877 | static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host, | ||
| 878 | struct platform_device *pdev) | ||
| 879 | { | ||
| 880 | struct device_node *np = pdev->dev.of_node; | ||
| 881 | int ret; | ||
| 882 | |||
| 883 | if (of_device_is_compatible(np, "allwinner,sun4i-a10-mmc")) | ||
| 884 | host->idma_des_size_bits = 13; | ||
| 885 | else | ||
| 886 | host->idma_des_size_bits = 16; | ||
| 887 | |||
| 888 | ret = mmc_regulator_get_supply(host->mmc); | ||
| 889 | if (ret) { | ||
| 890 | if (ret != -EPROBE_DEFER) | ||
| 891 | dev_err(&pdev->dev, "Could not get vmmc supply\n"); | ||
| 892 | return ret; | ||
| 893 | } | ||
| 894 | |||
| 895 | host->reg_base = devm_ioremap_resource(&pdev->dev, | ||
| 896 | platform_get_resource(pdev, IORESOURCE_MEM, 0)); | ||
| 897 | if (IS_ERR(host->reg_base)) | ||
| 898 | return PTR_ERR(host->reg_base); | ||
| 899 | |||
| 900 | host->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); | ||
| 901 | if (IS_ERR(host->clk_ahb)) { | ||
| 902 | dev_err(&pdev->dev, "Could not get ahb clock\n"); | ||
| 903 | return PTR_ERR(host->clk_ahb); | ||
| 904 | } | ||
| 905 | |||
| 906 | host->clk_mmc = devm_clk_get(&pdev->dev, "mmc"); | ||
| 907 | if (IS_ERR(host->clk_mmc)) { | ||
| 908 | dev_err(&pdev->dev, "Could not get mmc clock\n"); | ||
| 909 | return PTR_ERR(host->clk_mmc); | ||
| 910 | } | ||
| 911 | |||
| 912 | host->reset = devm_reset_control_get(&pdev->dev, "ahb"); | ||
| 913 | |||
| 914 | ret = clk_prepare_enable(host->clk_ahb); | ||
| 915 | if (ret) { | ||
| 916 | dev_err(&pdev->dev, "Enable ahb clk err %d\n", ret); | ||
| 917 | return ret; | ||
| 918 | } | ||
| 919 | |||
| 920 | ret = clk_prepare_enable(host->clk_mmc); | ||
| 921 | if (ret) { | ||
| 922 | dev_err(&pdev->dev, "Enable mmc clk err %d\n", ret); | ||
| 923 | goto error_disable_clk_ahb; | ||
| 924 | } | ||
| 925 | |||
| 926 | if (!IS_ERR(host->reset)) { | ||
| 927 | ret = reset_control_deassert(host->reset); | ||
| 928 | if (ret) { | ||
| 929 | dev_err(&pdev->dev, "reset err %d\n", ret); | ||
| 930 | goto error_disable_clk_mmc; | ||
| 931 | } | ||
| 932 | } | ||
| 933 | |||
| 934 | /* | ||
| 935 | * Sometimes the controller asserts the irq on boot for some reason, | ||
| 936 | * make sure the controller is in a sane state before enabling irqs. | ||
| 937 | */ | ||
| 938 | ret = sunxi_mmc_reset_host(host); | ||
| 939 | if (ret) | ||
| 940 | goto error_assert_reset; | ||
| 941 | |||
| 942 | host->irq = platform_get_irq(pdev, 0); | ||
| 943 | return devm_request_threaded_irq(&pdev->dev, host->irq, sunxi_mmc_irq, | ||
| 944 | sunxi_mmc_handle_manual_stop, 0, "sunxi-mmc", host); | ||
| 945 | |||
| 946 | error_assert_reset: | ||
| 947 | if (!IS_ERR(host->reset)) | ||
| 948 | reset_control_assert(host->reset); | ||
| 949 | error_disable_clk_mmc: | ||
| 950 | clk_disable_unprepare(host->clk_mmc); | ||
| 951 | error_disable_clk_ahb: | ||
| 952 | clk_disable_unprepare(host->clk_ahb); | ||
| 953 | return ret; | ||
| 954 | } | ||
| 955 | |||
| 956 | static int sunxi_mmc_probe(struct platform_device *pdev) | ||
| 957 | { | ||
| 958 | struct sunxi_mmc_host *host; | ||
| 959 | struct mmc_host *mmc; | ||
| 960 | int ret; | ||
| 961 | |||
| 962 | mmc = mmc_alloc_host(sizeof(struct sunxi_mmc_host), &pdev->dev); | ||
| 963 | if (!mmc) { | ||
| 964 | dev_err(&pdev->dev, "mmc alloc host failed\n"); | ||
| 965 | return -ENOMEM; | ||
| 966 | } | ||
| 967 | |||
| 968 | host = mmc_priv(mmc); | ||
| 969 | host->mmc = mmc; | ||
| 970 | spin_lock_init(&host->lock); | ||
| 971 | |||
| 972 | ret = sunxi_mmc_resource_request(host, pdev); | ||
| 973 | if (ret) | ||
| 974 | goto error_free_host; | ||
| 975 | |||
| 976 | host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, | ||
| 977 | &host->sg_dma, GFP_KERNEL); | ||
| 978 | if (!host->sg_cpu) { | ||
| 979 | dev_err(&pdev->dev, "Failed to allocate DMA descriptor mem\n"); | ||
| 980 | ret = -ENOMEM; | ||
| 981 | goto error_free_host; | ||
| 982 | } | ||
| 983 | |||
| 984 | mmc->ops = &sunxi_mmc_ops; | ||
| 985 | mmc->max_blk_count = 8192; | ||
| 986 | mmc->max_blk_size = 4096; | ||
| 987 | mmc->max_segs = PAGE_SIZE / sizeof(struct sunxi_idma_des); | ||
| 988 | mmc->max_seg_size = (1 << host->idma_des_size_bits); | ||
| 989 | mmc->max_req_size = mmc->max_seg_size * mmc->max_segs; | ||
| 990 | /* 400kHz ~ 50MHz */ | ||
| 991 | mmc->f_min = 400000; | ||
| 992 | mmc->f_max = 50000000; | ||
| 993 | mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; | ||
| 994 | |||
| 995 | ret = mmc_of_parse(mmc); | ||
| 996 | if (ret) | ||
| 997 | goto error_free_dma; | ||
| 998 | |||
| 999 | ret = mmc_add_host(mmc); | ||
| 1000 | if (ret) | ||
| 1001 | goto error_free_dma; | ||
| 1002 | |||
| 1003 | dev_info(&pdev->dev, "base:0x%p irq:%u\n", host->reg_base, host->irq); | ||
| 1004 | platform_set_drvdata(pdev, mmc); | ||
| 1005 | return 0; | ||
| 1006 | |||
| 1007 | error_free_dma: | ||
| 1008 | dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); | ||
| 1009 | error_free_host: | ||
| 1010 | mmc_free_host(mmc); | ||
| 1011 | return ret; | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | static int sunxi_mmc_remove(struct platform_device *pdev) | ||
| 1015 | { | ||
| 1016 | struct mmc_host *mmc = platform_get_drvdata(pdev); | ||
| 1017 | struct sunxi_mmc_host *host = mmc_priv(mmc); | ||
| 1018 | |||
| 1019 | mmc_remove_host(mmc); | ||
| 1020 | disable_irq(host->irq); | ||
| 1021 | sunxi_mmc_reset_host(host); | ||
| 1022 | |||
| 1023 | if (!IS_ERR(host->reset)) | ||
| 1024 | reset_control_assert(host->reset); | ||
| 1025 | |||
| 1026 | clk_disable_unprepare(host->clk_mmc); | ||
| 1027 | clk_disable_unprepare(host->clk_ahb); | ||
| 1028 | |||
| 1029 | dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); | ||
| 1030 | mmc_free_host(mmc); | ||
| 1031 | |||
| 1032 | return 0; | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | static struct platform_driver sunxi_mmc_driver = { | ||
| 1036 | .driver = { | ||
| 1037 | .name = "sunxi-mmc", | ||
| 1038 | .owner = THIS_MODULE, | ||
| 1039 | .of_match_table = of_match_ptr(sunxi_mmc_of_match), | ||
| 1040 | }, | ||
| 1041 | .probe = sunxi_mmc_probe, | ||
| 1042 | .remove = sunxi_mmc_remove, | ||
| 1043 | }; | ||
| 1044 | module_platform_driver(sunxi_mmc_driver); | ||
| 1045 | |||
| 1046 | MODULE_DESCRIPTION("Allwinner's SD/MMC Card Controller Driver"); | ||
| 1047 | MODULE_LICENSE("GPL v2"); | ||
| 1048 | MODULE_AUTHOR("David Lanzend�rfer <david.lanzendoerfer@o2s.ch>"); | ||
| 1049 | MODULE_ALIAS("platform:sunxi-mmc"); | ||
diff --git a/include/dt-bindings/clock/bcm21664.h b/include/dt-bindings/clock/bcm21664.h new file mode 100644 index 000000000000..5a7f0e4750a8 --- /dev/null +++ b/include/dt-bindings/clock/bcm21664.h | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2013 Broadcom Corporation | ||
| 3 | * Copyright 2013 Linaro Limited | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License as | ||
| 7 | * published by the Free Software Foundation version 2. | ||
| 8 | * | ||
| 9 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
| 10 | * kind, whether express or implied; without even the implied warranty | ||
| 11 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #ifndef _CLOCK_BCM21664_H | ||
| 16 | #define _CLOCK_BCM21664_H | ||
| 17 | |||
| 18 | /* | ||
| 19 | * This file defines the values used to specify clocks provided by | ||
| 20 | * the clock control units (CCUs) on Broadcom BCM21664 family SoCs. | ||
| 21 | */ | ||
| 22 | |||
| 23 | /* bcm21664 CCU device tree "compatible" strings */ | ||
| 24 | #define BCM21664_DT_ROOT_CCU_COMPAT "brcm,bcm21664-root-ccu" | ||
| 25 | #define BCM21664_DT_AON_CCU_COMPAT "brcm,bcm21664-aon-ccu" | ||
| 26 | #define BCM21664_DT_MASTER_CCU_COMPAT "brcm,bcm21664-master-ccu" | ||
| 27 | #define BCM21664_DT_SLAVE_CCU_COMPAT "brcm,bcm21664-slave-ccu" | ||
| 28 | |||
| 29 | /* root CCU clock ids */ | ||
| 30 | |||
| 31 | #define BCM21664_ROOT_CCU_FRAC_1M 0 | ||
| 32 | #define BCM21664_ROOT_CCU_CLOCK_COUNT 1 | ||
| 33 | |||
| 34 | /* aon CCU clock ids */ | ||
| 35 | |||
| 36 | #define BCM21664_AON_CCU_HUB_TIMER 0 | ||
| 37 | #define BCM21664_AON_CCU_CLOCK_COUNT 1 | ||
| 38 | |||
| 39 | /* master CCU clock ids */ | ||
| 40 | |||
| 41 | #define BCM21664_MASTER_CCU_SDIO1 0 | ||
| 42 | #define BCM21664_MASTER_CCU_SDIO2 1 | ||
| 43 | #define BCM21664_MASTER_CCU_SDIO3 2 | ||
| 44 | #define BCM21664_MASTER_CCU_SDIO4 3 | ||
| 45 | #define BCM21664_MASTER_CCU_SDIO1_SLEEP 4 | ||
| 46 | #define BCM21664_MASTER_CCU_SDIO2_SLEEP 5 | ||
| 47 | #define BCM21664_MASTER_CCU_SDIO3_SLEEP 6 | ||
| 48 | #define BCM21664_MASTER_CCU_SDIO4_SLEEP 7 | ||
| 49 | #define BCM21664_MASTER_CCU_CLOCK_COUNT 8 | ||
| 50 | |||
| 51 | /* slave CCU clock ids */ | ||
| 52 | |||
| 53 | #define BCM21664_SLAVE_CCU_UARTB 0 | ||
| 54 | #define BCM21664_SLAVE_CCU_UARTB2 1 | ||
| 55 | #define BCM21664_SLAVE_CCU_UARTB3 2 | ||
| 56 | #define BCM21664_SLAVE_CCU_BSC1 3 | ||
| 57 | #define BCM21664_SLAVE_CCU_BSC2 4 | ||
| 58 | #define BCM21664_SLAVE_CCU_BSC3 5 | ||
| 59 | #define BCM21664_SLAVE_CCU_BSC4 6 | ||
| 60 | #define BCM21664_SLAVE_CCU_CLOCK_COUNT 7 | ||
| 61 | |||
| 62 | #endif /* _CLOCK_BCM21664_H */ | ||
diff --git a/include/dt-bindings/clock/bcm281xx.h b/include/dt-bindings/clock/bcm281xx.h index e0096940886d..a763460cf1af 100644 --- a/include/dt-bindings/clock/bcm281xx.h +++ b/include/dt-bindings/clock/bcm281xx.h | |||
| @@ -20,6 +20,18 @@ | |||
| 20 | * the clock control units (CCUs) on Broadcom BCM281XX family SoCs. | 20 | * the clock control units (CCUs) on Broadcom BCM281XX family SoCs. |
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | /* | ||
| 24 | * These are the bcm281xx CCU device tree "compatible" strings. | ||
| 25 | * We're stuck with using "bcm11351" in the string because wild | ||
| 26 | * cards aren't allowed, and that name was the first one defined | ||
| 27 | * in this family of devices. | ||
| 28 | */ | ||
| 29 | #define BCM281XX_DT_ROOT_CCU_COMPAT "brcm,bcm11351-root-ccu" | ||
| 30 | #define BCM281XX_DT_AON_CCU_COMPAT "brcm,bcm11351-aon-ccu" | ||
| 31 | #define BCM281XX_DT_HUB_CCU_COMPAT "brcm,bcm11351-hub-ccu" | ||
| 32 | #define BCM281XX_DT_MASTER_CCU_COMPAT "brcm,bcm11351-master-ccu" | ||
| 33 | #define BCM281XX_DT_SLAVE_CCU_COMPAT "brcm,bcm11351-slave-ccu" | ||
| 34 | |||
| 23 | /* root CCU clock ids */ | 35 | /* root CCU clock ids */ |
| 24 | 36 | ||
| 25 | #define BCM281XX_ROOT_CCU_FRAC_1M 0 | 37 | #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 000000000000..aad579a75802 --- /dev/null +++ b/include/dt-bindings/clock/hix5hd2-clock.h | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014 Linaro Ltd. | ||
| 3 | * Copyright (c) 2014 Hisilicon Limited. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms and conditions of the GNU General Public License, | ||
| 7 | * version 2, as published by the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef __DTS_HIX5HD2_CLOCK_H | ||
| 11 | #define __DTS_HIX5HD2_CLOCK_H | ||
| 12 | |||
| 13 | /* fixed rate */ | ||
| 14 | #define HIX5HD2_FIXED_1200M 1 | ||
| 15 | #define HIX5HD2_FIXED_400M 2 | ||
| 16 | #define HIX5HD2_FIXED_48M 3 | ||
| 17 | #define HIX5HD2_FIXED_24M 4 | ||
| 18 | #define HIX5HD2_FIXED_600M 5 | ||
| 19 | #define HIX5HD2_FIXED_300M 6 | ||
| 20 | #define HIX5HD2_FIXED_75M 7 | ||
| 21 | #define HIX5HD2_FIXED_200M 8 | ||
| 22 | #define HIX5HD2_FIXED_100M 9 | ||
| 23 | #define HIX5HD2_FIXED_40M 10 | ||
| 24 | #define HIX5HD2_FIXED_150M 11 | ||
| 25 | #define HIX5HD2_FIXED_1728M 12 | ||
| 26 | #define HIX5HD2_FIXED_28P8M 13 | ||
| 27 | #define HIX5HD2_FIXED_432M 14 | ||
| 28 | #define HIX5HD2_FIXED_345P6M 15 | ||
| 29 | #define HIX5HD2_FIXED_288M 16 | ||
| 30 | #define HIX5HD2_FIXED_60M 17 | ||
| 31 | #define HIX5HD2_FIXED_750M 18 | ||
| 32 | #define HIX5HD2_FIXED_500M 19 | ||
| 33 | #define HIX5HD2_FIXED_54M 20 | ||
| 34 | #define HIX5HD2_FIXED_27M 21 | ||
| 35 | #define HIX5HD2_FIXED_1500M 22 | ||
| 36 | #define HIX5HD2_FIXED_375M 23 | ||
| 37 | #define HIX5HD2_FIXED_187M 24 | ||
| 38 | #define HIX5HD2_FIXED_250M 25 | ||
| 39 | #define HIX5HD2_FIXED_125M 26 | ||
| 40 | #define HIX5HD2_FIXED_2P02M 27 | ||
| 41 | #define HIX5HD2_FIXED_50M 28 | ||
| 42 | #define HIX5HD2_FIXED_25M 29 | ||
| 43 | #define HIX5HD2_FIXED_83M 30 | ||
| 44 | |||
| 45 | /* mux clocks */ | ||
| 46 | #define HIX5HD2_SFC_MUX 64 | ||
| 47 | #define HIX5HD2_MMC_MUX 65 | ||
| 48 | #define HIX5HD2_FEPHY_MUX 66 | ||
| 49 | |||
| 50 | /* gate clocks */ | ||
| 51 | #define HIX5HD2_SFC_RST 128 | ||
| 52 | #define HIX5HD2_SFC_CLK 129 | ||
| 53 | #define HIX5HD2_MMC_CIU_CLK 130 | ||
| 54 | #define HIX5HD2_MMC_BIU_CLK 131 | ||
| 55 | #define HIX5HD2_MMC_CIU_RST 132 | ||
| 56 | |||
| 57 | #define HIX5HD2_NR_CLKS 256 | ||
| 58 | #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 03bbf49d43b7..f9f547146a15 100644 --- a/include/dt-bindings/clock/qcom,gcc-msm8960.h +++ b/include/dt-bindings/clock/qcom,gcc-msm8960.h | |||
| @@ -51,7 +51,7 @@ | |||
| 51 | #define QDSS_TSCTR_CLK 34 | 51 | #define QDSS_TSCTR_CLK 34 |
| 52 | #define SFAB_ADM0_M0_A_CLK 35 | 52 | #define SFAB_ADM0_M0_A_CLK 35 |
| 53 | #define SFAB_ADM0_M1_A_CLK 36 | 53 | #define SFAB_ADM0_M1_A_CLK 36 |
| 54 | #define SFAB_ADM0_M2_A_CLK 37 | 54 | #define SFAB_ADM0_M2_H_CLK 37 |
| 55 | #define ADM0_CLK 38 | 55 | #define ADM0_CLK 38 |
| 56 | #define ADM0_PBUS_CLK 39 | 56 | #define ADM0_PBUS_CLK 39 |
| 57 | #define MSS_XPU_CLK 40 | 57 | #define MSS_XPU_CLK 40 |
| @@ -99,7 +99,7 @@ | |||
| 99 | #define CFPB2_H_CLK 82 | 99 | #define CFPB2_H_CLK 82 |
| 100 | #define SFAB_CFPB_M_H_CLK 83 | 100 | #define SFAB_CFPB_M_H_CLK 83 |
| 101 | #define CFPB_MASTER_H_CLK 84 | 101 | #define CFPB_MASTER_H_CLK 84 |
| 102 | #define SFAB_CFPB_S_HCLK 85 | 102 | #define SFAB_CFPB_S_H_CLK 85 |
| 103 | #define CFPB_SPLITTER_H_CLK 86 | 103 | #define CFPB_SPLITTER_H_CLK 86 |
| 104 | #define TSIF_H_CLK 87 | 104 | #define TSIF_H_CLK 87 |
| 105 | #define TSIF_INACTIVITY_TIMERS_CLK 88 | 105 | #define TSIF_INACTIVITY_TIMERS_CLK 88 |
| @@ -110,7 +110,6 @@ | |||
| 110 | #define CE1_SLEEP_CLK 93 | 110 | #define CE1_SLEEP_CLK 93 |
| 111 | #define CE2_H_CLK 94 | 111 | #define CE2_H_CLK 94 |
| 112 | #define CE2_CORE_CLK 95 | 112 | #define CE2_CORE_CLK 95 |
| 113 | #define CE2_SLEEP_CLK 96 | ||
| 114 | #define SFPB_H_CLK_SRC 97 | 113 | #define SFPB_H_CLK_SRC 97 |
| 115 | #define SFPB_H_CLK 98 | 114 | #define SFPB_H_CLK 98 |
| 116 | #define SFAB_SFPB_M_H_CLK 99 | 115 | #define SFAB_SFPB_M_H_CLK 99 |
| @@ -252,7 +251,7 @@ | |||
| 252 | #define MSS_S_H_CLK 235 | 251 | #define MSS_S_H_CLK 235 |
| 253 | #define MSS_CXO_SRC_CLK 236 | 252 | #define MSS_CXO_SRC_CLK 236 |
| 254 | #define SATA_H_CLK 237 | 253 | #define SATA_H_CLK 237 |
| 255 | #define SATA_SRC_CLK 238 | 254 | #define SATA_CLK_SRC 238 |
| 256 | #define SATA_RXOOB_CLK 239 | 255 | #define SATA_RXOOB_CLK 239 |
| 257 | #define SATA_PMALIVE_CLK 240 | 256 | #define SATA_PMALIVE_CLK 240 |
| 258 | #define SATA_PHY_REF_CLK 241 | 257 | #define SATA_PHY_REF_CLK 241 |
diff --git a/include/dt-bindings/clock/qcom,gcc-msm8974.h b/include/dt-bindings/clock/qcom,gcc-msm8974.h index 223ca174d9d3..51e51c860fe6 100644 --- a/include/dt-bindings/clock/qcom,gcc-msm8974.h +++ b/include/dt-bindings/clock/qcom,gcc-msm8974.h | |||
| @@ -316,5 +316,9 @@ | |||
| 316 | #define GCC_CE2_CLK_SLEEP_ENA 299 | 316 | #define GCC_CE2_CLK_SLEEP_ENA 299 |
| 317 | #define GCC_CE2_AXI_CLK_SLEEP_ENA 300 | 317 | #define GCC_CE2_AXI_CLK_SLEEP_ENA 300 |
| 318 | #define GCC_CE2_AHB_CLK_SLEEP_ENA 301 | 318 | #define GCC_CE2_AHB_CLK_SLEEP_ENA 301 |
| 319 | #define GPLL4 302 | ||
| 320 | #define GPLL4_VOTE 303 | ||
| 321 | #define GCC_SDCC1_CDCCAL_SLEEP_CLK 304 | ||
| 322 | #define GCC_SDCC1_CDCCAL_FF_CLK 305 | ||
| 319 | 323 | ||
| 320 | #endif | 324 | #endif |
diff --git a/include/dt-bindings/clock/r8a7779-clock.h b/include/dt-bindings/clock/r8a7779-clock.h new file mode 100644 index 000000000000..381a6114237a --- /dev/null +++ b/include/dt-bindings/clock/r8a7779-clock.h | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2013 Horms Solutions Ltd. | ||
| 3 | * | ||
| 4 | * Contact: Simon Horman <horms@verge.net.au> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef __DT_BINDINGS_CLOCK_R8A7779_H__ | ||
| 13 | #define __DT_BINDINGS_CLOCK_R8A7779_H__ | ||
| 14 | |||
| 15 | /* CPG */ | ||
| 16 | #define R8A7779_CLK_PLLA 0 | ||
| 17 | #define R8A7779_CLK_Z 1 | ||
| 18 | #define R8A7779_CLK_ZS 2 | ||
| 19 | #define R8A7779_CLK_S 3 | ||
| 20 | #define R8A7779_CLK_S1 4 | ||
| 21 | #define R8A7779_CLK_P 5 | ||
| 22 | #define R8A7779_CLK_B 6 | ||
| 23 | #define R8A7779_CLK_OUT 7 | ||
| 24 | |||
| 25 | /* MSTP 0 */ | ||
| 26 | #define R8A7779_CLK_HSPI 7 | ||
| 27 | #define R8A7779_CLK_TMU2 14 | ||
| 28 | #define R8A7779_CLK_TMU1 15 | ||
| 29 | #define R8A7779_CLK_TMU0 16 | ||
| 30 | #define R8A7779_CLK_HSCIF1 18 | ||
| 31 | #define R8A7779_CLK_HSCIF0 19 | ||
| 32 | #define R8A7779_CLK_SCIF5 21 | ||
| 33 | #define R8A7779_CLK_SCIF4 22 | ||
| 34 | #define R8A7779_CLK_SCIF3 23 | ||
| 35 | #define R8A7779_CLK_SCIF2 24 | ||
| 36 | #define R8A7779_CLK_SCIF1 25 | ||
| 37 | #define R8A7779_CLK_SCIF0 26 | ||
| 38 | #define R8A7779_CLK_I2C3 27 | ||
| 39 | #define R8A7779_CLK_I2C2 28 | ||
| 40 | #define R8A7779_CLK_I2C1 29 | ||
| 41 | #define R8A7779_CLK_I2C0 30 | ||
| 42 | |||
| 43 | /* MSTP 1 */ | ||
| 44 | #define R8A7779_CLK_USB01 0 | ||
| 45 | #define R8A7779_CLK_USB2 1 | ||
| 46 | #define R8A7779_CLK_DU 3 | ||
| 47 | #define R8A7779_CLK_VIN2 8 | ||
| 48 | #define R8A7779_CLK_VIN1 9 | ||
| 49 | #define R8A7779_CLK_VIN0 10 | ||
| 50 | #define R8A7779_CLK_ETHER 14 | ||
| 51 | #define R8A7779_CLK_SATA 15 | ||
| 52 | #define R8A7779_CLK_PCIE 16 | ||
| 53 | #define R8A7779_CLK_VIN3 20 | ||
| 54 | |||
| 55 | /* MSTP 3 */ | ||
| 56 | #define R8A7779_CLK_SDHI3 20 | ||
| 57 | #define R8A7779_CLK_SDHI2 21 | ||
| 58 | #define R8A7779_CLK_SDHI1 22 | ||
| 59 | #define R8A7779_CLK_SDHI0 23 | ||
| 60 | #define R8A7779_CLK_MMC1 30 | ||
| 61 | #define R8A7779_CLK_MMC0 31 | ||
| 62 | |||
| 63 | |||
| 64 | #endif /* __DT_BINDINGS_CLOCK_R8A7779_H__ */ | ||
diff --git a/include/dt-bindings/clock/tegra114-car.h b/include/dt-bindings/clock/tegra114-car.h index 6d0d8d8ef31e..fc12621fb432 100644 --- a/include/dt-bindings/clock/tegra114-car.h +++ b/include/dt-bindings/clock/tegra114-car.h | |||
| @@ -337,6 +337,7 @@ | |||
| 337 | #define TEGRA114_CLK_CLK_OUT_3_MUX 308 | 337 | #define TEGRA114_CLK_CLK_OUT_3_MUX 308 |
| 338 | #define TEGRA114_CLK_DSIA_MUX 309 | 338 | #define TEGRA114_CLK_DSIA_MUX 309 |
| 339 | #define TEGRA114_CLK_DSIB_MUX 310 | 339 | #define TEGRA114_CLK_DSIB_MUX 310 |
| 340 | #define TEGRA114_CLK_CLK_MAX 311 | 340 | #define TEGRA114_CLK_XUSB_SS_DIV2 311 |
| 341 | #define TEGRA114_CLK_CLK_MAX 312 | ||
| 341 | 342 | ||
| 342 | #endif /* _DT_BINDINGS_CLOCK_TEGRA114_CAR_H */ | 343 | #endif /* _DT_BINDINGS_CLOCK_TEGRA114_CAR_H */ |
diff --git a/include/dt-bindings/clock/tegra124-car.h b/include/dt-bindings/clock/tegra124-car.h index 433528ab5161..8a4c5892890f 100644 --- a/include/dt-bindings/clock/tegra124-car.h +++ b/include/dt-bindings/clock/tegra124-car.h | |||
| @@ -336,6 +336,7 @@ | |||
| 336 | #define TEGRA124_CLK_DSIA_MUX 309 | 336 | #define TEGRA124_CLK_DSIA_MUX 309 |
| 337 | #define TEGRA124_CLK_DSIB_MUX 310 | 337 | #define TEGRA124_CLK_DSIB_MUX 310 |
| 338 | #define TEGRA124_CLK_SOR0_LVDS 311 | 338 | #define TEGRA124_CLK_SOR0_LVDS 311 |
| 339 | #define TEGRA124_CLK_CLK_MAX 312 | 339 | #define TEGRA124_CLK_XUSB_SS_DIV2 312 |
| 340 | #define TEGRA124_CLK_CLK_MAX 313 | ||
| 340 | 341 | ||
| 341 | #endif /* _DT_BINDINGS_CLOCK_TEGRA124_CAR_H */ | 342 | #endif /* _DT_BINDINGS_CLOCK_TEGRA124_CAR_H */ |
diff --git a/include/dt-bindings/reset/qcom,gcc-msm8960.h b/include/dt-bindings/reset/qcom,gcc-msm8960.h index a840e680323c..07edd0e65eed 100644 --- a/include/dt-bindings/reset/qcom,gcc-msm8960.h +++ b/include/dt-bindings/reset/qcom,gcc-msm8960.h | |||
| @@ -58,7 +58,7 @@ | |||
| 58 | #define PPSS_PROC_RESET 41 | 58 | #define PPSS_PROC_RESET 41 |
| 59 | #define PPSS_RESET 42 | 59 | #define PPSS_RESET 42 |
| 60 | #define DMA_BAM_RESET 43 | 60 | #define DMA_BAM_RESET 43 |
| 61 | #define SIC_TIC_RESET 44 | 61 | #define SPS_TIC_H_RESET 44 |
| 62 | #define SLIMBUS_H_RESET 45 | 62 | #define SLIMBUS_H_RESET 45 |
| 63 | #define SFAB_CFPB_M_RESET 46 | 63 | #define SFAB_CFPB_M_RESET 46 |
| 64 | #define SFAB_CFPB_S_RESET 47 | 64 | #define SFAB_CFPB_S_RESET 47 |
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index f295bab1865d..0c287dbbb144 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h | |||
| @@ -40,14 +40,14 @@ struct dentry; | |||
| 40 | * through the clk_* api. | 40 | * through the clk_* api. |
| 41 | * | 41 | * |
| 42 | * @prepare: Prepare the clock for enabling. This must not return until | 42 | * @prepare: Prepare the clock for enabling. This must not return until |
| 43 | * the clock is fully prepared, and it's safe to call clk_enable. | 43 | * the clock is fully prepared, and it's safe to call clk_enable. |
| 44 | * This callback is intended to allow clock implementations to | 44 | * This callback is intended to allow clock implementations to |
| 45 | * do any initialisation that may sleep. Called with | 45 | * do any initialisation that may sleep. Called with |
| 46 | * prepare_lock held. | 46 | * prepare_lock held. |
| 47 | * | 47 | * |
| 48 | * @unprepare: Release the clock from its prepared state. This will typically | 48 | * @unprepare: Release the clock from its prepared state. This will typically |
| 49 | * undo any work done in the @prepare callback. Called with | 49 | * undo any work done in the @prepare callback. Called with |
| 50 | * prepare_lock held. | 50 | * prepare_lock held. |
| 51 | * | 51 | * |
| 52 | * @is_prepared: Queries the hardware to determine if the clock is prepared. | 52 | * @is_prepared: Queries the hardware to determine if the clock is prepared. |
| 53 | * This function is allowed to sleep. Optional, if this op is not | 53 | * This function is allowed to sleep. Optional, if this op is not |
| @@ -58,16 +58,16 @@ struct dentry; | |||
| 58 | * Called with prepare mutex held. This function may sleep. | 58 | * Called with prepare mutex held. This function may sleep. |
| 59 | * | 59 | * |
| 60 | * @enable: Enable the clock atomically. This must not return until the | 60 | * @enable: Enable the clock atomically. This must not return until the |
| 61 | * clock is generating a valid clock signal, usable by consumer | 61 | * clock is generating a valid clock signal, usable by consumer |
| 62 | * devices. Called with enable_lock held. This function must not | 62 | * devices. Called with enable_lock held. This function must not |
| 63 | * sleep. | 63 | * sleep. |
| 64 | * | 64 | * |
| 65 | * @disable: Disable the clock atomically. Called with enable_lock held. | 65 | * @disable: Disable the clock atomically. Called with enable_lock held. |
| 66 | * This function must not sleep. | 66 | * This function must not sleep. |
| 67 | * | 67 | * |
| 68 | * @is_enabled: Queries the hardware to determine if the clock is enabled. | 68 | * @is_enabled: Queries the hardware to determine if the clock is enabled. |
| 69 | * This function must not sleep. Optional, if this op is not | 69 | * This function must not sleep. Optional, if this op is not |
| 70 | * set then the enable count will be used. | 70 | * set then the enable count will be used. |
| 71 | * | 71 | * |
| 72 | * @disable_unused: Disable the clock atomically. Only called from | 72 | * @disable_unused: Disable the clock atomically. Only called from |
| 73 | * clk_disable_unused for gate clocks with special needs. | 73 | * clk_disable_unused for gate clocks with special needs. |
| @@ -75,34 +75,35 @@ struct dentry; | |||
| 75 | * sleep. | 75 | * sleep. |
| 76 | * | 76 | * |
| 77 | * @recalc_rate Recalculate the rate of this clock, by querying hardware. The | 77 | * @recalc_rate Recalculate the rate of this clock, by querying hardware. The |
| 78 | * parent rate is an input parameter. It is up to the caller to | 78 | * parent rate is an input parameter. It is up to the caller to |
| 79 | * ensure that the prepare_mutex is held across this call. | 79 | * ensure that the prepare_mutex is held across this call. |
| 80 | * Returns the calculated rate. Optional, but recommended - if | 80 | * Returns the calculated rate. Optional, but recommended - if |
| 81 | * this op is not set then clock rate will be initialized to 0. | 81 | * this op is not set then clock rate will be initialized to 0. |
| 82 | * | 82 | * |
| 83 | * @round_rate: Given a target rate as input, returns the closest rate actually | 83 | * @round_rate: Given a target rate as input, returns the closest rate actually |
| 84 | * supported by the clock. | 84 | * supported by the clock. The parent rate is an input/output |
| 85 | * parameter. | ||
| 85 | * | 86 | * |
| 86 | * @determine_rate: Given a target rate as input, returns the closest rate | 87 | * @determine_rate: Given a target rate as input, returns the closest rate |
| 87 | * actually supported by the clock, and optionally the parent clock | 88 | * actually supported by the clock, and optionally the parent clock |
| 88 | * that should be used to provide the clock rate. | 89 | * that should be used to provide the clock rate. |
| 89 | * | 90 | * |
| 90 | * @get_parent: Queries the hardware to determine the parent of a clock. The | ||
| 91 | * return value is a u8 which specifies the index corresponding to | ||
| 92 | * the parent clock. This index can be applied to either the | ||
| 93 | * .parent_names or .parents arrays. In short, this function | ||
| 94 | * translates the parent value read from hardware into an array | ||
| 95 | * index. Currently only called when the clock is initialized by | ||
| 96 | * __clk_init. This callback is mandatory for clocks with | ||
| 97 | * multiple parents. It is optional (and unnecessary) for clocks | ||
| 98 | * with 0 or 1 parents. | ||
| 99 | * | ||
| 100 | * @set_parent: Change the input source of this clock; for clocks with multiple | 91 | * @set_parent: Change the input source of this clock; for clocks with multiple |
| 101 | * possible parents specify a new parent by passing in the index | 92 | * possible parents specify a new parent by passing in the index |
| 102 | * as a u8 corresponding to the parent in either the .parent_names | 93 | * as a u8 corresponding to the parent in either the .parent_names |
| 103 | * or .parents arrays. This function in affect translates an | 94 | * or .parents arrays. This function in affect translates an |
| 104 | * array index into the value programmed into the hardware. | 95 | * array index into the value programmed into the hardware. |
| 105 | * Returns 0 on success, -EERROR otherwise. | 96 | * Returns 0 on success, -EERROR otherwise. |
| 97 | * | ||
| 98 | * @get_parent: Queries the hardware to determine the parent of a clock. The | ||
| 99 | * return value is a u8 which specifies the index corresponding to | ||
| 100 | * the parent clock. This index can be applied to either the | ||
| 101 | * .parent_names or .parents arrays. In short, this function | ||
| 102 | * translates the parent value read from hardware into an array | ||
| 103 | * index. Currently only called when the clock is initialized by | ||
| 104 | * __clk_init. This callback is mandatory for clocks with | ||
| 105 | * multiple parents. It is optional (and unnecessary) for clocks | ||
| 106 | * with 0 or 1 parents. | ||
| 106 | * | 107 | * |
| 107 | * @set_rate: Change the rate of this clock. The requested rate is specified | 108 | * @set_rate: Change the rate of this clock. The requested rate is specified |
| 108 | * by the second argument, which should typically be the return | 109 | * by the second argument, which should typically be the return |
| @@ -110,13 +111,6 @@ struct dentry; | |||
| 110 | * which is likely helpful for most .set_rate implementation. | 111 | * which is likely helpful for most .set_rate implementation. |
| 111 | * Returns 0 on success, -EERROR otherwise. | 112 | * Returns 0 on success, -EERROR otherwise. |
| 112 | * | 113 | * |
| 113 | * @recalc_accuracy: Recalculate the accuracy of this clock. The clock accuracy | ||
| 114 | * is expressed in ppb (parts per billion). The parent accuracy is | ||
| 115 | * an input parameter. | ||
| 116 | * Returns the calculated accuracy. Optional - if this op is not | ||
| 117 | * set then clock accuracy will be initialized to parent accuracy | ||
| 118 | * or 0 (perfect clock) if clock has no parent. | ||
| 119 | * | ||
| 120 | * @set_rate_and_parent: Change the rate and the parent of this clock. The | 114 | * @set_rate_and_parent: Change the rate and the parent of this clock. The |
| 121 | * requested rate is specified by the second argument, which | 115 | * requested rate is specified by the second argument, which |
| 122 | * should typically be the return of .round_rate call. The | 116 | * should typically be the return of .round_rate call. The |
| @@ -128,6 +122,18 @@ struct dentry; | |||
| 128 | * separately via calls to .set_parent and .set_rate. | 122 | * separately via calls to .set_parent and .set_rate. |
| 129 | * Returns 0 on success, -EERROR otherwise. | 123 | * Returns 0 on success, -EERROR otherwise. |
| 130 | * | 124 | * |
| 125 | * @recalc_accuracy: Recalculate the accuracy of this clock. The clock accuracy | ||
| 126 | * is expressed in ppb (parts per billion). The parent accuracy is | ||
| 127 | * an input parameter. | ||
| 128 | * Returns the calculated accuracy. Optional - if this op is not | ||
| 129 | * set then clock accuracy will be initialized to parent accuracy | ||
| 130 | * or 0 (perfect clock) if clock has no parent. | ||
| 131 | * | ||
| 132 | * @init: Perform platform-specific initialization magic. | ||
| 133 | * This is not not used by any of the basic clock types. | ||
| 134 | * Please consider other ways of solving initialization problems | ||
| 135 | * before using this callback, as its use is discouraged. | ||
| 136 | * | ||
| 131 | * @debug_init: Set up type-specific debugfs entries for this clock. This | 137 | * @debug_init: Set up type-specific debugfs entries for this clock. This |
| 132 | * is called once, after the debugfs directory entry for this | 138 | * is called once, after the debugfs directory entry for this |
| 133 | * clock has been created. The dentry pointer representing that | 139 | * clock has been created. The dentry pointer representing that |
| @@ -157,15 +163,15 @@ struct clk_ops { | |||
| 157 | void (*disable_unused)(struct clk_hw *hw); | 163 | void (*disable_unused)(struct clk_hw *hw); |
| 158 | unsigned long (*recalc_rate)(struct clk_hw *hw, | 164 | unsigned long (*recalc_rate)(struct clk_hw *hw, |
| 159 | unsigned long parent_rate); | 165 | unsigned long parent_rate); |
| 160 | long (*round_rate)(struct clk_hw *hw, unsigned long, | 166 | long (*round_rate)(struct clk_hw *hw, unsigned long rate, |
| 161 | unsigned long *); | 167 | unsigned long *parent_rate); |
| 162 | long (*determine_rate)(struct clk_hw *hw, unsigned long rate, | 168 | long (*determine_rate)(struct clk_hw *hw, unsigned long rate, |
| 163 | unsigned long *best_parent_rate, | 169 | unsigned long *best_parent_rate, |
| 164 | struct clk **best_parent_clk); | 170 | struct clk **best_parent_clk); |
| 165 | int (*set_parent)(struct clk_hw *hw, u8 index); | 171 | int (*set_parent)(struct clk_hw *hw, u8 index); |
| 166 | u8 (*get_parent)(struct clk_hw *hw); | 172 | u8 (*get_parent)(struct clk_hw *hw); |
| 167 | int (*set_rate)(struct clk_hw *hw, unsigned long, | 173 | int (*set_rate)(struct clk_hw *hw, unsigned long rate, |
| 168 | unsigned long); | 174 | unsigned long parent_rate); |
| 169 | int (*set_rate_and_parent)(struct clk_hw *hw, | 175 | int (*set_rate_and_parent)(struct clk_hw *hw, |
| 170 | unsigned long rate, | 176 | unsigned long rate, |
| 171 | unsigned long parent_rate, u8 index); | 177 | unsigned long parent_rate, u8 index); |
| @@ -254,12 +260,12 @@ void of_fixed_clk_setup(struct device_node *np); | |||
| 254 | * | 260 | * |
| 255 | * Flags: | 261 | * Flags: |
| 256 | * CLK_GATE_SET_TO_DISABLE - by default this clock sets the bit at bit_idx to | 262 | * CLK_GATE_SET_TO_DISABLE - by default this clock sets the bit at bit_idx to |
| 257 | * enable the clock. Setting this flag does the opposite: setting the bit | 263 | * enable the clock. Setting this flag does the opposite: setting the bit |
| 258 | * disable the clock and clearing it enables the clock | 264 | * disable the clock and clearing it enables the clock |
| 259 | * CLK_GATE_HIWORD_MASK - The gate settings are only in lower 16-bit | 265 | * CLK_GATE_HIWORD_MASK - The gate settings are only in lower 16-bit |
| 260 | * of this register, and mask of gate bits are in higher 16-bit of this | 266 | * of this register, and mask of gate bits are in higher 16-bit of this |
| 261 | * register. While setting the gate bits, higher 16-bit should also be | 267 | * register. While setting the gate bits, higher 16-bit should also be |
| 262 | * updated to indicate changing gate bits. | 268 | * updated to indicate changing gate bits. |
| 263 | */ | 269 | */ |
| 264 | struct clk_gate { | 270 | struct clk_gate { |
| 265 | struct clk_hw hw; | 271 | struct clk_hw hw; |
| @@ -298,20 +304,24 @@ struct clk_div_table { | |||
| 298 | * | 304 | * |
| 299 | * Flags: | 305 | * Flags: |
| 300 | * CLK_DIVIDER_ONE_BASED - by default the divisor is the value read from the | 306 | * CLK_DIVIDER_ONE_BASED - by default the divisor is the value read from the |
| 301 | * register plus one. If CLK_DIVIDER_ONE_BASED is set then the divider is | 307 | * register plus one. If CLK_DIVIDER_ONE_BASED is set then the divider is |
| 302 | * the raw value read from the register, with the value of zero considered | 308 | * the raw value read from the register, with the value of zero considered |
| 303 | * invalid, unless CLK_DIVIDER_ALLOW_ZERO is set. | 309 | * invalid, unless CLK_DIVIDER_ALLOW_ZERO is set. |
| 304 | * CLK_DIVIDER_POWER_OF_TWO - clock divisor is 2 raised to the value read from | 310 | * CLK_DIVIDER_POWER_OF_TWO - clock divisor is 2 raised to the value read from |
| 305 | * the hardware register | 311 | * the hardware register |
| 306 | * CLK_DIVIDER_ALLOW_ZERO - Allow zero divisors. For dividers which have | 312 | * CLK_DIVIDER_ALLOW_ZERO - Allow zero divisors. For dividers which have |
| 307 | * CLK_DIVIDER_ONE_BASED set, it is possible to end up with a zero divisor. | 313 | * CLK_DIVIDER_ONE_BASED set, it is possible to end up with a zero divisor. |
| 308 | * Some hardware implementations gracefully handle this case and allow a | 314 | * Some hardware implementations gracefully handle this case and allow a |
| 309 | * zero divisor by not modifying their input clock | 315 | * zero divisor by not modifying their input clock |
| 310 | * (divide by one / bypass). | 316 | * (divide by one / bypass). |
| 311 | * CLK_DIVIDER_HIWORD_MASK - The divider settings are only in lower 16-bit | 317 | * CLK_DIVIDER_HIWORD_MASK - The divider settings are only in lower 16-bit |
| 312 | * of this register, and mask of divider bits are in higher 16-bit of this | 318 | * of this register, and mask of divider bits are in higher 16-bit of this |
| 313 | * register. While setting the divider bits, higher 16-bit should also be | 319 | * register. While setting the divider bits, higher 16-bit should also be |
| 314 | * updated to indicate changing divider bits. | 320 | * updated to indicate changing divider bits. |
| 321 | * CLK_DIVIDER_ROUND_CLOSEST - Makes the best calculated divider to be rounded | ||
| 322 | * to the closest integer instead of the up one. | ||
| 323 | * CLK_DIVIDER_READ_ONLY - The divider settings are preconfigured and should | ||
| 324 | * not be changed by the clock framework. | ||
| 315 | */ | 325 | */ |
| 316 | struct clk_divider { | 326 | struct clk_divider { |
| 317 | struct clk_hw hw; | 327 | struct clk_hw hw; |
| @@ -327,8 +337,11 @@ struct clk_divider { | |||
| 327 | #define CLK_DIVIDER_POWER_OF_TWO BIT(1) | 337 | #define CLK_DIVIDER_POWER_OF_TWO BIT(1) |
| 328 | #define CLK_DIVIDER_ALLOW_ZERO BIT(2) | 338 | #define CLK_DIVIDER_ALLOW_ZERO BIT(2) |
| 329 | #define CLK_DIVIDER_HIWORD_MASK BIT(3) | 339 | #define CLK_DIVIDER_HIWORD_MASK BIT(3) |
| 340 | #define CLK_DIVIDER_ROUND_CLOSEST BIT(4) | ||
| 341 | #define CLK_DIVIDER_READ_ONLY BIT(5) | ||
| 330 | 342 | ||
| 331 | extern const struct clk_ops clk_divider_ops; | 343 | extern const struct clk_ops clk_divider_ops; |
| 344 | extern const struct clk_ops clk_divider_ro_ops; | ||
| 332 | struct clk *clk_register_divider(struct device *dev, const char *name, | 345 | struct clk *clk_register_divider(struct device *dev, const char *name, |
| 333 | const char *parent_name, unsigned long flags, | 346 | const char *parent_name, unsigned long flags, |
| 334 | void __iomem *reg, u8 shift, u8 width, | 347 | void __iomem *reg, u8 shift, u8 width, |
| @@ -356,9 +369,9 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name, | |||
| 356 | * CLK_MUX_INDEX_ONE - register index starts at 1, not 0 | 369 | * CLK_MUX_INDEX_ONE - register index starts at 1, not 0 |
| 357 | * CLK_MUX_INDEX_BIT - register index is a single bit (power of two) | 370 | * CLK_MUX_INDEX_BIT - register index is a single bit (power of two) |
| 358 | * CLK_MUX_HIWORD_MASK - The mux settings are only in lower 16-bit of this | 371 | * CLK_MUX_HIWORD_MASK - The mux settings are only in lower 16-bit of this |
| 359 | * register, and mask of mux bits are in higher 16-bit of this register. | 372 | * register, and mask of mux bits are in higher 16-bit of this register. |
| 360 | * While setting the mux bits, higher 16-bit should also be updated to | 373 | * While setting the mux bits, higher 16-bit should also be updated to |
| 361 | * indicate changing mux bits. | 374 | * indicate changing mux bits. |
| 362 | */ | 375 | */ |
| 363 | struct clk_mux { | 376 | struct clk_mux { |
| 364 | struct clk_hw hw; | 377 | struct clk_hw hw; |
diff --git a/include/linux/clk/shmobile.h b/include/linux/clk/shmobile.h index f9bf080a1123..9f8a14041dd5 100644 --- a/include/linux/clk/shmobile.h +++ b/include/linux/clk/shmobile.h | |||
| @@ -1,7 +1,9 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright 2013 Ideas On Board SPRL | 2 | * Copyright 2013 Ideas On Board SPRL |
| 3 | * Copyright 2013, 2014 Horms Solutions Ltd. | ||
| 3 | * | 4 | * |
| 4 | * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 5 | * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
| 6 | * Contact: Simon Horman <horms@verge.net.au> | ||
| 5 | * | 7 | * |
| 6 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
| @@ -14,6 +16,7 @@ | |||
| 14 | 16 | ||
| 15 | #include <linux/types.h> | 17 | #include <linux/types.h> |
| 16 | 18 | ||
| 19 | void r8a7779_clocks_init(u32 mode); | ||
| 17 | void rcar_gen2_clocks_init(u32 mode); | 20 | void rcar_gen2_clocks_init(u32 mode); |
| 18 | 21 | ||
| 19 | #endif | 22 | #endif |
diff --git a/include/linux/clk/sunxi.h b/include/linux/clk/sunxi.h new file mode 100644 index 000000000000..aed28c4451d9 --- /dev/null +++ b/include/linux/clk/sunxi.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2013 - Hans de Goede <hdegoede@redhat.com> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation; either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #ifndef __LINUX_CLK_SUNXI_H_ | ||
| 16 | #define __LINUX_CLK_SUNXI_H_ | ||
| 17 | |||
| 18 | #include <linux/clk.h> | ||
| 19 | |||
| 20 | void clk_sunxi_mmc_phase_control(struct clk *clk, u8 sample, u8 output); | ||
| 21 | |||
| 22 | #endif | ||
