1
0
Fork 0

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
Jacky Bai 2020-04-07 11:15:15 +08:00
parent 29bef0e553
commit 2590cdad64
3 changed files with 100 additions and 0 deletions

View File

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

View File

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

View File

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