Message ID | 1456755616-2472-3-git-send-email-kernel@martin.sperl.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
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.
> 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
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 --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,