~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/codecs/wm_adsp.c

Version: ~ [ linux-5.6.3 ] ~ [ linux-5.5.16 ] ~ [ linux-5.4.31 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.114 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.175 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.218 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.218 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.82 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * wm_adsp.c  --  Wolfson ADSP support
  3  *
  4  * Copyright 2012 Wolfson Microelectronics plc
  5  *
  6  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  7  *
  8  * This program is free software; you can redistribute it and/or modify
  9  * it under the terms of the GNU General Public License version 2 as
 10  * published by the Free Software Foundation.
 11  */
 12 
 13 #include <linux/module.h>
 14 #include <linux/moduleparam.h>
 15 #include <linux/init.h>
 16 #include <linux/delay.h>
 17 #include <linux/firmware.h>
 18 #include <linux/list.h>
 19 #include <linux/pm.h>
 20 #include <linux/pm_runtime.h>
 21 #include <linux/regmap.h>
 22 #include <linux/regulator/consumer.h>
 23 #include <linux/slab.h>
 24 #include <sound/core.h>
 25 #include <sound/pcm.h>
 26 #include <sound/pcm_params.h>
 27 #include <sound/soc.h>
 28 #include <sound/jack.h>
 29 #include <sound/initval.h>
 30 #include <sound/tlv.h>
 31 
 32 #include <linux/mfd/arizona/registers.h>
 33 
 34 #include "arizona.h"
 35 #include "wm_adsp.h"
 36 
 37 #define adsp_crit(_dsp, fmt, ...) \
 38         dev_crit(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
 39 #define adsp_err(_dsp, fmt, ...) \
 40         dev_err(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
 41 #define adsp_warn(_dsp, fmt, ...) \
 42         dev_warn(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
 43 #define adsp_info(_dsp, fmt, ...) \
 44         dev_info(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
 45 #define adsp_dbg(_dsp, fmt, ...) \
 46         dev_dbg(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
 47 
 48 #define ADSP1_CONTROL_1                   0x00
 49 #define ADSP1_CONTROL_2                   0x02
 50 #define ADSP1_CONTROL_3                   0x03
 51 #define ADSP1_CONTROL_4                   0x04
 52 #define ADSP1_CONTROL_5                   0x06
 53 #define ADSP1_CONTROL_6                   0x07
 54 #define ADSP1_CONTROL_7                   0x08
 55 #define ADSP1_CONTROL_8                   0x09
 56 #define ADSP1_CONTROL_9                   0x0A
 57 #define ADSP1_CONTROL_10                  0x0B
 58 #define ADSP1_CONTROL_11                  0x0C
 59 #define ADSP1_CONTROL_12                  0x0D
 60 #define ADSP1_CONTROL_13                  0x0F
 61 #define ADSP1_CONTROL_14                  0x10
 62 #define ADSP1_CONTROL_15                  0x11
 63 #define ADSP1_CONTROL_16                  0x12
 64 #define ADSP1_CONTROL_17                  0x13
 65 #define ADSP1_CONTROL_18                  0x14
 66 #define ADSP1_CONTROL_19                  0x16
 67 #define ADSP1_CONTROL_20                  0x17
 68 #define ADSP1_CONTROL_21                  0x18
 69 #define ADSP1_CONTROL_22                  0x1A
 70 #define ADSP1_CONTROL_23                  0x1B
 71 #define ADSP1_CONTROL_24                  0x1C
 72 #define ADSP1_CONTROL_25                  0x1E
 73 #define ADSP1_CONTROL_26                  0x20
 74 #define ADSP1_CONTROL_27                  0x21
 75 #define ADSP1_CONTROL_28                  0x22
 76 #define ADSP1_CONTROL_29                  0x23
 77 #define ADSP1_CONTROL_30                  0x24
 78 #define ADSP1_CONTROL_31                  0x26
 79 
 80 /*
 81  * ADSP1 Control 19
 82  */
 83 #define ADSP1_WDMA_BUFFER_LENGTH_MASK     0x00FF  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
 84 #define ADSP1_WDMA_BUFFER_LENGTH_SHIFT         0  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
 85 #define ADSP1_WDMA_BUFFER_LENGTH_WIDTH         8  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
 86 
 87 
 88 /*
 89  * ADSP1 Control 30
 90  */
 91 #define ADSP1_DBG_CLK_ENA                 0x0008  /* DSP1_DBG_CLK_ENA */
 92 #define ADSP1_DBG_CLK_ENA_MASK            0x0008  /* DSP1_DBG_CLK_ENA */
 93 #define ADSP1_DBG_CLK_ENA_SHIFT                3  /* DSP1_DBG_CLK_ENA */
 94 #define ADSP1_DBG_CLK_ENA_WIDTH                1  /* DSP1_DBG_CLK_ENA */
 95 #define ADSP1_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
 96 #define ADSP1_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
 97 #define ADSP1_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
 98 #define ADSP1_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
 99 #define ADSP1_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
100 #define ADSP1_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
101 #define ADSP1_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
102 #define ADSP1_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
103 #define ADSP1_START                       0x0001  /* DSP1_START */
104 #define ADSP1_START_MASK                  0x0001  /* DSP1_START */
105 #define ADSP1_START_SHIFT                      0  /* DSP1_START */
106 #define ADSP1_START_WIDTH                      1  /* DSP1_START */
107 
108 /*
109  * ADSP1 Control 31
110  */
111 #define ADSP1_CLK_SEL_MASK                0x0007  /* CLK_SEL_ENA */
112 #define ADSP1_CLK_SEL_SHIFT                    0  /* CLK_SEL_ENA */
113 #define ADSP1_CLK_SEL_WIDTH                    3  /* CLK_SEL_ENA */
114 
115 #define ADSP2_CONTROL        0x0
116 #define ADSP2_CLOCKING       0x1
117 #define ADSP2_STATUS1        0x4
118 #define ADSP2_WDMA_CONFIG_1 0x30
119 #define ADSP2_WDMA_CONFIG_2 0x31
120 #define ADSP2_RDMA_CONFIG_1 0x34
121 
122 /*
123  * ADSP2 Control
124  */
125 
126 #define ADSP2_MEM_ENA                     0x0010  /* DSP1_MEM_ENA */
127 #define ADSP2_MEM_ENA_MASK                0x0010  /* DSP1_MEM_ENA */
128 #define ADSP2_MEM_ENA_SHIFT                    4  /* DSP1_MEM_ENA */
129 #define ADSP2_MEM_ENA_WIDTH                    1  /* DSP1_MEM_ENA */
130 #define ADSP2_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
131 #define ADSP2_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
132 #define ADSP2_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
133 #define ADSP2_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
134 #define ADSP2_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
135 #define ADSP2_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
136 #define ADSP2_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
137 #define ADSP2_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
138 #define ADSP2_START                       0x0001  /* DSP1_START */
139 #define ADSP2_START_MASK                  0x0001  /* DSP1_START */
140 #define ADSP2_START_SHIFT                      0  /* DSP1_START */
141 #define ADSP2_START_WIDTH                      1  /* DSP1_START */
142 
143 /*
144  * ADSP2 clocking
145  */
146 #define ADSP2_CLK_SEL_MASK                0x0007  /* CLK_SEL_ENA */
147 #define ADSP2_CLK_SEL_SHIFT                    0  /* CLK_SEL_ENA */
148 #define ADSP2_CLK_SEL_WIDTH                    3  /* CLK_SEL_ENA */
149 
150 /*
151  * ADSP2 Status 1
152  */
153 #define ADSP2_RAM_RDY                     0x0001
154 #define ADSP2_RAM_RDY_MASK                0x0001
155 #define ADSP2_RAM_RDY_SHIFT                    0
156 #define ADSP2_RAM_RDY_WIDTH                    1
157 
158 struct wm_adsp_buf {
159         struct list_head list;
160         void *buf;
161 };
162 
163 static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len,
164                                              struct list_head *list)
165 {
166         struct wm_adsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL);
167 
168         if (buf == NULL)
169                 return NULL;
170 
171         buf->buf = kmemdup(src, len, GFP_KERNEL | GFP_DMA);
172         if (!buf->buf) {
173                 kfree(buf);
174                 return NULL;
175         }
176 
177         if (list)
178                 list_add_tail(&buf->list, list);
179 
180         return buf;
181 }
182 
183 static void wm_adsp_buf_free(struct list_head *list)
184 {
185         while (!list_empty(list)) {
186                 struct wm_adsp_buf *buf = list_first_entry(list,
187                                                            struct wm_adsp_buf,
188                                                            list);
189                 list_del(&buf->list);
190                 kfree(buf->buf);
191                 kfree(buf);
192         }
193 }
194 
195 #define WM_ADSP_NUM_FW 4
196 
197 #define WM_ADSP_FW_MBC_VSS 0
198 #define WM_ADSP_FW_TX      1
199 #define WM_ADSP_FW_TX_SPK  2
200 #define WM_ADSP_FW_RX_ANC  3
201 
202 static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
203         [WM_ADSP_FW_MBC_VSS] = "MBC/VSS",
204         [WM_ADSP_FW_TX] =      "Tx",
205         [WM_ADSP_FW_TX_SPK] =  "Tx Speaker",
206         [WM_ADSP_FW_RX_ANC] =  "Rx ANC",
207 };
208 
209 static struct {
210         const char *file;
211 } wm_adsp_fw[WM_ADSP_NUM_FW] = {
212         [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" },
213         [WM_ADSP_FW_TX] =      { .file = "tx" },
214         [WM_ADSP_FW_TX_SPK] =  { .file = "tx-spk" },
215         [WM_ADSP_FW_RX_ANC] =  { .file = "rx-anc" },
216 };
217 
218 static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
219                           struct snd_ctl_elem_value *ucontrol)
220 {
221         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
222         struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
223         struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec);
224 
225         ucontrol->value.integer.value[0] = adsp[e->shift_l].fw;
226 
227         return 0;
228 }
229 
230 static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
231                           struct snd_ctl_elem_value *ucontrol)
232 {
233         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
234         struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
235         struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec);
236 
237         if (ucontrol->value.integer.value[0] == adsp[e->shift_l].fw)
238                 return 0;
239 
240         if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW)
241                 return -EINVAL;
242 
243         if (adsp[e->shift_l].running)
244                 return -EBUSY;
245 
246         adsp[e->shift_l].fw = ucontrol->value.integer.value[0];
247 
248         return 0;
249 }
250 
251 static const struct soc_enum wm_adsp_fw_enum[] = {
252         SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
253         SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
254         SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
255         SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
256 };
257 
258 const struct snd_kcontrol_new wm_adsp1_fw_controls[] = {
259         SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
260                      wm_adsp_fw_get, wm_adsp_fw_put),
261         SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
262                      wm_adsp_fw_get, wm_adsp_fw_put),
263         SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
264                      wm_adsp_fw_get, wm_adsp_fw_put),
265 };
266 EXPORT_SYMBOL_GPL(wm_adsp1_fw_controls);
267 
268 #if IS_ENABLED(CONFIG_SND_SOC_ARIZONA)
269 static const struct soc_enum wm_adsp2_rate_enum[] = {
270         SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1,
271                               ARIZONA_DSP1_RATE_SHIFT, 0xf,
272                               ARIZONA_RATE_ENUM_SIZE,
273                               arizona_rate_text, arizona_rate_val),
274         SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1,
275                               ARIZONA_DSP1_RATE_SHIFT, 0xf,
276                               ARIZONA_RATE_ENUM_SIZE,
277                               arizona_rate_text, arizona_rate_val),
278         SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
279                               ARIZONA_DSP1_RATE_SHIFT, 0xf,
280                               ARIZONA_RATE_ENUM_SIZE,
281                               arizona_rate_text, arizona_rate_val),
282         SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
283                               ARIZONA_DSP1_RATE_SHIFT, 0xf,
284                               ARIZONA_RATE_ENUM_SIZE,
285                               arizona_rate_text, arizona_rate_val),
286 };
287 
288 const struct snd_kcontrol_new wm_adsp2_fw_controls[] = {
289         SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
290                      wm_adsp_fw_get, wm_adsp_fw_put),
291         SOC_ENUM("DSP1 Rate", wm_adsp2_rate_enum[0]),
292         SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
293                      wm_adsp_fw_get, wm_adsp_fw_put),
294         SOC_ENUM("DSP2 Rate", wm_adsp2_rate_enum[1]),
295         SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
296                      wm_adsp_fw_get, wm_adsp_fw_put),
297         SOC_ENUM("DSP3 Rate", wm_adsp2_rate_enum[2]),
298         SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3],
299                      wm_adsp_fw_get, wm_adsp_fw_put),
300         SOC_ENUM("DSP4 Rate", wm_adsp2_rate_enum[3]),
301 };
302 EXPORT_SYMBOL_GPL(wm_adsp2_fw_controls);
303 #endif
304 
305 static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
306                                                         int type)
307 {
308         int i;
309 
310         for (i = 0; i < dsp->num_mems; i++)
311                 if (dsp->mem[i].type == type)
312                         return &dsp->mem[i];
313 
314         return NULL;
315 }
316 
317 static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region,
318                                           unsigned int offset)
319 {
320         switch (region->type) {
321         case WMFW_ADSP1_PM:
322                 return region->base + (offset * 3);
323         case WMFW_ADSP1_DM:
324                 return region->base + (offset * 2);
325         case WMFW_ADSP2_XM:
326                 return region->base + (offset * 2);
327         case WMFW_ADSP2_YM:
328                 return region->base + (offset * 2);
329         case WMFW_ADSP1_ZM:
330                 return region->base + (offset * 2);
331         default:
332                 WARN_ON(NULL != "Unknown memory region type");
333                 return offset;
334         }
335 }
336 
337 static int wm_adsp_load(struct wm_adsp *dsp)
338 {
339         LIST_HEAD(buf_list);
340         const struct firmware *firmware;
341         struct regmap *regmap = dsp->regmap;
342         unsigned int pos = 0;
343         const struct wmfw_header *header;
344         const struct wmfw_adsp1_sizes *adsp1_sizes;
345         const struct wmfw_adsp2_sizes *adsp2_sizes;
346         const struct wmfw_footer *footer;
347         const struct wmfw_region *region;
348         const struct wm_adsp_region *mem;
349         const char *region_name;
350         char *file, *text;
351         struct wm_adsp_buf *buf;
352         unsigned int reg;
353         int regions = 0;
354         int ret, offset, type, sizes;
355 
356         file = kzalloc(PAGE_SIZE, GFP_KERNEL);
357         if (file == NULL)
358                 return -ENOMEM;
359 
360         snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.wmfw", dsp->part, dsp->num,
361                  wm_adsp_fw[dsp->fw].file);
362         file[PAGE_SIZE - 1] = '\0';
363 
364         ret = request_firmware(&firmware, file, dsp->dev);
365         if (ret != 0) {
366                 adsp_err(dsp, "Failed to request '%s'\n", file);
367                 goto out;
368         }
369         ret = -EINVAL;
370 
371         pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
372         if (pos >= firmware->size) {
373                 adsp_err(dsp, "%s: file too short, %zu bytes\n",
374                          file, firmware->size);
375                 goto out_fw;
376         }
377 
378         header = (void*)&firmware->data[0];
379 
380         if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
381                 adsp_err(dsp, "%s: invalid magic\n", file);
382                 goto out_fw;
383         }
384 
385         if (header->ver != 0) {
386                 adsp_err(dsp, "%s: unknown file format %d\n",
387                          file, header->ver);
388                 goto out_fw;
389         }
390 
391         if (header->core != dsp->type) {
392                 adsp_err(dsp, "%s: invalid core %d != %d\n",
393                          file, header->core, dsp->type);
394                 goto out_fw;
395         }
396 
397         switch (dsp->type) {
398         case WMFW_ADSP1:
399                 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
400                 adsp1_sizes = (void *)&(header[1]);
401                 footer = (void *)&(adsp1_sizes[1]);
402                 sizes = sizeof(*adsp1_sizes);
403 
404                 adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n",
405                          file, le32_to_cpu(adsp1_sizes->dm),
406                          le32_to_cpu(adsp1_sizes->pm),
407                          le32_to_cpu(adsp1_sizes->zm));
408                 break;
409 
410         case WMFW_ADSP2:
411                 pos = sizeof(*header) + sizeof(*adsp2_sizes) + sizeof(*footer);
412                 adsp2_sizes = (void *)&(header[1]);
413                 footer = (void *)&(adsp2_sizes[1]);
414                 sizes = sizeof(*adsp2_sizes);
415 
416                 adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n",
417                          file, le32_to_cpu(adsp2_sizes->xm),
418                          le32_to_cpu(adsp2_sizes->ym),
419                          le32_to_cpu(adsp2_sizes->pm),
420                          le32_to_cpu(adsp2_sizes->zm));
421                 break;
422 
423         default:
424                 BUG_ON(NULL == "Unknown DSP type");
425                 goto out_fw;
426         }
427 
428         if (le32_to_cpu(header->len) != sizeof(*header) +
429             sizes + sizeof(*footer)) {
430                 adsp_err(dsp, "%s: unexpected header length %d\n",
431                          file, le32_to_cpu(header->len));
432                 goto out_fw;
433         }
434 
435         adsp_dbg(dsp, "%s: timestamp %llu\n", file,
436                  le64_to_cpu(footer->timestamp));
437 
438         while (pos < firmware->size &&
439                pos - firmware->size > sizeof(*region)) {
440                 region = (void *)&(firmware->data[pos]);
441                 region_name = "Unknown";
442                 reg = 0;
443                 text = NULL;
444                 offset = le32_to_cpu(region->offset) & 0xffffff;
445                 type = be32_to_cpu(region->type) & 0xff;
446                 mem = wm_adsp_find_region(dsp, type);
447                 
448                 switch (type) {
449                 case WMFW_NAME_TEXT:
450                         region_name = "Firmware name";
451                         text = kzalloc(le32_to_cpu(region->len) + 1,
452                                        GFP_KERNEL);
453                         break;
454                 case WMFW_INFO_TEXT:
455                         region_name = "Information";
456                         text = kzalloc(le32_to_cpu(region->len) + 1,
457                                        GFP_KERNEL);
458                         break;
459                 case WMFW_ABSOLUTE:
460                         region_name = "Absolute";
461                         reg = offset;
462                         break;
463                 case WMFW_ADSP1_PM:
464                         BUG_ON(!mem);
465                         region_name = "PM";
466                         reg = wm_adsp_region_to_reg(mem, offset);
467                         break;
468                 case WMFW_ADSP1_DM:
469                         BUG_ON(!mem);
470                         region_name = "DM";
471                         reg = wm_adsp_region_to_reg(mem, offset);
472                         break;
473                 case WMFW_ADSP2_XM:
474                         BUG_ON(!mem);
475                         region_name = "XM";
476                         reg = wm_adsp_region_to_reg(mem, offset);
477                         break;
478                 case WMFW_ADSP2_YM:
479                         BUG_ON(!mem);
480                         region_name = "YM";
481                         reg = wm_adsp_region_to_reg(mem, offset);
482                         break;
483                 case WMFW_ADSP1_ZM:
484                         BUG_ON(!mem);
485                         region_name = "ZM";
486                         reg = wm_adsp_region_to_reg(mem, offset);
487                         break;
488                 default:
489                         adsp_warn(dsp,
490                                   "%s.%d: Unknown region type %x at %d(%x)\n",
491                                   file, regions, type, pos, pos);
492                         break;
493                 }
494 
495                 adsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file,
496                          regions, le32_to_cpu(region->len), offset,
497                          region_name);
498 
499                 if (text) {
500                         memcpy(text, region->data, le32_to_cpu(region->len));
501                         adsp_info(dsp, "%s: %s\n", file, text);
502                         kfree(text);
503                 }
504 
505                 if (reg) {
506                         buf = wm_adsp_buf_alloc(region->data,
507                                                 le32_to_cpu(region->len),
508                                                 &buf_list);
509                         if (!buf) {
510                                 adsp_err(dsp, "Out of memory\n");
511                                 return -ENOMEM;
512                         }
513 
514                         ret = regmap_raw_write_async(regmap, reg, buf->buf,
515                                                      le32_to_cpu(region->len));
516                         if (ret != 0) {
517                                 adsp_err(dsp,
518                                         "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
519                                         file, regions,
520                                         le32_to_cpu(region->len), offset,
521                                         region_name, ret);
522                                 goto out_fw;
523                         }
524                 }
525 
526                 pos += le32_to_cpu(region->len) + sizeof(*region);
527                 regions++;
528         }
529 
530         ret = regmap_async_complete(regmap);
531         if (ret != 0) {
532                 adsp_err(dsp, "Failed to complete async write: %d\n", ret);
533                 goto out_fw;
534         }
535 
536         if (pos > firmware->size)
537                 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
538                           file, regions, pos - firmware->size);
539 
540 out_fw:
541         regmap_async_complete(regmap);
542         wm_adsp_buf_free(&buf_list);
543         release_firmware(firmware);
544 out:
545         kfree(file);
546 
547         return ret;
548 }
549 
550 static int wm_adsp_setup_algs(struct wm_adsp *dsp)
551 {
552         struct regmap *regmap = dsp->regmap;
553         struct wmfw_adsp1_id_hdr adsp1_id;
554         struct wmfw_adsp2_id_hdr adsp2_id;
555         struct wmfw_adsp1_alg_hdr *adsp1_alg;
556         struct wmfw_adsp2_alg_hdr *adsp2_alg;
557         void *alg, *buf;
558         struct wm_adsp_alg_region *region;
559         const struct wm_adsp_region *mem;
560         unsigned int pos, term;
561         size_t algs, buf_size;
562         __be32 val;
563         int i, ret;
564 
565         switch (dsp->type) {
566         case WMFW_ADSP1:
567                 mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
568                 break;
569         case WMFW_ADSP2:
570                 mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
571                 break;
572         default:
573                 mem = NULL;
574                 break;
575         }
576 
577         if (mem == NULL) {
578                 BUG_ON(mem != NULL);
579                 return -EINVAL;
580         }
581 
582         switch (dsp->type) {
583         case WMFW_ADSP1:
584                 ret = regmap_raw_read(regmap, mem->base, &adsp1_id,
585                                       sizeof(adsp1_id));
586                 if (ret != 0) {
587                         adsp_err(dsp, "Failed to read algorithm info: %d\n",
588                                  ret);
589                         return ret;
590                 }
591 
592                 buf = &adsp1_id;
593                 buf_size = sizeof(adsp1_id);
594 
595                 algs = be32_to_cpu(adsp1_id.algs);
596                 dsp->fw_id = be32_to_cpu(adsp1_id.fw.id);
597                 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
598                           dsp->fw_id,
599                           (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
600                           (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
601                           be32_to_cpu(adsp1_id.fw.ver) & 0xff,
602                           algs);
603 
604                 region = kzalloc(sizeof(*region), GFP_KERNEL);
605                 if (!region)
606                         return -ENOMEM;
607                 region->type = WMFW_ADSP1_ZM;
608                 region->alg = be32_to_cpu(adsp1_id.fw.id);
609                 region->base = be32_to_cpu(adsp1_id.zm);
610                 list_add_tail(&region->list, &dsp->alg_regions);
611 
612                 region = kzalloc(sizeof(*region), GFP_KERNEL);
613                 if (!region)
614                         return -ENOMEM;
615                 region->type = WMFW_ADSP1_DM;
616                 region->alg = be32_to_cpu(adsp1_id.fw.id);
617                 region->base = be32_to_cpu(adsp1_id.dm);
618                 list_add_tail(&region->list, &dsp->alg_regions);
619 
620                 pos = sizeof(adsp1_id) / 2;
621                 term = pos + ((sizeof(*adsp1_alg) * algs) / 2);
622                 break;
623 
624         case WMFW_ADSP2:
625                 ret = regmap_raw_read(regmap, mem->base, &adsp2_id,
626                                       sizeof(adsp2_id));
627                 if (ret != 0) {
628                         adsp_err(dsp, "Failed to read algorithm info: %d\n",
629                                  ret);
630                         return ret;
631                 }
632 
633                 buf = &adsp2_id;
634                 buf_size = sizeof(adsp2_id);
635 
636                 algs = be32_to_cpu(adsp2_id.algs);
637                 dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
638                 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
639                           dsp->fw_id,
640                           (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
641                           (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
642                           be32_to_cpu(adsp2_id.fw.ver) & 0xff,
643                           algs);
644 
645                 region = kzalloc(sizeof(*region), GFP_KERNEL);
646                 if (!region)
647                         return -ENOMEM;
648                 region->type = WMFW_ADSP2_XM;
649                 region->alg = be32_to_cpu(adsp2_id.fw.id);
650                 region->base = be32_to_cpu(adsp2_id.xm);
651                 list_add_tail(&region->list, &dsp->alg_regions);
652 
653                 region = kzalloc(sizeof(*region), GFP_KERNEL);
654                 if (!region)
655                         return -ENOMEM;
656                 region->type = WMFW_ADSP2_YM;
657                 region->alg = be32_to_cpu(adsp2_id.fw.id);
658                 region->base = be32_to_cpu(adsp2_id.ym);
659                 list_add_tail(&region->list, &dsp->alg_regions);
660 
661                 region = kzalloc(sizeof(*region), GFP_KERNEL);
662                 if (!region)
663                         return -ENOMEM;
664                 region->type = WMFW_ADSP2_ZM;
665                 region->alg = be32_to_cpu(adsp2_id.fw.id);
666                 region->base = be32_to_cpu(adsp2_id.zm);
667                 list_add_tail(&region->list, &dsp->alg_regions);
668 
669                 pos = sizeof(adsp2_id) / 2;
670                 term = pos + ((sizeof(*adsp2_alg) * algs) / 2);
671                 break;
672 
673         default:
674                 BUG_ON(NULL == "Unknown DSP type");
675                 return -EINVAL;
676         }
677 
678         if (algs == 0) {
679                 adsp_err(dsp, "No algorithms\n");
680                 return -EINVAL;
681         }
682 
683         if (algs > 1024) {
684                 adsp_err(dsp, "Algorithm count %zx excessive\n", algs);
685                 print_hex_dump_bytes(dev_name(dsp->dev), DUMP_PREFIX_OFFSET,
686                                      buf, buf_size);
687                 return -EINVAL;
688         }
689 
690         /* Read the terminator first to validate the length */
691         ret = regmap_raw_read(regmap, mem->base + term, &val, sizeof(val));
692         if (ret != 0) {
693                 adsp_err(dsp, "Failed to read algorithm list end: %d\n",
694                         ret);
695                 return ret;
696         }
697 
698         if (be32_to_cpu(val) != 0xbedead)
699                 adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n",
700                           term, be32_to_cpu(val));
701 
702         alg = kzalloc((term - pos) * 2, GFP_KERNEL | GFP_DMA);
703         if (!alg)
704                 return -ENOMEM;
705 
706         ret = regmap_raw_read(regmap, mem->base + pos, alg, (term - pos) * 2);
707         if (ret != 0) {
708                 adsp_err(dsp, "Failed to read algorithm list: %d\n",
709                         ret);
710                 goto out;
711         }
712 
713         adsp1_alg = alg;
714         adsp2_alg = alg;
715 
716         for (i = 0; i < algs; i++) {
717                 switch (dsp->type) {
718                 case WMFW_ADSP1:
719                         adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
720                                   i, be32_to_cpu(adsp1_alg[i].alg.id),
721                                   (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
722                                   (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
723                                   be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
724                                   be32_to_cpu(adsp1_alg[i].dm),
725                                   be32_to_cpu(adsp1_alg[i].zm));
726 
727                         region = kzalloc(sizeof(*region), GFP_KERNEL);
728                         if (!region)
729                                 return -ENOMEM;
730                         region->type = WMFW_ADSP1_DM;
731                         region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
732                         region->base = be32_to_cpu(adsp1_alg[i].dm);
733                         list_add_tail(&region->list, &dsp->alg_regions);
734 
735                         region = kzalloc(sizeof(*region), GFP_KERNEL);
736                         if (!region)
737                                 return -ENOMEM;
738                         region->type = WMFW_ADSP1_ZM;
739                         region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
740                         region->base = be32_to_cpu(adsp1_alg[i].zm);
741                         list_add_tail(&region->list, &dsp->alg_regions);
742                         break;
743 
744                 case WMFW_ADSP2:
745                         adsp_info(dsp,
746                                   "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
747                                   i, be32_to_cpu(adsp2_alg[i].alg.id),
748                                   (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
749                                   (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
750                                   be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
751                                   be32_to_cpu(adsp2_alg[i].xm),
752                                   be32_to_cpu(adsp2_alg[i].ym),
753                                   be32_to_cpu(adsp2_alg[i].zm));
754 
755                         region = kzalloc(sizeof(*region), GFP_KERNEL);
756                         if (!region)
757                                 return -ENOMEM;
758                         region->type = WMFW_ADSP2_XM;
759                         region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
760                         region->base = be32_to_cpu(adsp2_alg[i].xm);
761                         list_add_tail(&region->list, &dsp->alg_regions);
762 
763                         region = kzalloc(sizeof(*region), GFP_KERNEL);
764                         if (!region)
765                                 return -ENOMEM;
766                         region->type = WMFW_ADSP2_YM;
767                         region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
768                         region->base = be32_to_cpu(adsp2_alg[i].ym);
769                         list_add_tail(&region->list, &dsp->alg_regions);
770 
771                         region = kzalloc(sizeof(*region), GFP_KERNEL);
772                         if (!region)
773                                 return -ENOMEM;
774                         region->type = WMFW_ADSP2_ZM;
775                         region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
776                         region->base = be32_to_cpu(adsp2_alg[i].zm);
777                         list_add_tail(&region->list, &dsp->alg_regions);
778                         break;
779                 }
780         }
781 
782 out:
783         kfree(alg);
784         return ret;
785 }
786 
787 static int wm_adsp_load_coeff(struct wm_adsp *dsp)
788 {
789         LIST_HEAD(buf_list);
790         struct regmap *regmap = dsp->regmap;
791         struct wmfw_coeff_hdr *hdr;
792         struct wmfw_coeff_item *blk;
793         const struct firmware *firmware;
794         const struct wm_adsp_region *mem;
795         struct wm_adsp_alg_region *alg_region;
796         const char *region_name;
797         int ret, pos, blocks, type, offset, reg;
798         char *file;
799         struct wm_adsp_buf *buf;
800         int tmp;
801 
802         file = kzalloc(PAGE_SIZE, GFP_KERNEL);
803         if (file == NULL)
804                 return -ENOMEM;
805 
806         snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.bin", dsp->part, dsp->num,
807                  wm_adsp_fw[dsp->fw].file);
808         file[PAGE_SIZE - 1] = '\0';
809 
810         ret = request_firmware(&firmware, file, dsp->dev);
811         if (ret != 0) {
812                 adsp_warn(dsp, "Failed to request '%s'\n", file);
813                 ret = 0;
814                 goto out;
815         }
816         ret = -EINVAL;
817 
818         if (sizeof(*hdr) >= firmware->size) {
819                 adsp_err(dsp, "%s: file too short, %zu bytes\n",
820                         file, firmware->size);
821                 goto out_fw;
822         }
823 
824         hdr = (void*)&firmware->data[0];
825         if (memcmp(hdr->magic, "WMDR", 4) != 0) {
826                 adsp_err(dsp, "%s: invalid magic\n", file);
827                 goto out_fw;
828         }
829 
830         switch (be32_to_cpu(hdr->rev) & 0xff) {
831         case 1:
832                 break;
833         default:
834                 adsp_err(dsp, "%s: Unsupported coefficient file format %d\n",
835                          file, be32_to_cpu(hdr->rev) & 0xff);
836                 ret = -EINVAL;
837                 goto out_fw;
838         }
839 
840         adsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
841                 (le32_to_cpu(hdr->ver) >> 16) & 0xff,
842                 (le32_to_cpu(hdr->ver) >>  8) & 0xff,
843                 le32_to_cpu(hdr->ver) & 0xff);
844 
845         pos = le32_to_cpu(hdr->len);
846 
847         blocks = 0;
848         while (pos < firmware->size &&
849                pos - firmware->size > sizeof(*blk)) {
850                 blk = (void*)(&firmware->data[pos]);
851 
852                 type = le16_to_cpu(blk->type);
853                 offset = le16_to_cpu(blk->offset);
854 
855                 adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n",
856                          file, blocks, le32_to_cpu(blk->id),
857                          (le32_to_cpu(blk->ver) >> 16) & 0xff,
858                          (le32_to_cpu(blk->ver) >>  8) & 0xff,
859                          le32_to_cpu(blk->ver) & 0xff);
860                 adsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n",
861                          file, blocks, le32_to_cpu(blk->len), offset, type);
862 
863                 reg = 0;
864                 region_name = "Unknown";
865                 switch (type) {
866                 case (WMFW_NAME_TEXT << 8):
867                 case (WMFW_INFO_TEXT << 8):
868                         break;
869                 case (WMFW_ABSOLUTE << 8):
870                         /*
871                          * Old files may use this for global
872                          * coefficients.
873                          */
874                         if (le32_to_cpu(blk->id) == dsp->fw_id &&
875                             offset == 0) {
876                                 region_name = "global coefficients";
877                                 mem = wm_adsp_find_region(dsp, type);
878                                 if (!mem) {
879                                         adsp_err(dsp, "No ZM\n");
880                                         break;
881                                 }
882                                 reg = wm_adsp_region_to_reg(mem, 0);
883 
884                         } else {
885                                 region_name = "register";
886                                 reg = offset;
887                         }
888                         break;
889 
890                 case WMFW_ADSP1_DM:
891                 case WMFW_ADSP1_ZM:
892                 case WMFW_ADSP2_XM:
893                 case WMFW_ADSP2_YM:
894                         adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n",
895                                  file, blocks, le32_to_cpu(blk->len),
896                                  type, le32_to_cpu(blk->id));
897 
898                         mem = wm_adsp_find_region(dsp, type);
899                         if (!mem) {
900                                 adsp_err(dsp, "No base for region %x\n", type);
901                                 break;
902                         }
903 
904                         reg = 0;
905                         list_for_each_entry(alg_region,
906                                             &dsp->alg_regions, list) {
907                                 if (le32_to_cpu(blk->id) == alg_region->alg &&
908                                     type == alg_region->type) {
909                                         reg = alg_region->base;
910                                         reg = wm_adsp_region_to_reg(mem,
911                                                                     reg);
912                                         reg += offset;
913                                 }
914                         }
915 
916                         if (reg == 0)
917                                 adsp_err(dsp, "No %x for algorithm %x\n",
918                                          type, le32_to_cpu(blk->id));
919                         break;
920 
921                 default:
922                         adsp_err(dsp, "%s.%d: Unknown region type %x at %d\n",
923                                  file, blocks, type, pos);
924                         break;
925                 }
926 
927                 if (reg) {
928                         buf = wm_adsp_buf_alloc(blk->data,
929                                                 le32_to_cpu(blk->len),
930                                                 &buf_list);
931                         if (!buf) {
932                                 adsp_err(dsp, "Out of memory\n");
933                                 ret = -ENOMEM;
934                                 goto out_fw;
935                         }
936 
937                         adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
938                                  file, blocks, le32_to_cpu(blk->len),
939                                  reg);
940                         ret = regmap_raw_write_async(regmap, reg, buf->buf,
941                                                      le32_to_cpu(blk->len));
942                         if (ret != 0) {
943                                 adsp_err(dsp,
944                                         "%s.%d: Failed to write to %x in %s\n",
945                                         file, blocks, reg, region_name);
946                         }
947                 }
948 
949                 tmp = le32_to_cpu(blk->len) % 4;
950                 if (tmp)
951                         pos += le32_to_cpu(blk->len) + (4 - tmp) + sizeof(*blk);
952                 else
953                         pos += le32_to_cpu(blk->len) + sizeof(*blk);
954 
955                 blocks++;
956         }
957 
958         ret = regmap_async_complete(regmap);
959         if (ret != 0)
960                 adsp_err(dsp, "Failed to complete async write: %d\n", ret);
961 
962         if (pos > firmware->size)
963                 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
964                           file, blocks, pos - firmware->size);
965 
966 out_fw:
967         regmap_async_complete(regmap);
968         release_firmware(firmware);
969         wm_adsp_buf_free(&buf_list);
970 out:
971         kfree(file);
972         return ret;
973 }
974 
975 int wm_adsp1_init(struct wm_adsp *adsp)
976 {
977         INIT_LIST_HEAD(&adsp->alg_regions);
978 
979         return 0;
980 }
981 EXPORT_SYMBOL_GPL(wm_adsp1_init);
982 
983 int wm_adsp1_event(struct snd_soc_dapm_widget *w,
984                    struct snd_kcontrol *kcontrol,
985                    int event)
986 {
987         struct snd_soc_codec *codec = w->codec;
988         struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
989         struct wm_adsp *dsp = &dsps[w->shift];
990         int ret;
991         int val;
992 
993         switch (event) {
994         case SND_SOC_DAPM_POST_PMU:
995                 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
996                                    ADSP1_SYS_ENA, ADSP1_SYS_ENA);
997 
998                 /*
999                  * For simplicity set the DSP clock rate to be the
1000                  * SYSCLK rate rather than making it configurable.
1001                  */
1002                 if(dsp->sysclk_reg) {
1003                         ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
1004                         if (ret != 0) {
1005                                 adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
1006                                 ret);
1007                                 return ret;
1008                         }
1009 
1010                         val = (val & dsp->sysclk_mask)
1011                                 >> dsp->sysclk_shift;
1012 
1013                         ret = regmap_update_bits(dsp->regmap,
1014                                                  dsp->base + ADSP1_CONTROL_31,
1015                                                  ADSP1_CLK_SEL_MASK, val);
1016                         if (ret != 0) {
1017                                 adsp_err(dsp, "Failed to set clock rate: %d\n",
1018                                          ret);
1019                                 return ret;
1020                         }
1021                 }
1022 
1023                 ret = wm_adsp_load(dsp);
1024                 if (ret != 0)
1025                         goto err;
1026 
1027                 ret = wm_adsp_setup_algs(dsp);
1028                 if (ret != 0)
1029                         goto err;
1030 
1031                 ret = wm_adsp_load_coeff(dsp);
1032                 if (ret != 0)
1033                         goto err;
1034 
1035                 /* Start the core running */
1036                 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1037                                    ADSP1_CORE_ENA | ADSP1_START,
1038                                    ADSP1_CORE_ENA | ADSP1_START);
1039                 break;
1040 
1041         case SND_SOC_DAPM_PRE_PMD:
1042                 /* Halt the core */
1043                 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1044                                    ADSP1_CORE_ENA | ADSP1_START, 0);
1045 
1046                 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19,
1047                                    ADSP1_WDMA_BUFFER_LENGTH_MASK, 0);
1048 
1049                 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1050                                    ADSP1_SYS_ENA, 0);
1051                 break;
1052 
1053         default:
1054                 break;
1055         }
1056 
1057         return 0;
1058 
1059 err:
1060         regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1061                            ADSP1_SYS_ENA, 0);
1062         return ret;
1063 }
1064 EXPORT_SYMBOL_GPL(wm_adsp1_event);
1065 
1066 static int wm_adsp2_ena(struct wm_adsp *dsp)
1067 {
1068         unsigned int val;
1069         int ret, count;
1070 
1071         ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
1072                                  ADSP2_SYS_ENA, ADSP2_SYS_ENA);
1073         if (ret != 0)
1074                 return ret;
1075 
1076         /* Wait for the RAM to start, should be near instantaneous */
1077         for (count = 0; count < 10; ++count) {
1078                 ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1,
1079                                   &val);
1080                 if (ret != 0)
1081                         return ret;
1082 
1083                 if (val & ADSP2_RAM_RDY)
1084                         break;
1085 
1086                 msleep(1);
1087         }
1088 
1089         if (!(val & ADSP2_RAM_RDY)) {
1090                 adsp_err(dsp, "Failed to start DSP RAM\n");
1091                 return -EBUSY;
1092         }
1093 
1094         adsp_dbg(dsp, "RAM ready after %d polls\n", count);
1095         adsp_info(dsp, "RAM ready after %d polls\n", count);
1096 
1097         return 0;
1098 }
1099 
1100 int wm_adsp2_event(struct snd_soc_dapm_widget *w,
1101                    struct snd_kcontrol *kcontrol, int event)
1102 {
1103         struct snd_soc_codec *codec = w->codec;
1104         struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
1105         struct wm_adsp *dsp = &dsps[w->shift];
1106         struct wm_adsp_alg_region *alg_region;
1107         unsigned int val;
1108         int ret;
1109 
1110         switch (event) {
1111         case SND_SOC_DAPM_POST_PMU:
1112                 /*
1113                  * For simplicity set the DSP clock rate to be the
1114                  * SYSCLK rate rather than making it configurable.
1115                  */
1116                 ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val);
1117                 if (ret != 0) {
1118                         adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
1119                                  ret);
1120                         return ret;
1121                 }
1122                 val = (val & ARIZONA_SYSCLK_FREQ_MASK)
1123                         >> ARIZONA_SYSCLK_FREQ_SHIFT;
1124 
1125                 ret = regmap_update_bits(dsp->regmap,
1126                                          dsp->base + ADSP2_CLOCKING,
1127                                          ADSP2_CLK_SEL_MASK, val);
1128                 if (ret != 0) {
1129                         adsp_err(dsp, "Failed to set clock rate: %d\n",
1130                                  ret);
1131                         return ret;
1132                 }
1133 
1134                 if (dsp->dvfs) {
1135                         ret = regmap_read(dsp->regmap,
1136                                           dsp->base + ADSP2_CLOCKING, &val);
1137                         if (ret != 0) {
1138                                 dev_err(dsp->dev,
1139                                         "Failed to read clocking: %d\n", ret);
1140                                 return ret;
1141                         }
1142 
1143                         if ((val & ADSP2_CLK_SEL_MASK) >= 3) {
1144                                 ret = regulator_enable(dsp->dvfs);
1145                                 if (ret != 0) {
1146                                         dev_err(dsp->dev,
1147                                                 "Failed to enable supply: %d\n",
1148                                                 ret);
1149                                         return ret;
1150                                 }
1151 
1152                                 ret = regulator_set_voltage(dsp->dvfs,
1153                                                             1800000,
1154                                                             1800000);
1155                                 if (ret != 0) {
1156                                         dev_err(dsp->dev,
1157                                                 "Failed to raise supply: %d\n",
1158                                                 ret);
1159                                         return ret;
1160                                 }
1161                         }
1162                 }
1163 
1164                 ret = wm_adsp2_ena(dsp);
1165                 if (ret != 0)
1166                         return ret;
1167 
1168                 ret = wm_adsp_load(dsp);
1169                 if (ret != 0)
1170                         goto err;
1171 
1172                 ret = wm_adsp_setup_algs(dsp);
1173                 if (ret != 0)
1174                         goto err;
1175 
1176                 ret = wm_adsp_load_coeff(dsp);
1177                 if (ret != 0)
1178                         goto err;
1179 
1180                 ret = regmap_update_bits(dsp->regmap,
1181                                          dsp->base + ADSP2_CONTROL,
1182                                          ADSP2_CORE_ENA | ADSP2_START,
1183                                          ADSP2_CORE_ENA | ADSP2_START);
1184                 if (ret != 0)
1185                         goto err;
1186 
1187                 dsp->running = true;
1188                 break;
1189 
1190         case SND_SOC_DAPM_PRE_PMD:
1191                 dsp->running = false;
1192 
1193                 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
1194                                    ADSP2_SYS_ENA | ADSP2_CORE_ENA |
1195                                    ADSP2_START, 0);
1196 
1197                 /* Make sure DMAs are quiesced */
1198                 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
1199                 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
1200                 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
1201 
1202                 if (dsp->dvfs) {
1203                         ret = regulator_set_voltage(dsp->dvfs, 1200000,
1204                                                     1800000);
1205                         if (ret != 0)
1206                                 dev_warn(dsp->dev,
1207                                          "Failed to lower supply: %d\n",
1208                                          ret);
1209 
1210                         ret = regulator_disable(dsp->dvfs);
1211                         if (ret != 0)
1212                                 dev_err(dsp->dev,
1213                                         "Failed to enable supply: %d\n",
1214                                         ret);
1215                 }
1216 
1217                 while (!list_empty(&dsp->alg_regions)) {
1218                         alg_region = list_first_entry(&dsp->alg_regions,
1219                                                       struct wm_adsp_alg_region,
1220                                                       list);
1221                         list_del(&alg_region->list);
1222                         kfree(alg_region);
1223                 }
1224                 break;
1225 
1226         default:
1227                 break;
1228         }
1229 
1230         return 0;
1231 err:
1232         regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
1233                            ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
1234         return ret;
1235 }
1236 EXPORT_SYMBOL_GPL(wm_adsp2_event);
1237 
1238 int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
1239 {
1240         int ret;
1241 
1242         /*
1243          * Disable the DSP memory by default when in reset for a small
1244          * power saving.
1245          */
1246         ret = regmap_update_bits(adsp->regmap, adsp->base + ADSP2_CONTROL,
1247                                  ADSP2_MEM_ENA, 0);
1248         if (ret != 0) {
1249                 adsp_err(adsp, "Failed to clear memory retention: %d\n", ret);
1250                 return ret;
1251         }
1252 
1253         INIT_LIST_HEAD(&adsp->alg_regions);
1254 
1255         if (dvfs) {
1256                 adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
1257                 if (IS_ERR(adsp->dvfs)) {
1258                         ret = PTR_ERR(adsp->dvfs);
1259                         dev_err(adsp->dev, "Failed to get DCVDD: %d\n", ret);
1260                         return ret;
1261                 }
1262 
1263                 ret = regulator_enable(adsp->dvfs);
1264                 if (ret != 0) {
1265                         dev_err(adsp->dev, "Failed to enable DCVDD: %d\n",
1266                                 ret);
1267                         return ret;
1268                 }
1269 
1270                 ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000);
1271                 if (ret != 0) {
1272                         dev_err(adsp->dev, "Failed to initialise DVFS: %d\n",
1273                                 ret);
1274                         return ret;
1275                 }
1276 
1277                 ret = regulator_disable(adsp->dvfs);
1278                 if (ret != 0) {
1279                         dev_err(adsp->dev, "Failed to disable DCVDD: %d\n",
1280                                 ret);
1281                         return ret;
1282                 }
1283         }
1284 
1285         return 0;
1286 }
1287 EXPORT_SYMBOL_GPL(wm_adsp2_init);
1288 
1289 MODULE_LICENSE("GPL v2");
1290 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp