mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-16 17:23:55 +08:00
The core clk framework changes are small again. They're mostly minor fixes
that weren't causing enough problems (or any problems when we're just clarifying things) to warrant sending outside the merge window. The majority of changes are in drivers for various SoCs. Full details are in the logs, but here's the summary. Core: - Better support for DeviceTree overlays with the addition of the CLK_OF_DECLARE_DRIVER macro. Now we won't probe a clk driver for a device node that matched during of_clk_init(), unless the driver uses CLK_OF_DECLARE_DRIVER instead of CLK_OF_DECLARE. This allows overlays to work cleanly for drivers that must probe before the device model is ready, and also after it's ready when an overlay is loaded. - Clarification in the code around how clk_hw pointers are returned from of clk providers - Proper migration of prepare/enable counts to parents when the clk tree is constructed New Drivers: - Socionext's UniPhier SoCs - Loongson1C - ZTE ZX296718 - Qualcomm MDM9615 - Amlogic GXBB AO clocks and resets - Broadcom BCM53573 ILP - Maxim MAX77620 Updates: - Four Allwinner SoCs are migrated to the new style clk driver (A31, A31s, A23 and A33) - Exynos 5xxx audio and DRAM clks - Loongson1B AC97, DMA and NAND clks - Rockchip DDR clks and rk3399 driver tweaks - Renesas R-Car M3-W (r8a7796) SoC SDHI interface and Watchdog timer clks - Renasas R-Car H3 and M3-W CMT clks and RAVB+Thermal clks for M3-W - Amlogic GXBB MMC gate clks - at91 sama5d4 sckc - Removal of STiH415 and STiH416 clk support as the SoC is being removed - Rework of STiH4xx clk support for new style bindings - Continuation of driver migration to clk_hw based registration APIs - xgene PMD support - bcm2835 critical clk markings - ARM versatile ICST -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABCAAGBQJX8v/WAAoJEK0CiJfG5JUl0YsQAJr91iV+yHQJAML1BS+nQO9T NMbGx/7Pmi2E2S7d62BtQO1kw4zFUX1rURfoTKWfB7vTfHLm1zs5S6MSLxayEr34 S3PCheFxPQY7OuzCfDFhMeavDha0bZ2jha7IHdshZndA/ZwYX3ghyHFEQf0rzRE+ HJ3+TGYijXi+/3dyM95HJrZ5A91cJhqhzmSfCvAG/cJgPDHkM8lDvhmNfiO+b4WX 0BLM+OQj3m5Ob7AXV8L2M3/CELKBzf8gZlDYP4b8LT5xc5P+225UevWQnFpJ6BWt 32ANz5Wc3MRJw7db4/A5aR/UNCaZZCfC/Sd8BXrHL+7RuxxnHAGEBPeAH5Pd0ubF zn1kZ7fQVvDbqim2S9gw6u7i4YoiYTj1PmQmY3j2iosjGxj2n2RK0zha4Y65b2rV CxlW07nKvNOgJH7bfQSazM6RIPpht7uDwKJ9dWb20uzRIOL2t94Msg1eXQvgD9ec nBn7wq6yBGlyvgg5s9WBogwUWJyg0wXrhN84q+cjptCqFfXUwR1AKRvS+T2EP2G0 B4HFw/hvnJqGgv5xBh/jWt9ZyqvLB0cSRMZtTcSMclrCdcECd2PbF4gVKUR99wVH ND1fai1/PbLZ4yxuUAuEQ5P866aq6Hj5iEXqe0dGUpA1lZWrYrB+vs/lwADyBcsR 7//DbP9+dHZFbJDQyiWK =NFUB -----END PGP SIGNATURE----- Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux Pull clk framework updates from Stephen Boyd: "The core clk framework changes are small again. They're mostly minor fixes that weren't causing enough problems (or any problems when we're just clarifying things) to warrant sending outside the merge window. The majority of changes are in drivers for various SoCs. Full details are in the logs, but here's the summary. Core: - Better support for DeviceTree overlays with the addition of the CLK_OF_DECLARE_DRIVER macro. Now we won't probe a clk driver for a device node that matched during of_clk_init(), unless the driver uses CLK_OF_DECLARE_DRIVER instead of CLK_OF_DECLARE. This allows overlays to work cleanly for drivers that must probe before the device model is ready, and also after it's ready when an overlay is loaded. - Clarification in the code around how clk_hw pointers are returned from of clk providers - Proper migration of prepare/enable counts to parents when the clk tree is constructed New Drivers: - Socionext's UniPhier SoCs - Loongson1C - ZTE ZX296718 - Qualcomm MDM9615 - Amlogic GXBB AO clocks and resets - Broadcom BCM53573 ILP - Maxim MAX77620 Updates: - Four Allwinner SoCs are migrated to the new style clk driver (A31, A31s, A23 and A33) - Exynos 5xxx audio and DRAM clks - Loongson1B AC97, DMA and NAND clks - Rockchip DDR clks and rk3399 driver tweaks - Renesas R-Car M3-W (r8a7796) SoC SDHI interface and Watchdog timer clks - Renasas R-Car H3 and M3-W CMT clks and RAVB+Thermal clks for M3-W - Amlogic GXBB MMC gate clks - at91 sama5d4 sckc - Removal of STiH415 and STiH416 clk support as the SoC is being removed - Rework of STiH4xx clk support for new style bindings - Continuation of driver migration to clk_hw based registration APIs - xgene PMD support - bcm2835 critical clk markings - ARM versatile ICST" * tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (199 commits) CLK: Add Loongson1C clock support clk: Loongson1: Make use of GENMASK clk: Loongson1: Update clocks of Loongson1B clk: Loongson1: Refactor Loongson1 clock clk: change the type of clk_hw_onecell_data.num to unsigned int clk: zx296718: register driver earlier with core_initcall clk: mvebu: dynamically allocate resources in Armada CP110 system controller clk: mvebu: fix setting unwanted flags in CP110 gate clock clk: nxp: clk-lpc32xx: Unmap region obtained by of_iomap clk: mediatek: clk-mt8173: Unmap region obtained by of_iomap clk: sunxi-ng: Fix reset offset for the A23 and A33 clk: at91: sckc: optimize boot time clk: at91: Add sama5d4 sckc support clk: at91: move slow clock controller clocks to sckc.c clk: imx6: initialize GPU clocks clk: imx6: fix i.MX6DL clock tree to reflect reality clk: imx53: Add clocks configuration clk: uniphier: add clock data for UniPhier SoCs clk: uniphier: add core support code for UniPhier clock driver clk: bcm: Add driver for BCM53573 ILP clock ...
This commit is contained in:
commit
5617c122e6
@ -5,7 +5,8 @@ The Mediatek apmixedsys controller provides the PLLs to the system.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: Should be:
|
||||
- compatible: Should be one of:
|
||||
- "mediatek,mt2701-apmixedsys"
|
||||
- "mediatek,mt8135-apmixedsys"
|
||||
- "mediatek,mt8173-apmixedsys"
|
||||
- #clock-cells: Must be 1
|
||||
|
@ -0,0 +1,22 @@
|
||||
Mediatek bdpsys controller
|
||||
============================
|
||||
|
||||
The Mediatek bdpsys controller provides various clocks to the system.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: Should be:
|
||||
- "mediatek,mt2701-bdpsys", "syscon"
|
||||
- #clock-cells: Must be 1
|
||||
|
||||
The bdpsys controller uses the common clk binding from
|
||||
Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
|
||||
|
||||
Example:
|
||||
|
||||
bdpsys: clock-controller@1c000000 {
|
||||
compatible = "mediatek,mt2701-bdpsys", "syscon";
|
||||
reg = <0 0x1c000000 0 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
@ -0,0 +1,22 @@
|
||||
Mediatek ethsys controller
|
||||
============================
|
||||
|
||||
The Mediatek ethsys controller provides various clocks to the system.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: Should be:
|
||||
- "mediatek,mt2701-ethsys", "syscon"
|
||||
- #clock-cells: Must be 1
|
||||
|
||||
The ethsys controller uses the common clk binding from
|
||||
Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
|
||||
|
||||
Example:
|
||||
|
||||
ethsys: clock-controller@1b000000 {
|
||||
compatible = "mediatek,mt2701-ethsys", "syscon";
|
||||
reg = <0 0x1b000000 0 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
@ -0,0 +1,24 @@
|
||||
Mediatek hifsys controller
|
||||
============================
|
||||
|
||||
The Mediatek hifsys controller provides various clocks and reset
|
||||
outputs to the system.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: Should be:
|
||||
- "mediatek,mt2701-hifsys", "syscon"
|
||||
- #clock-cells: Must be 1
|
||||
|
||||
The hifsys controller uses the common clk binding from
|
||||
Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
|
||||
|
||||
Example:
|
||||
|
||||
hifsys: clock-controller@1a000000 {
|
||||
compatible = "mediatek,mt2701-hifsys", "syscon";
|
||||
reg = <0 0x1a000000 0 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
@ -5,7 +5,8 @@ The Mediatek imgsys controller provides various clocks to the system.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: Should be:
|
||||
- compatible: Should be one of:
|
||||
- "mediatek,mt2701-imgsys", "syscon"
|
||||
- "mediatek,mt8173-imgsys", "syscon"
|
||||
- #clock-cells: Must be 1
|
||||
|
||||
|
@ -6,7 +6,8 @@ outputs to the system.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: Should be:
|
||||
- compatible: Should be one of:
|
||||
- "mediatek,mt2701-infracfg", "syscon"
|
||||
- "mediatek,mt8135-infracfg", "syscon"
|
||||
- "mediatek,mt8173-infracfg", "syscon"
|
||||
- #clock-cells: Must be 1
|
||||
|
@ -5,7 +5,8 @@ The Mediatek mmsys controller provides various clocks to the system.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: Should be:
|
||||
- compatible: Should be one of:
|
||||
- "mediatek,mt2701-mmsys", "syscon"
|
||||
- "mediatek,mt8173-mmsys", "syscon"
|
||||
- #clock-cells: Must be 1
|
||||
|
||||
|
@ -6,7 +6,8 @@ outputs to the system.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: Should be:
|
||||
- compatible: Should be one of:
|
||||
- "mediatek,mt2701-pericfg", "syscon"
|
||||
- "mediatek,mt8135-pericfg", "syscon"
|
||||
- "mediatek,mt8173-pericfg", "syscon"
|
||||
- #clock-cells: Must be 1
|
||||
|
@ -5,7 +5,8 @@ The Mediatek topckgen controller provides various clocks to the system.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: Should be:
|
||||
- compatible: Should be one of:
|
||||
- "mediatek,mt2701-topckgen"
|
||||
- "mediatek,mt8135-topckgen"
|
||||
- "mediatek,mt8173-topckgen"
|
||||
- #clock-cells: Must be 1
|
||||
|
@ -5,7 +5,8 @@ The Mediatek vdecsys controller provides various clocks to the system.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: Should be:
|
||||
- compatible: Should be one of:
|
||||
- "mediatek,mt2701-vdecsys", "syscon"
|
||||
- "mediatek,mt8173-vdecsys", "syscon"
|
||||
- #clock-cells: Must be 1
|
||||
|
||||
|
@ -0,0 +1,45 @@
|
||||
* Amlogic GXBB AO Clock and Reset Unit
|
||||
|
||||
The Amlogic GXBB AO clock controller generates and supplies clock to various
|
||||
controllers within the Always-On part of the SoC.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: should be "amlogic,gxbb-aoclkc"
|
||||
- reg: physical base address of the clock controller and length of memory
|
||||
mapped region.
|
||||
|
||||
- #clock-cells: should be 1.
|
||||
|
||||
Each clock is assigned an identifier and client nodes can use this identifier
|
||||
to specify the clock which they consume. All available clocks are defined as
|
||||
preprocessor macros in the dt-bindings/clock/gxbb-aoclkc.h header and can be
|
||||
used in device tree sources.
|
||||
|
||||
- #reset-cells: should be 1.
|
||||
|
||||
Each reset is assigned an identifier and client nodes can use this identifier
|
||||
to specify the reset which they consume. All available resets are defined as
|
||||
preprocessor macros in the dt-bindings/reset/gxbb-aoclkc.h header and can be
|
||||
used in device tree sources.
|
||||
|
||||
Example: AO Clock controller node:
|
||||
|
||||
clkc_AO: clock-controller@040 {
|
||||
compatible = "amlogic,gxbb-aoclkc";
|
||||
reg = <0x0 0x040 0x0 0x4>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
Example: UART controller node that consumes the clock and reset generated
|
||||
by the clock controller:
|
||||
|
||||
uart_AO: serial@4c0 {
|
||||
compatible = "amlogic,meson-uart";
|
||||
reg = <0x4c0 0x14>;
|
||||
interrupts = <0 90 1>;
|
||||
clocks = <&clkc_AO CLKID_AO_UART1>;
|
||||
resets = <&clkc_AO RESET_AO_UART1>;
|
||||
status = "disabled";
|
||||
};
|
@ -5,20 +5,50 @@ Technology (IDT). ARM integrated these oscillators deeply into their
|
||||
reference designs by adding special control registers that manage such
|
||||
oscillators to their system controllers.
|
||||
|
||||
The ARM system controller contains logic to serialize and initialize
|
||||
The various ARM system controllers contain logic to serialize and initialize
|
||||
an ICST clock request after a write to the 32 bit register at an offset
|
||||
into the system controller. Furthermore, to even be able to alter one of
|
||||
these frequencies, the system controller must first be unlocked by
|
||||
writing a special token to another offset in the system controller.
|
||||
|
||||
Some ARM hardware contain special versions of the serial interface that only
|
||||
connects the low 8 bits of the VDW (missing one bit), hardwires RDW to
|
||||
different values and sometimes also hardwire the output divider. They
|
||||
therefore have special compatible strings as per this table (the OD value is
|
||||
the value on the pins, not the resulting output divider):
|
||||
|
||||
Hardware variant: RDW OD VDW
|
||||
|
||||
Integrator/AP 22 1 Bit 8 0, rest variable
|
||||
integratorap-cm
|
||||
|
||||
Integrator/AP 46 3 Bit 8 0, rest variable
|
||||
integratorap-sys
|
||||
|
||||
Integrator/AP 22 or 1 17 or (33 or 25 MHz)
|
||||
integratorap-pci 14 1 14
|
||||
|
||||
Integrator/CP 22 variable Bit 8 0, rest variable
|
||||
integratorcp-cm-core
|
||||
|
||||
Integrator/CP 22 variable Bit 8 0, rest variable
|
||||
integratorcp-cm-mem
|
||||
|
||||
The ICST oscillator must be provided inside a system controller node.
|
||||
|
||||
Required properties:
|
||||
- compatible: must be one of
|
||||
"arm,syscon-icst525"
|
||||
"arm,syscon-icst307"
|
||||
"arm,syscon-icst525-integratorap-cm"
|
||||
"arm,syscon-icst525-integratorap-sys"
|
||||
"arm,syscon-icst525-integratorap-pci"
|
||||
"arm,syscon-icst525-integratorcp-cm-core"
|
||||
"arm,syscon-icst525-integratorcp-cm-mem"
|
||||
- lock-offset: the offset address into the system controller where the
|
||||
unlocking register is located
|
||||
- vco-offset: the offset address into the system controller where the
|
||||
ICST control register is located (even 32 bit address)
|
||||
- compatible: must be one of "arm,syscon-icst525" or "arm,syscon-icst307"
|
||||
- #clock-cells: must be <0>
|
||||
- clocks: parent clock, since the ICST needs a parent clock to derive its
|
||||
frequency from, this attribute is compulsory.
|
||||
|
@ -0,0 +1,70 @@
|
||||
* Peripheral Clock bindings for Marvell Armada 37xx SoCs
|
||||
|
||||
Marvell Armada 37xx SoCs provide peripheral clocks which are
|
||||
used as clock source for the peripheral of the SoC.
|
||||
|
||||
There are two different blocks associated to north bridge and south
|
||||
bridge.
|
||||
|
||||
The peripheral clock consumer should specify the desired clock by
|
||||
having the clock ID in its "clocks" phandle cell.
|
||||
|
||||
The following is a list of provided IDs for Armada 370 North bridge clocks:
|
||||
ID Clock name Description
|
||||
-----------------------------------
|
||||
0 mmc MMC controller
|
||||
1 sata_host Sata Host
|
||||
2 sec_at Security AT
|
||||
3 sac_dap Security DAP
|
||||
4 tsecm Security Engine
|
||||
5 setm_tmx Serial Embedded Trace Module
|
||||
6 avs Adaptive Voltage Scaling
|
||||
7 sqf SPI
|
||||
8 pwm PWM
|
||||
9 i2c_2 I2C 2
|
||||
10 i2c_1 I2C 1
|
||||
11 ddr_phy DDR PHY
|
||||
12 ddr_fclk DDR F clock
|
||||
13 trace Trace
|
||||
14 counter Counter
|
||||
15 eip97 EIP 97
|
||||
16 cpu CPU
|
||||
|
||||
The following is a list of provided IDs for Armada 370 South bridge clocks:
|
||||
ID Clock name Description
|
||||
-----------------------------------
|
||||
0 gbe-50 50 MHz parent clock for Gigabit Ethernet
|
||||
1 gbe-core parent clock for Gigabit Ethernet core
|
||||
2 gbe-125 125 MHz parent clock for Gigabit Ethernet
|
||||
3 gbe1-50 50 MHz clock for Gigabit Ethernet port 1
|
||||
4 gbe0-50 50 MHz clock for Gigabit Ethernet port 0
|
||||
5 gbe1-125 125 MHz clock for Gigabit Ethernet port 1
|
||||
6 gbe0-125 125 MHz clock for Gigabit Ethernet port 0
|
||||
7 gbe1-core Gigabit Ethernet core port 1
|
||||
8 gbe0-core Gigabit Ethernet core port 0
|
||||
9 gbe-bm Gigabit Ethernet Buffer Manager
|
||||
10 sdio SDIO
|
||||
11 usb32-sub2-sys USB 2 clock
|
||||
12 usb32-ss-sys USB 3 clock
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : shall be "marvell,armada-3700-periph-clock-nb" for the
|
||||
north bridge block, or
|
||||
"marvell,armada-3700-periph-clock-sb" for the south bridge block
|
||||
- reg : must be the register address of North/South Bridge Clock register
|
||||
- #clock-cells : from common clock binding; shall be set to 1
|
||||
|
||||
- clocks : list of the parent clock phandle in the following order:
|
||||
TBG-A P, TBG-B P, TBG-A S, TBG-B S and finally the xtal clock.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
nb_perih_clk: nb-periph-clk@13000{
|
||||
compatible = "marvell,armada-3700-periph-clock-nb";
|
||||
reg = <0x13000 0x1000>;
|
||||
clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>,
|
||||
<&tbg 3>, <&xtalclk>;
|
||||
#clock-cells = <1>;
|
||||
};
|
@ -0,0 +1,27 @@
|
||||
* Time Base Generator Clock bindings for Marvell Armada 37xx SoCs
|
||||
|
||||
Marvell Armada 37xx SoCs provde Time Base Generator clocks which are
|
||||
used as parent clocks for the peripheral clocks.
|
||||
|
||||
The TBG clock consumer should specify the desired clock by having the
|
||||
clock ID in its "clocks" phandle cell.
|
||||
|
||||
The following is a list of provided IDs and clock names on Armada 3700:
|
||||
0 = TBG A P
|
||||
1 = TBG B P
|
||||
2 = TBG A S
|
||||
3 = TBG B S
|
||||
|
||||
Required properties:
|
||||
- compatible : shall be "marvell,armada-3700-tbg-clock"
|
||||
- reg : must be the register address of North Bridge PLL register
|
||||
- #clock-cells : from common clock binding; shall be set to 1
|
||||
|
||||
Example:
|
||||
|
||||
tbg: tbg@13200 {
|
||||
compatible = "marvell,armada-3700-tbg-clock";
|
||||
reg = <0x13200 0x1000>;
|
||||
clocks = <&xtalclk>;
|
||||
#clock-cells = <1>;
|
||||
};
|
@ -0,0 +1,28 @@
|
||||
* Xtal Clock bindings for Marvell Armada 37xx SoCs
|
||||
|
||||
Marvell Armada 37xx SoCs allow to determine the xtal clock frequencies by
|
||||
reading the gpio latch register.
|
||||
|
||||
This node must be a subnode of the node exposing the register address
|
||||
of the GPIO block where the gpio latch is located.
|
||||
|
||||
Required properties:
|
||||
- compatible : shall be one of the following:
|
||||
"marvell,armada-3700-xtal-clock"
|
||||
- #clock-cells : from common clock binding; shall be set to 0
|
||||
|
||||
Optional properties:
|
||||
- clock-output-names : from common clock binding; allows overwrite default clock
|
||||
output names ("xtal")
|
||||
|
||||
Example:
|
||||
gpio1: gpio@13800 {
|
||||
compatible = "marvell,armada-3700-gpio", "syscon", "simple-mfd";
|
||||
reg = <0x13800 0x1000>;
|
||||
|
||||
xtalclk: xtal-clk {
|
||||
compatible = "marvell,armada-3700-xtal-clock";
|
||||
clock-output-names = "xtal";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
};
|
@ -6,7 +6,8 @@ This binding uses the common clock binding[1].
|
||||
|
||||
Required properties:
|
||||
- compatible : shall be one of the following:
|
||||
"atmel,at91sam9x5-sckc":
|
||||
"atmel,at91sam9x5-sckc" or
|
||||
"atmel,sama5d4-sckc":
|
||||
at91 SCKC (Slow Clock Controller)
|
||||
This node contains the slow clock definitions.
|
||||
|
||||
|
@ -0,0 +1,36 @@
|
||||
Broadcom BCM53573 ILP clock
|
||||
===========================
|
||||
|
||||
This binding uses the common clock binding:
|
||||
Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
This binding is used for ILP clock (sometimes referred as "slow clock")
|
||||
on Broadcom BCM53573 devices using Cortex-A7 CPU.
|
||||
|
||||
ILP's rate has to be calculated on runtime and it depends on ALP clock
|
||||
which has to be referenced.
|
||||
|
||||
This clock is part of PMU (Power Management Unit), a Broadcom's device
|
||||
handing power-related aspects. Its node must be sub-node of the PMU
|
||||
device.
|
||||
|
||||
Required properties:
|
||||
- compatible: "brcm,bcm53573-ilp"
|
||||
- clocks: has to reference an ALP clock
|
||||
- #clock-cells: should be <0>
|
||||
- clock-output-names: from common clock bindings, should contain clock
|
||||
name
|
||||
|
||||
Example:
|
||||
|
||||
pmu@18012000 {
|
||||
compatible = "simple-mfd", "syscon";
|
||||
reg = <0x18012000 0x00001000>;
|
||||
|
||||
ilp {
|
||||
compatible = "brcm,bcm53573-ilp";
|
||||
clocks = <&alp>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "ilp";
|
||||
};
|
||||
};
|
@ -10,6 +10,8 @@ Required Properties:
|
||||
- "samsung,exynos4210-audss-clock" - controller compatible with all Exynos4 SoCs.
|
||||
- "samsung,exynos5250-audss-clock" - controller compatible with Exynos5250
|
||||
SoCs.
|
||||
- "samsung,exynos5410-audss-clock" - controller compatible with Exynos5410
|
||||
SoCs.
|
||||
- "samsung,exynos5420-audss-clock" - controller compatible with Exynos5420
|
||||
SoCs.
|
||||
- reg: physical base address and length of the controller's register set.
|
||||
|
@ -12,24 +12,29 @@ Required Properties:
|
||||
|
||||
- #clock-cells: should be 1.
|
||||
|
||||
- clocks: should contain an entry specifying the root clock from external
|
||||
oscillator supplied through XXTI or XusbXTI pin. This clock should be
|
||||
defined using standard clock bindings with "fin_pll" clock-output-name.
|
||||
That clock is being passed internally to the 9 PLLs.
|
||||
|
||||
All available clocks are defined as preprocessor macros in
|
||||
dt-bindings/clock/exynos5410.h header and can be used in device
|
||||
tree sources.
|
||||
|
||||
External clock:
|
||||
|
||||
There is clock that is generated outside the SoC. It
|
||||
is expected that it is defined using standard clock bindings
|
||||
with following clock-output-name:
|
||||
|
||||
- "fin_pll" - PLL input clock from XXTI
|
||||
|
||||
Example 1: An example of a clock controller node is listed below.
|
||||
|
||||
fin_pll: xxti {
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <24000000>;
|
||||
clock-output-names = "fin_pll";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
clock: clock-controller@0x10010000 {
|
||||
compatible = "samsung,exynos5410-clock";
|
||||
reg = <0x10010000 0x30000>;
|
||||
#clock-cells = <1>;
|
||||
clocks = <&fin_pll>;
|
||||
};
|
||||
|
||||
Example 2: UART controller node that consumes the clock generated by the clock
|
||||
|
@ -1,10 +1,24 @@
|
||||
Binding for Maxim MAX77686 32k clock generator block
|
||||
Binding for Maxim MAX77686/MAX77802/MAX77620 32k clock generator block
|
||||
|
||||
This is a part of device tree bindings of MAX77686 multi-function device.
|
||||
More information can be found in bindings/mfd/max77686.txt file.
|
||||
This is a part of device tree bindings of MAX77686/MAX77802/MAX77620
|
||||
multi-function device. More information can be found in MFD DT binding
|
||||
doc as follows:
|
||||
bindings/mfd/max77686.txt for MAX77686 and
|
||||
bindings/mfd/max77802.txt for MAX77802 and
|
||||
bindings/mfd/max77620.txt for MAX77620.
|
||||
|
||||
The MAX77686 contains three 32.768khz clock outputs that can be controlled
|
||||
(gated/ungated) over I2C.
|
||||
(gated/ungated) over I2C. Clocks are defined as preprocessor macros in
|
||||
dt-bindings/clock/maxim,max77686.h.
|
||||
|
||||
|
||||
The MAX77802 contains two 32.768khz clock outputs that can be controlled
|
||||
(gated/ungated) over I2C. Clocks are defined as preprocessor macros in
|
||||
dt-bindings/clock/maxim,max77802.h.
|
||||
|
||||
The MAX77686 contains one 32.768khz clock outputs that can be controlled
|
||||
(gated/ungated) over I2C. Clocks are defined as preprocessor macros in
|
||||
dt-bindings/clock/maxim,max77620.h.
|
||||
|
||||
Following properties should be presend in main device node of the MFD chip.
|
||||
|
||||
@ -17,15 +31,21 @@ Optional properties:
|
||||
|
||||
Each clock is assigned an identifier and client nodes can use this identifier
|
||||
to specify the clock which they consume. Following indices are allowed:
|
||||
- 0: 32khz_ap clock,
|
||||
- 1: 32khz_cp clock,
|
||||
- 2: 32khz_pmic clock.
|
||||
- 0: 32khz_ap clock (max77686, max77802), 32khz_out0 (max77620)
|
||||
- 1: 32khz_cp clock (max77686, max77802),
|
||||
- 2: 32khz_pmic clock (max77686).
|
||||
|
||||
Clocks are defined as preprocessor macros in dt-bindings/clock/maxim,max77686.h
|
||||
header and can be used in device tree sources.
|
||||
Clocks are defined as preprocessor macros in above dt-binding header for
|
||||
respective chips.
|
||||
|
||||
Example: Node of the MFD chip
|
||||
Example:
|
||||
|
||||
1. With MAX77686:
|
||||
|
||||
#include <dt-bindings/clock/maxim,max77686.h>
|
||||
/* ... */
|
||||
|
||||
Node of the MFD chip
|
||||
max77686: max77686@09 {
|
||||
compatible = "maxim,max77686";
|
||||
interrupt-parent = <&wakeup_eint>;
|
||||
@ -36,7 +56,7 @@ Example: Node of the MFD chip
|
||||
/* ... */
|
||||
};
|
||||
|
||||
Example: Clock consumer node
|
||||
Clock consumer node
|
||||
|
||||
foo@0 {
|
||||
compatible = "bar,foo";
|
||||
@ -44,3 +64,51 @@ Example: Clock consumer node
|
||||
clock-names = "my-clock";
|
||||
clocks = <&max77686 MAX77686_CLK_PMIC>;
|
||||
};
|
||||
|
||||
2. With MAX77802:
|
||||
|
||||
#include <dt-bindings/clock/maxim,max77802.h>
|
||||
/* ... */
|
||||
|
||||
Node of the MFD chip
|
||||
max77802: max77802@09 {
|
||||
compatible = "maxim,max77802";
|
||||
interrupt-parent = <&wakeup_eint>;
|
||||
interrupts = <26 0>;
|
||||
reg = <0x09>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
/* ... */
|
||||
};
|
||||
|
||||
Clock consumer node
|
||||
|
||||
foo@0 {
|
||||
compatible = "bar,foo";
|
||||
/* ... */
|
||||
clock-names = "my-clock";
|
||||
clocks = <&max77802 MAX77802_CLK_32K_AP>;
|
||||
};
|
||||
|
||||
|
||||
3. With MAX77620:
|
||||
|
||||
#include <dt-bindings/clock/maxim,max77620.h>
|
||||
/* ... */
|
||||
|
||||
Node of the MFD chip
|
||||
max77620: max77620@3c {
|
||||
compatible = "maxim,max77620";
|
||||
reg = <0x3c>;
|
||||
#clock-cells = <1>;
|
||||
/* ... */
|
||||
};
|
||||
|
||||
Clock consumer node
|
||||
|
||||
foo@0 {
|
||||
compatible = "bar,foo";
|
||||
/* ... */
|
||||
clock-names = "my-clock";
|
||||
clocks = <&max77620 MAX77620_CLK_32K_OUT0>;
|
||||
};
|
||||
|
@ -1,44 +0,0 @@
|
||||
Binding for Maxim MAX77802 32k clock generator block
|
||||
|
||||
This is a part of device tree bindings of MAX77802 multi-function device.
|
||||
More information can be found in bindings/mfd/max77802.txt file.
|
||||
|
||||
The MAX77802 contains two 32.768khz clock outputs that can be controlled
|
||||
(gated/ungated) over I2C.
|
||||
|
||||
Following properties should be present in main device node of the MFD chip.
|
||||
|
||||
Required properties:
|
||||
- #clock-cells: From common clock binding; shall be set to 1.
|
||||
|
||||
Optional properties:
|
||||
- clock-output-names: From common clock binding.
|
||||
|
||||
Each clock is assigned an identifier and client nodes can use this identifier
|
||||
to specify the clock which they consume. Following indices are allowed:
|
||||
- 0: 32khz_ap clock,
|
||||
- 1: 32khz_cp clock.
|
||||
|
||||
Clocks are defined as preprocessor macros in dt-bindings/clock/maxim,max77802.h
|
||||
header and can be used in device tree sources.
|
||||
|
||||
Example: Node of the MFD chip
|
||||
|
||||
max77802: max77802@09 {
|
||||
compatible = "maxim,max77802";
|
||||
interrupt-parent = <&wakeup_eint>;
|
||||
interrupts = <26 0>;
|
||||
reg = <0x09>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
/* ... */
|
||||
};
|
||||
|
||||
Example: Clock consumer node
|
||||
|
||||
foo@0 {
|
||||
compatible = "bar,foo";
|
||||
/* ... */
|
||||
clock-names = "my-clock";
|
||||
clocks = <&max77802 MAX77802_CLK_32K_AP>;
|
||||
};
|
@ -86,6 +86,8 @@ ID Clock Peripheral
|
||||
7 pex3 PCIe 3
|
||||
8 pex0 PCIe 0
|
||||
9 usb3h0 USB3 Host 0
|
||||
10 usb3h1 USB3 Host 1
|
||||
15 sata0 SATA 0
|
||||
17 sdio SDIO
|
||||
22 xor0 XOR 0
|
||||
28 xor1 XOR 1
|
||||
|
@ -15,6 +15,7 @@ Required properties :
|
||||
"qcom,gcc-msm8974pro"
|
||||
"qcom,gcc-msm8974pro-ac"
|
||||
"qcom,gcc-msm8996"
|
||||
"qcom,gcc-mdm9615"
|
||||
|
||||
- reg : shall contain base register location and length
|
||||
- #clock-cells : shall contain 1
|
||||
|
@ -7,6 +7,7 @@ Required properties :
|
||||
"qcom,lcc-msm8960"
|
||||
"qcom,lcc-apq8064"
|
||||
"qcom,lcc-ipq8064"
|
||||
"qcom,lcc-mdm9615"
|
||||
|
||||
- reg : shall contain base register location and length
|
||||
- #clock-cells : shall contain 1
|
||||
|
@ -1,49 +0,0 @@
|
||||
Binding for a ST divider and multiplexer clock driver.
|
||||
|
||||
This binding uses the common clock binding[1].
|
||||
Base address is located to the parent node. See clock binding[2]
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
[2] Documentation/devicetree/bindings/clock/st/st,clkgen.txt
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : shall be:
|
||||
"st,clkgena-divmux-c65-hs", "st,clkgena-divmux"
|
||||
"st,clkgena-divmux-c65-ls", "st,clkgena-divmux"
|
||||
"st,clkgena-divmux-c32-odf0", "st,clkgena-divmux"
|
||||
"st,clkgena-divmux-c32-odf1", "st,clkgena-divmux"
|
||||
"st,clkgena-divmux-c32-odf2", "st,clkgena-divmux"
|
||||
"st,clkgena-divmux-c32-odf3", "st,clkgena-divmux"
|
||||
|
||||
- #clock-cells : From common clock binding; shall be set to 1.
|
||||
|
||||
- clocks : From common clock binding
|
||||
|
||||
- clock-output-names : From common clock binding.
|
||||
|
||||
Example:
|
||||
|
||||
clockgen-a@fd345000 {
|
||||
reg = <0xfd345000 0xb50>;
|
||||
|
||||
clk_m_a1_div1: clk-m-a1-div1 {
|
||||
#clock-cells = <1>;
|
||||
compatible = "st,clkgena-divmux-c32-odf1",
|
||||
"st,clkgena-divmux";
|
||||
|
||||
clocks = <&clk_m_a1_osc_prediv>,
|
||||
<&clk_m_a1_pll0 1>, /* PLL0 PHI1 */
|
||||
<&clk_m_a1_pll1 1>; /* PLL1 PHI1 */
|
||||
|
||||
clock-output-names = "clk-m-rx-icn-ts",
|
||||
"clk-m-rx-icn-vdp-0",
|
||||
"", /* unused */
|
||||
"clk-m-prv-t1-bus",
|
||||
"clk-m-icn-reg-12",
|
||||
"clk-m-icn-reg-10",
|
||||
"", /* unused */
|
||||
"clk-m-icn-st231";
|
||||
};
|
||||
};
|
||||
|
@ -10,14 +10,7 @@ This binding uses the common clock binding[1].
|
||||
Required properties:
|
||||
|
||||
- compatible : shall be:
|
||||
"st,stih416-clkgenc-vcc-hd", "st,clkgen-mux"
|
||||
"st,stih416-clkgenf-vcc-fvdp", "st,clkgen-mux"
|
||||
"st,stih416-clkgenf-vcc-hva", "st,clkgen-mux"
|
||||
"st,stih416-clkgenf-vcc-hd", "st,clkgen-mux"
|
||||
"st,stih416-clkgenf-vcc-sd", "st,clkgen-mux"
|
||||
"st,stih415-clkgen-a9-mux", "st,clkgen-mux"
|
||||
"st,stih416-clkgen-a9-mux", "st,clkgen-mux"
|
||||
"st,stih407-clkgen-a9-mux", "st,clkgen-mux"
|
||||
"st,stih407-clkgen-a9-mux"
|
||||
|
||||
- #clock-cells : from common clock binding; shall be set to 0.
|
||||
|
||||
@ -27,10 +20,13 @@ Required properties:
|
||||
|
||||
Example:
|
||||
|
||||
clk_m_hva: clk-m-hva@fd690868 {
|
||||
clk_m_a9: clk-m-a9@92b0000 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "st,stih416-clkgenf-vcc-hva", "st,clkgen-mux";
|
||||
reg = <0xfd690868 4>;
|
||||
compatible = "st,stih407-clkgen-a9-mux";
|
||||
reg = <0x92b0000 0x10000>;
|
||||
|
||||
clocks = <&clockgen_f 1>, <&clk_m_a1_div0 3>;
|
||||
clocks = <&clockgen_a9_pll 0>,
|
||||
<&clockgen_a9_pll 0>,
|
||||
<&clk_s_c0_flexgen 13>,
|
||||
<&clk_m_a9_ext2f_div2>;
|
||||
};
|
||||
|
@ -9,24 +9,10 @@ Base address is located to the parent node. See clock binding[2]
|
||||
Required properties:
|
||||
|
||||
- compatible : shall be:
|
||||
"st,clkgena-prediv-c65", "st,clkgena-prediv"
|
||||
"st,clkgena-prediv-c32", "st,clkgena-prediv"
|
||||
|
||||
"st,clkgena-plls-c65"
|
||||
"st,plls-c32-a1x-0", "st,clkgen-plls-c32"
|
||||
"st,plls-c32-a1x-1", "st,clkgen-plls-c32"
|
||||
"st,stih415-plls-c32-a9", "st,clkgen-plls-c32"
|
||||
"st,stih415-plls-c32-ddr", "st,clkgen-plls-c32"
|
||||
"st,stih416-plls-c32-a9", "st,clkgen-plls-c32"
|
||||
"st,stih416-plls-c32-ddr", "st,clkgen-plls-c32"
|
||||
"st,stih407-plls-c32-a0", "st,clkgen-plls-c32"
|
||||
"st,stih407-plls-c32-a9", "st,clkgen-plls-c32"
|
||||
"sst,plls-c32-cx_0", "st,clkgen-plls-c32"
|
||||
"sst,plls-c32-cx_1", "st,clkgen-plls-c32"
|
||||
"st,stih418-plls-c28-a9", "st,clkgen-plls-c32"
|
||||
|
||||
"st,stih415-gpu-pll-c32", "st,clkgengpu-pll-c32"
|
||||
"st,stih416-gpu-pll-c32", "st,clkgengpu-pll-c32"
|
||||
"st,clkgen-pll0"
|
||||
"st,clkgen-pll1"
|
||||
"st,stih407-clkgen-plla9"
|
||||
"st,stih418-clkgen-plla9"
|
||||
|
||||
- #clock-cells : From common clock binding; shall be set to 1.
|
||||
|
||||
@ -36,17 +22,16 @@ Required properties:
|
||||
|
||||
Example:
|
||||
|
||||
clockgen-a@fee62000 {
|
||||
reg = <0xfee62000 0xb48>;
|
||||
clockgen-a9@92b0000 {
|
||||
compatible = "st,clkgen-c32";
|
||||
reg = <0x92b0000 0xffff>;
|
||||
|
||||
clk_s_a0_pll: clk-s-a0-pll {
|
||||
clockgen_a9_pll: clockgen-a9-pll {
|
||||
#clock-cells = <1>;
|
||||
compatible = "st,clkgena-plls-c65";
|
||||
compatible = "st,stih407-clkgen-plla9";
|
||||
|
||||
clocks = <&clk_sysin>;
|
||||
|
||||
clock-output-names = "clk-s-a0-pll0-hs",
|
||||
"clk-s-a0-pll0-ls",
|
||||
"clk-s-a0-pll1";
|
||||
clock-output-names = "clockgen-a9-pll-odf";
|
||||
};
|
||||
};
|
||||
|
@ -1,36 +0,0 @@
|
||||
Binding for a ST pre-divider clock driver.
|
||||
|
||||
This binding uses the common clock binding[1].
|
||||
Base address is located to the parent node. See clock binding[2]
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
[2] Documentation/devicetree/bindings/clock/st/st,clkgen.txt
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : shall be:
|
||||
"st,clkgena-prediv-c65", "st,clkgena-prediv"
|
||||
"st,clkgena-prediv-c32", "st,clkgena-prediv"
|
||||
|
||||
- #clock-cells : From common clock binding; shall be set to 0.
|
||||
|
||||
- clocks : From common clock binding
|
||||
|
||||
- clock-output-names : From common clock binding.
|
||||
|
||||
Example:
|
||||
|
||||
clockgen-a@fd345000 {
|
||||
reg = <0xfd345000 0xb50>;
|
||||
|
||||
clk_m_a2_osc_prediv: clk-m-a2-osc-prediv {
|
||||
#clock-cells = <0>;
|
||||
compatible = "st,clkgena-prediv-c32",
|
||||
"st,clkgena-prediv";
|
||||
|
||||
clocks = <&clk_sysin>;
|
||||
|
||||
clock-output-names = "clk-m-a2-osc-prediv";
|
||||
};
|
||||
};
|
||||
|
@ -1,61 +0,0 @@
|
||||
Binding for a type of STMicroelectronics clock crossbar (VCC).
|
||||
|
||||
The crossbar can take up to 4 input clocks and control up to 16
|
||||
output clocks. Not all inputs or outputs have to be in use in a
|
||||
particular instantiation. Each output can be individually enabled,
|
||||
select any of the input clocks and apply a divide (by 1,2,4 or 8) to
|
||||
that selected clock.
|
||||
|
||||
This binding uses the common clock binding[1].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : shall be:
|
||||
"st,stih416-clkgenc", "st,vcc"
|
||||
"st,stih416-clkgenf", "st,vcc"
|
||||
|
||||
- #clock-cells : from common clock binding; shall be set to 1.
|
||||
|
||||
- reg : A Base address and length of the register set.
|
||||
|
||||
- clocks : from common clock binding
|
||||
|
||||
- clock-output-names : From common clock binding. The block has 16
|
||||
clock outputs but not all of them in a specific instance
|
||||
have to be used in the SoC. If a clock name is left as
|
||||
an empty string then no clock will be created for the
|
||||
output associated with that string index. If fewer than
|
||||
16 strings are provided then no clocks will be created
|
||||
for the remaining outputs.
|
||||
|
||||
Example:
|
||||
|
||||
clockgen_c_vcc: clockgen-c-vcc@0xfe8308ac {
|
||||
#clock-cells = <1>;
|
||||
compatible = "st,stih416-clkgenc", "st,clkgen-vcc";
|
||||
reg = <0xfe8308ac 12>;
|
||||
|
||||
clocks = <&clk_s_vcc_hd>,
|
||||
<&clockgen_c 1>,
|
||||
<&clk_s_tmds_fromphy>,
|
||||
<&clockgen_c 2>;
|
||||
|
||||
clock-output-names = "clk-s-pix-hdmi",
|
||||
"clk-s-pix-dvo",
|
||||
"clk-s-out-dvo",
|
||||
"clk-s-pix-hd",
|
||||
"clk-s-hddac",
|
||||
"clk-s-denc",
|
||||
"clk-s-sddac",
|
||||
"clk-s-pix-main",
|
||||
"clk-s-pix-aux",
|
||||
"clk-s-stfe-frc-0",
|
||||
"clk-s-ref-mcru",
|
||||
"clk-s-slave-mcru",
|
||||
"clk-s-tmds-hdmi",
|
||||
"clk-s-hdmi-reject-pll",
|
||||
"clk-s-thsens";
|
||||
};
|
||||
|
@ -13,14 +13,6 @@ address is common of all subnode.
|
||||
...
|
||||
};
|
||||
|
||||
prediv_node {
|
||||
...
|
||||
};
|
||||
|
||||
divmux_node {
|
||||
...
|
||||
};
|
||||
|
||||
quadfs_node {
|
||||
...
|
||||
};
|
||||
@ -29,10 +21,6 @@ address is common of all subnode.
|
||||
...
|
||||
};
|
||||
|
||||
vcc_node {
|
||||
...
|
||||
};
|
||||
|
||||
flexgen_node {
|
||||
...
|
||||
};
|
||||
@ -43,11 +31,8 @@ This binding uses the common clock binding[1].
|
||||
Each subnode should use the binding described in [2]..[7]
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
[2] Documentation/devicetree/bindings/clock/st,clkgen-divmux.txt
|
||||
[3] Documentation/devicetree/bindings/clock/st,clkgen-mux.txt
|
||||
[4] Documentation/devicetree/bindings/clock/st,clkgen-pll.txt
|
||||
[5] Documentation/devicetree/bindings/clock/st,clkgen-prediv.txt
|
||||
[6] Documentation/devicetree/bindings/clock/st,vcc.txt
|
||||
[7] Documentation/devicetree/bindings/clock/st,quadfs.txt
|
||||
[8] Documentation/devicetree/bindings/clock/st,flexgen.txt
|
||||
|
||||
@ -57,44 +42,27 @@ Required properties:
|
||||
|
||||
Example:
|
||||
|
||||
clockgen-a@fee62000 {
|
||||
|
||||
reg = <0xfee62000 0xb48>;
|
||||
clockgen-a@090ff000 {
|
||||
compatible = "st,clkgen-c32";
|
||||
reg = <0x90ff000 0x1000>;
|
||||
|
||||
clk_s_a0_pll: clk-s-a0-pll {
|
||||
#clock-cells = <1>;
|
||||
compatible = "st,clkgena-plls-c65";
|
||||
|
||||
clocks = <&clk-sysin>;
|
||||
|
||||
clock-output-names = "clk-s-a0-pll0-hs",
|
||||
"clk-s-a0-pll0-ls",
|
||||
"clk-s-a0-pll1";
|
||||
};
|
||||
|
||||
clk_s_a0_osc_prediv: clk-s-a0-osc-prediv {
|
||||
#clock-cells = <0>;
|
||||
compatible = "st,clkgena-prediv-c65",
|
||||
"st,clkgena-prediv";
|
||||
compatible = "st,clkgen-pll0";
|
||||
|
||||
clocks = <&clk_sysin>;
|
||||
|
||||
clock-output-names = "clk-s-a0-osc-prediv";
|
||||
clock-output-names = "clk-s-a0-pll-ofd-0";
|
||||
};
|
||||
|
||||
clk_s_a0_hs: clk-s-a0-hs {
|
||||
clk_s_a0_flexgen: clk-s-a0-flexgen {
|
||||
compatible = "st,flexgen";
|
||||
|
||||
#clock-cells = <1>;
|
||||
compatible = "st,clkgena-divmux-c65-hs",
|
||||
"st,clkgena-divmux";
|
||||
|
||||
clocks = <&clk-s_a0_osc_prediv>,
|
||||
<&clk-s_a0_pll 0>, /* pll0 hs */
|
||||
<&clk-s_a0_pll 2>; /* pll1 */
|
||||
clocks = <&clk_s_a0_pll 0>,
|
||||
<&clk_sysin>;
|
||||
|
||||
clock-output-names = "clk-s-fdma-0",
|
||||
"clk-s-fdma-1",
|
||||
""; /* clk-s-jit-sense */
|
||||
/* fourth output unused */
|
||||
clock-output-names = "clk-ic-lmi0";
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -60,6 +60,10 @@ This binding uses the common clock binding[2].
|
||||
Required properties:
|
||||
- compatible : shall be:
|
||||
"st,flexgen"
|
||||
"st,flexgen-audio", "st,flexgen" (enable clock propagation on parent for
|
||||
audio use case)
|
||||
"st,flexgen-video", "st,flexgen" (enable clock propagation on parent
|
||||
and activate synchronous mode)
|
||||
|
||||
- #clock-cells : from common clock binding; shall be set to 1 (multiple clock
|
||||
outputs).
|
||||
|
@ -11,12 +11,8 @@ This binding uses the common clock binding[1].
|
||||
|
||||
Required properties:
|
||||
- compatible : shall be:
|
||||
"st,stih416-quadfs216", "st,quadfs"
|
||||
"st,stih416-quadfs432", "st,quadfs"
|
||||
"st,stih416-quadfs660-E", "st,quadfs"
|
||||
"st,stih416-quadfs660-F", "st,quadfs"
|
||||
"st,stih407-quadfs660-C", "st,quadfs"
|
||||
"st,stih407-quadfs660-D", "st,quadfs"
|
||||
"st,quadfs"
|
||||
"st,quadfs-pll"
|
||||
|
||||
|
||||
- #clock-cells : from common clock binding; shall be set to 1.
|
||||
@ -35,14 +31,15 @@ Required properties:
|
||||
|
||||
Example:
|
||||
|
||||
clockgen_e: clockgen-e@fd3208bc {
|
||||
clk_s_c0_quadfs: clk-s-c0-quadfs@9103000 {
|
||||
#clock-cells = <1>;
|
||||
compatible = "st,stih416-quadfs660-E", "st,quadfs";
|
||||
reg = <0xfd3208bc 0xB0>;
|
||||
compatible = "st,quadfs-pll";
|
||||
reg = <0x9103000 0x1000>;
|
||||
|
||||
clocks = <&clk_sysin>;
|
||||
clock-output-names = "clk-m-pix-mdtp-0",
|
||||
"clk-m-pix-mdtp-1",
|
||||
"clk-m-pix-mdtp-2",
|
||||
"clk-m-mpelpc";
|
||||
|
||||
clock-output-names = "clk-s-c0-fs0-ch0",
|
||||
"clk-s-c0-fs0-ch1",
|
||||
"clk-s-c0-fs0-ch2",
|
||||
"clk-s-c0-fs0-ch3";
|
||||
};
|
||||
|
@ -2,7 +2,10 @@ Allwinner Clock Control Unit Binding
|
||||
------------------------------------
|
||||
|
||||
Required properties :
|
||||
- compatible: must contain one of the following compatible:
|
||||
- compatible: must contain one of the following compatibles:
|
||||
- "allwinner,sun6i-a31-ccu"
|
||||
- "allwinner,sun8i-a23-ccu"
|
||||
- "allwinner,sun8i-a33-ccu"
|
||||
- "allwinner,sun8i-h3-ccu"
|
||||
|
||||
- reg: Must contain the registers base address and length
|
||||
|
134
Documentation/devicetree/bindings/clock/uniphier-clock.txt
Normal file
134
Documentation/devicetree/bindings/clock/uniphier-clock.txt
Normal file
@ -0,0 +1,134 @@
|
||||
UniPhier clock controller
|
||||
|
||||
|
||||
System clock
|
||||
------------
|
||||
|
||||
Required properties:
|
||||
- compatible: should be one of the following:
|
||||
"socionext,uniphier-sld3-clock" - for sLD3 SoC.
|
||||
"socionext,uniphier-ld4-clock" - for LD4 SoC.
|
||||
"socionext,uniphier-pro4-clock" - for Pro4 SoC.
|
||||
"socionext,uniphier-sld8-clock" - for sLD8 SoC.
|
||||
"socionext,uniphier-pro5-clock" - for Pro5 SoC.
|
||||
"socionext,uniphier-pxs2-clock" - for PXs2/LD6b SoC.
|
||||
"socionext,uniphier-ld11-clock" - for LD11 SoC.
|
||||
"socionext,uniphier-ld20-clock" - for LD20 SoC.
|
||||
- #clock-cells: should be 1.
|
||||
|
||||
Example:
|
||||
|
||||
sysctrl@61840000 {
|
||||
compatible = "socionext,uniphier-sysctrl",
|
||||
"simple-mfd", "syscon";
|
||||
reg = <0x61840000 0x4000>;
|
||||
|
||||
clock {
|
||||
compatible = "socionext,uniphier-ld20-clock";
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
other nodes ...
|
||||
};
|
||||
|
||||
Provided clocks:
|
||||
|
||||
8: ST DMAC
|
||||
12: GIO (Giga bit stream I/O)
|
||||
14: USB3 ch0 host
|
||||
15: USB3 ch1 host
|
||||
16: USB3 ch0 PHY0
|
||||
17: USB3 ch0 PHY1
|
||||
20: USB3 ch1 PHY0
|
||||
21: USB3 ch1 PHY1
|
||||
|
||||
|
||||
Media I/O (MIO) clock
|
||||
---------------------
|
||||
|
||||
Required properties:
|
||||
- compatible: should be one of the following:
|
||||
"socionext,uniphier-sld3-mio-clock" - for sLD3 SoC.
|
||||
"socionext,uniphier-ld4-mio-clock" - for LD4 SoC.
|
||||
"socionext,uniphier-pro4-mio-clock" - for Pro4 SoC.
|
||||
"socionext,uniphier-sld8-mio-clock" - for sLD8 SoC.
|
||||
"socionext,uniphier-pro5-mio-clock" - for Pro5 SoC.
|
||||
"socionext,uniphier-pxs2-mio-clock" - for PXs2/LD6b SoC.
|
||||
"socionext,uniphier-ld11-mio-clock" - for LD11 SoC.
|
||||
"socionext,uniphier-ld20-mio-clock" - for LD20 SoC.
|
||||
- #clock-cells: should be 1.
|
||||
|
||||
Example:
|
||||
|
||||
mioctrl@59810000 {
|
||||
compatible = "socionext,uniphier-mioctrl",
|
||||
"simple-mfd", "syscon";
|
||||
reg = <0x59810000 0x800>;
|
||||
|
||||
clock {
|
||||
compatible = "socionext,uniphier-ld20-mio-clock";
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
other nodes ...
|
||||
};
|
||||
|
||||
Provided clocks:
|
||||
|
||||
0: SD ch0 host
|
||||
1: eMMC host
|
||||
2: SD ch1 host
|
||||
7: MIO DMAC
|
||||
8: USB2 ch0 host
|
||||
9: USB2 ch1 host
|
||||
10: USB2 ch2 host
|
||||
11: USB2 ch3 host
|
||||
12: USB2 ch0 PHY
|
||||
13: USB2 ch1 PHY
|
||||
14: USB2 ch2 PHY
|
||||
15: USB2 ch3 PHY
|
||||
|
||||
|
||||
Peripheral clock
|
||||
----------------
|
||||
|
||||
Required properties:
|
||||
- compatible: should be one of the following:
|
||||
"socionext,uniphier-sld3-peri-clock" - for sLD3 SoC.
|
||||
"socionext,uniphier-ld4-peri-clock" - for LD4 SoC.
|
||||
"socionext,uniphier-pro4-peri-clock" - for Pro4 SoC.
|
||||
"socionext,uniphier-sld8-peri-clock" - for sLD8 SoC.
|
||||
"socionext,uniphier-pro5-peri-clock" - for Pro5 SoC.
|
||||
"socionext,uniphier-pxs2-peri-clock" - for PXs2/LD6b SoC.
|
||||
"socionext,uniphier-ld11-peri-clock" - for LD11 SoC.
|
||||
"socionext,uniphier-ld20-peri-clock" - for LD20 SoC.
|
||||
- #clock-cells: should be 1.
|
||||
|
||||
Example:
|
||||
|
||||
perictrl@59820000 {
|
||||
compatible = "socionext,uniphier-perictrl",
|
||||
"simple-mfd", "syscon";
|
||||
reg = <0x59820000 0x200>;
|
||||
|
||||
clock {
|
||||
compatible = "socionext,uniphier-ld20-peri-clock";
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
other nodes ...
|
||||
};
|
||||
|
||||
Provided clocks:
|
||||
|
||||
0: UART ch0
|
||||
1: UART ch1
|
||||
2: UART ch2
|
||||
3: UART ch3
|
||||
4: I2C ch0
|
||||
5: I2C ch1
|
||||
6: I2C ch2
|
||||
7: I2C ch3
|
||||
8: I2C ch4
|
||||
9: I2C ch5
|
||||
10: I2C ch6
|
@ -8,6 +8,7 @@ Required properties:
|
||||
- compatible : shall be one of the following:
|
||||
"apm,xgene-socpll-clock" - for a X-Gene SoC PLL clock
|
||||
"apm,xgene-pcppll-clock" - for a X-Gene PCP PLL clock
|
||||
"apm,xgene-pmd-clock" - for a X-Gene PMD clock
|
||||
"apm,xgene-device-clock" - for a X-Gene device clock
|
||||
"apm,xgene-socpll-v2-clock" - for a X-Gene SoC PLL v2 clock
|
||||
"apm,xgene-pcppll-v2-clock" - for a X-Gene PCP PLL v2 clock
|
||||
@ -22,6 +23,15 @@ Required properties for SoC or PCP PLL clocks:
|
||||
Optional properties for PLL clocks:
|
||||
- clock-names : shall be the name of the PLL. If missing, use the device name.
|
||||
|
||||
Required properties for PMD clocks:
|
||||
- reg : shall be the physical register address for the pmd clock.
|
||||
- clocks : shall be the input parent clock phandle for the clock.
|
||||
- #clock-cells : shall be set to 1.
|
||||
- clock-output-names : shall be the name of the clock referenced by derive
|
||||
clock.
|
||||
Optional properties for PLL clocks:
|
||||
- clock-names : shall be the name of the clock. If missing, use the device name.
|
||||
|
||||
Required properties for device clocks:
|
||||
- reg : shall be a list of address and length pairs describing the CSR
|
||||
reset and/or the divider. Either may be omitted, but at least
|
||||
@ -59,6 +69,14 @@ For example:
|
||||
type = <0>;
|
||||
};
|
||||
|
||||
pmd0clk: pmd0clk@7e200200 {
|
||||
compatible = "apm,xgene-pmd-clock";
|
||||
#clock-cells = <1>;
|
||||
clocks = <&pmdpll 0>;
|
||||
reg = <0x0 0x7e200200 0x0 0x10>;
|
||||
clock-output-names = "pmd0clk";
|
||||
};
|
||||
|
||||
socpll: socpll@17000120 {
|
||||
compatible = "apm,xgene-socpll-clock";
|
||||
#clock-cells = <1>;
|
||||
|
35
Documentation/devicetree/bindings/clock/zx296718-clk.txt
Normal file
35
Documentation/devicetree/bindings/clock/zx296718-clk.txt
Normal file
@ -0,0 +1,35 @@
|
||||
Device Tree Clock bindings for ZTE zx296718
|
||||
|
||||
This binding uses the common clock binding[1].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
Required properties:
|
||||
- compatible : shall be one of the following:
|
||||
"zte,zx296718-topcrm":
|
||||
zx296718 top clock selection, divider and gating
|
||||
|
||||
"zte,zx296718-lsp0crm" and
|
||||
"zte,zx296718-lsp1crm":
|
||||
zx296718 device level clock selection and gating
|
||||
|
||||
- reg: Address and length of the register set
|
||||
|
||||
The clock consumer should specify the desired clock by having the clock
|
||||
ID in its "clocks" phandle cell. See include/dt-bindings/clock/zx296718-clock.h
|
||||
for the full list of zx296718 clock IDs.
|
||||
|
||||
|
||||
topclk: topcrm@1461000 {
|
||||
compatible = "zte,zx296718-topcrm-clk";
|
||||
reg = <0x01461000 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
usbphy0:usb-phy0 {
|
||||
compatible = "zte,zx296718-usb-phy";
|
||||
#phy-cells = <0>;
|
||||
clocks = <&topclk USB20_PHY_CLK>;
|
||||
clock-names = "phyclk";
|
||||
status = "okay";
|
||||
};
|
11
MAINTAINERS
11
MAINTAINERS
@ -1847,6 +1847,7 @@ F: arch/arm/mach-uniphier/
|
||||
F: arch/arm/mm/cache-uniphier.c
|
||||
F: arch/arm64/boot/dts/socionext/
|
||||
F: drivers/bus/uniphier-system-bus.c
|
||||
F: drivers/clk/uniphier/
|
||||
F: drivers/i2c/busses/i2c-uniphier*
|
||||
F: drivers/pinctrl/uniphier/
|
||||
F: drivers/tty/serial/8250/8250_uniphier.c
|
||||
@ -3164,6 +3165,7 @@ COMMON CLK FRAMEWORK
|
||||
M: Michael Turquette <mturquette@baylibre.com>
|
||||
M: Stephen Boyd <sboyd@codeaurora.org>
|
||||
L: linux-clk@vger.kernel.org
|
||||
Q: http://patchwork.kernel.org/project/linux-clk/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/clock/
|
||||
@ -9950,6 +9952,12 @@ F: drivers/rpmsg/
|
||||
F: Documentation/rpmsg.txt
|
||||
F: include/linux/rpmsg.h
|
||||
|
||||
RENESAS CLOCK DRIVERS
|
||||
M: Geert Uytterhoeven <geert+renesas@glider.be>
|
||||
L: linux-renesas-soc@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/clk/renesas/
|
||||
|
||||
RENESAS ETHERNET DRIVERS
|
||||
R: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
|
||||
L: netdev@vger.kernel.org
|
||||
@ -10293,9 +10301,12 @@ F: drivers/nfc/s3fwrn5
|
||||
SAMSUNG SOC CLOCK DRIVERS
|
||||
M: Sylwester Nawrocki <s.nawrocki@samsung.com>
|
||||
M: Tomasz Figa <tomasz.figa@gmail.com>
|
||||
M: Chanwoo Choi <cw00.choi@samsung.com>
|
||||
S: Supported
|
||||
L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
|
||||
F: drivers/clk/samsung/
|
||||
F: include/dt-bindings/clock/exynos*.h
|
||||
F: Documentation/devicetree/bindings/clock/exynos*.txt
|
||||
|
||||
SAMSUNG SPI DRIVERS
|
||||
M: Kukjin Kim <kgene@kernel.org>
|
||||
|
@ -15,7 +15,6 @@ config ARCH_BCM_IPROC
|
||||
select HAVE_ARM_SCU if SMP
|
||||
select HAVE_ARM_TWD if SMP
|
||||
select ARM_GLOBAL_TIMER
|
||||
select COMMON_CLK_IPROC
|
||||
select CLKSRC_MMIO
|
||||
select GPIOLIB
|
||||
select ARM_AMBA
|
||||
|
@ -31,22 +31,12 @@ config COMMON_CLK_WM831X
|
||||
|
||||
source "drivers/clk/versatile/Kconfig"
|
||||
|
||||
config COMMON_CLK_MAX_GEN
|
||||
bool
|
||||
|
||||
config COMMON_CLK_MAX77686
|
||||
tristate "Clock driver for Maxim 77686 MFD"
|
||||
depends on MFD_MAX77686
|
||||
select COMMON_CLK_MAX_GEN
|
||||
tristate "Clock driver for Maxim 77620/77686/77802 MFD"
|
||||
depends on MFD_MAX77686 || MFD_MAX77620
|
||||
---help---
|
||||
This driver supports Maxim 77686 crystal oscillator clock.
|
||||
|
||||
config COMMON_CLK_MAX77802
|
||||
tristate "Clock driver for Maxim 77802 PMIC"
|
||||
depends on MFD_MAX77686
|
||||
select COMMON_CLK_MAX_GEN
|
||||
---help---
|
||||
This driver supports Maxim 77802 crystal oscillator clock.
|
||||
This driver supports Maxim 77620/77686/77802 crystal oscillator
|
||||
clock.
|
||||
|
||||
config COMMON_CLK_RK808
|
||||
tristate "Clock driver for RK808/RK818"
|
||||
@ -210,6 +200,7 @@ config COMMON_CLK_OXNAS
|
||||
|
||||
source "drivers/clk/bcm/Kconfig"
|
||||
source "drivers/clk/hisilicon/Kconfig"
|
||||
source "drivers/clk/mediatek/Kconfig"
|
||||
source "drivers/clk/meson/Kconfig"
|
||||
source "drivers/clk/mvebu/Kconfig"
|
||||
source "drivers/clk/qcom/Kconfig"
|
||||
@ -218,5 +209,6 @@ source "drivers/clk/samsung/Kconfig"
|
||||
source "drivers/clk/sunxi-ng/Kconfig"
|
||||
source "drivers/clk/tegra/Kconfig"
|
||||
source "drivers/clk/ti/Kconfig"
|
||||
source "drivers/clk/uniphier/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
@ -26,10 +26,7 @@ obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
|
||||
obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
|
||||
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
|
||||
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
|
||||
obj-$(CONFIG_MACH_LOONGSON32) += clk-ls1x.o
|
||||
obj-$(CONFIG_COMMON_CLK_MAX_GEN) += clk-max-gen.o
|
||||
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
|
||||
obj-$(CONFIG_COMMON_CLK_MAX77802) += clk-max77802.o
|
||||
obj-$(CONFIG_ARCH_MB86S7X) += clk-mb86s7x.o
|
||||
obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o
|
||||
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
|
||||
@ -63,6 +60,7 @@ obj-$(CONFIG_ARCH_HISI) += hisilicon/
|
||||
obj-$(CONFIG_ARCH_MXC) += imx/
|
||||
obj-$(CONFIG_MACH_INGENIC) += ingenic/
|
||||
obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
|
||||
obj-$(CONFIG_MACH_LOONGSON32) += loongson1/
|
||||
obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
|
||||
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += meson/
|
||||
obj-$(CONFIG_MACH_PIC32) += microchip/
|
||||
@ -86,6 +84,7 @@ obj-$(CONFIG_ARCH_SUNXI) += sunxi/
|
||||
obj-$(CONFIG_ARCH_SUNXI) += sunxi-ng/
|
||||
obj-$(CONFIG_ARCH_TEGRA) += tegra/
|
||||
obj-y += ti/
|
||||
obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
|
||||
obj-$(CONFIG_ARCH_U8500) += ux500/
|
||||
obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/
|
||||
obj-$(CONFIG_X86) += x86/
|
||||
|
@ -233,14 +233,16 @@ static void clk_generated_startup(struct clk_generated *gck)
|
||||
>> AT91_PMC_PCR_GCKDIV_OFFSET;
|
||||
}
|
||||
|
||||
static struct clk * __init
|
||||
at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, const char
|
||||
*name, const char **parent_names, u8 num_parents,
|
||||
u8 id, const struct clk_range *range)
|
||||
static struct clk_hw * __init
|
||||
at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
|
||||
const char *name, const char **parent_names,
|
||||
u8 num_parents, u8 id,
|
||||
const struct clk_range *range)
|
||||
{
|
||||
struct clk_generated *gck;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
struct clk_hw *hw;
|
||||
int ret;
|
||||
|
||||
gck = kzalloc(sizeof(*gck), GFP_KERNEL);
|
||||
if (!gck)
|
||||
@ -258,13 +260,15 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, const char
|
||||
gck->lock = lock;
|
||||
gck->range = *range;
|
||||
|
||||
clk = clk_register(NULL, &gck->hw);
|
||||
if (IS_ERR(clk))
|
||||
hw = &gck->hw;
|
||||
ret = clk_hw_register(NULL, &gck->hw);
|
||||
if (ret) {
|
||||
kfree(gck);
|
||||
else
|
||||
hw = ERR_PTR(ret);
|
||||
} else
|
||||
clk_generated_startup(gck);
|
||||
|
||||
return clk;
|
||||
return hw;
|
||||
}
|
||||
|
||||
static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
|
||||
@ -272,7 +276,7 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
|
||||
int num;
|
||||
u32 id;
|
||||
const char *name;
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
unsigned int num_parents;
|
||||
const char *parent_names[GENERATED_SOURCE_MAX];
|
||||
struct device_node *gcknp;
|
||||
@ -306,13 +310,13 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
|
||||
of_at91_get_clk_range(gcknp, "atmel,clk-output-range",
|
||||
&range);
|
||||
|
||||
clk = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,
|
||||
hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,
|
||||
parent_names, num_parents,
|
||||
id, &range);
|
||||
if (IS_ERR(clk))
|
||||
if (IS_ERR(hw))
|
||||
continue;
|
||||
|
||||
of_clk_add_provider(gcknp, of_clk_src_simple_get, clk);
|
||||
of_clk_add_hw_provider(gcknp, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
}
|
||||
CLK_OF_DECLARE(of_sama5d2_clk_generated_setup, "atmel,sama5d2-clk-generated",
|
||||
|
@ -92,7 +92,7 @@ static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np)
|
||||
struct clk_init_data init;
|
||||
const char *parent_name;
|
||||
struct regmap *regmap;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
regmap = syscon_node_to_regmap(of_get_parent(np));
|
||||
if (IS_ERR(regmap))
|
||||
@ -113,13 +113,13 @@ static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np)
|
||||
h32mxclk->hw.init = &init;
|
||||
h32mxclk->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &h32mxclk->hw);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = clk_hw_register(NULL, &h32mxclk->hw);
|
||||
if (ret) {
|
||||
kfree(h32mxclk);
|
||||
return;
|
||||
}
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
of_clk_add_hw_provider(np, of_clk_hw_simple_get, &h32mxclk->hw);
|
||||
}
|
||||
CLK_OF_DECLARE(of_sama5d4_clk_h32mx_setup, "atmel,sama5d4-clk-h32mx",
|
||||
of_sama5d4_clk_h32mx_setup);
|
||||
|
@ -128,15 +128,16 @@ static const struct clk_ops main_osc_ops = {
|
||||
.is_prepared = clk_main_osc_is_prepared,
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
static struct clk_hw * __init
|
||||
at91_clk_register_main_osc(struct regmap *regmap,
|
||||
const char *name,
|
||||
const char *parent_name,
|
||||
bool bypass)
|
||||
{
|
||||
struct clk_main_osc *osc;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
struct clk_hw *hw;
|
||||
int ret;
|
||||
|
||||
if (!name || !parent_name)
|
||||
return ERR_PTR(-EINVAL);
|
||||
@ -160,16 +161,19 @@ at91_clk_register_main_osc(struct regmap *regmap,
|
||||
AT91_PMC_MOSCEN,
|
||||
AT91_PMC_OSCBYPASS | AT91_PMC_KEY);
|
||||
|
||||
clk = clk_register(NULL, &osc->hw);
|
||||
if (IS_ERR(clk))
|
||||
hw = &osc->hw;
|
||||
ret = clk_hw_register(NULL, &osc->hw);
|
||||
if (ret) {
|
||||
kfree(osc);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return clk;
|
||||
return hw;
|
||||
}
|
||||
|
||||
static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
const char *name = np->name;
|
||||
const char *parent_name;
|
||||
struct regmap *regmap;
|
||||
@ -183,11 +187,11 @@ static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np)
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
clk = at91_clk_register_main_osc(regmap, name, parent_name, bypass);
|
||||
if (IS_ERR(clk))
|
||||
hw = at91_clk_register_main_osc(regmap, name, parent_name, bypass);
|
||||
if (IS_ERR(hw))
|
||||
return;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
CLK_OF_DECLARE(at91rm9200_clk_main_osc, "atmel,at91rm9200-clk-main-osc",
|
||||
of_at91rm9200_clk_main_osc_setup);
|
||||
@ -271,14 +275,15 @@ static const struct clk_ops main_rc_osc_ops = {
|
||||
.recalc_accuracy = clk_main_rc_osc_recalc_accuracy,
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
static struct clk_hw * __init
|
||||
at91_clk_register_main_rc_osc(struct regmap *regmap,
|
||||
const char *name,
|
||||
u32 frequency, u32 accuracy)
|
||||
{
|
||||
struct clk_main_rc_osc *osc;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
struct clk_hw *hw;
|
||||
int ret;
|
||||
|
||||
if (!name || !frequency)
|
||||
return ERR_PTR(-EINVAL);
|
||||
@ -298,16 +303,19 @@ at91_clk_register_main_rc_osc(struct regmap *regmap,
|
||||
osc->frequency = frequency;
|
||||
osc->accuracy = accuracy;
|
||||
|
||||
clk = clk_register(NULL, &osc->hw);
|
||||
if (IS_ERR(clk))
|
||||
hw = &osc->hw;
|
||||
ret = clk_hw_register(NULL, hw);
|
||||
if (ret) {
|
||||
kfree(osc);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return clk;
|
||||
return hw;
|
||||
}
|
||||
|
||||
static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
u32 frequency = 0;
|
||||
u32 accuracy = 0;
|
||||
const char *name = np->name;
|
||||
@ -321,11 +329,11 @@ static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np)
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
clk = at91_clk_register_main_rc_osc(regmap, name, frequency, accuracy);
|
||||
if (IS_ERR(clk))
|
||||
hw = at91_clk_register_main_rc_osc(regmap, name, frequency, accuracy);
|
||||
if (IS_ERR(hw))
|
||||
return;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
CLK_OF_DECLARE(at91sam9x5_clk_main_rc_osc, "atmel,at91sam9x5-clk-main-rc-osc",
|
||||
of_at91sam9x5_clk_main_rc_osc_setup);
|
||||
@ -395,14 +403,15 @@ static const struct clk_ops rm9200_main_ops = {
|
||||
.recalc_rate = clk_rm9200_main_recalc_rate,
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
static struct clk_hw * __init
|
||||
at91_clk_register_rm9200_main(struct regmap *regmap,
|
||||
const char *name,
|
||||
const char *parent_name)
|
||||
{
|
||||
struct clk_rm9200_main *clkmain;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
struct clk_hw *hw;
|
||||
int ret;
|
||||
|
||||
if (!name)
|
||||
return ERR_PTR(-EINVAL);
|
||||
@ -423,16 +432,19 @@ at91_clk_register_rm9200_main(struct regmap *regmap,
|
||||
clkmain->hw.init = &init;
|
||||
clkmain->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &clkmain->hw);
|
||||
if (IS_ERR(clk))
|
||||
hw = &clkmain->hw;
|
||||
ret = clk_hw_register(NULL, &clkmain->hw);
|
||||
if (ret) {
|
||||
kfree(clkmain);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return clk;
|
||||
return hw;
|
||||
}
|
||||
|
||||
static void __init of_at91rm9200_clk_main_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
const char *parent_name;
|
||||
const char *name = np->name;
|
||||
struct regmap *regmap;
|
||||
@ -444,11 +456,11 @@ static void __init of_at91rm9200_clk_main_setup(struct device_node *np)
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
clk = at91_clk_register_rm9200_main(regmap, name, parent_name);
|
||||
if (IS_ERR(clk))
|
||||
hw = at91_clk_register_rm9200_main(regmap, name, parent_name);
|
||||
if (IS_ERR(hw))
|
||||
return;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
CLK_OF_DECLARE(at91rm9200_clk_main, "atmel,at91rm9200-clk-main",
|
||||
of_at91rm9200_clk_main_setup);
|
||||
@ -529,16 +541,17 @@ static const struct clk_ops sam9x5_main_ops = {
|
||||
.get_parent = clk_sam9x5_main_get_parent,
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
static struct clk_hw * __init
|
||||
at91_clk_register_sam9x5_main(struct regmap *regmap,
|
||||
const char *name,
|
||||
const char **parent_names,
|
||||
int num_parents)
|
||||
{
|
||||
struct clk_sam9x5_main *clkmain;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
unsigned int status;
|
||||
struct clk_hw *hw;
|
||||
int ret;
|
||||
|
||||
if (!name)
|
||||
return ERR_PTR(-EINVAL);
|
||||
@ -561,16 +574,19 @@ at91_clk_register_sam9x5_main(struct regmap *regmap,
|
||||
regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
|
||||
clkmain->parent = status & AT91_PMC_MOSCEN ? 1 : 0;
|
||||
|
||||
clk = clk_register(NULL, &clkmain->hw);
|
||||
if (IS_ERR(clk))
|
||||
hw = &clkmain->hw;
|
||||
ret = clk_hw_register(NULL, &clkmain->hw);
|
||||
if (ret) {
|
||||
kfree(clkmain);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return clk;
|
||||
return hw;
|
||||
}
|
||||
|
||||
static void __init of_at91sam9x5_clk_main_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
const char *parent_names[2];
|
||||
unsigned int num_parents;
|
||||
const char *name = np->name;
|
||||
@ -587,12 +603,12 @@ static void __init of_at91sam9x5_clk_main_setup(struct device_node *np)
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
|
||||
clk = at91_clk_register_sam9x5_main(regmap, name, parent_names,
|
||||
hw = at91_clk_register_sam9x5_main(regmap, name, parent_names,
|
||||
num_parents);
|
||||
if (IS_ERR(clk))
|
||||
if (IS_ERR(hw))
|
||||
return;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
CLK_OF_DECLARE(at91sam9x5_clk_main, "atmel,at91sam9x5-clk-main",
|
||||
of_at91sam9x5_clk_main_setup);
|
||||
|
@ -120,7 +120,7 @@ static const struct clk_ops master_ops = {
|
||||
.get_parent = clk_master_get_parent,
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
static struct clk_hw * __init
|
||||
at91_clk_register_master(struct regmap *regmap,
|
||||
const char *name, int num_parents,
|
||||
const char **parent_names,
|
||||
@ -128,8 +128,9 @@ at91_clk_register_master(struct regmap *regmap,
|
||||
const struct clk_master_characteristics *characteristics)
|
||||
{
|
||||
struct clk_master *master;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
struct clk_hw *hw;
|
||||
int ret;
|
||||
|
||||
if (!name || !num_parents || !parent_names)
|
||||
return ERR_PTR(-EINVAL);
|
||||
@ -149,12 +150,14 @@ at91_clk_register_master(struct regmap *regmap,
|
||||
master->characteristics = characteristics;
|
||||
master->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &master->hw);
|
||||
if (IS_ERR(clk)) {
|
||||
hw = &master->hw;
|
||||
ret = clk_hw_register(NULL, &master->hw);
|
||||
if (ret) {
|
||||
kfree(master);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return clk;
|
||||
return hw;
|
||||
}
|
||||
|
||||
|
||||
@ -198,7 +201,7 @@ static void __init
|
||||
of_at91_clk_master_setup(struct device_node *np,
|
||||
const struct clk_master_layout *layout)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
unsigned int num_parents;
|
||||
const char *parent_names[MASTER_SOURCE_MAX];
|
||||
const char *name = np->name;
|
||||
@ -221,13 +224,13 @@ of_at91_clk_master_setup(struct device_node *np,
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
clk = at91_clk_register_master(regmap, name, num_parents,
|
||||
hw = at91_clk_register_master(regmap, name, num_parents,
|
||||
parent_names, layout,
|
||||
characteristics);
|
||||
if (IS_ERR(clk))
|
||||
if (IS_ERR(hw))
|
||||
goto out_free_characteristics;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
|
||||
return;
|
||||
|
||||
out_free_characteristics:
|
||||
|
@ -104,13 +104,14 @@ static const struct clk_ops peripheral_ops = {
|
||||
.is_enabled = clk_peripheral_is_enabled,
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
static struct clk_hw * __init
|
||||
at91_clk_register_peripheral(struct regmap *regmap, const char *name,
|
||||
const char *parent_name, u32 id)
|
||||
{
|
||||
struct clk_peripheral *periph;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
struct clk_hw *hw;
|
||||
int ret;
|
||||
|
||||
if (!name || !parent_name || id > PERIPHERAL_ID_MAX)
|
||||
return ERR_PTR(-EINVAL);
|
||||
@ -129,11 +130,14 @@ at91_clk_register_peripheral(struct regmap *regmap, const char *name,
|
||||
periph->hw.init = &init;
|
||||
periph->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &periph->hw);
|
||||
if (IS_ERR(clk))
|
||||
hw = &periph->hw;
|
||||
ret = clk_hw_register(NULL, &periph->hw);
|
||||
if (ret) {
|
||||
kfree(periph);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return clk;
|
||||
return hw;
|
||||
}
|
||||
|
||||
static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph)
|
||||
@ -327,14 +331,15 @@ static const struct clk_ops sam9x5_peripheral_ops = {
|
||||
.set_rate = clk_sam9x5_peripheral_set_rate,
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
static struct clk_hw * __init
|
||||
at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
|
||||
const char *name, const char *parent_name,
|
||||
u32 id, const struct clk_range *range)
|
||||
{
|
||||
struct clk_sam9x5_peripheral *periph;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
struct clk_hw *hw;
|
||||
int ret;
|
||||
|
||||
if (!name || !parent_name)
|
||||
return ERR_PTR(-EINVAL);
|
||||
@ -357,13 +362,15 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
|
||||
periph->auto_div = true;
|
||||
periph->range = *range;
|
||||
|
||||
clk = clk_register(NULL, &periph->hw);
|
||||
if (IS_ERR(clk))
|
||||
hw = &periph->hw;
|
||||
ret = clk_hw_register(NULL, &periph->hw);
|
||||
if (ret) {
|
||||
kfree(periph);
|
||||
else
|
||||
hw = ERR_PTR(ret);
|
||||
} else
|
||||
clk_sam9x5_peripheral_autodiv(periph);
|
||||
|
||||
return clk;
|
||||
return hw;
|
||||
}
|
||||
|
||||
static void __init
|
||||
@ -371,7 +378,7 @@ of_at91_clk_periph_setup(struct device_node *np, u8 type)
|
||||
{
|
||||
int num;
|
||||
u32 id;
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
const char *parent_name;
|
||||
const char *name;
|
||||
struct device_node *periphclknp;
|
||||
@ -400,7 +407,7 @@ of_at91_clk_periph_setup(struct device_node *np, u8 type)
|
||||
name = periphclknp->name;
|
||||
|
||||
if (type == PERIPHERAL_AT91RM9200) {
|
||||
clk = at91_clk_register_peripheral(regmap, name,
|
||||
hw = at91_clk_register_peripheral(regmap, name,
|
||||
parent_name, id);
|
||||
} else {
|
||||
struct clk_range range = CLK_RANGE(0, 0);
|
||||
@ -409,17 +416,17 @@ of_at91_clk_periph_setup(struct device_node *np, u8 type)
|
||||
"atmel,clk-output-range",
|
||||
&range);
|
||||
|
||||
clk = at91_clk_register_sam9x5_peripheral(regmap,
|
||||
hw = at91_clk_register_sam9x5_peripheral(regmap,
|
||||
&pmc_pcr_lock,
|
||||
name,
|
||||
parent_name,
|
||||
id, &range);
|
||||
}
|
||||
|
||||
if (IS_ERR(clk))
|
||||
if (IS_ERR(hw))
|
||||
continue;
|
||||
|
||||
of_clk_add_provider(periphclknp, of_clk_src_simple_get, clk);
|
||||
of_clk_add_hw_provider(periphclknp, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -296,17 +296,18 @@ static const struct clk_ops pll_ops = {
|
||||
.set_rate = clk_pll_set_rate,
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
static struct clk_hw * __init
|
||||
at91_clk_register_pll(struct regmap *regmap, const char *name,
|
||||
const char *parent_name, u8 id,
|
||||
const struct clk_pll_layout *layout,
|
||||
const struct clk_pll_characteristics *characteristics)
|
||||
{
|
||||
struct clk_pll *pll;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_hw *hw;
|
||||
struct clk_init_data init;
|
||||
int offset = PLL_REG(id);
|
||||
unsigned int pllr;
|
||||
int ret;
|
||||
|
||||
if (id > PLL_MAX_ID)
|
||||
return ERR_PTR(-EINVAL);
|
||||
@ -330,12 +331,14 @@ at91_clk_register_pll(struct regmap *regmap, const char *name,
|
||||
pll->div = PLL_DIV(pllr);
|
||||
pll->mul = PLL_MUL(pllr, layout);
|
||||
|
||||
clk = clk_register(NULL, &pll->hw);
|
||||
if (IS_ERR(clk)) {
|
||||
hw = &pll->hw;
|
||||
ret = clk_hw_register(NULL, &pll->hw);
|
||||
if (ret) {
|
||||
kfree(pll);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return clk;
|
||||
return hw;
|
||||
}
|
||||
|
||||
|
||||
@ -465,7 +468,7 @@ of_at91_clk_pll_setup(struct device_node *np,
|
||||
const struct clk_pll_layout *layout)
|
||||
{
|
||||
u32 id;
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
struct regmap *regmap;
|
||||
const char *parent_name;
|
||||
const char *name = np->name;
|
||||
@ -486,12 +489,12 @@ of_at91_clk_pll_setup(struct device_node *np,
|
||||
if (!characteristics)
|
||||
return;
|
||||
|
||||
clk = at91_clk_register_pll(regmap, name, parent_name, id, layout,
|
||||
hw = at91_clk_register_pll(regmap, name, parent_name, id, layout,
|
||||
characteristics);
|
||||
if (IS_ERR(clk))
|
||||
if (IS_ERR(hw))
|
||||
goto out_free_characteristics;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
|
||||
return;
|
||||
|
||||
out_free_characteristics:
|
||||
|
@ -75,13 +75,14 @@ static const struct clk_ops plldiv_ops = {
|
||||
.set_rate = clk_plldiv_set_rate,
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
static struct clk_hw * __init
|
||||
at91_clk_register_plldiv(struct regmap *regmap, const char *name,
|
||||
const char *parent_name)
|
||||
{
|
||||
struct clk_plldiv *plldiv;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_hw *hw;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
|
||||
plldiv = kzalloc(sizeof(*plldiv), GFP_KERNEL);
|
||||
if (!plldiv)
|
||||
@ -96,18 +97,20 @@ at91_clk_register_plldiv(struct regmap *regmap, const char *name,
|
||||
plldiv->hw.init = &init;
|
||||
plldiv->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &plldiv->hw);
|
||||
|
||||
if (IS_ERR(clk))
|
||||
hw = &plldiv->hw;
|
||||
ret = clk_hw_register(NULL, &plldiv->hw);
|
||||
if (ret) {
|
||||
kfree(plldiv);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return clk;
|
||||
return hw;
|
||||
}
|
||||
|
||||
static void __init
|
||||
of_at91sam9x5_clk_plldiv_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
const char *parent_name;
|
||||
const char *name = np->name;
|
||||
struct regmap *regmap;
|
||||
@ -120,12 +123,11 @@ of_at91sam9x5_clk_plldiv_setup(struct device_node *np)
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
clk = at91_clk_register_plldiv(regmap, name, parent_name);
|
||||
if (IS_ERR(clk))
|
||||
hw = at91_clk_register_plldiv(regmap, name, parent_name);
|
||||
if (IS_ERR(hw))
|
||||
return;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
return;
|
||||
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
CLK_OF_DECLARE(at91sam9x5_clk_plldiv, "atmel,at91sam9x5-clk-plldiv",
|
||||
of_at91sam9x5_clk_plldiv_setup);
|
||||
|
@ -170,15 +170,16 @@ static const struct clk_ops programmable_ops = {
|
||||
.set_rate = clk_programmable_set_rate,
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
static struct clk_hw * __init
|
||||
at91_clk_register_programmable(struct regmap *regmap,
|
||||
const char *name, const char **parent_names,
|
||||
u8 num_parents, u8 id,
|
||||
const struct clk_programmable_layout *layout)
|
||||
{
|
||||
struct clk_programmable *prog;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_hw *hw;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
|
||||
if (id > PROG_ID_MAX)
|
||||
return ERR_PTR(-EINVAL);
|
||||
@ -198,11 +199,14 @@ at91_clk_register_programmable(struct regmap *regmap,
|
||||
prog->hw.init = &init;
|
||||
prog->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &prog->hw);
|
||||
if (IS_ERR(clk))
|
||||
hw = &prog->hw;
|
||||
ret = clk_hw_register(NULL, &prog->hw);
|
||||
if (ret) {
|
||||
kfree(prog);
|
||||
hw = &prog->hw;
|
||||
}
|
||||
|
||||
return clk;
|
||||
return hw;
|
||||
}
|
||||
|
||||
static const struct clk_programmable_layout at91rm9200_programmable_layout = {
|
||||
@ -229,7 +233,7 @@ of_at91_clk_prog_setup(struct device_node *np,
|
||||
{
|
||||
int num;
|
||||
u32 id;
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
unsigned int num_parents;
|
||||
const char *parent_names[PROG_SOURCE_MAX];
|
||||
const char *name;
|
||||
@ -257,13 +261,13 @@ of_at91_clk_prog_setup(struct device_node *np,
|
||||
if (of_property_read_string(np, "clock-output-names", &name))
|
||||
name = progclknp->name;
|
||||
|
||||
clk = at91_clk_register_programmable(regmap, name,
|
||||
hw = at91_clk_register_programmable(regmap, name,
|
||||
parent_names, num_parents,
|
||||
id, layout);
|
||||
if (IS_ERR(clk))
|
||||
if (IS_ERR(hw))
|
||||
continue;
|
||||
|
||||
of_clk_add_provider(progclknp, of_clk_src_simple_get, clk);
|
||||
of_clk_add_hw_provider(progclknp, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,42 +13,11 @@
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk/at91_pmc.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "pmc.h"
|
||||
#include "sckc.h"
|
||||
|
||||
#define SLOW_CLOCK_FREQ 32768
|
||||
#define SLOWCK_SW_CYCLES 5
|
||||
#define SLOWCK_SW_TIME_USEC ((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \
|
||||
SLOW_CLOCK_FREQ)
|
||||
|
||||
#define AT91_SCKC_CR 0x00
|
||||
#define AT91_SCKC_RCEN (1 << 0)
|
||||
#define AT91_SCKC_OSC32EN (1 << 1)
|
||||
#define AT91_SCKC_OSC32BYP (1 << 2)
|
||||
#define AT91_SCKC_OSCSEL (1 << 3)
|
||||
|
||||
struct clk_slow_osc {
|
||||
struct clk_hw hw;
|
||||
void __iomem *sckcr;
|
||||
unsigned long startup_usec;
|
||||
};
|
||||
|
||||
#define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw)
|
||||
|
||||
struct clk_slow_rc_osc {
|
||||
struct clk_hw hw;
|
||||
void __iomem *sckcr;
|
||||
unsigned long frequency;
|
||||
unsigned long accuracy;
|
||||
unsigned long startup_usec;
|
||||
};
|
||||
|
||||
#define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw)
|
||||
|
||||
struct clk_sam9260_slow {
|
||||
struct clk_hw hw;
|
||||
@ -57,328 +26,6 @@ struct clk_sam9260_slow {
|
||||
|
||||
#define to_clk_sam9260_slow(hw) container_of(hw, struct clk_sam9260_slow, hw)
|
||||
|
||||
struct clk_sam9x5_slow {
|
||||
struct clk_hw hw;
|
||||
void __iomem *sckcr;
|
||||
u8 parent;
|
||||
};
|
||||
|
||||
#define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
|
||||
|
||||
static int clk_slow_osc_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_slow_osc *osc = to_clk_slow_osc(hw);
|
||||
void __iomem *sckcr = osc->sckcr;
|
||||
u32 tmp = readl(sckcr);
|
||||
|
||||
if (tmp & AT91_SCKC_OSC32BYP)
|
||||
return 0;
|
||||
|
||||
writel(tmp | AT91_SCKC_OSC32EN, sckcr);
|
||||
|
||||
usleep_range(osc->startup_usec, osc->startup_usec + 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_slow_osc_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_slow_osc *osc = to_clk_slow_osc(hw);
|
||||
void __iomem *sckcr = osc->sckcr;
|
||||
u32 tmp = readl(sckcr);
|
||||
|
||||
if (tmp & AT91_SCKC_OSC32BYP)
|
||||
return;
|
||||
|
||||
writel(tmp & ~AT91_SCKC_OSC32EN, sckcr);
|
||||
}
|
||||
|
||||
static int clk_slow_osc_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_slow_osc *osc = to_clk_slow_osc(hw);
|
||||
void __iomem *sckcr = osc->sckcr;
|
||||
u32 tmp = readl(sckcr);
|
||||
|
||||
if (tmp & AT91_SCKC_OSC32BYP)
|
||||
return 1;
|
||||
|
||||
return !!(tmp & AT91_SCKC_OSC32EN);
|
||||
}
|
||||
|
||||
static const struct clk_ops slow_osc_ops = {
|
||||
.prepare = clk_slow_osc_prepare,
|
||||
.unprepare = clk_slow_osc_unprepare,
|
||||
.is_prepared = clk_slow_osc_is_prepared,
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
at91_clk_register_slow_osc(void __iomem *sckcr,
|
||||
const char *name,
|
||||
const char *parent_name,
|
||||
unsigned long startup,
|
||||
bool bypass)
|
||||
{
|
||||
struct clk_slow_osc *osc;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
|
||||
if (!sckcr || !name || !parent_name)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
osc = kzalloc(sizeof(*osc), GFP_KERNEL);
|
||||
if (!osc)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &slow_osc_ops;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
init.flags = CLK_IGNORE_UNUSED;
|
||||
|
||||
osc->hw.init = &init;
|
||||
osc->sckcr = sckcr;
|
||||
osc->startup_usec = startup;
|
||||
|
||||
if (bypass)
|
||||
writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP,
|
||||
sckcr);
|
||||
|
||||
clk = clk_register(NULL, &osc->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(osc);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
void __init of_at91sam9x5_clk_slow_osc_setup(struct device_node *np,
|
||||
void __iomem *sckcr)
|
||||
{
|
||||
struct clk *clk;
|
||||
const char *parent_name;
|
||||
const char *name = np->name;
|
||||
u32 startup;
|
||||
bool bypass;
|
||||
|
||||
parent_name = of_clk_get_parent_name(np, 0);
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
of_property_read_u32(np, "atmel,startup-time-usec", &startup);
|
||||
bypass = of_property_read_bool(np, "atmel,osc-bypass");
|
||||
|
||||
clk = at91_clk_register_slow_osc(sckcr, name, parent_name, startup,
|
||||
bypass);
|
||||
if (IS_ERR(clk))
|
||||
return;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
}
|
||||
|
||||
static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
|
||||
|
||||
return osc->frequency;
|
||||
}
|
||||
|
||||
static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw,
|
||||
unsigned long parent_acc)
|
||||
{
|
||||
struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
|
||||
|
||||
return osc->accuracy;
|
||||
}
|
||||
|
||||
static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
|
||||
void __iomem *sckcr = osc->sckcr;
|
||||
|
||||
writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr);
|
||||
|
||||
usleep_range(osc->startup_usec, osc->startup_usec + 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_slow_rc_osc_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
|
||||
void __iomem *sckcr = osc->sckcr;
|
||||
|
||||
writel(readl(sckcr) & ~AT91_SCKC_RCEN, sckcr);
|
||||
}
|
||||
|
||||
static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
|
||||
|
||||
return !!(readl(osc->sckcr) & AT91_SCKC_RCEN);
|
||||
}
|
||||
|
||||
static const struct clk_ops slow_rc_osc_ops = {
|
||||
.prepare = clk_slow_rc_osc_prepare,
|
||||
.unprepare = clk_slow_rc_osc_unprepare,
|
||||
.is_prepared = clk_slow_rc_osc_is_prepared,
|
||||
.recalc_rate = clk_slow_rc_osc_recalc_rate,
|
||||
.recalc_accuracy = clk_slow_rc_osc_recalc_accuracy,
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
at91_clk_register_slow_rc_osc(void __iomem *sckcr,
|
||||
const char *name,
|
||||
unsigned long frequency,
|
||||
unsigned long accuracy,
|
||||
unsigned long startup)
|
||||
{
|
||||
struct clk_slow_rc_osc *osc;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
|
||||
if (!sckcr || !name)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
osc = kzalloc(sizeof(*osc), GFP_KERNEL);
|
||||
if (!osc)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &slow_rc_osc_ops;
|
||||
init.parent_names = NULL;
|
||||
init.num_parents = 0;
|
||||
init.flags = CLK_IGNORE_UNUSED;
|
||||
|
||||
osc->hw.init = &init;
|
||||
osc->sckcr = sckcr;
|
||||
osc->frequency = frequency;
|
||||
osc->accuracy = accuracy;
|
||||
osc->startup_usec = startup;
|
||||
|
||||
clk = clk_register(NULL, &osc->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(osc);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
void __init of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np,
|
||||
void __iomem *sckcr)
|
||||
{
|
||||
struct clk *clk;
|
||||
u32 frequency = 0;
|
||||
u32 accuracy = 0;
|
||||
u32 startup = 0;
|
||||
const char *name = np->name;
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
of_property_read_u32(np, "clock-frequency", &frequency);
|
||||
of_property_read_u32(np, "clock-accuracy", &accuracy);
|
||||
of_property_read_u32(np, "atmel,startup-time-usec", &startup);
|
||||
|
||||
clk = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy,
|
||||
startup);
|
||||
if (IS_ERR(clk))
|
||||
return;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
}
|
||||
|
||||
static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
|
||||
void __iomem *sckcr = slowck->sckcr;
|
||||
u32 tmp;
|
||||
|
||||
if (index > 1)
|
||||
return -EINVAL;
|
||||
|
||||
tmp = readl(sckcr);
|
||||
|
||||
if ((!index && !(tmp & AT91_SCKC_OSCSEL)) ||
|
||||
(index && (tmp & AT91_SCKC_OSCSEL)))
|
||||
return 0;
|
||||
|
||||
if (index)
|
||||
tmp |= AT91_SCKC_OSCSEL;
|
||||
else
|
||||
tmp &= ~AT91_SCKC_OSCSEL;
|
||||
|
||||
writel(tmp, sckcr);
|
||||
|
||||
usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
|
||||
|
||||
return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL);
|
||||
}
|
||||
|
||||
static const struct clk_ops sam9x5_slow_ops = {
|
||||
.set_parent = clk_sam9x5_slow_set_parent,
|
||||
.get_parent = clk_sam9x5_slow_get_parent,
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
at91_clk_register_sam9x5_slow(void __iomem *sckcr,
|
||||
const char *name,
|
||||
const char **parent_names,
|
||||
int num_parents)
|
||||
{
|
||||
struct clk_sam9x5_slow *slowck;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
|
||||
if (!sckcr || !name || !parent_names || !num_parents)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
|
||||
if (!slowck)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &sam9x5_slow_ops;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
init.flags = 0;
|
||||
|
||||
slowck->hw.init = &init;
|
||||
slowck->sckcr = sckcr;
|
||||
slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL);
|
||||
|
||||
clk = clk_register(NULL, &slowck->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(slowck);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
void __init of_at91sam9x5_clk_slow_setup(struct device_node *np,
|
||||
void __iomem *sckcr)
|
||||
{
|
||||
struct clk *clk;
|
||||
const char *parent_names[2];
|
||||
unsigned int num_parents;
|
||||
const char *name = np->name;
|
||||
|
||||
num_parents = of_clk_get_parent_count(np);
|
||||
if (num_parents == 0 || num_parents > 2)
|
||||
return;
|
||||
|
||||
of_clk_parent_fill(np, parent_names, num_parents);
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
|
||||
clk = at91_clk_register_sam9x5_slow(sckcr, name, parent_names,
|
||||
num_parents);
|
||||
if (IS_ERR(clk))
|
||||
return;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
}
|
||||
|
||||
static u8 clk_sam9260_slow_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(hw);
|
||||
@ -393,15 +40,16 @@ static const struct clk_ops sam9260_slow_ops = {
|
||||
.get_parent = clk_sam9260_slow_get_parent,
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
static struct clk_hw * __init
|
||||
at91_clk_register_sam9260_slow(struct regmap *regmap,
|
||||
const char *name,
|
||||
const char **parent_names,
|
||||
int num_parents)
|
||||
{
|
||||
struct clk_sam9260_slow *slowck;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_hw *hw;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
|
||||
if (!name)
|
||||
return ERR_PTR(-EINVAL);
|
||||
@ -422,16 +70,19 @@ at91_clk_register_sam9260_slow(struct regmap *regmap,
|
||||
slowck->hw.init = &init;
|
||||
slowck->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &slowck->hw);
|
||||
if (IS_ERR(clk))
|
||||
hw = &slowck->hw;
|
||||
ret = clk_hw_register(NULL, &slowck->hw);
|
||||
if (ret) {
|
||||
kfree(slowck);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return clk;
|
||||
return hw;
|
||||
}
|
||||
|
||||
static void __init of_at91sam9260_clk_slow_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
const char *parent_names[2];
|
||||
unsigned int num_parents;
|
||||
const char *name = np->name;
|
||||
@ -448,12 +99,12 @@ static void __init of_at91sam9260_clk_slow_setup(struct device_node *np)
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
|
||||
clk = at91_clk_register_sam9260_slow(regmap, name, parent_names,
|
||||
hw = at91_clk_register_sam9260_slow(regmap, name, parent_names,
|
||||
num_parents);
|
||||
if (IS_ERR(clk))
|
||||
if (IS_ERR(hw))
|
||||
return;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
|
||||
CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow",
|
||||
|
@ -111,13 +111,14 @@ static const struct clk_ops at91sam9x5_smd_ops = {
|
||||
.set_rate = at91sam9x5_clk_smd_set_rate,
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
static struct clk_hw * __init
|
||||
at91sam9x5_clk_register_smd(struct regmap *regmap, const char *name,
|
||||
const char **parent_names, u8 num_parents)
|
||||
{
|
||||
struct at91sam9x5_clk_smd *smd;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_hw *hw;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
|
||||
smd = kzalloc(sizeof(*smd), GFP_KERNEL);
|
||||
if (!smd)
|
||||
@ -132,16 +133,19 @@ at91sam9x5_clk_register_smd(struct regmap *regmap, const char *name,
|
||||
smd->hw.init = &init;
|
||||
smd->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &smd->hw);
|
||||
if (IS_ERR(clk))
|
||||
hw = &smd->hw;
|
||||
ret = clk_hw_register(NULL, &smd->hw);
|
||||
if (ret) {
|
||||
kfree(smd);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return clk;
|
||||
return hw;
|
||||
}
|
||||
|
||||
static void __init of_at91sam9x5_clk_smd_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
unsigned int num_parents;
|
||||
const char *parent_names[SMD_SOURCE_MAX];
|
||||
const char *name = np->name;
|
||||
@ -159,12 +163,12 @@ static void __init of_at91sam9x5_clk_smd_setup(struct device_node *np)
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
clk = at91sam9x5_clk_register_smd(regmap, name, parent_names,
|
||||
hw = at91sam9x5_clk_register_smd(regmap, name, parent_names,
|
||||
num_parents);
|
||||
if (IS_ERR(clk))
|
||||
if (IS_ERR(hw))
|
||||
return;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
CLK_OF_DECLARE(at91sam9x5_clk_smd, "atmel,at91sam9x5-clk-smd",
|
||||
of_at91sam9x5_clk_smd_setup);
|
||||
|
@ -88,13 +88,14 @@ static const struct clk_ops system_ops = {
|
||||
.is_prepared = clk_system_is_prepared,
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
static struct clk_hw * __init
|
||||
at91_clk_register_system(struct regmap *regmap, const char *name,
|
||||
const char *parent_name, u8 id)
|
||||
{
|
||||
struct clk_system *sys;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_hw *hw;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
|
||||
if (!parent_name || id > SYSTEM_MAX_ID)
|
||||
return ERR_PTR(-EINVAL);
|
||||
@ -113,18 +114,21 @@ at91_clk_register_system(struct regmap *regmap, const char *name,
|
||||
sys->hw.init = &init;
|
||||
sys->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &sys->hw);
|
||||
if (IS_ERR(clk))
|
||||
hw = &sys->hw;
|
||||
ret = clk_hw_register(NULL, &sys->hw);
|
||||
if (ret) {
|
||||
kfree(sys);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return clk;
|
||||
return hw;
|
||||
}
|
||||
|
||||
static void __init of_at91rm9200_clk_sys_setup(struct device_node *np)
|
||||
{
|
||||
int num;
|
||||
u32 id;
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
const char *name;
|
||||
struct device_node *sysclknp;
|
||||
const char *parent_name;
|
||||
@ -147,11 +151,11 @@ static void __init of_at91rm9200_clk_sys_setup(struct device_node *np)
|
||||
|
||||
parent_name = of_clk_get_parent_name(sysclknp, 0);
|
||||
|
||||
clk = at91_clk_register_system(regmap, name, parent_name, id);
|
||||
if (IS_ERR(clk))
|
||||
hw = at91_clk_register_system(regmap, name, parent_name, id);
|
||||
if (IS_ERR(hw))
|
||||
continue;
|
||||
|
||||
of_clk_add_provider(sysclknp, of_clk_src_simple_get, clk);
|
||||
of_clk_add_hw_provider(sysclknp, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
}
|
||||
CLK_OF_DECLARE(at91rm9200_clk_sys, "atmel,at91rm9200-clk-system",
|
||||
|
@ -192,13 +192,14 @@ static const struct clk_ops at91sam9n12_usb_ops = {
|
||||
.set_rate = at91sam9x5_clk_usb_set_rate,
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
static struct clk_hw * __init
|
||||
at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
|
||||
const char **parent_names, u8 num_parents)
|
||||
{
|
||||
struct at91sam9x5_clk_usb *usb;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_hw *hw;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
|
||||
usb = kzalloc(sizeof(*usb), GFP_KERNEL);
|
||||
if (!usb)
|
||||
@ -214,20 +215,24 @@ at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
|
||||
usb->hw.init = &init;
|
||||
usb->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &usb->hw);
|
||||
if (IS_ERR(clk))
|
||||
hw = &usb->hw;
|
||||
ret = clk_hw_register(NULL, &usb->hw);
|
||||
if (ret) {
|
||||
kfree(usb);
|
||||
|
||||
return clk;
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static struct clk * __init
|
||||
return hw;
|
||||
}
|
||||
|
||||
static struct clk_hw * __init
|
||||
at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name,
|
||||
const char *parent_name)
|
||||
{
|
||||
struct at91sam9x5_clk_usb *usb;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_hw *hw;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
|
||||
usb = kzalloc(sizeof(*usb), GFP_KERNEL);
|
||||
if (!usb)
|
||||
@ -242,11 +247,14 @@ at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name,
|
||||
usb->hw.init = &init;
|
||||
usb->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &usb->hw);
|
||||
if (IS_ERR(clk))
|
||||
hw = &usb->hw;
|
||||
ret = clk_hw_register(NULL, &usb->hw);
|
||||
if (ret) {
|
||||
kfree(usb);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return clk;
|
||||
return hw;
|
||||
}
|
||||
|
||||
static unsigned long at91rm9200_clk_usb_recalc_rate(struct clk_hw *hw,
|
||||
@ -334,13 +342,14 @@ static const struct clk_ops at91rm9200_usb_ops = {
|
||||
.set_rate = at91rm9200_clk_usb_set_rate,
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
static struct clk_hw * __init
|
||||
at91rm9200_clk_register_usb(struct regmap *regmap, const char *name,
|
||||
const char *parent_name, const u32 *divisors)
|
||||
{
|
||||
struct at91rm9200_clk_usb *usb;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_hw *hw;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
|
||||
usb = kzalloc(sizeof(*usb), GFP_KERNEL);
|
||||
if (!usb)
|
||||
@ -356,16 +365,19 @@ at91rm9200_clk_register_usb(struct regmap *regmap, const char *name,
|
||||
usb->regmap = regmap;
|
||||
memcpy(usb->divisors, divisors, sizeof(usb->divisors));
|
||||
|
||||
clk = clk_register(NULL, &usb->hw);
|
||||
if (IS_ERR(clk))
|
||||
hw = &usb->hw;
|
||||
ret = clk_hw_register(NULL, &usb->hw);
|
||||
if (ret) {
|
||||
kfree(usb);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return clk;
|
||||
return hw;
|
||||
}
|
||||
|
||||
static void __init of_at91sam9x5_clk_usb_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
unsigned int num_parents;
|
||||
const char *parent_names[USB_SOURCE_MAX];
|
||||
const char *name = np->name;
|
||||
@ -383,19 +395,19 @@ static void __init of_at91sam9x5_clk_usb_setup(struct device_node *np)
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
clk = at91sam9x5_clk_register_usb(regmap, name, parent_names,
|
||||
hw = at91sam9x5_clk_register_usb(regmap, name, parent_names,
|
||||
num_parents);
|
||||
if (IS_ERR(clk))
|
||||
if (IS_ERR(hw))
|
||||
return;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
CLK_OF_DECLARE(at91sam9x5_clk_usb, "atmel,at91sam9x5-clk-usb",
|
||||
of_at91sam9x5_clk_usb_setup);
|
||||
|
||||
static void __init of_at91sam9n12_clk_usb_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
const char *parent_name;
|
||||
const char *name = np->name;
|
||||
struct regmap *regmap;
|
||||
@ -410,18 +422,18 @@ static void __init of_at91sam9n12_clk_usb_setup(struct device_node *np)
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
clk = at91sam9n12_clk_register_usb(regmap, name, parent_name);
|
||||
if (IS_ERR(clk))
|
||||
hw = at91sam9n12_clk_register_usb(regmap, name, parent_name);
|
||||
if (IS_ERR(hw))
|
||||
return;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
CLK_OF_DECLARE(at91sam9n12_clk_usb, "atmel,at91sam9n12-clk-usb",
|
||||
of_at91sam9n12_clk_usb_setup);
|
||||
|
||||
static void __init of_at91rm9200_clk_usb_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
const char *parent_name;
|
||||
const char *name = np->name;
|
||||
u32 divisors[4] = {0, 0, 0, 0};
|
||||
@ -440,12 +452,11 @@ static void __init of_at91rm9200_clk_usb_setup(struct device_node *np)
|
||||
regmap = syscon_node_to_regmap(of_get_parent(np));
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
clk = at91rm9200_clk_register_usb(regmap, name, parent_name, divisors);
|
||||
if (IS_ERR(clk))
|
||||
hw = at91rm9200_clk_register_usb(regmap, name, parent_name, divisors);
|
||||
if (IS_ERR(hw))
|
||||
return;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
CLK_OF_DECLARE(at91rm9200_clk_usb, "atmel,at91rm9200-clk-usb",
|
||||
of_at91rm9200_clk_usb_setup);
|
||||
|
@ -77,13 +77,14 @@ static const struct clk_ops utmi_ops = {
|
||||
.recalc_rate = clk_utmi_recalc_rate,
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
static struct clk_hw * __init
|
||||
at91_clk_register_utmi(struct regmap *regmap,
|
||||
const char *name, const char *parent_name)
|
||||
{
|
||||
struct clk_utmi *utmi;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_hw *hw;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
|
||||
utmi = kzalloc(sizeof(*utmi), GFP_KERNEL);
|
||||
if (!utmi)
|
||||
@ -98,16 +99,19 @@ at91_clk_register_utmi(struct regmap *regmap,
|
||||
utmi->hw.init = &init;
|
||||
utmi->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &utmi->hw);
|
||||
if (IS_ERR(clk))
|
||||
hw = &utmi->hw;
|
||||
ret = clk_hw_register(NULL, &utmi->hw);
|
||||
if (ret) {
|
||||
kfree(utmi);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return clk;
|
||||
return hw;
|
||||
}
|
||||
|
||||
static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
const char *parent_name;
|
||||
const char *name = np->name;
|
||||
struct regmap *regmap;
|
||||
@ -120,11 +124,11 @@ static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np)
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
clk = at91_clk_register_utmi(regmap, name, parent_name);
|
||||
if (IS_ERR(clk))
|
||||
hw = at91_clk_register_utmi(regmap, name, parent_name);
|
||||
if (IS_ERR(hw))
|
||||
return;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
|
||||
return;
|
||||
}
|
||||
CLK_OF_DECLARE(at91sam9x5_clk_utmi, "atmel,at91sam9x5-clk-utmi",
|
||||
|
@ -12,11 +12,382 @@
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "sckc.h"
|
||||
#define SLOW_CLOCK_FREQ 32768
|
||||
#define SLOWCK_SW_CYCLES 5
|
||||
#define SLOWCK_SW_TIME_USEC ((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \
|
||||
SLOW_CLOCK_FREQ)
|
||||
|
||||
#define AT91_SCKC_CR 0x00
|
||||
#define AT91_SCKC_RCEN (1 << 0)
|
||||
#define AT91_SCKC_OSC32EN (1 << 1)
|
||||
#define AT91_SCKC_OSC32BYP (1 << 2)
|
||||
#define AT91_SCKC_OSCSEL (1 << 3)
|
||||
|
||||
struct clk_slow_osc {
|
||||
struct clk_hw hw;
|
||||
void __iomem *sckcr;
|
||||
unsigned long startup_usec;
|
||||
};
|
||||
|
||||
#define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw)
|
||||
|
||||
struct clk_sama5d4_slow_osc {
|
||||
struct clk_hw hw;
|
||||
void __iomem *sckcr;
|
||||
unsigned long startup_usec;
|
||||
bool prepared;
|
||||
};
|
||||
|
||||
#define to_clk_sama5d4_slow_osc(hw) container_of(hw, struct clk_sama5d4_slow_osc, hw)
|
||||
|
||||
struct clk_slow_rc_osc {
|
||||
struct clk_hw hw;
|
||||
void __iomem *sckcr;
|
||||
unsigned long frequency;
|
||||
unsigned long accuracy;
|
||||
unsigned long startup_usec;
|
||||
};
|
||||
|
||||
#define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw)
|
||||
|
||||
struct clk_sam9x5_slow {
|
||||
struct clk_hw hw;
|
||||
void __iomem *sckcr;
|
||||
u8 parent;
|
||||
};
|
||||
|
||||
#define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
|
||||
|
||||
static int clk_slow_osc_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_slow_osc *osc = to_clk_slow_osc(hw);
|
||||
void __iomem *sckcr = osc->sckcr;
|
||||
u32 tmp = readl(sckcr);
|
||||
|
||||
if (tmp & (AT91_SCKC_OSC32BYP | AT91_SCKC_OSC32EN))
|
||||
return 0;
|
||||
|
||||
writel(tmp | AT91_SCKC_OSC32EN, sckcr);
|
||||
|
||||
usleep_range(osc->startup_usec, osc->startup_usec + 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_slow_osc_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_slow_osc *osc = to_clk_slow_osc(hw);
|
||||
void __iomem *sckcr = osc->sckcr;
|
||||
u32 tmp = readl(sckcr);
|
||||
|
||||
if (tmp & AT91_SCKC_OSC32BYP)
|
||||
return;
|
||||
|
||||
writel(tmp & ~AT91_SCKC_OSC32EN, sckcr);
|
||||
}
|
||||
|
||||
static int clk_slow_osc_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_slow_osc *osc = to_clk_slow_osc(hw);
|
||||
void __iomem *sckcr = osc->sckcr;
|
||||
u32 tmp = readl(sckcr);
|
||||
|
||||
if (tmp & AT91_SCKC_OSC32BYP)
|
||||
return 1;
|
||||
|
||||
return !!(tmp & AT91_SCKC_OSC32EN);
|
||||
}
|
||||
|
||||
static const struct clk_ops slow_osc_ops = {
|
||||
.prepare = clk_slow_osc_prepare,
|
||||
.unprepare = clk_slow_osc_unprepare,
|
||||
.is_prepared = clk_slow_osc_is_prepared,
|
||||
};
|
||||
|
||||
static struct clk_hw * __init
|
||||
at91_clk_register_slow_osc(void __iomem *sckcr,
|
||||
const char *name,
|
||||
const char *parent_name,
|
||||
unsigned long startup,
|
||||
bool bypass)
|
||||
{
|
||||
struct clk_slow_osc *osc;
|
||||
struct clk_hw *hw;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
|
||||
if (!sckcr || !name || !parent_name)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
osc = kzalloc(sizeof(*osc), GFP_KERNEL);
|
||||
if (!osc)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &slow_osc_ops;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
init.flags = CLK_IGNORE_UNUSED;
|
||||
|
||||
osc->hw.init = &init;
|
||||
osc->sckcr = sckcr;
|
||||
osc->startup_usec = startup;
|
||||
|
||||
if (bypass)
|
||||
writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP,
|
||||
sckcr);
|
||||
|
||||
hw = &osc->hw;
|
||||
ret = clk_hw_register(NULL, &osc->hw);
|
||||
if (ret) {
|
||||
kfree(osc);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
static void __init
|
||||
of_at91sam9x5_clk_slow_osc_setup(struct device_node *np, void __iomem *sckcr)
|
||||
{
|
||||
struct clk_hw *hw;
|
||||
const char *parent_name;
|
||||
const char *name = np->name;
|
||||
u32 startup;
|
||||
bool bypass;
|
||||
|
||||
parent_name = of_clk_get_parent_name(np, 0);
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
of_property_read_u32(np, "atmel,startup-time-usec", &startup);
|
||||
bypass = of_property_read_bool(np, "atmel,osc-bypass");
|
||||
|
||||
hw = at91_clk_register_slow_osc(sckcr, name, parent_name, startup,
|
||||
bypass);
|
||||
if (IS_ERR(hw))
|
||||
return;
|
||||
|
||||
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
|
||||
static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
|
||||
|
||||
return osc->frequency;
|
||||
}
|
||||
|
||||
static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw,
|
||||
unsigned long parent_acc)
|
||||
{
|
||||
struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
|
||||
|
||||
return osc->accuracy;
|
||||
}
|
||||
|
||||
static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
|
||||
void __iomem *sckcr = osc->sckcr;
|
||||
|
||||
writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr);
|
||||
|
||||
usleep_range(osc->startup_usec, osc->startup_usec + 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_slow_rc_osc_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
|
||||
void __iomem *sckcr = osc->sckcr;
|
||||
|
||||
writel(readl(sckcr) & ~AT91_SCKC_RCEN, sckcr);
|
||||
}
|
||||
|
||||
static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
|
||||
|
||||
return !!(readl(osc->sckcr) & AT91_SCKC_RCEN);
|
||||
}
|
||||
|
||||
static const struct clk_ops slow_rc_osc_ops = {
|
||||
.prepare = clk_slow_rc_osc_prepare,
|
||||
.unprepare = clk_slow_rc_osc_unprepare,
|
||||
.is_prepared = clk_slow_rc_osc_is_prepared,
|
||||
.recalc_rate = clk_slow_rc_osc_recalc_rate,
|
||||
.recalc_accuracy = clk_slow_rc_osc_recalc_accuracy,
|
||||
};
|
||||
|
||||
static struct clk_hw * __init
|
||||
at91_clk_register_slow_rc_osc(void __iomem *sckcr,
|
||||
const char *name,
|
||||
unsigned long frequency,
|
||||
unsigned long accuracy,
|
||||
unsigned long startup)
|
||||
{
|
||||
struct clk_slow_rc_osc *osc;
|
||||
struct clk_hw *hw;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
|
||||
if (!sckcr || !name)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
osc = kzalloc(sizeof(*osc), GFP_KERNEL);
|
||||
if (!osc)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &slow_rc_osc_ops;
|
||||
init.parent_names = NULL;
|
||||
init.num_parents = 0;
|
||||
init.flags = CLK_IGNORE_UNUSED;
|
||||
|
||||
osc->hw.init = &init;
|
||||
osc->sckcr = sckcr;
|
||||
osc->frequency = frequency;
|
||||
osc->accuracy = accuracy;
|
||||
osc->startup_usec = startup;
|
||||
|
||||
hw = &osc->hw;
|
||||
ret = clk_hw_register(NULL, &osc->hw);
|
||||
if (ret) {
|
||||
kfree(osc);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
static void __init
|
||||
of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np, void __iomem *sckcr)
|
||||
{
|
||||
struct clk_hw *hw;
|
||||
u32 frequency = 0;
|
||||
u32 accuracy = 0;
|
||||
u32 startup = 0;
|
||||
const char *name = np->name;
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
of_property_read_u32(np, "clock-frequency", &frequency);
|
||||
of_property_read_u32(np, "clock-accuracy", &accuracy);
|
||||
of_property_read_u32(np, "atmel,startup-time-usec", &startup);
|
||||
|
||||
hw = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy,
|
||||
startup);
|
||||
if (IS_ERR(hw))
|
||||
return;
|
||||
|
||||
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
|
||||
static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
|
||||
void __iomem *sckcr = slowck->sckcr;
|
||||
u32 tmp;
|
||||
|
||||
if (index > 1)
|
||||
return -EINVAL;
|
||||
|
||||
tmp = readl(sckcr);
|
||||
|
||||
if ((!index && !(tmp & AT91_SCKC_OSCSEL)) ||
|
||||
(index && (tmp & AT91_SCKC_OSCSEL)))
|
||||
return 0;
|
||||
|
||||
if (index)
|
||||
tmp |= AT91_SCKC_OSCSEL;
|
||||
else
|
||||
tmp &= ~AT91_SCKC_OSCSEL;
|
||||
|
||||
writel(tmp, sckcr);
|
||||
|
||||
usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
|
||||
|
||||
return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL);
|
||||
}
|
||||
|
||||
static const struct clk_ops sam9x5_slow_ops = {
|
||||
.set_parent = clk_sam9x5_slow_set_parent,
|
||||
.get_parent = clk_sam9x5_slow_get_parent,
|
||||
};
|
||||
|
||||
static struct clk_hw * __init
|
||||
at91_clk_register_sam9x5_slow(void __iomem *sckcr,
|
||||
const char *name,
|
||||
const char **parent_names,
|
||||
int num_parents)
|
||||
{
|
||||
struct clk_sam9x5_slow *slowck;
|
||||
struct clk_hw *hw;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
|
||||
if (!sckcr || !name || !parent_names || !num_parents)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
|
||||
if (!slowck)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &sam9x5_slow_ops;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
init.flags = 0;
|
||||
|
||||
slowck->hw.init = &init;
|
||||
slowck->sckcr = sckcr;
|
||||
slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL);
|
||||
|
||||
hw = &slowck->hw;
|
||||
ret = clk_hw_register(NULL, &slowck->hw);
|
||||
if (ret) {
|
||||
kfree(slowck);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
static void __init
|
||||
of_at91sam9x5_clk_slow_setup(struct device_node *np, void __iomem *sckcr)
|
||||
{
|
||||
struct clk_hw *hw;
|
||||
const char *parent_names[2];
|
||||
unsigned int num_parents;
|
||||
const char *name = np->name;
|
||||
|
||||
num_parents = of_clk_get_parent_count(np);
|
||||
if (num_parents == 0 || num_parents > 2)
|
||||
return;
|
||||
|
||||
of_clk_parent_fill(np, parent_names, num_parents);
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
|
||||
hw = at91_clk_register_sam9x5_slow(sckcr, name, parent_names,
|
||||
num_parents);
|
||||
if (IS_ERR(hw))
|
||||
return;
|
||||
|
||||
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
|
||||
static const struct of_device_id sckc_clk_ids[] __initconst = {
|
||||
/* Slow clock */
|
||||
@ -55,3 +426,94 @@ static void __init of_at91sam9x5_sckc_setup(struct device_node *np)
|
||||
}
|
||||
CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc",
|
||||
of_at91sam9x5_sckc_setup);
|
||||
|
||||
static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
|
||||
|
||||
if (osc->prepared)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Assume that if it has already been selected (for example by the
|
||||
* bootloader), enough time has aready passed.
|
||||
*/
|
||||
if ((readl(osc->sckcr) & AT91_SCKC_OSCSEL)) {
|
||||
osc->prepared = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
usleep_range(osc->startup_usec, osc->startup_usec + 1);
|
||||
osc->prepared = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_sama5d4_slow_osc_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
|
||||
|
||||
return osc->prepared;
|
||||
}
|
||||
|
||||
static const struct clk_ops sama5d4_slow_osc_ops = {
|
||||
.prepare = clk_sama5d4_slow_osc_prepare,
|
||||
.is_prepared = clk_sama5d4_slow_osc_is_prepared,
|
||||
};
|
||||
|
||||
static void __init of_sama5d4_sckc_setup(struct device_node *np)
|
||||
{
|
||||
void __iomem *regbase = of_iomap(np, 0);
|
||||
struct clk_hw *hw;
|
||||
struct clk_sama5d4_slow_osc *osc;
|
||||
struct clk_init_data init;
|
||||
const char *xtal_name;
|
||||
const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
|
||||
bool bypass;
|
||||
int ret;
|
||||
|
||||
if (!regbase)
|
||||
return;
|
||||
|
||||
hw = clk_hw_register_fixed_rate_with_accuracy(NULL, parent_names[0],
|
||||
NULL, 0, 32768,
|
||||
250000000);
|
||||
if (IS_ERR(hw))
|
||||
return;
|
||||
|
||||
xtal_name = of_clk_get_parent_name(np, 0);
|
||||
|
||||
bypass = of_property_read_bool(np, "atmel,osc-bypass");
|
||||
|
||||
osc = kzalloc(sizeof(*osc), GFP_KERNEL);
|
||||
if (!osc)
|
||||
return;
|
||||
|
||||
init.name = parent_names[1];
|
||||
init.ops = &sama5d4_slow_osc_ops;
|
||||
init.parent_names = &xtal_name;
|
||||
init.num_parents = 1;
|
||||
init.flags = CLK_IGNORE_UNUSED;
|
||||
|
||||
osc->hw.init = &init;
|
||||
osc->sckcr = regbase;
|
||||
osc->startup_usec = 1200000;
|
||||
|
||||
if (bypass)
|
||||
writel((readl(regbase) | AT91_SCKC_OSC32BYP), regbase);
|
||||
|
||||
hw = &osc->hw;
|
||||
ret = clk_hw_register(NULL, &osc->hw);
|
||||
if (ret) {
|
||||
kfree(osc);
|
||||
return;
|
||||
}
|
||||
|
||||
hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2);
|
||||
if (IS_ERR(hw))
|
||||
return;
|
||||
|
||||
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
CLK_OF_DECLARE(sama5d4_clk_sckc, "atmel,sama5d4-sckc",
|
||||
of_sama5d4_sckc_setup);
|
||||
|
@ -1,22 +0,0 @@
|
||||
/*
|
||||
* drivers/clk/at91/sckc.h
|
||||
*
|
||||
* Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef __AT91_SCKC_H_
|
||||
#define __AT91_SCKC_H_
|
||||
|
||||
extern void __init of_at91sam9x5_clk_slow_osc_setup(struct device_node *np,
|
||||
void __iomem *sckcr);
|
||||
extern void __init of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np,
|
||||
void __iomem *sckcr);
|
||||
extern void __init of_at91sam9x5_clk_slow_setup(struct device_node *np,
|
||||
void __iomem *sckcr);
|
||||
|
||||
#endif /* __AT91_SCKC_H_ */
|
@ -113,7 +113,7 @@ static void of_artpec6_clkctrl_setup(struct device_node *np)
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clkdata->clk_data);
|
||||
}
|
||||
|
||||
CLK_OF_DECLARE(artpec6_clkctrl, "axis,artpec6-clkctrl",
|
||||
CLK_OF_DECLARE_DRIVER(artpec6_clkctrl, "axis,artpec6-clkctrl",
|
||||
of_artpec6_clkctrl_setup);
|
||||
|
||||
static int artpec6_clkctrl_probe(struct platform_device *pdev)
|
||||
|
@ -19,8 +19,36 @@ config CLK_BCM_KONA
|
||||
in the BCM281xx and BCM21664 families.
|
||||
|
||||
config COMMON_CLK_IPROC
|
||||
bool
|
||||
bool "Broadcom iProc clock support"
|
||||
depends on ARCH_BCM_IPROC || COMPILE_TEST
|
||||
depends on COMMON_CLK
|
||||
default ARCH_BCM_IPROC
|
||||
help
|
||||
Enable common clock framework support for Broadcom SoCs
|
||||
based on the iProc architecture
|
||||
|
||||
if COMMON_CLK_IPROC
|
||||
|
||||
config CLK_BCM_CYGNUS
|
||||
bool "Broadcom Cygnus clock support"
|
||||
depends on ARCH_BCM_CYGNUS || COMPILE_TEST
|
||||
default ARCH_BCM_CYGNUS
|
||||
help
|
||||
Enable common clock framework support for the Broadcom Cygnus SoC
|
||||
|
||||
config CLK_BCM_NSP
|
||||
bool "Broadcom Northstar/Northstar Plus clock support"
|
||||
depends on ARCH_BCM_5301X || ARCH_BCM_NSP || COMPILE_TEST
|
||||
default ARCH_BCM_5301X || ARCH_BCM_NSP
|
||||
help
|
||||
Enable common clock framework support for the Broadcom Northstar and
|
||||
Northstar Plus SoCs
|
||||
|
||||
config CLK_BCM_NS2
|
||||
bool "Broadcom Northstar 2 clock support"
|
||||
depends on ARCH_BCM_IPROC || COMPILE_TEST
|
||||
default ARCH_BCM_IPROC
|
||||
help
|
||||
Enable common clock framework support for the Broadcom Northstar 2 SoC
|
||||
|
||||
endif
|
||||
|
@ -6,7 +6,7 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
|
||||
obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
|
||||
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
|
||||
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835-aux.o
|
||||
obj-$(CONFIG_COMMON_CLK_IPROC) += clk-ns2.o
|
||||
obj-$(CONFIG_ARCH_BCM_CYGNUS) += clk-cygnus.o
|
||||
obj-$(CONFIG_ARCH_BCM_NSP) += clk-nsp.o
|
||||
obj-$(CONFIG_ARCH_BCM_5301X) += clk-nsp.o
|
||||
obj-$(CONFIG_ARCH_BCM_53573) += clk-bcm53573-ilp.o
|
||||
obj-$(CONFIG_CLK_BCM_CYGNUS) += clk-cygnus.o
|
||||
obj-$(CONFIG_CLK_BCM_NSP) += clk-nsp.o
|
||||
obj-$(CONFIG_CLK_BCM_NS2) += clk-ns2.o
|
||||
|
@ -25,7 +25,7 @@
|
||||
static int bcm2835_aux_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct clk_onecell_data *onecell;
|
||||
struct clk_hw_onecell_data *onecell;
|
||||
const char *parent;
|
||||
struct clk *parent_clk;
|
||||
struct resource *res;
|
||||
@ -41,28 +41,24 @@ static int bcm2835_aux_clk_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(reg))
|
||||
return PTR_ERR(reg);
|
||||
|
||||
onecell = devm_kmalloc(dev, sizeof(*onecell), GFP_KERNEL);
|
||||
onecell = devm_kmalloc(dev, sizeof(*onecell) + sizeof(*onecell->hws) *
|
||||
BCM2835_AUX_CLOCK_COUNT, GFP_KERNEL);
|
||||
if (!onecell)
|
||||
return -ENOMEM;
|
||||
onecell->clk_num = BCM2835_AUX_CLOCK_COUNT;
|
||||
onecell->clks = devm_kcalloc(dev, BCM2835_AUX_CLOCK_COUNT,
|
||||
sizeof(*onecell->clks), GFP_KERNEL);
|
||||
if (!onecell->clks)
|
||||
return -ENOMEM;
|
||||
onecell->num = BCM2835_AUX_CLOCK_COUNT;
|
||||
|
||||
gate = reg + BCM2835_AUXENB;
|
||||
onecell->clks[BCM2835_AUX_CLOCK_UART] =
|
||||
clk_register_gate(dev, "aux_uart", parent, 0, gate, 0, 0, NULL);
|
||||
onecell->hws[BCM2835_AUX_CLOCK_UART] =
|
||||
clk_hw_register_gate(dev, "aux_uart", parent, 0, gate, 0, 0, NULL);
|
||||
|
||||
onecell->clks[BCM2835_AUX_CLOCK_SPI1] =
|
||||
clk_register_gate(dev, "aux_spi1", parent, 0, gate, 1, 0, NULL);
|
||||
onecell->hws[BCM2835_AUX_CLOCK_SPI1] =
|
||||
clk_hw_register_gate(dev, "aux_spi1", parent, 0, gate, 1, 0, NULL);
|
||||
|
||||
onecell->clks[BCM2835_AUX_CLOCK_SPI2] =
|
||||
clk_register_gate(dev, "aux_spi2", parent, 0, gate, 2, 0, NULL);
|
||||
onecell->hws[BCM2835_AUX_CLOCK_SPI2] =
|
||||
clk_hw_register_gate(dev, "aux_spi2", parent, 0, gate, 2, 0, NULL);
|
||||
|
||||
of_clk_add_provider(pdev->dev.of_node, of_clk_src_onecell_get, onecell);
|
||||
|
||||
return 0;
|
||||
return of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get,
|
||||
onecell);
|
||||
}
|
||||
|
||||
static const struct of_device_id bcm2835_aux_clk_of_match[] = {
|
||||
|
@ -36,6 +36,7 @@
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk/bcm2835.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/module.h>
|
||||
@ -302,8 +303,8 @@ struct bcm2835_cprman {
|
||||
spinlock_t regs_lock; /* spinlock for all clocks */
|
||||
const char *osc_name;
|
||||
|
||||
struct clk_onecell_data onecell;
|
||||
struct clk *clks[];
|
||||
/* Must be last */
|
||||
struct clk_hw_onecell_data onecell;
|
||||
};
|
||||
|
||||
static inline void cprman_write(struct bcm2835_cprman *cprman, u32 reg, u32 val)
|
||||
@ -344,24 +345,24 @@ static int bcm2835_debugfs_regset(struct bcm2835_cprman *cprman, u32 base,
|
||||
*/
|
||||
void __init bcm2835_init_clocks(void)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
int ret;
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, 0, 126000000);
|
||||
if (IS_ERR(clk))
|
||||
hw = clk_hw_register_fixed_rate(NULL, "apb_pclk", NULL, 0, 126000000);
|
||||
if (IS_ERR(hw))
|
||||
pr_err("apb_pclk not registered\n");
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "uart0_pclk", NULL, 0, 3000000);
|
||||
if (IS_ERR(clk))
|
||||
hw = clk_hw_register_fixed_rate(NULL, "uart0_pclk", NULL, 0, 3000000);
|
||||
if (IS_ERR(hw))
|
||||
pr_err("uart0_pclk not registered\n");
|
||||
ret = clk_register_clkdev(clk, NULL, "20201000.uart");
|
||||
ret = clk_hw_register_clkdev(hw, NULL, "20201000.uart");
|
||||
if (ret)
|
||||
pr_err("uart0_pclk alias not registered\n");
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "uart1_pclk", NULL, 0, 125000000);
|
||||
if (IS_ERR(clk))
|
||||
hw = clk_hw_register_fixed_rate(NULL, "uart1_pclk", NULL, 0, 125000000);
|
||||
if (IS_ERR(hw))
|
||||
pr_err("uart1_pclk not registered\n");
|
||||
ret = clk_register_clkdev(clk, NULL, "20215000.uart");
|
||||
ret = clk_hw_register_clkdev(hw, NULL, "20215000.uart");
|
||||
if (ret)
|
||||
pr_err("uart1_pclk alias not registered\n");
|
||||
}
|
||||
@ -443,6 +444,8 @@ struct bcm2835_clock_data {
|
||||
/* Number of fractional bits in the divider */
|
||||
u32 frac_bits;
|
||||
|
||||
u32 flags;
|
||||
|
||||
bool is_vpu_clock;
|
||||
bool is_mash_clock;
|
||||
};
|
||||
@ -1006,16 +1009,28 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
bcm2835_clk_is_pllc(struct clk_hw *hw)
|
||||
{
|
||||
if (!hw)
|
||||
return false;
|
||||
|
||||
return strncmp(clk_hw_get_name(hw), "pllc", 4) == 0;
|
||||
}
|
||||
|
||||
static int bcm2835_clock_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
|
||||
struct clk_hw *parent, *best_parent = NULL;
|
||||
bool current_parent_is_pllc;
|
||||
unsigned long rate, best_rate = 0;
|
||||
unsigned long prate, best_prate = 0;
|
||||
size_t i;
|
||||
u32 div;
|
||||
|
||||
current_parent_is_pllc = bcm2835_clk_is_pllc(clk_hw_get_parent(hw));
|
||||
|
||||
/*
|
||||
* Select parent clock that results in the closest but lower rate
|
||||
*/
|
||||
@ -1023,6 +1038,17 @@ static int bcm2835_clock_determine_rate(struct clk_hw *hw,
|
||||
parent = clk_hw_get_parent_by_index(hw, i);
|
||||
if (!parent)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Don't choose a PLLC-derived clock as our parent
|
||||
* unless it had been manually set that way. PLLC's
|
||||
* frequency gets adjusted by the firmware due to
|
||||
* over-temp or under-voltage conditions, without
|
||||
* prior notification to our clock consumer.
|
||||
*/
|
||||
if (bcm2835_clk_is_pllc(parent) && !current_parent_is_pllc)
|
||||
continue;
|
||||
|
||||
prate = clk_hw_get_rate(parent);
|
||||
div = bcm2835_clock_choose_div(hw, req->rate, prate, true);
|
||||
rate = bcm2835_clock_rate_from_divisor(clock, prate, div);
|
||||
@ -1121,11 +1147,12 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = {
|
||||
.debug_init = bcm2835_clock_debug_init,
|
||||
};
|
||||
|
||||
static struct clk *bcm2835_register_pll(struct bcm2835_cprman *cprman,
|
||||
static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman,
|
||||
const struct bcm2835_pll_data *data)
|
||||
{
|
||||
struct bcm2835_pll *pll;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
|
||||
memset(&init, 0, sizeof(init));
|
||||
|
||||
@ -1144,17 +1171,20 @@ static struct clk *bcm2835_register_pll(struct bcm2835_cprman *cprman,
|
||||
pll->data = data;
|
||||
pll->hw.init = &init;
|
||||
|
||||
return devm_clk_register(cprman->dev, &pll->hw);
|
||||
ret = devm_clk_hw_register(cprman->dev, &pll->hw);
|
||||
if (ret)
|
||||
return NULL;
|
||||
return &pll->hw;
|
||||
}
|
||||
|
||||
static struct clk *
|
||||
static struct clk_hw *
|
||||
bcm2835_register_pll_divider(struct bcm2835_cprman *cprman,
|
||||
const struct bcm2835_pll_divider_data *data)
|
||||
{
|
||||
struct bcm2835_pll_divider *divider;
|
||||
struct clk_init_data init;
|
||||
struct clk *clk;
|
||||
const char *divider_name;
|
||||
int ret;
|
||||
|
||||
if (data->fixed_divider != 1) {
|
||||
divider_name = devm_kasprintf(cprman->dev, GFP_KERNEL,
|
||||
@ -1188,32 +1218,33 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman,
|
||||
divider->cprman = cprman;
|
||||
divider->data = data;
|
||||
|
||||
clk = devm_clk_register(cprman->dev, ÷r->div.hw);
|
||||
if (IS_ERR(clk))
|
||||
return clk;
|
||||
ret = devm_clk_hw_register(cprman->dev, ÷r->div.hw);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
/*
|
||||
* PLLH's channels have a fixed divide by 10 afterwards, which
|
||||
* is what our consumers are actually using.
|
||||
*/
|
||||
if (data->fixed_divider != 1) {
|
||||
return clk_register_fixed_factor(cprman->dev, data->name,
|
||||
return clk_hw_register_fixed_factor(cprman->dev, data->name,
|
||||
divider_name,
|
||||
CLK_SET_RATE_PARENT,
|
||||
1,
|
||||
data->fixed_divider);
|
||||
}
|
||||
|
||||
return clk;
|
||||
return ÷r->div.hw;
|
||||
}
|
||||
|
||||
static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman,
|
||||
static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
|
||||
const struct bcm2835_clock_data *data)
|
||||
{
|
||||
struct bcm2835_clock *clock;
|
||||
struct clk_init_data init;
|
||||
const char *parents[1 << CM_SRC_BITS];
|
||||
size_t i;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Replace our "xosc" references with the oscillator's
|
||||
@ -1230,13 +1261,19 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman,
|
||||
init.parent_names = parents;
|
||||
init.num_parents = data->num_mux_parents;
|
||||
init.name = data->name;
|
||||
init.flags = CLK_IGNORE_UNUSED;
|
||||
init.flags = data->flags | CLK_IGNORE_UNUSED;
|
||||
|
||||
if (data->is_vpu_clock) {
|
||||
init.ops = &bcm2835_vpu_clock_clk_ops;
|
||||
} else {
|
||||
init.ops = &bcm2835_clock_clk_ops;
|
||||
init.flags |= CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
|
||||
|
||||
/* If the clock wasn't actually enabled at boot, it's not
|
||||
* critical.
|
||||
*/
|
||||
if (!(cprman_read(cprman, data->ctl_reg) & CM_ENABLE))
|
||||
init.flags &= ~CLK_IS_CRITICAL;
|
||||
}
|
||||
|
||||
clock = devm_kzalloc(cprman->dev, sizeof(*clock), GFP_KERNEL);
|
||||
@ -1247,7 +1284,10 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman,
|
||||
clock->data = data;
|
||||
clock->hw.init = &init;
|
||||
|
||||
return devm_clk_register(cprman->dev, &clock->hw);
|
||||
ret = devm_clk_hw_register(cprman->dev, &clock->hw);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
return &clock->hw;
|
||||
}
|
||||
|
||||
static struct clk *bcm2835_register_gate(struct bcm2835_cprman *cprman,
|
||||
@ -1259,7 +1299,7 @@ static struct clk *bcm2835_register_gate(struct bcm2835_cprman *cprman,
|
||||
CM_GATE_BIT, 0, &cprman->regs_lock);
|
||||
}
|
||||
|
||||
typedef struct clk *(*bcm2835_clk_register)(struct bcm2835_cprman *cprman,
|
||||
typedef struct clk_hw *(*bcm2835_clk_register)(struct bcm2835_cprman *cprman,
|
||||
const void *data);
|
||||
struct bcm2835_clk_desc {
|
||||
bcm2835_clk_register clk_register;
|
||||
@ -1649,6 +1689,7 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
|
||||
.div_reg = CM_VPUDIV,
|
||||
.int_bits = 12,
|
||||
.frac_bits = 8,
|
||||
.flags = CLK_IS_CRITICAL,
|
||||
.is_vpu_clock = true),
|
||||
|
||||
/* clocks with per parent mux */
|
||||
@ -1705,13 +1746,15 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
|
||||
.div_reg = CM_GP1DIV,
|
||||
.int_bits = 12,
|
||||
.frac_bits = 12,
|
||||
.flags = CLK_IS_CRITICAL,
|
||||
.is_mash_clock = true),
|
||||
[BCM2835_CLOCK_GP2] = REGISTER_PER_CLK(
|
||||
.name = "gp2",
|
||||
.ctl_reg = CM_GP2CTL,
|
||||
.div_reg = CM_GP2DIV,
|
||||
.int_bits = 12,
|
||||
.frac_bits = 12),
|
||||
.frac_bits = 12,
|
||||
.flags = CLK_IS_CRITICAL),
|
||||
|
||||
/* HDMI state machine */
|
||||
[BCM2835_CLOCK_HSM] = REGISTER_PER_CLK(
|
||||
@ -1790,18 +1833,38 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
|
||||
.ctl_reg = CM_PERIICTL),
|
||||
};
|
||||
|
||||
/*
|
||||
* Permanently take a reference on the parent of the SDRAM clock.
|
||||
*
|
||||
* While the SDRAM is being driven by its dedicated PLL most of the
|
||||
* time, there is a little loop running in the firmware that
|
||||
* periodically switches the SDRAM to using our CM clock to do PVT
|
||||
* recalibration, with the assumption that the previously configured
|
||||
* SDRAM parent is still enabled and running.
|
||||
*/
|
||||
static int bcm2835_mark_sdc_parent_critical(struct clk *sdc)
|
||||
{
|
||||
struct clk *parent = clk_get_parent(sdc);
|
||||
|
||||
if (IS_ERR(parent))
|
||||
return PTR_ERR(parent);
|
||||
|
||||
return clk_prepare_enable(parent);
|
||||
}
|
||||
|
||||
static int bcm2835_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct clk **clks;
|
||||
struct clk_hw **hws;
|
||||
struct bcm2835_cprman *cprman;
|
||||
struct resource *res;
|
||||
const struct bcm2835_clk_desc *desc;
|
||||
const size_t asize = ARRAY_SIZE(clk_desc_array);
|
||||
size_t i;
|
||||
int ret;
|
||||
|
||||
cprman = devm_kzalloc(dev,
|
||||
sizeof(*cprman) + asize * sizeof(*clks),
|
||||
cprman = devm_kzalloc(dev, sizeof(*cprman) +
|
||||
sizeof(*cprman->onecell.hws) * asize,
|
||||
GFP_KERNEL);
|
||||
if (!cprman)
|
||||
return -ENOMEM;
|
||||
@ -1819,17 +1882,20 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, cprman);
|
||||
|
||||
cprman->onecell.clk_num = asize;
|
||||
cprman->onecell.clks = cprman->clks;
|
||||
clks = cprman->clks;
|
||||
cprman->onecell.num = asize;
|
||||
hws = cprman->onecell.hws;
|
||||
|
||||
for (i = 0; i < asize; i++) {
|
||||
desc = &clk_desc_array[i];
|
||||
if (desc->clk_register && desc->data)
|
||||
clks[i] = desc->clk_register(cprman, desc->data);
|
||||
hws[i] = desc->clk_register(cprman, desc->data);
|
||||
}
|
||||
|
||||
return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
|
||||
ret = bcm2835_mark_sdc_parent_critical(hws[BCM2835_CLOCK_SDRAM]->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
|
||||
&cprman->onecell);
|
||||
}
|
||||
|
||||
|
148
drivers/clk/bcm/clk-bcm53573-ilp.c
Normal file
148
drivers/clk/bcm/clk-bcm53573-ilp.c
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Rafał Miłecki <rafal@milecki.pl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define PMU_XTAL_FREQ_RATIO 0x66c
|
||||
#define XTAL_ALP_PER_4ILP 0x00001fff
|
||||
#define XTAL_CTL_EN 0x80000000
|
||||
#define PMU_SLOW_CLK_PERIOD 0x6dc
|
||||
|
||||
struct bcm53573_ilp {
|
||||
struct clk_hw hw;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static int bcm53573_ilp_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct bcm53573_ilp *ilp = container_of(hw, struct bcm53573_ilp, hw);
|
||||
|
||||
regmap_write(ilp->regmap, PMU_SLOW_CLK_PERIOD, 0x10199);
|
||||
regmap_write(ilp->regmap, 0x674, 0x10000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bcm53573_ilp_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct bcm53573_ilp *ilp = container_of(hw, struct bcm53573_ilp, hw);
|
||||
|
||||
regmap_write(ilp->regmap, PMU_SLOW_CLK_PERIOD, 0);
|
||||
regmap_write(ilp->regmap, 0x674, 0);
|
||||
}
|
||||
|
||||
static unsigned long bcm53573_ilp_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct bcm53573_ilp *ilp = container_of(hw, struct bcm53573_ilp, hw);
|
||||
struct regmap *regmap = ilp->regmap;
|
||||
u32 last_val, cur_val;
|
||||
int sum = 0, num = 0, loop_num = 0;
|
||||
int avg;
|
||||
|
||||
/* Enable measurement */
|
||||
regmap_write(regmap, PMU_XTAL_FREQ_RATIO, XTAL_CTL_EN);
|
||||
|
||||
/* Read initial value */
|
||||
regmap_read(regmap, PMU_XTAL_FREQ_RATIO, &last_val);
|
||||
last_val &= XTAL_ALP_PER_4ILP;
|
||||
|
||||
/*
|
||||
* At minimum we should loop for a bit to let hardware do the
|
||||
* measurement. This isn't very accurate however, so for a better
|
||||
* precision lets try getting 20 different values for and use average.
|
||||
*/
|
||||
while (num < 20) {
|
||||
regmap_read(regmap, PMU_XTAL_FREQ_RATIO, &cur_val);
|
||||
cur_val &= XTAL_ALP_PER_4ILP;
|
||||
|
||||
if (cur_val != last_val) {
|
||||
/* Got different value, use it */
|
||||
sum += cur_val;
|
||||
num++;
|
||||
loop_num = 0;
|
||||
last_val = cur_val;
|
||||
} else if (++loop_num > 5000) {
|
||||
/* Same value over and over, give up */
|
||||
sum += cur_val;
|
||||
num++;
|
||||
break;
|
||||
}
|
||||
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
/* Disable measurement to save power */
|
||||
regmap_write(regmap, PMU_XTAL_FREQ_RATIO, 0x0);
|
||||
|
||||
avg = sum / num;
|
||||
|
||||
return parent_rate * 4 / avg;
|
||||
}
|
||||
|
||||
static const struct clk_ops bcm53573_ilp_clk_ops = {
|
||||
.enable = bcm53573_ilp_enable,
|
||||
.disable = bcm53573_ilp_disable,
|
||||
.recalc_rate = bcm53573_ilp_recalc_rate,
|
||||
};
|
||||
|
||||
static void bcm53573_ilp_init(struct device_node *np)
|
||||
{
|
||||
struct bcm53573_ilp *ilp;
|
||||
struct clk_init_data init = { };
|
||||
const char *parent_name;
|
||||
int err;
|
||||
|
||||
ilp = kzalloc(sizeof(*ilp), GFP_KERNEL);
|
||||
if (!ilp)
|
||||
return;
|
||||
|
||||
parent_name = of_clk_get_parent_name(np, 0);
|
||||
if (!parent_name) {
|
||||
err = -ENOENT;
|
||||
goto err_free_ilp;
|
||||
}
|
||||
|
||||
ilp->regmap = syscon_node_to_regmap(of_get_parent(np));
|
||||
if (IS_ERR(ilp->regmap)) {
|
||||
err = PTR_ERR(ilp->regmap);
|
||||
goto err_free_ilp;
|
||||
}
|
||||
|
||||
init.name = np->name;
|
||||
init.ops = &bcm53573_ilp_clk_ops;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
|
||||
ilp->hw.init = &init;
|
||||
err = clk_hw_register(NULL, &ilp->hw);
|
||||
if (err)
|
||||
goto err_free_ilp;
|
||||
|
||||
err = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &ilp->hw);
|
||||
if (err)
|
||||
goto err_clk_hw_unregister;
|
||||
|
||||
return;
|
||||
|
||||
err_clk_hw_unregister:
|
||||
clk_hw_unregister(&ilp->hw);
|
||||
err_free_ilp:
|
||||
kfree(ilp);
|
||||
pr_err("Failed to init ILP clock: %d\n", err);
|
||||
}
|
||||
|
||||
/* We need it very early for arch code, before device model gets ready */
|
||||
CLK_OF_DECLARE(bcm53573_ilp_clk, "brcm,bcm53573-ilp", bcm53573_ilp_init);
|
@ -586,8 +586,8 @@ static u32 *parent_process(const char *clocks[],
|
||||
}
|
||||
|
||||
/* There is at least one parent, so allocate a selector array */
|
||||
|
||||
parent_sel = kmalloc(parent_count * sizeof(*parent_sel), GFP_KERNEL);
|
||||
parent_sel = kmalloc_array(parent_count, sizeof(*parent_sel),
|
||||
GFP_KERNEL);
|
||||
if (!parent_sel) {
|
||||
pr_err("%s: error allocating %u parent selectors\n", __func__,
|
||||
parent_count);
|
||||
@ -696,77 +696,69 @@ static void bcm_clk_teardown(struct kona_clk *bcm_clk)
|
||||
bcm_clk->type = bcm_clk_none;
|
||||
}
|
||||
|
||||
static void kona_clk_teardown(struct clk *clk)
|
||||
static void kona_clk_teardown(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_hw *hw;
|
||||
struct kona_clk *bcm_clk;
|
||||
|
||||
if (!clk)
|
||||
if (!hw)
|
||||
return;
|
||||
|
||||
hw = __clk_get_hw(clk);
|
||||
if (!hw) {
|
||||
pr_err("%s: clk %p has null hw pointer\n", __func__, clk);
|
||||
return;
|
||||
}
|
||||
clk_unregister(clk);
|
||||
clk_hw_unregister(hw);
|
||||
|
||||
bcm_clk = to_kona_clk(hw);
|
||||
bcm_clk_teardown(bcm_clk);
|
||||
}
|
||||
|
||||
struct clk *kona_clk_setup(struct kona_clk *bcm_clk)
|
||||
static int kona_clk_setup(struct kona_clk *bcm_clk)
|
||||
{
|
||||
int ret;
|
||||
struct clk_init_data *init_data = &bcm_clk->init_data;
|
||||
struct clk *clk = NULL;
|
||||
|
||||
switch (bcm_clk->type) {
|
||||
case bcm_clk_peri:
|
||||
if (peri_clk_setup(bcm_clk->u.data, init_data))
|
||||
return NULL;
|
||||
ret = peri_clk_setup(bcm_clk->u.data, init_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
pr_err("%s: clock type %d invalid for %s\n", __func__,
|
||||
(int)bcm_clk->type, init_data->name);
|
||||
return NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Make sure everything makes sense before we set it up */
|
||||
if (!kona_clk_valid(bcm_clk)) {
|
||||
pr_err("%s: clock data invalid for %s\n", __func__,
|
||||
init_data->name);
|
||||
ret = -EINVAL;
|
||||
goto out_teardown;
|
||||
}
|
||||
|
||||
bcm_clk->hw.init = init_data;
|
||||
clk = clk_register(NULL, &bcm_clk->hw);
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err("%s: error registering clock %s (%ld)\n", __func__,
|
||||
init_data->name, PTR_ERR(clk));
|
||||
ret = clk_hw_register(NULL, &bcm_clk->hw);
|
||||
if (ret) {
|
||||
pr_err("%s: error registering clock %s (%d)\n", __func__,
|
||||
init_data->name, ret);
|
||||
goto out_teardown;
|
||||
}
|
||||
BUG_ON(!clk);
|
||||
|
||||
return clk;
|
||||
return 0;
|
||||
out_teardown:
|
||||
bcm_clk_teardown(bcm_clk);
|
||||
|
||||
return NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ccu_clks_teardown(struct ccu_data *ccu)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < ccu->clk_data.clk_num; i++)
|
||||
kona_clk_teardown(ccu->clk_data.clks[i]);
|
||||
kfree(ccu->clk_data.clks);
|
||||
for (i = 0; i < ccu->clk_num; i++)
|
||||
kona_clk_teardown(&ccu->kona_clks[i].hw);
|
||||
}
|
||||
|
||||
static void kona_ccu_teardown(struct ccu_data *ccu)
|
||||
{
|
||||
kfree(ccu->clk_data.clks);
|
||||
ccu->clk_data.clks = NULL;
|
||||
if (!ccu->base)
|
||||
return;
|
||||
|
||||
@ -793,6 +785,20 @@ static bool ccu_data_valid(struct ccu_data *ccu)
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct clk_hw *
|
||||
of_clk_kona_onecell_get(struct of_phandle_args *clkspec, void *data)
|
||||
{
|
||||
struct ccu_data *ccu = data;
|
||||
unsigned int idx = clkspec->args[0];
|
||||
|
||||
if (idx >= ccu->clk_num) {
|
||||
pr_err("%s: invalid index %u\n", __func__, idx);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return &ccu->kona_clks[idx].hw;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up a CCU. Call the provided ccu_clks_setup callback to
|
||||
* initialize the array of clocks provided by the CCU.
|
||||
@ -805,18 +811,6 @@ void __init kona_dt_ccu_setup(struct ccu_data *ccu,
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (ccu->clk_data.clk_num) {
|
||||
size_t size;
|
||||
|
||||
size = ccu->clk_data.clk_num * sizeof(*ccu->clk_data.clks);
|
||||
ccu->clk_data.clks = kzalloc(size, GFP_KERNEL);
|
||||
if (!ccu->clk_data.clks) {
|
||||
pr_err("%s: unable to allocate %u clocks for %s\n",
|
||||
__func__, ccu->clk_data.clk_num, node->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ret = of_address_to_resource(node, 0, &res);
|
||||
if (ret) {
|
||||
pr_err("%s: no valid CCU registers found for %s\n", __func__,
|
||||
@ -851,13 +845,13 @@ void __init kona_dt_ccu_setup(struct ccu_data *ccu,
|
||||
* the clock framework clock array (in ccu->data). Then
|
||||
* register as a provider for these clocks.
|
||||
*/
|
||||
for (i = 0; i < ccu->clk_data.clk_num; i++) {
|
||||
for (i = 0; i < ccu->clk_num; i++) {
|
||||
if (!ccu->kona_clks[i].ccu)
|
||||
continue;
|
||||
ccu->clk_data.clks[i] = kona_clk_setup(&ccu->kona_clks[i]);
|
||||
kona_clk_setup(&ccu->kona_clks[i]);
|
||||
}
|
||||
|
||||
ret = of_clk_add_provider(node, of_clk_src_onecell_get, &ccu->clk_data);
|
||||
ret = of_clk_add_hw_provider(node, of_clk_kona_onecell_get, ccu);
|
||||
if (ret) {
|
||||
pr_err("%s: error adding ccu %s as provider (%d)\n", __func__,
|
||||
node->name, ret);
|
||||
|
@ -1256,19 +1256,18 @@ bool __init kona_ccu_init(struct ccu_data *ccu)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int which;
|
||||
struct clk **clks = ccu->clk_data.clks;
|
||||
struct kona_clk *kona_clks = ccu->kona_clks;
|
||||
bool success = true;
|
||||
|
||||
flags = ccu_lock(ccu);
|
||||
__ccu_write_enable(ccu);
|
||||
|
||||
for (which = 0; which < ccu->clk_data.clk_num; which++) {
|
||||
struct kona_clk *bcm_clk;
|
||||
for (which = 0; which < ccu->clk_num; which++) {
|
||||
struct kona_clk *bcm_clk = &kona_clks[which];
|
||||
|
||||
if (!clks[which])
|
||||
if (!bcm_clk->ccu)
|
||||
continue;
|
||||
bcm_clk = &kona_clks[which];
|
||||
|
||||
success &= __kona_clk_init(bcm_clk);
|
||||
}
|
||||
|
||||
|
@ -481,7 +481,7 @@ struct ccu_data {
|
||||
bool write_enabled; /* write access is currently enabled */
|
||||
struct ccu_policy policy;
|
||||
struct device_node *node;
|
||||
struct clk_onecell_data clk_data;
|
||||
size_t clk_num;
|
||||
const char *name;
|
||||
u32 range; /* byte range of address space */
|
||||
struct kona_clk kona_clks[]; /* must be last */
|
||||
@ -491,9 +491,7 @@ struct ccu_data {
|
||||
#define KONA_CCU_COMMON(_prefix, _name, _ccuname) \
|
||||
.name = #_name "_ccu", \
|
||||
.lock = __SPIN_LOCK_UNLOCKED(_name ## _ccu_data.lock), \
|
||||
.clk_data = { \
|
||||
.clk_num = _prefix ## _ ## _ccuname ## _CCU_CLOCK_COUNT, \
|
||||
}
|
||||
.clk_num = _prefix ## _ ## _ccuname ## _CCU_CLOCK_COUNT
|
||||
|
||||
/* Exported globals */
|
||||
|
||||
@ -505,7 +503,6 @@ extern u64 scaled_div_max(struct bcm_clk_div *div);
|
||||
extern u64 scaled_div_build(struct bcm_clk_div *div, u32 div_value,
|
||||
u32 billionths);
|
||||
|
||||
extern struct clk *kona_clk_setup(struct kona_clk *bcm_clk);
|
||||
extern void __init kona_dt_ccu_setup(struct ccu_data *ccu,
|
||||
struct device_node *node);
|
||||
extern bool __init kona_ccu_init(struct ccu_data *ccu);
|
||||
|
@ -188,7 +188,7 @@ static const struct clk_ops berlin2_avpll_vco_ops = {
|
||||
.recalc_rate = berlin2_avpll_vco_recalc_rate,
|
||||
};
|
||||
|
||||
struct clk * __init berlin2_avpll_vco_register(void __iomem *base,
|
||||
int __init berlin2_avpll_vco_register(void __iomem *base,
|
||||
const char *name, const char *parent_name,
|
||||
u8 vco_flags, unsigned long flags)
|
||||
{
|
||||
@ -197,7 +197,7 @@ struct clk * __init berlin2_avpll_vco_register(void __iomem *base,
|
||||
|
||||
vco = kzalloc(sizeof(*vco), GFP_KERNEL);
|
||||
if (!vco)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return -ENOMEM;
|
||||
|
||||
vco->base = base;
|
||||
vco->flags = vco_flags;
|
||||
@ -208,7 +208,7 @@ struct clk * __init berlin2_avpll_vco_register(void __iomem *base,
|
||||
init.num_parents = 1;
|
||||
init.flags = flags;
|
||||
|
||||
return clk_register(NULL, &vco->hw);
|
||||
return clk_hw_register(NULL, &vco->hw);
|
||||
}
|
||||
|
||||
struct berlin2_avpll_channel {
|
||||
@ -364,7 +364,7 @@ static const struct clk_ops berlin2_avpll_channel_ops = {
|
||||
*/
|
||||
static const u8 quirk_index[] __initconst = { 0, 6, 5, 4, 3, 2, 1, 7 };
|
||||
|
||||
struct clk * __init berlin2_avpll_channel_register(void __iomem *base,
|
||||
int __init berlin2_avpll_channel_register(void __iomem *base,
|
||||
const char *name, u8 index, const char *parent_name,
|
||||
u8 ch_flags, unsigned long flags)
|
||||
{
|
||||
@ -373,7 +373,7 @@ struct clk * __init berlin2_avpll_channel_register(void __iomem *base,
|
||||
|
||||
ch = kzalloc(sizeof(*ch), GFP_KERNEL);
|
||||
if (!ch)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return -ENOMEM;
|
||||
|
||||
ch->base = base;
|
||||
if (ch_flags & BERLIN2_AVPLL_SCRAMBLE_QUIRK)
|
||||
@ -389,5 +389,5 @@ struct clk * __init berlin2_avpll_channel_register(void __iomem *base,
|
||||
init.num_parents = 1;
|
||||
init.flags = flags;
|
||||
|
||||
return clk_register(NULL, &ch->hw);
|
||||
return clk_hw_register(NULL, &ch->hw);
|
||||
}
|
||||
|
@ -19,17 +19,13 @@
|
||||
#ifndef __BERLIN2_AVPLL_H
|
||||
#define __BERLIN2_AVPLL_H
|
||||
|
||||
struct clk;
|
||||
|
||||
#define BERLIN2_AVPLL_BIT_QUIRK BIT(0)
|
||||
#define BERLIN2_AVPLL_SCRAMBLE_QUIRK BIT(1)
|
||||
|
||||
struct clk * __init
|
||||
berlin2_avpll_vco_register(void __iomem *base, const char *name,
|
||||
int berlin2_avpll_vco_register(void __iomem *base, const char *name,
|
||||
const char *parent_name, u8 vco_flags, unsigned long flags);
|
||||
|
||||
struct clk * __init
|
||||
berlin2_avpll_channel_register(void __iomem *base, const char *name,
|
||||
int berlin2_avpll_channel_register(void __iomem *base, const char *name,
|
||||
u8 index, const char *parent_name, u8 ch_flags,
|
||||
unsigned long flags);
|
||||
|
||||
|
@ -234,7 +234,7 @@ static const struct clk_ops berlin2_div_mux_ops = {
|
||||
.get_parent = berlin2_div_get_parent,
|
||||
};
|
||||
|
||||
struct clk * __init
|
||||
struct clk_hw * __init
|
||||
berlin2_div_register(const struct berlin2_div_map *map,
|
||||
void __iomem *base, const char *name, u8 div_flags,
|
||||
const char **parent_names, int num_parents,
|
||||
@ -259,7 +259,7 @@ berlin2_div_register(const struct berlin2_div_map *map,
|
||||
if ((div_flags & BERLIN2_DIV_HAS_MUX) == 0)
|
||||
mux_ops = NULL;
|
||||
|
||||
return clk_register_composite(NULL, name, parent_names, num_parents,
|
||||
return clk_hw_register_composite(NULL, name, parent_names, num_parents,
|
||||
&div->hw, mux_ops, &div->hw, rate_ops,
|
||||
&div->hw, gate_ops, flags);
|
||||
}
|
||||
|
@ -19,7 +19,7 @@
|
||||
#ifndef __BERLIN2_DIV_H
|
||||
#define __BERLIN2_DIV_H
|
||||
|
||||
struct clk;
|
||||
struct clk_hw;
|
||||
|
||||
#define BERLIN2_DIV_HAS_GATE BIT(0)
|
||||
#define BERLIN2_DIV_HAS_MUX BIT(1)
|
||||
@ -80,7 +80,7 @@ struct berlin2_div_data {
|
||||
u8 div_flags;
|
||||
};
|
||||
|
||||
struct clk * __init
|
||||
struct clk_hw *
|
||||
berlin2_div_register(const struct berlin2_div_map *map,
|
||||
void __iomem *base, const char *name, u8 div_flags,
|
||||
const char **parent_names, int num_parents,
|
||||
|
@ -84,7 +84,7 @@ static const struct clk_ops berlin2_pll_ops = {
|
||||
.recalc_rate = berlin2_pll_recalc_rate,
|
||||
};
|
||||
|
||||
struct clk * __init
|
||||
int __init
|
||||
berlin2_pll_register(const struct berlin2_pll_map *map,
|
||||
void __iomem *base, const char *name,
|
||||
const char *parent_name, unsigned long flags)
|
||||
@ -94,7 +94,7 @@ berlin2_pll_register(const struct berlin2_pll_map *map,
|
||||
|
||||
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
|
||||
if (!pll)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return -ENOMEM;
|
||||
|
||||
/* copy pll_map to allow __initconst */
|
||||
memcpy(&pll->map, map, sizeof(*map));
|
||||
@ -106,5 +106,5 @@ berlin2_pll_register(const struct berlin2_pll_map *map,
|
||||
init.num_parents = 1;
|
||||
init.flags = flags;
|
||||
|
||||
return clk_register(NULL, &pll->hw);
|
||||
return clk_hw_register(NULL, &pll->hw);
|
||||
}
|
||||
|
@ -19,8 +19,6 @@
|
||||
#ifndef __BERLIN2_PLL_H
|
||||
#define __BERLIN2_PLL_H
|
||||
|
||||
struct clk;
|
||||
|
||||
struct berlin2_pll_map {
|
||||
const u8 vcodiv[16];
|
||||
u8 mult;
|
||||
@ -29,8 +27,7 @@ struct berlin2_pll_map {
|
||||
u8 divsel_shift;
|
||||
};
|
||||
|
||||
struct clk * __init
|
||||
berlin2_pll_register(const struct berlin2_pll_map *map,
|
||||
int berlin2_pll_register(const struct berlin2_pll_map *map,
|
||||
void __iomem *base, const char *name,
|
||||
const char *parent_name, unsigned long flags);
|
||||
|
||||
|
@ -92,8 +92,7 @@
|
||||
*/
|
||||
|
||||
#define MAX_CLKS 41
|
||||
static struct clk *clks[MAX_CLKS];
|
||||
static struct clk_onecell_data clk_data;
|
||||
static struct clk_hw_onecell_data *clk_data;
|
||||
static DEFINE_SPINLOCK(lock);
|
||||
static void __iomem *gbase;
|
||||
|
||||
@ -505,8 +504,17 @@ static void __init berlin2_clock_setup(struct device_node *np)
|
||||
struct device_node *parent_np = of_get_parent(np);
|
||||
const char *parent_names[9];
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
struct clk_hw **hws;
|
||||
u8 avpll_flags = 0;
|
||||
int n;
|
||||
int n, ret;
|
||||
|
||||
clk_data = kzalloc(sizeof(*clk_data) +
|
||||
sizeof(*clk_data->hws) * MAX_CLKS, GFP_KERNEL);
|
||||
if (!clk_data)
|
||||
return;
|
||||
clk_data->num = MAX_CLKS;
|
||||
hws = clk_data->hws;
|
||||
|
||||
gbase = of_iomap(parent_np, 0);
|
||||
if (!gbase)
|
||||
@ -526,118 +534,118 @@ static void __init berlin2_clock_setup(struct device_node *np)
|
||||
}
|
||||
|
||||
/* simple register PLLs */
|
||||
clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_SYSPLLCTL0,
|
||||
ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_SYSPLLCTL0,
|
||||
clk_names[SYSPLL], clk_names[REFCLK], 0);
|
||||
if (IS_ERR(clk))
|
||||
if (ret)
|
||||
goto bg2_fail;
|
||||
|
||||
clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_MEMPLLCTL0,
|
||||
ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_MEMPLLCTL0,
|
||||
clk_names[MEMPLL], clk_names[REFCLK], 0);
|
||||
if (IS_ERR(clk))
|
||||
if (ret)
|
||||
goto bg2_fail;
|
||||
|
||||
clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_CPUPLLCTL0,
|
||||
ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_CPUPLLCTL0,
|
||||
clk_names[CPUPLL], clk_names[REFCLK], 0);
|
||||
if (IS_ERR(clk))
|
||||
if (ret)
|
||||
goto bg2_fail;
|
||||
|
||||
if (of_device_is_compatible(np, "marvell,berlin2-global-register"))
|
||||
avpll_flags |= BERLIN2_AVPLL_SCRAMBLE_QUIRK;
|
||||
|
||||
/* audio/video VCOs */
|
||||
clk = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL0, "avpll_vcoA",
|
||||
ret = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL0, "avpll_vcoA",
|
||||
clk_names[REFCLK], avpll_flags, 0);
|
||||
if (IS_ERR(clk))
|
||||
if (ret)
|
||||
goto bg2_fail;
|
||||
|
||||
for (n = 0; n < 8; n++) {
|
||||
clk = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL0,
|
||||
ret = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL0,
|
||||
clk_names[AVPLL_A1 + n], n, "avpll_vcoA",
|
||||
avpll_flags, 0);
|
||||
if (IS_ERR(clk))
|
||||
if (ret)
|
||||
goto bg2_fail;
|
||||
}
|
||||
|
||||
clk = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL31, "avpll_vcoB",
|
||||
ret = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL31, "avpll_vcoB",
|
||||
clk_names[REFCLK], BERLIN2_AVPLL_BIT_QUIRK |
|
||||
avpll_flags, 0);
|
||||
if (IS_ERR(clk))
|
||||
if (ret)
|
||||
goto bg2_fail;
|
||||
|
||||
for (n = 0; n < 8; n++) {
|
||||
clk = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL31,
|
||||
ret = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL31,
|
||||
clk_names[AVPLL_B1 + n], n, "avpll_vcoB",
|
||||
BERLIN2_AVPLL_BIT_QUIRK | avpll_flags, 0);
|
||||
if (IS_ERR(clk))
|
||||
if (ret)
|
||||
goto bg2_fail;
|
||||
}
|
||||
|
||||
/* reference clock bypass switches */
|
||||
parent_names[0] = clk_names[SYSPLL];
|
||||
parent_names[1] = clk_names[REFCLK];
|
||||
clk = clk_register_mux(NULL, "syspll_byp", parent_names, 2,
|
||||
hw = clk_hw_register_mux(NULL, "syspll_byp", parent_names, 2,
|
||||
0, gbase + REG_CLKSWITCH0, 0, 1, 0, &lock);
|
||||
if (IS_ERR(clk))
|
||||
if (IS_ERR(hw))
|
||||
goto bg2_fail;
|
||||
clk_names[SYSPLL] = __clk_get_name(clk);
|
||||
clk_names[SYSPLL] = clk_hw_get_name(hw);
|
||||
|
||||
parent_names[0] = clk_names[MEMPLL];
|
||||
parent_names[1] = clk_names[REFCLK];
|
||||
clk = clk_register_mux(NULL, "mempll_byp", parent_names, 2,
|
||||
hw = clk_hw_register_mux(NULL, "mempll_byp", parent_names, 2,
|
||||
0, gbase + REG_CLKSWITCH0, 1, 1, 0, &lock);
|
||||
if (IS_ERR(clk))
|
||||
if (IS_ERR(hw))
|
||||
goto bg2_fail;
|
||||
clk_names[MEMPLL] = __clk_get_name(clk);
|
||||
clk_names[MEMPLL] = clk_hw_get_name(hw);
|
||||
|
||||
parent_names[0] = clk_names[CPUPLL];
|
||||
parent_names[1] = clk_names[REFCLK];
|
||||
clk = clk_register_mux(NULL, "cpupll_byp", parent_names, 2,
|
||||
hw = clk_hw_register_mux(NULL, "cpupll_byp", parent_names, 2,
|
||||
0, gbase + REG_CLKSWITCH0, 2, 1, 0, &lock);
|
||||
if (IS_ERR(clk))
|
||||
if (IS_ERR(hw))
|
||||
goto bg2_fail;
|
||||
clk_names[CPUPLL] = __clk_get_name(clk);
|
||||
clk_names[CPUPLL] = clk_hw_get_name(hw);
|
||||
|
||||
/* clock muxes */
|
||||
parent_names[0] = clk_names[AVPLL_B3];
|
||||
parent_names[1] = clk_names[AVPLL_A3];
|
||||
clk = clk_register_mux(NULL, clk_names[AUDIO1_PLL], parent_names, 2,
|
||||
hw = clk_hw_register_mux(NULL, clk_names[AUDIO1_PLL], parent_names, 2,
|
||||
0, gbase + REG_CLKSELECT2, 29, 1, 0, &lock);
|
||||
if (IS_ERR(clk))
|
||||
if (IS_ERR(hw))
|
||||
goto bg2_fail;
|
||||
|
||||
parent_names[0] = clk_names[VIDEO0_PLL];
|
||||
parent_names[1] = clk_names[VIDEO_EXT0];
|
||||
clk = clk_register_mux(NULL, clk_names[VIDEO0_IN], parent_names, 2,
|
||||
hw = clk_hw_register_mux(NULL, clk_names[VIDEO0_IN], parent_names, 2,
|
||||
0, gbase + REG_CLKSELECT3, 4, 1, 0, &lock);
|
||||
if (IS_ERR(clk))
|
||||
if (IS_ERR(hw))
|
||||
goto bg2_fail;
|
||||
|
||||
parent_names[0] = clk_names[VIDEO1_PLL];
|
||||
parent_names[1] = clk_names[VIDEO_EXT0];
|
||||
clk = clk_register_mux(NULL, clk_names[VIDEO1_IN], parent_names, 2,
|
||||
hw = clk_hw_register_mux(NULL, clk_names[VIDEO1_IN], parent_names, 2,
|
||||
0, gbase + REG_CLKSELECT3, 6, 1, 0, &lock);
|
||||
if (IS_ERR(clk))
|
||||
if (IS_ERR(hw))
|
||||
goto bg2_fail;
|
||||
|
||||
parent_names[0] = clk_names[AVPLL_A2];
|
||||
parent_names[1] = clk_names[AVPLL_B2];
|
||||
clk = clk_register_mux(NULL, clk_names[VIDEO1_PLL], parent_names, 2,
|
||||
hw = clk_hw_register_mux(NULL, clk_names[VIDEO1_PLL], parent_names, 2,
|
||||
0, gbase + REG_CLKSELECT3, 7, 1, 0, &lock);
|
||||
if (IS_ERR(clk))
|
||||
if (IS_ERR(hw))
|
||||
goto bg2_fail;
|
||||
|
||||
parent_names[0] = clk_names[VIDEO2_PLL];
|
||||
parent_names[1] = clk_names[VIDEO_EXT0];
|
||||
clk = clk_register_mux(NULL, clk_names[VIDEO2_IN], parent_names, 2,
|
||||
hw = clk_hw_register_mux(NULL, clk_names[VIDEO2_IN], parent_names, 2,
|
||||
0, gbase + REG_CLKSELECT3, 9, 1, 0, &lock);
|
||||
if (IS_ERR(clk))
|
||||
if (IS_ERR(hw))
|
||||
goto bg2_fail;
|
||||
|
||||
parent_names[0] = clk_names[AVPLL_B1];
|
||||
parent_names[1] = clk_names[AVPLL_A5];
|
||||
clk = clk_register_mux(NULL, clk_names[VIDEO2_PLL], parent_names, 2,
|
||||
hw = clk_hw_register_mux(NULL, clk_names[VIDEO2_PLL], parent_names, 2,
|
||||
0, gbase + REG_CLKSELECT3, 10, 1, 0, &lock);
|
||||
if (IS_ERR(clk))
|
||||
if (IS_ERR(hw))
|
||||
goto bg2_fail;
|
||||
|
||||
/* clock divider cells */
|
||||
@ -648,7 +656,7 @@ static void __init berlin2_clock_setup(struct device_node *np)
|
||||
for (k = 0; k < dd->num_parents; k++)
|
||||
parent_names[k] = clk_names[dd->parent_ids[k]];
|
||||
|
||||
clks[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase,
|
||||
hws[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase,
|
||||
dd->name, dd->div_flags, parent_names,
|
||||
dd->num_parents, dd->flags, &lock);
|
||||
}
|
||||
@ -657,18 +665,18 @@ static void __init berlin2_clock_setup(struct device_node *np)
|
||||
for (n = 0; n < ARRAY_SIZE(bg2_gates); n++) {
|
||||
const struct berlin2_gate_data *gd = &bg2_gates[n];
|
||||
|
||||
clks[CLKID_GETH0 + n] = clk_register_gate(NULL, gd->name,
|
||||
hws[CLKID_GETH0 + n] = clk_hw_register_gate(NULL, gd->name,
|
||||
gd->parent_name, gd->flags, gbase + REG_CLKENABLE,
|
||||
gd->bit_idx, 0, &lock);
|
||||
}
|
||||
|
||||
/* twdclk is derived from cpu/3 */
|
||||
clks[CLKID_TWD] =
|
||||
clk_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3);
|
||||
hws[CLKID_TWD] =
|
||||
clk_hw_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3);
|
||||
|
||||
/* check for errors on leaf clocks */
|
||||
for (n = 0; n < MAX_CLKS; n++) {
|
||||
if (!IS_ERR(clks[n]))
|
||||
if (!IS_ERR(hws[n]))
|
||||
continue;
|
||||
|
||||
pr_err("%s: Unable to register leaf clock %d\n",
|
||||
@ -677,9 +685,7 @@ static void __init berlin2_clock_setup(struct device_node *np)
|
||||
}
|
||||
|
||||
/* register clk-provider */
|
||||
clk_data.clks = clks;
|
||||
clk_data.clk_num = MAX_CLKS;
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clk_data);
|
||||
|
||||
return;
|
||||
|
||||
|
@ -46,8 +46,7 @@
|
||||
#define REG_SDIO1XIN_CLKCTL 0x015c
|
||||
|
||||
#define MAX_CLKS 28
|
||||
static struct clk *clks[MAX_CLKS];
|
||||
static struct clk_onecell_data clk_data;
|
||||
static struct clk_hw_onecell_data *clk_data;
|
||||
static DEFINE_SPINLOCK(lock);
|
||||
static void __iomem *gbase;
|
||||
static void __iomem *cpupll_base;
|
||||
@ -293,7 +292,15 @@ static void __init berlin2q_clock_setup(struct device_node *np)
|
||||
struct device_node *parent_np = of_get_parent(np);
|
||||
const char *parent_names[9];
|
||||
struct clk *clk;
|
||||
int n;
|
||||
struct clk_hw **hws;
|
||||
int n, ret;
|
||||
|
||||
clk_data = kzalloc(sizeof(*clk_data) +
|
||||
sizeof(*clk_data->hws) * MAX_CLKS, GFP_KERNEL);
|
||||
if (!clk_data)
|
||||
return;
|
||||
clk_data->num = MAX_CLKS;
|
||||
hws = clk_data->hws;
|
||||
|
||||
gbase = of_iomap(parent_np, 0);
|
||||
if (!gbase) {
|
||||
@ -317,14 +324,14 @@ static void __init berlin2q_clock_setup(struct device_node *np)
|
||||
}
|
||||
|
||||
/* simple register PLLs */
|
||||
clk = berlin2_pll_register(&bg2q_pll_map, gbase + REG_SYSPLLCTL0,
|
||||
ret = berlin2_pll_register(&bg2q_pll_map, gbase + REG_SYSPLLCTL0,
|
||||
clk_names[SYSPLL], clk_names[REFCLK], 0);
|
||||
if (IS_ERR(clk))
|
||||
if (ret)
|
||||
goto bg2q_fail;
|
||||
|
||||
clk = berlin2_pll_register(&bg2q_pll_map, cpupll_base,
|
||||
ret = berlin2_pll_register(&bg2q_pll_map, cpupll_base,
|
||||
clk_names[CPUPLL], clk_names[REFCLK], 0);
|
||||
if (IS_ERR(clk))
|
||||
if (ret)
|
||||
goto bg2q_fail;
|
||||
|
||||
/* TODO: add BG2Q AVPLL */
|
||||
@ -342,7 +349,7 @@ static void __init berlin2q_clock_setup(struct device_node *np)
|
||||
for (k = 0; k < dd->num_parents; k++)
|
||||
parent_names[k] = clk_names[dd->parent_ids[k]];
|
||||
|
||||
clks[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase,
|
||||
hws[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase,
|
||||
dd->name, dd->div_flags, parent_names,
|
||||
dd->num_parents, dd->flags, &lock);
|
||||
}
|
||||
@ -351,22 +358,22 @@ static void __init berlin2q_clock_setup(struct device_node *np)
|
||||
for (n = 0; n < ARRAY_SIZE(bg2q_gates); n++) {
|
||||
const struct berlin2_gate_data *gd = &bg2q_gates[n];
|
||||
|
||||
clks[CLKID_GFX2DAXI + n] = clk_register_gate(NULL, gd->name,
|
||||
hws[CLKID_GFX2DAXI + n] = clk_hw_register_gate(NULL, gd->name,
|
||||
gd->parent_name, gd->flags, gbase + REG_CLKENABLE,
|
||||
gd->bit_idx, 0, &lock);
|
||||
}
|
||||
|
||||
/* cpuclk divider is fixed to 1 */
|
||||
clks[CLKID_CPU] =
|
||||
clk_register_fixed_factor(NULL, "cpu", clk_names[CPUPLL],
|
||||
hws[CLKID_CPU] =
|
||||
clk_hw_register_fixed_factor(NULL, "cpu", clk_names[CPUPLL],
|
||||
0, 1, 1);
|
||||
/* twdclk is derived from cpu/3 */
|
||||
clks[CLKID_TWD] =
|
||||
clk_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3);
|
||||
hws[CLKID_TWD] =
|
||||
clk_hw_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3);
|
||||
|
||||
/* check for errors on leaf clocks */
|
||||
for (n = 0; n < MAX_CLKS; n++) {
|
||||
if (!IS_ERR(clks[n]))
|
||||
if (!IS_ERR(hws[n]))
|
||||
continue;
|
||||
|
||||
pr_err("%s: Unable to register leaf clock %d\n",
|
||||
@ -375,9 +382,7 @@ static void __init berlin2q_clock_setup(struct device_node *np)
|
||||
}
|
||||
|
||||
/* register clk-provider */
|
||||
clk_data.clks = clks;
|
||||
clk_data.clk_num = MAX_CLKS;
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clk_data);
|
||||
|
||||
return;
|
||||
|
||||
|
@ -68,8 +68,7 @@
|
||||
#define HW_LCDCLKDIV 0x01fc
|
||||
#define HW_ADCANACLKDIV 0x0200
|
||||
|
||||
static struct clk *clks[MAX_CLKS];
|
||||
static struct clk_onecell_data clk_data;
|
||||
static struct clk_hw_onecell_data *clk_data;
|
||||
static DEFINE_SPINLOCK(asm9260_clk_lock);
|
||||
|
||||
struct asm9260_div_clk {
|
||||
@ -267,12 +266,20 @@ static struct asm9260_mux_clock asm9260_mux_clks[] __initdata = {
|
||||
|
||||
static void __init asm9260_acc_init(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
struct clk_hw **hws;
|
||||
const char *ref_clk, *pll_clk = "pll";
|
||||
u32 rate;
|
||||
int n;
|
||||
u32 accuracy = 0;
|
||||
|
||||
clk_data = kzalloc(sizeof(*clk_data) +
|
||||
sizeof(*clk_data->hws) * MAX_CLKS, GFP_KERNEL);
|
||||
if (!clk_data)
|
||||
return;
|
||||
clk_data->num = MAX_CLKS;
|
||||
hws = clk_data->hws;
|
||||
|
||||
base = of_io_request_and_map(np, 0, np->name);
|
||||
if (IS_ERR(base))
|
||||
panic("%s: unable to map resource", np->name);
|
||||
@ -282,10 +289,10 @@ static void __init asm9260_acc_init(struct device_node *np)
|
||||
|
||||
ref_clk = of_clk_get_parent_name(np, 0);
|
||||
accuracy = clk_get_accuracy(__clk_lookup(ref_clk));
|
||||
clk = clk_register_fixed_rate_with_accuracy(NULL, pll_clk,
|
||||
hw = clk_hw_register_fixed_rate_with_accuracy(NULL, pll_clk,
|
||||
ref_clk, 0, rate, accuracy);
|
||||
|
||||
if (IS_ERR(clk))
|
||||
if (IS_ERR(hw))
|
||||
panic("%s: can't register REFCLK. Check DT!", np->name);
|
||||
|
||||
for (n = 0; n < ARRAY_SIZE(asm9260_mux_clks); n++) {
|
||||
@ -293,7 +300,7 @@ static void __init asm9260_acc_init(struct device_node *np)
|
||||
|
||||
mc->parent_names[0] = ref_clk;
|
||||
mc->parent_names[1] = pll_clk;
|
||||
clk = clk_register_mux_table(NULL, mc->name, mc->parent_names,
|
||||
hw = clk_hw_register_mux_table(NULL, mc->name, mc->parent_names,
|
||||
mc->num_parents, mc->flags, base + mc->offset,
|
||||
0, mc->mask, 0, mc->table, &asm9260_clk_lock);
|
||||
}
|
||||
@ -302,7 +309,7 @@ static void __init asm9260_acc_init(struct device_node *np)
|
||||
for (n = 0; n < ARRAY_SIZE(asm9260_mux_gates); n++) {
|
||||
const struct asm9260_gate_data *gd = &asm9260_mux_gates[n];
|
||||
|
||||
clk = clk_register_gate(NULL, gd->name,
|
||||
hw = clk_hw_register_gate(NULL, gd->name,
|
||||
gd->parent_name, gd->flags | CLK_SET_RATE_PARENT,
|
||||
base + gd->reg, gd->bit_idx, 0, &asm9260_clk_lock);
|
||||
}
|
||||
@ -311,7 +318,7 @@ static void __init asm9260_acc_init(struct device_node *np)
|
||||
for (n = 0; n < ARRAY_SIZE(asm9260_div_clks); n++) {
|
||||
const struct asm9260_div_clk *dc = &asm9260_div_clks[n];
|
||||
|
||||
clks[dc->idx] = clk_register_divider(NULL, dc->name,
|
||||
hws[dc->idx] = clk_hw_register_divider(NULL, dc->name,
|
||||
dc->parent_name, CLK_SET_RATE_PARENT,
|
||||
base + dc->reg, 0, 8, CLK_DIVIDER_ONE_BASED,
|
||||
&asm9260_clk_lock);
|
||||
@ -321,14 +328,14 @@ static void __init asm9260_acc_init(struct device_node *np)
|
||||
for (n = 0; n < ARRAY_SIZE(asm9260_ahb_gates); n++) {
|
||||
const struct asm9260_gate_data *gd = &asm9260_ahb_gates[n];
|
||||
|
||||
clks[gd->idx] = clk_register_gate(NULL, gd->name,
|
||||
hws[gd->idx] = clk_hw_register_gate(NULL, gd->name,
|
||||
gd->parent_name, gd->flags, base + gd->reg,
|
||||
gd->bit_idx, 0, &asm9260_clk_lock);
|
||||
}
|
||||
|
||||
/* check for errors on leaf clocks */
|
||||
for (n = 0; n < MAX_CLKS; n++) {
|
||||
if (!IS_ERR(clks[n]))
|
||||
if (!IS_ERR(hws[n]))
|
||||
continue;
|
||||
|
||||
pr_err("%s: Unable to register leaf clock %d\n",
|
||||
@ -337,9 +344,7 @@ static void __init asm9260_acc_init(struct device_node *np)
|
||||
}
|
||||
|
||||
/* register clk-provider */
|
||||
clk_data.clks = clks;
|
||||
clk_data.clk_num = MAX_CLKS;
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
|
||||
return;
|
||||
fail:
|
||||
iounmap(base);
|
||||
|
@ -392,8 +392,8 @@ static int axi_clkgen_probe(struct platform_device *pdev)
|
||||
const char *parent_names[2];
|
||||
const char *clk_name;
|
||||
struct resource *mem;
|
||||
struct clk *clk;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (!pdev->dev.of_node)
|
||||
return -ENODEV;
|
||||
@ -433,12 +433,12 @@ static int axi_clkgen_probe(struct platform_device *pdev)
|
||||
axi_clkgen_mmcm_enable(axi_clkgen, false);
|
||||
|
||||
axi_clkgen->clk_hw.init = &init;
|
||||
clk = devm_clk_register(&pdev->dev, &axi_clkgen->clk_hw);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
ret = devm_clk_hw_register(&pdev->dev, &axi_clkgen->clk_hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get,
|
||||
clk);
|
||||
return of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_simple_get,
|
||||
&axi_clkgen->clk_hw);
|
||||
}
|
||||
|
||||
static int axi_clkgen_remove(struct platform_device *pdev)
|
||||
|
@ -516,6 +516,19 @@ static struct axxia_clk *axmclk_clocks[] = {
|
||||
[AXXIA_CLK_MMC] = &clk_mmc_mux.aclk,
|
||||
};
|
||||
|
||||
static struct clk_hw *
|
||||
of_clk_axmclk_get(struct of_phandle_args *clkspec, void *unused)
|
||||
{
|
||||
unsigned int idx = clkspec->args[0];
|
||||
|
||||
if (idx >= ARRAY_SIZE(axmclk_clocks)) {
|
||||
pr_err("%s: invalid index %u\n", __func__, idx);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return &axmclk_clocks[idx]->hw;
|
||||
}
|
||||
|
||||
static const struct regmap_config axmclk_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
@ -530,21 +543,14 @@ static const struct of_device_id axmclk_match_table[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, axmclk_match_table);
|
||||
|
||||
struct axmclk_priv {
|
||||
struct clk_onecell_data onecell;
|
||||
struct clk *clks[];
|
||||
};
|
||||
|
||||
static int axmclk_probe(struct platform_device *pdev)
|
||||
{
|
||||
void __iomem *base;
|
||||
struct resource *res;
|
||||
int i, ret;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct clk *clk;
|
||||
struct regmap *regmap;
|
||||
size_t num_clks;
|
||||
struct axmclk_priv *priv;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(dev, res);
|
||||
@ -557,29 +563,18 @@ static int axmclk_probe(struct platform_device *pdev)
|
||||
|
||||
num_clks = ARRAY_SIZE(axmclk_clocks);
|
||||
pr_info("axmclk: supporting %zu clocks\n", num_clks);
|
||||
priv = devm_kzalloc(dev, sizeof(*priv) + sizeof(*priv->clks) * num_clks,
|
||||
GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->onecell.clks = priv->clks;
|
||||
priv->onecell.clk_num = num_clks;
|
||||
|
||||
/* Update each entry with the allocated regmap and register the clock
|
||||
* with the common clock framework
|
||||
*/
|
||||
for (i = 0; i < num_clks; i++) {
|
||||
axmclk_clocks[i]->regmap = regmap;
|
||||
clk = devm_clk_register(dev, &axmclk_clocks[i]->hw);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
priv->clks[i] = clk;
|
||||
ret = devm_clk_hw_register(dev, &axmclk_clocks[i]->hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = of_clk_add_provider(dev->of_node,
|
||||
of_clk_src_onecell_get, &priv->onecell);
|
||||
|
||||
return ret;
|
||||
return of_clk_add_hw_provider(dev->of_node, of_clk_axmclk_get, NULL);
|
||||
}
|
||||
|
||||
static int axmclk_remove(struct platform_device *pdev)
|
||||
|
@ -71,7 +71,6 @@ struct cdce706_hw_data {
|
||||
struct cdce706_dev_data *dev_data;
|
||||
unsigned idx;
|
||||
unsigned parent;
|
||||
struct clk *clk;
|
||||
struct clk_hw hw;
|
||||
unsigned div;
|
||||
unsigned mul;
|
||||
@ -81,8 +80,6 @@ struct cdce706_hw_data {
|
||||
struct cdce706_dev_data {
|
||||
struct i2c_client *client;
|
||||
struct regmap *regmap;
|
||||
struct clk_onecell_data onecell;
|
||||
struct clk *clks[6];
|
||||
struct clk *clkin_clk[2];
|
||||
const char *clkin_name[2];
|
||||
struct cdce706_hw_data clkin[1];
|
||||
@ -455,18 +452,19 @@ static int cdce706_register_hw(struct cdce706_dev_data *cdce,
|
||||
struct clk_init_data *init)
|
||||
{
|
||||
unsigned i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < num_hw; ++i, ++hw) {
|
||||
init->name = clk_names[i];
|
||||
hw->dev_data = cdce;
|
||||
hw->idx = i;
|
||||
hw->hw.init = init;
|
||||
hw->clk = devm_clk_register(&cdce->client->dev,
|
||||
ret = devm_clk_hw_register(&cdce->client->dev,
|
||||
&hw->hw);
|
||||
if (IS_ERR(hw->clk)) {
|
||||
if (ret) {
|
||||
dev_err(&cdce->client->dev, "Failed to register %s\n",
|
||||
clk_names[i]);
|
||||
return PTR_ERR(hw->clk);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -613,13 +611,23 @@ static int cdce706_register_clkouts(struct cdce706_dev_data *cdce)
|
||||
cdce->clkout[i].parent);
|
||||
}
|
||||
|
||||
ret = cdce706_register_hw(cdce, cdce->clkout,
|
||||
return cdce706_register_hw(cdce, cdce->clkout,
|
||||
ARRAY_SIZE(cdce->clkout),
|
||||
cdce706_clkout_name, &init);
|
||||
for (i = 0; i < ARRAY_SIZE(cdce->clkout); ++i)
|
||||
cdce->clks[i] = cdce->clkout[i].clk;
|
||||
}
|
||||
|
||||
return ret;
|
||||
static struct clk_hw *
|
||||
of_clk_cdce_get(struct of_phandle_args *clkspec, void *data)
|
||||
{
|
||||
struct cdce706_dev_data *cdce = data;
|
||||
unsigned int idx = clkspec->args[0];
|
||||
|
||||
if (idx >= ARRAY_SIZE(cdce->clkout)) {
|
||||
pr_err("%s: invalid index %u\n", __func__, idx);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return &cdce->clkout[idx].hw;
|
||||
}
|
||||
|
||||
static int cdce706_probe(struct i2c_client *client,
|
||||
@ -657,12 +665,8 @@ static int cdce706_probe(struct i2c_client *client,
|
||||
ret = cdce706_register_clkouts(cdce);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
cdce->onecell.clks = cdce->clks;
|
||||
cdce->onecell.clk_num = ARRAY_SIZE(cdce->clks);
|
||||
ret = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get,
|
||||
&cdce->onecell);
|
||||
|
||||
return ret;
|
||||
return of_clk_add_hw_provider(client->dev.of_node, of_clk_cdce_get,
|
||||
cdce);
|
||||
}
|
||||
|
||||
static int cdce706_remove(struct i2c_client *client)
|
||||
|
@ -62,8 +62,6 @@ struct clk_cdce925_chip {
|
||||
struct i2c_client *i2c_client;
|
||||
struct clk_cdce925_pll pll[NUMBER_OF_PLLS];
|
||||
struct clk_cdce925_output clk[NUMBER_OF_OUTPUTS];
|
||||
struct clk *dt_clk[NUMBER_OF_OUTPUTS];
|
||||
struct clk_onecell_data onecell;
|
||||
};
|
||||
|
||||
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
|
||||
@ -557,6 +555,20 @@ static int cdce925_regmap_i2c_read(void *context,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static struct clk_hw *
|
||||
of_clk_cdce925_get(struct of_phandle_args *clkspec, void *_data)
|
||||
{
|
||||
struct clk_cdce925_chip *data = _data;
|
||||
unsigned int idx = clkspec->args[0];
|
||||
|
||||
if (idx >= ARRAY_SIZE(data->clk)) {
|
||||
pr_err("%s: invalid index %u\n", __func__, idx);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return &data->clk[idx].hw;
|
||||
}
|
||||
|
||||
/* The CDCE925 uses a funky way to read/write registers. Bulk mode is
|
||||
* just weird, so just use the single byte mode exclusively. */
|
||||
static struct regmap_bus regmap_cdce925_bus = {
|
||||
@ -572,7 +584,6 @@ static int cdce925_probe(struct i2c_client *client,
|
||||
const char *parent_name;
|
||||
const char *pll_clk_name[NUMBER_OF_PLLS] = {NULL,};
|
||||
struct clk_init_data init;
|
||||
struct clk *clk;
|
||||
u32 value;
|
||||
int i;
|
||||
int err;
|
||||
@ -622,10 +633,9 @@ static int cdce925_probe(struct i2c_client *client,
|
||||
data->pll[i].chip = data;
|
||||
data->pll[i].hw.init = &init;
|
||||
data->pll[i].index = i;
|
||||
clk = devm_clk_register(&client->dev, &data->pll[i].hw);
|
||||
if (IS_ERR(clk)) {
|
||||
err = devm_clk_hw_register(&client->dev, &data->pll[i].hw);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "Failed register PLL %d\n", i);
|
||||
err = PTR_ERR(clk);
|
||||
goto error;
|
||||
}
|
||||
sprintf(child_name, "PLL%d", i+1);
|
||||
@ -634,7 +644,7 @@ static int cdce925_probe(struct i2c_client *client,
|
||||
continue;
|
||||
if (!of_property_read_u32(np_output,
|
||||
"clock-frequency", &value)) {
|
||||
err = clk_set_rate(clk, value);
|
||||
err = clk_set_rate(data->pll[i].hw.clk, value);
|
||||
if (err)
|
||||
dev_err(&client->dev,
|
||||
"unable to set PLL frequency %ud\n",
|
||||
@ -663,14 +673,12 @@ static int cdce925_probe(struct i2c_client *client,
|
||||
data->clk[0].hw.init = &init;
|
||||
data->clk[0].index = 0;
|
||||
data->clk[0].pdiv = 1;
|
||||
clk = devm_clk_register(&client->dev, &data->clk[0].hw);
|
||||
err = devm_clk_hw_register(&client->dev, &data->clk[0].hw);
|
||||
kfree(init.name); /* clock framework made a copy of the name */
|
||||
if (IS_ERR(clk)) {
|
||||
if (err) {
|
||||
dev_err(&client->dev, "clock registration Y1 failed\n");
|
||||
err = PTR_ERR(clk);
|
||||
goto error;
|
||||
}
|
||||
data->dt_clk[0] = clk;
|
||||
|
||||
/* Register output clocks Y2 .. Y5*/
|
||||
init.ops = &cdce925_clk_ops;
|
||||
@ -695,21 +703,17 @@ static int cdce925_probe(struct i2c_client *client,
|
||||
init.parent_names = &pll_clk_name[1];
|
||||
break;
|
||||
}
|
||||
clk = devm_clk_register(&client->dev, &data->clk[i].hw);
|
||||
err = devm_clk_hw_register(&client->dev, &data->clk[i].hw);
|
||||
kfree(init.name); /* clock framework made a copy of the name */
|
||||
if (IS_ERR(clk)) {
|
||||
if (err) {
|
||||
dev_err(&client->dev, "clock registration failed\n");
|
||||
err = PTR_ERR(clk);
|
||||
goto error;
|
||||
}
|
||||
data->dt_clk[i] = clk;
|
||||
}
|
||||
|
||||
/* Register the output clocks */
|
||||
data->onecell.clk_num = NUMBER_OF_OUTPUTS;
|
||||
data->onecell.clks = data->dt_clk;
|
||||
err = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get,
|
||||
&data->onecell);
|
||||
err = of_clk_add_hw_provider(client->dev.of_node, of_clk_cdce925_get,
|
||||
data);
|
||||
if (err)
|
||||
dev_err(&client->dev, "unable to add OF clock provider\n");
|
||||
|
||||
|
@ -40,9 +40,8 @@ static const struct clk_div_table timer_div_table[] = {
|
||||
};
|
||||
|
||||
struct clps711x_clk {
|
||||
struct clk_onecell_data clk_data;
|
||||
spinlock_t lock;
|
||||
struct clk *clks[CLPS711X_CLK_MAX];
|
||||
struct clk_hw_onecell_data clk_data;
|
||||
};
|
||||
|
||||
static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base,
|
||||
@ -55,7 +54,9 @@ static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base,
|
||||
if (!base)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
clps711x_clk = kzalloc(sizeof(*clps711x_clk), GFP_KERNEL);
|
||||
clps711x_clk = kzalloc(sizeof(*clps711x_clk) +
|
||||
sizeof(*clps711x_clk->clk_data.hws) * CLPS711X_CLK_MAX,
|
||||
GFP_KERNEL);
|
||||
if (!clps711x_clk)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
@ -106,40 +107,40 @@ static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base,
|
||||
tmp |= SYSCON1_TC2M | SYSCON1_TC2S;
|
||||
writel(tmp, base + CLPS711X_SYSCON1);
|
||||
|
||||
clps711x_clk->clks[CLPS711X_CLK_DUMMY] =
|
||||
clk_register_fixed_rate(NULL, "dummy", NULL, 0, 0);
|
||||
clps711x_clk->clks[CLPS711X_CLK_CPU] =
|
||||
clk_register_fixed_rate(NULL, "cpu", NULL, 0, f_cpu);
|
||||
clps711x_clk->clks[CLPS711X_CLK_BUS] =
|
||||
clk_register_fixed_rate(NULL, "bus", NULL, 0, f_bus);
|
||||
clps711x_clk->clks[CLPS711X_CLK_PLL] =
|
||||
clk_register_fixed_rate(NULL, "pll", NULL, 0, f_pll);
|
||||
clps711x_clk->clks[CLPS711X_CLK_TIMERREF] =
|
||||
clk_register_fixed_rate(NULL, "timer_ref", NULL, 0, f_tim);
|
||||
clps711x_clk->clks[CLPS711X_CLK_TIMER1] =
|
||||
clk_register_divider_table(NULL, "timer1", "timer_ref", 0,
|
||||
clps711x_clk->clk_data.hws[CLPS711X_CLK_DUMMY] =
|
||||
clk_hw_register_fixed_rate(NULL, "dummy", NULL, 0, 0);
|
||||
clps711x_clk->clk_data.hws[CLPS711X_CLK_CPU] =
|
||||
clk_hw_register_fixed_rate(NULL, "cpu", NULL, 0, f_cpu);
|
||||
clps711x_clk->clk_data.hws[CLPS711X_CLK_BUS] =
|
||||
clk_hw_register_fixed_rate(NULL, "bus", NULL, 0, f_bus);
|
||||
clps711x_clk->clk_data.hws[CLPS711X_CLK_PLL] =
|
||||
clk_hw_register_fixed_rate(NULL, "pll", NULL, 0, f_pll);
|
||||
clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMERREF] =
|
||||
clk_hw_register_fixed_rate(NULL, "timer_ref", NULL, 0, f_tim);
|
||||
clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMER1] =
|
||||
clk_hw_register_divider_table(NULL, "timer1", "timer_ref", 0,
|
||||
base + CLPS711X_SYSCON1, 5, 1, 0,
|
||||
timer_div_table, &clps711x_clk->lock);
|
||||
clps711x_clk->clks[CLPS711X_CLK_TIMER2] =
|
||||
clk_register_divider_table(NULL, "timer2", "timer_ref", 0,
|
||||
clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMER2] =
|
||||
clk_hw_register_divider_table(NULL, "timer2", "timer_ref", 0,
|
||||
base + CLPS711X_SYSCON1, 7, 1, 0,
|
||||
timer_div_table, &clps711x_clk->lock);
|
||||
clps711x_clk->clks[CLPS711X_CLK_PWM] =
|
||||
clk_register_fixed_rate(NULL, "pwm", NULL, 0, f_pwm);
|
||||
clps711x_clk->clks[CLPS711X_CLK_SPIREF] =
|
||||
clk_register_fixed_rate(NULL, "spi_ref", NULL, 0, f_spi);
|
||||
clps711x_clk->clks[CLPS711X_CLK_SPI] =
|
||||
clk_register_divider_table(NULL, "spi", "spi_ref", 0,
|
||||
clps711x_clk->clk_data.hws[CLPS711X_CLK_PWM] =
|
||||
clk_hw_register_fixed_rate(NULL, "pwm", NULL, 0, f_pwm);
|
||||
clps711x_clk->clk_data.hws[CLPS711X_CLK_SPIREF] =
|
||||
clk_hw_register_fixed_rate(NULL, "spi_ref", NULL, 0, f_spi);
|
||||
clps711x_clk->clk_data.hws[CLPS711X_CLK_SPI] =
|
||||
clk_hw_register_divider_table(NULL, "spi", "spi_ref", 0,
|
||||
base + CLPS711X_SYSCON1, 16, 2, 0,
|
||||
spi_div_table, &clps711x_clk->lock);
|
||||
clps711x_clk->clks[CLPS711X_CLK_UART] =
|
||||
clk_register_fixed_factor(NULL, "uart", "bus", 0, 1, 10);
|
||||
clps711x_clk->clks[CLPS711X_CLK_TICK] =
|
||||
clk_register_fixed_rate(NULL, "tick", NULL, 0, 64);
|
||||
clps711x_clk->clk_data.hws[CLPS711X_CLK_UART] =
|
||||
clk_hw_register_fixed_factor(NULL, "uart", "bus", 0, 1, 10);
|
||||
clps711x_clk->clk_data.hws[CLPS711X_CLK_TICK] =
|
||||
clk_hw_register_fixed_rate(NULL, "tick", NULL, 0, 64);
|
||||
for (i = 0; i < CLPS711X_CLK_MAX; i++)
|
||||
if (IS_ERR(clps711x_clk->clks[i]))
|
||||
if (IS_ERR(clps711x_clk->clk_data.hws[i]))
|
||||
pr_err("clk %i: register failed with %ld\n",
|
||||
i, PTR_ERR(clps711x_clk->clks[i]));
|
||||
i, PTR_ERR(clps711x_clk->clk_data.hws[i]));
|
||||
|
||||
return clps711x_clk;
|
||||
}
|
||||
@ -153,17 +154,17 @@ void __init clps711x_clk_init(void __iomem *base)
|
||||
BUG_ON(IS_ERR(clps711x_clk));
|
||||
|
||||
/* Clocksource */
|
||||
clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_TIMER1],
|
||||
clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMER1],
|
||||
NULL, "clps711x-timer.0");
|
||||
clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_TIMER2],
|
||||
clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMER2],
|
||||
NULL, "clps711x-timer.1");
|
||||
|
||||
/* Drivers */
|
||||
clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_PWM],
|
||||
clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_PWM],
|
||||
NULL, "clps711x-pwm");
|
||||
clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_UART],
|
||||
clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_UART],
|
||||
NULL, "clps711x-uart.0");
|
||||
clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_UART],
|
||||
clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_UART],
|
||||
NULL, "clps711x-uart.1");
|
||||
}
|
||||
|
||||
@ -179,9 +180,8 @@ static void __init clps711x_clk_init_dt(struct device_node *np)
|
||||
clps711x_clk = _clps711x_clk_init(base, fref);
|
||||
BUG_ON(IS_ERR(clps711x_clk));
|
||||
|
||||
clps711x_clk->clk_data.clks = clps711x_clk->clks;
|
||||
clps711x_clk->clk_data.clk_num = CLPS711X_CLK_MAX;
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get,
|
||||
clps711x_clk->clk_data.num = CLPS711X_CLK_MAX;
|
||||
of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
|
||||
&clps711x_clk->clk_data);
|
||||
}
|
||||
CLK_OF_DECLARE(clps711x, "cirrus,ep7209-clk", clps711x_clk_init_dt);
|
||||
|
@ -59,7 +59,6 @@ struct cs2000_priv {
|
||||
struct i2c_client *client;
|
||||
struct clk *clk_in;
|
||||
struct clk *ref_clk;
|
||||
struct clk *clk_out;
|
||||
};
|
||||
|
||||
static const struct of_device_id cs2000_of_match[] = {
|
||||
@ -371,7 +370,6 @@ static int cs2000_clk_register(struct cs2000_priv *priv)
|
||||
struct device_node *np = dev->of_node;
|
||||
struct clk_init_data init;
|
||||
const char *name = np->name;
|
||||
struct clk *clk;
|
||||
static const char *parent_names[CLK_MAX];
|
||||
int ch = 0; /* it uses ch0 only at this point */
|
||||
int rate;
|
||||
@ -400,18 +398,16 @@ static int cs2000_clk_register(struct cs2000_priv *priv)
|
||||
|
||||
priv->hw.init = &init;
|
||||
|
||||
clk = clk_register(dev, &priv->hw);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
ret = clk_hw_register(dev, &priv->hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &priv->hw);
|
||||
if (ret < 0) {
|
||||
clk_unregister(clk);
|
||||
clk_hw_unregister(&priv->hw);
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->clk_out = clk;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -454,7 +450,7 @@ static int cs2000_remove(struct i2c_client *client)
|
||||
|
||||
of_clk_del_provider(np);
|
||||
|
||||
clk_unregister(priv->clk_out);
|
||||
clk_hw_unregister(&priv->hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -352,7 +352,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
/* if read only, just return current value */
|
||||
if (divider->flags & CLK_DIVIDER_READ_ONLY) {
|
||||
bestdiv = readl(divider->reg) >> divider->shift;
|
||||
bestdiv = clk_readl(divider->reg) >> divider->shift;
|
||||
bestdiv &= div_mask(divider->width);
|
||||
bestdiv = _get_div(divider->table, bestdiv, divider->flags,
|
||||
divider->width);
|
||||
|
@ -10,24 +10,31 @@
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <dt-bindings/clock/efm32-cmu.h>
|
||||
|
||||
#define CMU_HFPERCLKEN0 0x44
|
||||
#define CMU_MAX_CLKS 37
|
||||
|
||||
static struct clk *clk[37];
|
||||
static struct clk_onecell_data clk_data = {
|
||||
.clks = clk,
|
||||
.clk_num = ARRAY_SIZE(clk),
|
||||
};
|
||||
static struct clk_hw_onecell_data *clk_data;
|
||||
|
||||
static void __init efm32gg_cmu_init(struct device_node *np)
|
||||
{
|
||||
int i;
|
||||
void __iomem *base;
|
||||
struct clk_hw **hws;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(clk); ++i)
|
||||
clk[i] = ERR_PTR(-ENOENT);
|
||||
clk_data = kzalloc(sizeof(*clk_data) +
|
||||
sizeof(*clk_data->hws) * CMU_MAX_CLKS, GFP_KERNEL);
|
||||
|
||||
if (!clk_data)
|
||||
return;
|
||||
|
||||
hws = clk_data->hws;
|
||||
|
||||
for (i = 0; i < CMU_MAX_CLKS; ++i)
|
||||
hws[i] = ERR_PTR(-ENOENT);
|
||||
|
||||
base = of_iomap(np, 0);
|
||||
if (!base) {
|
||||
@ -35,46 +42,46 @@ static void __init efm32gg_cmu_init(struct device_node *np)
|
||||
return;
|
||||
}
|
||||
|
||||
clk[clk_HFXO] = clk_register_fixed_rate(NULL, "HFXO", NULL,
|
||||
0, 48000000);
|
||||
hws[clk_HFXO] = clk_hw_register_fixed_rate(NULL, "HFXO", NULL, 0,
|
||||
48000000);
|
||||
|
||||
clk[clk_HFPERCLKUSART0] = clk_register_gate(NULL, "HFPERCLK.USART0",
|
||||
hws[clk_HFPERCLKUSART0] = clk_hw_register_gate(NULL, "HFPERCLK.USART0",
|
||||
"HFXO", 0, base + CMU_HFPERCLKEN0, 0, 0, NULL);
|
||||
clk[clk_HFPERCLKUSART1] = clk_register_gate(NULL, "HFPERCLK.USART1",
|
||||
hws[clk_HFPERCLKUSART1] = clk_hw_register_gate(NULL, "HFPERCLK.USART1",
|
||||
"HFXO", 0, base + CMU_HFPERCLKEN0, 1, 0, NULL);
|
||||
clk[clk_HFPERCLKUSART2] = clk_register_gate(NULL, "HFPERCLK.USART2",
|
||||
hws[clk_HFPERCLKUSART2] = clk_hw_register_gate(NULL, "HFPERCLK.USART2",
|
||||
"HFXO", 0, base + CMU_HFPERCLKEN0, 2, 0, NULL);
|
||||
clk[clk_HFPERCLKUART0] = clk_register_gate(NULL, "HFPERCLK.UART0",
|
||||
hws[clk_HFPERCLKUART0] = clk_hw_register_gate(NULL, "HFPERCLK.UART0",
|
||||
"HFXO", 0, base + CMU_HFPERCLKEN0, 3, 0, NULL);
|
||||
clk[clk_HFPERCLKUART1] = clk_register_gate(NULL, "HFPERCLK.UART1",
|
||||
hws[clk_HFPERCLKUART1] = clk_hw_register_gate(NULL, "HFPERCLK.UART1",
|
||||
"HFXO", 0, base + CMU_HFPERCLKEN0, 4, 0, NULL);
|
||||
clk[clk_HFPERCLKTIMER0] = clk_register_gate(NULL, "HFPERCLK.TIMER0",
|
||||
hws[clk_HFPERCLKTIMER0] = clk_hw_register_gate(NULL, "HFPERCLK.TIMER0",
|
||||
"HFXO", 0, base + CMU_HFPERCLKEN0, 5, 0, NULL);
|
||||
clk[clk_HFPERCLKTIMER1] = clk_register_gate(NULL, "HFPERCLK.TIMER1",
|
||||
hws[clk_HFPERCLKTIMER1] = clk_hw_register_gate(NULL, "HFPERCLK.TIMER1",
|
||||
"HFXO", 0, base + CMU_HFPERCLKEN0, 6, 0, NULL);
|
||||
clk[clk_HFPERCLKTIMER2] = clk_register_gate(NULL, "HFPERCLK.TIMER2",
|
||||
hws[clk_HFPERCLKTIMER2] = clk_hw_register_gate(NULL, "HFPERCLK.TIMER2",
|
||||
"HFXO", 0, base + CMU_HFPERCLKEN0, 7, 0, NULL);
|
||||
clk[clk_HFPERCLKTIMER3] = clk_register_gate(NULL, "HFPERCLK.TIMER3",
|
||||
hws[clk_HFPERCLKTIMER3] = clk_hw_register_gate(NULL, "HFPERCLK.TIMER3",
|
||||
"HFXO", 0, base + CMU_HFPERCLKEN0, 8, 0, NULL);
|
||||
clk[clk_HFPERCLKACMP0] = clk_register_gate(NULL, "HFPERCLK.ACMP0",
|
||||
hws[clk_HFPERCLKACMP0] = clk_hw_register_gate(NULL, "HFPERCLK.ACMP0",
|
||||
"HFXO", 0, base + CMU_HFPERCLKEN0, 9, 0, NULL);
|
||||
clk[clk_HFPERCLKACMP1] = clk_register_gate(NULL, "HFPERCLK.ACMP1",
|
||||
hws[clk_HFPERCLKACMP1] = clk_hw_register_gate(NULL, "HFPERCLK.ACMP1",
|
||||
"HFXO", 0, base + CMU_HFPERCLKEN0, 10, 0, NULL);
|
||||
clk[clk_HFPERCLKI2C0] = clk_register_gate(NULL, "HFPERCLK.I2C0",
|
||||
hws[clk_HFPERCLKI2C0] = clk_hw_register_gate(NULL, "HFPERCLK.I2C0",
|
||||
"HFXO", 0, base + CMU_HFPERCLKEN0, 11, 0, NULL);
|
||||
clk[clk_HFPERCLKI2C1] = clk_register_gate(NULL, "HFPERCLK.I2C1",
|
||||
hws[clk_HFPERCLKI2C1] = clk_hw_register_gate(NULL, "HFPERCLK.I2C1",
|
||||
"HFXO", 0, base + CMU_HFPERCLKEN0, 12, 0, NULL);
|
||||
clk[clk_HFPERCLKGPIO] = clk_register_gate(NULL, "HFPERCLK.GPIO",
|
||||
hws[clk_HFPERCLKGPIO] = clk_hw_register_gate(NULL, "HFPERCLK.GPIO",
|
||||
"HFXO", 0, base + CMU_HFPERCLKEN0, 13, 0, NULL);
|
||||
clk[clk_HFPERCLKVCMP] = clk_register_gate(NULL, "HFPERCLK.VCMP",
|
||||
hws[clk_HFPERCLKVCMP] = clk_hw_register_gate(NULL, "HFPERCLK.VCMP",
|
||||
"HFXO", 0, base + CMU_HFPERCLKEN0, 14, 0, NULL);
|
||||
clk[clk_HFPERCLKPRS] = clk_register_gate(NULL, "HFPERCLK.PRS",
|
||||
hws[clk_HFPERCLKPRS] = clk_hw_register_gate(NULL, "HFPERCLK.PRS",
|
||||
"HFXO", 0, base + CMU_HFPERCLKEN0, 15, 0, NULL);
|
||||
clk[clk_HFPERCLKADC0] = clk_register_gate(NULL, "HFPERCLK.ADC0",
|
||||
hws[clk_HFPERCLKADC0] = clk_hw_register_gate(NULL, "HFPERCLK.ADC0",
|
||||
"HFXO", 0, base + CMU_HFPERCLKEN0, 16, 0, NULL);
|
||||
clk[clk_HFPERCLKDAC0] = clk_register_gate(NULL, "HFPERCLK.DAC0",
|
||||
hws[clk_HFPERCLKDAC0] = clk_hw_register_gate(NULL, "HFPERCLK.DAC0",
|
||||
"HFXO", 0, base + CMU_HFPERCLKEN0, 17, 0, NULL);
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clk_data);
|
||||
}
|
||||
CLK_OF_DECLARE(efm32ggcmu, "efm32gg,cmu", efm32gg_cmu_init);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/*
|
||||
* DOC: basic fixed multiplier and divider clock that cannot gate
|
||||
@ -147,27 +148,25 @@ static const struct of_device_id set_rate_parent_matches[] = {
|
||||
{ /* Sentinel */ },
|
||||
};
|
||||
|
||||
/**
|
||||
* of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock
|
||||
*/
|
||||
void __init of_fixed_factor_clk_setup(struct device_node *node)
|
||||
static struct clk *_of_fixed_factor_clk_setup(struct device_node *node)
|
||||
{
|
||||
struct clk *clk;
|
||||
const char *clk_name = node->name;
|
||||
const char *parent_name;
|
||||
unsigned long flags = 0;
|
||||
u32 div, mult;
|
||||
int ret;
|
||||
|
||||
if (of_property_read_u32(node, "clock-div", &div)) {
|
||||
pr_err("%s Fixed factor clock <%s> must have a clock-div property\n",
|
||||
__func__, node->name);
|
||||
return;
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
|
||||
if (of_property_read_u32(node, "clock-mult", &mult)) {
|
||||
pr_err("%s Fixed factor clock <%s> must have a clock-mult property\n",
|
||||
__func__, node->name);
|
||||
return;
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
|
||||
of_property_read_string(node, "clock-output-names", &clk_name);
|
||||
@ -178,10 +177,67 @@ void __init of_fixed_factor_clk_setup(struct device_node *node)
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, clk_name, parent_name, flags,
|
||||
mult, div);
|
||||
if (!IS_ERR(clk))
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
if (IS_ERR(clk))
|
||||
return clk;
|
||||
|
||||
ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
if (ret) {
|
||||
clk_unregister(clk);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock
|
||||
*/
|
||||
void __init of_fixed_factor_clk_setup(struct device_node *node)
|
||||
{
|
||||
_of_fixed_factor_clk_setup(node);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_fixed_factor_clk_setup);
|
||||
CLK_OF_DECLARE(fixed_factor_clk, "fixed-factor-clock",
|
||||
of_fixed_factor_clk_setup);
|
||||
|
||||
static int of_fixed_factor_clk_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct clk *clk = platform_get_drvdata(pdev);
|
||||
|
||||
clk_unregister_fixed_factor(clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int of_fixed_factor_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
/*
|
||||
* This function is not executed when of_fixed_factor_clk_setup
|
||||
* succeeded.
|
||||
*/
|
||||
clk = _of_fixed_factor_clk_setup(pdev->dev.of_node);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
platform_set_drvdata(pdev, clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id of_fixed_factor_clk_ids[] = {
|
||||
{ .compatible = "fixed-factor-clock" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_fixed_factor_clk_ids);
|
||||
|
||||
static struct platform_driver of_fixed_factor_clk_driver = {
|
||||
.driver = {
|
||||
.name = "of_fixed_factor_clk",
|
||||
.of_match_table = of_fixed_factor_clk_ids,
|
||||
},
|
||||
.probe = of_fixed_factor_clk_probe,
|
||||
.remove = of_fixed_factor_clk_remove,
|
||||
};
|
||||
builtin_platform_driver(of_fixed_factor_clk_driver);
|
||||
#endif
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/*
|
||||
* DOC: basic fixed-rate clock that cannot gate
|
||||
@ -157,18 +158,16 @@ void clk_hw_unregister_fixed_rate(struct clk_hw *hw)
|
||||
EXPORT_SYMBOL_GPL(clk_hw_unregister_fixed_rate);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/**
|
||||
* of_fixed_clk_setup() - Setup function for simple fixed rate clock
|
||||
*/
|
||||
void of_fixed_clk_setup(struct device_node *node)
|
||||
static struct clk *_of_fixed_clk_setup(struct device_node *node)
|
||||
{
|
||||
struct clk *clk;
|
||||
const char *clk_name = node->name;
|
||||
u32 rate;
|
||||
u32 accuracy = 0;
|
||||
int ret;
|
||||
|
||||
if (of_property_read_u32(node, "clock-frequency", &rate))
|
||||
return;
|
||||
return ERR_PTR(-EIO);
|
||||
|
||||
of_property_read_u32(node, "clock-accuracy", &accuracy);
|
||||
|
||||
@ -176,9 +175,66 @@ void of_fixed_clk_setup(struct device_node *node)
|
||||
|
||||
clk = clk_register_fixed_rate_with_accuracy(NULL, clk_name, NULL,
|
||||
0, rate, accuracy);
|
||||
if (!IS_ERR(clk))
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
if (IS_ERR(clk))
|
||||
return clk;
|
||||
|
||||
ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
if (ret) {
|
||||
clk_unregister(clk);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_fixed_clk_setup() - Setup function for simple fixed rate clock
|
||||
*/
|
||||
void __init of_fixed_clk_setup(struct device_node *node)
|
||||
{
|
||||
_of_fixed_clk_setup(node);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_fixed_clk_setup);
|
||||
CLK_OF_DECLARE(fixed_clk, "fixed-clock", of_fixed_clk_setup);
|
||||
|
||||
static int of_fixed_clk_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct clk *clk = platform_get_drvdata(pdev);
|
||||
|
||||
clk_unregister_fixed_rate(clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int of_fixed_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
/*
|
||||
* This function is not executed when of_fixed_clk_setup
|
||||
* succeeded.
|
||||
*/
|
||||
clk = _of_fixed_clk_setup(pdev->dev.of_node);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
platform_set_drvdata(pdev, clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id of_fixed_clk_ids[] = {
|
||||
{ .compatible = "fixed-clock" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_fixed_clk_ids);
|
||||
|
||||
static struct platform_driver of_fixed_clk_driver = {
|
||||
.driver = {
|
||||
.name = "of_fixed_clk",
|
||||
.of_match_table = of_fixed_clk_ids,
|
||||
},
|
||||
.probe = of_fixed_clk_probe,
|
||||
.remove = of_fixed_clk_remove,
|
||||
};
|
||||
builtin_platform_driver(of_fixed_clk_driver);
|
||||
#endif
|
||||
|
@ -1,161 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Zhang, Keguang <keguang.zhang@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <loongson1.h>
|
||||
|
||||
#define OSC (33 * 1000000)
|
||||
#define DIV_APB 2
|
||||
|
||||
static DEFINE_SPINLOCK(_lock);
|
||||
|
||||
static int ls1x_pll_clk_enable(struct clk_hw *hw)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ls1x_pll_clk_disable(struct clk_hw *hw)
|
||||
{
|
||||
}
|
||||
|
||||
static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u32 pll, rate;
|
||||
|
||||
pll = __raw_readl(LS1X_CLK_PLL_FREQ);
|
||||
rate = 12 + (pll & 0x3f) + (((pll >> 8) & 0x3ff) >> 10);
|
||||
rate *= OSC;
|
||||
rate >>= 1;
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static const struct clk_ops ls1x_pll_clk_ops = {
|
||||
.enable = ls1x_pll_clk_enable,
|
||||
.disable = ls1x_pll_clk_disable,
|
||||
.recalc_rate = ls1x_pll_recalc_rate,
|
||||
};
|
||||
|
||||
static struct clk *__init clk_register_pll(struct device *dev,
|
||||
const char *name,
|
||||
const char *parent_name,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct clk_hw *hw;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
/* allocate the divider */
|
||||
hw = kzalloc(sizeof(struct clk_hw), GFP_KERNEL);
|
||||
if (!hw) {
|
||||
pr_err("%s: could not allocate clk_hw\n", __func__);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
init.name = name;
|
||||
init.ops = &ls1x_pll_clk_ops;
|
||||
init.flags = flags | CLK_IS_BASIC;
|
||||
init.parent_names = (parent_name ? &parent_name : NULL);
|
||||
init.num_parents = (parent_name ? 1 : 0);
|
||||
hw->init = &init;
|
||||
|
||||
/* register the clock */
|
||||
clk = clk_register(dev, hw);
|
||||
|
||||
if (IS_ERR(clk))
|
||||
kfree(hw);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
static const char * const cpu_parents[] = { "cpu_clk_div", "osc_33m_clk", };
|
||||
static const char * const ahb_parents[] = { "ahb_clk_div", "osc_33m_clk", };
|
||||
static const char * const dc_parents[] = { "dc_clk_div", "osc_33m_clk", };
|
||||
|
||||
void __init ls1x_clk_init(void)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "osc_33m_clk", NULL, 0, OSC);
|
||||
clk_register_clkdev(clk, "osc_33m_clk", NULL);
|
||||
|
||||
/* clock derived from 33 MHz OSC clk */
|
||||
clk = clk_register_pll(NULL, "pll_clk", "osc_33m_clk", 0);
|
||||
clk_register_clkdev(clk, "pll_clk", NULL);
|
||||
|
||||
/* clock derived from PLL clk */
|
||||
/* _____
|
||||
* _______________________| |
|
||||
* OSC ___/ | MUX |___ CPU CLK
|
||||
* \___ PLL ___ CPU DIV ___| |
|
||||
* |_____|
|
||||
*/
|
||||
clk = clk_register_divider(NULL, "cpu_clk_div", "pll_clk",
|
||||
CLK_GET_RATE_NOCACHE, LS1X_CLK_PLL_DIV,
|
||||
DIV_CPU_SHIFT, DIV_CPU_WIDTH,
|
||||
CLK_DIVIDER_ONE_BASED |
|
||||
CLK_DIVIDER_ROUND_CLOSEST, &_lock);
|
||||
clk_register_clkdev(clk, "cpu_clk_div", NULL);
|
||||
clk = clk_register_mux(NULL, "cpu_clk", cpu_parents,
|
||||
ARRAY_SIZE(cpu_parents),
|
||||
CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV,
|
||||
BYPASS_CPU_SHIFT, BYPASS_CPU_WIDTH, 0, &_lock);
|
||||
clk_register_clkdev(clk, "cpu_clk", NULL);
|
||||
|
||||
/* _____
|
||||
* _______________________| |
|
||||
* OSC ___/ | MUX |___ DC CLK
|
||||
* \___ PLL ___ DC DIV ___| |
|
||||
* |_____|
|
||||
*/
|
||||
clk = clk_register_divider(NULL, "dc_clk_div", "pll_clk",
|
||||
0, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT,
|
||||
DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock);
|
||||
clk_register_clkdev(clk, "dc_clk_div", NULL);
|
||||
clk = clk_register_mux(NULL, "dc_clk", dc_parents,
|
||||
ARRAY_SIZE(dc_parents),
|
||||
CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV,
|
||||
BYPASS_DC_SHIFT, BYPASS_DC_WIDTH, 0, &_lock);
|
||||
clk_register_clkdev(clk, "dc_clk", NULL);
|
||||
|
||||
/* _____
|
||||
* _______________________| |
|
||||
* OSC ___/ | MUX |___ DDR CLK
|
||||
* \___ PLL ___ DDR DIV ___| |
|
||||
* |_____|
|
||||
*/
|
||||
clk = clk_register_divider(NULL, "ahb_clk_div", "pll_clk",
|
||||
0, LS1X_CLK_PLL_DIV, DIV_DDR_SHIFT,
|
||||
DIV_DDR_WIDTH, CLK_DIVIDER_ONE_BASED,
|
||||
&_lock);
|
||||
clk_register_clkdev(clk, "ahb_clk_div", NULL);
|
||||
clk = clk_register_mux(NULL, "ahb_clk", ahb_parents,
|
||||
ARRAY_SIZE(ahb_parents),
|
||||
CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV,
|
||||
BYPASS_DDR_SHIFT, BYPASS_DDR_WIDTH, 0, &_lock);
|
||||
clk_register_clkdev(clk, "ahb_clk", NULL);
|
||||
clk_register_clkdev(clk, "stmmaceth", NULL);
|
||||
|
||||
/* clock derived from AHB clk */
|
||||
/* APB clk is always half of the AHB clk */
|
||||
clk = clk_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1,
|
||||
DIV_APB);
|
||||
clk_register_clkdev(clk, "apb_clk", NULL);
|
||||
clk_register_clkdev(clk, "ls1x_i2c", NULL);
|
||||
clk_register_clkdev(clk, "ls1x_pwmtimer", NULL);
|
||||
clk_register_clkdev(clk, "ls1x_spi", NULL);
|
||||
clk_register_clkdev(clk, "ls1x_wdt", NULL);
|
||||
clk_register_clkdev(clk, "serial8250", NULL);
|
||||
}
|
@ -1,194 +0,0 @@
|
||||
/*
|
||||
* clk-max-gen.c - Generic clock driver for Maxim PMICs clocks
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electornics
|
||||
* Jonghwa Lee <jonghwa3.lee@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This driver is based on clk-max77686.c
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include "clk-max-gen.h"
|
||||
|
||||
struct max_gen_clk {
|
||||
struct regmap *regmap;
|
||||
u32 mask;
|
||||
u32 reg;
|
||||
struct clk_hw hw;
|
||||
};
|
||||
|
||||
static struct max_gen_clk *to_max_gen_clk(struct clk_hw *hw)
|
||||
{
|
||||
return container_of(hw, struct max_gen_clk, hw);
|
||||
}
|
||||
|
||||
static int max_gen_clk_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct max_gen_clk *max_gen = to_max_gen_clk(hw);
|
||||
|
||||
return regmap_update_bits(max_gen->regmap, max_gen->reg,
|
||||
max_gen->mask, max_gen->mask);
|
||||
}
|
||||
|
||||
static void max_gen_clk_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct max_gen_clk *max_gen = to_max_gen_clk(hw);
|
||||
|
||||
regmap_update_bits(max_gen->regmap, max_gen->reg,
|
||||
max_gen->mask, ~max_gen->mask);
|
||||
}
|
||||
|
||||
static int max_gen_clk_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct max_gen_clk *max_gen = to_max_gen_clk(hw);
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
ret = regmap_read(max_gen->regmap, max_gen->reg, &val);
|
||||
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return val & max_gen->mask;
|
||||
}
|
||||
|
||||
static unsigned long max_gen_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return 32768;
|
||||
}
|
||||
|
||||
struct clk_ops max_gen_clk_ops = {
|
||||
.prepare = max_gen_clk_prepare,
|
||||
.unprepare = max_gen_clk_unprepare,
|
||||
.is_prepared = max_gen_clk_is_prepared,
|
||||
.recalc_rate = max_gen_recalc_rate,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(max_gen_clk_ops);
|
||||
|
||||
static struct clk *max_gen_clk_register(struct device *dev,
|
||||
struct max_gen_clk *max_gen)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw = &max_gen->hw;
|
||||
int ret;
|
||||
|
||||
clk = devm_clk_register(dev, hw);
|
||||
if (IS_ERR(clk))
|
||||
return clk;
|
||||
|
||||
ret = clk_register_clkdev(clk, hw->init->name, NULL);
|
||||
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
|
||||
u32 reg, struct clk_init_data *clks_init, int num_init)
|
||||
{
|
||||
int i, ret;
|
||||
struct max_gen_clk *max_gen_clks;
|
||||
struct clk **clocks;
|
||||
struct device *dev = pdev->dev.parent;
|
||||
const char *clk_name;
|
||||
struct clk_init_data *init;
|
||||
|
||||
clocks = devm_kzalloc(dev, sizeof(struct clk *) * num_init, GFP_KERNEL);
|
||||
if (!clocks)
|
||||
return -ENOMEM;
|
||||
|
||||
max_gen_clks = devm_kzalloc(dev, sizeof(struct max_gen_clk)
|
||||
* num_init, GFP_KERNEL);
|
||||
if (!max_gen_clks)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < num_init; i++) {
|
||||
max_gen_clks[i].regmap = regmap;
|
||||
max_gen_clks[i].mask = 1 << i;
|
||||
max_gen_clks[i].reg = reg;
|
||||
|
||||
init = devm_kzalloc(dev, sizeof(*init), GFP_KERNEL);
|
||||
if (!init)
|
||||
return -ENOMEM;
|
||||
|
||||
if (dev->of_node &&
|
||||
!of_property_read_string_index(dev->of_node,
|
||||
"clock-output-names",
|
||||
i, &clk_name))
|
||||
init->name = clk_name;
|
||||
else
|
||||
init->name = clks_init[i].name;
|
||||
|
||||
init->ops = clks_init[i].ops;
|
||||
init->flags = clks_init[i].flags;
|
||||
|
||||
max_gen_clks[i].hw.init = init;
|
||||
|
||||
clocks[i] = max_gen_clk_register(dev, &max_gen_clks[i]);
|
||||
if (IS_ERR(clocks[i])) {
|
||||
ret = PTR_ERR(clocks[i]);
|
||||
dev_err(dev, "failed to register %s\n",
|
||||
max_gen_clks[i].hw.init->name);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, clocks);
|
||||
|
||||
if (dev->of_node) {
|
||||
struct clk_onecell_data *of_data;
|
||||
|
||||
of_data = devm_kzalloc(dev, sizeof(*of_data), GFP_KERNEL);
|
||||
if (!of_data)
|
||||
return -ENOMEM;
|
||||
|
||||
of_data->clks = clocks;
|
||||
of_data->clk_num = num_init;
|
||||
ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
|
||||
of_data);
|
||||
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register OF clock provider\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(max_gen_clk_probe);
|
||||
|
||||
int max_gen_clk_remove(struct platform_device *pdev, int num_init)
|
||||
{
|
||||
struct device *dev = pdev->dev.parent;
|
||||
|
||||
if (dev->of_node)
|
||||
of_clk_del_provider(dev->of_node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(max_gen_clk_remove);
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* clk-max-gen.h - Generic clock driver for Maxim PMICs clocks
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CLK_MAX_GEN_H__
|
||||
#define __CLK_MAX_GEN_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
|
||||
u32 reg, struct clk_init_data *clks_init, int num_init);
|
||||
int max_gen_clk_remove(struct platform_device *pdev, int num_init);
|
||||
extern struct clk_ops max_gen_clk_ops;
|
||||
|
||||
#endif /* __CLK_MAX_GEN_H__ */
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* clk-max77686.c - Clock driver for Maxim 77686
|
||||
* clk-max77686.c - Clock driver for Maxim 77686/MAX77802
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electornics
|
||||
* Jonghwa Lee <jonghwa3.lee@samsung.com>
|
||||
@ -25,45 +25,283 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/max77620.h>
|
||||
#include <linux/mfd/max77686.h>
|
||||
#include <linux/mfd/max77686-private.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <dt-bindings/clock/maxim,max77686.h>
|
||||
#include "clk-max-gen.h"
|
||||
#include <dt-bindings/clock/maxim,max77802.h>
|
||||
#include <dt-bindings/clock/maxim,max77620.h>
|
||||
|
||||
static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = {
|
||||
#define MAX77802_CLOCK_LOW_JITTER_SHIFT 0x3
|
||||
|
||||
enum max77686_chip_name {
|
||||
CHIP_MAX77686,
|
||||
CHIP_MAX77802,
|
||||
CHIP_MAX77620,
|
||||
};
|
||||
|
||||
struct max77686_hw_clk_info {
|
||||
const char *name;
|
||||
u32 clk_reg;
|
||||
u32 clk_enable_mask;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
struct max77686_clk_init_data {
|
||||
struct regmap *regmap;
|
||||
struct clk_hw hw;
|
||||
struct clk_init_data clk_idata;
|
||||
const struct max77686_hw_clk_info *clk_info;
|
||||
};
|
||||
|
||||
struct max77686_clk_driver_data {
|
||||
enum max77686_chip_name chip;
|
||||
struct max77686_clk_init_data *max_clk_data;
|
||||
size_t num_clks;
|
||||
};
|
||||
|
||||
static const struct
|
||||
max77686_hw_clk_info max77686_hw_clks_info[MAX77686_CLKS_NUM] = {
|
||||
[MAX77686_CLK_AP] = {
|
||||
.name = "32khz_ap",
|
||||
.ops = &max_gen_clk_ops,
|
||||
.clk_reg = MAX77686_REG_32KHZ,
|
||||
.clk_enable_mask = BIT(MAX77686_CLK_AP),
|
||||
},
|
||||
[MAX77686_CLK_CP] = {
|
||||
.name = "32khz_cp",
|
||||
.ops = &max_gen_clk_ops,
|
||||
.clk_reg = MAX77686_REG_32KHZ,
|
||||
.clk_enable_mask = BIT(MAX77686_CLK_CP),
|
||||
},
|
||||
[MAX77686_CLK_PMIC] = {
|
||||
.name = "32khz_pmic",
|
||||
.ops = &max_gen_clk_ops,
|
||||
.clk_reg = MAX77686_REG_32KHZ,
|
||||
.clk_enable_mask = BIT(MAX77686_CLK_PMIC),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct
|
||||
max77686_hw_clk_info max77802_hw_clks_info[MAX77802_CLKS_NUM] = {
|
||||
[MAX77802_CLK_32K_AP] = {
|
||||
.name = "32khz_ap",
|
||||
.clk_reg = MAX77802_REG_32KHZ,
|
||||
.clk_enable_mask = BIT(MAX77802_CLK_32K_AP),
|
||||
},
|
||||
[MAX77802_CLK_32K_CP] = {
|
||||
.name = "32khz_cp",
|
||||
.clk_reg = MAX77802_REG_32KHZ,
|
||||
.clk_enable_mask = BIT(MAX77802_CLK_32K_CP),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct
|
||||
max77686_hw_clk_info max77620_hw_clks_info[MAX77620_CLKS_NUM] = {
|
||||
[MAX77620_CLK_32K_OUT0] = {
|
||||
.name = "32khz_out0",
|
||||
.clk_reg = MAX77620_REG_CNFG1_32K,
|
||||
.clk_enable_mask = MAX77620_CNFG1_32K_OUT0_EN,
|
||||
},
|
||||
};
|
||||
|
||||
static struct max77686_clk_init_data *to_max77686_clk_init_data(
|
||||
struct clk_hw *hw)
|
||||
{
|
||||
return container_of(hw, struct max77686_clk_init_data, hw);
|
||||
}
|
||||
|
||||
static int max77686_clk_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct max77686_clk_init_data *max77686 = to_max77686_clk_init_data(hw);
|
||||
|
||||
return regmap_update_bits(max77686->regmap, max77686->clk_info->clk_reg,
|
||||
max77686->clk_info->clk_enable_mask,
|
||||
max77686->clk_info->clk_enable_mask);
|
||||
}
|
||||
|
||||
static void max77686_clk_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct max77686_clk_init_data *max77686 = to_max77686_clk_init_data(hw);
|
||||
|
||||
regmap_update_bits(max77686->regmap, max77686->clk_info->clk_reg,
|
||||
max77686->clk_info->clk_enable_mask,
|
||||
~max77686->clk_info->clk_enable_mask);
|
||||
}
|
||||
|
||||
static int max77686_clk_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct max77686_clk_init_data *max77686 = to_max77686_clk_init_data(hw);
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
ret = regmap_read(max77686->regmap, max77686->clk_info->clk_reg, &val);
|
||||
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return val & max77686->clk_info->clk_enable_mask;
|
||||
}
|
||||
|
||||
static unsigned long max77686_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return 32768;
|
||||
}
|
||||
|
||||
static struct clk_ops max77686_clk_ops = {
|
||||
.prepare = max77686_clk_prepare,
|
||||
.unprepare = max77686_clk_unprepare,
|
||||
.is_prepared = max77686_clk_is_prepared,
|
||||
.recalc_rate = max77686_recalc_rate,
|
||||
};
|
||||
|
||||
static struct clk_hw *
|
||||
of_clk_max77686_get(struct of_phandle_args *clkspec, void *data)
|
||||
{
|
||||
struct max77686_clk_driver_data *drv_data = data;
|
||||
unsigned int idx = clkspec->args[0];
|
||||
|
||||
if (idx >= drv_data->num_clks) {
|
||||
pr_err("%s: invalid index %u\n", __func__, idx);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return &drv_data->max_clk_data[idx].hw;
|
||||
}
|
||||
|
||||
static int max77686_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device *parent = dev->parent;
|
||||
const struct platform_device_id *id = platform_get_device_id(pdev);
|
||||
struct max77686_clk_driver_data *drv_data;
|
||||
const struct max77686_hw_clk_info *hw_clks;
|
||||
struct regmap *regmap;
|
||||
int i, ret, num_clks;
|
||||
|
||||
return max_gen_clk_probe(pdev, iodev->regmap, MAX77686_REG_32KHZ,
|
||||
max77686_clks_init, MAX77686_CLKS_NUM);
|
||||
drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL);
|
||||
if (!drv_data)
|
||||
return -ENOMEM;
|
||||
|
||||
regmap = dev_get_regmap(parent, NULL);
|
||||
if (!regmap) {
|
||||
dev_err(dev, "Failed to get rtc regmap\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
drv_data->chip = id->driver_data;
|
||||
|
||||
switch (drv_data->chip) {
|
||||
case CHIP_MAX77686:
|
||||
num_clks = MAX77686_CLKS_NUM;
|
||||
hw_clks = max77686_hw_clks_info;
|
||||
break;
|
||||
|
||||
case CHIP_MAX77802:
|
||||
num_clks = MAX77802_CLKS_NUM;
|
||||
hw_clks = max77802_hw_clks_info;
|
||||
break;
|
||||
|
||||
case CHIP_MAX77620:
|
||||
num_clks = MAX77620_CLKS_NUM;
|
||||
hw_clks = max77620_hw_clks_info;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(dev, "Unknown Chip ID\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
drv_data->max_clk_data = devm_kcalloc(dev, num_clks,
|
||||
sizeof(*drv_data->max_clk_data),
|
||||
GFP_KERNEL);
|
||||
if (!drv_data->max_clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < num_clks; i++) {
|
||||
struct max77686_clk_init_data *max_clk_data;
|
||||
const char *clk_name;
|
||||
|
||||
max_clk_data = &drv_data->max_clk_data[i];
|
||||
|
||||
max_clk_data->regmap = regmap;
|
||||
max_clk_data->clk_info = &hw_clks[i];
|
||||
max_clk_data->clk_idata.flags = hw_clks[i].flags;
|
||||
max_clk_data->clk_idata.ops = &max77686_clk_ops;
|
||||
|
||||
if (parent->of_node &&
|
||||
!of_property_read_string_index(parent->of_node,
|
||||
"clock-output-names",
|
||||
i, &clk_name))
|
||||
max_clk_data->clk_idata.name = clk_name;
|
||||
else
|
||||
max_clk_data->clk_idata.name = hw_clks[i].name;
|
||||
|
||||
max_clk_data->hw.init = &max_clk_data->clk_idata;
|
||||
|
||||
ret = devm_clk_hw_register(dev, &max_clk_data->hw);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to clock register: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_hw_register_clkdev(&max_clk_data->hw,
|
||||
max_clk_data->clk_idata.name, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to clkdev register: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent->of_node) {
|
||||
ret = of_clk_add_hw_provider(parent->of_node, of_clk_max77686_get,
|
||||
drv_data);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to register OF clock provider: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* MAX77802: Enable low-jitter mode on the 32khz clocks. */
|
||||
if (drv_data->chip == CHIP_MAX77802) {
|
||||
ret = regmap_update_bits(regmap, MAX77802_REG_32KHZ,
|
||||
1 << MAX77802_CLOCK_LOW_JITTER_SHIFT,
|
||||
1 << MAX77802_CLOCK_LOW_JITTER_SHIFT);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to config low-jitter: %d\n", ret);
|
||||
goto remove_of_clk_provider;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
remove_of_clk_provider:
|
||||
if (parent->of_node)
|
||||
of_clk_del_provider(parent->of_node);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max77686_clk_remove(struct platform_device *pdev)
|
||||
{
|
||||
return max_gen_clk_remove(pdev, MAX77686_CLKS_NUM);
|
||||
struct device *parent = pdev->dev.parent;
|
||||
|
||||
if (parent->of_node)
|
||||
of_clk_del_provider(parent->of_node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id max77686_clk_id[] = {
|
||||
{ "max77686-clk", 0},
|
||||
{ "max77686-clk", .driver_data = CHIP_MAX77686, },
|
||||
{ "max77802-clk", .driver_data = CHIP_MAX77802, },
|
||||
{ "max77620-clock", .driver_data = CHIP_MAX77620, },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, max77686_clk_id);
|
||||
|
@ -1,96 +0,0 @@
|
||||
/*
|
||||
* clk-max77802.c - Clock driver for Maxim 77802
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electornics
|
||||
* Jonghwa Lee <jonghwa3.lee@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This driver is based on clk-max77686.c
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/max77686-private.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/clkdev.h>
|
||||
|
||||
#include <dt-bindings/clock/maxim,max77802.h>
|
||||
#include "clk-max-gen.h"
|
||||
|
||||
#define MAX77802_CLOCK_OPMODE_MASK 0x1
|
||||
#define MAX77802_CLOCK_LOW_JITTER_SHIFT 0x3
|
||||
|
||||
static struct clk_init_data max77802_clks_init[MAX77802_CLKS_NUM] = {
|
||||
[MAX77802_CLK_32K_AP] = {
|
||||
.name = "32khz_ap",
|
||||
.ops = &max_gen_clk_ops,
|
||||
},
|
||||
[MAX77802_CLK_32K_CP] = {
|
||||
.name = "32khz_cp",
|
||||
.ops = &max_gen_clk_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int max77802_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
|
||||
int ret;
|
||||
|
||||
ret = max_gen_clk_probe(pdev, iodev->regmap, MAX77802_REG_32KHZ,
|
||||
max77802_clks_init, MAX77802_CLKS_NUM);
|
||||
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "generic probe failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enable low-jitter mode on the 32khz clocks. */
|
||||
ret = regmap_update_bits(iodev->regmap, MAX77802_REG_32KHZ,
|
||||
1 << MAX77802_CLOCK_LOW_JITTER_SHIFT,
|
||||
1 << MAX77802_CLOCK_LOW_JITTER_SHIFT);
|
||||
if (ret < 0)
|
||||
dev_err(&pdev->dev, "failed to enable low-jitter mode\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max77802_clk_remove(struct platform_device *pdev)
|
||||
{
|
||||
return max_gen_clk_remove(pdev, MAX77802_CLKS_NUM);
|
||||
}
|
||||
|
||||
static const struct platform_device_id max77802_clk_id[] = {
|
||||
{ "max77802-clk", 0},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, max77802_clk_id);
|
||||
|
||||
static struct platform_driver max77802_clk_driver = {
|
||||
.driver = {
|
||||
.name = "max77802-clk",
|
||||
},
|
||||
.probe = max77802_clk_probe,
|
||||
.remove = max77802_clk_remove,
|
||||
.id_table = max77802_clk_id,
|
||||
};
|
||||
|
||||
module_platform_driver(max77802_clk_driver);
|
||||
|
||||
MODULE_DESCRIPTION("MAXIM 77802 Clock Driver");
|
||||
MODULE_AUTHOR("Javier Martinez Canillas <javier@osg.samsung.com");
|
||||
MODULE_LICENSE("GPL");
|
@ -327,10 +327,11 @@ static struct clk_ops clk_clc_ops = {
|
||||
.set_rate = clc_set_rate,
|
||||
};
|
||||
|
||||
struct clk *mb86s7x_clclk_register(struct device *cpu_dev)
|
||||
static struct clk_hw *mb86s7x_clclk_register(struct device *cpu_dev)
|
||||
{
|
||||
struct clk_init_data init;
|
||||
struct cl_clk *clc;
|
||||
int ret;
|
||||
|
||||
clc = kzalloc(sizeof(*clc), GFP_KERNEL);
|
||||
if (!clc)
|
||||
@ -344,14 +345,17 @@ struct clk *mb86s7x_clclk_register(struct device *cpu_dev)
|
||||
init.flags = CLK_GET_RATE_NOCACHE;
|
||||
init.num_parents = 0;
|
||||
|
||||
return devm_clk_register(cpu_dev, &clc->hw);
|
||||
ret = devm_clk_hw_register(cpu_dev, &clc->hw);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
return &clc->hw;
|
||||
}
|
||||
|
||||
static int mb86s7x_clclk_of_init(void)
|
||||
{
|
||||
int cpu, ret = -ENODEV;
|
||||
struct device_node *np;
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "fujitsu,mb86s70-scb-1.0");
|
||||
if (!np || !of_device_is_available(np))
|
||||
@ -365,12 +369,12 @@ static int mb86s7x_clclk_of_init(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
clk = mb86s7x_clclk_register(cpu_dev);
|
||||
if (IS_ERR(clk)) {
|
||||
hw = mb86s7x_clclk_register(cpu_dev);
|
||||
if (IS_ERR(hw)) {
|
||||
pr_err("failed to register cpu%d clock\n", cpu);
|
||||
continue;
|
||||
}
|
||||
if (clk_register_clkdev(clk, NULL, dev_name(cpu_dev))) {
|
||||
if (clk_hw_register_clkdev(hw, NULL, dev_name(cpu_dev))) {
|
||||
pr_err("failed to register cpu%d clock lookup\n", cpu);
|
||||
continue;
|
||||
}
|
||||
|
@ -19,7 +19,8 @@
|
||||
static void __init moxart_of_pll_clk_init(struct device_node *node)
|
||||
{
|
||||
static void __iomem *base;
|
||||
struct clk *clk, *ref_clk;
|
||||
struct clk_hw *hw;
|
||||
struct clk *ref_clk;
|
||||
unsigned int mul;
|
||||
const char *name = node->name;
|
||||
const char *parent_name;
|
||||
@ -42,14 +43,14 @@ static void __init moxart_of_pll_clk_init(struct device_node *node)
|
||||
return;
|
||||
}
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, name, parent_name, 0, mul, 1);
|
||||
if (IS_ERR(clk)) {
|
||||
hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, mul, 1);
|
||||
if (IS_ERR(hw)) {
|
||||
pr_err("%s: failed to register clock\n", node->full_name);
|
||||
return;
|
||||
}
|
||||
|
||||
clk_register_clkdev(clk, NULL, name);
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
clk_hw_register_clkdev(hw, NULL, name);
|
||||
of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock",
|
||||
moxart_of_pll_clk_init);
|
||||
@ -57,7 +58,8 @@ CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock",
|
||||
static void __init moxart_of_apb_clk_init(struct device_node *node)
|
||||
{
|
||||
static void __iomem *base;
|
||||
struct clk *clk, *pll_clk;
|
||||
struct clk_hw *hw;
|
||||
struct clk *pll_clk;
|
||||
unsigned int div, val;
|
||||
unsigned int div_idx[] = { 2, 3, 4, 6, 8};
|
||||
const char *name = node->name;
|
||||
@ -85,14 +87,14 @@ static void __init moxart_of_apb_clk_init(struct device_node *node)
|
||||
return;
|
||||
}
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, name, parent_name, 0, 1, div);
|
||||
if (IS_ERR(clk)) {
|
||||
hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, 1, div);
|
||||
if (IS_ERR(hw)) {
|
||||
pr_err("%s: failed to register clock\n", node->full_name);
|
||||
return;
|
||||
}
|
||||
|
||||
clk_register_clkdev(clk, NULL, name);
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
clk_hw_register_clkdev(hw, NULL, name);
|
||||
of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
CLK_OF_DECLARE(moxart_apb_clock, "moxa,moxart-apb-clock",
|
||||
moxart_of_apb_clk_init);
|
||||
|
@ -69,7 +69,7 @@ static void __init nspire_ahbdiv_setup(struct device_node *node,
|
||||
{
|
||||
u32 val;
|
||||
void __iomem *io;
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
const char *clk_name = node->name;
|
||||
const char *parent_name;
|
||||
struct nspire_clk_info info;
|
||||
@ -85,10 +85,10 @@ static void __init nspire_ahbdiv_setup(struct device_node *node,
|
||||
of_property_read_string(node, "clock-output-names", &clk_name);
|
||||
parent_name = of_clk_get_parent_name(node, 0);
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, clk_name, parent_name, 0,
|
||||
hw = clk_hw_register_fixed_factor(NULL, clk_name, parent_name, 0,
|
||||
1, info.base_ahb_ratio);
|
||||
if (!IS_ERR(clk))
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
if (!IS_ERR(hw))
|
||||
of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
|
||||
static void __init nspire_ahbdiv_setup_cx(struct device_node *node)
|
||||
@ -111,7 +111,7 @@ static void __init nspire_clk_setup(struct device_node *node,
|
||||
{
|
||||
u32 val;
|
||||
void __iomem *io;
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
const char *clk_name = node->name;
|
||||
struct nspire_clk_info info;
|
||||
|
||||
@ -125,9 +125,10 @@ static void __init nspire_clk_setup(struct device_node *node,
|
||||
|
||||
of_property_read_string(node, "clock-output-names", &clk_name);
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, clk_name, NULL, 0, info.base_clock);
|
||||
if (!IS_ERR(clk))
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
hw = clk_hw_register_fixed_rate(NULL, clk_name, NULL, 0,
|
||||
info.base_clock);
|
||||
if (!IS_ERR(hw))
|
||||
of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
|
||||
else
|
||||
return;
|
||||
|
||||
|
@ -41,7 +41,6 @@ struct palmas_clk32k_desc {
|
||||
|
||||
struct palmas_clock_info {
|
||||
struct device *dev;
|
||||
struct clk *clk;
|
||||
struct clk_hw hw;
|
||||
struct palmas *palmas;
|
||||
const struct palmas_clk32k_desc *clk_desc;
|
||||
@ -218,7 +217,7 @@ static int palmas_clks_init_configure(struct palmas_clock_info *cinfo)
|
||||
}
|
||||
|
||||
if (cinfo->ext_control_pin) {
|
||||
ret = clk_prepare(cinfo->clk);
|
||||
ret = clk_prepare(cinfo->hw.clk);
|
||||
if (ret < 0) {
|
||||
dev_err(cinfo->dev, "Clock prep failed, %d\n", ret);
|
||||
return ret;
|
||||
@ -242,7 +241,6 @@ static int palmas_clks_probe(struct platform_device *pdev)
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
const struct palmas_clks_of_match_data *match_data;
|
||||
struct palmas_clock_info *cinfo;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
match_data = of_device_get_match_data(&pdev->dev);
|
||||
@ -261,22 +259,20 @@ static int palmas_clks_probe(struct platform_device *pdev)
|
||||
|
||||
cinfo->clk_desc = &match_data->desc;
|
||||
cinfo->hw.init = &match_data->init;
|
||||
clk = devm_clk_register(&pdev->dev, &cinfo->hw);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
ret = devm_clk_hw_register(&pdev->dev, &cinfo->hw);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Fail to register clock %s, %d\n",
|
||||
match_data->desc.clk_name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
cinfo->clk = clk;
|
||||
ret = palmas_clks_init_configure(cinfo);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Clock config failed, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = of_clk_add_provider(node, of_clk_src_simple_get, cinfo->clk);
|
||||
ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &cinfo->hw);
|
||||
if (ret < 0)
|
||||
dev_err(&pdev->dev, "Fail to add clock driver, %d\n", ret);
|
||||
return ret;
|
||||
|
@ -61,7 +61,6 @@ static int clk_pwm_probe(struct platform_device *pdev)
|
||||
struct pwm_device *pwm;
|
||||
struct pwm_args pargs;
|
||||
const char *clk_name;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
clk_pwm = devm_kzalloc(&pdev->dev, sizeof(*clk_pwm), GFP_KERNEL);
|
||||
@ -107,11 +106,11 @@ static int clk_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
clk_pwm->pwm = pwm;
|
||||
clk_pwm->hw.init = &init;
|
||||
clk = devm_clk_register(&pdev->dev, &clk_pwm->hw);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
ret = devm_clk_hw_register(&pdev->dev, &clk_pwm->hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
return of_clk_add_hw_provider(node, of_clk_hw_simple_get, &clk_pwm->hw);
|
||||
}
|
||||
|
||||
static int clk_pwm_remove(struct platform_device *pdev)
|
||||
|
@ -766,7 +766,11 @@ static struct clk * __init create_one_cmux(struct clockgen *cg, int idx)
|
||||
if (!hwc)
|
||||
return NULL;
|
||||
|
||||
if (cg->info.flags & CG_VER3)
|
||||
hwc->reg = cg->regs + 0x70000 + 0x20 * idx;
|
||||
else
|
||||
hwc->reg = cg->regs + 0x20 * idx;
|
||||
|
||||
hwc->info = cg->info.cmux_groups[cg->info.cmux_to_group[idx]];
|
||||
|
||||
/*
|
||||
|
@ -22,11 +22,8 @@
|
||||
#include <linux/mfd/rk808.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#define RK808_NR_OUTPUT 2
|
||||
|
||||
struct rk808_clkout {
|
||||
struct rk808 *rk808;
|
||||
struct clk_onecell_data clk_data;
|
||||
struct clk_hw clkout1_hw;
|
||||
struct clk_hw clkout2_hw;
|
||||
};
|
||||
@ -85,14 +82,28 @@ static const struct clk_ops rk808_clkout2_ops = {
|
||||
.recalc_rate = rk808_clkout_recalc_rate,
|
||||
};
|
||||
|
||||
static struct clk_hw *
|
||||
of_clk_rk808_get(struct of_phandle_args *clkspec, void *data)
|
||||
{
|
||||
struct rk808_clkout *rk808_clkout = data;
|
||||
unsigned int idx = clkspec->args[0];
|
||||
|
||||
if (idx >= 2) {
|
||||
pr_err("%s: invalid index %u\n", __func__, idx);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return idx ? &rk808_clkout->clkout2_hw : &rk808_clkout->clkout1_hw;
|
||||
}
|
||||
|
||||
static int rk808_clkout_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct i2c_client *client = rk808->i2c;
|
||||
struct device_node *node = client->dev.of_node;
|
||||
struct clk_init_data init = {};
|
||||
struct clk **clk_table;
|
||||
struct rk808_clkout *rk808_clkout;
|
||||
int ret;
|
||||
|
||||
rk808_clkout = devm_kzalloc(&client->dev,
|
||||
sizeof(*rk808_clkout), GFP_KERNEL);
|
||||
@ -101,11 +112,6 @@ static int rk808_clkout_probe(struct platform_device *pdev)
|
||||
|
||||
rk808_clkout->rk808 = rk808;
|
||||
|
||||
clk_table = devm_kcalloc(&client->dev, RK808_NR_OUTPUT,
|
||||
sizeof(struct clk *), GFP_KERNEL);
|
||||
if (!clk_table)
|
||||
return -ENOMEM;
|
||||
|
||||
init.parent_names = NULL;
|
||||
init.num_parents = 0;
|
||||
init.name = "rk808-clkout1";
|
||||
@ -116,10 +122,9 @@ static int rk808_clkout_probe(struct platform_device *pdev)
|
||||
of_property_read_string_index(node, "clock-output-names",
|
||||
0, &init.name);
|
||||
|
||||
clk_table[0] = devm_clk_register(&client->dev,
|
||||
&rk808_clkout->clkout1_hw);
|
||||
if (IS_ERR(clk_table[0]))
|
||||
return PTR_ERR(clk_table[0]);
|
||||
ret = devm_clk_hw_register(&client->dev, &rk808_clkout->clkout1_hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
init.name = "rk808-clkout2";
|
||||
init.ops = &rk808_clkout2_ops;
|
||||
@ -129,16 +134,11 @@ static int rk808_clkout_probe(struct platform_device *pdev)
|
||||
of_property_read_string_index(node, "clock-output-names",
|
||||
1, &init.name);
|
||||
|
||||
clk_table[1] = devm_clk_register(&client->dev,
|
||||
&rk808_clkout->clkout2_hw);
|
||||
if (IS_ERR(clk_table[1]))
|
||||
return PTR_ERR(clk_table[1]);
|
||||
ret = devm_clk_hw_register(&client->dev, &rk808_clkout->clkout2_hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rk808_clkout->clk_data.clks = clk_table;
|
||||
rk808_clkout->clk_data.clk_num = RK808_NR_OUTPUT;
|
||||
|
||||
return of_clk_add_provider(node, of_clk_src_onecell_get,
|
||||
&rk808_clkout->clk_data);
|
||||
return of_clk_add_hw_provider(node, of_clk_rk808_get, rk808_clkout);
|
||||
}
|
||||
|
||||
static int rk808_clkout_remove(struct platform_device *pdev)
|
||||
|
@ -146,13 +146,13 @@ static const struct of_device_id scpi_clk_match[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static struct clk *
|
||||
static int
|
||||
scpi_clk_ops_init(struct device *dev, const struct of_device_id *match,
|
||||
struct scpi_clk *sclk, const char *name)
|
||||
{
|
||||
struct clk_init_data init;
|
||||
struct clk *clk;
|
||||
unsigned long min = 0, max = 0;
|
||||
int ret;
|
||||
|
||||
init.name = name;
|
||||
init.flags = 0;
|
||||
@ -164,18 +164,18 @@ scpi_clk_ops_init(struct device *dev, const struct of_device_id *match,
|
||||
if (init.ops == &scpi_dvfs_ops) {
|
||||
sclk->info = sclk->scpi_ops->dvfs_get_info(sclk->id);
|
||||
if (IS_ERR(sclk->info))
|
||||
return NULL;
|
||||
return PTR_ERR(sclk->info);
|
||||
} else if (init.ops == &scpi_clk_ops) {
|
||||
if (sclk->scpi_ops->clk_get_range(sclk->id, &min, &max) || !max)
|
||||
return NULL;
|
||||
return -EINVAL;
|
||||
} else {
|
||||
return NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
clk = devm_clk_register(dev, &sclk->hw);
|
||||
if (!IS_ERR(clk) && max)
|
||||
ret = devm_clk_hw_register(dev, &sclk->hw);
|
||||
if (!ret && max)
|
||||
clk_hw_set_rate_range(&sclk->hw, min, max);
|
||||
return clk;
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct scpi_clk_data {
|
||||
@ -183,7 +183,7 @@ struct scpi_clk_data {
|
||||
unsigned int clk_num;
|
||||
};
|
||||
|
||||
static struct clk *
|
||||
static struct clk_hw *
|
||||
scpi_of_clk_src_get(struct of_phandle_args *clkspec, void *data)
|
||||
{
|
||||
struct scpi_clk *sclk;
|
||||
@ -193,7 +193,7 @@ scpi_of_clk_src_get(struct of_phandle_args *clkspec, void *data)
|
||||
for (count = 0; count < clk_data->clk_num; count++) {
|
||||
sclk = clk_data->clk[count];
|
||||
if (idx == sclk->id)
|
||||
return sclk->hw.clk;
|
||||
return &sclk->hw;
|
||||
}
|
||||
|
||||
return ERR_PTR(-EINVAL);
|
||||
@ -202,8 +202,7 @@ scpi_of_clk_src_get(struct of_phandle_args *clkspec, void *data)
|
||||
static int scpi_clk_add(struct device *dev, struct device_node *np,
|
||||
const struct of_device_id *match)
|
||||
{
|
||||
struct clk **clks;
|
||||
int idx, count;
|
||||
int idx, count, err;
|
||||
struct scpi_clk_data *clk_data;
|
||||
|
||||
count = of_property_count_strings(np, "clock-output-names");
|
||||
@ -222,10 +221,6 @@ static int scpi_clk_add(struct device *dev, struct device_node *np,
|
||||
if (!clk_data->clk)
|
||||
return -ENOMEM;
|
||||
|
||||
clks = devm_kcalloc(dev, count, sizeof(*clks), GFP_KERNEL);
|
||||
if (!clks)
|
||||
return -ENOMEM;
|
||||
|
||||
for (idx = 0; idx < count; idx++) {
|
||||
struct scpi_clk *sclk;
|
||||
const char *name;
|
||||
@ -249,15 +244,15 @@ static int scpi_clk_add(struct device *dev, struct device_node *np,
|
||||
|
||||
sclk->id = val;
|
||||
|
||||
clks[idx] = scpi_clk_ops_init(dev, match, sclk, name);
|
||||
if (IS_ERR_OR_NULL(clks[idx]))
|
||||
err = scpi_clk_ops_init(dev, match, sclk, name);
|
||||
if (err)
|
||||
dev_err(dev, "failed to register clock '%s'\n", name);
|
||||
else
|
||||
dev_dbg(dev, "Registered clock '%s'\n", name);
|
||||
clk_data->clk[idx] = sclk;
|
||||
}
|
||||
|
||||
return of_clk_add_provider(np, scpi_of_clk_src_get, clk_data);
|
||||
return of_clk_add_hw_provider(np, scpi_of_clk_src_get, clk_data);
|
||||
}
|
||||
|
||||
static int scpi_clocks_remove(struct platform_device *pdev)
|
||||
|
@ -305,7 +305,6 @@ static int si514_probe(struct i2c_client *client,
|
||||
{
|
||||
struct clk_si514 *data;
|
||||
struct clk_init_data init;
|
||||
struct clk *clk;
|
||||
int err;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
|
||||
@ -330,13 +329,13 @@ static int si514_probe(struct i2c_client *client,
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
|
||||
clk = devm_clk_register(&client->dev, &data->hw);
|
||||
if (IS_ERR(clk)) {
|
||||
err = devm_clk_hw_register(&client->dev, &data->hw);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "clock registration failed\n");
|
||||
return PTR_ERR(clk);
|
||||
return err;
|
||||
}
|
||||
err = of_clk_add_provider(client->dev.of_node, of_clk_src_simple_get,
|
||||
clk);
|
||||
err = of_clk_add_hw_provider(client->dev.of_node, of_clk_hw_simple_get,
|
||||
&data->hw);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "unable to add clk provider\n");
|
||||
return err;
|
||||
|
@ -54,7 +54,6 @@ struct si5351_driver_data {
|
||||
enum si5351_variant variant;
|
||||
struct i2c_client *client;
|
||||
struct regmap *regmap;
|
||||
struct clk_onecell_data onecell;
|
||||
|
||||
struct clk *pxtal;
|
||||
const char *pxtal_name;
|
||||
@ -66,6 +65,7 @@ struct si5351_driver_data {
|
||||
struct si5351_hw_data pll[2];
|
||||
struct si5351_hw_data *msynth;
|
||||
struct si5351_hw_data *clkout;
|
||||
size_t num_clkout;
|
||||
};
|
||||
|
||||
static const char * const si5351_input_names[] = {
|
||||
@ -1307,11 +1307,31 @@ put_child:
|
||||
of_node_put(child);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct clk_hw *
|
||||
si53351_of_clk_get(struct of_phandle_args *clkspec, void *data)
|
||||
{
|
||||
struct si5351_driver_data *drvdata = data;
|
||||
unsigned int idx = clkspec->args[0];
|
||||
|
||||
if (idx >= drvdata->num_clkout) {
|
||||
pr_err("%s: invalid index %u\n", __func__, idx);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return &drvdata->clkout[idx].hw;
|
||||
}
|
||||
#else
|
||||
static int si5351_dt_parse(struct i2c_client *client, enum si5351_variant variant)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clk_hw *
|
||||
si53351_of_clk_get(struct of_phandle_args *clkspec, void *data)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static int si5351_i2c_probe(struct i2c_client *client,
|
||||
@ -1321,7 +1341,6 @@ static int si5351_i2c_probe(struct i2c_client *client,
|
||||
struct si5351_platform_data *pdata;
|
||||
struct si5351_driver_data *drvdata;
|
||||
struct clk_init_data init;
|
||||
struct clk *clk;
|
||||
const char *parent_names[4];
|
||||
u8 num_parents, num_clocks;
|
||||
int ret, n;
|
||||
@ -1438,10 +1457,9 @@ static int si5351_i2c_probe(struct i2c_client *client,
|
||||
init.num_parents = 1;
|
||||
}
|
||||
drvdata->xtal.init = &init;
|
||||
clk = devm_clk_register(&client->dev, &drvdata->xtal);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = devm_clk_hw_register(&client->dev, &drvdata->xtal);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "unable to register %s\n", init.name);
|
||||
ret = PTR_ERR(clk);
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
@ -1456,11 +1474,10 @@ static int si5351_i2c_probe(struct i2c_client *client,
|
||||
init.num_parents = 1;
|
||||
}
|
||||
drvdata->clkin.init = &init;
|
||||
clk = devm_clk_register(&client->dev, &drvdata->clkin);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = devm_clk_hw_register(&client->dev, &drvdata->clkin);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "unable to register %s\n",
|
||||
init.name);
|
||||
ret = PTR_ERR(clk);
|
||||
goto err_clk;
|
||||
}
|
||||
}
|
||||
@ -1480,10 +1497,9 @@ static int si5351_i2c_probe(struct i2c_client *client,
|
||||
init.flags = 0;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
clk = devm_clk_register(&client->dev, &drvdata->pll[0].hw);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = devm_clk_hw_register(&client->dev, &drvdata->pll[0].hw);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "unable to register %s\n", init.name);
|
||||
ret = PTR_ERR(clk);
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
@ -1505,10 +1521,9 @@ static int si5351_i2c_probe(struct i2c_client *client,
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
}
|
||||
clk = devm_clk_register(&client->dev, &drvdata->pll[1].hw);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = devm_clk_hw_register(&client->dev, &drvdata->pll[1].hw);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "unable to register %s\n", init.name);
|
||||
ret = PTR_ERR(clk);
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
@ -1524,13 +1539,9 @@ static int si5351_i2c_probe(struct i2c_client *client,
|
||||
sizeof(*drvdata->msynth), GFP_KERNEL);
|
||||
drvdata->clkout = devm_kzalloc(&client->dev, num_clocks *
|
||||
sizeof(*drvdata->clkout), GFP_KERNEL);
|
||||
drvdata->num_clkout = num_clocks;
|
||||
|
||||
drvdata->onecell.clk_num = num_clocks;
|
||||
drvdata->onecell.clks = devm_kzalloc(&client->dev,
|
||||
num_clocks * sizeof(*drvdata->onecell.clks), GFP_KERNEL);
|
||||
|
||||
if (WARN_ON(!drvdata->msynth || !drvdata->clkout ||
|
||||
!drvdata->onecell.clks)) {
|
||||
if (WARN_ON(!drvdata->msynth || !drvdata->clkout)) {
|
||||
ret = -ENOMEM;
|
||||
goto err_clk;
|
||||
}
|
||||
@ -1547,11 +1558,11 @@ static int si5351_i2c_probe(struct i2c_client *client,
|
||||
init.flags |= CLK_SET_RATE_PARENT;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = 2;
|
||||
clk = devm_clk_register(&client->dev, &drvdata->msynth[n].hw);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = devm_clk_hw_register(&client->dev,
|
||||
&drvdata->msynth[n].hw);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "unable to register %s\n",
|
||||
init.name);
|
||||
ret = PTR_ERR(clk);
|
||||
goto err_clk;
|
||||
}
|
||||
}
|
||||
@ -1575,19 +1586,19 @@ static int si5351_i2c_probe(struct i2c_client *client,
|
||||
init.flags |= CLK_SET_RATE_PARENT;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
clk = devm_clk_register(&client->dev, &drvdata->clkout[n].hw);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = devm_clk_hw_register(&client->dev,
|
||||
&drvdata->clkout[n].hw);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "unable to register %s\n",
|
||||
init.name);
|
||||
ret = PTR_ERR(clk);
|
||||
goto err_clk;
|
||||
}
|
||||
drvdata->onecell.clks[n] = clk;
|
||||
|
||||
/* set initial clkout rate */
|
||||
if (pdata->clkout[n].rate != 0) {
|
||||
int ret;
|
||||
ret = clk_set_rate(clk, pdata->clkout[n].rate);
|
||||
ret = clk_set_rate(drvdata->clkout[n].hw.clk,
|
||||
pdata->clkout[n].rate);
|
||||
if (ret != 0) {
|
||||
dev_err(&client->dev, "Cannot set rate : %d\n",
|
||||
ret);
|
||||
@ -1595,8 +1606,8 @@ static int si5351_i2c_probe(struct i2c_client *client,
|
||||
}
|
||||
}
|
||||
|
||||
ret = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get,
|
||||
&drvdata->onecell);
|
||||
ret = of_clk_add_hw_provider(client->dev.of_node, si53351_of_clk_get,
|
||||
drvdata);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "unable to add clk provider\n");
|
||||
goto err_clk;
|
||||
|
@ -408,7 +408,6 @@ static int si570_probe(struct i2c_client *client,
|
||||
{
|
||||
struct clk_si570 *data;
|
||||
struct clk_init_data init;
|
||||
struct clk *clk;
|
||||
u32 initial_fout, factory_fout, stability;
|
||||
int err;
|
||||
enum clk_si570_variant variant = id->driver_data;
|
||||
@ -462,13 +461,13 @@ static int si570_probe(struct i2c_client *client,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
clk = devm_clk_register(&client->dev, &data->hw);
|
||||
if (IS_ERR(clk)) {
|
||||
err = devm_clk_hw_register(&client->dev, &data->hw);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "clock registration failed\n");
|
||||
return PTR_ERR(clk);
|
||||
return err;
|
||||
}
|
||||
err = of_clk_add_provider(client->dev.of_node, of_clk_src_simple_get,
|
||||
clk);
|
||||
err = of_clk_add_hw_provider(client->dev.of_node, of_clk_hw_simple_get,
|
||||
&data->hw);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "unable to add clk provider\n");
|
||||
return err;
|
||||
@ -477,7 +476,7 @@ static int si570_probe(struct i2c_client *client,
|
||||
/* Read the requested initial output frequency from device tree */
|
||||
if (!of_property_read_u32(client->dev.of_node, "clock-frequency",
|
||||
&initial_fout)) {
|
||||
err = clk_set_rate(clk, initial_fout);
|
||||
err = clk_set_rate(data->hw.clk, initial_fout);
|
||||
if (err) {
|
||||
of_clk_del_provider(client->dev.of_node);
|
||||
return err;
|
||||
|
@ -26,60 +26,73 @@
|
||||
#include <linux/mfd/twl6040.h>
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
struct twl6040_clk {
|
||||
struct twl6040_pdmclk {
|
||||
struct twl6040 *twl6040;
|
||||
struct device *dev;
|
||||
struct clk_hw mcpdm_fclk;
|
||||
struct clk *clk;
|
||||
struct clk_hw pdmclk_hw;
|
||||
int enabled;
|
||||
};
|
||||
|
||||
static int twl6040_bitclk_is_enabled(struct clk_hw *hw)
|
||||
static int twl6040_pdmclk_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk,
|
||||
mcpdm_fclk);
|
||||
return twl6040_clk->enabled;
|
||||
struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk,
|
||||
pdmclk_hw);
|
||||
|
||||
return pdmclk->enabled;
|
||||
}
|
||||
|
||||
static int twl6040_bitclk_prepare(struct clk_hw *hw)
|
||||
static int twl6040_pdmclk_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk,
|
||||
mcpdm_fclk);
|
||||
struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk,
|
||||
pdmclk_hw);
|
||||
int ret;
|
||||
|
||||
ret = twl6040_power(twl6040_clk->twl6040, 1);
|
||||
ret = twl6040_power(pdmclk->twl6040, 1);
|
||||
if (!ret)
|
||||
twl6040_clk->enabled = 1;
|
||||
pdmclk->enabled = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void twl6040_bitclk_unprepare(struct clk_hw *hw)
|
||||
static void twl6040_pdmclk_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk,
|
||||
mcpdm_fclk);
|
||||
struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk,
|
||||
pdmclk_hw);
|
||||
int ret;
|
||||
|
||||
ret = twl6040_power(twl6040_clk->twl6040, 0);
|
||||
ret = twl6040_power(pdmclk->twl6040, 0);
|
||||
if (!ret)
|
||||
twl6040_clk->enabled = 0;
|
||||
pdmclk->enabled = 0;
|
||||
|
||||
}
|
||||
|
||||
static const struct clk_ops twl6040_mcpdm_ops = {
|
||||
.is_enabled = twl6040_bitclk_is_enabled,
|
||||
.prepare = twl6040_bitclk_prepare,
|
||||
.unprepare = twl6040_bitclk_unprepare,
|
||||
static unsigned long twl6040_pdmclk_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk,
|
||||
pdmclk_hw);
|
||||
|
||||
return twl6040_get_sysclk(pdmclk->twl6040);
|
||||
}
|
||||
|
||||
static const struct clk_ops twl6040_pdmclk_ops = {
|
||||
.is_prepared = twl6040_pdmclk_is_prepared,
|
||||
.prepare = twl6040_pdmclk_prepare,
|
||||
.unprepare = twl6040_pdmclk_unprepare,
|
||||
.recalc_rate = twl6040_pdmclk_recalc_rate,
|
||||
};
|
||||
|
||||
static struct clk_init_data wm831x_clkout_init = {
|
||||
.name = "mcpdm_fclk",
|
||||
.ops = &twl6040_mcpdm_ops,
|
||||
static struct clk_init_data twl6040_pdmclk_init = {
|
||||
.name = "pdmclk",
|
||||
.ops = &twl6040_pdmclk_ops,
|
||||
.flags = CLK_GET_RATE_NOCACHE,
|
||||
};
|
||||
|
||||
static int twl6040_clk_probe(struct platform_device *pdev)
|
||||
static int twl6040_pdmclk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct twl6040 *twl6040 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct twl6040_clk *clkdata;
|
||||
struct twl6040_pdmclk *clkdata;
|
||||
int ret;
|
||||
|
||||
clkdata = devm_kzalloc(&pdev->dev, sizeof(*clkdata), GFP_KERNEL);
|
||||
if (!clkdata)
|
||||
@ -88,26 +101,28 @@ static int twl6040_clk_probe(struct platform_device *pdev)
|
||||
clkdata->dev = &pdev->dev;
|
||||
clkdata->twl6040 = twl6040;
|
||||
|
||||
clkdata->mcpdm_fclk.init = &wm831x_clkout_init;
|
||||
clkdata->clk = devm_clk_register(&pdev->dev, &clkdata->mcpdm_fclk);
|
||||
if (IS_ERR(clkdata->clk))
|
||||
return PTR_ERR(clkdata->clk);
|
||||
clkdata->pdmclk_hw.init = &twl6040_pdmclk_init;
|
||||
ret = devm_clk_hw_register(&pdev->dev, &clkdata->pdmclk_hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, clkdata);
|
||||
|
||||
return 0;
|
||||
return of_clk_add_hw_provider(pdev->dev.parent->of_node,
|
||||
of_clk_hw_simple_get,
|
||||
&clkdata->pdmclk_hw);
|
||||
}
|
||||
|
||||
static struct platform_driver twl6040_clk_driver = {
|
||||
static struct platform_driver twl6040_pdmclk_driver = {
|
||||
.driver = {
|
||||
.name = "twl6040-clk",
|
||||
.name = "twl6040-pdmclk",
|
||||
},
|
||||
.probe = twl6040_clk_probe,
|
||||
.probe = twl6040_pdmclk_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(twl6040_clk_driver);
|
||||
module_platform_driver(twl6040_pdmclk_driver);
|
||||
|
||||
MODULE_DESCRIPTION("TWL6040 clock driver for McPDM functional clock");
|
||||
MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
|
||||
MODULE_ALIAS("platform:twl6040-clk");
|
||||
MODULE_ALIAS("platform:twl6040-pdmclk");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user