This time we have a good set of changes to the core framework that do some
general cleanups, but nothing too major. The majority of the diff goes to two SoCs, Actions Semi and Qualcomm. A brand new driver is introduced for Actions Semi so it takes up some lines to add all the different types, and the Qualcomm diff is there because we add support for two SoCs and it's quite a bit of data. Otherwise the big driver updates are on TI Davinci and Amlogic platforms. And then the long tail of driver updates for various fixes and stuff follows after that. Core: - debugfs cleanups removing error checking and an unused provider API - Removal of a clk init typedef that isn't used - Usage of match_string() to simplify parent string name matching - OF clk helpers moved to their own file (linux/of_clk.h) - Make clk warnings more readable across kernel versions New Drivers: - Qualcomm SDM845 GCC and Video clk controllers - Qualcomm MSM8998 GCC - Actions Semi S900 SoC support - Nuvoton npcm750 microcontroller clks - Amlogic axg AO clock controller Removed Drivers: - Deprecated Rockchip clk-gate driver Updates: - debugfs functions stopped checking return values - Support for the MSIOF module clocks on Rensas R-Car M3-N - Support for the new Rensas RZ/G1C and R-Car E3 SoCs - Qualcomm GDSC, RCG, and PLL updates for clk changes in new SoCs - Berlin and Amlogic SPDX tagging - Usage of of_clk_get_parent_count() in more places - Proper implementation of the CDEV1/2 clocks on Tegra20 - Allwinner H6 PRCM clock support and R40 EMAC support - Add critical flag to meson8b's fdiv2 as temporary fixup for ethernet - Round closest support for meson's mpll driver - Support for meson8b nand clocks and gxbb video decoder clocks - Mediatek mali clks - STM32MP1 fixes - Uniphier LD11/LD20 stream demux system clock -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE9L57QeeUxqYDyoaDrQKIl8bklSUFAlsWxugACgkQrQKIl8bk lSVs2A/9HOMsWeiYx1MESrXw6N2UknWeqeT/b1v8L/VOiptJg+OTExPbzmSylngv AXJAfIkCpguSMh9b310pA3DAzk5docmbQ4zL977yY+KXmOcDooCd34aG5a+tB3ie ugC8T2bQLrJdMp3hsqaKZsYzqe7LoW2NJgoliXDMA/QUBLpvHq+fcu2zOawingTA GNc3LGqP5Op7p09aPK30gtQNqLK5qGpHASa/AY7Y0PXlUeTZ8rmF06fcEAg5shkC CT57Zy2rSFB2RorEJarYXDPLRHMw/jxXtpMVXEy7zuz/3ajvvRiZDHv75+NaBru9 hDt1rzslzexEN4fYzj4AtGYRKyBrHbDaxG1qdIWPWVyoE0CEb+dZ1gH7/Ski5r+s z5D28NogC0T0sey6yWssyG3RLvkPJ5nxUhL++siHm1lbyo16LmhB1+nFvxrlzmBB 0V1xqEa7feYpD+JD66lJFb5ornHLwGtVYBpeiY+hrDR3ddWEe1IxaYGR2p9nHwSS Us/ZQdHIYBVEqoo3+BWnTn+HSQzmd/sqHqWnLlVWUHoomm5nXx18PeS87vFbcPv9 dMr+FFJ3Elubzcy5UZJPfNw+pb+teE7tYGQkQ3nbLRxT1YZOoIJZJDqNKxM1cgne 6c/VXJMEyBBn/w7Iru/3eWCZVQJGlmYS47DFDzduFvd3LMfmKIM= =KK/v -----END PGP SIGNATURE----- Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux Pull clk updates from Stephen Boyd: "This time we have a good set of changes to the core framework that do some general cleanups, but nothing too major. The majority of the diff goes to two SoCs, Actions Semi and Qualcomm. A brand new driver is introduced for Actions Semi so it takes up some lines to add all the different types, and the Qualcomm diff is there because we add support for two SoCs and it's quite a bit of data. Otherwise the big driver updates are on TI Davinci and Amlogic platforms. And then the long tail of driver updates for various fixes and stuff follows after that. Core: - debugfs cleanups removing error checking and an unused provider API - Removal of a clk init typedef that isn't used - Usage of match_string() to simplify parent string name matching - OF clk helpers moved to their own file (linux/of_clk.h) - Make clk warnings more readable across kernel versions New Drivers: - Qualcomm SDM845 GCC and Video clk controllers - Qualcomm MSM8998 GCC - Actions Semi S900 SoC support - Nuvoton npcm750 microcontroller clks - Amlogic axg AO clock controller Removed Drivers: - Deprecated Rockchip clk-gate driver Updates: - debugfs functions stopped checking return values - Support for the MSIOF module clocks on Rensas R-Car M3-N - Support for the new Rensas RZ/G1C and R-Car E3 SoCs - Qualcomm GDSC, RCG, and PLL updates for clk changes in new SoCs - Berlin and Amlogic SPDX tagging - Usage of of_clk_get_parent_count() in more places - Proper implementation of the CDEV1/2 clocks on Tegra20 - Allwinner H6 PRCM clock support and R40 EMAC support - Add critical flag to meson8b's fdiv2 as temporary fixup for ethernet - Round closest support for meson's mpll driver - Support for meson8b nand clocks and gxbb video decoder clocks - Mediatek mali clks - STM32MP1 fixes - Uniphier LD11/LD20 stream demux system clock" * tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (134 commits) clk: qcom: Export clk_fabia_pll_configure() clk: bcm: Update and add Stingray clock entries dt-bindings: clk: Update Stingray binding doc clk-si544: Properly round requested frequency to nearest match clk: ingenic: jz4770: Add 150us delay after enabling VPU clock clk: ingenic: jz4770: Enable power of AHB1 bus after ungating VPU clock clk: ingenic: jz4770: Modify C1CLK clock to disable CPU clock stop on idle clk: ingenic: jz4770: Change OTG from custom to standard gated clock clk: ingenic: Support specifying "wait for clock stable" delay clk: ingenic: Add support for clocks whose gate bit is inverted clk: use match_string() helper clk: bcm2835: use match_string() helper clk: Return void from debug_init op clk: remove clk_debugfs_add_file() clk: tegra: no need to check return value of debugfs_create functions clk: davinci: no need to check return value of debugfs_create functions clk: bcm2835: no need to check return value of debugfs_create functions clk: no need to check return value of debugfs_create functions clk: imx6: add EPIT clock support clk: mvebu: use correct bit for 98DX3236 NAND ...
This commit is contained in:
commit
6419945e33
@ -0,0 +1,30 @@
|
||||
MediaTek g3dsys controller
|
||||
============================
|
||||
|
||||
The MediaTek g3dsys controller provides various clocks and reset controller to
|
||||
the GPU.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: Should be:
|
||||
- "mediatek,mt2701-g3dsys", "syscon":
|
||||
for MT2701 SoC
|
||||
- "mediatek,mt7623-g3dsys", "mediatek,mt2701-g3dsys", "syscon":
|
||||
for MT7623 SoC
|
||||
- #clock-cells: Must be 1
|
||||
- #reset-cells: Must be 1
|
||||
|
||||
The g3dsys 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:
|
||||
|
||||
g3dsys: clock-controller@13000000 {
|
||||
compatible = "mediatek,mt7623-g3dsys",
|
||||
"mediatek,mt2701-g3dsys",
|
||||
"syscon";
|
||||
reg = <0 0x13000000 0 0x200>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
47
Documentation/devicetree/bindings/clock/actions,s900-cmu.txt
Normal file
47
Documentation/devicetree/bindings/clock/actions,s900-cmu.txt
Normal file
@ -0,0 +1,47 @@
|
||||
* Actions S900 Clock Management Unit (CMU)
|
||||
|
||||
The Actions S900 clock management unit generates and supplies clock to various
|
||||
controllers within the SoC. The clock binding described here is applicable to
|
||||
S900 SoC.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: should be "actions,s900-cmu"
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- clocks: Reference to the parent clocks ("hosc", "losc")
|
||||
- #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
|
||||
dt-bindings/clock/actions,s900-cmu.h header and can be used in device
|
||||
tree sources.
|
||||
|
||||
External clocks:
|
||||
|
||||
The hosc clock used as input for the plls is generated outside the SoC. It is
|
||||
expected that it is defined using standard clock bindings as "hosc".
|
||||
|
||||
Actions S900 CMU also requires one more clock:
|
||||
- "losc" - internal low frequency oscillator
|
||||
|
||||
Example: Clock Management Unit node:
|
||||
|
||||
cmu: clock-controller@e0160000 {
|
||||
compatible = "actions,s900-cmu";
|
||||
reg = <0x0 0xe0160000 0x0 0x1000>;
|
||||
clocks = <&hosc>, <&losc>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
Example: UART controller node that consumes clock generated by the clock
|
||||
management unit:
|
||||
|
||||
uart: serial@e012a000 {
|
||||
compatible = "actions,s900-uart", "actions,owl-uart";
|
||||
reg = <0x0 0xe012a000 0x0 0x2000>;
|
||||
interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cmu CLK_UART5>;
|
||||
};
|
@ -9,6 +9,7 @@ Required Properties:
|
||||
- GXBB (S905) : "amlogic,meson-gxbb-aoclkc"
|
||||
- GXL (S905X, S905D) : "amlogic,meson-gxl-aoclkc"
|
||||
- GXM (S912) : "amlogic,meson-gxm-aoclkc"
|
||||
- AXG (A113D, A113X) : "amlogic,meson-axg-aoclkc"
|
||||
followed by the common "amlogic,meson-gx-aoclkc"
|
||||
|
||||
- #clock-cells: should be 1.
|
||||
|
@ -276,36 +276,38 @@ These clock IDs are defined in:
|
||||
clk_ts_500_ref genpll2 2 BCM_SR_GENPLL2_TS_500_REF_CLK
|
||||
clk_125_nitro genpll2 3 BCM_SR_GENPLL2_125_NITRO_CLK
|
||||
clk_chimp genpll2 4 BCM_SR_GENPLL2_CHIMP_CLK
|
||||
clk_nic_flash genpll2 5 BCM_SR_GENPLL2_NIC_FLASH
|
||||
clk_nic_flash genpll2 5 BCM_SR_GENPLL2_NIC_FLASH_CLK
|
||||
clk_fs genpll2 6 BCM_SR_GENPLL2_FS_CLK
|
||||
|
||||
genpll3 crystal 0 BCM_SR_GENPLL3
|
||||
clk_hsls genpll3 1 BCM_SR_GENPLL3_HSLS_CLK
|
||||
clk_sdio genpll3 2 BCM_SR_GENPLL3_SDIO_CLK
|
||||
|
||||
genpll4 crystal 0 BCM_SR_GENPLL4
|
||||
ccn genpll4 1 BCM_SR_GENPLL4_CCN_CLK
|
||||
clk_ccn genpll4 1 BCM_SR_GENPLL4_CCN_CLK
|
||||
clk_tpiu_pll genpll4 2 BCM_SR_GENPLL4_TPIU_PLL_CLK
|
||||
noc_clk genpll4 3 BCM_SR_GENPLL4_NOC_CLK
|
||||
clk_noc genpll4 3 BCM_SR_GENPLL4_NOC_CLK
|
||||
clk_chclk_fs4 genpll4 4 BCM_SR_GENPLL4_CHCLK_FS4_CLK
|
||||
clk_bridge_fscpu genpll4 5 BCM_SR_GENPLL4_BRIDGE_FSCPU_CLK
|
||||
|
||||
|
||||
genpll5 crystal 0 BCM_SR_GENPLL5
|
||||
fs4_hf_clk genpll5 1 BCM_SR_GENPLL5_FS4_HF_CLK
|
||||
crypto_ae_clk genpll5 2 BCM_SR_GENPLL5_CRYPTO_AE_CLK
|
||||
raid_ae_clk genpll5 3 BCM_SR_GENPLL5_RAID_AE_CLK
|
||||
clk_fs4_hf genpll5 1 BCM_SR_GENPLL5_FS4_HF_CLK
|
||||
clk_crypto_ae genpll5 2 BCM_SR_GENPLL5_CRYPTO_AE_CLK
|
||||
clk_raid_ae genpll5 3 BCM_SR_GENPLL5_RAID_AE_CLK
|
||||
|
||||
genpll6 crystal 0 BCM_SR_GENPLL6
|
||||
48_usb genpll6 1 BCM_SR_GENPLL6_48_USB_CLK
|
||||
clk_48_usb genpll6 1 BCM_SR_GENPLL6_48_USB_CLK
|
||||
|
||||
lcpll0 crystal 0 BCM_SR_LCPLL0
|
||||
clk_sata_refp lcpll0 1 BCM_SR_LCPLL0_SATA_REFP_CLK
|
||||
clk_sata_refn lcpll0 2 BCM_SR_LCPLL0_SATA_REFN_CLK
|
||||
clk_usb_ref lcpll0 3 BCM_SR_LCPLL0_USB_REF_CLK
|
||||
sata_refpn lcpll0 3 BCM_SR_LCPLL0_SATA_REFPN_CLK
|
||||
clk_sata_350 lcpll0 3 BCM_SR_LCPLL0_SATA_350_CLK
|
||||
clk_sata_500 lcpll0 4 BCM_SR_LCPLL0_SATA_500_CLK
|
||||
|
||||
lcpll1 crystal 0 BCM_SR_LCPLL1
|
||||
wan lcpll1 1 BCM_SR_LCPLL0_WAN_CLK
|
||||
clk_wan lcpll1 1 BCM_SR_LCPLL1_WAN_CLK
|
||||
clk_usb_ref lcpll1 2 BCM_SR_LCPLL1_USB_REF_CLK
|
||||
clk_crmu_ts lcpll1 3 BCM_SR_LCPLL1_CRMU_TS_CLK
|
||||
|
||||
lcpll_pcie crystal 0 BCM_SR_LCPLL_PCIE
|
||||
pcie_phy_ref lcpll1 1 BCM_SR_LCPLL_PCIE_PHY_REF_CLK
|
||||
clk_pcie_phy_ref lcpll1 1 BCM_SR_LCPLL_PCIE_PHY_REF_CLK
|
||||
|
100
Documentation/devicetree/bindings/clock/nuvoton,npcm750-clk.txt
Normal file
100
Documentation/devicetree/bindings/clock/nuvoton,npcm750-clk.txt
Normal file
@ -0,0 +1,100 @@
|
||||
* Nuvoton NPCM7XX Clock Controller
|
||||
|
||||
Nuvoton Poleg BMC NPCM7XX contains an integrated clock controller, which
|
||||
generates and supplies clocks to all modules within the BMC.
|
||||
|
||||
External clocks:
|
||||
|
||||
There are six fixed clocks that are generated outside the BMC. All clocks are of
|
||||
a known fixed value that cannot be changed. clk_refclk, clk_mcbypck and
|
||||
clk_sysbypck are inputs to the clock controller.
|
||||
clk_rg1refck, clk_rg2refck and clk_xin are external clocks suppling the
|
||||
network. They are set on the device tree, but not used by the clock module. The
|
||||
network devices use them directly.
|
||||
Example can be found below.
|
||||
|
||||
All available clocks are defined as preprocessor macros in:
|
||||
dt-bindings/clock/nuvoton,npcm7xx-clock.h
|
||||
and can be reused as DT sources.
|
||||
|
||||
Required Properties of clock controller:
|
||||
|
||||
- compatible: "nuvoton,npcm750-clk" : for clock controller of Nuvoton
|
||||
Poleg BMC NPCM750
|
||||
|
||||
- reg: physical base address of the clock controller and length of
|
||||
memory mapped region.
|
||||
|
||||
- #clock-cells: should be 1.
|
||||
|
||||
Example: Clock controller node:
|
||||
|
||||
clk: clock-controller@f0801000 {
|
||||
compatible = "nuvoton,npcm750-clk";
|
||||
#clock-cells = <1>;
|
||||
reg = <0xf0801000 0x1000>;
|
||||
clock-names = "refclk", "sysbypck", "mcbypck";
|
||||
clocks = <&clk_refclk>, <&clk_sysbypck>, <&clk_mcbypck>;
|
||||
};
|
||||
|
||||
Example: Required external clocks for network:
|
||||
|
||||
/* external reference clock */
|
||||
clk_refclk: clk-refclk {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <25000000>;
|
||||
clock-output-names = "refclk";
|
||||
};
|
||||
|
||||
/* external reference clock for cpu. float in normal operation */
|
||||
clk_sysbypck: clk-sysbypck {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <800000000>;
|
||||
clock-output-names = "sysbypck";
|
||||
};
|
||||
|
||||
/* external reference clock for MC. float in normal operation */
|
||||
clk_mcbypck: clk-mcbypck {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <800000000>;
|
||||
clock-output-names = "mcbypck";
|
||||
};
|
||||
|
||||
/* external clock signal rg1refck, supplied by the phy */
|
||||
clk_rg1refck: clk-rg1refck {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <125000000>;
|
||||
clock-output-names = "clk_rg1refck";
|
||||
};
|
||||
|
||||
/* external clock signal rg2refck, supplied by the phy */
|
||||
clk_rg2refck: clk-rg2refck {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <125000000>;
|
||||
clock-output-names = "clk_rg2refck";
|
||||
};
|
||||
|
||||
clk_xin: clk-xin {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <50000000>;
|
||||
clock-output-names = "clk_xin";
|
||||
};
|
||||
|
||||
|
||||
Example: GMAC controller node that consumes two clocks: a generated clk by the
|
||||
clock controller and a fixed clock from DT (clk_rg1refck).
|
||||
|
||||
ethernet0: ethernet@f0802000 {
|
||||
compatible = "snps,dwmac";
|
||||
reg = <0xf0802000 0x2000>;
|
||||
interrupts = <0 14 4>;
|
||||
interrupt-names = "macirq";
|
||||
clocks = <&clk_rg1refck>, <&clk NPCM7XX_CLK_AHB>;
|
||||
clock-names = "stmmaceth", "clk_gmac";
|
||||
};
|
@ -17,7 +17,9 @@ Required properties :
|
||||
"qcom,gcc-msm8974pro-ac"
|
||||
"qcom,gcc-msm8994"
|
||||
"qcom,gcc-msm8996"
|
||||
"qcom,gcc-msm8998"
|
||||
"qcom,gcc-mdm9615"
|
||||
"qcom,gcc-sdm845"
|
||||
|
||||
- reg : shall contain base register location and length
|
||||
- #clock-cells : shall contain 1
|
||||
|
22
Documentation/devicetree/bindings/clock/qcom,rpmh-clk.txt
Normal file
22
Documentation/devicetree/bindings/clock/qcom,rpmh-clk.txt
Normal file
@ -0,0 +1,22 @@
|
||||
Qualcomm Technologies, Inc. RPMh Clocks
|
||||
-------------------------------------------------------
|
||||
|
||||
Resource Power Manager Hardened (RPMh) manages shared resources on
|
||||
some Qualcomm Technologies Inc. SoCs. It accepts clock requests from
|
||||
other hardware subsystems via RSC to control clocks.
|
||||
|
||||
Required properties :
|
||||
- compatible : shall contain "qcom,sdm845-rpmh-clk"
|
||||
|
||||
- #clock-cells : must contain 1
|
||||
|
||||
Example :
|
||||
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
|
||||
&apps_rsc {
|
||||
rpmhcc: clock-controller {
|
||||
compatible = "qcom,sdm845-rpmh-clk";
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
};
|
19
Documentation/devicetree/bindings/clock/qcom,videocc.txt
Normal file
19
Documentation/devicetree/bindings/clock/qcom,videocc.txt
Normal file
@ -0,0 +1,19 @@
|
||||
Qualcomm Video Clock & Reset Controller Binding
|
||||
-----------------------------------------------
|
||||
|
||||
Required properties :
|
||||
- compatible : shall contain "qcom,sdm845-videocc"
|
||||
- reg : shall contain base register location and length
|
||||
- #clock-cells : from common clock binding, shall contain 1.
|
||||
- #power-domain-cells : from generic power domain binding, shall contain 1.
|
||||
|
||||
Optional properties :
|
||||
- #reset-cells : from common reset binding, shall contain 1.
|
||||
|
||||
Example:
|
||||
videocc: clock-controller@ab00000 {
|
||||
compatible = "qcom,sdm845-videocc";
|
||||
reg = <0xab00000 0x10000>;
|
||||
#clock-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
@ -15,6 +15,7 @@ Required Properties:
|
||||
- compatible: Must be one of:
|
||||
- "renesas,r8a7743-cpg-mssr" for the r8a7743 SoC (RZ/G1M)
|
||||
- "renesas,r8a7745-cpg-mssr" for the r8a7745 SoC (RZ/G1E)
|
||||
- "renesas,r8a77470-cpg-mssr" for the r8a77470 SoC (RZ/G1C)
|
||||
- "renesas,r8a7790-cpg-mssr" for the r8a7790 SoC (R-Car H2)
|
||||
- "renesas,r8a7791-cpg-mssr" for the r8a7791 SoC (R-Car M2-W)
|
||||
- "renesas,r8a7792-cpg-mssr" for the r8a7792 SoC (R-Car V2H)
|
||||
@ -25,6 +26,7 @@ Required Properties:
|
||||
- "renesas,r8a77965-cpg-mssr" for the r8a77965 SoC (R-Car M3-N)
|
||||
- "renesas,r8a77970-cpg-mssr" for the r8a77970 SoC (R-Car V3M)
|
||||
- "renesas,r8a77980-cpg-mssr" for the r8a77980 SoC (R-Car V3H)
|
||||
- "renesas,r8a77990-cpg-mssr" for the r8a77990 SoC (R-Car E3)
|
||||
- "renesas,r8a77995-cpg-mssr" for the r8a77995 SoC (R-Car D3)
|
||||
|
||||
- reg: Base address and length of the memory resource used by the CPG/MSSR
|
||||
@ -33,10 +35,12 @@ Required Properties:
|
||||
- clocks: References to external parent clocks, one entry for each entry in
|
||||
clock-names
|
||||
- clock-names: List of external parent clock names. Valid names are:
|
||||
- "extal" (r8a7743, r8a7745, r8a7790, r8a7791, r8a7792, r8a7793, r8a7794,
|
||||
r8a7795, r8a7796, r8a77965, r8a77970, r8a77980, r8a77995)
|
||||
- "extal" (r8a7743, r8a7745, r8a77470, r8a7790, r8a7791, r8a7792,
|
||||
r8a7793, r8a7794, r8a7795, r8a7796, r8a77965, r8a77970,
|
||||
r8a77980, r8a77990, r8a77995)
|
||||
- "extalr" (r8a7795, r8a7796, r8a77965, r8a77970, r8a77980)
|
||||
- "usb_extal" (r8a7743, r8a7745, r8a7790, r8a7791, r8a7793, r8a7794)
|
||||
- "usb_extal" (r8a7743, r8a7745, r8a77470, r8a7790, r8a7791, r8a7793,
|
||||
r8a7794)
|
||||
|
||||
- #clock-cells: Must be 2
|
||||
- For CPG core clocks, the two clock specifier cells must be "CPG_CORE"
|
||||
|
@ -1,77 +0,0 @@
|
||||
Device Tree Clock bindings for arch-rockchip
|
||||
|
||||
This binding uses the common clock binding[1].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
== Gate clocks ==
|
||||
|
||||
These bindings are deprecated!
|
||||
Please use the soc specific CRU bindings instead.
|
||||
|
||||
The gate registers form a continuos block which makes the dt node
|
||||
structure a matter of taste, as either all gates can be put into
|
||||
one gate clock spanning all registers or they can be divided into
|
||||
the 10 individual gates containing 16 clocks each.
|
||||
The code supports both approaches.
|
||||
|
||||
Required properties:
|
||||
- compatible : "rockchip,rk2928-gate-clk"
|
||||
- reg : shall be the control register address(es) for the clock.
|
||||
- #clock-cells : from common clock binding; shall be set to 1
|
||||
- clock-output-names : the corresponding gate names that the clock controls
|
||||
- clocks : should contain the parent clock for each individual gate,
|
||||
therefore the number of clocks elements should match the number of
|
||||
clock-output-names
|
||||
|
||||
Example using multiple gate clocks:
|
||||
|
||||
clk_gates0: gate-clk@200000d0 {
|
||||
compatible = "rockchip,rk2928-gate-clk";
|
||||
reg = <0x200000d0 0x4>;
|
||||
clocks = <&dummy>, <&dummy>,
|
||||
<&dummy>, <&dummy>,
|
||||
<&dummy>, <&dummy>,
|
||||
<&dummy>, <&dummy>,
|
||||
<&dummy>, <&dummy>,
|
||||
<&dummy>, <&dummy>,
|
||||
<&dummy>, <&dummy>,
|
||||
<&dummy>, <&dummy>;
|
||||
|
||||
clock-output-names =
|
||||
"gate_core_periph", "gate_cpu_gpll",
|
||||
"gate_ddrphy", "gate_aclk_cpu",
|
||||
"gate_hclk_cpu", "gate_pclk_cpu",
|
||||
"gate_atclk_cpu", "gate_i2s0",
|
||||
"gate_i2s0_frac", "gate_i2s1",
|
||||
"gate_i2s1_frac", "gate_i2s2",
|
||||
"gate_i2s2_frac", "gate_spdif",
|
||||
"gate_spdif_frac", "gate_testclk";
|
||||
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
clk_gates1: gate-clk@200000d4 {
|
||||
compatible = "rockchip,rk2928-gate-clk";
|
||||
reg = <0x200000d4 0x4>;
|
||||
clocks = <&xin24m>, <&xin24m>,
|
||||
<&xin24m>, <&dummy>,
|
||||
<&dummy>, <&xin24m>,
|
||||
<&xin24m>, <&dummy>,
|
||||
<&xin24m>, <&dummy>,
|
||||
<&xin24m>, <&dummy>,
|
||||
<&xin24m>, <&dummy>,
|
||||
<&xin24m>, <&dummy>;
|
||||
|
||||
clock-output-names =
|
||||
"gate_timer0", "gate_timer1",
|
||||
"gate_timer2", "gate_jtag",
|
||||
"gate_aclk_lcdc1_src", "gate_otgphy0",
|
||||
"gate_otgphy1", "gate_ddr_gpll",
|
||||
"gate_uart0", "gate_frac_uart0",
|
||||
"gate_uart1", "gate_frac_uart1",
|
||||
"gate_uart2", "gate_frac_uart2",
|
||||
"gate_uart3", "gate_frac_uart3";
|
||||
|
||||
#clock-cells = <1>;
|
||||
};
|
@ -21,6 +21,7 @@ Required properties :
|
||||
- "allwinner,sun50i-a64-r-ccu"
|
||||
- "allwinner,sun50i-h5-ccu"
|
||||
- "allwinner,sun50i-h6-ccu"
|
||||
- "allwinner,sun50i-h6-r-ccu"
|
||||
- "nextthing,gr8-ccu"
|
||||
|
||||
- reg: Must contain the registers base address and length
|
||||
@ -35,7 +36,7 @@ Required properties :
|
||||
For the main CCU on H6, one more clock is needed:
|
||||
- "iosc": the SoC's internal frequency oscillator
|
||||
|
||||
For the PRCM CCUs on A83T/H3/A64, two more clocks are needed:
|
||||
For the PRCM CCUs on A83T/H3/A64/H6, two more clocks are needed:
|
||||
- "pll-periph": the SoC's peripheral PLL from the main CCU
|
||||
- "iosc": the SoC's internal frequency oscillator
|
||||
|
||||
|
@ -96,7 +96,7 @@ the operations defined in clk-provider.h::
|
||||
int (*get_phase)(struct clk_hw *hw);
|
||||
int (*set_phase)(struct clk_hw *hw, int degrees);
|
||||
void (*init)(struct clk_hw *hw);
|
||||
int (*debug_init)(struct clk_hw *hw,
|
||||
void (*debug_init)(struct clk_hw *hw,
|
||||
struct dentry *dentry);
|
||||
};
|
||||
|
||||
|
@ -3587,6 +3587,7 @@ F: drivers/clk/
|
||||
X: drivers/clk/clkdev.c
|
||||
F: include/linux/clk-pr*
|
||||
F: include/linux/clk/
|
||||
F: include/linux/of_clk.h
|
||||
|
||||
COMMON INTERNET FILE SYSTEM (CIFS)
|
||||
M: Steve French <sfrench@samba.org>
|
||||
|
@ -120,7 +120,7 @@
|
||||
<GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX7D_ENET_AXI_ROOT_CLK>,
|
||||
clocks = <&clks IMX7D_ENET2_IPG_ROOT_CLK>,
|
||||
<&clks IMX7D_ENET_AXI_ROOT_CLK>,
|
||||
<&clks IMX7D_ENET2_TIME_ROOT_CLK>,
|
||||
<&clks IMX7D_PLL_ENET_MAIN_125M_CLK>,
|
||||
|
@ -1092,7 +1092,7 @@
|
||||
<GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX7D_ENET_AXI_ROOT_CLK>,
|
||||
clocks = <&clks IMX7D_ENET1_IPG_ROOT_CLK>,
|
||||
<&clks IMX7D_ENET_AXI_ROOT_CLK>,
|
||||
<&clks IMX7D_ENET1_TIME_ROOT_CLK>,
|
||||
<&clks IMX7D_PLL_ENET_MAIN_125M_CLK>,
|
||||
|
@ -277,6 +277,7 @@ config COMMON_CLK_STM32H7
|
||||
---help---
|
||||
Support for stm32h7 SoC family clocks
|
||||
|
||||
source "drivers/clk/actions/Kconfig"
|
||||
source "drivers/clk/bcm/Kconfig"
|
||||
source "drivers/clk/hisilicon/Kconfig"
|
||||
source "drivers/clk/imgtec/Kconfig"
|
||||
|
@ -33,6 +33,7 @@ obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o
|
||||
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
|
||||
obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o
|
||||
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
|
||||
obj-$(CONFIG_ARCH_NPCM7XX) += clk-npcm7xx.o
|
||||
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
|
||||
obj-$(CONFIG_COMMON_CLK_OXNAS) += clk-oxnas.o
|
||||
obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o
|
||||
@ -59,6 +60,7 @@ obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
|
||||
obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o
|
||||
|
||||
# please keep this section sorted lexicographically by directory path name
|
||||
obj-y += actions/
|
||||
obj-$(CONFIG_COMMON_CLK_AT91) += at91/
|
||||
obj-$(CONFIG_ARCH_ARTPEC) += axis/
|
||||
obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/
|
||||
|
14
drivers/clk/actions/Kconfig
Normal file
14
drivers/clk/actions/Kconfig
Normal file
@ -0,0 +1,14 @@
|
||||
config CLK_ACTIONS
|
||||
bool "Clock driver for Actions Semi SoCs"
|
||||
depends on ARCH_ACTIONS || COMPILE_TEST
|
||||
default ARCH_ACTIONS
|
||||
|
||||
if CLK_ACTIONS
|
||||
|
||||
# SoC Drivers
|
||||
|
||||
config CLK_OWL_S900
|
||||
bool "Support for the Actions Semi OWL S900 clocks"
|
||||
depends on (ARM64 && ARCH_ACTIONS) || COMPILE_TEST
|
||||
default ARM64 && ARCH_ACTIONS
|
||||
endif
|
12
drivers/clk/actions/Makefile
Normal file
12
drivers/clk/actions/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
obj-$(CONFIG_CLK_ACTIONS) += clk-owl.o
|
||||
|
||||
clk-owl-y += owl-common.o
|
||||
clk-owl-y += owl-gate.o
|
||||
clk-owl-y += owl-mux.o
|
||||
clk-owl-y += owl-divider.o
|
||||
clk-owl-y += owl-factor.o
|
||||
clk-owl-y += owl-composite.o
|
||||
clk-owl-y += owl-pll.o
|
||||
|
||||
# SoC support
|
||||
obj-$(CONFIG_CLK_OWL_S900) += owl-s900.o
|
89
drivers/clk/actions/owl-common.c
Normal file
89
drivers/clk/actions/owl-common.c
Normal file
@ -0,0 +1,89 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// OWL common clock driver
|
||||
//
|
||||
// Copyright (c) 2014 Actions Semi Inc.
|
||||
// Author: David Liu <liuwei@actions-semi.com>
|
||||
//
|
||||
// Copyright (c) 2018 Linaro Ltd.
|
||||
// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "owl-common.h"
|
||||
|
||||
static const struct regmap_config owl_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.max_register = 0x00cc,
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
static void owl_clk_set_regmap(const struct owl_clk_desc *desc,
|
||||
struct regmap *regmap)
|
||||
{
|
||||
int i;
|
||||
struct owl_clk_common *clks;
|
||||
|
||||
for (i = 0; i < desc->num_clks; i++) {
|
||||
clks = desc->clks[i];
|
||||
if (!clks)
|
||||
continue;
|
||||
|
||||
clks->regmap = regmap;
|
||||
}
|
||||
}
|
||||
|
||||
int owl_clk_regmap_init(struct platform_device *pdev,
|
||||
const struct owl_clk_desc *desc)
|
||||
{
|
||||
void __iomem *base;
|
||||
struct regmap *regmap;
|
||||
struct resource *res;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
regmap = devm_regmap_init_mmio(&pdev->dev, base, &owl_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
pr_err("failed to init regmap\n");
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
owl_clk_set_regmap(desc, regmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int owl_clk_probe(struct device *dev, struct clk_hw_onecell_data *hw_clks)
|
||||
{
|
||||
int i, ret;
|
||||
struct clk_hw *hw;
|
||||
|
||||
for (i = 0; i < hw_clks->num; i++) {
|
||||
|
||||
hw = hw_clks->hws[i];
|
||||
|
||||
if (IS_ERR_OR_NULL(hw))
|
||||
continue;
|
||||
|
||||
ret = devm_clk_hw_register(dev, hw);
|
||||
if (ret) {
|
||||
dev_err(dev, "Couldn't register clock %d - %s\n",
|
||||
i, hw->init->name);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, hw_clks);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to add clock provider\n");
|
||||
|
||||
return ret;
|
||||
}
|
41
drivers/clk/actions/owl-common.h
Normal file
41
drivers/clk/actions/owl-common.h
Normal file
@ -0,0 +1,41 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// OWL common clock driver
|
||||
//
|
||||
// Copyright (c) 2014 Actions Semi Inc.
|
||||
// Author: David Liu <liuwei@actions-semi.com>
|
||||
//
|
||||
// Copyright (c) 2018 Linaro Ltd.
|
||||
// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
#ifndef _OWL_COMMON_H_
|
||||
#define _OWL_COMMON_H_
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
struct device_node;
|
||||
|
||||
struct owl_clk_common {
|
||||
struct regmap *regmap;
|
||||
struct clk_hw hw;
|
||||
};
|
||||
|
||||
struct owl_clk_desc {
|
||||
struct owl_clk_common **clks;
|
||||
unsigned long num_clks;
|
||||
struct clk_hw_onecell_data *hw_clks;
|
||||
};
|
||||
|
||||
static inline struct owl_clk_common *
|
||||
hw_to_owl_clk_common(const struct clk_hw *hw)
|
||||
{
|
||||
return container_of(hw, struct owl_clk_common, hw);
|
||||
}
|
||||
|
||||
int owl_clk_regmap_init(struct platform_device *pdev,
|
||||
const struct owl_clk_desc *desc);
|
||||
int owl_clk_probe(struct device *dev, struct clk_hw_onecell_data *hw_clks);
|
||||
|
||||
#endif /* _OWL_COMMON_H_ */
|
199
drivers/clk/actions/owl-composite.c
Normal file
199
drivers/clk/actions/owl-composite.c
Normal file
@ -0,0 +1,199 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// OWL composite clock driver
|
||||
//
|
||||
// Copyright (c) 2014 Actions Semi Inc.
|
||||
// Author: David Liu <liuwei@actions-semi.com>
|
||||
//
|
||||
// Copyright (c) 2018 Linaro Ltd.
|
||||
// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "owl-composite.h"
|
||||
|
||||
static u8 owl_comp_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct owl_composite *comp = hw_to_owl_comp(hw);
|
||||
|
||||
return owl_mux_helper_get_parent(&comp->common, &comp->mux_hw);
|
||||
}
|
||||
|
||||
static int owl_comp_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct owl_composite *comp = hw_to_owl_comp(hw);
|
||||
|
||||
return owl_mux_helper_set_parent(&comp->common, &comp->mux_hw, index);
|
||||
}
|
||||
|
||||
static void owl_comp_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct owl_composite *comp = hw_to_owl_comp(hw);
|
||||
struct owl_clk_common *common = &comp->common;
|
||||
|
||||
owl_gate_set(common, &comp->gate_hw, false);
|
||||
}
|
||||
|
||||
static int owl_comp_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct owl_composite *comp = hw_to_owl_comp(hw);
|
||||
struct owl_clk_common *common = &comp->common;
|
||||
|
||||
owl_gate_set(common, &comp->gate_hw, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int owl_comp_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct owl_composite *comp = hw_to_owl_comp(hw);
|
||||
struct owl_clk_common *common = &comp->common;
|
||||
|
||||
return owl_gate_clk_is_enabled(common, &comp->gate_hw);
|
||||
}
|
||||
|
||||
static long owl_comp_div_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct owl_composite *comp = hw_to_owl_comp(hw);
|
||||
|
||||
return owl_divider_helper_round_rate(&comp->common, &comp->rate.div_hw,
|
||||
rate, parent_rate);
|
||||
}
|
||||
|
||||
static unsigned long owl_comp_div_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct owl_composite *comp = hw_to_owl_comp(hw);
|
||||
|
||||
return owl_divider_helper_recalc_rate(&comp->common, &comp->rate.div_hw,
|
||||
parent_rate);
|
||||
}
|
||||
|
||||
static int owl_comp_div_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct owl_composite *comp = hw_to_owl_comp(hw);
|
||||
|
||||
return owl_divider_helper_set_rate(&comp->common, &comp->rate.div_hw,
|
||||
rate, parent_rate);
|
||||
}
|
||||
|
||||
static long owl_comp_fact_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct owl_composite *comp = hw_to_owl_comp(hw);
|
||||
|
||||
return owl_factor_helper_round_rate(&comp->common,
|
||||
&comp->rate.factor_hw,
|
||||
rate, parent_rate);
|
||||
}
|
||||
|
||||
static unsigned long owl_comp_fact_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct owl_composite *comp = hw_to_owl_comp(hw);
|
||||
|
||||
return owl_factor_helper_recalc_rate(&comp->common,
|
||||
&comp->rate.factor_hw,
|
||||
parent_rate);
|
||||
}
|
||||
|
||||
static int owl_comp_fact_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct owl_composite *comp = hw_to_owl_comp(hw);
|
||||
|
||||
return owl_factor_helper_set_rate(&comp->common,
|
||||
&comp->rate.factor_hw,
|
||||
rate, parent_rate);
|
||||
}
|
||||
|
||||
static long owl_comp_fix_fact_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct owl_composite *comp = hw_to_owl_comp(hw);
|
||||
struct clk_fixed_factor *fix_fact_hw = &comp->rate.fix_fact_hw;
|
||||
|
||||
return comp->fix_fact_ops->round_rate(&fix_fact_hw->hw, rate, parent_rate);
|
||||
}
|
||||
|
||||
static unsigned long owl_comp_fix_fact_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct owl_composite *comp = hw_to_owl_comp(hw);
|
||||
struct clk_fixed_factor *fix_fact_hw = &comp->rate.fix_fact_hw;
|
||||
|
||||
return comp->fix_fact_ops->recalc_rate(&fix_fact_hw->hw, parent_rate);
|
||||
|
||||
}
|
||||
|
||||
static int owl_comp_fix_fact_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
/*
|
||||
* We must report success but we can do so unconditionally because
|
||||
* owl_comp_fix_fact_round_rate returns values that ensure this call is
|
||||
* a nop.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct clk_ops owl_comp_div_ops = {
|
||||
/* mux_ops */
|
||||
.get_parent = owl_comp_get_parent,
|
||||
.set_parent = owl_comp_set_parent,
|
||||
|
||||
/* gate_ops */
|
||||
.disable = owl_comp_disable,
|
||||
.enable = owl_comp_enable,
|
||||
.is_enabled = owl_comp_is_enabled,
|
||||
|
||||
/* div_ops */
|
||||
.round_rate = owl_comp_div_round_rate,
|
||||
.recalc_rate = owl_comp_div_recalc_rate,
|
||||
.set_rate = owl_comp_div_set_rate,
|
||||
};
|
||||
|
||||
|
||||
const struct clk_ops owl_comp_fact_ops = {
|
||||
/* mux_ops */
|
||||
.get_parent = owl_comp_get_parent,
|
||||
.set_parent = owl_comp_set_parent,
|
||||
|
||||
/* gate_ops */
|
||||
.disable = owl_comp_disable,
|
||||
.enable = owl_comp_enable,
|
||||
.is_enabled = owl_comp_is_enabled,
|
||||
|
||||
/* fact_ops */
|
||||
.round_rate = owl_comp_fact_round_rate,
|
||||
.recalc_rate = owl_comp_fact_recalc_rate,
|
||||
.set_rate = owl_comp_fact_set_rate,
|
||||
};
|
||||
|
||||
const struct clk_ops owl_comp_fix_fact_ops = {
|
||||
/* gate_ops */
|
||||
.disable = owl_comp_disable,
|
||||
.enable = owl_comp_enable,
|
||||
.is_enabled = owl_comp_is_enabled,
|
||||
|
||||
/* fix_fact_ops */
|
||||
.round_rate = owl_comp_fix_fact_round_rate,
|
||||
.recalc_rate = owl_comp_fix_fact_recalc_rate,
|
||||
.set_rate = owl_comp_fix_fact_set_rate,
|
||||
};
|
||||
|
||||
|
||||
const struct clk_ops owl_comp_pass_ops = {
|
||||
/* mux_ops */
|
||||
.get_parent = owl_comp_get_parent,
|
||||
.set_parent = owl_comp_set_parent,
|
||||
|
||||
/* gate_ops */
|
||||
.disable = owl_comp_disable,
|
||||
.enable = owl_comp_enable,
|
||||
.is_enabled = owl_comp_is_enabled,
|
||||
};
|
124
drivers/clk/actions/owl-composite.h
Normal file
124
drivers/clk/actions/owl-composite.h
Normal file
@ -0,0 +1,124 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// OWL composite clock driver
|
||||
//
|
||||
// Copyright (c) 2014 Actions Semi Inc.
|
||||
// Author: David Liu <liuwei@actions-semi.com>
|
||||
//
|
||||
// Copyright (c) 2018 Linaro Ltd.
|
||||
// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
#ifndef _OWL_COMPOSITE_H_
|
||||
#define _OWL_COMPOSITE_H_
|
||||
|
||||
#include "owl-common.h"
|
||||
#include "owl-mux.h"
|
||||
#include "owl-gate.h"
|
||||
#include "owl-factor.h"
|
||||
#include "owl-fixed-factor.h"
|
||||
#include "owl-divider.h"
|
||||
|
||||
union owl_rate {
|
||||
struct owl_divider_hw div_hw;
|
||||
struct owl_factor_hw factor_hw;
|
||||
struct clk_fixed_factor fix_fact_hw;
|
||||
};
|
||||
|
||||
struct owl_composite {
|
||||
struct owl_mux_hw mux_hw;
|
||||
struct owl_gate_hw gate_hw;
|
||||
union owl_rate rate;
|
||||
|
||||
const struct clk_ops *fix_fact_ops;
|
||||
|
||||
struct owl_clk_common common;
|
||||
};
|
||||
|
||||
#define OWL_COMP_DIV(_struct, _name, _parent, \
|
||||
_mux, _gate, _div, _flags) \
|
||||
struct owl_composite _struct = { \
|
||||
.mux_hw = _mux, \
|
||||
.gate_hw = _gate, \
|
||||
.rate.div_hw = _div, \
|
||||
.common = { \
|
||||
.regmap = NULL, \
|
||||
.hw.init = CLK_HW_INIT_PARENTS(_name, \
|
||||
_parent, \
|
||||
&owl_comp_div_ops,\
|
||||
_flags), \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define OWL_COMP_DIV_FIXED(_struct, _name, _parent, \
|
||||
_gate, _div, _flags) \
|
||||
struct owl_composite _struct = { \
|
||||
.gate_hw = _gate, \
|
||||
.rate.div_hw = _div, \
|
||||
.common = { \
|
||||
.regmap = NULL, \
|
||||
.hw.init = CLK_HW_INIT(_name, \
|
||||
_parent, \
|
||||
&owl_comp_div_ops,\
|
||||
_flags), \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define OWL_COMP_FACTOR(_struct, _name, _parent, \
|
||||
_mux, _gate, _factor, _flags) \
|
||||
struct owl_composite _struct = { \
|
||||
.mux_hw = _mux, \
|
||||
.gate_hw = _gate, \
|
||||
.rate.factor_hw = _factor, \
|
||||
.common = { \
|
||||
.regmap = NULL, \
|
||||
.hw.init = CLK_HW_INIT_PARENTS(_name, \
|
||||
_parent, \
|
||||
&owl_comp_fact_ops,\
|
||||
_flags), \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define OWL_COMP_FIXED_FACTOR(_struct, _name, _parent, \
|
||||
_gate, _mul, _div, _flags) \
|
||||
struct owl_composite _struct = { \
|
||||
.gate_hw = _gate, \
|
||||
.rate.fix_fact_hw.mult = _mul, \
|
||||
.rate.fix_fact_hw.div = _div, \
|
||||
.fix_fact_ops = &clk_fixed_factor_ops, \
|
||||
.common = { \
|
||||
.regmap = NULL, \
|
||||
.hw.init = CLK_HW_INIT(_name, \
|
||||
_parent, \
|
||||
&owl_comp_fix_fact_ops,\
|
||||
_flags), \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define OWL_COMP_PASS(_struct, _name, _parent, \
|
||||
_mux, _gate, _flags) \
|
||||
struct owl_composite _struct = { \
|
||||
.mux_hw = _mux, \
|
||||
.gate_hw = _gate, \
|
||||
.common = { \
|
||||
.regmap = NULL, \
|
||||
.hw.init = CLK_HW_INIT_PARENTS(_name, \
|
||||
_parent, \
|
||||
&owl_comp_pass_ops,\
|
||||
_flags), \
|
||||
}, \
|
||||
}
|
||||
|
||||
static inline struct owl_composite *hw_to_owl_comp(const struct clk_hw *hw)
|
||||
{
|
||||
struct owl_clk_common *common = hw_to_owl_clk_common(hw);
|
||||
|
||||
return container_of(common, struct owl_composite, common);
|
||||
}
|
||||
|
||||
extern const struct clk_ops owl_comp_div_ops;
|
||||
extern const struct clk_ops owl_comp_fact_ops;
|
||||
extern const struct clk_ops owl_comp_fix_fact_ops;
|
||||
extern const struct clk_ops owl_comp_pass_ops;
|
||||
extern const struct clk_ops clk_fixed_factor_ops;
|
||||
|
||||
#endif /* _OWL_COMPOSITE_H_ */
|
94
drivers/clk/actions/owl-divider.c
Normal file
94
drivers/clk/actions/owl-divider.c
Normal file
@ -0,0 +1,94 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// OWL divider clock driver
|
||||
//
|
||||
// Copyright (c) 2014 Actions Semi Inc.
|
||||
// Author: David Liu <liuwei@actions-semi.com>
|
||||
//
|
||||
// Copyright (c) 2018 Linaro Ltd.
|
||||
// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "owl-divider.h"
|
||||
|
||||
long owl_divider_helper_round_rate(struct owl_clk_common *common,
|
||||
const struct owl_divider_hw *div_hw,
|
||||
unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
return divider_round_rate(&common->hw, rate, parent_rate,
|
||||
div_hw->table, div_hw->width,
|
||||
div_hw->div_flags);
|
||||
}
|
||||
|
||||
static long owl_divider_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct owl_divider *div = hw_to_owl_divider(hw);
|
||||
|
||||
return owl_divider_helper_round_rate(&div->common, &div->div_hw,
|
||||
rate, parent_rate);
|
||||
}
|
||||
|
||||
unsigned long owl_divider_helper_recalc_rate(struct owl_clk_common *common,
|
||||
const struct owl_divider_hw *div_hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
unsigned long val;
|
||||
unsigned int reg;
|
||||
|
||||
regmap_read(common->regmap, div_hw->reg, ®);
|
||||
val = reg >> div_hw->shift;
|
||||
val &= (1 << div_hw->width) - 1;
|
||||
|
||||
return divider_recalc_rate(&common->hw, parent_rate,
|
||||
val, div_hw->table,
|
||||
div_hw->div_flags,
|
||||
div_hw->width);
|
||||
}
|
||||
|
||||
static unsigned long owl_divider_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct owl_divider *div = hw_to_owl_divider(hw);
|
||||
|
||||
return owl_divider_helper_recalc_rate(&div->common,
|
||||
&div->div_hw, parent_rate);
|
||||
}
|
||||
|
||||
int owl_divider_helper_set_rate(const struct owl_clk_common *common,
|
||||
const struct owl_divider_hw *div_hw,
|
||||
unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
unsigned long val;
|
||||
unsigned int reg;
|
||||
|
||||
val = divider_get_val(rate, parent_rate, div_hw->table,
|
||||
div_hw->width, 0);
|
||||
|
||||
regmap_read(common->regmap, div_hw->reg, ®);
|
||||
reg &= ~GENMASK(div_hw->width + div_hw->shift - 1, div_hw->shift);
|
||||
|
||||
regmap_write(common->regmap, div_hw->reg,
|
||||
reg | (val << div_hw->shift));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int owl_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct owl_divider *div = hw_to_owl_divider(hw);
|
||||
|
||||
return owl_divider_helper_set_rate(&div->common, &div->div_hw,
|
||||
rate, parent_rate);
|
||||
}
|
||||
|
||||
const struct clk_ops owl_divider_ops = {
|
||||
.recalc_rate = owl_divider_recalc_rate,
|
||||
.round_rate = owl_divider_round_rate,
|
||||
.set_rate = owl_divider_set_rate,
|
||||
};
|
75
drivers/clk/actions/owl-divider.h
Normal file
75
drivers/clk/actions/owl-divider.h
Normal file
@ -0,0 +1,75 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// OWL divider clock driver
|
||||
//
|
||||
// Copyright (c) 2014 Actions Semi Inc.
|
||||
// Author: David Liu <liuwei@actions-semi.com>
|
||||
//
|
||||
// Copyright (c) 2018 Linaro Ltd.
|
||||
// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
#ifndef _OWL_DIVIDER_H_
|
||||
#define _OWL_DIVIDER_H_
|
||||
|
||||
#include "owl-common.h"
|
||||
|
||||
struct owl_divider_hw {
|
||||
u32 reg;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
u8 div_flags;
|
||||
struct clk_div_table *table;
|
||||
};
|
||||
|
||||
struct owl_divider {
|
||||
struct owl_divider_hw div_hw;
|
||||
struct owl_clk_common common;
|
||||
};
|
||||
|
||||
#define OWL_DIVIDER_HW(_reg, _shift, _width, _div_flags, _table) \
|
||||
{ \
|
||||
.reg = _reg, \
|
||||
.shift = _shift, \
|
||||
.width = _width, \
|
||||
.div_flags = _div_flags, \
|
||||
.table = _table, \
|
||||
}
|
||||
|
||||
#define OWL_DIVIDER(_struct, _name, _parent, _reg, \
|
||||
_shift, _width, _table, _div_flags, _flags) \
|
||||
struct owl_divider _struct = { \
|
||||
.div_hw = OWL_DIVIDER_HW(_reg, _shift, _width, \
|
||||
_div_flags, _table), \
|
||||
.common = { \
|
||||
.regmap = NULL, \
|
||||
.hw.init = CLK_HW_INIT(_name, \
|
||||
_parent, \
|
||||
&owl_divider_ops, \
|
||||
_flags), \
|
||||
}, \
|
||||
}
|
||||
|
||||
static inline struct owl_divider *hw_to_owl_divider(const struct clk_hw *hw)
|
||||
{
|
||||
struct owl_clk_common *common = hw_to_owl_clk_common(hw);
|
||||
|
||||
return container_of(common, struct owl_divider, common);
|
||||
}
|
||||
|
||||
long owl_divider_helper_round_rate(struct owl_clk_common *common,
|
||||
const struct owl_divider_hw *div_hw,
|
||||
unsigned long rate,
|
||||
unsigned long *parent_rate);
|
||||
|
||||
unsigned long owl_divider_helper_recalc_rate(struct owl_clk_common *common,
|
||||
const struct owl_divider_hw *div_hw,
|
||||
unsigned long parent_rate);
|
||||
|
||||
int owl_divider_helper_set_rate(const struct owl_clk_common *common,
|
||||
const struct owl_divider_hw *div_hw,
|
||||
unsigned long rate,
|
||||
unsigned long parent_rate);
|
||||
|
||||
extern const struct clk_ops owl_divider_ops;
|
||||
|
||||
#endif /* _OWL_DIVIDER_H_ */
|
222
drivers/clk/actions/owl-factor.c
Normal file
222
drivers/clk/actions/owl-factor.c
Normal file
@ -0,0 +1,222 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// OWL factor clock driver
|
||||
//
|
||||
// Copyright (c) 2014 Actions Semi Inc.
|
||||
// Author: David Liu <liuwei@actions-semi.com>
|
||||
//
|
||||
// Copyright (c) 2018 Linaro Ltd.
|
||||
// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "owl-factor.h"
|
||||
|
||||
static unsigned int _get_table_maxval(const struct clk_factor_table *table)
|
||||
{
|
||||
unsigned int maxval = 0;
|
||||
const struct clk_factor_table *clkt;
|
||||
|
||||
for (clkt = table; clkt->div; clkt++)
|
||||
if (clkt->val > maxval)
|
||||
maxval = clkt->val;
|
||||
return maxval;
|
||||
}
|
||||
|
||||
static int _get_table_div_mul(const struct clk_factor_table *table,
|
||||
unsigned int val, unsigned int *mul, unsigned int *div)
|
||||
{
|
||||
const struct clk_factor_table *clkt;
|
||||
|
||||
for (clkt = table; clkt->div; clkt++) {
|
||||
if (clkt->val == val) {
|
||||
*mul = clkt->mul;
|
||||
*div = clkt->div;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int _get_table_val(const struct clk_factor_table *table,
|
||||
unsigned long rate, unsigned long parent_rate)
|
||||
{
|
||||
const struct clk_factor_table *clkt;
|
||||
int val = -1;
|
||||
u64 calc_rate;
|
||||
|
||||
for (clkt = table; clkt->div; clkt++) {
|
||||
calc_rate = parent_rate * clkt->mul;
|
||||
do_div(calc_rate, clkt->div);
|
||||
|
||||
if ((unsigned long)calc_rate <= rate) {
|
||||
val = clkt->val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (val == -1)
|
||||
val = _get_table_maxval(table);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int clk_val_best(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *best_parent_rate)
|
||||
{
|
||||
struct owl_factor *factor = hw_to_owl_factor(hw);
|
||||
struct owl_factor_hw *factor_hw = &factor->factor_hw;
|
||||
const struct clk_factor_table *clkt = factor_hw->table;
|
||||
unsigned long parent_rate, try_parent_rate, best = 0, cur_rate;
|
||||
unsigned long parent_rate_saved = *best_parent_rate;
|
||||
int bestval = 0;
|
||||
|
||||
if (!rate)
|
||||
rate = 1;
|
||||
|
||||
if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
|
||||
parent_rate = *best_parent_rate;
|
||||
bestval = _get_table_val(clkt, rate, parent_rate);
|
||||
return bestval;
|
||||
}
|
||||
|
||||
for (clkt = factor_hw->table; clkt->div; clkt++) {
|
||||
try_parent_rate = rate * clkt->div / clkt->mul;
|
||||
|
||||
if (try_parent_rate == parent_rate_saved) {
|
||||
pr_debug("%s: [%d %d %d] found try_parent_rate %ld\n",
|
||||
__func__, clkt->val, clkt->mul, clkt->div,
|
||||
try_parent_rate);
|
||||
/*
|
||||
* It's the most ideal case if the requested rate can be
|
||||
* divided from parent clock without any need to change
|
||||
* parent rate, so return the divider immediately.
|
||||
*/
|
||||
*best_parent_rate = parent_rate_saved;
|
||||
return clkt->val;
|
||||
}
|
||||
|
||||
parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
|
||||
try_parent_rate);
|
||||
cur_rate = DIV_ROUND_UP(parent_rate, clkt->div) * clkt->mul;
|
||||
if (cur_rate <= rate && cur_rate > best) {
|
||||
bestval = clkt->val;
|
||||
best = cur_rate;
|
||||
*best_parent_rate = parent_rate;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bestval) {
|
||||
bestval = _get_table_maxval(clkt);
|
||||
*best_parent_rate = clk_hw_round_rate(
|
||||
clk_hw_get_parent(hw), 1);
|
||||
}
|
||||
|
||||
return bestval;
|
||||
}
|
||||
|
||||
long owl_factor_helper_round_rate(struct owl_clk_common *common,
|
||||
const struct owl_factor_hw *factor_hw,
|
||||
unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
const struct clk_factor_table *clkt = factor_hw->table;
|
||||
unsigned int val, mul = 0, div = 1;
|
||||
|
||||
val = clk_val_best(&common->hw, rate, parent_rate);
|
||||
_get_table_div_mul(clkt, val, &mul, &div);
|
||||
|
||||
return *parent_rate * mul / div;
|
||||
}
|
||||
|
||||
static long owl_factor_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct owl_factor *factor = hw_to_owl_factor(hw);
|
||||
struct owl_factor_hw *factor_hw = &factor->factor_hw;
|
||||
|
||||
return owl_factor_helper_round_rate(&factor->common, factor_hw,
|
||||
rate, parent_rate);
|
||||
}
|
||||
|
||||
unsigned long owl_factor_helper_recalc_rate(struct owl_clk_common *common,
|
||||
const struct owl_factor_hw *factor_hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
const struct clk_factor_table *clkt = factor_hw->table;
|
||||
unsigned long long int rate;
|
||||
u32 reg, val, mul, div;
|
||||
|
||||
div = 0;
|
||||
mul = 0;
|
||||
|
||||
regmap_read(common->regmap, factor_hw->reg, ®);
|
||||
|
||||
val = reg >> factor_hw->shift;
|
||||
val &= div_mask(factor_hw);
|
||||
|
||||
_get_table_div_mul(clkt, val, &mul, &div);
|
||||
if (!div) {
|
||||
WARN(!(factor_hw->fct_flags & CLK_DIVIDER_ALLOW_ZERO),
|
||||
"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
|
||||
__clk_get_name(common->hw.clk));
|
||||
return parent_rate;
|
||||
}
|
||||
|
||||
rate = (unsigned long long int)parent_rate * mul;
|
||||
do_div(rate, div);
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static unsigned long owl_factor_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct owl_factor *factor = hw_to_owl_factor(hw);
|
||||
struct owl_factor_hw *factor_hw = &factor->factor_hw;
|
||||
struct owl_clk_common *common = &factor->common;
|
||||
|
||||
return owl_factor_helper_recalc_rate(common, factor_hw, parent_rate);
|
||||
}
|
||||
|
||||
int owl_factor_helper_set_rate(const struct owl_clk_common *common,
|
||||
const struct owl_factor_hw *factor_hw,
|
||||
unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u32 val, reg;
|
||||
|
||||
val = _get_table_val(factor_hw->table, rate, parent_rate);
|
||||
|
||||
if (val > div_mask(factor_hw))
|
||||
val = div_mask(factor_hw);
|
||||
|
||||
regmap_read(common->regmap, factor_hw->reg, ®);
|
||||
|
||||
reg &= ~(div_mask(factor_hw) << factor_hw->shift);
|
||||
reg |= val << factor_hw->shift;
|
||||
|
||||
regmap_write(common->regmap, factor_hw->reg, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int owl_factor_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct owl_factor *factor = hw_to_owl_factor(hw);
|
||||
struct owl_factor_hw *factor_hw = &factor->factor_hw;
|
||||
struct owl_clk_common *common = &factor->common;
|
||||
|
||||
return owl_factor_helper_set_rate(common, factor_hw,
|
||||
rate, parent_rate);
|
||||
}
|
||||
|
||||
const struct clk_ops owl_factor_ops = {
|
||||
.round_rate = owl_factor_round_rate,
|
||||
.recalc_rate = owl_factor_recalc_rate,
|
||||
.set_rate = owl_factor_set_rate,
|
||||
};
|
83
drivers/clk/actions/owl-factor.h
Normal file
83
drivers/clk/actions/owl-factor.h
Normal file
@ -0,0 +1,83 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// OWL factor clock driver
|
||||
//
|
||||
// Copyright (c) 2014 Actions Semi Inc.
|
||||
// Author: David Liu <liuwei@actions-semi.com>
|
||||
//
|
||||
// Copyright (c) 2018 Linaro Ltd.
|
||||
// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
#ifndef _OWL_FACTOR_H_
|
||||
#define _OWL_FACTOR_H_
|
||||
|
||||
#include "owl-common.h"
|
||||
|
||||
struct clk_factor_table {
|
||||
unsigned int val;
|
||||
unsigned int mul;
|
||||
unsigned int div;
|
||||
};
|
||||
|
||||
struct owl_factor_hw {
|
||||
u32 reg;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
u8 fct_flags;
|
||||
struct clk_factor_table *table;
|
||||
};
|
||||
|
||||
struct owl_factor {
|
||||
struct owl_factor_hw factor_hw;
|
||||
struct owl_clk_common common;
|
||||
};
|
||||
|
||||
#define OWL_FACTOR_HW(_reg, _shift, _width, _fct_flags, _table) \
|
||||
{ \
|
||||
.reg = _reg, \
|
||||
.shift = _shift, \
|
||||
.width = _width, \
|
||||
.fct_flags = _fct_flags, \
|
||||
.table = _table, \
|
||||
}
|
||||
|
||||
#define OWL_FACTOR(_struct, _name, _parent, _reg, \
|
||||
_shift, _width, _table, _fct_flags, _flags) \
|
||||
struct owl_factor _struct = { \
|
||||
.factor_hw = OWL_FACTOR_HW(_reg, _shift, \
|
||||
_width, _fct_flags, _table), \
|
||||
.common = { \
|
||||
.regmap = NULL, \
|
||||
.hw.init = CLK_HW_INIT(_name, \
|
||||
_parent, \
|
||||
&owl_factor_ops, \
|
||||
_flags), \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define div_mask(d) ((1 << ((d)->width)) - 1)
|
||||
|
||||
static inline struct owl_factor *hw_to_owl_factor(const struct clk_hw *hw)
|
||||
{
|
||||
struct owl_clk_common *common = hw_to_owl_clk_common(hw);
|
||||
|
||||
return container_of(common, struct owl_factor, common);
|
||||
}
|
||||
|
||||
long owl_factor_helper_round_rate(struct owl_clk_common *common,
|
||||
const struct owl_factor_hw *factor_hw,
|
||||
unsigned long rate,
|
||||
unsigned long *parent_rate);
|
||||
|
||||
unsigned long owl_factor_helper_recalc_rate(struct owl_clk_common *common,
|
||||
const struct owl_factor_hw *factor_hw,
|
||||
unsigned long parent_rate);
|
||||
|
||||
int owl_factor_helper_set_rate(const struct owl_clk_common *common,
|
||||
const struct owl_factor_hw *factor_hw,
|
||||
unsigned long rate,
|
||||
unsigned long parent_rate);
|
||||
|
||||
extern const struct clk_ops owl_factor_ops;
|
||||
|
||||
#endif /* _OWL_FACTOR_H_ */
|
28
drivers/clk/actions/owl-fixed-factor.h
Normal file
28
drivers/clk/actions/owl-fixed-factor.h
Normal file
@ -0,0 +1,28 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// OWL fixed factor clock driver
|
||||
//
|
||||
// Copyright (c) 2014 Actions Semi Inc.
|
||||
// Author: David Liu <liuwei@actions-semi.com>
|
||||
//
|
||||
// Copyright (c) 2018 Linaro Ltd.
|
||||
// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
#ifndef _OWL_FIXED_FACTOR_H_
|
||||
#define _OWL_FIXED_FACTOR_H_
|
||||
|
||||
#include "owl-common.h"
|
||||
|
||||
#define OWL_FIX_FACT(_struct, _name, _parent, _mul, _div, _flags) \
|
||||
struct clk_fixed_factor _struct = { \
|
||||
.mult = _mul, \
|
||||
.div = _div, \
|
||||
.hw.init = CLK_HW_INIT(_name, \
|
||||
_parent, \
|
||||
&clk_fixed_factor_ops, \
|
||||
_flags), \
|
||||
}
|
||||
|
||||
extern const struct clk_ops clk_fixed_factor_ops;
|
||||
|
||||
#endif /* _OWL_FIXED_FACTOR_H_ */
|
77
drivers/clk/actions/owl-gate.c
Normal file
77
drivers/clk/actions/owl-gate.c
Normal file
@ -0,0 +1,77 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// OWL gate clock driver
|
||||
//
|
||||
// Copyright (c) 2014 Actions Semi Inc.
|
||||
// Author: David Liu <liuwei@actions-semi.com>
|
||||
//
|
||||
// Copyright (c) 2018 Linaro Ltd.
|
||||
// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "owl-gate.h"
|
||||
|
||||
void owl_gate_set(const struct owl_clk_common *common,
|
||||
const struct owl_gate_hw *gate_hw, bool enable)
|
||||
{
|
||||
int set = gate_hw->gate_flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
|
||||
u32 reg;
|
||||
|
||||
set ^= enable;
|
||||
|
||||
regmap_read(common->regmap, gate_hw->reg, ®);
|
||||
|
||||
if (set)
|
||||
reg |= BIT(gate_hw->bit_idx);
|
||||
else
|
||||
reg &= ~BIT(gate_hw->bit_idx);
|
||||
|
||||
regmap_write(common->regmap, gate_hw->reg, reg);
|
||||
}
|
||||
|
||||
static void owl_gate_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct owl_gate *gate = hw_to_owl_gate(hw);
|
||||
struct owl_clk_common *common = &gate->common;
|
||||
|
||||
owl_gate_set(common, &gate->gate_hw, false);
|
||||
}
|
||||
|
||||
static int owl_gate_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct owl_gate *gate = hw_to_owl_gate(hw);
|
||||
struct owl_clk_common *common = &gate->common;
|
||||
|
||||
owl_gate_set(common, &gate->gate_hw, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int owl_gate_clk_is_enabled(const struct owl_clk_common *common,
|
||||
const struct owl_gate_hw *gate_hw)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
regmap_read(common->regmap, gate_hw->reg, ®);
|
||||
|
||||
if (gate_hw->gate_flags & CLK_GATE_SET_TO_DISABLE)
|
||||
reg ^= BIT(gate_hw->bit_idx);
|
||||
|
||||
return !!(reg & BIT(gate_hw->bit_idx));
|
||||
}
|
||||
|
||||
static int owl_gate_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct owl_gate *gate = hw_to_owl_gate(hw);
|
||||
struct owl_clk_common *common = &gate->common;
|
||||
|
||||
return owl_gate_clk_is_enabled(common, &gate->gate_hw);
|
||||
}
|
||||
|
||||
const struct clk_ops owl_gate_ops = {
|
||||
.disable = owl_gate_disable,
|
||||
.enable = owl_gate_enable,
|
||||
.is_enabled = owl_gate_is_enabled,
|
||||
};
|
73
drivers/clk/actions/owl-gate.h
Normal file
73
drivers/clk/actions/owl-gate.h
Normal file
@ -0,0 +1,73 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// OWL gate clock driver
|
||||
//
|
||||
// Copyright (c) 2014 Actions Semi Inc.
|
||||
// Author: David Liu <liuwei@actions-semi.com>
|
||||
//
|
||||
// Copyright (c) 2018 Linaro Ltd.
|
||||
// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
#ifndef _OWL_GATE_H_
|
||||
#define _OWL_GATE_H_
|
||||
|
||||
#include "owl-common.h"
|
||||
|
||||
struct owl_gate_hw {
|
||||
u32 reg;
|
||||
u8 bit_idx;
|
||||
u8 gate_flags;
|
||||
};
|
||||
|
||||
struct owl_gate {
|
||||
struct owl_gate_hw gate_hw;
|
||||
struct owl_clk_common common;
|
||||
};
|
||||
|
||||
#define OWL_GATE_HW(_reg, _bit_idx, _gate_flags) \
|
||||
{ \
|
||||
.reg = _reg, \
|
||||
.bit_idx = _bit_idx, \
|
||||
.gate_flags = _gate_flags, \
|
||||
}
|
||||
|
||||
#define OWL_GATE(_struct, _name, _parent, _reg, \
|
||||
_bit_idx, _gate_flags, _flags) \
|
||||
struct owl_gate _struct = { \
|
||||
.gate_hw = OWL_GATE_HW(_reg, _bit_idx, _gate_flags), \
|
||||
.common = { \
|
||||
.regmap = NULL, \
|
||||
.hw.init = CLK_HW_INIT(_name, \
|
||||
_parent, \
|
||||
&owl_gate_ops, \
|
||||
_flags), \
|
||||
} \
|
||||
} \
|
||||
|
||||
#define OWL_GATE_NO_PARENT(_struct, _name, _reg, \
|
||||
_bit_idx, _gate_flags, _flags) \
|
||||
struct owl_gate _struct = { \
|
||||
.gate_hw = OWL_GATE_HW(_reg, _bit_idx, _gate_flags), \
|
||||
.common = { \
|
||||
.regmap = NULL, \
|
||||
.hw.init = CLK_HW_INIT_NO_PARENT(_name, \
|
||||
&owl_gate_ops, \
|
||||
_flags), \
|
||||
}, \
|
||||
} \
|
||||
|
||||
static inline struct owl_gate *hw_to_owl_gate(const struct clk_hw *hw)
|
||||
{
|
||||
struct owl_clk_common *common = hw_to_owl_clk_common(hw);
|
||||
|
||||
return container_of(common, struct owl_gate, common);
|
||||
}
|
||||
|
||||
void owl_gate_set(const struct owl_clk_common *common,
|
||||
const struct owl_gate_hw *gate_hw, bool enable);
|
||||
int owl_gate_clk_is_enabled(const struct owl_clk_common *common,
|
||||
const struct owl_gate_hw *gate_hw);
|
||||
|
||||
extern const struct clk_ops owl_gate_ops;
|
||||
|
||||
#endif /* _OWL_GATE_H_ */
|
60
drivers/clk/actions/owl-mux.c
Normal file
60
drivers/clk/actions/owl-mux.c
Normal file
@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// OWL mux clock driver
|
||||
//
|
||||
// Copyright (c) 2014 Actions Semi Inc.
|
||||
// Author: David Liu <liuwei@actions-semi.com>
|
||||
//
|
||||
// Copyright (c) 2018 Linaro Ltd.
|
||||
// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "owl-mux.h"
|
||||
|
||||
u8 owl_mux_helper_get_parent(const struct owl_clk_common *common,
|
||||
const struct owl_mux_hw *mux_hw)
|
||||
{
|
||||
u32 reg;
|
||||
u8 parent;
|
||||
|
||||
regmap_read(common->regmap, mux_hw->reg, ®);
|
||||
parent = reg >> mux_hw->shift;
|
||||
parent &= BIT(mux_hw->width) - 1;
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
static u8 owl_mux_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct owl_mux *mux = hw_to_owl_mux(hw);
|
||||
|
||||
return owl_mux_helper_get_parent(&mux->common, &mux->mux_hw);
|
||||
}
|
||||
|
||||
int owl_mux_helper_set_parent(const struct owl_clk_common *common,
|
||||
struct owl_mux_hw *mux_hw, u8 index)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
regmap_read(common->regmap, mux_hw->reg, ®);
|
||||
reg &= ~GENMASK(mux_hw->width + mux_hw->shift - 1, mux_hw->shift);
|
||||
regmap_write(common->regmap, mux_hw->reg,
|
||||
reg | (index << mux_hw->shift));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int owl_mux_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct owl_mux *mux = hw_to_owl_mux(hw);
|
||||
|
||||
return owl_mux_helper_set_parent(&mux->common, &mux->mux_hw, index);
|
||||
}
|
||||
|
||||
const struct clk_ops owl_mux_ops = {
|
||||
.get_parent = owl_mux_get_parent,
|
||||
.set_parent = owl_mux_set_parent,
|
||||
.determine_rate = __clk_mux_determine_rate,
|
||||
};
|
61
drivers/clk/actions/owl-mux.h
Normal file
61
drivers/clk/actions/owl-mux.h
Normal file
@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// OWL mux clock driver
|
||||
//
|
||||
// Copyright (c) 2014 Actions Semi Inc.
|
||||
// Author: David Liu <liuwei@actions-semi.com>
|
||||
//
|
||||
// Copyright (c) 2018 Linaro Ltd.
|
||||
// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
#ifndef _OWL_MUX_H_
|
||||
#define _OWL_MUX_H_
|
||||
|
||||
#include "owl-common.h"
|
||||
|
||||
struct owl_mux_hw {
|
||||
u32 reg;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
};
|
||||
|
||||
struct owl_mux {
|
||||
struct owl_mux_hw mux_hw;
|
||||
struct owl_clk_common common;
|
||||
};
|
||||
|
||||
#define OWL_MUX_HW(_reg, _shift, _width) \
|
||||
{ \
|
||||
.reg = _reg, \
|
||||
.shift = _shift, \
|
||||
.width = _width, \
|
||||
}
|
||||
|
||||
#define OWL_MUX(_struct, _name, _parents, _reg, \
|
||||
_shift, _width, _flags) \
|
||||
struct owl_mux _struct = { \
|
||||
.mux_hw = OWL_MUX_HW(_reg, _shift, _width), \
|
||||
.common = { \
|
||||
.regmap = NULL, \
|
||||
.hw.init = CLK_HW_INIT_PARENTS(_name, \
|
||||
_parents, \
|
||||
&owl_mux_ops, \
|
||||
_flags), \
|
||||
}, \
|
||||
}
|
||||
|
||||
static inline struct owl_mux *hw_to_owl_mux(const struct clk_hw *hw)
|
||||
{
|
||||
struct owl_clk_common *common = hw_to_owl_clk_common(hw);
|
||||
|
||||
return container_of(common, struct owl_mux, common);
|
||||
}
|
||||
|
||||
u8 owl_mux_helper_get_parent(const struct owl_clk_common *common,
|
||||
const struct owl_mux_hw *mux_hw);
|
||||
int owl_mux_helper_set_parent(const struct owl_clk_common *common,
|
||||
struct owl_mux_hw *mux_hw, u8 index);
|
||||
|
||||
extern const struct clk_ops owl_mux_ops;
|
||||
|
||||
#endif /* _OWL_MUX_H_ */
|
194
drivers/clk/actions/owl-pll.c
Normal file
194
drivers/clk/actions/owl-pll.c
Normal file
@ -0,0 +1,194 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// OWL pll clock driver
|
||||
//
|
||||
// Copyright (c) 2014 Actions Semi Inc.
|
||||
// Author: David Liu <liuwei@actions-semi.com>
|
||||
//
|
||||
// Copyright (c) 2018 Linaro Ltd.
|
||||
// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "owl-pll.h"
|
||||
|
||||
static u32 owl_pll_calculate_mul(struct owl_pll_hw *pll_hw, unsigned long rate)
|
||||
{
|
||||
u32 mul;
|
||||
|
||||
mul = DIV_ROUND_CLOSEST(rate, pll_hw->bfreq);
|
||||
if (mul < pll_hw->min_mul)
|
||||
mul = pll_hw->min_mul;
|
||||
else if (mul > pll_hw->max_mul)
|
||||
mul = pll_hw->max_mul;
|
||||
|
||||
return mul &= mul_mask(pll_hw);
|
||||
}
|
||||
|
||||
static unsigned long _get_table_rate(const struct clk_pll_table *table,
|
||||
unsigned int val)
|
||||
{
|
||||
const struct clk_pll_table *clkt;
|
||||
|
||||
for (clkt = table; clkt->rate; clkt++)
|
||||
if (clkt->val == val)
|
||||
return clkt->rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_pll_table *_get_pll_table(
|
||||
const struct clk_pll_table *table, unsigned long rate)
|
||||
{
|
||||
const struct clk_pll_table *clkt;
|
||||
|
||||
for (clkt = table; clkt->rate; clkt++) {
|
||||
if (clkt->rate == rate) {
|
||||
table = clkt;
|
||||
break;
|
||||
} else if (clkt->rate < rate)
|
||||
table = clkt;
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
static long owl_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct owl_pll *pll = hw_to_owl_pll(hw);
|
||||
struct owl_pll_hw *pll_hw = &pll->pll_hw;
|
||||
const struct clk_pll_table *clkt;
|
||||
u32 mul;
|
||||
|
||||
if (pll_hw->table) {
|
||||
clkt = _get_pll_table(pll_hw->table, rate);
|
||||
return clkt->rate;
|
||||
}
|
||||
|
||||
/* fixed frequency */
|
||||
if (pll_hw->width == 0)
|
||||
return pll_hw->bfreq;
|
||||
|
||||
mul = owl_pll_calculate_mul(pll_hw, rate);
|
||||
|
||||
return pll_hw->bfreq * mul;
|
||||
}
|
||||
|
||||
static unsigned long owl_pll_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct owl_pll *pll = hw_to_owl_pll(hw);
|
||||
struct owl_pll_hw *pll_hw = &pll->pll_hw;
|
||||
const struct owl_clk_common *common = &pll->common;
|
||||
u32 val;
|
||||
|
||||
if (pll_hw->table) {
|
||||
regmap_read(common->regmap, pll_hw->reg, &val);
|
||||
|
||||
val = val >> pll_hw->shift;
|
||||
val &= mul_mask(pll_hw);
|
||||
|
||||
return _get_table_rate(pll_hw->table, val);
|
||||
}
|
||||
|
||||
/* fixed frequency */
|
||||
if (pll_hw->width == 0)
|
||||
return pll_hw->bfreq;
|
||||
|
||||
regmap_read(common->regmap, pll_hw->reg, &val);
|
||||
|
||||
val = val >> pll_hw->shift;
|
||||
val &= mul_mask(pll_hw);
|
||||
|
||||
return pll_hw->bfreq * val;
|
||||
}
|
||||
|
||||
static int owl_pll_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct owl_pll *pll = hw_to_owl_pll(hw);
|
||||
struct owl_pll_hw *pll_hw = &pll->pll_hw;
|
||||
const struct owl_clk_common *common = &pll->common;
|
||||
u32 reg;
|
||||
|
||||
regmap_read(common->regmap, pll_hw->reg, ®);
|
||||
|
||||
return !!(reg & BIT(pll_hw->bit_idx));
|
||||
}
|
||||
|
||||
static void owl_pll_set(const struct owl_clk_common *common,
|
||||
const struct owl_pll_hw *pll_hw, bool enable)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
regmap_read(common->regmap, pll_hw->reg, ®);
|
||||
|
||||
if (enable)
|
||||
reg |= BIT(pll_hw->bit_idx);
|
||||
else
|
||||
reg &= ~BIT(pll_hw->bit_idx);
|
||||
|
||||
regmap_write(common->regmap, pll_hw->reg, reg);
|
||||
}
|
||||
|
||||
static int owl_pll_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct owl_pll *pll = hw_to_owl_pll(hw);
|
||||
const struct owl_clk_common *common = &pll->common;
|
||||
|
||||
owl_pll_set(common, &pll->pll_hw, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void owl_pll_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct owl_pll *pll = hw_to_owl_pll(hw);
|
||||
const struct owl_clk_common *common = &pll->common;
|
||||
|
||||
owl_pll_set(common, &pll->pll_hw, false);
|
||||
}
|
||||
|
||||
static int owl_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct owl_pll *pll = hw_to_owl_pll(hw);
|
||||
struct owl_pll_hw *pll_hw = &pll->pll_hw;
|
||||
const struct owl_clk_common *common = &pll->common;
|
||||
const struct clk_pll_table *clkt;
|
||||
u32 val, reg;
|
||||
|
||||
/* fixed frequency */
|
||||
if (pll_hw->width == 0)
|
||||
return 0;
|
||||
|
||||
if (pll_hw->table) {
|
||||
clkt = _get_pll_table(pll_hw->table, rate);
|
||||
val = clkt->val;
|
||||
} else {
|
||||
val = owl_pll_calculate_mul(pll_hw, rate);
|
||||
}
|
||||
|
||||
regmap_read(common->regmap, pll_hw->reg, ®);
|
||||
|
||||
reg &= ~mul_mask(pll_hw);
|
||||
reg |= val << pll_hw->shift;
|
||||
|
||||
regmap_write(common->regmap, pll_hw->reg, reg);
|
||||
|
||||
udelay(PLL_STABILITY_WAIT_US);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct clk_ops owl_pll_ops = {
|
||||
.enable = owl_pll_enable,
|
||||
.disable = owl_pll_disable,
|
||||
.is_enabled = owl_pll_is_enabled,
|
||||
.round_rate = owl_pll_round_rate,
|
||||
.recalc_rate = owl_pll_recalc_rate,
|
||||
.set_rate = owl_pll_set_rate,
|
||||
};
|
92
drivers/clk/actions/owl-pll.h
Normal file
92
drivers/clk/actions/owl-pll.h
Normal file
@ -0,0 +1,92 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// OWL pll clock driver
|
||||
//
|
||||
// Copyright (c) 2014 Actions Semi Inc.
|
||||
// Author: David Liu <liuwei@actions-semi.com>
|
||||
//
|
||||
// Copyright (c) 2018 Linaro Ltd.
|
||||
// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
#ifndef _OWL_PLL_H_
|
||||
#define _OWL_PLL_H_
|
||||
|
||||
#include "owl-common.h"
|
||||
|
||||
/* last entry should have rate = 0 */
|
||||
struct clk_pll_table {
|
||||
unsigned int val;
|
||||
unsigned long rate;
|
||||
};
|
||||
|
||||
struct owl_pll_hw {
|
||||
u32 reg;
|
||||
u32 bfreq;
|
||||
u8 bit_idx;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
u8 min_mul;
|
||||
u8 max_mul;
|
||||
const struct clk_pll_table *table;
|
||||
};
|
||||
|
||||
struct owl_pll {
|
||||
struct owl_pll_hw pll_hw;
|
||||
struct owl_clk_common common;
|
||||
};
|
||||
|
||||
#define OWL_PLL_HW(_reg, _bfreq, _bit_idx, _shift, \
|
||||
_width, _min_mul, _max_mul, _table) \
|
||||
{ \
|
||||
.reg = _reg, \
|
||||
.bfreq = _bfreq, \
|
||||
.bit_idx = _bit_idx, \
|
||||
.shift = _shift, \
|
||||
.width = _width, \
|
||||
.min_mul = _min_mul, \
|
||||
.max_mul = _max_mul, \
|
||||
.table = _table, \
|
||||
}
|
||||
|
||||
#define OWL_PLL(_struct, _name, _parent, _reg, _bfreq, _bit_idx, \
|
||||
_shift, _width, _min_mul, _max_mul, _table, _flags) \
|
||||
struct owl_pll _struct = { \
|
||||
.pll_hw = OWL_PLL_HW(_reg, _bfreq, _bit_idx, _shift, \
|
||||
_width, _min_mul, \
|
||||
_max_mul, _table), \
|
||||
.common = { \
|
||||
.regmap = NULL, \
|
||||
.hw.init = CLK_HW_INIT(_name, \
|
||||
_parent, \
|
||||
&owl_pll_ops, \
|
||||
_flags), \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define OWL_PLL_NO_PARENT(_struct, _name, _reg, _bfreq, _bit_idx, \
|
||||
_shift, _width, _min_mul, _max_mul, _table, _flags) \
|
||||
struct owl_pll _struct = { \
|
||||
.pll_hw = OWL_PLL_HW(_reg, _bfreq, _bit_idx, _shift, \
|
||||
_width, _min_mul, \
|
||||
_max_mul, _table), \
|
||||
.common = { \
|
||||
.regmap = NULL, \
|
||||
.hw.init = CLK_HW_INIT_NO_PARENT(_name, \
|
||||
&owl_pll_ops, \
|
||||
_flags), \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define mul_mask(m) ((1 << ((m)->width)) - 1)
|
||||
#define PLL_STABILITY_WAIT_US (50)
|
||||
|
||||
static inline struct owl_pll *hw_to_owl_pll(const struct clk_hw *hw)
|
||||
{
|
||||
struct owl_clk_common *common = hw_to_owl_clk_common(hw);
|
||||
|
||||
return container_of(common, struct owl_pll, common);
|
||||
}
|
||||
|
||||
extern const struct clk_ops owl_pll_ops;
|
||||
|
||||
#endif /* _OWL_PLL_H_ */
|
721
drivers/clk/actions/owl-s900.c
Normal file
721
drivers/clk/actions/owl-s900.c
Normal file
@ -0,0 +1,721 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// OWL S900 SoC clock driver
|
||||
//
|
||||
// Copyright (c) 2014 Actions Semi Inc.
|
||||
// Author: David Liu <liuwei@actions-semi.com>
|
||||
//
|
||||
// Copyright (c) 2018 Linaro Ltd.
|
||||
// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "owl-common.h"
|
||||
#include "owl-composite.h"
|
||||
#include "owl-divider.h"
|
||||
#include "owl-factor.h"
|
||||
#include "owl-fixed-factor.h"
|
||||
#include "owl-gate.h"
|
||||
#include "owl-mux.h"
|
||||
#include "owl-pll.h"
|
||||
|
||||
#include <dt-bindings/clock/actions,s900-cmu.h>
|
||||
|
||||
#define CMU_COREPLL (0x0000)
|
||||
#define CMU_DEVPLL (0x0004)
|
||||
#define CMU_DDRPLL (0x0008)
|
||||
#define CMU_NANDPLL (0x000C)
|
||||
#define CMU_DISPLAYPLL (0x0010)
|
||||
#define CMU_AUDIOPLL (0x0014)
|
||||
#define CMU_TVOUTPLL (0x0018)
|
||||
#define CMU_BUSCLK (0x001C)
|
||||
#define CMU_SENSORCLK (0x0020)
|
||||
#define CMU_LCDCLK (0x0024)
|
||||
#define CMU_DSICLK (0x0028)
|
||||
#define CMU_CSICLK (0x002C)
|
||||
#define CMU_DECLK (0x0030)
|
||||
#define CMU_BISPCLK (0x0034)
|
||||
#define CMU_IMXCLK (0x0038)
|
||||
#define CMU_HDECLK (0x003C)
|
||||
#define CMU_VDECLK (0x0040)
|
||||
#define CMU_VCECLK (0x0044)
|
||||
#define CMU_NANDCCLK (0x004C)
|
||||
#define CMU_SD0CLK (0x0050)
|
||||
#define CMU_SD1CLK (0x0054)
|
||||
#define CMU_SD2CLK (0x0058)
|
||||
#define CMU_UART0CLK (0x005C)
|
||||
#define CMU_UART1CLK (0x0060)
|
||||
#define CMU_UART2CLK (0x0064)
|
||||
#define CMU_PWM0CLK (0x0070)
|
||||
#define CMU_PWM1CLK (0x0074)
|
||||
#define CMU_PWM2CLK (0x0078)
|
||||
#define CMU_PWM3CLK (0x007C)
|
||||
#define CMU_USBPLL (0x0080)
|
||||
#define CMU_ASSISTPLL (0x0084)
|
||||
#define CMU_EDPCLK (0x0088)
|
||||
#define CMU_GPU3DCLK (0x0090)
|
||||
#define CMU_CORECTL (0x009C)
|
||||
#define CMU_DEVCLKEN0 (0x00A0)
|
||||
#define CMU_DEVCLKEN1 (0x00A4)
|
||||
#define CMU_DEVRST0 (0x00A8)
|
||||
#define CMU_DEVRST1 (0x00AC)
|
||||
#define CMU_UART3CLK (0x00B0)
|
||||
#define CMU_UART4CLK (0x00B4)
|
||||
#define CMU_UART5CLK (0x00B8)
|
||||
#define CMU_UART6CLK (0x00BC)
|
||||
#define CMU_TLSCLK (0x00C0)
|
||||
#define CMU_SD3CLK (0x00C4)
|
||||
#define CMU_PWM4CLK (0x00C8)
|
||||
#define CMU_PWM5CLK (0x00CC)
|
||||
|
||||
static struct clk_pll_table clk_audio_pll_table[] = {
|
||||
{ 0, 45158400 }, { 1, 49152000 },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
static struct clk_pll_table clk_edp_pll_table[] = {
|
||||
{ 0, 810000000 }, { 1, 135000000 }, { 2, 270000000 },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
/* pll clocks */
|
||||
static OWL_PLL_NO_PARENT(core_pll_clk, "core_pll_clk", CMU_COREPLL, 24000000, 9, 0, 8, 5, 107, NULL, CLK_IGNORE_UNUSED);
|
||||
static OWL_PLL_NO_PARENT(dev_pll_clk, "dev_pll_clk", CMU_DEVPLL, 6000000, 8, 0, 8, 20, 180, NULL, CLK_IGNORE_UNUSED);
|
||||
static OWL_PLL_NO_PARENT(ddr_pll_clk, "ddr_pll_clk", CMU_DDRPLL, 24000000, 8, 0, 8, 5, 45, NULL, CLK_IGNORE_UNUSED);
|
||||
static OWL_PLL_NO_PARENT(nand_pll_clk, "nand_pll_clk", CMU_NANDPLL, 6000000, 8, 0, 8, 4, 100, NULL, CLK_IGNORE_UNUSED);
|
||||
static OWL_PLL_NO_PARENT(display_pll_clk, "display_pll_clk", CMU_DISPLAYPLL, 6000000, 8, 0, 8, 20, 180, NULL, CLK_IGNORE_UNUSED);
|
||||
static OWL_PLL_NO_PARENT(assist_pll_clk, "assist_pll_clk", CMU_ASSISTPLL, 500000000, 0, 0, 0, 0, 0, NULL, CLK_IGNORE_UNUSED);
|
||||
static OWL_PLL_NO_PARENT(audio_pll_clk, "audio_pll_clk", CMU_AUDIOPLL, 0, 4, 0, 1, 0, 0, clk_audio_pll_table, CLK_IGNORE_UNUSED);
|
||||
static OWL_PLL(edp_pll_clk, "edp_pll_clk", "edp24M_clk", CMU_EDPCLK, 0, 9, 0, 2, 0, 0, clk_edp_pll_table, CLK_IGNORE_UNUSED);
|
||||
|
||||
static const char *cpu_clk_mux_p[] = { "losc", "hosc", "core_pll_clk", };
|
||||
static const char *dev_clk_p[] = { "hosc", "dev_pll_clk", };
|
||||
static const char *noc_clk_mux_p[] = { "dev_clk", "assist_pll_clk", };
|
||||
static const char *dmm_clk_mux_p[] = { "dev_clk", "nand_pll_clk", "assist_pll_clk", "ddr_clk_src", };
|
||||
static const char *bisp_clk_mux_p[] = { "assist_pll_clk", "dev_clk", };
|
||||
static const char *csi_clk_mux_p[] = { "display_pll_clk", "dev_clk", };
|
||||
static const char *de_clk_mux_p[] = { "assist_pll_clk", "dev_clk", };
|
||||
static const char *gpu_clk_mux_p[] = { "dev_clk", "display_pll_clk", "ddr_clk_src", };
|
||||
static const char *hde_clk_mux_p[] = { "dev_clk", "display_pll_clk", "ddr_clk_src", };
|
||||
static const char *imx_clk_mux_p[] = { "assist_pll_clk", "dev_clk", };
|
||||
static const char *lcd_clk_mux_p[] = { "display_pll_clk", "nand_pll_clk", };
|
||||
static const char *nand_clk_mux_p[] = { "dev_clk", "nand_pll_clk", };
|
||||
static const char *sd_clk_mux_p[] = { "dev_clk", "nand_pll_clk", };
|
||||
static const char *sensor_clk_mux_p[] = { "hosc", "bisp_clk", };
|
||||
static const char *uart_clk_mux_p[] = { "hosc", "dev_pll_clk", };
|
||||
static const char *vce_clk_mux_p[] = { "dev_clk", "display_pll_clk", "assist_pll_clk", "ddr_clk_src", };
|
||||
static const char *i2s_clk_mux_p[] = { "audio_pll_clk", };
|
||||
static const char *edp_clk_mux_p[] = { "assist_pll_clk", "display_pll_clk", };
|
||||
|
||||
/* mux clocks */
|
||||
static OWL_MUX(cpu_clk, "cpu_clk", cpu_clk_mux_p, CMU_BUSCLK, 0, 2, CLK_SET_RATE_PARENT);
|
||||
static OWL_MUX(dev_clk, "dev_clk", dev_clk_p, CMU_DEVPLL, 12, 1, CLK_SET_RATE_PARENT);
|
||||
static OWL_MUX(noc_clk_mux, "noc_clk_mux", noc_clk_mux_p, CMU_BUSCLK, 7, 1, CLK_SET_RATE_PARENT);
|
||||
|
||||
static struct clk_div_table nand_div_table[] = {
|
||||
{ 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 6 },
|
||||
{ 4, 8 }, { 5, 10 }, { 6, 12 }, { 7, 14 },
|
||||
{ 8, 16 }, { 9, 18 }, { 10, 20 }, { 11, 22 },
|
||||
{ 12, 24 }, { 13, 26 }, { 14, 28 }, { 15, 30 },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
static struct clk_div_table apb_div_table[] = {
|
||||
{ 1, 2 }, { 2, 3 }, { 3, 4 },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
static struct clk_div_table eth_mac_div_table[] = {
|
||||
{ 0, 2 }, { 1, 4 },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
static struct clk_div_table rmii_ref_div_table[] = {
|
||||
{ 0, 4 }, { 1, 10 },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
static struct clk_div_table usb3_mac_div_table[] = {
|
||||
{ 1, 2 }, { 2, 3 }, { 3, 4 },
|
||||
{ 0, 8 },
|
||||
};
|
||||
|
||||
static struct clk_div_table i2s_div_table[] = {
|
||||
{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
|
||||
{ 4, 6 }, { 5, 8 }, { 6, 12 }, { 7, 16 },
|
||||
{ 8, 24 },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
static struct clk_div_table hdmia_div_table[] = {
|
||||
{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
|
||||
{ 4, 6 }, { 5, 8 }, { 6, 12 }, { 7, 16 },
|
||||
{ 8, 24 },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
/* divider clocks */
|
||||
static OWL_DIVIDER(noc_clk_div, "noc_clk_div", "noc_clk", CMU_BUSCLK, 19, 1, NULL, 0, 0);
|
||||
static OWL_DIVIDER(ahb_clk, "ahb_clk", "noc_clk_div", CMU_BUSCLK, 4, 1, NULL, 0, 0);
|
||||
static OWL_DIVIDER(apb_clk, "apb_clk", "ahb_clk", CMU_BUSCLK, 8, 2, apb_div_table, 0, 0);
|
||||
static OWL_DIVIDER(usb3_mac_clk, "usb3_mac_clk", "assist_pll_clk", CMU_ASSISTPLL, 12, 2, usb3_mac_div_table, 0, 0);
|
||||
static OWL_DIVIDER(rmii_ref_clk, "rmii_ref_clk", "assist_pll_clk", CMU_ASSISTPLL, 8, 1, rmii_ref_div_table, 0, 0);
|
||||
|
||||
static struct clk_factor_table sd_factor_table[] = {
|
||||
/* bit0 ~ 4 */
|
||||
{ 0, 1, 1 }, { 1, 1, 2 }, { 2, 1, 3 }, { 3, 1, 4 },
|
||||
{ 4, 1, 5 }, { 5, 1, 6 }, { 6, 1, 7 }, { 7, 1, 8 },
|
||||
{ 8, 1, 9 }, { 9, 1, 10 }, { 10, 1, 11 }, { 11, 1, 12 },
|
||||
{ 12, 1, 13 }, { 13, 1, 14 }, { 14, 1, 15 }, { 15, 1, 16 },
|
||||
{ 16, 1, 17 }, { 17, 1, 18 }, { 18, 1, 19 }, { 19, 1, 20 },
|
||||
{ 20, 1, 21 }, { 21, 1, 22 }, { 22, 1, 23 }, { 23, 1, 24 },
|
||||
{ 24, 1, 25 }, { 25, 1, 26 }, { 26, 1, 27 }, { 27, 1, 28 },
|
||||
{ 28, 1, 29 }, { 29, 1, 30 }, { 30, 1, 31 }, { 31, 1, 32 },
|
||||
|
||||
/* bit8: /128 */
|
||||
{ 256, 1, 1 * 128 }, { 257, 1, 2 * 128 }, { 258, 1, 3 * 128 }, { 259, 1, 4 * 128 },
|
||||
{ 260, 1, 5 * 128 }, { 261, 1, 6 * 128 }, { 262, 1, 7 * 128 }, { 263, 1, 8 * 128 },
|
||||
{ 264, 1, 9 * 128 }, { 265, 1, 10 * 128 }, { 266, 1, 11 * 128 }, { 267, 1, 12 * 128 },
|
||||
{ 268, 1, 13 * 128 }, { 269, 1, 14 * 128 }, { 270, 1, 15 * 128 }, { 271, 1, 16 * 128 },
|
||||
{ 272, 1, 17 * 128 }, { 273, 1, 18 * 128 }, { 274, 1, 19 * 128 }, { 275, 1, 20 * 128 },
|
||||
{ 276, 1, 21 * 128 }, { 277, 1, 22 * 128 }, { 278, 1, 23 * 128 }, { 279, 1, 24 * 128 },
|
||||
{ 280, 1, 25 * 128 }, { 281, 1, 26 * 128 }, { 282, 1, 27 * 128 }, { 283, 1, 28 * 128 },
|
||||
{ 284, 1, 29 * 128 }, { 285, 1, 30 * 128 }, { 286, 1, 31 * 128 }, { 287, 1, 32 * 128 },
|
||||
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
static struct clk_factor_table dmm_factor_table[] = {
|
||||
{ 0, 1, 1 }, { 1, 2, 3 }, { 2, 1, 2 }, { 3, 1, 3 },
|
||||
{ 4, 1, 4 },
|
||||
{ 0, 0, 0 },
|
||||
};
|
||||
|
||||
static struct clk_factor_table noc_factor_table[] = {
|
||||
{ 0, 1, 1 }, { 1, 2, 3 }, { 2, 1, 2 }, { 3, 1, 3 }, { 4, 1, 4 },
|
||||
{ 0, 0, 0 },
|
||||
};
|
||||
|
||||
static struct clk_factor_table bisp_factor_table[] = {
|
||||
{ 0, 1, 1 }, { 1, 2, 3 }, { 2, 1, 2 }, { 3, 2, 5 },
|
||||
{ 4, 1, 3 }, { 5, 1, 4 }, { 6, 1, 6 }, { 7, 1, 8 },
|
||||
{ 0, 0, 0 },
|
||||
};
|
||||
|
||||
/* factor clocks */
|
||||
static OWL_FACTOR(noc_clk, "noc_clk", "noc_clk_mux", CMU_BUSCLK, 16, 3, noc_factor_table, 0, 0);
|
||||
static OWL_FACTOR(de_clk1, "de_clk1", "de_clk", CMU_DECLK, 0, 3, bisp_factor_table, 0, 0);
|
||||
static OWL_FACTOR(de_clk2, "de_clk2", "de_clk", CMU_DECLK, 4, 3, bisp_factor_table, 0, 0);
|
||||
static OWL_FACTOR(de_clk3, "de_clk3", "de_clk", CMU_DECLK, 8, 3, bisp_factor_table, 0, 0);
|
||||
|
||||
/* gate clocks */
|
||||
static OWL_GATE(gpio_clk, "gpio_clk", "apb_clk", CMU_DEVCLKEN0, 18, 0, 0);
|
||||
static OWL_GATE_NO_PARENT(gpu_clk, "gpu_clk", CMU_DEVCLKEN0, 30, 0, 0);
|
||||
static OWL_GATE(dmac_clk, "dmac_clk", "noc_clk_div", CMU_DEVCLKEN0, 1, 0, 0);
|
||||
static OWL_GATE(timer_clk, "timer_clk", "hosc", CMU_DEVCLKEN1, 27, 0, 0);
|
||||
static OWL_GATE_NO_PARENT(dsi_clk, "dsi_clk", CMU_DEVCLKEN0, 12, 0, 0);
|
||||
static OWL_GATE(ddr0_clk, "ddr0_clk", "ddr_pll_clk", CMU_DEVCLKEN0, 31, 0, CLK_IGNORE_UNUSED);
|
||||
static OWL_GATE(ddr1_clk, "ddr1_clk", "ddr_pll_clk", CMU_DEVCLKEN0, 29, 0, CLK_IGNORE_UNUSED);
|
||||
static OWL_GATE_NO_PARENT(usb3_480mpll0_clk, "usb3_480mpll0_clk", CMU_USBPLL, 3, 0, 0);
|
||||
static OWL_GATE_NO_PARENT(usb3_480mphy0_clk, "usb3_480mphy0_clk", CMU_USBPLL, 2, 0, 0);
|
||||
static OWL_GATE_NO_PARENT(usb3_5gphy_clk, "usb3_5gphy_clk", CMU_USBPLL, 1, 0, 0);
|
||||
static OWL_GATE_NO_PARENT(usb3_cce_clk, "usb3_cce_clk", CMU_USBPLL, 0, 0, 0);
|
||||
static OWL_GATE(edp24M_clk, "edp24M_clk", "diff24M", CMU_EDPCLK, 8, 0, 0);
|
||||
static OWL_GATE(edp_link_clk, "edp_link_clk", "edp_pll_clk", CMU_DEVCLKEN0, 10, 0, 0);
|
||||
static OWL_GATE_NO_PARENT(usbh0_pllen_clk, "usbh0_pllen_clk", CMU_USBPLL, 12, 0, 0);
|
||||
static OWL_GATE_NO_PARENT(usbh0_phy_clk, "usbh0_phy_clk", CMU_USBPLL, 10, 0, 0);
|
||||
static OWL_GATE_NO_PARENT(usbh0_cce_clk, "usbh0_cce_clk", CMU_USBPLL, 8, 0, 0);
|
||||
static OWL_GATE_NO_PARENT(usbh1_pllen_clk, "usbh1_pllen_clk", CMU_USBPLL, 13, 0, 0);
|
||||
static OWL_GATE_NO_PARENT(usbh1_phy_clk, "usbh1_phy_clk", CMU_USBPLL, 11, 0, 0);
|
||||
static OWL_GATE_NO_PARENT(usbh1_cce_clk, "usbh1_cce_clk", CMU_USBPLL, 9, 0, 0);
|
||||
static OWL_GATE(spi0_clk, "spi0_clk", "ahb_clk", CMU_DEVCLKEN1, 10, 0, CLK_IGNORE_UNUSED);
|
||||
static OWL_GATE(spi1_clk, "spi1_clk", "ahb_clk", CMU_DEVCLKEN1, 11, 0, CLK_IGNORE_UNUSED);
|
||||
static OWL_GATE(spi2_clk, "spi2_clk", "ahb_clk", CMU_DEVCLKEN1, 12, 0, CLK_IGNORE_UNUSED);
|
||||
static OWL_GATE(spi3_clk, "spi3_clk", "ahb_clk", CMU_DEVCLKEN1, 13, 0, CLK_IGNORE_UNUSED);
|
||||
|
||||
/* composite clocks */
|
||||
static OWL_COMP_FACTOR(bisp_clk, "bisp_clk", bisp_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_BISPCLK, 4, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 14, 0),
|
||||
OWL_FACTOR_HW(CMU_BISPCLK, 0, 3, 0, bisp_factor_table),
|
||||
0);
|
||||
|
||||
static OWL_COMP_DIV(csi0_clk, "csi0_clk", csi_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_CSICLK, 4, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 13, 0),
|
||||
OWL_DIVIDER_HW(CMU_CSICLK, 0, 4, 0, NULL),
|
||||
0);
|
||||
|
||||
static OWL_COMP_DIV(csi1_clk, "csi1_clk", csi_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_CSICLK, 20, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 15, 0),
|
||||
OWL_DIVIDER_HW(CMU_CSICLK, 16, 4, 0, NULL),
|
||||
0);
|
||||
|
||||
static OWL_COMP_PASS(de_clk, "de_clk", de_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_DECLK, 12, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 8, 0),
|
||||
0);
|
||||
|
||||
static OWL_COMP_FACTOR(dmm_clk, "dmm_clk", dmm_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_BUSCLK, 10, 2),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 19, 0),
|
||||
OWL_FACTOR_HW(CMU_BUSCLK, 12, 3, 0, dmm_factor_table),
|
||||
CLK_IGNORE_UNUSED);
|
||||
|
||||
static OWL_COMP_FACTOR(edp_clk, "edp_clk", edp_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_EDPCLK, 19, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 10, 0),
|
||||
OWL_FACTOR_HW(CMU_EDPCLK, 16, 3, 0, bisp_factor_table),
|
||||
0);
|
||||
|
||||
static OWL_COMP_DIV_FIXED(eth_mac_clk, "eth_mac_clk", "assist_pll_clk",
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 22, 0),
|
||||
OWL_DIVIDER_HW(CMU_ASSISTPLL, 10, 1, 0, eth_mac_div_table),
|
||||
0);
|
||||
|
||||
static OWL_COMP_FACTOR(gpu_core_clk, "gpu_core_clk", gpu_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_GPU3DCLK, 4, 2),
|
||||
OWL_GATE_HW(CMU_GPU3DCLK, 15, 0),
|
||||
OWL_FACTOR_HW(CMU_GPU3DCLK, 0, 3, 0, bisp_factor_table),
|
||||
0);
|
||||
|
||||
static OWL_COMP_FACTOR(gpu_mem_clk, "gpu_mem_clk", gpu_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_GPU3DCLK, 20, 2),
|
||||
OWL_GATE_HW(CMU_GPU3DCLK, 14, 0),
|
||||
OWL_FACTOR_HW(CMU_GPU3DCLK, 16, 3, 0, bisp_factor_table),
|
||||
0);
|
||||
|
||||
static OWL_COMP_FACTOR(gpu_sys_clk, "gpu_sys_clk", gpu_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_GPU3DCLK, 28, 2),
|
||||
OWL_GATE_HW(CMU_GPU3DCLK, 13, 0),
|
||||
OWL_FACTOR_HW(CMU_GPU3DCLK, 24, 3, 0, bisp_factor_table),
|
||||
0);
|
||||
|
||||
static OWL_COMP_FACTOR(hde_clk, "hde_clk", hde_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_HDECLK, 4, 2),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 27, 0),
|
||||
OWL_FACTOR_HW(CMU_HDECLK, 0, 3, 0, bisp_factor_table),
|
||||
0);
|
||||
|
||||
static OWL_COMP_DIV(hdmia_clk, "hdmia_clk", i2s_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_AUDIOPLL, 24, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 22, 0),
|
||||
OWL_DIVIDER_HW(CMU_AUDIOPLL, 24, 4, 0, hdmia_div_table),
|
||||
0);
|
||||
|
||||
static OWL_COMP_FIXED_FACTOR(i2c0_clk, "i2c0_clk", "assist_pll_clk",
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 14, 0),
|
||||
1, 5, 0);
|
||||
|
||||
static OWL_COMP_FIXED_FACTOR(i2c1_clk, "i2c1_clk", "assist_pll_clk",
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 15, 0),
|
||||
1, 5, 0);
|
||||
|
||||
static OWL_COMP_FIXED_FACTOR(i2c2_clk, "i2c2_clk", "assist_pll_clk",
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 30, 0),
|
||||
1, 5, 0);
|
||||
|
||||
static OWL_COMP_FIXED_FACTOR(i2c3_clk, "i2c3_clk", "assist_pll_clk",
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 31, 0),
|
||||
1, 5, 0);
|
||||
|
||||
static OWL_COMP_FIXED_FACTOR(i2c4_clk, "i2c4_clk", "assist_pll_clk",
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 17, 0),
|
||||
1, 5, 0);
|
||||
|
||||
static OWL_COMP_FIXED_FACTOR(i2c5_clk, "i2c5_clk", "assist_pll_clk",
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 1, 0),
|
||||
1, 5, 0);
|
||||
|
||||
static OWL_COMP_DIV(i2srx_clk, "i2srx_clk", i2s_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_AUDIOPLL, 24, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 21, 0),
|
||||
OWL_DIVIDER_HW(CMU_AUDIOPLL, 20, 4, 0, i2s_div_table),
|
||||
0);
|
||||
|
||||
static OWL_COMP_DIV(i2stx_clk, "i2stx_clk", i2s_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_AUDIOPLL, 24, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 20, 0),
|
||||
OWL_DIVIDER_HW(CMU_AUDIOPLL, 16, 4, 0, i2s_div_table),
|
||||
0);
|
||||
|
||||
static OWL_COMP_FACTOR(imx_clk, "imx_clk", imx_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_IMXCLK, 4, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 17, 0),
|
||||
OWL_FACTOR_HW(CMU_IMXCLK, 0, 3, 0, bisp_factor_table),
|
||||
0);
|
||||
|
||||
static OWL_COMP_DIV(lcd_clk, "lcd_clk", lcd_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_LCDCLK, 12, 2),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 9, 0),
|
||||
OWL_DIVIDER_HW(CMU_LCDCLK, 0, 5, 0, NULL),
|
||||
0);
|
||||
|
||||
static OWL_COMP_DIV(nand0_clk, "nand0_clk", nand_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_NANDCCLK, 8, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 4, 0),
|
||||
OWL_DIVIDER_HW(CMU_NANDCCLK, 0, 4, 0, nand_div_table),
|
||||
CLK_SET_RATE_PARENT);
|
||||
|
||||
static OWL_COMP_DIV(nand1_clk, "nand1_clk", nand_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_NANDCCLK, 24, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 11, 0),
|
||||
OWL_DIVIDER_HW(CMU_NANDCCLK, 16, 4, 0, nand_div_table),
|
||||
CLK_SET_RATE_PARENT);
|
||||
|
||||
static OWL_COMP_DIV_FIXED(pwm0_clk, "pwm0_clk", "hosc",
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 23, 0),
|
||||
OWL_DIVIDER_HW(CMU_PWM0CLK, 0, 6, 0, NULL),
|
||||
0);
|
||||
|
||||
static OWL_COMP_DIV_FIXED(pwm1_clk, "pwm1_clk", "hosc",
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 24, 0),
|
||||
OWL_DIVIDER_HW(CMU_PWM1CLK, 0, 6, 0, NULL),
|
||||
0);
|
||||
/*
|
||||
* pwm2 may be for backlight, do not gate it
|
||||
* even it is "unused", because it may be
|
||||
* enabled at boot stage, and in kernel, driver
|
||||
* has no effective method to know the real status,
|
||||
* so, the best way is keeping it as what it was.
|
||||
*/
|
||||
static OWL_COMP_DIV_FIXED(pwm2_clk, "pwm2_clk", "hosc",
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 25, 0),
|
||||
OWL_DIVIDER_HW(CMU_PWM2CLK, 0, 6, 0, NULL),
|
||||
CLK_IGNORE_UNUSED);
|
||||
|
||||
static OWL_COMP_DIV_FIXED(pwm3_clk, "pwm3_clk", "hosc",
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 26, 0),
|
||||
OWL_DIVIDER_HW(CMU_PWM3CLK, 0, 6, 0, NULL),
|
||||
0);
|
||||
|
||||
static OWL_COMP_DIV_FIXED(pwm4_clk, "pwm4_clk", "hosc",
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 4, 0),
|
||||
OWL_DIVIDER_HW(CMU_PWM4CLK, 0, 6, 0, NULL),
|
||||
0);
|
||||
|
||||
static OWL_COMP_DIV_FIXED(pwm5_clk, "pwm5_clk", "hosc",
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 5, 0),
|
||||
OWL_DIVIDER_HW(CMU_PWM5CLK, 0, 6, 0, NULL),
|
||||
0);
|
||||
|
||||
static OWL_COMP_FACTOR(sd0_clk, "sd0_clk", sd_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_SD0CLK, 9, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 5, 0),
|
||||
OWL_FACTOR_HW(CMU_SD0CLK, 0, 9, 0, sd_factor_table),
|
||||
0);
|
||||
|
||||
static OWL_COMP_FACTOR(sd1_clk, "sd1_clk", sd_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_SD1CLK, 9, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 6, 0),
|
||||
OWL_FACTOR_HW(CMU_SD1CLK, 0, 9, 0, sd_factor_table),
|
||||
0);
|
||||
|
||||
static OWL_COMP_FACTOR(sd2_clk, "sd2_clk", sd_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_SD2CLK, 9, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 7, 0),
|
||||
OWL_FACTOR_HW(CMU_SD2CLK, 0, 9, 0, sd_factor_table),
|
||||
0);
|
||||
|
||||
static OWL_COMP_FACTOR(sd3_clk, "sd3_clk", sd_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_SD3CLK, 9, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 16, 0),
|
||||
OWL_FACTOR_HW(CMU_SD3CLK, 0, 9, 0, sd_factor_table),
|
||||
0);
|
||||
|
||||
static OWL_COMP_DIV(sensor_clk, "sensor_clk", sensor_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_SENSORCLK, 4, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 14, 0),
|
||||
OWL_DIVIDER_HW(CMU_SENSORCLK, 0, 4, 0, NULL),
|
||||
0);
|
||||
|
||||
static OWL_COMP_DIV_FIXED(speed_sensor_clk, "speed_sensor_clk",
|
||||
"hosc",
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 0, 0),
|
||||
OWL_DIVIDER_HW(CMU_TLSCLK, 0, 4, CLK_DIVIDER_POWER_OF_TWO, NULL),
|
||||
0);
|
||||
|
||||
static OWL_COMP_DIV_FIXED(thermal_sensor_clk, "thermal_sensor_clk",
|
||||
"hosc",
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 2, 0),
|
||||
OWL_DIVIDER_HW(CMU_TLSCLK, 8, 4, CLK_DIVIDER_POWER_OF_TWO, NULL),
|
||||
0);
|
||||
|
||||
static OWL_COMP_DIV(uart0_clk, "uart0_clk", uart_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_UART0CLK, 16, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 6, 0),
|
||||
OWL_DIVIDER_HW(CMU_UART0CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
|
||||
CLK_IGNORE_UNUSED);
|
||||
|
||||
static OWL_COMP_DIV(uart1_clk, "uart1_clk", uart_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_UART1CLK, 16, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 7, 0),
|
||||
OWL_DIVIDER_HW(CMU_UART1CLK, 1, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
|
||||
CLK_IGNORE_UNUSED);
|
||||
|
||||
static OWL_COMP_DIV(uart2_clk, "uart2_clk", uart_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_UART2CLK, 16, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 8, 0),
|
||||
OWL_DIVIDER_HW(CMU_UART2CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
|
||||
CLK_IGNORE_UNUSED);
|
||||
|
||||
static OWL_COMP_DIV(uart3_clk, "uart3_clk", uart_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_UART3CLK, 16, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 19, 0),
|
||||
OWL_DIVIDER_HW(CMU_UART3CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
|
||||
CLK_IGNORE_UNUSED);
|
||||
|
||||
static OWL_COMP_DIV(uart4_clk, "uart4_clk", uart_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_UART4CLK, 16, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 20, 0),
|
||||
OWL_DIVIDER_HW(CMU_UART4CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
|
||||
CLK_IGNORE_UNUSED);
|
||||
|
||||
static OWL_COMP_DIV(uart5_clk, "uart5_clk", uart_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_UART5CLK, 16, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 21, 0),
|
||||
OWL_DIVIDER_HW(CMU_UART5CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
|
||||
CLK_IGNORE_UNUSED);
|
||||
|
||||
static OWL_COMP_DIV(uart6_clk, "uart6_clk", uart_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_UART6CLK, 16, 1),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN1, 18, 0),
|
||||
OWL_DIVIDER_HW(CMU_UART6CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
|
||||
CLK_IGNORE_UNUSED);
|
||||
|
||||
static OWL_COMP_FACTOR(vce_clk, "vce_clk", vce_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_VCECLK, 4, 2),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 26, 0),
|
||||
OWL_FACTOR_HW(CMU_VCECLK, 0, 3, 0, bisp_factor_table),
|
||||
0);
|
||||
|
||||
static OWL_COMP_FACTOR(vde_clk, "vde_clk", hde_clk_mux_p,
|
||||
OWL_MUX_HW(CMU_VDECLK, 4, 2),
|
||||
OWL_GATE_HW(CMU_DEVCLKEN0, 25, 0),
|
||||
OWL_FACTOR_HW(CMU_VDECLK, 0, 3, 0, bisp_factor_table),
|
||||
0);
|
||||
|
||||
static struct owl_clk_common *s900_clks[] = {
|
||||
&core_pll_clk.common,
|
||||
&dev_pll_clk.common,
|
||||
&ddr_pll_clk.common,
|
||||
&nand_pll_clk.common,
|
||||
&display_pll_clk.common,
|
||||
&assist_pll_clk.common,
|
||||
&audio_pll_clk.common,
|
||||
&edp_pll_clk.common,
|
||||
&cpu_clk.common,
|
||||
&dev_clk.common,
|
||||
&noc_clk_mux.common,
|
||||
&noc_clk_div.common,
|
||||
&ahb_clk.common,
|
||||
&apb_clk.common,
|
||||
&usb3_mac_clk.common,
|
||||
&rmii_ref_clk.common,
|
||||
&noc_clk.common,
|
||||
&de_clk1.common,
|
||||
&de_clk2.common,
|
||||
&de_clk3.common,
|
||||
&gpio_clk.common,
|
||||
&gpu_clk.common,
|
||||
&dmac_clk.common,
|
||||
&timer_clk.common,
|
||||
&dsi_clk.common,
|
||||
&ddr0_clk.common,
|
||||
&ddr1_clk.common,
|
||||
&usb3_480mpll0_clk.common,
|
||||
&usb3_480mphy0_clk.common,
|
||||
&usb3_5gphy_clk.common,
|
||||
&usb3_cce_clk.common,
|
||||
&edp24M_clk.common,
|
||||
&edp_link_clk.common,
|
||||
&usbh0_pllen_clk.common,
|
||||
&usbh0_phy_clk.common,
|
||||
&usbh0_cce_clk.common,
|
||||
&usbh1_pllen_clk.common,
|
||||
&usbh1_phy_clk.common,
|
||||
&usbh1_cce_clk.common,
|
||||
&i2c0_clk.common,
|
||||
&i2c1_clk.common,
|
||||
&i2c2_clk.common,
|
||||
&i2c3_clk.common,
|
||||
&i2c4_clk.common,
|
||||
&i2c5_clk.common,
|
||||
&spi0_clk.common,
|
||||
&spi1_clk.common,
|
||||
&spi2_clk.common,
|
||||
&spi3_clk.common,
|
||||
&bisp_clk.common,
|
||||
&csi0_clk.common,
|
||||
&csi1_clk.common,
|
||||
&de_clk.common,
|
||||
&dmm_clk.common,
|
||||
&edp_clk.common,
|
||||
ð_mac_clk.common,
|
||||
&gpu_core_clk.common,
|
||||
&gpu_mem_clk.common,
|
||||
&gpu_sys_clk.common,
|
||||
&hde_clk.common,
|
||||
&hdmia_clk.common,
|
||||
&i2srx_clk.common,
|
||||
&i2stx_clk.common,
|
||||
&imx_clk.common,
|
||||
&lcd_clk.common,
|
||||
&nand0_clk.common,
|
||||
&nand1_clk.common,
|
||||
&pwm0_clk.common,
|
||||
&pwm1_clk.common,
|
||||
&pwm2_clk.common,
|
||||
&pwm3_clk.common,
|
||||
&pwm4_clk.common,
|
||||
&pwm5_clk.common,
|
||||
&sd0_clk.common,
|
||||
&sd1_clk.common,
|
||||
&sd2_clk.common,
|
||||
&sd3_clk.common,
|
||||
&sensor_clk.common,
|
||||
&speed_sensor_clk.common,
|
||||
&thermal_sensor_clk.common,
|
||||
&uart0_clk.common,
|
||||
&uart1_clk.common,
|
||||
&uart2_clk.common,
|
||||
&uart3_clk.common,
|
||||
&uart4_clk.common,
|
||||
&uart5_clk.common,
|
||||
&uart6_clk.common,
|
||||
&vce_clk.common,
|
||||
&vde_clk.common,
|
||||
};
|
||||
|
||||
static struct clk_hw_onecell_data s900_hw_clks = {
|
||||
.hws = {
|
||||
[CLK_CORE_PLL] = &core_pll_clk.common.hw,
|
||||
[CLK_DEV_PLL] = &dev_pll_clk.common.hw,
|
||||
[CLK_DDR_PLL] = &ddr_pll_clk.common.hw,
|
||||
[CLK_NAND_PLL] = &nand_pll_clk.common.hw,
|
||||
[CLK_DISPLAY_PLL] = &display_pll_clk.common.hw,
|
||||
[CLK_ASSIST_PLL] = &assist_pll_clk.common.hw,
|
||||
[CLK_AUDIO_PLL] = &audio_pll_clk.common.hw,
|
||||
[CLK_EDP_PLL] = &edp_pll_clk.common.hw,
|
||||
[CLK_CPU] = &cpu_clk.common.hw,
|
||||
[CLK_DEV] = &dev_clk.common.hw,
|
||||
[CLK_NOC_MUX] = &noc_clk_mux.common.hw,
|
||||
[CLK_NOC_DIV] = &noc_clk_div.common.hw,
|
||||
[CLK_AHB] = &ahb_clk.common.hw,
|
||||
[CLK_APB] = &apb_clk.common.hw,
|
||||
[CLK_USB3_MAC] = &usb3_mac_clk.common.hw,
|
||||
[CLK_RMII_REF] = &rmii_ref_clk.common.hw,
|
||||
[CLK_NOC] = &noc_clk.common.hw,
|
||||
[CLK_DE1] = &de_clk1.common.hw,
|
||||
[CLK_DE2] = &de_clk2.common.hw,
|
||||
[CLK_DE3] = &de_clk3.common.hw,
|
||||
[CLK_GPIO] = &gpio_clk.common.hw,
|
||||
[CLK_GPU] = &gpu_clk.common.hw,
|
||||
[CLK_DMAC] = &dmac_clk.common.hw,
|
||||
[CLK_TIMER] = &timer_clk.common.hw,
|
||||
[CLK_DSI] = &dsi_clk.common.hw,
|
||||
[CLK_DDR0] = &ddr0_clk.common.hw,
|
||||
[CLK_DDR1] = &ddr1_clk.common.hw,
|
||||
[CLK_USB3_480MPLL0] = &usb3_480mpll0_clk.common.hw,
|
||||
[CLK_USB3_480MPHY0] = &usb3_480mphy0_clk.common.hw,
|
||||
[CLK_USB3_5GPHY] = &usb3_5gphy_clk.common.hw,
|
||||
[CLK_USB3_CCE] = &usb3_cce_clk.common.hw,
|
||||
[CLK_24M_EDP] = &edp24M_clk.common.hw,
|
||||
[CLK_EDP_LINK] = &edp_link_clk.common.hw,
|
||||
[CLK_USB2H0_PLLEN] = &usbh0_pllen_clk.common.hw,
|
||||
[CLK_USB2H0_PHY] = &usbh0_phy_clk.common.hw,
|
||||
[CLK_USB2H0_CCE] = &usbh0_cce_clk.common.hw,
|
||||
[CLK_USB2H1_PLLEN] = &usbh1_pllen_clk.common.hw,
|
||||
[CLK_USB2H1_PHY] = &usbh1_phy_clk.common.hw,
|
||||
[CLK_USB2H1_CCE] = &usbh1_cce_clk.common.hw,
|
||||
[CLK_I2C0] = &i2c0_clk.common.hw,
|
||||
[CLK_I2C1] = &i2c1_clk.common.hw,
|
||||
[CLK_I2C2] = &i2c2_clk.common.hw,
|
||||
[CLK_I2C3] = &i2c3_clk.common.hw,
|
||||
[CLK_I2C4] = &i2c4_clk.common.hw,
|
||||
[CLK_I2C5] = &i2c5_clk.common.hw,
|
||||
[CLK_SPI0] = &spi0_clk.common.hw,
|
||||
[CLK_SPI1] = &spi1_clk.common.hw,
|
||||
[CLK_SPI2] = &spi2_clk.common.hw,
|
||||
[CLK_SPI3] = &spi3_clk.common.hw,
|
||||
[CLK_BISP] = &bisp_clk.common.hw,
|
||||
[CLK_CSI0] = &csi0_clk.common.hw,
|
||||
[CLK_CSI1] = &csi1_clk.common.hw,
|
||||
[CLK_DE0] = &de_clk.common.hw,
|
||||
[CLK_DMM] = &dmm_clk.common.hw,
|
||||
[CLK_EDP] = &edp_clk.common.hw,
|
||||
[CLK_ETH_MAC] = ð_mac_clk.common.hw,
|
||||
[CLK_GPU_CORE] = &gpu_core_clk.common.hw,
|
||||
[CLK_GPU_MEM] = &gpu_mem_clk.common.hw,
|
||||
[CLK_GPU_SYS] = &gpu_sys_clk.common.hw,
|
||||
[CLK_HDE] = &hde_clk.common.hw,
|
||||
[CLK_HDMI_AUDIO] = &hdmia_clk.common.hw,
|
||||
[CLK_I2SRX] = &i2srx_clk.common.hw,
|
||||
[CLK_I2STX] = &i2stx_clk.common.hw,
|
||||
[CLK_IMX] = &imx_clk.common.hw,
|
||||
[CLK_LCD] = &lcd_clk.common.hw,
|
||||
[CLK_NAND0] = &nand0_clk.common.hw,
|
||||
[CLK_NAND1] = &nand1_clk.common.hw,
|
||||
[CLK_PWM0] = &pwm0_clk.common.hw,
|
||||
[CLK_PWM1] = &pwm1_clk.common.hw,
|
||||
[CLK_PWM2] = &pwm2_clk.common.hw,
|
||||
[CLK_PWM3] = &pwm3_clk.common.hw,
|
||||
[CLK_PWM4] = &pwm4_clk.common.hw,
|
||||
[CLK_PWM5] = &pwm5_clk.common.hw,
|
||||
[CLK_SD0] = &sd0_clk.common.hw,
|
||||
[CLK_SD1] = &sd1_clk.common.hw,
|
||||
[CLK_SD2] = &sd2_clk.common.hw,
|
||||
[CLK_SD3] = &sd3_clk.common.hw,
|
||||
[CLK_SENSOR] = &sensor_clk.common.hw,
|
||||
[CLK_SPEED_SENSOR] = &speed_sensor_clk.common.hw,
|
||||
[CLK_THERMAL_SENSOR] = &thermal_sensor_clk.common.hw,
|
||||
[CLK_UART0] = &uart0_clk.common.hw,
|
||||
[CLK_UART1] = &uart1_clk.common.hw,
|
||||
[CLK_UART2] = &uart2_clk.common.hw,
|
||||
[CLK_UART3] = &uart3_clk.common.hw,
|
||||
[CLK_UART4] = &uart4_clk.common.hw,
|
||||
[CLK_UART5] = &uart5_clk.common.hw,
|
||||
[CLK_UART6] = &uart6_clk.common.hw,
|
||||
[CLK_VCE] = &vce_clk.common.hw,
|
||||
[CLK_VDE] = &vde_clk.common.hw,
|
||||
},
|
||||
.num = CLK_NR_CLKS,
|
||||
};
|
||||
|
||||
static const struct owl_clk_desc s900_clk_desc = {
|
||||
.clks = s900_clks,
|
||||
.num_clks = ARRAY_SIZE(s900_clks),
|
||||
|
||||
.hw_clks = &s900_hw_clks,
|
||||
};
|
||||
|
||||
static int s900_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct owl_clk_desc *desc;
|
||||
|
||||
desc = &s900_clk_desc;
|
||||
owl_clk_regmap_init(pdev, desc);
|
||||
|
||||
return owl_clk_probe(&pdev->dev, desc->hw_clks);
|
||||
}
|
||||
|
||||
static const struct of_device_id s900_clk_of_match[] = {
|
||||
{ .compatible = "actions,s900-cmu", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct platform_driver s900_clk_driver = {
|
||||
.probe = s900_clk_probe,
|
||||
.driver = {
|
||||
.name = "s900-cmu",
|
||||
.of_match_table = s900_clk_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init s900_clk_init(void)
|
||||
{
|
||||
return platform_driver_register(&s900_clk_driver);
|
||||
}
|
||||
core_initcall(s900_clk_init);
|
@ -132,19 +132,8 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_pll *pll = to_clk_pll(hw);
|
||||
unsigned int pllr;
|
||||
u16 mul;
|
||||
u8 div;
|
||||
|
||||
regmap_read(pll->regmap, PLL_REG(pll->id), &pllr);
|
||||
|
||||
div = PLL_DIV(pllr);
|
||||
mul = PLL_MUL(pllr, pll->layout);
|
||||
|
||||
if (!div || !mul)
|
||||
return 0;
|
||||
|
||||
return (parent_rate / div) * (mul + 1);
|
||||
return (parent_rate / pll->div) * (pll->mul + 1);
|
||||
}
|
||||
|
||||
static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate,
|
||||
|
@ -394,25 +394,21 @@ out:
|
||||
return count * 1000;
|
||||
}
|
||||
|
||||
static int bcm2835_debugfs_regset(struct bcm2835_cprman *cprman, u32 base,
|
||||
static void bcm2835_debugfs_regset(struct bcm2835_cprman *cprman, u32 base,
|
||||
struct debugfs_reg32 *regs, size_t nregs,
|
||||
struct dentry *dentry)
|
||||
{
|
||||
struct dentry *regdump;
|
||||
struct debugfs_regset32 *regset;
|
||||
|
||||
regset = devm_kzalloc(cprman->dev, sizeof(*regset), GFP_KERNEL);
|
||||
if (!regset)
|
||||
return -ENOMEM;
|
||||
return;
|
||||
|
||||
regset->regs = regs;
|
||||
regset->nregs = nregs;
|
||||
regset->base = cprman->regs + base;
|
||||
|
||||
regdump = debugfs_create_regset32("regdump", S_IRUGO, dentry,
|
||||
regset);
|
||||
|
||||
return regdump ? 0 : -ENOMEM;
|
||||
debugfs_create_regset32("regdump", S_IRUGO, dentry, regset);
|
||||
}
|
||||
|
||||
struct bcm2835_pll_data {
|
||||
@ -730,7 +726,7 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm2835_pll_debug_init(struct clk_hw *hw,
|
||||
static void bcm2835_pll_debug_init(struct clk_hw *hw,
|
||||
struct dentry *dentry)
|
||||
{
|
||||
struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw);
|
||||
@ -740,7 +736,7 @@ static int bcm2835_pll_debug_init(struct clk_hw *hw,
|
||||
|
||||
regs = devm_kzalloc(cprman->dev, 7 * sizeof(*regs), GFP_KERNEL);
|
||||
if (!regs)
|
||||
return -ENOMEM;
|
||||
return;
|
||||
|
||||
regs[0].name = "cm_ctrl";
|
||||
regs[0].offset = data->cm_ctrl_reg;
|
||||
@ -757,7 +753,7 @@ static int bcm2835_pll_debug_init(struct clk_hw *hw,
|
||||
regs[6].name = "ana3";
|
||||
regs[6].offset = data->ana_reg_base + 3 * 4;
|
||||
|
||||
return bcm2835_debugfs_regset(cprman, 0, regs, 7, dentry);
|
||||
bcm2835_debugfs_regset(cprman, 0, regs, 7, dentry);
|
||||
}
|
||||
|
||||
static const struct clk_ops bcm2835_pll_clk_ops = {
|
||||
@ -861,8 +857,8 @@ static int bcm2835_pll_divider_set_rate(struct clk_hw *hw,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm2835_pll_divider_debug_init(struct clk_hw *hw,
|
||||
struct dentry *dentry)
|
||||
static void bcm2835_pll_divider_debug_init(struct clk_hw *hw,
|
||||
struct dentry *dentry)
|
||||
{
|
||||
struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw);
|
||||
struct bcm2835_cprman *cprman = divider->cprman;
|
||||
@ -871,14 +867,14 @@ static int bcm2835_pll_divider_debug_init(struct clk_hw *hw,
|
||||
|
||||
regs = devm_kzalloc(cprman->dev, 7 * sizeof(*regs), GFP_KERNEL);
|
||||
if (!regs)
|
||||
return -ENOMEM;
|
||||
return;
|
||||
|
||||
regs[0].name = "cm";
|
||||
regs[0].offset = data->cm_reg;
|
||||
regs[1].name = "a2w";
|
||||
regs[1].offset = data->a2w_reg;
|
||||
|
||||
return bcm2835_debugfs_regset(cprman, 0, regs, 2, dentry);
|
||||
bcm2835_debugfs_regset(cprman, 0, regs, 2, dentry);
|
||||
}
|
||||
|
||||
static const struct clk_ops bcm2835_pll_divider_clk_ops = {
|
||||
@ -1254,15 +1250,14 @@ static struct debugfs_reg32 bcm2835_debugfs_clock_reg32[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static int bcm2835_clock_debug_init(struct clk_hw *hw,
|
||||
static void bcm2835_clock_debug_init(struct clk_hw *hw,
|
||||
struct dentry *dentry)
|
||||
{
|
||||
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
|
||||
struct bcm2835_cprman *cprman = clock->cprman;
|
||||
const struct bcm2835_clock_data *data = clock->data;
|
||||
|
||||
return bcm2835_debugfs_regset(
|
||||
cprman, data->ctl_reg,
|
||||
bcm2835_debugfs_regset(cprman, data->ctl_reg,
|
||||
bcm2835_debugfs_clock_reg32,
|
||||
ARRAY_SIZE(bcm2835_debugfs_clock_reg32),
|
||||
dentry);
|
||||
@ -1395,7 +1390,7 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
|
||||
struct bcm2835_clock *clock;
|
||||
struct clk_init_data init;
|
||||
const char *parents[1 << CM_SRC_BITS];
|
||||
size_t i, j;
|
||||
size_t i;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
@ -1405,12 +1400,11 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
|
||||
for (i = 0; i < data->num_mux_parents; i++) {
|
||||
parents[i] = data->parents[i];
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(cprman_parent_names); j++) {
|
||||
if (strcmp(parents[i], cprman_parent_names[j]) == 0) {
|
||||
parents[i] = cprman->real_parent_names[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret = match_string(cprman_parent_names,
|
||||
ARRAY_SIZE(cprman_parent_names),
|
||||
parents[i]);
|
||||
if (ret >= 0)
|
||||
parents[i] = cprman->real_parent_names[ret];
|
||||
}
|
||||
|
||||
memset(&init, 0, sizeof(init));
|
||||
|
@ -56,8 +56,8 @@ static const struct iproc_pll_ctrl sr_genpll0 = {
|
||||
};
|
||||
|
||||
static const struct iproc_clk_ctrl sr_genpll0_clk[] = {
|
||||
[BCM_SR_GENPLL0_SATA_CLK] = {
|
||||
.channel = BCM_SR_GENPLL0_SATA_CLK,
|
||||
[BCM_SR_GENPLL0_125M_CLK] = {
|
||||
.channel = BCM_SR_GENPLL0_125M_CLK,
|
||||
.flags = IPROC_CLK_AON,
|
||||
.enable = ENABLE_VAL(0x4, 6, 0, 12),
|
||||
.mdiv = REG_VAL(0x18, 0, 9),
|
||||
@ -102,6 +102,65 @@ static int sr_genpll0_clk_init(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iproc_pll_ctrl sr_genpll2 = {
|
||||
.flags = IPROC_CLK_AON | IPROC_CLK_PLL_HAS_NDIV_FRAC |
|
||||
IPROC_CLK_PLL_NEEDS_SW_CFG,
|
||||
.aon = AON_VAL(0x0, 1, 13, 12),
|
||||
.reset = RESET_VAL(0x0, 12, 11),
|
||||
.dig_filter = DF_VAL(0x0, 4, 3, 0, 4, 7, 3),
|
||||
.sw_ctrl = SW_CTRL_VAL(0x10, 31),
|
||||
.ndiv_int = REG_VAL(0x10, 20, 10),
|
||||
.ndiv_frac = REG_VAL(0x10, 0, 20),
|
||||
.pdiv = REG_VAL(0x14, 0, 4),
|
||||
.status = REG_VAL(0x30, 12, 1),
|
||||
};
|
||||
|
||||
static const struct iproc_clk_ctrl sr_genpll2_clk[] = {
|
||||
[BCM_SR_GENPLL2_NIC_CLK] = {
|
||||
.channel = BCM_SR_GENPLL2_NIC_CLK,
|
||||
.flags = IPROC_CLK_AON,
|
||||
.enable = ENABLE_VAL(0x4, 6, 0, 12),
|
||||
.mdiv = REG_VAL(0x18, 0, 9),
|
||||
},
|
||||
[BCM_SR_GENPLL2_TS_500_CLK] = {
|
||||
.channel = BCM_SR_GENPLL2_TS_500_CLK,
|
||||
.flags = IPROC_CLK_AON,
|
||||
.enable = ENABLE_VAL(0x4, 7, 1, 13),
|
||||
.mdiv = REG_VAL(0x18, 10, 9),
|
||||
},
|
||||
[BCM_SR_GENPLL2_125_NITRO_CLK] = {
|
||||
.channel = BCM_SR_GENPLL2_125_NITRO_CLK,
|
||||
.flags = IPROC_CLK_AON,
|
||||
.enable = ENABLE_VAL(0x4, 8, 2, 14),
|
||||
.mdiv = REG_VAL(0x18, 20, 9),
|
||||
},
|
||||
[BCM_SR_GENPLL2_CHIMP_CLK] = {
|
||||
.channel = BCM_SR_GENPLL2_CHIMP_CLK,
|
||||
.flags = IPROC_CLK_AON,
|
||||
.enable = ENABLE_VAL(0x4, 9, 3, 15),
|
||||
.mdiv = REG_VAL(0x1c, 0, 9),
|
||||
},
|
||||
[BCM_SR_GENPLL2_NIC_FLASH_CLK] = {
|
||||
.channel = BCM_SR_GENPLL2_NIC_FLASH_CLK,
|
||||
.flags = IPROC_CLK_AON,
|
||||
.enable = ENABLE_VAL(0x4, 10, 4, 16),
|
||||
.mdiv = REG_VAL(0x1c, 10, 9),
|
||||
},
|
||||
[BCM_SR_GENPLL2_FS4_CLK] = {
|
||||
.channel = BCM_SR_GENPLL2_FS4_CLK,
|
||||
.enable = ENABLE_VAL(0x4, 11, 5, 17),
|
||||
.mdiv = REG_VAL(0x1c, 20, 9),
|
||||
},
|
||||
};
|
||||
|
||||
static int sr_genpll2_clk_init(struct platform_device *pdev)
|
||||
{
|
||||
iproc_pll_clk_setup(pdev->dev.of_node,
|
||||
&sr_genpll2, NULL, 0, sr_genpll2_clk,
|
||||
ARRAY_SIZE(sr_genpll2_clk));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iproc_pll_ctrl sr_genpll3 = {
|
||||
.flags = IPROC_CLK_AON | IPROC_CLK_PLL_HAS_NDIV_FRAC |
|
||||
IPROC_CLK_PLL_NEEDS_SW_CFG,
|
||||
@ -157,6 +216,30 @@ static const struct iproc_clk_ctrl sr_genpll4_clk[] = {
|
||||
.enable = ENABLE_VAL(0x4, 6, 0, 12),
|
||||
.mdiv = REG_VAL(0x18, 0, 9),
|
||||
},
|
||||
[BCM_SR_GENPLL4_TPIU_PLL_CLK] = {
|
||||
.channel = BCM_SR_GENPLL4_TPIU_PLL_CLK,
|
||||
.flags = IPROC_CLK_AON,
|
||||
.enable = ENABLE_VAL(0x4, 7, 1, 13),
|
||||
.mdiv = REG_VAL(0x18, 10, 9),
|
||||
},
|
||||
[BCM_SR_GENPLL4_NOC_CLK] = {
|
||||
.channel = BCM_SR_GENPLL4_NOC_CLK,
|
||||
.flags = IPROC_CLK_AON,
|
||||
.enable = ENABLE_VAL(0x4, 8, 2, 14),
|
||||
.mdiv = REG_VAL(0x18, 20, 9),
|
||||
},
|
||||
[BCM_SR_GENPLL4_CHCLK_FS4_CLK] = {
|
||||
.channel = BCM_SR_GENPLL4_CHCLK_FS4_CLK,
|
||||
.flags = IPROC_CLK_AON,
|
||||
.enable = ENABLE_VAL(0x4, 9, 3, 15),
|
||||
.mdiv = REG_VAL(0x1c, 0, 9),
|
||||
},
|
||||
[BCM_SR_GENPLL4_BRIDGE_FSCPU_CLK] = {
|
||||
.channel = BCM_SR_GENPLL4_BRIDGE_FSCPU_CLK,
|
||||
.flags = IPROC_CLK_AON,
|
||||
.enable = ENABLE_VAL(0x4, 10, 4, 16),
|
||||
.mdiv = REG_VAL(0x1c, 10, 9),
|
||||
},
|
||||
};
|
||||
|
||||
static int sr_genpll4_clk_init(struct platform_device *pdev)
|
||||
@ -181,18 +264,21 @@ static const struct iproc_pll_ctrl sr_genpll5 = {
|
||||
};
|
||||
|
||||
static const struct iproc_clk_ctrl sr_genpll5_clk[] = {
|
||||
[BCM_SR_GENPLL5_FS_CLK] = {
|
||||
.channel = BCM_SR_GENPLL5_FS_CLK,
|
||||
.flags = IPROC_CLK_AON,
|
||||
[BCM_SR_GENPLL5_FS4_HF_CLK] = {
|
||||
.channel = BCM_SR_GENPLL5_FS4_HF_CLK,
|
||||
.enable = ENABLE_VAL(0x4, 6, 0, 12),
|
||||
.mdiv = REG_VAL(0x18, 0, 9),
|
||||
},
|
||||
[BCM_SR_GENPLL5_SPU_CLK] = {
|
||||
.channel = BCM_SR_GENPLL5_SPU_CLK,
|
||||
.flags = IPROC_CLK_AON,
|
||||
.enable = ENABLE_VAL(0x4, 6, 0, 12),
|
||||
[BCM_SR_GENPLL5_CRYPTO_AE_CLK] = {
|
||||
.channel = BCM_SR_GENPLL5_CRYPTO_AE_CLK,
|
||||
.enable = ENABLE_VAL(0x4, 7, 1, 12),
|
||||
.mdiv = REG_VAL(0x18, 10, 9),
|
||||
},
|
||||
[BCM_SR_GENPLL5_RAID_AE_CLK] = {
|
||||
.channel = BCM_SR_GENPLL5_RAID_AE_CLK,
|
||||
.enable = ENABLE_VAL(0x4, 8, 2, 14),
|
||||
.mdiv = REG_VAL(0x18, 20, 9),
|
||||
},
|
||||
};
|
||||
|
||||
static int sr_genpll5_clk_init(struct platform_device *pdev)
|
||||
@ -214,24 +300,30 @@ static const struct iproc_pll_ctrl sr_lcpll0 = {
|
||||
};
|
||||
|
||||
static const struct iproc_clk_ctrl sr_lcpll0_clk[] = {
|
||||
[BCM_SR_LCPLL0_SATA_REF_CLK] = {
|
||||
.channel = BCM_SR_LCPLL0_SATA_REF_CLK,
|
||||
[BCM_SR_LCPLL0_SATA_REFP_CLK] = {
|
||||
.channel = BCM_SR_LCPLL0_SATA_REFP_CLK,
|
||||
.flags = IPROC_CLK_AON,
|
||||
.enable = ENABLE_VAL(0x0, 7, 1, 13),
|
||||
.mdiv = REG_VAL(0x14, 0, 9),
|
||||
},
|
||||
[BCM_SR_LCPLL0_USB_REF_CLK] = {
|
||||
.channel = BCM_SR_LCPLL0_USB_REF_CLK,
|
||||
[BCM_SR_LCPLL0_SATA_REFN_CLK] = {
|
||||
.channel = BCM_SR_LCPLL0_SATA_REFN_CLK,
|
||||
.flags = IPROC_CLK_AON,
|
||||
.enable = ENABLE_VAL(0x0, 8, 2, 14),
|
||||
.mdiv = REG_VAL(0x14, 10, 9),
|
||||
},
|
||||
[BCM_SR_LCPLL0_SATA_REFPN_CLK] = {
|
||||
.channel = BCM_SR_LCPLL0_SATA_REFPN_CLK,
|
||||
[BCM_SR_LCPLL0_SATA_350_CLK] = {
|
||||
.channel = BCM_SR_LCPLL0_SATA_350_CLK,
|
||||
.flags = IPROC_CLK_AON,
|
||||
.enable = ENABLE_VAL(0x0, 9, 3, 15),
|
||||
.mdiv = REG_VAL(0x14, 20, 9),
|
||||
},
|
||||
[BCM_SR_LCPLL0_SATA_500_CLK] = {
|
||||
.channel = BCM_SR_LCPLL0_SATA_500_CLK,
|
||||
.flags = IPROC_CLK_AON,
|
||||
.enable = ENABLE_VAL(0x0, 10, 4, 16),
|
||||
.mdiv = REG_VAL(0x18, 0, 9),
|
||||
},
|
||||
};
|
||||
|
||||
static int sr_lcpll0_clk_init(struct platform_device *pdev)
|
||||
@ -259,6 +351,18 @@ static const struct iproc_clk_ctrl sr_lcpll1_clk[] = {
|
||||
.enable = ENABLE_VAL(0x0, 7, 1, 13),
|
||||
.mdiv = REG_VAL(0x14, 0, 9),
|
||||
},
|
||||
[BCM_SR_LCPLL1_USB_REF_CLK] = {
|
||||
.channel = BCM_SR_LCPLL1_USB_REF_CLK,
|
||||
.flags = IPROC_CLK_AON,
|
||||
.enable = ENABLE_VAL(0x0, 8, 2, 14),
|
||||
.mdiv = REG_VAL(0x14, 10, 9),
|
||||
},
|
||||
[BCM_SR_LCPLL1_CRMU_TS_CLK] = {
|
||||
.channel = BCM_SR_LCPLL1_CRMU_TS_CLK,
|
||||
.flags = IPROC_CLK_AON,
|
||||
.enable = ENABLE_VAL(0x0, 9, 3, 15),
|
||||
.mdiv = REG_VAL(0x14, 20, 9),
|
||||
},
|
||||
};
|
||||
|
||||
static int sr_lcpll1_clk_init(struct platform_device *pdev)
|
||||
@ -298,6 +402,7 @@ static int sr_lcpll_pcie_clk_init(struct platform_device *pdev)
|
||||
|
||||
static const struct of_device_id sr_clk_dt_ids[] = {
|
||||
{ .compatible = "brcm,sr-genpll0", .data = sr_genpll0_clk_init },
|
||||
{ .compatible = "brcm,sr-genpll2", .data = sr_genpll2_clk_init },
|
||||
{ .compatible = "brcm,sr-genpll4", .data = sr_genpll4_clk_init },
|
||||
{ .compatible = "brcm,sr-genpll5", .data = sr_genpll5_clk_init },
|
||||
{ .compatible = "brcm,sr-lcpll0", .data = sr_lcpll0_clk_init },
|
||||
|
@ -1,20 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2014 Marvell Technology Group Ltd.
|
||||
*
|
||||
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
* Alexandre Belloni <alexandre.belloni@free-electrons.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
|
@ -1,20 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2014 Marvell Technology Group Ltd.
|
||||
*
|
||||
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
* Alexandre Belloni <alexandre.belloni@free-electrons.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __BERLIN2_AVPLL_H
|
||||
#define __BERLIN2_AVPLL_H
|
||||
|
@ -1,20 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2014 Marvell Technology Group Ltd.
|
||||
*
|
||||
* Alexandre Belloni <alexandre.belloni@free-electrons.com>
|
||||
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk-provider.h>
|
||||
|
@ -1,20 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2014 Marvell Technology Group Ltd.
|
||||
*
|
||||
* Alexandre Belloni <alexandre.belloni@free-electrons.com>
|
||||
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __BERLIN2_DIV_H
|
||||
#define __BERLIN2_DIV_H
|
||||
|
@ -1,20 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2014 Marvell Technology Group Ltd.
|
||||
*
|
||||
* Alexandre Belloni <alexandre.belloni@free-electrons.com>
|
||||
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
|
@ -1,20 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2014 Marvell Technology Group Ltd.
|
||||
*
|
||||
* Alexandre Belloni <alexandre.belloni@free-electrons.com>
|
||||
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __BERLIN2_PLL_H
|
||||
#define __BERLIN2_PLL_H
|
||||
|
@ -1,20 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2014 Marvell Technology Group Ltd.
|
||||
*
|
||||
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
* Alexandre Belloni <alexandre.belloni@free-electrons.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
|
@ -1,20 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2014 Marvell Technology Group Ltd.
|
||||
*
|
||||
* Alexandre Belloni <alexandre.belloni@free-electrons.com>
|
||||
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
|
@ -1,20 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2014 Marvell Technology Group Ltd.
|
||||
*
|
||||
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
* Alexandre Belloni <alexandre.belloni@free-electrons.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __BERLIN2_COMMON_H
|
||||
#define __BERLIN2_COMMON_H
|
||||
|
@ -14,7 +14,9 @@
|
||||
|
||||
#include <dt-bindings/clock/aspeed-clock.h>
|
||||
|
||||
#define ASPEED_NUM_CLKS 35
|
||||
#define ASPEED_NUM_CLKS 36
|
||||
|
||||
#define ASPEED_RESET2_OFFSET 32
|
||||
|
||||
#define ASPEED_RESET_CTRL 0x04
|
||||
#define ASPEED_CLK_SELECTION 0x08
|
||||
@ -30,6 +32,7 @@
|
||||
#define CLKIN_25MHZ_EN BIT(23)
|
||||
#define AST2400_CLK_SOURCE_SEL BIT(18)
|
||||
#define ASPEED_CLK_SELECTION_2 0xd8
|
||||
#define ASPEED_RESET_CTRL2 0xd4
|
||||
|
||||
/* Globally visible clocks */
|
||||
static DEFINE_SPINLOCK(aspeed_clk_lock);
|
||||
@ -88,7 +91,7 @@ static const struct aspeed_gate_data aspeed_gates[] = {
|
||||
[ASPEED_CLK_GATE_GCLK] = { 1, 7, "gclk-gate", NULL, 0 }, /* 2D engine */
|
||||
[ASPEED_CLK_GATE_MCLK] = { 2, -1, "mclk-gate", "mpll", CLK_IS_CRITICAL }, /* SDRAM */
|
||||
[ASPEED_CLK_GATE_VCLK] = { 3, 6, "vclk-gate", NULL, 0 }, /* Video Capture */
|
||||
[ASPEED_CLK_GATE_BCLK] = { 4, 10, "bclk-gate", "bclk", 0 }, /* PCIe/PCI */
|
||||
[ASPEED_CLK_GATE_BCLK] = { 4, 8, "bclk-gate", "bclk", 0 }, /* PCIe/PCI */
|
||||
[ASPEED_CLK_GATE_DCLK] = { 5, -1, "dclk-gate", NULL, 0 }, /* DAC */
|
||||
[ASPEED_CLK_GATE_REFCLK] = { 6, -1, "refclk-gate", "clkin", CLK_IS_CRITICAL },
|
||||
[ASPEED_CLK_GATE_USBPORT2CLK] = { 7, 3, "usb-port2-gate", NULL, 0 }, /* USB2.0 Host port 2 */
|
||||
@ -291,47 +294,72 @@ struct aspeed_reset {
|
||||
#define to_aspeed_reset(p) container_of((p), struct aspeed_reset, rcdev)
|
||||
|
||||
static const u8 aspeed_resets[] = {
|
||||
/* SCU04 resets */
|
||||
[ASPEED_RESET_XDMA] = 25,
|
||||
[ASPEED_RESET_MCTP] = 24,
|
||||
[ASPEED_RESET_ADC] = 23,
|
||||
[ASPEED_RESET_JTAG_MASTER] = 22,
|
||||
[ASPEED_RESET_MIC] = 18,
|
||||
[ASPEED_RESET_PWM] = 9,
|
||||
[ASPEED_RESET_PCIVGA] = 8,
|
||||
[ASPEED_RESET_PECI] = 10,
|
||||
[ASPEED_RESET_I2C] = 2,
|
||||
[ASPEED_RESET_AHB] = 1,
|
||||
|
||||
/*
|
||||
* SCUD4 resets start at an offset to separate them from
|
||||
* the SCU04 resets.
|
||||
*/
|
||||
[ASPEED_RESET_CRT1] = ASPEED_RESET2_OFFSET + 5,
|
||||
};
|
||||
|
||||
static int aspeed_reset_deassert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct aspeed_reset *ar = to_aspeed_reset(rcdev);
|
||||
u32 rst = BIT(aspeed_resets[id]);
|
||||
u32 reg = ASPEED_RESET_CTRL;
|
||||
u32 bit = aspeed_resets[id];
|
||||
|
||||
return regmap_update_bits(ar->map, ASPEED_RESET_CTRL, rst, 0);
|
||||
if (bit >= ASPEED_RESET2_OFFSET) {
|
||||
bit -= ASPEED_RESET2_OFFSET;
|
||||
reg = ASPEED_RESET_CTRL2;
|
||||
}
|
||||
|
||||
return regmap_update_bits(ar->map, reg, BIT(bit), 0);
|
||||
}
|
||||
|
||||
static int aspeed_reset_assert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct aspeed_reset *ar = to_aspeed_reset(rcdev);
|
||||
u32 rst = BIT(aspeed_resets[id]);
|
||||
u32 reg = ASPEED_RESET_CTRL;
|
||||
u32 bit = aspeed_resets[id];
|
||||
|
||||
return regmap_update_bits(ar->map, ASPEED_RESET_CTRL, rst, rst);
|
||||
if (bit >= ASPEED_RESET2_OFFSET) {
|
||||
bit -= ASPEED_RESET2_OFFSET;
|
||||
reg = ASPEED_RESET_CTRL2;
|
||||
}
|
||||
|
||||
return regmap_update_bits(ar->map, reg, BIT(bit), BIT(bit));
|
||||
}
|
||||
|
||||
static int aspeed_reset_status(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct aspeed_reset *ar = to_aspeed_reset(rcdev);
|
||||
u32 val, rst = BIT(aspeed_resets[id]);
|
||||
int ret;
|
||||
u32 reg = ASPEED_RESET_CTRL;
|
||||
u32 bit = aspeed_resets[id];
|
||||
int ret, val;
|
||||
|
||||
ret = regmap_read(ar->map, ASPEED_RESET_CTRL, &val);
|
||||
if (bit >= ASPEED_RESET2_OFFSET) {
|
||||
bit -= ASPEED_RESET2_OFFSET;
|
||||
reg = ASPEED_RESET_CTRL2;
|
||||
}
|
||||
|
||||
ret = regmap_read(ar->map, reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return !!(val & rst);
|
||||
return !!(val & BIT(bit));
|
||||
}
|
||||
|
||||
static const struct reset_control_ops aspeed_reset_ops = {
|
||||
@ -474,6 +502,13 @@ static int aspeed_clk_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(hw);
|
||||
aspeed_clk_data->hws[ASPEED_CLK_BCLK] = hw;
|
||||
|
||||
/* Fixed 24MHz clock */
|
||||
hw = clk_hw_register_fixed_rate(NULL, "fixed-24m", "clkin",
|
||||
0, 24000000);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
aspeed_clk_data->hws[ASPEED_CLK_24M] = hw;
|
||||
|
||||
/*
|
||||
* TODO: There are a number of clocks that not included in this driver
|
||||
* as more information is required:
|
||||
|
@ -42,8 +42,9 @@ int __must_check clk_bulk_get(struct device *dev, int num_clks,
|
||||
clks[i].clk = clk_get(dev, clks[i].id);
|
||||
if (IS_ERR(clks[i].clk)) {
|
||||
ret = PTR_ERR(clks[i].clk);
|
||||
dev_err(dev, "Failed to get clk '%s': %d\n",
|
||||
clks[i].id, ret);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get clk '%s': %d\n",
|
||||
clks[i].id, ret);
|
||||
clks[i].clk = NULL;
|
||||
goto err;
|
||||
}
|
||||
|
656
drivers/clk/clk-npcm7xx.c
Normal file
656
drivers/clk/clk-npcm7xx.c
Normal file
@ -0,0 +1,656 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Nuvoton NPCM7xx Clock Generator
|
||||
* All the clocks are initialized by the bootloader, so this driver allow only
|
||||
* reading of current settings directly from the hardware.
|
||||
*
|
||||
* Copyright (C) 2018 Nuvoton Technologies tali.perry@nuvoton.com
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/bitfield.h>
|
||||
|
||||
#include <dt-bindings/clock/nuvoton,npcm7xx-clock.h>
|
||||
|
||||
struct npcm7xx_clk_pll {
|
||||
struct clk_hw hw;
|
||||
void __iomem *pllcon;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
#define to_npcm7xx_clk_pll(_hw) container_of(_hw, struct npcm7xx_clk_pll, hw)
|
||||
|
||||
#define PLLCON_LOKI BIT(31)
|
||||
#define PLLCON_LOKS BIT(30)
|
||||
#define PLLCON_FBDV GENMASK(27, 16)
|
||||
#define PLLCON_OTDV2 GENMASK(15, 13)
|
||||
#define PLLCON_PWDEN BIT(12)
|
||||
#define PLLCON_OTDV1 GENMASK(10, 8)
|
||||
#define PLLCON_INDV GENMASK(5, 0)
|
||||
|
||||
static unsigned long npcm7xx_clk_pll_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct npcm7xx_clk_pll *pll = to_npcm7xx_clk_pll(hw);
|
||||
unsigned long fbdv, indv, otdv1, otdv2;
|
||||
unsigned int val;
|
||||
u64 ret;
|
||||
|
||||
if (parent_rate == 0) {
|
||||
pr_err("%s: parent rate is zero", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
val = readl_relaxed(pll->pllcon);
|
||||
|
||||
indv = FIELD_GET(PLLCON_INDV, val);
|
||||
fbdv = FIELD_GET(PLLCON_FBDV, val);
|
||||
otdv1 = FIELD_GET(PLLCON_OTDV1, val);
|
||||
otdv2 = FIELD_GET(PLLCON_OTDV2, val);
|
||||
|
||||
ret = (u64)parent_rate * fbdv;
|
||||
do_div(ret, indv * otdv1 * otdv2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct clk_ops npcm7xx_clk_pll_ops = {
|
||||
.recalc_rate = npcm7xx_clk_pll_recalc_rate,
|
||||
};
|
||||
|
||||
static struct clk_hw *
|
||||
npcm7xx_clk_register_pll(void __iomem *pllcon, const char *name,
|
||||
const char *parent_name, unsigned long flags)
|
||||
{
|
||||
struct npcm7xx_clk_pll *pll;
|
||||
struct clk_init_data init;
|
||||
struct clk_hw *hw;
|
||||
int ret;
|
||||
|
||||
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
|
||||
if (!pll)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pr_debug("%s reg, name=%s, p=%s\n", __func__, name, parent_name);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &npcm7xx_clk_pll_ops;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
init.flags = flags;
|
||||
|
||||
pll->pllcon = pllcon;
|
||||
pll->hw.init = &init;
|
||||
|
||||
hw = &pll->hw;
|
||||
|
||||
ret = clk_hw_register(NULL, hw);
|
||||
if (ret) {
|
||||
kfree(pll);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
#define NPCM7XX_CLKEN1 (0x00)
|
||||
#define NPCM7XX_CLKEN2 (0x28)
|
||||
#define NPCM7XX_CLKEN3 (0x30)
|
||||
#define NPCM7XX_CLKSEL (0x04)
|
||||
#define NPCM7XX_CLKDIV1 (0x08)
|
||||
#define NPCM7XX_CLKDIV2 (0x2C)
|
||||
#define NPCM7XX_CLKDIV3 (0x58)
|
||||
#define NPCM7XX_PLLCON0 (0x0C)
|
||||
#define NPCM7XX_PLLCON1 (0x10)
|
||||
#define NPCM7XX_PLLCON2 (0x54)
|
||||
#define NPCM7XX_SWRSTR (0x14)
|
||||
#define NPCM7XX_IRQWAKECON (0x18)
|
||||
#define NPCM7XX_IRQWAKEFLAG (0x1C)
|
||||
#define NPCM7XX_IPSRST1 (0x20)
|
||||
#define NPCM7XX_IPSRST2 (0x24)
|
||||
#define NPCM7XX_IPSRST3 (0x34)
|
||||
#define NPCM7XX_WD0RCR (0x38)
|
||||
#define NPCM7XX_WD1RCR (0x3C)
|
||||
#define NPCM7XX_WD2RCR (0x40)
|
||||
#define NPCM7XX_SWRSTC1 (0x44)
|
||||
#define NPCM7XX_SWRSTC2 (0x48)
|
||||
#define NPCM7XX_SWRSTC3 (0x4C)
|
||||
#define NPCM7XX_SWRSTC4 (0x50)
|
||||
#define NPCM7XX_CORSTC (0x5C)
|
||||
#define NPCM7XX_PLLCONG (0x60)
|
||||
#define NPCM7XX_AHBCKFI (0x64)
|
||||
#define NPCM7XX_SECCNT (0x68)
|
||||
#define NPCM7XX_CNTR25M (0x6C)
|
||||
|
||||
struct npcm7xx_clk_gate_data {
|
||||
u32 reg;
|
||||
u8 bit_idx;
|
||||
const char *name;
|
||||
const char *parent_name;
|
||||
unsigned long flags;
|
||||
/*
|
||||
* If this clock is exported via DT, set onecell_idx to constant
|
||||
* defined in include/dt-bindings/clock/nuvoton, NPCM7XX-clock.h for
|
||||
* this specific clock. Otherwise, set to -1.
|
||||
*/
|
||||
int onecell_idx;
|
||||
};
|
||||
|
||||
struct npcm7xx_clk_mux_data {
|
||||
u8 shift;
|
||||
u8 mask;
|
||||
u32 *table;
|
||||
const char *name;
|
||||
const char * const *parent_names;
|
||||
u8 num_parents;
|
||||
unsigned long flags;
|
||||
/*
|
||||
* If this clock is exported via DT, set onecell_idx to constant
|
||||
* defined in include/dt-bindings/clock/nuvoton, NPCM7XX-clock.h for
|
||||
* this specific clock. Otherwise, set to -1.
|
||||
*/
|
||||
int onecell_idx;
|
||||
|
||||
};
|
||||
|
||||
struct npcm7xx_clk_div_fixed_data {
|
||||
u8 mult;
|
||||
u8 div;
|
||||
const char *name;
|
||||
const char *parent_name;
|
||||
u8 clk_divider_flags;
|
||||
/*
|
||||
* If this clock is exported via DT, set onecell_idx to constant
|
||||
* defined in include/dt-bindings/clock/nuvoton, NPCM7XX-clock.h for
|
||||
* this specific clock. Otherwise, set to -1.
|
||||
*/
|
||||
int onecell_idx;
|
||||
};
|
||||
|
||||
|
||||
struct npcm7xx_clk_div_data {
|
||||
u32 reg;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
const char *name;
|
||||
const char *parent_name;
|
||||
u8 clk_divider_flags;
|
||||
unsigned long flags;
|
||||
/*
|
||||
* If this clock is exported via DT, set onecell_idx to constant
|
||||
* defined in include/dt-bindings/clock/nuvoton, NPCM7XX-clock.h for
|
||||
* this specific clock. Otherwise, set to -1.
|
||||
*/
|
||||
int onecell_idx;
|
||||
};
|
||||
|
||||
struct npcm7xx_clk_pll_data {
|
||||
u32 reg;
|
||||
const char *name;
|
||||
const char *parent_name;
|
||||
unsigned long flags;
|
||||
/*
|
||||
* If this clock is exported via DT, set onecell_idx to constant
|
||||
* defined in include/dt-bindings/clock/nuvoton, NPCM7XX-clock.h for
|
||||
* this specific clock. Otherwise, set to -1.
|
||||
*/
|
||||
int onecell_idx;
|
||||
};
|
||||
|
||||
/*
|
||||
* Single copy of strings used to refer to clocks within this driver indexed by
|
||||
* above enum.
|
||||
*/
|
||||
#define NPCM7XX_CLK_S_REFCLK "refclk"
|
||||
#define NPCM7XX_CLK_S_SYSBYPCK "sysbypck"
|
||||
#define NPCM7XX_CLK_S_MCBYPCK "mcbypck"
|
||||
#define NPCM7XX_CLK_S_GFXBYPCK "gfxbypck"
|
||||
#define NPCM7XX_CLK_S_PLL0 "pll0"
|
||||
#define NPCM7XX_CLK_S_PLL1 "pll1"
|
||||
#define NPCM7XX_CLK_S_PLL1_DIV2 "pll1_div2"
|
||||
#define NPCM7XX_CLK_S_PLL2 "pll2"
|
||||
#define NPCM7XX_CLK_S_PLL_GFX "pll_gfx"
|
||||
#define NPCM7XX_CLK_S_PLL2_DIV2 "pll2_div2"
|
||||
#define NPCM7XX_CLK_S_PIX_MUX "gfx_pixel"
|
||||
#define NPCM7XX_CLK_S_GPRFSEL_MUX "gprfsel_mux"
|
||||
#define NPCM7XX_CLK_S_MC_MUX "mc_phy"
|
||||
#define NPCM7XX_CLK_S_CPU_MUX "cpu" /*AKA system clock.*/
|
||||
#define NPCM7XX_CLK_S_MC "mc"
|
||||
#define NPCM7XX_CLK_S_AXI "axi" /*AKA CLK2*/
|
||||
#define NPCM7XX_CLK_S_AHB "ahb" /*AKA CLK4*/
|
||||
#define NPCM7XX_CLK_S_CLKOUT_MUX "clkout_mux"
|
||||
#define NPCM7XX_CLK_S_UART_MUX "uart_mux"
|
||||
#define NPCM7XX_CLK_S_TIM_MUX "timer_mux"
|
||||
#define NPCM7XX_CLK_S_SD_MUX "sd_mux"
|
||||
#define NPCM7XX_CLK_S_GFXM_MUX "gfxm_mux"
|
||||
#define NPCM7XX_CLK_S_SU_MUX "serial_usb_mux"
|
||||
#define NPCM7XX_CLK_S_DVC_MUX "dvc_mux"
|
||||
#define NPCM7XX_CLK_S_GFX_MUX "gfx_mux"
|
||||
#define NPCM7XX_CLK_S_GFX_PIXEL "gfx_pixel"
|
||||
#define NPCM7XX_CLK_S_SPI0 "spi0"
|
||||
#define NPCM7XX_CLK_S_SPI3 "spi3"
|
||||
#define NPCM7XX_CLK_S_SPIX "spix"
|
||||
#define NPCM7XX_CLK_S_APB1 "apb1"
|
||||
#define NPCM7XX_CLK_S_APB2 "apb2"
|
||||
#define NPCM7XX_CLK_S_APB3 "apb3"
|
||||
#define NPCM7XX_CLK_S_APB4 "apb4"
|
||||
#define NPCM7XX_CLK_S_APB5 "apb5"
|
||||
#define NPCM7XX_CLK_S_TOCK "tock"
|
||||
#define NPCM7XX_CLK_S_CLKOUT "clkout"
|
||||
#define NPCM7XX_CLK_S_UART "uart"
|
||||
#define NPCM7XX_CLK_S_TIMER "timer"
|
||||
#define NPCM7XX_CLK_S_MMC "mmc"
|
||||
#define NPCM7XX_CLK_S_SDHC "sdhc"
|
||||
#define NPCM7XX_CLK_S_ADC "adc"
|
||||
#define NPCM7XX_CLK_S_GFX "gfx0_gfx1_mem"
|
||||
#define NPCM7XX_CLK_S_USBIF "serial_usbif"
|
||||
#define NPCM7XX_CLK_S_USB_HOST "usb_host"
|
||||
#define NPCM7XX_CLK_S_USB_BRIDGE "usb_bridge"
|
||||
#define NPCM7XX_CLK_S_PCI "pci"
|
||||
|
||||
static u32 pll_mux_table[] = {0, 1, 2, 3};
|
||||
static const char * const pll_mux_parents[] __initconst = {
|
||||
NPCM7XX_CLK_S_PLL0,
|
||||
NPCM7XX_CLK_S_PLL1_DIV2,
|
||||
NPCM7XX_CLK_S_REFCLK,
|
||||
NPCM7XX_CLK_S_PLL2_DIV2,
|
||||
};
|
||||
|
||||
static u32 cpuck_mux_table[] = {0, 1, 2, 3};
|
||||
static const char * const cpuck_mux_parents[] __initconst = {
|
||||
NPCM7XX_CLK_S_PLL0,
|
||||
NPCM7XX_CLK_S_PLL1_DIV2,
|
||||
NPCM7XX_CLK_S_REFCLK,
|
||||
NPCM7XX_CLK_S_SYSBYPCK,
|
||||
};
|
||||
|
||||
static u32 pixcksel_mux_table[] = {0, 2};
|
||||
static const char * const pixcksel_mux_parents[] __initconst = {
|
||||
NPCM7XX_CLK_S_PLL_GFX,
|
||||
NPCM7XX_CLK_S_REFCLK,
|
||||
};
|
||||
|
||||
static u32 sucksel_mux_table[] = {2, 3};
|
||||
static const char * const sucksel_mux_parents[] __initconst = {
|
||||
NPCM7XX_CLK_S_REFCLK,
|
||||
NPCM7XX_CLK_S_PLL2_DIV2,
|
||||
};
|
||||
|
||||
static u32 mccksel_mux_table[] = {0, 2, 3};
|
||||
static const char * const mccksel_mux_parents[] __initconst = {
|
||||
NPCM7XX_CLK_S_PLL1_DIV2,
|
||||
NPCM7XX_CLK_S_REFCLK,
|
||||
NPCM7XX_CLK_S_MCBYPCK,
|
||||
};
|
||||
|
||||
static u32 clkoutsel_mux_table[] = {0, 1, 2, 3, 4};
|
||||
static const char * const clkoutsel_mux_parents[] __initconst = {
|
||||
NPCM7XX_CLK_S_PLL0,
|
||||
NPCM7XX_CLK_S_PLL1_DIV2,
|
||||
NPCM7XX_CLK_S_REFCLK,
|
||||
NPCM7XX_CLK_S_PLL_GFX, // divided by 2
|
||||
NPCM7XX_CLK_S_PLL2_DIV2,
|
||||
};
|
||||
|
||||
static u32 gfxmsel_mux_table[] = {2, 3};
|
||||
static const char * const gfxmsel_mux_parents[] __initconst = {
|
||||
NPCM7XX_CLK_S_REFCLK,
|
||||
NPCM7XX_CLK_S_PLL2_DIV2,
|
||||
};
|
||||
|
||||
static u32 dvcssel_mux_table[] = {2, 3};
|
||||
static const char * const dvcssel_mux_parents[] __initconst = {
|
||||
NPCM7XX_CLK_S_REFCLK,
|
||||
NPCM7XX_CLK_S_PLL2,
|
||||
};
|
||||
|
||||
static const struct npcm7xx_clk_pll_data npcm7xx_plls[] __initconst = {
|
||||
{NPCM7XX_PLLCON0, NPCM7XX_CLK_S_PLL0, NPCM7XX_CLK_S_REFCLK, 0, -1},
|
||||
|
||||
{NPCM7XX_PLLCON1, NPCM7XX_CLK_S_PLL1,
|
||||
NPCM7XX_CLK_S_REFCLK, 0, -1},
|
||||
|
||||
{NPCM7XX_PLLCON2, NPCM7XX_CLK_S_PLL2,
|
||||
NPCM7XX_CLK_S_REFCLK, 0, -1},
|
||||
|
||||
{NPCM7XX_PLLCONG, NPCM7XX_CLK_S_PLL_GFX,
|
||||
NPCM7XX_CLK_S_REFCLK, 0, -1},
|
||||
};
|
||||
|
||||
static const struct npcm7xx_clk_mux_data npcm7xx_muxes[] __initconst = {
|
||||
{0, GENMASK(1, 0), cpuck_mux_table, NPCM7XX_CLK_S_CPU_MUX,
|
||||
cpuck_mux_parents, ARRAY_SIZE(cpuck_mux_parents), CLK_IS_CRITICAL,
|
||||
NPCM7XX_CLK_CPU},
|
||||
|
||||
{4, GENMASK(1, 0), pixcksel_mux_table, NPCM7XX_CLK_S_PIX_MUX,
|
||||
pixcksel_mux_parents, ARRAY_SIZE(pixcksel_mux_parents), 0,
|
||||
NPCM7XX_CLK_GFX_PIXEL},
|
||||
|
||||
{6, GENMASK(1, 0), pll_mux_table, NPCM7XX_CLK_S_SD_MUX,
|
||||
pll_mux_parents, ARRAY_SIZE(pll_mux_parents), 0, -1},
|
||||
|
||||
{8, GENMASK(1, 0), pll_mux_table, NPCM7XX_CLK_S_UART_MUX,
|
||||
pll_mux_parents, ARRAY_SIZE(pll_mux_parents), 0, -1},
|
||||
|
||||
{10, GENMASK(1, 0), sucksel_mux_table, NPCM7XX_CLK_S_SU_MUX,
|
||||
sucksel_mux_parents, ARRAY_SIZE(sucksel_mux_parents), 0, -1},
|
||||
|
||||
{12, GENMASK(1, 0), mccksel_mux_table, NPCM7XX_CLK_S_MC_MUX,
|
||||
mccksel_mux_parents, ARRAY_SIZE(mccksel_mux_parents), 0, -1},
|
||||
|
||||
{14, GENMASK(1, 0), pll_mux_table, NPCM7XX_CLK_S_TIM_MUX,
|
||||
pll_mux_parents, ARRAY_SIZE(pll_mux_parents), 0, -1},
|
||||
|
||||
{16, GENMASK(1, 0), pll_mux_table, NPCM7XX_CLK_S_GFX_MUX,
|
||||
pll_mux_parents, ARRAY_SIZE(pll_mux_parents), 0, -1},
|
||||
|
||||
{18, GENMASK(2, 0), clkoutsel_mux_table, NPCM7XX_CLK_S_CLKOUT_MUX,
|
||||
clkoutsel_mux_parents, ARRAY_SIZE(clkoutsel_mux_parents), 0, -1},
|
||||
|
||||
{21, GENMASK(1, 0), gfxmsel_mux_table, NPCM7XX_CLK_S_GFXM_MUX,
|
||||
gfxmsel_mux_parents, ARRAY_SIZE(gfxmsel_mux_parents), 0, -1},
|
||||
|
||||
{23, GENMASK(1, 0), dvcssel_mux_table, NPCM7XX_CLK_S_DVC_MUX,
|
||||
dvcssel_mux_parents, ARRAY_SIZE(dvcssel_mux_parents), 0, -1},
|
||||
};
|
||||
|
||||
/* fixed ratio dividers (no register): */
|
||||
static const struct npcm7xx_clk_div_fixed_data npcm7xx_divs_fx[] __initconst = {
|
||||
{ 1, 2, NPCM7XX_CLK_S_MC, NPCM7XX_CLK_S_MC_MUX, 0, NPCM7XX_CLK_MC},
|
||||
{ 1, 2, NPCM7XX_CLK_S_PLL1_DIV2, NPCM7XX_CLK_S_PLL1, 0, -1},
|
||||
{ 1, 2, NPCM7XX_CLK_S_PLL2_DIV2, NPCM7XX_CLK_S_PLL2, 0, -1},
|
||||
};
|
||||
|
||||
/* configurable dividers: */
|
||||
static const struct npcm7xx_clk_div_data npcm7xx_divs[] __initconst = {
|
||||
{NPCM7XX_CLKDIV1, 28, 3, NPCM7XX_CLK_S_ADC,
|
||||
NPCM7XX_CLK_S_TIMER, CLK_DIVIDER_POWER_OF_TWO, 0, NPCM7XX_CLK_ADC},
|
||||
/*30-28 ADCCKDIV*/
|
||||
{NPCM7XX_CLKDIV1, 26, 2, NPCM7XX_CLK_S_AHB,
|
||||
NPCM7XX_CLK_S_AXI, 0, CLK_IS_CRITICAL, NPCM7XX_CLK_AHB},
|
||||
/*27-26 CLK4DIV*/
|
||||
{NPCM7XX_CLKDIV1, 21, 5, NPCM7XX_CLK_S_TIMER,
|
||||
NPCM7XX_CLK_S_TIM_MUX, 0, 0, NPCM7XX_CLK_TIMER},
|
||||
/*25-21 TIMCKDIV*/
|
||||
{NPCM7XX_CLKDIV1, 16, 5, NPCM7XX_CLK_S_UART,
|
||||
NPCM7XX_CLK_S_UART_MUX, 0, 0, NPCM7XX_CLK_UART},
|
||||
/*20-16 UARTDIV*/
|
||||
{NPCM7XX_CLKDIV1, 11, 5, NPCM7XX_CLK_S_MMC,
|
||||
NPCM7XX_CLK_S_SD_MUX, 0, 0, NPCM7XX_CLK_MMC},
|
||||
/*15-11 MMCCKDIV*/
|
||||
{NPCM7XX_CLKDIV1, 6, 5, NPCM7XX_CLK_S_SPI3,
|
||||
NPCM7XX_CLK_S_AHB, 0, 0, NPCM7XX_CLK_SPI3},
|
||||
/*10-6 AHB3CKDIV*/
|
||||
{NPCM7XX_CLKDIV1, 2, 4, NPCM7XX_CLK_S_PCI,
|
||||
NPCM7XX_CLK_S_GFX_MUX, 0, 0, NPCM7XX_CLK_PCI},
|
||||
/*5-2 PCICKDIV*/
|
||||
{NPCM7XX_CLKDIV1, 0, 1, NPCM7XX_CLK_S_AXI,
|
||||
NPCM7XX_CLK_S_CPU_MUX, CLK_DIVIDER_POWER_OF_TWO, CLK_IS_CRITICAL,
|
||||
NPCM7XX_CLK_AXI},/*0 CLK2DIV*/
|
||||
|
||||
{NPCM7XX_CLKDIV2, 30, 2, NPCM7XX_CLK_S_APB4,
|
||||
NPCM7XX_CLK_S_AHB, CLK_DIVIDER_POWER_OF_TWO, 0, NPCM7XX_CLK_APB4},
|
||||
/*31-30 APB4CKDIV*/
|
||||
{NPCM7XX_CLKDIV2, 28, 2, NPCM7XX_CLK_S_APB3,
|
||||
NPCM7XX_CLK_S_AHB, CLK_DIVIDER_POWER_OF_TWO, 0, NPCM7XX_CLK_APB3},
|
||||
/*29-28 APB3CKDIV*/
|
||||
{NPCM7XX_CLKDIV2, 26, 2, NPCM7XX_CLK_S_APB2,
|
||||
NPCM7XX_CLK_S_AHB, CLK_DIVIDER_POWER_OF_TWO, 0, NPCM7XX_CLK_APB2},
|
||||
/*27-26 APB2CKDIV*/
|
||||
{NPCM7XX_CLKDIV2, 24, 2, NPCM7XX_CLK_S_APB1,
|
||||
NPCM7XX_CLK_S_AHB, CLK_DIVIDER_POWER_OF_TWO, 0, NPCM7XX_CLK_APB1},
|
||||
/*25-24 APB1CKDIV*/
|
||||
{NPCM7XX_CLKDIV2, 22, 2, NPCM7XX_CLK_S_APB5,
|
||||
NPCM7XX_CLK_S_AHB, CLK_DIVIDER_POWER_OF_TWO, 0, NPCM7XX_CLK_APB5},
|
||||
/*23-22 APB5CKDIV*/
|
||||
{NPCM7XX_CLKDIV2, 16, 5, NPCM7XX_CLK_S_CLKOUT,
|
||||
NPCM7XX_CLK_S_CLKOUT_MUX, 0, 0, NPCM7XX_CLK_CLKOUT},
|
||||
/*20-16 CLKOUTDIV*/
|
||||
{NPCM7XX_CLKDIV2, 13, 3, NPCM7XX_CLK_S_GFX,
|
||||
NPCM7XX_CLK_S_GFX_MUX, 0, 0, NPCM7XX_CLK_GFX},
|
||||
/*15-13 GFXCKDIV*/
|
||||
{NPCM7XX_CLKDIV2, 8, 5, NPCM7XX_CLK_S_USB_BRIDGE,
|
||||
NPCM7XX_CLK_S_SU_MUX, 0, 0, NPCM7XX_CLK_SU},
|
||||
/*12-8 SUCKDIV*/
|
||||
{NPCM7XX_CLKDIV2, 4, 4, NPCM7XX_CLK_S_USB_HOST,
|
||||
NPCM7XX_CLK_S_SU_MUX, 0, 0, NPCM7XX_CLK_SU48},
|
||||
/*7-4 SU48CKDIV*/
|
||||
{NPCM7XX_CLKDIV2, 0, 4, NPCM7XX_CLK_S_SDHC,
|
||||
NPCM7XX_CLK_S_SD_MUX, 0, 0, NPCM7XX_CLK_SDHC}
|
||||
,/*3-0 SD1CKDIV*/
|
||||
|
||||
{NPCM7XX_CLKDIV3, 6, 5, NPCM7XX_CLK_S_SPI0,
|
||||
NPCM7XX_CLK_S_AHB, 0, 0, NPCM7XX_CLK_SPI0},
|
||||
/*10-6 SPI0CKDV*/
|
||||
{NPCM7XX_CLKDIV3, 1, 5, NPCM7XX_CLK_S_SPIX,
|
||||
NPCM7XX_CLK_S_AHB, 0, 0, NPCM7XX_CLK_SPIX},
|
||||
/*5-1 SPIXCKDV*/
|
||||
|
||||
};
|
||||
|
||||
static const struct npcm7xx_clk_gate_data npcm7xx_gates[] __initconst = {
|
||||
{NPCM7XX_CLKEN1, 31, "smb1-gate", NPCM7XX_CLK_S_APB2, 0},
|
||||
{NPCM7XX_CLKEN1, 30, "smb0-gate", NPCM7XX_CLK_S_APB2, 0},
|
||||
{NPCM7XX_CLKEN1, 29, "smb7-gate", NPCM7XX_CLK_S_APB2, 0},
|
||||
{NPCM7XX_CLKEN1, 28, "smb6-gate", NPCM7XX_CLK_S_APB2, 0},
|
||||
{NPCM7XX_CLKEN1, 27, "adc-gate", NPCM7XX_CLK_S_APB1, 0},
|
||||
{NPCM7XX_CLKEN1, 26, "wdt-gate", NPCM7XX_CLK_S_TIMER, 0},
|
||||
{NPCM7XX_CLKEN1, 25, "usbdev3-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN1, 24, "usbdev6-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN1, 23, "usbdev5-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN1, 22, "usbdev4-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN1, 21, "emc2-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN1, 20, "timer5_9-gate", NPCM7XX_CLK_S_APB1, 0},
|
||||
{NPCM7XX_CLKEN1, 19, "timer0_4-gate", NPCM7XX_CLK_S_APB1, 0},
|
||||
{NPCM7XX_CLKEN1, 18, "pwmm0-gate", NPCM7XX_CLK_S_APB3, 0},
|
||||
{NPCM7XX_CLKEN1, 17, "huart-gate", NPCM7XX_CLK_S_UART, 0},
|
||||
{NPCM7XX_CLKEN1, 16, "smb5-gate", NPCM7XX_CLK_S_APB2, 0},
|
||||
{NPCM7XX_CLKEN1, 15, "smb4-gate", NPCM7XX_CLK_S_APB2, 0},
|
||||
{NPCM7XX_CLKEN1, 14, "smb3-gate", NPCM7XX_CLK_S_APB2, 0},
|
||||
{NPCM7XX_CLKEN1, 13, "smb2-gate", NPCM7XX_CLK_S_APB2, 0},
|
||||
{NPCM7XX_CLKEN1, 12, "mc-gate", NPCM7XX_CLK_S_MC, 0},
|
||||
{NPCM7XX_CLKEN1, 11, "uart01-gate", NPCM7XX_CLK_S_APB1, 0},
|
||||
{NPCM7XX_CLKEN1, 10, "aes-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN1, 9, "peci-gate", NPCM7XX_CLK_S_APB3, 0},
|
||||
{NPCM7XX_CLKEN1, 8, "usbdev2-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN1, 7, "uart23-gate", NPCM7XX_CLK_S_APB1, 0},
|
||||
{NPCM7XX_CLKEN1, 6, "emc1-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN1, 5, "usbdev1-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN1, 4, "shm-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
/* bit 3 is reserved */
|
||||
{NPCM7XX_CLKEN1, 2, "kcs-gate", NPCM7XX_CLK_S_APB1, 0},
|
||||
{NPCM7XX_CLKEN1, 1, "spi3-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN1, 0, "spi0-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
|
||||
{NPCM7XX_CLKEN2, 31, "cp-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN2, 30, "tock-gate", NPCM7XX_CLK_S_TOCK, 0},
|
||||
/* bit 29 is reserved */
|
||||
{NPCM7XX_CLKEN2, 28, "gmac1-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN2, 27, "usbif-gate", NPCM7XX_CLK_S_USBIF, 0},
|
||||
{NPCM7XX_CLKEN2, 26, "usbhost-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN2, 25, "gmac2-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
/* bit 24 is reserved */
|
||||
{NPCM7XX_CLKEN2, 23, "pspi2-gate", NPCM7XX_CLK_S_APB5, 0},
|
||||
{NPCM7XX_CLKEN2, 22, "pspi1-gate", NPCM7XX_CLK_S_APB5, 0},
|
||||
{NPCM7XX_CLKEN2, 21, "3des-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
/* bit 20 is reserved */
|
||||
{NPCM7XX_CLKEN2, 19, "siox2-gate", NPCM7XX_CLK_S_APB3, 0},
|
||||
{NPCM7XX_CLKEN2, 18, "siox1-gate", NPCM7XX_CLK_S_APB3, 0},
|
||||
/* bit 17 is reserved */
|
||||
{NPCM7XX_CLKEN2, 16, "fuse-gate", NPCM7XX_CLK_S_APB4, 0},
|
||||
/* bit 15 is reserved */
|
||||
{NPCM7XX_CLKEN2, 14, "vcd-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN2, 13, "ece-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN2, 12, "vdma-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN2, 11, "ahbpcibrg-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN2, 10, "gfxsys-gate", NPCM7XX_CLK_S_APB1, 0},
|
||||
{NPCM7XX_CLKEN2, 9, "sdhc-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN2, 8, "mmc-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN2, 7, "mft7-gate", NPCM7XX_CLK_S_APB4, 0},
|
||||
{NPCM7XX_CLKEN2, 6, "mft6-gate", NPCM7XX_CLK_S_APB4, 0},
|
||||
{NPCM7XX_CLKEN2, 5, "mft5-gate", NPCM7XX_CLK_S_APB4, 0},
|
||||
{NPCM7XX_CLKEN2, 4, "mft4-gate", NPCM7XX_CLK_S_APB4, 0},
|
||||
{NPCM7XX_CLKEN2, 3, "mft3-gate", NPCM7XX_CLK_S_APB4, 0},
|
||||
{NPCM7XX_CLKEN2, 2, "mft2-gate", NPCM7XX_CLK_S_APB4, 0},
|
||||
{NPCM7XX_CLKEN2, 1, "mft1-gate", NPCM7XX_CLK_S_APB4, 0},
|
||||
{NPCM7XX_CLKEN2, 0, "mft0-gate", NPCM7XX_CLK_S_APB4, 0},
|
||||
|
||||
{NPCM7XX_CLKEN3, 31, "gpiom7-gate", NPCM7XX_CLK_S_APB1, 0},
|
||||
{NPCM7XX_CLKEN3, 30, "gpiom6-gate", NPCM7XX_CLK_S_APB1, 0},
|
||||
{NPCM7XX_CLKEN3, 29, "gpiom5-gate", NPCM7XX_CLK_S_APB1, 0},
|
||||
{NPCM7XX_CLKEN3, 28, "gpiom4-gate", NPCM7XX_CLK_S_APB1, 0},
|
||||
{NPCM7XX_CLKEN3, 27, "gpiom3-gate", NPCM7XX_CLK_S_APB1, 0},
|
||||
{NPCM7XX_CLKEN3, 26, "gpiom2-gate", NPCM7XX_CLK_S_APB1, 0},
|
||||
{NPCM7XX_CLKEN3, 25, "gpiom1-gate", NPCM7XX_CLK_S_APB1, 0},
|
||||
{NPCM7XX_CLKEN3, 24, "gpiom0-gate", NPCM7XX_CLK_S_APB1, 0},
|
||||
{NPCM7XX_CLKEN3, 23, "espi-gate", NPCM7XX_CLK_S_APB2, 0},
|
||||
{NPCM7XX_CLKEN3, 22, "smb11-gate", NPCM7XX_CLK_S_APB2, 0},
|
||||
{NPCM7XX_CLKEN3, 21, "smb10-gate", NPCM7XX_CLK_S_APB2, 0},
|
||||
{NPCM7XX_CLKEN3, 20, "smb9-gate", NPCM7XX_CLK_S_APB2, 0},
|
||||
{NPCM7XX_CLKEN3, 19, "smb8-gate", NPCM7XX_CLK_S_APB2, 0},
|
||||
{NPCM7XX_CLKEN3, 18, "smb15-gate", NPCM7XX_CLK_S_APB2, 0},
|
||||
{NPCM7XX_CLKEN3, 17, "rng-gate", NPCM7XX_CLK_S_APB1, 0},
|
||||
{NPCM7XX_CLKEN3, 16, "timer10_14-gate", NPCM7XX_CLK_S_APB1, 0},
|
||||
{NPCM7XX_CLKEN3, 15, "pcirc-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN3, 14, "sececc-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN3, 13, "sha-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN3, 12, "smb14-gate", NPCM7XX_CLK_S_APB2, 0},
|
||||
/* bit 11 is reserved */
|
||||
/* bit 10 is reserved */
|
||||
{NPCM7XX_CLKEN3, 9, "pcimbx-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
/* bit 8 is reserved */
|
||||
{NPCM7XX_CLKEN3, 7, "usbdev9-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN3, 6, "usbdev8-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN3, 5, "usbdev7-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN3, 4, "usbdev0-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN3, 3, "smb13-gate", NPCM7XX_CLK_S_APB2, 0},
|
||||
{NPCM7XX_CLKEN3, 2, "spix-gate", NPCM7XX_CLK_S_AHB, 0},
|
||||
{NPCM7XX_CLKEN3, 1, "smb12-gate", NPCM7XX_CLK_S_APB2, 0},
|
||||
{NPCM7XX_CLKEN3, 0, "pwmm1-gate", NPCM7XX_CLK_S_APB3, 0},
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(npcm7xx_clk_lock);
|
||||
|
||||
static void __init npcm7xx_clk_init(struct device_node *clk_np)
|
||||
{
|
||||
struct clk_hw_onecell_data *npcm7xx_clk_data;
|
||||
void __iomem *clk_base;
|
||||
struct resource res;
|
||||
struct clk_hw *hw;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ret = of_address_to_resource(clk_np, 0, &res);
|
||||
if (ret) {
|
||||
pr_err("%s: failed to get resource, ret %d\n", clk_np->name,
|
||||
ret);
|
||||
return;
|
||||
}
|
||||
|
||||
clk_base = ioremap(res.start, resource_size(&res));
|
||||
if (!clk_base)
|
||||
goto npcm7xx_init_error;
|
||||
|
||||
npcm7xx_clk_data = kzalloc(sizeof(*npcm7xx_clk_data->hws) *
|
||||
NPCM7XX_NUM_CLOCKS + sizeof(npcm7xx_clk_data), GFP_KERNEL);
|
||||
if (!npcm7xx_clk_data)
|
||||
goto npcm7xx_init_np_err;
|
||||
|
||||
npcm7xx_clk_data->num = NPCM7XX_NUM_CLOCKS;
|
||||
|
||||
for (i = 0; i < NPCM7XX_NUM_CLOCKS; i++)
|
||||
npcm7xx_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
/* Register plls */
|
||||
for (i = 0; i < ARRAY_SIZE(npcm7xx_plls); i++) {
|
||||
const struct npcm7xx_clk_pll_data *pll_data = &npcm7xx_plls[i];
|
||||
|
||||
hw = npcm7xx_clk_register_pll(clk_base + pll_data->reg,
|
||||
pll_data->name, pll_data->parent_name, pll_data->flags);
|
||||
if (IS_ERR(hw)) {
|
||||
pr_err("npcm7xx_clk: Can't register pll\n");
|
||||
goto npcm7xx_init_fail;
|
||||
}
|
||||
|
||||
if (pll_data->onecell_idx >= 0)
|
||||
npcm7xx_clk_data->hws[pll_data->onecell_idx] = hw;
|
||||
}
|
||||
|
||||
/* Register fixed dividers */
|
||||
hw = clk_hw_register_fixed_factor(NULL, NPCM7XX_CLK_S_PLL1_DIV2,
|
||||
NPCM7XX_CLK_S_PLL1, 0, 1, 2);
|
||||
if (IS_ERR(hw)) {
|
||||
pr_err("npcm7xx_clk: Can't register fixed div\n");
|
||||
goto npcm7xx_init_fail;
|
||||
}
|
||||
|
||||
hw = clk_hw_register_fixed_factor(NULL, NPCM7XX_CLK_S_PLL2_DIV2,
|
||||
NPCM7XX_CLK_S_PLL2, 0, 1, 2);
|
||||
if (IS_ERR(hw)) {
|
||||
pr_err("npcm7xx_clk: Can't register div2\n");
|
||||
goto npcm7xx_init_fail;
|
||||
}
|
||||
|
||||
/* Register muxes */
|
||||
for (i = 0; i < ARRAY_SIZE(npcm7xx_muxes); i++) {
|
||||
const struct npcm7xx_clk_mux_data *mux_data = &npcm7xx_muxes[i];
|
||||
|
||||
hw = clk_hw_register_mux_table(NULL,
|
||||
mux_data->name,
|
||||
mux_data->parent_names, mux_data->num_parents,
|
||||
mux_data->flags, clk_base + NPCM7XX_CLKSEL,
|
||||
mux_data->shift, mux_data->mask, 0,
|
||||
mux_data->table, &npcm7xx_clk_lock);
|
||||
|
||||
if (IS_ERR(hw)) {
|
||||
pr_err("npcm7xx_clk: Can't register mux\n");
|
||||
goto npcm7xx_init_fail;
|
||||
}
|
||||
|
||||
if (mux_data->onecell_idx >= 0)
|
||||
npcm7xx_clk_data->hws[mux_data->onecell_idx] = hw;
|
||||
}
|
||||
|
||||
/* Register clock dividers specified in npcm7xx_divs */
|
||||
for (i = 0; i < ARRAY_SIZE(npcm7xx_divs); i++) {
|
||||
const struct npcm7xx_clk_div_data *div_data = &npcm7xx_divs[i];
|
||||
|
||||
hw = clk_hw_register_divider(NULL, div_data->name,
|
||||
div_data->parent_name,
|
||||
div_data->flags,
|
||||
clk_base + div_data->reg,
|
||||
div_data->shift, div_data->width,
|
||||
div_data->clk_divider_flags, &npcm7xx_clk_lock);
|
||||
if (IS_ERR(hw)) {
|
||||
pr_err("npcm7xx_clk: Can't register div table\n");
|
||||
goto npcm7xx_init_fail;
|
||||
}
|
||||
|
||||
if (div_data->onecell_idx >= 0)
|
||||
npcm7xx_clk_data->hws[div_data->onecell_idx] = hw;
|
||||
}
|
||||
|
||||
ret = of_clk_add_hw_provider(clk_np, of_clk_hw_onecell_get,
|
||||
npcm7xx_clk_data);
|
||||
if (ret)
|
||||
pr_err("failed to add DT provider: %d\n", ret);
|
||||
|
||||
of_node_put(clk_np);
|
||||
|
||||
return;
|
||||
|
||||
npcm7xx_init_fail:
|
||||
kfree(npcm7xx_clk_data->hws);
|
||||
npcm7xx_init_np_err:
|
||||
iounmap(clk_base);
|
||||
npcm7xx_init_error:
|
||||
of_node_put(clk_np);
|
||||
}
|
||||
CLK_OF_DECLARE(npcm7xx_clk_init, "nuvoton,npcm750-clk", npcm7xx_clk_init);
|
@ -207,6 +207,7 @@ static int si544_calc_muldiv(struct clk_si544_muldiv *settings,
|
||||
|
||||
/* And the fractional bits using the remainder */
|
||||
vco = (u64)tmp << 32;
|
||||
vco += FXO / 2; /* Round to nearest multiple */
|
||||
do_div(vco, FXO);
|
||||
settings->fb_div_frac = vco;
|
||||
|
||||
|
@ -579,14 +579,9 @@ clk_stm32_register_gate_ops(struct device *dev,
|
||||
spinlock_t *lock)
|
||||
{
|
||||
struct clk_init_data init = { NULL };
|
||||
struct clk_gate *gate;
|
||||
struct clk_hw *hw;
|
||||
int ret;
|
||||
|
||||
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
|
||||
if (!gate)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
@ -604,10 +599,8 @@ clk_stm32_register_gate_ops(struct device *dev,
|
||||
hw->init = &init;
|
||||
|
||||
ret = clk_hw_register(dev, hw);
|
||||
if (ret) {
|
||||
kfree(gate);
|
||||
if (ret)
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
@ -1988,7 +1981,8 @@ static const struct clock_config stm32mp1_clock_cfg[] = {
|
||||
_DIV(RCC_MCO2CFGR, 4, 4, 0, NULL)),
|
||||
|
||||
/* Debug clocks */
|
||||
GATE(CK_DBG, "ck_sys_dbg", "ck_axi", 0, RCC_DBGCFGR, 8, 0),
|
||||
GATE(CK_DBG, "ck_sys_dbg", "ck_axi", CLK_IGNORE_UNUSED,
|
||||
RCC_DBGCFGR, 8, 0),
|
||||
|
||||
COMPOSITE(CK_TRACE, "ck_trace", ck_trace_src, CLK_OPS_PARENT_ENABLE,
|
||||
_GATE(RCC_DBGCFGR, 9, 0),
|
||||
|
@ -549,7 +549,8 @@ static void clk_core_rate_unprotect(struct clk_core *core)
|
||||
if (!core)
|
||||
return;
|
||||
|
||||
if (WARN_ON(core->protect_count == 0))
|
||||
if (WARN(core->protect_count == 0,
|
||||
"%s already unprotected\n", core->name))
|
||||
return;
|
||||
|
||||
if (--core->protect_count > 0)
|
||||
@ -682,16 +683,18 @@ static void clk_core_unprepare(struct clk_core *core)
|
||||
if (!core)
|
||||
return;
|
||||
|
||||
if (WARN_ON(core->prepare_count == 0))
|
||||
if (WARN(core->prepare_count == 0,
|
||||
"%s already unprepared\n", core->name))
|
||||
return;
|
||||
|
||||
if (WARN_ON(core->prepare_count == 1 && core->flags & CLK_IS_CRITICAL))
|
||||
if (WARN(core->prepare_count == 1 && core->flags & CLK_IS_CRITICAL,
|
||||
"Unpreparing critical %s\n", core->name))
|
||||
return;
|
||||
|
||||
if (--core->prepare_count > 0)
|
||||
return;
|
||||
|
||||
WARN_ON(core->enable_count > 0);
|
||||
WARN(core->enable_count > 0, "Unpreparing enabled %s\n", core->name);
|
||||
|
||||
trace_clk_unprepare(core);
|
||||
|
||||
@ -809,10 +812,11 @@ static void clk_core_disable(struct clk_core *core)
|
||||
if (!core)
|
||||
return;
|
||||
|
||||
if (WARN_ON(core->enable_count == 0))
|
||||
if (WARN(core->enable_count == 0, "%s already disabled\n", core->name))
|
||||
return;
|
||||
|
||||
if (WARN_ON(core->enable_count == 1 && core->flags & CLK_IS_CRITICAL))
|
||||
if (WARN(core->enable_count == 1 && core->flags & CLK_IS_CRITICAL,
|
||||
"Disabling critical %s\n", core->name))
|
||||
return;
|
||||
|
||||
if (--core->enable_count > 0)
|
||||
@ -867,7 +871,8 @@ static int clk_core_enable(struct clk_core *core)
|
||||
if (!core)
|
||||
return 0;
|
||||
|
||||
if (WARN_ON(core->prepare_count == 0))
|
||||
if (WARN(core->prepare_count == 0,
|
||||
"Enabling unprepared %s\n", core->name))
|
||||
return -ESHUTDOWN;
|
||||
|
||||
if (core->enable_count == 0) {
|
||||
@ -2171,7 +2176,6 @@ void clk_hw_reparent(struct clk_hw *hw, struct clk_hw *new_parent)
|
||||
bool clk_has_parent(struct clk *clk, struct clk *parent)
|
||||
{
|
||||
struct clk_core *core, *parent_core;
|
||||
unsigned int i;
|
||||
|
||||
/* NULL clocks should be nops, so return success if either is NULL. */
|
||||
if (!clk || !parent)
|
||||
@ -2184,11 +2188,8 @@ bool clk_has_parent(struct clk *clk, struct clk *parent)
|
||||
if (core->parent == parent_core)
|
||||
return true;
|
||||
|
||||
for (i = 0; i < core->num_parents; i++)
|
||||
if (strcmp(core->parent_names[i], parent_core->name) == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return match_string(core->parent_names, core->num_parents,
|
||||
parent_core->name) >= 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_has_parent);
|
||||
|
||||
@ -2609,81 +2610,31 @@ static int possible_parents_show(struct seq_file *s, void *data)
|
||||
}
|
||||
DEFINE_SHOW_ATTRIBUTE(possible_parents);
|
||||
|
||||
static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
|
||||
static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
|
||||
{
|
||||
struct dentry *d;
|
||||
int ret = -ENOMEM;
|
||||
struct dentry *root;
|
||||
|
||||
if (!core || !pdentry) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (!core || !pdentry)
|
||||
return;
|
||||
|
||||
d = debugfs_create_dir(core->name, pdentry);
|
||||
if (!d)
|
||||
goto out;
|
||||
root = debugfs_create_dir(core->name, pdentry);
|
||||
core->dentry = root;
|
||||
|
||||
core->dentry = d;
|
||||
debugfs_create_ulong("clk_rate", 0444, root, &core->rate);
|
||||
debugfs_create_ulong("clk_accuracy", 0444, root, &core->accuracy);
|
||||
debugfs_create_u32("clk_phase", 0444, root, &core->phase);
|
||||
debugfs_create_file("clk_flags", 0444, root, core, &clk_flags_fops);
|
||||
debugfs_create_u32("clk_prepare_count", 0444, root, &core->prepare_count);
|
||||
debugfs_create_u32("clk_enable_count", 0444, root, &core->enable_count);
|
||||
debugfs_create_u32("clk_protect_count", 0444, root, &core->protect_count);
|
||||
debugfs_create_u32("clk_notifier_count", 0444, root, &core->notifier_count);
|
||||
|
||||
d = debugfs_create_ulong("clk_rate", 0444, core->dentry, &core->rate);
|
||||
if (!d)
|
||||
goto err_out;
|
||||
if (core->num_parents > 1)
|
||||
debugfs_create_file("clk_possible_parents", 0444, root, core,
|
||||
&possible_parents_fops);
|
||||
|
||||
d = debugfs_create_ulong("clk_accuracy", 0444, core->dentry,
|
||||
&core->accuracy);
|
||||
if (!d)
|
||||
goto err_out;
|
||||
|
||||
d = debugfs_create_u32("clk_phase", 0444, core->dentry, &core->phase);
|
||||
if (!d)
|
||||
goto err_out;
|
||||
|
||||
d = debugfs_create_file("clk_flags", 0444, core->dentry, core,
|
||||
&clk_flags_fops);
|
||||
if (!d)
|
||||
goto err_out;
|
||||
|
||||
d = debugfs_create_u32("clk_prepare_count", 0444, core->dentry,
|
||||
&core->prepare_count);
|
||||
if (!d)
|
||||
goto err_out;
|
||||
|
||||
d = debugfs_create_u32("clk_enable_count", 0444, core->dentry,
|
||||
&core->enable_count);
|
||||
if (!d)
|
||||
goto err_out;
|
||||
|
||||
d = debugfs_create_u32("clk_protect_count", 0444, core->dentry,
|
||||
&core->protect_count);
|
||||
if (!d)
|
||||
goto err_out;
|
||||
|
||||
d = debugfs_create_u32("clk_notifier_count", 0444, core->dentry,
|
||||
&core->notifier_count);
|
||||
if (!d)
|
||||
goto err_out;
|
||||
|
||||
if (core->num_parents > 1) {
|
||||
d = debugfs_create_file("clk_possible_parents", 0444,
|
||||
core->dentry, core, &possible_parents_fops);
|
||||
if (!d)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (core->ops->debug_init) {
|
||||
ret = core->ops->debug_init(core->hw, core->dentry);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
goto out;
|
||||
|
||||
err_out:
|
||||
debugfs_remove_recursive(core->dentry);
|
||||
core->dentry = NULL;
|
||||
out:
|
||||
return ret;
|
||||
if (core->ops->debug_init)
|
||||
core->ops->debug_init(core->hw, core->dentry);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2694,17 +2645,13 @@ out:
|
||||
* initialized. Otherwise it bails out early since the debugfs clk directory
|
||||
* will be created lazily by clk_debug_init as part of a late_initcall.
|
||||
*/
|
||||
static int clk_debug_register(struct clk_core *core)
|
||||
static void clk_debug_register(struct clk_core *core)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&clk_debug_lock);
|
||||
hlist_add_head(&core->debug_node, &clk_debug_list);
|
||||
if (inited)
|
||||
ret = clk_debug_create_one(core, rootdir);
|
||||
clk_debug_create_one(core, rootdir);
|
||||
mutex_unlock(&clk_debug_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2724,19 +2671,6 @@ static void clk_debug_unregister(struct clk_core *core)
|
||||
mutex_unlock(&clk_debug_lock);
|
||||
}
|
||||
|
||||
struct dentry *clk_debugfs_add_file(struct clk_hw *hw, char *name, umode_t mode,
|
||||
void *data, const struct file_operations *fops)
|
||||
{
|
||||
struct dentry *d = NULL;
|
||||
|
||||
if (hw->core->dentry)
|
||||
d = debugfs_create_file(name, mode, hw->core->dentry, data,
|
||||
fops);
|
||||
|
||||
return d;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_debugfs_add_file);
|
||||
|
||||
/**
|
||||
* clk_debug_init - lazily populate the debugfs clk directory
|
||||
*
|
||||
@ -2749,32 +2683,17 @@ EXPORT_SYMBOL_GPL(clk_debugfs_add_file);
|
||||
static int __init clk_debug_init(void)
|
||||
{
|
||||
struct clk_core *core;
|
||||
struct dentry *d;
|
||||
|
||||
rootdir = debugfs_create_dir("clk", NULL);
|
||||
|
||||
if (!rootdir)
|
||||
return -ENOMEM;
|
||||
|
||||
d = debugfs_create_file("clk_summary", 0444, rootdir, &all_lists,
|
||||
&clk_summary_fops);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
d = debugfs_create_file("clk_dump", 0444, rootdir, &all_lists,
|
||||
&clk_dump_fops);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
d = debugfs_create_file("clk_orphan_summary", 0444, rootdir,
|
||||
&orphan_list, &clk_summary_fops);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
d = debugfs_create_file("clk_orphan_dump", 0444, rootdir,
|
||||
&orphan_list, &clk_dump_fops);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
debugfs_create_file("clk_summary", 0444, rootdir, &all_lists,
|
||||
&clk_summary_fops);
|
||||
debugfs_create_file("clk_dump", 0444, rootdir, &all_lists,
|
||||
&clk_dump_fops);
|
||||
debugfs_create_file("clk_orphan_summary", 0444, rootdir, &orphan_list,
|
||||
&clk_summary_fops);
|
||||
debugfs_create_file("clk_orphan_dump", 0444, rootdir, &orphan_list,
|
||||
&clk_dump_fops);
|
||||
|
||||
mutex_lock(&clk_debug_lock);
|
||||
hlist_for_each_entry(core, &clk_debug_list, debug_node)
|
||||
@ -2787,7 +2706,7 @@ static int __init clk_debug_init(void)
|
||||
}
|
||||
late_initcall(clk_debug_init);
|
||||
#else
|
||||
static inline int clk_debug_register(struct clk_core *core) { return 0; }
|
||||
static inline void clk_debug_register(struct clk_core *core) { }
|
||||
static inline void clk_debug_reparent(struct clk_core *core,
|
||||
struct clk_core *new_parent)
|
||||
{
|
||||
@ -3907,7 +3826,7 @@ int of_clk_parent_fill(struct device_node *np, const char **parents,
|
||||
EXPORT_SYMBOL_GPL(of_clk_parent_fill);
|
||||
|
||||
struct clock_provider {
|
||||
of_clk_init_cb_t clk_init_cb;
|
||||
void (*clk_init_cb)(struct device_node *);
|
||||
struct device_node *np;
|
||||
struct list_head node;
|
||||
};
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk/davinci.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
@ -36,11 +37,11 @@ SYSCLK(5, pll0_sysclk5, pll0_pllen, 5, 0);
|
||||
SYSCLK(6, pll0_sysclk6, pll0_pllen, 5, SYSCLK_FIXED_DIV);
|
||||
SYSCLK(7, pll0_sysclk7, pll0_pllen, 5, 0);
|
||||
|
||||
int da830_pll_init(struct device *dev, void __iomem *base)
|
||||
int da830_pll_init(struct device *dev, void __iomem *base, struct regmap *cfgchip)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
davinci_pll_clk_register(dev, &da830_pll_info, "ref_clk", base);
|
||||
davinci_pll_clk_register(dev, &da830_pll_info, "ref_clk", base, cfgchip);
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll0_sysclk2, base);
|
||||
clk_register_clkdev(clk, "pll0_sysclk2", "da830-psc0");
|
||||
|
@ -7,10 +7,14 @@
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk/davinci.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/da8xx-cfgchip.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
@ -81,11 +85,11 @@ static const struct davinci_pll_obsclk_info da850_pll0_obsclk_info = {
|
||||
.ocsrc_mask = GENMASK(4, 0),
|
||||
};
|
||||
|
||||
int da850_pll0_init(struct device *dev, void __iomem *base)
|
||||
int da850_pll0_init(struct device *dev, void __iomem *base, struct regmap *cfgchip)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
davinci_pll_clk_register(dev, &da850_pll0_info, "ref_clk", base);
|
||||
davinci_pll_clk_register(dev, &da850_pll0_info, "ref_clk", base, cfgchip);
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll0_sysclk1, base);
|
||||
clk_register_clkdev(clk, "pll0_sysclk1", "da850-psc0");
|
||||
@ -134,11 +138,22 @@ static const struct davinci_pll_sysclk_info *da850_pll0_sysclk_info[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
int of_da850_pll0_init(struct device *dev, void __iomem *base)
|
||||
void of_da850_pll0_init(struct device_node *node)
|
||||
{
|
||||
return of_davinci_pll_init(dev, &da850_pll0_info,
|
||||
&da850_pll0_obsclk_info,
|
||||
da850_pll0_sysclk_info, 7, base);
|
||||
void __iomem *base;
|
||||
struct regmap *cfgchip;
|
||||
|
||||
base = of_iomap(node, 0);
|
||||
if (!base) {
|
||||
pr_err("%s: ioremap failed\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
cfgchip = syscon_regmap_lookup_by_compatible("ti,da830-cfgchip");
|
||||
|
||||
of_davinci_pll_init(NULL, node, &da850_pll0_info,
|
||||
&da850_pll0_obsclk_info,
|
||||
da850_pll0_sysclk_info, 7, base, cfgchip);
|
||||
}
|
||||
|
||||
static const struct davinci_pll_clk_info da850_pll1_info = {
|
||||
@ -179,11 +194,11 @@ static const struct davinci_pll_obsclk_info da850_pll1_obsclk_info = {
|
||||
.ocsrc_mask = GENMASK(4, 0),
|
||||
};
|
||||
|
||||
int da850_pll1_init(struct device *dev, void __iomem *base)
|
||||
int da850_pll1_init(struct device *dev, void __iomem *base, struct regmap *cfgchip)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
davinci_pll_clk_register(dev, &da850_pll1_info, "oscin", base);
|
||||
davinci_pll_clk_register(dev, &da850_pll1_info, "oscin", base, cfgchip);
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll1_sysclk1, base);
|
||||
|
||||
@ -204,9 +219,9 @@ static const struct davinci_pll_sysclk_info *da850_pll1_sysclk_info[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
int of_da850_pll1_init(struct device *dev, void __iomem *base)
|
||||
int of_da850_pll1_init(struct device *dev, void __iomem *base, struct regmap *cfgchip)
|
||||
{
|
||||
return of_davinci_pll_init(dev, &da850_pll1_info,
|
||||
return of_davinci_pll_init(dev, dev->of_node, &da850_pll1_info,
|
||||
&da850_pll1_obsclk_info,
|
||||
da850_pll1_sysclk_info, 3, base);
|
||||
da850_pll1_sysclk_info, 3, base, cfgchip);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk/davinci.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
@ -22,16 +23,16 @@ static const struct davinci_pll_clk_info dm355_pll1_info = {
|
||||
PLL_POSTDIV_ALWAYS_ENABLED | PLL_POSTDIV_FIXED_DIV,
|
||||
};
|
||||
|
||||
SYSCLK(1, pll1_sysclk1, pll1, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(2, pll1_sysclk2, pll1, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(3, pll1_sysclk3, pll1, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(4, pll1_sysclk4, pll1, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(1, pll1_sysclk1, pll1_pllen, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(2, pll1_sysclk2, pll1_pllen, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(3, pll1_sysclk3, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(4, pll1_sysclk4, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED);
|
||||
|
||||
int dm355_pll1_init(struct device *dev, void __iomem *base)
|
||||
int dm355_pll1_init(struct device *dev, void __iomem *base, struct regmap *cfgchip)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
davinci_pll_clk_register(dev, &dm355_pll1_info, "ref_clk", base);
|
||||
davinci_pll_clk_register(dev, &dm355_pll1_info, "ref_clk", base, cfgchip);
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk1, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk1", "dm355-psc");
|
||||
@ -62,17 +63,14 @@ static const struct davinci_pll_clk_info dm355_pll2_info = {
|
||||
PLL_POSTDIV_ALWAYS_ENABLED | PLL_POSTDIV_FIXED_DIV,
|
||||
};
|
||||
|
||||
SYSCLK(1, pll2_sysclk1, pll2, 5, SYSCLK_FIXED_DIV);
|
||||
SYSCLK(2, pll2_sysclk2, pll2, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
|
||||
SYSCLK(1, pll2_sysclk1, pll2_pllen, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
|
||||
|
||||
int dm355_pll2_init(struct device *dev, void __iomem *base)
|
||||
int dm355_pll2_init(struct device *dev, void __iomem *base, struct regmap *cfgchip)
|
||||
{
|
||||
davinci_pll_clk_register(dev, &dm355_pll2_info, "oscin", base);
|
||||
davinci_pll_clk_register(dev, &dm355_pll2_info, "oscin", base, cfgchip);
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll2_sysclk1, base);
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll2_sysclk2, base);
|
||||
|
||||
davinci_pll_sysclkbp_clk_register(dev, "pll2_sysclkbp", base);
|
||||
|
||||
return 0;
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk/davinci.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
@ -56,11 +57,11 @@ static const struct davinci_pll_obsclk_info dm365_pll1_obsclk_info = {
|
||||
.ocsrc_mask = BIT(4),
|
||||
};
|
||||
|
||||
int dm365_pll1_init(struct device *dev, void __iomem *base)
|
||||
int dm365_pll1_init(struct device *dev, void __iomem *base, struct regmap *cfgchip)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
davinci_pll_clk_register(dev, &dm365_pll1_info, "ref_clk", base);
|
||||
davinci_pll_clk_register(dev, &dm365_pll1_info, "ref_clk", base, cfgchip);
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk1, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk1", "dm365-psc");
|
||||
@ -119,11 +120,11 @@ static const struct davinci_pll_obsclk_info dm365_pll2_obsclk_info = {
|
||||
.ocsrc_mask = BIT(4),
|
||||
};
|
||||
|
||||
int dm365_pll2_init(struct device *dev, void __iomem *base)
|
||||
int dm365_pll2_init(struct device *dev, void __iomem *base, struct regmap *cfgchip)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
davinci_pll_clk_register(dev, &dm365_pll2_info, "oscin", base);
|
||||
davinci_pll_clk_register(dev, &dm365_pll2_info, "oscin", base, cfgchip);
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll2_sysclk1, base);
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk/davinci.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
@ -27,11 +28,11 @@ SYSCLK(2, pll1_sysclk2, pll1_pllen, 4, SYSCLK_FIXED_DIV);
|
||||
SYSCLK(3, pll1_sysclk3, pll1_pllen, 4, SYSCLK_FIXED_DIV);
|
||||
SYSCLK(5, pll1_sysclk5, pll1_pllen, 4, SYSCLK_FIXED_DIV);
|
||||
|
||||
int dm644x_pll1_init(struct device *dev, void __iomem *base)
|
||||
int dm644x_pll1_init(struct device *dev, void __iomem *base, struct regmap *cfgchip)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
davinci_pll_clk_register(dev, &dm644x_pll1_info, "ref_clk", base);
|
||||
davinci_pll_clk_register(dev, &dm644x_pll1_info, "ref_clk", base, cfgchip);
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk1, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk1", "dm644x-psc");
|
||||
@ -66,9 +67,9 @@ static const struct davinci_pll_clk_info dm644x_pll2_info = {
|
||||
SYSCLK(1, pll2_sysclk1, pll2_pllen, 4, 0);
|
||||
SYSCLK(2, pll2_sysclk2, pll2_pllen, 4, 0);
|
||||
|
||||
int dm644x_pll2_init(struct device *dev, void __iomem *base)
|
||||
int dm644x_pll2_init(struct device *dev, void __iomem *base, struct regmap *cfgchip)
|
||||
{
|
||||
davinci_pll_clk_register(dev, &dm644x_pll2_info, "oscin", base);
|
||||
davinci_pll_clk_register(dev, &dm644x_pll2_info, "oscin", base, cfgchip);
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll2_sysclk1, base);
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk/davinci.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
@ -29,11 +30,11 @@ SYSCLK(6, pll1_sysclk6, pll1_pllen, 4, 0);
|
||||
SYSCLK(8, pll1_sysclk8, pll1_pllen, 4, 0);
|
||||
SYSCLK(9, pll1_sysclk9, pll1_pllen, 4, 0);
|
||||
|
||||
int dm646x_pll1_init(struct device *dev, void __iomem *base)
|
||||
int dm646x_pll1_init(struct device *dev, void __iomem *base, struct regmap *cfgchip)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
davinci_pll_clk_register(dev, &dm646x_pll1_info, "ref_clk", base);
|
||||
davinci_pll_clk_register(dev, &dm646x_pll1_info, "ref_clk", base, cfgchip);
|
||||
|
||||
clk = davinci_pll_sysclk_register(dev, &pll1_sysclk1, base);
|
||||
clk_register_clkdev(clk, "pll1_sysclk1", "dm646x-psc");
|
||||
@ -72,11 +73,11 @@ static const struct davinci_pll_clk_info dm646x_pll2_info = {
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
SYSCLK(1, pll2_sysclk1, pll2_pllen, 4, 0);
|
||||
SYSCLK(1, pll2_sysclk1, pll2_pllen, 4, SYSCLK_ALWAYS_ENABLED);
|
||||
|
||||
int dm646x_pll2_init(struct device *dev, void __iomem *base)
|
||||
int dm646x_pll2_init(struct device *dev, void __iomem *base, struct regmap *cfgchip)
|
||||
{
|
||||
davinci_pll_clk_register(dev, &dm646x_pll2_info, "oscin", base);
|
||||
davinci_pll_clk_register(dev, &dm646x_pll2_info, "oscin", base, cfgchip);
|
||||
|
||||
davinci_pll_sysclk_register(dev, &pll2_sysclk1, base);
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk/davinci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
@ -190,7 +191,7 @@ static int davinci_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static int davinci_pll_debug_init(struct clk_hw *hw, struct dentry *dentry);
|
||||
static void davinci_pll_debug_init(struct clk_hw *hw, struct dentry *dentry);
|
||||
#else
|
||||
#define davinci_pll_debug_init NULL
|
||||
#endif
|
||||
@ -223,6 +224,7 @@ static const struct clk_ops dm365_pll_ops = {
|
||||
|
||||
/**
|
||||
* davinci_pll_div_register - common *DIV clock implementation
|
||||
* @dev: The PLL platform device or NULL
|
||||
* @name: the clock name
|
||||
* @parent_name: the parent clock name
|
||||
* @reg: the *DIV register
|
||||
@ -240,17 +242,21 @@ static struct clk *davinci_pll_div_register(struct device *dev,
|
||||
const struct clk_ops *divider_ops = &clk_divider_ops;
|
||||
struct clk_gate *gate;
|
||||
struct clk_divider *divider;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
|
||||
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
|
||||
if (!gate)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
gate->reg = reg;
|
||||
gate->bit_idx = DIV_ENABLE_SHIFT;
|
||||
|
||||
divider = devm_kzalloc(dev, sizeof(*divider), GFP_KERNEL);
|
||||
if (!divider)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
divider = kzalloc(sizeof(*divider), GFP_KERNEL);
|
||||
if (!divider) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free_gate;
|
||||
}
|
||||
|
||||
divider->reg = reg;
|
||||
divider->shift = DIV_RATIO_SHIFT;
|
||||
@ -261,9 +267,22 @@ static struct clk *davinci_pll_div_register(struct device *dev,
|
||||
divider_ops = &clk_divider_ro_ops;
|
||||
}
|
||||
|
||||
return clk_register_composite(dev, name, parent_names, num_parents,
|
||||
NULL, NULL, ÷r->hw, divider_ops,
|
||||
&gate->hw, &clk_gate_ops, flags);
|
||||
clk = clk_register_composite(dev, name, parent_names, num_parents,
|
||||
NULL, NULL, ÷r->hw, divider_ops,
|
||||
&gate->hw, &clk_gate_ops, flags);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
goto err_free_divider;
|
||||
}
|
||||
|
||||
return clk;
|
||||
|
||||
err_free_divider:
|
||||
kfree(divider);
|
||||
err_free_gate:
|
||||
kfree(gate);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
struct davinci_pllen_clk {
|
||||
@ -321,36 +340,17 @@ static int davinci_pllen_rate_change(struct notifier_block *nb,
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct davinci_pll_platform_data *davinci_pll_get_pdata(struct device *dev)
|
||||
{
|
||||
struct davinci_pll_platform_data *pdata = dev_get_platdata(dev);
|
||||
|
||||
/*
|
||||
* Platform data is optional, so allocate a new struct if one was not
|
||||
* provided. For device tree, this will always be the case.
|
||||
*/
|
||||
if (!pdata)
|
||||
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return NULL;
|
||||
|
||||
/* for device tree, we need to fill in the struct */
|
||||
if (dev->of_node)
|
||||
pdata->cfgchip =
|
||||
syscon_regmap_lookup_by_compatible("ti,da830-cfgchip");
|
||||
|
||||
return pdata;
|
||||
}
|
||||
|
||||
static struct notifier_block davinci_pllen_notifier = {
|
||||
.notifier_call = davinci_pllen_rate_change,
|
||||
};
|
||||
|
||||
/**
|
||||
* davinci_pll_clk_register - Register a PLL clock
|
||||
* @dev: The PLL platform device or NULL
|
||||
* @info: The device-specific clock info
|
||||
* @parent_name: The parent clock name
|
||||
* @base: The PLL's memory region
|
||||
* @cfgchip: CFGCHIP syscon regmap for info->unlock_reg or NULL
|
||||
*
|
||||
* This creates a series of clocks that represent the PLL.
|
||||
*
|
||||
@ -366,9 +366,9 @@ static struct notifier_block davinci_pllen_notifier = {
|
||||
struct clk *davinci_pll_clk_register(struct device *dev,
|
||||
const struct davinci_pll_clk_info *info,
|
||||
const char *parent_name,
|
||||
void __iomem *base)
|
||||
void __iomem *base,
|
||||
struct regmap *cfgchip)
|
||||
{
|
||||
struct davinci_pll_platform_data *pdata;
|
||||
char prediv_name[MAX_NAME_SIZE];
|
||||
char pllout_name[MAX_NAME_SIZE];
|
||||
char postdiv_name[MAX_NAME_SIZE];
|
||||
@ -376,11 +376,12 @@ struct clk *davinci_pll_clk_register(struct device *dev,
|
||||
struct clk_init_data init;
|
||||
struct davinci_pll_clk *pllout;
|
||||
struct davinci_pllen_clk *pllen;
|
||||
struct clk *pllout_clk, *clk;
|
||||
|
||||
pdata = davinci_pll_get_pdata(dev);
|
||||
if (!pdata)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
struct clk *oscin_clk = NULL;
|
||||
struct clk *prediv_clk = NULL;
|
||||
struct clk *pllout_clk;
|
||||
struct clk *postdiv_clk = NULL;
|
||||
struct clk *pllen_clk;
|
||||
int ret;
|
||||
|
||||
if (info->flags & PLL_HAS_CLKMODE) {
|
||||
/*
|
||||
@ -392,10 +393,10 @@ struct clk *davinci_pll_clk_register(struct device *dev,
|
||||
* a number of different things. In this driver we use it to
|
||||
* mean the signal after the PLLCTL[CLKMODE] switch.
|
||||
*/
|
||||
clk = clk_register_fixed_factor(dev, OSCIN_CLK_NAME,
|
||||
parent_name, 0, 1, 1);
|
||||
if (IS_ERR(clk))
|
||||
return clk;
|
||||
oscin_clk = clk_register_fixed_factor(dev, OSCIN_CLK_NAME,
|
||||
parent_name, 0, 1, 1);
|
||||
if (IS_ERR(oscin_clk))
|
||||
return oscin_clk;
|
||||
|
||||
parent_name = OSCIN_CLK_NAME;
|
||||
}
|
||||
@ -411,30 +412,34 @@ struct clk *davinci_pll_clk_register(struct device *dev,
|
||||
|
||||
/* Some? DM355 chips don't correctly report the PREDIV value */
|
||||
if (info->flags & PLL_PREDIV_FIXED8)
|
||||
clk = clk_register_fixed_factor(dev, prediv_name,
|
||||
parent_name, flags, 1, 8);
|
||||
prediv_clk = clk_register_fixed_factor(dev, prediv_name,
|
||||
parent_name, flags, 1, 8);
|
||||
else
|
||||
clk = davinci_pll_div_register(dev, prediv_name,
|
||||
prediv_clk = davinci_pll_div_register(dev, prediv_name,
|
||||
parent_name, base + PREDIV, fixed, flags);
|
||||
if (IS_ERR(clk))
|
||||
return clk;
|
||||
if (IS_ERR(prediv_clk)) {
|
||||
ret = PTR_ERR(prediv_clk);
|
||||
goto err_unregister_oscin;
|
||||
}
|
||||
|
||||
parent_name = prediv_name;
|
||||
}
|
||||
|
||||
/* Unlock writing to PLL registers */
|
||||
if (info->unlock_reg) {
|
||||
if (IS_ERR_OR_NULL(pdata->cfgchip))
|
||||
if (IS_ERR_OR_NULL(cfgchip))
|
||||
dev_warn(dev, "Failed to get CFGCHIP (%ld)\n",
|
||||
PTR_ERR(pdata->cfgchip));
|
||||
PTR_ERR(cfgchip));
|
||||
else
|
||||
regmap_write_bits(pdata->cfgchip, info->unlock_reg,
|
||||
regmap_write_bits(cfgchip, info->unlock_reg,
|
||||
info->unlock_mask, 0);
|
||||
}
|
||||
|
||||
pllout = devm_kzalloc(dev, sizeof(*pllout), GFP_KERNEL);
|
||||
if (!pllout)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
pllout = kzalloc(sizeof(*pllout), GFP_KERNEL);
|
||||
if (!pllout) {
|
||||
ret = -ENOMEM;
|
||||
goto err_unregister_prediv;
|
||||
}
|
||||
|
||||
snprintf(pllout_name, MAX_NAME_SIZE, "%s_pllout", info->name);
|
||||
|
||||
@ -456,9 +461,11 @@ struct clk *davinci_pll_clk_register(struct device *dev,
|
||||
pllout->pllm_min = info->pllm_min;
|
||||
pllout->pllm_max = info->pllm_max;
|
||||
|
||||
pllout_clk = devm_clk_register(dev, &pllout->hw);
|
||||
if (IS_ERR(pllout_clk))
|
||||
return pllout_clk;
|
||||
pllout_clk = clk_register(dev, &pllout->hw);
|
||||
if (IS_ERR(pllout_clk)) {
|
||||
ret = PTR_ERR(pllout_clk);
|
||||
goto err_free_pllout;
|
||||
}
|
||||
|
||||
clk_hw_set_rate_range(&pllout->hw, info->pllout_min_rate,
|
||||
info->pllout_max_rate);
|
||||
@ -474,17 +481,21 @@ struct clk *davinci_pll_clk_register(struct device *dev,
|
||||
if (info->flags & PLL_POSTDIV_ALWAYS_ENABLED)
|
||||
flags |= CLK_IS_CRITICAL;
|
||||
|
||||
clk = davinci_pll_div_register(dev, postdiv_name, parent_name,
|
||||
base + POSTDIV, fixed, flags);
|
||||
if (IS_ERR(clk))
|
||||
return clk;
|
||||
postdiv_clk = davinci_pll_div_register(dev, postdiv_name,
|
||||
parent_name, base + POSTDIV, fixed, flags);
|
||||
if (IS_ERR(postdiv_clk)) {
|
||||
ret = PTR_ERR(postdiv_clk);
|
||||
goto err_unregister_pllout;
|
||||
}
|
||||
|
||||
parent_name = postdiv_name;
|
||||
}
|
||||
|
||||
pllen = devm_kzalloc(dev, sizeof(*pllout), GFP_KERNEL);
|
||||
if (!pllen)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
pllen = kzalloc(sizeof(*pllout), GFP_KERNEL);
|
||||
if (!pllen) {
|
||||
ret = -ENOMEM;
|
||||
goto err_unregister_postdiv;
|
||||
}
|
||||
|
||||
snprintf(pllen_name, MAX_NAME_SIZE, "%s_pllen", info->name);
|
||||
|
||||
@ -497,17 +508,35 @@ struct clk *davinci_pll_clk_register(struct device *dev,
|
||||
pllen->hw.init = &init;
|
||||
pllen->base = base;
|
||||
|
||||
clk = devm_clk_register(dev, &pllen->hw);
|
||||
if (IS_ERR(clk))
|
||||
return clk;
|
||||
pllen_clk = clk_register(dev, &pllen->hw);
|
||||
if (IS_ERR(pllen_clk)) {
|
||||
ret = PTR_ERR(pllen_clk);
|
||||
goto err_free_pllen;
|
||||
}
|
||||
|
||||
clk_notifier_register(clk, &davinci_pllen_notifier);
|
||||
clk_notifier_register(pllen_clk, &davinci_pllen_notifier);
|
||||
|
||||
return pllout_clk;
|
||||
|
||||
err_free_pllen:
|
||||
kfree(pllen);
|
||||
err_unregister_postdiv:
|
||||
clk_unregister(postdiv_clk);
|
||||
err_unregister_pllout:
|
||||
clk_unregister(pllout_clk);
|
||||
err_free_pllout:
|
||||
kfree(pllout);
|
||||
err_unregister_prediv:
|
||||
clk_unregister(prediv_clk);
|
||||
err_unregister_oscin:
|
||||
clk_unregister(oscin_clk);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* davinci_pll_auxclk_register - Register bypass clock (AUXCLK)
|
||||
* @dev: The PLL platform device or NULL
|
||||
* @name: The clock name
|
||||
* @base: The PLL memory region
|
||||
*/
|
||||
@ -521,6 +550,7 @@ struct clk *davinci_pll_auxclk_register(struct device *dev,
|
||||
|
||||
/**
|
||||
* davinci_pll_sysclkbp_clk_register - Register bypass divider clock (SYSCLKBP)
|
||||
* @dev: The PLL platform device or NULL
|
||||
* @name: The clock name
|
||||
* @base: The PLL memory region
|
||||
*/
|
||||
@ -535,6 +565,7 @@ struct clk *davinci_pll_sysclkbp_clk_register(struct device *dev,
|
||||
|
||||
/**
|
||||
* davinci_pll_obsclk_register - Register oscillator divider clock (OBSCLK)
|
||||
* @dev: The PLL platform device or NULL
|
||||
* @info: The clock info
|
||||
* @base: The PLL memory region
|
||||
*/
|
||||
@ -546,9 +577,11 @@ davinci_pll_obsclk_register(struct device *dev,
|
||||
struct clk_mux *mux;
|
||||
struct clk_gate *gate;
|
||||
struct clk_divider *divider;
|
||||
struct clk *clk;
|
||||
u32 oscdiv;
|
||||
int ret;
|
||||
|
||||
mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
|
||||
mux = kzalloc(sizeof(*mux), GFP_KERNEL);
|
||||
if (!mux)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
@ -556,16 +589,20 @@ davinci_pll_obsclk_register(struct device *dev,
|
||||
mux->table = info->table;
|
||||
mux->mask = info->ocsrc_mask;
|
||||
|
||||
gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
|
||||
if (!gate)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
|
||||
if (!gate) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free_mux;
|
||||
}
|
||||
|
||||
gate->reg = base + CKEN;
|
||||
gate->bit_idx = CKEN_OBSCLK_SHIFT;
|
||||
|
||||
divider = devm_kzalloc(dev, sizeof(*divider), GFP_KERNEL);
|
||||
if (!divider)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
divider = kzalloc(sizeof(*divider), GFP_KERNEL);
|
||||
if (!divider) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free_gate;
|
||||
}
|
||||
|
||||
divider->reg = base + OSCDIV;
|
||||
divider->shift = DIV_RATIO_SHIFT;
|
||||
@ -576,11 +613,27 @@ davinci_pll_obsclk_register(struct device *dev,
|
||||
oscdiv |= BIT(DIV_ENABLE_SHIFT);
|
||||
writel(oscdiv, base + OSCDIV);
|
||||
|
||||
return clk_register_composite(dev, info->name, info->parent_names,
|
||||
info->num_parents,
|
||||
&mux->hw, &clk_mux_ops,
|
||||
÷r->hw, &clk_divider_ops,
|
||||
&gate->hw, &clk_gate_ops, 0);
|
||||
clk = clk_register_composite(dev, info->name, info->parent_names,
|
||||
info->num_parents,
|
||||
&mux->hw, &clk_mux_ops,
|
||||
÷r->hw, &clk_divider_ops,
|
||||
&gate->hw, &clk_gate_ops, 0);
|
||||
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
goto err_free_divider;
|
||||
}
|
||||
|
||||
return clk;
|
||||
|
||||
err_free_divider:
|
||||
kfree(divider);
|
||||
err_free_gate:
|
||||
kfree(gate);
|
||||
err_free_mux:
|
||||
kfree(mux);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/* The PLL SYSCLKn clocks have a mechanism for synchronizing rate changes. */
|
||||
@ -616,6 +669,7 @@ static struct notifier_block davinci_pll_sysclk_notifier = {
|
||||
|
||||
/**
|
||||
* davinci_pll_sysclk_register - Register divider clocks (SYSCLKn)
|
||||
* @dev: The PLL platform device or NULL
|
||||
* @info: The clock info
|
||||
* @base: The PLL memory region
|
||||
*/
|
||||
@ -630,6 +684,7 @@ davinci_pll_sysclk_register(struct device *dev,
|
||||
struct clk *clk;
|
||||
u32 reg;
|
||||
u32 flags = 0;
|
||||
int ret;
|
||||
|
||||
/* PLLDIVn registers are not entirely consecutive */
|
||||
if (info->id < 4)
|
||||
@ -637,16 +692,18 @@ davinci_pll_sysclk_register(struct device *dev,
|
||||
else
|
||||
reg = PLLDIV4 + 4 * (info->id - 4);
|
||||
|
||||
gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
|
||||
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
|
||||
if (!gate)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
gate->reg = base + reg;
|
||||
gate->bit_idx = DIV_ENABLE_SHIFT;
|
||||
|
||||
divider = devm_kzalloc(dev, sizeof(*divider), GFP_KERNEL);
|
||||
if (!divider)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
divider = kzalloc(sizeof(*divider), GFP_KERNEL);
|
||||
if (!divider) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free_gate;
|
||||
}
|
||||
|
||||
divider->reg = base + reg;
|
||||
divider->shift = DIV_RATIO_SHIFT;
|
||||
@ -668,22 +725,31 @@ davinci_pll_sysclk_register(struct device *dev,
|
||||
clk = clk_register_composite(dev, info->name, &info->parent_name, 1,
|
||||
NULL, NULL, ÷r->hw, divider_ops,
|
||||
&gate->hw, &clk_gate_ops, flags);
|
||||
if (IS_ERR(clk))
|
||||
return clk;
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
goto err_free_divider;
|
||||
}
|
||||
|
||||
clk_notifier_register(clk, &davinci_pll_sysclk_notifier);
|
||||
|
||||
return clk;
|
||||
|
||||
err_free_divider:
|
||||
kfree(divider);
|
||||
err_free_gate:
|
||||
kfree(gate);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
int of_davinci_pll_init(struct device *dev,
|
||||
int of_davinci_pll_init(struct device *dev, struct device_node *node,
|
||||
const struct davinci_pll_clk_info *info,
|
||||
const struct davinci_pll_obsclk_info *obsclk_info,
|
||||
const struct davinci_pll_sysclk_info **div_info,
|
||||
u8 max_sysclk_id,
|
||||
void __iomem *base)
|
||||
void __iomem *base,
|
||||
struct regmap *cfgchip)
|
||||
{
|
||||
struct device_node *node = dev->of_node;
|
||||
struct device_node *child;
|
||||
const char *parent_name;
|
||||
struct clk *clk;
|
||||
@ -693,7 +759,7 @@ int of_davinci_pll_init(struct device *dev,
|
||||
else
|
||||
parent_name = OSCIN_CLK_NAME;
|
||||
|
||||
clk = davinci_pll_clk_register(dev, info, parent_name, base);
|
||||
clk = davinci_pll_clk_register(dev, info, parent_name, base, cfgchip);
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(dev, "failed to register %s\n", info->name);
|
||||
return PTR_ERR(clk);
|
||||
@ -711,13 +777,15 @@ int of_davinci_pll_init(struct device *dev,
|
||||
int n_clks = max_sysclk_id + 1;
|
||||
int i;
|
||||
|
||||
clk_data = devm_kzalloc(dev, sizeof(*clk_data), GFP_KERNEL);
|
||||
clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
clks = devm_kmalloc_array(dev, n_clks, sizeof(*clks), GFP_KERNEL);
|
||||
if (!clks)
|
||||
clks = kmalloc_array(n_clks, sizeof(*clks), GFP_KERNEL);
|
||||
if (!clks) {
|
||||
kfree(clk_data);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
clk_data->clks = clks;
|
||||
clk_data->clk_num = n_clks;
|
||||
@ -770,32 +838,73 @@ int of_davinci_pll_init(struct device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct davinci_pll_platform_data *davinci_pll_get_pdata(struct device *dev)
|
||||
{
|
||||
struct davinci_pll_platform_data *pdata = dev_get_platdata(dev);
|
||||
|
||||
/*
|
||||
* Platform data is optional, so allocate a new struct if one was not
|
||||
* provided. For device tree, this will always be the case.
|
||||
*/
|
||||
if (!pdata)
|
||||
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return NULL;
|
||||
|
||||
/* for device tree, we need to fill in the struct */
|
||||
if (dev->of_node)
|
||||
pdata->cfgchip =
|
||||
syscon_regmap_lookup_by_compatible("ti,da830-cfgchip");
|
||||
|
||||
return pdata;
|
||||
}
|
||||
|
||||
/* needed in early boot for clocksource/clockevent */
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DA850
|
||||
CLK_OF_DECLARE(da850_pll0, "ti,da850-pll0", of_da850_pll0_init);
|
||||
#endif
|
||||
|
||||
static const struct of_device_id davinci_pll_of_match[] = {
|
||||
{ .compatible = "ti,da850-pll0", .data = of_da850_pll0_init },
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DA850
|
||||
{ .compatible = "ti,da850-pll1", .data = of_da850_pll1_init },
|
||||
#endif
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct platform_device_id davinci_pll_id_table[] = {
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DA830
|
||||
{ .name = "da830-pll", .driver_data = (kernel_ulong_t)da830_pll_init },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DA850
|
||||
{ .name = "da850-pll0", .driver_data = (kernel_ulong_t)da850_pll0_init },
|
||||
{ .name = "da850-pll1", .driver_data = (kernel_ulong_t)da850_pll1_init },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DM355
|
||||
{ .name = "dm355-pll1", .driver_data = (kernel_ulong_t)dm355_pll1_init },
|
||||
{ .name = "dm355-pll2", .driver_data = (kernel_ulong_t)dm355_pll2_init },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DM365
|
||||
{ .name = "dm365-pll1", .driver_data = (kernel_ulong_t)dm365_pll1_init },
|
||||
{ .name = "dm365-pll2", .driver_data = (kernel_ulong_t)dm365_pll2_init },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DM644x
|
||||
{ .name = "dm644x-pll1", .driver_data = (kernel_ulong_t)dm644x_pll1_init },
|
||||
{ .name = "dm644x-pll2", .driver_data = (kernel_ulong_t)dm644x_pll2_init },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DM646x
|
||||
{ .name = "dm646x-pll1", .driver_data = (kernel_ulong_t)dm646x_pll1_init },
|
||||
{ .name = "dm646x-pll2", .driver_data = (kernel_ulong_t)dm646x_pll2_init },
|
||||
#endif
|
||||
{ }
|
||||
};
|
||||
|
||||
typedef int (*davinci_pll_init)(struct device *dev, void __iomem *base);
|
||||
typedef int (*davinci_pll_init)(struct device *dev, void __iomem *base,
|
||||
struct regmap *cfgchip);
|
||||
|
||||
static int davinci_pll_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct davinci_pll_platform_data *pdata;
|
||||
const struct of_device_id *of_id;
|
||||
davinci_pll_init pll_init = NULL;
|
||||
struct resource *res;
|
||||
@ -812,12 +921,18 @@ static int davinci_pll_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pdata = davinci_pll_get_pdata(dev);
|
||||
if (!pdata) {
|
||||
dev_err(dev, "missing platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
return pll_init(dev, base);
|
||||
return pll_init(dev, base, pdata->cfgchip);
|
||||
}
|
||||
|
||||
static struct platform_driver davinci_pll_driver = {
|
||||
@ -874,26 +989,19 @@ static const struct debugfs_reg32 davinci_pll_regs[] = {
|
||||
DEBUG_REG(PLLDIV9),
|
||||
};
|
||||
|
||||
static int davinci_pll_debug_init(struct clk_hw *hw, struct dentry *dentry)
|
||||
static void davinci_pll_debug_init(struct clk_hw *hw, struct dentry *dentry)
|
||||
{
|
||||
struct davinci_pll_clk *pll = to_davinci_pll_clk(hw);
|
||||
struct debugfs_regset32 *regset;
|
||||
struct dentry *d;
|
||||
|
||||
regset = kzalloc(sizeof(*regset), GFP_KERNEL);
|
||||
if (!regset)
|
||||
return -ENOMEM;
|
||||
return;
|
||||
|
||||
regset->regs = davinci_pll_regs;
|
||||
regset->nregs = ARRAY_SIZE(davinci_pll_regs);
|
||||
regset->base = pll->base;
|
||||
|
||||
d = debugfs_create_regset32("registers", 0400, dentry, regset);
|
||||
if (IS_ERR(d)) {
|
||||
kfree(regset);
|
||||
return PTR_ERR(d);
|
||||
}
|
||||
|
||||
return 0;
|
||||
debugfs_create_regset32("registers", 0400, dentry, regset);
|
||||
}
|
||||
#endif
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define PLL_HAS_CLKMODE BIT(0) /* PLL has PLLCTL[CLKMODE] */
|
||||
@ -94,7 +95,8 @@ struct davinci_pll_obsclk_info {
|
||||
struct clk *davinci_pll_clk_register(struct device *dev,
|
||||
const struct davinci_pll_clk_info *info,
|
||||
const char *parent_name,
|
||||
void __iomem *base);
|
||||
void __iomem *base,
|
||||
struct regmap *cfgchip);
|
||||
struct clk *davinci_pll_auxclk_register(struct device *dev,
|
||||
const char *name,
|
||||
void __iomem *base);
|
||||
@ -110,32 +112,29 @@ davinci_pll_sysclk_register(struct device *dev,
|
||||
const struct davinci_pll_sysclk_info *info,
|
||||
void __iomem *base);
|
||||
|
||||
int of_davinci_pll_init(struct device *dev,
|
||||
int of_davinci_pll_init(struct device *dev, struct device_node *node,
|
||||
const struct davinci_pll_clk_info *info,
|
||||
const struct davinci_pll_obsclk_info *obsclk_info,
|
||||
const struct davinci_pll_sysclk_info **div_info,
|
||||
u8 max_sysclk_id,
|
||||
void __iomem *base);
|
||||
void __iomem *base,
|
||||
struct regmap *cfgchip);
|
||||
|
||||
/* Platform-specific callbacks */
|
||||
|
||||
int da830_pll_init(struct device *dev, void __iomem *base);
|
||||
|
||||
int da850_pll0_init(struct device *dev, void __iomem *base);
|
||||
int da850_pll1_init(struct device *dev, void __iomem *base);
|
||||
int of_da850_pll0_init(struct device *dev, void __iomem *base);
|
||||
int of_da850_pll1_init(struct device *dev, void __iomem *base);
|
||||
|
||||
int dm355_pll1_init(struct device *dev, void __iomem *base);
|
||||
int dm355_pll2_init(struct device *dev, void __iomem *base);
|
||||
|
||||
int dm365_pll1_init(struct device *dev, void __iomem *base);
|
||||
int dm365_pll2_init(struct device *dev, void __iomem *base);
|
||||
|
||||
int dm644x_pll1_init(struct device *dev, void __iomem *base);
|
||||
int dm644x_pll2_init(struct device *dev, void __iomem *base);
|
||||
|
||||
int dm646x_pll1_init(struct device *dev, void __iomem *base);
|
||||
int dm646x_pll2_init(struct device *dev, void __iomem *base);
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DA850
|
||||
int da850_pll1_init(struct device *dev, void __iomem *base, struct regmap *cfgchip);
|
||||
void of_da850_pll0_init(struct device_node *node);
|
||||
int of_da850_pll1_init(struct device *dev, void __iomem *base, struct regmap *cfgchip);
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DM355
|
||||
int dm355_pll2_init(struct device *dev, void __iomem *base, struct regmap *cfgchip);
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DM644x
|
||||
int dm644x_pll2_init(struct device *dev, void __iomem *base, struct regmap *cfgchip);
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DM646x
|
||||
int dm646x_pll2_init(struct device *dev, void __iomem *base, struct regmap *cfgchip);
|
||||
#endif
|
||||
|
||||
#endif /* __CLK_DAVINCI_PLL_H___ */
|
||||
|
@ -55,7 +55,8 @@ const struct davinci_psc_init_data da830_psc0_init_data = {
|
||||
.psc_init = &da830_psc0_init,
|
||||
};
|
||||
|
||||
LPSC_CLKDEV2(usb0_clkdev, NULL, "musb-da8xx",
|
||||
LPSC_CLKDEV3(usb0_clkdev, "fck", "da830-usb-phy-clks",
|
||||
NULL, "musb-da8xx",
|
||||
NULL, "cppi41-dmaengine");
|
||||
LPSC_CLKDEV1(usb1_clkdev, NULL, "ohci-da8xx");
|
||||
/* REVISIT: gpio-davinci.c should be modified to drop con_id */
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk/davinci.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/init.h>
|
||||
@ -41,14 +42,14 @@ static const struct davinci_lpsc_clk_info dm355_psc_info[] = {
|
||||
LPSC(5, 0, timer3, pll1_auxclk, NULL, 0),
|
||||
LPSC(6, 0, spi1, pll1_sysclk2, spi1_clkdev, 0),
|
||||
LPSC(7, 0, mmcsd1, pll1_sysclk2, mmcsd1_clkdev, 0),
|
||||
LPSC(8, 0, asp1, pll1_sysclk2, NULL, 0),
|
||||
LPSC(8, 0, asp1, pll1_sysclk2, mcbsp1_clkdev, 0),
|
||||
LPSC(9, 0, usb, pll1_sysclk2, usb_clkdev, 0),
|
||||
LPSC(10, 0, pwm3, pll1_auxclk, NULL, 0),
|
||||
LPSC(11, 0, spi2, pll1_sysclk2, spi2_clkdev, 0),
|
||||
LPSC(12, 0, rto, pll1_auxclk, NULL, 0),
|
||||
LPSC(14, 0, aemif, pll1_sysclk2, aemif_clkdev, 0),
|
||||
LPSC(15, 0, mmcsd0, pll1_sysclk2, mmcsd0_clkdev, 0),
|
||||
LPSC(17, 0, asp0, pll1_sysclk2, NULL, 0),
|
||||
LPSC(17, 0, asp0, pll1_sysclk2, mcbsp0_clkdev, 0),
|
||||
LPSC(18, 0, i2c, pll1_auxclk, i2c_clkdev, 0),
|
||||
LPSC(19, 0, uart0, pll1_auxclk, uart0_clkdev, 0),
|
||||
LPSC(20, 0, uart1, pll1_auxclk, uart1_clkdev, 0),
|
||||
@ -68,7 +69,7 @@ static const struct davinci_lpsc_clk_info dm355_psc_info[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
static int dm355_psc_init(struct device *dev, void __iomem *base)
|
||||
int dm355_psc_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
return davinci_psc_register_clocks(dev, dm355_psc_info, 42, base);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk/davinci.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/init.h>
|
||||
@ -65,15 +66,28 @@ static const struct davinci_lpsc_clk_info dm365_psc_info[] = {
|
||||
LPSC(31, 0, arm, pll2_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
|
||||
LPSC(38, 0, spi3, pll1_sysclk4, spi3_clkdev, 0),
|
||||
LPSC(39, 0, spi4, pll1_auxclk, spi4_clkdev, 0),
|
||||
LPSC(40, 0, emac, pll2_sysclk4, emac_clkdev, 0),
|
||||
LPSC(44, 1, voice_codec, pll1_sysclk3, voice_codec_clkdev, 0),
|
||||
LPSC(46, 1, vpss_dac, pll1_sysclk3, vpss_dac_clkdev, 0),
|
||||
LPSC(40, 0, emac, pll1_sysclk4, emac_clkdev, 0),
|
||||
/*
|
||||
* The TRM (ARM Subsystem User's Guide) shows two clocks input into
|
||||
* voice codec module (PLL2 SYSCLK4 with a DIV2 and PLL1 SYSCLK4). Its
|
||||
* not fully clear from documentation which clock should be considered
|
||||
* as parent for PSC. The clock chosen here is to maintain
|
||||
* compatibility with existing code in arch/arm/mach-davinci/dm365.c
|
||||
*/
|
||||
LPSC(44, 0, voice_codec, pll2_sysclk4, voice_codec_clkdev, 0),
|
||||
/*
|
||||
* Its not fully clear from TRM (ARM Subsystem User's Guide) as to what
|
||||
* the parent of VPSS DAC LPSC should actually be. PLL1 SYSCLK3 feeds
|
||||
* into HDVICP and MJCP. The clock chosen here is to remain compatible
|
||||
* with code existing in arch/arm/mach-davinci/dm365.c
|
||||
*/
|
||||
LPSC(46, 0, vpss_dac, pll1_sysclk3, vpss_dac_clkdev, 0),
|
||||
LPSC(47, 0, vpss_master, pll1_sysclk5, vpss_master_clkdev, 0),
|
||||
LPSC(50, 0, mjcp, pll1_sysclk3, NULL, 0),
|
||||
{ }
|
||||
};
|
||||
|
||||
static int dm365_psc_init(struct device *dev, void __iomem *base)
|
||||
int dm365_psc_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
return davinci_psc_register_clocks(dev, dm365_psc_info, 52, base);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk/davinci.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/init.h>
|
||||
@ -63,7 +64,7 @@ static const struct davinci_lpsc_clk_info dm644x_psc_info[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
static int dm644x_psc_init(struct device *dev, void __iomem *base)
|
||||
int dm644x_psc_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
return davinci_psc_register_clocks(dev, dm644x_psc_info, 41, base);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk/davinci.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/init.h>
|
||||
@ -58,7 +59,7 @@ static const struct davinci_lpsc_clk_info dm646x_psc_info[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
static int dm646x_psc_init(struct device *dev, void __iomem *base)
|
||||
int dm646x_psc_init(struct device *dev, void __iomem *base)
|
||||
{
|
||||
return davinci_psc_register_clocks(dev, dm646x_psc_info, 46, base);
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk/davinci.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of_address.h>
|
||||
@ -63,7 +64,7 @@ struct davinci_psc_data {
|
||||
|
||||
/**
|
||||
* struct davinci_lpsc_clk - LPSC clock structure
|
||||
* @dev: the device that provides this LPSC
|
||||
* @dev: the device that provides this LPSC or NULL
|
||||
* @hw: clk_hw for the LPSC
|
||||
* @pm_domain: power domain for the LPSC
|
||||
* @genpd_clk: clock reference owned by @pm_domain
|
||||
@ -221,6 +222,7 @@ static void davinci_psc_genpd_detach_dev(struct generic_pm_domain *pm_domain,
|
||||
|
||||
/**
|
||||
* davinci_lpsc_clk_register - register LPSC clock
|
||||
* @dev: the clocks's device or NULL
|
||||
* @name: name of this clock
|
||||
* @parent_name: name of clock's parent
|
||||
* @regmap: PSC MMIO region
|
||||
@ -238,7 +240,7 @@ davinci_lpsc_clk_register(struct device *dev, const char *name,
|
||||
int ret;
|
||||
bool is_on;
|
||||
|
||||
lpsc = devm_kzalloc(dev, sizeof(*lpsc), GFP_KERNEL);
|
||||
lpsc = kzalloc(sizeof(*lpsc), GFP_KERNEL);
|
||||
if (!lpsc)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
@ -261,9 +263,15 @@ davinci_lpsc_clk_register(struct device *dev, const char *name,
|
||||
lpsc->pd = pd;
|
||||
lpsc->flags = flags;
|
||||
|
||||
ret = devm_clk_hw_register(dev, &lpsc->hw);
|
||||
if (ret < 0)
|
||||
ret = clk_hw_register(dev, &lpsc->hw);
|
||||
if (ret < 0) {
|
||||
kfree(lpsc);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/* for now, genpd is only registered when using device-tree */
|
||||
if (!dev || !dev->of_node)
|
||||
return lpsc;
|
||||
|
||||
/* genpd attach needs a way to look up this clock */
|
||||
ret = clk_hw_register_clkdev(&lpsc->hw, name, best_dev_name(dev));
|
||||
@ -378,13 +386,15 @@ __davinci_psc_register_clocks(struct device *dev,
|
||||
struct regmap *regmap;
|
||||
int i, ret;
|
||||
|
||||
psc = devm_kzalloc(dev, sizeof(*psc), GFP_KERNEL);
|
||||
psc = kzalloc(sizeof(*psc), GFP_KERNEL);
|
||||
if (!psc)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
clks = devm_kmalloc_array(dev, num_clks, sizeof(*clks), GFP_KERNEL);
|
||||
if (!clks)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
clks = kmalloc_array(num_clks, sizeof(*clks), GFP_KERNEL);
|
||||
if (!clks) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free_psc;
|
||||
}
|
||||
|
||||
psc->clk_data.clks = clks;
|
||||
psc->clk_data.clk_num = num_clks;
|
||||
@ -396,16 +406,20 @@ __davinci_psc_register_clocks(struct device *dev,
|
||||
for (i = 0; i < num_clks; i++)
|
||||
clks[i] = ERR_PTR(-ENOENT);
|
||||
|
||||
pm_domains = devm_kcalloc(dev, num_clks, sizeof(*pm_domains), GFP_KERNEL);
|
||||
if (!pm_domains)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
pm_domains = kcalloc(num_clks, sizeof(*pm_domains), GFP_KERNEL);
|
||||
if (!pm_domains) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free_clks;
|
||||
}
|
||||
|
||||
psc->pm_data.domains = pm_domains;
|
||||
psc->pm_data.num_domains = num_clks;
|
||||
|
||||
regmap = devm_regmap_init_mmio(dev, base, &davinci_psc_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return ERR_CAST(regmap);
|
||||
regmap = regmap_init_mmio(dev, base, &davinci_psc_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
ret = PTR_ERR(regmap);
|
||||
goto err_free_pm_domains;
|
||||
}
|
||||
|
||||
for (; info->name; info++) {
|
||||
struct davinci_lpsc_clk *lpsc;
|
||||
@ -423,6 +437,13 @@ __davinci_psc_register_clocks(struct device *dev,
|
||||
pm_domains[info->md] = &lpsc->pm_domain;
|
||||
}
|
||||
|
||||
/*
|
||||
* for now, a reset controller is only registered when there is a device
|
||||
* to associate it with.
|
||||
*/
|
||||
if (!dev)
|
||||
return psc;
|
||||
|
||||
psc->rcdev.ops = &davinci_psc_reset_ops;
|
||||
psc->rcdev.owner = THIS_MODULE;
|
||||
psc->rcdev.dev = dev;
|
||||
@ -436,6 +457,15 @@ __davinci_psc_register_clocks(struct device *dev,
|
||||
dev_warn(dev, "Failed to register reset controller (%d)\n", ret);
|
||||
|
||||
return psc;
|
||||
|
||||
err_free_pm_domains:
|
||||
kfree(pm_domains);
|
||||
err_free_clks:
|
||||
kfree(clks);
|
||||
err_free_psc:
|
||||
kfree(psc);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
int davinci_psc_register_clocks(struct device *dev,
|
||||
@ -483,20 +513,34 @@ int of_davinci_psc_clk_init(struct device *dev,
|
||||
}
|
||||
|
||||
static const struct of_device_id davinci_psc_of_match[] = {
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DA850
|
||||
{ .compatible = "ti,da850-psc0", .data = &of_da850_psc0_init_data },
|
||||
{ .compatible = "ti,da850-psc1", .data = &of_da850_psc1_init_data },
|
||||
#endif
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct platform_device_id davinci_psc_id_table[] = {
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DA830
|
||||
{ .name = "da830-psc0", .driver_data = (kernel_ulong_t)&da830_psc0_init_data },
|
||||
{ .name = "da830-psc1", .driver_data = (kernel_ulong_t)&da830_psc1_init_data },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DA850
|
||||
{ .name = "da850-psc0", .driver_data = (kernel_ulong_t)&da850_psc0_init_data },
|
||||
{ .name = "da850-psc1", .driver_data = (kernel_ulong_t)&da850_psc1_init_data },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DM355
|
||||
{ .name = "dm355-psc", .driver_data = (kernel_ulong_t)&dm355_psc_init_data },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DM365
|
||||
{ .name = "dm365-psc", .driver_data = (kernel_ulong_t)&dm365_psc_init_data },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DM644x
|
||||
{ .name = "dm644x-psc", .driver_data = (kernel_ulong_t)&dm644x_psc_init_data },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DM646x
|
||||
{ .name = "dm646x-psc", .driver_data = (kernel_ulong_t)&dm646x_psc_init_data },
|
||||
#endif
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -94,15 +94,27 @@ struct davinci_psc_init_data {
|
||||
int (*psc_init)(struct device *dev, void __iomem *base);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DA830
|
||||
extern const struct davinci_psc_init_data da830_psc0_init_data;
|
||||
extern const struct davinci_psc_init_data da830_psc1_init_data;
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DA850
|
||||
extern const struct davinci_psc_init_data da850_psc0_init_data;
|
||||
extern const struct davinci_psc_init_data da850_psc1_init_data;
|
||||
extern const struct davinci_psc_init_data of_da850_psc0_init_data;
|
||||
extern const struct davinci_psc_init_data of_da850_psc1_init_data;
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DM355
|
||||
extern const struct davinci_psc_init_data dm355_psc_init_data;
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DM356
|
||||
extern const struct davinci_psc_init_data dm365_psc_init_data;
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DM644x
|
||||
extern const struct davinci_psc_init_data dm644x_psc_init_data;
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DM646x
|
||||
extern const struct davinci_psc_init_data dm646x_psc_init_data;
|
||||
#endif
|
||||
|
||||
#endif /* __CLK_DAVINCI_PSC_H__ */
|
||||
|
@ -44,14 +44,17 @@ config RESET_HISI
|
||||
Build reset controller driver for HiSilicon device chipsets.
|
||||
|
||||
config STUB_CLK_HI6220
|
||||
bool "Hi6220 Stub Clock Driver"
|
||||
depends on COMMON_CLK_HI6220 && MAILBOX
|
||||
default ARCH_HISI
|
||||
bool "Hi6220 Stub Clock Driver" if EXPERT
|
||||
depends on (COMMON_CLK_HI6220 || COMPILE_TEST)
|
||||
depends on MAILBOX
|
||||
default COMMON_CLK_HI6220
|
||||
help
|
||||
Build the Hisilicon Hi6220 stub clock driver.
|
||||
|
||||
config STUB_CLK_HI3660
|
||||
bool "Hi3660 Stub Clock Driver"
|
||||
depends on COMMON_CLK_HI3660 && MAILBOX
|
||||
bool "Hi3660 Stub Clock Driver" if EXPERT
|
||||
depends on (COMMON_CLK_HI3660 || COMPILE_TEST)
|
||||
depends on MAILBOX
|
||||
default COMMON_CLK_HI3660
|
||||
help
|
||||
Build the Hisilicon Hi3660 stub clock driver.
|
||||
|
@ -186,6 +186,23 @@ static const struct hisi_gate_clock hi3798cv200_gate_clks[] = {
|
||||
CLK_SET_RATE_PARENT, 0xbc, 0, 0 },
|
||||
{ HISTB_USB2_PHY2_REF_CLK, "clk_u2_phy2_ref", "24m",
|
||||
CLK_SET_RATE_PARENT, 0xbc, 2, 0 },
|
||||
/* USB3 */
|
||||
{ HISTB_USB3_BUS_CLK, "clk_u3_bus", NULL,
|
||||
CLK_SET_RATE_PARENT, 0xb0, 0, 0 },
|
||||
{ HISTB_USB3_UTMI_CLK, "clk_u3_utmi", NULL,
|
||||
CLK_SET_RATE_PARENT, 0xb0, 4, 0 },
|
||||
{ HISTB_USB3_PIPE_CLK, "clk_u3_pipe", NULL,
|
||||
CLK_SET_RATE_PARENT, 0xb0, 3, 0 },
|
||||
{ HISTB_USB3_SUSPEND_CLK, "clk_u3_suspend", NULL,
|
||||
CLK_SET_RATE_PARENT, 0xb0, 2, 0 },
|
||||
{ HISTB_USB3_BUS_CLK1, "clk_u3_bus1", NULL,
|
||||
CLK_SET_RATE_PARENT, 0xb0, 16, 0 },
|
||||
{ HISTB_USB3_UTMI_CLK1, "clk_u3_utmi1", NULL,
|
||||
CLK_SET_RATE_PARENT, 0xb0, 20, 0 },
|
||||
{ HISTB_USB3_PIPE_CLK1, "clk_u3_pipe1", NULL,
|
||||
CLK_SET_RATE_PARENT, 0xb0, 19, 0 },
|
||||
{ HISTB_USB3_SUSPEND_CLK1, "clk_u3_suspend1", NULL,
|
||||
CLK_SET_RATE_PARENT, 0xb0, 18, 0 },
|
||||
};
|
||||
|
||||
static struct hisi_clock_data *hi3798cv200_clk_register(
|
||||
|
@ -753,6 +753,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
|
||||
else
|
||||
clk[IMX6Q_CLK_ECSPI5] = imx_clk_gate2("ecspi5", "ecspi_root", base + 0x6c, 8);
|
||||
clk[IMX6QDL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x6c, 10);
|
||||
clk[IMX6QDL_CLK_EPIT1] = imx_clk_gate2("epit1", "ipg", base + 0x6c, 12);
|
||||
clk[IMX6QDL_CLK_EPIT2] = imx_clk_gate2("epit2", "ipg", base + 0x6c, 14);
|
||||
clk[IMX6QDL_CLK_ESAI_EXTAL] = imx_clk_gate2_shared("esai_extal", "esai_podf", base + 0x6c, 16, &share_count_esai);
|
||||
clk[IMX6QDL_CLK_ESAI_IPG] = imx_clk_gate2_shared("esai_ipg", "ahb", base + 0x6c, 16, &share_count_esai);
|
||||
clk[IMX6QDL_CLK_ESAI_MEM] = imx_clk_gate2_shared("esai_mem", "ahb", base + 0x6c, 16, &share_count_esai);
|
||||
|
@ -330,7 +330,7 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
|
||||
clks[IMX6SL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
|
||||
|
||||
/* name parent_name reg shift width */
|
||||
clks[IMX6SL_CLK_OCRAM_PODF] = imx_clk_divider("ocram_podf", "ocram_sel", base + 0x14, 16, 3);
|
||||
clks[IMX6SL_CLK_OCRAM_PODF] = imx_clk_busy_divider("ocram_podf", "ocram_sel", base + 0x14, 16, 3, base + 0x48, 0);
|
||||
clks[IMX6SL_CLK_PERIPH_CLK2_PODF] = imx_clk_divider("periph_clk2_podf", "periph_clk2_sel", base + 0x14, 27, 3);
|
||||
clks[IMX6SL_CLK_PERIPH2_CLK2_PODF] = imx_clk_divider("periph2_clk2_podf", "periph2_clk2_sel", base + 0x14, 0, 3);
|
||||
clks[IMX6SL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2);
|
||||
|
@ -80,7 +80,7 @@ static const char *lvds_sels[] = {
|
||||
"arm", "pll1_sys", "dummy", "dummy", "dummy", "dummy", "dummy", "pll5_video_div",
|
||||
"dummy", "dummy", "pcie_ref_125m", "dummy", "usbphy1", "usbphy2",
|
||||
};
|
||||
static const char *pll_bypass_src_sels[] = { "osc", "lvds1_in", };
|
||||
static const char *pll_bypass_src_sels[] = { "osc", "lvds1_in", "lvds2_in", "dummy", };
|
||||
static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", };
|
||||
static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", };
|
||||
static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", };
|
||||
@ -97,12 +97,7 @@ static int const clks_init_on[] __initconst = {
|
||||
IMX6SX_CLK_IPMUX1, IMX6SX_CLK_IPMUX2, IMX6SX_CLK_IPMUX3,
|
||||
IMX6SX_CLK_WAKEUP, IMX6SX_CLK_MMDC_P0_FAST, IMX6SX_CLK_MMDC_P0_IPG,
|
||||
IMX6SX_CLK_ROM, IMX6SX_CLK_ARM, IMX6SX_CLK_IPG, IMX6SX_CLK_OCRAM,
|
||||
IMX6SX_CLK_PER2_MAIN, IMX6SX_CLK_PERCLK, IMX6SX_CLK_M4,
|
||||
IMX6SX_CLK_QSPI1, IMX6SX_CLK_QSPI2, IMX6SX_CLK_UART_IPG,
|
||||
IMX6SX_CLK_UART_SERIAL, IMX6SX_CLK_I2C3, IMX6SX_CLK_ECSPI5,
|
||||
IMX6SX_CLK_CAN1_IPG, IMX6SX_CLK_CAN1_SERIAL, IMX6SX_CLK_CAN2_IPG,
|
||||
IMX6SX_CLK_CAN2_SERIAL, IMX6SX_CLK_CANFD, IMX6SX_CLK_EPIT1,
|
||||
IMX6SX_CLK_EPIT2,
|
||||
IMX6SX_CLK_PER2_MAIN, IMX6SX_CLK_PERCLK, IMX6SX_CLK_TZASC1,
|
||||
};
|
||||
|
||||
static const struct clk_div_table clk_enet_ref_table[] = {
|
||||
@ -158,8 +153,9 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
|
||||
clks[IMX6SX_CLK_IPP_DI0] = of_clk_get_by_name(ccm_node, "ipp_di0");
|
||||
clks[IMX6SX_CLK_IPP_DI1] = of_clk_get_by_name(ccm_node, "ipp_di1");
|
||||
|
||||
/* Clock source from external clock via CLK1 PAD */
|
||||
clks[IMX6SX_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0);
|
||||
/* Clock source from external clock via CLK1/2 PAD */
|
||||
clks[IMX6SX_CLK_ANACLK1] = of_clk_get_by_name(ccm_node, "anaclk1");
|
||||
clks[IMX6SX_CLK_ANACLK2] = of_clk_get_by_name(ccm_node, "anaclk2");
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-anatop");
|
||||
base = of_iomap(np, 0);
|
||||
@ -228,7 +224,9 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
|
||||
clks[IMX6SX_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
|
||||
|
||||
clks[IMX6SX_CLK_LVDS1_OUT] = imx_clk_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x160, 10, BIT(12));
|
||||
clks[IMX6SX_CLK_LVDS2_OUT] = imx_clk_gate_exclusive("lvds2_out", "lvds2_sel", base + 0x160, 11, BIT(13));
|
||||
clks[IMX6SX_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
|
||||
clks[IMX6SX_CLK_LVDS2_IN] = imx_clk_gate_exclusive("lvds2_in", "anaclk2", base + 0x160, 13, BIT(11));
|
||||
|
||||
clks[IMX6SX_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
|
||||
base + 0xe0, 0, 2, 0, clk_enet_ref_table,
|
||||
@ -270,6 +268,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
|
||||
|
||||
/* name reg shift width parent_names num_parents */
|
||||
clks[IMX6SX_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
|
||||
clks[IMX6SX_CLK_LVDS2_SEL] = imx_clk_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
|
||||
|
||||
np = ccm_node;
|
||||
base = of_iomap(np, 0);
|
||||
|
@ -40,7 +40,7 @@ static const char *axi_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_540m", };
|
||||
static const char *axi_sels[] = {"periph", "axi_alt_sel", };
|
||||
static const char *periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", };
|
||||
static const char *periph2_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll4_audio_div", };
|
||||
static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", };
|
||||
static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "pll2_bypass_src", };
|
||||
static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "osc", };
|
||||
static const char *periph_sels[] = { "periph_pre", "periph_clk2", };
|
||||
static const char *periph2_sels[] = { "periph2_pre", "periph2_clk2", };
|
||||
@ -68,6 +68,13 @@ static const char *sim_sels[] = { "sim_podf", "ipp_di0", "ipp_di1", "ldb_di0", "
|
||||
static const char *epdc_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd2_508m", };
|
||||
static const char *esai_sels[] = { "pll4_audio_div", "pll3_pfd2_508m", "pll5_video_div", "pll3_usb_otg", };
|
||||
static const char *epdc_sels[] = { "epdc_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
|
||||
static const char *cko1_sels[] = { "dummy", "dummy", "dummy", "dummy", "dummy", "axi", "enfc", "dummy", "dummy",
|
||||
"dummy", "lcdif_pix", "ahb", "ipg", "ipg_per", "ckil", "pll4_audio_div", };
|
||||
static const char *cko2_sels[] = { "dummy", "dummy", "dummy", "usdhc1", "dummy", "dummy", "ecspi_root", "dummy",
|
||||
"dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "osc", "dummy",
|
||||
"dummy", "usdhc2", "sai1", "sai2", "sai3", "dummy", "dummy", "can_root",
|
||||
"dummy", "dummy", "dummy", "dummy", "uart_serial", "spdif", "dummy", "dummy", };
|
||||
static const char *cko_sels[] = { "cko1", "cko2", };
|
||||
|
||||
static struct clk *clks[IMX6UL_CLK_END];
|
||||
static struct clk_onecell_data clk_data;
|
||||
@ -273,6 +280,10 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
|
||||
clks[IMX6UL_CLK_LDB_DI0_DIV_SEL] = imx_clk_mux("ldb_di0", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels));
|
||||
clks[IMX6UL_CLK_LDB_DI1_DIV_SEL] = imx_clk_mux("ldb_di1", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels));
|
||||
|
||||
clks[IMX6UL_CLK_CKO1_SEL] = imx_clk_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels));
|
||||
clks[IMX6UL_CLK_CKO2_SEL] = imx_clk_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels));
|
||||
clks[IMX6UL_CLK_CKO] = imx_clk_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels));
|
||||
|
||||
clks[IMX6UL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
|
||||
clks[IMX6UL_CLK_LDB_DI0_DIV_7] = imx_clk_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7);
|
||||
clks[IMX6UL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "qspi1_sel", 2, 7);
|
||||
@ -316,6 +327,9 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
|
||||
clks[IMX6UL_CLK_LCDIF_PRED] = imx_clk_divider("lcdif_pred", "lcdif_pre_sel", base + 0x38, 12, 3);
|
||||
clks[IMX6UL_CLK_CSI_PODF] = imx_clk_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3);
|
||||
|
||||
clks[IMX6UL_CLK_CKO1_PODF] = imx_clk_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3);
|
||||
clks[IMX6UL_CLK_CKO2_PODF] = imx_clk_divider("cko2_podf", "cko2_sel", base + 0x60, 21, 3);
|
||||
|
||||
clks[IMX6UL_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16);
|
||||
clks[IMX6UL_CLK_MMDC_PODF] = imx_clk_busy_divider("mmdc_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2);
|
||||
clks[IMX6UL_CLK_AXI_PODF] = imx_clk_busy_divider("axi_podf", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0);
|
||||
@ -445,6 +459,10 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
|
||||
clks[IMX6UL_CLK_PWM6] = imx_clk_gate2("pwm6", "perclk", base + 0x80, 28);
|
||||
clks[IMX6UL_CLK_PWM7] = imx_clk_gate2("pwm7", "perclk", base + 0x80, 30);
|
||||
|
||||
/* CCOSR */
|
||||
clks[IMX6UL_CLK_CKO1] = imx_clk_gate("cko1", "cko1_podf", base + 0x60, 7);
|
||||
clks[IMX6UL_CLK_CKO2] = imx_clk_gate("cko2", "cko2_podf", base + 0x60, 24);
|
||||
|
||||
/* mask handshake of mmdc */
|
||||
writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
|
||||
|
||||
|
@ -26,6 +26,8 @@ static u32 share_count_sai1;
|
||||
static u32 share_count_sai2;
|
||||
static u32 share_count_sai3;
|
||||
static u32 share_count_nand;
|
||||
static u32 share_count_enet1;
|
||||
static u32 share_count_enet2;
|
||||
|
||||
static const struct clk_div_table test_div_table[] = {
|
||||
{ .val = 3, .div = 1, },
|
||||
@ -729,7 +731,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
|
||||
clks[IMX7D_LCDIF_PIXEL_ROOT_DIV] = imx_clk_divider2("lcdif_pixel_post_div", "lcdif_pixel_pre_div", base + 0xa300, 0, 6);
|
||||
clks[IMX7D_MIPI_DSI_ROOT_DIV] = imx_clk_divider2("mipi_dsi_post_div", "mipi_dsi_pre_div", base + 0xa380, 0, 6);
|
||||
clks[IMX7D_MIPI_CSI_ROOT_DIV] = imx_clk_divider2("mipi_csi_post_div", "mipi_csi_pre_div", base + 0xa400, 0, 6);
|
||||
clks[IMX7D_MIPI_DPHY_ROOT_DIV] = imx_clk_divider2("mipi_dphy_post_div", "mipi_csi_dphy_div", base + 0xa480, 0, 6);
|
||||
clks[IMX7D_MIPI_DPHY_ROOT_DIV] = imx_clk_divider2("mipi_dphy_post_div", "mipi_dphy_pre_div", base + 0xa480, 0, 6);
|
||||
clks[IMX7D_SAI1_ROOT_DIV] = imx_clk_divider2("sai1_post_div", "sai1_pre_div", base + 0xa500, 0, 6);
|
||||
clks[IMX7D_SAI2_ROOT_DIV] = imx_clk_divider2("sai2_post_div", "sai2_pre_div", base + 0xa580, 0, 6);
|
||||
clks[IMX7D_SAI3_ROOT_DIV] = imx_clk_divider2("sai3_post_div", "sai3_pre_div", base + 0xa600, 0, 6);
|
||||
@ -738,7 +740,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
|
||||
clks[IMX7D_ENET1_TIME_ROOT_DIV] = imx_clk_divider2("enet1_time_post_div", "enet1_time_pre_div", base + 0xa780, 0, 6);
|
||||
clks[IMX7D_ENET2_REF_ROOT_DIV] = imx_clk_divider2("enet2_ref_post_div", "enet2_ref_pre_div", base + 0xa800, 0, 6);
|
||||
clks[IMX7D_ENET2_TIME_ROOT_DIV] = imx_clk_divider2("enet2_time_post_div", "enet2_time_pre_div", base + 0xa880, 0, 6);
|
||||
clks[IMX7D_ENET_PHY_REF_ROOT_DIV] = imx_clk_divider2("enet_phy_ref_post_div", "enet_phy_ref_pre_div", base + 0xa900, 0, 6);
|
||||
clks[IMX7D_ENET_PHY_REF_ROOT_CLK] = imx_clk_divider2("enet_phy_ref_root_clk", "enet_phy_ref_pre_div", base + 0xa900, 0, 6);
|
||||
clks[IMX7D_EIM_ROOT_DIV] = imx_clk_divider2("eim_post_div", "eim_pre_div", base + 0xa980, 0, 6);
|
||||
clks[IMX7D_NAND_ROOT_CLK] = imx_clk_divider2("nand_root_clk", "nand_pre_div", base + 0xaa00, 0, 6);
|
||||
clks[IMX7D_QSPI_ROOT_DIV] = imx_clk_divider2("qspi_post_div", "qspi_pre_div", base + 0xaa80, 0, 6);
|
||||
@ -805,6 +807,10 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
|
||||
clks[IMX7D_MIPI_DSI_ROOT_CLK] = imx_clk_gate4("mipi_dsi_root_clk", "mipi_dsi_post_div", base + 0x4650, 0);
|
||||
clks[IMX7D_MIPI_CSI_ROOT_CLK] = imx_clk_gate4("mipi_csi_root_clk", "mipi_csi_post_div", base + 0x4640, 0);
|
||||
clks[IMX7D_MIPI_DPHY_ROOT_CLK] = imx_clk_gate4("mipi_dphy_root_clk", "mipi_dphy_post_div", base + 0x4660, 0);
|
||||
clks[IMX7D_ENET1_IPG_ROOT_CLK] = imx_clk_gate2_shared2("enet1_ipg_root_clk", "enet_axi_post_div", base + 0x4700, 0, &share_count_enet1);
|
||||
clks[IMX7D_ENET1_TIME_ROOT_CLK] = imx_clk_gate2_shared2("enet1_time_root_clk", "enet1_time_post_div", base + 0x4700, 0, &share_count_enet1);
|
||||
clks[IMX7D_ENET2_IPG_ROOT_CLK] = imx_clk_gate2_shared2("enet2_ipg_root_clk", "enet_axi_post_div", base + 0x4710, 0, &share_count_enet2);
|
||||
clks[IMX7D_ENET2_TIME_ROOT_CLK] = imx_clk_gate2_shared2("enet2_time_root_clk", "enet2_time_post_div", base + 0x4710, 0, &share_count_enet2);
|
||||
clks[IMX7D_SAI1_ROOT_CLK] = imx_clk_gate2_shared2("sai1_root_clk", "sai1_post_div", base + 0x48c0, 0, &share_count_sai1);
|
||||
clks[IMX7D_SAI1_IPG_CLK] = imx_clk_gate2_shared2("sai1_ipg_clk", "ipg_root_clk", base + 0x48c0, 0, &share_count_sai1);
|
||||
clks[IMX7D_SAI2_ROOT_CLK] = imx_clk_gate2_shared2("sai2_root_clk", "sai2_post_div", base + 0x48d0, 0, &share_count_sai2);
|
||||
@ -812,11 +818,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
|
||||
clks[IMX7D_SAI3_ROOT_CLK] = imx_clk_gate2_shared2("sai3_root_clk", "sai3_post_div", base + 0x48e0, 0, &share_count_sai3);
|
||||
clks[IMX7D_SAI3_IPG_CLK] = imx_clk_gate2_shared2("sai3_ipg_clk", "ipg_root_clk", base + 0x48e0, 0, &share_count_sai3);
|
||||
clks[IMX7D_SPDIF_ROOT_CLK] = imx_clk_gate4("spdif_root_clk", "spdif_post_div", base + 0x44d0, 0);
|
||||
clks[IMX7D_ENET1_REF_ROOT_CLK] = imx_clk_gate4("enet1_ref_root_clk", "enet1_ref_post_div", base + 0x44e0, 0);
|
||||
clks[IMX7D_ENET1_TIME_ROOT_CLK] = imx_clk_gate4("enet1_time_root_clk", "enet1_time_post_div", base + 0x44f0, 0);
|
||||
clks[IMX7D_ENET2_REF_ROOT_CLK] = imx_clk_gate4("enet2_ref_root_clk", "enet2_ref_post_div", base + 0x4500, 0);
|
||||
clks[IMX7D_ENET2_TIME_ROOT_CLK] = imx_clk_gate4("enet2_time_root_clk", "enet2_time_post_div", base + 0x4510, 0);
|
||||
clks[IMX7D_ENET_PHY_REF_ROOT_CLK] = imx_clk_gate4("enet_phy_ref_root_clk", "enet_phy_ref_post_div", base + 0x4520, 0);
|
||||
clks[IMX7D_EIM_ROOT_CLK] = imx_clk_gate4("eim_root_clk", "eim_post_div", base + 0x4160, 0);
|
||||
clks[IMX7D_NAND_RAWNAND_CLK] = imx_clk_gate2_shared2("nand_rawnand_clk", "nand_root_clk", base + 0x4140, 0, &share_count_nand);
|
||||
clks[IMX7D_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_root_clk", base + 0x4140, 0, &share_count_nand);
|
||||
@ -891,6 +892,8 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
|
||||
clk_set_parent(clks[IMX7D_PLL_AUDIO_MAIN_BYPASS], clks[IMX7D_PLL_AUDIO_MAIN]);
|
||||
clk_set_parent(clks[IMX7D_PLL_VIDEO_MAIN_BYPASS], clks[IMX7D_PLL_VIDEO_MAIN]);
|
||||
|
||||
clk_set_parent(clks[IMX7D_MIPI_CSI_ROOT_SRC], clks[IMX7D_PLL_SYS_PFD3_CLK]);
|
||||
|
||||
/* use old gpt clk setting, gpt1 root clk must be twice as gpt counter freq */
|
||||
clk_set_parent(clks[IMX7D_GPT1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]);
|
||||
|
||||
|
@ -43,7 +43,8 @@ static inline bool
|
||||
ingenic_cgu_gate_get(struct ingenic_cgu *cgu,
|
||||
const struct ingenic_cgu_gate_info *info)
|
||||
{
|
||||
return readl(cgu->base + info->reg) & BIT(info->bit);
|
||||
return !!(readl(cgu->base + info->reg) & BIT(info->bit))
|
||||
^ info->clear_to_gate;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -62,7 +63,7 @@ ingenic_cgu_gate_set(struct ingenic_cgu *cgu,
|
||||
{
|
||||
u32 clkgr = readl(cgu->base + info->reg);
|
||||
|
||||
if (val)
|
||||
if (val ^ info->clear_to_gate)
|
||||
clkgr |= BIT(info->bit);
|
||||
else
|
||||
clkgr &= ~BIT(info->bit);
|
||||
@ -511,6 +512,9 @@ static int ingenic_clk_enable(struct clk_hw *hw)
|
||||
spin_lock_irqsave(&cgu->lock, flags);
|
||||
ingenic_cgu_gate_set(cgu, &clk_info->gate, false);
|
||||
spin_unlock_irqrestore(&cgu->lock, flags);
|
||||
|
||||
if (clk_info->gate.delay_us)
|
||||
udelay(clk_info->gate.delay_us);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -111,10 +111,14 @@ struct ingenic_cgu_fixdiv_info {
|
||||
* struct ingenic_cgu_gate_info - information about a clock gate
|
||||
* @reg: offset of the gate control register within the CGU
|
||||
* @bit: offset of the bit in the register that controls the gate
|
||||
* @clear_to_gate: if set, the clock is gated when the bit is cleared
|
||||
* @delay_us: delay in microseconds after which the clock is considered stable
|
||||
*/
|
||||
struct ingenic_cgu_gate_info {
|
||||
unsigned reg;
|
||||
u8 bit;
|
||||
bool clear_to_gate;
|
||||
u16 delay_us;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -42,7 +42,6 @@
|
||||
|
||||
/* bits within the OPCR register */
|
||||
#define OPCR_SPENDH BIT(5) /* UHC PHY suspend */
|
||||
#define OPCR_SPENDN BIT(7) /* OTG PHY suspend */
|
||||
|
||||
/* bits within the USBPCR1 register */
|
||||
#define USBPCR1_UHC_POWER BIT(5) /* UHC PHY power down */
|
||||
@ -83,37 +82,6 @@ static const struct clk_ops jz4770_uhc_phy_ops = {
|
||||
.is_enabled = jz4770_uhc_phy_is_enabled,
|
||||
};
|
||||
|
||||
static int jz4770_otg_phy_enable(struct clk_hw *hw)
|
||||
{
|
||||
void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
|
||||
|
||||
writel(readl(reg_opcr) | OPCR_SPENDN, reg_opcr);
|
||||
|
||||
/* Wait for the clock to be stable */
|
||||
udelay(50);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void jz4770_otg_phy_disable(struct clk_hw *hw)
|
||||
{
|
||||
void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
|
||||
|
||||
writel(readl(reg_opcr) & ~OPCR_SPENDN, reg_opcr);
|
||||
}
|
||||
|
||||
static int jz4770_otg_phy_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
|
||||
|
||||
return !!(readl(reg_opcr) & OPCR_SPENDN);
|
||||
}
|
||||
|
||||
static const struct clk_ops jz4770_otg_phy_ops = {
|
||||
.enable = jz4770_otg_phy_enable,
|
||||
.disable = jz4770_otg_phy_disable,
|
||||
.is_enabled = jz4770_otg_phy_is_enabled,
|
||||
};
|
||||
|
||||
static const s8 pll_od_encoding[8] = {
|
||||
0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
|
||||
};
|
||||
@ -186,7 +154,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
|
||||
"h1clk", CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { JZ4770_CLK_PLL0, },
|
||||
.div = { CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1 },
|
||||
.gate = { CGU_REG_LCR, 30 },
|
||||
.gate = { CGU_REG_CLKGR1, 7 },
|
||||
},
|
||||
[JZ4770_CLK_H2CLK] = {
|
||||
"h2clk", CGU_CLK_DIV,
|
||||
@ -194,9 +162,10 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
|
||||
.div = { CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1 },
|
||||
},
|
||||
[JZ4770_CLK_C1CLK] = {
|
||||
"c1clk", CGU_CLK_DIV,
|
||||
"c1clk", CGU_CLK_DIV | CGU_CLK_GATE,
|
||||
.parents = { JZ4770_CLK_PLL0, },
|
||||
.div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 },
|
||||
.gate = { CGU_REG_OPCR, 31, true }, // disable CCLK stop on idle
|
||||
},
|
||||
[JZ4770_CLK_PCLK] = {
|
||||
"pclk", CGU_CLK_DIV,
|
||||
@ -393,7 +362,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
|
||||
[JZ4770_CLK_VPU] = {
|
||||
"vpu", CGU_CLK_GATE,
|
||||
.parents = { JZ4770_CLK_H1CLK, },
|
||||
.gate = { CGU_REG_CLKGR1, 7 },
|
||||
.gate = { CGU_REG_LCR, 30, false, 150 },
|
||||
},
|
||||
[JZ4770_CLK_MMC0] = {
|
||||
"mmc0", CGU_CLK_GATE,
|
||||
@ -410,6 +379,11 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
|
||||
.parents = { JZ4770_CLK_MMC2_MUX, },
|
||||
.gate = { CGU_REG_CLKGR0, 12 },
|
||||
},
|
||||
[JZ4770_CLK_OTG_PHY] = {
|
||||
"usb_phy", CGU_CLK_GATE,
|
||||
.parents = { JZ4770_CLK_OTG },
|
||||
.gate = { CGU_REG_OPCR, 7, true, 50 },
|
||||
},
|
||||
|
||||
/* Custom clocks */
|
||||
|
||||
@ -418,11 +392,6 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
|
||||
.parents = { JZ4770_CLK_UHC, -1, -1, -1 },
|
||||
.custom = { &jz4770_uhc_phy_ops },
|
||||
},
|
||||
[JZ4770_CLK_OTG_PHY] = {
|
||||
"usb_phy", CGU_CLK_CUSTOM,
|
||||
.parents = { JZ4770_CLK_OTG, -1, -1, -1 },
|
||||
.custom = { &jz4770_otg_phy_ops },
|
||||
},
|
||||
|
||||
[JZ4770_CLK_EXT512] = {
|
||||
"ext/512", CGU_CLK_FIXDIV,
|
||||
|
@ -60,6 +60,12 @@ config COMMON_CLK_MT2701_AUDSYS
|
||||
---help---
|
||||
This driver supports Mediatek MT2701 audsys clocks.
|
||||
|
||||
config COMMON_CLK_MT2701_G3DSYS
|
||||
bool "Clock driver for MediaTek MT2701 g3dsys"
|
||||
depends on COMMON_CLK_MT2701
|
||||
---help---
|
||||
This driver supports MediaTek MT2701 g3dsys clocks.
|
||||
|
||||
config COMMON_CLK_MT2712
|
||||
bool "Clock driver for MediaTek MT2712"
|
||||
depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST
|
||||
|
@ -9,6 +9,7 @@ obj-$(CONFIG_COMMON_CLK_MT2701) += clk-mt2701.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT2701_AUDSYS) += clk-mt2701-aud.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT2701_BDPSYS) += clk-mt2701-bdp.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT2701_ETHSYS) += clk-mt2701-eth.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT2701_G3DSYS) += clk-mt2701-g3d.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT2701_HIFSYS) += clk-mt2701-hif.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT2701_IMGSYS) += clk-mt2701-img.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT2701_MMSYS) += clk-mt2701-mm.o
|
||||
|
95
drivers/clk/mediatek/clk-mt2701-g3d.c
Normal file
95
drivers/clk/mediatek/clk-mt2701-g3d.c
Normal file
@ -0,0 +1,95 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2018 MediaTek Inc.
|
||||
* Author: Sean Wang <sean.wang@mediatek.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "clk-mtk.h"
|
||||
#include "clk-gate.h"
|
||||
|
||||
#include <dt-bindings/clock/mt2701-clk.h>
|
||||
|
||||
#define GATE_G3D(_id, _name, _parent, _shift) { \
|
||||
.id = _id, \
|
||||
.name = _name, \
|
||||
.parent_name = _parent, \
|
||||
.regs = &g3d_cg_regs, \
|
||||
.shift = _shift, \
|
||||
.ops = &mtk_clk_gate_ops_setclr, \
|
||||
}
|
||||
|
||||
static const struct mtk_gate_regs g3d_cg_regs = {
|
||||
.sta_ofs = 0x0,
|
||||
.set_ofs = 0x4,
|
||||
.clr_ofs = 0x8,
|
||||
};
|
||||
|
||||
static const struct mtk_gate g3d_clks[] = {
|
||||
GATE_G3D(CLK_G3DSYS_CORE, "g3d_core", "mfg_sel", 0),
|
||||
};
|
||||
|
||||
static int clk_mt2701_g3dsys_init(struct platform_device *pdev)
|
||||
{
|
||||
struct clk_onecell_data *clk_data;
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
int r;
|
||||
|
||||
clk_data = mtk_alloc_clk_data(CLK_G3DSYS_NR);
|
||||
|
||||
mtk_clk_register_gates(node, g3d_clks, ARRAY_SIZE(g3d_clks),
|
||||
clk_data);
|
||||
|
||||
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
|
||||
if (r)
|
||||
dev_err(&pdev->dev,
|
||||
"could not register clock provider: %s: %d\n",
|
||||
pdev->name, r);
|
||||
|
||||
mtk_register_reset_controller(node, 1, 0xc);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static const struct of_device_id of_match_clk_mt2701_g3d[] = {
|
||||
{
|
||||
.compatible = "mediatek,mt2701-g3dsys",
|
||||
.data = clk_mt2701_g3dsys_init,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
|
||||
static int clk_mt2701_g3d_probe(struct platform_device *pdev)
|
||||
{
|
||||
int (*clk_init)(struct platform_device *);
|
||||
int r;
|
||||
|
||||
clk_init = of_device_get_match_data(&pdev->dev);
|
||||
if (!clk_init)
|
||||
return -EINVAL;
|
||||
|
||||
r = clk_init(pdev);
|
||||
if (r)
|
||||
dev_err(&pdev->dev,
|
||||
"could not register clock provider: %s: %d\n",
|
||||
pdev->name, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct platform_driver clk_mt2701_g3d_drv = {
|
||||
.probe = clk_mt2701_g3d_probe,
|
||||
.driver = {
|
||||
.name = "clk-mt2701-g3d",
|
||||
.of_match_table = of_match_clk_mt2701_g3d,
|
||||
},
|
||||
};
|
||||
|
||||
builtin_platform_driver(clk_mt2701_g3d_drv);
|
@ -46,8 +46,6 @@ static const struct mtk_fixed_clk top_fixed_clks[] = {
|
||||
340 * MHZ),
|
||||
FIXED_CLK(CLK_TOP_HDMI_0_PLL340M, "hdmi_0_pll340m", "clk26m",
|
||||
340 * MHZ),
|
||||
FIXED_CLK(CLK_TOP_HDMITX_CLKDIG_CTS, "hdmitx_dig_cts", "clk26m",
|
||||
300 * MHZ),
|
||||
FIXED_CLK(CLK_TOP_HADDS2_FB, "hadds2_fbclk", "clk26m",
|
||||
27 * MHZ),
|
||||
FIXED_CLK(CLK_TOP_WBG_DIG_416M, "wbg_dig_ck_416m", "clk26m",
|
||||
@ -977,6 +975,10 @@ static const struct mtk_pll_data apmixed_plls[] = {
|
||||
21, 0x2d0, 4, 0x0, 0x2d4, 0),
|
||||
};
|
||||
|
||||
static const struct mtk_fixed_factor apmixed_fixed_divs[] = {
|
||||
FACTOR(CLK_APMIXED_HDMI_REF, "hdmi_ref", "tvdpll", 1, 1),
|
||||
};
|
||||
|
||||
static int mtk_apmixedsys_init(struct platform_device *pdev)
|
||||
{
|
||||
struct clk_onecell_data *clk_data;
|
||||
@ -988,6 +990,8 @@ static int mtk_apmixedsys_init(struct platform_device *pdev)
|
||||
|
||||
mtk_clk_register_plls(node, apmixed_plls, ARRAY_SIZE(apmixed_plls),
|
||||
clk_data);
|
||||
mtk_clk_register_factors(apmixed_fixed_divs, ARRAY_SIZE(apmixed_fixed_divs),
|
||||
clk_data);
|
||||
|
||||
return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
|
||||
}
|
||||
|
@ -3,6 +3,12 @@ config COMMON_CLK_AMLOGIC
|
||||
depends on OF
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
|
||||
config COMMON_CLK_MESON_AO
|
||||
bool
|
||||
depends on OF
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
select COMMON_CLK_REGMAP_MESON
|
||||
|
||||
config COMMON_CLK_REGMAP_MESON
|
||||
bool
|
||||
select REGMAP
|
||||
@ -21,6 +27,7 @@ config COMMON_CLK_GXBB
|
||||
bool
|
||||
depends on COMMON_CLK_AMLOGIC
|
||||
select RESET_CONTROLLER
|
||||
select COMMON_CLK_MESON_AO
|
||||
select COMMON_CLK_REGMAP_MESON
|
||||
select MFD_SYSCON
|
||||
help
|
||||
@ -31,6 +38,7 @@ config COMMON_CLK_AXG
|
||||
bool
|
||||
depends on COMMON_CLK_AMLOGIC
|
||||
select RESET_CONTROLLER
|
||||
select COMMON_CLK_MESON_AO
|
||||
select COMMON_CLK_REGMAP_MESON
|
||||
select MFD_SYSCON
|
||||
help
|
||||
|
@ -3,7 +3,8 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-audio-divider.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
|
||||
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
|
||||
obj-$(CONFIG_COMMON_CLK_AXG) += axg.o
|
||||
obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
|
||||
obj-$(CONFIG_COMMON_CLK_REGMAP_MESON) += clk-regmap.o
|
||||
|
164
drivers/clk/meson/axg-aoclk.c
Normal file
164
drivers/clk/meson/axg-aoclk.c
Normal file
@ -0,0 +1,164 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Amlogic Meson-AXG Clock Controller Driver
|
||||
*
|
||||
* Copyright (c) 2016 Baylibre SAS.
|
||||
* Author: Michael Turquette <mturquette@baylibre.com>
|
||||
*
|
||||
* Copyright (c) 2018 Amlogic, inc.
|
||||
* Author: Qiufang Dai <qiufang.dai@amlogic.com>
|
||||
*/
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include "clk-regmap.h"
|
||||
#include "meson-aoclk.h"
|
||||
#include "axg-aoclk.h"
|
||||
|
||||
#define AXG_AO_GATE(_name, _bit) \
|
||||
static struct clk_regmap axg_aoclk_##_name = { \
|
||||
.data = &(struct clk_regmap_gate_data) { \
|
||||
.offset = (AO_RTI_GEN_CNTL_REG0), \
|
||||
.bit_idx = (_bit), \
|
||||
}, \
|
||||
.hw.init = &(struct clk_init_data) { \
|
||||
.name = "axg_ao_" #_name, \
|
||||
.ops = &clk_regmap_gate_ops, \
|
||||
.parent_names = (const char *[]){ "clk81" }, \
|
||||
.num_parents = 1, \
|
||||
.flags = CLK_IGNORE_UNUSED, \
|
||||
}, \
|
||||
}
|
||||
|
||||
AXG_AO_GATE(remote, 0);
|
||||
AXG_AO_GATE(i2c_master, 1);
|
||||
AXG_AO_GATE(i2c_slave, 2);
|
||||
AXG_AO_GATE(uart1, 3);
|
||||
AXG_AO_GATE(uart2, 5);
|
||||
AXG_AO_GATE(ir_blaster, 6);
|
||||
AXG_AO_GATE(saradc, 7);
|
||||
|
||||
static struct clk_regmap axg_aoclk_clk81 = {
|
||||
.data = &(struct clk_regmap_mux_data) {
|
||||
.offset = AO_RTI_PWR_CNTL_REG0,
|
||||
.mask = 0x1,
|
||||
.shift = 8,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "axg_ao_clk81",
|
||||
.ops = &clk_regmap_mux_ro_ops,
|
||||
.parent_names = (const char *[]){ "clk81", "ao_alt_xtal"},
|
||||
.num_parents = 2,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_aoclk_saradc_mux = {
|
||||
.data = &(struct clk_regmap_mux_data) {
|
||||
.offset = AO_SAR_CLK,
|
||||
.mask = 0x3,
|
||||
.shift = 9,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "axg_ao_saradc_mux",
|
||||
.ops = &clk_regmap_mux_ops,
|
||||
.parent_names = (const char *[]){ "xtal", "axg_ao_clk81" },
|
||||
.num_parents = 2,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_aoclk_saradc_div = {
|
||||
.data = &(struct clk_regmap_div_data) {
|
||||
.offset = AO_SAR_CLK,
|
||||
.shift = 0,
|
||||
.width = 8,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "axg_ao_saradc_div",
|
||||
.ops = &clk_regmap_divider_ops,
|
||||
.parent_names = (const char *[]){ "axg_ao_saradc_mux" },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap axg_aoclk_saradc_gate = {
|
||||
.data = &(struct clk_regmap_gate_data) {
|
||||
.offset = AO_SAR_CLK,
|
||||
.bit_idx = 8,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "axg_ao_saradc_gate",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_names = (const char *[]){ "axg_ao_saradc_div" },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static const unsigned int axg_aoclk_reset[] = {
|
||||
[RESET_AO_REMOTE] = 16,
|
||||
[RESET_AO_I2C_MASTER] = 18,
|
||||
[RESET_AO_I2C_SLAVE] = 19,
|
||||
[RESET_AO_UART1] = 17,
|
||||
[RESET_AO_UART2] = 22,
|
||||
[RESET_AO_IR_BLASTER] = 23,
|
||||
};
|
||||
|
||||
static struct clk_regmap *axg_aoclk_regmap[] = {
|
||||
[CLKID_AO_REMOTE] = &axg_aoclk_remote,
|
||||
[CLKID_AO_I2C_MASTER] = &axg_aoclk_i2c_master,
|
||||
[CLKID_AO_I2C_SLAVE] = &axg_aoclk_i2c_slave,
|
||||
[CLKID_AO_UART1] = &axg_aoclk_uart1,
|
||||
[CLKID_AO_UART2] = &axg_aoclk_uart2,
|
||||
[CLKID_AO_IR_BLASTER] = &axg_aoclk_ir_blaster,
|
||||
[CLKID_AO_SAR_ADC] = &axg_aoclk_saradc,
|
||||
[CLKID_AO_CLK81] = &axg_aoclk_clk81,
|
||||
[CLKID_AO_SAR_ADC_SEL] = &axg_aoclk_saradc_mux,
|
||||
[CLKID_AO_SAR_ADC_DIV] = &axg_aoclk_saradc_div,
|
||||
[CLKID_AO_SAR_ADC_CLK] = &axg_aoclk_saradc_gate,
|
||||
};
|
||||
|
||||
static const struct clk_hw_onecell_data axg_aoclk_onecell_data = {
|
||||
.hws = {
|
||||
[CLKID_AO_REMOTE] = &axg_aoclk_remote.hw,
|
||||
[CLKID_AO_I2C_MASTER] = &axg_aoclk_i2c_master.hw,
|
||||
[CLKID_AO_I2C_SLAVE] = &axg_aoclk_i2c_slave.hw,
|
||||
[CLKID_AO_UART1] = &axg_aoclk_uart1.hw,
|
||||
[CLKID_AO_UART2] = &axg_aoclk_uart2.hw,
|
||||
[CLKID_AO_IR_BLASTER] = &axg_aoclk_ir_blaster.hw,
|
||||
[CLKID_AO_SAR_ADC] = &axg_aoclk_saradc.hw,
|
||||
[CLKID_AO_CLK81] = &axg_aoclk_clk81.hw,
|
||||
[CLKID_AO_SAR_ADC_SEL] = &axg_aoclk_saradc_mux.hw,
|
||||
[CLKID_AO_SAR_ADC_DIV] = &axg_aoclk_saradc_div.hw,
|
||||
[CLKID_AO_SAR_ADC_CLK] = &axg_aoclk_saradc_gate.hw,
|
||||
},
|
||||
.num = NR_CLKS,
|
||||
};
|
||||
|
||||
static const struct meson_aoclk_data axg_aoclkc_data = {
|
||||
.reset_reg = AO_RTI_GEN_CNTL_REG0,
|
||||
.num_reset = ARRAY_SIZE(axg_aoclk_reset),
|
||||
.reset = axg_aoclk_reset,
|
||||
.num_clks = ARRAY_SIZE(axg_aoclk_regmap),
|
||||
.clks = axg_aoclk_regmap,
|
||||
.hw_data = &axg_aoclk_onecell_data,
|
||||
};
|
||||
|
||||
static const struct of_device_id axg_aoclkc_match_table[] = {
|
||||
{
|
||||
.compatible = "amlogic,meson-axg-aoclkc",
|
||||
.data = &axg_aoclkc_data,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver axg_aoclkc_driver = {
|
||||
.probe = meson_aoclkc_probe,
|
||||
.driver = {
|
||||
.name = "axg-aoclkc",
|
||||
.of_match_table = axg_aoclkc_match_table,
|
||||
},
|
||||
};
|
||||
|
||||
builtin_platform_driver(axg_aoclkc_driver);
|
29
drivers/clk/meson/axg-aoclk.h
Normal file
29
drivers/clk/meson/axg-aoclk.h
Normal file
@ -0,0 +1,29 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
|
||||
/*
|
||||
* Copyright (c) 2017 BayLibre, SAS
|
||||
* Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||
*
|
||||
* Copyright (c) 2018 Amlogic, inc.
|
||||
* Author: Qiufang Dai <qiufang.dai@amlogic.com>
|
||||
*/
|
||||
|
||||
#ifndef __AXG_AOCLKC_H
|
||||
#define __AXG_AOCLKC_H
|
||||
|
||||
#define NR_CLKS 11
|
||||
/* AO Configuration Clock registers offsets
|
||||
* Register offsets from the data sheet must be multiplied by 4.
|
||||
*/
|
||||
#define AO_RTI_PWR_CNTL_REG1 0x0C
|
||||
#define AO_RTI_PWR_CNTL_REG0 0x10
|
||||
#define AO_RTI_GEN_CNTL_REG0 0x40
|
||||
#define AO_OSCIN_CNTL 0x58
|
||||
#define AO_CRT_CLK_CNTL1 0x68
|
||||
#define AO_SAR_CLK 0x90
|
||||
#define AO_RTC_ALT_CLK_CNTL0 0x94
|
||||
#define AO_RTC_ALT_CLK_CNTL1 0x98
|
||||
|
||||
#include <dt-bindings/clock/axg-aoclkc.h>
|
||||
#include <dt-bindings/reset/axg-aoclkc.h>
|
||||
|
||||
#endif /* __AXG_AOCLKC_H */
|
@ -461,6 +461,7 @@ static struct clk_regmap axg_mpll0_div = {
|
||||
.width = 1,
|
||||
},
|
||||
.lock = &meson_clk_lock,
|
||||
.flags = CLK_MESON_MPLL_ROUND_CLOSEST,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mpll0_div",
|
||||
@ -507,6 +508,7 @@ static struct clk_regmap axg_mpll1_div = {
|
||||
.width = 1,
|
||||
},
|
||||
.lock = &meson_clk_lock,
|
||||
.flags = CLK_MESON_MPLL_ROUND_CLOSEST,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mpll1_div",
|
||||
@ -553,6 +555,7 @@ static struct clk_regmap axg_mpll2_div = {
|
||||
.width = 1,
|
||||
},
|
||||
.lock = &meson_clk_lock,
|
||||
.flags = CLK_MESON_MPLL_ROUND_CLOSEST,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mpll2_div",
|
||||
@ -599,6 +602,7 @@ static struct clk_regmap axg_mpll3_div = {
|
||||
.width = 1,
|
||||
},
|
||||
.lock = &meson_clk_lock,
|
||||
.flags = CLK_MESON_MPLL_ROUND_CLOSEST,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mpll3_div",
|
||||
|
@ -1,18 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2017 AmLogic, Inc.
|
||||
* Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -1,57 +1,7 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
|
||||
/*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright (c) 2016 AmLogic, Inc.
|
||||
* Author: Michael Turquette <mturquette@baylibre.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* The full GNU General Public License is included in this distribution
|
||||
* in the file called COPYING
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (c) 2016 AmLogic, Inc.
|
||||
* Author: Michael Turquette <mturquette@baylibre.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -89,10 +39,23 @@ static long rate_from_params(unsigned long parent_rate,
|
||||
static void params_from_rate(unsigned long requested_rate,
|
||||
unsigned long parent_rate,
|
||||
unsigned int *sdm,
|
||||
unsigned int *n2)
|
||||
unsigned int *n2,
|
||||
u8 flags)
|
||||
{
|
||||
uint64_t div = parent_rate;
|
||||
unsigned long rem = do_div(div, requested_rate);
|
||||
uint64_t frac = do_div(div, requested_rate);
|
||||
|
||||
frac *= SDM_DEN;
|
||||
|
||||
if (flags & CLK_MESON_MPLL_ROUND_CLOSEST)
|
||||
*sdm = DIV_ROUND_CLOSEST_ULL(frac, requested_rate);
|
||||
else
|
||||
*sdm = DIV_ROUND_UP_ULL(frac, requested_rate);
|
||||
|
||||
if (*sdm == SDM_DEN) {
|
||||
*sdm = 0;
|
||||
div += 1;
|
||||
}
|
||||
|
||||
if (div < N2_MIN) {
|
||||
*n2 = N2_MIN;
|
||||
@ -102,7 +65,6 @@ static void params_from_rate(unsigned long requested_rate,
|
||||
*sdm = SDM_DEN - 1;
|
||||
} else {
|
||||
*n2 = div;
|
||||
*sdm = DIV_ROUND_UP_ULL((u64)rem * SDM_DEN, requested_rate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,9 +87,11 @@ static long mpll_round_rate(struct clk_hw *hw,
|
||||
unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct clk_regmap *clk = to_clk_regmap(hw);
|
||||
struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
|
||||
unsigned int sdm, n2;
|
||||
|
||||
params_from_rate(rate, *parent_rate, &sdm, &n2);
|
||||
params_from_rate(rate, *parent_rate, &sdm, &n2, mpll->flags);
|
||||
return rate_from_params(*parent_rate, sdm, n2);
|
||||
}
|
||||
|
||||
@ -140,7 +104,7 @@ static int mpll_set_rate(struct clk_hw *hw,
|
||||
unsigned int sdm, n2;
|
||||
unsigned long flags = 0;
|
||||
|
||||
params_from_rate(rate, parent_rate, &sdm, &n2);
|
||||
params_from_rate(rate, parent_rate, &sdm, &n2, mpll->flags);
|
||||
|
||||
if (mpll->lock)
|
||||
spin_lock_irqsave(mpll->lock, flags);
|
||||
|
@ -1,21 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2015 Endless Mobile, Inc.
|
||||
* Author: Carlo Caione <carlo@endlessm.com>
|
||||
*
|
||||
* Copyright (c) 2018 Baylibre, SAS.
|
||||
* Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -1,6 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2018 BayLibre, SAS.
|
||||
// Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
/*
|
||||
* Copyright (c) 2018 BayLibre, SAS.
|
||||
* Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
*/
|
||||
|
||||
#include "clk-regmap.h"
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2018 BayLibre, SAS.
|
||||
// Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2018 BayLibre, SAS.
|
||||
* Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
*/
|
||||
|
||||
#ifndef __CLK_REGMAP_H
|
||||
#define __CLK_REGMAP_H
|
||||
|
@ -1,18 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2015 Endless Mobile, Inc.
|
||||
* Author: Carlo Caione <carlo@endlessm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __CLKC_H
|
||||
@ -97,8 +86,11 @@ struct meson_clk_mpll_data {
|
||||
struct parm ssen;
|
||||
struct parm misc;
|
||||
spinlock_t *lock;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
#define CLK_MESON_MPLL_ROUND_CLOSEST BIT(0)
|
||||
|
||||
struct meson_clk_audio_div_data {
|
||||
struct parm div;
|
||||
u8 flags;
|
||||
|
@ -1,8 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2017 BayLibre, SAS.
|
||||
* Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
|
@ -1,90 +1,14 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
|
||||
/*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright (c) 2016 BayLibre, SAS.
|
||||
* Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
* The full GNU General Public License is included in this distribution
|
||||
* in the file called COPYING.
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (c) 2016 BayLibre, SAS.
|
||||
* Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <dt-bindings/clock/gxbb-aoclkc.h>
|
||||
#include <dt-bindings/reset/gxbb-aoclkc.h>
|
||||
#include "clk-regmap.h"
|
||||
#include "meson-aoclk.h"
|
||||
#include "gxbb-aoclk.h"
|
||||
|
||||
struct gxbb_aoclk_reset_controller {
|
||||
struct reset_controller_dev reset;
|
||||
unsigned int *data;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static int gxbb_aoclk_do_reset(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct gxbb_aoclk_reset_controller *reset =
|
||||
container_of(rcdev, struct gxbb_aoclk_reset_controller, reset);
|
||||
|
||||
return regmap_write(reset->regmap, AO_RTI_GEN_CNTL_REG0,
|
||||
BIT(reset->data[id]));
|
||||
}
|
||||
|
||||
static const struct reset_control_ops gxbb_aoclk_reset_ops = {
|
||||
.reset = gxbb_aoclk_do_reset,
|
||||
};
|
||||
|
||||
#define GXBB_AO_GATE(_name, _bit) \
|
||||
static struct clk_regmap _name##_ao = { \
|
||||
.data = &(struct clk_regmap_gate_data) { \
|
||||
@ -96,7 +20,7 @@ static struct clk_regmap _name##_ao = { \
|
||||
.ops = &clk_regmap_gate_ops, \
|
||||
.parent_names = (const char *[]){ "clk81" }, \
|
||||
.num_parents = 1, \
|
||||
.flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \
|
||||
.flags = CLK_IGNORE_UNUSED, \
|
||||
}, \
|
||||
}
|
||||
|
||||
@ -117,7 +41,7 @@ static struct aoclk_cec_32k cec_32k_ao = {
|
||||
},
|
||||
};
|
||||
|
||||
static unsigned int gxbb_aoclk_reset[] = {
|
||||
static const unsigned int gxbb_aoclk_reset[] = {
|
||||
[RESET_AO_REMOTE] = 16,
|
||||
[RESET_AO_I2C_MASTER] = 18,
|
||||
[RESET_AO_I2C_SLAVE] = 19,
|
||||
@ -135,7 +59,7 @@ static struct clk_regmap *gxbb_aoclk_gate[] = {
|
||||
[CLKID_AO_IR_BLASTER] = &ir_blaster_ao,
|
||||
};
|
||||
|
||||
static struct clk_hw_onecell_data gxbb_aoclk_onecell_data = {
|
||||
static const struct clk_hw_onecell_data gxbb_aoclk_onecell_data = {
|
||||
.hws = {
|
||||
[CLKID_AO_REMOTE] = &remote_ao.hw,
|
||||
[CLKID_AO_I2C_MASTER] = &i2c_master_ao.hw,
|
||||
@ -145,58 +69,55 @@ static struct clk_hw_onecell_data gxbb_aoclk_onecell_data = {
|
||||
[CLKID_AO_IR_BLASTER] = &ir_blaster_ao.hw,
|
||||
[CLKID_AO_CEC_32K] = &cec_32k_ao.hw,
|
||||
},
|
||||
.num = 7,
|
||||
.num = NR_CLKS,
|
||||
};
|
||||
|
||||
static int gxbb_aoclkc_probe(struct platform_device *pdev)
|
||||
static int gxbb_register_cec_ao_32k(struct platform_device *pdev)
|
||||
{
|
||||
struct gxbb_aoclk_reset_controller *rstc;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct regmap *regmap;
|
||||
int ret, clkid;
|
||||
|
||||
rstc = devm_kzalloc(dev, sizeof(*rstc), GFP_KERNEL);
|
||||
if (!rstc)
|
||||
return -ENOMEM;
|
||||
int ret;
|
||||
|
||||
regmap = syscon_node_to_regmap(of_get_parent(dev->of_node));
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(dev, "failed to get regmap\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Reset Controller */
|
||||
rstc->regmap = regmap;
|
||||
rstc->data = gxbb_aoclk_reset;
|
||||
rstc->reset.ops = &gxbb_aoclk_reset_ops;
|
||||
rstc->reset.nr_resets = ARRAY_SIZE(gxbb_aoclk_reset);
|
||||
rstc->reset.of_node = dev->of_node;
|
||||
ret = devm_reset_controller_register(dev, &rstc->reset);
|
||||
|
||||
/*
|
||||
* Populate regmap and register all clks
|
||||
*/
|
||||
for (clkid = 0; clkid < ARRAY_SIZE(gxbb_aoclk_gate); clkid++) {
|
||||
gxbb_aoclk_gate[clkid]->map = regmap;
|
||||
|
||||
ret = devm_clk_hw_register(dev,
|
||||
gxbb_aoclk_onecell_data.hws[clkid]);
|
||||
if (ret)
|
||||
return ret;
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
/* Specific clocks */
|
||||
cec_32k_ao.regmap = regmap;
|
||||
ret = devm_clk_hw_register(dev, &cec_32k_ao.hw);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "clk cec_32k_ao register failed.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct meson_aoclk_data gxbb_aoclkc_data = {
|
||||
.reset_reg = AO_RTI_GEN_CNTL_REG0,
|
||||
.num_reset = ARRAY_SIZE(gxbb_aoclk_reset),
|
||||
.reset = gxbb_aoclk_reset,
|
||||
.num_clks = ARRAY_SIZE(gxbb_aoclk_gate),
|
||||
.clks = gxbb_aoclk_gate,
|
||||
.hw_data = &gxbb_aoclk_onecell_data,
|
||||
};
|
||||
|
||||
static int gxbb_aoclkc_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret = gxbb_register_cec_ao_32k(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
|
||||
&gxbb_aoclk_onecell_data);
|
||||
return meson_aoclkc_probe(pdev);
|
||||
}
|
||||
|
||||
static const struct of_device_id gxbb_aoclkc_match_table[] = {
|
||||
{ .compatible = "amlogic,meson-gx-aoclkc" },
|
||||
{
|
||||
.compatible = "amlogic,meson-gx-aoclkc",
|
||||
.data = &gxbb_aoclkc_data,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -1,13 +1,14 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (c) 2017 BayLibre, SAS
|
||||
* Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __GXBB_AOCLKC_H
|
||||
#define __GXBB_AOCLKC_H
|
||||
|
||||
#define NR_CLKS 7
|
||||
|
||||
/* AO Configuration Clock registers offsets */
|
||||
#define AO_RTI_PWR_CNTL_REG1 0x0c
|
||||
#define AO_RTI_PWR_CNTL_REG0 0x10
|
||||
@ -26,4 +27,7 @@ struct aoclk_cec_32k {
|
||||
|
||||
extern const struct clk_ops meson_aoclk_cec_32k_ops;
|
||||
|
||||
#include <dt-bindings/clock/gxbb-aoclkc.h>
|
||||
#include <dt-bindings/reset/gxbb-aoclkc.h>
|
||||
|
||||
#endif /* __GXBB_AOCLKC_H */
|
||||
|
@ -1,20 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* AmLogic S905 / GXBB Clock Controller Driver
|
||||
*
|
||||
* Copyright (c) 2016 AmLogic, Inc.
|
||||
* Michael Turquette <mturquette@baylibre.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
@ -1543,6 +1530,102 @@ static struct clk_regmap gxbb_vapb = {
|
||||
},
|
||||
};
|
||||
|
||||
/* VDEC clocks */
|
||||
|
||||
static const char * const gxbb_vdec_parent_names[] = {
|
||||
"fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7"
|
||||
};
|
||||
|
||||
static struct clk_regmap gxbb_vdec_1_sel = {
|
||||
.data = &(struct clk_regmap_mux_data){
|
||||
.offset = HHI_VDEC_CLK_CNTL,
|
||||
.mask = 0x3,
|
||||
.shift = 9,
|
||||
.flags = CLK_MUX_ROUND_CLOSEST,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vdec_1_sel",
|
||||
.ops = &clk_regmap_mux_ops,
|
||||
.parent_names = gxbb_vdec_parent_names,
|
||||
.num_parents = ARRAY_SIZE(gxbb_vdec_parent_names),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap gxbb_vdec_1_div = {
|
||||
.data = &(struct clk_regmap_div_data){
|
||||
.offset = HHI_VDEC_CLK_CNTL,
|
||||
.shift = 0,
|
||||
.width = 7,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vdec_1_div",
|
||||
.ops = &clk_regmap_divider_ops,
|
||||
.parent_names = (const char *[]){ "vdec_1_sel" },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap gxbb_vdec_1 = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VDEC_CLK_CNTL,
|
||||
.bit_idx = 8,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vdec_1",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_names = (const char *[]){ "vdec_1_div" },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap gxbb_vdec_hevc_sel = {
|
||||
.data = &(struct clk_regmap_mux_data){
|
||||
.offset = HHI_VDEC2_CLK_CNTL,
|
||||
.mask = 0x3,
|
||||
.shift = 25,
|
||||
.flags = CLK_MUX_ROUND_CLOSEST,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vdec_hevc_sel",
|
||||
.ops = &clk_regmap_mux_ops,
|
||||
.parent_names = gxbb_vdec_parent_names,
|
||||
.num_parents = ARRAY_SIZE(gxbb_vdec_parent_names),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap gxbb_vdec_hevc_div = {
|
||||
.data = &(struct clk_regmap_div_data){
|
||||
.offset = HHI_VDEC2_CLK_CNTL,
|
||||
.shift = 16,
|
||||
.width = 7,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "vdec_hevc_div",
|
||||
.ops = &clk_regmap_divider_ops,
|
||||
.parent_names = (const char *[]){ "vdec_hevc_sel" },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap gxbb_vdec_hevc = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = HHI_VDEC2_CLK_CNTL,
|
||||
.bit_idx = 24,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "vdec_hevc",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_names = (const char *[]){ "vdec_hevc_div" },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
/* Everything Else (EE) domain gates */
|
||||
static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0);
|
||||
static MESON_GATE(gxbb_dos, HHI_GCLK_MPEG0, 1);
|
||||
@ -1786,6 +1869,12 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = {
|
||||
[CLKID_FCLK_DIV4_DIV] = &gxbb_fclk_div4_div.hw,
|
||||
[CLKID_FCLK_DIV5_DIV] = &gxbb_fclk_div5_div.hw,
|
||||
[CLKID_FCLK_DIV7_DIV] = &gxbb_fclk_div7_div.hw,
|
||||
[CLKID_VDEC_1_SEL] = &gxbb_vdec_1_sel.hw,
|
||||
[CLKID_VDEC_1_DIV] = &gxbb_vdec_1_div.hw,
|
||||
[CLKID_VDEC_1] = &gxbb_vdec_1.hw,
|
||||
[CLKID_VDEC_HEVC_SEL] = &gxbb_vdec_hevc_sel.hw,
|
||||
[CLKID_VDEC_HEVC_DIV] = &gxbb_vdec_hevc_div.hw,
|
||||
[CLKID_VDEC_HEVC] = &gxbb_vdec_hevc.hw,
|
||||
[NR_CLKS] = NULL,
|
||||
},
|
||||
.num = NR_CLKS,
|
||||
@ -1942,6 +2031,12 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = {
|
||||
[CLKID_FCLK_DIV4_DIV] = &gxbb_fclk_div4_div.hw,
|
||||
[CLKID_FCLK_DIV5_DIV] = &gxbb_fclk_div5_div.hw,
|
||||
[CLKID_FCLK_DIV7_DIV] = &gxbb_fclk_div7_div.hw,
|
||||
[CLKID_VDEC_1_SEL] = &gxbb_vdec_1_sel.hw,
|
||||
[CLKID_VDEC_1_DIV] = &gxbb_vdec_1_div.hw,
|
||||
[CLKID_VDEC_1] = &gxbb_vdec_1.hw,
|
||||
[CLKID_VDEC_HEVC_SEL] = &gxbb_vdec_hevc_sel.hw,
|
||||
[CLKID_VDEC_HEVC_DIV] = &gxbb_vdec_hevc_div.hw,
|
||||
[CLKID_VDEC_HEVC] = &gxbb_vdec_hevc.hw,
|
||||
[NR_CLKS] = NULL,
|
||||
},
|
||||
.num = NR_CLKS,
|
||||
@ -2100,6 +2195,12 @@ static struct clk_regmap *const gx_clk_regmaps[] = {
|
||||
&gxbb_fclk_div4,
|
||||
&gxbb_fclk_div5,
|
||||
&gxbb_fclk_div7,
|
||||
&gxbb_vdec_1_sel,
|
||||
&gxbb_vdec_1_div,
|
||||
&gxbb_vdec_1,
|
||||
&gxbb_vdec_hevc_sel,
|
||||
&gxbb_vdec_hevc_div,
|
||||
&gxbb_vdec_hevc,
|
||||
};
|
||||
|
||||
struct clkc_data {
|
||||
|
@ -1,57 +1,7 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
|
||||
/*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright (c) 2016 AmLogic, Inc.
|
||||
* Author: Michael Turquette <mturquette@baylibre.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* The full GNU General Public License is included in this distribution
|
||||
* in the file called COPYING
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (c) 2016 BayLibre, Inc.
|
||||
* Author: Michael Turquette <mturquette@baylibre.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __GXBB_H
|
||||
@ -204,8 +154,12 @@
|
||||
#define CLKID_FCLK_DIV4_DIV 148
|
||||
#define CLKID_FCLK_DIV5_DIV 149
|
||||
#define CLKID_FCLK_DIV7_DIV 150
|
||||
#define CLKID_VDEC_1_SEL 151
|
||||
#define CLKID_VDEC_1_DIV 152
|
||||
#define CLKID_VDEC_HEVC_SEL 154
|
||||
#define CLKID_VDEC_HEVC_DIV 155
|
||||
|
||||
#define NR_CLKS 151
|
||||
#define NR_CLKS 157
|
||||
|
||||
/* include the CLKIDs that have been made part of the DT binding */
|
||||
#include <dt-bindings/clock/gxbb-clkc.h>
|
||||
|
81
drivers/clk/meson/meson-aoclk.c
Normal file
81
drivers/clk/meson/meson-aoclk.c
Normal file
@ -0,0 +1,81 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Amlogic Meson-AXG Clock Controller Driver
|
||||
*
|
||||
* Copyright (c) 2016 BayLibre, SAS.
|
||||
* Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||
*
|
||||
* Copyright (c) 2018 Amlogic, inc.
|
||||
* Author: Qiufang Dai <qiufang.dai@amlogic.com>
|
||||
* Author: Yixun Lan <yixun.lan@amlogic.com>
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/of_device.h>
|
||||
#include "clk-regmap.h"
|
||||
#include "meson-aoclk.h"
|
||||
|
||||
static int meson_aoclk_do_reset(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct meson_aoclk_reset_controller *rstc =
|
||||
container_of(rcdev, struct meson_aoclk_reset_controller, reset);
|
||||
|
||||
return regmap_write(rstc->regmap, rstc->data->reset_reg,
|
||||
BIT(rstc->data->reset[id]));
|
||||
}
|
||||
|
||||
static const struct reset_control_ops meson_aoclk_reset_ops = {
|
||||
.reset = meson_aoclk_do_reset,
|
||||
};
|
||||
|
||||
int meson_aoclkc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct meson_aoclk_reset_controller *rstc;
|
||||
struct meson_aoclk_data *data;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct regmap *regmap;
|
||||
int ret, clkid;
|
||||
|
||||
data = (struct meson_aoclk_data *) of_device_get_match_data(dev);
|
||||
if (!data)
|
||||
return -ENODEV;
|
||||
|
||||
rstc = devm_kzalloc(dev, sizeof(*rstc), GFP_KERNEL);
|
||||
if (!rstc)
|
||||
return -ENOMEM;
|
||||
|
||||
regmap = syscon_node_to_regmap(of_get_parent(dev->of_node));
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(dev, "failed to get regmap\n");
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
/* Reset Controller */
|
||||
rstc->data = data;
|
||||
rstc->regmap = regmap;
|
||||
rstc->reset.ops = &meson_aoclk_reset_ops;
|
||||
rstc->reset.nr_resets = data->num_reset,
|
||||
rstc->reset.of_node = dev->of_node;
|
||||
ret = devm_reset_controller_register(dev, &rstc->reset);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register reset controller\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Populate regmap and register all clks
|
||||
*/
|
||||
for (clkid = 0; clkid < data->num_clks; clkid++) {
|
||||
data->clks[clkid]->map = regmap;
|
||||
|
||||
ret = devm_clk_hw_register(dev, data->hw_data->hws[clkid]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
|
||||
(void *) data->hw_data);
|
||||
}
|
34
drivers/clk/meson/meson-aoclk.h
Normal file
34
drivers/clk/meson/meson-aoclk.h
Normal file
@ -0,0 +1,34 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
|
||||
/*
|
||||
* Copyright (c) 2017 BayLibre, SAS
|
||||
* Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||
*
|
||||
* Copyright (c) 2018 Amlogic, inc.
|
||||
* Author: Qiufang Dai <qiufang.dai@amlogic.com>
|
||||
* Author: Yixun Lan <yixun.lan@amlogic.com>
|
||||
*/
|
||||
|
||||
#ifndef __MESON_AOCLK_H__
|
||||
#define __MESON_AOCLK_H__
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include "clk-regmap.h"
|
||||
|
||||
struct meson_aoclk_data {
|
||||
const unsigned int reset_reg;
|
||||
const int num_reset;
|
||||
const unsigned int *reset;
|
||||
int num_clks;
|
||||
struct clk_regmap **clks;
|
||||
const struct clk_hw_onecell_data *hw_data;
|
||||
};
|
||||
|
||||
struct meson_aoclk_reset_controller {
|
||||
struct reset_controller_dev reset;
|
||||
const struct meson_aoclk_data *data;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
int meson_aoclkc_probe(struct platform_device *pdev);
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user