MLK-23751 clk: imx: Add audio PLL debug fs for K-divider monitor control
for userspace monitor control of the K-divider dynamically, we provide two interfaces to userspace: delta_k & pll_parameter 1): delta_k is used to adjust the K divider in PLL based on small steps; 2): the pll_parameter interface is used for get PLL's current M-divider, P-divider, S-divider & K-divider setting in PLL register example for the usage of these two interfaces: A): Get the current PLL setting of dividers: root@imx8mmevk:~# cat /sys/kernel/debug/audio_pll_monitor/audio_pll1/pll_parameter Mdiv: 0x106; Pdiv: 0x2; Sdiv: 0x3; Kdiv: 0x24dd B): if want to adjust the K-divider by a delta_k '1', then echo 0x1 > /sys/kernel/debug/audio_pll_monitor/audio_pll1/delta_k; root@imx8mmevk:~# cat /sys/kernel/debug/audio_pll_monitor/audio_pll1/pll_parameter Mdiv: 0x106; Pdiv: 0x2; Sdiv: 0x3; Kdiv: 0x24de C): if want to adjust the K-divider by a delta_k '-1', then echo -1 > /sys/kernel/debug/audio_pll_monitor/audio_pll1/delta_k; root@imx8mmevk:~# cat /sys/kernel/debug/audio_pll_monitor/audio_pll1/pll_parameter Mdiv: 0x106; Pdiv: 0x2; Sdiv: 0x3; Kdiv: 0x24dc Signed-off-by: Jacky Bai <ping.bai@nxp.com> Reviewed-by: Anson Huang <Anson.Huang@nxp.com>5.4-rM2-2.2.x-imx-squashed
parent
29bef0e553
commit
2590cdad64
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <dt-bindings/clock/imx8mm-clock.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
|
@ -714,3 +715,79 @@ static struct platform_driver imx8mm_clk_driver = {
|
|||
},
|
||||
};
|
||||
module_platform_driver(imx8mm_clk_driver);
|
||||
|
||||
/*
|
||||
* Debugfs interface for audio PLL K divider change dynamically.
|
||||
* Monitor control for the Audio PLL K-Divider
|
||||
*/
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
#define KDIV_MASK GENMASK(15, 0)
|
||||
#define MDIV_SHIFT 12
|
||||
#define MDIV_MASK GENMASK(21, 12)
|
||||
#define PDIV_SHIFT 4
|
||||
#define PDIV_MASK GENMASK(9, 4)
|
||||
#define SDIV_SHIFT 0
|
||||
#define SDIV_MASK GENMASK(2, 0)
|
||||
|
||||
static int pll_delta_k_set(void *data, u64 val)
|
||||
{
|
||||
struct clk_hw *hw;
|
||||
short int delta_k;
|
||||
|
||||
hw = __clk_get_hw(data);
|
||||
delta_k = (short int) (val & KDIV_MASK);
|
||||
|
||||
clk_set_delta_k(hw, val);
|
||||
|
||||
pr_debug("the delta k is %d\n", delta_k);
|
||||
return 0;
|
||||
}
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(delta_k_fops, NULL, pll_delta_k_set, "%lld\n");
|
||||
|
||||
static int pll_setting_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct clk *pll_clk;
|
||||
struct clk_hw *hw;
|
||||
u32 pll_div_ctrl0, pll_div_ctrl1;
|
||||
u32 mdiv, pdiv, sdiv, kdiv;
|
||||
|
||||
pll_clk = s->private;
|
||||
|
||||
hw = __clk_get_hw(pll_clk);
|
||||
|
||||
clk_get_pll_setting(hw, &pll_div_ctrl0, &pll_div_ctrl1);
|
||||
mdiv = (pll_div_ctrl0 & MDIV_MASK) >> MDIV_SHIFT;
|
||||
pdiv = (pll_div_ctrl0 & PDIV_MASK) >> PDIV_SHIFT;
|
||||
sdiv = (pll_div_ctrl0 & SDIV_MASK) >> SDIV_SHIFT;
|
||||
kdiv = (pll_div_ctrl1 & KDIV_MASK);
|
||||
|
||||
seq_printf(s, "Mdiv: 0x%x; Pdiv: 0x%x; Sdiv: 0x%x; Kdiv: 0x%x\n",
|
||||
mdiv, pdiv, sdiv, kdiv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DEFINE_SHOW_ATTRIBUTE(pll_setting);
|
||||
|
||||
static int __init dfll_debug_init(void)
|
||||
{
|
||||
struct dentry *root, *audio_pll1, *audio_pll2;
|
||||
|
||||
/* create a root dir for audio pll monitor */
|
||||
root = debugfs_create_dir("audio_pll_monitor", NULL);
|
||||
audio_pll1 = debugfs_create_dir("audio_pll1", root);
|
||||
audio_pll2 = debugfs_create_dir("audio_pll2", root);
|
||||
|
||||
debugfs_create_file_unsafe("delta_k", 0444, audio_pll1,
|
||||
clks[IMX8MM_AUDIO_PLL1], &delta_k_fops);
|
||||
debugfs_create_file("pll_parameter", 0x444, audio_pll1,
|
||||
clks[IMX8MM_AUDIO_PLL1], &pll_setting_fops);
|
||||
debugfs_create_file_unsafe("delta_k", 0444, audio_pll2,
|
||||
clks[IMX8MM_AUDIO_PLL2], &delta_k_fops);
|
||||
debugfs_create_file("pll_parameter", 0x444, audio_pll2,
|
||||
clks[IMX8MM_AUDIO_PLL2], &pll_setting_fops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
late_initcall(dfll_debug_init);
|
||||
|
|
|
@ -330,6 +330,26 @@ static void clk_pll14xx_unprepare(struct clk_hw *hw)
|
|||
writel_relaxed(val, pll->base + GNRL_CTL);
|
||||
}
|
||||
|
||||
void clk_set_delta_k(struct clk_hw *hw, short int delta_k)
|
||||
{
|
||||
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
|
||||
short int k;
|
||||
u32 val;
|
||||
|
||||
val = readl_relaxed(pll->base + 8);
|
||||
k = (val & KDIV_MASK) + delta_k;
|
||||
writel_relaxed(k << KDIV_SHIFT, pll->base + 8);
|
||||
}
|
||||
|
||||
void clk_get_pll_setting(struct clk_hw *hw, u32 *pll_div_ctrl0,
|
||||
u32 *pll_div_ctrl1)
|
||||
{
|
||||
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
|
||||
|
||||
*pll_div_ctrl0 = readl_relaxed(pll->base + 4);
|
||||
*pll_div_ctrl1 = readl_relaxed(pll->base + 8);
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_pll1416x_ops = {
|
||||
.prepare = clk_pll14xx_prepare,
|
||||
.unprepare = clk_pll14xx_unprepare,
|
||||
|
|
|
@ -557,4 +557,7 @@ struct clk_hw *imx_clk_divider_gate(const char *name, const char *parent_name,
|
|||
unsigned long flags, void __iomem *reg, u8 shift, u8 width,
|
||||
u8 clk_divider_flags, const struct clk_div_table *table,
|
||||
spinlock_t *lock);
|
||||
|
||||
void clk_set_delta_k(struct clk_hw *hw, short int delta_k);
|
||||
void clk_get_pll_setting(struct clk_hw *hw, u32 *pll_div_ctrl0, u32 *pll_div_ctrl1);
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue