]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - sound/soc/codecs/wm_adsp.c
Merge commit '6bb27d7349db51b50c40534710fe164ca0d58902' into omap-timer-for-v3.10
[karo-tx-linux.git] / sound / soc / codecs / wm_adsp.c
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/pm.h>
19 #include <linux/pm_runtime.h>
20 #include <linux/regmap.h>
21 #include <linux/regulator/consumer.h>
22 #include <linux/slab.h>
23 #include <sound/core.h>
24 #include <sound/pcm.h>
25 #include <sound/pcm_params.h>
26 #include <sound/soc.h>
27 #include <sound/jack.h>
28 #include <sound/initval.h>
29 #include <sound/tlv.h>
30
31 #include <linux/mfd/arizona/registers.h>
32
33 #include "wm_adsp.h"
34
35 #define adsp_crit(_dsp, fmt, ...) \
36         dev_crit(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
37 #define adsp_err(_dsp, fmt, ...) \
38         dev_err(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
39 #define adsp_warn(_dsp, fmt, ...) \
40         dev_warn(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
41 #define adsp_info(_dsp, fmt, ...) \
42         dev_info(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
43 #define adsp_dbg(_dsp, fmt, ...) \
44         dev_dbg(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
45
46 #define ADSP1_CONTROL_1                   0x00
47 #define ADSP1_CONTROL_2                   0x02
48 #define ADSP1_CONTROL_3                   0x03
49 #define ADSP1_CONTROL_4                   0x04
50 #define ADSP1_CONTROL_5                   0x06
51 #define ADSP1_CONTROL_6                   0x07
52 #define ADSP1_CONTROL_7                   0x08
53 #define ADSP1_CONTROL_8                   0x09
54 #define ADSP1_CONTROL_9                   0x0A
55 #define ADSP1_CONTROL_10                  0x0B
56 #define ADSP1_CONTROL_11                  0x0C
57 #define ADSP1_CONTROL_12                  0x0D
58 #define ADSP1_CONTROL_13                  0x0F
59 #define ADSP1_CONTROL_14                  0x10
60 #define ADSP1_CONTROL_15                  0x11
61 #define ADSP1_CONTROL_16                  0x12
62 #define ADSP1_CONTROL_17                  0x13
63 #define ADSP1_CONTROL_18                  0x14
64 #define ADSP1_CONTROL_19                  0x16
65 #define ADSP1_CONTROL_20                  0x17
66 #define ADSP1_CONTROL_21                  0x18
67 #define ADSP1_CONTROL_22                  0x1A
68 #define ADSP1_CONTROL_23                  0x1B
69 #define ADSP1_CONTROL_24                  0x1C
70 #define ADSP1_CONTROL_25                  0x1E
71 #define ADSP1_CONTROL_26                  0x20
72 #define ADSP1_CONTROL_27                  0x21
73 #define ADSP1_CONTROL_28                  0x22
74 #define ADSP1_CONTROL_29                  0x23
75 #define ADSP1_CONTROL_30                  0x24
76 #define ADSP1_CONTROL_31                  0x26
77
78 /*
79  * ADSP1 Control 19
80  */
81 #define ADSP1_WDMA_BUFFER_LENGTH_MASK     0x00FF  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
82 #define ADSP1_WDMA_BUFFER_LENGTH_SHIFT         0  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
83 #define ADSP1_WDMA_BUFFER_LENGTH_WIDTH         8  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
84
85
86 /*
87  * ADSP1 Control 30
88  */
89 #define ADSP1_DBG_CLK_ENA                 0x0008  /* DSP1_DBG_CLK_ENA */
90 #define ADSP1_DBG_CLK_ENA_MASK            0x0008  /* DSP1_DBG_CLK_ENA */
91 #define ADSP1_DBG_CLK_ENA_SHIFT                3  /* DSP1_DBG_CLK_ENA */
92 #define ADSP1_DBG_CLK_ENA_WIDTH                1  /* DSP1_DBG_CLK_ENA */
93 #define ADSP1_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
94 #define ADSP1_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
95 #define ADSP1_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
96 #define ADSP1_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
97 #define ADSP1_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
98 #define ADSP1_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
99 #define ADSP1_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
100 #define ADSP1_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
101 #define ADSP1_START                       0x0001  /* DSP1_START */
102 #define ADSP1_START_MASK                  0x0001  /* DSP1_START */
103 #define ADSP1_START_SHIFT                      0  /* DSP1_START */
104 #define ADSP1_START_WIDTH                      1  /* DSP1_START */
105
106 #define ADSP2_CONTROL  0
107 #define ADSP2_CLOCKING 1
108 #define ADSP2_STATUS1  4
109
110 /*
111  * ADSP2 Control
112  */
113
114 #define ADSP2_MEM_ENA                     0x0010  /* DSP1_MEM_ENA */
115 #define ADSP2_MEM_ENA_MASK                0x0010  /* DSP1_MEM_ENA */
116 #define ADSP2_MEM_ENA_SHIFT                    4  /* DSP1_MEM_ENA */
117 #define ADSP2_MEM_ENA_WIDTH                    1  /* DSP1_MEM_ENA */
118 #define ADSP2_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
119 #define ADSP2_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
120 #define ADSP2_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
121 #define ADSP2_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
122 #define ADSP2_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
123 #define ADSP2_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
124 #define ADSP2_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
125 #define ADSP2_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
126 #define ADSP2_START                       0x0001  /* DSP1_START */
127 #define ADSP2_START_MASK                  0x0001  /* DSP1_START */
128 #define ADSP2_START_SHIFT                      0  /* DSP1_START */
129 #define ADSP2_START_WIDTH                      1  /* DSP1_START */
130
131 /*
132  * ADSP2 clocking
133  */
134 #define ADSP2_CLK_SEL_MASK                0x0007  /* CLK_SEL_ENA */
135 #define ADSP2_CLK_SEL_SHIFT                    0  /* CLK_SEL_ENA */
136 #define ADSP2_CLK_SEL_WIDTH                    3  /* CLK_SEL_ENA */
137
138 /*
139  * ADSP2 Status 1
140  */
141 #define ADSP2_RAM_RDY                     0x0001
142 #define ADSP2_RAM_RDY_MASK                0x0001
143 #define ADSP2_RAM_RDY_SHIFT                    0
144 #define ADSP2_RAM_RDY_WIDTH                    1
145
146
147 static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
148                                                         int type)
149 {
150         int i;
151
152         for (i = 0; i < dsp->num_mems; i++)
153                 if (dsp->mem[i].type == type)
154                         return &dsp->mem[i];
155
156         return NULL;
157 }
158
159 static int wm_adsp_load(struct wm_adsp *dsp)
160 {
161         const struct firmware *firmware;
162         struct regmap *regmap = dsp->regmap;
163         unsigned int pos = 0;
164         const struct wmfw_header *header;
165         const struct wmfw_adsp1_sizes *adsp1_sizes;
166         const struct wmfw_adsp2_sizes *adsp2_sizes;
167         const struct wmfw_footer *footer;
168         const struct wmfw_region *region;
169         const struct wm_adsp_region *mem;
170         const char *region_name;
171         char *file, *text;
172         void *buf;
173         unsigned int reg;
174         int regions = 0;
175         int ret, offset, type, sizes;
176
177         file = kzalloc(PAGE_SIZE, GFP_KERNEL);
178         if (file == NULL)
179                 return -ENOMEM;
180
181         snprintf(file, PAGE_SIZE, "%s-dsp%d.wmfw", dsp->part, dsp->num);
182         file[PAGE_SIZE - 1] = '\0';
183
184         ret = request_firmware(&firmware, file, dsp->dev);
185         if (ret != 0) {
186                 adsp_err(dsp, "Failed to request '%s'\n", file);
187                 goto out;
188         }
189         ret = -EINVAL;
190
191         pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
192         if (pos >= firmware->size) {
193                 adsp_err(dsp, "%s: file too short, %zu bytes\n",
194                          file, firmware->size);
195                 goto out_fw;
196         }
197
198         header = (void*)&firmware->data[0];
199
200         if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
201                 adsp_err(dsp, "%s: invalid magic\n", file);
202                 goto out_fw;
203         }
204
205         if (header->ver != 0) {
206                 adsp_err(dsp, "%s: unknown file format %d\n",
207                          file, header->ver);
208                 goto out_fw;
209         }
210
211         if (header->core != dsp->type) {
212                 adsp_err(dsp, "%s: invalid core %d != %d\n",
213                          file, header->core, dsp->type);
214                 goto out_fw;
215         }
216
217         switch (dsp->type) {
218         case WMFW_ADSP1:
219                 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
220                 adsp1_sizes = (void *)&(header[1]);
221                 footer = (void *)&(adsp1_sizes[1]);
222                 sizes = sizeof(*adsp1_sizes);
223
224                 adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n",
225                          file, le32_to_cpu(adsp1_sizes->dm),
226                          le32_to_cpu(adsp1_sizes->pm),
227                          le32_to_cpu(adsp1_sizes->zm));
228                 break;
229
230         case WMFW_ADSP2:
231                 pos = sizeof(*header) + sizeof(*adsp2_sizes) + sizeof(*footer);
232                 adsp2_sizes = (void *)&(header[1]);
233                 footer = (void *)&(adsp2_sizes[1]);
234                 sizes = sizeof(*adsp2_sizes);
235
236                 adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n",
237                          file, le32_to_cpu(adsp2_sizes->xm),
238                          le32_to_cpu(adsp2_sizes->ym),
239                          le32_to_cpu(adsp2_sizes->pm),
240                          le32_to_cpu(adsp2_sizes->zm));
241                 break;
242
243         default:
244                 BUG_ON(NULL == "Unknown DSP type");
245                 goto out_fw;
246         }
247
248         if (le32_to_cpu(header->len) != sizeof(*header) +
249             sizes + sizeof(*footer)) {
250                 adsp_err(dsp, "%s: unexpected header length %d\n",
251                          file, le32_to_cpu(header->len));
252                 goto out_fw;
253         }
254
255         adsp_dbg(dsp, "%s: timestamp %llu\n", file,
256                  le64_to_cpu(footer->timestamp));
257
258         while (pos < firmware->size &&
259                pos - firmware->size > sizeof(*region)) {
260                 region = (void *)&(firmware->data[pos]);
261                 region_name = "Unknown";
262                 reg = 0;
263                 text = NULL;
264                 offset = le32_to_cpu(region->offset) & 0xffffff;
265                 type = be32_to_cpu(region->type) & 0xff;
266                 mem = wm_adsp_find_region(dsp, type);
267                 
268                 switch (type) {
269                 case WMFW_NAME_TEXT:
270                         region_name = "Firmware name";
271                         text = kzalloc(le32_to_cpu(region->len) + 1,
272                                        GFP_KERNEL);
273                         break;
274                 case WMFW_INFO_TEXT:
275                         region_name = "Information";
276                         text = kzalloc(le32_to_cpu(region->len) + 1,
277                                        GFP_KERNEL);
278                         break;
279                 case WMFW_ABSOLUTE:
280                         region_name = "Absolute";
281                         reg = offset;
282                         break;
283                 case WMFW_ADSP1_PM:
284                         BUG_ON(!mem);
285                         region_name = "PM";
286                         reg = mem->base + (offset * 3);
287                         break;
288                 case WMFW_ADSP1_DM:
289                         BUG_ON(!mem);
290                         region_name = "DM";
291                         reg = mem->base + (offset * 2);
292                         break;
293                 case WMFW_ADSP2_XM:
294                         BUG_ON(!mem);
295                         region_name = "XM";
296                         reg = mem->base + (offset * 2);
297                         break;
298                 case WMFW_ADSP2_YM:
299                         BUG_ON(!mem);
300                         region_name = "YM";
301                         reg = mem->base + (offset * 2);
302                         break;
303                 case WMFW_ADSP1_ZM:
304                         BUG_ON(!mem);
305                         region_name = "ZM";
306                         reg = mem->base + (offset * 2);
307                         break;
308                 default:
309                         adsp_warn(dsp,
310                                   "%s.%d: Unknown region type %x at %d(%x)\n",
311                                   file, regions, type, pos, pos);
312                         break;
313                 }
314
315                 adsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file,
316                          regions, le32_to_cpu(region->len), offset,
317                          region_name);
318
319                 if (text) {
320                         memcpy(text, region->data, le32_to_cpu(region->len));
321                         adsp_info(dsp, "%s: %s\n", file, text);
322                         kfree(text);
323                 }
324
325                 if (reg) {
326                         buf = kmemdup(region->data, le32_to_cpu(region->len),
327                                       GFP_KERNEL | GFP_DMA);
328                         if (!buf) {
329                                 adsp_err(dsp, "Out of memory\n");
330                                 return -ENOMEM;
331                         }
332
333                         ret = regmap_raw_write(regmap, reg, buf,
334                                                le32_to_cpu(region->len));
335
336                         kfree(buf);
337
338                         if (ret != 0) {
339                                 adsp_err(dsp,
340                                         "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
341                                         file, regions,
342                                         le32_to_cpu(region->len), offset,
343                                         region_name, ret);
344                                 goto out_fw;
345                         }
346                 }
347
348                 pos += le32_to_cpu(region->len) + sizeof(*region);
349                 regions++;
350         }
351         
352         if (pos > firmware->size)
353                 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
354                           file, regions, pos - firmware->size);
355
356 out_fw:
357         release_firmware(firmware);
358 out:
359         kfree(file);
360
361         return ret;
362 }
363
364 static int wm_adsp_load_coeff(struct wm_adsp *dsp)
365 {
366         struct regmap *regmap = dsp->regmap;
367         struct wmfw_coeff_hdr *hdr;
368         struct wmfw_coeff_item *blk;
369         const struct firmware *firmware;
370         const char *region_name;
371         int ret, pos, blocks, type, offset, reg;
372         char *file;
373         void *buf;
374
375         file = kzalloc(PAGE_SIZE, GFP_KERNEL);
376         if (file == NULL)
377                 return -ENOMEM;
378
379         snprintf(file, PAGE_SIZE, "%s-dsp%d.bin", dsp->part, dsp->num);
380         file[PAGE_SIZE - 1] = '\0';
381
382         ret = request_firmware(&firmware, file, dsp->dev);
383         if (ret != 0) {
384                 adsp_warn(dsp, "Failed to request '%s'\n", file);
385                 ret = 0;
386                 goto out;
387         }
388         ret = -EINVAL;
389
390         if (sizeof(*hdr) >= firmware->size) {
391                 adsp_err(dsp, "%s: file too short, %zu bytes\n",
392                         file, firmware->size);
393                 goto out_fw;
394         }
395
396         hdr = (void*)&firmware->data[0];
397         if (memcmp(hdr->magic, "WMDR", 4) != 0) {
398                 adsp_err(dsp, "%s: invalid magic\n", file);
399                 goto out_fw;
400         }
401
402         adsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
403                 (le32_to_cpu(hdr->ver) >> 16) & 0xff,
404                 (le32_to_cpu(hdr->ver) >>  8) & 0xff,
405                 le32_to_cpu(hdr->ver) & 0xff);
406
407         pos = le32_to_cpu(hdr->len);
408
409         blocks = 0;
410         while (pos < firmware->size &&
411                pos - firmware->size > sizeof(*blk)) {
412                 blk = (void*)(&firmware->data[pos]);
413
414                 type = be32_to_cpu(blk->type) & 0xff;
415                 offset = le32_to_cpu(blk->offset) & 0xffffff;
416
417                 adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n",
418                          file, blocks, le32_to_cpu(blk->id),
419                          (le32_to_cpu(blk->ver) >> 16) & 0xff,
420                          (le32_to_cpu(blk->ver) >>  8) & 0xff,
421                          le32_to_cpu(blk->ver) & 0xff);
422                 adsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n",
423                          file, blocks, le32_to_cpu(blk->len), offset, type);
424
425                 reg = 0;
426                 region_name = "Unknown";
427                 switch (type) {
428                 case WMFW_NAME_TEXT:
429                 case WMFW_INFO_TEXT:
430                         break;
431                 case WMFW_ABSOLUTE:
432                         region_name = "register";
433                         reg = offset;
434                         break;
435                 default:
436                         adsp_err(dsp, "Unknown region type %x\n", type);
437                         break;
438                 }
439
440                 if (reg) {
441                         buf = kmemdup(blk->data, le32_to_cpu(blk->len),
442                                       GFP_KERNEL | GFP_DMA);
443                         if (!buf) {
444                                 adsp_err(dsp, "Out of memory\n");
445                                 return -ENOMEM;
446                         }
447
448                         ret = regmap_raw_write(regmap, reg, blk->data,
449                                                le32_to_cpu(blk->len));
450                         if (ret != 0) {
451                                 adsp_err(dsp,
452                                         "%s.%d: Failed to write to %x in %s\n",
453                                         file, blocks, reg, region_name);
454                         }
455
456                         kfree(buf);
457                 }
458
459                 pos += le32_to_cpu(blk->len) + sizeof(*blk);
460                 blocks++;
461         }
462
463         if (pos > firmware->size)
464                 adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
465                           file, blocks, pos - firmware->size);
466
467 out_fw:
468         release_firmware(firmware);
469 out:
470         kfree(file);
471         return 0;
472 }
473
474 int wm_adsp1_event(struct snd_soc_dapm_widget *w,
475                    struct snd_kcontrol *kcontrol,
476                    int event)
477 {
478         struct snd_soc_codec *codec = w->codec;
479         struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
480         struct wm_adsp *dsp = &dsps[w->shift];
481         int ret;
482
483         switch (event) {
484         case SND_SOC_DAPM_POST_PMU:
485                 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
486                                    ADSP1_SYS_ENA, ADSP1_SYS_ENA);
487
488                 ret = wm_adsp_load(dsp);
489                 if (ret != 0)
490                         goto err;
491
492                 ret = wm_adsp_load_coeff(dsp);
493                 if (ret != 0)
494                         goto err;
495
496                 /* Start the core running */
497                 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
498                                    ADSP1_CORE_ENA | ADSP1_START,
499                                    ADSP1_CORE_ENA | ADSP1_START);
500                 break;
501
502         case SND_SOC_DAPM_PRE_PMD:
503                 /* Halt the core */
504                 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
505                                    ADSP1_CORE_ENA | ADSP1_START, 0);
506
507                 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19,
508                                    ADSP1_WDMA_BUFFER_LENGTH_MASK, 0);
509
510                 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
511                                    ADSP1_SYS_ENA, 0);
512                 break;
513
514         default:
515                 break;
516         }
517
518         return 0;
519
520 err:
521         regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
522                            ADSP1_SYS_ENA, 0);
523         return ret;
524 }
525 EXPORT_SYMBOL_GPL(wm_adsp1_event);
526
527 static int wm_adsp2_ena(struct wm_adsp *dsp)
528 {
529         unsigned int val;
530         int ret, count;
531
532         ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
533                                  ADSP2_SYS_ENA, ADSP2_SYS_ENA);
534         if (ret != 0)
535                 return ret;
536
537         /* Wait for the RAM to start, should be near instantaneous */
538         count = 0;
539         do {
540                 ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1,
541                                   &val);
542                 if (ret != 0)
543                         return ret;
544         } while (!(val & ADSP2_RAM_RDY) && ++count < 10);
545
546         if (!(val & ADSP2_RAM_RDY)) {
547                 adsp_err(dsp, "Failed to start DSP RAM\n");
548                 return -EBUSY;
549         }
550
551         adsp_dbg(dsp, "RAM ready after %d polls\n", count);
552         adsp_info(dsp, "RAM ready after %d polls\n", count);
553
554         return 0;
555 }
556
557 int wm_adsp2_event(struct snd_soc_dapm_widget *w,
558                    struct snd_kcontrol *kcontrol, int event)
559 {
560         struct snd_soc_codec *codec = w->codec;
561         struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
562         struct wm_adsp *dsp = &dsps[w->shift];
563         unsigned int val;
564         int ret;
565
566         switch (event) {
567         case SND_SOC_DAPM_POST_PMU:
568                 /*
569                  * For simplicity set the DSP clock rate to be the
570                  * SYSCLK rate rather than making it configurable.
571                  */
572                 ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val);
573                 if (ret != 0) {
574                         adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
575                                  ret);
576                         return ret;
577                 }
578                 val = (val & ARIZONA_SYSCLK_FREQ_MASK)
579                         >> ARIZONA_SYSCLK_FREQ_SHIFT;
580
581                 ret = regmap_update_bits(dsp->regmap,
582                                          dsp->base + ADSP2_CLOCKING,
583                                          ADSP2_CLK_SEL_MASK, val);
584                 if (ret != 0) {
585                         adsp_err(dsp, "Failed to set clock rate: %d\n",
586                                  ret);
587                         return ret;
588                 }
589
590                 if (dsp->dvfs) {
591                         ret = regmap_read(dsp->regmap,
592                                           dsp->base + ADSP2_CLOCKING, &val);
593                         if (ret != 0) {
594                                 dev_err(dsp->dev,
595                                         "Failed to read clocking: %d\n", ret);
596                                 return ret;
597                         }
598
599                         if ((val & ADSP2_CLK_SEL_MASK) >= 3) {
600                                 ret = regulator_enable(dsp->dvfs);
601                                 if (ret != 0) {
602                                         dev_err(dsp->dev,
603                                                 "Failed to enable supply: %d\n",
604                                                 ret);
605                                         return ret;
606                                 }
607
608                                 ret = regulator_set_voltage(dsp->dvfs,
609                                                             1800000,
610                                                             1800000);
611                                 if (ret != 0) {
612                                         dev_err(dsp->dev,
613                                                 "Failed to raise supply: %d\n",
614                                                 ret);
615                                         return ret;
616                                 }
617                         }
618                 }
619
620                 ret = wm_adsp2_ena(dsp);
621                 if (ret != 0)
622                         return ret;
623
624                 ret = wm_adsp_load(dsp);
625                 if (ret != 0)
626                         goto err;
627
628                 ret = wm_adsp_load_coeff(dsp);
629                 if (ret != 0)
630                         goto err;
631
632                 ret = regmap_update_bits(dsp->regmap,
633                                          dsp->base + ADSP2_CONTROL,
634                                          ADSP2_CORE_ENA | ADSP2_START,
635                                          ADSP2_CORE_ENA | ADSP2_START);
636                 if (ret != 0)
637                         goto err;
638                 break;
639
640         case SND_SOC_DAPM_PRE_PMD:
641                 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
642                                    ADSP2_SYS_ENA | ADSP2_CORE_ENA |
643                                    ADSP2_START, 0);
644
645                 if (dsp->dvfs) {
646                         ret = regulator_set_voltage(dsp->dvfs, 1200000,
647                                                     1800000);
648                         if (ret != 0)
649                                 dev_warn(dsp->dev,
650                                          "Failed to lower supply: %d\n",
651                                          ret);
652
653                         ret = regulator_disable(dsp->dvfs);
654                         if (ret != 0)
655                                 dev_err(dsp->dev,
656                                         "Failed to enable supply: %d\n",
657                                         ret);
658                 }
659                 break;
660
661         default:
662                 break;
663         }
664
665         return 0;
666 err:
667         regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
668                            ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
669         return ret;
670 }
671 EXPORT_SYMBOL_GPL(wm_adsp2_event);
672
673 int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
674 {
675         int ret;
676
677         /*
678          * Disable the DSP memory by default when in reset for a small
679          * power saving.
680          */
681         ret = regmap_update_bits(adsp->regmap, adsp->base + ADSP2_CONTROL,
682                                  ADSP2_MEM_ENA, 0);
683         if (ret != 0) {
684                 adsp_err(adsp, "Failed to clear memory retention: %d\n", ret);
685                 return ret;
686         }
687
688         if (dvfs) {
689                 adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
690                 if (IS_ERR(adsp->dvfs)) {
691                         ret = PTR_ERR(adsp->dvfs);
692                         dev_err(adsp->dev, "Failed to get DCVDD: %d\n", ret);
693                         return ret;
694                 }
695
696                 ret = regulator_enable(adsp->dvfs);
697                 if (ret != 0) {
698                         dev_err(adsp->dev, "Failed to enable DCVDD: %d\n",
699                                 ret);
700                         return ret;
701                 }
702
703                 ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000);
704                 if (ret != 0) {
705                         dev_err(adsp->dev, "Failed to initialise DVFS: %d\n",
706                                 ret);
707                         return ret;
708                 }
709
710                 ret = regulator_disable(adsp->dvfs);
711                 if (ret != 0) {
712                         dev_err(adsp->dev, "Failed to disable DCVDD: %d\n",
713                                 ret);
714                         return ret;
715                 }
716         }
717
718         return 0;
719 }
720 EXPORT_SYMBOL_GPL(wm_adsp2_init);