File Index
Files and directories
Sign in
FILE

wm8958-dsp2.c

File preview with syntax highlighting.

linux-6.19.14/sound/soc/codecs/wm8958-dsp2.c C
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * wm8958-dsp2.c  --  WM8958 DSP2 support
   4 *
   5 * Copyright 2011 Wolfson Microelectronics plc
   6 *
   7 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
   8 */
   9
  10#include <linux/module.h>
  11#include <linux/moduleparam.h>
  12#include <linux/init.h>
  13#include <linux/delay.h>
  14#include <linux/pm.h>
  15#include <linux/i2c.h>
  16#include <linux/platform_device.h>
  17#include <linux/slab.h>
  18#include <sound/soc.h>
  19#include <sound/initval.h>
  20#include <sound/tlv.h>
  21#include <trace/events/asoc.h>
  22
  23#include <linux/mfd/wm8994/core.h>
  24#include <linux/mfd/wm8994/registers.h>
  25#include <linux/mfd/wm8994/pdata.h>
  26#include <linux/mfd/wm8994/gpio.h>
  27
  28#include <linux/unaligned.h>
  29
  30#include "wm8994.h"
  31
  32#define WM_FW_BLOCK_INFO 0xff
  33#define WM_FW_BLOCK_PM   0x00
  34#define WM_FW_BLOCK_X    0x01
  35#define WM_FW_BLOCK_Y    0x02
  36#define WM_FW_BLOCK_Z    0x03
  37#define WM_FW_BLOCK_I    0x06
  38#define WM_FW_BLOCK_A    0x08
  39#define WM_FW_BLOCK_C    0x0c
  40
  41static int wm8958_dsp2_fw(struct snd_soc_component *component, const char *name,
  42			  const struct firmware *fw, bool check)
  43{
  44	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
  45	u64 data64;
  46	u32 data32;
  47	const u8 *data;
  48	char *str;
  49	size_t block_len, len;
  50	int ret = 0;
  51
  52	/* Suppress unneeded downloads */
  53	if (wm8994->cur_fw == fw)
  54		return 0;
  55
  56	if (fw->size < 32) {
  57		dev_err(component->dev, "%s: firmware too short (%zd bytes)\n",
  58			name, fw->size);
  59		goto err;
  60	}
  61
  62	if (memcmp(fw->data, "WMFW", 4) != 0) {
  63		data32 = get_unaligned_be32(fw->data);
  64		dev_err(component->dev, "%s: firmware has bad file magic %08x\n",
  65			name, data32);
  66		goto err;
  67	}
  68
  69	len = get_unaligned_be32(fw->data + 4);
  70	data32 = get_unaligned_be32(fw->data + 8);
  71
  72	if ((data32 >> 24) & 0xff) {
  73		dev_err(component->dev, "%s: unsupported firmware version %d\n",
  74			name, (data32 >> 24) & 0xff);
  75		goto err;
  76	}
  77	if ((data32 & 0xffff) != 8958) {
  78		dev_err(component->dev, "%s: unsupported target device %d\n",
  79			name, data32 & 0xffff);
  80		goto err;
  81	}
  82	if (((data32 >> 16) & 0xff) != 0xc) {
  83		dev_err(component->dev, "%s: unsupported target core %d\n",
  84			name, (data32 >> 16) & 0xff);
  85		goto err;
  86	}
  87
  88	if (check) {
  89		data64 = get_unaligned_be64(fw->data + 24);
  90		dev_info(component->dev, "%s timestamp %llx\n",  name, data64);
  91	} else {
  92		snd_soc_component_write(component, 0x102, 0x2);
  93		snd_soc_component_write(component, 0x900, 0x2);
  94	}
  95
  96	data = fw->data + len;
  97	len = fw->size - len;
  98	while (len) {
  99		if (len < 12) {
 100			dev_err(component->dev, "%s short data block of %zd\n",
 101				name, len);
 102			goto err;
 103		}
 104
 105		block_len = get_unaligned_be32(data + 4);
 106		if (block_len + 8 > len) {
 107			dev_err(component->dev, "%zd byte block longer than file\n",
 108				block_len);
 109			goto err;
 110		}
 111		if (block_len == 0) {
 112			dev_err(component->dev, "Zero length block\n");
 113			goto err;
 114		}
 115
 116		data32 = get_unaligned_be32(data);
 117
 118		switch ((data32 >> 24) & 0xff) {
 119		case WM_FW_BLOCK_INFO:
 120			/* Informational text */
 121			if (!check)
 122				break;
 123
 124			str = kzalloc(block_len + 1, GFP_KERNEL);
 125			if (str) {
 126				memcpy(str, data + 8, block_len);
 127				dev_info(component->dev, "%s: %s\n", name, str);
 128				kfree(str);
 129			} else {
 130				dev_err(component->dev, "Out of memory\n");
 131			}
 132			break;
 133		case WM_FW_BLOCK_PM:
 134		case WM_FW_BLOCK_X:
 135		case WM_FW_BLOCK_Y:
 136		case WM_FW_BLOCK_Z:
 137		case WM_FW_BLOCK_I:
 138		case WM_FW_BLOCK_A:
 139		case WM_FW_BLOCK_C:
 140			dev_dbg(component->dev, "%s: %zd bytes of %x@%x\n", name,
 141				block_len, (data32 >> 24) & 0xff,
 142				data32 & 0xffffff);
 143
 144			if (check)
 145				break;
 146
 147			data32 &= 0xffffff;
 148
 149			wm8994_bulk_write(wm8994->wm8994,
 150					  data32 & 0xffffff,
 151					  block_len / 2,
 152					  (void *)(data + 8));
 153
 154			break;
 155		default:
 156			dev_warn(component->dev, "%s: unknown block type %d\n",
 157				 name, (data32 >> 24) & 0xff);
 158			break;
 159		}
 160
 161		/* Round up to the next 32 bit word */
 162		block_len += block_len % 4;
 163
 164		data += block_len + 8;
 165		len -= block_len + 8;
 166	}
 167
 168	if (!check) {
 169		dev_dbg(component->dev, "%s: download done\n", name);
 170		wm8994->cur_fw = fw;
 171	} else {
 172		dev_info(component->dev, "%s: got firmware\n", name);
 173	}
 174
 175	goto ok;
 176
 177err:
 178	ret = -EINVAL;
 179ok:
 180	if (!check) {
 181		snd_soc_component_write(component, 0x900, 0x0);
 182		snd_soc_component_write(component, 0x102, 0x0);
 183	}
 184
 185	return ret;
 186}
 187
 188static void wm8958_dsp_start_mbc(struct snd_soc_component *component, int path)
 189{
 190	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 191	struct wm8994 *control = wm8994->wm8994;
 192	int i;
 193
 194	/* If the DSP is already running then noop */
 195	if (snd_soc_component_read(component, WM8958_DSP2_PROGRAM) & WM8958_DSP2_ENA)
 196		return;
 197
 198	/* If we have MBC firmware download it */
 199	if (wm8994->mbc)
 200		wm8958_dsp2_fw(component, "MBC", wm8994->mbc, false);
 201
 202	snd_soc_component_update_bits(component, WM8958_DSP2_PROGRAM,
 203			    WM8958_DSP2_ENA, WM8958_DSP2_ENA);
 204
 205	/* If we've got user supplied MBC settings use them */
 206	if (control->pdata.num_mbc_cfgs) {
 207		struct wm8958_mbc_cfg *cfg
 208			= &control->pdata.mbc_cfgs[wm8994->mbc_cfg];
 209
 210		for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++)
 211			snd_soc_component_write(component, i + WM8958_MBC_BAND_1_K_1,
 212				      cfg->coeff_regs[i]);
 213
 214		for (i = 0; i < ARRAY_SIZE(cfg->cutoff_regs); i++)
 215			snd_soc_component_write(component,
 216				      i + WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1,
 217				      cfg->cutoff_regs[i]);
 218	}
 219
 220	/* Run the DSP */
 221	snd_soc_component_write(component, WM8958_DSP2_EXECCONTROL,
 222		      WM8958_DSP2_RUNR);
 223
 224	/* And we're off! */
 225	snd_soc_component_update_bits(component, WM8958_DSP2_CONFIG,
 226			    WM8958_MBC_ENA |
 227			    WM8958_MBC_SEL_MASK,
 228			    path << WM8958_MBC_SEL_SHIFT |
 229			    WM8958_MBC_ENA);
 230}
 231
 232static void wm8958_dsp_start_vss(struct snd_soc_component *component, int path)
 233{
 234	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 235	struct wm8994 *control = wm8994->wm8994;
 236	int i, ena;
 237
 238	if (wm8994->mbc_vss)
 239		wm8958_dsp2_fw(component, "MBC+VSS", wm8994->mbc_vss, false);
 240
 241	snd_soc_component_update_bits(component, WM8958_DSP2_PROGRAM,
 242			    WM8958_DSP2_ENA, WM8958_DSP2_ENA);
 243
 244	/* If we've got user supplied settings use them */
 245	if (control->pdata.num_mbc_cfgs) {
 246		struct wm8958_mbc_cfg *cfg
 247			= &control->pdata.mbc_cfgs[wm8994->mbc_cfg];
 248
 249		for (i = 0; i < ARRAY_SIZE(cfg->combined_regs); i++)
 250			snd_soc_component_write(component, i + 0x2800,
 251				      cfg->combined_regs[i]);
 252	}
 253
 254	if (control->pdata.num_vss_cfgs) {
 255		struct wm8958_vss_cfg *cfg
 256			= &control->pdata.vss_cfgs[wm8994->vss_cfg];
 257
 258		for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
 259			snd_soc_component_write(component, i + 0x2600, cfg->regs[i]);
 260	}
 261
 262	if (control->pdata.num_vss_hpf_cfgs) {
 263		struct wm8958_vss_hpf_cfg *cfg
 264			= &control->pdata.vss_hpf_cfgs[wm8994->vss_hpf_cfg];
 265
 266		for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
 267			snd_soc_component_write(component, i + 0x2400, cfg->regs[i]);
 268	}
 269
 270	/* Run the DSP */
 271	snd_soc_component_write(component, WM8958_DSP2_EXECCONTROL,
 272		      WM8958_DSP2_RUNR);
 273
 274	/* Enable the algorithms we've selected */
 275	ena = 0;
 276	if (wm8994->mbc_ena[path])
 277		ena |= 0x8;
 278	if (wm8994->hpf2_ena[path])
 279		ena |= 0x4;
 280	if (wm8994->hpf1_ena[path])
 281		ena |= 0x2;
 282	if (wm8994->vss_ena[path])
 283		ena |= 0x1;
 284
 285	snd_soc_component_write(component, 0x2201, ena);
 286
 287	/* Switch the DSP into the data path */
 288	snd_soc_component_update_bits(component, WM8958_DSP2_CONFIG,
 289			    WM8958_MBC_SEL_MASK | WM8958_MBC_ENA,
 290			    path << WM8958_MBC_SEL_SHIFT | WM8958_MBC_ENA);
 291}
 292
 293static void wm8958_dsp_start_enh_eq(struct snd_soc_component *component, int path)
 294{
 295	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 296	struct wm8994 *control = wm8994->wm8994;
 297	int i;
 298
 299	wm8958_dsp2_fw(component, "ENH_EQ", wm8994->enh_eq, false);
 300
 301	snd_soc_component_update_bits(component, WM8958_DSP2_PROGRAM,
 302			    WM8958_DSP2_ENA, WM8958_DSP2_ENA);
 303
 304	/* If we've got user supplied settings use them */
 305	if (control->pdata.num_enh_eq_cfgs) {
 306		struct wm8958_enh_eq_cfg *cfg
 307			= &control->pdata.enh_eq_cfgs[wm8994->enh_eq_cfg];
 308
 309		for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
 310			snd_soc_component_write(component, i + 0x2200,
 311				      cfg->regs[i]);
 312	}
 313
 314	/* Run the DSP */
 315	snd_soc_component_write(component, WM8958_DSP2_EXECCONTROL,
 316		      WM8958_DSP2_RUNR);
 317
 318	/* Switch the DSP into the data path */
 319	snd_soc_component_update_bits(component, WM8958_DSP2_CONFIG,
 320			    WM8958_MBC_SEL_MASK | WM8958_MBC_ENA,
 321			    path << WM8958_MBC_SEL_SHIFT | WM8958_MBC_ENA);
 322}
 323
 324static void wm8958_dsp_apply(struct snd_soc_component *component, int path, int start)
 325{
 326	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 327	int pwr_reg = snd_soc_component_read(component, WM8994_POWER_MANAGEMENT_5);
 328	int ena, reg, aif;
 329
 330	switch (path) {
 331	case 0:
 332		pwr_reg &= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA);
 333		aif = 0;
 334		break;
 335	case 1:
 336		pwr_reg &= (WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA);
 337		aif = 0;
 338		break;
 339	case 2:
 340		pwr_reg &= (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA);
 341		aif = 1;
 342		break;
 343	default:
 344		WARN(1, "Invalid path %d\n", path);
 345		return;
 346	}
 347
 348	/* Do we have both an active AIF and an active algorithm? */
 349	ena = wm8994->mbc_ena[path] || wm8994->vss_ena[path] ||
 350		wm8994->hpf1_ena[path] || wm8994->hpf2_ena[path] ||
 351		wm8994->enh_eq_ena[path];
 352	if (!pwr_reg)
 353		ena = 0;
 354
 355	reg = snd_soc_component_read(component, WM8958_DSP2_PROGRAM);
 356
 357	dev_dbg(component->dev, "DSP path %d %d startup: %d, power: %x, DSP: %x\n",
 358		path, wm8994->dsp_active, start, pwr_reg, reg);
 359
 360	if (start && ena) {
 361		/* If the DSP is already running then noop */
 362		if (reg & WM8958_DSP2_ENA)
 363			return;
 364
 365		/* If either AIFnCLK is not yet enabled postpone */
 366		if (!(snd_soc_component_read(component, WM8994_AIF1_CLOCKING_1)
 367		      & WM8994_AIF1CLK_ENA_MASK) &&
 368		    !(snd_soc_component_read(component, WM8994_AIF2_CLOCKING_1)
 369		      & WM8994_AIF2CLK_ENA_MASK))
 370			return;
 371
 372		/* Switch the clock over to the appropriate AIF */
 373		snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
 374				    WM8958_DSP2CLK_SRC | WM8958_DSP2CLK_ENA,
 375				    aif << WM8958_DSP2CLK_SRC_SHIFT |
 376				    WM8958_DSP2CLK_ENA);
 377
 378		if (wm8994->enh_eq_ena[path])
 379			wm8958_dsp_start_enh_eq(component, path);
 380		else if (wm8994->vss_ena[path] || wm8994->hpf1_ena[path] ||
 381		    wm8994->hpf2_ena[path])
 382			wm8958_dsp_start_vss(component, path);
 383		else if (wm8994->mbc_ena[path])
 384			wm8958_dsp_start_mbc(component, path);
 385
 386		wm8994->dsp_active = path;
 387
 388		dev_dbg(component->dev, "DSP running in path %d\n", path);
 389	}
 390
 391	if (!start && wm8994->dsp_active == path) {
 392		/* If the DSP is already stopped then noop */
 393		if (!(reg & WM8958_DSP2_ENA))
 394			return;
 395
 396		snd_soc_component_update_bits(component, WM8958_DSP2_CONFIG,
 397				    WM8958_MBC_ENA, 0);	
 398		snd_soc_component_write(component, WM8958_DSP2_EXECCONTROL,
 399			      WM8958_DSP2_STOP);
 400		snd_soc_component_update_bits(component, WM8958_DSP2_PROGRAM,
 401				    WM8958_DSP2_ENA, 0);
 402		snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
 403				    WM8958_DSP2CLK_ENA, 0);
 404
 405		wm8994->dsp_active = -1;
 406
 407		dev_dbg(component->dev, "DSP stopped\n");
 408	}
 409}
 410
 411int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
 412		  struct snd_kcontrol *kcontrol, int event)
 413{
 414	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 415	struct wm8994 *control = dev_get_drvdata(component->dev->parent);
 416	int i;
 417
 418	if (control->type != WM8958)
 419		return 0;
 420
 421	switch (event) {
 422	case SND_SOC_DAPM_POST_PMU:
 423	case SND_SOC_DAPM_PRE_PMU:
 424		for (i = 0; i < 3; i++)
 425			wm8958_dsp_apply(component, i, 1);
 426		break;
 427	case SND_SOC_DAPM_POST_PMD:
 428	case SND_SOC_DAPM_PRE_PMD:
 429		for (i = 0; i < 3; i++)
 430			wm8958_dsp_apply(component, i, 0);
 431		break;
 432	}
 433
 434	return 0;
 435}
 436
 437/* Check if DSP2 is in use on another AIF */
 438static int wm8958_dsp2_busy(struct wm8994_priv *wm8994, int aif)
 439{
 440	int i;
 441
 442	for (i = 0; i < ARRAY_SIZE(wm8994->mbc_ena); i++) {
 443		if (i == aif)
 444			continue;
 445		if (wm8994->mbc_ena[i] || wm8994->vss_ena[i] ||
 446		    wm8994->hpf1_ena[i] || wm8994->hpf2_ena[i])
 447			return 1;
 448	}
 449
 450	return 0;
 451}
 452
 453static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
 454			       struct snd_ctl_elem_value *ucontrol)
 455{
 456	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 457	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 458	struct wm8994 *control = wm8994->wm8994;
 459	int value = ucontrol->value.enumerated.item[0];
 460	int reg;
 461
 462	/* Don't allow on the fly reconfiguration */
 463	reg = snd_soc_component_read(component, WM8994_CLOCKING_1);
 464	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
 465		return -EBUSY;
 466
 467	if (value >= control->pdata.num_mbc_cfgs)
 468		return -EINVAL;
 469
 470	wm8994->mbc_cfg = value;
 471
 472	return 0;
 473}
 474
 475static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol,
 476			       struct snd_ctl_elem_value *ucontrol)
 477{
 478	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 479	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 480
 481	ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg;
 482
 483	return 0;
 484}
 485
 486static int wm8958_mbc_info(struct snd_kcontrol *kcontrol,
 487			   struct snd_ctl_elem_info *uinfo)
 488{
 489	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 490	uinfo->count = 1;
 491	uinfo->value.integer.min = 0;
 492	uinfo->value.integer.max = 1;
 493	return 0;
 494}
 495
 496static int wm8958_mbc_get(struct snd_kcontrol *kcontrol,
 497			  struct snd_ctl_elem_value *ucontrol)
 498{
 499	int mbc = kcontrol->private_value;
 500	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 501	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 502
 503	ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc];
 504
 505	return 0;
 506}
 507
 508static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
 509			  struct snd_ctl_elem_value *ucontrol)
 510{
 511	int mbc = kcontrol->private_value;
 512	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 513	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 514
 515	if (wm8994->mbc_ena[mbc] == ucontrol->value.integer.value[0])
 516		return 0;
 517
 518	if (ucontrol->value.integer.value[0] > 1)
 519		return -EINVAL;
 520
 521	if (wm8958_dsp2_busy(wm8994, mbc)) {
 522		dev_dbg(component->dev, "DSP2 active on %d already\n", mbc);
 523		return -EBUSY;
 524	}
 525
 526	if (wm8994->enh_eq_ena[mbc])
 527		return -EBUSY;
 528
 529	wm8994->mbc_ena[mbc] = ucontrol->value.integer.value[0];
 530
 531	wm8958_dsp_apply(component, mbc, wm8994->mbc_ena[mbc]);
 532
 533	return 1;
 534}
 535
 536#define WM8958_MBC_SWITCH(xname, xval) {\
 537	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
 538	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
 539	.info = wm8958_mbc_info, \
 540	.get = wm8958_mbc_get, .put = wm8958_mbc_put, \
 541	.private_value = xval }
 542
 543static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
 544			       struct snd_ctl_elem_value *ucontrol)
 545{
 546	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 547	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 548	struct wm8994 *control = wm8994->wm8994;
 549	int value = ucontrol->value.enumerated.item[0];
 550	int reg;
 551
 552	/* Don't allow on the fly reconfiguration */
 553	reg = snd_soc_component_read(component, WM8994_CLOCKING_1);
 554	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
 555		return -EBUSY;
 556
 557	if (value >= control->pdata.num_vss_cfgs)
 558		return -EINVAL;
 559
 560	wm8994->vss_cfg = value;
 561
 562	return 0;
 563}
 564
 565static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol,
 566			       struct snd_ctl_elem_value *ucontrol)
 567{
 568	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 569	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 570
 571	ucontrol->value.enumerated.item[0] = wm8994->vss_cfg;
 572
 573	return 0;
 574}
 575
 576static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
 577				   struct snd_ctl_elem_value *ucontrol)
 578{
 579	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 580	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 581	struct wm8994 *control = wm8994->wm8994;
 582	int value = ucontrol->value.enumerated.item[0];
 583	int reg;
 584
 585	/* Don't allow on the fly reconfiguration */
 586	reg = snd_soc_component_read(component, WM8994_CLOCKING_1);
 587	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
 588		return -EBUSY;
 589
 590	if (value >= control->pdata.num_vss_hpf_cfgs)
 591		return -EINVAL;
 592
 593	wm8994->vss_hpf_cfg = value;
 594
 595	return 0;
 596}
 597
 598static int wm8958_get_vss_hpf_enum(struct snd_kcontrol *kcontrol,
 599				   struct snd_ctl_elem_value *ucontrol)
 600{
 601	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 602	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 603
 604	ucontrol->value.enumerated.item[0] = wm8994->vss_hpf_cfg;
 605
 606	return 0;
 607}
 608
 609static int wm8958_vss_info(struct snd_kcontrol *kcontrol,
 610			   struct snd_ctl_elem_info *uinfo)
 611{
 612	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 613	uinfo->count = 1;
 614	uinfo->value.integer.min = 0;
 615	uinfo->value.integer.max = 1;
 616	return 0;
 617}
 618
 619static int wm8958_vss_get(struct snd_kcontrol *kcontrol,
 620			  struct snd_ctl_elem_value *ucontrol)
 621{
 622	int vss = kcontrol->private_value;
 623	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 624	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 625
 626	ucontrol->value.integer.value[0] = wm8994->vss_ena[vss];
 627
 628	return 0;
 629}
 630
 631static int wm8958_vss_put(struct snd_kcontrol *kcontrol,
 632			  struct snd_ctl_elem_value *ucontrol)
 633{
 634	int vss = kcontrol->private_value;
 635	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 636	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 637
 638	if (wm8994->vss_ena[vss] == ucontrol->value.integer.value[0])
 639		return 0;
 640
 641	if (ucontrol->value.integer.value[0] > 1)
 642		return -EINVAL;
 643
 644	if (!wm8994->mbc_vss)
 645		return -ENODEV;
 646
 647	if (wm8958_dsp2_busy(wm8994, vss)) {
 648		dev_dbg(component->dev, "DSP2 active on %d already\n", vss);
 649		return -EBUSY;
 650	}
 651
 652	if (wm8994->enh_eq_ena[vss])
 653		return -EBUSY;
 654
 655	wm8994->vss_ena[vss] = ucontrol->value.integer.value[0];
 656
 657	wm8958_dsp_apply(component, vss, wm8994->vss_ena[vss]);
 658
 659	return 1;
 660}
 661
 662
 663#define WM8958_VSS_SWITCH(xname, xval) {\
 664	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
 665	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
 666	.info = wm8958_vss_info, \
 667	.get = wm8958_vss_get, .put = wm8958_vss_put, \
 668	.private_value = xval }
 669
 670static int wm8958_hpf_info(struct snd_kcontrol *kcontrol,
 671			   struct snd_ctl_elem_info *uinfo)
 672{
 673	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 674	uinfo->count = 1;
 675	uinfo->value.integer.min = 0;
 676	uinfo->value.integer.max = 1;
 677	return 0;
 678}
 679
 680static int wm8958_hpf_get(struct snd_kcontrol *kcontrol,
 681			  struct snd_ctl_elem_value *ucontrol)
 682{
 683	int hpf = kcontrol->private_value;
 684	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 685	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 686
 687	if (hpf < 3)
 688		ucontrol->value.integer.value[0] = wm8994->hpf1_ena[hpf % 3];
 689	else
 690		ucontrol->value.integer.value[0] = wm8994->hpf2_ena[hpf % 3];
 691
 692	return 0;
 693}
 694
 695static int wm8958_hpf_put(struct snd_kcontrol *kcontrol,
 696			  struct snd_ctl_elem_value *ucontrol)
 697{
 698	int hpf = kcontrol->private_value;
 699	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 700	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 701
 702	if (hpf < 3) {
 703		if (wm8994->hpf1_ena[hpf % 3] ==
 704		    ucontrol->value.integer.value[0])
 705			return 0;
 706	} else {
 707		if (wm8994->hpf2_ena[hpf % 3] ==
 708		    ucontrol->value.integer.value[0])
 709			return 0;
 710	}
 711
 712	if (ucontrol->value.integer.value[0] > 1)
 713		return -EINVAL;
 714
 715	if (!wm8994->mbc_vss)
 716		return -ENODEV;
 717
 718	if (wm8958_dsp2_busy(wm8994, hpf % 3)) {
 719		dev_dbg(component->dev, "DSP2 active on %d already\n", hpf);
 720		return -EBUSY;
 721	}
 722
 723	if (wm8994->enh_eq_ena[hpf % 3])
 724		return -EBUSY;
 725
 726	if (hpf < 3)
 727		wm8994->hpf1_ena[hpf % 3] = ucontrol->value.integer.value[0];
 728	else
 729		wm8994->hpf2_ena[hpf % 3] = ucontrol->value.integer.value[0];
 730
 731	wm8958_dsp_apply(component, hpf % 3, ucontrol->value.integer.value[0]);
 732
 733	return 1;
 734}
 735
 736#define WM8958_HPF_SWITCH(xname, xval) {\
 737	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
 738	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
 739	.info = wm8958_hpf_info, \
 740	.get = wm8958_hpf_get, .put = wm8958_hpf_put, \
 741	.private_value = xval }
 742
 743static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
 744				  struct snd_ctl_elem_value *ucontrol)
 745{
 746	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 747	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 748	struct wm8994 *control = wm8994->wm8994;
 749	int value = ucontrol->value.enumerated.item[0];
 750	int reg;
 751
 752	/* Don't allow on the fly reconfiguration */
 753	reg = snd_soc_component_read(component, WM8994_CLOCKING_1);
 754	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
 755		return -EBUSY;
 756
 757	if (value >= control->pdata.num_enh_eq_cfgs)
 758		return -EINVAL;
 759
 760	wm8994->enh_eq_cfg = value;
 761
 762	return 0;
 763}
 764
 765static int wm8958_get_enh_eq_enum(struct snd_kcontrol *kcontrol,
 766				  struct snd_ctl_elem_value *ucontrol)
 767{
 768	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 769	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 770
 771	ucontrol->value.enumerated.item[0] = wm8994->enh_eq_cfg;
 772
 773	return 0;
 774}
 775
 776static int wm8958_enh_eq_info(struct snd_kcontrol *kcontrol,
 777			   struct snd_ctl_elem_info *uinfo)
 778{
 779	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 780	uinfo->count = 1;
 781	uinfo->value.integer.min = 0;
 782	uinfo->value.integer.max = 1;
 783	return 0;
 784}
 785
 786static int wm8958_enh_eq_get(struct snd_kcontrol *kcontrol,
 787			  struct snd_ctl_elem_value *ucontrol)
 788{
 789	int eq = kcontrol->private_value;
 790	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 791	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 792
 793	ucontrol->value.integer.value[0] = wm8994->enh_eq_ena[eq];
 794
 795	return 0;
 796}
 797
 798static int wm8958_enh_eq_put(struct snd_kcontrol *kcontrol,
 799			  struct snd_ctl_elem_value *ucontrol)
 800{
 801	int eq = kcontrol->private_value;
 802	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 803	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 804
 805	if (wm8994->enh_eq_ena[eq] == ucontrol->value.integer.value[0])
 806		return 0;
 807
 808	if (ucontrol->value.integer.value[0] > 1)
 809		return -EINVAL;
 810
 811	if (!wm8994->enh_eq)
 812		return -ENODEV;
 813
 814	if (wm8958_dsp2_busy(wm8994, eq)) {
 815		dev_dbg(component->dev, "DSP2 active on %d already\n", eq);
 816		return -EBUSY;
 817	}
 818
 819	if (wm8994->mbc_ena[eq] || wm8994->vss_ena[eq] ||
 820	    wm8994->hpf1_ena[eq] || wm8994->hpf2_ena[eq])
 821		return -EBUSY;
 822
 823	wm8994->enh_eq_ena[eq] = ucontrol->value.integer.value[0];
 824
 825	wm8958_dsp_apply(component, eq, ucontrol->value.integer.value[0]);
 826
 827	return 1;
 828}
 829
 830#define WM8958_ENH_EQ_SWITCH(xname, xval) {\
 831	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
 832	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
 833	.info = wm8958_enh_eq_info, \
 834	.get = wm8958_enh_eq_get, .put = wm8958_enh_eq_put, \
 835	.private_value = xval }
 836
 837static const struct snd_kcontrol_new wm8958_mbc_snd_controls[] = {
 838WM8958_MBC_SWITCH("AIF1DAC1 MBC Switch", 0),
 839WM8958_MBC_SWITCH("AIF1DAC2 MBC Switch", 1),
 840WM8958_MBC_SWITCH("AIF2DAC MBC Switch", 2),
 841};
 842
 843static const struct snd_kcontrol_new wm8958_vss_snd_controls[] = {
 844WM8958_VSS_SWITCH("AIF1DAC1 VSS Switch", 0),
 845WM8958_VSS_SWITCH("AIF1DAC2 VSS Switch", 1),
 846WM8958_VSS_SWITCH("AIF2DAC VSS Switch", 2),
 847WM8958_HPF_SWITCH("AIF1DAC1 HPF1 Switch", 0),
 848WM8958_HPF_SWITCH("AIF1DAC2 HPF1 Switch", 1),
 849WM8958_HPF_SWITCH("AIF2DAC HPF1 Switch", 2),
 850WM8958_HPF_SWITCH("AIF1DAC1 HPF2 Switch", 3),
 851WM8958_HPF_SWITCH("AIF1DAC2 HPF2 Switch", 4),
 852WM8958_HPF_SWITCH("AIF2DAC HPF2 Switch", 5),
 853};
 854
 855static const struct snd_kcontrol_new wm8958_enh_eq_snd_controls[] = {
 856WM8958_ENH_EQ_SWITCH("AIF1DAC1 Enhanced EQ Switch", 0),
 857WM8958_ENH_EQ_SWITCH("AIF1DAC2 Enhanced EQ Switch", 1),
 858WM8958_ENH_EQ_SWITCH("AIF2DAC Enhanced EQ Switch", 2),
 859};
 860
 861static void wm8958_enh_eq_loaded(const struct firmware *fw, void *context)
 862{
 863	struct snd_soc_component *component = context;
 864	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 865
 866	if (fw && (wm8958_dsp2_fw(component, "ENH_EQ", fw, true) == 0)) {
 867		mutex_lock(&wm8994->fw_lock);
 868		wm8994->enh_eq = fw;
 869		mutex_unlock(&wm8994->fw_lock);
 870	}
 871}
 872
 873static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context)
 874{
 875	struct snd_soc_component *component = context;
 876	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 877
 878	if (fw && (wm8958_dsp2_fw(component, "MBC+VSS", fw, true) == 0)) {
 879		mutex_lock(&wm8994->fw_lock);
 880		wm8994->mbc_vss = fw;
 881		mutex_unlock(&wm8994->fw_lock);
 882	}
 883}
 884
 885static void wm8958_mbc_loaded(const struct firmware *fw, void *context)
 886{
 887	struct snd_soc_component *component = context;
 888	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 889
 890	if (fw && (wm8958_dsp2_fw(component, "MBC", fw, true) == 0)) {
 891		mutex_lock(&wm8994->fw_lock);
 892		wm8994->mbc = fw;
 893		mutex_unlock(&wm8994->fw_lock);
 894	}
 895}
 896
 897void wm8958_dsp2_init(struct snd_soc_component *component)
 898{
 899	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 900	struct wm8994 *control = wm8994->wm8994;
 901	struct wm8994_pdata *pdata = &control->pdata;
 902	int ret, i;
 903
 904	wm8994->dsp_active = -1;
 905
 906	snd_soc_add_component_controls(component, wm8958_mbc_snd_controls,
 907			     ARRAY_SIZE(wm8958_mbc_snd_controls));
 908	snd_soc_add_component_controls(component, wm8958_vss_snd_controls,
 909			     ARRAY_SIZE(wm8958_vss_snd_controls));
 910	snd_soc_add_component_controls(component, wm8958_enh_eq_snd_controls,
 911			     ARRAY_SIZE(wm8958_enh_eq_snd_controls));
 912
 913
 914	/* We don't *require* firmware and don't want to delay boot */
 915	request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,
 916				"wm8958_mbc.wfw", component->dev, GFP_KERNEL,
 917				component, wm8958_mbc_loaded);
 918	request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,
 919				"wm8958_mbc_vss.wfw", component->dev, GFP_KERNEL,
 920				component, wm8958_mbc_vss_loaded);
 921	request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,
 922				"wm8958_enh_eq.wfw", component->dev, GFP_KERNEL,
 923				component, wm8958_enh_eq_loaded);
 924
 925	if (pdata->num_mbc_cfgs) {
 926		struct snd_kcontrol_new mbc_control[] = {
 927			SOC_ENUM_EXT("MBC Mode", wm8994->mbc_enum,
 928				     wm8958_get_mbc_enum, wm8958_put_mbc_enum),
 929		};
 930
 931		/* We need an array of texts for the enum API */
 932		wm8994->mbc_texts = kmalloc_array(pdata->num_mbc_cfgs,
 933						  sizeof(char *),
 934						  GFP_KERNEL);
 935		if (!wm8994->mbc_texts)
 936			return;
 937
 938		for (i = 0; i < pdata->num_mbc_cfgs; i++)
 939			wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name;
 940
 941		wm8994->mbc_enum.items = pdata->num_mbc_cfgs;
 942		wm8994->mbc_enum.texts = wm8994->mbc_texts;
 943
 944		ret = snd_soc_add_component_controls(wm8994->hubs.component,
 945						 mbc_control, 1);
 946		if (ret != 0)
 947			dev_err(wm8994->hubs.component->dev,
 948				"Failed to add MBC mode controls: %d\n", ret);
 949	}
 950
 951	if (pdata->num_vss_cfgs) {
 952		struct snd_kcontrol_new vss_control[] = {
 953			SOC_ENUM_EXT("VSS Mode", wm8994->vss_enum,
 954				     wm8958_get_vss_enum, wm8958_put_vss_enum),
 955		};
 956
 957		/* We need an array of texts for the enum API */
 958		wm8994->vss_texts = kmalloc_array(pdata->num_vss_cfgs,
 959						  sizeof(char *),
 960						  GFP_KERNEL);
 961		if (!wm8994->vss_texts)
 962			return;
 963
 964		for (i = 0; i < pdata->num_vss_cfgs; i++)
 965			wm8994->vss_texts[i] = pdata->vss_cfgs[i].name;
 966
 967		wm8994->vss_enum.items = pdata->num_vss_cfgs;
 968		wm8994->vss_enum.texts = wm8994->vss_texts;
 969
 970		ret = snd_soc_add_component_controls(wm8994->hubs.component,
 971						 vss_control, 1);
 972		if (ret != 0)
 973			dev_err(wm8994->hubs.component->dev,
 974				"Failed to add VSS mode controls: %d\n", ret);
 975	}
 976
 977	if (pdata->num_vss_hpf_cfgs) {
 978		struct snd_kcontrol_new hpf_control[] = {
 979			SOC_ENUM_EXT("VSS HPF Mode", wm8994->vss_hpf_enum,
 980				     wm8958_get_vss_hpf_enum,
 981				     wm8958_put_vss_hpf_enum),
 982		};
 983
 984		/* We need an array of texts for the enum API */
 985		wm8994->vss_hpf_texts = kmalloc_array(pdata->num_vss_hpf_cfgs,
 986						      sizeof(char *),
 987						      GFP_KERNEL);
 988		if (!wm8994->vss_hpf_texts)
 989			return;
 990
 991		for (i = 0; i < pdata->num_vss_hpf_cfgs; i++)
 992			wm8994->vss_hpf_texts[i] = pdata->vss_hpf_cfgs[i].name;
 993
 994		wm8994->vss_hpf_enum.items = pdata->num_vss_hpf_cfgs;
 995		wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts;
 996
 997		ret = snd_soc_add_component_controls(wm8994->hubs.component,
 998						 hpf_control, 1);
 999		if (ret != 0)
1000			dev_err(wm8994->hubs.component->dev,
1001				"Failed to add VSS HPFmode controls: %d\n",
1002				ret);
1003	}
1004
1005	if (pdata->num_enh_eq_cfgs) {
1006		struct snd_kcontrol_new eq_control[] = {
1007			SOC_ENUM_EXT("Enhanced EQ Mode", wm8994->enh_eq_enum,
1008				     wm8958_get_enh_eq_enum,
1009				     wm8958_put_enh_eq_enum),
1010		};
1011
1012		/* We need an array of texts for the enum API */
1013		wm8994->enh_eq_texts = kmalloc_array(pdata->num_enh_eq_cfgs,
1014						     sizeof(char *),
1015						     GFP_KERNEL);
1016		if (!wm8994->enh_eq_texts)
1017			return;
1018
1019		for (i = 0; i < pdata->num_enh_eq_cfgs; i++)
1020			wm8994->enh_eq_texts[i] = pdata->enh_eq_cfgs[i].name;
1021
1022		wm8994->enh_eq_enum.items = pdata->num_enh_eq_cfgs;
1023		wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts;
1024
1025		ret = snd_soc_add_component_controls(wm8994->hubs.component,
1026						 eq_control, 1);
1027		if (ret != 0)
1028			dev_err(wm8994->hubs.component->dev,
1029				"Failed to add enhanced EQ controls: %d\n",
1030				ret);
1031	}
1032}
~/ Read-only file preview.