All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/7] ASoC: wm2200: Convert to devm APIs
@ 2012-10-05 18:55 Mark Brown
  2012-10-05 18:55 ` [PATCH 2/7] ASoC: wm2200: Implement AEC loopback support Mark Brown
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Mark Brown @ 2012-10-05 18:55 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 |   39 ++++++++++++++-------------------------
 1 file changed, 14 insertions(+), 25 deletions(-)

diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index eab64a1..6ca9bcc 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -2011,7 +2011,7 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c,
 	wm2200->dev = &i2c->dev;
 	init_completion(&wm2200->fll_lock);
 
-	wm2200->regmap = regmap_init_i2c(i2c, &wm2200_regmap);
+	wm2200->regmap = devm_regmap_init_i2c(i2c, &wm2200_regmap);
 	if (IS_ERR(wm2200->regmap)) {
 		ret = PTR_ERR(wm2200->regmap);
 		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@@ -2027,8 +2027,9 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c,
 	for (i = 0; i < ARRAY_SIZE(wm2200->core_supplies); i++)
 		wm2200->core_supplies[i].supply = wm2200_core_supply_names[i];
 
-	ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm2200->core_supplies),
-				 wm2200->core_supplies);
+	ret = devm_regulator_bulk_get(&i2c->dev,
+				      ARRAY_SIZE(wm2200->core_supplies),
+				      wm2200->core_supplies);
 	if (ret != 0) {
 		dev_err(&i2c->dev, "Failed to request core supplies: %d\n",
 			ret);
@@ -2044,8 +2045,9 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c,
 	}
 
 	if (wm2200->pdata.ldo_ena) {
-		ret = gpio_request_one(wm2200->pdata.ldo_ena,
-				       GPIOF_OUT_INIT_HIGH, "WM2200 LDOENA");
+		ret = devm_gpio_request_one(&i2c->dev, wm2200->pdata.ldo_ena,
+					    GPIOF_OUT_INIT_HIGH,
+					    "WM2200 LDOENA");
 		if (ret < 0) {
 			dev_err(&i2c->dev, "Failed to request LDOENA %d: %d\n",
 				wm2200->pdata.ldo_ena, ret);
@@ -2055,8 +2057,9 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c,
 	}
 
 	if (wm2200->pdata.reset) {
-		ret = gpio_request_one(wm2200->pdata.reset,
-				       GPIOF_OUT_INIT_HIGH, "WM2200 /RESET");
+		ret = devm_gpio_request_one(&i2c->dev, wm2200->pdata.reset,
+					    GPIOF_OUT_INIT_HIGH,
+					    "WM2200 /RESET");
 		if (ret < 0) {
 			dev_err(&i2c->dev, "Failed to request /RESET %d: %d\n",
 				wm2200->pdata.reset, ret);
@@ -2166,23 +2169,16 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c,
 err_pm_runtime:
 	pm_runtime_disable(&i2c->dev);
 err_reset:
-	if (wm2200->pdata.reset) {
+	if (wm2200->pdata.reset)
 		gpio_set_value_cansleep(wm2200->pdata.reset, 0);
-		gpio_free(wm2200->pdata.reset);
-	}
 err_ldo:
-	if (wm2200->pdata.ldo_ena) {
+	if (wm2200->pdata.ldo_ena)
 		gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
-		gpio_free(wm2200->pdata.ldo_ena);
-	}
 err_enable:
 	regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies),
 			       wm2200->core_supplies);
 err_core:
-	regulator_bulk_free(ARRAY_SIZE(wm2200->core_supplies),
-			    wm2200->core_supplies);
 err_regmap:
-	regmap_exit(wm2200->regmap);
 err:
 	return ret;
 }
@@ -2194,17 +2190,10 @@ static __devexit int wm2200_i2c_remove(struct i2c_client *i2c)
 	snd_soc_unregister_codec(&i2c->dev);
 	if (i2c->irq)
 		free_irq(i2c->irq, wm2200);
-	if (wm2200->pdata.reset) {
+	if (wm2200->pdata.reset)
 		gpio_set_value_cansleep(wm2200->pdata.reset, 0);
-		gpio_free(wm2200->pdata.reset);
-	}
-	if (wm2200->pdata.ldo_ena) {
+	if (wm2200->pdata.ldo_ena)
 		gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
-		gpio_free(wm2200->pdata.ldo_ena);
-	}
-	regulator_bulk_free(ARRAY_SIZE(wm2200->core_supplies),
-			    wm2200->core_supplies);
-	regmap_exit(wm2200->regmap);
 
 	return 0;
 }
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/7] ASoC: wm2200: Implement AEC loopback support
  2012-10-05 18:55 [PATCH 1/7] ASoC: wm2200: Convert to devm APIs Mark Brown
@ 2012-10-05 18:55 ` Mark Brown
  2012-10-05 18:55 ` [PATCH 3/7] ASoC: wm2200: Map DSPs into regmap Mark Brown
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Mark Brown @ 2012-10-05 18:55 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 |   25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index 6ca9bcc..367d1e5 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -880,7 +880,7 @@ static DECLARE_TLV_DB_SCALE(out_tlv, -6400, 100, 0);
 static const char *wm2200_mixer_texts[] = {
 	"None",
 	"Tone Generator",
-	"AEC loopback",
+	"AEC Loopback",
 	"IN1L",
 	"IN1R",
 	"IN2L",
@@ -1066,6 +1066,7 @@ WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE);
 
 #define WM2200_MIXER_INPUT_ROUTES(name)	\
 	{ name, "Tone Generator", "Tone Generator" }, \
+	{ name, "AEC Loopback", "AEC Loopback" }, \
         { name, "IN1L", "IN1L PGA" }, \
         { name, "IN1R", "IN1R PGA" }, \
         { name, "IN2L", "IN2L PGA" }, \
@@ -1106,6 +1107,20 @@ WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE);
 	WM2200_MIXER_INPUT_ROUTES(name " Input 3"), \
 	WM2200_MIXER_INPUT_ROUTES(name " Input 4")
 
+
+static const char *wm2200_aec_loopback_texts[] = {
+	"OUT1L", "OUT1R", "OUT2L", "OUT2R",
+};
+
+static const struct soc_enum wm2200_aec_loopback =
+	SOC_ENUM_SINGLE(WM2200_DAC_AEC_CONTROL_1,
+			WM2200_AEC_LOOPBACK_SRC_SHIFT,
+			ARRAY_SIZE(wm2200_aec_loopback_texts),
+			wm2200_aec_loopback_texts);
+
+static const struct snd_kcontrol_new wm2200_aec_loopback_mux =
+	SOC_DAPM_ENUM("AEC Loopback", wm2200_aec_loopback);
+
 static const struct snd_soc_dapm_widget wm2200_dapm_widgets[] = {
 SND_SOC_DAPM_SUPPLY("SYSCLK", WM2200_CLOCKING_3, WM2200_SYSCLK_ENA_SHIFT, 0,
 		    NULL, 0),
@@ -1181,6 +1196,9 @@ SND_SOC_DAPM_AIF_OUT("AIF1TX5", "Capture", 4,
 SND_SOC_DAPM_AIF_OUT("AIF1TX6", "Capture", 5,
 		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX6_ENA_SHIFT, 0),
 
+SND_SOC_DAPM_MUX("AEC Loopback", WM2200_DAC_AEC_CONTROL_1,
+		 WM2200_AEC_LOOPBACK_ENA_SHIFT, 0, &wm2200_aec_loopback_mux),
+
 SND_SOC_DAPM_PGA_S("OUT1L", 0, WM2200_OUTPUT_ENABLES,
 		   WM2200_OUT1L_ENA_SHIFT, 0, NULL, 0),
 SND_SOC_DAPM_PGA_S("OUT1R", 0, WM2200_OUTPUT_ENABLES,
@@ -1326,6 +1344,11 @@ static const struct snd_soc_dapm_route wm2200_dapm_routes[] = {
 	{ "SPK", NULL, "OUT2L" },
 	{ "SPK", NULL, "OUT2R" },
 
+	{ "AEC Loopback", "OUT1L", "OUT1L" },
+	{ "AEC Loopback", "OUT1R", "OUT1R" },
+	{ "AEC Loopback", "OUT2L", "OUT2L" },
+	{ "AEC Loopback", "OUT2R", "OUT2R" },
+
 	WM2200_MIXER_ROUTES("DSP1", "DSP1L"),
 	WM2200_MIXER_ROUTES("DSP1", "DSP1R"),
 	WM2200_MIXER_ROUTES("DSP2", "DSP2L"),
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/7] ASoC: wm2200: Map DSPs into regmap
  2012-10-05 18:55 [PATCH 1/7] ASoC: wm2200: Convert to devm APIs Mark Brown
  2012-10-05 18:55 ` [PATCH 2/7] ASoC: wm2200: Implement AEC loopback support Mark Brown
@ 2012-10-05 18:55 ` Mark Brown
  2012-10-05 18:55 ` [PATCH 4/7] ASoC: wm2200: Fully plumb the DSPs into the routing map Mark Brown
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Mark Brown @ 2012-10-05 18:55 UTC (permalink / raw)
  To: Liam Girdwood; +Cc: alsa-devel, patches, Mark Brown

Use the regmap ranges support to add the WM2200 DSP core memory pages
into the "register map" beyond the end of the real register map. We
don't extend beyond 16 bits since the regmap API will iterate over
every register doing diagnostics.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 sound/soc/codecs/wm2200.c |   85 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 84 insertions(+), 1 deletion(-)

diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index 367d1e5..1eafaae 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -64,6 +64,66 @@ struct wm2200_priv {
 	int sysclk;
 };
 
+#define WM2200_DSP_RANGE_BASE (WM2200_MAX_REGISTER + 1)
+#define WM2200_DSP_SPACING 12288
+
+#define WM2200_DSP1_DM_BASE (WM2200_DSP_RANGE_BASE + (0 * WM2200_DSP_SPACING))
+#define WM2200_DSP1_PM_BASE (WM2200_DSP_RANGE_BASE + (1 * WM2200_DSP_SPACING))
+#define WM2200_DSP1_ZM_BASE (WM2200_DSP_RANGE_BASE + (2 * WM2200_DSP_SPACING))
+#define WM2200_DSP2_DM_BASE (WM2200_DSP_RANGE_BASE + (3 * WM2200_DSP_SPACING))
+#define WM2200_DSP2_PM_BASE (WM2200_DSP_RANGE_BASE + (4 * WM2200_DSP_SPACING))
+#define WM2200_DSP2_ZM_BASE (WM2200_DSP_RANGE_BASE + (5 * WM2200_DSP_SPACING))
+
+static const struct regmap_range_cfg wm2200_ranges[] = {
+	/* DSP1 DM */
+	{ .range_min = WM2200_DSP1_DM_BASE,
+	  .range_max = WM2200_DSP1_DM_BASE + 12287,
+	  .selector_reg = WM2200_DSP1_CONTROL_3,
+	  .selector_mask = WM2200_DSP1_PAGE_BASE_DM_0_MASK,
+	  .selector_shift = WM2200_DSP1_PAGE_BASE_DM_0_SHIFT,
+	  .window_start = WM2200_DSP1_DM_0, .window_len = 2048, },
+
+	/* DSP1 PM */
+	{ .range_min = WM2200_DSP1_PM_BASE,
+	  .range_max = WM2200_DSP1_PM_BASE + 12287,
+	  .selector_reg = WM2200_DSP1_CONTROL_2,
+	  .selector_mask = WM2200_DSP1_PAGE_BASE_PM_0_MASK,
+	  .selector_shift = WM2200_DSP1_PAGE_BASE_PM_0_SHIFT,
+	  .window_start = WM2200_DSP1_PM_0, .window_len = 768, },
+
+	/* DSP1 ZM */
+	{ .range_min = WM2200_DSP1_ZM_BASE,
+	  .range_max = WM2200_DSP1_ZM_BASE + 2047,
+	  .selector_reg = WM2200_DSP1_CONTROL_4,
+	  .selector_mask = WM2200_DSP1_PAGE_BASE_ZM_0_MASK,
+	  .selector_shift = WM2200_DSP1_PAGE_BASE_ZM_0_SHIFT,
+	  .window_start = WM2200_DSP1_ZM_0, .window_len = 1024, },
+
+	/* DSP2 DM */
+	{ .range_min = WM2200_DSP2_DM_BASE,
+	  .range_max = WM2200_DSP2_DM_BASE + 4095,
+	  .selector_reg = WM2200_DSP2_CONTROL_3,
+	  .selector_mask = WM2200_DSP2_PAGE_BASE_DM_0_MASK,
+	  .selector_shift = WM2200_DSP2_PAGE_BASE_DM_0_SHIFT,
+	  .window_start = WM2200_DSP2_DM_0, .window_len = 2048, },
+
+	/* DSP2 PM */
+	{ .range_min = WM2200_DSP2_PM_BASE,
+	  .range_max = WM2200_DSP2_PM_BASE + 11287,
+	  .selector_reg = WM2200_DSP2_CONTROL_2,
+	  .selector_mask = WM2200_DSP2_PAGE_BASE_PM_0_MASK,
+	  .selector_shift = WM2200_DSP2_PAGE_BASE_PM_0_SHIFT,
+	  .window_start = WM2200_DSP2_PM_0, .window_len = 768, },
+
+	/* DSP2 ZM */
+	{ .range_min = WM2200_DSP2_ZM_BASE,
+	  .range_max = WM2200_DSP2_ZM_BASE + 2047,
+	  .selector_reg = WM2200_DSP2_CONTROL_4,
+	  .selector_mask = WM2200_DSP2_PAGE_BASE_ZM_0_MASK,
+	  .selector_shift = WM2200_DSP2_PAGE_BASE_ZM_0_SHIFT,
+	  .window_start = WM2200_DSP2_ZM_0, .window_len = 1024, },
+};
+
 static struct reg_default wm2200_reg_defaults[] = {
 	{ 0x000B, 0x0000 },   /* R11    - Tone Generator 1 */
 	{ 0x0102, 0x0000 },   /* R258   - Clocking 3 */
@@ -407,6 +467,16 @@ static struct reg_default wm2200_reg_defaults[] = {
 
 static bool wm2200_volatile_register(struct device *dev, unsigned int reg)
 {
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wm2200_ranges); i++)
+		if ((reg >= wm2200_ranges[i].window_start &&
+		     reg <= wm2200_ranges[i].window_start +
+		     wm2200_ranges[i].window_len) ||
+		    (reg >= wm2200_ranges[i].range_min &&
+		     reg <= wm2200_ranges[i].range_max))
+			return true;
+
 	switch (reg) {
 	case WM2200_SOFTWARE_RESET:
 	case WM2200_DEVICE_REVISION:
@@ -423,6 +493,16 @@ static bool wm2200_volatile_register(struct device *dev, unsigned int reg)
 
 static bool wm2200_readable_register(struct device *dev, unsigned int reg)
 {
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wm2200_ranges); i++)
+		if ((reg >= wm2200_ranges[i].window_start &&
+		     reg <= wm2200_ranges[i].window_start +
+		     wm2200_ranges[i].window_len) ||
+		    (reg >= wm2200_ranges[i].range_min &&
+		     reg <= wm2200_ranges[i].range_max))
+			return true;
+
 	switch (reg) {
 	case WM2200_SOFTWARE_RESET:
 	case WM2200_DEVICE_REVISION:
@@ -1991,12 +2071,15 @@ static const struct regmap_config wm2200_regmap = {
 	.reg_bits = 16,
 	.val_bits = 16,
 
-	.max_register = WM2200_MAX_REGISTER,
+	.max_register = WM2200_MAX_REGISTER + (ARRAY_SIZE(wm2200_ranges) *
+					       WM2200_DSP_SPACING),
 	.reg_defaults = wm2200_reg_defaults,
 	.num_reg_defaults = ARRAY_SIZE(wm2200_reg_defaults),
 	.volatile_reg = wm2200_volatile_register,
 	.readable_reg = wm2200_readable_register,
 	.cache_type = REGCACHE_RBTREE,
+	.ranges = wm2200_ranges,
+	.num_ranges = ARRAY_SIZE(wm2200_ranges),
 };
 
 static const unsigned int wm2200_dig_vu[] = {
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4/7] ASoC: wm2200: Fully plumb the DSPs into the routing map
  2012-10-05 18:55 [PATCH 1/7] ASoC: wm2200: Convert to devm APIs Mark Brown
  2012-10-05 18:55 ` [PATCH 2/7] ASoC: wm2200: Implement AEC loopback support Mark Brown
  2012-10-05 18:55 ` [PATCH 3/7] ASoC: wm2200: Map DSPs into regmap Mark Brown
@ 2012-10-05 18:55 ` Mark Brown
  2012-10-05 18:55 ` [PATCH 5/7] ASoC: wm2200: Initial DSP support Mark Brown
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Mark Brown @ 2012-10-05 18:55 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 |   55 ++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 49 insertions(+), 6 deletions(-)

diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index 1eafaae..f24ef0a 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -1056,6 +1056,20 @@ static int wm2200_mixer_values[] = {
 	static WM2200_MUX_CTL_DECL(name##_in3); \
 	static WM2200_MUX_CTL_DECL(name##_in4)
 
+#define WM2200_DSP_ENUMS(name, base_reg) \
+	static WM2200_MUX_ENUM_DECL(name##_aux1_enum, base_reg);     \
+	static WM2200_MUX_ENUM_DECL(name##_aux2_enum, base_reg + 1); \
+	static WM2200_MUX_ENUM_DECL(name##_aux3_enum, base_reg + 2); \
+	static WM2200_MUX_ENUM_DECL(name##_aux4_enum, base_reg + 3); \
+	static WM2200_MUX_ENUM_DECL(name##_aux5_enum, base_reg + 4); \
+	static WM2200_MUX_ENUM_DECL(name##_aux6_enum, base_reg + 5); \
+	static WM2200_MUX_CTL_DECL(name##_aux1); \
+	static WM2200_MUX_CTL_DECL(name##_aux2); \
+	static WM2200_MUX_CTL_DECL(name##_aux3); \
+	static WM2200_MUX_CTL_DECL(name##_aux4); \
+	static WM2200_MUX_CTL_DECL(name##_aux5); \
+	static WM2200_MUX_CTL_DECL(name##_aux6);
+
 static const struct snd_kcontrol_new wm2200_snd_controls[] = {
 SOC_SINGLE("IN1 High Performance Switch", WM2200_IN1L_CONTROL,
 	   WM2200_IN1_OSR_SHIFT, 1, 0),
@@ -1131,6 +1145,9 @@ WM2200_MIXER_ENUMS(DSP1R, WM2200_DSP1RMIX_INPUT_1_SOURCE);
 WM2200_MIXER_ENUMS(DSP2L, WM2200_DSP2LMIX_INPUT_1_SOURCE);
 WM2200_MIXER_ENUMS(DSP2R, WM2200_DSP2RMIX_INPUT_1_SOURCE);
 
+WM2200_DSP_ENUMS(DSP1, WM2200_DSP1AUX1MIX_INPUT_1_SOURCE);
+WM2200_DSP_ENUMS(DSP2, WM2200_DSP2AUX1MIX_INPUT_1_SOURCE);
+
 WM2200_MIXER_ENUMS(LHPF1, WM2200_LHPF1MIX_INPUT_1_SOURCE);
 WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE);
 
@@ -1144,6 +1161,16 @@ WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE);
 	WM2200_MUX(name_str " Input 4", &name##_in4_mux), \
 	SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0)
 
+#define WM2200_DSP_WIDGETS(name, name_str) \
+	WM2200_MIXER_WIDGETS(name##L, name_str "L"), \
+	WM2200_MIXER_WIDGETS(name##R, name_str "R"), \
+	WM2200_MUX(name_str " Aux 1", &name##_aux1_mux), \
+	WM2200_MUX(name_str " Aux 2", &name##_aux2_mux), \
+	WM2200_MUX(name_str " Aux 3", &name##_aux3_mux), \
+	WM2200_MUX(name_str " Aux 4", &name##_aux4_mux), \
+	WM2200_MUX(name_str " Aux 5", &name##_aux5_mux), \
+	WM2200_MUX(name_str " Aux 6", &name##_aux6_mux)
+
 #define WM2200_MIXER_INPUT_ROUTES(name)	\
 	{ name, "Tone Generator", "Tone Generator" }, \
 	{ name, "AEC Loopback", "AEC Loopback" }, \
@@ -1187,6 +1214,19 @@ WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE);
 	WM2200_MIXER_INPUT_ROUTES(name " Input 3"), \
 	WM2200_MIXER_INPUT_ROUTES(name " Input 4")
 
+#define WM2200_DSP_AUX_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" }, \
+	WM2200_MIXER_INPUT_ROUTES(name " Aux 1"), \
+	WM2200_MIXER_INPUT_ROUTES(name " Aux 2"), \
+	WM2200_MIXER_INPUT_ROUTES(name " Aux 3"), \
+	WM2200_MIXER_INPUT_ROUTES(name " Aux 4"), \
+	WM2200_MIXER_INPUT_ROUTES(name " Aux 5"), \
+	WM2200_MIXER_INPUT_ROUTES(name " Aux 6")
 
 static const char *wm2200_aec_loopback_texts[] = {
 	"OUT1L", "OUT1R", "OUT2L", "OUT2R",
@@ -1260,8 +1300,10 @@ 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", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0),
-SND_SOC_DAPM_PGA_E("DSP2", SND_SOC_NOPM, 1, 0, NULL, 0, NULL, 0),
+SND_SOC_DAPM_PGA_E("DSP1", WM2200_DSP1_CONTROL_30, WM2200_DSP1_SYS_ENA_SHIFT,
+		   0, NULL, 0, NULL, 0),
+SND_SOC_DAPM_PGA_E("DSP2", WM2200_DSP2_CONTROL_30, WM2200_DSP2_SYS_ENA_SHIFT,
+		   0, NULL, 0, NULL, 0),
 
 SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0,
 		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX1_ENA_SHIFT, 0),
@@ -1329,10 +1371,8 @@ WM2200_MIXER_WIDGETS(EQR, "EQR"),
 WM2200_MIXER_WIDGETS(LHPF1, "LHPF1"),
 WM2200_MIXER_WIDGETS(LHPF2, "LHPF2"),
 
-WM2200_MIXER_WIDGETS(DSP1L, "DSP1L"),
-WM2200_MIXER_WIDGETS(DSP1R, "DSP1R"),
-WM2200_MIXER_WIDGETS(DSP2L, "DSP2L"),
-WM2200_MIXER_WIDGETS(DSP2R, "DSP2R"),
+WM2200_DSP_WIDGETS(DSP1, "DSP1"),
+WM2200_DSP_WIDGETS(DSP2, "DSP2"),
 
 WM2200_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
 WM2200_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
@@ -1434,6 +1474,9 @@ static const struct snd_soc_dapm_route wm2200_dapm_routes[] = {
 	WM2200_MIXER_ROUTES("DSP2", "DSP2L"),
 	WM2200_MIXER_ROUTES("DSP2", "DSP2R"),
 
+	WM2200_DSP_AUX_ROUTES("DSP1"),
+	WM2200_DSP_AUX_ROUTES("DSP2"),
+
 	WM2200_MIXER_ROUTES("OUT1L", "OUT1L"),
 	WM2200_MIXER_ROUTES("OUT1R", "OUT1R"),
 	WM2200_MIXER_ROUTES("OUT2L", "OUT2L"),
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 5/7] ASoC: wm2200: Initial DSP support
  2012-10-05 18:55 [PATCH 1/7] ASoC: wm2200: Convert to devm APIs Mark Brown
                   ` (2 preceding siblings ...)
  2012-10-05 18:55 ` [PATCH 4/7] ASoC: wm2200: Fully plumb the DSPs into the routing map Mark Brown
@ 2012-10-05 18:55 ` Mark Brown
  2012-10-05 18:55 ` [PATCH 6/7] ASoC: wm2200: Provide initial coefficient loading Mark Brown
  2012-10-05 18:55 ` [PATCH 7/7] ASoC: wm2200: Add names for ranges Mark Brown
  5 siblings, 0 replies; 7+ messages in thread
From: Mark Brown @ 2012-10-05 18:55 UTC (permalink / raw)
  To: Liam Girdwood; +Cc: alsa-devel, patches, Mark Brown

Support download and execution of firmwares to the DSPs on the WM2200.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 sound/soc/codecs/wm2200.c |  240 ++++++++++++++++++++++++++++++++++++++++++++-
 sound/soc/codecs/wmfw.h   |   56 +++++++++++
 2 files changed, 294 insertions(+), 2 deletions(-)
 create mode 100644 sound/soc/codecs/wmfw.h

diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index f24ef0a..e3f549b 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
+#include <linux/firmware.h>
 #include <linux/gcd.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
@@ -32,6 +33,39 @@
 #include <sound/wm2200.h>
 
 #include "wm2200.h"
+#include "wmfw.h"
+
+#define WM2200_DSP_CONTROL_1                   0x00
+#define WM2200_DSP_CONTROL_2                   0x02
+#define WM2200_DSP_CONTROL_3                   0x03
+#define WM2200_DSP_CONTROL_4                   0x04
+#define WM2200_DSP_CONTROL_5                   0x06
+#define WM2200_DSP_CONTROL_6                   0x07
+#define WM2200_DSP_CONTROL_7                   0x08
+#define WM2200_DSP_CONTROL_8                   0x09
+#define WM2200_DSP_CONTROL_9                   0x0A
+#define WM2200_DSP_CONTROL_10                  0x0B
+#define WM2200_DSP_CONTROL_11                  0x0C
+#define WM2200_DSP_CONTROL_12                  0x0D
+#define WM2200_DSP_CONTROL_13                  0x0F
+#define WM2200_DSP_CONTROL_14                  0x10
+#define WM2200_DSP_CONTROL_15                  0x11
+#define WM2200_DSP_CONTROL_16                  0x12
+#define WM2200_DSP_CONTROL_17                  0x13
+#define WM2200_DSP_CONTROL_18                  0x14
+#define WM2200_DSP_CONTROL_19                  0x16
+#define WM2200_DSP_CONTROL_20                  0x17
+#define WM2200_DSP_CONTROL_21                  0x18
+#define WM2200_DSP_CONTROL_22                  0x1A
+#define WM2200_DSP_CONTROL_23                  0x1B
+#define WM2200_DSP_CONTROL_24                  0x1C
+#define WM2200_DSP_CONTROL_25                  0x1E
+#define WM2200_DSP_CONTROL_26                  0x20
+#define WM2200_DSP_CONTROL_27                  0x21
+#define WM2200_DSP_CONTROL_28                  0x22
+#define WM2200_DSP_CONTROL_29                  0x23
+#define WM2200_DSP_CONTROL_30                  0x24
+#define WM2200_DSP_CONTROL_31                  0x26
 
 /* The code assumes DCVDD is generated internally */
 #define WM2200_NUM_CORE_SUPPLIES 2
@@ -953,6 +987,206 @@ 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, %d 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: %d bytes at end of file\n",
+			 file, regions, pos - firmware->size);
+
+out:
+	release_firmware(firmware);
+	
+	return ret;
+}
+
+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;
+
+		/* 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);
@@ -1301,9 +1535,11 @@ 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, NULL, 0),
+		   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, NULL, 0),
+		   0, NULL, 0, wm2200_dsp_ev,
+		   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 
 SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0,
 		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX1_ENA_SHIFT, 0),
diff --git a/sound/soc/codecs/wmfw.h b/sound/soc/codecs/wmfw.h
new file mode 100644
index 0000000..ef37316
--- /dev/null
+++ b/sound/soc/codecs/wmfw.h
@@ -0,0 +1,56 @@
+/*
+ * wmfw.h - Wolfson firmware format information
+ *
+ * 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 __WMFW_H
+#define __WMFW_H
+
+#include <linux/types.h>
+
+struct wmfw_header {
+	char magic[4];
+	__le32 len;
+	__le16 rev;
+	u8 core;
+	u8 ver;
+} __packed;
+
+struct wmfw_footer {
+	__le64 timestamp;
+	__le32 checksum;
+} __packed;
+
+struct wmfw_adsp1_sizes {
+	__le32 dm;
+	__le32 pm;
+	__le32 zm;
+} __packed;
+
+struct wmfw_region {
+	union {
+		__be32 type;
+		__le32 offset;
+	};
+	__le32 len;
+	u8 data[];
+} __packed;
+
+#define WMFW_ADSP1 1
+
+#define WMFW_ABSOLUTE  0xf0
+#define WMFW_NAME_TEXT 0xfe
+#define WMFW_INFO_TEXT 0xff
+
+#define WMFW_ADSP1_PM 2
+#define WMFW_ADSP1_DM 3
+#define WMFW_ADSP1_ZM 4
+
+#endif
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 6/7] ASoC: wm2200: Provide initial coefficient loading
  2012-10-05 18:55 [PATCH 1/7] ASoC: wm2200: Convert to devm APIs Mark Brown
                   ` (3 preceding siblings ...)
  2012-10-05 18:55 ` [PATCH 5/7] ASoC: wm2200: Initial DSP support Mark Brown
@ 2012-10-05 18:55 ` Mark Brown
  2012-10-05 18:55 ` [PATCH 7/7] ASoC: wm2200: Add names for ranges Mark Brown
  5 siblings, 0 replies; 7+ messages in thread
From: Mark Brown @ 2012-10-05 18:55 UTC (permalink / raw)
  To: Liam Girdwood; +Cc: alsa-devel, patches, Mark Brown

Allow a coefficient set provided using the Wolfson callibration tools to
be provided along with the firmware files. Currently only coefficient
files which configure absolute register addresses are supported.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 sound/soc/codecs/wm2200.c |  194 +++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/wmfw.h   |   43 ++++++++++
 2 files changed, 237 insertions(+)

diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index e3f549b..06d4e61 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -1150,6 +1150,192 @@ out:
 	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, %d 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 %x 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, %d 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: %d 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)
@@ -1164,6 +1350,14 @@ static int wm2200_dsp_ev(struct snd_soc_dapm_widget *w,
 		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,
diff --git a/sound/soc/codecs/wmfw.h b/sound/soc/codecs/wmfw.h
index ef37316..5791f8e 100644
--- a/sound/soc/codecs/wmfw.h
+++ b/sound/soc/codecs/wmfw.h
@@ -43,6 +43,49 @@ struct wmfw_region {
 	u8 data[];
 } __packed;
 
+struct wmfw_id_hdr {
+	__be32 core_id;
+	__be32 core_rev;
+	__be32 id;
+	__be32 ver;
+} __packed;
+
+struct wmfw_adsp1_id_hdr {
+	struct wmfw_id_hdr fw;
+	__be32 zm;
+	__be32 dm;
+	__be32 algs;
+} __packed;
+
+struct wmfw_alg_hdr {
+	__be32 id;
+	__be32 ver;
+} __packed;
+
+struct wmfw_adsp1_alg_hdr {
+	struct wmfw_alg_hdr alg;
+	__be32 zm;
+	__be32 dm;
+} __packed;
+
+struct wmfw_coeff_hdr {
+	u8 magic[4];
+	__le32 len;
+	__le32 ver;
+	u8 data[];
+} __packed;
+
+struct wmfw_coeff_item {
+	union {
+		__be32 type;
+		__le32 offset;
+	};
+	__le32 id;
+	__le32 ver;
+	__le32 sr;
+	__le32 len;
+	u8 data[];
+} __packed;
 #define WMFW_ADSP1 1
 
 #define WMFW_ABSOLUTE  0xf0
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 7/7] ASoC: wm2200: Add names for ranges
  2012-10-05 18:55 [PATCH 1/7] ASoC: wm2200: Convert to devm APIs Mark Brown
                   ` (4 preceding siblings ...)
  2012-10-05 18:55 ` [PATCH 6/7] ASoC: wm2200: Provide initial coefficient loading Mark Brown
@ 2012-10-05 18:55 ` Mark Brown
  5 siblings, 0 replies; 7+ messages in thread
From: Mark Brown @ 2012-10-05 18:55 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 |   18 ++++++------------
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index 06d4e61..b63391a 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -109,48 +109,42 @@ struct wm2200_priv {
 #define WM2200_DSP2_ZM_BASE (WM2200_DSP_RANGE_BASE + (5 * WM2200_DSP_SPACING))
 
 static const struct regmap_range_cfg wm2200_ranges[] = {
-	/* DSP1 DM */
-	{ .range_min = WM2200_DSP1_DM_BASE,
+	{ .name = "DSP1DM", .range_min = WM2200_DSP1_DM_BASE,
 	  .range_max = WM2200_DSP1_DM_BASE + 12287,
 	  .selector_reg = WM2200_DSP1_CONTROL_3,
 	  .selector_mask = WM2200_DSP1_PAGE_BASE_DM_0_MASK,
 	  .selector_shift = WM2200_DSP1_PAGE_BASE_DM_0_SHIFT,
 	  .window_start = WM2200_DSP1_DM_0, .window_len = 2048, },
 
-	/* DSP1 PM */
-	{ .range_min = WM2200_DSP1_PM_BASE,
+	{ .name = "DSP1PM", .range_min = WM2200_DSP1_PM_BASE,
 	  .range_max = WM2200_DSP1_PM_BASE + 12287,
 	  .selector_reg = WM2200_DSP1_CONTROL_2,
 	  .selector_mask = WM2200_DSP1_PAGE_BASE_PM_0_MASK,
 	  .selector_shift = WM2200_DSP1_PAGE_BASE_PM_0_SHIFT,
 	  .window_start = WM2200_DSP1_PM_0, .window_len = 768, },
 
-	/* DSP1 ZM */
-	{ .range_min = WM2200_DSP1_ZM_BASE,
+	{ .name = "DSP1ZM", .range_min = WM2200_DSP1_ZM_BASE,
 	  .range_max = WM2200_DSP1_ZM_BASE + 2047,
 	  .selector_reg = WM2200_DSP1_CONTROL_4,
 	  .selector_mask = WM2200_DSP1_PAGE_BASE_ZM_0_MASK,
 	  .selector_shift = WM2200_DSP1_PAGE_BASE_ZM_0_SHIFT,
 	  .window_start = WM2200_DSP1_ZM_0, .window_len = 1024, },
 
-	/* DSP2 DM */
-	{ .range_min = WM2200_DSP2_DM_BASE,
+	{ .name = "DSP2DM", .range_min = WM2200_DSP2_DM_BASE,
 	  .range_max = WM2200_DSP2_DM_BASE + 4095,
 	  .selector_reg = WM2200_DSP2_CONTROL_3,
 	  .selector_mask = WM2200_DSP2_PAGE_BASE_DM_0_MASK,
 	  .selector_shift = WM2200_DSP2_PAGE_BASE_DM_0_SHIFT,
 	  .window_start = WM2200_DSP2_DM_0, .window_len = 2048, },
 
-	/* DSP2 PM */
-	{ .range_min = WM2200_DSP2_PM_BASE,
+	{ .name = "DSP2PM", .range_min = WM2200_DSP2_PM_BASE,
 	  .range_max = WM2200_DSP2_PM_BASE + 11287,
 	  .selector_reg = WM2200_DSP2_CONTROL_2,
 	  .selector_mask = WM2200_DSP2_PAGE_BASE_PM_0_MASK,
 	  .selector_shift = WM2200_DSP2_PAGE_BASE_PM_0_SHIFT,
 	  .window_start = WM2200_DSP2_PM_0, .window_len = 768, },
 
-	/* DSP2 ZM */
-	{ .range_min = WM2200_DSP2_ZM_BASE,
+	{ .name = "DSP2ZM", .range_min = WM2200_DSP2_ZM_BASE,
 	  .range_max = WM2200_DSP2_ZM_BASE + 2047,
 	  .selector_reg = WM2200_DSP2_CONTROL_4,
 	  .selector_mask = WM2200_DSP2_PAGE_BASE_ZM_0_MASK,
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2012-10-05 18:55 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-10-05 18:55 [PATCH 1/7] ASoC: wm2200: Convert to devm APIs Mark Brown
2012-10-05 18:55 ` [PATCH 2/7] ASoC: wm2200: Implement AEC loopback support Mark Brown
2012-10-05 18:55 ` [PATCH 3/7] ASoC: wm2200: Map DSPs into regmap Mark Brown
2012-10-05 18:55 ` [PATCH 4/7] ASoC: wm2200: Fully plumb the DSPs into the routing map Mark Brown
2012-10-05 18:55 ` [PATCH 5/7] ASoC: wm2200: Initial DSP support Mark Brown
2012-10-05 18:55 ` [PATCH 6/7] ASoC: wm2200: Provide initial coefficient loading Mark Brown
2012-10-05 18:55 ` [PATCH 7/7] ASoC: wm2200: Add names for ranges Mark Brown

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.