lkml.org 
[lkml]   [2020]   [Mar]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    SubjectRe: [RFC 08/11] clk: imx: Add audiomix clock controller support
    From
    Date
    Quoting Abel Vesa (2020-03-03 01:03:23)
    > diff --git a/drivers/clk/imx/clk-audiomix.c b/drivers/clk/imx/clk-audiomix.c
    > new file mode 100644
    > index 00000000..8b84943
    > --- /dev/null
    > +++ b/drivers/clk/imx/clk-audiomix.c
    > @@ -0,0 +1,237 @@
    > +// SPDX-License-Identifier: GPL-2.0
    > +/*
    > + * Copyright 2019 NXP.
    > + */
    > +
    > +#include <dt-bindings/clock/imx8mp-clock.h>
    > +#include <linux/clk.h>
    > +#include <linux/err.h>
    > +#include <linux/io.h>
    > +#include <linux/module.h>
    > +#include <linux/of.h>
    > +#include <linux/of_address.h>
    > +#include <linux/platform_device.h>
    > +#include <linux/pm_runtime.h>
    > +#include <linux/slab.h>
    > +#include <linux/types.h>
    > +
    > +#include "clk.h"
    > +
    > +static int shared_count_pdm;
    > +static struct clk_hw **hws;
    > +static struct clk_hw_onecell_data *clk_hw_data;
    > +static uint32_t audiomix_clk_saved_regs[14];
    > +static struct clk *clk_audio_root;
    > +static struct clk *clk_audio_ahb;
    > +static struct clk *clk_audio_axi_div;
    > +
    > +static const struct imx_pll14xx_rate_table imx_audiomix_sai_pll_tbl[] = {
    > + PLL_1443X_RATE(650000000U, 325, 3, 2, 0),
    > +};
    > +
    > +static const struct imx_pll14xx_clk imx_audiomix_sai_pll = {
    > + .type = PLL_1443X,
    > + .rate_table = imx_audiomix_sai_pll_tbl,
    > +};
    > +
    > +static const char *imx_sai_mclk2_sels[] = {"sai1", "sai2", "sai3", "dummy",
    > + "sai5", "sai6", "sai7", "dummy",
    > + "dummy", "dummy", "dummy",
    > + "dummy", "dummy", "dummy", "dummy"};
    > +static const char *imx_sai1_mclk1_sels[] = {"sai1", "dummy", };
    > +static const char *imx_sai2_mclk1_sels[] = {"sai2", "dummy", };
    > +static const char *imx_sai3_mclk1_sels[] = {"sai3", "dummy", };
    > +static const char *imx_sai5_mclk1_sels[] = {"sai5", "dummy", };
    > +static const char *imx_sai6_mclk1_sels[] = {"sai6", "dummy", };
    > +static const char *imx_sai7_mclk1_sels[] = {"sai7", "dummy", };
    > +static const char *imx_pdm_sels[] = {"pdm", "sai_pll_div2", "dummy", "dummy" };
    > +static const char *imx_sai_pll_ref_sels[] = {"osc_24m", "dummy", "dummy", "dummy", };
    > +static const char *imx_sai_pll_bypass_sels[] = {"sai_pll", "sai_pll_ref_sel", };
    > +
    > +static int imx_audiomix_clk_suspend(struct device *dev)
    > +{
    > + void __iomem *base;
    > +
    > + base = dev_get_drvdata(dev->parent);
    > +
    > + audiomix_clk_saved_regs[0] = readl(base);
    > + audiomix_clk_saved_regs[1] = readl(base + 0x4);
    > +
    > + audiomix_clk_saved_regs[2] = readl(base + 0x300);
    > + audiomix_clk_saved_regs[3] = readl(base + 0x304);
    > + audiomix_clk_saved_regs[4] = readl(base + 0x308);
    > + audiomix_clk_saved_regs[5] = readl(base + 0x30C);
    > + audiomix_clk_saved_regs[6] = readl(base + 0x310);
    > + audiomix_clk_saved_regs[7] = readl(base + 0x314);
    > + audiomix_clk_saved_regs[8] = readl(base + 0x318);
    > +
    > + audiomix_clk_saved_regs[9] = readl(base + 0x400);
    > + audiomix_clk_saved_regs[10] = readl(base + 0x404);
    > + audiomix_clk_saved_regs[11] = readl(base + 0x408);
    > + audiomix_clk_saved_regs[12] = readl(base + 0x40C);
    > + audiomix_clk_saved_regs[13] = readl(base + 0x410);

    Maybe use three loops that have an 'i' and an offset and then += 4 all
    the time? Would be a little more compact.

    > +
    > + clk_disable_unprepare(clk_audio_ahb);
    > + clk_disable_unprepare(clk_audio_root);
    > + clk_disable_unprepare(clk_audio_axi_div);
    > + pm_runtime_put(dev);
    > +
    > + return 0;
    > +}
    > +
    > +static int imx_audiomix_clk_resume(struct device *dev)
    > +{
    > + void __iomem *base;
    > +
    > + base = dev_get_drvdata(dev->parent);
    > +
    > + pm_runtime_get(dev);
    > + clk_prepare_enable(clk_audio_ahb);
    > + clk_prepare_enable(clk_audio_root);
    > + clk_prepare_enable(clk_audio_axi_div);
    > +
    > + writel(audiomix_clk_saved_regs[0], base);
    > + writel(audiomix_clk_saved_regs[1], base + 0x4);
    > +
    > + writel(audiomix_clk_saved_regs[2], base + 0x300);
    > + writel(audiomix_clk_saved_regs[3], base + 0x304);
    > + writel(audiomix_clk_saved_regs[4], base + 0x308);
    > + writel(audiomix_clk_saved_regs[5], base + 0x30C);
    > + writel(audiomix_clk_saved_regs[6], base + 0x310);
    > + writel(audiomix_clk_saved_regs[7], base + 0x314);
    > + writel(audiomix_clk_saved_regs[8], base + 0x318);
    > +
    > + writel(audiomix_clk_saved_regs[9], base + 0x400);
    > + writel(audiomix_clk_saved_regs[10], base + 0x404);
    > + writel(audiomix_clk_saved_regs[11], base + 0x408);
    > + writel(audiomix_clk_saved_regs[12], base + 0x40C);
    > + writel(audiomix_clk_saved_regs[13], base + 0x410);
    > +
    > + return 0;
    > +}
    > +
    > +static int imx_audiomix_clk_probe(struct platform_device *pdev)
    > +{
    > + struct device *dev = &pdev->dev;
    > + struct device_node *np = dev->of_node;
    > + void __iomem *base;
    > +
    > + clk_audio_root = of_clk_get_by_name(np, "audio_root");

    Any reason devm_clk_get() can't be used?

    > + if (IS_ERR(clk_audio_root))
    > + return PTR_ERR(clk_audio_root);
    > +
    > + clk_audio_ahb = of_clk_get_by_name(np, "audio_ahb");
    > + if (IS_ERR(clk_audio_ahb))
    > + return PTR_ERR(clk_audio_ahb);
    > +
    > + clk_audio_axi_div = of_clk_get_by_name(np, "audio_axi_div");
    > + if (IS_ERR(clk_audio_axi_div))
    > + return PTR_ERR(clk_audio_axi_div);
    > +
    > + base = dev_get_drvdata(dev->parent);
    > + if (IS_ERR(base))
    > + return PTR_ERR(base);
    > +
    > + clk_hw_data = kzalloc(struct_size(clk_hw_data, hws, IMX8MP_CLK_AUDIOMIX_END), GFP_KERNEL);

    This line is long. Please limit length.

    > + if (WARN_ON(!clk_hw_data))
    > + return -ENOMEM;
    > +
    > + clk_hw_data->num = IMX8MP_CLK_AUDIOMIX_END;
    > + hws = clk_hw_data->hws;
    > +
    > + pm_runtime_enable(dev);
    > +
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_REF_SEL] = imx_dev_clk_hw_mux(dev, "sai_pll_ref_sel", base + 0x400, 0, 2, imx_sai_pll_ref_sels, ARRAY_SIZE(imx_sai_pll_ref_sels));
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL] = imx_dev_clk_hw_pll14xx(dev, "sai_pll", "sai_pll_ref_sel", base + 0x400, &imx_audiomix_sai_pll);
    > +
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_BYPASS] = imx_dev_clk_hw_mux_flags(dev, "sai_pll_bypass", base + 0x400, 4, 1, imx_sai_pll_bypass_sels, ARRAY_SIZE(imx_sai_pll_bypass_sels), CLK_SET_RATE_PARENT);
    > +
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_OUT] = imx_dev_clk_hw_gate(dev, "sai_pll_out", "sai_pll_bypass", base + 0x400, 13);
    > +
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI1_MCLK1_SEL] = imx_dev_clk_hw_mux_flags(dev, "sai1_mclk1_sel", base + 0x300, 0, 1, imx_sai1_mclk1_sels, ARRAY_SIZE(imx_sai1_mclk1_sels), CLK_SET_RATE_PARENT);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI1_MCLK2_SEL] = imx_dev_clk_hw_mux(dev, "sai1_mclk2_sel", base + 0x300, 1, 4, imx_sai_mclk2_sels, ARRAY_SIZE(imx_sai_mclk2_sels));
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI2_MCLK1_SEL] = imx_dev_clk_hw_mux_flags(dev, "sai2_mclk1_sel", base + 0x304, 0, 1, imx_sai2_mclk1_sels, ARRAY_SIZE(imx_sai2_mclk1_sels), CLK_SET_RATE_PARENT);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI2_MCLK2_SEL] = imx_dev_clk_hw_mux(dev, "sai2_mclk2_sel", base + 0x304, 1, 4, imx_sai_mclk2_sels, ARRAY_SIZE(imx_sai_mclk2_sels));
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI3_MCLK1_SEL] = imx_dev_clk_hw_mux_flags(dev, "sai3_mclk1_sel", base + 0x308, 0, 1, imx_sai3_mclk1_sels, ARRAY_SIZE(imx_sai3_mclk1_sels), CLK_SET_RATE_PARENT);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI3_MCLK2_SEL] = imx_dev_clk_hw_mux(dev, "sai3_mclk2_sel", base + 0x308, 1, 4, imx_sai_mclk2_sels, ARRAY_SIZE(imx_sai_mclk2_sels));
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI5_MCLK1_SEL] = imx_dev_clk_hw_mux(dev, "sai5_mclk1_sel", base + 0x30C, 0, 1, imx_sai5_mclk1_sels, ARRAY_SIZE(imx_sai5_mclk1_sels));
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI5_MCLK2_SEL] = imx_dev_clk_hw_mux(dev, "sai5_mclk2_sel", base + 0x30C, 1, 4, imx_sai_mclk2_sels, ARRAY_SIZE(imx_sai_mclk2_sels));
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI6_MCLK1_SEL] = imx_dev_clk_hw_mux(dev, "sai6_mclk1_sel", base + 0x310, 0, 1, imx_sai6_mclk1_sels, ARRAY_SIZE(imx_sai6_mclk1_sels));
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI6_MCLK2_SEL] = imx_dev_clk_hw_mux(dev, "sai6_mclk2_sel", base + 0x310, 1, 4, imx_sai_mclk2_sels, ARRAY_SIZE(imx_sai_mclk2_sels));
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI7_MCLK1_SEL] = imx_dev_clk_hw_mux(dev, "sai7_mclk1_sel", base + 0x314, 0, 1, imx_sai7_mclk1_sels, ARRAY_SIZE(imx_sai7_mclk1_sels));
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI7_MCLK2_SEL] = imx_dev_clk_hw_mux(dev, "sai7_mclk2_sel", base + 0x314, 1, 4, imx_sai_mclk2_sels, ARRAY_SIZE(imx_sai_mclk2_sels));
    > +
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI1_IPG] = imx_dev_clk_hw_gate(dev, "sai1_ipg_clk", "ipg_audio_root", base, 0);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI1_MCLK1] = imx_dev_clk_hw_gate(dev, "sai1_mclk1_clk", "sai1_mclk1_sel", base, 1);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI1_MCLK2] = imx_dev_clk_hw_gate(dev, "sai1_mclk2_clk", "sai1_mclk2_sel", base, 2);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI1_MCLK3] = imx_dev_clk_hw_gate(dev, "sai1_mclk3_clk", "sai_pll_out", base, 3);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI2_IPG] = imx_dev_clk_hw_gate(dev, "sai2_ipg_clk", "ipg_audio_root", base, 4);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI2_MCLK1] = imx_dev_clk_hw_gate(dev, "sai2_mclk1_clk", "sai2_mclk1_sel", base, 5);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI2_MCLK2] = imx_dev_clk_hw_gate(dev, "sai2_mclk2_clk", "sai2_mclk2_sel", base, 6);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI2_MCLK3] = imx_dev_clk_hw_gate(dev, "sai2_mclk3_clk", "sai_pll_out", base, 7);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI3_IPG] = imx_dev_clk_hw_gate(dev, "sai3_ipg_clk", "ipg_audio_root", base, 8);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI3_MCLK1] = imx_dev_clk_hw_gate(dev, "sai3_mclk1_clk", "sai3_mclk1_sel", base, 9);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI3_MCLK2] = imx_dev_clk_hw_gate(dev, "sai3_mclk2_clk", "sai3_mclk2_sel", base, 10);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI3_MCLK3] = imx_dev_clk_hw_gate(dev, "sai3_mclk3_clk", "sai_pll_out", base, 11);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI5_IPG] = imx_dev_clk_hw_gate(dev, "sai5_ipg_clk", "ipg_audio_root", base, 12);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI5_MCLK1] = imx_dev_clk_hw_gate(dev, "sai5_mclk1_clk", "sai5_mclk1_sel", base, 13);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI5_MCLK2] = imx_dev_clk_hw_gate(dev, "sai5_mclk2_clk", "sai5_mclk2_sel", base, 14);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI5_MCLK3] = imx_dev_clk_hw_gate(dev, "sai5_mclk3_clk", "sai_pll_out", base, 15);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI6_IPG] = imx_dev_clk_hw_gate(dev, "sai6_ipg_clk", "ipg_audio_root", base, 16);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI6_MCLK1] = imx_dev_clk_hw_gate(dev, "sai6_mclk1_clk", "sai6_mclk1_sel", base, 17);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI6_MCLK2] = imx_dev_clk_hw_gate(dev, "sai6_mclk2_clk", "sai6_mclk2_sel", base, 18);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI6_MCLK3] = imx_dev_clk_hw_gate(dev, "sai6_mclk3_clk", "sai_pll_out", base, 19);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI7_IPG] = imx_dev_clk_hw_gate(dev, "sai7_ipg_clk", "ipg_audio_root", base, 20);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI7_MCLK1] = imx_dev_clk_hw_gate(dev, "sai7_mclk1_clk", "sai7_mclk1_sel", base, 21);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI7_MCLK2] = imx_dev_clk_hw_gate(dev, "sai7_mclk2_clk", "sai7_mclk2_sel", base, 22);
    > + hws[IMX8MP_CLK_AUDIOMIX_SAI7_MCLK3] = imx_dev_clk_hw_gate(dev, "sai7_mclk3_clk", "sai_pll_out", base, 23);
    > + hws[IMX8MP_CLK_AUDIOMIX_ASRC_IPG] = imx_dev_clk_hw_gate(dev, "asrc_ipg_clk", "ipg_audio_root", base, 24);
    > + hws[IMX8MP_CLK_AUDIOMIX_PDM_IPG] = imx_dev_clk_hw_gate_shared(dev, "pdm_ipg_clk", "ipg_audio_root", base, 25, &shared_count_pdm);
    > + hws[IMX8MP_CLK_AUDIOMIX_PDM_ROOT] = imx_dev_clk_hw_gate_shared(dev, "pdm_root_clk", "pdm", base, 25, &shared_count_pdm);
    > +
    > + hws[IMX8MP_CLK_AUDIOMIX_SDMA2_ROOT] = imx_dev_clk_hw_gate(dev, "sdma2_root_clk", "ipg_audio_root", base, 26);
    > + hws[IMX8MP_CLK_AUDIOMIX_SDMA3_ROOT] = imx_dev_clk_hw_gate(dev, "sdma3_root_clk", "ipg_audio_root", base, 27);
    > + hws[IMX8MP_CLK_AUDIOMIX_SPBA2_ROOT] = imx_dev_clk_hw_gate(dev, "spba2_root_clk", "ipg_audio_root", base, 28);
    > + hws[IMX8MP_CLK_AUDIOMIX_DSP_ROOT] = imx_dev_clk_hw_gate(dev, "dsp_root_clk", "ipg_audio_root", base, 29);
    > + hws[IMX8MP_CLK_AUDIOMIX_DSPDBG_ROOT] = imx_dev_clk_hw_gate(dev, "dsp_dbg_clk", "ipg_audio_root", base, 30);
    > + hws[IMX8MP_CLK_AUDIOMIX_EARC_IPG] = imx_dev_clk_hw_gate(dev, "earc_ipg_clk", "ipg_audio_root", base, 31);
    > +
    > + hws[IMX8MP_CLK_AUDIOMIX_OCRAMA_IPG] = imx_dev_clk_hw_gate(dev, "ocram_a_ipg_clk", "ipg_audio_root", base + 4, 0);
    > + hws[IMX8MP_CLK_AUDIOMIX_AUD2HTX_IPG] = imx_dev_clk_hw_gate(dev, "aud2htx_ipg_clk", "ipg_audio_root", base + 4, 1);
    > + hws[IMX8MP_CLK_AUDIOMIX_EDMA_ROOT] = imx_dev_clk_hw_gate(dev, "edma_root_clk", "ipg_audio_root", base + 4, 2);
    > + hws[IMX8MP_CLK_AUDIOMIX_AUDPLL_ROOT] = imx_dev_clk_hw_gate(dev, "aud_pll_clk", "ipg_audio_root", base + 4, 3);
    > + hws[IMX8MP_CLK_AUDIOMIX_MU2_ROOT] = imx_dev_clk_hw_gate(dev, "mu2_root_clk", "ipg_audio_root", base + 4, 4);
    > + hws[IMX8MP_CLK_AUDIOMIX_MU3_ROOT] = imx_dev_clk_hw_gate(dev, "mu3_root_clk", "ipg_audio_root", base + 4, 5);
    > + hws[IMX8MP_CLK_AUDIOMIX_EARC_PHY] = imx_dev_clk_hw_gate(dev, "earc_phy_clk", "ipg_audio_root", base + 4, 6);

    These ones are OK because they're basically setting up an array and we
    can't help it.

    > +
    > + hws[IMX8MP_CLK_AUDIOMIX_PDM_SEL] = imx_dev_clk_hw_mux(dev, "pdm_sel", base + 0x318, 1, 4, imx_pdm_sels, ARRAY_SIZE(imx_pdm_sels));
    > +
    > + /* unbypass the pll */
    > + clk_hw_set_parent(hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_BYPASS], hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL]);

    But this is long again so please don't.

    > +
    > + imx_check_clk_hws(hws, IMX8MP_CLK_AUDIOMIX_END);
    > +
    > + of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
    > +
    > + return 0;
    > +}
    > +
    > +UNIVERSAL_DEV_PM_OPS(imx_audiomix_clk_pm_ops, imx_audiomix_clk_suspend,
    > + imx_audiomix_clk_resume, imx_audiomix_clk_resume);
    > +
    > +static const struct of_device_id imx_audiomix_clk_of_match[] = {
    > + { .compatible = "fsl,imx8mp-audiomix-clk" },
    > + { /* Sentinel */ },

    Nitpick: Drop comma after sentinel so that nothing can come after
    without causing compile error.

    > +};

    \
     
     \ /
      Last update: 2020-03-21 01:51    [W:4.693 / U:0.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site