The new and exciting feature this time around is in the clk core.

We've added duty cycle support to the clk API so that clk signal
 duty cycle ratios can be adjusted while taking into account things
 like clk dividers and clk tree hierarchy. So far only one SoC has
 implemented support for this, but I expect there will be more to
 come in the future.
 
 Outside of the core, we have the usual pile of clk driver updates
 and additions. The Amlogic meson driver got the most lines in the
 diffstat this time around because it added support for a whole bunch
 of hardware and duty cycle configuration. After that the Rockchip PX30,
 Qualcomm SDM845, and Renesas SoC drivers fill in a majority of the diff.
 We're left with the collection of non-critical fixes after that. Overall
 it looks pretty quiet this time.
 
 Core:
  - Clk duty cycle support
  - Proper CLK_SET_RATE_GATE support throughout the tree
 
 New Drivers:
  - Actions Semi Owl series S700 SoC clk driver
  - Qualcomm SDM845 display clock controller
  - i.MX6SX ocram_s clk support
  - Uniphier NAND, USB3 PHY, and SPI clk support
  - Qualcomm RPMh clk driver
  - i.MX7D mailbox clk support
  - Maxim 9485 Programmable Clock Generator
  - Expose 32 kHz PLL on PXA SoCs
  - imx6sll GPIO clk gate support
  - Atmel at91 I2S audio clk support
  - SI544/SI514 clk on/off support
  - i.MX6UL GPIO clock gates in CCM CCGR
  - Renesas Crypto Engine clocks on R-Car H3
  - Renesas clk support for the new RZ/N1D SoC
  - Allwinner A64 display engine clock support
  - Support for Rockchip's PX30 SoC
  - Amlogic Meson axg PCIe and audio clocks
  - Amlogic Meson GEN CLK on gxbb, gxl and axg
 
 Updates:
  - Remove an unused variable from Exynos4412 ISP driver
  - Fix a thinko bug in SCMI clk division logic
  - Add missing of_node_put()s in some i.MX clk drivers
  - Tegra SDMMC clk jitter improvements with high speed signaling modes
  - SPDX tagging for qcom and cs2000-cp drivers
  - Stop leaking con ids in __clk_put()
  - Fix a corner case in fixed factor clk probing where node is in DT but
    parent clk is registered much later
  - Marvell Armada 3700 clk_pm_cpu_get_parent() had an invalid return value
  - i.MX clk init arrays removed in place of CLK_IS_CRITICAL
  - Convert to CLK_IS_CRITICAL for i.MX51/53 driver
  - Fix Tegra BPMP driver oops when xlating a NULL clk
  - Proper default configuration for vic03 and vde clks on Tegra124
  - Mark Tegra memory controller clks as critical
  - Fix array bounds clamp in Tegra's emc determine_rate() op
  - Ingenic i2s bit update and allow UDC clk to gate
  - Fix name of aspeed SDC clk define to have only one 'CLK'
  - Fix i.MX6QDL video clk parent
  - Critical clk markings for qcom SDM845
  - Fix Stratix10 mpu_free_clk and sdmmc_free_clk parents
  - Mark Rockchip's pclk_rkpwm_pmu as critical clock, due to it supplying
    the pwm used to drive the logic supply of the rk3399 core.
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEE9L57QeeUxqYDyoaDrQKIl8bklSUFAlt0WD0RHHNib3lkQGtl
 cm5lbC5vcmcACgkQrQKIl8bklSX5jBAAlMLb0fqnuAGNJeXZDk5rsCa496LMyGWx
 ku7uLA2H68SlbSQqq8FUPoCjDZkmsu2CbOX1U2/H4HFDS0pqpPiV3mZNtSeacedp
 4Wf8yUB5G3xdq9QUCSX5LxMmEQoGeJ+gaTspBvM6sNvEMBR2kEMGBqUy768tnDTR
 qCQ8Q1jOU6l8IdFV0SZGssmZ+oFqOyQoJVquPWPkw1+p/2f1KyYIyG5J5FXGxgcR
 1XQITY/I/dShQ2wd+ZeDdt+GjZqIXQ06Pt3ruRG7HVP79Zt1XCRJd5dZ2lf+Wj8T
 1ul3TWCAMYZ8gCPebLMbBGzKvQJQJcDU6DpIZsrUDN+C6z7KCS9vqeCxP9cF+3jJ
 LOmA6cWE7z9Vkk9s0I0KJJ2Sw7wRoXzE5OJcwa/yousSz3s9cX+F8SAkdZs77oUF
 0XnzPsvwdHI/egQ4UrsStPHM/gOFhsQqo8vvm5xaaTR2AxLKBHuPa9oUv9YpO/P5
 J6FCst3qeY3Wp69fJ5/Z058OFOAt81dKXij2fZJBOO4KJy7Kse8Sz5ApybXVAbY5
 lfvx+KGMITFqLYrcRIQZmlCuoHcMwI0FtHr9Ens5GXdbrJ+W+FlvP43eLCA0ZmRx
 9DidemChj3k3PC3H6tbax/jzV4IIxZdyUoBJ1imL4uyhhaXp/qr45A/aGwNp8Q8a
 WvkIGm3epK4=
 =Mcn+
 -----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:
 "The new and exciting feature this time around is in the clk core.
  We've added duty cycle support to the clk API so that clk signal duty
  cycle ratios can be adjusted while taking into account things like clk
  dividers and clk tree hierarchy. So far only one SoC has implemented
  support for this, but I expect there will be more to come in the
  future.

  Outside of the core, we have the usual pile of clk driver updates and
  additions. The Amlogic meson driver got the most lines in the diffstat
  this time around because it added support for a whole bunch of
  hardware and duty cycle configuration. After that the Rockchip PX30,
  Qualcomm SDM845, and Renesas SoC drivers fill in a majority of the
  diff. We're left with the collection of non-critical fixes after that.
  Overall it looks pretty quiet this time.

  Core:
   - Clk duty cycle support
   - Proper CLK_SET_RATE_GATE support throughout the tree

  New Drivers:
   - Actions Semi Owl series S700 SoC clk driver
   - Qualcomm SDM845 display clock controller
   - i.MX6SX ocram_s clk support
   - Uniphier NAND, USB3 PHY, and SPI clk support
   - Qualcomm RPMh clk driver
   - i.MX7D mailbox clk support
   - Maxim 9485 Programmable Clock Generator
   - expose 32 kHz PLL on PXA SoCs
   - imx6sll GPIO clk gate support
   - Atmel at91 I2S audio clk support
   - SI544/SI514 clk on/off support
   - i.MX6UL GPIO clock gates in CCM CCGR
   - Renesas Crypto Engine clocks on R-Car H3
   - Renesas clk support for the new RZ/N1D SoC
   - Allwinner A64 display engine clock support
   - support for Rockchip's PX30 SoC
   - Amlogic Meson axg PCIe and audio clocks
   - Amlogic Meson GEN CLK on gxbb, gxl and axg

  Updates:
   - remove an unused variable from Exynos4412 ISP driver
   - fix a thinko bug in SCMI clk division logic
   - add missing of_node_put()s in some i.MX clk drivers
   - Tegra SDMMC clk jitter improvements with high speed signaling modes
   - SPDX tagging for qcom and cs2000-cp drivers
   - stop leaking con ids in __clk_put()
   - fix a corner case in fixed factor clk probing where node is in DT
     but parent clk is registered much later
   - Marvell Armada 3700 clk_pm_cpu_get_parent() had an invalid return
     value
   - i.MX clk init arrays removed in place of CLK_IS_CRITICAL
   - convert to CLK_IS_CRITICAL for i.MX51/53 driver
   - fix Tegra BPMP driver oops when xlating a NULL clk
   - proper default configuration for vic03 and vde clks on Tegra124
   - mark Tegra memory controller clks as critical
   - fix array bounds clamp in Tegra's emc determine_rate() op
   - Ingenic i2s bit update and allow UDC clk to gate
   - fix name of aspeed SDC clk define to have only one 'CLK'
   - fix i.MX6QDL video clk parent
   - critical clk markings for qcom SDM845
   - fix Stratix10 mpu_free_clk and sdmmc_free_clk parents
   - mark Rockchip's pclk_rkpwm_pmu as critical clock, due to it
     supplying the pwm used to drive the logic supply of the rk3399
     core"

* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (85 commits)
  clk: rockchip: Add pclk_rkpwm_pmu to PMU critical clocks in rk3399
  clk: cs2000-cp: convert to SPDX identifiers
  clk: scmi: Fix the rounding of clock rate
  clk: qcom: Add display clock controller driver for SDM845
  clk: mvebu: armada-37xx-periph: Remove unused var num_parents
  clk: samsung: Remove unused mout_user_aclk400_mcuisp_p4x12 variable
  clk: actions: Add S700 SoC clock support
  dt-bindings: clock: Add S700 support for Actions Semi Soc's
  clk: actions: Add missing REGMAP_MMIO dependency
  clk: uniphier: add clock frequency support for SPI
  clk: uniphier: add more USB3 PHY clocks
  clk: uniphier: add NAND 200MHz clock
  clk: tegra: make sdmmc2 and sdmmc4 as sdmmc clocks
  clk: tegra: Add sdmmc mux divider clock
  clk: tegra: Refactor fractional divider calculation
  clk: tegra: Fix includes required by fence_udelay()
  clk: imx6sll: fix missing of_node_put()
  clk: imx6ul: fix missing of_node_put()
  clk: imx: add ocram_s clock for i.mx6sx
  clk: mvebu: armada-37xx-periph: Fix wrong return value in get_parent
  ...
This commit is contained in:
Linus Torvalds 2018-08-15 21:41:21 -07:00
commit db06f826ec
122 changed files with 7980 additions and 582 deletions

View File

@ -1,12 +1,14 @@
* Actions S900 Clock Management Unit (CMU)
* Actions Semi Owl 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.
The Actions Semi Owl Clock Management Unit generates and supplies clock
to various controllers within the SoC. The clock binding described here is
applicable to S900 and S700 SoC's.
Required Properties:
- compatible: should be "actions,s900-cmu"
- compatible: should be one of the following,
"actions,s900-cmu"
"actions,s700-cmu"
- reg: physical base address of the controller and length of memory mapped
region.
- clocks: Reference to the parent clocks ("hosc", "losc")
@ -15,16 +17,16 @@ Required Properties:
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.
All available clocks are defined as preprocessor macros in corresponding
dt-bindings/clock/actions,s900-cmu.h or actions,s700-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:
Actions Semi S900 CMU also requires one more clock:
- "losc" - internal low frequency oscillator
Example: Clock Management Unit node:

View File

@ -0,0 +1,56 @@
* Amlogic AXG Audio Clock Controllers
The Amlogic AXG audio clock controller generates and supplies clock to the
other elements of the audio subsystem, such as fifos, i2s, spdif and pdm
devices.
Required Properties:
- compatible : should be "amlogic,axg-audio-clkc" for the A113X and A113D
- reg : physical base address of the clock controller and length of
memory mapped region.
- clocks : a list of phandle + clock-specifier pairs for the clocks listed
in clock-names.
- clock-names : must contain the following:
* "pclk" - Main peripheral bus clock
may contain the following:
* "mst_in[0-7]" - 8 input plls to generate clock signals
* "slv_sclk[0-9]" - 10 slave bit clocks provided by external
components.
* "slv_lrclk[0-9]" - 10 slave sample clocks provided by external
components.
- resets : phandle of the internal reset line
- #clock-cells : should be 1.
Each clock is assigned an identifier and client nodes can use this identifier
to specify the clock which they consume. All available clocks are defined as
preprocessor macros in the dt-bindings/clock/axg-audio-clkc.h header and can be
used in device tree sources.
Example:
clkc_audio: clock-controller@0 {
compatible = "amlogic,axg-audio-clkc";
reg = <0x0 0x0 0x0 0xb4>;
#clock-cells = <1>;
clocks = <&clkc CLKID_AUDIO>,
<&clkc CLKID_MPLL0>,
<&clkc CLKID_MPLL1>,
<&clkc CLKID_MPLL2>,
<&clkc CLKID_MPLL3>,
<&clkc CLKID_HIFI_PLL>,
<&clkc CLKID_FCLK_DIV3>,
<&clkc CLKID_FCLK_DIV4>,
<&clkc CLKID_GP0_PLL>;
clock-names = "pclk",
"mst_in0",
"mst_in1",
"mst_in2",
"mst_in3",
"mst_in4",
"mst_in5",
"mst_in6",
"mst_in7";
resets = <&reset RESET_AUDIO>;
};

View File

@ -91,6 +91,9 @@ Required properties:
at91 audio pll output on AUDIOPLLCLK that feeds the PMC
and can be used by peripheral clock or generic clock
"atmel,sama5d2-clk-i2s-mux" (under pmc node):
at91 I2S clock source selection
Required properties for SCKC node:
- reg : defines the IO memory reserved for the SCKC.
- #size-cells : shall be 0 (reg is used to encode clk id).
@ -500,3 +503,35 @@ For example:
atmel,clk-output-range = <0 83000000>;
};
};
Required properties for I2S mux clocks:
- #size-cells : shall be 0 (reg is used to encode I2S bus id).
- #address-cells : shall be 1 (reg is used to encode I2S bus id).
- name: device tree node describing a specific mux clock.
* #clock-cells : from common clock binding; shall be set to 0.
* clocks : shall be the mux clock parent phandles; shall be 2 phandles:
peripheral and generated clock; the first phandle shall belong to the
peripheral clock and the second one shall belong to the generated
clock; "clock-indices" property can be user to specify
the correct order.
* reg: I2S bus id of the corresponding mux clock.
e.g. reg = <0>; for i2s0, reg = <1>; for i2s1
For example:
i2s_clkmux {
compatible = "atmel,sama5d2-clk-i2s-mux";
#address-cells = <1>;
#size-cells = <0>;
i2s0muxck: i2s0_muxclk {
clocks = <&i2s0_clk>, <&i2s0_gclk>;
#clock-cells = <0>;
reg = <0>;
};
i2s1muxck: i2s1_muxclk {
clocks = <&i2s1_clk>, <&i2s1_gclk>;
#clock-cells = <0>;
reg = <1>;
};
};

View File

@ -0,0 +1,59 @@
Devicetree bindings for Maxim MAX9485 Programmable Audio Clock Generator
This device exposes 4 clocks in total:
- MAX9485_MCLKOUT: A gated, buffered output of the input clock of 27 MHz
- MAX9485_CLKOUT: A PLL that can be configured to 16 different discrete
frequencies
- MAX9485_CLKOUT[1,2]: Two gated outputs for MAX9485_CLKOUT
MAX9485_CLKOUT[1,2] are children of MAX9485_CLKOUT which upchain all rate set
requests.
Required properties:
- compatible: "maxim,max9485"
- clocks: Input clock, must provice 27.000 MHz
- clock-names: Must be set to "xclk"
- #clock-cells: From common clock binding; shall be set to 1
Optional properties:
- reset-gpios: GPIO descriptor connected to the #RESET input pin
- vdd-supply: A regulator node for Vdd
- clock-output-names: Name of output clocks, as defined in common clock
bindings
If not explicitly set, the output names are "mclkout", "clkout", "clkout1"
and "clkout2".
Clocks are defined as preprocessor macros in the dt-binding header.
Example:
#include <dt-bindings/clock/maxim,max9485.h>
xo-27mhz: xo-27mhz {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <27000000>;
};
&i2c0 {
max9485: audio-clock@63 {
reg = <0x63>;
compatible = "maxim,max9485";
clock-names = "xclk";
clocks = <&xo-27mhz>;
reset-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>;
vdd-supply = <&3v3-reg>;
#clock-cells = <1>;
};
};
// Clock consumer node
foo@0 {
compatible = "bar,foo";
/* ... */
clock-names = "foo-input-clk";
clocks = <&max9485 MAX9485_CLKOUT1>;
};

View File

@ -0,0 +1,19 @@
Qualcomm Technologies, Inc. Display Clock Controller Binding
------------------------------------------------------------
Required properties :
- compatible : shall contain "qcom,sdm845-dispcc"
- reg : shall contain base register location and length.
- #clock-cells : from common clock binding, shall contain 1.
- #reset-cells : from common reset binding, shall contain 1.
- #power-domain-cells : from generic power domain binding, shall contain 1.
Example:
dispcc: clock-controller@af00000 {
compatible = "qcom,sdm845-dispcc";
reg = <0xaf00000 0x100000>;
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
};

View File

@ -0,0 +1,43 @@
* Renesas R9A06G032 SYSCTRL
Required Properties:
- compatible: Must be:
- "renesas,r9a06g032-sysctrl"
- reg: Base address and length of the SYSCTRL IO block.
- #clock-cells: Must be 1
- clocks: References to the parent clocks:
- external 40mhz crystal.
- external (optional) 32.768khz
- external (optional) jtag input
- external (optional) RGMII_REFCLK
- clock-names: Must be:
clock-names = "mclk", "rtc", "jtag", "rgmii_ref_ext";
Examples
--------
- SYSCTRL node:
sysctrl: system-controller@4000c000 {
compatible = "renesas,r9a06g032-sysctrl";
reg = <0x4000c000 0x1000>;
#clock-cells = <1>;
clocks = <&ext_mclk>, <&ext_rtc_clk>,
<&ext_jtag_clk>, <&ext_rgmii_ref>;
clock-names = "mclk", "rtc", "jtag", "rgmii_ref_ext";
};
- Other nodes can use the clocks provided by SYSCTRL as in:
#include <dt-bindings/clock/r9a06g032-sysctrl.h>
uart0: serial@40060000 {
compatible = "snps,dw-apb-uart";
reg = <0x40060000 0x400>;
interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
clocks = <&sysctrl R9A06G032_CLK_UART0>;
clock-names = "baudclk";
};

View File

@ -0,0 +1,65 @@
* Rockchip PX30 Clock and Reset Unit
The PX30 clock controller generates and supplies clock to various
controllers within the SoC and also implements a reset controller for SoC
peripherals.
Required Properties:
- compatible: PMU for CRU should be "rockchip,px30-pmu-cru"
- compatible: CRU should be "rockchip,px30-cru"
- reg: physical base address of the controller and length of memory mapped
region.
- #clock-cells: should be 1.
- #reset-cells: should be 1.
Optional Properties:
- rockchip,grf: phandle to the syscon managing the "general register files"
If missing, pll rates are not changeable, due to the missing pll lock status.
Each clock is assigned an identifier and client nodes can use this identifier
to specify the clock which they consume. All available clocks are defined as
preprocessor macros in the dt-bindings/clock/px30-cru.h headers and can be
used in device tree sources. Similar macros exist for the reset sources in
these files.
External clocks:
There are several clocks that are generated outside the SoC. It is expected
that they are defined using standard clock bindings with following
clock-output-names:
- "xin24m" - crystal input - required,
- "xin32k" - rtc clock - optional,
- "i2sx_clkin" - external I2S clock - optional,
- "gmac_clkin" - external GMAC clock - optional
Example: Clock controller node:
pmucru: clock-controller@ff2bc000 {
compatible = "rockchip,px30-pmucru";
reg = <0x0 0xff2bc000 0x0 0x1000>;
#clock-cells = <1>;
#reset-cells = <1>;
};
cru: clock-controller@ff2b0000 {
compatible = "rockchip,px30-cru";
reg = <0x0 0xff2b0000 0x0 0x1000>;
rockchip,grf = <&grf>;
#clock-cells = <1>;
#reset-cells = <1>;
};
Example: UART controller node that consumes the clock generated by the clock
controller:
uart0: serial@ff030000 {
compatible = "rockchip,px30-uart", "snps,dw-apb-uart";
reg = <0x0 0xff030000 0x0 0x100>;
interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&pmucru SCLK_UART0_PMU>, <&pmucru PCLK_UART0_PMU>;
clock-names = "baudclk", "apb_pclk";
reg-shift = <2>;
reg-io-width = <4>;
};

View File

@ -6,6 +6,7 @@ Required properties :
- "allwinner,sun8i-a83t-de2-clk"
- "allwinner,sun8i-h3-de2-clk"
- "allwinner,sun8i-v3s-de2-clk"
- "allwinner,sun50i-a64-de2-clk"
- "allwinner,sun50i-h5-de2-clk"
- reg: Must contain the registers base address and length

View File

@ -27,6 +27,7 @@ config SOC_SAMA5D2
select HAVE_AT91_H32MX
select HAVE_AT91_GENERATED_CLK
select HAVE_AT91_AUDIO_PLL
select HAVE_AT91_I2S_MUX_CLK
select PINCTRL_AT91PIO4
help
Select this if ou are using one of Microchip's SAMA5D2 family SoC.
@ -129,6 +130,9 @@ config HAVE_AT91_GENERATED_CLK
config HAVE_AT91_AUDIO_PLL
bool
config HAVE_AT91_I2S_MUX_CLK
bool
config SOC_SAM_V4_V5
bool

View File

@ -45,6 +45,12 @@ config COMMON_CLK_MAX77686
This driver supports Maxim 77620/77686/77802 crystal oscillator
clock.
config COMMON_CLK_MAX9485
tristate "Maxim 9485 Programmable Clock Generator"
depends on I2C
help
This driver supports Maxim 9485 Programmable Audio Clock Generator
config COMMON_CLK_RK808
tristate "Clock driver for RK805/RK808/RK818"
depends on MFD_RK808

View File

@ -31,6 +31,7 @@ obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-aspeed.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
obj-$(CONFIG_COMMON_CLK_MAX9485) += clk-max9485.o
obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
obj-$(CONFIG_ARCH_NPCM7XX) += clk-npcm7xx.o

View File

@ -1,14 +1,21 @@
config CLK_ACTIONS
bool "Clock driver for Actions Semi SoCs"
depends on ARCH_ACTIONS || COMPILE_TEST
select REGMAP_MMIO
default ARCH_ACTIONS
if CLK_ACTIONS
# SoC Drivers
config CLK_OWL_S700
bool "Support for the Actions Semi OWL S700 clocks"
depends on (ARM64 && ARCH_ACTIONS) || COMPILE_TEST
default ARM64 && ARCH_ACTIONS
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

@ -9,4 +9,5 @@ clk-owl-y += owl-composite.o
clk-owl-y += owl-pll.o
# SoC support
obj-$(CONFIG_CLK_OWL_S700) += owl-s700.o
obj-$(CONFIG_CLK_OWL_S900) += owl-s900.o

View File

@ -0,0 +1,606 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Actions Semi S700 clock driver
*
* Copyright (c) 2014 Actions Semi Inc.
* Author: David Liu <liuwei@actions-semi.com>
*
* Author: Pathiban Nallathambi <pn@denx.de>
* Author: Saravanan Sekar <sravanhome@gmail.com>
*/
#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,s700-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_DSIPLLCLK (0x0028)
#define CMU_CSICLK (0x002C)
#define CMU_DECLK (0x0030)
#define CMU_SICLK (0x0034)
#define CMU_BUSCLK1 (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_UART3CLK (0x0068)
#define CMU_UART4CLK (0x006C)
#define CMU_UART5CLK (0x0070)
#define CMU_UART6CLK (0x0074)
#define CMU_PWM0CLK (0x0078)
#define CMU_PWM1CLK (0x007C)
#define CMU_PWM2CLK (0x0080)
#define CMU_PWM3CLK (0x0084)
#define CMU_PWM4CLK (0x0088)
#define CMU_PWM5CLK (0x008C)
#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_USBPLL (0x00B0)
#define CMU_ETHERNETPLL (0x00B4)
#define CMU_CVBSPLL (0x00B8)
#define CMU_SSTSCLK (0x00C0)
static struct clk_pll_table clk_audio_pll_table[] = {
{0, 45158400}, {1, 49152000},
{0, 0},
};
static struct clk_pll_table clk_cvbs_pll_table[] = {
{27, 29 * 12000000}, {28, 30 * 12000000}, {29, 31 * 12000000},
{30, 32 * 12000000}, {31, 33 * 12000000}, {32, 34 * 12000000},
{33, 35 * 12000000}, {34, 36 * 12000000}, {35, 37 * 12000000},
{36, 38 * 12000000}, {37, 39 * 12000000}, {38, 40 * 12000000},
{39, 41 * 12000000}, {40, 42 * 12000000}, {41, 43 * 12000000},
{42, 44 * 12000000}, {43, 45 * 12000000}, {0, 0},
};
/* pll clocks */
static OWL_PLL_NO_PARENT(clk_core_pll, "core_pll", CMU_COREPLL, 12000000, 9, 0, 8, 4, 174, NULL, CLK_IGNORE_UNUSED);
static OWL_PLL_NO_PARENT(clk_dev_pll, "dev_pll", CMU_DEVPLL, 6000000, 8, 0, 8, 8, 126, NULL, CLK_IGNORE_UNUSED);
static OWL_PLL_NO_PARENT(clk_ddr_pll, "ddr_pll", CMU_DDRPLL, 6000000, 8, 0, 8, 2, 180, NULL, CLK_IGNORE_UNUSED);
static OWL_PLL_NO_PARENT(clk_nand_pll, "nand_pll", CMU_NANDPLL, 6000000, 8, 0, 8, 2, 86, NULL, CLK_IGNORE_UNUSED);
static OWL_PLL_NO_PARENT(clk_display_pll, "display_pll", CMU_DISPLAYPLL, 6000000, 8, 0, 8, 2, 140, NULL, CLK_IGNORE_UNUSED);
static OWL_PLL_NO_PARENT(clk_cvbs_pll, "cvbs_pll", CMU_CVBSPLL, 0, 8, 0, 8, 27, 43, clk_cvbs_pll_table, CLK_IGNORE_UNUSED);
static OWL_PLL_NO_PARENT(clk_audio_pll, "audio_pll", CMU_AUDIOPLL, 0, 4, 0, 1, 0, 0, clk_audio_pll_table, CLK_IGNORE_UNUSED);
static OWL_PLL_NO_PARENT(clk_ethernet_pll, "ethernet_pll", CMU_ETHERNETPLL, 500000000, 0, 0, 0, 0, 0, NULL, CLK_IGNORE_UNUSED);
static const char *cpu_clk_mux_p[] = {"losc", "hosc", "core_pll", "noc1_clk_div"};
static const char *dev_clk_p[] = { "hosc", "dev_pll"};
static const char *noc_clk_mux_p[] = { "dev_clk", "display_pll", "nand_pll", "ddr_pll", "cvbs_pll"};
static const char *csi_clk_mux_p[] = { "display_pll", "dev_clk"};
static const char *de_clk_mux_p[] = { "display_pll", "dev_clk"};
static const char *hde_clk_mux_p[] = { "dev_clk", "display_pll", "nand_pll", "ddr_pll"};
static const char *nand_clk_mux_p[] = { "nand_pll", "display_pll", "dev_clk", "ddr_pll"};
static const char *sd_clk_mux_p[] = { "dev_clk", "nand_pll", };
static const char *uart_clk_mux_p[] = { "hosc", "dev_pll"};
static const char *pwm_clk_mux_p[] = { "losc", "hosc"};
static const char *gpu_clk_mux_p[] = { "dev_clk", "display_pll", "nand_pll", "ddr_clk", "cvbs_pll"};
static const char *lcd_clk_mux_p[] = { "display_pll", "dev_clk" };
static const char *i2s_clk_mux_p[] = { "audio_pll" };
static const char *sensor_clk_mux_p[] = { "hosc", "si"};
/* mux clocks */
static OWL_MUX(clk_cpu, "cpu_clk", cpu_clk_mux_p, CMU_BUSCLK, 0, 2, CLK_SET_RATE_PARENT);
static OWL_MUX(clk_dev, "dev_clk", dev_clk_p, CMU_DEVPLL, 12, 1, CLK_SET_RATE_PARENT);
static OWL_MUX(clk_noc0_clk_mux, "noc0_clk_mux", noc_clk_mux_p, CMU_BUSCLK, 4, 3, CLK_SET_RATE_PARENT);
static OWL_MUX(clk_noc1_clk_mux, "noc1_clk_mux", noc_clk_mux_p, CMU_BUSCLK1, 4, 3, CLK_SET_RATE_PARENT);
static OWL_MUX(clk_hp_clk_mux, "hp_clk_mux", noc_clk_mux_p, CMU_BUSCLK1, 8, 3, CLK_SET_RATE_PARENT);
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},
/* 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},
{0, 0},
};
static struct clk_factor_table lcd_factor_table[] = {
/* bit0 ~ 3 */
{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},
/* bit8: /7 */
{256, 1, 1 * 7}, {257, 1, 2 * 7}, {258, 1, 3 * 7}, {259, 1, 4 * 7},
{260, 1, 5 * 7}, {261, 1, 6 * 7}, {262, 1, 7 * 7}, {263, 1, 8 * 7},
{264, 1, 9 * 7}, {265, 1, 10 * 7}, {266, 1, 11 * 7}, {267, 1, 12 * 7},
{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},
};
static struct clk_div_table rmii_div_table[] = {
{0, 4}, {1, 10},
};
/* divider clocks */
static OWL_DIVIDER(clk_noc0, "noc0_clk", "noc0_clk_mux", CMU_BUSCLK, 16, 2, NULL, 0, 0);
static OWL_DIVIDER(clk_noc1, "noc1_clk", "noc1_clk_mux", CMU_BUSCLK1, 16, 2, NULL, 0, 0);
static OWL_DIVIDER(clk_noc1_clk_div, "noc1_clk_div", "noc1_clk", CMU_BUSCLK1, 20, 1, NULL, 0, 0);
static OWL_DIVIDER(clk_hp_clk_div, "hp_clk_div", "hp_clk_mux", CMU_BUSCLK1, 12, 2, NULL, 0, 0);
static OWL_DIVIDER(clk_ahb, "ahb_clk", "hp_clk_div", CMU_BUSCLK1, 2, 2, NULL, 0, 0);
static OWL_DIVIDER(clk_apb, "apb_clk", "ahb_clk", CMU_BUSCLK1, 14, 2, NULL, 0, 0);
static OWL_DIVIDER(clk_sensor0, "sensor0", "sensor_src", CMU_SENSORCLK, 0, 4, NULL, 0, 0);
static OWL_DIVIDER(clk_sensor1, "sensor1", "sensor_src", CMU_SENSORCLK, 8, 4, NULL, 0, 0);
static OWL_DIVIDER(clk_rmii_ref, "rmii_ref", "ethernet_pll", CMU_ETHERNETPLL, 2, 1, rmii_div_table, 0, 0);
static struct clk_factor_table de_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},
{8, 1, 12}, {0, 0, 0},
};
static struct clk_factor_table hde_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},
};
/* gate clocks */
static OWL_GATE(clk_gpio, "gpio", "apb_clk", CMU_DEVCLKEN1, 25, 0, 0);
static OWL_GATE(clk_dmac, "dmac", "hp_clk_div", CMU_DEVCLKEN0, 17, 0, 0);
static OWL_GATE(clk_timer, "timer", "hosc", CMU_DEVCLKEN1, 22, 0, 0);
static OWL_GATE_NO_PARENT(clk_dsi, "dsi_clk", CMU_DEVCLKEN0, 2, 0, 0);
static OWL_GATE_NO_PARENT(clk_tvout, "tvout_clk", CMU_DEVCLKEN0, 3, 0, 0);
static OWL_GATE_NO_PARENT(clk_hdmi_dev, "hdmi_dev", CMU_DEVCLKEN0, 5, 0, 0);
static OWL_GATE_NO_PARENT(clk_usb3_480mpll0, "usb3_480mpll0", CMU_USBPLL, 3, 0, 0);
static OWL_GATE_NO_PARENT(clk_usb3_480mphy0, "usb3_480mphy0", CMU_USBPLL, 2, 0, 0);
static OWL_GATE_NO_PARENT(clk_usb3_5gphy, "usb3_5gphy", CMU_USBPLL, 1, 0, 0);
static OWL_GATE_NO_PARENT(clk_usb3_cce, "usb3_cce", CMU_DEVCLKEN0, 25, 0, 0);
static OWL_GATE(clk_i2c0, "i2c0", "hosc", CMU_DEVCLKEN1, 0, 0, 0);
static OWL_GATE(clk_i2c1, "i2c1", "hosc", CMU_DEVCLKEN1, 1, 0, 0);
static OWL_GATE(clk_i2c2, "i2c2", "hosc", CMU_DEVCLKEN1, 2, 0, 0);
static OWL_GATE(clk_i2c3, "i2c3", "hosc", CMU_DEVCLKEN1, 3, 0, 0);
static OWL_GATE(clk_spi0, "spi0", "ahb_clk", CMU_DEVCLKEN1, 4, 0, 0);
static OWL_GATE(clk_spi1, "spi1", "ahb_clk", CMU_DEVCLKEN1, 5, 0, 0);
static OWL_GATE(clk_spi2, "spi2", "ahb_clk", CMU_DEVCLKEN1, 6, 0, 0);
static OWL_GATE(clk_spi3, "spi3", "ahb_clk", CMU_DEVCLKEN1, 7, 0, 0);
static OWL_GATE_NO_PARENT(clk_usb2h0_pllen, "usbh0_pllen", CMU_USBPLL, 12, 0, 0);
static OWL_GATE_NO_PARENT(clk_usb2h0_phy, "usbh0_phy", CMU_USBPLL, 10, 0, 0);
static OWL_GATE_NO_PARENT(clk_usb2h0_cce, "usbh0_cce", CMU_DEVCLKEN0, 26, 0, 0);
static OWL_GATE_NO_PARENT(clk_usb2h1_pllen, "usbh1_pllen", CMU_USBPLL, 13, 0, 0);
static OWL_GATE_NO_PARENT(clk_usb2h1_phy, "usbh1_phy", CMU_USBPLL, 11, 0, 0);
static OWL_GATE_NO_PARENT(clk_usb2h1_cce, "usbh1_cce", CMU_DEVCLKEN0, 27, 0, 0);
static OWL_GATE_NO_PARENT(clk_irc_switch, "irc_switch", CMU_DEVCLKEN1, 15, 0, 0);
/* composite clocks */
static OWL_COMP_DIV(clk_csi, "csi", 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(clk_si, "si", csi_clk_mux_p,
OWL_MUX_HW(CMU_SICLK, 4, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 14, 0),
OWL_DIVIDER_HW(CMU_SICLK, 0, 4, 0, NULL),
0);
static OWL_COMP_FACTOR(clk_de, "de", de_clk_mux_p,
OWL_MUX_HW(CMU_DECLK, 12, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 0, 0),
OWL_FACTOR_HW(CMU_DECLK, 0, 3, 0, de_factor_table),
0);
static OWL_COMP_FACTOR(clk_hde, "hde", hde_clk_mux_p,
OWL_MUX_HW(CMU_HDECLK, 4, 2),
OWL_GATE_HW(CMU_DEVCLKEN0, 9, 0),
OWL_FACTOR_HW(CMU_HDECLK, 0, 3, 0, hde_factor_table),
0);
static OWL_COMP_FACTOR(clk_vde, "vde", hde_clk_mux_p,
OWL_MUX_HW(CMU_VDECLK, 4, 2),
OWL_GATE_HW(CMU_DEVCLKEN0, 10, 0),
OWL_FACTOR_HW(CMU_VDECLK, 0, 3, 0, hde_factor_table),
0);
static OWL_COMP_FACTOR(clk_vce, "vce", hde_clk_mux_p,
OWL_MUX_HW(CMU_VCECLK, 4, 2),
OWL_GATE_HW(CMU_DEVCLKEN0, 11, 0),
OWL_FACTOR_HW(CMU_VCECLK, 0, 3, 0, hde_factor_table),
0);
static OWL_COMP_DIV(clk_nand, "nand", nand_clk_mux_p,
OWL_MUX_HW(CMU_NANDCCLK, 8, 2),
OWL_GATE_HW(CMU_DEVCLKEN0, 21, 0),
OWL_DIVIDER_HW(CMU_NANDCCLK, 0, 3, 0, NULL),
CLK_SET_RATE_PARENT);
static OWL_COMP_FACTOR(clk_sd0, "sd0", sd_clk_mux_p,
OWL_MUX_HW(CMU_SD0CLK, 9, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 22, 0),
OWL_FACTOR_HW(CMU_SD0CLK, 0, 9, 0, sd_factor_table),
0);
static OWL_COMP_FACTOR(clk_sd1, "sd1", sd_clk_mux_p,
OWL_MUX_HW(CMU_SD1CLK, 9, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 23, 0),
OWL_FACTOR_HW(CMU_SD1CLK, 0, 9, 0, sd_factor_table),
0);
static OWL_COMP_FACTOR(clk_sd2, "sd2", sd_clk_mux_p,
OWL_MUX_HW(CMU_SD2CLK, 9, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 24, 0),
OWL_FACTOR_HW(CMU_SD2CLK, 0, 9, 0, sd_factor_table),
0);
static OWL_COMP_DIV(clk_uart0, "uart0", uart_clk_mux_p,
OWL_MUX_HW(CMU_UART0CLK, 16, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 8, 0),
OWL_DIVIDER_HW(CMU_UART0CLK, 0, 9, CLK_DIVIDER_ROUND_CLOSEST, NULL),
0);
static OWL_COMP_DIV(clk_uart1, "uart1", uart_clk_mux_p,
OWL_MUX_HW(CMU_UART1CLK, 16, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 9, 0),
OWL_DIVIDER_HW(CMU_UART1CLK, 0, 9, CLK_DIVIDER_ROUND_CLOSEST, NULL),
0);
static OWL_COMP_DIV(clk_uart2, "uart2", uart_clk_mux_p,
OWL_MUX_HW(CMU_UART2CLK, 16, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 10, 0),
OWL_DIVIDER_HW(CMU_UART2CLK, 0, 9, CLK_DIVIDER_ROUND_CLOSEST, NULL),
0);
static OWL_COMP_DIV(clk_uart3, "uart3", uart_clk_mux_p,
OWL_MUX_HW(CMU_UART3CLK, 16, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 11, 0),
OWL_DIVIDER_HW(CMU_UART3CLK, 0, 9, CLK_DIVIDER_ROUND_CLOSEST, NULL),
0);
static OWL_COMP_DIV(clk_uart4, "uart4", uart_clk_mux_p,
OWL_MUX_HW(CMU_UART4CLK, 16, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 12, 0),
OWL_DIVIDER_HW(CMU_UART4CLK, 0, 9, CLK_DIVIDER_ROUND_CLOSEST, NULL),
0);
static OWL_COMP_DIV(clk_uart5, "uart5", uart_clk_mux_p,
OWL_MUX_HW(CMU_UART5CLK, 16, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 13, 0),
OWL_DIVIDER_HW(CMU_UART5CLK, 0, 9, CLK_DIVIDER_ROUND_CLOSEST, NULL),
0);
static OWL_COMP_DIV(clk_uart6, "uart6", uart_clk_mux_p,
OWL_MUX_HW(CMU_UART6CLK, 16, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 14, 0),
OWL_DIVIDER_HW(CMU_UART6CLK, 0, 9, CLK_DIVIDER_ROUND_CLOSEST, NULL),
0);
static OWL_COMP_DIV(clk_pwm0, "pwm0", pwm_clk_mux_p,
OWL_MUX_HW(CMU_PWM0CLK, 12, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 16, 0),
OWL_DIVIDER_HW(CMU_PWM0CLK, 0, 10, 0, NULL),
CLK_IGNORE_UNUSED);
static OWL_COMP_DIV(clk_pwm1, "pwm1", pwm_clk_mux_p,
OWL_MUX_HW(CMU_PWM1CLK, 12, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 17, 0),
OWL_DIVIDER_HW(CMU_PWM1CLK, 0, 10, 0, NULL),
0);
static OWL_COMP_DIV(clk_pwm2, "pwm2", pwm_clk_mux_p,
OWL_MUX_HW(CMU_PWM2CLK, 12, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 18, 0),
OWL_DIVIDER_HW(CMU_PWM2CLK, 0, 10, 0, NULL),
0);
static OWL_COMP_DIV(clk_pwm3, "pwm3", pwm_clk_mux_p,
OWL_MUX_HW(CMU_PWM3CLK, 12, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 19, 0),
OWL_DIVIDER_HW(CMU_PWM3CLK, 0, 10, 0, NULL),
0);
static OWL_COMP_DIV(clk_pwm4, "pwm4", pwm_clk_mux_p,
OWL_MUX_HW(CMU_PWM4CLK, 12, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 20, 0),
OWL_DIVIDER_HW(CMU_PWM4CLK, 0, 10, 0, NULL),
0);
static OWL_COMP_DIV(clk_pwm5, "pwm5", pwm_clk_mux_p,
OWL_MUX_HW(CMU_PWM5CLK, 12, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 21, 0),
OWL_DIVIDER_HW(CMU_PWM5CLK, 0, 10, 0, NULL),
0);
static OWL_COMP_FACTOR(clk_gpu3d, "gpu3d", gpu_clk_mux_p,
OWL_MUX_HW(CMU_GPU3DCLK, 4, 3),
OWL_GATE_HW(CMU_DEVCLKEN0, 8, 0),
OWL_FACTOR_HW(CMU_GPU3DCLK, 0, 3, 0, hde_factor_table),
0);
static OWL_COMP_FACTOR(clk_lcd, "lcd", lcd_clk_mux_p,
OWL_MUX_HW(CMU_LCDCLK, 12, 2),
OWL_GATE_HW(CMU_DEVCLKEN0, 1, 0),
OWL_FACTOR_HW(CMU_LCDCLK, 0, 9, 0, lcd_factor_table),
0);
static OWL_COMP_DIV(clk_hdmi_audio, "hdmia", i2s_clk_mux_p,
OWL_MUX_HW(CMU_AUDIOPLL, 24, 1), /*CMU_AUDIOPLL 24,1 unused*/
OWL_GATE_HW(CMU_DEVCLKEN1, 28, 0),
OWL_DIVIDER_HW(CMU_AUDIOPLL, 24, 4, 0, hdmia_div_table),
0);
static OWL_COMP_DIV(clk_i2srx, "i2srx", i2s_clk_mux_p,
OWL_MUX_HW(CMU_AUDIOPLL, 24, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 27, 0),
OWL_DIVIDER_HW(CMU_AUDIOPLL, 20, 4, 0, hdmia_div_table),
0);
static OWL_COMP_DIV(clk_i2stx, "i2stx", i2s_clk_mux_p,
OWL_MUX_HW(CMU_AUDIOPLL, 24, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 26, 0),
OWL_DIVIDER_HW(CMU_AUDIOPLL, 16, 4, 0, hdmia_div_table),
0);
/* for bluetooth pcm communication */
static OWL_COMP_FIXED_FACTOR(clk_pcm1, "pcm1", "audio_pll",
OWL_GATE_HW(CMU_DEVCLKEN1, 31, 0),
1, 2, 0);
static OWL_COMP_DIV(clk_sensor_src, "sensor_src", sensor_clk_mux_p,
OWL_MUX_HW(CMU_SENSORCLK, 4, 1),
{0},
OWL_DIVIDER_HW(CMU_SENSORCLK, 5, 2, 0, NULL),
0);
static OWL_COMP_FIXED_FACTOR(clk_ethernet, "ethernet", "ethernet_pll",
OWL_GATE_HW(CMU_DEVCLKEN1, 23, 0),
1, 20, 0);
static OWL_COMP_DIV_FIXED(clk_thermal_sensor, "thermal_sensor", "hosc",
OWL_GATE_HW(CMU_DEVCLKEN0, 31, 0),
OWL_DIVIDER_HW(CMU_SSTSCLK, 20, 10, 0, NULL),
0);
static struct owl_clk_common *s700_clks[] = {
&clk_core_pll.common,
&clk_dev_pll.common,
&clk_ddr_pll.common,
&clk_nand_pll.common,
&clk_display_pll.common,
&clk_cvbs_pll .common,
&clk_audio_pll.common,
&clk_ethernet_pll.common,
&clk_cpu.common,
&clk_dev.common,
&clk_ahb.common,
&clk_apb.common,
&clk_dmac.common,
&clk_noc0_clk_mux.common,
&clk_noc1_clk_mux.common,
&clk_hp_clk_mux.common,
&clk_hp_clk_div.common,
&clk_noc1_clk_div.common,
&clk_noc0.common,
&clk_noc1.common,
&clk_sensor_src.common,
&clk_gpio.common,
&clk_timer.common,
&clk_dsi.common,
&clk_csi.common,
&clk_si.common,
&clk_de.common,
&clk_hde.common,
&clk_vde.common,
&clk_vce.common,
&clk_nand.common,
&clk_sd0.common,
&clk_sd1.common,
&clk_sd2.common,
&clk_uart0.common,
&clk_uart1.common,
&clk_uart2.common,
&clk_uart3.common,
&clk_uart4.common,
&clk_uart5.common,
&clk_uart6.common,
&clk_pwm0.common,
&clk_pwm1.common,
&clk_pwm2.common,
&clk_pwm3.common,
&clk_pwm4.common,
&clk_pwm5.common,
&clk_gpu3d.common,
&clk_i2c0.common,
&clk_i2c1.common,
&clk_i2c2.common,
&clk_i2c3.common,
&clk_spi0.common,
&clk_spi1.common,
&clk_spi2.common,
&clk_spi3.common,
&clk_usb3_480mpll0.common,
&clk_usb3_480mphy0.common,
&clk_usb3_5gphy.common,
&clk_usb3_cce.common,
&clk_lcd.common,
&clk_hdmi_audio.common,
&clk_i2srx.common,
&clk_i2stx.common,
&clk_sensor0.common,
&clk_sensor1.common,
&clk_hdmi_dev.common,
&clk_ethernet.common,
&clk_rmii_ref.common,
&clk_usb2h0_pllen.common,
&clk_usb2h0_phy.common,
&clk_usb2h0_cce.common,
&clk_usb2h1_pllen.common,
&clk_usb2h1_phy.common,
&clk_usb2h1_cce.common,
&clk_tvout.common,
&clk_thermal_sensor.common,
&clk_irc_switch.common,
&clk_pcm1.common,
};
static struct clk_hw_onecell_data s700_hw_clks = {
.hws = {
[CLK_CORE_PLL] = &clk_core_pll.common.hw,
[CLK_DEV_PLL] = &clk_dev_pll.common.hw,
[CLK_DDR_PLL] = &clk_ddr_pll.common.hw,
[CLK_NAND_PLL] = &clk_nand_pll.common.hw,
[CLK_DISPLAY_PLL] = &clk_display_pll.common.hw,
[CLK_CVBS_PLL] = &clk_cvbs_pll .common.hw,
[CLK_AUDIO_PLL] = &clk_audio_pll.common.hw,
[CLK_ETHERNET_PLL] = &clk_ethernet_pll.common.hw,
[CLK_CPU] = &clk_cpu.common.hw,
[CLK_DEV] = &clk_dev.common.hw,
[CLK_AHB] = &clk_ahb.common.hw,
[CLK_APB] = &clk_apb.common.hw,
[CLK_DMAC] = &clk_dmac.common.hw,
[CLK_NOC0_CLK_MUX] = &clk_noc0_clk_mux.common.hw,
[CLK_NOC1_CLK_MUX] = &clk_noc1_clk_mux.common.hw,
[CLK_HP_CLK_MUX] = &clk_hp_clk_mux.common.hw,
[CLK_HP_CLK_DIV] = &clk_hp_clk_div.common.hw,
[CLK_NOC1_CLK_DIV] = &clk_noc1_clk_div.common.hw,
[CLK_NOC0] = &clk_noc0.common.hw,
[CLK_NOC1] = &clk_noc1.common.hw,
[CLK_SENOR_SRC] = &clk_sensor_src.common.hw,
[CLK_GPIO] = &clk_gpio.common.hw,
[CLK_TIMER] = &clk_timer.common.hw,
[CLK_DSI] = &clk_dsi.common.hw,
[CLK_CSI] = &clk_csi.common.hw,
[CLK_SI] = &clk_si.common.hw,
[CLK_DE] = &clk_de.common.hw,
[CLK_HDE] = &clk_hde.common.hw,
[CLK_VDE] = &clk_vde.common.hw,
[CLK_VCE] = &clk_vce.common.hw,
[CLK_NAND] = &clk_nand.common.hw,
[CLK_SD0] = &clk_sd0.common.hw,
[CLK_SD1] = &clk_sd1.common.hw,
[CLK_SD2] = &clk_sd2.common.hw,
[CLK_UART0] = &clk_uart0.common.hw,
[CLK_UART1] = &clk_uart1.common.hw,
[CLK_UART2] = &clk_uart2.common.hw,
[CLK_UART3] = &clk_uart3.common.hw,
[CLK_UART4] = &clk_uart4.common.hw,
[CLK_UART5] = &clk_uart5.common.hw,
[CLK_UART6] = &clk_uart6.common.hw,
[CLK_PWM0] = &clk_pwm0.common.hw,
[CLK_PWM1] = &clk_pwm1.common.hw,
[CLK_PWM2] = &clk_pwm2.common.hw,
[CLK_PWM3] = &clk_pwm3.common.hw,
[CLK_PWM4] = &clk_pwm4.common.hw,
[CLK_PWM5] = &clk_pwm5.common.hw,
[CLK_GPU3D] = &clk_gpu3d.common.hw,
[CLK_I2C0] = &clk_i2c0.common.hw,
[CLK_I2C1] = &clk_i2c1.common.hw,
[CLK_I2C2] = &clk_i2c2.common.hw,
[CLK_I2C3] = &clk_i2c3.common.hw,
[CLK_SPI0] = &clk_spi0.common.hw,
[CLK_SPI1] = &clk_spi1.common.hw,
[CLK_SPI2] = &clk_spi2.common.hw,
[CLK_SPI3] = &clk_spi3.common.hw,
[CLK_USB3_480MPLL0] = &clk_usb3_480mpll0.common.hw,
[CLK_USB3_480MPHY0] = &clk_usb3_480mphy0.common.hw,
[CLK_USB3_5GPHY] = &clk_usb3_5gphy.common.hw,
[CLK_USB3_CCE] = &clk_usb3_cce.common.hw,
[CLK_LCD] = &clk_lcd.common.hw,
[CLK_HDMI_AUDIO] = &clk_hdmi_audio.common.hw,
[CLK_I2SRX] = &clk_i2srx.common.hw,
[CLK_I2STX] = &clk_i2stx.common.hw,
[CLK_SENSOR0] = &clk_sensor0.common.hw,
[CLK_SENSOR1] = &clk_sensor1.common.hw,
[CLK_HDMI_DEV] = &clk_hdmi_dev.common.hw,
[CLK_ETHERNET] = &clk_ethernet.common.hw,
[CLK_RMII_REF] = &clk_rmii_ref.common.hw,
[CLK_USB2H0_PLLEN] = &clk_usb2h0_pllen.common.hw,
[CLK_USB2H0_PHY] = &clk_usb2h0_phy.common.hw,
[CLK_USB2H0_CCE] = &clk_usb2h0_cce.common.hw,
[CLK_USB2H1_PLLEN] = &clk_usb2h1_pllen.common.hw,
[CLK_USB2H1_PHY] = &clk_usb2h1_phy.common.hw,
[CLK_USB2H1_CCE] = &clk_usb2h1_cce.common.hw,
[CLK_TVOUT] = &clk_tvout.common.hw,
[CLK_THERMAL_SENSOR] = &clk_thermal_sensor.common.hw,
[CLK_IRC_SWITCH] = &clk_irc_switch.common.hw,
[CLK_PCM1] = &clk_pcm1.common.hw,
},
.num = CLK_NR_CLKS,
};
static const struct owl_clk_desc s700_clk_desc = {
.clks = s700_clks,
.num_clks = ARRAY_SIZE(s700_clks),
.hw_clks = &s700_hw_clks,
};
static int s700_clk_probe(struct platform_device *pdev)
{
const struct owl_clk_desc *desc;
desc = &s700_clk_desc;
owl_clk_regmap_init(pdev, desc);
return owl_clk_probe(&pdev->dev, desc->hw_clks);
}
static const struct of_device_id s700_clk_of_match[] = {
{ .compatible = "actions,s700-cmu", },
{ /* sentinel */ }
};
static struct platform_driver s700_clk_driver = {
.probe = s700_clk_probe,
.driver = {
.name = "s700-cmu",
.of_match_table = s700_clk_of_match
},
};
static int __init s700_clk_init(void)
{
return platform_driver_register(&s700_clk_driver);
}
core_initcall(s700_clk_init);

View File

@ -13,3 +13,4 @@ obj-$(CONFIG_HAVE_AT91_USB_CLK) += clk-usb.o
obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o
obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o
obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o
obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o

View File

@ -0,0 +1,116 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2018 Microchip Technology Inc,
* Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
*
*
*/
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <soc/at91/atmel-sfr.h>
#define I2S_BUS_NR 2
struct clk_i2s_mux {
struct clk_hw hw;
struct regmap *regmap;
u8 bus_id;
};
#define to_clk_i2s_mux(hw) container_of(hw, struct clk_i2s_mux, hw)
static u8 clk_i2s_mux_get_parent(struct clk_hw *hw)
{
struct clk_i2s_mux *mux = to_clk_i2s_mux(hw);
u32 val;
regmap_read(mux->regmap, AT91_SFR_I2SCLKSEL, &val);
return (val & BIT(mux->bus_id)) >> mux->bus_id;
}
static int clk_i2s_mux_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_i2s_mux *mux = to_clk_i2s_mux(hw);
return regmap_update_bits(mux->regmap, AT91_SFR_I2SCLKSEL,
BIT(mux->bus_id), index << mux->bus_id);
}
static const struct clk_ops clk_i2s_mux_ops = {
.get_parent = clk_i2s_mux_get_parent,
.set_parent = clk_i2s_mux_set_parent,
.determine_rate = __clk_mux_determine_rate,
};
static struct clk_hw * __init
at91_clk_i2s_mux_register(struct regmap *regmap, const char *name,
const char * const *parent_names,
unsigned int num_parents, u8 bus_id)
{
struct clk_init_data init = {};
struct clk_i2s_mux *i2s_ck;
int ret;
i2s_ck = kzalloc(sizeof(*i2s_ck), GFP_KERNEL);
if (!i2s_ck)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &clk_i2s_mux_ops;
init.parent_names = parent_names;
init.num_parents = num_parents;
i2s_ck->hw.init = &init;
i2s_ck->bus_id = bus_id;
i2s_ck->regmap = regmap;
ret = clk_hw_register(NULL, &i2s_ck->hw);
if (ret) {
kfree(i2s_ck);
return ERR_PTR(ret);
}
return &i2s_ck->hw;
}
static void __init of_sama5d2_clk_i2s_mux_setup(struct device_node *np)
{
struct regmap *regmap_sfr;
u8 bus_id;
const char *parent_names[2];
struct device_node *i2s_mux_np;
struct clk_hw *hw;
int ret;
regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr");
if (IS_ERR(regmap_sfr))
return;
for_each_child_of_node(np, i2s_mux_np) {
if (of_property_read_u8(i2s_mux_np, "reg", &bus_id))
continue;
if (bus_id > I2S_BUS_NR)
continue;
ret = of_clk_parent_fill(i2s_mux_np, parent_names, 2);
if (ret != 2)
continue;
hw = at91_clk_i2s_mux_register(regmap_sfr, i2s_mux_np->name,
parent_names, 2, bus_id);
if (IS_ERR(hw))
continue;
of_clk_add_hw_provider(i2s_mux_np, of_clk_hw_simple_get, hw);
}
}
CLK_OF_DECLARE(sama5d2_clk_i2s_mux, "atmel,sama5d2-clk-i2s-mux",
of_sama5d2_clk_i2s_mux_setup);

View File

@ -109,7 +109,7 @@ static const struct aspeed_gate_data aspeed_gates[] = {
[ASPEED_CLK_GATE_RSACLK] = { 24, -1, "rsaclk-gate", NULL, 0 }, /* RSA */
[ASPEED_CLK_GATE_UART3CLK] = { 25, -1, "uart3clk-gate", "uart", 0 }, /* UART3 */
[ASPEED_CLK_GATE_UART4CLK] = { 26, -1, "uart4clk-gate", "uart", 0 }, /* UART4 */
[ASPEED_CLK_GATE_SDCLKCLK] = { 27, 16, "sdclk-gate", NULL, 0 }, /* SDIO/SD */
[ASPEED_CLK_GATE_SDCLK] = { 27, 16, "sdclk-gate", NULL, 0 }, /* SDIO/SD */
[ASPEED_CLK_GATE_LHCCLK] = { 28, -1, "lhclk-gate", "lhclk", 0 }, /* LPC master/LPC+ */
};

View File

@ -1,12 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/*
* CS2000 -- CIRRUS LOGIC Fractional-N Clock Synthesizer & Clock Multiplier
*
* Copyright (C) 2015 Renesas Electronics Corporation
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk-provider.h>
#include <linux/delay.h>

View File

@ -177,8 +177,15 @@ static struct clk *_of_fixed_factor_clk_setup(struct device_node *node)
clk = clk_register_fixed_factor(NULL, clk_name, parent_name, flags,
mult, div);
if (IS_ERR(clk))
if (IS_ERR(clk)) {
/*
* If parent clock is not registered, registration would fail.
* Clear OF_POPULATED flag so that clock registration can be
* attempted again from probe function.
*/
of_node_clear_flag(node, OF_POPULATED);
return clk;
}
ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
if (ret) {

387
drivers/clk/clk-max9485.c Normal file
View File

@ -0,0 +1,387 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/regulator/consumer.h>
#include <dt-bindings/clock/maxim,max9485.h>
#define MAX9485_NUM_CLKS 4
/* This chip has only one register of 8 bit width. */
#define MAX9485_FS_12KHZ (0 << 0)
#define MAX9485_FS_32KHZ (1 << 0)
#define MAX9485_FS_44_1KHZ (2 << 0)
#define MAX9485_FS_48KHZ (3 << 0)
#define MAX9485_SCALE_256 (0 << 2)
#define MAX9485_SCALE_384 (1 << 2)
#define MAX9485_SCALE_768 (2 << 2)
#define MAX9485_DOUBLE BIT(4)
#define MAX9485_CLKOUT1_ENABLE BIT(5)
#define MAX9485_CLKOUT2_ENABLE BIT(6)
#define MAX9485_MCLK_ENABLE BIT(7)
#define MAX9485_FREQ_MASK 0x1f
struct max9485_rate {
unsigned long out;
u8 reg_value;
};
/*
* Ordered by frequency. For frequency the hardware can generate with
* multiple settings, the one with lowest jitter is listed first.
*/
static const struct max9485_rate max9485_rates[] = {
{ 3072000, MAX9485_FS_12KHZ | MAX9485_SCALE_256 },
{ 4608000, MAX9485_FS_12KHZ | MAX9485_SCALE_384 },
{ 8192000, MAX9485_FS_32KHZ | MAX9485_SCALE_256 },
{ 9126000, MAX9485_FS_12KHZ | MAX9485_SCALE_768 },
{ 11289600, MAX9485_FS_44_1KHZ | MAX9485_SCALE_256 },
{ 12288000, MAX9485_FS_48KHZ | MAX9485_SCALE_256 },
{ 12288000, MAX9485_FS_32KHZ | MAX9485_SCALE_384 },
{ 16384000, MAX9485_FS_32KHZ | MAX9485_SCALE_256 | MAX9485_DOUBLE },
{ 16934400, MAX9485_FS_44_1KHZ | MAX9485_SCALE_384 },
{ 18384000, MAX9485_FS_48KHZ | MAX9485_SCALE_384 },
{ 22579200, MAX9485_FS_44_1KHZ | MAX9485_SCALE_256 | MAX9485_DOUBLE },
{ 24576000, MAX9485_FS_48KHZ | MAX9485_SCALE_256 | MAX9485_DOUBLE },
{ 24576000, MAX9485_FS_32KHZ | MAX9485_SCALE_384 | MAX9485_DOUBLE },
{ 24576000, MAX9485_FS_32KHZ | MAX9485_SCALE_768 },
{ 33868800, MAX9485_FS_44_1KHZ | MAX9485_SCALE_384 | MAX9485_DOUBLE },
{ 33868800, MAX9485_FS_44_1KHZ | MAX9485_SCALE_768 },
{ 36864000, MAX9485_FS_48KHZ | MAX9485_SCALE_384 | MAX9485_DOUBLE },
{ 36864000, MAX9485_FS_48KHZ | MAX9485_SCALE_768 },
{ 49152000, MAX9485_FS_32KHZ | MAX9485_SCALE_768 | MAX9485_DOUBLE },
{ 67737600, MAX9485_FS_44_1KHZ | MAX9485_SCALE_768 | MAX9485_DOUBLE },
{ 73728000, MAX9485_FS_48KHZ | MAX9485_SCALE_768 | MAX9485_DOUBLE },
{ } /* sentinel */
};
struct max9485_driver_data;
struct max9485_clk_hw {
struct clk_hw hw;
struct clk_init_data init;
u8 enable_bit;
struct max9485_driver_data *drvdata;
};
struct max9485_driver_data {
struct clk *xclk;
struct i2c_client *client;
u8 reg_value;
struct regulator *supply;
struct gpio_desc *reset_gpio;
struct max9485_clk_hw hw[MAX9485_NUM_CLKS];
};
static inline struct max9485_clk_hw *to_max9485_clk(struct clk_hw *hw)
{
return container_of(hw, struct max9485_clk_hw, hw);
}
static int max9485_update_bits(struct max9485_driver_data *drvdata,
u8 mask, u8 value)
{
int ret;
drvdata->reg_value &= ~mask;
drvdata->reg_value |= value;
dev_dbg(&drvdata->client->dev,
"updating mask 0x%02x value 0x%02x -> 0x%02x\n",
mask, value, drvdata->reg_value);
ret = i2c_master_send(drvdata->client,
&drvdata->reg_value,
sizeof(drvdata->reg_value));
return ret < 0 ? ret : 0;
}
static int max9485_clk_prepare(struct clk_hw *hw)
{
struct max9485_clk_hw *clk_hw = to_max9485_clk(hw);
return max9485_update_bits(clk_hw->drvdata,
clk_hw->enable_bit,
clk_hw->enable_bit);
}
static void max9485_clk_unprepare(struct clk_hw *hw)
{
struct max9485_clk_hw *clk_hw = to_max9485_clk(hw);
max9485_update_bits(clk_hw->drvdata, clk_hw->enable_bit, 0);
}
/*
* CLKOUT - configurable clock output
*/
static int max9485_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct max9485_clk_hw *clk_hw = to_max9485_clk(hw);
const struct max9485_rate *entry;
for (entry = max9485_rates; entry->out != 0; entry++)
if (entry->out == rate)
break;
if (entry->out == 0)
return -EINVAL;
return max9485_update_bits(clk_hw->drvdata,
MAX9485_FREQ_MASK,
entry->reg_value);
}
static unsigned long max9485_clkout_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct max9485_clk_hw *clk_hw = to_max9485_clk(hw);
struct max9485_driver_data *drvdata = clk_hw->drvdata;
u8 val = drvdata->reg_value & MAX9485_FREQ_MASK;
const struct max9485_rate *entry;
for (entry = max9485_rates; entry->out != 0; entry++)
if (val == entry->reg_value)
return entry->out;
return 0;
}
static long max9485_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
const struct max9485_rate *curr, *prev = NULL;
for (curr = max9485_rates; curr->out != 0; curr++) {
/* Exact matches */
if (curr->out == rate)
return rate;
/*
* Find the first entry that has a frequency higher than the
* requested one.
*/
if (curr->out > rate) {
unsigned int mid;
/*
* If this is the first entry, clamp the value to the
* lowest possible frequency.
*/
if (!prev)
return curr->out;
/*
* Otherwise, determine whether the previous entry or
* current one is closer.
*/
mid = prev->out + ((curr->out - prev->out) / 2);
return (mid > rate) ? prev->out : curr->out;
}
prev = curr;
}
/* If the last entry was still too high, clamp the value */
return prev->out;
}
struct max9485_clk {
const char *name;
int parent_index;
const struct clk_ops ops;
u8 enable_bit;
};
static const struct max9485_clk max9485_clks[MAX9485_NUM_CLKS] = {
[MAX9485_MCLKOUT] = {
.name = "mclkout",
.parent_index = -1,
.enable_bit = MAX9485_MCLK_ENABLE,
.ops = {
.prepare = max9485_clk_prepare,
.unprepare = max9485_clk_unprepare,
},
},
[MAX9485_CLKOUT] = {
.name = "clkout",
.parent_index = -1,
.ops = {
.set_rate = max9485_clkout_set_rate,
.round_rate = max9485_clkout_round_rate,
.recalc_rate = max9485_clkout_recalc_rate,
},
},
[MAX9485_CLKOUT1] = {
.name = "clkout1",
.parent_index = MAX9485_CLKOUT,
.enable_bit = MAX9485_CLKOUT1_ENABLE,
.ops = {
.prepare = max9485_clk_prepare,
.unprepare = max9485_clk_unprepare,
},
},
[MAX9485_CLKOUT2] = {
.name = "clkout2",
.parent_index = MAX9485_CLKOUT,
.enable_bit = MAX9485_CLKOUT2_ENABLE,
.ops = {
.prepare = max9485_clk_prepare,
.unprepare = max9485_clk_unprepare,
},
},
};
static struct clk_hw *
max9485_of_clk_get(struct of_phandle_args *clkspec, void *data)
{
struct max9485_driver_data *drvdata = data;
unsigned int idx = clkspec->args[0];
return &drvdata->hw[idx].hw;
}
static int max9485_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct max9485_driver_data *drvdata;
struct device *dev = &client->dev;
const char *xclk_name;
int i, ret;
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
drvdata->xclk = devm_clk_get(dev, "xclk");
if (IS_ERR(drvdata->xclk))
return PTR_ERR(drvdata->xclk);
xclk_name = __clk_get_name(drvdata->xclk);
drvdata->supply = devm_regulator_get(dev, "vdd");
if (IS_ERR(drvdata->supply))
return PTR_ERR(drvdata->supply);
ret = regulator_enable(drvdata->supply);
if (ret < 0)
return ret;
drvdata->reset_gpio =
devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(drvdata->reset_gpio))
return PTR_ERR(drvdata->reset_gpio);
i2c_set_clientdata(client, drvdata);
drvdata->client = client;
ret = i2c_master_recv(drvdata->client, &drvdata->reg_value,
sizeof(drvdata->reg_value));
if (ret < 0) {
dev_warn(dev, "Unable to read device register: %d\n", ret);
return ret;
}
for (i = 0; i < MAX9485_NUM_CLKS; i++) {
int parent_index = max9485_clks[i].parent_index;
const char *name;
if (of_property_read_string_index(dev->of_node,
"clock-output-names",
i, &name) == 0) {
drvdata->hw[i].init.name = name;
} else {
drvdata->hw[i].init.name = max9485_clks[i].name;
}
drvdata->hw[i].init.ops = &max9485_clks[i].ops;
drvdata->hw[i].init.num_parents = 1;
drvdata->hw[i].init.flags = 0;
if (parent_index > 0) {
drvdata->hw[i].init.parent_names =
&drvdata->hw[parent_index].init.name;
drvdata->hw[i].init.flags |= CLK_SET_RATE_PARENT;
} else {
drvdata->hw[i].init.parent_names = &xclk_name;
}
drvdata->hw[i].enable_bit = max9485_clks[i].enable_bit;
drvdata->hw[i].hw.init = &drvdata->hw[i].init;
drvdata->hw[i].drvdata = drvdata;
ret = devm_clk_hw_register(dev, &drvdata->hw[i].hw);
if (ret < 0)
return ret;
}
return devm_of_clk_add_hw_provider(dev, max9485_of_clk_get, drvdata);
}
static int __maybe_unused max9485_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct max9485_driver_data *drvdata = i2c_get_clientdata(client);
gpiod_set_value_cansleep(drvdata->reset_gpio, 0);
return 0;
}
static int __maybe_unused max9485_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct max9485_driver_data *drvdata = i2c_get_clientdata(client);
int ret;
gpiod_set_value_cansleep(drvdata->reset_gpio, 1);
ret = i2c_master_send(client, &drvdata->reg_value,
sizeof(drvdata->reg_value));
return ret < 0 ? ret : 0;
}
static const struct dev_pm_ops max9485_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(max9485_suspend, max9485_resume)
};
static const struct of_device_id max9485_dt_ids[] = {
{ .compatible = "maxim,max9485", },
{ }
};
MODULE_DEVICE_TABLE(of, max9485_dt_ids);
static const struct i2c_device_id max9485_i2c_ids[] = {
{ .name = "max9485", },
{ }
};
MODULE_DEVICE_TABLE(i2c, max9485_i2c_ids);
static struct i2c_driver max9485_driver = {
.driver = {
.name = "max9485",
.pm = &max9485_pm_ops,
.of_match_table = max9485_dt_ids,
},
.probe = max9485_i2c_probe,
.id_table = max9485_i2c_ids,
};
module_i2c_driver(max9485_driver);
MODULE_AUTHOR("Daniel Mack <daniel@zonque.org>");
MODULE_DESCRIPTION("MAX9485 Programmable Audio Clock Generator");
MODULE_LICENSE("GPL v2");

View File

@ -38,7 +38,6 @@ static unsigned long scmi_clk_recalc_rate(struct clk_hw *hw,
static long scmi_clk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
int step;
u64 fmin, fmax, ftmp;
struct scmi_clk *clk = to_scmi_clk(hw);
@ -60,9 +59,9 @@ static long scmi_clk_round_rate(struct clk_hw *hw, unsigned long rate,
ftmp = rate - fmin;
ftmp += clk->info->range.step_size - 1; /* to round up */
step = do_div(ftmp, clk->info->range.step_size);
do_div(ftmp, clk->info->range.step_size);
return step * clk->info->range.step_size + fmin;
return ftmp * clk->info->range.step_size + fmin;
}
static int scmi_clk_set_rate(struct clk_hw *hw, unsigned long rate,

View File

@ -74,6 +74,33 @@ static int si514_enable_output(struct clk_si514 *data, bool enable)
SI514_CONTROL_OE, enable ? SI514_CONTROL_OE : 0);
}
static int si514_prepare(struct clk_hw *hw)
{
struct clk_si514 *data = to_clk_si514(hw);
return si514_enable_output(data, true);
}
static void si514_unprepare(struct clk_hw *hw)
{
struct clk_si514 *data = to_clk_si514(hw);
si514_enable_output(data, false);
}
static int si514_is_prepared(struct clk_hw *hw)
{
struct clk_si514 *data = to_clk_si514(hw);
unsigned int val;
int err;
err = regmap_read(data->regmap, SI514_REG_CONTROL, &val);
if (err < 0)
return err;
return !!(val & SI514_CONTROL_OE);
}
/* Retrieve clock multiplier and dividers from hardware */
static int si514_get_muldiv(struct clk_si514 *data,
struct clk_si514_muldiv *settings)
@ -235,12 +262,17 @@ static int si514_set_rate(struct clk_hw *hw, unsigned long rate,
{
struct clk_si514 *data = to_clk_si514(hw);
struct clk_si514_muldiv settings;
unsigned int old_oe_state;
int err;
err = si514_calc_muldiv(&settings, rate);
if (err)
return err;
err = regmap_read(data->regmap, SI514_REG_CONTROL, &old_oe_state);
if (err)
return err;
si514_enable_output(data, false);
err = si514_set_muldiv(data, &settings);
@ -255,12 +287,16 @@ static int si514_set_rate(struct clk_hw *hw, unsigned long rate,
/* Applying a new frequency can take up to 10ms */
usleep_range(10000, 12000);
si514_enable_output(data, true);
if (old_oe_state & SI514_CONTROL_OE)
si514_enable_output(data, true);
return err;
}
static const struct clk_ops si514_clk_ops = {
.prepare = si514_prepare,
.unprepare = si514_unprepare,
.is_prepared = si514_is_prepared,
.recalc_rate = si514_recalc_rate,
.round_rate = si514_round_rate,
.set_rate = si514_set_rate,

View File

@ -86,6 +86,33 @@ static int si544_enable_output(struct clk_si544 *data, bool enable)
SI544_OE_STATE_ODC_OE, enable ? SI544_OE_STATE_ODC_OE : 0);
}
static int si544_prepare(struct clk_hw *hw)
{
struct clk_si544 *data = to_clk_si544(hw);
return si544_enable_output(data, true);
}
static void si544_unprepare(struct clk_hw *hw)
{
struct clk_si544 *data = to_clk_si544(hw);
si544_enable_output(data, false);
}
static int si544_is_prepared(struct clk_hw *hw)
{
struct clk_si544 *data = to_clk_si544(hw);
unsigned int val;
int err;
err = regmap_read(data->regmap, SI544_REG_OE_STATE, &val);
if (err < 0)
return err;
return !!(val & SI544_OE_STATE_ODC_OE);
}
/* Retrieve clock multiplier and dividers from hardware */
static int si544_get_muldiv(struct clk_si544 *data,
struct clk_si544_muldiv *settings)
@ -273,6 +300,7 @@ static int si544_set_rate(struct clk_hw *hw, unsigned long rate,
{
struct clk_si544 *data = to_clk_si544(hw);
struct clk_si544_muldiv settings;
unsigned int old_oe_state;
int err;
if (!is_valid_frequency(data, rate))
@ -282,6 +310,10 @@ static int si544_set_rate(struct clk_hw *hw, unsigned long rate,
if (err)
return err;
err = regmap_read(data->regmap, SI544_REG_OE_STATE, &old_oe_state);
if (err)
return err;
si544_enable_output(data, false);
/* Allow FCAL for this frequency update */
@ -303,12 +335,16 @@ static int si544_set_rate(struct clk_hw *hw, unsigned long rate,
/* Applying a new frequency can take up to 10ms */
usleep_range(10000, 12000);
si544_enable_output(data, true);
if (old_oe_state & SI544_OE_STATE_ODC_OE)
si544_enable_output(data, true);
return err;
}
static const struct clk_ops si544_clk_ops = {
.prepare = si544_prepare,
.unprepare = si544_unprepare,
.is_prepared = si544_is_prepared,
.recalc_rate = si544_recalc_rate,
.round_rate = si544_round_rate,
.set_rate = si544_set_rate,

View File

@ -691,6 +691,9 @@ static void clk_core_unprepare(struct clk_core *core)
"Unpreparing critical %s\n", core->name))
return;
if (core->flags & CLK_SET_RATE_GATE)
clk_core_rate_unprotect(core);
if (--core->prepare_count > 0)
return;
@ -765,6 +768,16 @@ static int clk_core_prepare(struct clk_core *core)
core->prepare_count++;
/*
* CLK_SET_RATE_GATE is a special case of clock protection
* Instead of a consumer claiming exclusive rate control, it is
* actually the provider which prevents any consumer from making any
* operation which could result in a rate change or rate glitch while
* the clock is prepared.
*/
if (core->flags & CLK_SET_RATE_GATE)
clk_core_rate_protect(core);
return 0;
unprepare:
clk_core_unprepare(core->parent);
@ -1888,9 +1901,6 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
if (clk_core_rate_is_protected(core))
return -EBUSY;
if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count)
return -EBUSY;
/* calculate new rates and get the topmost changed clock */
top = clk_calc_new_rates(core, req_rate);
if (!top)
@ -3122,6 +3132,7 @@ struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
return clk;
}
/* keep in sync with __clk_put */
void __clk_free_clk(struct clk *clk)
{
clk_prepare_lock();
@ -3501,6 +3512,7 @@ int __clk_get(struct clk *clk)
return 1;
}
/* keep in sync with __clk_free_clk */
void __clk_put(struct clk *clk)
{
struct module *owner;
@ -3534,6 +3546,7 @@ void __clk_put(struct clk *clk)
module_put(owner);
kfree_const(clk->con_id);
kfree(clk);
}

View File

@ -16,6 +16,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/sizes.h>
#include <soc/imx/revision.h>
#include <dt-bindings/clock/imx5-clock.h>
@ -175,13 +176,13 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base)
clk[IMX5_CLK_PER_ROOT] = imx_clk_mux("per_root", MXC_CCM_CBCMR, 0, 1,
per_root_sel, ARRAY_SIZE(per_root_sel));
clk[IMX5_CLK_AHB] = imx_clk_divider("ahb", "main_bus", MXC_CCM_CBCDR, 10, 3);
clk[IMX5_CLK_AHB_MAX] = imx_clk_gate2("ahb_max", "ahb", MXC_CCM_CCGR0, 28);
clk[IMX5_CLK_AIPS_TZ1] = imx_clk_gate2("aips_tz1", "ahb", MXC_CCM_CCGR0, 24);
clk[IMX5_CLK_AIPS_TZ2] = imx_clk_gate2("aips_tz2", "ahb", MXC_CCM_CCGR0, 26);
clk[IMX5_CLK_TMAX1] = imx_clk_gate2("tmax1", "ahb", MXC_CCM_CCGR1, 0);
clk[IMX5_CLK_TMAX2] = imx_clk_gate2("tmax2", "ahb", MXC_CCM_CCGR1, 2);
clk[IMX5_CLK_TMAX3] = imx_clk_gate2("tmax3", "ahb", MXC_CCM_CCGR1, 4);
clk[IMX5_CLK_SPBA] = imx_clk_gate2("spba", "ipg", MXC_CCM_CCGR5, 0);
clk[IMX5_CLK_AHB_MAX] = imx_clk_gate2_flags("ahb_max", "ahb", MXC_CCM_CCGR0, 28, CLK_IS_CRITICAL);
clk[IMX5_CLK_AIPS_TZ1] = imx_clk_gate2_flags("aips_tz1", "ahb", MXC_CCM_CCGR0, 24, CLK_IS_CRITICAL);
clk[IMX5_CLK_AIPS_TZ2] = imx_clk_gate2_flags("aips_tz2", "ahb", MXC_CCM_CCGR0, 26, CLK_IS_CRITICAL);
clk[IMX5_CLK_TMAX1] = imx_clk_gate2_flags("tmax1", "ahb", MXC_CCM_CCGR1, 0, CLK_IS_CRITICAL);
clk[IMX5_CLK_TMAX2] = imx_clk_gate2_flags("tmax2", "ahb", MXC_CCM_CCGR1, 2, CLK_IS_CRITICAL);
clk[IMX5_CLK_TMAX3] = imx_clk_gate2_flags("tmax3", "ahb", MXC_CCM_CCGR1, 4, CLK_IS_CRITICAL);
clk[IMX5_CLK_SPBA] = imx_clk_gate2_flags("spba", "ipg", MXC_CCM_CCGR5, 0, CLK_IS_CRITICAL);
clk[IMX5_CLK_IPG] = imx_clk_divider("ipg", "ahb", MXC_CCM_CBCDR, 8, 2);
clk[IMX5_CLK_AXI_A] = imx_clk_divider("axi_a", "main_bus", MXC_CCM_CBCDR, 16, 3);
clk[IMX5_CLK_AXI_B] = imx_clk_divider("axi_b", "main_bus", MXC_CCM_CBCDR, 19, 3);
@ -252,8 +253,8 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base)
clk[IMX5_CLK_ECSPI2_PER_GATE] = imx_clk_gate2("ecspi2_per_gate", "ecspi_podf", MXC_CCM_CCGR4, 24);
clk[IMX5_CLK_CSPI_IPG_GATE] = imx_clk_gate2("cspi_ipg_gate", "ipg", MXC_CCM_CCGR4, 26);
clk[IMX5_CLK_SDMA_GATE] = imx_clk_gate2("sdma_gate", "ipg", MXC_CCM_CCGR4, 30);
clk[IMX5_CLK_EMI_FAST_GATE] = imx_clk_gate2("emi_fast_gate", "dummy", MXC_CCM_CCGR5, 14);
clk[IMX5_CLK_EMI_SLOW_GATE] = imx_clk_gate2("emi_slow_gate", "emi_slow_podf", MXC_CCM_CCGR5, 16);
clk[IMX5_CLK_EMI_FAST_GATE] = imx_clk_gate2_flags("emi_fast_gate", "dummy", MXC_CCM_CCGR5, 14, CLK_IS_CRITICAL);
clk[IMX5_CLK_EMI_SLOW_GATE] = imx_clk_gate2_flags("emi_slow_gate", "emi_slow_podf", MXC_CCM_CCGR5, 16, CLK_IS_CRITICAL);
clk[IMX5_CLK_IPU_SEL] = imx_clk_mux("ipu_sel", MXC_CCM_CBCMR, 6, 2, ipu_sel, ARRAY_SIZE(ipu_sel));
clk[IMX5_CLK_IPU_GATE] = imx_clk_gate2("ipu_gate", "ipu_sel", MXC_CCM_CCGR5, 10);
clk[IMX5_CLK_NFC_GATE] = imx_clk_gate2("nfc_gate", "nfc_podf", MXC_CCM_CCGR5, 20);
@ -267,7 +268,7 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base)
clk[IMX5_CLK_VPU_SEL] = imx_clk_mux("vpu_sel", MXC_CCM_CBCMR, 14, 2, vpu_sel, ARRAY_SIZE(vpu_sel));
clk[IMX5_CLK_VPU_GATE] = imx_clk_gate2("vpu_gate", "vpu_sel", MXC_CCM_CCGR5, 6);
clk[IMX5_CLK_VPU_REFERENCE_GATE] = imx_clk_gate2("vpu_reference_gate", "osc", MXC_CCM_CCGR5, 8);
clk[IMX5_CLK_GPC_DVFS] = imx_clk_gate2("gpc_dvfs", "dummy", MXC_CCM_CCGR5, 24);
clk[IMX5_CLK_GPC_DVFS] = imx_clk_gate2_flags("gpc_dvfs", "dummy", MXC_CCM_CCGR5, 24, CLK_IS_CRITICAL);
clk[IMX5_CLK_SSI_APM] = imx_clk_mux("ssi_apm", MXC_CCM_CSCMR1, 8, 2, ssi_apm_sels, ARRAY_SIZE(ssi_apm_sels));
clk[IMX5_CLK_SSI1_ROOT_SEL] = imx_clk_mux("ssi1_root_sel", MXC_CCM_CSCMR1, 14, 2, ssi_clk_sels, ARRAY_SIZE(ssi_clk_sels));
@ -316,21 +317,6 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base)
/* move usb phy clk to 24MHz */
clk_set_parent(clk[IMX5_CLK_USB_PHY_SEL], clk[IMX5_CLK_OSC]);
clk_prepare_enable(clk[IMX5_CLK_GPC_DVFS]);
clk_prepare_enable(clk[IMX5_CLK_AHB_MAX]); /* esdhc3 */
clk_prepare_enable(clk[IMX5_CLK_AIPS_TZ1]);
clk_prepare_enable(clk[IMX5_CLK_AIPS_TZ2]); /* fec */
clk_prepare_enable(clk[IMX5_CLK_SPBA]);
clk_prepare_enable(clk[IMX5_CLK_EMI_FAST_GATE]); /* fec */
clk_prepare_enable(clk[IMX5_CLK_EMI_SLOW_GATE]); /* eim */
clk_prepare_enable(clk[IMX5_CLK_MIPI_HSC1_GATE]);
clk_prepare_enable(clk[IMX5_CLK_MIPI_HSC2_GATE]);
clk_prepare_enable(clk[IMX5_CLK_MIPI_ESC_GATE]);
clk_prepare_enable(clk[IMX5_CLK_MIPI_HSP_GATE]);
clk_prepare_enable(clk[IMX5_CLK_TMAX1]);
clk_prepare_enable(clk[IMX5_CLK_TMAX2]); /* esdhc2, fec */
clk_prepare_enable(clk[IMX5_CLK_TMAX3]); /* esdhc1, esdhc4 */
}
static void __init mx50_clocks_init(struct device_node *np)
@ -442,10 +428,10 @@ static void __init mx51_clocks_init(struct device_node *np)
clk[IMX5_CLK_ESDHC4_PER_GATE] = imx_clk_gate2("esdhc4_per_gate", "esdhc_d_sel", MXC_CCM_CCGR3, 14);
clk[IMX5_CLK_USB_PHY_GATE] = imx_clk_gate2("usb_phy_gate", "usb_phy_sel", MXC_CCM_CCGR2, 0);
clk[IMX5_CLK_HSI2C_GATE] = imx_clk_gate2("hsi2c_gate", "ipg", MXC_CCM_CCGR1, 22);
clk[IMX5_CLK_MIPI_HSC1_GATE] = imx_clk_gate2("mipi_hsc1_gate", "ipg", MXC_CCM_CCGR4, 6);
clk[IMX5_CLK_MIPI_HSC2_GATE] = imx_clk_gate2("mipi_hsc2_gate", "ipg", MXC_CCM_CCGR4, 8);
clk[IMX5_CLK_MIPI_ESC_GATE] = imx_clk_gate2("mipi_esc_gate", "ipg", MXC_CCM_CCGR4, 10);
clk[IMX5_CLK_MIPI_HSP_GATE] = imx_clk_gate2("mipi_hsp_gate", "ipg", MXC_CCM_CCGR4, 12);
clk[IMX5_CLK_MIPI_HSC1_GATE] = imx_clk_gate2_flags("mipi_hsc1_gate", "ipg", MXC_CCM_CCGR4, 6, CLK_IS_CRITICAL);
clk[IMX5_CLK_MIPI_HSC2_GATE] = imx_clk_gate2_flags("mipi_hsc2_gate", "ipg", MXC_CCM_CCGR4, 8, CLK_IS_CRITICAL);
clk[IMX5_CLK_MIPI_ESC_GATE] = imx_clk_gate2_flags("mipi_esc_gate", "ipg", MXC_CCM_CCGR4, 10, CLK_IS_CRITICAL);
clk[IMX5_CLK_MIPI_HSP_GATE] = imx_clk_gate2_flags("mipi_hsp_gate", "ipg", MXC_CCM_CCGR4, 12, CLK_IS_CRITICAL);
clk[IMX5_CLK_SPDIF_XTAL_SEL] = imx_clk_mux("spdif_xtal_sel", MXC_CCM_CSCMR1, 2, 2,
mx51_spdif_xtal_sel, ARRAY_SIZE(mx51_spdif_xtal_sel));
clk[IMX5_CLK_SPDIF1_SEL] = imx_clk_mux("spdif1_sel", MXC_CCM_CSCMR2, 2, 2,

View File

@ -65,7 +65,7 @@ static const char *ipg_per_sels[] = { "ipg", "osc", };
static const char *ecspi_sels[] = { "pll3_60m", "osc", };
static const char *can_sels[] = { "pll3_60m", "osc", "pll3_80m", };
static const char *cko1_sels[] = { "pll3_usb_otg", "pll2_bus", "pll1_sys", "pll5_video_div",
"dummy", "axi", "enfc", "ipu1_di0", "ipu1_di1", "ipu2_di0",
"video_27m", "axi", "enfc", "ipu1_di0", "ipu1_di1", "ipu2_di0",
"ipu2_di1", "ahb", "ipg", "ipg_per", "ckil", "pll4_audio_div", };
static const char *cko2_sels[] = {
"mmdc_ch0_axi", "mmdc_ch1_axi", "usdhc4", "usdhc1",
@ -96,12 +96,6 @@ static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
static struct clk *clk[IMX6QDL_CLK_END];
static struct clk_onecell_data clk_data;
static unsigned int const clks_init_on[] __initconst = {
IMX6QDL_CLK_MMDC_CH0_AXI,
IMX6QDL_CLK_ROM,
IMX6QDL_CLK_ARM,
};
static struct clk_div_table clk_enet_ref_table[] = {
{ .val = 0, .div = 20, },
{ .val = 1, .div = 10, },
@ -417,7 +411,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
void __iomem *anatop_base, *base;
int i;
int ret;
clk[IMX6QDL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
@ -794,7 +787,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb", "mlb_podf", base + 0x74, 18);
else
clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb", "axi", base + 0x74, 18);
clk[IMX6QDL_CLK_MMDC_CH0_AXI] = imx_clk_gate2("mmdc_ch0_axi", "mmdc_ch0_axi_podf", base + 0x74, 20);
clk[IMX6QDL_CLK_MMDC_CH0_AXI] = imx_clk_gate2_flags("mmdc_ch0_axi", "mmdc_ch0_axi_podf", base + 0x74, 20, CLK_IS_CRITICAL);
clk[IMX6QDL_CLK_MMDC_CH1_AXI] = imx_clk_gate2("mmdc_ch1_axi", "mmdc_ch1_axi_podf", base + 0x74, 22);
clk[IMX6QDL_CLK_OCRAM] = imx_clk_gate2("ocram", "ahb", base + 0x74, 28);
clk[IMX6QDL_CLK_OPENVG_AXI] = imx_clk_gate2("openvg_axi", "axi", base + 0x74, 30);
@ -808,7 +801,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_GPMI_BCH] = imx_clk_gate2("gpmi_bch", "usdhc4", base + 0x78, 26);
clk[IMX6QDL_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "enfc", base + 0x78, 28);
clk[IMX6QDL_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30);
clk[IMX6QDL_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0);
clk[IMX6QDL_CLK_ROM] = imx_clk_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL);
clk[IMX6QDL_CLK_SATA] = imx_clk_gate2("sata", "ahb", base + 0x7c, 4);
clk[IMX6QDL_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6);
clk[IMX6QDL_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12);
@ -878,9 +871,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
*/
clk_set_parent(clk[IMX6QDL_CLK_ENFC_SEL], clk[IMX6QDL_CLK_PLL2_PFD2_396M]);
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
clk_prepare_enable(clk[clks_init_on[i]]);
if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY1_GATE]);
clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY2_GATE]);

View File

@ -104,10 +104,6 @@ static struct clk_onecell_data clk_data;
static void __iomem *ccm_base;
static void __iomem *anatop_base;
static const u32 clks_init_on[] __initconst = {
IMX6SL_CLK_IPG, IMX6SL_CLK_ARM, IMX6SL_CLK_MMDC_ROOT,
};
/*
* ERR005311 CCM: After exit from WAIT mode, unwanted interrupt(s) taken
* during WAIT mode entry process could cause cache memory
@ -195,7 +191,6 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
void __iomem *base;
int i;
int ret;
clks[IMX6SL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
@ -426,13 +421,6 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
pr_warn("%s: failed to set AHB clock rate %d!\n",
__func__, ret);
/*
* Make sure those always on clocks are enabled to maintain the correct
* usecount and enabling/disabling of parent PLLs.
*/
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
clk_prepare_enable(clks[clks_init_on[i]]);
if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
clk_prepare_enable(clks[IMX6SL_CLK_USBPHY1_GATE]);
clk_prepare_enable(clks[IMX6SL_CLK_USBPHY2_GATE]);

View File

@ -92,6 +92,7 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node)
np = of_find_compatible_node(NULL, NULL, "fsl,imx6sll-anatop");
base = of_iomap(np, 0);
of_node_put(np);
WARN_ON(!base);
/* Do not bypass PLLs initially */
@ -253,6 +254,7 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node)
clks[IMX6SLL_CLK_DCP] = imx_clk_gate2("dcp", "ahb", base + 0x68, 10);
clks[IMX6SLL_CLK_UART2_IPG] = imx_clk_gate2("uart2_ipg", "ipg", base + 0x68, 28);
clks[IMX6SLL_CLK_UART2_SERIAL] = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28);
clks[IMX6SLL_CLK_GPIO2] = imx_clk_gate2("gpio2", "ipg", base + 0x68, 30);
/* CCGR1 */
clks[IMX6SLL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0);
@ -267,13 +269,17 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node)
clks[IMX6SLL_CLK_GPT_SERIAL] = imx_clk_gate2("gpt1_serial", "perclk", base + 0x6c, 22);
clks[IMX6SLL_CLK_UART4_IPG] = imx_clk_gate2("uart4_ipg", "ipg", base + 0x6c, 24);
clks[IMX6SLL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serail", "uart_podf", base + 0x6c, 24);
clks[IMX6SLL_CLK_GPIO1] = imx_clk_gate2("gpio1", "ipg", base + 0x6c, 26);
clks[IMX6SLL_CLK_GPIO5] = imx_clk_gate2("gpio5", "ipg", base + 0x6c, 30);
/* CCGR2 */
clks[IMX6SLL_CLK_GPIO6] = imx_clk_gate2("gpio6", "ipg", base + 0x70, 0);
clks[IMX6SLL_CLK_CSI] = imx_clk_gate2("csi", "axi", base + 0x70, 2);
clks[IMX6SLL_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6);
clks[IMX6SLL_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8);
clks[IMX6SLL_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10);
clks[IMX6SLL_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12);
clks[IMX6SLL_CLK_GPIO3] = imx_clk_gate2("gpio3", "ipg", base + 0x70, 26);
clks[IMX6SLL_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "axi", base + 0x70, 28);
clks[IMX6SLL_CLK_PXP] = imx_clk_gate2("pxp", "axi", base + 0x70, 30);
@ -283,6 +289,7 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node)
clks[IMX6SLL_CLK_EPDC_AXI] = imx_clk_gate2("epdc_aclk", "axi", base + 0x74, 4);
clks[IMX6SLL_CLK_EPDC_PIX] = imx_clk_gate2("epdc_pix", "epdc_podf", base + 0x74, 4);
clks[IMX6SLL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_podf", base + 0x74, 10);
clks[IMX6SLL_CLK_GPIO4] = imx_clk_gate2("gpio4", "ipg", base + 0x74, 12);
clks[IMX6SLL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16);
clks[IMX6SLL_CLK_MMDC_P0_FAST] = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
clks[IMX6SLL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);

View File

@ -92,14 +92,6 @@ static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
static struct clk *clks[IMX6SX_CLK_CLK_END];
static struct clk_onecell_data clk_data;
static int const clks_init_on[] __initconst = {
IMX6SX_CLK_AIPS_TZ1, IMX6SX_CLK_AIPS_TZ2, IMX6SX_CLK_AIPS_TZ3,
IMX6SX_CLK_IPMUX1, IMX6SX_CLK_IPMUX2, IMX6SX_CLK_IPMUX3,
IMX6SX_CLK_WAKEUP, IMX6SX_CLK_MMDC_P0_FAST, IMX6SX_CLK_MMDC_P0_IPG,
IMX6SX_CLK_ROM, IMX6SX_CLK_ARM, IMX6SX_CLK_IPG, IMX6SX_CLK_OCRAM,
IMX6SX_CLK_PER2_MAIN, IMX6SX_CLK_PERCLK, IMX6SX_CLK_TZASC1,
};
static const struct clk_div_table clk_enet_ref_table[] = {
{ .val = 0, .div = 20, },
{ .val = 1, .div = 10, },
@ -142,7 +134,6 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
void __iomem *base;
int i;
clks[IMX6SX_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
@ -332,7 +323,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clks[IMX6SX_CLK_QSPI1_PODF] = imx_clk_divider("qspi1_podf", "qspi1_sel", base + 0x1c, 26, 3);
clks[IMX6SX_CLK_EIM_SLOW_PODF] = imx_clk_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3);
clks[IMX6SX_CLK_LCDIF2_PODF] = imx_clk_divider("lcdif2_podf", "lcdif2_pred", base + 0x1c, 20, 3);
clks[IMX6SX_CLK_PERCLK] = imx_clk_divider("perclk", "perclk_sel", base + 0x1c, 0, 6);
clks[IMX6SX_CLK_PERCLK] = imx_clk_divider_flags("perclk", "perclk_sel", base + 0x1c, 0, 6, CLK_IS_CRITICAL);
clks[IMX6SX_CLK_VID_PODF] = imx_clk_divider("vid_podf", "vid_sel", base + 0x20, 24, 2);
clks[IMX6SX_CLK_CAN_PODF] = imx_clk_divider("can_podf", "can_sel", base + 0x20, 2, 6);
clks[IMX6SX_CLK_USDHC4_PODF] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3);
@ -380,8 +371,8 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
/* name parent_name reg shift */
/* CCGR0 */
clks[IMX6SX_CLK_AIPS_TZ1] = imx_clk_gate2("aips_tz1", "ahb", base + 0x68, 0);
clks[IMX6SX_CLK_AIPS_TZ2] = imx_clk_gate2("aips_tz2", "ahb", base + 0x68, 2);
clks[IMX6SX_CLK_AIPS_TZ1] = imx_clk_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL);
clks[IMX6SX_CLK_AIPS_TZ2] = imx_clk_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL);
clks[IMX6SX_CLK_APBH_DMA] = imx_clk_gate2("apbh_dma", "usdhc3", base + 0x68, 4);
clks[IMX6SX_CLK_ASRC_MEM] = imx_clk_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc);
clks[IMX6SX_CLK_ASRC_IPG] = imx_clk_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc);
@ -394,7 +385,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clks[IMX6SX_CLK_CAN2_SERIAL] = imx_clk_gate2("can2_serial", "can_podf", base + 0x68, 20);
clks[IMX6SX_CLK_DCIC1] = imx_clk_gate2("dcic1", "display_podf", base + 0x68, 24);
clks[IMX6SX_CLK_DCIC2] = imx_clk_gate2("dcic2", "display_podf", base + 0x68, 26);
clks[IMX6SX_CLK_AIPS_TZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x68, 30);
clks[IMX6SX_CLK_AIPS_TZ3] = imx_clk_gate2_flags("aips_tz3", "ahb", base + 0x68, 30, CLK_IS_CRITICAL);
/* CCGR1 */
clks[IMX6SX_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0);
@ -407,10 +398,11 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clks[IMX6SX_CLK_ESAI_EXTAL] = imx_clk_gate2_shared("esai_extal", "esai_podf", base + 0x6c, 16, &share_count_esai);
clks[IMX6SX_CLK_ESAI_IPG] = imx_clk_gate2_shared("esai_ipg", "ahb", base + 0x6c, 16, &share_count_esai);
clks[IMX6SX_CLK_ESAI_MEM] = imx_clk_gate2_shared("esai_mem", "ahb", base + 0x6c, 16, &share_count_esai);
clks[IMX6SX_CLK_WAKEUP] = imx_clk_gate2("wakeup", "ipg", base + 0x6c, 18);
clks[IMX6SX_CLK_WAKEUP] = imx_clk_gate2_flags("wakeup", "ipg", base + 0x6c, 18, CLK_IS_CRITICAL);
clks[IMX6SX_CLK_GPT_BUS] = imx_clk_gate2("gpt_bus", "perclk", base + 0x6c, 20);
clks[IMX6SX_CLK_GPT_SERIAL] = imx_clk_gate2("gpt_serial", "perclk", base + 0x6c, 22);
clks[IMX6SX_CLK_GPU] = imx_clk_gate2("gpu", "gpu_core_podf", base + 0x6c, 26);
clks[IMX6SX_CLK_OCRAM_S] = imx_clk_gate2("ocram_s", "ahb", base + 0x6c, 28);
clks[IMX6SX_CLK_CANFD] = imx_clk_gate2("canfd", "can_podf", base + 0x6c, 30);
/* CCGR2 */
@ -420,10 +412,10 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clks[IMX6SX_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10);
clks[IMX6SX_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12);
clks[IMX6SX_CLK_IOMUXC] = imx_clk_gate2("iomuxc", "lcdif1_podf", base + 0x70, 14);
clks[IMX6SX_CLK_IPMUX1] = imx_clk_gate2("ipmux1", "ahb", base + 0x70, 16);
clks[IMX6SX_CLK_IPMUX2] = imx_clk_gate2("ipmux2", "ahb", base + 0x70, 18);
clks[IMX6SX_CLK_IPMUX3] = imx_clk_gate2("ipmux3", "ahb", base + 0x70, 20);
clks[IMX6SX_CLK_TZASC1] = imx_clk_gate2("tzasc1", "mmdc_podf", base + 0x70, 22);
clks[IMX6SX_CLK_IPMUX1] = imx_clk_gate2_flags("ipmux1", "ahb", base + 0x70, 16, CLK_IS_CRITICAL);
clks[IMX6SX_CLK_IPMUX2] = imx_clk_gate2_flags("ipmux2", "ahb", base + 0x70, 18, CLK_IS_CRITICAL);
clks[IMX6SX_CLK_IPMUX3] = imx_clk_gate2_flags("ipmux3", "ahb", base + 0x70, 20, CLK_IS_CRITICAL);
clks[IMX6SX_CLK_TZASC1] = imx_clk_gate2_flags("tzasc1", "mmdc_podf", base + 0x70, 22, CLK_IS_CRITICAL);
clks[IMX6SX_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "display_podf", base + 0x70, 28);
clks[IMX6SX_CLK_PXP_AXI] = imx_clk_gate2("pxp_axi", "display_podf", base + 0x70, 30);
@ -437,15 +429,15 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clks[IMX6SX_CLK_LDB_DI0] = imx_clk_gate2("ldb_di0", "ldb_di0_div_sel", base + 0x74, 12);
clks[IMX6SX_CLK_QSPI1] = imx_clk_gate2("qspi1", "qspi1_podf", base + 0x74, 14);
clks[IMX6SX_CLK_MLB] = imx_clk_gate2("mlb", "ahb", base + 0x74, 18);
clks[IMX6SX_CLK_MMDC_P0_FAST] = imx_clk_gate2("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20);
clks[IMX6SX_CLK_MMDC_P0_IPG] = imx_clk_gate2("mmdc_p0_ipg", "ipg", base + 0x74, 24);
clks[IMX6SX_CLK_OCRAM] = imx_clk_gate2("ocram", "ocram_podf", base + 0x74, 28);
clks[IMX6SX_CLK_MMDC_P0_FAST] = imx_clk_gate2_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
clks[IMX6SX_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
clks[IMX6SX_CLK_OCRAM] = imx_clk_gate2_flags("ocram", "ocram_podf", base + 0x74, 28, CLK_IS_CRITICAL);
/* CCGR4 */
clks[IMX6SX_CLK_PCIE_AXI] = imx_clk_gate2("pcie_axi", "display_podf", base + 0x78, 0);
clks[IMX6SX_CLK_QSPI2] = imx_clk_gate2("qspi2", "qspi2_podf", base + 0x78, 10);
clks[IMX6SX_CLK_PER1_BCH] = imx_clk_gate2("per1_bch", "usdhc3", base + 0x78, 12);
clks[IMX6SX_CLK_PER2_MAIN] = imx_clk_gate2("per2_main", "ahb", base + 0x78, 14);
clks[IMX6SX_CLK_PER2_MAIN] = imx_clk_gate2_flags("per2_main", "ahb", base + 0x78, 14, CLK_IS_CRITICAL);
clks[IMX6SX_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16);
clks[IMX6SX_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18);
clks[IMX6SX_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20);
@ -456,7 +448,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clks[IMX6SX_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30);
/* CCGR5 */
clks[IMX6SX_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0);
clks[IMX6SX_CLK_ROM] = imx_clk_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL);
clks[IMX6SX_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6);
clks[IMX6SX_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12);
clks[IMX6SX_CLK_AUDIO] = imx_clk_gate2_shared("audio", "audio_podf", base + 0x7c, 14, &share_count_audio);
@ -502,9 +494,6 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clk_data.clk_num = ARRAY_SIZE(clks);
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
clk_prepare_enable(clks[clks_init_on[i]]);
if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
clk_prepare_enable(clks[IMX6SX_CLK_USBPHY1_GATE]);
clk_prepare_enable(clks[IMX6SX_CLK_USBPHY2_GATE]);

View File

@ -79,12 +79,6 @@ static const char *cko_sels[] = { "cko1", "cko2", };
static struct clk *clks[IMX6UL_CLK_END];
static struct clk_onecell_data clk_data;
static int const clks_init_on[] __initconst = {
IMX6UL_CLK_AIPSTZ1, IMX6UL_CLK_AIPSTZ2,
IMX6UL_CLK_AXI, IMX6UL_CLK_ARM, IMX6UL_CLK_ROM,
IMX6UL_CLK_MMDC_P0_FAST, IMX6UL_CLK_MMDC_P0_IPG,
};
static const struct clk_div_table clk_enet_ref_table[] = {
{ .val = 0, .div = 20, },
{ .val = 1, .div = 10, },
@ -129,7 +123,6 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
void __iomem *base;
int i;
clks[IMX6UL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
@ -142,6 +135,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-anatop");
base = of_iomap(np, 0);
of_node_put(np);
WARN_ON(!base);
clks[IMX6UL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
@ -336,8 +330,8 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1);
/* CCGR0 */
clks[IMX6UL_CLK_AIPSTZ1] = imx_clk_gate2("aips_tz1", "ahb", base + 0x68, 0);
clks[IMX6UL_CLK_AIPSTZ2] = imx_clk_gate2("aips_tz2", "ahb", base + 0x68, 2);
clks[IMX6UL_CLK_AIPSTZ1] = imx_clk_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL);
clks[IMX6UL_CLK_AIPSTZ2] = imx_clk_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL);
clks[IMX6UL_CLK_APBHDMA] = imx_clk_gate2("apbh_dma", "bch_podf", base + 0x68, 4);
clks[IMX6UL_CLK_ASRC_IPG] = imx_clk_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc);
clks[IMX6UL_CLK_ASRC_MEM] = imx_clk_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc);
@ -360,6 +354,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_CLK_UART2_SERIAL] = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28);
if (clk_on_imx6ull())
clks[IMX6UL_CLK_AIPSTZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x80, 18);
clks[IMX6UL_CLK_GPIO2] = imx_clk_gate2("gpio2", "ipg", base + 0x68, 30);
/* CCGR1 */
clks[IMX6UL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0);
@ -376,6 +371,8 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_CLK_GPT1_SERIAL] = imx_clk_gate2("gpt1_serial", "perclk", base + 0x6c, 22);
clks[IMX6UL_CLK_UART4_IPG] = imx_clk_gate2("uart4_ipg", "ipg", base + 0x6c, 24);
clks[IMX6UL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serial", "uart_podf", base + 0x6c, 24);
clks[IMX6UL_CLK_GPIO1] = imx_clk_gate2("gpio1", "ipg", base + 0x6c, 26);
clks[IMX6UL_CLK_GPIO5] = imx_clk_gate2("gpio5", "ipg", base + 0x6c, 30);
/* CCGR2 */
if (clk_on_imx6ull()) {
@ -389,6 +386,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10);
clks[IMX6UL_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12);
clks[IMX6UL_CLK_IOMUXC] = imx_clk_gate2("iomuxc", "lcdif_podf", base + 0x70, 14);
clks[IMX6UL_CLK_GPIO3] = imx_clk_gate2("gpio3", "ipg", base + 0x70, 26);
clks[IMX6UL_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "axi", base + 0x70, 28);
clks[IMX6UL_CLK_PXP] = imx_clk_gate2("pxp", "axi", base + 0x70, 30);
@ -405,11 +403,12 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_CLK_UART6_IPG] = imx_clk_gate2("uart6_ipg", "ipg", base + 0x74, 6);
clks[IMX6UL_CLK_UART6_SERIAL] = imx_clk_gate2("uart6_serial", "uart_podf", base + 0x74, 6);
clks[IMX6UL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_podf", base + 0x74, 10);
clks[IMX6UL_CLK_GPIO4] = imx_clk_gate2("gpio4", "ipg", base + 0x74, 12);
clks[IMX6UL_CLK_QSPI] = imx_clk_gate2("qspi1", "qspi1_podf", base + 0x74, 14);
clks[IMX6UL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16);
clks[IMX6UL_CLK_MMDC_P0_FAST] = imx_clk_gate("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20);
clks[IMX6UL_CLK_MMDC_P0_IPG] = imx_clk_gate2("mmdc_p0_ipg", "ipg", base + 0x74, 24);
clks[IMX6UL_CLK_AXI] = imx_clk_gate("axi", "axi_podf", base + 0x74, 28);
clks[IMX6UL_CLK_MMDC_P0_FAST] = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
clks[IMX6UL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
clks[IMX6UL_CLK_AXI] = imx_clk_gate_flags("axi", "axi_podf", base + 0x74, 28, CLK_IS_CRITICAL);
/* CCGR4 */
clks[IMX6UL_CLK_PER_BCH] = imx_clk_gate2("per_bch", "bch_podf", base + 0x78, 12);
@ -423,7 +422,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "bch_podf", base + 0x78, 30);
/* CCGR5 */
clks[IMX6UL_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0);
clks[IMX6UL_CLK_ROM] = imx_clk_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL);
clks[IMX6UL_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6);
clks[IMX6UL_CLK_KPP] = imx_clk_gate2("kpp", "ipg", base + 0x7c, 8);
clks[IMX6UL_CLK_WDOG2] = imx_clk_gate2("wdog2", "ipg", base + 0x7c, 10);
@ -497,10 +496,6 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clk_set_rate(clks[IMX6UL_CLK_ENET2_REF], 50000000);
clk_set_rate(clks[IMX6UL_CLK_CSI], 24000000);
/* keep all the clks on just for bringup */
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
clk_prepare_enable(clks[clks_init_on[i]]);
if (clk_on_imx6ull())
clk_prepare_enable(clks[IMX6UL_CLK_AIPSTZ3]);

View File

@ -797,6 +797,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate4("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0);
clks[IMX7D_OCOTP_CLK] = imx_clk_gate4("ocotp_clk", "ipg_root_clk", base + 0x4230, 0);
clks[IMX7D_SNVS_CLK] = imx_clk_gate4("snvs_clk", "ipg_root_clk", base + 0x4250, 0);
clks[IMX7D_MU_ROOT_CLK] = imx_clk_gate4("mu_root_clk", "ipg_root_clk", base + 0x4270, 0);
clks[IMX7D_CAAM_CLK] = imx_clk_gate4("caam_clk", "ipg_root_clk", base + 0x4240, 0);
clks[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4690, 0);
clks[IMX7D_SDMA_CORE_CLK] = imx_clk_gate4("sdma_root_clk", "ahb_root_clk", base + 0x4480, 0);

View File

@ -134,7 +134,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
"i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
.parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 },
.mux = { CGU_REG_CPCCR, 31, 1 },
.div = { CGU_REG_I2SCDR, 0, 1, 8, -1, -1, -1 },
.div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },
.gate = { CGU_REG_CLKGR, 6 },
},
@ -161,7 +161,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
},
[JZ4740_CLK_UDC] = {
"udc", CGU_CLK_MUX | CGU_CLK_DIV,
"udc", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
.parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 },
.mux = { CGU_REG_CPCCR, 29, 1 },
.div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 },

View File

@ -1,13 +1,19 @@
config COMMON_CLK_AMLOGIC
bool
depends on OF
depends on ARCH_MESON || COMPILE_TEST
select COMMON_CLK_REGMAP_MESON
config COMMON_CLK_AMLOGIC_AUDIO
bool
depends on ARCH_MESON || COMPILE_TEST
select COMMON_CLK_AMLOGIC
config COMMON_CLK_MESON_AO
bool
depends on OF
depends on ARCH_MESON || COMPILE_TEST
select COMMON_CLK_REGMAP_MESON
select RESET_CONTROLLER
config COMMON_CLK_REGMAP_MESON
bool
@ -15,9 +21,8 @@ config COMMON_CLK_REGMAP_MESON
config COMMON_CLK_MESON8B
bool
depends on COMMON_CLK_AMLOGIC
select COMMON_CLK_AMLOGIC
select RESET_CONTROLLER
select COMMON_CLK_REGMAP_MESON
help
Support for the clock controller on AmLogic S802 (Meson8),
S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you
@ -25,10 +30,8 @@ config COMMON_CLK_MESON8B
config COMMON_CLK_GXBB
bool
depends on COMMON_CLK_AMLOGIC
select RESET_CONTROLLER
select COMMON_CLK_AMLOGIC
select COMMON_CLK_MESON_AO
select COMMON_CLK_REGMAP_MESON
select MFD_SYSCON
help
Support for the clock controller on AmLogic S905 devices, aka gxbb.
@ -36,11 +39,18 @@ config COMMON_CLK_GXBB
config COMMON_CLK_AXG
bool
depends on COMMON_CLK_AMLOGIC
select RESET_CONTROLLER
select COMMON_CLK_AMLOGIC
select COMMON_CLK_MESON_AO
select COMMON_CLK_REGMAP_MESON
select MFD_SYSCON
help
Support for the clock controller on AmLogic A113D devices, aka axg.
Say Y if you want peripherals and CPU frequency scaling to work.
config COMMON_CLK_AXG_AUDIO
tristate "Meson AXG Audio Clock Controller Driver"
depends on COMMON_CLK_AXG
select COMMON_CLK_AMLOGIC_AUDIO
select MFD_SYSCON
help
Support for the audio clock controller on AmLogic A113D devices,
aka axg, Say Y if you want audio subsystem to work.

View File

@ -2,9 +2,11 @@
# Makefile for Meson specific clk
#
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-phase.o
obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO) += clk-triphase.o sclk-div.o
obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o
obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
obj-$(CONFIG_COMMON_CLK_REGMAP_MESON) += clk-regmap.o

View File

@ -0,0 +1,845 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Copyright (c) 2018 BayLibre, SAS.
* Author: Jerome Brunet <jbrunet@baylibre.com>
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/init.h>
#include <linux/of_device.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/slab.h>
#include "clkc-audio.h"
#include "axg-audio.h"
#define AXG_MST_IN_COUNT 8
#define AXG_SLV_SCLK_COUNT 10
#define AXG_SLV_LRCLK_COUNT 10
#define AXG_AUD_GATE(_name, _reg, _bit, _pname, _iflags) \
struct clk_regmap axg_##_name = { \
.data = &(struct clk_regmap_gate_data){ \
.offset = (_reg), \
.bit_idx = (_bit), \
}, \
.hw.init = &(struct clk_init_data) { \
.name = "axg_"#_name, \
.ops = &clk_regmap_gate_ops, \
.parent_names = (const char *[]){ _pname }, \
.num_parents = 1, \
.flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \
}, \
}
#define AXG_AUD_MUX(_name, _reg, _mask, _shift, _dflags, _pnames, _iflags) \
struct clk_regmap axg_##_name = { \
.data = &(struct clk_regmap_mux_data){ \
.offset = (_reg), \
.mask = (_mask), \
.shift = (_shift), \
.flags = (_dflags), \
}, \
.hw.init = &(struct clk_init_data){ \
.name = "axg_"#_name, \
.ops = &clk_regmap_mux_ops, \
.parent_names = (_pnames), \
.num_parents = ARRAY_SIZE(_pnames), \
.flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \
}, \
}
#define AXG_AUD_DIV(_name, _reg, _shift, _width, _dflags, _pname, _iflags) \
struct clk_regmap axg_##_name = { \
.data = &(struct clk_regmap_div_data){ \
.offset = (_reg), \
.shift = (_shift), \
.width = (_width), \
.flags = (_dflags), \
}, \
.hw.init = &(struct clk_init_data){ \
.name = "axg_"#_name, \
.ops = &clk_regmap_divider_ops, \
.parent_names = (const char *[]) { _pname }, \
.num_parents = 1, \
.flags = (_iflags), \
}, \
}
#define AXG_PCLK_GATE(_name, _bit) \
AXG_AUD_GATE(_name, AUDIO_CLK_GATE_EN, _bit, "axg_audio_pclk", 0)
/* Audio peripheral clocks */
static AXG_PCLK_GATE(ddr_arb, 0);
static AXG_PCLK_GATE(pdm, 1);
static AXG_PCLK_GATE(tdmin_a, 2);
static AXG_PCLK_GATE(tdmin_b, 3);
static AXG_PCLK_GATE(tdmin_c, 4);
static AXG_PCLK_GATE(tdmin_lb, 5);
static AXG_PCLK_GATE(tdmout_a, 6);
static AXG_PCLK_GATE(tdmout_b, 7);
static AXG_PCLK_GATE(tdmout_c, 8);
static AXG_PCLK_GATE(frddr_a, 9);
static AXG_PCLK_GATE(frddr_b, 10);
static AXG_PCLK_GATE(frddr_c, 11);
static AXG_PCLK_GATE(toddr_a, 12);
static AXG_PCLK_GATE(toddr_b, 13);
static AXG_PCLK_GATE(toddr_c, 14);
static AXG_PCLK_GATE(loopback, 15);
static AXG_PCLK_GATE(spdifin, 16);
static AXG_PCLK_GATE(spdifout, 17);
static AXG_PCLK_GATE(resample, 18);
static AXG_PCLK_GATE(power_detect, 19);
/* Audio Master Clocks */
static const char * const mst_mux_parent_names[] = {
"axg_mst_in0", "axg_mst_in1", "axg_mst_in2", "axg_mst_in3",
"axg_mst_in4", "axg_mst_in5", "axg_mst_in6", "axg_mst_in7",
};
#define AXG_MST_MCLK_MUX(_name, _reg) \
AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, CLK_MUX_ROUND_CLOSEST, \
mst_mux_parent_names, CLK_SET_RATE_PARENT)
static AXG_MST_MCLK_MUX(mst_a_mclk, AUDIO_MCLK_A_CTRL);
static AXG_MST_MCLK_MUX(mst_b_mclk, AUDIO_MCLK_B_CTRL);
static AXG_MST_MCLK_MUX(mst_c_mclk, AUDIO_MCLK_C_CTRL);
static AXG_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL);
static AXG_MST_MCLK_MUX(mst_e_mclk, AUDIO_MCLK_E_CTRL);
static AXG_MST_MCLK_MUX(mst_f_mclk, AUDIO_MCLK_F_CTRL);
static AXG_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
static AXG_MST_MCLK_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
static AXG_MST_MCLK_MUX(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0);
static AXG_MST_MCLK_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1);
#define AXG_MST_MCLK_DIV(_name, _reg) \
AXG_AUD_DIV(_name##_div, _reg, 0, 16, CLK_DIVIDER_ROUND_CLOSEST, \
"axg_"#_name"_sel", CLK_SET_RATE_PARENT) \
static AXG_MST_MCLK_DIV(mst_a_mclk, AUDIO_MCLK_A_CTRL);
static AXG_MST_MCLK_DIV(mst_b_mclk, AUDIO_MCLK_B_CTRL);
static AXG_MST_MCLK_DIV(mst_c_mclk, AUDIO_MCLK_C_CTRL);
static AXG_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL);
static AXG_MST_MCLK_DIV(mst_e_mclk, AUDIO_MCLK_E_CTRL);
static AXG_MST_MCLK_DIV(mst_f_mclk, AUDIO_MCLK_F_CTRL);
static AXG_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
static AXG_MST_MCLK_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
static AXG_MST_MCLK_DIV(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0);
static AXG_MST_MCLK_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1);
#define AXG_MST_MCLK_GATE(_name, _reg) \
AXG_AUD_GATE(_name, _reg, 31, "axg_"#_name"_div", \
CLK_SET_RATE_PARENT)
static AXG_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL);
static AXG_MST_MCLK_GATE(mst_b_mclk, AUDIO_MCLK_B_CTRL);
static AXG_MST_MCLK_GATE(mst_c_mclk, AUDIO_MCLK_C_CTRL);
static AXG_MST_MCLK_GATE(mst_d_mclk, AUDIO_MCLK_D_CTRL);
static AXG_MST_MCLK_GATE(mst_e_mclk, AUDIO_MCLK_E_CTRL);
static AXG_MST_MCLK_GATE(mst_f_mclk, AUDIO_MCLK_F_CTRL);
static AXG_MST_MCLK_GATE(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
static AXG_MST_MCLK_GATE(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
static AXG_MST_MCLK_GATE(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0);
static AXG_MST_MCLK_GATE(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1);
/* Sample Clocks */
#define AXG_MST_SCLK_PRE_EN(_name, _reg) \
AXG_AUD_GATE(mst_##_name##_sclk_pre_en, _reg, 31, \
"axg_mst_"#_name"_mclk", 0)
static AXG_MST_SCLK_PRE_EN(a, AUDIO_MST_A_SCLK_CTRL0);
static AXG_MST_SCLK_PRE_EN(b, AUDIO_MST_B_SCLK_CTRL0);
static AXG_MST_SCLK_PRE_EN(c, AUDIO_MST_C_SCLK_CTRL0);
static AXG_MST_SCLK_PRE_EN(d, AUDIO_MST_D_SCLK_CTRL0);
static AXG_MST_SCLK_PRE_EN(e, AUDIO_MST_E_SCLK_CTRL0);
static AXG_MST_SCLK_PRE_EN(f, AUDIO_MST_F_SCLK_CTRL0);
#define AXG_AUD_SCLK_DIV(_name, _reg, _div_shift, _div_width, \
_hi_shift, _hi_width, _pname, _iflags) \
struct clk_regmap axg_##_name = { \
.data = &(struct meson_sclk_div_data) { \
.div = { \
.reg_off = (_reg), \
.shift = (_div_shift), \
.width = (_div_width), \
}, \
.hi = { \
.reg_off = (_reg), \
.shift = (_hi_shift), \
.width = (_hi_width), \
}, \
}, \
.hw.init = &(struct clk_init_data) { \
.name = "axg_"#_name, \
.ops = &meson_sclk_div_ops, \
.parent_names = (const char *[]) { _pname }, \
.num_parents = 1, \
.flags = (_iflags), \
}, \
}
#define AXG_MST_SCLK_DIV(_name, _reg) \
AXG_AUD_SCLK_DIV(mst_##_name##_sclk_div, _reg, 20, 10, 0, 0, \
"axg_mst_"#_name"_sclk_pre_en", \
CLK_SET_RATE_PARENT)
static AXG_MST_SCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0);
static AXG_MST_SCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0);
static AXG_MST_SCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0);
static AXG_MST_SCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0);
static AXG_MST_SCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0);
static AXG_MST_SCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0);
#define AXG_MST_SCLK_POST_EN(_name, _reg) \
AXG_AUD_GATE(mst_##_name##_sclk_post_en, _reg, 30, \
"axg_mst_"#_name"_sclk_div", CLK_SET_RATE_PARENT)
static AXG_MST_SCLK_POST_EN(a, AUDIO_MST_A_SCLK_CTRL0);
static AXG_MST_SCLK_POST_EN(b, AUDIO_MST_B_SCLK_CTRL0);
static AXG_MST_SCLK_POST_EN(c, AUDIO_MST_C_SCLK_CTRL0);
static AXG_MST_SCLK_POST_EN(d, AUDIO_MST_D_SCLK_CTRL0);
static AXG_MST_SCLK_POST_EN(e, AUDIO_MST_E_SCLK_CTRL0);
static AXG_MST_SCLK_POST_EN(f, AUDIO_MST_F_SCLK_CTRL0);
#define AXG_AUD_TRIPHASE(_name, _reg, _width, _shift0, _shift1, _shift2, \
_pname, _iflags) \
struct clk_regmap axg_##_name = { \
.data = &(struct meson_clk_triphase_data) { \
.ph0 = { \
.reg_off = (_reg), \
.shift = (_shift0), \
.width = (_width), \
}, \
.ph1 = { \
.reg_off = (_reg), \
.shift = (_shift1), \
.width = (_width), \
}, \
.ph2 = { \
.reg_off = (_reg), \
.shift = (_shift2), \
.width = (_width), \
}, \
}, \
.hw.init = &(struct clk_init_data) { \
.name = "axg_"#_name, \
.ops = &meson_clk_triphase_ops, \
.parent_names = (const char *[]) { _pname }, \
.num_parents = 1, \
.flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \
}, \
}
#define AXG_MST_SCLK(_name, _reg) \
AXG_AUD_TRIPHASE(mst_##_name##_sclk, _reg, 1, 0, 2, 4, \
"axg_mst_"#_name"_sclk_post_en", CLK_SET_RATE_PARENT)
static AXG_MST_SCLK(a, AUDIO_MST_A_SCLK_CTRL1);
static AXG_MST_SCLK(b, AUDIO_MST_B_SCLK_CTRL1);
static AXG_MST_SCLK(c, AUDIO_MST_C_SCLK_CTRL1);
static AXG_MST_SCLK(d, AUDIO_MST_D_SCLK_CTRL1);
static AXG_MST_SCLK(e, AUDIO_MST_E_SCLK_CTRL1);
static AXG_MST_SCLK(f, AUDIO_MST_F_SCLK_CTRL1);
#define AXG_MST_LRCLK_DIV(_name, _reg) \
AXG_AUD_SCLK_DIV(mst_##_name##_lrclk_div, _reg, 0, 10, 10, 10, \
"axg_mst_"#_name"_sclk_post_en", 0) \
static AXG_MST_LRCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0);
static AXG_MST_LRCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0);
static AXG_MST_LRCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0);
static AXG_MST_LRCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0);
static AXG_MST_LRCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0);
static AXG_MST_LRCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0);
#define AXG_MST_LRCLK(_name, _reg) \
AXG_AUD_TRIPHASE(mst_##_name##_lrclk, _reg, 1, 1, 3, 5, \
"axg_mst_"#_name"_lrclk_div", CLK_SET_RATE_PARENT)
static AXG_MST_LRCLK(a, AUDIO_MST_A_SCLK_CTRL1);
static AXG_MST_LRCLK(b, AUDIO_MST_B_SCLK_CTRL1);
static AXG_MST_LRCLK(c, AUDIO_MST_C_SCLK_CTRL1);
static AXG_MST_LRCLK(d, AUDIO_MST_D_SCLK_CTRL1);
static AXG_MST_LRCLK(e, AUDIO_MST_E_SCLK_CTRL1);
static AXG_MST_LRCLK(f, AUDIO_MST_F_SCLK_CTRL1);
static const char * const tdm_sclk_parent_names[] = {
"axg_mst_a_sclk", "axg_mst_b_sclk", "axg_mst_c_sclk",
"axg_mst_d_sclk", "axg_mst_e_sclk", "axg_mst_f_sclk",
"axg_slv_sclk0", "axg_slv_sclk1", "axg_slv_sclk2",
"axg_slv_sclk3", "axg_slv_sclk4", "axg_slv_sclk5",
"axg_slv_sclk6", "axg_slv_sclk7", "axg_slv_sclk8",
"axg_slv_sclk9"
};
#define AXG_TDM_SCLK_MUX(_name, _reg) \
AXG_AUD_MUX(tdm##_name##_sclk_sel, _reg, 0xf, 24, \
CLK_MUX_ROUND_CLOSEST, \
tdm_sclk_parent_names, 0)
static AXG_TDM_SCLK_MUX(in_a, AUDIO_CLK_TDMIN_A_CTRL);
static AXG_TDM_SCLK_MUX(in_b, AUDIO_CLK_TDMIN_B_CTRL);
static AXG_TDM_SCLK_MUX(in_c, AUDIO_CLK_TDMIN_C_CTRL);
static AXG_TDM_SCLK_MUX(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
static AXG_TDM_SCLK_MUX(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
static AXG_TDM_SCLK_MUX(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
static AXG_TDM_SCLK_MUX(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
#define AXG_TDM_SCLK_PRE_EN(_name, _reg) \
AXG_AUD_GATE(tdm##_name##_sclk_pre_en, _reg, 31, \
"axg_tdm"#_name"_sclk_sel", CLK_SET_RATE_PARENT)
static AXG_TDM_SCLK_PRE_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL);
static AXG_TDM_SCLK_PRE_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL);
static AXG_TDM_SCLK_PRE_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL);
static AXG_TDM_SCLK_PRE_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
static AXG_TDM_SCLK_PRE_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
static AXG_TDM_SCLK_PRE_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
static AXG_TDM_SCLK_PRE_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
#define AXG_TDM_SCLK_POST_EN(_name, _reg) \
AXG_AUD_GATE(tdm##_name##_sclk_post_en, _reg, 30, \
"axg_tdm"#_name"_sclk_pre_en", CLK_SET_RATE_PARENT)
static AXG_TDM_SCLK_POST_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL);
static AXG_TDM_SCLK_POST_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL);
static AXG_TDM_SCLK_POST_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL);
static AXG_TDM_SCLK_POST_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
static AXG_TDM_SCLK_POST_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
static AXG_TDM_SCLK_POST_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
static AXG_TDM_SCLK_POST_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
#define AXG_TDM_SCLK(_name, _reg) \
struct clk_regmap axg_tdm##_name##_sclk = { \
.data = &(struct meson_clk_phase_data) { \
.ph = { \
.reg_off = (_reg), \
.shift = 29, \
.width = 1, \
}, \
}, \
.hw.init = &(struct clk_init_data) { \
.name = "axg_tdm"#_name"_sclk", \
.ops = &meson_clk_phase_ops, \
.parent_names = (const char *[]) \
{ "axg_tdm"#_name"_sclk_post_en" }, \
.num_parents = 1, \
.flags = CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT, \
}, \
}
static AXG_TDM_SCLK(in_a, AUDIO_CLK_TDMIN_A_CTRL);
static AXG_TDM_SCLK(in_b, AUDIO_CLK_TDMIN_B_CTRL);
static AXG_TDM_SCLK(in_c, AUDIO_CLK_TDMIN_C_CTRL);
static AXG_TDM_SCLK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
static AXG_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
static AXG_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
static AXG_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
static const char * const tdm_lrclk_parent_names[] = {
"axg_mst_a_lrclk", "axg_mst_b_lrclk", "axg_mst_c_lrclk",
"axg_mst_d_lrclk", "axg_mst_e_lrclk", "axg_mst_f_lrclk",
"axg_slv_lrclk0", "axg_slv_lrclk1", "axg_slv_lrclk2",
"axg_slv_lrclk3", "axg_slv_lrclk4", "axg_slv_lrclk5",
"axg_slv_lrclk6", "axg_slv_lrclk7", "axg_slv_lrclk8",
"axg_slv_lrclk9"
};
#define AXG_TDM_LRLCK(_name, _reg) \
AXG_AUD_MUX(tdm##_name##_lrclk, _reg, 0xf, 20, \
CLK_MUX_ROUND_CLOSEST, \
tdm_lrclk_parent_names, 0)
static AXG_TDM_LRLCK(in_a, AUDIO_CLK_TDMIN_A_CTRL);
static AXG_TDM_LRLCK(in_b, AUDIO_CLK_TDMIN_B_CTRL);
static AXG_TDM_LRLCK(in_c, AUDIO_CLK_TDMIN_C_CTRL);
static AXG_TDM_LRLCK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
static AXG_TDM_LRLCK(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
static AXG_TDM_LRLCK(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
static AXG_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
/*
* Array of all clocks provided by this provider
* The input clocks of the controller will be populated at runtime
*/
static struct clk_hw_onecell_data axg_audio_hw_onecell_data = {
.hws = {
[AUD_CLKID_DDR_ARB] = &axg_ddr_arb.hw,
[AUD_CLKID_PDM] = &axg_pdm.hw,
[AUD_CLKID_TDMIN_A] = &axg_tdmin_a.hw,
[AUD_CLKID_TDMIN_B] = &axg_tdmin_b.hw,
[AUD_CLKID_TDMIN_C] = &axg_tdmin_c.hw,
[AUD_CLKID_TDMIN_LB] = &axg_tdmin_lb.hw,
[AUD_CLKID_TDMOUT_A] = &axg_tdmout_a.hw,
[AUD_CLKID_TDMOUT_B] = &axg_tdmout_b.hw,
[AUD_CLKID_TDMOUT_C] = &axg_tdmout_c.hw,
[AUD_CLKID_FRDDR_A] = &axg_frddr_a.hw,
[AUD_CLKID_FRDDR_B] = &axg_frddr_b.hw,
[AUD_CLKID_FRDDR_C] = &axg_frddr_c.hw,
[AUD_CLKID_TODDR_A] = &axg_toddr_a.hw,
[AUD_CLKID_TODDR_B] = &axg_toddr_b.hw,
[AUD_CLKID_TODDR_C] = &axg_toddr_c.hw,
[AUD_CLKID_LOOPBACK] = &axg_loopback.hw,
[AUD_CLKID_SPDIFIN] = &axg_spdifin.hw,
[AUD_CLKID_SPDIFOUT] = &axg_spdifout.hw,
[AUD_CLKID_RESAMPLE] = &axg_resample.hw,
[AUD_CLKID_POWER_DETECT] = &axg_power_detect.hw,
[AUD_CLKID_MST_A_MCLK_SEL] = &axg_mst_a_mclk_sel.hw,
[AUD_CLKID_MST_B_MCLK_SEL] = &axg_mst_b_mclk_sel.hw,
[AUD_CLKID_MST_C_MCLK_SEL] = &axg_mst_c_mclk_sel.hw,
[AUD_CLKID_MST_D_MCLK_SEL] = &axg_mst_d_mclk_sel.hw,
[AUD_CLKID_MST_E_MCLK_SEL] = &axg_mst_e_mclk_sel.hw,
[AUD_CLKID_MST_F_MCLK_SEL] = &axg_mst_f_mclk_sel.hw,
[AUD_CLKID_MST_A_MCLK_DIV] = &axg_mst_a_mclk_div.hw,
[AUD_CLKID_MST_B_MCLK_DIV] = &axg_mst_b_mclk_div.hw,
[AUD_CLKID_MST_C_MCLK_DIV] = &axg_mst_c_mclk_div.hw,
[AUD_CLKID_MST_D_MCLK_DIV] = &axg_mst_d_mclk_div.hw,
[AUD_CLKID_MST_E_MCLK_DIV] = &axg_mst_e_mclk_div.hw,
[AUD_CLKID_MST_F_MCLK_DIV] = &axg_mst_f_mclk_div.hw,
[AUD_CLKID_MST_A_MCLK] = &axg_mst_a_mclk.hw,
[AUD_CLKID_MST_B_MCLK] = &axg_mst_b_mclk.hw,
[AUD_CLKID_MST_C_MCLK] = &axg_mst_c_mclk.hw,
[AUD_CLKID_MST_D_MCLK] = &axg_mst_d_mclk.hw,
[AUD_CLKID_MST_E_MCLK] = &axg_mst_e_mclk.hw,
[AUD_CLKID_MST_F_MCLK] = &axg_mst_f_mclk.hw,
[AUD_CLKID_SPDIFOUT_CLK_SEL] = &axg_spdifout_clk_sel.hw,
[AUD_CLKID_SPDIFOUT_CLK_DIV] = &axg_spdifout_clk_div.hw,
[AUD_CLKID_SPDIFOUT_CLK] = &axg_spdifout_clk.hw,
[AUD_CLKID_SPDIFIN_CLK_SEL] = &axg_spdifin_clk_sel.hw,
[AUD_CLKID_SPDIFIN_CLK_DIV] = &axg_spdifin_clk_div.hw,
[AUD_CLKID_SPDIFIN_CLK] = &axg_spdifin_clk.hw,
[AUD_CLKID_PDM_DCLK_SEL] = &axg_pdm_dclk_sel.hw,
[AUD_CLKID_PDM_DCLK_DIV] = &axg_pdm_dclk_div.hw,
[AUD_CLKID_PDM_DCLK] = &axg_pdm_dclk.hw,
[AUD_CLKID_PDM_SYSCLK_SEL] = &axg_pdm_sysclk_sel.hw,
[AUD_CLKID_PDM_SYSCLK_DIV] = &axg_pdm_sysclk_div.hw,
[AUD_CLKID_PDM_SYSCLK] = &axg_pdm_sysclk.hw,
[AUD_CLKID_MST_A_SCLK_PRE_EN] = &axg_mst_a_sclk_pre_en.hw,
[AUD_CLKID_MST_B_SCLK_PRE_EN] = &axg_mst_b_sclk_pre_en.hw,
[AUD_CLKID_MST_C_SCLK_PRE_EN] = &axg_mst_c_sclk_pre_en.hw,
[AUD_CLKID_MST_D_SCLK_PRE_EN] = &axg_mst_d_sclk_pre_en.hw,
[AUD_CLKID_MST_E_SCLK_PRE_EN] = &axg_mst_e_sclk_pre_en.hw,
[AUD_CLKID_MST_F_SCLK_PRE_EN] = &axg_mst_f_sclk_pre_en.hw,
[AUD_CLKID_MST_A_SCLK_DIV] = &axg_mst_a_sclk_div.hw,
[AUD_CLKID_MST_B_SCLK_DIV] = &axg_mst_b_sclk_div.hw,
[AUD_CLKID_MST_C_SCLK_DIV] = &axg_mst_c_sclk_div.hw,
[AUD_CLKID_MST_D_SCLK_DIV] = &axg_mst_d_sclk_div.hw,
[AUD_CLKID_MST_E_SCLK_DIV] = &axg_mst_e_sclk_div.hw,
[AUD_CLKID_MST_F_SCLK_DIV] = &axg_mst_f_sclk_div.hw,
[AUD_CLKID_MST_A_SCLK_POST_EN] = &axg_mst_a_sclk_post_en.hw,
[AUD_CLKID_MST_B_SCLK_POST_EN] = &axg_mst_b_sclk_post_en.hw,
[AUD_CLKID_MST_C_SCLK_POST_EN] = &axg_mst_c_sclk_post_en.hw,
[AUD_CLKID_MST_D_SCLK_POST_EN] = &axg_mst_d_sclk_post_en.hw,
[AUD_CLKID_MST_E_SCLK_POST_EN] = &axg_mst_e_sclk_post_en.hw,
[AUD_CLKID_MST_F_SCLK_POST_EN] = &axg_mst_f_sclk_post_en.hw,
[AUD_CLKID_MST_A_SCLK] = &axg_mst_a_sclk.hw,
[AUD_CLKID_MST_B_SCLK] = &axg_mst_b_sclk.hw,
[AUD_CLKID_MST_C_SCLK] = &axg_mst_c_sclk.hw,
[AUD_CLKID_MST_D_SCLK] = &axg_mst_d_sclk.hw,
[AUD_CLKID_MST_E_SCLK] = &axg_mst_e_sclk.hw,
[AUD_CLKID_MST_F_SCLK] = &axg_mst_f_sclk.hw,
[AUD_CLKID_MST_A_LRCLK_DIV] = &axg_mst_a_lrclk_div.hw,
[AUD_CLKID_MST_B_LRCLK_DIV] = &axg_mst_b_lrclk_div.hw,
[AUD_CLKID_MST_C_LRCLK_DIV] = &axg_mst_c_lrclk_div.hw,
[AUD_CLKID_MST_D_LRCLK_DIV] = &axg_mst_d_lrclk_div.hw,
[AUD_CLKID_MST_E_LRCLK_DIV] = &axg_mst_e_lrclk_div.hw,
[AUD_CLKID_MST_F_LRCLK_DIV] = &axg_mst_f_lrclk_div.hw,
[AUD_CLKID_MST_A_LRCLK] = &axg_mst_a_lrclk.hw,
[AUD_CLKID_MST_B_LRCLK] = &axg_mst_b_lrclk.hw,
[AUD_CLKID_MST_C_LRCLK] = &axg_mst_c_lrclk.hw,
[AUD_CLKID_MST_D_LRCLK] = &axg_mst_d_lrclk.hw,
[AUD_CLKID_MST_E_LRCLK] = &axg_mst_e_lrclk.hw,
[AUD_CLKID_MST_F_LRCLK] = &axg_mst_f_lrclk.hw,
[AUD_CLKID_TDMIN_A_SCLK_SEL] = &axg_tdmin_a_sclk_sel.hw,
[AUD_CLKID_TDMIN_B_SCLK_SEL] = &axg_tdmin_b_sclk_sel.hw,
[AUD_CLKID_TDMIN_C_SCLK_SEL] = &axg_tdmin_c_sclk_sel.hw,
[AUD_CLKID_TDMIN_LB_SCLK_SEL] = &axg_tdmin_lb_sclk_sel.hw,
[AUD_CLKID_TDMOUT_A_SCLK_SEL] = &axg_tdmout_a_sclk_sel.hw,
[AUD_CLKID_TDMOUT_B_SCLK_SEL] = &axg_tdmout_b_sclk_sel.hw,
[AUD_CLKID_TDMOUT_C_SCLK_SEL] = &axg_tdmout_c_sclk_sel.hw,
[AUD_CLKID_TDMIN_A_SCLK_PRE_EN] = &axg_tdmin_a_sclk_pre_en.hw,
[AUD_CLKID_TDMIN_B_SCLK_PRE_EN] = &axg_tdmin_b_sclk_pre_en.hw,
[AUD_CLKID_TDMIN_C_SCLK_PRE_EN] = &axg_tdmin_c_sclk_pre_en.hw,
[AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &axg_tdmin_lb_sclk_pre_en.hw,
[AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &axg_tdmout_a_sclk_pre_en.hw,
[AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &axg_tdmout_b_sclk_pre_en.hw,
[AUD_CLKID_TDMOUT_C_SCLK_PRE_EN] = &axg_tdmout_c_sclk_pre_en.hw,
[AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &axg_tdmin_a_sclk_post_en.hw,
[AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &axg_tdmin_b_sclk_post_en.hw,
[AUD_CLKID_TDMIN_C_SCLK_POST_EN] = &axg_tdmin_c_sclk_post_en.hw,
[AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &axg_tdmin_lb_sclk_post_en.hw,
[AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &axg_tdmout_a_sclk_post_en.hw,
[AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &axg_tdmout_b_sclk_post_en.hw,
[AUD_CLKID_TDMOUT_C_SCLK_POST_EN] = &axg_tdmout_c_sclk_post_en.hw,
[AUD_CLKID_TDMIN_A_SCLK] = &axg_tdmin_a_sclk.hw,
[AUD_CLKID_TDMIN_B_SCLK] = &axg_tdmin_b_sclk.hw,
[AUD_CLKID_TDMIN_C_SCLK] = &axg_tdmin_c_sclk.hw,
[AUD_CLKID_TDMIN_LB_SCLK] = &axg_tdmin_lb_sclk.hw,
[AUD_CLKID_TDMOUT_A_SCLK] = &axg_tdmout_a_sclk.hw,
[AUD_CLKID_TDMOUT_B_SCLK] = &axg_tdmout_b_sclk.hw,
[AUD_CLKID_TDMOUT_C_SCLK] = &axg_tdmout_c_sclk.hw,
[AUD_CLKID_TDMIN_A_LRCLK] = &axg_tdmin_a_lrclk.hw,
[AUD_CLKID_TDMIN_B_LRCLK] = &axg_tdmin_b_lrclk.hw,
[AUD_CLKID_TDMIN_C_LRCLK] = &axg_tdmin_c_lrclk.hw,
[AUD_CLKID_TDMIN_LB_LRCLK] = &axg_tdmin_lb_lrclk.hw,
[AUD_CLKID_TDMOUT_A_LRCLK] = &axg_tdmout_a_lrclk.hw,
[AUD_CLKID_TDMOUT_B_LRCLK] = &axg_tdmout_b_lrclk.hw,
[AUD_CLKID_TDMOUT_C_LRCLK] = &axg_tdmout_c_lrclk.hw,
[NR_CLKS] = NULL,
},
.num = NR_CLKS,
};
/* Convenience table to populate regmap in .probe() */
static struct clk_regmap *const axg_audio_clk_regmaps[] = {
&axg_ddr_arb,
&axg_pdm,
&axg_tdmin_a,
&axg_tdmin_b,
&axg_tdmin_c,
&axg_tdmin_lb,
&axg_tdmout_a,
&axg_tdmout_b,
&axg_tdmout_c,
&axg_frddr_a,
&axg_frddr_b,
&axg_frddr_c,
&axg_toddr_a,
&axg_toddr_b,
&axg_toddr_c,
&axg_loopback,
&axg_spdifin,
&axg_spdifout,
&axg_resample,
&axg_power_detect,
&axg_mst_a_mclk_sel,
&axg_mst_b_mclk_sel,
&axg_mst_c_mclk_sel,
&axg_mst_d_mclk_sel,
&axg_mst_e_mclk_sel,
&axg_mst_f_mclk_sel,
&axg_mst_a_mclk_div,
&axg_mst_b_mclk_div,
&axg_mst_c_mclk_div,
&axg_mst_d_mclk_div,
&axg_mst_e_mclk_div,
&axg_mst_f_mclk_div,
&axg_mst_a_mclk,
&axg_mst_b_mclk,
&axg_mst_c_mclk,
&axg_mst_d_mclk,
&axg_mst_e_mclk,
&axg_mst_f_mclk,
&axg_spdifout_clk_sel,
&axg_spdifout_clk_div,
&axg_spdifout_clk,
&axg_spdifin_clk_sel,
&axg_spdifin_clk_div,
&axg_spdifin_clk,
&axg_pdm_dclk_sel,
&axg_pdm_dclk_div,
&axg_pdm_dclk,
&axg_pdm_sysclk_sel,
&axg_pdm_sysclk_div,
&axg_pdm_sysclk,
&axg_mst_a_sclk_pre_en,
&axg_mst_b_sclk_pre_en,
&axg_mst_c_sclk_pre_en,
&axg_mst_d_sclk_pre_en,
&axg_mst_e_sclk_pre_en,
&axg_mst_f_sclk_pre_en,
&axg_mst_a_sclk_div,
&axg_mst_b_sclk_div,
&axg_mst_c_sclk_div,
&axg_mst_d_sclk_div,
&axg_mst_e_sclk_div,
&axg_mst_f_sclk_div,
&axg_mst_a_sclk_post_en,
&axg_mst_b_sclk_post_en,
&axg_mst_c_sclk_post_en,
&axg_mst_d_sclk_post_en,
&axg_mst_e_sclk_post_en,
&axg_mst_f_sclk_post_en,
&axg_mst_a_sclk,
&axg_mst_b_sclk,
&axg_mst_c_sclk,
&axg_mst_d_sclk,
&axg_mst_e_sclk,
&axg_mst_f_sclk,
&axg_mst_a_lrclk_div,
&axg_mst_b_lrclk_div,
&axg_mst_c_lrclk_div,
&axg_mst_d_lrclk_div,
&axg_mst_e_lrclk_div,
&axg_mst_f_lrclk_div,
&axg_mst_a_lrclk,
&axg_mst_b_lrclk,
&axg_mst_c_lrclk,
&axg_mst_d_lrclk,
&axg_mst_e_lrclk,
&axg_mst_f_lrclk,
&axg_tdmin_a_sclk_sel,
&axg_tdmin_b_sclk_sel,
&axg_tdmin_c_sclk_sel,
&axg_tdmin_lb_sclk_sel,
&axg_tdmout_a_sclk_sel,
&axg_tdmout_b_sclk_sel,
&axg_tdmout_c_sclk_sel,
&axg_tdmin_a_sclk_pre_en,
&axg_tdmin_b_sclk_pre_en,
&axg_tdmin_c_sclk_pre_en,
&axg_tdmin_lb_sclk_pre_en,
&axg_tdmout_a_sclk_pre_en,
&axg_tdmout_b_sclk_pre_en,
&axg_tdmout_c_sclk_pre_en,
&axg_tdmin_a_sclk_post_en,
&axg_tdmin_b_sclk_post_en,
&axg_tdmin_c_sclk_post_en,
&axg_tdmin_lb_sclk_post_en,
&axg_tdmout_a_sclk_post_en,
&axg_tdmout_b_sclk_post_en,
&axg_tdmout_c_sclk_post_en,
&axg_tdmin_a_sclk,
&axg_tdmin_b_sclk,
&axg_tdmin_c_sclk,
&axg_tdmin_lb_sclk,
&axg_tdmout_a_sclk,
&axg_tdmout_b_sclk,
&axg_tdmout_c_sclk,
&axg_tdmin_a_lrclk,
&axg_tdmin_b_lrclk,
&axg_tdmin_c_lrclk,
&axg_tdmin_lb_lrclk,
&axg_tdmout_a_lrclk,
&axg_tdmout_b_lrclk,
&axg_tdmout_c_lrclk,
};
static struct clk *devm_clk_get_enable(struct device *dev, char *id)
{
struct clk *clk;
int ret;
clk = devm_clk_get(dev, id);
if (IS_ERR(clk)) {
if (PTR_ERR(clk) != -EPROBE_DEFER)
dev_err(dev, "failed to get %s", id);
return clk;
}
ret = clk_prepare_enable(clk);
if (ret) {
dev_err(dev, "failed to enable %s", id);
return ERR_PTR(ret);
}
ret = devm_add_action_or_reset(dev,
(void(*)(void *))clk_disable_unprepare,
clk);
if (ret) {
dev_err(dev, "failed to add reset action on %s", id);
return ERR_PTR(ret);
}
return clk;
}
static const struct clk_ops axg_clk_no_ops = {};
static struct clk_hw *axg_clk_hw_register_bypass(struct device *dev,
const char *name,
const char *parent_name)
{
struct clk_hw *hw;
struct clk_init_data init;
char *clk_name;
int ret;
hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
if (!hw)
return ERR_PTR(-ENOMEM);
clk_name = kasprintf(GFP_KERNEL, "axg_%s", name);
if (!clk_name)
return ERR_PTR(-ENOMEM);
init.name = clk_name;
init.ops = &axg_clk_no_ops;
init.flags = 0;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
hw->init = &init;
ret = devm_clk_hw_register(dev, hw);
kfree(clk_name);
return ret ? ERR_PTR(ret) : hw;
}
static int axg_register_clk_hw_input(struct device *dev,
const char *name,
unsigned int clkid)
{
struct clk *parent_clk = devm_clk_get(dev, name);
struct clk_hw *hw = NULL;
if (IS_ERR(parent_clk)) {
int err = PTR_ERR(parent_clk);
/* It is ok if an input clock is missing */
if (err == -ENOENT) {
dev_dbg(dev, "%s not provided", name);
} else {
if (err != -EPROBE_DEFER)
dev_err(dev, "failed to get %s clock", name);
return err;
}
} else {
hw = axg_clk_hw_register_bypass(dev, name,
__clk_get_name(parent_clk));
}
if (IS_ERR(hw)) {
dev_err(dev, "failed to register %s clock", name);
return PTR_ERR(hw);
}
axg_audio_hw_onecell_data.hws[clkid] = hw;
return 0;
}
static int axg_register_clk_hw_inputs(struct device *dev,
const char *basename,
unsigned int count,
unsigned int clkid)
{
char *name;
int i, ret;
for (i = 0; i < count; i++) {
name = kasprintf(GFP_KERNEL, "%s%d", basename, i);
if (!name)
return -ENOMEM;
ret = axg_register_clk_hw_input(dev, name, clkid + i);
kfree(name);
if (ret)
return ret;
}
return 0;
}
static const struct regmap_config axg_audio_regmap_cfg = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = AUDIO_CLK_PDMIN_CTRL1,
};
static int axg_audio_clkc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct regmap *map;
struct resource *res;
void __iomem *regs;
struct clk *clk;
struct clk_hw *hw;
int ret, i;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(dev, res);
if (IS_ERR(regs))
return PTR_ERR(regs);
map = devm_regmap_init_mmio(dev, regs, &axg_audio_regmap_cfg);
if (IS_ERR(map)) {
dev_err(dev, "failed to init regmap: %ld\n", PTR_ERR(map));
return PTR_ERR(map);
}
/* Get the mandatory peripheral clock */
clk = devm_clk_get_enable(dev, "pclk");
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = device_reset(dev);
if (ret) {
dev_err(dev, "failed to reset device\n");
return ret;
}
/* Register the peripheral input clock */
hw = axg_clk_hw_register_bypass(dev, "audio_pclk",
__clk_get_name(clk));
if (IS_ERR(hw))
return PTR_ERR(hw);
axg_audio_hw_onecell_data.hws[AUD_CLKID_PCLK] = hw;
/* Register optional input master clocks */
ret = axg_register_clk_hw_inputs(dev, "mst_in",
AXG_MST_IN_COUNT,
AUD_CLKID_MST0);
if (ret)
return ret;
/* Register optional input slave sclks */
ret = axg_register_clk_hw_inputs(dev, "slv_sclk",
AXG_SLV_SCLK_COUNT,
AUD_CLKID_SLV_SCLK0);
if (ret)
return ret;
/* Register optional input slave lrclks */
ret = axg_register_clk_hw_inputs(dev, "slv_lrclk",
AXG_SLV_LRCLK_COUNT,
AUD_CLKID_SLV_LRCLK0);
if (ret)
return ret;
/* Populate regmap for the regmap backed clocks */
for (i = 0; i < ARRAY_SIZE(axg_audio_clk_regmaps); i++)
axg_audio_clk_regmaps[i]->map = map;
/* Take care to skip the registered input clocks */
for (i = AUD_CLKID_DDR_ARB; i < axg_audio_hw_onecell_data.num; i++) {
hw = axg_audio_hw_onecell_data.hws[i];
/* array might be sparse */
if (!hw)
continue;
ret = devm_clk_hw_register(dev, hw);
if (ret) {
dev_err(dev, "failed to register clock %s\n",
hw->init->name);
return ret;
}
}
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
&axg_audio_hw_onecell_data);
}
static const struct of_device_id clkc_match_table[] = {
{ .compatible = "amlogic,axg-audio-clkc" },
{}
};
MODULE_DEVICE_TABLE(of, clkc_match_table);
static struct platform_driver axg_audio_driver = {
.probe = axg_audio_clkc_probe,
.driver = {
.name = "axg-audio-clkc",
.of_match_table = clkc_match_table,
},
};
module_platform_driver(axg_audio_driver);
MODULE_DESCRIPTION("Amlogic A113x Audio Clock driver");
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,127 @@
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
/*
* Copyright (c) 2018 BayLibre, SAS.
* Author: Jerome Brunet <jbrunet@baylibre.com>
*/
#ifndef __AXG_AUDIO_CLKC_H
#define __AXG_AUDIO_CLKC_H
/*
* Audio Clock register offsets
*
* Register offsets from the datasheet must be multiplied by 4 before
* to get the right offset
*/
#define AUDIO_CLK_GATE_EN 0x000
#define AUDIO_MCLK_A_CTRL 0x004
#define AUDIO_MCLK_B_CTRL 0x008
#define AUDIO_MCLK_C_CTRL 0x00C
#define AUDIO_MCLK_D_CTRL 0x010
#define AUDIO_MCLK_E_CTRL 0x014
#define AUDIO_MCLK_F_CTRL 0x018
#define AUDIO_MST_A_SCLK_CTRL0 0x040
#define AUDIO_MST_A_SCLK_CTRL1 0x044
#define AUDIO_MST_B_SCLK_CTRL0 0x048
#define AUDIO_MST_B_SCLK_CTRL1 0x04C
#define AUDIO_MST_C_SCLK_CTRL0 0x050
#define AUDIO_MST_C_SCLK_CTRL1 0x054
#define AUDIO_MST_D_SCLK_CTRL0 0x058
#define AUDIO_MST_D_SCLK_CTRL1 0x05C
#define AUDIO_MST_E_SCLK_CTRL0 0x060
#define AUDIO_MST_E_SCLK_CTRL1 0x064
#define AUDIO_MST_F_SCLK_CTRL0 0x068
#define AUDIO_MST_F_SCLK_CTRL1 0x06C
#define AUDIO_CLK_TDMIN_A_CTRL 0x080
#define AUDIO_CLK_TDMIN_B_CTRL 0x084
#define AUDIO_CLK_TDMIN_C_CTRL 0x088
#define AUDIO_CLK_TDMIN_LB_CTRL 0x08C
#define AUDIO_CLK_TDMOUT_A_CTRL 0x090
#define AUDIO_CLK_TDMOUT_B_CTRL 0x094
#define AUDIO_CLK_TDMOUT_C_CTRL 0x098
#define AUDIO_CLK_SPDIFIN_CTRL 0x09C
#define AUDIO_CLK_SPDIFOUT_CTRL 0x0A0
#define AUDIO_CLK_RESAMPLE_CTRL 0x0A4
#define AUDIO_CLK_LOCKER_CTRL 0x0A8
#define AUDIO_CLK_PDMIN_CTRL0 0x0AC
#define AUDIO_CLK_PDMIN_CTRL1 0x0B0
/*
* CLKID index values
* These indices are entirely contrived and do not map onto the hardware.
*/
#define AUD_CLKID_PCLK 0
#define AUD_CLKID_MST0 1
#define AUD_CLKID_MST1 2
#define AUD_CLKID_MST2 3
#define AUD_CLKID_MST3 4
#define AUD_CLKID_MST4 5
#define AUD_CLKID_MST5 6
#define AUD_CLKID_MST6 7
#define AUD_CLKID_MST7 8
#define AUD_CLKID_MST_A_MCLK_SEL 59
#define AUD_CLKID_MST_B_MCLK_SEL 60
#define AUD_CLKID_MST_C_MCLK_SEL 61
#define AUD_CLKID_MST_D_MCLK_SEL 62
#define AUD_CLKID_MST_E_MCLK_SEL 63
#define AUD_CLKID_MST_F_MCLK_SEL 64
#define AUD_CLKID_MST_A_MCLK_DIV 65
#define AUD_CLKID_MST_B_MCLK_DIV 66
#define AUD_CLKID_MST_C_MCLK_DIV 67
#define AUD_CLKID_MST_D_MCLK_DIV 68
#define AUD_CLKID_MST_E_MCLK_DIV 69
#define AUD_CLKID_MST_F_MCLK_DIV 70
#define AUD_CLKID_SPDIFOUT_CLK_SEL 71
#define AUD_CLKID_SPDIFOUT_CLK_DIV 72
#define AUD_CLKID_SPDIFIN_CLK_SEL 73
#define AUD_CLKID_SPDIFIN_CLK_DIV 74
#define AUD_CLKID_PDM_DCLK_SEL 75
#define AUD_CLKID_PDM_DCLK_DIV 76
#define AUD_CLKID_PDM_SYSCLK_SEL 77
#define AUD_CLKID_PDM_SYSCLK_DIV 78
#define AUD_CLKID_MST_A_SCLK_PRE_EN 92
#define AUD_CLKID_MST_B_SCLK_PRE_EN 93
#define AUD_CLKID_MST_C_SCLK_PRE_EN 94
#define AUD_CLKID_MST_D_SCLK_PRE_EN 95
#define AUD_CLKID_MST_E_SCLK_PRE_EN 96
#define AUD_CLKID_MST_F_SCLK_PRE_EN 97
#define AUD_CLKID_MST_A_SCLK_DIV 98
#define AUD_CLKID_MST_B_SCLK_DIV 99
#define AUD_CLKID_MST_C_SCLK_DIV 100
#define AUD_CLKID_MST_D_SCLK_DIV 101
#define AUD_CLKID_MST_E_SCLK_DIV 102
#define AUD_CLKID_MST_F_SCLK_DIV 103
#define AUD_CLKID_MST_A_SCLK_POST_EN 104
#define AUD_CLKID_MST_B_SCLK_POST_EN 105
#define AUD_CLKID_MST_C_SCLK_POST_EN 106
#define AUD_CLKID_MST_D_SCLK_POST_EN 107
#define AUD_CLKID_MST_E_SCLK_POST_EN 108
#define AUD_CLKID_MST_F_SCLK_POST_EN 109
#define AUD_CLKID_MST_A_LRCLK_DIV 110
#define AUD_CLKID_MST_B_LRCLK_DIV 111
#define AUD_CLKID_MST_C_LRCLK_DIV 112
#define AUD_CLKID_MST_D_LRCLK_DIV 113
#define AUD_CLKID_MST_E_LRCLK_DIV 114
#define AUD_CLKID_MST_F_LRCLK_DIV 115
#define AUD_CLKID_TDMIN_A_SCLK_PRE_EN 137
#define AUD_CLKID_TDMIN_B_SCLK_PRE_EN 138
#define AUD_CLKID_TDMIN_C_SCLK_PRE_EN 139
#define AUD_CLKID_TDMIN_LB_SCLK_PRE_EN 140
#define AUD_CLKID_TDMOUT_A_SCLK_PRE_EN 141
#define AUD_CLKID_TDMOUT_B_SCLK_PRE_EN 142
#define AUD_CLKID_TDMOUT_C_SCLK_PRE_EN 143
#define AUD_CLKID_TDMIN_A_SCLK_POST_EN 144
#define AUD_CLKID_TDMIN_B_SCLK_POST_EN 145
#define AUD_CLKID_TDMIN_C_SCLK_POST_EN 146
#define AUD_CLKID_TDMIN_LB_SCLK_POST_EN 147
#define AUD_CLKID_TDMOUT_A_SCLK_POST_EN 148
#define AUD_CLKID_TDMOUT_B_SCLK_POST_EN 149
#define AUD_CLKID_TDMOUT_C_SCLK_POST_EN 150
/* include the CLKIDs which are part of the DT bindings */
#include <dt-bindings/clock/axg-audio-clkc.h>
#define NR_CLKS 151
#endif /*__AXG_AUDIO_CLKC_H */

View File

@ -12,7 +12,6 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/init.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_device.h>
@ -626,6 +625,137 @@ static struct clk_regmap axg_mpll3 = {
},
};
static const struct pll_rate_table axg_pcie_pll_rate_table[] = {
{
.rate = 100000000,
.m = 200,
.n = 3,
.od = 1,
.od2 = 3,
},
{ /* sentinel */ },
};
static const struct reg_sequence axg_pcie_init_regs[] = {
{ .reg = HHI_PCIE_PLL_CNTL, .def = 0x400106c8 },
{ .reg = HHI_PCIE_PLL_CNTL1, .def = 0x0084a2aa },
{ .reg = HHI_PCIE_PLL_CNTL2, .def = 0xb75020be },
{ .reg = HHI_PCIE_PLL_CNTL3, .def = 0x0a47488e },
{ .reg = HHI_PCIE_PLL_CNTL4, .def = 0xc000004d },
{ .reg = HHI_PCIE_PLL_CNTL5, .def = 0x00078000 },
{ .reg = HHI_PCIE_PLL_CNTL6, .def = 0x002323c6 },
};
static struct clk_regmap axg_pcie_pll = {
.data = &(struct meson_clk_pll_data){
.m = {
.reg_off = HHI_PCIE_PLL_CNTL,
.shift = 0,
.width = 9,
},
.n = {
.reg_off = HHI_PCIE_PLL_CNTL,
.shift = 9,
.width = 5,
},
.od = {
.reg_off = HHI_PCIE_PLL_CNTL,
.shift = 16,
.width = 2,
},
.od2 = {
.reg_off = HHI_PCIE_PLL_CNTL6,
.shift = 6,
.width = 2,
},
.frac = {
.reg_off = HHI_PCIE_PLL_CNTL1,
.shift = 0,
.width = 12,
},
.l = {
.reg_off = HHI_PCIE_PLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_PCIE_PLL_CNTL,
.shift = 29,
.width = 1,
},
.table = axg_pcie_pll_rate_table,
.init_regs = axg_pcie_init_regs,
.init_count = ARRAY_SIZE(axg_pcie_init_regs),
},
.hw.init = &(struct clk_init_data){
.name = "pcie_pll",
.ops = &meson_clk_pll_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
},
};
static struct clk_regmap axg_pcie_mux = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_PCIE_PLL_CNTL6,
.mask = 0x1,
.shift = 2,
},
.hw.init = &(struct clk_init_data){
.name = "pcie_mux",
.ops = &clk_regmap_mux_ops,
.parent_names = (const char *[]){ "mpll3", "pcie_pll" },
.num_parents = 2,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap axg_pcie_ref = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_PCIE_PLL_CNTL6,
.mask = 0x1,
.shift = 1,
/* skip the parent 0, reserved for debug */
.table = (u32[]){ 1 },
},
.hw.init = &(struct clk_init_data){
.name = "pcie_ref",
.ops = &clk_regmap_mux_ops,
.parent_names = (const char *[]){ "pcie_mux" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap axg_pcie_cml_en0 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_PCIE_PLL_CNTL6,
.bit_idx = 4,
},
.hw.init = &(struct clk_init_data) {
.name = "pcie_cml_en0",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "pcie_ref" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap axg_pcie_cml_en1 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_PCIE_PLL_CNTL6,
.bit_idx = 3,
},
.hw.init = &(struct clk_init_data) {
.name = "pcie_cml_en1",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "pcie_ref" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 };
static const char * const clk81_parent_names[] = {
"xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4",
@ -779,6 +909,63 @@ static struct clk_regmap axg_sd_emmc_c_clk0 = {
},
};
static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8,
9, 10, 11, 13, 14, };
static const char * const gen_clk_parent_names[] = {
"xtal", "hifi_pll", "mpll0", "mpll1", "mpll2", "mpll3",
"fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", "gp0_pll",
};
static struct clk_regmap axg_gen_clk_sel = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_GEN_CLK_CNTL,
.mask = 0xf,
.shift = 12,
.table = mux_table_gen_clk,
},
.hw.init = &(struct clk_init_data){
.name = "gen_clk_sel",
.ops = &clk_regmap_mux_ops,
/*
* bits 15:12 selects from 14 possible parents:
* xtal, [rtc_oscin_i], [sys_cpu_div16], [ddr_dpll_pt],
* hifi_pll, mpll0, mpll1, mpll2, mpll3, fdiv4,
* fdiv3, fdiv5, [cts_msr_clk], fdiv7, gp0_pll
*/
.parent_names = gen_clk_parent_names,
.num_parents = ARRAY_SIZE(gen_clk_parent_names),
},
};
static struct clk_regmap axg_gen_clk_div = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_GEN_CLK_CNTL,
.shift = 0,
.width = 11,
},
.hw.init = &(struct clk_init_data){
.name = "gen_clk_div",
.ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "gen_clk_sel" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap axg_gen_clk = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_GEN_CLK_CNTL,
.bit_idx = 7,
},
.hw.init = &(struct clk_init_data){
.name = "gen_clk",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "gen_clk_div" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
/* Everything Else (EE) domain gates */
static MESON_GATE(axg_ddr, HHI_GCLK_MPEG0, 0);
static MESON_GATE(axg_audio_locker, HHI_GCLK_MPEG0, 2);
@ -821,6 +1008,7 @@ static MESON_GATE(axg_mmc_pclk, HHI_GCLK_MPEG2, 11);
static MESON_GATE(axg_vpu_intr, HHI_GCLK_MPEG2, 25);
static MESON_GATE(axg_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26);
static MESON_GATE(axg_gic, HHI_GCLK_MPEG2, 30);
static MESON_GATE(axg_mipi_enable, HHI_MIPI_CNTL0, 29);
/* Always On (AO) domain gates */
@ -910,6 +1098,15 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = {
[CLKID_FCLK_DIV4_DIV] = &axg_fclk_div4_div.hw,
[CLKID_FCLK_DIV5_DIV] = &axg_fclk_div5_div.hw,
[CLKID_FCLK_DIV7_DIV] = &axg_fclk_div7_div.hw,
[CLKID_PCIE_PLL] = &axg_pcie_pll.hw,
[CLKID_PCIE_MUX] = &axg_pcie_mux.hw,
[CLKID_PCIE_REF] = &axg_pcie_ref.hw,
[CLKID_PCIE_CML_EN0] = &axg_pcie_cml_en0.hw,
[CLKID_PCIE_CML_EN1] = &axg_pcie_cml_en1.hw,
[CLKID_MIPI_ENABLE] = &axg_mipi_enable.hw,
[CLKID_GEN_CLK_SEL] = &axg_gen_clk_sel.hw,
[CLKID_GEN_CLK_DIV] = &axg_gen_clk_div.hw,
[CLKID_GEN_CLK] = &axg_gen_clk.hw,
[NR_CLKS] = NULL,
},
.num = NR_CLKS,
@ -988,6 +1185,15 @@ static struct clk_regmap *const axg_clk_regmaps[] = {
&axg_fclk_div4,
&axg_fclk_div5,
&axg_fclk_div7,
&axg_pcie_pll,
&axg_pcie_mux,
&axg_pcie_ref,
&axg_pcie_cml_en0,
&axg_pcie_cml_en1,
&axg_mipi_enable,
&axg_gen_clk_sel,
&axg_gen_clk_div,
&axg_gen_clk,
};
static const struct of_device_id clkc_match_table[] = {
@ -995,49 +1201,17 @@ static const struct of_device_id clkc_match_table[] = {
{}
};
static const struct regmap_config clkc_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
};
static int axg_clkc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
void __iomem *clk_base = NULL;
struct regmap *map;
int ret, i;
/* Get the hhi system controller node if available */
map = syscon_node_to_regmap(of_get_parent(dev->of_node));
if (IS_ERR(map)) {
dev_err(dev,
"failed to get HHI regmap - Trying obsolete regs\n");
/*
* FIXME: HHI registers should be accessed through
* the appropriate system controller. This is required because
* there is more than just clocks in this register space
*
* This fallback method is only provided temporarily until
* all the platform DTs are properly using the syscon node
*/
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -EINVAL;
clk_base = devm_ioremap(dev, res->start, resource_size(res));
if (!clk_base) {
dev_err(dev, "Unable to map clk base\n");
return -ENXIO;
}
map = devm_regmap_init_mmio(dev, clk_base,
&clkc_regmap_config);
if (IS_ERR(map))
return PTR_ERR(map);
dev_err(dev, "failed to get HHI regmap\n");
return PTR_ERR(map);
}
/* Populate regmap for the regmap backed clocks */

View File

@ -16,6 +16,7 @@
* Register offsets from the data sheet must be multiplied by 4 before
* adding them to the base address to get the right value.
*/
#define HHI_MIPI_CNTL0 0x00
#define HHI_GP0_PLL_CNTL 0x40
#define HHI_GP0_PLL_CNTL2 0x44
#define HHI_GP0_PLL_CNTL3 0x48
@ -127,8 +128,13 @@
#define CLKID_FCLK_DIV4_DIV 73
#define CLKID_FCLK_DIV5_DIV 74
#define CLKID_FCLK_DIV7_DIV 75
#define CLKID_PCIE_PLL 76
#define CLKID_PCIE_MUX 77
#define CLKID_PCIE_REF 78
#define CLKID_GEN_CLK_SEL 82
#define CLKID_GEN_CLK_DIV 83
#define NR_CLKS 76
#define NR_CLKS 85
/* include the CLKIDs that have been made part of the DT binding */
#include <dt-bindings/clock/axg-clkc.h>

View File

@ -1,110 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2017 AmLogic, Inc.
* Author: Jerome Brunet <jbrunet@baylibre.com>
*/
/*
* i2s master clock divider: The algorithm of the generic clk-divider used with
* a very precise clock parent such as the mpll tends to select a low divider
* factor. This gives poor results with this particular divider, especially with
* high frequencies (> 100 MHz)
*
* This driver try to select the maximum possible divider with the rate the
* upstream clock can provide.
*/
#include <linux/clk-provider.h>
#include "clkc.h"
static inline struct meson_clk_audio_div_data *
meson_clk_audio_div_data(struct clk_regmap *clk)
{
return (struct meson_clk_audio_div_data *)clk->data;
}
static int _div_round(unsigned long parent_rate, unsigned long rate,
unsigned long flags)
{
if (flags & CLK_DIVIDER_ROUND_CLOSEST)
return DIV_ROUND_CLOSEST_ULL((u64)parent_rate, rate);
return DIV_ROUND_UP_ULL((u64)parent_rate, rate);
}
static int _get_val(unsigned long parent_rate, unsigned long rate)
{
return DIV_ROUND_UP_ULL((u64)parent_rate, rate) - 1;
}
static int _valid_divider(unsigned int width, int divider)
{
int max_divider = 1 << width;
return clamp(divider, 1, max_divider);
}
static unsigned long audio_divider_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk);
unsigned long divider;
divider = meson_parm_read(clk->map, &adiv->div) + 1;
return DIV_ROUND_UP_ULL((u64)parent_rate, divider);
}
static long audio_divider_round_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long *parent_rate)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk);
unsigned long max_prate;
int divider;
if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
divider = _div_round(*parent_rate, rate, adiv->flags);
divider = _valid_divider(adiv->div.width, divider);
return DIV_ROUND_UP_ULL((u64)*parent_rate, divider);
}
/* Get the maximum parent rate */
max_prate = clk_hw_round_rate(clk_hw_get_parent(hw), ULONG_MAX);
/* Get the corresponding rounded down divider */
divider = max_prate / rate;
divider = _valid_divider(adiv->div.width, divider);
/* Get actual rate of the parent */
*parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
divider * rate);
return DIV_ROUND_UP_ULL((u64)*parent_rate, divider);
}
static int audio_divider_set_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk);
int val = _get_val(parent_rate, rate);
meson_parm_write(clk->map, &adiv->div, val);
return 0;
}
const struct clk_ops meson_clk_audio_divider_ro_ops = {
.recalc_rate = audio_divider_recalc_rate,
.round_rate = audio_divider_round_rate,
};
const struct clk_ops meson_clk_audio_divider_ops = {
.recalc_rate = audio_divider_recalc_rate,
.round_rate = audio_divider_round_rate,
.set_rate = audio_divider_set_rate,
};

View File

@ -0,0 +1,63 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Copyright (c) 2018 BayLibre, SAS.
* Author: Jerome Brunet <jbrunet@baylibre.com>
*/
#include <linux/clk-provider.h>
#include "clkc.h"
#define phase_step(_width) (360 / (1 << (_width)))
static inline struct meson_clk_phase_data *
meson_clk_phase_data(struct clk_regmap *clk)
{
return (struct meson_clk_phase_data *)clk->data;
}
int meson_clk_degrees_from_val(unsigned int val, unsigned int width)
{
return phase_step(width) * val;
}
EXPORT_SYMBOL_GPL(meson_clk_degrees_from_val);
unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width)
{
unsigned int val = DIV_ROUND_CLOSEST(degrees, phase_step(width));
/*
* This last calculation is here for cases when degrees is rounded
* to 360, in which case val == (1 << width).
*/
return val % (1 << width);
}
EXPORT_SYMBOL_GPL(meson_clk_degrees_to_val);
static int meson_clk_phase_get_phase(struct clk_hw *hw)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_phase_data *phase = meson_clk_phase_data(clk);
unsigned int val;
val = meson_parm_read(clk->map, &phase->ph);
return meson_clk_degrees_from_val(val, phase->ph.width);
}
static int meson_clk_phase_set_phase(struct clk_hw *hw, int degrees)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_phase_data *phase = meson_clk_phase_data(clk);
unsigned int val;
val = meson_clk_degrees_to_val(degrees, phase->ph.width);
meson_parm_write(clk->map, &phase->ph, val);
return 0;
}
const struct clk_ops meson_clk_phase_ops = {
.get_phase = meson_clk_phase_get_phase,
.set_phase = meson_clk_phase_set_phase,
};
EXPORT_SYMBOL_GPL(meson_clk_phase_ops);

View File

@ -0,0 +1,68 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Copyright (c) 2018 BayLibre, SAS.
* Author: Jerome Brunet <jbrunet@baylibre.com>
*/
#include <linux/clk-provider.h>
#include "clkc-audio.h"
/*
* This is a special clock for the audio controller.
* The phase of mst_sclk clock output can be controlled independently
* for the outside world (ph0), the tdmout (ph1) and tdmin (ph2).
* Controlling these 3 phases as just one makes things simpler and
* give the same clock view to all the element on the i2s bus.
* If necessary, we can still control the phase in the tdm block
* which makes these independent control redundant.
*/
static inline struct meson_clk_triphase_data *
meson_clk_triphase_data(struct clk_regmap *clk)
{
return (struct meson_clk_triphase_data *)clk->data;
}
static void meson_clk_triphase_sync(struct clk_hw *hw)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
unsigned int val;
/* Get phase 0 and sync it to phase 1 and 2 */
val = meson_parm_read(clk->map, &tph->ph0);
meson_parm_write(clk->map, &tph->ph1, val);
meson_parm_write(clk->map, &tph->ph2, val);
}
static int meson_clk_triphase_get_phase(struct clk_hw *hw)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
unsigned int val;
/* Phase are in sync, reading phase 0 is enough */
val = meson_parm_read(clk->map, &tph->ph0);
return meson_clk_degrees_from_val(val, tph->ph0.width);
}
static int meson_clk_triphase_set_phase(struct clk_hw *hw, int degrees)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
unsigned int val;
val = meson_clk_degrees_to_val(degrees, tph->ph0.width);
meson_parm_write(clk->map, &tph->ph0, val);
meson_parm_write(clk->map, &tph->ph1, val);
meson_parm_write(clk->map, &tph->ph2, val);
return 0;
}
const struct clk_ops meson_clk_triphase_ops = {
.init = meson_clk_triphase_sync,
.get_phase = meson_clk_triphase_get_phase,
.set_phase = meson_clk_triphase_set_phase,
};
EXPORT_SYMBOL_GPL(meson_clk_triphase_ops);

View File

@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2018 BayLibre, SAS.
* Author: Jerome Brunet <jbrunet@baylibre.com>
*/
#ifndef __MESON_CLKC_AUDIO_H
#define __MESON_CLKC_AUDIO_H
#include "clkc.h"
struct meson_clk_triphase_data {
struct parm ph0;
struct parm ph1;
struct parm ph2;
};
struct meson_sclk_div_data {
struct parm div;
struct parm hi;
unsigned int cached_div;
struct clk_duty cached_duty;
};
extern const struct clk_ops meson_clk_triphase_ops;
extern const struct clk_ops meson_sclk_div_ops;
#endif /* __MESON_CLKC_AUDIO_H */

View File

@ -91,11 +91,13 @@ struct meson_clk_mpll_data {
#define CLK_MESON_MPLL_ROUND_CLOSEST BIT(0)
struct meson_clk_audio_div_data {
struct parm div;
u8 flags;
struct meson_clk_phase_data {
struct parm ph;
};
int meson_clk_degrees_from_val(unsigned int val, unsigned int width);
unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width);
#define MESON_GATE(_name, _reg, _bit) \
struct clk_regmap _name = { \
.data = &(struct clk_regmap_gate_data){ \
@ -117,7 +119,6 @@ extern const struct clk_ops meson_clk_pll_ops;
extern const struct clk_ops meson_clk_cpu_ops;
extern const struct clk_ops meson_clk_mpll_ro_ops;
extern const struct clk_ops meson_clk_mpll_ops;
extern const struct clk_ops meson_clk_audio_divider_ro_ops;
extern const struct clk_ops meson_clk_audio_divider_ops;
extern const struct clk_ops meson_clk_phase_ops;
#endif /* __CLKC_H */

View File

@ -7,7 +7,6 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/init.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_device.h>
@ -971,28 +970,26 @@ static struct clk_regmap gxbb_cts_amclk_sel = {
.mask = 0x3,
.shift = 9,
.table = (u32[]){ 1, 2, 3 },
.flags = CLK_MUX_ROUND_CLOSEST,
},
.hw.init = &(struct clk_init_data){
.name = "cts_amclk_sel",
.ops = &clk_regmap_mux_ops,
.parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" },
.num_parents = 3,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap gxbb_cts_amclk_div = {
.data = &(struct meson_clk_audio_div_data){
.div = {
.reg_off = HHI_AUD_CLK_CNTL,
.shift = 0,
.width = 8,
},
.data = &(struct clk_regmap_div_data) {
.offset = HHI_AUD_CLK_CNTL,
.shift = 0,
.width = 8,
.flags = CLK_DIVIDER_ROUND_CLOSEST,
},
.hw.init = &(struct clk_init_data){
.name = "cts_amclk_div",
.ops = &meson_clk_audio_divider_ops,
.ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "cts_amclk_sel" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@ -1019,13 +1016,13 @@ static struct clk_regmap gxbb_cts_mclk_i958_sel = {
.mask = 0x3,
.shift = 25,
.table = (u32[]){ 1, 2, 3 },
.flags = CLK_MUX_ROUND_CLOSEST,
},
.hw.init = &(struct clk_init_data) {
.name = "cts_mclk_i958_sel",
.ops = &clk_regmap_mux_ops,
.parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" },
.num_parents = 3,
.flags = CLK_SET_RATE_PARENT,
},
};
@ -1627,6 +1624,63 @@ static struct clk_regmap gxbb_vdec_hevc = {
},
};
static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8,
9, 10, 11, 13, 14, };
static const char * const gen_clk_parent_names[] = {
"xtal", "vdec_1", "vdec_hevc", "mpll0", "mpll1", "mpll2",
"fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", "gp0_pll",
};
static struct clk_regmap gxbb_gen_clk_sel = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_GEN_CLK_CNTL,
.mask = 0xf,
.shift = 12,
.table = mux_table_gen_clk,
},
.hw.init = &(struct clk_init_data){
.name = "gen_clk_sel",
.ops = &clk_regmap_mux_ops,
/*
* bits 15:12 selects from 14 possible parents:
* xtal, [rtc_oscin_i], [sys_cpu_div16], [ddr_dpll_pt],
* vid_pll, vid2_pll (hevc), mpll0, mpll1, mpll2, fdiv4,
* fdiv3, fdiv5, [cts_msr_clk], fdiv7, gp0_pll
*/
.parent_names = gen_clk_parent_names,
.num_parents = ARRAY_SIZE(gen_clk_parent_names),
},
};
static struct clk_regmap gxbb_gen_clk_div = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_GEN_CLK_CNTL,
.shift = 0,
.width = 11,
},
.hw.init = &(struct clk_init_data){
.name = "gen_clk_div",
.ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "gen_clk_sel" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap gxbb_gen_clk = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_GEN_CLK_CNTL,
.bit_idx = 7,
},
.hw.init = &(struct clk_init_data){
.name = "gen_clk",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "gen_clk_div" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
/* Everything Else (EE) domain gates */
static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0);
static MESON_GATE(gxbb_dos, HHI_GCLK_MPEG0, 1);
@ -1876,6 +1930,9 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = {
[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,
[CLKID_GEN_CLK_SEL] = &gxbb_gen_clk_sel.hw,
[CLKID_GEN_CLK_DIV] = &gxbb_gen_clk_div.hw,
[CLKID_GEN_CLK] = &gxbb_gen_clk.hw,
[NR_CLKS] = NULL,
},
.num = NR_CLKS,
@ -2038,6 +2095,9 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = {
[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,
[CLKID_GEN_CLK_SEL] = &gxbb_gen_clk_sel.hw,
[CLKID_GEN_CLK_DIV] = &gxbb_gen_clk_div.hw,
[CLKID_GEN_CLK] = &gxbb_gen_clk.hw,
[NR_CLKS] = NULL,
},
.num = NR_CLKS,
@ -2202,6 +2262,9 @@ static struct clk_regmap *const gx_clk_regmaps[] = {
&gxbb_vdec_hevc_sel,
&gxbb_vdec_hevc_div,
&gxbb_vdec_hevc,
&gxbb_gen_clk_sel,
&gxbb_gen_clk_div,
&gxbb_gen_clk,
};
struct clkc_data {
@ -2228,17 +2291,9 @@ static const struct of_device_id clkc_match_table[] = {
{},
};
static const struct regmap_config clkc_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
};
static int gxbb_clkc_probe(struct platform_device *pdev)
{
const struct clkc_data *clkc_data;
struct resource *res;
void __iomem *clk_base;
struct regmap *map;
int ret, i;
struct device *dev = &pdev->dev;
@ -2250,31 +2305,8 @@ static int gxbb_clkc_probe(struct platform_device *pdev)
/* Get the hhi system controller node if available */
map = syscon_node_to_regmap(of_get_parent(dev->of_node));
if (IS_ERR(map)) {
dev_err(dev,
"failed to get HHI regmap - Trying obsolete regs\n");
/*
* FIXME: HHI registers should be accessed through
* the appropriate system controller. This is required because
* there is more than just clocks in this register space
*
* This fallback method is only provided temporarily until
* all the platform DTs are properly using the syscon node
*/
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -EINVAL;
clk_base = devm_ioremap(dev, res->start, resource_size(res));
if (!clk_base) {
dev_err(dev, "Unable to map clk base\n");
return -ENXIO;
}
map = devm_regmap_init_mmio(dev, clk_base,
&clkc_regmap_config);
if (IS_ERR(map))
return PTR_ERR(map);
dev_err(dev, "failed to get HHI regmap\n");
return PTR_ERR(map);
}
/* Populate regmap for the common regmap backed clocks */

View File

@ -66,7 +66,6 @@
#define HHI_USB_CLK_CNTL 0x220 /* 0x88 offset in data sheet */
#define HHI_32K_CLK_CNTL 0x224 /* 0x89 offset in data sheet */
#define HHI_GEN_CLK_CNTL 0x228 /* 0x8a offset in data sheet */
#define HHI_GEN_CLK_CNTL 0x228 /* 0x8a offset in data sheet */
#define HHI_PCM_CLK_CNTL 0x258 /* 0x96 offset in data sheet */
#define HHI_NAND_CLK_CNTL 0x25C /* 0x97 offset in data sheet */
@ -158,8 +157,10 @@
#define CLKID_VDEC_1_DIV 152
#define CLKID_VDEC_HEVC_SEL 154
#define CLKID_VDEC_HEVC_DIV 155
#define CLKID_GEN_CLK_SEL 157
#define CLKID_GEN_CLK_DIV 158
#define NR_CLKS 157
#define NR_CLKS 160
/* include the CLKIDs that have been made part of the DT binding */
#include <dt-bindings/clock/gxbb-clkc.h>

View File

@ -0,0 +1,243 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Copyright (c) 2018 BayLibre, SAS.
* Author: Jerome Brunet <jbrunet@baylibre.com>
*
* Sample clock generator divider:
* This HW divider gates with value 0 but is otherwise a zero based divider:
*
* val >= 1
* divider = val + 1
*
* The duty cycle may also be set for the LR clock variant. The duty cycle
* ratio is:
*
* hi = [0 - val]
* duty_cycle = (1 + hi) / (1 + val)
*/
#include "clkc-audio.h"
static inline struct meson_sclk_div_data *
meson_sclk_div_data(struct clk_regmap *clk)
{
return (struct meson_sclk_div_data *)clk->data;
}
static int sclk_div_maxval(struct meson_sclk_div_data *sclk)
{
return (1 << sclk->div.width) - 1;
}
static int sclk_div_maxdiv(struct meson_sclk_div_data *sclk)
{
return sclk_div_maxval(sclk) + 1;
}
static int sclk_div_getdiv(struct clk_hw *hw, unsigned long rate,
unsigned long prate, int maxdiv)
{
int div = DIV_ROUND_CLOSEST_ULL((u64)prate, rate);
return clamp(div, 2, maxdiv);
}
static int sclk_div_bestdiv(struct clk_hw *hw, unsigned long rate,
unsigned long *prate,
struct meson_sclk_div_data *sclk)
{
struct clk_hw *parent = clk_hw_get_parent(hw);
int bestdiv = 0, i;
unsigned long maxdiv, now, parent_now;
unsigned long best = 0, best_parent = 0;
if (!rate)
rate = 1;
maxdiv = sclk_div_maxdiv(sclk);
if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT))
return sclk_div_getdiv(hw, rate, *prate, maxdiv);
/*
* The maximum divider we can use without overflowing
* unsigned long in rate * i below
*/
maxdiv = min(ULONG_MAX / rate, maxdiv);
for (i = 2; i <= maxdiv; i++) {
/*
* It's the most ideal case if the requested rate can be
* divided from parent clock without needing to change
* parent rate, so return the divider immediately.
*/
if (rate * i == *prate)
return i;
parent_now = clk_hw_round_rate(parent, rate * i);
now = DIV_ROUND_UP_ULL((u64)parent_now, i);
if (abs(rate - now) < abs(rate - best)) {
bestdiv = i;
best = now;
best_parent = parent_now;
}
}
if (!bestdiv)
bestdiv = sclk_div_maxdiv(sclk);
else
*prate = best_parent;
return bestdiv;
}
static long sclk_div_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
int div;
div = sclk_div_bestdiv(hw, rate, prate, sclk);
return DIV_ROUND_UP_ULL((u64)*prate, div);
}
static void sclk_apply_ratio(struct clk_regmap *clk,
struct meson_sclk_div_data *sclk)
{
unsigned int hi = DIV_ROUND_CLOSEST(sclk->cached_div *
sclk->cached_duty.num,
sclk->cached_duty.den);
if (hi)
hi -= 1;
meson_parm_write(clk->map, &sclk->hi, hi);
}
static int sclk_div_set_duty_cycle(struct clk_hw *hw,
struct clk_duty *duty)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
if (MESON_PARM_APPLICABLE(&sclk->hi)) {
memcpy(&sclk->cached_duty, duty, sizeof(*duty));
sclk_apply_ratio(clk, sclk);
}
return 0;
}
static int sclk_div_get_duty_cycle(struct clk_hw *hw,
struct clk_duty *duty)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
int hi;
if (!MESON_PARM_APPLICABLE(&sclk->hi)) {
duty->num = 1;
duty->den = 2;
return 0;
}
hi = meson_parm_read(clk->map, &sclk->hi);
duty->num = hi + 1;
duty->den = sclk->cached_div;
return 0;
}
static void sclk_apply_divider(struct clk_regmap *clk,
struct meson_sclk_div_data *sclk)
{
if (MESON_PARM_APPLICABLE(&sclk->hi))
sclk_apply_ratio(clk, sclk);
meson_parm_write(clk->map, &sclk->div, sclk->cached_div - 1);
}
static int sclk_div_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long prate)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
unsigned long maxdiv = sclk_div_maxdiv(sclk);
sclk->cached_div = sclk_div_getdiv(hw, rate, prate, maxdiv);
if (clk_hw_is_enabled(hw))
sclk_apply_divider(clk, sclk);
return 0;
}
static unsigned long sclk_div_recalc_rate(struct clk_hw *hw,
unsigned long prate)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
return DIV_ROUND_UP_ULL((u64)prate, sclk->cached_div);
}
static int sclk_div_enable(struct clk_hw *hw)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
sclk_apply_divider(clk, sclk);
return 0;
}
static void sclk_div_disable(struct clk_hw *hw)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
meson_parm_write(clk->map, &sclk->div, 0);
}
static int sclk_div_is_enabled(struct clk_hw *hw)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
if (meson_parm_read(clk->map, &sclk->div))
return 1;
return 0;
}
static void sclk_div_init(struct clk_hw *hw)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
unsigned int val;
val = meson_parm_read(clk->map, &sclk->div);
/* if the divider is initially disabled, assume max */
if (!val)
sclk->cached_div = sclk_div_maxdiv(sclk);
else
sclk->cached_div = val + 1;
sclk_div_get_duty_cycle(hw, &sclk->cached_duty);
}
const struct clk_ops meson_sclk_div_ops = {
.recalc_rate = sclk_div_recalc_rate,
.round_rate = sclk_div_round_rate,
.set_rate = sclk_div_set_rate,
.enable = sclk_div_enable,
.disable = sclk_div_disable,
.is_enabled = sclk_div_is_enabled,
.get_duty_cycle = sclk_div_get_duty_cycle,
.set_duty_cycle = sclk_div_set_duty_cycle,
.init = sclk_div_init,
};
EXPORT_SYMBOL_GPL(meson_sclk_div_ops);

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Marvell Armada 37xx SoC Peripheral clocks
*
@ -5,10 +6,6 @@
*
* Gregory CLEMENT <gregory.clement@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2 or later. This program is licensed "as is"
* without any warranty of any kind, whether express or implied.
*
* Most of the peripheral clocks can be modelled like this:
* _____ _______ _______
* TBG-A-P --| | | | | | ______
@ -419,7 +416,6 @@ static unsigned int armada_3700_pm_dvfs_get_cpu_parent(struct regmap *base)
static u8 clk_pm_cpu_get_parent(struct clk_hw *hw)
{
struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw);
int num_parents = clk_hw_get_num_parents(hw);
u32 val;
if (armada_3700_pm_dvfs_is_enabled(pm_cpu->nb_pm_base)) {
@ -429,9 +425,6 @@ static u8 clk_pm_cpu_get_parent(struct clk_hw *hw)
val &= pm_cpu->mask_mux;
}
if (val >= num_parents)
return -EINVAL;
return val;
}

View File

@ -292,8 +292,10 @@ static void __init pxa25x_register_plls(void)
{
clk_register_fixed_rate(NULL, "osc_3_6864mhz", NULL,
CLK_GET_RATE_NOCACHE, 3686400);
clk_register_fixed_rate(NULL, "osc_32_768khz", NULL,
CLK_GET_RATE_NOCACHE, 32768);
clkdev_pxa_register(CLK_OSC32k768, "osc_32_768khz", NULL,
clk_register_fixed_rate(NULL, "osc_32_768khz", NULL,
CLK_GET_RATE_NOCACHE,
32768));
clk_register_fixed_rate(NULL, "clk_dummy", NULL, 0, 0);
clk_register_fixed_factor(NULL, "ppll_95_85mhz", "osc_3_6864mhz",
0, 26, 1);

View File

@ -314,9 +314,10 @@ static void __init pxa27x_register_plls(void)
clk_register_fixed_rate(NULL, "osc_13mhz", NULL,
CLK_GET_RATE_NOCACHE,
13 * MHz);
clk_register_fixed_rate(NULL, "osc_32_768khz", NULL,
CLK_GET_RATE_NOCACHE,
32768 * KHz);
clkdev_pxa_register(CLK_OSC32k768, "osc_32_768khz", NULL,
clk_register_fixed_rate(NULL, "osc_32_768khz", NULL,
CLK_GET_RATE_NOCACHE,
32768 * KHz));
clk_register_fixed_rate(NULL, "clk_dummy", NULL, 0, 0);
clk_register_fixed_factor(NULL, "ppll_312mhz", "osc_13mhz", 0, 24, 1);
}

View File

@ -286,9 +286,10 @@ static void __init pxa3xx_register_plls(void)
clk_register_fixed_rate(NULL, "osc_13mhz", NULL,
CLK_GET_RATE_NOCACHE,
13 * MHz);
clk_register_fixed_rate(NULL, "osc_32_768khz", NULL,
CLK_GET_RATE_NOCACHE,
32768);
clkdev_pxa_register(CLK_OSC32k768, "osc_32_768khz", NULL,
clk_register_fixed_rate(NULL, "osc_32_768khz", NULL,
CLK_GET_RATE_NOCACHE,
32768));
clk_register_fixed_rate(NULL, "ring_osc_120mhz", NULL,
CLK_GET_RATE_NOCACHE,
120 * MHz);

View File

@ -59,6 +59,15 @@ config QCOM_CLK_SMD_RPM
Say Y if you want to support the clocks exposed by the RPM on
platforms such as apq8016, apq8084, msm8974 etc.
config QCOM_CLK_RPMH
tristate "RPMh Clock Driver"
depends on COMMON_CLK_QCOM && QCOM_RPMH
help
RPMh manages shared resources on some Qualcomm Technologies, Inc.
SoCs. It accepts requests from other hardware subsystems via RSC.
Say Y if you want to support the clocks exposed by RPMh on
platforms such as SDM845.
config APQ_GCC_8084
tristate "APQ8084 Global Clock Controller"
select QCOM_GDSC
@ -245,6 +254,16 @@ config SDM_VIDEOCC_845
Say Y if you want to support video devices and functionality such as
video encode and decode.
config SDM_DISPCC_845
tristate "SDM845 Display Clock Controller"
select SDM_GCC_845
depends on COMMON_CLK_QCOM
help
Support for the display clock controller on Qualcomm Technologies, Inc
SDM845 devices.
Say Y if you want to support display devices and functionality such as
splash screen.
config SPMI_PMIC_CLKDIV
tristate "SPMI PMIC clkdiv Support"
depends on (COMMON_CLK_QCOM && SPMI) || COMPILE_TEST

View File

@ -37,7 +37,9 @@ obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o
obj-$(CONFIG_QCOM_A53PLL) += a53-pll.o
obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o
obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
obj-$(CONFIG_QCOM_CLK_RPMH) += clk-rpmh.o
obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o
obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o
obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o

View File

@ -1,14 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>

View File

@ -1,15 +1,5 @@
/*
* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved. */
#ifndef __QCOM_CLK_ALPHA_PLL_H__
#define __QCOM_CLK_ALPHA_PLL_H__

View File

@ -1,14 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>

View File

@ -1,15 +1,5 @@
/*
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2013, The Linux Foundation. All rights reserved. */
#ifndef __QCOM_CLK_BRANCH_H__
#define __QCOM_CLK_BRANCH_H__

View File

@ -7,6 +7,8 @@
#include <linux/clk-provider.h>
#include "clk-regmap.h"
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
struct freq_tbl {
unsigned long freq;
u8 src;

View File

@ -1,14 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/device.h>

View File

@ -1,15 +1,5 @@
/*
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2014, The Linux Foundation. All rights reserved. */
#ifndef __QCOM_CLK_REGMAP_H__
#define __QCOM_CLK_REGMAP_H__

329
drivers/clk/qcom/clk-rpmh.c Normal file
View File

@ -0,0 +1,329 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*/
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <soc/qcom/cmd-db.h>
#include <soc/qcom/rpmh.h>
#include <dt-bindings/clock/qcom,rpmh.h>
#define CLK_RPMH_ARC_EN_OFFSET 0
#define CLK_RPMH_VRM_EN_OFFSET 4
/**
* struct clk_rpmh - individual rpmh clock data structure
* @hw: handle between common and hardware-specific interfaces
* @res_name: resource name for the rpmh clock
* @div: clock divider to compute the clock rate
* @res_addr: base address of the rpmh resource within the RPMh
* @res_on_val: rpmh clock enable value
* @state: rpmh clock requested state
* @aggr_state: rpmh clock aggregated state
* @last_sent_aggr_state: rpmh clock last aggr state sent to RPMh
* @valid_state_mask: mask to determine the state of the rpmh clock
* @dev: device to which it is attached
* @peer: pointer to the clock rpmh sibling
*/
struct clk_rpmh {
struct clk_hw hw;
const char *res_name;
u8 div;
u32 res_addr;
u32 res_on_val;
u32 state;
u32 aggr_state;
u32 last_sent_aggr_state;
u32 valid_state_mask;
struct device *dev;
struct clk_rpmh *peer;
};
struct clk_rpmh_desc {
struct clk_hw **clks;
size_t num_clks;
};
static DEFINE_MUTEX(rpmh_clk_lock);
#define __DEFINE_CLK_RPMH(_platform, _name, _name_active, _res_name, \
_res_en_offset, _res_on, _div) \
static struct clk_rpmh _platform##_##_name_active; \
static struct clk_rpmh _platform##_##_name = { \
.res_name = _res_name, \
.res_addr = _res_en_offset, \
.res_on_val = _res_on, \
.div = _div, \
.peer = &_platform##_##_name_active, \
.valid_state_mask = (BIT(RPMH_WAKE_ONLY_STATE) | \
BIT(RPMH_ACTIVE_ONLY_STATE) | \
BIT(RPMH_SLEEP_STATE)), \
.hw.init = &(struct clk_init_data){ \
.ops = &clk_rpmh_ops, \
.name = #_name, \
.parent_names = (const char *[]){ "xo_board" }, \
.num_parents = 1, \
}, \
}; \
static struct clk_rpmh _platform##_##_name_active = { \
.res_name = _res_name, \
.res_addr = _res_en_offset, \
.res_on_val = _res_on, \
.div = _div, \
.peer = &_platform##_##_name, \
.valid_state_mask = (BIT(RPMH_WAKE_ONLY_STATE) | \
BIT(RPMH_ACTIVE_ONLY_STATE)), \
.hw.init = &(struct clk_init_data){ \
.ops = &clk_rpmh_ops, \
.name = #_name_active, \
.parent_names = (const char *[]){ "xo_board" }, \
.num_parents = 1, \
}, \
}
#define DEFINE_CLK_RPMH_ARC(_platform, _name, _name_active, _res_name, \
_res_on, _div) \
__DEFINE_CLK_RPMH(_platform, _name, _name_active, _res_name, \
CLK_RPMH_ARC_EN_OFFSET, _res_on, _div)
#define DEFINE_CLK_RPMH_VRM(_platform, _name, _name_active, _res_name, \
_div) \
__DEFINE_CLK_RPMH(_platform, _name, _name_active, _res_name, \
CLK_RPMH_VRM_EN_OFFSET, 1, _div)
static inline struct clk_rpmh *to_clk_rpmh(struct clk_hw *_hw)
{
return container_of(_hw, struct clk_rpmh, hw);
}
static inline bool has_state_changed(struct clk_rpmh *c, u32 state)
{
return (c->last_sent_aggr_state & BIT(state))
!= (c->aggr_state & BIT(state));
}
static int clk_rpmh_send_aggregate_command(struct clk_rpmh *c)
{
struct tcs_cmd cmd = { 0 };
u32 cmd_state, on_val;
enum rpmh_state state = RPMH_SLEEP_STATE;
int ret;
cmd.addr = c->res_addr;
cmd_state = c->aggr_state;
on_val = c->res_on_val;
for (; state <= RPMH_ACTIVE_ONLY_STATE; state++) {
if (has_state_changed(c, state)) {
if (cmd_state & BIT(state))
cmd.data = on_val;
ret = rpmh_write_async(c->dev, state, &cmd, 1);
if (ret) {
dev_err(c->dev, "set %s state of %s failed: (%d)\n",
!state ? "sleep" :
state == RPMH_WAKE_ONLY_STATE ?
"wake" : "active", c->res_name, ret);
return ret;
}
}
}
c->last_sent_aggr_state = c->aggr_state;
c->peer->last_sent_aggr_state = c->last_sent_aggr_state;
return 0;
}
/*
* Update state and aggregate state values based on enable value.
*/
static int clk_rpmh_aggregate_state_send_command(struct clk_rpmh *c,
bool enable)
{
int ret;
/* Nothing required to be done if already off or on */
if (enable == c->state)
return 0;
c->state = enable ? c->valid_state_mask : 0;
c->aggr_state = c->state | c->peer->state;
c->peer->aggr_state = c->aggr_state;
ret = clk_rpmh_send_aggregate_command(c);
if (!ret)
return 0;
if (ret && enable)
c->state = 0;
else if (ret)
c->state = c->valid_state_mask;
WARN(1, "clk: %s failed to %s\n", c->res_name,
enable ? "enable" : "disable");
return ret;
}
static int clk_rpmh_prepare(struct clk_hw *hw)
{
struct clk_rpmh *c = to_clk_rpmh(hw);
int ret = 0;
mutex_lock(&rpmh_clk_lock);
ret = clk_rpmh_aggregate_state_send_command(c, true);
mutex_unlock(&rpmh_clk_lock);
return ret;
};
static void clk_rpmh_unprepare(struct clk_hw *hw)
{
struct clk_rpmh *c = to_clk_rpmh(hw);
mutex_lock(&rpmh_clk_lock);
clk_rpmh_aggregate_state_send_command(c, false);
mutex_unlock(&rpmh_clk_lock);
};
static unsigned long clk_rpmh_recalc_rate(struct clk_hw *hw,
unsigned long prate)
{
struct clk_rpmh *r = to_clk_rpmh(hw);
/*
* RPMh clocks have a fixed rate. Return static rate.
*/
return prate / r->div;
}
static const struct clk_ops clk_rpmh_ops = {
.prepare = clk_rpmh_prepare,
.unprepare = clk_rpmh_unprepare,
.recalc_rate = clk_rpmh_recalc_rate,
};
/* Resource name must match resource id present in cmd-db. */
DEFINE_CLK_RPMH_ARC(sdm845, bi_tcxo, bi_tcxo_ao, "xo.lvl", 0x3, 2);
DEFINE_CLK_RPMH_VRM(sdm845, ln_bb_clk2, ln_bb_clk2_ao, "lnbclka2", 2);
DEFINE_CLK_RPMH_VRM(sdm845, ln_bb_clk3, ln_bb_clk3_ao, "lnbclka3", 2);
DEFINE_CLK_RPMH_VRM(sdm845, rf_clk1, rf_clk1_ao, "rfclka1", 1);
DEFINE_CLK_RPMH_VRM(sdm845, rf_clk2, rf_clk2_ao, "rfclka2", 1);
DEFINE_CLK_RPMH_VRM(sdm845, rf_clk3, rf_clk3_ao, "rfclka3", 1);
static struct clk_hw *sdm845_rpmh_clocks[] = {
[RPMH_CXO_CLK] = &sdm845_bi_tcxo.hw,
[RPMH_CXO_CLK_A] = &sdm845_bi_tcxo_ao.hw,
[RPMH_LN_BB_CLK2] = &sdm845_ln_bb_clk2.hw,
[RPMH_LN_BB_CLK2_A] = &sdm845_ln_bb_clk2_ao.hw,
[RPMH_LN_BB_CLK3] = &sdm845_ln_bb_clk3.hw,
[RPMH_LN_BB_CLK3_A] = &sdm845_ln_bb_clk3_ao.hw,
[RPMH_RF_CLK1] = &sdm845_rf_clk1.hw,
[RPMH_RF_CLK1_A] = &sdm845_rf_clk1_ao.hw,
[RPMH_RF_CLK2] = &sdm845_rf_clk2.hw,
[RPMH_RF_CLK2_A] = &sdm845_rf_clk2_ao.hw,
[RPMH_RF_CLK3] = &sdm845_rf_clk3.hw,
[RPMH_RF_CLK3_A] = &sdm845_rf_clk3_ao.hw,
};
static const struct clk_rpmh_desc clk_rpmh_sdm845 = {
.clks = sdm845_rpmh_clocks,
.num_clks = ARRAY_SIZE(sdm845_rpmh_clocks),
};
static struct clk_hw *of_clk_rpmh_hw_get(struct of_phandle_args *clkspec,
void *data)
{
struct clk_rpmh_desc *rpmh = data;
unsigned int idx = clkspec->args[0];
if (idx >= rpmh->num_clks) {
pr_err("%s: invalid index %u\n", __func__, idx);
return ERR_PTR(-EINVAL);
}
return rpmh->clks[idx];
}
static int clk_rpmh_probe(struct platform_device *pdev)
{
struct clk_hw **hw_clks;
struct clk_rpmh *rpmh_clk;
const struct clk_rpmh_desc *desc;
int ret, i;
desc = of_device_get_match_data(&pdev->dev);
if (!desc)
return -ENODEV;
hw_clks = desc->clks;
for (i = 0; i < desc->num_clks; i++) {
u32 res_addr;
rpmh_clk = to_clk_rpmh(hw_clks[i]);
res_addr = cmd_db_read_addr(rpmh_clk->res_name);
if (!res_addr) {
dev_err(&pdev->dev, "missing RPMh resource address for %s\n",
rpmh_clk->res_name);
return -ENODEV;
}
rpmh_clk->res_addr += res_addr;
rpmh_clk->dev = &pdev->dev;
ret = devm_clk_hw_register(&pdev->dev, hw_clks[i]);
if (ret) {
dev_err(&pdev->dev, "failed to register %s\n",
hw_clks[i]->init->name);
return ret;
}
}
/* typecast to silence compiler warning */
ret = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_rpmh_hw_get,
(void *)desc);
if (ret) {
dev_err(&pdev->dev, "Failed to add clock provider\n");
return ret;
}
dev_dbg(&pdev->dev, "Registered RPMh clocks\n");
return 0;
}
static const struct of_device_id clk_rpmh_match_table[] = {
{ .compatible = "qcom,sdm845-rpmh-clk", .data = &clk_rpmh_sdm845},
{ }
};
MODULE_DEVICE_TABLE(of, clk_rpmh_match_table);
static struct platform_driver clk_rpmh_driver = {
.probe = clk_rpmh_probe,
.driver = {
.name = "clk-rpmh",
.of_match_table = clk_rpmh_match_table,
},
};
static int __init clk_rpmh_init(void)
{
return platform_driver_register(&clk_rpmh_driver);
}
subsys_initcall(clk_rpmh_init);
static void __exit clk_rpmh_exit(void)
{
platform_driver_unregister(&clk_rpmh_driver);
}
module_exit(clk_rpmh_exit);
MODULE_DESCRIPTION("QCOM RPMh Clock Driver");
MODULE_LICENSE("GPL v2");

View File

@ -1,14 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/export.h>

View File

@ -1,15 +1,6 @@
/*
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2014, The Linux Foundation. All rights reserved. */
#ifndef __QCOM_CLK_COMMON_H__
#define __QCOM_CLK_COMMON_H__

View File

@ -0,0 +1,685 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*/
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset-controller.h>
#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
#include "clk-alpha-pll.h"
#include "clk-branch.h"
#include "clk-rcg.h"
#include "clk-regmap-divider.h"
#include "common.h"
#include "gdsc.h"
#include "reset.h"
enum {
P_BI_TCXO,
P_CORE_BI_PLL_TEST_SE,
P_DISP_CC_PLL0_OUT_MAIN,
P_DSI0_PHY_PLL_OUT_BYTECLK,
P_DSI0_PHY_PLL_OUT_DSICLK,
P_DSI1_PHY_PLL_OUT_BYTECLK,
P_DSI1_PHY_PLL_OUT_DSICLK,
P_GPLL0_OUT_MAIN,
P_GPLL0_OUT_MAIN_DIV,
};
static const struct parent_map disp_cc_parent_map_0[] = {
{ P_BI_TCXO, 0 },
{ P_DSI0_PHY_PLL_OUT_BYTECLK, 1 },
{ P_DSI1_PHY_PLL_OUT_BYTECLK, 2 },
{ P_CORE_BI_PLL_TEST_SE, 7 },
};
static const char * const disp_cc_parent_names_0[] = {
"bi_tcxo",
"dsi0_phy_pll_out_byteclk",
"dsi1_phy_pll_out_byteclk",
"core_bi_pll_test_se",
};
static const struct parent_map disp_cc_parent_map_2[] = {
{ P_BI_TCXO, 0 },
{ P_CORE_BI_PLL_TEST_SE, 7 },
};
static const char * const disp_cc_parent_names_2[] = {
"bi_tcxo",
"core_bi_pll_test_se",
};
static const struct parent_map disp_cc_parent_map_3[] = {
{ P_BI_TCXO, 0 },
{ P_DISP_CC_PLL0_OUT_MAIN, 1 },
{ P_GPLL0_OUT_MAIN, 4 },
{ P_GPLL0_OUT_MAIN_DIV, 5 },
{ P_CORE_BI_PLL_TEST_SE, 7 },
};
static const char * const disp_cc_parent_names_3[] = {
"bi_tcxo",
"disp_cc_pll0",
"gcc_disp_gpll0_clk_src",
"gcc_disp_gpll0_div_clk_src",
"core_bi_pll_test_se",
};
static const struct parent_map disp_cc_parent_map_4[] = {
{ P_BI_TCXO, 0 },
{ P_DSI0_PHY_PLL_OUT_DSICLK, 1 },
{ P_DSI1_PHY_PLL_OUT_DSICLK, 2 },
{ P_CORE_BI_PLL_TEST_SE, 7 },
};
static const char * const disp_cc_parent_names_4[] = {
"bi_tcxo",
"dsi0_phy_pll_out_dsiclk",
"dsi1_phy_pll_out_dsiclk",
"core_bi_pll_test_se",
};
static struct clk_alpha_pll disp_cc_pll0 = {
.offset = 0x0,
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "disp_cc_pll0",
.parent_names = (const char *[]){ "bi_tcxo" },
.num_parents = 1,
.ops = &clk_alpha_pll_fabia_ops,
},
},
};
/* Return the HW recalc rate for idle use case */
static struct clk_rcg2 disp_cc_mdss_byte0_clk_src = {
.cmd_rcgr = 0x20d0,
.mnd_width = 0,
.hid_width = 5,
.parent_map = disp_cc_parent_map_0,
.clkr.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_byte0_clk_src",
.parent_names = disp_cc_parent_names_0,
.num_parents = 4,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_byte2_ops,
},
};
/* Return the HW recalc rate for idle use case */
static struct clk_rcg2 disp_cc_mdss_byte1_clk_src = {
.cmd_rcgr = 0x20ec,
.mnd_width = 0,
.hid_width = 5,
.parent_map = disp_cc_parent_map_0,
.clkr.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_byte1_clk_src",
.parent_names = disp_cc_parent_names_0,
.num_parents = 4,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_byte2_ops,
},
};
static const struct freq_tbl ftbl_disp_cc_mdss_esc0_clk_src[] = {
F(19200000, P_BI_TCXO, 1, 0, 0),
{ }
};
static struct clk_rcg2 disp_cc_mdss_esc0_clk_src = {
.cmd_rcgr = 0x2108,
.mnd_width = 0,
.hid_width = 5,
.parent_map = disp_cc_parent_map_0,
.freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_esc0_clk_src",
.parent_names = disp_cc_parent_names_0,
.num_parents = 4,
.ops = &clk_rcg2_ops,
},
};
static struct clk_rcg2 disp_cc_mdss_esc1_clk_src = {
.cmd_rcgr = 0x2120,
.mnd_width = 0,
.hid_width = 5,
.parent_map = disp_cc_parent_map_0,
.freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_esc1_clk_src",
.parent_names = disp_cc_parent_names_0,
.num_parents = 4,
.ops = &clk_rcg2_ops,
},
};
static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src[] = {
F(19200000, P_BI_TCXO, 1, 0, 0),
F(85714286, P_GPLL0_OUT_MAIN, 7, 0, 0),
F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0),
F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
F(344000000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0),
F(430000000, P_DISP_CC_PLL0_OUT_MAIN, 2, 0, 0),
{ }
};
static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = {
.cmd_rcgr = 0x2088,
.mnd_width = 0,
.hid_width = 5,
.parent_map = disp_cc_parent_map_3,
.freq_tbl = ftbl_disp_cc_mdss_mdp_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_mdp_clk_src",
.parent_names = disp_cc_parent_names_3,
.num_parents = 5,
.ops = &clk_rcg2_shared_ops,
},
};
/* Return the HW recalc rate for idle use case */
static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = {
.cmd_rcgr = 0x2058,
.mnd_width = 8,
.hid_width = 5,
.parent_map = disp_cc_parent_map_4,
.clkr.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_pclk0_clk_src",
.parent_names = disp_cc_parent_names_4,
.num_parents = 4,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_pixel_ops,
},
};
/* Return the HW recalc rate for idle use case */
static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = {
.cmd_rcgr = 0x2070,
.mnd_width = 8,
.hid_width = 5,
.parent_map = disp_cc_parent_map_4,
.clkr.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_pclk1_clk_src",
.parent_names = disp_cc_parent_names_4,
.num_parents = 4,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_pixel_ops,
},
};
static const struct freq_tbl ftbl_disp_cc_mdss_rot_clk_src[] = {
F(19200000, P_BI_TCXO, 1, 0, 0),
F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0),
F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
F(344000000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0),
F(430000000, P_DISP_CC_PLL0_OUT_MAIN, 2, 0, 0),
{ }
};
static struct clk_rcg2 disp_cc_mdss_rot_clk_src = {
.cmd_rcgr = 0x20a0,
.mnd_width = 0,
.hid_width = 5,
.parent_map = disp_cc_parent_map_3,
.freq_tbl = ftbl_disp_cc_mdss_rot_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_rot_clk_src",
.parent_names = disp_cc_parent_names_3,
.num_parents = 5,
.ops = &clk_rcg2_shared_ops,
},
};
static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = {
.cmd_rcgr = 0x20b8,
.mnd_width = 0,
.hid_width = 5,
.parent_map = disp_cc_parent_map_2,
.freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_vsync_clk_src",
.parent_names = disp_cc_parent_names_2,
.num_parents = 2,
.ops = &clk_rcg2_ops,
},
};
static struct clk_branch disp_cc_mdss_ahb_clk = {
.halt_reg = 0x4004,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x4004,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_ahb_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch disp_cc_mdss_axi_clk = {
.halt_reg = 0x4008,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x4008,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_axi_clk",
.ops = &clk_branch2_ops,
},
},
};
/* Return the HW recalc rate for idle use case */
static struct clk_branch disp_cc_mdss_byte0_clk = {
.halt_reg = 0x2028,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x2028,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_byte0_clk",
.parent_names = (const char *[]){
"disp_cc_mdss_byte0_clk_src",
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
/* Return the HW recalc rate for idle use case */
static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = {
.reg = 0x20e8,
.shift = 0,
.width = 2,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_byte0_div_clk_src",
.parent_names = (const char *[]){
"disp_cc_mdss_byte0_clk_src",
},
.num_parents = 1,
.ops = &clk_regmap_div_ops,
},
},
};
/* Return the HW recalc rate for idle use case */
static struct clk_branch disp_cc_mdss_byte0_intf_clk = {
.halt_reg = 0x202c,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x202c,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_byte0_intf_clk",
.parent_names = (const char *[]){
"disp_cc_mdss_byte0_div_clk_src",
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
/* Return the HW recalc rate for idle use case */
static struct clk_branch disp_cc_mdss_byte1_clk = {
.halt_reg = 0x2030,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x2030,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_byte1_clk",
.parent_names = (const char *[]){
"disp_cc_mdss_byte1_clk_src",
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
/* Return the HW recalc rate for idle use case */
static struct clk_regmap_div disp_cc_mdss_byte1_div_clk_src = {
.reg = 0x2104,
.shift = 0,
.width = 2,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_byte1_div_clk_src",
.parent_names = (const char *[]){
"disp_cc_mdss_byte1_clk_src",
},
.num_parents = 1,
.ops = &clk_regmap_div_ops,
},
},
};
/* Return the HW recalc rate for idle use case */
static struct clk_branch disp_cc_mdss_byte1_intf_clk = {
.halt_reg = 0x2034,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x2034,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_byte1_intf_clk",
.parent_names = (const char *[]){
"disp_cc_mdss_byte1_div_clk_src",
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch disp_cc_mdss_esc0_clk = {
.halt_reg = 0x2038,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x2038,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_esc0_clk",
.parent_names = (const char *[]){
"disp_cc_mdss_esc0_clk_src",
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch disp_cc_mdss_esc1_clk = {
.halt_reg = 0x203c,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x203c,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_esc1_clk",
.parent_names = (const char *[]){
"disp_cc_mdss_esc1_clk_src",
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch disp_cc_mdss_mdp_clk = {
.halt_reg = 0x200c,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x200c,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_mdp_clk",
.parent_names = (const char *[]){
"disp_cc_mdss_mdp_clk_src",
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch disp_cc_mdss_mdp_lut_clk = {
.halt_reg = 0x201c,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x201c,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_mdp_lut_clk",
.parent_names = (const char *[]){
"disp_cc_mdss_mdp_clk_src",
},
.num_parents = 1,
.ops = &clk_branch2_ops,
},
},
};
/* Return the HW recalc rate for idle use case */
static struct clk_branch disp_cc_mdss_pclk0_clk = {
.halt_reg = 0x2004,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x2004,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_pclk0_clk",
.parent_names = (const char *[]){
"disp_cc_mdss_pclk0_clk_src",
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
/* Return the HW recalc rate for idle use case */
static struct clk_branch disp_cc_mdss_pclk1_clk = {
.halt_reg = 0x2008,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x2008,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_pclk1_clk",
.parent_names = (const char *[]){
"disp_cc_mdss_pclk1_clk_src",
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch disp_cc_mdss_rot_clk = {
.halt_reg = 0x2014,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x2014,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_rot_clk",
.parent_names = (const char *[]){
"disp_cc_mdss_rot_clk_src",
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch disp_cc_mdss_rscc_ahb_clk = {
.halt_reg = 0x5004,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x5004,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_rscc_ahb_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch disp_cc_mdss_rscc_vsync_clk = {
.halt_reg = 0x5008,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x5008,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_rscc_vsync_clk",
.parent_names = (const char *[]){
"disp_cc_mdss_vsync_clk_src",
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch disp_cc_mdss_vsync_clk = {
.halt_reg = 0x2024,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x2024,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_vsync_clk",
.parent_names = (const char *[]){
"disp_cc_mdss_vsync_clk_src",
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct gdsc mdss_gdsc = {
.gdscr = 0x3000,
.pd = {
.name = "mdss_gdsc",
},
.pwrsts = PWRSTS_OFF_ON,
.flags = HW_CTRL | POLL_CFG_GDSCR,
};
static struct clk_regmap *disp_cc_sdm845_clocks[] = {
[DISP_CC_MDSS_AHB_CLK] = &disp_cc_mdss_ahb_clk.clkr,
[DISP_CC_MDSS_AXI_CLK] = &disp_cc_mdss_axi_clk.clkr,
[DISP_CC_MDSS_BYTE0_CLK] = &disp_cc_mdss_byte0_clk.clkr,
[DISP_CC_MDSS_BYTE0_CLK_SRC] = &disp_cc_mdss_byte0_clk_src.clkr,
[DISP_CC_MDSS_BYTE0_INTF_CLK] = &disp_cc_mdss_byte0_intf_clk.clkr,
[DISP_CC_MDSS_BYTE0_DIV_CLK_SRC] =
&disp_cc_mdss_byte0_div_clk_src.clkr,
[DISP_CC_MDSS_BYTE1_CLK] = &disp_cc_mdss_byte1_clk.clkr,
[DISP_CC_MDSS_BYTE1_CLK_SRC] = &disp_cc_mdss_byte1_clk_src.clkr,
[DISP_CC_MDSS_BYTE1_INTF_CLK] = &disp_cc_mdss_byte1_intf_clk.clkr,
[DISP_CC_MDSS_BYTE1_DIV_CLK_SRC] =
&disp_cc_mdss_byte1_div_clk_src.clkr,
[DISP_CC_MDSS_ESC0_CLK] = &disp_cc_mdss_esc0_clk.clkr,
[DISP_CC_MDSS_ESC0_CLK_SRC] = &disp_cc_mdss_esc0_clk_src.clkr,
[DISP_CC_MDSS_ESC1_CLK] = &disp_cc_mdss_esc1_clk.clkr,
[DISP_CC_MDSS_ESC1_CLK_SRC] = &disp_cc_mdss_esc1_clk_src.clkr,
[DISP_CC_MDSS_MDP_CLK] = &disp_cc_mdss_mdp_clk.clkr,
[DISP_CC_MDSS_MDP_CLK_SRC] = &disp_cc_mdss_mdp_clk_src.clkr,
[DISP_CC_MDSS_MDP_LUT_CLK] = &disp_cc_mdss_mdp_lut_clk.clkr,
[DISP_CC_MDSS_PCLK0_CLK] = &disp_cc_mdss_pclk0_clk.clkr,
[DISP_CC_MDSS_PCLK0_CLK_SRC] = &disp_cc_mdss_pclk0_clk_src.clkr,
[DISP_CC_MDSS_PCLK1_CLK] = &disp_cc_mdss_pclk1_clk.clkr,
[DISP_CC_MDSS_PCLK1_CLK_SRC] = &disp_cc_mdss_pclk1_clk_src.clkr,
[DISP_CC_MDSS_ROT_CLK] = &disp_cc_mdss_rot_clk.clkr,
[DISP_CC_MDSS_ROT_CLK_SRC] = &disp_cc_mdss_rot_clk_src.clkr,
[DISP_CC_MDSS_RSCC_AHB_CLK] = &disp_cc_mdss_rscc_ahb_clk.clkr,
[DISP_CC_MDSS_RSCC_VSYNC_CLK] = &disp_cc_mdss_rscc_vsync_clk.clkr,
[DISP_CC_MDSS_VSYNC_CLK] = &disp_cc_mdss_vsync_clk.clkr,
[DISP_CC_MDSS_VSYNC_CLK_SRC] = &disp_cc_mdss_vsync_clk_src.clkr,
[DISP_CC_PLL0] = &disp_cc_pll0.clkr,
};
static const struct qcom_reset_map disp_cc_sdm845_resets[] = {
[DISP_CC_MDSS_RSCC_BCR] = { 0x5000 },
};
static struct gdsc *disp_cc_sdm845_gdscs[] = {
[MDSS_GDSC] = &mdss_gdsc,
};
static const struct regmap_config disp_cc_sdm845_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = 0x10000,
.fast_io = true,
};
static const struct qcom_cc_desc disp_cc_sdm845_desc = {
.config = &disp_cc_sdm845_regmap_config,
.clks = disp_cc_sdm845_clocks,
.num_clks = ARRAY_SIZE(disp_cc_sdm845_clocks),
.resets = disp_cc_sdm845_resets,
.num_resets = ARRAY_SIZE(disp_cc_sdm845_resets),
.gdscs = disp_cc_sdm845_gdscs,
.num_gdscs = ARRAY_SIZE(disp_cc_sdm845_gdscs),
};
static const struct of_device_id disp_cc_sdm845_match_table[] = {
{ .compatible = "qcom,sdm845-dispcc" },
{ }
};
MODULE_DEVICE_TABLE(of, disp_cc_sdm845_match_table);
static int disp_cc_sdm845_probe(struct platform_device *pdev)
{
struct regmap *regmap;
struct alpha_pll_config disp_cc_pll0_config = {};
regmap = qcom_cc_map(pdev, &disp_cc_sdm845_desc);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
disp_cc_pll0_config.l = 0x2c;
disp_cc_pll0_config.alpha = 0xcaaa;
clk_fabia_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config);
/* Enable hardware clock gating for DSI and MDP clocks */
regmap_update_bits(regmap, 0x8000, 0x7f0, 0x7f0);
return qcom_cc_really_probe(pdev, &disp_cc_sdm845_desc, regmap);
}
static struct platform_driver disp_cc_sdm845_driver = {
.probe = disp_cc_sdm845_probe,
.driver = {
.name = "disp_cc-sdm845",
.of_match_table = disp_cc_sdm845_match_table,
},
};
static int __init disp_cc_sdm845_init(void)
{
return platform_driver_register(&disp_cc_sdm845_driver);
}
subsys_initcall(disp_cc_sdm845_init);
static void __exit disp_cc_sdm845_exit(void)
{
platform_driver_unregister(&disp_cc_sdm845_driver);
}
module_exit(disp_cc_sdm845_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("QTI DISPCC SDM845 Driver");

View File

@ -106,8 +106,6 @@ static const char * const gcc_xo_pcie_sleep[] = {
"sleep_clk_src",
};
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
static struct clk_pll gpll0 = {
.l_reg = 0x0004,
.m_reg = 0x0008,

View File

@ -179,8 +179,6 @@ static const char * const gcc_xo_ddr_500_200[] = {
"ddrpllapss",
};
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
static const struct freq_tbl ftbl_gcc_audio_pwm_clk[] = {
F(48000000, P_XO, 1, 0, 0),
F(200000000, P_FEPLL200, 1, 0, 0),

View File

@ -1220,7 +1220,6 @@ static struct clk_rcg sdc1_src = {
.parent_names = gcc_pxo_pll8,
.num_parents = 2,
.ops = &clk_rcg_ops,
.flags = CLK_SET_RATE_GATE,
},
}
};
@ -1269,7 +1268,6 @@ static struct clk_rcg sdc3_src = {
.parent_names = gcc_pxo_pll8,
.num_parents = 2,
.ops = &clk_rcg_ops,
.flags = CLK_SET_RATE_GATE,
},
}
};
@ -1353,7 +1351,6 @@ static struct clk_rcg tsif_ref_src = {
.parent_names = gcc_pxo_pll8,
.num_parents = 2,
.ops = &clk_rcg_ops,
.flags = CLK_SET_RATE_GATE,
},
}
};

View File

@ -32,8 +32,6 @@
#include "clk-regmap-mux.h"
#include "reset.h"
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
enum {
P_XO,
P_GPLL0,

View File

@ -947,7 +947,6 @@ static struct clk_rcg sdc1_src = {
.parent_names = gcc_cxo_pll8,
.num_parents = 2,
.ops = &clk_rcg_ops,
.flags = CLK_SET_RATE_GATE,
},
}
};
@ -996,7 +995,6 @@ static struct clk_rcg sdc2_src = {
.parent_names = gcc_cxo_pll8,
.num_parents = 2,
.ops = &clk_rcg_ops,
.flags = CLK_SET_RATE_GATE,
},
}
};

View File

@ -1558,7 +1558,6 @@ static struct clk_rcg sdc1_src = {
.parent_names = gcc_pxo_pll8,
.num_parents = 2,
.ops = &clk_rcg_ops,
.flags = CLK_SET_RATE_GATE,
},
}
};
@ -1607,7 +1606,6 @@ static struct clk_rcg sdc2_src = {
.parent_names = gcc_pxo_pll8,
.num_parents = 2,
.ops = &clk_rcg_ops,
.flags = CLK_SET_RATE_GATE,
},
}
};
@ -1656,7 +1654,6 @@ static struct clk_rcg sdc3_src = {
.parent_names = gcc_pxo_pll8,
.num_parents = 2,
.ops = &clk_rcg_ops,
.flags = CLK_SET_RATE_GATE,
},
}
};
@ -1705,7 +1702,6 @@ static struct clk_rcg sdc4_src = {
.parent_names = gcc_pxo_pll8,
.num_parents = 2,
.ops = &clk_rcg_ops,
.flags = CLK_SET_RATE_GATE,
},
}
};
@ -1754,7 +1750,6 @@ static struct clk_rcg sdc5_src = {
.parent_names = gcc_pxo_pll8,
.num_parents = 2,
.ops = &clk_rcg_ops,
.flags = CLK_SET_RATE_GATE,
},
}
};

View File

@ -264,8 +264,6 @@ static const char * const gcc_xo_gpll1_emclk_sleep[] = {
"sleep_clk",
};
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
static struct clk_pll gpll0 = {
.l_reg = 0x21004,
.m_reg = 0x21008,

View File

@ -1628,7 +1628,6 @@ static struct clk_rcg sdc1_src = {
.parent_names = gcc_pxo_pll8,
.num_parents = 2,
.ops = &clk_rcg_ops,
.flags = CLK_SET_RATE_GATE,
},
}
};
@ -1677,7 +1676,6 @@ static struct clk_rcg sdc2_src = {
.parent_names = gcc_pxo_pll8,
.num_parents = 2,
.ops = &clk_rcg_ops,
.flags = CLK_SET_RATE_GATE,
},
}
};
@ -1726,7 +1724,6 @@ static struct clk_rcg sdc3_src = {
.parent_names = gcc_pxo_pll8,
.num_parents = 2,
.ops = &clk_rcg_ops,
.flags = CLK_SET_RATE_GATE,
},
}
};
@ -1775,7 +1772,6 @@ static struct clk_rcg sdc4_src = {
.parent_names = gcc_pxo_pll8,
.num_parents = 2,
.ops = &clk_rcg_ops,
.flags = CLK_SET_RATE_GATE,
},
}
};
@ -1824,7 +1820,6 @@ static struct clk_rcg sdc5_src = {
.parent_names = gcc_pxo_pll8,
.num_parents = 2,
.ops = &clk_rcg_ops,
.flags = CLK_SET_RATE_GATE,
},
}
};

View File

@ -62,8 +62,6 @@ static const char * const gcc_xo_gpll0_gpll4[] = {
"gpll4_vote",
};
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
static struct clk_pll gpll0 = {
.l_reg = 0x0004,
.m_reg = 0x0008,

View File

@ -57,8 +57,6 @@ static const char * const gcc_xo_gpll0_gpll4[] = {
"gpll4",
};
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
static struct clk_fixed_factor xo = {
.mult = 1,
.div = 1,

View File

@ -32,8 +32,6 @@
#include "reset.h"
#include "gdsc.h"
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
enum {
P_XO,
P_GPLL0,

View File

@ -25,8 +25,6 @@
#include "reset.h"
#include "gdsc.h"
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
enum {
P_AUD_REF_CLK,
P_CORE_BI_PLL_TEST_SE,

View File

@ -25,8 +25,6 @@
#include "gdsc.h"
#include "reset.h"
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
enum {
P_BI_TCXO,
P_AUD_REF_CLK,
@ -1103,6 +1101,7 @@ static struct clk_branch gcc_camera_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camera_ahb_clk",
.flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
@ -1129,6 +1128,7 @@ static struct clk_branch gcc_camera_xo_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camera_xo_clk",
.flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
@ -1270,6 +1270,7 @@ static struct clk_branch gcc_disp_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_disp_ahb_clk",
.flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
@ -1328,6 +1329,7 @@ static struct clk_branch gcc_disp_xo_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_disp_xo_clk",
.flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
@ -1397,6 +1399,7 @@ static struct clk_branch gcc_gpu_cfg_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_gpu_cfg_ahb_clk",
.flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
@ -2985,6 +2988,7 @@ static struct clk_branch gcc_video_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_video_ahb_clk",
.flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
@ -3011,6 +3015,7 @@ static struct clk_branch gcc_video_xo_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_video_xo_clk",
.flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
@ -3049,6 +3054,36 @@ static struct clk_branch gcc_vs_ctrl_clk = {
},
};
static struct clk_branch gcc_cpuss_dvm_bus_clk = {
.halt_reg = 0x48190,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x48190,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_cpuss_dvm_bus_clk",
.flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gcc_cpuss_gnoc_clk = {
.halt_reg = 0x48004,
.halt_check = BRANCH_HALT_VOTED,
.hwcg_reg = 0x48004,
.hwcg_bit = 1,
.clkr = {
.enable_reg = 0x52004,
.enable_mask = BIT(22),
.hw.init = &(struct clk_init_data){
.name = "gcc_cpuss_gnoc_clk",
.flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
};
static struct gdsc pcie_0_gdsc = {
.gdscr = 0x6b004,
.pd = {
@ -3344,6 +3379,8 @@ static struct clk_regmap *gcc_sdm845_clocks[] = {
[GPLL0] = &gpll0.clkr,
[GPLL0_OUT_EVEN] = &gpll0_out_even.clkr,
[GPLL4] = &gpll4.clkr,
[GCC_CPUSS_DVM_BUS_CLK] = &gcc_cpuss_dvm_bus_clk.clkr,
[GCC_CPUSS_GNOC_CLK] = &gcc_cpuss_gnoc_clk.clkr,
};
static const struct qcom_reset_map gcc_sdm845_resets[] = {
@ -3433,10 +3470,6 @@ static int gcc_sdm845_probe(struct platform_device *pdev)
regmap_update_bits(regmap, 0x09ffc, 0x3, 0x3);
regmap_update_bits(regmap, 0x71028, 0x3, 0x3);
/* Enable CPUSS clocks */
regmap_update_bits(regmap, 0x48190, BIT(0), 0x1);
regmap_update_bits(regmap, 0x52004, BIT(22), 0x1);
return qcom_cc_really_probe(pdev, &gcc_sdm845_desc, regmap);
}

View File

@ -219,8 +219,6 @@ static const char * const mmcc_xo_mmpll0_1_4_gpll1_0_sleep[] = {
"sleep_clk_src",
};
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
static struct clk_pll mmpll0 = {
.l_reg = 0x0004,
.m_reg = 0x0008,

View File

@ -184,8 +184,6 @@ static const char * const mmcc_xo_dsibyte_hdmi_edp_gpll0[] = {
"dsi1pllbyte",
};
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
static struct clk_pll mmpll0 = {
.l_reg = 0x0004,
.m_reg = 0x0008,

View File

@ -34,8 +34,6 @@
#include "reset.h"
#include "gdsc.h"
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
enum {
P_XO,
P_MMPLL0,

View File

@ -18,8 +18,6 @@
#include "clk-pll.h"
#include "gdsc.h"
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
enum {
P_BI_TCXO,
P_CORE_BI_PLL_TEST_SE,

View File

@ -21,6 +21,7 @@ config CLK_RENESAS
select CLK_R8A77980 if ARCH_R8A77980
select CLK_R8A77990 if ARCH_R8A77990
select CLK_R8A77995 if ARCH_R8A77995
select CLK_R9A06G032 if ARCH_R9A06G032
select CLK_SH73A0 if ARCH_SH73A0
if CLK_RENESAS
@ -125,6 +126,11 @@ config CLK_R8A77995
bool "R-Car D3 clock support" if COMPILE_TEST
select CLK_RCAR_GEN3_CPG
config CLK_R9A06G032
bool "Renesas R9A06G032 clock driver"
help
This is a driver for R9A06G032 clocks
config CLK_SH73A0
bool "SH-Mobile AG5 clock support" if COMPILE_TEST
select CLK_RENESAS_CPG_MSTP

View File

@ -20,6 +20,7 @@ obj-$(CONFIG_CLK_R8A77970) += r8a77970-cpg-mssr.o
obj-$(CONFIG_CLK_R8A77980) += r8a77980-cpg-mssr.o
obj-$(CONFIG_CLK_R8A77990) += r8a77990-cpg-mssr.o
obj-$(CONFIG_CLK_R8A77995) += r8a77995-cpg-mssr.o
obj-$(CONFIG_CLK_R9A06G032) += r9a06g032-clocks.o
obj-$(CONFIG_CLK_SH73A0) += clk-sh73a0.o
# Family

View File

@ -103,6 +103,7 @@ static struct cpg_core_clk r8a7795_core_clks[] __initdata = {
DEF_GEN3_SD("sd3", R8A7795_CLK_SD3, CLK_SDSRC, 0x26c),
DEF_FIXED("cl", R8A7795_CLK_CL, CLK_PLL1_DIV2, 48, 1),
DEF_FIXED("cr", R8A7795_CLK_CR, CLK_PLL1_DIV4, 2, 1),
DEF_FIXED("cp", R8A7795_CLK_CP, CLK_EXTAL, 2, 1),
DEF_DIV6P1("canfd", R8A7795_CLK_CANFD, CLK_PLL1_DIV4, 0x244),
@ -132,6 +133,7 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = {
DEF_MOD("sys-dmac2", 217, R8A7795_CLK_S0D3),
DEF_MOD("sys-dmac1", 218, R8A7795_CLK_S0D3),
DEF_MOD("sys-dmac0", 219, R8A7795_CLK_S0D3),
DEF_MOD("sceg-pub", 229, R8A7795_CLK_CR),
DEF_MOD("cmt3", 300, R8A7795_CLK_R),
DEF_MOD("cmt2", 301, R8A7795_CLK_R),
DEF_MOD("cmt1", 302, R8A7795_CLK_R),

View File

@ -0,0 +1,893 @@
// SPDX-License-Identifier: GPL-2.0
/*
* R9A09G032 clock driver
*
* Copyright (C) 2018 Renesas Electronics Europe Limited
*
* Michel Pollet <michel.pollet@bp.renesas.com>, <buserror@gmail.com>
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/math64.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <dt-bindings/clock/r9a06g032-sysctrl.h>
struct r9a06g032_gate {
u16 gate, reset, ready, midle,
scon, mirack, mistat;
};
/* This is used to describe a clock for instantiation */
struct r9a06g032_clkdesc {
const char *name;
uint32_t type: 3;
uint32_t index: 8;
uint32_t source : 8; /* source index + 1 (0 == none) */
/* these are used to populate the bitsel struct */
union {
struct r9a06g032_gate gate;
/* for dividers */
struct {
unsigned int div_min : 10, div_max : 10, reg: 10;
u16 div_table[4];
};
/* For fixed-factor ones */
struct {
u16 div, mul;
};
unsigned int factor;
unsigned int frequency;
/* for dual gate */
struct {
uint16_t group : 1, index: 3;
u16 sel, g1, r1, g2, r2;
} dual;
};
} __packed;
#define I_GATE(_clk, _rst, _rdy, _midle, _scon, _mirack, _mistat) \
{ .gate = _clk, .reset = _rst, \
.ready = _rdy, .midle = _midle, \
.scon = _scon, .mirack = _mirack, .mistat = _mistat }
#define D_GATE(_idx, _n, _src, ...) \
{ .type = K_GATE, .index = R9A06G032_##_idx, \
.source = 1 + R9A06G032_##_src, .name = _n, \
.gate = I_GATE(__VA_ARGS__), }
#define D_ROOT(_idx, _n, _mul, _div) \
{ .type = K_FFC, .index = R9A06G032_##_idx, .name = _n, \
.div = _div, .mul = _mul }
#define D_FFC(_idx, _n, _src, _div) \
{ .type = K_FFC, .index = R9A06G032_##_idx, \
.source = 1 + R9A06G032_##_src, .name = _n, \
.div = _div, .mul = 1}
#define D_DIV(_idx, _n, _src, _reg, _min, _max, ...) \
{ .type = K_DIV, .index = R9A06G032_##_idx, \
.source = 1 + R9A06G032_##_src, .name = _n, \
.reg = _reg, .div_min = _min, .div_max = _max, \
.div_table = { __VA_ARGS__ } }
#define D_UGATE(_idx, _n, _src, _g, _gi, _g1, _r1, _g2, _r2) \
{ .type = K_DUALGATE, .index = R9A06G032_##_idx, \
.source = 1 + R9A06G032_##_src, .name = _n, \
.dual = { .group = _g, .index = _gi, \
.g1 = _g1, .r1 = _r1, .g2 = _g2, .r2 = _r2 }, }
enum { K_GATE = 0, K_FFC, K_DIV, K_BITSEL, K_DUALGATE };
/* Internal clock IDs */
#define R9A06G032_CLKOUT 0
#define R9A06G032_CLKOUT_D10 2
#define R9A06G032_CLKOUT_D16 3
#define R9A06G032_CLKOUT_D160 4
#define R9A06G032_CLKOUT_D1OR2 5
#define R9A06G032_CLKOUT_D20 6
#define R9A06G032_CLKOUT_D40 7
#define R9A06G032_CLKOUT_D5 8
#define R9A06G032_CLKOUT_D8 9
#define R9A06G032_DIV_ADC 10
#define R9A06G032_DIV_I2C 11
#define R9A06G032_DIV_NAND 12
#define R9A06G032_DIV_P1_PG 13
#define R9A06G032_DIV_P2_PG 14
#define R9A06G032_DIV_P3_PG 15
#define R9A06G032_DIV_P4_PG 16
#define R9A06G032_DIV_P5_PG 17
#define R9A06G032_DIV_P6_PG 18
#define R9A06G032_DIV_QSPI0 19
#define R9A06G032_DIV_QSPI1 20
#define R9A06G032_DIV_REF_SYNC 21
#define R9A06G032_DIV_SDIO0 22
#define R9A06G032_DIV_SDIO1 23
#define R9A06G032_DIV_SWITCH 24
#define R9A06G032_DIV_UART 25
#define R9A06G032_DIV_MOTOR 64
#define R9A06G032_CLK_DDRPHY_PLLCLK_D4 78
#define R9A06G032_CLK_ECAT100_D4 79
#define R9A06G032_CLK_HSR100_D2 80
#define R9A06G032_CLK_REF_SYNC_D4 81
#define R9A06G032_CLK_REF_SYNC_D8 82
#define R9A06G032_CLK_SERCOS100_D2 83
#define R9A06G032_DIV_CA7 84
#define R9A06G032_UART_GROUP_012 154
#define R9A06G032_UART_GROUP_34567 155
#define R9A06G032_CLOCK_COUNT (R9A06G032_UART_GROUP_34567 + 1)
static const struct r9a06g032_clkdesc r9a06g032_clocks[] __initconst = {
D_ROOT(CLKOUT, "clkout", 25, 1),
D_ROOT(CLK_PLL_USB, "clk_pll_usb", 12, 10),
D_FFC(CLKOUT_D10, "clkout_d10", CLKOUT, 10),
D_FFC(CLKOUT_D16, "clkout_d16", CLKOUT, 16),
D_FFC(CLKOUT_D160, "clkout_d160", CLKOUT, 160),
D_DIV(CLKOUT_D1OR2, "clkout_d1or2", CLKOUT, 0, 1, 2),
D_FFC(CLKOUT_D20, "clkout_d20", CLKOUT, 20),
D_FFC(CLKOUT_D40, "clkout_d40", CLKOUT, 40),
D_FFC(CLKOUT_D5, "clkout_d5", CLKOUT, 5),
D_FFC(CLKOUT_D8, "clkout_d8", CLKOUT, 8),
D_DIV(DIV_ADC, "div_adc", CLKOUT, 77, 50, 250),
D_DIV(DIV_I2C, "div_i2c", CLKOUT, 78, 12, 16),
D_DIV(DIV_NAND, "div_nand", CLKOUT, 82, 12, 32),
D_DIV(DIV_P1_PG, "div_p1_pg", CLKOUT, 68, 12, 200),
D_DIV(DIV_P2_PG, "div_p2_pg", CLKOUT, 62, 12, 128),
D_DIV(DIV_P3_PG, "div_p3_pg", CLKOUT, 64, 8, 128),
D_DIV(DIV_P4_PG, "div_p4_pg", CLKOUT, 66, 8, 128),
D_DIV(DIV_P5_PG, "div_p5_pg", CLKOUT, 71, 10, 40),
D_DIV(DIV_P6_PG, "div_p6_pg", CLKOUT, 18, 12, 64),
D_DIV(DIV_QSPI0, "div_qspi0", CLKOUT, 73, 3, 7),
D_DIV(DIV_QSPI1, "div_qspi1", CLKOUT, 25, 3, 7),
D_DIV(DIV_REF_SYNC, "div_ref_sync", CLKOUT, 56, 2, 16, 2, 4, 8, 16),
D_DIV(DIV_SDIO0, "div_sdio0", CLKOUT, 74, 20, 128),
D_DIV(DIV_SDIO1, "div_sdio1", CLKOUT, 75, 20, 128),
D_DIV(DIV_SWITCH, "div_switch", CLKOUT, 37, 5, 40),
D_DIV(DIV_UART, "div_uart", CLKOUT, 79, 12, 128),
D_GATE(CLK_25_PG4, "clk_25_pg4", CLKOUT_D40, 0x749, 0x74a, 0x74b, 0, 0xae3, 0, 0),
D_GATE(CLK_25_PG5, "clk_25_pg5", CLKOUT_D40, 0x74c, 0x74d, 0x74e, 0, 0xae4, 0, 0),
D_GATE(CLK_25_PG6, "clk_25_pg6", CLKOUT_D40, 0x74f, 0x750, 0x751, 0, 0xae5, 0, 0),
D_GATE(CLK_25_PG7, "clk_25_pg7", CLKOUT_D40, 0x752, 0x753, 0x754, 0, 0xae6, 0, 0),
D_GATE(CLK_25_PG8, "clk_25_pg8", CLKOUT_D40, 0x755, 0x756, 0x757, 0, 0xae7, 0, 0),
D_GATE(CLK_ADC, "clk_adc", DIV_ADC, 0x1ea, 0x1eb, 0, 0, 0, 0, 0),
D_GATE(CLK_ECAT100, "clk_ecat100", CLKOUT_D10, 0x405, 0, 0, 0, 0, 0, 0),
D_GATE(CLK_HSR100, "clk_hsr100", CLKOUT_D10, 0x483, 0, 0, 0, 0, 0, 0),
D_GATE(CLK_I2C0, "clk_i2c0", DIV_I2C, 0x1e6, 0x1e7, 0, 0, 0, 0, 0),
D_GATE(CLK_I2C1, "clk_i2c1", DIV_I2C, 0x1e8, 0x1e9, 0, 0, 0, 0, 0),
D_GATE(CLK_MII_REF, "clk_mii_ref", CLKOUT_D40, 0x342, 0, 0, 0, 0, 0, 0),
D_GATE(CLK_NAND, "clk_nand", DIV_NAND, 0x284, 0x285, 0, 0, 0, 0, 0),
D_GATE(CLK_NOUSBP2_PG6, "clk_nousbp2_pg6", DIV_P2_PG, 0x774, 0x775, 0, 0, 0, 0, 0),
D_GATE(CLK_P1_PG2, "clk_p1_pg2", DIV_P1_PG, 0x862, 0x863, 0, 0, 0, 0, 0),
D_GATE(CLK_P1_PG3, "clk_p1_pg3", DIV_P1_PG, 0x864, 0x865, 0, 0, 0, 0, 0),
D_GATE(CLK_P1_PG4, "clk_p1_pg4", DIV_P1_PG, 0x866, 0x867, 0, 0, 0, 0, 0),
D_GATE(CLK_P4_PG3, "clk_p4_pg3", DIV_P4_PG, 0x824, 0x825, 0, 0, 0, 0, 0),
D_GATE(CLK_P4_PG4, "clk_p4_pg4", DIV_P4_PG, 0x826, 0x827, 0, 0, 0, 0, 0),
D_GATE(CLK_P6_PG1, "clk_p6_pg1", DIV_P6_PG, 0x8a0, 0x8a1, 0x8a2, 0, 0xb60, 0, 0),
D_GATE(CLK_P6_PG2, "clk_p6_pg2", DIV_P6_PG, 0x8a3, 0x8a4, 0x8a5, 0, 0xb61, 0, 0),
D_GATE(CLK_P6_PG3, "clk_p6_pg3", DIV_P6_PG, 0x8a6, 0x8a7, 0x8a8, 0, 0xb62, 0, 0),
D_GATE(CLK_P6_PG4, "clk_p6_pg4", DIV_P6_PG, 0x8a9, 0x8aa, 0x8ab, 0, 0xb63, 0, 0),
D_GATE(CLK_QSPI0, "clk_qspi0", DIV_QSPI0, 0x2a4, 0x2a5, 0, 0, 0, 0, 0),
D_GATE(CLK_QSPI1, "clk_qspi1", DIV_QSPI1, 0x484, 0x485, 0, 0, 0, 0, 0),
D_GATE(CLK_RGMII_REF, "clk_rgmii_ref", CLKOUT_D8, 0x340, 0, 0, 0, 0, 0, 0),
D_GATE(CLK_RMII_REF, "clk_rmii_ref", CLKOUT_D20, 0x341, 0, 0, 0, 0, 0, 0),
D_GATE(CLK_SDIO0, "clk_sdio0", DIV_SDIO0, 0x64, 0, 0, 0, 0, 0, 0),
D_GATE(CLK_SDIO1, "clk_sdio1", DIV_SDIO1, 0x644, 0, 0, 0, 0, 0, 0),
D_GATE(CLK_SERCOS100, "clk_sercos100", CLKOUT_D10, 0x425, 0, 0, 0, 0, 0, 0),
D_GATE(CLK_SLCD, "clk_slcd", DIV_P1_PG, 0x860, 0x861, 0, 0, 0, 0, 0),
D_GATE(CLK_SPI0, "clk_spi0", DIV_P3_PG, 0x7e0, 0x7e1, 0, 0, 0, 0, 0),
D_GATE(CLK_SPI1, "clk_spi1", DIV_P3_PG, 0x7e2, 0x7e3, 0, 0, 0, 0, 0),
D_GATE(CLK_SPI2, "clk_spi2", DIV_P3_PG, 0x7e4, 0x7e5, 0, 0, 0, 0, 0),
D_GATE(CLK_SPI3, "clk_spi3", DIV_P3_PG, 0x7e6, 0x7e7, 0, 0, 0, 0, 0),
D_GATE(CLK_SPI4, "clk_spi4", DIV_P4_PG, 0x820, 0x821, 0, 0, 0, 0, 0),
D_GATE(CLK_SPI5, "clk_spi5", DIV_P4_PG, 0x822, 0x823, 0, 0, 0, 0, 0),
D_GATE(CLK_SWITCH, "clk_switch", DIV_SWITCH, 0x982, 0x983, 0, 0, 0, 0, 0),
D_DIV(DIV_MOTOR, "div_motor", CLKOUT_D5, 84, 2, 8),
D_GATE(HCLK_ECAT125, "hclk_ecat125", CLKOUT_D8, 0x400, 0x401, 0, 0x402, 0, 0x440, 0x441),
D_GATE(HCLK_PINCONFIG, "hclk_pinconfig", CLKOUT_D40, 0x740, 0x741, 0x742, 0, 0xae0, 0, 0),
D_GATE(HCLK_SERCOS, "hclk_sercos", CLKOUT_D10, 0x420, 0x422, 0, 0x421, 0, 0x460, 0x461),
D_GATE(HCLK_SGPIO2, "hclk_sgpio2", DIV_P5_PG, 0x8c3, 0x8c4, 0x8c5, 0, 0xb41, 0, 0),
D_GATE(HCLK_SGPIO3, "hclk_sgpio3", DIV_P5_PG, 0x8c6, 0x8c7, 0x8c8, 0, 0xb42, 0, 0),
D_GATE(HCLK_SGPIO4, "hclk_sgpio4", DIV_P5_PG, 0x8c9, 0x8ca, 0x8cb, 0, 0xb43, 0, 0),
D_GATE(HCLK_TIMER0, "hclk_timer0", CLKOUT_D40, 0x743, 0x744, 0x745, 0, 0xae1, 0, 0),
D_GATE(HCLK_TIMER1, "hclk_timer1", CLKOUT_D40, 0x746, 0x747, 0x748, 0, 0xae2, 0, 0),
D_GATE(HCLK_USBF, "hclk_usbf", CLKOUT_D8, 0xe3, 0, 0, 0xe4, 0, 0x102, 0x103),
D_GATE(HCLK_USBH, "hclk_usbh", CLKOUT_D8, 0xe0, 0xe1, 0, 0xe2, 0, 0x100, 0x101),
D_GATE(HCLK_USBPM, "hclk_usbpm", CLKOUT_D8, 0xe5, 0, 0, 0, 0, 0, 0),
D_GATE(CLK_48_PG_F, "clk_48_pg_f", CLK_48, 0x78c, 0x78d, 0, 0x78e, 0, 0xb04, 0xb05),
D_GATE(CLK_48_PG4, "clk_48_pg4", CLK_48, 0x789, 0x78a, 0x78b, 0, 0xb03, 0, 0),
D_FFC(CLK_DDRPHY_PLLCLK_D4, "clk_ddrphy_pllclk_d4", CLK_DDRPHY_PLLCLK, 4),
D_FFC(CLK_ECAT100_D4, "clk_ecat100_d4", CLK_ECAT100, 4),
D_FFC(CLK_HSR100_D2, "clk_hsr100_d2", CLK_HSR100, 2),
D_FFC(CLK_REF_SYNC_D4, "clk_ref_sync_d4", CLK_REF_SYNC, 4),
D_FFC(CLK_REF_SYNC_D8, "clk_ref_sync_d8", CLK_REF_SYNC, 8),
D_FFC(CLK_SERCOS100_D2, "clk_sercos100_d2", CLK_SERCOS100, 2),
D_DIV(DIV_CA7, "div_ca7", CLK_REF_SYNC, 57, 1, 4, 1, 2, 4),
D_GATE(HCLK_CAN0, "hclk_can0", CLK_48, 0x783, 0x784, 0x785, 0, 0xb01, 0, 0),
D_GATE(HCLK_CAN1, "hclk_can1", CLK_48, 0x786, 0x787, 0x788, 0, 0xb02, 0, 0),
D_GATE(HCLK_DELTASIGMA, "hclk_deltasigma", DIV_MOTOR, 0x1ef, 0x1f0, 0x1f1, 0, 0, 0, 0),
D_GATE(HCLK_PWMPTO, "hclk_pwmpto", DIV_MOTOR, 0x1ec, 0x1ed, 0x1ee, 0, 0, 0, 0),
D_GATE(HCLK_RSV, "hclk_rsv", CLK_48, 0x780, 0x781, 0x782, 0, 0xb00, 0, 0),
D_GATE(HCLK_SGPIO0, "hclk_sgpio0", DIV_MOTOR, 0x1e0, 0x1e1, 0x1e2, 0, 0, 0, 0),
D_GATE(HCLK_SGPIO1, "hclk_sgpio1", DIV_MOTOR, 0x1e3, 0x1e4, 0x1e5, 0, 0, 0, 0),
D_DIV(RTOS_MDC, "rtos_mdc", CLK_REF_SYNC, 100, 80, 640, 80, 160, 320, 640),
D_GATE(CLK_CM3, "clk_cm3", CLK_REF_SYNC_D4, 0xba0, 0xba1, 0, 0xba2, 0, 0xbc0, 0xbc1),
D_GATE(CLK_DDRC, "clk_ddrc", CLK_DDRPHY_PLLCLK_D4, 0x323, 0x324, 0, 0, 0, 0, 0),
D_GATE(CLK_ECAT25, "clk_ecat25", CLK_ECAT100_D4, 0x403, 0x404, 0, 0, 0, 0, 0),
D_GATE(CLK_HSR50, "clk_hsr50", CLK_HSR100_D2, 0x484, 0x485, 0, 0, 0, 0, 0),
D_GATE(CLK_HW_RTOS, "clk_hw_rtos", CLK_REF_SYNC_D4, 0xc60, 0xc61, 0, 0, 0, 0, 0),
D_GATE(CLK_SERCOS50, "clk_sercos50", CLK_SERCOS100_D2, 0x424, 0x423, 0, 0, 0, 0, 0),
D_GATE(HCLK_ADC, "hclk_adc", CLK_REF_SYNC_D8, 0x1af, 0x1b0, 0x1b1, 0, 0, 0, 0),
D_GATE(HCLK_CM3, "hclk_cm3", CLK_REF_SYNC_D4, 0xc20, 0xc21, 0xc22, 0, 0, 0, 0),
D_GATE(HCLK_CRYPTO_EIP150, "hclk_crypto_eip150", CLK_REF_SYNC_D4, 0x123, 0x124, 0x125, 0, 0x142, 0, 0),
D_GATE(HCLK_CRYPTO_EIP93, "hclk_crypto_eip93", CLK_REF_SYNC_D4, 0x120, 0x121, 0, 0x122, 0, 0x140, 0x141),
D_GATE(HCLK_DDRC, "hclk_ddrc", CLK_REF_SYNC_D4, 0x320, 0x322, 0, 0x321, 0, 0x3a0, 0x3a1),
D_GATE(HCLK_DMA0, "hclk_dma0", CLK_REF_SYNC_D4, 0x260, 0x261, 0x262, 0x263, 0x2c0, 0x2c1, 0x2c2),
D_GATE(HCLK_DMA1, "hclk_dma1", CLK_REF_SYNC_D4, 0x264, 0x265, 0x266, 0x267, 0x2c3, 0x2c4, 0x2c5),
D_GATE(HCLK_GMAC0, "hclk_gmac0", CLK_REF_SYNC_D4, 0x360, 0x361, 0x362, 0x363, 0x3c0, 0x3c1, 0x3c2),
D_GATE(HCLK_GMAC1, "hclk_gmac1", CLK_REF_SYNC_D4, 0x380, 0x381, 0x382, 0x383, 0x3e0, 0x3e1, 0x3e2),
D_GATE(HCLK_GPIO0, "hclk_gpio0", CLK_REF_SYNC_D4, 0x212, 0x213, 0x214, 0, 0, 0, 0),
D_GATE(HCLK_GPIO1, "hclk_gpio1", CLK_REF_SYNC_D4, 0x215, 0x216, 0x217, 0, 0, 0, 0),
D_GATE(HCLK_GPIO2, "hclk_gpio2", CLK_REF_SYNC_D4, 0x229, 0x22a, 0x22b, 0, 0, 0, 0),
D_GATE(HCLK_HSR, "hclk_hsr", CLK_HSR100_D2, 0x480, 0x482, 0, 0x481, 0, 0x4c0, 0x4c1),
D_GATE(HCLK_I2C0, "hclk_i2c0", CLK_REF_SYNC_D8, 0x1a9, 0x1aa, 0x1ab, 0, 0, 0, 0),
D_GATE(HCLK_I2C1, "hclk_i2c1", CLK_REF_SYNC_D8, 0x1ac, 0x1ad, 0x1ae, 0, 0, 0, 0),
D_GATE(HCLK_LCD, "hclk_lcd", CLK_REF_SYNC_D4, 0x7a0, 0x7a1, 0x7a2, 0, 0xb20, 0, 0),
D_GATE(HCLK_MSEBI_M, "hclk_msebi_m", CLK_REF_SYNC_D4, 0x164, 0x165, 0x166, 0, 0x183, 0, 0),
D_GATE(HCLK_MSEBI_S, "hclk_msebi_s", CLK_REF_SYNC_D4, 0x160, 0x161, 0x162, 0x163, 0x180, 0x181, 0x182),
D_GATE(HCLK_NAND, "hclk_nand", CLK_REF_SYNC_D4, 0x280, 0x281, 0x282, 0x283, 0x2e0, 0x2e1, 0x2e2),
D_GATE(HCLK_PG_I, "hclk_pg_i", CLK_REF_SYNC_D4, 0x7ac, 0x7ad, 0, 0x7ae, 0, 0xb24, 0xb25),
D_GATE(HCLK_PG19, "hclk_pg19", CLK_REF_SYNC_D4, 0x22c, 0x22d, 0x22e, 0, 0, 0, 0),
D_GATE(HCLK_PG20, "hclk_pg20", CLK_REF_SYNC_D4, 0x22f, 0x230, 0x231, 0, 0, 0, 0),
D_GATE(HCLK_PG3, "hclk_pg3", CLK_REF_SYNC_D4, 0x7a6, 0x7a7, 0x7a8, 0, 0xb22, 0, 0),
D_GATE(HCLK_PG4, "hclk_pg4", CLK_REF_SYNC_D4, 0x7a9, 0x7aa, 0x7ab, 0, 0xb23, 0, 0),
D_GATE(HCLK_QSPI0, "hclk_qspi0", CLK_REF_SYNC_D4, 0x2a0, 0x2a1, 0x2a2, 0x2a3, 0x300, 0x301, 0x302),
D_GATE(HCLK_QSPI1, "hclk_qspi1", CLK_REF_SYNC_D4, 0x480, 0x481, 0x482, 0x483, 0x4c0, 0x4c1, 0x4c2),
D_GATE(HCLK_ROM, "hclk_rom", CLK_REF_SYNC_D4, 0xaa0, 0xaa1, 0xaa2, 0, 0xb80, 0, 0),
D_GATE(HCLK_RTC, "hclk_rtc", CLK_REF_SYNC_D8, 0xa00, 0, 0, 0, 0, 0, 0),
D_GATE(HCLK_SDIO0, "hclk_sdio0", CLK_REF_SYNC_D4, 0x60, 0x61, 0x62, 0x63, 0x80, 0x81, 0x82),
D_GATE(HCLK_SDIO1, "hclk_sdio1", CLK_REF_SYNC_D4, 0x640, 0x641, 0x642, 0x643, 0x660, 0x661, 0x662),
D_GATE(HCLK_SEMAP, "hclk_semap", CLK_REF_SYNC_D4, 0x7a3, 0x7a4, 0x7a5, 0, 0xb21, 0, 0),
D_GATE(HCLK_SPI0, "hclk_spi0", CLK_REF_SYNC_D4, 0x200, 0x201, 0x202, 0, 0, 0, 0),
D_GATE(HCLK_SPI1, "hclk_spi1", CLK_REF_SYNC_D4, 0x203, 0x204, 0x205, 0, 0, 0, 0),
D_GATE(HCLK_SPI2, "hclk_spi2", CLK_REF_SYNC_D4, 0x206, 0x207, 0x208, 0, 0, 0, 0),
D_GATE(HCLK_SPI3, "hclk_spi3", CLK_REF_SYNC_D4, 0x209, 0x20a, 0x20b, 0, 0, 0, 0),
D_GATE(HCLK_SPI4, "hclk_spi4", CLK_REF_SYNC_D4, 0x20c, 0x20d, 0x20e, 0, 0, 0, 0),
D_GATE(HCLK_SPI5, "hclk_spi5", CLK_REF_SYNC_D4, 0x20f, 0x210, 0x211, 0, 0, 0, 0),
D_GATE(HCLK_SWITCH, "hclk_switch", CLK_REF_SYNC_D4, 0x980, 0, 0x981, 0, 0, 0, 0),
D_GATE(HCLK_SWITCH_RG, "hclk_switch_rg", CLK_REF_SYNC_D4, 0xc40, 0xc41, 0xc42, 0, 0, 0, 0),
D_GATE(HCLK_UART0, "hclk_uart0", CLK_REF_SYNC_D8, 0x1a0, 0x1a1, 0x1a2, 0, 0, 0, 0),
D_GATE(HCLK_UART1, "hclk_uart1", CLK_REF_SYNC_D8, 0x1a3, 0x1a4, 0x1a5, 0, 0, 0, 0),
D_GATE(HCLK_UART2, "hclk_uart2", CLK_REF_SYNC_D8, 0x1a6, 0x1a7, 0x1a8, 0, 0, 0, 0),
D_GATE(HCLK_UART3, "hclk_uart3", CLK_REF_SYNC_D4, 0x218, 0x219, 0x21a, 0, 0, 0, 0),
D_GATE(HCLK_UART4, "hclk_uart4", CLK_REF_SYNC_D4, 0x21b, 0x21c, 0x21d, 0, 0, 0, 0),
D_GATE(HCLK_UART5, "hclk_uart5", CLK_REF_SYNC_D4, 0x220, 0x221, 0x222, 0, 0, 0, 0),
D_GATE(HCLK_UART6, "hclk_uart6", CLK_REF_SYNC_D4, 0x223, 0x224, 0x225, 0, 0, 0, 0),
D_GATE(HCLK_UART7, "hclk_uart7", CLK_REF_SYNC_D4, 0x226, 0x227, 0x228, 0, 0, 0, 0),
/*
* These are not hardware clocks, but are needed to handle the special
* case where we have a 'selector bit' that doesn't just change the
* parent for a clock, but also the gate it's suposed to use.
*/
{
.index = R9A06G032_UART_GROUP_012,
.name = "uart_group_012",
.type = K_BITSEL,
.source = 1 + R9A06G032_DIV_UART,
/* R9A06G032_SYSCTRL_REG_PWRCTRL_PG1_PR2 */
.dual.sel = ((0xec / 4) << 5) | 24,
.dual.group = 0,
},
{
.index = R9A06G032_UART_GROUP_34567,
.name = "uart_group_34567",
.type = K_BITSEL,
.source = 1 + R9A06G032_DIV_P2_PG,
/* R9A06G032_SYSCTRL_REG_PWRCTRL_PG0_0 */
.dual.sel = ((0x34 / 4) << 5) | 30,
.dual.group = 1,
},
D_UGATE(CLK_UART0, "clk_uart0", UART_GROUP_012, 0, 0, 0x1b2, 0x1b3, 0x1b4, 0x1b5),
D_UGATE(CLK_UART1, "clk_uart1", UART_GROUP_012, 0, 1, 0x1b6, 0x1b7, 0x1b8, 0x1b9),
D_UGATE(CLK_UART2, "clk_uart2", UART_GROUP_012, 0, 2, 0x1ba, 0x1bb, 0x1bc, 0x1bd),
D_UGATE(CLK_UART3, "clk_uart3", UART_GROUP_34567, 1, 0, 0x760, 0x761, 0x762, 0x763),
D_UGATE(CLK_UART4, "clk_uart4", UART_GROUP_34567, 1, 1, 0x764, 0x765, 0x766, 0x767),
D_UGATE(CLK_UART5, "clk_uart5", UART_GROUP_34567, 1, 2, 0x768, 0x769, 0x76a, 0x76b),
D_UGATE(CLK_UART6, "clk_uart6", UART_GROUP_34567, 1, 3, 0x76c, 0x76d, 0x76e, 0x76f),
D_UGATE(CLK_UART7, "clk_uart7", UART_GROUP_34567, 1, 4, 0x770, 0x771, 0x772, 0x773),
};
struct r9a06g032_priv {
struct clk_onecell_data data;
spinlock_t lock; /* protects concurent access to gates */
void __iomem *reg;
};
/* register/bit pairs are encoded as an uint16_t */
static void
clk_rdesc_set(struct r9a06g032_priv *clocks,
u16 one, unsigned int on)
{
u32 __iomem *reg = clocks->reg + (4 * (one >> 5));
u32 val = readl(reg);
val = (val & ~(1U << (one & 0x1f))) | ((!!on) << (one & 0x1f));
writel(val, reg);
}
static int
clk_rdesc_get(struct r9a06g032_priv *clocks,
uint16_t one)
{
u32 __iomem *reg = clocks->reg + (4 * (one >> 5));
u32 val = readl(reg);
return !!(val & (1U << (one & 0x1f)));
}
/*
* This implements the R9A09G032 clock gate 'driver'. We cannot use the system's
* clock gate framework as the gates on the R9A09G032 have a special enabling
* sequence, therefore we use this little proxy.
*/
struct r9a06g032_clk_gate {
struct clk_hw hw;
struct r9a06g032_priv *clocks;
u16 index;
struct r9a06g032_gate gate;
};
#define to_r9a06g032_gate(_hw) container_of(_hw, struct r9a06g032_clk_gate, hw)
static void
r9a06g032_clk_gate_set(struct r9a06g032_priv *clocks,
struct r9a06g032_gate *g, int on)
{
unsigned long flags;
WARN_ON(!g->gate);
spin_lock_irqsave(&clocks->lock, flags);
clk_rdesc_set(clocks, g->gate, on);
/* De-assert reset */
if (g->reset)
clk_rdesc_set(clocks, g->reset, 1);
spin_unlock_irqrestore(&clocks->lock, flags);
/* Hardware manual recommends 5us delay after enabling clock & reset */
udelay(5);
/* If the peripheral is memory mapped (i.e. an AXI slave), there is an
* associated SLVRDY bit in the System Controller that needs to be set
* so that the FlexWAY bus fabric passes on the read/write requests.
*/
if (g->ready || g->midle) {
spin_lock_irqsave(&clocks->lock, flags);
if (g->ready)
clk_rdesc_set(clocks, g->ready, on);
/* Clear 'Master Idle Request' bit */
if (g->midle)
clk_rdesc_set(clocks, g->midle, !on);
spin_unlock_irqrestore(&clocks->lock, flags);
}
/* Note: We don't wait for FlexWAY Socket Connection signal */
}
static int r9a06g032_clk_gate_enable(struct clk_hw *hw)
{
struct r9a06g032_clk_gate *g = to_r9a06g032_gate(hw);
r9a06g032_clk_gate_set(g->clocks, &g->gate, 1);
return 0;
}
static void r9a06g032_clk_gate_disable(struct clk_hw *hw)
{
struct r9a06g032_clk_gate *g = to_r9a06g032_gate(hw);
r9a06g032_clk_gate_set(g->clocks, &g->gate, 0);
}
static int r9a06g032_clk_gate_is_enabled(struct clk_hw *hw)
{
struct r9a06g032_clk_gate *g = to_r9a06g032_gate(hw);
/* if clock is in reset, the gate might be on, and still not 'be' on */
if (g->gate.reset && !clk_rdesc_get(g->clocks, g->gate.reset))
return 0;
return clk_rdesc_get(g->clocks, g->gate.gate);
}
static const struct clk_ops r9a06g032_clk_gate_ops = {
.enable = r9a06g032_clk_gate_enable,
.disable = r9a06g032_clk_gate_disable,
.is_enabled = r9a06g032_clk_gate_is_enabled,
};
static struct clk *
r9a06g032_register_gate(struct r9a06g032_priv *clocks,
const char *parent_name,
const struct r9a06g032_clkdesc *desc)
{
struct clk *clk;
struct r9a06g032_clk_gate *g;
struct clk_init_data init;
g = kzalloc(sizeof(*g), GFP_KERNEL);
if (!g)
return NULL;
init.name = desc->name;
init.ops = &r9a06g032_clk_gate_ops;
init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
g->clocks = clocks;
g->index = desc->index;
g->gate = desc->gate;
g->hw.init = &init;
/*
* important here, some clocks are already in use by the CM3, we
* have to assume they are not Linux's to play with and try to disable
* at the end of the boot!
*/
if (r9a06g032_clk_gate_is_enabled(&g->hw)) {
init.flags |= CLK_IS_CRITICAL;
pr_debug("%s was enabled, making read-only\n", desc->name);
}
clk = clk_register(NULL, &g->hw);
if (IS_ERR(clk)) {
kfree(g);
return NULL;
}
return clk;
}
struct r9a06g032_clk_div {
struct clk_hw hw;
struct r9a06g032_priv *clocks;
u16 index;
u16 reg;
u16 min, max;
u8 table_size;
u16 table[8]; /* we know there are no more than 8 */
};
#define to_r9a06g032_div(_hw) \
container_of(_hw, struct r9a06g032_clk_div, hw)
static unsigned long
r9a06g032_div_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct r9a06g032_clk_div *clk = to_r9a06g032_div(hw);
u32 __iomem *reg = clk->clocks->reg + (4 * clk->reg);
u32 div = readl(reg);
if (div < clk->min)
div = clk->min;
else if (div > clk->max)
div = clk->max;
return DIV_ROUND_UP(parent_rate, div);
}
/*
* Attempts to find a value that is in range of min,max,
* and if a table of set dividers was specified for this
* register, try to find the fixed divider that is the closest
* to the target frequency
*/
static long
r9a06g032_div_clamp_div(struct r9a06g032_clk_div *clk,
unsigned long rate, unsigned long prate)
{
/* + 1 to cope with rates that have the remainder dropped */
u32 div = DIV_ROUND_UP(prate, rate + 1);
int i;
if (div <= clk->min)
return clk->min;
if (div >= clk->max)
return clk->max;
for (i = 0; clk->table_size && i < clk->table_size - 1; i++) {
if (div >= clk->table[i] && div <= clk->table[i + 1]) {
unsigned long m = rate -
DIV_ROUND_UP(prate, clk->table[i]);
unsigned long p =
DIV_ROUND_UP(prate, clk->table[i + 1]) -
rate;
/*
* select the divider that generates
* the value closest to the ideal frequency
*/
div = p >= m ? clk->table[i] : clk->table[i + 1];
return div;
}
}
return div;
}
static long
r9a06g032_div_round_rate(struct clk_hw *hw,
unsigned long rate, unsigned long *prate)
{
struct r9a06g032_clk_div *clk = to_r9a06g032_div(hw);
u32 div = DIV_ROUND_UP(*prate, rate);
pr_devel("%s %pC %ld (prate %ld) (wanted div %u)\n", __func__,
hw->clk, rate, *prate, div);
pr_devel(" min %d (%ld) max %d (%ld)\n",
clk->min, DIV_ROUND_UP(*prate, clk->min),
clk->max, DIV_ROUND_UP(*prate, clk->max));
div = r9a06g032_div_clamp_div(clk, rate, *prate);
/*
* this is a hack. Currently the serial driver asks for a clock rate
* that is 16 times the baud rate -- and that is wildly outside the
* range of the UART divider, somehow there is no provision for that
* case of 'let the divider as is if outside range'.
* The serial driver *shouldn't* play with these clocks anyway, there's
* several uarts attached to this divider, and changing this impacts
* everyone.
*/
if (clk->index == R9A06G032_DIV_UART) {
pr_devel("%s div uart hack!\n", __func__);
return clk_get_rate(hw->clk);
}
pr_devel("%s %pC %ld / %u = %ld\n", __func__, hw->clk,
*prate, div, DIV_ROUND_UP(*prate, div));
return DIV_ROUND_UP(*prate, div);
}
static int
r9a06g032_div_set_rate(struct clk_hw *hw,
unsigned long rate, unsigned long parent_rate)
{
struct r9a06g032_clk_div *clk = to_r9a06g032_div(hw);
/* + 1 to cope with rates that have the remainder dropped */
u32 div = DIV_ROUND_UP(parent_rate, rate + 1);
u32 __iomem *reg = clk->clocks->reg + (4 * clk->reg);
pr_devel("%s %pC rate %ld parent %ld div %d\n", __func__, hw->clk,
rate, parent_rate, div);
/*
* Need to write the bit 31 with the divider value to
* latch it. Technically we should wait until it has been
* cleared too.
* TODO: Find whether this callback is sleepable, in case
* the hardware /does/ require some sort of spinloop here.
*/
writel(div | BIT(31), reg);
return 0;
}
static const struct clk_ops r9a06g032_clk_div_ops = {
.recalc_rate = r9a06g032_div_recalc_rate,
.round_rate = r9a06g032_div_round_rate,
.set_rate = r9a06g032_div_set_rate,
};
static struct clk *
r9a06g032_register_div(struct r9a06g032_priv *clocks,
const char *parent_name,
const struct r9a06g032_clkdesc *desc)
{
struct r9a06g032_clk_div *div;
struct clk *clk;
struct clk_init_data init;
unsigned int i;
div = kzalloc(sizeof(*div), GFP_KERNEL);
if (!div)
return NULL;
init.name = desc->name;
init.ops = &r9a06g032_clk_div_ops;
init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
div->clocks = clocks;
div->index = desc->index;
div->reg = desc->reg;
div->hw.init = &init;
div->min = desc->div_min;
div->max = desc->div_max;
/* populate (optional) divider table fixed values */
for (i = 0; i < ARRAY_SIZE(div->table) &&
i < ARRAY_SIZE(desc->div_table) && desc->div_table[i]; i++) {
div->table[div->table_size++] = desc->div_table[i];
}
clk = clk_register(NULL, &div->hw);
if (IS_ERR(clk)) {
kfree(div);
return NULL;
}
return clk;
}
/*
* This clock provider handles the case of the R9A06G032 where you have
* peripherals that have two potential clock source and two gates, one for
* each of the clock source - the used clock source (for all sub clocks)
* is selected by a single bit.
* That single bit affects all sub-clocks, and therefore needs to change the
* active gate (and turn the others off) and force a recalculation of the rates.
*
* This implements two clock providers, one 'bitselect' that
* handles the switch between both parents, and another 'dualgate'
* that knows which gate to poke at, depending on the parent's bit position.
*/
struct r9a06g032_clk_bitsel {
struct clk_hw hw;
struct r9a06g032_priv *clocks;
u16 index;
u16 selector; /* selector register + bit */
};
#define to_clk_bitselect(_hw) \
container_of(_hw, struct r9a06g032_clk_bitsel, hw)
static u8 r9a06g032_clk_mux_get_parent(struct clk_hw *hw)
{
struct r9a06g032_clk_bitsel *set = to_clk_bitselect(hw);
return clk_rdesc_get(set->clocks, set->selector);
}
static int r9a06g032_clk_mux_set_parent(struct clk_hw *hw, u8 index)
{
struct r9a06g032_clk_bitsel *set = to_clk_bitselect(hw);
/* a single bit in the register selects one of two parent clocks */
clk_rdesc_set(set->clocks, set->selector, !!index);
return 0;
}
static const struct clk_ops clk_bitselect_ops = {
.get_parent = r9a06g032_clk_mux_get_parent,
.set_parent = r9a06g032_clk_mux_set_parent,
};
static struct clk *
r9a06g032_register_bitsel(struct r9a06g032_priv *clocks,
const char *parent_name,
const struct r9a06g032_clkdesc *desc)
{
struct clk *clk;
struct r9a06g032_clk_bitsel *g;
struct clk_init_data init;
const char *names[2];
/* allocate the gate */
g = kzalloc(sizeof(*g), GFP_KERNEL);
if (!g)
return NULL;
names[0] = parent_name;
names[1] = "clk_pll_usb";
init.name = desc->name;
init.ops = &clk_bitselect_ops;
init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
init.parent_names = names;
init.num_parents = 2;
g->clocks = clocks;
g->index = desc->index;
g->selector = desc->dual.sel;
g->hw.init = &init;
clk = clk_register(NULL, &g->hw);
if (IS_ERR(clk)) {
kfree(g);
return NULL;
}
return clk;
}
struct r9a06g032_clk_dualgate {
struct clk_hw hw;
struct r9a06g032_priv *clocks;
u16 index;
u16 selector; /* selector register + bit */
struct r9a06g032_gate gate[2];
};
#define to_clk_dualgate(_hw) \
container_of(_hw, struct r9a06g032_clk_dualgate, hw)
static int
r9a06g032_clk_dualgate_setenable(struct r9a06g032_clk_dualgate *g, int enable)
{
u8 sel_bit = clk_rdesc_get(g->clocks, g->selector);
/* we always turn off the 'other' gate, regardless */
r9a06g032_clk_gate_set(g->clocks, &g->gate[!sel_bit], 0);
r9a06g032_clk_gate_set(g->clocks, &g->gate[sel_bit], enable);
return 0;
}
static int r9a06g032_clk_dualgate_enable(struct clk_hw *hw)
{
struct r9a06g032_clk_dualgate *gate = to_clk_dualgate(hw);
r9a06g032_clk_dualgate_setenable(gate, 1);
return 0;
}
static void r9a06g032_clk_dualgate_disable(struct clk_hw *hw)
{
struct r9a06g032_clk_dualgate *gate = to_clk_dualgate(hw);
r9a06g032_clk_dualgate_setenable(gate, 0);
}
static int r9a06g032_clk_dualgate_is_enabled(struct clk_hw *hw)
{
struct r9a06g032_clk_dualgate *g = to_clk_dualgate(hw);
u8 sel_bit = clk_rdesc_get(g->clocks, g->selector);
return clk_rdesc_get(g->clocks, g->gate[sel_bit].gate);
}
static const struct clk_ops r9a06g032_clk_dualgate_ops = {
.enable = r9a06g032_clk_dualgate_enable,
.disable = r9a06g032_clk_dualgate_disable,
.is_enabled = r9a06g032_clk_dualgate_is_enabled,
};
static struct clk *
r9a06g032_register_dualgate(struct r9a06g032_priv *clocks,
const char *parent_name,
const struct r9a06g032_clkdesc *desc,
uint16_t sel)
{
struct r9a06g032_clk_dualgate *g;
struct clk *clk;
struct clk_init_data init;
/* allocate the gate */
g = kzalloc(sizeof(*g), GFP_KERNEL);
if (!g)
return NULL;
g->clocks = clocks;
g->index = desc->index;
g->selector = sel;
g->gate[0].gate = desc->dual.g1;
g->gate[0].reset = desc->dual.r1;
g->gate[1].gate = desc->dual.g2;
g->gate[1].reset = desc->dual.r2;
init.name = desc->name;
init.ops = &r9a06g032_clk_dualgate_ops;
init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
init.parent_names = &parent_name;
init.num_parents = 1;
g->hw.init = &init;
/*
* important here, some clocks are already in use by the CM3, we
* have to assume they are not Linux's to play with and try to disable
* at the end of the boot!
*/
if (r9a06g032_clk_dualgate_is_enabled(&g->hw)) {
init.flags |= CLK_IS_CRITICAL;
pr_debug("%s was enabled, making read-only\n", desc->name);
}
clk = clk_register(NULL, &g->hw);
if (IS_ERR(clk)) {
kfree(g);
return NULL;
}
return clk;
}
static void r9a06g032_clocks_del_clk_provider(void *data)
{
of_clk_del_provider(data);
}
static int __init r9a06g032_clocks_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct r9a06g032_priv *clocks;
struct clk **clks;
struct clk *mclk;
unsigned int i;
u16 uart_group_sel[2];
int error;
clocks = devm_kzalloc(dev, sizeof(*clocks), GFP_KERNEL);
clks = devm_kcalloc(dev, R9A06G032_CLOCK_COUNT, sizeof(struct clk *),
GFP_KERNEL);
if (!clocks || !clks)
return -ENOMEM;
spin_lock_init(&clocks->lock);
clocks->data.clks = clks;
clocks->data.clk_num = R9A06G032_CLOCK_COUNT;
mclk = devm_clk_get(dev, "mclk");
if (IS_ERR(mclk))
return PTR_ERR(mclk);
clocks->reg = of_iomap(np, 0);
if (WARN_ON(!clocks->reg))
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(r9a06g032_clocks); ++i) {
const struct r9a06g032_clkdesc *d = &r9a06g032_clocks[i];
const char *parent_name = d->source ?
__clk_get_name(clocks->data.clks[d->source - 1]) :
__clk_get_name(mclk);
struct clk *clk = NULL;
switch (d->type) {
case K_FFC:
clk = clk_register_fixed_factor(NULL, d->name,
parent_name, 0,
d->mul, d->div);
break;
case K_GATE:
clk = r9a06g032_register_gate(clocks, parent_name, d);
break;
case K_DIV:
clk = r9a06g032_register_div(clocks, parent_name, d);
break;
case K_BITSEL:
/* keep that selector register around */
uart_group_sel[d->dual.group] = d->dual.sel;
clk = r9a06g032_register_bitsel(clocks, parent_name, d);
break;
case K_DUALGATE:
clk = r9a06g032_register_dualgate(clocks, parent_name,
d,
uart_group_sel[d->dual.group]);
break;
}
clocks->data.clks[d->index] = clk;
}
error = of_clk_add_provider(np, of_clk_src_onecell_get, &clocks->data);
if (error)
return error;
return devm_add_action_or_reset(dev,
r9a06g032_clocks_del_clk_provider, np);
}
static const struct of_device_id r9a06g032_match[] = {
{ .compatible = "renesas,r9a06g032-sysctrl" },
{ }
};
static struct platform_driver r9a06g032_clock_driver = {
.driver = {
.name = "renesas,r9a06g032-sysctrl",
.of_match_table = r9a06g032_match,
},
};
static int __init r9a06g032_clocks_init(void)
{
return platform_driver_probe(&r9a06g032_clock_driver,
r9a06g032_clocks_probe);
}
subsys_initcall(r9a06g032_clocks_init);

View File

@ -6,12 +6,14 @@
obj-y += clk.o
obj-y += clk-pll.o
obj-y += clk-cpu.o
obj-y += clk-half-divider.o
obj-y += clk-inverter.o
obj-y += clk-mmc-phase.o
obj-y += clk-muxgrf.o
obj-y += clk-ddr.o
obj-$(CONFIG_RESET_CONTROLLER) += softrst.o
obj-y += clk-px30.o
obj-y += clk-rv1108.o
obj-y += clk-rk3036.o
obj-y += clk-rk3128.o

View File

@ -0,0 +1,227 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
*/
#include <linux/slab.h>
#include <linux/clk-provider.h>
#include "clk.h"
#define div_mask(width) ((1 << (width)) - 1)
static bool _is_best_half_div(unsigned long rate, unsigned long now,
unsigned long best, unsigned long flags)
{
if (flags & CLK_DIVIDER_ROUND_CLOSEST)
return abs(rate - now) < abs(rate - best);
return now <= rate && now > best;
}
static unsigned long clk_half_divider_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_divider *divider = to_clk_divider(hw);
unsigned int val;
val = clk_readl(divider->reg) >> divider->shift;
val &= div_mask(divider->width);
val = val * 2 + 3;
return DIV_ROUND_UP_ULL(((u64)parent_rate * 2), val);
}
static int clk_half_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate, u8 width,
unsigned long flags)
{
unsigned int i, bestdiv = 0;
unsigned long parent_rate, best = 0, now, maxdiv;
unsigned long parent_rate_saved = *best_parent_rate;
if (!rate)
rate = 1;
maxdiv = div_mask(width);
if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
parent_rate = *best_parent_rate;
bestdiv = DIV_ROUND_UP_ULL(((u64)parent_rate * 2), rate);
if (bestdiv < 3)
bestdiv = 0;
else
bestdiv = (bestdiv - 3) / 2;
bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
return bestdiv;
}
/*
* The maximum divider we can use without overflowing
* unsigned long in rate * i below
*/
maxdiv = min(ULONG_MAX / rate, maxdiv);
for (i = 0; i <= maxdiv; i++) {
if (((u64)rate * (i * 2 + 3)) == ((u64)parent_rate_saved * 2)) {
/*
* It's the most ideal case if the requested rate can be
* divided from parent clock without needing to change
* parent rate, so return the divider immediately.
*/
*best_parent_rate = parent_rate_saved;
return i;
}
parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
((u64)rate * (i * 2 + 3)) / 2);
now = DIV_ROUND_UP_ULL(((u64)parent_rate * 2),
(i * 2 + 3));
if (_is_best_half_div(rate, now, best, flags)) {
bestdiv = i;
best = now;
*best_parent_rate = parent_rate;
}
}
if (!bestdiv) {
bestdiv = div_mask(width);
*best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), 1);
}
return bestdiv;
}
static long clk_half_divider_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_divider *divider = to_clk_divider(hw);
int div;
div = clk_half_divider_bestdiv(hw, rate, prate,
divider->width,
divider->flags);
return DIV_ROUND_UP_ULL(((u64)*prate * 2), div * 2 + 3);
}
static int clk_half_divider_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_divider *divider = to_clk_divider(hw);
unsigned int value;
unsigned long flags = 0;
u32 val;
value = DIV_ROUND_UP_ULL(((u64)parent_rate * 2), rate);
value = (value - 3) / 2;
value = min_t(unsigned int, value, div_mask(divider->width));
if (divider->lock)
spin_lock_irqsave(divider->lock, flags);
else
__acquire(divider->lock);
if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
val = div_mask(divider->width) << (divider->shift + 16);
} else {
val = clk_readl(divider->reg);
val &= ~(div_mask(divider->width) << divider->shift);
}
val |= value << divider->shift;
clk_writel(val, divider->reg);
if (divider->lock)
spin_unlock_irqrestore(divider->lock, flags);
else
__release(divider->lock);
return 0;
}
const struct clk_ops clk_half_divider_ops = {
.recalc_rate = clk_half_divider_recalc_rate,
.round_rate = clk_half_divider_round_rate,
.set_rate = clk_half_divider_set_rate,
};
EXPORT_SYMBOL_GPL(clk_half_divider_ops);
/**
* Register a clock branch.
* Most clock branches have a form like
*
* src1 --|--\
* |M |--[GATE]-[DIV]-
* src2 --|--/
*
* sometimes without one of those components.
*/
struct clk *rockchip_clk_register_halfdiv(const char *name,
const char *const *parent_names,
u8 num_parents, void __iomem *base,
int muxdiv_offset, u8 mux_shift,
u8 mux_width, u8 mux_flags,
u8 div_shift, u8 div_width,
u8 div_flags, int gate_offset,
u8 gate_shift, u8 gate_flags,
unsigned long flags,
spinlock_t *lock)
{
struct clk *clk;
struct clk_mux *mux = NULL;
struct clk_gate *gate = NULL;
struct clk_divider *div = NULL;
const struct clk_ops *mux_ops = NULL, *div_ops = NULL,
*gate_ops = NULL;
if (num_parents > 1) {
mux = kzalloc(sizeof(*mux), GFP_KERNEL);
if (!mux)
return ERR_PTR(-ENOMEM);
mux->reg = base + muxdiv_offset;
mux->shift = mux_shift;
mux->mask = BIT(mux_width) - 1;
mux->flags = mux_flags;
mux->lock = lock;
mux_ops = (mux_flags & CLK_MUX_READ_ONLY) ? &clk_mux_ro_ops
: &clk_mux_ops;
}
if (gate_offset >= 0) {
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
if (!gate)
goto err_gate;
gate->flags = gate_flags;
gate->reg = base + gate_offset;
gate->bit_idx = gate_shift;
gate->lock = lock;
gate_ops = &clk_gate_ops;
}
if (div_width > 0) {
div = kzalloc(sizeof(*div), GFP_KERNEL);
if (!div)
goto err_div;
div->flags = div_flags;
div->reg = base + muxdiv_offset;
div->shift = div_shift;
div->width = div_width;
div->lock = lock;
div_ops = &clk_half_divider_ops;
}
clk = clk_register_composite(NULL, name, parent_names, num_parents,
mux ? &mux->hw : NULL, mux_ops,
div ? &div->hw : NULL, div_ops,
gate ? &gate->hw : NULL, gate_ops,
flags);
return clk;
err_div:
kfree(gate);
err_gate:
kfree(mux);
return ERR_PTR(-ENOMEM);
}

File diff suppressed because it is too large Load Diff

View File

@ -631,7 +631,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
MUX(0, "clk_i2sout_src", mux_i2sch_p, CLK_SET_RATE_PARENT,
RK3399_CLKSEL_CON(31), 0, 2, MFLAGS),
COMPOSITE_NODIV(SCLK_I2S_8CH_OUT, "clk_i2sout", mux_i2sout_p, CLK_SET_RATE_PARENT,
RK3399_CLKSEL_CON(30), 8, 2, MFLAGS,
RK3399_CLKSEL_CON(31), 2, 1, MFLAGS,
RK3399_CLKGATE_CON(8), 12, GFLAGS),
/* uart */
@ -1523,6 +1523,7 @@ static const char *const rk3399_pmucru_critical_clocks[] __initconst = {
"pclk_pmu_src",
"fclk_cm0s_src_pmu",
"clk_timer_src_pmu",
"pclk_rkpwm_pmu",
};
static void __init rk3399_clk_init(struct device_node *np)

View File

@ -492,6 +492,16 @@ void __init rockchip_clk_register_branches(
list->gate_flags, flags, list->child,
&ctx->lock);
break;
case branch_half_divider:
clk = rockchip_clk_register_halfdiv(list->name,
list->parent_names, list->num_parents,
ctx->reg_base, list->muxdiv_offset,
list->mux_shift, list->mux_width,
list->mux_flags, list->div_shift,
list->div_width, list->div_flags,
list->gate_offset, list->gate_shift,
list->gate_flags, flags, &ctx->lock);
break;
case branch_gate:
flags |= CLK_SET_RATE_PARENT;

View File

@ -34,7 +34,46 @@ struct clk;
#define HIWORD_UPDATE(val, mask, shift) \
((val) << (shift) | (mask) << ((shift) + 16))
/* register positions shared by RV1108, RK2928, RK3036, RK3066, RK3188 and RK3228 */
/* register positions shared by PX30, RV1108, RK2928, RK3036, RK3066, RK3188 and RK3228 */
#define BOOST_PLL_H_CON(x) ((x) * 0x4)
#define BOOST_CLK_CON 0x0008
#define BOOST_BOOST_CON 0x000c
#define BOOST_SWITCH_CNT 0x0010
#define BOOST_HIGH_PERF_CNT0 0x0014
#define BOOST_HIGH_PERF_CNT1 0x0018
#define BOOST_STATIS_THRESHOLD 0x001c
#define BOOST_SHORT_SWITCH_CNT 0x0020
#define BOOST_SWITCH_THRESHOLD 0x0024
#define BOOST_FSM_STATUS 0x0028
#define BOOST_PLL_L_CON(x) ((x) * 0x4 + 0x2c)
#define BOOST_RECOVERY_MASK 0x1
#define BOOST_RECOVERY_SHIFT 1
#define BOOST_SW_CTRL_MASK 0x1
#define BOOST_SW_CTRL_SHIFT 2
#define BOOST_LOW_FREQ_EN_MASK 0x1
#define BOOST_LOW_FREQ_EN_SHIFT 3
#define BOOST_BUSY_STATE BIT(8)
#define PX30_PLL_CON(x) ((x) * 0x4)
#define PX30_CLKSEL_CON(x) ((x) * 0x4 + 0x100)
#define PX30_CLKGATE_CON(x) ((x) * 0x4 + 0x200)
#define PX30_GLB_SRST_FST 0xb8
#define PX30_GLB_SRST_SND 0xbc
#define PX30_SOFTRST_CON(x) ((x) * 0x4 + 0x300)
#define PX30_MODE_CON 0xa0
#define PX30_MISC_CON 0xa4
#define PX30_SDMMC_CON0 0x380
#define PX30_SDMMC_CON1 0x384
#define PX30_SDIO_CON0 0x388
#define PX30_SDIO_CON1 0x38c
#define PX30_EMMC_CON0 0x390
#define PX30_EMMC_CON1 0x394
#define PX30_PMU_PLL_CON(x) ((x) * 0x4)
#define PX30_PMU_CLKSEL_CON(x) ((x) * 0x4 + 0x40)
#define PX30_PMU_CLKGATE_CON(x) ((x) * 0x4 + 0x80)
#define PX30_PMU_MODE 0x0020
#define RV1108_PLL_CON(x) ((x) * 0x4)
#define RV1108_CLKSEL_CON(x) ((x) * 0x4 + 0x60)
#define RV1108_CLKGATE_CON(x) ((x) * 0x4 + 0x120)
@ -354,6 +393,7 @@ enum rockchip_clk_branch_type {
branch_inverter,
branch_factor,
branch_ddrclk,
branch_half_divider,
};
struct rockchip_clk_branch {
@ -684,6 +724,79 @@ struct rockchip_clk_branch {
.gate_flags = gf, \
}
#define COMPOSITE_HALFDIV(_id, cname, pnames, f, mo, ms, mw, mf, ds, dw,\
df, go, gs, gf) \
{ \
.id = _id, \
.branch_type = branch_half_divider, \
.name = cname, \
.parent_names = pnames, \
.num_parents = ARRAY_SIZE(pnames), \
.flags = f, \
.muxdiv_offset = mo, \
.mux_shift = ms, \
.mux_width = mw, \
.mux_flags = mf, \
.div_shift = ds, \
.div_width = dw, \
.div_flags = df, \
.gate_offset = go, \
.gate_shift = gs, \
.gate_flags = gf, \
}
#define COMPOSITE_NOGATE_HALFDIV(_id, cname, pnames, f, mo, ms, mw, mf, \
ds, dw, df) \
{ \
.id = _id, \
.branch_type = branch_half_divider, \
.name = cname, \
.parent_names = pnames, \
.num_parents = ARRAY_SIZE(pnames), \
.flags = f, \
.muxdiv_offset = mo, \
.mux_shift = ms, \
.mux_width = mw, \
.mux_flags = mf, \
.div_shift = ds, \
.div_width = dw, \
.div_flags = df, \
.gate_offset = -1, \
}
#define COMPOSITE_NOMUX_HALFDIV(_id, cname, pname, f, mo, ds, dw, df, \
go, gs, gf) \
{ \
.id = _id, \
.branch_type = branch_half_divider, \
.name = cname, \
.parent_names = (const char *[]){ pname }, \
.num_parents = 1, \
.flags = f, \
.muxdiv_offset = mo, \
.div_shift = ds, \
.div_width = dw, \
.div_flags = df, \
.gate_offset = go, \
.gate_shift = gs, \
.gate_flags = gf, \
}
#define DIV_HALF(_id, cname, pname, f, o, s, w, df) \
{ \
.id = _id, \
.branch_type = branch_half_divider, \
.name = cname, \
.parent_names = (const char *[]){ pname }, \
.num_parents = 1, \
.flags = f, \
.muxdiv_offset = o, \
.div_shift = s, \
.div_width = w, \
.div_flags = df, \
.gate_offset = -1, \
}
struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np,
void __iomem *base, unsigned long nr_clks);
void rockchip_clk_of_add_provider(struct device_node *np,
@ -708,6 +821,17 @@ void rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx,
#define ROCKCHIP_SOFTRST_HIWORD_MASK BIT(0)
struct clk *rockchip_clk_register_halfdiv(const char *name,
const char *const *parent_names,
u8 num_parents, void __iomem *base,
int muxdiv_offset, u8 mux_shift,
u8 mux_width, u8 mux_flags,
u8 div_shift, u8 div_width,
u8 div_flags, int gate_offset,
u8 gate_shift, u8 gate_flags,
unsigned long flags,
spinlock_t *lock);
#ifdef CONFIG_RESET_CONTROLLER
void rockchip_register_softrst(struct device_node *np,
unsigned int num_regs,

View File

@ -37,8 +37,6 @@ static const unsigned long exynos4x12_clk_isp_save[] __initconst = {
E4X12_GATE_ISP1,
};
PNAME(mout_user_aclk400_mcuisp_p4x12) = { "fin_pll", "div_aclk400_mcuisp", };
static struct samsung_div_clock exynos4x12_isp_div_clks[] = {
DIV(CLK_ISP_DIV_ISP0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3),
DIV(CLK_ISP_DIV_ISP1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3),

View File

@ -28,7 +28,7 @@ static const char * const emaca_free_mux[] = {"peri_emaca_clk", "boot_clk"};
static const char * const emacb_free_mux[] = {"peri_emacb_clk", "boot_clk"};
static const char * const emac_ptp_free_mux[] = {"peri_emac_ptp_clk", "boot_clk"};
static const char * const gpio_db_free_mux[] = {"peri_gpio_db_clk", "boot_clk"};
static const char * const sdmmc_free_mux[] = {"peri_sdmmc_clk", "boot_clk"};
static const char * const sdmmc_free_mux[] = {"main_sdmmc_clk", "boot_clk"};
static const char * const s2f_usr1_free_mux[] = {"peri_s2f_usr1_clk", "boot_clk"};
static const char * const psi_ref_free_mux[] = {"peri_psi_ref_clk", "boot_clk"};
static const char * const mpu_mux[] = { "mpu_free_clk", "boot_clk",};
@ -37,6 +37,11 @@ static const char * const s2f_usr0_mux[] = {"f2s_free_clk", "boot_clk"};
static const char * const emac_mux[] = {"emaca_free_clk", "emacb_free_clk"};
static const char * const noc_mux[] = {"noc_free_clk", "boot_clk"};
static const char * const mpu_free_mux[] = {"main_mpu_base_clk",
"peri_mpu_base_clk",
"osc1", "cb_intosc_hs_div2_clk",
"f2s_free_clk"};
/* clocks in AO (always on) controller */
static const struct stratix10_pll_clock s10_pll_clks[] = {
{ STRATIX10_BOOT_CLK, "boot_clk", boot_mux, ARRAY_SIZE(boot_mux), 0,
@ -57,7 +62,7 @@ static const struct stratix10_perip_c_clock s10_main_perip_c_clks[] = {
};
static const struct stratix10_perip_cnt_clock s10_main_perip_cnt_clks[] = {
{ STRATIX10_MPU_FREE_CLK, "mpu_free_clk", NULL, cntr_mux, ARRAY_SIZE(cntr_mux),
{ STRATIX10_MPU_FREE_CLK, "mpu_free_clk", NULL, mpu_free_mux, ARRAY_SIZE(mpu_free_mux),
0, 0x48, 0, 0, 0},
{ STRATIX10_NOC_FREE_CLK, "noc_free_clk", NULL, noc_free_mux, ARRAY_SIZE(noc_free_mux),
0, 0x4C, 0, 0, 0},

View File

@ -288,17 +288,14 @@ static const struct of_device_id sunxi_de2_clk_ids[] = {
.compatible = "allwinner,sun8i-v3s-de2-clk",
.data = &sun8i_v3s_de2_clk_desc,
},
{
.compatible = "allwinner,sun50i-a64-de2-clk",
.data = &sun50i_a64_de2_clk_desc,
},
{
.compatible = "allwinner,sun50i-h5-de2-clk",
.data = &sun50i_a64_de2_clk_desc,
},
/*
* The Allwinner A64 SoC needs some bit to be poke in syscon to make
* DE2 really working.
* So there's currently no A64 compatible here.
* H5 shares the same reset line with A64, so here H5 is using the
* clock description of A64.
*/
{ }
};

View File

@ -66,17 +66,18 @@ static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base",
CLK_SET_RATE_UNGATE);
/* TODO: The result of N/M is required to be in [8, 25] range. */
static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video0_clk, "pll-video0",
"osc24M", 0x0010,
8, 7, /* N */
0, 4, /* M */
BIT(24), /* frac enable */
BIT(25), /* frac select */
270000000, /* frac rate 0 */
297000000, /* frac rate 1 */
BIT(31), /* gate */
BIT(28), /* lock */
CLK_SET_RATE_UNGATE);
static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN(pll_video0_clk, "pll-video0",
"osc24M", 0x0010,
192000000, /* Minimum rate */
8, 7, /* N */
0, 4, /* M */
BIT(24), /* frac enable */
BIT(25), /* frac select */
270000000, /* frac rate 0 */
297000000, /* frac rate 1 */
BIT(31), /* gate */
BIT(28), /* lock */
CLK_SET_RATE_UNGATE);
/* TODO: The result of N/M is required to be in [8, 25] range. */
static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve",
@ -152,17 +153,18 @@ static struct ccu_nk pll_periph1_clk = {
};
/* TODO: The result of N/M is required to be in [8, 25] range. */
static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video1_clk, "pll-video1",
"osc24M", 0x030,
8, 7, /* N */
0, 4, /* M */
BIT(24), /* frac enable */
BIT(25), /* frac select */
270000000, /* frac rate 0 */
297000000, /* frac rate 1 */
BIT(31), /* gate */
BIT(28), /* lock */
CLK_SET_RATE_UNGATE);
static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN(pll_video1_clk, "pll-video1",
"osc24M", 0x030,
192000000, /* Minimum rate */
8, 7, /* N */
0, 4, /* M */
BIT(24), /* frac enable */
BIT(25), /* frac select */
270000000, /* frac rate 0 */
297000000, /* frac rate 1 */
BIT(31), /* gate */
BIT(28), /* lock */
CLK_SET_RATE_UNGATE);
static struct ccu_nkm pll_sata_clk = {
.enable = BIT(31),
@ -654,7 +656,8 @@ static SUNXI_CCU_GATE(dram_deinterlace_clk, "dram-deinterlace", "dram",
static const char * const de_parents[] = { "pll-periph0-2x", "pll-de" };
static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents,
0x104, 0, 4, 24, 3, BIT(31), 0);
0x104, 0, 4, 24, 3, BIT(31),
CLK_SET_RATE_PARENT);
static SUNXI_CCU_M_WITH_MUX_GATE(mp_clk, "mp", de_parents,
0x108, 0, 4, 24, 3, BIT(31), 0);
@ -666,9 +669,11 @@ static SUNXI_CCU_MUX_WITH_GATE(tcon_lcd0_clk, "tcon-lcd0", tcon_parents,
static SUNXI_CCU_MUX_WITH_GATE(tcon_lcd1_clk, "tcon-lcd1", tcon_parents,
0x114, 24, 3, BIT(31), CLK_SET_RATE_PARENT);
static SUNXI_CCU_M_WITH_MUX_GATE(tcon_tv0_clk, "tcon-tv0", tcon_parents,
0x118, 0, 4, 24, 3, BIT(31), 0);
0x118, 0, 4, 24, 3, BIT(31),
CLK_SET_RATE_PARENT);
static SUNXI_CCU_M_WITH_MUX_GATE(tcon_tv1_clk, "tcon-tv1", tcon_parents,
0x11c, 0, 4, 24, 3, BIT(31), 0);
0x11c, 0, 4, 24, 3, BIT(31),
CLK_SET_RATE_PARENT);
static const char * const deinterlace_parents[] = { "pll-periph0",
"pll-periph1" };
@ -698,7 +703,8 @@ static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M",
static const char * const hdmi_parents[] = { "pll-video0", "pll-video1" };
static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents,
0x150, 0, 4, 24, 2, BIT(31), 0);
0x150, 0, 4, 24, 2, BIT(31),
CLK_SET_RATE_PARENT);
static SUNXI_CCU_GATE(hdmi_slow_clk, "hdmi-slow", "osc24M",
0x154, BIT(31), 0);

View File

@ -25,7 +25,9 @@
#define CLK_PLL_AUDIO_2X 4
#define CLK_PLL_AUDIO_4X 5
#define CLK_PLL_AUDIO_8X 6
#define CLK_PLL_VIDEO0 7
/* PLL_VIDEO0 is exported */
#define CLK_PLL_VIDEO0_2X 8
#define CLK_PLL_VE 9
#define CLK_PLL_DDR0 10
@ -34,7 +36,9 @@
#define CLK_PLL_PERIPH0_2X 13
#define CLK_PLL_PERIPH1 14
#define CLK_PLL_PERIPH1_2X 15
#define CLK_PLL_VIDEO1 16
/* PLL_VIDEO1 is exported */
#define CLK_PLL_VIDEO1_2X 17
#define CLK_PLL_SATA 18
#define CLK_PLL_SATA_OUT 19

View File

@ -8,6 +8,7 @@ obj-y += clk-periph-fixed.o
obj-y += clk-periph-gate.o
obj-y += clk-pll.o
obj-y += clk-pll-out.o
obj-y += clk-sdmmc-mux.o
obj-y += clk-super.o
obj-y += clk-tegra-audio.o
obj-y += clk-tegra-periph.o
@ -24,3 +25,4 @@ obj-$(CONFIG_ARCH_TEGRA_132_SOC) += clk-tegra124.o
obj-y += cvb.o
obj-$(CONFIG_ARCH_TEGRA_210_SOC) += clk-tegra210.o
obj-$(CONFIG_CLK_TEGRA_BPMP) += clk-bpmp.o
obj-y += clk-utils.o

View File

@ -586,9 +586,15 @@ static struct clk_hw *tegra_bpmp_clk_of_xlate(struct of_phandle_args *clkspec,
unsigned int id = clkspec->args[0], i;
struct tegra_bpmp *bpmp = data;
for (i = 0; i < bpmp->num_clocks; i++)
if (bpmp->clocks[i]->id == id)
return &bpmp->clocks[i]->hw;
for (i = 0; i < bpmp->num_clocks; i++) {
struct tegra_bpmp_clk *clk = bpmp->clocks[i];
if (!clk)
continue;
if (clk->id == id)
return &clk->hw;
}
return NULL;
}

View File

@ -32,35 +32,15 @@
static int get_div(struct tegra_clk_frac_div *divider, unsigned long rate,
unsigned long parent_rate)
{
u64 divider_ux1 = parent_rate;
u8 flags = divider->flags;
int mul;
int div;
if (!rate)
div = div_frac_get(rate, parent_rate, divider->width,
divider->frac_width, divider->flags);
if (div < 0)
return 0;
mul = get_mul(divider);
if (!(flags & TEGRA_DIVIDER_INT))
divider_ux1 *= mul;
if (flags & TEGRA_DIVIDER_ROUND_UP)
divider_ux1 += rate - 1;
do_div(divider_ux1, rate);
if (flags & TEGRA_DIVIDER_INT)
divider_ux1 *= mul;
divider_ux1 -= mul;
if ((s64)divider_ux1 < 0)
return 0;
if (divider_ux1 > get_max_div(divider))
return get_max_div(divider);
return divider_ux1;
return div;
}
static unsigned long clk_frac_div_recalc_rate(struct clk_hw *hw,
@ -194,6 +174,7 @@ static const struct clk_div_table mc_div_table[] = {
struct clk *tegra_clk_register_mc(const char *name, const char *parent_name,
void __iomem *reg, spinlock_t *lock)
{
return clk_register_divider_table(NULL, name, parent_name, 0, reg,
16, 1, 0, mc_div_table, lock);
return clk_register_divider_table(NULL, name, parent_name,
CLK_IS_CRITICAL, reg, 16, 1, 0,
mc_div_table, lock);
}

View File

@ -132,7 +132,7 @@ static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
timing = tegra->timings + i;
if (timing->rate > req->max_rate) {
i = min(i, 1);
i = max(i, 1);
req->rate = tegra->timings[i - 1].rate;
return 0;
}

View File

@ -227,13 +227,11 @@ enum clk_id {
tegra_clk_sdmmc1_9,
tegra_clk_sdmmc2,
tegra_clk_sdmmc2_8,
tegra_clk_sdmmc2_9,
tegra_clk_sdmmc3,
tegra_clk_sdmmc3_8,
tegra_clk_sdmmc3_9,
tegra_clk_sdmmc4,
tegra_clk_sdmmc4_8,
tegra_clk_sdmmc4_9,
tegra_clk_se,
tegra_clk_soc_therm,
tegra_clk_soc_therm_8,

Some files were not shown because too many files have changed in this diff Show More