summaryrefslogtreecommitdiff
path: root/drivers/clk/qcom/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/qcom/common.c')
-rw-r--r--drivers/clk/qcom/common.c239
1 files changed, 3 insertions, 236 deletions
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
index f6ce3106ab6f..8ecb207a97e5 100644
--- a/drivers/clk/qcom/common.c
+++ b/drivers/clk/qcom/common.c
@@ -1,5 +1,7 @@
/*
- * Copyright (c) 2013-2014, 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 2016-2017,
+ *
+ * The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -287,239 +289,4 @@ int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc)
}
EXPORT_SYMBOL_GPL(qcom_cc_probe);
-/* Debugfs Support */
-static struct clk_hw *measure;
-
-DEFINE_SPINLOCK(clk_reg_lock);
-
-/* Sample clock for 'ticks' reference clock ticks. */
-static u32 run_measurement(unsigned ticks, struct regmap *regmap,
- u32 ctl_reg, u32 status_reg)
-{
- u32 regval;
-
- /* Stop counters and set the XO4 counter start value. */
- regmap_write(regmap, ctl_reg, ticks);
-
- regmap_read(regmap, status_reg, &regval);
-
- /* Wait for timer to become ready. */
- while ((regval & BIT(25)) != 0) {
- cpu_relax();
- regmap_read(regmap, status_reg, &regval);
- }
-
- /* Run measurement and wait for completion. */
- regmap_write(regmap, ctl_reg, (BIT(20)|ticks));
- regmap_read(regmap, ctl_reg, &regval);
-
- regmap_read(regmap, status_reg, &regval);
-
- while ((regval & BIT(25)) == 0) {
- cpu_relax();
- regmap_read(regmap, status_reg, &regval);
- }
-
- /* Return measured ticks. */
- regmap_read(regmap, status_reg, &regval);
- regval &= BM(24, 0);
-
- return regval;
-}
-
-/*
- * Perform a hardware rate measurement for a given clock.
- * FOR DEBUG USE ONLY: Measurements take ~15 ms!
- */
-static unsigned long clk_debug_mux_measure_rate(struct clk_hw *hw)
-{
- unsigned long flags, ret = 0;
- u32 gcc_xo4_reg, sample_ticks = 0x10000, multiplier;
- u64 raw_count_short, raw_count_full;
- struct clk_debug_mux *meas = to_clk_measure(hw);
- struct measure_clk_data *data = meas->priv;
-
- clk_prepare_enable(data->cxo);
-
- spin_lock_irqsave(&clk_reg_lock, flags);
-
- multiplier = meas->multiplier + 1;
-
- /* Enable CXO/4 and RINGOSC branch. */
- regmap_read(meas->regmap[GCC], data->xo_div4_cbcr, &gcc_xo4_reg);
- gcc_xo4_reg |= BIT(0);
- regmap_write(meas->regmap[GCC], data->xo_div4_cbcr, gcc_xo4_reg);
-
- /*
- * The ring oscillator counter will not reset if the measured clock
- * is not running. To detect this, run a short measurement before
- * the full measurement. If the raw results of the two are the same
- * then the clock must be off.
- */
-
- /* Run a short measurement. (~1 ms) */
- raw_count_short = run_measurement(0x1000, meas->regmap[GCC],
- data->ctl_reg, data->status_reg);
-
- /* Run a full measurement. (~14 ms) */
- raw_count_full = run_measurement(sample_ticks, meas->regmap[GCC],
- data->ctl_reg, data->status_reg);
-
- gcc_xo4_reg &= ~BIT(0);
- regmap_write(meas->regmap[GCC], data->xo_div4_cbcr, gcc_xo4_reg);
-
- /* Return 0 if the clock is off. */
- if (raw_count_full == raw_count_short)
- ret = 0;
- else {
- /* Compute rate in Hz. */
- raw_count_full = ((raw_count_full * 10) + 15) * 4800000;
- do_div(raw_count_full, ((sample_ticks * 10) + 35));
- ret = (raw_count_full * multiplier);
- }
-
- spin_unlock_irqrestore(&clk_reg_lock, flags);
-
- clk_disable_unprepare(data->cxo);
-
- return ret;
-}
-
-static u8 clk_debug_mux_get_parent(struct clk_hw *hw)
-{
- struct clk_debug_mux *meas = to_clk_measure(hw);
- int i, num_parents = clk_hw_get_num_parents(hw);
-
- for (i = 0; i < num_parents; i++) {
- if (!strcmp(meas->parent[i].parents,
- hw->init->parent_names[i])) {
- pr_debug("%s :Clock name %s index %d\n", __func__,
- hw->init->name, i);
- return i;
- }
- }
-
- return 0;
-}
-
-static int clk_debug_mux_set_parent(struct clk_hw *hw, u8 index)
-{
- struct clk_debug_mux *meas = to_clk_measure(hw);
- unsigned long lsb = 0;
- u32 regval = 0;
- int dbg_cc = 0;
-
- dbg_cc = meas->parent[index].dbg_cc;
-
- if (dbg_cc != GCC) {
- regmap_read(meas->regmap[dbg_cc], 0x0, &regval);
-
- /* Clear & Set post divider bits */
- if (meas->parent[index].post_div_mask) {
- regval &= ~meas->parent[index].post_div_mask;
- lsb = find_first_bit((unsigned long *)
- &meas->parent[index].post_div_mask, 32);
- regval |= (meas->parent[index].post_div_val << lsb) &
- meas->parent[index].post_div_mask;
- meas->multiplier = meas->parent[index].post_div_val;
- }
-
- if (meas->parent[index].mask)
- regval &= ~meas->parent[index].mask <<
- meas->parent[index].shift;
- else
- regval &= ~meas->mask;
-
- regval |= (meas->parent[index].next_sel & meas->mask);
-
- if (meas->parent[index].en_mask == 0xFF)
- /* Skip en_mask */
- regval = regval;
- else if (meas->parent[index].en_mask)
- regval |= meas->parent[index].en_mask;
- else
- regval |= meas->en_mask;
-
- regmap_write(meas->regmap[dbg_cc], 0x0, regval);
- }
-
- /* update the debug sel for GCC */
- regmap_read(meas->regmap[GCC], meas->debug_offset, &regval);
-
- /* clear post divider bits */
- regval &= ~BM(15, 12);
- lsb = find_first_bit((unsigned long *)
- &meas->parent[index].post_div_mask, 32);
- regval |= (meas->parent[index].post_div_val << lsb) &
- meas->parent[index].post_div_mask;
- meas->multiplier = meas->parent[index].post_div_val;
- regval &= ~meas->mask;
- regval |= (meas->parent[index].sel & meas->mask);
- regval |= meas->en_mask;
-
- regmap_write(meas->regmap[GCC], meas->debug_offset, regval);
-
- return 0;
-}
-
-const struct clk_ops clk_debug_mux_ops = {
- .get_parent = clk_debug_mux_get_parent,
- .set_parent = clk_debug_mux_set_parent,
-};
-EXPORT_SYMBOL_GPL(clk_debug_mux_ops);
-
-static int clk_debug_measure_get(void *data, u64 *val)
-{
- struct clk_hw *hw = data, *par;
- int ret = 0;
- unsigned long meas_rate, sw_rate;
-
- ret = clk_set_parent(measure->clk, hw->clk);
- if (!ret) {
- par = measure;
- while (par && par != hw) {
- if (par->init->ops->enable)
- par->init->ops->enable(par);
- par = clk_hw_get_parent(par);
- }
- *val = clk_debug_mux_measure_rate(measure);
- }
-
- meas_rate = clk_get_rate(hw->clk);
- sw_rate = clk_get_rate(clk_hw_get_parent(measure)->clk);
- if (sw_rate && meas_rate >= (sw_rate * 2))
- *val *= DIV_ROUND_CLOSEST(meas_rate, sw_rate);
-
- return ret;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(clk_measure_fops, clk_debug_measure_get,
- NULL, "%lld\n");
-
-void clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry)
-{
- if (IS_ERR_OR_NULL(measure))
- return;
-
- if (clk_set_parent(measure->clk, hw->clk))
- return;
-
- debugfs_create_file("measure", S_IRUGO, dentry, hw,
- &clk_measure_fops);
-}
-EXPORT_SYMBOL_GPL(clk_debug_measure_add);
-
-int clk_register_debug(struct clk_hw *hw, struct dentry *dentry)
-{
- if (IS_ERR_OR_NULL(measure)) {
- if (hw->init->flags & CLK_IS_MEASURE)
- measure = hw;
- if (!IS_ERR_OR_NULL(measure))
- clk_debug_measure_add(hw, dentry);
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(clk_register_debug);
-
MODULE_LICENSE("GPL v2");