linux/sound/soc/codecs/wm_adsp.c
<<
>>
Prefs
   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
 158struct wm_adsp_buf {
 159        struct list_head list;
 160        void *buf;
 161};
 162
 163static 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
 183static 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
 202static 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
 209static 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
 218static 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
 230static 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
 251static 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
 258const 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};
 266EXPORT_SYMBOL_GPL(wm_adsp1_fw_controls);
 267
 268#if IS_ENABLED(CONFIG_SND_SOC_ARIZONA)
 269static 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
 288const 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};
 302EXPORT_SYMBOL_GPL(wm_adsp2_fw_controls);
 303#endif
 304
 305static 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
 317static 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
 337static 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
 540out_fw:
 541        regmap_async_complete(regmap);
 542        wm_adsp_buf_free(&buf_list);
 543        release_firmware(firmware);
 544out:
 545        kfree(file);
 546
 547        return ret;
 548}
 549
 550static 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
 782out:
 783        kfree(alg);
 784        return ret;
 785}
 786
 787static 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
 966out_fw:
 967        release_firmware(firmware);
 968        wm_adsp_buf_free(&buf_list);
 969out:
 970        kfree(file);
 971        return ret;
 972}
 973
 974int wm_adsp1_init(struct wm_adsp *adsp)
 975{
 976        INIT_LIST_HEAD(&adsp->alg_regions);
 977
 978        return 0;
 979}
 980EXPORT_SYMBOL_GPL(wm_adsp1_init);
 981
 982int wm_adsp1_event(struct snd_soc_dapm_widget *w,
 983                   struct snd_kcontrol *kcontrol,
 984                   int event)
 985{
 986        struct snd_soc_codec *codec = w->codec;
 987        struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
 988        struct wm_adsp *dsp = &dsps[w->shift];
 989        int ret;
 990        int val;
 991
 992        switch (event) {
 993        case SND_SOC_DAPM_POST_PMU:
 994                regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
 995                                   ADSP1_SYS_ENA, ADSP1_SYS_ENA);
 996
 997                /*
 998                 * For simplicity set the DSP clock rate to be the
 999                 * SYSCLK rate rather than making it configurable.
1000                 */
1001                if(dsp->sysclk_reg) {
1002                        ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
1003                        if (ret != 0) {
1004                                adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
1005                                ret);
1006                                return ret;
1007                        }
1008
1009                        val = (val & dsp->sysclk_mask)
1010                                >> dsp->sysclk_shift;
1011
1012                        ret = regmap_update_bits(dsp->regmap,
1013                                                 dsp->base + ADSP1_CONTROL_31,
1014                                                 ADSP1_CLK_SEL_MASK, val);
1015                        if (ret != 0) {
1016                                adsp_err(dsp, "Failed to set clock rate: %d\n",
1017                                         ret);
1018                                return ret;
1019                        }
1020                }
1021
1022                ret = wm_adsp_load(dsp);
1023                if (ret != 0)
1024                        goto err;
1025
1026                ret = wm_adsp_setup_algs(dsp);
1027                if (ret != 0)
1028                        goto err;
1029
1030                ret = wm_adsp_load_coeff(dsp);
1031                if (ret != 0)
1032                        goto err;
1033
1034                /* Start the core running */
1035                regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1036                                   ADSP1_CORE_ENA | ADSP1_START,
1037                                   ADSP1_CORE_ENA | ADSP1_START);
1038                break;
1039
1040        case SND_SOC_DAPM_PRE_PMD:
1041                /* Halt the core */
1042                regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1043                                   ADSP1_CORE_ENA | ADSP1_START, 0);
1044
1045                regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19,
1046                                   ADSP1_WDMA_BUFFER_LENGTH_MASK, 0);
1047
1048                regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1049                                   ADSP1_SYS_ENA, 0);
1050                break;
1051
1052        default:
1053                break;
1054        }
1055
1056        return 0;
1057
1058err:
1059        regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1060                           ADSP1_SYS_ENA, 0);
1061        return ret;
1062}
1063EXPORT_SYMBOL_GPL(wm_adsp1_event);
1064
1065static int wm_adsp2_ena(struct wm_adsp *dsp)
1066{
1067        unsigned int val;
1068        int ret, count;
1069
1070        ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
1071                                 ADSP2_SYS_ENA, ADSP2_SYS_ENA);
1072        if (ret != 0)
1073                return ret;
1074
1075        /* Wait for the RAM to start, should be near instantaneous */
1076        count = 0;
1077        do {
1078                ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1,
1079                                  &val);
1080                if (ret != 0)
1081                        return ret;
1082        } while (!(val & ADSP2_RAM_RDY) && ++count < 10);
1083
1084        if (!(val & ADSP2_RAM_RDY)) {
1085                adsp_err(dsp, "Failed to start DSP RAM\n");
1086                return -EBUSY;
1087        }
1088
1089        adsp_dbg(dsp, "RAM ready after %d polls\n", count);
1090        adsp_info(dsp, "RAM ready after %d polls\n", count);
1091
1092        return 0;
1093}
1094
1095int wm_adsp2_event(struct snd_soc_dapm_widget *w,
1096                   struct snd_kcontrol *kcontrol, int event)
1097{
1098        struct snd_soc_codec *codec = w->codec;
1099        struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
1100        struct wm_adsp *dsp = &dsps[w->shift];
1101        struct wm_adsp_alg_region *alg_region;
1102        unsigned int val;
1103        int ret;
1104
1105        switch (event) {
1106        case SND_SOC_DAPM_POST_PMU:
1107                /*
1108                 * For simplicity set the DSP clock rate to be the
1109                 * SYSCLK rate rather than making it configurable.
1110                 */
1111                ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val);
1112                if (ret != 0) {
1113                        adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
1114                                 ret);
1115                        return ret;
1116                }
1117                val = (val & ARIZONA_SYSCLK_FREQ_MASK)
1118                        >> ARIZONA_SYSCLK_FREQ_SHIFT;
1119
1120                ret = regmap_update_bits(dsp->regmap,
1121                                         dsp->base + ADSP2_CLOCKING,
1122                                         ADSP2_CLK_SEL_MASK, val);
1123                if (ret != 0) {
1124                        adsp_err(dsp, "Failed to set clock rate: %d\n",
1125                                 ret);
1126                        return ret;
1127                }
1128
1129                if (dsp->dvfs) {
1130                        ret = regmap_read(dsp->regmap,
1131                                          dsp->base + ADSP2_CLOCKING, &val);
1132                        if (ret != 0) {
1133                                dev_err(dsp->dev,
1134                                        "Failed to read clocking: %d\n", ret);
1135                                return ret;
1136                        }
1137
1138                        if ((val & ADSP2_CLK_SEL_MASK) >= 3) {
1139                                ret = regulator_enable(dsp->dvfs);
1140                                if (ret != 0) {
1141                                        dev_err(dsp->dev,
1142                                                "Failed to enable supply: %d\n",
1143                                                ret);
1144                                        return ret;
1145                                }
1146
1147                                ret = regulator_set_voltage(dsp->dvfs,
1148                                                            1800000,
1149                                                            1800000);
1150                                if (ret != 0) {
1151                                        dev_err(dsp->dev,
1152                                                "Failed to raise supply: %d\n",
1153                                                ret);
1154                                        return ret;
1155                                }
1156                        }
1157                }
1158
1159                ret = wm_adsp2_ena(dsp);
1160                if (ret != 0)
1161                        return ret;
1162
1163                ret = wm_adsp_load(dsp);
1164                if (ret != 0)
1165                        goto err;
1166
1167                ret = wm_adsp_setup_algs(dsp);
1168                if (ret != 0)
1169                        goto err;
1170
1171                ret = wm_adsp_load_coeff(dsp);
1172                if (ret != 0)
1173                        goto err;
1174
1175                ret = regmap_update_bits(dsp->regmap,
1176                                         dsp->base + ADSP2_CONTROL,
1177                                         ADSP2_CORE_ENA | ADSP2_START,
1178                                         ADSP2_CORE_ENA | ADSP2_START);
1179                if (ret != 0)
1180                        goto err;
1181
1182                dsp->running = true;
1183                break;
1184
1185        case SND_SOC_DAPM_PRE_PMD:
1186                dsp->running = false;
1187
1188                regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
1189                                   ADSP2_SYS_ENA | ADSP2_CORE_ENA |
1190                                   ADSP2_START, 0);
1191
1192                /* Make sure DMAs are quiesced */
1193                regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
1194                regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
1195                regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
1196
1197                if (dsp->dvfs) {
1198                        ret = regulator_set_voltage(dsp->dvfs, 1200000,
1199                                                    1800000);
1200                        if (ret != 0)
1201                                dev_warn(dsp->dev,
1202                                         "Failed to lower supply: %d\n",
1203                                         ret);
1204
1205                        ret = regulator_disable(dsp->dvfs);
1206                        if (ret != 0)
1207                                dev_err(dsp->dev,
1208                                        "Failed to enable supply: %d\n",
1209                                        ret);
1210                }
1211
1212                while (!list_empty(&dsp->alg_regions)) {
1213                        alg_region = list_first_entry(&dsp->alg_regions,
1214                                                      struct wm_adsp_alg_region,
1215                                                      list);
1216                        list_del(&alg_region->list);
1217                        kfree(alg_region);
1218                }
1219                break;
1220
1221        default:
1222                break;
1223        }
1224
1225        return 0;
1226err:
1227        regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
1228                           ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
1229        return ret;
1230}
1231EXPORT_SYMBOL_GPL(wm_adsp2_event);
1232
1233int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
1234{
1235        int ret;
1236
1237        /*
1238         * Disable the DSP memory by default when in reset for a small
1239         * power saving.
1240         */
1241        ret = regmap_update_bits(adsp->regmap, adsp->base + ADSP2_CONTROL,
1242                                 ADSP2_MEM_ENA, 0);
1243        if (ret != 0) {
1244                adsp_err(adsp, "Failed to clear memory retention: %d\n", ret);
1245                return ret;
1246        }
1247
1248        INIT_LIST_HEAD(&adsp->alg_regions);
1249
1250        if (dvfs) {
1251                adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
1252                if (IS_ERR(adsp->dvfs)) {
1253                        ret = PTR_ERR(adsp->dvfs);
1254                        dev_err(adsp->dev, "Failed to get DCVDD: %d\n", ret);
1255                        return ret;
1256                }
1257
1258                ret = regulator_enable(adsp->dvfs);
1259                if (ret != 0) {
1260                        dev_err(adsp->dev, "Failed to enable DCVDD: %d\n",
1261                                ret);
1262                        return ret;
1263                }
1264
1265                ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000);
1266                if (ret != 0) {
1267                        dev_err(adsp->dev, "Failed to initialise DVFS: %d\n",
1268                                ret);
1269                        return ret;
1270                }
1271
1272                ret = regulator_disable(adsp->dvfs);
1273                if (ret != 0) {
1274                        dev_err(adsp->dev, "Failed to disable DCVDD: %d\n",
1275                                ret);
1276                        return ret;
1277                }
1278        }
1279
1280        return 0;
1281}
1282EXPORT_SYMBOL_GPL(wm_adsp2_init);
1283