Loading drivers/clk/Kconfig +9 −0 Original line number Diff line number Diff line Loading @@ -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 Loading drivers/clk/clk.c +231 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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, Loading Loading @@ -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 * Loading @@ -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); Loading drivers/clk/clk.h +4 −0 Original line number Diff line number Diff line Loading @@ -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 * Loading drivers/clk/qcom/clk-alpha-pll.c +86 −0 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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, Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading Loading @@ -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); Loading @@ -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); Loading Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading drivers/clk/qcom/clk-branch.c +62 −2 Original line number Diff line number Diff line // 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> Loading @@ -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) { Loading Loading @@ -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); Loading @@ -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); Loading Loading
drivers/clk/Kconfig +9 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
drivers/clk/clk.c +231 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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, Loading Loading @@ -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 * Loading @@ -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); Loading
drivers/clk/clk.h +4 −0 Original line number Diff line number Diff line Loading @@ -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 * Loading
drivers/clk/qcom/clk-alpha-pll.c +86 −0 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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, Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading Loading @@ -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); Loading @@ -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); Loading Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading
drivers/clk/qcom/clk-branch.c +62 −2 Original line number Diff line number Diff line // 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> Loading @@ -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) { Loading Loading @@ -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); Loading @@ -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); Loading