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:
Коммит
d16adaf0b9
|
@ -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>;
|
||||
};
|
|
@ -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>;
|
||||
};
|
|
@ -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]);
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
};
|
|
@ -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);
|
|
@ -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);
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
|
@ -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 --| | | | | | ______
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
Загрузка…
Ссылка в новой задаче