[alsa-devel] [PATCH v2 1/2] ASoC: wm_adsp: Add code_probe and codec_remove stubs
Currently the only init function in wm_adsp is called by the codec driver early in its probe before the codec has been registered with SOC.
This patch adds stubs for the codec_probe and codec_remove stages and calls them from WM5102 and WM5110 codec drivers. This allows us to hang anything that needs setup during the codec probe stage off these functions without further modification of the codec drivers.
Signed-off-by: Richard Fitzgerald rf@opensource.wolfsonmicro.com --- sound/soc/codecs/wm5102.c | 6 ++++++ sound/soc/codecs/wm5110.c | 12 +++++++++++- sound/soc/codecs/wm_adsp.c | 12 ++++++++++++ sound/soc/codecs/wm_adsp.h | 2 ++ 4 files changed, 31 insertions(+), 1 deletions(-)
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 11eba0e..341d96e 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1875,6 +1875,10 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); int ret;
+ ret = wm_adsp2_codec_probe(&priv->core.adsp[0], codec); + if (ret) + return ret; + ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 2); if (ret != 0) return ret; @@ -1893,6 +1897,8 @@ static int wm5102_codec_remove(struct snd_soc_codec *codec) { struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
+ wm_adsp2_codec_remove(&priv->core.adsp[0], codec); + priv->core.arizona->dapm = NULL;
return 0; diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index d65364e..6e15d9c 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -1599,7 +1599,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = { static int wm5110_codec_probe(struct snd_soc_codec *codec) { struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); - int ret; + int i, ret;
priv->core.arizona->dapm = &codec->dapm;
@@ -1607,6 +1607,12 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) arizona_init_gpio(codec); arizona_init_mono(codec);
+ for (i = 0; i < WM5110_NUM_ADSP; ++i) { + ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec); + if (ret) + return ret; + } + ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 8); if (ret != 0) return ret; @@ -1621,6 +1627,10 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) static int wm5110_codec_remove(struct snd_soc_codec *codec) { struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); + int i; + + for (i = 0; i < WM5110_NUM_ADSP; ++i) + wm_adsp2_codec_remove(&priv->core.adsp[i], codec);
priv->core.arizona->dapm = NULL;
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 6e358b5..490edb3 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -1906,6 +1906,18 @@ err: } EXPORT_SYMBOL_GPL(wm_adsp2_event);
+int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec) +{ + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp2_codec_probe); + +int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec) +{ + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp2_codec_remove); + int wm_adsp2_init(struct wm_adsp *dsp) { int ret; diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 0e5f07c..5584e34 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -79,6 +79,8 @@ extern const struct snd_kcontrol_new wm_adsp2_fw_controls[];
int wm_adsp1_init(struct wm_adsp *dsp); int wm_adsp2_init(struct wm_adsp *dsp); +int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec); +int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec); int wm_adsp1_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
This patch adds some debugfs nodes to get information about the currently running firmware.
Signed-off-by: Richard Fitzgerald rf@opensource.wolfsonmicro.com --- sound/soc/codecs/wm_adsp.c | 195 +++++++++++++++++++++++++++++++++++++++++++- sound/soc/codecs/wm_adsp.h | 11 ++- 2 files changed, 202 insertions(+), 4 deletions(-)
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 490edb3..045483a 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -23,6 +23,7 @@ #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/workqueue.h> +#include <linux/debugfs.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -243,6 +244,175 @@ struct wm_coeff_ctl { unsigned int flags; };
+#ifdef CONFIG_DEBUG_FS +static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s) +{ + char *tmp = kasprintf(GFP_KERNEL, "%s\n", s); + + mutex_lock(&dsp->debugfs_lock); + kfree(dsp->wmfw_file_name); + dsp->wmfw_file_name = tmp; + mutex_unlock(&dsp->debugfs_lock); +} + +static void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, const char *s) +{ + char *tmp = kasprintf(GFP_KERNEL, "%s\n", s); + + mutex_lock(&dsp->debugfs_lock); + kfree(dsp->bin_file_name); + dsp->bin_file_name = tmp; + mutex_unlock(&dsp->debugfs_lock); +} + +static void wm_adsp_debugfs_clear(struct wm_adsp *dsp) +{ + mutex_lock(&dsp->debugfs_lock); + kfree(dsp->wmfw_file_name); + kfree(dsp->bin_file_name); + dsp->wmfw_file_name = NULL; + dsp->bin_file_name = NULL; + mutex_unlock(&dsp->debugfs_lock); +} + +static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wm_adsp *dsp = file->private_data; + ssize_t ret; + + mutex_lock(&dsp->debugfs_lock); + + if (!dsp->wmfw_file_name || !dsp->running) + ret = 0; + else + ret = simple_read_from_buffer(user_buf, count, ppos, + dsp->wmfw_file_name, + strlen(dsp->wmfw_file_name)); + + mutex_unlock(&dsp->debugfs_lock); + return ret; +} + +static ssize_t wm_adsp_debugfs_bin_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wm_adsp *dsp = file->private_data; + ssize_t ret; + + mutex_lock(&dsp->debugfs_lock); + + if (!dsp->bin_file_name || !dsp->running) + ret = 0; + else + ret = simple_read_from_buffer(user_buf, count, ppos, + dsp->bin_file_name, + strlen(dsp->bin_file_name)); + + mutex_unlock(&dsp->debugfs_lock); + return ret; +} + +static const struct { + const char *name; + const struct file_operations fops; +} wm_adsp_debugfs_fops[] = { + { + .name = "wmfw_file_name", + .fops = { + .open = simple_open, + .read = wm_adsp_debugfs_wmfw_read, + }, + }, + { + .name = "bin_file_name", + .fops = { + .open = simple_open, + .read = wm_adsp_debugfs_bin_read, + }, + }, +}; + +static void wm_adsp2_init_debugfs(struct wm_adsp *dsp, + struct snd_soc_codec *codec) +{ + struct dentry *root = NULL; + char *root_name; + int i; + + if (!codec->component.debugfs_root) { + adsp_err(dsp, "No codec debugfs root\n"); + goto err; + } + + root_name = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!root_name) + goto err; + + snprintf(root_name, PAGE_SIZE, "dsp%d", dsp->num); + root = debugfs_create_dir(root_name, codec->component.debugfs_root); + kfree(root_name); + + if (!root) + goto err; + + if (!debugfs_create_bool("running", S_IRUGO, root, &dsp->running)) + goto err; + + if (!debugfs_create_x32("fw_id", S_IRUGO, root, &dsp->fw_id)) + goto err; + + if (!debugfs_create_x32("fw_version", S_IRUGO, root, + &dsp->fw_id_version)) + goto err; + + for (i = 0; i < ARRAY_SIZE(wm_adsp_debugfs_fops); ++i) { + if (!debugfs_create_file(wm_adsp_debugfs_fops[i].name, + S_IRUGO, root, dsp, + &wm_adsp_debugfs_fops[i].fops)) + goto err; + } + + dsp->debugfs_root = root; + return; + +err: + debugfs_remove_recursive(root); + adsp_err(dsp, "Failed to create debugfs\n"); +} + +static void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp) +{ + wm_adsp_debugfs_clear(dsp); + debugfs_remove_recursive(dsp->debugfs_root); +} +#else +static inline void wm_adsp2_init_debugfs(struct wm_adsp *dsp, + struct snd_soc_codec *codec) +{ +} + +static inline void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp) +{ +} + +static inline void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, + const char *s) +{ +} + +static inline void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, + const char *s) +{ +} + +static inline void wm_adsp_debugfs_clear(struct wm_adsp *dsp) +{ +} +#endif + static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1104,6 +1274,8 @@ static int wm_adsp_load(struct wm_adsp *dsp) adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", file, regions, pos - firmware->size);
+ wm_adsp_debugfs_save_wmfwname(dsp, file); + out_fw: regmap_async_complete(regmap); wm_adsp_buf_free(&buf_list); @@ -1321,11 +1493,12 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
n_algs = be32_to_cpu(adsp2_id.n_algs); dsp->fw_id = be32_to_cpu(adsp2_id.fw.id); + dsp->fw_id_version = be32_to_cpu(adsp2_id.fw.ver); adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", dsp->fw_id, - (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16, - (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8, - be32_to_cpu(adsp2_id.fw.ver) & 0xff, + (dsp->fw_id_version & 0xff0000) >> 16, + (dsp->fw_id_version & 0xff00) >> 8, + dsp->fw_id_version & 0xff, n_algs);
alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM, @@ -1601,6 +1774,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", file, blocks, pos - firmware->size);
+ wm_adsp_debugfs_save_binname(dsp, file); + out_fw: regmap_async_complete(regmap); release_firmware(firmware); @@ -1614,6 +1789,9 @@ int wm_adsp1_init(struct wm_adsp *dsp) { INIT_LIST_HEAD(&dsp->alg_regions);
+#ifdef CONFIG_DEBUG_FS + mutex_init(&dsp->debugfs_lock); +#endif return 0; } EXPORT_SYMBOL_GPL(wm_adsp1_init); @@ -1869,6 +2047,10 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, break;
case SND_SOC_DAPM_PRE_PMD: + wm_adsp_debugfs_clear(dsp); + + dsp->fw_id = 0; + dsp->fw_id_version = 0; dsp->running = false;
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, @@ -1908,12 +2090,16 @@ EXPORT_SYMBOL_GPL(wm_adsp2_event);
int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec) { + wm_adsp2_init_debugfs(dsp, codec); + return 0; } EXPORT_SYMBOL_GPL(wm_adsp2_codec_probe);
int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec) { + wm_adsp2_cleanup_debugfs(dsp); + return 0; } EXPORT_SYMBOL_GPL(wm_adsp2_codec_remove); @@ -1937,6 +2123,9 @@ int wm_adsp2_init(struct wm_adsp *dsp) INIT_LIST_HEAD(&dsp->ctl_list); INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
+#ifdef CONFIG_DEBUG_FS + mutex_init(&dsp->debugfs_lock); +#endif return 0; } EXPORT_SYMBOL_GPL(wm_adsp2_init); diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 5584e34..e018148 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -46,17 +46,26 @@ struct wm_adsp { struct list_head alg_regions;
int fw_id; + int fw_id_version;
const struct wm_adsp_region *mem; int num_mems;
int fw; int fw_ver; - bool running; + u32 running;
struct list_head ctl_list;
struct work_struct boot_work; + +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_root; + struct mutex debugfs_lock; + char *wmfw_file_name; + char *bin_file_name; +#endif + };
#define WM_ADSP1(wname, num) \
On Tue, Jun 09, 2015 at 04:16:56PM +0100, Richard Fitzgerald wrote:
- ret = wm_adsp2_codec_probe(&priv->core.adsp[0], codec);
- if (ret)
return ret;
I'm still not a big fan of the double registration that's being done - if nothing else the fact that it's not also factoring out the creation of the DSP controls seems wrong.
On Tue, Jun 09, 2015 at 05:00:43PM +0100, Mark Brown wrote:
On Tue, Jun 09, 2015 at 04:16:56PM +0100, Richard Fitzgerald wrote:
- ret = wm_adsp2_codec_probe(&priv->core.adsp[0], codec);
- if (ret)
return ret;
I'm still not a big fan of the double registration that's being done - if nothing else the fact that it's not also factoring out the creation of the DSP controls seems wrong.
I don't see the point of trying to fight against the design of ASoC with the second probe. ASoC gives us what we need at the codec_probe stage so why try to invent something different?
On Tue, Jun 09, 2015 at 05:13:56PM +0100, Richard Fitzgerald wrote:
On Tue, Jun 09, 2015 at 05:00:43PM +0100, Mark Brown wrote:
I'm still not a big fan of the double registration that's being done - if nothing else the fact that it's not also factoring out the creation of the DSP controls seems wrong.
I don't see the point of trying to fight against the design of ASoC with the second probe. ASoC gives us what we need at the codec_probe stage so why try to invent something different?
Well, you could've still hung things off the struct device - it's not like the ASoC level device is a requirement here - and like I say the fact that it's not actually factoring out the initialisation that's already happening at the ASoC probe isn't good.
On Tue, Jun 09, 2015 at 05:20:45PM +0100, Mark Brown wrote:
On Tue, Jun 09, 2015 at 05:13:56PM +0100, Richard Fitzgerald wrote:
On Tue, Jun 09, 2015 at 05:00:43PM +0100, Mark Brown wrote:
I'm still not a big fan of the double registration that's being done - if nothing else the fact that it's not also factoring out the creation of the DSP controls seems wrong.
We can certainly look at factoring out that control creation once we have a probe function in wm_adsp to put them in. Which is what this patch creates.
I don't see the point of trying to fight against the design of ASoC with the second probe. ASoC gives us what we need at the codec_probe stage so why try to invent something different?
Well, you could've still hung things off the struct device - it's not like the ASoC level device is a requirement here - and like I say the
I'm doing it in the codec_probe because by that time ASoC has created its codec: debugfs node and I can put the dsp debugfs nodes under that. If I created the debugfs earlier before ASoC has probed the codec that node won't exist so I'd have to create my own debugfs node, and it seems a bit odd and untidy to have some codec debug info under the asoc node but some stuff somewhere else.
fact that it's not actually factoring out the initialisation that's already happening at the ASoC probe isn't good.
On Tue, Jun 09, 2015 at 05:43:29PM +0100, Richard Fitzgerald wrote:
We can certainly look at factoring out that control creation once we have a probe function in wm_adsp to put them in. Which is what this patch creates.
Well, please do that then!
participants (2)
-
Mark Brown
-
Richard Fitzgerald