Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 876112d2 authored by Taniya Das's avatar Taniya Das Committed by Gerrit - the friendly Code Review server
Browse files

clk: Add support for clock list_rates ops



Add support to clock debugfs to be able to display
 - clk_rates_max which indicates the frequency to voltage mapping
   of a clock.
 - clk_list_rates, the list of clock frequencies supported by root
   clocks.
 - Also display the clk_rate_max associated with enabled clocks list.

Change-Id: I0a202af6f46c7cf164036d65487db5c40aab4063
Signed-off-by: default avatarTaniya Das <tdas@codeaurora.org>
Signed-off-by: default avatarDeepak Katragadda <dkatraga@codeaurora.org>
parent 2dd2572c
Loading
Loading
Loading
Loading
+130 −1
Original line number Diff line number Diff line
@@ -2513,6 +2513,14 @@ int clock_debug_print_clock(struct clk_core *c, struct seq_file *s)
	clock_debug_output(s, 0, "\t");

	do {
		if (clk->core->vdd_class)
			clock_debug_output(s, 1, "%s%s:%u:%u [%ld, %d]", start,
					clk->core->name,
					clk->core->prepare_count,
					clk->core->enable_count,
					clk->core->rate,
				clk_find_vdd_level(clk->core, clk->core->rate));
		else
			clock_debug_output(s, 1, "%s%s:%u:%u [%ld]", start,
					clk->core->name,
					clk->core->prepare_count,
@@ -2604,6 +2612,117 @@ static const struct file_operations clock_print_hw_fops = {
	.release	= seq_release,
};

static int list_rates_show(struct seq_file *s, void *unused)
{
	struct clk_core *core = s->private;
	int level = 0, i = 0;
	unsigned long rate, rate_max = 0;

	/* Find max frequency supported within voltage constraints. */
	if (!core->vdd_class) {
		rate_max = ULONG_MAX;
	} else {
		for (level = 0; level < core->num_rate_max; level++)
			if (core->rate_max[level])
				rate_max = core->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 =
			core->ops->list_rate(core->hw, i++, rate_max))) {
		if (rate <= 0)
			break;
		if (rate <= rate_max)
			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 clock_print_rate_max_by_level(struct seq_file *s, int level)
{
	struct clk_core *core = s->private;
	struct clk_vdd_class *vdd_class = core->vdd_class;
	int off, i, vdd_level, nregs = vdd_class->num_regulators;

	vdd_level = clk_find_vdd_level(core, core->rate);

	seq_printf(s, "%2s%10lu", vdd_level == level ? "[" : "",
		core->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_core *core = s->private;
	struct clk_vdd_class *vdd_class = core->vdd_class;
	int level = 0, i, nregs = vdd_class->num_regulators;
	char reg_name[10];

	int vdd_level = clk_find_vdd_level(core, core->rate);

	if (vdd_level < 0) {
		seq_printf(s, "could not find_vdd_level for %s, %ld\n",
			core->name, core->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 < core->num_rate_max; level++)
		clock_print_rate_max_by_level(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 clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
{
	struct dentry *d;
@@ -2625,6 +2744,16 @@ static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
	if (!d)
		goto err_out;

	if (core->ops->list_rate) {
		if (!debugfs_create_file("clk_list_rates",
				0444, core->dentry, core, &list_rates_fops))
			goto err_out;
	}

	if (core->vdd_class && !debugfs_create_file("clk_rate_max",
				0444, core->dentry, core, &rate_max_fops))
		goto err_out;

	d = debugfs_create_u32("clk_accuracy", 0444, core->dentry,
			(u32 *)&core->accuracy);
	if (!d)
+6 −0
Original line number Diff line number Diff line
@@ -184,6 +184,10 @@ struct clk_rate_request {
 * @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.
 *
 * 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,
@@ -226,6 +230,8 @@ struct clk_ops {
	int		(*set_flags)(struct clk_hw *hw, unsigned int flags);
	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);
};

/**