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); 721