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:
Linus Torvalds 2018-06-09 12:06:24 -07:00
commit 6419945e33
183 changed files with 13843 additions and 1313 deletions

View File

@ -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>;
};

View 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>;
};

View File

@ -9,6 +9,7 @@ Required Properties:
- GXBB (S905) : "amlogic,meson-gxbb-aoclkc" - GXBB (S905) : "amlogic,meson-gxbb-aoclkc"
- GXL (S905X, S905D) : "amlogic,meson-gxl-aoclkc" - GXL (S905X, S905D) : "amlogic,meson-gxl-aoclkc"
- GXM (S912) : "amlogic,meson-gxm-aoclkc" - GXM (S912) : "amlogic,meson-gxm-aoclkc"
- AXG (A113D, A113X) : "amlogic,meson-axg-aoclkc"
followed by the common "amlogic,meson-gx-aoclkc" followed by the common "amlogic,meson-gx-aoclkc"
- #clock-cells: should be 1. - #clock-cells: should be 1.

View File

@ -276,36 +276,38 @@ These clock IDs are defined in:
clk_ts_500_ref genpll2 2 BCM_SR_GENPLL2_TS_500_REF_CLK 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_125_nitro genpll2 3 BCM_SR_GENPLL2_125_NITRO_CLK
clk_chimp genpll2 4 BCM_SR_GENPLL2_CHIMP_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 genpll3 crystal 0 BCM_SR_GENPLL3
clk_hsls genpll3 1 BCM_SR_GENPLL3_HSLS_CLK clk_hsls genpll3 1 BCM_SR_GENPLL3_HSLS_CLK
clk_sdio genpll3 2 BCM_SR_GENPLL3_SDIO_CLK clk_sdio genpll3 2 BCM_SR_GENPLL3_SDIO_CLK
genpll4 crystal 0 BCM_SR_GENPLL4 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 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_chclk_fs4 genpll4 4 BCM_SR_GENPLL4_CHCLK_FS4_CLK
clk_bridge_fscpu genpll4 5 BCM_SR_GENPLL4_BRIDGE_FSCPU_CLK clk_bridge_fscpu genpll4 5 BCM_SR_GENPLL4_BRIDGE_FSCPU_CLK
genpll5 crystal 0 BCM_SR_GENPLL5 genpll5 crystal 0 BCM_SR_GENPLL5
fs4_hf_clk genpll5 1 BCM_SR_GENPLL5_FS4_HF_CLK clk_fs4_hf genpll5 1 BCM_SR_GENPLL5_FS4_HF_CLK
crypto_ae_clk genpll5 2 BCM_SR_GENPLL5_CRYPTO_AE_CLK clk_crypto_ae genpll5 2 BCM_SR_GENPLL5_CRYPTO_AE_CLK
raid_ae_clk genpll5 3 BCM_SR_GENPLL5_RAID_AE_CLK clk_raid_ae genpll5 3 BCM_SR_GENPLL5_RAID_AE_CLK
genpll6 crystal 0 BCM_SR_GENPLL6 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 lcpll0 crystal 0 BCM_SR_LCPLL0
clk_sata_refp lcpll0 1 BCM_SR_LCPLL0_SATA_REFP_CLK clk_sata_refp lcpll0 1 BCM_SR_LCPLL0_SATA_REFP_CLK
clk_sata_refn lcpll0 2 BCM_SR_LCPLL0_SATA_REFN_CLK clk_sata_refn lcpll0 2 BCM_SR_LCPLL0_SATA_REFN_CLK
clk_usb_ref lcpll0 3 BCM_SR_LCPLL0_USB_REF_CLK clk_sata_350 lcpll0 3 BCM_SR_LCPLL0_SATA_350_CLK
sata_refpn lcpll0 3 BCM_SR_LCPLL0_SATA_REFPN_CLK clk_sata_500 lcpll0 4 BCM_SR_LCPLL0_SATA_500_CLK
lcpll1 crystal 0 BCM_SR_LCPLL1 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 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

View 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";
};

View File

@ -17,7 +17,9 @@ Required properties :
"qcom,gcc-msm8974pro-ac" "qcom,gcc-msm8974pro-ac"
"qcom,gcc-msm8994" "qcom,gcc-msm8994"
"qcom,gcc-msm8996" "qcom,gcc-msm8996"
"qcom,gcc-msm8998"
"qcom,gcc-mdm9615" "qcom,gcc-mdm9615"
"qcom,gcc-sdm845"
- reg : shall contain base register location and length - reg : shall contain base register location and length
- #clock-cells : shall contain 1 - #clock-cells : shall contain 1

View 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>;
};
};

View 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>;
};

View File

@ -15,6 +15,7 @@ Required Properties:
- compatible: Must be one of: - compatible: Must be one of:
- "renesas,r8a7743-cpg-mssr" for the r8a7743 SoC (RZ/G1M) - "renesas,r8a7743-cpg-mssr" for the r8a7743 SoC (RZ/G1M)
- "renesas,r8a7745-cpg-mssr" for the r8a7745 SoC (RZ/G1E) - "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,r8a7790-cpg-mssr" for the r8a7790 SoC (R-Car H2)
- "renesas,r8a7791-cpg-mssr" for the r8a7791 SoC (R-Car M2-W) - "renesas,r8a7791-cpg-mssr" for the r8a7791 SoC (R-Car M2-W)
- "renesas,r8a7792-cpg-mssr" for the r8a7792 SoC (R-Car V2H) - "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,r8a77965-cpg-mssr" for the r8a77965 SoC (R-Car M3-N)
- "renesas,r8a77970-cpg-mssr" for the r8a77970 SoC (R-Car V3M) - "renesas,r8a77970-cpg-mssr" for the r8a77970 SoC (R-Car V3M)
- "renesas,r8a77980-cpg-mssr" for the r8a77980 SoC (R-Car V3H) - "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) - "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 - 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 - clocks: References to external parent clocks, one entry for each entry in
clock-names clock-names
- clock-names: List of external parent clock names. Valid names are: - clock-names: List of external parent clock names. Valid names are:
- "extal" (r8a7743, r8a7745, r8a7790, r8a7791, r8a7792, r8a7793, r8a7794, - "extal" (r8a7743, r8a7745, r8a77470, r8a7790, r8a7791, r8a7792,
r8a7795, r8a7796, r8a77965, r8a77970, r8a77980, r8a77995) r8a7793, r8a7794, r8a7795, r8a7796, r8a77965, r8a77970,
r8a77980, r8a77990, r8a77995)
- "extalr" (r8a7795, r8a7796, r8a77965, r8a77970, r8a77980) - "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 - #clock-cells: Must be 2
- For CPG core clocks, the two clock specifier cells must be "CPG_CORE" - For CPG core clocks, the two clock specifier cells must be "CPG_CORE"

View File

@ -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>;
};

View File

@ -21,6 +21,7 @@ Required properties :
- "allwinner,sun50i-a64-r-ccu" - "allwinner,sun50i-a64-r-ccu"
- "allwinner,sun50i-h5-ccu" - "allwinner,sun50i-h5-ccu"
- "allwinner,sun50i-h6-ccu" - "allwinner,sun50i-h6-ccu"
- "allwinner,sun50i-h6-r-ccu"
- "nextthing,gr8-ccu" - "nextthing,gr8-ccu"
- reg: Must contain the registers base address and length - 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: For the main CCU on H6, one more clock is needed:
- "iosc": the SoC's internal frequency oscillator - "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 - "pll-periph": the SoC's peripheral PLL from the main CCU
- "iosc": the SoC's internal frequency oscillator - "iosc": the SoC's internal frequency oscillator

View File

@ -96,7 +96,7 @@ the operations defined in clk-provider.h::
int (*get_phase)(struct clk_hw *hw); int (*get_phase)(struct clk_hw *hw);
int (*set_phase)(struct clk_hw *hw, int degrees); int (*set_phase)(struct clk_hw *hw, int degrees);
void (*init)(struct clk_hw *hw); void (*init)(struct clk_hw *hw);
int (*debug_init)(struct clk_hw *hw, void (*debug_init)(struct clk_hw *hw,
struct dentry *dentry); struct dentry *dentry);
}; };

View File

@ -3587,6 +3587,7 @@ F: drivers/clk/
X: drivers/clk/clkdev.c X: drivers/clk/clkdev.c
F: include/linux/clk-pr* F: include/linux/clk-pr*
F: include/linux/clk/ F: include/linux/clk/
F: include/linux/of_clk.h
COMMON INTERNET FILE SYSTEM (CIFS) COMMON INTERNET FILE SYSTEM (CIFS)
M: Steve French <sfrench@samba.org> M: Steve French <sfrench@samba.org>

View File

@ -120,7 +120,7 @@
<GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 103 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_ENET_AXI_ROOT_CLK>,
<&clks IMX7D_ENET2_TIME_ROOT_CLK>, <&clks IMX7D_ENET2_TIME_ROOT_CLK>,
<&clks IMX7D_PLL_ENET_MAIN_125M_CLK>, <&clks IMX7D_PLL_ENET_MAIN_125M_CLK>,

View File

@ -1092,7 +1092,7 @@
<GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 121 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_ENET_AXI_ROOT_CLK>,
<&clks IMX7D_ENET1_TIME_ROOT_CLK>, <&clks IMX7D_ENET1_TIME_ROOT_CLK>,
<&clks IMX7D_PLL_ENET_MAIN_125M_CLK>, <&clks IMX7D_PLL_ENET_MAIN_125M_CLK>,

View File

@ -277,6 +277,7 @@ config COMMON_CLK_STM32H7
---help--- ---help---
Support for stm32h7 SoC family clocks Support for stm32h7 SoC family clocks
source "drivers/clk/actions/Kconfig"
source "drivers/clk/bcm/Kconfig" source "drivers/clk/bcm/Kconfig"
source "drivers/clk/hisilicon/Kconfig" source "drivers/clk/hisilicon/Kconfig"
source "drivers/clk/imgtec/Kconfig" source "drivers/clk/imgtec/Kconfig"

View File

@ -33,6 +33,7 @@ obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
obj-$(CONFIG_ARCH_NPCM7XX) += clk-npcm7xx.o
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
obj-$(CONFIG_COMMON_CLK_OXNAS) += clk-oxnas.o obj-$(CONFIG_COMMON_CLK_OXNAS) += clk-oxnas.o
obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.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 obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o
# please keep this section sorted lexicographically by directory path name # please keep this section sorted lexicographically by directory path name
obj-y += actions/
obj-$(CONFIG_COMMON_CLK_AT91) += at91/ obj-$(CONFIG_COMMON_CLK_AT91) += at91/
obj-$(CONFIG_ARCH_ARTPEC) += axis/ obj-$(CONFIG_ARCH_ARTPEC) += axis/
obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/ obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/

View 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

View 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

View 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;
}

View 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_ */

View 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,
};

View 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_ */

View 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, &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);
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,
};

View 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_ */

View 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, &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);
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,
};

View 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_ */

View 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_ */

View 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, &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, &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,
};

View 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_ */

View 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, &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);
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,
};

View 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_ */

View 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, &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, &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);
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,
};

View 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_ */

View 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,
&eth_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] = &eth_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);

View File

@ -132,19 +132,8 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct clk_pll *pll = to_clk_pll(hw); struct clk_pll *pll = to_clk_pll(hw);
unsigned int pllr;
u16 mul;
u8 div;
regmap_read(pll->regmap, PLL_REG(pll->id), &pllr); return (parent_rate / pll->div) * (pll->mul + 1);
div = PLL_DIV(pllr);
mul = PLL_MUL(pllr, pll->layout);
if (!div || !mul)
return 0;
return (parent_rate / div) * (mul + 1);
} }
static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate, static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate,

View File

@ -394,25 +394,21 @@ out:
return count * 1000; 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 debugfs_reg32 *regs, size_t nregs,
struct dentry *dentry) struct dentry *dentry)
{ {
struct dentry *regdump;
struct debugfs_regset32 *regset; struct debugfs_regset32 *regset;
regset = devm_kzalloc(cprman->dev, sizeof(*regset), GFP_KERNEL); regset = devm_kzalloc(cprman->dev, sizeof(*regset), GFP_KERNEL);
if (!regset) if (!regset)
return -ENOMEM; return;
regset->regs = regs; regset->regs = regs;
regset->nregs = nregs; regset->nregs = nregs;
regset->base = cprman->regs + base; regset->base = cprman->regs + base;
regdump = debugfs_create_regset32("regdump", S_IRUGO, dentry, debugfs_create_regset32("regdump", S_IRUGO, dentry, regset);
regset);
return regdump ? 0 : -ENOMEM;
} }
struct bcm2835_pll_data { struct bcm2835_pll_data {
@ -730,7 +726,7 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw,
return 0; 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 dentry *dentry)
{ {
struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); 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); regs = devm_kzalloc(cprman->dev, 7 * sizeof(*regs), GFP_KERNEL);
if (!regs) if (!regs)
return -ENOMEM; return;
regs[0].name = "cm_ctrl"; regs[0].name = "cm_ctrl";
regs[0].offset = data->cm_ctrl_reg; 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].name = "ana3";
regs[6].offset = data->ana_reg_base + 3 * 4; 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 = { 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; return 0;
} }
static int bcm2835_pll_divider_debug_init(struct clk_hw *hw, static void bcm2835_pll_divider_debug_init(struct clk_hw *hw,
struct dentry *dentry) struct dentry *dentry)
{ {
struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw); struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw);
struct bcm2835_cprman *cprman = divider->cprman; 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); regs = devm_kzalloc(cprman->dev, 7 * sizeof(*regs), GFP_KERNEL);
if (!regs) if (!regs)
return -ENOMEM; return;
regs[0].name = "cm"; regs[0].name = "cm";
regs[0].offset = data->cm_reg; regs[0].offset = data->cm_reg;
regs[1].name = "a2w"; regs[1].name = "a2w";
regs[1].offset = data->a2w_reg; 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 = { 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 dentry *dentry)
{ {
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
struct bcm2835_cprman *cprman = clock->cprman; struct bcm2835_cprman *cprman = clock->cprman;
const struct bcm2835_clock_data *data = clock->data; const struct bcm2835_clock_data *data = clock->data;
return bcm2835_debugfs_regset( bcm2835_debugfs_regset(cprman, data->ctl_reg,
cprman, data->ctl_reg,
bcm2835_debugfs_clock_reg32, bcm2835_debugfs_clock_reg32,
ARRAY_SIZE(bcm2835_debugfs_clock_reg32), ARRAY_SIZE(bcm2835_debugfs_clock_reg32),
dentry); dentry);
@ -1395,7 +1390,7 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
struct bcm2835_clock *clock; struct bcm2835_clock *clock;
struct clk_init_data init; struct clk_init_data init;
const char *parents[1 << CM_SRC_BITS]; const char *parents[1 << CM_SRC_BITS];
size_t i, j; size_t i;
int ret; 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++) { for (i = 0; i < data->num_mux_parents; i++) {
parents[i] = data->parents[i]; parents[i] = data->parents[i];
for (j = 0; j < ARRAY_SIZE(cprman_parent_names); j++) { ret = match_string(cprman_parent_names,
if (strcmp(parents[i], cprman_parent_names[j]) == 0) { ARRAY_SIZE(cprman_parent_names),
parents[i] = cprman->real_parent_names[j]; parents[i]);
break; if (ret >= 0)
} parents[i] = cprman->real_parent_names[ret];
}
} }
memset(&init, 0, sizeof(init)); memset(&init, 0, sizeof(init));

View File

@ -56,8 +56,8 @@ static const struct iproc_pll_ctrl sr_genpll0 = {
}; };
static const struct iproc_clk_ctrl sr_genpll0_clk[] = { static const struct iproc_clk_ctrl sr_genpll0_clk[] = {
[BCM_SR_GENPLL0_SATA_CLK] = { [BCM_SR_GENPLL0_125M_CLK] = {
.channel = BCM_SR_GENPLL0_SATA_CLK, .channel = BCM_SR_GENPLL0_125M_CLK,
.flags = IPROC_CLK_AON, .flags = IPROC_CLK_AON,
.enable = ENABLE_VAL(0x4, 6, 0, 12), .enable = ENABLE_VAL(0x4, 6, 0, 12),
.mdiv = REG_VAL(0x18, 0, 9), .mdiv = REG_VAL(0x18, 0, 9),
@ -102,6 +102,65 @@ static int sr_genpll0_clk_init(struct platform_device *pdev)
return 0; 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 = { static const struct iproc_pll_ctrl sr_genpll3 = {
.flags = IPROC_CLK_AON | IPROC_CLK_PLL_HAS_NDIV_FRAC | .flags = IPROC_CLK_AON | IPROC_CLK_PLL_HAS_NDIV_FRAC |
IPROC_CLK_PLL_NEEDS_SW_CFG, 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), .enable = ENABLE_VAL(0x4, 6, 0, 12),
.mdiv = REG_VAL(0x18, 0, 9), .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) 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[] = { static const struct iproc_clk_ctrl sr_genpll5_clk[] = {
[BCM_SR_GENPLL5_FS_CLK] = { [BCM_SR_GENPLL5_FS4_HF_CLK] = {
.channel = BCM_SR_GENPLL5_FS_CLK, .channel = BCM_SR_GENPLL5_FS4_HF_CLK,
.flags = IPROC_CLK_AON,
.enable = ENABLE_VAL(0x4, 6, 0, 12), .enable = ENABLE_VAL(0x4, 6, 0, 12),
.mdiv = REG_VAL(0x18, 0, 9), .mdiv = REG_VAL(0x18, 0, 9),
}, },
[BCM_SR_GENPLL5_SPU_CLK] = { [BCM_SR_GENPLL5_CRYPTO_AE_CLK] = {
.channel = BCM_SR_GENPLL5_SPU_CLK, .channel = BCM_SR_GENPLL5_CRYPTO_AE_CLK,
.flags = IPROC_CLK_AON, .enable = ENABLE_VAL(0x4, 7, 1, 12),
.enable = ENABLE_VAL(0x4, 6, 0, 12),
.mdiv = REG_VAL(0x18, 10, 9), .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) 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[] = { static const struct iproc_clk_ctrl sr_lcpll0_clk[] = {
[BCM_SR_LCPLL0_SATA_REF_CLK] = { [BCM_SR_LCPLL0_SATA_REFP_CLK] = {
.channel = BCM_SR_LCPLL0_SATA_REF_CLK, .channel = BCM_SR_LCPLL0_SATA_REFP_CLK,
.flags = IPROC_CLK_AON, .flags = IPROC_CLK_AON,
.enable = ENABLE_VAL(0x0, 7, 1, 13), .enable = ENABLE_VAL(0x0, 7, 1, 13),
.mdiv = REG_VAL(0x14, 0, 9), .mdiv = REG_VAL(0x14, 0, 9),
}, },
[BCM_SR_LCPLL0_USB_REF_CLK] = { [BCM_SR_LCPLL0_SATA_REFN_CLK] = {
.channel = BCM_SR_LCPLL0_USB_REF_CLK, .channel = BCM_SR_LCPLL0_SATA_REFN_CLK,
.flags = IPROC_CLK_AON, .flags = IPROC_CLK_AON,
.enable = ENABLE_VAL(0x0, 8, 2, 14), .enable = ENABLE_VAL(0x0, 8, 2, 14),
.mdiv = REG_VAL(0x14, 10, 9), .mdiv = REG_VAL(0x14, 10, 9),
}, },
[BCM_SR_LCPLL0_SATA_REFPN_CLK] = { [BCM_SR_LCPLL0_SATA_350_CLK] = {
.channel = BCM_SR_LCPLL0_SATA_REFPN_CLK, .channel = BCM_SR_LCPLL0_SATA_350_CLK,
.flags = IPROC_CLK_AON, .flags = IPROC_CLK_AON,
.enable = ENABLE_VAL(0x0, 9, 3, 15), .enable = ENABLE_VAL(0x0, 9, 3, 15),
.mdiv = REG_VAL(0x14, 20, 9), .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) 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), .enable = ENABLE_VAL(0x0, 7, 1, 13),
.mdiv = REG_VAL(0x14, 0, 9), .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) 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[] = { static const struct of_device_id sr_clk_dt_ids[] = {
{ .compatible = "brcm,sr-genpll0", .data = sr_genpll0_clk_init }, { .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-genpll4", .data = sr_genpll4_clk_init },
{ .compatible = "brcm,sr-genpll5", .data = sr_genpll5_clk_init }, { .compatible = "brcm,sr-genpll5", .data = sr_genpll5_clk_init },
{ .compatible = "brcm,sr-lcpll0", .data = sr_lcpll0_clk_init }, { .compatible = "brcm,sr-lcpll0", .data = sr_lcpll0_clk_init },

View File

@ -1,20 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* Copyright (c) 2014 Marvell Technology Group Ltd. * Copyright (c) 2014 Marvell Technology Group Ltd.
* *
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Alexandre Belloni <alexandre.belloni@free-electrons.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/clk-provider.h>
#include <linux/io.h> #include <linux/io.h>

View File

@ -1,20 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* Copyright (c) 2014 Marvell Technology Group Ltd. * Copyright (c) 2014 Marvell Technology Group Ltd.
* *
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Alexandre Belloni <alexandre.belloni@free-electrons.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 #ifndef __BERLIN2_AVPLL_H
#define __BERLIN2_AVPLL_H #define __BERLIN2_AVPLL_H

View File

@ -1,20 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* Copyright (c) 2014 Marvell Technology Group Ltd. * Copyright (c) 2014 Marvell Technology Group Ltd.
* *
* Alexandre Belloni <alexandre.belloni@free-electrons.com> * Alexandre Belloni <alexandre.belloni@free-electrons.com>
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.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/bitops.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>

View File

@ -1,20 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* Copyright (c) 2014 Marvell Technology Group Ltd. * Copyright (c) 2014 Marvell Technology Group Ltd.
* *
* Alexandre Belloni <alexandre.belloni@free-electrons.com> * Alexandre Belloni <alexandre.belloni@free-electrons.com>
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.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 #ifndef __BERLIN2_DIV_H
#define __BERLIN2_DIV_H #define __BERLIN2_DIV_H

View File

@ -1,20 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* Copyright (c) 2014 Marvell Technology Group Ltd. * Copyright (c) 2014 Marvell Technology Group Ltd.
* *
* Alexandre Belloni <alexandre.belloni@free-electrons.com> * Alexandre Belloni <alexandre.belloni@free-electrons.com>
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.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/clk-provider.h>
#include <linux/io.h> #include <linux/io.h>

View File

@ -1,20 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* Copyright (c) 2014 Marvell Technology Group Ltd. * Copyright (c) 2014 Marvell Technology Group Ltd.
* *
* Alexandre Belloni <alexandre.belloni@free-electrons.com> * Alexandre Belloni <alexandre.belloni@free-electrons.com>
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.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 #ifndef __BERLIN2_PLL_H
#define __BERLIN2_PLL_H #define __BERLIN2_PLL_H

View File

@ -1,20 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* Copyright (c) 2014 Marvell Technology Group Ltd. * Copyright (c) 2014 Marvell Technology Group Ltd.
* *
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Alexandre Belloni <alexandre.belloni@free-electrons.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> #include <linux/clk.h>

View File

@ -1,20 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* Copyright (c) 2014 Marvell Technology Group Ltd. * Copyright (c) 2014 Marvell Technology Group Ltd.
* *
* Alexandre Belloni <alexandre.belloni@free-electrons.com> * Alexandre Belloni <alexandre.belloni@free-electrons.com>
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.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> #include <linux/clk.h>

View File

@ -1,20 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* Copyright (c) 2014 Marvell Technology Group Ltd. * Copyright (c) 2014 Marvell Technology Group Ltd.
* *
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Alexandre Belloni <alexandre.belloni@free-electrons.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 #ifndef __BERLIN2_COMMON_H
#define __BERLIN2_COMMON_H #define __BERLIN2_COMMON_H

View File

@ -14,7 +14,9 @@
#include <dt-bindings/clock/aspeed-clock.h> #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_RESET_CTRL 0x04
#define ASPEED_CLK_SELECTION 0x08 #define ASPEED_CLK_SELECTION 0x08
@ -30,6 +32,7 @@
#define CLKIN_25MHZ_EN BIT(23) #define CLKIN_25MHZ_EN BIT(23)
#define AST2400_CLK_SOURCE_SEL BIT(18) #define AST2400_CLK_SOURCE_SEL BIT(18)
#define ASPEED_CLK_SELECTION_2 0xd8 #define ASPEED_CLK_SELECTION_2 0xd8
#define ASPEED_RESET_CTRL2 0xd4
/* Globally visible clocks */ /* Globally visible clocks */
static DEFINE_SPINLOCK(aspeed_clk_lock); 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_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_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_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_DCLK] = { 5, -1, "dclk-gate", NULL, 0 }, /* DAC */
[ASPEED_CLK_GATE_REFCLK] = { 6, -1, "refclk-gate", "clkin", CLK_IS_CRITICAL }, [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 */ [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) #define to_aspeed_reset(p) container_of((p), struct aspeed_reset, rcdev)
static const u8 aspeed_resets[] = { static const u8 aspeed_resets[] = {
/* SCU04 resets */
[ASPEED_RESET_XDMA] = 25, [ASPEED_RESET_XDMA] = 25,
[ASPEED_RESET_MCTP] = 24, [ASPEED_RESET_MCTP] = 24,
[ASPEED_RESET_ADC] = 23, [ASPEED_RESET_ADC] = 23,
[ASPEED_RESET_JTAG_MASTER] = 22, [ASPEED_RESET_JTAG_MASTER] = 22,
[ASPEED_RESET_MIC] = 18, [ASPEED_RESET_MIC] = 18,
[ASPEED_RESET_PWM] = 9, [ASPEED_RESET_PWM] = 9,
[ASPEED_RESET_PCIVGA] = 8, [ASPEED_RESET_PECI] = 10,
[ASPEED_RESET_I2C] = 2, [ASPEED_RESET_I2C] = 2,
[ASPEED_RESET_AHB] = 1, [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, static int aspeed_reset_deassert(struct reset_controller_dev *rcdev,
unsigned long id) unsigned long id)
{ {
struct aspeed_reset *ar = to_aspeed_reset(rcdev); 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, static int aspeed_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id) unsigned long id)
{ {
struct aspeed_reset *ar = to_aspeed_reset(rcdev); 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, static int aspeed_reset_status(struct reset_controller_dev *rcdev,
unsigned long id) unsigned long id)
{ {
struct aspeed_reset *ar = to_aspeed_reset(rcdev); struct aspeed_reset *ar = to_aspeed_reset(rcdev);
u32 val, rst = BIT(aspeed_resets[id]); u32 reg = ASPEED_RESET_CTRL;
int ret; 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) if (ret)
return ret; return ret;
return !!(val & rst); return !!(val & BIT(bit));
} }
static const struct reset_control_ops aspeed_reset_ops = { 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); return PTR_ERR(hw);
aspeed_clk_data->hws[ASPEED_CLK_BCLK] = 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 * TODO: There are a number of clocks that not included in this driver
* as more information is required: * as more information is required:

View File

@ -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); clks[i].clk = clk_get(dev, clks[i].id);
if (IS_ERR(clks[i].clk)) { if (IS_ERR(clks[i].clk)) {
ret = PTR_ERR(clks[i].clk); ret = PTR_ERR(clks[i].clk);
dev_err(dev, "Failed to get clk '%s': %d\n", if (ret != -EPROBE_DEFER)
clks[i].id, ret); dev_err(dev, "Failed to get clk '%s': %d\n",
clks[i].id, ret);
clks[i].clk = NULL; clks[i].clk = NULL;
goto err; goto err;
} }

656
drivers/clk/clk-npcm7xx.c Normal file
View 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);

View File

@ -207,6 +207,7 @@ static int si544_calc_muldiv(struct clk_si544_muldiv *settings,
/* And the fractional bits using the remainder */ /* And the fractional bits using the remainder */
vco = (u64)tmp << 32; vco = (u64)tmp << 32;
vco += FXO / 2; /* Round to nearest multiple */
do_div(vco, FXO); do_div(vco, FXO);
settings->fb_div_frac = vco; settings->fb_div_frac = vco;

View File

@ -579,14 +579,9 @@ clk_stm32_register_gate_ops(struct device *dev,
spinlock_t *lock) spinlock_t *lock)
{ {
struct clk_init_data init = { NULL }; struct clk_init_data init = { NULL };
struct clk_gate *gate;
struct clk_hw *hw; struct clk_hw *hw;
int ret; int ret;
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
if (!gate)
return ERR_PTR(-ENOMEM);
init.name = name; init.name = name;
init.parent_names = &parent_name; init.parent_names = &parent_name;
init.num_parents = 1; init.num_parents = 1;
@ -604,10 +599,8 @@ clk_stm32_register_gate_ops(struct device *dev,
hw->init = &init; hw->init = &init;
ret = clk_hw_register(dev, hw); ret = clk_hw_register(dev, hw);
if (ret) { if (ret)
kfree(gate);
hw = ERR_PTR(ret); hw = ERR_PTR(ret);
}
return hw; return hw;
} }
@ -1988,7 +1981,8 @@ static const struct clock_config stm32mp1_clock_cfg[] = {
_DIV(RCC_MCO2CFGR, 4, 4, 0, NULL)), _DIV(RCC_MCO2CFGR, 4, 4, 0, NULL)),
/* Debug clocks */ /* 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, COMPOSITE(CK_TRACE, "ck_trace", ck_trace_src, CLK_OPS_PARENT_ENABLE,
_GATE(RCC_DBGCFGR, 9, 0), _GATE(RCC_DBGCFGR, 9, 0),

View File

@ -549,7 +549,8 @@ static void clk_core_rate_unprotect(struct clk_core *core)
if (!core) if (!core)
return; return;
if (WARN_ON(core->protect_count == 0)) if (WARN(core->protect_count == 0,
"%s already unprotected\n", core->name))
return; return;
if (--core->protect_count > 0) if (--core->protect_count > 0)
@ -682,16 +683,18 @@ static void clk_core_unprepare(struct clk_core *core)
if (!core) if (!core)
return; return;
if (WARN_ON(core->prepare_count == 0)) if (WARN(core->prepare_count == 0,
"%s already unprepared\n", core->name))
return; 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; return;
if (--core->prepare_count > 0) if (--core->prepare_count > 0)
return; return;
WARN_ON(core->enable_count > 0); WARN(core->enable_count > 0, "Unpreparing enabled %s\n", core->name);
trace_clk_unprepare(core); trace_clk_unprepare(core);
@ -809,10 +812,11 @@ static void clk_core_disable(struct clk_core *core)
if (!core) if (!core)
return; return;
if (WARN_ON(core->enable_count == 0)) if (WARN(core->enable_count == 0, "%s already disabled\n", core->name))
return; 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; return;
if (--core->enable_count > 0) if (--core->enable_count > 0)
@ -867,7 +871,8 @@ static int clk_core_enable(struct clk_core *core)
if (!core) if (!core)
return 0; return 0;
if (WARN_ON(core->prepare_count == 0)) if (WARN(core->prepare_count == 0,
"Enabling unprepared %s\n", core->name))
return -ESHUTDOWN; return -ESHUTDOWN;
if (core->enable_count == 0) { 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) bool clk_has_parent(struct clk *clk, struct clk *parent)
{ {
struct clk_core *core, *parent_core; struct clk_core *core, *parent_core;
unsigned int i;
/* NULL clocks should be nops, so return success if either is NULL. */ /* NULL clocks should be nops, so return success if either is NULL. */
if (!clk || !parent) if (!clk || !parent)
@ -2184,11 +2188,8 @@ bool clk_has_parent(struct clk *clk, struct clk *parent)
if (core->parent == parent_core) if (core->parent == parent_core)
return true; return true;
for (i = 0; i < core->num_parents; i++) return match_string(core->parent_names, core->num_parents,
if (strcmp(core->parent_names[i], parent_core->name) == 0) parent_core->name) >= 0;
return true;
return false;
} }
EXPORT_SYMBOL_GPL(clk_has_parent); 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); 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; struct dentry *root;
int ret = -ENOMEM;
if (!core || !pdentry) { if (!core || !pdentry)
ret = -EINVAL; return;
goto out;
}
d = debugfs_create_dir(core->name, pdentry); root = debugfs_create_dir(core->name, pdentry);
if (!d) core->dentry = root;
goto out;
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 (core->num_parents > 1)
if (!d) debugfs_create_file("clk_possible_parents", 0444, root, core,
goto err_out; &possible_parents_fops);
d = debugfs_create_ulong("clk_accuracy", 0444, core->dentry, if (core->ops->debug_init)
&core->accuracy); core->ops->debug_init(core->hw, core->dentry);
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;
} }
/** /**
@ -2694,17 +2645,13 @@ out:
* initialized. Otherwise it bails out early since the debugfs clk directory * 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. * 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); mutex_lock(&clk_debug_lock);
hlist_add_head(&core->debug_node, &clk_debug_list); hlist_add_head(&core->debug_node, &clk_debug_list);
if (inited) if (inited)
ret = clk_debug_create_one(core, rootdir); clk_debug_create_one(core, rootdir);
mutex_unlock(&clk_debug_lock); 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); 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 * 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) static int __init clk_debug_init(void)
{ {
struct clk_core *core; struct clk_core *core;
struct dentry *d;
rootdir = debugfs_create_dir("clk", NULL); rootdir = debugfs_create_dir("clk", NULL);
if (!rootdir) debugfs_create_file("clk_summary", 0444, rootdir, &all_lists,
return -ENOMEM; &clk_summary_fops);
debugfs_create_file("clk_dump", 0444, rootdir, &all_lists,
d = debugfs_create_file("clk_summary", 0444, rootdir, &all_lists, &clk_dump_fops);
&clk_summary_fops); debugfs_create_file("clk_orphan_summary", 0444, rootdir, &orphan_list,
if (!d) &clk_summary_fops);
return -ENOMEM; debugfs_create_file("clk_orphan_dump", 0444, rootdir, &orphan_list,
&clk_dump_fops);
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;
mutex_lock(&clk_debug_lock); mutex_lock(&clk_debug_lock);
hlist_for_each_entry(core, &clk_debug_list, debug_node) 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); late_initcall(clk_debug_init);
#else #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, static inline void clk_debug_reparent(struct clk_core *core,
struct clk_core *new_parent) 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); EXPORT_SYMBOL_GPL(of_clk_parent_fill);
struct clock_provider { struct clock_provider {
of_clk_init_cb_t clk_init_cb; void (*clk_init_cb)(struct device_node *);
struct device_node *np; struct device_node *np;
struct list_head node; struct list_head node;
}; };

View File

@ -6,6 +6,7 @@
*/ */
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/clk/davinci.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/types.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(6, pll0_sysclk6, pll0_pllen, 5, SYSCLK_FIXED_DIV);
SYSCLK(7, pll0_sysclk7, pll0_pllen, 5, 0); 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; 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 = davinci_pll_sysclk_register(dev, &pll0_sysclk2, base);
clk_register_clkdev(clk, "pll0_sysclk2", "da830-psc0"); clk_register_clkdev(clk, "pll0_sysclk2", "da830-psc0");

View File

@ -7,10 +7,14 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clk/davinci.h>
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/device.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mfd/da8xx-cfgchip.h> #include <linux/mfd/da8xx-cfgchip.h>
#include <linux/mfd/syscon.h>
#include <linux/of_address.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/types.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), .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; 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 = davinci_pll_sysclk_register(dev, &pll0_sysclk1, base);
clk_register_clkdev(clk, "pll0_sysclk1", "da850-psc0"); clk_register_clkdev(clk, "pll0_sysclk1", "da850-psc0");
@ -134,11 +138,22 @@ static const struct davinci_pll_sysclk_info *da850_pll0_sysclk_info[] = {
NULL 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, void __iomem *base;
&da850_pll0_obsclk_info, struct regmap *cfgchip;
da850_pll0_sysclk_info, 7, base);
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 = { 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), .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; 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); davinci_pll_sysclk_register(dev, &pll1_sysclk1, base);
@ -204,9 +219,9 @@ static const struct davinci_pll_sysclk_info *da850_pll1_sysclk_info[] = {
NULL 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_obsclk_info,
da850_pll1_sysclk_info, 3, base); da850_pll1_sysclk_info, 3, base, cfgchip);
} }

View File

@ -6,6 +6,7 @@
*/ */
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/clk/davinci.h>
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/types.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, PLL_POSTDIV_ALWAYS_ENABLED | PLL_POSTDIV_FIXED_DIV,
}; };
SYSCLK(1, pll1_sysclk1, pll1, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED); SYSCLK(1, pll1_sysclk1, pll1_pllen, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
SYSCLK(2, pll1_sysclk2, pll1, 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, 5, SYSCLK_ALWAYS_ENABLED); SYSCLK(3, pll1_sysclk3, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED);
SYSCLK(4, pll1_sysclk4, pll1, 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; 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 = davinci_pll_sysclk_register(dev, &pll1_sysclk1, base);
clk_register_clkdev(clk, "pll1_sysclk1", "dm355-psc"); 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, PLL_POSTDIV_ALWAYS_ENABLED | PLL_POSTDIV_FIXED_DIV,
}; };
SYSCLK(1, pll2_sysclk1, pll2, 5, SYSCLK_FIXED_DIV); SYSCLK(1, pll2_sysclk1, pll2_pllen, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
SYSCLK(2, pll2_sysclk2, pll2, 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_sysclk1, base);
davinci_pll_sysclk_register(dev, &pll2_sysclk2, base);
davinci_pll_sysclkbp_clk_register(dev, "pll2_sysclkbp", base); davinci_pll_sysclkbp_clk_register(dev, "pll2_sysclkbp", base);
return 0; return 0;

View File

@ -7,6 +7,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/clk/davinci.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/types.h> #include <linux/types.h>
@ -56,11 +57,11 @@ static const struct davinci_pll_obsclk_info dm365_pll1_obsclk_info = {
.ocsrc_mask = BIT(4), .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; 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 = davinci_pll_sysclk_register(dev, &pll1_sysclk1, base);
clk_register_clkdev(clk, "pll1_sysclk1", "dm365-psc"); 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), .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; 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); davinci_pll_sysclk_register(dev, &pll2_sysclk1, base);

View File

@ -6,6 +6,7 @@
*/ */
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/clk/davinci.h>
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/types.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(3, pll1_sysclk3, pll1_pllen, 4, SYSCLK_FIXED_DIV);
SYSCLK(5, pll1_sysclk5, 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; 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 = davinci_pll_sysclk_register(dev, &pll1_sysclk1, base);
clk_register_clkdev(clk, "pll1_sysclk1", "dm644x-psc"); 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(1, pll2_sysclk1, pll2_pllen, 4, 0);
SYSCLK(2, pll2_sysclk2, 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); davinci_pll_sysclk_register(dev, &pll2_sysclk1, base);

View File

@ -6,6 +6,7 @@
*/ */
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clk/davinci.h>
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/types.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(8, pll1_sysclk8, pll1_pllen, 4, 0);
SYSCLK(9, pll1_sysclk9, 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; 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 = davinci_pll_sysclk_register(dev, &pll1_sysclk1, base);
clk_register_clkdev(clk, "pll1_sysclk1", "dm646x-psc"); clk_register_clkdev(clk, "pll1_sysclk1", "dm646x-psc");
@ -72,11 +73,11 @@ static const struct davinci_pll_clk_info dm646x_pll2_info = {
.flags = 0, .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); davinci_pll_sysclk_register(dev, &pll2_sysclk1, base);

View File

@ -11,6 +11,7 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clk/davinci.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/io.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 #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 #else
#define davinci_pll_debug_init NULL #define davinci_pll_debug_init NULL
#endif #endif
@ -223,6 +224,7 @@ static const struct clk_ops dm365_pll_ops = {
/** /**
* davinci_pll_div_register - common *DIV clock implementation * davinci_pll_div_register - common *DIV clock implementation
* @dev: The PLL platform device or NULL
* @name: the clock name * @name: the clock name
* @parent_name: the parent clock name * @parent_name: the parent clock name
* @reg: the *DIV register * @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; const struct clk_ops *divider_ops = &clk_divider_ops;
struct clk_gate *gate; struct clk_gate *gate;
struct clk_divider *divider; 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) if (!gate)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
gate->reg = reg; gate->reg = reg;
gate->bit_idx = DIV_ENABLE_SHIFT; gate->bit_idx = DIV_ENABLE_SHIFT;
divider = devm_kzalloc(dev, sizeof(*divider), GFP_KERNEL); divider = kzalloc(sizeof(*divider), GFP_KERNEL);
if (!divider) if (!divider) {
return ERR_PTR(-ENOMEM); ret = -ENOMEM;
goto err_free_gate;
}
divider->reg = reg; divider->reg = reg;
divider->shift = DIV_RATIO_SHIFT; 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; divider_ops = &clk_divider_ro_ops;
} }
return clk_register_composite(dev, name, parent_names, num_parents, clk = clk_register_composite(dev, name, parent_names, num_parents,
NULL, NULL, &divider->hw, divider_ops, NULL, NULL, &divider->hw, divider_ops,
&gate->hw, &clk_gate_ops, flags); &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 { struct davinci_pllen_clk {
@ -321,36 +340,17 @@ static int davinci_pllen_rate_change(struct notifier_block *nb,
return NOTIFY_OK; 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 = { static struct notifier_block davinci_pllen_notifier = {
.notifier_call = davinci_pllen_rate_change, .notifier_call = davinci_pllen_rate_change,
}; };
/** /**
* davinci_pll_clk_register - Register a PLL clock * davinci_pll_clk_register - Register a PLL clock
* @dev: The PLL platform device or NULL
* @info: The device-specific clock info * @info: The device-specific clock info
* @parent_name: The parent clock name * @parent_name: The parent clock name
* @base: The PLL's memory region * @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. * 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, struct clk *davinci_pll_clk_register(struct device *dev,
const struct davinci_pll_clk_info *info, const struct davinci_pll_clk_info *info,
const char *parent_name, 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 prediv_name[MAX_NAME_SIZE];
char pllout_name[MAX_NAME_SIZE]; char pllout_name[MAX_NAME_SIZE];
char postdiv_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 clk_init_data init;
struct davinci_pll_clk *pllout; struct davinci_pll_clk *pllout;
struct davinci_pllen_clk *pllen; struct davinci_pllen_clk *pllen;
struct clk *pllout_clk, *clk; struct clk *oscin_clk = NULL;
struct clk *prediv_clk = NULL;
pdata = davinci_pll_get_pdata(dev); struct clk *pllout_clk;
if (!pdata) struct clk *postdiv_clk = NULL;
return ERR_PTR(-ENOMEM); struct clk *pllen_clk;
int ret;
if (info->flags & PLL_HAS_CLKMODE) { 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 * a number of different things. In this driver we use it to
* mean the signal after the PLLCTL[CLKMODE] switch. * mean the signal after the PLLCTL[CLKMODE] switch.
*/ */
clk = clk_register_fixed_factor(dev, OSCIN_CLK_NAME, oscin_clk = clk_register_fixed_factor(dev, OSCIN_CLK_NAME,
parent_name, 0, 1, 1); parent_name, 0, 1, 1);
if (IS_ERR(clk)) if (IS_ERR(oscin_clk))
return clk; return oscin_clk;
parent_name = OSCIN_CLK_NAME; 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 */ /* Some? DM355 chips don't correctly report the PREDIV value */
if (info->flags & PLL_PREDIV_FIXED8) if (info->flags & PLL_PREDIV_FIXED8)
clk = clk_register_fixed_factor(dev, prediv_name, prediv_clk = clk_register_fixed_factor(dev, prediv_name,
parent_name, flags, 1, 8); parent_name, flags, 1, 8);
else else
clk = davinci_pll_div_register(dev, prediv_name, prediv_clk = davinci_pll_div_register(dev, prediv_name,
parent_name, base + PREDIV, fixed, flags); parent_name, base + PREDIV, fixed, flags);
if (IS_ERR(clk)) if (IS_ERR(prediv_clk)) {
return clk; ret = PTR_ERR(prediv_clk);
goto err_unregister_oscin;
}
parent_name = prediv_name; parent_name = prediv_name;
} }
/* Unlock writing to PLL registers */ /* Unlock writing to PLL registers */
if (info->unlock_reg) { 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", dev_warn(dev, "Failed to get CFGCHIP (%ld)\n",
PTR_ERR(pdata->cfgchip)); PTR_ERR(cfgchip));
else else
regmap_write_bits(pdata->cfgchip, info->unlock_reg, regmap_write_bits(cfgchip, info->unlock_reg,
info->unlock_mask, 0); info->unlock_mask, 0);
} }
pllout = devm_kzalloc(dev, sizeof(*pllout), GFP_KERNEL); pllout = kzalloc(sizeof(*pllout), GFP_KERNEL);
if (!pllout) if (!pllout) {
return ERR_PTR(-ENOMEM); ret = -ENOMEM;
goto err_unregister_prediv;
}
snprintf(pllout_name, MAX_NAME_SIZE, "%s_pllout", info->name); 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_min = info->pllm_min;
pllout->pllm_max = info->pllm_max; pllout->pllm_max = info->pllm_max;
pllout_clk = devm_clk_register(dev, &pllout->hw); pllout_clk = clk_register(dev, &pllout->hw);
if (IS_ERR(pllout_clk)) if (IS_ERR(pllout_clk)) {
return pllout_clk; ret = PTR_ERR(pllout_clk);
goto err_free_pllout;
}
clk_hw_set_rate_range(&pllout->hw, info->pllout_min_rate, clk_hw_set_rate_range(&pllout->hw, info->pllout_min_rate,
info->pllout_max_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) if (info->flags & PLL_POSTDIV_ALWAYS_ENABLED)
flags |= CLK_IS_CRITICAL; flags |= CLK_IS_CRITICAL;
clk = davinci_pll_div_register(dev, postdiv_name, parent_name, postdiv_clk = davinci_pll_div_register(dev, postdiv_name,
base + POSTDIV, fixed, flags); parent_name, base + POSTDIV, fixed, flags);
if (IS_ERR(clk)) if (IS_ERR(postdiv_clk)) {
return clk; ret = PTR_ERR(postdiv_clk);
goto err_unregister_pllout;
}
parent_name = postdiv_name; parent_name = postdiv_name;
} }
pllen = devm_kzalloc(dev, sizeof(*pllout), GFP_KERNEL); pllen = kzalloc(sizeof(*pllout), GFP_KERNEL);
if (!pllen) if (!pllen) {
return ERR_PTR(-ENOMEM); ret = -ENOMEM;
goto err_unregister_postdiv;
}
snprintf(pllen_name, MAX_NAME_SIZE, "%s_pllen", info->name); 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->hw.init = &init;
pllen->base = base; pllen->base = base;
clk = devm_clk_register(dev, &pllen->hw); pllen_clk = clk_register(dev, &pllen->hw);
if (IS_ERR(clk)) if (IS_ERR(pllen_clk)) {
return 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; 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) * davinci_pll_auxclk_register - Register bypass clock (AUXCLK)
* @dev: The PLL platform device or NULL
* @name: The clock name * @name: The clock name
* @base: The PLL memory region * @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) * davinci_pll_sysclkbp_clk_register - Register bypass divider clock (SYSCLKBP)
* @dev: The PLL platform device or NULL
* @name: The clock name * @name: The clock name
* @base: The PLL memory region * @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) * davinci_pll_obsclk_register - Register oscillator divider clock (OBSCLK)
* @dev: The PLL platform device or NULL
* @info: The clock info * @info: The clock info
* @base: The PLL memory region * @base: The PLL memory region
*/ */
@ -546,9 +577,11 @@ davinci_pll_obsclk_register(struct device *dev,
struct clk_mux *mux; struct clk_mux *mux;
struct clk_gate *gate; struct clk_gate *gate;
struct clk_divider *divider; struct clk_divider *divider;
struct clk *clk;
u32 oscdiv; u32 oscdiv;
int ret;
mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); mux = kzalloc(sizeof(*mux), GFP_KERNEL);
if (!mux) if (!mux)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
@ -556,16 +589,20 @@ davinci_pll_obsclk_register(struct device *dev,
mux->table = info->table; mux->table = info->table;
mux->mask = info->ocsrc_mask; mux->mask = info->ocsrc_mask;
gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); gate = kzalloc(sizeof(*gate), GFP_KERNEL);
if (!gate) if (!gate) {
return ERR_PTR(-ENOMEM); ret = -ENOMEM;
goto err_free_mux;
}
gate->reg = base + CKEN; gate->reg = base + CKEN;
gate->bit_idx = CKEN_OBSCLK_SHIFT; gate->bit_idx = CKEN_OBSCLK_SHIFT;
divider = devm_kzalloc(dev, sizeof(*divider), GFP_KERNEL); divider = kzalloc(sizeof(*divider), GFP_KERNEL);
if (!divider) if (!divider) {
return ERR_PTR(-ENOMEM); ret = -ENOMEM;
goto err_free_gate;
}
divider->reg = base + OSCDIV; divider->reg = base + OSCDIV;
divider->shift = DIV_RATIO_SHIFT; divider->shift = DIV_RATIO_SHIFT;
@ -576,11 +613,27 @@ davinci_pll_obsclk_register(struct device *dev,
oscdiv |= BIT(DIV_ENABLE_SHIFT); oscdiv |= BIT(DIV_ENABLE_SHIFT);
writel(oscdiv, base + OSCDIV); writel(oscdiv, base + OSCDIV);
return clk_register_composite(dev, info->name, info->parent_names, clk = clk_register_composite(dev, info->name, info->parent_names,
info->num_parents, info->num_parents,
&mux->hw, &clk_mux_ops, &mux->hw, &clk_mux_ops,
&divider->hw, &clk_divider_ops, &divider->hw, &clk_divider_ops,
&gate->hw, &clk_gate_ops, 0); &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. */ /* 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) * davinci_pll_sysclk_register - Register divider clocks (SYSCLKn)
* @dev: The PLL platform device or NULL
* @info: The clock info * @info: The clock info
* @base: The PLL memory region * @base: The PLL memory region
*/ */
@ -630,6 +684,7 @@ davinci_pll_sysclk_register(struct device *dev,
struct clk *clk; struct clk *clk;
u32 reg; u32 reg;
u32 flags = 0; u32 flags = 0;
int ret;
/* PLLDIVn registers are not entirely consecutive */ /* PLLDIVn registers are not entirely consecutive */
if (info->id < 4) if (info->id < 4)
@ -637,16 +692,18 @@ davinci_pll_sysclk_register(struct device *dev,
else else
reg = PLLDIV4 + 4 * (info->id - 4); reg = PLLDIV4 + 4 * (info->id - 4);
gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); gate = kzalloc(sizeof(*gate), GFP_KERNEL);
if (!gate) if (!gate)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
gate->reg = base + reg; gate->reg = base + reg;
gate->bit_idx = DIV_ENABLE_SHIFT; gate->bit_idx = DIV_ENABLE_SHIFT;
divider = devm_kzalloc(dev, sizeof(*divider), GFP_KERNEL); divider = kzalloc(sizeof(*divider), GFP_KERNEL);
if (!divider) if (!divider) {
return ERR_PTR(-ENOMEM); ret = -ENOMEM;
goto err_free_gate;
}
divider->reg = base + reg; divider->reg = base + reg;
divider->shift = DIV_RATIO_SHIFT; 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, clk = clk_register_composite(dev, info->name, &info->parent_name, 1,
NULL, NULL, &divider->hw, divider_ops, NULL, NULL, &divider->hw, divider_ops,
&gate->hw, &clk_gate_ops, flags); &gate->hw, &clk_gate_ops, flags);
if (IS_ERR(clk)) if (IS_ERR(clk)) {
return clk; ret = PTR_ERR(clk);
goto err_free_divider;
}
clk_notifier_register(clk, &davinci_pll_sysclk_notifier); clk_notifier_register(clk, &davinci_pll_sysclk_notifier);
return clk; 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_clk_info *info,
const struct davinci_pll_obsclk_info *obsclk_info, const struct davinci_pll_obsclk_info *obsclk_info,
const struct davinci_pll_sysclk_info **div_info, const struct davinci_pll_sysclk_info **div_info,
u8 max_sysclk_id, u8 max_sysclk_id,
void __iomem *base) void __iomem *base,
struct regmap *cfgchip)
{ {
struct device_node *node = dev->of_node;
struct device_node *child; struct device_node *child;
const char *parent_name; const char *parent_name;
struct clk *clk; struct clk *clk;
@ -693,7 +759,7 @@ int of_davinci_pll_init(struct device *dev,
else else
parent_name = OSCIN_CLK_NAME; 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)) { if (IS_ERR(clk)) {
dev_err(dev, "failed to register %s\n", info->name); dev_err(dev, "failed to register %s\n", info->name);
return PTR_ERR(clk); return PTR_ERR(clk);
@ -711,13 +777,15 @@ int of_davinci_pll_init(struct device *dev,
int n_clks = max_sysclk_id + 1; int n_clks = max_sysclk_id + 1;
int i; int i;
clk_data = devm_kzalloc(dev, sizeof(*clk_data), GFP_KERNEL); clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
if (!clk_data) if (!clk_data)
return -ENOMEM; return -ENOMEM;
clks = devm_kmalloc_array(dev, n_clks, sizeof(*clks), GFP_KERNEL); clks = kmalloc_array(n_clks, sizeof(*clks), GFP_KERNEL);
if (!clks) if (!clks) {
kfree(clk_data);
return -ENOMEM; return -ENOMEM;
}
clk_data->clks = clks; clk_data->clks = clks;
clk_data->clk_num = n_clks; clk_data->clk_num = n_clks;
@ -770,32 +838,73 @@ int of_davinci_pll_init(struct device *dev,
return 0; 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[] = { 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 }, { .compatible = "ti,da850-pll1", .data = of_da850_pll1_init },
#endif
{ } { }
}; };
static const struct platform_device_id davinci_pll_id_table[] = { 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 }, { .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-pll0", .driver_data = (kernel_ulong_t)da850_pll0_init },
{ .name = "da850-pll1", .driver_data = (kernel_ulong_t)da850_pll1_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-pll1", .driver_data = (kernel_ulong_t)dm355_pll1_init },
{ .name = "dm355-pll2", .driver_data = (kernel_ulong_t)dm355_pll2_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-pll1", .driver_data = (kernel_ulong_t)dm365_pll1_init },
{ .name = "dm365-pll2", .driver_data = (kernel_ulong_t)dm365_pll2_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-pll1", .driver_data = (kernel_ulong_t)dm644x_pll1_init },
{ .name = "dm644x-pll2", .driver_data = (kernel_ulong_t)dm644x_pll2_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-pll1", .driver_data = (kernel_ulong_t)dm646x_pll1_init },
{ .name = "dm646x-pll2", .driver_data = (kernel_ulong_t)dm646x_pll2_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) static int davinci_pll_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct davinci_pll_platform_data *pdata;
const struct of_device_id *of_id; const struct of_device_id *of_id;
davinci_pll_init pll_init = NULL; davinci_pll_init pll_init = NULL;
struct resource *res; struct resource *res;
@ -812,12 +921,18 @@ static int davinci_pll_probe(struct platform_device *pdev)
return -EINVAL; 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); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res); base = devm_ioremap_resource(dev, res);
if (IS_ERR(base)) if (IS_ERR(base))
return PTR_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 = { static struct platform_driver davinci_pll_driver = {
@ -874,26 +989,19 @@ static const struct debugfs_reg32 davinci_pll_regs[] = {
DEBUG_REG(PLLDIV9), 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 davinci_pll_clk *pll = to_davinci_pll_clk(hw);
struct debugfs_regset32 *regset; struct debugfs_regset32 *regset;
struct dentry *d;
regset = kzalloc(sizeof(*regset), GFP_KERNEL); regset = kzalloc(sizeof(*regset), GFP_KERNEL);
if (!regset) if (!regset)
return -ENOMEM; return;
regset->regs = davinci_pll_regs; regset->regs = davinci_pll_regs;
regset->nregs = ARRAY_SIZE(davinci_pll_regs); regset->nregs = ARRAY_SIZE(davinci_pll_regs);
regset->base = pll->base; regset->base = pll->base;
d = debugfs_create_regset32("registers", 0400, dentry, regset); debugfs_create_regset32("registers", 0400, dentry, regset);
if (IS_ERR(d)) {
kfree(regset);
return PTR_ERR(d);
}
return 0;
} }
#endif #endif

View File

@ -11,6 +11,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/regmap.h>
#include <linux/types.h> #include <linux/types.h>
#define PLL_HAS_CLKMODE BIT(0) /* PLL has PLLCTL[CLKMODE] */ #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, struct clk *davinci_pll_clk_register(struct device *dev,
const struct davinci_pll_clk_info *info, const struct davinci_pll_clk_info *info,
const char *parent_name, const char *parent_name,
void __iomem *base); void __iomem *base,
struct regmap *cfgchip);
struct clk *davinci_pll_auxclk_register(struct device *dev, struct clk *davinci_pll_auxclk_register(struct device *dev,
const char *name, const char *name,
void __iomem *base); void __iomem *base);
@ -110,32 +112,29 @@ davinci_pll_sysclk_register(struct device *dev,
const struct davinci_pll_sysclk_info *info, const struct davinci_pll_sysclk_info *info,
void __iomem *base); 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_clk_info *info,
const struct davinci_pll_obsclk_info *obsclk_info, const struct davinci_pll_obsclk_info *obsclk_info,
const struct davinci_pll_sysclk_info **div_info, const struct davinci_pll_sysclk_info **div_info,
u8 max_sysclk_id, u8 max_sysclk_id,
void __iomem *base); void __iomem *base,
struct regmap *cfgchip);
/* Platform-specific callbacks */ /* Platform-specific callbacks */
int da830_pll_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);
int da850_pll0_init(struct device *dev, void __iomem *base); void of_da850_pll0_init(struct device_node *node);
int da850_pll1_init(struct device *dev, void __iomem *base); int of_da850_pll1_init(struct device *dev, void __iomem *base, struct regmap *cfgchip);
int of_da850_pll0_init(struct device *dev, void __iomem *base); #endif
int of_da850_pll1_init(struct device *dev, void __iomem *base); #ifdef CONFIG_ARCH_DAVINCI_DM355
int dm355_pll2_init(struct device *dev, void __iomem *base, struct regmap *cfgchip);
int dm355_pll1_init(struct device *dev, void __iomem *base); #endif
int dm355_pll2_init(struct device *dev, void __iomem *base); #ifdef CONFIG_ARCH_DAVINCI_DM644x
int dm644x_pll2_init(struct device *dev, void __iomem *base, struct regmap *cfgchip);
int dm365_pll1_init(struct device *dev, void __iomem *base); #endif
int dm365_pll2_init(struct device *dev, void __iomem *base); #ifdef CONFIG_ARCH_DAVINCI_DM646x
int dm646x_pll2_init(struct device *dev, void __iomem *base, struct regmap *cfgchip);
int dm644x_pll1_init(struct device *dev, void __iomem *base); #endif
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);
#endif /* __CLK_DAVINCI_PLL_H___ */ #endif /* __CLK_DAVINCI_PLL_H___ */

View File

@ -55,7 +55,8 @@ const struct davinci_psc_init_data da830_psc0_init_data = {
.psc_init = &da830_psc0_init, .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"); NULL, "cppi41-dmaengine");
LPSC_CLKDEV1(usb1_clkdev, NULL, "ohci-da8xx"); LPSC_CLKDEV1(usb1_clkdev, NULL, "ohci-da8xx");
/* REVISIT: gpio-davinci.c should be modified to drop con_id */ /* REVISIT: gpio-davinci.c should be modified to drop con_id */

View File

@ -6,6 +6,7 @@
*/ */
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clk/davinci.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/init.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(5, 0, timer3, pll1_auxclk, NULL, 0),
LPSC(6, 0, spi1, pll1_sysclk2, spi1_clkdev, 0), LPSC(6, 0, spi1, pll1_sysclk2, spi1_clkdev, 0),
LPSC(7, 0, mmcsd1, pll1_sysclk2, mmcsd1_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(9, 0, usb, pll1_sysclk2, usb_clkdev, 0),
LPSC(10, 0, pwm3, pll1_auxclk, NULL, 0), LPSC(10, 0, pwm3, pll1_auxclk, NULL, 0),
LPSC(11, 0, spi2, pll1_sysclk2, spi2_clkdev, 0), LPSC(11, 0, spi2, pll1_sysclk2, spi2_clkdev, 0),
LPSC(12, 0, rto, pll1_auxclk, NULL, 0), LPSC(12, 0, rto, pll1_auxclk, NULL, 0),
LPSC(14, 0, aemif, pll1_sysclk2, aemif_clkdev, 0), LPSC(14, 0, aemif, pll1_sysclk2, aemif_clkdev, 0),
LPSC(15, 0, mmcsd0, pll1_sysclk2, mmcsd0_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(18, 0, i2c, pll1_auxclk, i2c_clkdev, 0),
LPSC(19, 0, uart0, pll1_auxclk, uart0_clkdev, 0), LPSC(19, 0, uart0, pll1_auxclk, uart0_clkdev, 0),
LPSC(20, 0, uart1, pll1_auxclk, uart1_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); return davinci_psc_register_clocks(dev, dm355_psc_info, 42, base);
} }

View File

@ -6,6 +6,7 @@
*/ */
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clk/davinci.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/init.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(31, 0, arm, pll2_sysclk2, NULL, LPSC_ALWAYS_ENABLED),
LPSC(38, 0, spi3, pll1_sysclk4, spi3_clkdev, 0), LPSC(38, 0, spi3, pll1_sysclk4, spi3_clkdev, 0),
LPSC(39, 0, spi4, pll1_auxclk, spi4_clkdev, 0), LPSC(39, 0, spi4, pll1_auxclk, spi4_clkdev, 0),
LPSC(40, 0, emac, pll2_sysclk4, emac_clkdev, 0), LPSC(40, 0, emac, pll1_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), * 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(47, 0, vpss_master, pll1_sysclk5, vpss_master_clkdev, 0),
LPSC(50, 0, mjcp, pll1_sysclk3, NULL, 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); return davinci_psc_register_clocks(dev, dm365_psc_info, 52, base);
} }

View File

@ -6,6 +6,7 @@
*/ */
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clk/davinci.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/init.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); return davinci_psc_register_clocks(dev, dm644x_psc_info, 41, base);
} }

View File

@ -6,6 +6,7 @@
*/ */
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clk/davinci.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/init.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); return davinci_psc_register_clocks(dev, dm646x_psc_info, 46, base);
} }

View File

@ -15,6 +15,7 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clk/davinci.h>
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/of_address.h> #include <linux/of_address.h>
@ -63,7 +64,7 @@ struct davinci_psc_data {
/** /**
* struct davinci_lpsc_clk - LPSC clock structure * 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 * @hw: clk_hw for the LPSC
* @pm_domain: power domain for the LPSC * @pm_domain: power domain for the LPSC
* @genpd_clk: clock reference owned by @pm_domain * @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 * davinci_lpsc_clk_register - register LPSC clock
* @dev: the clocks's device or NULL
* @name: name of this clock * @name: name of this clock
* @parent_name: name of clock's parent * @parent_name: name of clock's parent
* @regmap: PSC MMIO region * @regmap: PSC MMIO region
@ -238,7 +240,7 @@ davinci_lpsc_clk_register(struct device *dev, const char *name,
int ret; int ret;
bool is_on; bool is_on;
lpsc = devm_kzalloc(dev, sizeof(*lpsc), GFP_KERNEL); lpsc = kzalloc(sizeof(*lpsc), GFP_KERNEL);
if (!lpsc) if (!lpsc)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
@ -261,9 +263,15 @@ davinci_lpsc_clk_register(struct device *dev, const char *name,
lpsc->pd = pd; lpsc->pd = pd;
lpsc->flags = flags; lpsc->flags = flags;
ret = devm_clk_hw_register(dev, &lpsc->hw); ret = clk_hw_register(dev, &lpsc->hw);
if (ret < 0) if (ret < 0) {
kfree(lpsc);
return ERR_PTR(ret); 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 */ /* genpd attach needs a way to look up this clock */
ret = clk_hw_register_clkdev(&lpsc->hw, name, best_dev_name(dev)); 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; struct regmap *regmap;
int i, ret; int i, ret;
psc = devm_kzalloc(dev, sizeof(*psc), GFP_KERNEL); psc = kzalloc(sizeof(*psc), GFP_KERNEL);
if (!psc) if (!psc)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
clks = devm_kmalloc_array(dev, num_clks, sizeof(*clks), GFP_KERNEL); clks = kmalloc_array(num_clks, sizeof(*clks), GFP_KERNEL);
if (!clks) if (!clks) {
return ERR_PTR(-ENOMEM); ret = -ENOMEM;
goto err_free_psc;
}
psc->clk_data.clks = clks; psc->clk_data.clks = clks;
psc->clk_data.clk_num = num_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++) for (i = 0; i < num_clks; i++)
clks[i] = ERR_PTR(-ENOENT); clks[i] = ERR_PTR(-ENOENT);
pm_domains = devm_kcalloc(dev, num_clks, sizeof(*pm_domains), GFP_KERNEL); pm_domains = kcalloc(num_clks, sizeof(*pm_domains), GFP_KERNEL);
if (!pm_domains) if (!pm_domains) {
return ERR_PTR(-ENOMEM); ret = -ENOMEM;
goto err_free_clks;
}
psc->pm_data.domains = pm_domains; psc->pm_data.domains = pm_domains;
psc->pm_data.num_domains = num_clks; psc->pm_data.num_domains = num_clks;
regmap = devm_regmap_init_mmio(dev, base, &davinci_psc_regmap_config); regmap = regmap_init_mmio(dev, base, &davinci_psc_regmap_config);
if (IS_ERR(regmap)) if (IS_ERR(regmap)) {
return ERR_CAST(regmap); ret = PTR_ERR(regmap);
goto err_free_pm_domains;
}
for (; info->name; info++) { for (; info->name; info++) {
struct davinci_lpsc_clk *lpsc; struct davinci_lpsc_clk *lpsc;
@ -423,6 +437,13 @@ __davinci_psc_register_clocks(struct device *dev,
pm_domains[info->md] = &lpsc->pm_domain; 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.ops = &davinci_psc_reset_ops;
psc->rcdev.owner = THIS_MODULE; psc->rcdev.owner = THIS_MODULE;
psc->rcdev.dev = dev; 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); dev_warn(dev, "Failed to register reset controller (%d)\n", ret);
return psc; 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, 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[] = { 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-psc0", .data = &of_da850_psc0_init_data },
{ .compatible = "ti,da850-psc1", .data = &of_da850_psc1_init_data }, { .compatible = "ti,da850-psc1", .data = &of_da850_psc1_init_data },
#endif
{ } { }
}; };
static const struct platform_device_id davinci_psc_id_table[] = { 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-psc0", .driver_data = (kernel_ulong_t)&da830_psc0_init_data },
{ .name = "da830-psc1", .driver_data = (kernel_ulong_t)&da830_psc1_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-psc0", .driver_data = (kernel_ulong_t)&da850_psc0_init_data },
{ .name = "da850-psc1", .driver_data = (kernel_ulong_t)&da850_psc1_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 }, { .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 }, { .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 }, { .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 }, { .name = "dm646x-psc", .driver_data = (kernel_ulong_t)&dm646x_psc_init_data },
#endif
{ } { }
}; };

View File

@ -94,15 +94,27 @@ struct davinci_psc_init_data {
int (*psc_init)(struct device *dev, void __iomem *base); 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_psc0_init_data;
extern const struct davinci_psc_init_data da830_psc1_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_psc0_init_data;
extern const struct davinci_psc_init_data da850_psc1_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_psc0_init_data;
extern const struct davinci_psc_init_data of_da850_psc1_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; 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; 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; 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; extern const struct davinci_psc_init_data dm646x_psc_init_data;
#endif
#endif /* __CLK_DAVINCI_PSC_H__ */ #endif /* __CLK_DAVINCI_PSC_H__ */

View File

@ -44,14 +44,17 @@ config RESET_HISI
Build reset controller driver for HiSilicon device chipsets. Build reset controller driver for HiSilicon device chipsets.
config STUB_CLK_HI6220 config STUB_CLK_HI6220
bool "Hi6220 Stub Clock Driver" bool "Hi6220 Stub Clock Driver" if EXPERT
depends on COMMON_CLK_HI6220 && MAILBOX depends on (COMMON_CLK_HI6220 || COMPILE_TEST)
default ARCH_HISI depends on MAILBOX
default COMMON_CLK_HI6220
help help
Build the Hisilicon Hi6220 stub clock driver. Build the Hisilicon Hi6220 stub clock driver.
config STUB_CLK_HI3660 config STUB_CLK_HI3660
bool "Hi3660 Stub Clock Driver" bool "Hi3660 Stub Clock Driver" if EXPERT
depends on COMMON_CLK_HI3660 && MAILBOX depends on (COMMON_CLK_HI3660 || COMPILE_TEST)
depends on MAILBOX
default COMMON_CLK_HI3660
help help
Build the Hisilicon Hi3660 stub clock driver. Build the Hisilicon Hi3660 stub clock driver.

View File

@ -186,6 +186,23 @@ static const struct hisi_gate_clock hi3798cv200_gate_clks[] = {
CLK_SET_RATE_PARENT, 0xbc, 0, 0 }, CLK_SET_RATE_PARENT, 0xbc, 0, 0 },
{ HISTB_USB2_PHY2_REF_CLK, "clk_u2_phy2_ref", "24m", { HISTB_USB2_PHY2_REF_CLK, "clk_u2_phy2_ref", "24m",
CLK_SET_RATE_PARENT, 0xbc, 2, 0 }, 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( static struct hisi_clock_data *hi3798cv200_clk_register(

View File

@ -753,6 +753,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
else else
clk[IMX6Q_CLK_ECSPI5] = imx_clk_gate2("ecspi5", "ecspi_root", base + 0x6c, 8); 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_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_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_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); clk[IMX6QDL_CLK_ESAI_MEM] = imx_clk_gate2_shared("esai_mem", "ahb", base + 0x6c, 16, &share_count_esai);

View File

@ -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)); 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 */ /* 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_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_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); clks[IMX6SL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2);

View File

@ -80,7 +80,7 @@ static const char *lvds_sels[] = {
"arm", "pll1_sys", "dummy", "dummy", "dummy", "dummy", "dummy", "pll5_video_div", "arm", "pll1_sys", "dummy", "dummy", "dummy", "dummy", "dummy", "pll5_video_div",
"dummy", "dummy", "pcie_ref_125m", "dummy", "usbphy1", "usbphy2", "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 *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", };
static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", }; static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", };
static const char *pll3_bypass_sels[] = { "pll3", "pll3_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_IPMUX1, IMX6SX_CLK_IPMUX2, IMX6SX_CLK_IPMUX3,
IMX6SX_CLK_WAKEUP, IMX6SX_CLK_MMDC_P0_FAST, IMX6SX_CLK_MMDC_P0_IPG, 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_ROM, IMX6SX_CLK_ARM, IMX6SX_CLK_IPG, IMX6SX_CLK_OCRAM,
IMX6SX_CLK_PER2_MAIN, IMX6SX_CLK_PERCLK, IMX6SX_CLK_M4, IMX6SX_CLK_PER2_MAIN, IMX6SX_CLK_PERCLK, IMX6SX_CLK_TZASC1,
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,
}; };
static const struct clk_div_table clk_enet_ref_table[] = { 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_DI0] = of_clk_get_by_name(ccm_node, "ipp_di0");
clks[IMX6SX_CLK_IPP_DI1] = of_clk_get_by_name(ccm_node, "ipp_di1"); clks[IMX6SX_CLK_IPP_DI1] = of_clk_get_by_name(ccm_node, "ipp_di1");
/* Clock source from external clock via CLK1 PAD */ /* Clock source from external clock via CLK1/2 PAD */
clks[IMX6SX_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0); 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"); np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-anatop");
base = of_iomap(np, 0); 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_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_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_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, clks[IMX6SX_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
base + 0xe0, 0, 2, 0, clk_enet_ref_table, 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 */ /* 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_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; np = ccm_node;
base = of_iomap(np, 0); base = of_iomap(np, 0);

View File

@ -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 *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 *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 *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 *periph2_clk2_sels[] = { "pll3_usb_otg", "osc", };
static const char *periph_sels[] = { "periph_pre", "periph_clk2", }; static const char *periph_sels[] = { "periph_pre", "periph_clk2", };
static const char *periph2_sels[] = { "periph2_pre", "periph2_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 *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 *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 *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 *clks[IMX6UL_CLK_END];
static struct clk_onecell_data clk_data; 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_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_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_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_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); 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_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_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_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_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); 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_PWM6] = imx_clk_gate2("pwm6", "perclk", base + 0x80, 28);
clks[IMX6UL_CLK_PWM7] = imx_clk_gate2("pwm7", "perclk", base + 0x80, 30); 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 */ /* mask handshake of mmdc */
writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR); writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);

View File

@ -26,6 +26,8 @@ static u32 share_count_sai1;
static u32 share_count_sai2; static u32 share_count_sai2;
static u32 share_count_sai3; static u32 share_count_sai3;
static u32 share_count_nand; static u32 share_count_nand;
static u32 share_count_enet1;
static u32 share_count_enet2;
static const struct clk_div_table test_div_table[] = { static const struct clk_div_table test_div_table[] = {
{ .val = 3, .div = 1, }, { .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_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_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_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_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_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); 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_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_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_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_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_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); 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_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_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_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_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_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); 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_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_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_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_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_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); 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_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_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 */ /* 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]); clk_set_parent(clks[IMX7D_GPT1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]);

View File

@ -43,7 +43,8 @@ static inline bool
ingenic_cgu_gate_get(struct ingenic_cgu *cgu, ingenic_cgu_gate_get(struct ingenic_cgu *cgu,
const struct ingenic_cgu_gate_info *info) 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); u32 clkgr = readl(cgu->base + info->reg);
if (val) if (val ^ info->clear_to_gate)
clkgr |= BIT(info->bit); clkgr |= BIT(info->bit);
else else
clkgr &= ~BIT(info->bit); clkgr &= ~BIT(info->bit);
@ -511,6 +512,9 @@ static int ingenic_clk_enable(struct clk_hw *hw)
spin_lock_irqsave(&cgu->lock, flags); spin_lock_irqsave(&cgu->lock, flags);
ingenic_cgu_gate_set(cgu, &clk_info->gate, false); ingenic_cgu_gate_set(cgu, &clk_info->gate, false);
spin_unlock_irqrestore(&cgu->lock, flags); spin_unlock_irqrestore(&cgu->lock, flags);
if (clk_info->gate.delay_us)
udelay(clk_info->gate.delay_us);
} }
return 0; return 0;

View File

@ -111,10 +111,14 @@ struct ingenic_cgu_fixdiv_info {
* struct ingenic_cgu_gate_info - information about a clock gate * struct ingenic_cgu_gate_info - information about a clock gate
* @reg: offset of the gate control register within the CGU * @reg: offset of the gate control register within the CGU
* @bit: offset of the bit in the register that controls the gate * @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 { struct ingenic_cgu_gate_info {
unsigned reg; unsigned reg;
u8 bit; u8 bit;
bool clear_to_gate;
u16 delay_us;
}; };
/** /**

View File

@ -42,7 +42,6 @@
/* bits within the OPCR register */ /* bits within the OPCR register */
#define OPCR_SPENDH BIT(5) /* UHC PHY suspend */ #define OPCR_SPENDH BIT(5) /* UHC PHY suspend */
#define OPCR_SPENDN BIT(7) /* OTG PHY suspend */
/* bits within the USBPCR1 register */ /* bits within the USBPCR1 register */
#define USBPCR1_UHC_POWER BIT(5) /* UHC PHY power down */ #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, .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] = { static const s8 pll_od_encoding[8] = {
0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3, 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, "h1clk", CGU_CLK_DIV | CGU_CLK_GATE,
.parents = { JZ4770_CLK_PLL0, }, .parents = { JZ4770_CLK_PLL0, },
.div = { CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1 }, .div = { CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1 },
.gate = { CGU_REG_LCR, 30 }, .gate = { CGU_REG_CLKGR1, 7 },
}, },
[JZ4770_CLK_H2CLK] = { [JZ4770_CLK_H2CLK] = {
"h2clk", CGU_CLK_DIV, "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 }, .div = { CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1 },
}, },
[JZ4770_CLK_C1CLK] = { [JZ4770_CLK_C1CLK] = {
"c1clk", CGU_CLK_DIV, "c1clk", CGU_CLK_DIV | CGU_CLK_GATE,
.parents = { JZ4770_CLK_PLL0, }, .parents = { JZ4770_CLK_PLL0, },
.div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 }, .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 },
.gate = { CGU_REG_OPCR, 31, true }, // disable CCLK stop on idle
}, },
[JZ4770_CLK_PCLK] = { [JZ4770_CLK_PCLK] = {
"pclk", CGU_CLK_DIV, "pclk", CGU_CLK_DIV,
@ -393,7 +362,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
[JZ4770_CLK_VPU] = { [JZ4770_CLK_VPU] = {
"vpu", CGU_CLK_GATE, "vpu", CGU_CLK_GATE,
.parents = { JZ4770_CLK_H1CLK, }, .parents = { JZ4770_CLK_H1CLK, },
.gate = { CGU_REG_CLKGR1, 7 }, .gate = { CGU_REG_LCR, 30, false, 150 },
}, },
[JZ4770_CLK_MMC0] = { [JZ4770_CLK_MMC0] = {
"mmc0", CGU_CLK_GATE, "mmc0", CGU_CLK_GATE,
@ -410,6 +379,11 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
.parents = { JZ4770_CLK_MMC2_MUX, }, .parents = { JZ4770_CLK_MMC2_MUX, },
.gate = { CGU_REG_CLKGR0, 12 }, .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 */ /* Custom clocks */
@ -418,11 +392,6 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
.parents = { JZ4770_CLK_UHC, -1, -1, -1 }, .parents = { JZ4770_CLK_UHC, -1, -1, -1 },
.custom = { &jz4770_uhc_phy_ops }, .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] = { [JZ4770_CLK_EXT512] = {
"ext/512", CGU_CLK_FIXDIV, "ext/512", CGU_CLK_FIXDIV,

View File

@ -60,6 +60,12 @@ config COMMON_CLK_MT2701_AUDSYS
---help--- ---help---
This driver supports Mediatek MT2701 audsys clocks. 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 config COMMON_CLK_MT2712
bool "Clock driver for MediaTek MT2712" bool "Clock driver for MediaTek MT2712"
depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST

View File

@ -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_AUDSYS) += clk-mt2701-aud.o
obj-$(CONFIG_COMMON_CLK_MT2701_BDPSYS) += clk-mt2701-bdp.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_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_HIFSYS) += clk-mt2701-hif.o
obj-$(CONFIG_COMMON_CLK_MT2701_IMGSYS) += clk-mt2701-img.o obj-$(CONFIG_COMMON_CLK_MT2701_IMGSYS) += clk-mt2701-img.o
obj-$(CONFIG_COMMON_CLK_MT2701_MMSYS) += clk-mt2701-mm.o obj-$(CONFIG_COMMON_CLK_MT2701_MMSYS) += clk-mt2701-mm.o

View 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);

View File

@ -46,8 +46,6 @@ static const struct mtk_fixed_clk top_fixed_clks[] = {
340 * MHZ), 340 * MHZ),
FIXED_CLK(CLK_TOP_HDMI_0_PLL340M, "hdmi_0_pll340m", "clk26m", FIXED_CLK(CLK_TOP_HDMI_0_PLL340M, "hdmi_0_pll340m", "clk26m",
340 * MHZ), 340 * MHZ),
FIXED_CLK(CLK_TOP_HDMITX_CLKDIG_CTS, "hdmitx_dig_cts", "clk26m",
300 * MHZ),
FIXED_CLK(CLK_TOP_HADDS2_FB, "hadds2_fbclk", "clk26m", FIXED_CLK(CLK_TOP_HADDS2_FB, "hadds2_fbclk", "clk26m",
27 * MHZ), 27 * MHZ),
FIXED_CLK(CLK_TOP_WBG_DIG_416M, "wbg_dig_ck_416m", "clk26m", 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), 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) static int mtk_apmixedsys_init(struct platform_device *pdev)
{ {
struct clk_onecell_data *clk_data; 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), mtk_clk_register_plls(node, apmixed_plls, ARRAY_SIZE(apmixed_plls),
clk_data); 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); return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
} }

View File

@ -3,6 +3,12 @@ config COMMON_CLK_AMLOGIC
depends on OF depends on OF
depends on ARCH_MESON || COMPILE_TEST 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 config COMMON_CLK_REGMAP_MESON
bool bool
select REGMAP select REGMAP
@ -21,6 +27,7 @@ config COMMON_CLK_GXBB
bool bool
depends on COMMON_CLK_AMLOGIC depends on COMMON_CLK_AMLOGIC
select RESET_CONTROLLER select RESET_CONTROLLER
select COMMON_CLK_MESON_AO
select COMMON_CLK_REGMAP_MESON select COMMON_CLK_REGMAP_MESON
select MFD_SYSCON select MFD_SYSCON
help help
@ -31,6 +38,7 @@ config COMMON_CLK_AXG
bool bool
depends on COMMON_CLK_AMLOGIC depends on COMMON_CLK_AMLOGIC
select RESET_CONTROLLER select RESET_CONTROLLER
select COMMON_CLK_MESON_AO
select COMMON_CLK_REGMAP_MESON select COMMON_CLK_REGMAP_MESON
select MFD_SYSCON select MFD_SYSCON
help help

View File

@ -3,7 +3,8 @@
# #
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-audio-divider.o 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_MESON8B) += meson8b.o
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.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 obj-$(CONFIG_COMMON_CLK_REGMAP_MESON) += clk-regmap.o

View 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);

View 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 */

View File

@ -461,6 +461,7 @@ static struct clk_regmap axg_mpll0_div = {
.width = 1, .width = 1,
}, },
.lock = &meson_clk_lock, .lock = &meson_clk_lock,
.flags = CLK_MESON_MPLL_ROUND_CLOSEST,
}, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mpll0_div", .name = "mpll0_div",
@ -507,6 +508,7 @@ static struct clk_regmap axg_mpll1_div = {
.width = 1, .width = 1,
}, },
.lock = &meson_clk_lock, .lock = &meson_clk_lock,
.flags = CLK_MESON_MPLL_ROUND_CLOSEST,
}, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mpll1_div", .name = "mpll1_div",
@ -553,6 +555,7 @@ static struct clk_regmap axg_mpll2_div = {
.width = 1, .width = 1,
}, },
.lock = &meson_clk_lock, .lock = &meson_clk_lock,
.flags = CLK_MESON_MPLL_ROUND_CLOSEST,
}, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mpll2_div", .name = "mpll2_div",
@ -599,6 +602,7 @@ static struct clk_regmap axg_mpll3_div = {
.width = 1, .width = 1,
}, },
.lock = &meson_clk_lock, .lock = &meson_clk_lock,
.flags = CLK_MESON_MPLL_ROUND_CLOSEST,
}, },
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "mpll3_div", .name = "mpll3_div",

View File

@ -1,18 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* Copyright (c) 2017 AmLogic, Inc. * Copyright (c) 2017 AmLogic, Inc.
* Author: Jerome Brunet <jbrunet@baylibre.com> * 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/>.
*/ */
/* /*

View File

@ -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. * Copyright (c) 2016 AmLogic, Inc.
* Author: Michael Turquette <mturquette@baylibre.com> * 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, static void params_from_rate(unsigned long requested_rate,
unsigned long parent_rate, unsigned long parent_rate,
unsigned int *sdm, unsigned int *sdm,
unsigned int *n2) unsigned int *n2,
u8 flags)
{ {
uint64_t div = parent_rate; 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) { if (div < N2_MIN) {
*n2 = N2_MIN; *n2 = N2_MIN;
@ -102,7 +65,6 @@ static void params_from_rate(unsigned long requested_rate,
*sdm = SDM_DEN - 1; *sdm = SDM_DEN - 1;
} else { } else {
*n2 = div; *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 rate,
unsigned long *parent_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; 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); 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 int sdm, n2;
unsigned long flags = 0; 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) if (mpll->lock)
spin_lock_irqsave(mpll->lock, flags); spin_lock_irqsave(mpll->lock, flags);

View File

@ -1,21 +1,10 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* Copyright (c) 2015 Endless Mobile, Inc. * Copyright (c) 2015 Endless Mobile, Inc.
* Author: Carlo Caione <carlo@endlessm.com> * Author: Carlo Caione <carlo@endlessm.com>
* *
* Copyright (c) 2018 Baylibre, SAS. * Copyright (c) 2018 Baylibre, SAS.
* Author: Jerome Brunet <jbrunet@baylibre.com> * 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/>.
*/ */
/* /*

View File

@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0 // 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" #include "clk-regmap.h"

View File

@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0 /* 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>
*/
#ifndef __CLK_REGMAP_H #ifndef __CLK_REGMAP_H
#define __CLK_REGMAP_H #define __CLK_REGMAP_H

View File

@ -1,18 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* Copyright (c) 2015 Endless Mobile, Inc. * Copyright (c) 2015 Endless Mobile, Inc.
* Author: Carlo Caione <carlo@endlessm.com> * 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 #ifndef __CLKC_H
@ -97,8 +86,11 @@ struct meson_clk_mpll_data {
struct parm ssen; struct parm ssen;
struct parm misc; struct parm misc;
spinlock_t *lock; spinlock_t *lock;
u8 flags;
}; };
#define CLK_MESON_MPLL_ROUND_CLOSEST BIT(0)
struct meson_clk_audio_div_data { struct meson_clk_audio_div_data {
struct parm div; struct parm div;
u8 flags; u8 flags;

View File

@ -1,8 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/* /*
* Copyright (c) 2017 BayLibre, SAS. * Copyright (c) 2017 BayLibre, SAS.
* Author: Neil Armstrong <narmstrong@baylibre.com> * Author: Neil Armstrong <narmstrong@baylibre.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/ */
#include <linux/clk-provider.h> #include <linux/clk-provider.h>

View File

@ -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. * Copyright (c) 2016 BayLibre, SAS.
* Author: Neil Armstrong <narmstrong@baylibre.com> * 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/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/mfd/syscon.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 "clk-regmap.h"
#include "meson-aoclk.h"
#include "gxbb-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) \ #define GXBB_AO_GATE(_name, _bit) \
static struct clk_regmap _name##_ao = { \ static struct clk_regmap _name##_ao = { \
.data = &(struct clk_regmap_gate_data) { \ .data = &(struct clk_regmap_gate_data) { \
@ -96,7 +20,7 @@ static struct clk_regmap _name##_ao = { \
.ops = &clk_regmap_gate_ops, \ .ops = &clk_regmap_gate_ops, \
.parent_names = (const char *[]){ "clk81" }, \ .parent_names = (const char *[]){ "clk81" }, \
.num_parents = 1, \ .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_REMOTE] = 16,
[RESET_AO_I2C_MASTER] = 18, [RESET_AO_I2C_MASTER] = 18,
[RESET_AO_I2C_SLAVE] = 19, [RESET_AO_I2C_SLAVE] = 19,
@ -135,7 +59,7 @@ static struct clk_regmap *gxbb_aoclk_gate[] = {
[CLKID_AO_IR_BLASTER] = &ir_blaster_ao, [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 = { .hws = {
[CLKID_AO_REMOTE] = &remote_ao.hw, [CLKID_AO_REMOTE] = &remote_ao.hw,
[CLKID_AO_I2C_MASTER] = &i2c_master_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_IR_BLASTER] = &ir_blaster_ao.hw,
[CLKID_AO_CEC_32K] = &cec_32k_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 device *dev = &pdev->dev;
struct regmap *regmap; struct regmap *regmap;
int ret, clkid; int ret;
rstc = devm_kzalloc(dev, sizeof(*rstc), GFP_KERNEL);
if (!rstc)
return -ENOMEM;
regmap = syscon_node_to_regmap(of_get_parent(dev->of_node)); regmap = syscon_node_to_regmap(of_get_parent(dev->of_node));
if (IS_ERR(regmap)) { if (IS_ERR(regmap)) {
dev_err(dev, "failed to get regmap\n"); dev_err(dev, "failed to get regmap\n");
return -ENODEV; return PTR_ERR(regmap);
}
/* 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;
} }
/* Specific clocks */ /* Specific clocks */
cec_32k_ao.regmap = regmap; cec_32k_ao.regmap = regmap;
ret = devm_clk_hw_register(dev, &cec_32k_ao.hw); 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) if (ret)
return ret; return ret;
return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, return meson_aoclkc_probe(pdev);
&gxbb_aoclk_onecell_data);
} }
static const struct of_device_id gxbb_aoclkc_match_table[] = { static const struct of_device_id gxbb_aoclkc_match_table[] = {
{ .compatible = "amlogic,meson-gx-aoclkc" }, {
.compatible = "amlogic,meson-gx-aoclkc",
.data = &gxbb_aoclkc_data,
},
{ } { }
}; };

View File

@ -1,13 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* /*
* Copyright (c) 2017 BayLibre, SAS * Copyright (c) 2017 BayLibre, SAS
* Author: Neil Armstrong <narmstrong@baylibre.com> * Author: Neil Armstrong <narmstrong@baylibre.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/ */
#ifndef __GXBB_AOCLKC_H #ifndef __GXBB_AOCLKC_H
#define __GXBB_AOCLKC_H #define __GXBB_AOCLKC_H
#define NR_CLKS 7
/* AO Configuration Clock registers offsets */ /* AO Configuration Clock registers offsets */
#define AO_RTI_PWR_CNTL_REG1 0x0c #define AO_RTI_PWR_CNTL_REG1 0x0c
#define AO_RTI_PWR_CNTL_REG0 0x10 #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; 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 */ #endif /* __GXBB_AOCLKC_H */

View File

@ -1,20 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* AmLogic S905 / GXBB Clock Controller Driver
*
* Copyright (c) 2016 AmLogic, Inc. * Copyright (c) 2016 AmLogic, Inc.
* Michael Turquette <mturquette@baylibre.com> * 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> #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 */ /* Everything Else (EE) domain gates */
static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0); static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0);
static MESON_GATE(gxbb_dos, HHI_GCLK_MPEG0, 1); 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_DIV4_DIV] = &gxbb_fclk_div4_div.hw,
[CLKID_FCLK_DIV5_DIV] = &gxbb_fclk_div5_div.hw, [CLKID_FCLK_DIV5_DIV] = &gxbb_fclk_div5_div.hw,
[CLKID_FCLK_DIV7_DIV] = &gxbb_fclk_div7_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, [NR_CLKS] = NULL,
}, },
.num = NR_CLKS, .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_DIV4_DIV] = &gxbb_fclk_div4_div.hw,
[CLKID_FCLK_DIV5_DIV] = &gxbb_fclk_div5_div.hw, [CLKID_FCLK_DIV5_DIV] = &gxbb_fclk_div5_div.hw,
[CLKID_FCLK_DIV7_DIV] = &gxbb_fclk_div7_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, [NR_CLKS] = NULL,
}, },
.num = NR_CLKS, .num = NR_CLKS,
@ -2100,6 +2195,12 @@ static struct clk_regmap *const gx_clk_regmaps[] = {
&gxbb_fclk_div4, &gxbb_fclk_div4,
&gxbb_fclk_div5, &gxbb_fclk_div5,
&gxbb_fclk_div7, &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 { struct clkc_data {

View File

@ -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. * Copyright (c) 2016 AmLogic, Inc.
* Author: Michael Turquette <mturquette@baylibre.com> * 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 #ifndef __GXBB_H
@ -204,8 +154,12 @@
#define CLKID_FCLK_DIV4_DIV 148 #define CLKID_FCLK_DIV4_DIV 148
#define CLKID_FCLK_DIV5_DIV 149 #define CLKID_FCLK_DIV5_DIV 149
#define CLKID_FCLK_DIV7_DIV 150 #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 the CLKIDs that have been made part of the DT binding */
#include <dt-bindings/clock/gxbb-clkc.h> #include <dt-bindings/clock/gxbb-clkc.h>

View 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);
}

View 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