diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-01-11 17:58:28 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-01-12 13:36:07 -0500 |
commit | 1023dbd90c1e3e87921198939917c1f50b4b6af7 (patch) | |
tree | 12d090ba617480996cd2eb997aeefb7a454804c1 /sound/soc/codecs/wm_adsp.c | |
parent | 471f488583c62e4daca7d24fc7c937a39de7d95f (diff) |
ASoC: wm_adsp: Add basic firmware selection support
There are many firmwares available for ADSP devices. Add basic support
for selecting between them, including a couple of feature sets in the
set of available firmware to start off with.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/wm_adsp.c')
-rw-r--r-- | sound/soc/codecs/wm_adsp.c | 75 |
1 files changed, 73 insertions, 2 deletions
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 5015ff287c39..1f8e8e2a1a6a 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c | |||
@@ -143,6 +143,71 @@ | |||
143 | #define ADSP2_RAM_RDY_SHIFT 0 | 143 | #define ADSP2_RAM_RDY_SHIFT 0 |
144 | #define ADSP2_RAM_RDY_WIDTH 1 | 144 | #define ADSP2_RAM_RDY_WIDTH 1 |
145 | 145 | ||
146 | #define WM_ADSP_NUM_FW 3 | ||
147 | |||
148 | static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = { | ||
149 | "MBC/VSS", "Tx", "Rx ANC" | ||
150 | }; | ||
151 | |||
152 | static struct { | ||
153 | const char *file; | ||
154 | } wm_adsp_fw[WM_ADSP_NUM_FW] = { | ||
155 | { .file = "mbc-vss" }, | ||
156 | { .file = "tx" }, | ||
157 | { .file = "rx-anc" }, | ||
158 | }; | ||
159 | |||
160 | static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, | ||
161 | struct snd_ctl_elem_value *ucontrol) | ||
162 | { | ||
163 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
164 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
165 | struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); | ||
166 | |||
167 | ucontrol->value.integer.value[0] = adsp[e->shift_l].fw; | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, | ||
173 | struct snd_ctl_elem_value *ucontrol) | ||
174 | { | ||
175 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
176 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
177 | struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); | ||
178 | |||
179 | if (ucontrol->value.integer.value[0] == adsp[e->shift_l].fw) | ||
180 | return 0; | ||
181 | |||
182 | if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW) | ||
183 | return -EINVAL; | ||
184 | |||
185 | if (adsp[e->shift_l].running) | ||
186 | return -EBUSY; | ||
187 | |||
188 | adsp->fw = ucontrol->value.integer.value[0]; | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static const struct soc_enum wm_adsp_fw_enum[] = { | ||
194 | SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), | ||
195 | SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), | ||
196 | SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), | ||
197 | SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), | ||
198 | }; | ||
199 | |||
200 | const struct snd_kcontrol_new wm_adsp_fw_controls[] = { | ||
201 | SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], | ||
202 | wm_adsp_fw_get, wm_adsp_fw_put), | ||
203 | SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], | ||
204 | wm_adsp_fw_get, wm_adsp_fw_put), | ||
205 | SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], | ||
206 | wm_adsp_fw_get, wm_adsp_fw_put), | ||
207 | SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3], | ||
208 | wm_adsp_fw_get, wm_adsp_fw_put), | ||
209 | }; | ||
210 | EXPORT_SYMBOL_GPL(wm_adsp_fw_controls); | ||
146 | 211 | ||
147 | static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, | 212 | static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, |
148 | int type) | 213 | int type) |
@@ -197,7 +262,8 @@ static int wm_adsp_load(struct wm_adsp *dsp) | |||
197 | if (file == NULL) | 262 | if (file == NULL) |
198 | return -ENOMEM; | 263 | return -ENOMEM; |
199 | 264 | ||
200 | snprintf(file, PAGE_SIZE, "%s-dsp%d.wmfw", dsp->part, dsp->num); | 265 | snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.wmfw", dsp->part, dsp->num, |
266 | wm_adsp_fw[dsp->fw].file); | ||
201 | file[PAGE_SIZE - 1] = '\0'; | 267 | file[PAGE_SIZE - 1] = '\0'; |
202 | 268 | ||
203 | ret = request_firmware(&firmware, file, dsp->dev); | 269 | ret = request_firmware(&firmware, file, dsp->dev); |
@@ -596,7 +662,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) | |||
596 | if (file == NULL) | 662 | if (file == NULL) |
597 | return -ENOMEM; | 663 | return -ENOMEM; |
598 | 664 | ||
599 | snprintf(file, PAGE_SIZE, "%s-dsp%d.bin", dsp->part, dsp->num); | 665 | snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.bin", dsp->part, dsp->num, |
666 | wm_adsp_fw[dsp->fw].file); | ||
600 | file[PAGE_SIZE - 1] = '\0'; | 667 | file[PAGE_SIZE - 1] = '\0'; |
601 | 668 | ||
602 | ret = request_firmware(&firmware, file, dsp->dev); | 669 | ret = request_firmware(&firmware, file, dsp->dev); |
@@ -886,9 +953,13 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
886 | ADSP2_CORE_ENA | ADSP2_START); | 953 | ADSP2_CORE_ENA | ADSP2_START); |
887 | if (ret != 0) | 954 | if (ret != 0) |
888 | goto err; | 955 | goto err; |
956 | |||
957 | dsp->running = true; | ||
889 | break; | 958 | break; |
890 | 959 | ||
891 | case SND_SOC_DAPM_PRE_PMD: | 960 | case SND_SOC_DAPM_PRE_PMD: |
961 | dsp->running = false; | ||
962 | |||
892 | regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, | 963 | regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, |
893 | ADSP2_SYS_ENA | ADSP2_CORE_ENA | | 964 | ADSP2_SYS_ENA | ADSP2_CORE_ENA | |
894 | ADSP2_START, 0); | 965 | ADSP2_START, 0); |