Merge branches 'clk-mvebu-spdx', 'clk-meson', 'clk-imx7d-mu', 'clk-imx-init-array-cleanup' and 'clk-rockchip' into clk-next

* clk-mvebu-spdx:
  clk: mvebu: armada-37xx-periph: switch to SPDX license identifier

* clk-meson:
  clk: meson: add gen_clk
  clk: meson: gxbb: remove HHI_GEN_CLK_CTNL duplicate definition
  clk: meson-axg: add clocks required by pcie driver
  clk: meson: remove unused clk-audio-divider driver
  clk: meson: stop rate propagation for audio clocks
  clk: meson: axg: add the audio clock controller driver
  clk: meson: add axg audio sclk divider driver
  clk: meson: add triple phase clock driver
  clk: meson: add clk-phase clock driver
  clk: meson: clean-up meson clock configuration
  clk: meson: remove obsolete register access
  clk: meson: expose GEN_CLK clkid
  clk: meson-axg: add pcie and mipi clock bindings
  dt-bindings: clock: add meson axg audio clock controller bindings
  clk: meson: audio-divider is one based
  clk: meson-gxbb: set fclk_div2 as CLK_IS_CRITICAL

* clk-imx7d-mu:
  :  - i.MX7D mailbox clk support
  clk: imx7d: add IMX7D_MU_ROOT_CLK

* clk-imx-init-array-cleanup:
  :  - i.MX clk init arrays removed in place of CLK_IS_CRITICAL
  clk: imx6sx: remove clks_init_on array
  clk: imx6sl: remove clks_init_on array
  clk: imx6q: remove clks_init_on array

* clk-rockchip:
  clk: rockchip: Add pclk_rkpwm_pmu to PMU critical clocks in rk3399
  clk: rockchip: fix clk_i2sout parent selection bits on rk3399
  clk: rockchip: add clock controller for px30
  clk: rockchip: add support for half divider
  dt-bindings: add bindings for px30 clock controller
  clk: rockchip: add dt-binding header for px30
This commit is contained in:
Stephen Boyd 2018-08-14 22:58:45 -07:00
31 changed files with 3729 additions and 262 deletions

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

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

@ -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,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,7 +398,7 @@ 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);
@ -420,10 +411,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 +428,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 +447,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 +493,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

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

@ -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);
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>
@ -498,6 +497,7 @@ static struct clk_regmap gxbb_fclk_div2 = {
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "fclk_div2_div" },
.num_parents = 1,
.flags = CLK_IS_CRITICAL,
},
};
@ -970,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,
@ -1018,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,
},
};
@ -1626,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);
@ -1875,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,
@ -2037,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,
@ -2201,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 {
@ -2227,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;
@ -2249,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 --| | | | | | ______

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

@ -0,0 +1,94 @@
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
/*
* Copyright (c) 2018 Baylibre SAS.
* Author: Jerome Brunet <jbrunet@baylibre.com>
*/
#ifndef __AXG_AUDIO_CLKC_BINDINGS_H
#define __AXG_AUDIO_CLKC_BINDINGS_H
#define AUD_CLKID_SLV_SCLK0 9
#define AUD_CLKID_SLV_SCLK1 10
#define AUD_CLKID_SLV_SCLK2 11
#define AUD_CLKID_SLV_SCLK3 12
#define AUD_CLKID_SLV_SCLK4 13
#define AUD_CLKID_SLV_SCLK5 14
#define AUD_CLKID_SLV_SCLK6 15
#define AUD_CLKID_SLV_SCLK7 16
#define AUD_CLKID_SLV_SCLK8 17
#define AUD_CLKID_SLV_SCLK9 18
#define AUD_CLKID_SLV_LRCLK0 19
#define AUD_CLKID_SLV_LRCLK1 20
#define AUD_CLKID_SLV_LRCLK2 21
#define AUD_CLKID_SLV_LRCLK3 22
#define AUD_CLKID_SLV_LRCLK4 23
#define AUD_CLKID_SLV_LRCLK5 24
#define AUD_CLKID_SLV_LRCLK6 25
#define AUD_CLKID_SLV_LRCLK7 26
#define AUD_CLKID_SLV_LRCLK8 27
#define AUD_CLKID_SLV_LRCLK9 28
#define AUD_CLKID_DDR_ARB 29
#define AUD_CLKID_PDM 30
#define AUD_CLKID_TDMIN_A 31
#define AUD_CLKID_TDMIN_B 32
#define AUD_CLKID_TDMIN_C 33
#define AUD_CLKID_TDMIN_LB 34
#define AUD_CLKID_TDMOUT_A 35
#define AUD_CLKID_TDMOUT_B 36
#define AUD_CLKID_TDMOUT_C 37
#define AUD_CLKID_FRDDR_A 38
#define AUD_CLKID_FRDDR_B 39
#define AUD_CLKID_FRDDR_C 40
#define AUD_CLKID_TODDR_A 41
#define AUD_CLKID_TODDR_B 42
#define AUD_CLKID_TODDR_C 43
#define AUD_CLKID_LOOPBACK 44
#define AUD_CLKID_SPDIFIN 45
#define AUD_CLKID_SPDIFOUT 46
#define AUD_CLKID_RESAMPLE 47
#define AUD_CLKID_POWER_DETECT 48
#define AUD_CLKID_MST_A_MCLK 49
#define AUD_CLKID_MST_B_MCLK 50
#define AUD_CLKID_MST_C_MCLK 51
#define AUD_CLKID_MST_D_MCLK 52
#define AUD_CLKID_MST_E_MCLK 53
#define AUD_CLKID_MST_F_MCLK 54
#define AUD_CLKID_SPDIFOUT_CLK 55
#define AUD_CLKID_SPDIFIN_CLK 56
#define AUD_CLKID_PDM_DCLK 57
#define AUD_CLKID_PDM_SYSCLK 58
#define AUD_CLKID_MST_A_SCLK 79
#define AUD_CLKID_MST_B_SCLK 80
#define AUD_CLKID_MST_C_SCLK 81
#define AUD_CLKID_MST_D_SCLK 82
#define AUD_CLKID_MST_E_SCLK 83
#define AUD_CLKID_MST_F_SCLK 84
#define AUD_CLKID_MST_A_LRCLK 86
#define AUD_CLKID_MST_B_LRCLK 87
#define AUD_CLKID_MST_C_LRCLK 88
#define AUD_CLKID_MST_D_LRCLK 89
#define AUD_CLKID_MST_E_LRCLK 90
#define AUD_CLKID_MST_F_LRCLK 91
#define AUD_CLKID_TDMIN_A_SCLK_SEL 116
#define AUD_CLKID_TDMIN_B_SCLK_SEL 117
#define AUD_CLKID_TDMIN_C_SCLK_SEL 118
#define AUD_CLKID_TDMIN_LB_SCLK_SEL 119
#define AUD_CLKID_TDMOUT_A_SCLK_SEL 120
#define AUD_CLKID_TDMOUT_B_SCLK_SEL 121
#define AUD_CLKID_TDMOUT_C_SCLK_SEL 122
#define AUD_CLKID_TDMIN_A_SCLK 123
#define AUD_CLKID_TDMIN_B_SCLK 124
#define AUD_CLKID_TDMIN_C_SCLK 125
#define AUD_CLKID_TDMIN_LB_SCLK 126
#define AUD_CLKID_TDMOUT_A_SCLK 127
#define AUD_CLKID_TDMOUT_B_SCLK 128
#define AUD_CLKID_TDMOUT_C_SCLK 129
#define AUD_CLKID_TDMIN_A_LRCLK 130
#define AUD_CLKID_TDMIN_B_LRCLK 131
#define AUD_CLKID_TDMIN_C_LRCLK 132
#define AUD_CLKID_TDMIN_LB_LRCLK 133
#define AUD_CLKID_TDMOUT_A_LRCLK 134
#define AUD_CLKID_TDMOUT_B_LRCLK 135
#define AUD_CLKID_TDMOUT_C_LRCLK 136
#endif /* __AXG_AUDIO_CLKC_BINDINGS_H */

View file

@ -68,5 +68,9 @@
#define CLKID_SD_EMMC_B_CLK0 59
#define CLKID_SD_EMMC_C_CLK0 60
#define CLKID_HIFI_PLL 69
#define CLKID_PCIE_CML_EN0 79
#define CLKID_PCIE_CML_EN1 80
#define CLKID_MIPI_ENABLE 81
#define CLKID_GEN_CLK 84
#endif /* __AXG_CLKC_H */

View file

@ -127,5 +127,6 @@
#define CLKID_VAPB 140
#define CLKID_VDEC_1 153
#define CLKID_VDEC_HEVC 156
#define CLKID_GEN_CLK 159
#endif /* __GXBB_CLKC_H */

View file

@ -0,0 +1,389 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _DT_BINDINGS_CLK_ROCKCHIP_PX30_H
#define _DT_BINDINGS_CLK_ROCKCHIP_PX30_H
/* core clocks */
#define PLL_APLL 1
#define PLL_DPLL 2
#define PLL_CPLL 3
#define PLL_NPLL 4
#define APLL_BOOST_H 5
#define APLL_BOOST_L 6
#define ARMCLK 7
/* sclk gates (special clocks) */
#define USB480M 14
#define SCLK_PDM 15
#define SCLK_I2S0_TX 16
#define SCLK_I2S0_TX_OUT 17
#define SCLK_I2S0_RX 18
#define SCLK_I2S0_RX_OUT 19
#define SCLK_I2S1 20
#define SCLK_I2S1_OUT 21
#define SCLK_I2S2 22
#define SCLK_I2S2_OUT 23
#define SCLK_UART1 24
#define SCLK_UART2 25
#define SCLK_UART3 26
#define SCLK_UART4 27
#define SCLK_UART5 28
#define SCLK_I2C0 29
#define SCLK_I2C1 30
#define SCLK_I2C2 31
#define SCLK_I2C3 32
#define SCLK_I2C4 33
#define SCLK_PWM0 34
#define SCLK_PWM1 35
#define SCLK_SPI0 36
#define SCLK_SPI1 37
#define SCLK_TIMER0 38
#define SCLK_TIMER1 39
#define SCLK_TIMER2 40
#define SCLK_TIMER3 41
#define SCLK_TIMER4 42
#define SCLK_TIMER5 43
#define SCLK_TSADC 44
#define SCLK_SARADC 45
#define SCLK_OTP 46
#define SCLK_OTP_USR 47
#define SCLK_CRYPTO 48
#define SCLK_CRYPTO_APK 49
#define SCLK_DDRC 50
#define SCLK_ISP 51
#define SCLK_CIF_OUT 52
#define SCLK_RGA_CORE 53
#define SCLK_VOPB_PWM 54
#define SCLK_NANDC 55
#define SCLK_SDIO 56
#define SCLK_EMMC 57
#define SCLK_SFC 58
#define SCLK_SDMMC 59
#define SCLK_OTG_ADP 60
#define SCLK_GMAC_SRC 61
#define SCLK_GMAC 62
#define SCLK_GMAC_RX_TX 63
#define SCLK_MAC_REF 64
#define SCLK_MAC_REFOUT 65
#define SCLK_MAC_OUT 66
#define SCLK_SDMMC_DRV 67
#define SCLK_SDMMC_SAMPLE 68
#define SCLK_SDIO_DRV 69
#define SCLK_SDIO_SAMPLE 70
#define SCLK_EMMC_DRV 71
#define SCLK_EMMC_SAMPLE 72
#define SCLK_GPU 73
#define SCLK_PVTM 74
#define SCLK_CORE_VPU 75
#define SCLK_GMAC_RMII 76
#define SCLK_UART2_SRC 77
#define SCLK_NANDC_DIV 78
#define SCLK_NANDC_DIV50 79
#define SCLK_SDIO_DIV 80
#define SCLK_SDIO_DIV50 81
#define SCLK_EMMC_DIV 82
#define SCLK_EMMC_DIV50 83
#define SCLK_DDRCLK 84
#define SCLK_UART1_SRC 85
/* dclk gates */
#define DCLK_VOPB 150
#define DCLK_VOPL 151
/* aclk gates */
#define ACLK_GPU 170
#define ACLK_BUS_PRE 171
#define ACLK_CRYPTO 172
#define ACLK_VI_PRE 173
#define ACLK_VO_PRE 174
#define ACLK_VPU 175
#define ACLK_PERI_PRE 176
#define ACLK_GMAC 178
#define ACLK_CIF 179
#define ACLK_ISP 180
#define ACLK_VOPB 181
#define ACLK_VOPL 182
#define ACLK_RGA 183
#define ACLK_GIC 184
#define ACLK_DCF 186
#define ACLK_DMAC 187
#define ACLK_BUS_SRC 188
#define ACLK_PERI_SRC 189
/* hclk gates */
#define HCLK_BUS_PRE 240
#define HCLK_CRYPTO 241
#define HCLK_VI_PRE 242
#define HCLK_VO_PRE 243
#define HCLK_VPU 244
#define HCLK_PERI_PRE 245
#define HCLK_MMC_NAND 246
#define HCLK_SDMMC 247
#define HCLK_USB 248
#define HCLK_CIF 249
#define HCLK_ISP 250
#define HCLK_VOPB 251
#define HCLK_VOPL 252
#define HCLK_RGA 253
#define HCLK_NANDC 254
#define HCLK_SDIO 255
#define HCLK_EMMC 256
#define HCLK_SFC 257
#define HCLK_OTG 258
#define HCLK_HOST 259
#define HCLK_HOST_ARB 260
#define HCLK_PDM 261
#define HCLK_I2S0 262
#define HCLK_I2S1 263
#define HCLK_I2S2 264
/* pclk gates */
#define PCLK_BUS_PRE 320
#define PCLK_DDR 321
#define PCLK_VO_PRE 322
#define PCLK_GMAC 323
#define PCLK_MIPI_DSI 324
#define PCLK_MIPIDSIPHY 325
#define PCLK_MIPICSIPHY 326
#define PCLK_USB_GRF 327
#define PCLK_DCF 328
#define PCLK_UART1 329
#define PCLK_UART2 330
#define PCLK_UART3 331
#define PCLK_UART4 332
#define PCLK_UART5 333
#define PCLK_I2C0 334
#define PCLK_I2C1 335
#define PCLK_I2C2 336
#define PCLK_I2C3 337
#define PCLK_I2C4 338
#define PCLK_PWM0 339
#define PCLK_PWM1 340
#define PCLK_SPI0 341
#define PCLK_SPI1 342
#define PCLK_SARADC 343
#define PCLK_TSADC 344
#define PCLK_TIMER 345
#define PCLK_OTP_NS 346
#define PCLK_WDT_NS 347
#define PCLK_GPIO1 348
#define PCLK_GPIO2 349
#define PCLK_GPIO3 350
#define PCLK_ISP 351
#define PCLK_CIF 352
#define PCLK_OTP_PHY 353
#define CLK_NR_CLKS (PCLK_OTP_PHY + 1)
/* pmu-clocks indices */
#define PLL_GPLL 1
#define SCLK_RTC32K_PMU 4
#define SCLK_WIFI_PMU 5
#define SCLK_UART0_PMU 6
#define SCLK_PVTM_PMU 7
#define PCLK_PMU_PRE 8
#define SCLK_REF24M_PMU 9
#define SCLK_USBPHY_REF 10
#define SCLK_MIPIDSIPHY_REF 11
#define XIN24M_DIV 12
#define PCLK_GPIO0_PMU 20
#define PCLK_UART0_PMU 21
#define CLKPMU_NR_CLKS (PCLK_UART0_PMU + 1)
/* soft-reset indices */
#define SRST_CORE0_PO 0
#define SRST_CORE1_PO 1
#define SRST_CORE2_PO 2
#define SRST_CORE3_PO 3
#define SRST_CORE0 4
#define SRST_CORE1 5
#define SRST_CORE2 6
#define SRST_CORE3 7
#define SRST_CORE0_DBG 8
#define SRST_CORE1_DBG 9
#define SRST_CORE2_DBG 10
#define SRST_CORE3_DBG 11
#define SRST_TOPDBG 12
#define SRST_CORE_NOC 13
#define SRST_STRC_A 14
#define SRST_L2C 15
#define SRST_DAP 16
#define SRST_CORE_PVTM 17
#define SRST_GPU 18
#define SRST_GPU_NIU 19
#define SRST_UPCTL2 20
#define SRST_UPCTL2_A 21
#define SRST_UPCTL2_P 22
#define SRST_MSCH 23
#define SRST_MSCH_P 24
#define SRST_DDRMON_P 25
#define SRST_DDRSTDBY_P 26
#define SRST_DDRSTDBY 27
#define SRST_DDRGRF_p 28
#define SRST_AXI_SPLIT_A 29
#define SRST_AXI_CMD_A 30
#define SRST_AXI_CMD_P 31
#define SRST_DDRPHY 32
#define SRST_DDRPHYDIV 33
#define SRST_DDRPHY_P 34
#define SRST_VPU_A 36
#define SRST_VPU_NIU_A 37
#define SRST_VPU_H 38
#define SRST_VPU_NIU_H 39
#define SRST_VI_NIU_A 40
#define SRST_VI_NIU_H 41
#define SRST_ISP_H 42
#define SRST_ISP 43
#define SRST_CIF_A 44
#define SRST_CIF_H 45
#define SRST_CIF_PCLKIN 46
#define SRST_MIPICSIPHY_P 47
#define SRST_VO_NIU_A 48
#define SRST_VO_NIU_H 49
#define SRST_VO_NIU_P 50
#define SRST_VOPB_A 51
#define SRST_VOPB_H 52
#define SRST_VOPB 53
#define SRST_PWM_VOPB 54
#define SRST_VOPL_A 55
#define SRST_VOPL_H 56
#define SRST_VOPL 57
#define SRST_RGA_A 58
#define SRST_RGA_H 59
#define SRST_RGA 60
#define SRST_MIPIDSI_HOST_P 61
#define SRST_MIPIDSIPHY_P 62
#define SRST_VPU_CORE 63
#define SRST_PERI_NIU_A 64
#define SRST_USB_NIU_H 65
#define SRST_USB2OTG_H 66
#define SRST_USB2OTG 67
#define SRST_USB2OTG_ADP 68
#define SRST_USB2HOST_H 69
#define SRST_USB2HOST_ARB_H 70
#define SRST_USB2HOST_AUX_H 71
#define SRST_USB2HOST_EHCI 72
#define SRST_USB2HOST 73
#define SRST_USBPHYPOR 74
#define SRST_USBPHY_OTG_PORT 75
#define SRST_USBPHY_HOST_PORT 76
#define SRST_USBPHY_GRF 77
#define SRST_CPU_BOOST_P 78
#define SRST_CPU_BOOST 79
#define SRST_MMC_NAND_NIU_H 80
#define SRST_SDIO_H 81
#define SRST_EMMC_H 82
#define SRST_SFC_H 83
#define SRST_SFC 84
#define SRST_SDCARD_NIU_H 85
#define SRST_SDMMC_H 86
#define SRST_NANDC_H 89
#define SRST_NANDC 90
#define SRST_GMAC_NIU_A 92
#define SRST_GMAC_NIU_P 93
#define SRST_GMAC_A 94
#define SRST_PMU_NIU_P 96
#define SRST_PMU_SGRF_P 97
#define SRST_PMU_GRF_P 98
#define SRST_PMU 99
#define SRST_PMU_MEM_P 100
#define SRST_PMU_GPIO0_P 101
#define SRST_PMU_UART0_P 102
#define SRST_PMU_CRU_P 103
#define SRST_PMU_PVTM 104
#define SRST_PMU_UART 105
#define SRST_PMU_NIU_H 106
#define SRST_PMU_DDR_FAIL_SAVE 107
#define SRST_PMU_CORE_PERF_A 108
#define SRST_PMU_CORE_GRF_P 109
#define SRST_PMU_GPU_PERF_A 110
#define SRST_PMU_GPU_GRF_P 111
#define SRST_CRYPTO_NIU_A 112
#define SRST_CRYPTO_NIU_H 113
#define SRST_CRYPTO_A 114
#define SRST_CRYPTO_H 115
#define SRST_CRYPTO 116
#define SRST_CRYPTO_APK 117
#define SRST_BUS_NIU_H 120
#define SRST_USB_NIU_P 121
#define SRST_BUS_TOP_NIU_P 122
#define SRST_INTMEM_A 123
#define SRST_GIC_A 124
#define SRST_ROM_H 126
#define SRST_DCF_A 127
#define SRST_DCF_P 128
#define SRST_PDM_H 129
#define SRST_PDM 130
#define SRST_I2S0_H 131
#define SRST_I2S0_TX 132
#define SRST_I2S1_H 133
#define SRST_I2S1 134
#define SRST_I2S2_H 135
#define SRST_I2S2 136
#define SRST_UART1_P 137
#define SRST_UART1 138
#define SRST_UART2_P 139
#define SRST_UART2 140
#define SRST_UART3_P 141
#define SRST_UART3 142
#define SRST_UART4_P 143
#define SRST_UART4 144
#define SRST_UART5_P 145
#define SRST_UART5 146
#define SRST_I2C0_P 147
#define SRST_I2C0 148
#define SRST_I2C1_P 149
#define SRST_I2C1 150
#define SRST_I2C2_P 151
#define SRST_I2C2 152
#define SRST_I2C3_P 153
#define SRST_I2C3 154
#define SRST_PWM0_P 157
#define SRST_PWM0 158
#define SRST_PWM1_P 159
#define SRST_PWM1 160
#define SRST_SPI0_P 161
#define SRST_SPI0 162
#define SRST_SPI1_P 163
#define SRST_SPI1 164
#define SRST_SARADC_P 165
#define SRST_SARADC 166
#define SRST_TSADC_P 167
#define SRST_TSADC 168
#define SRST_TIMER_P 169
#define SRST_TIMER0 170
#define SRST_TIMER1 171
#define SRST_TIMER2 172
#define SRST_TIMER3 173
#define SRST_TIMER4 174
#define SRST_TIMER5 175
#define SRST_OTP_NS_P 176
#define SRST_OTP_NS_SBPI 177
#define SRST_OTP_NS_USR 178
#define SRST_OTP_PHY_P 179
#define SRST_OTP_PHY 180
#define SRST_WDT_NS_P 181
#define SRST_GPIO1_P 182
#define SRST_GPIO2_P 183
#define SRST_GPIO3_P 184
#define SRST_SGRF_P 185
#define SRST_GRF_P 186
#define SRST_I2S0_RX 191
#endif