mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-15 01:01:56 -04:00
Merge "clk: qcom: Add additional clock debugfs support"
This commit is contained in:
commit
365ba81c39
13 changed files with 777 additions and 5 deletions
|
|
@ -23,6 +23,15 @@ config COMMON_CLK
|
|||
menu "Common Clock Framework"
|
||||
depends on COMMON_CLK
|
||||
|
||||
config COMMON_CLK_QCOM_DEBUG
|
||||
bool "QCOM clock debug features"
|
||||
depends on DEBUG_FS && QGKI
|
||||
help
|
||||
Support for QCOM debug features. These features include
|
||||
modifications to existing debugfs nodes to make them writable (e.g.
|
||||
clk_enable_count, clk_rate), as well as new debugfs nodes (e.g.
|
||||
clk_enabled_list, debug_suspend, trace_clocks).
|
||||
|
||||
config COMMON_CLK_WM831X
|
||||
tristate "Clock driver for WM831x/2x PMICs"
|
||||
depends on MFD_WM831X
|
||||
|
|
|
|||
|
|
@ -3127,6 +3127,76 @@ static int clk_max_rate_show(struct seq_file *s, void *data)
|
|||
}
|
||||
DEFINE_SHOW_ATTRIBUTE(clk_max_rate);
|
||||
|
||||
static int clock_debug_rate_set(void *data, u64 val)
|
||||
{
|
||||
struct clk_core *core = data;
|
||||
int ret;
|
||||
|
||||
ret = clk_set_rate(core->hw->clk, val);
|
||||
if (ret)
|
||||
pr_err("clk_set_rate(%lu) failed (%d)\n",
|
||||
(unsigned long)val, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int clock_debug_rate_get(void *data, u64 *val)
|
||||
{
|
||||
struct clk_core *core = data;
|
||||
|
||||
*val = clk_get_rate(core->hw->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(clock_rate_fops, clock_debug_rate_get,
|
||||
clock_debug_rate_set, "%llu\n");
|
||||
|
||||
static ssize_t clock_parent_read(struct file *filp, char __user *ubuf,
|
||||
size_t cnt, loff_t *ppos)
|
||||
{
|
||||
char name[256] = {0};
|
||||
struct clk_core *core = filp->private_data;
|
||||
struct clk_core *p = core->hw->core->parent;
|
||||
|
||||
snprintf(name, sizeof(name), "%s\n", p ? p->name : "None\n");
|
||||
|
||||
return simple_read_from_buffer(ubuf, cnt, ppos, name, strlen(name));
|
||||
}
|
||||
|
||||
static const struct file_operations clock_parent_fops = {
|
||||
.open = simple_open,
|
||||
.read = clock_parent_read,
|
||||
};
|
||||
|
||||
static int clock_debug_enable_set(void *data, u64 val)
|
||||
{
|
||||
struct clk_core *core = data;
|
||||
int rc = 0;
|
||||
|
||||
if (val)
|
||||
rc = clk_prepare_enable(core->hw->clk);
|
||||
else
|
||||
clk_disable_unprepare(core->hw->clk);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int clock_debug_enable_get(void *data, u64 *val)
|
||||
{
|
||||
struct clk_core *core = data;
|
||||
int enabled = 0;
|
||||
|
||||
enabled = core->enable_count;
|
||||
|
||||
*val = enabled;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(clock_enable_fops, clock_debug_enable_get,
|
||||
clock_debug_enable_set, "%lld\n");
|
||||
|
||||
static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
|
||||
{
|
||||
struct dentry *root;
|
||||
|
|
@ -3137,14 +3207,15 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
|
|||
root = debugfs_create_dir(core->name, pdentry);
|
||||
core->dentry = root;
|
||||
|
||||
debugfs_create_ulong("clk_rate", 0444, root, &core->rate);
|
||||
debugfs_create_file("clk_rate", 0444, root, core, &clock_rate_fops);
|
||||
debugfs_create_file("clk_min_rate", 0444, root, core, &clk_min_rate_fops);
|
||||
debugfs_create_file("clk_max_rate", 0444, root, core, &clk_max_rate_fops);
|
||||
debugfs_create_ulong("clk_accuracy", 0444, root, &core->accuracy);
|
||||
debugfs_create_u32("clk_phase", 0444, root, &core->phase);
|
||||
debugfs_create_file("clk_flags", 0444, root, core, &clk_flags_fops);
|
||||
debugfs_create_u32("clk_prepare_count", 0444, root, &core->prepare_count);
|
||||
debugfs_create_u32("clk_enable_count", 0444, root, &core->enable_count);
|
||||
debugfs_create_file("clk_enable_count", 0444, root, core,
|
||||
&clock_enable_fops);
|
||||
debugfs_create_u32("clk_protect_count", 0444, root, &core->protect_count);
|
||||
debugfs_create_u32("clk_notifier_count", 0444, root, &core->notifier_count);
|
||||
debugfs_create_file("clk_duty_cycle", 0444, root, core,
|
||||
|
|
@ -3196,6 +3267,156 @@ static void clk_debug_unregister(struct clk_core *core)
|
|||
mutex_unlock(&clk_debug_lock);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
#define clock_debug_output(m, fmt, ...) \
|
||||
do { \
|
||||
if (m) \
|
||||
seq_printf(m, fmt, ##__VA_ARGS__); \
|
||||
else \
|
||||
pr_info(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
static int clock_debug_print_clock(struct clk_core *c, struct seq_file *s)
|
||||
{
|
||||
char *start = "\t";
|
||||
struct clk *clk;
|
||||
|
||||
if (!c || !c->prepare_count)
|
||||
return 0;
|
||||
|
||||
clk = c->hw->clk;
|
||||
|
||||
do {
|
||||
c = clk->core;
|
||||
if (c->ops->list_rate_vdd_level)
|
||||
clock_debug_output(s, "%s%s:%u:%u [%ld, %d]", start,
|
||||
c->name,
|
||||
c->prepare_count,
|
||||
c->enable_count,
|
||||
c->rate,
|
||||
c->ops->list_rate_vdd_level(c->hw, c->rate));
|
||||
else
|
||||
clock_debug_output(s, "%s%s:%u:%u [%ld]", start,
|
||||
c->name,
|
||||
c->prepare_count,
|
||||
c->enable_count,
|
||||
c->rate);
|
||||
start = " -> ";
|
||||
} while (s && (clk = clk_get_parent(clk)));
|
||||
|
||||
if (s)
|
||||
clock_debug_output(s, "\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* clock_debug_print_enabled_clocks() - Print names of enabled clocks
|
||||
*/
|
||||
static void clock_debug_print_enabled_clocks(struct seq_file *s)
|
||||
{
|
||||
struct clk_core *core;
|
||||
int cnt = 0;
|
||||
|
||||
clock_debug_output(s, "Enabled clocks:\n");
|
||||
|
||||
hlist_for_each_entry(core, &clk_debug_list, debug_node)
|
||||
cnt += clock_debug_print_clock(core, s);
|
||||
|
||||
if (cnt)
|
||||
clock_debug_output(s, "Enabled clock count: %d\n", cnt);
|
||||
else
|
||||
clock_debug_output(s, "No clocks enabled.\n");
|
||||
}
|
||||
|
||||
static int enabled_clocks_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
mutex_lock(&clk_debug_lock);
|
||||
clock_debug_print_enabled_clocks(s);
|
||||
mutex_unlock(&clk_debug_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enabled_clocks_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, enabled_clocks_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations clk_enabled_list_fops = {
|
||||
.open = enabled_clocks_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
static u32 debug_suspend;
|
||||
|
||||
/*
|
||||
* Print the names of all enabled clocks and their parents if
|
||||
* debug_suspend is set from debugfs.
|
||||
*/
|
||||
void clock_debug_print_enabled(void)
|
||||
{
|
||||
if (likely(!debug_suspend))
|
||||
return;
|
||||
|
||||
if (!mutex_trylock(&clk_debug_lock))
|
||||
return;
|
||||
|
||||
clock_debug_print_enabled_clocks(NULL);
|
||||
mutex_unlock(&clk_debug_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(clock_debug_print_enabled);
|
||||
|
||||
static void clk_state_subtree(struct clk_core *c)
|
||||
{
|
||||
int vdd_level = 0;
|
||||
struct clk_core *child;
|
||||
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
if (c->ops->list_rate_vdd_level)
|
||||
vdd_level = c->ops->list_rate_vdd_level(c->hw, c->rate);
|
||||
|
||||
trace_clk_state(c->name, c->prepare_count, c->enable_count,
|
||||
c->rate, vdd_level);
|
||||
|
||||
hlist_for_each_entry(child, &c->children, child_node)
|
||||
clk_state_subtree(child);
|
||||
}
|
||||
|
||||
static int clk_state_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct clk_core *c;
|
||||
struct hlist_head **lists = (struct hlist_head **)s->private;
|
||||
|
||||
clk_prepare_lock();
|
||||
|
||||
for (; *lists; lists++)
|
||||
hlist_for_each_entry(c, *lists, child_node)
|
||||
clk_state_subtree(c);
|
||||
|
||||
clk_prepare_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int clk_state_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, clk_state_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations clk_state_fops = {
|
||||
.open = clk_state_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* clk_debug_init - lazily populate the debugfs clk directory
|
||||
*
|
||||
|
|
@ -3220,6 +3441,14 @@ static int __init clk_debug_init(void)
|
|||
debugfs_create_file("clk_orphan_dump", 0444, rootdir, &orphan_list,
|
||||
&clk_dump_fops);
|
||||
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
debugfs_create_file("clk_enabled_list", 0444, rootdir,
|
||||
&clk_debug_list, &clk_enabled_list_fops);
|
||||
debugfs_create_u32("debug_suspend", 0644, rootdir, &debug_suspend);
|
||||
debugfs_create_file("trace_clocks", 0444, rootdir, &all_lists,
|
||||
&clk_state_fops);
|
||||
#endif
|
||||
|
||||
mutex_lock(&clk_debug_lock);
|
||||
hlist_for_each_entry(core, &clk_debug_list, debug_node)
|
||||
clk_debug_create_one(core, rootdir);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@ struct clk_hw *clk_find_hw(const char *dev_id, const char *con_id);
|
|||
struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw,
|
||||
const char *dev_id, const char *con_id);
|
||||
void __clk_put(struct clk *clk);
|
||||
|
||||
/* Debugfs API to print the enabled clocks */
|
||||
void clock_debug_print_enabled(void);
|
||||
|
||||
#else
|
||||
/* All these casts to avoid ifdefs in clkdev... */
|
||||
static inline struct clk *
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/delay.h>
|
||||
|
||||
#include "clk-alpha-pll.h"
|
||||
#include "clk-debug.h"
|
||||
#include "common.h"
|
||||
|
||||
#define PLL_MODE(p) ((p)->offset + 0x0)
|
||||
|
|
@ -1331,6 +1332,53 @@ static void clk_zonda_5lpe_pll_disable(struct clk_hw *hw)
|
|||
return;
|
||||
}
|
||||
|
||||
static void clk_alpha_pll_list_registers(struct seq_file *f, struct clk_hw *hw)
|
||||
{
|
||||
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
|
||||
int size, i, val;
|
||||
|
||||
static struct clk_register_data data[] = {
|
||||
{"PLL_MODE", 0x0},
|
||||
{"PLL_L_VAL", 0x4},
|
||||
{"PLL_ALPHA_VAL", 0x8},
|
||||
{"PLL_ALPHA_VAL_U", 0xC},
|
||||
{"PLL_USER_CTL", 0x10},
|
||||
{"PLL_CONFIG_CTL", 0x18},
|
||||
};
|
||||
|
||||
static struct clk_register_data data1[] = {
|
||||
{"APSS_PLL_VOTE", 0x0},
|
||||
};
|
||||
|
||||
size = ARRAY_SIZE(data);
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
regmap_read(pll->clkr.regmap, pll->offset + data[i].offset,
|
||||
&val);
|
||||
seq_printf(f, "%20s: 0x%.8x\n", data[i].name, val);
|
||||
}
|
||||
|
||||
regmap_read(pll->clkr.regmap, pll->offset + data[0].offset, &val);
|
||||
|
||||
if (val & PLL_FSM_ENA) {
|
||||
regmap_read(pll->clkr.regmap, pll->clkr.enable_reg +
|
||||
data1[0].offset, &val);
|
||||
seq_printf(f, "%20s: 0x%.8x\n", data1[0].name, val);
|
||||
}
|
||||
}
|
||||
|
||||
static struct clk_regmap_ops clk_alpha_pll_regmap_ops = {
|
||||
.list_registers = clk_alpha_pll_list_registers,
|
||||
};
|
||||
|
||||
static void clk_alpha_pll_init(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_regmap *rclk = to_clk_regmap(hw);
|
||||
|
||||
if (!rclk->ops)
|
||||
rclk->ops = &clk_alpha_pll_regmap_ops;
|
||||
}
|
||||
|
||||
const struct clk_ops clk_alpha_pll_ops = {
|
||||
.prepare = clk_prepare_regmap,
|
||||
.unprepare = clk_unprepare_regmap,
|
||||
|
|
@ -1342,6 +1390,11 @@ const struct clk_ops clk_alpha_pll_ops = {
|
|||
.recalc_rate = clk_alpha_pll_recalc_rate,
|
||||
.round_rate = clk_alpha_pll_round_rate,
|
||||
.set_rate = clk_alpha_pll_set_rate,
|
||||
.init = clk_alpha_pll_init,
|
||||
.debug_init = clk_common_debug_init,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_alpha_pll_ops);
|
||||
|
||||
|
|
@ -1356,6 +1409,9 @@ const struct clk_ops clk_alpha_pll_huayra_ops = {
|
|||
.recalc_rate = alpha_pll_huayra_recalc_rate,
|
||||
.round_rate = alpha_pll_huayra_round_rate,
|
||||
.set_rate = alpha_pll_huayra_set_rate,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_alpha_pll_huayra_ops);
|
||||
|
||||
|
|
@ -1370,6 +1426,10 @@ const struct clk_ops clk_alpha_pll_hwfsm_ops = {
|
|||
.recalc_rate = clk_alpha_pll_recalc_rate,
|
||||
.round_rate = clk_alpha_pll_round_rate,
|
||||
.set_rate = clk_alpha_pll_hwfsm_set_rate,
|
||||
.debug_init = clk_common_debug_init,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_alpha_pll_hwfsm_ops);
|
||||
|
||||
|
|
@ -1383,6 +1443,9 @@ const struct clk_ops clk_trion_fixed_pll_ops = {
|
|||
.is_enabled = clk_trion_pll_is_enabled,
|
||||
.recalc_rate = clk_trion_pll_recalc_rate,
|
||||
.round_rate = clk_trion_pll_round_rate,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_trion_fixed_pll_ops);
|
||||
|
||||
|
|
@ -1397,6 +1460,9 @@ const struct clk_ops clk_alpha_pll_zonda_ops = {
|
|||
.recalc_rate = clk_zonda_pll_recalc_rate,
|
||||
.round_rate = clk_alpha_pll_round_rate,
|
||||
.set_rate = clk_zonda_pll_set_rate,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL(clk_alpha_pll_zonda_ops);
|
||||
|
||||
|
|
@ -1681,6 +1747,9 @@ const struct clk_ops clk_alpha_pll_fabia_ops = {
|
|||
.set_rate = alpha_pll_fabia_set_rate,
|
||||
.recalc_rate = alpha_pll_fabia_recalc_rate,
|
||||
.round_rate = clk_alpha_pll_round_rate,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_alpha_pll_fabia_ops);
|
||||
|
||||
|
|
@ -1694,6 +1763,9 @@ const struct clk_ops clk_alpha_pll_fixed_fabia_ops = {
|
|||
.is_enabled = clk_alpha_pll_is_enabled,
|
||||
.recalc_rate = alpha_pll_fabia_recalc_rate,
|
||||
.round_rate = clk_alpha_pll_round_rate,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_alpha_pll_fixed_fabia_ops);
|
||||
|
||||
|
|
@ -2476,6 +2548,9 @@ const struct clk_ops clk_alpha_pll_lucid_ops = {
|
|||
.recalc_rate = alpha_pll_lucid_recalc_rate,
|
||||
.round_rate = clk_alpha_pll_round_rate,
|
||||
.set_rate = alpha_pll_lucid_set_rate,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL(clk_alpha_pll_lucid_ops);
|
||||
|
||||
|
|
@ -2490,6 +2565,10 @@ const struct clk_ops clk_alpha_pll_lucid_5lpe_ops = {
|
|||
.recalc_rate = alpha_pll_lucid_recalc_rate,
|
||||
.round_rate = clk_alpha_pll_round_rate,
|
||||
.set_rate = alpha_pll_lucid_5lpe_set_rate,
|
||||
.debug_init = clk_common_debug_init,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL(clk_alpha_pll_lucid_5lpe_ops);
|
||||
|
||||
|
|
@ -2503,6 +2582,9 @@ const struct clk_ops clk_alpha_pll_fixed_lucid_ops = {
|
|||
.is_enabled = alpha_pll_lucid_is_enabled,
|
||||
.recalc_rate = alpha_pll_lucid_recalc_rate,
|
||||
.round_rate = clk_alpha_pll_round_rate,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL(clk_alpha_pll_fixed_lucid_ops);
|
||||
|
||||
|
|
@ -2523,6 +2605,10 @@ const struct clk_ops clk_alpha_pll_fixed_lucid_5lpe_ops = {
|
|||
.is_enabled = alpha_pll_lucid_is_enabled,
|
||||
.recalc_rate = alpha_pll_lucid_recalc_rate,
|
||||
.round_rate = clk_alpha_pll_round_rate,
|
||||
.debug_init = clk_common_debug_init,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL(clk_alpha_pll_fixed_lucid_5lpe_ops);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2013, 2016, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2013, 2016-2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "clk-branch.h"
|
||||
#include "clk-debug.h"
|
||||
#include "clk-regmap.h"
|
||||
|
||||
static bool clk_branch_in_hwcg_mode(const struct clk_branch *br)
|
||||
{
|
||||
|
|
@ -124,10 +125,17 @@ static void clk_branch_disable(struct clk_hw *hw)
|
|||
clk_branch_toggle(hw, false, clk_branch_check_halt);
|
||||
}
|
||||
|
||||
static void clk_branch_debug_init(struct clk_hw *hw, struct dentry *dentry)
|
||||
{
|
||||
clk_common_debug_init(hw, dentry);
|
||||
clk_debug_measure_add(hw, dentry);
|
||||
}
|
||||
|
||||
const struct clk_ops clk_branch_ops = {
|
||||
.enable = clk_branch_enable,
|
||||
.disable = clk_branch_disable,
|
||||
.is_enabled = clk_is_enabled_regmap,
|
||||
.debug_init = clk_branch_debug_init,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_branch_ops);
|
||||
|
||||
|
|
@ -141,17 +149,69 @@ static void clk_branch2_disable(struct clk_hw *hw)
|
|||
clk_branch_toggle(hw, false, clk_branch2_check_halt);
|
||||
}
|
||||
|
||||
static void clk_branch2_list_registers(struct seq_file *f, struct clk_hw *hw)
|
||||
{
|
||||
struct clk_branch *br = to_clk_branch(hw);
|
||||
struct clk_regmap *rclk = to_clk_regmap(hw);
|
||||
int size, i, val;
|
||||
|
||||
static struct clk_register_data data[] = {
|
||||
{"CBCR", 0x0},
|
||||
};
|
||||
|
||||
static struct clk_register_data data1[] = {
|
||||
{"APSS_VOTE", 0x0},
|
||||
{"APSS_SLEEP_VOTE", 0x4},
|
||||
};
|
||||
|
||||
size = ARRAY_SIZE(data);
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
regmap_read(br->clkr.regmap, br->halt_reg + data[i].offset,
|
||||
&val);
|
||||
seq_printf(f, "%20s: 0x%.8x\n", data[i].name, val);
|
||||
}
|
||||
|
||||
if ((br->halt_check & BRANCH_HALT_VOTED) &&
|
||||
!(br->halt_check & BRANCH_VOTED)) {
|
||||
if (rclk->enable_reg) {
|
||||
size = ARRAY_SIZE(data1);
|
||||
for (i = 0; i < size; i++) {
|
||||
regmap_read(br->clkr.regmap, rclk->enable_reg +
|
||||
data1[i].offset, &val);
|
||||
seq_printf(f, "%20s: 0x%.8x\n",
|
||||
data1[i].name, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct clk_regmap_ops clk_branch2_regmap_ops = {
|
||||
.list_registers = clk_branch2_list_registers,
|
||||
};
|
||||
|
||||
static void clk_branch2_init(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_regmap *rclk = to_clk_regmap(hw);
|
||||
|
||||
if (!rclk->ops)
|
||||
rclk->ops = &clk_branch2_regmap_ops;
|
||||
}
|
||||
|
||||
const struct clk_ops clk_branch2_ops = {
|
||||
.enable = clk_branch2_enable,
|
||||
.disable = clk_branch2_disable,
|
||||
.is_enabled = clk_is_enabled_regmap,
|
||||
.debug_init = clk_debug_measure_add,
|
||||
.init = clk_branch2_init,
|
||||
.debug_init = clk_branch_debug_init,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_branch2_ops);
|
||||
|
||||
const struct clk_ops clk_branch2_aon_ops = {
|
||||
.enable = clk_branch2_enable,
|
||||
.is_enabled = clk_is_enabled_regmap,
|
||||
.init = clk_branch2_init,
|
||||
.debug_init = clk_branch_debug_init,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_branch2_aon_ops);
|
||||
|
||||
|
|
|
|||
|
|
@ -386,3 +386,177 @@ int map_debug_bases(struct platform_device *pdev, const char *base,
|
|||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(map_debug_bases);
|
||||
|
||||
static void clock_print_rate_max_by_level(struct clk_hw *hw,
|
||||
struct seq_file *s, int level)
|
||||
{
|
||||
struct clk_regmap *rclk = to_clk_regmap(hw);
|
||||
struct clk_vdd_class_data *vdd_data = &rclk->vdd_data;
|
||||
struct clk_vdd_class *vdd_class = vdd_data->vdd_class;
|
||||
int off, i, vdd_level, nregs = vdd_class->num_regulators;
|
||||
unsigned long rate;
|
||||
|
||||
rate = clk_get_rate(hw->clk);
|
||||
vdd_level = clk_find_vdd_level(hw, vdd_data, rate);
|
||||
|
||||
seq_printf(s, "%2s%10lu", vdd_level == level ? "[" : "",
|
||||
vdd_data->rate_max[level]);
|
||||
|
||||
for (i = 0; i < nregs; i++) {
|
||||
off = nregs*level + i;
|
||||
if (vdd_class->vdd_uv)
|
||||
seq_printf(s, "%10u", vdd_class->vdd_uv[off]);
|
||||
}
|
||||
|
||||
if (vdd_level == level)
|
||||
seq_puts(s, "]");
|
||||
|
||||
seq_puts(s, "\n");
|
||||
}
|
||||
|
||||
static int rate_max_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct clk_hw *hw = s->private;
|
||||
struct clk_regmap *rclk = to_clk_regmap(hw);
|
||||
struct clk_vdd_class_data *vdd_data = &rclk->vdd_data;
|
||||
struct clk_vdd_class *vdd_class = vdd_data->vdd_class;
|
||||
int level = 0, i, nregs = vdd_class->num_regulators, vdd_level;
|
||||
char reg_name[10];
|
||||
unsigned long rate;
|
||||
|
||||
rate = clk_get_rate(hw->clk);
|
||||
vdd_level = clk_find_vdd_level(hw, vdd_data, rate);
|
||||
|
||||
if (vdd_level < 0) {
|
||||
seq_printf(s, "could not find_vdd_level for %s, %ld\n",
|
||||
clk_hw_get_name(hw), rate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
seq_printf(s, "%12s", "");
|
||||
for (i = 0; i < nregs; i++) {
|
||||
snprintf(reg_name, ARRAY_SIZE(reg_name), "reg %d", i);
|
||||
seq_printf(s, "%10s", reg_name);
|
||||
}
|
||||
|
||||
seq_printf(s, "\n%12s", "freq");
|
||||
for (i = 0; i < nregs; i++)
|
||||
seq_printf(s, "%10s", "uV");
|
||||
|
||||
seq_puts(s, "\n");
|
||||
|
||||
for (level = 0; level < vdd_data->num_rate_max; level++)
|
||||
clock_print_rate_max_by_level(hw, s, level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rate_max_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, rate_max_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations rate_max_fops = {
|
||||
.open = rate_max_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
static int list_rates_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct clk_hw *hw = s->private;
|
||||
struct clk_regmap *rclk = to_clk_regmap(hw);
|
||||
struct clk_vdd_class_data *vdd_data = &rclk->vdd_data;
|
||||
struct clk_vdd_class *vdd_class = vdd_data->vdd_class;
|
||||
int i = 0, level;
|
||||
unsigned long rate, rate_max = 0;
|
||||
|
||||
/* Find max frequency supported within voltage constraints. */
|
||||
if (!vdd_class) {
|
||||
rate_max = ULONG_MAX;
|
||||
} else {
|
||||
for (level = 0; level < vdd_data->num_rate_max; level++)
|
||||
if (vdd_data->rate_max[level])
|
||||
rate_max = vdd_data->rate_max[level];
|
||||
}
|
||||
|
||||
/*
|
||||
* List supported frequencies <= rate_max. Higher frequencies may
|
||||
* appear in the frequency table, but are not valid and should not
|
||||
* be listed.
|
||||
*/
|
||||
while (!IS_ERR_VALUE(rate = rclk->ops->list_rate(hw, i++, rate_max))) {
|
||||
if (rate <= 0)
|
||||
break;
|
||||
seq_printf(s, "%lu\n", rate);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int list_rates_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, list_rates_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations list_rates_fops = {
|
||||
.open = list_rates_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
static void clk_debug_print_hw(struct clk_hw *hw, struct seq_file *f)
|
||||
{
|
||||
struct clk_regmap *rclk = to_clk_regmap(hw);
|
||||
|
||||
if (IS_ERR_OR_NULL(hw))
|
||||
return;
|
||||
|
||||
clk_debug_print_hw(clk_hw_get_parent(hw), f);
|
||||
|
||||
seq_printf(f, "%s\n", clk_hw_get_name(hw));
|
||||
|
||||
if (rclk->ops && rclk->ops->list_registers)
|
||||
rclk->ops->list_registers(f, hw);
|
||||
}
|
||||
|
||||
static int print_hw_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct clk_hw *hw = m->private;
|
||||
|
||||
clk_debug_print_hw(hw, m);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_hw_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, print_hw_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations clock_print_hw_fops = {
|
||||
.open = print_hw_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
void clk_common_debug_init(struct clk_hw *hw, struct dentry *dentry)
|
||||
{
|
||||
struct clk_regmap *rclk = to_clk_regmap(hw);
|
||||
|
||||
if (rclk->vdd_data.vdd_class)
|
||||
debugfs_create_file("clk_rate_max", 0444, dentry, hw,
|
||||
&rate_max_fops);
|
||||
|
||||
if (rclk->ops && rclk->ops->list_rate)
|
||||
debugfs_create_file("clk_list_rates", 0444, dentry, hw,
|
||||
&list_rates_fops);
|
||||
|
||||
debugfs_create_file("clk_print_regs", 0444, dentry, hw,
|
||||
&clock_print_hw_fops);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -90,4 +90,6 @@ void clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry);
|
|||
int map_debug_bases(struct platform_device *pdev, const char *base,
|
||||
struct clk_debug_mux *mux);
|
||||
|
||||
void clk_common_debug_init(struct clk_hw *hw, struct dentry *dentry);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "clk-rcg.h"
|
||||
#include "common.h"
|
||||
#include "clk-debug.h"
|
||||
|
||||
#define CMD_REG 0x0
|
||||
#define CMD_UPDATE BIT(0)
|
||||
|
|
@ -444,6 +445,61 @@ static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f)
|
|||
return update_config(rcg);
|
||||
}
|
||||
|
||||
static void clk_rcg2_list_registers(struct seq_file *f, struct clk_hw *hw)
|
||||
{
|
||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||
int i = 0, size = 0, val;
|
||||
|
||||
static struct clk_register_data data[] = {
|
||||
{"CMD_RCGR", 0x0},
|
||||
{"CFG_RCGR", 0x4},
|
||||
};
|
||||
|
||||
static struct clk_register_data data1[] = {
|
||||
{"CMD_RCGR", 0x0},
|
||||
{"CFG_RCGR", 0x4},
|
||||
{"M_VAL", 0x8},
|
||||
{"N_VAL", 0xC},
|
||||
{"D_VAL", 0x10},
|
||||
};
|
||||
|
||||
if (rcg->mnd_width) {
|
||||
size = ARRAY_SIZE(data1);
|
||||
for (i = 0; i < size; i++) {
|
||||
regmap_read(rcg->clkr.regmap, (rcg->cmd_rcgr +
|
||||
data1[i].offset), &val);
|
||||
seq_printf(f, "%20s: 0x%.8x\n", data1[i].name, val);
|
||||
}
|
||||
} else {
|
||||
size = ARRAY_SIZE(data);
|
||||
for (i = 0; i < size; i++) {
|
||||
regmap_read(rcg->clkr.regmap, (rcg->cmd_rcgr +
|
||||
data[i].offset), &val);
|
||||
seq_printf(f, "%20s: 0x%.8x\n", data[i].name, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the nth supported frequency for a given clock. */
|
||||
static long clk_rcg2_list_rate(struct clk_hw *hw, unsigned int n,
|
||||
unsigned long fmax)
|
||||
{
|
||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||
const struct freq_tbl *f = rcg->freq_tbl;
|
||||
size_t freq_tbl_size = 0;
|
||||
|
||||
if (!f)
|
||||
return -ENXIO;
|
||||
|
||||
for (; f->freq; f++)
|
||||
freq_tbl_size++;
|
||||
|
||||
if (n > freq_tbl_size - 1)
|
||||
return -EINVAL;
|
||||
|
||||
return (rcg->freq_tbl + n)->freq;
|
||||
}
|
||||
|
||||
static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
enum freq_policy policy)
|
||||
{
|
||||
|
|
@ -628,6 +684,19 @@ static void clk_rcg2_disable(struct clk_hw *hw)
|
|||
clk_rcg2_clear_force_enable(hw);
|
||||
}
|
||||
|
||||
static struct clk_regmap_ops clk_rcg2_regmap_ops = {
|
||||
.list_rate = clk_rcg2_list_rate,
|
||||
.list_registers = clk_rcg2_list_registers,
|
||||
};
|
||||
|
||||
static void clk_rcg2_init(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_regmap *rclk = to_clk_regmap(hw);
|
||||
|
||||
if (!rclk->ops)
|
||||
rclk->ops = &clk_rcg2_regmap_ops;
|
||||
}
|
||||
|
||||
const struct clk_ops clk_rcg2_ops = {
|
||||
.prepare = clk_prepare_regmap,
|
||||
.unprepare = clk_unprepare_regmap,
|
||||
|
|
@ -642,6 +711,11 @@ const struct clk_ops clk_rcg2_ops = {
|
|||
.determine_rate = clk_rcg2_determine_rate,
|
||||
.set_rate = clk_rcg2_set_rate,
|
||||
.set_rate_and_parent = clk_rcg2_set_rate_and_parent,
|
||||
.init = clk_rcg2_init,
|
||||
.debug_init = clk_common_debug_init,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_rcg2_ops);
|
||||
|
||||
|
|
@ -657,6 +731,11 @@ const struct clk_ops clk_rcg2_floor_ops = {
|
|||
.determine_rate = clk_rcg2_determine_floor_rate,
|
||||
.set_rate = clk_rcg2_set_floor_rate,
|
||||
.set_rate_and_parent = clk_rcg2_set_floor_rate_and_parent,
|
||||
.init = clk_rcg2_init,
|
||||
.debug_init = clk_common_debug_init,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_rcg2_floor_ops);
|
||||
|
||||
|
|
@ -790,6 +869,11 @@ const struct clk_ops clk_edp_pixel_ops = {
|
|||
.set_rate = clk_edp_pixel_set_rate,
|
||||
.set_rate_and_parent = clk_edp_pixel_set_rate_and_parent,
|
||||
.determine_rate = clk_edp_pixel_determine_rate,
|
||||
.init = clk_rcg2_init,
|
||||
.debug_init = clk_common_debug_init,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_edp_pixel_ops);
|
||||
|
||||
|
|
@ -854,6 +938,11 @@ const struct clk_ops clk_byte_ops = {
|
|||
.set_rate = clk_byte_set_rate,
|
||||
.set_rate_and_parent = clk_byte_set_rate_and_parent,
|
||||
.determine_rate = clk_byte_determine_rate,
|
||||
.init = clk_rcg2_init,
|
||||
.debug_init = clk_common_debug_init,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_byte_ops);
|
||||
|
||||
|
|
@ -928,6 +1017,11 @@ const struct clk_ops clk_byte2_ops = {
|
|||
.set_rate = clk_byte2_set_rate,
|
||||
.set_rate_and_parent = clk_byte2_set_rate_and_parent,
|
||||
.determine_rate = clk_byte2_determine_rate,
|
||||
.init = clk_rcg2_init,
|
||||
.debug_init = clk_common_debug_init,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_byte2_ops);
|
||||
|
||||
|
|
@ -1022,6 +1116,11 @@ const struct clk_ops clk_pixel_ops = {
|
|||
.set_rate = clk_pixel_set_rate,
|
||||
.set_rate_and_parent = clk_pixel_set_rate_and_parent,
|
||||
.determine_rate = clk_pixel_determine_rate,
|
||||
.init = clk_rcg2_init,
|
||||
.debug_init = clk_common_debug_init,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_pixel_ops);
|
||||
|
||||
|
|
@ -1108,6 +1207,11 @@ const struct clk_ops clk_dp_ops = {
|
|||
.set_rate = clk_dp_set_rate,
|
||||
.set_rate_and_parent = clk_dp_set_rate_and_parent,
|
||||
.determine_rate = clk_dp_determine_rate,
|
||||
.init = clk_rcg2_init,
|
||||
.debug_init = clk_common_debug_init,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL(clk_dp_ops);
|
||||
|
||||
|
|
@ -1203,6 +1307,11 @@ const struct clk_ops clk_gfx3d_ops = {
|
|||
.set_rate = clk_gfx3d_set_rate,
|
||||
.set_rate_and_parent = clk_gfx3d_set_rate_and_parent,
|
||||
.determine_rate = clk_gfx3d_determine_rate,
|
||||
.init = clk_rcg2_init,
|
||||
.debug_init = clk_common_debug_init,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_gfx3d_ops);
|
||||
|
||||
|
|
@ -1314,6 +1423,11 @@ const struct clk_ops clk_rcg2_shared_ops = {
|
|||
.determine_rate = clk_rcg2_determine_rate,
|
||||
.set_rate = clk_rcg2_shared_set_rate,
|
||||
.set_rate_and_parent = clk_rcg2_shared_set_rate_and_parent,
|
||||
.init = clk_rcg2_init,
|
||||
.debug_init = clk_common_debug_init,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_rcg2_shared_ops);
|
||||
|
||||
|
|
@ -1458,6 +1572,11 @@ static const struct clk_ops clk_rcg2_dfs_ops = {
|
|||
.get_parent = clk_rcg2_get_parent,
|
||||
.determine_rate = clk_rcg2_dfs_determine_rate,
|
||||
.recalc_rate = clk_rcg2_dfs_recalc_rate,
|
||||
.init = clk_rcg2_init,
|
||||
.debug_init = clk_common_debug_init,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int clk_rcg2_enable_dfs(const struct clk_rcg_dfs_data *data,
|
||||
|
|
@ -1601,5 +1720,10 @@ const struct clk_ops clk_rcg2_dependent_ops = {
|
|||
.determine_rate = clk_rcg2_dependent_determine_rate,
|
||||
.set_rate = clk_rcg2_dependent_set_rate,
|
||||
.set_rate_and_parent = clk_rcg2_dependent_set_rate_and_parent,
|
||||
.init = clk_rcg2_init,
|
||||
.debug_init = clk_common_debug_init,
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
.list_rate_vdd_level = clk_list_rate_vdd_level,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL(clk_rcg2_dependent_ops);
|
||||
|
|
|
|||
|
|
@ -5,10 +5,28 @@
|
|||
#define __QCOM_CLK_REGMAP_H__
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include "vdd-class.h"
|
||||
|
||||
struct regmap;
|
||||
|
||||
/**
|
||||
* struct clk_regmap_ops - Operations for clk_regmap.
|
||||
*
|
||||
* @list_registers: Queries the hardware to get the current register contents.
|
||||
* This callback is optional.
|
||||
*
|
||||
* @list_rate: On success, return the nth supported frequency for a given
|
||||
* clock that is below rate_max. Return -ENXIO in case there is
|
||||
* no frequency table.
|
||||
*/
|
||||
struct clk_regmap_ops {
|
||||
void (*list_registers)(struct seq_file *f,
|
||||
struct clk_hw *hw);
|
||||
long (*list_rate)(struct clk_hw *hw, unsigned int n,
|
||||
unsigned long rate_max);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct clk_regmap - regmap supporting clock
|
||||
* @hw: handle between common and hardware-specific interfaces
|
||||
|
|
@ -19,7 +37,9 @@ struct regmap;
|
|||
* @enable_is_inverted: flag to indicate set enable_mask bits to disable
|
||||
* when using clock_enable_regmap and friends APIs.
|
||||
* @vdd_data: struct containing vdd-class data for this clock
|
||||
* @ops: operations this clk_regmap supports
|
||||
*/
|
||||
|
||||
struct clk_regmap {
|
||||
struct clk_hw hw;
|
||||
struct clk_hw *dependent_hw;
|
||||
|
|
@ -28,6 +48,7 @@ struct clk_regmap {
|
|||
unsigned int enable_mask;
|
||||
bool enable_is_inverted;
|
||||
struct clk_vdd_class_data vdd_data;
|
||||
struct clk_regmap_ops *ops;
|
||||
};
|
||||
#define to_clk_regmap(_hw) container_of(_hw, struct clk_regmap, hw)
|
||||
|
||||
|
|
@ -42,4 +63,9 @@ int clk_post_change_regmap(struct clk_hw *hw, unsigned long old_rate,
|
|||
unsigned long cur_rate);
|
||||
int devm_clk_register_regmap(struct device *dev, struct clk_regmap *rclk);
|
||||
|
||||
struct clk_register_data {
|
||||
char *name;
|
||||
u32 offset;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include "vdd-class.h"
|
||||
#include "clk-regmap.h"
|
||||
|
||||
/*
|
||||
* Aggregate the vdd_class level votes and call regulator framework functions
|
||||
|
|
@ -169,3 +170,15 @@ int clk_find_vdd_level(struct clk_hw *hw,
|
|||
return level;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_find_vdd_level);
|
||||
|
||||
int clk_list_rate_vdd_level(struct clk_hw *hw, unsigned int rate)
|
||||
{
|
||||
struct clk_regmap *rclk = to_clk_regmap(hw);
|
||||
struct clk_vdd_class_data *vdd_data = &rclk->vdd_data;
|
||||
|
||||
if (!vdd_data->vdd_class)
|
||||
return 0;
|
||||
|
||||
return clk_find_vdd_level(hw, vdd_data, rate);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,5 +66,6 @@ int clk_find_vdd_level(struct clk_hw *hw, struct clk_vdd_class_data *vdd_data,
|
|||
unsigned long rate);
|
||||
int clk_vote_vdd_level(struct clk_vdd_class_data *vdd_class, int level);
|
||||
int clk_unvote_vdd_level(struct clk_vdd_class_data *vdd_class, int level);
|
||||
int clk_list_rate_vdd_level(struct clk_hw *hw, unsigned int rate);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -208,6 +208,10 @@ struct clk_duty {
|
|||
* requirements that were needed while the clock and its tree
|
||||
* was changing states. Returns 0 on success, -EERROR otherwise.
|
||||
*
|
||||
* @list_rate_vdd_level: Queries the required voltage level for the given rate.
|
||||
* The return value may not represent an exact voltage and instead
|
||||
* may be an abstract index or voltage "corner".
|
||||
*
|
||||
* The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
|
||||
* implementations to split any work between atomic (enable) and sleepable
|
||||
* (prepare) contexts. If enabling a clock requires code that might sleep,
|
||||
|
|
@ -259,6 +263,10 @@ struct clk_ops {
|
|||
int (*post_rate_change)(struct clk_hw *hw,
|
||||
unsigned long old_rate,
|
||||
unsigned long rate);
|
||||
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
|
||||
int (*list_rate_vdd_level)(struct clk_hw *hw,
|
||||
unsigned int rate);
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM clk
|
||||
|
|
@ -220,6 +220,42 @@ DEFINE_EVENT(clk_duty_cycle, clk_set_duty_cycle_complete,
|
|||
TP_ARGS(core, duty)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(clk_state_dump,
|
||||
|
||||
TP_PROTO(const char *name, unsigned int prepare_count,
|
||||
unsigned int enable_count, unsigned long rate, unsigned int vdd_level),
|
||||
|
||||
TP_ARGS(name, prepare_count, enable_count, rate, vdd_level),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(name, name)
|
||||
__field(unsigned int, prepare_count)
|
||||
__field(unsigned int, enable_count)
|
||||
__field(unsigned long, rate)
|
||||
__field(unsigned int, vdd_level)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(name, name);
|
||||
__entry->prepare_count = prepare_count;
|
||||
__entry->enable_count = enable_count;
|
||||
__entry->rate = rate;
|
||||
__entry->vdd_level = vdd_level;
|
||||
),
|
||||
|
||||
TP_printk("%s\tprepare:enable cnt [%u:%u]\trate: vdd_level [%lu:%u]",
|
||||
__get_str(name), __entry->prepare_count, __entry->enable_count,
|
||||
__entry->rate, __entry->vdd_level)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(clk_state_dump, clk_state,
|
||||
|
||||
TP_PROTO(const char *name, unsigned int prepare_count,
|
||||
unsigned int enable_count, unsigned long rate, unsigned int vdd_level),
|
||||
|
||||
TP_ARGS(name, prepare_count, enable_count, rate, vdd_level)
|
||||
);
|
||||
|
||||
#endif /* _TRACE_CLK_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
|
|
|
|||
Loading…
Reference in a new issue