* [PATCH 1/4] ASoC: adsp: Add ADSP base support
@ 2012-10-26 18:36 Mark Brown
2012-10-26 18:36 ` [PATCH 2/4] ASoC: wm2200: Convert over to wm_adsp for ADSP1 support Mark Brown
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Mark Brown @ 2012-10-26 18:36 UTC (permalink / raw)
To: Liam Girdwood; +Cc: alsa-devel, patches, Mark Brown
Many current Wolfson devices feature DSPs based around an architecture
known as ADSP. Since there is a lot of commonality in the system
integration of these devices a common library will be used to provide
support for them.
This version provides equivalent support for ADSP1 to that currently
included in the WM2200 driver.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
sound/soc/codecs/Kconfig | 5 +
sound/soc/codecs/Makefile | 1 +
sound/soc/codecs/wm_adsp.c | 571 ++++++++++++++++++++++++++++++++++++++++++++
sound/soc/codecs/wm_adsp.h | 54 +++++
sound/soc/codecs/wmfw.h | 29 +++
5 files changed, 660 insertions(+)
create mode 100644 sound/soc/codecs/wm_adsp.c
create mode 100644 sound/soc/codecs/wm_adsp.h
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 6f4f284..91cbbe0 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -147,6 +147,11 @@ config SND_SOC_WM_HUBS
default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y
default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m
+config SND_SOC_WM_ADSP
+ tristate
+ default y if SND_SOC_WM2200=y
+ default m if SND_SOC_WM2200=m
+
config SND_SOC_AB8500_CODEC
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index c55d2d7..ffbed85 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -63,6 +63,7 @@ snd-soc-twl6040-objs := twl6040.o
snd-soc-uda134x-objs := uda134x.o
snd-soc-uda1380-objs := uda1380.o
snd-soc-wl1273-objs := wl1273.o
+snd-soc-wm-adsp := wm_adsp.o
snd-soc-wm0010-objs := wm0010.o
snd-soc-wm1250-ev1-objs := wm1250-ev1.o
snd-soc-wm2000-objs := wm2000.o
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
new file mode 100644
index 0000000..c72d3fa
--- /dev/null
+++ b/sound/soc/codecs/wm_adsp.c
@@ -0,0 +1,571 @@
+/*
+ * wm_adsp.c -- Wolfson ADSP support
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <linux/mfd/arizona/registers.h>
+
+#include "wm_adsp.h"
+
+#define adsp_crit(_dsp, fmt, ...) \
+ dev_crit(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
+#define adsp_err(_dsp, fmt, ...) \
+ dev_err(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
+#define adsp_warn(_dsp, fmt, ...) \
+ dev_warn(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
+#define adsp_info(_dsp, fmt, ...) \
+ dev_info(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
+#define adsp_dbg(_dsp, fmt, ...) \
+ dev_dbg(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
+
+#define ADSP1_CONTROL_1 0x00
+#define ADSP1_CONTROL_2 0x02
+#define ADSP1_CONTROL_3 0x03
+#define ADSP1_CONTROL_4 0x04
+#define ADSP1_CONTROL_5 0x06
+#define ADSP1_CONTROL_6 0x07
+#define ADSP1_CONTROL_7 0x08
+#define ADSP1_CONTROL_8 0x09
+#define ADSP1_CONTROL_9 0x0A
+#define ADSP1_CONTROL_10 0x0B
+#define ADSP1_CONTROL_11 0x0C
+#define ADSP1_CONTROL_12 0x0D
+#define ADSP1_CONTROL_13 0x0F
+#define ADSP1_CONTROL_14 0x10
+#define ADSP1_CONTROL_15 0x11
+#define ADSP1_CONTROL_16 0x12
+#define ADSP1_CONTROL_17 0x13
+#define ADSP1_CONTROL_18 0x14
+#define ADSP1_CONTROL_19 0x16
+#define ADSP1_CONTROL_20 0x17
+#define ADSP1_CONTROL_21 0x18
+#define ADSP1_CONTROL_22 0x1A
+#define ADSP1_CONTROL_23 0x1B
+#define ADSP1_CONTROL_24 0x1C
+#define ADSP1_CONTROL_25 0x1E
+#define ADSP1_CONTROL_26 0x20
+#define ADSP1_CONTROL_27 0x21
+#define ADSP1_CONTROL_28 0x22
+#define ADSP1_CONTROL_29 0x23
+#define ADSP1_CONTROL_30 0x24
+#define ADSP1_CONTROL_31 0x26
+
+/*
+ * ADSP1 Control 19
+ */
+#define ADSP1_WDMA_BUFFER_LENGTH_MASK 0x00FF /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
+#define ADSP1_WDMA_BUFFER_LENGTH_SHIFT 0 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
+#define ADSP1_WDMA_BUFFER_LENGTH_WIDTH 8 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
+
+
+/*
+ * ADSP1 Control 30
+ */
+#define ADSP1_DBG_CLK_ENA 0x0008 /* DSP1_DBG_CLK_ENA */
+#define ADSP1_DBG_CLK_ENA_MASK 0x0008 /* DSP1_DBG_CLK_ENA */
+#define ADSP1_DBG_CLK_ENA_SHIFT 3 /* DSP1_DBG_CLK_ENA */
+#define ADSP1_DBG_CLK_ENA_WIDTH 1 /* DSP1_DBG_CLK_ENA */
+#define ADSP1_SYS_ENA 0x0004 /* DSP1_SYS_ENA */
+#define ADSP1_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */
+#define ADSP1_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */
+#define ADSP1_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */
+#define ADSP1_CORE_ENA 0x0002 /* DSP1_CORE_ENA */
+#define ADSP1_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */
+#define ADSP1_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */
+#define ADSP1_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */
+#define ADSP1_START 0x0001 /* DSP1_START */
+#define ADSP1_START_MASK 0x0001 /* DSP1_START */
+#define ADSP1_START_SHIFT 0 /* DSP1_START */
+#define ADSP1_START_WIDTH 1 /* DSP1_START */
+
+#define ADSP2_CONTROL 0
+#define ADSP2_STATUS1 4
+
+/*
+ * ADSP2 Control
+ */
+
+#define ADSP2_MEM_ENA 0x0010 /* DSP1_MEM_ENA */
+#define ADSP2_MEM_ENA_MASK 0x0010 /* DSP1_MEM_ENA */
+#define ADSP2_MEM_ENA_SHIFT 4 /* DSP1_MEM_ENA */
+#define ADSP2_MEM_ENA_WIDTH 1 /* DSP1_MEM_ENA */
+#define ADSP2_SYS_ENA 0x0004 /* DSP1_SYS_ENA */
+#define ADSP2_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */
+#define ADSP2_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */
+#define ADSP2_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */
+#define ADSP2_CORE_ENA 0x0002 /* DSP1_CORE_ENA */
+#define ADSP2_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */
+#define ADSP2_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */
+#define ADSP2_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */
+#define ADSP2_START 0x0001 /* DSP1_START */
+#define ADSP2_START_MASK 0x0001 /* DSP1_START */
+#define ADSP2_START_SHIFT 0 /* DSP1_START */
+#define ADSP2_START_WIDTH 1 /* DSP1_START */
+
+/*
+ * ADSP2 Status 1
+ */
+#define ADSP2_RAM_RDY 0x0001
+#define ADSP2_RAM_RDY_MASK 0x0001
+#define ADSP2_RAM_RDY_SHIFT 0
+#define ADSP2_RAM_RDY_WIDTH 1
+
+
+static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
+ int type)
+{
+ int i;
+
+ for (i = 0; i < dsp->num_mems; i++)
+ if (dsp->mem[i].type == type)
+ return &dsp->mem[i];
+
+ return NULL;
+}
+
+static int wm_adsp_load(struct wm_adsp *dsp)
+{
+ const struct firmware *firmware;
+ struct regmap *regmap = dsp->regmap;
+ unsigned int pos = 0;
+ const struct wmfw_header *header;
+ const struct wmfw_adsp1_sizes *adsp1_sizes;
+ const struct wmfw_adsp2_sizes *adsp2_sizes;
+ const struct wmfw_footer *footer;
+ const struct wmfw_region *region;
+ const struct wm_adsp_region *mem;
+ const char *region_name;
+ char *file, *text;
+ unsigned int reg;
+ int regions = 0;
+ int ret, offset, type, sizes;
+
+ file = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (file == NULL)
+ return -ENOMEM;
+
+ snprintf(file, PAGE_SIZE, "%s-dsp%d.wmfw", dsp->part, dsp->num);
+ file[PAGE_SIZE - 1] = '\0';
+
+ ret = request_firmware(&firmware, file, dsp->dev);
+ if (ret != 0) {
+ adsp_err(dsp, "Failed to request '%s'\n", file);
+ goto out;
+ }
+ ret = -EINVAL;
+
+ pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
+ if (pos >= firmware->size) {
+ adsp_err(dsp, "%s: file too short, %zu bytes\n",
+ file, firmware->size);
+ goto out_fw;
+ }
+
+ header = (void*)&firmware->data[0];
+
+ if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
+ adsp_err(dsp, "%s: invalid magic\n", file);
+ goto out_fw;
+ }
+
+ if (header->ver != 0) {
+ adsp_err(dsp, "%s: unknown file format %d\n",
+ file, header->ver);
+ goto out_fw;
+ }
+
+ if (header->core != dsp->type) {
+ adsp_err(dsp, "%s: invalid core %d != %d\n",
+ file, header->core, dsp->type);
+ goto out_fw;
+ }
+
+ switch (dsp->type) {
+ case WMFW_ADSP1:
+ pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
+ adsp1_sizes = (void *)&(header[1]);
+ footer = (void *)&(adsp1_sizes[1]);
+ sizes = sizeof(*adsp1_sizes);
+
+ adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n",
+ file, le32_to_cpu(adsp1_sizes->dm),
+ le32_to_cpu(adsp1_sizes->pm),
+ le32_to_cpu(adsp1_sizes->zm));
+ break;
+
+ case WMFW_ADSP2:
+ pos = sizeof(*header) + sizeof(*adsp2_sizes) + sizeof(*footer);
+ adsp2_sizes = (void *)&(header[1]);
+ footer = (void *)&(adsp2_sizes[1]);
+ sizes = sizeof(*adsp2_sizes);
+
+ adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n",
+ file, le32_to_cpu(adsp2_sizes->xm),
+ le32_to_cpu(adsp2_sizes->ym),
+ le32_to_cpu(adsp2_sizes->pm),
+ le32_to_cpu(adsp2_sizes->zm));
+ break;
+
+ default:
+ BUG_ON(NULL == "Unknown DSP type");
+ goto out_fw;
+ }
+
+ if (le32_to_cpu(header->len) != sizeof(*header) +
+ sizes + sizeof(*footer)) {
+ adsp_err(dsp, "%s: unexpected header length %d\n",
+ file, le32_to_cpu(header->len));
+ goto out_fw;
+ }
+
+ adsp_dbg(dsp, "%s: timestamp %llu\n", file,
+ le64_to_cpu(footer->timestamp));
+
+ while (pos < firmware->size &&
+ pos - firmware->size > sizeof(*region)) {
+ region = (void *)&(firmware->data[pos]);
+ region_name = "Unknown";
+ reg = 0;
+ text = NULL;
+ offset = le32_to_cpu(region->offset) & 0xffffff;
+ type = be32_to_cpu(region->type) & 0xff;
+ mem = wm_adsp_find_region(dsp, type);
+
+ switch (type) {
+ case WMFW_NAME_TEXT:
+ region_name = "Firmware name";
+ text = kzalloc(le32_to_cpu(region->len) + 1,
+ GFP_KERNEL);
+ break;
+ case WMFW_INFO_TEXT:
+ region_name = "Information";
+ text = kzalloc(le32_to_cpu(region->len) + 1,
+ GFP_KERNEL);
+ break;
+ case WMFW_ABSOLUTE:
+ region_name = "Absolute";
+ reg = offset;
+ break;
+ case WMFW_ADSP1_PM:
+ BUG_ON(!mem);
+ region_name = "PM";
+ reg = mem->base + (offset * 3);
+ break;
+ case WMFW_ADSP1_DM:
+ BUG_ON(!mem);
+ region_name = "DM";
+ reg = mem->base + (offset * 2);
+ break;
+ case WMFW_ADSP2_XM:
+ BUG_ON(!mem);
+ region_name = "XM";
+ reg = mem->base + (offset * 2);
+ break;
+ case WMFW_ADSP2_YM:
+ BUG_ON(!mem);
+ region_name = "YM";
+ reg = mem->base + (offset * 2);
+ break;
+ case WMFW_ADSP1_ZM:
+ BUG_ON(!mem);
+ region_name = "ZM";
+ reg = mem->base + (offset * 2);
+ break;
+ default:
+ adsp_warn(dsp,
+ "%s.%d: Unknown region type %x at %d(%x)\n",
+ file, regions, type, pos, pos);
+ break;
+ }
+
+ adsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file,
+ regions, le32_to_cpu(region->len), offset,
+ region_name);
+
+ if (text) {
+ memcpy(text, region->data, le32_to_cpu(region->len));
+ adsp_info(dsp, "%s: %s\n", file, text);
+ kfree(text);
+ }
+
+ if (reg) {
+ ret = regmap_raw_write(regmap, reg, region->data,
+ le32_to_cpu(region->len));
+ if (ret != 0) {
+ adsp_err(dsp,
+ "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
+ file, regions,
+ le32_to_cpu(region->len), offset,
+ region_name, ret);
+ goto out_fw;
+ }
+ }
+
+ pos += le32_to_cpu(region->len) + sizeof(*region);
+ regions++;
+ }
+
+ if (pos > firmware->size)
+ adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
+ file, regions, pos - firmware->size);
+
+out_fw:
+ release_firmware(firmware);
+out:
+ kfree(file);
+
+ return ret;
+}
+
+static int wm_adsp_load_coeff(struct wm_adsp *dsp)
+{
+ struct regmap *regmap = dsp->regmap;
+ struct wmfw_coeff_hdr *hdr;
+ struct wmfw_coeff_item *blk;
+ const struct firmware *firmware;
+ const char *region_name;
+ int ret, pos, blocks, type, offset, reg;
+ char *file;
+
+ file = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (file == NULL)
+ return -ENOMEM;
+
+ snprintf(file, PAGE_SIZE, "%s-dsp%d.bin", dsp->part, dsp->num);
+ file[PAGE_SIZE - 1] = '\0';
+
+ ret = request_firmware(&firmware, file, dsp->dev);
+ if (ret != 0) {
+ adsp_warn(dsp, "Failed to request '%s'\n", file);
+ ret = 0;
+ goto out;
+ }
+ ret = -EINVAL;
+
+ if (sizeof(*hdr) >= firmware->size) {
+ adsp_err(dsp, "%s: file too short, %zu bytes\n",
+ file, firmware->size);
+ goto out_fw;
+ }
+
+ hdr = (void*)&firmware->data[0];
+ if (memcmp(hdr->magic, "WMDR", 4) != 0) {
+ adsp_err(dsp, "%s: invalid magic\n", file);
+ return -EINVAL;
+ }
+
+ adsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
+ (le32_to_cpu(hdr->ver) >> 16) & 0xff,
+ (le32_to_cpu(hdr->ver) >> 8) & 0xff,
+ le32_to_cpu(hdr->ver) & 0xff);
+
+ pos = le32_to_cpu(hdr->len);
+
+ blocks = 0;
+ while (pos < firmware->size &&
+ pos - firmware->size > sizeof(*blk)) {
+ blk = (void*)(&firmware->data[pos]);
+
+ type = be32_to_cpu(blk->type) & 0xff;
+ offset = le32_to_cpu(blk->offset) & 0xffffff;
+
+ adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n",
+ file, blocks, le32_to_cpu(blk->id),
+ (le32_to_cpu(blk->ver) >> 16) & 0xff,
+ (le32_to_cpu(blk->ver) >> 8) & 0xff,
+ le32_to_cpu(blk->ver) & 0xff);
+ adsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n",
+ file, blocks, le32_to_cpu(blk->len), offset, type);
+
+ reg = 0;
+ region_name = "Unknown";
+ switch (type) {
+ case WMFW_NAME_TEXT:
+ case WMFW_INFO_TEXT:
+ break;
+ case WMFW_ABSOLUTE:
+ region_name = "register";
+ reg = offset;
+ break;
+ default:
+ adsp_err(dsp, "Unknown region type %x\n", type);
+ break;
+ }
+
+ if (reg) {
+ ret = regmap_raw_write(regmap, reg, blk->data,
+ le32_to_cpu(blk->len));
+ if (ret != 0) {
+ adsp_err(dsp,
+ "%s.%d: Failed to write to %x in %s\n",
+ file, blocks, reg, region_name);
+ }
+ }
+
+ pos += le32_to_cpu(blk->len) + sizeof(*blk);
+ blocks++;
+ }
+
+ if (pos > firmware->size)
+ adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
+ file, blocks, pos - firmware->size);
+
+out_fw:
+ release_firmware(firmware);
+out:
+ kfree(file);
+ return 0;
+}
+
+int wm_adsp1_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
+ struct wm_adsp *dsp = &dsps[w->shift];
+ int ret;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
+ ADSP1_SYS_ENA, ADSP1_SYS_ENA);
+
+ ret = wm_adsp_load(dsp);
+ if (ret != 0)
+ goto err;
+
+ ret = wm_adsp_load_coeff(dsp);
+ if (ret != 0)
+ goto err;
+
+ /* Start the core running */
+ regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
+ ADSP1_CORE_ENA | ADSP1_START,
+ ADSP1_CORE_ENA | ADSP1_START);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ /* Halt the core */
+ regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
+ ADSP1_CORE_ENA | ADSP1_START, 0);
+
+ regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19,
+ ADSP1_WDMA_BUFFER_LENGTH_MASK, 0);
+
+ regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
+ ADSP1_SYS_ENA, 0);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+
+err:
+ regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
+ ADSP1_SYS_ENA, 0);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp1_event);
+
+static int wm_adsp2_ena(struct wm_adsp *dsp)
+{
+ unsigned int val;
+ int ret, count;
+
+ ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+ ADSP2_SYS_ENA, ADSP2_SYS_ENA);
+ if (ret != 0)
+ return ret;
+
+ /* Wait for the RAM to start, should be near instantaneous */
+ count = 0;
+ do {
+ ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1,
+ &val);
+ if (ret != 0)
+ return ret;
+ } while (!(val & ADSP2_RAM_RDY) && ++count < 10);
+
+ if (!(val & ADSP2_RAM_RDY)) {
+ adsp_err(dsp, "Failed to start DSP RAM\n");
+ return -EBUSY;
+ }
+
+ adsp_dbg(dsp, "RAM ready after %d polls\n", count);
+ adsp_info(dsp, "RAM ready after %d polls\n", count);
+
+ return 0;
+}
+
+int wm_adsp2_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
+ struct wm_adsp *dsp = &dsps[w->shift];
+ int ret;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ ret = wm_adsp2_ena(dsp);
+ if (ret != 0)
+ return ret;
+
+ ret = wm_adsp_load(dsp);
+ if (ret != 0)
+ goto err;
+
+ ret = wm_adsp_load_coeff(dsp);
+ if (ret != 0)
+ goto err;
+
+ ret = regmap_update_bits(dsp->regmap,
+ dsp->base + ADSP2_CONTROL,
+ ADSP2_SYS_ENA | ADSP2_START, 0);
+ if (ret != 0)
+ goto err;
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+ ADSP2_SYS_ENA | ADSP2_START, 0);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+err:
+ regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+ ADSP2_SYS_ENA | ADSP2_START, 0);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp2_event);
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
new file mode 100644
index 0000000..b303b1f
--- /dev/null
+++ b/sound/soc/codecs/wm_adsp.h
@@ -0,0 +1,54 @@
+/*
+ * wm_adsp.h -- Wolfson ADSP support
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __WM_ADSP_H
+#define __WM_ADSP_H
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "wmfw.h"
+
+struct wm_adsp_region {
+ int type;
+ unsigned int base;
+};
+
+struct wm_adsp {
+ const char *part;
+ int num;
+ int type;
+ struct device *dev;
+ struct regmap *regmap;
+
+ int base;
+
+ const struct wm_adsp_region *mem;
+ int num_mems;
+};
+
+#define WM_ADSP1(wname, num) \
+ { .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
+ .shift = num, .event = wm_adsp1_event, \
+ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
+
+#define WM_ADSP2(wname, num) \
+{ .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
+ .shift = num, .event = wm_adsp2_event, \
+ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
+
+int wm_adsp1_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+int wm_adsp2_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+
+#endif
diff --git a/sound/soc/codecs/wmfw.h b/sound/soc/codecs/wmfw.h
index 5791f8e..5632ded 100644
--- a/sound/soc/codecs/wmfw.h
+++ b/sound/soc/codecs/wmfw.h
@@ -34,6 +34,13 @@ struct wmfw_adsp1_sizes {
__le32 zm;
} __packed;
+struct wmfw_adsp2_sizes {
+ __le32 xm;
+ __le32 ym;
+ __le32 pm;
+ __le32 zm;
+} __packed;
+
struct wmfw_region {
union {
__be32 type;
@@ -57,6 +64,14 @@ struct wmfw_adsp1_id_hdr {
__be32 algs;
} __packed;
+struct wmfw_adsp2_id_hdr {
+ struct wmfw_id_hdr fw;
+ __be32 zm;
+ __be32 xm;
+ __be32 ym;
+ __be32 algs;
+} __packed;
+
struct wmfw_alg_hdr {
__be32 id;
__be32 ver;
@@ -68,6 +83,13 @@ struct wmfw_adsp1_alg_hdr {
__be32 dm;
} __packed;
+struct wmfw_adsp2_alg_hdr {
+ struct wmfw_alg_hdr alg;
+ __be32 zm;
+ __be32 xm;
+ __be32 ym;
+} __packed;
+
struct wmfw_coeff_hdr {
u8 magic[4];
__le32 len;
@@ -86,7 +108,9 @@ struct wmfw_coeff_item {
__le32 len;
u8 data[];
} __packed;
+
#define WMFW_ADSP1 1
+#define WMFW_ADSP2 2
#define WMFW_ABSOLUTE 0xf0
#define WMFW_NAME_TEXT 0xfe
@@ -96,4 +120,9 @@ struct wmfw_coeff_item {
#define WMFW_ADSP1_DM 3
#define WMFW_ADSP1_ZM 4
+#define WMFW_ADSP2_PM 2
+#define WMFW_ADSP2_ZM 4
+#define WMFW_ADSP2_XM 5
+#define WMFW_ADSP2_YM 6
+
#endif
--
1.7.10.4
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/4] ASoC: wm2200: Convert over to wm_adsp for ADSP1 support
2012-10-26 18:36 [PATCH 1/4] ASoC: adsp: Add ADSP base support Mark Brown
@ 2012-10-26 18:36 ` Mark Brown
2012-10-26 18:36 ` [PATCH 3/4] ASoC: arizona: Define standard hookup for ADSP2 Mark Brown
2012-10-26 18:36 ` [PATCH 4/4] ASoC: wm5102: Hook up DSP1 Mark Brown
2 siblings, 0 replies; 4+ messages in thread
From: Mark Brown @ 2012-10-26 18:36 UTC (permalink / raw)
To: Liam Girdwood; +Cc: alsa-devel, patches, Mark Brown
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
sound/soc/codecs/wm2200.c | 432 ++++-----------------------------------------
1 file changed, 32 insertions(+), 400 deletions(-)
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index 2148ee3..1730df8 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -34,6 +34,7 @@
#include "wm2200.h"
#include "wmfw.h"
+#include "wm_adsp.h"
#define WM2200_DSP_CONTROL_1 0x00
#define WM2200_DSP_CONTROL_2 0x02
@@ -83,6 +84,7 @@ struct wm2200_fll {
/* codec private data */
struct wm2200_priv {
+ struct wm_adsp dsp[2];
struct regmap *regmap;
struct device *dev;
struct snd_soc_codec *codec;
@@ -152,6 +154,18 @@ static const struct regmap_range_cfg wm2200_ranges[] = {
.window_start = WM2200_DSP2_ZM_0, .window_len = 1024, },
};
+static const struct wm_adsp_region wm2200_dsp1_regions[] = {
+ { .type = WMFW_ADSP1_PM, .base = WM2200_DSP1_PM_BASE },
+ { .type = WMFW_ADSP1_DM, .base = WM2200_DSP1_DM_BASE },
+ { .type = WMFW_ADSP1_ZM, .base = WM2200_DSP1_ZM_BASE },
+};
+
+static const struct wm_adsp_region wm2200_dsp2_regions[] = {
+ { .type = WMFW_ADSP1_PM, .base = WM2200_DSP2_PM_BASE },
+ { .type = WMFW_ADSP1_DM, .base = WM2200_DSP2_DM_BASE },
+ { .type = WMFW_ADSP1_ZM, .base = WM2200_DSP2_ZM_BASE },
+};
+
static struct reg_default wm2200_reg_defaults[] = {
{ 0x000B, 0x0000 }, /* R11 - Tone Generator 1 */
{ 0x0102, 0x0000 }, /* R258 - Clocking 3 */
@@ -981,400 +995,6 @@ static int wm2200_reset(struct wm2200_priv *wm2200)
}
}
-static int wm2200_dsp_load(struct snd_soc_codec *codec, int base)
-{
- const struct firmware *firmware;
- struct regmap *regmap = codec->control_data;
- unsigned int pos = 0;
- const struct wmfw_header *header;
- const struct wmfw_adsp1_sizes *adsp1_sizes;
- const struct wmfw_footer *footer;
- const struct wmfw_region *region;
- const char *file, *region_name;
- char *text;
- unsigned int dm, pm, zm, reg;
- int regions = 0;
- int ret, offset, type;
-
- switch (base) {
- case WM2200_DSP1_CONTROL_1:
- file = "wm2200-dsp1.wmfw";
- dm = WM2200_DSP1_DM_BASE;
- pm = WM2200_DSP1_PM_BASE;
- zm = WM2200_DSP1_ZM_BASE;
- break;
- case WM2200_DSP2_CONTROL_1:
- file = "wm2200-dsp2.wmfw";
- dm = WM2200_DSP2_DM_BASE;
- pm = WM2200_DSP2_PM_BASE;
- zm = WM2200_DSP2_ZM_BASE;
- break;
- default:
- dev_err(codec->dev, "BASE %x\n", base);
- BUG_ON(1);
- return -EINVAL;
- }
-
- ret = request_firmware(&firmware, file, codec->dev);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to request '%s'\n", file);
- return ret;
- }
-
- pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
- if (pos >= firmware->size) {
- dev_err(codec->dev, "%s: file too short, %zu bytes\n",
- file, firmware->size);
- return -EINVAL;
- }
-
- header = (void*)&firmware->data[0];
-
- if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
- dev_err(codec->dev, "%s: invalid magic\n", file);
- return -EINVAL;
- }
-
- if (header->ver != 0) {
- dev_err(codec->dev, "%s: unknown file format %d\n",
- file, header->ver);
- return -EINVAL;
- }
-
- if (le32_to_cpu(header->len) != sizeof(*header) +
- sizeof(*adsp1_sizes) + sizeof(*footer)) {
- dev_err(codec->dev, "%s: unexpected header length %d\n",
- file, le32_to_cpu(header->len));
- return -EINVAL;
- }
-
- if (header->core != WMFW_ADSP1) {
- dev_err(codec->dev, "%s: invalid core %d\n",
- file, header->core);
- return -EINVAL;
- }
-
- adsp1_sizes = (void *)&(header[1]);
- footer = (void *)&(adsp1_sizes[1]);
-
- dev_dbg(codec->dev, "%s: %d DM, %d PM, %d ZM\n",
- file, le32_to_cpu(adsp1_sizes->dm),
- le32_to_cpu(adsp1_sizes->pm), le32_to_cpu(adsp1_sizes->zm));
-
- dev_dbg(codec->dev, "%s: timestamp %llu\n", file,
- le64_to_cpu(footer->timestamp));
-
- while (pos < firmware->size &&
- pos - firmware->size > sizeof(*region)) {
- region = (void *)&(firmware->data[pos]);
- region_name = "Unknown";
- reg = 0;
- text = NULL;
- offset = le32_to_cpu(region->offset) & 0xffffff;
- type = be32_to_cpu(region->type) & 0xff;
-
- switch (type) {
- case WMFW_NAME_TEXT:
- region_name = "Firmware name";
- text = kzalloc(le32_to_cpu(region->len) + 1,
- GFP_KERNEL);
- break;
- case WMFW_INFO_TEXT:
- region_name = "Information";
- text = kzalloc(le32_to_cpu(region->len) + 1,
- GFP_KERNEL);
- break;
- case WMFW_ABSOLUTE:
- region_name = "Absolute";
- reg = offset;
- break;
- case WMFW_ADSP1_PM:
- region_name = "PM";
- reg = pm + (offset * 3);
- break;
- case WMFW_ADSP1_DM:
- region_name = "DM";
- reg = dm + (offset * 2);
- break;
- case WMFW_ADSP1_ZM:
- region_name = "ZM";
- reg = zm + (offset * 2);
- break;
- default:
- dev_warn(codec->dev,
- "%s.%d: Unknown region type %x at %d(%x)\n",
- file, regions, type, pos, pos);
- break;
- }
-
- dev_dbg(codec->dev, "%s.%d: %d bytes at %d in %s\n", file,
- regions, le32_to_cpu(region->len), offset,
- region_name);
-
- if (text) {
- memcpy(text, region->data, le32_to_cpu(region->len));
- dev_info(codec->dev, "%s: %s\n", file, text);
- kfree(text);
- }
-
- if (reg) {
- ret = regmap_raw_write(regmap, reg, region->data,
- le32_to_cpu(region->len));
- if (ret != 0) {
- dev_err(codec->dev,
- "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
- file, regions,
- le32_to_cpu(region->len), offset,
- region_name, ret);
- goto out;
- }
- }
-
- pos += le32_to_cpu(region->len) + sizeof(*region);
- regions++;
- }
-
- if (pos > firmware->size)
- dev_warn(codec->dev, "%s.%d: %zu bytes at end of file\n",
- file, regions, pos - firmware->size);
-
-out:
- release_firmware(firmware);
-
- return ret;
-}
-
-static int wm2200_setup_algs(struct snd_soc_codec *codec, int base)
-{
- struct regmap *regmap = codec->control_data;
- struct wmfw_adsp1_id_hdr id;
- struct wmfw_adsp1_alg_hdr *alg;
- size_t algs;
- int zm, dm, pm, ret, i;
- __be32 val;
-
- switch (base) {
- case WM2200_DSP1_CONTROL_1:
- dm = WM2200_DSP1_DM_BASE;
- pm = WM2200_DSP1_PM_BASE;
- zm = WM2200_DSP1_ZM_BASE;
- break;
- case WM2200_DSP2_CONTROL_1:
- dm = WM2200_DSP2_DM_BASE;
- pm = WM2200_DSP2_PM_BASE;
- zm = WM2200_DSP2_ZM_BASE;
- break;
- default:
- dev_err(codec->dev, "BASE %x\n", base);
- BUG_ON(1);
- return -EINVAL;
- }
-
- ret = regmap_raw_read(regmap, dm, &id, sizeof(id));
- if (ret != 0) {
- dev_err(codec->dev, "Failed to read algorithm info: %d\n",
- ret);
- return ret;
- }
-
- algs = be32_to_cpu(id.algs);
- dev_info(codec->dev, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
- be32_to_cpu(id.fw.id),
- (be32_to_cpu(id.fw.ver) & 0xff000) >> 16,
- (be32_to_cpu(id.fw.ver) & 0xff00) >> 8,
- be32_to_cpu(id.fw.ver) & 0xff,
- algs);
-
- /* Read the terminator first to validate the length */
- ret = regmap_raw_read(regmap, dm +
- (sizeof(id) + (algs * sizeof(*alg))) / 2,
- &val, sizeof(val));
- if (ret != 0) {
- dev_err(codec->dev, "Failed to read algorithm list end: %d\n",
- ret);
- return ret;
- }
-
- if (be32_to_cpu(val) != 0xbedead)
- dev_warn(codec->dev, "Algorithm list end %zx 0x%x != 0xbeadead\n",
- (sizeof(id) + (algs * sizeof(*alg))) / 2,
- be32_to_cpu(val));
-
- alg = kzalloc(sizeof(*alg) * algs, GFP_KERNEL);
- if (!alg)
- return -ENOMEM;
-
- ret = regmap_raw_read(regmap, dm + (sizeof(id) / 2),
- alg, algs * sizeof(*alg));
- if (ret != 0) {
- dev_err(codec->dev, "Failed to read algorithm list: %d\n",
- ret);
- goto out;
- }
-
- for (i = 0; i < algs; i++) {
- dev_info(codec->dev, "%d: ID %x v%d.%d.%d\n",
- i, be32_to_cpu(alg[i].alg.id),
- (be32_to_cpu(alg[i].alg.ver) & 0xff000) >> 16,
- (be32_to_cpu(alg[i].alg.ver) & 0xff00) >> 8,
- be32_to_cpu(alg[i].alg.ver) & 0xff);
- }
-
-out:
- kfree(alg);
- return ret;
-}
-
-static int wm2200_load_coeff(struct snd_soc_codec *codec, int base)
-{
- struct regmap *regmap = codec->control_data;
- struct wmfw_coeff_hdr *hdr;
- struct wmfw_coeff_item *blk;
- const struct firmware *firmware;
- const char *file, *region_name;
- int ret, dm, pm, zm, pos, blocks, type, offset, reg;
-
- switch (base) {
- case WM2200_DSP1_CONTROL_1:
- file = "wm2200-dsp1.bin";
- dm = WM2200_DSP1_DM_BASE;
- pm = WM2200_DSP1_PM_BASE;
- zm = WM2200_DSP1_ZM_BASE;
- break;
- case WM2200_DSP2_CONTROL_1:
- file = "wm2200-dsp2.bin";
- dm = WM2200_DSP2_DM_BASE;
- pm = WM2200_DSP2_PM_BASE;
- zm = WM2200_DSP2_ZM_BASE;
- break;
- default:
- dev_err(codec->dev, "BASE %x\n", base);
- BUG_ON(1);
- return -EINVAL;
- }
-
- ret = request_firmware(&firmware, file, codec->dev);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to request '%s'\n", file);
- return ret;
- }
-
- if (sizeof(*hdr) >= firmware->size) {
- dev_err(codec->dev, "%s: file too short, %zu bytes\n",
- file, firmware->size);
- return -EINVAL;
- }
-
- hdr = (void*)&firmware->data[0];
- if (memcmp(hdr->magic, "WMDR", 4) != 0) {
- dev_err(codec->dev, "%s: invalid magic\n", file);
- return -EINVAL;
- }
-
- dev_dbg(codec->dev, "%s: v%d.%d.%d\n", file,
- (le32_to_cpu(hdr->ver) >> 16) & 0xff,
- (le32_to_cpu(hdr->ver) >> 8) & 0xff,
- le32_to_cpu(hdr->ver) & 0xff);
-
- pos = le32_to_cpu(hdr->len);
-
- blocks = 0;
- while (pos < firmware->size &&
- pos - firmware->size > sizeof(*blk)) {
- blk = (void*)(&firmware->data[pos]);
-
- type = be32_to_cpu(blk->type) & 0xff;
- offset = le32_to_cpu(blk->offset) & 0xffffff;
-
- dev_dbg(codec->dev, "%s.%d: %x v%d.%d.%d\n",
- file, blocks, le32_to_cpu(blk->id),
- (le32_to_cpu(blk->ver) >> 16) & 0xff,
- (le32_to_cpu(blk->ver) >> 8) & 0xff,
- le32_to_cpu(blk->ver) & 0xff);
- dev_dbg(codec->dev, "%s.%d: %d bytes at 0x%x in %x\n",
- file, blocks, le32_to_cpu(blk->len), offset, type);
-
- reg = 0;
- region_name = "Unknown";
- switch (type) {
- case WMFW_NAME_TEXT:
- case WMFW_INFO_TEXT:
- break;
- case WMFW_ABSOLUTE:
- region_name = "register";
- reg = offset;
- break;
- default:
- dev_err(codec->dev, "Unknown region type %x\n", type);
- break;
- }
-
- if (reg) {
- ret = regmap_raw_write(regmap, reg, blk->data,
- le32_to_cpu(blk->len));
- if (ret != 0) {
- dev_err(codec->dev,
- "%s.%d: Failed to write to %x in %s\n",
- file, blocks, reg, region_name);
- }
- }
-
- pos += le32_to_cpu(blk->len) + sizeof(*blk);
- blocks++;
- }
-
- if (pos > firmware->size)
- dev_warn(codec->dev, "%s.%d: %zu bytes at end of file\n",
- file, blocks, pos - firmware->size);
-
- return 0;
-}
-
-static int wm2200_dsp_ev(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol,
- int event)
-{
- struct snd_soc_codec *codec = w->codec;
- int base = w->reg - WM2200_DSP_CONTROL_30;
- int ret;
-
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- ret = wm2200_dsp_load(codec, base);
- if (ret != 0)
- return ret;
-
- ret = wm2200_setup_algs(codec, base);
- if (ret != 0)
- return ret;
-
- ret = wm2200_load_coeff(codec, base);
- if (ret != 0)
- return ret;
-
- /* Start the core running */
- snd_soc_update_bits(codec, w->reg,
- WM2200_DSP1_CORE_ENA | WM2200_DSP1_START,
- WM2200_DSP1_CORE_ENA | WM2200_DSP1_START);
- break;
-
- case SND_SOC_DAPM_PRE_PMD:
- /* Halt the core */
- snd_soc_update_bits(codec, w->reg,
- WM2200_DSP1_CORE_ENA | WM2200_DSP1_START,
- 0);
-
- snd_soc_update_bits(codec, base + WM2200_DSP_CONTROL_19,
- WM2200_DSP1_WDMA_BUFFER_LENGTH_MASK, 0);
- break;
-
- default:
- break;
- }
-
- return 0;
-}
-
static DECLARE_TLV_DB_SCALE(in_tlv, -6300, 100, 0);
static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
static DECLARE_TLV_DB_SCALE(out_tlv, -6400, 100, 0);
@@ -1722,12 +1342,8 @@ SND_SOC_DAPM_PGA("LHPF1", WM2200_HPLPF1_1, WM2200_LHPF1_ENA_SHIFT, 0,
SND_SOC_DAPM_PGA("LHPF2", WM2200_HPLPF2_1, WM2200_LHPF2_ENA_SHIFT, 0,
NULL, 0),
-SND_SOC_DAPM_PGA_E("DSP1", WM2200_DSP1_CONTROL_30, WM2200_DSP1_SYS_ENA_SHIFT,
- 0, NULL, 0, wm2200_dsp_ev,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
-SND_SOC_DAPM_PGA_E("DSP2", WM2200_DSP2_CONTROL_30, WM2200_DSP2_SYS_ENA_SHIFT,
- 0, NULL, 0, wm2200_dsp_ev,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+WM_ADSP1("DSP1", 0),
+WM_ADSP1("DSP2", 1),
SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0,
WM2200_AUDIO_IF_1_22, WM2200_AIF1TX1_ENA_SHIFT, 0),
@@ -2592,6 +2208,22 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c,
goto err;
}
+ for (i = 0; i < 2; i++) {
+ wm2200->dsp[i].type = WMFW_ADSP1;
+ wm2200->dsp[i].part = "wm2200";
+ wm2200->dsp[i].num = i + 1;
+ wm2200->dsp[i].dev = &i2c->dev;
+ wm2200->dsp[i].regmap = wm2200->regmap;
+ }
+
+ wm2200->dsp[0].base = WM2200_DSP1_CONTROL_1;
+ wm2200->dsp[0].mem = wm2200_dsp1_regions;
+ wm2200->dsp[0].num_mems = ARRAY_SIZE(wm2200_dsp1_regions);
+
+ wm2200->dsp[1].base = WM2200_DSP2_CONTROL_1;
+ wm2200->dsp[1].mem = wm2200_dsp2_regions;
+ wm2200->dsp[1].num_mems = ARRAY_SIZE(wm2200_dsp2_regions);
+
if (pdata)
wm2200->pdata = *pdata;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 3/4] ASoC: arizona: Define standard hookup for ADSP2
2012-10-26 18:36 [PATCH 1/4] ASoC: adsp: Add ADSP base support Mark Brown
2012-10-26 18:36 ` [PATCH 2/4] ASoC: wm2200: Convert over to wm_adsp for ADSP1 support Mark Brown
@ 2012-10-26 18:36 ` Mark Brown
2012-10-26 18:36 ` [PATCH 4/4] ASoC: wm5102: Hook up DSP1 Mark Brown
2 siblings, 0 replies; 4+ messages in thread
From: Mark Brown @ 2012-10-26 18:36 UTC (permalink / raw)
To: Liam Girdwood; +Cc: alsa-devel, patches, Mark Brown
Many Arizona class devices contain ADSP2 cores with a standard method for
hooking them into the audio map. Define standard helpers for this.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
sound/soc/codecs/arizona.h | 47 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 46 insertions(+), 1 deletion(-)
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index 36ec649..5a09127 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -17,6 +17,8 @@
#include <sound/soc.h>
+#include "wm_adsp.h"
+
#define ARIZONA_CLK_SYSCLK 1
#define ARIZONA_CLK_ASYNCCLK 2
#define ARIZONA_CLK_OPCLK 3
@@ -46,15 +48,18 @@
#define ARIZONA_MIXER_VOL_SHIFT 1
#define ARIZONA_MIXER_VOL_WIDTH 7
-#define ARIZONA_MAX_DAI 3
+#define ARIZONA_MAX_DAI 4
+#define ARIZONA_MAX_ADSP 4
struct arizona;
+struct wm_adsp;
struct arizona_dai_priv {
int clk;
};
struct arizona_priv {
+ struct wm_adsp adsp[ARIZONA_MAX_ADSP];
struct arizona *arizona;
int sysclk;
int asyncclk;
@@ -99,6 +104,20 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
static ARIZONA_MUX_CTL_DECL(name##_in3); \
static ARIZONA_MUX_CTL_DECL(name##_in4)
+#define ARIZONA_DSP_AUX_ENUMS(name, base_reg) \
+ static ARIZONA_MUX_ENUM_DECL(name##_aux1_enum, base_reg); \
+ static ARIZONA_MUX_ENUM_DECL(name##_aux2_enum, base_reg + 8); \
+ static ARIZONA_MUX_ENUM_DECL(name##_aux3_enum, base_reg + 16); \
+ static ARIZONA_MUX_ENUM_DECL(name##_aux4_enum, base_reg + 24); \
+ static ARIZONA_MUX_ENUM_DECL(name##_aux5_enum, base_reg + 32); \
+ static ARIZONA_MUX_ENUM_DECL(name##_aux6_enum, base_reg + 40); \
+ static ARIZONA_MUX_CTL_DECL(name##_aux1); \
+ static ARIZONA_MUX_CTL_DECL(name##_aux2); \
+ static ARIZONA_MUX_CTL_DECL(name##_aux3); \
+ static ARIZONA_MUX_CTL_DECL(name##_aux4); \
+ static ARIZONA_MUX_CTL_DECL(name##_aux5); \
+ static ARIZONA_MUX_CTL_DECL(name##_aux6)
+
#define ARIZONA_MUX(name, ctrl) \
SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
@@ -109,6 +128,16 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
ARIZONA_MUX(name_str " Input 4", &name##_in4_mux), \
SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0)
+#define ARIZONA_DSP_WIDGETS(name, name_str) \
+ ARIZONA_MIXER_WIDGETS(name##L, name_str "L"), \
+ ARIZONA_MIXER_WIDGETS(name##R, name_str "R"), \
+ ARIZONA_MUX(name_str " Aux 1", &name##_aux1_mux), \
+ ARIZONA_MUX(name_str " Aux 2", &name##_aux2_mux), \
+ ARIZONA_MUX(name_str " Aux 3", &name##_aux3_mux), \
+ ARIZONA_MUX(name_str " Aux 4", &name##_aux4_mux), \
+ ARIZONA_MUX(name_str " Aux 5", &name##_aux5_mux), \
+ ARIZONA_MUX(name_str " Aux 6", &name##_aux6_mux)
+
#define ARIZONA_MIXER_ROUTES(widget, name) \
{ widget, NULL, name " Mixer" }, \
{ name " Mixer", NULL, name " Input 1" }, \
@@ -120,6 +149,22 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
ARIZONA_MIXER_INPUT_ROUTES(name " Input 3"), \
ARIZONA_MIXER_INPUT_ROUTES(name " Input 4")
+#define ARIZONA_DSP_ROUTES(name) \
+ { name, NULL, name " Aux 1" }, \
+ { name, NULL, name " Aux 2" }, \
+ { name, NULL, name " Aux 3" }, \
+ { name, NULL, name " Aux 4" }, \
+ { name, NULL, name " Aux 5" }, \
+ { name, NULL, name " Aux 6" }, \
+ ARIZONA_MIXER_INPUT_ROUTES(name " Aux 1"), \
+ ARIZONA_MIXER_INPUT_ROUTES(name " Aux 2"), \
+ ARIZONA_MIXER_INPUT_ROUTES(name " Aux 3"), \
+ ARIZONA_MIXER_INPUT_ROUTES(name " Aux 4"), \
+ ARIZONA_MIXER_INPUT_ROUTES(name " Aux 5"), \
+ ARIZONA_MIXER_INPUT_ROUTES(name " Aux 6"), \
+ ARIZONA_MIXER_ROUTES(name, name "L"), \
+ ARIZONA_MIXER_ROUTES(name, name "R")
+
extern const struct soc_enum arizona_lhpf1_mode;
extern const struct soc_enum arizona_lhpf2_mode;
extern const struct soc_enum arizona_lhpf3_mode;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 4/4] ASoC: wm5102: Hook up DSP1
2012-10-26 18:36 [PATCH 1/4] ASoC: adsp: Add ADSP base support Mark Brown
2012-10-26 18:36 ` [PATCH 2/4] ASoC: wm2200: Convert over to wm_adsp for ADSP1 support Mark Brown
2012-10-26 18:36 ` [PATCH 3/4] ASoC: arizona: Define standard hookup for ADSP2 Mark Brown
@ 2012-10-26 18:36 ` Mark Brown
2 siblings, 0 replies; 4+ messages in thread
From: Mark Brown @ 2012-10-26 18:36 UTC (permalink / raw)
To: Liam Girdwood; +Cc: alsa-devel, patches, Mark Brown
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
sound/soc/codecs/Kconfig | 2 ++
sound/soc/codecs/wm5102.c | 38 +++++++++++++++++++++++++++++++++++++-
2 files changed, 39 insertions(+), 1 deletion(-)
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 91cbbe0..c5c01bd 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -150,7 +150,9 @@ config SND_SOC_WM_HUBS
config SND_SOC_WM_ADSP
tristate
default y if SND_SOC_WM2200=y
+ default y if SND_SOC_WM5102=y
default m if SND_SOC_WM2200=m
+ default y if SND_SOC_WM5102=m
config SND_SOC_AB8500_CODEC
tristate
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index 94d9d7a..de40204 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -31,6 +31,7 @@
#include "arizona.h"
#include "wm5102.h"
+#include "wm_adsp.h"
struct wm5102_priv {
struct arizona_priv core;
@@ -561,6 +562,13 @@ static const struct reg_default wm5102_sysclk_reva_patch[] = {
{ 0x025e, 0x0112 },
};
+static const struct wm_adsp_region wm5102_dsp1_regions[] = {
+ { .type = WMFW_ADSP2_PM, .base = 0x100000 },
+ { .type = WMFW_ADSP2_ZM, .base = 0x180000 },
+ { .type = WMFW_ADSP2_XM, .base = 0x190000 },
+ { .type = WMFW_ADSP2_YM, .base = 0x1a0000 },
+};
+
static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -687,6 +695,9 @@ ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE),
+
SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode),
SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
@@ -824,6 +835,10 @@ ARIZONA_MIXER_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP1L, ARIZONA_DSP1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP1R, ARIZONA_DSP1RMIX_INPUT_1_SOURCE);
+
+ARIZONA_DSP_AUX_ENUMS(DSP1, ARIZONA_DSP1AUX1MIX_INPUT_1_SOURCE);
static const char *wm5102_aec_loopback_texts[] = {
"HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "EPOUT",
@@ -996,6 +1011,8 @@ SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,
SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
+WM_ADSP2("DSP1", ARIZONA_DSP1_CONTROL_1),
+
SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
ARIZONA_AEC_LOOPBACK_ENA, 0, &wm5102_aec_loopback_mux),
@@ -1076,6 +1093,8 @@ ARIZONA_MIXER_WIDGETS(ASRC1R, "ASRC1R"),
ARIZONA_MIXER_WIDGETS(ASRC2L, "ASRC2L"),
ARIZONA_MIXER_WIDGETS(ASRC2R, "ASRC2R"),
+WM_ADSP2("DSP1", 0),
+
SND_SOC_DAPM_OUTPUT("HPOUT1L"),
SND_SOC_DAPM_OUTPUT("HPOUT1R"),
SND_SOC_DAPM_OUTPUT("HPOUT2L"),
@@ -1127,7 +1146,13 @@ SND_SOC_DAPM_OUTPUT("SPKDAT1R"),
{ name, "ASRC1L", "ASRC1L" }, \
{ name, "ASRC1R", "ASRC1R" }, \
{ name, "ASRC2L", "ASRC2L" }, \
- { name, "ASRC2R", "ASRC2R" }
+ { name, "ASRC2R", "ASRC2R" }, \
+ { name, "DSP1.1", "DSP1" }, \
+ { name, "DSP1.2", "DSP1" }, \
+ { name, "DSP1.3", "DSP1" }, \
+ { name, "DSP1.4", "DSP1" }, \
+ { name, "DSP1.5", "DSP1" }, \
+ { name, "DSP1.6", "DSP1" }
static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
{ "AIF2 Capture", NULL, "DBVDD2" },
@@ -1260,6 +1285,8 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
ARIZONA_MIXER_ROUTES("ASRC2L", "ASRC2L"),
ARIZONA_MIXER_ROUTES("ASRC2R", "ASRC2R"),
+ ARIZONA_DSP_ROUTES("DSP1"),
+
{ "AEC Loopback", "HPOUT1L", "OUT1L" },
{ "AEC Loopback", "HPOUT1R", "OUT1R" },
{ "HPOUT1L", NULL, "OUT1L" },
@@ -1434,6 +1461,15 @@ static int __devinit wm5102_probe(struct platform_device *pdev)
wm5102->core.arizona = arizona;
+ wm5102->core.adsp[0].part = "wm5102";
+ wm5102->core.adsp[0].num = 1;
+ wm5102->core.adsp[0].type = WMFW_ADSP2;
+ wm5102->core.adsp[0].base = ARIZONA_DSP1_CONTROL_1;
+ wm5102->core.adsp[0].dev = arizona->dev;
+ wm5102->core.adsp[0].regmap = arizona->regmap;
+ wm5102->core.adsp[0].mem = wm5102_dsp1_regions;
+ wm5102->core.adsp[0].num_mems = ARRAY_SIZE(wm5102_dsp1_regions);
+
for (i = 0; i < ARRAY_SIZE(wm5102->fll); i++)
wm5102->fll[i].vco_mult = 1;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2012-10-26 18:36 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-10-26 18:36 [PATCH 1/4] ASoC: adsp: Add ADSP base support Mark Brown
2012-10-26 18:36 ` [PATCH 2/4] ASoC: wm2200: Convert over to wm_adsp for ADSP1 support Mark Brown
2012-10-26 18:36 ` [PATCH 3/4] ASoC: arizona: Define standard hookup for ADSP2 Mark Brown
2012-10-26 18:36 ` [PATCH 4/4] ASoC: wm5102: Hook up DSP1 Mark Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).