i.MX clocks changes for 6.6
- Add the PDM IPC clock for i.MX93 - Add 519.75MHz frequency support for i.MX9 PLL - Simplify the .determine_rate() for GPR mux - Make the i.MX8QXP LPCG clock use devm_platform_ioremap_resource - Add the audio mux clock to i.MX8 - Fix the SPLL2 MULT range for PLLv4 - Update the SPLL2 type in i.MX8ULP - Fix the SAI4 clock on i.MX8MP - Add silicon revision print for i.MX25 on clocks init - Drop the return value from __mx25_clocks_init - Fix the clock pauses on no-op set_rate for i.MX8M composite clock - Drop restrictions for PLL14xx and fix its max prediv value - Drop the 393216000 and 361267200 from PLL14xx rate table to allow glitch free switching -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEdRlgxHYCb3ovKt456LNSLBEEo7YFAmTcn0MACgkQ6LNSLBEE o7ZySQ//TTMsTMXwWkFQsV+4Q2x0wq6NyM+X2ajcRk+EVgT5Dv8SAYXtpP7ActWX AN5XX0zM/tXZQedzbV1ERm4EDGoff1CeAPa5G3Alms3q5gookHwun93ehf7sObeM JPWIyU/UzC4x7CgyL7gQaCpm/9RMlNiMg2QvbhabxMsH89qm2jUx11EeoQkexLKk 2kP+hBQ1/3CQxNJyHtbrbyl+nBWddASiK5zZTf6ualA+tbJAJES7s1/ZB+WX9/A5 QptiFnY5TobZsTiGA+OGRQBLjP0IR+edchOR523uFfwEnZkISi/7KXqPNqtjkzCc nEjopMAwven1NA2OAqP/HWYLncL5yF75KMtLgaA55glYFvts+wuYqwq21oD7IEMX FpynaXcOs+loTWHbp7PDgEEX0dENhnWcn48RAVrYQW9stBJpyeSL3ULF/+kJ+OeF FnBY3rtmzorDGCF3fznGDsDk9gQOwAmdYPlDIDgvQDlTvhJy2M2rS8VJe34J7YNU IgwkM0MFyxNPi5Fd+Yl/5TRmJHsc2wG4Ezci3lLVjlw0+eEnLncNtHjBtxTx9vEf q+kigNL/YZfm890oNSxGzQWzf83c4l9z0uFh76aTXAzClW1FbvcpuhyWxO+CcEHg Mv4BB3PXEye5llYReRlBQo3Wy7LbasS/OXX4FQ5wsWl9t3X8YMI= =RcQs -----END PGP SIGNATURE----- Merge tag 'clk-imx-6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/abelvesa/linux into clk-imx Pull i.MX clk driver updates from Abel Vesa: - Add the PDM IPC clock for i.MX93 - Add 519.75MHz frequency support for i.MX9 PLL - Simplify the .determine_rate() for GPR mux - Make the i.MX8QXP LPCG clock use devm_platform_ioremap_resource - Add the audio mux clock to i.MX8 - Fix the SPLL2 MULT range for PLLv4 - Update the SPLL2 type in i.MX8ULP - Fix the SAI4 clock on i.MX8MP - Add silicon revision print for i.MX25 on clocks init - Drop the return value from __mx25_clocks_init - Fix the clock pauses on no-op set_rate for i.MX8M composite clock - Drop restrictions for PLL14xx and fix its max prediv value - Drop the 393216000 and 361267200 from PLL14xx rate table to allow glitch free switching * tag 'clk-imx-6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/abelvesa/linux: clk: imx: pll14xx: dynamically configure PLL for 393216000/361267200Hz clk: imx: pll14xx: align pdiv with reference manual clk: imx: composite-8m: fix clock pauses when set_rate would be a no-op clk: imx25: make __mx25_clocks_init return void clk: imx25: print silicon revision during init dt-bindings: clocks: imx8mp: make sai4 a dummy clock clk: imx8mp: fix sai4 clock clk: imx: imx8ulp: update SPLL2 type clk: imx: pllv4: Fix SPLL2 MULT range clk: imx: imx8: add audio clock mux driver dt-bindings: clock: fsl,imx8-acm: Add audio clock mux support clk: imx: clk-imx8qxp-lpcg: Convert to devm_platform_ioremap_resource() clk: imx: clk-gpr-mux: Simplify .determine_rate() clk: imx: Add 519.75MHz frequency support for imx9 pll clk: imx93: Add PDM IPG clk dt-bindings: clock: imx93: Add PDM IPG clk
This commit is contained in:
commit
960535d54f
282
Documentation/devicetree/bindings/clock/fsl,imx8-acm.yaml
Normal file
282
Documentation/devicetree/bindings/clock/fsl,imx8-acm.yaml
Normal file
@ -0,0 +1,282 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/fsl,imx8-acm.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NXP i.MX8 Audio Clock Mux
|
||||
|
||||
maintainers:
|
||||
- Shengjiu Wang <shengjiu.wang@nxp.com>
|
||||
|
||||
description: |
|
||||
NXP i.MX8 Audio Clock Mux is dedicated clock muxing IP
|
||||
used to control Audio related clock on the SoC.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,imx8dxl-acm
|
||||
- fsl,imx8qm-acm
|
||||
- fsl,imx8qxp-acm
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
power-domains:
|
||||
minItems: 13
|
||||
maxItems: 21
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
description:
|
||||
The clock consumer should specify the desired clock by having the clock
|
||||
ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8-clock.h
|
||||
for the full list of i.MX8 ACM clock IDs.
|
||||
|
||||
clocks:
|
||||
minItems: 13
|
||||
maxItems: 27
|
||||
|
||||
clock-names:
|
||||
minItems: 13
|
||||
maxItems: 27
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- power-domains
|
||||
- '#clock-cells'
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- fsl,imx8qxp-acm
|
||||
then:
|
||||
properties:
|
||||
power-domains:
|
||||
items:
|
||||
- description: power domain of IMX_SC_R_AUDIO_CLK_0
|
||||
- description: power domain of IMX_SC_R_AUDIO_CLK_1
|
||||
- description: power domain of IMX_SC_R_MCLK_OUT_0
|
||||
- description: power domain of IMX_SC_R_MCLK_OUT_1
|
||||
- description: power domain of IMX_SC_R_AUDIO_PLL_0
|
||||
- description: power domain of IMX_SC_R_AUDIO_PLL_1
|
||||
- description: power domain of IMX_SC_R_ASRC_0
|
||||
- description: power domain of IMX_SC_R_ASRC_1
|
||||
- description: power domain of IMX_SC_R_ESAI_0
|
||||
- description: power domain of IMX_SC_R_SAI_0
|
||||
- description: power domain of IMX_SC_R_SAI_1
|
||||
- description: power domain of IMX_SC_R_SAI_2
|
||||
- description: power domain of IMX_SC_R_SAI_3
|
||||
- description: power domain of IMX_SC_R_SAI_4
|
||||
- description: power domain of IMX_SC_R_SAI_5
|
||||
- description: power domain of IMX_SC_R_SPDIF_0
|
||||
- description: power domain of IMX_SC_R_MQS_0
|
||||
|
||||
clocks:
|
||||
minItems: 18
|
||||
maxItems: 18
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: aud_rec_clk0_lpcg_clk
|
||||
- const: aud_rec_clk1_lpcg_clk
|
||||
- const: aud_pll_div_clk0_lpcg_clk
|
||||
- const: aud_pll_div_clk1_lpcg_clk
|
||||
- const: ext_aud_mclk0
|
||||
- const: ext_aud_mclk1
|
||||
- const: esai0_rx_clk
|
||||
- const: esai0_rx_hf_clk
|
||||
- const: esai0_tx_clk
|
||||
- const: esai0_tx_hf_clk
|
||||
- const: spdif0_rx
|
||||
- const: sai0_rx_bclk
|
||||
- const: sai0_tx_bclk
|
||||
- const: sai1_rx_bclk
|
||||
- const: sai1_tx_bclk
|
||||
- const: sai2_rx_bclk
|
||||
- const: sai3_rx_bclk
|
||||
- const: sai4_rx_bclk
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- fsl,imx8qm-acm
|
||||
then:
|
||||
properties:
|
||||
power-domains:
|
||||
items:
|
||||
- description: power domain of IMX_SC_R_AUDIO_CLK_0
|
||||
- description: power domain of IMX_SC_R_AUDIO_CLK_1
|
||||
- description: power domain of IMX_SC_R_MCLK_OUT_0
|
||||
- description: power domain of IMX_SC_R_MCLK_OUT_1
|
||||
- description: power domain of IMX_SC_R_AUDIO_PLL_0
|
||||
- description: power domain of IMX_SC_R_AUDIO_PLL_1
|
||||
- description: power domain of IMX_SC_R_ASRC_0
|
||||
- description: power domain of IMX_SC_R_ASRC_1
|
||||
- description: power domain of IMX_SC_R_ESAI_0
|
||||
- description: power domain of IMX_SC_R_ESAI_1
|
||||
- description: power domain of IMX_SC_R_SAI_0
|
||||
- description: power domain of IMX_SC_R_SAI_1
|
||||
- description: power domain of IMX_SC_R_SAI_2
|
||||
- description: power domain of IMX_SC_R_SAI_3
|
||||
- description: power domain of IMX_SC_R_SAI_4
|
||||
- description: power domain of IMX_SC_R_SAI_5
|
||||
- description: power domain of IMX_SC_R_SAI_6
|
||||
- description: power domain of IMX_SC_R_SAI_7
|
||||
- description: power domain of IMX_SC_R_SPDIF_0
|
||||
- description: power domain of IMX_SC_R_SPDIF_1
|
||||
- description: power domain of IMX_SC_R_MQS_0
|
||||
|
||||
clocks:
|
||||
minItems: 27
|
||||
maxItems: 27
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: aud_rec_clk0_lpcg_clk
|
||||
- const: aud_rec_clk1_lpcg_clk
|
||||
- const: aud_pll_div_clk0_lpcg_clk
|
||||
- const: aud_pll_div_clk1_lpcg_clk
|
||||
- const: mlb_clk
|
||||
- const: hdmi_rx_mclk
|
||||
- const: ext_aud_mclk0
|
||||
- const: ext_aud_mclk1
|
||||
- const: esai0_rx_clk
|
||||
- const: esai0_rx_hf_clk
|
||||
- const: esai0_tx_clk
|
||||
- const: esai0_tx_hf_clk
|
||||
- const: esai1_rx_clk
|
||||
- const: esai1_rx_hf_clk
|
||||
- const: esai1_tx_clk
|
||||
- const: esai1_tx_hf_clk
|
||||
- const: spdif0_rx
|
||||
- const: spdif1_rx
|
||||
- const: sai0_rx_bclk
|
||||
- const: sai0_tx_bclk
|
||||
- const: sai1_rx_bclk
|
||||
- const: sai1_tx_bclk
|
||||
- const: sai2_rx_bclk
|
||||
- const: sai3_rx_bclk
|
||||
- const: sai4_rx_bclk
|
||||
- const: sai5_tx_bclk
|
||||
- const: sai6_rx_bclk
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- fsl,imx8dxl-acm
|
||||
then:
|
||||
properties:
|
||||
power-domains:
|
||||
items:
|
||||
- description: power domain of IMX_SC_R_AUDIO_CLK_0
|
||||
- description: power domain of IMX_SC_R_AUDIO_CLK_1
|
||||
- description: power domain of IMX_SC_R_MCLK_OUT_0
|
||||
- description: power domain of IMX_SC_R_MCLK_OUT_1
|
||||
- description: power domain of IMX_SC_R_AUDIO_PLL_0
|
||||
- description: power domain of IMX_SC_R_AUDIO_PLL_1
|
||||
- description: power domain of IMX_SC_R_ASRC_0
|
||||
- description: power domain of IMX_SC_R_SAI_0
|
||||
- description: power domain of IMX_SC_R_SAI_1
|
||||
- description: power domain of IMX_SC_R_SAI_2
|
||||
- description: power domain of IMX_SC_R_SAI_3
|
||||
- description: power domain of IMX_SC_R_SPDIF_0
|
||||
- description: power domain of IMX_SC_R_MQS_0
|
||||
|
||||
clocks:
|
||||
minItems: 13
|
||||
maxItems: 13
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: aud_rec_clk0_lpcg_clk
|
||||
- const: aud_rec_clk1_lpcg_clk
|
||||
- const: aud_pll_div_clk0_lpcg_clk
|
||||
- const: aud_pll_div_clk1_lpcg_clk
|
||||
- const: ext_aud_mclk0
|
||||
- const: ext_aud_mclk1
|
||||
- const: spdif0_rx
|
||||
- const: sai0_rx_bclk
|
||||
- const: sai0_tx_bclk
|
||||
- const: sai1_rx_bclk
|
||||
- const: sai1_tx_bclk
|
||||
- const: sai2_rx_bclk
|
||||
- const: sai3_rx_bclk
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
# Clock Control Module node:
|
||||
- |
|
||||
#include <dt-bindings/clock/imx8-lpcg.h>
|
||||
#include <dt-bindings/firmware/imx/rsrc.h>
|
||||
|
||||
clock-controller@59e00000 {
|
||||
compatible = "fsl,imx8qxp-acm";
|
||||
reg = <0x59e00000 0x1d0000>;
|
||||
#clock-cells = <1>;
|
||||
power-domains = <&pd IMX_SC_R_AUDIO_CLK_0>,
|
||||
<&pd IMX_SC_R_AUDIO_CLK_1>,
|
||||
<&pd IMX_SC_R_MCLK_OUT_0>,
|
||||
<&pd IMX_SC_R_MCLK_OUT_1>,
|
||||
<&pd IMX_SC_R_AUDIO_PLL_0>,
|
||||
<&pd IMX_SC_R_AUDIO_PLL_1>,
|
||||
<&pd IMX_SC_R_ASRC_0>,
|
||||
<&pd IMX_SC_R_ASRC_1>,
|
||||
<&pd IMX_SC_R_ESAI_0>,
|
||||
<&pd IMX_SC_R_SAI_0>,
|
||||
<&pd IMX_SC_R_SAI_1>,
|
||||
<&pd IMX_SC_R_SAI_2>,
|
||||
<&pd IMX_SC_R_SAI_3>,
|
||||
<&pd IMX_SC_R_SAI_4>,
|
||||
<&pd IMX_SC_R_SAI_5>,
|
||||
<&pd IMX_SC_R_SPDIF_0>,
|
||||
<&pd IMX_SC_R_MQS_0>;
|
||||
clocks = <&aud_rec0_lpcg IMX_LPCG_CLK_0>,
|
||||
<&aud_rec1_lpcg IMX_LPCG_CLK_0>,
|
||||
<&aud_pll_div0_lpcg IMX_LPCG_CLK_0>,
|
||||
<&aud_pll_div1_lpcg IMX_LPCG_CLK_0>,
|
||||
<&clk_ext_aud_mclk0>,
|
||||
<&clk_ext_aud_mclk1>,
|
||||
<&clk_esai0_rx_clk>,
|
||||
<&clk_esai0_rx_hf_clk>,
|
||||
<&clk_esai0_tx_clk>,
|
||||
<&clk_esai0_tx_hf_clk>,
|
||||
<&clk_spdif0_rx>,
|
||||
<&clk_sai0_rx_bclk>,
|
||||
<&clk_sai0_tx_bclk>,
|
||||
<&clk_sai1_rx_bclk>,
|
||||
<&clk_sai1_tx_bclk>,
|
||||
<&clk_sai2_rx_bclk>,
|
||||
<&clk_sai3_rx_bclk>,
|
||||
<&clk_sai4_rx_bclk>;
|
||||
clock-names = "aud_rec_clk0_lpcg_clk",
|
||||
"aud_rec_clk1_lpcg_clk",
|
||||
"aud_pll_div_clk0_lpcg_clk",
|
||||
"aud_pll_div_clk1_lpcg_clk",
|
||||
"ext_aud_mclk0",
|
||||
"ext_aud_mclk1",
|
||||
"esai0_rx_clk",
|
||||
"esai0_rx_hf_clk",
|
||||
"esai0_tx_clk",
|
||||
"esai0_tx_hf_clk",
|
||||
"spdif0_rx",
|
||||
"sai0_rx_bclk",
|
||||
"sai0_tx_bclk",
|
||||
"sai1_rx_bclk",
|
||||
"sai1_tx_bclk",
|
||||
"sai2_rx_bclk",
|
||||
"sai3_rx_bclk",
|
||||
"sai4_rx_bclk";
|
||||
};
|
@ -32,11 +32,12 @@ obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o
|
||||
|
||||
obj-$(CONFIG_CLK_IMX93) += clk-imx93.o
|
||||
|
||||
obj-$(CONFIG_MXC_CLK_SCU) += clk-imx-scu.o clk-imx-lpcg-scu.o
|
||||
obj-$(CONFIG_MXC_CLK_SCU) += clk-imx-scu.o clk-imx-lpcg-scu.o clk-imx-acm.o
|
||||
clk-imx-scu-$(CONFIG_CLK_IMX8QXP) += clk-scu.o clk-imx8qxp.o \
|
||||
clk-imx8qxp-rsrc.o clk-imx8qm-rsrc.o \
|
||||
clk-imx8dxl-rsrc.o
|
||||
clk-imx-lpcg-scu-$(CONFIG_CLK_IMX8QXP) += clk-lpcg-scu.o clk-imx8qxp-lpcg.o
|
||||
clk-imx-acm-$(CONFIG_CLK_IMX8QXP) = clk-imx8-acm.o
|
||||
|
||||
obj-$(CONFIG_CLK_IMX8ULP) += clk-imx8ulp.o
|
||||
|
||||
|
@ -97,7 +97,7 @@ static int imx8m_clk_composite_divider_set_rate(struct clk_hw *hw,
|
||||
int prediv_value;
|
||||
int div_value;
|
||||
int ret;
|
||||
u32 val;
|
||||
u32 orig, val;
|
||||
|
||||
ret = imx8m_clk_composite_compute_dividers(rate, parent_rate,
|
||||
&prediv_value, &div_value);
|
||||
@ -106,13 +106,15 @@ static int imx8m_clk_composite_divider_set_rate(struct clk_hw *hw,
|
||||
|
||||
spin_lock_irqsave(divider->lock, flags);
|
||||
|
||||
val = readl(divider->reg);
|
||||
val &= ~((clk_div_mask(divider->width) << divider->shift) |
|
||||
(clk_div_mask(PCG_DIV_WIDTH) << PCG_DIV_SHIFT));
|
||||
orig = readl(divider->reg);
|
||||
val = orig & ~((clk_div_mask(divider->width) << divider->shift) |
|
||||
(clk_div_mask(PCG_DIV_WIDTH) << PCG_DIV_SHIFT));
|
||||
|
||||
val |= (u32)(prediv_value - 1) << divider->shift;
|
||||
val |= (u32)(div_value - 1) << PCG_DIV_SHIFT;
|
||||
writel(val, divider->reg);
|
||||
|
||||
if (val != orig)
|
||||
writel(val, divider->reg);
|
||||
|
||||
spin_unlock_irqrestore(divider->lock, flags);
|
||||
|
||||
|
@ -81,6 +81,7 @@ static const struct imx_fracn_gppll_rate_table fracn_tbl[] = {
|
||||
PLL_FRACN_GP(650000000U, 162, 50, 100, 0, 6),
|
||||
PLL_FRACN_GP(594000000U, 198, 0, 1, 0, 8),
|
||||
PLL_FRACN_GP(560000000U, 140, 0, 1, 0, 6),
|
||||
PLL_FRACN_GP(519750000U, 173, 25, 100, 1, 8),
|
||||
PLL_FRACN_GP(498000000U, 166, 0, 1, 0, 8),
|
||||
PLL_FRACN_GP(484000000U, 121, 0, 1, 0, 6),
|
||||
PLL_FRACN_GP(445333333U, 167, 0, 1, 0, 9),
|
||||
|
@ -65,16 +65,10 @@ static int imx_clk_gpr_mux_set_parent(struct clk_hw *hw, u8 index)
|
||||
return regmap_update_bits(priv->regmap, priv->reg, priv->mask, val);
|
||||
}
|
||||
|
||||
static int imx_clk_gpr_mux_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
return clk_mux_determine_rate_flags(hw, req, 0);
|
||||
}
|
||||
|
||||
static const struct clk_ops imx_clk_gpr_mux_ops = {
|
||||
.get_parent = imx_clk_gpr_mux_get_parent,
|
||||
.set_parent = imx_clk_gpr_mux_set_parent,
|
||||
.determine_rate = imx_clk_gpr_mux_determine_rate,
|
||||
.determine_rate = __clk_mux_determine_rate,
|
||||
};
|
||||
|
||||
struct clk_hw *imx_clk_gpr_mux(const char *name, const char *compatible,
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <soc/imx/revision.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
@ -73,7 +74,7 @@ enum mx25_clks {
|
||||
|
||||
static struct clk *clk[clk_max];
|
||||
|
||||
static int __init __mx25_clocks_init(void __iomem *ccm_base)
|
||||
static void __init __mx25_clocks_init(void __iomem *ccm_base)
|
||||
{
|
||||
BUG_ON(!ccm_base);
|
||||
|
||||
@ -220,7 +221,7 @@ static int __init __mx25_clocks_init(void __iomem *ccm_base)
|
||||
|
||||
imx_register_uart_clocks();
|
||||
|
||||
return 0;
|
||||
imx_print_silicon_rev("i.MX25", mx25_revision());
|
||||
}
|
||||
|
||||
static void __init mx25_clocks_init_dt(struct device_node *np)
|
||||
|
476
drivers/clk/imx/clk-imx8-acm.c
Normal file
476
drivers/clk/imx/clk-imx8-acm.c
Normal file
@ -0,0 +1,476 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// Copyright 2023 NXP
|
||||
//
|
||||
|
||||
#include <dt-bindings/clock/imx8-clock.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
/**
|
||||
* struct clk_imx_acm_pm_domains - structure for multi power domain
|
||||
* @pd_dev: power domain device
|
||||
* @pd_dev_link: power domain device link
|
||||
* @num_domains: power domain nummber
|
||||
*/
|
||||
struct clk_imx_acm_pm_domains {
|
||||
struct device **pd_dev;
|
||||
struct device_link **pd_dev_link;
|
||||
int num_domains;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct clk_imx8_acm_sel - for clock mux
|
||||
* @name: clock name
|
||||
* @clkid: clock id
|
||||
* @parents: clock parents
|
||||
* @num_parents: clock parents number
|
||||
* @reg: register offset
|
||||
* @shift: bit shift in register
|
||||
* @width: bits width
|
||||
*/
|
||||
struct clk_imx8_acm_sel {
|
||||
const char *name;
|
||||
int clkid;
|
||||
const struct clk_parent_data *parents; /* For mux */
|
||||
int num_parents;
|
||||
u32 reg;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct imx8_acm_soc_data - soc specific data
|
||||
* @sels: pointer to struct clk_imx8_acm_sel
|
||||
* @num_sels: numbers of items
|
||||
*/
|
||||
struct imx8_acm_soc_data {
|
||||
struct clk_imx8_acm_sel *sels;
|
||||
unsigned int num_sels;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct imx8_acm_priv - private structure
|
||||
* @dev_pm: multi power domain
|
||||
* @soc_data: pointer to soc data
|
||||
* @reg: base address of registers
|
||||
* @regs: save registers for suspend
|
||||
*/
|
||||
struct imx8_acm_priv {
|
||||
struct clk_imx_acm_pm_domains dev_pm;
|
||||
const struct imx8_acm_soc_data *soc_data;
|
||||
void __iomem *reg;
|
||||
u32 regs[IMX_ADMA_ACM_CLK_END];
|
||||
};
|
||||
|
||||
static const struct clk_parent_data imx8qm_aud_clk_sels[] = {
|
||||
{ .fw_name = "aud_rec_clk0_lpcg_clk" },
|
||||
{ .fw_name = "aud_rec_clk1_lpcg_clk" },
|
||||
{ .fw_name = "mlb_clk" },
|
||||
{ .fw_name = "hdmi_rx_mclk" },
|
||||
{ .fw_name = "ext_aud_mclk0" },
|
||||
{ .fw_name = "ext_aud_mclk1" },
|
||||
{ .fw_name = "esai0_rx_clk" },
|
||||
{ .fw_name = "esai0_rx_hf_clk" },
|
||||
{ .fw_name = "esai0_tx_clk" },
|
||||
{ .fw_name = "esai0_tx_hf_clk" },
|
||||
{ .fw_name = "esai1_rx_clk" },
|
||||
{ .fw_name = "esai1_rx_hf_clk" },
|
||||
{ .fw_name = "esai1_tx_clk" },
|
||||
{ .fw_name = "esai1_tx_hf_clk" },
|
||||
{ .fw_name = "spdif0_rx" },
|
||||
{ .fw_name = "spdif1_rx" },
|
||||
{ .fw_name = "sai0_rx_bclk" },
|
||||
{ .fw_name = "sai0_tx_bclk" },
|
||||
{ .fw_name = "sai1_rx_bclk" },
|
||||
{ .fw_name = "sai1_tx_bclk" },
|
||||
{ .fw_name = "sai2_rx_bclk" },
|
||||
{ .fw_name = "sai3_rx_bclk" },
|
||||
{ .fw_name = "sai4_rx_bclk" },
|
||||
};
|
||||
|
||||
static const struct clk_parent_data imx8qm_mclk_out_sels[] = {
|
||||
{ .fw_name = "aud_rec_clk0_lpcg_clk" },
|
||||
{ .fw_name = "aud_rec_clk1_lpcg_clk" },
|
||||
{ .fw_name = "mlb_clk" },
|
||||
{ .fw_name = "hdmi_rx_mclk" },
|
||||
{ .fw_name = "spdif0_rx" },
|
||||
{ .fw_name = "spdif1_rx" },
|
||||
{ .fw_name = "sai4_rx_bclk" },
|
||||
{ .fw_name = "sai6_rx_bclk" },
|
||||
};
|
||||
|
||||
static const struct clk_parent_data imx8qm_mclk_sels[] = {
|
||||
{ .fw_name = "aud_pll_div_clk0_lpcg_clk" },
|
||||
{ .fw_name = "aud_pll_div_clk1_lpcg_clk" },
|
||||
{ .fw_name = "acm_aud_clk0_sel" },
|
||||
{ .fw_name = "acm_aud_clk1_sel" },
|
||||
};
|
||||
|
||||
static const struct clk_parent_data imx8qm_asrc_mux_clk_sels[] = {
|
||||
{ .fw_name = "sai4_rx_bclk" },
|
||||
{ .fw_name = "sai5_tx_bclk" },
|
||||
{ .index = -1 },
|
||||
{ .fw_name = "mlb_clk" },
|
||||
|
||||
};
|
||||
|
||||
static struct clk_imx8_acm_sel imx8qm_sels[] = {
|
||||
{ "acm_aud_clk0_sel", IMX_ADMA_ACM_AUD_CLK0_SEL, imx8qm_aud_clk_sels, ARRAY_SIZE(imx8qm_aud_clk_sels), 0x000000, 0, 5 },
|
||||
{ "acm_aud_clk1_sel", IMX_ADMA_ACM_AUD_CLK1_SEL, imx8qm_aud_clk_sels, ARRAY_SIZE(imx8qm_aud_clk_sels), 0x010000, 0, 5 },
|
||||
{ "acm_mclkout0_sel", IMX_ADMA_ACM_MCLKOUT0_SEL, imx8qm_mclk_out_sels, ARRAY_SIZE(imx8qm_mclk_out_sels), 0x020000, 0, 3 },
|
||||
{ "acm_mclkout1_sel", IMX_ADMA_ACM_MCLKOUT1_SEL, imx8qm_mclk_out_sels, ARRAY_SIZE(imx8qm_mclk_out_sels), 0x030000, 0, 3 },
|
||||
{ "acm_asrc0_mclk_sel", IMX_ADMA_ACM_ASRC0_MUX_CLK_SEL, imx8qm_asrc_mux_clk_sels, ARRAY_SIZE(imx8qm_asrc_mux_clk_sels), 0x040000, 0, 2 },
|
||||
{ "acm_esai0_mclk_sel", IMX_ADMA_ACM_ESAI0_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x060000, 0, 2 },
|
||||
{ "acm_esai1_mclk_sel", IMX_ADMA_ACM_ESAI1_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x070000, 0, 2 },
|
||||
{ "acm_sai0_mclk_sel", IMX_ADMA_ACM_SAI0_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x0E0000, 0, 2 },
|
||||
{ "acm_sai1_mclk_sel", IMX_ADMA_ACM_SAI1_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x0F0000, 0, 2 },
|
||||
{ "acm_sai2_mclk_sel", IMX_ADMA_ACM_SAI2_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x100000, 0, 2 },
|
||||
{ "acm_sai3_mclk_sel", IMX_ADMA_ACM_SAI3_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x110000, 0, 2 },
|
||||
{ "acm_sai4_mclk_sel", IMX_ADMA_ACM_SAI4_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x120000, 0, 2 },
|
||||
{ "acm_sai5_mclk_sel", IMX_ADMA_ACM_SAI5_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x130000, 0, 2 },
|
||||
{ "acm_sai6_mclk_sel", IMX_ADMA_ACM_SAI6_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x140000, 0, 2 },
|
||||
{ "acm_sai7_mclk_sel", IMX_ADMA_ACM_SAI7_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x150000, 0, 2 },
|
||||
{ "acm_spdif0_mclk_sel", IMX_ADMA_ACM_SPDIF0_TX_CLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x1A0000, 0, 2 },
|
||||
{ "acm_spdif1_mclk_sel", IMX_ADMA_ACM_SPDIF1_TX_CLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x1B0000, 0, 2 },
|
||||
{ "acm_mqs_mclk_sel", IMX_ADMA_ACM_MQS_TX_CLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x1C0000, 0, 2 },
|
||||
};
|
||||
|
||||
static const struct clk_parent_data imx8qxp_aud_clk_sels[] = {
|
||||
{ .fw_name = "aud_rec_clk0_lpcg_clk" },
|
||||
{ .fw_name = "aud_rec_clk1_lpcg_clk" },
|
||||
{ .fw_name = "ext_aud_mclk0" },
|
||||
{ .fw_name = "ext_aud_mclk1" },
|
||||
{ .fw_name = "esai0_rx_clk" },
|
||||
{ .fw_name = "esai0_rx_hf_clk" },
|
||||
{ .fw_name = "esai0_tx_clk" },
|
||||
{ .fw_name = "esai0_tx_hf_clk" },
|
||||
{ .fw_name = "spdif0_rx" },
|
||||
{ .fw_name = "sai0_rx_bclk" },
|
||||
{ .fw_name = "sai0_tx_bclk" },
|
||||
{ .fw_name = "sai1_rx_bclk" },
|
||||
{ .fw_name = "sai1_tx_bclk" },
|
||||
{ .fw_name = "sai2_rx_bclk" },
|
||||
{ .fw_name = "sai3_rx_bclk" },
|
||||
};
|
||||
|
||||
static const struct clk_parent_data imx8qxp_mclk_out_sels[] = {
|
||||
{ .fw_name = "aud_rec_clk0_lpcg_clk" },
|
||||
{ .fw_name = "aud_rec_clk1_lpcg_clk" },
|
||||
{ .index = -1 },
|
||||
{ .index = -1 },
|
||||
{ .fw_name = "spdif0_rx" },
|
||||
{ .index = -1 },
|
||||
{ .index = -1 },
|
||||
{ .fw_name = "sai4_rx_bclk" },
|
||||
};
|
||||
|
||||
static const struct clk_parent_data imx8qxp_mclk_sels[] = {
|
||||
{ .fw_name = "aud_pll_div_clk0_lpcg_clk" },
|
||||
{ .fw_name = "aud_pll_div_clk1_lpcg_clk" },
|
||||
{ .fw_name = "acm_aud_clk0_sel" },
|
||||
{ .fw_name = "acm_aud_clk1_sel" },
|
||||
};
|
||||
|
||||
static struct clk_imx8_acm_sel imx8qxp_sels[] = {
|
||||
{ "acm_aud_clk0_sel", IMX_ADMA_ACM_AUD_CLK0_SEL, imx8qxp_aud_clk_sels, ARRAY_SIZE(imx8qxp_aud_clk_sels), 0x000000, 0, 5 },
|
||||
{ "acm_aud_clk1_sel", IMX_ADMA_ACM_AUD_CLK1_SEL, imx8qxp_aud_clk_sels, ARRAY_SIZE(imx8qxp_aud_clk_sels), 0x010000, 0, 5 },
|
||||
{ "acm_mclkout0_sel", IMX_ADMA_ACM_MCLKOUT0_SEL, imx8qxp_mclk_out_sels, ARRAY_SIZE(imx8qxp_mclk_out_sels), 0x020000, 0, 3 },
|
||||
{ "acm_mclkout1_sel", IMX_ADMA_ACM_MCLKOUT1_SEL, imx8qxp_mclk_out_sels, ARRAY_SIZE(imx8qxp_mclk_out_sels), 0x030000, 0, 3 },
|
||||
{ "acm_esai0_mclk_sel", IMX_ADMA_ACM_ESAI0_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x060000, 0, 2 },
|
||||
{ "acm_sai0_mclk_sel", IMX_ADMA_ACM_SAI0_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x0E0000, 0, 2 },
|
||||
{ "acm_sai1_mclk_sel", IMX_ADMA_ACM_SAI1_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x0F0000, 0, 2 },
|
||||
{ "acm_sai2_mclk_sel", IMX_ADMA_ACM_SAI2_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x100000, 0, 2 },
|
||||
{ "acm_sai3_mclk_sel", IMX_ADMA_ACM_SAI3_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x110000, 0, 2 },
|
||||
{ "acm_sai4_mclk_sel", IMX_ADMA_ACM_SAI4_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x140000, 0, 2 },
|
||||
{ "acm_sai5_mclk_sel", IMX_ADMA_ACM_SAI5_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x150000, 0, 2 },
|
||||
{ "acm_spdif0_mclk_sel", IMX_ADMA_ACM_SPDIF0_TX_CLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x1A0000, 0, 2 },
|
||||
{ "acm_mqs_mclk_sel", IMX_ADMA_ACM_MQS_TX_CLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x1C0000, 0, 2 },
|
||||
};
|
||||
|
||||
static const struct clk_parent_data imx8dxl_aud_clk_sels[] = {
|
||||
{ .fw_name = "aud_rec_clk0_lpcg_clk" },
|
||||
{ .fw_name = "aud_rec_clk1_lpcg_clk" },
|
||||
{ .fw_name = "ext_aud_mclk0" },
|
||||
{ .fw_name = "ext_aud_mclk1" },
|
||||
{ .index = -1 },
|
||||
{ .index = -1 },
|
||||
{ .index = -1 },
|
||||
{ .index = -1 },
|
||||
{ .fw_name = "spdif0_rx" },
|
||||
{ .fw_name = "sai0_rx_bclk" },
|
||||
{ .fw_name = "sai0_tx_bclk" },
|
||||
{ .fw_name = "sai1_rx_bclk" },
|
||||
{ .fw_name = "sai1_tx_bclk" },
|
||||
{ .fw_name = "sai2_rx_bclk" },
|
||||
{ .fw_name = "sai3_rx_bclk" },
|
||||
};
|
||||
|
||||
static const struct clk_parent_data imx8dxl_mclk_out_sels[] = {
|
||||
{ .fw_name = "aud_rec_clk0_lpcg_clk" },
|
||||
{ .fw_name = "aud_rec_clk1_lpcg_clk" },
|
||||
{ .index = -1 },
|
||||
{ .index = -1 },
|
||||
{ .fw_name = "spdif0_rx" },
|
||||
{ .index = -1 },
|
||||
{ .index = -1 },
|
||||
{ .index = -1 },
|
||||
};
|
||||
|
||||
static const struct clk_parent_data imx8dxl_mclk_sels[] = {
|
||||
{ .fw_name = "aud_pll_div_clk0_lpcg_clk" },
|
||||
{ .fw_name = "aud_pll_div_clk1_lpcg_clk" },
|
||||
{ .fw_name = "acm_aud_clk0_sel" },
|
||||
{ .fw_name = "acm_aud_clk1_sel" },
|
||||
};
|
||||
|
||||
static struct clk_imx8_acm_sel imx8dxl_sels[] = {
|
||||
{ "acm_aud_clk0_sel", IMX_ADMA_ACM_AUD_CLK0_SEL, imx8dxl_aud_clk_sels, ARRAY_SIZE(imx8dxl_aud_clk_sels), 0x000000, 0, 5 },
|
||||
{ "acm_aud_clk1_sel", IMX_ADMA_ACM_AUD_CLK1_SEL, imx8dxl_aud_clk_sels, ARRAY_SIZE(imx8dxl_aud_clk_sels), 0x010000, 0, 5 },
|
||||
{ "acm_mclkout0_sel", IMX_ADMA_ACM_MCLKOUT0_SEL, imx8dxl_mclk_out_sels, ARRAY_SIZE(imx8dxl_mclk_out_sels), 0x020000, 0, 3 },
|
||||
{ "acm_mclkout1_sel", IMX_ADMA_ACM_MCLKOUT1_SEL, imx8dxl_mclk_out_sels, ARRAY_SIZE(imx8dxl_mclk_out_sels), 0x030000, 0, 3 },
|
||||
{ "acm_sai0_mclk_sel", IMX_ADMA_ACM_SAI0_MCLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x0E0000, 0, 2 },
|
||||
{ "acm_sai1_mclk_sel", IMX_ADMA_ACM_SAI1_MCLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x0F0000, 0, 2 },
|
||||
{ "acm_sai2_mclk_sel", IMX_ADMA_ACM_SAI2_MCLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x100000, 0, 2 },
|
||||
{ "acm_sai3_mclk_sel", IMX_ADMA_ACM_SAI3_MCLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x110000, 0, 2 },
|
||||
{ "acm_spdif0_mclk_sel", IMX_ADMA_ACM_SPDIF0_TX_CLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x1A0000, 0, 2 },
|
||||
{ "acm_mqs_mclk_sel", IMX_ADMA_ACM_MQS_TX_CLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x1C0000, 0, 2 },
|
||||
};
|
||||
|
||||
/**
|
||||
* clk_imx_acm_attach_pm_domains: attach multi power domains
|
||||
* @dev: device pointer
|
||||
* @dev_pm: power domains for device
|
||||
*/
|
||||
static int clk_imx_acm_attach_pm_domains(struct device *dev,
|
||||
struct clk_imx_acm_pm_domains *dev_pm)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
dev_pm->num_domains = of_count_phandle_with_args(dev->of_node, "power-domains",
|
||||
"#power-domain-cells");
|
||||
if (dev_pm->num_domains <= 1)
|
||||
return 0;
|
||||
|
||||
dev_pm->pd_dev = devm_kmalloc_array(dev, dev_pm->num_domains,
|
||||
sizeof(*dev_pm->pd_dev),
|
||||
GFP_KERNEL);
|
||||
if (!dev_pm->pd_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_pm->pd_dev_link = devm_kmalloc_array(dev,
|
||||
dev_pm->num_domains,
|
||||
sizeof(*dev_pm->pd_dev_link),
|
||||
GFP_KERNEL);
|
||||
if (!dev_pm->pd_dev_link)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < dev_pm->num_domains; i++) {
|
||||
dev_pm->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i);
|
||||
if (IS_ERR(dev_pm->pd_dev[i]))
|
||||
return PTR_ERR(dev_pm->pd_dev[i]);
|
||||
|
||||
dev_pm->pd_dev_link[i] = device_link_add(dev,
|
||||
dev_pm->pd_dev[i],
|
||||
DL_FLAG_STATELESS |
|
||||
DL_FLAG_PM_RUNTIME |
|
||||
DL_FLAG_RPM_ACTIVE);
|
||||
if (IS_ERR(dev_pm->pd_dev_link[i])) {
|
||||
dev_pm_domain_detach(dev_pm->pd_dev[i], false);
|
||||
ret = PTR_ERR(dev_pm->pd_dev_link[i]);
|
||||
goto detach_pm;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
detach_pm:
|
||||
while (--i >= 0) {
|
||||
device_link_del(dev_pm->pd_dev_link[i]);
|
||||
dev_pm_domain_detach(dev_pm->pd_dev[i], false);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* clk_imx_acm_detach_pm_domains: detach multi power domains
|
||||
* @dev: deivice pointer
|
||||
* @dev_pm: multi power domain for device
|
||||
*/
|
||||
static int clk_imx_acm_detach_pm_domains(struct device *dev,
|
||||
struct clk_imx_acm_pm_domains *dev_pm)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (dev_pm->num_domains <= 1)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < dev_pm->num_domains; i++) {
|
||||
device_link_del(dev_pm->pd_dev_link[i]);
|
||||
dev_pm_domain_detach(dev_pm->pd_dev[i], false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx8_acm_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct clk_hw_onecell_data *clk_hw_data;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct clk_imx8_acm_sel *sels;
|
||||
struct imx8_acm_priv *priv;
|
||||
struct clk_hw **hws;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
base = devm_of_iomap(dev, dev->of_node, 0, NULL);
|
||||
if (WARN_ON(IS_ERR(base)))
|
||||
return PTR_ERR(base);
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->reg = base;
|
||||
priv->soc_data = of_device_get_match_data(dev);
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
clk_hw_data = devm_kzalloc(&pdev->dev, struct_size(clk_hw_data, hws, IMX_ADMA_ACM_CLK_END),
|
||||
GFP_KERNEL);
|
||||
if (!clk_hw_data)
|
||||
return -ENOMEM;
|
||||
|
||||
clk_hw_data->num = IMX_ADMA_ACM_CLK_END;
|
||||
hws = clk_hw_data->hws;
|
||||
|
||||
ret = clk_imx_acm_attach_pm_domains(&pdev->dev, &priv->dev_pm);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
|
||||
sels = priv->soc_data->sels;
|
||||
for (i = 0; i < priv->soc_data->num_sels; i++) {
|
||||
hws[sels[i].clkid] = devm_clk_hw_register_mux_parent_data_table(dev,
|
||||
sels[i].name, sels[i].parents,
|
||||
sels[i].num_parents, 0,
|
||||
base + sels[i].reg,
|
||||
sels[i].shift, sels[i].width,
|
||||
0, NULL, NULL);
|
||||
if (IS_ERR(hws[sels[i].clkid])) {
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
goto err_clk_register;
|
||||
}
|
||||
}
|
||||
|
||||
imx_check_clk_hws(hws, IMX_ADMA_ACM_CLK_END);
|
||||
|
||||
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_hw_data);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to register hws for ACM\n");
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
}
|
||||
|
||||
err_clk_register:
|
||||
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx8_acm_clk_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct imx8_acm_priv *priv = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
clk_imx_acm_detach_pm_domains(&pdev->dev, &priv->dev_pm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct imx8_acm_soc_data imx8qm_acm_data = {
|
||||
.sels = imx8qm_sels,
|
||||
.num_sels = ARRAY_SIZE(imx8qm_sels),
|
||||
};
|
||||
|
||||
static const struct imx8_acm_soc_data imx8qxp_acm_data = {
|
||||
.sels = imx8qxp_sels,
|
||||
.num_sels = ARRAY_SIZE(imx8qxp_sels),
|
||||
};
|
||||
|
||||
static const struct imx8_acm_soc_data imx8dxl_acm_data = {
|
||||
.sels = imx8dxl_sels,
|
||||
.num_sels = ARRAY_SIZE(imx8dxl_sels),
|
||||
};
|
||||
|
||||
static const struct of_device_id imx8_acm_match[] = {
|
||||
{ .compatible = "fsl,imx8qm-acm", .data = &imx8qm_acm_data },
|
||||
{ .compatible = "fsl,imx8qxp-acm", .data = &imx8qxp_acm_data },
|
||||
{ .compatible = "fsl,imx8dxl-acm", .data = &imx8dxl_acm_data },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imx8_acm_match);
|
||||
|
||||
static int __maybe_unused imx8_acm_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct imx8_acm_priv *priv = dev_get_drvdata(dev);
|
||||
struct clk_imx8_acm_sel *sels;
|
||||
int i;
|
||||
|
||||
sels = priv->soc_data->sels;
|
||||
|
||||
for (i = 0; i < priv->soc_data->num_sels; i++)
|
||||
priv->regs[i] = readl_relaxed(priv->reg + sels[i].reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused imx8_acm_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct imx8_acm_priv *priv = dev_get_drvdata(dev);
|
||||
struct clk_imx8_acm_sel *sels;
|
||||
int i;
|
||||
|
||||
sels = priv->soc_data->sels;
|
||||
|
||||
for (i = 0; i < priv->soc_data->num_sels; i++)
|
||||
writel_relaxed(priv->regs[i], priv->reg + sels[i].reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops imx8_acm_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(imx8_acm_runtime_suspend,
|
||||
imx8_acm_runtime_resume, NULL)
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
};
|
||||
|
||||
static struct platform_driver imx8_acm_clk_driver = {
|
||||
.driver = {
|
||||
.name = "imx8-acm",
|
||||
.of_match_table = imx8_acm_match,
|
||||
.pm = &imx8_acm_pm_ops,
|
||||
},
|
||||
.probe = imx8_acm_clk_probe,
|
||||
.remove = imx8_acm_clk_remove,
|
||||
};
|
||||
module_platform_driver(imx8_acm_clk_driver);
|
||||
|
||||
MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
|
||||
MODULE_DESCRIPTION("Freescale i.MX8 Audio Clock Mux driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -178,10 +178,6 @@ static const char * const imx8mp_sai3_sels[] = {"osc_24m", "audio_pll1_out", "au
|
||||
"video_pll1_out", "sys_pll1_133m", "osc_hdmi",
|
||||
"clk_ext3", "clk_ext4", };
|
||||
|
||||
static const char * const imx8mp_sai4_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
|
||||
"video_pll1_out", "sys_pll1_133m", "osc_hdmi",
|
||||
"clk_ext1", "clk_ext2", };
|
||||
|
||||
static const char * const imx8mp_sai5_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out",
|
||||
"video_pll1_out", "sys_pll1_133m", "osc_hdmi",
|
||||
"clk_ext2", "clk_ext3", };
|
||||
@ -567,7 +563,6 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
|
||||
hws[IMX8MP_CLK_SAI1] = imx8m_clk_hw_composite("sai1", imx8mp_sai1_sels, ccm_base + 0xa580);
|
||||
hws[IMX8MP_CLK_SAI2] = imx8m_clk_hw_composite("sai2", imx8mp_sai2_sels, ccm_base + 0xa600);
|
||||
hws[IMX8MP_CLK_SAI3] = imx8m_clk_hw_composite("sai3", imx8mp_sai3_sels, ccm_base + 0xa680);
|
||||
hws[IMX8MP_CLK_SAI4] = imx8m_clk_hw_composite("sai4", imx8mp_sai4_sels, ccm_base + 0xa700);
|
||||
hws[IMX8MP_CLK_SAI5] = imx8m_clk_hw_composite("sai5", imx8mp_sai5_sels, ccm_base + 0xa780);
|
||||
hws[IMX8MP_CLK_SAI6] = imx8m_clk_hw_composite("sai6", imx8mp_sai6_sels, ccm_base + 0xa800);
|
||||
hws[IMX8MP_CLK_ENET_QOS] = imx8m_clk_hw_composite("enet_qos", imx8mp_enet_qos_sels, ccm_base + 0xa880);
|
||||
|
@ -183,7 +183,6 @@ static int imx_lpcg_parse_clks_from_dt(struct platform_device *pdev,
|
||||
unsigned int bit_offset[IMX_LPCG_MAX_CLKS];
|
||||
struct clk_hw_onecell_data *clk_data;
|
||||
struct clk_hw **clk_hws;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
int count;
|
||||
int idx;
|
||||
@ -193,8 +192,7 @@ static int imx_lpcg_parse_clks_from_dt(struct platform_device *pdev,
|
||||
if (!of_device_is_compatible(np, "fsl,imx8qxp-lpcg"))
|
||||
return -EINVAL;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
|
@ -167,7 +167,7 @@ static int imx8ulp_clk_cgc1_init(struct platform_device *pdev)
|
||||
clks[IMX8ULP_CLK_SPLL2_PRE_SEL] = imx_clk_hw_mux_flags("spll2_pre_sel", base + 0x510, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE);
|
||||
clks[IMX8ULP_CLK_SPLL3_PRE_SEL] = imx_clk_hw_mux_flags("spll3_pre_sel", base + 0x610, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE);
|
||||
|
||||
clks[IMX8ULP_CLK_SPLL2] = imx_clk_hw_pllv4(IMX_PLLV4_IMX8ULP, "spll2", "spll2_pre_sel", base + 0x500);
|
||||
clks[IMX8ULP_CLK_SPLL2] = imx_clk_hw_pllv4(IMX_PLLV4_IMX8ULP_1GHZ, "spll2", "spll2_pre_sel", base + 0x500);
|
||||
clks[IMX8ULP_CLK_SPLL3] = imx_clk_hw_pllv4(IMX_PLLV4_IMX8ULP, "spll3", "spll3_pre_sel", base + 0x600);
|
||||
clks[IMX8ULP_CLK_SPLL3_VCODIV] = imx_clk_hw_divider("spll3_vcodiv", "spll3", base + 0x604, 0, 6);
|
||||
|
||||
|
@ -32,6 +32,7 @@ static u32 share_count_sai1;
|
||||
static u32 share_count_sai2;
|
||||
static u32 share_count_sai3;
|
||||
static u32 share_count_mub;
|
||||
static u32 share_count_pdm;
|
||||
|
||||
static const char * const a55_core_sels[] = {"a55_alt", "arm_pll"};
|
||||
static const char *parent_names[MAX_SEL][4] = {
|
||||
@ -236,7 +237,8 @@ static const struct imx93_clk_ccgr {
|
||||
{ IMX93_CLK_USB_CONTROLLER_GATE, "usb_controller", "hsio_root", 0x9a00, },
|
||||
{ IMX93_CLK_USB_TEST_60M_GATE, "usb_test_60m", "hsio_usb_test_60m_root", 0x9a40, },
|
||||
{ IMX93_CLK_HSIO_TROUT_24M_GATE, "hsio_trout_24m", "osc_24m", 0x9a80, },
|
||||
{ IMX93_CLK_PDM_GATE, "pdm", "pdm_root", 0x9ac0, },
|
||||
{ IMX93_CLK_PDM_GATE, "pdm", "pdm_root", 0x9ac0, 0, &share_count_pdm},
|
||||
{ IMX93_CLK_PDM_IPG, "pdm_ipg_clk", "bus_aon_root", 0x9ac0, 0, &share_count_pdm},
|
||||
{ IMX93_CLK_MQS1_GATE, "mqs1", "sai1_root", 0x9b00, },
|
||||
{ IMX93_CLK_MQS2_GATE, "mqs2", "sai3_root", 0x9b40, },
|
||||
{ IMX93_CLK_AUD_XCVR_GATE, "aud_xcvr", "audio_xcvr_root", 0x9b80, },
|
||||
|
@ -64,8 +64,6 @@ static const struct imx_pll14xx_rate_table imx_pll1443x_tbl[] = {
|
||||
PLL_1443X_RATE(650000000U, 325, 3, 2, 0),
|
||||
PLL_1443X_RATE(594000000U, 198, 2, 2, 0),
|
||||
PLL_1443X_RATE(519750000U, 173, 2, 2, 16384),
|
||||
PLL_1443X_RATE(393216000U, 262, 2, 3, 9437),
|
||||
PLL_1443X_RATE(361267200U, 361, 3, 3, 17511),
|
||||
};
|
||||
|
||||
struct imx_pll14xx_clk imx_1443x_pll = {
|
||||
@ -139,11 +137,10 @@ static void imx_pll14xx_calc_settings(struct clk_pll14xx *pll, unsigned long rat
|
||||
/*
|
||||
* Fractional PLL constrains:
|
||||
*
|
||||
* a) 6MHz <= prate <= 25MHz
|
||||
* b) 1 <= p <= 63 (1 <= p <= 4 prate = 24MHz)
|
||||
* c) 64 <= m <= 1023
|
||||
* d) 0 <= s <= 6
|
||||
* e) -32768 <= k <= 32767
|
||||
* a) 1 <= p <= 63
|
||||
* b) 64 <= m <= 1023
|
||||
* c) 0 <= s <= 6
|
||||
* d) -32768 <= k <= 32767
|
||||
*
|
||||
* fvco = (m * 65536 + k) * prate / (p * 65536)
|
||||
*/
|
||||
@ -186,7 +183,7 @@ static void imx_pll14xx_calc_settings(struct clk_pll14xx *pll, unsigned long rat
|
||||
}
|
||||
|
||||
/* Finally calculate best values */
|
||||
for (pdiv = 1; pdiv <= 7; pdiv++) {
|
||||
for (pdiv = 1; pdiv <= 63; pdiv++) {
|
||||
for (sdiv = 0; sdiv <= 6; sdiv++) {
|
||||
/* calc mdiv = round(rate * pdiv * 2^sdiv) / prate) */
|
||||
mdiv = DIV_ROUND_CLOSEST(rate * (pdiv << sdiv), prate);
|
||||
|
@ -44,11 +44,15 @@ struct clk_pllv4 {
|
||||
u32 cfg_offset;
|
||||
u32 num_offset;
|
||||
u32 denom_offset;
|
||||
bool use_mult_range;
|
||||
};
|
||||
|
||||
/* Valid PLL MULT Table */
|
||||
static const int pllv4_mult_table[] = {33, 27, 22, 20, 17, 16};
|
||||
|
||||
/* Valid PLL MULT range, (max, min) */
|
||||
static const int pllv4_mult_range[] = {54, 27};
|
||||
|
||||
#define to_clk_pllv4(__hw) container_of(__hw, struct clk_pllv4, hw)
|
||||
|
||||
#define LOCK_TIMEOUT_US USEC_PER_MSEC
|
||||
@ -94,17 +98,30 @@ static unsigned long clk_pllv4_recalc_rate(struct clk_hw *hw,
|
||||
static long clk_pllv4_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct clk_pllv4 *pll = to_clk_pllv4(hw);
|
||||
unsigned long parent_rate = *prate;
|
||||
unsigned long round_rate, i;
|
||||
u32 mfn, mfd = DEFAULT_MFD;
|
||||
bool found = false;
|
||||
u64 temp64;
|
||||
u32 mult;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) {
|
||||
round_rate = parent_rate * pllv4_mult_table[i];
|
||||
if (rate >= round_rate) {
|
||||
if (pll->use_mult_range) {
|
||||
temp64 = (u64)rate;
|
||||
do_div(temp64, parent_rate);
|
||||
mult = temp64;
|
||||
if (mult >= pllv4_mult_range[1] &&
|
||||
mult <= pllv4_mult_range[0]) {
|
||||
round_rate = parent_rate * mult;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) {
|
||||
round_rate = parent_rate * pllv4_mult_table[i];
|
||||
if (rate >= round_rate) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,14 +155,20 @@ static long clk_pllv4_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
return round_rate + (u32)temp64;
|
||||
}
|
||||
|
||||
static bool clk_pllv4_is_valid_mult(unsigned int mult)
|
||||
static bool clk_pllv4_is_valid_mult(struct clk_pllv4 *pll, unsigned int mult)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* check if mult is in valid MULT table */
|
||||
for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) {
|
||||
if (pllv4_mult_table[i] == mult)
|
||||
if (pll->use_mult_range) {
|
||||
if (mult >= pllv4_mult_range[1] &&
|
||||
mult <= pllv4_mult_range[0])
|
||||
return true;
|
||||
} else {
|
||||
for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) {
|
||||
if (pllv4_mult_table[i] == mult)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -160,7 +183,7 @@ static int clk_pllv4_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
mult = rate / parent_rate;
|
||||
|
||||
if (!clk_pllv4_is_valid_mult(mult))
|
||||
if (!clk_pllv4_is_valid_mult(pll, mult))
|
||||
return -EINVAL;
|
||||
|
||||
if (parent_rate <= MAX_MFD)
|
||||
@ -227,10 +250,13 @@ struct clk_hw *imx_clk_hw_pllv4(enum imx_pllv4_type type, const char *name,
|
||||
|
||||
pll->base = base;
|
||||
|
||||
if (type == IMX_PLLV4_IMX8ULP) {
|
||||
if (type == IMX_PLLV4_IMX8ULP ||
|
||||
type == IMX_PLLV4_IMX8ULP_1GHZ) {
|
||||
pll->cfg_offset = IMX8ULP_PLL_CFG_OFFSET;
|
||||
pll->num_offset = IMX8ULP_PLL_NUM_OFFSET;
|
||||
pll->denom_offset = IMX8ULP_PLL_DENOM_OFFSET;
|
||||
if (type == IMX_PLLV4_IMX8ULP_1GHZ)
|
||||
pll->use_mult_range = true;
|
||||
} else {
|
||||
pll->cfg_offset = PLL_CFG_OFFSET;
|
||||
pll->num_offset = PLL_NUM_OFFSET;
|
||||
|
@ -45,6 +45,7 @@ enum imx_pll14xx_type {
|
||||
enum imx_pllv4_type {
|
||||
IMX_PLLV4_IMX7ULP,
|
||||
IMX_PLLV4_IMX8ULP,
|
||||
IMX_PLLV4_IMX8ULP_1GHZ,
|
||||
};
|
||||
|
||||
enum imx_pfdv2_type {
|
||||
|
@ -164,4 +164,32 @@
|
||||
|
||||
#define IMX_ADMA_LPCG_CLK_END 45
|
||||
|
||||
#define IMX_ADMA_ACM_AUD_CLK0_SEL 0
|
||||
#define IMX_ADMA_ACM_AUD_CLK1_SEL 1
|
||||
#define IMX_ADMA_ACM_MCLKOUT0_SEL 2
|
||||
#define IMX_ADMA_ACM_MCLKOUT1_SEL 3
|
||||
#define IMX_ADMA_ACM_ESAI0_MCLK_SEL 4
|
||||
#define IMX_ADMA_ACM_ESAI1_MCLK_SEL 5
|
||||
#define IMX_ADMA_ACM_GPT0_MUX_CLK_SEL 6
|
||||
#define IMX_ADMA_ACM_GPT1_MUX_CLK_SEL 7
|
||||
#define IMX_ADMA_ACM_GPT2_MUX_CLK_SEL 8
|
||||
#define IMX_ADMA_ACM_GPT3_MUX_CLK_SEL 9
|
||||
#define IMX_ADMA_ACM_GPT4_MUX_CLK_SEL 10
|
||||
#define IMX_ADMA_ACM_GPT5_MUX_CLK_SEL 11
|
||||
#define IMX_ADMA_ACM_SAI0_MCLK_SEL 12
|
||||
#define IMX_ADMA_ACM_SAI1_MCLK_SEL 13
|
||||
#define IMX_ADMA_ACM_SAI2_MCLK_SEL 14
|
||||
#define IMX_ADMA_ACM_SAI3_MCLK_SEL 15
|
||||
#define IMX_ADMA_ACM_SAI4_MCLK_SEL 16
|
||||
#define IMX_ADMA_ACM_SAI5_MCLK_SEL 17
|
||||
#define IMX_ADMA_ACM_SAI6_MCLK_SEL 18
|
||||
#define IMX_ADMA_ACM_SAI7_MCLK_SEL 19
|
||||
#define IMX_ADMA_ACM_SPDIF0_TX_CLK_SEL 20
|
||||
#define IMX_ADMA_ACM_SPDIF1_TX_CLK_SEL 21
|
||||
#define IMX_ADMA_ACM_MQS_TX_CLK_SEL 22
|
||||
#define IMX_ADMA_ACM_ASRC0_MUX_CLK_SEL 23
|
||||
#define IMX_ADMA_ACM_ASRC1_MUX_CLK_SEL 24
|
||||
|
||||
#define IMX_ADMA_ACM_CLK_END 25
|
||||
|
||||
#endif /* __DT_BINDINGS_CLOCK_IMX_H */
|
||||
|
@ -130,7 +130,7 @@
|
||||
#define IMX8MP_CLK_SAI1 123
|
||||
#define IMX8MP_CLK_SAI2 124
|
||||
#define IMX8MP_CLK_SAI3 125
|
||||
#define IMX8MP_CLK_SAI4 126
|
||||
/* #define IMX8MP_CLK_SAI4 126 */
|
||||
#define IMX8MP_CLK_SAI5 127
|
||||
#define IMX8MP_CLK_SAI6 128
|
||||
#define IMX8MP_CLK_ENET_QOS 129
|
||||
|
@ -203,6 +203,7 @@
|
||||
#define IMX93_CLK_ARM_PLL 198
|
||||
#define IMX93_CLK_A55_SEL 199
|
||||
#define IMX93_CLK_A55_CORE 200
|
||||
#define IMX93_CLK_END 201
|
||||
#define IMX93_CLK_PDM_IPG 201
|
||||
#define IMX93_CLK_END 202
|
||||
|
||||
#endif
|
||||
|
@ -22,6 +22,7 @@
|
||||
#define IMX_CHIP_REVISION_3_3 0x33
|
||||
#define IMX_CHIP_REVISION_UNKNOWN 0xff
|
||||
|
||||
int mx25_revision(void);
|
||||
int mx27_revision(void);
|
||||
int mx31_revision(void);
|
||||
int mx35_revision(void);
|
||||
|
Loading…
x
Reference in New Issue
Block a user