diff options
Diffstat (limited to 'sound/soc/codecs/wm_adsp.c')
-rw-r--r-- | sound/soc/codecs/wm_adsp.c | 246 |
1 files changed, 227 insertions, 19 deletions
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index b62ffd0c133e..f9f90b0f5db4 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> @@ -248,6 +249,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) { @@ -298,7 +468,6 @@ const struct snd_kcontrol_new wm_adsp1_fw_controls[] = { }; EXPORT_SYMBOL_GPL(wm_adsp1_fw_controls); -#if IS_ENABLED(CONFIG_SND_SOC_ARIZONA) static const struct soc_enum wm_adsp2_rate_enum[] = { SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1, ARIZONA_DSP1_RATE_SHIFT, 0xf, @@ -318,22 +487,28 @@ static const struct soc_enum wm_adsp2_rate_enum[] = { arizona_rate_text, arizona_rate_val), }; -const struct snd_kcontrol_new wm_adsp2_fw_controls[] = { - SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], - wm_adsp_fw_get, wm_adsp_fw_put), - SOC_ENUM("DSP1 Rate", wm_adsp2_rate_enum[0]), - SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], - wm_adsp_fw_get, wm_adsp_fw_put), - SOC_ENUM("DSP2 Rate", wm_adsp2_rate_enum[1]), - SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], - wm_adsp_fw_get, wm_adsp_fw_put), - SOC_ENUM("DSP3 Rate", wm_adsp2_rate_enum[2]), - SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3], - wm_adsp_fw_get, wm_adsp_fw_put), - SOC_ENUM("DSP4 Rate", wm_adsp2_rate_enum[3]), +static const struct snd_kcontrol_new wm_adsp2_fw_controls[4][2] = { + { + SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], + wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM("DSP1 Rate", wm_adsp2_rate_enum[0]), + }, + { + SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], + wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM("DSP2 Rate", wm_adsp2_rate_enum[1]), + }, + { + SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], + wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM("DSP3 Rate", wm_adsp2_rate_enum[2]), + }, + { + SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3], + wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM("DSP4 Rate", wm_adsp2_rate_enum[3]), + }, }; -EXPORT_SYMBOL_GPL(wm_adsp2_fw_controls); -#endif static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, int type) @@ -1128,6 +1303,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); @@ -1345,11 +1522,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, @@ -1625,6 +1803,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); @@ -1638,6 +1818,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); @@ -1896,6 +2079,10 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, /* Log firmware state, it can be useful for analysis */ wm_adsp2_show_fw_status(dsp); + 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, @@ -1933,6 +2120,24 @@ err: } 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 snd_soc_add_codec_controls(codec, + wm_adsp2_fw_controls[dsp->num - 1], + ARRAY_SIZE(wm_adsp2_fw_controls[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); + int wm_adsp2_init(struct wm_adsp *dsp) { int ret; @@ -1952,6 +2157,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); |