diff mbox

[2/2] clk: bcm2835: expose current divider, parent and mash via debugfs

Message ID 1456755616-2472-3-git-send-email-kernel@martin.sperl.org (mailing list archive)
State New, archived
Headers show

Commit Message

Martin Sperl Feb. 29, 2016, 2:20 p.m. UTC
From: Martin Sperl <kernel@martin.sperl.org>

For each clock expose the following values via debugfs:
* current_parent - the currently selected parent
* current_divi - the integer portion of the currently set divider
* current_divf - the fractional portion of the currently set divider
* current_frac - the current frac/mash settings for the divider

Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
---
 drivers/clk/bcm/clk-bcm2835.c |  110 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 110 insertions(+)

Comments

Eric Anholt Feb. 29, 2016, 8:43 p.m. UTC | #1
kernel@martin.sperl.org writes:

> From: Martin Sperl <kernel@martin.sperl.org>
>
> For each clock expose the following values via debugfs:
> * current_parent - the currently selected parent
> * current_divi - the integer portion of the currently set divider
> * current_divf - the fractional portion of the currently set divider
> * current_frac - the current frac/mash settings for the divider

current_parent can already be found through /debug/clk/clk_summary quite
nicely I think.  If we wanted a per-clock parent file, that seems like
something the core ought to be doing.

current_frac is looking at a bit that doesn't exist for non-MASH clocks.

divi/divf are OK, I guess, but don't seem particularly useful given the
raw register output already.  A cooked floating point point divider
debugfs entry would be nice, but I don't know if we can do that.
Martin Sperl Feb. 29, 2016, 9:11 p.m. UTC | #2
> On 29.02.2016, at 21:43, Eric Anholt <eric@anholt.net> wrote:
> 
> kernel@martin.sperl.org writes:
> 
>> From: Martin Sperl <kernel@martin.sperl.org>
>> 
>> For each clock expose the following values via debugfs:
>> * current_parent - the currently selected parent
>> * current_divi - the integer portion of the currently set divider
>> * current_divf - the fractional portion of the currently set divider
>> * current_frac - the current frac/mash settings for the divider
> 
> current_parent can already be found through /debug/clk/clk_summary quite
> nicely I think.  If we wanted a per-clock parent file, that seems like
> something the core ought to be doing.
> 
> current_frac is looking at a bit that doesn't exist for non-MASH clocks.
> 
> divi/divf are OK, I guess, but don't seem particularly useful given the
> raw register output already.  A cooked floating point point divider
> debugfs entry would be nice, but I don't know if we can do that.

The reason I had those is because I wanted to allow people to
see quickly what is the parent clock and what is the used 
parent and divider…

While discussing with the PCM/I2s people they were always concerned
about those details - so I needed to provide them with a way to access
those things easily. And explaining to them the register format was -
for me - out of the question.

Especially the mapping of “id” to real parent was a bit of a pain.

What do you mean by cooked? Something like: "33+27/4096”?

Martin
Eric Anholt Feb. 29, 2016, 11:13 p.m. UTC | #3
Martin Sperl <kernel@martin.sperl.org> writes:

>> On 29.02.2016, at 21:43, Eric Anholt <eric@anholt.net> wrote:
>> 
>> kernel@martin.sperl.org writes:
>> 
>>> From: Martin Sperl <kernel@martin.sperl.org>
>>> 
>>> For each clock expose the following values via debugfs:
>>> * current_parent - the currently selected parent
>>> * current_divi - the integer portion of the currently set divider
>>> * current_divf - the fractional portion of the currently set divider
>>> * current_frac - the current frac/mash settings for the divider
>> 
>> current_parent can already be found through /debug/clk/clk_summary quite
>> nicely I think.  If we wanted a per-clock parent file, that seems like
>> something the core ought to be doing.
>> 
>> current_frac is looking at a bit that doesn't exist for non-MASH clocks.
>> 
>> divi/divf are OK, I guess, but don't seem particularly useful given the
>> raw register output already.  A cooked floating point point divider
>> debugfs entry would be nice, but I don't know if we can do that.
>
> The reason I had those is because I wanted to allow people to
> see quickly what is the parent clock and what is the used 
> parent and divider…
>
> While discussing with the PCM/I2s people they were always concerned
> about those details - so I needed to provide them with a way to access
> those things easily. And explaining to them the register format was -
> for me - out of the question.
>
> Especially the mapping of “id” to real parent was a bit of a pain.
>
> What do you mean by cooked? Something like: "33+27/4096”?

I mean, given your "33+27/4096" example, "33.006591796875"
diff mbox

Patch

diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 89de3d6..01a48cb 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -129,6 +129,10 @@ 
 # define CM_BUSY			BIT(7)
 # define CM_BUSYD			BIT(8)
 # define CM_FRAC			BIT(9)
+# define CM_MASH0			BIT(9)
+# define CM_MASH1			BIT(10)
+# define CM_MASH_MASK			(CM_MASH0 | CM_MASH1)
+# define CM_MASH_SHIFT			9
 # define CM_SRC_SHIFT			0
 # define CM_SRC_BITS			4
 # define CM_SRC_MASK			0xf
@@ -1063,6 +1067,99 @@  static u8 bcm2835_clock_get_parent(struct clk_hw *hw)
 	return (src & CM_SRC_MASK) >> CM_SRC_SHIFT;
 }
 
+static const char *bcm2835_clock_get_parent_name(struct clk_hw *hw)
+{
+	struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+	const struct bcm2835_clock_data *data = clock->data;
+	u8 id = bcm2835_clock_get_parent(hw);
+
+	return (id < data->num_mux_parents) ?
+		data->parents[id] : "unknown";
+}
+
+static int bcm2835_clock_debug_current_parent_open(struct inode *inode,
+						   struct file *file)
+{
+	const char *parent = bcm2835_clock_get_parent_name(inode->i_private);
+	size_t len = strlen(parent);
+	char *buf;
+
+	/* create string with trailing newline */
+	buf = kmalloc(len + 2, GFP_KERNEL);
+	memcpy(buf, parent, len);
+	buf[len] = '\n';
+	buf[len + 1] = 0;
+
+	file->private_data = buf;
+
+	return 0;
+}
+
+static ssize_t bcm2835_clock_debug_current_parent_read(struct file *file,
+						       char __user *buf,
+						       size_t len,
+						       loff_t *ppos)
+{
+	const char *parent = file->private_data;
+	size_t size = strlen(parent);
+
+	return simple_read_from_buffer(buf, len, ppos, parent, size);
+}
+
+static const struct file_operations bcm2835_clock_debug_current_parent_fops = {
+	.owner   = THIS_MODULE,
+	.open    = bcm2835_clock_debug_current_parent_open,
+	.release = simple_attr_release,
+	.read    = bcm2835_clock_debug_current_parent_read,
+	.llseek  = generic_file_llseek,
+};
+
+static int bcm2835_clock_debug_current_divi_get(void *hw, u64 *val)
+{
+	struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+	struct bcm2835_cprman *cprman = clock->cprman;
+	const struct bcm2835_clock_data *data = clock->data;
+	u32 div = cprman_read(cprman, data->div_reg);
+
+	*val = div >> CM_DIV_FRAC_BITS;
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(bcm2835_clock_debug_current_divi_fops,
+			bcm2835_clock_debug_current_divi_get,
+			NULL, "%llu\n");
+
+static int bcm2835_clock_debug_current_divf_get(void *hw, u64 *val)
+{
+	struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+	struct bcm2835_cprman *cprman = clock->cprman;
+	const struct bcm2835_clock_data *data = clock->data;
+	u32 div = cprman_read(cprman, data->div_reg);
+
+	*val = div & CM_DIV_FRAC_MASK;
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(bcm2835_clock_debug_current_divf_fops,
+			bcm2835_clock_debug_current_divf_get,
+			NULL, "%llu\n");
+
+static int bcm2835_clock_debug_current_frac_get(void *hw, u64 *val)
+{
+	struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+	struct bcm2835_cprman *cprman = clock->cprman;
+	const struct bcm2835_clock_data *data = clock->data;
+	u32 ctl = cprman_read(cprman, data->ctl_reg);
+
+	if (data->is_mash_clock)
+		*val = (ctl & CM_MASH_MASK) >> CM_MASH_SHIFT;
+	else
+		*val = ctl & CM_FRAC ? 1 : 0;
+
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(bcm2835_clock_debug_current_frac_fops,
+			bcm2835_clock_debug_current_frac_get,
+			NULL, "%llu\n");
+
 static struct debugfs_reg32 bcm2835_debugfs_clock_reg32[] = {
 	{
 		.name = "ctl",
@@ -1081,6 +1178,19 @@  static int bcm2835_clock_debug_init(struct clk_hw *hw,
 	struct bcm2835_cprman *cprman = clock->cprman;
 	const struct bcm2835_clock_data *data = clock->data;
 
+	/* expose the current parrent */
+	debugfs_create_file("current_parent", S_IRUGO, dentry, hw,
+			    &bcm2835_clock_debug_current_parent_fops);
+
+	/* expose the current divider components */
+	debugfs_create_file("current_divi", S_IRUGO, dentry, hw,
+			    &bcm2835_clock_debug_current_divi_fops);
+	debugfs_create_file("current_divf", S_IRUGO, dentry, hw,
+			    &bcm2835_clock_debug_current_divf_fops);
+	debugfs_create_file("current_frac", S_IRUGO, dentry, hw,
+			    &bcm2835_clock_debug_current_frac_fops);
+
+	/* add the regset */
 	return bcm2835_debugfs_regset(
 		cprman, data->ctl_reg,
 		bcm2835_debugfs_clock_reg32,